Пример #1
0
    def sync(self, siglistener):
        # We don't need an account lock because syncitall() goes through
        # each account once, then waits for all to finish.

        hook = self.getconf('presynchook', '')
        self.callhook(hook)

        quickconfig = self.getconfint('quick', 0)
        if quickconfig < 0:
            quick = True
        elif quickconfig > 0:
            if self.quicknum == 0 or self.quicknum > quickconfig:
                self.quicknum = 1
                quick = False
            else:
                self.quicknum = self.quicknum + 1
                quick = True
        else:
            quick = False

        try:
            remoterepos = self.remoterepos
            localrepos = self.localrepos
            statusrepos = self.statusrepos
            self.ui.syncfolders(remoterepos, localrepos)
            remoterepos.syncfoldersto(localrepos, [statusrepos])

            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()
            localrepos.holdordropconnections()
            remoterepos.holdordropconnections()
        finally:
            pass

        hook = self.getconf('postsynchook', '')
        self.callhook(hook)
Пример #2
0
    def sync(self, siglistener):
        # We don't need an account lock because syncitall() goes through
        # each account once, then waits for all to finish.

        hook = self.getconf('presynchook', '')
        self.callhook(hook)

        quickconfig = self.getconfint('quick', 0)
        if quickconfig < 0:
            quick = True
        elif quickconfig > 0:
            if self.quicknum == 0 or self.quicknum > quickconfig:
                self.quicknum = 1
                quick = False
            else:
                self.quicknum = self.quicknum + 1
                quick = True
        else:
            quick = False

        try:
            remoterepos = self.remoterepos
            localrepos = self.localrepos
            statusrepos = self.statusrepos
            self.ui.syncfolders(remoterepos, localrepos)
            remoterepos.syncfoldersto(localrepos, [statusrepos])

            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()
            localrepos.holdordropconnections()
            remoterepos.holdordropconnections()
        finally:
            pass

        hook = self.getconf('postsynchook', '')
        self.callhook(hook)
Пример #3
0
 def run(self):
     """Parse the commandline and invoke everything"""
     # next line also sets self.config and self.ui
     options, args = self.__parse_cmd_options()
     if options.diagnostics:
         self.__serverdiagnostics(options)
     elif options.migrate_fmd5:
         self.__migratefmd5(options)
     elif options.mbnames_prune:
         mbnames.init(self.config, self.ui, options.dryrun)
         mbnames.prune(self.config.get("general", "accounts"))
         mbnames.write()
     elif options.deletefolder:
         return self.__deletefolder(options)
     else:
         return self.__sync(options)
Пример #4
0
 def run(self):
     """Parse the commandline and invoke everything"""
     # next line also sets self.config and self.ui
     options, args = self.__parse_cmd_options()
     if options.diagnostics:
         self.__serverdiagnostics(options)
     elif options.migrate_fmd5:
         self.__migratefmd5(options)
     elif options.mbnames_prune:
         mbnames.init(self.config, self.ui, options.dryrun)
         mbnames.prune(self.config.get("general", "accounts"))
         mbnames.write()
     elif options.deletefolder:
         return self.__deletefolder(options)
     else:
         return self.__sync(options)
