import offlineimap.repository.Base, offlineimap.repository.LocalStatus
from offlineimap.ui import UIBase
from offlineimap.threadutil import InstanceLimitedThread, ExitNotifyThread
-from threading import Event
-import os
from subprocess import Popen, PIPE
+from threading import Event, Lock
+import os
+from Queue import Queue, Empty
+
+class SigListener(Queue):
+ def __init__(self):
+ self.folderlock = Lock()
+ self.folders = None
+ Queue.__init__(self, 20)
+ def put_nowait(self, sig):
+ self.folderlock.acquire()
+ try:
+ if sig == 1:
+ if self.folders is None or not self.autorefreshes:
+ # folders haven't yet been added, or this account is once-only; drop signal
+ return
+ elif self.folders:
+ for foldernr in range(len(self.folders)):
+ # requeue folder
+ self.folders[foldernr][1] = True
+ self.quick = False
+ return
+ # else folders have already been cleared, put signal...
+ finally:
+ self.folderlock.release()
+ Queue.put_nowait(self, sig)
+ def addfolders(self, remotefolders, autorefreshes, quick):
+ self.folderlock.acquire()
+ try:
+ self.folders = []
+ self.quick = quick
+ self.autorefreshes = autorefreshes
+ for folder in remotefolders:
+ # new folders are queued
+ self.folders.append([folder, True])
+ finally:
+ self.folderlock.release()
+ def clearfolders(self):
+ self.folderlock.acquire()
+ try:
+ for folder, queued in self.folders:
+ if queued:
+ # some folders still in queue
+ return False
+ self.folders[:] = []
+ return True
+ finally:
+ self.folderlock.release()
+ def queuedfolders(self):
+ self.folderlock.acquire()
+ try:
+ dirty = True
+ while dirty:
+ dirty = False
+ for foldernr, (folder, queued) in enumerate(self.folders):
+ if queued:
+ # mark folder as no longer queued
+ self.folders[foldernr][1] = False
+ dirty = True
+ quick = self.quick
+ self.folderlock.release()
+ yield (folder, quick)
+ self.folderlock.acquire()
+ finally:
+ self.folderlock.release()
def getaccountlist(customconfig):
return customconfig.getsectionlist('Account')
def getsection(self):
return 'Account ' + self.getname()
- def sleeper(self):
+ def sleeper(self, siglistener):
"""Sleep handler. Returns same value as UIBase.sleep:
0 if timeout expired, 1 if there was a request to cancel the timer,
and 2 if there is a request to abort the program.
item.startkeepalive()
refreshperiod = int(self.refreshperiod * 60)
- sleepresult = self.ui.sleep(refreshperiod)
+# try:
+# sleepresult = siglistener.get_nowait()
+# # retrieved signal before sleep started
+# if sleepresult == 1:
+# # catching signal 1 here means folders were cleared before signal was posted
+# pass
+# except Empty:
+# sleepresult = self.ui.sleep(refreshperiod, siglistener)
+ sleepresult = self.ui.sleep(refreshperiod, siglistener)
+ if sleepresult == 1:
+ self.quicknum = 0
+
# Cancel keepalive
for item in kaobjs:
item.stopkeepalive()
return sleepresult
class AccountSynchronizationMixin:
- def syncrunner(self):
+ def syncrunner(self, siglistener):
self.ui.registerthread(self.name)
self.ui.acct(self.name)
accountmetadata = self.getaccountmeta()
self.statusrepos = offlineimap.repository.LocalStatus.LocalStatusRepository(self.getconf('localrepository'), self)
if not self.refreshperiod:
- self.sync()
+ self.sync(siglistener)
self.ui.acctdone(self.name)
return
looping = 1
while looping:
- self.sync()
- looping = self.sleeper() != 2
+ self.sync(siglistener)
+ looping = self.sleeper(siglistener) != 2
self.ui.acctdone(self.name)
def getaccountmeta(self):
return os.path.join(self.metadatadir, 'Account-' + self.name)
- def sync(self):
+ def sync(self, siglistener):
# We don't need an account lock because syncitall() goes through
# each account once, then waits for all to finish.
self.ui.syncfolders(remoterepos, localrepos)
remoterepos.syncfoldersto(localrepos, [statusrepos])
- folderthreads = []
- for remotefolder in remoterepos.getfolders():
- thread = InstanceLimitedThread(\
- instancename = 'FOLDER_' + self.remoterepos.getname(),
- target = syncfolder,
- name = "Folder sync %s[%s]" % \
- (self.name, remotefolder.getvisiblename()),
- args = (self.name, remoterepos, remotefolder, localrepos,
- statusrepos, quick))
- thread.setDaemon(1)
- thread.start()
- folderthreads.append(thread)
- threadutil.threadsreset(folderthreads)
+ siglistener.addfolders(remoterepos.getfolders(), bool(self.refreshperiod), quick)
+
+ while True:
+ folderthreads = []
+ for remotefolder, quick in siglistener.queuedfolders():
+ thread = InstanceLimitedThread(\
+ instancename = 'FOLDER_' + self.remoterepos.getname(),
+ target = syncfolder,
+ name = "Folder sync %s[%s]" % \
+ (self.name, remotefolder.getvisiblename()),
+ args = (self.name, remoterepos, remotefolder, localrepos,
+ statusrepos, quick))
+ thread.setDaemon(1)
+ thread.start()
+ folderthreads.append(thread)
+ threadutil.threadsreset(folderthreads)
+ if siglistener.clearfolders():
+ break
mbnames.write()
localrepos.forgetfolders()
remoterepos.forgetfolders()