4 commits - cyruslib.py pykolab/cli pykolab/imap
Jeroen van Meeuwen
vanmeeuwen at kolabsys.com
Wed Aug 8 16:05:23 CEST 2012
cyruslib.py | 69 ++++++++++++++++++++++++-----
pykolab/cli/cmd_list_mailbox_acls.py | 8 ++-
pykolab/cli/cmd_list_mailbox_metadata.py | 66 ++++++++++++++++++++++++++++
pykolab/cli/cmd_set_mailbox_metadata.py | 72 +++++++++++++++++++++++++++++++
pykolab/imap/__init__.py | 50 +++++++++++++++++++++
pykolab/imap/cyrus.py | 5 +-
6 files changed, 253 insertions(+), 17 deletions(-)
New commits:
commit 7aafe929d98318c7a9bd4a5b6bc04e3c299588bc
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed Aug 8 15:05:01 2012 +0100
Ship commands to set and list mailbox metadata
diff --git a/pykolab/cli/cmd_list_mailbox_metadata.py b/pykolab/cli/cmd_list_mailbox_metadata.py
new file mode 100644
index 0000000..87fe1b0
--- /dev/null
+++ b/pykolab/cli/cmd_list_mailbox_metadata.py
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 3 or, at your option, any later version
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+import commands
+
+import pykolab
+
+from pykolab.imap import IMAP
+from pykolab.translate import _
+from pykolab import utils
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+def __init__():
+ commands.register('list_mailbox_metadata', execute, description=description())
+
+def description():
+ return """Obtain a list of metadata entries on a folder."""
+
+def execute(*args, **kw):
+ try:
+ folder = conf.cli_args.pop(0)
+ except IndexError, errmsg:
+ folder = utils.ask_question(_("Folder name"))
+
+ if len(folder.split('@')) > 1:
+ domain = folder.split('@')[1]
+ else:
+ domain = conf.get('kolab', 'primary_domain')
+
+ imap = IMAP()
+ imap.connect(domain=domain)
+
+ if not imap.has_folder(folder):
+ print >> sys.stderr, _("No such folder %r") % (folder)
+
+ else:
+ metadata = []
+ folders = imap.lm(folder)
+ for folder in folders:
+ print "Folder", folder
+
+ metadata = imap.get_metadata(folder)
+
+ for annotation in metadata[folder].keys():
+ print " %-49s %s" % (
+ annotation,
+ metadata[folder][annotation]
+ )
diff --git a/pykolab/cli/cmd_set_mailbox_metadata.py b/pykolab/cli/cmd_set_mailbox_metadata.py
new file mode 100644
index 0000000..9aa9b4e
--- /dev/null
+++ b/pykolab/cli/cmd_set_mailbox_metadata.py
@@ -0,0 +1,72 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2012 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 3 or, at your option, any later version
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+import sys
+
+import commands
+
+import pykolab
+
+from pykolab.imap import IMAP
+from pykolab.translate import _
+from pykolab import utils
+
+log = pykolab.getLogger('pykolab.cli')
+conf = pykolab.getConf()
+
+def __init__():
+ commands.register('set_mailbox_metadata', execute, description=description())
+
+def description():
+ return """Set an metadata entry on a folder."""
+
+def execute(*args, **kw):
+ try:
+ folder = conf.cli_args.pop(0)
+ try:
+ metadata_path = conf.cli_args.pop(0)
+ try:
+ metadata_value = conf.cli_args.pop(0)
+ except IndexError, errmsg:
+ metadata_value = utils.ask_question(_("Metadata value"))
+
+ except IndexError, errmsg:
+ metadata_path = utils.ask_question(_("Metadata path"))
+ metadata_value = utils.ask_question(_("Metadata value"))
+
+ except IndexError, errmsg:
+ folder = utils.ask_question(_("Folder name"))
+ metadata_path = utils.ask_question(_("Metadata path"))
+ metadata_value = utils.ask_question(_("Metadata value"))
+
+ if len(folder.split('@')) > 1:
+ domain = folder.split('@')[1]
+ else:
+ domain = conf.get('kolab', 'primary_domain')
+
+ imap = IMAP()
+ imap.connect(domain=domain)
+
+ if not imap.has_folder(folder):
+ print >> sys.stderr, _("No such folder %r") % (folder)
+
+ else:
+ folders = imap.lm(folder)
+ for folder in folders:
+ imap.set_metadata(folder, metadata_path, metadata_value)
commit c8a39374cb97cb8ff70ff85b8613e74d77067f40
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed Aug 8 15:04:38 2012 +0100
Add functions that support some of the new command line client commands
diff --git a/pykolab/imap/__init__.py b/pykolab/imap/__init__.py
index 65c232c..aee9148 100644
--- a/pykolab/imap/__init__.py
+++ b/pykolab/imap/__init__.py
@@ -212,6 +212,13 @@ class IMAP(object):
else:
raise AttributeError, _("%r has no attribute %s") % (self,name)
+ def get_metadata(self, folder):
+ """
+ Obtain all metadata entries on a folder
+ """
+
+ return self.imap.getannotation(folder, '*')
+
def namespaces(self):
"""
Obtain the namespaces.
@@ -255,6 +262,49 @@ class IMAP(object):
self.imap.sam(folder, identifier, acl)
+ def set_metadata(self, folder, metadata_path, metadata_value, shared=True):
+ """
+ Set a metadata entry on a folder
+ """
+
+ if metadata_path.startswith('/shared/'):
+ shared = True
+
+ if metadata_path.startswith('/shared/'):
+ metadata_path = metadata_path.replace('/shared/', '/')
+ elif metadata_path.startswith('/private/'):
+ shared = False
+ metadata_path = metadata_path.replace('/private/', '/')
+
+ backend = conf.get('kolab', 'imap_backend')
+
+ if not self.domain == None:
+ if conf.has_section(self.domain) and conf.has_option(self.domain, 'imap_backend'):
+ backend = conf.get(self.domain, 'imap_backend')
+
+ if not shared:
+ log.warning(_("Private annotations need to be set using the appropriate user account."))
+
+ admin_login = conf.get(backend, 'admin_login')
+
+ admin_acl = None
+
+ acls = self.list_acls(folder)
+ if acls.has_key(admin_login):
+ admin_acl = acls[admin_login]
+
+ if admin_acl == None:
+ self.set_acl(folder, admin_login, 'lrsipwa')
+ elif not 'w' in admin_acl:
+ self.set_acl(folder, admin_login, '%sw' % (admin_acl))
+
+ self.imap._setannotation(folder, metadata_path, metadata_value, shared)
+
+ if admin_acl == None:
+ self.set_acl(folder, admin_login, '')
+ elif not 'w' in admin_acl:
+ self.set_acl(folder, admin_login, admin_acl)
+
def shared_folder_create(self, folder_path, server=None):
"""
Create a shared folder.
diff --git a/pykolab/imap/cyrus.py b/pykolab/imap/cyrus.py
index af3e5b8..9b291bf 100644
--- a/pykolab/imap/cyrus.py
+++ b/pykolab/imap/cyrus.py
@@ -81,6 +81,7 @@ class Cyrus(cyruslib.CYRUS):
if conf.debuglevel > 8:
self.VERBOSE = True
+ self.m.debug = 5
# Initialize our variables
self.separator = self.SEP
@@ -217,7 +218,7 @@ class Cyrus(cyruslib.CYRUS):
def _getannotation(self, *args, **kw):
return self.getannotation(*args, **kw)
- def _setannotation(self, mailfolder, annotation, value):
+ def _setannotation(self, mailfolder, annotation, value, shared=False):
"""
Login to the actual backend server, then set annotation.
"""
@@ -228,7 +229,7 @@ class Cyrus(cyruslib.CYRUS):
#if annotation.startswith('/private'):
try:
- self.setannotation(mailfolder, annotation, value)
+ self.setannotation(mailfolder, annotation, value, shared)
except cyruslib.CYRUSError, e:
log.error(_("Could not set annotation %r on mail folder %r: %r") % (annotation,mailfolder,e))
commit fd3e861d85da2093be6d579e253e4290bf8ce932
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed Aug 8 15:04:02 2012 +0100
Print mailbox ACLs listed in a somewhat parseable format
diff --git a/pykolab/cli/cmd_list_mailbox_acls.py b/pykolab/cli/cmd_list_mailbox_acls.py
index 10a3321..7f4a9fc 100644
--- a/pykolab/cli/cmd_list_mailbox_acls.py
+++ b/pykolab/cli/cmd_list_mailbox_acls.py
@@ -55,7 +55,9 @@ def execute(*args, **kw):
acls = []
folders = imap.lm(folder)
for folder in folders:
- acls.append((folder, imap.list_acls(folder)))
+ print "Folder", folder
+ acls = imap.list_acls(folder)
+
+ for acl in acls.keys():
+ print " %-13s %s" %(acls[acl], acl)
- for folder, acl in acls:
- print folder, acl
commit dab08039fcd528f60b4703ec13b79cf3f3224314
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date: Wed Aug 8 15:03:26 2012 +0100
Make cyruslib support recognizing the difference between shared and private annotations
diff --git a/cyruslib.py b/cyruslib.py
index f141059..fe06b24 100644
--- a/cyruslib.py
+++ b/cyruslib.py
@@ -137,16 +137,26 @@ class IMAP4(imaplib.IMAP4):
return False, dat[0]
return ok(res), dat[0]
- def getannotation(self, mailbox, pattern='*'):
- typ, dat = self._simple_command('GETANNOTATION', mailbox, quote(pattern), quote('value.shared'))
+ def getannotation(self, mailbox, pattern='*', shared=None):
+ if shared == None:
+ typ, dat = self._simple_command('GETANNOTATION', mailbox, quote(pattern), quote('*'))
+ elif shared:
+ typ, dat = self._simple_command('GETANNOTATION', mailbox, quote(pattern), quote('value.shared'))
+ else:
+ typ, dat = self._simple_command('GETANNOTATION', mailbox, quote(pattern), quote('value.priv'))
+
return self._untagged_response(typ, dat, 'ANNOTATION')
- def setannotation(self, mailbox, desc, value):
+ def setannotation(self, mailbox, desc, value, shared=False):
if value:
value = quote(value)
else:
value = "NIL"
- typ, dat = self._simple_command('SETANNOTATION', mailbox, quote(desc), "(%s %s)" % (quote('value.shared'), value) )
+ if shared:
+ typ, dat = self._simple_command('SETANNOTATION', mailbox, quote(desc), "(%s %s)" % (quote('value.shared'), value) )
+ else:
+ typ, dat = self._simple_command('SETANNOTATION', mailbox, quote(desc), "(%s %s)" % (quote('value.priv'), value) )
+
return self._untagged_response(typ, dat, 'ANNOTATION')
def setquota(self, mailbox, limit):
@@ -208,16 +218,26 @@ class IMAP4_SSL(imaplib.IMAP4_SSL):
return False, dat[0]
return ok(res), dat[0]
- def getannotation(self, mailbox, pattern='*'):
- typ, dat = self._simple_command('GETANNOTATION', mailbox, quote(pattern), quote('value.shared'))
+ def getannotation(self, mailbox, pattern='*', shared=None):
+ if shared == None:
+ typ, dat = self._simple_command('GETANNOTATION', mailbox, quote(pattern), quote('*'))
+ elif shared:
+ typ, dat = self._simple_command('GETANNOTATION', mailbox, quote(pattern), quote('value.shared'))
+ else:
+ typ, dat = self._simple_command('GETANNOTATION', mailbox, quote(pattern), quote('value.priv'))
+
return self._untagged_response(typ, dat, 'ANNOTATION')
- def setannotation(self, mailbox, desc, value):
+ def setannotation(self, mailbox, desc, value, shared=False):
if value:
value = quote(value)
else:
value = "NIL"
- typ, dat = self._simple_command('SETANNOTATION', mailbox, quote(desc), "(%s %s)" % (quote('value.shared'), value) )
+ if shared:
+ typ, dat = self._simple_command('SETANNOTATION', mailbox, quote(desc), "(%s %s)" % (quote('value.shared'), value) )
+ else:
+ typ, dat = self._simple_command('SETANNOTATION', mailbox, quote(desc), "(%s %s)" % (quote('value.priv'), value) )
+
return self._untagged_response(typ, dat, 'ANNOTATION')
def setquota(self, mailbox, limit):
@@ -627,24 +647,49 @@ class CYRUS:
return {}
ann = {}
for annotation in data:
+ self.__verbose( '[GETANNOTATION] RAW %r (length %d)' % (annotation,len(annotation)))
annotation = annotation.split('"')
- if len(annotation) != 9:
+ self.__verbose( '[GETANNOTATION] SPLIT %r (length %d)' % (annotation,len(annotation)))
+ if not len(annotation) in [ 9, 17, 21, 37 ]:
self.__verbose( '[GETANNOTATION] Invalid annotation entry' )
continue
mbx = self.encode(annotation[1])
- key = annotation[3]
+ _key = annotation[3]
+
+ if annotation[5] == "value.shared":
+ key = "/shared%s" % (_key)
+ elif annotation[5] == "value.priv":
+ key = "/private%s" % (_key)
+
value = annotation[7]
+
self.__verbose( '[GETANNOTATION %s] %s: %s' % (mbx, key, value) )
if not ann.has_key(mbx):
ann[mbx] = {}
if not ann[mbx].has_key(key):
ann[mbx][key] = value
+
+ if len(annotation) > 21:
+ # There's another one hidden in here.
+ if annotation[21] == "value.shared":
+ key = "/shared%s" % (_key)
+ elif annotation[21] == "value.priv":
+ key = "/private%s" % (_key)
+
+ value = annotation[23]
+
+ self.__verbose( '[GETANNOTATION %s] %s: %s' % (mbx, key, value) )
+ if not ann.has_key(mbx):
+ ann[mbx] = {}
+ if not ann[mbx].has_key(key):
+ ann[mbx][key] = value
+
return ann
- def setannotation(self, mailbox, annotation, value):
+ def setannotation(self, mailbox, annotation, value, shared=False):
"""Set Annotation"""
self.__prepare('SETANNOTATION')
- res, msg = self.__docommand("setannotation", self.decode(mailbox), annotation, value)
+ res, msg = self.__docommand("setannotation", self.decode(mailbox), annotation, value, shared)
self.__verbose( '[SETANNOTATION %s] %s: %s' % (mailbox, res, msg[0]) )
def __reconstruct(self, mailbox):
More information about the commits
mailing list