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

#ifdef DELEGATE
#include "delegate.h"
extern int Mbdelegate;
#endif
extern int MAttended;
extern char *MAttendedAt;
extern char Mbpasswd[];
extern int BbsUsers;
extern char DFAR Only[];
extern char DFAR CurUsers[];
extern char DFAR Howtoend[];
extern char DFAR MsgAborted[];
extern char *skipwhite __ARGS((char *));
extern char DFAR *findhome __ARGS((char *));
extern FILE *fopennew __ARGS((char *fname, char *mode));
extern int searchfile __ARGS((char *searchfor,char *fname,char * buf,int entrysize,int *passes,int searchlen));
extern int doipheard __ARGS((int argc,char *argv[],void *p));
extern void suspendTipMail __ARGS((struct mbx *m));
extern void netPrompt __ARGS((void));
extern void tutorserv __ARGS((char *call,struct mbx *m,int mode, int color, int ip));
extern void forwardingSummary __ARGS((void));
extern int dombusers __ARGS((int argc,char *argv[],void *p));
extern struct list *expandalias __ARGS((struct list **head,char *user,char *orig));
extern char *Mbhaddress;


#ifdef MAILBOX
void bbsbump __ARGS((char *user,int zap));
void msgiddelete __ARGS((register char *string));
void wpageUpdate __ARGS((FILE *fp,char *string, char *entry, char *oldtime,int bbs, int updateit));
int groupcommand __ARGS((char *action, char *group, char *user,int local,FILE **out, FILE *in));
int isgroup __ARGS((char *group));
void informGroup __ARGS((char *action, char *group, char *user, char *buf,FILE *old, FILE *new, FILE *in));
static int quickstat __ARGS((register struct mbx *m,char *area));
int dombgetall __ARGS((struct mbx *m));
static int expertstat __ARGS((struct mbx *m));
static int uuencode __ARGS((FILE *infile,int s,char *infilename));
int dodownload __ARGS((int argc,char *argv[],void *p));
int dombfdesc __ARGS((int argc,char *argv[],void *p));
int dombupload __ARGS((int argc,char *argv[],void *p));
int dobump __ARGS((int argc,char *argv[],void *p));
int msgidcheck __ARGS((char *string));
int dombwpages __ARGS((int argc,char *argv[],void *p));
int dombnews __ARGS((int argc,char *argv[],void *p));
int dombtutor __ARGS((int argc,char *argv[],void *p));
int dombgroup __ARGS((int argc,char *argv[],void *p));
int dombquote __ARGS((int argc,char *argv[],void *p));
int dombtime __ARGS((int argc,char *argv[],void *p));
void quickscan __ARGS((struct mbx *m, int olduser));
int dombset __ARGS((int argc,char *argv[],void *p));
int dombrmail __ARGS((int argc,char *argv[],void *p));
int dombroute __ARGS((int argc,char *argv[],void *p));
int dombexpand __ARGS((int argc,char *argv[],void *p));
int dombexpert __ARGS((int argc,char *argv[],void *p));
int dombslip __ARGS((int argc,char *argv[],void *p));
int douser __ARGS((int argc,char *argv[],void *p));
int doreply __ARGS((int argc,char *argv[],void *p));
int dombget __ARGS((int argc,char *argv[],void *p));
int dombmovemail __ARGS((int argc,char *argv[],void *p));
int dombhelp __ARGS((int argc,char *argv[],void *p));
int dombconvers __ARGS((int argc,char *argv[],void *p));
int dombtelnet __ARGS((int argc,char *argv[],void *p));
int dombfinger __ARGS((int argc,char *argv[],void *p));
int dosysop __ARGS((int argc,char *argv[],void *p));
int dostars __ARGS((int argc,char *argv[],void *p));
int dochat __ARGS((int argc,char *argv[],void *p));
int dombjheard __ARGS((int argc,char *argv[],void *p));
int dombiproute __ARGS((int argc,char *argv[],void *p));
#ifdef LZW
void togglelzw __ARGS((int soc, int mode));
#endif
#ifdef WPAGES
void wpageAdd __ARGS((char *entry, int bbs, int updateit));
char *wpageCheck __ARGS((char *string,int bbs, int updateit));
#endif
char *wpage_exp __ARGS((char *to,int hier,int exphome));
int dozap __ARGS((int argc,char *argv[],void *p));
int dowhat __ARGS((int argc,char *argv[],void *p));
extern int gw_connect __ARGS((struct mbx *m,int s,struct sockaddr *fsocket,int len));
extern int dosend __ARGS((int argc,char *argv[],void *p));
extern char *permtest __ARGS((char *path,long privs,char *name,int mode,char *root,int dir));
extern char *cmd_line __ARGS((int argc,char *argv[],char stype));
extern char *nntp_name_expansion __ARGS((char *name));
extern void statusCtl __ARGS((char *who, char *extension,struct let *info,int entry, int readit));
extern void updateCtl __ARGS((char *who,struct let *info));

static char DFAR Alsomenu[] = "\nFor further help, type 'help cmdname', where 'cmdname' is one of the above.\n\
For a brief listing of all commands, type '?'\n\n\
Others: AF, AL, AN, AS, DU, KM, KS, KU, L$, L>, L<, LA, LB, LL, LM, LS, LT,\n\
        ML, MS, RH, RM, SB, SC, SF, SP, SR, ST, VM, XA, XC, XM, XN, XS\n";
static char DFAR Sysopmenu[] =  "Sysops: IF, MA, MC, MF, MH, MK, MM, MP, MR, MT, MW, MX, WA, WR, @\n";
static char DFAR index_dat[] = "index.dat";

short SecureTelnet = 1;


#ifdef MSDOS
#define WPAGEENTRYSIZE    30
#define WPAGEBBSENTRYSIZE 49
#else
#define WPAGEENTRYSIZE    29
#define WPAGEBBSENTRYSIZE 48
#endif

int
dowhat(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
FILE *fp, *in = NULLFILE;
char *file;
char *cp, *nm, *ptr;
char buf[50], buf2[80];
int yep;
#ifdef DOS_GETFILEATTR
unsigned attr;
#endif
			
	m = (struct mbx *)p;
#ifdef WPAGES
	if (m->stype == 'P')
		return (dombwpages (argc, argv, p));
#endif
	if(((m->stype == 'R') || (m->stype == 'A')) && !(m->privs & SYSOP_CMD)){
		tputs ("Sorry, command is only available to the SYSOP!\n");
		return 0;
	}
	if (m->stype == 'R')	{
		if(argc < 3)
			tputs("Syntax: WR user \"message\"\n");
		else	{
			dowrite (0, argv, 0);
		}
		return 0;
	}
	if (m->stype == 'A')	{
		if(argc < 2)
			tputs("Syntax: WA \"message\"\n");
		else	{
			dowriteall (0, argv, 0);
		}
		return 0;
	}
	if ((file = permtest (m->path, m->privs, (argc > 1) ? argv[1] : ".", RETR_CMD, NULLCHAR, (argc < 2))) != NULLCHAR)		{
		m->state = MBX_WHAT;

		/* check for index.dat file in that directory */
		cp = strdup (file);
#ifdef DOS_GETFILEATTR
		_dos_getfileattr (cp, &attr);
		if(!(attr & FA_DIREC))	{
			ptr = strrchr (cp, '/');
			*ptr = 0;
		}
#endif
		nm = pathname (cp,index_dat);
		free (cp);
		in = fopen (nm, READ_TEXT);
		free (nm);
		if (in != NULLFILE)	{
			tputc ('\n');
			while (fgets (buf2, 80, in) != NULLCHAR) {
				if (*buf2 == ' ' || *buf2 == '\t' || *buf2 == '\n')
					tputs (buf2);
				else
					break;
			}
		}

		if((fp = dir(file, (in == NULLFILE) ? 1 : 2)) == NULLFILE)
			tprintf("Can't read directory: \"%s\": %s\n",file,sys_errlist[errno]);
		else	{
#ifdef MBXTDISC
        		stop_timer(&m->tdisc);
#endif
			if (in == NULLFILE)
				sendfile(fp,m->user,ASCII_TYPE,0);
			else	{
				while (fgets(buf,50,fp)!= NULLCHAR) {
					yep = 0;
					if (*buf == ' ')
						continue;
					rewind (in);
					while (fgets (buf2, 80, in) != NULLCHAR)	{
						if (!strnicmp (buf, buf2, 12))	{
							yep = 1;
							rip (buf2);
							break;
						}
					}
					if (yep)
						rip (buf);
					tputs (buf);
					if (yep)	{
						ptr = &buf2[13];
						ptr = skipwhite (ptr);
						tprintf ("%-37.37s\n", ptr);
						while (fgets (buf2, 80, in) != NULLCHAR)	{
							if (*buf2 != ' ' && *buf2 != '\t')
								break;
							rip (buf2);
							ptr = skipwhite (buf2);
							tprintf ("%39s| %-37.37s\n", "", ptr);
						}
					}
				}
				fclose (in);
			}
			fclose(fp);
		}
		free(file);
	} else	{
		tputs(Noperm);
        	mail_error("%s: directory denied: %s\n",m->name,cmd_line(argc,argv,m->stype));
	}
	return 0;
}

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

	m = (struct mbx *)p;
	if ((file = permtest (m->path, m->privs, argv[1], DELE_CMD, NULLCHAR, 0)) != NULLCHAR)	{
		if(unlink(file))
			tprintf("Zap failed: %s\n",sys_errlist[errno]);
		else
			log(m->user,"MBOX Zap: %s",file);
		free(file);
	} else	{
		tputs(Noperm);
        	mail_error("%s: zap denied: %s\n",m->name,cmd_line(argc,argv,m->stype));
	}
	return 0;
}


