/*
 * This file is part of the FEddi package
 *
 * Personal use allowed under the terms of the
 *
 *              GNU GENERAL PUBLIC LICENSE Version 2
 *              (see LICENSE for the complete text)
 *
 *-------------------------------------------------------------------
 *
 *    ENTER AT YOUR OWN RISK !!
 *
 * This source is without any documentation and can drive you mad.
 * In case of sudden epileptic seizures please call your doctor.
 *
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include "proc.h"
#include "structs.h"
#include "charset.h"

const char wot[7][3]={"su","mo","tu","we","th","fr","sa"};

FILE *pktf;

PktHdrType Header;
PktMsgHdrType PktHdr;
MsgHdrType MsgHdr;
UserAkaType *runAka;
int textend;
char as[9];
char day[4];

int createpkt(char *s, int nm);
int appendpkt(char *s);
void writemsg(char *a, int num);
char *Addr36(short, short, short);
char *dayofweek();

int main(int argc, char **argv)
{
	FILE *flof;
	char name[256], sys[300], log[256], file[256], *d1, *d2, *d3, oldSubj[76];
	DIR *dir;
	struct dirent *ent;
	int scanned, crash=0, attached=0, request=0, mn, i, msc, off=0, EL=0;
	int hold=0, reghold=0, fattacherror;
	Addr4dType *runRoute;
	time_t timer;
	struct tm *tb;
	struct stat st;
	strcpy(ProgName,"fscan");
	while (argc-off>1)
	{
		if (strcmp(argv[off+1],"--config")==0 || strcmp(argv[off+1],"-c")==0)
		{
			strcpy(ConfigName,argv[off+2]);
			off+=2;
			continue;
		}
		if (strcmp(argv[off+1],"--quiet")==0 || strcmp(argv[off+1],"-q")==0)
		{
			QUIET=1;
			off++;
			continue;
		}
		printERR("Unknown param '%s'!\n",argv[off+1]);
		exit(1);
	}
	if (argc-off!=1)
	{
		printERR("Illegal number of params!\n");
		exit(1);
	}
	if (loadrc(1))
	{
		Log("*FEddi Scan");
		Log("+Scanning NetMail");
		scanned=0;
		textend=openarea("NETMAIL",NULL);
		for (mn=0; fread(&MsgHdr,sizeof(MsgHdrType),1,mhf); mn++)
		{
			if (MsgHdr.Attribute&512)
			{
				hold++;
				continue;
			}
			if ((MsgHdr.Attribute&264)==256 && !MsgHdr.Deleted)
			{
				if (!(MsgHdr.Attribute&2) && !MsgHdr.Direct)
				{
					for (runAka=Profile.Aka; runAka; runAka=runAka->next)
						for (runRoute=runAka->Route; runRoute; runRoute=runRoute->next)
						  if (AddrMatch(runRoute,&MsgHdr))
						  {
						  	if (runAka!=Profile.Aka)
							  	sprintf(name,"%s%s.%03x/%04x%04x.%s",OutboundPath,
											runAka->Outbound,runAka->UserZone,
											runAka->UserNet,runAka->UserNode,
											Mailer?"OUT":"out");
								else
							  	sprintf(name,"%s%s/%04x%04x.%s",OutboundPath,
											runAka->Outbound,
											runAka->UserNet,runAka->UserNode,
											Mailer?"OUT":"out");
								Header.OrigNode=Header.DestNode=runAka->UserNode;
								Header.OrigNet=Header.DestNet=runAka->UserNet;
								Header.OrigZone=Header.DestZone=\
										Header.qDestZone=Header.qOrigZone=runAka->UserZone;
								Header.OrigPoint=runAka->UserPoint;
								Header.DestPoint=0;
								if (appendpkt(name))
								{
								  writemsg(NULL,mn);
								  MsgHdr.Attribute|=8;
								  if (MsgHdr.Attribute&128)
								  {
								  	if (!MsgHdr.Deleted) MsgData.Deleted++;
								  	MsgHdr.Deleted=1;
								  }
								  fseek(mhf,mn*sizeof(MsgHdrType),SEEK_SET);
								  fwrite(&MsgHdr,sizeof(MsgHdrType),1,mhf);
								  fseek(mhf,0,SEEK_CUR);
									fputc((char)0,pktf);
									fputc((char)0,pktf);
									fclose(pktf);
									chmod(name,FIDO_MOD);
									chown(name,-1,FIDO_GID);
									while (runAka->next) runAka=runAka->next;
									while (runRoute->next) runRoute=runRoute->next;
								}
							}
				} else
				{
					strcpy(oldSubj,MsgHdr.Subj);
					for (runAka=Profile.Aka; runAka; runAka=runAka->next)
					{
						for (runRoute=runAka->Route; runRoute; runRoute=runRoute->next)
						  if (AddrMatch(runRoute,&MsgHdr)) break;
						if (runRoute) break;
					}
					if (MsgHdr.Attribute&16)
					{
						fattacherror=0;
						for (strcpy(sys,MsgHdr.Subj), d1=sys; d1; d1=d2)
						{
							d2=strchr(d1,32);
							if (d2) *d2++=0;
							if (*d1=='~')
								sprintf(file,"%s%s",HomePath,d1+1);
							else
								strcpy(file,d1);
							if (stat(file,&st))
							{
								Log("!Can't stat %s",file);
								printERR("Can't stat %s!\n",file);
								fattacherror=1;
							}
						}
						if (fattacherror)
						{
							printERR("Message #%u not send!\n",mn+1);
							Log("!Message #%u not send",mn+1);
							continue;
						}
						attached++;
						if (Profile.Aka->UserZone!=MsgHdr.DestZone)
							sprintf(name,"%s%s.%03x/%04x%04x.%s",OutboundPath,
									runAka->Outbound,
									MsgHdr.DestZone,MsgHdr.DestNet,MsgHdr.DestNode,
									Mailer?"CLO":"clo");
						else
							sprintf(name,"%s%s/%04x%04x.%s",OutboundPath,runAka->Outbound,
									MsgHdr.DestNet,MsgHdr.DestNode,
									Mailer?"CLO":"clo");
						flof=fopen(name,"at");
						if (flof)
						{
							log[0]=0;
							for (strcpy(sys,MsgHdr.Subj), d1=sys; d1; d1=d2)
							{
								d2=strchr(d1,32);
								if (d2) *d2++=0;
								if (*d1=='~')
									sprintf(file,"%s%s",HomePath,d1+1);
								else
									strcpy(file,d1);
								chmod(file,FIDO_MOD);
								chown(file,-1,FIDO_GID);
								if (MsgHdr.DeleteSent)
									fputc('^',flof);
								if (MsgHdr.TruncSent)
									fputc('#',flof);
								fprintf(flof,"%s\r\n",file);
								d3=strrchr(d1,'/');
								if (d3)	d3++; else d3=d1;
								strcat(log,d3);
								if (d2) strcat(log," ");
							}
							for (i=0; log[i]; i++)
								log[i]=toupper(log[i]);
							fclose(flof);
							strcpy(MsgHdr.Subj,log);
							chmod(name,FIDO_MOD);
							chown(name,-1,FIDO_GID);
						}
					}
					if (Profile.Aka->UserZone!=MsgHdr.DestZone)
						sprintf(name,"%s%s.%03x/%04x%04x.%s",OutboundPath,
								runAka->Outbound,
								MsgHdr.DestZone,MsgHdr.DestNet,MsgHdr.DestNode,
								MsgHdr.Direct?(Mailer?"DUT":"dut"):(Mailer?"CUT":"cut"));
					else
						sprintf(name,"%s%s/%04x%04x.%s",OutboundPath,
								runAka->Outbound,
								MsgHdr.DestNet,MsgHdr.DestNode,
								MsgHdr.Direct?(Mailer?"DUT":"dut"):(Mailer?"CUT":"cut"));
					Header.OrigZone=Header.qOrigZone=MsgHdr.OrigZone;
					Header.DestZone=Header.qDestZone=MsgHdr.DestZone;
					Header.OrigNet=MsgHdr.OrigNet;
					Header.DestNet=MsgHdr.DestNet;
					Header.OrigNode=MsgHdr.OrigNode;
					Header.DestNode=MsgHdr.DestNode;
					Header.OrigPoint=MsgHdr.OrigPoint;
					Header.DestPoint=0;									/* ??? */
					if (appendpkt(name))
					{
					  MsgHdr.Attribute|=8;
					  if (MsgHdr.Attribute&128)
					  {
					  	if (!MsgHdr.Deleted) MsgData.Deleted++;
					  	MsgHdr.Deleted=1;
					  }
					  fseek(mhf,mn*sizeof(MsgHdrType),SEEK_SET);
					  fwrite(&MsgHdr,sizeof(MsgHdrType),1,mhf);
					  fseek(mhf,0,SEEK_CUR);
					  crash++;
					  writemsg(NULL,mn);
						fputc((char)0,pktf);
						fputc((char)0,pktf);
						fclose(pktf);
						chmod(name,FIDO_MOD);
						chown(name,-1,FIDO_GID);
					}
					strcpy(MsgHdr.Subj,oldSubj);
				}
				scanned++;
				EL=100;
			}
		}
		Log("-Exported %u NetMail%c",scanned,(scanned==1)?0:'s');
		printERR("Exported %u NetMail%c\n",scanned,(scanned==1)?0:'s');
		if (crash || attached || request)
		{
			Log("-%u Crash %u FATT %u FREQ",crash,attached,request);
			printERR("%u Crash %u FATT %u FREQ\n",crash,attached,request);
		}
		if (hold)
		{
			Log("!%u on HOLD",hold);
			printERR("%u on HOLD\n",hold);
		}
		Log("+NetMail scanned");
		if ((dir=opendir(BasePath))!=NULL)
		{
			Log("+Scanning EchoMail");
			for (runAka=Profile.Aka; runAka; runAka=runAka->next)
			{
			  scanned=0;
			  reghold=0;
				rewinddir(dir);
				timer=time(NULL);
				tb=localtime(&timer);
				sprintf(name,TEMPPATH"%02u%02u%02u%02u.pkt",\
						tb->tm_mday,tb->tm_hour,tb->tm_min,tb->tm_sec);
				Log("-Scanning %s",runAka->NetName);
				Header.OrigNode=Header.DestNode=runAka->UserNode;
				Header.OrigNet=Header.DestNet=runAka->UserNet;
				Header.OrigZone=Header.DestZone=\
						Header.qDestZone=Header.qOrigZone=runAka->UserZone;
				Header.OrigPoint=runAka->UserPoint;
				Header.DestPoint=0;
				createpkt(name,0);
				while ((ent=readdir(dir))!=NULL && pktf)
					if (ent->d_name[0]=='+' && strcmp(ent->d_name,"+NETMAIL"))
					{
						textend=openarea(ent->d_name+1,NULL);
						if (MsgData.ReadOnly) continue;
						if (MsgData.RouteZone==runAka->UserZone &&
								MsgData.RouteNet==runAka->UserNet &&
								MsgData.RouteNode==runAka->UserNode)
						{
							if (strcmp(MsgData.Owner,Profile.UserName)==0)
							{
								for (hold=0, mn=0, msc=0;
										fread(&MsgHdr,sizeof(MsgHdrType),1,mhf); mn++)
								{
									if (MsgHdr.Attribute&512)
									{
										hold++;
										continue;
									}
									if ((MsgHdr.Attribute&264)==256 && !MsgHdr.Deleted)
									{
									  writemsg(ent->d_name+1,mn);
									  MsgHdr.Attribute|=8;
									  fseek(mhf,mn*sizeof(MsgHdrType),SEEK_SET);
									  fwrite(&MsgHdr,sizeof(MsgHdrType),1,mhf);
									  fseek(mhf,0,SEEK_CUR);
									  scanned++;
									  EL=100;
									  msc++;
									}
								}
								if (msc)
									Log("-%s [%u]",ent->d_name+1,msc);
								if (hold)
								{
									Log("!HOLD %s [%u]",ent->d_name+1,hold);
									reghold+=hold;
								}
							} else
							{
								Log("!Not Owner of %s",ent->d_name+1);
								printERR("Not Owner of %s!\n",ent->d_name+1);
							}
						}
					}
				fputc((char)0,pktf);
				fputc((char)0,pktf);
				fclose(pktf);
				chmod(name,FIDO_MOD);
				chown(name,-1,FIDO_GID);
				sprintf(sys,"Exported %u Message%c",scanned,scanned!=1?'s':0);
				strcat(sys," for ");
				strcat(sys,runAka->NetName);
				printERR("%s\n",sys);
				Log("-%s",sys);
				if (reghold)
				{
					Log("!%u on HOLD",reghold);
					printERR("%u on HOLD!\n",reghold);
				}
				if (!scanned)
					remove(name);
				else
				{
					if (Mailer)
					{
						if (Profile.Aka->UserZone!=runAka->UserZone)
							sprintf(log,"%s%s.%03x/%s.OAT",OutboundPath,
									runAka->Outbound,runAka->UserZone,
									Addr36(runAka->UserNet,runAka->UserNode,0));
						else
							sprintf(log,"%s%s/%s.OAT",OutboundPath,
									runAka->Outbound,
									Addr36(runAka->UserNet,runAka->UserNode,0));
					} else
					{
						if (Profile.Aka->UserZone!=runAka->UserZone)
							sprintf(log,"%s%s.%03x/%04x%04x.%s",OutboundPath,
									runAka->Outbound,runAka->UserZone,
									runAka->UserNet,runAka->UserNode,
									dayofweek());
						else
							sprintf(log,"%s%s/%04x%04x.%s",OutboundPath,
									runAka->Outbound,
									runAka->UserNet,runAka->UserNode,
									dayofweek());
					}
					sprintf(sys,Packer,log,name);
					system(sys);
					chmod(log,FIDO_MOD);
					chown(log,-1,FIDO_GID);
					if (!Mailer)
					{
						if (Profile.Aka->UserZone!=runAka->UserZone)
							sprintf(sys,"%s%s.%03x/%04x%04x.flo",OutboundPath,
									runAka->Outbound,runAka->UserZone,
									runAka->UserNet,runAka->UserNode);
						else
							sprintf(sys,"%s%s/%04x%04x.flo",OutboundPath,
									runAka->Outbound,
									runAka->UserNet,runAka->UserNode);
						if ((flof=fopen(sys,"at"))!=NULL)
						{
							fprintf(flof,"^%s\n",log);
							fclose(flof);
							chmod(sys,FIDO_MOD);
							chown(sys,-1,FIDO_GID);
						}
					}
				}
			}
			Log("+EchoMail scanned");
			closedir(dir);
		}
		Log("*Leaving Scan\n");
	} else
	{
		printERR("\nError while parsing ~/.feddirc\n");
		return 1;
	}
	return EL;
}

