/****************************************************************/
/**                                                            **/
/**   Direct Communication Chat and Conferencing System        **/
/**   Created May 1993 out of complete boredom.                **/
/**   (c) 1993 Takoyaki Software Ltd.                          **/
/**                                                            **/
/**   Will only run in conjunction with Desqview/X.            **/
/**                                                            **/
/**   File:    CHATHOST.C                                      **/
/**   Purpose: Controls the channelling of messages to and     **/
/**            from the different users.                       **/
/**   Usage:   Should be executed only once and always from    **/
/**            the same directory ('HOSTDATA.DAT' is written   **/
/**            into the current directory)                     **/
/**                                                            **/
/****************************************************************/

#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	<time.h>
#include	<ctype.h>
#include	<io.h>
#include	<sys/stat.h>
#include	<dos.h>
#include	<stdarg.h>
#include	<sys/time.h>
#include	<sys/socket.h>
#include	<netinet/in.h>

#include	"chatvars.h"
#include	"servcmds.h"
#include	"sockvars.h"


extern struct cmd cmds[];
extern int real_login();
extern int processdata();
extern int initsocket();
extern int closesockets();
extern int scanpackets();
extern int acknowledge(char *,unsigned long);
extern int purgemailbox(char *);
extern int m_modemmail(char *inbuff, char *input);

extern int mailboxread(int (*func)(char *));
extern int sendtomailbox(unsigned long, char *,struct packet *);
extern struct mail *findunsentmail();

extern struct item **getheader(int);
extern struct items *gettypedefbyname(char *);
extern struct items *gettypedef(int);
extern char *ExpandPercents(char *);

extern long on;

int autosavecount=0;
int speed=HOSTSPEED;
int sysmsgflag=0;

int dealwithit(char *inbuff, char *input);
int dealwithmodem(char *inbuff, char *input);
int m_newuser(char *inbuff, char *input);
int m_enterpassword(char *inbuff, char *input);
struct category *findcat(char *name);


char dcc[] = "[1;36m-SYS- [37m";
char dccmail[] = "[1;36m-MSG- [37m";

char tmpmsg[4096];
char tmpmsg2[128];
char tmpmsg3[4096];
char tmpmsg4[128];
char tmpmsg5[4096];

unsigned long hostmail;
struct stat sb;

int global(char *,char *);

int force_exit = 0;

char mailbox[32];
char indent;  /* value to indent messages by */


struct user *currentuser;
struct staticuser *currentstatic;
extern struct emote *emotes;
extern struct staticuser *staticlist;
extern struct category *categorylist;
extern struct user *userlist;

struct emote *currentemote;

int hostsocket=DEFAULTHOSTSOCKET;
int needtelix=0;



/*********************************************************************/
/*********************************************************************/
/*********************************************************************/
/*********************************************************************/
/*********************************************************************/
/*********************************************************************/
/*********************************************************************/






/*-------------------------------------------------------*/
/* add item into a list                                  */
/*-------------------------------------------------------*/

struct item *additem(int type)
	{
	struct item *i;
	struct items *d;

	if (!(d = gettypedef(type))) return NULL;

	if (!(i = calloc(d->size,1))) return NULL;

	if (*(d->header)) (*(d->header))->prev = i;

	i->next = *(d->header);
	i->type = type;
	*(d->header) = i;

	return i;
	}

/*-------------------------------------------------------*/
/* remove item from a list                               */
/*-------------------------------------------------------*/

remitem(struct item *i)
	{
	struct items *d;

	if (!(d = gettypedef(i->type))) return;

	if (i->prev)
		i->prev->next = i->next;
	else *d->header = i->next;

	if (i->next)
		i->next->prev = i->prev;

	free(i);

	}




/*-------------------------------------------------------*/
/* find an emote                                         */
/*-------------------------------------------------------*/

