From a843c3dcb4912b1c9554da696238c00c8670b8dc Mon Sep 17 00:00:00 2001 From: richard Date: Tue, 13 Apr 2004 04:11:49 +0000 Subject: [PATCH] added IMAP support to mail gateway (sf rfe 934000) git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@2280 57a73879-2fb5-44c3-a270-3262357dd7e2 --- CHANGES.txt | 2 + roundup/mailgw.py | 77 ++++++++++++++++++++++++++++++- roundup/scripts/roundup_mailgw.py | 27 ++++++++++- 3 files changed, 103 insertions(+), 3 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index bd4542b..e0d24b8 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -11,6 +11,7 @@ Feature: - roundup-server now uses the ForkingMixin - added another sample detector "creator_resolution" - added search_checkboxes as an option for the search form +- added IMAP support to mail gateway (sf rfe 934000) Fixed: - mysql and postgresql schema mutation now handle added Multilinks @@ -142,6 +143,7 @@ Fixed: - paging in classhelp popup was broken - socket timeout error logging can fail - hyperlink designators in message display (sf bug 931828) +- don't match retired items in RDBMS stringFind 2004-04-01 0.6.8 diff --git a/roundup/mailgw.py b/roundup/mailgw.py index 47d0831..35cc902 100644 --- a/roundup/mailgw.py +++ b/roundup/mailgw.py @@ -15,6 +15,8 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # +# vim: ts=4 sw=4 expandtab +# """An e-mail gateway for Roundup. @@ -72,7 +74,7 @@ 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. -$Id: mailgw.py,v 1.146 2004-03-26 00:44:11 richard Exp $ +$Id: mailgw.py,v 1.147 2004-04-13 04:11:06 richard Exp $ """ __docformat__ = 'restructuredtext' @@ -366,6 +368,79 @@ class MailGW: fcntl.flock(f.fileno(), FCNTL.LOCK_UN) return 0 + def do_imap(self, server, user='', password='', mailbox='', ssl=False): + ''' Do an IMAP connection + ''' + import getpass, imaplib, socket + try: + if not user: + user = raw_input('User: ') + if not password: + password = getpass.getpass() + except (KeyboardInterrupt, EOFError): + # Ctrl C or D maybe also Ctrl Z under Windows. + print "\nAborted by user." + return 1 + # open a connection to the server and retrieve all messages + try: + if ssl: + print 'Trying server "%s" with ssl' % server + server = imaplib.IMAP4_SSL(server) + else: + print 'Trying server %s without ssl' % server + server = imaplib.IMAP4(server) + except imaplib.IMAP4.error, e: + print 'IMAP server error:', e + return 1 + except socket.error, e: + print 'SOCKET error:', e + return 1 + except socket.sslerror, e: + print 'SOCKET ssl error:', e + return 1 + + try: + server.login(user, password) + except imaplib.IMAP4.error, e: + print 'Login failure:', e + return 1 + + try: + if not mailbox: + #print 'Using INBOX' + (typ, data) = server.select() + else: + #print 'Using mailbox' , mailbox + (typ, data) = server.select(mailbox=mailbox) + if typ != 'OK': + print 'Failed to get mailbox "%s": %s' % (mailbox, data) + return 1 + try: + numMessages = int(data[0]) + #print 'Found %s messages' % numMessages + except ValueError: + print 'Invalid return value from mailbox' + return 1 + for i in range(1, numMessages+1): + #print 'Processing message ', i + (typ, data) = server.fetch(str(i), '(RFC822)') + #This marks the message as deleted. + server.store(str(i), '+FLAGS', r'(\Deleted)') + #This is the raw text of the message + s = cStringIO.StringIO(data[0][1]) + s.seek(0) + self.handle_Message(Message(s)) + server.close() + finally: + try: + server.expunge() + except: + pass + server.logout() + + return 0 + + def do_apop(self, server, user='', password=''): ''' Do authentication POP ''' diff --git a/roundup/scripts/roundup_mailgw.py b/roundup/scripts/roundup_mailgw.py index 8695aee..33633ad 100644 --- a/roundup/scripts/roundup_mailgw.py +++ b/roundup/scripts/roundup_mailgw.py @@ -14,7 +14,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: roundup_mailgw.py,v 1.12 2004-04-05 23:43:03 richard Exp $ +# $Id: roundup_mailgw.py,v 1.13 2004-04-13 04:11:06 richard Exp $ """Command-line script stub that calls the roundup.mailgw. """ @@ -80,6 +80,17 @@ APOP: Same as POP, but using Authenticated POP: apop username:password@server +IMAP: + Connect to an IMAP server. This supports the same notation as that of POP mail. + imap username:password@server + It also allows you to specify a specific mailbox other than INBOX using this format: + imap username:password@server mailbox + +IMAPS: + Connect to an IMAP server over ssl. + This supports the same notation as IMAP. + imaps username:password@server [mailbox] + ''') return 1 @@ -126,7 +137,7 @@ def main(argv): # otherwise, figure what sort of mail source to handle if len(args) < 3: return usage(argv, _('Error: not enough source specification information')) - source, specification = args[1:] + source, specification = args[1:3] if source == 'mailbox': return handler.do_mailbox(specification) elif source == 'pop': @@ -143,6 +154,18 @@ def main(argv): return handler.do_apop(m.group('server'), m.group('user'), m.group('pass')) return usage(argv, _('Error: apop specification not valid')) + elif source == 'imap' or source == 'imaps': + m = re.match(r'((?P[^:]+)(:(?P.+))?@)?(?P.+)', + specification) + if m: + ssl = False + if source == 'imaps': + ssl = True + mailbox = '' + if len(args) > 3: + mailbox = args[3] + return handler.do_imap(m.group('server'), m.group('user'), + m.group('pass'), mailbox, ssl) return usage(argv, _('Error: The source must be either "mailbox", "pop" or "apop"')) finally: -- 2.30.2