SysIII/usr/src/games/mail.c

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

/*
**	mail [ person ]
**	mail -f file
**	(without Shell escapes, for use with "games", etc.)
*/

#include	<stdio.h>
#include	<pwd.h>
#include	<utmp.h>
#include	<signal.h>
#include	<sys/types.h>
#include	<sys/stat.h>
#include	<setjmp.h>

/*copylet flags */
#define	REMOTE		1		/* remote mail, add rmtmsg */
#define ORDINARY	2
#define ZAP		3		/* zap header and trailing empty line */
#define	LSIZE		256
#define	MAXLET		300		/* maximum number of letters */
#ifndef	MFMODE
#define	MFMODE		0666		/* create mode for `/usr/mail' files */
#endif

struct	let	{
	long	adr;
	char	change;
} let[MAXLET];

struct	passwd	*getpwuid(), getpwent();

char	lettmp[] = "/tmp/maXXXXX";
char	from[] = "From ";
char	maildir[] = "/usr/mail/";
char	mailfile[] = "/usr/mail/xxxxxxxxxxxxxxxxxxxxxxx";
char	maillock[] = ".lock";
char	dead[] = "dead.letter";
char	rmtbuf[] = "/tmp/marXXXXXX";
char	*rmtmsg = " remote from usg\n";
char	*thissys = "usg";
char	mbox[] = "/mbox";
char	curlock[50];
char	line[LSIZE];
char	resp[LSIZE];
char	*hmbox;
char	*home;
char	*my_name;
char	*getlogin();
char	*malloc();
char	lfil[50];
char	*ctime();
char	*getenv();

FILE	*tmpf;
FILE	*malf;
FILE	*rmtf;

int	error;
int	nlet	= 0;
int	locked;
int	changed;
int	forward;
int	delete();
int	flgf;
int	delflg;

long	ftell();
long	iop;

jmp_buf	sjbuf;

unsigned umsave;

main(argc, argv)
char **argv;
{
	register i;

	umsave = umask(0);
	setbuf(stdout, malloc(BUFSIZ));
	mktemp(lettmp);
	unlink(lettmp);
	my_name = getlogin();
	if (my_name == NULL)
		my_name = getpwuid(getuid())->pw_name;
	if(setjmp(sjbuf)) done();
	for (i=0; i<20; i++)
		setsig(i, delete);
	tmpf = fopen(lettmp, "w");
	if (tmpf == NULL) {
		fprintf(stderr, "mail: cannot open %s for writing\n", lettmp);
		error = 2;
		done();
	}
	if (argv[0][0] != 'r' &&	/* no favors for rmail */
	   (argc == 1 || argv[1][0] == '-' || argv[1][0] == '+'))
		printmail(argc, argv);
	else
		sendmail(argc, argv);
	done();
}

setsig(i, f)
int i;
int (*f)();
{
	if(signal(i, SIG_IGN)!=SIG_IGN)
		signal(i, f);
}

