/* ELM: (c) Jos & Kees Lemmens; Oktober 1993.

   This program behaves in a simular way as the UNIX 'elm' program,
   which is very popular among UNIX users. (although it has much less
   functionality !)
   However, the code was written completely by ourselves and we didn't
   need much more !!
   Unfortunately it can only handle local mail, but it is easy to add 
   an external program that can handle uucp mail.

   Code runs on ATARI (under MINT), on AMIGA 500-4000 (with gcc) and
   was also tested on several UNIX platforms.
   
   1.4 : cursor keys on Atari console now recognized;
         uucp mailaddresses redirected to OutboudMail function (same
         function as for Internet mail)

   Any questions or suggestions about this program can be send to:
   lemmens@dv.twi.tudelft.nl
*/

/* standard headers */

#include <stdio.h>
#include <stdlib.h>		/* getenv, malloc, free and exit */
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <stdarg.h>

#ifdef __MINT__
#include <osbind.h>
#include <termcap.h>
#include <ioctl.h>		/* ioctl & tty structs */
#include <fcntl.h>		/* O_RDONLY (access) */
#else
#include <curses.h>
#include <term.h>
#include <termios.h>
#include <sys/wait.h>
#endif

/* UNIX headers */

#include <signal.h>		/* only for suspend routine */
#include <unistd.h>

/* special headers */

#include "elm.h"

static char *version = "[ELM ST, J&KL; v1.4]";

/* termcap variables */

static char *_tcpent,*_tcpbuf;
static char *CL,*CM,*SO,*SE,*CE,*ME,*MR;
static int LINES,COLS;

#ifdef __MINT__
struct ltchars ltold,ltnew;	/* disable suspend */

void ttraw(struct ltchars *ltold,struct ltchars *ltnew)
{
	if(ioctl(0, TIOCGLTC, (char *) ltold) < 0)
		puts("Can't do ioctl");
	ioctl(0, TIOCGLTC, (char *)ltnew);

	ltnew->t_suspc = ltnew->t_dsuspc = 0xFF;
	ioctl(0, TIOCSLTC, (char *) ltnew);
}

void ttcooked(struct ltchars *ltold)
{
	ioctl(0, TIOCSLTC, (char *) ltold);
}
#endif

void InitTermcap(void)
{	char *tmp;

	if((tmp=getenv("TERM")) != NULL)	/* use UNIX termcap */
	{	_tcpent = (char *)malloc(2048); /* must be enough ! */
		tgetent(_tcpent,tmp);
		_tcpbuf = _tcpent +1024;

		CL = tgetstr("cl", &_tcpbuf);	CM = tgetstr("cm", &_tcpbuf);
		SO = tgetstr("so", &_tcpbuf);	SE = tgetstr("se", &_tcpbuf);
		CE = tgetstr("ce", &_tcpbuf);	ME = tgetstr("me", &_tcpbuf);
		MR = tgetstr("mr", &_tcpbuf);

		if((tmp=getenv("LINES")) == NULL)
			LINES = tgetnum("li");
		else
			LINES = atoi(tmp);

		if((tmp=getenv("COLUMNS")) == NULL)
			COLS = tgetnum("co");
		else
			COLS  = atoi(tmp);
	}
	else			/* set acceptable defaults : VT52 code */
	{	CL = "\33H\33J";	CM = "\33Y%+ %+ ";
		SO = "\33p";		SE = "\33q";
		CE = "\33K";
		LINES = 24;		COLS = 80;
	}
}

#ifdef __hpux	/* stupid error in HPUX 9.01 headerfile */
int outc(char c)
#else
int outc(int c)
#endif
{	return putchar(c);
}

void Clrscr(void)
{	tputs(CL,1,outc);
}

void Clrtoeol(void)
{	tputs(CE,1,outc);
}

void Gotoxy(int x,int y)
{	tputs(tgoto(CM, x, y),1,outc);
}

