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 #include "rcv.h" 35 #include <fcntl.h> 36 #include "extern.h" 37 38 /* 39 * Mail -- a mail program 40 * 41 * Startup -- interface with user. 42 */ 43 44 jmp_buf hdrjmp; 45 46 extern const char *version; 47 48 int 49 main(int argc, char **argv) 50 { 51 int i; 52 struct name *to, *cc, *bcc, *smopts; 53 char *subject, *replyto; 54 char *ef, *rc; 55 char nosrc = 0; 56 const char *progname; 57 sig_t prevint; 58 59 /* 60 * Set up a reasonable environment. 61 * Figure out whether we are being run interactively, 62 * start the SIGCHLD catcher, and so forth. 63 */ 64 signal(SIGCHLD, sigchild); 65 if (isatty(0)) 66 assign("interactive", ""); 67 image = -1; 68 /* 69 * Now, determine how we are being used. 70 * We successively pick off - flags. 71 * If there is anything left, it is the base of the list 72 * of users to mail to. Argp will be set to point to the 73 * first of these users. 74 */ 75 ef = NULL; 76 to = NULL; 77 cc = NULL; 78 bcc = NULL; 79 smopts = NULL; 80 subject = NULL; 81 while ((i = getopt(argc, argv, "FEHINT:b:c:edfins:u:v")) != -1) { 82 switch (i) { 83 case 'T': 84 /* 85 * Next argument is temp file to write which 86 * articles have been read/deleted for netnews. 87 */ 88 Tflag = optarg; 89 if ((i = open(Tflag, O_CREAT | O_TRUNC | O_WRONLY, 90 0600)) < 0) 91 err(1, "%s", Tflag); 92 close(i); 93 break; 94 case 'u': 95 /* 96 * Next argument is person to pretend to be. 97 */ 98 myname = optarg; 99 unsetenv("MAIL"); 100 break; 101 case 'i': 102 /* 103 * User wants to ignore interrupts. 104 * Set the variable "ignore" 105 */ 106 assign("ignore", ""); 107 break; 108 case 'd': 109 debug++; 110 break; 111 case 'e': 112 /* 113 * User wants to check mail and exit. 114 */ 115 assign("checkmode", ""); 116 break; 117 case 'H': 118 /* 119 * User wants a header summary only. 120 */ 121 assign("headersummary", ""); 122 break; 123 case 'F': 124 /* 125 * User wants to record messages to files 126 * named after first recipient username. 127 */ 128 assign("recordrecip", ""); 129 break; 130 case 's': 131 /* 132 * Give a subject field for sending from 133 * non terminal 134 */ 135 subject = optarg; 136 break; 137 case 'f': 138 /* 139 * User is specifying file to "edit" with Mail, 140 * as opposed to reading system mailbox. 141 * If no argument is given after -f, we read his 142 * mbox file. 143 * 144 * getopt() can't handle optional arguments, so here 145 * is an ugly hack to get around it. 146 */ 147 if ((argv[optind] != NULL) && (argv[optind][0] != '-')) 148 ef = argv[optind++]; 149 else 150 ef = "&"; 151 break; 152 case 'n': 153 /* 154 * User doesn't want to source /usr/lib/Mail.rc 155 */ 156 nosrc++; 157 break; 158 case 'N': 159 /* 160 * Avoid initial header printing. 161 */ 162 assign("noheader", ""); 163 break; 164 case 'v': 165 /* 166 * Send mailer verbose flag 167 */ 168 assign("verbose", ""); 169 break; 170 case 'I': 171 /* 172 * We're interactive 173 */ 174 assign("interactive", ""); 175 break; 176 case 'c': 177 /* 178 * Get Carbon Copy Recipient list 179 */ 180 cc = cat(cc, nalloc(optarg, GCC)); 181 break; 182 case 'b': 183 /* 184 * Get Blind Carbon Copy Recipient list 185 */ 186 bcc = cat(bcc, nalloc(optarg, GBCC)); 187 break; 188 case 'E': 189 /* 190 * Don't send empty files. 191 */ 192 assign("dontsendempty", ""); 193 break; 194 case '?': 195 progname = getprogname(); 196 fprintf(stderr, 197 "Usage: %s [-EiInv] [-s subject] [-c cc-addr] [-b bcc-addr] [-F] to-addr ...\n" 198 " %*s [- sendmail-options ...]\n" 199 " %s [-EHiInNv] [-F] -f [name]\n" 200 " %s [-EHiInNv] [-F] [-u user]\n" 201 " %s -e [-f name]\n" 202 " %s -H\n", progname, (int)strlen(progname), "", 203 progname, progname, progname, progname); 204 exit(1); 205 } 206 } 207 for (i = optind; (argv[i] != NULL) && (*argv[i] != '-'); i++) 208 to = cat(to, nalloc(argv[i], GTO)); 209 for (; argv[i] != NULL; i++) 210 smopts = cat(smopts, nalloc(argv[i], 0)); 211 /* 212 * Check for inconsistent arguments. 213 */ 214 if (to == NULL && (subject != NULL || cc != NULL || bcc != NULL)) 215 errx(1, "You must specify direct recipients with -s, -c, or -b."); 216 if (ef != NULL && to != NULL) 217 errx(1, "Cannot give -f and people to send to."); 218 tinit(); 219 setscreensize(); 220 input = stdin; 221 rcvmode = !to; 222 spreserve(); 223 if (!nosrc) { 224 char *s, *path_rc; 225 226 if ((path_rc = malloc(sizeof(_PATH_MASTER_RC))) == NULL) 227 err(1, "malloc(path_rc) failed"); 228 229 strcpy(path_rc, _PATH_MASTER_RC); 230 while ((s = strsep(&path_rc, ":")) != NULL) 231 if (*s != '\0') 232 load(s); 233 } 234 /* 235 * Expand returns a savestr, but load only uses the file name 236 * for fopen, so it's safe to do this. 237 */ 238 if ((rc = getenv("MAILRC")) == NULL) 239 rc = "~/.mailrc"; 240 load(expand(rc)); 241 242 replyto = value("REPLYTO"); 243 if (!rcvmode) { 244 mail(to, cc, bcc, smopts, subject, replyto); 245 /* 246 * why wait? 247 */ 248 exit(senderr); 249 } 250 251 if (value("checkmode") != NULL) { 252 if (ef == NULL) 253 ef = "%s"; 254 if (setfile(ef) <= 0) { 255 /* Either an error has occured, or no mail. */ 256 exit(1); 257 } else { 258 exit(0); 259 } 260 /* NOTREACHED */ 261 } 262 /* 263 * Ok, we are reading mail. 264 * Decide whether we are editing a mailbox or reading 265 * the system mailbox, and open up the right stuff. 266 */ 267 if (ef == NULL) 268 ef = "%"; 269 if (setfile(ef) < 0) 270 exit(1); /* error already reported */ 271 if (setjmp(hdrjmp) == 0) { 272 if ((prevint = signal(SIGINT, SIG_IGN)) != SIG_IGN) 273 signal(SIGINT, hdrstop); 274 if (value("quiet") == NULL) 275 printf("Mail version %s. Type ? for help.\n", 276 version); 277 announce(); 278 fflush(stdout); 279 signal(SIGINT, prevint); 280 } 281 282 /* If we were in header summary mode, it's time to exit. */ 283 if (value("headersummary") != NULL) 284 exit(0); 285 286 commands(); 287 signal(SIGHUP, SIG_IGN); 288 signal(SIGINT, SIG_IGN); 289 signal(SIGQUIT, SIG_IGN); 290 quit(); 291 exit(0); 292 } 293 294 /* 295 * Interrupt printing of the headers. 296 */ 297 /*ARGSUSED*/ 298 void 299 hdrstop(int signo) 300 { 301 fflush(stdout); 302 fprintf(stderr, "\nInterrupt\n"); 303 longjmp(hdrjmp, 1); 304 } 305 306 /* 307 * Compute what the screen size for printing headers should be. 308 * We use the following algorithm for the height: 309 * If baud rate < 1200, use 9 310 * If baud rate = 1200, use 14 311 * If baud rate > 1200, use 24 or ws_row 312 * Width is either 80 or ws_col; 313 */ 314 void 315 setscreensize(void) 316 { 317 struct termios tbuf; 318 struct winsize ws; 319 speed_t speed; 320 321 if (ioctl(1, TIOCGWINSZ, (char *)&ws) < 0) 322 ws.ws_col = ws.ws_row = 0; 323 if (tcgetattr(1, &tbuf) < 0) 324 speed = B9600; 325 else 326 speed = cfgetospeed(&tbuf); 327 if (speed < B1200) 328 screenheight = 9; 329 else if (speed == B1200) 330 screenheight = 14; 331 else if (ws.ws_row != 0) 332 screenheight = ws.ws_row; 333 else 334 screenheight = 24; 335 if ((realscreenheight = ws.ws_row) == 0) 336 realscreenheight = 24; 337 if ((screenwidth = ws.ws_col) == 0) 338 screenwidth = 80; 339 } 340