|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)mail.c 4.25 (Berkeley) 5/1/85"; ! 3: #endif ! 4: ! 5: #include <sys/types.h> ! 6: #include <sys/stat.h> ! 7: #include <sys/file.h> ! 8: ! 9: #include <ctype.h> ! 10: #include <stdio.h> ! 11: #include <pwd.h> ! 12: #include <utmp.h> ! 13: #include <signal.h> ! 14: #include <setjmp.h> ! 15: #include <sysexits.h> ! 16: ! 17: #define SENDMAIL "/usr/lib/sendmail" ! 18: ! 19: /* copylet flags */ ! 20: #define REMOTE 1 /* remote mail, add rmtmsg */ ! 21: #define ORDINARY 2 ! 22: #define ZAP 3 /* zap header and trailing empty line */ ! 23: #define FORWARD 4 ! 24: ! 25: #define LSIZE 256 ! 26: #define MAXLET 300 /* maximum number of letters */ ! 27: #define MAILMODE 0600 /* mode of created mail */ ! 28: ! 29: char line[LSIZE]; ! 30: char resp[LSIZE]; ! 31: struct let { ! 32: long adr; ! 33: char change; ! 34: } let[MAXLET]; ! 35: int nlet = 0; ! 36: char lfil[50]; ! 37: long iop, time(); ! 38: char *getenv(); ! 39: char *index(); ! 40: char lettmp[] = "/tmp/maXXXXX"; ! 41: char maildir[] = "/usr/spool/mail/"; ! 42: char mailfile[] = "/usr/spool/mail/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; ! 43: char dead[] = "dead.letter"; ! 44: char forwmsg[] = " forwarded\n"; ! 45: FILE *tmpf; ! 46: FILE *malf; ! 47: char *my_name; ! 48: char *getlogin(); ! 49: int error; ! 50: int changed; ! 51: int forward; ! 52: char from[] = "From "; ! 53: long ftell(); ! 54: int delex(); ! 55: char *ctime(); ! 56: int flgf; ! 57: int flgp; ! 58: int delflg = 1; ! 59: int hseqno; ! 60: jmp_buf sjbuf; ! 61: int rmail; ! 62: ! 63: main(argc, argv) ! 64: char **argv; ! 65: { ! 66: register i; ! 67: struct passwd *pwent; ! 68: ! 69: my_name = getlogin(); ! 70: if (my_name == NULL || *my_name == '\0') { ! 71: pwent = getpwuid(getuid()); ! 72: if (pwent==NULL) ! 73: my_name = "???"; ! 74: else ! 75: my_name = pwent->pw_name; ! 76: } ! 77: else { ! 78: pwent = getpwnam(my_name); ! 79: if ( getuid() != pwent->pw_uid) { ! 80: pwent = getpwuid(getuid()); ! 81: my_name = pwent->pw_name; ! 82: } ! 83: } ! 84: if (setjmp(sjbuf)) ! 85: done(); ! 86: for (i=SIGHUP; i<=SIGTERM; i++) ! 87: setsig(i, delex); ! 88: i = mkstemp(lettmp); ! 89: tmpf = fdopen(i, "r+w"); ! 90: if (i < 0 || tmpf == NULL) ! 91: panic("mail: %s: cannot open for writing", lettmp); ! 92: /* ! 93: * This protects against others reading mail from temp file and ! 94: * if we exit, the file will be deleted already. ! 95: */ ! 96: unlink(lettmp); ! 97: if (argv[0][0] == 'r') ! 98: rmail++; ! 99: if (argv[0][0] != 'r' && /* no favors for rmail*/ ! 100: (argc == 1 || argv[1][0] == '-' && !any(argv[1][1], "rhd"))) ! 101: printmail(argc, argv); ! 102: else ! 103: bulkmail(argc, argv); ! 104: done(); ! 105: } ! 106: ! 107: setsig(i, f) ! 108: int i; ! 109: int (*f)(); ! 110: { ! 111: if (signal(i, SIG_IGN) != SIG_IGN) ! 112: signal(i, f); ! 113: } ! 114: ! 115: any(c, str) ! 116: register int c; ! 117: register char *str; ! 118: { ! 119: ! 120: while (*str) ! 121: if (c == *str++) ! 122: return(1); ! 123: return(0); ! 124: } ! 125: ! 126: printmail(argc, argv) ! 127: char **argv; ! 128: { ! 129: int flg, i, j, print; ! 130: char *p, *getarg(); ! 131: struct stat statb; ! 132: ! 133: setuid(getuid()); ! 134: cat(mailfile, maildir, my_name); ! 135: #ifdef notdef ! 136: if (stat(mailfile, &statb) >= 0 ! 137: && (statb.st_mode & S_IFMT) == S_IFDIR) { ! 138: strcat(mailfile, "/"); ! 139: strcat(mailfile, my_name); ! 140: } ! 141: #endif ! 142: for (; argc > 1; argv++, argc--) { ! 143: if (argv[1][0] != '-') ! 144: break; ! 145: switch (argv[1][1]) { ! 146: ! 147: case 'p': ! 148: flgp++; ! 149: /* fall thru... */ ! 150: case 'q': ! 151: delflg = 0; ! 152: break; ! 153: ! 154: case 'f': ! 155: if (argc >= 3) { ! 156: strcpy(mailfile, argv[2]); ! 157: argv++, argc--; ! 158: } ! 159: break; ! 160: ! 161: case 'b': ! 162: forward = 1; ! 163: break; ! 164: ! 165: default: ! 166: panic("unknown option %c", argv[1][1]); ! 167: /*NOTREACHED*/ ! 168: } ! 169: } ! 170: malf = fopen(mailfile, "r"); ! 171: if (malf == NULL) { ! 172: printf("No mail.\n"); ! 173: return; ! 174: } ! 175: flock(fileno(malf), LOCK_SH); ! 176: copymt(malf, tmpf); ! 177: fclose(malf); /* implicit unlock */ ! 178: fseek(tmpf, 0, L_SET); ! 179: ! 180: changed = 0; ! 181: print = 1; ! 182: for (i = 0; i < nlet; ) { ! 183: j = forward ? i : nlet - i - 1; ! 184: if (setjmp(sjbuf)) { ! 185: print = 0; ! 186: } else { ! 187: if (print) ! 188: copylet(j, stdout, ORDINARY); ! 189: print = 1; ! 190: } ! 191: if (flgp) { ! 192: i++; ! 193: continue; ! 194: } ! 195: setjmp(sjbuf); ! 196: fputs("? ", stdout); ! 197: fflush(stdout); ! 198: if (fgets(resp, LSIZE, stdin) == NULL) ! 199: break; ! 200: switch (resp[0]) { ! 201: ! 202: default: ! 203: printf("usage\n"); ! 204: case '?': ! 205: print = 0; ! 206: printf("q\tquit\n"); ! 207: printf("x\texit without changing mail\n"); ! 208: printf("p\tprint\n"); ! 209: printf("s[file]\tsave (default mbox)\n"); ! 210: printf("w[file]\tsame without header\n"); ! 211: printf("-\tprint previous\n"); ! 212: printf("d\tdelete\n"); ! 213: printf("+\tnext (no delete)\n"); ! 214: printf("m user\tmail to user\n"); ! 215: printf("! cmd\texecute cmd\n"); ! 216: break; ! 217: ! 218: case '+': ! 219: case 'n': ! 220: case '\n': ! 221: i++; ! 222: break; ! 223: case 'x': ! 224: changed = 0; ! 225: case 'q': ! 226: goto donep; ! 227: case 'p': ! 228: break; ! 229: case '^': ! 230: case '-': ! 231: if (--i < 0) ! 232: i = 0; ! 233: break; ! 234: case 'y': ! 235: case 'w': ! 236: case 's': ! 237: flg = 0; ! 238: if (resp[1] != '\n' && resp[1] != ' ') { ! 239: printf("illegal\n"); ! 240: flg++; ! 241: print = 0; ! 242: continue; ! 243: } ! 244: if (resp[1] == '\n' || resp[1] == '\0') { ! 245: p = getenv("HOME"); ! 246: if (p != 0) ! 247: cat(resp+1, p, "/mbox"); ! 248: else ! 249: cat(resp+1, "", "mbox"); ! 250: } ! 251: for (p = resp+1; (p = getarg(lfil, p)) != NULL; ) { ! 252: malf = fopen(lfil, "a"); ! 253: if (malf == NULL) { ! 254: printf("mail: %s: cannot append\n", ! 255: lfil); ! 256: flg++; ! 257: continue; ! 258: } ! 259: copylet(j, malf, resp[0]=='w'? ZAP: ORDINARY); ! 260: fclose(malf); ! 261: } ! 262: if (flg) ! 263: print = 0; ! 264: else { ! 265: let[j].change = 'd'; ! 266: changed++; ! 267: i++; ! 268: } ! 269: break; ! 270: case 'm': ! 271: flg = 0; ! 272: if (resp[1] == '\n' || resp[1] == '\0') { ! 273: i++; ! 274: continue; ! 275: } ! 276: if (resp[1] != ' ') { ! 277: printf("invalid command\n"); ! 278: flg++; ! 279: print = 0; ! 280: continue; ! 281: } ! 282: for (p = resp+1; (p = getarg(lfil, p)) != NULL; ) ! 283: if (!sendmail(j, lfil, my_name)) ! 284: flg++; ! 285: if (flg) ! 286: print = 0; ! 287: else { ! 288: let[j].change = 'd'; ! 289: changed++; ! 290: i++; ! 291: } ! 292: break; ! 293: case '!': ! 294: system(resp+1); ! 295: printf("!\n"); ! 296: print = 0; ! 297: break; ! 298: case 'd': ! 299: let[j].change = 'd'; ! 300: changed++; ! 301: i++; ! 302: if (resp[1] == 'q') ! 303: goto donep; ! 304: break; ! 305: } ! 306: } ! 307: donep: ! 308: if (changed) ! 309: copyback(); ! 310: } ! 311: ! 312: /* copy temp or whatever back to /usr/spool/mail */ ! 313: copyback() ! 314: { ! 315: register i, c; ! 316: int fd, new = 0, oldmask; ! 317: struct stat stbuf; ! 318: ! 319: #define mask(s) (1 << ((s) - 1)) ! 320: oldmask = sigblock(mask(SIGINT)|mask(SIGHUP)|mask(SIGQUIT)); ! 321: #undef mask ! 322: fd = open(mailfile, O_RDWR | O_CREAT, MAILMODE); ! 323: if (fd >= 0) { ! 324: flock(fd, LOCK_EX); ! 325: malf = fdopen(fd, "r+w"); ! 326: } ! 327: if (fd < 0 || malf == NULL) ! 328: panic("can't rewrite %s", lfil); ! 329: fstat(fd, &stbuf); ! 330: if (stbuf.st_size != let[nlet].adr) { /* new mail has arrived */ ! 331: fseek(malf, let[nlet].adr, L_SET); ! 332: fseek(tmpf, let[nlet].adr, L_SET); ! 333: while ((c = getc(malf)) != EOF) ! 334: putc(c, tmpf); ! 335: let[++nlet].adr = stbuf.st_size; ! 336: new = 1; ! 337: fseek(malf, 0, L_SET); ! 338: } ! 339: ftruncate(fd, 0); ! 340: for (i = 0; i < nlet; i++) ! 341: if (let[i].change != 'd') ! 342: copylet(i, malf, ORDINARY); ! 343: fclose(malf); /* implict unlock */ ! 344: if (new) ! 345: printf("New mail has arrived.\n"); ! 346: sigsetmask(oldmask); ! 347: } ! 348: ! 349: /* copy mail (f1) to temp (f2) */ ! 350: copymt(f1, f2) ! 351: FILE *f1, *f2; ! 352: { ! 353: long nextadr; ! 354: ! 355: nlet = nextadr = 0; ! 356: let[0].adr = 0; ! 357: while (fgets(line, LSIZE, f1) != NULL) { ! 358: if (isfrom(line)) ! 359: let[nlet++].adr = nextadr; ! 360: nextadr += strlen(line); ! 361: fputs(line, f2); ! 362: } ! 363: let[nlet].adr = nextadr; /* last plus 1 */ ! 364: } ! 365: ! 366: copylet(n, f, type) ! 367: FILE *f; ! 368: { ! 369: int ch; ! 370: long k; ! 371: char hostname[32]; ! 372: ! 373: fseek(tmpf, let[n].adr, L_SET); ! 374: k = let[n+1].adr - let[n].adr; ! 375: while (k-- > 1 && (ch = getc(tmpf)) != '\n') ! 376: if (type != ZAP) ! 377: putc(ch, f); ! 378: switch (type) { ! 379: ! 380: case REMOTE: ! 381: gethostname(hostname, sizeof (hostname)); ! 382: fprintf(f, " remote from %s\n", hostname); ! 383: break; ! 384: ! 385: case FORWARD: ! 386: fprintf(f, forwmsg); ! 387: break; ! 388: ! 389: case ORDINARY: ! 390: putc(ch, f); ! 391: break; ! 392: ! 393: case ZAP: ! 394: break; ! 395: ! 396: default: ! 397: panic("Bad letter type %d to copylet.", type); ! 398: } ! 399: while (k-- > 1) { ! 400: ch = getc(tmpf); ! 401: putc(ch, f); ! 402: } ! 403: if (type != ZAP || ch != '\n') ! 404: putc(getc(tmpf), f); ! 405: } ! 406: ! 407: isfrom(lp) ! 408: register char *lp; ! 409: { ! 410: register char *p; ! 411: ! 412: for (p = from; *p; ) ! 413: if (*lp++ != *p++) ! 414: return(0); ! 415: return(1); ! 416: } ! 417: ! 418: bulkmail(argc, argv) ! 419: char **argv; ! 420: { ! 421: char truename[100]; ! 422: int first; ! 423: register char *cp; ! 424: int gaver = 0; ! 425: char *newargv[1000]; ! 426: register char **ap; ! 427: register char **vp; ! 428: int dflag; ! 429: ! 430: dflag = 0; ! 431: if (argc < 1) { ! 432: fprintf(stderr, "puke\n"); ! 433: return; ! 434: } ! 435: for (vp = argv, ap = newargv + 1; (*ap = *vp++) != 0; ap++) ! 436: if (ap[0][0] == '-' && ap[0][1] == 'd') ! 437: dflag++; ! 438: if (!dflag) { ! 439: /* give it to sendmail, rah rah! */ ! 440: unlink(lettmp); ! 441: ap = newargv+1; ! 442: if (rmail) ! 443: *ap-- = "-s"; ! 444: *ap = "-sendmail"; ! 445: setuid(getuid()); ! 446: execv(SENDMAIL, ap); ! 447: perror(SENDMAIL); ! 448: exit(EX_UNAVAILABLE); ! 449: } ! 450: ! 451: truename[0] = 0; ! 452: line[0] = '\0'; ! 453: ! 454: /* ! 455: * When we fall out of this, argv[1] should be first name, ! 456: * argc should be number of names + 1. ! 457: */ ! 458: ! 459: while (argc > 1 && *argv[1] == '-') { ! 460: cp = *++argv; ! 461: argc--; ! 462: switch (cp[1]) { ! 463: case 'r': ! 464: if (argc <= 1) ! 465: usage(); ! 466: gaver++; ! 467: strcpy(truename, argv[1]); ! 468: fgets(line, LSIZE, stdin); ! 469: if (strcmpn("From", line, 4) == 0) ! 470: line[0] = '\0'; ! 471: argv++; ! 472: argc--; ! 473: break; ! 474: ! 475: case 'h': ! 476: if (argc <= 1) ! 477: usage(); ! 478: hseqno = atoi(argv[1]); ! 479: argv++; ! 480: argc--; ! 481: break; ! 482: ! 483: case 'd': ! 484: break; ! 485: ! 486: default: ! 487: usage(); ! 488: } ! 489: } ! 490: if (argc <= 1) ! 491: usage(); ! 492: if (gaver == 0) ! 493: strcpy(truename, my_name); ! 494: time(&iop); ! 495: fprintf(tmpf, "%s%s %s", from, truename, ctime(&iop)); ! 496: iop = ftell(tmpf); ! 497: flgf = first = 1; ! 498: for (;;) { ! 499: if (first) { ! 500: first = 0; ! 501: if (*line == '\0' && fgets(line, LSIZE, stdin) == NULL) ! 502: break; ! 503: } else { ! 504: if (fgets(line, LSIZE, stdin) == NULL) ! 505: break; ! 506: } ! 507: if (*line == '.' && line[1] == '\n' && isatty(fileno(stdin))) ! 508: break; ! 509: if (isfrom(line)) ! 510: putc('>', tmpf); ! 511: fputs(line, tmpf); ! 512: flgf = 0; ! 513: } ! 514: putc('\n', tmpf); ! 515: nlet = 1; ! 516: let[0].adr = 0; ! 517: let[1].adr = ftell(tmpf); ! 518: if (flgf) ! 519: return; ! 520: while (--argc > 0) ! 521: if (!sendmail(0, *++argv, truename)) ! 522: error++; ! 523: if (error && safefile(dead)) { ! 524: setuid(getuid()); ! 525: malf = fopen(dead, "w"); ! 526: if (malf == NULL) { ! 527: printf("mail: cannot open %s\n", dead); ! 528: fclose(tmpf); ! 529: return; ! 530: } ! 531: copylet(0, malf, ZAP); ! 532: fclose(malf); ! 533: printf("Mail saved in %s\n", dead); ! 534: } ! 535: fclose(tmpf); ! 536: } ! 537: ! 538: sendrmt(n, name) ! 539: char *name; ! 540: { ! 541: FILE *rmf, *popen(); ! 542: register char *p; ! 543: char rsys[64], cmd[64]; ! 544: register pid; ! 545: int sts; ! 546: ! 547: #ifdef notdef ! 548: if (any('^', name)) { ! 549: while (p = index(name, '^')) ! 550: *p = '!'; ! 551: if (strncmp(name, "researc", 7)) { ! 552: strcpy(rsys, "research"); ! 553: if (*name != '!') ! 554: --name; ! 555: goto skip; ! 556: } ! 557: } ! 558: #endif ! 559: for (p=rsys; *name!='!'; *p++ = *name++) ! 560: if (*name=='\0') ! 561: return(0); /* local address, no '!' */ ! 562: *p = '\0'; ! 563: if (name[1]=='\0') { ! 564: printf("null name\n"); ! 565: return(0); ! 566: } ! 567: skip: ! 568: if ((pid = fork()) == -1) { ! 569: fprintf(stderr, "mail: can't create proc for remote\n"); ! 570: return(0); ! 571: } ! 572: if (pid) { ! 573: while (wait(&sts) != pid) { ! 574: if (wait(&sts)==-1) ! 575: return(0); ! 576: } ! 577: return(!sts); ! 578: } ! 579: setuid(getuid()); ! 580: if (any('!', name+1)) ! 581: sprintf(cmd, "uux - %s!rmail \\(%s\\)", rsys, name+1); ! 582: else ! 583: sprintf(cmd, "uux - %s!rmail %s", rsys, name+1); ! 584: if ((rmf=popen(cmd, "w")) == NULL) ! 585: exit(1); ! 586: copylet(n, rmf, REMOTE); ! 587: exit(pclose(rmf) != 0); ! 588: } ! 589: ! 590: usage() ! 591: { ! 592: ! 593: fprintf(stderr, "Usage: mail [ -f ] people . . .\n"); ! 594: error = EX_USAGE; ! 595: done(); ! 596: } ! 597: ! 598: #include <sys/socket.h> ! 599: #include <netinet/in.h> ! 600: #include <netdb.h> ! 601: ! 602: notifybiff(msg) ! 603: char *msg; ! 604: { ! 605: static struct sockaddr_in addr; ! 606: static int f = -1; ! 607: ! 608: if (addr.sin_family == 0) { ! 609: struct hostent *hp = gethostbyname("localhost"); ! 610: struct servent *sp = getservbyname("biff", "udp"); ! 611: ! 612: if (hp && sp) { ! 613: addr.sin_family = hp->h_addrtype; ! 614: bcopy(hp->h_addr, &addr.sin_addr, hp->h_length); ! 615: addr.sin_port = sp->s_port; ! 616: } ! 617: } ! 618: if (addr.sin_family) { ! 619: if (f < 0) ! 620: f = socket(AF_INET, SOCK_DGRAM, 0); ! 621: sendto(f, msg, strlen(msg)+1, 0, &addr, sizeof (addr)); ! 622: } ! 623: } ! 624: ! 625: sendmail(n, name, fromaddr) ! 626: int n; ! 627: char *name, *fromaddr; ! 628: { ! 629: char file[256]; ! 630: int mask, fd; ! 631: struct passwd *pw; ! 632: #ifdef notdef ! 633: struct stat statb; ! 634: #endif ! 635: char buf[128]; ! 636: ! 637: if (*name=='!') ! 638: name++; ! 639: if (any('!', name)) ! 640: return (sendrmt(n, name)); ! 641: if ((pw = getpwnam(name)) == NULL) { ! 642: printf("mail: can't send to %s\n", name); ! 643: return(0); ! 644: } ! 645: cat(file, maildir, name); ! 646: #ifdef notdef ! 647: if (stat(file, &statb) >= 0 && (statb.st_mode & S_IFMT) == S_IFDIR) { ! 648: strcat(file, "/"); ! 649: strcat(file, name); ! 650: } ! 651: #endif ! 652: if (!safefile(file)) ! 653: return(0); ! 654: fd = open(file, O_WRONLY | O_CREAT, MAILMODE); ! 655: if (fd >= 0) { ! 656: flock(fd, LOCK_EX); ! 657: malf = fdopen(fd, "a"); ! 658: } ! 659: if (fd < 0 || malf == NULL) { ! 660: close(fd); ! 661: printf("mail: %s: cannot append\n", file); ! 662: return(0); ! 663: } ! 664: fchown(fd, pw->pw_uid, pw->pw_gid); ! 665: sprintf(buf, "%s@%d\n", name, ftell(malf)); ! 666: copylet(n, malf, ORDINARY); ! 667: fclose(malf); ! 668: notifybiff(buf); ! 669: return(1); ! 670: } ! 671: ! 672: delex(i) ! 673: { ! 674: setsig(i, delex); ! 675: putc('\n', stderr); ! 676: if (delflg) ! 677: longjmp(sjbuf, 1); ! 678: done(); ! 679: } ! 680: ! 681: done() ! 682: { ! 683: ! 684: unlink(lettmp); ! 685: exit(error); ! 686: } ! 687: ! 688: cat(to, from1, from2) ! 689: char *to, *from1, *from2; ! 690: { ! 691: register char *cp, *dp; ! 692: ! 693: cp = to; ! 694: for (dp = from1; *cp = *dp++; cp++) ! 695: ; ! 696: for (dp = from2; *cp++ = *dp++; ) ! 697: ; ! 698: } ! 699: ! 700: /* copy p... into s, update p */ ! 701: char * ! 702: getarg(s, p) ! 703: register char *s, *p; ! 704: { ! 705: while (*p == ' ' || *p == '\t') ! 706: p++; ! 707: if (*p == '\n' || *p == '\0') ! 708: return(NULL); ! 709: while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') ! 710: *s++ = *p++; ! 711: *s = '\0'; ! 712: return(p); ! 713: } ! 714: ! 715: safefile(f) ! 716: char *f; ! 717: { ! 718: struct stat statb; ! 719: ! 720: if (lstat(f, &statb) < 0) ! 721: return (1); ! 722: if (statb.st_nlink != 1 || (statb.st_mode & S_IFMT) == S_IFLNK) { ! 723: fprintf(stderr, ! 724: "mail: %s has more than one link or is a symbolic link\n", ! 725: f); ! 726: return (0); ! 727: } ! 728: return (1); ! 729: } ! 730: ! 731: panic(msg, a1, a2, a3) ! 732: char *msg; ! 733: { ! 734: ! 735: fprintf(stderr, "mail: "); ! 736: fprintf(stderr, msg, a1, a2, a3); ! 737: fprintf(stderr, "\n"); ! 738: done(); ! 739: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.