[alt.sources] cit301.part8

eric@sactoh0.SAC.CA.US (Eric J. Nihill) (11/26/90)

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	source
# This archive created: Sun Nov 25 13:00:34 1990
export PATH; PATH=/bin:/usr/bin:$PATH
if test ! -d 'source'
then
	echo shar: "creating directory 'source'"
	mkdir 'source'
fi
echo shar: "entering directory 'source'"
cd 'source'
echo shar: "extracting 'readlog.c'" '(2176 characters)'
if test -f 'readlog.c'
then
	echo shar: "will not over-write existing file 'readlog.c'"
else
cat << \SHAR_EOF > 'readlog.c'
#include <fcntl.h>
#include <time.h>
#include "citadel.h"

long lseek();

main(argc,argv)
int argc;
char *argv[]; {
	struct calllog calllog;
	int file,pos,a;
	char aaa[100];
	struct tm *tm;
	char *tstring;

	file=open("calllog.pos",O_RDONLY);
	read(file,&pos,2);
	close(file);

	file=open("calllog",O_RDONLY);
	if (!strcmp(argv[1],"-t")) last20(file,(long)pos);
else {
	lseek(file,(long)(pos*sizeof(struct calllog)),0);
	for (a=0; a<CALLLOG; ++a) {
		if ((a+pos)==CALLLOG) lseek(file,0L,0);
		read(file,&calllog,sizeof(struct calllog));
	if (calllog.CLflags!=0) {
		strcpy(aaa,"");
		if (calllog.CLflags&CL_IN300)	strcpy(aaa,"Connect 300");
		if (calllog.CLflags&CL_IN1200)	strcpy(aaa,"Connect 1200");
		if (calllog.CLflags&CL_IN2400)	strcpy(aaa,"Connect 2400");
		if (calllog.CLflags&CL_INOTHER)	strcpy(aaa,"Console/Other");
		if (calllog.CLflags&CL_LOGIN)	strcpy(aaa,"Login");
		if (calllog.CLflags&CL_NEWUSER)	strcpy(aaa,"New User");
		if (calllog.CLflags&CL_BADPW)	strcpy(aaa,"Bad PW Attempt");
		if (calllog.CLflags&CL_TERMINATE) strcpy(aaa,"Terminate");
		if (calllog.CLflags&CL_DROPCARR) strcpy(aaa,"Dropped Carrier");
		if (calllog.CLflags&CL_SLEEPING) strcpy(aaa,"Sleeping");
		tm=(struct tm *)localtime(&calllog.CLtime);
		tstring=(char *)asctime(tm);
		printf("%30s %20s %s",calllog.CLfullname,aaa,tstring);
		}
		}
	}
	close(file);
	exit(0);
}
	
last20(file,pos)
int file;
long pos;
	{
	int a,count;
	long aa;
	struct calllog calllog;
	struct calllog listing[20];
	struct tm *tm;
	char *tstring;
	
	count=0;
	for (a=0; a<20; ++a) {
		listing[a].CLfullname[0]=0;
		listing[a].CLtime=0L;
		listing[a].CLflags=0;
		}
	aa=pos-1;
	while(count<20) {
		if (aa<0L) aa=CALLLOG;
		lseek(file,(aa*sizeof(struct calllog)),0);
		read(file,&calllog,sizeof(struct calllog));
		if (calllog.CLflags==CL_LOGIN) {
			strcpy(listing[count].CLfullname,calllog.CLfullname);
			listing[count].CLtime=calllog.CLtime;
			listing[count].CLflags=calllog.CLflags;
			++count;
			}
		if (aa==pos) break;
		aa=aa-1;
		}
	for (a=19; a>=0; --a) {
		tm=(struct tm *)localtime(&listing[a].CLtime);
		tstring=(char *)asctime(tm);
		printf("%30s %s",listing[a].CLfullname,tstring);
		}
	return(0);
}
SHAR_EOF
fi
echo shar: "extracting 'rmail.c'" '(7699 characters)'
if test -f 'rmail.c'
then
	echo shar: "will not over-write existing file 'rmail.c'"
else
cat << \SHAR_EOF > 'rmail.c'
/*
	Citadel/UX uucp mail reciever
	Version 2.10, January 1989

This is just a quick hack I threw together to enable BBS users
to recieve mail through the uucp mail facility. Move rmail to rmail.real
and compile this program as rmail.
   
  New change: mail can now be recieved by user number, i.e. sysname!cit123
  
  This program looks at the recipient to determine if he/she is a bbs user. It
falls back on the old mailer if:
  
  1. The program is called with less or more than one argument
  2. The recipient is not someone in the BBS user file
     (so users who are in /etc/passwd can still recieve mail)
  3. The recipient name contains ! or @ characters
     (so it doesn't try to mail something that really should be sent
     out of the system via uucp)

 Generally, this program will require a bit of hacking before it will run
on your system. If you have any questions, call UNCENSORED! BBS at
(914) 761-6877. Good luck...

*/
  
#include <fcntl.h>
#include <stdio.h>
#include <ctype.h>
#include "/usr/bbs/citadel.h"

long lseek();
long atol();

long finduser(file,name)
int file;
char name[];
{
	struct usersupp temp;
	int a;
	long bottom,top,guess,obottom,otop;

	obottom=(-1L); otop=(-1L);

	bottom=0L;
	top=(lseek(file,0L,2)/(long)sizeof(struct usersupp));

FPT:	if ((obottom==bottom)&&(otop==top)) {
		return(-1L); }
	obottom=bottom; otop=top;
	guess=(((top-bottom)/2)+bottom);
	lseek(file,(guess*(long)sizeof(struct usersupp)),0);
	read(file,&temp,sizeof(struct usersupp));
	a=strucmp(temp.fullname,name);
	if (a==0)
		
		return(lseek(file,(guess*(long)sizeof(struct usersupp)),0));
	if (a<0) {
		bottom=guess;
		goto FPT; }
	if (a>0) {
		top=guess;
		goto FPT; }
}
send_message(filename,retbuf)	/* send a message to the master file */
char filename[];		/* tempfilename of proper message */
struct smreturn *retbuf;	/* return information */
{

int file,a,b,c,d,e,file2;
long aa,bb,cc,dd,ee,templen,hibytes,origpos;
char aaa[100];
struct msgmain msgmain;


	file=open("/usr/bbs/MMstructure",O_RDWR);
	if (file<0) exit(13);
PWMINS:
	a=read(file,&msgmain,sizeof(struct msgmain));
	if (a<1) exit(14);
	if (msgmain.MMflags & MM_BUSY) {
					 lseek(file,0L,0); goto PWMINS; }

	lseek(file,0L,0);
	msgmain.MMflags=(msgmain.MMflags|MM_BUSY);
	a=write(file,&msgmain,sizeof(struct msgmain)); if (a<1) exit(16);
	close(file);
	origpos=msgmain.MMcurpos;

/* measure the message */
file=open(filename,O_RDONLY); if (file<0) exit(17);
templen=lseek(file,0L,2);
close(file);

/* check for FF bytes */
hibytes=0L;
file=open("/usr/bbs/msgmain",O_RDWR);
if (file<0) exit(18);
bb=lseek(file,msgmain.MMcurpos,0);

cc=lseek(file,0L,1);
for (bb=0L; bb<templen; ++bb) {
	if (cc>=MM_FILELEN) cc=lseek(file,0L,0);
	c=0; read(file,&c,1); ++cc;
	if (c>127) ++hibytes;		/* bump count if hi bit set */
	}

msgmain.MMlowest=msgmain.MMlowest+hibytes;
++msgmain.MMhighest;

cc=lseek(file,msgmain.MMcurpos,0);

file2=open(filename,O_RDONLY); if (file2<0) exit(19);
cc=lseek(file,0L,1);
for (bb=0L; bb<templen; ++bb) {
	if (((long)cc)>=((long)MM_FILELEN)) cc=lseek(file,0L,0);
	read(file2,&b,1); 
	write(file,&b,1); ++cc;
	}
msgmain.MMcurpos=lseek(file,0L,1);
close(file2);	/* done with temp file */
close(file);	/* done with master file */


/* now update the message structure */

msgmain.MMflags=msgmain.MMflags & ~MM_BUSY;

file=open("/usr/bbs/MMstructure",O_RDWR); if (file<0) exit(20);
a=write(file,&msgmain,sizeof(struct msgmain)); if (a<1) exit(21);
close(file);

retbuf->smnumber=msgmain.MMhighest;
retbuf->smpos=origpos;



return(0);

}

make_message(filename,recipient)
char filename[];	/* temporary file name */
char recipient[];	/* NULL if it's not mail */
{ 
	char author[300];
	FILE *fp;
	int a,b,c,old;
	long aa,bb,cc,beg,now;
	char aaa[300],bbb[300];

	strcpy(author,"UUCP Mailer");
	strcpy(aaa,"");
	gets(aaa);
	if (strncmp(aaa,"From ",5)) goto NOFRM;
	strcpy(aaa,&aaa[5]);
	strcpy(bbb,"somewhere");
	for (a=0; a<strlen(aaa); ++a)
		if (!strncmp(&aaa[a],"remote from ",12)) {
			strcpy(bbb,&aaa[a+12]);
			aaa[a]=0;
			}
	for (a=0; a<strlen(aaa); ++a) if (aaa[a]==32) aaa[a]=0;
	strcat(bbb,"!");
	strcat(bbb,aaa);
	strcpy(author,bbb);
	aaa[0]=0;

NOFRM:	time(&now);
	fp=fopen(filename,"wb"); if (fp==NULL) exit(22);
	putc(255,fp);
	putc(MES_NORMAL,fp);
	putc(1,fp);
	fprintf(fp,"T%ld",now); putc(0,fp);
	fprintf(fp,"A%s",author); putc(0,fp);
	if (recipient[0]!=0) { fprintf(fp,"R%s",recipient); putc(0,fp); }
	fprintf(fp,"OMail"); putc(0,fp);
	fprintf(fp,"N%s",NODENAME); putc(0,fp);
	putc('M',fp);
	if (aaa[0]!=0) fprintf(fp,"%s\n",aaa);
	do {
		a=getc(stdin);
		if (a>0) putc(a,fp);
		} while(a>0);

MEFIN:	putc(0,fp);
	fclose(fp);
	return(0);

}

strucmp(st1,st2)
char st1[],st2[];
{
	int a;
	char aaa[100],bbb[100];
	for (a=0; a<=strlen(st1); ++a) aaa[a]=tolower(st1[a]);
	for (a=0; a<=strlen(st2); ++a) bbb[a]=tolower(st2[a]);
	a=strcmp(aaa,bbb);
	return(a);
}

main(argc,argv)
int argc;
char *argv[];
{
	int a,file;
	long aa;
	char aaa[100],temp[20];
	struct usersupp usersupp;
	struct smreturn smreturn;
	struct quickroom quickroom;
	struct fullroom fullroom;
	
	sprintf(temp,"/tmp/rmail.%d",getpid());
	goto TRY;
GIVEUP:	execv("/usr/bin/rmail.real",argv);
	exit(1);

TRY:	if (argc!=2) goto GIVEUP;
	strcpy(aaa,argv[1]);
	for (a=0; a<strlen(aaa); ++a) {
		if ((aaa[a]=='!')||(aaa[a]=='@')) goto GIVEUP;
		if (aaa[a]=='_') aaa[a]=32;
		}
	check4n(aaa);
	alias(aaa);
	if (strucmp(aaa,"sysop")) {
		file=open("/usr/bbs/usersupp",O_RDWR);
		if (file<0) goto GIVEUP;
		aa=finduser(file,aaa);
		if (aa==(-1L)) {
			close(file);
			goto GIVEUP;
			}
		}
	make_message(temp,aaa);
	send_message(temp,&smreturn);
	if (strucmp(aaa,"sysop")) {
		aa=finduser(file,aaa);
		read(file,&usersupp,sizeof(struct usersupp));
		for (a=0; a<(MAILSLOTS-1); ++a) {
			usersupp.mailnum[a]=usersupp.mailnum[a+1];
			usersupp.mailpos[a]=usersupp.mailpos[a+1];
			}
		usersupp.mailnum[MAILSLOTS-1]=smreturn.smnumber;
		usersupp.mailpos[MAILSLOTS-1]=smreturn.smpos;
		aa=finduser(file,aaa);
		write(file,&usersupp,sizeof(struct usersupp));
		close(file);
		}

	else {	/* file it in Aide> */
		file=open("/usr/bbs/quickroom",O_RDWR);
		lseek(file,(long)(2*sizeof(struct quickroom)),0);
		read(file,&quickroom,sizeof(struct quickroom));
		quickroom.QRhighest=smreturn.smnumber;
		lseek(file,(long)(2*sizeof(struct quickroom)),0);
		write(file,&quickroom,sizeof(struct quickroom));
		close(file);
		
		file=open("/usr/bbs/rooms/fullrm2",O_RDWR);
		read(file,&fullroom,sizeof(struct fullroom));
		for (a=0; a<(MSGSPERRM-1); ++a) {
			fullroom.FRnum[a]=fullroom.FRnum[a+1];
			fullroom.FRpos[a]=fullroom.FRpos[a+1];
			}
		fullroom.FRnum[MSGSPERRM-1]=smreturn.smnumber;
		fullroom.FRpos[MSGSPERRM-1]=smreturn.smpos;
		lseek(file,0L,0);
		write(file,&fullroom,sizeof(struct fullroom));
		close(file);
		}
	
	unlink(temp);
	exit(0);
}

