/* 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 struct config config;
extern char temp[];
extern char *axdefs[7];
extern long highest_msg_read;

extern int errno;

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


sort_fullroom(frptr)
struct fullroom *frptr; {
	int a,b;
	long hold;
	for (a=MSGSPERRM-2; a>=0; --a) {
		for (b=0; b<=a; ++b) {
			if ((frptr->FRnum[b]) > (frptr->FRnum[b+1])) {
				hold = frptr->FRnum[b];
				frptr->FRnum[b] = frptr->FRnum[b+1];
				frptr->FRnum[b+1] = hold;
				hold = frptr->FRpos[b];
				frptr->FRpos[b] = frptr->FRpos[b+1];
				frptr->FRpos[b+1] = hold;
				}
			}
		}
	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);
	}

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);
	}

void entregis(is_rereg)	/* register with name and address */
int is_rereg; {
	char buf[15];
	int a;

	readyerself();

	if (is_rereg == NEWREGISTER) {
		strcpy(usersupp.USname,"");
		strcpy(usersupp.USaddr,"");
		strcpy(usersupp.UScity,"");
		strcpy(usersupp.USstate,"");
		strcpy(usersupp.USzip,"");
		strcpy(usersupp.USphone,"");
		}

	strprompt("REAL name",usersupp.USname,29);
	strprompt("Address",usersupp.USaddr,24);
	strprompt("City/town",usersupp.UScity,14);
	strprompt("State",usersupp.USstate,2);
	strcpy(buf,usersupp.USzip);
	strprompt("ZIP Code",buf,10);
	for (a=0; a<strlen(buf); ++a)
		if ((buf[a]<'0')||(buf[a]>'9')) {
			strcpy(&buf[a],&buf[a+1]);
			a=0;
			}
	buf[9]=0;
	strcpy(usersupp.USzip,buf);
	strcpy(buf,usersupp.USphone);
	strprompt("Telephone number",buf,14);
	for (a=0; a<strlen(buf); ++a)
		if ((buf[a]<'0')||(buf[a]>'9')) {
			strcpy(&buf[a],&buf[a+1]);
			a=0;
			}
	buf[10]=0;
	strcpy(usersupp.USphone,buf);
	printf("\n");
	
	writeyerself();
	lock_valid();
	}

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();
}

updatelsa() {   /* only make messages old in this room that have been read */
	readyerself();
	storeug();
	usersupp.lastseen[curr_rm]=highest_msg_read;
	writeyerself();
	}

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


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);
			}
	if (usersupp.axlevel < 3) {
		printf("Need higher access to upload.\n");
		return(1);
		}

	newprompt("Enter filename: ",aaa,15);
	for (a=0; a<strlen(aaa); ++a)
		if ( (aaa[a]=='/') || (aaa[a]=='\\') || (aaa[a]=='>')
		     || (aaa[a]=='?') || (aaa[a]=='*')
		     || (aaa[a]==';') || (aaa[a]=='&') ) aaa[a]='_';
	sprintf(bbb,"./files/%s/%s",quickroom.QRdirname,aaa);
	file = open(bbb,O_RDONLY);
	if (file>(-1)) {
		printf("'%s' already exists.\n",aaa);
		close(file); return(1);
		}
	newprompt("Enter a short description of the file:\n: ",buf,150);
	file=creat(bbb,0666);
	if (file<0) {
		printf("Can't create that file?\n");
		return(1); }
	if (c>0) {
		close(file);
		unlink(bbb);
		}

	set_wtmpsupp(aaa);		/* show that we're uploading */

	/* now do the transfer */
	switch(c) {
	 case 0:
		a=0;
		printf("Receiving %s - press Ctrl-D to end.\n",bbb);
		do {
			b=inkey(); 
			if (b==13) { b=10; printf("\r"); }
			if (b!=4) { printf("%c",b); write(file,&b,1); }
			} while(b!=4);
		close(file);
		a=0;
		break;
	 case 1:
		sprintf(bbb,"cd ./files/%s; exec rx %s",
			quickroom.QRdirname,aaa);
		a=system(bbb);
		break;
	 case 2:
		sprintf(bbb,"cd ./files/%s; exec rb",
			quickroom.QRdirname);
		a=system(bbb);
		break;
	 case 3:
		sprintf(bbb,"cd ./files/%s; exec rz",
			quickroom.QRdirname);
		a=system(bbb);
		break;
		}
	if (a==0) printf("*** Transfer successful.\n");
	else {
		printf("*** Transfer unsuccessful.\n");
		return(a);
		}
	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);
	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: '%s'\r %s\n",aaa,buf);
	putc(0,fp);
	fclose(fp);
	save_message(temp,buf,0,M_LOCAL);
	return(0);
}

