V8/usr/src/cmd/upas/send/send.c

Compare this file to the similar file:
Show the results in this format:

#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <pwd.h>
#include <sys/stat.h>
#include <time.h>
#include <sys/timeb.h>
#include "letter.h"
#include "mail.h"
#include "string.h"


/* configuration */
#define DEAD "dead.letter"
#define MAILMODE (~0644)		/* mode of created mail */
#define MAXFORWARD 32
#define MAXHOP 5

/* imports */
extern char *basename();
extern int (*signal())();
extern char *getsysname();
extern char *stringin();
extern char *getarg();
extern char *getenv();
extern char *mailpath();
extern char *upaspath();
extern void lock();
extern void unlock();
extern int rewrite();
extern int getrules();
extern long getunix();
extern void putunix();
extern void putrfunix();
extern FILE *popen();
extern char *getlogin();
extern char *asctime();
extern struct tm *localtime();
extern char *timezone();

/* exported */
char *thissys;		/* name of this system */
char *network = "uucp";	/* name of network mail is coming from */
int onatty;
int rmail;		/* true if not executed as 'mail' */

/* global to this module */
#define LETTERNAME 0
#define DEVTTY NOFILE-1
static int error;
static char *myname;		/* name of this program */

/* predeclared */
static void saveletter();
static int saveonint(), done();
static int send();
static int append_to_file();
static int pipe_to_cmd();
static long getfrom();

extern void
sendmail(ac, av)
	int ac;
	char *av[];
{
	int chkfl;		/* check forward list */
	int ind=1;
	int (*rc)();
	char sender[ADDRSIZE];
	char date[DATESIZE];
	long bodyoffset;
	letter *lp;

	/* avoid hanging dk lines (HACK!!!!!!!!) */
	close(DEVTTY);

	myname = basename(av[0]);
	rmail = chkfl = strcmp(myname, "mail") != 0;
	onatty = isatty(0);
	thissys = getsysname();

	/* make temporary */
	rc = signal(SIGINT, done);
	inittmp();

	/* get network (default uucp) */
	if (av[1][0] == '-' && av[1][1] == 'N') {
		if (av[1][2] == '\0') {
			network = av[2];
			ind++;
		} else {
			network = &(av[1][2]);
		}
		ind++;
	}

	/* read letter */
	(void)signal(SIGINT, saveonint);
	lp = lopen(LETTERNAME, "w");
	copyto(stdin, lp, onatty, 1);
	if (ltell(lp) == 0L)
		done();
		
	/* send */
	if (!error) {
		(void)getrules();
		lp = lopen(LETTERNAME, "r");
		bodyoffset = getfrom(lp, sender, date);
		(void)signal(SIGINT, rc);
		for (; ind<ac; ind++) {
			letseek(lp, bodyoffset);
			error += send(lp, sender, date, av[ind], chkfl, 0);
		}
	}
	if (error && onatty)
		saveletter(lp);
	(void)done();
}

/* come here on interrupt while reading in letter */
static int
saveonint() {
	(void)signal(SIGINT, saveonint);
	error++;
}

/* come here to finish up */
static int
done() {
	unlock();
	releasetmp();
	exit(error);
}

/* save the letter in dead.letter */
static void
saveletter(lp)
	letter *lp;
{
	FILE *malf;
	char where[PATHSIZE];
	char *home = getenv("HOME");

	(void)setgid(getgid());
	(void)setuid(getuid());
	if (home != NULL) {
		strcpy(where, home);
		strcat(where, "/");
	} else
		*where = '\0';
	strcat(where, DEAD);
	malf = fopen(where, "w");
	if (malf == NULL) {
		fprintf(stderr, "mail: cannot open %s\n", where);
		return;
	}
	letseek(lp, (long)0);
	copyfrom(lp, malf);
	fclose(malf);
	printf("Mail saved in %s\n", where);
}

/*
 *	Send a letter.  Return 0 if all went well.
 */