struct emote *findemote(char *find, char mode, char *user)
	{
	struct emote *e = emotes;

	mode = toupper(mode);

	while (e)
		{
		if (!(e->itemflags&I_INVALID))
			{
			if (mode == 'P' && (e->flags&E_PRIVATE))
				if (strcmpl(e->cmd,find) == 0 && strcmpl(e->user,user) == 0) break;
			if (mode == 'G' && !(e->flags&E_PRIVATE))
				if ((strcmpl(e->cmd,find) == 0) && ((strcmpl(e->user,user)==0) || (strcmpl(user,"") ==0))) break;
			if (mode == '*')
				if (strcmpl(e->cmd,find) == 0) break;
			}
		e = e->next;
		}

	return e;
	}



/*-------------------------------------------------------*/
/* wait around for a bit                                 */
/*-------------------------------------------------------*/

waitdvx(int time)
	{
	while (time--)
		{
		nextframe();
		}

	}


/*----------------------------------*/
/* check if a user's account exists */
/*----------------------------------*/

struct staticuser *findstatic(char *username)
	{
	struct staticuser *user=staticlist;

	if (!username) return NULL;

	while (user)
		{
		if (!(user->itemflags&I_INVALID) && strcmpl(user->username,username) == 0) return user;
		user = user->next;
		}

	return NULL;
	}


/*------------------------------------*/
/* check if a user exists, by mailbox */
/*------------------------------------*/

struct user *finduser(char *username)
	{
	struct user *user=userlist;

	if (!username) return NULL;

	while (user)
		{
		if (strcmpl(user->mailbox,username) == 0) return user;
		user = user->next;
		}

	return NULL;
	}

/*---------------------------------*/
/* check if a user exists, by name */
/*---------------------------------*/

struct user *findusername(char *username)
	{
	struct user *user=userlist;

	if (!username) return NULL;

	while (user)
		{
		if (user->ONLINE)
			if (strcmpl(user->username,username) == 0) return user;
		user = user->next;
		}

	return NULL;
	}


/*---------------*/
/* remove a user */
/*---------------*/

remuser(struct user *user)
	{

	if (user->staticuser)
		{
		if (user->staticuser->itemflags&I_INVALID)
			{
			free(user->staticuser);
			}
		user->staticuser->user = NULL;
		}

	purgemailbox(user->mailbox);
	free(user->mailbox);

	if (user->username) free(user->username);

	remonlineuser(user);

	}

/*----------------*/
/* add a new user */
/*----------------*/

struct user *adduser(char *username)
	{
	struct user *user;

	user = addonlineuser();

	user->mailbox = strdup(username);

	return user;
	}

/*--------------------------------------*/
/* send a message to the specified user */
/*--------------------------------------*/


sendmsg(char *user,char *umsg,...)
	{
	int cnt=0;
	char userfile[15];
	FILE *op;
	va_list argptr;
	char *msg=tmpmsg3;
	unsigned long mailbox;
	struct user *u = finduser(user);
	char inetaddr[30];
	char nullstr[1] = "\0";

/*	printf("Sending [%s] to [%s].\n",umsg,user);*/

	if (!u) return;
	if (!umsg) umsg = nullstr;

	va_start(argptr,umsg);

/* host->server private data set here. */


	if (u->BELL) *msg++ = WAKEUP;
	u->BELL = 0;

	if (u->CLOSEDOWN) *msg++ = SHUTDOWN;
	u->CLOSEDOWN = 0;

	if (u->inputline)
		{
		*msg++ = NEWINPUT;

		strcpy(msg, u->inputline);

		msg += strlen(u->inputline);
		*msg++ = NEWINPUT;
		u->inputline = NULL;
		}

	if (sysmsgflag&SYSMSG)
		{
		*msg++ = SETPREFIX;
		strcpy(msg,dcc);
		msg += strlen(dcc);
		*msg++ = SETPREFIX;
		sysmsgflag &= ~SYSMSG;
		}

	if (sysmsgflag&MAILMSG)
		{
		*msg++ = SETPREFIX;
		strcpy(msg,dccmail);
		msg += strlen(dccmail);
		*msg++ = SETPREFIX;
		sysmsgflag &= ~MAILMSG;
		}

	if (sysmsgflag&INDENTMSG)
		{
		*msg++ = SETINDENT;
		*msg++ = indent;
		sysmsgflag &= ~INDENTMSG;
		}

	if (u->NOECHO)
		*msg++ = ECHOOFF;

	if (sysmsgflag&ACKINPUT)
		{
		*msg++ = RETURNACK;
		sysmsgflag &= ~ACKINPUT;
		}

/* now generate the message */

	vsprintf(msg,umsg,argptr);

	va_end(argptr);

	msg = tmpmsg3;

	sendtomailbox((unsigned long)user, msg, NULL);
	
	}

