import inspect
import logging
import pydoc
+import re
import sys
import yaml
self.logger = self._get_logger(loglevel)
self._load_config(config)
self._update_logger()
+ self.uidnext = {}
def _get_logger(self, loglevel):
"""
imap.login(login, password)
self.imap = imap
+ def get_uidnext(self):
+ """
+ Get the state (uidnext) for each inbox used in the configuration.
+ It gives the uid of the next message the will be added in the mbox.
+ We will only care about messages with a uid lower than this uidnext,
+ to avoid race conditions with a message arriving while we are in the
+ middle of rules processing.
+ """
+ self.logger.info('Getting inbox state...')
+ mboxes = [self.config["inbox"]] + [rule.inbox for rule in self.rules]
+ for m in mboxes:
+ if m is None:
+ continue
+ if self.uidnext.get(m, None) is not None:
+ continue
+ self.imap.select(m)
+ typ, dat = self.imap.status(m, "(UIDNEXT)")
+ if typ != 'OK':
+ raise ValueError("cannot get UIDNEXT: %s", typ)
+ match = re.match("[^ ]* \(UIDNEXT ([0-9]+)\)", dat[0])
+ if match is None:
+ raise ValueError("cannot match UIDNEXT: %s", typ)
+ self.uidnext[m] = int(match.groups()[0])
+ self.logger.info('Done: %r', self.uidnext)
+
def process_rules(self):
"""
Process the rules.
"""
self.logger.info('Processing rules...')
- inbox = self.config["inbox"]
for rule in self.rules:
- rule.process(self, inbox)
+ rule.process(self)
self.logger.info('Done.')
def close(self):
sys.exit(0)
p.connect()
+ p.get_uidnext()
p.process_rules()
p.close()
:returns:
A list of IMAP items
"""
- # select the input mailbox
- if self.inbox is not None:
- ami.imap.select(self.inbox)
- else:
- ami.imap.select(inbox)
-
# search messages matching conditions
criteria = "(%s)" % self.get_criteria(ami)
ami.logger.debug("processing rule %s, inbox %s, imap criteria %s",
return
item_list = items[0].split()
+ item_list = [i for i in item_list if int(i) < ami.uidnext[inbox]]
ami.logger.debug("matching mails returned by server: %s", item_list)
return item_list
ami.logger.debug('get imap parts = %s', parts_str)
return parts_str, parts
- def process(self, ami, inbox):
+ def process(self, ami):
"""
Process the rule.
:arg Imapami ami:
The Imapami object
- :arg string inbox:
- The default input mailbox directory.
"""
+ if self.inbox is not None:
+ inbox = self.inbox
+ else:
+ inbox = ami.config["inbox"]
+ ami.imap.select(inbox)
+
# get the list of items (mails) matching the condition criteria
item_list = self._search(ami, inbox)
# determine what parts should be fetched