/*
 *	Simple mail user interface for KA9Q IP/TCP package.
 *	A.D. Barksdale Garbee II, aka Bdale, N3EUA
 *	Copyright 1986 Bdale Garbee, All Rights Reserved.
 *	Permission granted for non-commercial copying and use, provided
 *	this notice is retained.
 *	Copyright 1987 1988 Dave Trulli NN2Z, All Rights Reserved.
 *	Permission granted for non-commercial copying and use, provided
 *	this notice is retained.
 *
 *	Ported to NOS at 900120 by Anders Klemets SM0RGV.
 *
 * ST NOS Version by David Nash
 */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include "global.h"
#include "ftpserv.h"
#include "smtp.h"
#include "proc.h"
#include "usock.h"
#include "socket.h"
#include "telnet.h"
#include "timer.h"
#include "session.h"
#include "files.h"

#define		SETVBUF
#if	defined(UNIX) || defined(MICROSOFT)
#include	<sys/types.h>
#endif
/*
#if	defined(UNIX) || defined(MICROSOFT) || defined(__TURBOC__)
#include	<sys/stat.h>
#endif
#ifdef AZTEC
#include <stat.h>
#endif
*/
#ifndef ATARI
#include <fcntl.h>
#endif
#include "bm.h"
#include "mailbox.h"

#ifdef SETVBUF
#define		MYBUF	1024
#endif

void scanmail(struct mbx *m);

extern long ftell();
static char Badmsg[] = "Invalid Message number %d\n";
static char Nomail[] = "No messages\n";
static char Noaccess[] = "Unable to access %s\n";
static int readnotes __ARGS((struct mbx *m,FILE *ifile,int update));
static long isnewmail __ARGS((struct mbx *m));
static int initnotes __ARGS((struct mbx *m));
static int lockit __ARGS((struct mbx *m));
static long fsize __ARGS((char *name));
static void mfclose __ARGS((struct mbx *m));
static int tkeywait __ARGS((char *prompt,int flush));

static int initnotes(struct mbx *m)
{
#ifndef ATARI	
	FILE	*tmpfile();
#endif	
	FILE	*ifile;
	register struct	let *cmsg;
	char buf[256];
	int 	i, ret;

	sprintf(buf,"%s/%s.txt",Mailspool,m->area);
	if ((ifile = fopen(buf,READ_TEXT)) == NULLFILE)
		return 0;
	fseek(ifile,0L,2);	 /* go to end of file */
	m->mboxsize = ftell(ifile);
	rewind(ifile);
	if(!stricmp(m->area,m->name)) /* our private mail area */
		m->mysize = m->mboxsize;
	if ((m->mfile = tmpfile()) == NULLFILE) {
		(void) fclose(ifile);
		return -1;
	}
#ifdef	SETVBUF
	if (m->stdinbuf == NULLCHAR)
		m->stdinbuf = mallocw(MYBUF);
	setvbuf(ifile, m->stdinbuf, _IOFBF, MYBUF);
	if (m->stdoutbuf == NULLCHAR)
		m->stdoutbuf = mallocw(MYBUF);
	setvbuf(m->mfile, m->stdoutbuf, _IOFBF, MYBUF);
#endif
	m->nmsgs = 0;
	m->current = 0;
	m->change = 0;
	m->newmsgs = 0;
	m->anyread = 0;
	/* Allocate space for reading messages */
	free((char *)m->mbox);
	m->mbox = (struct let *)callocw(Maxlet+1,sizeof(struct let));
	ret = readnotes(m,ifile,0);
	(void) fclose(ifile);
#ifdef SETVBUF
	free(m->stdinbuf);
	m->stdinbuf = NULLCHAR;
#endif
	if (ret != 0)
		return -1;
	for (cmsg = &m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++)  
		if ((cmsg->status & BM_READ) == 0) {
			m->newmsgs++;
			if (m->current == 0)
				m->current = i;
		}
	/* start at one if no new messages */
	if (m->current == 0)
		m->current++;

	return 0;
}

/* readnotes assumes that ifile is pointing to the first
 * message that needs to be read.  For initial reads of a
 * notesfile, this will be the beginning of the file.  For
 * rereads when new mail arrives, it will be the first new
 * message.
 */