extern void dumproute __ARGS((struct route *rp,char *p));
extern char RouteHeader[];

/* Show non-private routes only */
int
dombiproute(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    register int i,bits;
	register struct route *rp;
    char buf[85];

    tputs(RouteHeader);
	for(bits=31;bits>=0;bits--){
		for(i=0;i<HASHMOD;i++){
			for(rp = Routes[bits][i];rp != NULLROUTE;rp = rp->next){
                if(!(rp->flags & RTPRIVATE)) {
                    dumproute(rp,buf);
                    if(tprintf("%s\n",&buf[4]) == EOF)
                        return 0;
                }
			}
		}
	}
    if(R_default.iface != NULLIF && !(R_default.flags & RTPRIVATE)) {
        dumproute(&R_default,buf);
        if(tprintf("%s\n",&buf[4]) == EOF)
            return 0;
    }
    return 0;
}


#ifdef AX25
int
dombjheard(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    struct iface *ifp;
    struct mbx *m = (struct mbx *)p;

	if(argc > 1){
        if( ((ifp = if_lookup(argv[1])) == NULLIF) || (ifp->type != CL_AX25) ||
           ((ifp->flags & HIDE_PORT) && !(m->privs & MBX_SYSOP)) ) {
            tprintf(Badinterface,argv[1]);
            return 0;
		}
		axheard(ifp);
		return 0;
	}
	for(ifp = Ifaces;ifp != NULLIF;ifp = ifp->next){
        if((ifp->flags & LOG_AXHEARD)  && ( !(ifp->flags & HIDE_PORT) || m->privs&MBX_SYSOP) )
            if(axheard(ifp) == EOF)
                break;
	}
    return 0;
}
#endif


char SysopBusy[] = "The system is unattended. Try again later.\n";

int
dochat(argc,argv,p)
int argc;
char *argv[];
void *p;
{
char buf[8], *newargv[3], doat[50];
struct mbx *m;

    m = (struct mbx *)p;

	if(MAttended){
		m->state = MBX_CHAT;
		newargv[0] = "C";
		newargv[1] = Hostname;
		if(MAttendedAt != NULLCHAR)	{
			strcpy (doat, MAttendedAt);
			newargv[1] = doat;
			rip (newargv[1]);
		}
		sprintf(buf,"%d",IPPORT_TTYLINK);
		newargv[2] = buf;
		SecureTelnet = 0;
		dombtelnet(3,newargv,p);
	}
	else
	        tputs(SysopBusy);

	/* It returns only after a disconnect or refusal */
	return 0;
}

/*Password protection added - 920118, WG7J */
int
dosysop(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
int c;
int len,pwdc[5],i,valid=0;
char *cp;
extern struct cmds DFAR Cmds[];

	m = (struct mbx *) p;
	log(m->user,"MBOX: %s attempting SYSOP",m->name);

	/*If you want anyone with the password to go sysop-mode
	 *comment out the next 4 line ! -WG7J
	 */
	if(!(m->privs & SYSOP_CMD))	{
		tputs(Noperm);
        mail_error("%s: SYSOP denied!\n",m->name);
		return 0;
	}

	/*only if set,
	 *check for the password before letting users proceed
	 */
	m->state = MBX_SYSOPTRY;
	if((len = strlen(Mbpasswd)) != 0) {
	        for (i=0;i<5;i++)
			tprintf("%d ",(pwdc[i]=RANDOM(len)) + 1); /*print the random chars*/
		tputc('\n');
		while(1) 	{
			c = mbxrecvline(m);
			if(c == EOF || c == -2)
				return 0;
			if(*m->line == '\0')
				break;
			if (*m->line == '?')	{
				tprintf ("Validation %somplete!\n", valid ? "C" : "Inc");
				continue;
			}
			cp = m->line;
			for(i=0;i<5;i++)
				if(tolower(*cp++) != tolower(Mbpasswd[pwdc[i]]))
					break;
			if (i == 5)
				valid = 1;
		}
		if(!valid)
			return 0;
	}

	log(m->user,"MBOX: %s is now SYSOP",m->name);
	m->state = MBX_SYSOP;
	tputs("\n\007Type 'exit' to return\n\nBe VERY careful!!\n");

	for(;;)		{
		netPrompt ();
		usflush(Curproc->output);
		if(mbxrecvline(m) < 0)
			break;
		log(m->user,"MBOX sysop: %s",m->line);
#ifdef MBXTDISC
		stop_timer(&m->tdisc);
#endif
		valid = cmdparse(Cmds,m->line,NULL);
#ifdef MBXTDISC
		start_timer(&m->tdisc);
#endif
		if (valid == -2)
			break;
	}
	return 0;
}

/* Handle the "*** Done" command when reverse forwarding ends or the
 * "*** LINKED to" command.
 */
