home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Trees / V7 / usr / src / cmd / mail.c < prev    next >
Encoding:
C/C++ Source or Header  |  1979-05-05  |  10.1 KB  |  555 lines

  1. #include <stdio.h>
  2. #include <pwd.h>
  3. #include <utmp.h>
  4. #include <signal.h>
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <setjmp.h>
  8. #include <whoami.h>
  9.  
  10. /*copylet flags */
  11.     /*remote mail, add rmtmsg */
  12. #define REMOTE    1
  13.     /* zap header and trailing empty line */
  14. #define ZAP    3
  15. #define ORDINARY 2
  16. #define    FORWARD    4
  17. #define    LSIZE    256
  18. #define    MAXLET    300    /* maximum number of letters */
  19. #define    MAILMODE (~0644)        /* mode of created mail */
  20.  
  21. char    line[LSIZE];
  22. char    resp[LSIZE];
  23. struct let {
  24.     long    adr;
  25.     char    change;
  26. } let[MAXLET];
  27. int    nlet    = 0;
  28. char    lfil[50];
  29. long    iop, time();
  30. char    lettmp[] = "/tmp/maXXXXX";
  31. char    maildir[] = "/usr/spool/mail/";
  32. char    mailfile[] = "/usr/spool/mail/xxxxxxxxxxxxxxxxxxxxxxx";
  33. char    dead[] = "dead.letter";
  34. char    *thissys = sysname;
  35. char    forwmsg[] = " forwarded\n";
  36. char    *curlock;
  37. int    lockerror;
  38. FILE    *tmpf;
  39. FILE    *malf;
  40. char    *my_name;
  41. char    *getlogin();
  42. struct    passwd    *getpwuid();
  43. int    error;
  44. int    locked;
  45. int    changed;
  46. int    forward;
  47. char    from[] = "From ";
  48. long    ftell();
  49. int    delete();
  50. char    *ctime();
  51. int    flgf;
  52. int    flgp;
  53. int    delflg = 1;
  54. jmp_buf    sjbuf;
  55.  
  56. main(argc, argv)
  57. char **argv;
  58. {
  59.     register i;
  60.     char sobuf[BUFSIZ];
  61.  
  62.     setbuf(stdout, sobuf);
  63.     mktemp(lettmp);
  64.     unlink(lettmp);
  65.     my_name = getlogin();
  66.     if (my_name == NULL) {
  67.         struct passwd *pwent;
  68.         pwent = getpwuid(getuid());
  69.         if (pwent==NULL)
  70.             my_name = "???";
  71.         else
  72.             my_name = pwent->pw_name;
  73.     }
  74.     if(setjmp(sjbuf)) done();
  75.     for (i=0; i<20; i++)
  76.         setsig(i, delete);
  77.     tmpf = fopen(lettmp, "w");
  78.     if (tmpf == NULL) {
  79.         fprintf(stderr, "mail: cannot open %s for writing\n", lettmp);
  80.         done();
  81.     }
  82.     if (argv[0][0] != 'r' &&    /* no favors for rmail*/
  83.        (argc == 1 || argv[1][0] == '-'))
  84.         printmail(argc, argv);
  85.     else
  86.         sendmail(argc, argv);
  87.     done();
  88. }
  89.  
  90. setsig(i, f)
  91. int i;
  92. int (*f)();
  93. {
  94.     if(signal(i, SIG_IGN)!=SIG_IGN)
  95.         signal(i, f);
  96. }
  97.  
  98. printmail(argc, argv)
  99. char **argv;
  100. {
  101.     int flg, i, j, print;
  102.     char *p, *getarg();
  103.  
  104.     setuid(getuid());
  105.     cat(mailfile, maildir, my_name);
  106.     for (; argc>1; argv++, argc--) {
  107.         if (argv[1][0]=='-') {
  108.             if (argv[1][1]=='q')
  109.                 delflg = 0;
  110.             else if (argv[1][1]=='p') {
  111.                 flgp++;
  112.                 delflg = 0;
  113.             } else if (argv[1][1]=='f') {
  114.                 if (argc>=3) {
  115.                     strcpy(mailfile, argv[2]);
  116.                     argv++;
  117.                     argc--;
  118.                 }
  119.             } else if (argv[1][1]=='r') {
  120.                 forward = 1;
  121.             } else {
  122.                 fprintf(stderr, "mail: unknown option %c\n", argv[1][1]);
  123.                 done();
  124.             }
  125.         } else
  126.             break;
  127.     }
  128.     malf = fopen(mailfile, "r");
  129.     if (malf == NULL) {
  130.         fprintf(stdout, "No mail.\n");
  131.         return;
  132.     }
  133.     lock(mailfile);
  134.     copymt(malf, tmpf);
  135.     fclose(malf);
  136.     fclose(tmpf);
  137.     unlock();
  138.     tmpf = fopen(lettmp, "r");
  139.  
  140.     changed = 0;
  141.     print = 1;
  142.     for (i = 0; i < nlet; ) {
  143.         j = forward ? i : nlet - i - 1;
  144.         if(setjmp(sjbuf)) {
  145.             print=0;
  146.         } else {
  147.             if (print)
  148.                 copylet(j, stdout, ORDINARY);
  149.             print = 1;
  150.         }
  151.         if (flgp) {
  152.             i++;
  153.             continue;
  154.         }
  155.         setjmp(sjbuf);
  156.         fprintf(stdout, "? ");
  157.         fflush(stdout);
  158.         if (fgets(resp, LSIZE, stdin) == NULL)
  159.             break;
  160.         switch (resp[0]) {
  161.  
  162.         default:
  163.             fprintf(stderr, "usage\n");
  164.         case '?':
  165.             print = 0;
  166.             fprintf(stderr, "q\tquit\n");
  167.             fprintf(stderr, "x\texit without changing mail\n");
  168.             fprintf(stderr, "p\tprint\n");
  169.             fprintf(stderr, "s[file]\tsave (default mbox)\n");
  170.             fprintf(stderr, "w[file]\tsame without header\n");
  171.             fprintf(stderr, "-\tprint previous\n");
  172.             fprintf(stderr, "d\tdelete\n");
  173.             fprintf(stderr, "+\tnext (no delete)\n");
  174.             fprintf(stderr, "m user\tmail to user\n");
  175.             fprintf(stderr, "! cmd\texecute cmd\n");
  176.             break;
  177.  
  178.         case '+':
  179.         case 'n':
  180.         case '\n':
  181.             i++;
  182.             break;
  183.         case 'x':
  184.             changed = 0;
  185.         case 'q':
  186.             goto donep;
  187.         case 'p':
  188.             break;
  189.         case '^':
  190.         case '-':
  191.             if (--i < 0)
  192.                 i = 0;
  193.             break;
  194.         case 'y':
  195.         case 'w':
  196.         case 's':
  197.             flg = 0;
  198.             if (resp[1] != '\n' && resp[1] != ' ') {
  199.                 printf("illegal\n");
  200.                 flg++;
  201.                 print = 0;
  202.                 continue;
  203.             }
  204.             if (resp[1] == '\n' || resp[1] == '\0')
  205.                 cat(resp+1, "mbox", "");
  206.             for (p = resp+1; (p = getarg(lfil, p)) != NULL; ) {
  207.                 malf = fopen(lfil, "a");
  208.                 if (malf == NULL) {
  209.                     fprintf(stdout, "mail: cannot append to %s\n", lfil);
  210.                     flg++;
  211.                     continue;
  212.                 }
  213.                 copylet(j, malf, resp[0]=='w'? ZAP: ORDINARY);
  214.                 fclose(malf);
  215.             }
  216.             if (flg)
  217.                 print = 0;
  218.             else {
  219.                 let[j].change = 'd';
  220.                 changed++;
  221.                 i++;
  222.             }
  223.             break;
  224.         case 'm':
  225.             flg = 0;
  226.             if (resp[1] == '\n' || resp[1] == '\0') {
  227.                 i++;
  228.                 continue;
  229.             }
  230.             if (resp[1] != ' ') {
  231.                 printf("invalid command\n");
  232.                 flg++;
  233.                 print = 0;
  234.                 continue;
  235.             }
  236.             for (p = resp+1; (p = getarg(lfil, p)) != NULL; )
  237.                 if (!sendrmt(j, lfil))    /* couldn't send it */
  238.                     flg++;
  239.             if (flg)
  240.                 print = 0;
  241.             else {
  242.                 let[j].change = 'd';
  243.                 changed++;
  244.                 i++;
  245.             }
  246.             break;
  247.         case '!':
  248.             system(resp+1);
  249.             printf("!\n");
  250.             print = 0;
  251.             break;
  252.         case 'd':
  253.             let[j].change = 'd';
  254.             changed++;
  255.             i++;
  256.             if (resp[1] == 'q')
  257.                 goto donep;
  258.             break;
  259.         }
  260.     }
  261.    donep:
  262.     if (changed)
  263.         copyback();
  264. }
  265.  
  266. copyback()    /* copy temp or whatever back to /usr/spool/mail */
  267. {
  268.     register i, n, c;
  269.     int new = 0;
  270.     struct stat stbuf;
  271.  
  272.     signal(SIGINT, SIG_IGN);
  273.     signal(SIGHUP, SIG_IGN);
  274.     signal(SIGQUIT, SIG_IGN);
  275.     lock(mailfile);
  276.     stat(mailfile, &stbuf);
  277.     if (stbuf.st_size != let[nlet].adr) {    /* new mail has arrived */
  278.         malf = fopen(mailfile, "r");
  279.         if (malf == NULL) {
  280.             fprintf(stdout, "mail: can't re-read %s\n", mailfile);
  281.             done();
  282.         }
  283.         fseek(malf, let[nlet].adr, 0);
  284.         fclose(tmpf);
  285.         tmpf = fopen(lettmp, "a");
  286.         fseek(tmpf, let[nlet].adr, 0);
  287.         while ((c = fgetc(malf)) != EOF)
  288.             fputc(c, tmpf);
  289.         fclose(malf);
  290.         fclose(tmpf);
  291.         tmpf = fopen(lettmp, "r");
  292.         let[++nlet].adr = stbuf.st_size;
  293.         new = 1;
  294.     }
  295.     malf = fopen(mailfile, "w");
  296.     if (malf == NULL) {
  297.         fprintf(stderr, "mail: can't rewrite %s\n", lfil);
  298.         done();
  299.     }
  300.     n = 0;
  301.     for (i = 0; i < nlet; i++)
  302.         if (let[i].change != 'd') {
  303.             copylet(i, malf, ORDINARY);
  304.             n++;
  305.         }
  306.     fclose(malf);
  307.     if (new)
  308.         fprintf(stdout, "new mail arrived\n");
  309.     unlock();
  310. }
  311.  
  312. copymt(f1, f2)    /* copy mail (f1) to temp (f2) */
  313. FILE *f1, *f2;
  314. {
  315.     long nextadr;
  316.  
  317.     nlet = nextadr = 0;
  318.     let[0].adr = 0;
  319.     while (fgets(line, LSIZE, f1) != NULL) {
  320.         if (isfrom(line))
  321.             let[nlet++].adr = nextadr;
  322.         nextadr += strlen(line);
  323.         fputs(line, f2);
  324.     }
  325.     let[nlet].adr = nextadr;    /* last plus 1 */
  326. }
  327.  
  328. copylet(n, f, type) FILE *f;
  329. {    int ch, k;
  330.     fseek(tmpf, let[n].adr, 0);
  331.     k = let[n+1].adr - let[n].adr;
  332.     while(k-- > 1 && (ch=fgetc(tmpf))!='\n')
  333.         if(type!=ZAP) fputc(ch,f);
  334.     if(type==REMOTE)
  335.         fprintf(f, " remote from %s\n", thissys);
  336.     else if (type==FORWARD)
  337.         fprintf(f, forwmsg);
  338.     else if(type==ORDINARY)
  339.         fputc(ch,f);
  340.     while(k-->1)
  341.         fputc(ch=fgetc(tmpf), f);
  342.     if(type!=ZAP || ch!= '\n')
  343.         fputc(fgetc(tmpf), f);
  344. }
  345.  
  346. isfrom(lp)
  347. register char *lp;
  348. {
  349.     register char *p;
  350.  
  351.     for (p = from; *p; )
  352.         if (*lp++ != *p++)
  353.             return(0);
  354.     return(1);
  355. }
  356.  
  357. sendmail(argc, argv)
  358. char **argv;
  359. {
  360.  
  361.     time(&iop);
  362.     fprintf(tmpf, "%s%s %s", from, my_name, ctime(&iop));
  363.     iop = ftell(tmpf);
  364.     flgf = 1;
  365.     while (fgets(line, LSIZE, stdin) != NULL) {
  366.         if (line[0] == '.' && line[1] == '\n')
  367.             break;
  368.         if (isfrom(line))
  369.             fputs(">", tmpf);
  370.         fputs(line, tmpf);
  371.         flgf = 0;
  372.     }
  373.     fputs("\n", tmpf);
  374.     nlet = 1;
  375.     let[0].adr = 0;
  376.     let[1].adr = ftell(tmpf);
  377.     fclose(tmpf);
  378.     if (flgf)
  379.         return;
  380.     tmpf = fopen(lettmp, "r");
  381.     if (tmpf == NULL) {
  382.         fprintf(stderr, "mail: cannot reopen %s for reading\n", lettmp);
  383.         return;
  384.     }
  385.     while (--argc > 0)
  386.         if (!send(0, *++argv))    /* couldn't send to him */
  387.             error++;
  388.     if (error) {
  389.         setuid(getuid());
  390.         malf = fopen(dead, "w");
  391.         if (malf == NULL) {
  392.             fprintf(stdout, "mail: cannot open %s\n", dead);
  393.             fclose(tmpf);
  394.             return;
  395.         }
  396.         copylet(0, malf, ZAP);
  397.         fclose(malf);
  398.         fprintf(stdout, "Mail saved in %s\n", dead);
  399.     }
  400.     fclose(tmpf);
  401. }
  402.  
  403. sendrmt(n, name)
  404. char *name;
  405. {
  406.     FILE *rmf, *popen();
  407.     register char *p;
  408.     char rsys[64], cmd[64];
  409.     register local, pid;
  410.     int sts;
  411.  
  412.     local = 0;
  413.     if (*name=='!')
  414.         name++;
  415.     for(p=rsys; *name!='!'; *p++ = *name++)
  416.         if (*name=='\0') {
  417.             local++;
  418.             break;
  419.         }
  420.     *p = '\0';
  421.     if ((!local && *name=='\0') || (local && *rsys=='\0')) {
  422.         fprintf(stdout, "null name\n");
  423.         return(0);
  424.     }
  425.     if ((pid = fork()) == -1) {
  426.         fprintf(stderr, "mail: can't create proc for remote\n");
  427.         return(0);
  428.     }
  429.     if (pid) {
  430.         while (wait(&sts) != pid) {
  431.             if (wait(&sts)==-1)
  432.                 return(0);
  433.         }
  434.         return(!sts);
  435.     }
  436.     setuid(getuid());
  437.     if (local)
  438.         sprintf(cmd, "mail %s", rsys);
  439.     else {
  440.         if (index(name+1, '!'))
  441.             sprintf(cmd, "uux - %s!rmail \\(%s\\)", rsys, name+1);
  442.         else
  443.             sprintf(cmd, "uux - %s!rmail %s", rsys, name+1);
  444.     }
  445.     if ((rmf=popen(cmd, "w")) == NULL)
  446.         exit(1);
  447.     copylet(n, rmf, local? FORWARD: REMOTE);
  448.     pclose(rmf);
  449.     exit(0);
  450. }
  451.  
  452. send(n, name)    /* send letter n to name */
  453. int n;
  454. char *name;
  455. {
  456.     char file[50];
  457.     register char *p;
  458.     register mask;
  459.     struct passwd *pw, *getpwnam();
  460.  
  461.     for(p=name; *p!='!' &&*p!='\0'; p++)
  462.         ;
  463.     if (*p == '!')
  464.         return(sendrmt(n, name));
  465.     if ((pw = getpwnam(name)) == NULL) {
  466.         fprintf(stdout, "mail: can't send to %s\n", name);
  467.         return(0);
  468.     }
  469.     cat(file, maildir, name);
  470.     mask = umask(MAILMODE);
  471.     malf = fopen(file, "a");
  472.     umask(mask);
  473.     if (malf == NULL) {
  474.         fprintf(stdout, "mail: cannot append to %s\n", file);
  475.         return(0);
  476.     }
  477.     lock(file);
  478.     chown(file, pw->pw_uid, pw->pw_gid);
  479.     copylet(n, malf, ORDINARY);
  480.     fclose(malf);
  481.     unlock();
  482.     return(1);
  483. }
  484.  
  485. delete(i)
  486. {
  487.     setsig(i, delete);
  488.     fprintf(stderr, "\n");
  489.     if(delflg)
  490.         longjmp(sjbuf, 1);
  491.     done();
  492. }
  493.  
  494. done()
  495. {
  496.     if(!lockerror)
  497.         unlock();
  498.     unlink(lettmp);
  499.     exit(error+lockerror);
  500. }
  501.  
  502. lock(file)
  503. char *file;
  504. {
  505.     struct stat stbuf;
  506.  
  507.     if (locked || flgf)
  508.         return;
  509.     if (stat(file, &stbuf)<0)
  510.         return;
  511.     if (stbuf.st_mode&01) {     /* user x bit is the lock */
  512.         if (stbuf.st_ctime+60 >= time((long *)0)) {
  513.             fprintf(stderr, "%s busy; try again in a minute\n", file);
  514.             lockerror++;
  515.             done();
  516.         }
  517.     }
  518.     locked = stbuf.st_mode & ~01;
  519.     curlock = file;
  520.     chmod(file, stbuf.st_mode|01);
  521. }
  522.  
  523. unlock()
  524. {
  525.     if (locked)
  526.         chmod(curlock, locked);
  527.     locked = 0;
  528. }
  529.  
  530. cat(to, from1, from2)
  531. char *to, *from1, *from2;
  532. {
  533.     int i, j;
  534.  
  535.     j = 0;
  536.     for (i=0; from1[i]; i++)
  537.         to[j++] = from1[i];
  538.     for (i=0; from2[i]; i++)
  539.         to[j++] = from2[i];
  540.     to[j] = 0;
  541. }
  542.  
  543. char *getarg(s, p)    /* copy p... into s, update p */
  544. register char *s, *p;
  545. {
  546.     while (*p == ' ' || *p == '\t')
  547.         p++;
  548.     if (*p == '\n' || *p == '\0')
  549.         return(NULL);
  550.     while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
  551.         *s++ = *p++;
  552.     *s = '\0';
  553.     return(p);
  554. }
  555.