home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / sendmail-5.65c+IDA-1.4.4.1 / src / collect.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-20  |  9.1 KB  |  414 lines

  1. /*
  2.  * Copyright (c) 1983 Eric P. Allman
  3.  * Copyright (c) 1988 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted provided
  7.  * that: (1) source distributions retain this entire copyright notice and
  8.  * comment, and (2) distributions including binaries display the following
  9.  * acknowledgement:  ``This product includes software developed by the
  10.  * University of California, Berkeley and its contributors'' in the
  11.  * documentation or other materials provided with the distribution and in
  12.  * all advertising materials mentioning features or use of this software.
  13.  * Neither the name of the University nor the names of its contributors may
  14.  * be used to endorse or promote products derived from this software without
  15.  * specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  17.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  18.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #ifndef lint
  22. static char sccsid[] = "@(#)collect.c    5.9 (Berkeley) 6/1/90";
  23. static char rcsid[] = "@(#)$Id: collect.c,v 5.9.0.14 1991/06/21 12:37:55 paul Exp $";
  24. #endif /* not lint */
  25.  
  26. #include <errno.h>
  27. #include "sendmail.h"
  28.  
  29. #ifdef __STDC__
  30. static void tferror(FILE *);
  31. static void eatfrom(const char *);
  32. #else /* !__STDC__ */
  33. static void tferror();
  34. static void eatfrom();
  35. #endif /* __STDC__ */
  36.  
  37. /*
  38. **  COLLECT -- read & parse message header & make temp file.
  39. **
  40. **    Creates a temporary file name and copies the standard
  41. **    input to that file.  Leading UNIX-style "From" lines are
  42. **    stripped off (after important information is extracted).
  43. **
  44. **    Parameters:
  45. **        sayok -- if set, give an ARPANET style message
  46. **            to say we are ready to collect input.
  47. **
  48. **    Returns:
  49. **        none.
  50. **
  51. **    Side Effects:
  52. **        Temp file is created and filled.
  53. **        The from person may be set.
  54. */
  55.  
  56. void
  57. collect(sayok)
  58.     bool sayok;
  59. {
  60.     register FILE *tf;
  61.     char buf[MAXFIELD+2];
  62.     register char *p;
  63. #ifdef BIT8
  64.     char buf1[MAXFIELD+2];
  65.     CHARSET *ch;
  66.     char *chname, *chesc;
  67. #endif /* BIT8 */
  68.  
  69.     /*
  70.     **  Create the temp file name and create the file.
  71.     */
  72.  
  73.     CurEnv->e_df = newstr(queuename(CurEnv, 'd'));
  74.     if ((tf = dfopen(CurEnv->e_df, "w")) == NULL)
  75.     {
  76.         syserr("Cannot create %s", CurEnv->e_df);
  77.         NoReturn = TRUE;
  78.         finis();
  79.     }
  80.     (void) chmod(CurEnv->e_df, FileMode);
  81.  
  82.     /*
  83.     **  Tell ARPANET to go ahead.
  84.     */
  85.  
  86.     if (sayok)
  87.         message("354", "Enter mail, end with \".\" on a line by itself");
  88.  
  89.     /*
  90.     **  Try to read a UNIX-style From line
  91.     */
  92.  
  93.     /*
  94.      * Read errors here are caught inside the do loop.  sfgets() will
  95.      * set buf[0] to NULL and fixcrlf() will return immediately because
  96.      * of that.
  97.      */
  98.     (void) sfgets(buf, sizeof buf, InChannel);
  99.     fixcrlf(buf, FALSE);
  100. #ifndef NOTUNIX
  101.     if (!SaveFrom && strncmp(buf, "From ", 5) == 0)
  102.     {
  103.         eatfrom(buf);
  104.         (void) sfgets(buf, sizeof buf, InChannel);
  105.         fixcrlf(buf, FALSE);
  106.     }
  107. #endif /* NOTUNIX */
  108.  
  109.     /*
  110.     **  Copy InChannel to temp file & do message editing.
  111.     **    To keep certain mailers from getting confused,
  112.     **    and to keep the output clean, lines that look
  113.     **    like UNIX "From" lines are deleted in the header.
  114.     **    (See above)
  115.     */
  116.  
  117.     do {
  118.         int c;
  119.  
  120.         /* drop out on error */
  121.         if (ferror(InChannel))
  122.             break;
  123.  
  124.         /* if the line is too long, throw the rest away */
  125.         if (index(buf, '\n') == NULL)
  126.         {
  127.             while ((c = getc(InChannel)) != '\n' && c != EOF)
  128.                 continue;
  129.         }
  130.         fixcrlf(buf, TRUE);
  131.  
  132.         /* see if the header is over */
  133.         if (!isheader(buf))
  134.             break;
  135.  
  136.         /* get the rest of this field */
  137.         while ((c = getc(InChannel)) == ' ' || c == '\t')
  138.         {
  139.             p = &buf[strlen(buf)];
  140.             *p++ = '\n';
  141.             *p++ = c;
  142.             if (sfgets(p, sizeof(buf) - (p - buf), InChannel) == NULL)
  143.                 break;
  144.             fixcrlf(p, TRUE);
  145.         }
  146.         if (!feof(InChannel) && !ferror(InChannel))
  147.             (void) ungetc(c, InChannel);
  148.  
  149.         CurEnv->e_msgsize += strlen(buf);
  150.  
  151.         /*
  152.         **  Snarf header away.
  153.         */
  154.  
  155.         if (bitset(H_EOH, chompheader(buf, FALSE)))
  156.             break;
  157.     } while (sfgets(buf, sizeof(buf) - 2, InChannel) != NULL);
  158.  
  159.     if (tTd(30, 1))
  160.         printf("EOH\n");
  161.  
  162.     /* throw away a blank line */
  163.     if (buf[0] == '\0' && !ferror(InChannel))
  164.         (void) sfgets(buf, sizeof(buf), InChannel);
  165.  
  166.     /*
  167.     **  Collect the body of the message.
  168.     */
  169.  
  170. #ifdef BIT8
  171.     chname = hvalue("x-charset");
  172.     chesc = hvalue("x-char-esc");
  173.     if (!chesc)
  174.         chesc = "29";
  175.     if (chname)
  176.         ch = getchset(chname, atoi(chesc));
  177.     else
  178.         ch = CurEnv->e_from.q_mailer->m_charset;
  179. #endif /* BIT8 */
  180. #ifdef SYSV
  181.     if (SuperSafe)
  182.     {
  183.         int fd = fileno(tf);
  184.         int flags;
  185.  
  186.         if ((flags = fcntl(fd, F_GETFL)) != -1)
  187.             (void) fcntl(fd, F_SETFL, flags | O_SYNC);
  188.     }
  189. #endif /* SYSV */
  190.  
  191.     do
  192.     {
  193.         register char *bp = buf;
  194.  
  195.         /* drop out on error */
  196.         if (ferror(InChannel))
  197.             break;
  198. #ifdef BIT8
  199.         if (ch)
  200.         {
  201.             strncnv(ascii, ch, (CHAR8U *)buf1, (CHAR8U *)buf, sizeof buf1);
  202.             strncpy(buf, buf1, sizeof buf);
  203.         }
  204. #endif /* BIT8 */
  205.  
  206.         fixcrlf(buf, TRUE);
  207.  
  208.         /* check for end-of-message */
  209.         if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0'))
  210.             break;
  211.  
  212.         /* check for transparent dot */
  213.         if (OpMode == MD_SMTP && !IgnrDot && bp[0] == '.' && bp[1] == '.')
  214.             bp++;
  215.  
  216.         /*
  217.         **  Figure message length, output the line to the temp
  218.         **  file, and insert a newline if missing.
  219.         */
  220.  
  221.         CurEnv->e_msgsize += strlen(bp) + 1;
  222.         fputs(bp, tf);
  223.         fputs("\n", tf);
  224.         if (ferror(tf))
  225.             tferror(tf);
  226.     } while (sfgets(buf, sizeof(buf), InChannel) != NULL);
  227.  
  228.     if (fflush(tf) != 0)
  229.         tferror(tf);
  230.     
  231.     /*
  232.      * Since overly long headers are appended to the end of the message
  233.      * body, delay closing tf until eatheader is done.
  234.      */
  235.  
  236.     /* An EOF when running SMTP is an error */
  237.     if ((feof(InChannel) || ferror(InChannel)) && OpMode == MD_SMTP)
  238.     {
  239. #ifdef LOG
  240.         if (RealHostName != NULL && LogLevel > 0)
  241.             syslog(LOG_NOTICE,
  242.                 "collect: unexpected close on connection from %s: %m",
  243.                 RealHostName);
  244. #endif /* LOG */
  245.         /*
  246.          * So many broken compilers out there...
  247.          * (feof(InChannel) ? usrerr: syserr)
  248.          *    ("collect: unexpected close, from=%s",
  249.          *        CurEnv->e_from.q_paddr);
  250.          */
  251.         if (feof(InChannel))
  252.             usrerr("collect: unexpected close, from=%s",
  253.                 CurEnv->e_from.q_paddr);
  254.         else
  255.             syserr("collect: unexpected close, from=%s",
  256.                 CurEnv->e_from.q_paddr);
  257.         (void) fclose(tf);
  258.  
  259.         /* don't return an error indication */
  260.         CurEnv->e_to = NULL;
  261.         CurEnv->e_flags &= ~EF_FATALERRS;
  262.  
  263.         /* and don't try to deliver the partial message either */
  264.         finis();
  265.     }
  266.  
  267.     /*
  268.     **  Find out some information from the headers.
  269.     **    Examples are who is the from person & the date.
  270.     */
  271.  
  272.     eatheader(CurEnv, tf);
  273.  
  274.     /* Now close the tf file */
  275. #ifndef SYSV
  276.     if (SuperSafe)
  277.         (void) fsync(fileno(tf));
  278. #endif /* !SYSV */
  279.     (void) fclose(tf);
  280.  
  281.     /*
  282.     **  Add an Apparently-To: line if we have no recipient lines.
  283.     */
  284.  
  285.     if (hvalue("to") == NULL && hvalue("cc") == NULL &&
  286.         hvalue("bcc") == NULL && hvalue("apparently-to") == NULL)
  287.     {
  288.         register ADDRESS *q;
  289.  
  290.         /* create an Apparently-To: field */
  291.         /*    that or reject the message.... */
  292.         for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)
  293.         {
  294.             if (q->q_alias != NULL)
  295.                 continue;
  296.             if (tTd(30, 3))
  297.                 printf("Adding Apparently-To: %s\n", q->q_paddr);
  298.             addheader("apparently-to", q->q_paddr, CurEnv);
  299.         }
  300.     }
  301.  
  302.     if ((CurEnv->e_dfp = fopen(CurEnv->e_df, "r")) == NULL)
  303.         syserr("Cannot reopen %s", CurEnv->e_df);
  304. }
  305. /*
  306. **  TFERROR -- signal error on writing the temporary file.
  307. **
  308. **    Parameters:
  309. **        tf -- the file pointer for the temporary file.
  310. **
  311. **    Returns:
  312. **        none.
  313. **
  314. **    Side Effects:
  315. **        Gives an error message.
  316. **        Arranges for following output to go elsewhere.
  317. */
  318.  
  319. static void
  320. tferror(tf)
  321.     FILE *tf;
  322. {
  323.     if (errno == ENOSPC)
  324.     {
  325.         (void) freopen(CurEnv->e_df, "w", tf);
  326.         fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf);
  327.         usrerr("452 Out of disk space for temp file");
  328.     }
  329.     else
  330.         syserr("collect: Cannot write %s", CurEnv->e_df);
  331.     (void) freopen("/dev/null", "w", tf);
  332. }
  333. /*
  334. **  EATFROM -- chew up a UNIX style from line and process
  335. **
  336. **    This does indeed make some assumptions about the format
  337. **    of UNIX messages.
  338. **
  339. **    Parameters:
  340. **        fm -- the from line.
  341. **
  342. **    Returns:
  343. **        none.
  344. **
  345. **    Side Effects:
  346. **        extracts what information it can from the header,
  347. **        such as the date.
  348. */
  349.  
  350. char    *DowList[] =
  351. {
  352.     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
  353. };
  354.  
  355. char    *MonthList[] =
  356. {
  357.     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  358.     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
  359.     NULL
  360. };
  361.  
  362. #ifndef NOTUNIX
  363.  
  364. static void
  365. eatfrom(fm)
  366.     const char *fm;
  367. {
  368.     register const char *p = fm;
  369.     register char **dt;
  370.  
  371.     if (tTd(30, 2))
  372.         printf("eatfrom(%s)\n", fm);
  373.  
  374.     /* find the date part */
  375.     while (*p != '\0')
  376.     {
  377.         /* skip a word */
  378.         while (*p != '\0' && *p != ' ')
  379.             p++;
  380.         while (*p == ' ')
  381.             p++;
  382.         if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':')
  383.             continue;
  384.  
  385.         /* we have a possible date */
  386.         for (dt = DowList; *dt != NULL; dt++)
  387.             if (strncmp(*dt, p, 3) == 0)
  388.                 break;
  389.         if (*dt == NULL)
  390.             continue;
  391.  
  392.         for (dt = MonthList; *dt != NULL; dt++)
  393.             if (strncmp(*dt, &p[4], 3) == 0)
  394.                 break;
  395.         if (*dt != NULL)
  396.             break;
  397.     }
  398.  
  399.     if (*p != (char) NULL)
  400.     {
  401.         char *q;
  402.  
  403.         /* we have found a date */
  404.         q = xalloc(25);
  405.         (void) strncpy(q, p, 25);
  406.         q[24] = '\0';
  407.         define('d', q, CurEnv);
  408.         q = arpadate(q);
  409.         define('a', newstr(q), CurEnv);
  410.     }
  411. }
  412.  
  413. #endif /* NOTUNIX */
  414.