/*-----------------------------------------------------------*/
/* send a message to everyone, excluding a user if necessary */
/*-----------------------------------------------------------*/

global(char *msg,char *exclude)
	{
	struct user *user=userlist;
	int sysmsgflag2 = sysmsgflag;
	int n=0;

	if (!exclude) exclude = "";

	while (user)
		{
		if (strcmpl(exclude,user->mailbox) && user->ONLINE)
			{
			sysmsgflag = sysmsgflag2;
			sendmsg(user->mailbox,msg);
			n++;
			}
		
		user = user->next;
		}
	sysmsgflag = 0;
	return n;
	}


login_info()
	{
	sysmsgflag |= SYSMSG;
	sprintf(tmpmsg2,"[%s] has just logged in.\n",currentuser->username);
	global(tmpmsg2,mailbox);
	currentuser->staticuser->logins++;
	currentuser->mode = dealwithit;
	currentuser->modestate = 0;
	currentuser->NOECHO = 0;
	currentuser->ONLINE = 1;
	newsection();
	}

/***************************************************************/
/* login the modem server */

login_modem()
	{
	currentuser->staticuser->logins++;
	currentuser->mode = dealwithmodem;
	currentuser->modestate = 0;
	currentuser->NOECHO = 0;
	sendmsg(currentuser->mailbox,"Ok.");
	sendmsg(currentuser->mailbox,"Ready>");
	}


/*--------------------*/
/* run a host command */
/*--------------------*/

runcommand(char *cmd,char *parm)
	{
	int n=0;

	while (cmds[n].name != NULL)
		{
		if (strcmpl(cmds[n].name,cmd) == 0)
			{
			cmds[n].func(parm);
			return;
			}
		n++;
		}

	if (!findusername(cmd))
		{
		sysmsg(mailbox,"Command Not Recognised.");
		}
	else
		{
		indentmsg(strlen(currentuser->username)+2+2);
		sendmsg(findusername(cmd)->mailbox,"[1;35m[%s]: [0m%s\n",currentuser->username,parm);
		}
	}


/*------------------------------------------*/
/* deal with a message received from a user */
/*------------------------------------------*/

m_enterpassword(char *inbuff, char *input)
	{
	switch(currentuser->modestate)
		{
		case 0:
			sendmsg(mailbox,"\nWhat is your name? (Enter NEW to create an account)\n");
			currentuser->modestate++;
			break;
		case 1:
			if (strlen(input)<3 || strlen(input)>15 || strchr(input,' '))
				{
				sendmsg(mailbox,"Error: Name must be between 3 to 15 characters long.");
				break;
				}

			if (findusername(input))
				{
				sendmsg(mailbox,"Error: User with that name is already logged on.\nPlease try again.\n");
				break;
				}

			if (strcmpl(input,"NEW")==0)
				{
				sendmsg(mailbox,"\nCreating new account.\n\nPlease enter the name you wish to be called by. (no spaces)\n");
				currentuser->modestate = 10;
				break;
				}

			if (!(currentuser->staticuser = findstatic(input)))
				{
				sendmsg(mailbox,"Error: Cannot find account for %s.\n(Enter NEW to create an account)\n",input);
				break;
				}

			currentuser->staticuser->user = currentuser;
			currentuser->username = strdup(currentuser->staticuser->username);

			currentuser->NOECHO = 1;
			sendmsg(mailbox,"\nWhat is your password?\n");
			currentuser->modestate++;
			break;
		case 2:
		case 3:
		case 4:
			if (strcmpl(currentuser->staticuser->password,input))
				{

				if (currentuser->modestate == 4)
					{
					currentuser->CLOSEDOWN = 1;
					sendmsg(mailbox,"Password Invalid - Third time unlucky, bye bye.\n");
					remuser(currentuser);
					}
				else
					{
					sendmsg(mailbox,"Password Invalid.. try again.\n");
					}

				currentuser->modestate++;
				break;
				}

			if (currentuser->staticuser->flags&U_MODEM)
				{
				login_modem();
				}
			else
				{
				real_login();
				login_info();
				}
			break;

/* the creating of a new account */
		case 10:
			if (strlen(input)<3 || strlen(input)>15 || strchr(input,' '))
				{
				sendmsg(mailbox,"Error: Name must be between 3 to 15 characters long.");
				break;
				}

			if (findstatic(input))
				{
				sendmsg(mailbox,"Error: Account with same name already exists.\nPlease try again.\n");
				break;
				}

			currentuser->mode = m_newuser;
			currentuser->modestate = 0;

			currentuser->username = strdup(input);

			strlwr(currentuser->username);
			*currentuser->username = toupper(*currentuser->username);

			currentuser->mode(inbuff,input);
			break;

		default:
			break;
		}
	}