int
dostars(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
int anony = 1;
int founddigit = 0;
int oldprivs;
char *cp;

	m = (struct mbx *)p;

    /* The "*** LINKED to" command is only allowed to stations with
	 * SYSOP privileges to prevent others from obtaining the same.
	 */
#ifdef notdef
	if((m->privs & SYSOP_CMD) && argc == 4 && !strcmp(argv[1],"linked")) {
#endif
	/* Allow 'linked to' from anyone, but reset SYSOP priviledges
	 * when the sysop-password is not set !
	 * Also try to set the new call !
	 * Inspired by Kurt, wb5bbw
	 * Check for the strange TEXNET linked message !
	 * 920220 - WG7J
	 */
    if((argc >= 4) && !strcmp(argv[1],"linked") && !strcmp(argv[2],"to") ) {
#ifdef GWTRACE
		log(m->user,"MBOX LINKED: %s changed to %s",m->name,argv[3]);
#endif
        strcpy(m->name,argv[3]);
		oldprivs = m->privs; /*Save this !*/
		/* Try to find the privileges of this user from the userfile */
		if((m->privs = userlogin(m->name,NULLCHAR,&m->path,MBXLINE,
					 &anony)) == -1)
		     if((m->privs = userlogin("bbs",NULLCHAR,&m->path,
				      MBXLINE,&anony)) == -1)
			  if((m->privs = userlogin("anonymous",NULLCHAR,
					   &m->path,MBXLINE,&anony)) == -1){
						m->privs = 0;
						free(m->path);
						m->path = NULLCHAR;
			  }
		if(m->privs & EXCLUDED_CMD)
			return domboxbye(0,NULLCHARP,p);
#ifdef AX25
        /* Set the call */
		for(cp=m->name;*cp != '\0';cp++)
			if(isdigit((int)*cp))
				break;
		if(*cp != '\0')
			founddigit = 1;
		if( (setcall(m->call,m->name) == -1) || (!founddigit) ) {
			m->privs &= ~AX25_CMD;
			m->privs &= ~NETROM_CMD;
		}
#else
        m->privs &= ~AX25_CMD;
        m->privs &= ~NETROM_CMD;
#endif
        /*Kill ssid in name, if any*/
        if((cp=strchr(m->name,'-')) != NULLCHAR)
            *cp = '\0';
        /*Check if sysop password is set,
		 *if not, disallow sysop privs no matter what !
		 */
		if(*Mbpasswd == '\0')
			m->privs &= ~SYSOP_CMD;
		/*Check to see if any of NO_READ,NO_SEND or NO_3PARTY were set,
		 *if so, dis-allow those no matter what
		 *(so that users cannot get priviledges by issuing a ***linked)
		 * 920220 - WG7J
		 */
		if(oldprivs & NO_SENDCMD)
			m->privs |= NO_SENDCMD;
		if(oldprivs & NO_READCMD)
			m->privs |= NO_READCMD;
		if(oldprivs & NO_3PARTY)
			m->privs |= NO_3PARTY;

		tprintf("Oh, hello %s.\n",m->name);
		changearea(m,m->name, (int) 1);
		return 0;
	}
	if(argc > 1 && (m->sid & MBX_SID))	/* "*** Done" or similar */
	        return -2;
	return -1;
}


int
dombtelnet(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
int s, len, i;
char dsocket[MAXSOCKSIZE];
struct sockaddr_in fsocket;

	m = (struct mbx *) p;
	fsocket.sin_family = AF_INET;
	if(argc < 3)
		fsocket.sin_port = IPPORT_TELNET;
	else
		fsocket.sin_port = atoip(argv[2]);

	if((fsocket.sin_addr.s_addr = resolve(argv[1])) == 0){
		tprintf(Badhost,argv[1]);
        /* Free m->startmsg if set ! - WG7J */
        if(m->startmsg != NULLCHAR) {
            free(m->startmsg);
            m->startmsg = NULLCHAR;
        }
        return 0;
	}
	/* Only local telnets are are allowed to the unprivileged user */
    /* The above is a security hole ! DO NOT allow this anymore ! - WG7J */

    /* If the first letter of the command is 'C', then it was
     * the CALL,QUERY,OPERATOR or CONFERENCE command !
     * Allow these, no matter what.
     * This way, you can give access to the Internet callserver,
     * but disable all other telnets - WG7J
     */
    if(SecureTelnet && *argv[0] != 'C') {
        if(!(m->privs & TELNET_CMD) /* && !ismyaddr(fsocket.sin_addr.s_addr)*/ ){
            tputs(Noperm);
            mail_error("%s: Telnet denied: %s\n",m->name,cmd_line(argc,argv,m->stype));
            /* Free m->starmsg if set ! - WG7J */
            /* Shouldn't happen here, but just in case */
            if(m->startmsg != NULLCHAR) {
                free(m->startmsg);
                m->startmsg = NULLCHAR;
            }
            return 0;
        }
    }
    SecureTelnet = 1;
	if((s = socket(AF_INET,SOCK_STREAM,0)) == -1){
        tputs(Nosock);
        /* Free m->starmsg if set ! - WG7J */
        if(m->startmsg != NULLCHAR) {
            free(m->startmsg);
            m->startmsg = NULLCHAR;
        }
        return 0;
	}
#ifdef GWTRACE
	log(m->user,"MBOX TELNET: %s to %s:%d",m->name,argv[1],fsocket.sin_port);
#endif
	if(fsocket.sin_port == IPPORT_TTYLINK) {
		m->startmsg = mallocw(80);
		len = MAXSOCKSIZE;
		i = getpeername(m->user,dsocket,&len);
		sprintf(m->startmsg,"*** Incoming call from %s@%s ***\n",
			m->name,i != -1 ? psocket(dsocket): Hostname);
	}
    m->state = MBX_GATEWAY;
    return gw_connect(m,s,(struct sockaddr *)&fsocket,SOCKSIZE);
}

int
dombfinger(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
char *host, *user = NULLCHAR, buf[8], *newargv[3];

	if(argc > 2){
        tputs("Usage: F user@host  or  F @host  or  F user.\n");
		return -1;
	}
	host = Hostname;
	if(argc == 2){
		if((host = strchr(argv[1], '@')) != NULLCHAR){
			*host = '\0';
			host++;
		} else
			host = Hostname;
		user = argv[1];
	}
	m = (struct mbx *) p;
	m->startmsg = mallocw(80);
	if(user != NULLCHAR)
		sprintf(m->startmsg,"%s\n",user);
	else
		strcpy(m->startmsg,"\n");
    newargv[0] = "t";
    newargv[1] = host;
	sprintf(buf,"%d",IPPORT_FINGER);
	newargv[2] = buf;
	SecureTelnet = 0;
	return dombtelnet(3,newargv,p);
}


extern int Mbconverse;

#ifdef  CONVERS
int
dombconvers(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
int channel = -1;
struct session *sp;

	m = (struct mbx *) p;

        if(!Mbconverse) {
            tputs("Conference server not enabled\n");
            return 0;
        }
	if(argc != 1)
		channel = atoi (argv[1]);
#ifdef GWTRACE
        log(m->user,"MBOX CONFERENCE: %s",m->name);
#endif
        m->state = MBX_CONVERS;
	usflush(Curproc->output);
	if (Current->type == 1)
		tprintf ("%c%c", IAC, CLEARSCREEN);	/* sets Current->split */
	sp = Current;
	pwait (NULL);
        mbox_converse(m->user, m->name, channel, m);
	if (sp->split)	{
		usflush(Curproc->output);
		tprintf ("%c%c", IAC, CLEARSPLIT);	/* clears Current->split */
		usflush(Curproc->output);
	        sp->split = 0;
	}
	return 0;
}
#endif

#ifdef TUTOR
extern int Sinfo;
#endif

int
dombhelp(argc,argv,p)
int argc;
char *argv[];
void *p;
{
char buf[255];
FILE *fp;
struct mbx *m;

	m = (struct mbx *)p;

	if ((m->stype == 'F') && (m->privs & SYSOP_CMD))	{
		forwardingSummary ();
		return 0;
	}
	if (m->stype == 'H')
		return (doipheard (argc, argv, p));
	if (m->stype == 'P')
		return (dombiproute (argc, argv, p));
		
	buf[0] = '\0';
	/* check for "?" and "help" here */
	if(*argv[0] == '?' || *argv[0] == 'h') {
		bbscolorcls (m);
		bbscolorchange (m, "07");
		dombxhelp (argc, argv, p);
		if (*argv[0] == '?' && argc == 1)	{
			bbscolorchange (m, "0B");
			tputs(Alsomenu);
			if (m->privs & SYSOP_CMD)
				tputs(Sysopmenu);
			bbscolorchange (m, "09");
			sprintf(buf,"%s/help.hlp",Helpdir);
			goto also;
		}
		return 0;
	}
#ifdef TUTOR
	if (Sinfo != -1)	{
	        log(m->user,"MBOX TUTORIAL: %s",m->name);
       		m->state = MBX_TUTOR;
       		tutorserv(m->name, m, 1, m->usecolor, 0);
       	} else	{
#endif
		tprintf(Nosversion,Version);
		tprintf ((BbsUsers == 1) ? Only : CurUsers, BbsUsers);
		sprintf(buf,"%s/sysinfo.hlp",Helpdir);
also:		if((fp = fopen(buf,READ_TEXT)) != NULLFILE) {
			sendfile(fp,Curproc->output,ASCII_TYPE,0);
			fclose(fp);
		} else {
			if(argc > 1 && *argv[0] == 'h')
			tputs("No help available.\n");
		}
#ifdef TUTOR
	}
#endif
	return 0;
}

extern char Badmsg[];
extern char Nomail[];

/* Move messages from current area to another */
int
dombmovemail(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int num,i;
int movebuf[NARG];
char *to;
struct mbx *m;
char buf[MBXLINE];
#ifdef notdef
char *cp;
#endif
FILE * Mfile;           /* file to move to */
struct let *cmsg;
long size;
int thisone, wrcntr;
#ifdef nope
int nextisBID;
long msgid;
#endif
struct let lt;

    m = (struct mbx *)p;

    if(argc == 1) {
	char *which;
	which = (m->stype == 'M') ? "move" : (m->stype == 'W') ? "write" : "copy";
        tprintf("Syntax: M%c area - %s current message\n        M%c n1 [n2...] %s - %s message n1 (n2...)\n",
		m->stype, which, m->stype, (m->stype == 'W') ? "filename" : "area", which);
        return 0;
    }
    if(m->mfile == NULLFILE) {
        tputs(Nomail);
        return 0;
    }
    if(argc == 2) {
        /* NO message #, use current message */
        num = 1;
        to = argv[1];
        movebuf[0] = m->current;
    } else {
        /* Scan all message # to move */
        num=0;
        for(i=1;i<argc-1;i++) {
            if( (movebuf[num]=atoi(argv[i])) != 0 )
                if(movebuf[num] <= m->nmsgs)
                    num++;
            else
                tprintf(Badmsg,argv[i]);
        }
        to = argv[argc-1];
    }
#ifdef notdef
    /* translate '.' and '\' to '/' */
    for(cp=to;*cp!='\0';cp++)
        if((*cp == '.') || (*cp == '\\'))
            *cp = '/';
#else
    if (m->stype != 'W')
	    nntp_name_expansion (to);
#endif

    /* Now try to lock the destination file, if not a write */
    if(m->stype != 'W')
	    if(mlock(Mailspool,to) == -1) {
        	tprintf("Can't lock '%s', please try later\n",to);
	        return 0;
    		}
    /* open the destination file for appending */
    if (m->stype == 'W')	{
    	char *p;
    	p = permtest (m->path, m->privs, to, STOR_CMD, NULLCHAR, 0);
    	if (!p)
    		return 0;
	strcpy (buf,p);
	free (p);
    } else 
	sprintf(buf,"%s/%s.txt",Mailspool,to);
    if((Mfile=fopen(buf,"a")) == NULLFILE) {
        tprintf("Can't open '%s'\n",buf);
        if (m->stype != 'W')
	        rmlock(Mailspool,to);
        return 0;
    }
#ifdef nope
    nextisBID = 0;
#endif
    /* Okay, let's do the work */
    for(i=0;i<num;i++) {
        thisone = movebuf[i];
        cmsg = &m->mbox[thisone];
        /* find start of this message */
        fseek(m->mfile,cmsg->start,0);
        size = cmsg->size;
        fflush (Mfile);
        lt.size = cmsg->size;
        lt.bid = cmsg->bid;
        lt.status = 0;
        lt.start = filelength (fileno(Mfile));
	wrcntr = 0;
        
        /* now read this message */
        while(size > 0 && fgets(buf,MBXLINE,m->mfile)!= NULLCHAR) {
	    pwait (NULL);
	    if (m->stype != 'W' || wrcntr > 2)
	            fputs(buf,Mfile);
	    wrcntr += 1;
#ifdef nope
	    if (nextisBID && (cp=strstr(buf,"AA")) != NULLCHAR) {
		/*what follows is the message-number*/
		msgid = atol(cp+2);
		nextisBID = 0;
		}
            if (!strncmp (Hdrs[RECEIVED], buf, strlen(Hdrs[RECEIVED])))
            	nextisBID = 1;
#endif						
            size -= strlen(buf);
        }
#ifdef USERLOG
        updateCtl (to, &lt);
#endif
        /* delete this message, if moving */
        if (m->stype == 'M')	{
	        cmsg->status |= BM_DELETE;
		statusCtl (m->area, "ctl", cmsg, thisone, 0);
		if (!issysarea (m->area))
		       	m->change |= CHG_DELETE;
        }
	tprintf("Message %d %s...\n",thisone, (m->stype == 'M') ? "moved" : (m->stype == 'W') ? "written" : "copied");
    }
    fclose(Mfile);
    if (m->stype != 'W')
	    rmlock(Mailspool,to);
    return 0;
}


static int
expertstat (m)
struct mbx *m;
{
char *p;
int32 flag;

	switch(m->stype) {
		case 'M':	tprintf("-more- after %d lines\n",m->morerows);
				return 0;
		case 'A':	p = "Area added to prompt";
				flag = m->sid & MBX_AREA;
				break;
		case 'N':	p = "Name added to prompt";
				flag = m->sid & MBX_NRID;
				break;
		case 'S':	p = "New message scan at login";
				flag = m->sid & MBX_STATS;
				break;
		case 'G':	p = "Use ANSI color graphics";
				flag = m->sid & MBX_GFX;
				break;
#ifdef DELEGATE
		case 'D':	display_delegation(m->name);
				p = "Forward delegation";
				flag = m->sid & MBX_DELEGATE;
				break;
#endif
#ifdef LZW
		case 'C':	p = "Use Compressed streams";
				flag = m->sid & MBX_TNOS;
				break;
#endif
		case 'X':
		case ' ':       p = "Expert user prompts";
				flag = m->sid & MBX_EXPERT;
				break;
		default:        return 0;
	}
	tprintf ("%s: o%s\n", p, (flag) ? "n" : "ff");
	return 0;
}


int
dombgetall (m)
struct mbx *m;
{
char *args[2];

	tprintf ("*** User profile settings: %s ***\n\n", m->name);
	m->stype = 'M';		expertstat (m);
	m->stype = 'A';		expertstat (m);
	m->stype = 'N';		expertstat (m);
	m->stype = 'S';		expertstat (m);
	m->stype = 'G';		expertstat (m);
	m->stype = 'C';		expertstat (m);
#ifdef LZW
	m->stype = 'X';		expertstat (m);
#endif
	args[1] = "F";		dombget(2, args, m);
	args[1] = "Si";		dombget(2, args, m);
#ifdef DELEGATE
	args[1] = "D";		dombget(2, args, m);
#endif
	tprintf ("\nUse the SET command to change these options. For help, type HELP SET.\n");
	return 0;
}


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

	if (argc == 1)
		return (dombgetall(p));
	m = (struct mbx *)p;
	m->stype = toupper (*argv[1]);
	if (m->stype != 'F' && strnicmp(argv[1], "Si", 2))
		return (expertstat(m));
	sprintf (m->line, "%s/%s%s", (m->stype == 'F') ? Fdir : Signature, m->name, (m->stype == 'S') ? ".sig" : "");
	tprintf ("---------------- Current %s Information ----------------\n", (m->stype == 'F') ? "Finger" : "Signature");
	cnt = DisplayFile(m->line, m->user);
	tprintf ("---------------- %s %s Information ----------------\n", (cnt) ? "End of" : "No", (m->stype == 'F') ? "Finger" : "Signature");
	return 0;
}


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

	m = (struct mbx *)p;
	m->stype = 'R';
	return (dosend (argc, argv, p));
}

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

	m = (struct mbx *)p;
	m->stype = 'L';
	return (dombusers (argc, argv, p));
}


