/*
 * Citadel/UX
 *
 * commands.c - front end for Citadel
 *
 * This version is the traditional command parser for room prompts.
 *
 */

#include <stdio.h>
#include <ctype.h>
#include <termio.h>
#include <signal.h>
#include "citadel.h"

#define IFAIDE if(usersupp.axlevel>=6)
#define IFNAIDE if (usersupp.axlevel<6)
#define IFNEXPERT if ((usersupp.flags&US_EXPERT)==0)
struct passwd *getpwuid();
long lseek();

extern struct usersupp usersupp;
extern int curr_rm;
extern struct quickroom quickroom;
extern struct config config;


void sleeping() {			/* called by alarm() */
	struct calllog rtmp;
	printf("Sleeping? Call again.\n");
	strcpy(rtmp.CLfullname,(char *)ttyname(0));
	rtmp.CLflags=CL_SLEEPING;
	rec_log(&rtmp);
	logoff(2);
	}

inkey() {		/* get a character from the keyboard, with   */
	int a;		/* the watchdog timer in effect if necessary */
	if (SLEEPING) signal(SIGALRM,sleeping);
	alarm((getppid()==1) ? SLEEPING : 0);
	do {
		a=getc(stdin);
		if (a==127) a=8;
		} while((a<1)||(a>126));
	signal(SIGALRM,SIG_IGN);
	return(a);
	}


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

/*
 * strprompt()  -  prompt for a string, print the existing value and
 *                 allow the user to press return to keep it...
 */
void strprompt(prompt,str,len)
char *prompt;
char *str;
int len; {
	char buf[128];
	printf("%s [%s]: ",prompt,str);
	getline(buf,len);
	if (buf[0]!=0) strcpy(str,buf);
	}

/* 
 * intprompt()  -  like strprompt(), except for an integer
 *                 (note that it RETURNS the new value!)
 */
int intprompt(prompt,ival,imin,imax)
char *prompt;
int ival;
int imin;
int imax; {
	char buf[16];
	int i;
	i = ival;
	do {
		sprintf(buf,"%d",i);
		strprompt(prompt,buf,15);
		i=atoi(buf);
		if (i<imin) printf("*** Must be no less than %d.\n",imin);
		if (i>imax) printf("*** Must be no more than %d.\n",imax);
		} while((i<imin)||(i>imax));
	return(i);
	}

/* 
 * newprompt()  -  prompt for a string with no existing value
 *                 (clears out string buffer first)
 */
void newprompt(prompt,str,len)
char *prompt;
char *str;
int len; {
	printf("%s",prompt);
	getline(str,len);
	}


int lkey() {	/* returns a lower case value */
	int a;
	a=inkey();
	if (isupper(a)) a=tolower(a);
	return(a);
	}

/*
 * This routine is called to get and parse a command.
 * It returns the command number.  If the command also requires an
 * argument (like .Goto: or .Help: etc.) it will be placed in strbuf.
 */
