diff --git a/Changelog.rst b/Changelog.rst index 7acccd3..704d3ae 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -13,6 +13,7 @@ WIP (add new stuff for the next release) * Curses UI, don't use colors after we shut down curses already (C.Höger) * Document that '%' needs encoding as '%%' in *.conf * Fix crash when IMAP.quickchanged() led to an Error (reported by sharat87) +* Implement the createfolders setting to disable folder propagation (see docs) OfflineIMAP v6.5.3.1 (2012-04-03) ================================= diff --git a/docs/doc-src/nametrans.rst b/docs/doc-src/nametrans.rst index ca25345..c211072 100644 --- a/docs/doc-src/nametrans.rst +++ b/docs/doc-src/nametrans.rst @@ -65,6 +65,22 @@ have filtered out everything starting with "debian" in your folderfilter settings. +createfolders +------------- + +By default OfflineImap propagates new folders in both +directions. Sometimes this is not what you want. E.g. you might want +new folders on your IMAP server to propagate to your local MailDir, +but not the other way around. The 'readonly' setting on a repository +will not help here, as it prevents any change from occuring on that +repository. This is what the `createfolders` setting is for. By +default it is `True`, meaning that new folders can be created on this +repository. To prevent folders from ever being created on a +repository, set this to `False`. If you set this to False on the +REMOTE repository, you will not have to create the `Reverse +nametrans`_ rules on the LOCAL repository. + + nametrans ---------- diff --git a/offlineimap.conf b/offlineimap.conf index 0c1880f..fccceab 100644 --- a/offlineimap.conf +++ b/offlineimap.conf @@ -504,6 +504,14 @@ remoteuser = username # one. For example: # folderincludes = ['debian.user', 'debian.personal'] + +# If you do not want to have any folders created on this repository, +# set the createfolders variable to False, the default is True. Using +# this feature you can e.g. disable the propagation of new folders to +# the new repository. +#createfolders = True + + # 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. The two diff --git a/offlineimap/repository/Base.py b/offlineimap/repository/Base.py index 61cdc75..81050b0 100644 --- a/offlineimap/repository/Base.py +++ b/offlineimap/repository/Base.py @@ -129,6 +129,13 @@ class BaseRepository(CustomConfig.ConfigHelperMixin, object): def getsep(self): raise NotImplementedError + def get_create_folders(self): + """Is folder creation enabled on this repository? + + It is disabled by either setting the whole repository + 'readonly' or by using the 'createfolders' setting.""" + return self._readonly or self.getconfboolean('createfolders', True) + def makefolder(self, foldername): """Create a new folder""" raise NotImplementedError @@ -147,6 +154,10 @@ class BaseRepository(CustomConfig.ConfigHelperMixin, object): that forward and backward nametrans actually match up! Configuring nametrans on BOTH repositories therefore could lead to infinite folder creation cycles.""" + if not self.get_create_folders() and not dst_repo.get_create_folders(): + # quick exit if no folder creation is enabled on either side. + return + src_repo = self src_folders = src_repo.getfolders() dst_folders = dst_repo.getfolders() @@ -166,7 +177,7 @@ class BaseRepository(CustomConfig.ConfigHelperMixin, object): # Find new folders on src_repo. for src_name_t, src_folder in src_hash.iteritems(): # Don't create on dst_repo, if it is readonly - if dst_repo.getconfboolean('readonly', False): + if not dst_repo.get_create_folders(): break if src_folder.sync_this and not src_name_t in dst_folders: try: @@ -181,7 +192,7 @@ class BaseRepository(CustomConfig.ConfigHelperMixin, object): status_repo.getsep())) # Find new folders on dst_repo. for dst_name_t, dst_folder in dst_hash.iteritems(): - if self.getconfboolean('readonly', False): + if not src_repo.get_create_folders(): # Don't create missing folder on readonly repo. break diff --git a/test/tests/test_01_basic.py b/test/tests/test_01_basic.py index f5a0ea1..8e45a62 100644 --- a/test/tests/test_01_basic.py +++ b/test/tests/test_01_basic.py @@ -105,6 +105,7 @@ class TestBasicFunctions(unittest.TestCase): # Write out default config file again OLITestLib.write_config_file() + def test_04_createmail(self): """Create mail in OLItest 1, sync, wipe folder sync @@ -127,3 +128,30 @@ class TestBasicFunctions(unittest.TestCase): self.assertFalse (None in uids, msg = "All mails should have been "+ \ "assigned the IMAP's UID number, but {} messages had no valid ID "\ .format(len([None for x in uids if x==None]))) + + def test_05_createfolders(self): + """Test if createfolders works as expected + + Create a local Maildir, then sync with remote "createfolders" + disabled. Delete local Maildir and sync. We should have no new + local maildir then. TODO: Rewrite this test to directly test + and count the remote folders when the helper functions have + been written""" + config = OLITestLib.get_default_config() + config.set('Repository IMAP', 'createfolders', + 'False' ) + OLITestLib.write_config_file(config) + + # delete all remote and local testfolders + OLITestLib.delete_remote_testfolders() + OLITestLib.delete_maildir('') + OLITestLib.create_maildir('INBOX.OLItest') + code, res = OLITestLib.run_OLI() + #logging.warn("%s %s "% (code, res)) + self.assertEqual(res, "") + OLITestLib.delete_maildir('INBOX.OLItest') + code, res = OLITestLib.run_OLI() + boxes, mails = OLITestLib.count_maildir_mails('') + self.assertTrue((boxes, mails)==(0,0), msg="Expected 0 folders and 0 " + "mails, but sync led to {} folders and {} mails".format( + boxes, mails))