#ifdef TIPMAIL
int
dombslip(argc,argv,p)
int argc;
char *argv[];
void *p;
{
register struct mbx *m;

	m = (struct mbx *)p;
	if (m->type != TIP)	{
		tputs ("This command not configured for this interface\n");
		return (0);
	}
	if (m->privs & NO_SLIP)	{
		tputs (Noperm);
		return 0;
	}
	suspendTipMail (m);
	return -2;
}
#endif


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

    m = (struct mbx *)p;

    switch(m->stype) {
    case 'M':
        if(argc == 1)	{
            tprintf("-more- after %d lines\n",m->morerows);
            return 0;
        } else {
            m->morerows = atoi(argv[1]);
        }
        break;
    case 'A':
        m->sid ^= MBX_AREA;
        break;
    case 'G':
    	m->sid ^= MBX_GFX;
	m->usecolor ^= 1;
    	break;
    case 'N':
        m->sid ^= MBX_NRID;
        break;
    case 'S':
        m->sid ^= MBX_STATS;
        break;
#ifdef DELEGATE
    case 'D':
	if (Mbdelegate)	{
		m->sid ^= MBX_DELEGATE;
		if (m->sid & MBX_DELEGATE)
			setup_delegate (m);
		else
			clear_delegate (m);
	} else	{
		tprintf ("Forwarding delegation disabled by SYSOP\n");
		m->sid &= ~MBX_DELEGATE;
		return 0;
	}
	break;
#endif
#ifdef LZW
    case 'C':
    	m->sid ^= MBX_TNOS;
	up = itop(m->user);
    	if ((m->sid & MBX_TNOS) || (up->zout != NULLLZW))
	    	togglelzw (m->user, m->sid & MBX_TNOS);
    	break;
#endif
    case ' ':
    case 'X':
        m->sid ^= MBX_EXPERT;
        break;
    default:
        return 0;
    }
    m->update = 1;
    return (expertstat (m));
}

