]> code.delx.au - offlineimap/blobdiff - offlineimap/init.py
Bug#502779: Sync accounts in order of general.accounts option
[offlineimap] / offlineimap / init.py
index 45a57737bc39a30bdb47391a83efe34c6fd61087..8d888b43d8c0884d80ef22da728be215f065edeb 100644 (file)
@@ -1,5 +1,5 @@
 # OfflineIMAP initialization code
-# Copyright (C) 2002, 2003 John Goerzen
+# Copyright (C) 2002-2007 John Goerzen
 # <jgoerzen@complete.org>
 #
 #    This program is free software; you can redistribute it and/or modify
 #    along with this program; if not, write to the Free Software
 #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 
-from offlineimap import imaplib, imapserver, repository, folder, mbnames, threadutil, version, syncmaster, accounts
+from offlineimap import imaplib2, imapserver, repository, folder, mbnames, threadutil, version, syncmaster, accounts
 from offlineimap.localeval import LocalEval
 from offlineimap.threadutil import InstanceLimitedThread, ExitNotifyThread
 from offlineimap.ui import UIBase
 import re, os, os.path, offlineimap, sys
 from offlineimap.CustomConfig import CustomConfigParser
 from threading import *
-import threading
+import threading, socket
 from getopt import getopt
+import signal
 
 try:
     import fcntl
@@ -49,14 +50,14 @@ def startup(versionno):
     assert versionno == version.versionstr, "Revision of main program (%s) does not match that of library (%s).  Please double-check your PYTHONPATH and installation locations." % (versionno, version.versionstr)
     options = {}
     if '--help' in sys.argv[1:]:
-        sys.stdout.write(version.cmdhelp + "\n")
+        sys.stdout.write(version.getcmdhelp() + "\n")
         sys.exit(0)
 
-    for optlist in getopt(sys.argv[1:], 'P:1oa:c:d:l:u:h')[0]:
+    for optlist in getopt(sys.argv[1:], 'P:1oqa:c:d:l:u:hk:f:')[0]:
         options[optlist[0]] = optlist[1]
 
     if options.has_key('-h'):
-        sys.stdout.write(version.cmdhelp)
+        sys.stdout.write(version.getcmdhelp())
         sys.stdout.write("\n")
         sys.exit(0)
     configfilename = os.path.expanduser("~/.offlineimaprc")
@@ -78,6 +79,17 @@ def startup(versionno):
 
     config.read(configfilename)
 
+    # override config values with option '-k'
+    for option in options.keys():
+        if option == '-k':
+            (key, value) = options['-k'].split('=', 1)
+            if ':' in key:
+                (secname, key) = key.split(':', 1)
+                section = secname.replace("_", " ")
+            else:
+                section = "general"
+            config.set(section, key, value)
+
     ui = offlineimap.ui.detector.findUI(config, options.get('-u'))
     UIBase.setglobalui(ui)
 
@@ -90,7 +102,7 @@ def startup(versionno):
         for debugtype in options['-d'].split(','):
             ui.add_debug(debugtype.strip())
             if debugtype == 'imap':
-                imaplib.Debug = 5
+                imaplib2.Debug = 5
             if debugtype == 'thread':
                 threading._VERBOSE = 1
 
@@ -99,48 +111,114 @@ def startup(versionno):
         for section in accounts.getaccountlist(config):
             config.remove_option('Account ' + section, "autorefresh")
 
+    if options.has_key('-q'):
+        for section in accounts.getaccountlist(config):
+            config.set('Account ' + section, "quick", '-1')
+
+    if options.has_key('-f'):
+        foldernames = options['-f'].replace(" ", "").split(",")
+        folderfilter = "lambda f: f in %s" % foldernames
+        folderincludes = "[]"
+        for accountname in accounts.getaccountlist(config):
+            account_section = 'Account ' + accountname
+            remote_repo_section = 'Repository ' + \
+                                  config.get(account_section, 'remoterepository')
+            local_repo_section = 'Repository ' + \
+                                 config.get(account_section, 'localrepository')
+            for section in [remote_repo_section, local_repo_section]:
+                config.set(section, "folderfilter", folderfilter)
+                config.set(section, "folderincludes", folderincludes)
+
     lock(config, ui)
 
