/*
 *	$Id: pcmail.c,v 1.4 90/01/16 10:26:55 crash Exp Locker: crash $
 *
 *	Copying and use of this program are controlled by the terms of the
 *	Free Software Foundations GNU Emacs General Public License.
 *
 *	Copyright (C) 1987 Stuart Lynne
 *	Version		0.1		March 31/1987
 *
 *	pcmail address1 address2 ... < the.message
 *
 *	DESCRIPTION
 *
 *	An 822 compatible (hopefully) mail delivery system for pc's.
 *
 *	Designed for delivering mail on a pc based system. It will put
 *	local mail (ie, not @ or ! in address) into files in the default
 *	mail directory.
 *
 *	If remote it will put into an outgoing mailbag in the default mail
 *	directory. Performs a simple bundling of mail messages into one
 *	file with arguments prepended as To: arg header lines. And adds a
 *	Message-Lines: header which gives the number of lines in the
 *	content part of the message (after the first blank line).
 *
 *		pcmail john jack jill@xyz.uucp < afile
 *
 *		To: john
 *		To: jack
 *		To: jill@xyz.uucp
 *		X-Message-Lines: ?????
 *		Content-Length: ?????
 *
 *		...
 *		...
 *		...
 *
 *	Content-Length: is used without X- prepended to be compatible with AT&T
 *	Mail bundles. This is not 822 compatible per se, but is allowed.
 *
 *	It also adds the From and Date lines.  Subject: lines may be inserted
 *	by placing them at the beginning of the message.
 *
 *	A Unix version should lock the /usr/mail/mailbag file.
 *
 *	Another program called rpcmail will unbundle the files created by
 *	pcmail and deliver each message to the local rmail. So conceptually
 *
 *		(pcmail ..... < ...; pcmail .... < ...) | sz -> rz | rpcmail
 *
 *	would deliver remote messages intact.
 *
 *	ENVIRONMENT VARIABLES
 *
 *	The following environment variables are used:
 *		MAILBOX		current user's mailbox, 	"crash"
 *		NAME		current user's name, 		"Frank Edwards"
 *		DOMAIN		domain of this machine, 	"ckctpa.UUCP"
 *		MAILDIR		where is mail kept,			":usr/crash"
 *
 *	COMPILING
 *
 *	Compiled by itself it will operate as a standalone program. If the
 *	compiler option:
 *
 *		-DNOMAIN
 *
 *	is used, it will compile as a routine:
 *
 *		pcmail (argc, argv)
 *		char **argv;
 *		int argc;
 *
 *	and can be used internally in other programs.
 *
 *	CUSTOMIZATION
 *		PCMAIL		mailbag for remote mail
 *		RMAIL		rmail
 */

#define ORGANIZATION	"ComputerKnowledge Corp, Clearwater FL"

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

/*
# ifdef NOMAIN
#  include "dcp.h"
# else
*/
#  include <stdio.h>
#  include "host.h"
/*
# endif
*/

#ifdef MSDOS
#  define PC_FILENMS	1
#else
#  ifdef AMIGA
#    define PC_FILENMS	1
#    ifdef MCH_AMIGA
#      include <functions.h>
#    else
#      include <proto/exec.h>
#    endif
#  endif
#endif

FILE *FOPEN();

#define FORWARD		"Forward to"
#define	SBUFSIZ		124

FILE *mailfile;
FILE *tempfile;

char buf[BUFSIZ];
char miscbuff[100];
long lines = 0;
long bytes = 0;
long sequence = 0;

long tloc;
char chartime[26];			/* current time in ASCII */
char *thetime;

char tfilename[100];
char mfilename[100];
char mailsent[100];

int flag_rnews = FALSE;		/* Flag for news posting instead of email */
int local = TRUE;
char remotes[BUFSIZ];
char uucp[] = "uucp";

extern char *getcwd();
extern int chdir();

extern void *malloc();
extern char *index();
extern char *rindex();
extern char *fgets();
extern int fputs();

#ifdef NOMAIN
#  ifdef RMAIL
#    define main	rmail
#  else
#    define main	lmail
#  endif
#  define exit	return
	extern int debuglevel;