alias(name)
char name[]; {
	FILE *fp;
	int a,b;
	char aaa[50],bbb[50];
	
	fp=fopen("/usr/bbs/network/mail.aliases","r");
	if (fp==NULL) return(2);
GNA:	strcpy(aaa,""); strcpy(bbb,"");
	do {
		a=getc(fp);
		if (a==',') a=0;
		if (a>0) { b=strlen(aaa); aaa[b]=a; aaa[b+1]=0; }
		} while(a>0);
	do {
		a=getc(fp);
		if (a==10) a=0;
		if (a>0) { b=strlen(bbb); bbb[b]=a; bbb[b+1]=0; }
		} while(a>0);
	if (a<0) {
		fclose(fp);
		return(1);
		}
	if (strucmp(name,aaa)) goto GNA;
	fclose(fp);
	strcpy(name,bbb);
	return(0);
}

check4n(name)
char name[]; {
	struct usersupp usersupp;
	int a,file;
	
	if ((strncmp(name,"cit",2))||(atol(&name[3])==0L)) return(0);

	file=open("/usr/bbs/usersupp",O_RDONLY);
	while (read(file,&usersupp,sizeof(struct usersupp))>0) {
		if (usersupp.eternal==atol(&name[3])) {
			strcpy(name,usersupp.fullname);
			goto CLCN;
			}
		}
CLCN:	close(file);
	return(0);
}
SHAR_EOF
fi
echo shar: "extracting 'rnews.c'" '(4125 characters)'
if test -f 'rnews.c'
then
	echo shar: "will not over-write existing file 'rnews.c'"
else
cat << \SHAR_EOF > 'rnews.c'
/* Citadel/UX rnews
 * version 1.02
 *
 * This program functions the same as the standard rnews program for
 * UseNet. It accepts standard input, and looks for rooms to post messages
 * in that match the names of the newsgroups. network/rnews.xref is checked
 * in case the sysop wants to cross-reference room names to newsgroup names.
 *   The netproc program is required for final processing.
 * 
 * usage:
 *          rnews        <stdin is translated to Cit/UX format and posted>
 *          rnews -c     <assumes stdin is already in Cit/UX format and posts>
 */

#include <fcntl.h>
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include "citadel.h"

long lseek();
long atol();

main(argc,argv)
int argc;
char *argv[]; {
	char aaa[100],bbb[100],ccc[100];
	char author[50],recipient[50],room[50],node[50],path[300];
	long mid,now,bcount,aa;
	int a;
	char flnm[100],tname[100];
	FILE *mout,*mtemp;

	chdir(BBSDIR);
	sprintf(flnm,"./network/spoolin/rnews.%d",getpid());
	sprintf(tname,"/tmp/rnews.%d",getpid());

	mout=fopen(flnm,"w");
	if ((argc==2)&&(!strcmp(argv[1],"-c"))) {
		while ((a=getc(stdin))>=0) putc(a,mout);
		goto END;
		}
A:	a=getline(aaa,stdin);
	if (a<0) goto END;
	if (strncmp(aaa,"#! rnews ",9)) goto A;
	bcount=atol(&aaa[9]);
	mtemp=fopen(tname,"w");
	for (aa=0L; aa<bcount; ++aa) {
		a=getc(stdin);
		if (a<0) goto NMA;
		if (a>=0) putc(a,mtemp);
		}
NMA:	fclose(mtemp);
	if (a<0) goto END;

	mtemp=fopen(tname,"r");
	strcpy(author,"");
	strcpy(recipient,"");
	strcpy(room,"");
	strcpy(node,"");
	strcpy(path,"");

B:	a=getline(aaa,mtemp);
	if (a==0) goto C;
	if (a<0) goto ABORT;

	if (!strncmp(aaa,"From: ",5)) {
		while((aaa[0]!='(')&&(aaa[0]!=0)) {
			strcpy(&aaa[0],&aaa[1]);
			}
		strcpy(&aaa[0],&aaa[1]);
		for (a=0; a<strlen(aaa); ++a) if (aaa[a]==')') aaa[a]=0;
		strcpy(author,aaa);
		goto B;
		}

	if (!strncmp(aaa,"Path: ",5)) strcpy(path,&aaa[6]);

	if (!strncmp(aaa,"Newsgroups: ",11)) {
		strcpy(room,&aaa[12]);
		for (a=0; a<strlen(aaa); ++a) if (aaa[a]==',') aaa[a]=0;
		goto B;
		}

	if (!strncmp(aaa,"Message-ID: ",11)) {
		strcpy(bbb,&aaa[13]);
		for (a=0; a<strlen(bbb); ++a) if (bbb[a]=='@') bbb[a]=0;
		mid=atol(bbb);
		while((aaa[0]!='@')&&(aaa[0]!=0)) {
			strcpy(&aaa[0],&aaa[1]);
			}
		strcpy(&aaa[0],&aaa[1]);
for (a=0; a<strlen(aaa); ++a) if ((aaa[a]=='.')||(aaa[a]=='>')) aaa[a]=0;
		strcpy(node,aaa);
		goto B;
		}
		goto B;

C:	if ((author[0]==0)||(room[0]==0)||(node[0]==0)) goto ABORT;
	putc(255,mout);			/* start of message */
	putc(MES_NORMAL,mout);		/* not anonymous */
	putc(1,mout);			/* not formatted */
	time(&now);

	fprintf(mout,"I%ld",mid); putc(0,mout);
	fprintf(mout,"P%s",path); putc(0,mout);
	fprintf(mout,"T%ld",now); putc(0,mout);
	fprintf(mout,"A%s",author); putc(0,mout);
	strcpy(ccc,room);
	getroom(room,ccc);
	fprintf(mout,"O%s",room); putc(0,mout);
	fprintf(mout,"N%s",node); putc(0,mout);
	fprintf(mout,"M");
	a=0;
	aaa[0]=0;

D:	do {
		a=getc(mtemp);
		if (a>0) putc(a,mout);
		} while (a>0);
	putc(0,mout);
ABORT:	pclose(mtemp);
	unlink(tname);
	goto A;

END:	putc(0,mout);
	fclose(mout);
	unlink(tname);
	execlp("netproc","netproc",NULL);
	exit(0);
}

strucmp(st1,st2)
char st1[];
char st2[]; {
	int a;
	char aaa[100],bbb[100];
	for (a=0; a<=strlen(st1); ++a) aaa[a]=tolower(st1[a]);
	for (a=0; a<=strlen(st2); ++a) bbb[a]=tolower(st2[a]);
	a=strcmp(aaa,bbb);
	return(a);
	}

getroom(room,ngroup)		/* xref table */
char room[]; 
char ngroup[]; {
	FILE *fp;
	int a,b;
	char aaa[50],bbb[50];
	
	strcpy(room,ngroup);
	fp=fopen("network/rnews.xref","r");
GNA:	strcpy(aaa,""); strcpy(bbb,"");
	do {
		a=getc(fp);
		if (a==',') a=0;
		if (a>0) { b=strlen(aaa); aaa[b]=a; aaa[b+1]=0; }
		} while(a>0);
	do {
		a=getc(fp);
		if (a==10) a=0;
		if (a>0) { b=strlen(bbb); bbb[b]=a; bbb[b+1]=0; }
		} while(a>0);
	if (a<0) {
		fclose(fp);
		return(1);
		}
	if (strucmp(ngroup,aaa)) goto GNA;
	fclose(fp);
	strcpy(room,bbb);
	return(0);
}

getline(str,fp)
char str[];
FILE *fp; {
	int a,b;

	a=0;
	str[0]=0;
	do {
		a=getc(fp);
		if (a>10) { b=strlen(str); str[b]=a; str[b+1]=0; }
		} while(a>10);
	if (a<0) return(a);
	return(strlen(str));
	}
SHAR_EOF
fi
echo shar: "extracting 'rooms.c'" '(15734 characters)'
if test -f 'rooms.c'
then
	echo shar: "will not over-write existing file 'rooms.c'"
else
cat << \SHAR_EOF > 'rooms.c'
/* Citadel/UX room-oriented routines */

#include <fcntl.h>
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <pwd.h>
#include <setjmp.h>
#include <termio.h>
#include "citadel.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)

long atol();
long lseek();
long finduser();

extern int curr_rm;
extern int ugnum;
extern long uglsn;
extern struct quickroom quickroom;
extern struct usersupp usersupp;
extern struct fullroom fullroom;

knrooms(USgiven)
struct usersupp *USgiven;
{
	int a,b,c,d,file;
	struct quickroom QRscratch;

	b=1;
	printf("\n   Rooms with unread messages:\n");
	file=open("./quickroom",O_RDONLY); if (file<0) return(1);
	for (a=0; a<MAXROOMS; ++a) {
		c=read(file,&QRscratch,sizeof(struct quickroom));
		if (c<1) interr(58);
		if (a==1) QRscratch.QRhighest=USgiven->mailnum[MAILSLOTS-1];
		d=b+strlen(QRscratch.QRname)+3;
		if ((QRscratch.QRflags & QR_INUSE)
			&& (QRscratch.QRhighest> (USgiven->lastseen[a]) )
			&& ( (a!=2) || (USgiven->axlevel>=6))
			&& (QRscratch.QRgen != (USgiven->forget[a]) )

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

			&& (	((QRscratch.QRflags&QR_PRIVATE)==0)
   			||	((USgiven->axlevel)>=6)
   			||	(QRscratch.QRgen==(USgiven->generation[a]))
   			)

		) {
		if (d>=(USgiven->screenwidth)) {
			printf("\n"); b=1; }
		c=room_prompt(&QRscratch);
		printf("%s%c  ",QRscratch.QRname,c);
		b=b+strlen(QRscratch.QRname)+3;
		}
	} 
	if (b!=1) printf("\n");

	b=1;
	printf("\n   No unseen messages in:\n");
	lseek(file,0L,0);
	for (a=0; a<MAXROOMS; ++a) {
		c=read(file,&QRscratch,sizeof(struct quickroom));
		if (c<1) return(1);
		if (a==1) QRscratch.QRhighest=USgiven->mailnum[MAILSLOTS-1];
		if ((QRscratch.QRflags & QR_INUSE)
			&& (QRscratch.QRhighest<=USgiven->lastseen[a])
			&& ( (a!=2) || ((USgiven->axlevel)>=6))
			&& (QRscratch.QRgen != USgiven->forget[a])

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

			&& (	((QRscratch.QRflags&QR_PRIVATE)==0)
   			||	((USgiven->axlevel)>=6)
   			||	(QRscratch.QRgen==USgiven->generation[a])
   			)

		) {
		d=strlen(QRscratch.QRname)+3+b;
		if (d>=(USgiven->screenwidth)) {
			printf("\n"); b=1; }
		c=room_prompt(&QRscratch);
		printf("%s%c  ",QRscratch.QRname,c);
		b=b+strlen(QRscratch.QRname)+3;
		}
	}
	if (b!=1) printf("\n");

	close(file);
	return(0);
}

listzrooms(USgiven)		/* list public forgotten rooms */
struct usersupp *USgiven;
{
	int a,b,c,d,file;
	struct quickroom QRscratch;

	b=1;
	printf("\n   Forgotten public rooms:\n");
	file=open("./quickroom",O_RDONLY); if (file<0) return(1);
	for (a=0; a<MAXROOMS; ++a) {
		c=read(file,&QRscratch,sizeof(struct quickroom));
		if (c<1) interr(58);
		if (a==1) QRscratch.QRhighest=USgiven->mailnum[MAILSLOTS-1];
		if ((QRscratch.QRflags & QR_INUSE)
			&& (QRscratch.QRgen == (USgiven->forget[a]) )
			&& ( (a!=2) || ((USgiven->axlevel)>=6))
			&& (	((QRscratch.QRflags&QR_PRIVATE)==0)
   			||	((USgiven->axlevel)>=6)
   			||	(QRscratch.QRgen==(USgiven->generation[a]))
   		)
		) {
		d=b+strlen(QRscratch.QRname)+3;
		if (d>=(USgiven->screenwidth)) {
			printf("\n"); b=1; }
		c=room_prompt(&QRscratch);
		printf("%s%c  ",QRscratch.QRname,c);
		b=b+strlen(QRscratch.QRname)+3;
		}
	} 
	if (b!=1) printf("\n");
	close(file);
	return(0);
}

