home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR3 / KA9Q212.ZIP / SMTPCLI.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  34KB  |  1,531 lines

  1. /*
  2.  *    CLIENT routines for Simple Mail Transfer Protocol ala RFC821
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *     Modified 14 June 1987 by P. Karn for symbolic target addresses,
  8.  *    also rebuilt locking mechanism
  9.  *    Copyright 1987 1988 David Trulli, All Rights Reserved.
  10.  *    Permission granted for non-commercial copying and use, provided
  11.  *    this notice is retained.
  12.  */
  13.  
  14. /****************************************************************************
  15. *    $Id: smtpcli.c 1.17 93/07/16 11:50:25 ROOT_DOS Exp $
  16. *    29 May 92    1.2        GT    mailroute (): use gateway if defined.            *
  17. *    02 Jun 92    1.3        GT    Add "smtp wait" and timeout on connect () call    *
  18. *                            in smtp_send ().                                *
  19. *    04 Jun 92    1.4        GT    Make smtptick () a separate process.            *
  20. *    05 Jun 92    1.5        GT    Timeout on connect () to Gateway.                *
  21. *    26 Jun 92            Paul@wolf.demon.co.uk Fixed routing for internal    *
  22. *                        email (doesn't go via the external gateway)         *
  23. *    13 Jul 92    1.7        GT    Remove 1.6 changes.                                *
  24. *    05 Aug 92            amc@beryl.demon.co.uk changed printfs to tprintf    *
  25. *    27 Aug 92   1.10    mt@kram.demon.co.uk added smtp separator            *
  26. *    Dec 92                mt@kram.org don't use gateway for any mail MXed via *
  27. *                        us. Add delay channel for local mail                  *
  28. *                        Add smtp beep on|off                                *
  29. *    19 Apr 93    1.16    GT    If newproc () fails, reset tick flag.            *
  30. *    08 May 93    1.17    GT    Fix warnings.                                    *
  31. *                            Fix "smtp list".                                *
  32. *                        IAY    Fix dot transparency as per RFC 821.            *
  33. ****************************************************************************/
  34.  
  35. #include <stdio.h>
  36. #include <fcntl.h>
  37. #include <time.h>
  38. #include <setjmp.h>
  39. #ifdef UNIX
  40. #include <sys/types.h>
  41. #endif
  42. #ifdef    AMIGA
  43. #include <stat.h>
  44. #else
  45. #include <sys/stat.h>
  46. #endif
  47. #ifdef    __TURBOC__
  48. #include <dir.h>
  49. #include <io.h>
  50. #endif
  51. #include "global.h"
  52. #ifdef    ANSIPROTO
  53. #include <stdarg.h>
  54. #endif
  55. #include "config.h"
  56. #include "domain.h"
  57. #include "mbuf.h"
  58. #include "cmdparse.h"
  59. #include "proc.h"
  60. #include "socket.h"
  61. #include "timer.h"
  62. #include "netuser.h"
  63. #include "smtp.h"
  64. #include "dirutil.h"
  65. #include "commands.h"
  66. #include "session.h"
  67. #include "ip.h"
  68.  
  69. static struct timer Smtpcli_t;
  70. static int32 Gateway;
  71. static int32 Delaytime = 0;
  72. int smtpverbose = 1;
  73. char *smtp_separator = NULL;
  74. int are_we_an_mx;
  75.  
  76. #ifdef SMTPTRACE
  77. static unsigned short Smtptrace = 0;    /* used for trace level */
  78. static int dosmtptrace __ARGS ((int argc, char *argv[], void *p));
  79.  
  80. #endif
  81.  
  82. static unsigned short Smtpmaxcli = MAXSESSIONS;    /* the max client connections
  83.                                                  * allowed */
  84. static int Smtpsessions = 0; /* number of client connections currently open */
  85. static int Smtpbatch;
  86. int Smtpmode = 0;
  87. int Smtpbeep = 0;
  88.  
  89. int32 connect_wait_val = 60000L;        /* default connection timeout         */
  90.  
  91. static struct smtpcli *cli_session[MAXSESSIONS];        /* queue of client
  92.                                                          * sessions  */
  93.  
  94. static void del_job __ARGS ((struct smtp_job * jp));
  95. static void del_session __ARGS ((struct smtpcli * cb));
  96. static int dogateway __ARGS ((int argc, char *argv[], void *p));
  97. static int doseparator __ARGS ((int argc, char *argv[], void *p));
  98. static int dosmtpmaxcli __ARGS ((int argc, char *argv[], void *p));
  99. static int dotimer __ARGS ((int argc, char *argv[], void *p));
  100. static int dodelay __ARGS ((int argc, char *argv[], void *p));
  101. static int dowait __ARGS ((int argc, char *argv[], void *p));
  102. static int dosmtpkill __ARGS ((int argc, char *argv[], void *p));
  103. static int dosmtplist __ARGS ((int argc, char *argv[], void *p));
  104. static int dobatch __ARGS ((int argc, char *argv[], void *p));
  105. static int dobeep __ARGS ((int argc, char *argv[], void *p));
  106. static void execjobs __ARGS ((void));
  107. static int getresp __ARGS ((struct smtpcli * ftp, int mincode));
  108. static void logerr __ARGS ((struct smtpcli * cb, char *line));
  109. static struct smtpcli *lookup __ARGS ((int32 destaddr));
  110. static struct smtpcli *newcb __ARGS ((void));
  111. static int next_job __ARGS ((struct smtpcli * cb));
  112. static void retmail __ARGS ((struct smtpcli * cb));
  113. static void sendcmd __ARGS ((struct smtpcli * cb, char *fmt,...));
  114. static int smtpsendfile __ARGS ((struct smtpcli * cb));
  115. static int setsmtpmode __ARGS ((int argc, char *argv[], void *p));
  116. static struct smtp_job *setupjob __ARGS ((struct smtpcli * cb, char *id, char *from));
  117. static void smtp_send __ARGS ((int unused, void *cb1, void *p));
  118. static int smtpkick __ARGS ((int argc, char *argv[], void *p));
  119. static void smtptick_body __ARGS ((int unused, void *t, void *p));
  120. static int doverbose __ARGS ((int argc, char *argv[], void *p));
  121. static int should_enter_delay __ARGS ((struct smtpcli * cb));
  122. static int explock __ARGS ((char *dir, char *pre, char *suf, int32 age));
  123.  
  124. static struct cmds Smtpcmds[] = {
  125.                                  {"batch", dobatch, 0, 0, NULLCHAR},
  126.                                  {"beep", dobeep, 0, 0, NULLCHAR},
  127.                                  {"delay", dodelay, 0, 0, NULLCHAR},
  128.                                  {"gateway", dogateway, 0, 0, NULLCHAR},
  129.                                  {"kick", smtpkick, 0, 0, NULLCHAR},
  130.                              {"kill", dosmtpkill, 0, 2, "kill <jobnumber>"},
  131.                                  {"list", dosmtplist, 0, 0, NULLCHAR},
  132.                                {"maxclients", dosmtpmaxcli, 0, 0, NULLCHAR},
  133.                                  {"mode", setsmtpmode, 0, 0, NULLCHAR},
  134.                                  {"separator", doseparator, 0, 0, NULLCHAR},
  135.                                  {"timer", dotimer, 0, 0, NULLCHAR},
  136. #ifdef SMTPTRACE
  137.                                  {"trace", dosmtptrace, 0, 0, NULLCHAR},
  138. #endif
  139.                                  {"wait", dowait, 0, 0, NULLCHAR},
  140.                                  {"verbose", doverbose, 0, 0, NULLCHAR},        /* Actually for Server */
  141.                                  {NULLCHAR},
  142.     };
  143.  
  144. int
  145.     dosmtp (argc, argv, p)
  146. int argc;
  147. char *argv[];
  148. void *p;
  149.  
  150.     {
  151.     return subcmd (Smtpcmds, argc, argv, p);
  152.     }
  153.  
  154. static int
  155.     dobatch (argc, argv, p)
  156. int argc;
  157. char *argv[];
  158. void *p;
  159.  
  160.     {
  161.     return setbool (&Smtpbatch, "SMTP batching", argc, argv);
  162.     }
  163.  
  164. static int
  165.     dobeep (argc, argv, p)
  166. int argc;
  167. char *argv[];
  168. void *p;
  169.  
  170.     {
  171.     return setbool (&Smtpbeep, "SMTP beep on delivery", argc, argv);
  172.     }
  173.  
  174. static int
  175.     dosmtpmaxcli (argc, argv, p)
  176. int argc;
  177. char *argv[];
  178. void *p;
  179.  
  180.     {
  181.     return setshort (&Smtpmaxcli, "Max clients", argc, argv);
  182.     }
  183.  
  184. static int
  185.     setsmtpmode (argc, argv, p)
  186. int argc;
  187. char *argv[];
  188. void *p;
  189.  
  190.     {
  191.     if (argc < 2)
  192.         {
  193.         tprintf ("smtp mode: %s\n",
  194.                  (Smtpmode & QUEUE) ? "queue" : "route");
  195.         }
  196.     else
  197.         {
  198.         switch (*argv[1])
  199.             {
  200.             case 'q':
  201.                 Smtpmode |= QUEUE;
  202.                 break;
  203.             case 'r':
  204.                 Smtpmode &= ~QUEUE;
  205.                 break;
  206.             default:
  207.                 tprintf ("Usage: smtp mode [queue | route]\n");
  208.                 break;
  209.             }
  210.         }
  211.  
  212.     return 0;
  213.     }
  214. static int
  215.     dogateway (argc, argv, p)
  216. int argc;
  217. char *argv[];
  218. void *p;
  219.  
  220.     {
  221.     int32 n;
  222.  
  223.     if (argc < 2)
  224.         {
  225.         tprintf ("%s\n", inet_ntoa (Gateway));
  226.         }
  227.     else
  228.     if ((n = resolve (argv[1])) == 0)
  229.         {
  230.         tprintf (Badhost, argv[1]);
  231.         return 1;
  232.         }
  233.     else
  234.         Gateway = n;
  235.  
  236.     return 0;
  237.     }
  238.  
  239. static int
  240.     doseparator (argc, argv, p)
  241. int argc;
  242. char *argv[];
  243. void *p;
  244.  
  245.     {
  246.     int i;
  247.     char *t;
  248.  
  249.     if (argc < 2)
  250.         {
  251.         if (smtp_separator)
  252.             free (smtp_separator);
  253.  
  254.         smtp_separator = NULL;
  255.         }
  256.     else
  257.         {
  258.         t = mallocw (81);
  259.         if (t == NULL)
  260.             return 1;
  261.  
  262.         t[0] = '\0';
  263.         for (i = 1; i < argc; i++)
  264.             {
  265.             strcat (t, argv[i]);
  266.             if (i < (argc - 1))
  267.                 strcat (t, " ");
  268.  
  269.             }
  270.         if ((smtp_separator = mallocw (strlen (t) + 1)) == NULL)
  271.             {
  272.             free (t);
  273.             return 1;
  274.             }
  275.  
  276.         strcpy (smtp_separator, t);
  277.         free (t);
  278.         }
  279.  
  280.     return 0;
  281.     }
  282.  
  283. #ifdef SMTPTRACE
  284. static int
  285.     dosmtptrace (argc, argv, p)
  286. int argc;
  287. char *argv[];
  288. void *p;
  289.  
  290.     {
  291.     return setshort (&Smtptrace, "SMTP tracing", argc, argv);
  292.     }
  293.  
  294. #endif
  295.  
  296. /* list jobs wating to be sent in the mqueue */
  297.  
  298. static int dosmtplist (argc, argv, p)
  299. int argc;
  300. char *argv[];
  301. void *p;
  302.     {
  303.     char tstring[80];
  304.     char line[20];
  305.     char host[LINELEN];
  306.     char to[LINELEN];
  307.     char from[LINELEN];
  308.     char *cp;
  309.     char status;
  310.     struct stat stbuf;
  311.     struct tm *tminfo, *localtime ();
  312.     FILE *fp;
  313.  
  314.     Current->flowmode = 1;                         /* Enable the more mechanism */
  315.     tprintf ("S     Job    Size Date  Time  Host                 From\n");
  316.     filedir (Mailqueue, 0, line);
  317.     while (line[0] != '\0')
  318.         {
  319.         (void) sprintf (tstring, "%s/%s", Mailqdir, line);
  320.         if ((fp = fopen (tstring, READ_TEXT)) == NULLFILE)
  321.             {
  322.             tprintf ("Can't open %s: %s\n", tstring, sys_errlist[errno]);
  323.             pwait (NULL);
  324.             filedir (Mailqueue, 1, line);
  325.             continue;
  326.             }
  327.  
  328.         if ((cp = strrchr (line, '.')) != NULLCHAR)
  329.             *cp = '\0';
  330.  
  331.         (void) sprintf (tstring, "%s/%s.lck", Mailqdir, line);
  332.         if (access (tstring, 0))
  333.             status = ' ';
  334.         else
  335.             status = 'L';
  336.  
  337.         /* Now see if it's in delay */
  338.         if (status == ' ')
  339.             {
  340.             sprintf (tstring, "%s/%s.dly", Mailqdir, line);
  341.             if (!access (tstring, 0))
  342.                 status = 'D';
  343.  
  344.             }
  345.  
  346.         (void) sprintf (tstring, "%s/%s.txt", Mailqdir, line);
  347.         if (stat (tstring, &stbuf) == -1)
  348.             {
  349.             tprintf ("Can't stat %s: %s\n", tstring, sys_errlist[errno]);
  350.             pwait (NULL);
  351.             filedir (Mailqueue, 1, line);
  352.             continue;
  353.             }
  354.  
  355.         tminfo = localtime (&stbuf.st_ctime);
  356.         fgets (host, sizeof (host), fp);
  357.         rip (host);
  358.         fgets (from, sizeof (from), fp);
  359.         rip (from);
  360.         tprintf ("%c %7s %7ld %02d/%02d %02d:%02d %-20s %s\n      ",
  361.                  status, line, stbuf.st_size,
  362.                  tminfo->tm_mon + 1,
  363.                  tminfo->tm_mday,
  364.                  tminfo->tm_hour,
  365.                  tminfo->tm_min,
  366.                  host, from);
  367.         while (fgets (to, sizeof (to), fp) != NULLCHAR)
  368.             {
  369.             rip (to);
  370.             tprintf ("%s ", to);
  371.             }
  372.  
  373.         tprintf ("\n");
  374.         (void) fclose (fp);
  375.         pwait (NULL);
  376.         filedir (Mailqueue, 1, line);
  377.         }
  378.  
  379.     Current->flowmode = 0;
  380.     return 0;
  381.     }    /* static int dosmtplist (argc, argv, p) */
  382.     
  383.  
  384. /* kill a job in the mqueue */
  385. static int
  386.     dosmtpkill (argc, argv, p)
  387. int argc;
  388. char *argv[];
  389. void *p;
  390.  
  391.     {
  392.     char s[SLINELEN];
  393.     char *cp, c;
  394.  
  395.     sprintf (s, "%s/%s.lck", Mailqdir, argv[1]);
  396.     cp = strrchr (s, '.');
  397.     if (!access (s, 0))
  398.         {
  399.         Current->ttystate.echo = Current->ttystate.edit = 0;
  400.         c = keywait ("Warning, the job is locked by SMTP. Remove (y/n)? ", 0);
  401.         Current->ttystate.echo = Current->ttystate.edit = 1;
  402.         if (c != 'y')
  403.             return 0;
  404.  
  405.         (void) unlink (s);
  406.         }
  407.  
  408.     strcpy (cp, ".wrk");
  409.     if (unlink (s))
  410.         tprintf ("Job id %s not found\n", argv[1]);
  411.  
  412.     strcpy (cp, ".txt");
  413.     (void) unlink (s);
  414.     strcpy (cp, ".dly");
  415.     (void) unlink (s);
  416.     return 0;
  417.     }
  418.  
  419. /* Set outbound spool scan interval */
  420. static int
  421.     dotimer (argc, argv, p)
  422. int argc;
  423. char *argv[];
  424. void *p;
  425.  
  426.     {
  427.     if (argc < 2)
  428.         {
  429.         tprintf ("%lu/%lu\n",
  430.                  read_timer (&Smtpcli_t) / 1000L,
  431.                  dur_timer (&Smtpcli_t) / 1000L);
  432.         return 0;
  433.         }
  434.  
  435.     Smtpcli_t.func = (void (*) ()) smtptick;     /* what to call on timeout */
  436.     Smtpcli_t.arg = NULL;                         /* dummy value */
  437.     set_timer (&Smtpcli_t, atol (argv[1]) * 1000L);        /* set timer duration */
  438.     start_timer (&Smtpcli_t);                     /* and fire it up */
  439.     return 0;
  440.     }
  441.  
  442. /* Set delay channel time */
  443. static int
  444.     dodelay (argc, argv, p)
  445. int argc;
  446. char *argv[];
  447. void *p;
  448.  
  449.     {
  450.     if (argc < 2)
  451.         {
  452.         tprintf ("%lu\n", Delaytime);
  453.         return 0;
  454.         }
  455.  
  456.     Delaytime = atol (argv[1]);
  457.     return 0;
  458.     }
  459.  
  460. /****************************************************************************
  461. *    dowait                                                                    *
  462. *    Displays or sets the connection wait timeout.                            *
  463. ****************************************************************************/
  464.  
  465. static int dowait (argc, argv, p)
  466. int argc;
  467. char *argv[];
  468. void *p;
  469.  
  470.     {
  471.     if (argc < 2)
  472.         {
  473.         tprintf ("smtp connection timeout: %lu\n", connect_wait_val / 1000L);
  474.         return (0);
  475.         }
  476.  
  477.     connect_wait_val = atol (argv[1]) * 1000L;     /* set timeout                     */
  478.     return (0);
  479.     }                         /* static int dowait (argc, argv, p) */
  480.  
  481. static int
  482.     smtpkick (argc, argv, p)
  483. int argc;
  484. char *argv[];
  485. void *p;
  486.  
  487.     {
  488.     int32 addr = 0;
  489.  
  490.     if (argc > 1 && (addr = resolve (argv[1])) == 0)
  491.         {
  492.         tprintf (Badhost, argv[1]);
  493.         return 1;
  494.         }
  495.  
  496.     smtptick ((void *) addr);
  497.     return 0;
  498.     }
  499.  
  500. /* This is the routine that gets called every so often to do outgoing
  501.  * mail processing. When called with a null argument, it runs the entire
  502.  * queue; if called with a specific non-zero IP address from the remote
  503.  * kick server, it only starts up sessions to that address.
  504.  */
  505.  
  506. static char smtptick_running = 0;
  507.  
  508. int
  509.     smtptick (t)
  510. void *t;
  511.     {
  512.     if (smtptick_running != 0)
  513.         return (0);
  514.  
  515.     smtptick_running = 1;
  516.     if (newproc ("smtp_tick", 1024, smtptick_body, 0, t, NULL, 0) == NULLPROC)
  517.         {
  518.         /* Wait a while. */
  519.  
  520.         start_timer (&Smtpcli_t);
  521.         smtptick_running = 0;
  522.         }
  523.  
  524.     return (0);
  525.     }
  526.  
  527. static void smtptick_body (unused, t, p)
  528. int unused;
  529. void *t;
  530. void *p;
  531.     {
  532.     register struct smtpcli *cb;
  533.     struct smtp_job *jp;
  534.     struct list *ap;
  535.     char tmpstring[LINELEN], wfilename[13], prefix[9];
  536.     char from[LINELEN], to[LINELEN];
  537.     char *cp, *cp1;
  538.     int32 destaddr, target, num_files;
  539.     FILE *wfile;
  540.  
  541.     target = (int32) t;
  542. #ifdef SMTPTRACE
  543.     if (Smtptrace > 5)
  544.         tprintf ("smtp daemon entered, target = %s\n", inet_ntoa (target));
  545. #endif
  546.  
  547.     if (availmem () < Memthresh)
  548.         {
  549.         /* Memory is tight, don't do anything */
  550.         /* Restart timer */
  551.         start_timer (&Smtpcli_t);
  552.         smtptick_running = 0;
  553.         return;
  554.         }
  555.     /* First see how many there are now */
  556.  
  557.     num_files = 0;
  558.     for (filedir (Mailqueue, 0, wfilename); wfilename[0] != '\0';
  559.          filedir (Mailqueue, 1, wfilename))
  560.         num_files++;
  561.  
  562.     /* Try to deal with that many messages, no more or we may loop forever */
  563.     for (filedir (Mailqueue, 0, wfilename); wfilename[0] != '\0' && num_files--;
  564.          filedir (Mailqueue, 1, wfilename))
  565.         {
  566.  
  567.         /* save the prefix of the file name which it job id */
  568.         cp = wfilename;
  569.         cp1 = prefix;
  570.         while (*cp && *cp != '.')
  571.             *cp1++ = *cp++;
  572.  
  573.         *cp1 = '\0';
  574.  
  575.         /* lock this file from the smtp daemon */
  576.         if (mlock (Mailqdir, prefix))
  577.             continue;
  578.  
  579.         /* Try to bring the job outof delay (in case it's in delay) */
  580.  
  581.         explock (Mailqdir, prefix, "dly", Delaytime);
  582.  
  583.         /* Check that it's not in delay */
  584.         if (mlock_suffix (Mailqdir, prefix, "dly"))
  585.             {
  586.             rmlock (Mailqdir, prefix);
  587.             continue;
  588.             }
  589.         else
  590.             rmlock_suffix (Mailqdir, prefix, "dly");
  591.  
  592.         sprintf (tmpstring, "%s/%s", Mailqdir, wfilename);
  593.         if ((wfile = fopen (tmpstring, READ_TEXT)) == NULLFILE)
  594.             {
  595.             /* probably too many open files */
  596.             (void) rmlock (Mailqdir, prefix);
  597.             /* continue to next message. The failure may be temporary */
  598.             continue;
  599.             }
  600.  
  601.         (void) fgets (tmpstring, LINELEN, wfile);/* read target host */
  602.         rip (tmpstring);
  603.  
  604.         if ((destaddr = mailroute (tmpstring, Ip_addr)) == 0)
  605.             {
  606.             fclose (wfile);
  607.             tprintf ("** smtp: Unknown address %s\n", tmpstring);
  608.             (void) rmlock (Mailqdir, prefix);
  609.             continue;
  610.             }
  611.  
  612.         if (target != 0 && destaddr != target)
  613.             {
  614.             fclose (wfile);
  615.             (void) rmlock (Mailqdir, prefix);
  616.             continue;                             /* Not the proper target of
  617.                                                   * a kick */
  618.             }
  619.  
  620.         if ((cb = lookup (destaddr)) == NULLSMTPCLI)
  621.             {
  622.             /* there are enough processes running already */
  623.             if (Smtpsessions >= Smtpmaxcli)
  624.                 {
  625. #ifdef SMTPTRACE
  626.                 if (Smtptrace)
  627.                     {
  628.                     tprintf ("smtp daemon: too many processes\n");
  629.                     }
  630. #endif
  631.  
  632.                 fclose (wfile);
  633.                 (void) rmlock (Mailqdir, prefix);
  634.                 break;
  635.                 }
  636.  
  637.             if ((cb = newcb ()) == NULLSMTPCLI)
  638.                 {
  639.                 fclose (wfile);
  640.                 (void) rmlock (Mailqdir, prefix);
  641.                 break;
  642.                 }
  643.  
  644.             cb->ipdest = destaddr;
  645.             cb->destname = strdup (tmpstring);
  646.             }
  647.         else
  648.             {
  649.             if (cb->lock)
  650.                 {
  651.                 /* This system is already is sending mail lets not
  652.                  * interfere with its send queue. */
  653.                 fclose (wfile);
  654.                 (void) rmlock (Mailqdir, prefix);
  655.                 continue;
  656.                 }
  657.  
  658.             }
  659.  
  660.         (void) fgets (from, LINELEN, wfile);     /* read from */
  661.         rip (from);
  662.         if ((jp = setupjob (cb, prefix, from)) == NULLJOB)
  663.             {
  664.             fclose (wfile);
  665.             (void) rmlock (Mailqdir, prefix);
  666.             del_session (cb);
  667.             break;
  668.             }
  669.  
  670.         while (fgets (to, LINELEN, wfile) != NULLCHAR)
  671.             {
  672.             rip (to);
  673.             if (addlist (&jp->to, to, DOMAIN) == NULLLIST)
  674.                 {
  675.                 fclose (wfile);
  676.                 del_session (cb);
  677.                 }
  678.  
  679.             }
  680.         fclose (wfile);
  681. #ifdef SMTPTRACE
  682.         if (Smtptrace > 1)
  683.             {
  684.             tprintf ("queue job %s From: %s To:", prefix, from);
  685.             for (ap = jp->to; ap != NULLLIST; ap = ap->next)
  686.                 tprintf (" %s", ap->val);
  687.  
  688.             tprintf ("\n");
  689.             }
  690. #endif
  691.  
  692.         }
  693.  
  694.     /* start sending that mail */
  695.     execjobs ();
  696.  
  697.     /* Restart timer */
  698.     start_timer (&Smtpcli_t);
  699.     smtptick_running = 0;
  700.     return;
  701.     }
  702.  
  703. static int
  704.     should_enter_delay (cb)
  705. struct smtpcli *cb;
  706.     {
  707.     resolve_mx (cb->destname);
  708.     if (are_we_an_mx)
  709.         return 1;
  710.  
  711.     return 0;
  712.     }
  713.  
  714. void
  715.      delay_job (msgid)
  716. int32 msgid;
  717.     {
  718.     char t[20];
  719.  
  720.     if (Delaytime == 0)
  721.         /* Not using SMTP delay */
  722.         return;
  723.  
  724.     sprintf (t, "%lu", msgid);
  725. #ifdef SMTPTRACE
  726.     if (Smtptrace)
  727.         tprintf ("Delivery Failed: adding job %s to delay queue\n", t);
  728. #endif
  729.  
  730.     mlock_suffix (Mailqdir, t, "dly");
  731.     }
  732.  
  733. /* This is the master state machine that handles a single SMTP transaction.
  734.  * It is called with a queue of jobs for a particular host.
  735.  * The logic is complicated by the "Smtpbatch" variable, which controls
  736.  * the batching of SMTP commands. If Smtpbatch is true, then many of the
  737.  * SMTP commands are sent in one swell foop before waiting for any of
  738.  * the responses. Unfortunately, this breaks many brain-damaged SMTP servers
  739.  * out there, so provisions have to be made to operate SMTP in lock-step mode.
  740.  */
  741. static void
  742.      smtp_send (unused, cb1, p)
  743. int unused;
  744. void *cb1;
  745. void *p;
  746.     {
  747.     register struct smtpcli *cb;
  748.     register struct list *tp;
  749.     struct sockaddr_in fsocket;
  750.     char *cp;
  751.     int rcode;
  752.     int rcpts;
  753.     int goodrcpt;
  754.     int i;
  755.     int init = 1;
  756.  
  757.     cb = (struct smtpcli *) cb1;
  758.     cb->lock = 1;
  759.     fsocket.sin_family = AF_INET;
  760.     fsocket.sin_addr.s_addr = cb->ipdest;
  761.     fsocket.sin_port = IPPORT_SMTP;
  762.  
  763.     cb->s = socket (AF_INET, SOCK_STREAM, 0);
  764.     sockmode (cb->s, SOCK_ASCII);
  765.     setflush (cb->s, -1);                         /* We'll explicitly flush
  766.                                                   * before reading */
  767. #ifdef SMTPTRACE
  768.     if (Smtptrace)
  769.         tprintf ("SMTP client Trying...\n");
  770. #endif
  771.  
  772.     /* Run connect () under a timeout in case the destination is
  773.      * unreachable. */
  774.  
  775.     alarm (connect_wait_val);
  776.     if (connect (cb->s, (char *) &fsocket, SOCKSIZE) == 0)
  777.         {
  778.         alarm (0L);
  779. #ifdef SMTPTRACE
  780.         if (Smtptrace)
  781.             tprintf ("Connected\n");
  782. #endif
  783.  
  784.         ;
  785.         }
  786.     else
  787.         {
  788.         alarm (0L);
  789.         if (Delaytime && (cb->ipdest == Ip_addr || should_enter_delay (cb)))
  790.             delay_job (atol (cb->jobq->jobname));
  791.         else
  792.         if (Gateway != 0L)
  793.             {
  794.             /* Try sending it via the gateway, as long as it's not for us. */
  795. #ifdef SMTPTRACE
  796.             if (Smtptrace)
  797.                 tprintf ("SMTP client Trying gateway...\n");
  798. #endif
  799.  
  800.             (void) close_s (cb->s);
  801.             cb->ipdest = Gateway;
  802.             fsocket.sin_addr.s_addr = Gateway;
  803.             cb->s = socket (AF_INET, SOCK_STREAM, 0);
  804.             sockmode (cb->s, SOCK_ASCII);
  805.             setflush (cb->s, -1);
  806.             alarm (connect_wait_val);
  807.             if (connect (cb->s, (char *) &fsocket, SOCKSIZE) != 0)
  808.                 {
  809.                 alarm (0L);
  810.                 cp = sockerr (cb->s);
  811. #ifdef SMTPTRACE
  812.                 if (Smtptrace)
  813.                     tprintf ("Connect failed: %s\n", cp != NULLCHAR ? cp : "");
  814. #endif
  815.                 log (cb->s, "SMTP %s Connect failed: %s", psocket (&fsocket),
  816.  
  817.                      cp != NULLCHAR ? cp : "");
  818.  
  819.                 goto quit;
  820.                 }
  821.             else
  822.                 {
  823.                 alarm (0L);
  824. #ifdef SMTPTRACE
  825.                 if (Smtptrace)
  826.                     tprintf ("Connected to Gateway\n");
  827. #endif
  828.  
  829.                 ;
  830.                 }
  831.  
  832.             }                                     /* if (Gateway != 0L) */
  833.         else
  834.             {
  835.             cp = sockerr (cb->s);
  836. #ifdef SMTPTRACE
  837.             if (Smtptrace)
  838.                 tprintf ("Connect failed: %s\n", cp != NULLCHAR ? cp : "");
  839. #endif
  840.             log (cb->s, "SMTP %s Connect failed: %s", psocket (&fsocket),
  841.  
  842.                  cp != NULLCHAR ? cp : "");
  843.  
  844.             goto quit;
  845.             }
  846.  
  847.         }
  848.  
  849.     if (!Smtpbatch)
  850.         {
  851.         rcode = getresp (cb, 200);
  852.         if (rcode == -1 || rcode >= 400)
  853.             goto quit;
  854.  
  855.         }
  856.     /* Say HELO */
  857.  
  858.     sendcmd (cb, "HELO %s\n", Hostname);
  859.     if (!Smtpbatch)
  860.         {
  861.         rcode = getresp (cb, 200);
  862.         if (rcode == -1 || rcode >= 400)
  863.             goto quit;
  864.  
  865.         }
  866.  
  867.     do
  868.         {                                         /* For each message... */
  869.  
  870.         /* if this file open fails, skip it */
  871.         if ((cb->tfile = fopen (cb->tname, READ_TEXT)) == NULLFILE)
  872.             continue;
  873.  
  874.         /* Send MAIL and RCPT commands */
  875.  
  876.         sendcmd (cb, "MAIL FROM:<%s>\n", cb->jobq->from);
  877.         if (!Smtpbatch)
  878.             {
  879.             rcode = getresp (cb, 200);
  880.             if (rcode == -1 || rcode >= 400)
  881.                 goto quit;
  882.  
  883.             }
  884.  
  885.         rcpts = 0;
  886.         goodrcpt = 0;
  887.         for (tp = cb->jobq->to; tp != NULLLIST; tp = tp->next)
  888.             {
  889.             sendcmd (cb, "RCPT TO:<%s>\n", tp->val);
  890.             if (!Smtpbatch)
  891.                 {
  892.                 rcode = getresp (cb, 200);
  893.                 if (rcode == -1)
  894.                     goto quit;
  895.  
  896.                 if (rcode < 400)
  897.                     goodrcpt = 1;                 /* At least one good */
  898.  
  899.                 }
  900.  
  901.             rcpts++;
  902.             }
  903.  
  904.         /* Send DATA command */
  905.         sendcmd (cb, "DATA\n");
  906.         if (!Smtpbatch)
  907.             {
  908.             rcode = getresp (cb, 200);
  909.             if (rcode == -1 || rcode >= 400)
  910.                 goto quit;
  911.  
  912.             }
  913.  
  914.         if (Smtpbatch)
  915.             {
  916.             /* Now wait for the responses to come back. The first time we
  917.              * do this, we wait first for the start banner and HELO
  918.              * response. In any case, we wait for the response to the MAIL
  919.              * command here. */
  920.             for (i = init ? 3 : 1; i > 0; i--)
  921.                 {
  922.                 rcode = getresp (cb, 200);
  923.                 if (rcode == -1 || rcode >= 400)
  924.                     goto quit;
  925.  
  926.                 }
  927.             init = 0;
  928.  
  929.             /* Now process the responses to the RCPT commands */
  930.             for (i = rcpts; i != 0; i--)
  931.                 {
  932.                 rcode = getresp (cb, 200);
  933.                 if (rcode == -1)
  934.                     goto quit;
  935.  
  936.                 if (rcode < 400)
  937.                     goodrcpt = 1;                 /* At least one good */
  938.  
  939.                 }
  940.             /* And finally get the response to the DATA command. Some
  941.              * servers will return failure here if no recipients are valid,
  942.              * some won't. */
  943.             rcode = getresp (cb, 200);
  944.             if (rcode == -1 || rcode >= 400)
  945.                 goto quit;
  946.  
  947.             /* check for no good rcpt on the list */
  948.  
  949.             if (goodrcpt == 0)
  950.                 {
  951.                 sendcmd (cb, ".\n");             /* Get out of data mode */
  952.                 goto quit;
  953.                 }
  954.  
  955.             }
  956.         /* Send the file. This also closes it */
  957.  
  958.         smtpsendfile (cb);
  959.  
  960.         /* Wait for the OK response */
  961.         rcode = getresp (cb, 200);
  962.         if (rcode == -1)
  963.             goto quit;
  964.  
  965.         if ((rcode >= 200 && rcode < 300) || rcode >= 500)
  966.             {
  967.             /* if a good transfer or permanent failure remove job */
  968.  
  969.             if (cb->errlog != NULLLIST)
  970.                 retmail (cb);
  971.             /* Unlink the textfile */
  972.  
  973.             (void) unlink (cb->tname);
  974.             (void) unlink (cb->wname);             /* unlink workfile */
  975.             log (cb->s, "SMTP sent job %s To: %s From: %s",
  976.                  cb->jobq->jobname, cb->jobq->to->val, cb->jobq->from);
  977.             }
  978.  
  979.         } while (next_job (cb));
  980.  
  981. quit:
  982.     sendcmd (cb, "QUIT\n");
  983.     if (cb->errlog != NULLLIST)
  984.         {
  985.         retmail (cb);
  986.         (void) unlink (cb->wname);                 /* unlink workfile */
  987.         (void) unlink (cb->tname);                 /* unlink text */
  988.         }
  989.  
  990.     (void) close_s (cb->s);
  991.     if (cb->tfile != NULLFILE)
  992.         fclose (cb->tfile);
  993.  
  994.     cb->lock = 0;
  995.     del_session (cb);
  996.     }
  997.  
  998. /* create mail lockfile */
  999. int
  1000.     mlock (dir, id)
  1001. char *dir, *id;
  1002.     {
  1003.     return mlock_suffix (dir, id, "lck");
  1004.     }
  1005.  
  1006. int
  1007.     mlock_suffix (dir, id, suffix)
  1008. char *dir, *id, *suffix;
  1009.     {
  1010.     char lockname[LINELEN];
  1011.     int fd;
  1012.  
  1013. #ifdef    MSDOS
  1014.     if (strlen (id) > 8)
  1015.         {                                         /* truncate long filenames */
  1016.         id[8] = '\0';
  1017.         if (id[7] == '/')
  1018.             id[7] = '\0';
  1019.  
  1020.         }
  1021. #endif
  1022.     /* Try to create the lock file in an atomic operation */
  1023.  
  1024.     sprintf (lockname, "%s/%s.%s", dir, id, suffix);
  1025. #ifdef        AMIGA
  1026.     /* don't ask, really, just don't ask... I'd do file locking on an Amiga
  1027.      * much more differently than this. */
  1028.     if (access (lockname, 0) == 0)
  1029.         return -1;
  1030. #endif
  1031.  
  1032.     if ((fd = open (lockname, O_WRONLY | O_EXCL | O_CREAT, 0600)) == -1)
  1033.         return -1;
  1034.  
  1035.     close (fd);
  1036.     return 0;
  1037.     }
  1038.  
  1039. /* remove mail lockfile */
  1040. int
  1041.     rmlock (dir, id)
  1042. char *dir, *id;
  1043.     {
  1044.     return rmlock_suffix (dir, id, "lck");
  1045.     }
  1046.  
  1047. int
  1048.     rmlock_suffix (dir, id, suffix)
  1049. char *dir, *id, *suffix;
  1050.     {
  1051.     char lockname[LINELEN];
  1052.  
  1053. #ifdef    MSDOS
  1054.     if (strlen (id) > 8)
  1055.         {                                         /* truncate long filenames */
  1056.         id[8] = '\0';
  1057.         if (id[7] == '/')
  1058.             id[7] = '\0';
  1059.  
  1060.         }
  1061. #endif
  1062.  
  1063.     sprintf (lockname, "%s/%s.%s", dir, id, suffix);
  1064.     return (unlink (lockname));
  1065.     }
  1066.  
  1067. /* free the message struct and data */
  1068. static void
  1069.      del_session (cb)
  1070. register struct smtpcli *cb;
  1071.     {
  1072.     register struct smtp_job *jp, *tp;
  1073.     register int i;
  1074.  
  1075.     if (cb == NULLSMTPCLI)
  1076.         return;
  1077.  
  1078.     for (i = 0; i < MAXSESSIONS; i++)
  1079.         if (cli_session[i] == cb)
  1080.             {
  1081.             cli_session[i] = NULLSMTPCLI;
  1082.             break;
  1083.             }
  1084.  
  1085.     free (cb->wname);
  1086.     free (cb->tname);
  1087.     free (cb->destname);
  1088.     for (jp = cb->jobq; jp != NULLJOB; jp = tp)
  1089.         {
  1090.         tp = jp->next;
  1091.         del_job (jp);
  1092.         }
  1093.  
  1094.     del_list (cb->errlog);
  1095.     free ((char *) cb);
  1096.     Smtpsessions--;                                 /* number of connections
  1097.                                                   * active */
  1098.     }
  1099.  
  1100. static void
  1101.      del_job (jp)
  1102. register struct smtp_job *jp;
  1103.     {
  1104.     if (*jp->jobname != '\0')
  1105.         (void) rmlock (Mailqdir, jp->jobname);
  1106.  
  1107.     free (jp->from);
  1108.     del_list (jp->to);
  1109.     free ((char *) jp);
  1110.     }
  1111.  
  1112. /* delete a list of list structs */
  1113. void
  1114.      del_list (lp)
  1115. struct list *lp;
  1116.     {
  1117.     register struct list *tp, *tp1;
  1118.  
  1119.     for (tp = lp; tp != NULLLIST; tp = tp1)
  1120.         {
  1121.         tp1 = tp->next;
  1122.         free (tp->val);
  1123.         free ((char *) tp);
  1124.         }
  1125.     }
  1126.  
  1127. /* stub for calling mdaemon to return message to sender */
  1128. static void
  1129.      retmail (cb)
  1130. struct smtpcli *cb;
  1131.     {
  1132.     FILE *infile;
  1133.  
  1134. #ifdef SMTPTRACE
  1135.     if (Smtptrace > 5)
  1136.         {
  1137.         tprintf ("smtp job %s returned to sender\n", cb->wname);
  1138.         }
  1139. #endif
  1140.  
  1141.     if ((infile = fopen (cb->tname, READ_TEXT)) == NULLFILE)
  1142.         return;
  1143.  
  1144.     mdaemon (infile, cb->jobq->from, cb->errlog, 1);
  1145.     fclose (infile);
  1146.     }
  1147.  
  1148. /* look to see if a smtp control block exists for this ipdest */
  1149. static struct smtpcli *
  1150.         lookup (destaddr)
  1151. int32 destaddr;
  1152.     {
  1153.     register int i;
  1154.  
  1155.     for (i = 0; i < MAXSESSIONS; i++)
  1156.         {
  1157.         if (cli_session[i] == NULLSMTPCLI)
  1158.             continue;
  1159.  
  1160.         if (cli_session[i]->ipdest == destaddr)
  1161.             return cli_session[i];
  1162.  
  1163.         }
  1164.     return NULLSMTPCLI;
  1165.     }
  1166.  
  1167. /* create a new  smtp control block */
  1168. static struct smtpcli *
  1169.         newcb ()
  1170.     {
  1171.     register int i;
  1172.     register struct smtpcli *cb;
  1173.  
  1174.     for (i = 0; i < MAXSESSIONS; i++)
  1175.         {
  1176.         if (cli_session[i] == NULLSMTPCLI)
  1177.             {
  1178.             cb = (struct smtpcli *) callocw (1, sizeof (struct smtpcli));
  1179.             cb->wname = mallocw ((unsigned) strlen (Mailqdir) + JOBNAME);
  1180.             cb->tname = mallocw ((unsigned) strlen (Mailqdir) + JOBNAME);
  1181.             cli_session[i] = cb;
  1182.             Smtpsessions++;                         /* number of connections
  1183.                                                   * active */
  1184.             return (cb);
  1185.             }
  1186.  
  1187.         }
  1188.     return NULLSMTPCLI;
  1189.     }
  1190.  
  1191. static void
  1192.      execjobs ()
  1193.     {
  1194.     register struct smtpcli *cb;
  1195.     register int i;
  1196.  
  1197.     for (i = 0; i < MAXSESSIONS; i++)
  1198.         {
  1199.         cb = cli_session[i];
  1200.         if (cb == NULLSMTPCLI)
  1201.             continue;
  1202.  
  1203.         if (cb->lock)
  1204.             continue;
  1205.  
  1206.         sprintf (cb->tname, "%s/%s.txt", Mailqdir, cb->jobq->jobname);
  1207.         sprintf (cb->wname, "%s/%s.wrk", Mailqdir, cb->jobq->jobname);
  1208.  
  1209.         newproc ("smtp_send", 1024, smtp_send, 0, cb, NULL, 0);
  1210.  
  1211. #ifdef SMTPTRACE
  1212.         if (Smtptrace)
  1213.             tprintf ("Trying Connection to %s\n", inet_ntoa (cb->ipdest));
  1214. #endif
  1215.  
  1216.         }
  1217.     }
  1218.  
  1219. /* add this job to control block queue */
  1220. static struct smtp_job *
  1221.          setupjob (cb, id, from)
  1222. struct smtpcli *cb;
  1223. char *id, *from;
  1224.     {
  1225.     register struct smtp_job *p1, *p2;
  1226.  
  1227.     p1 = (struct smtp_job *) callocw (1, sizeof (struct smtp_job));
  1228.     p1->from = strdup (from);
  1229.     strcpy (p1->jobname, id);
  1230.     /* now add to end of jobq */
  1231.     if ((p2 = cb->jobq) == NULLJOB)
  1232.         cb->jobq = p1;
  1233.     else
  1234.         {
  1235.         while (p2->next != NULLJOB)
  1236.             p2 = p2->next;
  1237.  
  1238.         p2->next = p1;
  1239.         }
  1240.  
  1241.     return p1;
  1242.     }
  1243.  
  1244. /* called to advance to the next job */
  1245. static int
  1246.     next_job (cb)
  1247. register struct smtpcli *cb;
  1248.     {
  1249.     register struct smtp_job *jp;
  1250.  
  1251.     jp = cb->jobq->next;
  1252.     del_job (cb->jobq);
  1253.     /* remove the error log of previous message */
  1254.     del_list (cb->errlog);
  1255.     cb->errlog = NULLLIST;
  1256.     cb->jobq = jp;
  1257.     if (jp == NULLJOB)
  1258.         return 0;
  1259.  
  1260.     sprintf (cb->tname, "%s/%s.txt", Mailqdir, jp->jobname);
  1261.     sprintf (cb->wname, "%s/%s.wrk", Mailqdir, jp->jobname);
  1262. #ifdef SMTPTRACE
  1263.     if (Smtptrace > 5)
  1264.         {
  1265.         tprintf ("sending job %s\n", jp->jobname);
  1266.         }
  1267. #endif
  1268.  
  1269.     return 1;
  1270.  
  1271.     }
  1272.  
  1273. /* Mail routing function. */
  1274. int32
  1275. mailroute (dest, gateway)
  1276. char *dest;
  1277. int32 gateway;
  1278.     {
  1279.     int32 destaddr;
  1280.  
  1281. /* If the destination is this site, then *don't* go through a mail
  1282.  * server (MX site)
  1283.  */
  1284.     if (stricmp (dest, Hostname) == 0)
  1285.         if ((destaddr = resolve (dest)) != 0)
  1286.             return destaddr;
  1287.  
  1288.     /* look up address or use the gateway */
  1289.  
  1290.     destaddr = resolve_mx (dest);
  1291.     if (destaddr == 0 && (destaddr = resolve (dest)) == 0)
  1292.         {
  1293. #ifdef DSERVER
  1294.         if (zone_filename (dest, NULL))
  1295.             destaddr = gateway;
  1296.         else
  1297. #endif
  1298.         if (Gateway != 0)
  1299.             destaddr = Gateway;                     /* Use the gateway  */
  1300.  
  1301.         }
  1302.  
  1303.     return destaddr;
  1304.  
  1305.     }
  1306.  
  1307. /* save line in error list */
  1308. static void
  1309.      logerr (cb, line)
  1310. struct smtpcli *cb;
  1311. char *line;
  1312.     {
  1313.     register struct list *lp, *tp;
  1314.  
  1315.     tp = (struct list *) callocw (1, sizeof (struct list));
  1316.     tp->val = strdup (line);
  1317.     /* find end of list */
  1318.     if ((lp = cb->errlog) == NULLLIST)
  1319.         cb->errlog = tp;
  1320.     else
  1321.         {
  1322.         while (lp->next != NULLLIST)
  1323.             lp = lp->next;
  1324.  
  1325.         lp->next = tp;
  1326.         }
  1327.     }
  1328.  
  1329. static int
  1330.     smtpsendfile (cb)
  1331. register struct smtpcli *cb;
  1332.     {
  1333.     int error = 0;
  1334.  
  1335.     strcpy (cb->buf, "\n");
  1336.     while (fgets (cb->buf, sizeof (cb->buf), cb->tfile) != NULLCHAR)
  1337.         {
  1338.         /*
  1339.         ** Dot transparency: add another '.' at the start of
  1340.         ** any line which already starts with a '.'
  1341.         */
  1342.  
  1343.         if (cb->buf[0] == '.')
  1344.             usputc (cb->s,'.');
  1345.  
  1346.         usputs (cb->s, cb->buf);
  1347.         }
  1348.  
  1349.     fclose (cb->tfile);
  1350.     cb->tfile = NULLFILE;
  1351.     /* Send the end-of-message command */
  1352.     if (cb->buf[strlen (cb->buf) - 1] == '\n')
  1353.         sendcmd (cb, ".\n");
  1354.     else
  1355.         sendcmd (cb, "\n.\n");
  1356.  
  1357.     return error;
  1358.     }
  1359.  
  1360. /* do a printf() on the socket with optional local tracing */
  1361. #ifdef    ANSIPROTO
  1362. static void
  1363.      sendcmd (struct smtpcli * cb, char *fmt,...)
  1364.     {
  1365.     va_list args;
  1366.  
  1367.     va_start (args, fmt);
  1368. #ifdef    SMTPTRACE
  1369.     if (Smtptrace)
  1370.         {
  1371.         vsprintf (cb->buf, fmt, args);
  1372.         tprintf ("smtp sent: %s", cb->buf);
  1373.         }
  1374. #endif
  1375.  
  1376.     vsprintf (cb->buf, fmt, args);
  1377.     usputs (cb->s, cb->buf);
  1378.     va_end (args);
  1379.     }
  1380.  
  1381. #else
  1382. static void
  1383.      sendcmd (cb, fmt, arg1, arg2, arg3, arg4)
  1384. struct smtpcli *cb;
  1385. char *fmt;
  1386. int arg1, arg2, arg3, arg4;
  1387.     {
  1388. #ifdef    SMTPTRACE
  1389.     if (Smtptrace)
  1390.         {
  1391.         tprintf ("smtp sent: ");
  1392.         tprintf (fmt, arg1, arg2, arg3, arg4);
  1393.         }
  1394. #endif
  1395.  
  1396.     sprintf (cb->buf, fmt, arg1, arg2, arg3, arg4);
  1397.     usputs (cb->s, cb->buf);
  1398.     }
  1399.  
  1400. #endif
  1401.  
  1402. /* Wait for, read and display response from server. Return the result code. */
  1403. static int
  1404.     getresp (cb, mincode)
  1405. struct smtpcli *cb;
  1406. int mincode;                 /* Keep reading until at least this code comes
  1407.                               * back */
  1408.     {
  1409.     int rval;
  1410.     char line[LINELEN];
  1411.  
  1412.     usflush (cb->s);
  1413.     for (;;)
  1414.         {
  1415.         /* Get line */
  1416.         if (recvline (cb->s, line, LINELEN) == -1)
  1417.             {
  1418.             rval = -1;
  1419.             break;
  1420.             }
  1421.  
  1422.         rip (line);                                 /* Remove cr/lf */
  1423.         rval = atoi (line);
  1424. #ifdef    SMTPTRACE
  1425.         if (Smtptrace)
  1426.             tprintf ("smtp recv: %s\n", line);     /* Display to user */
  1427. #endif
  1428.  
  1429.         if (rval >= 500)
  1430.             {                                     /* Save permanent error
  1431.                                                   * replies */
  1432.             char tmp[LINELEN];
  1433.  
  1434.             if (cb->errlog == NULLLIST)
  1435.                 {
  1436.                 sprintf (tmp, "While talking to %s:",
  1437.                          cb->destname);
  1438.                 logerr (cb, tmp);
  1439.                 }
  1440.  
  1441.             if (cb->buf[0] != '\0')
  1442.                 {                                 /* Save offending command */
  1443.                 rip (cb->buf);
  1444.                 sprintf (tmp, ">>> %s", cb->buf);
  1445.                 logerr (cb, tmp);
  1446.                 cb->buf[0] = '\0';
  1447.                 }
  1448.  
  1449.             sprintf (tmp, "<<< %s", line);
  1450.             logerr (cb, tmp);                     /* save the error reply */
  1451.             }
  1452.         /* Messages with dashes are continued */
  1453.  
  1454.         if (line[3] != '-' && rval >= mincode)
  1455.             break;
  1456.  
  1457.         }
  1458.     return rval;
  1459.     }
  1460.  
  1461. static int
  1462.     doverbose (argc, argv, p)
  1463. int argc;
  1464. char *argv[];
  1465. void *p;
  1466.  
  1467.     {
  1468.     return setbool (&smtpverbose, "SMTP verbose mode", argc, argv);
  1469.     }
  1470.  
  1471. unsigned long golden_ymdhms (long year, long month, long day, long hour, long minute, long second)
  1472.     {
  1473.     long result = 365L * year + day + 31L * (month - 1);
  1474.  
  1475.     if (month < 3)
  1476.         result += (year - 1L) / 4L - (75L * ((year - 1) / 100 + 1)) / 100L;
  1477.     else
  1478.         result = result - (40L * month + 230L) / 100L + year / 4L - (75L * (year / 100 + 1)) / 100L;
  1479.  
  1480.     result *= 86400L;
  1481.     result += 3600 * hour;
  1482.     result += 60 * minute;
  1483.     result += second;
  1484.     return result;
  1485.     }
  1486.  
  1487. static int
  1488.     explock (dir, pre, suf, age)
  1489. char *dir, *pre, *suf;
  1490. int32 age;
  1491.     {
  1492.     union FILE_TIME
  1493.         {
  1494.         struct ftime ft;
  1495.         unsigned int ft_int[2];
  1496.         }         file_time;
  1497.  
  1498. #if    0
  1499.     struct ftime ft;
  1500.  
  1501. #endif
  1502.     struct ffblk fileinfo;
  1503.     struct tm *tm_now;
  1504.     time_t t_now;
  1505.     char t[80];
  1506.     unsigned long now, fage, difference;
  1507.  
  1508.     sprintf (t, "%s/%s.%s", dir, pre, suf);
  1509.     if (findfirst (t, &fileinfo, 0) == -1)
  1510.         return 1;
  1511.  
  1512.     if (Delaytime == 0)
  1513.         return !unlink (t);
  1514.  
  1515.     t_now = time (NULL);
  1516.     tm_now = localtime (&t_now);
  1517.     now = golden_ymdhms (tm_now->tm_year + 1900, tm_now->tm_mon + 1,
  1518.                          tm_now->tm_mday, tm_now->tm_hour, tm_now->tm_min,
  1519.                          tm_now->tm_sec);
  1520.     file_time.ft_int[0] = fileinfo.ff_ftime;
  1521.     file_time.ft_int[1] = fileinfo.ff_fdate;
  1522.     fage = golden_ymdhms (file_time.ft.ft_year + 1980, file_time.ft.ft_month,
  1523.              file_time.ft.ft_day, file_time.ft.ft_hour, file_time.ft.ft_min,
  1524.                           file_time.ft.ft_tsec * 2);
  1525.     difference = now - fage;
  1526.     if (difference >= Delaytime)
  1527.         return !unlink (t);
  1528.  
  1529.     return 0;
  1530.     }
  1531.