#else
	int debuglevel;
#endif

#ifndef RMAIL
char	Subject[132] = "";
#endif

char *progname;			/* Holder for argv[0] for error messages */
char *mcurdir;
char s_mcurdir[BUFSIZ];	/* current directory path (save malloc call) */

main(argc, argv)
char *argv[];
{
	long position;
	register int header = 1;
	register int amount;

	register int argcount;
	register char **argvec;
	int remote;
	int s1, s2;

	progname = argv[0];

#ifndef NOMAIN
	/* get environment var's */
	HOSTINIT;
	loadenv();

 	if (argc <= 1) {
		fprintf( stderr, "Usage:  %s [-s subj] users\n", progname );
		exit(1);
	}
	debuglevel = 1;
#endif

#ifdef RMAIL
	local = FALSE;
#else
	local = TRUE;
#endif

	if ( debuglevel > 5 ) {
		fprintf( stderr, "%s: argc %d ", progname, argc );
		argcount = argc;
		argvec = argv;
		while (argcount--)
			fprintf( stderr, " \"%s\"", *argvec++ );
		fputc( '\n', stderr );

		tloc = time( (long *)NULL );
		thetime = ctime(&tloc);
		fprintf( stderr, "thetime: %s\n",thetime );
	}

#ifdef PC_FILENMS
 	getcwd( s_mcurdir, sizeof(s_mcurdir) );
#else
	getcwd( s_mcurdir, 0 );
#endif
	chdir( spooldir );

	/* get sequence number */
	mkfilename( tfilename, confdir, SFILENAME );

 	if ( debuglevel > 4 )
 	   fprintf( stderr, "%s: opening %s\n", progname, tfilename ); /* */

	tempfile = FOPEN( tfilename, "r", 't' );
	if (tempfile != (FILE *)NULL) {
		fscanf( tempfile, "%ld", &sequence );
		fclose( tempfile );
	} else {
 		fprintf( stderr,
			"%s: can't find %s file, creating\n", progname, tfilename );
 		sequence = 1;	/* start at 1 */
 	}
	/* update sequence number */
	if ( debuglevel > 5 )
		fprintf( stderr, "%s: new sequence # %ld\n", progname, sequence );

	tempfile = FOPEN( tfilename, "w", 't' );
	if (tempfile != (FILE *)NULL) {
		fprintf( tempfile, "%ld\n", sequence+1 );
		fclose( tempfile );
	}
	s1 = sequence;
	/* open a temporary file */
	/* sprintf( tfilename, TFILENAME, sequence ); */

try_tmpfile_again:
 	sprintf( miscbuff, TFILENAME, sequence );
 	mkfilename( tfilename, tempdir, miscbuff );

 	if ( debuglevel > 5 )
 		fprintf( stderr, "%s: opening %s\n", progname, tfilename );

	tempfile = FOPEN( tfilename, "w", 'b' );
 	if (tempfile == (FILE *)NULL)  {		/* got an error here somehow */
		fprintf( stderr, "%s: can't open %s\n", progname, tfilename );
#ifdef FJE
		if (++sequence < s1 + 100)			/* Try more than once... */
			goto try_tmpfile_again;
		else
#endif /* FJE */
			exit(1);
	}
	/* copy stdin to tempfile, counting content lines and bytes */
#ifndef RMAIL
	if ( strcmp( argv[1], "-s" ) == SAME ) {
		argv += 2;
		argc -= 2;
		if ( argc == 0 )
			return( -1 );
		strcpy( Subject, *argv );
	}
#  ifdef FJE		/* Interactive Subject: line prompt */
	else if (isatty( fileno(stdin) )) {
		fputs("Subject: ", stderr);
		fflush(stderr);
		gets( Subject );
	}
	if (argc==2 && !strnicmp(argv[1], "rnews", 6))	/* same as stricmp() */
		flag_rnews = TRUE;		/* Posting an article instead of email */
#  endif /* FJE */
#endif /* !RMAIL */

	header = 1;
	while (fgets( buf, sizeof(buf), stdin ) != (char *)NULL) {
		if (header) {
			char *tmp = buf;
			while (isspace(*tmp)) tmp++;
			if (strlen( tmp ) < 2) {
				header = 0;
				continue;
			} else if (strchr( tmp, ':' ) == NULL) {
				header = 0;
			} else
				header = storehdr( tmp );
		}
		if (!header) {
			lines++;
			bytes += strlen( buf );
			fputs( buf, tempfile );
		}
	}
	/* get signature */
#ifndef RMAIL
#ifdef FJE			/* Different .signature if posting an article */
	mkfilename( mfilename, home, flag_rnews ? POSTFILE : SIGFILE );
#else
	mkfilename( mfilename, home, SIGFILE );
#endif /* !FJE */

	if (debuglevel > 4)
 	   fprintf( stderr, "%s: opening sigfile %s\n", progname, mfilename );
	mailfile = FOPEN( mfilename, "r", 't' );
	if (mailfile != (FILE *)NULL) {
		fputs( "\n-----\n", tempfile );
		bytes += 7;
		while (fgets( buf, sizeof(buf), mailfile ) != (char *)NULL) {
			lines++;
			bytes += strlen( buf );
			fputs( buf, tempfile );
		}
		fclose( mailfile );
 	}
#endif /* !RMAIL */

 	fclose( tempfile );
	if ( debuglevel > 4 ) {
		fprintf( stderr, "%s: stdin copied to tmp: %ld bytes %ld lines\n",
	                 progname, bytes, lines );
 		fprintf( stderr, "%s: args %d\n", progname, argc );
	}
	/*
	 *	loop on args, copying to appropriate postbox,
	 *	do remote only once
	 *	remote checking is done empirically, could be better
	 */
	remotes[0] = '\0';
	argcount = argc;
	argvec = argv;

	while (--argcount > 0) {
		argvec++;
		if ( debuglevel > 5 )
			fprintf( stderr,
				"%s: arg# %d %s\n", progname, argcount, *argvec );
		if (index( *argvec, '!' ) || index( *argvec, '@' ) ||
									 index( *argvec, '%' )) {
			if ( debuglevel > 5 )
				fprintf( stderr, "%s: send to remote\n", progname );

			s1 = strlen( remotes );
			s2 = strlen( *argvec );

			/* can we cram one more address on line */
			if ( s1 > 0 && (s1 + s2 + 1) > 128 ) {
				/* dump it then, too bad */
				sendone( argc, argv, remotes, TRUE );
				remotes[0] = '\0';
			}
			/* add *arvgvec to list of remotes */
			strcat( remotes, " " );
			strcat( remotes, *argvec );
		} else {
			if ( debuglevel > 5 )
				fprintf( stderr,
					"%s: calling sendone %s\n", progname, *argvec );
			sendone( argc, argv, *argvec, flag_rnews );
		}
	}
	/* dump remotes if necessary */
	if ( strlen( remotes ) > 0 )
		sendone( argc, argv, remotes, TRUE );

#ifndef RMAIL
#ifdef FJE
	if (!flag_rnews)		/* Only record if email, not a posting */
#endif /* FJE */
	{
		mkfilename( mailsent, home, COPYFILE );
		if ( debuglevel > 4 )
		   fprintf( stderr, "%s: copfile = %s\n", progname, mailsent );
		sendone( argc, argv, mailsent, FALSE );
	}
#endif /* !RMAIL */
	unlink( tfilename );
	chdir( s_mcurdir );
	exit(0);
}

