folder/IMAP: introduce dedicated parsing for davmail (not supporting UIDPLUS)

Some returned responses end with ')' rather than 'UID XXX)' as expected.

BTW, a better policy could be to request for the 'X-OfflineIMAP' header only
rather than fetching all the headers and looking for it manually.

Also:
- Strip the output when error occurs: we don't need the full response unless
  'imap' debug mode is enabled.
- Improve the comments.

Github-ref: https://github.com/OfflineIMAP/offlineimap/issues/479
Tested-by: https://github.com/secomi
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
This commit is contained in:
Nicolas Sebrecht 2017-06-15 01:22:42 +02:00
parent ce83efc3c7
commit ba47138616

View File

@ -444,32 +444,49 @@ class IMAPFolder(BaseFolder):
# in our way. # in our way.
result = imapobj.uid('FETCH', bytearray('%d:*'% start), 'rfc822.header') result = imapobj.uid('FETCH', bytearray('%d:*'% start), 'rfc822.header')
orig_result = result
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:
# [
# ('185 (RFC822.HEADER {1789}', '... mail headers ...'), ' UID 2444)',
# ('186 (RFC822.HEADER {1789}', '... 2nd mail headers ...'), ' UID 2445)'
# ]
result = result[1] result = result[1]
found = 0 found = None
# item is like:
# ('185 (RFC822.HEADER {1789}', '... mail headers ...'), ' UID 2444)'
for item in result: for item in result:
if found == 0 and type(item) == type( () ): 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 = 1 found = item[0]
elif found == 1: elif found is not None:
if type(item) == type (""): if type(item) == type(""):
uid = re.search("UID\s+(\d+)", item, flags=re.IGNORECASE) uid = re.search("UID\s+(\d+)", item, flags=re.IGNORECASE)
if uid: if uid:
return int(uid.group(1)) return int(uid.group(1))
else: else:
self.ui.warn("Can't parse FETCH response, can't find UID: %s"% # This parsing is for Davmail.
repr(orig_result) # https://github.com/OfflineIMAP/offlineimap/issues/479
# item is like:
# ')'
# and item[0] stored in "found" is like:
# '1694 (UID 1694 RFC822.HEADER {1294}'
uid = re.search("\d+\s+\(UID\s+(\d+)", found, flags=re.IGNORECASE)
if uid:
return int(uid.group(1))
self.ui.warn("Can't parse FETCH response, can't find UID in %s"%
item
) )
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(orig_result) repr(item)
) )
return 0 return 0
@ -711,8 +728,9 @@ class IMAPFolder(BaseFolder):
'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('imap', "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())
finally: finally:
if imapobj: if imapobj:
self.imapserver.releaseconnection(imapobj) self.imapserver.releaseconnection(imapobj)