xref: /netbsd-src/usr.bin/mail/main.c (revision d449716afd45eef6b809a8deb59493f03b8bf0b5)
1*d449716aSchristos /*	$NetBSD: main.c,v 1.31 2010/01/12 14:45:31 christos Exp $	*/
288b833a7Schristos 
361f28255Scgd /*
42cb5542fSderaadt  * Copyright (c) 1980, 1993
52cb5542fSderaadt  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * Redistribution and use in source and binary forms, with or without
861f28255Scgd  * modification, are permitted provided that the following conditions
961f28255Scgd  * are met:
1061f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1261f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1461f28255Scgd  *    documentation and/or other materials provided with the distribution.
1589aaa1bbSagc  * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd  *    may be used to endorse or promote products derived from this software
1761f28255Scgd  *    without specific prior written permission.
1861f28255Scgd  *
1961f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd  * SUCH DAMAGE.
3061f28255Scgd  */
3161f28255Scgd 
327c81c8f3Slukem #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
3498e5374cSlukem __COPYRIGHT("@(#) Copyright (c) 1980, 1993\
3598e5374cSlukem  The Regents of the University of California.  All rights reserved.");
3661f28255Scgd #endif /* not lint */
3761f28255Scgd 
3861f28255Scgd #ifndef lint
3988b833a7Schristos #if 0
4019d35cbcStls static char sccsid[] = "@(#)main.c	8.2 (Berkeley) 4/20/95";
4188b833a7Schristos #else
42*d449716aSchristos __RCSID("$NetBSD: main.c,v 1.31 2010/01/12 14:45:31 christos Exp $");
4388b833a7Schristos #endif
4461f28255Scgd #endif /* not lint */
4561f28255Scgd 
4655ce51b2Swsanchez #define EXTERN
4761f28255Scgd #include "rcv.h"
4855ce51b2Swsanchez #undef EXTERN
49798fbc60Schristos #include <assert.h>
508207b28aSchristos #include <util.h>
5155ce51b2Swsanchez 
522cb5542fSderaadt #include "extern.h"
53ca13337dSchristos #include "sig.h"
5461f28255Scgd 
558207b28aSchristos #ifdef USE_EDITLINE
5685c81c58Schristos #include "complete.h"
5785c81c58Schristos #endif
58798fbc60Schristos #include "format.h"
598207b28aSchristos #ifdef MIME_SUPPORT
608207b28aSchristos #include "mime.h"
618207b28aSchristos #endif
62f3098750Schristos #ifdef THREAD_SUPPORT
63f3098750Schristos #include "thread.h"
64f3098750Schristos #endif
657c81c8f3Slukem 
6661f28255Scgd /*
6761f28255Scgd  * Mail -- a mail program
6861f28255Scgd  *
6961f28255Scgd  * Startup -- interface with user.
7061f28255Scgd  */
7161f28255Scgd 
72ca13337dSchristos __dead
73f3098750Schristos static void
usage(void)74ca13337dSchristos usage(void)
75f3098750Schristos {
76ca13337dSchristos #ifdef MIME_SUPPORT
77ca13337dSchristos 	(void)fputs("\
78ca13337dSchristos Usage: mail [-EiInv] [-r rcfile] [-s subject] [-a file] [-c cc-addr]\n\
79ca13337dSchristos             [-b bcc-addr] to-addr ... [- sendmail-options ...]\n\
80ca13337dSchristos        mail [-EiInNv] [-H[colon-modifier]] -f [name]\n\
81ca13337dSchristos        mail [-EiInNv] [-H[colon-modifier]] [-u user]\n",
82ca13337dSchristos 				stderr);
83ca13337dSchristos #else /* MIME_SUPPORT */
84ca13337dSchristos 	(void)fputs("\
85ca13337dSchristos Usage: mail [-EiInv] [-r rcfile] [-s subject] [-c cc-addr] [-b bcc-addr]\n\
86ca13337dSchristos             to-addr ... [- sendmail-options ...]\n\
87ca13337dSchristos        mail [-EiInNv] [-H[colon-modifier]] -f [name]\n\
88ca13337dSchristos        mail [-EiInNv] [-H[colon-modifier]] [-u user]\n",
89ca13337dSchristos 				stderr);
90ca13337dSchristos #endif /* MIME_SUPPORT */
91ca13337dSchristos 	exit(1);
92f3098750Schristos }
93f3098750Schristos 
94f3098750Schristos /*
95f3098750Schristos  * Compute what the screen size for printing headers should be.
96f3098750Schristos  * We use the following algorithm for the height:
97f3098750Schristos  *	If baud rate < 1200, use  9
98f3098750Schristos  *	If baud rate = 1200, use 14
99f3098750Schristos  *	If baud rate > 1200, use 24 or ws_row
100f3098750Schristos  * Width is either 80 or ws_col;
101f3098750Schristos  */
102f3098750Schristos PUBLIC void
setscreensize(void)103f3098750Schristos setscreensize(void)
104f3098750Schristos {
105f3098750Schristos 	struct termios tbuf;
106f3098750Schristos 	struct winsize ws;
107f3098750Schristos 	speed_t ospeed;
108f3098750Schristos 	char *cp;
109f3098750Schristos 
110f3098750Schristos 	if (ioctl(1, TIOCGWINSZ, &ws) < 0)
111f3098750Schristos 		ws.ws_col = ws.ws_row = 0;
112f3098750Schristos 	if (tcgetattr(1, &tbuf) < 0)
113f3098750Schristos 		ospeed = 9600;
114f3098750Schristos 	else
115f3098750Schristos 		ospeed = cfgetospeed(&tbuf);
116f3098750Schristos 	if (ospeed < 1200)
117f3098750Schristos 		screenheight = 9;
118f3098750Schristos 	else if (ospeed == 1200)
119f3098750Schristos 		screenheight = 14;
120f3098750Schristos 	else if (ws.ws_row != 0)
121f3098750Schristos 		screenheight = ws.ws_row;
122f3098750Schristos 	else
123f3098750Schristos 		screenheight = 24;
124f3098750Schristos 	if ((realscreenheight = ws.ws_row) == 0)
125f3098750Schristos 		realscreenheight = 24;
126f3098750Schristos 	if ((screenwidth = ws.ws_col) == 0)
127f3098750Schristos 		screenwidth = 80;
128f3098750Schristos 	/*
129f3098750Schristos 	 * Possible overrides from the rcfile.
130f3098750Schristos 	 */
131f3098750Schristos 	if ((cp = value(ENAME_SCREENWIDTH)) != NULL) {
132f3098750Schristos 		int width;
133f3098750Schristos 		width = *cp ? atoi(cp) : 0;
134f3098750Schristos 		if (width >= 0)
135f3098750Schristos 			screenwidth = width;
136f3098750Schristos 	}
137f3098750Schristos 	if ((cp = value(ENAME_SCREENHEIGHT)) != NULL) {
138f3098750Schristos 		int height;
139f3098750Schristos 		height = *cp ? atoi(cp) : 0;
140f3098750Schristos 		if (height >= 0) {
141f3098750Schristos 			realscreenheight = height;
142f3098750Schristos 			screenheight = height;
143f3098750Schristos 		}
144f3098750Schristos 	}
145f3098750Schristos }
14685c81c58Schristos 
14785c81c58Schristos /*
14885c81c58Schristos  * Break up a white-space or comma delimited name list so that aliases
14985c81c58Schristos  * can get expanded.  Without this, the CC: or BCC: list is broken too
15085c81c58Schristos  * late for alias expansion to occur.
15185c81c58Schristos  */
152f3098750Schristos PUBLIC struct name *
lexpand(char * str,int ntype)15385c81c58Schristos lexpand(char *str, int ntype)
15485c81c58Schristos {
15585c81c58Schristos 	char *list;
15685c81c58Schristos 	struct name *np = NULL;
15785c81c58Schristos 	char *word, *p;
15885c81c58Schristos 
1598207b28aSchristos 	list = estrdup(str);
16085c81c58Schristos 	word = list;
16185c81c58Schristos 	for (word = list; *word; word = p) {
162d727506fSchristos 		word = skip_WSP(word);
16385c81c58Schristos 		for (p = word;
164d727506fSchristos 		     *p && !is_WSP(*p) && *p != ',';
16585c81c58Schristos 		     p++)
16685c81c58Schristos 			continue;
16785c81c58Schristos 		if (*p)
16885c81c58Schristos 			*p++ = '\0';
16985c81c58Schristos 		np = cat(np, nalloc(word, ntype));
17085c81c58Schristos 	}
17185c81c58Schristos 
17285c81c58Schristos 	free(list);
17385c81c58Schristos 	return np;
17485c81c58Schristos }
17585c81c58Schristos 
176f3098750Schristos PUBLIC int
main(int argc,char * argv[])177b127ccccSwiz main(int argc, char *argv[])
17861f28255Scgd {
179ca13337dSchristos 	jmp_buf jmpbuf;
180ca13337dSchristos 	struct sigaction sa;
18161f28255Scgd 	struct name *to, *cc, *bcc, *smopts;
1828207b28aSchristos #ifdef MIME_SUPPORT
183798fbc60Schristos 	struct name *attach_optargs;
184798fbc60Schristos 	struct name *attach_end;
1858207b28aSchristos #endif
18661f28255Scgd 	char *subject;
187ece0fd5cSchristos 	const char *ef;
18861f28255Scgd 	char nosrc = 0;
189ece0fd5cSchristos 	const char *rc;
190ca13337dSchristos 	int Hflag;
191ca13337dSchristos 	int i;
19261f28255Scgd 
19361f28255Scgd 	/*
194c5d61cf8Schristos 	 * For portability, call setprogname() early, before
195c5d61cf8Schristos 	 * getprogname() is called.
196c5d61cf8Schristos 	 */
197c5d61cf8Schristos 	(void)setprogname(argv[0]);
198c5d61cf8Schristos 
199c5d61cf8Schristos 	/*
20061f28255Scgd 	 * Set up a reasonable environment.
20161f28255Scgd 	 * Figure out whether we are being run interactively,
20261f28255Scgd 	 * start the SIGCHLD catcher, and so forth.
203ca13337dSchristos 	 * (Other signals are setup later by sig_setup().)
20461f28255Scgd 	 */
205ca13337dSchristos 	(void)sigemptyset(&sa.sa_mask);
206ca13337dSchristos 	sa.sa_flags = SA_RESTART;
207ca13337dSchristos 	sa.sa_handler = sigchild;
208ca13337dSchristos 	(void)sigaction(SIGCHLD, &sa, NULL);
209ca13337dSchristos 
21061f28255Scgd 	if (isatty(0))
211f3098750Schristos 		assign(ENAME_INTERACTIVE, "");
21261f28255Scgd 	image = -1;
213ca13337dSchristos 
21461f28255Scgd 	/*
21561f28255Scgd 	 * Now, determine how we are being used.
21661f28255Scgd 	 * We successively pick off - flags.
21761f28255Scgd 	 * If there is anything left, it is the base of the list
21861f28255Scgd 	 * of users to mail to.  Argp will be set to point to the
21961f28255Scgd 	 * first of these users.
22061f28255Scgd 	 */
221ca13337dSchristos 	rc = NULL;
222ab850155Swiz 	ef = NULL;
223cb6786d4Swiz 	to = NULL;
224cb6786d4Swiz 	cc = NULL;
225cb6786d4Swiz 	bcc = NULL;
226cb6786d4Swiz 	smopts = NULL;
227ab850155Swiz 	subject = NULL;
228798fbc60Schristos 	Hflag = 0;
2298207b28aSchristos #ifdef MIME_SUPPORT
230798fbc60Schristos 	attach_optargs = NULL;
231798fbc60Schristos 	attach_end = NULL;
232ca13337dSchristos 	while ((i = getopt(argc, argv, ":~EH:INT:a:b:c:dfinr:s:u:v")) != -1)
2338207b28aSchristos #else
234ca13337dSchristos 	while ((i = getopt(argc, argv, ":~EH:INT:b:c:dfinr:s:u:v")) != -1)
2358207b28aSchristos #endif
23685c81c58Schristos 	{
23761f28255Scgd 		switch (i) {
23861f28255Scgd 		case 'T':
23961f28255Scgd 			/*
24061f28255Scgd 			 * Next argument is temp file to write which
24161f28255Scgd 			 * articles have been read/deleted for netnews.
24261f28255Scgd 			 */
24361f28255Scgd 			Tflag = optarg;
24461f28255Scgd 			if ((i = creat(Tflag, 0600)) < 0) {
245ae38aa87Swiz 				warn("%s", Tflag);
24661f28255Scgd 				exit(1);
24761f28255Scgd 			}
248ca286310Schristos 			(void)close(i);
24961f28255Scgd 			break;
2508207b28aSchristos #ifdef MIME_SUPPORT
251798fbc60Schristos 		case 'a': {
252798fbc60Schristos 			struct name *np;
253798fbc60Schristos 			np = nalloc(optarg, 0);
254798fbc60Schristos 			if (attach_end == NULL)
255798fbc60Schristos 				attach_optargs = np;
256798fbc60Schristos 			else {
257798fbc60Schristos 				np->n_blink = attach_end;
258798fbc60Schristos 				attach_end->n_flink = np;
259798fbc60Schristos 			}
260798fbc60Schristos 			attach_end = np;
2618207b28aSchristos 			break;
262798fbc60Schristos 		}
2638207b28aSchristos #endif
26461f28255Scgd 		case 'u':
26561f28255Scgd 			/*
26661f28255Scgd 			 * Next argument is person to pretend to be.
26761f28255Scgd 			 */
26861f28255Scgd 			myname = optarg;
269ca286310Schristos 			(void)unsetenv("MAIL");
27061f28255Scgd 			break;
27161f28255Scgd 		case 'i':
27261f28255Scgd 			/*
27361f28255Scgd 			 * User wants to ignore interrupts.
27461f28255Scgd 			 * Set the variable "ignore"
27561f28255Scgd 			 */
276f3098750Schristos 			assign(ENAME_IGNORE, "");
27761f28255Scgd 			break;
27861f28255Scgd 		case 'd':
27961f28255Scgd 			debug++;
28061f28255Scgd 			break;
281ca13337dSchristos 		case 'r':
282ca13337dSchristos 			rc = optarg;
283ca13337dSchristos 			break;
28461f28255Scgd 		case 's':
28561f28255Scgd 			/*
28661f28255Scgd 			 * Give a subject field for sending from
28761f28255Scgd 			 * non terminal
28861f28255Scgd 			 */
28961f28255Scgd 			subject = optarg;
29061f28255Scgd 			break;
29161f28255Scgd 		case 'f':
29261f28255Scgd 			/*
29361f28255Scgd 			 * User is specifying file to "edit" with Mail,
29461f28255Scgd 			 * as opposed to reading system mailbox.
29561f28255Scgd 			 * If no argument is given after -f, we read his
29661f28255Scgd 			 * mbox file.
29761f28255Scgd 			 *
29861f28255Scgd 			 * getopt() can't handle optional arguments, so here
29961f28255Scgd 			 * is an ugly hack to get around it.
30061f28255Scgd 			 */
30161f28255Scgd 			if ((argv[optind]) && (argv[optind][0] != '-'))
30261f28255Scgd 				ef = argv[optind++];
30361f28255Scgd 			else
30461f28255Scgd 				ef = "&";
30561f28255Scgd 			break;
306798fbc60Schristos 		case 'H':
307798fbc60Schristos 			/*
308798fbc60Schristos 			 * Print out the headers and quit.
309798fbc60Schristos 			 */
310798fbc60Schristos 			Hflag = get_Hflag(argv);
311798fbc60Schristos 			break;
31261f28255Scgd 		case 'n':
31361f28255Scgd 			/*
31461f28255Scgd 			 * User doesn't want to source /usr/lib/Mail.rc
31561f28255Scgd 			 */
31661f28255Scgd 			nosrc++;
31761f28255Scgd 			break;
31861f28255Scgd 		case 'N':
31961f28255Scgd 			/*
32061f28255Scgd 			 * Avoid initial header printing.
32161f28255Scgd 			 */
322f3098750Schristos 			assign(ENAME_NOHEADER, "");
32361f28255Scgd 			break;
32461f28255Scgd 		case 'v':
32561f28255Scgd 			/*
32661f28255Scgd 			 * Send mailer verbose flag
32761f28255Scgd 			 */
328f3098750Schristos 			assign(ENAME_VERBOSE, "");
32961f28255Scgd 			break;
33061f28255Scgd 		case 'I':
331253750edSchristos 		case '~':
33261f28255Scgd 			/*
33361f28255Scgd 			 * We're interactive
33461f28255Scgd 			 */
335f3098750Schristos 			assign(ENAME_INTERACTIVE, "");
33661f28255Scgd 			break;
33761f28255Scgd 		case 'c':
33861f28255Scgd 			/*
33961f28255Scgd 			 * Get Carbon Copy Recipient list
34061f28255Scgd 			 */
34185c81c58Schristos 			cc = cat(cc, lexpand(optarg, GCC));
34261f28255Scgd 			break;
34361f28255Scgd 		case 'b':
34461f28255Scgd 			/*
34561f28255Scgd 			 * Get Blind Carbon Copy Recipient list
34661f28255Scgd 			 */
34785c81c58Schristos 			bcc = cat(bcc, lexpand(optarg, GBCC));
34885c81c58Schristos 
34985c81c58Schristos 			break;
350253750edSchristos 		case 'E':
351253750edSchristos 			/*
352253750edSchristos 			 * Don't send empty files.
353253750edSchristos 			 */
354f3098750Schristos 			assign(ENAME_DONTSENDEMPTY, "");
355253750edSchristos 			break;
356798fbc60Schristos 		case ':':
357798fbc60Schristos 			/*
358798fbc60Schristos 			 * An optarg was expected but not found.
359798fbc60Schristos 			 */
360798fbc60Schristos 			if (optopt == 'H') {
361798fbc60Schristos 				Hflag = get_Hflag(NULL);
362798fbc60Schristos 				break;
363798fbc60Schristos 			}
364798fbc60Schristos 			(void)fprintf(stderr,
365798fbc60Schristos 			    "%s: option requires an argument -- %c\n",
366798fbc60Schristos 			    getprogname(), optopt);
367798fbc60Schristos 
368798fbc60Schristos 			/* FALLTHROUGH */
36961f28255Scgd 		case '?':
370798fbc60Schristos 			/*
371798fbc60Schristos 			 * An unknown option flag.  We need to do the
372798fbc60Schristos 			 * error message.
373798fbc60Schristos 			 */
374798fbc60Schristos 			if (optopt != '?')
375798fbc60Schristos 				(void)fprintf(stderr,
376798fbc60Schristos 				    "%s: unknown option -- %c\n", getprogname(),
377798fbc60Schristos 				    optopt);
378ca13337dSchristos 			usage();	/* print usage message and die */
379ca13337dSchristos 			/*NOTREACHED*/
38061f28255Scgd 		}
38161f28255Scgd 	}
38261f28255Scgd 	for (i = optind; (argv[i]) && (*argv[i] != '-'); i++)
38361f28255Scgd 		to = cat(to, nalloc(argv[i], GTO));
384d727506fSchristos 	for (/*EMPTY*/; argv[i]; i++)
38585c81c58Schristos 		smopts = cat(smopts, nalloc(argv[i], GSMOPTS));
38661f28255Scgd 	/*
38761f28255Scgd 	 * Check for inconsistent arguments.
38861f28255Scgd 	 */
389ed5c178aSchristos 	if (to == NULL && (subject != NULL || cc != NULL || bcc != NULL))
390*d449716aSchristos 		errx(EXIT_FAILURE, "You must specify direct recipients with -s, -c, or -b.");
391cb6786d4Swiz 	if (ef != NULL && to != NULL) {
392*d449716aSchristos 		errx(EXIT_FAILURE, "Cannot give -f and people to send to.");
39361f28255Scgd 	}
394798fbc60Schristos 	if (Hflag != 0 && to != NULL)
395798fbc60Schristos 		errx(EXIT_FAILURE, "Cannot give -H and people to send to.");
3968207b28aSchristos #ifdef MIME_SUPPORT
397798fbc60Schristos 	if (attach_optargs != NULL && to == NULL)
398798fbc60Schristos 		errx(EXIT_FAILURE, "Cannot give -a without people to send to.");
3998207b28aSchristos #endif
400798fbc60Schristos 	tinit();	/* must be done before loading the rcfile */
40161f28255Scgd 	input = stdin;
402f3098750Schristos 	mailmode = Hflag ? mm_hdrsonly :
403f3098750Schristos 	    to ? mm_sending : mm_receiving;
404f3098750Schristos 
40561f28255Scgd 	spreserve();
40661f28255Scgd 	if (!nosrc)
40761f28255Scgd 		load(_PATH_MASTER_RC);
40861f28255Scgd 	/*
40961f28255Scgd 	 * Expand returns a savestr, but load only uses the file name
41061f28255Scgd 	 * for fopen, so it's safe to do this.
41161f28255Scgd 	 */
412ca13337dSchristos 	if (rc == NULL && (rc = getenv("MAILRC")) == NULL)
41319d35cbcStls 		rc = "~/.mailrc";
41419d35cbcStls 	load(expand(rc));
415f3098750Schristos 	setscreensize();	/* do this after loading the rcfile */
41685c81c58Schristos 
4178207b28aSchristos #ifdef USE_EDITLINE
418b01c8fbcSchristos 	/*
419b01c8fbcSchristos 	 * This is after loading the MAILRC so we can use value().
420b01c8fbcSchristos 	 * Avoid editline in mm_hdrsonly mode or pipelines will screw
421b01c8fbcSchristos 	 * up.  XXX - there must be a better way!
422b01c8fbcSchristos 	 */
423b01c8fbcSchristos 	if (mailmode != mm_hdrsonly)
4248207b28aSchristos 		init_editline();
42585c81c58Schristos #endif
42685c81c58Schristos 
427ca13337dSchristos 	sig_setup();
428ca13337dSchristos 
429f3098750Schristos 	switch (mailmode) {
430f3098750Schristos 	case mm_sending:
431f3098750Schristos 		(void)mail(to, cc, bcc, smopts, subject,
432f3098750Schristos 		    mime_attach_optargs(attach_optargs));
43361f28255Scgd 		/*
43461f28255Scgd 		 * why wait?
43561f28255Scgd 		 */
43661f28255Scgd 		exit(senderr);
437f3098750Schristos 		break;	/* XXX - keep lint happy */
438f3098750Schristos 
439f3098750Schristos 	case mm_receiving:
440f3098750Schristos 	case mm_hdrsonly:
44161f28255Scgd 		/*
44261f28255Scgd 		 * Ok, we are reading mail.
44361f28255Scgd 		 * Decide whether we are editing a mailbox or reading
44461f28255Scgd 		 * the system mailbox, and open up the right stuff.
44561f28255Scgd 		 */
446ab850155Swiz 		if (ef == NULL)
44761f28255Scgd 			ef = "%";
44861f28255Scgd 		if (setfile(ef) < 0)
44961f28255Scgd 			exit(1);		/* error already reported */
450f3098750Schristos 		if (value(ENAME_QUIET) == NULL)
451ca286310Schristos 			(void)printf("Mail version %s.  Type ? for help.\n",
45261f28255Scgd 			    version);
453f3098750Schristos 		if (mailmode == mm_hdrsonly)
454f3098750Schristos 			show_headers_and_exit(Hflag);	/* NORETURN */
45561f28255Scgd 		announce();
456ca286310Schristos 		(void)fflush(stdout);
457ca13337dSchristos 
458ca13337dSchristos 		if (setjmp(jmpbuf) != 0) {
459ca13337dSchristos 			/* Return here if quit() fails below. */
460ca13337dSchristos 			(void)printf("Use 'exit' to quit without saving changes.\n");
46161f28255Scgd 		}
46261f28255Scgd 		commands();
463ca13337dSchristos 
464ca13337dSchristos 		/* Ignore these signals from now on! */
465ca286310Schristos 		(void)signal(SIGHUP, SIG_IGN);
466ca286310Schristos 		(void)signal(SIGINT, SIG_IGN);
467ca286310Schristos 		(void)signal(SIGQUIT, SIG_IGN);
468ca13337dSchristos 		quit(jmpbuf);
469f3098750Schristos 		break;
470f3098750Schristos 
471f3098750Schristos 	default:
472f3098750Schristos 		assert(/*CONSTCOND*/0);
473f3098750Schristos 		break;
474f3098750Schristos 	}
475f3098750Schristos 
476ca286310Schristos 	return 0;
47761f28255Scgd }
478