int getcmd(strbuf)
char *strbuf; {

char *logstr;

	int a,b,c,d;
	strcpy(strbuf,"");

	/* if we're running in idiot mode, display a cute little menu */
	IFNEXPERT {
		if(isansi())
			formout("messages/mainmenu.ansi");
		else
			formout("messages/mainmenu");
		}

/* now the room prompt... */
printf("\n%s%c ",quickroom.QRname,room_prompt(&quickroom));

 while (1) {
  a=lkey();
/*  sprintf(logstr,"%c\0",a); */
  logint(a);
  IFNAIDE if (a=='!') a=0;
  if (a=='?') a='h';
  switch(a) {
   case 'h':	printf("Help\n");
		return(1);
   case '*':	printf("Doorway\n");
		return(2);
   case 'c':	printf("Chat\n");
		return(3);
   case 'e':	printf("Enter message\n");
		return(DEFAULT_ENTRY);
   case 'g':	printf("Goto\n");
		return(5);
   case 's':	printf("Skip %s\n",quickroom.QRname);
		return(6);
   case 'z':	printf("Zap (forget) room\n");
		return(7);
   case 'k':	printf("Known rooms\n");
		return(8);
   case 'l':	printf("Last five msgs\n");
		return(9);
   case 'f':	printf("Forward read\n");
		return(10);
   case 'r':	printf("Reverse read\n");
		return(11);
   case 'o':	printf("Old msgs reverse\n");
		return(12);
   case 'n':	printf("New messages\n");
		return(13);
   case 'd':	printf("Directory\n");
		return(14);
   case 't':	printf("Terminate\n");
		return(15);
   case 'u':	printf("Ungoto\n");
		return(16);
   case 'w':	printf("Who is online\n");
		return(17);
   case 'a':	printf("Abandon room, goto...\n");
		return(47);
   case 'x':	printf("toggle eXpert mode\n");
		return(50);
   case '!':	printf("! <shell>\n");
		return(18);
   case '.': printf(".");
	     do {
		b=lkey();
if ((b=='a')&&(usersupp.axlevel<6)&&(quickroom.QRroomaide!=usersupp.eternal))
	b=0;
		switch(b) {
		   case 'z':	printf("Zapped list\n");
				return(19);
		   case 's':	printf("Skip this room, goto: ");
				getline(strbuf,19);
				return(52);
		   case 'g':	printf("Goto: ");
				getline(strbuf,19);
				return(20);
		   case 'h':	printf("Help: ");
				getline(strbuf,31);
				return(21);

/* start of aide options */
		   case 'a': printf("Aide ");
			     do {
				c=lkey();
IFNAIDE
    if ((c!='r')&&(c!='e')&&(c!='w')&&(c!='i')&&(c!='f')&&(c!='?')&&(c!=8))
	c=0;
				switch(c) {
				   case 'k':	printf("Kill this room\n");
						return(22);
				   case 'e':	printf("Edit this room\n");
						return(23);
				   case 'w':	printf("Who knows room\n");
						return(24);
				   case 'u':	printf("User edit\n");
						return(25);
				   case 'v':	printf("Validate new users\n");
						return(26);
				   case 'i':	printf("enter Info file\n");
						return(48);

/* start of room options */
				   case 'r': printf("Room cmd: ");
					     do {
						d=lkey();
						switch(d) {
					case 'i': printf("Invite user\n");
						  return(27);
					case 'k': printf("Kick out user\n");
						  return(28);
						  }
						} while(d!=8);
					     back(10);
					     break;
/* end of room options */

/* start of file options */
				   case 'f': printf("File cmd: ");
					     do {
						d=lkey();
						switch(d) {
					case 'd': printf("Delete file\n");
						  return(51);
						  }
					case 's': printf("Send over net\n");
						  return(53);
						} while(d!=8);
					     back(10);
					     break;
/* end of room options */

				   case '?':	printf("(options)\n");
						if(isansi())
							formout("messages/aideopt.ansi");
						else
							formout("messages/aideopt");
printf("%s%c .Aide ",quickroom.QRname,room_prompt(&quickroom));
					}
				} while(c!=8);
			     back(5);
			     break;
/* end of aide options */

/* start of terminate options */
		   case 't': printf("Terminate ");
			     do {
				c=lkey();
				switch(c) {
				   case 'q':	printf("and Quit\n");
						return(29);
				   case 's':	printf("and Stay online\n");
						return(30);
					}
				} while(c!=8);
			     back(10);
			     break;
/* end of terminate options */

/* start of read options */
		   case 'r': printf("Read ");
			     do {
				c=lkey();
				switch(c) {
				   case 'f':	printf("File unformatted\n");
						return(31);
				   case 'u':	printf("User listing\n");
						return(32);
				   case 't':	printf("Textfile paginated\n");
						return(33);
				   case 'x':	printf("file using Xmodem\n");
						return(34);
				   case 'y':	printf("file using Ymodem\n");
						return(43);
				   case 'z':	printf("file using Zmodem\n");
						return(45);
				   case 'n':	printf("New messages\n");
						return(13);
				   case 'o':	printf("Old msgs reverse\n");
						return(12);
				   case 'l':	printf("Last five msgs\n");
						return(9);
				   case 'd':	printf("Directory\n");
						return(14);
				   case 'i':	printf("Info file\n");
						return(49);
				   case '?':	printf("(options)\n");
						if(isansi())
							formout("messages/readopt.ansi");
						else
							formout("messages/readopt");
printf("%s%c .Read ",quickroom.QRname,room_prompt(&quickroom));
					}
				} while(c!=8);
			     back(5);
			     break;
/* end of read options */

/* start of enter options */
		   case 'e': printf("Enter ");
			     do {
				c=lkey();
				switch(c) {
				   case 'p':	printf("Password\n");
						return(35);
				   case 'a':	printf("ASCII message\n");
						return(36);
				   case 'c':	printf("Configuration\n");
						return(37);
				   case 'r':	printf("a new Room\n");
						return(38);
				   case 't':	printf("Textfile\n");
						return(39);
				   case 'x':	printf("file using Xmodem\n");
						return(40);
				   case 'y':	printf("file using Ymodem\n");
						return(42);
				   case 'z':	printf("file using Zmodem\n");
						return(44);
				   case 'g':	printf("reGistration\n");
						return(41);
				   case 'm':	printf("Message\n");
						return(4);
				   case 'e':	printf("message with Editor\n");
						return(46);
				   case '?':	printf("(options)\n");
						if(isansi())
							formout("messages/entopt.ansi");
						else
							formout("messages/entopt");
printf("%s%c .Enter ",quickroom.QRname,room_prompt(&quickroom));
					}
				} while(c!=8);
			     back(6);
			     break;
/* end of enter options */

		   case '?':	printf("(options)\n");
				if(isansi())
					formout("messages/dotopt.ansi");
				else
					formout("messages/dotopt");
printf("%s%c .",quickroom.QRname,room_prompt(&quickroom));
		   }
		} while(b!=8);
		back(1);
		break;

    }	/* end switch	*/
  }	/* end while	*/
}	/* end getcmd()	*/


