]> Pileus Git - ~andy/fetchmail/blobdiff - rfc822.c
Ready for the UIDL patch.
[~andy/fetchmail] / rfc822.c
index 94b60c7f3a68df8429c435e60b7db1806058c5b4..f7a74212553a62eb5556b39218bb9592dde91a2e 100644 (file)
--- a/rfc822.c
+++ b/rfc822.c
 
 #define HEADER_END(p)  ((p)[0] == '\n' && ((p)[1] != ' ' && (p)[1] != '\t'))
 
+#ifdef TESTMAIN
+static int verbose;
+#endif /* TESTMAIN */
+
 void reply_hack(buf, host)
 /* hack message headers so replies will work properly */
 char *buf;             /* header to be hacked */
 const char *host;      /* server hostname */
 {
-    const char *from;
+    char *from, *cp;
     int parendepth, state, has_host_part;
-    char mycopy[MSGBUFSIZE+1];
 
     if (strncmp("From: ", buf, 6)
        && strncmp("To: ", buf, 4)
@@ -34,65 +37,78 @@ const char *host;   /* server hostname */
        return;
     }
 
-    strcpy(mycopy, buf);
     parendepth = state = 0;
     has_host_part = FALSE;
-    for (from = mycopy; *from; from++)
+    for (from = buf; *from; from++)
     {
 #ifdef TESTMAIN
-       printf("state %d: %s", state, mycopy);
-       printf("%*s^\n", from - mycopy + 10, " ");
+       if (verbose)
+       {
+           printf("state %d: %s", state, buf);
+           printf("%*s^\n", from - buf + 10, " ");
+       }
 #endif /* TESTMAIN */
-       if (*from == '(')
-           ++parendepth;
-       else if (*from == ')')
-           --parendepth;
+       if (state != 2)
+           if (*from == '(')
+               ++parendepth;
+           else if (*from == ')')
+               --parendepth;
 
        if (!parendepth && !has_host_part)
            switch (state)
            {
-           case 0:   /* before header colon */
+           case 0:     /* before header colon */
                if (*from == ':')
                    state = 1;
                break;
 
-           case 1:   /* we've seen the colon, we're looking for addresses */
+           case 1:     /* we've seen the colon, we're looking for addresses */
                if (*from == '<')
-                   state = 2;
+                   state = 3;
                else if (*from == '@')
                    has_host_part = TRUE;
+               else if (*from == '"')
+                   state = 2;
                else if ((*from == ',' || HEADER_END(from)) && !has_host_part)
                {
+                   int hostlen;
+
                    while (isspace(*from))
                        --from;
                    from++;
-                   while (isspace(*buf))
-                       --buf;
-                   buf++;
-                   strcpy(buf, "@");
-                   strcat(buf, host);
-                   buf += strlen(buf);
+                   hostlen = strlen(host);
+                   for (cp = from + strlen(from); cp >= from; --cp)
+                       cp[hostlen+1] = *cp;
+                   *from++ = '@';
+                   memcpy(from, host, hostlen);
+                   from += strlen(from);
+                   has_host_part = TRUE;
                }
                break;
 
-           case 2:   /* we're in a <>-enclosed address */
+           case 2:     /* we're in a string */
+               if (*from == '"')
+                   state = 1;
+               break;
+
+           case 3:     /* we're in a <>-enclosed address */
                if (*from == '@')
                    has_host_part = TRUE;
                else if (*from == '>' && !has_host_part)
                {
-                   strcpy(buf, "@");
-                   strcat(buf, host);
-                   buf += strlen(buf);
+                   int hostlen;
+
+                   hostlen = strlen(host);
+                   for (cp = from + strlen(from); cp >= from; --cp)
+                       cp[hostlen+1] = *cp;
+                   *from++ = '@';
+                   memcpy(from, host, hostlen);
+                   from += strlen(from);
                    has_host_part = TRUE;
                }
                break;
            }
-
-       /* all characters from the old buffer get copied to the new one */
-       *buf++ = *from;
     }
-
-    *buf = '\0';
 }
 
 char *nxtaddr(hdr)
@@ -102,6 +118,9 @@ const char *hdr;    /* header to be parsed, NUL to continue previous hdr */
     static char *tp, address[POPBUFSIZE+1];
     static const char *hp;
     static int state, oldstate;
+#ifdef TESTMAIN
+    static const char *orighdr;
+#endif /* TESTMAIN */
     int parendepth;
 
 #define START_HDR      0       /* before header colon */
