1: #ifndef lint 2: static char sccsid[] = "@(#)mail.c 4.18 (Berkeley) 9/9/83"; 3: #endif 4: 5: #include <ctype.h> 6: #include <stdio.h> 7: #include <pwd.h> 8: #include <utmp.h> 9: #include <signal.h> 10: #include <sys/types.h> 11: #include <sys/stat.h> 12: #include <setjmp.h> 13: #include <whoami.h> 14: #include <sysexits.h> 15: 16: #define DELIVERMAIL "/etc/delivermail" 17: 18: 19: /*copylet flags */ 20: /*remote mail, add rmtmsg */ 21: #define REMOTE 1 22: /* zap header and trailing empty line */ 23: #define ZAP 3 24: #define ORDINARY 2 25: #define FORWARD 4 26: #define LSIZE 256 27: #define MAXLET 300 /* maximum number of letters */ 28: #define MAILMODE (~0600) /* mode of created mail */ 29: # ifndef DELIVERMAIL 30: #define MSGS "/usr/ucb/msgs" 31: #define RMAIL "/usr/net/bin/sendberkmail" 32: #define LOCNAM1 "csvax" 33: #define LOCNAM2 "ucbvax" 34: #define LOCNAM3 "vax" 35: #define LOCNAM4 "v" 36: # endif 37: 38: char line[LSIZE]; 39: char resp[LSIZE]; 40: struct let { 41: long adr; 42: char change; 43: } let[MAXLET]; 44: int nlet = 0; 45: char lfil[50]; 46: long iop, time(); 47: char *getenv(); 48: char *index(); 49: char lettmp[] = "/tmp/maXXXXX"; 50: char maildir[] = "/usr/spool/mail/"; 51: char mailfile[] = "/usr/spool/mail/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; 52: char dead[] = "dead.letter"; 53: char forwmsg[] = " forwarded\n"; 54: FILE *tmpf; 55: FILE *malf; 56: char *my_name; 57: struct passwd *getpwuid(); 58: int error; 59: int changed; 60: int forward; 61: char from[] = "From "; 62: long ftell(); 63: int delete(); 64: char *ctime(); 65: int flgf; 66: int flgp; 67: int delflg = 1; 68: int hseqno; 69: jmp_buf sjbuf; 70: int rmail; 71: char hostname[32]; 72: 73: main(argc, argv) 74: char **argv; 75: { 76: register i; 77: char sobuf[BUFSIZ]; 78: 79: setbuf(stdout, sobuf); 80: mktemp(lettmp); 81: unlink(lettmp); 82: if (my_name == NULL || strlen(my_name) == 0) { 83: struct passwd *pwent; 84: pwent = getpwuid(getuid()); 85: if (pwent==NULL) 86: my_name = "???"; 87: else 88: my_name = pwent->pw_name; 89: } 90: if(setjmp(sjbuf)) done(); 91: for (i = SIGHUP; i <= SIGTERM; i++) 92: setsig(i, delete); 93: tmpf = fopen(lettmp, "w"); 94: if (tmpf == NULL) { 95: fprintf(stderr, "mail: cannot open %s for writing\n", lettmp); 96: done(); 97: } 98: if (argv[0][0] == 'r') 99: rmail++; 100: if (argv[0][0] != 'r' && /* no favors for rmail*/ 101: (argc == 1 || argv[1][0] == '-' && !any(argv[1][1], "rhd"))) 102: printmail(argc, argv); 103: else 104: sendmail(argc, argv); 105: done(); 106: } 107: 108: setsig(i, f) 109: int i; 110: int (*f)(); 111: { 112: if(signal(i, SIG_IGN) != SIG_IGN) 113: signal(i, f); 114: } 115: 116: any(c, str) 117: register int c; 118: register char *str; 119: { 120: 121: while (*str) 122: if (c == *str++) 123: return(1); 124: return(0); 125: } 126: 127: printmail(argc, argv) 128: char **argv; 129: { 130: int flg, i, j, print; 131: char *p, *getarg(); 132: struct stat statb; 133: 134: setuid(getuid()); 135: cat(mailfile, maildir, my_name); 136: if (stat(mailfile, &statb) >= 0 137: && (statb.st_mode & S_IFMT) == S_IFDIR) { 138: strcat(mailfile, "/"); 139: strcat(mailfile, my_name); 140: } 141: for (; argc>1; argv++, argc--) { 142: if (argv[1][0]=='-') { 143: if (argv[1][1]=='q') 144: delflg = 0; 145: else if (argv[1][1]=='p') { 146: flgp++; 147: delflg = 0; 148: } else if (argv[1][1]=='f') { 149: if (argc>=3) { 150: strcpy(mailfile, argv[2]); 151: argv++; 152: argc--; 153: } 154: } else if (argv[1][1]=='r') { 155: forward = 1; 156: } else if (argv[1][1]=='h') { 157: forward = 1; 158: } else { 159: fprintf(stderr, "mail: unknown option %c\n", argv[1][1]); 160: done(); 161: } 162: } else 163: break; 164: } 165: malf = fopen(mailfile, "r"); 166: if (malf == NULL) { 167: fprintf(stdout, "No mail.\n"); 168: return; 169: } 170: lock(mailfile); 171: copymt(malf, tmpf); 172: fclose(malf); 173: fclose(tmpf); 174: unlock(); 175: tmpf = fopen(lettmp, "r"); 176: 177: changed = 0; 178: print = 1; 179: for (i = 0; i < nlet; ) { 180: j = forward ? i : nlet - i - 1; 181: if(setjmp(sjbuf)) { 182: print=0; 183: } else { 184: if (print) 185: copylet(j, stdout, ORDINARY); 186: print = 1; 187: } 188: if (flgp) { 189: i++; 190: continue; 191: } 192: setjmp(sjbuf); 193: fprintf(stdout, "? "); 194: fflush(stdout); 195: if (fgets(resp, LSIZE, stdin) == NULL) 196: break; 197: switch (resp[0]) { 198: 199: default: 200: fprintf(stderr, "usage\n"); 201: case '?': 202: print = 0; 203: fprintf(stderr, "q\tquit\n"); 204: fprintf(stderr, "x\texit without changing mail\n"); 205: fprintf(stderr, "p\tprint\n"); 206: fprintf(stderr, "s[file]\tsave (default mbox)\n"); 207: fprintf(stderr, "w[file]\tsame without header\n"); 208: fprintf(stderr, "-\tprint previous\n"); 209: fprintf(stderr, "d\tdelete\n"); 210: fprintf(stderr, "+\tnext (no delete)\n"); 211: fprintf(stderr, "m user\tmail to user\n"); 212: fprintf(stderr, "! cmd\texecute cmd\n"); 213: break; 214: 215: case '+': 216: case 'n': 217: case '\n': 218: i++; 219: break; 220: case 'x': 221: changed = 0; 222: case 'q': 223: goto donep; 224: case 'p': 225: break; 226: case '^': 227: case '-': 228: if (--i < 0) 229: i = 0; 230: break; 231: case 'y': 232: case 'w': 233: case 's': 234: flg = 0; 235: if (resp[1] != '\n' && resp[1] != ' ') { 236: printf("illegal\n"); 237: flg++; 238: print = 0; 239: continue; 240: } 241: if (resp[1] == '\n' || resp[1] == '\0') { 242: p = getenv("HOME"); 243: if(p != 0) 244: cat(resp+1, p, "/mbox"); 245: else 246: cat(resp+1, "", "mbox"); 247: } 248: for (p = resp+1; (p = getarg(lfil, p)) != NULL; ) { 249: malf = fopen(lfil, "a"); 250: if (malf == NULL) { 251: fprintf(stdout, "mail: cannot append to %s\n", lfil); 252: flg++; 253: continue; 254: } 255: copylet(j, malf, resp[0]=='w'? ZAP: ORDINARY); 256: fclose(malf); 257: } 258: if (flg) 259: print = 0; 260: else { 261: let[j].change = 'd'; 262: changed++; 263: i++; 264: } 265: break; 266: case 'm': 267: flg = 0; 268: if (resp[1] == '\n' || resp[1] == '\0') { 269: i++; 270: continue; 271: } 272: if (resp[1] != ' ') { 273: printf("invalid command\n"); 274: flg++; 275: print = 0; 276: continue; 277: } 278: for (p = resp+1; (p = getarg(lfil, p)) != NULL; ) 279: if (!sendrmt(j, lfil, "/bin/mail")) /* couldn't send it */ 280: flg++; 281: if (flg) 282: print = 0; 283: else { 284: let[j].change = 'd'; 285: changed++; 286: i++; 287: } 288: break; 289: case '!': 290: system(resp+1); 291: printf("!\n"); 292: print = 0; 293: break; 294: case 'd': 295: let[j].change = 'd'; 296: changed++; 297: i++; 298: if (resp[1] == 'q') 299: goto donep; 300: break; 301: } 302: } 303: donep: 304: if (changed) 305: copyback(); 306: } 307: 308: copyback() /* copy temp or whatever back to /usr/spool/mail */ 309: { 310: register i, n, c; 311: int new = 0; 312: struct stat stbuf; 313: 314: signal(SIGINT, SIG_IGN); 315: signal(SIGHUP, SIG_IGN); 316: signal(SIGQUIT, SIG_IGN); 317: lock(mailfile); 318: stat(mailfile, &stbuf); 319: if (stbuf.st_size != let[nlet].adr) { /* new mail has arrived */ 320: malf = fopen(mailfile, "r"); 321: if (malf == NULL) { 322: fprintf(stdout, "mail: can't re-read %s\n", mailfile); 323: done(); 324: } 325: fseek(malf, let[nlet].adr, 0); 326: fclose(tmpf); 327: tmpf = fopen(lettmp, "a"); 328: fseek(tmpf, let[nlet].adr, 0); 329: while ((c = fgetc(malf)) != EOF) 330: fputc(c, tmpf); 331: fclose(malf); 332: fclose(tmpf); 333: tmpf = fopen(lettmp, "r"); 334: let[++nlet].adr = stbuf.st_size; 335: new = 1; 336: } 337: malf = fopen(mailfile, "w"); 338: if (malf == NULL) { 339: fprintf(stderr, "mail: can't rewrite %s\n", lfil); 340: done(); 341: } 342: n = 0; 343: for (i = 0; i < nlet; i++) 344: if (let[i].change != 'd') { 345: copylet(i, malf, ORDINARY); 346: n++; 347: } 348: fclose(malf); 349: if (new) 350: fprintf(stdout, "new mail arrived\n"); 351: unlock(); 352: } 353: 354: copymt(f1, f2) /* copy mail (f1) to temp (f2) */ 355: FILE *f1, *f2; 356: { 357: long nextadr; 358: 359: nlet = nextadr = 0; 360: let[0].adr = 0; 361: while (fgets(line, LSIZE, f1) != NULL) { 362: if (isfrom(line)) 363: let[nlet++].adr = nextadr; 364: nextadr += strlen(line); 365: fputs(line, f2); 366: } 367: let[nlet].adr = nextadr; /* last plus 1 */ 368: } 369: 370: copylet(n, f, type) FILE *f; 371: { int ch; 372: long k; 373: fseek(tmpf, let[n].adr, 0); 374: k = let[n+1].adr - let[n].adr; 375: while(k-- > 1L && (ch=fgetc(tmpf))!='\n') 376: if(type!=ZAP) fputc(ch,f); 377: if(type==REMOTE) { 378: gethostname(hostname, sizeof (hostname)); 379: fprintf(f, " remote from %s\n", hostname); 380: } 381: else if (type==FORWARD) 382: fprintf(f, forwmsg); 383: else if(type==ORDINARY) 384: fputc(ch,f); 385: while(k-->1L) 386: fputc(ch=fgetc(tmpf), f); 387: if(type!=ZAP || ch!= '\n') 388: fputc(fgetc(tmpf), f); 389: } 390: 391: isfrom(lp) 392: register char *lp; 393: { 394: register char *p; 395: 396: for (p = from; *p; ) 397: if (*lp++ != *p++) 398: return(0); 399: return(1); 400: } 401: 402: sendmail(argc, argv) 403: char **argv; 404: { 405: char truename[100]; 406: int first; 407: register char *cp; 408: int gaver = 0; 409: # ifdef DELIVERMAIL 410: char *newargv[1000]; 411: register char **ap; 412: register char **vp; 413: int dflag; 414: 415: dflag = 0; 416: if (argc < 1) 417: fprintf(stderr, "puke\n"); 418: for (vp = argv, ap = newargv + 1; (*ap = *vp++) != 0; ap++) 419: { 420: if (ap[0][0] == '-' && ap[0][1] == 'd') 421: dflag++; 422: } 423: if (!dflag) 424: { 425: /* give it to delivermail, rah rah! */ 426: unlink(lettmp); 427: ap = newargv+1; 428: if (rmail) 429: *ap-- = "-s"; 430: *ap = "-delivermail"; 431: execv(DELIVERMAIL, ap); 432: perror(DELIVERMAIL); 433: exit(EX_UNAVAILABLE); 434: } 435: # endif DELIVERMAIL 436: 437: truename[0] = 0; 438: line[0] = '\0'; 439: 440: /* 441: * When we fall out of this, argv[1] should be first name, 442: * argc should be number of names + 1. 443: */ 444: 445: while (argc > 1 && *argv[1] == '-') { 446: cp = *++argv; 447: argc--; 448: switch (cp[1]) { 449: case 'r': 450: if (argc <= 0) { 451: usage(); 452: done(); 453: } 454: if (strcmp(my_name, "root") && 455: strcmp(my_name, "daemon") && 456: strcmp(my_name, "uucp") && 457: strcmp(my_name, "network")) { 458: usage(); 459: done(); 460: } 461: gaver++; 462: strcpy(truename, argv[1]); 463: fgets(line, LSIZE, stdin); 464: if (strncmp("From", line, 4) == 0) 465: line[0] = '\0'; 466: argv++; 467: argc--; 468: break; 469: 470: case 'h': 471: if (argc <= 0) { 472: usage(); 473: done(); 474: } 475: hseqno = atoi(argv[1]); 476: argv++; 477: argc--; 478: break; 479: 480: # ifdef DELIVERMAIL 481: case 'd': 482: break; 483: # endif DELIVERMAIL 484: 485: default: 486: usage(); 487: done(); 488: } 489: } 490: if (argc <= 1) { 491: usage(); 492: done(); 493: } 494: if (gaver == 0) 495: strcpy(truename, my_name); 496: /* 497: if (argc > 4 && strcmp(argv[1], "-r") == 0) { 498: strcpy(truename, argv[2]); 499: argc -= 2; 500: argv += 2; 501: fgets(line, LSIZE, stdin); 502: if (strncmp("From", line, 4) == 0) 503: line[0] = '\0'; 504: } else 505: strcpy(truename, my_name); 506: */ 507: time(&iop); 508: fprintf(tmpf, "%s%s %s", from, truename, ctime(&iop)); 509: iop = ftell(tmpf); 510: flgf = 1; 511: for (first = 1;; first = 0) { 512: if (first && line[0] == '\0' && fgets(line, LSIZE, stdin) == NULL) 513: break; 514: if (!first && fgets(line, LSIZE, stdin) == NULL) 515: break; 516: if (line[0] == '.' && line[1] == '\n' && isatty(fileno(stdin))) 517: break; 518: if (isfrom(line)) 519: fputs(">", tmpf); 520: fputs(line, tmpf); 521: flgf = 0; 522: } 523: fputs("\n", tmpf); 524: nlet = 1; 525: let[0].adr = 0; 526: let[1].adr = ftell(tmpf); 527: fclose(tmpf); 528: if (flgf) 529: return; 530: tmpf = fopen(lettmp, "r"); 531: if (tmpf == NULL) { 532: fprintf(stderr, "mail: cannot reopen %s for reading\n", lettmp); 533: return; 534: } 535: while (--argc > 0) 536: if (!send(0, *++argv, truename)) 537: error++; 538: if (error && safefile(dead)) { 539: setuid(getuid()); 540: malf = fopen(dead, "w"); 541: if (malf == NULL) { 542: fprintf(stdout, "mail: cannot open %s\n", dead); 543: fclose(tmpf); 544: return; 545: } 546: copylet(0, malf, ZAP); 547: fclose(malf); 548: fprintf(stdout, "Mail saved in %s\n", dead); 549: } 550: fclose(tmpf); 551: } 552: 553: sendrmt(n, name, rcmd) 554: char *name; 555: char *rcmd; 556: { 557: FILE *rmf, *popen(); 558: register char *p; 559: char rsys[64], cmd[64]; 560: register local, pid; 561: int ret, sts; 562: 563: local = 0; 564: if (index(name, '^')) { 565: while (p = index(name, '^')) 566: *p = '!'; 567: if (strncmp(name, "researc", 7)) { 568: strcpy(rsys, "research"); 569: if (*name != '!') 570: --name; 571: goto skip; 572: } 573: } 574: if (*name=='!') 575: name++; 576: for(p=rsys; *name!='!'; *p++ = *name++) 577: if (*name=='\0') { 578: local++; 579: break; 580: } 581: *p = '\0'; 582: if ((!local && *name=='\0') || (local && *rsys=='\0')) { 583: fprintf(stdout, "null name\n"); 584: return(0); 585: } 586: skip: 587: if ((pid = fork()) == -1) { 588: fprintf(stderr, "mail: can't create proc for remote\n"); 589: return(0); 590: } 591: if (pid) { 592: while ((ret = wait(&sts)) != pid) { 593: if (ret == -1) 594: return(0); 595: } 596: return(!sts); 597: } 598: setuid(getuid()); 599: if (local) 600: sprintf(cmd, "%s %s", rcmd, rsys); 601: else { 602: if (index(name+1, '!')) 603: sprintf(cmd, "uux - %s!rmail \\(%s\\)", rsys, name+1); 604: else 605: sprintf(cmd, "uux - %s!rmail %s", rsys, name+1); 606: } 607: if ((rmf=popen(cmd, "w")) == NULL) 608: exit(1); 609: copylet(n, rmf, local ? (!strcmp(rcmd, "/bin/mail") ? FORWARD : ORDINARY) : REMOTE); 610: exit(pclose(rmf) != 0); 611: } 612: 613: # ifndef DELIVERMAIL 614: /* 615: * Send mail on the Berkeley network. 616: * Sorry Bill, sendrmt() is so awful we just gave up. 617: */ 618: 619: sendberkmail(n, name, fromaddr) 620: char name[]; 621: char fromaddr[]; 622: { 623: char cmd[200]; 624: register FILE *cmdf; 625: 626: sprintf(cmd, "%s -h %d -f %s -t %s", RMAIL, hseqno, fromaddr, name); 627: if ((cmdf = popen(cmd, "w")) == NULL) { 628: perror(RMAIL); 629: return(0); 630: } 631: copylet(n, cmdf, ORDINARY); 632: pclose(cmdf); 633: return(9); 634: } 635: # endif 636: 637: usage() 638: { 639: fprintf(stderr, "Usage: mail [ -f ] people . . .\n"); 640: error = EX_USAGE; 641: } 642: 643: send(n, name, fromaddr) 644: int n; 645: char *name; 646: char *fromaddr; 647: { 648: char file[100]; 649: register char *p; 650: register mask; 651: struct passwd *pw, *getpwnam(); 652: struct stat statb; 653: 654: # ifndef DELIVERMAIL 655: stripfx(LOCNAM1, &name); 656: stripfx(LOCNAM2, &name); 657: stripfx(LOCNAM3, &name); 658: stripfx(LOCNAM4, &name); 659: if(*name == ':') 660: name++; /* skip colon in to-name */ 661: for(p=name; *p!=':' && *p!='!' && *p!='^' &&*p!='\0'; p++) 662: ; 663: /* if(*p == ':') return(sendrmt(n, name, RMAIL)); */ 664: if (*p == ':') 665: return(sendberkmail(n, name, fromaddr)); 666: else if (*p=='\0' && strcmp(name, "msgs") == 0) 667: return(sendrmt(n, "-s", MSGS)); 668: # endif 669: for(p=name; *p!='!'&&*p!='^' &&*p!='\0'; p++) 670: ; 671: if (*p == '!'|| *p=='^') 672: return(sendrmt(n, name, 0)); 673: if ((pw = getpwnam(name)) == NULL) { 674: fprintf(stdout, "mail: can't send to %s\n", name); 675: return(0); 676: } 677: cat(file, maildir, name); 678: if (stat(file, &statb) >= 0 && (statb.st_mode & S_IFMT) == S_IFDIR) { 679: strcat(file, "/"); 680: strcat(file, name); 681: } 682: mask = umask(MAILMODE); 683: if (!safefile(file)) 684: return(0); 685: lock(file); 686: malf = fopen(file, "a"); 687: umask(mask); 688: if (malf == NULL) { 689: unlock(); 690: fprintf(stdout, "mail: cannot append to %s\n", file); 691: return(0); 692: } 693: chown(file, pw->pw_uid, pw->pw_gid); 694: copylet(n, malf, ORDINARY); 695: fclose(malf); 696: unlock(); 697: return(1); 698: } 699: 700: delete(i) 701: { 702: setsig(i, delete); 703: fprintf(stderr, "\n"); 704: if(delflg) 705: longjmp(sjbuf, 1); 706: done(); 707: } 708: 709: /* 710: * Lock the specified mail file by setting the file mailfile.lock. 711: * We must, of course, be careful to unlink the lock file by a call 712: * to unlock before we stop. The algorithm used here is to see if 713: * the lock exists, and if it does, to check its modify time. If it 714: * is older than 30 seconds, we assume error and set our own file. 715: * Otherwise, we wait for 5 seconds and try again. 716: */ 717: 718: char *maillock = ".lock"; /* Lock suffix for mailname */ 719: char *lockname = "/usr/spool/mail/tmXXXXXX"; 720: char locktmp[30]; /* Usable lock temporary */ 721: char curlock[50]; /* Last used name of lock */ 722: int locked; /* To note that we locked it */ 723: 724: lock(file) 725: char *file; 726: { 727: register int f; 728: struct stat sbuf; 729: long curtime; 730: int statfailed; 731: 732: if (locked || flgf) 733: return(0); 734: strcpy(curlock, file); 735: strcat(curlock, maillock); 736: strcpy(locktmp, lockname); 737: mktemp(locktmp); 738: unlink(locktmp); 739: statfailed = 0; 740: for (;;) { 741: f = lock1(locktmp, curlock); 742: if (f == 0) { 743: locked = 1; 744: return(0); 745: } 746: if (stat(curlock, &sbuf) < 0) { 747: if (statfailed++ > 5) 748: return(-1); 749: sleep(5); 750: continue; 751: } 752: statfailed = 0; 753: time(&curtime); 754: if (curtime < sbuf.st_ctime + 30) { 755: sleep(5); 756: continue; 757: } 758: unlink(curlock); 759: } 760: } 761: 762: /* 763: * Remove the mail lock, and note that we no longer 764: * have it locked. 765: */ 766: 767: unlock() 768: { 769: 770: unlink(curlock); 771: locked = 0; 772: } 773: 774: /* 775: * Attempt to set the lock by creating the temporary file, 776: * then doing a link/unlink. If it fails, return -1 else 0 777: */ 778: 779: lock1(tempfile, name) 780: char tempfile[], name[]; 781: { 782: register int fd; 783: 784: fd = creat(tempfile, 0); 785: if (fd < 0) 786: return(-1); 787: close(fd); 788: if (link(tempfile, name) < 0) { 789: unlink(tempfile); 790: return(-1); 791: } 792: unlink(tempfile); 793: return(0); 794: } 795: 796: done() 797: { 798: if(locked) 799: unlock(); 800: unlink(lettmp); 801: unlink(locktmp); 802: exit(error); 803: } 804: 805: cat(to, from1, from2) 806: char *to, *from1, *from2; 807: { 808: int i, j; 809: 810: j = 0; 811: for (i=0; from1[i]; i++) 812: to[j++] = from1[i]; 813: for (i=0; from2[i]; i++) 814: to[j++] = from2[i]; 815: to[j] = 0; 816: } 817: 818: char *getarg(s, p) /* copy p... into s, update p */ 819: register char *s, *p; 820: { 821: while (*p == ' ' || *p == '\t') 822: p++; 823: if (*p == '\n' || *p == '\0') 824: return(NULL); 825: while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 826: *s++ = *p++; 827: *s = '\0'; 828: return(p); 829: } 830: # ifndef DELIVERMAIL 831: /* 832: stripfx(prefix string, pointer to string) 833: 834: takes a ptr to string and compares it to prefix string. 835: may be called multiple times 836: */ 837: stripfx(pfx, name) 838: char *pfx; 839: char **name; 840: { 841: register char *cp = *name; 842: 843: while (*pfx && (*cp == *pfx || *cp == toupper(*pfx))) 844: cp++, pfx++; 845: if (*cp != ':' || *pfx != 0) 846: return; 847: *name = cp; 848: } 849: # endif 850: 851: safefile(f) 852: char *f; 853: { 854: struct stat statb; 855: 856: #ifdef UCB_SYMLINKS 857: if (lstat(f, &statb) < 0) 858: #else 859: if (stat(f, &statb) < 0) 860: #endif 861: return(1); 862: if (statb.st_nlink != 1 || (statb.st_mode & S_IFMT) == S_IFLNK) { 863: fprintf(stderr, "mail: %s has more than one link or is a symbolic link\n", f); 864: return(0); 865: } 866: return(1); 867: }