/* EMACS_MODES: !lnumb !fill */
#define NAME "extract"
#define VERSION "2.1"


#include <stdio.h>
#include <string.h>
#include <io.h>
#include <fcntl.h>
#include <dos.h>
#include <stdlib.h>
#include <time.h>


#define nl() printf("\n");

#define OK 0
#define NOT_OK 1
#define ERROR 1
#define FATAL 2

#define NET           0x0001      /* Main Types */
#define EMAIL         0x0002
#define POST          0x0003
#define PREPOST       0x0005
#define NOTUSED_04    0x0004
#define EXTERNAL      0x0006
#define EMAIL_VERBOSE 0x0007
#define NETEDIT       0x0008
#define SUBSLIST      0x0009
#define NOTUSED_10    0x000A
#define BBSLIST       0x000B
#define CONNECT       0x000C
#define NOTUSED_13    0x000D
#define GRP_INFO      0x000E
#define MAIL_CONF     0x000F

#define TO            1   /* +to extract messages to a user@system */
#define TYPE          2   /* +type extract certain types of messages */
#define DEL_TO        3   /* -to Delete certain types of messages */
#define DEL_TYPE      4   /* -type Delete certain types of messages */

#define ERRLOG  "extract.err"  /* File to log errors to */

#define MAXSYS  (unsigned short)65535  /* highest node number for WWIVnet */
#define LF	'\012'        /* Line Feed */

#define MAXLINE 128         /* Maximum length of a line in a message */
#define MAXPATH 128         /* Maximum length of a DOS filesytem pathname */
#define MSGLEN  33000       /* Max number of bytes for a single message */

/* For Pattern Matching Routines */
#define TRUE		1
#define FALSE		0
#define ABORT		-1
#define NEGATE_CLASS	'^'

int error; /* error flag/counter */
short faddr; /* Set to true if UUCP address is set on command line */
unsigned short to_sys;
unsigned short to_user;
unsigned short main_type;
unsigned short minor_type;
unsigned short mode;
char message[MSGLEN];
char address[MAXLINE];

FILE *ferr;

/* From WWIVnet Doc */
typedef struct {
        unsigned short  tosys,         /* destination system */
                        touser,        /* destination user */
                        fromsys,       /* originating system */
                        fromuser;      /* originating user */
        unsigned short  main_type,     /* main message type */
                        minor_type;    /* minor message type */
        unsigned short  list_len;      /* # of entries in system list */
        unsigned long   daten;         /* date/time sent */
        unsigned long   length;        /* # of bytes of msg after header */
        unsigned short  method;        /* method of compression */
} net_header_rec;

typedef struct {
	char file[MAXPATH];        /* path for files directory */
	char external[MAXPATH];    /* path for external.net file */
	char temp[MAXPATH];         /* path for temp files */
	char minor[MAXPATH];       /* minor type */
} config;

net_header_rec nh;
config cf;

FILE *fi; /* Input file */
FILE *fo; /* Output file */
FILE *fe; /* Error file */
FILE *ft; /* Temp file */

void main(int argc, char *argv[])
{

	int i,j;
	unsigned long length;
	char s[MAXLINE];


	error=0;

	colour(4);
	nl();
	printf("[%s:%s] Copyright (c) 1991 Andrew Gaunt. ",NAME,VERSION);
	colour(0);
	nl();
	colour(3);
	printf("Compiled %s %s",__DATE__,__TIME__);
	colour(0);
	nl();

	if (argc<7){
		printf("usage: %s -to|-type|-del to_user|main_type to_system|sub_type infile outfile work_dir [address]\n",argv[0]);
		exit(0);
	}

	faddr=FALSE;
	if(argc==8){
		strcpy(address,argv[7]);
		faddr=1;
	}
	/* Open the error log file */
	if ( (ferr=fopen(ERRLOG,"w")) == NULL ){
		colour(6);
		printf("FATAL: can't open error log %s for writing.",ERRLOG);
		colour(0);
		nl();
		myexit(FATAL);
	}
	mode=0;
	if (strcmp(argv[1],"+to")==0){
		mode=TO;
	}
	if (strcmp(argv[1],"+type")==0){
		mode=TYPE;
	}
	if (strcmp(argv[1],"-to")==0){
		mode=DEL_TO;
	}
	if (strcmp(argv[1],"-type")==0){
		mode=DEL_TYPE;
	}
/* 	printf("argv[1] %s, nh.main_type %d, mode %d\n",argv[1],nh.main_type,mode); /* DEBUG */

	to_user=(unsigned short)atoi(argv[2]);
	to_sys=(unsigned short)atoi(argv[3]);
	main_type=(unsigned short)atoi(argv[2]);
	minor_type=(unsigned short)atoi(argv[3]);
	if(extract(argv[4],argv[5],argv[6]) != NULL){
		myexit(FATAL);
	}
	colour(4);
	printf("[%s:%s] Complete ",NAME,VERSION);
	colour(0);
	nl();
        exit(0);
}

