/* NOTE: because of size, the previous 'mailbox.c' has been
 * split in 3 parts:
 * mboxcmd.c, containing the 'mbox' subcommands,
 * 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
 *
 */
#include <stdio.h>
#ifdef MSDOS
#include <io.h>
#endif
#include <time.h>
#include <ctype.h>
#ifdef MSDOS
#include <alloc.h>
#include <fcntl.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <time.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 "cmdparse.h"
#include "mailfor.h"
#ifdef POOLED
#include "pool.h"
#endif

#ifdef MAILBOX

/*
#define MBDEBUG
*/

void Expiretick __ARGS((void *));
extern char *mblookname __ARGS((struct mbx *m,char *str));
extern int dombmovemail __ARGS((int argc,char *argv[],void *p));
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 char *permtest __ARGS((char *path,long privs,char *name,int mode,char *root,int dir));
extern int rdaemon __ARGS((FILE *data,char *from, char *to, char *msg, char msgtype, int mode));
extern char *skipwhite __ARGS((char *));
extern char *skipnonwhite __ARGS((char *));

extern char Myalias[];
extern char MyBBS[AXALEN];
extern char shortversion[];
extern int ExpireActive;
extern char *ExpireArea;
extern time_t ExpireLast;

extern struct mbx *Mbox[NUMMBX];
extern int BbsUsers;
extern int Totallogins, Conflogins, Tutorlogins[], BBSlogins;
char *MMotd;
char *MExit;
char *Mtmsg;
char *MAttendedAt;
int MAttended = 0;
/* unsigned Maxlet = BM_NLET; */
char Mbpasswd[MAXPWDLEN+1] = "";
struct no_js *Exclude = (struct no_js *)NULL;

#ifdef MBFWD
char *Mbzip = NULLCHAR;
char *Mbqth = NULLCHAR;
char *Mbhome = NULLCHAR;
char *Mbhaddress = NULLCHAR;
char *Mbfwdinfo = NULLCHAR;
int Mbsmtptoo = 0;
int Mtrace = 0;
int Mbfullsvc = 1;
extern unsigned subchannels[NUMMBX];
extern int subchannelusage[NUMMBX];
#endif

#ifdef DELEGATE
int Mbdelegate = 1;
#endif

extern int MbSent;
extern int MbRead;
extern int MbRecvd;
#ifdef MBFWD
extern int MbForwarded;
#endif

#ifdef AX25
static char Uplink[] =     "Uplink   (%s)";
static char Downlink[] =   "Downlink (%s)";
#endif
#ifdef NETROM
static char incircuit[]  = "Circuit  (%s%s%s %s)";
static char outcircuit[] = "Circuit  (%s%s%s)";
#endif
static char Telnet[] =     "Telnet   (%s @ %s)";
static char Telnetdown[] = "Telnet   (%s)";
static char Local[] =      "Local    (%s @ %s)";

struct pu *pu_lookup __ARGS((char *name));
void updatedefaults __ARGS((struct mbx *m,int homeonly));
char DFAR *findhome __ARGS((char *name));
void askhome __ARGS((struct mbx *m,int initial));
int dobbshome __ARGS((int argc,char *argv[],void *p));
void askrealname __ARGS((struct mbx *m,int initial));
int dorealname __ARGS((int argc,char *argv[],void *p));
char *cmd_line __ARGS((int argc,char *argv[],char stype));
static int dostr __ARGS((int argc,char *argv[],char *label, char **str));
static int dobbsdumperr __ARGS((int argc,char *argv[],void *p));
static int doalias __ARGS((int argc,char *argv[],void *p));
static int donewmotdfile __ARGS((int argc,char *argv[],void *p));
static int doattend __ARGS((int argc,char *argv[],void *p));
#ifdef notagain
static int domaxmsg __ARGS((int argc,char *argv[],void *p));
#endif
static int dombmotd __ARGS((int argc,char *argv[],void *p));
static int domexit __ARGS((int argc,char *argv[],void *p));
static int dotimeout __ARGS((int argc,char *argv[],void *p));
static int dotipsecurity __ARGS((int argc,char *argv[],void *p));
static int dombsubchannel __ARGS((int argc,char *argv[],void *p));
int dombusers __ARGS((int argc,char *argv[],void *p));
static int dombpast __ARGS((int argc,char *argv[],void *p));
static int dojumpstart __ARGS((int argc,char *argv[],void *p));
static int dombnrid __ARGS((int argc,char *argv[],void *p));
static int dombpasswd __ARGS((int argc,char *argv[],void *p));
static int dombsecure __ARGS((int argc,char *argv[],void *p));
static int dombtrace __ARGS((int argc,char *argv[],void *p));
static int dombzipcode __ARGS((int argc,char *argv[],void *p));
static int dombfwdinfo __ARGS((int argc,char *argv[],void *p));
static int dombqth __ARGS((int argc,char *argv[],void *p));
static int dombhome __ARGS((int argc,char *argv[],void *p));
static int dombhaddress __ARGS((int argc,char *argv[],void *p));
static int dombsmtptoo __ARGS((int argc,char *argv[],void *p));
static int dombutc __ARGS((int argc,char *argv[],void *p));
static int dombmport __ARGS((int argc,char *argv[],void *p));
extern int dombmailfor __ARGS((int argc,char *argv[],void *p));
extern int dombstatus __ARGS((int argc,char *argv[],void *p));
int dombmailstats __ARGS((int argc,char *argv[],void *p));
static int dombtdisc __ARGS((int argc,char *argv[],void *p));
static int dombtmsg __ARGS((int argc,char *argv[],void *p));
static int dombconvers __ARGS((int argc,char *argv[],void *p));
static int dombremote __ARGS((int argc,char *argv[],void *p));
static int dombsendquery __ARGS((int argc,char *argv[],void *p));
static int dombbid __ARGS((int argc,char *argv[],void *p));
static int dombfullsvc __ARGS((int argc,char *argv[],void *p));
static int dombmid __ARGS((int argc,char *argv[],void *p));
static int dombwpages __ARGS((int argc,char *argv[],void *p));
static int dombrsample __ARGS((int argc,char *argv[],void *p));
static int dombrstyle __ARGS((int argc,char *argv[],void *p));
static int dobump __ARGS((int argc,char *argv[],void *p));
static int dozap __ARGS((int argc,char *argv[],void *p));
static int dombhideport __ARGS((int argc,char *argv[],void *p));
static int dombnobid __ARGS((int argc,char *argv[],void *p));
static int domblogging __ARGS((int argc,char *argv[],void *p));
static int dombmaxtimer __ARGS((int argc,char *argv[],void *p));
#ifdef DELEGATE
static int dombdelegate __ARGS((int argc,char *argv[],void *p));
#endif
extern char *mbxtime __ARGS((char *line));
extern void updateFwd __ARGS((char *who, char *area, long bid));
extern void bbsbump __ARGS((char *user, int zap));


int Mbjumpstart = 1;
int Usenrid = 0;
int NoBid;
int MbBID = 0;
int MbMID = 1;
int MbRSTYLE = 0;
int MbLogging = 0;
#ifdef WPAGES
int MbWpages = 1;
#endif
int MBSecure = 0;
int Mbsendquery = 1;
#ifdef MBXTDISC
int32 Mbtdiscinit = 0;
#endif
int32 mbxMaxTimer = 0;
#ifdef TIPMAIL
int32 Mbtipperms = 0x109401;	/* no_slip, ftp_read, no_sendcmd, no_3party, no_convers */
#endif

