]> Pileus Git - ~andy/fetchmail/blobdiff - driver.c
Updated.
[~andy/fetchmail] / driver.c
index 0e4d099710e1f59051742a539bcb6a42e20339e5..317e75949a5416a25b6f58ccedd08733f518f543 100644 (file)
--- a/driver.c
+++ b/driver.c
 #endif
 #if defined(HAVE_ALLOCA_H)
 #include <alloca.h>
+#else
+#ifdef _AIX
+ #pragma alloca
+#endif
 #endif
 #if defined(HAVE_SYS_ITIMER_H)
 #include <sys/itimer.h>
@@ -45,7 +49,7 @@
 #include <krb.h>
 #define krb_get_err_text(e) (krb_err_txt[e])
 #else
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) || defined(__linux__)
 #define krb_get_err_text(e) (krb_err_txt[e])
 #include <krb.h>
 #include <des.h>
@@ -68,7 +72,9 @@
 
 #define        SMTP_PORT       25      /* standard SMTP service port */
 
+#ifndef strstr         /* glibc-2.1 declares this as a macro */
 extern char *strstr(); /* needed on sysV68 R3V7.1. */
+#endif /* strstr */
 
 int fetchlimit;                /* how often to tear down the server connection */
 int batchcount;                /* count of messages sent in current batch */
@@ -350,6 +356,9 @@ static char *parse_received(struct query *ctl, char *bufp)
            sp = ok + 4;
            if (*sp == '<')
                sp++;
+           while (*sp == '@')          /* skip routes */
+               while (*sp++ != ':')
+                   continue;
            while (*sp && *sp != '>' && *sp != '@' && *sp != ';')
                if (!isspace(*sp))
                    *tp++ = *sp++;
@@ -390,9 +399,10 @@ static int smtp_open(struct query *ctl)
     {
        /* 
         * RFC 1123 requires that the domain name in HELO address is a
-        * "valid principal domain name" for the client host.  We
-        * violate this with malice aforethought in order to make the
-        * Received headers and logging look right.
+        * "valid principal domain name" for the client host. If we're
+        * running in invisible mode, violate this with malice
+        * aforethought in order to make the Received headers and
+        * logging look right.
         *
         * In fact this code relies on the RFC1123 requirement that the
         * SMTP listener must accept messages even if verification of the
@@ -406,10 +416,15 @@ static int smtp_open(struct query *ctl)
         * What it will affect is the listener's logging.
         */
        struct idlist   *idp;
+       char *id_me = use_invisible ? ctl->server.truename : fetchmailhost;
 
        errno = 0;
 
-       /* run down the SMTP hunt list looking for a server that's up */
+       /*
+        * Run down the SMTP hunt list looking for a server that's up.
+        * Use both explicit hunt entries (value TRUE) and implicit 
+        * (default) ones (value FALSE).
+        */
        for (idp = ctl->smtphunt; idp; idp = idp->next)
        {
            ctl->smtphost = idp->id;  /* remember last host tried. */
@@ -418,8 +433,7 @@ static int smtp_open(struct query *ctl)
                continue;
 
            if (SMTP_ok(ctl->smtp_socket) == SM_OK &&
-                   SMTP_ehlo(ctl->smtp_socket, 
-                         ctl->server.truename,
+                   SMTP_ehlo(ctl->smtp_socket, id_me,
                          &ctl->server.esmtp_options) == SM_OK)
               break;  /* success */
 
@@ -435,7 +449,7 @@ static int smtp_open(struct query *ctl)
                continue;
 
            if (SMTP_ok(ctl->smtp_socket) == SM_OK && 
-                   SMTP_helo(ctl->smtp_socket, ctl->server.truename) == SM_OK)
+                   SMTP_helo(ctl->smtp_socket, id_me) == SM_OK)
                break;  /* success */
 
            close(ctl->smtp_socket);
@@ -485,7 +499,7 @@ static int stuffline(struct query *ctl, char *buf)
            else
                /* writing to SMTP, leave the byte-stuffing in place */;
        }
-        else /* if (!protocol->delimited)      /* not byte-stuffed already */
+        else /* if (!protocol->delimited)      -- not byte-stuffed already */
        {
            if (!ctl->mda)
                SockWrite(ctl->smtp_socket, buf, 1);    /* byte-stuff it */
@@ -529,7 +543,7 @@ int num;            /* index of message */
     char buf[MSGBUFSIZE+1], return_path[MSGBUFSIZE+1]; 
     int        from_offs, ctt_offs, env_offs, next_address;
     char *headers, *received_for, *desthost, *rcv;
-    int n, linelen, oldlen, ch, remaining;
+    int n, linelen, oldlen, ch, remaining, skipcount;
     char               *cp;
     struct idlist      *idp, *xmit_names;
     flag                       good_addresses, bad_addresses, has_nuls;
@@ -548,6 +562,7 @@ int num;            /* index of message */
     from_offs = ctt_offs = env_offs = -1;
     oldlen = 0;
     msglen = 0;
+    skipcount = 0;
 
     for (remaining = fetchlen; remaining > 0 || protocol->delimited; remaining -= linelen)
     {
@@ -736,9 +751,11 @@ int num;           /* index of message */
        {
            if( ctl->server.uidl )
            {
-               char id[IDLEN+1];
+               char id[IDLEN+1];
+               /* prevent stack overflows */
+               buf[IDLEN+12] = 0;
                sscanf( buf+12, "%s", id);
-               if( !str_in_list( &ctl->newsaved, id ) )
+               if( !str_find( &ctl->newsaved, num ) )
                    save_str(&ctl->newsaved, num, id );
            }
        }
@@ -764,11 +781,19 @@ int num;          /* index of message */
                if (env_offs == -1 && !strncasecmp(ctl->server.envelope,
                                                line,
                                                strlen(ctl->server.envelope)))
+               {                               
+                   if (skipcount++ != ctl->server.envskip)
+                       continue;
                    env_offs = (line - headers);
+               }    
            }
 #ifdef HAVE_RES_SEARCH
            else if (!received_for && !strncasecmp("Received:", line, 9))
+           {
+               if (skipcount++ != ctl->server.envskip)
+                   continue;
                received_for = parse_received(ctl, line);
+           }
 #endif /* HAVE_RES_SEARCH */
        }
     }
