/* NOTE: because of size, the previous 'mailbox.c' has been
 * split in 3 parts:
 * mboxcmd.c, containing the 'mbox' subcommands, and
 * mailbox.c, containing some user mailbox commands, and
 * mailbox2.c, containing the remaining user commands.
 * 921125 - WG7J
 */
/* There are only two functions in this mailbox code that depend on the
 * underlying protocol, namely mbx_getname() and dochat(). All the other
 * functions can hopefully be used without modification on other stream
 * oriented protocols than AX.25 or NET/ROM.
 *
 * SM0RGV 890506, most work done previously by W9NK
 *
 *** Changed 900114 by KA9Q to use newline mapping features in stream socket
 *	interface code; everything here uses C eol convention (\n)
 *
 *	Numerous new commands and other changes by SM0RGV, 900120
 *
 * Gateway function now support outgoing connects with the user's call
 * with inverted ssid. Users can connect to system alias as well...
 * See also several mods in socket.c,ax25.c and others
 * 11/15/91, WG7J/PA3DIS
 *
 * Userlogging, RM,VM and KM commands, and R:-line interpretation
 * added 920307 and later, Johan. K. Reinalda, WG7J/PA3DIS
 *
 * Inactivity timeout-disconnect added 920325 and later - WG7J
 *
 * Removed mbox overhead from calling Convers directly from ax25 - KO4KS
 * Several other additions - KO4KS
 */
#include <stdio.h>
#include <time.h>
#ifdef MSDOS
#include <io.h>
#endif
#include <ctype.h>
#ifdef MSDOS
#include <alloc.h>
#endif
#include <stdlib.h>
#include <string.h>
#ifdef  UNIX
#include <sys/types.h>
#include <sys/stat.h>
#endif
#ifdef MSDOS
#include <dir.h>
#include <dos.h>
#endif
#include "global.h"
#include "config.h"
#include "timer.h"
#include "proc.h"
#include "socket.h"
#include "usock.h"
#include "session.h"
#include "smtp.h"
#include "dirutil.h"
#include "telnet.h"
#include "ftp.h"
#include "ftpserv.h"
#include "commands.h"
#include "netuser.h"
#include "files.h"
#include "bm.h"
#include "pktdrvr.h"
#include "ax25.h"
#include "mailbox.h"
#include "ax25mail.h"
#include "nr4mail.h"
#include "mailfor.h"
#include "help.h"
#include "color.h"
#ifdef DELEGATE
#include "delegate.h"
#endif

#ifdef MAILBOX

/* By setting the fp to NULL, we can check in exitbbs()
 * wether a tempfile has been closed or not - WG7J
 */
#define MYFCLOSE(x) { fclose(x); x = (FILE *) 0; }

/*
#define MBDEBUG
*/

#ifdef FBBFWD
extern int Mfbb;
extern char MboxIdFBB[], MboxIdFwdFBB[];
extern int dofbbfwd __ARGS((int argc,char *argv[],void *p));
#endif
extern char AXRosecall[AXALEN];
extern char *Mbhaddress;
extern time_t StartTime;
extern char Myalias[];
extern int Mbfullsvc;
extern char stars[];
extern int32 mbxMaxTimer;
#ifdef TIPMAIL
extern long Mbtipperms;
#endif
#ifdef WPAGES
extern int MbWpages;
#endif
extern int Mbconverse;
extern int FWDlzw;
extern int MbLogging;
extern int Smtpheaders;

struct mbx *Mbox[NUMMBX];
int BbsUsers = 0;
int Totallogins, Conflogins, Tutorlogins[3], BBSlogins;
extern char *MMotd;
extern char *MExit;
extern char *Mtmsg;
/* extern unsigned Maxlet; */
extern int BBSdump;
extern short SecureTelnet;

int MbSent = 0;
int MbRead = 0;
int MbRecvd = 0;
#ifdef MBFWD
int MbForwarded = 0;
#endif
static long lastsentid = 0;

extern char Noperm[];
extern char Nosock[];
extern char MboxId[], MboxIdFwd[];
extern char *ANSIArea, *ANSILogin;

static char DFAR Loginbanner[] = "\nKA9Q NOS - %s (%s)\n\n";
static char DFAR RLoginbanner[] = "\nRemote Login at %s - %s\n\n";

char DFAR Howtoend[] = "End with /EX or ^Z in first column (^A aborts):\n";
static char DFAR CcLine[] = "Cc: ";
static char DFAR Mbwelcome[] = "\nWelcome %s, ";
static char DFAR Mbbanner[] = "to the %s TCP/IP Mailbox (%s)\n";
static char DFAR Mbwarning[] = "Third Party mail is not permitted.\n";
char DFAR CurUsers[] = "There are currently %d users on the BBS\n";
char DFAR Only[] = "You are the only user currently on the BBS\n";
static char DFAR MessageData[] = "%4d message%s - %4d new.\n";
static char DFAR SMessageData[] = "%4d message%s - %4d new. (%4d on hold)\n";
char DFAR MsgAborted[] = "*** Message aborted\n";
static char DFAR sendthemail[] = "Send this message (N=no)?";

static char DFAR Mbmenu[] = "Current msg# %-d of %-d.\n?,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z ";

extern char Mbnrid[];

#ifdef nope
#ifdef NETROM
#ifdef CALLCLI
static char Longmenu[] = "(?)help  (A)rea     (B)ye   (C)onnect (D)ownload (E)scape\n"
                         "(F)inger (H)elp     (I)nfo  (J)heard  (K)ill     (L)ist   (M)boxusers\n"
                         "(N)odes  (O)perator (P)orts (Q)uery   (R)ead     (S)end   (T)elnet\n"
                         "(U)pload (V)erbose  (W)hat  (X)pert   (Z)ap\n";
#else
static char Longmenu[] = "(?)help    (A)rea  (B)ye    (C)onnect (D)ownload (E)scape    (F)inger\n"
                         "(H)elp     (I)nfo  (J)heard (K)ill    (L)ist     (M)boxusers (N)odes\n"
                         "(O)perator (P)orts (R)ead   (S)end    (T)elnet   (U)pload\n"
                         "(V)erbose  (W)hat  (X)pert  (Z)ap\n";
#endif /*CALLCLI*/
#else /*NETROM*/
#ifdef CALLCLI
static char DFAR Longmenu[] = "(?)help (A)rea (B)ye    (C)onnect (CONF)erence (D)ownload  (E)scape   (F)inger\n"
			      "(H)elp  (I)nfo (J)heard (K)ill    (L)ist       (M)boxusers (O)perator (P)orts\n"
                              "(Q)uery (R)ead (S)end   (T)elnet  (U)pload     (V)erbose   (W)hat     (X)pert\n"
                              "(Z)ap\n\n"
                              "For further help, type 'help cmdname', where 'cmdname' is one of the above.\n\n";
#else
static char DFAR Longmenu[] = "(?)help (A)rea (B)ye    (C)onnect (CONF)erence (D)ownload  (E)scape   (F)inger\n"
			      "(H)elp  (I)nfo (J)heard (K)ill    (L)ist       (M)boxusers (O)perator (P)orts\n"
                              "(R)ead  (S)end (T)elnet (U)pload  (V)erbose    (W)hat      (X)pert    (Z)ap\n\n"
                              "For further help, type 'help cmdname', where 'cmdname' is one of the above.\n\n";
#endif /*CALLCLI*/
#endif /*NETROM*/
#endif /* nope */

extern int isgroup __ARGS((char *group));
extern char *mblookname __ARGS((struct mbx *m,char *str));
extern int dombusers __ARGS((int argc,char *argv[],void *p));
extern int dombpast __ARGS((int argc,char *argv[],void *p));
static int doarea __ARGS((int argc,char *argv[],void *p));
extern int dombstatus __ARGS((int argc,char *argv[],void *p));
#if defined(SAMCALLB) || defined(CALLCLI)
static int dombcallbook __ARGS((int argc,char *argv[],void *p));
#endif
void quickscan __ARGS((struct mbx *m, int olduser));
extern void netPrompt __ARGS((void));
extern int CountConfUsers __ARGS((void));
extern char *getquote __ARGS((void));
extern void tutorserv __ARGS((char *call, struct mbx *m, int mode, int color, int ip));
extern char *skipwhite __ARGS((char *ptr));
extern char *skipnonwhite __ARGS((char *ptr));
extern int dosysop __ARGS((int argc,char *argv[],void *p));
#ifdef LZW
void togglelzw __ARGS((int soc, int mode));
#endif
extern char *cmd_line __ARGS((int argc,char *argv[],char stype));
extern char *nntp_name_expansion __ARGS((char *name));

#ifdef WPAGES
void wpageAdd __ARGS((char *entry, int bbs, int updateit));
#endif
extern char *host_or_wpage_exp __ARGS((char *to,int hier,int exphome));
extern char *wpage_exp __ARGS((char *to,int hier,int exphome));
extern FILE *subdir_fopen __ARGS((char *name, char *mode));

extern int Usenrid;
extern int MBSecure;
extern int Mbsendquery;
#ifdef MBXTDISC
extern int32 Mbtdiscinit;
#endif

static void dombconnecthelp __ARGS((void));
static int mbx_getname __ARGS((struct mbx *m));
void mboxredundant __ARGS((struct mbx *m));
static void statarea __ARGS((register struct mbx *m,char *area,int *total, int *new, int *hold, int special));
int dombsemicolon __ARGS((int argc,char *argv[],void *p));
char *addroot __ARGS((char *root, char *name));
char *permtest __ARGS((char *path, long privs, char *name, int mode, char *root, int dir));
extern int lockit __ARGS((struct mbx *m));
extern int dochat __ARGS((int argc,char *argv[],void *p));
extern void askhome __ARGS((struct mbx *m,int initial));
extern void askrealname __ARGS((struct mbx *m,int initial));
extern void notifynewmail __ARGS((struct mbx *m));


/*Enlighten them a bit!
 */
static void
dombconnecthelp() {
#ifdef NETROM
    tputs("Syntax: 'C <node>'        for NET/ROM connects\n");
#endif /* NETROM */
    tputs("Syntax: 'C <port> <call>' for AX.25 connects\n\n");
}

void
bbscolorcls(m)
struct mbx *m;
{
    	if (m->usecolor)
	    	colorcls ();
}

void
bbscolorchange (m, str)
struct mbx *m;
unsigned char *str;
{
    	if (m->usecolor)
	    	colorchange (str, m->colorset);
}


int
dombports(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct iface *ifp;
struct mbx *m = (struct mbx *)p;
    tputs("Available ports:\n");
    for(ifp=Ifaces;ifp!=NULLIF;ifp=ifp->next)
        if(ifp->type == CL_AX25 && \
           (!(ifp->flags & HIDE_PORT) || (m->privs & SYSOP_CMD)) ) {
            tprintf("%-7s",ifp->name);
            if(ifp->descr != NULLCHAR)
                tprintf(":  %s",ifp->descr);
            else
                tputc('\n');
        }
    tputc('\n');
    return 0;
}

/* This is called by the finger-daemon */
void
listusers(s)
int s;
{
int outsave;
struct mbx m;

	m.privs = 0;
	m.stype = ' ';

#ifdef notdef
	usprintf(s,"\nCurrent remote users:\n");
#endif
	outsave = Curproc->output;
	Curproc->output = s;
	dombusers(0,NULLCHARP,&m);
	Curproc->output = outsave;
}

struct mbx *
newmbx()
{
int i;
struct mbx *m;

	for(i = 0; i < NUMMBX; i++){
		if(Mbox[i] == NULLMBX){
			m = Mbox[i] = (struct mbx *)callocw(1,sizeof(struct mbx));
			m->mbnum = i;
            BbsUsers++;
            return m;
		}
	}
	/* If we get here, there are no free mailbox sessions */
	return NULLMBX;
}

static int
mbx_getname(m)
struct mbx *m;
{
char *cp;
FILE *tfp;
union sp sp;
char tmp[MAXSOCKSIZE];
int len = MAXSOCKSIZE;
int anony = 0;
int oldmode;
int founddigit=0;
int count=0;
#ifdef AX25
int32 flags = 0;
int ax_25 = 0;
struct usock *up;
#endif

	sp.p = tmp;
	sp.sa->sa_family = AF_LOCAL;	/* default to AF_LOCAL */
	getpeername(m->user,tmp,&len);
    m->family = sp.sa->sa_family;
    m->path = mallocw(MBXLINE);
	/* This is one of the two parts of the mbox code that depends on the
	 * underlying protocol. We have to figure out the name of the
	 * calling station. This is only practical when AX.25 or NET/ROM is
	 * used. Telnet users have to identify themselves by a login procedure.
	 */
	switch(sp.sa->sa_family){
#ifdef	AX25
	case AF_AX25:
	/* If this is not to the convers call, and this port is
	 * set for NO_AX25, then disconnect ! - WG7J
	 */
	if((m->type != CONF_LINK) && ((up = itop(m->user)) != NULLUSOCK) ) {
	    if((flags=up->cb.ax25->iface->flags) & NO_AX25)
		return -1;
	}
	ax_25 = 1;
	/* note fallthrough */
	case AF_NETROM:
		/* NETROM and AX25 socket address structures are "compatible" */
        /*Save user call, in case she/he wants to use gateway function*/
        memcpy(m->call,sp.ax->ax25_addr,AXALEN);
        m->call[ALEN] &= 0xfc;/*Make sure E-bit isn't set !*/
        pax25(m->name,sp.ax->ax25_addr);
        cp = strchr(m->name,'-');
		if(cp != NULLCHAR)			/* get rid of SSID */
			*cp = '\0';
		/* SMTP wants the name to be in lower case */
		strlwr (m->name);
		anony = 1;
		/* Try to find the privileges of this user from the userfile */
        if((m->privs = userlogin(m->name,m->line,&m->path,MBXLINE,&anony)) == -1){
			m->privs = 0;
			free(m->path);
			m->path = NULLCHAR;
		}
        if(m->privs & EXCLUDED_CMD)
			return -1;
	if(ax_25)
	    if(((flags & USERS_ONLY) && (m->privs & IS_BBS)) ||
	       ((flags & BBS_ONLY) && !(m->privs & IS_BBS)) ||
	       ((flags & SYSOP_ONLY) && !(m->privs & SYSOP_CMD)))
		return -1;
		return 0;
#endif
	case AF_LOCAL:
	case AF_INET:
		m->state = MBX_LOGIN;
	if (m->type == RLOGIN_LINK)
	        tprintf(RLoginbanner,Hostname,Version);
	else	{
	        tprintf(Loginbanner,Version,Hostname);
	        if(Mtmsg != NULLCHAR)
        	    tputs(Mtmsg);
        }
		for(;;){
            /* Maximum of 3 tries - WG7J */
            if(count++ == 3)
                return -1;
            oldmode = sockmode(m->user,SOCK_ASCII);
            tputs("login: ");
	    usflush(m->user);
            if(mbxrecvline(m) == -1)
				return -1;
            if(*m->line == 4) /* Control-d */
                return -1;
            if(*m->line == '\0')
				continue;

            /* add a little test to avoid 'Mailfile busy' syndrome - WG7J */
	    /* changed "if"s to "while"s - ko4ks */
            while((cp=strchr(m->line,'.')) != NULLCHAR)
                *cp = '_';
            while((cp=strchr(m->line,'/')) != NULLCHAR)
                *cp = '_';
            while((cp=strchr(m->line,'\\')) != NULLCHAR)
                *cp = '_';
            if((tfp=fopen(m->line,"w")) == NULL)  /* Invalid name */
                continue;
            fclose(tfp);
            unlink(m->line);
            if(strlen(m->line) < sizeof(m->name))
                strcpy(m->name,m->line);
            else    /* Too long! */
                continue;
			tprintf("Password: %c%c%c",IAC,WILL,TN_ECHO);
			usflush(m->user);
            sockmode(m->user,SOCK_BINARY);
            if(mbxrecvline(m) == -1)
				return -1;
			tprintf("%c%c%c",IAC,WONT,TN_ECHO);
			sockmode(m->user,oldmode);
			tputc('\n');
			usflush(m->user);
			/* This is needed if the password was send before the
			 * telnet no-echo options were receied. We neeed to
			 * flush the eold sequence from the input buffers, sigh
			 */
			if(socklen(m->user,0))/* discard any remaining input */
				recv_mbuf(m->user,NULL,0,NULLCHAR,0);
            if((m->privs = userlogin(m->name,m->line,&m->path,MBXLINE,&anony))
			 != -1){
				if(anony)
                    log(m->user,"MBOX login: %s Password: %s",m->name,m->line);
				else
					log(m->user,"MBOX login: %s",m->name);
				if(m->privs & EXCLUDED_CMD)
					return -1;
#ifdef TIPMAIL
		if (anony && m->type == TIP)
			m->privs = Mbtipperms;
#endif
#ifdef AX25
                /*try to set the name as the user-call.
                 *this is a very crude test! Be careful...
                 *Login must have at least 1 digit (0-9) in it,
                 *and it must be possible to convert it to a call.
                 *if this doesn't work, disallow the gateway command,
                 *no matter if this was allowed by priviledges or not.
                 *Be careful, some one with login name '4us' and
                 *permission set to allow gateway/netrom, will
                 *go out as '4us-15' or '4us-0' !!!!!
                 *11/15/91 WG7J/PA3DIS
                 */
                for(cp=m->name;*cp != '\0';cp++)
                    if(isdigit((int)*cp))
                        break;
                if(*cp != '\0')
                    founddigit = 1;
                if( (setcall(m->call,m->name) == -1) || (!founddigit) ) {
                    m->privs &= ~AX25_CMD;
                    m->privs &= ~NETROM_CMD;
                }
#else
                m->privs &= ~AX25_CMD;
                m->privs &= ~NETROM_CMD;

#endif /* AX25 */
                /* Set the morerows to MAXLIN for telnet logins - WG7J */
                m->morerows = MAXLIN - 1;
                return 0;
			}
            tputs("Login incorrect\n");
            log(m->user,"MBOX login FAILED - login: %s Password: %s",m->name,m->line);
	    mail_error("MBOX Login failed: %s, pw %s",m->name,m->line);
			*m->name = '\0';	/* wipe any garbage */
		}
	}
	return 0;
}

