/*
 *	mail
 *
 *	Amiga system mailer
 *	This is the user interface for mail.  It supports a limited command
 *	list and can display a list of messages waiting in the mailbox.
 *
 *	$Id: mail.c,v 1.2 90/01/16 10:26:32 crash Exp Locker: crash $
 */

#ifndef lint
static char RCSid[] = "$Id: mail.c,v 1.2 90/01/16 10:26:32 crash Exp Locker: crash $";
#endif /* lint */

#define	EXIT	return

#include <stdio.h>
#include "host.h"

extern char *index();
extern char *rindex();

#ifdef MSDOS
# define PC_FILENMS	1
#endif

#ifdef AMIGA
# define PC_FILENMS	1
#endif

FILE *FOPEN();
FILE *freopen();

int	debuglevel = 1;

#define OUT(x)		fprintf(stderr, x)
#define LSIZE   	256

#ifndef MAXNAMLEN
# define MAXNAMLEN	255
#endif

char	line[LSIZE];
char	resp[LSIZE];
char	mfilename[MAXNAMLEN+1];

struct ldesc {
	int   		delete;		/* status of this message */
	long		adr;		/* address of From line */
	long		date;		/* address of Date: line */
	long		subject;	/* address of Subject: line */
	long		from;		/* address of From: line */
	long		size;		/* number of lines */
};

#define MAXMSGS	300					/* Maxmimum number of letters */

struct	ldesc letters[MAXMSGS];
int   	letternum   = 0;
char   	thefilename[MAXNAMLEN+1];

char   	tmailbox[MAXNAMLEN+1];
char 	tmailbag[MAXNAMLEN+1];

FILE   	*fmailbox;
FILE 	*rmailbox;
FILE	*fmailbag;

int	error = 0;
int	modified;
int	printonly;
int	PageCount = 0;

mailmain(argc, argv)
int argc;
char **argv;
{
#if 0			/* This is done by l_host.c before calling mailmain() */
	HOSTINIT;
	loadenv();
#endif

	mkfilename( tmailbox, tempdir, "mailbox");
	mkfilename( tmailbag, tempdir, "mailbag");
	unlink( tmailbox );
	if ( mailbox == (char *)NULL )
		mailbox = "???";

	if (argc == 1 || (argv[1][0] == '-') && (argv[1][1] != 's'))
		showmail (argc, argv );
	else
		lmail (argc, argv );

	finis();
}

finis()
{
	if (fmailbag != (FILE *)NULL) fclose( fmailbag );
	if (fmailbox != (FILE *)NULL) fclose( fmailbox );
	unlink( tmailbox );
	unlink( tmailbag );
	EXIT( error );
}

/*
 *	sendmail
 *	send message n to "line"
 */

sendmail(n, line)
int n;
char *line;
{
#ifdef PC_FILENMS
	FILE	*tmpfp, *tmp2fp;
#endif
	char 	*argv[50];
	int 	argc;
	char	buf[BUFSIZ];
	long 	bytes;

	bytes = letters[ n+1 ].adr - letters[ n ].adr;

	/* open a temporary file */
	fmailbag = FOPEN( tmailbag, "w", 'b' );

	/* copy nth message to mailbag file */
	fseek( fmailbox, letters[ n ].adr, 0 );
	while( bytes > 0 && fgets( buf, sizeof(buf), fmailbox) ) {
		fputs( buf, fmailbag  );
		bytes -= strlen( buf );
	}
	fclose( fmailbag );

	/* use mailbag as stdin to mail delivery */
	FILEMODE( 'b' );
	if ( freopen( tmailbag, "r", stdin ) != (FILE *)NULL ) {
		argc = getargs( line, argv );
		lmail( argc, argv );
	}
#ifdef AMIGA
	freopen( "*", "r", stdin );
#else
	freopen( device, "r", stdin );
#endif

	/* get rid of mailbag */
	unlink( tmailbag );
}

invert( i )
{
	return( letternum-i-1 );
}

