[net.sources] Dmail under sys3

allbery@ncoast.UUCP (Brandon S. Allbery) (12/26/85)

I have gotten dmail working under System III, by means of much hacking and an
interface to /bin/mail (or /etc/delivermail, for that matter) which reads the
To:, Cc:, and Bcc: lines from a message coming in on stdin (if invoked with
-t; otherwise it execs /bin/mail), discards Bcc:'s, and adds sendmail-style
Date: and From: lines.  If anyone's interested, I'll diff the sources so that I
can #ifdef the changes for BSD42_3, ATT3_5, and RE_V7 and post them, along with
my mail interface.

One flame: if the author of dmail had been working under sys3 he wouldn't
have misused pointers: my first use of setlist caused dmail to dump core when
it did a free(0).  Would it have been much harder to check the list of setlist
header lines for nullity before freeing it?  End flame.

--Brandon
-- 
This is a recording.  Please leave a message at the tone...	<beep>

..decvax!cwruecmp!ncoast!tdi2!brandon (cwruecmp is Case.CSNET, O ye Arpanauts)
(..ncoast!tdi2!root for business)	      6615 Center St., Mentor, OH 44060
Phone: +01 216 974 9210      CIS 74106,1032       MCI MAIL BALLBERY (part-time)
I am affiliated with ncoast only to read news.  And even that may change.

hansen@pegasus.UUCP (Tony L. Hansen) (01/03/86)

< From: allbery@ncoast.UUCP (Brandon S. Allbery)
< I have gotten dmail working under System III, by means of much hacking and
< an interface to /bin/mail (or /etc/delivermail, for that matter) which reads
< the To:, Cc:, and Bcc: lines from a message coming in on stdin (if invoked
< with -t; otherwise it execs /bin/mail), discards Bcc:'s, and adds
< sendmail-style Date: and From: lines.  If anyone's interested, I'll diff the
< sources so that I can #ifdef the changes for BSD42_3, ATT3_5, and RE_V7 and
< post them, along with my mail interface.

This interface program sounds an awful lot like the recmail.c program that
comes along with the netnews programs. Wasn't that usable?

I did some hacking on the recmail.c source to make it handle Bcc: lines
properly where it didn't before. This includes ensuring that a Bcc: line is
visible, without showing other Bcc: recipients, for the Bcc: recipient to
tell them why they had gotten the message.

This version is also being passed onto Rick Adams for inclusion in 2.10.3.

					Tony Hansen
					ihnp4!pegasus!hansen

#!/bin/sh
# This is a shar archive.
# The rest of this file is a shell script which will extract:
# recmail.c
# Archive created: Fri Jan 3 15:18:39 EST 1986
echo x - recmail.c
sed 's/^X//' > recmail.c << '~FUNKY STUFF~'
/*
 * recmail: read a mail message on stdin, grab all addresses in To and Cc
 * lines, and pass the full message to all addressees.  This is useful to
 * send the output of a recently edited mail message (with headers edited too).
 * It is similar to sendmail -t, but only assumes /bin/mail.
 * To use your own mailer, e. g. nmail, compile with -DMAILER=my_mailer.
 */

#ifdef SCCSID
static char	*SccsId = "@(#)recmail.c	1.11++	12/85";
#endif /* SCCSID */

#include "params.h"

#ifndef MAILER
#define MAILER "/bin/mail"
#endif
char mailer[] = MAILER;

#define MAXRECIPS 100
char *recips[MAXRECIPS];
char *tmpf, *errf, *bccf, *progname;
int nrecips = 0;

main(argc, argv)
char **argv;
int argc;
{
	FILE *fd, *errfd;
	char linebuf[BUFSIZ];
	int i, pid, wpid;
	int exstat;
	char *mypath;
	int goodcnt, badcnt;
	char *mktemp(), *getenv();

	progname = argv[0];
	tmpf = mktemp("/tmp/rmXXXXXX");
	(void) close(creat(tmpf,0666));
	fd = fopen(tmpf, "w");
	errf = mktemp("/tmp/rmXXXXXX");
	(void) close(creat(errf,0666));
	errfd = fopen(errf, "w");
	bccf = mktemp("/tmp/rmXXXXXX");
	(void) close(creat(errf,0666));
	fputs("Subject: Returned mail\n", errfd);
	fputs("\n  ----- Transcript of session follows -----\n", errfd);
	(void) fflush(errfd);
	goodcnt = badcnt = 0;

	while (fgets(linebuf, sizeof linebuf, stdin) != NULL) {
		if (Equal(linebuf, "BCC: ", 5))
			addrecips(linebuf+5, 1);
		else {
			if (fputs(linebuf, fd) == EOF)
				werror();
			if (linebuf[0] == '\n')
				break;
			if (Equal(linebuf, "TO: ", 4) ||
			    Equal(linebuf, "CC: ", 4))
				addrecips(linebuf+4, 0);
		}
	}
	if (!feof(stdin)) {
		while (fgets(linebuf, sizeof linebuf, stdin) != NULL) {
			if (fputs(linebuf, fd) == EOF)
				werror();
		}
	}
	/*
	 * Append the contents of the .signature file (if it exists) to
	 * the end of the mail message
	 */
	{
		char sigbuf[BUFSIZ];
		register c;
		register char *p = getenv("HOME");
		FILE *infp;
			
		if (p) {
			(void) sprintf(sigbuf, "%s/%s", p, ".signature");
			if (infp = fopen(sigbuf, "r")) {
				fputs("---\n", fd);
				while ((c = getc(infp)) != EOF)
					putc(c,fd);
				(void) fclose(infp);
			}
		}
	}
	(void) fclose(fd);

	/*
	 * Force the path to only consider /bin and /usr/bin, since
	 * that's the version of mail we want (not /usr/ucb/mail)
	 */
	{
		extern char **environ;
		register char **p = environ;
		for (;*p;p++)
			if (strncmp(*p, "PATH=", 5) == 0) {
				*p = "PATH=/bin:/usr/bin";
				break;
			}
	}

	/*
	 * We send the copies out separately, because of a bug in
	 * some versions of /bin/mail which will generate ANOTHER To: line,
	 * even though we already have one, if there are at least
	 * two recipients.
	 */
	for (i=0; i<nrecips; i++) {
		/*
		 * mail recips[i] < tmpf
		 */
		pid = mailto(tmpf, bccf, errfd, recips[i]);
		exstat = -1;
		while ((wpid = wait(&exstat)) >= 0 && wpid != pid)
			;
		if (exstat == 0)
			goodcnt++;
		else
			badcnt++;
	}
	if (badcnt) {
		mailback(errfd, tmpf, errf);
		quit(1);
	} else if (goodcnt == 0) {
		fputs("recmail: no 'To:' line\n", errfd);
		mailback(errfd, tmpf, errf);
		quit (1);
	} else
		quit(0);
}