editroom() {	/* .<A>ide <E>dit room */
	int file,file2,a,b;
	char aaa[50]; long aa;
	struct usersupp tempUS;

	if (curr_rm<3) {
		printf("Can't edit this room.\n");
		return(0);
		}
	file=open("quickroom",O_RDWR);
	if (file<0) interr(34);
	lseek(file,(long)(curr_rm*sizeof(struct quickroom)),0);
	a=read(file,&quickroom,sizeof(struct quickroom));
	if (a<1) interr(35);
	printf("Room name is currently: %s\n",quickroom.QRname);
	printf("New name <return=same>? ");
	getline(aaa,19);
	if (aaa[0]!=0) strcpy(quickroom.QRname,aaa);
	printf("This is currently a");
	if ((quickroom.QRflags&QR_PRIVATE)==0) printf(" public");
	if (quickroom.QRflags&QR_PRIVATE) printf(" private");
	if (quickroom.QRflags&QR_PASSWORDED) printf(", passworded");
	if (quickroom.QRflags&QR_GUESSNAME) printf(", guessname");
	printf(" room");
	if ((quickroom.QRflags&QR_PASSWORDED)==QR_PASSWORDED)
			printf(", password: %s",quickroom.QRpasswd);
	printf(".\n");
if (quickroom.QRflags&QR_PREFONLY) printf("PREFERRED USERS ONLY.\n");
if (quickroom.QRflags&QR_DIRECTORY) {
	printf("Directory room");
	if (quickroom.QRflags&QR_UPLOAD) printf(", uploading allowed");
	if (quickroom.QRflags&QR_DOWNLOAD) printf(", downloading allowed");
	if (quickroom.QRflags&QR_VISDIR) printf(", visible directory");
	printf(".\nDirectory name: %s\n",quickroom.QRdirname); }
if (quickroom.QRflags&QR_ANONONLY)
	printf("Anonymous-only room.\n");

quickroom.QRflags=(quickroom.QRflags|QR_PRIVATE|QR_PASSWORDED|QR_GUESSNAME);
quickroom.QRflags=(quickroom.QRflags|QR_DIRECTORY|QR_UPLOAD|QR_DOWNLOAD);
quickroom.QRflags=(quickroom.QRflags|QR_VISDIR|QR_ANONONLY);
quickroom.QRflags=(quickroom.QRflags|QR_ANON2|QR_NETWORK|QR_PREFONLY);
	printf("New room type? <1>pub <2>guessname <3>passwd <4>inv-only : ");
	do {
		b=inkey()-48;
		} while ((b<1)||(b>4));
	printf("%d\n",b);
	if (b!=2) quickroom.QRflags=(quickroom.QRflags-QR_GUESSNAME);
	if (b!=3) quickroom.QRflags=(quickroom.QRflags-QR_PASSWORDED);
	if (b==1) quickroom.QRflags=(quickroom.QRflags-QR_PRIVATE);
	if ((quickroom.QRflags&QR_PASSWORDED)==QR_PASSWORDED) {
		printf("<return> or new password: ");
		getline(aaa,9);
		if (aaa[0]!=0) strcpy(quickroom.QRpasswd,aaa); }
	if ((quickroom.QRflags&QR_PRIVATE)==QR_PRIVATE) {
		printf("Cause users to forget room? ");
		if (yesno()==1) {	++quickroom.QRgen;
				if (quickroom.QRgen==100) quickroom.QRgen=10; }
		}

	printf("Preferred users only? ");
if (yesno()==0) quickroom.QRflags=(quickroom.QRflags-QR_PREFONLY);
	printf("Directory room? ");
if (yesno()==0) quickroom.QRflags=(quickroom.QRflags-QR_DIRECTORY);
else {
	printf("     Directory name? ");
	getline(quickroom.QRdirname,14);
	printf("  Uploading allowed? ");
if (yesno()==0) quickroom.QRflags=(quickroom.QRflags-QR_UPLOAD);
	printf("Downloading allowed? ");
if (yesno()==0) quickroom.QRflags=(quickroom.QRflags-QR_DOWNLOAD);
	printf("  Visible Directory? ");
if (yesno()==0) quickroom.QRflags=(quickroom.QRflags-QR_VISDIR); }
	printf("Network Room? ");
if (yesno()==0) quickroom.QRflags=(quickroom.QRflags-QR_NETWORK);
	printf("<1>Normal <2>Anon-only <3>Anon-option ? ");
	do {
		a=inkey()-48;
		} while((a<1)||(a>3));
	printf("%d\n",a);
if ((a==1)||(a==3)) quickroom.QRflags=(quickroom.QRflags-QR_ANONONLY);
if ((a==1)||(a==2)) quickroom.QRflags=(quickroom.QRflags-QR_ANON2);
RANSU:	file2=open("usersupp",O_RDONLY);	/* (gee, thanks a lot!) */
	if (quickroom.QRroomaide>=0L) {
		do {
			a=read(file2,&tempUS,sizeof(struct usersupp));
			} while((a>0)&&(quickroom.QRroomaide!=tempUS.eternal));
		close(file2);
		if (a>0) printf("Room aide is currently: %s\nNew ",
			tempUS.fullname);
		}
	else printf("No room aide.\n");
	printf("Room aide (RETURN to leave unchanged): ");
	getline(aaa,29);
	if (aaa[0]!=0) {
		file2=open("usersupp",O_RDONLY);
		aa=finduser(file2,aaa);
		read(file2,&tempUS,sizeof(struct usersupp));
		close(file2);
		if (aa==(-1L)) {
			printf("No such user.\n"); goto RANSU; }
		quickroom.QRroomaide=tempUS.eternal;
		}
	printf("\n\nSave changes (y/n)? ");
	if (yesno()==0) {
		lseek(file,(long)(curr_rm*sizeof(struct quickroom)),0);
		b=read(file,&quickroom,sizeof(struct quickroom));
		if (b<1) interr(36);
		close(file); return(0);
		}
	lseek(file,(long)(curr_rm*sizeof(struct quickroom)),0);
	b=write(file,&quickroom,sizeof(struct quickroom));
	close(file);
	if (quickroom.QRflags & QR_DIRECTORY) {
		sprintf(aaa,"mkdir ./files/%s",quickroom.QRdirname);
		system(aaa);
		sprintf(aaa,"./files/%s",quickroom.QRdirname);
		chmod(aaa,0777);
		}
	sprintf(aaa,"%s%c edited by %s",
		quickroom.QRname,room_prompt(&quickroom),usersupp.fullname);
	aide_message(aaa);
	return(0);
}

ungoto() {
	if (ugnum==(-1)) return(0);
	readyerself();
	curr_rm=ugnum;
	gotocurr();
	usersupp.lastseen[curr_rm]=uglsn;
	writeyerself();
	return(0);
}

download(c)
int c;
{
	int a;
	char aaa[100],bbb[100];
	if ((quickroom.QRflags&QR_DIRECTORY)
		&&(quickroom.QRflags&QR_DOWNLOAD)) {
			printf("Enter filename: ");
			getline(aaa,15);
			for (a=0; a<strlen(aaa); ++a) {
				aaa[a]=tolower(aaa[a]);
				if (aaa[a]=='/') aaa[a]='_';
				}
	sprintf(bbb,"files/%s/%s",quickroom.QRdirname,aaa);
	if (c==0) formout(bbb);
	if (c==1) {
		sprintf(aaa,"wcsend %s",bbb);
		system(aaa);
		}
	if (c==2) {
		signal(SIGQUIT,SIG_DFL);
		sttybbs(1);
		sprintf(aaa,"cat <%s",bbb);
		system(aaa);
		sttybbs(0);
		unlink("core");	/* just in case the core was dumped */
		}
	}
	else
		printf("Not in this room.\n");
	return(0);
}

roomdir() {
	char aaa[100];
	if ((quickroom.QRflags&QR_DIRECTORY)
	   &&(quickroom.QRflags&QR_VISDIR)) {
		sprintf(aaa,"./files/%s",quickroom.QRdirname);
		printf("Directory of %s!%s/%s\n",NODENAME,BBSDIR,&aaa[2]);
		directory(aaa);
		}
	else
		printf("Not in this room.\n");
	return(0);
}

invite() {	/* add a user to a private room */
	char aaa[31];
	int file;
	long aa;
	struct usersupp USscratch;
	if ((quickroom.QRflags&QR_PRIVATE)==0) {
		printf("Not a private room.\n");
		return(0);
		}
	printf("Name of user? ");
	getline(aaa,30);
	if (aaa[0]==0) return(0);
	file=open("usersupp",O_RDWR);
	if (file<0) interr(38);
	aa=finduser(file,aaa);
	if (aa!=(-1L)) {
		read(file,&USscratch,sizeof(struct usersupp));
		lseek(file,aa,0);
		USscratch.generation[curr_rm]=quickroom.QRgen;
		USscratch.forget[curr_rm]=(-1);
		write(file,&USscratch,sizeof(struct usersupp));
		}
	else	printf("No such user.\n");
	close(file);
	return(0);

}

kickout() {	/* kick a user out of a private room */
	int file;
	char aaa[100];
	long aa;
	struct usersupp USscratch;
	if ((quickroom.QRflags&QR_PRIVATE)==0) {
		printf("Not a private room.\n");
		return(0);
		}
	printf("Name of user? ");
	getline(aaa,30);
	file=open("usersupp",O_RDWR);
	if (file<0) interr(40);
	aa=finduser(file,aaa);
	if (aa!=(-1L)) {
		read(file,&USscratch,sizeof(struct usersupp));
		lseek(file,aa,0);
		USscratch.generation[curr_rm]=(-1);
		write(file,&USscratch,sizeof(struct usersupp));
		}
	else	printf("No such user.\n");
	close(file);
	return(0);
}

killroom() {	/* aide command: kill the current room */
	int file;
	long aa;
	char aaa[100];
	if (curr_rm<3) { printf("Can't kill this room.\n"); return(0); }
	printf("Are you sure you want to kill this room? ");
	if (yesno()==0) return(0);
	file=open("quickroom",O_RDWR); if (file<0) interr(42);
	aa=(long)curr_rm*sizeof(struct quickroom);
	lseek(file,aa,0);
	quickroom.QRflags=0;
	write(file,&quickroom,sizeof(struct quickroom));
	close(file);
	sprintf(aaa,"%s%c killed by %s",
		quickroom.QRname,room_prompt(&quickroom),usersupp.fullname);
	aide_message(aaa);
	curr_rm=0;		/* then goto the lobby */
	gotocurr();
	return(0);
}

forget() {	/* forget the current room */
	if (curr_rm<3) {
		printf("Cannot forget this room.\n");
		return(0);
		}
	IFAIDE { printf("Aides cannot forget rooms.\n"); return(0); }
	printf("Are you sure you want to forget this room? ");
	if (yesno()==0) return(0);
	readyerself();
	usersupp.forget[curr_rm]=quickroom.QRgen;
	usersupp.generation[curr_rm]=(-1);
	writeyerself();
	curr_rm=0;		/* then goto the lobby */
	gotocurr();
	return(0);
}

entroom() {
	int a,b,c,d,file;
	char aaa[100],bbb[100];
	long bb,cc,dd;
	struct quickroom QRscratch;

	if (usersupp.axlevel<3) {
		printf("You need higher access to create rooms.\n");
		return(0);
		}

	printf("Name for new room? ");
	getline(aaa,19);
	if (strlen(aaa)==0) return(0);
	aaa[19]=0;
	file=open("quickroom",O_RDONLY); if (file<0) interr(62);
	b=0;
	for (a=0; a<MAXROOMS; ++a) {
		c=read(file,&QRscratch,sizeof(struct quickroom));
		if (c<1) interr(63);
		if ( (QRscratch.QRflags & QR_INUSE)
			&& (!strucmp(QRscratch.QRname,aaa)) ) b=1; }
	close(file);
	if (b==1) {
		printf("'%s' already exists.\n",aaa);
		return(0); }
	bb=(-1L);	
	file=open("quickroom",O_RDONLY); if (file<0) interr(64);
	for (a=0; a<MAXROOMS; ++a) {
		cc=lseek(file,0L,1);
		c=read(file,&QRscratch,sizeof(struct quickroom));
		if (c<1) interr(65);
		if (((QRscratch.QRflags&QR_INUSE)==0)&&(bb==(-1L))) bb=cc;
		}
	close(file);
	if (bb==(-1L)) {
		printf("No room space available.\n");
		return(0);
		}
	IFNEXPERT formout("messages/roomaccess");
ACSEL:	printf("<?>Help\n<1>Public room\n<2>Guess-name room\n");
	printf("<3>Passworded room\n<4>Invitation-only room\n");
	printf("Enter room type: ");
ACSE2:	b=inkey(); b=tolower(b);
	if (b=='?') { printf("?\n");
		formout("messages/roomaccess"); goto ACSEL; }
	b=b-48;
	if ((b<1)||(b>4)) goto ACSE2;
	if (b==3) {
		printf("Enter a room password: ");
		getline(bbb,9); }
	printf("%d\n\042%s\042, a",b,aaa);
	if (b==1) printf(" public room.");
	if (b==2) printf(" guess-name room.");
	if (b==3) printf(" passworded room, password: %s",bbb);
	if (b==4) printf("n invitation-only room.");
	printf("\nInstall it? (y/n) : ");
	a=yesno();
	if (a==0) return(0);
	curr_rm=(int)(bb/sizeof(struct quickroom)); 
	file=open("quickroom",O_RDWR);
	if (file<0) interr(66);
	dd=lseek(file,bb,0);
	d=read(file,&quickroom,sizeof(struct quickroom));
	if (d<1) interr(67);
	strcpy(quickroom.QRname,aaa);
	strcpy(quickroom.QRpasswd,"");
	if (b==3) strcpy(quickroom.QRpasswd,bbb);
	quickroom.QRroomaide=(-1L);
	quickroom.QRhighest=0L;
	++quickroom.QRgen; if (quickroom.QRgen==100) quickroom.QRgen=10;
	quickroom.QRflags=QR_INUSE;
	if (b>1) quickroom.QRflags=(quickroom.QRflags|QR_PRIVATE);
	if (b==2) quickroom.QRflags=(quickroom.QRflags|QR_GUESSNAME);
	if (b==3) quickroom.QRflags=(quickroom.QRflags|QR_PASSWORDED);
	if ((b>2)&&(CREATAIDE==1)) quickroom.QRroomaide=usersupp.eternal;
	lseek(file,bb,0);
	write(file,&quickroom,sizeof(struct quickroom));
	close(file);

	/* Initialize a blank fullroom structure */
	for (a=0; a<MSGSPERRM; ++a) {
		fullroom.FRnum[a]=0L;
		fullroom.FRpos[a]=0L;
		}

	sprintf(aaa,"./rooms/fullrm%d",curr_rm);
	file=open(aaa,O_RDWR);
	if (file<0) interr(70);
	write(file,&fullroom,sizeof(struct fullroom));
	close(file);
	gotocurr();
	strcpy(aaa,quickroom.QRname); strcat(aaa,"> created by ");
	strcat(aaa,usersupp.fullname);
	if (quickroom.QRflags&QR_PRIVATE) strcat(aaa," [private]");
	if (quickroom.QRflags&QR_GUESSNAME) strcat(aaa,"[guessname] ");
	if (quickroom.QRflags&QR_PASSWORDED) {
		strcat(aaa,"\n Password: ");
		strcat(aaa,quickroom.QRpasswd);
		}
	aide_message(aaa);
	return(0);
}

