1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * Copyright (c) 2016 by Delphix. All rights reserved. 26 */ 27 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 29 /* All Rights Reserved */ 30 31 /* 32 * University Copyright- Copyright (c) 1982, 1986, 1988 33 * The Regents of the University of California 34 * All Rights Reserved 35 * 36 * University Acknowledgment- Portions of this document are derived from 37 * software developed by the University of California, Berkeley, and its 38 * contributors. 39 */ 40 41 #include "rcv.h" 42 #ifndef preSVr4 43 #include <locale.h> 44 #endif 45 46 /* 47 * mailx -- a modified version of a University of California at Berkeley 48 * mail program 49 * 50 * Startup -- interface with user. 51 */ 52 53 static void hdrstop(int); 54 55 static jmp_buf hdrjmp; 56 57 const char *const version = "mailx version 5.0"; 58 59 /* 60 * Find out who the user is, copy their mail file (if exists) into 61 * /tmp/Rxxxxx and set up the message pointers. Then, print out the 62 * message headers and read user commands. 63 * 64 * Command line syntax: 65 * mailx [ -i ] [ -r address ] [ -h number ] [ -f [ name ] ] 66 * or: 67 * mailx [ -i ] [ -r address ] [ -h number ] people ... 68 * 69 * and a bunch of other options. 70 */ 71 72 int 73 main(int argc, char **argv) 74 { 75 register char *ef; 76 register int argp; 77 int mustsend, f, goerr = 0; 78 void (*prevint)(int); 79 int loaded = 0; 80 struct termio tbuf; 81 struct termios tbufs; 82 int c; 83 char *cwd, *mf; 84 85 /* 86 * Set up a reasonable environment. 87 * Figure out whether we are being run interactively, set up 88 * all the temporary files, buffer standard output, and so forth. 89 */ 90 91 #ifndef preSVr4 92 (void)setlocale(LC_ALL, ""); 93 #endif 94 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 95 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 96 #endif 97 (void) textdomain(TEXT_DOMAIN); 98 99 #ifdef SIGCONT 100 sigset(SIGCONT, SIG_DFL); 101 #endif 102 rpterr = 0; /* initialize; set when we output to stderr */ 103 progname = argv[0]; 104 if (progname[strlen(progname) - 1] != 'x') { 105 assign("bsdcompat", ""); 106 } 107 myegid = getegid(); 108 myrgid = getgid(); 109 myeuid = geteuid(); 110 myruid = getuid(); 111 mypid = getpid(); 112 setgid(myrgid); 113 setuid(myruid); 114 inithost(); 115 intty = isatty(0); 116 if (ioctl(1, TCGETS, &tbufs) < 0) { 117 if (ioctl(1, TCGETA, &tbuf)==0) { 118 outtty = 1; 119 baud = tbuf.c_cflag & CBAUD; 120 } else 121 baud = B9600; 122 } else { 123 outtty = 1; 124 baud = cfgetospeed(&tbufs); 125 } 126 image = -1; 127 128 /* 129 * Now, determine how we are being used. 130 * We successively pick off instances of -r, -h, -f, and -i. 131 * If called as "rmail" we note this fact for letter sending. 132 * If there is anything left, it is the base of the list 133 * of users to mail to. Argp will be set to point to the 134 * first of these users. 135 */ 136 137 ef = NOSTR; 138 argp = -1; 139 mustsend = 0; 140 if (argc > 0 && **argv == 'r') 141 rmail++; 142 while ((c = getopt(argc, argv, "b:Bc:defFh:HiInNr:s:u:UtT:vV~")) != EOF) 143 switch (c) { 144 case 'e': 145 /* 146 * exit status only 147 */ 148 exitflg++; 149 break; 150 151 case 'r': 152 /* 153 * Next argument is address to be sent along 154 * to the mailer. 155 */ 156 mustsend++; 157 rflag = optarg; 158 break; 159 160 case 'T': 161 /* 162 * Next argument is temp file to write which 163 * articles have been read/deleted for netnews. 164 */ 165 Tflag = optarg; 166 if ((f = creat(Tflag, TEMPPERM)) < 0) { 167 perror(Tflag); 168 exit(1); 169 } 170 close(f); 171 /* fall through for -I too */ 172 /* FALLTHROUGH */ 173 174 case 'I': 175 /* 176 * print newsgroup in header summary 177 */ 178 newsflg++; 179 break; 180 181 case 'u': 182 /* 183 * Next argument is person's mailbox to use. 184 * Treated the same as "-f /var/mail/user". 185 */ 186 { 187 static char u[PATHSIZE]; 188 snprintf(u, sizeof (u), "%s%s", maildir, optarg); 189 ef = u; 190 break; 191 } 192 193 case 'i': 194 /* 195 * User wants to ignore interrupts. 196 * Set the variable "ignore" 197 */ 198 assign("ignore", ""); 199 break; 200 201 case 'U': 202 UnUUCP++; 203 break; 204 205 case 'd': 206 assign("debug", ""); 207 break; 208 209 case 'h': 210 /* 211 * Specified sequence number for network. 212 * This is the number of "hops" made so 213 * far (count of times message has been 214 * forwarded) to help avoid infinite mail loops. 215 */ 216 mustsend++; 217 hflag = atoi(optarg); 218 if (hflag == 0) { 219 fprintf(stderr, 220 gettext("-h needs non-zero number\n")); 221 goerr++; 222 } 223 break; 224 225 case 's': 226 /* 227 * Give a subject field for sending from 228 * non terminal 229 */ 230 mustsend++; 231 sflag = optarg; 232 break; 233 234 case 'c': /* Cc: from command line */ 235 mustsend++; 236 cflag = optarg; 237 break; 238 239 case 'b': /* Bcc: from command line */ 240 mustsend++; 241 bflag = optarg; 242 break; 243 244 case 'f': 245 /* 246 * User is specifying file to "edit" with mailx, 247 * as opposed to reading system mailbox. 248 * If no argument is given after -f, we read their 249 * $MBOX file or mbox in their home directory. 250 */ 251 ef = (argc == optind || *argv[optind] == '-') 252 ? "" : argv[optind++]; 253 if (*ef && *ef != '/' && *ef != '+') 254 cwd = getcwd(NOSTR, PATHSIZE); 255 break; 256 257 case 'F': 258 Fflag++; 259 mustsend++; 260 break; 261 262 case 'n': 263 /* 264 * User doesn't want to source 265 * /etc/mail/mailx.rc 266 */ 267 nosrc++; 268 break; 269 270 case 'N': 271 /* 272 * Avoid initial header printing. 273 */ 274 noheader++; 275 break; 276 277 case 'H': 278 /* 279 * Print headers and exit 280 */ 281 Hflag++; 282 break; 283 284 case 'V': 285 puts(version); 286 return 0; 287 288 case '~': 289 /* 290 * Permit tildas no matter where 291 * the input is coming from. 292 */ 293 assign("escapeok", ""); 294 break; 295 296 case 'v': 297 /* 298 * Send mailer verbose flag 299 */ 300 assign("verbose", ""); 301 break; 302 303 case 'B': 304 /* 305 * Don't buffer output 306 * (Line buffered is good enough) 307 */ 308 setvbuf(stdout, NULL, _IOLBF, BUFSIZ); 309 setvbuf(stderr, NULL, _IOLBF, BUFSIZ); 310 break; 311 312 case 't': 313 /* 314 * Like sendmail -t, read headers from text 315 */ 316 tflag++; 317 mustsend++; 318 break; 319 320 case '?': 321 default: 322 goerr++; 323 break; 324 } 325 326 if (optind != argc) 327 argp = optind; 328 329 /* 330 * Check for inconsistent arguments. 331 */ 332 333 if (newsflg && ef==NOSTR) { 334 fprintf(stderr, gettext("Need -f with -I flag\n")); 335 goerr++; 336 } 337 if (ef != NOSTR && argp != -1) { 338 fprintf(stderr, 339 gettext("Cannot give -f and people to send to.\n")); 340 goerr++; 341 } 342 if (exitflg && (mustsend || argp != -1)) 343 exit(1); /* nonsense flags involving -e simply exit */ 344 if (tflag && argp != -1) { 345 fprintf(stderr, 346 gettext("Ignoring recipients on command line with -t\n")); 347 argp = -1; 348 } else if (!tflag && mustsend && argp == -1) { 349 fprintf(stderr, 350 gettext("The flags you gave are used only when sending mail.\n")); 351 goerr++; 352 } 353 if (goerr) { 354 fprintf(stderr, 355 gettext("Usage: %s -eiIUdFntBNHvV~ -T FILE -u USER -h hops -r address\n"), 356 progname); 357 fprintf(stderr, 358 gettext("\t\t-s SUBJECT -f FILE users\n")); 359 exit(1); 360 } 361 tinit(); 362 input = stdin; 363 rcvmode = !tflag && argp == -1; 364 if (!nosrc) 365 load(MASTER); 366 367 if (!rcvmode) { 368 load(Getf("MAILRC")); 369 if (tflag) 370 tmail(); 371 else 372 mail(&argv[argp]); 373 exit(senderr ? senderr : rpterr); 374 } 375 376 /* 377 * Ok, we are reading mail. 378 * Decide whether we are editing a mailbox or reading 379 * the system mailbox, and open up the right stuff. 380 * 381 * Do this before sourcing the MAILRC, because there might be 382 * a 'chdir' there that breaks the -f option. But if the 383 * file specified with -f is a folder name, go ahead and 384 * source the MAILRC anyway so that "folder" will be defined. 385 */ 386 387 nstrcpy(origname, PATHSIZE, mailname); 388 editfile = mailname; 389 390 if (ef != NOSTR) { 391 if (ef == NOSTR || *ef == '\0' || *ef == '+') { 392 load(Getf("MAILRC")); 393 loaded++; 394 } 395 ef = *ef ? safeexpand(ef) : Getf("MBOX"); 396 nstrcpy(origname, PATHSIZE, ef); 397 if (ef[0] != '/') { 398 if (cwd == NOSTR) 399 cwd = getcwd(NOSTR, PATHSIZE); 400 nstrcat(cwd, PATHSIZE, "/"); 401 nstrcat(cwd, PATHSIZE, ef); 402 ef = cwd; 403 } 404 editfile = ef; 405 edit++; 406 } 407 408 if (setfile(editfile, edit) < 0) 409 exit(1); 410 411 if (!loaded) 412 load(Getf("MAILRC")); 413 if (msgCount > 0 && !noheader && value("header") != NOSTR) { 414 if (setjmp(hdrjmp) == 0) { 415 if ((prevint = sigset(SIGINT, SIG_IGN)) != SIG_IGN) 416 sigset(SIGINT, hdrstop); 417 announce(); 418 fflush(stdout); 419 sigset(SIGINT, prevint); 420 } 421 } 422 if (Hflag || (!edit && msgCount == 0)) { 423 if (!Hflag) { 424 fprintf(stderr, gettext("No mail for %s\n"), myname); 425 Verhogen(); 426 } 427 fflush(stdout); 428 exit(rpterr); 429 } 430 commands(); 431 sigset(SIGHUP, SIG_IGN); 432 sigset(SIGINT, SIG_IGN); 433 sigset(SIGQUIT, SIG_IGN); 434 if (!outtty) 435 sigset(SIGPIPE, SIG_IGN); 436 if (edit) 437 edstop(0); 438 else { 439 quit(0); 440 Verhogen(); 441 } 442 return (rpterr); 443 } 444 445 /* 446 * Interrupt printing of the headers. 447 */ 448 static void 449 #ifdef __cplusplus 450 hdrstop(int) 451 #else 452 /* ARGSUSED */ 453 hdrstop(int s) 454 #endif 455 { 456 457 fflush(stdout); 458 fprintf(stderr, gettext("\nInterrupt\n")); 459 # ifdef OLD_BSD_SIGS 460 sigrelse(SIGINT); 461 # endif 462 longjmp(hdrjmp, 1); 463 } 464