/* mbox subcommand table */
static struct cmds DFAR Mbtab[] = {
	"alias",	doalias,	0, 0, NULLCHAR,
	"attend",	doattend,	0, 0, NULLCHAR,
	"bid",		dombbid,	0, 0, NULLCHAR,
	"bbsdumperr",	dobbsdumperr,	0, 0, NULLCHAR,
	"bump",		dobump,		0, 0, NULLCHAR,
#ifdef CONVERS
	"convers",	dombconvers,	0, 0, NULLCHAR,
#endif
#ifdef DELEGATE
	"delegate",	dombdelegate,	0, 0, NULLCHAR,
#endif
#ifdef MBFWD
    "fullservice", dombfullsvc,0,0, NULLCHAR,
    "fwdinfo",  dombfwdinfo,0, 0, NULLCHAR,
    "haddress", dombhaddress,0,0, NULLCHAR,
    "hideport", dombhideport, 0,0, NULLCHAR,
    "home",     dombhome, 0, 0, NULLCHAR,
#endif
#ifdef AX25
    "jumpstart", dojumpstart,0, 0, NULLCHAR,
#ifdef MBFWD
    "kick",     dombkick,   0, 0, NULLCHAR,
#endif
#endif
    "logging",	domblogging, 0, 0, NULLCHAR,
#ifdef MAILFOR
#ifdef AX25
    "mailfor",  dombmailfor,0, 0, NULLCHAR,
#endif
#endif
#ifdef notagain
	"maxmsg",	domaxmsg,	0, 0, NULLCHAR,
#endif
	"mailstats",	dombmailstats,	0, 0, NULLCHAR,
	"maxtimer",	dombmaxtimer,	0, 0, NULLCHAR,
	"mexit",	domexit,	0, 0, NULLCHAR,
	"mid",		dombmid,	0, 0, NULLCHAR,
	"motd",		dombmotd,		0, 0, NULLCHAR,
#ifdef AX25
	"mport",	dombmport,	0, 0, NULLCHAR,
#endif
	"newmotdfile",	donewmotdfile,	0, 0, NULLCHAR,
    "nobid",  dombnobid,  0, 0, NULLCHAR,
#ifdef AX25
    "nrid",     dombnrid,   0, 0, NULLCHAR,
#endif
    "past",     dombpast,   0, 0, NULLCHAR,
    "password", dombpasswd, 0, 0, NULLCHAR,
    "remote",   dombremote, 0, 0, NULLCHAR,
    "rsample",	dombrsample,0, 0, NULLCHAR,
    "rstyle",	dombrstyle, 0, 0, NULLCHAR,
#ifdef MBFWD
    "qth",      dombqth,    0, 0, NULLCHAR,
#endif
    "secure",   dombsecure, 0, 0, NULLCHAR,
    "sendquery",dombsendquery,0,0,NULLCHAR,
#ifdef MBFWD
    "smtptoo",  dombsmtptoo,0, 0, NULLCHAR,
#endif
    "status",   dombstatus,  0, 0, NULLCHAR,
#ifdef  AX25
#ifdef MBFWD
	"subchannel",	dombsubchannel,	0, 0, NULLCHAR,
	"timer",	dombtimer,	0, 0, NULLCHAR,
#endif
#endif
#ifdef MBXTDISC
    "tdisc",    dombtdisc,  0, 0, NULLCHAR,
#endif
#ifdef TIPMAIL
#ifdef ALLSERV
    "tipsecurity", dotipsecurity, 0, 0, NULLCHAR,
    "tiptimeout",   dotimeout,  0, 0, NULLCHAR,
#endif
#endif
    "tmsg",     dombtmsg,   0, 0, NULLCHAR,
#ifdef MBFWD
    "trace",    dombtrace,  0, 0, NULLCHAR,
    "utc",      dombutc,    0, 0, NULLCHAR,
#ifdef WPAGES
    "wpages",	dombwpages, 0, 0, NULLCHAR,
#endif
    "zap",	dozap,	    0, 0, NULLCHAR,
    "zipcode",  dombzipcode,0, 0, NULLCHAR,
#endif
    NULLCHAR,
};

char Mbnrid[20];

/*set the mailbox netrom id*/
void
setmbnrid() {
    char tmp[AXBUF];
#ifdef NETROM
    char tmp2[AXBUF];
#endif
#ifndef AX25
    char *cp;
#endif

#ifdef NETROM
    if(Nr_iface != NULLIF) { /* Use netrom call, and alias (if exists) */
        if(*Myalias != '\0')
            sprintf(Mbnrid,"%s:%s ",pax25(tmp,Myalias),
                    pax25(tmp2,Nr_iface->hwaddr));
        else
            sprintf(Mbnrid,"%s ",pax25(tmp,Nr_iface->hwaddr));
        return;
    }
    /* Use Mycall, and alias (if exists) */
    if(*Myalias != '\0')
        sprintf(Mbnrid,"%s:%s ",pax25(tmp,Myalias),pax25(tmp2,Mycall));
    else
#endif
#ifdef AX25
        sprintf(Mbnrid,"%s ",pax25(tmp,Mycall));
#else
        strncpy(Mbnrid,Hostname,19);
        if((cp = strchr(Mbnrid,'.')) != NULLCHAR)
            *cp = '\0';
#endif
    return;
}

/*This is a dummy called from the main command interpreter,
 *setup a mbx structure so dombusers() works correct - WG7J
 */
int
dombstatus(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    struct mbx m;

    m.privs = SYSOP_CMD;
    m.stype = ' ';
    return dombusers(0,NULL,&m);
}

static int
dobump(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	if (argc == 1)
		tprintf ("Syntax: mbox bump username\n");
	else
		bbsbump (argv[1], 0);
	return 0;
}

static int
dozap(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	if (argc == 1)
		tprintf ("Syntax: mbox zap username\n");
	else
		bbsbump (argv[1], 1);
	return 0;
}

int
dombrsample(argc,argv,p)
int argc;
char *argv[];
void *p;
{
time_t t;
char *cp, buf[40], thetime[100];

	time(&t);
	pax25(buf,Mycall);
	if((cp = strchr(buf,'-')) != NULLCHAR)
		*cp = '\0'; /* remove SSID */
	strcpy(thetime, ptime(&t));
	if (!MbRSTYLE)	{
		tprintf("R:%s @:%s%s%s ", mbxtime(thetime), buf, (Mbhaddress) ? "." : "",
			(Mbhaddress) ? Mbhaddress : "");
		if (Mbfwdinfo)
			tprintf("[%s] ", Mbfwdinfo);
		if (Mbqth)
			tprintf("%s ", Mbqth);
		if (MbMID)
			tprintf("#:7388 ");
		if (Mbzip)
			tprintf("Z:%s ", Mbzip);
		if (MbBID)	{
			strncpy (buf, Hostname, 40);
			strupr (buf);
			if((cp = strchr(buf,'.')) != NULLCHAR)
				*cp = '\0';
			tprintf("$:7388_%s", buf);
		}
	} else
		tprintf("R:%s 7388@%s%s%s", mbxtime(thetime), buf, (Mbhaddress) ? "." : "",
			(Mbhaddress) ? Mbhaddress : "");
	tprintf("\n");
	return 0;
}


int
dombrstyle(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    return setbool(&MbRSTYLE,"W0RLI style R: lines",argc,argv);
}


int
domblogging(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    return setbool(&MbLogging,"Keep log of each MBOX login",argc,argv);
}


int
dombox(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	if(argc == 1)
        return dombstatus(0,NULL,NULL);
	return subcmd(Mbtab,argc,argv,p);
}

#ifdef AX25

static int
dombhideport(argc, argv,p)
int argc;
char *argv[];
void *p;
{
    return(dosetflag(argc,argv,p,HIDE_PORT, 1));
}