showmail(argc, argv)
int argc;
char **argv;
{
	int flg, i, j, k, print;
	char *p, *cp, *getnext();
	long nextadr;
	struct ldesc *letter;

	/* get mailbox file name */
	mkfilename( mfilename, maildir, mailbox );

	/* parse arg's */
	for (; argc > 1; argv++, argc--) {
		if ( argv[1][0] == '-' ) {
			switch (argv[1][1]) {
			case 'f' :
				if (argc > 2) {
					if (argv[2][0] == '~')
						mkfilename( mfilename, maildir, argv[2]+1 );
					else
						strcpy( mfilename, argv[2] );
					argv++;
					argc--;
				}
				break;
			case 'p' :
				printonly = TRUE;
				break;
			default :
				fprintf(stderr, "mail: unknown option %c\n", argv[1][1]);
				finis();
			}
		} else
			break;
	}
	/* open real mailbox file */
	if (( rmailbox = FOPEN( mfilename, "r", 'b' ))  == (FILE *)NULL) {
		fprintf( stdout, "No mail in %s.\n", mfilename );
		return;
	}
	/* open up tmp mailbox file */
	if (( fmailbox = FOPEN( tmailbox, "w", 'b' )) == (FILE *)NULL ) {
		fprintf( stderr, "mail: cannot open %s for writing\n", tmailbox );
		finis();
	}
	/*
	 *	Copy real mailbox file to tmp mailbox file.
	 *
	 *	During the copy, record the header information so it can
	 *	be displayed later.
	 */
	letternum = 0;
	nextadr = 0;
	while (fgets(line, LSIZE, rmailbox)) {
		fputs(line, fmailbox);
		if ( strncmp( line, "From ", 5 ) == SAME ) {
			letter          = &letters[letternum++];
			letter->from    = -1L;
			letter->subject = -1L;
			letter->date    = -1L;
			letter->adr     = nextadr;
			letter->delete  = FALSE;
			letter->size    = 0L;
		} else if ( strncmp( line, "Date: ", 6 ) == SAME )
			letter->date    = nextadr;
		else if ( strncmp( line, "From: ", 6 ) == SAME )
			letter->from    = nextadr;
		else if ( strncmp( line, "Subject: ", 9 ) == SAME )
			letter->subject = nextadr;
		letter->size++;					/* Count number of lines */
		nextadr += strlen( line );		/* Keep track of seek position */
	}
	letters[letternum].adr = nextadr;	/* last plus 1 */

	/* close mailbox files */
	fclose( rmailbox );
	fclose( fmailbox );

	fmailbox = FOPEN( tmailbox, "r", 'b' );
	modified = 0;
	if (printonly) {
		j = letternum;
		while (j > 0)
			pager(j--);
		return;
	}
	printsub(-1);			/* Print the subject list */

	i = letternum-1;
	while (TRUE) {
		register char *inp = resp;

		if (i < 0) i = 0;
		if (i >= letternum) i = letternum-1;
		j = invert(i);

		fprintf(stdout, "%d ? ", j);
		if (!fgets( inp, LSIZE, stdin)) break;
		switch (*inp) {
		default:
			fprintf(stderr, "Usage\n");
		case '?':
			print = 0;
			OUT("q\tquit\n");
			OUT("x\texit\tmailbox restored\n");
			OUT("p\tprint current message; also `RETURN'\n");
			OUT("+\tprint next message; also `n'\n");
			OUT("-\tprint last message; also `^'\n");
			OUT("h\tprint subject header list; also `H'\n");
			OUT("s[file]\tsave message to a file (default mbox)\n");
			OUT("w[file]\t(same as `s' but without headers\n");
			OUT("\t`file' may be absolute path or use ~ for $MAILDIR\n");
			OUT("d\tdelete current message\n");
			OUT("f user\tforward current message to `user'\n");
			OUT("m user\tmail a message to `user'\n");
			OUT("g num\tset current message; also `num'\n");
			break;
		case '+':
		case 'n':
			i-- ;
			break;
		case 'g':
			i = invert(atoi(inp+1));
			break;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			i = invert(atoi(inp));
			break;

		case 'x':
			modified = 0;
		case 'q':
			goto donep;
		case '\n':
		case 'p':
			pager( j );
			break;
		case '^':
		case '-':
			i++;
			break;
		case 'y':
		case 'w':
		case 's':
			flg = 0;
			k = *inp;
#ifdef FJE
			inp++;
			while (isspace(*inp))
				inp++;
#else
			if (inp[1] != '\n' && inp[1] != ' ') {
				printf("illegal\n");
				flg++;
				print = 0;
				continue;
			}
#endif /* !FJE */
			if (strlen(inp) < 2)
				strcat(inp, "~mbox");
			for (p = inp; p = getnext(&cp, p); ) {
				if (*cp == '~')
					mkfilename(thefilename, maildir, ++cp);
				else
					strcpy(thefilename, cp);
				fprintf(stderr, "%s to %s\n",
				    (k == 's') ? "Saving" : "Writing", thefilename);
				if ( !(fmailbag = FOPEN(thefilename, "a", 't')) ) {
					fprintf(stderr, "mail: cannot open %s\n", thefilename);
					flg++;
					continue;
				}
				copymsg(j, fmailbag, k == 'w');
				fclose( fmailbag );
			}
			if (flg)
				print = 0;
			else {
				letters[j].delete = TRUE;
				modified++;
				i--;
			}
			break;
		case 'm':
			OUT("mail command not implemented yet!\n");
			break;
		case 'f':
			flg = 0;
			while (isspace(*inp))
				inp++;
			if (!*inp) {
				printf("No user id to forward to!?\n");
				i++;
				continue;
			}
			sendmail(j, p);
			if (flg)
				print = 0;
			else {
				letters[j].delete = TRUE;
				modified++;
				i++;
			}
			break;

		case 'd':
			letters[j].delete = TRUE;
			modified++;
			i--;
			if (inp[1] == 'q')
				goto donep;
			break;

		case 'h':
			printsub( -1 );
			break;

		case 'H':
			printsub( i );
			break;
		}
	}
donep:
	if (modified) copyback();
}

