Continue after multipart error

pull/207/head
M66B 3 years ago
parent e1e268c389
commit 46a9127785

@ -3728,24 +3728,6 @@ class Core {
IMAPStore istore, IMAPFolder ifolder, MimeMessage imessage, IMAPStore istore, IMAPFolder ifolder, MimeMessage imessage,
boolean browsed, boolean download, boolean browsed, boolean download,
List<EntityRule> rules, State state, SyncStats stats) throws MessagingException, IOException { List<EntityRule> rules, State state, SyncStats stats) throws MessagingException, IOException {
try {
return _synchronizeMessage(context, account, folder,
istore, ifolder, imessage,
browsed, download, rules, state, stats);
} catch (MessageHelper.MessagingStructureException ex) {
Log.e(ex);
long uid = ifolder.getUID(imessage);
EntityOperation.queue(context, folder, EntityOperation.FETCH, uid);
return null;
}
}
private static EntityMessage _synchronizeMessage(
Context context,
EntityAccount account, EntityFolder folder,
IMAPStore istore, IMAPFolder ifolder, MimeMessage imessage,
boolean browsed, boolean download,
List<EntityRule> rules, State state, SyncStats stats) throws MessagingException, IOException {
DB db = DB.getInstance(context); DB db = DB.getInstance(context);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean download_headers = prefs.getBoolean("download_headers", false); boolean download_headers = prefs.getBoolean("download_headers", false);

@ -3806,8 +3806,11 @@ public class MessageHelper {
break; break;
} }
} }
} else } else {
throw new MessagingStructureException(content, "multipart/mixed"); String msg = "Expected multipart/mixed got " + content.getClass().getName();
Log.e(msg);
parts.warnings.add(msg);
}
} }
if (part.isMimeType("multipart/signed")) { if (part.isMimeType("multipart/signed")) {
@ -3851,8 +3854,11 @@ public class MessageHelper {
sb.append(' ').append(i).append('=').append(multipart.getBodyPart(i).getContentType()); sb.append(' ').append(i).append('=').append(multipart.getBodyPart(i).getContentType());
Log.e(sb.toString()); Log.e(sb.toString());
} }
} else } else {
throw new MessagingStructureException(content, "multipart/signed"); String msg = "Expected multipart/signed got " + content.getClass().getName();
Log.e(msg);
parts.warnings.add(msg);
}
} else } else
Log.e(ct.toString()); Log.e(ct.toString());
} else if (part.isMimeType("multipart/encrypted")) { } else if (part.isMimeType("multipart/encrypted")) {
@ -3873,8 +3879,12 @@ public class MessageHelper {
sb.append(' ').append(i).append('=').append(multipart.getBodyPart(i).getContentType()); sb.append(' ').append(i).append('=').append(multipart.getBodyPart(i).getContentType());
Log.e(sb.toString()); Log.e(sb.toString());
} }
} else } else {
throw new MessagingStructureException(content, "multipart/encrypted"); String msg = "Expected multipart/encrypted got " + content.getClass().getName();
Log.e(msg);
parts.warnings.add(msg);
}
} else } else
Log.e(ct.toString()); Log.e(ct.toString());
} else if (part.isMimeType("application/pkcs7-mime") || } else if (part.isMimeType("application/pkcs7-mime") ||
@ -3954,145 +3964,148 @@ public class MessageHelper {
if (part.isMimeType("multipart/*")) { if (part.isMimeType("multipart/*")) {
Multipart multipart; Multipart multipart;
Object content = part.getContent(); // Should always be Multipart Object content = part.getContent(); // Should always be Multipart
if (content instanceof Multipart) if (content instanceof Multipart) {
multipart = (Multipart) part.getContent(); multipart = (Multipart) part.getContent();
else int count = multipart.getCount();
throw new MessagingStructureException(content, "multipart/*"); for (int i = 0; i < count; i++)
try {
BodyPart child = multipart.getBodyPart(i);
getMessageParts(part, child, parts, encrypt);
} catch (ParseException ex) {
// Nested body: try to continue
// ParseException: In parameter list boundary="...">, expected parameter name, got ";"
Log.w(ex);
parts.warnings.add(Log.formatThrowable(ex, false));
}
return;
} else {
String msg = "Expected multipart/* got " + content.getClass().getName();
Log.e(msg);
parts.warnings.add(msg);
}
}
int count = multipart.getCount(); // https://www.iana.org/assignments/cont-disp/cont-disp.xhtml
for (int i = 0; i < count; i++) String disposition;
try { try {
BodyPart child = multipart.getBodyPart(i); // From the body structure
getMessageParts(part, child, parts, encrypt); disposition = part.getDisposition();
} catch (ParseException ex) { if (disposition != null)
// Nested body: try to continue disposition = disposition.toLowerCase(Locale.ROOT);
// ParseException: In parameter list boundary="...">, expected parameter name, got ";" } catch (MessagingException ex) {
Log.w(ex); Log.w(ex);
parts.warnings.add(Log.formatThrowable(ex, false)); parts.warnings.add(Log.formatThrowable(ex, false));
disposition = null;
}
String filename;
try {
// From the body structure:
// 1. disposition filename
// 2. content type name
filename = part.getFileName(); // IMAPBodyPart/BODYSTRUCTURE
if (filename != null) {
// https://tools.ietf.org/html/rfc2231
// http://kb.mozillazine.org/Attachments_renamed
// https://blog.nodemailer.com/2017/01/27/the-mess-that-is-attachment-filenames/
int q1 = filename.indexOf('\'');
int q2 = filename.indexOf('\'', q1 + 1);
if (q1 >= 0 && q2 > 0) {
try {
String charset = filename.substring(0, q1);
String language = filename.substring(q1 + 1, q2);
String name = filename.substring(q2 + 1)
.replace("+", "%2B");
if (!TextUtils.isEmpty(charset))
filename = URLDecoder.decode(name, charset);
} catch (Throwable ex) {
Log.e(ex);
}
} }
} else {
// https://www.iana.org/assignments/cont-disp/cont-disp.xhtml filename = decodeMime(filename);
String disposition;
try {
// From the body structure
disposition = part.getDisposition();
if (disposition != null)
disposition = disposition.toLowerCase(Locale.ROOT);
} catch (MessagingException ex) {
Log.w(ex);
parts.warnings.add(Log.formatThrowable(ex, false));
disposition = null;
} }
} catch (MessagingException ex) {
Log.w(ex);
parts.warnings.add(Log.formatThrowable(ex, false));
filename = null;
}
String filename; ContentType contentType;
try { try {
// From the body structure: // From the body structure
// 1. disposition filename contentType = new ContentType(part.getContentType());
// 2. content type name } catch (ParseException ex) {
filename = part.getFileName(); // IMAPBodyPart/BODYSTRUCTURE if (part instanceof MimeMessage)
if (filename != null) { Log.w("MimeMessage content type=" + ex.getMessage());
// https://tools.ietf.org/html/rfc2231 else
// http://kb.mozillazine.org/Attachments_renamed Log.w(ex);
// https://blog.nodemailer.com/2017/01/27/the-mess-that-is-attachment-filenames/ contentType = new ContentType(Helper.guessMimeType(filename));
int q1 = filename.indexOf('\''); }
int q2 = filename.indexOf('\'', q1 + 1);
if (q1 >= 0 && q2 > 0) {
try {
String charset = filename.substring(0, q1);
String language = filename.substring(q1 + 1, q2);
String name = filename.substring(q2 + 1)
.replace("+", "%2B");
if (!TextUtils.isEmpty(charset)) String ct = contentType.getBaseType();
filename = URLDecoder.decode(name, charset); if (("text/plain".equalsIgnoreCase(ct) || "text/html".equalsIgnoreCase(ct)) &&
} catch (Throwable ex) { !Part.ATTACHMENT.equalsIgnoreCase(disposition) && TextUtils.isEmpty(filename)) {
Log.e(ex); parts.text.add(new PartHolder(part, contentType));
} } else {
} if (Report.isDeliveryStatus(ct) || Report.isDispositionNotification(ct))
parts.extra.add(new PartHolder(part, contentType));
AttachmentPart apart = new AttachmentPart();
apart.disposition = disposition;
apart.filename = filename;
apart.encrypt = encrypt;
apart.part = part;
filename = decodeMime(filename); String cid = null;
try {
if (apart.part instanceof IMAPBodyPart)
cid = ((IMAPBodyPart) apart.part).getContentID();
if (TextUtils.isEmpty(cid)) {
String[] cids = apart.part.getHeader("Content-ID");
if (cids != null && cids.length > 0)
cid = MimeUtility.unfold(cids[0]);
} }
} catch (MessagingException ex) { } catch (MessagingException ex) {
Log.w(ex); Log.w(ex);
parts.warnings.add(Log.formatThrowable(ex, false)); if (!"Failed to fetch headers".equals(ex.getMessage()))
filename = null; parts.warnings.add(Log.formatThrowable(ex, false));
}
ContentType contentType;
try {
// From the body structure
contentType = new ContentType(part.getContentType());
} catch (ParseException ex) {
if (part instanceof MimeMessage)
Log.w("MimeMessage content type=" + ex.getMessage());
else
Log.w(ex);
contentType = new ContentType(Helper.guessMimeType(filename));
} }
String ct = contentType.getBaseType(); Boolean related = null;
if (("text/plain".equalsIgnoreCase(ct) || "text/html".equalsIgnoreCase(ct)) && if (parent != null)
!Part.ATTACHMENT.equalsIgnoreCase(disposition) && TextUtils.isEmpty(filename)) {
parts.text.add(new PartHolder(part, contentType));
} else {
if (Report.isDeliveryStatus(ct) || Report.isDispositionNotification(ct))
parts.extra.add(new PartHolder(part, contentType));
AttachmentPart apart = new AttachmentPart();
apart.disposition = disposition;
apart.filename = filename;
apart.encrypt = encrypt;
apart.part = part;
String cid = null;
try { try {
if (apart.part instanceof IMAPBodyPart) related = parent.isMimeType("multipart/related");
cid = ((IMAPBodyPart) apart.part).getContentID();
if (TextUtils.isEmpty(cid)) {
String[] cids = apart.part.getHeader("Content-ID");
if (cids != null && cids.length > 0)
cid = MimeUtility.unfold(cids[0]);
}
} catch (MessagingException ex) { } catch (MessagingException ex) {
Log.w(ex); Log.w(ex);
if (!"Failed to fetch headers".equals(ex.getMessage()))
parts.warnings.add(Log.formatThrowable(ex, false));
} }
Boolean related = null; apart.attachment = new EntityAttachment();
if (parent != null) apart.attachment.disposition = apart.disposition;
try { apart.attachment.name = apart.filename;
related = parent.isMimeType("multipart/related"); apart.attachment.type = contentType.getBaseType().toLowerCase(Locale.ROOT);
} catch (MessagingException ex) { apart.attachment.size = (long) apart.part.getSize();
Log.w(ex); apart.attachment.cid = cid;
} apart.attachment.related = related;
apart.attachment.encryption = apart.encrypt;
apart.attachment = new EntityAttachment();
apart.attachment.disposition = apart.disposition; if ("text/calendar".equalsIgnoreCase(apart.attachment.type) &&
apart.attachment.name = apart.filename; TextUtils.isEmpty(apart.attachment.name))
apart.attachment.type = contentType.getBaseType().toLowerCase(Locale.ROOT); apart.attachment.name = "invite.ics";
apart.attachment.size = (long) apart.part.getSize();
apart.attachment.cid = cid; if (apart.attachment.size <= 0)
apart.attachment.related = related; apart.attachment.size = null;
apart.attachment.encryption = apart.encrypt;
// https://tools.ietf.org/html/rfc2392
if ("text/calendar".equalsIgnoreCase(apart.attachment.type) && if (apart.attachment.cid != null) {
TextUtils.isEmpty(apart.attachment.name)) if (!apart.attachment.cid.startsWith("<"))
apart.attachment.name = "invite.ics"; apart.attachment.cid = "<" + apart.attachment.cid;
if (!apart.attachment.cid.endsWith(">"))
if (apart.attachment.size <= 0) apart.attachment.cid += ">";
apart.attachment.size = null;
// https://tools.ietf.org/html/rfc2392
if (apart.attachment.cid != null) {
if (!apart.attachment.cid.startsWith("<"))
apart.attachment.cid = "<" + apart.attachment.cid;
if (!apart.attachment.cid.endsWith(">"))
apart.attachment.cid += ">";
}
parts.attachments.add(apart);
} }
parts.attachments.add(apart);
} }
} catch (FolderClosedException ex) { } catch (FolderClosedException ex) {
throw ex; throw ex;
@ -4435,24 +4448,6 @@ public class MessageHelper {
return values; return values;
} }
static class MessagingStructureException extends MessagingException {
private String className;
private String expected;
MessagingStructureException(Object content, String expected) {
super();
if (content != null)
this.className = content.getClass().getName();
this.expected = expected;
}
@Nullable
@Override
public String getMessage() {
return className + " expected: " + expected;
}
}
static class Report { static class Report {
String type; String type;
String reporter; String reporter;

Loading…
Cancel
Save