xref: /dragonfly/usr.bin/mail/main.c (revision 984263bc)
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 #ifndef lint
35 static char copyright[] =
36 "@(#) Copyright (c) 1980, 1993\n\
37 	The Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39 
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)main.c	8.2 (Berkeley) 4/20/95";
43 #endif
44 #endif /* not lint */
45 #include <sys/cdefs.h>
46 __FBSDID("$FreeBSD: src/usr.bin/mail/main.c,v 1.6.2.5 2003/01/06 05:46:03 mikeh Exp $");
47 
48 #include "rcv.h"
49 #include <fcntl.h>
50 #include "extern.h"
51 
52 /*
53  * Mail -- a mail program
54  *
55  * Startup -- interface with user.
56  */
57 
58 jmp_buf	hdrjmp;
59 
60 extern const char *version;
61 
62 int
63 main(argc, argv)
64 	int argc;
65 	char *argv[];
66 {
67 	int i;
68 	struct name *to, *cc, *bcc, *smopts;
69 	char *subject, *replyto;
70 	char *ef, *rc;
71 	char nosrc = 0;
72 	sig_t prevint;
73 
74 	/*
75 	 * Set up a reasonable environment.
76 	 * Figure out whether we are being run interactively,
77 	 * start the SIGCHLD catcher, and so forth.
78 	 */
79 	(void)signal(SIGCHLD, sigchild);
80 	if (isatty(0))
81 		assign("interactive", "");
82 	image = -1;
83 	/*
84 	 * Now, determine how we are being used.
85 	 * We successively pick off - flags.
86 	 * If there is anything left, it is the base of the list
87 	 * of users to mail to.  Argp will be set to point to the
88 	 * first of these users.
89 	 */
90 	ef = NULL;
91 	to = NULL;
92 	cc = NULL;
93 	bcc = NULL;
94 	smopts = NULL;
95 	subject = NULL;
96 	while ((i = getopt(argc, argv, "EINT:b:c:dfins:u:v")) != -1) {
97 		switch (i) {
98 		case 'T':
99 			/*
100 			 * Next argument is temp file to write which
101 			 * articles have been read/deleted for netnews.
102 			 */
103 			Tflag = optarg;
104 			if ((i = open(Tflag, O_CREAT | O_TRUNC | O_WRONLY,
105 			    0600)) < 0)
106 				err(1, "%s", Tflag);
107 			(void)close(i);
108 			break;
109 		case 'u':
110 			/*
111 			 * Next argument is person to pretend to be.
112 			 */
113 			myname = optarg;
114 			unsetenv("MAIL");
115 			break;
116 		case 'i':
117 			/*
118 			 * User wants to ignore interrupts.
119 			 * Set the variable "ignore"
120 			 */
121 			assign("ignore", "");
122 			break;
123 		case 'd':
124 			debug++;
125 			break;
126 		case 's':
127 			/*
128 			 * Give a subject field for sending from
129 			 * non terminal
130 			 */
131 			subject = optarg;
132 			break;
133 		case 'f':
134 			/*
135 			 * User is specifying file to "edit" with Mail,
136 			 * as opposed to reading system mailbox.
137 			 * If no argument is given after -f, we read his
138 			 * mbox file.
139 			 *
140 			 * getopt() can't handle optional arguments, so here
141 			 * is an ugly hack to get around it.
142 			 */
143 			if ((argv[optind] != NULL) && (argv[optind][0] != '-'))
144 				ef = argv[optind++];
145 			else
146 				ef = "&";
147 			break;
148 		case 'n':
149 			/*
150 			 * User doesn't want to source /usr/lib/Mail.rc
151 			 */
152 			nosrc++;
153 			break;
154 		case 'N':
155 			/*
156 			 * Avoid initial header printing.
157 			 */
158 			assign("noheader", "");
159 			break;
160 		case 'v':
161 			/*
162 			 * Send mailer verbose flag
163 			 */
164 			assign("verbose", "");
165 			break;
166 		case 'I':
167 			/*
168 			 * We're interactive
169 			 */
170 			assign("interactive", "");
171 			break;
172 		case 'c':
173 			/*
174 			 * Get Carbon Copy Recipient list
175 			 */
176 			cc = cat(cc, nalloc(optarg, GCC));
177 			break;
178 		case 'b':
179 			/*
180 			 * Get Blind Carbon Copy Recipient list
181 			 */
182 			bcc = cat(bcc, nalloc(optarg, GBCC));
183 			break;
184 		case 'E':
185 			/*
186 			 * Don't send empty files.
187 			 */
188 			assign("dontsendempty", "");
189 			break;
190 		case '?':
191 			fprintf(stderr, "\
192 Usage: %s [-EiInv] [-s subject] [-c cc-addr] [-b bcc-addr] to-addr ...\n\
193        %*s [- sendmail-options ...]\n\
194        %s [-EiInNv] -f [name]\n\
195        %s [-EiInNv] [-u user]\n",__progname, strlen(__progname), "",
196 			    __progname, __progname);
197 			exit(1);
198 		}
199 	}
200 	for (i = optind; (argv[i] != NULL) && (*argv[i] != '-'); i++)
201 		to = cat(to, nalloc(argv[i], GTO));
202 	for (; argv[i] != NULL; i++)
203 		smopts = cat(smopts, nalloc(argv[i], 0));
204 	/*
205 	 * Check for inconsistent arguments.
206 	 */
207 	if (to == NULL && (subject != NULL || cc != NULL || bcc != NULL))
208 		errx(1, "You must specify direct recipients with -s, -c, or -b.");
209 	if (ef != NULL && to != NULL)
210 		errx(1, "Cannot give -f and people to send to.");
211 	tinit();
212 	setscreensize();
213 	input = stdin;
214 	rcvmode = !to;
215 	spreserve();
216 	if (!nosrc) {
217 		char *s, *path_rc;
218 
219 		if ((path_rc = malloc(sizeof(_PATH_MASTER_RC))) == NULL)
220 			err(1, "malloc(path_rc) failed");
221 
222 		strcpy(path_rc, _PATH_MASTER_RC);
223 		while ((s = strsep(&path_rc, ":")) != NULL)
224 			if (*s != '\0')
225 				load(s);
226 	}
227 	/*
228 	 * Expand returns a savestr, but load only uses the file name
229 	 * for fopen, so it's safe to do this.
230 	 */
231 	if ((rc = getenv("MAILRC")) == NULL)
232 		rc = "~/.mailrc";
233 	load(expand(rc));
234 
235 	replyto = value("REPLYTO");
236 	if (!rcvmode) {
237 		mail(to, cc, bcc, smopts, subject, replyto);
238 		/*
239 		 * why wait?
240 		 */
241 		exit(senderr);
242 	}
243 	/*
244 	 * Ok, we are reading mail.
245 	 * Decide whether we are editing a mailbox or reading
246 	 * the system mailbox, and open up the right stuff.
247 	 */
248 	if (ef == NULL)
249 		ef = "%";
250 	if (setfile(ef) < 0)
251 		exit(1);		/* error already reported */
252 	if (setjmp(hdrjmp) == 0) {
253 		if ((prevint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
254 			(void)signal(SIGINT, hdrstop);
255 		if (value("quiet") == NULL)
256 			printf("Mail version %s.  Type ? for help.\n",
257 				version);
258 		announce();
259 		(void)fflush(stdout);
260 		(void)signal(SIGINT, prevint);
261 	}
262 	commands();
263 	(void)signal(SIGHUP, SIG_IGN);
264 	(void)signal(SIGINT, SIG_IGN);
265 	(void)signal(SIGQUIT, SIG_IGN);
266 	quit();
267 	exit(0);
268 }
269 
270 /*
271  * Interrupt printing of the headers.
272  */
273 /*ARGSUSED*/
274 void
275 hdrstop(signo)
276 	int signo;
277 {
278 
279 	(void)fflush(stdout);
280 	fprintf(stderr, "\nInterrupt\n");
281 	longjmp(hdrjmp, 1);
282 }
283 
284 /*
285  * Compute what the screen size for printing headers should be.
286  * We use the following algorithm for the height:
287  *	If baud rate < 1200, use  9
288  *	If baud rate = 1200, use 14
289  *	If baud rate > 1200, use 24 or ws_row
290  * Width is either 80 or ws_col;
291  */
292 void
293 setscreensize()
294 {
295 	struct termios tbuf;
296 	struct winsize ws;
297 	speed_t speed;
298 
299 	if (ioctl(1, TIOCGWINSZ, (char *)&ws) < 0)
300 		ws.ws_col = ws.ws_row = 0;
301 	if (tcgetattr(1, &tbuf) < 0)
302 		speed = B9600;
303 	else
304 		speed = cfgetospeed(&tbuf);
305 	if (speed < B1200)
306 		screenheight = 9;
307 	else if (speed == B1200)
308 		screenheight = 14;
309 	else if (ws.ws_row != 0)
310 		screenheight = ws.ws_row;
311 	else
312 		screenheight = 24;
313 	if ((realscreenheight = ws.ws_row) == 0)
314 		realscreenheight = 24;
315 	if ((screenwidth = ws.ws_col) == 0)
316 		screenwidth = 80;
317 }
318