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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include "mail.h" 34 /* 35 * Print mail entries 36 */ 37 void 38 printmail() 39 { 40 static char pn[] = "printmail"; 41 int flg, curlet, showlet, k, print, aret, stret, rc; 42 int nsmbox = 0; /* 1 ==> mailbox is in non-standard place */ 43 int sav_j = -1; 44 char *p, *getarg(); 45 struct stat stbuf; 46 struct stat *stbufp; 47 int ttyf = isatty(1) ? TTY : ORDINARY; 48 char readbuf[LSIZE]; /* holds user's response in interactive mode */ 49 char *resp; 50 gid_t savedegid; 51 52 stbufp = &stbuf; 53 54 /* 55 * create working directory mbox name 56 */ 57 if ((hmbox = malloc(strlen(home) + strlen(mbox) + 1)) == NULL) { 58 errmsg(E_MBOX, ""); 59 return; 60 } 61 cat(hmbox, home, mbox); 62 63 /* 64 * If we are not using an alternate mailfile, then get 65 * the $MAIL value and build the filename for the mailfile. 66 * If $MAIL is set, but is NOT the 'standard' place, then 67 * use it but set flgf to circumvent :saved processing. 68 */ 69 if (!flgf) { 70 if ((p = malloc(strlen(maildir) + strlen(my_name) + 1)) 71 == NULL) { 72 errmsg(E_MEM, ""); 73 return; 74 } 75 cat(p, maildir, my_name); 76 if (((mailfile = getenv("MAIL")) == NULL) || 77 (strlen(mailfile) == 0)) { 78 /* $MAIL not set, use standard path to mailfile */ 79 mailfile = p; 80 } else { 81 if (strcmp(mailfile, p) != 0) { 82 flgf = 1; 83 nsmbox = 1; 84 Dout(pn, 0, "$MAIL ('%s') != standard path\n", 85 mailfile); 86 Dout("", 0, "\tSetting flgf to 1.\n"); 87 } 88 free(p); 89 } 90 } 91 92 /* 93 * Get ACCESS and MODIFICATION times of mailfile BEFORE we 94 * use it. This allows us to put them back when we are 95 * done. If we didn't, the shell would think NEW mail had 96 * arrived since the file times would have changed. 97 */ 98 stret = CERROR; 99 if (access(mailfile, A_EXIST) == A_OK) { 100 if ((stret = stat(mailfile, stbufp)) != A_OK) { 101 errmsg(E_FILE, "Cannot stat mailfile"); 102 return; 103 } 104 mf_gid = stbufp->st_gid; 105 mf_uid = stbufp->st_uid; 106 utimep->actime = stbufp->st_atime; 107 utimep->modtime = stbufp->st_mtime; 108 file_size = stbufp->st_size; 109 } 110 111 /* Open the file as the real gid */ 112 savedegid = getegid(); 113 (void) setegid(getgid()); 114 malf = fopen(mailfile, "r"); 115 (void) setegid(savedegid); 116 /* 117 * stat succeeded, but we cannot access the mailfile 118 */ 119 if (stret == CSUCCESS && malf == NULL) { 120 char buf[MAXFILENAME+50]; 121 (void) snprintf(buf, sizeof (buf), 122 "Invalid permissions on %s", mailfile); 123 errmsg(E_PERM, buf); 124 return; 125 } else 126 /* 127 * using an alternate mailfile, but we failed on access 128 */ 129 if (!nsmbox && flgf && (malf == NULL)) { 130 errmsg(E_FILE, "Cannot open mailfile"); 131 return; 132 } 133 /* 134 * we failed to access OR the file is empty 135 */ 136 else if ((malf == NULL) || (stbuf.st_size == 0)) { 137 if (!flge && !flgE) { 138 printf("No mail.\n"); 139 } 140 error = E_FLGE; 141 Dout(pn, 0, "error set to %d\n", error); 142 return; 143 } 144 if (flge) 145 return; 146 147 if (flgE) { 148 if (utimep->modtime < utimep->actime) { 149 error = E_FLGE_OM; 150 Dout(pn, 0, "error set to %d\n", error); 151 } 152 return; 153 } 154 /* 155 * Secure the mailfile to guarantee integrity 156 */ 157 lock(my_name); 158 159 /* 160 * copy mail to temp file and mark each letter in the 161 * let array --- mailfile is still locked !!! 162 */ 163 mktmp(); 164 copymt(malf, tmpf); 165 onlet = nlet; 166 fclose(malf); 167 fclose(tmpf); 168 unlock(); /* All done, OK to unlock now */ 169 tmpf = doopen(lettmp, "r+", E_TMP); 170 changed = 0; 171 print = 1; 172 curlet = 0; 173 while (curlet < nlet) { 174 /* 175 * reverse order ? 176 */ 177 showlet = flgr ? curlet : nlet - curlet - 1; 178 179 if (setjmp(sjbuf) == 0 && print != 0) { 180 /* -h says to print the headers first */ 181 if (flgh) { 182 gethead(showlet, 0); 183 flgh = 0; /* Only once */ 184 /* set letter # to invalid # */ 185 curlet--; 186 showlet = 187 flgr ? curlet : nlet - curlet - 1; 188 } else { 189 if (showlet != sav_j) { 190 /* Looking at new message. */ 191 /* Reset flag to override */ 192 /* non-display of binary */ 193 /* contents */ 194 sav_j = showlet; 195 pflg = 0; 196 Pflg = flgP; 197 } 198 copylet(showlet, stdout, ttyf); 199 } 200 } 201 202 /* 203 * print only 204 */ 205 if (flgp) { 206 curlet++; 207 continue; 208 } 209 /* 210 * Interactive 211 */ 212 interactive = 1; 213 setjmp(sjbuf); 214 stat(mailfile, stbufp); 215 if (stbufp->st_size != file_size) { 216 /* 217 * New mail has arrived, load it 218 */ 219 k = nlet; 220 lock(my_name); 221 malf = doopen(mailfile, "r", E_FILE); 222 fclose(tmpf); 223 tmpf = doopen(lettmp, "a", E_TMP); 224 fseek(malf, let[nlet].adr, 0); 225 copymt(malf, tmpf); 226 file_size = stbufp->st_size; 227 fclose(malf); 228 fclose(tmpf); 229 unlock(); 230 tmpf = doopen(lettmp, "r+", E_TMP); 231 if (++k < nlet) 232 printf("New mail loaded into letters %d - %d\n", 233 k, nlet); 234 else 235 printf("New mail loaded into letter %d\n", 236 nlet); 237 } 238 239 /* read the command */ 240 printf("? "); 241 fflush(stdout); 242 fflush(stderr); 243 if (fgets(readbuf, sizeof (readbuf), stdin) == NULL) break; 244 resp = readbuf; 245 while (*resp == ' ' || *resp == '\t') resp++; 246 print = 1; 247 Dout(pn, 0, "resp = '%s'\n", resp); 248 if ((rc = atoi(resp)) != 0) { 249 if (!validmsg(rc)) print = 0; 250 else curlet = flgr ? rc - 1 : nlet - rc; 251 } else switch (resp[0]) { 252 default: 253 printf("Usage:\n"); 254 /* 255 * help 256 */ 257 case '?': 258 print = 0; 259 for (rc = 0; help[rc]; rc++) 260 printf("%s", help[rc]); 261 break; 262 /* 263 * print message number of current message 264 */ 265 case '#': 266 print = 0; 267 if ((showlet == nlet) || (showlet < 0)) { 268 printf("No message selected yet.\n"); 269 } else { 270 printf("Current message number is %d\n", 271 showlet+1); 272 } 273 break; 274 /* 275 * headers 276 */ 277 case 'h': 278 print = 0; 279 if (resp[2] != 'd' && 280 resp[2] != 'a' && 281 (rc = getnumbr(resp+1)) > 0) { 282 showlet = rc - 1; 283 curlet = flgr ? rc - 1 : nlet - rc- 1; 284 } 285 if (rc == -1 && resp[2] != 'a' && 286 resp[2] != 'd') 287 break; 288 if (resp[2] == 'a') rc = 1; 289 else if (resp[2] == 'd') rc = 2; 290 else rc = 0; 291 292 /* 293 * if (!validmsg(showlet)) break; 294 */ 295 gethead(showlet, rc); 296 break; 297 /* 298 * skip entry 299 */ 300 case '+': 301 case 'n': 302 case '\n': 303 curlet++; 304 break; 305 case 'P': 306 Pflg++; 307 break; 308 case 'p': 309 pflg++; 310 break; 311 case 'x': 312 changed = 0; 313 case 'q': 314 goto donep; 315 /* 316 * Previous entry 317 */ 318 case '^': 319 case '-': 320 if (--curlet < 0) curlet = 0; 321 break; 322 /* 323 * Save in file without header 324 */ 325 case 'y': 326 case 'w': 327 /* 328 * Save mail with header 329 */ 330 case 's': 331 print = 0; 332 if (!validmsg(curlet)) break; 333 if (resp[1] == '\n' || resp[1] == '\0') { 334 cat(resp+1, hmbox, ""); 335 } else if (resp[1] != ' ') { 336 printf("Invalid command\n"); 337 break; 338 } 339 umask(umsave); 340 flg = 0; 341 if (getarg(lfil, resp + 1) == NULL) { 342 cat(resp + 1, hmbox, ""); 343 } 344 malf = (FILE *)NULL; 345 p = resp + 1; 346 while ((p = getarg(lfil, p)) != NULL) { 347 if (flg) { 348 fprintf(stderr, 349 "%s: File '%s' skipped\n", 350 program, lfil); 351 continue; 352 } 353 malf = NULL; 354 if ((aret = legal(lfil))) { 355 malf = fopen(lfil, "a"); 356 } 357 if ((malf == NULL) || (aret == 0)) { 358 fprintf(stderr, 359 "%s: Cannot append to %s\n", 360 program, lfil); 361 flg++; 362 } else if (aret == 2) { 363 chown(lfil, my_euid, my_gid); 364 } 365 if (!flg && 366 copylet(showlet, malf, resp[0] == 367 's'? ORDINARY: ZAP) == FALSE) { 368 fprintf(stderr, 369 "%s: Cannot save mail to '%s'\n", 370 program, lfil); 371 flg++; 372 } else 373 Dout(pn, 0, "!saved\n"); 374 if (malf != (FILE *)NULL) { 375 fclose(malf); 376 } 377 } 378 umask(7); 379 if (!flg) { 380 setletr(showlet, resp[0]); 381 print = 1; 382 curlet++; 383 } 384 break; 385 /* 386 * Reply to a letter 387 */ 388 case 'r': 389 print = 0; 390 if (!validmsg(curlet)) break; 391 replying = 1; 392 for (k = 1; resp[k] == ' ' || resp[k] == '\t'; 393 ++k); 394 resp[strlen(resp)-1] = '\0'; 395 (void) strlcpy(m_sendto, resp+k, 396 sizeof (m_sendto)); 397 goback(showlet); 398 replying = 0; 399 setletr(showlet, resp[0]); 400 break; 401 /* 402 * Undelete 403 */ 404 case 'u': 405 print = 0; 406 if ((k = getnumbr(resp+1)) <= 0) k = showlet; 407 else k--; 408 if (!validmsg(k)) break; 409 setletr(k, ' '); 410 break; 411 /* 412 * Mail letter to someone else 413 */ 414 case 'm': 415 { 416 reciplist list; 417 print = 0; 418 if (!validmsg(curlet)) break; 419 new_reciplist(&list); 420 flg = 0; 421 k = 0; 422 if (substr(resp, " -") != -1 || 423 substr(resp, "\t-") != -1) { 424 printf("Only users may be specified\n"); 425 break; 426 } 427 p = resp + 1; 428 while ((p = getarg(lfil, p)) != NULL) { 429 char *env; 430 if (lfil[0] == '$') { 431 if (!(env = getenv(&lfil[1]))) { 432 fprintf(stderr, 433 "%s: %s has no value or is not exported.\n", 434 program, lfil); 435 flg++; 436 } else 437 add_recip(&list, env, 438 FALSE); 439 k++; 440 } else if (lfil[0] != '\0') { 441 add_recip(&list, lfil, FALSE); 442 k++; 443 } 444 } 445 (void) strlcpy(Rpath, my_name, sizeof (Rpath)); 446 sending = TRUE; 447 flg += sendlist(&list, showlet, 0); 448 sending = FALSE; 449 if (k) { 450 if (!flg) { 451 setletr(showlet, 'm'); 452 print = 1; 453 curlet++; 454 } 455 } else 456 printf("Invalid command\n"); 457 del_reciplist(&list); 458 break; 459 } 460 /* 461 * Read new letters 462 */ 463 case 'a': 464 if (onlet == nlet) { 465 printf("No new mail\n"); 466 print = 0; 467 break; 468 } 469 curlet = 0; 470 print = 1; 471 break; 472 /* 473 * Escape to shell 474 */ 475 case '!': 476 systm(resp + 1); 477 printf("!\n"); 478 print = 0; 479 break; 480 /* 481 * Delete an entry 482 */ 483 case 'd': 484 print = 0; 485 k = 0; 486 if (strncmp("dq", resp, 2) != SAME && 487 strncmp("dp", resp, 2) != SAME) 488 if ((k = getnumbr(resp+1)) == -1) break; 489 if (k == 0) { 490 k = showlet; 491 if (!validmsg(curlet)) break; 492 print = 1; 493 curlet++; 494 } else k--; 495 496 setletr(k, 'd'); 497 if (resp[1] == 'p') print = 1; 498 else if (resp[1] == 'q') goto donep; 499 break; 500 } 501 } 502 /* 503 * Copy updated mailfile back 504 */ 505 donep: 506 if (changed) { 507 copyback(); 508 stamp(); 509 } 510 } 511