diff --git a/offlineimap/head/offlineimap.conf b/offlineimap/head/offlineimap.conf index 9fbbb35..c893ea9 100644 --- a/offlineimap/head/offlineimap.conf +++ b/offlineimap/head/offlineimap.conf @@ -75,6 +75,16 @@ ui = Tk.Blinkenlights, Tk.VerboseUI, TTY.TTYUI, Noninteractive.Basic, ignore-readonly = no +########## Advanced settings + +# You can give a Python source filename here and all config file +# python snippets will be evaluated in the context of that file. +# This allows you to e.g. define helper functions in the Python +# source file and call them from this config file. +# +# pythonfile = ~/.offlineimap.py +# + ################################################## # Mailbox name recorder ################################################## @@ -251,6 +261,14 @@ remoteuser = username # folderincludes = ['box1', 'box2', 'box3', 'box4', # 'box5', 'box6'] +# You can specify foldersort to determine how folders are sorted. +# This affects order of synchronization and mbnames. The expression +# should return -1, 0, or 1, as the default Python cmp() does. +# +# To reverse the sort: +# +# foldersort = lambda x, y: -cmp(x, y) + # OfflineIMAP can use multiple connections to the server in order # to perform multiple synchronization actions simultaneously. diff --git a/offlineimap/head/offlineimap.py b/offlineimap/head/offlineimap.py index 6f8659e..d24f2e9 100644 --- a/offlineimap/head/offlineimap.py +++ b/offlineimap/head/offlineimap.py @@ -17,7 +17,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -from offlineimap import imaplib, imaputil, imapserver, repository, folder, mbnames, threadutil, version +from offlineimap import imaplib, imaputil, imapserver, repository, folder, mbnames, threadutil, version, localeval from offlineimap.threadutil import InstanceLimitedThread, ExitNotifyThread from offlineimap.ui import UIBase import re, os, os.path, offlineimap, sys @@ -58,10 +58,16 @@ if not os.path.exists(configfilename): config.read(configfilename) -if '-u' in options: - ui = offlineimap.ui.detector.getUImod(options['-u'])(config) +if config.has_option("general", "pythonfile"): + path=os.path.expanduser(config.get("general", "pythonfile")) else: - ui = offlineimap.ui.detector.findUI(config) + path=None +localeval = localeval.LocalEval(path) + +if '-u' in options: + ui = offlineimap.ui.detector.getUImod(options['-u'])(config, localeval) +else: + ui = offlineimap.ui.detector.findUI(config, localeval) ui.init_banner() if '-d' in options: @@ -138,7 +144,7 @@ def syncaccount(accountname, *args): server = imapserver.ConfigedIMAPServer(config, accountname, passwords) servers[accountname] = server - remoterepos = repository.IMAP.IMAPRepository(config, accountname, server) + remoterepos = repository.IMAP.IMAPRepository(config, localeval, accountname, server) # Connect to the Maildirs. localrepos = repository.Maildir.MaildirRepository(os.path.expanduser(config.get(accountname, "localfolders")), accountname, config) @@ -256,7 +262,7 @@ def syncitall(): threads.append(thread) # Wait for the threads to finish. threadutil.threadsreset(threads) - mbnames.genmbnames(config, mailboxes) + mbnames.genmbnames(config, localeval, mailboxes) def sync_with_timer(): currentThread().setExitMessage('SYNC_WITH_TIMER_TERMINATE') diff --git a/offlineimap/head/offlineimap/mbnames.py b/offlineimap/head/offlineimap/mbnames.py index 24944ee..9329c4d 100644 --- a/offlineimap/head/offlineimap/mbnames.py +++ b/offlineimap/head/offlineimap/mbnames.py @@ -18,16 +18,16 @@ import os.path -def genmbnames(config, boxlist): +def genmbnames(config, localeval, boxlist): """Takes a configparser object and a boxlist, which is a list of hashes containing 'accountname' and 'foldername' keys.""" if not config.getboolean("mbnames", "enabled"): return file = open(os.path.expanduser(config.get("mbnames", "filename")), "wt") - file.write(eval(config.get("mbnames", "header"))) - itemlist = [eval(config.get("mbnames", "peritem", raw=1)) % item for item in boxlist] - file.write(eval(config.get("mbnames", "sep")).join(itemlist)) - file.write(eval(config.get("mbnames", "footer"))) + file.write(localeval.eval(config.get("mbnames", "header"))) + itemlist = [localeval.eval(config.get("mbnames", "peritem", raw=1)) % item for item in boxlist] + file.write(localeval.eval(config.get("mbnames", "sep")).join(itemlist)) + file.write(localeval.eval(config.get("mbnames", "footer"))) file.close() diff --git a/offlineimap/head/offlineimap/repository/IMAP.py b/offlineimap/head/offlineimap/repository/IMAP.py index d0833ce..6af8158 100644 --- a/offlineimap/head/offlineimap/repository/IMAP.py +++ b/offlineimap/head/offlineimap/repository/IMAP.py @@ -22,7 +22,7 @@ import re from threading import * class IMAPRepository(BaseRepository): - def __init__(self, config, accountname, imapserver): + def __init__(self, config, localeval, accountname, imapserver): """Initialize an IMAPRepository object. Takes an IMAPServer object.""" self.imapserver = imapserver @@ -32,12 +32,15 @@ class IMAPRepository(BaseRepository): self.nametrans = lambda foldername: foldername self.folderfilter = lambda foldername: 1 self.folderincludes = [] + self.foldersort = cmp if config.has_option(accountname, 'nametrans'): - self.nametrans = eval(config.get(accountname, 'nametrans')) + self.nametrans = localeval.eval(config.get(accountname, 'nametrans'), {'re': re}) if config.has_option(accountname, 'folderfilter'): - self.folderfilter = eval(config.get(accountname, 'folderfilter')) + self.folderfilter = localeval.eval(config.get(accountname, 'folderfilter'), {'re': re}) if config.has_option(accountname, 'folderincludes'): - self.folderincludes = eval(config.get(accountname, 'folderincludes')) + self.folderincludes = localeval.eval(config.get(accountname, 'folderincludes'), {'re': re}) + if config.has_option(accountname, 'foldersort'): + self.foldersort = localeval.eval(config.get(accountname, 'foldersort'), {'re': re}) def getsep(self): return self.imapserver.delim @@ -71,6 +74,6 @@ class IMAPRepository(BaseRepository): retval.append(folder.IMAP.IMAPFolder(self.imapserver, foldername, self.nametrans(foldername), self.accountname)) - retval.sort(lambda x, y: cmp(x.getvisiblename(), y.getvisiblename())) + retval.sort(lambda x, y: self.foldersort(x.getvisiblename(), y.getvisiblename())) self.folders = retval return retval diff --git a/offlineimap/head/offlineimap/ui/detector.py b/offlineimap/head/offlineimap/ui/detector.py index 1523fb9..361ae7f 100644 --- a/offlineimap/head/offlineimap/ui/detector.py +++ b/offlineimap/head/offlineimap/ui/detector.py @@ -16,16 +16,21 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -from offlineimap.ui import * +import offlineimap.ui import sys -def findUI(config): +def findUI(config, localeval): uistrlist = ['Tk.Blinkenlights', 'Tk.VerboseUI', 'TTY.TTYUI', 'Noninteractive.Basic', 'Noninteractive.Quiet'] + namespace={} + for ui in dir(offlineimap.ui): + if ui.startswith('_') or ui=='detector': + continue + namespace[ui]=getattr(offlineimap.ui, ui) if config.has_option("general", "ui"): uistrlist = config.get("general", "ui").replace(" ", "").split(",") for uistr in uistrlist: - uimod = getUImod(uistr) + uimod = getUImod(uistr, localeval, namespace) if uimod: uiinstance = uimod(config) if uiinstance.isusable(): @@ -33,9 +38,9 @@ def findUI(config): sys.stderr.write("ERROR: No UIs were found usable!\n") sys.exit(200) -def getUImod(uistr): +def getUImod(uistr, localeval, namespace): try: - uimod = eval(uistr) - except (AttributeError, NameError): + uimod = localeval.eval(uistr, namespace) + except (AttributeError, NameError), e: return None return uimod