Reformat offlineimap/folder/IMAP.py
Add some spaces, remove lines,... now format is better (lintian).
This commit is contained in:
parent
2f97dda6d9
commit
da1788db53
@ -27,7 +27,6 @@ from offlineimap import imaputil, imaplibutil, emailutil, OfflineImapError
|
|||||||
from offlineimap import globals
|
from offlineimap import globals
|
||||||
from offlineimap.virtual_imaplib2 import MonthNames
|
from offlineimap.virtual_imaplib2 import MonthNames
|
||||||
|
|
||||||
|
|
||||||
# Globals
|
# Globals
|
||||||
CRLF = '\r\n'
|
CRLF = '\r\n'
|
||||||
MSGCOPY_NAMESPACE = 'MSGCOPY_'
|
MSGCOPY_NAMESPACE = 'MSGCOPY_'
|
||||||
@ -58,7 +57,7 @@ class IMAPFolder(BaseFolder):
|
|||||||
self.visiblename = imaputil.decode_mailbox_name(self.visiblename)
|
self.visiblename = imaputil.decode_mailbox_name(self.visiblename)
|
||||||
self.idle_mode = False
|
self.idle_mode = False
|
||||||
self.expunge = repository.getexpunge()
|
self.expunge = repository.getexpunge()
|
||||||
self.root = None # imapserver.root
|
self.root = None # imapserver.root
|
||||||
self.imapserver = imapserver
|
self.imapserver = imapserver
|
||||||
self.randomgenerator = random.Random()
|
self.randomgenerator = random.Random()
|
||||||
# self.ui is set in BaseFolder.
|
# self.ui is set in BaseFolder.
|
||||||
@ -103,7 +102,7 @@ class IMAPFolder(BaseFolder):
|
|||||||
singlethreadperfolder_default = True
|
singlethreadperfolder_default = True
|
||||||
|
|
||||||
onethread = self.config.getdefaultboolean(
|
onethread = self.config.getdefaultboolean(
|
||||||
"Repository %s"% self.repository.getname(),
|
"Repository %s" % self.repository.getname(),
|
||||||
"singlethreadperfolder", singlethreadperfolder_default)
|
"singlethreadperfolder", singlethreadperfolder_default)
|
||||||
if onethread is True:
|
if onethread is True:
|
||||||
return False
|
return False
|
||||||
@ -114,8 +113,8 @@ class IMAPFolder(BaseFolder):
|
|||||||
self.imapserver.connectionwait()
|
self.imapserver.connectionwait()
|
||||||
|
|
||||||
def getmaxage(self):
|
def getmaxage(self):
|
||||||
if self.config.getdefault("Account %s"%
|
if self.config.getdefault("Account %s" %
|
||||||
self.accountname, "maxage", None):
|
self.accountname, "maxage", None):
|
||||||
six.reraise(OfflineImapError,
|
six.reraise(OfflineImapError,
|
||||||
OfflineImapError(
|
OfflineImapError(
|
||||||
"maxage is not supported on IMAP-IMAP sync",
|
"maxage is not supported on IMAP-IMAP sync",
|
||||||
@ -153,7 +152,7 @@ class IMAPFolder(BaseFolder):
|
|||||||
# An IMAP folder has definitely changed if the number of
|
# An IMAP folder has definitely changed if the number of
|
||||||
# messages or the UID of the last message have changed. Otherwise
|
# messages or the UID of the last message have changed. Otherwise
|
||||||
# only flag changes could have occurred.
|
# only flag changes could have occurred.
|
||||||
retry = True # Should we attempt another round or exit?
|
retry = True # Should we attempt another round or exit?
|
||||||
while retry:
|
while retry:
|
||||||
retry = False
|
retry = False
|
||||||
imapobj = self.imapserver.acquireconnection()
|
imapobj = self.imapserver.acquireconnection()
|
||||||
@ -213,14 +212,14 @@ class IMAPFolder(BaseFolder):
|
|||||||
res_type, res_data = imapobj.search(None, search_conditions)
|
res_type, res_data = imapobj.search(None, search_conditions)
|
||||||
if res_type != 'OK':
|
if res_type != 'OK':
|
||||||
raise OfflineImapError("SEARCH in folder [%s]%s failed. "
|
raise OfflineImapError("SEARCH in folder [%s]%s failed. "
|
||||||
"Search string was '%s'. Server responded '[%s] %s'"% (
|
"Search string was '%s'. Server responded '[%s] %s'" % (
|
||||||
self.getrepository(), self, search_cond, res_type, res_data),
|
self.getrepository(), self, search_cond, res_type, res_data),
|
||||||
OfflineImapError.ERROR.FOLDER)
|
OfflineImapError.ERROR.FOLDER)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise OfflineImapError("SEARCH in folder [%s]%s failed. "
|
raise OfflineImapError("SEARCH in folder [%s]%s failed. "
|
||||||
"Search string was '%s'. Error: %s"% (
|
"Search string was '%s'. Error: %s" % (
|
||||||
self.getrepository(), self, search_cond, str(e)),
|
self.getrepository(), self, search_cond, str(e)),
|
||||||
OfflineImapError.ERROR.FOLDER)
|
OfflineImapError.ERROR.FOLDER)
|
||||||
# Davmail returns list instead of list of one element string.
|
# Davmail returns list instead of list of one element string.
|
||||||
# On first run the first element is empty.
|
# On first run the first element is empty.
|
||||||
if ' ' in res_data[0] or res_data[0] == '':
|
if ' ' in res_data[0] or res_data[0] == '':
|
||||||
@ -239,20 +238,20 @@ class IMAPFolder(BaseFolder):
|
|||||||
conditions = []
|
conditions = []
|
||||||
# 1. min_uid condition.
|
# 1. min_uid condition.
|
||||||
if min_uid != None:
|
if min_uid != None:
|
||||||
conditions.append("UID %d:*"% min_uid)
|
conditions.append("UID %d:*" % min_uid)
|
||||||
# 2. date condition.
|
# 2. date condition.
|
||||||
elif min_date != None:
|
elif min_date != None:
|
||||||
# Find out what the oldest message is that we should look at.
|
# Find out what the oldest message is that we should look at.
|
||||||
conditions.append("SINCE %02d-%s-%d"% (
|
conditions.append("SINCE %02d-%s-%d" % (
|
||||||
min_date[2], MonthNames[min_date[1]], min_date[0]))
|
min_date[2], MonthNames[min_date[1]], min_date[0]))
|
||||||
# 3. maxsize condition.
|
# 3. maxsize condition.
|
||||||
maxsize = self.getmaxsize()
|
maxsize = self.getmaxsize()
|
||||||
if maxsize != None:
|
if maxsize != None:
|
||||||
conditions.append("SMALLER %d"% maxsize)
|
conditions.append("SMALLER %d" % maxsize)
|
||||||
|
|
||||||
if len(conditions) >= 1:
|
if len(conditions) >= 1:
|
||||||
# Build SEARCH command.
|
# Build SEARCH command.
|
||||||
search_cond = "(%s)"% ' '.join(conditions)
|
search_cond = "(%s)" % ' '.join(conditions)
|
||||||
search_result = search(search_cond)
|
search_result = search(search_cond)
|
||||||
return imaputil.uid_sequence(search_result)
|
return imaputil.uid_sequence(search_result)
|
||||||
|
|
||||||
@ -263,7 +262,6 @@ class IMAPFolder(BaseFolder):
|
|||||||
def msglist_item_initializer(self, uid):
|
def msglist_item_initializer(self, uid):
|
||||||
return {'uid': uid, 'flags': set(), 'time': 0}
|
return {'uid': uid, 'flags': set(), 'time': 0}
|
||||||
|
|
||||||
|
|
||||||
# Interface from BaseFolder
|
# Interface from BaseFolder
|
||||||
def cachemessagelist(self, min_date=None, min_uid=None):
|
def cachemessagelist(self, min_date=None, min_uid=None):
|
||||||
self.ui.loadmessagelist(self.repository, self)
|
self.ui.loadmessagelist(self.repository, self)
|
||||||
@ -274,19 +272,20 @@ class IMAPFolder(BaseFolder):
|
|||||||
msgsToFetch = self._msgs_to_fetch(
|
msgsToFetch = self._msgs_to_fetch(
|
||||||
imapobj, min_date=min_date, min_uid=min_uid)
|
imapobj, min_date=min_date, min_uid=min_uid)
|
||||||
if not msgsToFetch:
|
if not msgsToFetch:
|
||||||
return # No messages to sync.
|
return # No messages to sync.
|
||||||
|
|
||||||
# Get the flags and UIDs for these. single-quotes prevent
|
# Get the flags and UIDs for these. single-quotes prevent
|
||||||
# imaplib2 from quoting the sequence.
|
# imaplib2 from quoting the sequence.
|
||||||
fetch_msg = "%s"% msgsToFetch
|
fetch_msg = "%s" % msgsToFetch
|
||||||
self.ui.debug('imap', "calling imaplib2 fetch command: %s %s"%
|
self.ui.debug('imap', "calling imaplib2 fetch command: %s %s" %
|
||||||
(fetch_msg, '(FLAGS UID INTERNALDATE)'))
|
(fetch_msg, '(FLAGS UID INTERNALDATE)'))
|
||||||
res_type, response = imapobj.fetch(
|
res_type, response = imapobj.fetch(
|
||||||
fetch_msg, '(FLAGS UID INTERNALDATE)')
|
fetch_msg, '(FLAGS UID INTERNALDATE)')
|
||||||
if res_type != 'OK':
|
if res_type != 'OK':
|
||||||
raise OfflineImapError("FETCHING UIDs in folder [%s]%s failed. "
|
raise OfflineImapError("FETCHING UIDs in folder [%s]%s failed. "
|
||||||
"Server responded '[%s] %s'"% (self.getrepository(), self,
|
"Server responded '[%s] %s'" % (self.getrepository(), self,
|
||||||
res_type, response), OfflineImapError.ERROR.FOLDER)
|
res_type, response),
|
||||||
|
OfflineImapError.ERROR.FOLDER)
|
||||||
finally:
|
finally:
|
||||||
self.imapserver.releaseconnection(imapobj)
|
self.imapserver.releaseconnection(imapobj)
|
||||||
|
|
||||||
@ -298,8 +297,8 @@ class IMAPFolder(BaseFolder):
|
|||||||
messagestr = messagestr.decode('utf-8').split(' ', 1)[1]
|
messagestr = messagestr.decode('utf-8').split(' ', 1)[1]
|
||||||
options = imaputil.flags2hash(messagestr)
|
options = imaputil.flags2hash(messagestr)
|
||||||
if 'UID' not in options:
|
if 'UID' not in options:
|
||||||
self.ui.warn('No UID in message with options %s'%
|
self.ui.warn('No UID in message with options %s' %
|
||||||
str(options), minor=1)
|
str(options), minor=1)
|
||||||
else:
|
else:
|
||||||
uid = int(options['UID'])
|
uid = int(options['UID'])
|
||||||
self.messagelist[uid] = self.msglist_item_initializer(uid)
|
self.messagelist[uid] = self.msglist_item_initializer(uid)
|
||||||
@ -307,7 +306,7 @@ class IMAPFolder(BaseFolder):
|
|||||||
keywords = imaputil.flagsimap2keywords(options['FLAGS'])
|
keywords = imaputil.flagsimap2keywords(options['FLAGS'])
|
||||||
rtime = imaplibutil.Internaldate2epoch(messagestr)
|
rtime = imaplibutil.Internaldate2epoch(messagestr)
|
||||||
self.messagelist[uid] = {'uid': uid, 'flags': flags, 'time': rtime,
|
self.messagelist[uid] = {'uid': uid, 'flags': flags, 'time': rtime,
|
||||||
'keywords': keywords}
|
'keywords': keywords}
|
||||||
self.ui.messagelistloaded(self.repository, self, self.getmessagecount())
|
self.ui.messagelistloaded(self.repository, self, self.getmessagecount())
|
||||||
|
|
||||||
# Interface from BaseFolder
|
# Interface from BaseFolder
|
||||||
@ -330,11 +329,11 @@ class IMAPFolder(BaseFolder):
|
|||||||
data = data[0][1].replace(CRLF, "\n")
|
data = data[0][1].replace(CRLF, "\n")
|
||||||
|
|
||||||
if len(data) > 200:
|
if len(data) > 200:
|
||||||
dbg_output = "%s...%s"% (str(data)[:150], str(data)[-50:])
|
dbg_output = "%s...%s" % (str(data)[:150], str(data)[-50:])
|
||||||
else:
|
else:
|
||||||
dbg_output = data
|
dbg_output = data
|
||||||
|
|
||||||
self.ui.debug('imap', "Returned object from fetching %d: '%s'"%
|
self.ui.debug('imap', "Returned object from fetching %d: '%s'" %
|
||||||
(uid, dbg_output))
|
(uid, dbg_output))
|
||||||
|
|
||||||
return data
|
return data
|
||||||
@ -374,40 +373,39 @@ class IMAPFolder(BaseFolder):
|
|||||||
|
|
||||||
# Compute unsigned crc32 of 'content' as unique hash.
|
# Compute unsigned crc32 of 'content' as unique hash.
|
||||||
# NB: crc32 returns unsigned only starting with python 3.0.
|
# NB: crc32 returns unsigned only starting with python 3.0.
|
||||||
headervalue = str( binascii.crc32(content) & 0xffffffff ) + '-'
|
headervalue = str(binascii.crc32(content) & 0xffffffff) + '-'
|
||||||
headervalue += str(self.randomgenerator.randint(0,9999999999))
|
headervalue += str(self.randomgenerator.randint(0, 9999999999))
|
||||||
return (headername, headervalue)
|
return (headername, headervalue)
|
||||||
|
|
||||||
|
|
||||||
def __savemessage_searchforheader(self, imapobj, headername, headervalue):
|
def __savemessage_searchforheader(self, imapobj, headername, headervalue):
|
||||||
self.ui.debug('imap', '__savemessage_searchforheader called for %s: %s'%
|
self.ui.debug('imap', '__savemessage_searchforheader called for %s: %s' %
|
||||||
(headername, headervalue))
|
(headername, headervalue))
|
||||||
# Now find the UID it got.
|
# Now find the UID it got.
|
||||||
headervalue = imapobj._quote(headervalue)
|
headervalue = imapobj._quote(headervalue)
|
||||||
try:
|
try:
|
||||||
matchinguids = imapobj.uid('search', 'HEADER',
|
matchinguids = imapobj.uid('search', 'HEADER',
|
||||||
headername, headervalue)[1][0]
|
headername, headervalue)[1][0]
|
||||||
except imapobj.error as err:
|
except imapobj.error as err:
|
||||||
# IMAP server doesn't implement search or had a problem.
|
# IMAP server doesn't implement search or had a problem.
|
||||||
self.ui.debug('imap', "__savemessage_searchforheader: got IMAP "
|
self.ui.debug('imap', "__savemessage_searchforheader: got IMAP "
|
||||||
"error '%s' while attempting to UID SEARCH for message with "
|
"error '%s' while attempting to UID SEARCH for message with "
|
||||||
"header %s"% (err, headername))
|
"header %s" % (err, headername))
|
||||||
return 0
|
return 0
|
||||||
self.ui.debug('imap', "__savemessage_searchforheader got initial "
|
self.ui.debug('imap', "__savemessage_searchforheader got initial "
|
||||||
"matchinguids: " + repr(matchinguids))
|
"matchinguids: " + repr(matchinguids))
|
||||||
|
|
||||||
if matchinguids == '':
|
if matchinguids == '':
|
||||||
self.ui.debug('imap', "__savemessage_searchforheader: UID SEARCH "
|
self.ui.debug('imap', "__savemessage_searchforheader: UID SEARCH "
|
||||||
"for message with header %s yielded no results"% headername)
|
"for message with header %s yielded no results" % headername)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
matchinguids = matchinguids.split(' ')
|
matchinguids = matchinguids.split(' ')
|
||||||
self.ui.debug('imap', '__savemessage_searchforheader: matchinguids now '
|
self.ui.debug('imap', '__savemessage_searchforheader: matchinguids now '
|
||||||
+ repr(matchinguids))
|
+ repr(matchinguids))
|
||||||
if len(matchinguids) != 1 or matchinguids[0] is None:
|
if len(matchinguids) != 1 or matchinguids[0] is None:
|
||||||
raise OfflineImapError(
|
raise OfflineImapError(
|
||||||
"While attempting to find UID for message with "
|
"While attempting to find UID for message with "
|
||||||
"header %s, got wrong-sized matchinguids of %s"%
|
"header %s, got wrong-sized matchinguids of %s" %
|
||||||
(headername, str(matchinguids)),
|
(headername, str(matchinguids)),
|
||||||
OfflineImapError.ERROR.MESSAGE
|
OfflineImapError.ERROR.MESSAGE
|
||||||
)
|
)
|
||||||
@ -436,8 +434,8 @@ class IMAPFolder(BaseFolder):
|
|||||||
|
|
||||||
Returns UID when found, 0 when not found."""
|
Returns UID when found, 0 when not found."""
|
||||||
|
|
||||||
self.ui.debug('imap', '__savemessage_fetchheaders called for %s: %s'% \
|
self.ui.debug('imap', '__savemessage_fetchheaders called for %s: %s' % \
|
||||||
(headername, headervalue))
|
(headername, headervalue))
|
||||||
|
|
||||||
# Run "fetch X:* rfc822.header".
|
# Run "fetch X:* rfc822.header".
|
||||||
# Since we stored the mail we are looking for just recently, it would
|
# Since we stored the mail we are looking for just recently, it would
|
||||||
@ -456,10 +454,10 @@ class IMAPFolder(BaseFolder):
|
|||||||
# with the range X:*. So we use bytearray to stop imaplib from getting
|
# with the range X:*. So we use bytearray to stop imaplib from getting
|
||||||
# in our way.
|
# in our way.
|
||||||
|
|
||||||
result = imapobj.uid('FETCH', bytearray('%d:*'% start), 'rfc822.header')
|
result = imapobj.uid('FETCH', bytearray('%d:*' % start), 'rfc822.header')
|
||||||
if result[0] != 'OK':
|
if result[0] != 'OK':
|
||||||
raise OfflineImapError('Error fetching mail headers: %s'%
|
raise OfflineImapError('Error fetching mail headers: %s' %
|
||||||
'. '.join(result[1]), OfflineImapError.ERROR.MESSAGE)
|
'. '.join(result[1]), OfflineImapError.ERROR.MESSAGE)
|
||||||
|
|
||||||
# result is like:
|
# result is like:
|
||||||
# [
|
# [
|
||||||
@ -474,8 +472,8 @@ class IMAPFolder(BaseFolder):
|
|||||||
for item in result:
|
for item in result:
|
||||||
if found is None and type(item) == tuple:
|
if found is None and type(item) == tuple:
|
||||||
# Walk just tuples.
|
# Walk just tuples.
|
||||||
if re.search("(?:^|\\r|\\n)%s:\s*%s(?:\\r|\\n)"% (headername, headervalue),
|
if re.search("(?:^|\\r|\\n)%s:\s*%s(?:\\r|\\n)" % (headername, headervalue),
|
||||||
item[1], flags=re.IGNORECASE):
|
item[1], flags=re.IGNORECASE):
|
||||||
found = item[0]
|
found = item[0]
|
||||||
elif found is not None:
|
elif found is not None:
|
||||||
if type(item) == type(""):
|
if type(item) == type(""):
|
||||||
@ -493,14 +491,14 @@ class IMAPFolder(BaseFolder):
|
|||||||
if uid:
|
if uid:
|
||||||
return int(uid.group(1))
|
return int(uid.group(1))
|
||||||
|
|
||||||
self.ui.warn("Can't parse FETCH response, can't find UID in %s"%
|
self.ui.warn("Can't parse FETCH response, can't find UID in %s" %
|
||||||
item
|
item
|
||||||
)
|
)
|
||||||
self.ui.debug('imap', "Got: %s"% repr(result))
|
self.ui.debug('imap', "Got: %s" % repr(result))
|
||||||
else:
|
else:
|
||||||
self.ui.warn("Can't parse FETCH response, we awaited string: %s"%
|
self.ui.warn("Can't parse FETCH response, we awaited string: %s" %
|
||||||
repr(item)
|
repr(item)
|
||||||
)
|
)
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@ -557,13 +555,13 @@ class IMAPFolder(BaseFolder):
|
|||||||
# will rause a ValueError if the year is 0102 but not 1902,
|
# will rause a ValueError if the year is 0102 but not 1902,
|
||||||
# but some IMAP servers nonetheless choke on 1902.
|
# but some IMAP servers nonetheless choke on 1902.
|
||||||
self.ui.debug('imap', "Message with invalid date %s. "
|
self.ui.debug('imap', "Message with invalid date %s. "
|
||||||
"Server will use local time."% datetuple)
|
"Server will use local time." % datetuple)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Produce a string representation of datetuple that works as
|
# Produce a string representation of datetuple that works as
|
||||||
# INTERNALDATE.
|
# INTERNALDATE.
|
||||||
num2mon = {1:'Jan', 2:'Feb', 3:'Mar', 4:'Apr', 5:'May', 6:'Jun',
|
num2mon = {1: 'Jan', 2: 'Feb', 3: 'Mar', 4: 'Apr', 5: 'May', 6: 'Jun',
|
||||||
7:'Jul', 8:'Aug', 9:'Sep', 10:'Oct', 11:'Nov', 12:'Dec'}
|
7: 'Jul', 8: 'Aug', 9: 'Sep', 10: 'Oct', 11: 'Nov', 12: 'Dec'}
|
||||||
|
|
||||||
# tm_isdst coming from email.parsedate is not usable, we still use it
|
# tm_isdst coming from email.parsedate is not usable, we still use it
|
||||||
# here, mhh.
|
# here, mhh.
|
||||||
@ -571,11 +569,11 @@ class IMAPFolder(BaseFolder):
|
|||||||
zone = -time.altzone
|
zone = -time.altzone
|
||||||
else:
|
else:
|
||||||
zone = -time.timezone
|
zone = -time.timezone
|
||||||
offset_h, offset_m = divmod(zone//60, 60)
|
offset_h, offset_m = divmod(zone // 60, 60)
|
||||||
|
|
||||||
internaldate = '"%02d-%s-%04d %02d:%02d:%02d %+03d%02d"'% \
|
internaldate = '"%02d-%s-%04d %02d:%02d:%02d %+03d%02d"' % \
|
||||||
(datetuple.tm_mday, num2mon[datetuple.tm_mon], datetuple.tm_year, \
|
(datetuple.tm_mday, num2mon[datetuple.tm_mon], datetuple.tm_year, \
|
||||||
datetuple.tm_hour, datetuple.tm_min, datetuple.tm_sec, offset_h, offset_m)
|
datetuple.tm_hour, datetuple.tm_min, datetuple.tm_sec, offset_h, offset_m)
|
||||||
|
|
||||||
return internaldate
|
return internaldate
|
||||||
|
|
||||||
@ -618,7 +616,7 @@ class IMAPFolder(BaseFolder):
|
|||||||
if not msg_id:
|
if not msg_id:
|
||||||
msg_id = '[unknown message-id]'
|
msg_id = '[unknown message-id]'
|
||||||
|
|
||||||
retry_left = 2 # succeeded in APPENDING?
|
retry_left = 2 # succeeded in APPENDING?
|
||||||
imapobj = self.imapserver.acquireconnection()
|
imapobj = self.imapserver.acquireconnection()
|
||||||
# NB: in the finally clause for this try we will release
|
# NB: in the finally clause for this try we will release
|
||||||
# NB: the acquired imapobj, so don't do that twice unless
|
# NB: the acquired imapobj, so don't do that twice unless
|
||||||
@ -635,16 +633,16 @@ class IMAPFolder(BaseFolder):
|
|||||||
# Insert a random unique header that we can fetch later.
|
# Insert a random unique header that we can fetch later.
|
||||||
(headername, headervalue) = self.__generate_randomheader(
|
(headername, headervalue) = self.__generate_randomheader(
|
||||||
content)
|
content)
|
||||||
self.ui.debug('imap', 'savemessage: header is: %s: %s'%
|
self.ui.debug('imap', 'savemessage: header is: %s: %s' %
|
||||||
(headername, headervalue))
|
(headername, headervalue))
|
||||||
content = self.addmessageheader(content, CRLF, headername, headervalue)
|
content = self.addmessageheader(content, CRLF, headername, headervalue)
|
||||||
|
|
||||||
if len(content) > 200:
|
if len(content) > 200:
|
||||||
dbg_output = "%s...%s"% (content[:150], content[-50:])
|
dbg_output = "%s...%s" % (content[:150], content[-50:])
|
||||||
else:
|
else:
|
||||||
dbg_output = content
|
dbg_output = content
|
||||||
self.ui.debug('imap', "savemessage: date: %s, content: '%s'"%
|
self.ui.debug('imap', "savemessage: date: %s, content: '%s'" %
|
||||||
(date, dbg_output))
|
(date, dbg_output))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Select folder for append and make the box READ-WRITE.
|
# Select folder for append and make the box READ-WRITE.
|
||||||
@ -658,7 +656,7 @@ class IMAPFolder(BaseFolder):
|
|||||||
# Do the APPEND.
|
# Do the APPEND.
|
||||||
try:
|
try:
|
||||||
(typ, dat) = imapobj.append(self.getfullIMAPname(),
|
(typ, dat) = imapobj.append(self.getfullIMAPname(),
|
||||||
imaputil.flagsmaildir2imap(flags), date, content)
|
imaputil.flagsmaildir2imap(flags), date, content)
|
||||||
# This should only catch 'NO' responses since append()
|
# This should only catch 'NO' responses since append()
|
||||||
# will raise an exception for 'BAD' responses:
|
# will raise an exception for 'BAD' responses:
|
||||||
if typ != 'OK':
|
if typ != 'OK':
|
||||||
@ -670,10 +668,10 @@ class IMAPFolder(BaseFolder):
|
|||||||
# and continue with the next account.
|
# and continue with the next account.
|
||||||
msg = \
|
msg = \
|
||||||
"Saving msg (%s) in folder '%s', repository '%s' failed (abort). " \
|
"Saving msg (%s) in folder '%s', repository '%s' failed (abort). " \
|
||||||
"Server responded: %s %s\n"% \
|
"Server responded: %s %s\n" % \
|
||||||
(msg_id, self, self.getrepository(), typ, dat)
|
(msg_id, self, self.getrepository(), typ, dat)
|
||||||
raise OfflineImapError(msg, OfflineImapError.ERROR.REPO)
|
raise OfflineImapError(msg, OfflineImapError.ERROR.REPO)
|
||||||
retry_left = 0 # Mark as success.
|
retry_left = 0 # Mark as success.
|
||||||
except imapobj.abort as e:
|
except imapobj.abort as e:
|
||||||
# Connection has been reset, release connection and retry.
|
# Connection has been reset, release connection and retry.
|
||||||
retry_left -= 1
|
retry_left -= 1
|
||||||
@ -682,14 +680,14 @@ class IMAPFolder(BaseFolder):
|
|||||||
if not retry_left:
|
if not retry_left:
|
||||||
six.reraise(OfflineImapError,
|
six.reraise(OfflineImapError,
|
||||||
OfflineImapError("Saving msg (%s) in folder '%s', "
|
OfflineImapError("Saving msg (%s) in folder '%s', "
|
||||||
"repository '%s' failed (abort). Server responded: %s\n"
|
"repository '%s' failed (abort). Server responded: %s\n"
|
||||||
"Message content was: %s"%
|
"Message content was: %s" %
|
||||||
(msg_id, self, self.getrepository(), str(e), dbg_output),
|
(msg_id, self, self.getrepository(), str(e), dbg_output),
|
||||||
OfflineImapError.ERROR.MESSAGE),
|
OfflineImapError.ERROR.MESSAGE),
|
||||||
exc_info()[2])
|
exc_info()[2])
|
||||||
# XXX: is this still needed?
|
# XXX: is this still needed?
|
||||||
self.ui.error(e, exc_info()[2])
|
self.ui.error(e, exc_info()[2])
|
||||||
except imapobj.error as e: # APPEND failed
|
except imapobj.error as e: # APPEND failed
|
||||||
# If the server responds with 'BAD', append()
|
# If the server responds with 'BAD', append()
|
||||||
# raise()s directly. So we catch that too.
|
# raise()s directly. So we catch that too.
|
||||||
# drop conn, it might be bad.
|
# drop conn, it might be bad.
|
||||||
@ -697,14 +695,14 @@ class IMAPFolder(BaseFolder):
|
|||||||
imapobj = None
|
imapobj = None
|
||||||
six.reraise(OfflineImapError,
|
six.reraise(OfflineImapError,
|
||||||
OfflineImapError("Saving msg (%s) folder '%s', repo '%s'"
|
OfflineImapError("Saving msg (%s) folder '%s', repo '%s'"
|
||||||
"failed (error). Server responded: %s\nMessage content was: "
|
"failed (error). Server responded: %s\nMessage content was: "
|
||||||
"%s"% (msg_id, self, self.getrepository(), str(e), dbg_output),
|
"%s" % (msg_id, self, self.getrepository(), str(e), dbg_output),
|
||||||
OfflineImapError.ERROR.MESSAGE),
|
OfflineImapError.ERROR.MESSAGE),
|
||||||
exc_info()[2])
|
exc_info()[2])
|
||||||
# Checkpoint. Let it write out stuff, etc. Eg searches for
|
# Checkpoint. Let it write out stuff, etc. Eg searches for
|
||||||
# just uploaded messages won't work if we don't do this.
|
# just uploaded messages won't work if we don't do this.
|
||||||
(typ,dat) = imapobj.check()
|
(typ, dat) = imapobj.check()
|
||||||
assert(typ == 'OK')
|
assert (typ == 'OK')
|
||||||
|
|
||||||
# Get the new UID, do we use UIDPLUS?
|
# Get the new UID, do we use UIDPLUS?
|
||||||
if use_uidplus:
|
if use_uidplus:
|
||||||
@ -717,55 +715,54 @@ class IMAPFolder(BaseFolder):
|
|||||||
resp = imapobj._get_untagged_response('APPENDUID')
|
resp = imapobj._get_untagged_response('APPENDUID')
|
||||||
if resp == [None] or resp is None:
|
if resp == [None] or resp is None:
|
||||||
self.ui.warn("Server supports UIDPLUS but got no APPENDUID "
|
self.ui.warn("Server supports UIDPLUS but got no APPENDUID "
|
||||||
"appending a message. Got: %s."% str(resp))
|
"appending a message. Got: %s." % str(resp))
|
||||||
return 0
|
return 0
|
||||||
try:
|
try:
|
||||||
uid = int(resp[-1].split(' ')[1])
|
uid = int(resp[-1].split(' ')[1])
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
uid = 0 # Definetly not what we should have.
|
uid = 0 # Definetly not what we should have.
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise OfflineImapError("Unexpected response: %s"% str(resp),
|
raise OfflineImapError("Unexpected response: %s" % str(resp),
|
||||||
OfflineImapError.ERROR.MESSAGE)
|
OfflineImapError.ERROR.MESSAGE)
|
||||||
if uid == 0:
|
if uid == 0:
|
||||||
self.ui.warn("savemessage: Server supports UIDPLUS, but"
|
self.ui.warn("savemessage: Server supports UIDPLUS, but"
|
||||||
" we got no usable UID back. APPENDUID reponse was "
|
" we got no usable UID back. APPENDUID reponse was "
|
||||||
"'%s'"% str(resp))
|
"'%s'" % str(resp))
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
# We don't use UIDPLUS.
|
# We don't use UIDPLUS.
|
||||||
uid = self.__savemessage_searchforheader(imapobj, headername,
|
uid = self.__savemessage_searchforheader(imapobj, headername,
|
||||||
headervalue)
|
headervalue)
|
||||||
# See docs for savemessage in Base.py for explanation
|
# See docs for savemessage in Base.py for explanation
|
||||||
# of this and other return values.
|
# of this and other return values.
|
||||||
if uid == 0:
|
if uid == 0:
|
||||||
self.ui.debug('imap', 'savemessage: attempt to get new UID '
|
self.ui.debug('imap', 'savemessage: attempt to get new UID '
|
||||||
'UID failed. Search headers manually.')
|
'UID failed. Search headers manually.')
|
||||||
uid = self.__savemessage_fetchheaders(imapobj, headername,
|
uid = self.__savemessage_fetchheaders(imapobj, headername,
|
||||||
headervalue)
|
headervalue)
|
||||||
self.ui.warn("savemessage: Searching mails for new "
|
self.ui.warn("savemessage: Searching mails for new "
|
||||||
"Message-ID failed. Could not determine new UID "
|
"Message-ID failed. Could not determine new UID "
|
||||||
"on %s."% self.getname())
|
"on %s." % self.getname())
|
||||||
# Something wrong happened while trying to get the UID. Explain
|
# Something wrong happened while trying to get the UID. Explain
|
||||||
# the error might be about the 'get UID' process not necesseraly
|
# the error might be about the 'get UID' process not necesseraly
|
||||||
# the APPEND.
|
# the APPEND.
|
||||||
except Exception:
|
except Exception:
|
||||||
self.ui.warn("%s: could not determine the UID while we got "
|
self.ui.warn("%s: could not determine the UID while we got "
|
||||||
"no error while appending the email with '%s: %s'"%
|
"no error while appending the email with '%s: %s'" %
|
||||||
(self.getname(), headername, headervalue)
|
(self.getname(), headername, headervalue)
|
||||||
)
|
)
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
if imapobj:
|
if imapobj:
|
||||||
self.imapserver.releaseconnection(imapobj)
|
self.imapserver.releaseconnection(imapobj)
|
||||||
|
|
||||||
if uid: # Avoid UID FETCH 0 crash happening later on.
|
if uid: # Avoid UID FETCH 0 crash happening later on.
|
||||||
self.messagelist[uid] = self.msglist_item_initializer(uid)
|
self.messagelist[uid] = self.msglist_item_initializer(uid)
|
||||||
self.messagelist[uid]['flags'] = flags
|
self.messagelist[uid]['flags'] = flags
|
||||||
|
|
||||||
self.ui.debug('imap', 'savemessage: returning new UID %d'% uid)
|
self.ui.debug('imap', 'savemessage: returning new UID %d' % uid)
|
||||||
return uid
|
return uid
|
||||||
|
|
||||||
|
|
||||||
def _fetch_from_imap(self, uids, retry_num=1):
|
def _fetch_from_imap(self, uids, retry_num=1):
|
||||||
"""Fetches data from IMAP server.
|
"""Fetches data from IMAP server.
|
||||||
|
|
||||||
@ -777,7 +774,7 @@ class IMAPFolder(BaseFolder):
|
|||||||
|
|
||||||
imapobj = self.imapserver.acquireconnection()
|
imapobj = self.imapserver.acquireconnection()
|
||||||
try:
|
try:
|
||||||
query = "(%s)"% (" ".join(self.imap_query))
|
query = "(%s)" % (" ".join(self.imap_query))
|
||||||
fails_left = retry_num # Retry on dropped connection.
|
fails_left = retry_num # Retry on dropped connection.
|
||||||
while fails_left:
|
while fails_left:
|
||||||
try:
|
try:
|
||||||
@ -789,24 +786,24 @@ class IMAPFolder(BaseFolder):
|
|||||||
# self.ui.error() will show the original traceback.
|
# self.ui.error() will show the original traceback.
|
||||||
if fails_left <= 0:
|
if fails_left <= 0:
|
||||||
message = ("%s, while fetching msg %r in folder %r."
|
message = ("%s, while fetching msg %r in folder %r."
|
||||||
" Max retry reached (%d)"%
|
" Max retry reached (%d)" %
|
||||||
(e, uids, self.name, retry_num))
|
(e, uids, self.name, retry_num))
|
||||||
severity = OfflineImapError.ERROR.MESSAGE
|
severity = OfflineImapError.ERROR.MESSAGE
|
||||||
raise OfflineImapError(message,
|
raise OfflineImapError(message,
|
||||||
OfflineImapError.ERROR.MESSAGE)
|
OfflineImapError.ERROR.MESSAGE)
|
||||||
self.ui.error("%s. While fetching msg %r in folder %r."
|
self.ui.error("%s. While fetching msg %r in folder %r."
|
||||||
" Query: %s Retrying (%d/%d)"% (
|
" Query: %s Retrying (%d/%d)" % (
|
||||||
e, uids, self.name, query,
|
e, uids, self.name, query,
|
||||||
retry_num - fails_left, retry_num
|
retry_num - fails_left, retry_num
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
# Release dropped connection, and get a new one.
|
# Release dropped connection, and get a new one.
|
||||||
self.imapserver.releaseconnection(imapobj, True)
|
self.imapserver.releaseconnection(imapobj, True)
|
||||||
imapobj = self.imapserver.acquireconnection()
|
imapobj = self.imapserver.acquireconnection()
|
||||||
finally:
|
finally:
|
||||||
# The imapobj here might be different than the one created before
|
# The imapobj here might be different than the one created before
|
||||||
# the ``try`` clause. So please avoid transforming this to a nice
|
# the ``try`` clause. So please avoid transforming this to a nice
|
||||||
# ``with`` without taking this into account.
|
# ``with`` without taking this into account.
|
||||||
self.imapserver.releaseconnection(imapobj)
|
self.imapserver.releaseconnection(imapobj)
|
||||||
|
|
||||||
# Ensure to not consider unsolicited FETCH responses caused by flag
|
# Ensure to not consider unsolicited FETCH responses caused by flag
|
||||||
@ -820,13 +817,13 @@ class IMAPFolder(BaseFolder):
|
|||||||
# data for the UID FETCH command.
|
# data for the UID FETCH command.
|
||||||
if data == [None] or res_type != 'OK' or len(data) != 1:
|
if data == [None] or res_type != 'OK' or len(data) != 1:
|
||||||
severity = OfflineImapError.ERROR.MESSAGE
|
severity = OfflineImapError.ERROR.MESSAGE
|
||||||
reason = "IMAP server '%s' failed to fetch messages UID '%s'."\
|
reason = "IMAP server '%s' failed to fetch messages UID '%s'." \
|
||||||
" Server responded: %s %s"% (self.getrepository(), uids,
|
" Server responded: %s %s" % (self.getrepository(), uids,
|
||||||
res_type, data)
|
res_type, data)
|
||||||
if data == [None] or len(data) < 1:
|
if data == [None] or len(data) < 1:
|
||||||
# IMAP server did not find a message with this UID.
|
# IMAP server did not find a message with this UID.
|
||||||
reason = "IMAP server '%s' does not have a message "\
|
reason = "IMAP server '%s' does not have a message " \
|
||||||
"with UID '%s'"% (self.getrepository(), uids)
|
"with UID '%s'" % (self.getrepository(), uids)
|
||||||
raise OfflineImapError(reason, severity)
|
raise OfflineImapError(reason, severity)
|
||||||
|
|
||||||
# Convert bytes to str
|
# Convert bytes to str
|
||||||
@ -836,7 +833,6 @@ class IMAPFolder(BaseFolder):
|
|||||||
|
|
||||||
return ndata
|
return ndata
|
||||||
|
|
||||||
|
|
||||||
def _store_to_imap(self, imapobj, uid, field, data):
|
def _store_to_imap(self, imapobj, uid, field, data):
|
||||||
"""Stores data to IMAP server
|
"""Stores data to IMAP server
|
||||||
|
|
||||||
@ -850,9 +846,9 @@ class IMAPFolder(BaseFolder):
|
|||||||
res_type, retdata = imapobj.uid('store', uid, field, data)
|
res_type, retdata = imapobj.uid('store', uid, field, data)
|
||||||
if res_type != 'OK':
|
if res_type != 'OK':
|
||||||
severity = OfflineImapError.ERROR.MESSAGE
|
severity = OfflineImapError.ERROR.MESSAGE
|
||||||
reason = "IMAP server '%s' failed to store %s for message UID '%d'."\
|
reason = "IMAP server '%s' failed to store %s for message UID '%d'." \
|
||||||
"Server responded: %s %s"% (
|
"Server responded: %s %s" % (
|
||||||
self.getrepository(), field, uid, res_type, retdata)
|
self.getrepository(), field, uid, res_type, retdata)
|
||||||
raise OfflineImapError(reason, severity)
|
raise OfflineImapError(reason, severity)
|
||||||
return retdata[0]
|
return retdata[0]
|
||||||
|
|
||||||
@ -867,7 +863,7 @@ class IMAPFolder(BaseFolder):
|
|||||||
imapobj = self.imapserver.acquireconnection()
|
imapobj = self.imapserver.acquireconnection()
|
||||||
try:
|
try:
|
||||||
result = self._store_to_imap(imapobj, str(uid), 'FLAGS',
|
result = self._store_to_imap(imapobj, str(uid), 'FLAGS',
|
||||||
imaputil.flagsmaildir2imap(flags))
|
imaputil.flagsmaildir2imap(flags))
|
||||||
except imapobj.readonly:
|
except imapobj.readonly:
|
||||||
self.ui.flagstoreadonly(self, [uid], flags)
|
self.ui.flagstoreadonly(self, [uid], flags)
|
||||||
return
|
return
|
||||||
@ -912,11 +908,11 @@ class IMAPFolder(BaseFolder):
|
|||||||
self.ui.flagstoreadonly(self, uidlist, flags)
|
self.ui.flagstoreadonly(self, uidlist, flags)
|
||||||
return
|
return
|
||||||
response = imapobj.uid('store',
|
response = imapobj.uid('store',
|
||||||
imaputil.uid_sequence(uidlist), operation + 'FLAGS',
|
imaputil.uid_sequence(uidlist), operation + 'FLAGS',
|
||||||
imaputil.flagsmaildir2imap(flags))
|
imaputil.flagsmaildir2imap(flags))
|
||||||
if response[0] != 'OK':
|
if response[0] != 'OK':
|
||||||
raise OfflineImapError(
|
raise OfflineImapError(
|
||||||
'Error with store: %s'% '. '.join(response[1]),
|
'Error with store: %s' % '. '.join(response[1]),
|
||||||
OfflineImapError.ERROR.MESSAGE)
|
OfflineImapError.ERROR.MESSAGE)
|
||||||
response = response[1]
|
response = response[1]
|
||||||
finally:
|
finally:
|
||||||
@ -947,16 +943,14 @@ class IMAPFolder(BaseFolder):
|
|||||||
elif operation == '-':
|
elif operation == '-':
|
||||||
self.messagelist[uid]['flags'] -= flags
|
self.messagelist[uid]['flags'] -= flags
|
||||||
|
|
||||||
|
|
||||||
def __processmessagesflags(self, operation, uidlist, flags):
|
def __processmessagesflags(self, operation, uidlist, flags):
|
||||||
# Hack for those IMAP servers with a limited line length.
|
# Hack for those IMAP servers with a limited line length.
|
||||||
batch_size = 100
|
batch_size = 100
|
||||||
for i in range(0, len(uidlist), batch_size):
|
for i in range(0, len(uidlist), batch_size):
|
||||||
self.__processmessagesflags_real(operation,
|
self.__processmessagesflags_real(operation,
|
||||||
uidlist[i:i + batch_size], flags)
|
uidlist[i:i + batch_size], flags)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
# Interface from BaseFolder
|
# Interface from BaseFolder
|
||||||
def change_message_uid(self, uid, new_uid):
|
def change_message_uid(self, uid, new_uid):
|
||||||
"""Change the message from existing uid to new_uid
|
"""Change the message from existing uid to new_uid
|
||||||
@ -964,7 +958,7 @@ class IMAPFolder(BaseFolder):
|
|||||||
If the backend supports it. IMAP does not and will throw errors."""
|
If the backend supports it. IMAP does not and will throw errors."""
|
||||||
|
|
||||||
raise OfflineImapError('IMAP backend cannot change a messages UID from '
|
raise OfflineImapError('IMAP backend cannot change a messages UID from '
|
||||||
'%d to %d'% (uid, new_uid), OfflineImapError.ERROR.MESSAGE)
|
'%d to %d' % (uid, new_uid), OfflineImapError.ERROR.MESSAGE)
|
||||||
|
|
||||||
# Interface from BaseFolder
|
# Interface from BaseFolder
|
||||||
def deletemessage(self, uid):
|
def deletemessage(self, uid):
|
||||||
@ -987,7 +981,7 @@ class IMAPFolder(BaseFolder):
|
|||||||
self.ui.deletereadonly(self, uidlist)
|
self.ui.deletereadonly(self, uidlist)
|
||||||
return
|
return
|
||||||
if self.expunge:
|
if self.expunge:
|
||||||
assert(imapobj.expunge()[0] == 'OK')
|
assert (imapobj.expunge()[0] == 'OK')
|
||||||
finally:
|
finally:
|
||||||
self.imapserver.releaseconnection(imapobj)
|
self.imapserver.releaseconnection(imapobj)
|
||||||
for uid in uidlist:
|
for uid in uidlist:
|
||||||
|
Loading…
Reference in New Issue
Block a user