From 340a6e9e6cdf1d0cc7e0eb98cbcbdccc42a62f13 Mon Sep 17 00:00:00 2001 From: M66B Date: Thu, 26 Sep 2019 10:53:27 +0200 Subject: [PATCH] Workaround server bugs --- .../email/BoundaryCallbackMessages.java | 3 +- app/src/main/java/eu/faircode/email/Core.java | 54 ++++++++++++++++--- .../java/eu/faircode/email/MessageHelper.java | 31 ++++------- 3 files changed, 60 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/eu/faircode/email/BoundaryCallbackMessages.java b/app/src/main/java/eu/faircode/email/BoundaryCallbackMessages.java index 5ece84feca..2c1a5de691 100644 --- a/app/src/main/java/eu/faircode/email/BoundaryCallbackMessages.java +++ b/app/src/main/java/eu/faircode/email/BoundaryCallbackMessages.java @@ -56,6 +56,7 @@ import javax.mail.MessageRemovedException; import javax.mail.MessagingException; import javax.mail.UIDFolder; import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; import javax.mail.search.AndTerm; import javax.mail.search.BodyTerm; import javax.mail.search.ComparisonTerm; @@ -466,7 +467,7 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback rules = db.rule().getEnabledRules(folder.id); try { - IMAPMessage imessage = (IMAPMessage) ifolder.getMessageByUID(uid); + MimeMessage imessage = (MimeMessage) ifolder.getMessageByUID(uid); if (imessage == null) throw new MessageRemovedException(); @@ -762,7 +764,7 @@ class Core { if (download && message != null) downloadMessage(context, folder, ifolder, imessage, message.id, state); } finally { - imessage.invalidateHeaders(); + ((IMAPMessage) imessage).invalidateHeaders(); } } catch (MessageRemovedException ex) { Log.i(ex); @@ -1641,7 +1643,7 @@ class Core { EntityMessage message = synchronizeMessage( context, account, folder, - ifolder, (IMAPMessage) isub[j], + ifolder, (MimeMessage) isub[j], false, download, rules, state); ids[from + j] = message.id; @@ -1706,7 +1708,7 @@ class Core { downloadMessage( context, folder, ifolder, - (IMAPMessage) isub[j], ids[from + j], state); + (MimeMessage) isub[j], ids[from + j], state); } catch (FolderClosedException ex) { throw ex; } catch (Throwable ex) { @@ -1748,11 +1750,51 @@ class Core { static EntityMessage synchronizeMessage( Context context, EntityAccount account, EntityFolder folder, - IMAPFolder ifolder, IMAPMessage imessage, + IMAPFolder ifolder, MimeMessage imessage, boolean browsed, boolean download, List rules, State state) throws MessagingException, IOException { + long uid = ifolder.getUID(imessage); + try { + return _synchronizeMessage(context, account, folder, uid, imessage, browsed, download, rules, state); + } catch (MessagingException ex) { + // https://javaee.github.io/javamail/FAQ#imapserverbug + if (MessageHelper.retryRaw(ex)) try { + Log.w(folder.name + " " + ex.getMessage()); + + Log.i(folder.name + " fetching raw message uid=" + uid); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + imessage.writeTo(bos); + bos.close(); + + Properties properties = MessageHelper.getSessionProperties(); + Session isession = Session.getInstance(properties, null); + + Log.i(folder.name + " decoding again uid=" + uid); + ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); + imessage = new MimeMessage(isession, bis); + bis.close(); + + Log.i(folder.name + " synchronizing again uid=" + uid); + return _synchronizeMessage(context, account, folder, uid, imessage, browsed, download, rules, state); + } catch (MessagingException ex1) { + if (MessageHelper.retryRaw(ex1)) + Log.e(ex1); + throw ex1; + } + + throw ex; + } + } + + static EntityMessage _synchronizeMessage( + Context context, + EntityAccount account, EntityFolder folder, + long uid, MimeMessage imessage, + boolean browsed, boolean download, + List rules, State state) throws MessagingException, IOException { + if (imessage.isExpunged()) { Log.i(folder.name + " expunged uid=" + uid); throw new MessageRemovedException("Expunged"); @@ -2187,7 +2229,7 @@ class Core { static void downloadMessage( Context context, EntityFolder folder, IMAPFolder ifolder, - IMAPMessage imessage, long id, State state) throws MessagingException, IOException { + MimeMessage imessage, long id, State state) throws MessagingException, IOException { if (state.getNetworkState().isRoaming()) return; diff --git a/app/src/main/java/eu/faircode/email/MessageHelper.java b/app/src/main/java/eu/faircode/email/MessageHelper.java index 7e14d5310e..41757daa2d 100644 --- a/app/src/main/java/eu/faircode/email/MessageHelper.java +++ b/app/src/main/java/eu/faircode/email/MessageHelper.java @@ -1106,31 +1106,13 @@ public class MessageHelper { EntityAttachment attachment; } - MessageParts getMessageParts() throws IOException, FolderClosedException { + MessageParts getMessageParts() throws IOException, MessagingException { MessageParts parts = new MessageParts(); - - MimeMessage cmessage = imessage; - try { - // Load body structure - cmessage.getContentID(); - } catch (MessagingException ex) { - // https://javaee.github.io/javamail/FAQ#imapserverbug - if ("Unable to load BODYSTRUCTURE".equals(ex.getMessage())) { - Log.w(ex); - parts.warnings.add(Helper.formatThrowable(ex, false)); - try { - cmessage = new MimeMessage(imessage); - } catch (MessagingException ignored) { - } - } - } - - getMessageParts(cmessage, parts, false); - + getMessageParts(imessage, parts, false); return parts; } - private void getMessageParts(Part part, MessageParts parts, boolean pgp) throws IOException, FolderClosedException { + private void getMessageParts(Part part, MessageParts parts, boolean pgp) throws IOException, MessagingException { try { if (BuildConfig.DEBUG) Log.i("Part class=" + part.getClass() + " type=" + part.getContentType()); @@ -1272,11 +1254,18 @@ public class MessageHelper { } catch (FolderClosedException ex) { throw ex; } catch (MessagingException ex) { + if (retryRaw(ex)) + throw ex; Log.w(ex); parts.warnings.add(Helper.formatThrowable(ex, false)); } } + static boolean retryRaw(MessagingException ex) { + return ("Failed to load IMAP envelope".equals(ex.getMessage()) || + "Unable to load BODYSTRUCTURE".equals(ex.getMessage())); + } + static boolean equal(Address[] a1, Address[] a2) { if (a1 == null && a2 == null) return true;