xref: /freebsd/usr.bin/mail/main.c (revision 99bd6601d77f49992f6c2fb637d2c6721d6ff19e)
19b50d902SRodney W. Grimes /*
29b50d902SRodney W. Grimes  * Copyright (c) 1980, 1993
39b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
49b50d902SRodney W. Grimes  *
59b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
69b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
79b50d902SRodney W. Grimes  * are met:
89b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
99b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
109b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
119b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
129b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
139b50d902SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
149b50d902SRodney W. Grimes  *    must display the following acknowledgement:
159b50d902SRodney W. Grimes  *	This product includes software developed by the University of
169b50d902SRodney W. Grimes  *	California, Berkeley and its contributors.
179b50d902SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
189b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
199b50d902SRodney W. Grimes  *    without specific prior written permission.
209b50d902SRodney W. Grimes  *
219b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
229b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
239b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
249b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
259b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
269b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
279b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
289b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
299b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
309b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
319b50d902SRodney W. Grimes  * SUCH DAMAGE.
329b50d902SRodney W. Grimes  */
339b50d902SRodney W. Grimes 
349b50d902SRodney W. Grimes #ifndef lint
359b50d902SRodney W. Grimes static char copyright[] =
369b50d902SRodney W. Grimes "@(#) Copyright (c) 1980, 1993\n\
379b50d902SRodney W. Grimes 	The Regents of the University of California.  All rights reserved.\n";
389b50d902SRodney W. Grimes #endif /* not lint */
399b50d902SRodney W. Grimes 
409b50d902SRodney W. Grimes #ifndef lint
419b50d902SRodney W. Grimes static char sccsid[] = "@(#)main.c	8.1 (Berkeley) 6/6/93";
429b50d902SRodney W. Grimes #endif /* not lint */
439b50d902SRodney W. Grimes 
449b50d902SRodney W. Grimes #include "rcv.h"
45e9b074c3SJordan K. Hubbard #include <err.h>
469b50d902SRodney W. Grimes #include <fcntl.h>
479b50d902SRodney W. Grimes #include "extern.h"
489b50d902SRodney W. Grimes 
499b50d902SRodney W. Grimes /*
509b50d902SRodney W. Grimes  * Mail -- a mail program
519b50d902SRodney W. Grimes  *
529b50d902SRodney W. Grimes  * Startup -- interface with user.
539b50d902SRodney W. Grimes  */
549b50d902SRodney W. Grimes 
559b50d902SRodney W. Grimes jmp_buf	hdrjmp;
569b50d902SRodney W. Grimes 
579b50d902SRodney W. Grimes int
589b50d902SRodney W. Grimes main(argc, argv)
599b50d902SRodney W. Grimes 	int argc;
609b50d902SRodney W. Grimes 	char *argv[];
619b50d902SRodney W. Grimes {
629b50d902SRodney W. Grimes 	register int i;
639b50d902SRodney W. Grimes 	struct name *to, *cc, *bcc, *smopts;
6499bd6601SJoerg Wunsch 	char *subject, *replyto;
6599bd6601SJoerg Wunsch 	char *ef, *cp;
669b50d902SRodney W. Grimes 	char nosrc = 0;
679b50d902SRodney W. Grimes 	void hdrstop();
689b50d902SRodney W. Grimes 	sig_t prevint;
699b50d902SRodney W. Grimes 	void sigchild();
709b50d902SRodney W. Grimes 
719b50d902SRodney W. Grimes 	/*
729b50d902SRodney W. Grimes 	 * Set up a reasonable environment.
739b50d902SRodney W. Grimes 	 * Figure out whether we are being run interactively,
749b50d902SRodney W. Grimes 	 * start the SIGCHLD catcher, and so forth.
759b50d902SRodney W. Grimes 	 */
769b50d902SRodney W. Grimes 	(void) signal(SIGCHLD, sigchild);
779b50d902SRodney W. Grimes 	if (isatty(0))
789b50d902SRodney W. Grimes 		assign("interactive", "");
799b50d902SRodney W. Grimes 	image = -1;
809b50d902SRodney W. Grimes 	/*
819b50d902SRodney W. Grimes 	 * Now, determine how we are being used.
829b50d902SRodney W. Grimes 	 * We successively pick off - flags.
839b50d902SRodney W. Grimes 	 * If there is anything left, it is the base of the list
849b50d902SRodney W. Grimes 	 * of users to mail to.  Argp will be set to point to the
859b50d902SRodney W. Grimes 	 * first of these users.
869b50d902SRodney W. Grimes 	 */
879b50d902SRodney W. Grimes 	ef = NOSTR;
889b50d902SRodney W. Grimes 	to = NIL;
899b50d902SRodney W. Grimes 	cc = NIL;
909b50d902SRodney W. Grimes 	bcc = NIL;
919b50d902SRodney W. Grimes 	smopts = NIL;
929b50d902SRodney W. Grimes 	subject = NOSTR;
9399bd6601SJoerg Wunsch 	replyto = NOSTR;
941c8af878SWarner Losh 	while ((i = getopt(argc, argv, "INT:b:c:dfins:u:v")) != -1) {
959b50d902SRodney W. Grimes 		switch (i) {
969b50d902SRodney W. Grimes 		case 'T':
979b50d902SRodney W. Grimes 			/*
989b50d902SRodney W. Grimes 			 * Next argument is temp file to write which
999b50d902SRodney W. Grimes 			 * articles have been read/deleted for netnews.
1009b50d902SRodney W. Grimes 			 */
1019b50d902SRodney W. Grimes 			Tflag = optarg;
1029b50d902SRodney W. Grimes 			if ((i = creat(Tflag, 0600)) < 0) {
1039b50d902SRodney W. Grimes 				perror(Tflag);
1049b50d902SRodney W. Grimes 				exit(1);
1059b50d902SRodney W. Grimes 			}
1069b50d902SRodney W. Grimes 			close(i);
1079b50d902SRodney W. Grimes 			break;
1089b50d902SRodney W. Grimes 		case 'u':
1099b50d902SRodney W. Grimes 			/*
1109b50d902SRodney W. Grimes 			 * Next argument is person to pretend to be.
1119b50d902SRodney W. Grimes 			 */
1129b50d902SRodney W. Grimes 			myname = optarg;
1139b50d902SRodney W. Grimes 			break;
1149b50d902SRodney W. Grimes 		case 'i':
1159b50d902SRodney W. Grimes 			/*
1169b50d902SRodney W. Grimes 			 * User wants to ignore interrupts.
1179b50d902SRodney W. Grimes 			 * Set the variable "ignore"
1189b50d902SRodney W. Grimes 			 */
1199b50d902SRodney W. Grimes 			assign("ignore", "");
1209b50d902SRodney W. Grimes 			break;
1219b50d902SRodney W. Grimes 		case 'd':
1229b50d902SRodney W. Grimes 			debug++;
1239b50d902SRodney W. Grimes 			break;
1249b50d902SRodney W. Grimes 		case 's':
1259b50d902SRodney W. Grimes 			/*
1269b50d902SRodney W. Grimes 			 * Give a subject field for sending from
1279b50d902SRodney W. Grimes 			 * non terminal
1289b50d902SRodney W. Grimes 			 */
1299b50d902SRodney W. Grimes 			subject = optarg;
1309b50d902SRodney W. Grimes 			break;
1319b50d902SRodney W. Grimes 		case 'f':
1329b50d902SRodney W. Grimes 			/*
1339b50d902SRodney W. Grimes 			 * User is specifying file to "edit" with Mail,
1349b50d902SRodney W. Grimes 			 * as opposed to reading system mailbox.
1359b50d902SRodney W. Grimes 			 * If no argument is given after -f, we read his
1369b50d902SRodney W. Grimes 			 * mbox file.
1379b50d902SRodney W. Grimes 			 *
1389b50d902SRodney W. Grimes 			 * getopt() can't handle optional arguments, so here
1399b50d902SRodney W. Grimes 			 * is an ugly hack to get around it.
1409b50d902SRodney W. Grimes 			 */
1419b50d902SRodney W. Grimes 			if ((argv[optind]) && (argv[optind][0] != '-'))
1429b50d902SRodney W. Grimes 				ef = argv[optind++];
1439b50d902SRodney W. Grimes 			else
1449b50d902SRodney W. Grimes 				ef = "&";
1459b50d902SRodney W. Grimes 			break;
1469b50d902SRodney W. Grimes 		case 'n':
1479b50d902SRodney W. Grimes 			/*
1489b50d902SRodney W. Grimes 			 * User doesn't want to source /usr/lib/Mail.rc
1499b50d902SRodney W. Grimes 			 */
1509b50d902SRodney W. Grimes 			nosrc++;
1519b50d902SRodney W. Grimes 			break;
1529b50d902SRodney W. Grimes 		case 'N':
1539b50d902SRodney W. Grimes 			/*
1549b50d902SRodney W. Grimes 			 * Avoid initial header printing.
1559b50d902SRodney W. Grimes 			 */
1569b50d902SRodney W. Grimes 			assign("noheader", "");
1579b50d902SRodney W. Grimes 			break;
1589b50d902SRodney W. Grimes 		case 'v':
1599b50d902SRodney W. Grimes 			/*
1609b50d902SRodney W. Grimes 			 * Send mailer verbose flag
1619b50d902SRodney W. Grimes 			 */
1629b50d902SRodney W. Grimes 			assign("verbose", "");
1639b50d902SRodney W. Grimes 			break;
1649b50d902SRodney W. Grimes 		case 'I':
1659b50d902SRodney W. Grimes 			/*
1669b50d902SRodney W. Grimes 			 * We're interactive
1679b50d902SRodney W. Grimes 			 */
1689b50d902SRodney W. Grimes 			assign("interactive", "");
1699b50d902SRodney W. Grimes 			break;
1709b50d902SRodney W. Grimes 		case 'c':
1719b50d902SRodney W. Grimes 			/*
1729b50d902SRodney W. Grimes 			 * Get Carbon Copy Recipient list
1739b50d902SRodney W. Grimes 			 */
1749b50d902SRodney W. Grimes 			cc = cat(cc, nalloc(optarg, GCC));
1759b50d902SRodney W. Grimes 			break;
1769b50d902SRodney W. Grimes 		case 'b':
1779b50d902SRodney W. Grimes 			/*
1789b50d902SRodney W. Grimes 			 * Get Blind Carbon Copy Recipient list
1799b50d902SRodney W. Grimes 			 */
1809b50d902SRodney W. Grimes 			bcc = cat(bcc, nalloc(optarg, GBCC));
1819b50d902SRodney W. Grimes 			break;
1829b50d902SRodney W. Grimes 		case '?':
1839b50d902SRodney W. Grimes 			fputs("\
1849b50d902SRodney W. Grimes Usage: mail [-iInv] [-s subject] [-c cc-addr] [-b bcc-addr] to-addr ...\n\
1859b50d902SRodney W. Grimes             [- sendmail-options ...]\n\
1869b50d902SRodney W. Grimes        mail [-iInNv] -f [name]\n\
1879b50d902SRodney W. Grimes        mail [-iInNv] [-u user]\n",
1889b50d902SRodney W. Grimes 				stderr);
1899b50d902SRodney W. Grimes 			exit(1);
1909b50d902SRodney W. Grimes 		}
1919b50d902SRodney W. Grimes 	}
1929b50d902SRodney W. Grimes 	for (i = optind; (argv[i]) && (*argv[i] != '-'); i++)
1939b50d902SRodney W. Grimes 		to = cat(to, nalloc(argv[i], GTO));
1949b50d902SRodney W. Grimes 	for (; argv[i]; i++)
1959b50d902SRodney W. Grimes 		smopts = cat(smopts, nalloc(argv[i], 0));
1969b50d902SRodney W. Grimes 	/*
1979b50d902SRodney W. Grimes 	 * Check for inconsistent arguments.
1989b50d902SRodney W. Grimes 	 */
1999b50d902SRodney W. Grimes 	if (to == NIL && (subject != NOSTR || cc != NIL || bcc != NIL)) {
2009b50d902SRodney W. Grimes 		fputs("You must specify direct recipients with -s, -c, or -b.\n", stderr);
2019b50d902SRodney W. Grimes 		exit(1);
2029b50d902SRodney W. Grimes 	}
2039b50d902SRodney W. Grimes 	if (ef != NOSTR && to != NIL) {
2049b50d902SRodney W. Grimes 		fprintf(stderr, "Cannot give -f and people to send to.\n");
2059b50d902SRodney W. Grimes 		exit(1);
2069b50d902SRodney W. Grimes 	}
2079b50d902SRodney W. Grimes 	tinit();
2089b50d902SRodney W. Grimes 	setscreensize();
2099b50d902SRodney W. Grimes 	input = stdin;
2109b50d902SRodney W. Grimes 	rcvmode = !to;
2119b50d902SRodney W. Grimes 	spreserve();
212e9b074c3SJordan K. Hubbard 	if (!nosrc) {
213e9b074c3SJordan K. Hubbard 		char *s, *path_rc;
214e9b074c3SJordan K. Hubbard 
215e9b074c3SJordan K. Hubbard 		path_rc = malloc(sizeof(_PATH_MASTER_RC));
216e9b074c3SJordan K. Hubbard 		if (path_rc == NULL)
217e9b074c3SJordan K. Hubbard 			errx(1, "malloc(path_rc) failed");
218e9b074c3SJordan K. Hubbard 
219e9b074c3SJordan K. Hubbard 		strcpy(path_rc, _PATH_MASTER_RC);
220e9b074c3SJordan K. Hubbard 		while ((s = strsep(&path_rc, ":")) != NULL)
221e9b074c3SJordan K. Hubbard 			if (*s != '\0')
222e9b074c3SJordan K. Hubbard 				load(s);
223e9b074c3SJordan K. Hubbard 	}
22499bd6601SJoerg Wunsch 	if ((cp = getenv("REPLYTO")) != NULL)
22599bd6601SJoerg Wunsch 		replyto = cp;
226e9b074c3SJordan K. Hubbard 
2279b50d902SRodney W. Grimes 	/*
2289b50d902SRodney W. Grimes 	 * Expand returns a savestr, but load only uses the file name
2299b50d902SRodney W. Grimes 	 * for fopen, so it's safe to do this.
2309b50d902SRodney W. Grimes 	 */
2319b50d902SRodney W. Grimes 	load(expand("~/.mailrc"));
2329b50d902SRodney W. Grimes 	if (!rcvmode) {
23399bd6601SJoerg Wunsch 		mail(to, cc, bcc, smopts, subject, replyto);
2349b50d902SRodney W. Grimes 		/*
2359b50d902SRodney W. Grimes 		 * why wait?
2369b50d902SRodney W. Grimes 		 */
2379b50d902SRodney W. Grimes 		exit(senderr);
2389b50d902SRodney W. Grimes 	}
2399b50d902SRodney W. Grimes 	/*
2409b50d902SRodney W. Grimes 	 * Ok, we are reading mail.
2419b50d902SRodney W. Grimes 	 * Decide whether we are editing a mailbox or reading
2429b50d902SRodney W. Grimes 	 * the system mailbox, and open up the right stuff.
2439b50d902SRodney W. Grimes 	 */
2449b50d902SRodney W. Grimes 	if (ef == NOSTR)
2459b50d902SRodney W. Grimes 		ef = "%";
2469b50d902SRodney W. Grimes 	if (setfile(ef) < 0)
2479b50d902SRodney W. Grimes 		exit(1);		/* error already reported */
2489b50d902SRodney W. Grimes 	if (setjmp(hdrjmp) == 0) {
2499b50d902SRodney W. Grimes 		extern char *version;
2509b50d902SRodney W. Grimes 
2519b50d902SRodney W. Grimes 		if ((prevint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
2529b50d902SRodney W. Grimes 			signal(SIGINT, hdrstop);
2539b50d902SRodney W. Grimes 		if (value("quiet") == NOSTR)
2549b50d902SRodney W. Grimes 			printf("Mail version %s.  Type ? for help.\n",
2559b50d902SRodney W. Grimes 				version);
2569b50d902SRodney W. Grimes 		announce();
2579b50d902SRodney W. Grimes 		fflush(stdout);
2589b50d902SRodney W. Grimes 		signal(SIGINT, prevint);
2599b50d902SRodney W. Grimes 	}
2609b50d902SRodney W. Grimes 	commands();
2619b50d902SRodney W. Grimes 	signal(SIGHUP, SIG_IGN);
2629b50d902SRodney W. Grimes 	signal(SIGINT, SIG_IGN);
2639b50d902SRodney W. Grimes 	signal(SIGQUIT, SIG_IGN);
2649b50d902SRodney W. Grimes 	quit();
2659b50d902SRodney W. Grimes 	exit(0);
2669b50d902SRodney W. Grimes }
2679b50d902SRodney W. Grimes 
2689b50d902SRodney W. Grimes /*
2699b50d902SRodney W. Grimes  * Interrupt printing of the headers.
2709b50d902SRodney W. Grimes  */
2719b50d902SRodney W. Grimes void
2729b50d902SRodney W. Grimes hdrstop(signo)
2739b50d902SRodney W. Grimes 	int signo;
2749b50d902SRodney W. Grimes {
2759b50d902SRodney W. Grimes 
2769b50d902SRodney W. Grimes 	fflush(stdout);
2779b50d902SRodney W. Grimes 	fprintf(stderr, "\nInterrupt\n");
2789b50d902SRodney W. Grimes 	longjmp(hdrjmp, 1);
2799b50d902SRodney W. Grimes }
2809b50d902SRodney W. Grimes 
2819b50d902SRodney W. Grimes /*
2829b50d902SRodney W. Grimes  * Compute what the screen size for printing headers should be.
2839b50d902SRodney W. Grimes  * We use the following algorithm for the height:
2849b50d902SRodney W. Grimes  *	If baud rate < 1200, use  9
2859b50d902SRodney W. Grimes  *	If baud rate = 1200, use 14
2869b50d902SRodney W. Grimes  *	If baud rate > 1200, use 24 or ws_row
2879b50d902SRodney W. Grimes  * Width is either 80 or ws_col;
2889b50d902SRodney W. Grimes  */
2899b50d902SRodney W. Grimes void
2909b50d902SRodney W. Grimes setscreensize()
2919b50d902SRodney W. Grimes {
2929b50d902SRodney W. Grimes 	struct winsize ws;
2937c6d202aSPeter Wemm 	struct termios tio;
2947c6d202aSPeter Wemm 	speed_t speed = 0;
2959b50d902SRodney W. Grimes 
2969b50d902SRodney W. Grimes 	if (ioctl(1, TIOCGWINSZ, (char *) &ws) < 0)
2979b50d902SRodney W. Grimes 		ws.ws_col = ws.ws_row = 0;
2987c6d202aSPeter Wemm 	if (tcgetattr(1, &tio) != -1)
2997c6d202aSPeter Wemm 		speed = cfgetospeed(&tio);
3007c6d202aSPeter Wemm 	if (speed <= 0)
3017c6d202aSPeter Wemm 		speed = B9600;
3027c6d202aSPeter Wemm 	if (speed < B1200)
3039b50d902SRodney W. Grimes 		screenheight = 9;
3047c6d202aSPeter Wemm 	else if (speed == B1200)
3059b50d902SRodney W. Grimes 		screenheight = 14;
3069b50d902SRodney W. Grimes 	else if (ws.ws_row != 0)
3079b50d902SRodney W. Grimes 		screenheight = ws.ws_row;
3089b50d902SRodney W. Grimes 	else
3099b50d902SRodney W. Grimes 		screenheight = 24;
3109b50d902SRodney W. Grimes 	if ((realscreenheight = ws.ws_row) == 0)
3119b50d902SRodney W. Grimes 		realscreenheight = 24;
3129b50d902SRodney W. Grimes 	if ((screenwidth = ws.ws_col) == 0)
3139b50d902SRodney W. Grimes 		screenwidth = 80;
3149b50d902SRodney W. Grimes }
315