/* NOTE: because of size, the previous 'mailbox.c' has been
 * split in 3 parts:
 * pbbscmd.c, containing the 'pbbs' 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 "global.h"
#include "ctype.h"
#include "commands.h"
#ifndef MSDOS
#include <time.h>
#endif
#ifdef  UNIX
#include <sys/stat.h>
#endif
#include "timer.h"
#include "proc.h"
#include "socket.h"
#include "usock.h"
#include "session.h"
#include "smtp.h"
#include "ftpserv.h"
#include "bm.h"
#include "pool.h"
#include "assoc.h"


#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: pbbscmd.c,v 1.30 2001/05/06 16:32:58 brian Exp $";
#endif

#ifdef MAILBOX

#ifdef MSDOS
extern void mbmemory (void);
#endif

#ifdef EXPIRY
extern void Expiretick (void *);
#endif
extern char *mblookname (struct mbx * m, char *str);
extern int dombmovemail (int argc, char *argv[], void *p);
extern char *host_or_wpage_exp (char *to, int hier, int exphome, int *dns);
extern char *wpage_exp (char *to, int hier, int exphome);
extern char *permtest (char *path, long privs, const char *name, int mode, char *root, int thedir);
extern int dombkickone (int argc, char *argv[], void *p);

extern char Myalias[];
extern char MyBBS[AXALEN];
#ifdef EXPIRY
extern int ExpireActive;
extern char *ExpireArea;
extern time_t ExpireLast;
#endif
#ifdef MBFWD
extern char *mbxRCall;
#endif
extern char *Mbhaddress;

extern int BbsUsers;
extern int Totallogins, Tutorlogins[], BBSlogins;
#ifdef CONVERS
extern int Conflogins;
#endif
char *Mbprompt;
char *MMotd;
char *MExit;
char *Mtmsg;
char *MAttendedAt;
int MOTDalways = 0;
int MAttended = 0;
int MBnoSubjBell = 0;
int MBnoReturnReceipt = 0;
int enforceBhosts = 0;
int MBackfilter = 0;
int LoginTimer = 180;

#ifdef EXPIRY
#define HALFYEAR 182		/* used for expiring personal areas */
int PruneAge = HALFYEAR;
#endif
char Mbpasswd[MAXPWDLEN + 1] = "";
struct no_js *Exclude = (struct no_js *) NULL;

#ifdef ASKHOME
static char *Mbhome = NULLCHAR;
#endif

AarrayPtr Mbcustom = NULLASSOC;


#ifdef MBFWD
extern int MbForwarded;
int Mbfullsvc = 1;
#endif

#ifdef DELEGATE
int Mbdelegate = 1;
#endif

#ifdef AX25
int Mbaxpasswd = 0;
#endif

extern int MbSent;
extern int MbRead;
extern int MbRecvd;


const char *continents[] =
{
	"euro", "medr", "indi", "mdle", "seas", "asia", "noam",
	"ceam", "carb", "soam", "aunz", "epac", "npac", "spac",
	"wpac", "nafr", "cafr", "safr", "antr"
};

#define numcontinents 19


#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)";

const char *displayMBstatus (int state, int issysop);
int isaPBBShost (char *str);

#ifdef USERLOG
void updatedefaults (struct mbx * m, int homeonly);
void askrealname (struct mbx * m, int initial);
int dorealname (int argc, char *argv[], void *p);
#endif

char *findhome (char *name);
void askhome (struct mbx * m, int initial);
int dobbshome (int argc, char *argv[], void *p);
char *cmd_line (int argc, char *argv[], char stype);
int dostr (int argc, char *argv[], const char *cmdstr, const char *label, char **str);
static int dobbsdumperr (int argc, char *argv[], void *p);
static int dombnewscan (int argc, char *argv[], void *p);
static int dombarea (int argc, char *argv[], void *p);
static int dombmore (int argc, char *argv[], void *p);
static int dombnorreceipt (int argc, char *argv[], void *p);

#ifdef MAILCMDS
static int dombscan (int argc, char *argv[], void *p);
static int dombholdsumm (int argc, char *argv[], void *p);
static int dopbbsreview (int argc, char *argv[], void *p);
static int dombmport (int argc, char *argv[], void *p);
static int dombbonly (int argc, char *argv[], void *p);
static int dombsendquery (int argc, char *argv[], void *p);
static int dombholdall (int argc, char *argv[], void *p);
static int dombhold (int argc, char *argv[], void *p);
static int dombnobid (int argc, char *argv[], void *p);
#endif

static int dombalias (int argc, char *argv[], void *p);
static int donewmotdfile (int argc, char *argv[], void *p);
static int doattend (int argc, char *argv[], void *p);

static int dombnewuser (int argc, char *argv[], void *p);
static int dombmotd (int argc, char *argv[], void *p);
static int dombmotdalways (int argc, char *argv[], void *p);
static int domexit (int argc, char *argv[], void *p);
int dombusers (int argc, char *argv[], void *p);
int dombpast (int argc, char *argv[], void *p);
static int dojumpstart (int argc, char *argv[], void *p);
static int dombnrid (int argc, char *argv[], void *p);
static int dombsetpasswd (int argc, char *argv[], void *p);
static int dombenforce (int argc, char *argv[], void *p);
static int dombnoax25 (int argc, char *argv[], void *p);
static int dombuonly (int argc, char *argv[], void *p);
static int dombsonly (int argc, char *argv[], void *p);
static int dombmaint (int argc, char *argv[], void *p);
static int dombmaintstr (int argc, char *argv[], void *p);
static int dombmaintmode (int argc, char *argv[], void *p);
static int dombmaintclear (int argc, char *argv[], void *p);
extern int dombmailfor (int argc, char *argv[], void *p);
extern int dombstatus (int argc, char *argv[], void *p);
int dombmailstats (int argc, char *argv[], void *p);
static int dombtmsg (int argc, char *argv[], void *p);
#ifdef EXPIRY
static int dombprune (int argc, char *argv[], void *p);
static int dombpruneage (int argc, char *argv[], void *p);
static void mbpruning (int a, void *v1, void *v2);
extern void expire (char *, int);
#endif
static int dombackfilter (int argc, char *argv[], void *p);
static int domaildomain (int argc, char *argv[], void *p);
static int dombremote (int argc, char *argv[], void *p);
static int dombbump (int argc, char *argv[], void *p);
static int dombzap (int argc, char *argv[], void *p);
static int dombhideport (int argc, char *argv[], void *p);
static int domblogging (int argc, char *argv[], void *p);
static int dombmaxtimer (int argc, char *argv[], void *p);
static int dombmaxusers (int argc, char *argv[], void *p);
static int dombprompt (int argc, char *argv[], void *p);
static int dombcmd (int argc, char *argv[], void *p);
static int dombnosubjbell (int argc, char *argv[], void *p);
static int doaxpasswd (int argc, char *argv[], void *p);
static int domblogintimer (int argc, char *argv[], void *p);


