Skip to content

Commit 71f1f09

Browse files
author
Richard Jones
committed
Fixes to mailgw subject parsing
1 parent 77eeba1 commit 71f1f09

File tree

2 files changed

+73
-36
lines changed

2 files changed

+73
-36
lines changed

roundup/mailgw.py

Lines changed: 56 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class node. Any parts of other types are each stored in separate files
7272
an exception, the original message is bounced back to the sender with the
7373
explanatory message given in the exception.
7474
75-
$Id: mailgw.py,v 1.183 2007-01-28 13:49:13 forsberg Exp $
75+
$Id: mailgw.py,v 1.184 2007-02-15 03:09:53 richard Exp $
7676
"""
7777
__docformat__ = 'restructuredtext'
7878

@@ -620,8 +620,9 @@ def handle_message(self, message):
620620
# Matches subjects like:
621621
# Re: "[issue1234] title of issue [status=resolved]"
622622

623-
tmpsubject = subject # We need subject untouched for later use
624-
# in error messages
623+
# Alias since we need a reference to the original subject for
624+
# later use in error messages
625+
tmpsubject = subject
625626

626627
sd_open, sd_close = config['MAILGW_SUBJECT_SUFFIX_DELIMITERS']
627628
delim_open = re.escape(sd_open)
@@ -633,7 +634,6 @@ def handle_message(self, message):
633634
'nodeid', 'title', 'args',
634635
'argswhole'])
635636

636-
637637
# Look for Re: et. al. Used later on for MAILGW_SUBJECT_CONTENT_MATCH
638638
re_re = r'''(?P<refwd>(\s*\W?\s*(fw|fwd|re|aw|sv|ang)\W)+)\s*'''
639639
m = re.match(re_re, tmpsubject, re.IGNORECASE|re.VERBOSE)
@@ -642,32 +642,39 @@ def handle_message(self, message):
642642
tmpsubject = tmpsubject[len(matches['refwd']):] # Consume Re:
643643

644644
# Look for Leading "
645-
m = re.match(r'''(?P<quote>\s*")''', tmpsubject,
646-
re.IGNORECASE|re.VERBOSE)
645+
m = re.match(r'(?P<quote>\s*")', tmpsubject,
646+
re.IGNORECASE)
647647
if m:
648648
matches.update(m.groupdict())
649649
tmpsubject = tmpsubject[len(matches['quote']):] # Consume quote
650650

651-
class_re = r'''%s(?P<classname>(%s))+(?P<nodeid>\d+)?%s''' % \
652-
(delim_open, "|".join(self.db.getclasses()), delim_close)
651+
has_prefix = re.search(r'^%s(\w+)%s'%(delim_open,
652+
delim_close), tmpsubject.strip())
653+
654+
class_re = r'%s(?P<classname>(%s))(?P<nodeid>\d+)?%s'%(delim_open,
655+
"|".join(self.db.getclasses()), delim_close)
653656
# Note: re.search, not re.match as there might be garbage
654657
# (mailing list prefix, etc.) before the class identifier
655-
m = re.search(class_re, tmpsubject, re.IGNORECASE|re.VERBOSE)
658+
m = re.search(class_re, tmpsubject, re.IGNORECASE)
656659
if m:
657660
matches.update(m.groupdict())
658661
# Skip to the end of the class identifier, including any
659662
# garbage before it.
660663

661664
tmpsubject = tmpsubject[m.end():]
662665

663-
m = re.match(r'''(?P<title>[^%s]+)''' % delim_open, tmpsubject,
664-
re.IGNORECASE|re.VERBOSE)
666+
# if we've not found a valid classname prefix then force the
667+
# scanning to handle there being a leading delimiter
668+
title_re = r'(?P<title>%s[^%s]+)'%(
669+
not matches['classname'] and '.' or '', delim_open)
670+
m = re.match(title_re, tmpsubject.strip(), re.IGNORECASE)
665671
if m:
666672
matches.update(m.groupdict())
667673
tmpsubject = tmpsubject[len(matches['title']):] # Consume title
668674

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)
675+
args_re = r'(?P<argswhole>%s(?P<args>.+?)%s)?'%(delim_open,
676+
delim_close)
677+
m = re.search(args_re, tmpsubject.strip(), re.IGNORECASE|re.VERBOSE)
671678
if m:
672679
matches.update(m.groupdict())
673680

@@ -687,21 +694,14 @@ def handle_message(self, message):
687694
sendto = [from_list[0][1]]
688695
self.mailer.standard_message(sendto, subject, '')
689696
return
697+
690698
# get the classname
691699
if pfxmode == 'none':
692700
classname = None
693701
else:
694702
classname = matches['classname']
695-
if classname is None:
696-
if self.default_class:
697-
classname = self.default_class
698-
else:
699-
classname = config['MAILGW_DEFAULT_CLASS']
700-
if not classname:
701-
# fail
702-
m = None
703703

704-
if not classname and pfxmode == 'strict':
704+
if not classname and has_prefix and pfxmode == 'strict':
705705
raise MailUsageError, _("""
706706
The message you sent to roundup did not contain a properly formed subject
707707
line. The subject must contain a class name or designator to indicate the
@@ -716,29 +716,50 @@ def handle_message(self, message):
716716
Subject was: '%(subject)s'
717717
""") % locals()
718718

719-
# try to get the class specified - if "loose" then fall back on the
720-
# default
721-
attempts = [classname]
722-
if pfxmode == 'loose':
723-
if self.default_class:
724-
attempts.append(self.default_class)
725-
else:
726-
attempts.append(config['MAILGW_DEFAULT_CLASS'])
719+
# try to get the class specified - if "loose" or "none" then fall
720+
# back on the default
721+
attempts = []
722+
if classname:
723+
attempts.append(classname)
724+
725+
if self.default_class:
726+
attempts.append(self.default_class)
727+
else:
728+
attempts.append(config['MAILGW_DEFAULT_CLASS'])
729+
730+
# first valid class name wins
727731
cl = None
728732
for trycl in attempts:
729733
try:
730-
cl = self.db.getclass(classname)
734+
cl = self.db.getclass(trycl)
735+
classname = trycl
731736
break
732737
except KeyError:
733738
pass
739+
734740
if not cl:
735741
validname = ', '.join(self.db.getclasses())
736-
raise MailUsageError, _("""
737-
The class name you identified in the subject line ("%(classname)s") does not exist in the
738-
database.
742+
if classname:
743+
raise MailUsageError, _("""
744+
The class name you identified in the subject line ("%(classname)s") does
745+
not exist in the database.
739746
740747
Valid class names are: %(validname)s
741748
Subject was: "%(subject)s"
749+
""") % locals()
750+
else:
751+
raise MailUsageError, _("""
752+
You did not identify a class name in the subject line and there is no
753+
default set for this tracker. The subject must contain a class name or
754+
designator to indicate the 'topic' of the message. For example:
755+
Subject: [issue] This is a new issue
756+
- this will create a new issue in the tracker with the title 'This is
757+
a new issue'.
758+
Subject: [issue1234] This is a followup to issue 1234
759+
- this will append the message's contents to the existing issue 1234
760+
in the tracker.
761+
762+
Subject was: '%(subject)s'
742763
""") % locals()
743764