extract(infile,outfile,extdir)
char infile[];
char outfile[];
char extdir[];
{
	char s[512];
	char extfile[MAXPATH];
	unsigned long count;
	unsigned long msgnum;
	unsigned num_read;
	unsigned short ok;
	unsigned long i;
	unsigned short n;
	short found_addr; /* Found address status */
	short last_nl; /* Last char was a newline flag */
	int c;


	if( (fi=fopen(infile,"r+b")) == NULL){
		sprintf(s,"Can't read %s file.\n",infile);
		errlog(s);
		return(ERROR);
	}
	colour(3);
	printf("WWIVnet input %s.",infile);
	colour(0);
	nl();

	if( (fo=fopen(outfile,"w+b")) == NULL){
		sprintf(s,"Can't write %s file.\n",outfile);
		errlog(s);
		return(ERROR);
	}
	colour(3);
	printf("WWIVnet output %s.",outfile);
	colour(0);
	nl();
	nl();

	count=0;
	msgnum=0;

	while(read_header(fi) == NULL){
		colour(1);
		nl();
		print_header();
		colour(0);

/*	printf("nh.main_type %d, mode %d\n",nh.main_type,mode); /* DEBUG */
/*  If to_user, to_sys, main_type, or minor_type are set to zero
 *  Then any nh.to_user, nh.to_sys, nh.main_type, or nh.minor_type is accepted,
 *  respectively.
 */
		ok=NOT_OK;
		switch(mode){
			case TO:
			case DEL_TO:
				if((\
				(nh.touser==to_user)||(to_user==0)\
				)&&(\
				(nh.tosys==to_sys)||(to_sys==0)\
				)){
					ok=OK;
				}
				break;

			case TYPE:
			case DEL_TYPE:
				if((\
				(nh.main_type==main_type)||(nh.main_type==0)\
				)&&(\
				(nh.minor_type==minor_type)||(nh.main_type==0)\
				)){
					ok=OK;
				}
				break;

			default:
				sprintf(s,"Mode invalid: %d\n",mode);
				errlog(s);
				myexit(FATAL);				
				ok=NOT_OK;
				break;
		}

		if(ok==OK){

			num_read=read(fileno(fi),(char *)message,(unsigned)nh.length+(nh.list_len*sizeof(unsigned short)));

/* 			printf("Read returns %u.",num_read); /* DEBUG */
/* 			nl(); */

			if( (mode!=DEL_TO)&&(mode!=DEL_TYPE) ){
 				sprintf(extfile,"%s/%08d.msg",extdir,msgnum);
				printf("\tUUCP message file -> %s\n",extfile);
				if( (fe=fopen(extfile,"wb")) == NULL){
					sprintf(s,"Can't write to msg file %s.\n",extfile);
					errlog(s);
					return(ERROR);
				}
 				sprintf(extfile,"%s/%08d.add",extdir,msgnum);
				printf("\tUUCP Address file -> %s\n",extfile);
				if( (ft=fopen(extfile,"wb")) == NULL){
					sprintf(s,"Can't write to address file %s.\n",extfile);
					errlog(s);
					return(ERROR);
				}
			}else{
				printf("Deleting %d bytes.\n",num_read);
			}
			count=0;
			found_addr=0;
			last_nl=0;
			for(i=0;i<num_read;i++){

				/* Don't look for UUCP addr when deleting */
				if(mode==DEL_TO || mode==DEL_TYPE){
					found_addr=3;
				}

				/* address specified on command line */
				/* force it in here one time */
				if ( faddr==1 && found_addr==0){
					fprintf(ft,"%s\r\n",address);
					fflush(ft);
					printf("\tUUCP Address: %s\n",address);
					found_addr=2;
				}

				/* The rest of these are for non-specifed or */
				/* "forced" addresses */
				/* Be sure ~ is at start of line (last_nl) */
/* 				printf("%d",last_nl); /* DEBUG */
				if(message[i]=='~' && found_addr==0\
					&& last_nl==1 && faddr==0){
					found_addr=1;
					fputc('~',fe);
					printf("\tUUCP Address: ");
					continue;
				}

				if ( found_addr==1 && faddr==0 ){
					if(message[i]=='\n'){
						found_addr=2;
						fputc('\n',ft);	
						printf("\n");
						continue;
					}
					fputc(message[i],ft);
 					printf("%c",message[i]);
				}

				if (isprint(message[i])){
					last_nl=0;
					fputc(message[i],fe);
				}
				else{
					if (message[i]!='\n'){
						fputc('\r',fe);
						fputc('\n',fe);
					}
					else{
						last_nl=1; 
					}
				}
				count++;
			}

			if ( found_addr==2  && faddr==0){
				printf("\tConfirmation; ");
				colour(1);
				sprintf(s,"SUCCESS:\r\n\
Your message has been received by a UUCP gateway and forwarded.\r\n\r\n");

				sendmail("Confirmation",s,\
					nh.fromuser,nh.fromsys,0,"UUCP",\
					nh.tosys,2,0);

/*
				sprintf(s,"confmail %d %d",nh.fromuser,nh.fromsys);
				printf("Executing %s\n",s);
				colour(0);
				system(s);
*/
				printf("%d bytes in message, %d bytes extracted.",i,count);
			}

			if (found_addr<2 && faddr==0){
				colour(6);
				printf("\tNo UUCP address; ");
				colour(1);
				sprintf(s,"FAILURE:\r\n\
Your message has been received by a UUCP gateway.\r\n\
No secondary address was found; it has not been forwarded.\r\n\r\n\
Be sure to put a \"~\" in the message as the first character on a line,\r\n\
followed by the secondary address.\r\n\r\n");

/*				printf("\"%s\"",s); /* DEBUG */
				sendmail("Failure notification",s,\
					nh.fromuser,nh.fromsys,0,"UUCP",\
					nh.tosys,2,0);

/*  
				sprintf(s,"rtrnmail %d %d",nh.fromuser,nh.fromsys);
				printf("Executing %s\n",s);
				colour(0);
				system(s);
*/
				/* Return message to sender */
				n=nh.touser;
				nh.touser=nh.fromuser;
				nh.fromuser=n;
				n=nh.fromsys;
				nh.tosys=nh.fromsys;
				nh.fromsys=n;

				printf("\tUnlinking message and address files\n");
	 			sprintf(extfile,"%s/%08d.add",extdir,msgnum);
				unlink(extfile);
	 			sprintf(extfile,"%s/%08d.msg",extdir,msgnum);
				unlink(extfile);
				msgnum--;

				write(fileno(fo),(void *)&nh,sizeof(net_header_rec));
 				fflush(fo);
				for(i=0;i<num_read;i++){
					fputc(message[i],fo);
/*					printf("%c",message[i]); /* DEBUG */
				}
				colour(3);
				printf("%d bytes in message, %d bytes to return.",i,count);
				colour(0);

			}
			nl();
			if( mode!=DEL_TO && mode!=DEL_TYPE){
				msgnum++;
				fclose(fe);
				fclose(ft);
			}
		}
		else{
			num_read=read(fileno(fi),(char *)message,(unsigned)nh.length+(nh.list_len*sizeof(unsigned short)));
/*   			printf("Read returns %u.\n",num_read); /* DEBUG */
			fflush(fo);
			write(fileno(fo),(void *)&nh,sizeof(net_header_rec));
 			fflush(fo);
			for(i=0;i<num_read;i++){
				fputc(message[i],fo);
/*				printf("%c",message[i]); /* DEBUG */
			}
			colour(1);
			printf("%d bytes in message, nothing extracted.",i);
			colour(0);
			nl();
			fclose(fe);
		}
	}
		
	fclose(fi);
	fclose(fo);
	fclose(fe);
	fclose(ft);
	return(OK);	
}


