Code

Fixed missing import in mailgw :(
[roundup.git] / roundup / mailgw.py
index a2c15e30658c7a203d9e7c5efdeaa32ea12bdb00..19151b2108934e9c711511fe468dcfcd023e0a7c 100644 (file)
@@ -72,13 +72,16 @@ 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. 
 
 an exception, the original message is bounced back to the sender with the
 explanatory message given in the exception. 
 
-$Id: mailgw.py,v 1.10 2001-08-07 00:24:42 richard Exp $
+$Id: mailgw.py,v 1.15 2001-08-30 06:01:17 richard Exp $
 '''
 
 
 import string, re, os, mimetools, cStringIO, smtplib, socket, binascii, quopri
 import traceback
 '''
 
 
 import string, re, os, mimetools, cStringIO, smtplib, socket, binascii, quopri
 import traceback
-import date
+import hyperdb, date
+
+class MailUsageError(ValueError):
+    pass
 
 class Message(mimetools.Message):
     ''' subclass mimetools.Message so we can retrieve the parts of the
 
 class Message(mimetools.Message):
     ''' subclass mimetools.Message so we can retrieve the parts of the
@@ -121,8 +124,17 @@ class MailGW:
         '''
         # ok, figure the subject, author, recipients and content-type
         message = Message(fp)
         '''
         # ok, figure the subject, author, recipients and content-type
         message = Message(fp)
+        m = []
         try:
             self.handle_message(message)
         try:
             self.handle_message(message)
+        except MailUsageError, value:
+            # bounce the message back to the sender with the usage message
+            fulldoc = '\n'.join(string.split(__doc__, '\n')[2:])
+            sendto = [message.getaddrlist('from')[0][1]]
+            m = ['Subject: Failed issue tracker submission', '']
+            m.append(str(value))
+            m.append('\nMail Gateway Help\n=================')
+            m.append(fulldoc)
         except:
             # bounce the message back to the sender with the error message
             sendto = [message.getaddrlist('from')[0][1]]
         except:
             # bounce the message back to the sender with the error message
             sendto = [message.getaddrlist('from')[0][1]]
@@ -140,6 +152,7 @@ class MailGW:
             except:
                 pass
             m.append(fp.read())
             except:
                 pass
             m.append(fp.read())
+        if m:
             try:
                 smtp = smtplib.SMTP(self.MAILHOST)
                 smtp.sendmail(self.ADMIN_EMAIL, sendto, '\n'.join(m))
             try:
                 smtp = smtplib.SMTP(self.MAILHOST)
                 smtp.sendmail(self.ADMIN_EMAIL, sendto, '\n'.join(m))
@@ -154,14 +167,36 @@ class MailGW:
         Parse the message as per the module docstring.
         '''
         # handle the subject line
         Parse the message as per the module docstring.
         '''
         # handle the subject line
-        m = subject_re.match(message.getheader('subject'))
+        subject = message.getheader('subject', '')
+        m = subject_re.match(subject)
         if not m:
         if not m:
-            raise ValueError, 'No [designator] found in subject "%s"'
+            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
+"topic" of the message. For example:
+    Subject: [issue] This is a new issue
+      - this will create a new issue in the tracker with the title "This is
+        a new issue".
+    Subject: [issue1234] This is a followup to issue 1234
+      - this will append the message's contents to the existing issue 1234
+        in the tracker.
+
+Subject was: "%s"
+'''%subject
         classname = m.group('classname')
         nodeid = m.group('nodeid')
         title = m.group('title').strip()
         subject_args = m.group('args')
         classname = m.group('classname')
         nodeid = m.group('nodeid')
         title = m.group('title').strip()
         subject_args = m.group('args')
-        cl = self.db.getclass(classname)
+        try:
+            cl = self.db.getclass(classname)
+        except KeyError:
+            raise MailUsageError, '''
+The class name you identified in the subject line ("%s") does not exist in the
+database.
+
+Valid class names are: %s
+Subject was: "%s"
+'''%(classname, ', '.join(self.db.getclasses()), subject)
         properties = cl.getprops()
         props = {}
         args = m.group('args')
         properties = cl.getprops()
         props = {}
         args = m.group('args')
@@ -170,17 +205,29 @@ class MailGW:
                 try:
                     key, value = prop.split('=')
                 except ValueError, message:
                 try:
                     key, value = prop.split('=')
                 except ValueError, message:
-                    raise ValueError, 'Args list not of form [arg=value,value,...;arg=value,value,value..]  (specific exception message was "%s")'%message
-                type =  properties[key]
-                if type.isStringType:
+                    raise MailUsageError, '''
+Subject argument list not of form [arg=value,value,...;arg=value,value...]
+   (specific exception message was "%s")
+
+Subject was: "%s"
+'''%(message, subject)
+                try:
+                    type =  properties[key]
+                except KeyError:
+                    raise MailUsageError, '''
+Subject argument list refers to an invalid property: "%s"
+
+Subject was: "%s"
+'''%(key, subject)
+                if isinstance(type, hyperdb.String):
                     props[key] = value 
                     props[key] = value 
-                elif type.isDateType:
+                elif isinstance(type, hyperdb.Date):
                     props[key] = date.Date(value)
                     props[key] = date.Date(value)
-                elif type.isIntervalType:
+                elif isinstance(type, hyperdb.Interval):
                     props[key] = date.Interval(value)
                     props[key] = date.Interval(value)
-                elif type.isLinkType:
+                elif isinstance(type, hyperdb.Link):
                     props[key] = value
                     props[key] = value
-                elif type.isMultilinkType:
+                elif isinstance(type, hyperdb.Multilink):
                     props[key] = value.split(',')
 
         # handle the users
                     props[key] = value.split(',')
 
         # handle the users
@@ -236,7 +283,10 @@ class MailGW:
                     attachments.append((name, part.gettype(), data))
 
             if content is None:
                     attachments.append((name, part.gettype(), data))
 
             if content is None:
-                raise ValueError, 'No text/plain part found'
+                raise MailUsageError, '''
+Roundup requires the submission to be plain text. The message parser could
+not find a text/plain part o use.
+'''
 
         elif content_type[:10] == 'multipart/':
             # skip over the intro to the first boundary
 
         elif content_type[:10] == 'multipart/':
             # skip over the intro to the first boundary
@@ -252,10 +302,16 @@ class MailGW:
                     # this one's our content
                     content = part.fp.read()
             if content is None:
                     # this one's our content
                     content = part.fp.read()
             if content is None:
-                raise ValueError, 'No text/plain part found'
+                raise MailUsageError, '''
+Roundup requires the submission to be plain text. The message parser could
+not find a text/plain part o use.
+'''
 
         elif content_type != 'text/plain':
 
         elif content_type != 'text/plain':
-            raise ValueError, 'No text/plain part found'
+            raise MailUsageError, '''
+Roundup requires the submission to be plain text. The message parser could
+not find a text/plain part o use.
+'''
 
         else:
             content = message.fp.read()
 
         else:
             content = message.fp.read()
@@ -277,7 +333,15 @@ class MailGW:
             message_id = self.db.msg.create(author=author,
                 recipients=recipients, date=date.Date('.'), summary=summary,
                 content=content, files=files)
             message_id = self.db.msg.create(author=author,
                 recipients=recipients, date=date.Date('.'), summary=summary,
                 content=content, files=files)
-            messages = cl.get(nodeid, 'messages')
+            try:
+                messages = cl.get(nodeid, 'messages')
+            except IndexError:
+                raise MailUsageError, '''
+The node specified by the designator in the subject of your message ("%s")
+does not exist.
+
+Subject was: "%s"
+'''%(nodeid, subject)
             messages.append(message_id)
             props['messages'] = messages
             cl.set(nodeid, **props)
             messages.append(message_id)
             props['messages'] = messages
             cl.set(nodeid, **props)
@@ -334,6 +398,21 @@ def parseContent(content, blank_line=re.compile(r'[\r\n]+\s*[\r\n]+'),
 
 #
 # $Log: not supported by cvs2svn $
 
 #
 # $Log: not supported by cvs2svn $
+# Revision 1.14  2001/08/13 23:02:54  richard
+# Make the mail parser a little more robust.
+#
+# Revision 1.13  2001/08/12 06:32:36  richard
+# using isinstance(blah, Foo) now instead of isFooType
+#
+# Revision 1.12  2001/08/08 01:27:00  richard
+# Added better error handling to mailgw.
+#
+# Revision 1.11  2001/08/08 00:08:03  richard
+# oops ;)
+#
+# Revision 1.10  2001/08/07 00:24:42  richard
+# stupid typo
+#
 # Revision 1.9  2001/08/07 00:15:51  richard
 # Added the copyright/license notice to (nearly) all files at request of
 # Bizar Software.
 # Revision 1.9  2001/08/07 00:15:51  richard
 # Added the copyright/license notice to (nearly) all files at request of
 # Bizar Software.