1/*
2 * Copyright (c) 1980, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include <sys/cdefs.h>
35#ifndef lint
36__unused static char copyright[] =
37"@(#) Copyright (c) 1980, 1993\n\
38	The Regents of the University of California.  All rights reserved.\n";
39#endif /* not lint */
40
41#ifndef lint
42#if 0
43static char sccsid[] = "@(#)main.c	8.2 (Berkeley) 4/20/95";
44#endif
45__unused static const char rcsid[] =
46  "$FreeBSD: src/usr.bin/mail/main.c,v 1.14 2004/02/29 20:44:44 mikeh Exp $";
47#endif /* not lint */
48
49#include <sys/cdefs.h>
50#include <sys/ioctl.h>
51
52#define EXTERN
53#include "rcv.h"
54#include <fcntl.h>
55#include "extern.h"
56
57/*
58 * Mail -- a mail program
59 *
60 * Startup -- interface with user.
61 */
62
63jmp_buf	hdrjmp;
64
65extern const char *version;
66
67int
68main(argc, argv)
69	int argc;
70	char *argv[];
71{
72	int i;
73	struct name *to, *cc, *bcc, *smopts;
74	char *subject, *replyto;
75	char *ef, *rc;
76	char nosrc = 0;
77	sig_t prevint;
78
79	/*
80	 * Set up a reasonable environment.
81	 * Figure out whether we are being run interactively,
82	 * start the SIGCHLD catcher, and so forth.
83	 */
84	(void)signal(SIGCHLD, sigchild);
85	if (isatty(0))
86		assign("interactive", "");
87	image = -1;
88
89	/* Define defaults for internal variables, based on Unix 2003 standard  */
90	/* noallnet			allnet  off	*/
91	/* noappend			append off	*/
92	assign("asksub","");	/*	asksub on	*/
93	/* noaskbcc			askbcc off	*/
94	/* noaskcc			askcc off	*/
95	/* noautoprint			autoprint  off	*/
96	/* nobang			bang off	*/
97	/* nocmd			cmd off		*/
98	/* nocrt			crt off		*/
99	/* nodebug			debug off	*/
100	/* nodot			dot off		*/
101	/* noflipr			flipr off	*/
102	/* nofolder			folder off	*/
103	assign("header", "");	/*	headers on	*/
104	/* nohold			hold off	*/
105	/* noignore			ignore off	*/
106	/* noignoreeof			ignoreeof off	*/
107	/* nokeep			keep off	*/
108	/* nokeepsave			keepsave off	*/
109	/* nometoo			metoo off	*/
110	/* noonehop			onehop off	*/
111	/* nooutfolder			outfolder off	*/
112	/* nopage			page off	*/
113	assign("prompt", "? ");
114	/* noquiet			quiet off	*/
115	/* norecord			record off	*/
116	assign("save", "");	/*	save on		*/
117	/* nosendwait			sendwait off	*/
118	/* noshowto			showto off	*/
119	/* nosign			sign off	*/
120	/* noSign			Sign off	*/
121
122	/*
123	 * Now, determine how we are being used.
124	 * We successively pick off - flags.
125	 * If there is anything left, it is the base of the list
126	 * of users to mail to.  Argp will be set to point to the
127	 * first of these users.
128	 */
129	ef = NULL;
130	to = NULL;
131	cc = NULL;
132	bcc = NULL;
133	smopts = NULL;
134	subject = NULL;
135	while ((i = getopt(argc, argv, "FEHINT:b:c:edfins:u:v")) != -1) {
136		switch (i) {
137		case 'T':
138			/*
139			 * Next argument is temp file to write which
140			 * articles have been read/deleted for netnews.
141			 */
142			Tflag = optarg;
143			if ((i = open(Tflag, O_CREAT | O_TRUNC | O_WRONLY,
144			    0600)) < 0)
145				err(1, "%s", Tflag);
146			(void)close(i);
147			break;
148		case 'u':
149			/*
150			 * Next argument is person to pretend to be.
151			 */
152			myname = optarg;
153			unsetenv("MAIL");
154			break;
155		case 'i':
156			/*
157			 * User wants to ignore interrupts.
158			 * Set the variable "ignore"
159			 */
160			assign("ignore", "");
161			break;
162		case 'd':
163			debug = 1; /* 1 -> set from command line; disables env var [no]debug */
164			break;
165		case 'e':
166			/*
167			 * User wants to check mail and exit.
168			 */
169			assign("checkmode", "");
170			break;
171		case 'H':
172			/*
173			 * User wants a header summary only.
174			 */
175			assign("headersummary", "");
176			break;
177		case 'F':
178			/*
179			 * User wants to record messages to files
180			 * named after first recipient username.
181			 */
182			assign("recordrecip", "");
183			break;
184		case 's':
185			/*
186			 * Give a subject field for sending from
187			 * non terminal
188			 */
189			subject = optarg;
190			break;
191		case 'f':
192			/*
193			 * User is specifying file to "edit" with Mail,
194			 * as opposed to reading system mailbox.
195			 * If no argument is given after -f, we read his
196			 * mbox file.
197			 *
198			 * getopt() can't handle optional arguments, so here
199			 * is an ugly hack to get around it.
200			 */
201			if ((argv[optind] != NULL) && (argv[optind][0] != '-'))
202				ef = argv[optind++];
203			else
204				ef = "&";
205			break;
206		case 'n':
207			/*
208			 * User doesn't want to source /usr/lib/Mail.rc
209			 */
210			nosrc++;
211			break;
212		case 'N':
213			/*
214			 * Avoid initial header printing.
215			 */
216			assign("quiet", "");
217			break;
218		case 'v':
219			/*
220			 * Send mailer verbose flag
221			 */
222			assign("verbose", "");
223			break;
224		case 'I':
225			/*
226			 * We're interactive
227			 */
228			assign("interactive", "");
229			break;
230		case 'c':
231			/*
232			 * Get Carbon Copy Recipient list
233			 */
234			cc = cat(cc, nalloc(optarg, GCC));
235			break;
236		case 'b':
237			/*
238			 * Get Blind Carbon Copy Recipient list
239			 */
240			bcc = cat(bcc, nalloc(optarg, GBCC));
241			break;
242		case 'E':
243			/*
244			 * Don't send empty files.
245			 */
246			assign("dontsendempty", "");
247			break;
248		case '?':
249			fprintf(stderr, "\
250Usage: %s [-EiInv] [-s subject] [-c cc-addr] [-b bcc-addr] [-F] to-addr ...\n\
251       %*s [- sendmail-options ...]\n\
252       %s [-EHiInNv] [-F] -f [name]\n\
253       %s [-EHiInNv] [-F] [-u user]\n\
254       %s -e [-f name]\n\
255       %s -H\n",__progname, (int)strlen(__progname), "",
256			    __progname, __progname, __progname, __progname);
257			exit(1);
258		}
259	}
260	for (i = optind; (argv[i] != NULL) && (*argv[i] != '-'); i++)
261		to = cat(to, nalloc(argv[i], GTO));
262	for (; argv[i] != NULL; i++)
263		smopts = cat(smopts, nalloc(argv[i], 0));
264	/*
265	 * Check for inconsistent arguments.
266	 */
267	if (to == NULL && (subject != NULL || cc != NULL || bcc != NULL))
268		errx(1, "You must specify direct recipients with -s, -c, or -b.");
269	if (ef != NULL && to != NULL)
270		errx(1, "Cannot give -f and people to send to.");
271	tinit();
272	setscreensize();
273	input = stdin;
274	rcvmode = !to;
275	spreserve();
276	if (!nosrc) {
277		char *s, *path_rc;
278
279		if ((path_rc = malloc(sizeof(_PATH_MASTER_RC))) == NULL)
280			err(1, "malloc(path_rc) failed");
281
282		strcpy(path_rc, _PATH_MASTER_RC);
283		while ((s = strsep(&path_rc, ":")) != NULL)
284			if (*s != '\0')
285				load(s);
286	}
287	/*
288	 * Expand returns a savestr, but load only uses the file name
289	 * for fopen, so it's safe to do this.
290	 */
291	if ((rc = getenv("MAILRC")) == NULL)
292		rc = "~/.mailrc";
293	load(expand(rc));
294
295	replyto = value("REPLYTO");
296	if (!rcvmode) {
297		mail(to, cc, bcc, smopts, subject, replyto);
298		/*
299		 * why wait?
300		 */
301		exit(senderr);
302	}
303
304	if(value("checkmode") != NULL) {
305		if (ef == NULL)
306			ef = "%";
307		if (setfile(ef) <= 0)
308			/* Either an error has occured, or no mail */
309			exit(1);
310		else
311			exit(0);
312		/* NOTREACHED */
313	}
314
315	/*
316	 * Ok, we are reading mail.
317	 * Decide whether we are editing a mailbox or reading
318	 * the system mailbox, and open up the right stuff.
319	 */
320	if (ef == NULL)
321		ef = "%";
322	if (setfile(ef) < 0)
323		exit(1);		/* error already reported */
324	if (setjmp(hdrjmp) == 0) {
325		if ((prevint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
326			(void)signal(SIGINT, hdrstop);
327		if (value("quiet") == NULL) {
328			printf("Mail version %s.  Type ? for help.\n",
329				version);
330			announce();
331		}
332		(void)fflush(stdout);
333		(void)signal(SIGINT, prevint);
334	}
335
336	/* If we were in header summary mode, it's time to exit. */
337	if (value("headersummary") != NULL)
338		exit(0);
339
340	commands();
341	(void)signal(SIGHUP, SIG_IGN);
342	(void)signal(SIGINT, SIG_IGN);
343	(void)signal(SIGQUIT, SIG_IGN);
344	quit();
345	exit(0);
346}
347
348/*
349 * Interrupt printing of the headers.
350 */
351/*ARGSUSED*/
352void
353hdrstop(signo)
354	int signo;
355{
356
357	(void)fflush(stdout);
358	fprintf(stderr, "\nInterrupt\n");
359	longjmp(hdrjmp, 1);
360}
361
362/*
363 * Compute what the screen size for printing headers should be.
364 * We use the following algorithm for the height:
365 *	If baud rate < 1200, use  9
366 *	If baud rate = 1200, use 14
367 *	If baud rate > 1200, use 24 or ws_row
368 * Width is either 80 or ws_col;
369 */
370void
371setscreensize()
372{
373	struct termios tbuf;
374	struct winsize ws;
375	speed_t speed;
376
377	if (ioctl(1, TIOCGWINSZ, (char *)&ws) < 0)
378		ws.ws_col = ws.ws_row = 0;
379	if (tcgetattr(1, &tbuf) < 0)
380		speed = B9600;
381	else
382		speed = cfgetospeed(&tbuf);
383	if (speed < B1200)
384		screenheight = 9;
385	else if (speed == B1200)
386		screenheight = 14;
387	else if (ws.ws_row != 0)
388		screenheight = ws.ws_row;
389	else
390		screenheight = 24;
391	if ((realscreenheight = ws.ws_row) == 0)
392		realscreenheight = 24;
393	if ((screenwidth = ws.ws_col) == 0)
394		screenwidth = 80;
395}
396