Skip to content

Commit 5007a59

Browse files
author
Alexander Smishlajev
committed
MailGW.handle_message():
as config is used many times in this method, have a local variable instead of going through self.instance.config each time; change config attribute access to container (item) access; where possible, avoid duplicate computing of config settings; fix MAILGW_KEEP_QUOTED_TEXT and MAILGW_LEAVE_BODY_UNCHANGED - config values are boolean now; trim trailing spaces, fix vim modeline
1 parent 1743a1d commit 5007a59

File tree

1 file changed

+49
-46
lines changed

1 file changed

+49
-46
lines changed

roundup/mailgw.py

Lines changed: 49 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
examined. The text/plain subparts are assembled to form the textual
2626
body of the message, to be stored in the file associated with a "msg"
2727
class node. Any parts of other types are each stored in separate files
28-
and given "file" class nodes that are linked to the "msg" node.
28+
and given "file" class nodes that are linked to the "msg" node.
2929
. In a multipart/alternative message or part, we look for a text/plain
3030
subpart and ignore the other parts.
3131
@@ -35,7 +35,7 @@ class node. Any parts of other types are each stored in separate files
3535
section in the message body. The message body is divided into sections by
3636
blank lines. Sections where the second and all subsequent lines begin with
3737
a ">" or "|" character are considered "quoting sections". The first line of
38-
the first non-quoting section becomes the summary of the message.
38+
the first non-quoting section becomes the summary of the message.
3939
4040
Addresses
4141
---------
@@ -48,33 +48,33 @@ class node. Any parts of other types are each stored in separate files
4848
address. (The web interface does not permit logins for users with no
4949
passwords.) If we prefer to reject mail from outside sources, we can simply
5050
register an auditor on the "user" class that prevents the creation of user
51-
nodes with no passwords.
51+
nodes with no passwords.
5252
5353
Actions
5454
-------
5555
The subject line of the incoming message is examined to determine whether
5656
the message is an attempt to create a new item or to discuss an existing
5757
item. A designator enclosed in square brackets is sought as the first thing
58-
on the subject line (after skipping any "Fwd:" or "Re:" prefixes).
58+
on the subject line (after skipping any "Fwd:" or "Re:" prefixes).
5959
6060
If an item designator (class name and id number) is found there, the newly
6161
created "msg" node is added to the "messages" property for that item, and
62-
any new "file" nodes are added to the "files" property for the item.
62+
any new "file" nodes are added to the "files" property for the item.
6363
6464
If just an item class name is found there, we attempt to create a new item
6565
of that class with its "messages" property initialized to contain the new
6666
"msg" node and its "files" property initialized to contain any new "file"
67-
nodes.
67+
nodes.
6868
6969
Triggers
7070
--------
7171
Both cases may trigger detectors (in the first case we are calling the
7272
set() method to add the message to the item's spool; in the second case we
7373
are calling the create() method to create a new node). If an auditor raises
7474
an exception, the original message is bounced back to the sender with the
75-
explanatory message given in the exception.
75+
explanatory message given in the exception.
7676
77-
$Id: mailgw.py,v 1.151 2004-07-14 01:12:25 richard Exp $
77+
$Id: mailgw.py,v 1.152 2004-07-26 09:29:22 a1s Exp $
7878
"""
7979
__docformat__ = 'restructuredtext'
8080

@@ -211,7 +211,7 @@ def getbody(self):
211211
data = None
212212
if encoding == 'base64':
213213
# BUG: is base64 really used for text encoding or
214-
# are we inserting zip files here.
214+
# are we inserting zip files here.
215215
data = binascii.a2b_base64(self.fp.read())
216216
elif encoding == 'quoted-printable':
217217
# the quopri module wants to work with files
@@ -223,7 +223,7 @@ def getbody(self):
223223
else:
224224
# take it as text
225225
data = self.fp.read()
226-
226+
227227
# Encode message to unicode
228228
charset = rfc2822.unaliasCharset(self.getparam("charset"))
229229
if charset:
@@ -234,24 +234,24 @@ def getbody(self):
234234
else:
235235
# Leave message content as is
236236
edata = data
237-
237+
238238
return edata
239239

240240
# General multipart handling:
241-
# Take the first text/plain part, anything else is considered an
241+
# Take the first text/plain part, anything else is considered an
242242
# attachment.
243243
# multipart/mixed:
244244
# Multiple "unrelated" parts.
245245
# multipart/Alternative (rfc 1521):
246246
# Like multipart/mixed, except that we'd only want one of the
247247
# alternatives. Generally a top-level part from MUAs sending HTML
248248
# mail - there will be a text/plain version.
249-
# multipart/signed (rfc 1847):
250-
# The control information is carried in the second of the two
249+
# multipart/signed (rfc 1847):
250+
# The control information is carried in the second of the two
251251
# required body parts.
252252
# ACTION: Default, so if content is text/plain we get it.
253-
# multipart/encrypted (rfc 1847):
254-
# The control information is carried in the first of the two
253+
# multipart/encrypted (rfc 1847):
254+
# The control information is carried in the first of the two
255255
# required body parts.
256256
# ACTION: Not handleable as the content is encrypted.
257257
# multipart/related (rfc 1872, 2112, 2387):
@@ -261,7 +261,7 @@ def getbody(self):
261261
# ACTION: Default, if we must.
262262
# multipart/report (rfc 1892):
263263
# e.g. mail system delivery status reports.
264-
# ACTION: Default. Could be ignored or used for Delivery Notification
264+
# ACTION: Default. Could be ignored or used for Delivery Notification
265265
# flagging.
266266
# multipart/form-data:
267267
# For web forms only.
@@ -271,7 +271,7 @@ def extract_content(self, parent_type=None):
271271
content_type = self.gettype()
272272
content = None
273273
attachments = []
274-
274+
275275
if content_type == 'text/plain':
276276
content = self.getbody()
277277
elif content_type[:10] == 'multipart/':
@@ -284,7 +284,7 @@ def extract_content(self, parent_type=None):
284284
content = new_content
285285
elif new_content:
286286
attachments.append(part.as_attachment())
287-
287+
288288
attachments.extend(new_attach)
289289
elif (parent_type == 'multipart/signed' and
290290
content_type == 'application/pgp-signature'):
@@ -308,7 +308,7 @@ class MailGW:
308308
(\[(?P<classname>[^\d\s]+) # [issue..
309309
(?P<nodeid>\d+)? # ..1234]
310310
\])?\s*
311-
(?P<title>[^[]+)? # issue title
311+
(?P<title>[^[]+)? # issue title
312312
"? # Trailing "
313313
(\[(?P<args>.+?)\])? # [prop=value]
314314
''', re.IGNORECASE|re.VERBOSE)
@@ -470,7 +470,7 @@ def do_pop(self, server, user='', password='', apop=0):
470470
server.pass_(password)
471471
numMessages = len(server.list()[1])
472472
for i in range(1, numMessages+1):
473-
# retr: returns
473+
# retr: returns
474474
# [ pop response e.g. '+OK 459 octets',
475475
# [ array of message lines ],
476476
# number of octets ]
@@ -582,13 +582,16 @@ def handle_message(self, message):
582582
if (message.getheader('precedence', '') == 'bulk'):
583583
raise IgnoreBulk
584584

585+
# config is used many times in this method.
586+
# make local variable for easier access
587+
config = self.instance.config
588+
585589
# XXX Don't enable. This doesn't work yet.
586590
# "[^A-z.]tracker\+(?P<classname>[^\d\s]+)(?P<nodeid>\d+)\@some.dom.ain[^A-z.]"
587591
# handle delivery to addresses like:[email protected]
588592
# use the embedded issue number as our issue
589-
# if hasattr(self.instance.config, 'EMAIL_ISSUE_ADDRESS_RE') and \
590-
# self.instance.config.EMAIL_ISSUE_ADDRESS_RE:
591-
# issue_re = self.instance.config.EMAIL_ISSUE_ADDRESS_RE
593+
# issue_re = config['MAILGW_ISSUE_ADDRESS_RE']
594+
# if issue_re:
592595
# for header in ['to', 'cc', 'bcc']:
593596
# addresses = message.getheader(header, '')
594597
# if addresses:
@@ -629,16 +632,15 @@ def handle_message(self, message):
629632
if otk:
630633
self.db.confirm_registration(otk.group('otk'))
631634
subject = 'Your registration to %s is complete' % \
632-
self.instance.config.TRACKER_NAME
635+
config['TRACKER_NAME']
633636
sendto = [from_list[0][1]]
634-
self.mailer.standard_message(sendto, subject, '')
637+
self.mailer.standard_message(sendto, subject, '')
635638
return
636-
elif hasattr(self.instance.config, 'MAIL_DEFAULT_CLASS') and \
637-
self.instance.config.MAIL_DEFAULT_CLASS:
638-
classname = self.instance.config.MAIL_DEFAULT_CLASS
639639
else:
640-
# fail
641-
m = None
640+
classname = config['MAILGW_DEFAULT_CLASS']
641+
if not classname:
642+
# fail
643+
m = None
642644

643645
if not m:
644646
raise MailUsageError, """
@@ -724,12 +726,15 @@ def handle_message(self, message):
724726
for option, propstring in self.arguments:
725727
if option in ( '-C', '--class'):
726728
current_class = propstring.strip()
729+
# XXX this is not flexible enough.
730+
# we should chect for subclasses of these classes,
731+
# not for the class name...
727732
if current_class not in ('msg', 'file', 'user', 'issue'):
728733
raise MailUsageError, '''
729734
The mail gateway is not properly set up. Please contact
730735
%s and have them fix the incorrect class specified as:
731736
%s
732-
'''%(self.instance.config.ADMIN_EMAIL, current_class)
737+
''' % (config['ADMIN_EMAIL'], current_class)
733738
if option in ('-S', '--set'):
734739
if current_class == 'issue' :
735740
errors, issue_props = setPropArrayFromString(self,
@@ -751,7 +756,7 @@ def handle_message(self, message):
751756
The mail gateway is not properly set up. Please contact
752757
%s and have them fix the incorrect properties:
753758
%s
754-
'''%(self.instance.config.ADMIN_EMAIL, errors)
759+
'''%(config['ADMIN_EMAIL'], errors)
755760

756761
#
757762
# handle the users
@@ -803,7 +808,7 @@ def handle_message(self, message):
803808

804809
# now update the recipients list
805810
recipients = []
806-
tracker_email = self.instance.config.TRACKER_EMAIL.lower()
811+
tracker_email = config['TRACKER_EMAIL'].lower()
807812
for recipient in message.getaddrlist('to') + message.getaddrlist('cc'):
808813
r = recipient[1].strip().lower()
809814
if r == tracker_email or not r:
@@ -849,7 +854,7 @@ def handle_message(self, message):
849854
# generate a messageid if there isn't one
850855
if not messageid:
851856
messageid = "<%s.%s.%s%s@%s>"%(time.time(), random.random(),
852-
classname, nodeid, self.instance.config.MAIL_DOMAIN)
857+
classname, nodeid, config['MAIL_DOMAIN'])
853858

854859
# now handle the body - find the message
855860
content, attachments = message.extract_content()
@@ -858,19 +863,17 @@ def handle_message(self, message):
858863
Roundup requires the submission to be plain text. The message parser could
859864
not find a text/plain part to use.
860865
'''
861-
866+
862867
# figure how much we should muck around with the email body
863-
keep_citations = getattr(self.instance.config, 'EMAIL_KEEP_QUOTED_TEXT',
864-
'no') == 'yes'
865-
keep_body = getattr(self.instance.config, 'EMAIL_LEAVE_BODY_UNCHANGED',
866-
'no') == 'yes'
868+
keep_citations = config['MAILGW_KEEP_QUOTED_TEXT']
869+
keep_body = config['MAILGW_LEAVE_BODY_UNCHANGED']
867870

868871
# parse the body of the message, stripping out bits as appropriate
869872
summary, content = parseContent(content, keep_citations,
870873
keep_body)
871874
content = content.strip()
872875

873-
#
876+
#
874877
# handle the attachments
875878
#
876879
if properties.has_key('files'):
@@ -895,7 +898,7 @@ def handle_message(self, message):
895898
# pre-load the files list
896899
props['files'] = files
897900

898-
#
901+
#
899902
# create the message if there's a message body (content)
900903
#
901904
if (content and properties.has_key('messages')):
@@ -942,7 +945,7 @@ def handle_message(self, message):
942945

943946
return nodeid
944947

945-
948+
946949
def setPropArrayFromString(self, cl, propString, nodeid=None):
947950
''' takes string of form prop=value,value;prop2=value
948951
and returns (error, prop[..])
@@ -1042,13 +1045,13 @@ def uidFromAddress(db, address, create=1, **user_props):
10421045

10431046
def parseContent(content, keep_citations, keep_body,
10441047
blank_line=re.compile(r'[\r\n]+\s*[\r\n]+'),
1045-
eol=re.compile(r'[\r\n]+'),
1048+
eol=re.compile(r'[\r\n]+'),
10461049
signature=re.compile(r'^[>|\s]*-- ?$'),
10471050
original_msg=re.compile(r'^[>|\s]*-----\s?Original Message\s?-----$')):
10481051
''' The message body is divided into sections by blank lines.
10491052
Sections where the second and all subsequent lines begin with a ">"
10501053
or "|" character are considered "quoting sections". The first line of
1051-
the first non-quoting section becomes the summary of the message.
1054+
the first non-quoting section becomes the summary of the message.
10521055
10531056
If keep_citations is true, then we keep the "quoting sections" in the
10541057
content.
@@ -1122,4 +1125,4 @@ def parseContent(content, keep_citations, keep_body,
11221125

11231126
return summary, content
11241127

1125-
# vim: set filetype=python sts=4 sw=4 et si
1128+
# vim: set filetype=python sts=4 sw=4 et si :

0 commit comments

Comments
 (0)