744765
# get the optional nodeid
@@ -770,7 +791,7 @@ def handle_message(self, message):
770791
if nodeid is None and not title:
771792
raise MailUsageError, _("""
772793
I cannot match your message to a node in the database - you need to either
773-
supply a full designator (with number, eg "[issue123]" or keep the
794+
supply a full designator (with number, eg "[issue123]") or keep the
774795
previous subject title intact so I can match that.
775796
776797
Subject was: "%(subject)s"

test/test_mailgw.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
# but WITHOUT ANY WARRANTY; without even the implied warranty of
99
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1010
#
11-
# $Id: test_mailgw.py,v 1.84 2007-01-28 13:49:21 forsberg Exp $
11+
# $Id: test_mailgw.py,v 1.85 2007-02-15 03:09:53 richard Exp $
1212

1313
# TODO: test bcc
1414

@@ -1160,6 +1160,22 @@ def testInvalidClassLoose(self):
11601160
11611161
Message-Id: <dummy_test_message_id>
11621162
1163+
''')
1164+
assert not os.path.exists(SENDMAILDEBUG)
1165+
self.assertEqual(self.db.issue.get(nodeid, 'title'),
1166+
'[frobulated] testing')
1167+
1168+
def testInvalidClassLooseReply(self):
1169+
self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1170+
nodeid = self._handle_mail('''Content-Type: text/plain;
1171+
charset="iso-8859-1"
1172+
From: Chef <[email protected]>
1173+
1174+
Subject: Re: [frobulated] testing
1175+
Cc: richard@test
1176+
1177+
Message-Id: <dummy_test_message_id>
1178+
11631179
''')
11641180
assert not os.path.exists(SENDMAILDEBUG)
11651181
self.assertEqual(self.db.issue.get(nodeid, 'title'),

0 commit comments

Comments
 (0)