Пример #5
0
    def __sync(self, options):
        """Invoke the correct single/multithread syncing

        self.config is supposed to have been correctly initialized
        already."""

        def sig_handler(sig, frame):
            if sig == signal.SIGUSR1:
                # tell each account to stop sleeping
                accounts.Account.set_abort_event(self.config, 1)
            elif sig == signal.SIGUSR2:
                # tell each account to stop looping
                getglobalui().warn("Terminating after this sync...")
                accounts.Account.set_abort_event(self.config, 2)
            elif sig in (signal.SIGTERM, signal.SIGINT, signal.SIGHUP):
                # tell each account to ABORT ASAP (ctrl-c)
                getglobalui().warn("Terminating NOW (this may "\
                                   "take a few seconds)...")
                accounts.Account.set_abort_event(self.config, 3)
                if 'thread' in self.ui.debuglist:
                    self.__dumpstacks(5)

                # Abort after three Ctrl-C keystrokes
                self.num_sigterm += 1
                if self.num_sigterm >= 3:
                    getglobalui().warn("Signaled thrice. Aborting!")
                    sys.exit(1)
            elif sig == signal.SIGQUIT:
                stacktrace.dump(sys.stderr)
                os.abort()

        try:
            self.num_sigterm = 0
            signal.signal(signal.SIGHUP, sig_handler)
            signal.signal(signal.SIGUSR1, sig_handler)
            signal.signal(signal.SIGUSR2, sig_handler)
            signal.signal(signal.SIGTERM, sig_handler)
            signal.signal(signal.SIGINT, sig_handler)
            signal.signal(signal.SIGQUIT, sig_handler)

            # Various initializations that need to be performed:
            activeaccounts = self._get_activeaccounts(options)
            mbnames.init(self.config, self.ui, options.dryrun)

            if options.singlethreading:
                # Singlethreaded.
                self.__sync_singlethreaded(activeaccounts)
            else:
                # Multithreaded.
                t = threadutil.ExitNotifyThread(
                    target=syncitall,
                    name='Sync Runner',
                    args=(activeaccounts, self.config,)
                    )
                # Special exit message for the monitor to stop looping.
                t.exit_message = threadutil.STOP_MONITOR
                t.start()
                threadutil.monitor()

            # All sync are done.
            mbnames.write()
            self.ui.terminate()
            return 0
        except (SystemExit):
            raise
        except Exception as e:
            self.ui.error(e)
            self.ui.terminate()
            return 1
Пример #6
0
    def sync(self):
        """Synchronize the account once, then return

        Assumes that `self.remoterepos`, `self.localrepos`, and
        `self.statusrepos` has already been populated, so it should only
        be called from the :meth:`syncrunner` function.
        """
        folderthreads = []

        hook = self.getconf('presynchook', '')
        self.callhook(hook)

        quickconfig = self.getconfint('quick', 0)
        if quickconfig < 0:
            quick = True
        elif quickconfig > 0:
            if self.quicknum == 0 or self.quicknum > quickconfig:
                self.quicknum = 1
                quick = False
            else:
                self.quicknum = self.quicknum + 1
                quick = True
        else:
            quick = False

        try:
            remoterepos = self.remoterepos
            localrepos = self.localrepos
            statusrepos = self.statusrepos

            # init repos with list of folders, so we have them (and the
            # folder delimiter etc)
            remoterepos.getfolders()
            localrepos.getfolders()

            remoterepos.sync_folder_structure(localrepos, statusrepos)
            # replicate the folderstructure between REMOTE to LOCAL
            if not localrepos.getconfboolean('readonly', False):
                self.ui.syncfolders(remoterepos, localrepos)

            # iterate through all folders on the remote repo and sync
            for remotefolder in remoterepos.getfolders():
                # check for CTRL-C or SIGTERM
                if Account.abort_NOW_signal.is_set(): break

                if not remotefolder.sync_this:
                    self.ui.debug('', "Not syncing filtered folder '%s'"
                                  "[%s]" % (remotefolder, remoterepos))
                    continue # Ignore filtered folder
                localfolder = self.get_local_folder(remotefolder)
                if not localfolder.sync_this:
                    self.ui.debug('', "Not syncing filtered folder '%s'"
                                 "[%s]" % (localfolder, localfolder.repository))
                    continue # Ignore filtered folder
                thread = InstanceLimitedThread(\
                    instancename = 'FOLDER_' + self.remoterepos.getname(),
                    target = syncfolder,
                    name = "Folder %s [acc: %s]" % (remotefolder, self),
                    args = (self, remotefolder, quick))
                thread.start()
                folderthreads.append(thread)
            # wait for all threads to finish
            for thr in folderthreads:
                thr.join()
            # Write out mailbox names if required and not in dry-run mode
            if not self.dryrun:
                mbnames.write()
            localrepos.forgetfolders()
            remoterepos.forgetfolders()
        except:
            #error while syncing. Drop all connections that we have, they
            #might be bogus by now (e.g. after suspend)
            localrepos.dropconnections()
            remoterepos.dropconnections()
            raise
        else:
            # sync went fine. Hold or drop depending on config
            localrepos.holdordropconnections()
            remoterepos.holdordropconnections()

        hook = self.getconf('postsynchook', '')
        self.callhook(hook)