/*------------------------------------------*/
/* deal with a message received from a user */
/*------------------------------------------*/

m_newuser(char *inbuff,char *input)
	{
	switch(currentuser->modestate)
		{
		case 0:
			currentuser->NOECHO = 1;
			sendmsg(mailbox,"\nPlease enter a password for your account.\n");
			currentuser->modestate++;
			(currentuser->staticuser = addstatic())->itemflags |= I_INVALID;
			currentuser->staticuser->username = strdup(currentuser->username);
			break;
		case 1:
			if (strlen(input)<3)
				{
				sendmsg(mailbox,"That password is too short, please try again.\n");
				break;
				}
			if (strchr(input,'˙'))
				{
				sendmsg(mailbox,"Spaces are NOT allowed in passwords, please try again.\n");
				break;
				}
			currentuser->staticuser->password = strdup(input);
			currentuser->modestate++;
			sendmsg(mailbox,"Please re-enter your password for confirmation.\n");
			break;
		case 2:
			if (strcmpl(currentuser->staticuser->password,input))
				{
				sendmsg(mailbox,"Incorrect Password.  Please enter a password for your account.\n");
				currentuser->staticuser->password = NULL;
				free(currentuser->staticuser->password);
				currentuser->modestate = 1;
				break;
				}

			currentuser->NOECHO = 0;
			sendmsg(mailbox,"Are you male or female? (M/F)\n");
			currentuser->modestate++;
			break;
			case 3:
				if (strlen(input) != 1 || (toupper(*input) != 'M' && toupper(*input) != 'F'))
					{
					sendmsg(mailbox,"M or F expected.  Please try again.\n");
					break;
					}

				currentuser->staticuser->flags |= (toupper(*input) == 'F')?FEMALE:MALE;
				newsection();
				sysmsg(mailbox,
					"\nWelcome %s, you have succeeded in creating an account.\n"
					"Please memorise your password or write it down somewhere.\n"
					"Type /HELP for a summary of commands available.  Apart from\n"
					"that, you're on your own.  Good Luck!\n"
						,currentuser->username);
				currentuser->staticuser->itemflags &= ~I_INVALID;
				login_info();
				break;
		default:
			break;
		}

	}


/*------------------------------------------*/
/* Show emotes in various forms             */
/*------------------------------------------*/

showemotes(char mode, char *category)
	{
	struct emote *e = emotes;
	char *c = NULL;
	int perline=0;

	if (category) c = strdup(category);

	sprintf(tmpmsg,"%sEmote list:\n%s",dcc,dcc);
	mode = toupper(mode);

	while (e)
		{
		if (!(e->itemflags&I_INVALID))
			{
			if (
				(mode == 'G' && !(e->flags&E_PRIVATE) && strcmpl(currentuser->username,e->user)==0) ||
				(mode == 'P' && (e->flags&E_PRIVATE) && strcmpl(currentuser->username,e->user)==0) ||
				(mode == 'C' && !(e->flags&E_PRIVATE) && strcmpl(e->category,c)==0) ||
				(mode == 'U' && !(e->flags&E_PRIVATE) && !findcat(e->category)) ||
				(mode == '*' && !(e->flags&E_PRIVATE)) )
				{
				if (perline+strlen(e->cmd) >WORDWRAP)
					{
					strcat(tmpmsg,"\n");
					strcat(tmpmsg,dcc);
					perline = 0;
					}
				strcat(tmpmsg,e->cmd);
				strcat(tmpmsg," ");
				perline += strlen(e->cmd)+1;
				}
			}
		e = e->next;
		}
	sendmsg(mailbox,tmpmsg);

	if (c) free(c);
	}