void EndTermcap(void)
{	free(_tcpent);
}

void PutStr (char *string,...)
{	va_list ptr;

 	if(string == NULL)
		return;

	va_start(ptr,string);
	vfprintf(stdout,string,ptr);
	fflush(stdout);
	va_end(ptr);
}

char GetChar(void)
{	char c;

#ifdef __MINT__
    /* this fixes for ATARI cursor keys using scancodes */
    static union { long scan; char byte[4]; } ch;

    ch.scan=Crawcin();
    if (ch.byte[3] == 0)
	switch(ch.byte[1])
	{	case 'H': return 'k'; /* cursor up */
		case 'P': return 'j'; /* cursor down */ 
/*		case 'K': return 'h'; /* cursor left */
/*		case 'M': return 'l'; /* cursor right */
	}

    c = ch.byte[3];
#else
#ifdef __AMIGA__	/* doesn't echo for some reason */
	read(fileno(stdin),&c,1);
	write(fileno(stdout),&c,1);
#else
	read(fileno(stdin),&c,1);
#endif
#endif
	return c;
}

char *GetStr(char *string,int size)
{
#ifdef __AMIGA__
/* this implies that input editing (backspacing) is not possible ! */
	int count=0;
	do
	{	*string = GetChar();
		if(*string == '\r')
		{	*string = '\0';
			break;
		}
	}	while(string++,count++ < size);
#else
	fgets(string,size,stdin);
#endif

/* todo: try fflush(stdin) on AMIGA, maybe this works !! */

	return string;
}

void usage(void)
{	fputs("\nUsage: elm [-f <mailfile>] [-e <editor>]\n",stderr);
	exit(1);
}

void PutStatus(char *string,...)
{	va_list ptr;

	va_start(ptr,string);
	Gotoxy(0,LINES-2);
	Clrtoeol();
	vfprintf(stdout,string,ptr);
	fflush(stdout);
	va_end(ptr);
}

void PutHeader(Mbox *M)
{	Gotoxy(5,STARTHEADER);
	PutStr("Mailbox '%.30s' with %d messages %s",M->Path,M->Count,version);
}

void PutMenus(void)
{
	Gotoxy(4,STARTMENU);
	PutStr("m)ail user; f)orward user; r)eply user; $ = reread mailfile; q)uit");
	Gotoxy(3,STARTMENU+1);
	PutStr("k = move up; j = move down; s)ave to file; d)elete mail; u)ndelete mail");
	Gotoxy(4,STARTMENU+2);
	PutStr("! = start shell;  To read a message, press RETURN");
}

void PutMessage(Mbox *M,int x)
{	int offset = 0;

	offset = M->CurMsg /(MSGLISTSIZE) * MSGLISTSIZE;

	Gotoxy(0,x-offset+STARTLIST);

	PutStr ("   %1.1s %.3d  %-6.6s  %-15.15s  (%.3d)  %-35.35s",
		&M->Msglist[x]->flag,    x+1,
		M->Msglist[x]->date + 4,
		M->Msglist[x]->sender,
		M->Msglist[x]->nrlines,
		M->Msglist[x]->subject);
}

void PutMessages(Mbox *M)
{	int x;
	int offset = 0;

	offset = M->CurMsg /(MSGLISTSIZE) * MSGLISTSIZE;

	for(x=0;x<MSGLISTSIZE && x+offset<M->Count; x++)
		PutMessage(M,offset+x);

	while(x<MSGLISTSIZE)
	{	Gotoxy(0,x+STARTLIST);
		Clrtoeol();
		x++;
	}
}

void OpenMailbox(Mbox *M)
{	if((M->fd = fopen (ux2dos(M->Path), "r")) == NULL)
	{	/* create an empty mailfile */
		if((M->fd = fopen (ux2dos(M->Path), "w+")) == NULL)
		{	fprintf(stderr,"Can't open mailbox for %s\n",M->User);
			exit(1);
		}
		else
		{	PutStatus("Empty mailbox %s created; Press a key ...",
				M->Path);
			GetChar();
		}
	}
}