static struct _header {
	char *hdr;				/* Header text */
	char *text;				/* Text found in letter for this header */
} headers[] = {
	{ "Path:",			NULL },
	{ "Newsgroups:",	NULL },
	{ "Followup-To:",	NULL },
	{ "Organization:",	NULL },
	{ "Summary:",		NULL },
	{ "Received:",		NULL },
	{ "From:",			NULL },
	{ "Date:",			NULL },
	{ "Subject:",		NULL },
	{ "Message-ID:",	NULL },
	{ NULL,				NULL }  };

#define H_PATH		0
#define H_GRPS		1
#define H_FOLL		2
#define H_ORG		3
#define H_SUMM		4
#define H_FROM		5
#define H_RECV		6
#define H_DATE		7
#define H_SUBJ		8
#define H_MSG		9

static struct _header *findhdr(str)
register char *str;
{
	register struct _header *hdr = headers;

	while (hdr->hdr && strcmp(hdr->hdr, str))
		hdr++;
	return( hdr->hdr ? hdr : (struct _header *) 0);
}

static int storehdr(str)
register char *str;
{
	char ch;
	register char *tmp = index(str, ':');
	register struct _header *hdr;

	ch = *++tmp;
	*tmp++ = '\0';
	if (hdr = findhdr(str)) {
		while (isspace(*tmp)) tmp++;
		if (hdr->text = (char *) malloc(strlen(tmp) + 1)) {
			strcpy(*hdr, str);
			return( TRUE );
		}
	}
	tmp[-1] = ch;		/* Either header not found or malloc() failed */
	return( FALSE );
}