static int
dojumpstart(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	register int i;
	char tmp[AXBUF];
	struct no_js *ep;

	if(*argv[1] == 'e') {
		/*the exclude subcommand*/
		if(argc == 2) { /*just list them*/
			for(ep=Exclude;ep!=(struct no_js *)NULL;ep=ep->next)
				tprintf("%s ",pax25(tmp,ep->call));
			tputc('\n');
		} else { /*add some call(s)*/
			for(i=0;i<argc-2;i++) {
				ep = callocw(1,sizeof(struct no_js));
				if(setcall(ep->call,argv[i+2]) == -1){
					tprintf("Invalid call: %s\n",argv[i+2]);
					free(ep);
				} else { /* add to list */
					ep->next = Exclude;
					Exclude = ep;
				}
			}
		}
		return 0;
	}
	return setbool(&Mbjumpstart,"Jump start on connect",argc,argv);
}

static int
dombnrid(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    return setbool(&Usenrid,"Netrom id prompt",argc,argv);
}


static int
dombmport(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    return(dosetflag(argc,argv,p,MAIL_BEACON, 1));
}

#endif /* AX25 */


static int
dombfullsvc(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    return setbool(&Mbfullsvc,"Full Service BBS",argc,argv);
}

#ifdef DELEGATE
static int
dombdelegate(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    return setbool(&Mbdelegate,"Allow user delegation forwarding",argc,argv);
}
#endif

static int
dombbid(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    return setbool(&MbBID,"Original BID in R: lines",argc,argv);
}

static int
dombmid(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    return setbool(&MbMID,"Local MID in R: lines",argc,argv);
}

#ifdef WPAGES
static int
dombwpages(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    return setbool(&MbWpages,"Use White Pages dbase",argc,argv);
}
#endif

static int
dombnobid(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    return setbool(&NoBid,"Accept Buls without BID",argc,argv);
}

static int
dombsendquery(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    return setbool(&Mbsendquery,"query after send",argc,argv);
}

#ifdef CONVERS
int Mbconverse = 1;

static int
dombconvers(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    return setbool(&Mbconverse,"Mbox convers",argc,argv);
}
#endif

int BBSdump = 1;

static int
dobbsdumperr(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    return setbool(&BBSdump,"BBS - Dump on error",argc,argv);
}

/* if unattended mode is set, ax25, telnet and maybe other sessions will
 * be restricted.
 */
static int
doattend(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return setbool(&MAttended,"Mailbox Attended flag",argc,argv);
}

#ifdef notagain
static int
domaxmsg(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return setuns(&Maxlet,"Maximum messages per area",argc,argv);
}
#endif

#ifdef MBXTDISC
/* Set mailbox redundancy timer */
static int
dombtdisc(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    return setlong(&Mbtdiscinit,"Mbox redundancy timer (sec)",argc,argv);
}
#endif

/* Set mailbox maximum session timer */
static int
dombmaxtimer(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    return setlong(&mbxMaxTimer,"Mbox Maximum session time allowed (sec)",argc,argv);
}

#ifdef MBFWD
static int
dombsmtptoo(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    return setbool(&Mbsmtptoo,"Bbs forwards SMTP headers",argc,argv);
}
#endif

static int
dombpasswd(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    int len;

	/*Only allowed from keyboard*/
	if(Curproc->input != Command->input) {
		tputs(Noperm);
		return 0;
	}
    if(argc != 2) {
        tputs("Usage: mbox password \"<sysop password>\"\n");
		return 0;
	}
    if((len=strlen(argv[1])) == 0)
        return 0;       /* zero length, don't reset */

    if(len > MAXPWDLEN) {
        tputs("Too long\n");
        return 0;
    }
    strcpy(Mbpasswd,argv[1]);
	return 0;
}

/* define the BBS alias*/
static int
doalias(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
char tmp[AXBUF];

	if(argc < 2) {
		tprintf("%s\n",pax25(tmp,MyBBS));
		return 0;
	}
	if(setcall(MyBBS,argv[1]) == -1)	{
		tputs("can't set BBS alias\n");
		return 0;
	}
	return 0;
}

static int
dostr(argc,argv,label,str)
int argc;
char *argv[];
char *label, **str;
{
	if(argc > 2) {
	        tprintf ("Usage: mbox %s \"<your message>\"\n", label);
		return 0;
	}

	if(argc < 2) {
		if(*str != NULLCHAR)
			tputs(*str);
	}
	else {
		if(*str != NULLCHAR){
			free(*str);
			*str = NULLCHAR;	/* reset the pointer */
		}
		if(!strlen(argv[1]))
			return 0;		/* clearing the buffer */
		*str = mallocw(strlen(argv[1])+5);/* allow for the EOL char */
		strcpy(*str, argv[1]);
		strcat(*str, "\n");		/* add the EOL char */
	}
	return 0;
}

static int
dombmotd(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return dostr (argc,argv,"motd",&MMotd);
}

static int
dombremote(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return dostr (argc,argv,"remote",&MAttendedAt);
}


static int
donewmotdfile(argc,argv,p)
int argc;
char *argv[];
void *p;
{
FILE *Ufile, *tfile;
char buf[256], *cp;

	/* Save old defaults file to backup */
	unlink(UDefbak);
	if(rename(UDefaults,UDefbak))
		return 0;
        if ((tfile = fopen(UDefbak,"r")) != NULLFILE) {
        	if ((Ufile = fopen(UDefaults,"w")) == NULLFILE)	  {
        		fclose (tfile);
        		return 0;
        	}
       	        while(fgets(buf,sizeof(buf),tfile) != NULLCHAR)	{
	            if((cp=strchr(buf,' ')) != NULLCHAR)
		            if((cp=strchr(buf,' ')) != NULLCHAR)
				if ((cp=strchr(cp,'R')) != NULLCHAR)
	        	       		*cp = ' ';
		    fputs(buf,Ufile);
               	}
               	fclose(tfile);
               	fclose(Ufile);
	        tputs ("All users will view the 'motd' file on their next login!\n");
        } else
	        rename(UDefbak,UDefaults);
	return 0;
}

static int
domexit(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return dostr (argc,argv,"mexit",&MExit);
}

static int
dombtmsg(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return dostr (argc,argv,"tmsgs",&Mtmsg);
}

#ifdef MBFWD
int UtcOffset=0;

/*Set the difference between Local time, and UTC !*/
static int
dombutc(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    if(argc < 2) {
        tputs("Local Time is UTC");
        if(UtcOffset == 0)
            tputc('\n');
        else {
            if(UtcOffset > 0)
                tputc('+');
            tprintf("%d\n",UtcOffset);
        }
        return 0;
    }
    UtcOffset = atoi(argv[1]);
    return 0;
}

/*Set the ZIP to be used in the R: line when forwarding */
static int
dombzipcode(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    int len;

	if(argc > 2) {
        tputs("Usage: mbox zipcode <your zip>\n");
		return 0;
	}

	if(argc < 2) {
        if(Mbzip != NULLCHAR)
            tprintf("%s\n",Mbzip);
	}
	else {
        len = strlen(argv[1]);
#ifdef notdef
        /*check for a valid zip - this is for USA only!!! - WG7J*/
        if( (len != 5) || !(atol(argv[1])) ){
            tprintf("%s: Invalid, should be 5 digits!\n",argv[1]);
            return 0;
        }
#endif
        if(Mbzip != NULLCHAR){
            free(Mbzip);
            Mbzip = NULLCHAR;   /* reset the pointer */
		}
        if(len == 0)
			return 0;		/* clearing the buffer */
        Mbzip = mallocw((unsigned)(len+1)); /* room for \0 */
        strcpy(Mbzip, argv[1]);
	}
	return 0;
}

