def new_mesg(self, s, tn=None, secs=None): if secs is None: secs = time.time() if tn is None: tn = threading.currentThread().getName() tm = time.strftime('%M:%S', time.localtime(secs)) getglobalui().debug('imap', ' %s.%02d %s %s' % (tm, (secs*100)%100, tn, s))
def prime_gpg_agent(): ret = False count = 1 while not ret: ret = (mailpasswd("prime")=="prime") if count>2: from offlineimap.ui import getglobalui sys.stderr.write("Error reading in passwords. Terminating.\n") getglobalui().terminate() count += 1 return ret
def prime_gpg_agent(): # echo "prime" | gpg -e -r <recipient> > ~/.offlineimap/prime.gpg ret = False i = 1 while not ret: ret = (mailpasswd("prime") == "prime") if i > 2: from offlineimap.ui import getglobalui sys.stderr.write("Error reading in passwords. Terminating.\n") getglobalui().terminate() i += 1 return ret
def sig_handler(sig, frame): if sig == signal.SIGUSR1 or sig == signal.SIGHUP: # 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 == signal.SIGTERM or sig == signal.SIGINT: # 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)
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) elif sig == signal.SIGQUIT: stacktrace.dump(sys.stderr) os.abort()
def __init__(self, name, repository): """ :param name: Path & name of folder minus root or reference :param repository: Repository() in which the folder is. """ self.ui = getglobalui() self.messagelist = {} # Save original name for folderfilter operations. self.ffilter_name = name # Top level dir name is always ''. self.root = None self.name = name if not name == self.getsep() else '' self.newmail_hook = None # Only set the newmail_hook if the IMAP folder is named 'INBOX'. if self.name == 'INBOX': self.newmail_hook = repository.newmail_hook self.have_newmail = False self.copy_ignoreUIDs = None # List of UIDs to ignore. self.repository = repository self.visiblename = repository.nametrans(name) # In case the visiblename becomes '.' or '/' (top-level) we use # '' as that is the name that e.g. the Maildir scanning will # return for the top-level dir. if self.visiblename == self.getsep(): self.visiblename = '' self.repoconfname = "Repository " + repository.name self.config = repository.getconfig() # Do we need to use mail timestamp for filename prefix? filename_use_mail_timestamp_global = self.config.getdefaultboolean( "general", "filename_use_mail_timestamp", False) self._filename_use_mail_timestamp = self.config.getdefaultboolean( self.repoconfname, "filename_use_mail_timestamp", filename_use_mail_timestamp_global) self._sync_deletes = self.config.getdefaultboolean( self.repoconfname, "sync_deletes", True) # Determine if we're running static or dynamic folder filtering # and check filtering status. self._dynamic_folderfilter = self.config.getdefaultboolean( self.repoconfname, "dynamic_folderfilter", False) self._sync_this = repository.should_sync_folder(self.ffilter_name) if self._dynamic_folderfilter: self.ui.debug('', "Running dynamic folder filtering on '%s'[%s]"% (self.ffilter_name, repository)) elif not self._sync_this: self.ui.debug('', "Filtering out '%s'[%s] due to folderfilter"% (self.ffilter_name, repository)) # Passes for syncmessagesto. self.syncmessagesto_passes = [ self.__syncmessagesto_copy, self.__syncmessagesto_delete, self.__syncmessagesto_flags, ]
def prime_gpg_agent(): ret = False i = 1 while not ret: x = "" try: x = subprocess.check_output(["pass", "show", "prime"]).strip() except subprocess.CalledProcessError: x = "" ret = (x == "prime") if i > 2: from offlineimap.ui import getglobalui sys.stderr.write("Error reading in passwords. Terminating.\n") getglobalui().terminate() i += 1 return ret
def __init__(self, repos): self.ui = getglobalui() self.repos = repos self.config = repos.getconfig() self.tunnel = repos.getpreauthtunnel() self.usessl = repos.getssl() self.username = None if self.tunnel else repos.getuser() self.password = None self.passworderror = None self.goodpassword = None self.hostname = None if self.tunnel else repos.gethost() self.port = repos.getport() if self.port == None: self.port = 993 if self.usessl else 143 self.sslclientcert = repos.getsslclientcert() self.sslclientkey = repos.getsslclientkey() self.sslcacertfile = repos.getsslcacertfile() if self.sslcacertfile is None: self.verifycert = None # disable cert verification self.delim = None self.root = None self.maxconnections = repos.getmaxconnections() self.availableconnections = [] self.assignedconnections = [] self.lastowner = {} self.semaphore = BoundedSemaphore(self.maxconnections) self.connectionlock = Lock() self.reference = repos.getreference() self.idlefolders = repos.getidlefolders() self.gss_step = self.GSS_STATE_STEP self.gss_vc = None self.gssapi = False
def __init__(self, name, repository): """ :para name: Path & name of folder minus root or reference :para repository: Repository() in which the folder is. """ self.ui = getglobalui() """Should this folder be included in syncing?""" self._sync_this = repository.should_sync_folder(name) if not self._sync_this: self.ui.debug('', "Filtering out '%s'[%s] due to folderfilter" \ % (name, repository)) # Top level dir name is always '' self.name = name if not name == self.getsep() else '' self.repository = repository self.visiblename = repository.nametrans(name) # In case the visiblename becomes '.' or '/' (top-level) we use # '' as that is the name that e.g. the Maildir scanning will # return for the top-level dir. if self.visiblename == self.getsep(): self.visiblename = '' self.config = repository.getconfig() # Passes for syncmessagesto self.syncmessagesto_passes = [('copying messages' , self.syncmessagesto_copy), ('deleting messages' , self.syncmessagesto_delete), ('syncing flags' , self.syncmessagesto_flags)]
def __init__(self, config, name): """ :param config: Representing the offlineimap configuration file. :type config: :class:`offlineimap.CustomConfig.CustomConfigParser` :param name: A (str) string denoting the name of the Account as configured. """ self.config = config self.name = name self.metadatadir = config.getmetadatadir() self.localeval = config.getlocaleval() # Current :mod:`offlineimap.ui`, can be used for logging: self.ui = getglobalui() self.refreshperiod = self.getconffloat('autorefresh', 0.0) self.dryrun = self.config.getboolean('general', 'dry-run') self.quicknum = 0 if self.refreshperiod < 0: self.ui.warn("autorefresh for %s is negative, fixing it to 0."% name) self.refreshperiod = 0.0 if self.refreshperiod == 0.0: self.refreshperiod = None self.remoterepos = None self.localrepos = None self.statusrepos = None
def __init__(self, name, repository): """ :para name: Path & name of folder minus root or reference :para repository: Repository() in which the folder is. """ self.ui = getglobalui() """Should this folder be included in syncing?""" self._sync_this = repository.should_sync_folder(name) if not self._sync_this: self.ui.debug("", "Filtering out '%s'[%s] due to folderfilter" % (name, repository)) # Top level dir name is always '' self.name = name if not name == self.getsep() else "" self.repository = repository self.visiblename = repository.nametrans(name) # In case the visiblename becomes '.' or '/' (top-level) we use # '' as that is the name that e.g. the Maildir scanning will # return for the top-level dir. if self.visiblename == self.getsep(): self.visiblename = "" self.config = repository.getconfig() # Passes for syncmessagesto self.syncmessagesto_passes = [ ("copying messages", self.syncmessagesto_copy), ("deleting messages", self.syncmessagesto_delete), ("syncing flags", self.syncmessagesto_flags), ]
def __init__(self, name, repository): """ :para name: Path & name of folder minus root or reference :para repository: Repository() in which the folder is. """ self.ui = getglobalui() """Should this folder be included in syncing?""" self._sync_this = repository.should_sync_folder(name) if not self._sync_this: self.ui.debug('', "Filtering out '%s'[%s] due to folderfilter" \ % (name, repository)) # Top level dir name is always '' self.name = name if not name == self.getsep() else '' self.repository = repository self.visiblename = repository.nametrans(name) # In case the visiblename becomes '.' or '/' (top-level) we use # '' as that is the name that e.g. the Maildir scanning will # return for the top-level dir. if self.visiblename == self.getsep(): self.visiblename = '' self.config = repository.getconfig() utime_from_message_global = \ self.config.getdefaultboolean("general", "utime_from_message", False) repo = "Repository " + repository.name self._utime_from_message = \ self.config.getdefaultboolean(repo, "utime_from_message", utime_from_message_global)
def __init__(self, repos): self.ui = getglobalui() self.repos = repos self.config = repos.getconfig() self.tunnel = repos.getpreauthtunnel() self.usessl = repos.getssl() self.username = repos.getuser() self.password = None self.passworderror = None self.goodpassword = None self.hostname = repos.gethost() self.port = repos.getport() if self.port == None: self.port = 993 if self.usessl else 143 self.sslclientcert = repos.getsslclientcert() self.sslclientkey = repos.getsslclientkey() self.sslcacertfile = repos.getsslcacertfile() if self.sslcacertfile is None: self.verifycert = None # disable cert verification self.delim = None self.root = None self.maxconnections = repos.getmaxconnections() self.availableconnections = [] self.assignedconnections = [] self.lastowner = {} self.semaphore = BoundedSemaphore(self.maxconnections) self.connectionlock = Lock() self.reference = repos.getreference() self.idlefolders = repos.getidlefolders() self.gss_step = self.GSS_STATE_STEP self.gss_vc = None self.gssapi = False
def __init__(self, reposname, account): self.ui = getglobalui() self.account = account self.config = account.getconfig() self.name = reposname self.localeval = account.getlocaleval() self._accountname = self.account.getname() self._readonly = self.getconfboolean('readonly', False) self.uiddir = os.path.join(self.config.getmetadatadir(), 'Repository-' + self.name) if not os.path.exists(self.uiddir): os.mkdir(self.uiddir, 0o700) self.mapdir = os.path.join(self.uiddir, 'UIDMapping') if not os.path.exists(self.mapdir): os.mkdir(self.mapdir, 0o700) self.uiddir = os.path.join(self.uiddir, 'FolderValidity') if not os.path.exists(self.uiddir): os.mkdir(self.uiddir, 0o700) self.nametrans = lambda foldername: foldername self.folderfilter = lambda foldername: 1 self.folderincludes = [] self.foldersort = None if self.config.has_option(self.getsection(), 'nametrans'): self.nametrans = self.localeval.eval( self.getconf('nametrans'), {'re': re}) if self.config.has_option(self.getsection(), 'folderfilter'): self.folderfilter = self.localeval.eval( self.getconf('folderfilter'), {'re': re}) if self.config.has_option(self.getsection(), 'folderincludes'): self.folderincludes = self.localeval.eval( self.getconf('folderincludes'), {'re': re}) if self.config.has_option(self.getsection(), 'foldersort'): self.foldersort = self.localeval.eval( self.getconf('foldersort'), {'re': re})
def __init__(self, config, name): """ :param config: Representing the offlineimap configuration file. :type config: :class:`offlineimap.CustomConfig.CustomConfigParser` :param name: A (str) string denoting the name of the Account as configured. """ self.config = config self.name = name self.metadatadir = config.getmetadatadir() self.localeval = config.getlocaleval() # Current :mod:`offlineimap.ui`, can be used for logging: self.ui = getglobalui() self.refreshperiod = self.getconffloat('autorefresh', 0.0) self.dryrun = self.config.getboolean('general', 'dry-run') self.quicknum = 0 if self.refreshperiod < 0: self.ui.warn("autorefresh for %s is negative, fixing it to 0." % name) self.refreshperiod = 0.0 if self.refreshperiod == 0.0: self.refreshperiod = None self.remoterepos = None self.localrepos = None self.statusrepos = None
def __init__(self, reposname, account): self.ui = getglobalui() self.account = account self.config = account.getconfig() self.name = reposname self.localeval = account.getlocaleval() self._accountname = self.account.getname() self._readonly = self.getconfboolean('readonly', False) self.uiddir = os.path.join(self.config.getmetadatadir(), 'Repository-' + self.name) if not os.path.exists(self.uiddir): os.mkdir(self.uiddir, 0o700) self.mapdir = os.path.join(self.uiddir, 'UIDMapping') if not os.path.exists(self.mapdir): os.mkdir(self.mapdir, 0o700) self.uiddir = os.path.join(self.uiddir, 'FolderValidity') if not os.path.exists(self.uiddir): os.mkdir(self.uiddir, 0o700) self.nametrans = lambda foldername: foldername self.folderfilter = lambda foldername: 1 self.folderincludes = [] self.foldersort = None if self.config.has_option(self.getsection(), 'nametrans'): self.nametrans = self.localeval.eval(self.getconf('nametrans'), {'re': re}) if self.config.has_option(self.getsection(), 'folderfilter'): self.folderfilter = self.localeval.eval( self.getconf('folderfilter'), {'re': re}) if self.config.has_option(self.getsection(), 'folderincludes'): self.folderincludes = self.localeval.eval( self.getconf('folderincludes'), {'re': re}) if self.config.has_option(self.getsection(), 'foldersort'): self.foldersort = self.localeval.eval(self.getconf('foldersort'), {'re': re})
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) elif sig == signal.SIGQUIT: stacktrace.dump(sys.stderr) os.abort()
def __init__(self, config, name): self.config = config self.name = name self.metadatadir = config.getmetadatadir() self.localeval = config.getlocaleval() self.ui = getglobalui() self.refreshperiod = self.getconffloat('autorefresh', 0.0) self.quicknum = 0 if self.refreshperiod == 0.0: self.refreshperiod = None
def dosync(self): remoterepos = self.parent.repos account = remoterepos.account localrepos = account.localrepos remoterepos = account.remoterepos statusrepos = account.statusrepos remotefolder = remoterepos.getfolder(self.folder) offlineimap.accounts.syncfolder(account.name, remoterepos, remotefolder, localrepos, statusrepos, quick=False) ui = getglobalui() ui.unregisterthread(currentThread())
def dosync(self): remoterepos = self.parent.repos account = remoterepos.account localrepos = account.localrepos remoterepos = account.remoterepos statusrepos = account.statusrepos remotefolder = remoterepos.getfolder(self.folder) offlineimap.accounts.syncfolder(account, remotefolder, quick=False) ui = getglobalui() ui.unregisterthread(currentThread()) #syncfolder registered the thread
def __init__(self, repos): self.ui = getglobalui() self.repos = repos self.config = repos.getconfig() self.preauth_tunnel = repos.getpreauthtunnel() self.transport_tunnel = repos.gettransporttunnel() if self.preauth_tunnel and self.transport_tunnel: raise OfflineImapError('%s: ' % repos + \ 'you must enable precisely one ' 'type of tunnel (preauth or transport), ' 'not both', OfflineImapError.ERROR.REPO) self.tunnel = \ self.preauth_tunnel if self.preauth_tunnel \ else self.transport_tunnel self.username = \ None if self.preauth_tunnel else repos.getuser() self.user_identity = repos.get_remote_identity() self.authmechs = repos.get_auth_mechanisms() self.password = None self.oauth2 = repos.getoauth2() self.oauth2url = repos.getoauth2url() if self.oauth2 else None self.oauth2clientid = repos.getoauth2clientid() if self.oauth2 else None self.oauth2clientsecret = repos.getoauth2clientsecret() if self.oauth2 else None self.oauth2refreshtoken = repos.getoauth2refreshtoken() if self.oauth2 else None self.passworderror = None self.goodpassword = None self.usessl = repos.getssl() self.hostname = \ None if self.preauth_tunnel else repos.gethost() self.port = repos.getport() if self.port == None: self.port = 993 if self.usessl else 143 self.sslclientcert = repos.getsslclientcert() self.sslclientkey = repos.getsslclientkey() self.sslcacertfile = repos.getsslcacertfile() self.sslversion = repos.getsslversion() if self.sslcacertfile is None: self.__verifycert = None # disable cert verification self.delim = None self.root = None self.maxconnections = repos.getmaxconnections() self.availableconnections = [] self.assignedconnections = [] self.lastowner = {} self.semaphore = BoundedSemaphore(self.maxconnections) self.connectionlock = Lock() self.reference = repos.getreference() self.idlefolders = repos.getidlefolders() self.gss_step = self.GSS_STATE_STEP self.gss_vc = None self.gssapi = False
def __init__(self, reposname, account): """Initialize a MaildirRepository object. Takes a path name to the directory holding all the Maildir directories.""" BaseRepository.__init__(self, reposname, account) self.mailpath = self.getconf("mailpath", reposname) self.db_url = self.getconf("database") self.folders = None self.ui = getglobalui() self.connect()
def processcachemessagelist(folder): """Function used only when config syncflagsignoremaxage is True and the operation is sync.""" ui = getglobalui() ml = getcachemessagelist(folder.repository.name, folder, True) if ml == None: ui.cachingmessagesnomaxage(folder.repository.name, folder) folder.cachemessagelist() addcachemessagelist(folder.repository.name, folder, True, folder.getmessagelist()) else: folder.setmessagelist(ml)
def monitor(): """An infinite "monitoring" loop watching for finished ExitNotifyThread's. This one is supposed to run in the main thread. :param callback: the function to call when a thread terminated. That function is called with a single argument -- the ExitNotifyThread that has terminated. The monitor will not continue to monitor for other threads until 'callback' returns, so if it intends to perform long calculations, it should start a new thread itself -- but NOT an ExitNotifyThread, or else an infinite loop may result. Furthermore, the monitor will hold the lock all the while the other thread is waiting. :type callback: a callable function """ global exitedThreads ui = getglobalui() while True: # Loop forever and call 'callback' for each thread that exited try: # We need a timeout in the get() call, so that ctrl-c can throw a # SIGINT (http://bugs.python.org/issue1360). A timeout with empty # Queue will raise `Empty`. # # ExitNotifyThread add themselves to the exitedThreads queue once # they are done (normally or with exception). thread = exitedThreads.get(True, 60) # Request to abort when callback returns True. if thread.exit_exception is not None: if isinstance(thread.exit_exception, SystemExit): # Bring a SystemExit into the main thread. # Do not send it back to UI layer right now. # Maybe later send it to ui.terminate? raise SystemExit ui.threadException( thread) # Expected to terminate the program. # Should never hit this line. raise AssertionError( "thread has 'exit_exception' set to" " '%s' [%s] but this value is unexpected" " and the ui did not stop the program." % (repr(thread.exit_exception), type(thread.exit_exception))) # Only the monitor thread has this exit message set. elif thread.exit_message == STOP_MONITOR: break # Exit the loop here. else: ui.threadExited(thread) except Empty: pass
def dosync(self): remoterepos = self.parent.repos account = remoterepos.account localrepos = account.localrepos remoterepos = account.remoterepos statusrepos = account.statusrepos remotefolder = remoterepos.getfolder(self.folder) offlineimap.accounts.syncfolder(account, remotefolder, quick=False) ui = getglobalui() hook = account.getconf('postsynchook', '') account.callhook(hook) ui.unregisterthread(currentThread()) #syncfolder registered the thread
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 in (signal.SIGUSR2, signal.SIGABRT): # 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("Preparing to shutdown after sync (this may " "take some time), press CTRL-C three " "times to shutdown immediately") 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()
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 in (signal.SIGUSR2, signal.SIGABRT): # 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("Preparing to shutdown after sync (this may "\ "take some time), press CTRL-C three "\ "times to shutdown immediately") 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()
def monitor(): """An infinite "monitoring" loop watching for finished ExitNotifyThread's. This one is supposed to run in the main thread. :param callback: the function to call when a thread terminated. That function is called with a single argument -- the ExitNotifyThread that has terminated. The monitor will not continue to monitor for other threads until 'callback' returns, so if it intends to perform long calculations, it should start a new thread itself -- but NOT an ExitNotifyThread, or else an infinite loop may result. Furthermore, the monitor will hold the lock all the while the other thread is waiting. :type callback: a callable function """ global exitedThreads ui = getglobalui() while True: # Loop forever and call 'callback' for each thread that exited try: # We need a timeout in the get() call, so that ctrl-c can throw a # SIGINT (http://bugs.python.org/issue1360). A timeout with empty # Queue will raise `Empty`. # # ExitNotifyThread add themselves to the exitedThreads queue once # they are done (normally or with exception). thread = exitedThreads.get(True, 60) # Request to abort when callback returns True. if thread.exit_exception is not None: if isinstance(thread.exit_exception, SystemExit): # Bring a SystemExit into the main thread. # Do not send it back to UI layer right now. # Maybe later send it to ui.terminate? raise SystemExit ui.threadException(thread) # Expected to terminate the program. # Should never hit this line. raise AssertionError("thread has 'exit_exception' set to" " '%s' [%s] but this value is unexpected" " and the ui did not stop the program."% (repr(thread.exit_exception), type(thread.exit_exception))) # Only the monitor thread has this exit message set. elif thread.exit_message == STOP_MONITOR: break # Exit the loop here. else: ui.threadExited(thread) except Empty: pass
def __init__(self, name, repository): """ :param name: Path & name of folder minus root or reference :param repository: Repository() in which the folder is. """ self.ui = getglobalui() # Save original name for folderfilter operations self.ffilter_name = name # Top level dir name is always '' self.root = None self.name = name if not name == self.getsep() else '' self.newmail_hook = None # Only set the newmail_hook if the IMAP folder is named 'INBOX' if self.name == 'INBOX': self.newmail_hook = repository.newmail_hook self.have_newmail = False self.repository = repository self.visiblename = repository.nametrans(name) # In case the visiblename becomes '.' or '/' (top-level) we use # '' as that is the name that e.g. the Maildir scanning will # return for the top-level dir. if self.visiblename == self.getsep(): self.visiblename = '' self.config = repository.getconfig() utime_from_header_global = self.config.getdefaultboolean( "general", "utime_from_header", False) repo = "Repository " + repository.name self._utime_from_header = self.config.getdefaultboolean( repo, "utime_from_header", utime_from_header_global) # Determine if we're running static or dynamic folder filtering # and check filtering status self._dynamic_folderfilter = self.config.getdefaultboolean( repo, "dynamic_folderfilter", False) self._sync_this = repository.should_sync_folder(self.ffilter_name) if self._dynamic_folderfilter: self.ui.debug( '', "Running dynamic folder filtering on '%s'[%s]" % (self.ffilter_name, repository)) elif not self._sync_this: self.ui.debug( '', "Filtering out '%s'[%s] due to folderfilter" % (self.ffilter_name, repository)) # Passes for syncmessagesto self.syncmessagesto_passes = [ ('copying messages', self.__syncmessagesto_copy), ('deleting messages', self.__syncmessagesto_delete), ('syncing flags', self.__syncmessagesto_flags) ]
def __init__(self, parent, folder=None): """If invoked without 'folder', perform a NOOP and wait for self.stop() to be called. If invoked with folder, switch to IDLE mode and synchronize once we have a new message""" self.parent = parent self.folder = folder self.stop_sig = Event() self.ui = getglobalui() if folder is None: self.thread = Thread(target=self.noop) else: self.thread = Thread(target=self.idle) self.thread.setDaemon(1)
def __init__(self, reposname, account): """Initialize a MaildirRepository object. Takes a path name to the directory holding all the Maildir directories.""" BaseRepository.__init__(self, reposname, account) self.root = self.getlocalroot() self.folders = None self.ui = getglobalui() self.debug("MaildirRepository initialized, sep is " + repr(self.getsep())) self.folder_atimes = [] # Create the top-level folder if it doesn't exist if not os.path.isdir(self.root): os.mkdir(self.root, 0o700)
def __init__(self, reposname, account): """Initialize a MaildirRepository object. Takes a path name to the directory holding all the Maildir directories.""" BaseRepository.__init__(self, reposname, account) self.root = self.getlocalroot() self.folders = None self.ui = getglobalui() self.debug("MaildirRepository initialized, sep is " + repr(self.getsep())) self.folder_atimes = [] # Create the top-level folder if it doesn't exist if not os.path.isdir(self.root): os.mkdir(self.root, 0700)
def __init__(self, repos): self.ui = getglobalui() self.repos = repos self.config = repos.getconfig() self.preauth_tunnel = repos.getpreauthtunnel() self.transport_tunnel = repos.gettransporttunnel() if self.preauth_tunnel and self.transport_tunnel: raise OfflineImapError('%s: ' % repos + \ 'you must enable precisely one ' 'type of tunnel (preauth or transport), ' 'not both', OfflineImapError.ERROR.REPO) self.tunnel = \ self.preauth_tunnel if self.preauth_tunnel \ else self.transport_tunnel self.username = \ None if self.preauth_tunnel else repos.getuser() self.user_identity = repos.get_remote_identity() self.authmechs = repos.get_auth_mechanisms() self.password = None self.passworderror = None self.goodpassword = None self.usessl = repos.getssl() self.hostname = \ None if self.preauth_tunnel else repos.gethost() self.port = repos.getport() if self.port == None: self.port = 993 if self.usessl else 143 self.sslclientcert = repos.getsslclientcert() self.sslclientkey = repos.getsslclientkey() self.sslcacertfile = repos.getsslcacertfile() self.sslversion = repos.getsslversion() if self.sslcacertfile is None: self.verifycert = None # disable cert verification self.delim = None self.root = None self.maxconnections = repos.getmaxconnections() self.availableconnections = [] self.assignedconnections = [] self.lastowner = {} self.semaphore = BoundedSemaphore(self.maxconnections) self.connectionlock = Lock() self.reference = repos.getreference() self.idlefolders = repos.getidlefolders() self.gss_step = self.GSS_STATE_STEP self.gss_vc = None self.gssapi = False
def __dosync(self): remoterepos = self.parent.repos account = remoterepos.account remoterepos = account.remoterepos remotefolder = remoterepos.getfolder(self.folder, decode=False) hook = account.getconf('presynchook', '') account.callhook(hook) offlineimap.accounts.syncfolder(account, remotefolder, quick=False) hook = account.getconf('postsynchook', '') account.callhook(hook) ui = getglobalui() ui.unregisterthread(currentThread()) # syncfolder registered the thread
def syncfoldersto(self, dest, copyfolders): """Syncs the folders in this repository to those in dest. It does NOT sync the contents of those folders. For every time dest.makefolder() is called, also call makefolder() on each folder in copyfolders.""" src = self srcfolders = src.getfolders() destfolders = dest.getfolders() # Create hashes with the names, but convert the source folders # to the dest folder's sep. srchash = {} for folder in srcfolders: srchash[folder.getvisiblename().replace(src.getsep(), dest.getsep())] = \ folder desthash = {} for folder in destfolders: desthash[folder.getvisiblename()] = folder # # Find new folders. # for key in srchash.keys(): if not key in desthash: try: dest.makefolder(key) for copyfolder in copyfolders: copyfolder.makefolder(key.replace(dest.getsep(), copyfolder.getsep())) except (KeyboardInterrupt): raise except: getglobalui().warn("ERROR Attempting to make folder " \ + key + ":" +str(sys.exc_info()[1]))
def __init__(self, name, repository): """ :param name: Path & name of folder minus root or reference :param repository: Repository() in which the folder is. """ self.ui = getglobalui() # Save original name for folderfilter operations self.ffilter_name = name # Top level dir name is always '' self.root = None self.name = name if not name == self.getsep() else '' self.newmail_hook = None # Only set the newmail_hook if the IMAP folder is named 'INBOX' if self.name == 'INBOX': self.newmail_hook = repository.newmail_hook self.have_newmail = False self.repository = repository self.visiblename = repository.nametrans(name) # In case the visiblename becomes '.' or '/' (top-level) we use # '' as that is the name that e.g. the Maildir scanning will # return for the top-level dir. if self.visiblename == self.getsep(): self.visiblename = '' self.config = repository.getconfig() utime_from_header_global = self.config.getdefaultboolean( "general", "utime_from_header", False) repo = "Repository " + repository.name self._utime_from_header = self.config.getdefaultboolean(repo, "utime_from_header", utime_from_header_global) # Determine if we're running static or dynamic folder filtering # and check filtering status self._dynamic_folderfilter = self.config.getdefaultboolean( repo, "dynamic_folderfilter", False) self._sync_this = repository.should_sync_folder(self.ffilter_name) if self._dynamic_folderfilter: self.ui.debug('', "Running dynamic folder filtering on '%s'[%s]"% (self.ffilter_name, repository)) elif not self._sync_this: self.ui.debug('', "Filtering out '%s'[%s] due to folderfilter"% (self.ffilter_name, repository)) # Passes for syncmessagesto self.syncmessagesto_passes = [('copying messages' , self.__syncmessagesto_copy), ('deleting messages' , self.__syncmessagesto_delete), ('syncing flags' , self.__syncmessagesto_flags)]
def __init__(self, reposname, account): self.ui = getglobalui() self.account = account self.config = account.getconfig() self.name = reposname self.localeval = account.getlocaleval() self.accountname = self.account.getname() self.uiddir = os.path.join(self.config.getmetadatadir(), 'Repository-' + self.name) if not os.path.exists(self.uiddir): os.mkdir(self.uiddir, 0700) self.mapdir = os.path.join(self.uiddir, 'UIDMapping') if not os.path.exists(self.mapdir): os.mkdir(self.mapdir, 0700) self.uiddir = os.path.join(self.uiddir, 'FolderValidity') if not os.path.exists(self.uiddir): os.mkdir(self.uiddir, 0700)
def __init__(self, config, reposname, username=None, password=None, hostname=None, port=None, ssl=1, maxconnections=1, tunnel=None, reference='""', sslclientcert=None, sslclientkey=None, sslcacertfile=None, idlefolders=[]): self.ui = getglobalui() self.reposname = reposname self.config = config self.username = username self.password = password self.passworderror = None self.goodpassword = None self.hostname = hostname self.tunnel = tunnel self.port = port self.usessl = ssl self.sslclientcert = sslclientcert self.sslclientkey = sslclientkey self.sslcacertfile = sslcacertfile self.delim = None self.root = None if port == None: if ssl: self.port = 993 else: self.port = 143 self.maxconnections = maxconnections self.availableconnections = [] self.assignedconnections = [] self.lastowner = {} self.semaphore = BoundedSemaphore(self.maxconnections) self.connectionlock = Lock() self.reference = reference self.idlefolders = idlefolders self.gss_step = self.GSS_STATE_STEP self.gss_vc = None self.gssapi = False
def savemessage(self, uid, content, flags, rtime): """Writes a new message, with the specified uid. See folder/Base for detail. Note that savemessage() does not check against dryrun settings, so you need to ensure that savemessage is never called in a dryrun mode.""" # This function only ever saves to tmp/, # but it calls savemessageflags() to actually save to cur/ or new/. self.ui.savemessage('maildir', uid, flags, self) if uid < 0: # We cannot assign a new uid. return uid if uid in self.messagelist: # We already have it, just update flags. self.savemessageflags(uid, flags) return uid # Otherwise, save the message in tmp/ and then call savemessageflags() # to give it a permanent home. tmpdir = os.path.join(self.getfullname(), 'tmp') messagename = self.new_message_filename(uid, flags) tmpname = self.save_to_tmp_file(messagename, content) if self.utime_from_header: try: date = emailutil.get_message_date(content, 'Date') if date is not None: os.utime(os.path.join(self.getfullname(), tmpname), (date, date)) # In case date is wrongly so far into the future as to be > max int32 except Exception as e: from email.Parser import Parser from offlineimap.ui import getglobalui datestr = Parser().parsestr(content, True).get("Date") ui = getglobalui() ui.warn("UID %d has invalid date %s: %s\n" "Not changing file modification time" % (uid, datestr, e)) self.messagelist[uid] = self.msglist_item_initializer(uid) self.messagelist[uid]['flags'] = flags self.messagelist[uid]['filename'] = tmpname # savemessageflags moves msg to 'cur' or 'new' as appropriate self.savemessageflags(uid, flags) self.ui.debug('maildir', 'savemessage: returning uid %d' % uid) return uid
def __init__(self, name, repository): """ :para name: Path & name of folder minus root or reference :para repository: Repository() in which the folder is. """ self.sync_this = True """Should this folder be included in syncing?""" self.ui = getglobalui() self.name = name self.repository = repository self.visiblename = repository.nametrans(name) # In case the visiblename becomes '.' (top-level) we use '' as # that is the name that e.g. the Maildir scanning will return # for the top-level dir. if self.visiblename == '.': self.visiblename = '' self.config = repository.getconfig()
def __init__(self, config, name): """ :param config: Representing the offlineimap configuration file. :type config: :class:`offlineimap.CustomConfig.CustomConfigParser` :param name: A string denoting the name of the Account as configured""" self.config = config self.name = name self.metadatadir = config.getmetadatadir() self.localeval = config.getlocaleval() #Contains the current :mod:`offlineimap.ui`, and can be used for logging etc. self.ui = getglobalui() self.refreshperiod = self.getconffloat('autorefresh', 0.0) self.quicknum = 0 if self.refreshperiod == 0.0: self.refreshperiod = None
def threadexited(thread): """Called when a thread exits.""" ui = getglobalui() if thread.getExitCause() == 'EXCEPTION': if isinstance(thread.getExitException(), SystemExit): # Bring a SystemExit into the main thread. # Do not send it back to UI layer right now. # Maybe later send it to ui.terminate? raise SystemExit ui.threadException(thread) # Expected to terminate sys.exit(100) # Just in case... elif thread.getExitMessage() == 'SYNC_WITH_TIMER_TERMINATE': ui.terminate() # Just in case... sys.exit(100) else: ui.threadExited(thread)
def savemessage(self, uid, content, flags, rtime): """Writes a new message, with the specified uid. See folder/Base for detail. Note that savemessage() does not check against dryrun settings, so you need to ensure that savemessage is never called in a dryrun mode.""" # This function only ever saves to tmp/, # but it calls savemessageflags() to actually save to cur/ or new/. self.ui.savemessage("maildir", uid, flags, self) if uid < 0: # We cannot assign a new uid. return uid if uid in self.messagelist: # We already have it, just update flags. self.savemessageflags(uid, flags) return uid # Otherwise, save the message in tmp/ and then call savemessageflags() # to give it a permanent home. tmpdir = os.path.join(self.getfullname(), "tmp") messagename = self.new_message_filename(uid, flags) tmpname = self.save_to_tmp_file(messagename, content) if self.utime_from_header: try: date = emailutil.get_message_date(content, "Date") if date is not None: os.utime(os.path.join(self.getfullname(), tmpname), (date, date)) # In case date is wrongly so far into the future as to be > max int32 except Exception as e: from email.Parser import Parser from offlineimap.ui import getglobalui datestr = Parser().parsestr(content, True).get("Date") ui = getglobalui() ui.warn("UID %d has invalid date %s: %s\n" "Not changing file modification time" % (uid, datestr, e)) self.messagelist[uid] = self.msglist_item_initializer(uid) self.messagelist[uid]["flags"] = flags self.messagelist[uid]["filename"] = tmpname # savemessageflags moves msg to 'cur' or 'new' as appropriate self.savemessageflags(uid, flags) self.ui.debug("maildir", "savemessage: returning uid %d" % uid) return uid
def threadexited(thread): """Called when a thread exits. Main thread is aborted when this returns True.""" ui = getglobalui() if thread.exit_exception: if isinstance(thread.exit_exception, SystemExit): # Bring a SystemExit into the main thread. # Do not send it back to UI layer right now. # Maybe later send it to ui.terminate? raise SystemExit ui.threadException(thread) # Expected to terminate sys.exit(100) # Just in case... elif thread.exit_message == 'SYNCRUNNER_EXITED_NORMALLY': return True else: ui.threadExited(thread) return False
def __init__(self, config, name): """ :param config: Representing the offlineimap configuration file. :type config: :class:`offlineimap.CustomConfig.CustomConfigParser` :param name: A string denoting the name of the Account as configured""" self.config = config self.name = name self.metadatadir = config.getmetadatadir() self.localeval = config.getlocaleval() # current :mod:`offlineimap.ui`, can be used for logging: self.ui = getglobalui() self.refreshperiod = self.getconffloat('autorefresh', 0.0) # should we run in "dry-run" mode? self.dryrun = self.config.getboolean('general', 'dry-run') self.quicknum = 0 if self.refreshperiod == 0.0: self.refreshperiod = None
def monitor(): """An infinite "monitoring" loop watching for finished ExitNotifyThread's. This one is supposed to run in the main thread. """ global exitedThreads ui = getglobalui() while True: # Loop forever and call 'callback' for each thread that exited try: # We need a timeout in the get() call, so that ctrl-c can throw a # SIGINT (http://bugs.python.org/issue1360). A timeout with empty # Queue will raise `Empty`. # # ExitNotifyThread add themselves to the exitedThreads queue once # they are done (normally or with exception). thread = exitedThreads.get(True, 60) # Request to abort when callback returns True. if thread.exit_exception is not None: if isinstance(thread.exit_exception, SystemExit): # Bring a SystemExit into the main thread. # Do not send it back to UI layer right now. # Maybe later send it to ui.terminate? raise SystemExit ui.threadException(thread) # Expected to terminate the program. # Should never hit this line. raise AssertionError("thread has 'exit_exception' set to" " '%s' [%s] but this value is unexpected" " and the ui did not stop the program." % (repr(thread.exit_exception), type(thread.exit_exception))) # Only the monitor thread has this exit message set. elif thread.exit_message == STOP_MONITOR: break # Exit the loop here. else: ui.threadExited(thread) except Empty: pass
def idle(self): while True: if self.event.isSet(): return self.needsync = False self.imapaborted = False def callback(args): result, cb_arg, exc_data = args if exc_data is None: if not self.event.isSet(): self.needsync = True self.event.set() else: # We got an "abort" signal. self.imapaborted = True self.stop() imapobj = self.parent.acquireconnection() imapobj.select(self.folder) if "IDLE" in imapobj.capabilities: imapobj.idle(callback=callback) else: ui = getglobalui() ui.warn("IMAP IDLE not supported on connection to %s." "Falling back to old behavior: sleeping until next" "refresh cycle." % (imapobj.identifier, )) imapobj.noop() self.event.wait() if self.event.isSet(): # Can't NOOP on a bad connection. if not self.imapaborted: imapobj.noop() # We don't do event.clear() so that we'll fall out # of the loop next time around. self.parent.releaseconnection(imapobj) if self.needsync: self.event.clear() self.dosync()
def __init__(self, name, repository): """ :para name: Path & name of folder minus root or reference :para repository: Repository() in which the folder is. """ self.ui = getglobalui() # Save original name for folderfilter operations self.ffilter_name = name # Top level dir name is always '' self.name = name if not name == self.getsep() else '' self.repository = repository self.visiblename = repository.nametrans(name) # In case the visiblename becomes '.' or '/' (top-level) we use # '' as that is the name that e.g. the Maildir scanning will # return for the top-level dir. if self.visiblename == self.getsep(): self.visiblename = '' self.config = repository.getconfig() utime_from_message_global = \ self.config.getdefaultboolean("general", "utime_from_message", False) repo = "Repository " + repository.name self._utime_from_message = \ self.config.getdefaultboolean(repo, "utime_from_message", utime_from_message_global) # Determine if we're running static or dynamic folder filtering # and check filtering status self._dynamic_folderfilter = \ self.config.getdefaultboolean(repo, "dynamic_folderfilter", False) self._sync_this = repository.should_sync_folder(self.ffilter_name) if self._dynamic_folderfilter: self.ui.debug('', "Running dynamic folder filtering on '%s'[%s]" \ % (self.ffilter_name, repository)) elif not self._sync_this: self.ui.debug('', "Filtering out '%s'[%s] due to folderfilter" \ % (self.ffilter_name, repository))
def __init__(self, reposname, account): """Initialize a MaildirRepository object. Takes a path name to the directory holding all the Maildir directories.""" BaseRepository.__init__(self, reposname, account) self.root = self.getlocalroot() self.folders = None self.ui = getglobalui() self.debug("MaildirRepository initialized, sep is %s" % repr(self.getsep())) self.folder_atimes = [] # Create the top-level folder if it doesn't exist if not os.path.isdir(self.root): os.makedirs(self.root, 0o700) # Create the keyword->char mapping self.keyword2char = dict() for c in 'abcdefghijklmnopqrstuvwxyz': confkey = 'customflag_' + c keyword = self.getconf(confkey, None) if keyword is not None: self.keyword2char[keyword] = c
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()