/*------------------------------------------*/
/* Show categories to user                  */
/*------------------------------------------*/

showcats(char *user)
	{
	int d=0;
	char number[16];
	struct category *c = categorylist;

	newsection();
	sprintf(tmpmsg,"Emote categories list:\n");

	while (c)
		{
		sprintf(tmpmsg+strlen(tmpmsg),"%d.[33m%s[37m  ",++d,c->name);
		c = c->next;
		}

	sysmsg(user,tmpmsg);
	}



/*------------------------------------------*/
/* Find category                            */
/*------------------------------------------*/

struct category *findcat(char *name)
	{
	int d;
	struct category *c = categorylist;

	if (!strlen(name) || !name) return NULL;

	if ((d = strtol(name,NULL,0)))
		{
		while (c)
			{
			if (!--d) return c;
			c = c->next;
			}
		return NULL;
		}
	else
		{
		while (c)
			{
			if (strncmpl(c->name,name,strlen(name))==0) return c;
			c = c->next;
			}
		}

	return NULL;
	}


/*------------------------------------------*/
/* deal with a message received from a user */
/*------------------------------------------*/

m_setcategory(char *inbuff, char *input)
	{
	struct category *c;
	char *cat;
	switch(currentuser->modestate)
		{
		case 0:
			newsection();
			sysmsg(mailbox,"Enter new category name.\n");
			currentuser->modestate++;
			break;
		case 1:
			if (strlen(input)<3 || strchr(input,' '))
				{
				sysmsg(mailbox,"Category must be at least 3 characters long and no spaces.\nPlease try again.\n");
				break;
				}
			strupr(input);
			if (c = findcat(input))
				{
				sysmsg(mailbox,"Category [%s] already exists.\n",c->name);
				}
			else
				{			
				if (!(c = addcat()))
					{
					sysmsg(mailbox,"Have reached maximum amount of categories.\n");
					}
				else
					{
					c->name = strdup(input);
					sysmsg(mailbox,"Category [%s] created successfully.\n",input);
					}
				}
			currentuser->modestate = 0;
			currentuser->mode = dealwithit;
			break;
		default:
			break;
		}
	}


/*------------------------------------------*/
/* deal with a message received from a user */
/*------------------------------------------*/