void CloseMailbox(Mbox *M)
{	fclose(M->fd);
}

void RemoveCR(char *ptr)
{	char *tmp;

	if((tmp=strchr(ptr,'\n')) != NULL) *tmp = 0;
}

char *EatWhiteSpace(char *ptr)
{	while(*ptr == ' ' || *ptr == '\t') ptr++;
	return ptr;
}

void BuildMailList(Mbox *M)
{	int x;
	int nrlines=0;
	char regel[MAXSTR+1], *tmp1,*tmp2;
	
	OpenMailbox(M);

	for(x=0;x < MAXMSG && !feof(M->fd);x++ )
	{
		/* first search for start of (next) message */
		while (strncmp (regel, "From ", 5) && !feof(M->fd) )
		{	fgets(regel,MAXSTR,M->fd);
			nrlines++;
		}

		if(feof(M->fd)) break;

		M->Msglist[x] = calloc(1,sizeof(Msg));
		M->Msglist[x]->start  = ftell(M->fd) - strlen(regel) - 1;
		M->Msglist[x]->flag   = 'N';
		M->Msglist[x]->status = 0;
		/* assume new msg until proved to be old */

		if(x>0) M->Msglist[x-1]->nrlines = nrlines;

		nrlines=0;	/* start new line count */

		if((tmp1 = strchr (regel, ' ')) != NULL)	/* sender */
		{	tmp1 = EatWhiteSpace(tmp1);

			if((tmp2 = strchr (tmp1, ' ')) != NULL)	/* date */
			{	*tmp2++ = 0;				/* fix end of tmp1 */
				tmp2 = EatWhiteSpace(tmp2);
				strncpy(M->Msglist[x]->date,tmp2,MAXDATE);
			}
			strncpy(M->Msglist[x]->sender,tmp1,MAXNAME);
		}
		do
		{	fgets (regel,MAXSTR,M->fd);
			nrlines++;

			if(!strncmp (regel, "Status:",7))
			{	if(strchr(regel + 7,'R') != NULL)
					M->Msglist[x]->flag = ' ';
				M->Msglist[x]->status = 1;
			}
			else if(!strncmp (regel, "Subject:",8))
			{	tmp1 = EatWhiteSpace(regel + 8);
				RemoveCR(tmp1);
				strncpy(M->Msglist[x]->subject,tmp1,MAXSUBJECT);
			}
		}while (strncmp (regel, "From ", 5) && !feof(M->fd) );
	}

	if(x>0) M->Msglist[x-1]->nrlines = nrlines;	/* save length for last message */

	/* last (extra) record is only used save end of file position */

	M->Msglist[x] = calloc(1,sizeof(Msg));
	M->Msglist[x]->start = ftell(M->fd);

	if(x == 0)	/* fix for empty file */
	{	M->Msglist[1] = calloc(1,sizeof(Msg));
		M->Msglist[1]->start = ftell(M->fd);
	}

	M->Count = x;
	M->CurMsg = 0;
	CloseMailbox(M);
}

void SetCurMsg(Mbox *M,int new,int echo)
{	int old;

	old = M->CurMsg;

	if(new < 0 || new >=M->Count)
	{	if(echo) PutStatus("No more messages");
		Gotoxy(0,STARTLIST + old%MSGLISTSIZE);	PutStr("-> ");
		return;
	}
	M->CurMsg  = new;

	if(old /(MSGLISTSIZE) != new /(MSGLISTSIZE))
		PutMessages(M);	/* show next page */

	Gotoxy(0,STARTLIST + old%MSGLISTSIZE);	PutStr("   ");
	Gotoxy(0,STARTLIST + new%MSGLISTSIZE);	PutStr("-> ");
}

void InitScreen(Mbox *Mailbox)
{	extern void PutMenus(void);

	Clrscr();
	PutHeader(Mailbox);
	PutMenus();
	PutMessages(Mailbox);
	SetCurMsg(Mailbox,Mailbox->CurMsg,0);
}

void SuspendMail(Mbox *Mailbox)
{	long omask;
	
	if (getenv("SHLVL") != NULL) /* there is a running (C) shell */
	{	omask= sigsetmask(0);
#ifdef __MINT__
		ttcooked(&ltold);
#endif
		(void) kill(0, SIGTSTP);
		(void) sigsetmask(omask);
#ifdef __MINT__
		ttraw(&ltold,&ltnew);
#endif
		InitScreen(Mailbox);
	}
	else
		PutStatus("No shell active");
}

void ListMessage(Mbox *M)
{	int cn;
	char ch,regel[MAXSTR+1];
	Msg *Current = M->Msglist[M->CurMsg];
  	long start = Current->start;
  	long end   = M->Msglist[M->CurMsg+1]->start;

	Clrscr();

	OpenMailbox(M);
	fseek(M->fd,start,SEEK_SET);
	while (ftell(M->fd) < end)
	{	for(cn=1;cn<LINES && ftell(M->fd) < end;cn++)
		{	fgets (regel,MAXSTR,M->fd);
			fputs(regel,stdout);
		}
		PutStatus("  Press 'i' to return to menu ...");
		ch=GetChar();
		if(ch == 'i') break;
		Clrtoeol();
	}
	if(Current->flag == 'N')
		Current->flag = ' ';	/* mark as read */

	CloseMailbox(M);
	InitScreen(M);
}

void SaveMessage(Mbox *M)
{	char msgname[MAXSTR+1],regel[MAXSTR+1];
	FILE *msg;
  	long start = M->Msglist[M->CurMsg  ]->start;
  	long end   = M->Msglist[M->CurMsg+1]->start;

	Gotoxy(0,STARTPROMPT + 1); Clrtoeol();
	PutStr("Save as: ");
	GetStr(msgname,MAXSTR);
	RemoveCR(msgname);

	if((msg = fopen (ux2dos(msgname), "w")) == NULL)
	{	PutStatus("Can't save mail to file");
		return;
	}
	OpenMailbox(M);
	fseek(M->fd,start,SEEK_SET);

	while (ftell(M->fd) < end)
	{	fgets(regel,MAXSTR,M->fd);
		fputs(regel,msg);
	}

	CloseMailbox(M);
	fclose(msg);
	PutStatus("Mail saved to: %s",msgname);
}

int StartEditor(Mbox *M,char *msgname)
{	char *arg[3];
	int stat=0;

	Clrscr();
	arg[0]=M->Editor; arg[1]=msgname; arg[2]=NULL;

	if(access(ux2dos(arg[0]),X_OK) == 0)
	{
#ifdef __AMIGA__
		switch(vfork())
#else
		switch((int)fork())
#endif
		{	case  0 : execv(arg[0],arg); break;
			case -1 : PutStatus("Can't fork editor !"); return -1;
			default : wait(&stat); break;
		}
	}
	else
	{	PutStatus("Can't open editor %s",M->Editor);
		return -1;
	}
	return stat;
}

void DeadLetter(char *msgname)
{	char *dlname = DEADLETTER;
	PutStatus("Can't send message, saved in %s",dlname);
	remove(dlname);
	rename(msgname,dlname);
}

void OutboundMail(char *dest, char *subj, char *msgname)
{	/* this can be replaced by an external function that
	   drops mail on Internet or uucp. 
	*/
	subj=subj;	/* only to avoid compiler warnings ! */
	Gotoxy(0,LINES-3);
	PutStr("Only local mail: can't send to %s",dest);
	DeadLetter(msgname);
}
	