int
dombexpand(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
struct list *ap,*list;
char *arg, *orig, *newaddr, buf[LINELEN];
int loopindex;

	m = (struct mbx *)p;
	tprintf ("Address '%s' expands to: ", argv[1]);
	arg = argv[1];
	list = NULLLIST;
	orig = strdup (arg);
        /* rewrite address if possible */
	if((newaddr = rewrite_address(arg)) != NULLCHAR)
		if(strcmp(newaddr,arg) == 0){
			free(newaddr);
			newaddr = NULLCHAR;
		} else {
			strcpy(buf,newaddr);
			arg = buf;
		}
        list = NULLLIST;
	expandalias(&list,arg, orig);
	free (orig);
	if (strcmp(list->val,arg) == 0 && list->next == NULLLIST)
		if(newaddr == NULLCHAR){
			(void) tprintf("'%s'\n",arg);
			del_list(list);
			return 0;
		}
	ap = list;
	loopindex = 0;
	while (ap->next != NULLLIST){
		if (!(loopindex++ % 2))
			tputc ('\n');
		tputs ("     ");
		(void) tprintf("%-32.32s",ap->val);
		ap = ap->next;
	}
	tprintf ("%s     %s\n", (loopindex % 2) ? "" : "\n", ap->val);
	del_list(list);
	free(newaddr);
	return 0;
}


int
dombroute(argc,argv,p)
int argc;
char *argv[];
void *p;
{
char *arg, *newaddr, buf[LINELEN];
int k, loopindex;

	arg = argv[1];
	tprintf ("Address '%s' routes to:", argv[1]);
        /* rewrite address if possible */
	if((newaddr = rewrite_address(arg)) != NULLCHAR)
		if(strcmp(newaddr,arg) == 0){
			free(newaddr);
			newaddr = NULLCHAR;
		} else {
			strcpy(buf,newaddr);
			arg = buf;
		}
	else
		newaddr = strdup (argv[1]);
	for (loopindex = 0,k = 0; k < Numfwds; k++)
		if (AREAlookup (newaddr, k))	{
			if (!(loopindex++ % 3))
				tputs ("\n   ");
			(void) tprintf("%-25.25s",MyFwds[k]);
		}
	tputc ('\n');
	free (newaddr);
	return 0;		
}


#ifdef RMAIL
int
dombrmail(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int orgchange;
struct mbx *m;
char *cp;

	m = (struct mbx *)p;
	if (!(m->sid & MBX_SID))	{	/* not available to BBSs */
		orgchange = m->change;
		m->change = -1;
		m->stype = 'C';
		cp = malloc (strlen (argv[1]) + 8);
		sprintf (cp, "rmail@%s", argv[1]);
		argv[1] = cp;
		dosend (argc, argv, p);
		m->change = orgchange;
		free (cp);
	}
	return 0;
}
#endif


#ifdef LZW
void
togglelzw(soc, mode)
int soc, mode;
{
struct usock *up;

	if((up = itop(soc)) == NULLUSOCK)
		return;
    	tprintf ("%c%c%c%c", IAC, COMPRESSED, (Lzwmode) ? 'f' : 'c', Lzwbits);
	usflush(soc);
/*	if(socklen(soc,0)) */	/* discard any remaining input */
/*		recv_mbuf(soc,NULL,0,NULLCHAR,0);	*/
	if(mode)	{
	    	lzwinit (soc, Lzwbits, Lzwmode);
	    	up->zin->maxbits = -1;
	} else
		lzwfree (up);
	usflush(soc);
	if(socklen(soc,0)) /* discard any remaining input */
		recv_mbuf(soc,NULL,0,NULLCHAR,0);
}
#endif


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

	m = (struct mbx *)p;
	m->stype = toupper (*argv[1]);
	if (!strnicmp(argv[1], "Si", 2))
		m->stype = '$';
	if (m->stype == 'F' || m->stype == '$')
		return (dombupload(argc, argv, p));
	else
		return (dombexpert(argc - 1, &argv[1], p));
}


/* Routine for quickly checking an area for messages that are new to this user.
   This routine reads the area.ctl files, which contains a bid for each message.  */

static int
quickstat(m, area)
register struct mbx *m;
char *area;
{
long last, newlast, lastone;
char oldarea[20], buf[256];
FILE *fp;
register int retval = 0;

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

	if( (stricmp(area,"help") && isarea(area)) || !strnicmp(m->area,"sys",3) || (m->privs & SYSOP_CMD))
		getlastread(m);
	pwait (NULL);
	lastone = m->lastread;
	m->lastread = last;
	m->newlastread = newlast;
	strcpy (m->area, oldarea);
	sprintf (buf, "%s/control/%s.ctl", Mailspool, area);
	if ((fp = fopen (buf, READ_BINARY)) != NULLFILE)	{
		struct let lt;
		long size;
		size = (filelength (fileno(fp)) - sizeof(struct let));
		fseek (fp, size, SEEK_SET);
		fread (&lt, sizeof(struct let), 1, fp);
		fclose(fp);
		if (lt.bid > lastone)
			retval = 1;
	}
	pwait (NULL);
#endif
	return retval;
}



#ifdef USERLOG
void
quickscan (m, olduser)
struct mbx *m;
int olduser;
{
char *cp;
FILE *fp;
char buf[MBXLINE];
char out[80], *initmsg;
int found = 0, length = 3;
/* int total, new, hold;	*/

	cp = Arealist;
	if((m->privs & SYSOP_CMD) && (!access(AreaSlist, 0)))
		cp = AreaSlist;
	if((fp = fopen(cp,READ_TEXT)) == NULLFILE)
		return;
	if (olduser)
		initmsg = "You have unread messages, in the following message areas:\n";
	else
		initmsg = "As a new user, you will find messages in the following message areas:\n";
	strcpy (out, "   ");
	while(fgets(buf,MBXLINE,fp) != NULLCHAR) 	{
		pwait (NULL);
		if(isalnum(buf[0])) 	{ /* skip comments */
			if((cp=strpbrk(buf," \t")) != NULLCHAR)
				*cp = '\0';
/*			statarea (m, buf, &total, &new, &hold, 0);
			if (new)	{		*/
			if (quickstat (m, buf))		{
				if (!found)	{
					tputs (initmsg);
					found++;
					}
				length += (strlen(buf) + 2);
				strcat (out, buf);
				strcat (out, "  ");
				}
			if (length > 70)	{
				tputs (out);
				tputc('\n');
				out[3] = 0;
				length = 3;
				}
			}
		}
	if (length != 3)	{
		tputs (out);
		tputc('\n');
	}
	fclose (fp);
	if (!found)
		tputs ("No unread messages in the public areas! You are up-to-date!\n");
}
#endif


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

	m = (struct mbx *) p;
	time (&isnow);
	tprintf ("The system time at '%s' is now: %s\n", Hostname, ptime(&isnow));
	return 0;
}


