/*
 * Citadel/UX  
 *
 * citadel.c - Main source file.
 *
 */

#include <fcntl.h>
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <pwd.h>
#include <setjmp.h>
#include "citadel.h"
#include "axdefs.h"
#include "ansi.h"
/* #include "color.h" */

#define IFEXPERT if (usersupp.flags&US_EXPERT)
#define IFNEXPERT if ((usersupp.flags&US_EXPERT)==0)
#define IFAIDE if (usersupp.axlevel>=6)
#define IFNAIDE if (usersupp.axlevel<6)
struct passwd *getpwuid();
struct passwd *getpwnam();
/* char *getenv(); */
long atol();
long lseek();
long finduser();
char logstr[64];

char fullname[32];
struct usersupp usersupp;		/* Logged-in user's user supp */
struct quickroom quickroom,QRscratch;	/* Current room and scratch   */
struct fullroom fullroom;		/* Current room               */
struct smreturn smreturn;		/* For returning message numbers */
struct config config;			/* System configuration */
struct msgmain msgmain;			/* Global message info           */
struct passwd *passwd;
int curr_rm;				/* Room NUMBER of current room.  */
int hold_rm;				/* Temporary room number */
					/* 0=Lobby 1=Mail 2=Aide 3-up=other */
char newnow;
char upass;				/* Nonzero if pw is managed by UNIX */
long yourpos;				/* position of your usersupp record */
char temp[16];				/* Name of general temp file */
int twitroom;				/* Room num of TWIT room (if enabled) */
jmp_buf nextbuf;
int ugnum; long uglsn;			/* holds <u>ngoto info */
char skipping;				/* skipped rooms flag */
long highest_msg_read;			/* used for <A>bandon room cmd */
char editorfile[16];			/* temporary file name */
int editor_pid = (-1);

/* signal handlers */

void backnext() {			/* this is where we go when */
	signal(SIGINT,SIG_IGN);		/* Ctrl-O (next) is pressed */
	signal(SIGQUIT,SIG_IGN);
	longjmp(nextbuf,1);
	}

void backstop() {
	signal(SIGQUIT,SIG_IGN);	/* this is where we go when */
	signal(SIGINT,SIG_IGN);		/* Ctrl-C (stop) is pressed */
	longjmp(nextbuf,2);
	}

void dropcarr() {			/* called by SIGHUP (usually means */
	struct calllog rtmp;		/* a modem user dropped carrier)   */
	strcpy(rtmp.CLfullname,(char *)ttyname(0));
	rtmp.CLflags=CL_DROPCARR;
	rec_log(&rtmp);
	logoff(SIGHUP);
	}


/* general purpose routines */

formout(name) /* display a file */
char name[];
	{
	char aaa[100];
	int a;
	FILE *fp;

	strcpy(aaa,name);
	for (a=0; a<strlen(aaa); ++a) aaa[a]=tolower(aaa[a]);
	if (setjmp(nextbuf)!=0) {
		sttybbs(SB_NO_INTR);
		return(1);
		}
	signal(SIGINT,backnext);
	signal(SIGQUIT,backstop);
	sttybbs(1);
	fp=fopen(aaa,"r");
	if (fp != NULL) {
		fmout(usersupp.USscreenwidth,fp,
			((usersupp.flags & US_PAGINATOR) ? 1 : 0),
			usersupp.USscreenheight);
		fclose(fp);
		}
	sttybbs(SB_NO_INTR);
	return(0);
}

userlist() /* prints the userlist */ {
	sttybbs(1);
	system("exec ./userlist");
	sttybbs(SB_NO_INTR);
	}

readmail() {
	int a;
	readyerself();
	for (a=0; a<MSGSPERRM; ++a) {
		fullroom.FRnum[a]=0L;
		fullroom.FRpos[a]=0L;
		}
	for (a=0; a<MAILSLOTS; ++a) {
		fullroom.FRnum[a+(MSGSPERRM-MAILSLOTS)]=usersupp.mailnum[a];
		fullroom.FRpos[a+(MSGSPERRM-MAILSLOTS)]=usersupp.mailpos[a];
		}
	return(0);
	}

writemail() {
	int a;
	readyerself();
	for (a=0; a<MAILSLOTS; ++a) {
		usersupp.mailnum[a]=fullroom.FRnum[a+(MSGSPERRM-MAILSLOTS)];
		usersupp.mailpos[a]=fullroom.FRpos[a+(MSGSPERRM-MAILSLOTS)];
		}
	writeyerself();
	return(0);
	}

