Mercurial > p > roundup > code
diff roundup/mailgw.py @ 475:a1a44636bace
Fix breakage caused by transaction changes.
Sorry for the huge checkin message - I was only intending to implement
[SF#496356] but I found a number of places where things had been
broken by transactions:
. modified ROUNDUPDBSENDMAILDEBUG to be SENDMAILDEBUG and hold a filename
for _all_ roundup-generated smtp messages to be sent to.
. the transaction cache had broken the roundupdb.Class set() reactors
. newly-created author users in the mailgw weren't being committed to the db
Stuff that made it into CHANGES.txt (ie. the stuff I was actually working
on when I found that stuff :):
. [SF#496356] Use threading in messages
. detectors were being registered multiple times
. added tests for mailgw
. much better attaching of erroneous messages in the mail gateway
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Wed, 02 Jan 2002 02:31:38 +0000 |
| parents | 103f521810f7 |
| children | 00450ff9c4e7 |
line wrap: on
line diff
--- a/roundup/mailgw.py Mon Dec 31 05:20:34 2001 +0000 +++ b/roundup/mailgw.py Wed Jan 02 02:31:38 2002 +0000 @@ -73,14 +73,17 @@ an exception, the original message is bounced back to the sender with the explanatory message given in the exception. -$Id: mailgw.py,v 1.45 2001-12-20 15:43:01 rochecompaan Exp $ +$Id: mailgw.py,v 1.46 2002-01-02 02:31:38 richard Exp $ ''' import string, re, os, mimetools, cStringIO, smtplib, socket, binascii, quopri +import time, random import traceback, MimeWriter import hyperdb, date, password +SENDMAILDEBUG = os.environ.get('SENDMAILDEBUG', '') + class MailGWError(ValueError): pass @@ -180,14 +183,18 @@ subject='Badly formed message from mail gateway') # now send the message - try: - smtp = smtplib.SMTP(self.MAILHOST) - smtp.sendmail(self.ADMIN_EMAIL, sendto, m.getvalue()) - except socket.error, value: - raise MailGWError, "Couldn't send confirmation email: "\ - "mailhost %s"%value - except smtplib.SMTPException, value: - raise MailGWError, "Couldn't send confirmation email: %s"%value + if SENDMAILDEBUG: + open(SENDMAILDEBUG, 'w').write('From: %s\nTo: %s\n%s\n'%( + self.ADMIN_EMAIL, ', '.join(sendto), m.getvalue())) + else: + try: + smtp = smtplib.SMTP(self.MAILHOST) + smtp.sendmail(self.ADMIN_EMAIL, sendto, m.getvalue()) + except socket.error, value: + raise MailGWError, "Couldn't send error email: "\ + "mailhost %s"%value + except smtplib.SMTPException, value: + raise MailGWError, "Couldn't send error email: %s"%value def bounce_message(self, message, sendto, error, subject='Failed issue tracker submission'): @@ -210,20 +217,24 @@ # reconstruct the original message m = cStringIO.StringIO() w = MimeWriter.MimeWriter(m) + # default the content_type, just in case... + content_type = 'text/plain' + # add the headers except the content-type for header in message.headers: header_name = header.split(':')[0] - if message.getheader(header_name): - w.addheader(header_name,message.getheader(header_name)) - body = w.startbody('text/plain') - try: - message.fp.seek(0) - except: - pass + if header_name.lower() == 'content-type': + content_type = message.getheader(header_name) + elif message.getheader(header_name): + w.addheader(header_name, message.getheader(header_name)) + # now attach the message body + body = w.startbody(content_type) + message.rewindbody() body.write(message.fp.read()) # attach the original message to the returned message part = writer.nextpart() part.addheader('Content-Disposition','attachment') + part.addheader('Content-Description','Message that caused the error') part.addheader('Content-Transfer-Encoding', '7bit') body = part.startbody('message/rfc822') body.write(m.getvalue()) @@ -371,12 +382,11 @@ else: props[key] = [v] - # # handle the users # - # Don't create users if ANONYMOUS_ACCESS is denied + # Don't create users if ANONYMOUS_REGISTER is denied if self.ANONYMOUS_ACCESS == 'deny': create = 0 else: @@ -389,6 +399,10 @@ Unknown address: %s '''%message.getaddrlist('from')[0][1] + + # the author may have been created - make sure the change is + # committed before we reopen the database + self.db.commit() # reopen the database as the author username = self.db.user.get(author, 'username') @@ -401,11 +415,24 @@ recipients = [] tracker_email = self.ISSUE_TRACKER_EMAIL.lower() for recipient in message.getaddrlist('to') + message.getaddrlist('cc'): - if recipient[1].strip().lower() == tracker_email: + r = recipient[1].strip().lower() + if r == tracker_email or not r: continue recipients.append(self.db.uidFromAddress(recipient)) + # + # handle message-id and in-reply-to + # + messageid = message.getheader('message-id') + inreplyto = message.getheader('in-reply-to') or '' + # generate a messageid if there isn't one + if not messageid: + messageid = "%s.%s.%s%s-%s"%(time.time(), random.random(), + classname, nodeid, self.MAIL_DOMAIN) + + # # now handle the body - find the message + # content_type = message.gettype() attachments = [] if content_type == 'multipart/mixed': @@ -487,13 +514,17 @@ summary, content = parseContent(content) - # handle the files + # + # handle the attachments + # files = [] for (name, mime_type, data) in attachments: files.append(self.db.file.create(type=mime_type, name=name, content=data)) + # # now handle the db stuff + # if nodeid: # If an item designator (class name and id number) is found there, # the newly created "msg" node is added to the "messages" property @@ -536,10 +567,11 @@ props['nosy'].append(assignedto) except: pass - + message_id = self.db.msg.create(author=author, recipients=recipients, date=date.Date('.'), summary=summary, - content=content, files=files) + content=content, files=files, messageid=messageid, + inreplyto=inreplyto) try: messages = cl.get(nodeid, 'messages') except IndexError: @@ -569,7 +601,8 @@ # contain any new "file" nodes. message_id = self.db.msg.create(author=author, recipients=recipients, date=date.Date('.'), summary=summary, - content=content, files=files) + content=content, files=files, messageid=messageid, + inreplyto=inreplyto) # pre-set the issue to unread if properties.has_key('status') and not props.has_key('status'): @@ -585,8 +618,10 @@ if properties.has_key('title') and not props.has_key('title'): props['title'] = title - # pre-load the messages list and nosy list + # pre-load the messages list props['messages'] = [message_id] + + # set up (clean) the nosy list nosy = props.get('nosy', []) n = {} for value in nosy: @@ -596,18 +631,30 @@ continue if n.has_key(nid): continue n[nid] = 1 - props['nosy'] = n.keys() + recipients + props['nosy'] = n.keys() + # add on the recipients of the message + for recipient in recipients: + if not n.has_key(recipient): + props['nosy'].append(recipient) + n[recipient] = 1 + # add the author to the nosy list if not n.has_key(author): props['nosy'].append(author) n[author] = 1 + # add assignedto to the nosy list - try: - assignedto = self.db.user.lookup(props['assignedto']) + if properties.has_key('assignedto') and props.has_key('assignedto'): + try: + assignedto = self.db.user.lookup(props['assignedto']) + except KeyError: + raise MailUsageError, ''' +There was a problem with the message you sent: + Assignedto user '%s' doesn't exist +'''%props['assignedto'] if not n.has_key(assignedto): props['nosy'].append(assignedto) - except: - pass + n[assignedto] = 1 # and attempt to create the new node try: @@ -661,6 +708,14 @@ # # $Log: not supported by cvs2svn $ +# Revision 1.45 2001/12/20 15:43:01 rochecompaan +# Features added: +# . Multilink properties are now displayed as comma separated values in +# a textbox +# . The add user link is now only visible to the admin user +# . Modified the mail gateway to reject submissions from unknown +# addresses if ANONYMOUS_ACCESS is denied +# # Revision 1.44 2001/12/18 15:30:34 rochecompaan # Fixed bugs: # . Fixed file creation and retrieval in same transaction in anydbm
