2.9BSD/usr/src/ucb/delivermail/v6-mail.c

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

#

/*
 * mail command usage
 *	mail [-yn]
 *		prints your mail
 *	mail people
 *		sends standard input to people
 *
 *	mail -r machine user people
 *		sends mail from the network
 *
 * if NOTROOT is defined, don't run as root.
 */

#define	SIGINT		2
#define DIRECT		040000
#define RMAILCMD	"/usr/net/bin/sendmail"
#define GETUID()	(getuid() & 0377)
#define	SPOOLDIR	"/usr/spool/mail/"
#define NOTROOT		$

struct inode {
	char minor;
	char major;
	int inumber;
	int flags;
	char nlinks;
	char uid;
	char gid;
	char size0;
	int size1;
	int addr[8];
	int actime[2];
	int modtime[2];
} inode;

char	lettmp[] "/tmp/maXXXXX";
char	preptmp[] "/tmp/mbXXXXX";
int	pwfil;
int	chew;
int	errs;
char	*strcat(), *strcpy();

main(argc, argv)
char **argv;
{
	register int me;
	extern int fout;
	int uf, delexit();
	char namebuf[20];

	mktemp(lettmp);
	mktemp(preptmp);
	unlink(lettmp);
	unlink(preptmp);
	me = GETUID();
	if (getname(me, namebuf) < 0) {
		printf("Who are you?\n");
		delexit(1);
	}
	if (argc < 2)
		goto hitit;
	for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++)
	switch(argv[0][1]) {
		register char *cp, *np;

		case 'y':
		case 'n':
			argc++, argv--;
hitit:
			printmail(argc, argv, namebuf);
			delexit(0);

		case 'r':
			if (argc < 2)
				continue;
		case 'f':
			if (argc < 1)
				continue;
			if (!equal("network", namebuf) && me != 0) {
				printf("Nice try!\n");
				delexit(1);
			}
			chew++;
			np = namebuf;
			for (cp = argv[1]; *cp; cp++)
				*np++ = *cp;
			if (argv[0][1] == 'r')
			{
				argc--, argv++;
				*np++ = ':';
				for (cp = argv[1]; *cp; cp++)
					*np++ = *cp;
			}
			*np++ = 0;
			argc--, argv++;
			continue;
	}
	if ((signal(SIGINT, 01) & 01) == 0)
		signal(SIGINT, delexit);
	unlink(lettmp);
# ifdef NOTROOT
	fout = creat(lettmp, 0666);
# else
	fout = creat(lettmp, 0600);
# endif
	if (fout < 0) {
		fout = 1;
		perror(lettmp);
		delexit(1);
	}
	argc++, argv--;
	bulkmail(argc, argv, namebuf);
	delexit(0);
}

printmail(argc, argv, name)
char **argv;
char *name;
{
	extern int fin, fout;
	register n, c, f;
	char *mname;

	mname = cat(SPOOLDIR, name);
	if (stat(mname, &inode)>=0 && inode.nlinks==1 &&
		fopen(mname, &fin)>=0 && (c = getchar())) {
		putchar(c);
		getput();
		close(fin);
		c = 'x';
		if (argc<2) {
			if (ttyn(0)!='x') {
				printf("Save?");
				fin = 0;
				c = getchar();
			}
		} else
			c = argv[1][1];
		if (!any(c, "yn"))
			delexit(0);
		if (c == 'y') {
			if (accesss("mbox")) {
				printf("Saved mail in 'mbox'\n");
				prepend(mname, "mbox", GETUID());
				unlink(mname);
			} else
				printf("In wrong directory\n");
		} else
			unlink(mname);
	} else
		printf("No mail.\n");
}

