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