/*
 * set tty modes.  commands are:
 * 
 * 0 - set to bbs mode, intr/quit disabled
 * 1 - set to bbs mode, intr/quit enabled
 * 2 - save current settings for later restoral
 * 3 - restore saved settings
 */
sttybbs(cmd) 
int cmd; {
	struct termio live;
	static struct termio saved_settings;

	if ( (cmd == 0) || (cmd == 1) ) {
		ioctl(0,TCGETA,&live);
		live.c_iflag=ISTRIP|IXON|IXANY;
		live.c_oflag=OPOST|ONLCR;
		live.c_lflag=NOFLSH;
		if (cmd==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);
		}
	if (cmd == 2) {
		ioctl(0,TCGETA,&saved_settings);
		}
	if (cmd == 3) {
		ioctl(0,TCSETA,&saved_settings);
		}
	}


/* 
 * help_subst()  -  support routine for help file viewer
 */
void help_subst(strbuf,source,dest)
char strbuf[];
char source[];
char dest[]; {
	int a;
	char workbuf[128];
	
	for (a=0; a<strlen(strbuf); ++a)
		if (!struncmp(&strbuf[a],source,strlen(source))) {
			strcpy(workbuf,strbuf);
			workbuf[a]=0;
			strcat(workbuf,dest);
			strcat(workbuf,&strbuf[a+strlen(source)]);
			strcpy(strbuf,workbuf);
			}
	}


/*
 * display_help()  -  help file viewer
 */
void display_help(name)
char name[]; {
	FILE *hfp;
	char buf[128],buf2[32];
	int a;
	
	for (a=0; a<strlen(name); ++a) {
		if (name[a]=='/') name[a]='_';
		name[a] = tolower(name[a]);
		}
	sprintf(buf,"./help/%s",name);
	hfp=fopen(buf,"r");
	if (hfp==NULL) {
		printf("There is no help file called '%s'.\n",name);
		return;
		}
	while(fgets(buf,128,hfp)!=NULL) {
		buf[strlen(buf)-1] = 0;
		help_subst(buf,"^nodename",config.c_nodename);
		help_subst(buf,"^humannode",config.c_humannode);
		help_subst(buf,"^fqdn",config.c_fqdn);
		help_subst(buf,"^username",usersupp.fullname);
		sprintf(buf2,"%ld",usersupp.eternal);
		help_subst(buf,"^usernum",buf2);
		help_subst(buf,"^sysadm",config.c_sysadm);
		help_subst(buf,"^variantname",CITADEL);
		printf("%s\n",buf);
		}
	fclose(hfp);
	return;
	}