bulkmail(argc, argv, from)
char **argv, *from;
{
	extern int fin, fout;
	register int c;
	register char *cp;
	char linebuf[128];
	int tbuf[2], ttyn1;

	fin = 0;
	(&fin)[1] = 0;
	time(tbuf);
	ttyn1 = ttyn(1);
	if (ttyn1 < 033) {
		ttyn1 =+ 'a' - 1;
		ttyn1 =<< 8;
		ttyn1 =| '^';
	}
	printf("From %s  tty%c  %s", from, ttyn1, ctime(tbuf));

	/*
	 * If delivering mail from the network via mail -r,
	 * Strip the leading line and throw it away, as long
	 * as it begins with "From ..."
	 */

	if (chew) {
		cp = linebuf;
		do {
			c = getchar();
			if (cp - linebuf < 120)
				*cp++ = c;
		} while (c != '\n' && c != 0);
		*cp = '\0';
		if (linebuf[0] != 'F' || linebuf[1] != 'r' ||
		    linebuf[2] != 'o' || linebuf[3] != 'm')
			printf("%s", linebuf);
	}
	getput();
	putchar('\n');
	flush();
	close(fout);
	while (--argc > 0)
		sendto(*++argv);
	delexit(errs);
}

sendto(person)
char *person;
{
	static int saved;
	extern int fout, fin;
	register char *filep;
	register int him;
	int i;

	if ((person[0] == 'i' || person[0] == 'I') && person[1] == ':')
		person += 2;
	for (i = 0; person[i] != '\0'; i++)
	{
		if (person[i] == ':')
		{
			person[i] = '\0';
			if (equal(person, "ing70") || equal(person, "ingres"))
				person += i + 1;
			else
				person[i] = ':';
			break;
		}
	}
	if (person[i] == ':' || equal(person, "msgs"))
	{
		int i = fork();
		int s;

		if (i < 0) {
			perror("fork");
			goto assback;
		}
		if (i == 0) {
			close(0);
			open(lettmp, 0);
			if (any(':', person)) {
				execl(RMAILCMD, "sendmail", person, 0);
				execl("/usr/bin/sendmail", "sendmail", person, 0);
				execl("/bin/sendmail", "sendmail", person, 0);
				perror("sendmail");
			} else {
				execl("/usr/new/msgs", "msgs", "-s", 0);
				execl("/usr/ucb/msgs", "msgs", "-s", 0);
				execl("/usr/bin/msgs", "msgs", "-s", 0);
			}
			exit(12);
		}
		for (;;) {
			register int j = wait(&s);
			if (j == -1)
				goto assback;
			if (j == i)
				break;
		}
		if ((s & 0377) != 0 || (s >> 8) == 12)
			goto assback;
		return;
	}

	if ((him = getuserid(person)) == -1) {
assback:
		fout = 1;
		flush();
		printf("Can't send to %s.\n", person);
		errs++;
		if (ttyn(0)!='x' && saved==0) {
			saved++;
			if (accesss("dead.letter")) {
				printf("Letter saved in 'dead.letter'\n");
				prepend(lettmp, "dead.letter", GETUID());
			} else
				printf("In wrong directory\n");
		}
		return;
	}
	filep = cat(SPOOLDIR, person);
	lock(filep);
	prepend(lettmp, filep, him);
	unlock();
}

prepend(from, to, own)
char *from, *to;
{
	extern int fin, fout;
	register int sig;
	int statb[18];

	if (stat(to, statb) >= 0 && (statb[2] & 060000) != 0) {
		write(2, "Exotic destination\n", 19);
		delexit(1);
	}
	unlink(preptmp);
	if (fcreat(preptmp, &fout) < 0) {
		fout = 1;
		perror("mail");
		delexit(1);
	}
	chmod(preptmp, 0600);
	if (fopen(from, &fin) < 0) {
		close(fout);
		fout = 1;
		perror("mail");
		unlink(preptmp);
		return(0);
	}
	getput();
	close(fin);
	fopen(to, &fin);
	getput();
	close(fin);
	flush();
	close(fout);
	sig = signal(SIGINT, 01);
	unlink(to);
	if (fcreat(to, &fout) < 0) {
		unlink(preptmp);
		fout = 1;
		signal(SIGINT, sig);
		return(0);
	}
# ifdef NOTROOT
	chmod(to, 0666);
# else
	chmod(to, 0600);
	chown(to, own);
# endif
	if(stat(to, &inode) < 0 || inode.nlinks != 1) {
		close(fout);
		fout = 1;
		unlink(preptmp);
		signal(SIGINT, sig);
		return(0);
	}
	if (fopen(preptmp, &fin) < 0) {
		fout = 1;
		perror("mail");
		signal(SIGINT, sig);
		errs++;
		return(0);
	}
	getput();
	flush();
	close(fout);
	close(fin);
	fout = 1;
	signal(SIGINT, sig);
	return(1);
}