#ifdef STRICT_CALL
static int dombstrict (int argc, char *argv[], void *p);
#endif

#ifdef DELEGATE
static int dombdelegate (int argc, char *argv[], void *p);
#endif

extern void updateFwd (char *who, char *area, long bid, long size);
extern void bbsbump (char *user, int zap);

#ifdef MBXTDISC
static int dombtdisc (int argc, char *argv[], void *p);
static int dombtdiscsysop (int argc, char *argv[], void *p);
#endif

#ifdef ASKHOME
static int dombhome (int argc, char *argv[], void *p);
#endif

#ifdef MBFWD
static int dombfullsvc (int argc, char *argv[], void *p);
#endif

#ifdef CONVERS
static int dombconvlink (int argc, char *argv[], void *p);
#endif

#if defined(TIPMAIL) && defined(ALLSERV)
static int dotimeout (int argc, char *argv[], void *p);
#endif

#ifdef REJECT
static int dombreject (int argc, char *argv[], void *p);
#endif

#ifdef CATALOG
#include "catalog.h"

#define CAT pbbscmd_catalog

#define bumpusage	__STR(0)
#define zapusage	__STR(1)
#define logging_str	__STR(2)
#define holdall_str	__STR(3)
#define maint_str	__STR(4)
#define maintmode_str	__STR(5)
#define maintclear_str	__STR(6)
#define invalidcall	__STR(7)
#define jumpstart_str	__STR(8)
#define nrid_str	__STR(9)
#define mbarea_str	__STR(10)
#define scan_str	__STR(11)
#define hold_str	__STR(12)
#define fullsvc_str	__STR(13)
#define delegate_str	__STR(14)
#define nobid_str	__STR(15)
#define query_str	__STR(16)
#define convers_str	__STR(17)
#define dumperr_str	__STR(18)
#define attend_str	__STR(19)
#define tdisc_str	__STR(20)
#define tdiscsysop_str	__STR(21)
#define maxtimer_str	__STR(22)
#define maxusers_str	__STR(23)
#define passwdusage	__STR(24)
#define strusage	__STR(25)
#define motdalways_str	__STR(26)
#define allview_str	__STR(27)
#define homeusage	__STR(28)
#define promptusage	__STR(29)
#define changehome_str	__STR(30)
#define homeset_str	__STR(31)
#define homesyntax	__STR(32)
#define realname_as	__STR(33)
#define realname_str	__STR(34)
#define realname_change	__STR(35)
#define realname_set	__STR(36)
#define realname_syntax	__STR(37)
#define past_header	__STR(38)
#define queued_str	__STR(39)
#define ms_logins	__STR(40)
#define users_count	__STR(41)
#define info_on		__STR(42)
#define ipaddress_str	__STR(43)
#define nolocal_str	__STR(44)
#define message_oor	__STR(45)
#define mr_syntax	__STR(46)
#define fwd_daemon	__STR(47)
#define tiptimeout_str	__STR(48)
#ifdef CALLBOOK
#define callusage	__STR(49)
#endif
#define usernoton	__STR(50)
#define sysopchat	__STR(51)
#define nosubj_str	__STR(52)
#define enforce_str	__STR(53)
#define maildomain_str	__STR(54)
#define norreceipt_str	__STR(55)
#define mbmore_str	__STR(56)
#define ackfilter_str	__STR(57)
#ifdef EXPIRY
#define pruneage_str	__STR(58)
#endif
#define axpasswd_str	__STR(59)
#define mbtimer_str	__STR(60)


#else /* CATALOG */

static const char bumpusage[] = "Syntax: pbbs bump username\n";
static const char zapusage[] = "Syntax: pbbs zap username\n";
static const char logging_str[] = "Keep log of each PBBS login";
static const char holdall_str[] = "Hold all local messages for SYSOP review";
static const char maint_str[] = "BBS Maintenance";
static const char maintmode_str[] = "Use BBS Maintenance mode";
static const char maintclear_str[] = "Clear BBS (bump users) for BBS Maintenance mode";
static const char invalidcall[] = "Invalid call: %s\n";
static const char jumpstart_str[] = "Jump start on connect";
static const char nrid_str[] = "Netrom id prompt";
static const char mbarea_str[] = "New users get area indication in prompt";
static const char scan_str[] = "New users get 'new mail scan' permission";
static const char hold_str[] = "New users have mail entered held for review";
static const char fullsvc_str[] = "Full Service BBS";
static const char delegate_str[] = "Allow user delegation forwarding";
static const char nobid_str[] = "Accept Buls without BID";
static const char query_str[] = "Query after send";
static const char convers_str[] = "PBBS convers";
static const char dumperr_str[] = "BBS - Dump on error";
static const char attend_str[] = "Mailbox Attended flag";
static const char tdisc_str[] = "PBBS redundancy timer (sec)";
static const char tdiscsysop_str[] = "PBBS redundancy timer used for Sysops";
static const char maxtimer_str[] = "PBBS Maximum session time allowed (sec)";
static const char maxusers_str[] = "Maximum PBBS incoming users (%d max)";
static const char passwdusage[] = "Usage: pbbs password \"<sysop password>\"\n";
static const char strusage[] = "Usage: %s %s \"<your message>\"\n";
static const char motdalways_str[] = "Always display MOTD file";
static const char allview_str[] = "All users will view the 'motd' file on their next login!\n";
static const char homeusage[] = "Usage: pbbs home <your prompt string>\n";
static const char promptusage[] = "Usage: pbbs prompt \"prompt string\"\n";
static const char changehome_str[] = "\nChanging HOME BBS from '%s'! Enter name of new HOME...\n";
static const char homeset_str[] = "\nHOME BBS set to '%s'\n";
static const char homesyntax[] = "Syntax: HOME user @bbs\n";
static const char realname_as[] = "\nThe on-line callbook shows your real name as '%s'\n";
static const char realname_str[] = "Your real name is used along with your callsign when sending a message\n"
"If you wish to %s this, use the NAME command\n";
static const char realname_change[] = "\nChanging REAL NAME from '%s'!\nEnter the name you wish to be known by...\n";
static const char realname_set[] = "\nREAL NAME set to '%s'\n";
static const char realname_syntax[] = "Syntax: NAME user \"realname\"\n";
static const char past_header[] = "Past users:\nUser       Logins  Time since last   User       Logins  Time since last\n";
static const char queued_str[] = "SMTP queued messages: %d\n";
static const char ms_logins[] = "Total Logins: %d   (BBS: %d";
static const char users_count[] = "Users: %d\nCount: %d\n";
static const char info_on[] = "Information on %s %s\n";
static const char ipaddress_str[] = "%s's TCP/IP ADDRESS: %s\n";
static const char nolocal_str[] = "No local data found for '%s'\n";
static const char message_oor[] = "Message number out of range\n";
static const char mr_syntax[] = "Syntax: MR type filename toname [fromname]\n";
static const char fwd_daemon[] = "Forwarding Daemon: %s";
static const char tiptimeout_str[] = "Tip connection timeout";
#ifdef CALLBOOK
static const char callusage[] = "Usage: callserver <host> <port>\n";
#endif
static const char usernoton[] = "User '%s' not on BBS!\n";
static const char sysopchat[] = "\nSYSOP requests a chat.....\n\n";
static const char nosubj_str[] = "Strip bell characters from subject lines";
static const char enforce_str[] = "Enforce that all bulletins are sent with a '@host'";
static const char maildomain_str[] = "Force user@host to use DNS hostname rather than WPages";
static const char norreceipt_str[] = "Disable responses to Return Receipt requests";
static const char mbmore_str[] = "New users get this value for 'more after' lines";
static const char ackfilter_str[] = "Filter out all '/ack' lines in email messages";
static const char pruneage_str[] = "Number of days to save messages when pruning";
static const char axpasswd_str[] = "Require all non-anonyous, non-PBBS AX.25 users to provide password";
static const char mbtimer_str[] = "Login timeout delay (in seconds)";
#endif /* CATALOG */



