xref: /openbsd-src/usr.bin/mail/main.c (revision a4afd6dad3fba28f80e70208181c06c482259988)
1 /*	$OpenBSD: main.c,v 1.3 1996/09/16 02:26:09 deraadt Exp $	*/
2 /*	$NetBSD: main.c,v 1.5 1996/06/08 19:48:31 christos 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. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #ifndef lint
38 static char copyright[] =
39 "@(#) Copyright (c) 1980, 1993\n\
40 	The Regents of the University of California.  All rights reserved.\n";
41 #endif /* not lint */
42 
43 #ifndef lint
44 #if 0
45 static char sccsid[] = "@(#)main.c	8.1 (Berkeley) 6/6/93";
46 #else
47 static char rcsid[] = "$OpenBSD: main.c,v 1.3 1996/09/16 02:26:09 deraadt Exp $";
48 #endif
49 #endif /* not lint */
50 
51 #include "rcv.h"
52 #include <fcntl.h>
53 #include <sys/ioctl.h>
54 #include "extern.h"
55 
56 /*
57  * Mail -- a mail program
58  *
59  * Startup -- interface with user.
60  */
61 
62 jmp_buf	hdrjmp;
63 
64 int
65 main(argc, argv)
66 	int argc;
67 	char *argv[];
68 {
69 	register int i;
70 	struct name *to, *cc, *bcc, *smopts;
71 	char *subject;
72 	char *ef;
73 	char nosrc = 0;
74 	sig_t prevint;
75 
76 	/*
77 	 * Set up a reasonable environment.
78 	 * Figure out whether we are being run interactively,
79 	 * start the SIGCHLD catcher, and so forth.
80 	 */
81 	(void) signal(SIGCHLD, sigchild);
82 	if (isatty(0))
83 		assign("interactive", "");
84 	image = -1;
85 	/*
86 	 * Now, determine how we are being used.
87 	 * We successively pick off - flags.
88 	 * If there is anything left, it is the base of the list
89 	 * of users to mail to.  Argp will be set to point to the
90 	 * first of these users.
91 	 */
92 	ef = NOSTR;
93 	to = NIL;
94 	cc = NIL;
95 	bcc = NIL;
96 	smopts = NIL;
97 	subject = NOSTR;
98 	while ((i = getopt(argc, argv, "INT:b:c:dfins:u:v")) != EOF) {
99 		switch (i) {
100 		case 'T':
101 			/*
102 			 * Next argument is temp file to write which
103 			 * articles have been read/deleted for netnews.
104 			 */
105 			Tflag = optarg;
106 			if ((i = creat(Tflag, 0600)) < 0) {
107 				perror(Tflag);
108 				exit(1);
109 			}
110 			close(i);
111 			break;
112 		case 'u':
113 			/*
114 			 * Next argument is person to pretend to be.
115 			 */
116 			unsetenv("MAIL");
117 			myname = optarg;
118 			break;
119 		case 'i':
120 			/*
121 			 * User wants to ignore interrupts.
122 			 * Set the variable "ignore"
123 			 */
124 			assign("ignore", "");
125 			break;
126 		case 'd':
127 			debug++;
128 			break;
129 		case 's':
130 			/*
131 			 * Give a subject field for sending from
132 			 * non terminal
133 			 */
134 			subject = optarg;
135 			break;
136 		case 'f':
137 			/*
138 			 * User is specifying file to "edit" with Mail,
139 			 * as opposed to reading system mailbox.
140 			 * If no argument is given after -f, we read his
141 			 * mbox file.
142 			 *
143 			 * getopt() can't handle optional arguments, so here
144 			 * is an ugly hack to get around it.
145 			 */
146 			if ((argv[optind]) && (argv[optind][0] != '-'))
147 				ef = argv[optind++];
148 			else
149 				ef = "&";
150 			break;
151 		case 'n':
152 			/*
153 			 * User doesn't want to source /usr/lib/Mail.rc
154 			 */
155 			nosrc++;
156 			break;
157 		case 'N':
158 			/*
159 			 * Avoid initial header printing.
160 			 */
161 			assign("noheader", "");
162 			break;
163 		case 'v':
164 			/*
165 			 * Send mailer verbose flag
166 			 */
167 			assign("verbose", "");
168 			break;
169 		case 'I':
170 			/*
171 			 * We're interactive
172 			 */
173 			assign("interactive", "");
174 			break;
175 		case 'c':
176 			/*
177 			 * Get Carbon Copy Recipient list
178 			 */
179 			cc = cat(cc, nalloc(optarg, GCC));
180 			break;
181 		case 'b':
182 			/*
183 			 * Get Blind Carbon Copy Recipient list
184 			 */
185 			bcc = cat(bcc, nalloc(optarg, GBCC));
186 			break;
187 		case '?':
188 			fputs("\
189 Usage: mail [-iInv] [-s subject] [-c cc-addr] [-b bcc-addr] to-addr ...\n\
190             [- sendmail-options ...]\n\
191        mail [-iInNv] -f [name]\n\
192        mail [-iInNv] [-u user]\n",
193 				stderr);
194 			exit(1);
195 		}
196 	}
197 	for (i = optind; (argv[i]) && (*argv[i] != '-'); i++)
198 		to = cat(to, nalloc(argv[i], GTO));
199 	for (; argv[i]; i++)
200 		smopts = cat(smopts, nalloc(argv[i], 0));
201 	/*
202 	 * Check for inconsistent arguments.
203 	 */
204 	if (to == NIL && (subject != NOSTR || cc != NIL || bcc != NIL)) {
205 		fputs("You must specify direct recipients with -s, -c, or -b.\n", stderr);
206 		exit(1);
207 	}
208 	if (ef != NOSTR && to != NIL) {
209 		fprintf(stderr, "Cannot give -f and people to send to.\n");
210 		exit(1);
211 	}
212 	tinit();
213 	setscreensize();
214 	input = stdin;
215 	rcvmode = !to;
216 	spreserve();
217 	if (!nosrc)
218 		load(_PATH_MASTER_RC);
219 	/*
220 	 * Expand returns a savestr, but load only uses the file name
221 	 * for fopen, so it's safe to do this.
222 	 */
223 	load(expand("~/.mailrc"));
224 	if (!rcvmode) {
225 		mail(to, cc, bcc, smopts, subject);
226 		/*
227 		 * why wait?
228 		 */
229 		exit(senderr);
230 	}
231 	/*
232 	 * Ok, we are reading mail.
233 	 * Decide whether we are editing a mailbox or reading
234 	 * the system mailbox, and open up the right stuff.
235 	 */
236 	if (ef == NOSTR)
237 		ef = "%";
238 	if (setfile(ef) < 0)
239 		exit(1);		/* error already reported */
240 	if (setjmp(hdrjmp) == 0) {
241 		extern char *version;
242 
243 		if ((prevint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
244 			signal(SIGINT, hdrstop);
245 		if (value("quiet") == NOSTR)
246 			printf("Mail version %s.  Type ? for help.\n",
247 				version);
248 		announce();
249 		fflush(stdout);
250 		signal(SIGINT, prevint);
251 	}
252 	commands();
253 	signal(SIGHUP, SIG_IGN);
254 	signal(SIGINT, SIG_IGN);
255 	signal(SIGQUIT, SIG_IGN);
256 	quit();
257 	exit(0);
258 }
259 
260 /*
261  * Interrupt printing of the headers.
262  */
263 void
264 hdrstop(signo)
265 	int signo;
266 {
267 
268 	fflush(stdout);
269 	fprintf(stderr, "\nInterrupt\n");
270 	longjmp(hdrjmp, 1);
271 }
272 
273 /*
274  * Compute what the screen size for printing headers should be.
275  * We use the following algorithm for the height:
276  *	If baud rate < 1200, use  9
277  *	If baud rate = 1200, use 14
278  *	If baud rate > 1200, use 24 or ws_row
279  * Width is either 80 or ws_col;
280  */
281 void
282 setscreensize()
283 {
284 	struct termios tbuf;
285 	struct winsize ws;
286 	speed_t ospeed;
287 
288 	if (ioctl(1, TIOCGWINSZ, (char *) &ws) < 0)
289 		ws.ws_col = ws.ws_row = 0;
290 	if (tcgetattr(1, &tbuf) < 0)
291 		ospeed = 9600;
292 	else
293 		ospeed = cfgetospeed(&tbuf);
294 	if (ospeed < 1200)
295 		screenheight = 9;
296 	else if (ospeed == 1200)
297 		screenheight = 14;
298 	else if (ws.ws_row != 0)
299 		screenheight = ws.ws_row;
300 	else
301 		screenheight = 24;
302 	if ((realscreenheight = ws.ws_row) == 0)
303 		realscreenheight = 24;
304 	if ((screenwidth = ws.ws_col) == 0)
305 		screenwidth = 80;
306 }
307