]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/mail/main.c
Add two missing eventhandler.h headers
[FreeBSD/FreeBSD.git] / usr.bin / mail / main.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1980, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #ifndef lint
33 static const char copyright[] =
34 "@(#) Copyright (c) 1980, 1993\n\
35         The Regents of the University of California.  All rights reserved.\n";
36 #endif /* not lint */
37
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)main.c      8.2 (Berkeley) 4/20/95";
41 #endif
42 #endif /* not lint */
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD$");
45
46 #include "rcv.h"
47 #include <fcntl.h>
48 #include "extern.h"
49
50 /*
51  * Mail -- a mail program
52  *
53  * Startup -- interface with user.
54  */
55
56 static jmp_buf  hdrjmp;
57
58 extern const char *version;
59
60 int
61 main(int argc, char *argv[])
62 {
63         int i;
64         struct name *to, *cc, *bcc, *smopts;
65         char *subject, *replyto;
66         char *ef, *rc;
67         char nosrc = 0;
68         sig_t prevint;
69
70         /*
71          * Set up a reasonable environment.
72          * Figure out whether we are being run interactively,
73          * start the SIGCHLD catcher, and so forth.
74          */
75         (void)signal(SIGCHLD, sigchild);
76         if (isatty(0))
77                 assign("interactive", "");
78         image = -1;
79         /*
80          * Now, determine how we are being used.
81          * We successively pick off - flags.
82          * If there is anything left, it is the base of the list
83          * of users to mail to.  Argp will be set to point to the
84          * first of these users.
85          */
86         ef = NULL;
87         to = NULL;
88         cc = NULL;
89         bcc = NULL;
90         smopts = NULL;
91         subject = NULL;
92         while ((i = getopt(argc, argv, "FEHINT:b:c:edfins:u:v")) != -1) {
93                 switch (i) {
94                 case 'T':
95                         /*
96                          * Next argument is temp file to write which
97                          * articles have been read/deleted for netnews.
98                          */
99                         Tflag = optarg;
100                         if ((i = open(Tflag, O_CREAT | O_TRUNC | O_WRONLY,
101                             0600)) < 0)
102                                 err(1, "%s", Tflag);
103                         (void)close(i);
104                         break;
105                 case 'u':
106                         /*
107                          * Next argument is person to pretend to be.
108                          */
109                         myname = optarg;
110                         unsetenv("MAIL");
111                         break;
112                 case 'i':
113                         /*
114                          * User wants to ignore interrupts.
115                          * Set the variable "ignore"
116                          */
117                         assign("ignore", "");
118                         break;
119                 case 'd':
120                         debug++;
121                         break;
122                 case 'e':
123                         /*
124                          * User wants to check mail and exit.
125                          */
126                         assign("checkmode", "");
127                         break;
128                 case 'H':
129                         /*
130                          * User wants a header summary only.
131                          */
132                         assign("headersummary", "");
133                         break;
134                 case 'F':
135                         /*
136                          * User wants to record messages to files
137                          * named after first recipient username.
138                          */
139                         assign("recordrecip", "");
140                         break;
141                 case 's':
142                         /*
143                          * Give a subject field for sending from
144                          * non terminal
145                          */
146                         subject = optarg;
147                         break;
148                 case 'f':
149                         /*
150                          * User is specifying file to "edit" with Mail,
151                          * as opposed to reading system mailbox.
152                          * If no argument is given after -f, we read his
153                          * mbox file.
154                          *
155                          * getopt() can't handle optional arguments, so here
156                          * is an ugly hack to get around it.
157                          */
158                         if ((argv[optind] != NULL) && (argv[optind][0] != '-'))
159                                 ef = argv[optind++];
160                         else
161                                 ef = "&";
162                         break;
163                 case 'n':
164                         /*
165                          * User doesn't want to source /usr/lib/Mail.rc
166                          */
167                         nosrc++;
168                         break;
169                 case 'N':
170                         /*
171                          * Avoid initial header printing.
172                          */
173                         assign("noheader", "");
174                         break;
175                 case 'v':
176                         /*
177                          * Send mailer verbose flag
178                          */
179                         assign("verbose", "");
180                         break;
181                 case 'I':
182                         /*
183                          * We're interactive
184                          */
185                         assign("interactive", "");
186                         break;
187                 case 'c':
188                         /*
189                          * Get Carbon Copy Recipient list
190                          */
191                         cc = cat(cc, nalloc(optarg, GCC));
192                         break;
193                 case 'b':
194                         /*
195                          * Get Blind Carbon Copy Recipient list
196                          */
197                         bcc = cat(bcc, nalloc(optarg, GBCC));
198                         break;
199                 case 'E':
200                         /*
201                          * Don't send empty files.
202                          */
203                         assign("dontsendempty", "");
204                         break;
205                 case '?':
206                         fprintf(stderr, "\
207 Usage: %s [-dEiInv] [-s subject] [-c cc-addr] [-b bcc-addr] [-F] to-addr ...\n\
208        %*s [-sendmail-option ...]\n\
209        %s [-dEHiInNv] [-F] -f [name]\n\
210        %s [-dEHiInNv] [-F] [-u user]\n\
211        %s [-d] -e [-f name]\n", __progname, (int)strlen(__progname), "",
212                                 __progname, __progname, __progname);
213                         exit(1);
214                 }
215         }
216         for (i = optind; (argv[i] != NULL) && (*argv[i] != '-'); i++)
217                 to = cat(to, nalloc(argv[i], GTO));
218         for (; argv[i] != NULL; i++)
219                 smopts = cat(smopts, nalloc(argv[i], 0));
220         /*
221          * Check for inconsistent arguments.
222          */
223         if (to == NULL && (subject != NULL || cc != NULL || bcc != NULL))
224                 errx(1, "You must specify direct recipients with -s, -c, or -b.");
225         if (ef != NULL && to != NULL)
226                 errx(1, "Cannot give -f and people to send to.");
227         tinit();
228         setscreensize();
229         input = stdin;
230         rcvmode = !to;
231         spreserve();
232         if (!nosrc) {
233                 char *s, *path_rc;
234
235                 if ((path_rc = malloc(sizeof(_PATH_MASTER_RC))) == NULL)
236                         err(1, "malloc(path_rc) failed");
237
238                 strcpy(path_rc, _PATH_MASTER_RC);
239                 while ((s = strsep(&path_rc, ":")) != NULL)
240                         if (*s != '\0')
241                                 load(s);
242         }
243         /*
244          * Expand returns a savestr, but load only uses the file name
245          * for fopen, so it's safe to do this.
246          */
247         if ((rc = getenv("MAILRC")) == NULL)
248                 rc = "~/.mailrc";
249         load(expand(rc));
250
251         replyto = value("REPLYTO");
252         if (!rcvmode) {
253                 mail(to, cc, bcc, smopts, subject, replyto);
254                 /*
255                  * why wait?
256                  */
257                 exit(senderr);
258         }
259
260         if(value("checkmode") != NULL) {
261                 if (ef == NULL)
262                         ef = "%";
263                 if (setfile(ef) <= 0)
264                         /* Either an error has occurred, or no mail */
265                         exit(1);
266                 else
267                         exit(0);
268                 /* NOTREACHED */
269         }
270
271         /*
272          * Ok, we are reading mail.
273          * Decide whether we are editing a mailbox or reading
274          * the system mailbox, and open up the right stuff.
275          */
276         if (ef == NULL)
277                 ef = "%";
278         if (setfile(ef) < 0)
279                 exit(1);                /* error already reported */
280         if (setjmp(hdrjmp) == 0) {
281                 if ((prevint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
282                         (void)signal(SIGINT, hdrstop);
283                 if (value("quiet") == NULL)
284                         printf("Mail version %s.  Type ? for help.\n",
285                                 version);
286                 announce();
287                 (void)fflush(stdout);
288                 (void)signal(SIGINT, prevint);
289         }
290
291         /* If we were in header summary mode, it's time to exit. */
292         if (value("headersummary") != NULL)
293                 exit(0);
294
295         commands();
296         (void)signal(SIGHUP, SIG_IGN);
297         (void)signal(SIGINT, SIG_IGN);
298         (void)signal(SIGQUIT, SIG_IGN);
299         quit();
300         exit(0);
301 }
302
303 /*
304  * Interrupt printing of the headers.
305  */
306 /*ARGSUSED*/
307 void
308 hdrstop(int signo __unused)
309 {
310
311         (void)fflush(stdout);
312         fprintf(stderr, "\nInterrupt\n");
313         longjmp(hdrjmp, 1);
314 }
315
316 /*
317  * Compute what the screen size for printing headers should be.
318  * We use the following algorithm for the height:
319  *      If baud rate < 1200, use  9
320  *      If baud rate = 1200, use 14
321  *      If baud rate > 1200, use 24 or ws_row
322  * Width is either 80 or ws_col;
323  */
324 void
325 setscreensize(void)
326 {
327         struct termios tbuf;
328         struct winsize ws;
329         speed_t speed;
330
331         if (ioctl(1, TIOCGWINSZ, (char *)&ws) < 0)
332                 ws.ws_col = ws.ws_row = 0;
333         if (tcgetattr(1, &tbuf) < 0)
334                 speed = B9600;
335         else
336                 speed = cfgetospeed(&tbuf);
337         if (speed < B1200)
338                 screenheight = 9;
339         else if (speed == B1200)
340                 screenheight = 14;
341         else if (ws.ws_row != 0)
342                 screenheight = ws.ws_row;
343         else
344                 screenheight = 24;
345         if ((realscreenheight = ws.ws_row) == 0)
346                 realscreenheight = 24;
347         if ((screenwidth = ws.ws_col) == 0)
348                 screenwidth = 80;
349 }