gotocurr() /* goto room currently in global variable curr_rm */
{
	int file,d; char aaa[100];
	file=open("quickroom",O_RDONLY); if (file<0) interr(74);
		lseek(file,(long)(curr_rm*sizeof(struct quickroom)),0);
		d=read(file,&quickroom,sizeof(struct quickroom));
		if (d<1) interr(75);
	close(file);
	if (curr_rm==1) { readmail(); return(0); }
	sprintf(aaa,"./rooms/fullrm%d",curr_rm);
	file=open(aaa,O_RDONLY); if (file<0) interr(76);
	d=read(file,&fullroom,sizeof(struct fullroom));
	if (d<1) interr(77);
	close(file);
	return(0);
}

whoknows() {
	struct usersupp temp;
	int file;
	file=open("usersupp",O_RDONLY);
	if (file<0) return(file);
	while(read(file,&temp,sizeof(struct usersupp))>0)
		if ((quickroom.QRflags & QR_INUSE)
			&& ( (curr_rm!=2) || (temp.axlevel>=6) )
			&& (quickroom.QRgen != (temp.forget[curr_rm]) )

			&& (	((quickroom.QRflags&QR_PREFONLY)==0)
			||	(temp.axlevel>=5)
			)

			&& (	((quickroom.QRflags&QR_PRIVATE)==0)
   			||	(temp.axlevel>=6)
   			||	(quickroom.QRgen==(temp.generation[curr_rm]))
   			)

		) printf("%s\n",temp.fullname);
	close(file);
	return(0);
}
SHAR_EOF
fi
echo shar: "extracting 'routines.c'" '(10412 characters)'
if test -f 'routines.c'
then
	echo shar: "will not over-write existing file 'routines.c'"
else
cat << \SHAR_EOF > 'routines.c'
/* Citadel/UX independent routines (i.e. no global variables are used) */

#include <fcntl.h>
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <pwd.h>
#include <setjmp.h>
#include <termio.h>

#define ROUTINES_C

#include "citadel.h"

#define IFEXPERT if (usersupp.flags&US_EXPERT)
#define IFNEXPERT if ((usersupp.flags&US_EXPERT)==0)
#define IFUPASS if (upass!=0)
#define IFNUPASS if (upass==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();

extern char *days[7];
extern char *months[12];
extern char *axdefs[7];

strucmp(st1,st2) /* Compares two strings without case sensitivity */
char st1[],st2[]; {
char aaa[100],bbb[100];
int a;
	for (a=0; a<=strlen(st1); ++a) aaa[a]=tolower(st1[a]);
	for (a=0; a<=strlen(st2); ++a) bbb[a]=tolower(st2[a]);
	return(strcmp(aaa,bbb));
}

back(spaces) /* Destructive backspace */
int spaces; {
int a;
	for (a=1; a<=spaces; ++a) {
		putc(8,stdout); putc(32,stdout); putc(8,stdout);
		}
	}

yesno() { /* Returns 1 for yes, 0 for no */
int a;
	while (1) {
		a=inkey(); a=tolower(a);
		if (a=='y') { printf("Yes\n"); return(1); }
		if (a=='n') { printf("No\n");  return(0); }
		}
	}

edituser(structure)
struct usersupp *structure; {
	int a,b;
do {	printf("Current access level: %d [%s]\n",structure->axlevel,
		axdefs[structure->axlevel]);
	printf("New level (? to list them): ");
	a=inkey();
	if (a=='?') {
		printf("list\n");
		for (b=0; b<7; ++b) printf("%d %s\n",b,axdefs[b]);
		}
	a=a-48;
	} while((a<0)||(a>6));
	printf("%d\n",a);
	structure->axlevel=a;
	return(0);
	}

getusinfo(structure)
struct usersupp *structure; {
	int a; char aaa[100];
	do {
		printf("Enter your screen width: ");
		getline(aaa,3); a=atoi(aaa);
		if ((a<20)||(a>132))
			printf("...must be between 20 and 132.\n");
		} while((a<20)||(a>132));
	structure->screenwidth=a;
	printf("Are you an experienced Citadel user? ");
	structure->flags=((structure->flags)|US_EXPERT);
	if (yesno()==0) structure->flags=((structure->flags)^US_EXPERT);
	printf("Print last old message on New message request? ");
	structure->flags=((structure->flags)|US_LASTOLD);
	if (yesno()==0) structure->flags=((structure->flags)^US_LASTOLD);
	if ((structure->flags&US_EXPERT)==0) formout("messages/unlisted");
	printf("List in userlog? ");
	structure->flags=((structure->flags)|US_UNLISTED);
	if (yesno()==1) structure->flags=((structure->flags)^US_UNLISTED);
	printf("Prompt after each message? ");
	structure->flags=((structure->flags)|US_NOPROMPT);
	if (yesno()==1) structure->flags=((structure->flags)^US_NOPROMPT);
}

getfield(file,string)		/* Break out next null-terminated string */
int file; char string[]; {
int a,b,c;
	strcpy(string,"");
	a=0;
	do {
		c=0; b=read(file,&c,1);
		if (b<1) { string[a]=0; return(0); }
		string[a]=c;
		++a;
		} while(c!=0); return(0);
}

getstring(file,string)		/* get a line of text from a file */
int file; char string[]; {	/* ignores lines beginning with # */
int a,b,c;
do {
	strcpy(string,"");
	a=0;
	do {
		c=0; b=read(file,&c,1);
		if (b<1) { string[a]=0; return(-1); }
		string[a]=c;
		++a;
		} while(c!=10);
		string[a-1]=0;
	} while(string[0]=='#');
return(strlen(string));
}

pattern(search,patn)	/* Searches for patn in search string */
char search[];
char patn[];
{
	int a,b;
	for (a=0; a<strlen(search); ++a)
	{	b=strncmp(&search[a],patn,strlen(patn));
		if (b==0) return(b);
		}
	return(1);
}

interr(errnum)	/* display internal error as defined in errmsgs */
int errnum; {
	printf("INTERNAL ERROR %d\n",errnum);
	printf("(Press any key to continue)\n");
	inkey();
	logoff(errnum);
}

directory(path)
char *path;
{
	struct directx {
		int d_ino;
		char d_name[15];
	} dlink;
	char comment[151];
	int fd,nread,a; char tname[100];
	struct stat statbuf; long aa;
	FILE *fp;
if ((fd=open(path,0))==(-1)) return(1);
dlink.d_name[14]=0;
printf("-----------------------\n");
read(fd,&dlink,16); read(fd,&dlink,16);
while ((nread=read(fd,&dlink,16)) > 0)
	{
	if ((strucmp(dlink.d_name,"filedir"))&&(dlink.d_ino!=0)) {
		sprintf(tname,"%s/%s",path,dlink.d_name);
		stat(tname,&statbuf);
		aa=(long)statbuf.st_size;
		sprintf(tname,"%s/filedir",path);
	fp=fopen(tname,"r");
	comment[0]=0;
	if (fp!=NULL) {
		do {
			for (a=0; a<17; ++a) comment[a]=0;
			fgets(comment,151,fp);
			comment[strlen(comment)-1]=0;
	if (!strncmp(comment,dlink.d_name,strlen(dlink.d_name))) goto FND;
			} while(!feof(fp));
FND:		fclose(fp);
		}
printf("%-14s %8ld %s\n",dlink.d_name,aa,&comment[strlen(dlink.d_name)+1]);
	}
	}
	close(fd);
	return(0);
}

fpgetfield(fp,string)	/* level-2 break out next null-terminated string */
FILE *fp;
char string[];
{
int a,b;
strcpy(string,"");
a=0;
	do {
		b=getc(fp);
		if (b<1) { string[a]=0; return(0); }
		string[a]=b;
		++a;
		} while(b!=0);
	return(0);
}


fmout(width,flname)
int width;
char flname[];
	{

	int a,b,c,real,old;
	char aaa[140];
	FILE *fp;
	
	fp=fopen(flname,"rb");
	if (fp==NULL) {
			printf("No file %s.\n",flname);
			return(1); }

	strcpy(aaa,""); old=255;
	c=1; /* c is the current pos */
FMTA:	old=real; a=getc(fp); real=a;
	if (a==0) goto FMTEND;
	if (a<0) goto FMTEND;
	
	if ( ((a==13)||(a==10)) && (old!=13) && (old!=10) ) a=32;
	if ( ((old==13)||(old==10)) && (isspace(real)) ) {
						printf("\n"); c=1; }
	if (a>126) goto FMTA;

	if (a>32) {
	if ( ((strlen(aaa)+c)>(width-5)) && (strlen(aaa)>(width-5)) )
		{ printf("\n%s",aaa); c=strlen(aaa); aaa[0]=0; }
	 b=strlen(aaa); aaa[b]=a; aaa[b+1]=0; }
	if (a==32) { 	if ((strlen(aaa)+c)>(width-5)) { 
							printf("\n");
							c=1;
							}
			printf("%s ",aaa); ++c; c=c+strlen(aaa);
			strcpy(aaa,""); goto FMTA; }
	if ((a==13)||(a==10)) {
				printf("%s\n",aaa); c=1;
				strcpy(aaa,""); goto FMTA; }
	goto FMTA;

FMTEND:	fclose(fp);
	printf("\n");
	return(0);
}

strproc(string)
char string[];
{
	int a;
	char aaa[100];
	char bbb[5];
	strcpy(aaa,string);

	if (string[0]==0) return(0);

/* Convert non-printable characters to blanks */
	for (a=0; a<strlen(aaa); ++a) {
		if (aaa[a]<32) aaa[a]=32;
		if (aaa[a]>126) aaa[a]=32; }

/* Remove leading and trailing blanks */
	while(aaa[0]<33) strcpy(aaa,&aaa[1]);
	while(aaa[strlen(aaa)-1]<33) aaa[strlen(aaa)-1]=0;

/* Remove double blanks */
	bbb[1]=0;
	strcpy(string,"");
	for (a=0; a<strlen(aaa); ++a) {
		if ((aaa[a]==32)&&(aaa[a+1]==32)) goto PSSKP;
	bbb[0]=aaa[a];
	strcat(string,bbb);
PSSKP:	bbb[1]=0;
	}

/* remove characters which would interfere with the network */
	for (a=0; a<strlen(aaa); ++a) {
		if (aaa[a]=='!') strcpy(&aaa[a],&aaa[a+1]);
		if (aaa[a]=='@') strcpy(&aaa[a],&aaa[a+1]);
		if (aaa[a]=='_') strcpy(&aaa[a],&aaa[a+1]);
		if (aaa[a]==',') strcpy(&aaa[a],&aaa[a+1]);
		}

	return(0);
}

sttybbs(sflag) 
int sflag;{
struct termio live;
	ioctl(0,TCGETA,&live);
	live.c_iflag=ISTRIP|IXON|IXANY;
	live.c_oflag=OPOST|ONLCR;
	live.c_lflag=NOFLSH;
	if (sflag==1) live.c_lflag=ISIG|NOFLSH;
	live.c_line=0;
	live.c_cc[0]=15;
	live.c_cc[1]=3;
	live.c_cc[2]=8;
	live.c_cc[3]=24;
	live.c_cc[4]=1;
	live.c_cc[5]=255;
	live.c_cc[6]=0;
	live.c_cc[7]=0;
	ioctl(0,TCSETA,&live);
	return(0);
}

