From f56910db1efe25d2ce1d36db787c010a9f2a36f9 Mon Sep 17 00:00:00 2001 From: smizrahi Date: Mon, 5 Feb 2024 10:50:07 +0100 Subject: [PATCH] fix(mail): Use text/plain fallback if an error occured while parsing html message --- .../UIxMailPartAlternativeViewer.m | 24 ++++++- UI/MailPartViewers/UIxMailPartHTMLViewer.h | 4 +- UI/MailPartViewers/UIxMailPartHTMLViewer.m | 67 +++++++++++++++++++ UI/MailPartViewers/UIxMailPartViewer.m | 22 +++++- 4 files changed, 112 insertions(+), 5 deletions(-) diff --git a/UI/MailPartViewers/UIxMailPartAlternativeViewer.m b/UI/MailPartViewers/UIxMailPartAlternativeViewer.m index 8b6a89f13..07185c8e4 100644 --- a/UI/MailPartViewers/UIxMailPartAlternativeViewer.m +++ b/UI/MailPartViewers/UIxMailPartAlternativeViewer.m @@ -179,8 +179,9 @@ id info, viewer; NSArray *parts; NSMutableArray *renderedParts; - NSString *preferredType; + NSString *preferredType, *htmlNoTags; NSUInteger i, max; + BOOL fallbackNeeded, hasTextPlain; if ([self decodedFlatContent]) parts = [[self decodedFlatContent] parts]; @@ -214,6 +215,27 @@ [[self childInfo] objectForKey: @"type"], [[self childInfo] objectForKey: @"subtype"]]; + // Check if the HTML part is good + // If no, try to fallback on text/plain + fallbackNeeded = NO; + hasTextPlain = NO; + for (i = 0 ; i < [renderedParts length] ; i++) { + if ([[[[renderedParts objectAtIndex: i] objectForKey: @"contentType"] lowercaseString] isEqualToString: @"text/html"] + && [[preferredType lowercaseString] isEqualToString: @"text/html"]) { + if ([[renderedParts objectAtIndex: i] objectForKey:@"exception"]) { + fallbackNeeded = YES; + } + } + + if ([[[[renderedParts objectAtIndex: i] objectForKey: @"contentType"] lowercaseString] isEqualToString: @"text/plain"]) { + hasTextPlain = YES; + } + } + + if (fallbackNeeded && hasTextPlain) { + preferredType = @"text/plain"; + } + return [NSDictionary dictionaryWithObjectsAndKeys: [self className], @"type", preferredType, @"preferredPart", diff --git a/UI/MailPartViewers/UIxMailPartHTMLViewer.h b/UI/MailPartViewers/UIxMailPartHTMLViewer.h index 5ba673c31..420ea75c7 100644 --- a/UI/MailPartViewers/UIxMailPartHTMLViewer.h +++ b/UI/MailPartViewers/UIxMailPartHTMLViewer.h @@ -23,9 +23,10 @@ #import "UIxMailPartViewer.h" -@interface UIxMailPartHTMLViewer : UIxMailPartViewer +@interface UIxMailPartHTMLViewer : UIxMailPartViewer { id handler; + NSException *ex; } - (NSString *) flatContentAsString; @@ -35,6 +36,7 @@ @interface UIxMailPartExternalHTMLViewer : UIxMailPartViewer { id handler; + NSException *ex; } - (NSString *) flatContentAsString; diff --git a/UI/MailPartViewers/UIxMailPartHTMLViewer.m b/UI/MailPartViewers/UIxMailPartHTMLViewer.m index b4eff9f03..a15c86522 100644 --- a/UI/MailPartViewers/UIxMailPartHTMLViewer.m +++ b/UI/MailPartViewers/UIxMailPartHTMLViewer.m @@ -750,6 +750,7 @@ _xmlCharsetForCharset (NSString *charset) if ((self = [super init])) { handler = nil; + ex = nil; } return self; @@ -758,6 +759,9 @@ _xmlCharsetForCharset (NSString *charset) - (void) dealloc { [handler release]; + if (ex) { + [ex release]; + } [super dealloc]; } @@ -782,6 +786,8 @@ _xmlCharsetForCharset (NSString *charset) xmlCharEncoding enc; + [self cleanException]; + if ([[self decodedFlatContent] isKindOfClass: [NGMimeBodyPart class]]) preparsedContent = [[[self decodedFlatContent] body] sanitizedContentUsingVoidTags: VoidTags]; else @@ -852,9 +858,37 @@ _xmlCharsetForCharset (NSString *charset) [handler setContentEncoding: enc]; [parser setContentHandler: handler]; + [parser setErrorHandler: self]; [parser parseFromSource: preparsedContent]; } +- (void)cleanException +{ + ex = nil; +} + +- (void)warning:(SaxParseException *)_exception +{ + +} + +- (void)error:(SaxParseException *)_exception +{ + +} + +- (void)fatalError:(SaxParseException *)_exception +{ + ex = [NSException exceptionWithName:[_exception name] reason: [_exception reason] userInfo: [_exception userInfo]]; + [ex retain]; +} + +- (NSException *)getException +{ + return ex; +} + + - (NSString *) cssContent { NSString *cssContent, *css; @@ -890,6 +924,7 @@ _xmlCharsetForCharset (NSString *charset) if ((self = [super init])) { handler = nil; + ex = nil; } return self; @@ -898,6 +933,9 @@ _xmlCharsetForCharset (NSString *charset) - (void) dealloc { [handler release]; + if (ex) { + [ex release]; + } [super dealloc]; } @@ -921,6 +959,8 @@ _xmlCharsetForCharset (NSString *charset) NSString *encoding; xmlCharEncoding enc; + [self cleanException]; + parser = [[SaxXMLReaderFactory standardXMLReaderFactory] createXMLReaderForMimeType: @"text/html"]; @@ -966,9 +1006,36 @@ _xmlCharsetForCharset (NSString *charset) [handler setContentEncoding: enc]; [parser setContentHandler: handler]; + [parser setErrorHandler: self]; [parser parseFromSource: preparsedContent]; } +- (void)cleanException +{ + ex = nil; +} + +- (void)warning:(SaxParseException *)_exception +{ + +} + +- (void)error:(SaxParseException *)_exception +{ + +} + +- (void)fatalError:(SaxParseException *)_exception +{ + ex = [NSException exceptionWithName:[_exception name] reason: [_exception reason] userInfo: [_exception userInfo]]; + [ex retain]; +} + +- (NSException *)getException +{ + return ex; +} + - (NSString *) filename { return [[self clientObject] filename]; diff --git a/UI/MailPartViewers/UIxMailPartViewer.m b/UI/MailPartViewers/UIxMailPartViewer.m index 13a7f89c9..7a2341c91 100644 --- a/UI/MailPartViewers/UIxMailPartViewer.m +++ b/UI/MailPartViewers/UIxMailPartViewer.m @@ -190,16 +190,27 @@ - (id) renderedPart { - NSString *type; + NSString *type, *content; + NSException *e; + NSMutableDictionary *r; + e = nil; type = [NSString stringWithFormat: @"%@/%@", [bodyInfo objectForKey: @"type"], [bodyInfo objectForKey: @"subtype"]]; + - return [NSDictionary dictionaryWithObjectsAndKeys: + + content = [[[self generateResponse] contentAsString] stringWithoutHTMLInjection: NO]; + if ([self respondsToSelector:@selector(getException)]) { + e = [self getException]; + } + + + r = [NSMutableDictionary dictionaryWithObjectsAndKeys: [self className], @"type", type, @"contentType", - [[[self generateResponse] contentAsString] stringWithoutHTMLInjection: NO], @"content", + content, @"content", [self filenameForDisplay], @"filename", [self preferredPathExtension], @"extension", [[self sizeFormatter] stringForObjectValue: [bodyInfo objectForKey: @"size"]], @"size", @@ -207,6 +218,11 @@ [self pathForDownload], @"downloadURL", [NSNumber numberWithBool:_shouldDisplayAttachment], @"shouldDisplayAttachment", nil]; + if (e) { + [r setObject: [e userInfo] forKey: @"exception"]; + } + + return r; } - (NSDictionary *) attachmentIds