-    if options.has_key('-l'):
-        sys.stderr = ui.logfile
-
-    activeaccounts = config.get("general", "accounts")
-    if options.has_key('-a'):
-        activeaccounts = options['-a']
-    activeaccounts = activeaccounts.replace(" ", "")
-    activeaccounts = activeaccounts.split(",")
-    allaccounts = accounts.AccountHashGenerator(config)
-
-    syncaccounts = {}
-    for account in activeaccounts:
-        syncaccounts[account] = allaccounts[account]
-
-    server = None
-    remoterepos = None
-    localrepos = None
-
-    if options.has_key('-1'):
-        threadutil.initInstanceLimit("ACCOUNTLIMIT", 1)
-    else:
-        threadutil.initInstanceLimit("ACCOUNTLIMIT",
-                                     config.getdefaultint("general", "maxsyncaccounts", 1))
-
-    for reposname in config.getsectionlist('Repository'):
-        for instancename in ["FOLDER_" + reposname,
-                             "MSGCOPY_" + reposname]:
-            if options.has_key('-1'):
-                threadutil.initInstanceLimit(instancename, 1)
-            else:
-                threadutil.initInstanceLimit(instancename,
-                                             config.getdefaultint('Repository ' + reposname, "maxconnections", 1))
-
-    threadutil.initexitnotify()
-    t = ExitNotifyThread(target=syncmaster.syncitall,
-                         name='Sync Runner',
-                         kwargs = {'accounts': syncaccounts,
-                                   'config': config})
-    t.setDaemon(1)
-    t.start()
+    def sigterm_handler(signum, frame):
+        # die immediately
+        ui.terminate(errormsg="terminating...")
+    signal.signal(signal.SIGTERM,sigterm_handler)
+
+    try:
+        pidfd = open(config.getmetadatadir() + "/pid", "w")
+        pidfd.write(str(os.getpid()) + "\n")
+        pidfd.close()
+    except:
+        pass
+
+    try:
+        if options.has_key('-l'):
+            sys.stderr = ui.logfile
+
+        socktimeout = config.getdefaultint("general", "socktimeout", 0)
+        if socktimeout > 0:
+            socket.setdefaulttimeout(socktimeout)
+
+        activeaccounts = config.get("general", "accounts")
+        if options.has_key('-a'):
+            activeaccounts = options['-a']
+        activeaccounts = activeaccounts.replace(" ", "")
+        activeaccounts = activeaccounts.split(",")
+        allaccounts = accounts.AccountHashGenerator(config)
+
+        syncaccounts = []
+        for account in activeaccounts:
+            if account not in allaccounts:
+                if len(allaccounts) == 0:
+                    errormsg = 'The account "%s" does not exist because no accounts are defined!'%account
+                else:
+                    errormsg = 'The account "%s" does not exist.  Valid accounts are:'%account
+                    for name in allaccounts.keys():
+                        errormsg += '\n%s'%name
+                ui.terminate(1, errortitle = 'Unknown Account "%s"'%account, errormsg = errormsg)
+            if account not in syncaccounts:
+                syncaccounts.append(account)
+
+        server = None
+        remoterepos = None
+        localrepos = None
+
+        if options.has_key('-1'):
+            threadutil.initInstanceLimit("ACCOUNTLIMIT", 1)
+        else:
+            threadutil.initInstanceLimit("ACCOUNTLIMIT",
+                                         config.getdefaultint("general", "maxsyncaccounts", 1))
+
+        for reposname in config.getsectionlist('Repository'):
+            for instancename in ["FOLDER_" + reposname,
+                                 "MSGCOPY_" + reposname]:
+                if options.has_key('-1'):
+                    threadutil.initInstanceLimit(instancename, 1)
+                else:
+                    threadutil.initInstanceLimit(instancename,
+                                                 config.getdefaultint('Repository ' + reposname, "maxconnections", 1))
+        siglisteners = []
+        def sig_handler(signum, frame):
+            if signum == signal.SIGUSR1:
+                # tell each account to do a full sync asap
+                signum = (1,)
+            elif signum == signal.SIGHUP:
+                # tell each account to die asap
+                signum = (2,)
+            elif signum == signal.SIGUSR2:
+                # tell each account to do a full sync asap, then die
+                signum = (1, 2)
+            # one listener per account thread (up to maxsyncaccounts)
+            for listener in siglisteners:
+                for sig in signum:
+                    listener.put_nowait(sig)
+        signal.signal(signal.SIGHUP,sig_handler)
+        signal.signal(signal.SIGUSR1,sig_handler)
+        signal.signal(signal.SIGUSR2,sig_handler)
+
+        threadutil.initexitnotify()
+        t = ExitNotifyThread(target=syncmaster.syncitall,
+                             name='Sync Runner',
+                             kwargs = {'accounts': syncaccounts,
+                                       'config': config,
+                                       'siglisteners': siglisteners})
+        t.setDaemon(1)
+        t.start()
+    except:
+        ui.mainException()
+
     try:
         threadutil.exitnotifymonitorloop(threadutil.threadexited)
     except SystemExit: