# -*- Mode: Python -*-

import imaplib
import select

class NoIdleError (Exception):
    pass

class imap_filter (imaplib.IMAP4):

    idle_state = False
    idle_exit_flag = False

    def send (self, data):
        import sys
        if data.find ('LOGIN ') != -1:
            sys.stderr.write ('=> LOGIN <user> <password>\n')
        else:
            sys.stderr.write ('=> %r\n' % (data,))
        imaplib.IMAP4.send (self, data)

    def get_delimiter (self):
        status, data = self.list ("", "INBOX")
        if status == 'OK':
            delim = data[0].split()[-2]
            # hopefully not too scary
            delim = eval (delim)
            self.delimiter = delim
            print 'delimiter character = %r' % (delim,)

    def go_idle (self):
        if 'IDLE' not in self.capabilities:
            raise NoIdleError ("idle not supported by server.  sorry.")
        self.idle_hooks = []
        fd = self.sock.fileno()
        while 1:
            # this loop send the IDLE command repeatedly
            self.send ('%s IDLE\r\n' % (self._new_tag(),))
            self.idle_state = True
            try:
                # this loop fetches multiple untagged responses
                # from the IDLE command...
                while 1:
                    r = None
                    # refresh every 15 minutes
                    rfd, wfd, efd = select.select (
                        [fd], [], [], 15 * 60
                        )
                    if rfd:
                        # _get_response() will trigger calls to
                        # _append_untagged(), which will look for
                        # 'hooked' events.  If any hooks need to run,
                        # they'll collect in self.idle_hooks, which
                        # will tell us to exit the IDLE command so we
                        # can move some stuff around.
                        r = self._get_response()
                        print 'response=%r' % (r,)
                    else:
                        # timeout, force a refresh
                        self.idle_exit_flag = True
                        print 'refresh'
                    if self.idle_exit_flag:
                        print 'sending DONE'
                        # no tag on this one...
                        self.send ('DONE\r\n')
                        print 'DONE response=', self._get_response()
                        self.idle_state = False
                        self.process_hooks()
                        self.idle_exit_flag = False
                        break
            finally:
                self.idle_state = False

    def _append_untagged (self, typ, dat):
        if self.idle_state:
            hook_probe = getattr (self, 'hook_%s' % (typ.lower(),), None)
            if hook_probe:
                if self.idle_hooks is None:
                    self.idle_hooks = [(hook_probe, dat)]
                else:
                    self.idle_hooks.append ((hook_probe, dat))
                self.idle_exit_flag = True
        else:
            imaplib.IMAP4._append_untagged (self, typ, dat)

    def process_hooks (self):
        for fun, dat in self.idle_hooks:
            fun (dat)
        self.idle_hooks = []

    movement_rules = [
        ('\r\nX-Spam-Flag: YES', "INBOX.spam"),
        ('\r\nX-Fnord-Flag: YES', "INBOX.spam"), # for testing
        ('\r\nSubject: cvs[ \r\n\t]+\\[', "INBOX.cvs"),
        ('\r\nFrom: dogfood-euq@ironport.com', "INBOX.euq"),
        ('\r\nList-Id: [^\r\n]+<stackless\\.stackless\\.com>\r\n', "INBOX.stackless"),
        ('\r\nList-Id: <mac-users\\.lists\\.ironport\\.com>\r\n', "INBOX.mac-users")
        ]

    def hook_exists (self, dat):
        import re
        uid, header = self.fetch (dat, "(UID RFC822.HEADER)")
        # pull the actual header text out
        header = header[0][1]
        #print 'header= %r' % (header,)
        moved = False
        for search, moveto in self.movement_rules:
            if re.search (search, header) is not None:
                self.store (dat, 'FLAGS', '(\Seen)')
                # replace delimiter in mailbox names
                moveto = moveto.replace ('.', self.delimiter)
                self.copy (dat, moveto)
                self.store (dat, 'FLAGS', '(\Deleted)')
                moved = True

if __name__ == '__main__':
    import getpass
    import sys
    host = sys.argv[1]
    user = sys.argv[2]
    if len(sys.argv) > 3:
        port = int (sys.argv[3])
    pwd = getpass.getpass()
    c = imap_filter (host)
    #c.debug = 5
    c.login (user, pwd)
    c.get_delimiter()
    c.select ("INBOX")
    c.go_idle()
