/* Some of the code in this file was originally based on the following file:
 * gateway.c : Paul Healy, EI9GL, 900818
 *
 * Rewrote forwarding mechanism to use "X-Forwarded-To" paradigm instead of
 * "X-BBS-To", added timer support, etc.  Anders Klemets, SM0RGV, 901009.
 */
/* Mods by G1EMM and WG7J */
#include "global.h"
#include "files.h"
#include "ctype.h"
#include "commands.h"
#ifndef MSDOS
#include <time.h>
#include "ftp.h"
#endif
#include "bm.h"
#include "usock.h"

#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: forward.c,v 1.52 2001/05/08 12:26:44 brian Exp $";
#endif

#ifdef MBFWD

extern int MbForwarded, SYSOPprotect;
extern char *mbxRCall;
extern char AXRosecall[AXALEN];

#ifdef XFWD
extern int MXfwd;
#endif

#ifdef FBBFWD
extern int Mfbb;
#endif

#ifdef LOCK
extern int Kblocked;
#endif

extern int BBSdump;
extern int MbBID, MbMID;

#define ISPROMPT(s) (strlen(s) > 1 && s[strlen(s)-2] == '>')
static struct timer fwdtimer;
static int lastSessionSkipped;
extern int FWDmode, FWDpersonal, FWDbulletins, FWDreverse, FWDinreverse;
extern int FWDctlz, FWDpmulti;
extern char FWDCall[AXALEN];

extern char *Mbhaddress;
extern int MbRSTYLE;
extern char *Mbfwdinfo;
extern char *Mbqth;
extern char *Mbzip;
extern int Mbsmtptoo;
extern int UtcOffset;
extern int MBXMaint;
extern int MBXMaintMode;

struct subchan *subchannels;

#if defined(FBBCMP) && defined(UNIX)
extern int Mfbbcmp;
#endif

#ifdef STRICT_CALL
extern int PBBSstrict;
#endif

#ifdef UKIP
extern int FWDtlines;
extern int FWDxbid;
#endif

static void sendtempfile (FILE * newfile, struct mbx * m, int sendit);

static int uselessconnect (struct mbx * m, char *filename);
static void sendwithcorrectNL (struct mbx * m, char *str);
void checkforALTs (void);
static void checkoneALT (char *name);
extern void updateFwd (char *who, char *area, long bid, long size);
extern void ReadFwdBbs (void);
extern void freeareas (void);
void forwardingSummary (void);
static char *findident (char *str, int n, char *result);
char *mbxtime (char *line);
static int fwdanybbs (struct mbx * m, int *poll, int *theindex);
static void fwdtick (void *v);
void fwdproc (int, void *, void *);
static int isconnbbs (struct mbx * m);
static void startfwd (int a, void *v1, void *v2);
static int openconn (int argc, char *argv[], void *p);
static int sendmsgtobbs (struct mbx * m, int msgn, char const *dest, int bulletin);
static char *grabtext (char *from, char *to, int marker, int maxlen);
extern char *nntp_name_expansion (char *name);
extern void bid_delete (register char *string);
int forwardreset (int argc, char *argv[], void *p);
static int checkone (char *line, const char *str, const char *sub);
static int adaptaddress (char *line);
static int fwdthisarea (struct mbx * m, FILE * fwd, char *area, char *newto);
static void fwdcleanup (struct mbx * m, const char *string);
static int fwd_clockset (struct mbx * m);
extern int indexFwdBbs (char *name);
extern int makeBBSbid (char *bid, int bidlen, char *line);
extern void bid_add (char *bid, time_t now, int tofile, char *to);
extern int msgidcheck (char *string);
#ifdef UKIP
void makeTlines (struct mbx *m, int msgn);
#endif


#ifdef CATALOG
#include "catalog.h"

#define CAT forward_catalog

#define forwardingtimer	__STR(0)
#define nostart		__STR(1)
#define defering	__STR(2)
#define queueing	__STR(3)
#define delayedmaintenance __STR(4)
#define started		__STR(5)
#define unabletostart	__STR(6)
#define examining	__STR(7)
#define alreadyconnected __STR(8)
#define checkingforfile	__STR(9)
#define forwardingcomplete __STR(10)
#define connectionfailed __STR(11)
#define scriptdone	__STR(12)
#define waitingfor	__STR(13)
#define Netromunavailable __STR(14)
#define Netromsocket	__STR(15)
#define mailsent	__STR(16)
#define mailrefused	__STR(17)
#define unexpectedresponse __STR(18)
#define forwardingmailto __STR(19)
#define forwardfailed	__STR(20)
#define badax25iface	__STR(21)
#define nosidfound	__STR(22)
#define nosidfound2	__STR(23)

#else /* CATALOG */
static const char forwardingtimer[] = "Forwarding timer: %lu/%lu\n";
static const char nostart[] = "Couldn't start Forwarding process";
static const char defering[] = "fwd: Deferring large message to %s, allowed=%ld, size=%ld\n";
static const char queueing[] = "fwd: queueing message %ld from BBS %s, to alternate: %s\n";
static const char delayedmaintenance[] = "fwd: forward delayed - maintenance mode\n";
static const char started[] = "fwd: forward started\n";
static const char unabletostart[] = "fwd: unable to start new maibox\n";
static const char examining[] = "fwd: examining '%s'\n";
static const char alreadyconnected[] = "fwd: '%s' already connected\n";
static const char checkingforfile[] = "fwd: checking for file '%s'\n";
static const char forwardingcomplete[] = "PBBS forwarding complete to: %s\n";
static const char connectionfailed[] = "fwd: Connection failed to %s, TRY = %d\n";
static const char scriptdone[] = "fwd: %s, script done\n";
static const char waitingfor[] = "fwd: %s, wait %ld -  waiting for %s\n";
static const char Netromunavailable[] = "fwd: Netrom route unavailable - %s\n";
static const char Netromsocket[] = "fwd: unable to open Netrom socket - %s\n";
static const char mailsent[] = "PBBS mail sent: %s ";
static const char mailrefused[] = "PBBS mail refused: %s\n     %s";
static const char unexpectedresponse[] = "PBBS mail - unexpected response: %s\n     %s";
static const char forwardingmailto[] = "PBBS %sforwarding mail to: %s ";
static const char forwardfailed[] = "PBBS forward failed: %s errno %d";
static const char badax25iface[] = "Invalid forwarding interface '%s' for %s";
static const char nosidfound[] = "No SID received from remote system %s - aborting";
static const char nosidfound2[] = "'No SID' indicates a probable problem with your forwarding script";
#endif /* CATALOG */



#ifdef FBBFWD
static char *ltoa (long value, char *string, int radix OPTIONAL);

static char *
ltoa (long value, char *string, int radix OPTIONAL)
{
	/* assume radix of 10, since only called with that value */
	sprintf (string, "%ld", value);
	return (string);
}
#endif



char *
fwd_bbsname (struct mbx *m)
{
static char tmp[20];

	if (*m->call)
		(void) pax25 (tmp, m->call);
	else {
		strncpy (tmp, m->name, 19);
		(void) strupr (tmp);
	}
	return (tmp);
}



/***************************************************************************
   findident copies the 'n'th alphanumeric sequence from 'str' to result.
   It returns a ptr to result. It returns "\0" for missing identifier etc.
   Uses isalnum macro to decide on alphanumeric/non-alnum status.
*/
static char *
findident (char *str, int n, char *result)
{
int count;		/* current identifier */

	count = 0;
	*result = '\0';
	while ((count < n) && (*str != '\0')) {	/* Process alnum or non alnum seq */
		while ((*str != '\0') && (!isalnum (*str)))	/* Get rid of ';:.@%"# etc */
			str++;
		if ((*str != '\0') && isalnum (*str)) {	/* this is an alnum seq */
			count++;
			while ((*str != '\0') && (isalnum (*str) || (*str == '_')))
				if (count == n)
					*result++ = *str++;
				else
					str++;
			if (count == n)
				*result = '\0';
		}
	}
	return result;
}


extern int Mbfullsvc;



static int
checkone (char *line, const char *str, const char *sub)
{
char *cp;

	if (str && line && !strnicmp (line, str, strlen (str)) && (cp = strstr (line, Hostname)) != NULLCHAR) {
		strcpy (cp, sub);
		return 1;
	}
	return 0;
}



static int
adaptaddress (char *line)
{
char buf[60], *cp;

	(void) pax25 (buf, Mycall);
	if ((cp = strpbrk (buf, DIGI_IDS)) != NULLCHAR)
		*cp = '\0';	/* remove SSID */
	if (Mbhaddress != NULLCHAR) {
		strcat (buf, ".");
		strcat (buf, Mbhaddress);
	}
	strcat (buf, "\n");
	if (checkone (line, Hdrs[XMAILGROUP], buf))
		return 1;
	if (checkone (line, Hdrs[ERRORSTO], buf))
		return 1;
	return (checkone (line, Hdrs[REPLYTO], buf));
}



static void
sendwithcorrectNL (struct mbx *m, char *str)
{
#if defined(UNIX) && defined(FBBCMP)
	if (m->msglst && Mfbbcmp && m->sid & MBX_FBBCMP) {
		rip (str);
		strcat (str, "\r\n");
	}
#endif
	fputs (str, m->quickfile);
}



/**************************************************************************/
/* sendmsg() modified to send the R: line always.
 * also added some additional strings like qth and zipcode etc. to R: line.
 * Original SMTP headers get forwarded optionally.
 * 920114 - WG7J
 */

