diff --git a/head/offlineimap.conf b/head/offlineimap.conf index 39279b0..fda9364 100644 --- a/head/offlineimap.conf +++ b/head/offlineimap.conf @@ -35,6 +35,12 @@ metadata = ~/.imapsync accounts = Test +# You can have imapsync continue running indefinately, automatically +# syncing your mail periodically. If you want that, specify how +# frequently to do that (in minutes) here. + +# autorefresh = 5 + ################################################## # Mailbox name recorder ################################################## diff --git a/head/offlineimap.py b/head/offlineimap.py index 1eb0c77..b8e8d7b 100644 --- a/head/offlineimap.py +++ b/head/offlineimap.py @@ -45,71 +45,88 @@ remoterepos = None localrepos = None mailboxes = [] -for accountname in accounts: - ui.acct(accountname) - accountmetadata = os.path.join(metadatadir, accountname) - if not os.path.exists(accountmetadata): - os.mkdir(accountmetadata, 0700) - host = config.get(accountname, "remotehost") - user = config.get(accountname, "remoteuser") - port = None - if config.has_option(accountname, "remoteport"): - port = config.getint(accountname, "remoteport") - password = None - if config.has_option(accountname, "remotepass"): - password = config.get(accountname, "remotepass") - else: - password = ui.getpass(accountname, host, port, user) - ssl = config.getboolean(accountname, "ssl") +def syncitall(): + for accountname in accounts: + ui.acct(accountname) + accountmetadata = os.path.join(metadatadir, accountname) + if not os.path.exists(accountmetadata): + os.mkdir(accountmetadata, 0700) + host = config.get(accountname, "remotehost") + user = config.get(accountname, "remoteuser") + port = None + if config.has_option(accountname, "remoteport"): + port = config.getint(accountname, "remoteport") + password = None + if config.has_option(accountname, "remotepass"): + password = config.get(accountname, "remotepass") + else: + password = ui.getpass(accountname, host, port, user) + # Save it for future reference. + config.set(accountname, "remotepass", password) + ssl = config.getboolean(accountname, "ssl") - # Connect to the remote server. - server = imapserver.IMAPServer(user, password, host, port, ssl) - remoterepos = repository.IMAP.IMAPRepository(config, accountname, server) + # Connect to the remote server. + server = imapserver.IMAPServer(user, password, host, port, ssl) + remoterepos = repository.IMAP.IMAPRepository(config, accountname, server) - # Connect to the Maildirs. - localrepos = repository.Maildir.MaildirRepository(os.path.expanduser(config.get(accountname, "localfolders"))) + # Connect to the Maildirs. + localrepos = repository.Maildir.MaildirRepository(os.path.expanduser(config.get(accountname, "localfolders"))) - # Connect to the local cache. - statusrepos = repository.LocalStatus.LocalStatusRepository(accountmetadata) - - ui.syncfolders(remoterepos, localrepos) - remoterepos.syncfoldersto(localrepos) + # Connect to the local cache. + statusrepos = repository.LocalStatus.LocalStatusRepository(accountmetadata) - for remotefolder in remoterepos.getfolders(): - mailboxes.append({'accountname': accountname, - 'foldername': remotefolder.getvisiblename()}) - # Load local folder. - localfolder = localrepos.getfolder(remotefolder.getvisiblename()) - if not localfolder.isuidvalidityok(remotefolder): - ui.validityproblem(remotefolder) - continue - ui.syncingfolder(remoterepos, remotefolder, localrepos, localfolder) - ui.loadmessagelist(localrepos, localfolder) - localfolder.cachemessagelist() - ui.messagelistloaded(localrepos, localfolder, len(localfolder.getmessagelist().keys())) + ui.syncfolders(remoterepos, localrepos) + remoterepos.syncfoldersto(localrepos) + + for remotefolder in remoterepos.getfolders(): + mailboxes.append({'accountname': accountname, + 'foldername': remotefolder.getvisiblename()}) + # Load local folder. + localfolder = localrepos.getfolder(remotefolder.getvisiblename()) + if not localfolder.isuidvalidityok(remotefolder): + ui.validityproblem(remotefolder) + continue + ui.syncingfolder(remoterepos, remotefolder, localrepos, localfolder) + ui.loadmessagelist(localrepos, localfolder) + localfolder.cachemessagelist() + ui.messagelistloaded(localrepos, localfolder, len(localfolder.getmessagelist().keys())) + + # Load remote folder. + ui.loadmessagelist(remoterepos, remotefolder) + remotefolder.cachemessagelist() + ui.messagelistloaded(remoterepos, remotefolder, + len(remotefolder.getmessagelist().keys())) + + # Load status folder. + statusfolder = statusrepos.getfolder(remotefolder.getvisiblename()) + statusfolder.cachemessagelist() + + if not statusfolder.isnewfolder(): + ui.syncingmessages(localrepos, localfolder, remoterepos, remotefolder) + localfolder.syncmessagesto(statusfolder, [remotefolder, statusfolder]) + + # Synchronize remote changes. + ui.syncingmessages(remoterepos, remotefolder, localrepos, localfolder) + remotefolder.syncmessagesto(localfolder) + + # Make sure the status folder is up-to-date. + ui.syncingmessages(localrepos, localfolder, statusrepos, statusfolder) + localfolder.syncmessagesto(statusfolder) + statusfolder.save() + server.close() + + + mbnames.genmbnames(config, mailboxes) + +syncitall() +if config.has_option('general', 'autorefresh'): + refreshperiod = config.getint('general', 'autorefresh') * 60 + while 1: + sleepamount = refreshperiod + abortsleep = 0 + while sleepamount > 0 and not abortsleep: + abortsleep = ui.sleeping(1, sleepamount) + sleepamount -= 1 + ui.sleeping(0, 0) # Done sleeping. + syncitall() - # Load remote folder. - ui.loadmessagelist(remoterepos, remotefolder) - remotefolder.cachemessagelist() - ui.messagelistloaded(remoterepos, remotefolder, - len(remotefolder.getmessagelist().keys())) - - # Load status folder. - statusfolder = statusrepos.getfolder(remotefolder.getvisiblename()) - statusfolder.cachemessagelist() - - if not statusfolder.isnewfolder(): - ui.syncingmessages(localrepos, localfolder, remoterepos, remotefolder) - localfolder.syncmessagesto(statusfolder, [remotefolder, statusfolder]) - - # Synchronize remote changes. - ui.syncingmessages(remoterepos, remotefolder, localrepos, localfolder) - remotefolder.syncmessagesto(localfolder) - - # Make sure the status folder is up-to-date. - ui.syncingmessages(localrepos, localfolder, statusrepos, statusfolder) - localfolder.syncmessagesto(statusfolder) - statusfolder.save() - - -mbnames.genmbnames(config, mailboxes) diff --git a/head/offlineimap/folder/IMAP.py b/head/offlineimap/folder/IMAP.py index 9356ebb..9e9c264 100644 --- a/head/offlineimap/folder/IMAP.py +++ b/head/offlineimap/folder/IMAP.py @@ -64,7 +64,7 @@ class IMAPFolder(BaseFolder): def getmessage(self, uid): assert(self.imapobj.select(self.getfullname())[0] == 'OK') - return self.imapobj.uid('fetch', '%d' % uid, '(RFC822)')[1][0][1].replace("\r\n", "\n") + return self.imapobj.uid('fetch', '%d' % uid, '(BODY.PEEK[])')[1][0][1].replace("\r\n", "\n") def getmessageflags(self, uid): return self.getmessagelist()[uid]['flags'] diff --git a/head/offlineimap/imapserver.py b/head/offlineimap/imapserver.py index 3d8dac5..2f31186 100644 --- a/head/offlineimap/imapserver.py +++ b/head/offlineimap/imapserver.py @@ -67,4 +67,6 @@ class IMAPServer: self.imapobj = imapobj return imapobj - + def close(self): + self.imapobj.logout() + self.imapobj = None diff --git a/head/offlineimap/repository/IMAP.py b/head/offlineimap/repository/IMAP.py index 6e942f7..df49b58 100644 --- a/head/offlineimap/repository/IMAP.py +++ b/head/offlineimap/repository/IMAP.py @@ -50,5 +50,6 @@ class IMAPRepository(BaseRepository): continue retval.append(folder.IMAP.IMAPFolder(self.imapserver, name, self.nametrans(imaputil.dequote(name)))) + retval.sort() self.folders = retval return retval diff --git a/head/offlineimap/ui/TTY.py b/head/offlineimap/ui/TTY.py index 9851193..35f2409 100644 --- a/head/offlineimap/ui/TTY.py +++ b/head/offlineimap/ui/TTY.py @@ -1,5 +1,6 @@ from UIBase import UIBase from getpass import getpass +import select, sys class TTYUI(UIBase): def __init__(self, verbose = 0): @@ -23,3 +24,18 @@ class TTYUI(UIBase): def messagelistloaded(s, repos, folder, count): if s.verbose: UIBase.messagelistloaded(s, repos, folder, count) + + def sleeping(s, sleepsecs, remainingsecs): + if remainingsecs > 0: + sys.stdout.write("Next sync in %d:%02d (press Enter to sync now) \r" % \ + (remainingsecs / 60, remainingsecs % 60)) + sys.stdout.flush() + else: + sys.stdout.write("Wait done, proceeding with sync.... ") + + if sleepsecs > 0: + if len(select.select([sys.stdin], [], [], sleepsecs)[0]): + return 1 + return 0 + + diff --git a/head/offlineimap/ui/UIBase.py b/head/offlineimap/ui/UIBase.py index 9f87624..91373e9 100644 --- a/head/offlineimap/ui/UIBase.py +++ b/head/offlineimap/ui/UIBase.py @@ -17,7 +17,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA from imapsync import repository -import re +import re, time class UIBase: ################################################## UTILS @@ -95,12 +95,22 @@ class UIBase: def addingflags(s, uid, flags, destlist): ds = s.folderlist(destlist) s._msg("Adding flags %s to message %d on %s" % \ - (flags.join(", "), uid, ds)) + (", ".join(flags), uid, ds)) def deletingflags(s, uid, flags, destlist): ds = s.folderlist(destlist) s._msg("Deleting flags %s to message %d on %s" % \ - (flags.join(", "), uid, ds)) + (", ".join(flags), uid, ds)) + ################################################## Other - + def sleeping(s, sleepsecs, remainingsecs): + """Sleep for sleepsecs, remainingsecs to go. + If sleepsecs is 0, indicates we're done sleeping. + + Return 0 for normal sleep, or 1 to indicate a request + to sync immediately.""" + s._msg("Next refresh in %d seconds" % remainingsec) + if sleepsecs > 0: + time.sleep(sleepsecs) + return 0