|
|
1.1 ! root 1: /* ! 2: * $Header: /newbits/bin/mail.c,v 1.6 89/02/22 05:34:00 bin Exp $ ! 3: * $Log: /newbits/bin/mail.c,v $ ! 4: * Revision 1.6 89/02/22 05:34:00 bin ! 5: * Changes by rec to integrate with lauren's uumail. ! 6: * ! 7: * Revision 1.5 88/09/01 14:49:01 bin ! 8: * Source administration: Re-install declaration of getenv. ! 9: * It was inserted after epstein made his copy. ! 10: * ! 11: * Revision 1.4 88/09/01 14:44:49 bin ! 12: * Mark Epsteins changes for ASKCC and for message scrolling, and interrupt ! 13: * handling during processing. ! 14: * ! 15: * Revision 1.3 88/09/01 14:27:41 bin ! 16: * declare getenv to get rid of integer pointer pun error message. ! 17: * ! 18: * Revision 1.2 88/09/01 11:02:23 bin ! 19: * Remove extra declaration of header which had rcs stuff in it. ! 20: * ! 21: * Revision 1.1 88/09/01 10:55:34 bin ! 22: * Initial revision ! 23: * ! 24: */ ! 25: static char *rcsrev = "$Revision 1.1 $"; ! 26: static char *rcshdr = ! 27: "$Header: /newbits/bin/mail.c,v 1.6 89/02/22 05:34:00 bin Exp $"; ! 28: ! 29: /* ! 30: * The mail command. ! 31: * Coherent electronic postal system. ! 32: * (NOTE: this command is written in such a way that ! 33: * it assumed that it is setuid on execution to `root'. ! 34: * All file accession is checked on this basis). ! 35: * Modifications by rec january 1986 to include xmail. ! 36: * by epstein november 1987 to include CC: ! 37: * by epstein november 1987 to allow ^C exit to leave you in ! 38: * mail command processor ! 39: * by epstein november 1987 to substitute /usr/games/fortune ! 40: * for printing encrypted messages ! 41: * by rec february 1989 to tail to lauren weinstein's ! 42: * mail for alias expansion and uucp queuing. ! 43: */ ! 44: ! 45: char helpmessage[] = "\ ! 46: \ ! 47: mail -- computer mail\n\ ! 48: xmail -- secret computer mail\n\ ! 49: Usage: mail [ options ] [ user ... ]\n\ ! 50: or: xmail [ options ] user [ ... ]\n\ ! 51: Options:\n\ ! 52: -f file Print mail from 'file' instead of the default\n\ ! 53: -p Print mail non-interactively\n\ ! 54: -q Exit on interrupt, leaving mail unchanged\n\ ! 55: -r Print mail in reverse order, latest first\n\ ! 56: If 'user' is present, send each a mail message read from standard input.\n\ ! 57: If 'xmail' is the command, use xencode to encrypt the mail messages.\n\ ! 58: Mail message ends with EOF of a line containing only '.'. Otherwise, read\n\ ! 59: and print the invoking user's mailbox.\n\ ! 60: \ ! 61: "; ! 62: ! 63: char isummary[] = "\ ! 64: \ ! 65: Command summary:\n\ ! 66: d Delete current message and print the next message\n\ ! 67: m [user ...] Mail current message to each named 'user'\n\ ! 68: p Print current message again\n\ ! 69: q Quit and update the mailbox\n\ ! 70: r Reverse direction of scan\n\ ! 71: s [file ...] Save message in each named 'file'\n\ ! 72: t [user ...] Mail standard input to each named 'user'\n\ ! 73: w [file ...] Save message in each named 'file' without its header\n\ ! 74: x Exit without updating mailbox\n\ ! 75: newline Print the next message\n\ ! 76: . Print current message again\n\ ! 77: + Print the next message\n\ ! 78: - Print the previous message\n\ ! 79: EOF Put undeleted mail back into mailbox and quit\n\ ! 80: ? Print this command summary\n\ ! 81: !command Pass 'command' to the shell to execute\n\ ! 82: If no 'file' is specified, 'mbox' in user's home directory is default.\n\ ! 83: If no 'user' is specified, the invoking user is default.\n\ ! 84: If the 'm', 'p', 't' commands are followed by an 'x',\n\ ! 85: then the public key cryptosystem is applied to the message.\n\ ! 86: \ ! 87: "; ! 88: ! 89: #include <stdio.h> ! 90: #include <pwd.h> ! 91: #include <utmp.h> ! 92: #include <types.h> ! 93: #include <access.h> ! 94: #include <signal.h> ! 95: #include <sys/mdata.h> ! 96: #include <sys/stat.h> ! 97: #include <time.h> ! 98: ! 99: #define SPOOLDIR "/usr/spool/mail/" ! 100: #define PUBKEYDIR "/usr/spool/pubkey/" ! 101: #define NARGS 64 /* Maximum # args to interactive command */ ! 102: #define NLINE 512 /* Longest line in a message */ ! 103: #define NCLINE 256 /* Length of an interactive command */ ! 104: ! 105: extern char *getenv(); ! 106: ! 107: ! 108: ! 109: int rflag; /* Reverse order of print */ ! 110: int qflag; /* Exit after interrrupts */ ! 111: int pflag; /* Print mail */ ! 112: int eflag; /* Edit this mail */ ! 113: int callmexmail; /* Xmail modifier present */ ! 114: ! 115: struct msg { ! 116: struct msg *m_next; /* Link to next message */ ! 117: struct msg *m_prev; /* Link to previous message */ ! 118: int m_flag; /* Flags - non-zero if deleted */ ! 119: int m_hsize; /* Size of header of message */ ! 120: fsize_t m_seek; /* Start position of message */ ! 121: fsize_t m_end; /* End of message */ ! 122: }; ! 123: struct msg *m_first = NULL; /* First message */ ! 124: struct msg *m_last = NULL; /* Last message */ ! 125: ! 126: struct tm *tp; ! 127: ! 128: char iusage[] = "Bad command--type '?' for command summary\n"; ! 129: char nombox[] = "No mailbox '%s'.\n"; ! 130: char nomail[] = "No mail.\n"; ! 131: char noperm[] = "Mailbox '%s' access denied.\n"; ! 132: char nosend[] = "Can't send mail to '%s'\n"; ! 133: char moerr[] = "Cannot open mailbox '%s'\n"; ! 134: char wrerr[] = "Write error on '%s'\n"; ! 135: char toerr[] = "Cannot create temporary file\n"; ! 136: char nosave[] = "Cannot save letter in '%s'\n"; ! 137: char nopubk[] = "Can't send xmail to '%s'\n"; ! 138: ! 139: FILE *mfp; /* Mailbox stream */ ! 140: int myuid; /* User-id of mail user */ ! 141: int mygid; /* Group-id of mail user */ ! 142: char myname[25]; /* User name */ ! 143: char mymbox[256]; /* $HOME/mbox */ ! 144: char spoolname[50] = SPOOLDIR; ! 145: char *mailbox = spoolname; ! 146: char boxname[64]; /* Destination mailbox */ ! 147: char keyname[64]; /* Destination public key file name */ ! 148: char cmdname[1024]; /* Command for x{en,de}code filter */ ! 149: /* and for tail recursion to uumail */ ! 150: /* and for editor recursion */ ! 151: char header[256]; /* Message header */ ! 152: ! 153: char *args[NARGS]; /* Interactive command arglist */ ! 154: char msgline[NLINE]; ! 155: char cline[NCLINE] = "+\n"; ! 156: ! 157: char *temp; /* Currently open temp file */ ! 158: char templ[] = "/tmp/mailXXXXXX"; /* Temp file name template */ ! 159: char *editname; /* name of editor */ ! 160: char *askcc; /* Ask for CC: list? (YES/NO) */ ! 161: ! 162: fsize_t ftell(); ! 163: char *getlogin(); ! 164: char *mktemp(); ! 165: char *index(); ! 166: char *parent(); ! 167: int catchintr(); ! 168: char *malloc(); ! 169: ! 170: main(argc, argv) ! 171: char *argv[]; ! 172: { ! 173: register char *ap; ! 174: ! 175: callmexmail = (strcmp(argv[0], "xmail") == 0); ! 176: if (signal(SIGINT, SIG_IGN) != SIG_IGN) ! 177: signal(SIGINT, catchintr); ! 178: if (argc>1 && *argv[1]=='-') { ! 179: while (argc>1 && *argv[1]=='-') { ! 180: for (ap=&argv[1][1]; *ap != '\0'; ap++) ! 181: switch (*ap) { ! 182: case 'f': ! 183: if (argc < 3) ! 184: usage(); ! 185: mailbox = argv[2]; ! 186: argv++; ! 187: argc--; ! 188: break; ! 189: ! 190: case 'm': ! 191: break; ! 192: ! 193: case 'p': ! 194: pflag++; ! 195: break; ! 196: ! 197: case 'q': ! 198: qflag++; ! 199: break; ! 200: ! 201: case 'r': ! 202: rflag++; ! 203: break; ! 204: ! 205: default: ! 206: usage(); ! 207: } ! 208: argv++; ! 209: argc--; ! 210: } ! 211: } ! 212: setname(); ! 213: if (argc > 1) { ! 214: qflag = 1; ! 215: send(stdin, &argv[1], (fsize_t)0, (fsize_t)MAXLONG); ! 216: } else { ! 217: if ( ! pflag) ! 218: callmexmail = 0; ! 219: commands(); ! 220: } ! 221: rmexit(0); ! 222: } ! 223: ! 224: /* ! 225: * Setup all the identities for the current user. ! 226: */ ! 227: setname() ! 228: { ! 229: register struct passwd *pwp; ! 230: register char *np; ! 231: ! 232: if ((np = getlogin()) == NULL) { ! 233: myuid = getuid(); ! 234: if ((pwp = getpwuid(myuid)) == NULL) ! 235: merr("Who are you?\n"); ! 236: np = pwp->pw_name; ! 237: } else { ! 238: if ((pwp = getpwnam(np)) != NULL) ! 239: myuid = pwp->pw_uid; ! 240: } ! 241: mygid = pwp->pw_gid; ! 242: strcat(spoolname, np); ! 243: strcpy(myname, np); ! 244: strcpy(mymbox, pwp->pw_dir); ! 245: strcat(mymbox, "/mbox"); ! 246: mktemp(templ); ! 247: ! 248: if ((editname=getenv("EDITOR"))==NULL) ! 249: editname = "/bin/ed"; ! 250: ! 251: if ((askcc=getenv("ASKCC")) != NULL) ! 252: if ( strcmp(askcc, "YES") || !isatty(fileno(stdin)) ) ! 253: askcc = NULL; ! 254: } ! 255: ! 256: /* ! 257: * Send the message found on ! 258: * the file pointer to the list ! 259: * of people (argv style) with ! 260: * a NULL pointer at the end. ! 261: * The message is copied to a temp-file ! 262: * from position `start' to `end' (or EOF). ! 263: */ ! 264: send(fp, users, start, end) ! 265: FILE *fp; ! 266: register char **users; ! 267: fsize_t start, end; ! 268: { ! 269: FILE *tfp, *xfp; ! 270: char **getcc(); ! 271: ! 272: temp = templ; ! 273: if ((tfp = fopen(temp, "w")) != NULL) { ! 274: fclose(tfp); ! 275: if ((tfp = fopen(temp, "r+w")) == NULL) ! 276: merr(toerr); ! 277: } else ! 278: merr(toerr); ! 279: chown(temp, myuid, mygid); ! 280: unlink(temp); ! 281: temp = NULL; ! 282: fseek(fp, start, 0); ! 283: end -= start; ! 284: ! 285: eflag = 0; ! 286: for (;;) { ! 287: if (fgets(msgline, sizeof msgline, fp) == NULL) ! 288: break; ! 289: if (fp == stdin) ! 290: if ((strcmp(".\n", msgline)==0)) ! 291: break; ! 292: else if ((strcmp("?\n", msgline)==0)) { ! 293: eflag = 1; ! 294: break; ! 295: } ! 296: if (strncmp("From ", msgline, 5) == 0) ! 297: putc('>', tfp); ! 298: fputs(msgline, tfp); ! 299: ! 300: end -= strlen(msgline); /* compiler bug */ ! 301: if (end <= 0) { ! 302: break; ! 303: } ! 304: } ! 305: /* ! 306: * If interrupted, bug out. ! 307: */ ! 308: if (intcheck()) { ! 309: fclose(tfp); ! 310: return; ! 311: } ! 312: /* ! 313: * Now, see if user wants to edit the message ! 314: */ ! 315: if (eflag) { ! 316: xfp = tfp; ! 317: temp = templ; ! 318: if ((tfp = fopen(temp, "wr")) == NULL) ! 319: merr(toerr); ! 320: chown(temp, myuid, mygid); ! 321: mcopy(xfp, tfp, (fsize_t)0, (fsize_t)MAXLONG, 0); ! 322: fclose(xfp); ! 323: sprintf(cmdname, "%s %s", editname, templ); ! 324: system(cmdname); ! 325: unlink(temp); ! 326: temp = NULL; ! 327: } ! 328: /* ! 329: * Otherwise if empty message, bug out. ! 330: */ ! 331: else if (ftell(tfp) == 0) { ! 332: fclose(tfp); ! 333: return; ! 334: } ! 335: /* ! 336: * Now see if a copy list is requested. ! 337: */ ! 338: if (askcc) ! 339: users = getcc(users); ! 340: /* ! 341: * Now send the message. ! 342: */ ! 343: if (callmexmail) ! 344: xsend(users, tfp); ! 345: else ! 346: usend(users, tfp); ! 347: } ! 348: ! 349: char *subject() ! 350: { ! 351: /* lauren's mail refuses to read a subject from standard input */ ! 352: /* without discarding the rest of the message */ ! 353: /* and refuses to accept an empty subject on the command line */ ! 354: /* so we supply a subject */ ! 355: static char *subject[] = { ! 356: #if 0 ! 357: "national security", "world peace", "elvis sighted", ! 358: "ayatollah ups reward", "new version", "old version", ! 359: "budget deficit", "technical support", "worker satisfaction", ! 360: "profit sharing", "fringe benefit", "coherent software", ! 361: "computer virus", "no subject", "forbidden", ! 362: "to memory failure", "ive", "object", "not specified", ! 363: "new policy", "old policy", "pass words", ! 364: #else ! 365: " " ! 366: #endif ! 367: }; ! 368: srand((int)time(NULL)); ! 369: return subject[rand() % (sizeof(subject)/sizeof(subject[0]))]; ! 370: } ! 371: ! 372: usend(users, tfp) char **users; FILE *tfp; ! 373: { ! 374: FILE *xfp; ! 375: strcpy(cmdname, "/usr/bin/uumail"); ! 376: while (*users) { ! 377: strcat(cmdname, " "); ! 378: strcat(cmdname, *users++); ! 379: } ! 380: strcat(cmdname, " -n -s'"); ! 381: strcat(cmdname, subject()); ! 382: strcat(cmdname, "'"); ! 383: rewind(tfp); ! 384: if ((xfp = popen(cmdname, "w")) == NULL) { ! 385: mmsg("Can't pipe to uumail\n"); ! 386: return; ! 387: } ! 388: if (mcopy(tfp, xfp, (fsize_t)0, (fsize_t)MAXLONG), 0) ! 389: merr(wrerr, cmdname); ! 390: pclose(xfp); ! 391: } ! 392: xsend(users, tfp) char **users; FILE *tfp; ! 393: { ! 394: register char **ulist; ! 395: register char *cp; ! 396: register struct passwd *pwp; ! 397: time_t curtime; ! 398: FILE *xfp; ! 399: ! 400: time(&curtime); ! 401: tp = localtime(&curtime); ! 402: cp = asctime(tp); ! 403: cp[strlen(cp)-1] = 0; ! 404: sprintf(header, "From %s %s %s\n", myname, cp, ! 405: tzname[tp->tm_isdst ? 1 : 0]); ! 406: if (users[0]!=NULL && users[1]!=NULL) { ! 407: strcat(header, "(cc:"); ! 408: for (ulist = users; *ulist != NULL; ulist++) { ! 409: strcat(header, " "); ! 410: strcat(header, *ulist); ! 411: } ! 412: strcat(header, ")\n"); ! 413: } ! 414: for (ulist = users; *ulist!=NULL; ulist++) { ! 415: rewind(tfp); ! 416: sprintf(boxname, "%s%s", SPOOLDIR, *ulist); ! 417: sprintf(cmdname, "xencode %s >> %s", *ulist, boxname); ! 418: if (index(*ulist, '!') != NULL ! 419: || (pwp = getpwnam(*ulist)) == NULL) { ! 420: mmsg(nosend, *ulist); ! 421: continue; ! 422: } ! 423: if (xaccess(*ulist) == 0) { ! 424: mmsg(nopubk, *ulist); ! 425: continue; ! 426: } ! 427: mlock(pwp->pw_uid); ! 428: if ((xfp = fopen(boxname, "a")) == NULL) { ! 429: mmsg(nosend, *ulist); ! 430: munlock(); ! 431: continue; ! 432: } ! 433: chown(boxname, pwp->pw_uid, pwp->pw_gid); ! 434: fprintf(xfp, "From xmail %s %s\n", cp, ! 435: tzname[tp->tm_isdst ? 1 : 0]); ! 436: fclose(xfp); ! 437: if ((xfp = popen(cmdname, "w")) == NULL) { ! 438: mmsg("Can't pipe to xencode\n"); ! 439: continue; ! 440: } ! 441: if (fwrite(header, strlen(header), 1, xfp) != 1 ! 442: || mcopy(tfp, xfp, (fsize_t)0, (fsize_t)MAXLONG), 0) { ! 443: merr(wrerr, cmdname); ! 444: } ! 445: pclose(xfp); ! 446: munlock(); ! 447: } ! 448: fclose(tfp); ! 449: } ! 450: ! 451: /* ! 452: * Check access on a file. ! 453: */ ! 454: maccess(name) ! 455: char *name; ! 456: { ! 457: struct stat sb; ! 458: ! 459: if (stat(name, &sb) < 0) { ! 460: if (access(parent(name), ACREAT) < 0) ! 461: return (-1); ! 462: } else if (access(name, AWRITE) < 0) ! 463: return (-1); ! 464: return (0); ! 465: } ! 466: ! 467: /* ! 468: * Check enrollment for xmail. ! 469: */ ! 470: xaccess(name) char *name; ! 471: { ! 472: struct stat sb; ! 473: sprintf(keyname, "%s%s", PUBKEYDIR, name); ! 474: return stat(keyname, &sb) >= 0; ! 475: } ! 476: /* ! 477: * Find the parent directory for access permissions. ! 478: */ ! 479: char * ! 480: parent(name) ! 481: char *name; ! 482: { ! 483: register char *cp, *xp; ! 484: static char p[256]; ! 485: char *rindex(); ! 486: ! 487: xp = rindex(name, '/'); ! 488: if (xp == NULL) ! 489: return ("."); ! 490: if (xp == name) ! 491: return ("/"); ! 492: if (xp - name >= 256) ! 493: return (""); ! 494: cp = p; ! 495: while (name < xp) ! 496: *cp++ = *name++; ! 497: *cp = 0; ! 498: return (p); ! 499: } ! 500: ! 501: /* ! 502: * Copy from the file stream `ifp' (starting at ! 503: * position `start' and ending at `end' or EOF) ! 504: * to the file stream `ofp' which is assumed ! 505: * to be already correctly positioned. ! 506: * Returns non-zero on errors. ! 507: * intstop == 1 means stop on interrupt ! 508: * intstop == 0 means ignore interrupt ! 509: */ ! 510: mcopy(ifp, ofp, start, end, intstop) ! 511: register FILE *ifp, *ofp; ! 512: fsize_t start, end; ! 513: { ! 514: register int c; ! 515: ! 516: fseek(ifp, start, 0); ! 517: end -= start; ! 518: if (intstop) ! 519: while (!intcheck() && end-- > 0 && (c = getc(ifp))!=EOF) ! 520: putc(c, ofp); ! 521: else ! 522: while (end-- > 0 && (c = getc(ifp))!=EOF) ! 523: putc(c, ofp); ! 524: fflush(ofp); ! 525: if (ferror(ofp)) ! 526: return (1); ! 527: return (0); ! 528: } ! 529: ! 530: /* ! 531: * Process mail's interactive commands ! 532: * for reading/deleting/saving mail. ! 533: */ ! 534: commands() ! 535: { ! 536: register struct msg *mp; ! 537: struct msg *dest; ! 538: register char **fnp; ! 539: register FILE *fp; ! 540: fsize_t seek; ! 541: ! 542: readmail(); ! 543: mprint(mp = rflag ? m_last : m_first); ! 544: for (;;) { ! 545: readmail(); ! 546: intcheck(); ! 547: if ( ! pflag) { ! 548: callmexmail = 0; ! 549: mmsg("? "); ! 550: if (fgets(cline, sizeof cline, stdin) == NULL) { ! 551: if (intcheck()) ! 552: continue; ! 553: break; ! 554: } ! 555: } ! 556: switch (cline[0]) { ! 557: case 'd': ! 558: if (cline[1] != '\n') ! 559: goto usage; ! 560: mp->m_flag += 1; ! 561: goto advance; ! 562: ! 563: case 'm': ! 564: case 't': ! 565: if (csplit(cline, args) == 1) { ! 566: args[1] = myname; ! 567: args[2] = NULL; ! 568: } ! 569: callmexmail = (cline[1] == 'x'); ! 570: if (cline[0] == 'm') ! 571: send(mfp, args+1, mp->m_seek, mp->m_end); ! 572: else ! 573: send(stdin, args+1, 0L, (fsize_t)MAXLONG); ! 574: break; ! 575: ! 576: case '.': ! 577: case 'p': ! 578: if (cline[1] == 'x') { ! 579: callmexmail = 1; ! 580: if (cline[2] != '\n') ! 581: goto usage; ! 582: } else if (cline[1] != '\n') ! 583: goto usage; ! 584: if (mprint(mp)) ! 585: break; ! 586: goto advance; ! 587: ! 588: case 'q': ! 589: if (cline[1] != '\n') ! 590: goto usage; ! 591: mquit(); ! 592: /* NOTREACHED */ ! 593: ! 594: case 'r': ! 595: if (cline[1] != '\n') ! 596: goto usage; ! 597: rflag = ! rflag; ! 598: break; ! 599: case 's': ! 600: case 'w': ! 601: if (csplit(cline, args) == 1) { ! 602: args[1] = mymbox; ! 603: args[2] = NULL; ! 604: } ! 605: seek = mp->m_seek; ! 606: if (cline[0] == 'w') ! 607: seek += mp->m_hsize; ! 608: for (fnp = &args[1]; *fnp != NULL; fnp++) { ! 609: fp = NULL; ! 610: if (maccess(*fnp) < 0 ! 611: || (fp = fopen(*fnp, "a")) == NULL ! 612: || mcopy(mfp, fp, seek, mp->m_end, 0)) ! 613: mmsg(nosave, *fnp); ! 614: if (fp != NULL) { ! 615: fclose(fp); ! 616: chown(*fnp, myuid, mygid); ! 617: } ! 618: } ! 619: break; ! 620: ! 621: case 'x': ! 622: if (cline[1] != '\n') ! 623: goto usage; ! 624: rmexit(0); ! 625: /* NOTREACHED */ ! 626: ! 627: case '!': ! 628: if (system(cline+1) == 127) ! 629: mmsg("Try again\n"); ! 630: else ! 631: mmsg("!\n"); ! 632: break; ! 633: ! 634: case '?': ! 635: mmsg(isummary); ! 636: break; ! 637: ! 638: case '-': ! 639: if (cline[1] != '\n') ! 640: goto usage; ! 641: dest = rflag ? m_last : m_first; ! 642: goto nextmsg; ! 643: ! 644: case '+': ! 645: if (cline[1] != '\n') ! 646: goto usage; ! 647: case '\n': ! 648: advance: ! 649: dest = rflag ? m_first : m_last; ! 650: nextmsg: ! 651: do { ! 652: if (mp == dest) { ! 653: if (pflag) ! 654: return; ! 655: mmsg("No more messages.\n"); ! 656: break; ! 657: } ! 658: mp = (dest==m_last) ? mp->m_next : mp->m_prev; ! 659: } while (mprint(mp) == 0); ! 660: break; ! 661: ! 662: default: ! 663: usage: ! 664: mmsg(iusage); ! 665: break; ! 666: } ! 667: } ! 668: putc('\n', stderr); ! 669: mquit(); ! 670: } ! 671: ! 672: /* ! 673: * Read through the mail-box file ! 674: * constructing list of letters. ! 675: * On subsequent calls, append any additional mail ! 676: * and notify the user. ! 677: */ ! 678: readmail() ! 679: { ! 680: register struct msg *mp, *lmp; ! 681: struct stat sb; ! 682: static long m_last_end; ! 683: long last; ! 684: ! 685: if (m_first == NULL) { ! 686: if (stat(mailbox, &sb) < 0) ! 687: merr(nombox, mailbox); ! 688: if (sb.st_size == 0) ! 689: merr(nomail); ! 690: if (access(mailbox, AREAD) < 0) ! 691: merr(noperm, mailbox); ! 692: if ((mfp = fopen(mailbox, "r")) == NULL) ! 693: merr(moerr, mailbox); ! 694: mp = lmp = NULL; ! 695: last = m_last_end = 0; ! 696: } else { ! 697: fstat(fileno(mfp), &sb); ! 698: if (sb.st_size == m_last_end) ! 699: return; ! 700: mmsg("More mail received.\n"); ! 701: mp = lmp = m_last; ! 702: last = mp->m_end; ! 703: fseek(mfp, m_last_end, 0); ! 704: } ! 705: mlock(myuid); ! 706: while (fgets(msgline, sizeof msgline, mfp) != NULL) { ! 707: if (strncmp("From ", msgline, 5) == 0) { ! 708: mp = (struct msg *)malloc(sizeof(*mp)); ! 709: mp->m_prev = NULL; ! 710: mp->m_next = NULL; ! 711: mp->m_flag = 0; ! 712: mp->m_hsize = strlen(msgline); ! 713: mp->m_seek = ftell(mfp)-mp->m_hsize; ! 714: if (lmp == NULL) { ! 715: m_first = mp; ! 716: } else { ! 717: lmp->m_next = mp; ! 718: lmp->m_end = last; ! 719: } ! 720: mp->m_prev = lmp; ! 721: m_last = lmp = mp; ! 722: } ! 723: if (strcmp("\n", msgline) != 0 ! 724: && strcmp("\1\1\n", msgline) != 0) ! 725: last = ftell(mfp); ! 726: } ! 727: if (mp == NULL) ! 728: merr("Not mailbox format '%s'\n", mailbox); ! 729: mp->m_end = last; ! 730: m_last_end = ftell(mfp); ! 731: munlock(); ! 732: } ! 733: ! 734: /* ! 735: * Split a command line up into ! 736: * argv (passed) and argc (returned). ! 737: */ ! 738: int ! 739: csplit(command, args) ! 740: char *command; ! 741: char **args; ! 742: { ! 743: register char *cp; ! 744: register char **ap; ! 745: register int c; ! 746: ! 747: cp = command; ! 748: ap = args; ! 749: for (;;) { ! 750: while ((c = *cp)==' ' || c=='\t') ! 751: *cp++ = '\0'; ! 752: if (*cp == '\n') ! 753: *cp = '\0'; ! 754: if (*cp == '\0') ! 755: break; ! 756: *ap++ = cp; ! 757: while ((c = *cp)!=' ' && c!='\t' && c!='\n' && c!='\0') ! 758: cp++; ! 759: } ! 760: *ap = NULL; ! 761: return (ap - args); ! 762: } ! 763: ! 764: /* ! 765: * Lock the appropriately-numbered mailbox ! 766: * (numbered by user-number) from multiple ! 767: * accesses. There is a (small) race here ! 768: * which will be overlooked for now. ! 769: */ ! 770: char *lockname; ! 771: ! 772: mlock(uid) ! 773: int uid; ! 774: { ! 775: register int fd; ! 776: static char lock[32]; ! 777: ! 778: lockname = lock; ! 779: sprintf(lock, "/tmp/maillock%d", uid); ! 780: while (access(lockname, 0) == 0) ! 781: sleep(1); ! 782: if ((fd = creat(lockname, 0)) >= 0) ! 783: close(fd); ! 784: } ! 785: ! 786: /* ! 787: * Unlock the currently-set lock (by `mlock') ! 788: * also called from rmexit. ! 789: */ ! 790: munlock() ! 791: { ! 792: if (lockname != NULL) ! 793: unlink(lockname); ! 794: lockname = NULL; ! 795: } ! 796: ! 797: /* ! 798: * Exit, after rewriting the ! 799: * mailbox ! 800: */ ! 801: mquit() ! 802: { ! 803: register struct msg *mp; ! 804: register FILE *nfp; ! 805: struct stat sb; ! 806: ! 807: readmail(); ! 808: mlock(myuid); ! 809: if (mailbox != spoolname && maccess(mailbox) < 0) ! 810: merr(noperm, mailbox); ! 811: fstat(fileno(mfp), &sb); ! 812: signal(SIGINT, SIG_IGN); ! 813: unlink(mailbox); ! 814: if ((nfp = fopen(mailbox, "w")) == NULL) ! 815: merr("Cannot re-write '%s'\n", mailbox); ! 816: chown(mailbox, sb.st_uid, sb.st_gid); ! 817: chmod(mailbox, sb.st_mode&0777); ! 818: for (mp = m_first; mp != NULL; mp = mp->m_next) ! 819: if (mp->m_flag == 0 ! 820: && mcopy(mfp, nfp, mp->m_seek, mp->m_end, 0)) ! 821: merr(wrerr, mailbox); ! 822: fclose(nfp); ! 823: fclose(mfp); ! 824: munlock(); ! 825: rmexit(0); ! 826: } ! 827: ! 828: /* ! 829: * Print the current message, given by ! 830: * the message pointer (`mp'). ! 831: */ ! 832: mprint(mp) ! 833: register struct msg *mp; ! 834: { ! 835: FILE *xfp; ! 836: if (mp->m_flag) ! 837: return 0; ! 838: if (callmexmail) { ! 839: sprintf(cmdname, "xdecode"); ! 840: if ((xfp = popen(cmdname, "w")) == NULL) { ! 841: return 0; ! 842: } ! 843: mcopy(mfp, xfp, mp->m_seek+mp->m_hsize, mp->m_end, 1); ! 844: pclose(xfp); ! 845: } else { ! 846: fseek(mfp, mp->m_seek, 0); ! 847: if (fgets(msgline, sizeof msgline, mfp) != NULL && ! 848: strncmp(msgline, "From xmail", 10) == 0) { ! 849: printf("From xmail\n"); ! 850: system("/usr/games/fortune"); ! 851: return(1); ! 852: } ! 853: mcopy(mfp, stdout, mp->m_seek, mp->m_end, 1); ! 854: } ! 855: return (1); ! 856: } ! 857: ! 858: /* ! 859: * Get additional users to receive message (CC:) ! 860: */ ! 861: ! 862: char ** ! 863: getcc(users) ! 864: register char **users; ! 865: { ! 866: register char **ulist = args; ! 867: static char names[NCLINE]; ! 868: ! 869: mmsg("CC: "); ! 870: if ( fgets(names, sizeof names, stdin) == NULL ) ! 871: return(users); ! 872: ! 873: while (*users != NULL) ! 874: *ulist++ = *users++; ! 875: ! 876: csplit(names, ulist); ! 877: return(args); ! 878: } ! 879: ! 880: ! 881: /* ! 882: * Errors, usage, and exit removing ! 883: * any tempfiles left around. ! 884: */ ! 885: mmsg(x, s) ! 886: char *x, *s; ! 887: { ! 888: fprintf(stderr, x, s); ! 889: } ! 890: ! 891: merr(x, s) ! 892: char *x, *s; ! 893: { ! 894: mmsg(x, s); ! 895: rmexit(1); ! 896: } ! 897: ! 898: usage() ! 899: { ! 900: mmsg(helpmessage); ! 901: rmexit(1); ! 902: } ! 903: ! 904: rmexit(s) ! 905: int s; ! 906: { ! 907: if (temp != NULL) ! 908: unlink(temp); ! 909: munlock(); ! 910: exit(s); ! 911: } ! 912: ! 913: /* ! 914: * Catch interrupts, taking the ! 915: * appropriate action based on ! 916: * the `-q' option. ! 917: */ ! 918: int intflag; /* On when interrupt sent */ ! 919: ! 920: catchintr() ! 921: { ! 922: signal(SIGINT, SIG_IGN); ! 923: if (qflag) ! 924: rmexit(1); ! 925: intflag = 1; ! 926: signal(SIGINT, catchintr); ! 927: } ! 928: ! 929: intcheck() ! 930: { ! 931: if (intflag) { ! 932: intflag = 0; ! 933: putc('\n', stderr); ! 934: return (1); ! 935: } ! 936: return (0); ! 937: } ! 938: ! 939: /* ! 940: * Call the system to execute a command line ! 941: * which is passed as an argument. ! 942: * Change the user id and group id. ! 943: */ ! 944: system(line) ! 945: char *line; ! 946: { ! 947: int status, pid; ! 948: register wpid; ! 949: register int (*intfun)(), (*quitfun)(); ! 950: ! 951: if ((pid = fork()) < 0) ! 952: return (-1); ! 953: if (pid == 0) { /* Child */ ! 954: setuid(myuid); ! 955: setgid(mygid); ! 956: execl("/bin/sh", "sh", "-c", line, NULL); ! 957: exit(0177); ! 958: } ! 959: intfun = signal(SIGINT, SIG_IGN); ! 960: quitfun = signal(SIGQUIT, SIG_IGN); ! 961: while ((wpid = wait(&status))!=pid && wpid>=0) ! 962: ; ! 963: if (wpid < 0) ! 964: status = wpid; ! 965: signal(SIGINT, intfun); ! 966: signal(SIGQUIT, quitfun); ! 967: return (status); ! 968: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.