]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/mail/main.c
RELNOTES: Document the addition of NVMe over Fabrics support
[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 #include "rcv.h"
33 #include <fcntl.h>
34 #include "extern.h"
35
36 /*
37  * Mail -- a mail program
38  *
39  * Startup -- interface with user.
40  */
41 int     msgCount;
42 int     rcvmode;
43 int     sawcom;
44 char    *Tflag;
45 int     senderr;
46 int     edit;
47 int     readonly;
48 int     noreset;
49 int     sourcing;
50 int     loading;
51 int     cond;
52 FILE    *itf;
53 FILE    *otf;
54 int     image;
55 FILE    *input;
56 char    mailname[PATHSIZE];
57 char    prevfile[PATHSIZE];
58 char    *homedir;
59 char    *myname;
60 off_t   mailsize;
61 int     lexnumber;
62 char    lexstring[STRINGLEN];
63 int     regretp;
64 int     regretstack[REGDEP];
65 char    *string_stack[REGDEP];
66 int     numberstack[REGDEP];
67 struct  message *dot;
68 struct  message *message;
69 struct  var     *variables[HSHSIZE];
70 struct  grouphead       *groups[HSHSIZE];
71 struct  ignoretab       ignore[2];
72
73 struct  ignoretab       saveignore[2];
74
75 struct  ignoretab       ignoreall[2];
76 char    **altnames;
77 int     debug;
78 int     screenwidth;
79 int     screenheight;
80
81 int     realscreenheight;
82
83 jmp_buf srbuf;
84
85 static jmp_buf  hdrjmp;
86
87 extern const char *version;
88
89 int
90 main(int argc, char *argv[])
91 {
92         int i;
93         struct name *to, *cc, *bcc, *smopts;
94         char *subject, *replyto;
95         char *ef, *rc;
96         char nosrc = 0;
97         sig_t prevint;
98
99         /*
100          * Set up a reasonable environment.
101          * Figure out whether we are being run interactively,
102          * start the SIGCHLD catcher, and so forth.
103          */
104         (void)signal(SIGCHLD, sigchild);
105         if (isatty(0))
106                 assign("interactive", "");
107         image = -1;
108         /*
109          * Now, determine how we are being used.
110          * We successively pick off - flags.
111          * If there is anything left, it is the base of the list
112          * of users to mail to.  Argp will be set to point to the
113          * first of these users.
114          */
115         ef = NULL;
116         to = NULL;
117         cc = NULL;
118         bcc = NULL;
119         smopts = NULL;
120         subject = NULL;
121         while ((i = getopt(argc, argv, "FEHINT:b:c:edfins:u:v")) != -1) {
122                 switch (i) {
123                 case 'T':
124                         /*
125                          * Next argument is temp file to write which
126                          * articles have been read/deleted for netnews.
127                          */
128                         Tflag = optarg;
129                         if ((i = open(Tflag, O_CREAT | O_TRUNC | O_WRONLY,
130                             0600)) < 0)
131                                 err(1, "%s", Tflag);
132                         (void)close(i);
133                         break;
134                 case 'u':
135                         /*
136                          * Next argument is person to pretend to be.
137                          */
138                         myname = optarg;
139                         unsetenv("MAIL");
140                         break;
141                 case 'i':
142                         /*
143                          * User wants to ignore interrupts.
144                          * Set the variable "ignore"
145                          */
146                         assign("ignore", "");
147                         break;
148                 case 'd':
149                         debug++;
150                         break;
151                 case 'e':
152                         /*
153                          * User wants to check mail and exit.
154                          */
155                         assign("checkmode", "");
156                         break;
157                 case 'H':
158                         /*
159                          * User wants a header summary only.
160                          */
161                         assign("headersummary", "");
162                         break;
163                 case 'F':
164                         /*
165                          * User wants to record messages to files
166                          * named after first recipient username.
167                          */
168                         assign("recordrecip", "");
169                         break;
170                 case 's':
171                         /*
172                          * Give a subject field for sending from
173                          * non terminal
174                          */
175                         subject = optarg;
176                         break;
177                 case 'f':
178                         /*
179                          * User is specifying file to "edit" with Mail,
180                          * as opposed to reading system mailbox.
181                          * If no argument is given after -f, we read his
182                          * mbox file.
183                          *
184                          * getopt() can't handle optional arguments, so here
185                          * is an ugly hack to get around it.
186                          */
187                         if ((argv[optind] != NULL) && (argv[optind][0] != '-'))
188                                 ef = argv[optind++];
189                         else
190                                 ef = "&";
191                         break;
192                 case 'n':
193                         /*
194                          * User doesn't want to source /usr/lib/Mail.rc
195                          */
196                         nosrc++;
197                         break;
198                 case 'N':
199                         /*
200                          * Avoid initial header printing.
201                          */
202                         assign("noheader", "");
203                         break;
204                 case 'v':
205                         /*
206                          * Send mailer verbose flag
207                          */
208                         assign("verbose", "");
209                         break;
210                 case 'I':
211                         /*
212                          * We're interactive
213                          */
214                         assign("interactive", "");
215                         break;
216                 case 'c':
217                         /*
218                          * Get Carbon Copy Recipient list
219                          */
220                         cc = cat(cc, nalloc(optarg, GCC));
221                         break;
222                 case 'b':
223                         /*
224                          * Get Blind Carbon Copy Recipient list
225                          */
226                         bcc = cat(bcc, nalloc(optarg, GBCC));
227                         break;
228                 case 'E':
229                         /*
230                          * Don't send empty files.
231                          */
232                         assign("dontsendempty", "");
233                         break;
234                 case '?':
235                         fprintf(stderr, "\
236 Usage: %s [-dEiInv] [-s subject] [-c cc-addr] [-b bcc-addr] [-F] to-addr ...\n\
237        %*s [-sendmail-option ...]\n\
238        %s [-dEHiInNv] [-F] -f [name]\n\
239        %s [-dEHiInNv] [-F] [-u user]\n\
240        %s [-d] -e [-f name]\n", __progname, (int)strlen(__progname), "",
241                                 __progname, __progname, __progname);
242                         exit(1);
243                 }
244         }
245         for (i = optind; (argv[i] != NULL) && (*argv[i] != '-'); i++)
246                 to = cat(to, nalloc(argv[i], GTO));
247         for (; argv[i] != NULL; i++)
248                 smopts = cat(smopts, nalloc(argv[i], 0));
249         /*
250          * Check for inconsistent arguments.
251          */
252         if (to == NULL && (subject != NULL || cc != NULL || bcc != NULL))
253                 errx(1, "You must specify direct recipients with -s, -c, or -b.");
254         if (ef != NULL && to != NULL)
255                 errx(1, "Cannot give -f and people to send to.");
256         tinit();
257         setscreensize();
258         input = stdin;
259         rcvmode = !to;
260         spreserve();
261         if (!nosrc) {
262                 char *s, *path_rc;
263
264                 if ((path_rc = malloc(sizeof(_PATH_MASTER_RC))) == NULL)
265                         err(1, "malloc(path_rc) failed");
266
267                 strcpy(path_rc, _PATH_MASTER_RC);
268                 while ((s = strsep(&path_rc, ":")) != NULL)
269                         if (*s != '\0')
270                                 load(s);
271         }
272         /*
273          * Expand returns a savestr, but load only uses the file name
274          * for fopen, so it's safe to do this.
275          */
276         if ((rc = getenv("MAILRC")) == NULL)
277                 rc = "~/.mailrc";
278         load(expand(rc));
279
280         replyto = value("REPLYTO");
281         if (!rcvmode) {
282                 mail(to, cc, bcc, smopts, subject, replyto);
283                 /*
284                  * why wait?
285                  */
286                 exit(senderr);
287         }
288
289         if(value("checkmode") != NULL) {
290                 if (ef == NULL)
291                         ef = "%";
292                 if (setfile(ef) <= 0)
293                         /* Either an error has occurred, or no mail */
294                         exit(1);
295                 else
296                         exit(0);
297                 /* NOTREACHED */
298         }
299
300         /*
301          * Ok, we are reading mail.
302          * Decide whether we are editing a mailbox or reading
303          * the system mailbox, and open up the right stuff.
304          */
305         if (ef == NULL)
306                 ef = "%";
307         if (setfile(ef) < 0)
308                 exit(1);                /* error already reported */
309         if (setjmp(hdrjmp) == 0) {
310                 if ((prevint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
311                         (void)signal(SIGINT, hdrstop);
312                 if (value("quiet") == NULL)
313                         printf("Mail version %s.  Type ? for help.\n",
314                                 version);
315                 announce();
316                 (void)fflush(stdout);
317                 (void)signal(SIGINT, prevint);
318         }
319
320         /* If we were in header summary mode, it's time to exit. */
321         if (value("headersummary") != NULL)
322                 exit(0);
323
324         commands();
325         (void)signal(SIGHUP, SIG_IGN);
326         (void)signal(SIGINT, SIG_IGN);
327         (void)signal(SIGQUIT, SIG_IGN);
328         quit();
329         exit(0);
330 }
331
332 /*
333  * Interrupt printing of the headers.
334  */
335 /*ARGSUSED*/
336 void
337 hdrstop(int signo __unused)
338 {
339
340         (void)fflush(stdout);
341         fprintf(stderr, "\nInterrupt\n");
342         longjmp(hdrjmp, 1);
343 }
344
345 /*
346  * Compute what the screen size for printing headers should be.
347  * We use the following algorithm for the height:
348  *      If baud rate < 1200, use  9
349  *      If baud rate = 1200, use 14
350  *      If baud rate > 1200, use 24 or ws_row
351  * Width is either 80 or ws_col;
352  */
353 void
354 setscreensize(void)
355 {
356         struct termios tbuf;
357         struct winsize ws;
358         speed_t speed;
359
360         if (ioctl(1, TIOCGWINSZ, (char *)&ws) < 0)
361                 ws.ws_col = ws.ws_row = 0;
362         if (tcgetattr(1, &tbuf) < 0)
363                 speed = B9600;
364         else
365                 speed = cfgetospeed(&tbuf);
366         if (speed < B1200)
367                 screenheight = 9;
368         else if (speed == B1200)
369                 screenheight = 14;
370         else if (ws.ws_row != 0)
371                 screenheight = ws.ws_row;
372         else
373                 screenheight = 24;
374         if ((realscreenheight = ws.ws_row) == 0)
375                 realscreenheight = 24;
376         if ((screenwidth = ws.ws_col) == 0)
377                 screenwidth = 80;
378 }