long finduser(file,name)	/* binary search for a user */
int file;
char name[];
{
	struct usersupp temp;
	int a;
	long bottom,top,guess,obottom,otop;

	obottom=(-1L); otop=(-1L);
	bottom=0L;
	top=(lseek(file,0L,2)/(long)sizeof(struct usersupp));

while(1) {
	if ((obottom==bottom)&&(otop==top)) return(-1L);
	obottom=bottom; otop=top;
	guess=(((top-bottom)/2)+bottom);
	lseek(file,(guess*(long)sizeof(struct usersupp)),0);
	read(file,&temp,sizeof(struct usersupp));
	a=strucmp(temp.fullname,name);
	if (a==0) return(lseek(file,(guess*(long)sizeof(struct usersupp)),0));
	if (a<0) bottom=guess;
	if (a>0) top=guess;
	}
}

rec_log(record)		/* record an entry in the call log */
struct calllog *record;
{
	int file,a,b;
	time(&record->CLtime);
	file=open("calllog.pos",O_RDWR);
	read(file,&a,2);
	b=a; ++a; if (a==CALLLOG) a=0;
	lseek(file,0L,0);
	write(file,&a,2);
	close(file);

	file=open("calllog",O_RDWR);
	lseek(file,(long)(b*sizeof(struct calllog)),0);
	write(file,record,sizeof(struct calllog));
	close(file);
	return(0);
}

log_carr()		/* use rec_log to record the connection */
{
	struct calllog temp;
	struct termio stty;
	strcpy(temp.CLfullname,ttyname(0));
	temp.CLflags=CL_INOTHER;
	ioctl(0,TCGETA,&stty);
	if ((stty.c_cflag&B300)==B300)		temp.CLflags=CL_IN300;
	if ((stty.c_cflag&B1200)==B1200)	temp.CLflags=CL_IN1200;
	if ((stty.c_cflag&B2400)==B2400)	temp.CLflags=CL_IN2400;
	if ((stty.c_cflag&B9600)==B9600)	temp.CLflags=CL_INOTHER;
	rec_log(&temp);
	return(0);
}

alias(name)		/* process alias and routing info for mail */
char name[]; {
	FILE *fp;
	int a,b,file;
	char aaa[300],bbb[300];
	
	fp=fopen("network/mail.aliases","r");
	if (fp==NULL) return(2);
GNA:	strcpy(aaa,""); strcpy(bbb,"");
	do {
		a=getc(fp);
		if (a==',') a=0;
		if (a>0) { b=strlen(aaa); aaa[b]=a; aaa[b+1]=0; }
		} while(a>0);
	do {
		a=getc(fp);
		if (a==10) a=0;
		if (a>0) { b=strlen(bbb); bbb[b]=a; bbb[b+1]=0; }
		} while(a>0);
	if (a<0) {
		fclose(fp);
		goto DETYPE;
		}
	if (strucmp(name,aaa)) goto GNA;
	fclose(fp);
	strcpy(name,bbb);
	printf("*** Mail is being forwarded to %s\n",name);

DETYPE:	/* determine local or remote type, see citadel.h */
	for (a=0; a<strlen(name); ++a) if (name[a]=='!') return(M_UUCP);
	b=0; for (a=0; a<strlen(name); ++a) if (name[a]=='@') ++b;
	if (b>1) {
		printf("Too many @'s in address\n");
		return(M_ERROR);
		}
	if (b==1) {
		for (a=0; a<strlen(name); ++a)
			if (name[a]=='@') strcpy(bbb,&name[a+1]);
		while (bbb[0]==32) strcpy(bbb,&bbb[1]);
		file=open("network/mail.sysinfo",O_RDONLY);
GETSN:		do {
			a=getstring(file,aaa);
			} while ((a>=0)&&(strucmp(aaa,bbb)));
		a=getstring(file,aaa);
		if (!strncmp(aaa,"use ",4)) {
			strcpy(bbb,&aaa[4]);
			goto GETSN;
			}
		close(file);
		if (!strncmp(aaa,"bin",3)) {
			strcpy(aaa,name); strcpy(bbb,name);
			while (aaa[strlen(aaa)-1]!='@') aaa[strlen(aaa)-1]=0;
			aaa[strlen(aaa)-1]=0;
			while (aaa[strlen(aaa)-1]==' ') aaa[strlen(aaa)-1]=0;
			while (bbb[0]!='@') strcpy(bbb,&bbb[1]);
			strcpy(bbb,&bbb[1]);
			while (bbb[0]==' ') strcpy(bbb,&bbb[1]);
			sprintf(name,"%s @%s",aaa,bbb);
			return(M_BINARY);
			}
		printf("Error in network/mail.sysinfo file\n");
		return(M_ERROR);
		}
	return(M_LOCAL);
	}
SHAR_EOF
fi
echo shar: "extracting 'routines2.c'" '(10078 characters)'
if test -f 'routines2.c'
then
	echo shar: "will not over-write existing file 'routines2.c'"
else
cat << \SHAR_EOF > 'routines2.c'
/* More Citadel/UX routines...
 * unlike routines.c, some of these DO use global variables.
 */

#include <fcntl.h>
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <pwd.h>
#include <setjmp.h>
#include <termio.h>
#include "citadel.h"

long atol();
long lseek();
long finduser();

extern int curr_rm;
extern int ugnum;
extern long uglsn;
extern struct quickroom quickroom;
extern struct usersupp usersupp;
extern struct fullroom fullroom;
extern char temp[];
extern char *axdefs[7];

eopen(name,mode)
char *name;
int mode; {
	int ret;
	ret=open(name,mode);
	if (ret<0) {
		fprintf(stderr,"-------------------------\n");
		fprintf(stderr,"Cannot open file '%s', mode=%d\n",name,mode);
		interr(1);
		}
	return(ret);
	}

pwcrypt(text,code)
char text[];
int code; {
	int a;
	for (a=0; a<strlen(text); ++a) text[a]=(text[a]^(((code|128)^a)&0xFF));
	return(0);
	}

int room_prompt(qrptr)	/* return proper room prompt character */
struct quickroom *qrptr; {
	int a;
a='>'; if ((qrptr->QRflags)&QR_DIRECTORY) a=']';
if ((a==']')&&((qrptr->QRflags)&QR_NETWORK)) a='}';
	if ((a=='>')&&((qrptr->QRflags)&QR_NETWORK)) a=')';
	return(a);
	}

entregis(who)		/* register a user with name and address */
long who; {
	int f,file,a,b;
	char pbuf[15];
	struct registration regis,rtemp;
	regis.RGeternal=who;
	printf("REAL name: ");
	getline(regis.RGname,29);
	printf("  Address: ");
	getline(regis.RGaddr,24);
	printf("City/town: ");
	getline(regis.RGcity,14);
	printf("    State: ");
	getline(regis.RGstate,2);
	printf(" ZIP code: ");
	getline(regis.RGzip,5);
	printf("Phone num: ");
	getline(pbuf,14);
	regis.RGphone[0]=0;
	for (a=0; a<strlen(pbuf); ++a) 
		if ((pbuf[a]>='0')&&(pbuf[a]<='9')) {
			b=strlen(regis.RGphone);
			regis.RGphone[b]=pbuf[a]; regis.RGphone[b+1]=0;
			}
	printf("\n");
	f=fork();			/* register in the background */
	if (f<0) {
		fprintf(stderr,"citadel: cannot fork-registration not filed\n");
		return(-1);
		}
	if (f>0) return(0);
	
	/* remainder of this routine happens in a separate task! */
	file=open("registration",O_RDWR);
	if (file<0) file=creat("registration",0644);
	while(read(file,&rtemp,sizeof(struct registration))>0) {
		if (rtemp.RGeternal==who) {
			lseek(file,(0L-sizeof(struct registration)),1);
			goto WRT;
			}
		}
WRT:	write(file,&regis,sizeof(struct registration));
	close(file);
	exit(0);		/* no, not return() - we're a child process */
	}


updatels() {	/* make all messages old in current room */
	int a;
	readyerself();
	storeug();
	for (a=0; a<MSGSPERRM; ++a)
		if (fullroom.FRnum[a]>usersupp.lastseen[curr_rm])
			usersupp.lastseen[curr_rm]=fullroom.FRnum[a];
	if (curr_rm==1) /* if mail room, do it a little differently... */
		usersupp.lastseen[1]=usersupp.mailnum[MAILSLOTS-1];
	writeyerself();
}

storeug() {	/* store <u>ngoto information */
	ugnum=curr_rm;
	uglsn=usersupp.lastseen[curr_rm];
	return(0); }


getline(string,lim)	/* Gets a line from the terminal */
char string[]; 		/* Pointer to string buffer */
int lim;		/* Maximum length - if negative, no-show */
{
int a,b; char flag;
	flag=0;
	if (lim<0) { lim=(0-lim); flag=1; }
	strcpy(string,"");
GLA:	a=inkey(); a=(a&127);
	if ((a==8)&&(strlen(string)==0)) goto GLA;
	if ((a!=13)&&(a!=8)&&(strlen(string)==lim)) goto GLA;
	if ((a==8)&&(string[0]!=0)) {
		string[strlen(string)-1]=0;
		putc(8,stdout); putc(32,stdout); putc(8,stdout); goto GLA; }
	if ((a==13)||(a==10)) {
		putc(13,stdout); putc(10,stdout); return(0); }
	b=strlen(string);
	string[b]=a;
	string[b+1]=0;
	if (flag==0) putc(a,stdout);
	if (flag==1) putc('*',stdout);
	goto GLA;
}

delete_message(delnum) /* Delete message from current room */
long delnum; {
	int file,a,b;
	char aaa[100];
	if (curr_rm==1) {
		printf("Can't delete mail.\n");
		return(1); }
	sprintf(aaa,"./rooms/fullrm%d",curr_rm);
	file=eopen(aaa,O_RDWR);
	a=read(file,&fullroom,sizeof(struct fullroom));
	if (a<1) interr(79); 
	for (a=0; a<MSGSPERRM; ++a)
		if (fullroom.FRnum[a]==delnum) {
			fullroom.FRnum[a]=0L;
			fullroom.FRpos[a]=0L; }
	lseek(file,0L,0);
	a=write(file,&fullroom,sizeof(struct fullroom));
	if (a<1) interr(80);
	close(file);
	file=eopen("./quickroom",O_RDWR);
	lseek(file,(long)(curr_rm*sizeof(struct quickroom)),0);
	b=read(file,&quickroom,sizeof(struct quickroom));
	if (b<1) interr(82);
	quickroom.QRhighest=0L;
	for (a=0; a<MSGSPERRM; ++a)
		if (fullroom.FRnum[a]>quickroom.QRhighest)
			quickroom.QRhighest=fullroom.FRnum[a];
	lseek(file,(long)(curr_rm*sizeof(struct quickroom)),0);
	b=write(file,&quickroom,sizeof(struct quickroom));
	if (b<1) interr(83);
	close(file);
	printf("Message deleted.\n");
	return(0);
}


upload(c)	/* c = upload mode */
int c; {
	char buf[151],aaa[100],bbb[60],ccc[60];
	int a,b,file;
	long cc;
	FILE *fp;

	if ( ((quickroom.QRflags&QR_DIRECTORY)==0)
		|| ((quickroom.QRflags&QR_UPLOAD)==0) ) {
			printf("Not in this room.\n");
			return(1);
			}

	printf("Enter filename: ");
	getline(aaa,15);
	for (a=0; a<strlen(aaa); ++a) aaa[a]=tolower(aaa[a]);
	sprintf(bbb,"./files/%s/%s",quickroom.QRdirname,aaa);
	file=open(bbb,O_RDONLY);
	if (file>(-1)) {
		printf("There already is a file by that name.\n");
		close(file); return(1); }
	printf("Enter a short description of the file:\n: ");
	getline(buf,150);
	sprintf(ccc,"./files/%s/filedir",quickroom.QRdirname);
	fp=fopen(ccc,"r+");
	if (fp==NULL) fp=fopen(ccc,"w");
	fseek(fp,0L,2);
	fprintf(fp,"%s %s\n",aaa,buf);
	fclose(fp);
	file=creat(bbb,0666);
	if (file<0) {
		printf("Can't create that file?\n");
		return(1); }
	if (c>0) {
		close(file);
		goto ETUX;
		}
	a=0;
	printf("Now recieving. ESC to end.\n");
	do {
		b=inkey(); 
		if (b==13) { b=10; printf("\r"); }
		if (b!=27) { printf("%c",b); write(file,&b,1); }
		} while(b!=27);
	close(file);
ETPRF:	printf("File recieved.\n");
	time(&cc);			/* put together an upload notice */
	fp=fopen(temp,"wb"); if (fp==NULL) interr(22);
	putc(255,fp);
	putc(MES_NORMAL,fp);
	putc(0,fp);
	fprintf(fp,"Psysop"); putc(0,fp);
	fprintf(fp,"T%ld",cc); putc(0,fp);
	fprintf(fp,"A%s",usersupp.fullname); putc(0,fp);
	fprintf(fp,"O%s",quickroom.QRname); putc(0,fp);
	fprintf(fp,"N%s",NODENAME); putc(0,fp); putc('M',fp);
	fprintf(fp,"*New Upload*\nFilename: %s\r %s\n",aaa,buf);
	putc(0,fp);
	fclose(fp);
	save_message(temp,buf,0,M_LOCAL);
	return(0);

ETUX:	if (c==1) {
		sprintf(ccc,"wcreceive %s",bbb);
		system(ccc);
		}
	goto ETPRF;
}