int
dombquote(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
char *host, buf[8], *newargv[3];

	host = Hostname;
	if(argc == 2)
		host = argv[1];
	m = (struct mbx *) p;
	newargv[0] = "t";
	newargv[1] = host;
	sprintf(buf,"%d",IPPORT_QUOTE);
	newargv[2] = buf;
	SecureTelnet = 0;
	return dombtelnet(3,newargv,p);
}

void
informGroup (action, group, user, buf, old, new, in)
char *action, *group, *user, *buf;
FILE *old, *new, *in;
{
char subj[68], *cp;

	sprintf (subj, "%s: SUBSCRIBED %s", user, group);
	while (fgets(buf,50,old) != NULLCHAR)	{
		fputs (buf, new);
		if (*buf != ' ')
			break;
		if (buf[strlen (buf) - 2] == 'I')	{
			if ((cp = strchr (&buf[1], ' ')) != NULLCHAR)
				*cp = 0;
			if (in)
				rewind (in);
			rdaemon (in, NULLCHAR, &buf[1], subj, 'P', 0);
		}
	}
}


int
isgroup (group)
char *group;
{
FILE *old;
register len, retval = 0;
char buf[80];

#if 0
	if (group && (len = strlen (group)) > 6)
		return 0;
#else
	len = strlen (group);
#endif
	if ((old = fopen(Group, UPDATE_TEXT)) == NULLFILE)
		return 0;
	while (fgets(buf,80,old) != NULLCHAR)	{
		if (!strnicmp (buf, group, (unsigned)len) && buf[len] == ':')	{
			retval = 1;
			break;
		}
	}
	fclose (old);
	return retval;
}

int
groupcommand (action, group, user, local, out, in)
char *action, *group, *user;
int local;
FILE **out, *in;
{
FILE *new, *old;
char *newname, *cp;
register int len, found = 0, retval = 0;
char which, buf[80], subj[68];

#if 0
	if (group && (len = strlen (group)) > 6)
		return 0;
#else
	len = strlen (group);
#endif
	if ((old = fopen(Group, UPDATE_TEXT)) == NULLFILE)
		if ((old = fopen(Group, CREATE_TEXT)) == NULLFILE)
			return 0;
	newname = (char *) malloc (strlen (Group) + 5);
	sprintf (newname, "%s.new", Group);
	if ((new = fopen(newname, CREATE_TEXT)) == NULLFILE)	{
		fclose (old);
		free (newname);
		return 0;
	}
	*action = tolower (*action);
	if (*action == 'l')	{	/* list groups */
		if (!local)
			fprintf (new, "Index of mailing lists/groups\n\n");
		while (fgets(buf,50,old) != NULLCHAR)	{
			if (*buf != ' ' && (cp = strchr (buf, ':')) != 0)	{
				*cp++ = '\n';
				*cp = 0;
				if (!local)
					fputs (buf, new);
				else
					tputs (buf);
			}
		}
		if (!local)	{
			rewind (new);
			strcpy (subj, "GROUP LISTING");
			rdaemon (new, NULLCHAR, user, subj, 'P', 0);
		}
		retval = 1;
		goto confuzed;
	}
	if (*action != 'a')	{
		while (fgets(buf,50,old) != NULLCHAR)	{
			if (!strnicmp (buf, group, (unsigned)len) && buf[len] == ':')	{
				found = 1;
				break;
			}
			fputs (buf, new);
		}
		if (!found)
			goto confuzed;
		if (*action != 'd')
			fputs (buf, new);
	}
	switch (tolower (*action))	{
		case 'a':	fprintf (new, "%s:\n\n", group);
				break;
		case 'i':	fprintf (new, " %s I\n", user);
				break;
		case 's':	fprintf (new, " %s S\n", user);
				rip (buf);
				if (local)
					DisplayFile (&buf[len+2], Curproc->output);
				else
					*out = fopen (&buf[len+2], READ_TEXT);
				informGroup (action, group, user, buf, old, new, in);
				break;
		case 'u':	len = strlen (user);
				which = (strlen (action) < 3) ? 's' : tolower (action[2]);
				while (fgets(buf,50,old) != NULLCHAR)	{
					if (*buf != ' ')	{
						fputs (buf, new);
						break;
					}
					if (strnicmp (&buf[1], user, (unsigned)len) ||
						tolower (buf[strlen (buf) - 2]) != which)
							fputs (buf, new);
					else
						break;
				}
				break;
		case 'd':	while (fgets(buf,50,old) != NULLCHAR)
					if (*buf != ' ')	{
						if (*buf != '\n')
							fputs (buf, new);
						break;
					}
				break;
		default:	goto confuzed;
	}
	while (fgets(buf,50,old) != NULLCHAR)
		fputs (buf, new);
	fclose (new);
	fclose (old);
	unlink (Group);
	rename (newname, Group);
	free (newname);
	return 1;

confuzed:
	fclose (new);
	fclose (old);
	unlink (newname);
	free (newname);
	return retval;
}


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

	m = (struct mbx *) p;

	cmd = tolower (*argv[1]);
	if (cmd != 's' && cmd != 'u' && cmd != 'l')
		if (m->privs == -1 || !(m->privs & SYSOP_CMD))
			goto denied;
	if (cmd != 'l' && argc < 3)
		goto denied;
	if (!groupcommand (argv[1], (argc > 2) ? argv[2] : NULLCHAR, (argc > 3 && m->privs & SYSOP_CMD) ? argv[3] : m->name, 1, (FILE **)0, (FILE *)0))
denied:		tputs ("Denied!\n");
	return 0;
}


#ifdef TUTOR
extern int Stutor, Snews;

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

	m = (struct mbx *) p;

        if(Stutor == -1) {
            tputs("Tutorial server not enabled\n");
            return 0;
        }
        log(m->user,"MBOX TUTORIAL: %s",m->name);
        m->state = MBX_TUTOR;
        tutorserv(m->name, m, 0, m->usecolor, 0);
	return 0;
}


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

	m = (struct mbx *) p;

        if(Snews == -1) {
            tputs("News Center not enabled\n");
            return 0;
        }
        log(m->user,"MBOX NEWS: %s",m->name);
        m->state = MBX_TUTOR;
        tutorserv(m->name, m, 2, m->usecolor, 0);
	return 0;
}
#endif


char *
wpage_exp (to, hier, exphome)
char *to;
int hier;
int exphome;	/* append and expand home bbs name ? */
{
char DFAR *cp;
char DFAR *cp2;
char origbbs[40], buf[12];

/* This section adds the HOME BBS to any messages to known users that do
   not have "@bbs" portions of the TO address, except when user is a BBS	*/

    cp2=strchr(to,'@');
    cp = NULLCHAR;
    if ((cp2 == NULLCHAR) && (cp = findhome (to)) != (char DFAR *) NULL)	{
	if (cp != (char DFAR *) -1)	{	/* home no here */
	    	sprintf (origbbs, "%s@%s", to, cp);
    		free (to);
	    	free (cp);
	    	to = strdup (origbbs);
	}
    }
#ifdef WPAGES
/* This section looks up the destination bbs in the White Pages file, if user not a BBS
   If found, the complete address is substituted	*/
 
    if (cp != (char DFAR *) -1)	{	/* if home not here */
	    cp2=strchr(to,'@');
	    if (cp2 == NULLCHAR)	{	/* no dest BBS given */
    		if ((cp2 = wpageCheck (to, 0, 0)) != NULLCHAR)	{ /* found the bbs */
    			free (to);
	    		strlwr (cp2);
	    		to = cp2;
    		}
	    	cp2 = strchr(to, '@');
	    }
	    if (hier && cp2 != NULLCHAR)	{	/* we have a dest bbs, get correct, full haddress */
   			    cp = cp2++;
		    if ((cp2 = wpageCheck (cp2, 1, 0)) != NULLCHAR)	{
	    		    *cp = '\0';
	    		    sprintf (origbbs, "%s@%s", to, cp2);
	                    free (to);
        	            free (cp2);
               		    strlwr (origbbs);
	                    to = strdup (origbbs);	    	
		    }
	    }
    } else if (exphome)	{
	pax25(buf,Mycall);
	if((cp = strchr(buf,'-')) != NULLCHAR)
		*cp = '\0'; /* remove SSID */
    	sprintf (origbbs, "%s@%s%s%s", to, buf,
		(Mbhaddress != NULLCHAR) ? "." : "",
		(Mbhaddress != NULLCHAR) ? Mbhaddress : "");
	free (to);
    	to = strdup (origbbs);
    }
#endif
    pwait (NULL);
    return (to); 
}