/* put up the prompt */
void
putprompt(m)
struct mbx *m;
{
char area[64];
char *cp1,*cp2;
int inconf;

#if 0
#ifdef FBBFWD
    if(m->sid & MBX_FBBFWD) {
       /* do nothing. */
    } else
#endif
#endif
    if(m->sid & MBX_SID)
        tputs(">\n");
    else {
    	bbscolorchange (m, "09");
        if(m->sid & MBX_NRID)
            tputs(Mbnrid);
        if(m->sid & MBX_AREA) {
            cp1 = m->area;
            cp2 = area;
            /* Convert / and \ into . */
            while(*cp1 != '\0') {
                if(*cp1=='/')
                    *cp2 = '.';
                else
                    *cp2 = *cp1;
                cp1++;
                cp2++;
            }
            *cp2 = '\0';
            tprintf("Area: ");
            bbscolorchange (m, "0C");
            tprintf ("'%s' ", area);
            bbscolorchange (m, "09");
	    if(m->privs & SYSOP_CMD)	{
#ifdef CONVERS
	    	inconf = CountConfUsers ();
#else
		inconf = 0;
#endif
		if((BbsUsers > 1) || inconf)	{
			tputs ("(");
			if (BbsUsers > 1)	{
			        bbscolorchange (m, "0F");
				tprintf("%-d", BbsUsers);
			        bbscolorchange (m, "09");
				tprintf(" users");
			}
#ifdef CONVERS
			if ((BbsUsers > 1) && inconf)
				tputs (", ");
			if (inconf)	{
			        bbscolorchange (m, "0F");
				tprintf ("%-d", inconf);
			        bbscolorchange (m, "09");
				tprintf (" in conference");
			}
#endif
			tputs (") ");
		}
	    }
        }
        bbscolorchange (m, "0B");        
        tprintf((m->sid & MBX_EXPERT) ? (m->sid & MBX_AREA) ? "(%-d/%-d)" : "" : Mbmenu, m->current, m->nmsgs);
        bbscolorchange (m, "0A");
        tprintf (">\n");
        bbscolorchange (m, "0E");
    }
}

#ifdef MBXTDISC
/* Mailbox user has been idle for too long,
 * disconnect the socket - WG7J
 */
void
mboxredundant(m)
struct mbx *m;
{
#ifdef notdef
struct usock *up;

    /* After fix from Mark, ve3dte this is not needed anymore - WG7J */
    /* nasty hack! we may have screwed up reference count */
	/* by invoking newproc("smtp_send",....); Fudge it!   */
    if((up = itop(m->user)) != NULLUSOCK)
        up->refcnt = 1;
#endif

/*    exitbbs (m);	*/
    /* Close the socket*/
    close_s(m->user);
    return; /* Keep lint happy */
}
#endif

extern void mbox_converse __ARGS((int, char *, int, struct mbx *));

/* Incoming mailbox session */
void
mbx_incom(s,t,p)
int s;
void *t;
void *p;
{
#ifdef TIPMAIL
struct tipcb *tip;
#endif
struct mbx *m;
#ifdef notdef
struct usock *up;
#endif
char *buf[3], *cp;
char tmp[AXBUF];
int rval;
time_t newuser;

	sockmode(s,SOCK_ASCII);
	sockowner(s,Curproc);	/* We own it now */
	/* Secede from the parent's sockets, and use the network socket that
	 * was passed to us for both input and output. The reference
	 * count on this socket will still be 1; this allows the domboxbye()
	 * command to work by closing that socket with a single call.
	 * If we return, the socket will be closed automatically.
	 */
	close_s(Curproc->output);
	close_s(Curproc->input);
	Curproc->output = Curproc->input = s;

	/* We'll do our own flushing right before we read input */
	setflush(s,-1);

	if((m = newmbx()) == NULLMBX)	{
	        tputs("Too many mailbox sessions\n");
		return;
		}

	m->user = s;
	m->escape = 20;		/* default escape character is Ctrl-T */
	m->type = (int) t;
	m->linemode = 0;
	m->colorset[0] = 0;
#ifdef TIPMAIL        
#ifdef XMODEM
	if (m->type==TIP) {
	    tip = (struct tipcb *) p;
	    tip->raw=0;
	    m->tip=tip;    
	} 
#endif        
#endif

#ifndef UNIX
    while(socklen(s,0)) /* discard any remaining input */
	 recv_mbuf(s,NULL,0,NULLCHAR,0);
#endif
    
	/* get the name of the remote station */
	if(mbx_getname(m) == -1)	{
		exitbbs(m);
		return;
		}
	Totallogins++;
	newuser = loguser(m);

#ifdef RLOGINSERV
	if ((int)t == RLOGIN_LINK)	{
		tputc ('\n');
		dosysop (1, (char **)0, (void *)m);
		exitbbs(m);
		return;
	}
#endif
#ifdef CONVERS
	if((int)t != TIP && (int)t & CONF_LINK)	{
		if(m->privs & NO_CONVERS)
			tputs(Noperm);
		else	{
			m->state = MBX_CONVERS;
			chname(Curproc,"conference");
			log(s,"open CONF");
			{
				int fd = m->user;
				char name[20];
				strcpy (name, m->name);
			        Mbox[m->mbnum] = NULLMBX;
        			free((char *)m);
			        BbsUsers--;
				mbox_converse (fd, name, (int) -1, NULLMBX);
			}
		}
        	close_s(Curproc->output);
	        return;
    		}
#endif

#ifdef TTYCALL
    if((int)t & TTY_LINK) {
	int ostate = m->state;

	m->state = MBX_CHAT;
	chname(Curproc,"ttylink");
	log(s,"open TTYLINK");
	if (dochat(0, 0, m) == 2)
	{
	    exitbbs(m);
	    return;
	}
	tputs("Chaining to BBS...\n");
	m->state = ostate;
    }
#endif

#ifdef TUTOR
	if((int)t != TIP && ((int)t & TUTOR_LINK || (int)t & INFO_LINK || (int)t & NEWS_LINK))	{
		m->state = MBX_TUTOR;
		chname(Curproc,"tutorial");
		log(s,"open TUTORIAL");
		{
			char name[20];
			strcpy (name, m->name);
		        Mbox[m->mbnum] = NULLMBX;
        		free((char *)m);
		        BbsUsers--;
/*			setflush(s,'\n');  */     /* automatic flushing each line */
			tutorserv (name, NULLMBX, ((int)t & INFO_LINK) ? 1 : ((int)t & NEWS_LINK) ? 2 : 0, m->usecolor, 0);
			mspause (2000);
		}
        	close_s(Curproc->output);
	        return;
    		}
#endif

	log(s,"open MBOX for '%s'", m->name);

	if (MbLogging)	{
		char buf[128];
		FILE *out;
		sprintf(buf,"%s/mbox.log",Spool);
		if((out = fopen(buf,APPEND_TEXT)) != NULLFILE)	{
			time_t t;
			time(&t);
			fprintf (out, "MBOX from %s %s on %s", m->name, m->realname, ptime(&t));
			fclose (out);
		}
	}

	BBSlogins++;
#ifdef MBXTDISC
	/*Start inactivity timer - WG7J */
	set_timer(&m->tdisc,Mbtdiscinit * 1000L);
	m->tdisc.func = (void(*)__FARGS((void*)))mboxredundant;
	m->tdisc.arg = m;
	start_timer(&m->tdisc);
#endif
	if(m->privs & IS_BBS)
/*		m->sid = MBX_SID; */ /*force bbs status*/
		m->sid = MBX_EXPERT;	/* make BBS 'SID' itself, else it's sysop enters as EXPERT */
	else if(m->privs & IS_EXPERT)
		m->sid |= MBX_EXPERT;

/*	newuser = loguser(m);	*/
#ifdef LZW
	if (m->sid & MBX_TNOS)	{
		tputs ("Use LZW Compression (*y/n) ?\n");
    		if (mbxrecvline(m) != -1)	{
			if (tolower (*m->line) != 'n')
				togglelzw (m->user, 1);
    		}
    	}
#endif
	m->state = MBX_CMD;	/* start in command state */
	if (!(m->privs & IS_BBS) && (m->sid & MBX_GFX))
		colorfile (ANSILogin, m->colorset);

#ifdef FBBFWD
	if(Mfbb)
		tputs(FWDlzw ? MboxIdFwdFBB : MboxIdFBB);
	else
#endif // fbbfwd
	tputs(FWDlzw ? MboxIdFwd : MboxId);

	/* Say 'hello' only if user is not a bbs - WG7J */
/*	if(!(m->sid & MBX_SID))	{	*/
	if(!(m->privs & IS_BBS))	{
	        bbscolorchange (m, "0F");
		if (m->home[0] == '-')
			askhome (m, 1);
		if (m->realname == NULLCHAR)
			askrealname (m, 1);
		if(!(m->sid & MBX_RDMOTD))	{
			DisplayFile (MOTDfile, s);
			m->sid |= MBX_RDMOTD;
			m->update = 1;
			}
		if (m->privs & SYSOP_CMD)
			DisplayFile (MOTDsysfile, s);
	        tprintf(Mbwelcome,m->name);
#ifdef AX25
        	if(m->family == AF_INET)
#endif
			tprintf(Mbbanner,Hostname,Version);
#ifdef AX25
		else
			tprintf(Mbbanner,pax25(tmp,Mycall),Version);
#endif
		if (newuser > 0)
			tprintf ("Last on the BBS: %s", ctime(&newuser));
		if (BbsUsers == 1)
			tprintf (Only);
		else
			tprintf(CurUsers,BbsUsers);
		if(!ThirdParty || !Mbfullsvc)
			tputs(Mbwarning);
		if (!newuser)	{
			DisplayFile (NEWUSERfile, s);
#ifdef TUTOR
			sprintf (m->line, "newuser %s", m->name);
			mbscripthook (m, "newuser.sys");
#endif
		}
		tflush ();
#ifdef USERLOG
		if (m->sid & MBX_STATS)
			quickscan (m, (int) newuser);
#endif
		cp = getquote();
		if (cp)		{
			tprintf ("\nQuote of the Day:");
		        bbscolorchange (m, "0A");
			tprintf ("\n%s\n", cp);
		        bbscolorchange (m, "0F");
		}
		if(((!cp) || strcmp (MMotd, cp)) && MMotd != NULLCHAR)
			tprintf ("\n%s", MMotd);
		free (cp);
	        usflush(m->user);
#ifdef oldway
        	/* Enable our local message area,
	         * only if we're not a bbs - WG7J
        	 */
	        buf[1] = m->name;
        	doarea(2,buf,m);
    	} else
    		m->mysize = 0;
#else
        	m->special = ' ';
		}
#ifdef DELEGATE
	if (m->sid & MBX_DELEGATE)	{
		tputs ("You have delegation enabled, do you wish to disable it (*y/n) ?\007\n");
		if (mbxrecvline(m) != -1)	{
			if (tolower (*m->line) != 'n')	{
				clear_delegate (m);
				m->sid &= ~MBX_DELEGATE;
				m->update = 1;
			}
		}
	}
#endif
       	/* Enable our local message area */
        buf[1] = m->name;
       	doarea(2,buf,m);
#endif
#ifdef TUTOR
	if(!(m->privs & IS_BBS))	{
		sprintf (m->line, "login %s", m->name);
		mbscripthook (m, "login.sys");
	}
#endif

	/* Send prompt */
	if(!(m->privs & IS_BBS))
		putprompt(m);
	else	/* first prompt to a BBS has color disabled, after this it
		   depends on whether we have seen an SID. If an SID, no color.
		   This allows the BBS's SYSOP to 'live' login and have color
		   capabilities (after the first prompt).	*/
	        tputs(">\n");

	while(mbxrecvline(m) != -1)	{
		if (m->privs & EXCLUDED_CMD)
			break;
		if(m->special)	/* no-color BBS first prompt, also */
			bbscolorchange (m, "0F");
        	if((rval = mbx_parse(m)) == -2)
			break;
		if(rval == 2)
			break;
		if (rval && BBSdump && (m->sid & MBX_SID))
			break;
		if (m->privs & EXCLUDED_CMD)
			break;
		if(rval == 1)
			tputs("Bad syntax.\n");
        	notifynewmail (m);
		/* Do not check mailfile if we're bbs, saves a tmpfile- WG7J*/
		if(!(m->sid & MBX_SID))
			scanmail(m);
		if (mbxMaxTimer && (m->logontime + mbxMaxTimer) < time((time_t *)0))	{
			if (!(m->sid & MBX_SID))	{
				tprintf ("Maximum allowed time per session exceeded!\007\n\n");
				domboxbye(0, (char **)0, m);
			}
			log(Curproc->output,"Mailbox MaxTimer expired for '%s'", m->name);
			break;
		}
		putprompt(m);
		m->state = MBX_CMD;
		}
	exitbbs(m);