move_message(pos)
long pos; {
	char targ[20];
	int file,a,h;
	struct quickroom qtemp;
	h=curr_rm;
	pull_message(pos,temp);
	do {
		curr_rm=(-1);
		printf("Enter target room: ");
		getline(targ,19);
		if (targ[0]==0) strcpy(targ,quickroom.QRname);
		file=open("quickroom",O_RDONLY);
		for (a=0; a<MAXROOMS; ++a) {
			read(file,&qtemp,sizeof(struct quickroom));
if ((!strucmp(qtemp.QRname,targ))&&(qtemp.QRflags&QR_INUSE)) curr_rm=a;
			}
		close(file);
		} while(curr_rm<0);
	gotocurr();
	save_message(temp,"",0,M_LOCAL);
	curr_rm=h;
	gotocurr();
	return(0);
	}

aide_message(text) 			/* post a message in Aide> */
char *text; {
	long now;
	FILE *fp;

	time(&now);
	fp=fopen(temp,"wb"); if (fp==NULL) interr(92);
	putc(255,fp);
	putc(MES_NORMAL,fp);
	putc(0,fp);
	fprintf(fp,"Psysop"); putc(0,fp);
	fprintf(fp,"T%ld",now); putc(0,fp);
	fprintf(fp,"ACitadel"); putc(0,fp);
	fprintf(fp,"OAide"); putc(0,fp);
	fprintf(fp,"N%s",NODENAME); putc(0,fp); putc('M',fp);
	fprintf(fp,"%s\n",text);
	putc(0,fp);
	fclose(fp);
	save_message(temp,"",1,M_LOCAL);
	return(0);
	}

validate() {	/* validate new users */
	struct msgmain MMtemp;
	struct usersupp UStemp;
	int file,a,b;

	file=eopen("MMstructure",O_RDONLY);
	read(file,&MMtemp,sizeof(struct msgmain));
	close(file);
	if ((MMtemp.MMflags&MM_VALID)==0) {
		printf("There are no unvalidated users.\n");
		return(0);
		}
	do {
		file=eopen("MMstructure",O_RDONLY);
		read(file,&MMtemp,sizeof(struct msgmain));
		close(file);
		} while(MMtemp.MMflags&MM_BUSY);
	file=eopen("MMstructure",O_WRONLY);
	MMtemp.MMflags=MMtemp.MMflags&(~MM_VALID);
	write(file,&MMtemp,sizeof(struct msgmain));
	close(file);

	file=eopen("usersupp",O_RDWR);
	while(read(file,&UStemp,sizeof(struct usersupp))>0) {
		if (UStemp.axlevel==1) {
			printf("\n\n\nUser #%-5ld %s ",
			       UStemp.eternal,UStemp.fullname);
			if (usersupp.screenwidth<=40) printf("\n");
			pwcrypt(UStemp.password,PWCRYPT);
			printf("PW: %s\n",UStemp.password);
			dis_regis(&UStemp);
			printf("Access level (? for list): ");
			do {
				a=inkey();
				if (a=='?') {
					printf("list\n");
					for (b=0; b<7; ++b)
						printf("%d %s\n",b,axdefs[b]);
					}
				a=a-48;
				} while((a<0)||(a>6));
			printf("%d\n",a);
			UStemp.axlevel=a;
			pwcrypt(UStemp.password,PWCRYPT);
			lseek(file,(0L-sizeof(struct usersupp)),1);
			write(file,&UStemp,sizeof(struct usersupp));
			}
		}
	close(file);
	printf("\n*** End of registration.\n");
	return(0);
	}

dis_regis(userdata)
struct usersupp *userdata; {
	struct registration regis;
	int a,b,file;
	char pbuf[20];
	if (!((userdata->flags)&US_REGIS)) {
		printf("No registration online.\n");
		return(1);
		}
	file=open("registration",O_RDONLY);
	if (file<0) return(2);
	while(read(file,&regis,sizeof(struct registration))>0) {
		if (userdata->eternal==regis.RGeternal) {
			printf("%-29s\n",regis.RGname);
			printf("%-29s\n",regis.RGaddr);
			printf("%-14s %2s %6s\n",
				regis.RGcity,regis.RGstate,regis.RGzip);
			strcpy(pbuf,regis.RGphone);
			regis.RGphone[0]=0;
			for (a=0; a<strlen(pbuf); ++a) {
				if ((pbuf[a]>='0')&&(pbuf[a]<='9')) {
					b=strlen(regis.RGphone);
					regis.RGphone[b]=pbuf[a];
					regis.RGphone[b+1]=0;
					}
				}
			while(strlen(regis.RGphone)<10) {
				strcpy(pbuf,regis.RGphone);
				strcpy(regis.RGphone," ");
				strcat(regis.RGphone,pbuf);
				}

			printf("(%c%c%c) %c%c%c-%c%c%c%c\n",
				regis.RGphone[0],regis.RGphone[1],
				regis.RGphone[2],regis.RGphone[3],
				regis.RGphone[4],regis.RGphone[5],
				regis.RGphone[6],regis.RGphone[7],
				regis.RGphone[8],regis.RGphone[9]);
			}
		if (userdata->eternal==regis.RGeternal) break;
		}
	close(file);
	return(0);
	}
SHAR_EOF
fi
echo shar: "extracting 's.h'" '(2401 characters)'
if test -f 's.h'
then
	echo shar: "will not over-write existing file 's.h'"
else
cat << \SHAR_EOF > 's.h'
/****************************************************************************/
/*           YOUR SYSTEM CONFIGURATION!!!                                   */
/* Edit these values to your particular system, then recompile all programs */
/* which use Citadel.h, so they all use your new values. Customize your   */
/* system BEFORE running setup for the first time to avoid UNIXmadness!!    */
/****************************************************************************/

/****************************************************************************/
/* Networking stuff
 * set NODENAME to your UUCP node name. Set PREVMSGS to the number of
 * records you want in the prevmsgs file, which keeps a record of recently
 * seen messages on all systems. This prevents messages from cycling
 * endlessly through the network. If you are not in a network, set PREVMSGS
 * to 2. If messages seem to be cycling endlessly through the network,
 * increase the value of PREVMSGS.
 */

#define NODENAME	"cavevax"	/* Your system's uucp nodename      */
#define PREVMSGS	2		/* Number of recs in prevmsgs file  */
/****************************************************************************/

#define BBSUID		999
/* make an account called "bbs", "guest", or something to that effect which
 * shells directly to citadel. Place the userid of the account here. */

#define CREATAIDE	0
/* If CREATAIDE is set to 1, anyone who creates a class 3 (passworded) or
 * class 4 (invitation-only) room automatically becomes the room-aide for
 * that room. */

#define SLEEPING	1800
/* If the program is waiting for input more than SLEEPING number of seconds,
 * Citadel will print "Sleeping? Call again." and hang up. To disable the
 * feature, set SLEEPING to 0. */

/* You may NOT change these six values once you set up your system.	    */
#define MAXROOMS	100		/* Number of rooms in system        */
#define NVOTES		10		/* Number of votes sys can handle   */
#define MAILSLOTS	35		/* Number of mail slots             */
#define MSGSPERRM	150		/* Messages per room                */
#define MM_FILELEN	(2000000L)	/* Number of bytes in message file  */
#define CALLLOG		1000		/* Number of entries in call log    */
/* Do not set MAILSLOTS higher than MSGSPERRM 				    */

/* problem user stuff. */
#define IAADETECT	1		/* 1=on, 0=off                      */
#define IAAROOM		"IAA etc."	/* Name of room to send problems to */
SHAR_EOF
fi
echo shar: "extracting 'setup.c'" '(3913 characters)'
if test -f 'setup.c'
then
	echo shar: "will not over-write existing file 'setup.c'"
else
cat << \SHAR_EOF > 'setup.c'
/*
 * Citadel/UX setup program
 * v1.1 / by Art Cancro 05/25/89
 * see copyright.doc for copyright information
 *
 * *** YOU MUST EDIT sysconfig.h >BEFORE< COMPILING SETUP ***
 */

#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#include "citadel.h"

main() {
	int a;
	char aaa[20];
	printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
	printf("Citadel/UX setup program\n\n");
	printf("DO NOT re-create files that you wish to keep intact.\n");
	printf("They will be ERASED if you do so!\n");
	printf("If you are setting up Citadel/UX for the first time,\n");
	printf("answer 'yes' to all of the prompts.\n\n");

	a=0;	
	printf("\nCreate message file? ");
	gets(aaa);
	aaa[0]=tolower(aaa[0]);
	a=aaa[0];
	if (aaa[0]=='y') cre8msg();

	printf("\n   Create user file? ");
	gets(aaa);
	aaa[0]=tolower(aaa[0]);
	if (aaa[0]=='y') cre8user();

	printf("\n  Create room files? ");
	if (a!='y') gets(aaa);
	aaa[0]=tolower(aaa[0]);
	if (aaa[0]=='y') cre8room();

	printf("\n    Create call log? ");
	gets(aaa);
	aaa[0]=tolower(aaa[0]);
	if (aaa[0]=='y') cre8clog();

	printf("\nSetup finished.\n");
	exit(0);
}

cre8msg() {
	struct msgmain msgmain;
	FILE *fp;
	long aa;

	fp=fopen("msgmain","wb");
	for (aa=0; aa<=(MM_FILELEN+100); ++aa) {
		putc(0,fp);
		if ((aa%10000L)==0L)
			printf("setup: writing msgmain byte %15ld\r",aa);
		}
	fclose(fp);

	printf("setup: writing control structure and unlocking file\n");
	msgmain.MMlowest=1L;
	msgmain.MMhighest=1L;
	msgmain.MMcurpos=0L;
	msgmain.MMflags=0;

	fp=fopen("MMstructure","wb");
	fwrite(&msgmain,sizeof(struct msgmain),1,fp);
	fclose(fp);
}

cre8user() {
	int file;
	struct usersupp usersupp;
	long aa;

	printf("setup: creating a blank user file\n");
	unlink("usersupp");
	file=creat("usersupp",0666);
	usersupp.screenwidth=0;
	usersupp.eternal=0L;
	usersupp.timescalled=0;
	usersupp.posted=0;
	usersupp.flags=US_UNLISTED;
	usersupp.USuid=(-1);
	strcpy(usersupp.fullname,"!");
	strcpy(usersupp.password,"");
	usersupp.axlevel=4;
	write(file,&usersupp,sizeof(struct usersupp));
	close(file);
	file=creat("eternal",0666);
	chmod("eternal",0666);
	aa=1L;
	write(file,&aa,4);
	close(file);
}

cre8room() {
	int a;
	FILE *fp;
	char aaa[50];
	struct quickroom quickroom;
	struct fullroom fullroom;

	printf("setup: creating and initializing room files\n");

	/* Load up a blank fullroom structure to be used for all rooms */
	for (a=0; a<MSGSPERRM; ++a) {
		fullroom.FRnum[a]=0L;
		fullroom.FRpos[a]=0L;
		}

	/* Open a new quickroom file */
	fp=fopen("quickroom","wb");
	strcpy(quickroom.QRpasswd,"");
	quickroom.QRroomaide=0L;
	quickroom.QRhighest=0L;
	quickroom.QRgen=1;
	quickroom.QRflags=QR_INUSE;

	/* Create Lobby> Mail> and Aide> */
	strcpy(quickroom.QRname,"Lobby");
	fwrite(&quickroom,sizeof(struct quickroom),1,fp);

	strcpy(quickroom.QRname,"Mail");
	fwrite(&quickroom,sizeof(struct quickroom),1,fp);
	
	strcpy(quickroom.QRname,"Aide");
	fwrite(&quickroom,sizeof(struct quickroom),1,fp);

	/* make the remaining rooms blanks */
	strcpy(quickroom.QRname,"");
	quickroom.QRflags=0;
	for (a=3; a<MAXROOMS; ++a) {
		printf("setup: creating quickroom %-3d\r",a);
		fwrite(&quickroom,sizeof(struct quickroom),1,fp);
		}
	fclose(fp);

	/* Create directories and fullroom files */
	system("mkdir rooms");
	for (a=0; a<MAXROOMS; ++a) {
		printf("setup: creating fullroom %-4d\n",a);
		sprintf(aaa,"./rooms/fullrm%d",a);
		fp=fopen(aaa,"wb");
		fwrite(&fullroom,sizeof(struct fullroom),1,fp);
		fclose(fp);
		}
}

cre8clog() {
	int file,a;
	struct calllog calllog;

	calllog.CLfullname[0]=0;
	calllog.CLtime=0L;
	calllog.CLflags=0;
	a=0;

	file=creat("calllog.pos",0666);
	chmod("calllog.pos",0666);
	write(file,&a,2);
	close(file);

	file=creat("calllog",0666);
	chmod("calllog",0666);
	for (a=0; a<CALLLOG; ++a) {
		printf("setup: creating call log #%-4d\r",a);
		write(file,&calllog,sizeof(struct calllog));
		}
	close(file);
	return(0);
}
SHAR_EOF
fi
echo shar: "extracting 'stats.c'" '(6446 characters)'
if test -f 'stats.c'
then
	echo shar: "will not over-write existing file 'stats.c'"