m_setemote(char *inbuff, char *input)
	{
	struct category *c;

	switch(currentuser->modestate)
		{

/* deal with the adding of emotes */

		case 0:
			newsection();
			sysmsg(mailbox,"Is it a personal emote? (only to be used by yourself)\n(Y or N)\n");
			currentuser->modestate++;			
			break;
		case 1:
			if ((toupper(*input) != 'Y' && toupper(*input) != 'N') || strlen(input) != 1)
				{
				sysmsg(mailbox,"Y or N expected.  Please try again.\n");
				break;
				}
			(currentuser->emote = addemote())->flags |= (toupper(*input) == 'Y')?E_PRIVATE:0;
			currentuser->emote->itemflags |= I_INVALID;
			currentuser->modestate++;
			currentuser->emote->user = strdup(currentuser->username);
			sysmsg(mailbox,"Please enter the command you wish the emote to be invoked by.\n");
			break;
		case 2:
			if (!strlen(input)) break;
			if (strchr(input,'˙'))
				{
				sysmsg(mailbox,"Spaces are NOT allowed in the command.  Please try again.\n");
				break;
				}
			if ((currentuser->emote->flags&E_PRIVATE) && findemote(input,'P',currentuser->username))
				{
				sysmsg(mailbox,"[%s] already exists as your personal emote. Use /EDIT EMOTE to change.\n",input);
				currentuser->mode = dealwithit;
				currentuser->modestate = 0;
				break;
				}
			if (!(currentuser->emote->flags&E_PRIVATE) && findemote(input,'G',currentuser->username))
				{
				sysmsg(mailbox,"[%s] already exists as a global emote.  Use /EDIT EMOTE to change.\n",input);
				currentuser->mode = dealwithit;
				currentuser->modestate = 0;
				break;
				}
			currentuser->emote->cmd = strdup(input);
			currentuser->modestate++;
			sysmsg(mailbox,"Please enter the emote string for [%s].\n%%s translates into the user's name.\n",currentuser->emote->cmd);
			break;
		case 3:
			if (!strlen(input)) break;

			currentuser->emote->emote = strdup(input);

			showcats(mailbox);

			sysmsg(mailbox,"Please select a category (by name or number) from above.\n");
			currentuser->modestate++;
			break;
		case 4:

			if (!(c = findcat(input)))
				{
				showcats(mailbox);
				currentuser->BELL = 1;
				sysmsg(mailbox,"You MUST select a category.\n");
				break;
				}

			currentuser->emote->category = strupr(strdup(c->name));

			currentuser->emote->itemflags &= ~I_INVALID;
			currentuser->mode = dealwithit;
			currentuser->modestate=0;

			sysmsg(mailbox,"[%s] created successfully.\n",currentuser->emote->cmd);
			break;

/* deal with the editting of emotes */

		case 5:
			newsection();
			sysmsg(mailbox,"Which emote do you wish to edit?\nPlease use PRIVATE <name> if it is a personal.\n");
			currentuser->modestate++;
			break;
		case 6:
			if (!strlen(input)) break;
			if (strncmpl("PRIVATE˙",input,strlen("PRIVATE˙")) == 0)
				currentuser->emote = findemote(input+strlen("PRIVATE˙"),'P',currentuser->username);
			else
				currentuser->emote = findemote(input,'G',ISSYSOP?"":currentuser->username);

			if (!currentuser->emote)
				{
				sysmsg(mailbox,"No such emote exists.\n");
				currentuser->modestate = 0;
				currentuser->mode = dealwithit;
				break;
				}

			if (strcmpl(currentuser->emote->user,currentuser->username) && !ISSYSOP)
				{
				sysmsg(mailbox,"You didn't create the emote [%s].\n",currentuser->emote->cmd);
				currentuser->modestate = 0;
				currentuser->mode = dealwithit;
				break;
				}

			currentuser->modestate++;

			sysmsg(mailbox,"Swap Private/Public Status? (currently %s)\n(Y or N)\n",(currentuser->emote->flags&E_PRIVATE)?"PRIVATE":"PUBLIC");
			break;
		case 7:
			*input = toupper(*input);
			if (strlen(input) != 1 || (*input != 'N' && *input != 'Y'))
				{
				sysmsg(mailbox,"Y or N expected.  Please try again.\n");
				break;
				}
			if (*input == 'Y')
				{
				if (currentuser->emote->flags&E_PRIVATE)
					{
					if (findemote(currentuser->emote->cmd,'G',currentuser->username))
						{
						sysmsg(mailbox,"Public with same name already exists; cannot change.\n");
						currentuser->mode = dealwithit;
						currentuser->modestate = 0;
						break;
						}
					}
				else
					{
					if (findemote(currentuser->emote->cmd,'P',currentuser->username))
						{
						sysmsg(mailbox,"Public with same name already exists; cannot change.\n");
						currentuser->mode = dealwithit;
						currentuser->modestate = 0;
						break;
						}
					}
				sysmsg(mailbox,"[%s] is now %s.\n",currentuser->emote->cmd,(currentuser->emote->flags&E_PRIVATE)?"PUBLIC":"PRIVATE");
				currentuser->emote->flags ^= E_PRIVATE;
				currentuser->mode = dealwithit;
				currentuser->modestate = 0;
				break;
				}
			currentuser->modestate++;
			setinput(currentuser->emote->emote);
			sysmsg(mailbox,"Enter new emote string.\n[%s]\n<Enter> to leave as before.\n",currentuser->emote->emote);
			break;
		case 8:
			if (strlen(input))
				{
				if (currentuser->emote->emote) free(currentuser->emote->emote);
				currentuser->emote->emote = strdup(input);
				sysmsg(mailbox,"[%s] is now:\n [%s].\n",currentuser->emote->cmd,currentuser->emote->emote);
				}
			else
				{
				sysmsg(mailbox,"Emote string left untouched.\n");
				}
			showcats(mailbox);
			sysmsg(mailbox,"Please select a category from above.\n<Enter> to leave as before - [%s]\n",currentuser->emote->category);
			currentuser->modestate++;
			break;
		case 9:
			if (strlen(input))
				{
				if (!(c = findcat(input)))
					{
					showcats(mailbox);
					sysmsg(mailbox,"Please select a category (by name or number) from above.\n<Enter> to leave as before - [%s]\n",currentuser->emote->category);
					break;
					}
				if (currentuser->emote->category) free(currentuser->emote->category);
				currentuser->emote->category = strupr(strdup(c->name));
				sysmsg(mailbox,"Emote [%s]'s category changed to [%s].\n",currentuser->emote->cmd,currentuser->emote->category);
				}
			else
				{
				sysmsg(mailbox,"Category left as before - [%s].\n",currentuser->emote->category);
				}
			currentuser->mode = dealwithit;
			currentuser->modestate = 0;
			break;

/* deal with the listing of emotes */

		case 10:
			newsection();
			sysmsg(mailbox,"Enter list mode for emotes.\n(P,  G, C or * - Private/global/categories/all)\n");
			currentuser->modestate++;
			break;
		case 11:
			*input = toupper(*input);
			if (*input == 'C')
				{
				showcats(mailbox);
				sysmsg(mailbox,"Please select a category from the above.\n");
				currentuser->modestate++;
				break;
				}
			if (strlen(input)==1 && (*input == 'P' || *input == 'G' || *input == '*' ))
				showemotes(*input,NULL);
			else
				{
				sysmsg(mailbox,"Invalid list mode.\n");
				}
			currentuser->mode = dealwithit;
			currentuser->modestate = 0;
			break;
		case 12:
			if (strcmpl(input,"UNKNOWN")==0)
				showemotes('U',NULL);
			else
				{
				if ((c = findcat(input)))
					showemotes('C',c->name);
				else
					{
					sysmsg(mailbox,"Unknown category specified.\n");
					}
				}
			currentuser->mode = dealwithit;
			currentuser->modestate = 0;
			break;

/* deal with the deleting of emotes */

		case 20:
			newsection();
			sysmsg(mailbox,"Enter command name of emote to delete.\nEnter PRIVATE <name> if personal.\n");
			currentuser->modestate++;
			break;
		default:
			if (!strlen(input)) break;
			if (strncmpl("PRIVATE˙",input,strlen("PRIVATE˙")) == 0)
				currentuser->emote = findemote(input+strlen("PRIVATE˙"),'P',currentuser->username);
			else
				currentuser->emote = findemote(input,'G',ISSYSOP?"":currentuser->username);

			if (!currentuser->emote)
				{
				sysmsg(mailbox,"No such emote exists.\n");
				currentuser->modestate = 0;
				currentuser->mode = dealwithit;
				break;
				}

			sysmsg(mailbox,"[%s] deleted.\n",currentuser->emote->cmd);

			if (currentuser->emote->emote) free(currentuser->emote->emote);
			if (currentuser->emote->cmd) free(currentuser->emote->cmd);
			if (currentuser->emote->user) free(currentuser->emote->user);

			rememote(currentuser->emote);

			currentuser->emote = NULL;
			currentuser->modestate = 0;
			currentuser->mode = dealwithit;
			
			break;
		}
	}