#ifdef notdef
    /* After fix from Mark, ve3dte this is not needed anymore - WG7J */
	/* by invoking newproc("smtp_send",....); Fudge it!   */
	if((up = itop(Curproc->output)) != NULLUSOCK)
        	up->refcnt = 1;
#endif
        usflush(Curproc->output);
	mspause(500L);
	close_s(Curproc->output);
}

void
exitbbs(m)
struct mbx *m;
{
#ifdef MBXTDISC
	stop_timer(&m->tdisc);
#endif
	closenotes(m);
	free(m->to);
	free(m->tofrom);
	free(m->origto);
	free(m->origbbs);
	free(m->subject);
	free(m->date);
	free(m->tomsgid);
	free(m->path);
	free(m->home);
	/* Close the tempfiles if they are not nullpointers - WG7J */
	if(m->tfile != (FILE *) 0)
        	fclose(m->tfile);
	if(m->tfp != (FILE *) 0)
	        fclose(m->tfp);
	if(m->stdinbuf != NULLCHAR)
		free(m->stdinbuf);
	if(m->stdoutbuf != NULLCHAR)
		free(m->stdoutbuf);
	free((char *)m->mbox);
	Mbox[m->mbnum] = NULLMBX;
	free((char *)m);
	if (BbsUsers)
		BbsUsers--;
	if ((m->state != MBX_FORWARD) && m->name && *m->name)
		log(Curproc->output,"close MBOX from '%s'", m->name);
}

/**********************************************************************/

static int dombconnect __ARGS((int argc,char *argv[],void *p));
int dombconvers __ARGS((int argc,char *argv[],void *p));
#ifdef CALLBOOK
static int dombcall __ARGS((int argc,char *argv[],void *p));
#endif
int dodownload __ARGS((int argc,char *argv[],void *p));
int dombupload __ARGS((int argc,char *argv[],void *p));
int dowhat __ARGS((int argc,char *argv[],void *p));
int dozap __ARGS((int argc,char *argv[],void *p));
int dosend __ARGS((int argc,char *argv[],void *p));
static int dosid __ARGS((int argc,char *argv[],void *p));
int dosysop __ARGS((int argc,char *argv[],void *p));
int dostars __ARGS((int argc,char *argv[],void *p));
int dombhelp __ARGS((int argc,char *argv[],void *p));
int dombtelnet __ARGS((int argc,char *argv[],void *p));
int dombfinger __ARGS((int argc,char *argv[],void *p));
int dombquote __ARGS((int argc,char *argv[],void *p));
int dombtutor __ARGS((int argc,char *argv[],void *p));
int dombnews __ARGS((int argc,char *argv[],void *p));
int dombexpert __ARGS((int argc,char *argv[],void *p));
int dobump __ARGS((int argc,char *argv[],void *p));
int dombfdesc __ARGS((int argc,char *argv[],void *p));
int dombtime __ARGS((int argc,char *argv[],void *p));
int dombwpages __ARGS((int argc,char *argv[],void *p));
int dombset __ARGS((int argc,char *argv[],void *p));
int dombget __ARGS((int argc,char *argv[],void *p));
int dombrmail __ARGS((int argc,char *argv[],void *p));
int dombgroup __ARGS((int argc,char *argv[],void *p));
int doreply __ARGS((int argc,char *argv[],void *p));
int douser __ARGS((int argc,char *argv[],void *p));
int dombexpand __ARGS((int argc,char *argv[],void *p));
int dombslip __ARGS((int argc,char *argv[],void *p));
int dombjheard __ARGS((int argc,char *argv[],void *p));
int dombiproute __ARGS((int argc,char *argv[],void *p));
int dombroute __ARGS((int argc,char *argv[],void *p));
extern int dobbshome __ARGS((int argc,char *argv[],void *p));
static void gw_alarm __ARGS((void *p));
static void gw_input __ARGS((int s,void *notused,void *p));
static void gw_superv __ARGS((int null,void *proc,void *p));
static int mbx_to __ARGS((int argc,char *argv[],void *p));
int mbx_data __ARGS((struct mbx *m,struct list *cclist,char *extra, int returnreceipt));
int msgidcheck __ARGS((char *string));
static int thirdparty __ARGS((struct mbx *m));
extern int doipheard __ARGS((int argc,char *argv[],void *p));
extern int dorealname __ARGS((int argc,char *argv[],void *p));
extern int doversion __ARGS((int argc,char *argv[],void *p));
#ifdef NETROM
static int dombnrnodes __ARGS((int argc,char *argv[],void *p));
extern int donrneighbour __ARGS((int argc,char *argv[],void *p));
#endif
#ifdef TUTOR
extern int dombscript __ARGS((int argc,char *argv[],void *p));
#endif

struct cmds DFAR Mbcmds[] = {
	"",		doreadnext,	0, 0, NULLCHAR,
	"?",		dombhelp,	0, 0, NULLCHAR,
	"Area",		doarea,		0, 0, NULLCHAR,
	"Bye",		domboxbye,	0, 0, NULLCHAR,
	"BUmp",         dobump,         0, 0, NULLCHAR,
	"Connect",	dombconnect,	0, 0, NULLCHAR,
#ifdef CALLBOOK
	"CAll",		dombcall,	0, 0, NULLCHAR,
#endif
#ifdef SAMCALLB
	"CAll",		dombcallbook,	0, 2, "Call callsign\nMultiple callsigns allowed per line",
#endif
#ifdef TUTOR
	"CMd",		dombscript,	0, 0, NULLCHAR,
#endif
#ifdef CONVERS
	"CONFerence",	dombconvers,	0, 0, NULLCHAR,
#endif
#ifdef XMODEM
	"Download",	dodownload,	0, 2, "D[U|X] filename",
#else
	"Download",	dodownload, 	0, 2, "D[U] filename",
#endif        
/* next entry out of order DELIBERATELY, to make "D" download, not del! */
	"DEl",		dozap,		0, 2, "DEL filename",
	"DIr",          dowhat,         0, 0, NULLCHAR,
	"Escape",	dombescape,	0, 0, NULLCHAR,
	"EXit",		domboxbye,	0, 0, NULLCHAR,
	"EXPand",	dombexpand,	0, 2, "EXPand aliasname",
	"Finger",	dombfinger,	0, 0, NULLCHAR,
/* next entry out of order DELIBERATELY, to make "F" finger, not fdesc! */
	"FDesc",	dombfdesc,	0, 2, "FD filename",
	"Get",		dombget,	0, 0, NULLCHAR,
	"GRoup",	dombgroup,	0, 2, "GROUP action groupname",
	"Help",		dombhelp,	0, 0, NULLCHAR,
	"HOme",         dobbshome,	0, 0, NULLCHAR,
	"Info",		dombhelp,	0, 0, NULLCHAR,
/* next entry out of order DELIBERATELY, to make "I" info, not iheard! */
	"IHeard",	doipheard,	0, 0, NULLCHAR,
	"IProute",	dombiproute,	0, 0, NULLCHAR,
#ifdef	AX25
	"Jheard",	dombjheard,	0, 0, NULLCHAR,
#endif
	"Kill",		dodelmsg,	0, 0, NULLCHAR,
	"List",		dolistnotes,	0, 0, NULLCHAR,
	"Mboxusers",	dombusers,	0, 0, NULLCHAR,
	"Name",         dorealname,	0, 0, NULLCHAR,
#ifdef TUTOR
	"NEws",         dombnews,      0, 0, NULLCHAR,
#endif
#ifdef NETROM
	"NOdes",	dombnrnodes,	0, 0, NULLCHAR,
	"NRoutes",	donrneighbour,	0, 0, NULLCHAR,
#endif
	"Operator",	dochat,		0, 0, NULLCHAR,
	"Ping",		doping,		0, 0, NULLCHAR,
	"POrts",	dombports,	0, 0, NULLCHAR,
	"Quit",		domboxbye,	0, 0, NULLCHAR,
/* next entry out of order DELIBERATELY, to make "Q" quit, not query! */
#if defined(CALLCLI) || defined(SAMCALLB)
	"QUEry",	dombcallbook,	0, 2, "Q callsign\nMultiple callsigns allowed per line",
#endif
	"QUOte",	dombquote,	0, 0, NULLCHAR,
	"Read",		doreadmsg,	0, 0, NULLCHAR,
	"REPly",	doreply,	0, 0, NULLCHAR,
#ifdef RMAIL
	"RMAil",	dombrmail,	0, 2, "RMAIL destbbs",
#endif
	"ROute",	dombroute,	0, 2, "ROute address",
	"Send",		dosend,		0, 0, NULLCHAR,
	"SET",		dombset,	0, 2, "SET A|C|F|M|N|S|SI|X",
#ifdef TIPMAIL
	"SLip",		dombslip,	0, 0, NULLCHAR,
#endif
	"Telnet",	dombtelnet,	0, 2, "T hostname",
	"TIme",		dombtime,	0, 0, NULLCHAR,
#ifdef TUTOR
	"TUtor",        dombtutor,      0, 0, NULLCHAR,
#endif
#ifdef XMODEM        
	"Upload",	dombupload,	0, 2, "U[X] filename",
#else
	"Upload",	dombupload,	0, 2, "U filename",
#endif    
	"USer",		douser,		0, 0, NULLCHAR,
	"Verbose",	doreadmsg,	0, 0, NULLCHAR,
	"VERSion",	doversion,	0, 0, NULLCHAR,
	"What",		dowhat,		0, 0, NULLCHAR,
#ifdef WPAGES
	"WPages",	dombwpages,	0, 2, "WP call [@bbs]",
#endif
	"Xpert",	dombexpert,	0, 0, NULLCHAR,
	"Zap",		dozap,		0, 2, "Z filename",
/* the rest aren't displayed with "?" */
	"[",		dosid,		0, 0, NULLCHAR,
	"@",		dosysop,	0, 0, NULLCHAR,
#ifdef	AX25
#ifdef MBFWD
	"f>",		dorevfwd,	0, 0, NULLCHAR,
#ifdef FBBFWD
	"fb",		dofbbfwd,	0, 0, NULLCHAR,
	"ff",		dofbbfwd,	0, 0, NULLCHAR,
	"fq",		domboxbye,	0, 0, NULLCHAR,
#endif
#endif
#endif
	"***",		dostars,	0, 0, NULLCHAR,
	";",		dombsemicolon,	0, 0, NULLCHAR,
	NULLCHAR,       NULLFP((int,char**,void*)),         0, 0, "Huh?",
};

/* "twocmds" defines the MBL/RLI two-letter commands, eg. "SB", "SP" and so on.
 * They have to be treated specially since cmdparse() wants a space between
 * the actual command and its arguments.
 * "SP FOO" is converted to "s  foo" and the second command letter is saved
 * in m->stype. Longer commands like "SEND" are unaffected, except for
 * commands starting with "[", i.e. the SID, since we don't know what it will
 * look like.
 */
static char twocmds[] = "aslrd[mvkxwiu";    /* A,S,L,R,D,M,V,K,X,W,I,U are two-letter commands */

int
mbx_parse(m)
struct mbx *m;
{
char *cp, *cp2;
int i;
char *newargv[2];
unsigned char specialfound = 0;
int inbid = 0, sendtype = 0;

	/* Skip any spaces at the begining */
	for(cp = m->line;isspace(*cp);++cp)
		;
	if (tolower (*cp) == 's')
		sendtype = 1;		/* a 'send' command, of some form */

	/* Translate entire buffer to lower case */
	/* fix by KO4KS to convert a message's BID to upper case.  */
	for (cp2 = cp; *cp2 != '\0'; ++cp2)	{
		if (sendtype && !inbid && *cp2 == '$')
			inbid = 1;
		if (!inbid)
			*cp2 = tolower(*cp2);
		else
			*cp2 = toupper(*cp2);
		if (*cp2 == ' ')
			inbid = 0;
	}

	m->special = m->stype = ' ';
	if (*cp == '^' || *cp == '~') {
		if (cp[1] == 's')	{
			m->special = *cp;
			specialfound = 0x80;
		}
		*cp++ = ' ';
	}
	if(*cp != '\0' && *(cp+1) != '\0')
		for(i=0; i<strlen(twocmds); ++i)	{
			if(*cp == twocmds[i] && (isspace(*(cp+2)) || *(cp+2) == '\0'
			 || *cp == '['))	{
				if(islower(*(++cp)))
					m->stype = toupper(*cp); /* Save the second character */
				else
					m->stype = *cp;
				m->stype |= specialfound;
				*cp = ' ';
				break;
			}
		}
	/* See if the input line consists solely of digits */
	cp = m->line;
	for(cp = m->line;isspace(*cp);++cp)
		;
	if (*cp == ';')
		return 0;	/* allow self-identification */
	newargv[1] = cp;
	for(;*cp != '\0' && isdigit(*cp);++cp)
		;
	if(*cp == '\0' && strlen(newargv[1]) > 0) {
	        newargv[0] = "r";
        	return doreadmsg(2,newargv,(void *)m);
	}
	return cmdparse(Mbcmds,m->line,(void *)m);
}

/* This works like recvline(), but telnet options are answered and the
 * terminating newline character is not put into the buffer. If the
 * incoming character equals the value of escape, any queued input is
 * flushed and -2 returned.
 */
int
mbxrecvline(m)
struct mbx *m;
{
int s = m->user;
int escape = m->escape;
char *buf = m->line;
	int c, cnt = 0, opt, cl;

	if(buf == NULLCHAR)
		return 0;
	usflush(Curproc->output);
#ifdef MBXTDISC
    start_timer(&m->tdisc);
#endif
	pwait(NULL);
	while((c = recvchar(s)) != EOF){
		pwait(NULL);
		if((m->type & (TELNET_LINK|RLOGIN_LINK)) && !m->inmessage && c == IAC){		/* Telnet command escape */
			if((c = recvchar(s)) == EOF)
				break;
			if(c >= 250 && c < 255 && (opt = recvchar(s)) != EOF){
				switch(c){
				case SB:
					opt=recvchar(s); /* Get the real option */
					if(opt==EOF) break;
					cl=opt;
					c=recvchar(s);
				    /* Gobble up until we see IAC SE */
					while((c!=EOF) && !(cl==IAC && c==SE)){
						/* maybe check for timeout here, in case someone
						   happened to send a binary file with the IAC SB
						   sequence in it. */
						cl=c; /* keep track of second last char read */
						c=recvchar(s);
					}
					/* and tell the client where to go... */
					/* tprintf("%c%c%c",IAC,WONT,opt); */
					break;
				case WILL:
					if(opt==TN_LINEMODE){
					    m->linemode = 1;
						/* we WANT linemode */
						tprintf("%c%c%c",IAC,DO,opt);
						/* Tell client to do editing */
						tprintf("%c%c%c%c%c%c%c",IAC,SB,TN_LINEMODE,1,1,IAC,SE);
					}
					else{
						tprintf("%c%c%c",IAC,DONT,opt);
					}
					break;
				case WONT:
					tprintf("%c%c%c",IAC,DONT,opt);
					break;
				case DO:
					tprintf("%c%c%c",IAC,WONT,opt);
					break;
				case DONT:
					tprintf("%c%c%c",IAC,WONT,opt);
				}
/* to be fixed 			usflush(Curproc->output);*/
				pwait(NULL);
				continue;
			}
			if(c != IAC && (c = recvchar(s)) == EOF)
				break;
		}
		/* ordinary character */
#ifndef TNOS_68K
		if(c == '\r' || c == '\n')
#else
		if(c == '\r' || c == '\l')
#endif
			break;
		if(!m->inmessage && uchar(c) == escape){
			if(socklen(s,0)) /* discard any remaining input */
				recv_mbuf(s,NULL,0,NULLCHAR,0);
			cnt = -2;
			break;
		}
        /* Handle <del> chars - from wa7tas */
        if(!m->inmessage && c == 8) {
            if(cnt > 0) {
                *--buf = 0;
                cnt--;
            }
        } else {
		*buf++ = c;
		++cnt;
		}
	        if(cnt == (MBXLINE - 1))	{
        		cnt = -2;
			break;
		}
	pwait(NULL);
	}
	if(c == EOF && cnt == 0)
		return -1;
	*buf = '\0';
#ifdef MBXTDISC
    /* Restart the timeout-timer - WG7J*/
    start_timer(&m->tdisc);
#endif
    return cnt;
}