static int readnotes(struct mbx *m,FILE *ifile,int update)
{
	char 	tstring[LINELEN];
	long	cpos;
	register struct	let *cmsg;
	register char *line;

	cmsg = (struct let *)NULL;
	line = tstring;
	while(fgets(line,LINELEN,ifile) != NULLCHAR) {
		/* scan for begining of a message */
		if(strncmp(line,"From ",5) == 0) {
			pwait(NULL);
			cpos = ftell(m->mfile);
			fputs(line,m->mfile);
			if (m->nmsgs == Maxlet) {
				tprintf("Mail box full: > %d messages\n",Maxlet);
				mfclose(m);
				return -1;
			}
			m->nmsgs++;
			cmsg = &m->mbox[m->nmsgs];
			cmsg->start = cpos;
			if(!update)
				cmsg->status = 0;
			cmsg->size = strlen(line);
			while (fgets(line,LINELEN,ifile) != NULLCHAR) {
				if (*line == '\n') { /* done header part */
					cmsg->size++;
					putc(*line, m->mfile);
					break;
				}
				if (htype(line) == STATUS) {
					if (line[8] == 'R') 
						cmsg->status |= BM_READ;
					continue;
				}
				cmsg->size += strlen(line);
				if (fputs(line,m->mfile) == EOF) {
					tprintf("tmp file: %s",strerror(errno));
					mfclose(m);
					return -1;
				}

			}
		} else if (cmsg) {
			cmsg->size += strlen(line);
			fputs(line,m->mfile);
		}
	}
	return 0;
}

/* list headers of a notesfile a message */
int
dolistnotes(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	struct mbx *m;
	register struct	let *cmsg;
	register char	*cp, *s;
	char	smtp_date[SLINELEN], smtp_from[SLINELEN];
	char	smtp_subject[SLINELEN], tstring[LINELEN], type;
	int	start, stop;
	long	size;
	char	*area;

	m = (struct mbx *) p;
	if (m->mfile == NULLFILE) {
		tprintf(Nomail);
		return 0;
	}

	area = strdup(m->area);
	while((cp = strchr(area,'/')) != NULLCHAR)
		*cp = '.';
	tprintf("Mail area: %s  %d message%s -  %d new\n\n",area,m->nmsgs,
		m->nmsgs == 1 ? " " : "s ", m->newmsgs);
	free(area);

	stop = m->nmsgs;
	if(m->stype == 'L') {		/* LL (List Latest) command */
	     if(argc > 1)
		  start = stop - atoi(argv[1]) + 1;
	     else
		  start = stop;
	}
	else {
	     if(argc > 1)
		  start = atoi(argv[1]);
	     else
		  start = 1;
	     if(argc > 2)
		  stop = atoi(argv[2]);
	}
	if(stop > m->nmsgs)
		stop = m->nmsgs;
	if(start < 1 || start > stop) {
		tprintf("Invalid range.\n");
		return 0;
	}
	for (cmsg = &m->mbox[start]; start <= stop; start++, cmsg++) {
		*smtp_date = '\0';
		*smtp_from = '\0';
		*smtp_subject = '\0';
		type = ' ';
		fseek(m->mfile,cmsg->start,0);
		size = cmsg->size;
		while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
		       != NULLCHAR) {
			if (*tstring == '\n')	/* end of header */
				break;
			size -= strlen(tstring);
			rip(tstring);
			/* handle continuation later */
			if (*tstring == ' '|| *tstring == '\t')
				continue;
			switch(htype(tstring)) {
			case FROM:
				cp = getaddress(tstring,0);
				sprintf(smtp_from,"%.30s",
					cp != NULLCHAR ? cp : "");
				break;
			case SUBJECT:
				sprintf(smtp_subject,"%.34s",&tstring[9]);
				break;
			case DATE:
				if ((cp = strchr(tstring,',')) == NULLCHAR)
					cp = &tstring[6];
				else
					cp++;
				/* skip spaces */
				while (*cp == ' ') cp++;
				if(strlen(cp) < 17)
					break; 	/* not a valid length */
				s = smtp_date;
				/* copy day */
				if (atoi(cp) < 10 && *cp != '0') {
					*s++ = ' ';
				} else
					*s++ = *cp++;
				*s++ = *cp++;

				*s++ = ' ';
				*s = '\0';
				while (*cp == ' ')
					cp++;
				strncat(s,cp,3);	/* copy month */
				cp += 3;
				while (*cp == ' ')
					cp++;
				/* skip year */
				while (isdigit(*cp))
					cp++;
				/* copy time */
				strncat(s,cp,6); /* space hour : min */
				break;
			case BBSTYPE:
				type = tstring[16];
				break;
			case NOHEADER:
				break;
			}
		}
		if((type == m->stype && m->stype != ' ') || m->stype == ' '
		   || m->stype == 'L')
		     tprintf("%c%c%c%3d %-27.27s %-12.12s %5ld %.25s\n",
			     (start == m->current ? '>' : ' '),
			     (cmsg->status & BM_DELETE ? 'D' : ' '),
			     (cmsg->status & BM_READ ? 'Y' : 'N'),
			     start, smtp_from, smtp_date,
			     cmsg->size, smtp_subject);
	}
	return 0;
}