delexit(ex)
{
	unlock();
	unlink(lettmp);
	unlink(preptmp);
	exit(ex);
}

equal(as1, as2)
{
	register char *s1, *s2;

	s1 = as1;
	s2 = as2;
	while (*s1++ == *s2)
		if (*s2++ == 0)
			return(1);
	return(0);
}

cat(ap1, ap2)
char *ap1, *ap2;
{
	register char *p1, *p2;
	static char fn[32];

	p1 = ap1;
	p2 = fn;
	while (*p2++ = *p1++);
	p2--;
	p1 = ap2;
	while (*p2++ = *p1++);
	return(fn);
}

getput()
{
	extern int errno;
	register c;

	while(c = getchar()) {
		errno = 0;
		putchar(c);
		if(errno) {
			perror("mail");
			delexit(1);
		}
	}
}

accesss(s1)
{
	if (access(".", 2) != -1 && (stat(s1, &inode)<0 || access(s1, 2)==0))
		return(1);
	return(0);
}

any(c, str)
	char *str;
{
	register char *f;

	f = str;
	while (*f)
		if (c == *f++)
			return(1);
	return(0);
}

char	*maillock	= ".lock";		/* Lock suffix for mailname */
char	*lockname	= "/usr/spool/mail/tmXXXXXX";
char	locktmp[30];				/* Usable lock temporary */
char	curlock[50];				/* Last used name of lock */
int	locked;					/* To note that we locked it */

/*
 * Lock the specified mail file by setting the file mailfile.lock.
 * We must, of course, be careful to unlink the lock file by a call
 * to unlock before we stop.  The algorithm used here is to see if
 * the lock exists, and if it does, to check its modify time.  If it
 * is older than 30 seconds, we assume error and set our own file.
 * Otherwise, we wait for 5 seconds and try again.
 */

lock(file)
char *file;
{
	register int f;
	long age;
	struct inode sbuf;
	long curtime;

	if (file == (char *) 0) {
		printf("Locked = %d\n", locked);
		return(0);
	}
	if (locked)
		return(0);
	strcpy(curlock, file);
	strcat(curlock, maillock);
	strcpy(locktmp, lockname);
	mktemp(locktmp);
	unlink(locktmp);
	for (;;) {
		f = lock1(locktmp, curlock);
		if (f == 0) {
			locked = 1;
			return(0);
		}
		if (stat(curlock, &sbuf) < 0)
			return(0);
		time(&curtime);
		age = * ((long *) sbuf.modtime);
		if (curtime < age + 30) {
			sleep(5);
			continue;
		}
		unlink(curlock);
	}
}

/*
 * Remove the mail lock, and note that we no longer
 * have it locked.
 */

unlock()
{

	if (locked)
		unlink(curlock);
	locked = 0;
}

/*
 * Attempt to set the lock by creating the temporary file,
 * then doing a link/unlink.  If it fails, return -1 else 0
 */

lock1(tempfile, name)
	char tempfile[], name[];
{
	register int fd;

	fd = creat(tempfile, 0);
	if (fd < 0)
		return(-1);
	close(fd);
	if (link(tempfile, name) < 0) {
		unlink(tempfile);
		return(-1);
	}
	unlink(tempfile);
	return(0);
}

/*
 * Concatenate s2 on the end of s1.  S1's space must be large enough.
 * Return s1.
 */

char *
strcat(s1, s2)
register char *s1, *s2;
{
	register os1;

	os1 = s1;
	while (*s1++)
		;
	*--s1;
	while (*s1++ = *s2++)
		;
	return(os1);
}

/*
 * Copy string s2 to s1.  s1 must be large enough.
 * return s1
 */

char *
strcpy(s1, s2)
register char *s1, *s2;
{
	register os1;

	os1 = s1;
	while (*s1++ = *s2++)
		;
	return(os1);
}