/* New forwarding option, simply ignore all data - WG7J */
int
dombsemicolon(int argc,char *argv[],void *p) {

    return 0;
}

extern void updatedefaults __ARGS((struct mbx *, int));

int
domboxbye(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
long elapsedtime;
char *cptr;

	m = (struct mbx *)p;

#ifdef TUTOR
	if(!(m->sid & MBX_SID))		{	/* not a BBS */
		sprintf (m->line, "logout %s", m->name);
		mbscripthook (m, "logout.sys");
	}
#endif
#ifdef USERLOG
	if(!(m->sid & MBX_SID))		/* not a BBS */
		setlastread(m);
	if(m->update)
        	updatedefaults(m, 0);
#endif
	if(m->sid & MBX_SID)		{	/* if a BBS */
		smtptick (NULL);	/* clean up any unfiled mail */
		mspause (500L);
		return -2;		/* for bbs's, just disconnect */
	}

	/* Now say goodbye */
	bbscolorchange (m, "09");
	tprintf("\nThank you ");
	bbscolorchange (m, "0C");
	tprintf (m->name);
	bbscolorchange (m, "09");
	tprintf (", for calling the %s TNOS Tcp/Ip Mailbox.\n",	Hostname);
        time((time_t *)&elapsedtime);
        cptr = ctime((time_t *) &elapsedtime);
        rip (cptr);
        elapsedtime -= m->logontime;
        tprintf ("Logged off: ");
	bbscolorchange (m, "0F");
	tprintf (cptr);
	bbscolorchange (m, "09");
	tprintf (" --- Time this session: ");
	bbscolorchange (m, "0F");
	tprintf ("%s\n", tformat (elapsedtime));
	if(MExit != NULLCHAR)
		tprintf("%s\n",MExit);
#ifdef nope /* ALLSERV */
	if(m->type == TIP)
	        tputs("Please hang up now.\n");
#endif
/*	usflush(m->user);	*/
	usflush(Curproc->output);
	return -2;	/* signal that exitbbs() should be called */
}

char *
addroot (root,name)
char *root, *name;
{
	return strdup (make_fname (root, name));
}


char *
permtest (path, privs, name, mode, root, dir)
char *path, *name, *root;
long privs;
int mode, dir;
{
char *file, *defdir, *cp;

	if (root == NULLCHAR)	{
		defdir = strdup(path);
		if ((cp = strchr (defdir, ';')) != NULLCHAR)
			*cp = 0;
	} else	defdir = strdup (root);
	if (dir)	
		file = strdup(defdir);
	else
		file = addroot (defdir, name);
	free (defdir);
	if(!permcheck(path,privs,mode,file))	{
		free (file);
		tputs(Noperm);
		return 0;
	}
	return file;
}


#if defined(CALLBOOK)
extern char *InetCallserver;
extern char *InetCallserverport;

/*This is a simple way of estiblishing a connection
 *to a callbook-server via tcp - WG7J
 */
static int
dombcall(argc,argv,p)
int argc;
char *argv[];
void *p;
{
char buf[8], *newargv[3];

	if(InetCallserver!=NULLCHAR){
		newargv[0] = "C";
		newargv[1] = InetCallserver;
		newargv[2] = InetCallserverport;
		SecureTelnet = 0;
		return dombtelnet(3,newargv,p);
	}
	else {
		tputs("Internet callserver not configured\n");
	}
	/* It returns only after a disconnect or refusal */
	return 0;
}

#endif /*CALLBOOK*/

#if defined(CALLCLI)  || defined(SAMCALLB)
static int
dombcallbook(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
char buf[8], *newargv[3];
extern char *Callserver;
int req, ret = 0;

	if(argc > 2){
        tputs("Usage: Q callsign [callsign] [...]\n");
		return -1;
	}
	m = (struct mbx *) p;
#ifndef newcode
	sprintf(buf,"%d",IPPORT_CALLDB);
	newargv[0] = "C";
#else	/* to call KF5MG's callbook server, through FINGER */
	sprintf(buf,"%d",IPPORT_FINGER);
	newargv[0] = "t";
#endif
	newargv[1] = Callserver;
	newargv[2] = buf;

	for (req = 1; req < argc; req++)  {
		if (argv[req] == NULLCHAR) return ret;
		log(m->user, "%s checking callbook: %s",m->name,argv[req]);
		if (!Callserver || !*Callserver)	{
#ifdef SAMCALLB
			cb_lookup (Curproc->output, argv[req], (FILE *) 0);
#else
			cb_lookup (Curproc->output, argv[req]);
#endif
			ret = 0;
		} else	{
			m->startmsg = mallocw(80);  /* is freed each time by gw_connect() */
			sprintf(m->startmsg,"%s\n", argv[req]);
			tprintf("Looking for \"%s\" in the callbook at %s\n",argv[req],Callserver);
			SecureTelnet = 0;
			ret = dombtelnet(3,newargv,p);
		}
	}
	return ret; /* It looks like all possible returns are zero anyway!    */
}
#endif


extern int Mbloophold;

/*Some additional security - WG7J
 *NO_3PARTY =  disallow all 3rd party mail
 *NO_SENDCMD = only allow mail to sysop
 */
extern int NoBid;