Пример #7
0
    def __sync(self, options):
        """Invoke the correct single/multithread syncing

        self.config is supposed to have been correctly initialized
        already."""
        def sig_handler(sig, frame):
            if sig == signal.SIGUSR1:
                # tell each account to stop sleeping
                accounts.Account.set_abort_event(self.config, 1)
            elif sig == signal.SIGUSR2:
                # tell each account to stop looping
                getglobalui().warn("Terminating after this sync...")
                accounts.Account.set_abort_event(self.config, 2)
            elif sig in (signal.SIGTERM, signal.SIGINT, signal.SIGHUP):
                # tell each account to ABORT ASAP (ctrl-c)
                getglobalui().warn("Terminating NOW (this may "\
                                   "take a few seconds)...")
                accounts.Account.set_abort_event(self.config, 3)
                if 'thread' in self.ui.debuglist:
                    self.__dumpstacks(5)

                # Abort after three Ctrl-C keystrokes
                self.num_sigterm += 1
                if self.num_sigterm >= 3:
                    getglobalui().warn("Signaled thrice. Aborting!")
                    sys.exit(1)
            elif sig == signal.SIGQUIT:
                stacktrace.dump(sys.stderr)
                os.abort()

        try:
            self.num_sigterm = 0
            signal.signal(signal.SIGHUP, sig_handler)
            signal.signal(signal.SIGUSR1, sig_handler)
            signal.signal(signal.SIGUSR2, sig_handler)
            signal.signal(signal.SIGTERM, sig_handler)
            signal.signal(signal.SIGINT, sig_handler)
            signal.signal(signal.SIGQUIT, sig_handler)

            # Various initializations that need to be performed:
            activeaccounts = self._get_activeaccounts(options)
            mbnames.init(self.config, self.ui, options.dryrun)

            if options.singlethreading:
                # Singlethreaded.
                self.__sync_singlethreaded(activeaccounts)
            else:
                # Multithreaded.
                t = threadutil.ExitNotifyThread(target=syncitall,
                                                name='Sync Runner',
                                                args=(
                                                    activeaccounts,
                                                    self.config,
                                                ))
                # Special exit message for the monitor to stop looping.
                t.exit_message = threadutil.STOP_MONITOR
                t.start()
                threadutil.monitor()

            # All sync are done.
            mbnames.write()
            self.ui.terminate()
            return 0
        except (SystemExit):
            raise
        except Exception as e:
            self.ui.error(e)
            self.ui.terminate()
            return 1
Пример #8
0
    def sync(self):
        """Synchronize the account once, then return

        Assumes that `self.remoterepos`, `self.localrepos`, and
        `self.statusrepos` has already been populated, so it should only
        be called from the :meth:`syncrunner` function.
        """
        folderthreads = []

        hook = self.getconf('presynchook', '')
        self.callhook(hook)

        quickconfig = self.getconfint('quick', 0)
        if quickconfig < 0:
            quick = True
        elif quickconfig > 0:
            if self.quicknum == 0 or self.quicknum > quickconfig:
                self.quicknum = 1
                quick = False
            else:
                self.quicknum = self.quicknum + 1
                quick = True
        else:
            quick = False

        try:
            remoterepos = self.remoterepos
            localrepos = self.localrepos
            statusrepos = self.statusrepos

            # init repos with list of folders, so we have them (and the
            # folder delimiter etc)
            remoterepos.getfolders()
            localrepos.getfolders()

            remoterepos.sync_folder_structure(localrepos, statusrepos)
            # replicate the folderstructure between REMOTE to LOCAL
            if not localrepos.getconfboolean('readonly', False):
                self.ui.syncfolders(remoterepos, localrepos)

            # iterate through all folders on the remote repo and sync
            for remotefolder in remoterepos.getfolders():
                # check for CTRL-C or SIGTERM
                if Account.abort_NOW_signal.is_set(): break

                if not remotefolder.sync_this:
                    self.ui.debug(
                        '', "Not syncing filtered folder '%s'"
                        "[%s]" % (remotefolder, remoterepos))
                    continue  # Ignore filtered folder
                localfolder = self.get_local_folder(remotefolder)
                if not localfolder.sync_this:
                    self.ui.debug(
                        '', "Not syncing filtered folder '%s'"
                        "[%s]" % (localfolder, localfolder.repository))
                    continue  # Ignore filtered folder
                if not globals.options.singlethreading:
                    thread = InstanceLimitedThread(\
                        instancename = 'FOLDER_' + self.remoterepos.getname(),
                        target = syncfolder,
                        name = "Folder %s [acc: %s]" % (remotefolder, self),
                        args = (self, remotefolder, quick))
                    thread.start()
                    folderthreads.append(thread)
                else:
                    syncfolder(self, remotefolder, quick)
            # wait for all threads to finish
            for thr in folderthreads:
                thr.join()
            # Write out mailbox names if required and not in dry-run mode
            if not self.dryrun:
                mbnames.write()
            localrepos.forgetfolders()
            remoterepos.forgetfolders()
        except:
            #error while syncing. Drop all connections that we have, they
            #might be bogus by now (e.g. after suspend)
            localrepos.dropconnections()
            remoterepos.dropconnections()
            raise
        else:
            # sync went fine. Hold or drop depending on config
            localrepos.holdordropconnections()
            remoterepos.holdordropconnections()

        hook = self.getconf('postsynchook', '')
        self.callhook(hook)
