summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com>2013-07-05 17:09:53 +0100
committerJeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com>2013-07-05 18:05:40 +0100
commitdb06665be4e8356208c975b87fb1f6750a1e842f (patch)
tree07cb5374364de8f72851c38b7c1e49aca5b12327
parent481936527f5f65a80e83c4807b79c7a1c0f272bf (diff)
downloadpykolab-db06665be4e8356208c975b87fb1f6750a1e842f.tar.gz
Make sure folder names are utf-7 encoded
Conflicts: pykolab/imap/__init__.py
-rw-r--r--pykolab/imap/__init__.py22
-rw-r--r--pykolab/imap_utf7.py87
2 files changed, 99 insertions, 10 deletions
diff --git a/pykolab/imap/__init__.py b/pykolab/imap/__init__.py
index c91d84f..5e72769 100644
--- a/pykolab/imap/__init__.py
+++ b/pykolab/imap/__init__.py
@@ -211,6 +211,10 @@ class IMAP(object):
else:
raise AttributeError, _("%r has no attribute %s") % (self,name)
+ def folder_utf7(self, folder):
+ from pykolab import imap_utf7
+ return imap_utf7.encode(folder_path)
+
def get_metadata(self, folder):
"""
Obtain all metadata entries on a folder
@@ -275,10 +279,7 @@ class IMAP(object):
shared = False
metadata_path = metadata_path.replace('/private/', '/')
- if not shared:
- log.warning(_("Private annotations need to be set using the appropriate user account."))
-
- self.imap._setannotation(folder, metadata_path, metadata_value, shared)
+ self.imap._setannotation(self.folder_utf7(folder), metadata_path, metadata_value, shared)
def shared_folder_create(self, folder_path, server=None):
"""
@@ -402,9 +403,10 @@ class IMAP(object):
folder_name = additional_folder
try:
- self.imap.cm(folder_name)
+ self.create_folder(folder_name)
except:
log.warning(_("Mailbox already exists: %s") % (folder_name))
+ continue
if additional_folders[additional_folder].has_key("annotations"):
for annotation in additional_folders[additional_folder]["annotations"].keys():
@@ -532,7 +534,7 @@ class IMAP(object):
"""
Check if the environment has a folder named folder.
"""
- folders = self.imap.lm(folder)
+ folders = self.imap.lm(self.folder_utf7(folder))
log.debug(_("Looking for folder '%s', we found folders: %r") % (folder,folders), level=8)
# Greater then one, this folder may have subfolders.
if len(folders) > 0:
@@ -559,8 +561,8 @@ class IMAP(object):
_("Setting ACL rights %s for subject %s on folder " + \
"%s") % (rights,subject,folder), level=8)
- self.imap.sam(
- folder,
+ self.set_acl(
+ self.folder_utf7(folder),
"%s" % (subject),
"%s" % (rights)
)
@@ -570,8 +572,8 @@ class IMAP(object):
_("Removing ACL rights %s for subject %s on folder " + \
"%s") % (rights,subject,folder), level=8)
- self.imap.sam(
- folder,
+ self.set_acl(
+ self.folder_utf7(folder),
"%s" % (subject),
""
)
diff --git a/pykolab/imap_utf7.py b/pykolab/imap_utf7.py
new file mode 100644
index 0000000..6a670b5
--- /dev/null
+++ b/pykolab/imap_utf7.py
@@ -0,0 +1,87 @@
+# The contents of this file has been derived code from the Twisted project
+# (http://twistedmatrix.com/). The original author is Jp Calderone.
+
+# Twisted project license follows:
+
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+class FolderNameError(ValueError):
+ pass
+
+
+def encode(s):
+ if isinstance(s, str) and sum(n for n in (ord(c) for c in s) if n > 127):
+ raise FolderNameError("%r contains characters not valid in a str folder name. "
+ "Convert to unicode first?" % s)
+
+ r = []
+ _in = []
+ for c in s:
+ if ord(c) in (range(0x20, 0x26) + range(0x27, 0x7f)):
+ if _in:
+ r.extend(['&', modified_base64(''.join(_in)), '-'])
+ del _in[:]
+ r.append(str(c))
+ elif c == '&':
+ if _in:
+ r.extend(['&', modified_base64(''.join(_in)), '-'])
+ del _in[:]
+ r.append('&-')
+ else:
+ _in.append(c)
+ if _in:
+ r.extend(['&', modified_base64(''.join(_in)), '-'])
+ return ''.join(r)
+
+
+def decode(s):
+ r = []
+ decode = []
+ for c in s:
+ if c == '&' and not decode:
+ decode.append('&')
+ elif c == '-' and decode:
+ if len(decode) == 1:
+ r.append('&')
+ else:
+ r.append(modified_unbase64(''.join(decode[1:])))
+ decode = []
+ elif decode:
+ decode.append(c)
+ else:
+ r.append(c)
+ if decode:
+ r.append(modified_unbase64(''.join(decode[1:])))
+ out = ''.join(r)
+
+ if not isinstance(out, unicode):
+ out = unicode(out, 'latin-1')
+ return out
+
+
+def modified_base64(s):
+ s_utf7 = s.encode('utf-7')
+ return s_utf7[1:-1].replace('/', ',')
+
+
+def modified_unbase64(s):
+ s_utf7 = '+' + s.replace(',', '/') + '-'
+ return s_utf7.decode('utf-7')