xref: /openbsd-src/usr.bin/mail/main.c (revision cb39b41371628601fbe4c618205356d538b9d08a)
1 /*	$OpenBSD: main.c,v 1.31 2015/02/08 23:40:34 deraadt Exp $	*/
2 /*	$NetBSD: main.c,v 1.7 1997/05/13 06:15:57 mikel Exp $	*/
3 
4 /*
5  * Copyright (c) 1980, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include "rcv.h"
34 #include <fcntl.h>
35 #include <sys/ioctl.h>
36 #include "extern.h"
37 
38 __dead	void	usage(void);
39 	int	main(int, char **);
40 
41 /*
42  * Mail -- a mail program
43  *
44  * Startup -- interface with user.
45  */
46 
47 int
48 main(int argc, char **argv)
49 {
50 	int i;
51 	struct name *to, *cc, *bcc, *smopts;
52 	char *fromaddr;
53 	char *subject;
54 	char *ef;
55 	char nosrc = 0;
56 	char *rc;
57 	extern const char version[];
58 
59 	/*
60 	 * Set up a reasonable environment.
61 	 * Figure out whether we are being run interactively,
62 	 * start the SIGCHLD catcher, and so forth.
63 	 */
64 	(void)signal(SIGCHLD, sigchild);
65 	(void)signal(SIGPIPE, SIG_IGN);
66 	if (isatty(0))
67 		assign("interactive", "");
68 	image = -1;
69 	/*
70 	 * Now, determine how we are being used.
71 	 * We successively pick off - flags.
72 	 * If there is anything left, it is the base of the list
73 	 * of users to mail to.  Argp will be set to point to the
74 	 * first of these users.
75 	 */
76 	ef = NULL;
77 	to = NULL;
78 	cc = NULL;
79 	bcc = NULL;
80 	smopts = NULL;
81 	fromaddr = NULL;
82 	subject = NULL;
83 	while ((i = getopt(argc, argv, "EINb:c:dfinr:s:u:v")) != -1) {
84 		switch (i) {
85 		case 'u':
86 			/*
87 			 * Next argument is person to pretend to be.
88 			 */
89 			if (strlen(optarg) >= LOGIN_NAME_MAX)
90 				errx(1, "username `%s' too long", optarg);
91 			unsetenv("MAIL");
92 			myname = optarg;
93 			uflag = 1;
94 			break;
95 		case 'i':
96 			/*
97 			 * User wants to ignore interrupts.
98 			 * Set the variable "ignore"
99 			 */
100 			assign("ignore", "");
101 			break;
102 		case 'd':
103 			debug++;
104 			break;
105 		case 'r':
106 			/*
107 			 * Set From: address
108 			 */
109 			fromaddr = optarg;
110 			break;
111 		case 's':
112 			/*
113 			 * Give a subject field for sending from
114 			 * non terminal
115 			 */
116 			subject = optarg;
117 			break;
118 		case 'f':
119 			/*
120 			 * User is specifying file to "edit" with Mail,
121 			 * as opposed to reading system mailbox.
122 			 * We read his mbox file unless another file
123 			 * is specified after the arguments.
124 			 */
125 			ef = "&";
126 			break;
127 		case 'n':
128 			/*
129 			 * User doesn't want to source /usr/lib/Mail.rc
130 			 */
131 			nosrc = 1;
132 			break;
133 		case 'N':
134 			/*
135 			 * Avoid initial header printing.
136 			 */
137 			assign("noheader", "");
138 			break;
139 		case 'v':
140 			/*
141 			 * Send mailer verbose flag
142 			 */
143 			assign("verbose", "");
144 			break;
145 		case 'I':
146 			/*
147 			 * We're interactive
148 			 */
149 			assign("interactive", "");
150 			break;
151 		case 'c':
152 			/*
153 			 * Get Carbon Copy Recipient list
154 			 */
155 			cc = cat(cc, nalloc(optarg, GCC));
156 			break;
157 		case 'b':
158 			/*
159 			 * Get Blind Carbon Copy Recipient list
160 			 */
161 			bcc = cat(bcc, nalloc(optarg, GBCC));
162 			break;
163 		case 'E':
164 			/*
165 			 * Don't send messages with an empty body.
166 			 */
167 			assign("skipempty", "");
168 			break;
169 		default:
170 			usage();
171 			/*NOTREACHED*/
172 		}
173 	}
174 	if (ef != NULL) {
175 		/* Check for optional mailbox file name. */
176 		if (optind < argc) {
177 			ef = argv[optind++];
178 			if (optind < argc)
179 			    errx(1, "Cannot give -f and people to send to");
180 		}
181 	} else {
182 		for (i = optind; argv[i]; i++)
183 			to = cat(to, nalloc(argv[i], GTO));
184 	}
185 	/*
186 	 * Check for inconsistent arguments.
187 	 */
188 	if (to == NULL && (subject != NULL || cc != NULL || bcc != NULL ||
189 	    fromaddr != NULL))
190 		errx(1, "You must specify direct recipients with -s, -c, -b, "
191 		    "or -r");
192 	/*
193 	 * Block SIGINT except where we install an explicit handler for it.
194 	 */
195 	sigemptyset(&intset);
196 	sigaddset(&intset, SIGINT);
197 	(void)sigprocmask(SIG_BLOCK, &intset, NULL);
198 	/*
199 	 * Initialization.
200 	 */
201 	tinit();
202 	setscreensize();
203 	input = stdin;
204 	rcvmode = !to;
205 	spreserve();
206 	if (!nosrc)
207 		load(_PATH_MASTER_RC);
208 	/*
209 	 * Expand returns a savestr, but load only uses the file name
210 	 * for fopen, so it's safe to do this.
211 	 */
212 	if ((rc = getenv("MAILRC")) == 0)
213 		rc = "~/.mailrc";
214 	load(expand(rc));
215 	if (!rcvmode) {
216 		mail(to, cc, bcc, smopts, fromaddr, subject);
217 		/*
218 		 * why wait?
219 		 */
220 		exit(senderr);
221 	}
222 	/*
223 	 * Ok, we are reading mail.
224 	 * Decide whether we are editing a mailbox or reading
225 	 * the system mailbox, and open up the right stuff.
226 	 */
227 	if (ef == NULL)
228 		ef = "%";
229 	if (setfile(ef) < 0)
230 		exit(1);		/* error already reported */
231 
232 	if (value("quiet") == NULL)
233 		(void)printf("Mail version %s.  Type ? for help.\n",
234 			version);
235 	announce();
236 	(void)fflush(stdout);
237 	commands();
238 	(void)ignoresig(SIGHUP, NULL, NULL);
239 	(void)ignoresig(SIGINT, NULL, NULL);
240 	(void)ignoresig(SIGQUIT, NULL, NULL);
241 	quit();
242 	exit(0);
243 }
244 
245 /*
246  * Compute what the screen size for printing headers should be.
247  * We use the following algorithm for the height:
248  *	If baud rate < 1200, use  9
249  *	If baud rate = 1200, use 14
250  *	If baud rate > 1200, use 24 or ws_row
251  * Width is either 80 or ws_col;
252  */
253 void
254 setscreensize(void)
255 {
256 	struct termios tbuf;
257 	struct winsize ws;
258 	speed_t ospeed;
259 
260 	if (ioctl(1, TIOCGWINSZ, (char *) &ws) < 0)
261 		ws.ws_col = ws.ws_row = 0;
262 	if (tcgetattr(1, &tbuf) < 0)
263 		ospeed = 9600;
264 	else
265 		ospeed = cfgetospeed(&tbuf);
266 	if (ospeed < B1200)
267 		screenheight = 9;
268 	else if (ospeed == B1200)
269 		screenheight = 14;
270 	else if (ws.ws_row != 0)
271 		screenheight = ws.ws_row;
272 	else
273 		screenheight = 24;
274 	if ((realscreenheight = ws.ws_row) == 0)
275 		realscreenheight = 24;
276 	if ((screenwidth = ws.ws_col) == 0)
277 		screenwidth = 80;
278 }
279 
280 __dead void
281 usage(void)
282 {
283 
284 	fprintf(stderr, "usage: %s [-dEIinv] [-b list] [-c list] "
285 	    "[-r from-addr] [-s subject] to-addr ...\n", __progname);
286 	fprintf(stderr, "       %s [-dEIiNnv] -f [file]\n", __progname);
287 	fprintf(stderr, "       %s [-dEIiNnv] [-u user]\n", __progname);
288 	exit(1);
289 }
290