Merge branch 'master' into multiple_encoding_support. Dropping patch

for "Included charset detection"
This commit is contained in:
Joseph Ishac 2021-02-21 22:36:30 -05:00
commit f71ef226bf
3 changed files with 64 additions and 35 deletions

View File

@ -310,12 +310,8 @@ class IMAPServer:
# This is a behavior we got from pykerberos. First byte is one, # This is a behavior we got from pykerberos. First byte is one,
# first four bytes are preserved (pykerberos calls this a length). # first four bytes are preserved (pykerberos calls this a length).
# Any additional bytes are username. # Any additional bytes are username.
reply = [] reply = b'\x01' + response.message[1:4]
reply[0:4] = response.message[0:4] reply += bytes(self.username, 'utf-8')
reply[0] = '\x01'
if self.username:
reply[5:] = self.username
reply = ''.join(reply)
response = self.gss_vc.wrap(reply, response.encrypted) response = self.gss_vc.wrap(reply, response.encrypted)
return response.message if response.message else "" return response.message if response.message else ""

View File

@ -18,6 +18,7 @@
import re import re
import binascii import binascii
import codecs import codecs
from typing import Tuple
from offlineimap.ui import getglobalui from offlineimap.ui import getglobalui
# Globals # Globals
@ -352,42 +353,45 @@ def decode_mailbox_name(name):
def IMAP_utf8(foldername): def IMAP_utf8(foldername):
"""Convert IMAP4_utf_7 encoded string to utf-8""" """Convert IMAP4_utf_7 encoded string to utf-8"""
return foldername.decode('imap4-utf-7').encode('utf-8') return codecs.decode(
foldername.encode(),
'imap4-utf-7'
).encode('utf-8').decode()
def utf8_IMAP(foldername): def utf8_IMAP(foldername):
"""Convert utf-8 encoded string to IMAP4_utf_7""" """Convert utf-8 encoded string to IMAP4_utf_7"""
return foldername.decode('utf-8').encode('imap4-utf-7') return codecs.decode(
foldername.encode(),
'utf-8'
).encode('imap4-utf-7').decode()
# Codec definition # Codec definition
def modified_base64(s): def modified_base64(s):
s = s.encode('utf-16be') s = s.encode('utf-16be')
return binascii.b2a_base64(s).rstrip('\n=').replace('/', ',') return binascii.b2a_base64(s).rstrip(b'\n=').replace(b'/', b',')
def doB64(_in, r): def doB64(_in, r):
if _in: if _in:
r.append('&%s-' % modified_base64(''.join(_in))) r.append(b'&%s-' % modified_base64(''.join(_in)))
del _in[:] del _in[:]
def encoder(s): def utf7m_encode(text: str) -> Tuple[bytes, int]:
r = [] r = []
_in = [] _in = []
for c in s:
ordC = ord(c) for c in text:
if 0x20 <= ordC <= 0x25 or 0x27 <= ordC <= 0x7e: if 0x20 <= ord(c) <= 0x7e:
doB64(_in, r) doB64(_in, r)
r.append(c) r.append(b'&-' if c == '&' else c.encode())
elif c == '&':
doB64(_in, r)
r.append('&-')
else: else:
_in.append(c) _in.append(c)
doB64(_in, r) doB64(_in, r)
return str(''.join(r)), len(s) return b''.join(r), len(text)
# decoding # decoding
@ -396,10 +400,10 @@ def modified_unbase64(s):
return str(b, 'utf-16be') return str(b, 'utf-16be')
def decoder(s): def utf7m_decode(binary: bytes) -> Tuple[str, int]:
r = [] r = []
decode = [] decode = []
for c in s: for c in binary.decode():
if c == '&' and not decode: if c == '&' and not decode:
decode.append('&') decode.append('&')
elif c == '-' and decode: elif c == '-' and decode:
@ -415,26 +419,31 @@ def decoder(s):
if decode: if decode:
r.append(modified_unbase64(''.join(decode[1:]))) r.append(modified_unbase64(''.join(decode[1:])))
bin_str = ''.join(r)
return bin_str, len(s) return ''.join(r), len(binary)
class StreamReader(codecs.StreamReader): class StreamReader(codecs.StreamReader):
def decode(self, s, errors='strict'): def decode(self, s, errors='strict'):
return decoder(s) return utf7m_decode(s)
class StreamWriter(codecs.StreamWriter): class StreamWriter(codecs.StreamWriter):
def decode(self, s, errors='strict'): def decode(self, s, errors='strict'):
return encoder(s) return utf7m_encode(s)
def imap4_utf_7(name): def utf7m_search_function(name):
if name == 'imap4-utf-7': return codecs.CodecInfo(
return encoder, decoder, StreamReader, StreamWriter utf7m_encode,
utf7m_decode,
StreamReader,
StreamWriter,
name='imap4-utf-7'
)
codecs.register(imap4_utf_7) codecs.register(utf7m_search_function)
def foldername_to_imapname(folder_name): def foldername_to_imapname(folder_name):
@ -454,4 +463,4 @@ def foldername_to_imapname(folder_name):
if any((c in atom_specials) for c in folder_name): if any((c in atom_specials) for c in folder_name):
folder_name = '"' + folder_name + '"' folder_name = '"' + folder_name + '"'
return folder_name return folder_name

View File

@ -206,12 +206,23 @@ class IMAPRepository(BaseRepository):
Returns: Returns the remoteusereval or remoteuser or netrc user value. Returns: Returns the remoteusereval or remoteuser or netrc user value.
""" """
localeval = self.localeval
if self.config.has_option(self.getsection(), 'remoteusereval'): if self.config.has_option(self.getsection(), 'remoteusereval'):
user = self.getconf('remoteusereval') user = self.getconf('remoteusereval')
if user is not None: if user is not None:
return localeval.eval(user).encode('UTF-8') l_user = self.localeval.eval(user)
# We need a str username
if isinstance(l_user, bytes):
return l_user.decode(encoding='utf-8')
elif isinstance(l_user, str):
return l_user
# If is not bytes or str, we have a problem
raise OfflineImapError("Could not get a right username format for"
" repository %s. Type found: %s. "
"Please, open a bug." %
(self.name, type(l_user)),
OfflineImapError.ERROR.FOLDER)
if self.config.has_option(self.getsection(), 'remoteuser'): if self.config.has_option(self.getsection(), 'remoteuser'):
# Assume the configuration file to be UTF-8 encoded so we must not # Assume the configuration file to be UTF-8 encoded so we must not
@ -590,7 +601,20 @@ class IMAPRepository(BaseRepository):
encoding='utf-8') encoding='utf-8')
password = file_desc.readline().strip() password = file_desc.readline().strip()
file_desc.close() file_desc.close()
return password.encode('UTF-8')
# We need a str password
if isinstance(password, bytes):
return password.decode(encoding='utf-8')
elif isinstance(password, str):
return password
# If is not bytes or str, we have a problem
raise OfflineImapError("Could not get a right password format for"
" repository %s. Type found: %s. "
"Please, open a bug." %
(self.name, type(password)),
OfflineImapError.ERROR.FOLDER)
# 4. Read password from ~/.netrc. # 4. Read password from ~/.netrc.
try: try:
netrcentry = netrc.netrc().authenticators(self.gethost()) netrcentry = netrc.netrc().authenticators(self.gethost())