]> Pileus Git - ~andy/fetchmail/blobdiff - sink.c
Fix typo repsonsible -> responsible.
[~andy/fetchmail] / sink.c
diff --git a/sink.c b/sink.c
index 8a0561f8fbc0fb73e7e465fe2601786b4c231bb2..5e9bef9864eb80f6ae3bac880a33b582be8a1e55 100644 (file)
--- a/sink.c
+++ b/sink.c
 #include  <errno.h>
 #include  <string.h>
 #include  <signal.h>
-#ifdef HAVE_MEMORY_H
-#include  <memory.h>
-#endif /* HAVE_MEMORY_H */
-#if defined(STDC_HEADERS)
 #include  <stdlib.h>
-#endif
-#if defined(HAVE_UNISTD_H)
 #include  <unistd.h>
-#endif
-#if defined(HAVE_STDARG_H)
 #include  <stdarg.h>
-#else
-#include  <varargs.h>
-#endif
 #include  <ctype.h>
 #include  <langinfo.h>
 
@@ -42,7 +31,7 @@
 
 #include  "socket.h"
 #include  "smtp.h"
-#include  "i18n.h"
+#include  "gettext.h"
 
 /* BSD portability hack...I know, this is an ugly place to put it */
 #if !defined(SIGCHLD) && defined(SIGCLD)
@@ -76,7 +65,7 @@ static void smtp_rset(struct query *ctl)
     }
 }
 