static char *saveprintf(fmt, args)
char *fmt;
int args;
{
	register char *mem;

	if (mem = (char *) malloc(512))
		vsprintf(mem, fmt, &args);
	return( mem );
}

char fpat1[] = "%c.%.7s%04ld";
char fpat2[] = "S %s %s %s - %s 0666 %s";

/*
 *	sendone copies file plus headers to appropriate postbox
 *
 *	NB. we do headers here to allow flexibility later, for example
 *	in being able to do bcc, per host service processing etc.
 */

sendone( argc, argv, address, remote )
char **argv;
int argc;
char *address;
{
	register char 	*cp;
	char	icfilename[32];		/* local C. copy file */
	char	ixfilename[32];		/* local X. xqt file */
	char	idfilename[32];		/* local D. data file */
	char	rxfilename[32];		/* remote X. xqt file */
	char	rdfilename[32];		/* remote D. data file */
 	char	tmfilename[32];		/* temporary storage */
#ifdef PC_FILENMS
 	char	cixfilename[32];	/* canonical ixfilename */
 	char	cidfilename[32];	/* canonical idfilename */
#endif
#ifdef FJE			/* Print the headers from headers[] */
	register struct _header *start;
#endif /* FJE */

 	if ( remote ) {
 		/* sprintf all required file names */
		sprintf( tmfilename, fpat1, 'C', mailserv, sequence );
		importpath( icfilename, tmfilename );
#ifdef PC_FILENMS
 		sprintf( cidfilename, fpat1, 'D', mailserv, sequence );
		importpath( idfilename, cidfilename );
		sprintf( cixfilename, fpat1, 'D', nodename, sequence );
 		importpath( ixfilename, cixfilename );
#else
		sprintf( tmfilename, fpat1, 'D', mailserv, sequence );
		importpath( idfilename, tmfilename );
		sprintf( tmfilename, fpat1, 'D', nodename, sequence );
		importpath( ixfilename, tmfilename );
#endif
		sprintf( rdfilename, fpat1, 'D', nodename, sequence );
		sprintf( rxfilename, fpat1, 'X', nodename, sequence );
 	} else {
		/* postbox file name */
 		if ( index( address, SEPCHAR ) == (char *)NULL )
			mkfilename( idfilename, maildir, address );
		else
			strcpy( idfilename, address );	/* Can't get here, can it!? */
	}
	if ( debuglevel > 5 )
 		fprintf( stderr, "%s: sendone: %s\n", progname, idfilename );

 	if (!remote) {
 	   if ( debuglevel > 5 )
 	      fprintf( stderr, "%s: sendone: check for remote\n", progname );

		/* check for forwarding */
		if ( (mailfile = FOPEN( idfilename, "r", 'b' )) != (FILE *)NULL ) {
			cp = fgets( buf, BUFSIZ, mailfile );
			fclose( mailfile );
			if (cp && !strncmp( buf, FORWARD, 10 )) {
				strcpy( buf, buf+11 );
				return( sendone( argc, argv, buf, FALSE ) );
			}
		}
	}
	/* open mailfile */
	if ( (mailfile = FOPEN( idfilename, "a+", 'b' )) == (FILE *)NULL ) {
		fprintf( stdout, "%s: cannot append to %s\n", progname, idfilename );
		return( 0 );
	}
	if ( debuglevel > 5 )
		fprintf( stderr, "%s: append to mailfile\n", progname );

	tloc = time( (long *)NULL );
 	(void) strcpy(thetime = chartime, ctime(&tloc));	/* our own copy */
	thetime[strlen(thetime)-1] = '\0';					/* remove '\n' */

#ifdef RMAIL
	fprintf( mailfile, "From uucp %s", thetime );
	fputc( '\012', mailfile );
	fprintf(mailfile, "Received: by %s (%s) %s", domain, progname, thetime);
	fputc( '\012', mailfile );
#else /* !RMAIL */
# ifdef FJE
	if (flag_rnews) {
		start = &headers[H_PATH];
		if (!headers[H_PATH].text)
			headers[H_PATH].text = nodename;
		if (!headers[H_ORG].text)
			headers[H_ORG].text = ORGANIZATION;
		headers[H_RECV].text = NULL;
	} else {
		start = &headers[H_RECV];
		headers[H_PATH].text = NULL;
		headers[H_ORG].text = NULL;
		if (!headers[H_RECV].text)
			headers[H_RECV].text = saveprintf("Received: by %s (%s) %s\012",
				domain, progname, thetime);
		fprintf( mailfile, "From %s %s", mailbox, thetime );
		if (remote) fprintf( mailfile, " remote from %s", nodename );
		fputc( '\012', mailfile );
	}
	if (!headers[H_FROM].text)
#ifdef KLUDGE_FROM_LINE
	/*
	 *	From: Frank J. Edwards <ckctpa!crash@boake2>\012",
	 *					name, nodename, mailbox, mailserv
	 */
		headers[H_FROM].text = saveprintf("%s <%s!%s@%s>\012",
			name, nodename, mailbox, mailserv);
#else /* !KLUDGE_FROM_LINE */
	/*
	 *	From: %s <%s@%s>\012", name, mailbox, domain
	 */
		headers[H_FROM].text = saveprintf("%s <%s@%s>\012",
			name, mailbox, domain);
#endif /* KLUDGE_FROM_LINE */
	if (!headers[H_DATE].text)
		headers[H_DATE].text = saveprintf("%s\012", thetime);
	if (!headers[H_MSG].text)
		headers[H_MSG].text = saveprintf("<%ld@%s>\012", sequence, domain );
	if (!headers[H_SUBJ].text)
		headers[H_SUBJ].text = Subject;
	for ( ; start->hdr; start++)
		if (start->text)
			fprintf(mailfile, "%s %s\012", start->hdr, start->text);

	if (!flag_rnews) {
		/* add To: headers */
		while (--argc > 0)
			fprintf( mailfile, "To: %s\012", *++argv );
	}
# else /* FJE */
	fprintf( mailfile, "From %s %s", mailbox, thetime );
	if ( remote )
		fprintf( mailfile, " remote from %s", nodename );
	fputc( '\012', mailfile );
	fprintf( mailfile, "Received: by %s (%s) %s\012",
		domain, progname, thetime);
	fprintf( mailfile, "Date: %s\012", thetime );

	/*	"From: %s <%s@%s>\012", name, mailbox, domain	*/
	fprintf( mailfile, "From: %s <%s@%s>\012", name, mailbox, domain );
	fprintf( mailfile, "Message-ID: <%ld@%s>\012", sequence, domain );

	/* add To: headers */
	while (--argc > 0)
		fprintf( mailfile, "To: %s\012", *++argv );
	if ( strlen( Subject ) > 0 ) {
		fprintf( mailfile, "Subject: %s", Subject );
		fputc( '\012', mailfile );
	}
# endif /* !FJE */
# ifdef PCMAIL
	/* add Message-Lines: and Content-Length: headers */
	fprintf( mailfile, "X-Message-Lines: %ld", lines );
	fputc( '\012', mailfile );
	fprintf( mailfile, "Content-Length: %ld", bytes );
	fputc( '\012', mailfile );
# endif /* PCMAIL */
	fputc( '\012', mailfile );		/* Blank line between hdrs & message */
#endif /* !RMAIL */

	/* copy tempfile to postbox file */
	if (debuglevel > 4)
		fprintf( stderr, "%s: copy tempfile %s to %s\n",
			progname, tfilename, idfilename );
	tempfile = FOPEN( tfilename, "r", 'b' );
	if ( tempfile == (FILE *)NULL) {
		fprintf( stdout, "%s: can't re-open %s\n", progname, tfilename );
		return( 0 );
	}
	while (fgets( buf, 512, tempfile ) != (char *)NULL) {
		if ( strncmp( buf, "From ", 5 ) == 0 )
			fputc( '>', mailfile );
		if (cp = index(buf, '\n'))
			*cp = '\0';
		fputs( buf, mailfile );
		fputc( '\012', mailfile );
 	}
	/* close files */
	fclose( mailfile );
	fclose( tempfile );

	/* all done unless going to remote via uucp */
	/* must create the job control files */

	if ( remote ) {
		/* create remote X xqt file */
		mailfile = FOPEN( ixfilename, "w", 'b' );
		if 	(mailfile == (FILE *)NULL) {
			fprintf( stdout,
				"%s: cannot append to %s\n", progname, ixfilename );
			return( 0 );
		}
		fprintf( mailfile, "U %s %s\012", uucp, nodename );
		fprintf( mailfile, "F %s\012", rdfilename );
		fprintf( mailfile, "I %s\012", rdfilename );
		cp = address;
#ifdef FJE
		while (*cp && isspace(*cp))
			cp++;
# if 0
		if ( !strncmp(cp, mailserv, first = strlen(mailserv)) ) {
			if ( cp[ first ] == '!' )
				cp += first + 1;
		}
# endif
#endif /* FJE */
		fprintf(mailfile, flag_rnews ? "C rnews\012" : "C rmail %s\012",cp);
		fclose( mailfile );

		/* create local C copy file */
		mailfile = FOPEN( icfilename, "w", 't' );
		if 	(mailfile == (FILE *)NULL) {
			printf("%s: cannot append to %s\n", progname, icfilename );
			return( 0 );
		}
#ifdef PC_FILENMS
 		fprintf( mailfile, fpat2, cidfilename, rdfilename,
 					uucp, cidfilename, uucp );
 		fputc( '\012', mailfile );
 		fprintf( mailfile, fpat2, cixfilename, rxfilename,
 					uucp, cixfilename, uucp );
 		fputc( '\012', mailfile );
#else
		fprintf( mailfile, fpat2, idfilename, rdfilename,
					uucp, idfilename, uucp );
		fputc( '\012', mailfile );
		fprintf( mailfile, fpat2, ixfilename, rxfilename,
					uucp, ixfilename, uucp );
		fputc( '\012', mailfile );
#endif /* !PC_FILENMS */
		fclose( mailfile );
	}
	return( 1 );
}

#ifndef AMIGA
# ifdef RMAIL
rnews(argc, argv)
int argc;
char *argv[];
{
	struct tm	*thetm;
	char	filename[132];
	char	format[128];
	FILE 	*f;
	char	buf[BUFSIZ];

	static int count = 0;

	tloc    = time( (long *)NULL );
	thetime = ctime(&tloc);
	thetm   = localtime( &tloc );

	/* mkfilename( format, spooldir, NEWSDIR );	*/
	sprintf( filename, NEWSDIR,
		thetm->tm_year % 100, thetm->tm_mon,
		thetm->tm_mday, thetm->tm_hour,
		thetm->tm_min,  thetm->tm_sec,  count
		);

	count++;
	if ( debuglevel > 5 )
		fprintf( stderr, "rnews: %s\n", filename );

	if ( (f = FOPEN( filename, "w", 't' )) == (FILE *)NULL ) {
		fprintf( stderr, "rnews: can't open %s %d\n", filename, errno );
		return( -1 );
	}
	while ( fgets( buf, BUFSIZ, stdin ) != (char *)NULL )
		fputs( buf, f );
	fclose( f );
}
# endif /* RMAIL */
#endif /* !AMIGA */
/* !AMIGA */