int createpkt(char *s, int nm)
{
	time_t timer;
	struct tm *tb;
	pktf=fopen(s,"wb");
	if (pktf)
	{
		Header.Version=2;
		Header.Baud=9600;
		Header.ProductCodeHi=Header.ProductCodeLo=0;
		Header.SerialNumMin=VERlo;												/* Version */
		Header.SerialNumMaj=VERhi;												/* Version */
	  timer=time(NULL);
	  tb=localtime(&timer);
		Header.Year=1900+tb->tm_year;
		Header.Month=tb->tm_mon;
		Header.Day=tb->tm_mday;
		Header.Hour=tb->tm_hour;
		Header.Minute=tb->tm_min;
		Header.Second=tb->tm_sec;
		Header.Use4dAddressing=1;
		memset(Header.Password,0,8);
		if (runAka->UserZone==Header.DestZone &&
				runAka->UserNet==Header.DestNet &&
				runAka->UserNode==Header.DestNode/* && nm*/)
			strncpy(Header.Password,runAka->Password,8);
		Header.CapWord=1;
		Header.ProductData=Header.ProductData2=0;
		fwrite(&Header,sizeof(PktHdrType),1,pktf);
		return 1;
	} else return 0;
}

int appendpkt(char *s)
{
	struct stat st;
	if ((pktf=fopen(s,"r+b")))
	{
		stat(s,&st);
		fseek(pktf,st.st_size-2,SEEK_SET);
	}
	else
		createpkt(s,1);
	if (pktf) return 1; else return 0;
}