/*  save msg on stream - if noheader set don't output the header */
int msgtofile(struct mbx *m,int msg,FILE *tfile,int noheader)
{
	char	tstring[LINELEN];
	long 	size;

	if (m->mfile == NULLFILE) {
		tprintf(Nomail);
		return -1;
	}
	fseek(m->mfile,m->mbox[msg].start,0);
	size = m->mbox[msg].size;

	if (noheader) {
		/* skip header */
		while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
		       != NULLCHAR) {
			size -= strlen(tstring);
			if (*tstring == '\n')
				break;
		}
	}
	while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
	       != NULLCHAR) {
		size -= strlen(tstring);
		fputs(tstring,tfile);
		if (ferror(tfile)) {
			tprintf("Error writing mail file\n");
			return -1;
		}
	}
	return 0;
}

/*  dodelmsg - delete message in current notesfile */
int
dodelmsg(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	struct mbx *m;
	int msg,i;
	m = (struct mbx *) p;
	if (m->mfile == NULLFILE) {
		tprintf(Nomail);
		return 0;
	}
	for(i = 1; i < argc; ++i) {
		msg = atoi(argv[i]);
		if(msg < 0 || msg > m->nmsgs) {
			tprintf(Badmsg,msg);
			continue;
		}
		/* Check if we have permission to delete others mail */
		if(!(m->privs & FTP_WRITE) && stricmp(m->area,m->name)) {
			tprintf(Noperm);
			return 0;
		}
		m->mbox[msg].status |= BM_DELETE;
		tprintf("Msg %d Killed.\n", msg);
		m->change = 1;
	}
	return 0;
}
/* close the temp file while coping mail back to the mailbox */
int closenotes(struct mbx *m)
{
	register struct	let *cmsg;
	register char *line;
	char tstring[LINELEN], buf[256];
	long size;
	int i, nostatus = 0, nodelete;
	FILE	*nfile;

	if (m->mfile == NULLFILE)
		return 0;

	if(!m->change) {		/* no changes were made */
		mfclose(m);
		m->mboxsize = 0;
		return 0;
	}
	/* If this area is a public message area, then we will not add a
	 * Status line to indicate that the message has been read.
	 */
	nostatus = isarea(m->area);

	/* Don't delete messages from public message areas unless you are
	 * a BBS.
	 */
	if(nostatus)
		nodelete = !(m->privs & SYSOP_CMD);
	else
		nodelete = 0;

	/* See if any messages have been forwarded, otherwise just close
	 * the file and return since there is nothing to write back.
	 */
	if(nostatus && nodelete) {
		for(i=1; i <= m->nmsgs; ++i)
			if(m->mbox[i].status & BM_FORWARDED)
				break;
		if(i > m->nmsgs) {
			mfclose(m);
			m->mboxsize = 0;
			return 0;
		}
	}
	line = tstring;
	scanmail(m);
	if(lockit(m))
		return -1;
	sprintf(buf,"%s/%s.txt",Mailspool,m->area);
	if ((nfile = fopen(buf,WRITE_TEXT)) == NULLFILE) {
		tprintf(Noaccess,buf);
		mfclose(m);
		m->mboxsize = 0;
		rmlock(Mailspool,m->area);
		return -1;
	}
	/* copy tmp file back to notes file */
	for (cmsg = &m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++) {
		fseek(m->mfile,cmsg->start,0);
		size = cmsg->size;
		/* It is not possible to delete messages if nodelete is set */
		if ((cmsg->status & BM_DELETE) && !nodelete)
			continue;
		/* copy the header */
		while (size > 0 && fgets(line,LINELEN,m->mfile) != NULLCHAR) {
			size -= strlen(line);
			if (*line == '\n') {
				if (cmsg->status & BM_FORWARDED)
					fprintf(nfile,"%s%s\n",Hdrs[XFORWARD],
						m->name);
				if ((cmsg->status & BM_READ) != 0 && !nostatus)
					fprintf(nfile,"%sR\n",Hdrs[STATUS]);
				fprintf(nfile,"\n");
				break;
			}
			fputs(line,nfile);
			/* pwait(NULL);  can cause problems if exiting NOS */
		}
		while (size > 0 && fgets(line,LINELEN,m->mfile) != NULLCHAR) {
			fputs(line,nfile);
			size -= strlen(line);
			/* pwait(NULL);   dont want no damaged files */
			if (ferror(nfile)) {
				tprintf("Error writing mail file\n");
				(void) fclose(nfile);
				mfclose(m);
				m->mboxsize = 0;
				rmlock(Mailspool,m->area);
				return -1;
			}
		}
	}
	m->nmsgs = 0;
	if (!stricmp(m->name,m->area))
		m->mysize = ftell(nfile); /* Update the size of our mailbox */
	/* remove a zero length file */
	if (ftell(nfile) == 0L)
		(void) unlink(buf);
	(void) fclose(nfile);
	mfclose(m);
	m->mboxsize = 0;
	rmlock(Mailspool,m->area);
	pwait(NULL);
	return 0;
}

