1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1980, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#ifndef lint
33static const char copyright[] =
34"@(#) Copyright (c) 1980, 1993\n\
35	The Regents of the University of California.  All rights reserved.\n";
36#endif /* not lint */
37
38#ifndef lint
39#if 0
40static char sccsid[] = "@(#)main.c	8.2 (Berkeley) 4/20/95";
41#endif
42#endif /* not lint */
43#include <sys/cdefs.h>
44__FBSDID("$FreeBSD$");
45
46#include "rcv.h"
47#include <fcntl.h>
48#include "extern.h"
49
50/*
51 * Mail -- a mail program
52 *
53 * Startup -- interface with user.
54 */
55int	msgCount;
56int	rcvmode;
57int	sawcom;
58char	*Tflag;
59int	senderr;
60int	edit;
61int	readonly;
62int	noreset;
63int	sourcing;
64int	loading;
65int	cond;
66FILE	*itf;
67FILE	*otf;
68int	image;
69FILE	*input;
70char	mailname[PATHSIZE];
71char	prevfile[PATHSIZE];
72char	*homedir;
73char	*myname;
74off_t	mailsize;
75int	lexnumber;
76char	lexstring[STRINGLEN];
77int	regretp;
78int	regretstack[REGDEP];
79char	*string_stack[REGDEP];
80int	numberstack[REGDEP];
81struct	message	*dot;
82struct	message	*message;
83struct	var	*variables[HSHSIZE];
84struct	grouphead	*groups[HSHSIZE];
85struct	ignoretab	ignore[2];
86
87struct	ignoretab	saveignore[2];
88
89struct	ignoretab	ignoreall[2];
90char	**altnames;
91int	debug;
92int	screenwidth;
93int	screenheight;
94
95int	realscreenheight;
96
97jmp_buf	srbuf;
98
99static jmp_buf	hdrjmp;
100
101extern const char *version;
102
103int
104main(int argc, char *argv[])
105{
106	int i;
107	struct name *to, *cc, *bcc, *smopts;
108	char *subject, *replyto;
109	char *ef, *rc;
110	char nosrc = 0;
111	sig_t prevint;
112
113	/*
114	 * Set up a reasonable environment.
115	 * Figure out whether we are being run interactively,
116	 * start the SIGCHLD catcher, and so forth.
117	 */
118	(void)signal(SIGCHLD, sigchild);
119	if (isatty(0))
120		assign("interactive", "");
121	image = -1;
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++;
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("noheader", "");
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 [-dEiInv] [-s subject] [-c cc-addr] [-b bcc-addr] [-F] to-addr ...\n\
251       %*s [-sendmail-option ...]\n\
252       %s [-dEHiInNv] [-F] -f [name]\n\
253       %s [-dEHiInNv] [-F] [-u user]\n\
254       %s [-d] -e [-f name]\n", __progname, (int)strlen(__progname), "",
255				__progname, __progname, __progname);
256			exit(1);
257		}
258	}
259	for (i = optind; (argv[i] != NULL) && (*argv[i] != '-'); i++)
260		to = cat(to, nalloc(argv[i], GTO));
261	for (; argv[i] != NULL; i++)
262		smopts = cat(smopts, nalloc(argv[i], 0));
263	/*
264	 * Check for inconsistent arguments.
265	 */
266	if (to == NULL && (subject != NULL || cc != NULL || bcc != NULL))
267		errx(1, "You must specify direct recipients with -s, -c, or -b.");
268	if (ef != NULL && to != NULL)
269		errx(1, "Cannot give -f and people to send to.");
270	tinit();
271	setscreensize();
272	input = stdin;
273	rcvmode = !to;
274	spreserve();
275	if (!nosrc) {
276		char *s, *path_rc;
277
278		if ((path_rc = malloc(sizeof(_PATH_MASTER_RC))) == NULL)
279			err(1, "malloc(path_rc) failed");
280
281		strcpy(path_rc, _PATH_MASTER_RC);
282		while ((s = strsep(&path_rc, ":")) != NULL)
283			if (*s != '\0')
284				load(s);
285	}
286	/*
287	 * Expand returns a savestr, but load only uses the file name
288	 * for fopen, so it's safe to do this.
289	 */
290	if ((rc = getenv("MAILRC")) == NULL)
291		rc = "~/.mailrc";
292	load(expand(rc));
293
294	replyto = value("REPLYTO");
295	if (!rcvmode) {
296		mail(to, cc, bcc, smopts, subject, replyto);
297		/*
298		 * why wait?
299		 */
300		exit(senderr);
301	}
302
303	if(value("checkmode") != NULL) {
304		if (ef == NULL)
305			ef = "%";
306		if (setfile(ef) <= 0)
307			/* Either an error has occurred, or no mail */
308			exit(1);
309		else
310			exit(0);
311		/* NOTREACHED */
312	}
313
314	/*
315	 * Ok, we are reading mail.
316	 * Decide whether we are editing a mailbox or reading
317	 * the system mailbox, and open up the right stuff.
318	 */
319	if (ef == NULL)
320		ef = "%";
321	if (setfile(ef) < 0)
322		exit(1);		/* error already reported */
323	if (setjmp(hdrjmp) == 0) {
324		if ((prevint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
325			(void)signal(SIGINT, hdrstop);
326		if (value("quiet") == NULL)
327			printf("Mail version %s.  Type ? for help.\n",
328				version);
329		announce();
330		(void)fflush(stdout);
331		(void)signal(SIGINT, prevint);
332	}
333
334	/* If we were in header summary mode, it's time to exit. */
335	if (value("headersummary") != NULL)
336		exit(0);
337
338	commands();
339	(void)signal(SIGHUP, SIG_IGN);
340	(void)signal(SIGINT, SIG_IGN);
341	(void)signal(SIGQUIT, SIG_IGN);
342	quit();
343	exit(0);
344}
345
346/*
347 * Interrupt printing of the headers.
348 */
349/*ARGSUSED*/
350void
351hdrstop(int signo __unused)
352{
353
354	(void)fflush(stdout);
355	fprintf(stderr, "\nInterrupt\n");
356	longjmp(hdrjmp, 1);
357}
358
359/*
360 * Compute what the screen size for printing headers should be.
361 * We use the following algorithm for the height:
362 *	If baud rate < 1200, use  9
363 *	If baud rate = 1200, use 14
364 *	If baud rate > 1200, use 24 or ws_row
365 * Width is either 80 or ws_col;
366 */
367void
368setscreensize(void)
369{
370	struct termios tbuf;
371	struct winsize ws;
372	speed_t speed;
373
374	if (ioctl(1, TIOCGWINSZ, (char *)&ws) < 0)
375		ws.ws_col = ws.ws_row = 0;
376	if (tcgetattr(1, &tbuf) < 0)
377		speed = B9600;
378	else
379		speed = cfgetospeed(&tbuf);
380	if (speed < B1200)
381		screenheight = 9;
382	else if (speed == B1200)
383		screenheight = 14;
384	else if (ws.ws_row != 0)
385		screenheight = ws.ws_row;
386	else
387		screenheight = 24;
388	if ((realscreenheight = ws.ws_row) == 0)
389		realscreenheight = 24;
390	if ((screenwidth = ws.ws_col) == 0)
391		screenwidth = 80;
392}
393