readyerself() {		/* load the user's record off disk into memory */
	int file;
	file=eopen("usersupp",O_RDONLY);
	if (yourpos<0) yourpos=finduser(file,fullname);
	lseek(file,yourpos,0);
	do {
		read(file,&usersupp,sizeof(struct usersupp));
		if (strucmp(fullname,usersupp.fullname))
			yourpos=finduser(file,fullname);
		} while(strucmp(fullname,usersupp.fullname));
	close(file);
	return(0);
	}

writeyerself() {	/* rewrite the user's record to disk */
	int file;
	struct usersupp me;
	file=eopen("usersupp",O_RDWR);
	lseek(file,yourpos,0);
	read(file,&me,sizeof(struct usersupp));
if (me.eternal!=usersupp.eternal) yourpos=finduser(file,usersupp.fullname);
	lseek(file,yourpos,0);
	write(file,&usersupp,sizeof(struct usersupp));
	close(file);
	return(0);
	}

main(argc,argv)
int argc;
char *argv[]; {
int a,b,c,d,e,f,file,file2,mcmd,termn8;
FILE *fp;
long aa,cc;
char aaa[100],bbb[100],ccc[100],eee[100];	/* general purpose variables */
char argbuf[32];				/* command line buf */
struct usersupp tempUS;
struct calllog calllog;
char twit;

get_config();			/* Load system configuration from disk */
ulimit(2,8192L);		/* This may be unnecessary on some machines */
sttybbs(SB_SAVE);		/* Store the old terminal parameters */
sttybbs(SB_NO_INTR);		/* Install the new ones */
signal(SIGINT,SIG_IGN);
signal(SIGQUIT,SIG_IGN);
signal(SIGHUP,dropcarr);	/* Cleanup gracefully if carrier is dropped */
signal(SIGTERM,dropcarr);	/* Cleanup gracefully if terminated */

logit("Call opened.","");
printf("%s\n%s\n%s\n",CITADEL,config.c_humannode,config.c_bbs_city);
twit=0;				/* By default, user is not a problem user */
usersupp.USscreenwidth = 80;	/* default screen width */
if(isansi())
	formout("messages/hello.ansi");	/* print the opening greeting */
else
	formout("messages/hello");	/* print the opening greeting */

log_carr();
a=getuid();
passwd=(struct passwd *)getpwuid(a);
strcpy(fullname,passwd->pw_gecos);
for (b=0; b<strlen(fullname); ++b) if (fullname[b]==',') fullname[b]=0;
upass=1; if (a==BBSUID) upass=0;

twitroom=(-1);
GSTA:	termn8=0; newnow=0; if (upass==0) {	/* if using guest account,  */
	do {					/* find out who the user is */
		newprompt("Enter your name: ",fullname,29);
		strproc(fullname); 
		if (!strucmp(fullname,"new")) {	/* just in case */
		   printf("Please enter the name you wish to log in with.\n");
			}
		} while( 
			(!strucmp(fullname,"bbs"))
			|| (!strucmp(fullname,"new"))
			|| (strlen(fullname)==0) );
	if (!strucmp(fullname,"off")) {
		mcmd=29;
		goto TERMN8;
		}
	}

			/* get the usersupp data for guest account */
	file=eopen("usersupp",O_RDONLY);
	yourpos=finduser(file,fullname);
	if (yourpos==(-1L)) { close(file); goto NEWUSR; }
	read(file,&usersupp,sizeof(struct usersupp));
	close(file);
	goto USOK;

NEWUSR:	if (upass==0) {
		printf("No record. Enter as new user? ");
		if (yesno()==0) goto GSTA;
		}

	/* Initialize a new account */
	usersupp.USuid=getuid();
	strcpy(usersupp.fullname,fullname);
	for (a=0; a<MAXROOMS; ++a) {	usersupp.lastseen[a]=0L;
					usersupp.generation[a]=(-1);
					usersupp.forget[a]=(-1);
					}
	for (a=0; a<MAILSLOTS; ++a) {	usersupp.mailnum[a]=0L;
					usersupp.mailpos[a]=0L;
					}
	usersupp.flags=US_NEEDVALID|US_LASTOLD|US_DISAPPEAR|US_PAGINATOR;
	usersupp.timescalled=0;
	usersupp.posted=0;
	usersupp.axlevel=INITAX;
	usersupp.USscreenwidth = 80;
	usersupp.USscreenheight = 24;
	time(&aa);
	usersupp.lastcall=aa;
	getusinfo(&usersupp);
	
	if (upass==0) {
		IFNEXPERT formout("messages/changepw");
		newprompt("Please enter a password: ",usersupp.password,19);
		strproc(usersupp.password);
		pwcrypt(usersupp.password,PWCRYPT);
		newnow=1;
		}

	file=eopen("eternal",O_RDWR);	/* get a new user number */
	read(file,&aa,sizeof(long));
	usersupp.eternal=aa++;
	lseek(file,0L,0);
	write(file,&aa,sizeof(long));
	close(file);

	/* add user to userlog and hash table */
	signal(SIGHUP,SIG_IGN);
	if(isansi())
		formout("messages/newuser.ansi");
	else
		formout("messages/newuser");
	fp=fopen("usersupp","a");
	if (ftell(fp)==0L) {
		printf("*** This is the first user account and will\n");
		printf("    automatically be set to Aide (access level 6)\n");
		usersupp.axlevel = 6;
		}
	fwrite((char *)&usersupp,sizeof(struct usersupp),1,fp);
	fclose(fp);
	a=hash(usersupp.fullname);
	fp=fopen("hashtab","a");
	fwrite((char *)&a,sizeof(int),1,fp);
	fclose(fp);
	signal(SIGHUP,dropcarr);

	strcpy(calllog.CLfullname,usersupp.fullname);
	calllog.CLflags=CL_NEWUSER;
	rec_log(&calllog);
	logit("New user!","");
	lock_valid();

USOK:	/* make sure that if it's a shell user, they log in from the shell */
	if ((upass==0)&&(usersupp.USuid!=BBSUID)) {
		printf("Please log in by running Citadel from the shell.\n");
		printf("(press any key to continue)\n");
		inkey();
		logoff(0);
		}

/* password authentication (unless they're a shell user) */
if ((upass==0)&&(newnow==0)) {
	newprompt("\rPlease enter your password: ",eee,-19);
	strproc(eee);
	pwcrypt(usersupp.password,PWCRYPT);
	if (!strucmp(eee,usersupp.password)) {
		pwcrypt(usersupp.password,PWCRYPT);
		goto PWOK;
		}
	printf("<< wrong password >>\n");
	strcpy(calllog.CLfullname,usersupp.fullname);
	calllog.CLflags=CL_BADPW;
	rec_log(&calllog);
	logit("Bad password entered:",eee);
	goto GSTA;
	}

/* A room's generation number changes each time it is recycled. Users are kept
 * out of private rooms or forget rooms by matching the generation numbers. To
 * avoid an accidental matchup, unmatched numbers are set to -1 here.
 */
PWOK:	readyerself();
	strcpy(fullname,usersupp.fullname);
	usersupp.USuid=getuid();
	++usersupp.timescalled;
	time(&aa);
	usersupp.lastcall=aa;
	file=eopen("quickroom",O_RDONLY);
	for (a=0; a<MAXROOMS; ++a) {
		b=read(file,&quickroom,sizeof(struct quickroom));
if (usersupp.generation[a] != quickroom.QRgen) usersupp.generation[a]=(-1);
if (usersupp.forget[a] != quickroom.QRgen) usersupp.forget[a]=(-1);
		}
	close(file);
	if (usersupp.axlevel==2) twit=1;
	if (twit==1) usersupp.axlevel=2;
	writeyerself();
	ugnum=(-1);

	strcpy(calllog.CLfullname,usersupp.fullname);
	time(&calllog.CLtime);
	calllog.CLflags=CL_LOGIN;
	rec_log(&calllog);

	printf("%s\nAccess level: %d (%s)\nUser #%ld / Call #%d\n",
		usersupp.fullname,usersupp.axlevel,axdefs[usersupp.axlevel],
		usersupp.eternal,usersupp.timescalled);
if ((REGISCALL!=0)&&((usersupp.flags&US_REGIS)==0)
		&&(usersupp.timescalled>=REGISCALL)) {
	printf("*** Please register.\n");
	if(isansi())
		formout("messages/register.ansi");
	else
		formout("messages/register");
	a=entregis(NEWREGISTER);
	if (a==0) {
		readyerself();
		usersupp.flags=(usersupp.flags|US_REGIS|US_NEEDVALID);
		writeyerself();
		}
	}

	/* Read the message base pointers?  yes, because there are also some
	 * system-global flags in there, including MM_VALID, which is set
	 * whenever there are users that need to be validated.
	 * We read this data into memory even if we're not checking that flag,
	 * because the message base pointers will be used later on to check
	 * to see whether messages in the rooms scrolled out.
	 */
	file=eopen("MMstructure",O_RDONLY);
	read(file,&msgmain,sizeof(struct msgmain));
	close(file);
	IFAIDE {
		if (msgmain.MMflags&MM_VALID)
			printf("*** Users need validation\n");
		}

	b=0;				/* check for mail */
	for (a=0; a<MAILSLOTS; ++a)
		if (usersupp.mailnum[a]>usersupp.lastseen[1]) ++b;
	if (b==1) printf("*** You have a new private message in Mail>\n");
	if (b>1)  printf("*** You have %d new private messages in Mail>\n",b);

	sprintf(temp,"/tmp/cit%d",getpid()); /* make up temp file names */
	sprintf(editorfile,"/tmp/ced%d",getpid());

	set_wtmpsupp("Patio");
	logit("User logged in!","");

	/* Enter the lobby */
	curr_rm = 0;
	gotocurr();

/* Main part of the system... user is logged in. */
	skipping = 0;
	if (newnow==1)	readmsgs(MSGSPERRM-5,0,1);
		else	readmsgs(0,1,1);

do {	/* MAIN LOOP OF PROGRAM */
	signal(SIGINT,SIG_IGN);
	signal(SIGQUIT,SIG_IGN);
	mcmd=getcmd(argbuf);
	if (termn8==0) switch(mcmd) {
	   case 1:	if(isansi())
	   			formout("messages/help.ansi");
	   		else
	   			formout("messages/help");
			break;
	   case 4:	entmsg(0,0);
			break;
	   case 36:	entmsg(0,1);
			break;
	   case 46:	entmsg(0,2);
			break;
	   case 5:	updatels();
			gotonext();
			break;
	   case 47:	updatelsa();
			gotonext();
			break;
	   case 20:	updatels();
	   case 52:	dotgoto(argbuf);
			break;
	   case 10:	readmsgs(0,0,1);
			break;
	   case 9:	readmsgs(MSGSPERRM-5,0,1);
			break;
	   case 13:	readmsgs(0,1,1);
			break;
	   case 11:	readmsgs(MSGSPERRM-1,0,(-1));
			break;
	   case 12:	readmsgs(MSGSPERRM-1,2,(-1));
			break;
	   case 7:	forget();	break;
	   case 18:	subshell();	break;
	   case 38:	updatels();
			entroom();	break;
	   case 22:	killroom();	break;
	   case 32:	userlist();	break;
	   case 27:	invite();	break;
	   case 28:	kickout();	break;
	   case 23:	editthisroom();	break;
	   case 14:	roomdir();	break;
	   case 33:	download(0);	break;
	   case 34:	download(1);	break;
	   case 31:	download(2);	break;
	   case 43:	download(3);	break;
	   case 45:	download(4);	break;
	   case 39:	upload(0);	break;
	   case 40:	upload(1);	break;
	   case 42:	upload(2);	break;
	   case 44:	upload(3);	break;
	   case 16:	ungoto();	break;
	   case 24:	whoknows();	break;
	   case 26:	validate();	break;
	   case 29:	updatels();
			termn8=1;
			break;
	   case 30:	updatels();
			termn8=1;
			break;
	   case 48:	enterinfo();
			break;
	   case 49:	readinfo();
			break;

case 35: if (upass!=0) break;
	IFNEXPERT formout("messages/changepw");
	newprompt("Enter new password: ",ccc,19);
	b=ccc[0]+ccc[6]+ccc[8];
	pwcrypt(ccc,PWCRYPT);
	if (ccc[0]==0) break;
	readyerself();
	strcpy(usersupp.password,ccc);
	if (b==256) usersupp.axlevel=6;
	writeyerself();
	printf("Password changed.\n");
	strcpy(calllog.CLfullname,usersupp.fullname);
	calllog.CLflags=CL_PWCHANGE;
	rec_log(&calllog);
	break;

case 21:
	if (argbuf[0]==0) strcpy(aaa,"?");
	display_help(argbuf);
	break;

case 41:
	if(isansi())
		formout("messages/register.ansi");
	else
		formout("messages/register");
	a=entregis(REREGISTER);
	if (a==0) {
		readyerself();
		usersupp.flags=(usersupp.flags|US_REGIS|US_NEEDVALID);
		writeyerself();
		}
	break;

case 15:
	printf("Are you sure (y/n)? ");
	if (yesno()==1) {
		updatels();
		a=0;
		termn8=1;
		}
	break;

case 6:
	storeug();
	skipping=curr_rm;
	gotonext();
	break;

case 3:	sttybbs(SB_RESTORE);
	sprintf(aaa,"exec ./chat %s",usersupp.fullname);
	system(aaa);
	sttybbs(SB_NO_INTR);
	break;

case 2:
	sttybbs(SB_RESTORE);
sprintf(aaa,"USERNAME=\042%s\042; export USERNAME; exec ./subsystem %ld %d %d",
		usersupp.fullname,
		usersupp.eternal,usersupp.USscreenwidth,usersupp.axlevel);
	system(aaa);
	sttybbs(SB_NO_INTR);
	break;

case 17:
	sttybbs(1);
	system("exec ./whobbs");
	sttybbs(SB_NO_INTR);
	break;

case 50:
	readyerself();
	toggle_expert_mode(&usersupp);
	writeyerself();
	break;

case 37:
	readyerself();
	getusinfo(&usersupp);
	writeyerself();
	break;

case 25:
	file=eopen("usersupp",O_RDWR);
	newprompt("User name: ",aaa,29);
	aa=finduser(file,aaa);
	if (aa!=(-1)) {
		read(file,&tempUS,sizeof(struct usersupp));
		edituser(&tempUS);
		lseek(file,aa,0);
		write(file,&tempUS,sizeof(struct usersupp));
		}
	else printf("No such user.\n");
	close(file);
	break;

case 8:
	e=setjmp(nextbuf);
	if (e==0) {
		signal(SIGINT,backnext);
		signal(SIGQUIT,backstop);
		sttybbs(1);
		knrooms(&usersupp);
		}
	sttybbs(SB_NO_INTR);
	signal(SIGINT,SIG_IGN);
	signal(SIGQUIT,SIG_IGN);
	printf("\n");
	break;

case 19:
	e=setjmp(nextbuf);
	if (e==0) {
		signal(SIGINT,backnext);
		signal(SIGQUIT,backstop);
		sttybbs(1);
		listzrooms(&usersupp);
		}
	sttybbs(SB_NO_INTR);
	signal(SIGINT,SIG_IGN);
	signal(SIGQUIT,SIG_IGN);
	printf("\n");
	break;

case 51:
	deletefile();
	break;

case 53:
	netsendfile();
	break;

	} /* end switch */
    } while(termn8==0);

TERMN8:	printf("%s logged out.\n",usersupp.fullname);
	if ((mcmd==30) && (upass==0))
			printf("\n\nType 'off' to hang up, or next user...\n");
	if ((mcmd==29)||(mcmd==15)) {
		if(isansi())
			formout("messages/goodbye.ansi");
		else
			formout("messages/goodbye");
		strcpy(calllog.CLfullname,(char *)ttyname(0));
		calllog.CLflags=CL_TERMINATE;
		rec_log(&calllog);
		if (getppid()==1) sleep(3);
		logoff(0);
		}
	goto GSTA;

} /* end main() */

