home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / system / mail / delivery / deliver.tz / deliver / copymsg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-07  |  8.6 KB  |  459 lines

  1. /* $Header: copymsg.c,v 2.4 90/02/06 11:56:38 chip Exp $
  2.  *
  3.  * Take the message from standard input and write it to two temp files,
  4.  * one for the header (including the empty line) and one for the body.
  5.  *
  6.  * $Log:    copymsg.c,v $
  7.  * Revision 2.4  90/02/06  11:56:38  chip
  8.  * Enforce MBX_MODE regardless of UMASK.
  9.  * Enforce ordered logging with a log lockfile.
  10.  * Revise log format.
  11.  * 
  12.  * Revision 2.3  89/11/27  14:18:29  network
  13.  * Strip trailing spaces from date on From_ line.
  14.  * 
  15.  * Revision 2.2  89/09/29  18:17:53  network
  16.  * Save message when delivery file produces no output,
  17.  * unless delivery file output the "DROP" string.
  18.  * Don't recopy temp files for sys and post-user delfiles.
  19.  * 
  20.  * Revision 2.1  89/06/09  12:25:16  network
  21.  * Update RCS revisions.
  22.  * 
  23.  * Revision 1.9  89/06/09  12:23:40  network
  24.  * Baseline for 2.0 release.
  25.  * 
  26.  */
  27.  
  28. #include "deliver.h"
  29.  
  30. /*
  31.  * Macros.
  32.  */
  33.  
  34. /* Does a string start with "From "? */
  35.  
  36. #define ISFROM(p) ((p)[0] == 'F' && (p)[1] == 'r' && (p)[2] == 'o' \
  37.         && (p)[3] == 'm' && (p)[4] == ' ')
  38.  
  39. /*----------------------------------------------------------------------
  40.  * Copy the message on the standard input to two temp files:
  41.  * one for the header and one for the body.
  42.  */
  43.  
  44. int
  45. copy_message()
  46. {
  47.     char    buf[BUFSIZ];
  48.     FILE    *dfp[T_MAX];
  49.     char    *p, *from_line, *fsender, *fdate, *fremote;
  50.     int     t, b, empty_line;
  51.     int     ret = 0;
  52.  
  53.     /*
  54.      * Create temporary files to hold the header and message body.
  55.      */
  56.  
  57.     for (t = T_HDR; t <= T_BODY; ++t)
  58.     {
  59.         int     fd;
  60.  
  61.         tfile[t] = tempfile();
  62.         if ((tfd[t] = tcreate(tfile[t])) == -1)
  63.             return -1;
  64.  
  65.         if ((fd = dup(tfd[t])) == -1)
  66.         {
  67.             syserr("dup %s fd", ttype[t]);
  68.             return -1;
  69.         }
  70.         (void) lseek(fd, 0L, 0);
  71.         if ((dfp[t] = fdopen(fd, "r+")) == NULL)
  72.         {
  73.             error("can't fdopen %s fd", ttype[t]);
  74.             return -1;
  75.         }
  76.     }
  77.  
  78.     /* Debugging message for later examination of temp files. */
  79.  
  80.     if (verbose)
  81.     {
  82.         message("header=%s, body=%s\n",
  83.             tfile[T_HDR], tfile[T_BODY]);
  84.     }
  85.  
  86.     /*
  87.      * If there is a From_ line, find the sender name therein.
  88.      */
  89.  
  90.     from_line = NULL;
  91.     fsender = fdate = fremote = NULL;
  92.  
  93.     b = (fgets(buf, GETSIZE(buf), stdin) ? TRUE : FALSE);
  94.  
  95.     if (b && ISFROM(buf) && (p = strchr(buf, '\n')) != NULL)
  96.     {
  97.         b = FALSE;
  98.  
  99.         /* Make a mungable copy of the From_ line */
  100.  
  101.         from_line = copystr(buf);
  102.         if ((p = strchr(from_line, '\n')) != NULL)
  103.             *p = 0;
  104.  
  105.         /* Find sender */
  106.  
  107.         p = from_line + 5;
  108.         while (*p && isspace(*p))
  109.             ++p;
  110.         fsender = p;
  111.         while (*p && !isspace(*p))
  112.             ++p;
  113.         if (*p)
  114.             *p++ = 0;
  115.  
  116.         /* Date received should be around here somewhere */
  117.  
  118.         fdate = p;
  119.  
  120.         /* Find 'remote from' phrase (if any) */
  121.  
  122.         for (; (p = strchr(p, 'r')) != NULL; ++p)
  123.         {
  124.             if (strncmp(p, "remote from", 11) == 0)
  125.             {
  126.                 *p = 0;
  127.                 p += 11;
  128.                 while (*p && isspace(*p))
  129.                     ++p;
  130.                 if (*p)
  131.                     fremote = p;
  132.                 break;
  133.             }
  134.         }
  135.  
  136.         /*
  137.          * Advance to first non-space in date.
  138.          * Strip trailing spaces from date.
  139.          * If there is no date, clear the date pointer.
  140.          */
  141.  
  142.         while (*fdate && isspace(*fdate))
  143.             ++fdate;
  144.         p = fdate + strlen(fdate);
  145.         while (p > fdate && isspace(*(p - 1)))
  146.             *--p = 0;
  147.         if (*fdate == 0)
  148.             fdate = NULL;
  149.  
  150.         /*
  151.          * If sender is missing, or if date is invalid,
  152.          * we consider the entire From_ line invalid.
  153.          */
  154.  
  155.         if (*fsender == 0
  156.          || (fdate != NULL && unctime(fdate) == -1) )
  157.         {
  158.             /* Ignore everything we found. */
  159.  
  160.             fsender = fdate = fremote = NULL;
  161.  
  162.             /* Print invalid From_ line in a harmless way. */
  163.  
  164.             (void) strcpy(from_line, buf);
  165.             (void) strcpy(buf, "Invalid-UUCP-From: ");
  166.             (void) strcat(buf, from_line);
  167.             b = TRUE;
  168.         }
  169.     }
  170.  
  171.     /*
  172.      * Write a From_ line to the header file.
  173.      */
  174.  
  175.     /* if caller specified sender, use it */
  176.     if (sender)
  177.         ; /* fine */
  178.  
  179.     /* else if we found a From_ line, use it */
  180.     else if (fsender)
  181.     {
  182.         if (fremote)
  183.         {
  184.             sender = zalloc(strlen(fremote) + sizeof("!")
  185.                     + strlen(fsender));
  186.             (void) sprintf(sender, "%s!%s", fremote, fsender);
  187.         }
  188.         else
  189.             sender = copystr(fsender);
  190.     }
  191.  
  192.     /* else use our real ID */
  193.     else
  194.         sender = real_ct->ct_name;
  195.  
  196.     /* debugging message */
  197.  
  198.     if (verbose)
  199.         message("copy_msg: sender is \"%s\"\n", sender);
  200.  
  201.     /*
  202.      * Finally!  Write the From_ line.
  203.      */
  204.  
  205.     (void) fputs("From ", dfp[T_HDR]);
  206.     (void) fputs(sender, dfp[T_HDR]);
  207.     (void) fputc(' ', dfp[T_HDR]);
  208.     if (fdate)
  209.     {
  210.         (void) fputs(fdate, dfp[T_HDR]);
  211.         (void) fputc('\n', dfp[T_HDR]);
  212.     }
  213.     else
  214.     {
  215.         time_t  now;
  216.  
  217.         (void) time(&now);
  218.         (void) fputs(ctime(&now), dfp[T_HDR]);
  219.     }
  220.  
  221.     /*
  222.      * Free the From_ line if we allocated a copy of it.
  223.      */
  224.  
  225.     if (from_line)
  226.         free(from_line);
  227.  
  228.     /*
  229.      * Copy the rest of the header (if any).
  230.      */
  231.  
  232.     for (; !feof(stdin) && !ferror(stdin); b = FALSE)
  233.     {
  234.         if (!b)
  235.         {
  236.             if (fgets(buf, GETSIZE(buf), stdin))
  237.                 b = TRUE;
  238.             else
  239.                 break;
  240.         }
  241.  
  242.         /* Empty line means "end of header" */
  243.  
  244.         if (buf[0] == '\n')
  245.         {
  246.             b = FALSE;    /* Don't put this line in the body. */
  247.             break;
  248.         }
  249.  
  250.         /*
  251.          * A line too long to fit in buf[] can't be a header line.
  252.          * At least, that's my opinion... :-)
  253.          */
  254.  
  255.         if (!strchr(buf, '\n'))
  256.             break;
  257.  
  258.         /*
  259.          * If line begins with whitespace, it's a continuation.
  260.          * Else if line begins with From_ or '>', prepend '>'.
  261.          * Else if line doesn't look like a header, this must
  262.          * be the beginning of the body.
  263.          */
  264.  
  265.         if (isspace(buf[0]))
  266.             ;               /* continuation */
  267.         else if (ISFROM(buf) || (buf[0] == '>'))
  268.             (void) fputc('>', dfp[T_HDR]);
  269.         else
  270.         {
  271.             /* look for the colon on a header label */
  272.  
  273.             p = buf;
  274.             while (isalpha(*p) || *p == '-')
  275.                 ++p;
  276.             if ((p == buf) || (*p != ':'))
  277.                 break;  /* Not a header line! */
  278.         }
  279.  
  280.         /* Write the line to the header file. */
  281.  
  282.         (void) fputs(buf, dfp[T_HDR]);
  283.     }
  284.  
  285.     /*
  286.      * End the header file with a blank line.
  287.      * This enables us to simply concatenate it with the body file
  288.      * to produce a valid message.
  289.      */
  290.  
  291.     (void) fputc('\n', dfp[T_HDR]);
  292.  
  293.     /*
  294.      * Copy the body (if any).
  295.      */
  296.  
  297.     empty_line = FALSE;
  298.     for (; !feof(stdin) && !ferror(stdin); b = FALSE)
  299.     {
  300.         if (!b)
  301.         {
  302.             if (fgets(buf, GETSIZE(buf), stdin))
  303.                 b = TRUE;
  304.             else
  305.                 break;
  306.         }
  307.  
  308.         if (ISFROM(buf))
  309.             (void) fputc('>', dfp[T_BODY]);
  310.         (void) fputs(buf, dfp[T_BODY]);
  311.  
  312.         empty_line = (buf[0] == '\n');
  313.  
  314.         /*
  315.          * Output the rest of a very long line.
  316.          * We do this here, instead of going around the loop,
  317.          * in order to avoid misinterpreting From_ strings
  318.          * that may be found in long lines.
  319.          */
  320.  
  321.         while (!strchr(buf, '\n')
  322.             && !feof(stdin)
  323.             && !ferror(stdin)
  324.             && fgets(buf, GETSIZE(buf), stdin))
  325.             (void) fputs(buf, dfp[T_BODY]);
  326.     }
  327.  
  328.     /* Ensure that the body ends with a blank line. */
  329.  
  330.     if (! empty_line)
  331.         (void) fputc('\n', dfp[T_BODY]);
  332.  
  333.     /*
  334.      * If we encountered any trouble writing to the temp files,
  335.      * let's not keep it secret.
  336.      */
  337.  
  338.     for (t = T_HDR; t <= T_BODY; ++t)
  339.     {
  340.         if (ferror(dfp[t]))
  341.         {
  342.             error("error writing to %s file %s\n",
  343.                 ttype[t], tfile[t]);
  344.             ret = -1;
  345.         }
  346.  
  347.         (void) fclose(dfp[t]);
  348.     }
  349.  
  350.     /* Return error/success. */
  351.  
  352.     return ret;
  353. }
  354.  
  355. /*----------------------------------------------------------------------
  356.  * Don't bother copying message.
  357.  * Put the original names in the environment.
  358.  */
  359.  
  360. int
  361. dont_copy()
  362. {
  363.     int     r, t;
  364.  
  365.     for (r = T_HDR, t = T_HDRCOPY; r <= T_BODY; ++r, ++t)
  366.     {
  367.         if (tenv[t] && tfile[r])
  368.             alloc_env(tenv[t], tfile[r]);
  369.     }
  370.  
  371.     if (verbose)
  372.     {
  373.         message("dont_copy: header is %s, body is %s\n",
  374.             tfile[T_HDR], tfile[T_BODY]);
  375.     }
  376.  
  377.     return 0;
  378. }
  379.  
  380. /*----------------------------------------------------------------------
  381.  * Create another copy of each temp file, for security reasons.
  382.  * Also, put the names of the copies in the environment.
  383.  */
  384.  
  385. int
  386. copy_again()
  387. {
  388.     int     r, t;
  389.  
  390.     for (r = T_HDR, t = T_HDRCOPY; r <= T_BODY; ++r, ++t)
  391.     {
  392.         /*
  393.          * If the file exists, remove it but keep its name.
  394.          * Otherwise, make a new name and put that name in
  395.          * the environment.
  396.          */
  397.  
  398.         if (tfile[t])
  399.             (void) unlink(tfile[t]);
  400.         else
  401.         {
  402.             tfile[t] = tempfile();
  403.             if (tenv[t])
  404.                 alloc_env(tenv[t], tfile[t]);
  405.         }
  406.  
  407.         /*
  408.          * Create the file and copy the contents of the
  409.          * original file to it.
  410.          */
  411.  
  412.         if (tfd[t] != -1)
  413.             (void) close(tfd[t]);
  414.  
  415.         if ((tfd[t] = tcreate(tfile[t])) == -1)
  416.             return -1;
  417.  
  418.         (void) lseek(tfd[r], 0L, 0);
  419.         if (copyfd(tfd[r], tfd[t]) < 0)
  420.             return -1;
  421.     }
  422.  
  423.     if (verbose)
  424.     {
  425.         message("copy_again: header to %s, body to %s\n",
  426.             tfile[T_HDRCOPY], tfile[T_BODYCOPY]);
  427.     }
  428.  
  429.     return 0;
  430. }
  431.  
  432. /*----------------------------------------------------------------------
  433.  * Copy a file via file descriptors.
  434.  */
  435.  
  436. int
  437. copyfd(src_fd, dest_fd)
  438. int     src_fd;
  439. int     dest_fd;
  440. {
  441.     char    buf[BUFSIZ];
  442.     int     rd, wr;
  443.  
  444.     while ((rd = read(src_fd, buf, sizeof(buf))) > 0)
  445.     {
  446.         if ((wr = write(dest_fd, buf, (unsigned) rd)) != rd)
  447.         {
  448.             if (wr == -1)
  449.                 syserr("can't write in copyfd");
  450.             else
  451.                 error("write error -- disk full?\n");
  452.             return -1;
  453.         }
  454.     }
  455.  
  456.     return 0;
  457. }
  458.  
  459.