/* Returns 1 if name is a public message Area, 0 otherwise */
int
isarea(name)
char *name;
{
	char buf[LINELEN], *cp;
	FILE *fp;
	if((fp = fopen(Arealist,READ_TEXT)) == NULLFILE)
		return 0;
	while(fgets(buf,sizeof(buf),fp) != NULLCHAR) {
		/* The first word on each line is all that matters */
		if((cp = strchr(buf,' ')) == NULLCHAR)
			if((cp = strchr(buf,'\t')) == NULLCHAR)
				continue;
		*cp = '\0';
		if((cp = strchr(buf,'\t')) != NULLCHAR)
			*cp = '\0';
		if(stricmp(name,buf) == 0) {	/* found it */
			fclose(fp);
			return 1;
		}
	}
	fclose(fp);
	return 0;
}

static int lockit(struct mbx *m)
{
	int c, cnt = 0;

	while(mlock(Mailspool,m->area)) {
		Pause(1000L/MSPTICK);	/* Wait one second */
		if(++cnt == 10) {
			cnt = 0;
			c = tkeywait("Mail file is busy, Abort or Retry ? ",1);
			if (c == 'A' || c == 'a' || c == EOF) {
				mfclose(m);
				return 1;
			}
		}
	}
	return 0;
}

/* read the next message or the current one if new */
int
doreadnext(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	struct mbx *m;
	char buf[10], *newargv[2];
	m = (struct mbx *) p;
	if (m->mfile == NULLFILE)
		return 0;
	if ((m->mbox[m->current].status & BM_READ) != 0) {
		if (m->current == 1 && m->anyread == 0)
			;
		else if (m->current < m->nmsgs) {
			m->current++;
		} else {
			tprintf("Last message\n");
			return 0;
		}
	}
	sprintf(buf,"%d",m->current);
	newargv[0] = "read";
	newargv[1] = buf;
	m->anyread = 1;
	return doreadmsg(2,newargv,p);
}