-int smtp_open(struct query *ctl)
+int smtp_setup(struct query *ctl)
 /* try to open a socket to the appropriate SMTP server for this query */ 
 {
     /* maybe it's time to close the socket in order to force delivery */
@@ -114,7 +103,7 @@ int smtp_open(struct query *ctl)
         */
        struct idlist   *idp;
        const char *id_me = run.invisible ? ctl->server.truename : fetchmailhost;
-       int oldphase = phase;
+       int oldphase;
        char *parsed_host = NULL;
 
        errno = 0;
@@ -131,7 +120,7 @@ int smtp_open(struct query *ctl)
        for (idp = ctl->smtphunt; idp; idp = idp->next)
        {
            char        *cp;
-           char        *portnum = SMTP_PORT;
+           const char  *portnum = SMTP_PORT;
 
            ctl->smtphost = idp->id;  /* remember last host tried. */
            if (ctl->smtphost[0]=='/')
@@ -262,12 +251,13 @@ char *rcpt_address(struct query *ctl, const char *id,
 }
 
 static int send_bouncemail(struct query *ctl, struct msgblk *msg,
-                          int userclass, char *message /* should have \r\n at the end */,
+                          int userclass, const char *message /* should have \r\n at the end */,
                           int nerrors, char *errors[])
 /* bounce back an error report a la RFC 1892 */
 {
     char daemon_name[15 + HOSTLEN] = "MAILER-DAEMON@";
-    char boundary[BUFSIZ], *bounce_to;
+    char boundary[BUFSIZ];
+    const char *bounce_to;
     int sock;
     static char *fqdn_of_host = NULL;
     const char *md1 = "MAILER-DAEMON", *md2 = "MAILER-DAEMON@";
@@ -440,23 +430,9 @@ static int handle_smtp_report(struct query *ctl, struct msgblk *msg)
 {
     int smtperr = atoi(smtp_response);
     char *responses[1];
-    struct idlist *walk;
-    int found = 0;
 
     responses[0] = xstrdup(smtp_response);
 
-#ifdef __UNUSED__
-    /*
-     * Don't do this!  It can really mess you up if, for example, you're
-     * reporting an error with a single RCPT TO address among several;
-     * RSET discards the message body and it doesn't get sent to the
-     * valid recipients.
-     */
-    smtp_rset(ctl);    /* stay on the safe side */
-    if (outlevel >= O_DEBUG)
-       report(stdout, GT_("Saved error is still %d\n"), smtperr);
-#endif /* __UNUSED */
-
     /*
      * Note: send_bouncemail message strings are not made subject
      * to gettext translation because (a) they're going to be 
@@ -465,15 +441,7 @@ static int handle_smtp_report(struct query *ctl, struct msgblk *msg)
      * messages, which are probably in English (none of the
      * MTAs I know about are internationalized).
      */
-    for( walk = ctl->antispam; walk; walk = walk->next )
-        if ( walk->val.status.num == smtperr ) 
-       { 
-               found=1;
-               break;
-       }
-
-    /* if (str_find(&ctl->antispam, smtperr)) */
-    if ( found )
+    if (str_find(&ctl->antispam, smtperr))
     {
        /*
         * SMTP listener explicitly refuses to deliver mail
@@ -541,12 +509,6 @@ 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.
         */
-#ifdef __DONT_FEED_THE_SPAMMERS__
-       if (run.bouncemail)
-           send_bouncemail(ctl, msg, XMIT_ACCEPT,
-                       "Invalid address in MAIL FROM (SMTP error 553).\r\n", 
-                       1, responses);
-#endif /* __DONT_FEED_THE_SPAMMERS__ */
        free(responses[0]);
        return(PS_REFUSED);
 
@@ -625,10 +587,7 @@ static int handle_smtp_report_without_bounce(struct query *ctl, struct msgblk *m
        return(PS_REFUSED);
 
     case 553: /* invalid sending domain */
-#ifdef __DONT_FEED_THE_SPAMMERS__
-       if (run.bouncemail)
-           return(PS_SUCCESS);
-#endif /* __DONT_FEED_THE_SPAMMERS__ */
+       /* do not send bounce mail - it would feed spammers */
        return(PS_REFUSED);
 
     default:
@@ -648,6 +607,9 @@ int stuffline(struct query *ctl, char *buf)
     int        n, oldphase;
     char *last;
 
+    if (!buf)
+       return -1;
+
     /* The line may contain NUL characters. Find the last char to use
      * -- the real line termination is the sequence "\n\0".
      */
@@ -784,7 +746,7 @@ static int open_bsmtp_sink(struct query *ctl, struct msgblk *msg,
 
     if (fflush(sinkfp) || ferror(sinkfp))
     {
-       report(stderr, GT_("BSMTP preamble write failed.\n"));
+       report(stderr, GT_("BSMTP preamble write failed: %s.\n"), strerror(errno));
        return(PS_BSMTP);
     }
 
@@ -1102,9 +1064,7 @@ static int open_mda_sink(struct query *ctl, struct msgblk *msg,
              int *good_addresses, int *bad_addresses)
 /* open a stream to a local MDA */
 {
-#ifdef HAVE_SETEUID
     uid_t orig_uid;
-#endif /* HAVE_SETEUID */
     struct     idlist *idp;
     int        length = 0, fromlen = 0, nameslen = 0;
     char       *names = NULL, *before, *after, *from = NULL;
@@ -1129,9 +1089,9 @@ static int open_mda_sink(struct query *ctl, struct msgblk *msg,
         */
        nameslen = 0;
        for (idp = msg->recipients; idp; idp = idp->next)
-           if ((idp->val.status.mark == XMIT_ACCEPT))
+           if (idp->val.status.mark == XMIT_ACCEPT)
                nameslen += (strlen(idp->id) + 1);      /* string + ' ' */
-       if ((*good_addresses == 0))
+       if (*good_addresses == 0)
            nameslen = strlen(run.postmaster);
 
        names = (char *)xmalloc(nameslen + 1);  /* account for '\0' */
@@ -1190,6 +1150,16 @@ static int open_mda_sink(struct query *ctl, struct msgblk *msg,
        for (dp = after, sp = before; (*dp = *sp); dp++, sp++) {
            if (sp[0] != '%')   continue;
 
+           if (sp > before && sp[-1] == '\'') {
+               report(stderr, GT_("MDA option contains single-quoted %%%c expansion.\n"), sp[1]);
+               report(stderr, GT_("Refusing to deliver. Check the manual and fix your mda option.\n"));
+               free(before);
+               free(after);
+               if (from) free(from);
+               if (names) free(names);
+               return PS_SYNTAX;
+           }
+
            /* need to expand? BTW, no here overflow, because in
            ** the worst case (end of string) sp[1] == '\0' */
            if (sp[1] == 's' || sp[1] == 'T') {
@@ -1227,7 +1197,6 @@ static int open_mda_sink(struct query *ctl, struct msgblk *msg,
     if (outlevel >= O_DEBUG)
        report(stdout, GT_("about to deliver with: %s\n"), before);
 
-#ifdef HAVE_SETEUID
     /*
      * Arrange to run with user's permissions if we're root.
      * This will initialize the ownership of any files the
@@ -1235,17 +1204,20 @@ static int open_mda_sink(struct query *ctl, struct msgblk *msg,
      * under all BSDs and Linux)
      */
     orig_uid = getuid();
-    seteuid(ctl->uid);
-#endif /* HAVE_SETEUID */
+    if (seteuid(ctl->uid)) {
+       report(stderr, GT_("Cannot switch effective user id to %ld: %s\n"), (long)ctl->uid, strerror(errno));
+       return PS_IOERR;
+    }
 
     sinkfp = popen(before, "w");
     free(before);
     before = NULL;
 
-#ifdef HAVE_SETEUID
     /* this will fail quietly if we didn't start as root */
-    seteuid(orig_uid);
-#endif /* HAVE_SETEUID */
+    if (seteuid(orig_uid)) {
+       report(stderr, GT_("Cannot switch effective user id back to original %ld: %s\n"), (long)orig_uid, strerror(errno));
+       return PS_IOERR;
+    }
 
     if (!sinkfp)
     {
@@ -1269,6 +1241,8 @@ int open_sink(struct query *ctl, struct msgblk *msg,
 {
     *bad_addresses = *good_addresses = 0;
 
+    if (want_progress() && outlevel >= O_VERBOSE && !ctl->mda && !ctl->bsmtp) puts("");
+
     if (ctl->bsmtp)            /* dump to a BSMTP batch file */
        return(open_bsmtp_sink(ctl, msg, good_addresses, bad_addresses));
     /* 
@@ -1276,7 +1250,7 @@ int open_sink(struct query *ctl, struct msgblk *msg,
      * open a socket fails, fall through to attempt delivery via
      * local MDA.
      */
-    else if (!ctl->mda && smtp_open(ctl) != -1)
+    else if (!ctl->mda && smtp_setup(ctl) != -1)
        return(open_smtp_sink(ctl, msg, good_addresses, bad_addresses));
 
     /*
@@ -1347,8 +1321,31 @@ int close_sink(struct query *ctl, struct msgblk *msg, flag forward)
 /* perform end-of-message actions on the current output sink */
 {
     int smtp_err;
-    if (ctl->mda)
-    {
+
+    if (want_progress() && outlevel >= O_VERBOSE && !ctl->mda && !ctl->bsmtp) puts("");
+
+    if (ctl->bsmtp && sinkfp) {
+       int error, oerrno;
+
+       /* implicit disk-full check here... */
+       fputs(".\r\n", sinkfp);
+       error = ferror(sinkfp);
+       oerrno = errno;
+       if (strcmp(ctl->bsmtp, "-"))
+       {
+           if (fclose(sinkfp) == EOF) {
+               error = 1;
+               oerrno = errno;
+           }
+           sinkfp = (FILE *)NULL;
+       }
+       if (error)
+       {
+           report(stderr, 
+                  GT_("Message termination or close of BSMTP file failed: %s\n"), strerror(oerrno));
+           return(FALSE);
+       }
+    } else if (ctl->mda) {
        int rc = 0, e = 0, e2 = 0, err = 0;
 
        /* close the delivery pipe, we'll reopen before next message */
@@ -1364,8 +1361,6 @@ int close_sink(struct query *ctl, struct msgblk *msg, flag forward)
            e = errno;
            sinkfp = (FILE *)NULL;
        }
-       else
-           rc = e = 0;
 
        deal_with_sigchld(); /* Restore SIGCHLD handling to reap zombies */
 
@@ -1388,25 +1383,6 @@ int close_sink(struct query *ctl, struct msgblk *msg, flag forward)
            return(FALSE);
        }
     }
-    else if (ctl->bsmtp && sinkfp)
-    {
-       int error;
-
-       /* implicit disk-full check here... */
-       fputs(".\r\n", sinkfp);
-       error = ferror(sinkfp);
-       if (strcmp(ctl->bsmtp, "-"))
-       {
-           if (fclose(sinkfp) == EOF) error = 1;
-           sinkfp = (FILE *)NULL;
-       }
-       if (error)
-       {
-           report(stderr, 
-                  GT_("Message termination or close of BSMTP file failed\n"));
-           return(FALSE);
-       }
-    }
     else if (forward)
     {
        /* write message terminator */
@@ -1572,15 +1548,7 @@ int open_warning_by_mail(struct query *ctl)
 /* if rfc2047charset is non-NULL, encode the line (that is assumed to be
  * a header line) as per RFC-2047 using rfc2047charset as the character
  * set field */
-#if defined(HAVE_STDARG_H)
 void stuff_warning(const char *rfc2047charset, struct query *ctl, const char *fmt, ... )
-#else
-void stuff_warning(rfc2047charset, ctl, fmt, va_alist)
-const char *charset;
-struct query *ctl;
-const char *fmt;       /* printf-style format */
-va_dcl
-#endif
 {
     /* make huge -- i18n can bulk up error messages a lot */
     char       buf[2*MSGBUFSIZE+4];
@@ -1592,11 +1560,7 @@ va_dcl
      * case it was a string constant.  We make a virtue of that necessity
      * here by supporting stdargs/varargs.
      */
-#if defined(HAVE_STDARG_H)
     va_start(ap, fmt) ;
-#else
-    va_start(ap);
-#endif
     vsnprintf(buf, sizeof(buf) - 2, fmt, ap);
     va_end(ap);
 
@@ -1617,4 +1581,18 @@ void close_warning_by_mail(struct query *ctl, struct msgblk *msg)
     close_sink(ctl, msg, TRUE);
 }
 
+void abort_message_sink(struct query *ctl)
+/*
+ * Forcibly close the SMTP connection and re-open.
+ *
+ * Used to abort message delivery once the DATA command has been issued.
+ * Required because all text after the DATA command is considered to be
+ * part of the message body (it is impossible to issue an SMTP command
+ * to abort message delivery once the DATA command has been issued).
+ */
+{
+  smtp_close(ctl, 0);
+  smtp_setup(ctl);
+}
+
 /* sink.c ends here */