/*****************************************************************************
 *
 * $Id$
 * Purpose ...............: Toss a single *.pkt file
 *
 *****************************************************************************
 * Copyright (C) 1997-2002
 *   
 * Michiel Broek		FIDO:		2:280/2802
 * Beekmansbos 10
 * 1971 BV IJmuiden
 * the Netherlands
 *
 * This file is part of MBSE BBS.
 *
 * This BBS is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * MBSE BBS is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with MBSE BBS; see the file COPYING.  If not, write to the Free
 * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *****************************************************************************/

#include "../config.h"
#include "../lib/libs.h"
#include "../lib/memwatch.h"
#include "../lib/structs.h"
#include "../lib/users.h"
#include "../lib/records.h"
#include "../lib/common.h"
#include "../lib/clcomm.h"
#include "../lib/msg.h"
#include "../lib/msgtext.h"
#include "../lib/dbcfg.h"
#include "../lib/dbnode.h"
#include "../lib/dbmsgs.h"
#include "../lib/dbdupe.h"
#include "../lib/dbuser.h"
#include "../lib/dbftn.h"
#include "tosspkt.h"
#include "postnetmail.h"
#include "postecho.h"
#include "rollover.h"
#include "createm.h"



/*
 * External declarations
 */
extern	int	do_quiet;
extern  int     do_unsec;
extern  int     check_dupe;
extern  time_t  t_start;



/*
 * Global variables
 */
int		net_in = 0;		/* Netmails received		    */
int		net_imp = 0;		/* Netmails imported                */
int		net_out = 0;		/* Netmails forwarded		    */
int		net_bad = 0;		/* Bad netmails (tracking errors    */
int		echo_in = 0;		/* Echomail received		    */
int		echo_imp = 0;		/* Echomail imported		    */
int		echo_out = 0;		/* Echomail forwarded		    */
int		echo_bad = 0;		/* Bad echomail			    */
int		echo_dupe = 0;		/* Dupe echomail		    */
int		news_in = 0;		/* News received		    */
int		news_imp = 0;		/* News imported		    */
int		news_out = 0;		/* News posted			    */
int		news_bad = 0;		/* Bad news			    */
int		news_dupe = 0;		/* Dupe articles		    */
int		email_in = 0;		/* Email received		    */
int		email_imp = 0;		/* Email imported		    */
int		email_out = 0;		/* Email forwarded		    */
int		email_bad = 0;		/* Bad email			    */


static int at_zero = 0;


/*
 *  Internal prototypes
 */
char	*aread(char *, int, FILE *);
int     importmsg(faddr *, faddr *, faddr *, char *, char *, time_t, int, int, FILE *);



char *aread(char *s, int count, FILE *fp)
{
	int i,c,next;

	if (feof(fp)) 
		return(NULL);
	if (s == NULL) 
		return NULL;
	if (at_zero)
	{
		at_zero=0;
		return NULL;
	}

	for (i = 0,next = 1; (i < count-1) && next;)
		switch (c=getc(fp)) {
		case '\n':	break;

		case '\r':	s[i]='\n';
				i++;
				next=0;
				break;

		case 0x8d:	s[i]=' ';
				i++;
				break;

		case '\0':	at_zero=1;
				next=0;
				break;

		default:	s[i]=c;
				i++;
				break;
		}
	s[i]='\0';
	return s;
}



/*
 * Import 1 message, forward if needed.
 * pkt_from, from, to, subj, orig, mdate, flags, cost, file
 *
 *  0 - All Seems Well.
 *  1 - Can't access messagebase.
 *  2 - Cannot open mareas.data
 *  3 - Echomail without Origin line.
 *  4 - Echomail from unknown node, disconnected node.
 *  5 - Locking error.
 *
 */
