home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / sendmail-5.65 / binmail / binmail.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-01  |  13.0 KB  |  733 lines

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