int
dosend(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int cccnt = 0, fail = 0;
char *host, *cp, *rhdr = NULLCHAR;
struct list *ap, *cclist = NULLLIST;
struct mbx *m;
FILE *fp;
#ifdef notdef
time_t now;
#endif
int done = 0;
char *cp2;
char returnreceipt = 0, nosig = 0;
int foundCTLz = 0;
int c;
long here, datastart;

#ifdef RLINE
struct tm t;
#define ODLEN   16
#define OBLEN   32
char origdate[ODLEN];
char origbbs[OBLEN];
char fwdbbs[NUMFWDBBS][FWDBBSLEN+1];
int myfwds = 0;
register int i;
int zulu = 0;
int check_r = 0, check_r2 = 0;
int found_r = 0, wrotedata = 0;
int loops = 0;
char Me[15];
int recvsize;
long messagesize;
int userlevelending = 0;


	origdate[0] = '\0';
	origbbs[0] = '\0';
#endif
 
	m = (struct mbx *)p;
	if (m->stype & 0x80)	{
		if (m->special == '~')
			nosig = 1;
		else
			returnreceipt = 1;
		m->stype &= 0x7f;
	}

#ifdef TIPMAIL
	if(m->stype == 'L')
		return (dombslip (argc, argv, p));
#endif
	if((m->stype != 'R' || (m->sid & MBX_SID)) && mbx_to(argc,argv,m) == -1)	{
		tputs((m->sid & MBX_SID) ? "NO - syntax error\n" : \
                    "S command syntax error - format is:\nS[C|F] name [@ host] [< from_addr] [$bulletin_id]\nSR [number]\n");
        mail_error("%s: MBOX S syntax error - %s\n",m->name,cmd_line(argc,argv,m->stype));
		return 0;
	}

	bbscolorchange (m, "0D");

	/*Check for send permission */
	if(m->privs & NO_SENDCMD) { /*is this to 'SYSOP' or 'sysop' ?*/
		if(stricmp(m->to,"sysop")) 	{
			tputs((m->sid & MBX_SID) ? "NO - permission denied\n" : \
	                    "Sorry, only mail to 'sysop' allowed!\n");
            mail_error("%s: no mail permission - %s\n",m->name,m->to);
			return 0;
		}
	}

    /* Check for a BID on bulletins from other bbs's - WG7J */
    if((m->sid & MBX_SID) && !NoBid &&
        (m->stype == 'B') && (m->tomsgid == NULLCHAR)) {
	    tputs("NO - No BID!\n");
        log(m->user,"MBOX %s: SB without BID - %s",m->name,m->to);
        mail_error("MBOX %s: SB without BID - %s",m->name,m->to);
	    return 0;
    }

	pwait (NULL);		/* just to be nice to others */
	if(m->stype != 'R' && msgidcheck(m->tomsgid)) {
		if(m->sid & MBX_SID)
			tputs("NO - ");
		tprintf("Already have %s\n",m->tomsgid);
		return 0;
	}

	pwait (NULL);		/* just to be nice to others */
/*	if (!(m->sid & MBX_SID))	*/	/* if BBS, no need! */
	if ((m->stype != 'B') && (m->stype != 'T') && (m->stype != 'R'))
		m->to = host_or_wpage_exp (m->to, 1, 0);


#ifdef WPAGES
	check_r2 = 1;
#endif
#ifdef TUTOR
	if (!(m->sid & MBX_SID))	{
		sprintf (m->line, "%s - %s", m->origto, m->to);
		mbscripthook (m, "dosend.sys");
	}
#endif
	if(m->stype == 'R' && !(m->sid & MBX_SID))
		if (mbx_reply(argc,argv,m,&cclist,&rhdr) == -1)
			return 0;
		else
			check_r2 = 0;
	if((cp = rewrite_address(m->to)) != NULLCHAR)
		if(stricmp(m->to,cp) != 0)	{
			m->origto = m->to;
			m->to = cp;
		} else
			free(cp);

#ifdef DELEGATE
	if ((m->sid & MBX_DELEGATE) && !stricmp(m->name, m->to))	{
		tputs((m->sid & MBX_SID) ? "NO - refused\n" : \
                	"Sending to yourself with DELEGATION enabled causes mailing loops\nSend cancelled,  please mail 'sysop' for help\007\n\n");
		log(m->user,"MBOX DELEGATE mail loop attempted: %s",m->name);
		mail_error("MBOX DELEGATE mail loop attempted: %s",m->name);
		free (rhdr);
		return 0;
	}
#endif

	pwait (NULL);		/* just to be nice to others */
	/* refuse any mail that gets rewritten into 'refuse' - WG7J */
	if(!stricmp(m->to,"refuse")) 	{
		tputs((m->sid & MBX_SID) ? "NO - refused\n" : \
                	"Bad user or hostname,  please mail 'sysop' for help\n");
		free (rhdr);
		return 0;
	}

	if( ((!Mbfullsvc || !ThirdParty) && !(m->privs & SYSOP_CMD)) || (m->privs & NO_3PARTY) )
		if(thirdparty(m) == 0)	{
			if (m->sid & MBX_SID)
				tputs ("NO - ");
			tputs(Mbwarning);
	    mail_error("%s: 3rd party mail refused - %s\n",m->name,m->to);
		        free (rhdr);
			return 0;
		}

	/* Send the new 'To:' line to sysops only - WG7J */
	if((m->privs&SYSOP_CMD) && (m->origto != NULLCHAR || m->stype == 'R') && !(m->sid & MBX_SID))
		tprintf("To: %s\n", m->to);
	if(validate_address(m->to) == 0)	{
		tputs((m->sid & MBX_SID) ? "NO - bad address\n" : \
                	"Bad user or hostname,  please mail 'sysop' for help\n");
		free(rhdr);
		del_list(cclist);
		/* We don't free any more buffers here. They are freed upon
		 * the next call to mbx_to() or to domboxbye()	 */
		return 0;
	}
	pwait (NULL);		/* just to be nice to others */
	/* Display the Cc: line (during SR command) */
	for(ap = cclist; ap != NULLLIST; ap = ap->next) {
		if(cccnt == 0){
			tprintf("%s",Hdrs[CC]);
			cccnt = 4;
		} else {
			tputs(", ");
			cccnt += 2;
		}
		if(cccnt + strlen(ap->val) > 80 - 3) {
			tputs("\n    ");
			cccnt = 4;
		}
		tputs(ap->val);
		cccnt += strlen(ap->val);
	}
	if(cccnt)
		tputc('\n');

	pwait (NULL);		/* just to be nice to others */
	/* If the the command was 'SC' then read the Cc: list now - WG7J */
	if((m->stype == 'C') && !(m->sid & MBX_SID)) 	{
		m->stype = 'P'; /* make everything private */
		tputs(CcLine);
		if(mbxrecvline(m) != -1) {
			if(strlen(m->line)) 	{
				if(*m->line == 0x01) { /* CTRL-A, abort */
					free(rhdr);
					del_list(cclist);
					tputs(MsgAborted);
					return 0;
				}
				cp = m->line;
				/* get all the Cc addresses, separated by comma's */
				while((cp2=strchr(cp,',')) != NULLCHAR) 	{
					*cp2 = '\0';
					/*get rid of leading spaces or tabs*/
					while(*cp == ' ' || *cp == '\t')
						cp++;
					if(strlen(cp))	{
						cp = host_or_wpage_exp (strdup (cp), 0, 0);
						addlist(&cclist,cp,0,cp);
						free (cp);
					}
					cp = cp2 + 1;
				}
				/* Do the last or only one */
				/* get rid of leading spaces or tabs*/
				while(*cp == ' ' || *cp == '\t')
					cp++;
				if(strlen(cp))	{
					cp = host_or_wpage_exp (strdup (cp), 0, 0);
					addlist(&cclist,cp,0,cp);
					free (cp);
				}
			}
		} else {
			free(rhdr);
			del_list(cclist);
			return 0;
		}
	}

	/* Now check to make sure we can create the needed tempfiles - WG7J */
	if((m->tfile = tmpfile()) == NULLFILE) {
		free(rhdr);
		del_list(cclist);
		tputs((m->sid & MBX_SID) ? "NO - no temp file\n" : \
			"Can't create temp file for mail\n");
		return -2;	/* disconnect if no files!! */
	}
#ifdef RLINE
	pwait (NULL);		/* just to be nice to others */
	/* Only accept R: lines from bbs's */
	if((m->sid & MBX_SID)&&(Rdate || Rreturn || Rfwdcheck || Mbloophold)){
		/* Going to interpret R:headers, we need another tempfile !  */
		if((m->tfp = tmpfile()) == NULLFILE) {
			free(rhdr);
			del_list(cclist);
			tputs("NO - no temp file\n");
			return 0;
		}
		/* Now we got enough :-) */
		check_r = 1;
		Checklock++;
		/* Set the call, used in loop detect code - WG7J */
		if(Mbloophold) {
			pax25(Me,Mycall);
			if((cp = strchr(Me,'-')) != NULLCHAR)
				*cp = '\0'; /* remove SSID */
		}
	}
#endif

	m->state = MBX_SUBJ;
	pwait (NULL);		/* just to be nice to others */
	if(m->stype != 'R' || (m->sid & MBX_SID)) 	{
#ifdef FBBFWD
	  if(!Mfbb || !(m->sid & MBX_FBBFWD))
          /* Don't display the OK or Subject: tag on FBB forwards.	*/
#endif
		tputs((m->sid & MBX_SID) ? "OK\n" : "Subject:\n");
		if(mbxrecvline(m) == -1) {
#ifdef RLINE
			if(check_r) {
				MYFCLOSE(m->tfp);
				Checklock--;
			}
#endif
			free (rhdr);
			return 0;
		}
	} else				/* Replying to a message */
		tprintf("Subject: %s\n",m->line);

	m->subject = strdup(m->line);

#ifdef RLINE
	if(!check_r) {
#endif
		mbx_data(m,cclist,rhdr, returnreceipt);
		wrotedata = 1;
#ifdef RLINE
	}
#endif
	free(rhdr);
	m->state = MBX_DATA;
	pwait (NULL);		/* just to be nice to others */

#ifdef RMAIL
	if (m->change == -1)	{
		/* Write RMAIL line */
		fseek (m->tfile, -2, 1);
		for(ap = cclist; ap != NULLLIST; ap = ap->next) {
#if 0
			if(cccnt == 0)	{
				fprintf(m->tfile,"%s",Hdrs[TO]);
				cccnt = 4;
				cp2 = (m->origto) ? m->origto : m->to;
				cp = strchr (cp2, '.');
				i = (cp) ? (int)(cp - cp2) : strlen (cp2);
				fwrite (cp2, 1, i, m->tfile);
				cccnt += i;
			}
#endif
		        fprintf(m->tfile,", ");
		        cccnt += 2;
			fputs(ap->val,m->tfile);
			cccnt += strlen(ap->val);
			if (cccnt > 508)
				break;
		}
		if(cccnt)
			fputs("\n\n",m->tfile);
		del_list(cclist);
		cclist = NULLLIST;
	}
	pwait (NULL);		/* just to be nice to others */
#endif

	if(!(m->sid & MBX_SID))		{
		if((m->privs&SYSOP_CMD) && (m->origto != NULLCHAR || m->stype == 'R') && !strcmp(m->to, "check"))
			tprintf("\007The system doesn't know where to route this message..\nSuggest you abort this message and re-enter!\n");
		tprintf("Enter %smessage%s%s",(m->stype == 'F') ? "a personal " : "",
			(m->stype == 'F') ? " to precede the forwarded message.\n" : ".  ", Howtoend);
	}

	bbscolorchange (m, "07");
#if 0	/* now in mbx_data() */
	/* Add a return receipt line, if requested */
	if (returnreceipt)	{
		fseek (m->tfile, -1, 1);
		fprintf(m->tfile, "%s%s@%s\n\n", Hdrs[RRECEIPT],m->name,Hostname);
		returnreceipt = 0;
	}
#endif
	datastart = ftell (m->tfile);
	m->inmessage = 1;
	if(Rfwdcheck) {		/* checking sender here JUST IN CASE R: line is bad or missing */
		for(i=0;i<Numfwds;i++) {
			if(!stricmp(MyFwds[i],m->name)) {
				/*Found it !*/
				strcpy(fwdbbs[myfwds++],m->name);
				break;
			}
		}
	}
	while(!foundCTLz && ((recvsize = mbxrecvline(m)) != -1))	 {
		pwait (NULL);		/* just in case sender is hosing us */
		if ((cp = strchr (m->line, CTLZ)) != NULLCHAR)	{
        		*(cp+1) = 0;
        		*cp = '\n';
			foundCTLz = 1;
        	}
		if(!(m->sid & MBX_SID) && (m->line[0] == 0x01 || !strnicmp(m->line, "/a", 2)))		{  /* CTRL-A */
       		        MYFCLOSE(m->tfile);
#ifdef RLINE
			if(check_r)
				MYFCLOSE(m->tfp);
#endif
			tputs(MsgAborted);
			del_list(cclist);
			return 0;
		}
		userlevelending = (!strnicmp(m->line, "/e", 2) || !strnicmp(m->line, "/b", 2) || !strnicmp (m->line, "/q", 2) || !strcmp (m->line, ".")) ? 1 : 0;
		if (m->sid & MBX_SID)
			userlevelending = 0;
		if(m->line[0] != CTLZ && stricmp(m->line, "/ex") && !userlevelending) {
			if (*m->line == '/' && !(m->sid & MBX_SID))	{
				cp = &m->line[2];
				cp = skipnonwhite (cp);
				cp = skipwhite (cp);
				c = i = 0;
				switch (tolower (m->line[1]))	{
					case 'o':	i = 1;
					case 'v':	if (m->stype != 'R')
								break;
							if ((fp = tmpfile ()) != NULLFILE)	{
								tprintf ("%sOriginal message #%-d\n", stars, m->current);
								msgtofile(m, m->current, fp, i);
								rewind (fp);
								sendfile(fp, m->user, ASCII_TYPE,0);
								tprintf ("%s\n", stars);
								fclose (fp);
							}
							break;
					case 'f':	if (!(cp = permtest(m->path, m->privs,cp,RETR_CMD, NULLCHAR, 0)))
								break;
							if((fp = fopen(cp,READ_TEXT)) != NULLFILE)		{
								tprintf ("%sAdded file: %s\n", stars, cp);
								while(fgets(m->line,LINELEN,fp) != NULLCHAR)
									fputs(m->line,m->tfile);
								fclose(fp);
							}
							free (cp);
							break;
					case 'd':	if (*cp)
								i = atoi (cp);
							if (!i)
								i = 1;
							tprintf ("%sDeleted %d line%s\n", stars, i, (i - 1) ? "s" : "");
							here = ftell (m->tfile);
							while (here > 0)	{
								fseek (m->tfile, --here, SEEK_SET);
								if ((fgetc (m->tfile)) == '\n' && !(i--))
									break;
								fseek (m->tfile, here, SEEK_SET);
								putc ('\0', m->tfile);
							}
							break;
					case '/':	strcpy (m->line, &m->line[1]);
							c = 1;
							break;
					case 's':	nosig ^= 1;
							tprintf ("%sSignature o%s\n", stars, nosig ? "ff" : "n");
							break;
					case 'p':	here = ftell (m->tfile);
							fseek (m->tfile, datastart, SEEK_SET);
							sendfile(m->tfile,m->user,ASCII_TYPE,0);
							fseek (m->tfile, here, SEEK_SET);
							tprintf ("%s\n", stars);
							break;
					case 'c':	if(strlen(cp))	{
								cp = host_or_wpage_exp (strdup (cp), 0, 0);
								addlist(&cclist,cp,0,cp);
								tprintf ("%sAdded call: %s\n", stars, cp);
								free (cp);
							}
							break;
					case 'm':	i = atoi (cp);
							if (i && i <= m->nmsgs)	{
								msgtofile(m,i,m->tfile,0);
								tprintf ("%sAdded Message: %d\n", stars, i);
							}
							break;
					case 'h':
					case '?':	bbscolorchange (m, "0B");
							DisplayFile (EditorHelp, m->user);
							bbscolorchange (m, "07");
							break;
				}
				if (!c)
					continue;
			}

#ifdef RLINE
			if(check_r || check_r2) {
				pwait (NULL);		/* just to be nice to others */
				/* Check for R: lines to start with */
				/* Invalidate R: lines that don't have R:YYMMDD/ */
				if((!strnicmp(m->line,"R:",2)) && (*(m->line+8) == '/')) {	/* found one */
					found_r = 1;
					/*Write this line to the second tempfile
					 *for later rewriting to the real one   */
					fprintf(m->tfp,"%s\n",m->line);
					/* Find the '@[:]CALL.STATE.COUNTRY'or
					 * or the '?[:]CALL.STATE.COUNTRY' string
					 * The : is optional.     */
					if( ((cp=strchr(m->line,'@')) != NULLCHAR) || ((cp=strchr(m->line,'?')) != NULLCHAR) ) {
						if((cp2=strpbrk(cp," \n\t")) != NULLCHAR)
							*cp2 = '\0';
						/* Some bbs's send @bbs instead of @:bbs*/
						if (*++cp == ':')
							cp++;
#ifdef nope	/* was WPAGES, now done in smtpserv */
						if(MbWpages)
							wpageAdd (cp, 1, 1);
#endif
						pwait (NULL);		/* just to be nice to others */
						/* if we use 'return addres' copy whole 'domain' name */
						if(Rreturn)
							if((strlen(cp) <= OBLEN) && (strlen(cp)))
								strcpy(origbbs,cp);
						/* Optimize forwarding ? */
						if(Rfwdcheck || Mbloophold) {
							/*if there is a HADDRESS, cut off after '.'*/
							if((cp2=strchr(cp,'.')) != NULLCHAR)
								*cp2 = '\0';
							if(Mbloophold)
								/* check to see if this is my call ! */
								if(!stricmp(Me,cp))
									loops++;
							/*cross-check with MyFwds list*/
			                                if(Rfwdcheck) {
								for(i=0;i<Numfwds;i++) {
									if(!stricmp(MyFwds[i],cp)) {
										/*Found one !*/
										strcpy(fwdbbs[myfwds++],cp);
										break;
									}
								}
							}
						}
					}
					if(Rdate) {
						/* Find the 'R:yymmdd/hhmmz' string */
						if((cp=strchr(m->line,' ')) != NULLCHAR) {
							*cp = '\0';
							if(strlen(m->line+2) <= ODLEN)
								strcpy(origdate,m->line+2);
						}
					}
				} else {	/* if not R: line */
					/* The previous line was last R: line
					 * so we're done checking
					 * now write the smtp headers and
					 * all saved R: lines to the right tempfile	*/
					if (check_r)	{
						check_r = 0;
		                        	Checklock--;
		        	                if (Checklock < 0)
       	        			        	Checklock = 0;
					}
					check_r2 = 0;
					/*Did we actually find one ?*/
					if(found_r) {
						if(Rreturn)
							m->origbbs = strdup(strlwr(origbbs));
						if(Rdate) {
							if((cp=strchr(origdate,'/')) != NULLCHAR) {
								if((*(cp+5) == 'z') || (*(cp+5) == 'Z')) {
									*(cp+5) = '\0';
									zulu = 1;
								}
								t.tm_min = atoi(cp+3);
								*(cp+3) = '\0';
								t.tm_hour = atoi(cp+1);
								*cp = '\0';
								t.tm_mday = atoi(&origdate[4]);
								origdate[4] = '\0';
								t.tm_mon = (atoi(&origdate[2]) - 1);
								origdate[2] = '\0';
								t.tm_year = atoi(origdate);
								/* Set the date in rfc 822 format */
								m->date = mallocw(40);
								sprintf(m->date,"%.2d %s %02d %02d:%02d:00 %.3s\n",
									t.tm_mday, Months[t.tm_mon], t.tm_year, t.tm_hour, t.tm_min, zulu ? "UTC" : "");
							}
						}
					}
					/* Now write the headers,
					 * possibly adding Xforwarded lines for bulletins,
					 * or anything that has a BID.
					 * Add the X-Forwarded lines FIRST,
					 * this speeds up forwarding...  */
					if(Mbloophold && loops >= Mbloophold)
						fprintf(m->tfile,"%sLoop\n",Hdrs[XBBSHOLD]);
					if(Rfwdcheck && found_r && ((m->stype == 'B') || (m->tomsgid)) )	{
						/*write Xforwarded headers*/
						for(i=0;i<myfwds;i++)
							fprintf(m->tfile,"%s%s\n",Hdrs[XFORWARD],fwdbbs[i]);
					}
					/*write regular headers*/
					if (!wrotedata)	{
						mbx_data(m,cclist,NULLCHAR, returnreceipt);
						wrotedata = 1;
					}
					pwait (NULL);		/* just to be nice to others */

					/* Now copy the R: lines back */
					if(found_r) {
						char tmpline[MBXLINE];
						rewind(m->tfp);
						while(fgets(tmpline,sizeof(tmpline),m->tfp)!=NULLCHAR)	{
							pwait (NULL);		/* just to be nice to others */
							fputs(tmpline,m->tfile);
						}
					}
					MYFCLOSE(m->tfp);
						/* And add this first non-R: line */
					fprintf(m->tfile,"%s\n",m->line);
				}
			} else		{	/* not check_r or check_r2 */
#endif
				fprintf(m->tfile,"%s",m->line);
				if (recvsize != - 2)
					putc ('\n', m->tfile);
			}
		} else {	/* CTLZ or /ex */
#ifdef RLINE
			if(check_r) {
				/* Hmm, this means we never finished the R: headers
				 * tmp file still open !         */
				MYFCLOSE(m->tfp);
			}
#endif
			done = 1; /* To indicate the difference between
       	                           * mbxrecvline() returning -1 and /ex ! - WG7J
               	                   * Now also used to indicate if the message should
                       	           * be sent or not !    */
			/* Now ask users if they want to send this ! - WG7J */
			if( Mbsendquery && !(m->sid & MBX_SID)) {
				if(m->type == TELNET || m->type == TIP)
					c = tkeywait(sendthemail,0,m->linemode);
				else  /* For AX.25 and NET/ROM connects */
					c = mykeywait(sendthemail,m);
				if(c == -1 || c == 'n' || c == 'N') {
					done = 0;   /* signal delete of message */
					tputs(MsgAborted);
				}
			}
			break;  /* all done */
		}
	}
        if(!done && !foundCTLz) {
		/* We did NOT get ^Z or /EX, but mbxrecvline returned -1 !!!
		 * This means the connection is gone ! - WG7J	*/
		MYFCLOSE(m->tfile);
#ifdef RLINE
		if(check_r)
			MYFCLOSE(m->tfp);
#endif
		del_list(cclist);
/*     	        free(rhdr); */	/*Just in case*/
		return 0;
	}
	m->inmessage = 0;
	if (m->stype == 'F') {	/* type == 'F' */
		tputs ("Inserting original message...\n");
		usflush(m->user);
		fprintf(m->tfile,"----- Forwarded message -----\n\n");
		msgtofile(m,m->current,m->tfile,0);
		fprintf(m->tfile,"----- End of forwarded message -----\n");
	}

	/* Insert customized signature if one is found */
	if(!nosig && !(m->sid & MBX_SID)) {	/* not a forwarding BBS */
		char sigwork[LINELEN];
		sprintf(sigwork,"%s/%s.sig",Signature,m->tofrom ? m->tofrom : m->name);
		if((fp = fopen(sigwork,READ_TEXT)) != NULLFILE)		{
			while(fgets(sigwork,LINELEN,fp) != NULLCHAR)	{
				pwait (NULL);		/* just to be nice to others */
				fputs(sigwork,m->tfile);
			}
			fclose(fp);
		}
	}

	if((host = strrchr(m->to,'@')) == NULLCHAR) {
		host = Hostname;	/* use our hostname */
		if(m->origto != NULLCHAR) {
			/* rewrite_address() will be called again by our
			 * SMTP server, so revert to the original address.
			 */
		 	free(m->to);
			m->to = m->origto;
			m->origto = NULLCHAR;
		}
	} else
		host++;	/* use the host part of address */

	{
	char fullfrom[MBXLINE];

		/* make up full from name for work file */
		if(m->tofrom != NULLCHAR)
			sprintf(fullfrom,"%s%%%s@%s",m->tofrom, m->name, Hostname);
		else
			sprintf(fullfrom,"%s@%s",m->name,Hostname);
		if(cclist != NULLLIST && stricmp(host,Hostname) != 0) {
			fseek(m->tfile,0L,0);	/* reset to beginning */
			pwait (NULL);		/* just to be nice to others */
			fail = queuejob(m->tfile,Hostname,cclist,fullfrom);
			del_list(cclist);
			cclist = NULLLIST;
		}
		addlist(&cclist,m->to,0,m->to);
		fseek(m->tfile,0L,0);
		pwait (NULL);		/* just to be nice to others */
		fail += queuejob(m->tfile,host,cclist,fullfrom);
	}
	del_list(cclist);
	messagesize = filelength (fileno(m->tfile));
	MYFCLOSE(m->tfile);
	if(fail)	{
		if(!(m->sid & MBX_SID)) /* only when we're not a bbs */
			tputs("Couldn't queue message for delivery\n");
	} else {
		if(!(m->sid & MBX_SID)) /* only when we're not a bbs */
			tputs("Message queued\n");
		if(m->sid & MBX_SID)
			MbRecvd++;
		else	{
			MbSent++;
			if (MbHolding && m->stype == 'B')
				tputs("Bulletins are held till reviewed by the SYSOP\n");
		}
#ifdef notdef
		/* BID is now saved in the smtp server ! - WG7J */
		time(&now);
		if(m->tomsgid != NULLCHAR && (fp = fopen(Historyfile,APPEND_TEXT)) != NULLFILE) {
			fprintf(fp,"%s %ld\n",m->tomsgid,now); /* Save BID in history file */
			fclose(fp);
		}
#endif
		pwait (NULL);		/* just to be nice to others */
	}
	if (m->sid & MBX_SID) 	{
		m->mysize = ((m->mysize + 1) % 10);
		if (!m->mysize)
			smtptick(NULL);		/* wake SMTP to send that mail */
	} else		{
		char buf[50], *cp;
		sprintf (buf, "%s", Hostname);
		if((cp = strchr(buf,'.')) != NULLCHAR)
			*cp = '\0';
		strupr(buf);
		tprintf ("\n*** Message forwarding to: %s\n*** MID: ", m->to);
		if (m->tomsgid)
			tprintf (m->tomsgid);
		else
			tprintf ("%ld_%s", lastsentid, buf);
		tprintf ("    Size: %ld\n\n", messagesize);
		/* Instead of kicking off the smtp now, let it happen in a short time.
		 * That way the user gets the prompt back immediately, and the smtp kick
		 * will run when the user most likely is working on typing the next command.
		 * this *should* improve the user's perception of system's speed, and
		 * might speed up bbs forwarding a bit too... :-) - WG7J
		 */
		{
		#define WAITTM 5000L
	        extern struct timer Smtpcli_t;
        	long t;
        	int32 old;

		        stop_timer(&Smtpcli_t);
		        t = read_timer(&Smtpcli_t);
		        old = Smtpcli_t.duration;
		        if(t <= 0  || t > WAITTM)
		             set_timer(&Smtpcli_t,WAITTM);  /* set timer duration */
		        if(Smtpcli_t.func == NULL) {    /* in case not set yet */
		            Smtpcli_t.func = (void (*)__ARGS((void*)))smtptick;/* what to call on timeout */
		            Smtpcli_t.arg = NULL;       /* dummy value */
		        }
		        start_timer(&Smtpcli_t);        /* and fire it up */
		        Smtpcli_t.duration = old;
		}
#ifdef nope
		smtptick(NULL);     /* wake SMTP to send that mail */
#endif
	}
	pwait (NULL);
	return 0;
}