void MailMsgTo(Mbox *M,char *msgname,char *dest,char *subj)
{	char destbox[MAXSTR+1];
	char c=0,buffer[MAXSTR+1];
	time_t t;
	FILE *destfile, *msgfile;
	
	/* ask for confirmation or to reenter editor */

	while(c != 's')
	{	Clrscr();
		Gotoxy(0,STARTPROMPT);
		PutStr("r)estart editor, s)end or f)orget ? ");

		switch(c=GetChar())
		{	case 'f':
				PutStatus("Mail cancelled");
				InitScreen(M);
				remove(msgname);	/* delete temporary file */
				return;
			case 'r':
				StartEditor(M,msgname);
				break;
			default:
				break;
		}
	}

	InitScreen(M);

	/* catch UUCP and internet mail */
	
	if(strchr(dest,'@') != NULL || strchr(dest,'!') != NULL)
	{	OutboundMail(dest,subj,msgname);
		return;
	}
	
	sprintf (destbox, "%s/%s", MAILDIR, dest);

	if((destfile = fopen(ux2dos(destbox),"a")) == NULL)
	{	DeadLetter(msgname);
		return;
	}
	time(&t);
	
	/* first line must be conform mail headers under UNIX */

	fprintf(destfile,"From %s %s",M->User,ctime(&t));
	fprintf(destfile,"To: %s\n",dest);
	fprintf(destfile,"Subject: %s\n",subj);
	fprintf(destfile,"Mailer: %s\n\n",version);

	if((msgfile  = fopen(ux2dos(msgname),"r")) != NULL)
	{	while (!feof(msgfile))
		{	*buffer=0;
			fgets (buffer,MAXSTR,msgfile);
			fputs (buffer,destfile);
		}
		fclose(msgfile);
		remove(msgname);	/* delete temporary file */
	}
	fprintf(destfile,"\n");	 /* extra empty line */
	fclose(destfile);	
	PutStatus("Mail sent !");
}

void SendMail(Mbox *M)
{	char *msgname=tmpnam(NULL);
	char dest[MAXSTR+1], subj[MAXSTR+1];

	Gotoxy(0,STARTPROMPT + 1); Clrtoeol();
	PutStr("Mail to: ");
	GetStr(dest,MAXSTR);	RemoveCR(dest);
	Gotoxy(0,STARTPROMPT + 2);	Clrtoeol();
	PutStr("Subject: ");
	GetStr(subj,MAXSTR);	RemoveCR(subj);
	
	if(StartEditor(M,msgname))
		return;
	MailMsgTo(M,msgname,dest,subj);
}

void ForwardMail(Mbox *M)
{	char *msgname=tmpnam(NULL);
	char regel[MAXSTR+1], dest[MAXSTR+1], subj[MAXSTR+1];
	long start,end;
	FILE *msg;

	Gotoxy(0,STARTPROMPT + 1);	Clrtoeol();
	PutStr("Forward to: ");
	GetStr(dest,MAXSTR);	RemoveCR(dest);
	Gotoxy(0,STARTPROMPT + 2);	Clrtoeol();
	sprintf(subj,"%s (fwd)",M->Msglist[M->CurMsg]->subject);
	PutStr("Subject: %s",subj);
	GetChar(); /* must be possible to edit later */

	if((msg = fopen (ux2dos(msgname), "w")) == NULL)
	{	PutStatus("Can't open temporary file ");
		return;
	}
	OpenMailbox(M);

	start = M->Msglist[M->CurMsg  ]->start;
  	end   = M->Msglist[M->CurMsg+1]->start;
	fseek(M->fd,start,SEEK_SET);

	while (ftell(M->fd) < end)
	{	fgets(regel,MAXSTR,M->fd);
		fputs(PREFIX,msg);
		fputs(regel,msg);
	}

	CloseMailbox(M);
	fclose(msg);
	
	Gotoxy(40,STARTPROMPT + 2);
	PutStr("edit message ? (n) ");
	if(GetChar() == 'y')
		if(StartEditor(M,msgname))
			return;

	MailMsgTo(M,msgname,dest,subj);
}

