home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / contrib / smail / smail-3.1 / smail-3 / smail-3.1.28 / src / smtprecv.c < prev    next >
C/C++ Source or Header  |  1992-09-06  |  19KB  |  762 lines

  1. /* @(#)src/smtprecv.c    1.16 9/6/92 01:33:48 */
  2.  
  3. /*
  4.  *    Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
  5.  *    Copyright (C) 1992  Ronald S. Karr
  6.  * 
  7.  * See the file COPYING, distributed with smail, for restriction
  8.  * and warranty information.
  9.  */
  10.  
  11. /*
  12.  * smtprecv.c:
  13.  *    Receive mail using the SMTP protocol.
  14.  */
  15. #include <stdio.h>
  16. #include <ctype.h>
  17. #include <signal.h>
  18. #include "defs.h"
  19. #include "main.h"
  20. #include "smail.h"
  21. #include "addr.h"
  22. #include "dys.h"
  23. #include "log.h"
  24. #include "hash.h"
  25. #ifndef DEPEND
  26. # include "extern.h"
  27. # include "debug.h"
  28. # include "exitcodes.h"
  29. #endif
  30.  
  31. /* library functions */
  32. extern long time();
  33.  
  34. /* types local to this file */
  35. enum e_smtp_commands {
  36.     HELO_CMD,                /* HELO domain */
  37.     MAIL_CMD,                /* MAIL FROM:<sender> */
  38.     RCPT_CMD,                /* RCPT TO:<recipient> */
  39.     DATA_CMD,                /* DATA */
  40.     VRFY_CMD,                /* VRFY */
  41.     EXPN_CMD,                /* EXPN */
  42.     QUIT_CMD,                /* QUIT */
  43.     RSET_CMD,                /* RSET */
  44.     NOOP_CMD,                /* NOOP */
  45.     DEBUG_CMD,                /* DEBUG [level] */
  46.     HELP_CMD,                /* HELP */
  47.     EOF_CMD,                /* end of file encountered */
  48.     OTHER_CMD,                /* unknown command */
  49. };
  50.  
  51. /* functions local to this file */
  52. static void reset_state();
  53. static enum e_smtp_commands read_smtp_command();
  54. static void expand_addr();
  55. static void verify_addr();
  56. static void smtp_input_signals();
  57. static void smtp_processing_signals();
  58. static void set_term_signal();
  59. static void smtp_receive_timeout_sig();
  60. static void smtp_sig_unlink();
  61.  
  62. /* variables local to this file */
  63. static char *data;            /* interesting data within input */
  64.  
  65. static int term_signal;
  66. static int smtp_remove_on_timeout;
  67. static FILE *out_file;
  68. static char *help_msg[] = {
  69.     "250-The following SMTP commands are recognized:",
  70.     "250-",
  71.     "250-   HELO hostname                   - startup and give your hostname",
  72.     "250-   MAIL FROM:<sender-address>      - start transaction from sender",
  73.     "250-   RCPT TO:<recipient-address>     - name recipient for message",
  74.     "250-   VRFY <address>                  - verify deliverability of address",
  75.     "250-   EXPN <address>                  - expand mailing list address",
  76.     "250-   DATA                            - start text of mail message",
  77.     "250-   RSET                            - reset state, drop transaction",
  78.     "250-   NOOP                            - do nothing",
  79.     "250-   DEBUG [level]                   - set debugging level, default 1",
  80.     "250-   HELP                            - produce this help message",
  81.     "250-   QUIT                            - close SMTP connection",
  82.     "250-",
  83.     "250-The normal sequence of events in sending a message is to state the",
  84.     "250-sender address with a MAIL FROM command, give the recipients with",
  85.     "250-as many RCPT TO commands as are required (one address per command)",
  86.     "250-and then to specify the mail message text after the DATA command.",
  87.     "250 Multiple messages may be specified.  End the last one with a QUIT."
  88. };
  89.  
  90.  
  91.  
  92. /*
  93.  * receive_smtp - receive mail over SMTP.
  94.  *
  95.  * Take SMTP commands on the `in' file.  Send reply messages
  96.  * to the `out' file.  If `out' is NULL, then don't send reply
  97.  * messages (i.e., read batch SMTP commands).
  98.  *
  99.  * return an array of spool files which were created in this SMTP
  100.  * conversation.
  101.  *
  102.  * The last spooled message is left open as an efficiency move, so the
  103.  * caller must arrange to close it or process it to completion.  As
  104.  * well, it is the callers responsibility to close the input and
  105.  * output channels.
  106.  */
  107. char **
  108. receive_smtp(in, out)
  109.     FILE *in;                /* stream of SMTP commands */
  110.     FILE *out;                /* channel for responses */
  111. {
  112.     char *error;            /* temp to hold error messages */
  113.     struct addr *cur;
  114.     static char **files = NULL;
  115.     static int file_cnt = 7;        /* initially put 7 parts in array */
  116.     int file_i = 0;            /* index starts at the beginning */
  117.     /* save important state to restore after initialize_state() */
  118.     enum er_proc save_error_proc = error_processing;
  119.     int save_do_aliasing = do_aliasing;
  120.     int save_dont_deliver = dont_deliver;
  121.     FILE *save_errfile = errfile;
  122.     int save_debug = debug;
  123.     int temp, i;
  124.  
  125.     /* initialize state */
  126.     initialize_state();
  127.  
  128.     /* restore important state */
  129.     error_processing = save_error_proc;
  130.     do_aliasing = save_do_aliasing;
  131.     dont_deliver = save_dont_deliver;
  132.  
  133.     term_signal = FALSE;
  134.     out_file = out;
  135.     smtp_processing_signals();
  136.     if (out) {
  137.     (void) signal(SIGALRM, smtp_receive_timeout_sig);
  138.     }
  139.  
  140.     /* allocate an initial chunk of spool filename slots */
  141.     if (files == NULL) {
  142.     files = (char **)xmalloc((file_cnt + 1) * sizeof(*files));
  143.     }
  144.  
  145.     /* output the startup banner line */
  146.     if (out) {
  147.     char *s;
  148.  
  149.     s = expand_string(smtp_banner, (struct addr *)NULL,
  150.               (char *)NULL, (char *)NULL);
  151.     while (*s) {
  152.         fprintf(out, "220%c", index(s, '\n') == NULL? ' ': '-');
  153.         while (*s) {
  154.         putc(*s, out);
  155.         if (*s++ == '\n') break;
  156.         }
  157.     }
  158.     putc('\r', out);
  159.     putc('\n', out);
  160.     fflush(out);
  161.     }
  162.  
  163.     while (! term_signal || out == NULL) {
  164.     if (out) {
  165.         alarm(smtp_receive_command_timeout);
  166.     }
  167.     switch (read_smtp_command(in)) {
  168.     case HELO_CMD:
  169.         strip_rfc822_comments(data);
  170.         if (out && data[0] == '\0') {
  171.         fprintf(out, "501 HELO requires domain name as operand\r\n");
  172.         fflush(out);
  173.         break;
  174.         }
  175.         if (sender_host == NULL && data[0] != '\0') {
  176.         sender_host = COPY_STRING(data);
  177.         }
  178.         if (sender_proto == NULL) {
  179.         sender_proto = (out? "smtp": "bsmtp");
  180.         }
  181.         if (out) {
  182.         fprintf(out, "250 %s Hello %s\r\n", primary_name, data);
  183.         fflush(out);
  184.         }
  185.         reset_state();
  186.         break;
  187.  
  188.     case MAIL_CMD:
  189.         strip_rfc822_comments(data);
  190.         if (out && data[0] == '\0') {
  191.         fprintf(out, "501 MAIL FROM requires address as operand\r\n");
  192.         fflush(out);
  193.         break;
  194.         }
  195.         if (sender) {
  196.         if (out) {
  197.             fprintf(out, "503 Sender already specified\r\n");
  198.             fflush(out);
  199.         }
  200.         break;
  201.         }
  202.         sender = preparse_address(data, &error);
  203.         if (out) {
  204.         if (sender) {
  205.             fprintf(out, "250 <%s> ... Sender Okay\r\n",
  206.                    sender);
  207.         } else {
  208.             fprintf(out, "501 <%s> ... %s\r\n", data, error);
  209.         }
  210.         fflush(out);
  211.         }
  212.         if (sender && sender[0] == '\0') {
  213.         /* special error sender form <> given */
  214.         sender = COPY_STRING("<>");
  215.         }
  216.         if (sender && EQ(sender, "+")) {
  217.         /* special smail-internal <+> was given */
  218.         sender = COPY_STRING("<+>");
  219.         }
  220.         break;
  221.  
  222.     case RCPT_CMD:
  223.         strip_rfc822_comments(data);
  224.         if (out && data[0] == '\0') {
  225.         fprintf(out, "501 RCPT TO requires address as operand\r\n");
  226.         fflush(out);
  227.         break;
  228.         }
  229.         cur = alloc_addr();
  230.         if (out) {
  231.         if (cur->work_addr = preparse_address(data, &error)) {
  232.             fprintf(out, "250 <%s> ... Recipient Okay\r\n",
  233.                 cur->work_addr);
  234.             fflush(out);
  235.         } else {
  236.             fprintf(out, "501 <%s> ... %s\r\n", data, error);
  237.             fflush(out);
  238.             break;
  239.         }
  240.         }
  241.         /*
  242.          * surround in angle brackets, if the addr begins with `-'.
  243.          * This will avoid ambiguities in the data dumped to the spool
  244.          * file.
  245.          */
  246.         if (data[0] == '-') {
  247.         cur->in_addr = xprintf("<%s>", data);
  248.         } else {
  249.         cur->in_addr = COPY_STRING(data);
  250.         }
  251.         cur->succ = recipients;
  252.         recipients = cur;
  253.         break;
  254.  
  255.     case DATA_CMD:
  256.         if (sender == NULL) {
  257.         if (out) {
  258.             fprintf(out, "503 Need MAIL command\r\n");
  259.             fflush(out);
  260.         } else {
  261.             /* sink the message for the sake of further batched cmds */
  262.             if (spool_fn) {
  263.             close_spool();
  264.             }
  265.             swallow_smtp(in);
  266.         }
  267.         break;
  268.         }
  269.         if (recipients == NULL) {
  270.         if (out) {
  271.             fprintf(out, "503 Need RCPT (recpient)\r\n");
  272.             fflush(out);
  273.         } else {
  274.             /* sink the message for the sake of further batched cmds */
  275.             if (spool_fn) {
  276.             close_spool();
  277.             }
  278.             swallow_smtp(in);
  279.         }
  280.         break;
  281.         }
  282.         if (out) {
  283.         fprintf(out,
  284.              "354 Enter mail, end with \".\" on a line by itself\r\n");
  285.         fflush(out);
  286.         alarm(0);
  287.         }
  288.  
  289.         /*
  290.          * if we had the previous spool file opened, close it
  291.          * before creating a new one
  292.          */
  293.         if (spool_fn) {
  294.         close_spool();
  295.         }
  296.         if (out) {
  297.         /*
  298.          * if we are not interactive and cannot send back failure
  299.          * messages, always try to accept the complete message.
  300.          */
  301.         smtp_input_signals();
  302.         alarm(smtp_receive_message_timeout);
  303.         }
  304.         smtp_remove_on_timeout = 1;
  305.         if (queue_message(in, SMTP_DOTS, recipients, &error) == FAIL) {
  306.         exitvalue = EX_IOERR;
  307.         log_spool_errors();
  308.         if (out) {
  309.             fprintf(out, "451 Failed to queue message: %s: %s\r\n",
  310.                 error, strerrno());
  311.             fflush(out);
  312.             break;
  313.         } else if (errfile) {
  314.             fprintf(errfile, "Failed to queue message: %s: %s\r\n",
  315.                 error, strerrno());
  316.         }
  317.         }
  318.         smtp_processing_signals();
  319.         if (sender == NULL) {
  320.         unlink_spool();
  321.         reset_state();
  322.         break;
  323.         }
  324.         if (read_message() == NULL) {
  325.         log_spool_errors();
  326.         unlink_spool();
  327.         if (out) {
  328.             fprintf(out, "451 error in spooled message\r\n");
  329.             fflush(out);
  330.         }
  331.         break;
  332.         }
  333.         alarm(0);
  334.         smtp_remove_on_timeout = 0;
  335.  
  336.         check_grade();
  337.         log_incoming();
  338.         log_spool_errors();
  339.         if (out) {
  340.         fprintf(out, "250 Mail accepted\r\n");
  341.         fflush(out);
  342.         }
  343.         /* always allow an extra element to store the ending NULL */
  344.         if (file_i >= file_cnt) {
  345.         /* we need to grow the array of spool file names */
  346.         file_cnt += 8;
  347.         files = (char **)xrealloc((char *)files,
  348.                       (file_cnt + 1) * sizeof(*files));
  349.         }
  350.         files[file_i++] = xprintf("%s/input/%s", spool_dir, spool_fn);
  351.         reset_state();
  352.         break;
  353.  
  354.     case VRFY_CMD:
  355.         if (out) {
  356. #ifdef NO_VERIFY
  357.         fprintf(out, "502 Command not implemented\r\n");
  358. #else
  359.         strip_rfc822_comments(data);
  360.         verify_addr(data, out);
  361.         fflush(out);
  362. #endif
  363.         }
  364.         break;
  365.  
  366.     case EXPN_CMD:
  367.         if (out) {
  368. #ifdef NO_VERIFY
  369.         fprintf(out, "502 Command not implemented\r\n");
  370. #else
  371.         strip_rfc822_comments(data);
  372.         expand_addr(data, out);
  373.         fflush(out);
  374. #endif
  375.         }
  376.         break;
  377.  
  378.     case QUIT_CMD:
  379.         if (out) {
  380.         fprintf(out, "221 %s closing connection\r\n",
  381.                    primary_name);
  382.         fflush(out);
  383.         }
  384.         reset_state();
  385.         files[file_i++] = NULL;
  386.         errfile = save_errfile;
  387.         debug = save_debug;
  388.         return files;
  389.  
  390.     case RSET_CMD:
  391.         reset_state();
  392.         if (out) {
  393.         fprintf(out, "250 Reset state\r\n");
  394.         fflush(out);
  395.         }
  396.         break;
  397.  
  398.     case NOOP_CMD:
  399.         if (out) {
  400.         fprintf(out, "250 Okay\r\n");
  401.         fflush(out);
  402.         }
  403.         break;
  404.  
  405.     case DEBUG_CMD:
  406.         if (out) {
  407. #ifndef NODEBUG
  408.         if (smtp_debug) {
  409.             strip_rfc822_comments(data);
  410.             if (data[0]) {
  411.             error = NULL;
  412.             temp = c_atol(data, &error);
  413.             if (error) {
  414.                 fprintf(out, "500 bad number: %s\r\n", error);
  415.                 fflush(out);
  416.                 break;
  417.             }
  418.             } else {
  419.             temp = 1;
  420.             }
  421.             if (temp == 0) {
  422.             fprintf(out, "250 Debugging disabled\r\n");
  423.             } else {
  424.             DEBUG(DBG_QUEUE_LO,
  425.                   "debugging output grabbed by SMTP\r\n");
  426.             fprintf(out, "250 Debugging level: %d\r\n", temp);
  427.             }
  428.             fflush(out);
  429.             debug = temp;
  430.             errfile = out;
  431.             break;
  432.         }
  433. #endif    /* NODEBUG */
  434.         fprintf(out, "500 I hear you knocking, but you can't come in\r\n");
  435.         fflush(out);
  436.         }
  437.         break;
  438.  
  439.     case HELP_CMD:
  440.         if (out) {
  441.         for (i = 0; i < TABLESIZE(help_msg); i++) {
  442.             fprintf(out, "%s\r\n", help_msg[i]);
  443.         }
  444.         fflush(out);
  445.         }
  446.         break;
  447.  
  448.     case EOF_CMD:
  449.         if (out) {
  450.         fprintf(out, "421 %s Lost input channel\r\n", primary_name);
  451.         fflush(out);
  452.         }
  453.         files[file_i++] = NULL;
  454.         errfile = save_errfile;
  455.         debug = save_debug;
  456.         return files;
  457.  
  458.     default:
  459.         if (out) {
  460.         fprintf(out, "500 Command unrecognized\r\n");
  461.         fflush(out);
  462.         }
  463.         break;
  464.     }
  465.     }
  466.  
  467.     /*
  468.      * we appear to have received a SIGTERM, so shutdown and tell the
  469.      * remote host.
  470.      */
  471.     fprintf(out, "421 %s Service not available, closing channel\r\n",
  472.         primary_name);
  473.     fflush(out);
  474.  
  475.     files[file_i] = NULL;
  476.     errfile = save_errfile;
  477.     debug = save_debug;
  478.     return files;
  479. }
  480.  
  481. static void
  482. reset_state()
  483. {
  484.     struct addr *cur;
  485.     struct addr *next;
  486.  
  487.     for (cur = recipients; cur; cur = next) {
  488.     next = cur->succ;
  489.     xfree(cur->in_addr);
  490.     if (cur->work_addr) {
  491.         /* work_addr is defined only for interactive smtp */
  492.         xfree(cur->work_addr);
  493.     }
  494.     xfree((char *)cur);
  495.     }
  496.     recipients = NULL;
  497.  
  498.     if (sender) {
  499.     xfree(sender);
  500.     sender = NULL;
  501.     }
  502. }
  503.  
  504. static enum e_smtp_commands
  505. read_smtp_command(f)
  506.     register FILE *f;            /* SMTP command stream */
  507. {
  508.     static struct str input;        /* buffer storing recent command */
  509.     static int inited = FALSE;        /* TRUE if input initialized */
  510.     register int c;            /* input char */
  511.     static struct smtp_cmd_list {
  512.     char *name;
  513.     int len;
  514.     enum e_smtp_commands cmd;
  515.     } smtp_cmd_list[] = {
  516.     "HELO",     sizeof("HELO")-1,    HELO_CMD,
  517.     "MAIL FROM:",    sizeof("MAIL FROM:")-1,    MAIL_CMD,
  518.     "RCPT TO:",    sizeof("RCPT TO:")-1,    RCPT_CMD,
  519.     "DATA",        sizeof("DATA")-1,    DATA_CMD,
  520.     "VRFY",        sizeof("VRFY")-1,    VRFY_CMD,
  521.     "EXPN",        sizeof("EXPN")-1,    EXPN_CMD,
  522.     "QUIT",        sizeof("QUIT")-1,    QUIT_CMD,
  523.     "RSET",        sizeof("RSET")-1,    RSET_CMD,
  524.     "NOOP",        sizeof("NOOP")-1,    NOOP_CMD,
  525.     "DEBUG",    sizeof("DEBUG")-1,    DEBUG_CMD,
  526.     "HELP",        sizeof("HELP")-1,    HELP_CMD,
  527.     };
  528.     struct smtp_cmd_list *cp;
  529.  
  530.     if (! inited) {
  531.     STR_INIT(&input);
  532.     inited = TRUE;
  533.     } else {
  534.     input.i = 0;
  535.     }
  536.     while ((c = getc(f)) != '\n' && c != EOF) {
  537.     STR_NEXT(&input, c);
  538.     }
  539.     if (input.p[input.i - 1] == '\r') {
  540.     input.p[input.i - 1] = '\0';
  541.     } else {
  542.     STR_NEXT(&input, '\0');
  543.     }
  544.  
  545.     /* return end of file pseudo command if end of file encountered */
  546.     if (c == EOF) {
  547.     return EOF_CMD;
  548.     }
  549.  
  550.     for (cp = smtp_cmd_list; cp < ENDTABLE(smtp_cmd_list); cp++) {
  551.     if (strncmpic(cp->name, input.p, cp->len) == 0) {
  552.         for (data = input.p + cp->len; isspace(*data); data++) ;
  553.         return cp->cmd;
  554.     }
  555.     }
  556.  
  557.     return OTHER_CMD;
  558. }
  559.  
  560. #ifndef NO_VERIFY
  561. /*
  562.  * expand_addr - expand an address
  563.  *
  564.  * display the list of items that an address expands to.
  565.  */
  566. static void
  567. expand_addr(in_addr, out)
  568.     char *in_addr;            /* input address string */
  569.     FILE *out;                /* write expansion here */
  570. {
  571.     struct addr *addr = alloc_addr();    /* get an addr structure */
  572.     struct addr *okay = NULL;        /* list of deliverable addrs */
  573.     struct addr *defer = NULL;        /* list of currently unknown addrs */
  574.     struct addr *fail = NULL;        /* list of undeliverable addrs */
  575.     char *error;            /* hold error message */
  576.  
  577.     addr->in_addr = in_addr;        /* setup the input addr structure */
  578.     /* build the mungeable addr string */
  579.     addr->work_addr = preparse_address(in_addr, &error);
  580.     if (addr->work_addr == NULL) {
  581.     fprintf(out, "501 %s ... %s\r\n", in_addr, error);
  582.     fflush(out);
  583.     return;
  584.     }
  585.  
  586.     /* cache directors and routers on the assumption we will need them again */
  587.     if (! queue_only) {
  588.     if (! cached_directors) {
  589.         cache_directors();
  590.     }
  591.     if (! cached_routers) {
  592.         cache_routers();
  593.     }
  594.     }
  595.  
  596.     hit_table = new_hash_table(hit_table_len,
  597.                    (struct block *)NULL,
  598.                    HASH_DEFAULT);
  599.     resolve_addr_list(addr, &okay, &defer, &fail, TRUE);
  600.     if (okay) {
  601.     register struct addr *cur;    /* current addr to display */
  602.  
  603.     /* display the complete list of resolved addresses */
  604.     for (cur = okay; cur->succ; cur = cur->succ) {
  605.         fprintf(out, "250-%s\r\n", cur->in_addr);
  606.         fflush(out);
  607.     }
  608.     /* the last one should not begin with 250- */
  609.     fprintf(out, "250 %s\r\n", cur->in_addr);
  610.     } else {
  611.     /* just say we couldn't find it */
  612.     fprintf(out, "550 %s ... not matched\r\n", in_addr);
  613.     }
  614. }
  615.  
  616. /*
  617.  * verify_addr - verify an address
  618.  *
  619.  * redisplay the input address if it is a valid address.
  620.  */
  621. static void
  622. verify_addr(in_addr, out)
  623.     char *in_addr;            /* input address string */
  624.     FILE *out;                /* write expansion here */
  625. {
  626.     struct addr *addr = alloc_addr();    /* get an addr structure */
  627.     struct addr *okay = NULL;        /* verified address */
  628.     struct addr *defer = NULL;        /* temporarily unverifiable addr */
  629.     struct addr *fail = NULL;        /* unverified addr */
  630.     char *error;            /* hold error message */
  631.  
  632.     addr->in_addr = in_addr;        /* setup the input addr structure */
  633.     /* build the mungeable addr string */
  634.     addr->work_addr = preparse_address(in_addr, &error);
  635.     if (addr->work_addr == NULL) {
  636.     fprintf(out, "501 %s ... %s\r\n", in_addr, error);
  637.     fflush(out);
  638.     return;
  639.     }
  640.  
  641.     /* cache directors and routers on the assumption we will need them again */
  642.     if (! queue_only) {
  643.     if (! cached_directors) {
  644.         cache_directors();
  645.     }
  646.     if (! cached_routers) {
  647.         cache_routers();
  648.     }
  649.     }
  650.     verify_addr_list(addr, &okay, &defer, &fail);
  651.  
  652.     if (okay) {
  653.     fprintf(out, "250 %s\r\n", in_addr);
  654.     } else if (defer) {
  655.     fprintf(out, "550 %s ... cannot verify: %s\r\n", in_addr,
  656.         defer->error->message);
  657.     } else if (fail) {
  658.     fprintf(out, "550 %s ... not matched: %s\r\n", in_addr,
  659.         fail->error->message);
  660.     } else {
  661.     /* hmmm, it should have been in one of the lists */
  662.     fprintf(out, "550 %s ... not matched\r\n", in_addr);
  663.     }
  664. }
  665. #endif    /* NO_VERIFY */
  666.  
  667.  
  668. /*
  669.  * smtp_input_signals - setup signals for reading in message with smtp
  670.  *
  671.  * Basically, unlink the message except in the case of SIGTERM, which
  672.  * will cause sig_term and queue_only to be set.
  673.  */
  674. static void
  675. smtp_input_signals()
  676. {
  677.     if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
  678.     (void) signal(SIGHUP, smtp_sig_unlink);
  679.     }
  680.     if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
  681.     (void) signal(SIGINT, smtp_sig_unlink);
  682.     }
  683.     (void) signal(SIGTERM, set_term_signal);
  684. }
  685.  
  686. /*
  687.  * smtp_processing_signals - setup signals for getting smtp commands
  688.  *
  689.  * basically, everything interesting should cause a call to
  690.  * set_term_signal.
  691.  */
  692. static void
  693. smtp_processing_signals()
  694. {
  695.     if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
  696.     (void) signal(SIGHUP, set_term_signal);
  697.     }
  698.     if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
  699.     (void) signal(SIGINT, set_term_signal);
  700.     }
  701.     (void) signal(SIGTERM, set_term_signal);
  702. }
  703.  
  704. /*
  705.  * set_term_signal - set term_signal and queue_only
  706.  *
  707.  * This is used by signals to abort SMTP command processing and to
  708.  * prevent attempting delivery.
  709.  *
  710.  * NOTE:  This doesn't work correctly for systems that lack restartable
  711.  *      system calls, as read will return EINTR for such systems,
  712.  *      rather than continuing.  This situation could be improved,
  713.  *      though it doesn't really seem worth the rather large amount
  714.  *      of bother required.
  715.  */
  716. static void
  717. set_term_signal(sig)
  718.     int sig;
  719. {
  720.     (void) signal(sig, set_term_signal);
  721.     term_signal = TRUE;
  722.     queue_only = TRUE;
  723. }
  724.  
  725. /*
  726.  * smtp_receive_timeout_sig - timeout SMTP
  727.  */
  728.  
  729. static void
  730. smtp_receive_timeout_sig(sig)
  731.     int sig;
  732. {
  733.     fprintf(out_file, "421 %s SMTP command timeout, closing channel\r\n",
  734.         primary_name);
  735.     write_log(LOG_SYS, "SMTP connection timeout%s%s.",
  736.           sender_host? "while talking with": "",
  737.           sender_host? sender_host: "");
  738.     if (smtp_remove_on_timeout) {
  739.     unlink_spool();
  740.     }
  741.     exit(EX_TEMPFAIL);
  742. }
  743.  
  744. /*
  745.  * smtp_sig_unlink - unlink spool file and fast exit.
  746.  *
  747.  * This is useful for handling signals to abort reading a message in
  748.  * with SMTP.
  749.  */
  750. static void
  751. smtp_sig_unlink(sig)
  752.     int sig;
  753. {
  754.     (void) signal(sig, SIG_IGN);
  755.     if (out_file) {
  756.     fprintf(out_file, "421 %s Service not available, closing channel\r\n",
  757.         primary_name);
  758.     }
  759.     unlink_spool();
  760.     exit(EX_OSFILE);
  761. }
  762.