/* Set the QTH to be used in R: line when forwarding*/
static int
dombqth(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	if(argc > 2) {
        tputs("Usage: mbox qth <your qth> || \"<your qth, state>\"\n");
		return 0;
	}

	if(argc < 2) {
        if(Mbqth != NULLCHAR)
            tprintf("%s\n",Mbqth);
	}
	else {
        if(Mbqth != NULLCHAR){
            free(Mbqth);
            Mbqth = NULLCHAR;   /* reset the pointer */
		}
		if(!strlen(argv[1]))
			return 0;		/* clearing the buffer */
        Mbqth = mallocw(strlen(argv[1]) + 1);
        strcpy(Mbqth, argv[1]);
	}
	return 0;
}

/* Set the HOME BBS prompt string to be used */
static int
dombhome(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	if(argc > 2) {
	        tputs("Usage: mbox home <your prompt string>\n");
		return 0;
	}

	if(argc < 2) {
        	if(Mbhome != NULLCHAR)
			tprintf("%s\n",Mbhome);
	}
	else {
		if(Mbhome != NULLCHAR){
			free(Mbhome);
			Mbhome = NULLCHAR;   /* reset the pointer */
		}
		if(!strlen(argv[1]))
			return 0;		/* clearing the buffer */
		Mbhome = mallocw(strlen(argv[1]) + 1);
		strcpy(Mbhome, argv[1]);
	}
	return 0;
}

/*Set the hierachical address to be used in R: line when forwarding*/
static int
dombhaddress(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	if(argc > 2) {
        tputs("Usage: mbox haddress <your H-address (without call)>\n");
		return 0;
	}

	if(argc < 2) {
        if(Mbhaddress != NULLCHAR)
            tprintf("%s\n",Mbhaddress);
	}
	else {
        if(Mbhaddress != NULLCHAR){
            free(Mbhaddress);
            Mbhaddress = NULLCHAR;   /* reset the pointer */
		}
		if(!strlen(argv[1]))
			return 0;		/* clearing the buffer */
        Mbhaddress = mallocw(strlen(argv[1]) + 1);
        strcpy(Mbhaddress, argv[1]);
        /*make sure the're upper case*/
        strupr(Mbhaddress);
    }
	return 0;
}

/*Set the R: line [info] to be used when forwarding*/
static int
dombfwdinfo(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	if(argc > 2) {
        tputs("Usage: mbox fwdinfo \"<your R:-line [info]>\"\n");
		return 0;
	}

	if(argc < 2) {
        if(Mbfwdinfo != NULLCHAR)
            tprintf("%s\n",Mbfwdinfo);
	}
	else {
        if(Mbfwdinfo != NULLCHAR){
            free(Mbfwdinfo);
            Mbfwdinfo = NULLCHAR;   /* reset the pointer */
		}
		if(!strlen(argv[1]))
			return 0;		/* clearing the buffer */
        Mbfwdinfo = mallocw(strlen(argv[1]) + 1);
        strcpy(Mbfwdinfo, argv[1]);
	}
	return 0;
}
#endif /*MBFWD*/

/* Keep track of all past users */
struct pu {
    struct pu *next;    /* next one in list */
    char name[20];              /* user name */
#ifdef notdef
    int family;                 /* how did user come in last */
#endif
    int32 time;                 /* When was the last login ? */
    int number;                 /* Number of times logged in */
};
#define NULLPU (struct pu *)NULL
struct pu *Pu = NULLPU;
#ifdef POOLED
struct mempool Pu_pool = {NULLPOOLBLK, NULLPOOLBLK, 0, sizeof (struct pu), 50};
#endif

/* Look up an entry in the users-list*/
struct pu *
pu_lookup(name)
char *name;
{
    register struct pu *ppu;
    struct pu *pulast = NULLPU;

    for(ppu = Pu;ppu != NULLPU;pulast = ppu,ppu = ppu->next){
        if(!strcmp(name,ppu->name)){ /* found it! */
            if(pulast != NULLPU){
				/* Move entry to top of list */
                pulast->next = ppu->next;
                ppu->next = Pu;
                Pu = ppu;
			}
            return ppu;
		}
	}
    return NULLPU;
}

/*Log all users of the mailbox*/
/* This gets kept track of in the file name UDefaults */
/* format is
user @home (realname) datestamp options
where options are separated by spaces
M# - use more with # lines
A - use area indiation
X - use expert status
N - use netrom lookalike prompt
R - has the motd file been read?
S - give new message statistics on login
L - use LZW compressed streams
G - use ANSI color graphics
D - forwarding delegation enabled?
Cx - Connection type x (A=AX.25, N=NET/ROM, T=TELNET)
*/

#ifdef USERLOG

/* Write the new defaults - WG7J */
void
updatedefaults(m, homeonly)
struct mbx *m;
int homeonly;
{
FILE *Ufile, *tfile;
char buf[256];
char *cp, *cp2;
time_t t;

    /* Save old defaults file to backup */
    unlink(UDefbak);
    if(rename(UDefaults,UDefbak))
        return;

    /*Write all users back, but update this one!*/
    if((Ufile = fopen(UDefaults,"w")) == NULLFILE)	{
        /* Can't create defaults file ???*/
        rename(UDefbak,UDefaults);
        return;
    }

    if((tfile = fopen(UDefbak,"r")) == NULLFILE) {
        /* What on earth happened ???? */
        fclose(Ufile);
        return;
    }
    while(fgets(buf,sizeof(buf),tfile) != NULLCHAR) {
        if((cp=strchr(buf,' ')) != NULLCHAR)
            *cp = '\0';
        if(!stricmp(m->name,buf)) {
            /*found this user*/
            time(&t);
            if (homeonly == 1)	{
	        cp = strchr(++cp,' ');
		cp++;
		if (*cp == '@')		{
		        cp = strchr(++cp,' ');
			cp++;
		}
        	cp = strdup (cp);
        	sprintf (buf, "%s %s %s", m->name, m->home, cp);
        	free (cp);
            } else if (homeonly == 2)	{
            	*cp = ' ';
	        cp = strchr(++cp,' ');
		*cp++ = 0;
		if (*cp == '(')	{
		        cp = strchr(++cp,')');
			cp += 2;
		}
        	cp = strdup (cp);
        	cp2 = strdup (buf);
        	sprintf (buf, "%s (%s) %s", cp2, m->realname, cp);
        	free (cp);
        	free (cp2);
            } else
	            sprintf(buf,"%s @%s %s %lu M%d %c %c %c %c %c %c %c %c C%c\n",
        	            m->name,
			    (m->home && strnicmp (m->home, Hostname, strlen(m->home)))
				 ? m->home : "",
			    (m->realname) ? m->realname : "()",
			    t,m->morerows,
	                    (m->sid&MBX_AREA) ? 'A' : ' ' ,
        	            (m->sid&MBX_EXPERT) ? 'X' : ' ' ,
                	    (m->sid&MBX_NRID) ? 'N' : ' ',
	                    (m->sid&MBX_RDMOTD) ? 'R' : ' ',
        	            (m->sid&MBX_STATS) ? 'S' : ' ',
                	    (m->sid&MBX_TNOS) ? 'L' : ' ',
                	    (m->sid&MBX_GFX) ? 'G' : ' ',
			    (m->sid&MBX_DELEGATE) ? 'D' : ' ',
	                    (m->family == AF_AX25) ? 'A' : \
        	            ((m->family == AF_NETROM) ? 'N' : 'T'));	
        } else
            *cp = ' '; /* restore the space !*/
        fputs(buf,Ufile);
    }
    fclose(tfile);
    fclose(Ufile);
    return;
}
#endif /* USERLOG */


