114465Ssam #ifndef lint
2*29763Skarels static char sccsid[] = "@(#)mail.c	4.25 (Berkeley) 5/1/85";
314465Ssam #endif
414465Ssam 
5*29763Skarels #include <sys/param.h>
616731Sralph #include <sys/stat.h>
716731Sralph #include <sys/file.h>
816731Sralph 
9579Sroot #include <ctype.h>
10579Sroot #include <stdio.h>
11579Sroot #include <pwd.h>
12579Sroot #include <utmp.h>
13579Sroot #include <signal.h>
14579Sroot #include <setjmp.h>
15579Sroot #include <sysexits.h>
16579Sroot 
179978Seric #define SENDMAIL	"/usr/lib/sendmail"
18579Sroot 
1916731Sralph 	/* copylet flags */
2016731Sralph #define REMOTE		1		/* remote mail, add rmtmsg */
2116731Sralph #define ORDINARY	2
2216731Sralph #define ZAP		3		/* zap header and trailing empty line */
2316731Sralph #define	FORWARD		4
24579Sroot 
2516731Sralph #define	LSIZE		256
2616731Sralph #define	MAXLET		300		/* maximum number of letters */
2716731Sralph #define	MAILMODE	0600		/* mode of created mail */
28579Sroot 
29579Sroot char	line[LSIZE];
30579Sroot char	resp[LSIZE];
31579Sroot struct let {
32579Sroot 	long	adr;
33579Sroot 	char	change;
34579Sroot } let[MAXLET];
35579Sroot int	nlet	= 0;
36579Sroot char	lfil[50];
37579Sroot long	iop, time();
38579Sroot char	*getenv();
39579Sroot char	*index();
40579Sroot char	lettmp[] = "/tmp/maXXXXX";
41579Sroot char	maildir[] = "/usr/spool/mail/";
42579Sroot char	mailfile[] = "/usr/spool/mail/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
43579Sroot char	dead[] = "dead.letter";
44579Sroot char	forwmsg[] = " forwarded\n";
45579Sroot FILE	*tmpf;
46579Sroot FILE	*malf;
47*29763Skarels char	my_name[60];
48579Sroot char	*getlogin();
49579Sroot int	error;
50579Sroot int	changed;
51579Sroot int	forward;
52579Sroot char	from[] = "From ";
53579Sroot long	ftell();
5416731Sralph int	delex();
55579Sroot char	*ctime();
56579Sroot int	flgf;
57579Sroot int	flgp;
58579Sroot int	delflg = 1;
59579Sroot int	hseqno;
60579Sroot jmp_buf	sjbuf;
61579Sroot int	rmail;
62579Sroot 
63579Sroot main(argc, argv)
64579Sroot char **argv;
65579Sroot {
66579Sroot 	register i;
67*29763Skarels 	char *name;
6819868Smiriam 	struct passwd *pwent;
69579Sroot 
70*29763Skarels 	name = getlogin();
71*29763Skarels 	if (name == NULL || *name == '\0') {
72579Sroot 		pwent = getpwuid(getuid());
73579Sroot 		if (pwent==NULL)
74*29763Skarels 			name = "???";
75579Sroot 		else
76*29763Skarels 			name = pwent->pw_name;
77579Sroot 	}
7819868Smiriam 	else {
7919868Smiriam 		pwent = getpwnam(my_name);
8019868Smiriam 		if ( getuid() != pwent->pw_uid) {
8119868Smiriam 			pwent = getpwuid(getuid());
82*29763Skarels 			name = pwent->pw_name;
8319868Smiriam 		}
8419868Smiriam 	}
85*29763Skarels 	strncpy(my_name, name, sizeof(my_name)-1);
8616731Sralph 	if (setjmp(sjbuf))
8716731Sralph 		done();
8814912Sralph 	for (i=SIGHUP; i<=SIGTERM; i++)
8916731Sralph 		setsig(i, delex);
9017533Sralph 	i = mkstemp(lettmp);
9117533Sralph 	tmpf = fdopen(i, "r+w");
9217533Sralph 	if (i < 0 || tmpf == NULL)
9316731Sralph 		panic("mail: %s: cannot open for writing", lettmp);
9416731Sralph 	/*
9516731Sralph 	 * This protects against others reading mail from temp file and
9616731Sralph 	 * if we exit, the file will be deleted already.
9716731Sralph 	 */
9816731Sralph 	unlink(lettmp);
99579Sroot 	if (argv[0][0] == 'r')
100579Sroot 		rmail++;
101579Sroot 	if (argv[0][0] != 'r' &&	/* no favors for rmail*/
102579Sroot 	   (argc == 1 || argv[1][0] == '-' && !any(argv[1][1], "rhd")))
103579Sroot 		printmail(argc, argv);
104579Sroot 	else
1056015Swnj 		bulkmail(argc, argv);
106579Sroot 	done();
107579Sroot }
108579Sroot 
109579Sroot setsig(i, f)
110579Sroot int i;
111579Sroot int (*f)();
112579Sroot {
11316731Sralph 	if (signal(i, SIG_IGN) != SIG_IGN)
114579Sroot 		signal(i, f);
115579Sroot }
116579Sroot 
117579Sroot any(c, str)
118579Sroot 	register int c;
119579Sroot 	register char *str;
120579Sroot {
121579Sroot 
122579Sroot 	while (*str)
123579Sroot 		if (c == *str++)
124579Sroot 			return(1);
125579Sroot 	return(0);
126579Sroot }
127579Sroot 
128579Sroot printmail(argc, argv)
12916731Sralph 	char **argv;
130579Sroot {
131579Sroot 	int flg, i, j, print;
132579Sroot 	char *p, *getarg();
133579Sroot 	struct stat statb;
134579Sroot 
135579Sroot 	setuid(getuid());
136579Sroot 	cat(mailfile, maildir, my_name);
13716731Sralph #ifdef notdef
138579Sroot 	if (stat(mailfile, &statb) >= 0
139579Sroot 	    && (statb.st_mode & S_IFMT) == S_IFDIR) {
140579Sroot 		strcat(mailfile, "/");
141579Sroot 		strcat(mailfile, my_name);
142579Sroot 	}
14316731Sralph #endif
14416731Sralph 	for (; argc > 1; argv++, argc--) {
14516731Sralph 		if (argv[1][0] != '-')
14616731Sralph 			break;
14716731Sralph 		switch (argv[1][1]) {
14816731Sralph 
14916731Sralph 		case 'p':
15016731Sralph 			flgp++;
15116731Sralph 			/* fall thru... */
15216731Sralph 		case 'q':
15316731Sralph 			delflg = 0;
15416731Sralph 			break;
15516731Sralph 
15616731Sralph 		case 'f':
15716731Sralph 			if (argc >= 3) {
15816731Sralph 				strcpy(mailfile, argv[2]);
15916731Sralph 				argv++, argc--;
160579Sroot 			}
161579Sroot 			break;
16216731Sralph 
16316731Sralph 		case 'b':
16416731Sralph 			forward = 1;
16516731Sralph 			break;
16616731Sralph 
16716731Sralph 		default:
16816731Sralph 			panic("unknown option %c", argv[1][1]);
16916731Sralph 			/*NOTREACHED*/
17016731Sralph 		}
171579Sroot 	}
172579Sroot 	malf = fopen(mailfile, "r");
173579Sroot 	if (malf == NULL) {
17416731Sralph 		printf("No mail.\n");
175579Sroot 		return;
176579Sroot 	}
17716731Sralph 	flock(fileno(malf), LOCK_SH);
178579Sroot 	copymt(malf, tmpf);
17916731Sralph 	fclose(malf);			/* implicit unlock */
18016731Sralph 	fseek(tmpf, 0, L_SET);
181579Sroot 
182579Sroot 	changed = 0;
183579Sroot 	print = 1;
184579Sroot 	for (i = 0; i < nlet; ) {
185579Sroot 		j = forward ? i : nlet - i - 1;
18616731Sralph 		if (setjmp(sjbuf)) {
18716731Sralph 			print = 0;
188579Sroot 		} else {
189579Sroot 			if (print)
190579Sroot 				copylet(j, stdout, ORDINARY);
191579Sroot 			print = 1;
192579Sroot 		}
193579Sroot 		if (flgp) {
194579Sroot 			i++;
195579Sroot 			continue;
196579Sroot 		}
197579Sroot 		setjmp(sjbuf);
19816731Sralph 		fputs("? ", stdout);
199579Sroot 		fflush(stdout);
200579Sroot 		if (fgets(resp, LSIZE, stdin) == NULL)
201579Sroot 			break;
202579Sroot 		switch (resp[0]) {
203579Sroot 
204579Sroot 		default:
20516731Sralph 			printf("usage\n");
206579Sroot 		case '?':
207579Sroot 			print = 0;
20816731Sralph 			printf("q\tquit\n");
20916731Sralph 			printf("x\texit without changing mail\n");
21016731Sralph 			printf("p\tprint\n");
21116731Sralph 			printf("s[file]\tsave (default mbox)\n");
21216731Sralph 			printf("w[file]\tsame without header\n");
21316731Sralph 			printf("-\tprint previous\n");
21416731Sralph 			printf("d\tdelete\n");
21516731Sralph 			printf("+\tnext (no delete)\n");
21616731Sralph 			printf("m user\tmail to user\n");
21716731Sralph 			printf("! cmd\texecute cmd\n");
218579Sroot 			break;
219579Sroot 
220579Sroot 		case '+':
221579Sroot 		case 'n':
222579Sroot 		case '\n':
223579Sroot 			i++;
224579Sroot 			break;
225579Sroot 		case 'x':
226579Sroot 			changed = 0;
227579Sroot 		case 'q':
228579Sroot 			goto donep;
229579Sroot 		case 'p':
230579Sroot 			break;
231579Sroot 		case '^':
232579Sroot 		case '-':
233579Sroot 			if (--i < 0)
234579Sroot 				i = 0;
235579Sroot 			break;
236579Sroot 		case 'y':
237579Sroot 		case 'w':
238579Sroot 		case 's':
239579Sroot 			flg = 0;
240579Sroot 			if (resp[1] != '\n' && resp[1] != ' ') {
241579Sroot 				printf("illegal\n");
242579Sroot 				flg++;
243579Sroot 				print = 0;
244579Sroot 				continue;
245579Sroot 			}
246579Sroot 			if (resp[1] == '\n' || resp[1] == '\0') {
247579Sroot 				p = getenv("HOME");
24816731Sralph 				if (p != 0)
249579Sroot 					cat(resp+1, p, "/mbox");
250579Sroot 				else
251579Sroot 					cat(resp+1, "", "mbox");
252579Sroot 			}
253579Sroot 			for (p = resp+1; (p = getarg(lfil, p)) != NULL; ) {
254579Sroot 				malf = fopen(lfil, "a");
255579Sroot 				if (malf == NULL) {
25616731Sralph 					printf("mail: %s: cannot append\n",
25716731Sralph 					    lfil);
258579Sroot 					flg++;
259579Sroot 					continue;
260579Sroot 				}
261579Sroot 				copylet(j, malf, resp[0]=='w'? ZAP: ORDINARY);
262579Sroot 				fclose(malf);
263579Sroot 			}
264579Sroot 			if (flg)
265579Sroot 				print = 0;
266579Sroot 			else {
267579Sroot 				let[j].change = 'd';
268579Sroot 				changed++;
269579Sroot 				i++;
270579Sroot 			}
271579Sroot 			break;
272579Sroot 		case 'm':
273579Sroot 			flg = 0;
274579Sroot 			if (resp[1] == '\n' || resp[1] == '\0') {
275579Sroot 				i++;
276579Sroot 				continue;
277579Sroot 			}
278579Sroot 			if (resp[1] != ' ') {
279579Sroot 				printf("invalid command\n");
280579Sroot 				flg++;
281579Sroot 				print = 0;
282579Sroot 				continue;
283579Sroot 			}
284579Sroot 			for (p = resp+1; (p = getarg(lfil, p)) != NULL; )
28517019Sralph 				if (!sendmail(j, lfil, my_name))
286579Sroot 					flg++;
287579Sroot 			if (flg)
288579Sroot 				print = 0;
289579Sroot 			else {
290579Sroot 				let[j].change = 'd';
291579Sroot 				changed++;
292579Sroot 				i++;
293579Sroot 			}
294579Sroot 			break;
295579Sroot 		case '!':
296579Sroot 			system(resp+1);
297579Sroot 			printf("!\n");
298579Sroot 			print = 0;
299579Sroot 			break;
300579Sroot 		case 'd':
301579Sroot 			let[j].change = 'd';
302579Sroot 			changed++;
303579Sroot 			i++;
304579Sroot 			if (resp[1] == 'q')
305579Sroot 				goto donep;
306579Sroot 			break;
307579Sroot 		}
308579Sroot 	}
309579Sroot    donep:
310579Sroot 	if (changed)
311579Sroot 		copyback();
312579Sroot }
313579Sroot 
31416731Sralph /* copy temp or whatever back to /usr/spool/mail */
31516731Sralph copyback()
316579Sroot {
31716731Sralph 	register i, c;
31816731Sralph 	int fd, new = 0, oldmask;
319579Sroot 	struct stat stbuf;
320579Sroot 
32116731Sralph #define	mask(s)	(1 << ((s) - 1))
32216731Sralph 	oldmask = sigblock(mask(SIGINT)|mask(SIGHUP)|mask(SIGQUIT));
32316731Sralph #undef mask
32416731Sralph 	fd = open(mailfile, O_RDWR | O_CREAT, MAILMODE);
32516731Sralph 	if (fd >= 0) {
32616731Sralph 		flock(fd, LOCK_EX);
32716731Sralph 		malf = fdopen(fd, "r+w");
32816731Sralph 	}
32916731Sralph 	if (fd < 0 || malf == NULL)
33016731Sralph 		panic("can't rewrite %s", lfil);
33116731Sralph 	fstat(fd, &stbuf);
332579Sroot 	if (stbuf.st_size != let[nlet].adr) {	/* new mail has arrived */
33316731Sralph 		fseek(malf, let[nlet].adr, L_SET);
33416731Sralph 		fseek(tmpf, let[nlet].adr, L_SET);
33516731Sralph 		while ((c = getc(malf)) != EOF)
33616731Sralph 			putc(c, tmpf);
337579Sroot 		let[++nlet].adr = stbuf.st_size;
338579Sroot 		new = 1;
33916731Sralph 		fseek(malf, 0, L_SET);
340579Sroot 	}
34116731Sralph 	ftruncate(fd, 0);
342579Sroot 	for (i = 0; i < nlet; i++)
34316731Sralph 		if (let[i].change != 'd')
344579Sroot 			copylet(i, malf, ORDINARY);
34516731Sralph 	fclose(malf);		/* implict unlock */
346579Sroot 	if (new)
34716731Sralph 		printf("New mail has arrived.\n");
34816731Sralph 	sigsetmask(oldmask);
349579Sroot }
350579Sroot 
35116731Sralph /* copy mail (f1) to temp (f2) */
35216731Sralph copymt(f1, f2)
35316731Sralph 	FILE *f1, *f2;
354579Sroot {
355579Sroot 	long nextadr;
356579Sroot 
357579Sroot 	nlet = nextadr = 0;
358579Sroot 	let[0].adr = 0;
359579Sroot 	while (fgets(line, LSIZE, f1) != NULL) {
360579Sroot 		if (isfrom(line))
361579Sroot 			let[nlet++].adr = nextadr;
362579Sroot 		nextadr += strlen(line);
363579Sroot 		fputs(line, f2);
364579Sroot 	}
365579Sroot 	let[nlet].adr = nextadr;	/* last plus 1 */
366579Sroot }
367579Sroot 
36811893Seric copylet(n, f, type)
36911893Seric 	FILE *f;
37011893Seric {
37111893Seric 	int ch;
37211893Seric 	long k;
373*29763Skarels 	char hostname[MAXHOSTNAMELEN];
37411893Seric 
37516731Sralph 	fseek(tmpf, let[n].adr, L_SET);
376579Sroot 	k = let[n+1].adr - let[n].adr;
37716731Sralph 	while (k-- > 1 && (ch = getc(tmpf)) != '\n')
37816731Sralph 		if (type != ZAP)
37916731Sralph 			putc(ch, f);
38016731Sralph 	switch (type) {
38116731Sralph 
38216731Sralph 	case REMOTE:
3836199Sroot 		gethostname(hostname, sizeof (hostname));
3846199Sroot 		fprintf(f, " remote from %s\n", hostname);
38516731Sralph 		break;
38616731Sralph 
38716731Sralph 	case FORWARD:
388579Sroot 		fprintf(f, forwmsg);
38916731Sralph 		break;
39016731Sralph 
39116731Sralph 	case ORDINARY:
39216731Sralph 		putc(ch, f);
39316731Sralph 		break;
39416731Sralph 
39517019Sralph 	case ZAP:
39617019Sralph 		break;
39717019Sralph 
39816731Sralph 	default:
39916731Sralph 		panic("Bad letter type %d to copylet.", type);
40016731Sralph 	}
40116731Sralph 	while (k-- > 1) {
40216731Sralph 		ch = getc(tmpf);
40316731Sralph 		putc(ch, f);
40416731Sralph 	}
40516731Sralph 	if (type != ZAP || ch != '\n')
40616731Sralph 		putc(getc(tmpf), f);
407579Sroot }
408579Sroot 
409579Sroot isfrom(lp)
410579Sroot register char *lp;
411579Sroot {
412579Sroot 	register char *p;
413579Sroot 
414579Sroot 	for (p = from; *p; )
415579Sroot 		if (*lp++ != *p++)
416579Sroot 			return(0);
417579Sroot 	return(1);
418579Sroot }
419579Sroot 
4206015Swnj bulkmail(argc, argv)
421579Sroot char **argv;
422579Sroot {
423*29763Skarels 	char *truename;
424579Sroot 	int first;
425579Sroot 	register char *cp;
426579Sroot 	char *newargv[1000];
427579Sroot 	register char **ap;
428579Sroot 	register char **vp;
429579Sroot 	int dflag;
430579Sroot 
431579Sroot 	dflag = 0;
432*29763Skarels 	delflg = 0;
43316731Sralph 	if (argc < 1) {
434579Sroot 		fprintf(stderr, "puke\n");
43516731Sralph 		return;
43616731Sralph 	}
437579Sroot 	for (vp = argv, ap = newargv + 1; (*ap = *vp++) != 0; ap++)
438579Sroot 		if (ap[0][0] == '-' && ap[0][1] == 'd')
439579Sroot 			dflag++;
44016731Sralph 	if (!dflag) {
4419978Seric 		/* give it to sendmail, rah rah! */
442579Sroot 		unlink(lettmp);
443579Sroot 		ap = newargv+1;
444579Sroot 		if (rmail)
445579Sroot 			*ap-- = "-s";
4469978Seric 		*ap = "-sendmail";
4474461Sroot 		setuid(getuid());
4489978Seric 		execv(SENDMAIL, ap);
4499978Seric 		perror(SENDMAIL);
450579Sroot 		exit(EX_UNAVAILABLE);
451579Sroot 	}
452579Sroot 
453*29763Skarels 	truename = 0;
454579Sroot 	line[0] = '\0';
455579Sroot 
456579Sroot 	/*
457579Sroot 	 * When we fall out of this, argv[1] should be first name,
458579Sroot 	 * argc should be number of names + 1.
459579Sroot 	 */
460579Sroot 
461579Sroot 	while (argc > 1 && *argv[1] == '-') {
462579Sroot 		cp = *++argv;
463579Sroot 		argc--;
464579Sroot 		switch (cp[1]) {
465579Sroot 		case 'r':
46616731Sralph 			if (argc <= 1)
467579Sroot 				usage();
468*29763Skarels 			truename = argv[1];
46915346Skarels 			fgets(line, LSIZE, stdin);
47015346Skarels 			if (strcmpn("From", line, 4) == 0)
47115346Skarels 				line[0] = '\0';
472579Sroot 			argv++;
473579Sroot 			argc--;
474579Sroot 			break;
475579Sroot 
476579Sroot 		case 'h':
47716731Sralph 			if (argc <= 1)
478579Sroot 				usage();
479579Sroot 			hseqno = atoi(argv[1]);
480579Sroot 			argv++;
481579Sroot 			argc--;
482579Sroot 			break;
483579Sroot 
484579Sroot 		case 'd':
485579Sroot 			break;
486579Sroot 
487579Sroot 		default:
488579Sroot 			usage();
489579Sroot 		}
490579Sroot 	}
49116731Sralph 	if (argc <= 1)
492579Sroot 		usage();
493*29763Skarels 	if (truename == 0)
494*29763Skarels 		truename = my_name;
495579Sroot 	time(&iop);
496579Sroot 	fprintf(tmpf, "%s%s %s", from, truename, ctime(&iop));
497579Sroot 	iop = ftell(tmpf);
49816731Sralph 	flgf = first = 1;
49916731Sralph 	for (;;) {
50016731Sralph 		if (first) {
50116731Sralph 			first = 0;
50216731Sralph 			if (*line == '\0' && fgets(line, LSIZE, stdin) == NULL)
50316731Sralph 				break;
50416731Sralph 		} else {
50516731Sralph 			if (fgets(line, LSIZE, stdin) == NULL)
50616731Sralph 				break;
50716731Sralph 		}
50816731Sralph 		if (*line == '.' && line[1] == '\n' && isatty(fileno(stdin)))
509579Sroot 			break;
510579Sroot 		if (isfrom(line))
51116731Sralph 			putc('>', tmpf);
512579Sroot 		fputs(line, tmpf);
513579Sroot 		flgf = 0;
514579Sroot 	}
51516731Sralph 	putc('\n', tmpf);
516579Sroot 	nlet = 1;
517579Sroot 	let[0].adr = 0;
518579Sroot 	let[1].adr = ftell(tmpf);
519579Sroot 	if (flgf)
520579Sroot 		return;
52116731Sralph 	while (--argc > 0)
5226015Swnj 		if (!sendmail(0, *++argv, truename))
523579Sroot 			error++;
52410644Seric 	if (error && safefile(dead)) {
525579Sroot 		setuid(getuid());
526579Sroot 		malf = fopen(dead, "w");
527579Sroot 		if (malf == NULL) {
52816731Sralph 			printf("mail: cannot open %s\n", dead);
529579Sroot 			fclose(tmpf);
530579Sroot 			return;
531579Sroot 		}
532579Sroot 		copylet(0, malf, ZAP);
533579Sroot 		fclose(malf);
53416731Sralph 		printf("Mail saved in %s\n", dead);
535579Sroot 	}
536579Sroot 	fclose(tmpf);
537579Sroot }
538579Sroot 
53917019Sralph sendrmt(n, name)
540579Sroot char *name;
541579Sroot {
542579Sroot 	FILE *rmf, *popen();
543579Sroot 	register char *p;
544579Sroot 	char rsys[64], cmd[64];
54517019Sralph 	register pid;
546579Sroot 	int sts;
547579Sroot 
54817019Sralph #ifdef notdef
54917019Sralph 	if (any('^', name)) {
550579Sroot 		while (p = index(name, '^'))
551579Sroot 			*p = '!';
552579Sroot 		if (strncmp(name, "researc", 7)) {
553579Sroot 			strcpy(rsys, "research");
554579Sroot 			if (*name != '!')
555579Sroot 				--name;
556579Sroot 			goto skip;
557579Sroot 		}
558579Sroot 	}
55917019Sralph #endif
56017019Sralph 	for (p=rsys; *name!='!'; *p++ = *name++)
56117019Sralph 		if (*name=='\0')
56217019Sralph 			return(0);	/* local address, no '!' */
563579Sroot 	*p = '\0';
56417019Sralph 	if (name[1]=='\0') {
56516731Sralph 		printf("null name\n");
566579Sroot 		return(0);
567579Sroot 	}
568579Sroot skip:
569579Sroot 	if ((pid = fork()) == -1) {
570579Sroot 		fprintf(stderr, "mail: can't create proc for remote\n");
571579Sroot 		return(0);
572579Sroot 	}
573579Sroot 	if (pid) {
574579Sroot 		while (wait(&sts) != pid) {
575579Sroot 			if (wait(&sts)==-1)
576579Sroot 				return(0);
577579Sroot 		}
578579Sroot 		return(!sts);
579579Sroot 	}
580579Sroot 	setuid(getuid());
58117019Sralph 	if (any('!', name+1))
58217019Sralph 		sprintf(cmd, "uux - %s!rmail \\(%s\\)", rsys, name+1);
58317019Sralph 	else
58417019Sralph 		sprintf(cmd, "uux - %s!rmail %s", rsys, name+1);
585579Sroot 	if ((rmf=popen(cmd, "w")) == NULL)
586579Sroot 		exit(1);
58717019Sralph 	copylet(n, rmf, REMOTE);
58810783Seric 	exit(pclose(rmf) != 0);
589579Sroot }
590579Sroot 
591579Sroot usage()
592579Sroot {
593579Sroot 
594579Sroot 	fprintf(stderr, "Usage: mail [ -f ] people . . .\n");
59515299Skarels 	error = EX_USAGE;
59616731Sralph 	done();
597579Sroot }
598579Sroot 
5996015Swnj #include <sys/socket.h>
6009226Ssam #include <netinet/in.h>
60110227Ssam #include <netdb.h>
6026015Swnj 
60316731Sralph notifybiff(msg)
60416731Sralph 	char *msg;
60516731Sralph {
60616731Sralph 	static struct sockaddr_in addr;
60716731Sralph 	static int f = -1;
60816731Sralph 
60916731Sralph 	if (addr.sin_family == 0) {
61016731Sralph 		struct hostent *hp = gethostbyname("localhost");
61116731Sralph 		struct servent *sp = getservbyname("biff", "udp");
61216731Sralph 
61316731Sralph 		if (hp && sp) {
61416731Sralph 			addr.sin_family = hp->h_addrtype;
61516731Sralph 			bcopy(hp->h_addr, &addr.sin_addr, hp->h_length);
61616731Sralph 			addr.sin_port = sp->s_port;
61716731Sralph 		}
61816731Sralph 	}
61916731Sralph 	if (addr.sin_family) {
62016731Sralph 		if (f < 0)
62116731Sralph 			f = socket(AF_INET, SOCK_DGRAM, 0);
62216731Sralph 		sendto(f, msg, strlen(msg)+1, 0, &addr, sizeof (addr));
62316731Sralph 	}
62416731Sralph }
62516731Sralph 
6266015Swnj sendmail(n, name, fromaddr)
62716731Sralph 	int n;
62816731Sralph 	char *name, *fromaddr;
629579Sroot {
63016731Sralph 	char file[256];
63116731Sralph 	int mask, fd;
63216731Sralph 	struct passwd *pw;
63316731Sralph #ifdef notdef
634579Sroot 	struct stat statb;
63516731Sralph #endif
6363666Swnj 	char buf[128];
637579Sroot 
63817019Sralph 	if (*name=='!')
63917019Sralph 		name++;
64017019Sralph 	if (any('!', name))
64117019Sralph 		return (sendrmt(n, name));
642579Sroot 	if ((pw = getpwnam(name)) == NULL) {
64316731Sralph 		printf("mail: can't send to %s\n", name);
644579Sroot 		return(0);
645579Sroot 	}
646579Sroot 	cat(file, maildir, name);
64716731Sralph #ifdef notdef
648579Sroot 	if (stat(file, &statb) >= 0 && (statb.st_mode & S_IFMT) == S_IFDIR) {
649579Sroot 		strcat(file, "/");
650579Sroot 		strcat(file, name);
651579Sroot 	}
65216731Sralph #endif
65310644Seric 	if (!safefile(file))
6544458Sroot 		return(0);
65516731Sralph 	fd = open(file, O_WRONLY | O_CREAT, MAILMODE);
65616731Sralph 	if (fd >= 0) {
65716731Sralph 		flock(fd, LOCK_EX);
65816731Sralph 		malf = fdopen(fd, "a");
65916731Sralph 	}
66016731Sralph 	if (fd < 0 || malf == NULL) {
66116731Sralph 		close(fd);
66216731Sralph 		printf("mail: %s: cannot append\n", file);
663579Sroot 		return(0);
664579Sroot 	}
66516731Sralph 	fchown(fd, pw->pw_uid, pw->pw_gid);
66616731Sralph 	sprintf(buf, "%s@%d\n", name, ftell(malf));
667579Sroot 	copylet(n, malf, ORDINARY);
6686015Swnj 	fclose(malf);
66916731Sralph 	notifybiff(buf);
670579Sroot 	return(1);
671579Sroot }
672579Sroot 
67316731Sralph delex(i)
674579Sroot {
675*29763Skarels 	if (i != SIGINT) {
676*29763Skarels 		setsig(i, SIG_DFL);
677*29763Skarels 		sigsetmask(sigblock(0) &~ sigmask(i));
678*29763Skarels 	}
67916731Sralph 	putc('\n', stderr);
68016731Sralph 	if (delflg)
681579Sroot 		longjmp(sjbuf, 1);
682*29763Skarels 	if (error == 0)
683*29763Skarels 		error = i;
684579Sroot 	done();
685579Sroot }
686579Sroot 
68716731Sralph done()
688579Sroot {
689579Sroot 
690579Sroot 	unlink(lettmp);
691579Sroot 	exit(error);
692579Sroot }
693579Sroot 
694579Sroot cat(to, from1, from2)
69516731Sralph 	char *to, *from1, *from2;
696579Sroot {
69716731Sralph 	register char *cp, *dp;
698579Sroot 
69916731Sralph 	cp = to;
70016731Sralph 	for (dp = from1; *cp = *dp++; cp++)
70116731Sralph 		;
70216731Sralph 	for (dp = from2; *cp++ = *dp++; )
70316731Sralph 		;
704579Sroot }
705579Sroot 
70616731Sralph /* copy p... into s, update p */
70716731Sralph char *
70816731Sralph getarg(s, p)
70916731Sralph 	register char *s, *p;
710579Sroot {
711579Sroot 	while (*p == ' ' || *p == '\t')
712579Sroot 		p++;
713579Sroot 	if (*p == '\n' || *p == '\0')
714579Sroot 		return(NULL);
715579Sroot 	while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
716579Sroot 		*s++ = *p++;
717579Sroot 	*s = '\0';
718579Sroot 	return(p);
719579Sroot }
72010644Seric 
72110644Seric safefile(f)
72210644Seric 	char *f;
72310644Seric {
72410644Seric 	struct stat statb;
72510644Seric 
72610644Seric 	if (lstat(f, &statb) < 0)
72710644Seric 		return (1);
72810644Seric 	if (statb.st_nlink != 1 || (statb.st_mode & S_IFMT) == S_IFLNK) {
72916731Sralph 		fprintf(stderr,
73016731Sralph 		    "mail: %s has more than one link or is a symbolic link\n",
73116731Sralph 		    f);
73210644Seric 		return (0);
73310644Seric 	}
73410644Seric 	return (1);
73510644Seric }
73616731Sralph 
73716731Sralph panic(msg, a1, a2, a3)
73816731Sralph 	char *msg;
73916731Sralph {
74016731Sralph 
74116731Sralph 	fprintf(stderr, "mail: ");
74216731Sralph 	fprintf(stderr, msg, a1, a2, a3);
74316731Sralph 	fprintf(stderr, "\n");
74416731Sralph 	done();
74516731Sralph }
746