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