/*****************************************************************************
 *
 * File ..................: tosser/importmsg.c
 * Purpose ...............: Import a message
 * Last modification date : 11-Nov-1999
 *
 *****************************************************************************
 * Copyright (C) 1997-1999
 *   
 * Michiel Broek		FIDO:		2:2801/16
 * Beekmansbos 10		Internet:	mbroek@ux123.pttnwb.nl
 * 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 "../include/libs.h"
#include "../include/structs.h"
#include "../include/records.h"
#include "../common/common.h"
#include "../msgbase/msg.h"
#include "../msgbase/msgtext.h"
#include "../dbase/dbcfg.h"
#include "../dbase/dbnode.h"
#include "../dbase/dbmsgs.h"
#include "../dbase/dbdupe.h"
#include "../dbase/dbuser.h"
#include "../dbase/dbftn.h"
#include "tracker.h"
#include "echoout.h"
#include "addpkt.h"
#include "putil.h"
#include "importnet.h"
#include "importmsg.h"
#include "areamgr.h"
#include "filemgr.h"
#include "rollover.h"



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


/*
 * Global variables
 */
extern	int	net_in;			/* Netmails received		    */
extern	int	net_out;		/* Netmails forwarded		    */
extern	int	net_bad;		/* Bad netmails (tracking errors    */
extern	int	echo_in;		/* Echomail received		    */
extern	int	echo_imp;		/* Echomail imported		    */
extern	int	echo_out;		/* Echomail forwarded		    */
extern	int	echo_bad;		/* Bad echomail			    */
extern	int	echo_dupe;		/* Dupe echomail		    */
extern	char	*subj;			/* Message subject		    */
char		*msgid = NULL;		/* Message id string		    */

#define	MAXPATH	73
#define	MAXSEEN	70


void tidy_qualify(qualify **);
void fill_qualify(qualify **, fidoaddr, int, int);
void dlog_qualify(qualify **, char *);


void tidy_qualify(qualify **qal)
{
	qualify	*tmp, *old;

	for (tmp = *qal; tmp; tmp = old) {
		old = tmp->next;
		free(tmp);
	}
	*qal = NULL;
}



void fill_qualify(qualify **qal, fidoaddr aka, int orig, int insb)
{
	qualify		*tmp;

	tmp = (qualify *)xmalloc(sizeof(qualify));
	tmp->next     = *qal;
	tmp->aka      = aka;
	tmp->inseenby = insb;
	tmp->send     = ((!insb) && (!orig));
	tmp->orig     = orig;
	*qal = tmp;
}



void dlog_qualify(qualify **qal, char *msg)
{
	qualify	*tmpl;

//	Syslog('m', "Qualify list at: %s", msg);

	for (tmpl = *qal; tmpl; tmpl = tmpl->next) {
		Syslog('m', "%s InSB=%s Snd=%s Org=%s", 
			aka2str(tmpl->aka), tmpl->inseenby ? "True":"False",
			tmpl->send ? "True":"False",
			tmpl->orig ? "True":"False");
	}
}



/*
 * Import 1 message, forward if needed.
 * pkt_from, from, to, subj, orig, mdate, flags, cost, file
 *
 *  1 - Cannot open message base.
 *  2 - Cannot open mareas.data
 *  3 - Echomail without Origin line.
 *  4 - Echomail from unknown node, disconnected node.
 *
 * For echomail, the crc32 is calculated over the ^AREA kludge, subject, 
 * message date, origin line, message id.
 */
