Home | History | Annotate | Line # | Download | only in mail
main.c revision 1.30
      1  1.30  christos /*	$NetBSD: main.c,v 1.30 2009/04/10 13:08:25 christos Exp $	*/
      2   1.5  christos 
      3   1.1       cgd /*
      4   1.3   deraadt  * Copyright (c) 1980, 1993
      5   1.3   deraadt  *	The Regents of the University of California.  All rights reserved.
      6   1.1       cgd  *
      7   1.1       cgd  * Redistribution and use in source and binary forms, with or without
      8   1.1       cgd  * modification, are permitted provided that the following conditions
      9   1.1       cgd  * are met:
     10   1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     11   1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     12   1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     14   1.1       cgd  *    documentation and/or other materials provided with the distribution.
     15  1.18       agc  * 3. Neither the name of the University nor the names of its contributors
     16   1.1       cgd  *    may be used to endorse or promote products derived from this software
     17   1.1       cgd  *    without specific prior written permission.
     18   1.1       cgd  *
     19   1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20   1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21   1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22   1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23   1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24   1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25   1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26   1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27   1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28   1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29   1.1       cgd  * SUCH DAMAGE.
     30   1.1       cgd  */
     31   1.1       cgd 
     32   1.8     lukem #include <sys/cdefs.h>
     33   1.1       cgd #ifndef lint
     34  1.29     lukem __COPYRIGHT("@(#) Copyright (c) 1980, 1993\
     35  1.29     lukem  The Regents of the University of California.  All rights reserved.");
     36   1.1       cgd #endif /* not lint */
     37   1.1       cgd 
     38   1.1       cgd #ifndef lint
     39   1.5  christos #if 0
     40   1.6       tls static char sccsid[] = "@(#)main.c	8.2 (Berkeley) 4/20/95";
     41   1.5  christos #else
     42  1.30  christos __RCSID("$NetBSD: main.c,v 1.30 2009/04/10 13:08:25 christos Exp $");
     43   1.5  christos #endif
     44   1.1       cgd #endif /* not lint */
     45   1.1       cgd 
     46   1.9  wsanchez #define EXTERN
     47   1.1       cgd #include "rcv.h"
     48   1.9  wsanchez #undef EXTERN
     49  1.24  christos #include <assert.h>
     50  1.23  christos #include <util.h>
     51   1.9  wsanchez 
     52   1.3   deraadt #include "extern.h"
     53  1.30  christos #include "sig.h"
     54   1.1       cgd 
     55  1.23  christos #ifdef USE_EDITLINE
     56  1.22  christos #include "complete.h"
     57  1.22  christos #endif
     58  1.24  christos #include "format.h"
     59  1.23  christos #ifdef MIME_SUPPORT
     60  1.23  christos #include "mime.h"
     61  1.23  christos #endif
     62  1.25  christos #ifdef THREAD_SUPPORT
     63  1.25  christos #include "thread.h"
     64  1.25  christos #endif
     65   1.8     lukem 
     66   1.1       cgd /*
     67   1.1       cgd  * Mail -- a mail program
     68   1.1       cgd  *
     69   1.1       cgd  * Startup -- interface with user.
     70   1.1       cgd  */
     71   1.1       cgd 
     72  1.30  christos __dead
     73  1.25  christos static void
     74  1.30  christos usage(void)
     75  1.25  christos {
     76  1.30  christos #ifdef MIME_SUPPORT
     77  1.30  christos 	(void)fputs("\
     78  1.30  christos Usage: mail [-EiInv] [-r rcfile] [-s subject] [-a file] [-c cc-addr]\n\
     79  1.30  christos             [-b bcc-addr] to-addr ... [- sendmail-options ...]\n\
     80  1.30  christos        mail [-EiInNv] [-H[colon-modifier]] -f [name]\n\
     81  1.30  christos        mail [-EiInNv] [-H[colon-modifier]] [-u user]\n",
     82  1.30  christos 				stderr);
     83  1.30  christos #else /* MIME_SUPPORT */
     84  1.30  christos 	(void)fputs("\
     85  1.30  christos Usage: mail [-EiInv] [-r rcfile] [-s subject] [-c cc-addr] [-b bcc-addr]\n\
     86  1.30  christos             to-addr ... [- sendmail-options ...]\n\
     87  1.30  christos        mail [-EiInNv] [-H[colon-modifier]] -f [name]\n\
     88  1.30  christos        mail [-EiInNv] [-H[colon-modifier]] [-u user]\n",
     89  1.30  christos 				stderr);
     90  1.30  christos #endif /* MIME_SUPPORT */
     91  1.30  christos 	exit(1);
     92  1.25  christos }
     93  1.25  christos 
     94  1.25  christos /*
     95  1.25  christos  * Compute what the screen size for printing headers should be.
     96  1.25  christos  * We use the following algorithm for the height:
     97  1.25  christos  *	If baud rate < 1200, use  9
     98  1.25  christos  *	If baud rate = 1200, use 14
     99  1.25  christos  *	If baud rate > 1200, use 24 or ws_row
    100  1.25  christos  * Width is either 80 or ws_col;
    101  1.25  christos  */
    102  1.25  christos PUBLIC void
    103  1.25  christos setscreensize(void)
    104  1.25  christos {
    105  1.25  christos 	struct termios tbuf;
    106  1.25  christos 	struct winsize ws;
    107  1.25  christos 	speed_t ospeed;
    108  1.25  christos 	char *cp;
    109  1.25  christos 
    110  1.25  christos 	if (ioctl(1, TIOCGWINSZ, &ws) < 0)
    111  1.25  christos 		ws.ws_col = ws.ws_row = 0;
    112  1.25  christos 	if (tcgetattr(1, &tbuf) < 0)
    113  1.25  christos 		ospeed = 9600;
    114  1.25  christos 	else
    115  1.25  christos 		ospeed = cfgetospeed(&tbuf);
    116  1.25  christos 	if (ospeed < 1200)
    117  1.25  christos 		screenheight = 9;
    118  1.25  christos 	else if (ospeed == 1200)
    119  1.25  christos 		screenheight = 14;
    120  1.25  christos 	else if (ws.ws_row != 0)
    121  1.25  christos 		screenheight = ws.ws_row;
    122  1.25  christos 	else
    123  1.25  christos 		screenheight = 24;
    124  1.25  christos 	if ((realscreenheight = ws.ws_row) == 0)
    125  1.25  christos 		realscreenheight = 24;
    126  1.25  christos 	if ((screenwidth = ws.ws_col) == 0)
    127  1.25  christos 		screenwidth = 80;
    128  1.25  christos 	/*
    129  1.25  christos 	 * Possible overrides from the rcfile.
    130  1.25  christos 	 */
    131  1.25  christos 	if ((cp = value(ENAME_SCREENWIDTH)) != NULL) {
    132  1.25  christos 		int width;
    133  1.25  christos 		width = *cp ? atoi(cp) : 0;
    134  1.25  christos 		if (width >= 0)
    135  1.25  christos 			screenwidth = width;
    136  1.25  christos 	}
    137  1.25  christos 	if ((cp = value(ENAME_SCREENHEIGHT)) != NULL) {
    138  1.25  christos 		int height;
    139  1.25  christos 		height = *cp ? atoi(cp) : 0;
    140  1.25  christos 		if (height >= 0) {
    141  1.25  christos 			realscreenheight = height;
    142  1.25  christos 			screenheight = height;
    143  1.25  christos 		}
    144  1.25  christos 	}
    145  1.25  christos }
    146  1.22  christos 
    147  1.22  christos /*
    148  1.22  christos  * Break up a white-space or comma delimited name list so that aliases
    149  1.22  christos  * can get expanded.  Without this, the CC: or BCC: list is broken too
    150  1.22  christos  * late for alias expansion to occur.
    151  1.22  christos  */
    152  1.25  christos PUBLIC struct name *
    153  1.22  christos lexpand(char *str, int ntype)
    154  1.22  christos {
    155  1.22  christos 	char *list;
    156  1.22  christos 	struct name *np = NULL;
    157  1.22  christos 	char *word, *p;
    158  1.22  christos 
    159  1.23  christos 	list = estrdup(str);
    160  1.22  christos 	word = list;
    161  1.23  christos 	for (word = list; *word; word = p) {
    162  1.28  christos 		word = skip_WSP(word);
    163  1.22  christos 		for (p = word;
    164  1.28  christos 		     *p && !is_WSP(*p) && *p != ',';
    165  1.23  christos 		     p++)
    166  1.22  christos 			continue;
    167  1.22  christos 		if (*p)
    168  1.22  christos 			*p++ = '\0';
    169  1.22  christos 		np = cat(np, nalloc(word, ntype));
    170  1.22  christos 	}
    171  1.22  christos 
    172  1.22  christos 	free(list);
    173  1.22  christos 	return np;
    174  1.22  christos }
    175  1.22  christos 
    176  1.25  christos PUBLIC int
    177  1.13       wiz main(int argc, char *argv[])
    178   1.1       cgd {
    179  1.30  christos 	jmp_buf jmpbuf;
    180  1.30  christos 	struct sigaction sa;
    181   1.1       cgd 	struct name *to, *cc, *bcc, *smopts;
    182  1.23  christos #ifdef MIME_SUPPORT
    183  1.24  christos 	struct name *attach_optargs;
    184  1.24  christos 	struct name *attach_end;
    185  1.23  christos #endif
    186   1.1       cgd 	char *subject;
    187  1.19  christos 	const char *ef;
    188   1.1       cgd 	char nosrc = 0;
    189  1.19  christos 	const char *rc;
    190  1.30  christos 	int Hflag;
    191  1.30  christos 	int i;
    192   1.1       cgd 
    193   1.1       cgd 	/*
    194  1.27  christos 	 * For portability, call setprogname() early, before
    195  1.27  christos 	 * getprogname() is called.
    196  1.27  christos 	 */
    197  1.27  christos 	(void)setprogname(argv[0]);
    198  1.27  christos 
    199  1.27  christos 	/*
    200   1.1       cgd 	 * Set up a reasonable environment.
    201   1.1       cgd 	 * Figure out whether we are being run interactively,
    202   1.1       cgd 	 * start the SIGCHLD catcher, and so forth.
    203  1.30  christos 	 * (Other signals are setup later by sig_setup().)
    204   1.1       cgd 	 */
    205  1.30  christos 	(void)sigemptyset(&sa.sa_mask);
    206  1.30  christos 	sa.sa_flags = SA_RESTART;
    207  1.30  christos 	sa.sa_handler = sigchild;
    208  1.30  christos 	(void)sigaction(SIGCHLD, &sa, NULL);
    209  1.30  christos 
    210   1.1       cgd 	if (isatty(0))
    211  1.25  christos 		assign(ENAME_INTERACTIVE, "");
    212   1.1       cgd 	image = -1;
    213  1.30  christos 
    214   1.1       cgd 	/*
    215   1.1       cgd 	 * Now, determine how we are being used.
    216   1.1       cgd 	 * We successively pick off - flags.
    217   1.1       cgd 	 * If there is anything left, it is the base of the list
    218   1.1       cgd 	 * of users to mail to.  Argp will be set to point to the
    219   1.1       cgd 	 * first of these users.
    220   1.1       cgd 	 */
    221  1.30  christos 	rc = NULL;
    222  1.14       wiz 	ef = NULL;
    223  1.15       wiz 	to = NULL;
    224  1.15       wiz 	cc = NULL;
    225  1.15       wiz 	bcc = NULL;
    226  1.15       wiz 	smopts = NULL;
    227  1.14       wiz 	subject = NULL;
    228  1.24  christos 	Hflag = 0;
    229  1.23  christos #ifdef MIME_SUPPORT
    230  1.24  christos 	attach_optargs = NULL;
    231  1.24  christos 	attach_end = NULL;
    232  1.30  christos 	while ((i = getopt(argc, argv, ":~EH:INT:a:b:c:dfinr:s:u:v")) != -1)
    233  1.23  christos #else
    234  1.30  christos 	while ((i = getopt(argc, argv, ":~EH:INT:b:c:dfinr:s:u:v")) != -1)
    235  1.23  christos #endif
    236  1.22  christos 	{
    237   1.1       cgd 		switch (i) {
    238   1.1       cgd 		case 'T':
    239   1.1       cgd 			/*
    240   1.1       cgd 			 * Next argument is temp file to write which
    241   1.1       cgd 			 * articles have been read/deleted for netnews.
    242   1.1       cgd 			 */
    243   1.1       cgd 			Tflag = optarg;
    244   1.1       cgd 			if ((i = creat(Tflag, 0600)) < 0) {
    245  1.17       wiz 				warn("%s", Tflag);
    246   1.1       cgd 				exit(1);
    247   1.1       cgd 			}
    248  1.20  christos 			(void)close(i);
    249   1.1       cgd 			break;
    250  1.23  christos #ifdef MIME_SUPPORT
    251  1.24  christos 		case 'a': {
    252  1.24  christos 			struct name *np;
    253  1.24  christos 			np = nalloc(optarg, 0);
    254  1.24  christos 			if (attach_end == NULL)
    255  1.24  christos 				attach_optargs = np;
    256  1.24  christos 			else {
    257  1.24  christos 				np->n_blink = attach_end;
    258  1.24  christos 				attach_end->n_flink = np;
    259  1.24  christos 			}
    260  1.24  christos 			attach_end = np;
    261  1.23  christos 			break;
    262  1.24  christos 		}
    263  1.23  christos #endif
    264   1.1       cgd 		case 'u':
    265   1.1       cgd 			/*
    266   1.1       cgd 			 * Next argument is person to pretend to be.
    267   1.1       cgd 			 */
    268   1.1       cgd 			myname = optarg;
    269  1.20  christos 			(void)unsetenv("MAIL");
    270   1.1       cgd 			break;
    271   1.1       cgd 		case 'i':
    272   1.1       cgd 			/*
    273   1.1       cgd 			 * User wants to ignore interrupts.
    274   1.1       cgd 			 * Set the variable "ignore"
    275   1.1       cgd 			 */
    276  1.25  christos 			assign(ENAME_IGNORE, "");
    277   1.1       cgd 			break;
    278   1.1       cgd 		case 'd':
    279   1.1       cgd 			debug++;
    280   1.1       cgd 			break;
    281  1.30  christos 		case 'r':
    282  1.30  christos 			rc = optarg;
    283  1.30  christos 			break;
    284   1.1       cgd 		case 's':
    285   1.1       cgd 			/*
    286   1.1       cgd 			 * Give a subject field for sending from
    287   1.1       cgd 			 * non terminal
    288   1.1       cgd 			 */
    289   1.1       cgd 			subject = optarg;
    290   1.1       cgd 			break;
    291   1.1       cgd 		case 'f':
    292   1.1       cgd 			/*
    293   1.1       cgd 			 * User is specifying file to "edit" with Mail,
    294   1.1       cgd 			 * as opposed to reading system mailbox.
    295   1.1       cgd 			 * If no argument is given after -f, we read his
    296   1.1       cgd 			 * mbox file.
    297   1.1       cgd 			 *
    298   1.1       cgd 			 * getopt() can't handle optional arguments, so here
    299   1.1       cgd 			 * is an ugly hack to get around it.
    300   1.1       cgd 			 */
    301   1.1       cgd 			if ((argv[optind]) && (argv[optind][0] != '-'))
    302   1.1       cgd 				ef = argv[optind++];
    303   1.1       cgd 			else
    304   1.1       cgd 				ef = "&";
    305   1.1       cgd 			break;
    306  1.24  christos 		case 'H':
    307  1.24  christos 			/*
    308  1.24  christos 			 * Print out the headers and quit.
    309  1.24  christos 			 */
    310  1.24  christos 			Hflag = get_Hflag(argv);
    311  1.24  christos 			break;
    312   1.1       cgd 		case 'n':
    313   1.1       cgd 			/*
    314   1.1       cgd 			 * User doesn't want to source /usr/lib/Mail.rc
    315   1.1       cgd 			 */
    316   1.1       cgd 			nosrc++;
    317   1.1       cgd 			break;
    318   1.1       cgd 		case 'N':
    319   1.1       cgd 			/*
    320   1.1       cgd 			 * Avoid initial header printing.
    321   1.1       cgd 			 */
    322  1.25  christos 			assign(ENAME_NOHEADER, "");
    323   1.1       cgd 			break;
    324   1.1       cgd 		case 'v':
    325   1.1       cgd 			/*
    326   1.1       cgd 			 * Send mailer verbose flag
    327   1.1       cgd 			 */
    328  1.25  christos 			assign(ENAME_VERBOSE, "");
    329   1.1       cgd 			break;
    330   1.1       cgd 		case 'I':
    331  1.11  christos 		case '~':
    332   1.1       cgd 			/*
    333   1.1       cgd 			 * We're interactive
    334   1.1       cgd 			 */
    335  1.25  christos 			assign(ENAME_INTERACTIVE, "");
    336   1.1       cgd 			break;
    337   1.1       cgd 		case 'c':
    338   1.1       cgd 			/*
    339   1.1       cgd 			 * Get Carbon Copy Recipient list
    340   1.1       cgd 			 */
    341  1.22  christos 			cc = cat(cc, lexpand(optarg, GCC));
    342   1.1       cgd 			break;
    343   1.1       cgd 		case 'b':
    344   1.1       cgd 			/*
    345   1.1       cgd 			 * Get Blind Carbon Copy Recipient list
    346   1.1       cgd 			 */
    347  1.22  christos 			bcc = cat(bcc, lexpand(optarg, GBCC));
    348  1.22  christos 
    349  1.22  christos 			break;
    350  1.11  christos 		case 'E':
    351  1.11  christos 			/*
    352  1.11  christos 			 * Don't send empty files.
    353  1.11  christos 			 */
    354  1.25  christos 			assign(ENAME_DONTSENDEMPTY, "");
    355  1.11  christos 			break;
    356  1.24  christos 		case ':':
    357  1.24  christos 			/*
    358  1.24  christos 			 * An optarg was expected but not found.
    359  1.24  christos 			 */
    360  1.24  christos 			if (optopt == 'H') {
    361  1.24  christos 				Hflag = get_Hflag(NULL);
    362  1.24  christos 				break;
    363  1.24  christos 			}
    364  1.24  christos 			(void)fprintf(stderr,
    365  1.24  christos 			    "%s: option requires an argument -- %c\n",
    366  1.24  christos 			    getprogname(), optopt);
    367  1.28  christos 
    368  1.24  christos 			/* FALLTHROUGH */
    369   1.1       cgd 		case '?':
    370  1.24  christos 			/*
    371  1.24  christos 			 * An unknown option flag.  We need to do the
    372  1.24  christos 			 * error message.
    373  1.24  christos 			 */
    374  1.24  christos 			if (optopt != '?')
    375  1.24  christos 				(void)fprintf(stderr,
    376  1.24  christos 				    "%s: unknown option -- %c\n", getprogname(),
    377  1.24  christos 				    optopt);
    378  1.30  christos 			usage();	/* print usage message and die */
    379  1.30  christos 			/*NOTREACHED*/
    380   1.1       cgd 		}
    381   1.1       cgd 	}
    382   1.1       cgd 	for (i = optind; (argv[i]) && (*argv[i] != '-'); i++)
    383   1.1       cgd 		to = cat(to, nalloc(argv[i], GTO));
    384  1.28  christos 	for (/*EMPTY*/; argv[i]; i++)
    385  1.22  christos 		smopts = cat(smopts, nalloc(argv[i], GSMOPTS));
    386   1.1       cgd 	/*
    387   1.1       cgd 	 * Check for inconsistent arguments.
    388   1.1       cgd 	 */
    389  1.21  christos 	if (to == NULL && (subject != NULL || cc != NULL || bcc != NULL))
    390  1.21  christos 		errx(1, "You must specify direct recipients with -s, -c, or -b.");
    391  1.15       wiz 	if (ef != NULL && to != NULL) {
    392  1.21  christos 		errx(1, "Cannot give -f and people to send to.");
    393   1.1       cgd 	}
    394  1.24  christos 	if (Hflag != 0 && to != NULL)
    395  1.24  christos 		errx(EXIT_FAILURE, "Cannot give -H and people to send to.");
    396  1.23  christos #ifdef MIME_SUPPORT
    397  1.24  christos 	if (attach_optargs != NULL && to == NULL)
    398  1.24  christos 		errx(EXIT_FAILURE, "Cannot give -a without people to send to.");
    399  1.23  christos #endif
    400  1.24  christos 	tinit();	/* must be done before loading the rcfile */
    401   1.1       cgd 	input = stdin;
    402  1.25  christos 	mailmode = Hflag ? mm_hdrsonly :
    403  1.25  christos 	    to ? mm_sending : mm_receiving;
    404  1.28  christos 
    405   1.1       cgd 	spreserve();
    406   1.1       cgd 	if (!nosrc)
    407   1.1       cgd 		load(_PATH_MASTER_RC);
    408   1.1       cgd 	/*
    409   1.1       cgd 	 * Expand returns a savestr, but load only uses the file name
    410   1.1       cgd 	 * for fopen, so it's safe to do this.
    411   1.1       cgd 	 */
    412  1.30  christos 	if (rc == NULL && (rc = getenv("MAILRC")) == NULL)
    413   1.6       tls 		rc = "~/.mailrc";
    414   1.6       tls 	load(expand(rc));
    415  1.25  christos 	setscreensize();	/* do this after loading the rcfile */
    416  1.22  christos 
    417  1.23  christos #ifdef USE_EDITLINE
    418  1.26  christos 	/*
    419  1.26  christos 	 * This is after loading the MAILRC so we can use value().
    420  1.26  christos 	 * Avoid editline in mm_hdrsonly mode or pipelines will screw
    421  1.26  christos 	 * up.  XXX - there must be a better way!
    422  1.26  christos 	 */
    423  1.26  christos 	if (mailmode != mm_hdrsonly)
    424  1.26  christos 		init_editline();
    425  1.22  christos #endif
    426  1.22  christos 
    427  1.30  christos 	sig_setup();
    428  1.30  christos 
    429  1.25  christos 	switch (mailmode) {
    430  1.25  christos 	case mm_sending:
    431  1.25  christos 		(void)mail(to, cc, bcc, smopts, subject,
    432  1.25  christos 		    mime_attach_optargs(attach_optargs));
    433   1.1       cgd 		/*
    434   1.1       cgd 		 * why wait?
    435   1.1       cgd 		 */
    436   1.1       cgd 		exit(senderr);
    437  1.25  christos 		break;	/* XXX - keep lint happy */
    438  1.25  christos 
    439  1.25  christos 	case mm_receiving:
    440  1.25  christos 	case mm_hdrsonly:
    441  1.25  christos 		/*
    442  1.25  christos 		 * Ok, we are reading mail.
    443  1.25  christos 		 * Decide whether we are editing a mailbox or reading
    444  1.25  christos 		 * the system mailbox, and open up the right stuff.
    445  1.25  christos 		 */
    446  1.25  christos 		if (ef == NULL)
    447  1.25  christos 			ef = "%";
    448  1.25  christos 		if (setfile(ef) < 0)
    449  1.25  christos 			exit(1);		/* error already reported */
    450  1.30  christos 		if (value(ENAME_QUIET) == NULL)
    451  1.30  christos 			(void)printf("Mail version %s.  Type ? for help.\n",
    452  1.30  christos 			    version);
    453  1.30  christos 		if (mailmode == mm_hdrsonly)
    454  1.30  christos 			show_headers_and_exit(Hflag);	/* NORETURN */
    455  1.30  christos 		announce();
    456  1.30  christos 		(void)fflush(stdout);
    457  1.30  christos 
    458  1.30  christos 		if (setjmp(jmpbuf) != 0) {
    459  1.30  christos 			/* Return here if quit() fails below. */
    460  1.30  christos 			(void)printf("Use 'exit' to quit without saving changes.\n");
    461  1.25  christos 		}
    462  1.25  christos 		commands();
    463  1.30  christos 
    464  1.30  christos 		/* Ignore these signals from now on! */
    465  1.25  christos 		(void)signal(SIGHUP, SIG_IGN);
    466  1.25  christos 		(void)signal(SIGINT, SIG_IGN);
    467  1.25  christos 		(void)signal(SIGQUIT, SIG_IGN);
    468  1.30  christos 		quit(jmpbuf);
    469  1.25  christos 		break;
    470  1.28  christos 
    471  1.25  christos 	default:
    472  1.25  christos 		assert(/*CONSTCOND*/0);
    473  1.25  christos 		break;
    474   1.1       cgd 	}
    475  1.25  christos 
    476  1.20  christos 	return 0;
    477   1.1       cgd }
    478