diff roundup/mailgw.py @ 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 58848e3b6bb8
children 1df7d4a41da4
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 :

Roundup Issue Tracker: http://roundup-tracker.org/