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