#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include <time.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/execbase.h>
#include <libraries/dosextens.h>
#include <proto/exec.h>
#include <proto/dos.h>

#include "/lib/misc.h"
#include "rn.h"
#include "rnlanguage.h"

extern char Host[];
extern char Upload[];
extern char Newshome[];
extern char Batchfile[];
extern char Netlogfile[];
extern char Activefile[];
extern char Sysfile[];

#define HUNKSIZE	2048
#define MAXGROUPS   100
#define NAMELEN		100
#define MAXNAMELEN	256

char	Machine[NAMELEN]="tap.tampere.fi";		/* machine we are interested in */
UBYTE	*buffer;
char	**Groups=0L;

int 	Sysnum=0,Numgrp=0;

int  getgrp(char *name);

/***********************************************************************\
*  These are to speed up the net packet unpacking.                      *
\***********************************************************************/

#define FAST 1

#if FAST

#define MAXHOSTS	20	/* number of the hosts in the sys-file */
#define HOSTNAMELEN	32
#define MAXPATTERNS	24	/* max patterns for each host */
#define PATTERNLEN	24

char	BatchHost[MAXHOSTS][HOSTNAMELEN];
int		BatchHosts;
char	BatchPattern[MAXHOSTS][MAXPATTERNS][PATTERNLEN];
int		BatchPatterns[MAXHOSTS];

int  readbatches(char *sysfile);
int  batchgroup(int host,char *group);

int readbatches(char *sysfile)
{	char line[MAXNAMELEN],pat[MAXNAMELEN];
	FILE *handle;
	int i,j;

	BatchHosts=0;
	if(handle=fopen(sysfile,"rb"))
	{
		while(!feof(handle))
		{
			if(fgets(line,MAXNAMELEN,handle)==0)
				break;
			i=strlen(line)-1;
			if(i<0 || feof(handle))
				break;

			line[i]=0;
			if(i && line[0]!='#')
			{
				i=0;
				while(line[i] && line[i]!=':')
					++i;
				if(line[i])
					line[i]=0;
				else
					line[i+1]=0;
				strcpy(BatchHost[BatchHosts],line);		/* hostname */

				strcpy(pat,line+i+1);	/* newsgroup patterns */

				j=0;
				while(pat[j])		/* for each pattern */
				{
					i=j;
					while(pat[j] && pat[j]!=',')
						j++;

					strncpy(BatchPattern[BatchHosts][BatchPatterns[BatchHosts]],pat+i,j-i);
					BatchPattern[BatchHosts][BatchPatterns[BatchHosts]][j-i]=0;

					BatchPatterns[BatchHosts]++;
					if(pat[j])
						j++;

				}	/* for all patterns */
				BatchHosts++;
				if(BatchHosts==MAXHOSTS)
				{
					printf("Too many hosts in %s\n",sysfile);
					break;
				}
			}
		}
		fclose(handle);
	}
	return 0;
}


int batchgroup(int host,char *group)
{	int match,i;

	match=0;
	for(i=0;i<BatchPatterns[host];i++)	/* for each pattern */
	{
/*		for(k=0;k<numgrp;k++)
		{*/	/* for each x-posted group */

			if(BatchPattern[host][i][0]=='-')
			{
				if(simplepatternmatch(group,BatchPattern[host][i]+1))
				{	match=0;
				}
			}
			else
			{
				if(simplepatternmatch(group,BatchPattern[host][i]))
				{	match=-1;
				}
			}

/*		}*/
	}
	if(match)
		return -1;
	else
		return 0;
}
#endif

/***********************************************************************/
/* rnnet starts */