@@ -817,8 +842,6 @@ int num;            /* index of message */
            map_name(received_for, ctl, &xmit_names);
        else
        {
-           int i;
-
            /*
             * We haven't extracted the envelope address.
             * So check all the header addresses.
@@ -870,15 +893,22 @@ int num;          /* index of message */
        desthost = "localhost";
 
        length = strlen(ctl->mda) + 1;
-       before = strdup(ctl->mda);
+       before = xstrdup(ctl->mda);
 
        /* sub user addresses for %T (or %s for backward compatibility) */
        cp = (char *)NULL;
        if (strstr(before, "%s") || (cp = strstr(before, "%T")))
        {
+           char        *sp;
+
            if (cp && cp[1] == 'T')
                cp[1] = 's';
 
+           /* \177 had better be out-of-band for MDA commands */
+           for (sp = before; *sp; sp++)
+               if (*sp == '%' && sp[1] != 's' && sp[1] != 'T')
+                   *sp = '\177';
+
            /*
             * We go through this in order to be able to handle very
             * long lists of users and (re)implement %s.
@@ -903,12 +933,22 @@ int num;          /* index of message */
 #endif /* SNPRINTF */
            free(before);
            before = after;
+
+           for (sp = before; *sp; sp++)
+               if (*sp == '\177')
+                   *sp = '%';
        }
 
        /* substitute From address for %F */
        if ((cp = strstr(before, "%F")))
        {
            char *from = nxtaddr(headers + from_offs);
+           char        *sp;
+
+           /* \177 had better be out-of-band for MDA commands */
+           for (sp = before; *sp; sp++)
+               if (*sp == '%' && sp[1] != 'F')
+                   *sp = '\177';
 
            length += strlen(from);
            after = alloca(length);
@@ -920,6 +960,10 @@ int num;           /* index of message */
 #endif /* SNPRINTF */
            free(before);
            before = after;
+
+           for (sp = before; *sp; sp++)
+               if (*sp == '\177')
+                   *sp = '%';
        }
 
        if (outlevel == O_VERBOSE)
@@ -1134,14 +1178,14 @@ int num;                /* index of message */
        n = stuffline(ctl, headers);
        *rcv = 'R';
     }
