diff --git a/ChangeLog b/ChangeLog index 0b6848b79..c77ec13d5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2008-08-22 Wolfgang Sourdeau + + * SoObjects/Mailer/SOGoHTMLMailBodyPart.[hm]: new class module + implementing the HTML content body parts. + + * UI/MailPartViewers/UIxMailPartHTMLViewer.m + ([UIxMailPartExternalHTMLViewer -init]): new class derived from + UIxMailPartHTMLViewer but which as as a full page wrapper. + 2008-08-22 Ludovic Marcotte * Modified SoObjects/Mailer/NSData+Mail.m diff --git a/SoObjects/Mailer/GNUmakefile b/SoObjects/Mailer/GNUmakefile index 370dece0a..88e19059e 100644 --- a/SoObjects/Mailer/GNUmakefile +++ b/SoObjects/Mailer/GNUmakefile @@ -23,6 +23,7 @@ Mailer_OBJC_FILES += \ SOGoTrashFolder.m \ \ SOGoMailBodyPart.m \ + SOGoHTMLMailBodyPart.m \ SOGoImageMailBodyPart.m \ SOGoMessageMailBodyPart.m \ SOGoCalendarMailBodyPart.m \ diff --git a/SoObjects/Mailer/SOGoHTMLMailBodyPart.m b/SoObjects/Mailer/SOGoHTMLMailBodyPart.m new file mode 100644 index 000000000..026fd1e9a --- /dev/null +++ b/SoObjects/Mailer/SOGoHTMLMailBodyPart.m @@ -0,0 +1,62 @@ +/* SOGoHTMLMailBodyPart.m - this file is part of SOGo + * + * Copyright (C) 2008 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import + +#import +#import +#import +#import + +#import + +#import "SOGoMailBodyPart.h" + +@interface SOGoHTMLMailBodyPart : SOGoMailBodyPart + +@end + +@implementation SOGoHTMLMailBodyPart + +- (id) GETAction: (id) localContext +{ + WORequest *request; + NSString *uri; + id response; + + request = [localContext request]; + if ([request isSoWebDAVRequest]) + response = [super GETAction: localContext]; + else + { + response = [localContext response]; + uri = [[request uri] composeURLWithAction: @"view" + parameters: [request formValues] + andHash: NO]; + [response setStatus: 302 /* moved */]; + [response setHeader: uri forKey: @"location"]; + } + + return response; +} + +@end diff --git a/SoObjects/Mailer/SOGoMailBodyPart.m b/SoObjects/Mailer/SOGoMailBodyPart.m index 41f14a6b2..0172df20a 100644 --- a/SoObjects/Mailer/SOGoMailBodyPart.m +++ b/SoObjects/Mailer/SOGoMailBodyPart.m @@ -353,57 +353,58 @@ static BOOL debugOn = NO; /* actions */ -- (id)GETAction:(id)_ctx { +- (id) GETAction: (WOContext *) localContext +{ NSException *error; - WOResponse *r; NSData *data; NSString *etag, *mimeType, *fileName; + id response; - if ((error = [self matchesRequestConditionInContext:_ctx]) != nil) { - // TODO: currently we fetch the body structure to get here - check this! - /* check whether the mail still exists */ - if (![[self mailObject] doesMailExist]) { - return [NSException exceptionWithHTTPStatus:404 /* Not Found */ - reason:@"mail was deleted"]; + error = [self matchesRequestConditionInContext: localContext]; + if (error) + { + response = error; /* return 304 or 416 */ } - return error; /* return 304 or 416 */ - } - - [self debugWithFormat:@"should fetch body part: %@", - [self bodyPartIdentifier]]; - - if ((data = [self fetchBLOB]) == nil) { - return [NSException exceptionWithHTTPStatus:404 /* not found */ - reason:@"did not find body part"]; - } - - [self debugWithFormat:@" fetched %d bytes: %@", [data length], - [self partInfo]]; + else + { +// [self debugWithFormat: @"should fetch body part: %@", +// [self bodyPartIdentifier]]; + data = [self fetchBLOB]; + if (data) + { +// [self debugWithFormat:@" fetched %d bytes: %@", [data length], +// [self partInfo]]; // TODO: wrong, could be encoded - r = [(WOContext *)_ctx response]; - mimeType = [self davContentType]; - if ([mimeType isEqualToString: @"application/x-xpinstall"]) - mimeType = @"application/octet-stream"; - - [r setHeader: mimeType forKey:@"content-type"]; - [r setHeader: [NSString stringWithFormat:@"%d", [data length]] - forKey: @"content-length"]; + response = [localContext response]; + mimeType = [self davContentType]; + if ([mimeType isEqualToString: @"application/x-xpinstall"]) + mimeType = @"application/octet-stream"; + + [response setHeader: mimeType forKey: @"content-type"]; + [response setHeader: [NSString stringWithFormat:@"%d", [data length]] + forKey: @"content-length"]; - if (asAttachment) - { - fileName = [self filename]; - if ([fileName length]) - [r setHeader: [NSString stringWithFormat: @"attachment; filename=%@", fileName] - forKey: @"content-disposition"]; + if (asAttachment) + { + fileName = [self filename]; + if ([fileName length]) + [response setHeader: [NSString stringWithFormat: @"attachment; filename=%@", fileName] + forKey: @"content-disposition"]; + } + + etag = [self davEntityTag]; + if (etag) + [response setHeader: etag forKey: @"etag"]; + + [response setContent: data]; + } + else + response = [NSException exceptionWithHTTPStatus: 404 /* not found */ + reason: @"did not find body part"]; } - if ((etag = [self davEntityTag]) != nil) - [r setHeader:etag forKey:@"etag"]; - - [r setContent:data]; - - return r; + return response; } /* factory */ @@ -454,6 +455,8 @@ static BOOL debugOn = NO; else if ([mimeType isEqualToString: @"text/calendar"] || [mimeType isEqualToString: @"application/ics"]) classString = @"SOGoCalendarMailBodyPart"; + else if ([mimeType isEqualToString: @"text/html"]) + classString = @"SOGoHTMLMailBodyPart"; else if ([mimeType isEqualToString: @"text/x-vcard"]) classString = @"SOGoVCardMailBodyPart"; else if ([mimeType isEqualToString: @"message/rfc822"]) diff --git a/SoObjects/Mailer/product.plist b/SoObjects/Mailer/product.plist index 6d013e679..5a470e3ee 100644 --- a/SoObjects/Mailer/product.plist +++ b/SoObjects/Mailer/product.plist @@ -58,6 +58,9 @@ SOGoMailBodyPart = { superclass = "SOGoMailBaseObject"; }; + SOGoHTMLMailBodyPart = { + superclass = "SOGoMailBodyPart"; + }; SOGoImageMailBodyPart = { superclass = "SOGoMailBodyPart"; }; diff --git a/SoObjects/SOGo/SOGoObject.m b/SoObjects/SOGo/SOGoObject.m index aed5f3d34..2e8e526fe 100644 --- a/SoObjects/SOGo/SOGoObject.m +++ b/SoObjects/SOGo/SOGoObject.m @@ -878,7 +878,7 @@ SEL SOGoSelectorForPropertySetter (NSString *property) NSException *error; id value; - request = [localContext request]; + request = [localContext request]; if ([request isSoWebDAVRequest]) { if ([self respondsToSelector: @selector (contentAsString)]) diff --git a/UI/MailPartViewers/UIxMailPartHTMLViewer.h b/UI/MailPartViewers/UIxMailPartHTMLViewer.h index 415152ded..ce90665fe 100644 --- a/UI/MailPartViewers/UIxMailPartHTMLViewer.h +++ b/UI/MailPartViewers/UIxMailPartHTMLViewer.h @@ -34,4 +34,13 @@ @end +@interface UIxMailPartExternalHTMLViewer : UIxMailPartViewer +{ + id handler; +} + +- (NSString *) flatContentAsString; + +@end + #endif /* UIXMAILPARTHTMLVIEWER_H */ diff --git a/UI/MailPartViewers/UIxMailPartHTMLViewer.m b/UI/MailPartViewers/UIxMailPartHTMLViewer.m index e9dbe7dec..78e9cddb1 100644 --- a/UI/MailPartViewers/UIxMailPartHTMLViewer.m +++ b/UI/MailPartViewers/UIxMailPartHTMLViewer.m @@ -1,6 +1,6 @@ /* UIxMailPartHTMLViewer.m - this file is part of SOGo * - * Copyright (C) 2007 Inverse groupe conseil + * Copyright (C) 2007, 2008 Inverse groupe conseil * * Author: Wolfgang Sourdeau * @@ -37,6 +37,7 @@ #include #import +#import #import "UIxMailPartHTMLViewer.h" @@ -46,6 +47,52 @@ #define showWhoWeAre() #endif +static xmlCharEncoding +_xmlCharsetForCharset (NSString *charset) +{ + struct { NSString *name; xmlCharEncoding encoding; } xmlEncodings[] = { + { @"us-ascii", XML_CHAR_ENCODING_ASCII}, + { @"utf-8", XML_CHAR_ENCODING_UTF8}, + { @"utf-16le", XML_CHAR_ENCODING_UTF16LE}, + { @"utf-16be", XML_CHAR_ENCODING_UTF16BE}, + { @"ucs-4le", XML_CHAR_ENCODING_UCS4LE}, + { @"ucs-4be", XML_CHAR_ENCODING_UCS4BE}, + { @"ebcdic", XML_CHAR_ENCODING_EBCDIC}, +// { @"iso-10646" , XML_CHAR_ENCODING_UCS4_2143}, +// { , XML_CHAR_ENCODING_UCS4_3412}, +// { @"ucs-2", XML_CHAR_ENCODING_UCS2}, + { @"iso8859_1", XML_CHAR_ENCODING_8859_1}, + { @"iso-8859-1", XML_CHAR_ENCODING_8859_1}, + { @"iso-8859-2", XML_CHAR_ENCODING_8859_2}, + { @"iso-8859-3", XML_CHAR_ENCODING_8859_3}, + { @"iso-8859-4", XML_CHAR_ENCODING_8859_4}, + { @"iso-8859-5", XML_CHAR_ENCODING_8859_5}, + { @"iso-8859-6", XML_CHAR_ENCODING_8859_6}, + { @"iso-8859-7", XML_CHAR_ENCODING_8859_7}, + { @"iso-8859-8", XML_CHAR_ENCODING_8859_8}, + { @"iso-8859-9", XML_CHAR_ENCODING_8859_9}, + { @"iso-2022-jp", XML_CHAR_ENCODING_2022_JP}, +// { @"iso-2022-jp", XML_CHAR_ENCODING_SHIFT_JIS}, + { @"euc-jp", XML_CHAR_ENCODING_EUC_JP}}; + unsigned count; + xmlCharEncoding encoding; + + encoding = XML_CHAR_ENCODING_NONE; + count = 0; + + while (encoding == XML_CHAR_ENCODING_NONE + && count < (sizeof (xmlEncodings) / sizeof (xmlEncodings[0]))) + if ([charset isEqualToString: xmlEncodings[count].name]) + encoding = xmlEncodings[count].encoding; + else + count++; + + if (encoding == XML_CHAR_ENCODING_NONE) + encoding = XML_CHAR_ENCODING_8859_1; + + return encoding; +} + @interface _UIxHTMLMailContentHandler : NSObject { NSMutableString *result; @@ -227,7 +274,7 @@ { resultPart = [NSMutableString new]; [resultPart appendFormat: @"<%@", _rawName]; - + max = [_attributes count]; for (count = 0; count < max; count++) { @@ -248,6 +295,14 @@ else skipAttribute = YES; } + else if ([name caseInsensitiveCompare: @"href"] == NSOrderedSame + || [name caseInsensitiveCompare: @"action"] == NSOrderedSame) + { + value = [_attributes valueAtIndex: count]; + skipAttribute = ([value rangeOfString: @"://"].location + == NSNotFound + && ![value hasPrefix: @"#"]); + } else value = [_attributes valueAtIndex: count]; if (!skipAttribute) @@ -258,6 +313,7 @@ [resultPart appendString: @">"]; [result appendString: resultPart]; + [resultPart release]; } } @@ -437,62 +493,16 @@ [super dealloc]; } -- (xmlCharEncoding) _xmlCharsetForCharset: (NSString *) charset -{ - struct { NSString *name; xmlCharEncoding encoding; } xmlEncodings[] = { - { @"us-ascii", XML_CHAR_ENCODING_ASCII}, - { @"utf-8", XML_CHAR_ENCODING_UTF8}, - { @"utf-16le", XML_CHAR_ENCODING_UTF16LE}, - { @"utf-16be", XML_CHAR_ENCODING_UTF16BE}, - { @"ucs-4le", XML_CHAR_ENCODING_UCS4LE}, - { @"ucs-4be", XML_CHAR_ENCODING_UCS4BE}, - { @"ebcdic", XML_CHAR_ENCODING_EBCDIC}, -// { @"iso-10646" , XML_CHAR_ENCODING_UCS4_2143}, -// { , XML_CHAR_ENCODING_UCS4_3412}, -// { @"ucs-2", XML_CHAR_ENCODING_UCS2}, - { @"iso8859_1", XML_CHAR_ENCODING_8859_1}, - { @"iso-8859-1", XML_CHAR_ENCODING_8859_1}, - { @"iso-8859-2", XML_CHAR_ENCODING_8859_2}, - { @"iso-8859-3", XML_CHAR_ENCODING_8859_3}, - { @"iso-8859-4", XML_CHAR_ENCODING_8859_4}, - { @"iso-8859-5", XML_CHAR_ENCODING_8859_5}, - { @"iso-8859-6", XML_CHAR_ENCODING_8859_6}, - { @"iso-8859-7", XML_CHAR_ENCODING_8859_7}, - { @"iso-8859-8", XML_CHAR_ENCODING_8859_8}, - { @"iso-8859-9", XML_CHAR_ENCODING_8859_9}, - { @"iso-2022-jp", XML_CHAR_ENCODING_2022_JP}, -// { @"iso-2022-jp", XML_CHAR_ENCODING_SHIFT_JIS}, - { @"euc-jp", XML_CHAR_ENCODING_EUC_JP}}; - unsigned count; - xmlCharEncoding encoding; - - encoding = XML_CHAR_ENCODING_NONE; - count = 0; - - while (encoding == XML_CHAR_ENCODING_NONE - && count < (sizeof (xmlEncodings) / sizeof (xmlEncodings[0]))) - if ([charset isEqualToString: xmlEncodings[count].name]) - encoding = xmlEncodings[count].encoding; - else - count++; - - if (encoding == XML_CHAR_ENCODING_NONE) - encoding = XML_CHAR_ENCODING_8859_1; - - return encoding; -} - - (xmlCharEncoding) _xmlCharEncoding { - NSString *charset; charset = [[bodyInfo objectForKey:@"parameterList"] objectForKey: @"charset"]; if (![charset length]) charset = @"us-ascii"; - - return [self _xmlCharsetForCharset: [charset lowercaseString]]; + + return _xmlCharsetForCharset ([charset lowercaseString]); } - (void) _parseContent @@ -541,3 +551,91 @@ } @end + +@implementation UIxMailPartExternalHTMLViewer + +- (id) init +{ + if ((self = [super init])) + { + handler = nil; + } + + return self; +} + +- (void) dealloc +{ + [handler release]; + [super dealloc]; +} + +- (xmlCharEncoding) _xmlCharEncoding +{ + NSString *charset; + + charset = [[bodyInfo objectForKey:@"parameterList"] + objectForKey: @"charset"]; + if (![charset length]) + charset = @"us-ascii"; + + return _xmlCharsetForCharset ([charset lowercaseString]); +} + +- (void) _parseContent +{ + NSObject *parser; + NSData *preparsedContent; + SOGoMailObject *mail; + SOGoMailBodyPart *part; + NSString *encoding; + + part = [self clientObject]; + mail = [part mailObject]; + + preparsedContent = [part fetchBLOB]; + parser = [[SaxXMLReaderFactory standardXMLReaderFactory] + createXMLReaderForMimeType: @"text/html"]; + encoding = [[part partInfo] valueForKey: @"encoding"]; + if (![encoding length]) + encoding = @"us-ascii"; + + handler = [_UIxHTMLMailContentHandler new]; + [handler setAttachmentIds: [mail fetchAttachmentIds]]; + [handler setContentEncoding: _xmlCharsetForCharset (encoding)]; + [parser setContentHandler: handler]; + [parser parseFromSource: preparsedContent]; +} + +- (NSString *) filename +{ + return [[self clientObject] filename]; +} + +- (NSString *) cssContent +{ + NSString *cssContent, *css; + + if (!handler) + [self _parseContent]; + + css = [handler css]; + if ([css length]) + cssContent + = [NSString stringWithFormat: @"", + [handler css]]; + else + cssContent = @""; + + return cssContent; +} + +- (NSString *) flatContentAsString +{ + if (!handler) + [self _parseContent]; + + return [handler result]; +} + +@end diff --git a/UI/MailPartViewers/product.plist b/UI/MailPartViewers/product.plist index cdf98f67b..c5c85df75 100644 --- a/UI/MailPartViewers/product.plist +++ b/UI/MailPartViewers/product.plist @@ -8,6 +8,14 @@ }; categories = { + SOGoHTMLMailBodyPart = { + methods = { + view = { + protectedBy = "View"; + pageName = "UIxMailPartExternalHTMLViewer"; + }; + }; + }; SOGoCalendarMailBodyPart = { methods = { accept = { diff --git a/UI/Templates/MailPartViewers/UIxMailPartExternalHTMLViewer.wox b/UI/Templates/MailPartViewers/UIxMailPartExternalHTMLViewer.wox new file mode 100644 index 000000000..bc4148817 --- /dev/null +++ b/UI/Templates/MailPartViewers/UIxMailPartExternalHTMLViewer.wox @@ -0,0 +1,15 @@ + + + + +
+
diff --git a/UI/WebServerResources/UIxMailPartExternalHTMLViewer.css b/UI/WebServerResources/UIxMailPartExternalHTMLViewer.css new file mode 100644 index 000000000..0de2d775f --- /dev/null +++ b/UI/WebServerResources/UIxMailPartExternalHTMLViewer.css @@ -0,0 +1,4 @@ +HTML, BODY +{ background-color: #fff; + font-size: normal; + font-family: sans-serif; }