This patch converts the search results from bytes to strings
I add a bit comment about it here:
In Py2, with IMAP, imaplib2 returned a list of one element string.
['1, 2, 3, ...'] -> in Py3 is [b'1 2 3,...']
In Py2, with Davmail, imaplib2 returned a list of strings.
['1', '2', '3', ...] -> in Py3 should be [b'1', b'2', b'3',...]
In my tests with Py3, I get a list with one element: [b'1 2 3 ...']
Then I convert the values to string and I get ['1 2 3 ...']
With Davmail, it should be [b'1', b'2', b'3',...]
When I convert the values to string, I get ['1', '2', '3',...]
imaplib2 is doing this code for strings:
if isinstance(message, str):
message = bytes(message, 'ASCII')
But our message is already encoded using 'utf-8'.
Then, we can set the message as bytes, encoded using 'utf-8'
in offlineimap and imaplib2 won't change our message.
This patch solves this problem:
WARNING:OfflineImap:
Traceback:
File "/home/kix/src/offlineimap3/offlineimap/folder/Base.py", line 1127, in syncmessagesto
action(dstfolder, statusfolder)
File "/home/kix/src/offlineimap3/offlineimap/folder/Base.py", line 955, in __syncmessagesto_copy
self.copymessageto(uid, dstfolder, statusfolder, register=0)
File "/home/kix/src/offlineimap3/offlineimap/folder/Base.py", line 855, in copymessageto
new_uid = dstfolder.savemessage(uid, message, flags, rtime)
File "/home/kix/src/offlineimap3/offlineimap/folder/IMAP.py", line 668, in savemessage
(typ, dat) = imapobj.append(self.getfullIMAPname(),
File "/usr/lib/python3/dist-packages/imaplib2.py", line 660, in append
message = bytes(message, 'ASCII')
Emails received may not be UTF-8. Following error was observed on a specific
mail:
Traceback (most recent call last):
File "/home/tdescham/repo/offlineimap3/offlineimap/threadutil.py", line 146, in run
Thread.run(self)
File "/usr/lib/python3.7/threading.py", line 870, in run
self._target(*self._args, **self._kwargs)
File "/home/tdescham/repo/offlineimap3/offlineimap/folder/Base.py", line 850, in copymessageto
message = self.getmessage(uid)
File "/home/tdescham/repo/offlineimap3/offlineimap/folder/IMAP.py", line 327, in getmessage
data = self._fetch_from_imap(str(uid), self.retrycount)
File "/home/tdescham/repo/offlineimap3/offlineimap/folder/IMAP.py", line 844, in _fetch_from_imap
ndata1 = data[0][1].decode('utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa0 in position 10177: invalid start byte
This completely aborted offlineimap3, blocking further mail reception.
Instead, use the 'replace' error strategy in Python:
Replace with a suitable replacement character; Python will use the
official U+FFFD REPLACEMENT CHARACTER for the built-in Unicode codecs on
decoding and ‘?’ on encoding.
https://docs.python.org/2/library/codecs.html#codec-base-classes
ERROR: ERROR in syncfolder for gmail folder INBOX: Traceback (most recent call last):
File ".../offlineimap3/offlineimap/accounts.py", line 634, in syncfolder
cachemessagelists_upto_date(maxage)
File ".../offlineimap3/offlineimap/accounts.py", line 526, in cachemessagelists_upto_date
min_date=time.gmtime(time.mktime(date) + 24 * 60 * 60))
File ".../offlineimap3/offlineimap/folder/IMAP.py", line 277, in cachemessagelist
imapobj, min_date=min_date, min_uid=min_uid)
File ".../offlineimap3/offlineimap/folder/IMAP.py", line 259, in _msgs_to_fetch
search_result = search(search_cond)
File ".../offlineimap3/offlineimap/folder/IMAP.py", line 222, in search
if ' ' in res_data[0] or res_data[0] == '':
TypeError: a bytes-like object is required, not 'str'
Following error is seen when parsing server responses for sent mail:
2020-10-12 08:19:11 WARNING: Can't parse FETCH response, we awaited string: b' UID 26855)'
2020-10-12 08:19:11 WARNING: savemessage: Searching mails for new Message-ID failed. Could not determine new UID on Sent.
The comparison with 'type("")' means comparing with 'string' type in Python
3, but the left-hand side is a bytes object.
In case a tuple was received (first case in the code), the input is already
decoded from bytes to strings, but in case a single input was received it
was not.
Note that the comparison with 'type("")' is a bit odd, a more logical way
seems to be:
if isinstance(item, bytes)
Signed-off-by: Thomas De Schampheleire <thomas.de_schampheleire@nokia.com>
This patch allows using folders with atom-specials like
"(", ")", spaces,...
We need quotes the folder name if it includes this special
characters.
Closes#4
This patch removes the library six, compatible with python2.
I need change these re-raise calls.
Signed-off-by: Rodolfo García Peñas (kix) <kix@kix.es>
This patch changes the function __savemessage_fetchheaders to decode the
bytes retunred by imaplib2.
We need a list of headers, with string values, but imapli2 is providing
a list with bytes. This change convert the values to str.
Signed-off-by: Rodolfo García Peñas (kix) <kix@kix.es>
matchinguids variable is a list of UIDs, separated by spaces. You can
check it some lines later, using the split command.
We need decode the bytes value returned by imaplib2 and convert it to
sting.
Signed-off-by: Rodolfo García Peñas (kix) <kix@kix.es>
Now, the server response is in a list of strings. We need the second
string, so we need read the [1].
Previously, was a list of tuples, so, we used [0][1].
This patch change these errors in the 'folder' folder
C0121: Comparison to None should be 'expr is None' (singleton-comparison)
C0121: Comparison to None should be 'expr is not None' (singleton-comparison)
The IMAP command is:
C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
not
C: A654 FETCH '2:4' (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
The single quotes must be removed.
When there is not UIDPLUS we have to figure the UID by our means. When this
process fails, we don't know if the email was successfully uploaded. This patch
provides better logs to explain what happened.
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
If utf8foldernames is enabled on account level all folder names read
from the IMAP server will immediately be reencoded to UTF-8. Names
will be treated as UTF-8 as long as the IMAP server isn't contacted again,
for which they are reencoded to IMAP4-UTF-7.
This means that any further processing such as nametrans, folderfilter
etc. will act upon the UTF-8 names, which will have to be documented
carefully.
NOTE 1:
GMail repositories and folders inherit from the IMAP... classes, so I don't
know yet if these changes have ugly side-effects. But web research suggests
that GMail IMAP folders are equally encoded in UTF-7 so that should work
identically here and incorporate the same improvements.
NOTE 2:
I could not test the behaviour with idlefolders as I didn't get this option
to work at all, not even with the latest stable version.
NOTE 3:
I *did* test to sync an IMAP repository against another IMAP repository.
Signed-off-by: Urs Liska <git@ursliska.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
While intending *not* to change the behaviour of the existing
decodefoldernames option this commit transparently improves
the coding.
So far this worked by overriding the folder's getvisiblename() method
which reads self.visiblename from and applies the conversion on
*every* invocation of getvisiblename().
This commit does the calculation once in the IMAPFolder's __init__.
Signed-off-by: Urs Liska <git@ursliska.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
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>
Allow retrying the download of messages more than twice.
Signed-off-by: Luke Kenneth Casson Leighton <lkcl@lkcl.net>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
To further ensure that messages are synchronized strictly in UID
order, this option can be set to cause only one thread to be used
to synchronise an individual folder, though other folders may
be synchronized simultaneously by other threads.
Signed-off-by: James E. Blair <corvus@gnu.org>
Based-on-patch-by: James E. Blair <corvus@gnu.org>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
OfflineIMAP frequently delivers mail files to the Maildir consisting exclusively
of a single ASCII digit in IDLE mode. IMAPFolder.getmessage expects 'data' to be
of the form
[(fetch-info, message-body)]
However, the imapobj.uid call in getmessage returns a list of *all* pending
untagged FETCH responses. If any message flags were changed in the selected
IMAP folder since the last command (by another client or another thread in
OfflineIMAP itself), the IMAP server will issue unsolicited FETCH responses
indicating these flag changes (RFC3501, section 7). When this happens, 'data'
will look like, for example
['1231 (FLAGS (\\Seen) UID 5300)',
'1238 (FLAGS (\\Seen) UID 5318)',
('1242 (UID 5325 BODY[] {7976}', message-body)]
Unfortunately, getmessage retrieves the message body as data[0][1], which in
this example is just the string "2", and this is what gets stored in the mail
file.
Multi-threaded OfflineIMAP with IDLE or holdconnectionopen is particularly
susceptible to this problem because flag changes synced back to the IMAP server
on one thread will appear as unsolicited FETCH responses on another thread if it
happens to have the same folder selected. This can also happen without IDLE or
holdconnectionopen or even in single-threaded OfflineIMAP with concurrent access
from other IMAP clients (webmail clients, etc.), though the window for the bug
is much smaller.
Ideally, either imaplib2 or getmessage would parse the fetch responses to find
the response for the requested UID. However, since IMAP only specifies
unilateral FETCH responses for flag changes, it's almost certainly safe to
simply find the element of 'data' that is a tuple (perhaps aborting if there is
more than one tuple) and use that.
Github-fix: https://github.com/OfflineIMAP/offlineimap/issues/162
Based-on-patch-by: Austin Clements <amdragon@MIT.EDU>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>