static void smtpqueuecheck (void);

int Mbjumpstart = 1;
int Usenrid = 0;
int Usescan = 0;
int Usearea = 1;
int Usemore = 0;
int Usehold = 0;
int NoBid;
int MbLogging = 0;
static int PBBSmaildomain = 0;
#ifdef STRICT_CALL
int PBBSstrict = 0;
#endif
int MBXMaint = 0;
int MBXMaintMode = 1;
static int MBXMaintClear = 0;
char *MBXMaintStr;
int Mbsendquery = 1;
char Mbnrid[20];

#ifdef MBXTDISC
int32 Mbtdiscinit = 0;
int MbtdiscSysop = 1;
#endif

int32 mbxMaxTimer = 0;
int mbxMaxUsers;
extern int MbHoldall;

#ifdef REJECT
int MbReject = 0;
#endif


/* pbbs subcommand table */
static struct cmds Mbtab[] =
{
	{ "ackfilter",	dombackfilter,	0,	0,	NULLCHAR },
	{ "alias",	dombalias,	0,	0,	NULLCHAR },
	{ "attend",	doattend,	0,	0,	NULLCHAR },
	{ "ax25passwd",	doaxpasswd,	0,	0,	NULLCHAR },
	{ "bbsdumperr",	dobbsdumperr,	0,	0,	NULLCHAR },
#if defined(MAILCMDS) && defined(AX25)
	{ "bbsonly",	dombbonly,	0,	0,	NULLCHAR },
#endif
	{ "bump",	dombbump,	0,	2,	"pbbs bump <bbsuser>" },
#if defined(FOQ_CMDS) && defined(ALLSERV)
	{ "chat",	dombchat,	0,	2,	"pbbs chat <bbsuser>" },
#endif
	{ "cmd",	dombcmd,	0,	0,	NULLCHAR },
#ifdef CONVERS
	{ "convers",	dombconvlink,	0,	0,	NULLCHAR },
#endif
#ifdef MAILCMDS
#ifdef DELEGATE
	{ "delegate",	dombdelegate,	0,	0,	NULLCHAR },
#endif
	{ "enforce",	dombenforce,	0,	0,	NULLCHAR },
#ifdef MBFWD
	{ "fullservice",dombfullsvc,	0,	0,	NULLCHAR },
#endif
#endif
#ifdef MAILCMDS
	{ "holdsummary",dombholdsumm,	0,	0,	NULLCHAR },
#endif
	{ "hideport",	dombhideport,	0,	0,	NULLCHAR },
#ifdef MAILCMDS
	{ "holdall",	dombholdall,	0,	0,	NULLCHAR },
#endif
#ifdef ASKHOME
	{ "home",	dombhome,	0,	0,	NULLCHAR },
#endif
#ifdef AX25
	{ "jumpstart",	dojumpstart,	0,	0,	NULLCHAR },
#endif
	{ "logging",	domblogging,	0,	0,	NULLCHAR },
	{ "logintimer",	domblogintimer,	0,	0,	NULLCHAR },
	{ "maildomain",	domaildomain,	0,	0,	NULLCHAR },
#if defined(MAILFOR) && defined(AX25) && defined(MAILCMDS)
	{ "mailfor",	dombmailfor,	0,	0,	NULLCHAR },
#endif
	{ "mailstats",	dombmailstats,	0,	0,	NULLCHAR },
	{ "maintenance",dombmaint,	0,	0,	NULLCHAR },
	{ "maintclear",	dombmaintclear,	0,	0,	NULLCHAR },
	{ "maintmode",	dombmaintmode,	0,	0,	NULLCHAR },
	{ "maintstr",	dombmaintstr,	0,	0,	NULLCHAR },
	{ "maxtimer",	dombmaxtimer,	0,	0,	NULLCHAR },
	{ "maxusers",	dombmaxusers,	0,	0,	NULLCHAR },
	{ "mexit",	domexit,	0,	0,	NULLCHAR },
	{ "motd",	dombmotd,	0,	0,	NULLCHAR },
	{ "motdalways",	dombmotdalways,	0,	0,	NULLCHAR },
#if defined(AX25) && defined(MAILCMDS)
	{ "mport",	dombmport,	0,	0,	NULLCHAR },
#endif
	{ "newuser",	dombnewuser,	0,	0,	NULLCHAR },
	{ "newmotdfile",donewmotdfile,	0,	0,	NULLCHAR },
#ifdef AX25
	{ "noax25",	dombnoax25,	0,	0,	NULLCHAR },
#endif
#ifdef MAILCMDS
	{ "nobid",	dombnobid,	0,	0,	NULLCHAR },
#endif
	{ "norreceipt",	dombnorreceipt,	0,	0,	NULLCHAR },
	{ "nosubjbell",	dombnosubjbell,	0,	0,	NULLCHAR },
	{ "past",	dombpast,	0,	0,	NULLCHAR },
	{ "password",	dombsetpasswd,	0,	0,	NULLCHAR },
	{ "prompt",	dombprompt,	0,	0,	NULLCHAR },
#ifdef EXPIRY
	{ "prune",	dombprune,	0,	0,	NULLCHAR },
	{ "pruneage",	dombpruneage,	0,	0,	NULLCHAR },
#endif
#ifdef MAILCMDS
	{ "review",	dopbbsreview,	0,	0,	NULLCHAR },
#endif
#ifdef REJECT
	{ "reject",	dombreject,	0,	0,	NULLCHAR },
#endif
	{ "remote",	dombremote,	0,	0,	NULLCHAR },
#ifdef MAILCMDS
	{ "scan",	dombscan,	0,	2,	"pbbs scan <bbsuser>" },
	{ "sendquery",	dombsendquery,	0,	0,	NULLCHAR },
#endif
	{ "status",	dombstatus,	0,	0,	NULLCHAR },
#ifdef STRICT_CALL
	{ "strictcall",	dombstrict,	0,	0,	NULLCHAR },
#endif
#ifdef  AX25
	{ "sysoponly",	dombsonly,	0,	0,	NULLCHAR },
#endif
#ifdef MBXTDISC
	{ "tdisc",	dombtdisc,	0,	0,	NULLCHAR },
	{ "tdiscsysop",	dombtdiscsysop,	0,	0,	NULLCHAR },
#endif
#if defined(TIPMAIL) && defined(ALLSERV)
	{ "tiptimeout",	dotimeout,	0,	0,	NULLCHAR },
#endif
	{ "tmsg",	dombtmsg,	0,	0,	NULLCHAR },
#ifdef AX25
	{ "usersonly",	dombuonly,	0,	0,	NULLCHAR },
#endif
	{ "zap",	dombzap,	0,	0,	NULLCHAR },
	{ NULLCHAR,	NULL,		0,	0,	NULLCHAR }
};




