Monotone-Parent: 16149b4acf28c43530866e0b00c8f641e07afc24

Monotone-Revision: 52fad13e2d8c7765e5b822c94adbb945e0636f00

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2009-06-10T20:00:45
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
Wolfgang Sourdeau 2009-06-10 20:00:45 +00:00
parent ad313c2ad8
commit 0136b1b83d

View file

@ -49,6 +49,9 @@
#define showWhoWeAre() #define showWhoWeAre()
#endif #endif
/* Tags that are forbidden within the body of the html content */
static NSArray *BannedTags = nil;
static xmlCharEncoding static xmlCharEncoding
_xmlCharsetForCharset (NSString *charset) _xmlCharsetForCharset (NSString *charset)
{ {
@ -102,14 +105,14 @@ _xmlCharsetForCharset (NSString *charset)
NSMutableString *result; NSMutableString *result;
NSMutableString *css; NSMutableString *css;
NSDictionary *attachmentIds; NSDictionary *attachmentIds;
BOOL ignoreContent;
NSString *ignoreTag;
BOOL inBody; BOOL inBody;
BOOL inStyle; BOOL inStyle;
BOOL inScript;
BOOL inCSSDeclaration; BOOL inCSSDeclaration;
BOOL hasEmbeddedCSS; BOOL hasEmbeddedCSS;
BOOL hasExternalImages; BOOL hasExternalImages;
BOOL unsafe; BOOL unsafe;
NSMutableArray *crumb;
xmlCharEncoding contentEncoding; xmlCharEncoding contentEncoding;
} }
@ -119,13 +122,23 @@ _xmlCharsetForCharset (NSString *charset)
@implementation _UIxHTMLMailContentHandler @implementation _UIxHTMLMailContentHandler
+ (void) initialize
{
if (!BannedTags)
{
BannedTags = [NSArray arrayWithObjects: @"SCRIPT", @"LINK", @"BASE",
@"META", @"TITLE", nil];
[BannedTags retain];
}
}
- (id) init - (id) init
{ {
if ((self = [super init])) if ((self = [super init]))
{ {
crumb = nil;
css = nil; css = nil;
result = nil; result = nil;
ignoreTag = nil;
attachmentIds = nil; attachmentIds = nil;
contentEncoding = XML_CHAR_ENCODING_UTF8; contentEncoding = XML_CHAR_ENCODING_UTF8;
} }
@ -135,7 +148,6 @@ _xmlCharsetForCharset (NSString *charset)
- (void) dealloc - (void) dealloc
{ {
[crumb release];
[result release]; [result release];
[css release]; [css release];
[super dealloc]; [super dealloc];
@ -181,34 +193,25 @@ _xmlCharsetForCharset (NSString *charset)
{ {
showWhoWeAre(); showWhoWeAre();
[crumb release];
[css release]; [css release];
[result release]; [result release];
result = [NSMutableString new]; result = [NSMutableString new];
css = [NSMutableString new]; css = [NSMutableString new];
crumb = [NSMutableArray new];
ignoreContent = NO;
[ignoreTag release];
ignoreTag = nil;
inBody = NO; inBody = NO;
inStyle = NO; inStyle = NO;
inScript = NO;
inCSSDeclaration = NO; inCSSDeclaration = NO;
hasEmbeddedCSS = NO; hasEmbeddedCSS = NO;
} }
- (void) endDocument - (void) endDocument
{ {
unsigned int count, max;
showWhoWeAre(); showWhoWeAre();
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 - (void) startPrefixMapping: (NSString *)_prefix
@ -225,10 +228,13 @@ _xmlCharsetForCharset (NSString *charset)
- (void) _appendStyle: (unichar *) _chars - (void) _appendStyle: (unichar *) _chars
length: (int) _len length: (int) _len
{ {
unsigned int count; unsigned int count, length;
unichar *start, *currentChar; unichar *start, *currentChar;
start = _chars; start = _chars;
while (*start < 33)
start++;
currentChar = start; currentChar = start;
for (count = 0; count < _len; count++) for (count = 0; count < _len; count++)
{ {
@ -243,28 +249,39 @@ _xmlCharsetForCharset (NSString *charset)
} }
else else
{ {
if (*currentChar == '{') if (*currentChar < 32)
inCSSDeclaration = YES;
if (*currentChar == ',')
hasEmbeddedCSS = NO;
else if (!hasEmbeddedCSS)
{ {
if (*currentChar == '@') if (currentChar > start)
hasEmbeddedCSS = YES; [css appendString: [NSString stringWithCharacters: start
else length: (currentChar - start)]];
if (*currentChar > 32) start = currentChar + 1;
{ }
[css appendString: [NSString stringWithCharacters: start else
length: (currentChar - start)]]; {
[css appendString: @".SOGoHTMLMail-CSS-Delimiter "]; if (*currentChar == '{')
inCSSDeclaration = YES;
else if (*currentChar == ',')
hasEmbeddedCSS = NO;
else if (!hasEmbeddedCSS)
{
if (*currentChar == '@')
hasEmbeddedCSS = YES; hasEmbeddedCSS = YES;
start = currentChar; else
} if (*currentChar > 32)
{
length = (currentChar - start);
[css appendFormat: @"%@\n.SOGoHTMLMail-CSS-Delimiter ",
[NSString stringWithCharacters: start length: length]];
hasEmbeddedCSS = YES;
start = currentChar;
}
}
} }
} }
} }
[css appendString: [NSString stringWithCharacters: start if (currentChar > start)
length: (currentChar - start)]]; [css appendString: [NSString stringWithCharacters: start
length: (currentChar - start)]];
} }
- (void) startElement: (NSString *) _localName - (void) startElement: (NSString *) _localName
@ -273,111 +290,146 @@ _xmlCharsetForCharset (NSString *charset)
attributes: (id <SaxAttributes>) _attributes attributes: (id <SaxAttributes>) _attributes
{ {
unsigned int count, max; unsigned int count, max;
NSString *name, *value, *cid; NSString *name, *value, *cid, *upperName;
NSMutableString *resultPart; NSMutableString *resultPart;
BOOL skipAttribute; BOOL skipAttribute;
showWhoWeAre(); showWhoWeAre();
if (inStyle || inScript)
upperName = [_localName uppercaseString];
if (inStyle || ignoreContent)
; ;
else if ([_localName caseInsensitiveCompare: @"base"] == NSOrderedSame) else if ([upperName isEqualToString: @"BASE"])
; ;
else if ([_localName caseInsensitiveCompare: @"meta"] == NSOrderedSame) else if ([upperName isEqualToString: @"META"])
; ;
else if ([_localName caseInsensitiveCompare: @"body"] == NSOrderedSame) else if ([upperName isEqualToString: @"BODY"])
inBody = YES; inBody = YES;
else if ([_localName caseInsensitiveCompare: @"script"] == NSOrderedSame) else if ([upperName isEqualToString: @"STYLE"])
inScript = YES;
else if ([_localName caseInsensitiveCompare: @"style"] == NSOrderedSame)
inStyle = YES; inStyle = YES;
else if (inBody) else if (inBody)
{ {
resultPart = [NSMutableString new]; if ([BannedTags containsObject: upperName])
[resultPart appendFormat: @"<%@", _rawName];
max = [_attributes count];
for (count = 0; count < max; count++)
{ {
skipAttribute = NO; ignoreTag = [upperName copy];
name = [_attributes nameAtIndex: count]; ignoreContent = YES;
if ([[name lowercaseString] hasPrefix: @"on"])
skipAttribute = YES;
else if ([name caseInsensitiveCompare: @"src"] == NSOrderedSame)
{
value = [_attributes valueAtIndex: count];
if ([value hasPrefix: @"cid:"])
{
cid = [NSString stringWithFormat: @"<%@>",
[value substringFromIndex: 4]];
value = [attachmentIds objectForKey: cid];
skipAttribute = (value == nil);
}
else if ([_rawName caseInsensitiveCompare: @"img"] == NSOrderedSame)
{
hasExternalImages = YES;
if (!unsafe) skipAttribute = YES;
}
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)
[resultPart appendFormat: @" %@=\"%@\"",
name, [value stringByReplacingString: @"\""
withString: @"\\\""]];
} }
else
{
resultPart = [NSMutableString new];
[resultPart appendFormat: @"<%@", _rawName];
[resultPart appendString: @">"]; max = [_attributes count];
[result appendString: resultPart]; for (count = 0; count < max; count++)
[resultPart release]; {
skipAttribute = NO;
name = [[_attributes nameAtIndex: count] uppercaseString];
if ([name hasPrefix: @"ON"])
skipAttribute = YES;
else if ([name isEqualToString: @"SRC"])
{
value = [_attributes valueAtIndex: count];
if ([value hasPrefix: @"cid:"])
{
cid = [NSString stringWithFormat: @"<%@>",
[value substringFromIndex: 4]];
value = [attachmentIds objectForKey: cid];
skipAttribute = (value == nil);
}
else if ([upperName isEqualToString: @"IMG"])
{
hasExternalImages = YES;
if (!unsafe) skipAttribute = YES;
}
else
skipAttribute = YES;
}
else if ([name isEqualToString: @"HREF"]
|| [name isEqualToString: @"ACTION"])
{
value = [_attributes valueAtIndex: count];
skipAttribute = ([value rangeOfString: @"://"].location
== NSNotFound
&& ![value hasPrefix: @"#"]);
}
else
value = [_attributes valueAtIndex: count];
if (!skipAttribute)
[resultPart appendFormat: @" %@=\"%@\"",
name, [value stringByReplacingString: @"\""
withString: @"\\\""]];
}
[resultPart appendString: @">"];
[result appendString: resultPart];
[resultPart release];
}
} }
} }
- (void) _finishCSS - (void) _finishCSS
{ {
NSRange excessiveDelimiter;
[css replaceString: @"<!--" withString: @""];
[css replaceString: @"-->" withString: @""];
[css replaceString: @".SOGoHTMLMail-CSS-Delimiter body" [css replaceString: @".SOGoHTMLMail-CSS-Delimiter body"
withString: @".SOGoHTMLMail-CSS-Delimiter"]; withString: @".SOGoHTMLMail-CSS-Delimiter"];
[css replaceString: @";" withString: @" !important;"]; [css replaceString: @";" withString: @" !important;"];
[css replaceString: @"<!--" withString: @""];
[css replaceString: @"-->" withString: @""]; excessiveDelimiter = [css rangeOfString: @".SOGoHTMLMail-CSS-Delimiter "
options: NSBackwardsSearch];
if (excessiveDelimiter.location != NSNotFound)
{
if (NSMaxRange (excessiveDelimiter) == [css length])
[css deleteCharactersInRange: excessiveDelimiter];
}
} }
- (void) endElement: (NSString *) _localName - (void) endElement: (NSString *) _localName
namespace: (NSString *) _ns namespace: (NSString *) _ns
rawName: (NSString *) _rawName rawName: (NSString *) _rawName
{ {
NSString *upperName;
showWhoWeAre(); showWhoWeAre();
if (inStyle) upperName = [_localName uppercaseString];
if (ignoreContent)
{ {
if ([_localName caseInsensitiveCompare: @"style"] == NSOrderedSame) if ([upperName isEqualToString: ignoreTag])
{ {
inStyle = NO; ignoreContent = NO;
inCSSDeclaration = NO; [ignoreTag release];
} ignoreTag = nil;
}
} }
else if (inScript) else
inScript = ([_localName caseInsensitiveCompare: @"script"] != NSOrderedSame);
else if (inBody)
{ {
if ([_localName caseInsensitiveCompare: @"body"] == NSOrderedSame) if (inStyle)
{ {
inBody = NO; if ([upperName isEqualToString: @"STYLE"])
if (css) {
[self _finishCSS]; inStyle = NO;
} inCSSDeclaration = NO;
else }
[result appendFormat: @"</%@>", _localName]; }
else if (inBody)
{
if ([upperName isEqualToString: @"BODY"])
{
inBody = NO;
if (css)
[self _finishCSS];
}
else
{
NSLog (@"%@", _localName);
[result appendFormat: @"</%@>", _localName];
}
}
} }
} }
@ -385,7 +437,7 @@ _xmlCharsetForCharset (NSString *charset)
length: (int) _len length: (int) _len
{ {
showWhoWeAre(); showWhoWeAre();
if (!inScript) if (!ignoreContent)
{ {
if (inStyle) if (inStyle)
[self _appendStyle: _chars length: _len]; [self _appendStyle: _chars length: _len];