char DFAR *
findhome (name)
char *name;
{
char buf[256];
register char *cp, *cp2;
char DFAR *retval = (char DFAR *)0;
register FILE *Ufile;

	if((Ufile = fopen(UDefaults,"r")) != NULLFILE)		{
		while(fgets(buf,sizeof(buf),Ufile) != NULLCHAR)		{
			if((cp=strchr(buf,' ')) != NULLCHAR)
				*cp++ = '\0';
			if(!stricmp(name,buf))	{
				if((cp2=strchr(cp,' ')) != NULLCHAR)
					*cp2 = '\0';
				if (*cp == '@')		{
					cp++;
					if (!*cp)
						retval = (char DFAR *) -1;	/* -1 means home is here */
					else if (*cp != '-')
						retval = (char DFAR *) strdup (cp);
				}
				break;
			}
		}
		fclose (Ufile);
	}
	return (retval);
}


void askhome (m, initial)
struct mbx *m;
int initial;
{
#ifdef ASKHOME
char *cp;
char name[80], here[AXBUF];

	if (initial && m->privs & IS_BBS)	{
		m->home = strdup (m->name);
		m->morerows = 0;
		return;
	}
	pax25(here,Mycall);
	if (initial)	{
		tputs ("\nSorry to have to ask, but this system does not know your HOME BBS!\n");
		tputs ("This information is needed in order to properly send any mail to you from\nusers of this system\n\n");
		tputs ("Your HOME BBS is like your Postal Address. If you have already defined your\n");
		tputs ("HOME BBS on another system, the name of that system is needed.\n");
		tputs ("\nNOTE: only use a BBS hierarchial address, not a TCP/IP address.\n");
		if (Mbhome != NULLCHAR)
			tputs (Mbhome);
		strcpy (name, here);
		if((cp=strchr(name,'.')) != NULLCHAR)
			*cp = '\0';
		m->home = strdup (name);
	} else
		tprintf ("\nChanging HOME BBS from '%s'! Enter name of new HOME...\n",
			(m->home) ? m->home : here);
	tputs ("\nHOME BBS>\n");
	if (mbxrecvline(m) == -1)
		return;
	for (cp = m->line; isspace(*cp); ++cp)
		;
	if (*cp && *cp != '\n')		{
		free (m->home);
		strlwr (cp);
		m->home = strdup (cp);
	}
	tprintf ("\nHOME BBS set to '%s'\n", (m->home) ? m->home: here);
/*	if (!initial)	*/
		m->update = 1;
#endif
}



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

	m = (struct mbx *)p;
	if (argc > 1 && (m->privs & SYSOP_CMD))	{
		if (argc == 2)
			return (dombuserinfo (argc, argv, p));
		if (argc > 3 || argv[2][0] != '@')	{
			tputs ("Syntax: HOME user @bbs\n");
			return (0);
		}
		orgname = strdup (m->name);
		orghome = m->home;
		strcpy (m->name,argv[1]);
		m->home = argv[2];
		updatedefaults (m, 1);
		strcpy (m->name, orgname);
		m->home = orghome;
		free (orgname);
	} else
		askhome (m, 0);
	return 0;
}



void askrealname (m, initial)
struct mbx *m;
int initial;
{
char *cp;
char name[80];
char *callnm;

	if (initial)	{
		callnm = mblookname (NULLMBX, m->name);
		if (m->privs & IS_BBS)	{
			m->realname = strdup (m->name);
			m->morerows = 0;
			return;
		}
		if (callnm)	{
			m->realname = strdup (&callnm[1]);
			free (callnm);
			m->update = 1;
			tprintf ("\nThe on-line callbook shows your real name as '%s'\n", callnm);
		} else	{
			m->realname = strdup ("()");
/*			tprintf ("\nThe on-line callbook could not find your real name\n");	*/
		}
		tputs ("Your real name is used along with your callsign when sending a message\n");
		tprintf ("If you wish to %s this, use the NAME command\n", (callnm) ? "change" : "set");
		return;
	}
	tprintf ("\nChanging REAL NAME from '%s'!\nEnter the name you wish to be known by...\n",
		(!m->realname || !strcmp (m->realname, "()")) ? "unknown" : m->realname);
	tputs ("\nREAL NAME>\n");
	if (mbxrecvline(m) == -1)
		return;
	cp = skipwhite (m->line);
	if (*cp && *cp != '\n')		{
		free (m->realname);
		sprintf (name, "(%s)", cp);
		m->realname = strdup (name);
	}
	tprintf ("\nREAL NAME set to '%s'\n", (m->realname && strcmp(m->realname, "()")) ? m->realname: "unknown");
	m->update = 1;
}



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

	m = (struct mbx *)p;
	if (argc > 1 && (m->privs & SYSOP_CMD))	{
		if (argc == 2)
			return (dombuserinfo (argc, argv, p));
		if (argc > 3)	{
			tputs ("Syntax: NAME user \"realname\"\n");
			return (0);
		}
		orgname = strdup (m->name);
		orgreal = m->realname;
		strcpy (m->name,argv[1]);
		m->realname = argv[2];
		updatedefaults (m, 2);
		strcpy (m->name, orgname);
		m->realname = orgreal;
		free (orgname);
	} else
		askrealname (m, 0);
	return 0;
}



int DiffUsers;

time_t
loguser(m)
struct mbx *m;
{
    register struct pu *pu;
#ifdef USERLOG
    FILE *Ufile;
    char buf[256];
    char *cp;
    int found=0;
    time_t t, laston = 0;
    int xpert = 0;
#endif