/* Read a WWIVnet header, the system, major/minor types, and stuff */
read_header(fi)
FILE *fi;
{
	char s[MAXLINE];
	unsigned i,l,num_read;

/*  	printf("\nReading WWIVnet header.\n"); /* DEBUG */
	fflush(fi);
	if(read(fileno(fi),(void *)&nh,sizeof(net_header_rec))==NULL){
		return(ERROR);
	}

	fflush(fi);
	return(OK);
}

 
print_header()
{
/* 	printf("nh.main_type %d, mode %d\n",nh.main_type,mode); /* DEBUG */

	switch(nh.main_type){
		case EMAIL:
			if(mode==TO){
				printf("+");
			}
			if(mode==DEL_TO){
				printf("-");
			}
			printf("Email, ");
			break;

		case PREPOST:
			if(mode==TYPE){
				printf("+");
			}
			if(mode==DEL_TYPE){
				printf("-");
			}
			printf("Prepost, ");
			break;

		case POST:
			if(mode==TYPE){
				printf("+");
			}
			if(mode==DEL_TYPE){
				printf("-");
			}
			printf("Post, ");
			break;

		case NET: printf("Net info, ");break;
		case NOTUSED_04: printf("N/A (0x04), ");break;
		case EXTERNAL: printf("External, ");break;
		case EMAIL_VERBOSE: printf("Email verbose, ");break;
		case NETEDIT: printf("Net edit, ");break;
		case SUBSLIST: printf("Subs list, ");break;
		case NOTUSED_10: printf("N/A (0x10), ");break;
		case BBSLIST: printf("BBSlist, ");break;
		case CONNECT: printf("Connect, ");break;
		case NOTUSED_13: printf("N/A (0x13), ");break;
		case GRP_INFO: printf("Group info, ");break;
		case MAIL_CONF: printf("Mail conf., ");break;

		default:
			printf("???? %x, ",nh.main_type);
			break;
	}

	printf("from %u@%u, ",nh.fromuser,nh.fromsys);
	printf("to %u@%u, ",nh.touser,nh.tosys);
	printf("type %u-%u, ",nh.main_type,nh.minor_type);
	printf("total-list %u-%u\n",nh.length,nh.list_len);
/* 	printf("time=%u, msglen=%u",nh.daten,nh.length); */
	return(OK);
}