/* pbbs newuser subcommand table */
static struct cmds Mbnewtab[] =
{
	{ "area",	dombarea,	0,	0,	NULLCHAR },
#ifdef MAILCMDS
	{ "hold",	dombhold,	0,	0,	NULLCHAR },
#endif
	{ "more",	dombmore,	0,	0,	NULLCHAR },
#ifdef AX25
	{ "nrid",	dombnrid,	0,	0,	NULLCHAR },
#endif
	{ "scan",	dombnewscan,	0,	0,	NULLCHAR },
	{ NULLCHAR,	NULL,		0,	0,	NULLCHAR }
};



/*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 (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
struct mbx m;

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



static int
dombbump (int argc, char *argv[], void *p OPTIONAL)
{
	if (argc == 1)
		tputs (bumpusage);
	else
		bbsbump (argv[1], 0);
	return 0;
}



static int
dombzap (int argc, char *argv[], void *p OPTIONAL)
{
	if (argc == 1)
		tputs (zapusage);
	else
		bbsbump (argv[1], 1);
	return 0;
}



static int
domaildomain (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&PBBSmaildomain, maildomain_str, argc, argv);
}



#ifdef STRICT_CALL
static int
dombstrict (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&PBBSstrict, "Allow login from callsigns, only", argc, argv);
}
#endif



static int
domblogging (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&MbLogging, logging_str, argc, argv);
}



static int
dombenforce (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&enforceBhosts, enforce_str, argc, argv);
}



static int
dombackfilter (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&MBackfilter, ackfilter_str, argc, argv);
}



#ifdef MAILCMDS
static int
dombholdall (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&MbHoldall, holdall_str, argc, argv);
}



static int
dombnobid (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&NoBid, nobid_str, argc, argv);
}



static int
dombsendquery (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&Mbsendquery, query_str, argc, argv);
}



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

	tputc ('\n');
	m.privs = SYSOP_CMD;
	m.stype = 'H';

	return doarea (0, NULLCHARP, &m);
}



static int
dombscan (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
{
struct mbx m;
char *buf;
long perm;

	tputc ('\n');
	m.privs = 0;
	m.stype = ' ';
	strncpy (m.name, argv[1], 20);
	(void) strupr (m.name);

	if ((buf = userlookup (m.name, NULLCHARP, NULLCHARP, &perm, NULL)) != NULLCHAR)	{
		m.privs = perm;
		free (buf);
	}

	quickscan (&m, 1, 1);
	return 0;
}



static int
dopbbsreview (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
struct mbx m;
int oldflow = Command->flowmode;

	tputc ('\n');
	m.privs = SYSOP_CMD | FTP_WRITE;
	m.stype = ' ';
	m.morerows = 0;
	m.quickfile = (FILE *) -1;
	m.sid = 0;
	m.user = Curproc->output;
	m.mfile = NULLFILE;
	m.area[0] = 0;
	strcpy (m.name, "sysop");
	if (Curproc->input == Command->input)
		Command->flowmode = 1;

	(void) dombreview (0, NULLCHARP, &m);

	Command->flowmode = oldflow;
	return 0;
}
#endif



#ifdef REJECT
static int
dombreject (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&MbReject, "Process 'reject.dat' file", argc, argv);
}
#endif



static int
dombmaint (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&MBXMaint, maint_str, argc, argv);
}



static int
dombmaintmode (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&MBXMaintMode, maintmode_str, argc, argv);
}



static int
dombmaintclear (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&MBXMaintClear, maintclear_str, argc, argv);
}



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



static int
dombnewuser (int argc, char *argv[], void *p)
{
	return subcmd (Mbnewtab, argc, argv, p);
}



#ifdef AX25

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



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

	if ((argc > 1) && (*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 (invalidcall, argv[i + 2]);
					free (ep);
				} else {	/* add to list */
					ep->next = Exclude;
					Exclude = ep;
				}
			}
		}
		return 0;
	}
	return setbool (&Mbjumpstart, jumpstart_str, argc, argv);
}



static int
dombnrid (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&Usenrid, nrid_str, argc, argv);
}



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



static int
dombhold (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&Usehold, hold_str, argc, argv);
}
#endif



static int
dombnoax25 (int argc, char *argv[], void *p)
{
	return (dosetflag (argc, argv, p, NO_AX25, 1));
}
#endif /* AX25 */



static int
dombarea (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&Usearea, mbarea_str, argc, argv);
}



static int
domblogintimer (int argc, char *argv[], void *p OPTIONAL)
{
	return setint (&LoginTimer, mbtimer_str, argc, argv);
}



static int
dombmore (int argc, char *argv[], void *p OPTIONAL)
{
	return setint (&Usemore, mbmore_str, argc, argv);
}



static int
dombnewscan (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&Usescan, scan_str, argc, argv);
}



static int
dombnosubjbell (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&MBnoSubjBell, nosubj_str, argc, argv);
}



static int
dombnorreceipt (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&MBnoReturnReceipt, norreceipt_str, argc, argv);
}



#ifdef MBFWD
static int
dombfullsvc (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&Mbfullsvc, fullsvc_str, argc, argv);
}
#endif



static int
doaxpasswd (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&Mbaxpasswd, axpasswd_str, argc, argv);
}



#ifdef DELEGATE
static int
dombdelegate (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&Mbdelegate, delegate_str, argc, argv);
}
#endif



#ifdef CONVERS
int Mbconverse = 1;

static int
dombconvlink (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&Mbconverse, convers_str, argc, argv);
}
#endif



int BBSdump = 1;

static int
dobbsdumperr (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&BBSdump, dumperr_str, argc, argv);
}



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



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



/* Set mailbox redundancy timer mode for sysops */
static int
dombtdiscsysop (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&MbtdiscSysop, tdiscsysop_str, argc, argv);
}
#endif



/* Set mailbox maximum session timer */
static int
dombmaxtimer (int argc, char *argv[], void *p OPTIONAL)
{
	return setlong (&mbxMaxTimer, maxtimer_str, argc, argv);
}