int importmsg(faddr *p_from, faddr *f, faddr *t, char *orig, char *subj, 
		time_t mdate, int flags, int cost, FILE *fp)
{
	char		*buf, *marea = NULL;
	int		echomail = FALSE, rc = 0, bad = FALSE, Known = FALSE, FirstLine;
	sysconnect	Link;

	if (CFG.slow_util && do_quiet)
		usleep(1);

	memset(&Link, 0, sizeof(Link));

	/*
	 * Increase uplink's statistic counter.
	 */
	Link.aka.zone  = p_from->zone;
	Link.aka.net   = p_from->net;
	Link.aka.node  = p_from->node;
	Link.aka.point = p_from->point;
	if (SearchNode(Link.aka)) {
		StatAdd(&nodes.MailRcvd, 1);
		UpdateNode();
		SearchNode(Link.aka);
		Known = TRUE;
	}

	buf = calloc(2048, sizeof(char));
	marea = NULL;

	/*
	 * First read the message for kludges we need.
	 */
	rewind(fp);

	FirstLine = TRUE;
	while ((fgets(buf, 2048, fp)) != NULL) {

		Striplf(buf);

		/*
		 * Check if message is echomail and if the areas exists.
		 */
		if (FirstLine && (!strncmp(buf, "AREA:", 5))) {

			marea = xstrcpy(tu(buf + 5));

			if (orig == NULL) {
				Syslog('!', "Echomail without Origin line");
				echo_bad++;
				echo_in++;
				bad = TRUE;
				free(buf);
				free(marea);
				return 3;
			}

			if (!SearchMsgs(marea)) {
				UpdateNode();
				Syslog('m', "Unknown echo area %s", marea);
				if (!create_msgarea(marea, p_from)) {
				    WriteError("Create echomail area %s failed", marea);
				    echo_bad++;
				    echo_in++;
				    bad = TRUE;
				    free(marea);
				    free(buf);
				    return 4;
				}
				SearchNode(Link.aka);
				if (!SearchMsgs(marea)) {
					WriteError("Unknown echo area %s", marea);
					echo_bad++;
					echo_in++;
					bad = TRUE;
					free(marea);
					free(buf);
					return 4;
				}       
			}
			echomail = TRUE;
			free(marea);
		}
		if (*buf != '\001')
			FirstLine = FALSE;
	} /* end of checking kludges */


	if (echomail)
		rc = postecho(p_from, f, t, orig, subj, mdate, flags, cost, fp, TRUE);
	else
		rc = postnetmail(fp, f, t, orig, subj, mdate, flags, TRUE);

	free(buf);
	return rc;
}



/*
 * Toss one packet.
 *
 *  0  - 
 *  1  - Cannot open packet
 *  2  - Bad packet header
 *  3  - Packet is not for us
 *  4  - Bad password
 */
int TossPkt(char *fn)
{
	int		rc, count = 0; 
	static int	maxrc = 0;
	static faddr	from, to;
	FILE		*pkt;

	if (!do_quiet) {
		colour(10, 0);
		printf("Tossing packet %s\n", fn);
	}

	if ((pkt = fopen(fn, "r")) == 0) {
		WriteError("$Cannot open %s", fn);
		return 1;
	}

	memset(&from, 0, sizeof(faddr));
	memset(&to,   0, sizeof(faddr));

	if (((rc = getheader(&from, &to, pkt, fn)) != 0)) {
		WriteError("%s, aborting",
				(rc == 1)?"wrong header type":
				(rc == 2)?"bad packet header":
				(rc == 3)?"packet is not for us":
				(rc == 4)?"bad password":
				"bad packet");
		return(rc);
	}

	while ((rc = getmessage(pkt, &from, &to)) == 1) {
		count++;
	}
	Syslog('+', "Messages : %d", count);

	maxrc = rc;
	if (!do_quiet)
		printf("\r                                                    \r");

	if (rc)
		Syslog('+', "End, rc=%d", maxrc);

	fclose(pkt);
	return maxrc;
}



/*
 * Process one message from message packet.
 *
 *  0   - no more messages
 *  1   - more messages
 *  2   - bad file
 *  3   - bad message header
 *  4   - unable to open temp file
 *  5   - unexpected end of packet
 *  >10 - import error
 */
