Changeset View
Changeset View
Standalone View
Standalone View
pykolab/imap_utf7.py
Show All 16 Lines | |||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | # 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): | class FolderNameError(ValueError): | ||||
pass | pass | ||||
try: | |||||
unicode() | |||||
except: | |||||
unicode = str | |||||
memory_cast = getattr(memoryview, "cast", lambda *x: x[0]) | |||||
def encode(s): | def encode(s): | ||||
if isinstance(s, str) and sum(n for n in (ord(c) for c in s) if n > 127): | if isinstance(s, str) and sum(n for n in (ord(c) for c in s) if n > 127): | ||||
try: | try: | ||||
s = unicode(s, "UTF-8") | s = bytes(s, "UTF-8") | ||||
except Exception: | except Exception: | ||||
raise FolderNameError("%r contains characters not valid in a str folder name. " | 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 = [] | _in = [] | ||||
valid_chars = set(map(chr, range(0x20, 0x7f))) - {u"&"} | |||||
for c in s: | for c in s: | ||||
if ord(c) in (range(0x20, 0x26) + range(0x27, 0x7f)): | if c in valid_chars: | ||||
if _in: | if _in: | ||||
r.extend(['&', modified_base64(''.join(_in)), '-']) | r += b'&' + modified_base64(''.join(_in)) + b'-' | ||||
del _in[:] | del _in[:] | ||||
r.append(str(c)) | r.append(ord(c)) | ||||
elif c == '&': | elif c == u'&': | ||||
if _in: | if _in: | ||||
r.extend(['&', modified_base64(''.join(_in)), '-']) | r += b'&' + modified_base64(''.join(_in)) + b'-' | ||||
del _in[:] | del _in[:] | ||||
r.append('&-') | r += b'&-' | ||||
else: | else: | ||||
_in.append(c) | _in.append(c) | ||||
if _in: | 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): | def decode(s): | ||||
r = [] | r = [] | ||||
decode = [] | decode = [] | ||||
s = memory_cast(memoryview(s), 'c') | |||||
for c in s: | for c in s: | ||||
if c == '&' and not decode: | if c == b'&' and not decode: | ||||
decode.append('&') | decode.append(u'&') | ||||
elif c == '-' and decode: | elif c == b'-' and decode: | ||||
if len(decode) == 1: | if len(decode) == 1: | ||||
r.append('&') | r.append(u'&') | ||||
else: | else: | ||||
r.append(modified_unbase64(''.join(decode[1:]))) | r.append(modified_unbase64(b''.join(decode[1:]))) | ||||
decode = [] | decode = [] | ||||
elif decode: | elif decode: | ||||
decode.append(c) | decode.append(c) | ||||
else: | else: | ||||
r.append(c) | r.append(c.decode()) | ||||
if decode: | if decode: | ||||
r.append(modified_unbase64(''.join(decode[1:]))) | r.append(modified_unbase64(b''.join(decode[1:]))) | ||||
out = ''.join(r) | out = ''.join(r) | ||||
if not isinstance(out, unicode): | if not isinstance(out, unicode): | ||||
out = unicode(out, 'latin-1') | out = unicode(out, 'latin-1') | ||||
return out | return out | ||||
def modified_base64(s): | def modified_base64(s): | ||||
s_utf7 = s.encode('utf-7') | s_utf7 = s.encode('utf-7') | ||||
return s_utf7[1:-1].replace('/', ',') | return s_utf7[1:-1].replace(b'/', b',') | ||||
def modified_unbase64(s): | def modified_unbase64(s): | ||||
s_utf7 = '+' + s.replace(',', '/') + '-' | s_utf7 = b'+' + s.replace(b',', b'/') + b'-' | ||||
return s_utf7.decode('utf-7') | return s_utf7.decode('utf-7') |