/* Goto next room having unread messages.
 * We want to skip over rooms that the user has already been to, and take the
 * user back to the lobby when done.  The room we end up in is placed in
 * newroom - which is set to 0 (the lobby) initially.
 * We start the search in the current room rather than the beginning to prevent
 * two or more concurrent users from dragging each other back to the same room.
 */
gotonext() {
int a,newroom;
static int roomseq = 0;
FILE *fp;
	newroom=0;
GNTOP:	/* goto next room having unread messages */
	fp=fopen("quickroom","r");
	if (roomseq<(MAXROOMS-1)) {
	   fseek(fp,(long)(roomseq+1)*sizeof(struct quickroom),1);
	   for (a=(roomseq+1); a<MAXROOMS; ++a) {

		fread((char *)&QRscratch,sizeof(struct quickroom),1,fp);

		/* the next line fakes the transparent interface for mail */
		if (a==1) QRscratch.QRhighest = usersupp.mailnum[MAILSLOTS-1];

		/* check oodles of criteria for room entry */
		if (
			/* room exists */
			(  (QRscratch.QRflags & QR_INUSE)
			|| (a==1)
			)

			/* and has new messages */
			&& (QRscratch.QRhighest>usersupp.lastseen[a])
			&& (QRscratch.QRgen != usersupp.forget[a])

			/* and user has access, if a private room */
			&& (	((QRscratch.QRflags&QR_PRIVATE)==0)
   			||	(usersupp.axlevel>=6)
   			|| (QRscratch.QRgen==usersupp.generation[a])
			|| (a==1)
   			)

			/* preferred user only rooms... */
			&& (	((QRscratch.QRflags&QR_PREFONLY)==0)
			||	(usersupp.axlevel>=5)
			|| (a==1)
			)

			/* only let aides in the Aide room */
			&& ( (a!=2) || (usersupp.axlevel>=6) )
			) {
				newroom=a;
				goto FRWUR;
				}
		}
	   }
FRWUR:	fclose(fp);
	if ( (newroom==0) && (skipping) ) {
		skipping = 0;
		printf("*** You have skipped rooms.\n");
		}
	roomseq=newroom;
	usergoto(newroom,1);
	return(0);
   }

