From 08b2d66e7a2ef6411bf0a9b990a36fee4b05db76 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 15 Feb 2007 21:04:31 +0000 Subject: [PATCH] Monotone-Parent: 84362f2350a7b9647b853e2a15e4797ea7c589ee Monotone-Revision: 38290ec957f9b6f35375587b7126f8610d1252f1 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2007-02-15T21:04:31 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 3 + UI/MailPartViewers/UIxMailPartHTMLViewer.h | 34 ++ UI/MailPartViewers/UIxMailPartHTMLViewer.m | 473 +++++++++++++++++- .../MailPartViewers/UIxMailPartHTMLViewer.wox | 30 +- 4 files changed, 498 insertions(+), 42 deletions(-) create mode 100644 UI/MailPartViewers/UIxMailPartHTMLViewer.h diff --git a/ChangeLog b/ChangeLog index 8039c5fc5..38a054621 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2007-02-15 Wolfgang Sourdeau + * UI/MailPartViewers/UIxMailPartHTMLViewer.m: reimplemented module + from scratch. + * UI/MailPartViewers/UIxMailPartAlternativeViewer.m: select the text/html component before text/plain. diff --git a/UI/MailPartViewers/UIxMailPartHTMLViewer.h b/UI/MailPartViewers/UIxMailPartHTMLViewer.h new file mode 100644 index 000000000..edc0143c3 --- /dev/null +++ b/UI/MailPartViewers/UIxMailPartHTMLViewer.h @@ -0,0 +1,34 @@ +/* UIxMailPartHTMLViewer.h - this file is part of SOGo + * + * Copyright (C) 2007 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. + */ + +#ifndef UIXMAILPARTHTMLVIEWER_H +#define UIXMAILPARTHTMLVIEWER_H + +#import "UIxMailPartViewer.h" + +@interface UIxMailPartHTMLViewer : UIxMailPartViewer + +- (NSString *) flatContentAsString; + +@end + +#endif /* UIXMAILPARTHTMLVIEWER_H */ diff --git a/UI/MailPartViewers/UIxMailPartHTMLViewer.m b/UI/MailPartViewers/UIxMailPartHTMLViewer.m index ab7746de6..4b926e1e1 100644 --- a/UI/MailPartViewers/UIxMailPartHTMLViewer.m +++ b/UI/MailPartViewers/UIxMailPartHTMLViewer.m @@ -1,30 +1,463 @@ -/* - Copyright (C) 2004-2005 SKYRIX Software AG +/* UIxMailPartHTMLViewer.m - this file is part of SOGo + * + * Copyright (C) 2007 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. + */ - This file is part of OpenGroupware.org. +#import +#import +#import +#import +#import +#import +#import +#import - OGo is free software; you can redistribute it and/or modify it under - the terms of the GNU Lesser General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. +#import "UIxMailPartHTMLViewer.h" - OGo 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 Lesser General Public - License for more details. +#define showWhoWeAre() NSLog(@"invoked '%@'", NSStringFromSelector(_cmd)) - 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 - Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. -*/ +@interface _UIxHTMLMailContentHandler : NSObject +{ + NSMutableString *result; + NSMutableString *css; + NSDictionary *attachmentIds; + BOOL inBody; + BOOL inStyle; + BOOL inScript; + BOOL inCSSDeclaration; + NSMutableArray *crumb; +} -#include "UIxMailPartLinkViewer.h" +- (NSString *) result; -@interface UIxMailPartHTMLViewer : UIxMailPartLinkViewer @end -#include "common.h" +@implementation _UIxHTMLMailContentHandler + +- (id) init +{ + if ((self = [super init])) + { + crumb = nil; + css = nil; + result = nil; + attachmentIds = nil; + } + + return self; +} + +- (void) dealloc +{ + if (crumb) + [crumb release]; + if (result) + [result release]; + if (css) + [css release]; + [super dealloc]; +} + +- (void) setAttachmentIds: (NSDictionary *) newAttachmentIds +{ + attachmentIds = newAttachmentIds; +} + +- (NSString *) css +{ + return [[css copy] autorelease]; +} + +- (NSString *) result +{ + return [[result copy] autorelease]; +} + +/* SaxContentHandler */ +- (void) startDocument +{ + if (crumb) + [crumb release]; + if (result) + [result release]; + if (css) + [css release]; + + result = [NSMutableString new]; + css = [NSMutableString new]; + crumb = [NSMutableArray new]; + inBody = NO; + inStyle = NO; + inScript = NO; + inCSSDeclaration = NO; +} + +- (void) endDocument +{ + unsigned int count, max; + + max = [crumb count]; + if (max > 0) + for (count = max - 1; count > -1; count--) + { + [result appendFormat: @"", [crumb objectAtIndex: count]]; + [crumb removeObjectAtIndex: count]; + } +} + +- (void) startPrefixMapping: (NSString *)_prefix + uri: (NSString *)_uri +{ + showWhoWeAre(); +} + +- (void) endPrefixMapping: (NSString *)_prefix +{ + showWhoWeAre(); +} + +- (NSString *) _valueForCSSIdentifier: (NSString *) primaryValue +{ + NSMutableString *value; + NSEnumerator *classes; + NSString *currentValue; + + value = [NSMutableString new]; + [value autorelease]; + + classes = [[primaryValue componentsSeparatedByString: @" "] objectEnumerator]; + currentValue = [classes nextObject]; + while (currentValue) + { + [value appendFormat: @"SOGoHTMLMail-%@ ", currentValue]; + currentValue = [classes nextObject]; + } + + return value; +} + +- (void) _appendStyle: (unichar *) _chars + length: (int) _len +{ + unsigned int count; + unichar *start, *currentChar; + + start = _chars; + currentChar = start; + for (count = 0; count < _len; count++) + { + currentChar = _chars + count; + if (inCSSDeclaration) + { + if (*(char *) currentChar == '}') + inCSSDeclaration = NO; + } + else + { + if (*(char *) currentChar == '{') + inCSSDeclaration = YES; + else if (*(char *) currentChar == '.' + || *(char *) currentChar == '#') + { + [css appendString: [NSString stringWithCharacters: start + length: (currentChar - start + 1)]]; + [css appendString: @"SOGoHTMLMail-"]; + start = currentChar + 1; + } + } + } + [css appendString: [NSString stringWithCharacters: start + length: (currentChar - start + 1)]]; +} + +- (void) startElement: (NSString *) _localName + namespace: (NSString *) _ns + rawName: (NSString *) _rawName + attributes: (id ) _attributes +{ + unsigned int count, max; + NSString *name, *value; + NSMutableString *resultPart; + BOOL skipAttribute; + + if (inStyle || inScript) + ; + else if ([_localName caseInsensitiveCompare: @"body"] == NSOrderedSame) + inBody = YES; + else if ([_localName caseInsensitiveCompare: @"script"] == NSOrderedSame) + inScript = YES; + else if ([_localName caseInsensitiveCompare: @"style"] == NSOrderedSame) + inStyle = YES; + else if (inBody) + { + resultPart = [NSMutableString new]; + [resultPart appendFormat: @"<%@", _rawName]; + + max = [_attributes count]; + for (count = 0; count < max; count++) + { + skipAttribute = NO; + name = [_attributes nameAtIndex: count]; + if ([name caseInsensitiveCompare: @"class"] == NSOrderedSame + || [name caseInsensitiveCompare: @"id"] == NSOrderedSame) + value = [self _valueForCSSIdentifier: [_attributes valueAtIndex: count]]; + else if ([[name lowercaseString] hasPrefix: @"on"]) + skipAttribute = YES; + else if ([name caseInsensitiveCompare: @"src"] == NSOrderedSame) + { + value = [_attributes valueAtIndex: count]; + if ([value hasPrefix: @"cid:"]) + { + value = [attachmentIds + objectForKey: [value substringFromIndex: 4]]; + skipAttribute = (value == nil); + } + else + skipAttribute = YES; + } + else + value = [_attributes valueAtIndex: count]; + if (!skipAttribute) + [resultPart appendFormat: @" %@=\"%@\"", + name, [value stringByReplacingString: @"\"" + withString: @"\\\""]]; + } + + [resultPart appendString: @">"]; + [result appendString: resultPart]; + } +} + +- (void) endElement: (NSString *) _localName + namespace: (NSString *) _ns + rawName: (NSString *) _rawName +{ + if (inStyle) + { + if ([_localName caseInsensitiveCompare: @"style"] == NSOrderedSame) + { + inStyle = NO; + inCSSDeclaration = NO; + } + } + else if (inScript) + inScript = ([_localName caseInsensitiveCompare: @"script"] != NSOrderedSame); + else if (inBody) + { + if ([_localName caseInsensitiveCompare: @"body"] == NSOrderedSame) + inBody = NO; + else + [result appendFormat: @"", _localName]; + } +} + +- (void) characters: (unichar *) _chars + length: (int) _len +{ + NSString *tmpString; + + if (!inScript) + { + if (inStyle) + [self _appendStyle: _chars length: _len]; + if (inBody) + { + tmpString = [NSString stringWithCharacters: _chars length: _len]; + [result appendString: [tmpString stringByEscapingHTMLString]]; + } + } +} + +- (void) ignorableWhitespace: (unichar *) _chars + length: (int) _len +{ + showWhoWeAre(); +} + +- (void) processingInstruction: (NSString *) _pi + data: (NSString *) _data +{ + showWhoWeAre(); +} + +- (void) setDocumentLocator: (id ) _locator +{ + showWhoWeAre(); +} + +- (void) skippedEntity: (NSString *) _entityName +{ + showWhoWeAre(); +} + +/* SaxLexicalHandler */ +- (void) comment: (unichar *) _chars + length: (int) _len +{ + if (inStyle) + [self _appendStyle: _chars length: _len]; +} + +- (void) startDTD: (NSString *) _name + publicId: (NSString *) _pub + systemId: (NSString *) _sys +{ + showWhoWeAre(); +} + +- (void) endDTD +{ + showWhoWeAre(); +} + +- (void) startEntity: (NSString *) _name +{ + showWhoWeAre(); +} + +- (void) endEntity: (NSString *) _name +{ + showWhoWeAre(); +} + +- (void) startCDATA +{ + showWhoWeAre(); +} + +- (void) endCDATA +{ + showWhoWeAre(); +} + +@end + +@interface NSDictionary (SOGoDebug) + +- (void) dump; + +@end + +@implementation NSDictionary (SOGoDebug) + +- (void) dump +{ + NSEnumerator *keys; + NSString *key; + NSMutableString *dump; + + dump = [NSMutableString new]; + [dump appendFormat: @"\nNSDictionary dump (%@):\n", self]; + keys = [[self allKeys] objectEnumerator]; + key = [keys nextObject]; + while (key) + { + [dump appendFormat: @"%@: %@\n", key, [self objectForKey: key]]; + key = [keys nextObject]; + } + [dump appendFormat: @"--- end ---\n"]; + + NSLog (dump); + [dump release]; +} + +@end @implementation UIxMailPartHTMLViewer -@end /* UIxMailPartHTMLViewer */ + +- (void) _convertReferencesForPart: (NSDictionary *) part + withCount: (unsigned int) count + andBaseURL: (NSString *) url + intoDictionary: (NSMutableDictionary *) attachmentIds +{ + NSString *bodyId; + + bodyId = [part objectForKey: @"bodyId"]; + if ([bodyId length] > 0) + { + NSLog(@"%@", part); + if ([bodyId hasPrefix: @"<"]) + bodyId = [bodyId substringFromIndex: 1]; + if ([bodyId hasSuffix: @">"]) + bodyId = [bodyId substringToIndex: [bodyId length] - 1]; + [attachmentIds setObject: [url stringByAppendingFormat: @"/%d", count] + forKey: bodyId]; + } +} + +- (NSDictionary *) _attachmentIds +{ + NSMutableDictionary *attachmentIds; + UIxMailPartViewer *parent; + unsigned int count, max; + NSString *baseURL; + NSArray *parts; + + attachmentIds = [NSMutableDictionary new]; + [attachmentIds autorelease]; + + parent = [self parent]; + if ([NSStringFromClass ([parent class]) + isEqualToString: @"UIxMailPartAlternativeViewer"]) + { + baseURL = [[self clientObject] baseURLInContext: context]; + parts = [[parent bodyInfo] objectForKey: @"parts"]; + max = [parts count]; + for (count = 0; count < max; count++) + [self _convertReferencesForPart: [parts objectAtIndex: count] + withCount: count + 1 + andBaseURL: baseURL + intoDictionary: attachmentIds]; + } + + NSLog(@"attc: '%@'", attachmentIds); + return attachmentIds; +} + +- (NSString *) flatContentAsString +{ + id parser; + _UIxHTMLMailContentHandler *handler; + NSString *preparsedContent, *content, *css; + + preparsedContent = [super flatContentAsString]; + parser = [[SaxXMLReaderFactory standardXMLReaderFactory] + createXMLReaderForMimeType: @"text/html"]; + + handler = [_UIxHTMLMailContentHandler new]; + [handler setAttachmentIds: [self _attachmentIds]]; + [parser setContentHandler: handler]; + [parser setProperty: @"http://xml.org/sax/properties/lexical-handler" + to: handler]; + [parser parseFromSource: preparsedContent]; + + css = [handler css]; + if ([css length]) + content + = [NSString stringWithFormat: @"%@", + css, [handler result]]; + else + content = [handler result]; + [handler release]; + + return content; +} + +@end diff --git a/UI/Templates/MailPartViewers/UIxMailPartHTMLViewer.wox b/UI/Templates/MailPartViewers/UIxMailPartHTMLViewer.wox index 8ca1d5f73..bafb05470 100644 --- a/UI/Templates/MailPartViewers/UIxMailPartHTMLViewer.wox +++ b/UI/Templates/MailPartViewers/UIxMailPartHTMLViewer.wox @@ -1,23 +1,9 @@ -
- - - -
- -
- : - / - , - - : - -
-
-
+