diff --git a/pykolab/imap_utf7.py b/pykolab/imap_utf7.py --- a/pykolab/imap_utf7.py +++ b/pykolab/imap_utf7.py @@ -22,58 +22,70 @@ # 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): @@ -83,9 +95,9 @@ 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')