    time(&t);
    m->logontime = (long) t;
    if((pu = pu_lookup(m->name)) == NULLPU) {   /* not 'known' user */
#ifdef POOLED
        pu = (struct pu *)pool_alloc(&Pu_pool);
#else
        pu = (struct pu *)callocw(1,sizeof(struct pu));
#endif
        strcpy(pu->name,m->name);
        pu->next = Pu;
        Pu = pu;
        DiffUsers++;    /* A new guy */
    }
#ifdef notdef
    pu->family = m->family;
#endif
    pu->time = secclock();
    pu->number++;

#ifdef USERLOG
    /* Now get options from the userdefaults file, and add timestamp */
    if(!(m->sid&MBX_SID)) { /* only if not a bbs */
        sprintf(buf,"%s",UDefaults);
        if ((Ufile = fopen(buf,"r+")) == NULLFILE) {
            /* default file doesn't exist, create it */
            if((Ufile = fopen(buf,"w")) == NULLFILE)
                return (time_t) -1;
            /* Add this user as first one,
             * default uses Area indication
             */
	    m->home = strdup ("-");

            time(&t);
            sprintf(buf,"%s @%s () %lu M%d %c %c %c         C%c\n",
                    m->name,
		    (m->home && strnicmp (m->home, Hostname, strlen(m->home)))
			 ? m->home : "",t,m->morerows,
		    (m->privs&IS_BBS) ? ' ' : 'A',
                    (m->sid&MBX_EXPERT) ? 'X' : ' ' ,
                    (m->sid&MBX_NRID) ? 'N' : ' ',
                    (m->family == AF_AX25) ? 'A' : \
                    ((m->family == AF_NETROM) ? 'N' : 'T'));
            fputs(buf,Ufile);
            fclose(Ufile);
            m->realname = NULLCHAR;
            if (!(m->privs&IS_BBS))
		m->sid |= MBX_AREA;
            if(Usenrid)
                m->sid |= MBX_NRID;
            return laston;
        }
        /* Find user in the default file */
        while(!found) {
            if(fgets(buf,sizeof(buf),Ufile) == NULLCHAR)
                break;
            if((cp=strchr(buf,' ')) != NULLCHAR)
                *cp++ = '\0';
            if(!stricmp(m->name,buf)) {
                /* found user, now scan the options used */
                found = 1;
                fclose(Ufile);
                if (*cp == '@')		{
                	char *cp2;
			if((cp2=strchr(cp++,' ')) != NULLCHAR)	{
				*cp2++ = '\0';
				if (*cp)
					m->home = strdup (cp);
				cp = cp2;
			}
                }
                else
			m->home = strdup ("-");
		cp = skipwhite (cp);
		m->realname = NULLCHAR;
		if (*cp == '(')		{
			char *cp2;
			if((cp2=strchr(cp,')')) != NULLCHAR)	{
				cp2++;
				*cp2++ = '\0';
				m->realname = strdup (cp);
				cp = cp2;
			}
		}
		cp = skipwhite (cp);
                laston = atol (cp);
                while(*cp != ' ')	/* now skip the laston time */
                	cp++;
                while(*cp != '\0') {
                    while(*cp == ' ')   /*skip blanks*/
                        cp++;
                    switch(*cp){
                        case 'C':
                            /* All options end BEFORE the CT/CN or CA */
                            *(cp+1) = '\0';
                            break;
			case 'D':
			    m->sid |= MBX_DELEGATE;
			    break;
                        case 'M':
                            cp++;
                            m->morerows = atoi(cp);
                            break;
                        case 'A':
                            m->sid |= MBX_AREA;
                            break;
                        case 'G':
                            m->sid |= MBX_GFX;
                            m->usecolor = 1;
                            break;
                        case 'X':
                            m->sid |= MBX_EXPERT;
                            xpert = 1;
                            break;
                        case 'N':
                            m->sid |= MBX_NRID;
                            break;
                        case 'R':
                            m->sid |= MBX_RDMOTD;
                            break;
                        case 'S':
                            m->sid |= MBX_STATS;
                            break;
                        case 'L':
                            m->sid |= MBX_TNOS;
                            break;
                    }
                    cp++;
                }
            }
        } /* while(!found)*/
        if(found) {
            /* add the new timestamp to the defaults file */
            updatedefaults(m, 0);
            if(!xpert)
                m->sid &= ~MBX_EXPERT;
            return laston;
        } else {
            /* a new one, add to the end (where we now should be!)*/
	    m->home = strdup ("-");
            time(&t);
            sprintf(buf,"%s @%s () %lu M%d %c %c %c         C%c\n",
                    m->name,
		    (m->home && strnicmp (m->home, Hostname, strlen(m->home)))
			 ? m->home : "",t,m->morerows,
		    (m->privs&IS_BBS) ? ' ' : 'A',
                    (m->sid & MBX_EXPERT) ? 'X' : ' ' ,
                    (Usenrid) ? 'N' : ' ' ,
                    (m->family == AF_AX25) ? 'A' : \
                    ((m->family == AF_NETROM) ? 'N' : 'T'));
            fputs(buf,Ufile);
            fclose(Ufile);
            m->realname = NULLCHAR;
	    if (!(m->privs&IS_BBS))
		m->sid |= MBX_AREA;
            if(Usenrid)
                m->sid |= MBX_NRID;
            return laston;
        }
    }/* if not bbs */
#ifdef notnow
    else if (findhome (m->name) == NULLCHAR)	{	/* if not in file, flag to add for HOME BBS info, only */
    		m->home = strdup (m->name);
    		m->update = 1;
    }
#endif
#endif /* USERLOG */
    return (time_t) -1;
}


/*List all past users of the mailbox */
static int
dombpast(argc,argv,p)
int argc;
char *argv[];
void *p;
{

    register struct pu *pu;
    int col = 0;
    int maxcount=10000;      /* Large enough :-) */
    int count=0;

    if(argc>1)
        maxcount = atoi(argv[1])-1;

	tputs("Past users:\nUser       Logins  Time since last   User       Logins  Time since last\n");
    for (pu=Pu;pu!=NULLPU;pu=pu->next) {
        if(col)
			tputs(" : ");
		tprintf("%-10s    %-4d    %12s",pu->name,pu->number,\
                tformat(secclock() - pu->time));
        count++;
        if(count>maxcount)
            break;
        if(col) {
            col = 0;
            tputc('\n');
        } else
            col = 1;
    }
    if(col)
        tputc('\n');
    tputc('\n');
    return 0;
}

void
smtpqueuecheck ()
{
struct ffblk block;
int done,i = 0;
char buffer[1024];

	sprintf(buffer, "%s/*.wrk",Mailqdir);
	done = findfirst(buffer,&block,0x3F);
	while (!done) {
		i++;
		done = findnext(&block);
	}
	if (i)
		tprintf ("SMTP queued messages: %d\n", i);
}


int
dombmailstats(argc,argv,p)
int argc;
char *argv[];
void *p;
{
#ifndef UNIX
    tprintf ("Mem: ");
    mbmemory ();
#endif
    tprintf("Total Logins: %d   (BBS: %d - CONF: %d - TUTOR: %d - INFO: %d - NEWS: %d)\nUp: %s\nUsers: %d\nCount: %d\n",
             Totallogins,BBSlogins,
             Conflogins,Tutorlogins[0],Tutorlogins[1],Tutorlogins[2],tformat(secclock()),BbsUsers,DiffUsers);

#ifdef MBFWD
    tprintf("Users sent: %d\nUsers read: %d\nReceived  : %d\nForwarded : %d\n",
            MbSent,MbRead,MbRecvd,MbForwarded);
#else
    tprintf("Users sent: %d\nUsers read: %d\nReceived  : %d\n",MbSent,MbRead,MbRecvd);
#endif
       	if (ExpireActive)
      		tprintf ("Expiration of public area%s %c%s%sin progress\n",
			ExpireArea ? "" : "s", ExpireArea ? '\'' : '\0',
			ExpireArea ? ExpireArea : "", ExpireArea ? "\' " : "");
	else if (ExpireLast)
		tprintf ("Last Expiration: %s", ptime(&ExpireLast));	
	smtpqueuecheck();
       	dombmailfor (1, (char **) 0, (void *) 0);
    return 0;
}

#ifdef USERLOG
extern int DTranslate;                 /* do IP address to domain name translation */