int  rnnet(int argc,char *argv[])
{	register int i,j;
	int done,len,mgs=0,files=0,errorvalue=0,dpath,start,temp,number;
    char name[NAMELEN],filename[NAMELEN],group[NAMELEN+1],groups[MAXNAMELEN],
		 tempstr[NAMELEN],path[MAXNAMELEN],xref[MAXNAMELEN],c;
	long writefile,readfile,filesize;
	FILE *fp,*batch;

	if(strlen(Host)>28) Host[28]=0;/* We don't want to exceed AmigaDOS' 30 chars */

	if(Groups=(char **)AllocMem(MAXGROUPS*sizeof(char *),MEMF_PUBLIC | MEMF_CLEAR))
	{
		if(Groups[0]=(char *)AllocMem(MAXGROUPS*NAMELEN,MEMF_PUBLIC | MEMF_CLEAR))
		{
			for(i=1;i<MAXGROUPS;i++)
				Groups[i]=NAMELEN*i+Groups[0];
		}
	}

	if(!Groups || !Groups[0])
	{
		printf(printout(MSG_MEM_ALLOC_ERR_2));
		errorvalue=42;
		goto freememory;
	}

	if(argc>1)
	{
		strcpy(Machine,argv[1]);
		if (strlen(Machine)>28) Machine[28]=0;
	}

	if(argc==4)		/* rnnet Machine send file */
	{
		if(!strcmp(argv[2],"send"))
		{
			sprintf(filename,"%s%s",Newshome,Machine);
			/* if we have old packet.. */
			if(writefile=Open(filename,MODE_OLDFILE))
			{
				Seek(writefile,0L,OFFSET_END);
			}
			else
				writefile=Open(filename,MODE_NEWFILE);

			if(writefile)
			{
				if(!strcmp(argv[2],"send"))
				{
					if(readfile=Open(argv[3],MODE_OLDFILE))
					{
						Seek(readfile,0,OFFSET_END);
						filesize=Seek(readfile,0,OFFSET_BEGINNING);

						i=strlen(argv[3]);
						while(i>=0 && argv[3][i]!='/' && argv[3][i]!=':')	i--;
						strcpy(name,argv[3]+i+1);

						len=strlen(name)+1+filesize;

						if(buffer=(char *)AllocMem(filesize,MEMF_PUBLIC | MEMF_CLEAR))
						{
							Read(readfile,buffer,filesize);

							Write(writefile,&"F",1);	/* File packet */
							Write(writefile,&len,sizeof(int));	/* name lenght */
							Write(writefile,name,strlen(name)+1);
							Write(writefile,buffer,filesize);
							FreeMem(buffer,filesize);
						}
						Close(readfile);
					}
					else
					{
						printf(printout(MSG_CANT_OPEN),argv[3]);
						errorvalue=10;
					}
				}
				Close(writefile);
			}
			else
			{
				printf(printout(MSG_CANT_OPEN),filename);
				errorvalue=20;
			}
		}
		else
		{
			printf(printout(MSG_NET_USAGE));
			errorvalue=5;
		}
	}
	else
	if(argc==3)	/* rnnet Machine unpack|pack */
	{
		if(!strcmp(argv[2],"pack"))
		{
			sprintf(filename,"%s%s",Newshome,Machine);

			/* if we have old packet, append.. */
			if(writefile=Open(filename,MODE_OLDFILE))
			{
				Seek(writefile,0L,OFFSET_END);
				++mgs;
			}
			if(writefile || (writefile=Open(filename,MODE_NEWFILE)))
			{
				sprintf(filename,Batchfile,Machine);
				if(batch=fopen(filename,"rb"))
				{
					while(!feof(batch))
					{
						if(fgets(name,MAXNAMELEN-1,batch)==0)
							break;

						i=strlen(name)-1;
						if(i<1 || feof(batch))
							break;
						name[i]=0;

						i=0;
						while(name[i] && name[i]!=' ')
							++i;
						if(name[i])
							name[i]=0;
						else
							name[i+1]=0;

						i=0;	/* See if we have full filename */
						while(name[i] && name[i]!=':')
							++i;
						if(name[i]!=':')
						{
							sprintf(filename,"%s%s",Newshome,name);
						}
						else
						{
							strcpy(filename,name);
						}

						dpath=0;
						if(readfile=Open(filename,MODE_OLDFILE))
						{
							Seek(readfile,0,OFFSET_END);
							filesize=Seek(readfile,0,OFFSET_BEGINNING);

							if(buffer=(char *)AllocMem(filesize,MEMF_PUBLIC | MEMF_CLEAR))
							{
								len=Read(readfile,buffer,filesize);

								start=0;	/* Xref: is guaranteed to be on the first line */
								if(!strncmp(buffer,"Xref: ",6))
								{
									while(buffer[start]!='\n' && buffer[start]!='\r' && buffer[start])
										++start;
									++start;
								}
								j=start;
								while(j<len)
								{
									if(!strncmp(buffer+j,"Path: ",6))
									{
										dpath=j+6;
										break;
									}
									while(buffer[j] && buffer[j]!='\n' && buffer[j]!='\r')
										j++;
									j++;
								}
								if(dpath)
								{
									Write(writefile,"A",1);
									temp=len+strlen(Host)+1-start;
									Write(writefile,&temp,sizeof(int));
									Write(writefile,buffer+start,j+6);
									Write(writefile,Host,strlen(Host));
									Write(writefile,"!",1);
									Write(writefile,buffer+j+6,len-j-6);
								}
								else
								{
									/* If we didn't have Path:, add it! */
									temp=len-start+6+strlen(Host)+1;
									Write(writefile,"A",1);
									Write(writefile,"Path: ",6);
									Write(writefile,Host,strlen(Host));
									Write(writefile,"\n",1);
									Write(writefile,&temp,sizeof(int));
									Write(writefile,buffer+start,temp);
								}
								FreeMem(buffer,filesize);
							}
							Close(readfile);
							++mgs;
						}
					}
					fclose(batch);
					sprintf(filename,Batchfile,Machine);
					DeleteFile(filename);
				}
				Close(writefile);

				if(!mgs)
				{
					sprintf(filename,"%s%s",Newshome,Machine);
					DeleteFile(filename);	/* if no Articles, delete packet */
				}
			}
			else
			{
				printf(printout(MSG_CANT_OPEN),filename);
				errorvalue=20;
			}
		}
		else
		if(!strcmp(argv[2],"unpack"))
		{	int *msgs;

#if FAST
			readbatches(Sysfile);
#endif
			if(msgs=(int *)AllocMem(MAXGROUPS*sizeof(int),MEMF_CLEAR))
			{
				for(i=0;i<MAXGROUPS;msgs[i++]=0);
				sprintf(filename,"%s%s",Newshome,Host);
				writefile=0L;

				if(readfile=Open(filename,MODE_OLDFILE))
				{
					done=0;
					while(!done)
					{
						len=Read(readfile,&c,1);
						if(!len)	break;			/* End of packet (file) */

						Read(readfile,&len,sizeof(int));

						switch(c)
						{
						case 'A':	/* article start */
							if(buffer=(char *)AllocMem(len,MEMF_PUBLIC | MEMF_CLEAR))
							{
								Read(readfile,buffer,len);

								j=0;
								groups[0]=path[0]='\0';
								while(j<len)
								{
									if(!strncmp(buffer+j,"Newsgroups: ",12))
									{
										i=0;
										while((groups[i]=buffer[12+j+i])!='\n')
											++i;
										groups[i]=0;
									}
									if(!strncmp(buffer+j,"Path: ",6))
									{
										i=0;
										while((path[i]=buffer[6+j+i])!='\n')
											++i;
										path[i]=0;
									}
									if(groups[0] && path[0])
										break;
									while(j<len && buffer[j]!='\n')
										j++;
									j++;
								}
								if(!path[0])
									sprintf(path,"Path: %s!nobody",Machine);

								xref[0]='\0';
								i=0;
/* TODO: post the article to all groups and use Xref:-line */
								while(groups[i])
								{
									j=i;
									while(groups[j] && groups[j]!=',')
										++j;
									strncpy(group,groups+i,j-i);
									group[j-i]=0;

									/* Just safety precaution.. */
									while(group[0]==' ')
										strcpy(group,group+1);

									lowercase(group,group);
									if(is_group(group) || !groups[j])
										break;
									i=j+1;
								}
								if(!is_group(group))
								{
									strcpy(group,"junk");
									if(!is_group(group))
									{
										if(add_group(group,60,FLAG_READ_ONLY))
										{
											printf(printout(MSG_GROUP_CREATION_ERR));
										}
									}
								}
								printf("%s\n",group);
								++msgs[getgrp(group)];

								number=inc_next(group);
								articlename(name,group,number,-1);

/* append the name of the article file to the appropriate batch-files */
#if FAST
								for(j=0;j<BatchHosts;j++)
								{
									if(!strstr(path,BatchHost[j]))
									{
										if(batchgroup(j,groups))
										{
											sprintf(tempstr,Batchfile,BatchHost[j]);
											if(batch=fopen(tempstr,"ab"))
											{
												fprintf(batch,"%s\n",name);
												fclose(batch);
											}
										}
									}
								}
#else
								batchfile(name,groups,path);
#endif

								articlename(name,group,number,0);
								if(writefile=Open(name,MODE_NEWFILE))
								{
									Write(writefile,buffer,len);
									Close(writefile);
								}
								FreeMem(buffer,len);
							}
							else
							{
								Seek(readfile,len,OFFSET_CURRENT);
							}
							break;
						case 'F':	/* File start */
							if(buffer=(char *)AllocMem(len,MEMF_PUBLIC | MEMF_CLEAR))
							{
								Read(readfile,buffer,len);
								sprintf(name,"%s%s",Upload,buffer);
								filesize=len-strlen(buffer)-1;

								if(writefile=Open(name,MODE_NEWFILE))
								{
									Write(writefile,buffer+strlen(buffer)+1,filesize);
									Close(writefile);
									++files;
								}
								FreeMem(buffer,len);
							}
							else
							{
								Seek(readfile,len,OFFSET_CURRENT);
							}
							break;
						default:
							printf(printout(MSG_UNKNOWN_HUNK),c);
							break;
						}
					}
					Close(readfile);
					DeleteFile(filename);
					mgs=0;
					if(Numgrp || files)
					{
						if(fp=fopen(Netlogfile,"a"))
						{	for(i=0;i<Numgrp;i++)
							{	fprintf(fp,"102 %d %s\n",msgs[i],Groups[i]);
								mgs+=msgs[i];
							}
							if(mgs)		fprintf(fp,"104 %d messages total\n",mgs);
							if(files)	fprintf(fp,"110 %d files recvd\n",files);
							fprintf(fp,"\n");
							fclose(fp);
						}
					}
				}
				else
				{	printf(printout(MSG_CANT_OPEN),filename);
					errorvalue=20;
				}
				FreeMem(msgs,MAXGROUPS*sizeof(int));
				if(strcmp(Activefile,"none"))
					update_active(Activefile);
			}
			else
			{	printf(printout(MSG_MEM_ALLOC_ERR_2));
				errorvalue=42;
			}
		}
		else
		{	printf(printout(MSG_NET_USAGE_2));
			errorvalue=5;
		}
	}
	else
	{	printf(printout(MSG_NET_USAGE_3));
		errorvalue=5;
	}

freememory:
	if(Groups)
	{	if(Groups[0])
			FreeMem(Groups[0],MAXGROUPS*NAMELEN);
		FreeMem(Groups,MAXGROUPS*sizeof(char *));
	}

	return errorvalue;
}

int getgrp(char *name)
{	int i=0;
	char temp[NAMELEN],apu[NAMELEN];

	lowercase(apu,name);
	while(strcmp(lowercase(temp,Groups[i]),apu) && i<Numgrp)	i++;
	if(i==Numgrp && Numgrp<MAXGROUPS)
		strcpy(Groups[Numgrp++],name);
	return i;
}


