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:
parent
ad313c2ad8
commit
0136b1b83d
|
@ -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];
|
||||||
|
|
Loading…
Reference in a new issue