void writemsg(char *a, int num)
{
	int i;
	char *atx, line[80], *d1, *d2;
	PktHdr.Version=2;
	PktHdr.OrigNode=PktHdr.DestNode=runAka->UserNode;
	PktHdr.OrigNet=PktHdr.DestNet=runAka->UserNet;
	if (MsgHdr.DestNode)
	{
	  PktHdr.DestNode=MsgHdr.DestNode;
		PktHdr.DestNet=MsgHdr.DestNet;
	}
	PktHdr.Attribute=MsgHdr.Attribute&0x7413; /* zero unnuetze Flags */
	PktHdr.Cost=0;
	fwrite(&PktHdr,sizeof(PktHdr),1,pktf);
	fwrite(&MsgHdr.DateTime,20,1,pktf);
	strcpy(line,MsgHdr.WhoTo);
	transback(line,MsgData.CharSet);
	fputs(line,pktf); fputc((char)0,pktf);
	strcpy(line,MsgHdr.WhoFrom);
	transback(line,MsgData.CharSet);
	fputs(line,pktf); fputc((char)0,pktf);
	strcpy(line,MsgHdr.Subj);
	transback(line,MsgData.CharSet);
	fputs(line,pktf); fputc((char)0,pktf);
	if (a)
	{
		fputs("AREA:",pktf);
		fputs(a,pktf);
		fputc((char)0xd,pktf);
	}
	fseek(mtf,256*MsgHdr.StartRec,SEEK_SET);
	atx=(char *)malloc(256*MsgHdr.NumRecs+513);
	atx[0]=0xd;
	fread(atx+1,256,MsgHdr.NumRecs,mtf);
	if ((d1=strstr(atx,"\015\001MSGID: "))!=NULL)
	{
		d2=strchr(d1+1,0xd);
		if (!d2) d2=strchr(d1+1,0);
		memmove(d1,d2,strlen(d2)+1);
	}
	sprintf(line,"\001MSGID: %u:%u/%u.%u@%s %08x\r",MsgHdr.OrigZone,
				MsgHdr.OrigNet,MsgHdr.OrigNode,
				MsgHdr.OrigPoint,runAka->NetName,MsgId(MsgHdr.DateTime,num));
	memmove(atx+1+strlen(line),atx+1,strlen(atx)+1);
	memcpy(atx+1,line,strlen(line));
	if ((d1=strstr(atx,"\015\001CHRS: "))!=NULL)
	{
		d2=strchr(d1+1,0xd);
		if (!d2) d2=strchr(d1+1,0);
		memmove(d1,d2,strlen(d2)+1);
	}
	sprintf(line,"\001CHRS: %s\r",CHRSETS[MsgData.CharSet][0]);
	memmove(atx+1+strlen(line),atx+1,strlen(atx)+1);
	memcpy(atx+1,line,strlen(line));
	if ((d1=strstr(atx,"\015\001PID: "))!=NULL)
	{
		d2=strchr(d1+1,0xd);
		if (!d2) d2=strchr(d1+1,0);
		memmove(d1,d2,strlen(d2)+1);
	}
	sprintf(line,"\001PID: FEddi %s\r",VERSION);
	memmove(atx+1+strlen(line),atx+1,strlen(atx)+1);
	memcpy(atx+1,line,strlen(line));
	if (MsgData.NetMail)
	{
		if (MsgHdr.DestPoint)
		{
			if ((d1=strstr(atx,"\015\001TOPT "))!=NULL)
			{
				d2=strchr(d1+1,0xd);
				if (!d2) d2=strchr(d1+1,0);
				memmove(d1,d2,strlen(d2)+1);
			}
			sprintf(line,"\001TOPT %u\r",MsgHdr.DestPoint);
			memmove(atx+1+strlen(line),atx+1,strlen(atx)+1);
			memcpy(atx+1,line,strlen(line));
		}
		if (MsgHdr.OrigPoint)
		{
			if ((d1=strstr(atx,"\015\001FMPT "))!=NULL)
			{
				d2=strchr(d1+1,0xd);
				if (!d2) d2=strchr(d1+1,0);
				memmove(d1,d2,strlen(d2)+1);
			}
			sprintf(line,"\001FMPT %u\r",MsgHdr.OrigPoint);
			memmove(atx+1+strlen(line),atx+1,strlen(atx)+1);
			memcpy(atx+1,line,strlen(line));
		}
		if ((d1=strstr(atx,"\015\001INTL "))!=NULL)
		{
			d2=strchr(d1+1,0xd);
			if (!d2) d2=strchr(d1+1,0);
			memmove(d1,d2,strlen(d2)+1);
		}
		sprintf(line,"\001INTL %u:%u/%u %u:%u/%u\r",\
				MsgHdr.DestZone,MsgHdr.DestNet,MsgHdr.DestNode,\
				MsgHdr.OrigZone,MsgHdr.OrigNet,MsgHdr.OrigNode);
		memmove(atx+1+strlen(line),atx+1,strlen(atx)+1);
		memcpy(atx+1,line,strlen(line));
	} else
	{
		if ((d1=strstr(atx,"\015SEEN-BY: "))!=NULL)
		{
			d2=strchr(d1+1,0xd);
			if (!d2) d2=strchr(d1+1,0);
			memmove(d1,d2,strlen(d2)+1);
		}
	  sprintf(line,"SEEN-BY: %u/%u\r",MsgData.RouteNet,MsgData.RouteNode);
	  strcat(atx,line);
		if ((d1=strstr(atx,"\015\001PATH: "))!=NULL)
		{
			d2=strchr(d1+1,0xd);
			if (!d2) d2=strchr(d1+1,0);
			memmove(d1,d2,strlen(d2)+1);
		}
	 	sprintf(line,"\001PATH: %u/%u\r",MsgData.RouteNet,MsgData.RouteNode);
	 	strcat(atx,line);
	}
	fseek(mtf,256*textend,SEEK_SET);
	i=(strlen(atx+1)+1)/256+1;
	MsgHdr.NumRecs=i;
	MsgHdr.StartRec=textend;
	textend+=i;
	fwrite(atx+1,256,i,mtf);
	transback(atx+1,MsgData.CharSet);
	fwrite(atx+1,strlen(atx+1),1,pktf);
	fputc((char)0,pktf);
	free(atx);
}

void put36(char *s, unsigned int n, int len)
{
	s+=len;
	*s--=0;
	while(len--)
	{
		int d=n%36;
		n/=36;
		if (d<10)
			*s--=d+'0';
		else
			*s--=d-10+(Mailer?'A':'a');
	}
}

char *Addr36(short Net, short Node, short Point)
{
	put36(as,Net,3);
	put36(as+3,Node,3);
	put36(as+6,Point,2);
	return as;
}

char *dayofweek()
{
	time_t timer;
	struct tm *tblock;
	timer=time(NULL);
	tblock=localtime(&timer);
	sprintf(day,"%s0",wot[tblock->tm_wday]);
	return day;
}

void spezExt(char *s)
{
}