void ReplyMail(Mbox *M)
{	char *msgname=tmpnam(NULL);
	char dest[MAXSTR+1], subj[MAXSTR+1];

	Gotoxy(0,STARTPROMPT + 1); Clrtoeol();
	PutStr("Reply to: %s",M->Msglist[M->CurMsg]->sender);
	strncpy(dest,M->Msglist[M->CurMsg]->sender,MAXSTR);

	Gotoxy(0,STARTPROMPT + 2); Clrtoeol();
	sprintf(subj,"Re: %s",M->Msglist[M->CurMsg]->subject);
	PutStr("Subject: %s",subj);
	GetChar(); /* must be possible to edit later */
	
	if(StartEditor(M,msgname))
		return;
	MailMsgTo(M,msgname,dest,subj);
}

void RebuildMailFile(Mbox *M)
{	FILE *new;
	char regel[MAXSTR+1],newname[MAXSTR+1];
	char *statusline = "Status: RO\n";
	long start,end;
	int x,delflag=0;
	
	/* check if we need to update */

	for(x=0;x<M->Count;x++)
		if(M->Msglist[x]->flag == 'D')
			break;
	if(x < M->Count)
	{	Gotoxy(40,STARTPROMPT); Clrtoeol();
		PutStr("Delete marked messages ? (n) ");
		if(GetChar() == 'y')
			delflag = 1;
	}

	PutStatus("Updating mailbox %s ....",M->Path);
	sprintf(newname,"%s.new",M->Path);
	if((new = fopen (ux2dos(newname), "w")) == NULL)
	{	PutStatus("Can't open new mailbox");
		return;
	}
	OpenMailbox(M);

	for(x=0;x<M->Count;x++)
	{	if(M->Msglist[x]->flag == 'D' && delflag == 1)
			continue;	/* skip deleted messages */

		start = M->Msglist[x  ]->start;
  		end   = M->Msglist[x+1]->start;
		fseek(M->fd,start,SEEK_SET);

		if(fgets(regel,MAXSTR,M->fd) != NULL)
			fputs(regel,new);		/* Write first (From) line */

		while (ftell(M->fd) < end && !feof(M->fd))
		{	fgets(regel,MAXSTR,M->fd);

			if(M->Msglist[x]->flag != 'N')
			{
				/* Add a new statusline */
				if(M->Msglist[x]->status == 0)
				{	while(strchr(regel,':') != NULL &&
						 ftell(M->fd) < end && !feof(M->fd))
					{	fputs(regel,new);
						fgets(regel,MAXSTR,M->fd);
					}
					fputs(statusline,new);
					M->Msglist[x]->status = 1;
				}

				/* Or update an existing statusline */
				if(!strncmp(regel,"Status:",7))
				{	fputs(statusline,new);
					continue;
				}
			}
			fputs(regel,new);
		}
	}
	
	/* this is to copy new messages arrived during the session !! */

	/* goto 'official' end of file */
	fseek(M->fd,M->Msglist[M->Count]->start,SEEK_SET);

	while (fgets(regel,MAXSTR,M->fd) != NULL)
		fputs(regel,new);

	CloseMailbox(M);
	fclose(new);
	if(! remove(M->Path))
		if( !rename(newname,M->Path))
			return;
	PutStatus("Update mailbox %s failed",M->Path);
}

void HandleQuit(Mbox *M)
{	Gotoxy(40,STARTPROMPT);
	PutStr("Do you want to quit ? (y) ");
	if(GetChar() != 'n')
	{	RebuildMailFile(M);
		putchar('\n');
		EndTermcap();
#ifdef __MINT__
		ttcooked(&ltold);
#endif
		exit(0);
	}
}