/* Search for info on a certain user in the users.dat file */
int
dombuserinfo(argc,argv,p)
int argc;
char *argv[];
void *p;
{
FILE *Ufile;
char buf[MBXLINE];
int found = 0;
time_t t;
struct tm *lt;
char *cp, *cp2, *home = 0, *cp3;
struct mbx *m;
char *realname;
long addr;
int trans;

    m = (struct mbx *) p;

    if((Ufile = fopen(UDefaults,"r")) == NULLFILE) {
        tputs("Can't find user data\n");
        return 0;
    }
    while( !found && (fgets(buf,MBXLINE,Ufile) != NULLCHAR) ) {
        if((cp=strchr(buf,' ')) != NULLCHAR)
            *cp++ = '\0';
        if(!stricmp(buf,argv[1])) { /* Found it ! */
            home = Hostname;
            if((cp3=strchr(cp,' ')) != NULLCHAR)
                *cp3++ = '\0';
	    if (*cp == '@')	{
	    	cp++;
	    	if (*cp)
		    	home = cp;
	    }

		cp = skipwhite (cp3);
		realname = NULLCHAR;
		if (*cp == '(')		{
			if((cp2=strchr(cp,')')) != NULLCHAR)	{
				cp2++;
				*cp2++ = '\0';
				realname = cp;
				cp = cp2;
			}
		}
		cp = skipwhite (cp);

            t = atol(cp);
            lt = localtime(&t);
	    cp2 = "TELNET";
            if((cp = strchr(cp,'C'))!=NULLCHAR) {
                cp++;
                /* How was the connection made ? */
                switch(*cp) {
                    case 'A':
                        cp2 = "AX.25";
                        break;
                    case 'N':
                        cp2 = "NETROM";
                        break;
                }
            }

	    tprintf ("Information on %s %s\n", argv[1], (realname) ? realname : "");
            if (m == NULLMBX || m->stype == 'L')
		tprintf("%s last connected via %s on %s",argv[1],cp2,asctime(lt));
            tprintf ("%s's HOME BBS", argv[1]);
	    if (*home == '-')
	    	tprintf (" is unknown!\n");
            else	{
            	strcpy (buf, home);
            	if ((cp = strchr (buf, '.')) != 0)
            		*cp = 0;
            	strupr (buf);
		tprintf (": '%s'\n", buf);
	    }
            found = 1;
        }
    }
    fclose(Ufile);
    cp2 = wpage_exp (strdup (argv[1]), 1, 1);
    if (strchr(cp2, '.'))	{
    	    strupr (cp2);
	    tprintf ("%s's WHITE PAGES: '%s'\n", argv[1], cp2);
    } else if (home && home == Hostname)	{
	tprintf ("%s's WHITE PAGES: '", argv[1]);
	sprintf (buf, "%s@", argv[1]);
        pax25(&buf[strlen(buf)],Mycall);
        if((cp = strchr(buf,'-')) != NULLCHAR)
            *cp = '\0'; /* remove SSID */
        strupr (buf);
        tputs (buf);
	sprintf(buf,"%s%s'\n", (Mbhaddress != NULLCHAR) ? "." : "",
		(Mbhaddress != NULLCHAR) ? Mbhaddress : "");
	strupr (buf);
        tputs (buf);
    }    
    free (cp2);
    if((addr = resolve(argv[1])) != 0){
	trans = DTranslate;             /* Save IP address translation state */
	DTranslate = 0;                 /* Force output to be numeric IP addr */
	tprintf("%s's TCP/IP ADDRESS: %s\n",argv[1], inet_ntoa(addr));
	DTranslate = trans;             /* Restore original state */
    }

    if(!found)
        tprintf("No local data found for %s\n",argv[1]);
    return 0;
}

#endif

int
dombusers(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    register struct mbx *m,*caller;
	int i, len;
	char *cp, *cp1, fsocket[MAXSOCKSIZE];
	char upl[40], down[40];

	struct usock *up, *up1;
	int s;
	time_t elapsedtime;

#ifdef NETROM
	struct nrroute_tab *np;
	char temp[AXBUF], *cp2, *cp3;
#endif

    caller = (struct mbx *) p;

    if (caller->stype == 'H' || caller->stype == 'P' || caller->stype == 'T' || caller->stype == 'A')
    	return dodelmsg(argc, argv, p);

    if(caller->stype == 'S')
        return dombmailstats(argc,argv,p);

    if(caller->stype == 'F' && (caller->privs & SYSOP_CMD))	{
    	if (argc < 3)	{
    		tputs ("Syntax: MF msg# BBSname\n");
    		return 0;
    	}
	s = atoi (argv[1]);
    	if (!s || (caller->nmsgs < s))
    		tputs ("Message number out of range\n");
    	else
	    	updateFwd (argv[2], caller->area, caller->mbox[s].bid);
    	return 0;
    }

    if(caller->stype == 'K' && (caller->privs & SYSOP_CMD))
        return dombkick(argc,argv,p);

    if(caller->stype == 'X' && (caller->privs & SYSOP_CMD))	{
        Expiretick(NULL);
        return 0;
    }
    if((caller->stype == 'W' || caller->stype == 'M' || caller->stype == 'C') && (caller->privs & SYSOP_CMD))
        return dombmovemail(argc,argv,p);
    if (caller->stype == 'R')		{
    	FILE *fp;
    	char *from, *to = NULLCHAR, *file, msgtype;
	if (!(caller->privs & SYSOP_CMD))	{
    		tputs ("Only available to SYSOPs, sorry!\n");
    		return 0;
    	}
    	if (argc < 4 || argc > 5)	{
    		tputs ("Syntax: MR type filename toname [fromname]\n");
    		return 0;
    	}
	if (!(file = permtest(caller->path, caller->privs,argv[2],RETR_CMD, NULLCHAR, 0)))
		return 0;
    	
    	if ((fp = fopen (file, READ_TEXT)) != NULLFILE)	{
    		from = host_or_wpage_exp (strdup ((argc == 5) ? argv[4] : caller->name), 1, 0);
    		msgtype = toupper(argv[1][0]);
    		if (msgtype != 'B')
			to = host_or_wpage_exp (strdup (argv[3]), 1, 0);
    		tputs ("Subject:\n");
    		if (mbxrecvline(caller) != -1)	{
	    		rdaemon (fp, from, to, caller->line, msgtype, 0);
    			tputs ("Message queued\n");
			smtptick(NULL);		/* wake up SMTP to send mail */
		}
    		fclose (fp);
    		free (from);
    		free (to);
    	} else
    		tprintf ("Unable to open file '%s'\n", file);
    	free(file);
    	return 0;
    }

    if(caller->stype == 'L')
#ifdef USERLOG
        if((argc > 1) && (atoi(argv[1]) == 0))
            return dombuserinfo(argc,argv,p);
        else
#endif
            return dombpast(argc,argv,p);

    tputs("Users:\n");

	for(i = 0; i < NUMMBX; i++) {
		if((m = Mbox[i]) != NULLMBX){
			len = MAXSOCKSIZE;
			getpeername(m->user,fsocket,&len);
			cp = strdup(psocket(fsocket));

			upl[0] = '\0';
			down[0] = '\0';

			switch(m->family) {		/* UPLINK */
#ifdef AX25
			case AF_AX25:
                   sprintf(upl,Uplink,cp);
				break;
#endif
#ifdef NETROM
			case AF_NETROM:
				if((cp1 = strchr(cp,' ')) != NULLCHAR)
					*cp1 = '\0';
				cp1 += 3;
				setcall(temp,cp1);
                np = find_nrroute(temp);
                cp2 = strdup(np->alias);
				if((cp3 = strchr(cp2,' ')) != NULLCHAR)
					*cp3 = '\0';
            /*
                if(*cp2 == '#' || *cp2 == '\0')
                    sprintf(upl,incircuit,"","",cp1,cp);
				else
             */
             /* show correct user name when outgoing forward over netrom
              * problem caused by use of the '.C xxx' lines.
              */
                if(m->state == MBX_TRYING || m->state == MBX_FORWARD)
                    sprintf(upl,incircuit,cp2,":",cp1,m->name);
                else
                    sprintf(upl,incircuit,cp2,":",cp1,cp);
				free(cp2);
				break;
#endif
			case AF_INET:
				if((cp1 = strchr(cp,':')) != NULLCHAR)
					*cp1 = '\0';
                sprintf(upl,Telnet,m->name,cp);
				break;
			case AF_LOCAL:
                sprintf(upl,Local,m->name,Hostname);
				break;
			default:
				strcpy(upl,"Connect");
				break;
			}
			free(cp);
			if (m->state == MBX_TRYING)	/* forwarding session */
				sprintf (upl, "Forwarding Daemon: %s", m->name);
			tprintf("%-36s",upl);

	    /* Show their elapsed time on system - KO4KS */
	    	elapsedtime = 0;
		if (m->state != MBX_LOGIN)	{
		        time((time_t *)&elapsedtime);
        		elapsedtime -= m->logontime;
		}
		tprintf (" %10.10s", (m->state == MBX_TRYING) ? "" : tformat (elapsedtime));
	    
            /* Now show what they are doing - WG7J */
            if(m->state != MBX_GATEWAY)
                tputs("  -> ");
            switch(m->state){
            case MBX_GATEWAY:
                for(s = SOCKBASE; s < Nusock + SOCKBASE; s++) {
                    if((up = itop(s)) == NULLUSOCK || s == m->user)
                        continue;
                    up1 = itop(m->user);
                    if(up->owner == up1->owner) {
                        getpeername(s,fsocket,&len);
                        cp = strdup(psocket(fsocket));
                        switch(up->type) {
                            case TYPE_TCP:
#ifdef notdef
                                if((cp1 = strchr(cp,':')) != NULLCHAR)
                                    *cp1 = '\0';
#endif
                                sprintf(down,Telnetdown,cp);
                                break;
#ifdef AX25
                            case TYPE_AX25I:
                                /*
                                if((cp1 = strchr(cp,' ')) != NULLCHAR)
                                    *cp1 = '\0';
                                */
                                sprintf(down,Downlink,cp);
                                break;
#endif
#ifdef NETROM
                            case TYPE_NETROML4:
                                /*get rid of usercall*/
                                if((cp1 = strchr(cp,' ')) != NULLCHAR)
                                    *cp1 = '\0';
                                cp1 += 3;   /*get rid of ' @ '*/
                                setcall(temp,cp1);      /*get node call*/
                                np = find_nrroute(temp);/*find alias, if any*/
                                cp2 = strdup(np->alias);
                                if((cp3 = strchr(cp2,' ')) != NULLCHAR)
                                    *cp3 = '\0';
                                /*
                                memcpy(cp,m->call,AXALEN);
                                cp[ALEN] ^= 0x1e;
                                */
                                /*
                                if(*cp2 == '#' || *cp2 == '\0')
                                    sprintf(down,outcircuit,"","",cp1);
                                else
                                */
                                sprintf(down,outcircuit,cp2,":",cp1);
                                free(cp2);
                                break;
#endif
                            case TYPE_LOCAL_STREAM:
                            case TYPE_LOCAL_DGRAM:
                                sprintf(down,Local,m->name, Hostname);
                                break;
                            default:
                                strcpy(down,"Connect");
                                break;
                        }
                        free(cp);
                        tprintf("<--> %s\n",down);
                        break;
                    }
                }
                break;
            case MBX_LOGIN:
                tputs("Logging in\n");
                break;
            case MBX_CMD:
                tputs("Idle\n");
                break;
            case MBX_SUBJ:
            case MBX_DATA:
                tputs("Sending message\n");
                break;
            case MBX_REVFWD:
                tputs("Reverse Forwarding\n");
                break;
            case MBX_TRYING:
                tputs("Attempting Forward\n");
                break;
            case MBX_FORWARD:
                tputs("Forwarding\n");
                break;
            case MBX_READ:
                tputs("Reading message\n");
                break;
            case MBX_UPLOAD:
                tputs("Uploading file\n");
                break;
            case MBX_DOWNLOAD:
                tputs("Downloading file\n");
                break;
#ifdef CONVERS
            case MBX_CONVERS:
                tputs("Convers mode\n");
                break;
#endif
            case MBX_TUTOR:
                tputs("Being Tutored\n");
                break;
            case MBX_CHAT:
                tputs("Chatting with sysop\n");
                break;
            case MBX_WHAT:
                tputs("Listing files\n");
                break;
	    case MBX_XMODEM_RX:
		tputs("Xmodem Receiving\n");
		break;
	    case MBX_XMODEM_TX:
		tputs("Xmodem Sending\n");
		break;
            }
            /* Only show callers with sysop-privs who is sysop-mode!
             * This prevents users from easily learning who's
             * got SYSOP privs
             */
            if(m->state == MBX_SYSOPTRY) {
                if(caller->privs & SYSOP_CMD)
                    tputs("Attempting Sysop mode\n");
                else
                    tputs("Idle\n");
            } else {
                if(m->state == MBX_SYSOP) {
                    if(caller->privs & SYSOP_CMD)
                        tputs("Sysop mode\n");
                    else
                        tputs("Idle\n");
                }
            }
        }
    }
    tputc('\n');
	return 0;
}