#ifdef WPAGES
extern int MbWpages;

int
dombwpages(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
char buf[80], *cp, *cp2, origchar = 0;
#if 0
char *cp3;
#endif

	m = (struct mbx *)p;
	if(!(m->privs & SYSOP_CMD) && argc > 2)	{
		tputs ("Sorry, command is only available to the SYSOP!\n");
		return 0;
	}
	if (argc == 2)	{	/* lookup */
		cp = wpageCheck (argv[1], 0, 0);
		if (!cp)
			tputs ("Sorry, user not in whitepages! If local user, try \"ML user\"...\n");
		else	{
#if 0
			cp2 = strchr (cp, '@');
			*cp2++ = 0;
			cp3 = wpageCheck (cp2, 1, 0);
			if (!cp3)
				cp3 = cp2;
			strupr (argv[1]);
			strupr (cp3);
			tprintf ("White Pages lists this person as '%s@%s'\n", argv[1], cp3);
			if (cp3 != cp2)
				free (cp3);
#else
			cp2 = wpage_exp (strdup(argv[1]), 1, 1);
			strupr (cp2);
			tprintf ("White Pages lists this person as '%s'\n", cp2);
			free (cp2);
#endif
			free (cp);
		}
	} else	{	/* else, setting it */
		if (argv[2][0] != '@')
			tputs ("Syntax: WP user @bbsname\n");
		else	{
			if ((cp = strchr(argv[2], '.')) != NULLCHAR)	{
				sprintf(buf, &argv[2][1]);
				wpageAdd(buf, 1, 1);
				origchar = *cp;
				*cp = 0;
			}
			sprintf (buf, "%s%s", argv[1], argv[2]);
			wpageAdd (buf, 0, 1);
			if (origchar)
				*cp = origchar;
			RenewWPages();
		}
	}
	return 0;
}


void
wpageUpdate(fp, string, entry, oldtime, bbs, updateit)
FILE *fp;
char *string, *entry, *oldtime;
int bbs, updateit;
{
time_t now;
char buf[14], *cp;

/* parameters string and oldtime are not being used, yet */

	if (updateit && !bbs)	{	/* not updating bbs's, yet */
		strncpy (buf, string, 13);
		buf[13] = 0;
		if ((cp = strchr(buf, '.')) != NULLCHAR)
			*cp = 0;
		entry = buf;
	}
	time(&now);
	fprintf(fp,"%-*s %-14ld\n",(bbs) ? 32 : 13, entry,now); /* update time stamp */
	pwait (NULL);
}


/* Returns a copy (strdup'ed) of existing entry if string is in whitepages file */
char *
wpageCheck(string, bbs, updateit)
char *string;
int bbs, updateit;
{
register FILE *fp;
char buf[LINELEN], *retval = NULLCHAR;
register char *cp;
int result, thelen;
int entrysize;
char *fname;

	if (!MbWpages || string == NULLCHAR || !*string)
		return (retval);
	if (!strnicmp (string, "sysop", 5))
		return (retval);
	entrysize = (bbs) ? WPAGEBBSENTRYSIZE : WPAGEENTRYSIZE;
	fname = (bbs) ? WhitePagesBBS : WhitePages;
	if ((cp = strchr(string, (bbs) ? '.' : '@')) != NULLCHAR)
		thelen = (int) (cp - string);
	else
		thelen = strlen (string);
	result = searchfile (string, fname, buf, entrysize, 0, thelen);
	if (result != -1)	{	/* found it */
		if( ((cp=strpbrk(buf," \t")) != NULLCHAR))
			*cp = '\0';
		rip(buf);
		retval = strdup (buf);
		fp = fopen (fname, UPDATE_TEXT);
		fseek (fp, (long) (long)result * (long) entrysize, 0);
		wpageUpdate (fp, string, buf, &buf[(bbs) ? 33 : 14], bbs, updateit);
		fclose(fp);
	}
	return retval;
}
     

void
wpageAdd (entry, bbs, updateit)
char *entry;
int bbs, updateit;
{
time_t now;
FILE *fp;
char *last, buf[14];

	if (!MbWpages || entry == NULLCHAR)
		return;
	if (!strnicmp (entry, "sysop", 5))
		return;
	last = wpageCheck (entry, bbs, updateit);
	free (last);
	if (!last)	{
		time(&now);
		if (!bbs)	{
			strncpy (buf, entry, 13);
			buf[13] = 0;
			if ((last = strchr(buf, '.')) != NULLCHAR)
				*last = 0;
			entry = buf;
		}
		if((fp = fopennew((bbs) ? WhitePagesBBS : WhitePages,APPEND_TEXT)) != NULLFILE) {
			fprintf(fp,"%-*s %-14ld\n",(bbs) ? 32 : 13, entry,now); /* Save h_addr in whitepages file */
			pwait (NULL);
			fclose(fp);
		}
	}

}
#endif


/* Returns true if string is in history file or if string appears to be a
 * message id generated by our system.
 */
int
msgidcheck(string)
register char *string;
{
char buf[LINELEN];
register char *cp;

     if(string == NULLCHAR)
	  return 0;
     /* BID's that we have generated ourselves are not kept in the history
      * file. Such BID's are in the nnnn_hhhh form, where hhhh is a part of
      * our hostname, truncated so that the BID is no longer than 11
      * characters.
      */
     if((cp = strchr(string,'_')) != NULLCHAR && *(cp+1) != '\0' && 
	strnicmp(cp+1,Hostname,strlen(cp+1)) == 0)
	  return 1;

     if (searchfile (string, Historyfile, buf, WPAGEENTRYSIZE, 0, 0) != -1)
     	return 1;
     return 0;
}
     

/* Releases a bid from the history file. Used when a personal message
 * is forwarded off the system. Lets it be able to come back here,
 * if needed.
 */
void
msgiddelete(string)
register char *string;
{
register FILE *fp;
char buf[LINELEN];
int index;

	if(string == NULLCHAR)
		return;

	index = searchfile (string, Historyfile, buf, WPAGEENTRYSIZE, 0, 0);
	if (index == -1)
		return;

	if((fp = fopen(Historyfile,UPDATE_TEXT)) == NULLFILE)
		return;
	fseek (fp, (long) ((long) index * (long) 30), 0);
	fputc ('$', fp);
	fclose(fp);
	pwait (NULL);
}
     

int
dombfdesc(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
char *file, *cp, *nm;
FILE *fp;
int k;
#ifdef DOS_GETFILEATTR
unsigned attr;
char name[14];
#endif
	
	m = (struct mbx *) p;
	if (!(file = permtest (m->path, m->privs, argv[1], RETR_CMD, NULLCHAR, 0)))	{
		tputs (Noperm);
		return 0;
	}

#ifdef DOS_GETFILEATTR
	_dos_getfileattr (file, &attr);
#endif
	nm = strrchr (file, '/');
	*nm++ = 0;
#ifdef DOS_GETFILEATTR
	if(attr & FA_DIREC)	{
		sprintf (name, "%s/", nm);
		nm = name;
		}
#endif
	cp = pathname (file,index_dat);
	if ((fp = fopen (cp, APPEND_TEXT)) == NULLFILE)	{
		tputs ("Can't open description file!\n");
		return 0;
	}
	fprintf (fp, "%-12s", nm);
	free (file);
	free (cp);
	tputs ("Enter description lines, each line 37 characters maximum.\n'/EX' when complete:\n");
	for (k = 1; k < 38; k++)
		tputc ('0' + (k % 10));
	tputc ('\n');
	while(mbxrecvline(m) != -1)	{
		if (!strnicmp (m->line, "/ex", 3))	{
			fclose (fp);
			return (0);
		}
		fprintf (fp, " %-37.37s\n", skipwhite (m->line));
	}
	fclose (fp);
	return (-2);	/* socket closed here! */
}