int importmsg(faddr *p_from, faddr *f, faddr *t, char *orig, time_t mdate, int flags, int cost, FILE *fp)
{
	char		*buf, *area = NULL, *reply = NULL;
	char		*p, *q, *l, *r;
	int		echomail = FALSE, First = FALSE;
	int		rc = 0, i, topt = 0, fmpt = 0;
	faddr		*ta;
	fidoaddr	na, route, Orig;
	int		result, dupe = FALSE, bad = FALSE;
	unsigned long	crc, crc2;
	char		name[36], sbe[16];
	char		System[36], ext[4];
	sysconnect	Link;
	fa_list		*sbl = NULL, *ptl = NULL, *tmpl;
	qualify		*qal = NULL, *tmpq;
	FILE		*net, *nfp;
	int		Known = FALSE, seenlen, oldnet;
	struct tm	*tm;
	time_t		now;

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

	memset(&Link, 0, sizeof(Link));
	msgid = NULL;

	/*
	 * 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, TRUE)) {
		StatAdd(&nodes.MailRcvd, 1);
		UpdateNode();
		SearchNode(Link.aka, Link.aka.point);
		Known = TRUE;
	}

	crc = 0xffffffff;
	buf = calloc(2048, sizeof(char));
	area = NULL;

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

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

		Striplf(buf);

		/*
		 * Check all sort of relevant kludges.
		 */
		if (!strncmp(buf, "AREA:", 5)) {

			echo_in++;
			area = xstrcpy(tu(buf + 5));

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

			if (!SearchMsgs(area)) {
				WriteError("Unknown echo area %s", area);
				echo_bad++;
				bad = TRUE;
				free(buf);
				free(area);
				return 4;
			}
			crc = upd_crc32(buf, crc, strlen(buf));
			echomail = TRUE;

			/*
			 * Check if node is allowed to enter echomail in this area.
			 */
			bad = TRUE;
			First = TRUE;
			while (GetMsgSystem(&Link, First)) {
				First = FALSE;
				if ((p_from->zone == Link.aka.zone) &&
				    (p_from->net  == Link.aka.net) &&
				    (p_from->node == Link.aka.node)) {
					bad = FALSE;
					break;
				}
			}
			if (bad && msgs.UnSecure) {
				bad = FALSE;
				memset(&Link, 0, sizeof(Link));
			}
			if (bad) {
				Syslog('+', "Node %s not connected to area %s", 
					ascfnode(p_from, 0x1f), area);
				free(buf);
				free(area);
				echo_bad++;
				return 4;
			} 

			if (Link.cutoff && !bad) {
				Syslog('+', "Echomail from %s in %s refused, cutoff",
						ascfnode(p_from, 0x1f), area);
				free(buf);
				free(area);
				bad = TRUE;
				echo_bad++;
				return 4;
			}
			if (!Link.receivefrom && !bad) {
				Syslog('+', "Echomail from %s in %s refused, read only",
						ascfnode(p_from, 0x1f), area);
				bad = TRUE;
				free(buf);
				free(area);
				echo_bad++;
				return 4;
			}

			if (CFG.toss_old) {
				if (((t_start - mdate) / 86400) > CFG.toss_old) {
					Syslog('+', "Rejecting msg: too old, %s", rfcdate(mdate));
					bad = TRUE;
					free(buf);
					free(area);
					echo_bad++;
					return 4;
				}
			}

                        StatAdd(&msgs.Received, 1);
                        time(&msgs.LastRcvd);
                        StatAdd(&mgroup.MsgsRcvd, 1);
                        time(&mgroup.LastDate);
                        UpdateMsgs();
		}

		if (!echomail) {
			/*
			 * Check DOMAIN and INTL kludges
			 */
			if (!strncmp(buf, "\001DOMAIN", 7)) {
				l = strtok(buf," \n");
				l = strtok(NULL," \n");
				p = strtok(NULL," \n");
				r = strtok(NULL," \n");
				q = strtok(NULL," \n");
				if ((ta = parsefnode(p))) {
					t->point = ta->point;
					t->node = ta->node;
					t->net = ta->net;
					t->zone = ta->zone;
					tidy_faddr(ta);
				}
				t->domain = xstrcpy(l);
				if ((ta = parsefnode(q))) {
					f->point = ta->point;
					f->node = ta->node;
					f->net = ta->net;
					f->zone = ta->zone;
					tidy_faddr(ta);
				}
				f->domain = xstrcpy(r);
			} else {
				if (!strncmp(buf, "\001INTL", 5)) {
					l = strtok(buf," \n");
					l = strtok(NULL," \n");
					r = strtok(NULL," \n");
					if ((ta = parsefnode(l))) {
						t->point = ta->point;
						t->node = ta->node;
						t->net = ta->net;
						t->zone = ta->zone;
						if (ta->domain) {
							if (t->domain) 
								free(t->domain);
							t->domain = ta->domain;
							ta->domain = NULL;
						}
						tidy_faddr(ta);
					}
					if ((ta = parsefnode(r))) {
						f->point = ta->point;
						f->node = ta->node;
						f->net = ta->net;
						f->zone = ta->zone;
						if (ta->domain) {
							if (f->domain) 
								free(f->domain);
							f->domain = ta->domain;
							ta->domain = NULL;
						}
						tidy_faddr(ta);
					}
				}
			}
			/*
			 * Now check FMPT and TOPT kludges
			 */
			if (!strncmp(buf, "\001FMPT", 5)) {
				p = strtok(buf, " \n");
				p = strtok(NULL, " \n");
				fmpt = atoi(p);
			}
			if (!strncmp(buf, "\001TOPT", 5)) {
				p = strtok(buf, " \n");
				p = strtok(NULL, " \n");
				topt = atoi(p);
			}
		} /* if netmail */

		if (!strncmp(buf, "\001MSGID", 6))
			msgid = strdup(buf + 8);
		if (!strncmp(buf, "\001REPLY", 6))
			reply = strdup(buf + 8);
		if (!strncmp(buf, "SEEN-BY:", 8)) {
			if (Link.aka.zone == msgs.Aka.zone)
				fill_list(&sbl, strdup(buf + 9), NULL);
			else
				Syslog('m', "Strip zone SB lines");
		}
		if (!strncmp(buf, "\001PATH:", 6))
			fill_path(&ptl, strdup(buf + 7));

	} /* end of checking kludges */

	/*
	 * Handle netmail
	 */
	if (!echomail) {
		f->point = fmpt;
		t->point = topt;
		Syslog('m', "Final from: %s", ascfnode(f, 0xff));
		Syslog('+', "Netmail to: %s", ascfnode(t, 0x7f));
		net_in++;
		memset(&na, 0, sizeof(na));
		na.zone  = t->zone;
		na.net   = t->net;
		na.node  = t->node;
		na.point = t->point;
		if (SearchFidonet(na.zone))
			sprintf(na.domain, "%s", fidonet.domain);

		switch(TrackMail(na, &route)) {
		case R_LOCAL:
			if (strchr(t->name, '@') != NULL) {
				sprintf(name, "%s", strtok(t->name, "@"));
				sprintf(System, "%s", strtok(NULL, "\000"));
			} else {
				sprintf(name, "%s", t->name);
				sprintf(System, "%s", CFG.sysdomain);
			}

			/*
			 * If the system domainname is not the name in our setup
			 * we are probably acting as a gateway, the message should
			 * now be converted to a RFC... and then feed it to sendmail
			 */
			if (strcmp(CFG.sysdomain, System) != 0) {
				Syslog('+', "  Forward e-mail to %s@%s via sendmail", name, system);
				Syslog('+', "  Well... not implemented");
				/* sendmail interface */
				net_out++;
				free(buf);
				return 0;
			}

			/*
			 * If message to "sysop" or "postmaster" replace it
			 * with the sysops real name.
			 */
			if ((strcasecmp(name, "sysop") == 0) ||
			    (strcasecmp(name, "postmaster") == 0)) {
				Syslog('+', "  Readdress from %s to %s", name, CFG.sysop_name);
				sprintf(name, "%s", CFG.sysop_name);
			}

			/*
			 * If message is to one of our areamgr/filemgr names
			 * hand it over to that mgr function. First make sure
			 * that the right noderecord is loaded.
			 */
			(void)noderecord(f);
			for (i = 0; i < 5; i++) {
				if ((strcasecmp(CFG.mgrname[i], name) == 0) &&
				    (strlen(CFG.mgrname[i]) > 0)) {
					FileMgr(f, t, mdate, flags, fp);
					free(buf);
					return 0;
				}
				if ((strcasecmp(name, CFG.areamgr[i]) == 0) &&
				    (strlen(CFG.areamgr[i]) > 0)) {
					AreaMgr(f, t, mdate, flags, fp);
					free(buf);
					return 0;
				}
			}

			/*
			 * Check userlist real names, handles, unix names.
			 * Import if one fits.
			 */
			if (SearchUser(name)) {
				free(buf);
				return importnet(f, t, mdate, flags, fp);
			}

			Syslog('+', "  \"%s\" is not a known BBS user", name);
			/*
			 * If it is a Unix name, it could be a shell
			 * user, we check the passwd file and if there
			 * is a user with that name we mail the message
			 *
			 * If it's not a Unix name, we bounce this message.
			 * Or, maybe better, put it in the netmail directory.
			 */

			net_bad++;
			free(buf);
			return importnet(f, t, mdate, flags, fp);
			break;

		case R_DIRECT:
		case R_ROUTE:
			Syslog('+', "  Route netmail via %s", aka2str(route));
			/*
			 * Forward this message. Will not work for unknown
			 * direct links.
			 */
			if (SearchNode(route, route.point)) {
				memset(&Orig, 0, sizeof(Orig));
				Orig.zone  = f->zone;
				Orig.net   = f->net;
				Orig.node  = f->node;
				Orig.point = f->point;

				memset(&ext, 0, sizeof(ext));
				if (nodes.PackNetmail)
					sprintf(ext, (char *)"qqq");
				else if (nodes.Crash)
					sprintf(ext, (char *)"ccc");
				else if (nodes.Hold)
					sprintf(ext, (char *)"hhh");
				else 
					sprintf(ext, (char *)"nnn");

				if ((net = OpenPkt(Orig , route, (char *)ext)) == NULL) {
					WriteError("Can't create netmail");
					return 0;
				}
			} else {
				/*
				 * If it's not a direct link, create a outbound
				 * .pkt anyway, better then that this mail is 
				 * lost. It gets the normal status, it might
				 * get delivered during ZMH this way.
				 */
				Syslog('!', "Warning: not a direct link, check setup");
				memset(&Orig, 0, sizeof(Orig));
				Orig.zone  = f->zone;
				Orig.net   = f->net;
				Orig.node  = f->node;
				Orig.point = f->point;

				if ((net = OpenPkt(Orig , route, (char *)"nnn")) == NULL) {
					WriteError("Can't create netmail");
					return 0;
				}
			}

			/*
			 * Now start forward.
			 */
			Syslog('m', "Net from  %s", ascfnode(f, 0xff));
			Syslog('m', "Net to    %s", ascfnode(t, 0xff));
			Syslog('m', "Net flags %08x", flags);
			Syslog('m', "Net cost  %d", cost);
			Syslog('m', "Net subj  %s", subj);

			if (AddMsgHdr(net, f, t, flags, cost, mdate, t->name, f->name, subj)) {
				WriteError("Can't write message header");
				return 0;
			}
			rewind(fp);

			/*
			 * Copy all text including kludges, when
			 * finished, insert our ^aVia line.
			 */
			while ((fgets(buf, 2048, fp)) != NULL)
				fprintf(net, "%s\r", buf);

			now = time(NULL);
			tm = gmtime(&now);
			fprintf(net, "\001Via %s @%d%02d%02d.%02d%02d%02d.00.UTC mbfido %s\r", 
				ascfnode(bestaka_s(t), 0x1f), tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
				tm->tm_hour, tm->tm_min, tm->tm_sec, MBSEVersion);
			fprintf(net, "%s\r", buf);

			putc(0, net);
			fclose(net);
			fclose(fp);
			free(buf);
			net_out++;
			Syslog('m', "Forward done.");
			return 0;

		default:
			/*
			 * If we came this far, there's definitly something wrong
			 * with this netmail.
			 */
			WriteError("No ROUTE for this netmail");
			net_bad++;
			free(buf);
			return importnet(f, t, mdate, flags, fp);
			break;
		}
	} /* if !echomail */


	/*
	 * Handle echomail
	 */
	if (echomail && (!bad)) {
		/*
		 * First, further dupe checking.
		 */
		crc = upd_crc32(subj, crc, strlen(subj));

		if (orig == NULL)
			Syslog('!', "No origin line found");
		else
			crc = upd_crc32(orig, crc, strlen(orig));

		crc = upd_crc32((char *)&mdate, crc, sizeof(mdate));

		if (msgid != NULL)
			crc = upd_crc32(msgid, crc, strlen(msgid));

		if (check_dupe)
			dupe = CheckDupe(crc, (char *)"echomail", CFG.toss_dupes);
		else
			dupe = FALSE;
		if (dupe)
			echo_dupe++;
	}

	if ((echomail) && (!bad) && (!dupe)) {

		/*
		 * Check if the message is for us. Don't check point address,
		 * echomail messages don't have point destination set.
		 */
		if ((msgs.Aka.zone != t->zone) || (msgs.Aka.net != t->net) ||
		    (msgs.Aka.node != t->node)) {
			bad = TRUE;
			/*
			 * If we are a hub or host and have all our echomail
			 * connected to the hub/host aka, echomail from points
			 * under a nodenumber aka isn't accepted. The match
			 * must be further tested.
			 */
			if ((msgs.Aka.zone == t->zone) && 
			    (msgs.Aka.net == t->net)) {
				for (i = 0; i < 40; i++) {
					if ((CFG.akavalid[i]) &&
					    (CFG.aka[i].zone == t->zone) &&
					    (CFG.aka[i].net  == t->net) &&
					    (CFG.aka[i].node == t->node))
						bad = FALSE; /* Undo the result */
				}
			}
		}
		if (bad) {
			echo_bad++;
			WriteError("Msg in %s not for us (%s) but for %s", msgs.Tag, aka2str(msgs.Aka), ascfnode(t,0x1f));
		}
	}

	if ((echomail) && (!bad) && (!dupe)) {

//		Syslog('m', "Accepted msg in area %s", msgs.Tag);

		if (msgs.Aka.zone != Link.aka.zone) {
			/*
			 * If it is a gated echomailmessage the SEEN-BY lines
			 * are stripped off including that of the other zone's
			 * gate. Add the gate's aka to the SEEN-BY
			 */
			Syslog('m', "Gated echomail, clean SB");
			tidy_falist(&sbl);
			sprintf(sbe, "%u/%u", Link.aka.net, Link.aka.node);
			Syslog('m', "Add gate SB %s", sbe);
			fill_list(&sbl, sbe, NULL);
		}

		/*
		 * Add more aka's to SEENBY if in the same zone as our system.
		 * When ready filter dupe's, there is at least one.
		 */
		for (i = 0; i < 40; i++) {
			if (CFG.akavalid[i] && 
			    (msgs.Aka.zone == CFG.aka[i].zone) &&
			    !((msgs.Aka.net == CFG.aka[i].net) &&
			    (msgs.Aka.node == CFG.aka[i].node))) {
				sprintf(sbe, "%u/%u", CFG.aka[i].net, CFG.aka[i].node);
//				Syslog('m', "Add extra SB: %s", sbe);
				fill_list(&sbl, sbe, NULL);
			}
		}
		uniq_list(&sbl);
	}

	/*
	 * Add our system to the path for later export.
	 */
	sprintf(sbe, "%u/%u", msgs.Aka.net, msgs.Aka.node);
	fill_path(&ptl, sbe);
