/* ### Modified by P.Saratxaga on 19 Sep 1995 ###
 * - Added X-FTN-From and X-FTN-To support
 * - added code by T.Tanaka, dated 13 Mar 1995, to put the freename in the ftn
 *   header, instead of the userid, when the address is fido parseable
 * - modified ^aREPLY: code, to look in In-Reply-To: only if not newsmode, and
 *   in References: only if newsmode
 * - modified the way ^aREPLYADDR and ftn 'to:' are created (I use the
 *   function parserfcaddr() ), so the address of the "Reply-To: " line (if
 *   exists) is used for ^aREPLYADDR and registration database.
 * - support to decode MSGID from fidogate "Message-ID: <MSGID_....>"
 * - suport for X-Apparently-To: (generated by the french fido->usenet gate)
 * - added -DDONT_REGATE code by Wim Van Sebroeck <vsebro@medelec.uia.ac.be>
 * - corriged a bug when Organization: has only blanks
 */
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include "xutil.h"
#include "lutil.h"
#include "ftn.h"
#include "ftnmsg.h"
#include "rfcmsg.h"
#include "rfcaddr.h"
#include "mime.h"
#include "charset.h"
#include "charconv.h"
#include "config.h"
#include "version.h"
#include "hash.h"
#ifdef GATEBAU_MSGID
#include "areas.h"
#endif

#ifndef ULONG_MAX
#define ULONG_MAX 4294967295
#endif

int newsmode=0;
char *replyaddr=NULL;

extern time_t now;
extern faddr *bestaka;
extern int rfclevel;

extern time_t parsedate(char *,void *);
extern int registrate(char *,char *);
extern unsigned long atoul(char*);

extern unsigned INT16 crc(char *);
extern int flagset(char *);
#ifdef GATEBAU_MSGID
extern unsigned long crcgatebau(char*);
#endif