#ifdef NETROM
static int
dombnrnodes(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;

	m = (struct mbx *)p;

	if(argc < 2)
		return doroutedump();
    if(*argv[1] == '*')
        argc = 1;
    return dorouteinfo(argc,argv,p);
}
#endif

static int
dosid(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
char *cp, *flags;
#ifdef LZW
struct usock *up;
#endif

	m = (struct mbx *)p;
	if(argc == 1)
		return 1;
	if(argv[1][strlen(argv[1]) - 1] != ']') /* must be an SID */
		return 1;
	m->usecolor = 0;
#ifdef notdef
	if(m->stype == 'Z' && strnicmp(argv[1],"cz",2) == 0) {
		/* LAN-LINK's [ZCZ] */
		m->sid |= MBX_LL;
		return 0;
	}
#endif
	/* Other bbs's */
	m->sid = MBX_SID;

	/* Now check to see if this is an RLI board.
	 * As usual, Hank does it a bit differently from
	 * the rest of the world.
	 */
	if(m->stype == 'R' && strnicmp(argv[1],"li",2) == 0)/* [RLI] at a minimum */
		m->sid |= MBX_RLI_SID;
	else if(m->stype == 'F' && strnicmp(argv[1],"bb",2) == 0)/* [FBB] at a minimum */
		m->sid |= MBX_FBB;

	
	/* Check to see if the BBS supports a kludge called "hierarchical
	 * routing designators."
	 *
	 * No need to check for ']' -- it must be there or this is not
	 * a valid mbox id -- it is checked earlier (fix de OH3LKU)
	 *
	 * Sid format is [BBSTYPE-VERSION-OPTIONS]
	 * check for LAST -, to allow for version portion. - WG7J
	 */
	flags = strrchr(argv[1], '-');
	if(flags != NULLCHAR && (cp=strchr(flags+1,'h')) != NULLCHAR && strchr(cp+1,'$'))
		m->sid |= MBX_HIER_SID;
#ifdef LZW
	/* Check to see if it's another TNOS board */
	if (flags != NULLCHAR && (cp=strchr(flags+1, 't')) != NULLCHAR)	{
		if (m->state != MBX_FORWARD)	{	/* if forwarding, wait till we can send out SSID */
			up = itop(m->user);
			if(up->zout == NULLLZW)
	    			togglelzw (m->user, 1);
		}
    		m->sid |= MBX_TNOS;
	}
#endif
	if (flags != NULLCHAR && (cp=strchr (flags+1, 'm')) != NULLCHAR)
		m->sid |= MBX_MID;
	if (flags != NULLCHAR && (cp=strchr (flags+1, 'f')) != NULLCHAR)	{
		m->sid |= MBX_FBBFWD;
		if ((cp = strchr (flags+1, 'b')) != NULLCHAR)
			m->sid |= MBX_FBBCOMP;
	}
	m->mysize = 0;
	return 0;
}


int
dombescape(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;

	m = (struct mbx *)p;
	if(argc < 2)	{
	        tprintf("Escape is %s, Escape char: ", (m->privs & NO_ESCAPE) ? "OFF" : "ON");
		if(m->escape < 32)
			tprintf("CTRL-%c\n",m->escape+'A'-1);
		else
			tprintf("'%c'\n",m->escape);
		return 0;
	}
	if(strlen(argv[1]) > 1) {
		if(isdigit(*argv[1]))
			m->escape = (char) atoi(argv[1]);
		else {
			if( !strnicmp(argv[1],"OFF",3) || !strnicmp(argv[1],"dis",3) )
				m->privs |= NO_ESCAPE;
			else
				m->privs &= ~NO_ESCAPE;
		}
	} else
		m->escape = *argv[1];
	return 0;
}

/* Routine for finding out total number of messages for an area and the
   number of messages that are new to this user. Just reports NEW messages,
   does not check their read status (for personal areas). Though it USES the
   mbox structure, it returns it back to the previous state. This routine
   reads the area.ctl files, which just contain a bid for each message.  */

static void
statarea(m, area, total, new, hold, special)
register struct mbx *m;
char *area;
int *total, *new, *hold, special;
{
#ifdef USERLOG
long last, newlast;
char oldarea[20], buf[256];
FILE *fp;
long size;
struct let *lt;
register struct	let *cmsg;
register int i;
#endif
register int tnew, ttotal, thold;

	ttotal = tnew = thold = 0;
#ifdef USERLOG
	last = m->lastread;
	newlast = m->newlastread;
	m->lastread = 0;
	strcpy (oldarea, m->area);
	strcpy (m->area, area);
	if (!lockit (m))		{
		/* only read last read message-id if this is not a bbs,
		 * current area is a public area and not 'help'
		 * or area starts with 'sys'
		 * read in all cases if a SYSOP
		 */

		if(!(m->sid & MBX_SID))
			if( (stricmp(area,"help") && isarea(area)) || !strnicmp(m->area,"sys",3) || (m->privs & SYSOP_CMD))
				getlastread(m);
		pwait (NULL);
		sprintf (buf, "%s/control/%s", Mailspool, m->area);
		nntp_name_expansion (buf);
		strcat (buf, ".ctl");
		if ((fp = subdir_fopen (buf, READ_BINARY)) != NULLFILE)	{
			size = filelength (fileno(fp));
			lt = (struct let *) malloc ((unsigned)size);
			fread (lt, (unsigned)size, 1, fp);
			fclose(fp);
			ttotal = (int) (size / (long) sizeof(struct let));
			pwait(NULL);
			for (cmsg = lt,i = 0; i < ttotal; i++, cmsg++)
				if (!special)	{
					if ((cmsg->bid > m->lastread) && !(cmsg->status & BM_DELETE))
						tnew += 1;
					if (cmsg->status & BM_ONHOLD)
						thold += 1;
				} else	{
					if (!(cmsg->status & BM_READ))
						tnew += 1;
				}
			free (lt);
			}
		pwait (NULL);
		m->lastread = last;
		m->newlastread = newlast;
		rmlock (Mailspool, m->area);
		strcpy (m->area, oldarea);
		}
#endif
	*new = tnew;
	*total = ttotal;
	*hold = thold;
}


static int
doarea(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
char *cp, *area, *tmparea, *theone;
FILE *fp;
char buf[MBXLINE];
int k;
int hold, total, new, xtotal = 0, xnew = 0;
struct ffblk ff;

	m = (struct mbx *) p;
	if ((m->stype == 'F') && m->usecolor && !access (ANSIArea, 0))	{
		colorfile (ANSIArea, m->colorset);
		return 0;
	}
	if(argc < 2 || m->stype == 'N' || m->stype == 'S')		{
		area = strdup(m->area);
		tmparea = strdup(m->area);
		while((cp = strchr(tmparea,'/')) != NULLCHAR)
			*cp = '.';
		bbscolorcls (m);
		tprintf("Current message area is: %s\n\n",tmparea);
		free (tmparea);

		bbscolorchange (m, "0B");
		tputs("Available areas are:\n");
		total = m->nmsgs;
		new = m->newmsgs;
		if (stricmp (m->area, m->name))		{
			changearea(m,m->name, (int) 1);
		}
		else
			scanmail (m);
		if ((m->stype == 'N' && m->newmsgs) || m->stype != 'N')	{
			bbscolorchange (m, "09");
			tprintf ("%-15s  ",m->name);
		}
		if(m->stype == 'F')
			tputs("  Your private mail area\n");
		else if ((m->stype == 'S') || (m->stype == 'N' && m->newmsgs))	{
			bbscolorchange (m, "07");
			tprintf(MessageData, m->nmsgs,
				m->nmsgs == 1 ? " " : "s", m->newmsgs);
/*			tprintf(MessageData, total,total == 1 ? " " : "s", new); */
			xtotal += total;
			xnew += new;
		}
		else if (m->stype != 'N')
			tputc('\n');
		theone = Arealist;
		if((m->privs & SYSOP_CMD) && (!access(AreaSlist, 0)))
			theone = AreaSlist;
		if((fp = fopen(theone,READ_TEXT)) == NULLFILE)
			return 0;
		if(m->stype == 'F')	{
			sendfile(fp,m->user,ASCII_TYPE,0);
			tputc('\n');
			}
		else if (m->stype == 'S' || m->stype == 'N')	{
			while(fgets(buf,MBXLINE,fp) != NULLCHAR) 	{
				pwait(NULL);
				if(isalnum(buf[0])) 	{ /* skip comments */
					if((cp=strpbrk(buf," \t")) != NULLCHAR)
						*cp = '\0';
					statarea (m, buf, &total, &new, &hold, 0);
					if (m->stype == 'S' || new)	{
						bbscolorchange (m, "09");
						tprintf ("%-15.15s  ", buf);
						bbscolorchange (m, "07");
						if ((m->privs & SYSOP_CMD) && hold)
							tprintf(SMessageData, total,
								total == 1 ? " " : "s", new, hold);
						else
							tprintf(MessageData, total,
								total == 1 ? " " : "s", new);
						usflush(Curproc->output);
						xtotal += total;
						xnew += new;
						}
					}
				}
			if ((m->privs & SYSOP_CMD) && argv[1][0] == 'a')	{	/* also list mailfor's if 'AN|S all' */
				sprintf(buf,"%s/*.txt",Mailspool);
				if (findfirst(buf, &ff, 0) == 0)	{
					do	{
						pwait(NULL);    /* Let others run */
						*(strchr(ff.ff_name,'.')) = '\0';
						/*must be private mail area, and not on exclude list !*/
						if(!issysarea(ff.ff_name)) {
							if (!stricmp (ff.ff_name, m->name))
								continue;
							statarea (m, ff.ff_name, &total, &new, &hold, 1);
							if (m->stype == 'S' || new)	{
								bbscolorchange (m, "09");
								tprintf ("%-15.15s  ", ff.ff_name);
								bbscolorchange (m, "07");
								tprintf(MessageData, total,
									total == 1 ? " " : "s", new);
								usflush(Curproc->output);
								xtotal += total;
								xnew += new;
								}
						}
					} while (findnext(&ff) == 0);
				}
			}
			bbscolorchange (m, "0B");
			tputs("*** Total ***    ");
			tprintf(MessageData, xtotal,xtotal == 1 ? " " : "s", xnew);
			usflush(Curproc->output);
			tputc('\n');
			}
		else 		{
			/* send only the area names, not the description */
			k = 0;
			while(fgets(buf,MBXLINE,fp) != NULLCHAR) 	{
				if(isalnum(buf[0])) 	{ /* skip comments */
					if((cp=strpbrk(buf," \t")) != NULLCHAR)
						*cp = '\0';
					tprintf ("%-15.15s", buf);
					if (++k == 5)	{
						tputc('\n');
						k = 0;
						}
					}
				}
			if (k)
				tputc('\n');
			bbscolorchange (m, "0A");			
			tputs("\nType AF to get description of areas\n\n");
			}
		if (stricmp (area, m->area))
			changearea(m,area, (int) 0);			
		free(area);
		fclose(fp);
		return 0;
		}
	if((m->privs & SYSOP_CMD) || stricmp(m->name,argv[1]) == 0){
		/*Private mail-areas*/
		changearea(m,argv[1], (int) 1);
		if(m->nmsgs && !(m->privs&IS_BBS)){
			if(!stricmp(m->name,m->area))
		                tputs("You have ");
			else {
				area = strdup(m->area);
				while((cp = strchr(area,'/')) != NULLCHAR)
					*cp = '.';
				tprintf("%s: ",area);
				free(area);
			}
			tprintf((m->hmsgs) ? SMessageData : MessageData, m->nmsgs,
			  m->nmsgs == 1 ? " " : "s", m->newmsgs, m->hmsgs);
		}
		if (m->stype == 'L')	{
			m->stype = ' ';
			dolistnotes (0, 0, m);
		}
		return 0;
	}
	if(isarea(argv[1])) {
		/*Public mail areas*/
		changearea(m,argv[1], (int) 1);
		area = strdup(m->area);
		while((cp = strchr(area,'/')) != NULLCHAR)
			*cp = '.';
		if (!(m->privs & IS_BBS))
#ifdef USERLOG
			tprintf("%s: %d message%s -  %d new\n",area,m->nmsgs,
				m->nmsgs == 1 ? " " : "s ", m->newmsgs);
#else
		        tprintf("%s: %d message%s.\n", area, m->nmsgs,
			        m->nmsgs == 1 ? "" : "s");
#endif
	        free(area);
		if (m->stype == 'L')	{
			m->stype = ' ';
			dolistnotes (0, 0, m);
		}
	}
	else
		tprintf("No such message area: %s\n",argv[1]);
	return 0;
}