/* Set mailbox maximum user count */
static int
dombmaxusers (int argc, char *argv[], void *p OPTIONAL)
{
char buf[50];

	sprintf (buf, maxusers_str, NUMMBX);
	return setint (&mbxMaxUsers, buf, argc, argv);
}



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

	/*Only allowed from keyboard*/
	if (Curproc->input != Command->input) {
		tputs (Noperm);
		return 0;
	}
	if (argc != 2) {
		tputs (passwdusage);
		return 0;
	}
	if ((len = (int) strlen (argv[1])) == 0)
		return 0;	/* zero length, don't reset */

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



/* define the BBS alias*/
static int
dombalias (int argc, char *argv[], void *p OPTIONAL)
{
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;
}



int
dostr (int argc, char *argv[], const char *cmdstr, const char *label, char **str)
{
	if (argc > 2) {
		tprintf (strusage, (cmdstr) ? cmdstr : "pbbs", label);
		return 0;
	}
	if (argc < 2) {
		if (*str != NULLCHAR) {
			tputs (*str);
			if (str[0][strlen (*str) - 1] != '\n')
				tputs ("\n");
		}
	} 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
dombmaintstr (int argc, char *argv[], void *p OPTIONAL)
{
	return dostr (argc, argv, NULLCHAR, "maintstr", &MBXMaintStr);
}



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



static int
dombmotdalways (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&MOTDalways, motdalways_str, argc, argv);
}



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



static int
donewmotdfile (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
#ifdef USERLOG
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) {
			(void) fclose (tfile);
			return 0;
		}
		while (fgets (buf, sizeof (buf), tfile) != NULLCHAR) {
			if ((cp = strchr (buf, ' ')) != NULLCHAR)
				if ((cp = strchr (cp, ' ')) != NULLCHAR)
					if ((cp = strchr (cp, ')')) != NULLCHAR)
						if ((cp = strchr (cp, 'R')) != NULLCHAR)
							*cp = ' ';
			fputs (buf, Ufile);
		}
		(void) fclose (tfile);
		(void) fclose (Ufile);
		tputs (allview_str);
	} else
		(void) rename (UDefbak, UDefaults);
	return 0;
#endif
}



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



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



#ifdef ASKHOME
/* Set the HOME BBS prompt string to be used */
static int
dombhome (int argc, char *argv[], void *p OPTIONAL)
{
	if (argc > 2) {
		tputs (homeusage);
		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 = strdup (argv[1]);
	}
	return 0;
}
#endif /* ASKHOME */



/* Set a custom BBS prompt string*/
static int
dombprompt (int argc, char *argv[], void *p OPTIONAL)
{
	if (argc > 2)
		tputs (promptusage);
	else if (argc < 2) {
		if (Mbprompt != NULLCHAR)
			tprintf ("%s\n", Mbprompt);
	} else {
		if (Mbprompt != NULLCHAR) {
			free (Mbprompt);
			Mbprompt = NULLCHAR;	/* reset the pointer */
		}
		if (!strlen (argv[1]))
			return 0;	/* clearing the buffer */
		Mbprompt = strdup (argv[1]);
	}
	return 0;
}



/* Keep track of all past users */
struct pu {
	struct pu *next;	/* next one in list */
	char name[20];		/* user name */
	int32 time;		/* When was the last login ? */
	int number;		/* Number of times logged in */
};



#define NULLPU (struct pu *)NULL
static struct pu *Pu = NULLPU;

static struct pu *pu_lookup (char *name);

#ifdef POOLED
static struct mempool Pu_pool = {NULLPOOLBLK, NULLPOOLBLK, 0, sizeof (struct pu), 50};
#endif



/* Look up an entry in the users-list*/
static struct pu *
pu_lookup (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 (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 ???*/
		(void) rename (UDefbak, UDefaults);
		return;
	}
	if ((tfile = fopen (UDefbak, "r")) == NULLFILE) {
		/* What on earth happened ???? */
		(void) fclose (Ufile);
		(void) rename (UDefbak, UDefaults);
		return;
	}
	while (fgets (buf, sizeof (buf), tfile) != NULLCHAR) {
		if ((cp = strchr (buf, ' ')) == NULLCHAR)
			continue;
		*cp = '\0';
		if (!stricmp (m->name, buf)) {
			/*found this user*/
			(void) time (&t);
			if (homeonly == 1) {
				if ((cp = strchr (++cp, ' ')) == NULLCHAR)
					continue;
				cp++;
				if (*cp == '@') {
					if ((cp = strchr (++cp, ' ')) == NULLCHAR)
						continue;
					cp++;
				}
				cp = strdup (cp);
				sprintf (buf, "%s %s %s", m->name, m->home, cp);
				free (cp);
			} else if (homeonly == 2) {
				*cp = ' ';
				if ((cp = strchr (++cp, ' ')) == NULLCHAR)
					continue;
				*cp++ = 0;
				if (*cp == '(') {
					if ((cp = strchr (++cp, ')')) == NULLCHAR)
						continue;
					cp += 2;
				}
				cp = strdup (cp);
				cp2 = strdup (buf);
				sprintf (buf, "%s (%s) %s", cp2, m->realname, cp);
				free (cp);
				free (cp2);
			} else {
				char *tmpcp = 0, *tmpcp2, *tmpcp3 = 0;

				if (m->home) {
					tmpcp3 = tmpcp = strdup (m->home);
					tmpcp2 = strchr (tmpcp, '@');
					if (tmpcp2)
						tmpcp3 = ++tmpcp2;
					tmpcp2 = strchr (tmpcp3, '.');
					if (tmpcp2)
						*tmpcp2 = 0;
				}
				sprintf (buf, "%s @%s %s %lu M%d %s%s%s%s%s%s%s%s%s C%c\n",
					 m->name,
					 (m->home && Hostname && strnicmp (m->home, Hostname, strlen (m->home)))
					 ? tmpcp3 : "",
					 (m->realname) ? m->realname : "()",
					 t, m->morerows,
					 (m->sid & MBX_AREA) ? "A" : "",
					 (m->sid & MBX_DELEGATE) ? "D" : "",
					 (m->sid & MBX_GFX) ? "G" : "",
					 (m->sid & MBX_HOLD) ? "H" : "",
					 (m->sid & MBX_TNOS) ? "L" : "",
					 (m->sid & MBX_NRID) ? "N" : "",
					 (m->sid & MBX_RDMOTD) ? "R" : "",
					 (m->sid & MBX_STATS) ? "S" : "",
					 (m->sid & MBX_EXPERT) ? "X" : "",
					 (m->family == AF_AX25) ? 'A' : \
					 ((m->family == AF_NETROM) ? 'N' : 'T'));
				if (m->home)
					free (tmpcp);
			}
		} else
			*cp = ' ';	/* restore the space !*/
		fputs (buf, Ufile);
	}
	(void) fclose (tfile);
	(void) fclose (Ufile);
	return;
}
#endif /* USERLOG */



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

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



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

	if (initial && m->privs & IS_BBS) {
		m->home = strdup (m->name);
		return;
	}