move_message(pos,num)
long pos;
long num; {
	char targ[32];
	int file,a,h;
	struct quickroom qtemp;
	struct fullroom ftemp;
	h=curr_rm;
	do {
		curr_rm=(-1);
		newprompt("Enter target room: ",targ,19);
		if (targ[0]==0) {
			curr_rm = h;
			return(1);
			}
		file=eopen("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();
	sprintf(targ,"./rooms/fullrm%d",curr_rm);
	file=eopen(targ,O_RDWR);
	read(file,&ftemp,sizeof(struct fullroom));
	for (a=0; a<MSGSPERRM-1; ++a) {
		ftemp.FRnum[a]=ftemp.FRnum[a+1];
		ftemp.FRpos[a]=ftemp.FRpos[a+1];
		}
	ftemp.FRnum[MSGSPERRM-1] = num;
	ftemp.FRpos[MSGSPERRM-1] = pos;
	sort_fullroom(&ftemp);
	lseek(file,0L,0);
	write(file,&ftemp,sizeof(struct fullroom));
	close(file);
	file=eopen("quickroom",O_RDWR);
	lseek(file,(long)(curr_rm * sizeof(struct quickroom)),0);
	read(file,&qtemp,sizeof(struct quickroom));
	qtemp.QRhighest = ftemp.FRnum[MSGSPERRM-1];
	lseek(file,(long)(curr_rm * sizeof(struct quickroom)),0);
	write(file,&qtemp,sizeof(struct quickroom));
	close(file);
	
	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);
		}
	lock_msgmain();
	file=eopen("MMstructure",O_RDWR);
	read(file,&MMtemp,sizeof(struct msgmain));
	MMtemp.MMflags=MMtemp.MMflags&(~MM_VALID);
	lseek(file,0L,0);
	write(file,&MMtemp,sizeof(struct msgmain));
	close(file);
	unlock_msgmain();

	file=eopen("usersupp",O_RDWR);
	while(read(file,&UStemp,sizeof(struct usersupp))>0) {
		if (UStemp.flags & US_NEEDVALID) {
			printf("\n\n\nUser #%-5ld %s ",
			       UStemp.eternal,UStemp.fullname);
			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;
			UStemp.flags = (UStemp.flags & ~US_NEEDVALID);
			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; {
	char pbuf[15];
	int a,b;

	printf("%-29s\n",userdata->USname);
	printf("%-29s\n",userdata->USaddr);
	printf("%-14s %2s %6s\n",
		userdata->UScity,userdata->USstate,userdata->USzip);
	strcpy(pbuf,userdata->USphone);
	userdata->USphone[0]=0;
	for (a=0; a<strlen(pbuf); ++a) {
		if ((pbuf[a]>='0')&&(pbuf[a]<='9')) {
			b=strlen(userdata->USphone);
			userdata->USphone[b]=pbuf[a];
			userdata->USphone[b+1]=0;
			}
		}
	while(strlen(userdata->USphone)<10) {
		strcpy(pbuf,userdata->USphone);
		strcpy(userdata->USphone," ");
		strcat(userdata->USphone,pbuf);
		}

	printf("(%c%c%c) %c%c%c-%c%c%c%c\n",
		userdata->USphone[0],userdata->USphone[1],
		userdata->USphone[2],userdata->USphone[3],
		userdata->USphone[4],userdata->USphone[5],
		userdata->USphone[6],userdata->USphone[7],
		userdata->USphone[8],userdata->USphone[9]);
	return(0);
	}

subshell() {
	int a,b;
	a=fork();
	if (a==0) {
		sttybbs(SB_RESTORE);
		signal(SIGINT,SIG_DFL);
		signal(SIGQUIT,SIG_DFL);
		setuid(getuid());
		execlp("/bin/sh","/bin/sh",NULL);
		exit(0);
		}
	do {
		b=wait(NULL);
		} while ((a!=b)&&(a!=(-1)));
	sttybbs(0);
	return(0);
	}


void deletefile() {
	char pathname[64],filename[32];
	int a;
	newprompt("Filename: ",filename,31);
	if (strlen(filename)==0) return;
	for (a=0; a<strlen(filename); ++a)
		if (filename[a]=='/') filename[a] = '_';
	sprintf(pathname,"./files/%s/%s",quickroom.QRdirname,filename);
	a=unlink(pathname);
	if (a==0) printf("File '%s' deleted.\n",pathname);
	else printf("File '%s' not found.\n",pathname);
	return;
	}

void netsendfile() {
	char pathname[64],filename[32],destsys[20],buf[128];
	int a,e;
	long now;
	FILE *ifp,*ofp;
	newprompt("Filename: ",filename,31);
	if (strlen(filename)==0) return;
	for (a=0; a<strlen(filename); ++a)
		if (filename[a]=='/') filename[a] = '_';
	sprintf(pathname,"./files/%s/%s",quickroom.QRdirname,filename);
	if (access(pathname,0)!=0) {
		printf("File '%s' not found.\n",pathname);
		return;
		}
	newprompt("System to send to: ",destsys,19);
	sprintf(buf,"sysop@%s",destsys);
	e=alias(buf);
	if (e!=M_BINARY) {
		printf("Invalid system name.\n");
		return;
		}
	sprintf(buf,"./network/spoolin/nsf.%d",getpid());
	ofp=fopen(buf,"a");
	sprintf(buf,"cd ./files/%s; uuencode %s <%s",
		quickroom.QRdirname,filename,filename);
	ifp=popen(buf,"r");
	putc(255,ofp);
	putc(MES_NORMAL,ofp);
	putc(0,ofp);
	fprintf(ofp,"Pcit%ld",usersupp.eternal); putc(0,ofp);
	time(&now);
	fprintf(ofp,"T%ld",now); putc(0,ofp);
	fprintf(ofp,"A%s",usersupp.fullname); putc(0,ofp);
	fprintf(ofp,"O%s",quickroom.QRname); putc(0,ofp);
	fprintf(ofp,"N%s",NODENAME); putc(0,ofp);
	fprintf(ofp,"D%s",destsys); putc(0,ofp);
	fprintf(ofp,"SFILE"); putc(0,ofp);
	putc('M',ofp);
	while (a=getc(ifp), a>=0) putc(a,ofp);
	pclose(ifp);
	putc(0,ofp);
	fclose(ofp);
	printf("File '%s' has been sent to %s.\n",filename,destsys);
	system("nohup netproc >/dev/null 2>&1 &");
	return;
	}