void HandleExit(void)
{	Gotoxy(40,STARTPROMPT);
	PutStr("Exit without update ? (y) ");
	if(GetChar() != 'n')
	{	putchar('\n');
		EndTermcap();
#ifdef __MINT__
		ttcooked(&ltold);
#endif
		exit(0);
	}
}

int main(int argc,char *argv[]) 
{	char cmd[MAXSTR+1];
	char editflag=0,fileflag=0;
	Mbox Mailbox;
	char *tmp;

#ifndef __MINT__
	struct termios p;

	tcgetattr(fileno(stdin),&p);
	p.c_lflag &= ~ICANON;
	p.c_cc[VTIME] = 0;
	p.c_cc[VMIN]  = 1;
	tcsetattr(fileno(stdin),TCSANOW,&p);
#else
	ttraw(&ltold,&ltnew); /* disable Ctrl-Z */
#endif

	while(--argc>0)			/* parse options */
	{
		if(*argv[1]=='-')
		{	switch(*(++argv[1]))
			{	case 'f':
					strcpy(Mailbox.Path,argv[2]);
					fileflag = 1;
					break;
				case 'e':
					strcpy(Mailbox.Editor,argv[2]);
					editflag = 1;
					break;
			 	default :
			 		usage();
			}
		}
		++argv;
	}	
	InitTermcap();

/* Initialize */

	if((tmp=getenv("LOGNAME")) == NULL)
		tmp="root";
	strncpy(Mailbox.User,tmp,MAXNAME);

	if(!fileflag)
		sprintf (Mailbox.Path, "%s/%s", MAILDIR, Mailbox.User);
	if(!editflag)
		sprintf (Mailbox.Editor, "%s", EDITOR);

	BuildMailList(&Mailbox);
	InitScreen(&Mailbox);

	while(1)
	{	Gotoxy(0,STARTPROMPT); Clrtoeol();
		PutStr("Command: ");
		*cmd=GetChar();
		if(!isdigit(*cmd))
			PutStatus("");	/* clear statusline */
		switch(*cmd)
		{	case'\r':
			case'\n': ListMessage(&Mailbox);
					  SetCurMsg(&Mailbox,Mailbox.CurMsg+1,0);
					  break;
			case '!': SuspendMail(&Mailbox);	/* shell */
					  break;
			case 'd': Mailbox.Msglist[Mailbox.CurMsg]->flag = 'D';
					  PutMessage(&Mailbox,Mailbox.CurMsg);
					  SetCurMsg(&Mailbox,Mailbox.CurMsg+1,0);
					  break;
			case 'u': Mailbox.Msglist[Mailbox.CurMsg]->flag = 'U';
					  PutMessage(&Mailbox,Mailbox.CurMsg);
					  SetCurMsg(&Mailbox,Mailbox.CurMsg,0);
					  break;
			case 'm': SendMail(&Mailbox);
					  break;
			case 'f': ForwardMail(&Mailbox);
					  break;
			case 'r': ReplyMail(&Mailbox);
					  break;
			case 'k': SetCurMsg(&Mailbox,Mailbox.CurMsg-1,1);
					  break;
			case 'j': SetCurMsg(&Mailbox,Mailbox.CurMsg+1,1);
					  break;
			case 's': SaveMessage(&Mailbox);
					  break;
			case '$': RebuildMailFile(&Mailbox);
					  BuildMailList(&Mailbox);
					  InitScreen(&Mailbox);
					  break;
			case 'q': HandleQuit(&Mailbox);
					  break;
			case 'x': HandleExit();
					  break;
			default : if(atoi(cmd) != 0)
					  {	GetStr(cmd+1,MAXSTR-1);
						SetCurMsg(&Mailbox,atoi(cmd) - 1,1);
						PutStatus("Current message set to %d",
							Mailbox.CurMsg + 1);
					  }
					  else
					  	PutStatus("Unknown command !");		  
		}
	}
}
