/* 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();
extern struct config config;
char *getenv();
long atol();
long lseek();

extern char *axdefs[7];

int struncmp(lstr,rstr,len)
char lstr[],rstr[];
int len; {
	int pos = 0;
	char lc,rc;
	while (pos<len) {
		lc=tolower(lstr[pos]);
		rc=tolower(rstr[pos]);
		if ((lc==0)&&(rc==0)) return(0);
		if (lc<rc) return(-1);
		if (lc>rc) return(1);
		pos=pos+1;
		}
	return(0);
	}

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

yesno_d(d) /* Returns 1 for yes, 0 for no, arg is default value */
int d; {
int a;
	while (1) {
		a=inkey(); a=tolower(a);
		if (a==13) a=(d ? 'y' : 'n');
		if (a=='y') { printf("Yes\n"); return(1); }
		if (a=='n') { printf("No\n");  return(0); }
		}
	}


hit_any_key() {		/* hit any key to continue */
	int a;
	printf("%s\r",MORE_PROMPT);
	a=inkey();
	for (a=0; a<strlen(MORE_PROMPT); ++a)
		putc(' ',stdout);
	putc(13,stdout);
	}


edituser(userbuf)
struct usersupp *userbuf; {
	int a,b;
do {	printf("Current access level: %d [%s]\n",userbuf->axlevel,
		axdefs[userbuf->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);
	userbuf->axlevel=a;
	return(0);
	}

toggle_expert_mode(userbuf)
struct usersupp *userbuf; {
	if (userbuf->flags & US_EXPERT) {
		userbuf->flags = (userbuf->flags ^ US_EXPERT);
		printf("Expert mode now OFF\n");
		}
	else {
		userbuf->flags = (userbuf->flags | US_EXPERT);
		printf("Expert mode now ON\n");
		}
	}


set_user_attr(userbuf,prompt,sbit)
struct usersupp *userbuf;
char *prompt;
unsigned sbit; {
	int a;
	printf("%45s [%3s]? ",prompt,(((userbuf->flags)&sbit) ? "Yes":"No"));
	a=yesno_d(userbuf->flags&sbit);
	userbuf->flags=((userbuf->flags)|sbit);
	if (!a) userbuf->flags=(userbuf->flags^sbit);
	return(0);
	}

getusinfo(userbuf)
struct usersupp *userbuf; {
	userbuf->USscreenwidth = intprompt(
		"Enter your screen width",userbuf->USscreenwidth,20,255);
	userbuf->USscreenheight = intprompt(
		"Enter your screen height",userbuf->USscreenheight,3,255);
	set_user_attr(userbuf,
		"Are you an experienced Citadel user",US_EXPERT);
	if (((userbuf->flags&US_EXPERT)==0)&&(userbuf->timescalled==0))
		return(0);
	set_user_attr(userbuf,
		"Print last old message on New message request",US_LASTOLD);
	if ((userbuf->flags&US_EXPERT)==0) formout("messages/unlisted");
	set_user_attr(userbuf,"Be unlisted in userlog",US_UNLISTED);
	set_user_attr(userbuf,"Suppress message prompts",US_NOPROMPT);
	if ((userbuf->flags & US_NOPROMPT)==0)
	    set_user_attr(userbuf,"Use 'disappearing' prompts",US_DISAPPEAR);
	set_user_attr(userbuf,
		"Pause after each screenful of text",US_PAGINATOR);
	return(0);
}

/*
 * getstring()  -  get a line of text from a file
 *		   ignores lines beginning with "#"
 */
getstring(fp,string)
FILE *fp;		
char string[]; {
	int a,c;
	do {
		strcpy(string,"");
		a=0;
		do {
			c=getc(fp);
			if (c<0) {
				string[a]=0;
				return(-1);
				}
			string[a++]=c;
			} 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;
{
	char flnm[256];
	char comment[100];
	char tname[100];
	struct stat statbuf; long aa;
	FILE *filedir;
	FILE *ls;
	sprintf(tname,"ls %s",path);
	ls=(FILE *)popen(tname,"r"); if (ls==NULL) return(1);
	printf("-----------------------\n");
	while (fgets(flnm,256,ls)!=NULL) {
		flnm[strlen(flnm)-1]=0;
		sprintf(tname,"%s/%s",path,flnm);
		stat(tname,&statbuf);
		aa=(long)statbuf.st_size;
		if (strcmp(flnm,"filedir")) {
			sprintf(tname,"%s/filedir",path);
			filedir=fopen(tname,"r");
			strcpy(comment,flnm);
			strcat(comment,"   ");
			if (filedir!=NULL) {
				while (fgets(tname,100,filedir)!=NULL) {
				   if ((!struncmp(tname,flnm,strlen(flnm)))
					&& (isspace(tname[strlen(flnm)])) ){
						tname[strlen(tname)-1]=0;
						strcpy(comment,tname);
						}
					}
				fclose(filedir);
				}
		    if (strlen(flnm)<=14)
		    	printf("%-14s %8ld %s\n",
				flnm,aa,&comment[strlen(flnm)+1]);
		    else
			printf("%s\n%14s %8ld %s\n",
				flnm,"",aa,&comment[strlen(flnm)+1]);
			}
		}
	pclose(ls);
	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);
	}


int checkpagin(lp,pagin,height)
int lp;
int pagin; {
	if (pagin!=1) return(0);
	if (lp>=(height-1)) {
		hit_any_key();
		return(0);
		}
	return(lp);
	}

fmout(width,fp,pagin,height)
int width;
FILE *fp;
char pagin;
	{
	int a,b,c,real,old;
	char aaa[140];
	int lines_printed = 0;
	
	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==13)||(a==10)) && (old!=13) && (old!=10) ) a=32;
	if ( ((old==13)||(old==10)) && (isspace(real)) ) {
		printf("\n");
		++lines_printed;
		lines_printed = checkpagin(lines_printed,pagin,height);
		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;
		++lines_printed;
		lines_printed = checkpagin(lines_printed,pagin,height);
		}
	 b=strlen(aaa); aaa[b]=a; aaa[b+1]=0; }
	if (a==32) {
		if ((strlen(aaa)+c)>(width-5)) { 
			printf("\n");
			c=1;
			++lines_printed;
			lines_printed = checkpagin(lines_printed,pagin,height);
			}
		printf("%s ",aaa); ++c; c=c+strlen(aaa);
		strcpy(aaa,"");
		goto FMTA;
		}
	if ((a==13)||(a==10)) {
		printf("%s\n",aaa);
		c=1;
		++lines_printed;
		lines_printed = checkpagin(lines_printed,pagin,height);
		strcpy(aaa,"");
		goto FMTA;
		}
	goto FMTA;

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