readaline(adr, line)
long adr;
char *line;
{
	char 	buf[132];
	register char	*cp = buf;

	*line = '\0';
	if (adr != -1L && !fseek(fmailbox, adr, 0) && fgets(cp, 132, fmailbox))
		strcpy(line, cp);
	if (cp = index(line, '\n'))
		*cp = '\0';
}

#if 0
returnaddress()
{
	readaline( lp->from, line );
	if (i = index(line, '<') && k = index(line, '>') && k > i) {
		strncpy(from, line[i], k-i);
		from[k] = '\0';
	}
}
#endif

printsub( K )
int K;
{
	static char from[132], subject[132], date[132], line[132];
	register char	*sp, *dp, *lp, *tp;

	struct ldesc *ld;
	int k, mink, maxk, j;

	pagereset();
	if ( K == -1 ) {
		maxk = letternum-1;
		mink = 0;
	} else
		maxk = mink = K;

	sprintf(line, "%3s %6s %-20s %-35s Lines\n",
				"# ", "Date ", "From", "Subject");
	pageline( line );
	for (k = maxk; k >= mink; k--) {
		j = invert(k);
		ld = letters+j;

		(void) strcpy(from, "unknown");		/* default to "unknown" */
		readaline(ld->from, line);
		if (strlen(line)) {
			/*
			 *	get first usable stuff after From:
			 */
			sp = index(line, ':')+1;
			/*
			 *	Is it "From: mailbox@site.domain (Proper Name)"?
			 */
			if ( (tp = index(line, '(')) && (lp = index(tp, ')')) )
				sp = ++tp;
			else
				/*
				 *	or "From: Proper Name <mailbox@site.domain>"
				 */
				lp = index( line, '<');

			if ( *lp == '<' || *lp == ')' )
				--lp;

			/* if we didn't get either of the last two, just grab line */
			if (lp < sp || !lp)
				lp = line+strlen(line)-1;

			while (isspace(*sp)) sp++;
			while (isspace(*lp)) lp--;
			dp = from;
			while (sp <= lp) *dp++ = *sp++;
			*dp = '\0';
		}
		/*
		 *	Date formats:
		 *		Date: Wed May 13 23:59:53 1987
		 */
		*date = '\0';
		readaline(ld->date, date);
		if (strlen(date)) {
			sscanf(date, "%*s %*s %s %s", line, subject);
			sprintf(date, "%s %s", line, subject);
		}
		strcpy(subject, "--- no subject ---");
		readaline(ld->subject, line);
		if (strlen(line)) {
			sp = line;
			while (!isspace(*sp)) sp++;
			while ( isspace(*sp)) sp++;
			strcpy(subject, sp);
		}
		sprintf(line, "%3.3d %6.6s %-20.20s %-35.35s (%ld)\n",
					    j,   date,   from,  subject, ld->size);
		if (pageline(line))
			break;
	}
}

copyback()
{
	register i, n, c;
	int new = 0;

	if ( !(fmailbag = FOPEN(mfilename, "w", 'b')) ) {
		fprintf(stderr, "mail: can't rewrite %s\n", mfilename);
		finis();
	}
	n = 0;
	for (i = 0; i < letternum; i++)
		if (letters[i].delete == FALSE) {
			copymsg(i, fmailbag, FALSE);
			n++;
		}
	fclose(fmailbag);
}

/*
 *	copy a message
 *	if noheaders is TRUE, don't copy header lines
 */

copymsg(n, f, noheaders)
int n;
FILE *f;
int noheaders;
{
	long 	bytes;
	char	buf[BUFSIZ];

	fseek(fmailbox, letters[n].adr, 0);
	bytes = letters[n+1].adr - letters[n].adr;

	while (bytes > 0 && fgets(buf, sizeof(buf), fmailbox)) {
		bytes -= strlen(buf);
		if (!noheaders) fputs(buf, f);
		if (noheaders && buf[0] == '\n' && !buf[1]) noheaders = FALSE;
	}
}

pager(n)
int n;
{
	long bytes;
	char buf[BUFSIZ];

	fseek(fmailbox, letters[n].adr, 0);
	bytes = letters[n+1].adr - letters[n].adr;

	pagereset();
	while (bytes > 0 && fgets(buf, sizeof(buf), fmailbox)) {
		bytes -= strlen(buf);
		if (pageline(buf))
			break;
	}
	pageline("\n");
}

pagereset()
{
	PageCount = 0;
}

pageline(s)
char *s;
{
	int c;

	fputs(s, stdout);
	if (++PageCount > 18) {
		PageCount = 0;
		fputs("\033[7m`q' to quit, SPACE to continue:\033[0m", stdout);
		c = get_one();
		fputs("\r\033[K", stdout);
		switch (c) {
			case 'q':
			case 'Q':
			case 'x':
			case 'X':
			case '\003':	/* ^C */
			case '\033':	/* ESC */
				return( TRUE );
		}
	}
	return( FALSE );
}

char *getnext(s, p)
register char **s, *p;
{
	*s = NULL;
	while (*p == ' ' || *p == '\t')
		p++;
	if (*p == '\n' || !*p)
		return( NULL );
	*s = p;
	while (isspace(*p))
		*p++;
	if (*p)
		*p++ = '\0';
	return(p);
}