static int
send(lp, sender, date, rcvr, chkfl, hop)
	letter *lp;
	char *sender, *date, *rcvr;
	int chkfl;
	int hop;
{
	int rv, notinfl;
	char dest[ADDRSIZE], rest[ADDRSIZE], cmd[CMDSIZE], format[32], sysname[64];

	if ((notinfl = rewrite(rcvr, sender, chkfl, cmd)) < 0) {
		fprintf(stderr, "mail: can't understand address %s\n", dest);
		return 1;
	}
	if (cmd[0]=='\0')
		rv = append_to_file(lp, sender, date, rcvr, chkfl, hop);
	else
		rv = pipe_to_cmd(lp, sender, date, rcvr, cmd,
			chkfl && notinfl);
	return rv;
}

/*
 *	Put mail into a mail file in the standard place.
 */
static int
append_to_file(lp, sender, date, rcvr, chkfl, hop)
	letter *lp;
	char *sender, *date, *rcvr;
	int hop;
{
	register mask;
	struct passwd *pw, *getpwnam();
	struct stat stbuf;
	char file[PATHSIZE];
	char sendto[CMDSIZE];
	int exists;
	FILE *malf;
	char *p;
	int i;

	if (strcmp(rcvr, "-") == 0)
		return(1);
	if (strchr(rcvr, '/') != NULL) {
		fprintf(stderr, "mail: illegal name %s\n", rcvr);
		return(0);
	}
	strcpy(file, mailpath(rcvr));
	switch (delivery_status(file, sendto) & MFTYPE) {
	case MF_NORMAL:
		/* normal message */
		break;
	case MF_FORWARD:
		/* look for possible forwarding loop */
		for (i = 0, p = sender-1; p != NULL; p = strchr(p+1, '!'))
			if (strncmp(thissys, p+1, strlen(thissys))==0)
				i++;
		if (i > MAXHOP) {
			logsend(rcvr, sender, date, "remote-mail-loop-err");
			fprintf(stderr, "mail: remote mail loop\n");
			break;
		}

		/* forward message */
		return forward_to(lp, rcvr, sender, date, sendto, hop);
	case MF_PIPE:
		/* pipe to a command */
		(void)stat(file, &stbuf);
		return pipe_to(lp, rcvr, sender, date, sendto, stbuf.st_uid,
			       stbuf.st_gid);
	}
	exists = stat(file, &stbuf);
	if ((pw = getpwnam(rcvr)) == NULL) {
		if (exists < 0) {
			if (chkfl) {
				refuse(lp,sender, date, rcvr, "addressee unknown.");
				return(0);
			}
			fprintf(stderr, "mail: can't send to %s\n", rcvr);
			return 1;
		}
	} else {
		stbuf.st_uid = pw->pw_uid;
		stbuf.st_gid = pw->pw_gid;
	}
	mask = umask(MAILMODE);
	lock(file);
	malf = fopen(file, "a");
	umask(mask);
	if (malf == NULL) {
		fprintf(stderr, "mail: cannot append to %s\n", file);
		logsend(rcvr, sender, date, "append-err");
		return 1;
	}
	if (exists < 0)
		chown(file, stbuf.st_uid, stbuf.st_gid);
	fprintf(malf, "%s%s %s\n", FROM, sender, date);
	copyfrom(lp, malf);
	fputs("\n", malf);
	fclose(malf);
	unlock();
	logsend(rcvr, sender, date, "delivered");
	notify(rcvr, sender);	/* let him know it right away! */
	return 0;
}

/*
 *	Pipe the mail into a command.  This is either for remote
 *	mail or specially handled mail.  Remote mail is distinguished
 *	by a non-null string as the destination.
 */