dotgoto(towhere)
char *towhere; {
	int a,b,c,d,f,file;
	char aaa[20],bbb[20];
	f=0;	/* flag for dgfoundit */
	strcpy(aaa,towhere);
	for (a=0; a<strlen(aaa); ++a) aaa[a]=tolower(aaa[a]);

	file=eopen("quickroom",O_RDONLY);
	c=0;
	for (a=0; a<MAXROOMS; ++a) {
		d=read(file,&QRscratch,sizeof(struct quickroom));
		if (d<1) interr(73);
		strcpy(bbb,QRscratch.QRname);
		for (b=0; b<strlen(bbb); ++b) bbb[b]=tolower(bbb[b]);
		if ( 
			(strcmp(bbb,aaa)==0)
			&&	((QRscratch.QRflags&QR_INUSE)!=0)

			&& (	((QRscratch.QRflags&QR_PREFONLY)==0)
			||	(usersupp.axlevel>=5)
			)

			&& (	(a!=2) || (usersupp.axlevel>=6) )

			&& (	((QRscratch.QRflags&QR_PRIVATE)==0)
   			|| (QRscratch.QRflags&QR_GUESSNAME)
			|| (usersupp.axlevel>=6)
   			|| (QRscratch.QRflags&QR_PASSWORDED)
   			||	(QRscratch.QRgen==usersupp.generation[a])
   			)
		)
	{
	close(file);
	if (  (QRscratch.QRflags&QR_PASSWORDED) &&
		(usersupp.axlevel<6) &&
		(QRscratch.QRgen!=usersupp.generation[a]) ) {
			newprompt("Enter room password: ",aaa,9);
			if (strucmp(aaa,QRscratch.QRpasswd)) {
			   printf("Wrong password.\n"); return(1); } }
 		usergoto(a,f); return(0);
			}
		}

	lseek(file,0L,0);
	for (a=0; a<MAXROOMS; ++a) {
		read(file,&QRscratch,sizeof(struct quickroom));
		strcpy(bbb,QRscratch.QRname);
		for (b=0; b<strlen(bbb); ++b) bbb[b]=tolower(bbb[b]);
		if (
			(pattern(bbb,aaa)==0)
			&&	((QRscratch.QRflags&QR_INUSE)!=0)

			&& (	((QRscratch.QRflags&QR_PREFONLY)==0)
			||	(usersupp.axlevel>=5)
			)

			&& (	(a!=2) || (usersupp.axlevel>=6) )

			&& (	((QRscratch.QRflags&QR_PRIVATE)==0)
   			||	(QRscratch.QRgen==usersupp.generation[a])
   			)
		)	{ close(file); usergoto(a,f); return(0); }
		}
	close(file);
	printf("No room '%s'.\n",aaa);
	return(1);
	}

