-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
73b1cea
commit 2f39911
Showing
3 changed files
with
65 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,9 +18,9 @@ | |
"Internaldate2Time", "ParseFlags", "Time2Internaldate", | ||
"Mon2num", "MonthNames", "InternalDate") | ||
|
||
__version__ = "2.55" | ||
__version__ = "2.57" | ||
__release__ = "2" | ||
__revision__ = "55" | ||
__revision__ = "57" | ||
__credits__ = """ | ||
Authentication code contributed by Donn Cave <[email protected]> June 1998. | ||
String method conversion by ESR, February 2001. | ||
|
@@ -109,6 +109,7 @@ | |
'CREATE': ((AUTH, SELECTED), True), | ||
'DELETE': ((AUTH, SELECTED), True), | ||
'DELETEACL': ((AUTH, SELECTED), True), | ||
'ENABLE': ((AUTH,), False), | ||
'EXAMINE': ((AUTH, SELECTED), False), | ||
'EXPUNGE': ((SELECTED,), True), | ||
'FETCH': ((SELECTED,), True), | ||
|
@@ -300,17 +301,18 @@ class abort(error): pass # Service errors - close and retry | |
class readonly(abort): pass # Mailbox status changed to READ-ONLY | ||
|
||
|
||
# These must be encoded according to utf8 setting in _mode_xxx(): | ||
_literal = br'.*{(?P<size>\d+)}$' | ||
_untagged_status = br'\* (?P<data>\d+) (?P<type>[A-Z-]+)( (?P<data2>.*))?' | ||
|
||
continuation_cre = re.compile(r'\+( (?P<data>.*))?') | ||
literal_cre = re.compile(r'.*{(?P<size>\d+)}$') | ||
mapCRLF_cre = re.compile(r'\r\n|\r|\n') | ||
# Need to quote "atom-specials" :- | ||
# "(" / ")" / "{" / SP / 0x00 - 0x1f / 0x7f / "%" / "*" / DQUOTE / "\" / "]" | ||
# so match not the inverse set | ||
mustquote_cre = re.compile(r"[^!#$&'+,./0-9:;<=>?@A-Z\[^_`a-z|}~-]") | ||
response_code_cre = re.compile(r'\[(?P<type>[A-Z-]+)( (?P<data>[^\]]*))?\]') | ||
# sequence_set_cre = re.compile(r"^[0-9]+(:([0-9]+|\*))?(,[0-9]+(:([0-9]+|\*))?)*$") | ||
untagged_response_cre = re.compile(r'\* (?P<type>[A-Z-]+)( (?P<data>.*))?') | ||
untagged_status_cre = re.compile(r'\* (?P<data>\d+) (?P<type>[A-Z-]+)( (?P<data2>.*))?') | ||
|
||
|
||
def __init__(self, host=None, port=None, debug=None, debug_file=None, identifier=None, timeout=None, debug_buf_lvl=None): | ||
|
@@ -342,6 +344,8 @@ def __init__(self, host=None, port=None, debug=None, debug_file=None, identifier | |
+ self.tagpre | ||
+ r'\d+) (?P<type>[A-Z]+) (?P<data>.*)') | ||
|
||
self._mode_ascii() # Only option in py2 | ||
|
||
if __debug__: self._init_debug(debug, debug_file, debug_buf_lvl) | ||
|
||
self.resp_timeout = timeout # Timeout waiting for command response | ||
|
@@ -428,6 +432,28 @@ def __getattr__(self, attr): | |
raise AttributeError("Unknown IMAP4 command: '%s'" % attr) | ||
|
||
|
||
def _mode_ascii(self): | ||
self.utf8_enabled = False | ||
self._encoding = 'ascii' | ||
if bytes != str: | ||
self.literal_cre = re.compile(self._literal, re.ASCII) | ||
self.untagged_status_cre = re.compile(self._untagged_status, re.ASCII) | ||
else: | ||
self.literal_cre = re.compile(self._literal) | ||
self.untagged_status_cre = re.compile(self._untagged_status) | ||
|
||
|
||
def _mode_utf8(self): | ||
self.utf8_enabled = True | ||
self._encoding = 'utf-8' | ||
if bytes != str: | ||
self.literal_cre = re.compile(self._literal) | ||
self.untagged_status_cre = re.compile(self._untagged_status) | ||
else: | ||
self.literal_cre = re.compile(self._literal, re.UNICODE) | ||
self.untagged_status_cre = re.compile(self._untagged_status, re.UNICODE) | ||
|
||
|
||
|
||
# Overridable methods | ||
|
||
|
@@ -676,7 +702,10 @@ def append(self, mailbox, flags, date_time, message, **kw): | |
date_time = Time2Internaldate(date_time) | ||
else: | ||
date_time = None | ||
self.literal = self.mapCRLF_cre.sub(CRLF, message) | ||
literal = self.mapCRLF_cre.sub(CRLF, message) | ||
if self.utf8_enabled: | ||
literal = b'UTF8 (' + literal + b')' | ||
self.literal = literal | ||
try: | ||
return self._simple_command(name, mailbox, flags, date_time, **kw) | ||
finally: | ||
|
@@ -774,6 +803,19 @@ def deleteacl(self, mailbox, who, **kw): | |
return self._simple_command('DELETEACL', mailbox, who, **kw) | ||
|
||
|
||
def enable(self, capability): | ||
"""Send an RFC5161 enable string to the server. | ||
(typ, [data]) = <intance>.enable(capability) | ||
""" | ||
if 'ENABLE' not in self.capabilities: | ||
raise self.error("Server does not support ENABLE") | ||
typ, data = self._simple_command('ENABLE', capability) | ||
if typ == 'OK' and 'UTF8=ACCEPT' in capability.upper(): | ||
self._mode_utf8() | ||
return typ, data | ||
|
||
|
||
def examine(self, mailbox='INBOX', **kw): | ||
"""(typ, [data]) = examine(mailbox='INBOX') | ||
Select a mailbox for READ-ONLY access. (Flushes all untagged responses.) | ||
|
@@ -1025,11 +1067,14 @@ def rename(self, oldmailbox, newmailbox, **kw): | |
def search(self, charset, *criteria, **kw): | ||
"""(typ, [data]) = search(charset, criterion, ...) | ||
Search mailbox for matching messages. | ||
If UTF8 is enabled, charset MUST be None. | ||
'data' is space separated list of matching message numbers.""" | ||
|
||
name = 'SEARCH' | ||
kw['untagged_response'] = name | ||
if charset: | ||
if self.utf8_enabled: | ||
raise self.error("Non-None charset not valid in UTF8 mode") | ||
return self._simple_command(name, 'CHARSET', charset, *criteria, **kw) | ||
return self._simple_command(name, *criteria, **kw) | ||
|
||
|
@@ -1412,6 +1457,9 @@ def _command(self, name, *args, **kw): | |
if not ok: | ||
break | ||
|
||
if data == 'go ahead': # Apparently not uncommon broken IMAP4 server response to AUTHENTICATE command | ||
data = '' | ||
|
||
# Send literal | ||
|
||
if literator is not None: | ||
|