char *
nntp_name_expansion (name)
char *name;
{
#if 1
char *cp;

	while((cp = strpbrk(&name[1],".\\")) != NULLCHAR)
		*cp = '/';
#endif
	return name;
}


/* subroutine to do the actual switch from one area to another */
/* USERLOGGING added by WG7J */
void
changearea(m,area,setit)
struct mbx *m;
char *area;
int setit;
{
#ifdef USERLOG
    if (setit)
         setlastread(m);
#endif
	closenotes(m);
	m->nmsgs = m->newmsgs = m->current = 0;
	strcpy(m->area,area);
	nntp_name_expansion (m->area);

#ifdef USERLOG
	/* only read last read message-id if this is not a bbs,
	 * current area is a public area and not 'help'
	 * or area starts with 'sys'
	 * read in all cases if a SYSOP
	 */
	if(!(m->sid & MBX_SID))
		if( (stricmp(area,"help") && isarea(area)) || !strnicmp(m->area,"sys",3) || (m->privs & SYSOP_CMD))
			getlastread(m);
#endif
	scanmail(m);
}

/* Generic mbox gateway code. It sends and frees the contents of m->startmsg
 * when the connection has been established unless it a null pointer.
 */
int
gw_connect(m,s,fsocket,len)
struct mbx *m;
int s;
struct sockaddr *fsocket;
int len;
{
int c;
char *cp, *cp1;
struct proc *child;
struct gwalarm *gwa;
char *tocall, whereto[128], buf[80];
#ifdef NETROM
char *node;
char temp[AXBUF];
struct nrroute_tab *rp;
#endif

    sockmode(s,SOCK_ASCII);
    child = newproc("gw supervisor",256,gw_superv,0,Curproc,m,0);
    tputs("Trying...");
    if(m->privs & NO_ESCAPE)
        tputc('\n');
    else {
        tputs("  The escape character is: ");
        if(m->escape < 32)
            tprintf("CTRL-%c\n",m->escape+'A'-1);
        else
            tprintf("'%c'\n",m->escape);
    }
    usflush(Curproc->output);

    /*find out where we're going to*/
    tocall = strdup(psocket(fsocket));
    if((cp1 = strchr(tocall,' ')) != NULLCHAR)
		*cp1 = '\0';
#ifdef NETROM
    if(fsocket->sa_family == AF_NETROM) {
        /*find the node alias*/
        setcall(temp,tocall);
        rp = find_nrroute(temp);
        node = strdup(rp->alias);
        if((cp1 = strchr(node,' ')) != NULLCHAR)
                    *cp1 = '\0';
        sprintf(whereto,"%s:%s",node,tocall);
        free(node);
    } else
#endif
	 strcpy(whereto,tocall);
    free(tocall);

    if(connect(s,(char *)fsocket,len) == -1){
		if((cp = sockerr(s)) != NULLCHAR) {
			switch(cp[0]) {
			case 'R':
				sprintf(buf,"%susy from",
					(m->family == AF_NETROM)?"B":"*** b");
				break;
			case 'T':
				if(m->family != AF_NETROM) {
					sprintf(buf,"*** timeout with");
					break;
				}
			default:
				sprintf(buf,"%sailure with",
					(m->family == AF_NETROM)?"F":"*** f");
				break;
			}
            tprintf("%s%s %s\n\n",
                (m->family == AF_NETROM) ? Mbnrid : "",buf,whereto);
		}
        shutdown(s,2);  /* HB9RWM suggestion */
        close_s(s);
		killproc(child);
        /* Free m->starmsg if set ! - WG7J */
        if(m->startmsg != NULLCHAR) {
            free(m->startmsg);
            m->startmsg = NULLCHAR;
        }

        return 0;
	}
    /* The user did not type the escape character */
	killproc(child);

	tprintf("%s%sonnected to %s\n",
        (m->family == AF_NETROM) ? Mbnrid : "",
		(m->family == AF_NETROM) ? "C" : "*** c",
        whereto);

	if(m->startmsg != NULLCHAR){
		usputs(s,m->startmsg);
		free(m->startmsg);
		m->startmsg = NULLCHAR;
	}

	/* Since NOS does not flush the output socket after a certain
	 * period of time, we have to arrange that ourselves.
	 */
	gwa = (struct gwalarm *) mallocw(sizeof(struct gwalarm));
	gwa->s1 = Curproc->output;
	gwa->s2 = s;
    set_timer(&gwa->t,2*1000L);
	gwa->t.func = gw_alarm;
	gwa->t.arg = (void *) gwa;
	start_timer(&gwa->t);
	/* Fork off the receive process */
    child = newproc("gw in",1024,gw_input,s,m,Curproc,0);

	for(;;){
		if((c = recvchar(Curproc->input)) == EOF)
			break;
        /* Only check ESCAPE char if that is currently turned on */
        if( !(m->privs & NO_ESCAPE) && c == m->escape){
            if(socklen(Curproc->input,0))
                recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0);
			break;
        }
#ifdef MBXTDISC
        if(c == '\n')
            start_timer(&m->tdisc);
#endif
        if(usputc(s,c) == EOF)
			break;
	}
	stop_timer(&gwa->t);
	free((char *)gwa);
	close_s(s);
	killproc(child); /* get rid of the receive process */
    if(m->family == AF_INET)
		tprintf("%c%c%c\n",IAC,WONT,TN_ECHO);
#ifdef TTYCALL
	if (fsocket->sa_family == AF_INET &&
	    ((struct sockaddr_in *) fsocket)->sin_port == IPPORT_TTYLINK &&
	    ismyaddr((int32)((struct sockaddr_in *) fsocket)->sin_addr.s_addr))
	    return 2;		/* magic success code to avoid BBS chaining */
#endif
	return 0;
}

static void
gw_input(s,notused,p)
int s;
void *notused;
void *p;
{
int c;
struct proc *parent;
struct mbx *m;
char *cp, *cp1;
char response[4];

	parent = (struct proc *) p;
	m = (struct mbx *) notused;

    cp1 = strdup(Mbnrid);
    if((cp = strchr(cp1,'}')) != NULLCHAR)
		*cp = '\0';
	strupr(cp1);

#ifdef notdef
    while((c = recvchar(s)) != EOF)
		tputc(c);
#endif
    while((c = recvchar(s)) != EOF){
		if(c != IAC){
			tputc((char)c);
			continue;
		}
		/* IAC received, get command sequence */
		c = recvchar(s);
		switch(c){
		case WILL:
			response[0] = IAC;
			response[1] = DONT;
			response[2] = recvchar(s);
			response[3] = '\0';
			usputs(s,response);
			break;
		case WONT:
		case DONT:
			c = recvchar(s);
			break;
		case DO:
			response[0] = IAC;
			response[1] = WONT;
			response[2] = recvchar(s);
			response[3] = '\0';
			usputs(s,response);
			break;
		case IAC:	/* Escaped IAC */
			usputc(s,IAC);
			break;
		}
    }

	if((cp = sockerr(s)) != NULLCHAR && m->family != AF_NETROM) {
		switch(cp[0]) {
		case 'T':
            usprintf(m->user,"\n*** %s: Link failure",cp1);
			break;
		case 'R':
			usprintf(m->user,"*** DM received");
			break;
		}
	}
    usprintf(m->user,"\n%s%seconnected to %s\n\n",
        (m->family == AF_NETROM) ? Mbnrid : "",
		(m->family == AF_NETROM) ? "R" : "*** r",
		cp1);

	free(cp1);
	cp1 = NULLCHAR;

	/* Tell the parent that we are no longer connected */
	alert(parent,ENOTCONN);
	pwait(Curproc); /* Now wait to be killed */
}

/* Check if the escape character is typed while the parent process is busy
 * doing other things. 
 */
static void
gw_superv(null,proc,p)
int null;
void *proc;
void *p;
{
struct proc *parent;
struct mbx *m;
int c;

	parent = (struct proc *) proc;
	m = (struct mbx *) p;
	while((c = recvchar(Curproc->input)) != EOF)
		if(c == m->escape){
			/* flush anything in the input queue */
			if(socklen(Curproc->input,0))
				recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0);
			break;
		}
	alert(parent,EINTR);	 /* Tell the parent to quit */
	pwait(Curproc);		 /* Please kill me */
}

static void
gw_alarm(p)
void *p;
{
struct gwalarm *gwa = (struct gwalarm *)p;
char oldbl;
struct usock *up;

	/* Flush sockets s1 and s2, but first make sure that the socket
	 * is set to non-blocking mode, to prevent the flush from blocking
	 * if the high water mark has been reached.
	 */
	if((up = itop(gwa->s1)) != NULLUSOCK) {
		oldbl = up->noblock;
		up->noblock = 1;
		usflush(gwa->s1);
		up->noblock = oldbl;
	}
	if((up = itop(gwa->s2)) != NULLUSOCK) {
		oldbl = up->noblock;
		up->noblock = 1;
		usflush(gwa->s2);
		up->noblock = oldbl;
	}
	start_timer(&gwa->t);
}

/* States for send line parser state machine */
#define		LOOK_FOR_USER		2
#define		IN_USER			3
#define		AFTER_USER		4
#define		LOOK_FOR_HOST		5
#define		IN_HOST			6
#define		AFTER_HOST		7
#define		LOOK_FOR_FROM		8
#define		IN_FROM			9
#define		AFTER_FROM		10
#define		LOOK_FOR_MSGID		11
#define		IN_MSGID		12
#define		FINAL_STATE		13
#define		ERROR_STATE		14

/* Prepare the addressee.  If the address is bad, return -1, otherwise
 * return 0
 */
static int
mbx_to(argc,argv,p)
int argc;
char *argv[];
void *p;
{
register char *cp;
register struct mbx *m;
register int state, i;
char *user, *host, *from, *msgid;
int userlen = 0, hostlen = 0, fromlen = 0, msgidlen = 0;

	m = (struct mbx *)p;
	/* Free anything that might be allocated
	 * since the last call to mbx_to() or mbx_reply()
	 */
	free(m->to);
	m->to = NULLCHAR;
	free(m->tofrom);
	m->tofrom = NULLCHAR;
	free(m->tomsgid);
	m->tomsgid = NULLCHAR;
	free(m->origto);
	m->origto = NULLCHAR;
    free(m->origbbs);
    m->origbbs = NULLCHAR;
    free(m->subject);
    m->subject = NULLCHAR;
    free(m->date);
    m->date = NULLCHAR;

	if(argc == 1)
		return -1;
#ifdef __GNUC__
	user = 0;		/* shut gcc warnings off */
	host = 0;
	from = 0;
	msgid = 0;
#endif
	i = 1;
	cp = argv[i];
	state = LOOK_FOR_USER;
	while(state < FINAL_STATE){
#ifdef MBDEBUG
		tprintf("State is %d, char is %c\n", state, *cp);
#endif
		switch(state){
		case LOOK_FOR_USER:
			if(*cp == '@' || *cp == '<' || *cp == '$'){
				state = ERROR_STATE;		/* no user */
			} else {
				user = cp;			/* point at start */
				userlen++;			/* start counting */
				state = IN_USER;
			}
			break;
		case IN_USER:
			switch(*cp){
			case '\0':
				state = AFTER_USER;		/* done with username */
				break;
			case '@':
				state = LOOK_FOR_HOST;		/* hostname should follow */
				break;
			case '<':
				state = LOOK_FOR_FROM;		/* from name should follow */
				break;
			case '$':
				state = LOOK_FOR_MSGID;	/* message id should follow */
				break;
			default:
				userlen++;			/* part of username */
			}
			break;
		case AFTER_USER:
			switch(*cp){
			case '@':
				state = LOOK_FOR_HOST;		/* hostname follows */
				break;
			case '<':
				state = LOOK_FOR_FROM;		/* fromname follows */
				break;
			case '$':
			state = LOOK_FOR_MSGID;	/* message id follows */
				break;
			default:
				state = ERROR_STATE;
			}
			break;
		case LOOK_FOR_HOST:
			if(*cp == '@' || *cp == '<' || *cp == '$'){
				state = ERROR_STATE;
				break;
			}
			if(*cp == '\0')
				break;
			host = cp;
			hostlen++;
			state = IN_HOST;
			break;
		case IN_HOST:
			switch(*cp){
			case '\0':
				state = AFTER_HOST;		/* found user@host */
				break;
			case '@':
				state = ERROR_STATE;		/* user@host@? */
				break;
			case '<':
				state = LOOK_FOR_FROM;		/* fromname follows */
				break;
			case '$':
				state = LOOK_FOR_MSGID;	/* message id follows */
				break;
			default:
				hostlen++;
			}
			break;
		case AFTER_HOST:
			switch(*cp){
			case '@':
				state = ERROR_STATE;		/* user@host @ */
				break;
			case '<':
				state = LOOK_FOR_FROM;		/* user@host < */
				break;
			case '$':
				state = LOOK_FOR_MSGID;	/* user@host $ */
				break;
			default:
				state = ERROR_STATE;		/* user@host foo */
			}
			break;
		case LOOK_FOR_FROM:
			if(*cp == '@' || *cp == '<' || *cp == '$'){
				state = ERROR_STATE;
				break;
			}
			if(*cp == '\0')
				break;
			from = cp;
			fromlen++;
			state = IN_FROM;
			break;
		case IN_FROM:
			switch(*cp){
			case '\0':
				state = AFTER_FROM;		/* user@host <foo */
				break;
			case '<':
				state = ERROR_STATE;		/* user@host <foo< */
				break;
			case '$':
				state = LOOK_FOR_MSGID;	/* message id follows */
				break;
			default:
				fromlen++;
			}
			break;
		case AFTER_FROM:
			switch(*cp){
			case '@':				/* user@host <foo @ */
			case '<':				/* user@host <foo < */
				state = ERROR_STATE;
				break;
			case '$':
				state = LOOK_FOR_MSGID;	/* user@host <foo $ */
				break;
			default:
				state = ERROR_STATE;		/* user@host foo */
			}
			break;
		case LOOK_FOR_MSGID:
			if(*cp == '\0')
				break;
			msgid = cp;
			msgidlen++;
			state = IN_MSGID;
			break;
		case IN_MSGID:
			if(*cp == '\0')
				state = FINAL_STATE;
			else
				msgidlen++;
			break;
		default:
			/* what are we doing in this state? */
			state = ERROR_STATE;
		}
		if(*(cp) == '\0'){
			++i;
			if(i < argc)
			cp = argv[i];
			else break;
		} else
			++cp;
	}
	if(state == ERROR_STATE || state == LOOK_FOR_HOST
	 || state == LOOK_FOR_FROM || state == LOOK_FOR_MSGID)
		return -1;		/* syntax error */

	m->to = mallocw((unsigned)(userlen + hostlen + 2));

	strncpy(m->to, user, (unsigned)userlen);
	m->to[userlen] = '\0';

	if(hostlen){
		m->to[userlen] = '@';
		strncpy(m->to + userlen + 1, host, (unsigned)hostlen);
		m->to[userlen + hostlen + 1] = '\0';
	}
	if(fromlen){
		m->tofrom = mallocw((unsigned)(fromlen + 1));
		strncpy(m->tofrom, from, (unsigned)fromlen);
		m->tofrom[fromlen] = '\0';
	}
	if(msgidlen){
		m->tomsgid = mallocw((unsigned)(msgidlen + 1));
		strncpy(m->tomsgid, msgid, (unsigned)msgidlen);
		m->tomsgid[msgidlen] = '\0';
	}
	return 0;
}

