]> Pileus Git - ~andy/fetchmail/blobdiff - sink.c
Better bug guidelines.
[~andy/fetchmail] / sink.c
diff --git a/sink.c b/sink.c
index 2ead73d39e5d321636dcd69e3bf29b7d2fbc70c0..519fc2bd67a981278ce8ca01ab25e75aa0127ccb 100644 (file)
--- a/sink.c
+++ b/sink.c
@@ -169,7 +169,11 @@ static int smtp_open(struct query *ctl)
 
 /* these are shared by open_sink and stuffline */
 static FILE *sinkfp;
+#ifndef HAVE_SIGACTION
 static RETSIGTYPE (*sigchld)(int);
+#else
+static struct sigaction sa_old;
+#endif /* HAVE_SIGACTION */
 
 int stuffline(struct query *ctl, char *buf)
 /* ship a line to the given control block's output sink (SMTP server or MDA) */
@@ -377,7 +381,7 @@ static int send_bouncemail(struct query *ctl, struct msgblk *msg,
 
 static int handle_smtp_report(struct query *ctl, struct msgblk *msg)
 /* handle SMTP errors based on the content of SMTP_response */
-/* Mail is deleted from the server if this function returns PS_REFUSED. */
+/* return of PS_REFUSED deletes mail from the server; PS_TRANSIENT keeps it */
 {
     int smtperr = atoi(smtp_response);
     char *responses[1];
@@ -385,6 +389,11 @@ static int handle_smtp_report(struct query *ctl, struct msgblk *msg)
     xalloca(responses[0], char *, strlen(smtp_response)+1);
     strcpy(responses[0], smtp_response);
 
+    SMTP_rset(ctl->smtp_socket);    /* stay on the safe site */
+
+    if (outlevel >= O_DEBUG)
+       report(stdout, "Saved error is still %d\n", smtperr);
+
     /*
      * Note: send_bouncemail message strings are not made subject
      * to gettext translation because (a) they're going to be 
@@ -408,7 +417,6 @@ static int handle_smtp_report(struct query *ctl, struct msgblk *msg)
         * 554 = Postfix antispam response.
         *
         */
-       SMTP_rset(ctl->smtp_socket);    /* stay on the safe site */
        send_bouncemail(ctl, msg, XMIT_ACCEPT,
                        "Our spam filter rejected this transaction.\r\n", 
                        1, responses);
@@ -427,32 +435,14 @@ static int handle_smtp_report(struct query *ctl, struct msgblk *msg)
 
     switch (smtperr)
     {
-    case 452: /* insufficient system storage */
-       /*
-        * Temporary out-of-queue-space condition on the
-        * ESMTP server.  Don't try to ship the message, 
-        * and suppress deletion so it can be retried on
-        * a future retrieval cycle. 
-        *
-        * Bouncemail *might* be appropriate here as a delay
-        * notification (note; if we ever add this, we must make
-        * sure the RFC1894 Action field is "delayed" rather thwn
-        * "failed").  But it's not really necessary because
-        * this is not an actual failure, we're very likely to be
-        * able to recover on the next cycle.
-        */
-       SMTP_rset(ctl->smtp_socket);    /* required by RFC1870 */
-       return(PS_TRANSIENT);
-
     case 552: /* message exceeds fixed maximum message size */
        /*
         * Permanent no-go condition on the
         * ESMTP server.  Don't try to ship the message, 
         * and allow it to be deleted.
         */
-       SMTP_rset(ctl->smtp_socket);    /* required by RFC1870 */
        send_bouncemail(ctl, msg, XMIT_ACCEPT,
-                       "This message was too large.\r\n", 
+                       "This message was too large (SMTP error 552).\r\n", 
                        1, responses);
        return(run.bouncemail ? PS_REFUSED : PS_TRANSIENT);
   
@@ -464,19 +454,35 @@ static int handle_smtp_report(struct query *ctl, struct msgblk *msg)
         * (b) we wouldn't want spammers to get confirmation that
         * this address is live, anyway.
         */
-       SMTP_rset(ctl->smtp_socket);    /* stay on the safe side */
        send_bouncemail(ctl, msg, XMIT_ACCEPT,
-                       "Invalid address.\r\n", 
+                       "Invalid address in MAIL FROM (SMTP error 553).\r\n", 
                        1, responses);
        return(PS_REFUSED);
 
-    default:   /* bounce non-transient errors back to the sender */
-       SMTP_rset(ctl->smtp_socket);    /* stay on the safe side */
+    default:
+       /* bounce non-transient errors back to the sender */
        if (smtperr >= 500 && smtperr <= 599)
            if (send_bouncemail(ctl, msg, XMIT_ACCEPT,
                                "General SMTP/ESMTP error.\r\n", 
                                1, responses))
                return(run.bouncemail ? PS_REFUSED : PS_TRANSIENT);
+       /*
+        * We're going to end up here on 4xx errors, like:
+        *
+        * 451: temporarily unable to identify sender (exim)
+        * 452: temporary out-of-queue-space condition on the ESMTP server.
+        *
+        * These are temporary errors.  Don't try to ship the message,
+        * and suppress deletion so it can be retried on a future
+        * retrieval cycle.
+        *
+        * Bouncemail *might* be appropriate here as a delay
+        * notification (note; if we ever add this, we must make
+        * sure the RFC1894 Action field is "delayed" rather thwn
+        * "failed").  But it's not really necessary because
+        * these are not actual failures, we're very likely to be
+        * able to recover on the next cycle.
+        */
        return(PS_TRANSIENT);
     }
 }
@@ -486,6 +492,9 @@ int open_sink(struct query *ctl, struct msgblk *msg,
 /* set up sinkfp to be an input sink we can ship a message to */
 {
     struct     idlist *idp;
+#ifdef HAVE_SIGACTION
+    struct      sigaction sa_new;
+#endif /* HAVE_SIGACTION */
 
     *bad_addresses = *good_addresses = 0;
 
@@ -506,7 +515,9 @@ int open_sink(struct query *ctl, struct msgblk *msg,
            fputs(" BODY=7BIT", sinkfp);
 
        /* exim's BSMTP processor does not handle SIZE */
-       /* fprintf(sinkfp, " SIZE=%d\r\n", msg->reallen); */
+       /* fprintf(sinkfp, " SIZE=%d", msg->reallen); */
+
+       fprintf(sinkfp, "\r\n");
 
        /*
         * RFC 1123 requires that the domain name part of the
@@ -521,12 +532,14 @@ int open_sink(struct query *ctl, struct msgblk *msg,
        for (idp = msg->recipients; idp; idp = idp->next)
            if (idp->val.status.mark == XMIT_ACCEPT)
            {
-               if (strchr(idp->id, '@'))
-                   fprintf(sinkfp,
-                               "RCPT TO: %s\r\n", idp->id);
+               if (ctl->smtpname)
+                   fprintf(sinkfp, "RCPT TO: %s\r\n", ctl->smtpname);
+               else if (strchr(idp->id, '@'))
+                   fprintf(sinkfp,
+                           "RCPT TO: %s\r\n", idp->id);
                else
                    fprintf(sinkfp,
-                               "RCPT TO: %s@%s\r\n", idp->id, ctl->destaddr);
+                           "RCPT TO: %s@%s\r\n", idp->id, ctl->destaddr);
                *good_addresses = 0;
            }
 
@@ -682,7 +695,14 @@ int open_sink(struct query *ctl, struct msgblk *msg,
            return(PS_IOERR);
        }
 
+#ifndef HAVE_SIGACTION
        sigchld = signal(SIGCHLD, SIG_DFL);
+#else
+       memset (&sa_new, 0, sizeof sa_new);
+       sigemptyset (&sa_new.sa_mask);
+       sa_new.sa_handler = SIG_DFL;
+       sigaction (SIGCHLD, &sa_new, &sa_old);
+#endif /* HAVE_SIGACTION */
     }
     else /* forward to an SMTP or LMTP listener */
     {
@@ -717,22 +737,38 @@ int open_sink(struct query *ctl, struct msgblk *msg,
 
        /*
         * Try to get the SMTP listener to take the Return-Path
-        * address as MAIL FROM .  If it won't, fall back on the
-        * calling-user ID.  This won't affect replies, which use the
-        * header From address anyway.
+        * address as MAIL FROM.  If it won't, fall back on the
+        * remotename and mailserver host.  This won't affect replies,
+        * which use the header From address anyway; the MAIL FROM
+        * address is a place for the SMTP listener to send
+        * bouncemail.  The point is to guarantee a FQDN in the MAIL
+        * FROM line -- some SMTP listeners, like smail, become
+        * unhappy otherwise.
         *
         * RFC 1123 requires that the domain name part of the
         * MAIL FROM address be "canonicalized", that is a
-        * FQDN or MX but not a CNAME.  We'll assume the From
+        * FQDN or MX but not a CNAME.  We'll assume the Return-Path
         * header is already in this form here (it certainly
         * is if rewrite is on).  RFC 1123 is silent on whether
         * a nonexistent hostname part is considered canonical.
         *
         * This is a potential problem if the MTAs further upstream
         * didn't pass canonicalized From/Return-Path lines, *and* the
-        * local SMTP listener insists on them.
+        * local SMTP listener insists on them. 
         */
-       ap = (msg->return_path[0]) ? msg->return_path : user;
+       if (!msg->return_path[0])
+       {
+           sprintf(addr, "%s@%s", ctl->remotename, ctl->server.truename);
+           ap = addr;
+       }
+       else if (strchr(msg->return_path, '@'))
+           ap = msg->return_path;
+       else            /* in case Return-Path existed but was local */
+       {
+           sprintf(addr, "%s@%s", msg->return_path, ctl->server.truename);
+           ap = addr;
+       }
+
        if (SMTP_from(ctl->smtp_socket, ap, options) != SM_OK)
            return(handle_smtp_report(ctl, msg));
 
@@ -748,13 +784,22 @@ int open_sink(struct query *ctl, struct msgblk *msg,
            {
                if (strchr(idp->id, '@'))
                    strcpy(addr, idp->id);
-               else
+               else {
+                   if (ctl->smtpname) {
 #ifdef HAVE_SNPRINTF
-                   snprintf(addr, sizeof(addr)-1, "%s@%s", idp->id, ctl->destaddr);
+                       snprintf(addr, sizeof(addr)-1, "%s", ctl->smtpname);
 #else
-                   sprintf(addr, "%s@%s", idp->id, ctl->destaddr);
+                       sprintf(addr, "%s", ctl->smtpname);
 #endif /* HAVE_SNPRINTF */
 
+                   } else {
+#ifdef HAVE_SNPRINTF
+                     snprintf(addr, sizeof(addr)-1, "%s@%s", idp->id, ctl->destaddr);
+#else
+                     sprintf(addr, "%s@%s", idp->id, ctl->destaddr);
+#endif /* HAVE_SNPRINTF */
+                   }
+               }
                if (SMTP_rcpt(ctl->smtp_socket, addr) == SM_OK)
                    (*good_addresses)++;
                else
@@ -842,7 +887,11 @@ void release_sink(struct query *ctl)
            pclose(sinkfp);
            sinkfp = (FILE *)NULL;
        }
+#ifndef HAVE_SIGACTION
        signal(SIGCHLD, sigchld);
+#else
+       sigaction (SIGCHLD, &sa_old, NULL);
+#endif /* HAVE_SIGACTION */
     }
 }
 
@@ -861,7 +910,11 @@ int close_sink(struct query *ctl, struct msgblk *msg, flag forward)
        }
        else
            rc = 0;
+#ifndef HAVE_SIGACTION
        signal(SIGCHLD, sigchld);
+#else
+       sigaction (SIGCHLD, &sa_old, NULL);
+#endif /* HAVE_SIGACTION */
        if (rc)
        {
            report(stderr, 
@@ -871,11 +924,14 @@ int close_sink(struct query *ctl, struct msgblk *msg, flag forward)
     }
     else if (ctl->bsmtp)
     {
+       int error;
+
        /* implicit disk-full check here... */
        fputs(".\r\n", sinkfp);
+       error = ferror(sinkfp);
        if (strcmp(ctl->bsmtp, "-"))
-           fclose(sinkfp);
-       if (ferror(sinkfp))
+           if (fclose(sinkfp) == EOF) error = 1;
+       if (error)
        {
            report(stderr, 
                   _("Message termination or close of BSMTP file failed\n"));