strproc(string)
char string[];
{
	int a;

	if (strlen(string)==0) return(0);

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

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

	/* Remove double blanks */
	for (a=0; a<strlen(string); ++a) {
		if ((string[a]==32)&&(string[a+1]==32)) {
			strcpy(&string[a],&string[a+1]);
			a=0;
			}
		}

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

	return(0);
	}


int hash(str)
char str[]; {
	int h = 0;
	int i;

	for (i=0; i<strlen(str); ++i) h=h+((i+1)*tolower(str[i]));
	return(h);
	}

long finduser(file,name)
int file;
char *name; {
	FILE *fp;
	int uh,fh;
	long pp=0L;
	
	uh=hash(name);
	fp=fopen("hashtab","r");
	while(fread((char *)&fh,sizeof(int),1,fp)>0) {
		if (uh==fh) {
			lseek(file,pp,0);
			return(pp);
			}
		pp = pp + (long)sizeof(struct usersupp);
		}
	fclose(fp);
	return(-1L);
	}

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

	file=eopen("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,(char *)ttyname(0));
	ioctl(0,TCGETA,&stty);
	if ((stty.c_cflag&B300)==B300)		temp.CLflags=CL_IN300;
	else if ((stty.c_cflag&B1200)==B1200)	temp.CLflags=CL_IN1200;
	else if ((stty.c_cflag&B2400)==B2400)	temp.CLflags=CL_IN2400;
	else					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);
	for (a=0; a<strlen(name); ++a)
		if (name[a]=='@')
			for (b=a; b<strlen(name); ++b)
				if (name[b]=='.') 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]);
		fp = fopen("network/mail.sysinfo","r");
		if (fp==NULL) return(M_ERROR);
GETSN:		do {
			a=getstring(fp,aaa);
			} while ((a>=0)&&(strucmp(aaa,bbb)));
		a=getstring(fp,aaa);
		if (!strncmp(aaa,"use ",4)) {
			strcpy(bbb,&aaa[4]);
			fseek(fp,0L,0);
			goto GETSN;
			}
		fclose(fp);
		if (!strncmp(aaa,"uum",3)) {
			strcpy(bbb,name);
			for (a=0; a<strlen(bbb); ++a) {
				if (bbb[a]=='@') bbb[a]=0;
				if (bbb[a]==' ') bbb[a]='_';
				}
			while(bbb[strlen(bbb)-1]=='_') bbb[strlen(bbb)-1]=0;
			sprintf(name,&aaa[4],bbb);
			return(M_UUCP);
			}
		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);
			}
		return(M_ERROR);
		}
	return(M_LOCAL);
	}

clearcon(void)
{

	if(getenv(TERM)=="vt100")
		printf("");
	else
	if(getenv(TERM)=="ansi")
		printf("");
	else
		printf("");
}