Annotation of src/usr.bin/mail/main.c, Revision 1.35
1.35 ! deraadt 1: /* $OpenBSD: main.c,v 1.34 2019/06/28 13:35:02 deraadt Exp $ */
1.5 millert 2: /* $NetBSD: main.c,v 1.7 1997/05/13 06:15:57 mikel Exp $ */
1.2 deraadt 3:
1.1 deraadt 4: /*
5: * Copyright (c) 1980, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
1.18 millert 16: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: #include "rcv.h"
34: #include <fcntl.h>
1.2 deraadt 35: #include <sys/ioctl.h>
1.1 deraadt 36: #include "extern.h"
1.35 ! deraadt 37:
! 38: int msgCount; /* Count of messages read in */
! 39: int rcvmode; /* True if receiving mail */
! 40: int sawcom; /* Set after first command */
! 41: int senderr; /* An error while checking */
! 42: int edit; /* Indicates editing a file */
! 43: int readonly; /* Will be unable to rewrite file */
! 44: int noreset; /* String resets suspended */
! 45: int sourcing; /* Currently reading variant file */
! 46: int loading; /* Loading user definitions */
! 47: int cond; /* Current state of conditional exc. */
! 48: FILE *itf; /* Input temp file buffer */
! 49: FILE *otf; /* Output temp file buffer */
! 50: int image; /* File descriptor for image of msg */
! 51: FILE *input; /* Current command input file */
! 52: char mailname[PATHSIZE]; /* Name of current file */
! 53: char prevfile[PATHSIZE]; /* Name of previous file */
! 54: char *homedir; /* Path name of home directory */
! 55: const char
! 56: *myname; /* My login name */
! 57: off_t mailsize; /* Size of system mailbox */
! 58: int lexnumber; /* Number of TNUMBER from scan() */
! 59: char lexstring[STRINGLEN]; /* String from TSTRING, scan() */
! 60: int regretp; /* Pointer to TOS of regret tokens */
! 61: int regretstack[REGDEP]; /* Stack of regretted tokens */
! 62: char *string_stack[REGDEP]; /* Stack of regretted strings */
! 63: int numberstack[REGDEP]; /* Stack of regretted numbers */
! 64: struct message *dot; /* Pointer to current message */
! 65: struct message *message; /* The actual message structure */
! 66: struct var *variables[HSHSIZE]; /* Pointer to active var list */
! 67: struct grouphead *groups[HSHSIZE];/* Pointer to active groups */
! 68: struct ignoretab ignore[2]; /* ignored and retained fields
! 69: 0 is ignore, 1 is retain */
! 70: struct ignoretab saveignore[2]; /* ignored and retained fields
! 71: on save to folder */
! 72: struct ignoretab ignoreall[2]; /* special, ignore all headers */
! 73: char **altnames; /* List of alternate names for user */
! 74: int debug; /* Debug flag set */
! 75: int screenwidth; /* Screen width, or best guess */
! 76: int screenheight; /* Screen height, or best guess,
! 77: for "header" command */
! 78: int realscreenheight; /* the real screen height */
! 79: int uflag; /* Are we in -u mode? */
! 80: sigset_t intset; /* Signal set that is just SIGINT */
! 81:
! 82: /*
! 83: * The pointers for the string allocation routines,
! 84: * there are NSPACE independent areas.
! 85: * The first holds STRINGSIZE bytes, the next
! 86: * twice as much, and so on.
! 87: */
! 88: struct strings stringdope[NSPACE];
1.1 deraadt 89:
1.16 millert 90: __dead void usage(void);
91: int main(int, char **);
1.10 millert 92:
1.1 deraadt 93: /*
94: * Mail -- a mail program
95: *
96: * Startup -- interface with user.
97: */
98:
99: int
1.16 millert 100: main(int argc, char **argv)
1.1 deraadt 101: {
1.10 millert 102: int i;
1.1 deraadt 103: struct name *to, *cc, *bcc, *smopts;
1.28 millert 104: char *fromaddr;
1.1 deraadt 105: char *subject;
106: char *ef;
107: char nosrc = 0;
1.5 millert 108: char *rc;
1.17 millert 109: extern const char version[];
1.32 deraadt 110:
1.33 deraadt 111: if (pledge("stdio rpath wpath cpath getpw tmppath fattr tty flock proc exec",
1.32 deraadt 112: NULL) == -1)
113: err(1, "pledge");
1.1 deraadt 114:
115: /*
116: * Set up a reasonable environment.
117: * Figure out whether we are being run interactively,
118: * start the SIGCHLD catcher, and so forth.
119: */
1.6 millert 120: (void)signal(SIGCHLD, sigchild);
1.15 millert 121: (void)signal(SIGPIPE, SIG_IGN);
1.1 deraadt 122: if (isatty(0))
123: assign("interactive", "");
124: image = -1;
125: /*
126: * Now, determine how we are being used.
127: * We successively pick off - flags.
128: * If there is anything left, it is the base of the list
129: * of users to mail to. Argp will be set to point to the
130: * first of these users.
131: */
1.7 millert 132: ef = NULL;
1.16 millert 133: to = NULL;
134: cc = NULL;
135: bcc = NULL;
136: smopts = NULL;
1.28 millert 137: fromaddr = NULL;
1.7 millert 138: subject = NULL;
1.30 millert 139: while ((i = getopt(argc, argv, "EINb:c:dfinr:s:u:v")) != -1) {
1.1 deraadt 140: switch (i) {
141: case 'u':
142: /*
143: * Next argument is person to pretend to be.
144: */
1.27 deraadt 145: if (strlen(optarg) >= LOGIN_NAME_MAX)
1.14 millert 146: errx(1, "username `%s' too long", optarg);
1.3 deraadt 147: unsetenv("MAIL");
1.1 deraadt 148: myname = optarg;
1.11 millert 149: uflag = 1;
1.1 deraadt 150: break;
151: case 'i':
152: /*
153: * User wants to ignore interrupts.
154: * Set the variable "ignore"
155: */
156: assign("ignore", "");
157: break;
158: case 'd':
159: debug++;
160: break;
1.28 millert 161: case 'r':
162: /*
163: * Set From: address
164: */
165: fromaddr = optarg;
166: break;
1.1 deraadt 167: case 's':
168: /*
169: * Give a subject field for sending from
170: * non terminal
171: */
172: subject = optarg;
173: break;
174: case 'f':
175: /*
176: * User is specifying file to "edit" with Mail,
177: * as opposed to reading system mailbox.
1.25 millert 178: * We read his mbox file unless another file
179: * is specified after the arguments.
180: */
181: ef = "&";
1.1 deraadt 182: break;
183: case 'n':
184: /*
185: * User doesn't want to source /usr/lib/Mail.rc
186: */
1.31 deraadt 187: nosrc = 1;
1.1 deraadt 188: break;
189: case 'N':
190: /*
191: * Avoid initial header printing.
192: */
193: assign("noheader", "");
194: break;
195: case 'v':
196: /*
197: * Send mailer verbose flag
198: */
199: assign("verbose", "");
200: break;
201: case 'I':
202: /*
203: * We're interactive
204: */
205: assign("interactive", "");
206: break;
207: case 'c':
208: /*
209: * Get Carbon Copy Recipient list
210: */
211: cc = cat(cc, nalloc(optarg, GCC));
212: break;
213: case 'b':
214: /*
215: * Get Blind Carbon Copy Recipient list
216: */
217: bcc = cat(bcc, nalloc(optarg, GBCC));
218: break;
1.21 martynas 219: case 'E':
220: /*
221: * Don't send messages with an empty body.
222: */
223: assign("skipempty", "");
224: break;
1.15 millert 225: default:
226: usage();
227: /*NOTREACHED*/
1.1 deraadt 228: }
229: }
1.25 millert 230: if (ef != NULL) {
231: /* Check for optional mailbox file name. */
232: if (optind < argc) {
233: ef = argv[optind++];
234: if (optind < argc)
235: errx(1, "Cannot give -f and people to send to");
236: }
237: } else {
1.26 millert 238: for (i = optind; argv[i]; i++)
1.25 millert 239: to = cat(to, nalloc(argv[i], GTO));
240: }
1.1 deraadt 241: /*
242: * Check for inconsistent arguments.
243: */
1.29 millert 244: if (to == NULL && (subject != NULL || cc != NULL || bcc != NULL ||
245: fromaddr != NULL))
246: errx(1, "You must specify direct recipients with -s, -c, -b, "
247: "or -r");
1.15 millert 248: /*
249: * Block SIGINT except where we install an explicit handler for it.
250: */
251: sigemptyset(&intset);
252: sigaddset(&intset, SIGINT);
253: (void)sigprocmask(SIG_BLOCK, &intset, NULL);
254: /*
255: * Initialization.
256: */
1.1 deraadt 257: tinit();
258: setscreensize();
259: input = stdin;
260: rcvmode = !to;
261: spreserve();
262: if (!nosrc)
263: load(_PATH_MASTER_RC);
264: /*
265: * Expand returns a savestr, but load only uses the file name
266: * for fopen, so it's safe to do this.
267: */
1.5 millert 268: if ((rc = getenv("MAILRC")) == 0)
269: rc = "~/.mailrc";
270: load(expand(rc));
1.1 deraadt 271: if (!rcvmode) {
1.28 millert 272: mail(to, cc, bcc, smopts, fromaddr, subject);
1.1 deraadt 273: /*
274: * why wait?
275: */
276: exit(senderr);
277: }
278: /*
279: * Ok, we are reading mail.
280: * Decide whether we are editing a mailbox or reading
281: * the system mailbox, and open up the right stuff.
282: */
1.7 millert 283: if (ef == NULL)
1.1 deraadt 284: ef = "%";
285: if (setfile(ef) < 0)
286: exit(1); /* error already reported */
287:
1.15 millert 288: if (value("quiet") == NULL)
289: (void)printf("Mail version %s. Type ? for help.\n",
290: version);
291: announce();
292: (void)fflush(stdout);
1.1 deraadt 293: commands();
1.15 millert 294: (void)ignoresig(SIGHUP, NULL, NULL);
295: (void)ignoresig(SIGINT, NULL, NULL);
296: (void)ignoresig(SIGQUIT, NULL, NULL);
1.1 deraadt 297: quit();
298: exit(0);
299: }
300:
301: /*
302: * Compute what the screen size for printing headers should be.
303: * We use the following algorithm for the height:
304: * If baud rate < 1200, use 9
305: * If baud rate = 1200, use 14
306: * If baud rate > 1200, use 24 or ws_row
307: * Width is either 80 or ws_col;
308: */
309: void
1.16 millert 310: setscreensize(void)
1.1 deraadt 311: {
312: struct termios tbuf;
313: struct winsize ws;
314: speed_t ospeed;
315:
1.34 deraadt 316: if (ioctl(1, TIOCGWINSZ, (char *) &ws) == -1)
1.1 deraadt 317: ws.ws_col = ws.ws_row = 0;
1.34 deraadt 318: if (tcgetattr(1, &tbuf) == -1)
1.1 deraadt 319: ospeed = 9600;
320: else
321: ospeed = cfgetospeed(&tbuf);
1.8 millert 322: if (ospeed < B1200)
1.1 deraadt 323: screenheight = 9;
1.8 millert 324: else if (ospeed == B1200)
1.1 deraadt 325: screenheight = 14;
326: else if (ws.ws_row != 0)
327: screenheight = ws.ws_row;
328: else
329: screenheight = 24;
330: if ((realscreenheight = ws.ws_row) == 0)
331: realscreenheight = 24;
332: if ((screenwidth = ws.ws_col) == 0)
333: screenwidth = 80;
1.15 millert 334: }
335:
336: __dead void
1.16 millert 337: usage(void)
1.15 millert 338: {
339:
1.22 jmc 340: fprintf(stderr, "usage: %s [-dEIinv] [-b list] [-c list] "
1.28 millert 341: "[-r from-addr] [-s subject] to-addr ...\n", __progname);
1.22 jmc 342: fprintf(stderr, " %s [-dEIiNnv] -f [file]\n", __progname);
343: fprintf(stderr, " %s [-dEIiNnv] [-u user]\n", __progname);
1.15 millert 344: exit(1);
1.1 deraadt 345: }