-    if (n != -1)
+    if (!use_invisible && n != -1)
     {
        /* utter any per-message Received information we need here */
        sprintf(buf, "Received: from %s\n", ctl->server.truename);
        n = stuffline(ctl, buf);
        if (n != -1)
        {
-           sprintf(buf, "\tby %s (fetchmail-%s %s run by %s)\n",
+           sprintf(buf, "\tby %s (fetchmail-%s %s run for %s)\n",
                    fetchmailhost, 
                    RELEASE_ID,
                    protocol->name,
@@ -1173,12 +1217,13 @@ int num;                /* index of message */
                time(&now);
                strcat(buf, ctime(&now));
                n = stuffline(ctl, buf);
-               if (n != -1)
-                   n = stuffline(ctl, rcv);    /* ship out rest of headers */
            }
        }
     }
 
+    if (n != -1)
+       n = stuffline(ctl, rcv);        /* ship out rest of headers */
+
     if (n == -1)
     {
        error(0, errno, "writing RFC822 headers");
@@ -1275,7 +1320,7 @@ int len;          /* length of message */
 flag forward;          /* TRUE to forward */
 {
     int        linelen;
-    char buf[MSGBUFSIZE+1], *cp;
+    char buf[MSGBUFSIZE+1];
 
     /* pass through the text lines */
     while (protocol->delimited || len > 0)
@@ -1382,8 +1427,8 @@ int do_protocol(ctl, proto)
 struct query *ctl;             /* parsed options with merged-in defaults */
 const struct method *proto;    /* protocol method table */
 {
-    int ok, js, pst, sock = -1;
-    char *msg, *cp;
+    int ok, js, sock = -1;
+    char *msg;
     void (*sigsave)();
 
 #ifndef KERBEROS_V4
@@ -1424,7 +1469,6 @@ const struct method *proto;       /* protocol method table */
     tagnum = 0;
     tag[0] = '\0';     /* nuke any tag hanging out from previous query */
     ok = 0;
-    error_init(poll_interval == 0 && !logfile);
 
     /* set up the server-nonresponse timeout */
     sigsave = signal(SIGALRM, timeout_handler);
@@ -1443,9 +1487,9 @@ const struct method *proto;       /* protocol method table */
     }
     else
     {
-       char buf [POPBUFSIZE+1], *sp, *realhost;
+       char buf [POPBUFSIZE+1], *realhost;
        int *msgsizes, len, num, count, new, deletions = 0;
-       int port, fetches;
+       int port, fetches, dispatches;
        struct idlist *idp;
 
        /* execute pre-initialization command, if any */
@@ -1532,12 +1576,14 @@ const struct method *proto;     /* protocol method table */
        /* now iterate over each folder selected */
        for (idp = ctl->mailboxes; idp; idp = idp->next)
        {
+           pass = 0;
            do {
+               dispatches = 0;
                ++pass;
 
                if (outlevel >= O_VERBOSE)
-                   if (idp->next)
-                       error(0, 0, "selecting or re-polling folder %s");
+                   if (idp->id)
+                       error(0, 0, "selecting or re-polling folder %s", idp->id);
                    else
                        error(0, 0, "selecting or re-polling default folder");
 
@@ -1549,27 +1595,27 @@ const struct method *proto;     /* protocol method table */
 
                /* show user how many messages we downloaded */
                if (idp->id)
-                   (void) sprintf(buf, "%s@%s:%s",
+                   (void) sprintf(buf, "%s at %s (folder %s)",
                                   ctl->remotename, ctl->server.truename, idp->id);
                else
-                   (void) sprintf(buf, "%s@%s", ctl->remotename, ctl->server.truename);
+                   (void) sprintf(buf, "%s at %s", ctl->remotename, ctl->server.truename);
                if (outlevel > O_SILENT)
                    if (count == -1)            /* only used for ETRN */
                        error(0, 0, "Polling %s", ctl->server.truename);
                    else if (count != 0)
                    {
                        if (new != -1 && (count - new) > 0)
-                           error(0, 0, "%d message%s (%d seen) at %s.",
+                           error(0, 0, "%d message%s (%d seen) for %s.",
                                  count, count > 1 ? "s" : "", count-new, buf);
                        else
-                           error(0, 0, "%d message%s at %s.", 
+                           error(0, 0, "%d message%s for %s.", 
                                  count, count > 1 ? "s" : "", buf);
                    }
                    else
                    {
                        /* these are pointless in normal daemon mode */
                        if (pass == 1 && (poll_interval == 0 || outlevel == O_VERBOSE))
-                           error(0, 0, "No mail at %s", buf); 
+                           error(0, 0, "No mail for %s", buf); 
                    }
 
                /* very important, this is where we leave the do loop */ 
@@ -1775,6 +1821,10 @@ const struct method *proto;      /* protocol method table */
                                }
                            }
 
+                           /* count # messages forwarded on this pass */
+                           if (!suppress_forward)
+                               dispatches++;
+
                            /*
                             * Check to see if the numbers matched?
                             *
@@ -1862,7 +1912,9 @@ const struct method *proto;       /* protocol method table */
                            if (ok != 0)
                                goto cleanUp;
                            set_timeout(ctl->server.timeout);
+#ifdef POP3_ENABLE
                            delete_str(&ctl->newsaved, num);
+#endif /* POP3_ENABLE */
                        }
                        else if (outlevel > O_SILENT) 
                            error_complete(0, 0, " not flushed");
@@ -1874,15 +1926,20 @@ const struct method *proto;     /* protocol method table */
                }
            } while
                  /*
-                  * Only re-poll if we allowed deletions and had no errors.
+                  * Only re-poll if we had some actual forwards, allowed
+                  * deletions and had no errors.
                   * Otherwise it is far too easy to get into infinite loops.
                   */
-                 (protocol->retry && !ctl->keep && !ctl->errcount);
+                 (dispatches && protocol->retry && !ctl->keep && !ctl->errcount);
        }
 
    no_error:
        set_timeout(ctl->server.timeout);
        ok = (protocol->logout_cmd)(sock, ctl);
+       /*
+        * Hmmmm...arguably this would be incorrect if we had fetches but
+        * no dispatches (due to oversized messages, etc.)
+        */
        if (ok == 0)
            ok = (fetches > 0) ? PS_SUCCESS : PS_NOMAIL;
        set_timeout(0);
@@ -1953,7 +2010,7 @@ closeUp:
 }
 
 #if defined(HAVE_STDARG_H)
-void gen_send(int sock, char *fmt, ... )
+void gen_send(int sock, const char *fmt, ... )
 /* assemble command in printf(3) style and send to the server */
 #else
 void gen_send(sock, fmt, va_alist)