18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni *
49b50d902SRodney W. Grimes * Copyright (c) 1980, 1993
59b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved.
69b50d902SRodney W. Grimes *
79b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without
89b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions
99b50d902SRodney W. Grimes * are met:
109b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
119b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer.
129b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
139b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
149b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
169b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software
179b50d902SRodney W. Grimes * without specific prior written permission.
189b50d902SRodney W. Grimes *
199b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
209b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
239b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
249b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
259b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
279b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
289b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299b50d902SRodney W. Grimes * SUCH DAMAGE.
309b50d902SRodney W. Grimes */
319b50d902SRodney W. Grimes
329b50d902SRodney W. Grimes #include "rcv.h"
339b50d902SRodney W. Grimes #include <fcntl.h>
349b50d902SRodney W. Grimes #include "extern.h"
359b50d902SRodney W. Grimes
369b50d902SRodney W. Grimes /*
379b50d902SRodney W. Grimes * Mail -- a mail program
389b50d902SRodney W. Grimes *
399b50d902SRodney W. Grimes * Startup -- interface with user.
409b50d902SRodney W. Grimes */
41*a86ddfe8SKyle Evans int msgCount;
42*a86ddfe8SKyle Evans int rcvmode;
43*a86ddfe8SKyle Evans int sawcom;
44*a86ddfe8SKyle Evans char *Tflag;
45*a86ddfe8SKyle Evans int senderr;
46*a86ddfe8SKyle Evans int edit;
47*a86ddfe8SKyle Evans int readonly;
48*a86ddfe8SKyle Evans int noreset;
49*a86ddfe8SKyle Evans int sourcing;
50*a86ddfe8SKyle Evans int loading;
51*a86ddfe8SKyle Evans int cond;
52*a86ddfe8SKyle Evans FILE *itf;
53*a86ddfe8SKyle Evans FILE *otf;
54*a86ddfe8SKyle Evans int image;
55*a86ddfe8SKyle Evans FILE *input;
56*a86ddfe8SKyle Evans char mailname[PATHSIZE];
57*a86ddfe8SKyle Evans char prevfile[PATHSIZE];
58*a86ddfe8SKyle Evans char *homedir;
59*a86ddfe8SKyle Evans char *myname;
60*a86ddfe8SKyle Evans off_t mailsize;
61*a86ddfe8SKyle Evans int lexnumber;
62*a86ddfe8SKyle Evans char lexstring[STRINGLEN];
63*a86ddfe8SKyle Evans int regretp;
64*a86ddfe8SKyle Evans int regretstack[REGDEP];
65*a86ddfe8SKyle Evans char *string_stack[REGDEP];
66*a86ddfe8SKyle Evans int numberstack[REGDEP];
67*a86ddfe8SKyle Evans struct message *dot;
68*a86ddfe8SKyle Evans struct message *message;
69*a86ddfe8SKyle Evans struct var *variables[HSHSIZE];
70*a86ddfe8SKyle Evans struct grouphead *groups[HSHSIZE];
71*a86ddfe8SKyle Evans struct ignoretab ignore[2];
72*a86ddfe8SKyle Evans
73*a86ddfe8SKyle Evans struct ignoretab saveignore[2];
74*a86ddfe8SKyle Evans
75*a86ddfe8SKyle Evans struct ignoretab ignoreall[2];
76*a86ddfe8SKyle Evans char **altnames;
77*a86ddfe8SKyle Evans int debug;
78*a86ddfe8SKyle Evans int screenwidth;
79*a86ddfe8SKyle Evans int screenheight;
80*a86ddfe8SKyle Evans
81*a86ddfe8SKyle Evans int realscreenheight;
82*a86ddfe8SKyle Evans
83*a86ddfe8SKyle Evans jmp_buf srbuf;
849b50d902SRodney W. Grimes
85e7d53813SDiomidis Spinellis static jmp_buf hdrjmp;
869b50d902SRodney W. Grimes
879ce73e90SMike Heffner extern const char *version;
889ce73e90SMike Heffner
899b50d902SRodney W. Grimes int
main(int argc,char * argv[])906d8484b0SPhilippe Charnier main(int argc, char *argv[])
919b50d902SRodney W. Grimes {
929ce73e90SMike Heffner int i;
939b50d902SRodney W. Grimes struct name *to, *cc, *bcc, *smopts;
9499bd6601SJoerg Wunsch char *subject, *replyto;
95856f23edSMike Heffner char *ef, *rc;
969b50d902SRodney W. Grimes char nosrc = 0;
979b50d902SRodney W. Grimes sig_t prevint;
989b50d902SRodney W. Grimes
999b50d902SRodney W. Grimes /*
1009b50d902SRodney W. Grimes * Set up a reasonable environment.
1019b50d902SRodney W. Grimes * Figure out whether we are being run interactively,
1029b50d902SRodney W. Grimes * start the SIGCHLD catcher, and so forth.
1039b50d902SRodney W. Grimes */
1049b50d902SRodney W. Grimes (void)signal(SIGCHLD, sigchild);
1059b50d902SRodney W. Grimes if (isatty(0))
1069b50d902SRodney W. Grimes assign("interactive", "");
1079b50d902SRodney W. Grimes image = -1;
1089b50d902SRodney W. Grimes /*
1099b50d902SRodney W. Grimes * Now, determine how we are being used.
1109b50d902SRodney W. Grimes * We successively pick off - flags.
1119b50d902SRodney W. Grimes * If there is anything left, it is the base of the list
1129b50d902SRodney W. Grimes * of users to mail to. Argp will be set to point to the
1139b50d902SRodney W. Grimes * first of these users.
1149b50d902SRodney W. Grimes */
1159ce73e90SMike Heffner ef = NULL;
1169ce73e90SMike Heffner to = NULL;
1179ce73e90SMike Heffner cc = NULL;
1189ce73e90SMike Heffner bcc = NULL;
1199ce73e90SMike Heffner smopts = NULL;
1209ce73e90SMike Heffner subject = NULL;
121c92dfc23SMike Heffner while ((i = getopt(argc, argv, "FEHINT:b:c:edfins:u:v")) != -1) {
1229b50d902SRodney W. Grimes switch (i) {
1239b50d902SRodney W. Grimes case 'T':
1249b50d902SRodney W. Grimes /*
1259b50d902SRodney W. Grimes * Next argument is temp file to write which
1269b50d902SRodney W. Grimes * articles have been read/deleted for netnews.
1279b50d902SRodney W. Grimes */
1289b50d902SRodney W. Grimes Tflag = optarg;
1290c3a8314SMike Heffner if ((i = open(Tflag, O_CREAT | O_TRUNC | O_WRONLY,
1300c3a8314SMike Heffner 0600)) < 0)
1310c3a8314SMike Heffner err(1, "%s", Tflag);
1329ce73e90SMike Heffner (void)close(i);
1339b50d902SRodney W. Grimes break;
1349b50d902SRodney W. Grimes case 'u':
1359b50d902SRodney W. Grimes /*
1369b50d902SRodney W. Grimes * Next argument is person to pretend to be.
1379b50d902SRodney W. Grimes */
1389b50d902SRodney W. Grimes myname = optarg;
13949936df3SJean-Marc Zucconi unsetenv("MAIL");
1409b50d902SRodney W. Grimes break;
1419b50d902SRodney W. Grimes case 'i':
1429b50d902SRodney W. Grimes /*
1439b50d902SRodney W. Grimes * User wants to ignore interrupts.
1449b50d902SRodney W. Grimes * Set the variable "ignore"
1459b50d902SRodney W. Grimes */
1469b50d902SRodney W. Grimes assign("ignore", "");
1479b50d902SRodney W. Grimes break;
1489b50d902SRodney W. Grimes case 'd':
1499b50d902SRodney W. Grimes debug++;
1509b50d902SRodney W. Grimes break;
151c92dfc23SMike Heffner case 'e':
152c92dfc23SMike Heffner /*
153c92dfc23SMike Heffner * User wants to check mail and exit.
154c92dfc23SMike Heffner */
155c92dfc23SMike Heffner assign("checkmode", "");
156c92dfc23SMike Heffner break;
157c92dfc23SMike Heffner case 'H':
158c92dfc23SMike Heffner /*
159c92dfc23SMike Heffner * User wants a header summary only.
160c92dfc23SMike Heffner */
161c92dfc23SMike Heffner assign("headersummary", "");
162c92dfc23SMike Heffner break;
163c92dfc23SMike Heffner case 'F':
164c92dfc23SMike Heffner /*
165c92dfc23SMike Heffner * User wants to record messages to files
166c92dfc23SMike Heffner * named after first recipient username.
167c92dfc23SMike Heffner */
168c92dfc23SMike Heffner assign("recordrecip", "");
169c92dfc23SMike Heffner break;
1709b50d902SRodney W. Grimes case 's':
1719b50d902SRodney W. Grimes /*
1729b50d902SRodney W. Grimes * Give a subject field for sending from
1739b50d902SRodney W. Grimes * non terminal
1749b50d902SRodney W. Grimes */
1759b50d902SRodney W. Grimes subject = optarg;
1769b50d902SRodney W. Grimes break;
1779b50d902SRodney W. Grimes case 'f':
1789b50d902SRodney W. Grimes /*
1799b50d902SRodney W. Grimes * User is specifying file to "edit" with Mail,
1809b50d902SRodney W. Grimes * as opposed to reading system mailbox.
1819b50d902SRodney W. Grimes * If no argument is given after -f, we read his
1829b50d902SRodney W. Grimes * mbox file.
1839b50d902SRodney W. Grimes *
1849b50d902SRodney W. Grimes * getopt() can't handle optional arguments, so here
1859b50d902SRodney W. Grimes * is an ugly hack to get around it.
1869b50d902SRodney W. Grimes */
1879ce73e90SMike Heffner if ((argv[optind] != NULL) && (argv[optind][0] != '-'))
1889b50d902SRodney W. Grimes ef = argv[optind++];
1899b50d902SRodney W. Grimes else
1909b50d902SRodney W. Grimes ef = "&";
1919b50d902SRodney W. Grimes break;
1929b50d902SRodney W. Grimes case 'n':
1939b50d902SRodney W. Grimes /*
1949b50d902SRodney W. Grimes * User doesn't want to source /usr/lib/Mail.rc
1959b50d902SRodney W. Grimes */
1969b50d902SRodney W. Grimes nosrc++;
1979b50d902SRodney W. Grimes break;
1989b50d902SRodney W. Grimes case 'N':
1999b50d902SRodney W. Grimes /*
2009b50d902SRodney W. Grimes * Avoid initial header printing.
2019b50d902SRodney W. Grimes */
2029b50d902SRodney W. Grimes assign("noheader", "");
2039b50d902SRodney W. Grimes break;
2049b50d902SRodney W. Grimes case 'v':
2059b50d902SRodney W. Grimes /*
2069b50d902SRodney W. Grimes * Send mailer verbose flag
2079b50d902SRodney W. Grimes */
2089b50d902SRodney W. Grimes assign("verbose", "");
2099b50d902SRodney W. Grimes break;
2109b50d902SRodney W. Grimes case 'I':
2119b50d902SRodney W. Grimes /*
2129b50d902SRodney W. Grimes * We're interactive
2139b50d902SRodney W. Grimes */
2149b50d902SRodney W. Grimes assign("interactive", "");
2159b50d902SRodney W. Grimes break;
2169b50d902SRodney W. Grimes case 'c':
2179b50d902SRodney W. Grimes /*
2189b50d902SRodney W. Grimes * Get Carbon Copy Recipient list
2199b50d902SRodney W. Grimes */
2209b50d902SRodney W. Grimes cc = cat(cc, nalloc(optarg, GCC));
2219b50d902SRodney W. Grimes break;
2229b50d902SRodney W. Grimes case 'b':
2239b50d902SRodney W. Grimes /*
2249b50d902SRodney W. Grimes * Get Blind Carbon Copy Recipient list
2259b50d902SRodney W. Grimes */
2269b50d902SRodney W. Grimes bcc = cat(bcc, nalloc(optarg, GBCC));
2279b50d902SRodney W. Grimes break;
228dcd24e27SMike Heffner case 'E':
229dcd24e27SMike Heffner /*
230dcd24e27SMike Heffner * Don't send empty files.
231dcd24e27SMike Heffner */
232dcd24e27SMike Heffner assign("dontsendempty", "");
233dcd24e27SMike Heffner break;
2349b50d902SRodney W. Grimes case '?':
2350c3a8314SMike Heffner fprintf(stderr, "\
236e53e5e56SYaroslav Tykhiy Usage: %s [-dEiInv] [-s subject] [-c cc-addr] [-b bcc-addr] [-F] to-addr ...\n\
237e53e5e56SYaroslav Tykhiy %*s [-sendmail-option ...]\n\
238e53e5e56SYaroslav Tykhiy %s [-dEHiInNv] [-F] -f [name]\n\
239e53e5e56SYaroslav Tykhiy %s [-dEHiInNv] [-F] [-u user]\n\
240081aa516SDimitry Andric %s [-d] -e [-f name]\n", __progname, (int)strlen(__progname), "",
241e53e5e56SYaroslav Tykhiy __progname, __progname, __progname);
2429b50d902SRodney W. Grimes exit(1);
2439b50d902SRodney W. Grimes }
2449b50d902SRodney W. Grimes }
2459ce73e90SMike Heffner for (i = optind; (argv[i] != NULL) && (*argv[i] != '-'); i++)
2469b50d902SRodney W. Grimes to = cat(to, nalloc(argv[i], GTO));
2479ce73e90SMike Heffner for (; argv[i] != NULL; i++)
2489b50d902SRodney W. Grimes smopts = cat(smopts, nalloc(argv[i], 0));
2499b50d902SRodney W. Grimes /*
2509b50d902SRodney W. Grimes * Check for inconsistent arguments.
2519b50d902SRodney W. Grimes */
2529ce73e90SMike Heffner if (to == NULL && (subject != NULL || cc != NULL || bcc != NULL))
2530c3a8314SMike Heffner errx(1, "You must specify direct recipients with -s, -c, or -b.");
2549ce73e90SMike Heffner if (ef != NULL && to != NULL)
2550c3a8314SMike Heffner errx(1, "Cannot give -f and people to send to.");
2569b50d902SRodney W. Grimes tinit();
2579b50d902SRodney W. Grimes setscreensize();
2589b50d902SRodney W. Grimes input = stdin;
2599b50d902SRodney W. Grimes rcvmode = !to;
2609b50d902SRodney W. Grimes spreserve();
261e9b074c3SJordan K. Hubbard if (!nosrc) {
262e9b074c3SJordan K. Hubbard char *s, *path_rc;
263e9b074c3SJordan K. Hubbard
2640c3a8314SMike Heffner if ((path_rc = malloc(sizeof(_PATH_MASTER_RC))) == NULL)
2650c3a8314SMike Heffner err(1, "malloc(path_rc) failed");
266e9b074c3SJordan K. Hubbard
267e9b074c3SJordan K. Hubbard strcpy(path_rc, _PATH_MASTER_RC);
268e9b074c3SJordan K. Hubbard while ((s = strsep(&path_rc, ":")) != NULL)
269e9b074c3SJordan K. Hubbard if (*s != '\0')
270e9b074c3SJordan K. Hubbard load(s);
271e9b074c3SJordan K. Hubbard }
2729b50d902SRodney W. Grimes /*
2739b50d902SRodney W. Grimes * Expand returns a savestr, but load only uses the file name
2749b50d902SRodney W. Grimes * for fopen, so it's safe to do this.
2759b50d902SRodney W. Grimes */
276856f23edSMike Heffner if ((rc = getenv("MAILRC")) == NULL)
277856f23edSMike Heffner rc = "~/.mailrc";
278856f23edSMike Heffner load(expand(rc));
27959c3f4f7SMike Heffner
28059c3f4f7SMike Heffner replyto = value("REPLYTO");
2819b50d902SRodney W. Grimes if (!rcvmode) {
28299bd6601SJoerg Wunsch mail(to, cc, bcc, smopts, subject, replyto);
2839b50d902SRodney W. Grimes /*
2849b50d902SRodney W. Grimes * why wait?
2859b50d902SRodney W. Grimes */
2869b50d902SRodney W. Grimes exit(senderr);
2879b50d902SRodney W. Grimes }
288c92dfc23SMike Heffner
289c92dfc23SMike Heffner if(value("checkmode") != NULL) {
290c92dfc23SMike Heffner if (ef == NULL)
291c92dfc23SMike Heffner ef = "%";
292c92dfc23SMike Heffner if (setfile(ef) <= 0)
293389ae6c6SUlrich Spörlein /* Either an error has occurred, or no mail */
294c92dfc23SMike Heffner exit(1);
295c92dfc23SMike Heffner else
296c92dfc23SMike Heffner exit(0);
297c92dfc23SMike Heffner /* NOTREACHED */
298c92dfc23SMike Heffner }
299c92dfc23SMike Heffner
3009b50d902SRodney W. Grimes /*
3019b50d902SRodney W. Grimes * Ok, we are reading mail.
3029b50d902SRodney W. Grimes * Decide whether we are editing a mailbox or reading
3039b50d902SRodney W. Grimes * the system mailbox, and open up the right stuff.
3049b50d902SRodney W. Grimes */
3059ce73e90SMike Heffner if (ef == NULL)
3069b50d902SRodney W. Grimes ef = "%";
3079b50d902SRodney W. Grimes if (setfile(ef) < 0)
3089b50d902SRodney W. Grimes exit(1); /* error already reported */
3099b50d902SRodney W. Grimes if (setjmp(hdrjmp) == 0) {
3109b50d902SRodney W. Grimes if ((prevint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
3119ce73e90SMike Heffner (void)signal(SIGINT, hdrstop);
3129ce73e90SMike Heffner if (value("quiet") == NULL)
3139b50d902SRodney W. Grimes printf("Mail version %s. Type ? for help.\n",
3149b50d902SRodney W. Grimes version);
3159b50d902SRodney W. Grimes announce();
3169ce73e90SMike Heffner (void)fflush(stdout);
3179ce73e90SMike Heffner (void)signal(SIGINT, prevint);
3189b50d902SRodney W. Grimes }
319c92dfc23SMike Heffner
320c92dfc23SMike Heffner /* If we were in header summary mode, it's time to exit. */
321c92dfc23SMike Heffner if (value("headersummary") != NULL)
322c92dfc23SMike Heffner exit(0);
323c92dfc23SMike Heffner
3249b50d902SRodney W. Grimes commands();
3259ce73e90SMike Heffner (void)signal(SIGHUP, SIG_IGN);
3269ce73e90SMike Heffner (void)signal(SIGINT, SIG_IGN);
3279ce73e90SMike Heffner (void)signal(SIGQUIT, SIG_IGN);
3289b50d902SRodney W. Grimes quit();
3299b50d902SRodney W. Grimes exit(0);
3309b50d902SRodney W. Grimes }
3319b50d902SRodney W. Grimes
3329b50d902SRodney W. Grimes /*
3339b50d902SRodney W. Grimes * Interrupt printing of the headers.
3349b50d902SRodney W. Grimes */
3359ce73e90SMike Heffner /*ARGSUSED*/
3369b50d902SRodney W. Grimes void
hdrstop(int signo __unused)3376d8484b0SPhilippe Charnier hdrstop(int signo __unused)
3389b50d902SRodney W. Grimes {
3399b50d902SRodney W. Grimes
3409ce73e90SMike Heffner (void)fflush(stdout);
3419b50d902SRodney W. Grimes fprintf(stderr, "\nInterrupt\n");
3429b50d902SRodney W. Grimes longjmp(hdrjmp, 1);
3439b50d902SRodney W. Grimes }
3449b50d902SRodney W. Grimes
3459b50d902SRodney W. Grimes /*
3469b50d902SRodney W. Grimes * Compute what the screen size for printing headers should be.
3479b50d902SRodney W. Grimes * We use the following algorithm for the height:
3489b50d902SRodney W. Grimes * If baud rate < 1200, use 9
3499b50d902SRodney W. Grimes * If baud rate = 1200, use 14
3509b50d902SRodney W. Grimes * If baud rate > 1200, use 24 or ws_row
3519b50d902SRodney W. Grimes * Width is either 80 or ws_col;
3529b50d902SRodney W. Grimes */
3539b50d902SRodney W. Grimes void
setscreensize(void)3546d8484b0SPhilippe Charnier setscreensize(void)
3559b50d902SRodney W. Grimes {
356856f23edSMike Heffner struct termios tbuf;
3579b50d902SRodney W. Grimes struct winsize ws;
358856f23edSMike Heffner speed_t speed;
3599b50d902SRodney W. Grimes
3609b50d902SRodney W. Grimes if (ioctl(1, TIOCGWINSZ, (char *)&ws) < 0)
3619b50d902SRodney W. Grimes ws.ws_col = ws.ws_row = 0;
362856f23edSMike Heffner if (tcgetattr(1, &tbuf) < 0)
3637c6d202aSPeter Wemm speed = B9600;
364856f23edSMike Heffner else
365856f23edSMike Heffner speed = cfgetospeed(&tbuf);
3667c6d202aSPeter Wemm if (speed < B1200)
3679b50d902SRodney W. Grimes screenheight = 9;
3687c6d202aSPeter Wemm else if (speed == B1200)
3699b50d902SRodney W. Grimes screenheight = 14;
3709b50d902SRodney W. Grimes else if (ws.ws_row != 0)
3719b50d902SRodney W. Grimes screenheight = ws.ws_row;
3729b50d902SRodney W. Grimes else
3739b50d902SRodney W. Grimes screenheight = 24;
3749b50d902SRodney W. Grimes if ((realscreenheight = ws.ws_row) == 0)
3759b50d902SRodney W. Grimes realscreenheight = 24;
3769b50d902SRodney W. Grimes if ((screenwidth = ws.ws_col) == 0)
3779b50d902SRodney W. Grimes screenwidth = 80;
3789b50d902SRodney W. Grimes }
379