home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / src / local / lo_wtmail.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-02-28  |  26.1 KB  |  1,139 lines

  1. /*
  2.  *    Deliver to the users mailbox
  3.  *    Does most of the interesting, non-mechanical work. It tries hard
  4.  *    not to parse the message unless needed.
  5.  *
  6.  *    Severe hacking done this file reconstructed from bits of old
  7.  *    qu2lo_send.c and a lot of new stuff.
  8.  *
  9.  *    Julian Onions <jpo@cs.nott.ac.uk>    August 1985
  10.  */
  11.  
  12. #include "util.h"
  13. #include "mmdf.h"
  14. #include "phs.h"
  15. #include "ap.h"
  16. #include "ch.h"
  17. #include <pwd.h>
  18. #include <sys/stat.h>
  19. #include <signal.h>
  20. #include <sgtty.h>
  21. #include "adr_queue.h"
  22. #include "hdr.h"
  23.  
  24. extern Chan    *chanptr;
  25. extern LLog    *logptr;
  26.  
  27. extern int    errno;
  28.  
  29. extern int    sentprotect;
  30. extern int    flgtrest;
  31. extern int    numfds;
  32. extern long    qu_msglen;
  33. extern jmp_buf  timerest;
  34.  
  35. extern char     *strcpy();
  36.  
  37. extern char *mldflfil;        /* name of local mailbox file        */
  38. extern char *mldfldir;        /* name of local mailbox directory    */
  39. extern char *delim1;        /* prefix and suffix lines for        */
  40. extern char *delim2;        /*    delivery mailbox/msg        */
  41. extern char *dlvfile;        /* name of user deliver control file    */
  42. extern char *sysdlvfile;    /* name of system deliver control file  */
  43. extern char *lckdfldir;        /* directory to lock in            */
  44.  
  45. LOCVAR int    mbx_fd = -1;    /* handle on recipient mailbox        */
  46.  
  47. extern char lo_info[];        /* type of delivery        */
  48. extern char lo_sender[];    /* return address for message    */
  49. extern char lo_adr[];        /* destination address from deliver */
  50. extern char lo_replyto[];    /* the reply address        */
  51. extern char lo_size[];
  52. extern char *lo_parm;        /* parameter portion of address */
  53. extern struct passwd *lo_pw;    /* passwd struct for recipient  */
  54.  
  55. extern  long    lseek();
  56. extern    char    *strdup();
  57. extern    char    *expand();
  58.  
  59. int    sigpipe;        /* has pipe gone bad? */
  60. sigtype    onpipe();        /* catch that pipe write failure */
  61. LOCVAR char mbx_wasclear;    /* this message the first in mbox?    */
  62.  
  63. LOCFUN lo_dofile(), qu2lo_txtcpy(), lo_pwait(), mbx_create(), mbx_close(),
  64.     mbx_chkdelim(), hdr_line(), hdr_parse(), lookup(), setupenv();
  65.  
  66. /*    Structure used in lookup routines */
  67.  
  68. typedef struct {
  69.     char    *l_key;
  70.     short    l_val;
  71. } Lookup;
  72.  
  73. # define    MAXLINES    200    /* max no. of lines in .maildelivery */
  74.  
  75. /* the action types */
  76. # define    M_FILE        1
  77. # define    M_PIPE        2
  78. # define    M_DESTROY    4
  79.  
  80. /* the result types */
  81. # define    M_ACCEPT    01
  82. # define    M_REJECT    02
  83. # define    M_CONDACC    03
  84.  
  85. /* the special headers */
  86. # define    M_DEFAULT    1
  87. # define    M_TRUE        2
  88. # define    M_ADDRESS    3
  89. # define    M_SENDER    4
  90.  
  91. typedef struct mdlvry {
  92.     char    *m_header;        /* the header string    */
  93.     char    *m_pattern;        /* the pattern to match */
  94.     char    *m_options;        /* the options string    */
  95.     unsigned short m_parse      : 1;  /* header type        */
  96.     unsigned short m_special  : 1;  /* special actions?    */
  97.     unsigned short m_hit      : 1;  /* have we hit        */
  98.     unsigned short m_ar      : 2;  /* accept reject bits    */
  99.     unsigned short m_dollar   : 3;  /* the dollar field    */
  100.     unsigned short m_action   : 4;  /* the action to do    */
  101.     unsigned short m_hdrtype  : 4;  /* the special hdr type */
  102. } Mdlvry;
  103.  
  104. Lookup  spec_hdrs[] = { /* the table of special headers */
  105.     "default",    M_DEFAULT,
  106.     "true",        M_TRUE,
  107.     "addr",        M_ADDRESS,
  108.     "source",    M_SENDER,
  109.     "*",        M_TRUE,
  110.     0,        0,
  111. };
  112.  
  113. Lookup  actions[] = {    /* the table of actions */
  114.     "pipe",        M_PIPE,
  115.     "qpipe",    M_PIPE,
  116.     "file",        M_FILE,
  117.     "destroy",    M_DESTROY,
  118.     "|",        M_PIPE,
  119.     "^",        M_PIPE,
  120.     ">",        M_FILE,
  121.     0,    0,
  122. };
  123.  
  124. Lookup  dolfields[] = {
  125.     "$(reply-to)",  1,
  126.     0,        0,
  127. };
  128.  
  129. /*
  130.  *    Give the user something nice in the environment.
  131.  */
  132. LOCVAR char *envp[] = {
  133.     (char *) 0,        /* HOME=xxx  */
  134.     (char *) 0,        /* SHELL=xxx */
  135.     (char *) 0,        /* USER=xxx  */
  136.     0
  137. };
  138.  
  139. /*
  140.  *    Some things that can be macro expanded.
  141.  */
  142. LOCVAR char *vararray[] = {
  143.     "sender",    lo_sender,    /* 0/1 */
  144.     "address",    lo_adr,        /* 2/3 */
  145.     "info",        lo_info,    /* 4/5 */
  146.     "reply-to",    lo_replyto,    /* 6/7 */
  147.     "size",        lo_size,    /* 8/9 */
  148.     0,        0
  149. };
  150.  
  151. /*
  152.  * characters that need to be padded to pass to a shell
  153.  */
  154.  
  155. LOCVAR char *padchar = " \\\"'%$@#?!*|<>()&^~=+-;";
  156.  
  157.  
  158. /*   */
  159.  
  160. lo_slave ()
  161. {
  162.     char    buf[LINESIZE];
  163.     register int      result;
  164.     Mdlvry    mdlv;    /* A fake construct */
  165.     Mdlvry    *mp;
  166.  
  167. #ifdef DEBUG
  168.     ll_log (logptr, LLOGBTR, "lo_slave()");
  169. #endif
  170.     mp = &mdlv;
  171.     printx ("\n");
  172.     /* The production system of delivery attempts */
  173.  
  174.     /* FIRST Attempt: alias file specified file or pipe delivery */
  175.  
  176.     switch (*lo_parm) {
  177.     case '|':    /* send to special process        */
  178.         printx ("(sending message to piped process)\r\n\t");
  179.         sprintf (buf, "default - | A \"%s\"", lo_parm+1);
  180.         if( parse_line(mp, buf) != OK)
  181.             ll_log (logptr, LLOGTMP, "problem parsing '%s'", buf);
  182.         return ( lo_dorules(mp, mp+1) );
  183.     case '^':
  184.         printx ("(sending message to process unformatted)\r\n\t");
  185.         sprintf (buf, "default - ^ A \"%s\"", lo_parm + 1);
  186.         if( parse_line (mp, buf) != OK)
  187.             ll_log (logptr, LLOGTMP, "problem parsing '%s'", buf);
  188.         return ( lo_dorules(mp, mp+1) );
  189.     case '/':
  190.         printx ("(placing into mail file '%s')\r\n\t", lo_parm+1);
  191.         sprintf (buf, "default - > A \"%s\"", lo_parm +1 );
  192.         if( parse_line (mp, buf) != OK)
  193.             ll_log (logptr, LLOGTMP, "problem parsing '%s'", buf);
  194.         return (lo_dorules (mp, mp + 1));
  195.     }
  196.  
  197.     /*
  198.      * SECOND Attempt: user's .maildelivery file
  199.      */
  200.  
  201.     if (rp_isgood (result = lo_dlvfile(dlvfile))
  202.             || result != RP_MECH)
  203.         return (result);
  204.  
  205.     /* THIRD Attempt: system delivery file */
  206.  
  207.     if (rp_isgood (result = lo_dlvfile(sysdlvfile))
  208.             || result != RP_MECH)
  209.         return (result);
  210.  
  211.     /* FOURTH Attempt: regular deliver to the mailbox */
  212.  
  213.     printx ("trying normal delivery\r\n");
  214.     sprintf (buf, "%s/%s",
  215.         (mldfldir == 0 || isnull(mldfldir[0])) ? "." : mldfldir,
  216.         (mldflfil == 0 || isnull(mldflfil[0])) ? lo_pw->pw_name : mldflfil);
  217.     return (lo_dofile (buf));
  218. }
  219. /* *************** FILE DELIVERY ROUTINES *************** */
  220.  
  221. LOCFUN
  222. lo_dofile(mboxname)
  223. char    *mboxname;
  224. {
  225.     register int    retval;
  226.  
  227. #ifdef    DEBUG
  228.     ll_log (logptr, LLOGBTR, "lo_dofile(%s)", mboxname);
  229. #endif /* DEBUG */
  230.     printx ("\tdelivering to file '%s'", mboxname);
  231.  
  232.     if (rp_gval(retval = mbx_open (mboxname)) == RP_LOCK) {
  233.         printx (", locked out\r\n");
  234.         return (RP_LOCK);
  235.     } else if (rp_isbad(retval)) {
  236.         printx (", failed\r\n");
  237.         return (retval);
  238.     }
  239.     retval = qu2lo_txtcpy (mbx_fd, TRUE);
  240.     mbx_close (mboxname);
  241.     printx (rp_isgood (retval) ? ", succeeded\r\n" : ", failed\r\n");
  242.     return (retval);
  243. }
  244.  
  245. LOCFUN
  246. qu2lo_txtcpy (ofd, tstdelim)    /* copy the text of the message          */
  247. register int ofd;        /* where to send the text */
  248. register int tstdelim;        /* should we check for message delimiters? */
  249. {
  250.     register int offset;
  251.     int    len;
  252.     int    result;
  253.     char    buffer[BUFSIZ];
  254.  
  255. #ifdef DEBUG
  256.     ll_log (logptr, LLOGBTR, "qu2lo_txtcpy()");
  257. #endif
  258.  
  259.     qu_rtinit (0L);
  260.     len = sizeof(buffer);
  261.     while (rp_gval (result = qu_rtxt (buffer, &len)) == RP_OK) {
  262.         if (tstdelim) {       /* text may not contain a delimiter     */
  263.             /*
  264.              *  Check for occurences of the message delimiter.
  265.              *  If we find any, change the string by changing
  266.              *  the first char to a space.
  267.              */
  268.             if( isstr(delim1) )
  269.                 for (offset = 0;
  270.                      (offset = strindex (delim1, buffer)) >= 0;
  271.                     buffer[offset] = ' ');
  272.  
  273.             if( isstr(delim2) )
  274.                 for (offset = 0;
  275.                      (offset = strindex (delim2, buffer)) >= 0;
  276.                     buffer[offset] = ' ');
  277.         }
  278.         if (write (ofd, buffer, len) != len) {
  279.             ll_err (logptr, LLOGTMP, "error writing out text");
  280.             return (RP_LIO);
  281.         }
  282.         len = sizeof(buffer);
  283.     }
  284.  
  285.     if (rp_gval (result) != RP_DONE)
  286.         return (RP_LIO);     /* didn't get it all across? */
  287.  
  288.     return (RP_MOK);          /* got the text out            */
  289. }
  290. /* *************** PIPE DELIVERY ROUTINES *************** */
  291.  
  292. LOCFUN
  293. lo_dopipe(prog)
  294. char    *prog;
  295. {
  296.     int    childid;        /* child does the real work */
  297.     int    ofd;            /* what to write on */
  298.     char    tmpbuf[LINESIZE];
  299.     char    buffer[BUFSIZ];
  300.     sigtype    (*savepipe)();
  301.     Pip    pipdes;
  302.     int    result;
  303.     int    len;
  304.  
  305. #ifdef    DEBUG
  306.     ll_log (logptr, LLOGBTR, "lo_dopipe(%s)", prog);
  307. #endif /* DEBUG */
  308.  
  309.     if( pipe(pipdes.pipcall) == NOTOK)
  310.         return (RP_LIO);
  311.  
  312.     ll_close(logptr);
  313.     switch (childid = fork ()) {
  314.     case NOTOK:
  315.         (void) close(pipdes.pip.prd);
  316.         (void) close(pipdes.pip.pwrt);
  317.         return (RP_LIO);    /* problem with system */
  318.  
  319.     case OK:
  320.         /* Child */
  321.         lo_padadr();
  322.         /* first - expand out any '$' keywords */
  323.         expand (tmpbuf, prog, vararray);
  324. #ifdef DEBUG
  325.         ll_log (logptr, LLOGBTR, "lo_dopipe() child (%s)", tmpbuf);
  326. #endif
  327.         printx ("\tdelivering to pipe '%s'", tmpbuf);
  328.         fflush (stdout);
  329.         (void) close(0);
  330.         dup (pipdes.pip.prd);
  331.  
  332.         setupenv();
  333.  
  334.         execle ("/bin/sh", "sh", "-c", tmpbuf, (char *)0, envp);
  335.         ll_log( logptr, LLOGFAT, "Can't execl /bin/sh (%d)",errno);
  336.         exit (RP_MECH);
  337.     }
  338.  
  339.     /* Parent */
  340.     /* our job is to pass on the message to the process */
  341.     (void) close (pipdes.pip.prd);
  342.     ofd = pipdes.pip.pwrt;  /* nicer name */
  343.     qu_rtinit(0L);        /* init the message */
  344.     savepipe = signal(SIGPIPE, onpipe);
  345.     sigpipe = FALSE;
  346.     len = sizeof(buffer);
  347.     while (rp_gval(result = qu_rtxt(buffer, &len)) == RP_OK)
  348.     {
  349.         if( sigpipe )    /* childs had enough */
  350.             break;
  351.         if( write(ofd, buffer, len) != len)
  352.         {
  353.             if( errno != EPIPE)
  354.                 ll_err (logptr, LLOGTMP, "error on pipe %d",
  355.                     errno);
  356.             break;
  357.         }
  358.         len = sizeof(buffer);
  359.     }
  360.     (void) close(ofd);    /* finished with pipe */
  361.     signal(SIGPIPE, savepipe);    /* restore the dying signal */
  362.     if(rp_gval(result) != RP_OK && rp_gval(result) != RP_DONE)
  363.         return result;
  364.     return (lo_pwait (childid, prog)); /* .... and wait */
  365. }
  366.  
  367. LOCFUN
  368. lo_pwait (procid, prog)        /* wait for child to complete          */
  369. int    procid;            /* id of child process              */
  370. char    *prog;
  371. {
  372.     int status;
  373.  
  374. #ifdef DEBUG
  375.     ll_log (logptr, LLOGBTR, "lo_pwait ()");
  376. #endif
  377.  
  378.     if (setjmp (timerest) == 0)
  379.     {            /* alarm is in case user's pgm hangs    */
  380.         flgtrest = TRUE;
  381.         /*NOSTRICT*/
  382.         s_alarm ((unsigned) (qu_msglen / 20) + 300);
  383.         errno = 0;
  384.         status = pgmwait (procid);
  385.         s_alarm (0);
  386.         if (status == NOTOK) {
  387.             /* system killed the process */
  388.             ll_err (logptr, LLOGTMP, "bad return: (%s) %s [wait=NOTOK]",
  389.                 lo_pw->pw_name, prog);
  390.             return (RP_LIO);
  391.         }
  392.         ll_log (logptr, LLOGBTR, "(%s) %s [%s]",
  393.             lo_pw->pw_name, prog, rp_valstr (status));
  394.         if( status == 0)    /* A-OK */
  395.         {
  396.             printx (", succeeded\r\n");
  397.             return (RP_MOK);
  398.         }
  399.         else if(status == 1)    /* command not found - ECB */
  400.         {
  401.             printx (", failed (PATH)\r\n");
  402.             return (RP_MECH);
  403.         }
  404.         else if( rp_gbval(status) == RP_BNO)    /* permanent error */
  405.         {
  406.             printx (", failed (perm)\r\n");
  407.             return (RP_NO);
  408.         }
  409.         else    /* temp error */
  410.         {
  411.             printx (", failed (temp)\r\n");
  412.             return (RP_MECH);
  413.         }
  414.         /* NOTREACHED */
  415.     }
  416.     else
  417.     {
  418.         flgtrest = FALSE;
  419.         printx (", user program taking too long");
  420.         ll_log (logptr, LLOGGEN, "user program taking too long - killing");
  421. #ifndef V4_2BSD
  422.         kill (procid, SIGKILL); /* we're superuser, so always works */
  423. #else /* V4_2BSD */
  424.         killpg (procid, SIGKILL); /* we're superuser, so always works*/
  425. #endif /* V4_2BSD */
  426.         return (RP_TIME);
  427.     }
  428. }
  429.  
  430. /*  ensure that all addresses can be passed to shell */
  431. lo_padadr()
  432. {
  433.     static done_pad = 0;
  434.     register int i;
  435.     register char *c1, *c2, *p;
  436.     char tmp[2 * LINESIZE];
  437.  
  438.     if (done_pad)
  439.     return;
  440.  
  441.     for(i=0; vararray[i] != 0; i += 2)
  442.     {
  443.     (void) strcpy(tmp,vararray[i+1]);
  444.  
  445.     for(c1=tmp,c2=vararray[i+1]; *c1 != '\0'; c1++)
  446.     {
  447.         for(p=padchar; *p != '\0';  p++)
  448.         {
  449.         if (*p == *c1)
  450.         {
  451.             *c2++ = '\\';
  452.             break;
  453.         }
  454.         }
  455.  
  456.         *c2++ = *c1;
  457.     }
  458.     *c2 = '\0';
  459.     }
  460. }
  461.  
  462. /* *******  (mbx_)  STANDARD DELIVERY TO MAILBOX STYLE FILE  *********** */
  463.  
  464. mbx_open (file)            /* stuff into mailbox              */
  465. char    *file;
  466. {
  467.     struct stat    mbxstat;
  468.     register int    count;
  469.     short     retval;
  470.     int    mbxmade;        /* Infinite loop preventer */
  471.  
  472. #ifdef DEBUG
  473.     ll_log (logptr, LLOGBTR, "mbx_open (%s)", file);
  474. #endif
  475.     mbxmade = mbx_wasclear = FALSE;
  476. reopen:
  477.     if ((mbx_fd = lk_open (file, 2, (char *) 0, (char *) 0, 10)) < 0)
  478.     {
  479.         switch (errno) {
  480. #ifdef EWOULDBLOCK
  481.         case EWOULDBLOCK:
  482. #endif /* EWOULDBLOCK */
  483.         case ETXTBSY:
  484.             printx (", mail file is locked");
  485.             return (RP_LOCK);
  486.  
  487.         case ENOENT:      /* doesn't exist */
  488.             if (!mbxmade && rp_isgood (mbx_create (file))) {
  489.                 printx (", mail file created");
  490.                 mbxmade = mbx_wasclear = TRUE;
  491.                 goto reopen;
  492.             }
  493.             /* DROP THROUGH */
  494.         default:
  495.             ll_err (logptr, LLOGTMP, "can't open mailbox '%s'",
  496.                                 file);
  497.             return (RP_LIO);
  498.         }
  499.     }
  500.     else
  501.     {
  502.         if (fstat (mbx_fd, &mbxstat) < 0)
  503.         {
  504.             ll_err (logptr, LLOGTMP, "can't fstat %s", file);
  505.             return (RP_LIO);
  506.         }
  507.         mbx_wasclear = (st_gsize (&mbxstat) == 0L);
  508.     }
  509.  
  510.     if (!mbx_wasclear && rp_isbad (retval = mbx_chkdelim ()))
  511.         return (retval);          /* mbox has bad terminator        */
  512.  
  513.     count = strlen (delim1);      /* write prefatory separator        */
  514.     if (write (mbx_fd, delim1, count) != count)
  515.     {
  516.         ll_err (logptr, LLOGTMP, "error writing delim1");
  517.         return (RP_LIO);
  518.     }
  519.  
  520.     return (RP_OK);
  521. }
  522. /* */
  523.  
  524. LOCFUN
  525. mbx_create (mboxname)    /* create receiver's mailbox file     */
  526. char    *mboxname;
  527. {
  528. #ifdef DEBUG
  529.     ll_log (logptr, LLOGBTR, "mbx_create (%s)", mboxname);
  530. #endif
  531.  
  532.     if ((mbx_fd = creat (mboxname, sentprotect)) < 0)
  533.     {
  534.         ll_err (logptr, LLOGFAT, "can't create mailbox '%s'",
  535.                         mboxname);
  536.         return (RP_LIO);
  537.     }
  538.     (void) close (mbx_fd);    /* unix create() forces wrong modes    */
  539.  
  540.     return (RP_OK);
  541. }
  542.  
  543. LOCFUN
  544. mbx_close (file)    /* done with mailbox    */
  545. char    *file;
  546. {
  547.     short      count;
  548.  
  549. #ifdef DEBUG
  550.     ll_log (logptr, LLOGBTR, "mbx_close ()");
  551. #endif
  552.     if (mbx_fd < 0)
  553.     {
  554. #ifdef DEBUG
  555.         ll_log (logptr, LLOGFTR, "not open");
  556. #endif
  557.         return;
  558.     }
  559.  
  560.     count = strlen (delim2);
  561.     if (write (mbx_fd, delim2, count) != count)
  562.     {    /* couldn't put ending delimiter on   */
  563.         ll_err (logptr, LLOGTMP, "error writing delim2");
  564.     }
  565.     lk_close (mbx_fd, file, (char *) 0, (char *) 0);
  566.     mbx_fd = -1;
  567. }
  568. /* */
  569.  
  570. LOCFUN
  571. mbx_chkdelim () /* last msg delimited properly?          */
  572. {        /* check ending delimiter of last msg */
  573.     int    count;
  574.     char    ldelim[LINESIZE];
  575.     struct stat statb;
  576.  
  577. #ifdef DEBUG
  578.     ll_log (logptr, LLOGBTR, "mbx_chkdelim ()");
  579. #endif
  580.  
  581.     count = strlen (delim2);
  582.  
  583.     if (lseek (mbx_fd, (long)(-count), 2) == (long) NOTOK ||
  584.         read (mbx_fd, ldelim, count) != count) {
  585.         printx(", mailbox is missing delimiter");
  586.         if (fstat(mbx_fd, &statb) == 0 && statb.st_size < count) {
  587.             lseek(mbx_fd, 0L, 2);
  588.             goto patch;
  589.         }
  590.         printx(", mailbox lseek/read errors");
  591.         return (RP_LIO);
  592.         }
  593.  
  594.     if (count == 0)
  595.         return (RP_OK);
  596.     if (!initstr (delim2, ldelim, count))
  597.     {    /* previous didn't end cleanly. patch */
  598.         ll_err (logptr, LLOGTMP, "bad delim; patching");
  599. patch:        printx("\n\tpatching in missing delimiter");
  600.  
  601.         if ((write (mbx_fd, "\n", 1) != 1) ||
  602.             (write (mbx_fd, delim2, count) != count))
  603.         {            /* write separator    */
  604.             ll_err (logptr, LLOGTMP, "unable to patch");
  605.             return (RP_LIO);
  606.         }
  607.     }
  608.     return (RP_OK);
  609. }
  610. /* ****************** MAILDELIVERY HANDLING ROUTINES ***************/
  611.  
  612. /*
  613.  *    Given a maildelivery format file, this routine parses the
  614.  *    file into an array - then calls dorules to follow the actions.
  615.  *    The file is either personal
  616.  *        e.g. .maildelvery
  617.  *    or else system wide
  618.  *        i.e. /usr/lib/maildlvry
  619.  */
  620.  
  621. lo_dlvfile (dlv_file)
  622. char    *dlv_file;        /* the file to scan */
  623. {
  624.     register FILE *fp;
  625.     struct stat sb;
  626.     Mdlvry  thefile[MAXLINES];    /* the representation of the md file */
  627.     register Mdlvry *mptr, *maxptr;    /* some handy pointers  */
  628.     char    dlvline[LINESIZE];
  629.     int    len;
  630.  
  631. #ifdef    DEBUG
  632.     ll_log (logptr, LLOGBTR, "lo_dlvfile(%s)", seenull(dlv_file));
  633. #endif /* DEBUG */
  634.  
  635.     if ((!isstr(dlv_file)) || (fp = fopen(dlv_file, "r")) == NULL)
  636.         return (RP_MECH);
  637.  
  638.     /*        Security Check!
  639.      *
  640.      *  The file must owned by the person we are delivering to
  641.      *  or the superuser.  In addition, the file must not have
  642.      *  write permission to anyone accept the owner.   (DPK)
  643.      *  In the case of system wide file, this is constrained to
  644.      *  be root generally. (JPO)
  645.      */
  646.  
  647.     if (fstat (fileno(fp), &sb) < 0
  648.         || (sb.st_uid != lo_pw->pw_uid && sb.st_uid != 0)
  649.         || sb.st_mode & 022) {
  650.         printx("ownership problems on '%s'\n", dlv_file);
  651.         ll_log (logptr, LLOGBTR, "ownership problems on '%s'",
  652.                 dlv_file);
  653.         fclose(fp);
  654.         return (RP_MECH);
  655.     }
  656.  
  657.     for (mptr = thefile;
  658.         (len = gcread(fp, dlvline, LINESIZE, "\n\377")) > 0
  659.             && mptr < &thefile[MAXLINES];)
  660.     {
  661.         if( dlvline[0] == '\n' || dlvline[0] == '#' )
  662.             continue;    /* skip this line */
  663.  
  664.         dlvline[len - 1] = '\0'; /* zap the lf */
  665.  
  666.         if( parse_line(mptr, dlvline) == OK)
  667.             mptr ++;
  668.     }
  669.     if ( mptr >= &thefile[MAXLINES] )
  670.         ll_log (logptr, LLOGFST, "more than %d lines in %s (%s)",
  671.             MAXLINES, dlv_file, lo_pw->pw_name);
  672.  
  673.     maxptr = mptr;
  674.     fclose (fp);    /* OK, file finished, take a deep breath and ... */
  675.     return lo_dorules(thefile, maxptr);
  676. }
  677.  
  678. /*
  679.  * apply the given rules. mptr is the begining of an array of
  680.  * rules, mpmax is the last rule in the array + 1.
  681.  */
  682.  
  683. lo_dorules(mptr, mpmax)    /* apply the maildelivwery rules */
  684. Mdlvry    *mptr, *mpmax;
  685. {
  686.     int    doneparse = FALSE;    /* a couple of bools */
  687.     int    delivered = FALSE;
  688.     int    retval;
  689. /*
  690.  *    Now comes the bit where we try and be fearfully clever.
  691.  *    We proceed down the array of md lines, whistling nochalantly,
  692.  *    until we hit a situation where parsing must take place.
  693.  *    At this point (with a sheepish grin) we then go and dig into
  694.  *    the message and see what we can find, and then continue on as
  695.  *    if nothing had happened.
  696.  */
  697.  
  698.     for(; mptr < mpmax; mptr ++)
  699.     {
  700.         if( delivered && mptr->m_ar == M_CONDACC)
  701.             continue;    /* this line can be ignored */
  702.         if( mptr->m_parse && !doneparse)    /* arggh caught out! */
  703.         {
  704.             if(rp_isgood( dotheparse(mptr, mpmax)))
  705.                 doneparse = TRUE;
  706.             else    return RP_NO;
  707.         }
  708.         if(! mptr->m_special )  /* this is a real header */
  709.         {
  710.             if( !mptr->m_hit)
  711.                 continue;    /* but no hit */
  712. #ifdef    DEBUG
  713.             ll_log (logptr, LLOGFTR, "hit with %s (%s)",
  714.                 mptr->m_pattern, mptr->m_header);
  715. #endif /* DEBUG */
  716.             /* else we drop through to beyond the switch */
  717.         }    /* beware the dangling else !! */
  718.         else    /* do the switch */
  719.         {
  720. /* Run through the special case headers, break if hit, continue if miss */
  721.             switch( mptr->m_hdrtype)
  722.             {
  723.             case    M_DEFAULT:
  724.                 if( ! delivered ) /* this applys */
  725.                     break;
  726.                 continue;
  727.             case    M_ADDRESS:
  728.                 if( strindex(mptr->m_pattern, lo_adr) >= 0)
  729.                     break;
  730.                 continue;
  731.             case    M_TRUE: /* always true */
  732.                 break;
  733.             case    M_SENDER:
  734.                 if( strindex(mptr->m_pattern, lo_sender) >= 0)
  735.                     break;
  736.                 continue;
  737.             default: /* what else can we do ? */
  738.                 continue;
  739.             }
  740.         }
  741.                 /* OK, do the action */
  742.         retval = lo_doaction(mptr);
  743.  
  744.         switch( mptr->m_ar)    /* now how did it go ? */
  745.         {
  746.             case    M_CONDACC:
  747.             case    M_ACCEPT:
  748.                 if( rp_isgood(retval))  /* delivered */
  749.                     delivered = TRUE;
  750.                 else if(rp_gval(retval) != RP_NO)
  751.                     return RP_AGN;  /* went bad (temp) */
  752.                 break;
  753.             case    M_REJECT:
  754.                 continue;
  755.         }
  756.     }
  757.     return(delivered ? RP_MOK : RP_MECH);
  758. }
  759.  
  760. parse_line(mptr, line)  /* dump the line into the Mdlvry struct */
  761. Mdlvry  *mptr;
  762. char    *line;
  763. {
  764.     char    *argv[15];    /* the argv array */
  765.     char    opts[LINESIZE]; /* temp space for gathering opts */
  766.     int    argc;
  767.     int    type;
  768.     int    i;
  769.     Lookup  *lp;
  770.  
  771. #ifdef    DEBUG
  772.     ll_log (logptr, LLOGBTR, "parse_line(%s)", line);
  773. #endif /* DEBUG */
  774.  
  775.     argc = sstr2arg(line, 15, argv, " \t,");    /* split it */
  776.     if( argc < 4 )  /* not good enough! */
  777.         return NOTOK;
  778.     if( (type = lookup(argv[0], spec_hdrs)) == -1 ) /* not a special ?*/
  779.     {
  780.         mptr->m_parse = TRUE;
  781.         mptr->m_special = FALSE;
  782.         mptr->m_header = strdup(argv[0]);
  783.         mptr->m_pattern = strdup(argv[1]);
  784. #ifdef    DEBUG
  785.         ll_log (logptr, LLOGFTR, "header='%s' pat='%s'",
  786.                 mptr->m_header, mptr->m_pattern);
  787. #endif /* DEBUG */
  788.     }
  789.     else    /* Oh, it is a special */
  790.     {
  791.         mptr->m_special = TRUE;
  792.         mptr->m_parse = FALSE;
  793.         mptr->m_hdrtype = type;
  794.         mptr->m_header = NULL;
  795.         mptr->m_pattern = strdup(argv[1]);
  796. #ifdef    DEBUG
  797.         ll_log (logptr, LLOGFTR, "special pat='%s'", mptr->m_pattern);
  798. #endif /* DEBUG */
  799.     }
  800.     switch( argv[3][0] )    /* only a,A & ? - anything else == R */
  801.     {
  802.         case    'A':
  803.         case    'a':
  804.             mptr->m_ar = M_ACCEPT;
  805.             break;
  806.         case    '?':
  807.             mptr->m_ar = M_CONDACC;
  808.             break;
  809.         default:
  810.         case    'r':
  811.         case    'R':
  812.             mptr->m_ar = M_REJECT;
  813.             break;
  814.     }
  815. #ifdef    DEBUG
  816.     ll_log (logptr, LLOGFTR, "action=%o", mptr->m_ar);
  817. #endif /* DEBUG */
  818.     if( (type = lookup(argv[2], actions)) == -1)
  819.         ll_log(logptr, LLOGFAT, "Unknown action to perform '%s'\n",
  820.                 argv[2]); /* a `never happens case' */
  821.     else    mptr->m_action = type;
  822. #ifdef    DEBUG
  823.     ll_log (logptr, LLOGFTR, "action=%o", mptr->m_action);
  824. #endif /* DEBUG */
  825.     switch (mptr->m_action )
  826.     {
  827.         case    M_FILE:
  828.             mptr->m_options = strdup(argv[4]);
  829.             break;
  830.         case    M_DESTROY:
  831.             break;
  832.         case    M_PIPE: /* gather together the argv's */
  833.             opts[0] = '\0';
  834.             for( i = 4; i < argc; i++)
  835.             {
  836.                 strcat(opts, argv[i]);
  837.                 if( i != argc -1 )
  838.                     strcat(opts, " ");
  839.             }
  840.             mptr->m_dollar = 0;
  841.             mptr->m_options = strdup(opts);
  842.             for(lp = dolfields; lp->l_key != NULL; lp++)
  843.                 if( strindex(lp->l_key, opts) >= 0)
  844.                 {
  845.                     mptr->m_parse = TRUE;
  846.                     mptr->m_dollar |= lp->l_val;
  847.                 }
  848.             break;
  849.         default:
  850.             break;
  851.     }
  852.     mptr->m_hit = 0;
  853. #ifdef    DEBUG
  854.     ll_log (logptr, LLOGFTR, "dol=%o parse=%o opts='%s'",
  855.             mptr->m_dollar, mptr->m_parse, mptr->m_options);
  856. #endif /* DEBUG */
  857.     return OK;
  858. }
  859. lo_doaction(mp)
  860. Mdlvry    *mp;
  861. {
  862. # ifdef    DEBUG
  863.     ll_log (logptr, LLOGBTR, "lo_doaction");
  864. #endif /* DEBUG */
  865.  
  866.     switch( mp->m_action )
  867.     {
  868.         case    M_DESTROY:    /* /dev/null it */
  869.             return (RP_MOK);
  870.  
  871.         /* pipe has gone away */
  872.         case    M_PIPE:
  873.             return lo_dopipe(mp->m_options);
  874.         case    M_FILE:
  875.             return lo_dofile(mp->m_options);
  876.         default:
  877.             ll_log( logptr, LLOGFAT, "unidentified action type %o",
  878.                     mp->m_action);
  879.             return RP_NO;
  880.     }
  881.     /* NOTREACHED */
  882. }
  883. /* *************** PARSING DELIVERY ROUTINES *************** */
  884.  
  885. /*
  886.  * the routine that actually parses the message and sets up hit/miss
  887.  * bits in the md struct.
  888.  */
  889.  
  890. dotheparse(mpbase, mpmax)
  891. Mdlvry  *mpbase, *mpmax;
  892. {
  893.     char    line[LINESIZE];
  894.     char    name[LINESIZE], contents[LINESIZE];
  895.     Mdlvry  *mp;
  896.     int    len;
  897.     int    gotrepl = 0;
  898.  
  899. # ifdef DEBUG
  900.     ll_log (logptr, LLOGBTR, "dotheparse()");
  901. #endif /* DEBUG */
  902.     /* start reading header */
  903.     qu_rtinit(0L);
  904.  
  905.     while((len = hdr_line(line, LINESIZE)) > 0)
  906.     {
  907.         line[len] = '\0';
  908.         switch(hdr_parse(line, name, contents))
  909.         {
  910.         case    HDR_NAM:
  911.             continue;    /* to avoid break */
  912.  
  913.         case    HDR_EOH:
  914.             break;    /* break out of loop below */
  915.  
  916.         case    HDR_NEW:
  917.         case    HDR_MOR:
  918.             for(mp = mpbase; mp < mpmax; mp++)
  919.             {
  920.                 if( !mp->m_hit && lexequ(mp->m_header, name) &&
  921.                     strindex(mp->m_pattern, contents) >= 0)
  922.                 {
  923.                     mp->m_hit = TRUE;
  924. #ifdef    DEBUG
  925.             ll_log (logptr, LLOGFTR, "hit in parse '%s' & '%s'",
  926.                     contents, mp->m_pattern);
  927. #endif /* DEBUG                     */
  928.                 }
  929.                 if(( mp->m_dollar & 1))
  930.                     if(! gotrepl && lexequ(name, "from"))
  931.                         (void) strcpy(lo_replyto, contents);
  932.                     else if(lexequ(name, "reply-to"))
  933.                     {
  934.                         (void) strcpy(lo_replyto, contents);
  935.                         gotrepl = TRUE;
  936.                     }
  937.             }
  938.             continue;
  939.         } /* end switch */
  940.         break;
  941.     }
  942.  
  943.     if (len <= 0)
  944.         return RP_NO;
  945.     return  RP_OK;
  946. }
  947.  
  948. /* basic processing of incoming header lines */
  949. LOCFUN
  950. hdr_line(buf, len)
  951. char *buf;
  952. int len;
  953. {
  954.     register int count;
  955.     static char hdr_buf[LINESIZE];    /* buffer */
  956.     static int buf_cnt = 0;    /* chars in buf */
  957.     static char *buf_ptr;
  958.     register char *hp;
  959.     register char *bp;
  960.  
  961.     count = len;
  962.     hp = buf_ptr;
  963.     bp = buf;
  964.     while (count > 0)
  965.     {
  966.     if (buf_cnt == 0)
  967.     {
  968.         buf_cnt = sizeof(hdr_buf);
  969.         if (qu_rtxt(hdr_buf,&buf_cnt) != RP_OK)
  970.         buf_cnt = 0;    /* break below */
  971.         hp = hdr_buf;
  972.     }
  973.     
  974.     /* any more chars? */
  975.     if (buf_cnt <= 0)
  976.         break;
  977.  
  978.     /* bugfix from howard */
  979.     buf_cnt--;
  980.     count--;
  981.  
  982.     if ((*bp++ = *hp++) == '\n')
  983.         break;
  984.     }
  985.  
  986.     buf_ptr = hp;
  987.  
  988. #ifdef DEBUG
  989.     ll_log(logptr, LLOGFTR, "hdr_line (%*s)", len-count, (len-count)?buf:"");
  990. #endif
  991.  
  992.     return(len - count);
  993. }
  994.  
  995. LOCFUN
  996. hdr_parse (src, name, contents)      /* parse one header line        */
  997.     register char *src;          /* a line of header text        */
  998.     char *name,              /* where to put field's name        */
  999.      *contents;          /* where to put field's contents    */
  1000. {
  1001.     extern char *compress ();
  1002.     char linetype;
  1003.     register char *dest;
  1004.  
  1005. #ifdef DEBUG
  1006.     ll_log (logptr, LLOGBTR, "hdr_parse(%s)", src);
  1007. #endif
  1008.  
  1009.     if (isspace (*src))
  1010.     {                  /* continuation text            */
  1011. #ifdef DEBUG
  1012.     ll_log (logptr, LLOGFTR, "cmpnt more");
  1013. #endif
  1014.     if (*src == '\n')
  1015.         return (HDR_EOH);
  1016.     linetype = HDR_MOR;
  1017.     }
  1018.     else
  1019.     {                  /* copy the name            */
  1020.     linetype = HDR_NEW;
  1021.     for (dest = name; *dest = *src++; dest++)
  1022.     {
  1023.         if (*dest == ':')
  1024.         break;          /* end of the name            */
  1025.         if (*dest == '\n')
  1026.         {              /* oops, end of the line        */
  1027.         *dest = '\0';
  1028.         return (HDR_NAM);
  1029.         }
  1030.     }
  1031.     *dest = '\0';
  1032.     compress (name, name);      /* strip extra & trailing spaces    */
  1033. #ifdef DEBUG
  1034.     ll_log (logptr, LLOGFTR, "cmpnt name '%s'", name);
  1035. #endif
  1036.     }
  1037.  
  1038.     for (dest = contents; isspace (*src); )
  1039.     if (*src++ == '\n')      /* skip leading white space        */
  1040.     {              /* unfulfilled promise, no contents    */
  1041.         *dest = '\0';
  1042.         return ((linetype == HDR_MOR) ? HDR_EOH : linetype);
  1043.     }               /* hack to fix up illegal spaces     */
  1044.  
  1045.     while ((*dest = *src) != '\n' && *src != 0)
  1046.          src++, dest++;      /* copy contents and then, backup    */
  1047.     while (isspace (*--dest));      /*   to eliminate trailing spaces    */
  1048.     *++dest = '\0';
  1049.  
  1050.     return (linetype);
  1051. }
  1052. /* **************  (misc) MISCELLANEOUS ROUTINES  ******************** */
  1053.  
  1054. /*
  1055.  *    Dig into table for a match - return associated value else -1
  1056.  *    table ends when key == 0;
  1057.  *        (JPO)
  1058.  */
  1059.  
  1060. LOCFUN
  1061. lookup( str, table )
  1062. char    *str;
  1063. Lookup  table[];
  1064. {
  1065.     register Lookup *p;
  1066.  
  1067.     for(p = table; p -> l_key ; p++)
  1068.     {
  1069. /*
  1070.  * match with prefix, this allows "addr" to match "address"
  1071.  */
  1072.         if( prefix(p -> l_key, str) )
  1073.             return (p -> l_val);
  1074.     }
  1075.     return (-1);
  1076. }
  1077.  
  1078. /*
  1079.  * setup the environment for the process to run in. This includes :-
  1080.  *    Environment variables
  1081.  *    file descriptors - close all but fd0
  1082.  *    process groups
  1083.  *    controlling ttys.
  1084.  *    umask
  1085.  */
  1086.  
  1087. LOCFUN setupenv()
  1088. {
  1089.     int    fd;
  1090.     static char    homestr[64];        /* environment $HOME param */
  1091.     static char    shellstr[64];        /* environment $SHELL param */
  1092.     static char    userstr[64];        /* environment $USER param */
  1093.  
  1094. #ifdef    DEBUG
  1095.     ll_log (logptr, LLOGBTR, "setupenv()");
  1096. #endif /* DEBUG */
  1097.     for (fd = 1; fd < numfds; fd++)
  1098.         (void) close (fd);
  1099.     fd = open ("/dev/null", 1);    /* stdout */
  1100.     dup (fd);            /* stderr */
  1101.  
  1102.     umask(077);    /* Restrictive umask */
  1103.  
  1104. #ifdef TIOCNOTTY
  1105.     if (setjmp (timerest) == 0)
  1106.     {
  1107.         flgtrest = TRUE;
  1108.         s_alarm(15);    /* should be enough */
  1109.         if( (fd = open("/dev/tty", 2)) != NOTOK) {
  1110.             (void) ioctl(fd, TIOCNOTTY, (char *)0);
  1111.             (void) close(fd);
  1112.         }
  1113.         s_alarm(0);
  1114.     }
  1115.     else
  1116.     {
  1117.         flgtrest = FALSE;
  1118.         ll_log (logptr, LLOGGEN, "TIOCNOTTY not available");
  1119.     }
  1120. #endif /* TIOCNOTTY */
  1121. #ifdef V4_2BSD
  1122.     setpgrp (0, getpid());
  1123. #endif
  1124.     sprintf (homestr, "HOME=%s", lo_pw->pw_dir);
  1125.     sprintf (shellstr, "SHELL=%s",
  1126.             isstr(lo_pw->pw_shell) ? lo_pw->pw_shell : "/bin/sh");
  1127.     sprintf (userstr, "USER=%s", lo_pw->pw_name);
  1128.     envp[0] = homestr;
  1129.     envp[1] = shellstr;
  1130.     envp[2] = userstr;
  1131. }
  1132.  
  1133. sigtype
  1134. onpipe()
  1135. {
  1136.     signal(SIGPIPE, onpipe);
  1137.     sigpipe = TRUE;
  1138. }
  1139.