@@ -72,7 +72,7 @@ class node. Any parts of other types are each stored in separate files
7272an exception, the original message is bounced back to the sender with the
7373explanatory message given in the exception.
7474
75- $Id: mailgw.py,v 1.182 2007-01-21 18:08:31 forsberg Exp $
75+ $Id: mailgw.py,v 1.183 2007-01-28 13:49:13 forsberg Exp $
7676"""
7777__docformat__ = 'restructuredtext'
7878
@@ -619,57 +619,89 @@ def handle_message(self, message):
619619
620620 # Matches subjects like:
621621 # Re: "[issue1234] title of issue [status=resolved]"
622- open , close = config ['MAILGW_SUBJECT_SUFFIX_DELIMITERS' ]
623- delim_open = re .escape (open )
622+
623+ tmpsubject = subject # We need subject untouched for later use
624+ # in error messages
625+
626+ sd_open , sd_close = config ['MAILGW_SUBJECT_SUFFIX_DELIMITERS' ]
627+ delim_open = re .escape (sd_open )
624628 if delim_open in '[(' : delim_open = '\\ ' + delim_open
625- delim_close = re .escape (close )
629+ delim_close = re .escape (sd_close )
626630 if delim_close in '[(' : delim_close = '\\ ' + delim_close
627- subject_re = r'''
628- (?P<refwd>\s*\W?\s*(fw|fwd|re|aw|sv|ang)\W\s*)*\s* # Re:
629- (?P<quote>")? # Leading "
630- (%s(?P<classname>[^\d\s]+) # [issue..
631- (?P<nodeid>\d+)? # ..1234]
632- %s)?\s*
633- (?P<title>[^%s]+)? # issue title
634- "? # Trailing "
635- (?P<argswhole>%s(?P<args>.+?)%s)? # [prop=value]
636- ''' % (delim_open , delim_close , delim_open , delim_open , delim_close )
637- subject_re = re .compile (subject_re , re .IGNORECASE | re .VERBOSE )
631+
632+ matches = dict .fromkeys (['refwd' , 'quote' , 'classname' ,
633+ 'nodeid' , 'title' , 'args' ,
634+ 'argswhole' ])
635+
636+
637+ # Look for Re: et. al. Used later on for MAILGW_SUBJECT_CONTENT_MATCH
638+ re_re = r'''(?P<refwd>(\s*\W?\s*(fw|fwd|re|aw|sv|ang)\W)+)\s*'''
639+ m = re .match (re_re , tmpsubject , re .IGNORECASE | re .VERBOSE )
640+ if m :
641+ matches .update (m .groupdict ())
642+ tmpsubject = tmpsubject [len (matches ['refwd' ]):] # Consume Re:
643+
644+ # Look for Leading "
645+ m = re .match (r'''(?P<quote>\s*")''' , tmpsubject ,
646+ re .IGNORECASE | re .VERBOSE )
647+ if m :
648+ matches .update (m .groupdict ())
649+ tmpsubject = tmpsubject [len (matches ['quote' ]):] # Consume quote
650+
651+ class_re = r'''%s(?P<classname>(%s))+(?P<nodeid>\d+)?%s''' % \
652+ (delim_open , "|" .join (self .db .getclasses ()), delim_close )
653+ # Note: re.search, not re.match as there might be garbage
654+ # (mailing list prefix, etc.) before the class identifier
655+ m = re .search (class_re , tmpsubject , re .IGNORECASE | re .VERBOSE )
656+ if m :
657+ matches .update (m .groupdict ())
658+ # Skip to the end of the class identifier, including any
659+ # garbage before it.
660+
661+ tmpsubject = tmpsubject [m .end ():]
662+
663+ m = re .match (r'''(?P<title>[^%s]+)''' % delim_open , tmpsubject ,
664+ re .IGNORECASE | re .VERBOSE )
665+ if m :
666+ matches .update (m .groupdict ())
667+ tmpsubject = tmpsubject [len (matches ['title' ]):] # Consume title
668+
669+ args_re = r'''(?P<argswhole>%s(?P<args>.+?)%s)?''' % (delim_open , delim_close )
670+ m = re .search (args_re , tmpsubject , re .IGNORECASE | re .VERBOSE )
671+ if m :
672+ matches .update (m .groupdict ())
638673
639674 # figure subject line parsing modes
640675 pfxmode = config ['MAILGW_SUBJECT_PREFIX_PARSING' ]
641676 sfxmode = config ['MAILGW_SUBJECT_SUFFIX_PARSING' ]
642677
643- # check for well-formed subject line
644- m = subject_re .match (subject )
645- if m :
646- # check for registration OTK
647- # or fallback on the default class
648- if self .db .config ['EMAIL_REGISTRATION_CONFIRMATION' ]:
649- otk_re = re .compile ('-- key (?P<otk>[a-zA-Z0-9]{32})' )
650- otk = otk_re .search (m .group ('title' ) or '' )
651- if otk :
652- self .db .confirm_registration (otk .group ('otk' ))
653- subject = 'Your registration to %s is complete' % \
654- config ['TRACKER_NAME' ]
655- sendto = [from_list [0 ][1 ]]
656- self .mailer .standard_message (sendto , subject , '' )
657- return
658- # get the classname
659- if pfxmode == 'none' :
660- classname = None
678+ # check for registration OTK
679+ # or fallback on the default class
680+ if self .db .config ['EMAIL_REGISTRATION_CONFIRMATION' ]:
681+ otk_re = re .compile ('-- key (?P<otk>[a-zA-Z0-9]{32})' )
682+ otk = otk_re .search (matches ['title' ] or '' )
683+ if otk :
684+ self .db .confirm_registration (otk .group ('otk' ))
685+ subject = 'Your registration to %s is complete' % \
686+ config ['TRACKER_NAME' ]
687+ sendto = [from_list [0 ][1 ]]
688+ self .mailer .standard_message (sendto , subject , '' )
689+ return
690+ # get the classname
691+ if pfxmode == 'none' :
692+ classname = None
693+ else :
694+ classname = matches ['classname' ]
695+ if classname is None :
696+ if self .default_class :
697+ classname = self .default_class
661698 else :
662- classname = m .group ('classname' )
663- if classname is None :
664- if self .default_class :
665- classname = self .default_class
666- else :
667- classname = config ['MAILGW_DEFAULT_CLASS' ]
668- if not classname :
669- # fail
670- m = None
699+ classname = config ['MAILGW_DEFAULT_CLASS' ]
700+ if not classname :
701+ # fail
702+ m = None
671703
672- if not m and pfxmode == 'strict' :
704+ if not classname and pfxmode == 'strict' :
673705 raise MailUsageError , _ ("""
674706The message you sent to roundup did not contain a properly formed subject
675707line. The subject must contain a class name or designator to indicate the
@@ -713,7 +745,7 @@ def handle_message(self, message):
713745 if pfxmode == 'none' :
714746 nodeid = None
715747 else :
716- nodeid = m . group ( 'nodeid' )
748+ nodeid = matches [ 'nodeid' ]
717749
718750 # try in-reply-to to match the message if there's no nodeid
719751 inreplyto = message .getheader ('in-reply-to' ) or ''
@@ -723,15 +755,15 @@ def handle_message(self, message):
723755 nodeid = cl .filter (None , {'messages' :l })[0 ]
724756
725757 # title is optional too
726- title = m . group ( 'title' )
758+ title = matches [ 'title' ]
727759 if title :
728760 title = title .strip ()
729761 else :
730762 title = ''
731763
732764 # strip off the quotes that dumb emailers put around the subject, like
733765 # Re: "[issue1] bla blah"
734- if m . group ( 'quote' ) and title .endswith ('"' ):
766+ if matches [ 'quote' ] and title .endswith ('"' ):
735767 title = title [:- 1 ]
736768
737769 # but we do need either a title or a nodeid...
@@ -752,7 +784,7 @@ def handle_message(self, message):
752784 # additional restriction based on the matched node's creation or
753785 # activity.
754786 tmatch_mode = config ['MAILGW_SUBJECT_CONTENT_MATCH' ]
755- if tmatch_mode != 'never' and nodeid is None and m . group ( 'refwd' ) :
787+ if tmatch_mode != 'never' and nodeid is None and matches [ 'refwd' ] :
756788 l = cl .stringFind (title = title )
757789 limit = None
758790 if (tmatch_mode .startswith ('creation' ) or
@@ -905,8 +937,8 @@ def handle_message(self, message):
905937 # figure what the properties of this Class are
906938 properties = cl .getprops ()
907939 props = {}
908- args = m . group ( 'args' )
909- argswhole = m . group ( 'argswhole' )
940+ args = matches [ 'args' ]
941+ argswhole = matches [ 'argswhole' ]
910942 if args :
911943 if sfxmode == 'none' :
912944 title += ' ' + argswhole
0 commit comments