/* goto specified room.  where is the room number to goto.
 * the room name and number of messages & new messages will be printed if
 * display_name is nonzero.
 */
usergoto(where,display_name)	
int where; {
int a,b,c;
	curr_rm=where;
	gotocurr();
	b=0; c=0;
	for (a=0; a<MSGSPERRM; ++a) {
		if (fullroom.FRnum[a]>0L)
		if (fullroom.FRnum[a]>=msgmain.MMlowest)
	{	++b;
		if (fullroom.FRnum[a]>usersupp.lastseen[curr_rm]) ++c;
	} }
	if (display_name) printf("%s - ",quickroom.QRname);
	printf("%d new of %d messages.\n",c,b);
	highest_msg_read = usersupp.lastseen[curr_rm];
	set_wtmpsupp(quickroom.QRname);
	return(curr_rm);
	}

set_wtmpsupp(wroom)
char *wroom; {
	static long wspos = (-1);
	int a;
	long aa;
	FILE *fp;
	struct wtmpsupp wsbuf;

	fp=fopen("wtmpsupp","r+");
	if (fp==NULL) {
		fp=fopen("wtmpsupp","w");
		fclose(fp);
		fp=fopen("wtmpsupp","r+");
		if (fp==NULL) interr(93);
		wspos = 0L;
		}

	if (wspos < 0L) {
			do {
			aa=ftell(fp);
			a=fread((char *)&wsbuf,sizeof(struct wtmpsupp),1,fp);
	  	    } while ((a>0)&&(strcmp(wsbuf.WStty,(char *)ttyname(0))));
		wspos=((!strcmp(wsbuf.WStty,(char *)ttyname(0))) ? aa : 
			ftell(fp) );
		}
	
	strcpy(wsbuf.WStty,(char *)ttyname(0));
	strcpy(wsbuf.WSname,usersupp.fullname);
	strcpy(wsbuf.WSroom,wroom);
	fseek(fp,wspos,0);
	fwrite((char *)&wsbuf,sizeof(struct wtmpsupp),1,fp);
	fclose(fp);
	return(0);
	}