else
cat << \SHAR_EOF > 'stats.c'
/* Citadel/UX call log stats program
 * version 1.01
 */
#include <fcntl.h>
#include <time.h>
#include <curses.h>
#include "citadel.h"

long lseek();

halfhour(time)	/* Returns half-hour time period of time */
long time; {
	int a;
	struct tm *tm;
	tm=(struct tm *)localtime(&time);
	a=(tm->tm_hour)*2;
	if ((tm->tm_min)>29) ++a;
	return(a);
	}
	
main() {
	struct calllog calllog;
	int file,pos,a,b;
	float p,q;
	long timeon[48];
	long timeup[48];
	char dname[30];
	long cftime,cttime,aa;
	int calls,calls300,calls1200,calls2400,console,logins,newusers,noncon;
	int badpws,terms,drops,sleeps;
	long from,to,tottime;
	int days,hours,minutes;
	char aaa[100];
	struct tm *tm;
	char *tstring;

	initscr();
	clear();
	move(10,20);
	standout();
	addstr("Scanning call log, please wait...");
	standend();
	refresh();

	file=open("calllog.pos",O_RDONLY);
	read(file,&pos,2);
	close(file);
	from=0L; to=0L;
	for (a=0; a<48; ++a) { timeon[a]=0L; timeup[a]=0L; }
	cftime=0L; cttime=0L;

	calls=0; calls300=0; calls1200=0; console=0; logins=0; newusers=0;
	badpws=0; terms=0; drops=0; sleeps=0; noncon=0;
	file=open("calllog",O_RDONLY);
	lseek(file,(long)(pos*sizeof(struct calllog)),0);
	for (a=0; a<CALLLOG; ++a) {
		if ((a+pos)==CALLLOG) lseek(file,0L,0);
		read(file,&calllog,sizeof(struct calllog));
	if (calllog.CLflags!=0) {
		if ((calllog.CLtime<from)||(from==0L)) from=calllog.CLtime;
		if ((calllog.CLtime>to)||(to==0L)) to=calllog.CLtime;
		strcpy(aaa,"");
if (calllog.CLflags&CL_IN300)	{ ++calls; ++calls300; cftime=calllog.CLtime; 
					++noncon;
				  strcpy(dname,calllog.CLfullname); }
if (calllog.CLflags&CL_IN1200)	{ ++calls; ++calls1200; cftime=calllog.CLtime;
					++noncon;
				  strcpy(dname,calllog.CLfullname); }
if (calllog.CLflags&CL_IN2400)	{ ++calls; ++calls2400; cftime=calllog.CLtime;
					++noncon;
				  strcpy(dname,calllog.CLfullname); }
if (calllog.CLflags&CL_INOTHER)	{ ++calls; ++console; }
if (calllog.CLflags&CL_LOGIN)	++logins;
if (calllog.CLflags&CL_NEWUSER)	++newusers;
if (calllog.CLflags&CL_BADPW)	++badpws;
if (calllog.CLflags&CL_TERMINATE) { ++terms; cttime=calllog.CLtime; 
	if ((cftime!=0L)&&(cttime!=0L)&&(!strcmp(dname,calllog.CLfullname)))
		for (aa=cftime; aa<=cttime; aa=aa+300L)
			timeon[halfhour(aa)]=timeon[halfhour(aa)]+5L;
	cftime=0L; cttime=0L;
}
if (calllog.CLflags&CL_DROPCARR) { ++drops; cttime=calllog.CLtime; 
	if ((cftime!=0L)&&(cttime!=0L)&&(!strcmp(dname,calllog.CLfullname)))
		for (aa=cftime; aa<=cttime; aa=aa+300L)
			timeon[halfhour(aa)]=timeon[halfhour(aa)]+5L;
	cftime=0L; cttime=0L;
}
if (calllog.CLflags&CL_SLEEPING) { ++sleeps; cttime=calllog.CLtime;
	if ((cftime!=0L)&&(cttime!=0L)&&(!strcmp(dname,calllog.CLfullname)))
		for (aa=cftime; aa<=cttime; aa=aa+300L)
			timeon[halfhour(aa)]=timeon[halfhour(aa)]+5L;
	cftime=0L; cttime=0L;
}


		}
		}
	close(file);
	tottime=to-from;
	days=(int)(tottime/86400L);
	hours=(int)((tottime%86400L)/3600L);
	minutes=(int)((tottime%3600L)/60L);

	clear();
	move(3,3);	addstr("300 bps calls:");
	move(4,2);	addstr("1200 bps calls:");
	move(5,2);	addstr("2400 bps calls:");
	move(6,3);	addstr("Console calls:");
	move(7,10);	addstr("Logins:");
	move(8,7);	addstr("New users:");
	move(9,1);	addstr("Bad pw attempts:");
	move(10,2);	addstr("Proper logoffs:");
	move(11,3);	addstr("Carrier drops:");
	move(12,2);	addstr("Sleeping drops:");
	move(13,5);	addstr("TOTAL CALLS:");
	move(14,1);	addstr("Non-Console Calls:");
	refresh();
	move(2,43);	addstr("Total");
	move(2,33);	addstr("Avg/Day");
	move(2,23);	addstr("Avg/Call");
	move(18,19);	addstr("From:");
	move(19,21);	addstr("To:");
	move(20,6);	addstr("Total report time:");
	move(21,12);	addstr("Total calls:");
	refresh();

	move(21,25);	printw("%d",calls);
	move(3,41);	printw("%9d",calls300);
	move(4,41);	printw("%9d",calls1200);
	move(5,41);	printw("%9d",calls2400);
	move(6,41);	printw("%9d",console);
	move(7,41);	printw("%9d",logins);
	move(8,41);	printw("%9d",newusers);
	move(9,41);	printw("%9d",badpws);
	move(10,41);	printw("%9d",terms);
	move(11,41);	printw("%9d",drops);
	move(12,41);	printw("%9d",sleeps);
	move(13,41);	printw("%9d",calls);
	move(14,41);	printw("%9d",noncon);
	refresh();

	move(3,31);	printw("%9.1f",(float)calls300/days);
	move(4,31);	printw("%9.1f",(float)calls1200/days);
	move(5,31);	printw("%9.1f",(float)calls2400/days);
	move(6,31);	printw("%9.1f",(float)console/days);
	move(7,31);	printw("%9.1f",(float)logins/days);
	move(8,31);	printw("%9.1f",(float)newusers/days);
	move(9,31);	printw("%9.1f",(float)badpws/days);
	move(10,31);	printw("%9.1f",(float)terms/days);
	move(11,31);	printw("%9.1f",(float)drops/days);
	move(12,31);	printw("%9.1f",(float)sleeps/days);
	move(13,31);	printw("%9.1f",(float)calls/days);
	move(14,31);	printw("%9.1f",(float)noncon/days);
	refresh();

	move(3,21);	printw("%9.1f",(float)calls300/calls);
	move(4,21);	printw("%9.1f",(float)calls1200/calls);
	move(5,21);	printw("%9.1f",(float)calls2400/calls);
	move(6,21);	printw("%9.1f",(float)console/calls);
	move(7,21);	printw("%9.1f",(float)logins/calls);
	move(8,21);	printw("%9.1f",(float)newusers/calls);
	move(9,21);	printw("%9.1f",(float)badpws/calls);
	move(10,21);	printw("%9.1f",(float)terms/calls);
	move(11,21);	printw("%9.1f",(float)drops/calls);
	move(12,21);	printw("%9.1f",(float)sleeps/calls);
	move(13,21);	printw("%9.1f",(float)calls/calls);
	move(14,21);	printw("%9.1f",(float)noncon/calls);
	refresh();

	tm=(struct tm *)localtime(&from);
	tstring=(char *)asctime(tm);
	move(18,25);	addstr(tstring);
	tm=(struct tm *)localtime(&to);
	tstring=(char *)asctime(tm);
	move(19,25);	addstr(tstring);
	move(20,25);	printw("%d days, %d hours, %d minutes",
				days,hours,minutes);
	refresh();

	move(23,0);
	addstr("(please wait)");
	refresh();
	for (aa=from; aa<=to; aa=aa+1800L)
			timeup[halfhour(aa)]=timeup[halfhour(aa)]+30L;
	move(23,0);
	addstr("Press RETURN for system usage graph");
	move(0,0);
	refresh();
	gets(aaa);
	
	clear();
	move(21,6);
	addstr("0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2");
	move(22,6);
	addstr("0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3");
	for (a=0; a<21; ++a) {
		move(a,4);
		addch('%');
		}
	for (a=0; a<=20; ++a) {
		move(20-a,1);
		printw("%3d",a*5);
		}
	refresh();
	for (b=0; b<48; ++b) {
		for (a=0; a<=20; ++a) {
			p=((float)timeon[b])/((float)timeup[b])*20;
			q=(float)a;
			if (p>=q) {
				move(20-a,6+b);
				addch('*');
				}
			}
		refresh();
		}
	move(23,0);
	refresh();
	endwin();
	exit(0);
	}
SHAR_EOF
fi
echo shar: "extracting 'sysconfig.h'" '(3506 characters)'
if test -f 'sysconfig.h'
then
	echo shar: "will not over-write existing file 'sysconfig.h'"
else
cat << \SHAR_EOF > 'sysconfig.h'
/****************************************************************************/
/*                  YOUR SYSTEM CONFIGURATION                               */
/* Set all the values in this file appropriately BEFORE compiling any of the*/
/* C programs. If you are upgrading from an older version of Citadel/UX, it */
/* is vitally important that the #defines which are labelled "structure size*/
/* variables" are EXACTLY the same as they were in your old system,         */
/* otherwise your files will be munged beyond repair.                       */
/****************************************************************************/

/****************************************************************************/
/* Networking stuff
 * set NODENAME to your UUCP node name. Set PREVMSGS to the number of
 * records you want in the prevmsgs file, which keeps a record of recently
 * seen messages on all systems. This prevents messages from cycling
 * endlessly through the network. If you are not in a network, set PREVMSGS
 * to 2. If messages seem to be cycling endlessly through the network,
 * increase the value of PREVMSGS.
 */

#define NODENAME	"sysname"	/* Your system's uucp nodename      */
#define PREVMSGS	1000		/* Number of recs in prevmsgs file  */
/****************************************************************************/

#define BBSDIR		"/usr/bbs"
/* This is the directory Citadel will reside in. */

#define BBSUID		7
/* make an account called "bbs", "guest", or something to that effect which
 * shells directly to citadel. Place the userid of the account here. */

#define PWCRYPT		123
/* Set PWCRYPT to any value between 0 and 255 for password encryption. DO
 * NOT CHANGE IT ONCE IT IS SET or your users will all be locked out.
 */

#define CREATAIDE	0
/* If CREATAIDE is set to 1, anyone who creates a class 3 (passworded) or
 * class 4 (invitation-only) room automatically becomes the room-aide for
 * that room.
 */

#define SLEEPING	180
/* If the program is waiting for input more than SLEEPING number of seconds,
 * Citadel will print "Sleeping? Call again." and hang up. To disable the
 * feature, set SLEEPING to 0.
 */

#define INITAX		1
/* New users are assigned the access level of INITAX:
 * 0 = Marked for deletion
 * 1 = New User
 * 2 = Problem User
 * 3 = Local User
 * 4 = Network User
 * 5 = Preferred User
 * 6 = Aide
 * set this value to 4 for instant validation or 1 for validation required.
 */

#define REGISCALL	1
/* If a user has called REGISCALL times, he/she will be required to register.
 * Set this value to 0 to disable required registration.
 * NOTE: Citadel/UX still does not require user validation by the sysop.
 */

/*** STRUCTURE SIZE VARIABLES ***/
/* You may NOT change these six values once you set up your system.	    */
#define MAXROOMS	64		/* Number of rooms in system        */
#define MAILSLOTS	35		/* Number of mail slots             */
#define MSGSPERRM	150		/* Messages per room                */
#define MM_FILELEN	(2000000L)	/* Number of bytes in message file  */
#define CALLLOG		1000		/* Number of entries in call log    */
/* Do not set MAILSLOTS higher than MSGSPERRM 				    */
/*** END OF STRUCTURE SIZE VARIABLES ***/

#define TWITDETECT	1		/* 1=on, 0=off                      */
#define TWITROOM	"Trashcan"	/* Name of room to send problems to */
/* If TWITDETECT is set to 1, messages posted by those designated as
 * "problem users" will automatically be moved to TWITROOM regardless of
 * what room they were posted in.
 */
SHAR_EOF
fi
echo shar: "extracting 'sysoputil.c'" '(10343 characters)'
if test -f 'sysoputil.c'
then
	echo shar: "will not over-write existing file 'sysoputil.c'"
else
cat << \SHAR_EOF > 'sysoputil.c'
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "citadel.h"

#define ILIST 5000
#define CLN (5184000L)
#define RLN (1209600L)
#define BROWSE
	/* define BROWSE if the browse system is installed. */

/* Citadel/UX sysop utilities for release 3.01
 * The software assumes that if any user who has access to this program is
 * allowed to use the sysop utilities. Make sure that the permissions
 * are correct for this.
 */

long atol;
long lseek();