#ifdef TIPMAIL
#ifdef ALLSERV
static int
dotimeout(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return setuns(&Tiptimeout,"Tip connection timeout",argc,argv);
}
static int
dotipsecurity(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return setlong(&Mbtipperms,"Tip security permission (for anonymous)",argc,argv);
}
#endif
#endif

#ifdef MBFWD
static int
dombsubchannel(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int netnum;
char buf[60], *cp;

	if (argc == 1)	{
		for (netnum = 0; netnum < NUMMBX; netnum++)
			tprintf ("Subchannel %2d: Maximum Fwds - %2d, Currently - %2d\n", netnum, (int) subchannels[netnum], (int) subchannelusage[netnum]);
		return 0;
	}
	if (argv[1][0] == '?')	{
		tputs ("Usage: mbox subchannel channel# [maxfwds]\n");
		return 0;
	}
	netnum = atoi (argv[1]);
	if (netnum > NUMMBX)	{
		tprintf ("Valid subchannel numbers are 0 through %d\n", NUMMBX);
		return 0;
	}
	sprintf (buf, "Maximum Forwarding Sessions on Subchannel %d", netnum);
	cp = argv[1];
	argv[1] = argv[2];
	argv[2] = cp;
	return setuns(&subchannels[netnum],buf,argc - 1,argv);
}

static int
dombtrace(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return setbool(&Mtrace,"Mailbox trace flag",argc,argv);
}
#endif

static int
dombsecure(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return setbool(&MBSecure,"Mailbox gateway secure flag",argc,argv);
}

#ifdef CALLBOOK
char *InetCallserver = NULLCHAR;
char *InetCallserverport = NULLCHAR;

int
doinetcallserver(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	if(argc == 1) {
        if(InetCallserver != NULLCHAR) {
            tprintf("Server %s, on port %s\n",InetCallserver,InetCallserverport);
		} else
			tputs("Not set!\n");
		return 0;
	}
	if(argc == 2) {
		tputs("Usage: callserver <host> <port>\n");
		return 0;
	}
	/*Check validity of the parameters*/
	if(resolve(argv[1]) == (int32) 0) {
		tprintf(Badhost,argv[1]);
		return 0;
	}
	if(atoi(argv[2]) == (int) 0) {
		tprintf("Bad port %s\n",argv[2]);
		return 0;
	}
    if(InetCallserver != NULLCHAR) {
        free(InetCallserver);
        free(InetCallserverport);
	}
    InetCallserver = strdup(argv[1]);
    InetCallserverport = strdup(argv[2]);
	return 0;
}
#endif /* CALLBOOK */

char *cmd_line(argc, argv, stype)
int argc;
char *argv[];
char stype;
{
    static char line[MBXLINE+1];
    int i;
    char *cp;


    cp = line;
    sprintf(cp,"%s ",argv[0]);
    cp+=strlen(cp);
    if(stype != ' ') {
        --cp;
        if (islower(*line))
        	tolower(stype);
        sprintf(cp,"%c ",stype);
        cp += 2;
    }
    for(i=1;i<argc;i++) {
        sprintf(cp,"%s ",argv[i]);
        cp += strlen(cp);
    }
    return line;
}

#endif /* MAILBOX */