Пример #9
0
    def sync(self):
        """Synchronize the account once, then return

        Assumes that `self.remoterepos`, `self.localrepos`, and
        `self.statusrepos` has already been populated, so it should only
        be called from the :meth:`syncrunner` function.
        """
        folderthreads = []

        hook = self.getconf('presynchook', '')
        self.callhook(hook)

        quickconfig = self.getconfint('quick', 0)
        if quickconfig < 0:
            quick = True
        elif quickconfig > 0:
            if self.quicknum == 0 or self.quicknum > quickconfig:
                self.quicknum = 1
                quick = False
            else:
                self.quicknum = self.quicknum + 1
                quick = True
        else:
            quick = False

        try:
            remoterepos = self.remoterepos
            localrepos = self.localrepos
            statusrepos = self.statusrepos
            # replicate the folderstructure from REMOTE to LOCAL
            if not localrepos.getconf('readonly', False):
                self.ui.syncfolders(remoterepos, localrepos)
                remoterepos.syncfoldersto(localrepos, [statusrepos])

            # iterate through all folders on the remote repo and sync
            for remotefolder in remoterepos.getfolders():
                thread = InstanceLimitedThread(\
                    instancename = 'FOLDER_' + self.remoterepos.getname(),
                    target = syncfolder,
                    name = "Folder sync [%s]" % self,
                    args = (self.name, remoterepos, remotefolder, localrepos,
                            statusrepos, quick))
                thread.setDaemon(1)
                thread.start()
                folderthreads.append(thread)
            # wait for all threads to finish
            for thr in folderthreads:
                thr.join()
            mbnames.write()
            localrepos.forgetfolders()
            remoterepos.forgetfolders()
        except:
            #error while syncing. Drop all connections that we have, they
            #might be bogus by now (e.g. after suspend)
            localrepos.dropconnections()
            remoterepos.dropconnections()
            raise
        else:
            # sync went fine. Hold or drop depending on config
            localrepos.holdordropconnections()
            remoterepos.holdordropconnections()

        hook = self.getconf('postsynchook', '')
        self.callhook(hook)
Пример #10
0
    def sync(self):
        """Synchronize the account once, then return

        Assumes that `self.remoterepos`, `self.localrepos`, and
        `self.statusrepos` has already been populated, so it should only
        be called from the :meth:`syncrunner` function.
        """
        folderthreads = []

        hook = self.getconf('presynchook', '')
        self.callhook(hook)

        quickconfig = self.getconfint('quick', 0)
        if quickconfig < 0:
            quick = True
        elif quickconfig > 0:
            if self.quicknum == 0 or self.quicknum > quickconfig:
                self.quicknum = 1
                quick = False
            else:
                self.quicknum = self.quicknum + 1
                quick = True
        else:
            quick = False

        try:
            remoterepos = self.remoterepos
            localrepos = self.localrepos
            statusrepos = self.statusrepos
            # replicate the folderstructure from REMOTE to LOCAL
            if not localrepos.getconf('readonly', False):
                self.ui.syncfolders(remoterepos, localrepos)
                remoterepos.syncfoldersto(localrepos, [statusrepos])

            # iterate through all folders on the remote repo and sync
            for remotefolder in remoterepos.getfolders():
                thread = InstanceLimitedThread(\
                    instancename = 'FOLDER_' + self.remoterepos.getname(),
                    target = syncfolder,
                    name = "Folder sync [%s]" % self,
                    args = (self.name, remoterepos, remotefolder, localrepos,
                            statusrepos, quick))
                thread.setDaemon(1)
                thread.start()
                folderthreads.append(thread)
            # wait for all threads to finish
            for thr in folderthreads:
                thr.join()
            mbnames.write()
            localrepos.forgetfolders()
            remoterepos.forgetfolders()
        except:
            #error while syncing. Drop all connections that we have, they
            #might be bogus by now (e.g. after suspend)
            localrepos.dropconnections()
            remoterepos.dropconnections()
            raise
        else:
            # sync went fine. Hold or drop depending on config
            localrepos.holdordropconnections()
            remoterepos.holdordropconnections()

        hook = self.getconf('postsynchook', '')
        self.callhook(hook)