void
sendmbmsg (struct mbx *m, int msgn, char *thebid)
{
FILE *oldfile, *newfile;
char buf[LINELEN], tb[LINELEN], *cp;
char Rline[LINELEN];
int rec = 0;		/* rec is line-counter */
unsigned int msgid = 0;	/* message id number - WG7J */
int col, ccnt;
char c;
int sendthefile = 0;
long endofmsg = 0L;
#ifdef UKIP
int foundt = 0, lastlinewast = 0, blanklines = 0;
#endif
	
	/* point to start and end of this message in file */
	fseek (m->mfile, m->mbox[msgn].start, 0);
	if (m->nmsgs > msgn)
		endofmsg = m->mbox[msgn + 1].start;

	/* If the data part of the message starts with "R:" the RFC-822
	 * headers will not normally be forwarded. Instead we will add an R:
	 * line of our own. ALWAYS forward with "R:" line
	 */

	/* This loop is until we have read our internal MID */
	for (;;) {
		/* read a line */
		if (fgets (buf, sizeof (buf), m->mfile) == NULLCHAR)
			break;
		kwait (NULL);

		if (rec == 1) {	/* We are on the line with the MID */
			/* look at the line following Received:
			 * This has the ID followed by ' ; date&time in arpa-format'
			 * Get the message number from the ID line - WG7J
			 */
			if ((cp = strstr (buf, "AA")) != NULLCHAR)
				/* what follows is the message-number */
				msgid = (unsigned int) atoi (cp + 2);

			/* get the ARPA format date/time string */
			if ((cp = strchr (buf, ';')) != NULLCHAR)
				strncpy (tb, cp + 1, LINELEN);	/* point to the date of receipt */

			/* Get the callsign for the R: line */
			if (mbxRCall)
				strncpy (buf, mbxRCall, LINELEN);
			else
				(void) pax25 (buf, Mycall);
			if ((cp = strpbrk (buf, DIGI_IDS)) != NULLCHAR)
				*cp = '\0';	/* remove SSID */

			/* If not a fullservice BBS, don't send the R: line */
			if (Mbfullsvc) {
				if (!MbRSTYLE) {
					sprintf (Rline, "R:%s @:%s%s%s ", mbxtime (tb), buf,
					(Mbhaddress != NULLCHAR) ? "." : "",
						 (Mbhaddress != NULLCHAR) ? Mbhaddress : "");
					if (Mbfwdinfo)
						sprintf (&Rline[strlen (Rline)], "[%s] ", Mbfwdinfo);
					if (Mbqth)
						sprintf (&Rline[strlen (Rline)], "%s ", Mbqth);
					if (MbMID)
						sprintf (&Rline[strlen (Rline)], "#:%u ", msgid);
					if (Mbzip)
						sprintf (&Rline[strlen (Rline)], "Z:%s ", Mbzip);
					if (MbBID)
						sprintf (&Rline[strlen (Rline)], "$:%s", thebid);
					strcat (Rline, "\n");
				} else
					sprintf (Rline, "R:%s %d@%s%s%s\n", mbxtime (tb), msgid, buf,
						 (Mbhaddress) ? "." : "", (Mbhaddress) ? Mbhaddress : "");
#ifdef BBSEXPORT
				if (m->quickfile)
					sendwithcorrectNL (m, Rline);
				else
#endif
					usputs (m->user, Rline);
			}	/* Mbfullsvc */
			break;	/* done with this portion of the message */
		}		/* rec == 1 */
		/* The first Received: line is the one that we have added */
		if (!rec && htype (buf) == RECEIVED)
			++rec;
	}


	/* Go past the SMTP headers to the data of the message.
	 * Check if we need to forward the SMTP headers! 920114 - WG7J
	 */


	/* first, save any current quickfile, and replace it with a tmpfile
	 * for placing any smtp headers into.
	 */
	oldfile = m->quickfile;
	newfile = tmpfile ();
	m->quickfile = newfile;

	/* place the separating NL */
#if defined(UNIX) && defined(FBBCMP)
	if (m->msglst && Mfbbcmp && m->sid & MBX_FBBCMP)
		fputs ("\r\n", m->quickfile);
	else
#endif
		fputs ("\n", m->quickfile);


	/* This loop is to process the RFC headers and send any needed ones
	 * to a TEMP file, to be inserted at the proper time.
	 */
	for (;;) {
		if (fgets (buf, sizeof (buf), m->mfile) == NULLCHAR)
			break;
		kwait (NULL);
		if (*buf == '\n')	/* last header line */
			break;
		if (adaptaddress (buf)) {	/* check for headers always sent */
			sendwithcorrectNL (m, buf);
			sendthefile = 1;
		} else if (Mbsmtptoo) {
			/* YES, forward SMTP headers TOO !*/
			switch (htype (buf)) {
				case XFORWARD:	/* Do not forward the "X-Forwarded-To:" lines */
				case STATUS:	/* Don't forward the "Status:" line either */
				case BBSTYPE:
				case XBID:
				case XBBSTO:
				case XNNTPNEWSGROUPS:
				case LINECNT:
				case SUBJECT:
				case TO:
				case DATE:
					/* never send these headers */
					break;
				case FROM:	/* Don't forward the "From: " line either, make it ">From: " */
					cp = strdup (buf);
					strcpy (buf, ">");
					strcat (buf, cp);
					free (cp);
					/* note fall-through */
				default:
				            /* Don't pass 'X-BBS' headers */
				    if (strncmp (buf, "X-BBS", 5) == 0)
					    break;
				
				    trimrightCR (buf);
					sendwithcorrectNL (m, buf);
					sendthefile = 1;
				
			}	/* switch */
		}		/* Mbsmtptoo */
	}			/* for */

	/* Now reset the quickfile to it's previous state and rewind tempfile */
	m->quickfile = oldfile;
	if (newfile)
		rewind (newfile);

	/* If there are other R: headers, process them first */
	for (;;) {		/* do this while you have R: lines */
		/* if there is no data, send the tempfile and you're done */
		if (fgets (buf, sizeof (buf), m->mfile) == NULLCHAR) {
			sendtempfile (newfile, m, sendthefile);
			return;	/* NO text ??? */
		}
		if (strncmp (buf, "R:", 2))	{/* No more R: lines! */
#ifdef UKIP
			/* Pass any T: Lines in with the R: Lines     */
			/* If there are none, make our own if enabled */

			if (strncmp (buf, "T:", 2)) {    /* This is not a T: Line */
				if ((FWDtlines) && (!foundt))
					makeTlines (m, msgn);          /* Go make T: lines if none already */
#endif
				break;
#ifdef UKIP
			}
			else
				foundt = 1; /* T: Line in with R: Lines - flag and pass*/
#endif
			}
#ifdef BBSEXPORT
		if (m->quickfile)
			sendwithcorrectNL (m, buf);
		else
#endif
			usputs (m->user, buf);
	}

	/* Now add the smtp headers desired. */
	sendtempfile (newfile, m, sendthefile);

	if (!strncmp (Hdrs[RRECEIPT], buf, strlen (Hdrs[RRECEIPT]))) {	/* return receipt line */
		if (!isarea (m->area)) {	/* only send if not a bulletin */
#ifdef BBSEXPORT
			if (m->quickfile)
				sendwithcorrectNL (m, buf);
			else
#endif
				usputs (m->user, buf);
		}
		(void) fgets (buf, sizeof (buf), m->mfile);	/* eat the blank line following */
		if (*buf == '\n')
			(void) fgets (buf, sizeof (buf), m->mfile);	/* eat the blank line following */
	}
	/* place the separating NL */
#ifdef BBSEXPORT
#if defined(UNIX) && defined(FBBCMP)
	if (m->quickfile) {
		if (m->msglst && Mfbbcmp && m->sid & MBX_FBBCMP)
			fputs ("\r\n", m->quickfile);
		else
#else
	if (m->quickfile) {
#endif
			fputs ("\n", m->quickfile);
	} else
#endif
		usputs (m->user, "\n");

	/* we now have the first data line in buf, so send it */
#ifdef BBSEXPORT
	if (m->quickfile)
		sendwithcorrectNL (m, buf);
	else
#endif
		usputs (m->user, buf);



	/* the rest of the message is treated below */
	col = 0;
	while (!feof (m->mfile)) {
		if (endofmsg && (ftell (m->mfile) >= endofmsg))
			break;
		for (col = 0; col < MAXBUF;) {
			c = (char) getc (m->mfile);
			if (feof (m->mfile))	/* end this line */
				break;
			if (c == '\t') {
				ccnt = col + 8 - (col & 7);
				if (ccnt >= MAXBUF)	/* end this line */
					break;
				while (col < ccnt)
					buf[col++] = ' ';
			} else {
				if (c == '\n')
					break;
				buf[col++] = c;
			}
		}		/* for */
		if (col < MAXBUF)
			buf[col++] = '\n';
		buf[col] = '\0';

		if (!strncmp (buf, "From ", 5))	/* somehow endofmsg didn't work */
			break;
#ifdef UKIP
		/* If we're making our own T: Lines, or if there are T: Lines
		 * already included in with the R: Lines, kill off any existing
		 * T: lines near the top of the message that have been separated
		 * out by another BBS  */
		
		if (FWDtlines || foundt) {
			if (buf[0] == '\n') {
				blanklines ++;
				if (lastlinewast) { /* chew any blank line following a T: Line */
					lastlinewast = 0;
						continue;
				}
			}
			if ((blanklines < 3) && (strncmp (buf, "T:", 2) == 0)) {  
				lastlinewast = 1;
				continue;          /* chew the T: line */
			}
			else 
				lastlinewast = 0;
		}
#endif
				
#ifdef BBSEXPORT
		if (m->quickfile)
			sendwithcorrectNL (m, buf);
		else
#endif
			usputs (m->user, buf);
		kwait (NULL);
	}			/* while */
}



static void
sendtempfile (FILE *newfile, struct mbx *m, int sendit)
{
int c;

	if (sendit) {
#ifdef BBSEXPORT
		if (m->quickfile) {
			while ((c = getc (newfile)) != EOF)
				fputc (c, m->quickfile);
		} else
#endif
			(void) sendfile (newfile, m->user, ASCII_TYPE, 0);
	}
	(void) fclose (newfile);
}



/* Parse a line for date and time in Arpanet format
 * (Day, day Month year hh:mm:ss Zone) and return it in mailbox format
 * (yymmdd/hhmmz)
 */
char *
mbxtime (char *line)
{
static char buf[13];
char *cp;
int year, month, day, hour, minute, maxdays;

	cp = line;
	if (!cp)
		return NULLCHAR;
	while (isspace (*cp))	/* skip initial blanks */
		++cp;
	if (*cp == '\0')
		return NULLCHAR;
	if (strlen (cp) < 22)
		return NULLCHAR;
	cp += 5;
	day = atoi (cp);
	if (*(++cp) != ' ')
		++cp;
	++cp;
	for (month = 0; month < 12; ++month)
		if (strnicmp (Months[month], cp, 3) == 0)
			break;
	if (month == 12)
		return NULLCHAR;

	/* Get things, and adjust for GMT/UTC time - WG7J */
	month++;
	year = atoi (cp + 4);
	hour = atoi (cp + 7);
	minute = atoi (cp + 10);

	if (UtcOffset != 0) {
		hour -= UtcOffset;
		/* See if we went past midnight */
		if (hour > 23) {
			hour -= 24;
			++day;
			/*Check for next month*/
			if (month == 2) {	/*February, check leap-year*/
				if ((year % 4) == 0)
					maxdays = 29;
				else
					maxdays = 28;
			} else {
				if ((month % 2) == 0)
					maxdays = 30;
				else
					maxdays = 31;
			}
			if (day > maxdays) {	/*adjust month*/
				day = 1;
				if (++month == 13) {	/*next year*/
					month = 1;
					year++;
				}
			}
		} else if (hour < 0) {	/*previous day !*/
			hour += 24;
			if (--day == 0) {	/*previous month*/
				if (--month == 0) {	/*previous year*/
					year--;
					month = 12;
				}
				if (month == 2) {	/* February, check leap year */
					if ((year % 4) == 0)
						day = 29;
					else
						day = 28;
				} else {
					if ((month % 2) == 0)
						day = 30;
					else
						day = 31;
				}
			}
		}
	}
	sprintf (buf, "%02d%02d%02d/%02d%02dz", year, month, day, hour, minute);
	return buf;
}



static char *
grabtext (char *from, char *to, int marker, int maxlen)
{
	while (*from != marker) {
		*to++ = *from++;
		if (!--maxlen)
			break;
	}
	*to = '\0';
	return from + 1;
}



/* Makes a command line and returns -1 if the message cannot be sent and
   -2 if message couldn't be sent and should be deleted.
 */
int
makecl (m, msgn, dest, line, subj, bid, bul)
struct mbx *m;
int msgn;			/* Message number */
char const *dest;		/* Destination address to use instead of To: line */
char *line, *subj;		/* Buffers to keep command line and subject */
char *bid;			/* Buffer to keep bid */
int *bul;			/* True if message is in public message area */
{
int bulletin = *bul;
int foundbid = 0, foundmid = 0, foundto = 0;
char to[LINELEN], atbbs[LINELEN], from[LINELEN], buf[LINELEN], *cp;
#ifdef FBBFWD
char bid2[LINELEN];
char tmp[40];
#endif
#ifdef UKIP
int xbidlen = 0;
#endif

	if (m->mfile == NULLFILE)
		return -1;

	/* used to be if(!bulletin && (m->mbox[msgn].status & BM_READ)) */
	if (!issysarea (m->area) && (m->mbox[msgn].status & BM_READ))
		return -2;	/* the message was already read */
	fseek (m->mfile, m->mbox[msgn].start, 0);
	*bid = *to = *atbbs = *from = '\0';
	if (subj != NULLCHAR)
		*subj = '\0';
	m->stype = bulletin ? 'B' : 'P';	/* default to SB or SP */
	/* if it comes from a NTS area, always send as traffic, ie 'ST' - WG7J */
	if (!strnicmp (m->area, "nts", 3))
		m->stype = 'T';
	while (fgets (buf, sizeof (buf), m->mfile)) {
		if (buf[0] == '\n')
			break;	/* envelope finished */
		switch (htype (buf)) {
			case TO:
#ifdef UKIP
			    if (foundto)
				    break;
			case XBBSTO:           /* Use X-BBS-TO in preference to To: */
#endif
				trimrightCR (buf);
				/* The following code tries to parse "To: " lines where the
				 * address looks like any of the following: "to@atbbs",
				 * "<to@atbbs>", "<to%atbbs@host>" and with possible spaces
				 * surrounding the '<>' characters.
				 */
				if ((cp = getaddress (buf, 0)) == NULLCHAR)
					break;
				strncpy (to, cp, LINELEN);
				if ((cp = strchr (to, '%')) != NULLCHAR) {	/* look for a '%' */
					strncpy (atbbs, cp + 1, LINELEN);
					*cp = '\0';	/* "to" ends at the '%' character */
					if ((cp = strchr (atbbs, '@')) != NULLCHAR)
						*cp = 0;
				} else {	/* no '%' but maybe a '@'? */
					if ((cp = strchr (to, '@')) != NULLCHAR) {
						strncpy (atbbs, cp + 1, LINELEN);
						*cp = '\0';	/* "to" ends at the '@' character */
					}
				}

				/* "to" or "atbbs" should not be more than 6 characters (ALEN).
				 * If "to" is too long, it might simply be because the area name
				 * is longer than 6 characters, but it might also be because
				 * the address on the To: line is in an obscure format that we
				 * failed to parse (eg '!' character notation.)
				 */
				if (strlen (to) > ALEN) {
#if 0
					/* Play safe and set "to" and "atbbs" to the area name */
					strncpy (to, m->area, LINELEN);
					strncpy (atbbs, m->area, LINELEN);
#else
					/* if "to" or "atbbs" are > 6 character, they are IMPROPER. Delete them */
					return -2;
#endif
				}
				/* why would we want to add an atbbs if the message doesn't have one originally ?!?! */
#if 0
				if (*atbbs == '\0')
					strncpy (atbbs, to, LINELEN);
#endif

				to[ALEN] = '\0';
				/* Only if the BBS supports "hierarchical routing designators"
				 * is the atbbs field allowd to be longer than 6 characters and
				 * have dots in it.
				 */
				if ((m->sid & MBX_HIER_SID) == 0) {
					atbbs[ALEN] = '\0';	/* 6 character limit */
					if ((cp = strchr (atbbs, '.')) != NULLCHAR)
						*cp = '\0';	/* cut "atbbs" at first dot */
				}
			    foundto = 1;
				break;
			case MSGID:
				if (!foundmid)	{
					foundmid = 1;
					trimrightCR (buf);
					bid[0] = '$';
					
					
					/* Is this clobbering the subject line in export ? */
#if 0
					foundbid = makeBBSbid (&bid[1], LINELEN - 1, buf);
#else
					foundbid = makeBBSbid (&bid[1], LINELEN - 2, buf);
#endif
					/* if a bulletin and not in the history file, add it */
					if (*bul && !msgidcheck (&bid[1]))
						bid_add (&bid[1], time ((time_t *)0), 1, m->area);
				}
				break;
#ifdef UKIP
			case XBID:        /* Use BID from X-BID if present */
			    xbidlen = strlen (buf);
				if ((xbidlen > 7) && (xbidlen < 21) && FWDxbid) {
					foundmid = 1;
					trimrightCR (buf);
					bid[0] = '$';
					strcpy (&bid[1], &buf[7]);
					bid[13] = '\0';
					cp = (strchr (bid, '\n'));
					if (cp)
						*cp = '\0';
					break;
				}
#endif			
			case SUBJECT:
				trimrightCR (buf);
				if (subj != NULLCHAR) {
					if (buf[8] != '\n')
						(void) grabtext (buf + 9, subj, '\n', LINELEN - 1);
					/* Make sure subject isn't empty - WG7J */
					cp = subj;
					while (*cp == ' ' || *cp == '\t')
						cp++;
					if (*cp == '\0')
						strcpy (subj, "None");
				}
				break;
			case FROM:
				trimrightCR (buf);
				if ((cp = getaddress (buf, 0)) != NULLCHAR) {
					if (!strnicmp (cp, "REQSVR", 6) || !strnicmp (cp, "MAILER-DAEMON", 13)) {	/* MAILER-DAEMON going out->call sign */
						(void) pax25 (buf, Mycall);
						cp = strpbrk (buf, DIGI_IDS);
						if (cp)
							*cp = 0;
						strncpy (from, buf, LINELEN);
					} else
						(void) findident (cp, 1, from);	/* cp points to from@domain */
					from[ALEN] = '\0';	/* 6 character limit */
				}
				break;
			case XFORWARD:
				if ((cp = getaddress (buf, 0)) == NULLCHAR)
					break;
				if (stricmp (m->name, cp) == 0) {

					/* This message was RECEIVED from this BBS, abort */
					return -2;
				}
				break;
			case BBSTYPE:
				if (m->stype == 'P') {
					/* we do not make messages in public areas into personals
					 * but the reverse is permitted
					 */
					m->stype = buf[16];
					if (m->stype == 'B')
						bulletin = *bul = 1;
					else
						bulletin = *bul = 0;
				}
				break;
			default:
				break;
		}
	}
	/* Check for an invalid RFC-822 header */
	if ((to[0] == '\0' && ((dest != NULLCHAR && *dest == '\0') ||
			       dest == NULLCHAR)) || from[0] == '\0')
		return -2;

#ifdef STRICT_CALL
	if (PBBSstrict && strcasecmp(from, "WP") && !iscall (from))
		return -2;
#endif

	if (line != NULLCHAR) {
#ifdef FBBFWD
		if (Mfbb && (m->sid & MBX_FBBFWD)) {
			if (*atbbs)	{
				strncpy (tmp, atbbs, 39);
				tmp[39] = 0;
			} else if (*m->call) {
				/* outgoing, we canNOT be sure m->name is correct!
				   The BBS name in forward.bbs (which is m->name)
				   does NOT need to be the BBS name, so we look at
				   the callsign, instead... */
				(void) pax25 (tmp, m->call);
				if ((cp = strpbrk (tmp, DIGI_IDS)) != NULLCHAR)
					*cp = 0;
			} else {
				strncpy (tmp, m->name, 39);
				tmp[39] = 0;
			}
		}
#endif
		if (dest != NULLCHAR && *dest != '\0') {
			char *tempcp = strdup (dest);

			/* strip off hierarchical routing designators from the predefined
			 * destination address if they are not supported
			 */
#ifdef FBBFWD
			if (Mfbb && (m->sid & MBX_FBBFWD)) {
				if ((cp = strchr (tempcp, '.')) != NULLCHAR)
					*cp = '\0';
				if ((cp = strchr (tempcp, '@')) != NULLCHAR)
					*cp = '\0';
				sprintf (line, "FA %c %s %s %s ", m->stype, from, (cp) ? (cp + 1) : tmp, tempcp);
			} else {
#endif
				if ((m->sid & MBX_HIER_SID) == 0 && (cp = strchr (tempcp, '.')) != NULLCHAR)
					*cp = '\0';
				sprintf (line, "S%c %s < %s ", m->stype, tempcp, from);
#ifdef FBBFWD
			}
#endif
			free (tempcp);
		} else {
#ifdef FBBFWD
			if (Mfbb && (m->sid & MBX_FBBFWD))
				sprintf (line, "FA %c %s %s %s ", m->stype, from, tmp, to);
			else
#endif
				sprintf (line, "S%c %s%s%s < %s ", m->stype, to, (*atbbs) ? " @ " : "", atbbs, from);
		}
#ifdef nope
		/* This fixes the problem with personal MIDs being the same with
		 * messages generated from aliases, RMAIL, or mail-groups. Changes
		 * the bid from $abcde_host.domain to $abcde_destinationuser. - KO4KS
		 */
		if (!bulletin && (m->sid & MBX_MID)) {
			if ((cp = strrchr (bid, '_')) != NULLCHAR) {
				*cp++;
				if (!strnicmp (Hostname, cp, strlen (cp))) {
					*(cp - 1) = '%';
					if (dest != NULLCHAR && *dest != '\0')
						strcpy (cp, dest);
					else
						strcpy (cp, to);
					bid[13] = '\0';
					if ((cp = strchr (bid, '.')) != NULLCHAR)
						*cp = '\0';
				}
			}
		}
#endif

		/* This keeps us from adding a MID to someone else's message */
		if (!foundbid) {/* if one wasn't found, but GENERATED */
			(void) fgets (buf, sizeof (buf), m->mfile);	/* get first data line */
			if (!strnicmp (buf, "R:", 2))	/* if it has at least one "R:" line */
				bid[0] = '\0';	/* blank out the MID */
		}
		/* convert the bid to upper case for compatability with BBSs */
		(void) strupr (bid);

		/* Add the bid to bulletins,
		 * AND ALSO to anything that came in with a bid !
		 * Takes care off duplicate 'SP SYSOP@xxx $BID' problems - WG7J
		 * ALSO add it to ALL messages if the remote system supports MID's - WG7J
		 */
#ifdef FBBFWD
		if (Mfbb && (m->sid & MBX_FBBFWD) &&
		    ((m->sid & MBX_MID) || (bulletin && (m->sid & MBX_SID))))
			/* Append BID ( minus the '$' character. */
			strcat (line, &bid[1]);
		else
#endif

		if ((m->sid & MBX_MID) || (bulletin && (m->sid & MBX_SID)))
			strcat (line, bid);
#ifdef FBBFWD
		if (Mfbb && (m->sid & MBX_FBBFWD)) {
			strcat (line, " ");
			strcat (line, (char *) ltoa (m->mbox[msgn].size, bid2, 10));
		}
#endif
		strcat (line, "\n");
	}
	return 0;
}



/* return 0 = ok, -1 = problem so disc */
static int
sendmsgtobbs (m, msgn, dest, bulletin)
struct mbx *m;
int msgn;
char const *dest;		/* Optional destination address to override To: line */
int bulletin;
{
int result = -1;
char line[LINELEN], subj[LINELEN], thebid[LINELEN];

	if (makecl (m, msgn, dest, line, subj, thebid, &bulletin) < 0)
		return 0;	/* do not forward this particular message */

	if (thebid[0] == 0)	{
		if (Mtrace)
			tcmdprintf ("FWD: Skipping message to %s without a BID: %s\n", fwd_bbsname (m), line);
		log (m->user, "Skipping message to %s without a BID: %s\n", fwd_bbsname (m), line);
		return 0;
	}
	if (Mtrace)
		tcmdprintf ("FWD: Sending to %s - %s.\n", fwd_bbsname (m), line);

#ifdef BBSEXPORT
	if (m->quickfile) {
		fputs (line, m->quickfile);
		m->line[0] = 'O';
	} else {
#endif
		tputs (line);	/* Send mail offer to bbs */
		usflush (m->user);
#ifdef BBSEXPORT
	}
#endif
	rip (line);
	if (m->quickfile || recvline (m->user, (unsigned char *) m->line, MBXLINE) != -1) {
		if (Mtrace)
			tcmdprintf ("FWD: Received from %s - %s.\n", fwd_bbsname (m), m->line);

		if (m->line[0] == 'O' || m->line[0] == 'o' || (m->sid & MBX_SID) == 0) {
			if (Mtrace)
				tcmdprintf ("FWD: Sending message to %s\n", fwd_bbsname (m));
			/* Got 'OK' or any line if the bbs is unsofisticated */
#ifdef BBSEXPORT
			if (m->quickfile)
				fprintf (m->quickfile, "%s\n", subj);
			else
#endif
				tprintf ("%s\n", subj);
			sendmbmsg (m, msgn, &thebid[1]);	/* send the message */
#ifdef BBSEXPORT
			if (m->quickfile) {
				fputs ("/EX\n", m->quickfile);
				strcpy (m->line, "> ");
			} else {
#endif
				if (FWDctlz)
					tputs ("\032\n");
				else
					tputs ("/EX\n");
				usflush (m->user);
#ifdef BBSEXPORT
			}
#endif
			/* get '>' for a good deliver */
			while (m->quickfile || recvline (m->user, (unsigned char *) m->line, MBXLINE) != -1)
				if (ISPROMPT (m->line)) {
					log (m->user, mailsent, line);
					if (!bulletin && (stricmp (m->area, "sysop") || !SYSOPprotect) && (!FWDpmulti)) {
						m->mbox[msgn].status |= BM_DELETE;
						statusCtl (m->area, "ctl", &m->mbox[msgn], msgn, 0);
						m->change |= CHG_DELETE;
					}
					result = 0;
					MbForwarded++;
					break;
				}
		} else {	/* OK response not received from bbs */
			if (tolower (m->line[0]) == 'n' || tolower (m->line[0]) == 'r') {	/* 'NO/REJECT' response */
				log (m->user, mailrefused, line, m->line);
				result = 0;	/* don't want it, so skip it! */
			} else
				log (m->user, unexpectedresponse, line, m->line);

			/* should get a F> here */
			while (recvline (m->user, (unsigned char *) m->line, MBXLINE) != -1)
				if (ISPROMPT (m->line)) {
					result = 0;
					break;
				}
		}
	}			/* OK or NO here */
	if (m->stype != 'B')
		bid_delete (&thebid[1]);
	return result;
}



void
mark_forwarded (FILE *fp, long ind, char thetype)
{
long save;

	clearerr (fp);
	save = ftell (fp);
	fseek (fp, ind, SEEK_SET);
	fputc (thetype, fp);	/* mark as done! */
	(void) fflush (fp);
	fseek (fp, save, SEEK_SET);
}



/* Forward messages from one message area.  */
static int
fwdthisarea (struct mbx *m, FILE *fwd, char *area, char *newto)
{
int bulletin;
long bid, pos = 0;
int theindex, changed = 0, i;
int err = 0;
char *cp;
struct let *cmsg;
char line[80];


	kwait (NULL);
	bulletin = isarea (area);	/* public area */

	if (Mtrace && FWDareatrace)
		tcmdprintf ("FWD: Processing %s message area %s for %s.\n",
			bulletin ? "Public  " : "Private ", area, fwd_bbsname (m));

	if (bulletin && (!FWDbulletins || !m->fwdbbs->bulletins))
		return err;
	if (!bulletin && (!FWDpersonal || !m->fwdbbs->personals))
		return err;
	rewind (fwd);
	while (!err && fgets (line, sizeof (line), fwd) != NULLCHAR) {
		(void) fflush (fwd);
		kwait (NULL);
		if (*line == ' ') {	/* if not already done or blocked */
			if ((cp = strpbrk (&line[1], " \t")) == NULLCHAR)
				continue;
			*cp++ = '\0';
			if (!stricmp (area, &line[1])) {	/* only if for us */
				bid = atol (cp);
				if (!changed) {	/* if not already changed */
					m->area[0] = 0;		   /* force a reload of index      */
					changearea (m, area, (int) 1);
					changed = 1;
				}
				theindex = 0;
				for (cmsg = &m->mbox[1], i = 1; i <= m->nmsgs; i++, cmsg++)
					if ((bid == cmsg->bid) && !(cmsg->status & BM_DELETE)) {
						theindex = i;
						break;
					}
				if (theindex && m->fwdbbs && m->fwdbbs->maxsize && cmsg->size > m->fwdbbs->maxsize) {
					if (Mtrace)
						tcmdprintf (defering, m->fwdbbs->name, m->fwdbbs->maxsize, cmsg->size);
				} else {
					if (theindex && !(cmsg->status & (BM_ONHOLD | BM_DELETE))) {
						mark_forwarded (fwd, pos, '!');
						if (sendmsgtobbs (m, theindex, newto, bulletin) == -1)
							err = 1;	/* abort */
						else {
#ifdef STATS_MSG
							STATS_addmsg (1, 1);
#endif
#ifdef STATS_TFC
							STATS_addtfc (3, 1);
#endif
#ifdef STATS_FWD
							STATS_addfwd (1, 1, m->name);
#endif
						}
					}
					if (!theindex || (!err && !(cmsg->status & BM_ONHOLD)))
						mark_forwarded (fwd, pos, '*');
				}
			}
		}
		pos = ftell (fwd);	/* get new backup position */
		if (MBXMaintMode && MBXMaint)
			break;
	}
	return err;
}



/* This is the main entry point for reverse forwarding. It is also used
 * for normal, "forward", forwarding.
 */
int
dorevfwd (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
{
char oldarea[64], *area, *cp;
struct mbx *m;
int err = 0;
FILE *fwd;
long thesize, theend, newsize;
char name[256];
struct arealist *a;

	m = (struct mbx *) p;
	/* indicate we are doing reverse forwarding, if we are not already
	 * doing normal forwarding.
	 */
	if (m->state != MBX_FORWARD) {
		if (!FWDreverse)
			goto notallowed;
		m->state = MBX_REVFWD;
		if ((m->sid & MBX_SID) && m->mysize)
			smtptick (NULL);	/* wake SMTP to send that mail */
		m->mysize = 0;
	}
	if (m->fwdbbs || fwdinit (m, 1) != -1) {
		strncpy (oldarea, m->area, 64);
		sprintf (name, "%s/%s", Mailspool, m->name);
		(void) nntp_name_expansion (name);
		strcat (name, ".fwd");
		(void) strlwr (name);
		if ((fwd = fopen (name, UPDATE_TEXT)) == NULLFILE)
			return 0;	/* shouldn't happen except with reverse fwd */
		log (m->user, forwardingmailto, (m->state == MBX_REVFWD) ? "reverse " : "", m->name);
		thesize = (long) filelength (fileno (fwd));	/* so we know if any new */

		a = m->fwdbbs->areas;
		if (m->fwdbbs->noreverseincoming)
			m->usecolor = 0;
		if (m->state != MBX_FORWARD)
			if (checksubchannel (m, 1))
				err = 1;

		while (!err) {
			if (cutofffwding (m))
				break;
			if (m->privs & EXCLUDED_CMD)
				break;
			newsize = (long) filelength (fileno (fwd));
			if (thesize != newsize) {
				/* if new mail came in to forward, start back
				   up at the top of the areas to forward.
				   This allows you to push personal traffic
				   at highest priority */
				thesize = newsize;
				a = m->fwdbbs->areas;
			}
			if (a == NULLAREALIST)
				break;

			cp = strdup ((a->forceaddr) ? a->forceaddr : "");
			area = strdup (a->name);
			a = a->next;
			err = fwdthisarea (m, fwd, area, cp);
			if (MBXMaintMode && MBXMaint)
				break;
			free (cp);
			free (area);
		}

		if (*oldarea != '\0')
			changearea (m, oldarea, (int) 1);
		fwdlockit (m->name);
		theend = (long) filelength (fileno (fwd));
		if (!err && thesize == theend) {
			rewind (fwd);
			while (newsize = ftell (fwd), fgets (m->line, MBXLINE, fwd) != NULLCHAR) {
				kwait (NULL);
				if (*m->line == '=') {
					mark_forwarded (fwd, newsize, '!');
					err = 1;
				} else if (*m->line == '!') {
					mark_forwarded (fwd, newsize, ' ');
					err = 1;
				} else if (*m->line != '*' && *m->line != '-') {	/* if not already done */
					err = 1;
#if 0
					break;
#endif
				}
			}
			(void) fclose (fwd);
			if (!err)
				(void) remove (name);
		} else
			(void) fclose (fwd);
		fwdunlockit (m->name);
	}
	if (m->state != MBX_FORWARD)
		releasesubchannel (m);
	if (m->state == MBX_FORWARD)
		return err;
notallowed:
	/* This section marks the last fwd session time */
	if ((err = indexFwdBbs (fwd_bbsname (m))) != NUMFWDBBS) {
		MyFwds[err].laston = time (NULL);
		MyFwds[err].lastactivity = time (NULL);
	}
	tputs ("*** Done\n");
	tflush ();
	if (m->sid & MBX_RLI_SID)	/* disconnect if it is a W0RLI bbs */
		return domboxbye (0, NULL, m);
	return 0;
}



void
releasesubchannel (struct mbx *m)
{
	if (m->subchannel != NOSUBCHANNEL) {
		if (subchannels[m->subchannel].used)
			subchannels[m->subchannel].used--;
		m->subchannel = NOSUBCHANNEL;
	}
}



/* Check to see if there is room in the subchannel tables for this BBS,
 * *IF* they are suppose to use a subchannel. This routine also is used
 * to assign the subchannel, if desired. Returns 0 if subchannel is available,
 * -1 if it is NOT available.
 */
int
checksubchannel (struct mbx *m, int assignit)
{
int i;

	i = m->fwdbbs->subchannel;

	/* return OK if no subchannel is to be used */
	if (i == NOSUBCHANNEL)
		return 0;

	/* return OK if subchannel already assigned to this BBS */
	if (i == m->subchannel)
		return 0;

	/* Now check if there is room on this subchannel */
	if (i > NUMMBX || subchannels[i].used >= (int) subchannels[i].limit)
		return -1;	/* nope */

	/* Now we assign the subchannel slot to this BBS, if desired */
	if (assignit) {
		subchannels[i].used++;
		m->subchannel = i;
	}
	return 0;
}



static int
uselessconnect (struct mbx *m, char *filename)
{
int retval = -1;
FILE *fp;
char buf[255], *cp;
int foundone = 0, i;
long bid;
struct let *cmsg;
int anyvalid = 0;

	if (!access (filename, 0)) {
		if ((fp = fopen (filename, "r")) != NULLFILE)	{
			while (fgets (buf, 255, fp)) {
				/* if forwarded, skip it (no valid message, here) */
				if (*buf == '*')
					continue;

				/* if passed to an alt, skip it (valid message, though) */
				if (*buf == '-')	{
					anyvalid = 1;
					continue;
				}

				if ((cp = strchr (&buf[1], ' ')) == NULLCHAR)
					continue;	/* syntax error */
				*cp++ = 0;
				/* get internal id number of message */
				bid = atol (cp);
				changearea (m, &buf[1], (int) 0);
				for (cmsg = &m->mbox[1], i = 1; i <= m->nmsgs; i++, cmsg++)
					/* find the message we're supposed to forward. */
					if (bid == cmsg->bid)	{
						if (!(cmsg->status & (BM_DELETE | BM_ONHOLD))) {
							/* this is the message... set the flag and break. */
							foundone = 1;
							break;
						} else if (!(cmsg->status & BM_DELETE))	{
							/* not deleted, just on hold (valid message) */
							anyvalid = 1;
						}
					}
				if (foundone) {
					retval = 0;
					break;
				}
			}
			(void) fclose (fp);
		}
		if (!foundone)	{
			if (Mtrace)
				tcmdprintf ("fwd: no available traffic found - skipping useless connect to %s\n", m->fwdbbs->name);
			if (!anyvalid)	{
				/* if all messages are fwded or deleted, then remove the file */
				(void) remove (filename);
				if (Mtrace)
					tcmdprintf ("fwd: no remaining traffic found - removing forward file for %s\n", m->fwdbbs->name);
			}
		}
	}
	return retval;
}



/* Read the forward file for a record for the connected BBS. If found,
 * return 0 if this is the right time to forward, m->tfile is left pointing
 * at the first message area to be forwarded.
 * returns -1, also, if nothing queued for forwarding.
 */
int
fwdinit (struct mbx *m, int try)
{
int retval = -1;
char name[256];

	fwdfree (&m->fwdbbs);
	m->fwdbbs = fwdread (m->name, try);
	if (m->fwdbbs != NULLFWDBBS && m->fwdbbs->conn) {
		sprintf (name, "%s/%s", Mailspool, m->fwdbbs->name);
		(void) nntp_name_expansion (name);
		strcat (name, ".fwd");
		(void) strlwr (name);
		if (m->special || m->fwdbbs->poll)
			retval = 0;
		else
			retval = uselessconnect (m, name);
	}
	if (!retval)
		retval = checksubchannel (m, 0);
	return retval;
}



/* Read the forward file for a record for the connected BBS. If found,
 * determine if this is the right time to forward, and return the command
 * line to establish a forwarding connection. m->tfile is left pointing
 * at the first message area to be forwarded.
 */
static int
fwdanybbs (struct mbx *m, int *poll, int *theindex)
{
int k;
int done = 0;
int retval = 0;

	*poll = 0;		/* Default to no polling */

	fwdfree (&m->fwdbbs);

	do {
		m->fwdbbs = fwdread (NULLCHAR, *theindex++);
		if (m->fwdbbs == NULLFWDBBS) {
			done = 1;
			continue;
		}
		if (!m->fwdbbs->conn) {	/* bad time - no connect method */
			if (Mtrace)
				tcmdprintf ("fwd: skipping '%s' - no connect method\n", m->fwdbbs->name);
			/* This section keeps a inactive BBS from blocking others in a subchannel */
			k = indexFwdBbs (m->fwdbbs->name);
			if (k != NUMFWDBBS)
				MyFwds[k].processed = 1;
			fwdfree (&m->fwdbbs);
			continue;
		}
		strncpy (m->name, m->fwdbbs->name, 20);
		*poll = m->fwdbbs->poll;
		if (m->special)
			*poll = 1;
		retval = 1;
		done = 1;

	} while (!done);
	return retval;
}



int
dombtimer (int argc, char *argv[], void *p OPTIONAL)
{
	if (argc < 2) {
		tprintf (forwardingtimer, read_timer (&fwdtimer) / 1000L, dur_timer (&fwdtimer) / 1000L);
		return 0;
	}
	stop_timer (&fwdtimer);	/* just in case */
	fwdtimer.func = (void (*)(void *)) fwdtick;	/* what to call on timeout */
	fwdtimer.arg = NULL;	/* dummy value */
	set_timer (&fwdtimer, atol (argv[1]) * 1000L);	/* set timer duration */
	start_detached_timer (&fwdtimer);/* fire it up */
	return 0;
}



int
dombkick (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
	fwdtick (NULL);
	return 0;
}



/* MDMII: fwdproc is the old fwdtick.   But, since it can call kpause, which is
 * very very bad for timer functions :-( this has been converted to a server.
 */
static void
fwdtick (void *v OPTIONAL)
{
	start_detached_timer (&fwdtimer);/* and restart the timer */
	checkforALTs ();
	(void) forwardreset (0, 0, 0);
	if (FWDmode)
		if (newproc ("forward daemon", 2048, fwdproc, 0, NULL, NULL, 0) == NULLPROC)
			log (-1, nostart);
}



static void
checkoneALT (char *name)
{
long bid, pos = 0;
struct fwdbbs *f;
struct arealist *a;
struct altlist *alt;
char buf[256], *cp;
FILE *fp;
time_t now, then;
long size;
int nummsgs;

	(void) time (&now);
	f = fwdread (name, 1);
	if (f == NULLFWDBBS)	/* shouldn't happen */
		return;

	/* look at each area for this bbs */
	for (a = f->areas; a; a = a->next) {

		/* if there are no alternates for this area, skip it */
		if (!a->alternates)
			continue;

		/* now check to see if the *.fwd file exists */
		sprintf (buf, "%s/%s", Mailspool, f->name);
		(void) nntp_name_expansion (buf);
		strcat (buf, ".fwd");
		(void) strlwr (buf);
		if ((fp = fopen (buf, UPDATE_TEXT)) == NULLFILE)
			continue;	/* nope, skip it */

		nummsgs = 0;
		/* check every message not already forwarded or sent to an alt */
		while (pos = ftell (fp), fgets (buf, 255, fp)) {
			/* if forwarded or passed to an alt, skip it */
			if (*buf == '*' || *buf == '-')
				continue;
			/* if not this area, skip it */
			if (strnicmp (&buf[1], a->name, strlen (a->name))) {
				nummsgs++;
				continue;
			}
			if ((cp = strchr (&buf[1], ' ')) == NULLCHAR)
				continue;	/* syntax error */
			/* get internal id number of message */
			bid = atol (++cp);
			if ((cp = strchr (cp, ' ')) == NULLCHAR)
				continue;	/* syntax error */
			/* get original timestamp */
			then = atol (++cp);
			if ((cp = strchr (cp, ' ')) == NULLCHAR)
				continue;	/* syntax error */
			/* get original timestamp */
			size = atol (++cp);
			for (alt = a->alternates; alt; alt = alt->next) {
				/* time to send to this alt? */
				if ((then + (alt->minutes * 60)) > now) {
					nummsgs++;
					continue;	/* nope */
				}
				/* send it to the alt bbs's .fwd file */
				updateFwd (alt->name, a->name, bid, size);
				mark_forwarded (fp, pos, '-');
				if (Mtrace)
					tcmdprintf (queueing, bid, f->name, alt->name);
				log (-1, queueing, bid, f->name, alt->name);
			}
		}
		(void) fclose (fp);
		if (!nummsgs) {
			sprintf (buf, "%s/%s", Mailspool, f->name);
			(void) nntp_name_expansion (buf);
			strcat (buf, ".fwd");
			(void) strlwr (buf);
			(void) remove (buf);
		}
	}
	fwdfree (&f);
}



void
checkforALTs (void)
{
int k;

	ReadFwdBbs ();		/* just in case */

	/* for each BBS in the forward.bbs file */
	for (k = 0; k < Numfwds; k++)
		checkoneALT (MyFwds[k].name);

	freeareas ();
}



int
forwardreset (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
int k;

	for (k = 0; k < NUMFWDBBS; k++)
		MyFwds[k].processed = 0;
	return 0;
}



/* called when the forward timer expires or explicitly by dombkick() */
void
fwdproc (int nerf, void *v1, void *v2 OPTIONAL)
{
struct mbx *m;
int poll, k;
char name[256];
time_t t;
int doneit = 0;
char *bbsname = NULLCHAR;
int bbsindex = 0;
int skip;

	if (MBXMaintMode && MBXMaint) {
		if (Mtrace)
			tcmdprintf (delayedmaintenance);
		return;
	}
	if (v1)
		bbsname = strdup (v1);
	if (Mtrace)
		tcmdprintf (started);
	if ((m = newmbx (1)) == NULLMBX) {
		if (Mtrace)
			tcmdprintf (unabletostart);
		return;
	}
	(void) time (&t);
	m->special = (char) nerf;	/* non-zero, if forced or exported connect */
	m->logontime = (long) t;
	m->user = Curproc->output;
	m->name[0] = 0;
	m->state = MBX_TRYING;
	lastSessionSkipped = 0;
	while (fwdanybbs (m, &poll, &bbsindex)) {
		bbsindex++;

		if (Mtrace)
			tcmdprintf (examining, m->name);
		kwait (NULL);
		if (isconnbbs (m)) {
			/* already connected to this BBS, skip it */
			if (Mtrace)
				tcmdprintf (alreadyconnected, m->name);
			goto skipped;
		}
		kwait (NULL);
		if (bbsname && stricmp (m->name, bbsname))
			goto skipped;

		/* If we poll, there is no need to check message area, since this
		 * is also done later. It will speed things up here - WG7J
		 */
		if (!poll) {	/* don't need if polling */
			sprintf (name, "%s/%s.fwd", Mailspool, m->name);
			(void) strlwr (name);
			if (Mtrace)
				tcmdprintf (checkingforfile, name);
		}
		skip = 0;
		k = indexFwdBbs (m->name);
#if 1
		if (!m->special && m->fwdbbs->minidle && k != NUMFWDBBS && MyFwds[k].lastactivity && (MyFwds[k].lastactivity + (time_t) m->fwdbbs->minidle) > t)
			skip = 1;
#endif
		/* This section keeps a dead BBS from blocking other in a subchannel */
		if (poll || !uselessconnect (m, name)) {
			if (checksubchannel (m, 0)) {	/* maxed out */
				lastSessionSkipped = 1;
				goto skipped;
			}
			if (k != NUMFWDBBS) {
				if (MyFwds[k].processed) {
#if 0
					int chk;

					for (chk = 0; chk < NUMFWDBBS; chk++) {
						if (MyFwds[k].subchannel == MyFwds[chk].subchannel && MyFwds[chk].processed == 0)
#endif
							goto skipped;
#if 0
					}
#endif
				} else
					MyFwds[k].processed = 1;
			}
			if (!strnicmp (m->fwdbbs->conn, "incoming", strlen (m->fwdbbs->conn))) {
				/* it is an incoming PBBS, only */
				if (Mtrace)
					tcmdprintf ("fwd: skipping incoming-only: %s\n", m->name);
				goto skipped;
			}
			if (skip || checksubchannel (m, 1))
				goto skipped;

			if (Mtrace)
				tcmdprintf ("fwd: to %s\n", m->name);

			sprintf (m->line, "PBBS forwarding: %s", m->name);
			(void) newproc (m->line, 3072, startfwd, (int) m->subchannel | (m->special << 8), (void *) 0, (void *) strdup (m->name), 0); /*lint !e701 */
			m->subchannel = NOSUBCHANNEL;
			kwait (NULL);
		} else {
			/* not polling and we have nothing, mark us as done */
			if (k != NUMFWDBBS)
				MyFwds[k].processed = 1;
		}
		if (nerf) {
			doneit = 1;
			break;
		}
	      skipped:if (nerf && doneit)
			break;
	}
	m->state = MBX_FORWARD;
	if (lastSessionSkipped == 0)
		(void) forwardreset (0, NULLCHARP, 0);
	if (bbsname)
		free (bbsname);
	exitbbs (m);
}



/* returns 1 if m->name matches the name of another connected mailbox. */
static int
isconnbbs (struct mbx *m)
{
int i;

	for (i = 0; i < NUMMBX; ++i)
		if (Mbox[i] != NULLMBX && Mbox[i] != m &&
		    (stricmp (m->name, Mbox[i]->name) == 0) &&
		    (Mbox[i]->sid & MBX_SID))
			return 1;
	return 0;
}



/* code to support setting the time of TNC PMS's that request it */
static int
fwd_clockset (struct mbx *m)
{
time_t now;
struct tm *t;

	if ((m->sid & MBX_CLOCK) && (!m->fwdbbs->noclockset)) {
		/* send the clock set command to the TNC */
		now = time ((time_t *) 0);
		now += (((long) m->fwdbbs->clockoffset) * 3600L);
		t = localtime (&now);
	        usprintf (m->user, "C %02d%02d%02d %02d%02d\n", (t->tm_year % 100),
					  t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min);
		usflush (m->user);
		for (;;) {
			if (recvline (m->user, (unsigned char *) m->line, MBXLINE) == -1)
				return -1;
			if (ISPROMPT (m->line))
				break;
		}
	}
	return 0;
}



/* possible commands on the command line in the forwarding file */
static struct cmds cfwdcmds[] =
{
#ifdef AX25
	{ "ax25",	openconn,	0, 0, NULLCHAR },
	{ "connect",	openconn,	0, 0, NULLCHAR },
#endif
#ifdef BBSEXPORT
	{ "export",	openconn,	0, 0, NULLCHAR },
#endif
	{ "fbbtelnet",	openconn,	0, 0, NULLCHAR },
	{ "incoming",	openconn,	0, 0, NULLCHAR },
#ifdef NETROM
	{ "netrom",	openconn,	0, 0, NULLCHAR },
#endif
	{ "tcp",	openconn,	0, 0, NULLCHAR },
	{ "telnet",	openconn,	0, 0, NULLCHAR },
	{ NULLCHAR,	NULL,		0, 0, NULLCHAR }
};



static void
fwdcleanup (struct mbx *m, const char *string)
{
int k;
char *thisname;

	thisname = fwd_bbsname (m);
	if (Mtrace && string)
		tcmdprintf (string, thisname);
	log (-1, (string) ? string : forwardingcomplete, thisname);

	/* This section marks the last fwd session time */
	k = indexFwdBbs (thisname);
	if (k != NUMFWDBBS) {
		if (m->sid & MBX_SENTSID || m->fwdbbs->alwaysupdate)	{
			MyFwds[k].laston = time (NULL);
			smtptick(NULL);		/* kick the smtp server, just in case */
		}
		MyFwds[k].lastactivity = time (NULL);
	}
	releasesubchannel (m);
	exitbbs (m);
	if (lastSessionSkipped)
		fwdtick (NULL);
}




/* this function tells us whether the forwarding session has
   gone too long */
int
cutofffwding (struct mbx *m)
{
time_t now;

	/* if not initialized, or limittime disabled, return okay */
	if (!m || m->quickfile || !m->fwdbbs || !m->fwdbbs->limittime)
		return 0;

	/* if no starttime (incoming session), initialize it, and return okay */
	if (m->fwdbbs->starttime)	{
		(void) time (&m->fwdbbs->starttime);
		return 0;
	}

	/* else, get current time, and see if limittime reached */
	(void) time (&now);
	if ((now - m->fwdbbs->starttime) > m->fwdbbs->limittime)
		return 1;
	else
		return 0;
}



/* this function is called whenever the forwarding timer expires */
static void
startfwd (int a, void *v1 OPTIONAL, void *v2)
{
struct mbx *m;
int32 timeout;
int rval, retval;
time_t t;
int poll;
struct fscript *s;
int connectnum = 1;
int err;
char export[7];
#ifdef LOCK
int lockedstate;
#endif

	server_disconnect_io ();
	poll = a / 256;
	a %= 256;
	if ((m = newmbx (1)) == NULLMBX) {
		free ((char *) v2);
		if (a != NOSUBCHANNEL)
			subchannels[a].used--;
		return;
	}
	m->subchannel = a;
#ifdef STATS_USE
	STATS_adduse (0);
#endif
	(void) time (&t);
	m->special = (char) ((poll == 1) ? poll : 0);
	m->logontime = (long) t;
	strncpy (m->name, (char *) v2, 20);

	strcpy (export, "export");

	free ((char *) v2);
	m->state = MBX_TRYING;
	for (;;) {
		fwdfree (&m->fwdbbs);
		m->fwdbbs = fwdread (m->name, connectnum);
		if (m->fwdbbs->conn == NULLCHAR) {	/* shouldn't happen */
			fwdcleanup (m, "fwd: error in forward.bbs for %s\n");
			return;
		}
		if (poll == 1 && !stricmp (m->fwdbbs->conn, export))
			poll = 2;
		if (Mtrace)
			tcmdprintf ("fwd: Attempting connect #%d to %s: '%s'\n", connectnum, m->name, (poll == 2) ? export : m->fwdbbs->conn);

#ifdef LOCK
		lockedstate = Kblocked;
		Kblocked = 0;
#endif
		/* open the connection, m->user will be the new socket */
		retval = cmdparse (cfwdcmds, (poll == 2) ? export : m->fwdbbs->conn, (void *) m);
#ifdef LOCK
		Kblocked = lockedstate;
#endif
		if (retval != -1)
			break;

		if (connectnum++ == m->fwdbbs->maxtries) {
			checkoneALT (m->name);
			fwdcleanup (m, "fwd: unknown connect protocol or TRIES exceeded to %s\n");
			return;
		}
		if (Mtrace)
			tcmdprintf (connectionfailed, m->name, connectnum - 1);
	}
	m->state = MBX_FORWARD;
	if (m->user)
		(void) sockowner (m->user, Curproc);
	close_s (Curproc->output);
	close_s (Curproc->input);
	/* m->user will be closed automatically when this process exits */
	Curproc->output = Curproc->input = m->user;
	/* We'll do our own flushing right before we read input */
	kwait (NULL);
#ifdef BBSEXPORT
	if (m->user)
#endif
		(void) setflush (m->user, -1);

#if 0
	if (fwdinit (m, connectnum) == -1) {
		/* it is probably not the right time to forward anymore */
		fwdcleanup (m, NULLCHAR);
		return;
	}
#endif
#ifdef BBSEXPORT
	if (!m->user) {
		m->sid = (MBX_SID | MBX_MID | MBX_HIER_SID);
#if 0
		if (!m->special)
#endif
			(void) dorevfwd (0, NULL, (void *) m);
		(void) fclose (m->quickfile);
#if 1
		rmlock (EXPORTDir, m->name);
#endif
		fwdcleanup (m, NULLCHAR);
		close_s (Curproc->output);
		return;
	}
#endif

	/* read the connect script. Lines starting with a dot will be sent
	 * to the remote BBS.
	 */
	for (s = m->fwdbbs->script; s; s = s->next) {
		if (s->linetype == SCRIPT_SID) {
			strncpy (m->line, s->string, 20);
			(void) mbx_parse (m);	/* interpret it */
			/* now automatically send OUR SID */
#ifdef MBFWD
			mbx_SendSid (m);
#endif
			continue;
		}
		if (s->linetype == SCRIPT_SEND) {
			tprintf (s->string);
			tputc ('\n');
			if (Mtrace)
				tcmdprintf ("fwd: %s > %s\n", m->name, s->string);
		} else if (s->linetype == SCRIPT_WAIT) {
			char good[80], bad[80], *myptr;
			int checkbad = 0;

			bad[0] = 0;
			strncpy (good, s->string, 80);
			if ((myptr = strchr (good, '|')) != NULLCHAR) {
				/* negative search string found */
				*myptr++ = 0;
				strncpy (bad, myptr, 80);
				checkbad = 1;
			}
			timeout = s->timeout;
			if (timeout)	/* if a valid conversion */
				timeout *= 1000;	/* in ms ! */
			if (Mtrace)
				tcmdprintf ("fwd: %s, wait %d < %s\n", m->name, s->timeout, s->string);

			/* Now do the actual response interpretations */
			kalarm (timeout);
			for (;;) {

				rval = recvline (m->user, (unsigned char *) m->line, MBXLINE);
				if (Mtrace) {
					tcmdprintf ("fwd: %s, rx %d", m->name, rval);
					if (rval >= 0)
						tcmdprintf (", %s", m->line);
					else
						tcmdprintf ("\n");
				}
				/* Did we timeout, or connection disappear ? */
				if (rval < 0) {
					fwdcleanup (m, "fwd: %s, aborted!\n");
					return;
				}
				if (strstr (m->line, good))
					break;
				if (checkbad && strstr (m->line, bad)) {
					fwdcleanup (m, "fwd: %s, aborted!\n");
					return;
				}
			}
			kalarm (0L);
		} else		/* must be the end of the script */
			goto go_on;

		usflush (m->user);	/* send it, if any */
	}
	/* Now we've past all in-between stuff, go talk to the bbs ! */
go_on:
	usflush (m->user);
	if (Mtrace)
		tcmdprintf (scriptdone, m->name);

	/* read the initial output from the bbs, looking for the SID */
	for (;;) {
		timeout = 120 * 1000L;	/* wait up to 2 minutes for each response line */
		if (Mtrace)
			tcmdprintf (waitingfor, m->name, timeout / 1000, ">");
		kalarm (timeout);
		rval = recvline (m->user, (unsigned char *) m->line, MBXLINE);
		kalarm (0L);
		if (rval == -1) {
			fwdcleanup (m, NULLCHAR);
			return;
		}
		if (Mtrace)
			tcmdprintf ("fwd: %s < %s", m->name, m->line);
		if (ISPROMPT (m->line))
			break;
		if (*m->line == '[') {	/* parse the SID */
			rip (m->line);
			(void) mbx_parse (m);
			continue;
		}
	}

	/* Now sync the two ends as telnet password messes them up */
	if (socklen (m->user, 0))	/* discard any remaining input */
		(void) recv_mbuf (m->user, NULL, 0, NULLCHAR, 0);

	/* set the start time, for cutofffwding() */
	(void) time (&m->fwdbbs->starttime);

	/* send our SID if the peer announced its SID */
#ifdef FBBFWD
	if (Mfbb && (m->sid & MBX_FBBFWD)) {
		/* All we do is send a SID and start forwarding. */
		/* The remote box doesn't send any OK prompts.   */

		/* Send [xxxx] string. */
		mbx_SendSid (m);
		if (!(m->sid & MBX_FBBFWD))	/* since mbx_SendSid can change this */
			goto adjust;
		if (fwd_clockset (m) != -1)
			/* start the actual forwarding */
			(void) dofbbfwd (0, NULL, (void *) m);
		fwdcleanup (m, NULLCHAR);
		return;
	} else
#endif
	if (m->sid & MBX_SID) {
		mbx_SendSid (m);
#ifdef FBBFWD
adjust:
#endif
		if (fwd_clockset (m) == -1) {
			fwdcleanup (m, NULLCHAR);
			return;
		}
		usflush (m->user);
		for (;;) {
			if (recvline (m->user, (unsigned char *) m->line, MBXLINE) == -1) {
				fwdcleanup (m, NULLCHAR);
				return;
			}
			if (ISPROMPT (m->line))
				break;
		}
	} else	{
		/* if the sysop has told us that this is a dumb PMS, then
		   we will ignore the lack of a SID */
		if (!m->fwdbbs->dumbpms)	{
			/* if we get here and have NOT received a SID, we have a
			   screwed up forwarding script, or the remote has a SERIOUS
			   breach of the forwarding protocol. Since we do NOT know the
			   capabilities of the remote machine, we abort! */
			log (m->user, nosidfound, fwd_bbsname(m));
			log (m->user, nosidfound2);
			tcmdprintf (nosidfound, fwd_bbsname(m));
			tcmdprintf ("\n");
			tcmdprintf (nosidfound2);
			tcmdprintf ("\n");
			fwdcleanup (m, NULLCHAR);
			return;
		}
	}
		
	/* start the actual forwarding */
#ifdef FBBFWD
	if (Mfbb && (m->sid & MBX_FBBFWD)) {
		(void) dofbbfwd (0, NULL, (void *) m);
		fwdcleanup (m, NULLCHAR);
		return;
	} else
#endif
#ifdef XFWD
	if (MXfwd && (m->sid & MBX_XFWD)) {
		(void) doxfwd (0, NULL, (void *) m);
		fwdcleanup (m, NULLCHAR);
		return;
	} else
#endif
		m->usecolor = (char) FWDinreverse;	/* default to this, each entry can override */
	err = dorevfwd (0, NULL, (void *) m);
	/* if no incoming reverse, just disconnect, else */
	/* ask for reverse forwarding or just disconnect */
	if (err || m->usecolor == 0 || ((m->sid & MBX_SID) && tputs ("F>\n") == -1) ||
	    (m->sid & MBX_SID) == 0) {
		fwdcleanup (m, NULLCHAR);
		close_s (Curproc->output);
		return;
	}
	m->usecolor = 0;
	usflush (m->user);
	/* parse the commands that are are received during reverse
	 * forwarding.
	 */
	while (recvline (m->user, (unsigned char *) m->line, MBXLINE) > 0) {
		if (cutofffwding (m))
			break;
		if (m->privs & EXCLUDED_CMD)
			break;
		rip (m->line);
		if ((rval = mbx_parse (m)) < 0)
			/* -2 == "*** Done" rec'd, -1 => cmd not in Mbcmds, or other err) */
			break;
		if (rval && BBSdump)	/* we dump for all unknowns! */
			break;
		if (m->privs & EXCLUDED_CMD)
			break;
		if (MBXMaintMode && MBXMaint)
			break;
		tputs ("F>\n");
		usflush (m->user);
	}
	(void) domboxbye (0, NULL, m);

	if ((m->sid & MBX_SID) && m->mysize)
		smtptick (NULL);/* wake SMTP to send that mail */
	fwdcleanup (m, NULLCHAR);
	usflush (Curproc->output);
	kpause (500L);
	close_s (Curproc->output);
}



/* open a network connection based upon information in the cc line.
 * m->user is set to the socket number.
 */
static int
openconn (int argc, char *argv[], void *p)
{
struct mbx *m;
char sock[MAXSOCKSIZE];
union sp sp;
int len;
#ifdef NETROM
char alias[AXBUF];
struct nrroute_tab *rp;
#endif
#ifdef BBSEXPORT
char namebuf[512];
#endif

	m = (struct mbx *) p;
	sp.p = sock;
#ifdef BBSEXPORT
	if (argv[0][0] != 'e' && argc < 2)
#else
	if (argc < 2)
#endif
		return -1;
	switch (*argv[0]) {
		case 'f':
			m->fwdbbs->limittype &= ~FWDTYPE_XFWD;
			/* fall through */
		case 't':
			sp.in->sin_family = AF_INET;
			{
				if ((sp.in->sin_addr.s_addr = resolve (argv[1])) == 0)
					return -1;
				/* get the optional port number */
				if (argc > 2)
					sp.in->sin_port = (int16) atoip (argv[2]);
				else
					sp.in->sin_port = IPPORT_TELNET;
			}
			if ((m->user = socket (AF_INET, SOCK_STREAM, 0)) == -1)
				return -1;
			len = sizeof (*sp.in);
			m->family = AF_INET;	/*So the user list will be correct! - WG7J */
			break;
#ifdef AX25
		case 'a':
		case 'c':	/* allow 'c' for 'connect' as well */
			if (argc < 3)
				return -1;
			sp.ax->sax_family = AF_AX25;
			if (if_lookup (argv[1]) == NULLIF) {
				if (Mtrace)
					tcmdprintf (badax25iface, argv[1], m->name);
				log (-1, badax25iface, argv[1], m->name);
				return -1;
			}
			if ((m->user = socket (AF_AX25, SOCK_STREAM, 0)) == -1)
				return -1;
			if (*FWDCall) {
				memcpy (sp.ax->ax25_addr, FWDCall, AXALEN);
				(void) bind (m->user, (char *) sp.ax, sizeof (struct sockaddr_ax));
			}
			strncpy (sp.ax->iface, argv[1], ILEN - 1);	/* the interface name */
			(void) setcall (sp.ax->ax25_addr, argv[2]);	/* the remote callsign */

			/* no digipeaters for now, use the "ax25 route add" command */
			/* this code attempts to correct this longstanding limitation */
			if (argc > 3) {
				int didrose = 0, i;
				char tmp[AXBUF];

				if (!strcmp (argv[3], "@")) {
					didrose = 1;
					argv[3] = strdup (pax25 (tmp, AXRosecall));
				}
				i = connect_filt (argc, argv, sp.ax->ax25_addr, if_lookup (argv[1]), AX_SETUP);
				if (didrose)
					free (argv[3]);
				if (i == 0)
					return -1;
			}
			len = sizeof (*sp.ax);
			m->family = AF_AX25;	/*So the user list will be correct! - WG7J */
			break;
#endif /* AX25 */
#ifdef NETROM
		case 'n':
			/* See if the requested destination could be an alias, and
			 * use it if it is.  Otherwise assume it is an AX.25
			 * address.
			 */
			(void) putalias (alias, argv[1], 0);
			(void) strupr (argv[1]);
			if ((rp = find_nrboth (alias, argv[1])) == NULLNRRTAB) {
				if (Mtrace)
					tcmdprintf (Netromunavailable, argv[1]);
				return -1;
			}
			/* Setup the local side of the connection */
			sp.nr->nr_family = AF_NETROM;
			len = sizeof (*sp.nr);
			if ((m->user = socket (AF_NETROM, SOCK_SEQPACKET, 0)) == -1) {
				if (Mtrace)
					tcmdprintf (Netromsocket, argv[1]);

				return -1;
			}
			memcpy (sp.nr->nr_addr.user, Nr4user, AXALEN);
			memcpy (sp.nr->nr_addr.node, Nr_iface->hwaddr, AXALEN);
			(void) bind (m->user, sp.p, len);

			/* Now the remote side */
			memcpy (sp.nr->nr_addr.node, rp->call, AXALEN);
			/* The user callsign of the remote station is never
			 * used by NET/ROM, but it is needed for the psocket() call.
			 */
			memcpy (sp.nr->nr_addr.user, rp->call, AXALEN);

			m->family = AF_NETROM;	/*So the user list will be correct! - WG7J */
			break;
#endif /* NETROM */
#ifdef BBSEXPORT
		case 'e':
			/* open current export file */
#if 1
		    if (mlock (EXPORTDir, m->name))
			    return -1;
#endif
			sprintf (namebuf, "%s/%s.exp", EXPORTDir, m->name);
			m->quickfile = fopen (namebuf, APPEND_TEXT);
			if (m->quickfile) {
				m->user = 0;
				m->family = AF_LOCAL;
				return 0;
			}	/* else, fall through */
#endif
		case 'i':	/* incoming only, no outbound */
		default:
			return -1;
	}
	(void) sockmode (m->user, SOCK_ASCII);
	if (*argv[0] == 'f')
		(void) seteol (m->user, "\r\n");

	if (connect (m->user, sp.p, len) == -1) {
		log (m->user, forwardfailed, sockerr (m->user), errno);
		close_s (m->user);
		return -1;
	}
	return m->user;
}



void
forwardingSummary ()
{
int k, first = 1, i;
char curstate, curtype;
register FILE *fp;
char buf[100], *cp;
int totbul = 0, totper = 0, bul, per;
long size, totsize = 0;

	ReadFwdBbs ();		/* just in case */
	for (k = 0; k < Numfwds; k++) {
		sprintf (buf, "%s/%s.fwd", Mailspool, MyFwds[k].name);
		(void) strlwr (buf);
		per = bul = 0;
		size = 0;
		if ((fp = fopen (buf, READ_TEXT)) != NULLFILE) {
			while (fgets (buf, sizeof (buf), fp) != NULLCHAR)
				if (*buf != '*' && *buf != '-') {
					cp = strchr (&buf[1], ' ');
					if (cp) {
						*cp++ = 0;
						if (isarea (&buf[1]))
							bul++;
						else
							per++;
						cp = strrchr (cp, ' ');
						if (cp)
							size += atol (++cp);
					}
				}
			(void) fclose (fp);
		}
		totsize += size;
		if (size)
			size = ((size + 513) / 1024);
		if (first) {
			tputc ('\n');
			first = 0;
		}
		curstate = ':';
		curtype = ' ';
		for (i = 0; i < NUMMBX; ++i) {
			if (Mbox[i] == NULLMBX)
				continue;
			if (!stricmp (Mbox[i]->name, MyFwds[k].name) && Mbox[i]->state >= MBX_SUBJ && Mbox[i]->state <= MBX_FORWARD) {
				curstate = '*';
#ifdef XFWD
				if (MXfwd && Mbox[i]->sid & MBX_XFWD)
					curtype = 'X';
#endif
#ifdef FBBFWD
				if (Mfbb && Mbox[i]->sid & MBX_FBBFWD)
					curtype = 'F';
#endif
				break;
			}
		}

		tprintf ("Queued for forwarding to %-10.10s%c%c Bulletins/Personal (%5d/%-5d) %-ldK\n", MyFwds[k].name, curstate, curtype, bul, per, size);
		totbul += bul;
		totper += per;
	}
	if (k) {
		if (totsize)
			totsize = ((totsize + 513) / 1024);
		for (k = 0; k < 78; k++)
			tputc ('-');
		tprintf ("\nTotal messages to forward          :  Bulletins/Personal (%5d/%-5d) %-ldK\n\n", totbul, totper, totsize);
	} else
		tputs ("You have no BBS's in your 'forward.bbs' file!\n");
}



int
AREAlookup (char *area, int theindex)
{
int retval = 0;
struct fwdbbs *f = NULLFWDBBS;
struct arealist *a;
int cur = 0;

	for (cur = 0; cur <= theindex; cur++) {
		f = fwdread (NULLCHAR, cur);
		if (f == NULLFWDBBS)
			return retval;
		if (cur != theindex)
			fwdfree (&f);
	}
	if (f) {
		a = f->areas;
		while (a) {
			if (!stricmp (a->name, area)) {
				retval = (!a->isALT);
				break;
			}
			a = a->next;
		}
		fwdfree (&f);
	}
	return retval;
}

#ifdef UKIP
void
makeTlines (struct mbx *m, int msgn)
{
fpos_t filepos;
char buf [LINELEN], Tnewsgpline [LINELEN], Tmsgidline [LINELEN];
char Tfromline [LINELEN];
int x, foundt = 0;
	
	/* Save the 'input' file position */
	fgetpos (m->mfile, &filepos);
	
	Tnewsgpline [0] = '\0';
	Tmsgidline  [0] = '\0';
	Tfromline   [0] = '\0';
	
	fseek (m->mfile, m->mbox[msgn].start, 0); /* Rewind to the message start */
	
	/* Try and recover any original 'T:' lines */
	(void) fsetpos (m->mfile, &filepos);
	if (look_for_t_line (buf, sizeof (buf), m->mfile, Hdrs[NEWSGROUPS]) == 0) {
		sprintf (Tnewsgpline, "T:%s%s", Hdrs[NEWSGROUPS], buf + 14);
		foundt = 1;
	}
	(void) fsetpos (m->mfile, &filepos);
	if (look_for_t_line (buf, sizeof (buf), m->mfile, Hdrs[MSGID]) == 0) {
		sprintf (Tmsgidline, "T:%s%s", Hdrs[MSGID], buf + 14);
		foundt = 1;
	}
	(void) fsetpos (m->mfile, &filepos);
	if (look_for_t_line (buf, sizeof (buf), m->mfile, Hdrs[FROM]) == 0) {
		sprintf (Tfromline, "T:%s%s", Hdrs[FROM], buf + 8);
		foundt = 1;
	}
	
   /* If there were no T: lines in the original - make our own */
	
	if (!foundt) {
		/* reset the file position to the top of the message */
		fseek (m->mfile, m->mbox[msgn].start, 0);
		if (Mtrace)
			tcmdprintf ("FWD: Generating T: Lines from Headers\n");
	
		for (;;) {
			/* read a line */
			if (fgets (buf, sizeof (buf), m->mfile) == NULLCHAR)
				break;
			if (*buf == '\n')	/* last header line */
				break;
			
			kwait (NULL);
			switch (htype (buf)) {
				case XNNTPNEWSGROUPS:
				    trimrightCR (buf);
				    sprintf (Tnewsgpline, "T:%s", buf + 7);
				    break;
				case MSGID:
				    trimrightCR (buf);
					sprintf(Tmsgidline, "T:%s", buf);
				    break;
				case FROM:
				    trimrightCR (buf);
					sprintf(Tfromline, "T:%s", buf);
				    break;

				default:
			}
		}
	} /* foundt */
	
	else if (Mtrace)
		tcmdprintf ("FWD: Regenerating T: lines from those already found\n");
#if 0	
	/* Check we haven't overrun into the next message,
	 * then write the T: lines to the output */
	
	if ((ftell (m->mfile)) > (m->mbox[msgn + 1].start)) { 
		if (Mtrace)
			tcmdprintf ("FWD: T: Line generator overshot to next message\n");
		x = fsetpos (m->mfile, &filepos); /* Reset the file pointer */
		return;
	}
#endif	
#ifdef BBSEXPORT
	if (m->quickfile) {
		if (*Tmsgidline != '\0')
			sendwithcorrectNL (m, Tmsgidline);
		if (*Tnewsgpline != '\0')
			sendwithcorrectNL (m, Tnewsgpline);
		if (*Tfromline != '\0')
			sendwithcorrectNL (m, Tfromline);

	}
				else
#endif
		if (*Tmsgidline != '\0')
			usputs (m->user, Tmsgidline);
		if (*Tnewsgpline != '\0')
			usputs (m->user, Tnewsgpline);
		if (*Tfromline != '\0')
			usputs (m->user, Tfromline);
	
	x = fsetpos (m->mfile, &filepos); /* Reset the file pointer to where it was */
	return;
}
#endif

#endif /*MBFWD*/

void
fwdlockit (char *name)
{
	while (mlock (Mailspool, name))
		kpause (1000L);		/* Wait one second and try again */
}

void
fwdunlockit (char *name)
{
	rmlock (Mailspool, name);
}

