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 setscreensize(); 221 input = stdin; 222 rcvmode = !to; 223 spreserve(); 224 if (!nosrc) { 225 char *s, *path_rc; 226 227 if ((path_rc = malloc(sizeof(_PATH_MASTER_RC))) == NULL) 228 err(1, "malloc(path_rc) failed"); 229 230 strcpy(path_rc, _PATH_MASTER_RC); 231 while ((s = strsep(&path_rc, ":")) != NULL) 232 if (*s != '\0') 233 load(s); 234 } 235 /* 236 * Expand returns a savestr, but load only uses the file name 237 * for fopen, so it's safe to do this. 238 */ 239 if ((rc = getenv("MAILRC")) == NULL) 240 rc = "~/.mailrc"; 241 load(expand(rc)); 242 243 replyto = value("REPLYTO"); 244 if (!rcvmode) { 245 mail(to, cc, bcc, smopts, subject, replyto); 246 /* 247 * why wait? 248 */ 249 exit(senderr); 250 } 251 252 if (value("checkmode") != NULL) { 253 if (ef == NULL) 254 ef = "%s"; 255 if (setfile(ef) <= 0) { 256 /* Either an error has occured, or no mail. */ 257 exit(1); 258 } else { 259 exit(0); 260 } 261 /* NOTREACHED */ 262 } 263 /* 264 * Ok, we are reading mail. 265 * Decide whether we are editing a mailbox or reading 266 * the system mailbox, and open up the right stuff. 267 */ 268 if (ef == NULL) 269 ef = "%"; 270 if (setfile(ef) < 0) 271 exit(1); /* error already reported */ 272 if (setjmp(hdrjmp) == 0) { 273 if ((prevint = signal(SIGINT, SIG_IGN)) != SIG_IGN) 274 signal(SIGINT, hdrstop); 275 if (value("quiet") == NULL) 276 printf("Mail version %s. Type ? for help.\n", 277 version); 278 announce(); 279 fflush(stdout); 280 signal(SIGINT, prevint); 281 } 282 283 /* If we were in header summary mode, it's time to exit. */ 284 if (value("headersummary") != NULL) 285 exit(0); 286 287 commands(); 288 signal(SIGHUP, SIG_IGN); 289 signal(SIGINT, SIG_IGN); 290 signal(SIGQUIT, SIG_IGN); 291 quit(); 292 exit(0); 293 } 294 295 /* 296 * Interrupt printing of the headers. 297 */ 298 /*ARGSUSED*/ 299 void 300 hdrstop(int signo) 301 { 302 fflush(stdout); 303 fprintf(stderr, "\nInterrupt\n"); 304 longjmp(hdrjmp, 1); 305 } 306 307 /* 308 * Compute what the screen size for printing headers should be. 309 * We use the following algorithm for the height: 310 * If baud rate < 1200, use 9 311 * If baud rate = 1200, use 14 312 * If baud rate > 1200, use 24 or ws_row 313 * Width is either 80 or ws_col; 314 */ 315 void 316 setscreensize(void) 317 { 318 struct termios tbuf; 319 struct winsize ws; 320 speed_t speed; 321 322 if (ioctl(1, TIOCGWINSZ, (char *)&ws) < 0) 323 ws.ws_col = ws.ws_row = 0; 324 if (tcgetattr(1, &tbuf) < 0) 325 speed = B9600; 326 else 327 speed = cfgetospeed(&tbuf); 328 if (speed < B1200) 329 screenheight = 9; 330 else if (speed == B1200) 331 screenheight = 14; 332 else if (ws.ws_row != 0) 333 screenheight = ws.ws_row; 334 else 335 screenheight = 24; 336 if ((realscreenheight = ws.ws_row) == 0) 337 realscreenheight = 24; 338 if ((screenwidth = ws.ws_col) == 0) 339 screenwidth = 80; 340 } 341