printmail(argc, argv)
char **argv;
{
	int	flg, i, j, print;
	char	*p, *getarg();

	if (argv[1][0] == '+') {
		forward = 1;
		argc--;
		argv++;
	}
	flgf = 0;
	home = getenv("HOME");
	if(home == NULL)
		fprintf(stderr, "mail: cannot find home directory\n");
	hmbox = malloc(strlen(home) + strlen(mbox) + 1);
	strcpy(hmbox, home);
	strcat(hmbox, mbox);
	cat(mailfile, maildir, my_name);
	if ((argv[1][0] == '-') && (argv[1][1] == 'i')) {
		delflg++;
		argc--; argv++;
	}
	if (argc > 2 && argv[1][1] == 'f') {
		flgf = 1;
		cat(mailfile, argv[2], "");
	}
	malf = fopen(mailfile, "r");
	if (malf == NULL) {
		fprintf(stdout, "No mail.\n");
		return;
	}
	lock(mailfile);
	copymt(malf, tmpf);
	fclose(malf);
	fclose(tmpf);
	unlock();
	tmpf = fopen(lettmp, "r");
	changed = 0;
	print = 1;
	for (i = 0; i < nlet; ) {
		j = forward ? i : nlet - i - 1;
		if(setjmp(sjbuf)) {
			print=0;
		} else {
			if (print)
				copylet(j, stdout, ORDINARY);
			print = 1;
		}
		setjmp(sjbuf);
		fprintf(stdout, "? ");
		fflush(stdout);
		if (fgets(resp, LSIZE, stdin) == NULL)
			break;
		switch (resp[0]) {

		default:
			fprintf(stderr, "usage\n");
		case '?':
			print = 0;
			fprintf(stderr, "q\t\tquit\n");
			fprintf(stderr, "p\t\tprint\n");
			fprintf(stderr, "s [file]\tsave (default mbox)\n");
			fprintf(stderr, "w [file]\tsame without header\n");
			fprintf(stderr, "-\t\tprint previous\n");
			fprintf(stderr, "d\t\tdelete\n");
			fprintf(stderr, "+\t\tnext (no delete)\n");
			fprintf(stderr, "m [user]\tmail to user\n");
			break;

		case 'n':
		case '\n':
			i++;
			break;
		case 'q':
			goto donep;
		case 'p':
			break;
		case '^':
		case '-':
			if (--i < 0)
				i = 0;
			break;
		case 'y':
		case 'w':
		case 's':
			flg = 0;
			if (resp[1] == '\n' || resp[1] == '\0')
				cat(resp+1, hmbox, "");
			else if(resp[1] != ' ') {
				printf("invalid command\n");
				flg++;
				print = 0;
				continue;
			}
			for (p = resp+1; (p = getarg(lfil, p)) != NULL; ) {
				umask(umsave);
				malf = fopen(lfil, "a");
				umask(0);
				if (malf == NULL) {
					fprintf(stdout, "mail: cannot append to %s\n", lfil);
					flg++;
					continue;
				}
				copylet(j, malf, resp[0]=='w'? ZAP: ORDINARY);
				fclose(malf);
			}
			if (flg)
				print = 0;
			else {
				let[j].change = 'd';
				changed++;
				i++;
			}
			break;
		case 'm':
			flg = 0;
			if (resp[1] == '\n' || resp[1] == '\0') {
				i++;
				continue;
			}
			if (resp[1] != ' ') {
				printf("invalid command\n");
				flg++;
				print = 0;
				continue;
			}
			for (p = resp+1; (p = getarg(lfil, p)) != NULL; )
				if (!send(j, lfil))	/* couldn't send it */
					flg++;
			if (flg)
				print = 0;
			else {
				let[j].change = 'd';
				changed++;
				i++;
			}
			break;
		case 'd':
			let[j].change = 'd';
			changed++;
			i++;
			if (resp[1] == 'q')
				goto donep;
			break;
		}
	}
   donep:
	if (changed)
		copyback();
}

copyback()	/* copy temp or whatever back to /usr/mail */
{
	register i, n, c;
	int new = 0;
	struct stat stbuf;

	signal(SIGINT, SIG_IGN);
	signal(SIGHUP, SIG_IGN);
	signal(SIGQUIT, SIG_IGN);
	lock(mailfile);
	stat(mailfile, &stbuf);
	if (stbuf.st_size != let[nlet].adr) {	/* new mail has arrived */
		malf = fopen(mailfile, "r");
		if (malf == NULL) {
			fprintf(stdout, "mail: can't re-read %s\n", mailfile);
			error = 2;
			done();
		}
		fseek(malf, let[nlet].adr, 0);
		fclose(tmpf);
		tmpf = fopen(lettmp, "a");
		fseek(tmpf, let[nlet].adr, 0);
		while ((c = fgetc(malf)) != EOF)
			fputc(c, tmpf);
		fclose(malf);
		fclose(tmpf);
		tmpf = fopen(lettmp, "r");
		let[++nlet].adr = stbuf.st_size;
		new = 1;
	}
	malf = fopen(mailfile, "w");
	if (malf == NULL) {
		fprintf(stderr, "mail: can't rewrite %s\n", mailfile);
		error = 2;
		done();
	}
	n = 0;
	for (i = 0; i < nlet; i++)
		if (let[i].change != 'd') {
			copylet(i, malf, ORDINARY);
			n++;
		}
	fclose(malf);
	if (n == 0)	/* none written, empty mailbox */
		unlink(mailfile);
	if (new)
		fprintf(stdout, "new mail arrived\n");
	unlock();
}

copymt(f1, f2)	/* copy mail (f1) to temp (f2) */
FILE *f1, *f2;
{
	long nextadr;

	nlet = nextadr = 0;
	let[0].adr = 0;
	while (fgets(line, LSIZE, f1) != NULL) {
		if (isfrom(line))
			let[nlet++].adr = nextadr;
		nextadr += strlen(line);
		fputs(line, f2);
	}
	let[nlet].adr = nextadr;	/* last plus 1 */
}

copylet(n, f, type) FILE *f;
{	int ch, k;
	fseek(tmpf, let[n].adr, 0);
	k = let[n+1].adr - let[n].adr;
	while(k-- > 1 && (ch=fgetc(tmpf))!='\n')
		if(type!=ZAP)
			fputc(ch,f);
	if(type==REMOTE)
		fprintf(f, rmtmsg);
	else if(type==ORDINARY)
		fputc(ch,f);
	while(k-->1)
		fputc(ch=fgetc(tmpf), f);
	if(type!=ZAP || ch!= '\n')
		fputc(fgetc(tmpf), f);
}