Пример #11
0
    def __parse_cmd_options(self):
        parser = OptionParser(
            version=offlineimap.__version__,
            description="%s.\n\n%s"% (offlineimap.__copyright__,
                offlineimap.__license__)
            )
        parser.add_option("--dry-run",
                  action="store_true", dest="dryrun",
                  default=False,
                  help="dry run mode")

        parser.add_option("--info",
                  action="store_true", dest="diagnostics",
                  default=False,
                  help="output information on the configured email repositories")

        parser.add_option("-1",
                  action="store_true", dest="singlethreading",
                  default=False,
                  help="(the number one) disable all multithreading operations")

        parser.add_option("-P", dest="profiledir", metavar="DIR",
                  help="sets OfflineIMAP into profile mode.")

        parser.add_option("-a", dest="accounts",
                  metavar="account1[,account2[,...]]",
                  help="list of accounts to sync")

        parser.add_option("-c", dest="configfile", metavar="FILE",
                  default=None,
                  help="specifies a configuration file to use")

        parser.add_option("-d", dest="debugtype",
                  metavar="type1[,type2[,...]]",
                  help="enables debugging for OfflineIMAP "
                  " (types: imap, maildir, thread)")

        parser.add_option("-l", dest="logfile", metavar="FILE",
                  help="log to FILE")

        parser.add_option("-s",
                  action="store_true", dest="syslog",
                  default=False,
                  help="log to syslog")

        parser.add_option("-f", dest="folders",
                  metavar="folder1[,folder2[,...]]",
                  help="only sync the specified folders")

        parser.add_option("-k", dest="configoverride",
                  action="append",
                  metavar="[section:]option=value",
                  help="override configuration file option")

        parser.add_option("-o",
                  action="store_true", dest="runonce",
                  default=False,
                  help="run only once (ignore autorefresh)")

        parser.add_option("-q",
                  action="store_true", dest="quick",
                  default=False,
                  help="run only quick synchronizations (don't update flags)")

        parser.add_option("-u", dest="interface",
                  help="specifies an alternative user interface"
                  " (quiet, basic, syslog, ttyui, blinkenlights, machineui)")

        parser.add_option("--migrate-fmd5-using-nametrans",
                  action="store_true", dest="migrate_fmd5", default=False,
                  help="migrate FMD5 hashes from versions prior to 6.3.5")

        parser.add_option("--mbnames-prune",
                  action="store_true", dest="mbnames_prune", default=False,
                  help="remove mbnames entries for accounts not in accounts")

        parser.add_option("-V",
                  action="store_true", dest="version",
                  default=False,
                  help="show full version infos")

        (options, args) = parser.parse_args()
        globals.set_options (options)

        if options.version:
            print("offlineimap v%s, imaplib2 v%s (%s)"% (
                offlineimap.__version__, imaplib.__version__, imaplib.DESC))
            sys.exit(0)

        # Read in configuration file.
        if not options.configfile:
            # Try XDG location, then fall back to ~/.offlineimaprc
            xdg_var = 'XDG_CONFIG_HOME'
            if not xdg_var in os.environ or not os.environ[xdg_var]:
                xdg_home = os.path.expanduser('~/.config')
            else:
                xdg_home = os.environ[xdg_var]
            options.configfile = os.path.join(xdg_home, "offlineimap", "config")
            if not os.path.exists(options.configfile):
                options.configfile = os.path.expanduser('~/.offlineimaprc')
            configfilename = options.configfile
        else:
            configfilename = os.path.expanduser(options.configfile)

        config = CustomConfigParser()
        if not os.path.exists(configfilename):
            # TODO, initialize and make use of chosen ui for logging
            logging.error(" *** Config file '%s' does not exist; aborting!"%
                          configfilename)
            sys.exit(1)
        config.read(configfilename)

        # Profile mode chosen?
        if options.profiledir:
            if not options.singlethreading:
                # TODO, make use of chosen ui for logging
                logging.warn("Profile mode: Forcing to singlethreaded.")
                options.singlethreading = True
            if os.path.exists(options.profiledir):
                # TODO, make use of chosen ui for logging
                logging.warn("Profile mode: Directory '%s' already exists!"%
                             options.profiledir)
            else:
                os.mkdir(options.profiledir)
            threadutil.ExitNotifyThread.set_profiledir(options.profiledir)
            # TODO, make use of chosen ui for logging
            logging.warn("Profile mode: Potentially large data will be "
                         "created in '%s'"% options.profiledir)

        # Override a config value.
        if options.configoverride:
            for option in options.configoverride:
                (key, value) = option.split('=', 1)
                if ':' in key:
                    (secname, key) = key.split(':', 1)
                    section = secname.replace("_", " ")
                else:
                    section = "general"
                config.set(section, key, value)

        # Which ui to use? CLI option overrides config file.
        ui_type = config.getdefault('general', 'ui', 'ttyui')
        if options.interface != None:
            ui_type = options.interface
        if '.' in ui_type:
            # Transform Curses.Blinkenlights -> Blinkenlights.
            ui_type = ui_type.split('.')[-1]
            # TODO, make use of chosen ui for logging
            logging.warning('Using old interface name, consider using one '
                            'of %s'% ', '.join(UI_LIST.keys()))
        if options.diagnostics: ui_type = 'basic' # enforce basic UI for --info

        # dry-run? Set [general]dry-run=True.
        if options.dryrun:
            dryrun = config.set('general', 'dry-run', 'True')
        config.set_if_not_exists('general', 'dry-run', 'False')

        try:
            # Create the ui class.
            self.ui = UI_LIST[ui_type.lower()](config)
        except KeyError:
            logging.error("UI '%s' does not exist, choose one of: %s"% \
                              (ui_type, ', '.join(UI_LIST.keys())))
            sys.exit(1)
        setglobalui(self.ui)

        # Set up additional log files.
        if options.logfile:
            self.ui.setlogfile(options.logfile)

        # Set up syslog.
        if options.syslog:
            self.ui.setup_sysloghandler()

        # Welcome blurb.
        self.ui.init_banner()

        if options.debugtype:
            self.ui.logger.setLevel(logging.DEBUG)
            if options.debugtype.lower() == 'all':
                options.debugtype = 'imap,maildir,thread'
            # Force single threading?
            if not ('thread' in options.debugtype.split(',') \
                    and not options.singlethreading):
                self.ui._msg("Debug mode: Forcing to singlethreaded.")
                options.singlethreading = True

            debugtypes = options.debugtype.split(',') + ['']
            for dtype in debugtypes:
                dtype = dtype.strip()
                self.ui.add_debug(dtype)
                if dtype.lower() == u'imap':
                    imaplib.Debug = 5

        if options.mbnames_prune:
            mbnames.init(config, self.ui, options.dryrun)
            mbnames.prune(config.get("general", "accounts"))
            mbnames.write()
            sys.exit(0)

        if options.runonce:
            # Must kill the possible default option.
            if config.has_option('DEFAULT', 'autorefresh'):
                config.remove_option('DEFAULT', 'autorefresh')
            # FIXME: spaghetti code alert!
            for section in accounts.getaccountlist(config):
                config.remove_option('Account ' + section, "autorefresh")

        if options.quick:
            for section in accounts.getaccountlist(config):
                config.set('Account ' + section, "quick", '-1')

        # Custom folder list specified?
        if options.folders:
            foldernames = options.folders.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')
                config.set(remote_repo_section, "folderfilter", folderfilter)
                config.set(remote_repo_section, "folderincludes",
                           folderincludes)

        if options.logfile:
            sys.stderr = self.ui.logfile

        socktimeout = config.getdefaultint("general", "socktimeout", 0)
        if socktimeout > 0:
            socket.setdefaulttimeout(socktimeout)

        threadutil.initInstanceLimit(
            ACCOUNT_LIMITED_THREAD_NAME,
            config.getdefaultint('general', 'maxsyncaccounts', 1)
            )

        for reposname in config.getsectionlist('Repository'):
            # XXX: We are likely lying around. If we must use at most n
            # connections for a remote IMAP server, why do we allow twice this
            # number? The max connections number is used by both the FOLDER_ and
            # the MSGCOPY_ prefixes!
            for namespace in [accounts.FOLDER_NAMESPACE + reposname,
                                 MSGCOPY_NAMESPACE + reposname]:
                if options.singlethreading:
                    threadutil.initInstanceLimit(namespace, 1)
                else:
                    threadutil.initInstanceLimit(
                        namespace,
                        config.getdefaultint(
                            'Repository ' + reposname,
                            'maxconnections', 2)
                        )
        self.config = config
        return (options, args)
