--- a/server/python/junius/proto/imap.py
+++ b/server/python/junius/proto/imap.py
@@ -15,21 +15,28 @@ logger = logging.getLogger(__name__)
imap_encoding = 'utf-8'
class ImapClient(imap4.IMAP4Client):
'''
Much of our logic here should perhaps be in another class that holds a
reference to the IMAP4Client instance subclass. Consider refactoring if we
don't turn out to benefit from the subclassing relationship.
'''
+ def finished(self, result):
+ # See bottom of file - it would be good to remove this...
+ logger.info("Finished synchronizing IMAP folders")
+ # XXX - this should be done via callback/errback
+ from ..sync import get_conductor
+ return get_conductor().accountFinishedSync(self.account, result)
+
def serverGreeting(self, caps):
logger.debug("IMAP server greeting: capabilities are %s", caps)
- d = self._doAuthenticate()
- d.addCallback(self._reqList)
-
+ return self._doAuthenticate(
+ ).addCallback(self._reqList
+ ).addBoth(self.finished)
def _doAuthenticate(self):
if self.account.details.get('crypto') == 'TLS':
d = self.startTLS(self.factory.ctx)
d.addErrback(self.accountStatus,
brat.SERVER, brat.BAD, brat.CRYPTO, brat.PERMANENT)
d.addCallback(self._doLogin)
else:
@@ -51,20 +58,17 @@ class ImapClient(imap4.IMAP4Client):
# As per http://python.codefetch.com/example/ow/tnpe_code/ch07/imapdownload.py,
# We keep a 'stack' of items left to process in an instance variable...
self.folder_infos = result[:]
return self._processNextFolder()
def _processNextFolder(self):
if not self.folder_infos:
# yay - all done!
- logger.info("Finished synchronizing IMAP folders")
- # need to report we are done somewhere?
- from ..sync import get_conductor
- return get_conductor().accountFinishedSync(self.account)
+ return
flags, delim, name = self.folder_infos.pop()
self.current_folder_path = cfp = name.split(delim)
logger.debug('Processing folder %s (flags=%s)', name, flags)
if r"\Noselect" in flags:
logger.debug("'%s' is unselectable - skipping", name)
return self._processNextFolder()
@@ -78,19 +82,19 @@ class ImapClient(imap4.IMAP4Client):
return self.examine(name
).addCallback(self._examineFolder, cfp
).addErrback(self._cantExamineFolder, cfp)
def _examineFolder(self, result, folder_path):
logger.debug('Looking for messages already fetched for folder %s', folder_path)
startkey=['rfc822', self.account.details['_id'], [folder_path, 0]]
endkey=['rfc822', self.account.details['_id'], [folder_path, 4000000000]]
- get_db().openView('raindrop!messages!by', 'by_storage',
- startkey=startkey, endkey=endkey,
- ).addCallback(self._fetchAndProcess, folder_path)
+ return get_db().openView('raindrop!messages!by', 'by_storage',
+ startkey=startkey, endkey=endkey,
+ ).addCallback(self._fetchAndProcess, folder_path)
def _fetchAndProcess(self, rows, folder_path):
allMessages = imap4.MessageSet(1, None)
seen_ids = [r['key'][2][1] for r in rows]
logger.debug("%d messages already exist from %s",
len(seen_ids), folder_path)
return self.fetchUID(allMessages, True).addCallback(
self._gotUIDs, folder_path, seen_ids)
@@ -150,20 +154,20 @@ class ImapClient(imap4.IMAP4Client):
doc = dict(
type='rawMessage',
subtype='rfc822',
account_id=self.account.details['_id'],
storage_key=[self.current_folder_path, int(result['UID'])],
rfc822=body,
imap_flags=flags,
)
- get_db().saveDoc(doc
- ).addCallback(self._savedDocument
- ).addErrback(self._cantSaveDocument
- )
+ return get_db().saveDoc(doc
+ ).addCallback(self._savedDocument
+ ).addErrback(self._cantSaveDocument
+ )
def _cantGetMessage(self, failure):
logger.error("Failed to fetch message: %s", failure)
return self._processNextMessage()
def _savedDocument(self, result):
logger.debug("Saved message %s", result)
return self._processNextMessage()
@@ -172,17 +176,17 @@ class ImapClient(imap4.IMAP4Client):
logger.error("Failed to save message: %s", failure)
return self._processNextMessage()
def _cantExamineFolder(self, failure, name, *args, **kw):
logger.warning("Failed to examine folder '%s': %s", name, failure)
return self._processNextFolder()
def accountStatus(self, result, *args):
- self.account.reportStatus(*args)
+ return self.account.reportStatus(*args)
class ImapClientFactory(protocol.ClientFactory):
protocol = ImapClient
def __init__(self, account):
self.account = account
@@ -234,8 +238,11 @@ class ImapClientFactory(protocol.ClientF
class IMAPAccount(base.AccountBase):
def __init__(self, db, details):
self.db = db
self.details = details
def startSync(self, conductor):
self.factory = ImapClientFactory(self)
self.factory.connect()
+ # XXX - wouldn't it be good to return a deferred here, so the conductor
+ # can reliably wait for the deferred to complete, rather than forcing
+ # each deferred to manage 'finished' itself?