/*
 * 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 <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "regex.h"
#include <signal.h>
#include <ncurses.h>
#include "proc.h"
#include "structs.h"
#include "colors.h"
#include "functs.h"
#include "mbhelp.h"
#include "mbnl.h"

extern LineListType *MsgTxt;
extern int MsgLines;

char _FILENAME[100]="(^|[[:space:]]+)[A-Z0-9_!$&_{}#%()@-]{1,8}\\.[A-Z0-9_!$&_{}#%()@-]{2,3}($|[[:space:]]+)";

typedef struct
{
	char name[13];
	char passwd[10];
	int mark;
} FileNameType;

#define FileNameSize sizeof(FileNameType)

FileNameType *ReqFile=NULL;
int numReqFile=0;

int reloadRequest(Addr4dType *addr)
{
	Addr4dType *rrou;
	UserAkaType *raka;
	MsgHdrType mdh;
	FILE *f;
	char name[PATH_MAX], *d1;
	mdh.DestZone=addr->Zone;
	mdh.DestNet=addr->Net;
	mdh.DestNode=addr->Node;
	mdh.DestPoint=addr->Point;
	for (raka=Profile.Aka; raka; raka=raka->next)
	{
		for (rrou=raka->Route; rrou; rrou=rrou->next)
		{
			if (AddrMatch(rrou,&mdh))
			{
				if (Profile.Aka->UserZone!=mdh.DestZone)
					sprintf(name,"%s%s.%03x/%04x%04x.%s",OutboundPath,
							raka->Outbound,
							mdh.DestZone,mdh.DestNet,mdh.DestNode,
							Mailer?"REQ":"req");
				else
					sprintf(name,"%s%s/%04x%04x.%s",OutboundPath,
							raka->Outbound,
							mdh.DestNet,mdh.DestNode,
							Mailer?"REQ":"req");
				if ((f=fopen(name,"rt"))!=NULL)
				{
					while (fgets(name,80,f))
					{
						if ((d1=strchr(name,'\r'))) *d1=0;
						if ((d1=strchr(name,'\n'))) *d1=0;
						d1=strchr(name,32);
						if (d1) *d1++=0;
						numReqFile++;
						ReqFile=(FileNameType *)realloc(ReqFile,
								FileNameSize*numReqFile);
						strcpy(ReqFile[numReqFile-1].name,name);
						if (d1)
							strcpy(ReqFile[numReqFile-1].passwd,d1);
						else
							memset(ReqFile[numReqFile-1].passwd,0,10);
						ReqFile[numReqFile-1].mark=1;
					}
					fclose(f);
					remove(name);
					if (!Mailer)
					{
						strcpy(name+strlen(name)-4,".flo");
						remove(name);
					}
				}
				break;
			}
		}
		if (rrou) break;
	}
	return numReqFile;
}

int extractFilenames()
{
	int i, j;
	char *d1, line[4096];
	struct re_pattern_buffer regexp;
	struct re_registers regs;
	memset(&regexp,0,sizeof(struct re_pattern_buffer));
	re_set_syntax(RE_SYNTAX_POSIX_EGREP);
	if (re_compile_pattern(_FILENAME,strlen(_FILENAME),&regexp))
		return 0;
	for (j=0; j<MsgLines; j++)
	{
		strcpy(line,MsgTxt[j].line);
		for (i=0; i!=-1;)
		{
			regs.num_regs=0;
			regs.start=regs.end=NULL;
			i=re_search(&regexp,line,strlen(line),i,strlen(line),&regs);
			if (i!=-1)
			{
				numReqFile++;
				ReqFile=(FileNameType *)realloc(ReqFile,
						FileNameSize*numReqFile);
				while (line[i]==32) i++;
				strncpy(ReqFile[numReqFile-1].name,line+i,12);
				ReqFile[numReqFile-1].name[12]=0;
				d1=strchr(ReqFile[numReqFile-1].name,32);
				if (d1) *d1=0;
				memset(ReqFile[numReqFile-1].passwd,0,9);
				ReqFile[numReqFile-1].mark=0;
				i++;
				free(regs.start);
				free(regs.end);
			}
		}
	}
	return numReqFile;
}

void saveRequest(Addr4dType *addr)
{
	Addr4dType *rrou;
	UserAkaType *raka;
	MsgHdrType mdh;
	FILE *f;
	char name[PATH_MAX], flof[PATH_MAX];
	int i;
	mdh.DestZone=addr->Zone;
	mdh.DestNet=addr->Net;
	mdh.DestNode=addr->Node;
	mdh.DestPoint=addr->Point;
	for (raka=Profile.Aka; raka; raka=raka->next)
	{
		for (rrou=raka->Route; rrou; rrou=rrou->next)
		{
			if (AddrMatch(rrou,&mdh))
			{
				if (Profile.Aka->UserZone!=mdh.DestZone)
					sprintf(name,"%s%s.%03x/%04x%04x.%s",OutboundPath,
							raka->Outbound,
							mdh.DestZone,mdh.DestNet,mdh.DestNode,
							Mailer?"REQ":"req");
				else
					sprintf(name,"%s%s/%04x%04x.%s",OutboundPath,
							raka->Outbound,
							mdh.DestNet,mdh.DestNode,
							Mailer?"REQ":"req");
				if ((f=fopen(name,"wt"))!=NULL)
				{
					for (i=0; i<numReqFile; i++)
						if (ReqFile[i].mark)
							if (ReqFile[i].passwd[0])
								fprintf(f,"%s %s\r\n",ReqFile[i].name,ReqFile[i].passwd);
							else
								fprintf(f,"%s\r\n",ReqFile[i].name);
					fclose(f);
					chmod(name,FIDO_MOD);
					chown(name,-1,FIDO_GID);
				}
				if (!Mailer)
				{
					if (Profile.Aka->UserZone!=mdh.DestZone)
						sprintf(name,"%s%s.%03x/%04x%04x.flo",OutboundPath,
								raka->Outbound,
								mdh.DestZone,mdh.DestNet,mdh.DestNode);
					else
						sprintf(name,"%s%s/%04x%04x.flo",OutboundPath,
								raka->Outbound,
								mdh.DestNet,mdh.DestNode);
					if ((f=fopen(flof,"wt")))
					{
						fprintf(f,"^%s\r\n",name);
						fclose(f);
						chmod(flof,FIDO_MOD);
						chown(flof,-1,FIDO_GID);
					}
				}
			}
		}
	}
}

void showreqfiles(WINDOW *win, int p, int m)
{
	int y, yy;
	yy=(LINES-13)/2-p-1;
	for (y=0; y<yy; y++)
		mvwaddstr(win,4+y,1,"                            ");
	for (; y<LINES-13; y++)
	{
		mvwaddstr(win,4+y,1,"                            ");
		if (p-(LINES-13)/2+1+y<numReqFile)
		{
			if (p-(LINES-13)/2+1+y==p)
				mvwprintw(win,4+y,1,"  %c %c%-12s%c%-9s%c",
						ReqFile[p-(LINES-13)/2+1+y].mark?'*':32,
						m?32:'>',
						ReqFile[p-(LINES-13)/2+1+y].name,
						m?'>':'<',
						ReqFile[p-(LINES-13)/2+1+y].passwd,
						m?'<':32);
			else
				mvwprintw(win,4+y,1,"  %c  %-12s %-9s ",
						ReqFile[p-(LINES-13)/2+1+y].mark?'*':32,
						ReqFile[p-(LINES-13)/2+1+y].name,
						ReqFile[p-(LINES-13)/2+1+y].passwd);
		}
	}
	wrefresh(win);
}

void request(MsgHdrType *hdr, WINDOW *wHlp, int manual)
{
	WINDOW *win=NULL;
	int i, pos, in=0, ende=0, ok, side=0;
	Addr4dType adr, oldadr;
	char inp[22], name[40], *d1, addr[80];
	NLentryType ent;
	FILE *f;
	free(ReqFile);
	ReqFile=NULL;
	numReqFile=0;
	sprintf(name,"%smagic",BasePath);
	if ((f=fopen(name,"rt"))!=NULL)
	{
		while (fgets(name,39,f))
		{
			if (name[0]==';') continue;
			if ((d1=strchr(name,'\n'))) *d1=0;
			if ((d1=strchr(name,'\r'))) *d1=0;
			numReqFile++;
			ReqFile=(FileNameType *)realloc(ReqFile,FileNameSize*numReqFile);
			memset(&(ReqFile[numReqFile-1]),0,FileNameSize);
			upperstr(name);
			d1=strchr(name,',');
			if (d1)
			{
				*d1++=0;
				strcpy(ReqFile[numReqFile-1].passwd,d1);
			}
			strcpy(ReqFile[numReqFile-1].name,name);
		}
		fclose(f);
	} else
	{
		numReqFile=1;
		ReqFile=(FileNameType *)malloc(FileNameSize);
		memset(&(ReqFile[0]),0,FileNameSize);
		strcpy(ReqFile[0].name,"FILES");
	}
	if ((win=openask(LINES-8,30,7,COLS/2-15,"Request Files",COL_Menu))!=NULL)
	{
		wmove(win,3,1);
		for (i=0; i<28; i++) waddch(win,ACS_HLINE);
		mvwaddstr(win,3,6,"Filename");
		mvwaddstr(win,3,19,"Password");
		if (manual)
		{
			mvwaddstr(win,1,2,"from");
			inp[0]=0;
			adr.Zone=0;
			while (inputline(win,wHlp,1,7,21,inp,NULL,0,0)!=-2)
			{
				if (!inp[0])
				{
					Beep();
					continue;
				}
				if (!Str2Addr(inp,&adr)) break;
				adr.Zone=0;
				Beep();
			}
			if (adr.Zone==0)
			{
				delwin(win);
				return;
			}
			adr.Point=0;
			reloadRequest(&adr);
		} else
		{
			adr.Zone=hdr->OrigZone;
			adr.Net=hdr->OrigNet;
			adr.Node=hdr->OrigNode;
			adr.Point=0;
			reloadRequest(&adr);
			extractFilenames();
		}
		werase(wHlp);
		mvwaddstr(wHlp,0,2,bhelp_request);
		wrefresh(wHlp);
		mvwprintw(win,1,2,"from %u:%u/%u",adr.Zone,adr.Net,adr.Node);
		sprintf(addr,"%u:%u/%u",adr.Zone,adr.Net,adr.Node);
		ok=keyentry(addr,&ent);
		if (ok)
			if (strlen(ent.Box)>21) ent.Box[21]=0;
		mvwaddstr(win,2,7,ok?"- Unlisted -":ent.Box);
		wclrtoeoln(win);
		pos=0;
		showreqfiles(win,pos,side);
		while (!ende)
		{
			in=getchn();
			switch (in)
			{
				case 10:
					if (!numReqFile) {Beep(); break;}
					if (side)
					{
						mvwaddch(win,LINES/2-4,19,'!');
						strcpy(inp,ReqFile[pos].passwd+1);
						if (!inputline(win,wHlp,LINES/2-4,20,8,inp,NULL,0,0))
						{
							strcpy(ReqFile[pos].passwd+1,inp);
							ReqFile[pos].passwd[0]='!';
						}
					} else
					{
						strcpy(inp,ReqFile[pos].name);
						if (!inputline(win,wHlp,LINES/2-4,6,12,inp,NULL,0,0))
							strcpy(ReqFile[pos].name,inp);
					}
					werase(wHlp);
					mvwaddstr(wHlp,0,2,bhelp_request);
					wrefresh(wHlp);
					showreqfiles(win,pos,side);
					break;
				case 32:
					ReqFile[pos].mark=1-ReqFile[pos].mark;
					showreqfiles(win,pos,side);
					break;
				case 0x1b:
					switch ((in=getchn()))
					{
						case 'h':
							showRequestHelp();
							touchwin(win);
							wrefresh(win);
							showreqfiles(win,pos,side);
							break;
						case 'g':
							ende=1;
							break;
						case 'a':
							sprintf(inp,"%u:%u/%u",adr.Zone,adr.Net,adr.Node);
							oldadr=adr;
							adr.Zone=0;
							while (!inputline(win,wHlp,1,7,21,inp,NULL,0,0))
							{
								if (!Str2Addr(inp,&adr)) break;
								adr.Zone=0;
								Beep();
							}
							if (adr.Zone==0)
								adr=oldadr;
							adr.Point=0;
							mvwprintw(win,1,2,"from %u:%u/%u",adr.Zone,adr.Net,adr.Node);
							sprintf(addr,"%u:%u/%u",adr.Zone,adr.Net,adr.Node);
							ok=keyentry(addr,&ent);
							if (ok)
								if (strlen(ent.Box)>21) ent.Box[21]=0;
							mvwaddstr(win,2,7,ok?"- Unlisted -":ent.Box);
							wclrtoeoln(win);
							wrefresh(win);
							werase(wHlp);
							mvwaddstr(wHlp,0,2,bhelp_request);
							wrefresh(wHlp);
							reloadRequest(&adr);
							showreqfiles(win,pos,side);
							break;
						case 0x1b:
							ende=-1;
							break;
						case 0x5b:
							switch (getchn())
							{
								case 0x41:
									if (pos>0) pos--;
									showreqfiles(win,pos,side);
									break;
								case 0x42:
									if (pos<numReqFile-1) pos++;
									showreqfiles(win,pos,side);
									break;
								case 0x43:
								case 0x44:
									side=1-side;
									showreqfiles(win,pos,side);
									break;
								case 0x31: getch();
									pos=0;
									showreqfiles(win,pos,side);
									break;
								case 0x34: getch();
									pos=numReqFile-1;
									showreqfiles(win,pos,side);
									break;
								case 0x35: getch();
									pos-=(LINES-12)/2;
									if (pos<0) pos=0;
									showreqfiles(win,pos,side);
									break;
								case 0x36: getch();
									pos+=(LINES-12)/2;
									if (pos>numReqFile-1) pos=numReqFile-1;
									showreqfiles(win,pos,side);
									break;
								case 0x32: getch();
									numReqFile++;
									ReqFile=(FileNameType *)realloc(ReqFile,
										FileNameSize*numReqFile);
									memset(&(ReqFile[numReqFile-1]),0,FileNameSize);
									showreqfiles(win,numReqFile-1,side);
									strcpy(inp,ReqFile[numReqFile-1].name);
									mvwaddch(win,LINES/2-4,5,'>');
									mvwaddch(win,LINES/2-4,18,'<');
									mvwaddch(win,LINES/2-4,28,' ');
									if (!inputline(win,wHlp,LINES/2-4,6,12,inp,NULL,0,0))
									{
										strcpy(ReqFile[numReqFile-1].name,inp);
										ReqFile[numReqFile-1].mark=1;
										pos=numReqFile-1;
									} else
									{
										numReqFile--;
										ReqFile=(FileNameType *)realloc(ReqFile,
											FileNameSize*numReqFile);
									}
									werase(wHlp);
									mvwaddstr(wHlp,0,2,bhelp_request);
									wrefresh(wHlp);
									showreqfiles(win,pos,side);
									break;
							}
					}
					break;
			}
		}
		if (ende==1)
			saveRequest(&adr);
		delwin(win);
		return;
	}
	Beep();
}
