xref: /freebsd/usr.bin/mail/main.c (revision 389ae6c65d4db89e86fd303d7e1288a2a8d12d46)
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  * 4. Neither the name of the University nor the names of its contributors
149b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
159b50d902SRodney W. Grimes  *    without specific prior written permission.
169b50d902SRodney W. Grimes  *
179b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
189b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
199b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
209b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
219b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
229b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
239b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
249b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
259b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
269b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
279b50d902SRodney W. Grimes  * SUCH DAMAGE.
289b50d902SRodney W. Grimes  */
299b50d902SRodney W. Grimes 
309b50d902SRodney W. Grimes #ifndef lint
319b50d902SRodney W. Grimes static char copyright[] =
329b50d902SRodney W. Grimes "@(#) Copyright (c) 1980, 1993\n\
339b50d902SRodney W. Grimes 	The Regents of the University of California.  All rights reserved.\n";
349b50d902SRodney W. Grimes #endif /* not lint */
359b50d902SRodney W. Grimes 
369b50d902SRodney W. Grimes #ifndef lint
370c3a8314SMike Heffner #if 0
38856f23edSMike Heffner static char sccsid[] = "@(#)main.c	8.2 (Berkeley) 4/20/95";
390c3a8314SMike Heffner #endif
409b50d902SRodney W. Grimes #endif /* not lint */
41e026a48cSDavid E. O'Brien #include <sys/cdefs.h>
42e026a48cSDavid E. O'Brien __FBSDID("$FreeBSD$");
439b50d902SRodney W. Grimes 
449b50d902SRodney W. Grimes #include "rcv.h"
459b50d902SRodney W. Grimes #include <fcntl.h>
469b50d902SRodney W. Grimes #include "extern.h"
479b50d902SRodney W. Grimes 
489b50d902SRodney W. Grimes /*
499b50d902SRodney W. Grimes  * Mail -- a mail program
509b50d902SRodney W. Grimes  *
519b50d902SRodney W. Grimes  * Startup -- interface with user.
529b50d902SRodney W. Grimes  */
539b50d902SRodney W. Grimes 
54e7d53813SDiomidis Spinellis static jmp_buf	hdrjmp;
559b50d902SRodney W. Grimes 
569ce73e90SMike Heffner extern const char *version;
579ce73e90SMike Heffner 
589b50d902SRodney W. Grimes int
596d8484b0SPhilippe Charnier main(int argc, char *argv[])
609b50d902SRodney W. Grimes {
619ce73e90SMike Heffner 	int i;
629b50d902SRodney W. Grimes 	struct name *to, *cc, *bcc, *smopts;
6399bd6601SJoerg Wunsch 	char *subject, *replyto;
64856f23edSMike Heffner 	char *ef, *rc;
659b50d902SRodney W. Grimes 	char nosrc = 0;
669b50d902SRodney W. Grimes 	sig_t prevint;
679b50d902SRodney W. Grimes 
689b50d902SRodney W. Grimes 	/*
699b50d902SRodney W. Grimes 	 * Set up a reasonable environment.
709b50d902SRodney W. Grimes 	 * Figure out whether we are being run interactively,
719b50d902SRodney W. Grimes 	 * start the SIGCHLD catcher, and so forth.
729b50d902SRodney W. Grimes 	 */
739b50d902SRodney W. Grimes 	(void)signal(SIGCHLD, sigchild);
749b50d902SRodney W. Grimes 	if (isatty(0))
759b50d902SRodney W. Grimes 		assign("interactive", "");
769b50d902SRodney W. Grimes 	image = -1;
779b50d902SRodney W. Grimes 	/*
789b50d902SRodney W. Grimes 	 * Now, determine how we are being used.
799b50d902SRodney W. Grimes 	 * We successively pick off - flags.
809b50d902SRodney W. Grimes 	 * If there is anything left, it is the base of the list
819b50d902SRodney W. Grimes 	 * of users to mail to.  Argp will be set to point to the
829b50d902SRodney W. Grimes 	 * first of these users.
839b50d902SRodney W. Grimes 	 */
849ce73e90SMike Heffner 	ef = NULL;
859ce73e90SMike Heffner 	to = NULL;
869ce73e90SMike Heffner 	cc = NULL;
879ce73e90SMike Heffner 	bcc = NULL;
889ce73e90SMike Heffner 	smopts = NULL;
899ce73e90SMike Heffner 	subject = NULL;
90c92dfc23SMike Heffner 	while ((i = getopt(argc, argv, "FEHINT:b:c:edfins:u:v")) != -1) {
919b50d902SRodney W. Grimes 		switch (i) {
929b50d902SRodney W. Grimes 		case 'T':
939b50d902SRodney W. Grimes 			/*
949b50d902SRodney W. Grimes 			 * Next argument is temp file to write which
959b50d902SRodney W. Grimes 			 * articles have been read/deleted for netnews.
969b50d902SRodney W. Grimes 			 */
979b50d902SRodney W. Grimes 			Tflag = optarg;
980c3a8314SMike Heffner 			if ((i = open(Tflag, O_CREAT | O_TRUNC | O_WRONLY,
990c3a8314SMike Heffner 			    0600)) < 0)
1000c3a8314SMike Heffner 				err(1, "%s", Tflag);
1019ce73e90SMike Heffner 			(void)close(i);
1029b50d902SRodney W. Grimes 			break;
1039b50d902SRodney W. Grimes 		case 'u':
1049b50d902SRodney W. Grimes 			/*
1059b50d902SRodney W. Grimes 			 * Next argument is person to pretend to be.
1069b50d902SRodney W. Grimes 			 */
1079b50d902SRodney W. Grimes 			myname = optarg;
10849936df3SJean-Marc Zucconi 			unsetenv("MAIL");
1099b50d902SRodney W. Grimes 			break;
1109b50d902SRodney W. Grimes 		case 'i':
1119b50d902SRodney W. Grimes 			/*
1129b50d902SRodney W. Grimes 			 * User wants to ignore interrupts.
1139b50d902SRodney W. Grimes 			 * Set the variable "ignore"
1149b50d902SRodney W. Grimes 			 */
1159b50d902SRodney W. Grimes 			assign("ignore", "");
1169b50d902SRodney W. Grimes 			break;
1179b50d902SRodney W. Grimes 		case 'd':
1189b50d902SRodney W. Grimes 			debug++;
1199b50d902SRodney W. Grimes 			break;
120c92dfc23SMike Heffner 		case 'e':
121c92dfc23SMike Heffner 			/*
122c92dfc23SMike Heffner 			 * User wants to check mail and exit.
123c92dfc23SMike Heffner 			 */
124c92dfc23SMike Heffner 			assign("checkmode", "");
125c92dfc23SMike Heffner 			break;
126c92dfc23SMike Heffner 		case 'H':
127c92dfc23SMike Heffner 			/*
128c92dfc23SMike Heffner 			 * User wants a header summary only.
129c92dfc23SMike Heffner 			 */
130c92dfc23SMike Heffner 			assign("headersummary", "");
131c92dfc23SMike Heffner 			break;
132c92dfc23SMike Heffner 		case 'F':
133c92dfc23SMike Heffner 			/*
134c92dfc23SMike Heffner 			 * User wants to record messages to files
135c92dfc23SMike Heffner 			 * named after first recipient username.
136c92dfc23SMike Heffner 			 */
137c92dfc23SMike Heffner 			assign("recordrecip", "");
138c92dfc23SMike Heffner 			break;
1399b50d902SRodney W. Grimes 		case 's':
1409b50d902SRodney W. Grimes 			/*
1419b50d902SRodney W. Grimes 			 * Give a subject field for sending from
1429b50d902SRodney W. Grimes 			 * non terminal
1439b50d902SRodney W. Grimes 			 */
1449b50d902SRodney W. Grimes 			subject = optarg;
1459b50d902SRodney W. Grimes 			break;
1469b50d902SRodney W. Grimes 		case 'f':
1479b50d902SRodney W. Grimes 			/*
1489b50d902SRodney W. Grimes 			 * User is specifying file to "edit" with Mail,
1499b50d902SRodney W. Grimes 			 * as opposed to reading system mailbox.
1509b50d902SRodney W. Grimes 			 * If no argument is given after -f, we read his
1519b50d902SRodney W. Grimes 			 * mbox file.
1529b50d902SRodney W. Grimes 			 *
1539b50d902SRodney W. Grimes 			 * getopt() can't handle optional arguments, so here
1549b50d902SRodney W. Grimes 			 * is an ugly hack to get around it.
1559b50d902SRodney W. Grimes 			 */
1569ce73e90SMike Heffner 			if ((argv[optind] != NULL) && (argv[optind][0] != '-'))
1579b50d902SRodney W. Grimes 				ef = argv[optind++];
1589b50d902SRodney W. Grimes 			else
1599b50d902SRodney W. Grimes 				ef = "&";
1609b50d902SRodney W. Grimes 			break;
1619b50d902SRodney W. Grimes 		case 'n':
1629b50d902SRodney W. Grimes 			/*
1639b50d902SRodney W. Grimes 			 * User doesn't want to source /usr/lib/Mail.rc
1649b50d902SRodney W. Grimes 			 */
1659b50d902SRodney W. Grimes 			nosrc++;
1669b50d902SRodney W. Grimes 			break;
1679b50d902SRodney W. Grimes 		case 'N':
1689b50d902SRodney W. Grimes 			/*
1699b50d902SRodney W. Grimes 			 * Avoid initial header printing.
1709b50d902SRodney W. Grimes 			 */
1719b50d902SRodney W. Grimes 			assign("noheader", "");
1729b50d902SRodney W. Grimes 			break;
1739b50d902SRodney W. Grimes 		case 'v':
1749b50d902SRodney W. Grimes 			/*
1759b50d902SRodney W. Grimes 			 * Send mailer verbose flag
1769b50d902SRodney W. Grimes 			 */
1779b50d902SRodney W. Grimes 			assign("verbose", "");
1789b50d902SRodney W. Grimes 			break;
1799b50d902SRodney W. Grimes 		case 'I':
1809b50d902SRodney W. Grimes 			/*
1819b50d902SRodney W. Grimes 			 * We're interactive
1829b50d902SRodney W. Grimes 			 */
1839b50d902SRodney W. Grimes 			assign("interactive", "");
1849b50d902SRodney W. Grimes 			break;
1859b50d902SRodney W. Grimes 		case 'c':
1869b50d902SRodney W. Grimes 			/*
1879b50d902SRodney W. Grimes 			 * Get Carbon Copy Recipient list
1889b50d902SRodney W. Grimes 			 */
1899b50d902SRodney W. Grimes 			cc = cat(cc, nalloc(optarg, GCC));
1909b50d902SRodney W. Grimes 			break;
1919b50d902SRodney W. Grimes 		case 'b':
1929b50d902SRodney W. Grimes 			/*
1939b50d902SRodney W. Grimes 			 * Get Blind Carbon Copy Recipient list
1949b50d902SRodney W. Grimes 			 */
1959b50d902SRodney W. Grimes 			bcc = cat(bcc, nalloc(optarg, GBCC));
1969b50d902SRodney W. Grimes 			break;
197dcd24e27SMike Heffner 		case 'E':
198dcd24e27SMike Heffner 			/*
199dcd24e27SMike Heffner 			 * Don't send empty files.
200dcd24e27SMike Heffner 			 */
201dcd24e27SMike Heffner 			assign("dontsendempty", "");
202dcd24e27SMike Heffner 			break;
2039b50d902SRodney W. Grimes 		case '?':
2040c3a8314SMike Heffner 			fprintf(stderr, "\
205e53e5e56SYaroslav Tykhiy Usage: %s [-dEiInv] [-s subject] [-c cc-addr] [-b bcc-addr] [-F] to-addr ...\n\
206e53e5e56SYaroslav Tykhiy        %*s [-sendmail-option ...]\n\
207e53e5e56SYaroslav Tykhiy        %s [-dEHiInNv] [-F] -f [name]\n\
208e53e5e56SYaroslav Tykhiy        %s [-dEHiInNv] [-F] [-u user]\n\
209081aa516SDimitry Andric        %s [-d] -e [-f name]\n", __progname, (int)strlen(__progname), "",
210e53e5e56SYaroslav Tykhiy 				__progname, __progname, __progname);
2119b50d902SRodney W. Grimes 			exit(1);
2129b50d902SRodney W. Grimes 		}
2139b50d902SRodney W. Grimes 	}
2149ce73e90SMike Heffner 	for (i = optind; (argv[i] != NULL) && (*argv[i] != '-'); i++)
2159b50d902SRodney W. Grimes 		to = cat(to, nalloc(argv[i], GTO));
2169ce73e90SMike Heffner 	for (; argv[i] != NULL; i++)
2179b50d902SRodney W. Grimes 		smopts = cat(smopts, nalloc(argv[i], 0));
2189b50d902SRodney W. Grimes 	/*
2199b50d902SRodney W. Grimes 	 * Check for inconsistent arguments.
2209b50d902SRodney W. Grimes 	 */
2219ce73e90SMike Heffner 	if (to == NULL && (subject != NULL || cc != NULL || bcc != NULL))
2220c3a8314SMike Heffner 		errx(1, "You must specify direct recipients with -s, -c, or -b.");
2239ce73e90SMike Heffner 	if (ef != NULL && to != NULL)
2240c3a8314SMike Heffner 		errx(1, "Cannot give -f and people to send to.");
2259b50d902SRodney W. Grimes 	tinit();
2269b50d902SRodney W. Grimes 	setscreensize();
2279b50d902SRodney W. Grimes 	input = stdin;
2289b50d902SRodney W. Grimes 	rcvmode = !to;
2299b50d902SRodney W. Grimes 	spreserve();
230e9b074c3SJordan K. Hubbard 	if (!nosrc) {
231e9b074c3SJordan K. Hubbard 		char *s, *path_rc;
232e9b074c3SJordan K. Hubbard 
2330c3a8314SMike Heffner 		if ((path_rc = malloc(sizeof(_PATH_MASTER_RC))) == NULL)
2340c3a8314SMike Heffner 			err(1, "malloc(path_rc) failed");
235e9b074c3SJordan K. Hubbard 
236e9b074c3SJordan K. Hubbard 		strcpy(path_rc, _PATH_MASTER_RC);
237e9b074c3SJordan K. Hubbard 		while ((s = strsep(&path_rc, ":")) != NULL)
238e9b074c3SJordan K. Hubbard 			if (*s != '\0')
239e9b074c3SJordan K. Hubbard 				load(s);
240e9b074c3SJordan K. Hubbard 	}
2419b50d902SRodney W. Grimes 	/*
2429b50d902SRodney W. Grimes 	 * Expand returns a savestr, but load only uses the file name
2439b50d902SRodney W. Grimes 	 * for fopen, so it's safe to do this.
2449b50d902SRodney W. Grimes 	 */
245856f23edSMike Heffner 	if ((rc = getenv("MAILRC")) == NULL)
246856f23edSMike Heffner 		rc = "~/.mailrc";
247856f23edSMike Heffner 	load(expand(rc));
24859c3f4f7SMike Heffner 
24959c3f4f7SMike Heffner 	replyto = value("REPLYTO");
2509b50d902SRodney W. Grimes 	if (!rcvmode) {
25199bd6601SJoerg Wunsch 		mail(to, cc, bcc, smopts, subject, replyto);
2529b50d902SRodney W. Grimes 		/*
2539b50d902SRodney W. Grimes 		 * why wait?
2549b50d902SRodney W. Grimes 		 */
2559b50d902SRodney W. Grimes 		exit(senderr);
2569b50d902SRodney W. Grimes 	}
257c92dfc23SMike Heffner 
258c92dfc23SMike Heffner 	if(value("checkmode") != NULL) {
259c92dfc23SMike Heffner 		if (ef == NULL)
260c92dfc23SMike Heffner 			ef = "%";
261c92dfc23SMike Heffner 		if (setfile(ef) <= 0)
262*389ae6c6SUlrich Spörlein 			/* Either an error has occurred, or no mail */
263c92dfc23SMike Heffner 			exit(1);
264c92dfc23SMike Heffner 		else
265c92dfc23SMike Heffner 			exit(0);
266c92dfc23SMike Heffner 		/* NOTREACHED */
267c92dfc23SMike Heffner 	}
268c92dfc23SMike Heffner 
2699b50d902SRodney W. Grimes 	/*
2709b50d902SRodney W. Grimes 	 * Ok, we are reading mail.
2719b50d902SRodney W. Grimes 	 * Decide whether we are editing a mailbox or reading
2729b50d902SRodney W. Grimes 	 * the system mailbox, and open up the right stuff.
2739b50d902SRodney W. Grimes 	 */
2749ce73e90SMike Heffner 	if (ef == NULL)
2759b50d902SRodney W. Grimes 		ef = "%";
2769b50d902SRodney W. Grimes 	if (setfile(ef) < 0)
2779b50d902SRodney W. Grimes 		exit(1);		/* error already reported */
2789b50d902SRodney W. Grimes 	if (setjmp(hdrjmp) == 0) {
2799b50d902SRodney W. Grimes 		if ((prevint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
2809ce73e90SMike Heffner 			(void)signal(SIGINT, hdrstop);
2819ce73e90SMike Heffner 		if (value("quiet") == NULL)
2829b50d902SRodney W. Grimes 			printf("Mail version %s.  Type ? for help.\n",
2839b50d902SRodney W. Grimes 				version);
2849b50d902SRodney W. Grimes 		announce();
2859ce73e90SMike Heffner 		(void)fflush(stdout);
2869ce73e90SMike Heffner 		(void)signal(SIGINT, prevint);
2879b50d902SRodney W. Grimes 	}
288c92dfc23SMike Heffner 
289c92dfc23SMike Heffner 	/* If we were in header summary mode, it's time to exit. */
290c92dfc23SMike Heffner 	if (value("headersummary") != NULL)
291c92dfc23SMike Heffner 		exit(0);
292c92dfc23SMike Heffner 
2939b50d902SRodney W. Grimes 	commands();
2949ce73e90SMike Heffner 	(void)signal(SIGHUP, SIG_IGN);
2959ce73e90SMike Heffner 	(void)signal(SIGINT, SIG_IGN);
2969ce73e90SMike Heffner 	(void)signal(SIGQUIT, SIG_IGN);
2979b50d902SRodney W. Grimes 	quit();
2989b50d902SRodney W. Grimes 	exit(0);
2999b50d902SRodney W. Grimes }
3009b50d902SRodney W. Grimes 
3019b50d902SRodney W. Grimes /*
3029b50d902SRodney W. Grimes  * Interrupt printing of the headers.
3039b50d902SRodney W. Grimes  */
3049ce73e90SMike Heffner /*ARGSUSED*/
3059b50d902SRodney W. Grimes void
3066d8484b0SPhilippe Charnier hdrstop(int signo __unused)
3079b50d902SRodney W. Grimes {
3089b50d902SRodney W. Grimes 
3099ce73e90SMike Heffner 	(void)fflush(stdout);
3109b50d902SRodney W. Grimes 	fprintf(stderr, "\nInterrupt\n");
3119b50d902SRodney W. Grimes 	longjmp(hdrjmp, 1);
3129b50d902SRodney W. Grimes }
3139b50d902SRodney W. Grimes 
3149b50d902SRodney W. Grimes /*
3159b50d902SRodney W. Grimes  * Compute what the screen size for printing headers should be.
3169b50d902SRodney W. Grimes  * We use the following algorithm for the height:
3179b50d902SRodney W. Grimes  *	If baud rate < 1200, use  9
3189b50d902SRodney W. Grimes  *	If baud rate = 1200, use 14
3199b50d902SRodney W. Grimes  *	If baud rate > 1200, use 24 or ws_row
3209b50d902SRodney W. Grimes  * Width is either 80 or ws_col;
3219b50d902SRodney W. Grimes  */
3229b50d902SRodney W. Grimes void
3236d8484b0SPhilippe Charnier setscreensize(void)
3249b50d902SRodney W. Grimes {
325856f23edSMike Heffner 	struct termios tbuf;
3269b50d902SRodney W. Grimes 	struct winsize ws;
327856f23edSMike Heffner 	speed_t speed;
3289b50d902SRodney W. Grimes 
3299b50d902SRodney W. Grimes 	if (ioctl(1, TIOCGWINSZ, (char *)&ws) < 0)
3309b50d902SRodney W. Grimes 		ws.ws_col = ws.ws_row = 0;
331856f23edSMike Heffner 	if (tcgetattr(1, &tbuf) < 0)
3327c6d202aSPeter Wemm 		speed = B9600;
333856f23edSMike Heffner 	else
334856f23edSMike Heffner 		speed = cfgetospeed(&tbuf);
3357c6d202aSPeter Wemm 	if (speed < B1200)
3369b50d902SRodney W. Grimes 		screenheight = 9;
3377c6d202aSPeter Wemm 	else if (speed == B1200)
3389b50d902SRodney W. Grimes 		screenheight = 14;
3399b50d902SRodney W. Grimes 	else if (ws.ws_row != 0)
3409b50d902SRodney W. Grimes 		screenheight = ws.ws_row;
3419b50d902SRodney W. Grimes 	else
3429b50d902SRodney W. Grimes 		screenheight = 24;
3439b50d902SRodney W. Grimes 	if ((realscreenheight = ws.ws_row) == 0)
3449b50d902SRodney W. Grimes 		realscreenheight = 24;
3459b50d902SRodney W. Grimes 	if ((screenwidth = ws.ws_col) == 0)
3469b50d902SRodney W. Grimes 		screenwidth = 80;
3479b50d902SRodney W. Grimes }
348