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