#ifdef MBFWD
	if (mbxRCall)
		strncpy (here, mbxRCall, AXBUF);
	else
#endif
		(void) pax25 (here, Mycall);
	if (initial) {
		(void) DisplayFile (AskhomeFile, m->user);
		if (Mbhome != NULLCHAR)
			tputs (Mbhome);
		strncpy (name, here, 80);
		if ((cp = strchr (name, '.')) != NULLCHAR)
			*cp = '\0';
		m->home = strdup (name);
	} else
		tprintf (changehome_str, (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);
		(void) strlwr (cp);
		m->home = strdup (cp);
		if ((cp = strchr (m->home, '.')) != NULLCHAR)
			*cp = '\0';
		m->change |= CHG_WP;
	}
	tprintf (homeset_str, (m->home) ? m->home : here);
	updatedefaults (m, 0);
#endif
}



#if (defined(ASKHOME) || defined(WPAGES))
int
dobbshome (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 (homesyntax);
			return (0);
		}
		orgname = strdup (m->name);
		orghome = m->home;
		strncpy (m->name, argv[1], 20);
		m->home = argv[2];
		updatedefaults (m, 1);
		strncpy (m->name, orgname, 20);
		m->home = orghome;
		free (orgname);
	} else
		askhome (m, 0);
	return 0;
}
#endif /* ASKHOME || WPAGES */



#ifdef USERLOG
void 
askrealname (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);
			return;
		}
		if (callnm) {
			m->realname = strdup (&callnm[1]);
			free (callnm);
			m->update = 1;
			tprintf (realname_as, callnm);
		} else
			m->realname = strdup ("()");

		tprintf (realname_str, (callnm) ? "change" : "set");
		return;
	}
	tprintf (realname_change, (!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);
		m->change |= CHG_WP;
	}
	tprintf (realname_set, (m->realname && strcmp (m->realname, "()")) ? m->realname : "unknown");
	m->update = 1;
}



int
dorealname (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 (realname_syntax);
			return (0);
		}
		orgname = strdup (m->name);
		orgreal = m->realname;
		strncpy (m->name, argv[1], 20);
		m->realname = argv[2];
		updatedefaults (m, 2);
		strncpy (m->name, orgname, 20);
		m->realname = orgreal;
		free (orgname);
	} else
		askrealname (m, 0);
	return 0;
}
#endif



static int DiffUsers = 0;



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

	(void) 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
		strncpy (pu->name, m->name, 20);
		pu->next = Pu;
		Pu = pu;
		DiffUsers++;	/* A new guy */
	}
	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 ("-");

			(void) time (&t);
			sprintf (buf, "%s @%s () %lu M%d %s%s%s%s%s C%c\n",
				 m->name,
				 (m->home && Hostname && strnicmp (m->home, Hostname, strlen (m->home)))
				 ? m->home : "", t, m->morerows,
				 (m->privs & IS_BBS) ? "" : (Usearea) ? "A" : "",
				 (Usehold) ? "H" : "",
				 (Usenrid) ? "N" : "",
				 (Usescan) ? "S" : "",
				 (m->sid & MBX_EXPERT) ? "X" : "",
				 (m->family == AF_AX25) ? 'A' : \
				 ((m->family == AF_NETROM) ? 'N' : 'T'));
			fputs (buf, Ufile);
			(void) fclose (Ufile);
			m->realname = NULLCHAR;
			if (!(m->privs & IS_BBS) && Usearea)
				m->sid |= MBX_AREA;
			if (Usenrid)
				m->sid |= MBX_NRID;
			if (Usescan)
				m->sid |= MBX_STATS;
			return laston;
		}
		/* Find user in the default file */
		while (!found) {
			if (fgets (buf, sizeof (buf), Ufile) == NULLCHAR)
				break;
			if ((cp = strchr (buf, ' ')) == NULLCHAR)
				continue;
			*cp++ = '\0';
			if (!stricmp (m->name, buf)) {
				/* found user, now scan the options used */
				found = 1;
				(void) 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 'H':
							m->sid |= MBX_HOLD;
							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;
						default:
							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 ("-");
			(void) time (&t);
			sprintf (buf, "%s @%s () %lu M%d %s%s%s%s%s C%c\n",
				 m->name,
				 (m->home && Hostname && strnicmp (m->home, Hostname, strlen (m->home)))
				 ? m->home : "", t, m->morerows,
				 (m->privs & IS_BBS) ? "" : (Usearea) ? "A" : "",
				 (Usehold) ? "H" : "",
				 (Usenrid) ? "N" : "",
				 (Usescan) ? "S" : "",
				 (m->sid & MBX_EXPERT) ? "X" : "",
				 (m->family == AF_AX25) ? 'A' : \
				 ((m->family == AF_NETROM) ? 'N' : 'T'));
			if (Ufile != NULLFILE)	{	/*lint !e644 */
				fputs (buf, Ufile);
				(void) fclose (Ufile);
			}
			m->realname = NULLCHAR;
			if (!(m->privs & IS_BBS) && Usearea)
				m->sid |= MBX_AREA;
			if (Usenrid)
				m->sid |= MBX_NRID;
			if (Usescan)
				m->sid |= MBX_STATS;
			return laston;
		}
	}			/* if not bbs */
#endif /* USERLOG */
	return (time_t) - 1;
}



/*List all past users of the mailbox */
int
dombpast (int argc, char *argv[], void *p OPTIONAL)
{
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_header);
	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;
}



static 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 (queued_str, i);
}



int
douptime (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
	tprintf ("Up: %s\n", tformat (secclock ()));
	return 0;
}



int
dombmailstats (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
#ifndef UNIX
	tputs ("Mem: ");
	mbmemory ();
#endif

	tprintf (ms_logins, Totallogins, BBSlogins);
#ifdef CONVERS
	tprintf (" - CONF: %d", Conflogins);
#endif
#ifdef TUTOR
	tprintf (" - TUTOR: %d - INFO: %d - NEWS: %d", Tutorlogins[0], Tutorlogins[1], Tutorlogins[2]);
#endif
	tputs (")\n");
	(void) douptime (0, (char **) 0, (void *) 0);
	tprintf (users_count, 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
#ifdef EXPIRY
	if (ExpireActive)
		tprintf ("Expiration of public area%s %s%s%sin progress\n",
			ExpireArea ? "" : "s", ExpireArea ? "\'" : "",
			ExpireArea ? ExpireArea : "", ExpireArea ? "\' " : "");
	else if (ExpireLast)
		tprintf ("Last Expiration: %s", ptime (&ExpireLast));
#endif
	smtpqueuecheck ();
#ifdef MAILFOR
	(void) domftimer (1, (char **) 0, (void *) 0);
#endif
	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 (int argc OPTIONAL, char *argv[], void *p)
{
FILE *Ufile;
char buf[MBXLINE];
int found = 0;
time_t t;
struct tm *lt;
char *cp, *home = 0, *cp3 = 0;
char const *cp2;
char *cp4;
struct mbx *m;
char *realname;
uint32 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)
			continue;
		*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 ((cp4 = strchr (cp, ')')) != NULLCHAR) {
					cp4++;
					*cp4++ = '\0';
					realname = cp;
					cp = cp4;
				}
			}
			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;
					default:
						break;
				}
			}
			tprintf (info_on, argv[1], (realname) ? realname : "");
			if (m == NULLMBX || m->stype == 'L')
				tprintf ("%s last connected via %s on %s", argv[1], cp2, asctime (lt));
