@@ -72,14 +72,17 @@ class node. Any parts of other types are each stored in separate files
7272an exception, the original message is bounced back to the sender with the
7373explanatory message given in the exception.
7474
75- $Id: mailgw.py,v 1.29 2001-11-07 05:29:26 richard Exp $
75+ $Id: mailgw.py,v 1.30 2001-11-09 22:33:28 richard Exp $
7676'''
7777
7878
7979import string , re , os , mimetools , cStringIO , smtplib , socket , binascii , quopri
8080import traceback
8181import hyperdb , date , password
8282
83+ class MailGWError (ValueError ):
84+ pass
85+
8386class MailUsageError (ValueError ):
8487 pass
8588
@@ -129,41 +132,63 @@ def handle_Message(self, message):
129132 handle errors in a different manner.
130133 '''
131134 m = []
132- try :
133- self .handle_message (message )
134- except MailUsageError , value :
135- # bounce the message back to the sender with the usage message
136- fulldoc = '\n ' .join (string .split (__doc__ , '\n ' )[2 :])
137- sendto = [message .getaddrlist ('from' )[0 ][1 ]]
138- m = ['Subject: Failed issue tracker submission' , '' ]
139- m .append (str (value ))
140- m .append ('\n \n Mail Gateway Help\n =================' )
141- m .append (fulldoc )
142- except :
143- # bounce the message back to the sender with the error message
144- sendto = [message .getaddrlist ('from' )[0 ][1 ]]
145- m = ['Subject: failed issue tracker submission' ]
135+ # in some rare cases, a particularly stuffed-up e-mail will make
136+ # its way into here... try to handle it gracefully
137+ sendto = message .getaddrlist ('from' )
138+ if sendto :
139+ try :
140+ self .handle_message (message )
141+ return
142+ except MailUsageError , value :
143+ # bounce the message back to the sender with the usage message
144+ fulldoc = '\n ' .join (string .split (__doc__ , '\n ' )[2 :])
145+ sendto = [sendto [0 ][1 ]]
146+ m = ['Subject: Failed issue tracker submission' , '' ]
147+ m .append (str (value ))
148+ m .append ('\n \n Mail Gateway Help\n =================' )
149+ m .append (fulldoc )
150+ except :
151+ # bounce the message back to the sender with the error message
152+ sendto = [sendto [0 ][1 ]]
153+ m = ['Subject: failed issue tracker submission' ]
154+ m .append ('' )
155+ # TODO as attachments?
156+ m .append ('---- traceback of failure ----' )
157+ s = cStringIO .StringIO ()
158+ import traceback
159+ traceback .print_exc (None , s )
160+ m .append (s .getvalue ())
161+ m .append ('---- failed message follows ----' )
162+ try :
163+ message .fp .seek (0 )
164+ except :
165+ pass
166+ m .append (message .fp .read ())
167+ else :
168+ # very bad-looking message - we don't even know who sent it
169+ sendto = [self .ADMIN_EMAIL ]
170+ m = ['Subject: badly formed message from mail gateway' ]
171+ m .append ('' )
172+ m .append ('The mail gateway retrieved a message which has no From:' )
173+ m .append ('line, indicating that it is corrupt. Please check your' )
174+ m .append ('mail gateway source.' )
146175 m .append ('' )
147- # TODO as attachments?
148- m .append ('---- traceback of failure ----' )
149- s = cStringIO .StringIO ()
150- import traceback
151- traceback .print_exc (None , s )
152- m .append (s .getvalue ())
153176 m .append ('---- failed message follows ----' )
154177 try :
155178 message .fp .seek (0 )
156179 except :
157180 pass
158181 m .append (message .fp .read ())
159- if m :
160- try :
161- smtp = smtplib .SMTP (self .MAILHOST )
162- smtp .sendmail (self .ADMIN_EMAIL , sendto , '\n ' .join (m ))
163- except socket .error , value :
164- return "Couldn't send confirmation email: mailhost %s" % value
165- except smtplib .SMTPException , value :
166- return "Couldn't send confirmation email: %s" % value
182+
183+ # now send the message
184+ try :
185+ smtp = smtplib .SMTP (self .MAILHOST )
186+ smtp .sendmail (self .ADMIN_EMAIL , sendto , '\n ' .join (m ))
187+ except socket .error , value :
188+ raise MailGWError , "Couldn't send confirmation email: " \
189+ "mailhost %s" % value
190+ except smtplib .SMTPException , value :
191+ raise MailGWError , "Couldn't send confirmation email: %s" % value
167192
168193 def handle_message (self , message ):
169194 ''' message - a Message instance
@@ -242,9 +267,25 @@ def handle_message(self, message):
242267 if isinstance (type , hyperdb .Password ):
243268 props [key ] = password .Password (value )
244269 elif isinstance (type , hyperdb .Date ):
245- props [key ] = date .Date (value )
270+ try :
271+ props [key ] = date .Date (value )
272+ except ValueError , message :
273+ raise UsageError , '''
274+ Subject argument list contains an invalid date for %s.
275+
276+ Error was: %s
277+ Subject was: "%s"
278+ ''' % (key , message , subject )
246279 elif isinstance (type , hyperdb .Interval ):
247- props [key ] = date .Interval (value )
280+ try :
281+ props [key ] = date .Interval (value )
282+ except ValueError , message :
283+ raise UsageError , '''
284+ Subject argument list contains an invalid date interval for %s.
285+
286+ Error was: %s
287+ Subject was: "%s"
288+ ''' % (key , message , subject )
248289 elif isinstance (type , hyperdb .Link ):
249290 props [key ] = value
250291 elif isinstance (type , hyperdb .Multilink ):
@@ -386,7 +427,13 @@ def handle_message(self, message):
386427 props ['status' ] == resolved_id ):
387428 props ['status' ] = chatting_id
388429
389- cl .set (nodeid , ** props )
430+ try :
431+ cl .set (nodeid , ** props )
432+ except (TypeError , IndexError , ValueError ), message :
433+ raise MailUsageError , '''
434+ There was a problem with the message you sent:
435+ %s
436+ ''' % message
390437 else :
391438 # If just an item class name is found there, we attempt to create a
392439 # new item of that class with its "messages" property initialized to
@@ -399,15 +446,35 @@ def handle_message(self, message):
399446 if properties .has_key ('assignedto' ) and \
400447 not props .has_key ('assignedto' ):
401448 props ['assignedto' ] = '1' # "admin"
449+
450+ # pre-set the issue to unread
402451 if properties .has_key ('status' ) and not props .has_key ('status' ):
403- props ['status' ] = '1' # "unread"
452+ try :
453+ # determine the id of 'unread'
454+ unread_id = self .db .status .lookup ('unread' )
455+ except KeyError :
456+ pass
457+ else :
458+ props ['status' ] = '1'
459+
460+ # set the title to the subject
404461 if properties .has_key ('title' ) and not props .has_key ('title' ):
405462 props ['title' ] = title
463+
464+ # pre-load the messages list and nosy list
406465 props ['messages' ] = [message_id ]
407466 props ['nosy' ] = props .get ('nosy' , []) + recipients
408467 props ['nosy' ].append (author )
409468 props ['nosy' ].sort ()
410- nodeid = cl .create (** props )
469+
470+ # and attempt to create the new node
471+ try :
472+ nodeid = cl .create (** props )
473+ except (TypeError , IndexError , ValueError ), message :
474+ raise MailUsageError , '''
475+ There was a problem with the message you sent:
476+ %s
477+ ''' % message
411478
412479def parseContent (content , blank_line = re .compile (r'[\r\n]+\s*[\r\n]+' ),
413480 eol = re .compile (r'[\r\n]+' ), signature = re .compile (r'^[>|\s]*[-_]+\s*$' )):
@@ -449,6 +516,12 @@ def parseContent(content, blank_line=re.compile(r'[\r\n]+\s*[\r\n]+'),
449516
450517#
451518# $Log: not supported by cvs2svn $
519+ # Revision 1.29 2001/11/07 05:29:26 richard
520+ # Modified roundup-mailgw so it can read e-mails from a local mail spool
521+ # file. Truncates the spool file after parsing.
522+ # Fixed a couple of small bugs introduced in roundup.mailgw when I started
523+ # the popgw.
524+ #
452525# Revision 1.28 2001/11/01 22:04:37 richard
453526# Started work on supporting a pop3-fetching server
454527# Fixed bugs:
0 commit comments