diff --git a/pykolab/imap_utf7.py b/pykolab/imap_utf7.py index 0ecb83c..152609c 100644 --- a/pykolab/imap_utf7.py +++ b/pykolab/imap_utf7.py @@ -1,91 +1,103 @@ # 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. +# https://twistedmatrix.com/trac/attachment/ticket/6289/imap4.patch +# #6289 enhancement closed fixed (fixed) +# Port imap4-utf-7 codec implementation to Python 3 class FolderNameError(ValueError): pass +try: + unicode() +except: + unicode = str + +memory_cast = getattr(memoryview, "cast", lambda *x: x[0]) + def encode(s): if isinstance(s, str) and sum(n for n in (ord(c) for c in s) if n > 127): try: - s = unicode(s, "UTF-8") + s = bytes(s, "UTF-8") except Exception: raise FolderNameError("%r contains characters not valid in a str folder name. " - "Convert to unicode first?" % s) + "Convert to unicode first?" % s) - r = [] + r = bytearray() _in = [] + valid_chars = set(map(chr, range(0x20, 0x7f))) - {u"&"} for c in s: - if ord(c) in (range(0x20, 0x26) + range(0x27, 0x7f)): + if c in valid_chars: if _in: - r.extend(['&', modified_base64(''.join(_in)), '-']) + r += b'&' + modified_base64(''.join(_in)) + b'-' del _in[:] - r.append(str(c)) - elif c == '&': + r.append(ord(c)) + elif c == u'&': if _in: - r.extend(['&', modified_base64(''.join(_in)), '-']) + r += b'&' + modified_base64(''.join(_in)) + b'-' del _in[:] - r.append('&-') + r += b'&-' else: _in.append(c) if _in: - r.extend(['&', modified_base64(''.join(_in)), '-']) + r.extend(b'&' + modified_base64(''.join(_in)) + b'-') - return ''.join(r) + return bytes(r) def decode(s): r = [] decode = [] + s = memory_cast(memoryview(s), 'c') for c in s: - if c == '&' and not decode: - decode.append('&') - elif c == '-' and decode: + if c == b'&' and not decode: + decode.append(u'&') + elif c == b'-' and decode: if len(decode) == 1: - r.append('&') + r.append(u'&') else: - r.append(modified_unbase64(''.join(decode[1:]))) + r.append(modified_unbase64(b''.join(decode[1:]))) decode = [] elif decode: decode.append(c) else: - r.append(c) + r.append(c.decode()) if decode: - r.append(modified_unbase64(''.join(decode[1:]))) + r.append(modified_unbase64(b''.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('/', ',') + return s_utf7[1:-1].replace(b'/', b',') def modified_unbase64(s): - s_utf7 = '+' + s.replace(',', '/') + '-' + s_utf7 = b'+' + s.replace(b',', b'/') + b'-' return s_utf7.decode('utf-7')