//	uniq_list(&ptl);

	if (echomail) {
		/*
		 * Build a list of qualified systems to receive this message.
		 * Complete the SEEN-BY lines.
		 */
		First = TRUE;
		while (GetMsgSystem(&Link, First)) {
			First = FALSE;
			if ((Link.aka.zone) && (Link.sendto) &&
			    (!Link.pause) && (!Link.cutoff)) {
				fill_qualify(&qal, Link.aka,
				     ((p_from->zone  == Link.aka.zone) &&
				      (p_from->net   == Link.aka.net) &&
				      (p_from->node  == Link.aka.node) &&
				      (p_from->point == Link.aka.point)),
				      in_list(fido2faddr(Link.aka), &sbl, FALSE));
			}
		}
//		sort_list(&sbl);
//		dlog_qualify(&qal, (char *)"After Build qualify");

		/*
		 *  Add SEEN-BY for nodes qualified to receive this message.
		 *  When ready, filter the dupes and sort the SEEN-BY entries.
		 */
		for (tmpq = qal; tmpq; tmpq = tmpq->next) {
			if (tmpq->send) {
				sprintf(sbe, "%u/%u", tmpq->aka.net, tmpq->aka.node);
				fill_list(&sbl, sbe, NULL);
			}
		}
		uniq_list(&sbl);
		sort_list(&sbl);

		/*
		 *  Create a new tmpfile with a copy of the message
		 *  without original PATH and SEENBY lines, add the
		 *  new PATH and SEENBY lines.
		 */
		rewind(fp);
		if ((nfp = tmpfile()) == NULL) {
			WriteError("$Unable to open tmpfile");
		}
		while ((fgets(buf, 2048, fp)) != NULL) {
			Striplf(buf);
			fprintf(nfp, "%s", buf);
			/*
			 * Don't write SEEN-BY and PATH lines
			 */
			if (strncmp(buf, " * Origin:", 10) == 0)
				break;
			fprintf(nfp, "\n");
		}

		/*
		 * Now add new SEEN-BY and PATH lines
		 */
		seenlen = MAXSEEN + 1;
		/*
		 * Ensure that it will not match for 
		 * the first entry.
		 */
		oldnet = sbl->addr->net - 1;
		for (tmpl = sbl; tmpl; tmpl = tmpl->next) {
			if (tmpl->addr->net == oldnet)
				sprintf(sbe, " %u", tmpl->addr->node);
			else
				sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node);
			oldnet = tmpl->addr->net;
			seenlen += strlen(sbe);
			if (seenlen > MAXSEEN) {
				seenlen = 0;
				fprintf(nfp, "\nSEEN-BY:");
				sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node);
				seenlen = strlen(sbe);
			}
			fprintf(nfp, "%s", sbe);
		}

		seenlen = MAXPATH + 1;
		/* 
		 * Ensure it will not match for the first entry
		 */
		oldnet = ptl->addr->net - 1;
		for (tmpl = ptl; tmpl; tmpl = tmpl->next) {
			if (tmpl->addr->net == oldnet)
				sprintf(sbe, " %u", tmpl->addr->node);
			else
				sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node);
			oldnet = tmpl->addr->net;
			seenlen += strlen(sbe);
			if (seenlen > MAXPATH) {
				seenlen = 0;
				fprintf(nfp, "\n\001PATH:");
				sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node);
				seenlen = strlen(sbe);
			}
			fprintf(nfp, "%s", sbe);
		}
		fprintf(nfp, "\n");
		fflush(nfp);
		rewind(nfp);

		/*
		 * Import this message if not passthru or if dupe or if bad.
		 */
		if ((!msgs.PassThru) || (dupe) || (bad)) {
			if (bad) {
				if (strlen(CFG.badboard) == 0) {
					Syslog('+', "Killing bad message");
					tidy_falist(&sbl);
					tidy_falist(&ptl);
					tidy_qualify(&qal);
					free(buf);
					return 0;
				} else {
					result = Msg_Open(CFG.badboard);
					if (result)
						Syslog('+', "Tossing in bad board");
				}
			} else
				if (dupe) {
					if (strlen(CFG.dupboard) == 0) {
						Syslog('+', "Killing dupe message");
						tidy_falist(&sbl);
						tidy_falist(&ptl);
						tidy_qualify(&qal);
						free(buf);
						return 0;
					} else {
						result = Msg_Open(CFG.dupboard);
						if (result)
							Syslog('+', "Tossing in dupe board");
					}
				} else {
					result = Msg_Open(msgs.Base);
				}
			if (!result) {
				WriteError("Can't open JAMmb %s", msgs.Base);
				tidy_falist(&sbl);
				tidy_falist(&ptl);
				tidy_qualify(&qal);
				free(buf);
				return 1;
			}

			if (Msg_Lock(30L)) {
				if ((!dupe) && (!bad))
					echo_imp++;

				if (!do_quiet) {
					colour(3, 0);
					printf("\r%6u => %-40s\r", echo_in, msgs.Name);
					fflush(stdout);
				}

				Msg_New();

				/*
				 * Fill subfields
				 */
				strcpy(Msg.From, f->name);
				strcpy(Msg.To, t->name);
				strcpy(Msg.FromAddress, ascfnode(f,0x1f));
				strcpy(Msg.Subject, subj);
				Msg.Written = mdate;
				Msg.Arrived = time(NULL);
				Msg.Echomail = TRUE;

				/*
				 * These are the only usefull flags in echomail
				 */
				if ((flags & M_PVT) && (msgs.Private))
					Msg.Private = TRUE;
				if (flags & M_FILE)
					Msg.FileAttach = TRUE;

				/*
				 * Set MSGID and REPLYID crc.
				 */
				if (msgid != NULL) {
					crc2 = -1;
					Msg.MsgIdCRC = upd_crc32(msgid, crc2, strlen(msgid));
				}
				if (reply != NULL) {
					crc2 = -1;
					Msg.ReplyCRC = upd_crc32(reply, crc2, strlen(reply));
				}

				/*
				 * Start write the message
				 * If not a bad or dupe message, eat the first
				 * line (AREA:tag).
				 */
				rewind(nfp);
				if (!dupe && !bad)
					fgets(buf , 256, nfp);
				Msg_Write(nfp);
				Msg_AddMsg();
				Msg_UnLock();
			} else
				Syslog('+', "Can't lock msgbase %s", msgs.Base);
			Msg_Close();
		}

		/*
		 * Forward to other links
		 */
		if ((!dupe) && (!bad)) {
			/*
			 * Now start exporting this echomail.
			 */
			for (tmpq = qal; tmpq; tmpq = tmpq->next) {
				if (tmpq->send) {
					if (SearchNode(tmpq->aka, tmpq->aka.point)) {
						StatAdd(&nodes.MailSent, 1L);
						UpdateNode();
						SearchNode(tmpq->aka, tmpq->aka.point);
					}
					echo_out++;
					EchoOut(p_from, tmpq->aka, nfp, flags, cost, mdate);
				}
			}
		}
	}

	/*
	 * Free memory used by SEEN-BY, ^APATH and Qualified lines.
	 */
	tidy_falist(&sbl);
	tidy_falist(&ptl);
	tidy_qualify(&qal);

	if (rc < 0) 
		rc =-rc;
	free(buf);
	return rc;
}