int getmessage(FILE *pkt, faddr *p_from, faddr *p_to)
{
	char		buf[2048];
	char		*orig = NULL;
	char		*p, *l, *r;
	int		tmp, rc, maxrc = 0;
	static faddr	f, t;
	faddr		*o;
	int		result, flags, cost;
	time_t		mdate = 0L;
	FILE		*fp;
	unsigned char	buffer[0x0e];
	char		*subj = NULL;

	result = fread(&buffer, 1, sizeof(buffer), pkt);
	if (result == 0) {
		Syslog('m', "Zero bytes message, assume end of pkt");
		return 0;
	}

	switch(tmp = (buffer[0x01] << 8) + buffer[0x00]) {
	case 0:	
		if (result == 2)
			return 0;
		else {
			Syslog('!', "Junk after logical end of packet, skipped");
			return 5;

		}
	case 2:	
		break;

	default:
		Syslog('!', "bad message type: 0x%04x",tmp);
		return 2;
	}

	if (result != 14) {
		Syslog('!', "Unexpected end of packet");
		return 5;
	}

	memset(&f, 0, sizeof(f));
	memset(&t, 0, sizeof(t));
	f.node = (buffer[0x03] << 8) + buffer[0x02];
	t.node = (buffer[0x05] << 8) + buffer[0x04];
	f.net  = (buffer[0x07] << 8) + buffer[0x06];
	t.net  = (buffer[0x09] << 8) + buffer[0x08];
	flags  = (buffer[0x0b] << 8) + buffer[0x0a];
	cost   = (buffer[0x0d] << 8) + buffer[0x0c];

	/*
	 * Read the DateTime, toUserName, fromUserName and subject fields
	 * from the packed message. The stringlength is +1 for the right
	 * check. This is different then in ifmail's original code.
	 */
	if (aread(buf, sizeof(buf)-1, pkt)) {
		if (strlen(buf) > 20)
			Syslog('!', "date too long (%d) \"%s\"", strlen(buf), printable(buf, 0));
		mdate = parsefdate(buf, NULL);
		if (aread(buf, sizeof(buf)-1, pkt)) {
			Syslog('!', "date not null-terminated: \"%s\"",buf);
			return 3;
		}
	}

	if (aread(buf, sizeof(buf)-1, pkt)) {
		if (strlen(buf) > 36)
			Syslog('!', "to name too long (%d) \"%s\"", strlen(buf), printable(buf, 0));
		t.name = xstrcpy(buf);
		if (aread(buf, sizeof(buf)-1, pkt)) {
			if (*(p=t.name+strlen(t.name)-1) == '\n')
				 *p = '\0';
			Syslog('!', "to name not null-terminated: \"%s\"",buf);
			return 3;
		}
	}

	if (aread(buf, sizeof(buf)-1, pkt)) {
		if (strlen(buf) > 36)
			Syslog('!', "from name too long (%d) \"%s\"", strlen(buf), printable(buf, 0));
		f.name = xstrcpy(buf);
		if (aread(buf, sizeof(buf)-1, pkt)) {
			if (*(p=f.name+strlen(f.name)-1) == '\n') 
				*p = '\0';
			Syslog('!', "from name not null-terminated: \"%s\"",buf);
			return 3;
		}
	}
	
	if (aread(buf, sizeof(buf)-1, pkt)) {
		if (strlen(buf) > 72)
			Syslog('!', "subject too long (%d) \"%s\"", strlen(buf), printable(buf, 0));
		subj = xstrcpy(buf);
		if (aread(buf, sizeof(buf)-1, pkt)) {
			if (*(p=subj+strlen(subj)-1) == '\n') 
				*p = '\0';
			subj = xstrcat(subj,(char *)"\\n");
			subj = xstrcat(subj,buf);
			Syslog('!', "subj not null-terminated: \"%s\"",buf);
			return 3;
		}
	}

	if (feof(pkt) || ferror(pkt)) {
		Syslog('!', "Could not read message header, aborting");
		return 3;
	}

	f.zone = p_from->zone;
	t.zone = p_to->zone;
	
	if ((fp = tmpfile()) == NULL) {
		WriteError("$unable to open temporary file");
		return 4;
	}

	/*
	 * Read the text from the .pkt file
	 */
	while (aread(buf,sizeof(buf)-1,pkt)) {

		fputs(buf, fp);

		/*
		 * Extract info from Origin line if found.
		 */
		if (!strncmp(buf," * Origin:",10)) {
			p=buf+10;
			while (*p == ' ') p++;
			if ((l=strrchr(p,'(')) && (r=strrchr(p,')')) && (l < r)) {
				*l = '\0';
				*r = '\0';
				l++;
				if ((o = parsefnode(l))) {
					f.point = o->point;
					f.node = o->node;
					f.net = o->net;
					f.zone = o->zone;
					if (o->domain) 
						f.domain=o->domain;
					o->domain=NULL;
					tidy_faddr(o);
				}
			} else
				if (*(l=p+strlen(p)-1) == '\n')
					 *l='\0';
			for (l=p+strlen(p)-1;*l == ' ';l--) 
				*l='\0'; 
			orig = xstrcpy(p);
		}
	}

	rc = importmsg(p_from, &f,&t,orig,subj,mdate,flags,cost,fp);
	if (rc)
		rc+=10;
	if (rc > maxrc) 
		maxrc = rc;

	fclose(fp);

	if(f.name) 
		free(f.name); 
	f.name=NULL;

	if(t.name) 
		free(t.name); 
	t.name=NULL;

	if(f.domain) 
		free(f.domain); 
	f.domain=NULL;

	if(t.domain) 
		free(t.domain); 
	t.domain=NULL;

	if (subj)
		free(subj);
	subj = NULL;

	if (orig)
		free(orig);
	orig = NULL;

	if (feof(pkt) || ferror(pkt)) {
		WriteError("Unexpected end of packet");
		return 5;
	}
	return 1;
}