quit(exitstatus)
int exitstatus;
{
	(void) unlink(tmpf);
	(void) unlink(errf);
	(void) unlink(bccf);
	exit (exitstatus);
	/* NOTREACHED */
}

/* in case of write error */
werror()
{
	fprintf(stderr, "%s: write error on temp file\n", progname);
	quit(2);
}

/*
  compare two strings, folding case on first string
*/
Equal(s1, s2, n)
register char *s1, *s2;
register int n;
{
	while (n-- > 0)
		if (toupper(*s1++) != *s2++)
			return 0;
	return 1;
}

#define isok(c) (isprint(c) && (c) != ' ' && (c) != ',' && (c) != '\t')
/*
  Add a list of recipients to the array of recipients.
  If Bcc is true, then this is a blind carbon copy.
*/
addrecips(line, Bcc)
char *line;
int Bcc;
{
	char *front, *back, *tail;
	char *malloc();

	tail = line + strlen(line);
	for (front=line; front < tail; ) {
		while (!isok(*front) && front < tail)
			front++;
		for (back=front; isok(*back); back++)
			;
		*back=0;
		if (nrecips >= MAXRECIPS) {
			fprintf(stderr, "%s: Too many destinations\n", progname);
			quit(2);
		}
		if ((recips[nrecips] = malloc(strlen(front) + 2)) == NULL) {
			fprintf(stderr, "%s: Out of space\n", progname);
			quit(2);
		}
		recips[nrecips][0] = Bcc ? 'B' : 'T';
		(void) strcpy(&recips[nrecips][1], front);
		nrecips++;
		front = back+1;
	}
}

int
mailto(tmpf, bccf, errfd, recip)
char *tmpf, *bccf, *recip;
FILE *errfd;
{
	register int pid;
	if (recip[0] == 'B') {	/* Bcc recipient */
		/*
		 * Copy file into bcc tmp file with Bcc: line
		 * added back in (pointing only to this recipient).
		*/
		FILE *bccfd, *tmpfd;
		char linebuf[BUFSIZ];

		bccfd = fopen(bccf, "w");
		tmpfd = fopen(tmpf, "r");
		while (fgets(linebuf, sizeof linebuf, tmpfd) != NULL) {
			if (linebuf[0] == '\n')
				break;
			if (fputs(linebuf, bccfd) == EOF)
				werror();
		}
		fprintf(bccfd, "Bcc: %s\n\n", recip+1);
		if (!feof(tmpfd))
			while (fgets(linebuf, sizeof linebuf, tmpfd))
				if (fputs(linebuf, bccfd) == EOF)
					werror();
		fclose(bccfd);
		fclose(tmpfd);
	}

	/*
	 * mail recips < tmpf
	 */
	while ((pid = fork()) == -1) {
		fprintf(stderr, "%s: fork failed, waiting...\r\n", progname);
		sleep(60);
	}
	if (pid == 0) {
		(void) close(0);
		if (recip[0] == 'B')	/* Bcc recipient */
			(void) open(bccf, 0);
		else			/* regular To/Cc recipient */
			(void) open(tmpf, 0);
		if (errfd != NULL) {
			(void) close(1);
			(void) dup(fileno(errfd));
			(void) fclose(errfd);
			(void) close(2);
			(void) dup(1);
		}
		execlp(mailer, mailer, recip+1, (char *)0);
		perror(mailer);
		exit(1);
	}
	return pid;
}

mailback(errfd, tmpf, errf)
register FILE *errfd;
char *tmpf;
char *errf;
{
	register FILE *fd;
	register int c;
	int exstat;
	register int pid, wpid;
	char *logn;
	char *getlogin(), *getenv();
	register struct passwd *pwd;

	if ((fd = fopen(tmpf, "r")) != NULL) {
		fputs("\n   ----- Unsent message follows -----\n", errfd);
		while ((c = getc(fd)) != EOF)
			putc(c, errfd);
		(void) fclose(fd);
	}
	(void) fclose(errfd);
	if ((logn = getlogin()) == NULL && (logn = getenv("USER")) == NULL) {
		if ((pwd = getpwent(getuid())) == NULL)
			return;
		logn = pwd->pw_name;
	}
	pid = mailto(errf, (FILE *)NULL, logn);
	while ((wpid = wait(&exstat)) >= 0 && wpid != pid)
		;
}
~FUNKY STUFF~
ls -l recmail.c
# The following exit is to ensure that extra garbage 
# after the end of the shar file will be ignored.
exit 0