]> Pileus Git - ~andy/fetchmail/blobdiff - transact.c
Better skip handling.
[~andy/fetchmail] / transact.c
index 73c133f707527bff04762f675b3dea5ef02bec49..a5e40cbc411239c035c11dc7b87324305ba09f5c 100644 (file)
@@ -10,6 +10,7 @@
 #include  "config.h"
 #include  <stdio.h>
 #include  <string.h>
+#include  <ctype.h> /* isspace() */
 #ifdef HAVE_MEMORY_H
 #include  <memory.h>
 #endif /* HAVE_MEMORY_H */
@@ -387,6 +388,7 @@ int readheaders(int sock,
     for (remaining = fetchlen; remaining > 0 || protocol->delimited; remaining -= linelen)
     {
        char *line;
+       int overlong = FALSE;
 
        line = xmalloc(sizeof(buf));
        linelen = 0;
@@ -404,6 +406,19 @@ int readheaders(int sock,
            linelen += n;
            msgblk.msglen += n;
 
+               /*
+                * Try to gracefully handle the case, where the length of a
+                * line exceeds MSGBUFSIZE.
+                */
+               if ( n && buf[n-1] != '\n' ) {
+                       unsigned int llen = strlen(line);
+                       overlong = TRUE;
+                       line = realloc(line, llen + n + 1);
+                       strcpy(line + llen, buf);
+                       ch = ' '; /* So the next iteration starts */
+                       continue;
+               }
+
            /* lines may not be properly CRLF terminated; fix this for qmail */
            if (ctl->forcecr)
            {
@@ -416,17 +431,27 @@ int readheaders(int sock,
                }
            }
 
-           /*
-            * Decode MIME encoded headers. We MUST do this before
-            * looking at the Content-Type / Content-Transfer-Encoding
-            * headers (RFC 2046).
-            */
-           if (ctl->mimedecode)
-               UnMimeHeader(buf);
-
-           line = (char *) realloc(line, strlen(line) + strlen(buf) +1);
+               /*
+                * Decode MIME encoded headers. We MUST do this before
+                * looking at the Content-Type / Content-Transfer-Encoding
+                * headers (RFC 2046).
+                */
+               if ( ctl->mimedecode && overlong ) {
+                       /*
+                        * If we received an overlong line, we have to decode the
+                        * whole line at once.
+                        */
+                       line = (char *) realloc(line, strlen(line) + strlen(buf) +1);
+                       strcat(line, buf);
+                       UnMimeHeader(line);
+               }
+               else {
+                       if ( ctl->mimedecode )
+                               UnMimeHeader(buf);
 
-           strcat(line, buf);
+                       line = (char *) realloc(line, strlen(line) + strlen(buf) +1);
+                       strcat(line, buf);
+               }
 
            /* check for end of headers */
            if (EMPTYLINE(line))
@@ -444,8 +469,8 @@ int readheaders(int sock,
             */
            if (protocol->delimited && line[0] == '.' && EMPTYLINE(line+1))
            {
-               free(line);
                has_nuls = (linelen != strlen(line));
+               free(line);
                goto process_headers;
            }
 
@@ -772,14 +797,14 @@ int readheaders(int sock,
                                                line,
                                                strlen(ctl->server.envelope)))
                {                               
-                   if (skipcount++ != ctl->server.envskip)
+                   if (skipcount++ < ctl->server.envskip)
                        continue;
                    env_offs = (line - msgblk.headers);
                }    
            }
            else if (!received_for && !strncasecmp("Received:", line, 9))
            {
-               if (skipcount++ != ctl->server.envskip)
+               if (skipcount++ < ctl->server.envskip)
                    continue;
                received_for = parse_received(ctl, line);
            }
@@ -990,14 +1015,24 @@ int readheaders(int sock,
     {
        /* utter any per-message Received information we need here */
         if (ctl->server.trueaddr) {
-           sprintf(buf, "Received: from %s [%u.%u.%u.%u]\r\n", 
+#ifdef HAVE_SNPRINTF
+           snprintf(buf, sizeof(buf),
+#else
+           sprintf(buf, 
+#endif /* HAVE_SNPRINTF */
+                   "Received: from %s [%u.%u.%u.%u]\r\n", 
                    ctl->server.truename,
                    (unsigned char)ctl->server.trueaddr[0],
                    (unsigned char)ctl->server.trueaddr[1],
                    (unsigned char)ctl->server.trueaddr[2],
                    (unsigned char)ctl->server.trueaddr[3]);
        } else {
-         sprintf(buf, "Received: from %s\r\n", ctl->server.truename);
+#ifdef HAVE_SNPRINTF
+         snprintf(buf, sizeof(buf),
+#else                       
+         sprintf(buf,
+#endif /* HAVE_SNPRINTF */
+                 "Received: from %s\r\n", ctl->server.truename);
        }
        n = stuffline(ctl, buf);
        if (n != -1)
@@ -1006,7 +1041,12 @@ int readheaders(int sock,
             * This header is technically invalid under RFC822.
             * POP3, IMAP, etc. are not legal mail-parameter values.
             */
-           sprintf(buf, "\tby %s with %s (fetchmail-%s)",
+#ifdef HAVE_SNPRINTF
+           snprintf(buf, sizeof(buf),
+#else
+           sprintf(buf,
+#endif /* HAVE_SNPRINTF */
+                   "\tby %s with %s (fetchmail-%s",
                    fetchmailhost,
                    protocol->name,
                    VERSION);
@@ -1016,14 +1056,22 @@ int readheaders(int sock,
                        ctl->server.pollname, 
                        ctl->remotename);
            }
-           strcat(buf, "\r\n");
+#ifdef HAVE_SNPRINTF
+           snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), ")\r\n");
+#else
+           strcat(buf, ")\r\n");
+#endif /* HAVE_SNPRINTF */
            n = stuffline(ctl, buf);
            if (n != -1)
            {
                buf[0] = '\t';
                if (good_addresses == 0)
                {
-                   sprintf(buf+1, 
+#ifdef HAVE_SNPRINTF
+                   snprintf(buf+1, sizeof(buf)-1,
+#else
+                   sprintf(buf+1,
+#endif /* HAVE_SNPRINTF */
                            "for %s@%s (by default); ",
                            user, ctl->destaddr);
                }
@@ -1033,22 +1081,37 @@ int readheaders(int sock,
                        if (idp->val.status.mark == XMIT_ACCEPT)
                            break;      /* only report first address */
                    if (strchr(idp->id, '@'))
-                       sprintf(buf+1, "for %s", idp->id);
+#ifdef HAVE_SNPRINTF
+                   snprintf(buf+1, sizeof(buf)-1,
+#else                       
+                   sprintf(buf+1,
+#endif /* HAVE_SNPRINTF */
+                           "for %s", idp->id);
                    else
                        /*
                         * This could be a bit misleading, as destaddr is
                         * the forwarding host rather than the actual 
                         * destination.  Most of the time they coincide.
                         */
-                       sprintf(buf+1, "for %s@%s", idp->id, ctl->destaddr);
+#ifdef HAVE_SNPRINTF
+                       snprintf(buf+1, sizeof(buf)-1,
+#else                       
+                       sprintf(buf+1,
+#endif /* HAVE_SNPRINTF */
+                               "for %s@%s", idp->id, ctl->destaddr);
                    sprintf(buf+strlen(buf), " (%s); ",
                            MULTIDROP(ctl) ? "multi-drop" : "single-drop");
                }
                else
                    buf[1] = '\0';
 
+#ifdef HAVE_SNPRINTF
+               snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s\r\n",
+                       rfc822timestamp());
+#else
                strcat(buf, rfc822timestamp());
                strcat(buf, "\r\n");
+#endif /* HAVE_SNPRINTF */
                n = stuffline(ctl, buf);
            }
        }
@@ -1283,7 +1346,11 @@ va_dcl
 #endif
     va_end(ap);
 
+#ifdef HAVE_SNPRINTF
+    snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "\r\n");
+#else
     strcat(buf, "\r\n");
+#endif /* HAVE_SNPRINTF */
     SockWrite(sock, buf, strlen(buf));
 
     if (outlevel >= O_MONITOR)
@@ -1369,7 +1436,11 @@ va_dcl
 #endif
     va_end(ap);
 
+#ifdef HAVE_SNPRINTF
+    snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "\r\n");
+#else
     strcat(buf, "\r\n");
+#endif /* HAVE_SNPRINTF */
     SockWrite(sock, buf, strlen(buf));
 
     if (outlevel >= O_MONITOR)