@@ -116,19 +135,43 @@ const char *hdr;  /* header to be parsed, NUL to continue previous hdr */
     {
        hp = hdr;
        state = START_HDR;
+#ifdef TESTMAIN
+       orighdr = hdr;
+#endif /* TESTMAIN */
     }
 
     for (; *hp; hp++)
     {
-       switch (state)
+#ifdef TESTMAIN
+       if (verbose)
        {
-       case START_HDR:   /* before header colon */
-           if (HEADER_END(hp))
+           printf("state %d: %s", state, orighdr);
+           printf("%*s^\n", hp - orighdr + 10, " ");
+       }
+#endif /* TESTMAIN */
+
+       if (state == ENDIT_ALL)         /* after last address */
+           return(NULL);
+       else if (HEADER_END(hp))
+       {
+           state = ENDIT_ALL;
+           while (isspace(*--tp))
+               continue;
+           *++tp = '\0';
+           return(tp > address ? (tp = address) : (char *)NULL);
+       }
+       else if (*hp == '\\')           /* handle RFC822 escaping */
+       {
+           if (state != INSIDE_PARENS)
            {
-               state = ENDIT_ALL;
-               return(NULL);
+               *tp++ = *hp++;                  /* take the escape */
+               *tp++ = *hp;                    /* take following char */
            }
-           else if (*hp == ':')
+       }
+       else switch (state)
+       {
+       case START_HDR:   /* before header colon */
+           if (*hp == ':')
            {
                state = SKIP_JUNK;
                tp = address;
@@ -136,17 +179,7 @@ const char *hdr;   /* header to be parsed, NUL to continue previous hdr */
            break;
 
        case SKIP_JUNK:         /* looking for address start */
-           if (HEADER_END(hp))         /* no more addresses */
-           {
-               state = ENDIT_ALL;
-               return(NULL);
-           }
-           else if (*hp == '\\')       /* handle RFC822 escaping */
-           {
-               *tp++ = *hp++;                  /* take the escape */
-               *tp++ = *hp;                    /* take following char */
-           }
-           else if (*hp == '"')        /* quoted string */
+           if (*hp == '"')     /* quoted string */
            {
                oldstate = SKIP_JUNK;
                state = INSIDE_DQUOTE;
@@ -162,7 +195,7 @@ const char *hdr;    /* header to be parsed, NUL to continue previous hdr */
                state = INSIDE_BRACKETS;
                tp = address;
            }
-           else if (!isspace(*hp))     /* ignore space */
+           else if (*hp != ',' && !isspace(*hp))
            {
                --hp;
                state = BARE_ADDRESS;
@@ -170,23 +203,7 @@ const char *hdr;   /* header to be parsed, NUL to continue previous hdr */
            break;
 
        case BARE_ADDRESS:      /* collecting address without delimiters */
-           if (HEADER_END(hp))         /* end of bare address */
-           {
-               if (tp > address)
-               {
-                   while (isspace(*--tp))
-                       continue;
-                   *++tp = '\0';
-                   state = ENDIT_ALL;
-                   return(tp = address);
-               }
-           }
-           else if (*hp == '\\')       /* handle RFC822 escaping */
-           {
-               *tp++ = *hp++;                  /* take the escape */
-               *tp++ = *hp;                    /* take following char */
-           }
-           else if (*hp == ',')        /* end of address */
+           if (*hp == ',')     /* end of address */
            {
                if (tp > address)
                {
@@ -195,27 +212,22 @@ const char *hdr;  /* header to be parsed, NUL to continue previous hdr */
                    return(tp = address);
                }
            }
+           else if (*hp == '(')        /* beginning of comment */
+           {
+               parendepth = 1;
+               state = INSIDE_PARENS;    
+           }
            else if (*hp == '<')        /* beginning of real address */
            {
                state = INSIDE_BRACKETS;
                tp = address;
            }
-           else                /* just take it */
+           else if (!isspace(*hp))     /* just take it, ignoring whitespace */
                *tp++ = *hp;
            break;
 
        case INSIDE_DQUOTE:     /* we're in a quoted string, copy verbatim */
-           if (HEADER_END(hp))         /* premature end of string */
-           {
-               state = ENDIT_ALL;
-               return(NULL);
-           }
-           else if (*hp == '\\')       /* handle RFC822 escaping */
-           {
-               *tp++ = *hp++;                  /* take the escape */
-               *tp++ = *hp;                    /* take following char */
-           }
-           else if (*hp != '"')
+           if (*hp != '"')
                *tp++ = *hp;
            else
            {
@@ -225,17 +237,7 @@ const char *hdr;   /* header to be parsed, NUL to continue previous hdr */
            break;
 
        case INSIDE_PARENS:     /* we're in a parenthesized comment, ignore */
-           if (HEADER_END(hp))         /* end of line, just bomb out */
-           {
-               state = ENDIT_ALL;
-               return(NULL);
-           }
-           else if (*hp == '\\')       /* handle RFC822 escaping */
-           {
-               *tp++ = *hp++;                  /* take the escape */
-               *tp++ = *hp;                    /* take following char */
-           }
-           else if (*hp == '(')
+           if (*hp == '(')
                ++parendepth;
            else if (*hp == ')')
                --parendepth;
@@ -244,17 +246,7 @@ const char *hdr;   /* header to be parsed, NUL to continue previous hdr */
            break;
 
        case INSIDE_BRACKETS:   /* possible <>-enclosed address */
-           if (HEADER_END(hp))         /* end of line, just bomb out */
-           {
-               state = ENDIT_ALL;
-               return(NULL);
-           }
-           else if (*hp == '\\')       /* handle RFC822 escaping */
-           {
-               *tp++ = *hp++;                  /* take the escape */
-               *tp++ = *hp;                    /* take following char */
-           }
-           else if (*hp == '>')        /* end of address */
+           if (*hp == '>')     /* end of address */
            {
                *tp++ = '\0';
                state = SKIP_JUNK;
@@ -272,10 +264,6 @@ const char *hdr;   /* header to be parsed, NUL to continue previous hdr */
            else                        /* just copy address */
                *tp++ = *hp;
            break;
-
-       case ENDIT_ALL:         /* after last address */
-           return(NULL);
-           break;
        }
     }
 
@@ -283,35 +271,66 @@ const char *hdr;  /* header to be parsed, NUL to continue previous hdr */
 }
 
 #ifdef TESTMAIN
+static void parsebuf(char *longbuf, int reply)
+{
+    char       *cp;
+
+    if (reply)
+    {
+       reply_hack(longbuf, "HOSTNAME.NET");
+       printf("Rewritten buffer: %s", longbuf);
+    }
+    else
+       if ((cp = nxtaddr(longbuf)) != (char *)NULL)
+           do {
+               printf("\t-> \"%s\"\n", cp);
+           } while
+               ((cp = nxtaddr((char *)NULL)) != (char *)NULL);
+}
+
+
+
 main(int argc, char *argv[])
 {
-    char       buf[MSGBUFSIZE], *cp;
-    int                reply =  (argc > 1 && !strcmp(argv[1], "-r"));
+    char       buf[MSGBUFSIZE], longbuf[BUFSIZ];
+    int                ch, reply;
+    
+    verbose = reply = FALSE;
+    while ((ch = getopt(argc, argv, "rv")) != EOF)
+       switch(ch)
+       {
+       case 'r':
+           reply = TRUE;
+           break;
+
+       case 'v':
+           verbose = TRUE;
+           break;
+       }
 
     while (fgets(buf, sizeof(buf)-1, stdin))
     {
-       if (strncmp("From: ", buf, 6)
-                   && strncmp("To: ", buf, 4)
-                   && strncmp("Reply-", buf, 6)
-                   && strncmp("Cc: ", buf, 4)
-                   && strncmp("Bcc: ", buf, 5))
-           continue;
-       else
+       if (buf[0] == ' ' || buf[0] == '\t')
+           strcat(longbuf, buf);
+       else if (!strncmp("From: ", buf, 6)
+                   || !strncmp("To: ", buf, 4)
+                   || !strncmp("Reply-", buf, 6)
+                   || !strncmp("Cc: ", buf, 4)
+                   || !strncmp("Bcc: ", buf, 5))
+           strcpy(longbuf, buf);       
+       else if (longbuf[0])
        {
-           fputs(buf, stdout);
-           if (reply)
-           {
-               reply_hack(buf, "HOSTNAME.NET");
-               printf("Rewritten buffer: %s", buf);
-           }
-           else
-               if ((cp = nxtaddr(buf)) != (char *)NULL)
-                   do {
-                       printf("\t%s\n", cp);
-                   } while
-                       ((cp = nxtaddr((char *)NULL)) != (char *)NULL);
+           if (verbose)
+               fputs(longbuf, stdout);
+           parsebuf(longbuf, reply);
+           longbuf[0] = '\0';
        }
-
+    }
+    if (longbuf[0])
+    {
+       if (verbose)
+           fputs(longbuf, stdout);
+       parsebuf(longbuf, reply);
     }
 }
 #endif /* TESTMAIN */