@@ -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.167 2005-09-28 05:48:23 richard Exp $
75+ $Id: mailgw.py,v 1.168 2005-10-07 04:42:13 richard Exp $
7676"""
7777__docformat__ = 'restructuredtext'
7878
@@ -297,19 +297,6 @@ def as_attachment(self):
297297
298298class MailGW :
299299
300- # Matches subjects like:
301- # Re: "[issue1234] title of issue [status=resolved]"
302- subject_re = re .compile (r'''
303- (?P<refwd>\s*\W?\s*(fw|fwd|re|aw)\W\s*)*\s* # Re:
304- (?P<quote>")? # Leading "
305- (\[(?P<classname>[^\d\s]+) # [issue..
306- (?P<nodeid>\d+)? # ..1234]
307- \])?\s*
308- (?P<title>[^[]+)? # issue title
309- "? # Trailing "
310- (\[(?P<args>.+?)\])? # [prop=value]
311- ''' , re .IGNORECASE | re .VERBOSE )
312-
313300 def __init__ (self , instance , db , arguments = ()):
314301 self .instance = instance
315302 self .db = db
@@ -611,6 +598,23 @@ def handle_message(self, message):
611598 # make local variable for easier access
612599 config = self .instance .config
613600
601+ # determine the sender's address
602+ from_list = message .getaddrlist ('resent-from' )
603+ if not from_list :
604+ from_list = message .getaddrlist ('from' )
605+
606+ # check for registration OTK
607+ # or fallback on the default class
608+ otk_re = re .compile ('-- key (?P<otk>[a-zA-Z0-9]{32})' )
609+ otk = otk_re .search (subject )
610+ if otk :
611+ self .db .confirm_registration (otk .group ('otk' ))
612+ subject = 'Your registration to %s is complete' % \
613+ config ['TRACKER_NAME' ]
614+ sendto = [from_list [0 ][1 ]]
615+ self .mailer .standard_message (sendto , subject , '' )
616+ return
617+
614618 # XXX Don't enable. This doesn't work yet.
615619# "[^A-z.]tracker\+(?P<classname>[^\d\s]+)(?P<nodeid>\d+)\@some.dom.ain[^A-z.]"
616620 # handle delivery to addresses like:[email protected] @@ -627,37 +631,45 @@ def handle_message(self, message):
627631# nodeid = issue.group('nodeid')
628632# break
629633
630- # determine the sender's address
631- from_list = message .getaddrlist ('resent-from' )
632- if not from_list :
633- from_list = message .getaddrlist ('from' )
634+ # Matches subjects like:
635+ # Re: "[issue1234] title of issue [status=resolved]"
636+ open , close = config ['MAILGW_SUBJECT_SUFFIX_DELIMITERS' ]
637+ delim_open = re .escape (open )
638+ delim_close = re .escape (close )
639+ subject_re = re .compile (r'''
640+ (?P<refwd>\s*\W?\s*(fw|fwd|re|aw)\W\s*)*\s* # Re:
641+ (?P<quote>")? # Leading "
642+ (\[(?P<classname>[^\d\s]+) # [issue..
643+ (?P<nodeid>\d+)? # ..1234]
644+ \])?\s*
645+ (?P<title>[^%s]+)? # issue title
646+ "? # Trailing "
647+ (?P<argswhole>%s(?P<args>.+?)%s)? # [prop=value]
648+ ''' % (delim_open , delim_open , delim_close ),
649+ re .IGNORECASE | re .VERBOSE )
650+
651+ # figure subject line parsing modes
652+ pfxmode = config ['MAILGW_SUBJECT_PREFIX_PARSING' ]
653+ sfxmode = config ['MAILGW_SUBJECT_SUFFIX_PARSING' ]
634654
635655 # check for well-formed subject line
636- m = self . subject_re .match (subject )
656+ m = subject_re .match (subject )
637657 if m :
638658 # get the classname
639- classname = m .group ('classname' )
659+ if pfxmode == 'none' :
660+ classname = None
661+ else :
662+ classname = m .group ('classname' )
640663 if classname is None :
641- # no classname, check if this a registration confirmation email
642- # or fallback on the default class
643- otk_re = re .compile ('-- key (?P<otk>[a-zA-Z0-9]{32})' )
644- otk = otk_re .search (m .group ('title' ))
645- if otk :
646- self .db .confirm_registration (otk .group ('otk' ))
647- subject = 'Your registration to %s is complete' % \
648- config ['TRACKER_NAME' ]
649- sendto = [from_list [0 ][1 ]]
650- self .mailer .standard_message (sendto , subject , '' )
651- return
652- elif self .default_class :
664+ if self .default_class :
653665 classname = self .default_class
654666 else :
655667 classname = config ['MAILGW_DEFAULT_CLASS' ]
656668 if not classname :
657669 # fail
658670 m = None
659671
660- if not m :
672+ if not m and pfxmode == 'strict' :
661673 raise MailUsageError , """
662674The message you sent to roundup did not contain a properly formed subject
663675line. The subject must contain a class name or designator to indicate the
@@ -672,10 +684,22 @@ def handle_message(self, message):
672684Subject was: '%s'
673685""" % subject
674686
675- # get the class
676- try :
677- cl = self .db .getclass (classname )
678- except KeyError :
687+ # try to get the class specified - if "loose" then fall back on the
688+ # default
689+ attempts = [classname ]
690+ if pfxmode == 'loose' :
691+ if self .default_class :
692+ attempts .append (self .default_class )
693+ else :
694+ attempts .append (config ['MAILGW_DEFAULT_CLASS' ])
695+ cl = None
696+ for trycl in attempts :
697+ try :
698+ cl = self .db .getclass (classname )
699+ break
700+ except KeyError :
701+ pass
702+ if not cl :
679703 raise MailUsageError , '''
680704The class name you identified in the subject line ("%s") does not exist in the
681705database.
@@ -685,7 +709,10 @@ def handle_message(self, message):
685709''' % (classname , ', ' .join (self .db .getclasses ()), subject )
686710
687711 # get the optional nodeid
688- nodeid = m .group ('nodeid' )
712+ if pfxmode == 'none' :
713+ nodeid = None
714+ else :
715+ nodeid = m .group ('nodeid' )
689716
690717 # title is optional too
691718 title = m .group ('title' )
@@ -703,7 +730,7 @@ def handle_message(self, message):
703730 if nodeid is None and not title :
704731 raise MailUsageError , '''
705732I cannot match your message to a node in the database - you need to either
706- supply a full node identifier (with number, eg "[issue123]" or keep the
733+ supply a full designator (with number, eg "[issue123]" or keep the
707734previous subject title intact so I can match that.
708735
709736Subject was: "%s"
@@ -713,20 +740,36 @@ def handle_message(self, message):
713740 # maybe someone's responded to the initial mail that created an
714741 # entry. Try to find the matching nodes with the same title, and
715742 # use the _last_ one matched (since that'll _usually_ be the most
716- # recent...)
717- if nodeid is None and m .group ('refwd' ):
743+ # recent...). The subject_content_match config may specify an
744+ # additional restriction based on the matched node's creation or
745+ # activity.
746+ tmatch_mode = config ['MAILGW_SUBJECT_CONTENT_MATCH' ]
747+ if tmatch_mode != 'never' and nodeid is None and m .group ('refwd' ):
718748 l = cl .stringFind (title = title )
719- if l :
720- nodeid = l [- 1 ]
749+ limit = None
750+ if (tmatch_mode .startswith ('creation' ) or
751+ tmatch_mode .startswith ('activity' )):
752+ limit , interval = tmatch_mode .split (' ' , 1 )
753+ threshold = date .Date ('.' ) - date .Interval (interval )
754+ for id in l :
755+ if limit :
756+ if threshold < cl .get (id , limit ):
757+ nodeid = id
758+ else :
759+ nodeid = id
721760
722761 # if a nodeid was specified, make sure it's valid
723762 if nodeid is not None and not cl .hasnode (nodeid ):
724- raise MailUsageError , '''
763+ if pfxmode == 'strict' :
764+ raise MailUsageError , '''
725765The node specified by the designator in the subject of your message ("%s")
726766does not exist.
727767
728768Subject was: "%s"
729769''' % (nodeid , subject )
770+ else :
771+ title = subject
772+ nodeid = None
730773
731774 # Handle the arguments specified by the email gateway command line.
732775 # We do this by looping over the list of self.arguments looking for
@@ -844,17 +887,24 @@ def handle_message(self, message):
844887 properties = cl .getprops ()
845888 props = {}
846889 args = m .group ('args' )
890+ argswhole = m .group ('argswhole' )
847891 if args :
848- errors , props = setPropArrayFromString (self , cl , args , nodeid )
849- # handle any errors parsing the argument list
850- if errors :
851- errors = '\n - ' .join (map (str , errors ))
852- raise MailUsageError , '''
892+ if sfxmode == 'none' :
893+ title += ' ' + argswhole
894+ else :
895+ errors , props = setPropArrayFromString (self , cl , args , nodeid )
896+ # handle any errors parsing the argument list
897+ if errors :
898+ if sfxmode == 'strict' :
899+ errors = '\n - ' .join (map (str , errors ))
900+ raise MailUsageError , '''
853901There were problems handling your subject line argument list:
854902- %s
855903
856904Subject was: "%s"
857905''' % (errors , subject )
906+ else :
907+ title += ' ' + argswhole
858908
859909
860910 # set the issue title to the subject
0 commit comments