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