#ifdef ASKHOME
			tprintf ("%s's HOME BBS", argv[1]);
			if (*home == '-')
				tputs (" is unknown!\n");
			else {
				strncpy (buf, home, MBXLINE);
				if ((cp = strchr (buf, '.')) != 0)
					*cp = 0;
				(void) strupr (buf);
				tprintf (": '%s'\n", buf);
			}
#endif
			found = 1;
		}
	}
	(void) fclose (Ufile);
	cp2 = wpage_exp (strdup (argv[1]), 1, 1);
	if (strchr (cp2, '.')) {
		cp4 = strdup (cp2);
		(void) strupr (cp4);
		tprintf ("%s's WHITE PAGES: '%s'\n", argv[1], cp4);
		free (cp4);
	} else if (home && Hostname && home == Hostname) {
		tprintf ("%s's WHITE PAGES: '", argv[1]);
		sprintf (buf, "%s@", argv[1]);
		(void) pax25 (&buf[strlen (buf)], Mycall);
		if ((cp = strpbrk (buf, DIGI_IDS)) != NULLCHAR)
			*cp = '\0';	/* remove SSID */
		(void) strupr (buf);
		tputs (buf);
#ifdef MBFWD
		sprintf (buf, "%s%s'\n", (Mbhaddress != NULLCHAR) ? "." : "",
			 (Mbhaddress != NULLCHAR) ? Mbhaddress : "");
#else
		sprintf (buf, "'\n");
#endif
		(void) 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 (ipaddress_str, argv[1], inet_ntoa (addr));
		DTranslate = trans;	/* Restore original state */
	}
	if (!found)
		tprintf (nolocal_str, argv[1]);
	return 0;
}
#endif



static const char *MBstates[] =
{
	"Logging in", "Idle", "Sending message", "Sending message",
	"Reverse Forwarding", "Attempting Forward", "Forwarding",
	"Using gateway", "Reading message", "Uploading file",
	"Downloading file", "Convers mode", "Chatting with sysop",
	"Listing files", "Attempting Sysop mode", "Sysop mode",
	"Xmodem Receiving", "Xmodem Sending", "Being Tutored",
	"Node (idle)", "Unknown state"
};



const char *
displayMBstatus (int state, int issysop)
{
	/* Only show callers with sysop-privs who is sysop-mode!
         * This prevents users from easily learning who's
         * got SYSOP privs
         */
	if (!issysop && (state == MBX_SYSOPTRY || state == MBX_SYSOP))
		state = MBX_CMD;
	if (state < 0 || state > MBX_MAXSTATE)
		state = MBX_MAXSTATE + 1;
	return MBstates[state];
}



int
dombusers (int argc, char *argv[], void *p)
{
register struct mbx *m, *caller;
int i, len, nerf;
char *cp, *cp1, fsocket[MAXSOCKSIZE];
char upl[60], down[60];
struct usock *up, *up1, *up2;
int s;
time_t elapsedtime;
#ifdef NETROM
struct nrroute_tab *np;
char temp[AXBUF], *cp2, *cp3;
#endif

	caller = (struct mbx *) p;

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

	if (caller->privs & ALL_AREAS)
		return 0;	/* can't do this in all areas */

	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_oor);
		else
			updateFwd (argv[2], caller->area, caller->mbox[s].bid, caller->mbox[s].size);
		return 0;
	}
#ifdef MBFWD
	if (caller->stype == 'K' && (caller->privs & SYSOP_CMD)) {
		if (argc > 1)
			return dombkickone (argc, argv, p);
		else
			return dombkick (argc, argv, p);
	}
#endif

#ifdef EXPIRY
	if (caller->stype == 'X' && (caller->privs & SYSOP_CMD)) {
		Expiretick (NULL);
		return 0;
	}
#endif
#ifdef MAILCMDS
	if ((caller->stype == 'W' || caller->stype == 'M' || caller->stype == 'C') && (caller->privs & SYSOP_CMD))
		return dombmovemail (argc, argv, p);