static int
pipe_to_cmd(lp, sender, date, rcvr, cmd, chkfl)
	letter *lp;
	char *sender, *date, *rcvr, *cmd;
	int chkfl;
{
	FILE *fp;
	char errbuf[CMDSIZE];
	char reason[2*CMDSIZE];
	long pos, status;

	/* check forwarding (what anti-social crap!) */
	if (chkfl) {
		if (rewrite(sender, "", chkfl, (char *)NULL) != 0) {
			refuse(lp, sender, date, rcvr,
				"forwarding to this system disallowed.");
			return(0);
		}
	}

	/* do it */
	if ((fp=popen(cmd, getuid(), getgid())) == NULL) {
		fprintf(stderr, "mail: can't pipe to network mailer\n");
		exit(1);
	}
	pos = ltell(lp);
	putrfunix(sender, date, thissys, fp);
	copyfrom(lp, fp);
	status = pclose(fp, errbuf, CMDSIZE);
	if (status==0) {
		logsend(rcvr, sender, date, "remote");
		return 0;
	} else {
		logsend(rcvr, sender, date, "remote-err");
		logsend("", cmd, "", "remote-err");
		sprintf(reason, "\"%s\"\nwas unable to send your mail.  It returned the status 0x%x.\nStderr was:\n%s",
			cmd, status, errbuf);
		(void)letseek(lp, pos);
		refuse(lp, sender, date, rcvr, reason);
		return 0;
	}
}


/* return to sender, address unknown, no such number, no such phone... */
refuse(lp, sender, date, rcvr, reason)
	letter *lp;
	char *sender, *date, *rcvr, *reason;
{
	FILE *pf;
	char cbuf[CMDSIZE];

	sprintf(cbuf, "PATH=/bin:/usr/bin mail %s", sender);
	if ((pf = popen(cbuf, getuid(), getgid())) == NULL)
		return;
	fprintf(pf, "Mail to %s failed. %s\nMessage was:\n", rcvr, reason);
	fprintf(pf, "%s%s %s\n", FROM, sender, date);
	copyfrom(lp, pf);
	pclose(pf, 0, 0);
	logsend(rcvr, sender, date, "refused");
}

/* forward mail to a list of people */
forward_to(lp, rcvr, sender, date, list, hop)
	letter *lp;
	char *rcvr, *sender, *date, *list;
	int hop;
{
	char dest[ADDRSIZE];
	char *p;
	int rv=0;

	if (hop > MAXFORWARD) {
		fprintf(stderr, "mail: forwarding loop!!\n");
		logsend(rcvr, sender, date, "forward-loop-err");
		return 1;
	}
	for (p = list; (p = getarg(dest, p)) != NULL; ) {
		(void)letseek(lp, (long)0);
		rv += send(lp, sender, date, dest, 0, ++hop);
	}
	return rv;
}

#define SU 0	/* super-duper user uid */

/* change uid to the receiver and perform the command */
pipe_to(lp, rcvr, sender, date, cmd, uid, gid)
	letter *lp;
	char *rcvr, *sender, *date, *cmd;
{
	FILE *fp;
	int i;

	/* do it */
	if ((fp=popen(cmd, uid, gid)) == NULL) {
		fprintf(stderr, "mail: can't pipe to network mailer\n");
		return 1;
	}
	putunix(sender, date, fp);
	copyfrom(lp, fp);
	if ((i=pclose(fp, 0, 0))==0) {
		logsend(rcvr, sender, date, "pipe_to");
		return 0;
	} else {
		logsend(rcvr, sender, date, "pipe_to_err");
		logsend("", cmd, "", "pipe_to_err");
		fprintf(stderr, "mail: Pipe to \"%s\" returns error status %d\n",
			cmd, i);
		return 1;
	}
}

/* default sender */
static void
defaultsender(sender, date)
	char *sender;	/* filled by defaultsender */
	char *date;	/* filled by defaultsender */
{
	char *tp, *dp;
	struct timeb timbuf;
	struct tm *bp;
	long thetime;

	(void)strcpy(sender, getlogin());
	ftime(&timbuf);
	thetime = timbuf.time;
	bp = localtime(&thetime);
	dp = asctime(bp);
	tp = timezone(timbuf.timezone, bp->tm_isdst);
	sprintf(date, "%.16s %.3s %.4s", dp, tp, dp+20);
}

/* Get/parse a unix header. */
static long
getfrom(lp, sender, date)
	letter *lp;
	char *sender, *date;
{
	char line[FROMLINESIZE];
	long n=0;

	defaultsender(sender, date);
	initgetunix();
	while (lgets(line, sizeof(line), lp) != NULL) {
		if (getunix(line, sender, date) == 0)
			break;
		n = ltell(lp);
	}

	return n;
}