From 2e81331a3cd47e39a501a5131a12c5ee0e7e617a Mon Sep 17 00:00:00 2001 From: Nicolas Sebrecht Date: Fri, 8 Jul 2016 21:23:27 +0200 Subject: [PATCH] learn --delete-folder CLI option Signed-off-by: Nicolas Sebrecht --- docs/offlineimap.txt | 8 ++++++++ offlineimap/accounts.py | 15 +++++++++++++++ offlineimap/init.py | 17 ++++++++++++++++- offlineimap/repository/IMAP.py | 24 ++++++++++++++++++------ 4 files changed, 57 insertions(+), 7 deletions(-) diff --git a/docs/offlineimap.txt b/docs/offlineimap.txt index f434336..ddafc91 100644 --- a/docs/offlineimap.txt +++ b/docs/offlineimap.txt @@ -153,6 +153,14 @@ is not usable. Possible interface choices are: quiet, basic, syslog, ttyui, blinkenlights, machineui. +--delete-folder:: + Delete a folder on the remote repository. ++ +Only one account must be specified/configured for this feature to work. The +folder name must be provided in IMAP encoding with the remote separators (likely +'/'). E.g.: "Remote/folder/name". + + --migrate-fmd5-using-nametrans:: Migrate FMD5 hashes from versions prior to 6.3.5. + diff --git a/offlineimap/accounts.py b/offlineimap/accounts.py index 741b81e..a40fad2 100644 --- a/offlineimap/accounts.py +++ b/offlineimap/accounts.py @@ -183,6 +183,21 @@ class Account(CustomConfig.ConfigHelperMixin): self.ui.serverdiagnostics(local_repo, 'Local') #self.ui.serverdiagnostics(statusrepos, 'Status') + def deletefolder(self, foldername): + remote_repo = Repository(self, 'remote') + + try: + if self.dryrun: + self.ui.info("would try to remove '%s' on remote of '%s' " + "account"% (foldername, self)) + else: + remote_repo.deletefolder(foldername) + self.ui.info("Folder '%s' deleted."% foldername) + return 0 + except Exception as e: + self.ui.error(e) + return 1 + class SyncableAccount(Account): """A syncable email account connecting 2 repositories. diff --git a/offlineimap/init.py b/offlineimap/init.py index 880d535..c2a9d84 100644 --- a/offlineimap/init.py +++ b/offlineimap/init.py @@ -27,7 +27,7 @@ from optparse import OptionParser import offlineimap import offlineimap.virtual_imaplib2 as imaplib -from offlineimap import globals, accounts, threadutil, folder, mbnames +from offlineimap import globals, threadutil, accounts, folder, mbnames from offlineimap.ui import UI_LIST, setglobalui, getglobalui from offlineimap.CustomConfig import CustomConfigParser from offlineimap.utils import stacktrace @@ -77,6 +77,8 @@ class OfflineImap(object): 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) @@ -148,6 +150,11 @@ class OfflineImap(object): help="specifies an alternative user interface" " (quiet, basic, syslog, ttyui, blinkenlights, machineui)") + parser.add_option("--delete-folder", dest="deletefolder", + default=None, + metavar="FOLDERNAME", + help="Delete a folder") + 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") @@ -475,6 +482,14 @@ class OfflineImap(object): account = accounts.Account(self.config, accountname) account.serverdiagnostics() + def __deletefolder(self, options): + list_accounts = self._get_activeaccounts(options) + if len(list_accounts) != 1: + self.ui.error("you must supply only one account with '-a'") + return 1 + account = accounts.Account(self.config, list_accounts.pop()) + return account.deletefolder(options.deletefolder) + def __migratefmd5(self, options): for accountname in self._get_activeaccounts(options): account = accounts.Account(self.config, accountname) diff --git a/offlineimap/repository/IMAP.py b/offlineimap/repository/IMAP.py index d5db185..01a5583 100644 --- a/offlineimap/repository/IMAP.py +++ b/offlineimap/repository/IMAP.py @@ -15,17 +15,16 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -from threading import Event import os -from sys import exc_info import netrc import errno -import six import codecs +from sys import exc_info +from threading import Event +import six -from offlineimap.repository.Base import BaseRepository from offlineimap import folder, imaputil, imapserver, OfflineImapError -from offlineimap.folder.UIDMaps import MappedIMAPFolder +from offlineimap.repository.Base import BaseRepository from offlineimap.threadutil import ExitNotifyThread from offlineimap.utils.distro import get_os_sslcertfile, get_os_sslcertfile_searchpath @@ -471,6 +470,19 @@ class IMAPRepository(BaseRepository): self.folders = retval return self.folders + def deletefolder(self, foldername): + """Delete a folder on the IMAP server.""" + + imapobj = self.imapserver.acquireconnection() + try: + result = imapobj.delete(foldername) + if result[0] != 'OK': + raise OfflineImapError("Folder '%s'[%s] could not be deleted. " + "Server responded: %s"% (foldername, self, str(result)), + OfflineImapError.ERROR.FOLDER) + finally: + self.imapserver.releaseconnection(imapobj) + def makefolder(self, foldername): """Create a folder on the IMAP server @@ -502,4 +514,4 @@ class IMAPRepository(BaseRepository): class MappedIMAPRepository(IMAPRepository): def getfoldertype(self): - return MappedIMAPFolder + return folder.UIDMaps.MappedIMAPFolder