int
dodownload(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
FILE *fp;
char *file;

	m = (struct mbx *)p;
	if (m->stype == 'I')
		return (dowhat (argc, argv, p));
	if (m->stype == 'E')
		return (dozap (argc, argv, p));

	if (!(file = permtest(m->path, m->privs,argv[1],RETR_CMD, NULLCHAR, 0)))	{
	        tputs(Noperm);
        	mail_error("%s: download denied: %s\n",m->name,cmd_line(argc,argv,m->stype));
		return 0;
	}
	m->state = MBX_DOWNLOAD;
#ifdef TIPMAIL
#ifdef XMODEM
	if (m->stype=='X') { 
	      if (m->type==TIP){   /* xmodem send tip only */
		m->state = MBX_XMODEM_TX;
#ifdef MBXTDISC
	/* disable the mbox inactivity timeout timer - WG7J */
		stop_timer(&m->tdisc);   
#endif
		doxmodem('S',file,m);
		return 0;
	      } else {
		tprintf("Xmodem on TIP connects only\n");
		return 0;
	      }
	}
#endif
#endif
	if((fp = fopen(file,READ_TEXT)) == NULLFILE)
		tprintf("Can't open \"%s\": %s\n",file,sys_errlist[errno]);
	else		{
#ifdef MBXTDISC
	        /* disable the mbox inactivity timeout timer - WG7J */
        	stop_timer(&m->tdisc);
#endif
		if(m->stype == 'U')	{			/* uuencode ? */
			fclose(fp);
			fp = fopen(file,READ_BINARY);	/* assume non-ascii */
			uuencode(fp,m->user,file);
		} else
			sendfile(fp,m->user,ASCII_TYPE,0);
		fclose(fp);
	}
	free(file);
	return 0;
}


int
dombupload(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
FILE *fp;
char *file;

	m = (struct mbx *)p;
	if (m->stype == 'S')	{
		m->stype = 'L';
		return (dombusers (argc, argv, p));
	}
	if (m->stype == 'F')	{
		sprintf (m->line, "%s/%s", Fdir, m->name);
		file = strdup(m->line);
	} else if (m->stype == '$')	{
		sprintf (m->line, "%s/%s.sig", Signature, m->name);
		file = strdup(m->line);
#ifdef DELEGATE
	} else if (m->stype == 'M')	{
		sprintf (m->line, "%s/%s.del", Signature, m->name);
		file = strdup(m->line);
#endif
	} else if(!(file = permtest(m->path, m->privs,argv[1],STOR_CMD, NULLCHAR, 0)))	{
		tputs(Noperm);
	        mail_error("%s: upload denied: %s\n",m->name,cmd_line(argc,argv,m->stype));
		return 0;
	}
#ifdef TIPMAIL
#ifdef XMODEM
	if (m->stype=='X'){ 
		if (m->type==TIP){   /* xmodem receive tip only */
			m->state = MBX_XMODEM_RX;
#ifdef MBXTDISC
	/* disable the mbox inactivity timeout timer - WG7J */
			stop_timer(&m->tdisc);   
#endif
			doxmodem('R',file,m);
			return 0;
		} else {
			tprintf("Xmodem on TIP connects only\n");
			return 0;
		}
	}
#endif
#endif
	
	if((fp = fopen(file,WRITE_TEXT)) == NULLFILE)	{
		tprintf("Can't create \"%s\": %s\n",file,sys_errlist[errno]);
		free(file);
		return 0;
	}
	log(m->user,"MBOX upload: %s",file);
	m->state = MBX_UPLOAD;
	tprintf("Send %s,  %s",(m->stype == 'F') ? "personal information" : (m->stype == 'S') ? "signature information" : (m->stype == 'M') ? "personal message" : "file", Howtoend);
	for(;;)		{
		if(mbxrecvline(m) == -1)	{
			unlink(file);
			break;
		}
		if(*m->line == 0x01 || !stricmp (m->line, "/abort"))	{  /* CTRL-A */
			unlink(file);
			tputs(MsgAborted);
			break;
		}
		if(*m->line == CTLZ || !strnicmp("/ex",m->line,3) || !stricmp(m->line, "."))
			break;
		fputs(m->line,fp);
#if !defined(UNIX) && !defined(__TURBOC__) && !defined(AMIGA) && !defined(TNOS_68K)
		/* Needed only if the OS uses a CR/LF
		 * convention and putc doesn't do
		 * an automatic translation
		 */
		if(putc('\r',fp) == EOF)
			break;
#endif
		if(putc('\n',fp) == EOF)
			break;
	}
	free(file);
	fclose(fp);
	return 0;
}

void
bbsbump (user, zap)
char *user;
int zap;	/* if zap=1, remove entry, else just mark for bumping */
{
int i;
struct mbx *m;

	/* check the mailbox users */
	for(i = 0; i < NUMMBX; i++)	{
		if((m = Mbox[i]) != NULLMBX)	{
			if(!stricmp(m->name,user))
				break;
		}
	}
	if(i != NUMMBX)	{
		if (zap)
			exitbbs(m);
		else
			m->privs |= EXCLUDED_CMD;
	}
}


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

	m = (struct mbx *)p;
	if(!(m->privs & SYSOP_CMD))
		tputs ("Sorry, command is only available to the SYSOP!\n");
	else
		bbsbump (argv[1], ((argc > 2) && !strnicmp ("now", argv[2], 3)) ? 1 : 0);
	return 0;
}

/* uuencode a file -- translated from C++; both versions copyright 1990
   by David R. Evans, G4AMJ/NQ0I
*/

static int
uuencode(infile,s,infilename)
FILE *infile;
int s;			/* output socket */
char *infilename;
{
int n_read_so_far = 0, n_written_so_far = 0, in_chars, n, mode = 0755;
unsigned long cnt = 0;
unsigned char in[3], out[4], line[100];
#ifdef UNIX
struct stat stb;
  
  if(stat(infilename,&stb) != -1)
       mode = stb.st_mode & 0777;	/* get real file protection mode */
#endif
  usprintf(s, "begin %03o %s\n", mode, infilename);

  /* do the encode */
 for(;;){	
    in_chars = fread(in, 1, 3, infile);
    out[0] = in[0] >> 2;
    out[1] = in[0] << 6;
    out[1] = out[1] >> 2;
    out[1] = out[1] | (in[1] >> 4);
    out[2] = in[1] << 4;
    out[2] = out[2] >> 2;
    out[2] = out[2] | (in[2] >> 6);
    out[3] = in[2] << 2;
    out[3] = out[3] >> 2;
    for (n = 0; n < 4; n++)
      out[n] += ' ';
    n_read_so_far += in_chars;
    for (n = 0; n < 4; n++)
      line[n_written_so_far++] = out[n];
    if (((in_chars != 3) || (n_written_so_far == 60)) && n_read_so_far > 0) {
      line[(n_read_so_far + 2) / 3 * 4] = '\0';
      
      usprintf(s,"%c%s\n",n_read_so_far + ' ', line);
      cnt += n_read_so_far;
      n_read_so_far = 0;
      n_written_so_far = 0;
    }
    if (in_chars == 0)
      break;
  }
  if (usprintf(s," \nend\nsize %lu\n", cnt) == EOF)
    return 1;
  return 0;
}

#endif /* MAILBOX */