/*  display message on the crt given msg number */
int
doreadmsg(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	struct mbx *m;
	register int c, col, lin;
	char	buf[MAXCOL+2], *cp, *cp2;
	int	msg, cnt, i, usemore, verbose, mbxheader, pathcol;
	int	header, lastheader;
	long 	size;

	m = (struct mbx *) p;
	if (m->mfile == NULLFILE) {
		tprintf(Nomail);
		return 0;
	}
	if(m->type == TELNET || m->type == TIP)
		usemore = 1;	/* Display More prompt */
	else
		usemore = 0;
	lin = MAXLIN-1;
	for(i = 1; i < argc; ++i) {
		msg = atoi(argv[i]);
		if( msg < 1 || msg > m->nmsgs) {
			tprintf(Badmsg,msg);
			return 0;
		}
		fseek(m->mfile,m->mbox[msg].start,0);
		size = m->mbox[msg].size;
		m->current = msg;
		header = NOHEADER;
		mbxheader = 0;
		if(*argv[0] == 'v')
			verbose = 1;	/* display all header lines */
		else
			verbose = 0;

		tprintf("Message #%d %s\n", msg,
			m->mbox[msg].status & BM_DELETE ? "[Deleted]" : "");
		if ((m->mbox[msg].status & BM_READ) == 0) {
			m->mbox[msg].status |= BM_READ;
			m->change = 1;
			m->newmsgs--;
		}
		--lin;
		col = 0;
		while (!feof(m->mfile) && size > 0) {
			for (col = 0;  col < MAXCOL;) {
				c = getc(m->mfile);
				size--;
				if (feof(m->mfile) || size == 0) /* end this line */
					break;
				if (c == '\t') {
					cnt = col + 8 - (col & 7);
					if (cnt >= MAXCOL) /* end this line */
						break;
					while (col < cnt)
						buf[col++] = ' ';
				} else {
					if (c == '\n')
						break;
					buf[col++] = c;
				}
			}
			if(col < MAXCOL)
				buf[col++] = '\n';
			buf[col] = '\0';
			if(mbxheader > 0) {
			     /* Digest R: lines and display as a Path: line */
			     if(strncmp(buf,"R:",2) != 0 ||
				(cp = strchr(buf,'@')) == NULLCHAR) {
				  tputc('\n');
				  mbxheader = -1; /* don't get here again */
				  verbose = 1;
			     }
			     else {
				  if(*(++cp) == ':')
				       ++cp;
				  for(cp2 = cp; isalnum(*cp2); ++cp2)  ;
				  *cp2 = '\0';
				  if(mbxheader++ == 1) {
				       tputs("Path: ");
				       pathcol = 5;
				       --lin;
				  }
				  else {
				       tputc('!');
				       if(++pathcol + strlen(cp) > MAXCOL-3){
					    tputs("\n      ");
					    pathcol = 5;
					    --lin;
				       }
				  }
				  tputs(cp);
				  pathcol += strlen(cp);
				  ++lin;	/* to allow for not printing it later */
			     }
			}
			if(col == 1 && !verbose && !mbxheader)
			     /* last header line reached */
			     mbxheader = 1;
			if(verbose)
				tputs(buf);
			if(!verbose && !mbxheader){
				lastheader = header;
				if(!isspace(*buf))
					header = htype(buf);
				else
					header = lastheader;
				switch(header) {
				case TO:
				case CC:
				case FROM:
				case DATE:
				case SUBJECT:
				case APPARTO:
				case ORGANIZATION:
					tputs(buf);
					break;
				default:
					++lin;
				}
			}
			col = 0;
			if(usemore && --lin == 0){
				c = tkeywait("--More--",0);
				lin = MAXLIN-1;
				if(c == -1 || c == 'q' || c == 'Q')
					break;
				if(c == '\n' || c == '\r')
					lin = 1;
			}
		}
	}
	return 0;
}

/* Set up m->to when replying to a message. The subject is returned in
 * m->line.
 */