/*
print_header()
{
printf("WWIVnet Header Data:\n");
printf("\tTo system   : %u\n",nh.tosys);
printf("\tFrom system : %u\n",nh.fromsys);
printf("\tTo user     : %u\n",nh.touser);
printf("\tFrom user   : %u\n",nh.fromuser);
printf("\tMain type   : %u\n",nh.main_type);
printf("\tMinor type  : %u\n",nh.minor_type);
printf("\tList length : %u\n",nh.list_len);
printf("\tTime stamp  : %u\n",nh.daten);
printf("\tTotal len.  : %u",nh.length);
colour(0);
nl();
return(OK);
}
*/

errlog(s)
char *s[];
{
	fprintf(ferr,"ERROR: %s",s);
	error++;
	return(OK);
}

myexit(r)
int r;
{
	char s[MAXLINE];

	/* close the error log */
	fclose(ferr);
	if ( (ferr=fopen(ERRLOG,"r")) == NULL ){
		printf("FATAL: can't open error log %s for reading.\n",ERRLOG);
		exit(FATAL);
	}
	printf("%d ERROR(S) have occuured:\n",error);
	while ( fgets(s,MAXLINE-1,ferr)  ){
		printf("\t%s",s);
	}			
	fclose(ferr);
	exit(r);
	return(OK);
}

int readable(f)
char f[];
{
  FILE *fp;
  if ( (fp=fopen(f,"r")) != NULL){
    fclose(fp);
    return(0);
  }
  fclose(fp);
  return(1);
}


sendmail(title,text,touser,tosys,fromuser,fromuname,fromsys,major,minor)
char title[];
char text[];
unsigned short touser;
unsigned short tosys;
unsigned short fromuser;
char fromuname[];
unsigned short fromsys;
unsigned short major;
unsigned short minor;
{

	struct date datep;
	struct time timep;
	char s[MAXLINE];
	char post_date[30];
	long T;
	int i;
	net_header_rec old_nh;

	old_nh = nh; /* Save the old stuff */

	time(&T);
	strcpy(s,ctime(&T));
	/* Don't let post_date contain a newline */
	for(i=0;i<strlen(s);i++){
		if (s[i]==LF){
			post_date[i]='\0';
		}
		else{
			post_date[i]=s[i];
		}
	}	

	gettime(&timep);
	getdate(&datep);

	nh.tosys=tosys;
	nh.touser=touser;
	nh.fromsys=fromsys;
	nh.fromuser=fromuser;
	nh.main_type=major;
	nh.minor_type=minor;
	nh.list_len=0;

	nh.daten=dostounix(&datep, &timep);
	nh.length=strlen(text)+strlen(title)+1+strlen(fromuname)+1+strlen(post_date)+2;
	nh.method=0;
	colour(3);
 	printf("Sending mail\n");
  	print_header(); /* DEBUG */
	printf("\tTitle: %s\n",title);        /* DEBUG */
/*	printf("\t Name: %s\n",fromuname);    /* DEBUG */
	printf("\t Date: %s\n",post_date);    /* DEBUG */
	colour(0);
	fflush(fo);
 	write(fileno(fo),(void *)&nh,sizeof(net_header_rec));
	write(fileno(fo),(void *)title,strlen(title));
	write(fileno(fo),'\0',sizeof(char));
	write(fileno(fo),(void *)fromuname,strlen(fromuname));
	fflush(fo);
	fprintf(fo,"\r");
	fflush(fo);
 	write(fileno(fo),(void *)post_date,strlen(post_date));
	fflush(fo);
	fprintf(fo,"\r\n");
	fflush(fo);
	colour(2);
	fputs(text,fo);
	fflush(fo);
 	printf("\t%d bytes of mail data.",strlen(text)); /* DEBUG */
	nl();
	nh = old_nh; /* Restore the old stuff */

	return(OK);
}

colour(code)
short code;
{
  return(OK);
/* NOT REACHED */
  if (code<=7 && code>=0 ){
    printf("%c%d",'\003',code);

  }
  return(OK);
}