long finduser(file,name)
int file;
char name[];
{
	struct usersupp temp;
	int a;
	long bottom,top,guess,obottom,otop;

	obottom=(-1L); otop=(-1L);

	bottom=0L;
	top=(lseek(file,0L,2)/(long)sizeof(struct usersupp));

FPT:	if ((obottom==bottom)&&(otop==top)) {
		return(-1L); }
	obottom=bottom; otop=top;
	guess=(((top-bottom)/2)+bottom);
	lseek(file,(guess*(long)sizeof(struct usersupp)),0);
	read(file,&temp,sizeof(struct usersupp));
	a=strucmp(temp.fullname,name);
	if (a==0)
		
		return(lseek(file,(guess*(long)sizeof(struct usersupp)),0));
	if (a<0) {
		bottom=guess;
		goto FPT; }
	if (a>0) {
		top=guess;
		goto FPT; }
	return(0);
}

cls() {
	return(system("clear"));
	}

main(argc,argv) 
int argc;
char *argv[];
{
	int a;
	char aaa[100];

	chdir(BBSDIR);

	if (!strcmp(argv[1],"-u")) {
		userpurge();
		exit(0);
		}
	if (!strcmp(argv[1],"-r")) {
		roompurge();
		exit(0);
		}
	if (!strcmp(argv[1],"-g")) {
		readregis(1);
		exit(0);
		}

MAINMENU:
	cls();
	printf("\n\n");
	printf("              *** Citadel/UX Sysop Utilities ***\n");
	printf(
	"(aide access and /etc/passwd attachments are now in useradmin)\n\n");
	printf(" 1. Purge old rooms\n");
	printf(" 2. Read registration file (user num, street, city, phone)\n");
	printf(" 3. Delete a user\n");
	printf(" 4. Unlock message file\n");
	printf(" 5. \n");
	printf(" 6. Sort the userlog\n");
	printf(" 7. Purge old users\n");
	printf(" 8. Change casing of a user's name\n");
	printf(" 9. Quit\n");
	printf(" Please enter your selection: ");
	gets(aaa);
	a=atoi(aaa);

	switch(a) {
	   case 1:	roompurge();
			break;
	   case 2:	readregis(0);
			break;
	   case 3:	deluser();
			break;
	   case 4:	unlock();
			break;
	   case 6:	sortlog("usersupp");
			break;
	   case 7:	userpurge();
			break;
	   case 8:	renameuser();
			break;
	   case 9:	exit(0);
	   default:	goto MAINMENU;
	   }
	goto MAINMENU;
	}

deluser(argc,argv)
int argc;
char *argv[]; {
int a,b,file,file2;
char dme[100];
struct usersupp usersupp;

printf("Name of user to delete? ");
gets(dme);

file=open("usersupp",O_RDONLY);
if (file<0) {
	printf("No usersupp file available.\n");
	return(1); }
file2=creat("usersupp.new",0666);
if (file<0) {
	printf("Can't open the new file.\n");
	close(file);
	return(2); }
A:	a=read(file,&usersupp,sizeof(struct usersupp));
	if (a<1) goto END;
	if (!strucmp(dme,usersupp.fullname)) goto B;
	b=write(file2,&usersupp,sizeof(struct usersupp));
	if (b<1) printf("Can't rewrite!!!\n");
	goto A;

B:	printf("%s removed\n",
		usersupp.fullname);
	goto A;

END:	close(file);
	close(file2);
	printf("                                        ");
	printf("                                   \n");
	system("mv usersupp.new usersupp");
	system("chmod 666 usersupp");
	return(0);
}
/* The msgmain file is locked through the MMstructure file during writes,
 * to avoid two processes writing in the same place. If the program crashes
 * while the file is locked, run this program to unlock it.
 */

unlock() {

	struct msgmain msgmain;
	FILE *fp;

fp=fopen("MMstructure","rb");
fread(&msgmain,sizeof(struct msgmain),1,fp);
msgmain.MMflags = msgmain.MMflags & ~MM_BUSY;
fclose(fp);
fp=fopen("MMstructure","wb");

fwrite(&msgmain,sizeof(struct msgmain),1,fp);

fclose(fp);

return(0);
}

sortlog(filename)
char *filename; {
	char aaa[100];
	struct usersupp rec1;
	struct usersupp rec2;
	int file;
	long aa,cc,dd,nrecs;

	system("clear");
	printf("6. Sort the userlog\n");
	printf("--- this will take a long time, and if it is stopped\n");
	printf("before it is finished, the userlog will be screwed up!\n");
	printf("Enter password, or <return> to abort: ");
	gets(aaa);
	if (strucmp(aaa,"ledatic")) return(1);
	sprintf(aaa,"cp %s usersupp.bak",filename);
	system(aaa);
	file=open(filename,O_RDWR);
	if (file<0) return(file);
	aa=lseek(file,0L,2); nrecs=(aa/sizeof(struct usersupp));
	for (cc=0; cc<nrecs; ++cc) {
		printf("Sorted %5d of %5d records.\n",cc,nrecs);
		for (dd=(nrecs-1L); dd>cc; --dd) {
			aa=((dd-1L)*sizeof(struct usersupp));
			lseek(file,aa,0);
			read(file,&rec1,sizeof(struct usersupp));
			read(file,&rec2,sizeof(struct usersupp));
			if (strucmp(rec1.fullname,rec2.fullname)>0) {
				lseek(file,aa,0);
				write(file,&rec2,sizeof(struct usersupp));
				write(file,&rec1,sizeof(struct usersupp));
				}
			}
		}
	close(file);
	return(0);
}

strucmp(st1,st2)
char *st1;
char *st2; {
	char aaa[100],bbb[100];
	int a;
	strcpy(aaa,st1);
	strcpy(bbb,st2);
	for (a=0; a<strlen(aaa); ++a) aaa[a]=tolower(aaa[a]);
	for (a=0; a<strlen(bbb); ++a) bbb[a]=tolower(bbb[a]);
	a=strcmp(aaa,bbb);
	return(a);
}

userpurge() {	/* removes anyone who hasn't called in 2 months */
int a,b,c,d,file,file2;
char aaa[100],bbb[100];
char dme[100];
long inlist[ILIST];
struct usersupp usersupp;
struct registration regis;
long now,call;
FILE *post;

for (a=0; a<ILIST; ++a) inlist[a]=0L;
c=0;
post=(FILE *)popen("aidepost","w");
fprintf(post,"Program: sysoputil userpurge() / Shell user = %s\n",logname());
fprintf(post,"The following users have not called in the past %ld seconds\n",
		CLN);
fprintf(post,"or have been marked for deletion, and have been purged:\n");
time(&now);
file=open("usersupp",O_RDONLY);
if (file<0) {
	printf("No usersupp file available.\n");
	return(1);
	}
file2=creat("usersupp.new",0666);
if (file<0) {
	printf("Can't open the new file.\n");
	close(file);
	return(2);
	}
	read(file,&usersupp,sizeof(struct usersupp));
	write(file2,&usersupp,sizeof(struct usersupp));
	while (read(file,&usersupp,sizeof(struct usersupp))>0) {
		call=now-(usersupp.lastcall);
		strcpy(aaa,usersupp.password);
		pwcrypt(aaa,PWCRYPT);
		if (!strucmp(aaa,"deleteme")) call=CLN+1L;
		if (usersupp.axlevel==0) call=CLN+2L;
		printf("\r%20ld ",call);
		if ((call<=CLN)||(usersupp.flags&US_PERM)) {
			b=write(file2,&usersupp,sizeof(struct usersupp));
			if (b<1) fprintf(stderr,"userpurge: cannot rewrite\n");
			inlist[c]=usersupp.eternal; ++c;
			}
		else {
			printf("%s removed\n",usersupp.fullname);
			fprintf(post,"#%-5ld %-30s\n",usersupp.eternal,
				usersupp.fullname);
			}
		}
END:	close(file);
	close(file2);
	pclose(post);
	system("mv usersupp.new usersupp");
	chmod("usersupp",0666);
	printf("Purging registration...\n");
	file=open("registration",O_RDONLY);
	file2=creat("regis.new",0666);
	while(read(file,&regis,sizeof(struct registration))>0) {
		for (a=0; a<c; ++a) if (inlist[a]==regis.RGeternal) 
			write(file2,&regis,sizeof(struct registration));
		printf("\n");
		}
	close(file);
	close(file2);
	system("mv regis.new registration");
#ifdef BROWSE
	printf("Purging browse files...\n");
	system("mkdir /tmp/browse");
	for (a=0; a<c; ++a) {
		sprintf(aaa,"subsysdir/browsedir/%ld",inlist[a]);
		sprintf(bbb,"/tmp/browse/%ld",inlist[a]);
		link(aaa,bbb);
		}
		system("rm subsysdir/browsedir/*");
		system("mv /tmp/browse/* subsysdir/browsedir");
		system("rm -r /tmp/browse");
#endif
	return(0);
}


roompurge() {	/* remove any rooms which have not been accessed in 2 weeks */
	int file,a,b;
	char fname[50];
	long act,now;
	FILE *post;
	struct stat sbuf;
	struct quickroom quickroom;

	post=(FILE *)popen("aidepost","w");
	fprintf(post,
		"Program: sysoputil roompurge() / Shell user = %s\n",logname());
	fprintf(post,
		"The following rooms have not been used for %ld seconds\n",RLN);
	fprintf(post,"and have been deleted from the room files:\n");
	time(&now);

	file=open("quickroom",O_RDWR);
	for (a=0; a<MAXROOMS; ++a) {
		sprintf(fname,"./rooms/fullrm%d",a);
		b=stat(fname,&sbuf);
		act=now-(long)sbuf.st_mtime;
		read(file,&quickroom,sizeof(struct quickroom));
		if ((a>2)&&(quickroom.QRflags&QR_INUSE)&&(act>RLN)&&(b>=0)
			&&((quickroom.QRflags&QR_NETWORK)==0)
			&&((quickroom.QRflags&QR_DIRECTORY)==0)) {

			quickroom.QRflags=quickroom.QRflags-QR_INUSE;
			lseek(file,(long)a*sizeof(struct quickroom),0);
			write(file,&quickroom,sizeof(struct quickroom));
			printf("%20s deleted\n",quickroom.QRname,act);
			fprintf(post,"%s\n",quickroom.QRname);
			}	
		}
	close(file);
	pclose(post);
	return(0);
	}


renameuser() {
	long aa;
	int file;
	struct usersupp user;
	char aaa[100];
	long finduser();

	printf("Enter old name: ");
	gets(aaa);
	file=open("usersupp",O_RDWR);
	aa=finduser(file,aaa);
	if (aa==(-1L)) {
		printf("No such user.\n");
		close(file);
		return(0); }
	read(file,&user,sizeof(struct usersupp));
	printf("Enter new name EXACTLY as it should appear: ");
	gets(user.fullname);
	if (strucmp(aaa,user.fullname)) {
		printf("You may only change casing. Rename not allowed\n");
		close(file);
		return(1);
		}

	finduser(file,aaa);
	write(file,&user,sizeof(struct usersupp));
	close(file);
	return(0);
}

readregis(mode)
int mode; {
	struct registration regis;
	int file,a,b;
	char pbuf[11];
	
	file=open("registration",O_RDONLY);
	if (file<0) {
		fprintf(stderr,"sysoputil: cannot open registration file\n");
		return(1);
		}

	if (mode==0) cls();
	while(read(file,&regis,sizeof(struct registration))>0) {
		strcpy(pbuf,regis.RGphone);
		regis.RGphone[0]=0;
		for (a=0; a<strlen(pbuf); ++a) {
			if ((pbuf[a]>='0')&&(pbuf[a]<='9')) {
				b=strlen(regis.RGphone);
				regis.RGphone[b]=pbuf[a];
				regis.RGphone[b+1]=0;
				}
			}
		while(strlen(regis.RGphone)<10) {
			strcpy(pbuf,regis.RGphone);
			strcpy(regis.RGphone," ");
			strcat(regis.RGphone,pbuf);
			}
		printf("#%4ld %-29s %14s, %-2s %6s ",
			regis.RGeternal,regis.RGname,
			regis.RGcity,regis.RGstate,regis.RGzip);
		printf("(%c%c%c) %c%c%c-%c%c%c%c\n",
			regis.RGphone[0],regis.RGphone[1],regis.RGphone[2],
			regis.RGphone[3],regis.RGphone[4],regis.RGphone[5],
			regis.RGphone[6],regis.RGphone[7],regis.RGphone[8],
			regis.RGphone[9]);
		}
	close(file);
	if (mode==0) {
		printf("<press return to continue>\n");
		gets(pbuf);
		}
	return(0);
	}

pwcrypt(text,code)
char text[];
int code; {
	int a;
	for (a=0; a<strlen(text); ++a) text[a]=(text[a]^(((code|128)^a)&0xFF));
	return(0);
	}
SHAR_EOF
fi
echo shar: "done with directory 'source'"
cd ..
exit 0
#	End of shell archive
-- 
     Some do, some don't.           |       eric@sactoh0.SAC.CA.US
    Some will, some won't.          |      ames!pacbell!sactoh0!eric
          I might!                  |      ucbvax!csusac!sactoh0!eric
                                    |     ( A Home For Unwanted 3B's )