/*------------------------------------------*/
/* deal with a message received from a user */
/*------------------------------------------*/


dealwithit(char *inbuff, char *input)
	{
	char *p,*c;
	struct emote *e;

	strcpy(input,ExpandPercents(input));

/* is it a command? */
	if (*input == '/')
		{
		c=strchr(input,'˙');
		if (c)
			{
			*c++ = '\0';
			if (*c=='\0') c=NULL;
			}
		runcommand(input+1,c);
		}
	else
		{

/* or is it an emote command? */
		if (!(e = findemote(input,'P',currentuser->username)))
			e = findemote(input,'G',"");

		if (e)
			{
			e->usage++;
			sprintf(tmpmsg5,e->emote,currentuser->username,currentuser->username);
			indentmsg(2);
			global(tmpmsg5,NULL);
			}
/* or just a message */
		else
			{
			indentmsg(strlen(currentuser->username)+2);
			sprintf(tmpmsg5,"[01m[33m%s: [00m%s\n",currentuser->username,input);
			if (global(tmpmsg5,NULL) < 2)
				{
				sysmsg(mailbox,"There is no-one around to hear your pitiful whinings.\n");
				}
			}
		}
	}




/*---------------------------------------------*/
/* deal with a message received from the modem */
/*---------------------------------------------*/


