1 /* $OpenBSD: main.c,v 1.34 2019/06/28 13:35:02 deraadt Exp $ */ 2 /* $NetBSD: main.c,v 1.7 1997/05/13 06:15:57 mikel Exp $ */ 3 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. 16 * 3. Neither the name of the University nor the names of its contributors 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> 35 #include <sys/ioctl.h> 36 #include "extern.h" 37 38 __dead void usage(void); 39 int main(int, char **); 40 41 /* 42 * Mail -- a mail program 43 * 44 * Startup -- interface with user. 45 */ 46 47 int 48 main(int argc, char **argv) 49 { 50 int i; 51 struct name *to, *cc, *bcc, *smopts; 52 char *fromaddr; 53 char *subject; 54 char *ef; 55 char nosrc = 0; 56 char *rc; 57 extern const char version[]; 58 59 if (pledge("stdio rpath wpath cpath getpw tmppath fattr tty flock proc exec", 60 NULL) == -1) 61 err(1, "pledge"); 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 (void)signal(SIGPIPE, SIG_IGN); 70 if (isatty(0)) 71 assign("interactive", ""); 72 image = -1; 73 /* 74 * Now, determine how we are being used. 75 * We successively pick off - flags. 76 * If there is anything left, it is the base of the list 77 * of users to mail to. Argp will be set to point to the 78 * first of these users. 79 */ 80 ef = NULL; 81 to = NULL; 82 cc = NULL; 83 bcc = NULL; 84 smopts = NULL; 85 fromaddr = NULL; 86 subject = NULL; 87 while ((i = getopt(argc, argv, "EINb:c:dfinr:s:u:v")) != -1) { 88 switch (i) { 89 case 'u': 90 /* 91 * Next argument is person to pretend to be. 92 */ 93 if (strlen(optarg) >= LOGIN_NAME_MAX) 94 errx(1, "username `%s' too long", optarg); 95 unsetenv("MAIL"); 96 myname = optarg; 97 uflag = 1; 98 break; 99 case 'i': 100 /* 101 * User wants to ignore interrupts. 102 * Set the variable "ignore" 103 */ 104 assign("ignore", ""); 105 break; 106 case 'd': 107 debug++; 108 break; 109 case 'r': 110 /* 111 * Set From: address 112 */ 113 fromaddr = optarg; 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 * We read his mbox file unless another file 127 * is specified after the arguments. 128 */ 129 ef = "&"; 130 break; 131 case 'n': 132 /* 133 * User doesn't want to source /usr/lib/Mail.rc 134 */ 135 nosrc = 1; 136 break; 137 case 'N': 138 /* 139 * Avoid initial header printing. 140 */ 141 assign("noheader", ""); 142 break; 143 case 'v': 144 /* 145 * Send mailer verbose flag 146 */ 147 assign("verbose", ""); 148 break; 149 case 'I': 150 /* 151 * We're interactive 152 */ 153 assign("interactive", ""); 154 break; 155 case 'c': 156 /* 157 * Get Carbon Copy Recipient list 158 */ 159 cc = cat(cc, nalloc(optarg, GCC)); 160 break; 161 case 'b': 162 /* 163 * Get Blind Carbon Copy Recipient list 164 */ 165 bcc = cat(bcc, nalloc(optarg, GBCC)); 166 break; 167 case 'E': 168 /* 169 * Don't send messages with an empty body. 170 */ 171 assign("skipempty", ""); 172 break; 173 default: 174 usage(); 175 /*NOTREACHED*/ 176 } 177 } 178 if (ef != NULL) { 179 /* Check for optional mailbox file name. */ 180 if (optind < argc) { 181 ef = argv[optind++]; 182 if (optind < argc) 183 errx(1, "Cannot give -f and people to send to"); 184 } 185 } else { 186 for (i = optind; argv[i]; i++) 187 to = cat(to, nalloc(argv[i], GTO)); 188 } 189 /* 190 * Check for inconsistent arguments. 191 */ 192 if (to == NULL && (subject != NULL || cc != NULL || bcc != NULL || 193 fromaddr != NULL)) 194 errx(1, "You must specify direct recipients with -s, -c, -b, " 195 "or -r"); 196 /* 197 * Block SIGINT except where we install an explicit handler for it. 198 */ 199 sigemptyset(&intset); 200 sigaddset(&intset, SIGINT); 201 (void)sigprocmask(SIG_BLOCK, &intset, NULL); 202 /* 203 * Initialization. 204 */ 205 tinit(); 206 setscreensize(); 207 input = stdin; 208 rcvmode = !to; 209 spreserve(); 210 if (!nosrc) 211 load(_PATH_MASTER_RC); 212 /* 213 * Expand returns a savestr, but load only uses the file name 214 * for fopen, so it's safe to do this. 215 */ 216 if ((rc = getenv("MAILRC")) == 0) 217 rc = "~/.mailrc"; 218 load(expand(rc)); 219 if (!rcvmode) { 220 mail(to, cc, bcc, smopts, fromaddr, subject); 221 /* 222 * why wait? 223 */ 224 exit(senderr); 225 } 226 /* 227 * Ok, we are reading mail. 228 * Decide whether we are editing a mailbox or reading 229 * the system mailbox, and open up the right stuff. 230 */ 231 if (ef == NULL) 232 ef = "%"; 233 if (setfile(ef) < 0) 234 exit(1); /* error already reported */ 235 236 if (value("quiet") == NULL) 237 (void)printf("Mail version %s. Type ? for help.\n", 238 version); 239 announce(); 240 (void)fflush(stdout); 241 commands(); 242 (void)ignoresig(SIGHUP, NULL, NULL); 243 (void)ignoresig(SIGINT, NULL, NULL); 244 (void)ignoresig(SIGQUIT, NULL, NULL); 245 quit(); 246 exit(0); 247 } 248 249 /* 250 * Compute what the screen size for printing headers should be. 251 * We use the following algorithm for the height: 252 * If baud rate < 1200, use 9 253 * If baud rate = 1200, use 14 254 * If baud rate > 1200, use 24 or ws_row 255 * Width is either 80 or ws_col; 256 */ 257 void 258 setscreensize(void) 259 { 260 struct termios tbuf; 261 struct winsize ws; 262 speed_t ospeed; 263 264 if (ioctl(1, TIOCGWINSZ, (char *) &ws) == -1) 265 ws.ws_col = ws.ws_row = 0; 266 if (tcgetattr(1, &tbuf) == -1) 267 ospeed = 9600; 268 else 269 ospeed = cfgetospeed(&tbuf); 270 if (ospeed < B1200) 271 screenheight = 9; 272 else if (ospeed == B1200) 273 screenheight = 14; 274 else if (ws.ws_row != 0) 275 screenheight = ws.ws_row; 276 else 277 screenheight = 24; 278 if ((realscreenheight = ws.ws_row) == 0) 279 realscreenheight = 24; 280 if ((screenwidth = ws.ws_col) == 0) 281 screenwidth = 80; 282 } 283 284 __dead void 285 usage(void) 286 { 287 288 fprintf(stderr, "usage: %s [-dEIinv] [-b list] [-c list] " 289 "[-r from-addr] [-s subject] to-addr ...\n", __progname); 290 fprintf(stderr, " %s [-dEIiNnv] -f [file]\n", __progname); 291 fprintf(stderr, " %s [-dEIiNnv] [-u user]\n", __progname); 292 exit(1); 293 } 294