int mbx_reply(int argc,char *argv[],struct mbx *m,struct list **cclist,char **rhdr)
{
	char subject[MBXLINE], *msgid = NULLCHAR, *date = NULLCHAR;
	char *cp;
	int msg, lastheader, header = NOHEADER;
	long size;

	/* Free anything that might be allocated
	 * since the last call to mbx_to() or mbx_reply()
	 */
	free(m->to);
	m->to = NULLCHAR;
	free(m->tofrom);
	m->tofrom = NULLCHAR;
	free(m->tomsgid);
	m->tomsgid = NULLCHAR;
	free(m->origto);
	m->origto = NULLCHAR;
	subject[0] = '\0';

	if(argc == 1)
	     msg = m->current;
	else
	     msg = atoi(argv[1]);
	if (m->mfile == NULLFILE) {
	     if(m->sid & MBX_SID)
		  tputs("NO - ");
		tputs(Nomail);
		return 0;
	}
	if(msg < 1 || msg > m->nmsgs) {
	     if(m->sid & MBX_SID)
		  tputs("NO - ");
	     tputs(Badmsg);
	     return -1;
	}
	fseek(m->mfile,m->mbox[msg].start,0);
	size = m->mbox[msg].size;
	m->current = msg;
	while(size > 0 && fgets(m->line,MBXLINE-1,m->mfile) != NULLCHAR) {
	     size -= strlen(m->line);
	     if(m->line[0] == '\n')	/* end of header */
		  break;
	     rip(m->line);
	     lastheader = header;
	     if(!isspace(m->line[0])) {
		  header = htype(m->line);
		  lastheader = NOHEADER;
	     }
	     switch(header) {
	     case SUBJECT:
		  if(strlen(m->line) > 11 && !strnicmp(&m->line[9],"Re:",3))
		       strcpy(subject,&m->line[9]);
		  else
		       sprintf(subject,"Re: %s",&m->line[9]);
		  break;
	     case FROM:
		  if(m->to == NULLCHAR && (cp = getaddress(m->line,0)) !=
		     NULLCHAR)
		       m->to = strdup(cp);
		  break;
	     case REPLYTO:
		  if((cp = getaddress(m->line,0)) != NULLCHAR) {
		       free(m->to);
		       m->to = strdup(cp);
		  }
		  break;
	     case MSGID:
		  free(msgid);
		  msgid = strdup(&m->line[12]);
		  break;
	     case DATE:
		  free(date);
		  date = strdup(&m->line[6]);
		  break;
	     case TO:
	     case CC:
	     case APPARTO:
		  /* Get addresses on To, Cc and Apparently-To lines */
		  cp = m->line;
		  m->line[strlen(cp)+1] = '\0';	/* add extra null at end */
		  for(;;) {
		       if((cp = getaddress(cp,lastheader == header ||
					   cp != m->line)) == NULLCHAR)
			    break;
		       addlist(cclist,cp,0);
		       /* skip to next address, if any */
		       cp += strlen(cp) + 1;
		  }
		  break;
	     }
	}
	if(msgid != NULLCHAR || date != NULLCHAR) {
	     *rhdr = mallocw(LINELEN);
	     sprintf(*rhdr,"In-Reply-To: your message ");
	     if(date != NULLCHAR) {
		  sprintf(m->line,"of %s.\n",date);
		  strcat(*rhdr,m->line);
		  if(msgid != NULLCHAR)
		       strcat(*rhdr,"             ");
	     }
	     if(msgid != NULLCHAR) {
		  sprintf(m->line,"%s\n",msgid);
		  strcat(*rhdr,m->line);
	     }
	     free(msgid);
	     free(date);
	}
	strcpy(m->line,subject);
	return 0;
}

void scanmail(struct mbx *m)		 /* Get any new mail */
{
	FILE *nfile;
	int ret, cnt;
	char buf[256];
	long diff;

	if ((diff = isnewmail(m)) == 0L)
		return;
	if(lockit(m))
		return;
	if(m->mfile == NULLFILE || diff < 0L) {
		/* This is the first time scanmail is called, or the
		 * mail file size has decreased. In the latter case,
		 * any changes we did to this area will be lost, but this
		 * is not fatal.
		 */
		initnotes(m);
		rmlock(Mailspool,m->area);
		return;
	}
	sprintf(buf,"%s/%s.txt",Mailspool,m->area);
	if ((nfile = fopen(buf,READ_TEXT)) == NULLFILE)
		tprintf(Noaccess,buf);
	else {
		/* rewind tempfile */
		fseek(m->mfile,0L,0);
		cnt = m->nmsgs;
		/* Reread all messages since size they may have changed
		 * in size after a X-Forwarded-To line was added.
		 */
		m->nmsgs = 0;
		ret = readnotes(m,nfile,1);   /* get the mail */
		m->newmsgs += m->nmsgs - cnt;
		m->mboxsize = ftell(nfile);
		if(!stricmp(m->name,m->area))
			m->mysize = m->mboxsize;
		(void) fclose(nfile);
		if (ret != 0)
			tprintf("Error updating mail file\n");
	}
	rmlock(Mailspool,m->area);
}

/* Check the current mailbox to see if new mail has arrived.
 * Returns the difference in size.
 */
static long isnewmail(struct mbx *m)
{
	char buf[256];
	sprintf(buf,"%s/%s.txt",Mailspool,m->area);
	return fsize(buf) - m->mboxsize;
}

