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 20:25:15 +0100
commit643a625bd75bcdc098b3c04ed7366207efb0dad0 (patch)
treed62c585ad08201dae2ab0b0b482b46e3ef7cdccb
parentaa1b0da1dcca7cd0572ddfb88abed84490c7b383 (diff)
downloadpykolab-643a625bd75bcdc098b3c04ed7366207efb0dad0.tar.gz
Make sure folder names are utf-7 encoded
-rw-r--r--pykolab/imap/__init__.py17
-rw-r--r--pykolab/imap_utf7.py87
2 files changed, 99 insertions, 5 deletions
diff --git a/pykolab/imap/__init__.py b/pykolab/imap/__init__.py
index fa71014..8855909 100644
--- a/pykolab/imap/__init__.py
+++ b/pykolab/imap/__init__.py
@@ -243,6 +243,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
@@ -328,7 +332,7 @@ class IMAP(object):
shared = False
metadata_path = metadata_path.replace('/private/', '/')
- 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):
"""
@@ -478,9 +482,12 @@ class IMAP(object):
folder_name = "%s%s" % (personal, folder_name)
try:
- self.imap.cm(folder_name)
+ self.create_folder(folder_name)
except:
log.warning(_("Mailbox already exists: %s") % (folder_name))
+ if conf.debuglevel > 8:
+ import traceback
+ traceback.print_exc()
continue
if additional_folders[additional_folder].has_key("annotations"):
@@ -625,7 +632,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:
@@ -653,7 +660,7 @@ class IMAP(object):
"%s") % (rights,subject,folder), level=8)
self.set_acl(
- folder,
+ self.folder_utf7(folder),
"%s" % (subject),
"%s" % (rights)
)
@@ -664,7 +671,7 @@ class IMAP(object):
"%s") % (rights,subject,folder), level=8)
self.set_acl(
- folder,
+ 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')