Пример #12
0
    def __sync(self, options):
        """Invoke the correct single/multithread syncing

        self.config is supposed to have been correctly initialized
        already."""
        try:
            # Honor CLI --account option, only.
            # Accounts to sync are put into syncaccounts variable.
            activeaccounts = self.config.get("general", "accounts")
            if options.accounts:
                activeaccounts = options.accounts
            activeaccounts = activeaccounts.replace(" ", "")
            activeaccounts = activeaccounts.split(",")
            allaccounts = accounts.AccountHashGenerator(self.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 ac" \
                            "counts are: %s"% \
                            (account, ", ".join(allaccounts.keys()))
                    self.ui.terminate(1, errormsg=errormsg)
                if account not in syncaccounts:
                    syncaccounts.append(account)

            def sig_handler(sig, frame):
                if sig == signal.SIGUSR1:
                    # tell each account to stop sleeping
                    accounts.Account.set_abort_event(self.config, 1)
                elif sig == signal.SIGUSR2:
                    # tell each account to stop looping
                    getglobalui().warn("Terminating after this sync...")
                    accounts.Account.set_abort_event(self.config, 2)
                elif sig in (signal.SIGTERM, signal.SIGINT, signal.SIGHUP):
                    # tell each account to ABORT ASAP (ctrl-c)
                    getglobalui().warn("Terminating NOW (this may "\
                                       "take a few seconds)...")
                    accounts.Account.set_abort_event(self.config, 3)
                    if 'thread' in self.ui.debuglist:
                        self.__dumpstacks(5)

                    # Abort after three Ctrl-C keystrokes
                    self.num_sigterm += 1
                    if self.num_sigterm >= 3:
                        getglobalui().warn("Signaled thrice. Aborting!")
                        sys.exit(1)
                elif sig == signal.SIGQUIT:
                    stacktrace.dump(sys.stderr)
                    os.abort()

            self.num_sigterm = 0
            signal.signal(signal.SIGHUP, sig_handler)
            signal.signal(signal.SIGUSR1, sig_handler)
            signal.signal(signal.SIGUSR2, sig_handler)
            signal.signal(signal.SIGTERM, sig_handler)
            signal.signal(signal.SIGINT, sig_handler)
            signal.signal(signal.SIGQUIT, sig_handler)

            # Various initializations that need to be performed:
            mbnames.init(self.config, self.ui, options.dryrun)

            if options.singlethreading:
                # Singlethreaded.
                self.__sync_singlethreaded(syncaccounts)
            else:
                # Multithreaded.
                t = threadutil.ExitNotifyThread(
                    target=syncitall,
                    name='Sync Runner',
                    args=(syncaccounts, self.config,)
                    )
                # Special exit message for the monitor to stop looping.
                t.exit_message = threadutil.STOP_MONITOR
                t.start()
                threadutil.monitor()

            # All sync are done.
            mbnames.write()
            self.ui.terminate()
            return 0
        except (SystemExit):
            raise
        except Exception as e:
            self.ui.error(e)
            self.ui.terminate()
            return 1