/* Check if the private mail area has changed */
long isnewprivmail(struct mbx *m)
{
	long cnt;
	char buf[256];
	sprintf(buf,"%s/%s.txt",Mailspool,m->name);
	cnt = m->mysize;
	m->mysize = fsize(buf);
	return m->mysize - cnt; /* != 0 not more than once */
}

char *Hdrs[] = {
	"Approved: ",
	"From: ",
	"To: ",
	"Date: ",
	"Message-Id: ",
	"Subject: ",
	"Received: ",
	"Sender: ",
	"Reply-To: ",
	"Status: ",
	"X-BBS-Msg-Type: ",
	"X-Forwarded-To: ",
	"Cc: ",
	"Return-Receipt-To: ",
	"Apparently-To: ",
	"Errors-To: ",
	"Organization: ",
	NULLCHAR
};

/* return the header type */
int
htype(s)
char *s;
{
	register char *p;
	register int i;

	p = s;
	/* check to see if there is a ':' before and white space */
	while (*p != '\0' && *p != ' ' && *p != ':')
		p++;
	if (*p != ':')
		return NOHEADER;

	for (i = 0; Hdrs[i] != NULLCHAR; i++) {
		if (strnicmp(Hdrs[i],s,strlen(Hdrs[i])) == 0)
			return i;
	}
	return UNKNOWN;
}

/* This function returns the length of a file. The proper thing would be
 * to use stat(), but it fails when using DesqView together with Turbo-C
 * code.
 */
static long
fsize(name)
char *name;
{
	long cnt;
	FILE *fp;
	if((fp = fopen(name,READ_TEXT)) == NULLFILE)
		return -1L;
	fseek(fp,0L,2);
	cnt = ftell(fp);
	fclose(fp);
	return cnt;
}

/* close the temporary mail file */
static void mfclose(struct mbx *m)
{
	if(m->mfile != NULLFILE)
		fclose(m->mfile);
	m->mfile = NULLFILE;
#ifdef SETVBUF
	free(m->stdoutbuf);
	m->stdoutbuf = NULLCHAR;
#endif
}

/* Parse a string in the "Text: <user@host>" or "Text: user@host (Text)"
 * format for the address user@host.
 */
char *
getaddress(string,cont)
char *string;
int cont;		/* true if string is a continued header line */
{
	char *cp, *ap = NULLCHAR;
	int par = 0;
	if((cp = getname(string)) != NULLCHAR) /* Look for <> style address */
	     return cp;
	cp = string;
	if(!cont)
	     if((cp = strchr(string,':')) == NULLCHAR)	/* Skip the token */
		  return NULLCHAR;
	     else
		  ++cp;
	for(; *cp != '\0'; ++cp) {
	     if(par && *cp == ')') {
		  --par;
		  continue;
	     }
	     if(*cp == '(')		/* Ignore text within parenthesis */
		  ++par;
	     if(par)
		  continue;
	     if(*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == ',') {
		  if(ap != NULLCHAR)
		       break;
		  continue;
	     }
	     if(ap == NULLCHAR)
		  ap = cp;
	}
	*cp = '\0';
	return ap;
}

/* Print prompt and read one character, telnet version */
static int
tkeywait(prompt,flush)
char *prompt;	/* Optional prompt */
int flush;	/* Flush queued input? */
{
	int c, i, oldimode,oldomode;

	if(flush && socklen(Curproc->input,0) != 0)
		recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0); /* flush */
	if(prompt == NULLCHAR)
		prompt = "Hit enter to continue"; 
	tprintf("%s%c%c%c",prompt,IAC,WILL,TN_ECHO);
	usflush(Curproc->output);

	/* discard the response */

	oldimode = sockmode(Curproc->input,SOCK_BINARY);
	oldomode = sockmode(Curproc->output,SOCK_BINARY);

	while((c = rrecvchar(Curproc->input)) == IAC){
		c = rrecvchar(Curproc->input);
		if(c > 250 && c < 255)
			rrecvchar(Curproc->input);
	}

	sockmode(Curproc->output,oldomode);
	sockmode(Curproc->input,oldimode);

	/* Get rid of the prompt */
	for(i=strlen(prompt);i != 0;i--)
		tputc('\b');
	for(i=strlen(prompt);i != 0;i--)
		tputc(' ');
	for(i=strlen(prompt);i != 0;i--)
		tputc('\b');
	tprintf("%c%c%c",IAC,WONT,TN_ECHO);
	usflush(Curproc->output);
	return c;
}
