Mercurial > p > roundup > code
changeset 2631:2bbcfc80ba5b
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
| author | Alexander Smishlajev <a1s@users.sourceforge.net> |
|---|---|
| date | Mon, 26 Jul 2004 09:29:22 +0000 |
| parents | a65bae7af6d1 |
| children | 9c55f2bc5961 |
| files | roundup/mailgw.py |
| diffstat | 1 files changed, 49 insertions(+), 46 deletions(-) [+] |
line wrap: on
line diff
--- a/roundup/mailgw.py Mon Jul 26 09:13:17 2004 +0000 +++ b/roundup/mailgw.py Mon Jul 26 09:29:22 2004 +0000 @@ -25,7 +25,7 @@ examined. The text/plain subparts are assembled to form the textual body of the message, to be stored in the file associated with a "msg" class node. Any parts of other types are each stored in separate files - and given "file" class nodes that are linked to the "msg" node. + and given "file" class nodes that are linked to the "msg" node. . In a multipart/alternative message or part, we look for a text/plain subpart and ignore the other parts. @@ -35,7 +35,7 @@ section in the message body. The message body is divided into sections by blank lines. Sections where the second and all subsequent lines begin with a ">" or "|" character are considered "quoting sections". The first line of -the first non-quoting section becomes the summary of the message. +the first non-quoting section becomes the summary of the message. Addresses --------- @@ -48,23 +48,23 @@ address. (The web interface does not permit logins for users with no passwords.) If we prefer to reject mail from outside sources, we can simply register an auditor on the "user" class that prevents the creation of user -nodes with no passwords. +nodes with no passwords. Actions ------- The subject line of the incoming message is examined to determine whether the message is an attempt to create a new item or to discuss an existing item. A designator enclosed in square brackets is sought as the first thing -on the subject line (after skipping any "Fwd:" or "Re:" prefixes). +on the subject line (after skipping any "Fwd:" or "Re:" prefixes). If an item designator (class name and id number) is found there, the newly created "msg" node is added to the "messages" property for that item, and -any new "file" nodes are added to the "files" property for the item. +any new "file" nodes are added to the "files" property for the item. If just an item class name is found there, we attempt to create a new item of that class with its "messages" property initialized to contain the new "msg" node and its "files" property initialized to contain any new "file" -nodes. +nodes. Triggers -------- @@ -72,9 +72,9 @@ set() method to add the message to the item's spool; in the second case we are calling the create() method to create a new node). If an auditor raises an exception, the original message is bounced back to the sender with the -explanatory message given in the exception. +explanatory message given in the exception. -$Id: mailgw.py,v 1.151 2004-07-14 01:12:25 richard Exp $ +$Id: mailgw.py,v 1.152 2004-07-26 09:29:22 a1s Exp $ """ __docformat__ = 'restructuredtext' @@ -211,7 +211,7 @@ data = None if encoding == 'base64': # BUG: is base64 really used for text encoding or - # are we inserting zip files here. + # are we inserting zip files here. data = binascii.a2b_base64(self.fp.read()) elif encoding == 'quoted-printable': # the quopri module wants to work with files @@ -223,7 +223,7 @@ else: # take it as text data = self.fp.read() - + # Encode message to unicode charset = rfc2822.unaliasCharset(self.getparam("charset")) if charset: @@ -234,11 +234,11 @@ else: # Leave message content as is edata = data - + return edata # General multipart handling: - # Take the first text/plain part, anything else is considered an + # Take the first text/plain part, anything else is considered an # attachment. # multipart/mixed: # Multiple "unrelated" parts. @@ -246,12 +246,12 @@ # Like multipart/mixed, except that we'd only want one of the # alternatives. Generally a top-level part from MUAs sending HTML # mail - there will be a text/plain version. - # multipart/signed (rfc 1847): - # The control information is carried in the second of the two + # multipart/signed (rfc 1847): + # The control information is carried in the second of the two # required body parts. # ACTION: Default, so if content is text/plain we get it. - # multipart/encrypted (rfc 1847): - # The control information is carried in the first of the two + # multipart/encrypted (rfc 1847): + # The control information is carried in the first of the two # required body parts. # ACTION: Not handleable as the content is encrypted. # multipart/related (rfc 1872, 2112, 2387): @@ -261,7 +261,7 @@ # ACTION: Default, if we must. # multipart/report (rfc 1892): # e.g. mail system delivery status reports. - # ACTION: Default. Could be ignored or used for Delivery Notification + # ACTION: Default. Could be ignored or used for Delivery Notification # flagging. # multipart/form-data: # For web forms only. @@ -271,7 +271,7 @@ content_type = self.gettype() content = None attachments = [] - + if content_type == 'text/plain': content = self.getbody() elif content_type[:10] == 'multipart/': @@ -284,7 +284,7 @@ content = new_content elif new_content: attachments.append(part.as_attachment()) - + attachments.extend(new_attach) elif (parent_type == 'multipart/signed' and content_type == 'application/pgp-signature'): @@ -308,7 +308,7 @@ (\[(?P<classname>[^\d\s]+) # [issue.. (?P<nodeid>\d+)? # ..1234] \])?\s* - (?P<title>[^[]+)? # issue title + (?P<title>[^[]+)? # issue title "? # Trailing " (\[(?P<args>.+?)\])? # [prop=value] ''', re.IGNORECASE|re.VERBOSE) @@ -470,7 +470,7 @@ server.pass_(password) numMessages = len(server.list()[1]) for i in range(1, numMessages+1): - # retr: returns + # retr: returns # [ pop response e.g. '+OK 459 octets', # [ array of message lines ], # number of octets ] @@ -582,13 +582,16 @@ if (message.getheader('precedence', '') == 'bulk'): raise IgnoreBulk + # config is used many times in this method. + # make local variable for easier access + config = self.instance.config + # 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 # use the embedded issue number as our issue -# if hasattr(self.instance.config, 'EMAIL_ISSUE_ADDRESS_RE') and \ -# self.instance.config.EMAIL_ISSUE_ADDRESS_RE: -# issue_re = self.instance.config.EMAIL_ISSUE_ADDRESS_RE +# issue_re = config['MAILGW_ISSUE_ADDRESS_RE'] +# if issue_re: # for header in ['to', 'cc', 'bcc']: # addresses = message.getheader(header, '') # if addresses: @@ -629,16 +632,15 @@ if otk: self.db.confirm_registration(otk.group('otk')) subject = 'Your registration to %s is complete' % \ - self.instance.config.TRACKER_NAME + config['TRACKER_NAME'] sendto = [from_list[0][1]] - self.mailer.standard_message(sendto, subject, '') + self.mailer.standard_message(sendto, subject, '') return - elif hasattr(self.instance.config, 'MAIL_DEFAULT_CLASS') and \ - self.instance.config.MAIL_DEFAULT_CLASS: - classname = self.instance.config.MAIL_DEFAULT_CLASS else: - # fail - m = None + classname = config['MAILGW_DEFAULT_CLASS'] + if not classname: + # fail + m = None if not m: raise MailUsageError, """ @@ -724,12 +726,15 @@ for option, propstring in self.arguments: if option in ( '-C', '--class'): current_class = propstring.strip() + # XXX this is not flexible enough. + # we should chect for subclasses of these classes, + # not for the class name... if current_class not in ('msg', 'file', 'user', 'issue'): raise MailUsageError, ''' The mail gateway is not properly set up. Please contact %s and have them fix the incorrect class specified as: %s -'''%(self.instance.config.ADMIN_EMAIL, current_class) +''' % (config['ADMIN_EMAIL'], current_class) if option in ('-S', '--set'): if current_class == 'issue' : errors, issue_props = setPropArrayFromString(self, @@ -751,7 +756,7 @@ The mail gateway is not properly set up. Please contact %s and have them fix the incorrect properties: %s -'''%(self.instance.config.ADMIN_EMAIL, errors) +'''%(config['ADMIN_EMAIL'], errors) # # handle the users @@ -803,7 +808,7 @@ # now update the recipients list recipients = [] - tracker_email = self.instance.config.TRACKER_EMAIL.lower() + tracker_email = config['TRACKER_EMAIL'].lower() for recipient in message.getaddrlist('to') + message.getaddrlist('cc'): r = recipient[1].strip().lower() if r == tracker_email or not r: @@ -849,7 +854,7 @@ # generate a messageid if there isn't one if not messageid: messageid = "<%s.%s.%s%s@%s>"%(time.time(), random.random(), - classname, nodeid, self.instance.config.MAIL_DOMAIN) + classname, nodeid, config['MAIL_DOMAIN']) # now handle the body - find the message content, attachments = message.extract_content() @@ -858,19 +863,17 @@ Roundup requires the submission to be plain text. The message parser could not find a text/plain part to use. ''' - + # figure how much we should muck around with the email body - keep_citations = getattr(self.instance.config, 'EMAIL_KEEP_QUOTED_TEXT', - 'no') == 'yes' - keep_body = getattr(self.instance.config, 'EMAIL_LEAVE_BODY_UNCHANGED', - 'no') == 'yes' + keep_citations = config['MAILGW_KEEP_QUOTED_TEXT'] + keep_body = config['MAILGW_LEAVE_BODY_UNCHANGED'] # parse the body of the message, stripping out bits as appropriate summary, content = parseContent(content, keep_citations, keep_body) content = content.strip() - # + # # handle the attachments # if properties.has_key('files'): @@ -895,7 +898,7 @@ # pre-load the files list props['files'] = files - # + # # create the message if there's a message body (content) # if (content and properties.has_key('messages')): @@ -942,7 +945,7 @@ return nodeid - + def setPropArrayFromString(self, cl, propString, nodeid=None): ''' takes string of form prop=value,value;prop2=value and returns (error, prop[..]) @@ -1042,13 +1045,13 @@ def parseContent(content, keep_citations, keep_body, blank_line=re.compile(r'[\r\n]+\s*[\r\n]+'), - eol=re.compile(r'[\r\n]+'), + eol=re.compile(r'[\r\n]+'), signature=re.compile(r'^[>|\s]*-- ?$'), original_msg=re.compile(r'^[>|\s]*-----\s?Original Message\s?-----$')): ''' The message body is divided into sections by blank lines. Sections where the second and all subsequent lines begin with a ">" or "|" character are considered "quoting sections". The first line of - the first non-quoting section becomes the summary of the message. + the first non-quoting section becomes the summary of the message. If keep_citations is true, then we keep the "quoting sections" in the content. @@ -1122,4 +1125,4 @@ return summary, content -# vim: set filetype=python sts=4 sw=4 et si +# vim: set filetype=python sts=4 sw=4 et si :