/* This opens the data file and writes the mail header into it.
 * Returns 0 if OK, and -1 if not.
 */
int
mbx_data(m,cclist,extra, returnreceipt)
struct mbx *m;
struct list *cclist;	/* list of carbon copy recipients */
char *extra;        /* optional extra header lines */
int returnreceipt;
{
time_t t;
struct list *ap;
int cccnt = 0;
char buf[80];
char stype, *cp = NULLCHAR;
	
#ifdef notdef
    time(&t);
/*These 2 lines get added again when the smtp-server handles the mail
 *not really needed - WG7J
 */
    fprintf(m->tfile,Hdrs[RECEIVED]);
	if(m->tofrom != NULLCHAR)
		fprintf(m->tfile,"from %s ",m->name);
	fprintf(m->tfile,"by %s (%s)\n\tid AA%ld ; %s",
        Hostname, Version, get_msgid(0),ptime(&t));
#endif

#ifdef nope
	if(!isspace(m->stype) && ((m->stype != 'R' && m->stype != 'F') ||
	  (m->sid & MBX_SID) !=0))
		  fprintf(m->tfile,"%s%c\n", Hdrs[BBSTYPE],m->stype);
#else
	stype = m->stype;
	if(isspace(stype) || stype == 'R' || stype == 'F')
		stype = 'P';
	fprintf(m->tfile,"%s%c\n", Hdrs[BBSTYPE],stype);
#endif

    /* If m->date is set, use this one (comes from bbs-forwarded mail) */
    if(m->date != NULLCHAR)
        fprintf(m->tfile,"%s%s",Hdrs[DATE],m->date);
    else {
        time(&t);
        fprintf(m->tfile,"%s%s",Hdrs[DATE],ptime(&t));
    }

    /* Bulletin ID, if any */
	fprintf(m->tfile,Hdrs[MSGID]);
	if(m->tomsgid)
		fprintf(m->tfile,"<%s@%s.bbs>\n", m->tomsgid, m->name);
	else	{
		lastsentid = get_msgid(1);
		fprintf(m->tfile,"<%ld@%s>\n",lastsentid, Hostname);
	}

    /* From : , could use 'real bbs address', if origbbs is set */
    fprintf(m->tfile,Hdrs[FROM]);
    if(m->tofrom) {  /* BBS style '< call' */
        if(m->origbbs != NULLCHAR)
            sprintf(buf,"%s@%s\n",m->tofrom,m->origbbs);
        else
            sprintf(buf,"%s%%%s@%s\n",m->tofrom, m->name, Hostname);
    } else {
        if(m->origbbs != NULLCHAR)
            sprintf(buf,"%s@%s\n",m->name,m->origbbs);
        else
            sprintf(buf,"%s@%s ",m->name,Hostname);
    }

#ifdef WPAGES
    if(m->origbbs != NULLCHAR)	{
	char *cptr;
	cptr = strdup (buf);
	rip (cptr);
    	wpageAdd (buf, 0, 1);	/* update users file */
	free (cptr);
    }
#endif
    if (!m->tofrom && m->origbbs == NULLCHAR)	{
            if (strcmp(m->realname, "()"))	{
            	strcat (buf, m->realname);
            }
	    strcat (buf, "\n");
    }
    fputs (buf, m->tfile);
    if ((m->origto != NULLCHAR) && ((cp = strchr (m->origto, '(')) != 0))
    	*(cp-1) = 0;
    fprintf(m->tfile,"%s%s\n",Hdrs[TO],m->origto != NULLCHAR ? m->origto : m->to);
    if (cp)
    	*(cp-1) = ' ';

    if (m->change != -1)	{
	    /* Write Cc: line */
		for(ap = cclist; ap != NULLLIST; ap = ap->next) {
			if(cccnt == 0){
				fprintf(m->tfile,"%s",Hdrs[CC]);
				cccnt = 4;
			}
			else {
			       fprintf(m->tfile,", ");
			       cccnt += 2;
			}
			if(cccnt + strlen(ap->val) > 80 - 3) {
			       fprintf(m->tfile,"\n    ");
			       cccnt = 4;
			}
			fputs(ap->val,m->tfile);
			cccnt += strlen(ap->val);
		}
		if(cccnt)
			fputc('\n',m->tfile);
    }
    fprintf(m->tfile,"%s%s\n",Hdrs[SUBJECT],m->subject);

#ifdef notdef
    /*not really needed, the 'From <user%fwdbbs@host>' shows this too!*/
    /* Also store the 'real smtp from' address */
    if((m->tofrom != NULLCHAR) && (m->origbbs != NULLCHAR))
        fprintf(m->tfile,"%s%s%%%s@%s\n",Hdrs[XFROM],m->tofrom,m->name, Hostname);
#endif

    if(extra != NULLCHAR)
		fprintf(m->tfile,extra);

        /*Finish smtp headers*/
        fprintf(m->tfile,"\n");

	/* RFC headers in data area, unless this is a "SC" message */
        if(m->stype != 'C' && Smtpheaders && m->origbbs == NULLCHAR)	{
        	char *cp;
        	
		fprintf(m->tfile,Hdrs[MSGID]);
		if(m->tomsgid)
			fprintf(m->tfile,"%s\n", m->tomsgid);
		else	{
			strcpy (buf, Hostname);
			if((cp = strchr(buf,'.')) != NULLCHAR)
				*cp = '\0';
			fprintf(m->tfile,"%ld_%s\n",lastsentid, buf);
		}

		/* Add a return receipt line, if requested */
		if (returnreceipt)	{
		        pax25(buf,Mycall);
        	        if((cp = strchr(buf,'-')) != NULLCHAR)
            		    *cp = '\0'; /* remove SSID */
	            	strlwr (buf);
			fprintf(m->tfile, "%s%s@%s", Hdrs[RRECEIPT],m->name,buf);
		
			sprintf(buf,"%s%s ", (Mbhaddress != NULLCHAR) ? "." : "",
				(Mbhaddress != NULLCHAR) ? Mbhaddress : "");
			strlwr (buf);
			if (strcmp(m->realname, "()"))
		            	strcat (buf, m->realname);
		        strcat (buf, "\n");
			fputs (buf, m->tfile);
		}

		if (isgroup (m->to))
			fprintf (m->tfile, "%s%s@%s\n",  Hdrs[XMAILGROUP], m->to, Hostname);

	        pax25(buf,Mycall);
                if((cp = strchr(buf,'-')) != NULLCHAR)
            	    *cp = '\0'; /* remove SSID */
            	strlwr (buf);
		fprintf(m->tfile,"%s%s@%s", Hdrs[FROM], m->name, buf);
		
		sprintf(buf,"%s%s ", (Mbhaddress != NULLCHAR) ? "." : "",
			(Mbhaddress != NULLCHAR) ? Mbhaddress : "");
		strlwr (buf);
		if (strcmp(m->realname, "()"))
	            	strcat (buf, m->realname);
	        strcat (buf, "\n");
		fputs (buf, m->tfile);
		
		cp = (m->origto != NULLCHAR) ? m->origto : m->to;
		fprintf(m->tfile,"%s%s",Hdrs[TO],cp);
		if ((cp = mblookname (NULLMBX, cp)) != 0)	{
			fputs (cp, m->tfile);
			free (cp);
		}
		fputs("\n\n", m->tfile);
	}
	return 0;
}


/* Attempt to determine if this is third-party mail. */
static int 
thirdparty(m)
struct mbx *m;
{
char buf[MBXLINE], *cp, *rp;
FILE *fp;

	if(strpbrk(m->to,"@%!") != NULLCHAR)
		return 0;

	rp = strdup(Hostname);

	if((cp = strchr(rp, '.')) != NULLCHAR)
		*cp = '\0';

	if(stricmp(m->to,rp) == 0){
		free(rp);
		return -1;
	}
	free(rp);

	if(stricmp(m->to,"sysop") == 0)
		return -1;

	if((fp = fopen(Arealist,READ_TEXT)) == NULLFILE)
		return 0;

	while(fgets(buf,MBXLINE,fp) != NULLCHAR){
		/* The first word on each line is all that matters */
		if((cp = strpbrk(buf, " \t")) != NULLCHAR)
			*cp = '\0';
		if(stricmp(m->to,buf) == 0){
			fclose(fp);
			return -1;
		}
	}
	fclose(fp);
	return 0;
}

#ifdef NETROM
extern struct nrroute_tab *find_nrboth __ARGS((char *alias,char *call));
#endif

static int
dombconnect(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
int ndigis,i,s;
struct sockaddr_ax alsocket;    /*the local socket*/
struct sockaddr_ax afsocket;    /*the remote socket*/
struct iface *ifp;
#ifdef NETROM
struct nrroute_tab *np;
struct sockaddr_nr lsocket,fsocket;
char alias[AXBUF];
#endif
char local_call[AXALEN];
char digis[MAXDIGIS][AXALEN];
char target[AXALEN];
#ifdef CONVERS
struct session *sp;
#endif
char tmp[AXBUF];
int didrose = 0;

    m = (struct mbx *) p;

	if(argc == 1){
#ifdef  CONVERS
        if(!Mbconverse) {
            tputs("Conference server not enabled\n");
            return 0;
        }
        if(m->privs & NO_CONVERS) {
            tputs(Noperm);
	    mail_error("%s: converse denied\n",m->name);
            return 0;
        }
#ifdef GWTRACE
        log(m->user,"MBOX CONFERENCE: %s",m->name);
#endif
        m->state = MBX_CONVERS;
	usflush(Curproc->output);
	if (Current->type == 1)
		tprintf ("%c%c", IAC, CLEARSCREEN);	/* sets Current->split */
	sp = Current;
	pwait (NULL);
        mbox_converse(m->user, m->name, (int) -1, m);
        if (sp->split)	{
		usflush(Curproc->output);
		tprintf ("%c%c", IAC, CLEARSPLIT);	/* clears Current->split */
		usflush(Curproc->output);
	        sp->split = 0;
	}
#else
        dombconnecthelp();
#endif
		return 0;
	}

    if(MBSecure)
#ifdef NETROM
        if((m->family != AF_AX25) && (m->family != AF_NETROM)) {
#else
		if(m->family != AF_AX25) {
#endif
            tputs(Noperm);
        mail_error("%s: gateway denied (secure mode): %s\n",m->name,cmd_line(argc,argv,m->stype));
            return 0;
        }

    if (argc == 2) {
#ifndef NETROM
		dombconnecthelp();
		return 0;
	}
#else
        /*NETROM connection wanted*/
        if(!(m->privs & NETROM_CMD)) {
            tputs(Noperm);
	    mail_error("%s: NETROM gate to %s denied\n",m->name,argv[1]);
            return 0;
        }

        if(Nr_iface == NULLIF){
            tputs("NET/ROM not activated.\n\n");
            return 0;
        }
        /* See if the requested destination is a known alias or call,
         * use it if it is.  Otherwize give an error message.
         */
        putalias(alias,argv[1],0);
        strupr(argv[1]);    /*make sure it's upper case*/
        if((np = find_nrboth(alias,argv[1])) == NULLNRRTAB){
            /*no such call or node alias*/
            tputs("no such node\n\n");
            dombconnecthelp();
            dombports(0,NULL,NULL);
            return 0;
        }

        if((s = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1){
            tputs(Nosock);
            return 0;
        }
#ifdef GWTRACE
		log(m->user,"MBOX NETROM: %s to %s",m->name,argv[1]);
#endif
		lsocket.nr_family = AF_NETROM;

        /* Set up our local username, bind would use Mycall instead */
        memcpy(lsocket.nr_addr.user,m->call,AXALEN);
        /* Set up our source address */
        memcpy(lsocket.nr_addr.node,Nr_iface->hwaddr,AXALEN);

        bind(s,(char *)&lsocket,sizeof(struct sockaddr_nr));

        memcpy(fsocket.nr_addr.user,np->call,AXALEN);
        memcpy(fsocket.nr_addr.node,np->call,AXALEN);
        fsocket.nr_family = AF_NETROM;
        m->state = MBX_GATEWAY;
        return gw_connect(m,s,(struct sockaddr *)&fsocket, sizeof(struct sockaddr_nr));
    }
#endif /*NETROM*/

#ifdef AX25
    if(argc > 2) {
        /*AX25 gateway connection wanted*/
        if(!(m->privs & AX25_CMD)) {
            tputs(Noperm);
	    mail_error("%s: AX.25 gate to %s on %s denied\n",m->name,argv[2],argv[1]);
            return 0;
        }

        if( ((ifp = if_lookup(argv[1])) == NULLIF) ||
           ((ifp->flags & HIDE_PORT) && !(m->privs & SYSOP_CMD)) ||
            (ifp->type != CL_AX25) ) {
            tprintf("Unknown port %s\n",argv[1]);
            dombports(0,NULL,NULL);
            return 0;
        }
        if(ifp->type != CL_AX25){
            tprintf("Port %s not usable for AX.25 connects\n",argv[1]);
            dombports(0,NULL,NULL);
            return 0;
        }
	if(argc > 3 && !strcmp(argv[3], "@"))	{
		didrose = 1;
		argv[3] = strdup(pax25(tmp,AXRosecall));
	}
        if(setcall(target,argv[2]) == -1){
            tprintf("Bad callsign %s\n",argv[2]);
            return 0;
        }
        /* If digipeaters are given, put them in the routing table */
        if(argc > 3){
            ndigis = argc - 3;
            if(ndigis > MAXDIGIS){
                tputs("Too many digipeaters\n");
                return 0;
            }
            for(i=0;i<ndigis;i++){
                if(setcall(digis[i],argv[i+3]) == -1){
                    tprintf("Bad digipeater %s\n",argv[i+3]);
                    return 0;
                }
            }
	if(ax_add(target,AX_AUTO,digis,ndigis,ifp) == NULLAXR){
                tputs("AX25 route add failed\n");
                return 0;
            }
        }
        if((s = socket(AF_AX25,SOCK_STREAM,0)) == -1){
            tputs(Nosock);
            return 0;
        }
#ifdef GWTRACE
		log(m->user,"MBOX AX25: %s to %s on %s %s %s %s",m->name,argv[2],argv[1],(argc > 3) ? "via" : "", (argc > 3) ? argv[3] : "", (argc > 4) ? argv[4] : "");
#endif

	if (didrose)
		free (argv[3]);	

        /*fill in the known stuff*/
        alsocket.sax_family = afsocket.sax_family= AF_AX25;
        
        /*the remote call to connect to*/
        setcall(afsocket.ax25_addr,argv[2]);

        /*the outgoing interface*/
        strncpy(afsocket.iface,argv[1],ILEN);

        /*now set local user call, invert ssid*/
        memcpy(local_call,m->call,AXALEN);
        local_call[AXALEN-1] ^= 0x1e;
        memcpy(alsocket.ax25_addr,local_call,AXALEN);
        /*and bind it (otherwize Mycall will be used!)*/
        bind(s,(char *)&alsocket,sizeof(struct sockaddr_ax));
        m->state = MBX_GATEWAY;
        return gw_connect(m,s,(struct sockaddr *)&afsocket, sizeof(struct sockaddr_ax));
    }
#endif /* AX25 */

    return 0;
}

#endif /* MAILBOX */