int ftnmsgid(msgid,s,n,areaname)
char *msgid;
char **s;
unsigned long *n;
char *areaname;
{
	char *buf,*l,*r,*p;
	unsigned long nid=0L;
	faddr *tmp;
	int ftnorigin=0;

	debug(3,"make ftn msgid from \"%s\"",msgid);

	if (msgid == NULL)
	{
		*s=NULL;
		*n=0L;
		return ftnorigin;
	}

	buf=xmalloc(strlen(msgid)+65);
	strcpy(buf,msgid);
	if ((l=strchr(buf,'<'))) l++;
	else l=buf;
	while (isspace(*l)) l++;
	if ((r=strchr(l,'>'))) *r='\0';
	r=l+strlen(l)-1;
	while (isspace(*r) && (r > l)) (*r--)='\0';
	if ((tmp=parsefaddr(l)))
	{
		if (tmp->name)
		{
			if (strspn(tmp->name,"0123456789") == strlen(tmp->name))
				nid=atoul(tmp->name);
			else nid=ULONG_MAX;
			if (nid == ULONG_MAX)
				hash_update_s(&nid,tmp->name);
			else
				ftnorigin=1;
		}
		else
		{
			hash_update_s(&nid,l);
		}
		*s=xstrcpy(ascfnode(tmp,0x1f));
		tidy_faddr(tmp);
	}
	else
	{
		if ((r=strchr(l,'@')) == NULL) /* should never happen */
		{
			*s=xstrcpy(l);
			hash_update_s(&nid,l);
		}
		else if ((rfclevel < 1) && (bestaka) && (ftnmsgidstyle) &&
			 (strncasecmp(r+1,ftnmsgidstyle,
				strlen(ftnmsgidstyle)) == 0))
		{
			*s=xstrcpy(ascfnode(bestaka,0x1f));
			/* FIXME: what to put here ? -- P.Saratxaga */
			hash_update_s(&nid,l);
		}
	/* <MSGID_mimeanything_abcd1234@ftn.domain> */
		else if (strncmp(l,"MSGID_",6) == 0)
		{
			*r='\0';
			r=strrchr(l+6,'_');
                	if (r) *r++='\0';
                	*s=xstrcpy(qp_decode(l+6));
			if (r) sscanf(r,"%lx",&nid);
			ftnorigin=1;
		}
	/* <NOMSGID_mimeanything_abcd1234@ftn.domain> */
		else if (strncmp(l,"NOMSGID_",8) == 0)
		{
			*s=NULL;
			*n=0L;
			ftnorigin=1;
			return ftnorigin;
		}
	/* <ftn_2.204.226$fidonet_1d17b3b3_Johan.Olofsson@magnus.ct.se> */
		else if (strncmp(l,"ftn_",4) == 0)
		{
			*r='\0';
			if ((r=strchr(l+4,'$')) || (r=strchr(l+4,'#')))
			{
				if (*r=='$') *r='@';
				if ((r=strchr(l+4,'.')))
					*r=':';
				if ((r=strchr(l+4,'.')))
					*r='/';
			}
			while ((r=strrchr(l+4,'_')) != strchr(l+4,'_')) *r='\0';
			r=strchr(l+4,'_');
			*r++='\0';
			*s=xstrcpy(l+4);
			sscanf(r,"%lx",&nid);
			ftnorigin=1;
		}
	/* <wgcid$3$g712$h610$i22$kfidonet$j6596dbf5@brazerko.com> */
		else if (strncmp(l,"wgcid$",6) == 0)
		{
			*r='\0';
			if ((r=strstr(l+6,"$g")))
			{
				*r='\0';
				*s=xstrcpy(l+6);
				*s=xstrcat(*s,":");
				l=r+2;
			}
			if ((r=strstr(l,"$h")))
			{
				*r++='\0';
				*s=xstrcat(*s,l);
				*s=xstrcat(*s,"/");
				l=r+2;
			}
			if ((r=strstr(l,"$i")))
			{
				*r='\0';
				*s=xstrcat(*s,l);
				*s=xstrcat(*s,".");
				l=r+2;
			}
			if ((r=strstr(l,"$k")))
			{
				*r='\0';
				*s=xstrcat(*s,l);
				*s=xstrcat(*s,"@");
				l=r+2;
			}
			if ((r=strstr(l,"$j")))
			{
				*r='\0';
				*s=xstrcat(*s,l);
				sscanf(r+2,"%lx",&nid);
			}
		}
#ifdef GATEBAU_MSGID
		else if (areagatebau(areaname))
		{
			*s=xstrcpy("<");
			*s=xstrcat(*s,l);
			*s=xstrcat(*s,">");
			if (areaname) {
				r=xstrcpy(*s);
				r=xstrcat(r,areaname);
				nid=crcgatebau(r);
			} else {
				nid=crcgatebau(*s);
			}
		}
#endif
		else
		{
			*r='\0';
			if ((p=strchr(l,'%')))
			{
				*p='\0';
				if (strspn(l,"0123456789") == strlen(l))
				{
					*r='@';
					r=p;
				}
				else *p='%';
			}
			r++;
			if (strspn(l,"0123456789") == strlen(l))
				nid=atoul(l);
			else nid=ULONG_MAX;
			if (nid == ULONG_MAX) {
				hash_update_s(&nid,l);
			}
			*s=xstrcpy(r);
		}
	}
	*n=nid;

	free(buf);
	return ftnorigin;
}

