After starting a thread on this list
(http://mail.python.org/pipermail/mailman-developers/2006-May/018787.html>
and also posting a request for feedback on Mailman-Users
<http://mail.python.org/pipermail/mailman-users/2006-June/051588.html>
which received no replies, I think I'm almost done with this. My patch
is attached for review, comment.

Basically, I implement a new Utils.strip_verbose_pattern() function
which converts verbose patterns to single-line, non-verbose
equivalents and add code to versions.py for a one time conversion of
existing topics regexps.

I then modify the Gui, etc so that all future multi-line patterns are
stored as entered, but compiled and used with the lines connected by
'|'.

Specifically, I would like advice and comment on two things.

First since the strip_verbose_pattern() function is basically a
one-time, list conversion function, would it be better added to
versions.py rather than Utils.py.

Second, when a topic pattern is first entered, an attempt is made to
compile it, and if this throws an exception, the error is reported in
the Gui and the topic is ignored. A similar thing is also done in
MailList.py which will catch (eventually) and log bad topic regexps
that might be entered with config_list or withlist.

My question here is in the error message and log message, The pattern I
report as invalid is the '|' joined pattern and not the original
entry. I think this makes more sense, but I'm interested in what
others think.

Finally, in writing this post I have thought of another issue. Someone
may have a saved config_list 'template' with old style 'verbose' topic
regexps which wouldn't get converted if applied to a new 2.2.x list.
Is this something to be concerned about? Note that this could be an
issue any time a list attribute is deleted or has its set of values
manipulated.

-- 
Mark Sapiro <[EMAIL PROTECTED]>       The highway is for gamblers,
San Francisco Bay Area, California    better use your sense - B. Dylan

Index: mailman/Mailman/Cgi/options.py
===================================================================
--- mailman/Mailman/Cgi/options.py      (revision 7907)
+++ mailman/Mailman/Cgi/options.py      (working copy)
@@ -33,6 +33,7 @@
 
 from Mailman.htmlformat import *
 
+OR = '|'
 SLASH = '/'
 SETLANGUAGE = -1
 
@@ -1021,7 +1022,8 @@
     table.AddRow([Bold(Label(_('Name:'))),
                   Utils.websafe(name)])
     table.AddRow([Bold(Label(_('Pattern (as regexp):'))),
-                  '<pre>' + Utils.websafe(pattern) + '</pre>'])
+                  '<pre>' + Utils.websafe(OR.join(pattern.splitlines()))
+                   + '</pre>'])
     table.AddRow([Bold(Label(_('Description:'))),
                   Utils.websafe(description)])
     # Make colors look nice
Index: mailman/Mailman/Gui/Topics.py
===================================================================
--- mailman/Mailman/Gui/Topics.py       (revision 7907)
+++ mailman/Mailman/Gui/Topics.py       (working copy)
@@ -22,7 +22,9 @@
 from Mailman.i18n import _
 from Mailman.Gui.GUIBase import GUIBase
 
+OR = '|'
 
+
 
 class Topics(GUIBase):
     def GetConfigCategory(self):
@@ -119,9 +121,10 @@
             # Make sure the pattern was a legal regular expression
             name = Utils.websafe(name)
             try:
-                re.compile(pattern)
+                orpattern = OR.join(pattern.splitlines())
+                re.compile(orpattern)
             except (re.error, TypeError):
-                safepattern = Utils.websafe(pattern)
+                safepattern = Utils.websafe(orpattern)
                 doc.addError(_("""The topic pattern '%(safepattern)s' is not a
                 legal regular expression.  It will be discarded."""))
                 continue
Index: mailman/Mailman/Handlers/Tagger.py
===================================================================
--- mailman/Mailman/Handlers/Tagger.py  (revision 7907)
+++ mailman/Mailman/Handlers/Tagger.py  (working copy)
@@ -23,6 +23,7 @@
 import email.Iterators
 import email.Parser
 
+OR = '|'
 CRNL = '\r\n'
 EMPTYSTRING = ''
 NLTAB = '\n\t'
@@ -51,7 +52,8 @@
     # added to the specific topics bucket.
     hits = {}
     for name, pattern, desc, emptyflag in mlist.topics:
-        cre = re.compile(pattern, re.IGNORECASE | re.VERBOSE)
+        pattern = OR.join(pattern.splitlines())
+        cre = re.compile(pattern, re.IGNORECASE)
         for line in matchlines:
             if cre.search(line):
                 hits[name] = 1
Index: mailman/Mailman/MailList.py
===================================================================
--- mailman/Mailman/MailList.py (revision 7907)
+++ mailman/Mailman/MailList.py (working copy)
@@ -74,6 +74,7 @@
 _ = i18n._
 
 EMPTYSTRING = ''