#endif
	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 (mr_syntax);
			return 0;
		}
		if ((file = permtest (caller->path, caller->privs, argv[2], RETR_CMD, NULLCHAR, 0)) == NULLCHAR)
			return 0;

		if ((fp = fopen (file, READ_TEXT)) != NULLFILE) {
			from = host_or_wpage_exp (strdup ((argc == 5) ? argv[4] : caller->name), 1, 0, &nerf);
			msgtype = (char) toupper (argv[1][0]);
			if (msgtype != 'B')
				to = host_or_wpage_exp (strdup (argv[3]), 1, 0, &nerf);
			tputs ("Subject:\n");
			if (mbxrecvline (caller) != -1) {
				(void) rdaemon (fp, NULLCHAR, from, to, caller->line, msgtype, 0);
				tputs ("Message queued\n");
				smtptick (NULL);	/* wake up SMTP to send mail */
			}
			(void) 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) {
			for (i = 0; i < (int) strlen (argv[1]); i++) {
				if (!isdigit (argv[1][i]))
					return dombuserinfo (argc, argv, p);
			}
			return dombpast (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;
			if (getpeername (m->user, fsocket, &len) != -1)
				cp = strdup (psocket (fsocket));
			else
				cp = strdup ("unknown");

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

#if 0
			switch (m->family) {	/* UPLINK */
#else
			up2 = itop (m->user);
			if (up2 == NULLUSOCK)
				continue;
			switch (up2->type) {	/* UPLINK */
#endif
#ifdef AX25
#if 0
				case AF_AX25:
#else
				case TYPE_AX25I:
				case TYPE_AX25UI:
#endif
					sprintf (upl, Uplink, cp);
					break;
#endif
#ifdef NETROM
#if 0
				case AF_NETROM:
#else
				case TYPE_NETROML3:
				case TYPE_NETROML4:
#endif
					if ((cp1 = strchr (cp, ' ')) == NULLCHAR)
						continue;
					*cp1 = '\0';
					cp1 += 3;
					(void) setcall (temp, cp1);
					np = find_nrroute (temp);
					if (np != NULLNRRTAB)
						cp2 = strdup (np->alias);
					else
						cp2 = strdup (" ");
					if ((cp3 = strchr (cp2, ' ')) != NULLCHAR)
						*cp3 = '\0';
					/*
					if(*cp2 == '#' || *cp2 == '\0')
						sprintf(upl,incircuit,cp,"","",cp1);
					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, m->name, cp2, ":", cp1);
					else
						sprintf (upl, incircuit, cp, cp2, ":", cp1);
					free (cp2);
					break;
#endif
#if 0
				case AF_INET:
#else
				case TYPE_TCP:
				case TYPE_UDP:
#endif
					if ((cp1 = strchr (cp, ':')) != NULLCHAR)
						*cp1 = '\0';
					sprintf (upl, Telnet, m->name, cp);
					/* this fixes a problem where 127.0.0.1 is NOT
					   recognized as Local, but Telnet */
					if (strnicmp (cp, "127.0.0.1", 9))
						break;
					/*lint -save -e616 * else, fall through and fix the problem */
#if 0
				case AF_LOCAL:
#else
				case TYPE_LOCAL_STREAM:
				case TYPE_LOCAL_DGRAM:
#endif
					sprintf (upl, Local, m->name, Hostname);
					break;
				default:
#if 0
					strcpy (upl, "Connect");
					break;
#else
					/* if it gets here, it is NOT a valid user!
					 * We will NOT try to free the garbage, though
					 */
					Mbox[i] = NULLMBX;
					continue;
#endif
			/*lint -restore */
			}
			free (cp);
			if (m->state == MBX_TRYING)	/* forwarding session */
				sprintf (upl, fwd_daemon, m->name);
			tprintf ("%-38.38s", upl);

			/* Show their elapsed time on system - KO4KS */
			elapsedtime = 0;
			if (m->state != MBX_LOGIN) {
				(void) time ((time_t *) & elapsedtime);
				elapsedtime -= m->logontime;
			}
			tprintf (" %10.10s", (m->state == MBX_TRYING) ? "" : tformat ((long) 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) {
							if (getpeername (s, fsocket, &len) != -1)
								cp = strdup (psocket (fsocket));
							else
								cp = strdup ("unknown");
							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)
										continue;
									*cp1 = '\0';
									cp1 += 3;	/*get rid of ' @ '*/
									(void) setcall (temp, cp1);	/*get node call*/
									np = find_nrroute (temp);	/*find alias, if any*/
									if (np == NULLNRRTAB)
										cp2 = strdup ("???");
									else {
										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", down);
							break;
						}
					}
					if (!down[0])	/* couldn't find out where the gateway was TO! */
						tputs ("<--> ??INVALID GATEWAY INFO??");
					tputs ("\n");
					break;
				default:
					tprintf ("%s\n", displayMBstatus (m->state, (caller->privs & SYSOP_CMD)));
			}
		}
	}
	tputc ('\n');
	return 0;
}



#if defined(TIPMAIL) && defined(ALLSERV)
static int
dotimeout (int argc, char *argv[], void *p OPTIONAL)
{
	return setuns (&Tiptimeout, tiptimeout_str, argc, argv);
}
#endif



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

int
doinetcallserver (int argc, char *argv[], void *p OPTIONAL)
{
	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 (callusage);
		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 (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))
			stype = (char) tolower (stype);
		sprintf (cp, "%c ", stype);
		cp += 2;
	}
	for (i = 1; i < argc; i++) {
		sprintf (cp, "%s ", argv[i]);
		cp += strlen (cp);
	}
	return line;
}



static int
dombcmd (int argc, char *argv[], void *p OPTIONAL)
{
	if (argc < 3)
		assoc_list (Mbcustom, 10, (argc == 1) ? NULLCHAR : argv[1]);
	else
		(void) assoc_addstr (&Mbcustom, argv[1], argv[2], 1);

	return 0;
}



#ifdef MAILCMDS
static int
dombbonly (int argc, char *argv[], void *p)
{
	return (dosetflag (argc, argv, p, BBS_ONLY, 1));
}
#endif



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



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



int
isaPBBShost (char *str)
{
int k;
char *cp;

	/* this routine returns 1 if it looks like an AX25 PBBS name,
	   otherwise it returns 0 which means it is probably an IP hostname */
	for (k = 0; k < numcontinents; k++) {
		if (((cp = strstr (str, continents[k])) != NULLCHAR) && (*(cp - 1) == '.') && (*(cp - 5) == '.') && !cp[4])
			return 1;
	}
	return 0;
}


#ifdef ALLSERV
extern int CHAToneshotBypass;



int
dombchat (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
{
int i;
struct mbx *m = NULLMBX;

	/* check the mailbox users */
	for (i = 0; i < NUMMBX; i++) {
		if ((m = Mbox[i]) != NULLMBX) {
			if (!stricmp (m->name, argv[1]))
				break;
		}
	}
	if (m != NULLMBX && i != NUMMBX) {
		MAttended = TRUE;	/* force to attended */
		CHAToneshotBypass = 1;
		if (m->state == MBX_CMD) {
			usputc (m->user, '\007');
			usputs (m->user, sysopchat);
			usflush (m->user);
		}
		m->privs |= SYS_CHAT;
	} else
		tprintf (usernoton, argv[1]);
	return 0;
}
#endif


void
setMaintenance ()
{
int i;

	MBXMaint += 1;
	if (MBXMaintMode) {
		switch (MBXMaintClear) {
			case 1:/* Clear out the BBS - bump users */
				for (i = 0; i < NUMMBX; i++) {
					if (Mbox[i] != NULLMBX) {
						if (MBXMaintStr) {
							usprintf (Mbox[i]->user, "\n%s\n", MBXMaintStr);
							usflush (Mbox[i]->user);
							kpause (5000);
						}
						close_s (Mbox[i]->user);
					}
				}
				break;
			default:
				while (BbsUsers)
					kpause (1000);
				break;
		}
	}
}



void
clearMaintenance ()
{
	MBXMaint -= 1;
}



#ifdef EXPIRY
static int
dombprune (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
	if (newproc ("Pruning", 2048, mbpruning, 0, NULL, NULL, 0) == NULLPROC)
		log (-1, "Couldn't start Pruning process");
	return 0;
}


static int
dombpruneage (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
	return setint (&PruneAge, pruneage_str, argc, argv);
}


static void
mbpruning (int a OPTIONAL, void *v1 OPTIONAL, void *v2 OPTIONAL)
{
char buf[MBXLINE];
struct ffblk ff;
char *tmp;

	log (-1, "BBS Pruning process started");
	setMaintenance ();
	sprintf (buf, "%s/*.txt", Mailspool);
	if (findfirst (buf, &ff, 0) == 0) {
		do {
			kwait (NULL);	/* Let others run */
			if ((tmp = strchr (ff.ff_name, '.')) != NULLCHAR)
				*tmp = '\0';
			if (!issysarea (ff.ff_name))
				expire (ff.ff_name, -1);
		} while (findnext (&ff) == 0);
	}
	clearMaintenance ();
	log (-1, "BBS Pruning process completed");
}
#endif

#endif /* MAILBOX */