ftnmsg *mkftnhdr(msg,incode,outcode)
rfcmsg *msg;
int incode, outcode;
{
	char *freename=NULL,*rfcfrom=NULL,*p,*q,*l,*r;
	char *fbuf=NULL;
#ifdef DONT_REGATE
	char *ftnfrom=NULL;
#endif
	ftnmsg *tmsg;
	int needreplyaddr;

	tmsg=(ftnmsg *)xmalloc(sizeof(ftnmsg));

	tmsg->flags=0;
	tmsg->ftnorigin=0;
	tmsg->to=NULL;
	tmsg->from=NULL;
	tmsg->date=0L;
	tmsg->subj=NULL;
	tmsg->msgid_s=NULL;
	tmsg->msgid_a=NULL;
	tmsg->reply_s=NULL;
	tmsg->reply_a=NULL;
	tmsg->origin=NULL;
	tmsg->area=NULL;

	if (newsmode)
	{
		p=xstrcpy(hdr("Comment-To",msg));
		if (p == NULL) p=xstrcpy(hdr("X-Comment-To",msg));
		if (p == NULL) p=xstrcpy(hdr("X-FTN-To",msg));
		if (p == NULL) p=xstrcpy(hdr("X-Fidonet-Comment-To",msg));
		if (p == NULL) p=xstrcpy(hdr("X-Apparently-To",msg));
		if (p)
		{
			debug(6,"getting `to' address from: \"%s\"",p);
			if ((tmsg->to=parsefaddr(p)) == NULL)
				tmsg->to=parsefaddr("All@p0.f0.n0.z0");
			if ((l=strrchr(p,'<')) && (r=strchr(p,'>')) && (l < r))
			{
				r=l;
				*r--='\0';
				if ((l=strchr(p,'"')) && (r=strrchr(p,'"')) && (l < r))
				{
					l++;
					*r--='\0';
				}
				while (isspace(*r)) *r--='\0';
				if (!l) l=p;
				while (isspace(*l)) l++;
			}
			else if ((l=strrchr(p,'(')) && (r=strchr(p,')')) && (l < r))
			{
				*r--='\0';
				while (isspace(*r)) *r--='\0';
				l++;
				while (isspace(*l)) l++;
			}
			else
			{
				l=p;
				while (isspace(*l)) l++;
				r=p+strlen(p)-1;
				if (*r == '\n') *r--='\0';
				while (isspace(*r)) *r--='\0';
			}

			if(*l)
			{
				strcpy(l,hdrnconv(l,incode,outcode,MAXNAME));
				if (strlen(l) > MAXNAME)
					l[MAXNAME]='\0';
				free(tmsg->to->name);
				tmsg->to->name=xstrcpy(l);
			}
			free(p);
		}
		else
		tmsg->to=parsefaddr("All@p0.f0.n0.z0");
		debug(3,"TO: %s",ascinode(tmsg->to,0x7f));
	}

	p=fbuf=xstrcpy(hdr("Reply-To",msg));
	if (fbuf == NULL) p=fbuf=xstrcpy(hdr("From",msg));
	if (fbuf == NULL) p=fbuf=xstrcpy(hdr("X-UUCP-From",msg));
	if (p) {
	        q=p;
		while (isspace(*q)) q++;
		fbuf=parserfcaddr(q).remainder;
		if (parserfcaddr(q).target) {
			fbuf=xstrcat(fbuf,"@");
			fbuf=xstrcat(fbuf,parserfcaddr(q).target);
		}	
		rfcfrom=fbuf;
	}
	if (!rfcfrom) rfcfrom=xstrcpy("postmaster");
        p=fbuf=xstrcpy(hdr("From",msg));
        if (fbuf == NULL) p=fbuf=xstrcpy(hdr("X-UUCP-From",msg));
	if (p) {
	        q=p;
		while (isspace(*q)) q++;
                if ((q) && (*q !=  '\0'))
                	freename=parserfcaddr(q).comment;
                else freename=NULL;
		}
	else freename=xstrcpy("Unidentified User");
	if (freename) {
		while (isspace(*freename)) freename++;
		}

	if (rfcfrom)
	{
		while (isspace(*rfcfrom)) rfcfrom++;
		p=rfcfrom+strlen(rfcfrom)-1;
		while ((isspace(*p)) || (*p == '\n')) *(p--)='\0';
	}
	if ((freename) && (*freename != '\0'))
	{
		while (isspace(*freename)) freename++;
		p=freename+strlen(freename)-1;
		while ((isspace(*p)) || (*p == '\n')) *(p--)='\0';
		strcpy(freename,hdrconv(freename,incode,outcode));
		if ((*freename == '\"') && (*(p=freename+strlen(freename)-1) == '\"'))
		{
			freename++;
			*p='\0';
		}
	}
	if ((!freename) || ((freename) && (*freename == '\0')) || (strcmp(freename,".")==0)) 
	    freename=rfcfrom;

	if (newsmode) debug(3,"FROM: %s <%s>",freename,rfcfrom);
	else loginf("from: %s <%s>",freename,rfcfrom);

	needreplyaddr=1;
	if ((tmsg->from=parsefaddr(rfcfrom)) == NULL)
	{
		if (freename && rfcfrom)
		if (!strchr(freename,'@') && 
		    !strchr(freename,'%') && 
		    strncasecmp(freename,rfcfrom,MAXNAME) &&
		    strncasecmp(freename,"uucp",4) &&
		    strncasecmp(freename,"usenet",6) &&
		    strncasecmp(freename,"news",4) &&
		    strncasecmp(freename,"super",5) &&
		    strncasecmp(freename,"admin",5) &&
		    strncasecmp(freename,"postmaster",10) &&
		    strncasecmp(freename,"sys",3)) 
			needreplyaddr=registrate(freename,rfcfrom);
	}
	else
	{
		tmsg->ftnorigin=1;
		tmsg->from->name=xstrcpy(freename);
		if (strlen(tmsg->from->name) > MAXNAME)
			tmsg->from->name[MAXNAME]='\0';
	}

	if (replyaddr)
	{
		free(replyaddr);
		replyaddr=NULL;
	}
	if (needreplyaddr && (tmsg->from == NULL))
	{
		debug(6,"fill replyaddr with \"%s\"",rfcfrom);
		replyaddr=xstrcpy(rfcfrom);
	}

	debug(6,"From address was%s distinguished as ftn",
		tmsg->from ? "" : " not");

	if ((tmsg->from == NULL) && (bestaka))
	{
#ifdef DONT_REGATE
		p=xstrcpy(hdr("X-FTN-Sender",msg));
		if (p == NULL) {
			if ((p=hdr("X-FTN-From",msg)))
				p=xstrcpy(ascinode(parsefnode(p),0xff));
		}
		if (p)
		{
	        	q=p;
			while (isspace(*q)) q++;
			ftnfrom=parserfcaddr(q).remainder;
			if (parserfcaddr(q).target) 
			{
				ftnfrom=xstrcat(ftnfrom,"@");
				ftnfrom=xstrcat(ftnfrom,parserfcaddr(q).target);
			}	
			debug(6,"Ftn gateway: \"%s\"", ftnfrom);
			if (newsmode) debug(3,"FTN-FROM: %s",ftnfrom);
			else loginf("ftn sender: %s",ftnfrom);
			if (ftnfrom) tmsg->from=parsefaddr(ftnfrom);
			if ((tmsg->from) && (!tmsg->from->name))
			{
				tmsg->from->name=xstrcpy(rfcfrom);			
			}
		}
		if (tmsg->from == NULL)
		{
#endif
			tmsg->from=(faddr *)xmalloc(sizeof(faddr));
			tmsg->from->name=xstrcpy(freename);
			if (tmsg->from->name && (strlen(tmsg->from->name) > MAXNAME))
				tmsg->from->name[MAXNAME]='\0';
			tmsg->from->point=bestaka->point;
			tmsg->from->node=bestaka->node;
			tmsg->from->net=bestaka->net;
			tmsg->from->zone=bestaka->zone;
			tmsg->from->domain=xstrcpy(bestaka->domain);
#ifdef DONT_REGATE
		}
#endif
	}

	if (fbuf) free(fbuf); fbuf=NULL;

	p=hdr("Subject",msg);
	if (p)
	{
		while (isspace(*p)) p++;
	/* charset conversion for subject line is done in message.c 
	 * here we only convert quoted-printable and base64 to 8 bit
	 */
		tmsg->subj=xstrcpy(hdrnconv(p, 0, 0, MAXSUBJ));
		tmsg->subj=xstrcpy(p);
		if (*(p=tmsg->subj+strlen(tmsg->subj)-1) == '\n') *p='\0';
		if (strlen(tmsg->subj) > MAXSUBJ) tmsg->subj[MAXSUBJ]='\0';
	}
	else tmsg->subj=xstrcpy(" ");

	debug(3,"SUBJ: \"%s\"",tmsg->subj);

	if ((p=hdr("X-FTN-FLAGS",msg))) tmsg->flags |= flagset(p);
	if (hdr("Return-Receipt-To",msg)) tmsg->flags |= FLG_RRQ;
	if (hdr("Notice-Requested-Upon-Delivery-To",msg)) tmsg->flags |= FLG_RRQ;
	if (!newsmode)
	{
		tmsg->flags |= FLG_PVT;
		tmsg->flags |= FLG_K_S;
	}

	if ((p=hdr("X-Origin-Date",msg))) tmsg->date=parsedate(p,NULL);
	else if ((p=hdr("Date",msg))) tmsg->date=parsedate(p,NULL);
	else tmsg->date=time((time_t *)NULL);

	if ((p=hdr("X-FTN-MSGID",msg)))
	{
		tmsg->ftnorigin&=1;
		while (isspace(*p)) p++;
		tmsg->msgid_s=xstrcpy(p);
		if (*(p=tmsg->msgid_s+strlen(tmsg->msgid_s)-1) == '\n') *p='\0';
	}
	else if ((p=hdr(".MSGID",msg)))
	{
		tmsg->ftnorigin&=1;
		while (isspace(*p)) p++;
		tmsg->msgid_s=xstrcpy(p);
		if (*(p=tmsg->msgid_s+strlen(tmsg->msgid_s)-1) == '\n') *p='\0';
	}
	else if ((p=hdr("Message-ID",msg)))
	{
		tmsg->ftnorigin &=
			ftnmsgid(p,&(tmsg->msgid_a),&(tmsg->msgid_n),tmsg->area);
	}
	else
	{
		tmsg->msgid_a=NULL;
	}

	if ((p=hdr("X-FTN-REPLY",msg)))
	{
		while (isspace(*p)) p++;
		tmsg->reply_s=xstrcpy(p);
		if (*(p=tmsg->reply_s+strlen(tmsg->reply_s)-1) == '\n') *p='\0';
	}
	else
	{
	    if (newsmode)
	    {
		p=hdr("References",msg);
		if (p)
		{	l=xstrcpy(p);
			r=strtok(l," \t\n");
			while ((l=strtok(NULL," \t\n")) != NULL) r=l;
			p=r;
			free(l);
		}
	    }
	    else p=hdr("In-Reply-To",msg);	
	}
	if (p)
	{
		(void)ftnmsgid(p,&(tmsg->reply_a),&(tmsg->reply_n),NULL);
	}
	else
	{
		tmsg->reply_a=NULL;
	}

	debug(3,"DATE: %s, MSGID: %s %lx, REPLY: %s %lx",
		ftndate(tmsg->date),
		S(tmsg->msgid_a),tmsg->msgid_n,
		S(tmsg->reply_a),tmsg->reply_n);

	if ((p=hdr("Organization",msg)))
	{
		while (isspace(*p)) p++;
                tmsg->origin=xstrcpy(hdrconv(p, incode, outcode));
		if (tmsg->origin)
		if (*(p=tmsg->origin+strlen(tmsg->origin)-1) == '\n') *p='\0';
	}

	debug(3,"ORIGIN: %s",S(tmsg->origin));

	return tmsg;
}
