Message-ID checking patch

Patrik Rådman <[email protected]>
Newsgroups gmane.network.sn
Message-ID <[email protected]>
Hi,

Attached to this message is a patch that replaces the Message-ID checking
with a looser test based (mainly) on RFC 2822.

For example, the following Message-ID that previously was replaced is
now OK (and all of Chris Niekel's examples as well :)):

<pan.2004.04.05.16.03.57.428926@%hash%.usenet.us.com>

The patch also allows some Message-IDs which are not legal according to RFC
2822, such as these (real-life examples from a mail-to-news server):

<200401170007.i0H07r6r029257@thinkpad..>
<1078336421.650.5.camel@(null)>
<444446RND_LC_CHAR[1-5]3076l$8309258af84$1p39jiz17@apache>

Let me know if this causes any problems...

-- 
  Patrik Rådman  ·  patrik at iki dot fi  ·  http://www.iki.fi/patrik/
                "I know this because Tyler knows this."
addr_msgid.patch_3 (text/plain, 6 KB)
Index: addr.c
===================================================================
--- addr.c	(revision 34)
+++ addr.c	(revision 42)
@@ -5,11 +5,17 @@
  * Copyright © 2000- Patrik Rådman.
  */
 
+/*
+ * The functions here are based (mainly) on RFC 822 / 2822
+ */
+
+#include <stdlib.h>
 #include "config.h"
 #include "addr.h"
 
 static const char ver_ctrl_id[] = "$Id: addr.c 29 2004-04-24 23:02:38Z patrik $";
 
+/*
 int addr_addrspec(char *buf)
 {
    char *p;
@@ -29,7 +35,41 @@
    p += len;
    return (p - buf);
 }
+*/
 
+int addr_idleft (char *buf);
+int addr_idright (char *buf);
+
+/*
+ * Checks for a valid Message-ID
+ */
+
+int addr_msgid (char *buf)
+{
+   char *p;
+   int len;
+   
+   p = buf;
+   if (*p != '<')
+      return 0;
+   p++;
+   len = addr_idleft(p);
+   if (!len)
+      return 0;
+   p += len;
+   if (*p != '@')
+      return 0;
+   p++;
+   len = addr_idright(p);
+   if (!len)
+      return 0;
+   p += len;
+   if (*p != '>')
+      return 0;
+   p++;
+   return (p - buf);
+}
+
 #define C(x) case x:
 
 int addr_domain(char *buf)
@@ -113,6 +153,10 @@
    return 0;
 }
 
+/*
+ * Like strchr() but ignores comments and quoted strings
+ */
+
 char *addr_qstrchr(char *str, int find)
 {
    bool bs, dq, cm;
@@ -177,3 +221,87 @@
    *dst = '\0';
    return (dst - to);
 }
+
+/*
+ * Used by addr_msgid to check the part left of the '@'
+ */
+
+int addr_idleft (char *buf)
+{
+   char *p;
+   bool dq, bs = FALSE;
+   
+   p = buf;
+   if ((dq = (*p == '"')))
+      p++;
+   
+   for (; *p; p++)
+      if (!bs)
+         switch (*p)
+         {
+            case '"':
+               if (dq && *++p == '@')
+                  return (p - buf);
+               else
+                  return 0;
+            case '\\':
+               bs = TRUE;
+               break;
+            case '>':
+               return 0;
+            case '@':
+               if (!dq)
+                  return (p - buf);
+               else
+                  return 0;
+            default:
+               if (*p < 33 || *p > 126)
+                  return 0;
+         }
+      else
+         bs = FALSE;
+   
+   return 0;
+}
+
+/*
+ * Used by addr_msgid() to check the part right of the '@'
+ */
+
+int addr_idright (char *buf)
+{
+   char *p;
+   bool lb, bs = FALSE;
+
+   p = buf;
+   if ((lb = (*p == '[')))
+      p++;
+
+   for (; *p; p++)
+      if (!bs)
+         switch (*p)
+         {
+            case '[':
+               return 0;
+            case ']':
+               if (lb && *++p == '>')
+                  return (p - buf);
+               else
+                  return 0;
+            case '\\':
+               bs = TRUE;
+               break;
+            case '>':
+               if (!lb)
+                  return (p - buf);
+               else
+                  return 0;
+            default:
+               if (*p < 33 || *p > 126)
+                  return 0;
+         }
+      else
+         bs = FALSE;
+
+   return 0;
+}
Index: addr.h
===================================================================
--- addr.h	(revision 34)
+++ addr.h	(revision 42)
@@ -11,8 +11,9 @@
  * strchr() but ignores comments and quoted strings.
  */
 
