From 9ed65e34adccc34caaa1cee374a2de8554723945 Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Tue, 12 May 2015 22:37:58 -0400 Subject: [PATCH] JSONify mail parts --- .../UIxMailPartAlternativeViewer.m | 103 ++++++++---------- UI/MailPartViewers/UIxMailPartMixedViewer.h | 14 ++- UI/MailPartViewers/UIxMailPartMixedViewer.m | 36 +++++- UI/MailPartViewers/UIxMailPartSignedViewer.m | 37 ++++++- UI/MailPartViewers/UIxMailPartViewer.h | 4 +- UI/MailPartViewers/UIxMailPartViewer.m | 21 +++- UI/MailerUI/UIxMailView.m | 20 +++- UI/Templates/MailerUI/UIxMailViewTemplate.wox | 6 +- .../js/Mailer/Message.service.js | 77 ++++++++----- 9 files changed, 215 insertions(+), 103 deletions(-) diff --git a/UI/MailPartViewers/UIxMailPartAlternativeViewer.m b/UI/MailPartViewers/UIxMailPartAlternativeViewer.m index 65d30b76a..68c402e58 100644 --- a/UI/MailPartViewers/UIxMailPartAlternativeViewer.m +++ b/UI/MailPartViewers/UIxMailPartAlternativeViewer.m @@ -1,5 +1,5 @@ /* - Copyright (C) 2007-2009 Inverse inc. + Copyright (C) 2007-2015 Inverse inc. Copyright (C) 2004 SKYRIX Software AG This file is part of SOGo. @@ -15,11 +15,12 @@ License for more details. You should have received a copy of the GNU Lesser General Public - License along with OGo; see the file COPYING. If not, write to the + License along with SOGo; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#import #import #import @@ -27,24 +28,21 @@ #import #import "UIxMailPartViewer.h" +#import "UIxMailPartMixedViewer.h" #import "UIxMailRenderingContext.h" /* UIxMailPartAlternativeViewer - + Display multipart/alternative parts. Most common application is for messages which contain text/html and text/plain, but it is also used in other contexts, eg in OGo appointment mails. - + TODO: We might want to give the user the possibility to access all parts of the alternative set. */ -@interface UIxMailPartAlternativeViewer : UIxMailPartViewer -{ - id childInfo; - NSUInteger childIndex; -} +@interface UIxMailPartAlternativeViewer : UIxMailPartMixedViewer @end @@ -52,19 +50,9 @@ - (void) dealloc { - [childInfo release]; [super dealloc]; } -/* caches */ - -- (void) resetBodyInfoCaches -{ - [childInfo release]; childInfo = nil; - childIndex = 0; - [super resetBodyInfoCaches]; -} - /* part selection */ - (NSArray *) childPartTypes @@ -76,7 +64,7 @@ childParts = [[self bodyInfo] valueForKey:@"parts"]; count = [childParts count]; types = [NSMutableArray arrayWithCapacity:count]; - + for (i = 0; i < count; i++) { NSString *mt, *st; @@ -140,7 +128,7 @@ [childInfo release]; childInfo = nil; childIndex = 0; - + idx = [self _selectPartIndexFromTypes: [self childPartTypes]]; if (idx == NSNotFound) { @@ -150,42 +138,7 @@ } childIndex = idx + 1; - childInfo = - [[[[self bodyInfo] valueForKey:@"parts"] objectAtIndex:idx] retain]; -} - -/* accessors */ - -- (id) childInfo -{ - if (!childInfo) - [self selectChildInfo]; - - return childInfo; -} - -- (NSUInteger) childIndex -{ - if (!childIndex) - [self selectChildInfo]; - - return childIndex - 1; -} - -- (NSString *) childPartName -{ - return [NSString stringWithFormat: @"%u", - (unsigned int) ([self childIndex] + 1)]; -} - -- (id) childPartPath -{ - NSArray *pp; - - pp = [self partPath]; - return [pp count] > 0 - ? (id)[pp arrayByAddingObject:[self childPartName]] - : (id)[NSArray arrayWithObject:[self childPartName]]; + childInfo = [[[[self bodyInfo] valueForKey:@"parts"] objectAtIndex:idx] retain]; } /* nested viewers */ @@ -193,9 +146,43 @@ - (id) contentViewerComponent { id info; - + info = [self childInfo]; return [[[self context] mailRenderingContext] viewerForBodyInfo:info]; } +- (id) renderedPart { + id info, viewer; + NSArray *parts; + NSMutableArray *renderedParts; + NSString *preferredType; + NSUInteger i, max; + + parts = [[self bodyInfo] objectForKey: @"parts"]; + max = [parts count]; + renderedParts = [NSMutableArray arrayWithCapacity: max]; + for (i = 0; i < max; i++) + { + [self setChildIndex: i]; + [self setChildInfo: [parts objectAtIndex: i]]; + info = [self childInfo]; + viewer = [[[self context] mailRenderingContext] viewerForBodyInfo: info]; + [viewer setBodyInfo: info]; + [viewer setPartPath: [self childPartPath]]; + [renderedParts addObject: [viewer renderedPart]]; + } + + // Identity a preferred type + [self selectChildInfo]; + preferredType = [NSString stringWithFormat: @"%@/%@", + [[self childInfo] objectForKey: @"type"], + [[self childInfo] objectForKey: @"subtype"]]; + + return [NSDictionary dictionaryWithObjectsAndKeys: + [self className], @"type", + preferredType, @"preferredPart", + renderedParts, @"content", + nil]; +} + @end /* UIxMailPartAlternativeViewer */ diff --git a/UI/MailPartViewers/UIxMailPartMixedViewer.h b/UI/MailPartViewers/UIxMailPartMixedViewer.h index c5b97dcc6..3c49cd64c 100644 --- a/UI/MailPartViewers/UIxMailPartMixedViewer.h +++ b/UI/MailPartViewers/UIxMailPartMixedViewer.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2007-2009 Inverse inc. + Copyright (C) 2007-2015 Inverse inc. Copyright (C) 2004-2005 SKYRIX Software AG This file is part of SOGo. @@ -15,7 +15,7 @@ License for more details. You should have received a copy of the GNU Lesser General Public - License along with OGo; see the file COPYING. If not, write to the + License along with SOGo; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ @@ -27,10 +27,16 @@ @interface UIxMailPartMixedViewer : UIxMailPartViewer { - id childInfo; - unsigned int childIndex; + id childInfo; + NSUInteger childIndex; } +- (void) setChildInfo: (id) _info; +- (id) childInfo; +- (void) setChildIndex: (unsigned int) _index; +- (id) childPartPath; + + @end #endif /* UIXMAILPARTMIXEDVIEWER_H */ diff --git a/UI/MailPartViewers/UIxMailPartMixedViewer.m b/UI/MailPartViewers/UIxMailPartMixedViewer.m index 39544c0d8..6a36c2457 100644 --- a/UI/MailPartViewers/UIxMailPartMixedViewer.m +++ b/UI/MailPartViewers/UIxMailPartMixedViewer.m @@ -1,5 +1,5 @@ /* - Copyright (C) 2007-2009 Inverse inc. + Copyright (C) 2007-2015 Inverse inc. Copyright (C) 2004-2005 SKYRIX Software AG This file is part of SOGo. @@ -20,6 +20,8 @@ 02111-1307, USA. */ +#import + #import #import "UIxMailRenderingContext.h" @@ -48,14 +50,16 @@ return self->childInfo; } -- (void)setChildIndex:(unsigned int)_index { +- (void) setChildIndex: (NSUInteger) _index { self->childIndex = _index; } -- (unsigned int)childIndex { +- (NSUInteger) childIndex { return self->childIndex; } - (NSString *)childPartName { + return [NSString stringWithFormat: @"%u", + (unsigned int) ([self childIndex] + 1)]; char buf[8]; sprintf(buf, "%d", [self childIndex] + 1); return [NSString stringWithCString:buf]; @@ -79,4 +83,30 @@ return [[[self context] mailRenderingContext] viewerForBodyInfo:info]; } +- (id) renderedPart { + id info, viewer; + NSArray *parts; + NSMutableArray *renderedParts; + NSUInteger i, max; + + parts = [[self bodyInfo] objectForKey: @"parts"]; + max = [parts count]; + renderedParts = [NSMutableArray arrayWithCapacity: max]; + for (i = 0; i < max; i++) + { + [self setChildIndex: i]; + [self setChildInfo: [parts objectAtIndex: i]]; + info = [self childInfo]; + viewer = [[[self context] mailRenderingContext] viewerForBodyInfo: info]; + [viewer setBodyInfo: info]; + [viewer setPartPath: [self childPartPath]]; + [renderedParts addObject: [viewer renderedPart]]; + } + + return [NSDictionary dictionaryWithObjectsAndKeys: + [self className], @"type", + renderedParts, @"content", + nil]; +} + @end /* UIxMailPartMixedViewer */ diff --git a/UI/MailPartViewers/UIxMailPartSignedViewer.m b/UI/MailPartViewers/UIxMailPartSignedViewer.m index 16692657a..d78fd059d 100644 --- a/UI/MailPartViewers/UIxMailPartSignedViewer.m +++ b/UI/MailPartViewers/UIxMailPartSignedViewer.m @@ -1,9 +1,6 @@ /* UIxMailPartSignedViewer.m - this file is part of SOGo * - * Copyright (C) 2009 Inverse inc. - * - * Author: Wolfgang Sourdeau - * Ludovic Marcotte + * Copyright (C) 2009-2015 Inverse inc. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,9 +27,12 @@ #endif #import +#import +#import #import #import +#import "UIxMailRenderingContext.h" #import "UIxMailPartSignedViewer.h" @implementation UIxMailPartSignedViewer : UIxMailPartMixedViewer @@ -211,4 +211,33 @@ } #endif +- (id) renderedPart { + id info, viewer; + NSArray *parts; + NSMutableArray *renderedParts; + NSUInteger i, max; + + parts = [[self bodyInfo] objectForKey: @"parts"]; + max = [parts count]; + renderedParts = [NSMutableArray arrayWithCapacity: max]; + for (i = 0; i < max; i++) + { + [self setChildIndex: i]; + [self setChildInfo: [parts objectAtIndex: i]]; + info = [self childInfo]; + viewer = [[[self context] mailRenderingContext] viewerForBodyInfo:info]; + [viewer setBodyInfo: info]; + [viewer setPartPath: [self childPartPath]]; + [renderedParts addObject: [viewer renderedPart]]; + } + + return [NSDictionary dictionaryWithObjectsAndKeys: + [self className], @"type", + @"supports-smime", [NSNumber numberWithBool: [self supportsSMIME]], + @"valid", [NSNumber numberWithBool: [self validSignature]], + @"error", [self validationMessage], + renderedParts, @"content", + nil]; +} + @end diff --git a/UI/MailPartViewers/UIxMailPartViewer.h b/UI/MailPartViewers/UIxMailPartViewer.h index ce8f35f67..e60675e6e 100644 --- a/UI/MailPartViewers/UIxMailPartViewer.h +++ b/UI/MailPartViewers/UIxMailPartViewer.h @@ -1,4 +1,5 @@ /* + Copyright (C) 2015 Inverse inc. Copyright (C) 2004-2005 SKYRIX Software AG This file is part of OpenGroupware.org. @@ -14,7 +15,7 @@ License for more details. You should have received a copy of the GNU Lesser General Public - License along with OGo; see the file COPYING. If not, write to the + License along with SOGo; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ @@ -63,6 +64,7 @@ - (id)bodyInfo; - (SOGoMailBodyPart *) clientPart; +- (id) renderedPart; - (NSData *)flatContent; - (NSData *)decodedFlatContent; diff --git a/UI/MailPartViewers/UIxMailPartViewer.m b/UI/MailPartViewers/UIxMailPartViewer.m index c973acbb6..a34bcb2ab 100644 --- a/UI/MailPartViewers/UIxMailPartViewer.m +++ b/UI/MailPartViewers/UIxMailPartViewer.m @@ -1,5 +1,5 @@ /* - Copyright (C) 2007-2013 Inverse inc. + Copyright (C) 2007-2015 Inverse inc. Copyright (C) 2004-2005 SKYRIX Software AG This file is part of SOGo. @@ -15,7 +15,7 @@ License for more details. You should have received a copy of the GNU Lesser General Public - License along with OGo; see the file COPYING. If not, write to the + License along with SOGo; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ @@ -31,6 +31,8 @@ #import #import +#import + #import #import #import @@ -141,6 +143,21 @@ return currentObject; } +- (id) renderedPart +{ + NSString *type; + + type = [NSString stringWithFormat: @"%@/%@", + [bodyInfo objectForKey: @"type"], + [bodyInfo objectForKey: @"subtype"]]; + + return [NSDictionary dictionaryWithObjectsAndKeys: + [self className], @"type", + type, @"contentType", + [[self generateResponse] contentAsString], @"content", + nil]; +} + - (NSData *) content { return [[self clientObject] fetchBLOB]; diff --git a/UI/MailerUI/UIxMailView.m b/UI/MailerUI/UIxMailView.m index 0c02028d0..ba297b53c 100644 --- a/UI/MailerUI/UIxMailView.m +++ b/UI/MailerUI/UIxMailView.m @@ -1,5 +1,5 @@ /* - Copyright (C) 2005-2014 Inverse inc. + Copyright (C) 2005-2015 Inverse inc. This file is part of SOGo. @@ -215,11 +215,14 @@ static NSString *mailETag = nil; { // TODO: I would prefer to flatten the body structure prior rendering, // using some delegate to decide which parts to select for alternative. - id info; + id info, viewer; info = [[self clientObject] bodyStructure]; - return [[context mailRenderingContext] viewerForBodyInfo:info]; + viewer = [[context mailRenderingContext] viewerForBodyInfo: info]; + [viewer setBodyInfo: info]; + + return viewer; } /* actions */ @@ -232,10 +235,15 @@ static NSString *mailETag = nil; NSArray *addresses; SOGoMailObject *co; UIxEnvelopeAddressFormatter *addressFormatter; + UIxMailRenderingContext *mctx; co = [self clientObject]; addressFormatter = [context mailEnvelopeAddressFormatter]; + mctx = [[UIxMailRenderingContext alloc] initWithViewer: self context: context]; + [context pushMailRenderingContext: mctx]; + [mctx release]; + /* check etag to see whether we really must rerender */ /* Note: There is one thing which *can* change for an existing message, @@ -280,7 +288,7 @@ static NSString *mailETag = nil; [self attachmentAttrs], @"attachmentAttrs", [self shouldAskReceipt], @"shouldAskReceipt", [NSNumber numberWithBool: [self mailIsDraft]], @"isDraft", - [[self generateResponse] contentAsString], @"content", + [[self contentViewerComponent] renderedPart], @"parts", nil]; if ([self messageSubject]) [data setObject: [self messageSubject] forKey: @"subject"]; @@ -298,6 +306,10 @@ static NSString *mailETag = nil; response = [self responseWithStatus: 200 andString: [data jsonRepresentation]]; + [response setHeader: mailETag forKey: @"etag"]; + + [[context popMailRenderingContext] reset]; + return response; } diff --git a/UI/Templates/MailerUI/UIxMailViewTemplate.wox b/UI/Templates/MailerUI/UIxMailViewTemplate.wox index ba1fc010a..630283369 100644 --- a/UI/Templates/MailerUI/UIxMailViewTemplate.wox +++ b/UI/Templates/MailerUI/UIxMailViewTemplate.wox @@ -107,8 +107,10 @@
-
+
+
+
diff --git a/UI/WebServerResources/js/Mailer/Message.service.js b/UI/WebServerResources/js/Mailer/Message.service.js index 0c753c20f..4aca0c30b 100644 --- a/UI/WebServerResources/js/Mailer/Message.service.js +++ b/UI/WebServerResources/js/Mailer/Message.service.js @@ -163,31 +163,59 @@ * @returns the HTML representation of the body */ Message.prototype.$content = function() { - var _this = this; - - if (this.$loadUnsafeContent) { - if (angular.isUndefined(this.unsafeContent)) { - this.unsafeContent = document.createElement('div'); - this.unsafeContent.innerHTML = this.content; - angular.forEach(['src', 'data', 'classid', 'background', 'style'], function(suffix) { - var elements = _this.unsafeContent.querySelectorAll('[unsafe-' + suffix + ']'), - element, - value, - i; - for (i = 0; i < elements.length; i++) { - element = angular.element(elements[i]); - value = element.attr('unsafe-' + suffix); - element.attr(suffix, value); - element.removeAttr('unsafe-' + suffix); + var _this = this, + parts = [], + _visit = function(part) { + if (part.type == "UIxMailPartAlternativeViewer") { + _visit(_.find(part.content, function(alternatePart) { + return part.preferredPart == alternatePart.contentType; + })); } - }); - } - this.$hasUnsafeContent = false; - return Message.$sce.trustAs('html', this.unsafeContent.innerHTML); - } - else { - return Message.$sce.trustAs('html', this.content); - } + else if (angular.isArray(part.content)) { + _.each(part.content, function(mixedPart) { + _visit(mixedPart); + }); + } + else { + if (angular.isUndefined(part.safeContent)) { + // Keep a copy of the original content + part.safeContent = part.content; + _this.$hasUnsafeContent = (part.safeContent.indexOf(' unsafe-') > -1); + } + if (part.type == "UIxMailPartHTMLViewer") { + if (_this.$loadUnsafeContent) { + if (angular.isUndefined(part.unsafeContent)) { + part.unsafeContent = document.createElement('div'); + part.unsafeContent.innerHTML = part.safeContent; + angular.forEach(['src', 'data', 'classid', 'background', 'style'], function(suffix) { + var elements = part.unsafeContent.querySelectorAll('[unsafe-' + suffix + ']'), + element, + value, + i; + for (i = 0; i < elements.length; i++) { + element = angular.element(elements[i]); + value = element.attr('unsafe-' + suffix); + element.attr(suffix, value); + element.removeAttr('unsafe-' + suffix); + } + }); + } + part.content = Message.$sce.trustAs('html', part.unsafeContent.innerHTML); + } + else { + part.content = Message.$sce.trustAs('html', part.safeContent); + } + parts.push(part); + } + else { + part.content = Message.$sce.trustAs('html', part.safeContent); + parts.push(part); + } + } + }; + _visit(this.parts); + + return parts; }; /** @@ -391,7 +419,6 @@ angular.extend(_this, data); _this.id = _this.$absolutePath(); _this.$formatFullAddresses(); - _this.$hasUnsafeContent = (_this.content.indexOf(' unsafe-') > -1); _this.$loadUnsafeContent = false; deferred.resolve(_this); });