isfrom(lp)
register char *lp;
{
	register char *p;

	for (p = from; *p; )
		if (*lp++ != *p++)
			return(0);
	return(1);
}

sendmail(argc, argv)
char **argv;
{

	time(&iop);
	fprintf(tmpf, "%s%s %s", from, my_name, ctime(&iop));
	iop = ftell(tmpf);
	flgf = 1;
	while (fgets(line, LSIZE, stdin) != NULL) {
		if (line[0] == '.' && line[1] == '\n')
			break;
		if (isfrom(line))
			fputs(">", tmpf);
		fputs(line, tmpf);
		flgf = 0;
	}
	fputs("\n", tmpf);
	nlet = 1;
	let[0].adr = 0;
	let[1].adr = ftell(tmpf);
	fclose(tmpf);
	if (flgf)
		return;
	tmpf = fopen(lettmp, "r");
	if (tmpf == NULL) {
		fprintf(stderr, "mail: cannot reopen %s for reading\n", lettmp);
		error = 2;
		return;
	}
	while (--argc > 0)
		if (!send(0, *++argv))	/* couldn't send to him */
			error++;
	if (error) {
		umask(umsave);
		malf = fopen(dead, "w");
		if (malf == NULL) {
			fprintf(stdout, "mail: cannot create %s\n", dead);
			fclose(tmpf);
			error = 2;
			return;
		}
		copylet(0, malf, ZAP);
		fclose(malf);
		fprintf(stdout, "Mail saved in %s\n", dead);
	}
	fclose(tmpf);
}

sendrmt(n, name) char *name;
{	char rsys[50], cmd[128], *p;
	if(*name == '!') strcpy(name, thissys);
	else	for(p=rsys; *name!='!'; *p++ = *name++);
	*p = '\0';
	if(*name++=='\0')
	{	fprintf(stdout, "null name\n");
		return(0);
	}
	if(rmtf==NULL)
	{	mktemp(rmtbuf);
		unlink(rmtbuf);
		rmtf = fopen(rmtbuf, "w");
		if(rmtf==NULL)
		{	fprintf(stderr,"can't open %s for writing\n",rmtbuf);
			return(0);
		}
	}
	else
	{	close(creat(rmtbuf, 0600)); /*truncate*/
		rewind(rmtf);
	}
	copylet(n, rmtf, REMOTE);
	sprintf(cmd, "cat %s | uux - '%s!rmail %s'", rmtbuf, rsys, name);
	fflush(rmtf);
	return(!system(cmd));
}

send(n, name)	/* send letter n to name */
int n;
char *name;
{
	char	file[50], *p;
	struct	passwd	*pwd;

	for(p=name; *p!='!' &&*p!='\0'; p++);
	if(*p == '!')
		return(sendrmt(n, name));
	setpwent();	/* rewind password file -- dumb design */
	pwd = getpwnam(name);
	if (pwd == NULL) {
		fprintf(stdout, "mail: can't send to %s\n", name);
		return(0);
	}
	cat(file, maildir, name);
	lock(file);
	if(access(file, 0) < 0) {
		close(creat(file, MFMODE));
		chown(file, pwd->pw_uid, pwd->pw_gid);
	}
	malf = fopen(file, "a");
	if (malf == NULL) {
		fprintf(stdout, "mail: cannot append to %s\n", file);
		unlock();
		return(0);
	}
	copylet(n, malf, ORDINARY);
	fclose(malf);
	unlock();
	return(1);
}

delete(i)
{
	setsig(i, delete);
	fprintf(stderr, "\n");
	if(delflg)
		longjmp(sjbuf, 1);
	done();
}

done()
{
	unlock();
	unlink(lettmp);
	unlink(rmtbuf);
	exit(error);
}

lock(file)
char *file;
{
	int f, i;

	if (locked)
		return;
	cat(curlock, file, maillock);
	for (i=0; i<10; i++) {
		f = creat(curlock, 0);
		if (f >= 0) {
			close(f);
			locked = 1;
			return;
		}
		sleep(2);
	}
	fprintf(stderr, "mail: %s not creatable after %d tries\n", curlock, i);
	fprintf(stderr, "gok whats wrong\n");
	error = 2;
	done();
}

unlock()
{
	unlink(curlock);
	locked = 0;
}

cat(to, from1, from2)
char *to, *from1, *from2;
{
	int i, j;

	j = 0;
	for (i=0; from1[i]; i++)
		to[j++] = from1[i];
	for (i=0; from2[i]; i++)
		to[j++] = from2[i];
	to[j] = 0;
}

char *getarg(s, p)	/* copy p... into s, update p */
register char *s, *p;
{
	while (*p == ' ' || *p == '\t')
		p++;
	if (*p == '\n' || *p == '\0')
		return(NULL);
	while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
		*s++ = *p++;
	*s = '\0';
	return(p);
}