dealwithmodem(char *inbuff, char *input)
	{
	char *p,*c;
	struct emote *e;

	if (strcmpl(input,"Do you need anything?") == 0)
		{
		if (!needtelix && !findunsentmail()) sendmsg(currentuser->mailbox,"No");
		else
			{
			if (!needtelix)
				{
				sendmsg(currentuser->mailbox,"Yes - Batch mail please");
				}
			else
				{
				sendmsg(currentuser->mailbox,"Yes - Telix please");
				needtelix = 0;
				}
			}
		return;
		}

	if (strcmpl(input,"mail") == 0)
		{
		currentuser->mode = m_modemmail;
		currentuser->modestate = 0;
		m_modemmail("","");
		}

	sendmsg(currentuser->mailbox,"Ready>");
	}


mailfromuser(char *inbuff)
	{
	char *p;
	unsigned long n;
	char *q;

	if ((p = strchr(inbuff,':')))
		{

		strncpy(mailbox,inbuff,p-inbuff);
		mailbox[p-inbuff] = '\0';

		currentuser = finduser(mailbox);

		if ((inbuff[p-inbuff+2] == TERMINALRESET) && currentuser)
			{
			remuser(currentuser);
			currentuser = NULL;
			}

		if ((inbuff[p-inbuff+2] == ACKNOWLEDGE) && currentuser)
			{
			acknowledge(mailbox,strtol(&inbuff[p-inbuff+3],NULL,0));
			return;
			}

		if ((inbuff[p-inbuff+2] == CHECKHOST) && currentuser)
			{
			sendmsg(mailbox,"Connected.");
			return;
			}

		if ((inbuff[p-inbuff+2] == SENDACK))
			{
			n = strtol(p+3,&q,10);

			p = q-1;

			sysmsgflag |= ACKINPUT;
			sendmsg(mailbox,"%lu",n);

			if (currentuser)
				{
				if ((int)(currentuser->ack-n) >= 0) return;
				currentuser->ack = n;
				}
			}

		if (!currentuser)
			{
			currentuser = adduser(mailbox);
			sendmsg(mailbox,"Host Connection Established.");
			currentuser->mode = m_enterpassword;
			currentuser->modestate = 0;
			}

		if (inbuff[strlen(inbuff)-1]=='\n')
			inbuff[strlen(inbuff)-1] = '\0';

		currentuser->mode(inbuff,p+2);

		}
	}



dirlist(char *spec,int (*func)(char *))
	{
	int done;
	struct ffblk fb;

	done = findfirst(spec,&fb,0);

	while (!done)
		{
		func(fb.ff_name);
		done = findnext(&fb);
		}

	}



/*-------------------------------------------------------*/
/*-------------------------------------------------------*/
/*-------------------------------------------------------*/
/*-------------------------------------------------------*/
/*-------------------------------------------------------*/
/*-------------------------------------------------------*/

main(int argc,char *argv[])
	{
	int n;

	if (argc==2)
		{
		hostsocket = strtol(argv[1],NULL,0);
		}

	processdata();

	initsocket();

	while (!kbhit() && !force_exit)
		{
		waitdvx(speed);
		mailboxread(mailfromuser);
		scanpackets();

		if (autosavecount++ > AUTOSAVE)
			{
			saveall();
			autosavecount = 0;
			}
		}


	closesockets();

	printf("Saving Data, Please wait...");
	saveall();


	}