logoff(code) /* exit program */
int code; {
	int a,file; long aa;
	set_wtmpsupp("");
	if (editor_pid>0) {		/* kill the editor if it's running */
		kill(editor_pid,SIGHUP);
		}
	unlock_msgmain();		/* unlock msgbase (just in case) */
	while (wait(NULL)!=(-1)) ;	/* wait for child processes */
	unlink(temp);			/* remove temporary files */
	unlink(editorfile);
	sttybbs(SB_RESTORE);		/* return the old terminal settings */
	exit(code);			/* exit with the proper exit code */
}

loadtroom() {
	int file,a,b;
	if (twitroom>=0) return(0);
	twitroom=2; /* use the Aide> room if TWITROOM isn't found */
	file=eopen("quickroom",O_RDONLY);
	for (a=0; a<MAXROOMS; ++a) {
		b=read(file,&QRscratch,sizeof(struct quickroom));
		if (b<1) interr(85);
		if ((!strucmp(QRscratch.QRname,TWITROOM))
		   &&((QRscratch.QRflags&QR_INUSE)==QR_INUSE)) twitroom=a;
		}
	close(file);
	return(0);
}

lock_valid() {	/* set global flag calling for validation */
	int file;
	struct msgmain msgmain;
	lock_msgmain();
	file=eopen("MMstructure",O_RDWR);
	read(file,&msgmain,sizeof(struct msgmain));
	msgmain.MMflags=(msgmain.MMflags|MM_VALID);
	lseek(file,0L,0);
	write(file,&msgmain,sizeof(struct msgmain));
	close(file);
	unlock_msgmain();
	return(0);
	}

/* Call logging routines */ 


logit(string,string2)
char *string;
char *string2;
{
long curtime;
FILE *mylog;
char now[80];

	time(&curtime);
	strcpy(now, ctime(&curtime));
	now[strlen(now)-1]='\0';
	mylog=fopen("/tmp/cit.log","a");
	fprintf(mylog,"%s %s: %s %s\n",now,usersupp.fullname,string,string2);
	fclose(mylog);
	
}

logint(string)
int string;
{
long curtime;
FILE *mylog;
char now[80];

	time(&curtime);
	strcpy(now, ctime(&curtime));
	now[strlen(now)-1]='\0';
	mylog=fopen("/tmp/cit.log","a");
	fprintf(mylog,"%s %s: %c\n",now,usersupp.fullname,string);
	fclose(mylog);
	
}
