Index: Lib/imaplib.py =================================================================== --- Lib/imaplib.py (révision 66888) +++ Lib/imaplib.py (copie de travail) @@ -29,7 +29,7 @@ # Globals -CRLF = '\r\n' +CRLF = b'\r\n' Debug = 0 IMAP4_PORT = 143 IMAP4_SSL_PORT = 993 @@ -81,19 +81,19 @@ # Patterns to match server responses -Continuation = re.compile(r'\+( (?P.*))?') -Flags = re.compile(r'.*FLAGS \((?P[^\)]*)\)') -InternalDate = re.compile(r'.*INTERNALDATE "' - r'(?P[ 0123][0-9])-(?P[A-Z][a-z][a-z])-(?P[0-9][0-9][0-9][0-9])' - r' (?P[0-9][0-9]):(?P[0-9][0-9]):(?P[0-9][0-9])' - r' (?P[-+])(?P[0-9][0-9])(?P[0-9][0-9])' - r'"') -Literal = re.compile(r'.*{(?P\d+)}$', re.ASCII) -MapCRLF = re.compile(r'\r\n|\r|\n') -Response_code = re.compile(r'\[(?P[A-Z-]+)( (?P[^\]]*))?\]') -Untagged_response = re.compile(r'\* (?P[A-Z-]+)( (?P.*))?') +Continuation = re.compile(br'\+( (?P.*))?') +Flags = re.compile(br'.*FLAGS \((?P[^\)]*)\)') +InternalDate = re.compile(br'.*INTERNALDATE "' + br'(?P[ 0123][0-9])-(?P[A-Z][a-z][a-z])-(?P[0-9][0-9][0-9][0-9])' + br' (?P[0-9][0-9]):(?P[0-9][0-9]):(?P[0-9][0-9])' + br' (?P[-+])(?P[0-9][0-9])(?P[0-9][0-9])' + br'"') +Literal = re.compile(br'.*{(?P\d+)}$', re.ASCII) +MapCRLF = re.compile(br'\r\n|\r|\n') +Response_code = re.compile(br'\[(?P[A-Z-]+)( (?P[^\]]*))?\]') +Untagged_response = re.compile(br'\* (?P[A-Z-]+)( (?P.*))?') Untagged_status = re.compile( - r'\* (?P\d+) (?P[A-Z-]+)( (?P.*))?', re.ASCII) + br'\* (?P\d+) (?P[A-Z-]+)( (?P.*))?', re.ASCII) @@ -147,7 +147,7 @@ class abort(error): pass # Service errors - close and retry class readonly(abort): pass # Mailbox status changed to READ-ONLY - mustquote = re.compile(r"[^\w!#$%&'*+,.:;<=>?^`|~-]", re.ASCII) + mustquote = re.compile(br"[^\w!#$%&'*+,.:;<=>?^`|~-]", re.ASCII) def __init__(self, host = '', port = IMAP4_PORT): self.debug = Debug @@ -167,9 +167,9 @@ # and compile tagged response matcher. self.tagpre = Int2AP(random.randint(4096, 65535)) - self.tagre = re.compile(r'(?P' + self.tagre = re.compile(br'(?P' + self.tagpre - + r'\d+) (?P[A-Z]+) (?P.*)', re.ASCII) + + br'\d+) (?P[A-Z]+) (?P.*)', re.ASCII) # Get server welcome message, # request and store CAPABILITY response. @@ -193,7 +193,9 @@ typ, dat = self.capability() if dat == [None]: raise self.error('no CAPABILITY response from server') - self.capabilities = tuple(dat[-1].upper().split()) + dat = str(dat[-1], "ASCII") + dat = dat.upper() + self.capabilities = tuple(dat.split()) if __debug__: if self.debug >= 3: @@ -791,12 +793,19 @@ def _append_untagged(self, typ, dat): + assert isinstance(typ, str) - if dat is None: dat = '' + if dat is None: + dat = b'' + assert (isinstance(dat, bytes) + or (isinstance(dat, tuple) + and len(dat) == 2 + and isinstance(dat[0], bytes) + and isinstance(dat[1], bytes))), repr(dat) ur = self.untagged_responses if __debug__: if self.debug >= 5: - self._mesg('untagged_responses[%s] %s += ["%s"]' % + self._mesg('untagged_responses[%s] %s += ["%r"]' % (typ, len(ur.get(typ,'')), dat)) if typ in ur: ur[typ].append(dat) @@ -828,10 +837,15 @@ raise self.readonly('mailbox status changed to READ-ONLY') tag = self._new_tag() - data = '%s %s' % (tag, name) + name = bytes(name, 'ASCII') + data = tag + b' ' + name for arg in args: if arg is None: continue - data = '%s %s' % (data, self._checkquote(arg)) + if isinstance(arg, str): + arg = bytes(arg, "ASCII") + #data = data + b' ' + self._checkquote(arg) + assert isinstance(arg, bytes), arg + data = data + b' ' + arg literal = self.literal if literal is not None: @@ -840,16 +854,16 @@ literator = literal else: literator = None - data = '%s {%s}' % (data, len(literal)) + data = data + bytes(' {%s}' % len(literal), 'ASCII') if __debug__: if self.debug >= 4: - self._mesg('> %s' % data) + self._mesg('> %r' % data) else: - self._log('> %s' % data) + self._log('> %r' % data) try: - self.send('%s%s' % (data, CRLF)) + self.send(data + CRLF) except (socket.error, OSError) as val: raise self.abort('socket error: %s' % val) @@ -915,6 +929,7 @@ raise self.abort('unexpected tagged response: %s' % resp) typ = self.mo.group('type') + typ = str(typ, 'ASCII') dat = self.mo.group('data') self.tagged_commands[tag] = (typ, [dat]) else: @@ -936,9 +951,10 @@ raise self.abort("unexpected response: '%s'" % resp) typ = self.mo.group('type') + typ = str(typ, 'ascii') dat = self.mo.group('data') - if dat is None: dat = '' # Null untagged response - if dat2: dat = dat + ' ' + dat2 + if dat is None: dat = b'' # Null untagged response + if dat2: dat = dat + b' ' + dat2 # Is there a literal to come? @@ -960,16 +976,19 @@ dat = self._get_line() + assert isinstance(typ, str) self._append_untagged(typ, dat) # Bracketed response information? if typ in ('OK', 'NO', 'BAD') and self._match(Response_code, dat): - self._append_untagged(self.mo.group('type'), self.mo.group('data')) + typ = self.mo.group('type') + typ = str(typ, "ASCII") + self._append_untagged(typ, self.mo.group('data')) if __debug__: if self.debug >= 1 and typ in ('NO', 'BAD', 'BYE'): - self._mesg('%s response: %s' % (typ, dat)) + self._mesg('%s response: %r' % (typ, dat)) return resp @@ -1007,9 +1026,9 @@ line = line[:-2] if __debug__: if self.debug >= 4: - self._mesg('< %s' % line) + self._mesg('< %r' % line) else: - self._log('< %s' % line) + self._log('< %r' % line) return line @@ -1021,13 +1040,13 @@ self.mo = cre.match(s) if __debug__: if self.mo is not None and self.debug >= 5: - self._mesg("\tmatched r'%s' => %r" % (cre.pattern, self.mo.groups())) + self._mesg("\tmatched r'%r' => %r" % (cre.pattern, self.mo.groups())) return self.mo is not None def _new_tag(self): - tag = '%s%s' % (self.tagpre, self.tagnum) + tag = self.tagpre + bytes(str(self.tagnum), 'ASCII') self.tagnum = self.tagnum + 1 self.tagged_commands[tag] = None return tag @@ -1038,8 +1057,7 @@ # Must quote command args if non-alphanumeric chars present, # and not already quoted. - if type(arg) is not type(''): - return arg + assert isinstance(arg, bytes) if len(arg) >= 2 and (arg[0],arg[-1]) in (('(',')'),('"','"')): return arg if arg and self.mustquote.search(arg) is None: @@ -1049,10 +1067,10 @@ def _quote(self, arg): - arg = arg.replace('\\', '\\\\') - arg = arg.replace('"', '\\"') + arg = arg.replace(b'\\', b'\\\\') + arg = arg.replace(b'"', b'\\"') - return '"%s"' % arg + return b'"' + arg + b'"' def _simple_command(self, name, *args): @@ -1061,6 +1079,7 @@ def _untagged_response(self, typ, dat, name): + assert isinstance(typ, str) if typ == 'NO': return typ, dat @@ -1355,11 +1374,11 @@ """Convert integer to A-P string representation.""" - val = ''; AP = 'ABCDEFGHIJKLMNOP' + val = b''; AP = b'ABCDEFGHIJKLMNOP' num = int(abs(num)) while num: num, mod = divmod(num, 16) - val = AP[mod] + val + val = AP[mod:mod+1] + val return val