Code

added IMAP support to mail gateway (sf rfe 934000)
authorrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Tue, 13 Apr 2004 04:11:49 +0000 (04:11 +0000)
committerrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Tue, 13 Apr 2004 04:11:49 +0000 (04:11 +0000)
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@2280 57a73879-2fb5-44c3-a270-3262357dd7e2

CHANGES.txt
roundup/mailgw.py
roundup/scripts/roundup_mailgw.py

index bd4542bc2511bab06c0887efaf847911f310f654..e0d24b89171eb1eb074a1af5106b62c50bc6b676 100644 (file)
@@ -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
index 47d0831099bff7579ab1f7e7fd3311c29b4d5999..35cc90248470b73aedc5cd2bacaa1d232c0bf1b6 100644 (file)
@@ -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
         '''
index 8695aee377e7d69c722a0335973e940e61439eb3..33633ad632c6c317c9bf2c0905d64b02b76d4db6 100644 (file)
@@ -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<user>[^:]+)(:(?P<pass>.+))?@)?(?P<server>.+)',
+                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: