xref: /openbsd/usr.bin/mail/main.c (revision 17df1aa7)
1 /*	$OpenBSD: main.c,v 1.23 2009/10/27 23:59:40 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 *subject;
53 	char *ef;
54 	char nosrc = 0;
55 	char *rc;
56 	extern const char version[];
57 
58 	/*
59 	 * Set up a reasonable environment.
60 	 * Figure out whether we are being run interactively,
61 	 * start the SIGCHLD catcher, and so forth.
62 	 */
63 	(void)signal(SIGCHLD, sigchild);
64 	(void)signal(SIGPIPE, SIG_IGN);
65 	if (isatty(0))
66 		assign("interactive", "");
67 	image = -1;
68 	/*
69 	 * Now, determine how we are being used.
70 	 * We successively pick off - flags.
71 	 * If there is anything left, it is the base of the list
72 	 * of users to mail to.  Argp will be set to point to the
73 	 * first of these users.
74 	 */
75 	ef = NULL;
76 	to = NULL;
77 	cc = NULL;
78 	bcc = NULL;
79 	smopts = NULL;
80 	subject = NULL;
81 	while ((i = getopt(argc, argv, "EINT:b:c:dfins:u:v")) != -1) {
82 		switch (i) {
83 		case 'T':
84 			/*
85 			 * Next argument is temp file to write which
86 			 * articles have been read/deleted for netnews.
87 			 */
88 			Tflag = optarg;
89 			if ((i = creat(Tflag, 0600)) < 0)
90 				err(1, "%s", Tflag);
91 			(void)close(i);
92 			break;
93 		case 'u':
94 			/*
95 			 * Next argument is person to pretend to be.
96 			 */
97 			if (strlen(optarg) >= MAXLOGNAME)
98 				errx(1, "username `%s' too long", optarg);
99 			unsetenv("MAIL");
100 			myname = optarg;
101 			uflag = 1;
102 			break;
103 		case 'i':
104 			/*
105 			 * User wants to ignore interrupts.
106 			 * Set the variable "ignore"
107 			 */
108 			assign("ignore", "");
109 			break;
110 		case 'd':
111 			debug++;
112 			break;
113 		case 's':
114 			/*
115 			 * Give a subject field for sending from
116 			 * non terminal
117 			 */
118 			subject = optarg;
119 			break;
120 		case 'f':
121 			/*
122 			 * User is specifying file to "edit" with Mail,
123 			 * as opposed to reading system mailbox.
124 			 * If no argument is given after -f, we read his
125 			 * mbox file.
126 			 *
127 			 * getopt() can't handle optional arguments, so here
128 			 * is an ugly hack to get around it.
129 			 */
130 			if ((argv[optind]) && (argv[optind][0] != '-'))
131 				ef = argv[optind++];
132 			else
133 				ef = "&";
134 			break;
135 		case 'n':
136 			/*
137 			 * User doesn't want to source /usr/lib/Mail.rc
138 			 */
139 			nosrc++;
140 			break;
141 		case 'N':
142 			/*
143 			 * Avoid initial header printing.
144 			 */
145 			assign("noheader", "");
146 			break;
147 		case 'v':
148 			/*
149 			 * Send mailer verbose flag
150 			 */
151 			assign("verbose", "");
152 			break;
153 		case 'I':
154 			/*
155 			 * We're interactive
156 			 */
157 			assign("interactive", "");
158 			break;
159 		case 'c':
160 			/*
161 			 * Get Carbon Copy Recipient list
162 			 */
163 			cc = cat(cc, nalloc(optarg, GCC));
164 			break;
165 		case 'b':
166 			/*
167 			 * Get Blind Carbon Copy Recipient list
168 			 */
169 			bcc = cat(bcc, nalloc(optarg, GBCC));
170 			break;
171 		case 'E':
172 			/*
173 			 * Don't send messages with an empty body.
174 			 */
175 			assign("skipempty", "");
176 			break;
177 		default:
178 			usage();
179 			/*NOTREACHED*/
180 		}
181 	}
182 	for (i = optind; (argv[i]) && (*argv[i] != '-'); i++)
183 		to = cat(to, nalloc(argv[i], GTO));
184 	for (; argv[i]; i++)
185 		smopts = cat(smopts, nalloc(argv[i], 0));
186 	/*
187 	 * Check for inconsistent arguments.
188 	 */
189 	if (to == NULL && (subject != NULL || cc != NULL || bcc != NULL))
190 		errx(1, "You must specify direct recipients with -s, -c, or -b");
191 	if (ef != NULL && to != NULL)
192 		errx(1, "Cannot give -f and people to send to");
193 	/*
194 	 * Block SIGINT except where we install an explicit handler for it.
195 	 */
196 	sigemptyset(&intset);
197 	sigaddset(&intset, SIGINT);
198 	(void)sigprocmask(SIG_BLOCK, &intset, NULL);
199 	/*
200 	 * Initialization.
201 	 */
202 	tinit();
203 	setscreensize();
204 	input = stdin;
205 	rcvmode = !to;
206 	spreserve();
207 	if (!nosrc)
208 		load(_PATH_MASTER_RC);
209 	/*
210 	 * Expand returns a savestr, but load only uses the file name
211 	 * for fopen, so it's safe to do this.
212 	 */
213 	if ((rc = getenv("MAILRC")) == 0)
214 		rc = "~/.mailrc";
215 	load(expand(rc));
216 	if (!rcvmode) {
217 		mail(to, cc, bcc, smopts, subject);
218 		/*
219 		 * why wait?
220 		 */
221 		exit(senderr);
222 	}
223 	/*
224 	 * Ok, we are reading mail.
225 	 * Decide whether we are editing a mailbox or reading
226 	 * the system mailbox, and open up the right stuff.
227 	 */
228 	if (ef == NULL)
229 		ef = "%";
230 	if (setfile(ef) < 0)
231 		exit(1);		/* error already reported */
232 
233 	if (value("quiet") == NULL)
234 		(void)printf("Mail version %s.  Type ? for help.\n",
235 			version);
236 	announce();
237 	(void)fflush(stdout);
238 	commands();
239 	(void)ignoresig(SIGHUP, NULL, NULL);
240 	(void)ignoresig(SIGINT, NULL, NULL);
241 	(void)ignoresig(SIGQUIT, NULL, NULL);
242 	quit();
243 	exit(0);
244 }
245 
246 /*
247  * Compute what the screen size for printing headers should be.
248  * We use the following algorithm for the height:
249  *	If baud rate < 1200, use  9
250  *	If baud rate = 1200, use 14
251  *	If baud rate > 1200, use 24 or ws_row
252  * Width is either 80 or ws_col;
253  */
254 void
255 setscreensize(void)
256 {
257 	struct termios tbuf;
258 	struct winsize ws;
259 	speed_t ospeed;
260 
261 	if (ioctl(1, TIOCGWINSZ, (char *) &ws) < 0)
262 		ws.ws_col = ws.ws_row = 0;
263 	if (tcgetattr(1, &tbuf) < 0)
264 		ospeed = 9600;
265 	else
266 		ospeed = cfgetospeed(&tbuf);
267 	if (ospeed < B1200)
268 		screenheight = 9;
269 	else if (ospeed == B1200)
270 		screenheight = 14;
271 	else if (ws.ws_row != 0)
272 		screenheight = ws.ws_row;
273 	else
274 		screenheight = 24;
275 	if ((realscreenheight = ws.ws_row) == 0)
276 		realscreenheight = 24;
277 	if ((screenwidth = ws.ws_col) == 0)
278 		screenwidth = 80;
279 }
280 
281 __dead void
282 usage(void)
283 {
284 
285 	fprintf(stderr, "usage: %s [-dEIinv] [-b list] [-c list] "
286 	    "[-s subject] to-addr ...\n", __progname);
287 	fprintf(stderr, "       %*s [-sendmail-options ...]\n",
288 	    (int)strlen(__progname), "");
289 	fprintf(stderr, "       %s [-dEIiNnv] -f [file]\n", __progname);
290 	fprintf(stderr, "       %s [-dEIiNnv] [-u user]\n", __progname);
291 	exit(1);
292 }
293