-extern int addr_addrspec (char *buf);
+/*extern int addr_addrspec (char *buf);*/
 extern int addr_domain (char *buf);
 extern int addr_localpart (char *buf);
+extern int addr_msgid (char *buf);
 extern char *addr_qstrchr (char *str, int find);
 extern int addr_unescape (char *from, char *to, int len);
Index: snsend.c
===================================================================
--- snsend.c	(revision 34)
+++ snsend.c	(revision 42)
@@ -606,16 +606,16 @@
       }
       HEADER("Message-ID")
       {
-         int c;
+         int len;
 
          if (msgid.used) break; /* XXX */
          for (p = line + hlen + 1; ' ' == *p; p++) ;
-         if ('<' != *p++ || (c = addr_addrspec(p)) <= 0)
+         if ('<' != *p || (len = addr_msgid(p)) <= 0)
          {
-            LOG("append: will replace bad Message-ID \"%s\"", p - 1);
+            LOG("append: will replace bad Message-ID \"%s\"", p);
             return 0;
          }
-         if (b_appendl(&msgid, p, c)) nomem();
+         if (b_appendl(&msgid, p + 1, len - 2)) nomem();
          break;
       }
       if (0 == strncasecmp(line, "X-sn-", 5))
Index: snmail.c
===================================================================
--- snmail.c	(revision 34)
+++ snmail.c	(revision 42)
@@ -57,6 +57,10 @@
 
 void memerr (void) { fail(2, "No memory"); }
 
+/*
+ * Creates a Message-ID of the form "pid.time()@hostname"
+ */
+
 char *mkid (void)
 {
    char *buf;
@@ -94,13 +98,16 @@
    while ((p = addr_qstrchr(p, '<')))
    {
       int len;
-
-      if ((len = addr_addrspec(++p)) <= 0 || '>' != p[len])
+      
+      if ((len = addr_msgid(p)) <= 0)
+      {
+         p++;
          continue;
+      }
       if (-1 == b_appendl(&references, " <", 2)) memerr();
-      if (-1 == b_appendl(&references, buf, addr_unescape(p, buf, len))) memerr();
+      if (-1 == b_appendl(&references, buf, addr_unescape(p + 1, buf, len - 2))) memerr();
       if (-1 == b_appendl(&references, ">", 1)) memerr();
-      p += len + 1;
+      p += len;
    }
 }
 
@@ -157,7 +164,6 @@
 int switchline (char *line, int len)
 {
    char *p;
-   int c;
 
    if (check_from_)
    {
@@ -200,13 +206,16 @@
          if (!messageid)
             if (0 == strncasecmp(line, "Message-ID:", 11))
                if ((p = addr_qstrchr(line + 11, '<')))
-                  if ((c = addr_addrspec(++p)) > 0 && '>' == p[c])
+               {
+                  int len = 0;
+                  if ((len = addr_msgid(p)) > 0)
                   {
-                     if (!(messageid = malloc(c + 1)))
+                     if (!(messageid = malloc(len - 1)))
                         memerr();
                      else
-                        addr_unescape(p, messageid, c);
+                        addr_unescape(p + 1, messageid, len - 2);
                   }
+               }
          break;
       case 'n': case 'N':
          if (0 == strncasecmp(line, "Newsgroups:", 11))
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.