+OR = '|'
 
 clog    = logging.getLogger('mailman.config')
 elog    = logging.getLogger('mailman.error')
@@ -742,10 +743,11 @@
         goodtopics = []
         for name, pattern, desc, emptyflag in self.topics:
             try:
-                re.compile(pattern)
+                orpattern = OR.join(pattern.splitlines())
+                re.compile(orpattern)
             except (re.error, TypeError):
                 elog.error('Bad topic pattern "%s" for list: %s',
-                           pattern, self.internal_name())
+                           orpattern, self.internal_name())
             else:
                 goodtopics.append((name, pattern, desc, emptyflag))
         self.topics = goodtopics
Index: mailman/Mailman/Utils.py
===================================================================
--- mailman/Mailman/Utils.py    (revision 7907)
+++ mailman/Mailman/Utils.py    (working copy)
@@ -47,6 +47,7 @@
 
 EMPTYSTRING = ''
 UEMPTYSTRING = u''
+CR = '\r'
 NL = '\n'
 DOT = '.'
 IDENTCHARS = ascii_letters + digits + '_'
@@ -849,3 +850,58 @@
     except (LookupError, UnicodeError, ValueError, HeaderParseError):
         # possibly charset problem. return with undecoded string in one line.
         return EMPTYSTRING.join(s.splitlines())
+
+
+def strip_verbose_pattern(pattern):
+    # Remove white space and comments from a verbose pattern and return a
+    # non-verbose, equivalent pattern.  Replace CR and NL in the result
+    # with '\\r' and '\\n' respectively to avoid multi-line results.
+    if not isinstance(pattern, str):
+        return pattern
+    newpattern = ''
+    i = 0
+    inclass = False
+    skiptoeol = False
+    copynext = False
+    while i < len(pattern):
+        c = pattern[i]
+        if copynext:
+            if c == NL:
+                newpattern += '\\n'
+            elif c == CR:
+                newpattern += '\\r'
+            else:
+                newpattern += c
+            copynext = False
+        elif skiptoeol:
+            if c == NL:
+                skiptoeol = False
+        elif c == '#' and not inclass:
+            skiptoeol = True
+        elif c == '[' and not inclass:
+            inclass = True
+            newpattern += c
+            copynext = True
+        elif c == ']' and inclass:
+            inclass = False
+            newpattern += c
+        elif re.search('\s', c):
+            if inclass:
+                if c == NL:
+                    newpattern += '\\n'
+                elif c == CR:
+                    newpattern += '\\r'
+                else:
+                    newpattern += c
+        elif c == '\\' and not inclass:
+            newpattern += c
+            copynext = True
+        else:
+            if c == NL:
+                newpattern += '\\n'
+            elif c == CR:
+                newpattern += '\\r'
+            else:
+                newpattern += c
+        i += 1
+    return newpattern
Index: mailman/Mailman/Version.py
===================================================================
--- mailman/Mailman/Version.py  (revision 7907)
+++ mailman/Mailman/Version.py  (working copy)
@@ -36,7 +36,7 @@
                (REL_LEVEL << 4)  | (REL_SERIAL << 0))
 
 # config.pck schema version number
-DATA_FILE_VERSION = 97
+DATA_FILE_VERSION = 98
 
 # qfile/*.db schema version number
 QFILE_SCHEMA_VERSION = 3
Index: mailman/Mailman/versions.py
===================================================================
--- mailman/Mailman/versions.py (revision 7907)
+++ mailman/Mailman/versions.py (working copy)
@@ -307,6 +307,15 @@
             pass
         else:
             l.digest_members[k] = 0
+    #
+    # Convert pre 2.2 topics regexps which were compiled in verbose mode
+    # to a non-verbose equivalent.
+    #
+    if stored_state['data_version'] <= 97 and stored_state.has_key('topics'):
+        l.topics = []
+        for name, pattern, description, emptyflag in stored_state['topics']:
+            pattern = Utils.strip_verbose_pattern(pattern)
+            l.topics.append((name, pattern, description, emptyflag))
 
 
 
_______________________________________________
Mailman-Developers mailing list
Mailman-Developers@python.org
http://mail.python.org/mailman/listinfo/mailman-developers
Mailman FAQ: http://www.python.org/cgi-bin/faqw-mm.py
Searchable Archives: 
http://www.mail-archive.com/mailman-developers%40python.org/
Unsubscribe: 
http://mail.python.org/mailman/options/mailman-developers/archive%40jab.org

Security Policy: 
http://www.python.org/cgi-bin/faqw-mm.py?req=show&file=faq01.027.htp

Reply via email to