Mercurial > p > roundup > code
diff roundup/mailgw.py @ 3417:07c696890f55
mailgw subject parsing has configurable levels of strictness
nosy messages may be sent individually to all recipients
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Fri, 07 Oct 2005 04:42:13 +0000 |
| parents | 4a228402b810 |
| children | d3b02352484f |
line wrap: on
line diff
--- a/roundup/mailgw.py Wed Sep 28 05:48:23 2005 +0000 +++ b/roundup/mailgw.py Fri Oct 07 04:42:13 2005 +0000 @@ -72,7 +72,7 @@ an exception, the original message is bounced back to the sender with the explanatory message given in the exception. -$Id: mailgw.py,v 1.167 2005-09-28 05:48:23 richard Exp $ +$Id: mailgw.py,v 1.168 2005-10-07 04:42:13 richard Exp $ """ __docformat__ = 'restructuredtext' @@ -297,19 +297,6 @@ class MailGW: - # Matches subjects like: - # Re: "[issue1234] title of issue [status=resolved]" - subject_re = re.compile(r''' - (?P<refwd>\s*\W?\s*(fw|fwd|re|aw)\W\s*)*\s* # Re: - (?P<quote>")? # Leading " - (\[(?P<classname>[^\d\s]+) # [issue.. - (?P<nodeid>\d+)? # ..1234] - \])?\s* - (?P<title>[^[]+)? # issue title - "? # Trailing " - (\[(?P<args>.+?)\])? # [prop=value] - ''', re.IGNORECASE|re.VERBOSE) - def __init__(self, instance, db, arguments=()): self.instance = instance self.db = db @@ -611,6 +598,23 @@ # make local variable for easier access config = self.instance.config + # determine the sender's address + from_list = message.getaddrlist('resent-from') + if not from_list: + from_list = message.getaddrlist('from') + + # check for registration OTK + # or fallback on the default class + otk_re = re.compile('-- key (?P<otk>[a-zA-Z0-9]{32})') + otk = otk_re.search(subject) + if otk: + self.db.confirm_registration(otk.group('otk')) + subject = 'Your registration to %s is complete' % \ + config['TRACKER_NAME'] + sendto = [from_list[0][1]] + self.mailer.standard_message(sendto, subject, '') + return + # XXX Don't enable. This doesn't work yet. # "[^A-z.]tracker\+(?P<classname>[^\d\s]+)(?P<nodeid>\d+)\@some.dom.ain[^A-z.]" # handle delivery to addresses like:tracker+issue25@some.dom.ain @@ -627,29 +631,37 @@ # nodeid = issue.group('nodeid') # break - # determine the sender's address - from_list = message.getaddrlist('resent-from') - if not from_list: - from_list = message.getaddrlist('from') + # Matches subjects like: + # Re: "[issue1234] title of issue [status=resolved]" + open, close = config['MAILGW_SUBJECT_SUFFIX_DELIMITERS'] + delim_open = re.escape(open) + delim_close = re.escape(close) + subject_re = re.compile(r''' + (?P<refwd>\s*\W?\s*(fw|fwd|re|aw)\W\s*)*\s* # Re: + (?P<quote>")? # Leading " + (\[(?P<classname>[^\d\s]+) # [issue.. + (?P<nodeid>\d+)? # ..1234] + \])?\s* + (?P<title>[^%s]+)? # issue title + "? # Trailing " + (?P<argswhole>%s(?P<args>.+?)%s)? # [prop=value] + '''%(delim_open, delim_open, delim_close), + re.IGNORECASE|re.VERBOSE) + + # figure subject line parsing modes + pfxmode = config['MAILGW_SUBJECT_PREFIX_PARSING'] + sfxmode = config['MAILGW_SUBJECT_SUFFIX_PARSING'] # check for well-formed subject line - m = self.subject_re.match(subject) + m = subject_re.match(subject) if m: # get the classname - classname = m.group('classname') + if pfxmode == 'none': + classname = None + else: + classname = m.group('classname') if classname is None: - # no classname, check if this a registration confirmation email - # or fallback on the default class - otk_re = re.compile('-- key (?P<otk>[a-zA-Z0-9]{32})') - otk = otk_re.search(m.group('title')) - if otk: - self.db.confirm_registration(otk.group('otk')) - subject = 'Your registration to %s is complete' % \ - config['TRACKER_NAME'] - sendto = [from_list[0][1]] - self.mailer.standard_message(sendto, subject, '') - return - elif self.default_class: + if self.default_class: classname = self.default_class else: classname = config['MAILGW_DEFAULT_CLASS'] @@ -657,7 +669,7 @@ # fail m = None - if not m: + if not m and pfxmode == 'strict': raise MailUsageError, """ The message you sent to roundup did not contain a properly formed subject line. The subject must contain a class name or designator to indicate the @@ -672,10 +684,22 @@ Subject was: '%s' """%subject - # get the class - try: - cl = self.db.getclass(classname) - except KeyError: + # try to get the class specified - if "loose" then fall back on the + # default + attempts = [classname] + if pfxmode == 'loose': + if self.default_class: + attempts.append(self.default_class) + else: + attempts.append(config['MAILGW_DEFAULT_CLASS']) + cl = None + for trycl in attempts: + try: + cl = self.db.getclass(classname) + break + except KeyError: + pass + if not cl: raise MailUsageError, ''' The class name you identified in the subject line ("%s") does not exist in the database. @@ -685,7 +709,10 @@ '''%(classname, ', '.join(self.db.getclasses()), subject) # get the optional nodeid - nodeid = m.group('nodeid') + if pfxmode == 'none': + nodeid = None + else: + nodeid = m.group('nodeid') # title is optional too title = m.group('title') @@ -703,7 +730,7 @@ if nodeid is None and not title: raise MailUsageError, ''' I cannot match your message to a node in the database - you need to either -supply a full node identifier (with number, eg "[issue123]" or keep the +supply a full designator (with number, eg "[issue123]" or keep the previous subject title intact so I can match that. Subject was: "%s" @@ -713,20 +740,36 @@ # maybe someone's responded to the initial mail that created an # entry. Try to find the matching nodes with the same title, and # use the _last_ one matched (since that'll _usually_ be the most - # recent...) - if nodeid is None and m.group('refwd'): + # recent...). The subject_content_match config may specify an + # additional restriction based on the matched node's creation or + # activity. + tmatch_mode = config['MAILGW_SUBJECT_CONTENT_MATCH'] + if tmatch_mode != 'never' and nodeid is None and m.group('refwd'): l = cl.stringFind(title=title) - if l: - nodeid = l[-1] + limit = None + if (tmatch_mode.startswith('creation') or + tmatch_mode.startswith('activity')): + limit, interval = tmatch_mode.split(' ', 1) + threshold = date.Date('.') - date.Interval(interval) + for id in l: + if limit: + if threshold < cl.get(id, limit): + nodeid = id + else: + nodeid = id # if a nodeid was specified, make sure it's valid if nodeid is not None and not cl.hasnode(nodeid): - raise MailUsageError, ''' + if pfxmode == 'strict': + raise MailUsageError, ''' The node specified by the designator in the subject of your message ("%s") does not exist. Subject was: "%s" '''%(nodeid, subject) + else: + title = subject + nodeid = None # Handle the arguments specified by the email gateway command line. # We do this by looping over the list of self.arguments looking for @@ -844,17 +887,24 @@ properties = cl.getprops() props = {} args = m.group('args') + argswhole = m.group('argswhole') if args: - errors, props = setPropArrayFromString(self, cl, args, nodeid) - # handle any errors parsing the argument list - if errors: - errors = '\n- '.join(map(str, errors)) - raise MailUsageError, ''' + if sfxmode == 'none': + title += ' ' + argswhole + else: + errors, props = setPropArrayFromString(self, cl, args, nodeid) + # handle any errors parsing the argument list + if errors: + if sfxmode == 'strict': + errors = '\n- '.join(map(str, errors)) + raise MailUsageError, ''' There were problems handling your subject line argument list: - %s Subject was: "%s" '''%(errors, subject) + else: + title += ' ' + argswhole # set the issue title to the subject
