+@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 <SaxAttributes>) _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 <NSObject, SaxLocator>) _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