From ad313c2ad833a23f9fabed9189de1c71fec49d46 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 10 Jun 2009 20:00:42 +0000 Subject: [PATCH 1/7] Monotone-Parent: 931357c046b4c2c5bca20cfc7027809a3240f43a Monotone-Revision: 16149b4acf28c43530866e0b00c8f641e07afc24 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-06-10T20:00:42 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ChangeLog b/ChangeLog index 7669b9008..4e8bd9180 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2009-06-10 Wolfgang Sourdeau + + * UI/MailPartViewers/UIxMailPartHTMLViewer.m: fixed rendering of + CSS content containing comment characters. Ignore certain HTML + tags that can alter the appearance of the SOGo display altogether + (SCRIPT, LINK, BASE, META, TITLE). + 2009-06-09 Wolfgang Sourdeau * SoObjects/Appointments/SOGoFreeBusyObject.m From 0136b1b83d838354ddda805195fd27999a35dc39 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 10 Jun 2009 20:00:45 +0000 Subject: [PATCH 2/7] Monotone-Parent: 16149b4acf28c43530866e0b00c8f641e07afc24 Monotone-Revision: 52fad13e2d8c7765e5b822c94adbb945e0636f00 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-06-10T20:00:45 Monotone-Branch: ca.inverse.sogo --- UI/MailPartViewers/UIxMailPartHTMLViewer.m | 270 ++++++++++++--------- 1 file changed, 161 insertions(+), 109 deletions(-) diff --git a/UI/MailPartViewers/UIxMailPartHTMLViewer.m b/UI/MailPartViewers/UIxMailPartHTMLViewer.m index 284fb134c..dc0a571dd 100644 --- a/UI/MailPartViewers/UIxMailPartHTMLViewer.m +++ b/UI/MailPartViewers/UIxMailPartHTMLViewer.m @@ -49,6 +49,9 @@ #define showWhoWeAre() #endif +/* Tags that are forbidden within the body of the html content */ +static NSArray *BannedTags = nil; + static xmlCharEncoding _xmlCharsetForCharset (NSString *charset) { @@ -102,14 +105,14 @@ _xmlCharsetForCharset (NSString *charset) NSMutableString *result; NSMutableString *css; NSDictionary *attachmentIds; + BOOL ignoreContent; + NSString *ignoreTag; BOOL inBody; BOOL inStyle; - BOOL inScript; BOOL inCSSDeclaration; BOOL hasEmbeddedCSS; BOOL hasExternalImages; BOOL unsafe; - NSMutableArray *crumb; xmlCharEncoding contentEncoding; } @@ -119,13 +122,23 @@ _xmlCharsetForCharset (NSString *charset) @implementation _UIxHTMLMailContentHandler ++ (void) initialize +{ + if (!BannedTags) + { + BannedTags = [NSArray arrayWithObjects: @"SCRIPT", @"LINK", @"BASE", + @"META", @"TITLE", nil]; + [BannedTags retain]; + } +} + - (id) init { if ((self = [super init])) { - crumb = nil; css = nil; result = nil; + ignoreTag = nil; attachmentIds = nil; contentEncoding = XML_CHAR_ENCODING_UTF8; } @@ -135,7 +148,6 @@ _xmlCharsetForCharset (NSString *charset) - (void) dealloc { - [crumb release]; [result release]; [css release]; [super dealloc]; @@ -181,34 +193,25 @@ _xmlCharsetForCharset (NSString *charset) { showWhoWeAre(); - [crumb release]; [css release]; [result release]; result = [NSMutableString new]; css = [NSMutableString new]; - crumb = [NSMutableArray new]; + + ignoreContent = NO; + [ignoreTag release]; + ignoreTag = nil; inBody = NO; inStyle = NO; - inScript = NO; inCSSDeclaration = NO; hasEmbeddedCSS = NO; } - (void) endDocument { - unsigned int count, max; - - 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 @@ -225,10 +228,13 @@ _xmlCharsetForCharset (NSString *charset) - (void) _appendStyle: (unichar *) _chars length: (int) _len { - unsigned int count; + unsigned int count, length; unichar *start, *currentChar; start = _chars; + while (*start < 33) + start++; + currentChar = start; for (count = 0; count < _len; count++) { @@ -243,28 +249,39 @@ _xmlCharsetForCharset (NSString *charset) } else { - if (*currentChar == '{') - inCSSDeclaration = YES; - if (*currentChar == ',') - hasEmbeddedCSS = NO; - else if (!hasEmbeddedCSS) + if (*currentChar < 32) { - if (*currentChar == '@') - hasEmbeddedCSS = YES; - else - if (*currentChar > 32) - { - [css appendString: [NSString stringWithCharacters: start - length: (currentChar - start)]]; - [css appendString: @".SOGoHTMLMail-CSS-Delimiter "]; + if (currentChar > start) + [css appendString: [NSString stringWithCharacters: start + length: (currentChar - start)]]; + start = currentChar + 1; + } + else + { + if (*currentChar == '{') + inCSSDeclaration = YES; + else if (*currentChar == ',') + hasEmbeddedCSS = NO; + else if (!hasEmbeddedCSS) + { + if (*currentChar == '@') 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 - length: (currentChar - start)]]; + if (currentChar > start) + [css appendString: [NSString stringWithCharacters: start + length: (currentChar - start)]]; } - (void) startElement: (NSString *) _localName @@ -273,111 +290,146 @@ _xmlCharsetForCharset (NSString *charset) attributes: (id ) _attributes { unsigned int count, max; - NSString *name, *value, *cid; + NSString *name, *value, *cid, *upperName; NSMutableString *resultPart; BOOL skipAttribute; 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; - else if ([_localName caseInsensitiveCompare: @"script"] == NSOrderedSame) - inScript = YES; - else if ([_localName caseInsensitiveCompare: @"style"] == NSOrderedSame) + else if ([upperName isEqualToString: @"STYLE"]) inStyle = YES; else if (inBody) { - resultPart = [NSMutableString new]; - [resultPart appendFormat: @"<%@", _rawName]; - - max = [_attributes count]; - for (count = 0; count < max; count++) + if ([BannedTags containsObject: upperName]) { - skipAttribute = NO; - name = [_attributes nameAtIndex: count]; - 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: @"\\\""]]; + ignoreTag = [upperName copy]; + ignoreContent = YES; } + else + { + resultPart = [NSMutableString new]; + [resultPart appendFormat: @"<%@", _rawName]; - [resultPart appendString: @">"]; - [result appendString: resultPart]; - [resultPart release]; + max = [_attributes count]; + for (count = 0; count < max; count++) + { + 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 { + NSRange excessiveDelimiter; + + [css replaceString: @"" withString: @""]; [css replaceString: @".SOGoHTMLMail-CSS-Delimiter body" withString: @".SOGoHTMLMail-CSS-Delimiter"]; [css replaceString: @";" withString: @" !important;"]; - [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 namespace: (NSString *) _ns rawName: (NSString *) _rawName { + NSString *upperName; + showWhoWeAre(); - if (inStyle) + upperName = [_localName uppercaseString]; + + if (ignoreContent) { - if ([_localName caseInsensitiveCompare: @"style"] == NSOrderedSame) - { - inStyle = NO; - inCSSDeclaration = NO; - } + if ([upperName isEqualToString: ignoreTag]) + { + ignoreContent = NO; + [ignoreTag release]; + ignoreTag = nil; + } } - else if (inScript) - inScript = ([_localName caseInsensitiveCompare: @"script"] != NSOrderedSame); - else if (inBody) + else { - if ([_localName caseInsensitiveCompare: @"body"] == NSOrderedSame) - { - inBody = NO; - if (css) - [self _finishCSS]; - } - else - [result appendFormat: @"", _localName]; + if (inStyle) + { + if ([upperName isEqualToString: @"STYLE"]) + { + inStyle = NO; + inCSSDeclaration = NO; + } + } + 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 { showWhoWeAre(); - if (!inScript) + if (!ignoreContent) { if (inStyle) [self _appendStyle: _chars length: _len]; @@ -394,7 +446,7 @@ _xmlCharsetForCharset (NSString *charset) NSString *tmpString; tmpString = [NSString stringWithCharacters: _chars length: _len]; - + // HACK: This is to avoid appending the useless junk in the tag // that Outlook adds. It seems to confuse the XML parser for // forwarded messages as we get this in the _body_ of the email From 97f9609afb1b762633c938e480359e7b9d7b1102 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 10 Jun 2009 20:54:02 +0000 Subject: [PATCH 3/7] Monotone-Parent: 810ca1c510af3f2653d3478ccb575204bc309c5a Monotone-Revision: d3d21b70ee927b400d90095e3cd2ed9de1afc2f4 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-06-10T20:54:02 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 10 ++++++ SoObjects/SOGo/NSArray+Utilities.h | 6 +++- SoObjects/SOGo/NSArray+Utilities.m | 36 ++++++++++++++++++--- SoObjects/SOGo/NSString+Utilities.m | 49 +++++++++++++++-------------- 4 files changed, 72 insertions(+), 29 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4e8bd9180..d5cc529f0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,15 @@ 2009-06-10 Wolfgang Sourdeau + * SoObjects/SOGo/NSString+Utilities.m (-stringByDetectingURLs): + fixed a leak. Fixed a crash on GNUstep by using arrays of pointers + to NSRange instead of converting/parsing them to/from NSString. + + * SoObjects/SOGo/NSArray+Utilities.m (-addRange): removed method. + (-addNonNSObject:withSize:copy:): new helper method to add object + pointers to arrays. + (-freeNonNSObjects): new helper method to release the above object + pointers. + * UI/MailPartViewers/UIxMailPartHTMLViewer.m: fixed rendering of CSS content containing comment characters. Ignore certain HTML tags that can alter the appearance of the SOGo display altogether diff --git a/SoObjects/SOGo/NSArray+Utilities.h b/SoObjects/SOGo/NSArray+Utilities.h index 1f379d475..4f9cf4aab 100644 --- a/SoObjects/SOGo/NSArray+Utilities.h +++ b/SoObjects/SOGo/NSArray+Utilities.h @@ -53,9 +53,13 @@ @interface NSMutableArray (SOGoArrayUtilities) +- (void) addNonNSObject: (void *) objectPtr + withSize: (size_t) objectSize + copy: (BOOL) doCopy; +- (void) freeNonNSObjects; + - (void) addObjectUniquely: (id) object; -- (void) addRange: (NSRange) newRange; - (BOOL) hasRangeIntersection: (NSRange) testRange; @end diff --git a/SoObjects/SOGo/NSArray+Utilities.m b/SoObjects/SOGo/NSArray+Utilities.m index 857371f07..51b5f19b1 100644 --- a/SoObjects/SOGo/NSArray+Utilities.m +++ b/SoObjects/SOGo/NSArray+Utilities.m @@ -24,6 +24,7 @@ #import #import #import +#import #import "NSArray+Utilities.h" @@ -199,17 +200,42 @@ @implementation NSMutableArray (SOGoArrayUtilities) +- (void) addNonNSObject: (void *) objectPtr + withSize: (size_t) objectSize + copy: (BOOL) doCopy +{ + void *newObjectPtr; + + if (doCopy) + { + newObjectPtr = NSZoneMalloc (NULL, objectSize); + memcpy (newObjectPtr, objectPtr, objectSize); + } + else + newObjectPtr = objectPtr; + + [self addObject: [NSValue valueWithPointer: newObjectPtr]]; +} + +- (void) freeNonNSObjects +{ + unsigned int count, max; + void *objectPtr; + + max = [self count]; + for (count = 0; count < max; count++) + { + objectPtr = [[self objectAtIndex: count] pointerValue]; + NSZoneFree (NULL, objectPtr); + } +} + - (void) addObjectUniquely: (id) object { if (![self containsObject: object]) [self addObject: object]; } -- (void) addRange: (NSRange) newRange -{ - [self addObject: NSStringFromRange (newRange)]; -} - - (BOOL) hasRangeIntersection: (NSRange) testRange { NSEnumerator *ranges; diff --git a/SoObjects/SOGo/NSString+Utilities.m b/SoObjects/SOGo/NSString+Utilities.m index 66fdbafba..d9a2027d4 100644 --- a/SoObjects/SOGo/NSString+Utilities.m +++ b/SoObjects/SOGo/NSString+Utilities.m @@ -23,6 +23,7 @@ #import #import #import +#import #import @@ -88,7 +89,7 @@ static NSMutableCharacterSet *urlStartChars = nil; r = [self rangeOfString:@"?" options: NSBackwardsSearch]; if (r.length > 0) - newUrl = [self substringToIndex: NSMaxRange(r) - 1]; + newUrl = [self substringToIndex: NSMaxRange (r) - 1]; else newUrl = self; @@ -132,11 +133,10 @@ static NSMutableCharacterSet *urlStartChars = nil; { nsEnclosing = [self rangeOfString: @"}"]; length = [self length]; - if (nsEnclosing.length > 0 - && nsEnclosing.location < (length - 1)) + if (nsEnclosing.length > 0 && nsEnclosing.location < (length - 1)) { - methodEnclosing = NSMakeRange(nsEnclosing.location + 1, - length - nsEnclosing.location - 1); + methodEnclosing = NSMakeRange (nsEnclosing.location + 1, + length - nsEnclosing.location - 1); nsEnclosing.length = nsEnclosing.location - 1; nsEnclosing.location = 1; davInvocation = [NSMutableDictionary dictionaryWithCapacity: 2]; @@ -176,7 +176,7 @@ static NSMutableCharacterSet *urlStartChars = nil; start--; start++; length = [self length] - start; - workRange = NSMakeRange(start, length); + workRange = NSMakeRange (start, length); workRange = [self rangeOfCharacterFromSet: urlAfterEndingChars options: NSLiteralSearch range: workRange]; if (workRange.location != NSNotFound) @@ -198,7 +198,8 @@ static NSMutableCharacterSet *urlStartChars = nil; NSEnumerator *enumRanges; NSMutableArray *newRanges; NSRange matchRange, currentUrlRange, rest; - NSString *urlText, *newUrlText, *range; + NSRange *rangePtr; + NSString *urlText, *newUrlText; unsigned int length, matchLength, offset; int startLocation; @@ -209,10 +210,11 @@ static NSMutableCharacterSet *urlStartChars = nil; @"ABCDEFGHIJKLMNOPQRSTUVWXYZ" @"0123456789:@"]; } - newRanges = [NSMutableArray new]; + + newRanges = [NSMutableArray array]; matchLength = [match length]; rest.location = -1; - + matchRange = [selfCopy rangeOfString: match]; while (matchRange.location != NSNotFound) { @@ -225,12 +227,14 @@ static NSMutableCharacterSet *urlStartChars = nil; currentUrlRange = [selfCopy _rangeOfURLInRange: matchRange]; if ([ranges hasRangeIntersection: currentUrlRange]) - rest.location = NSMaxRange(currentUrlRange); + rest.location = NSMaxRange (currentUrlRange); else { if (currentUrlRange.length > matchLength) - [newRanges addRange: currentUrlRange]; - rest.location = NSMaxRange(currentUrlRange); + [newRanges addNonNSObject: ¤tUrlRange + withSize: sizeof (NSRange) + copy: YES]; + rest.location = NSMaxRange (currentUrlRange); } length = [selfCopy length]; @@ -242,25 +246,24 @@ static NSMutableCharacterSet *urlStartChars = nil; // Make the substitutions, keep track of the new offset offset = 0; enumRanges = [newRanges objectEnumerator]; - range = [enumRanges nextObject]; - while (range) + while ((rangePtr = [[enumRanges nextObject] pointerValue])) { - currentUrlRange = NSRangeFromString(range); - currentUrlRange.location += offset; - urlText = [selfCopy substringFromRange: currentUrlRange]; + rangePtr->location += offset; + urlText = [selfCopy substringFromRange: *rangePtr]; if ([urlText hasPrefix: prefix]) prefix = @""; newUrlText = [NSString stringWithFormat: @"%@", prefix, urlText, urlText]; - [selfCopy replaceCharactersInRange: currentUrlRange + [selfCopy replaceCharactersInRange: *rangePtr withString: newUrlText]; offset += ([newUrlText length] - [urlText length]); // Add range for further substitutions currentUrlRange = NSMakeRange (currentUrlRange.location, [newUrlText length]); - [ranges addRange: currentUrlRange]; - - range = [enumRanges nextObject]; + [ranges addNonNSObject: ¤tUrlRange + withSize: sizeof (NSRange) + copy: YES]; } + [newRanges freeNonNSObjects]; } - (NSString *) stringByDetectingURLs @@ -268,7 +271,7 @@ static NSMutableCharacterSet *urlStartChars = nil; NSMutableString *selfCopy; NSMutableArray *ranges; - ranges = [NSMutableArray new]; + ranges = [NSMutableArray array]; selfCopy = [NSMutableString stringWithString: self]; [self _handleURLs: selfCopy textToMatch: @"://" @@ -278,7 +281,7 @@ static NSMutableCharacterSet *urlStartChars = nil; textToMatch: @"@" prefix: @"mailto:" inRanges: ranges]; - [ranges release]; + [ranges freeNonNSObjects]; return selfCopy; } From 698b9d676a40bbccd7c4b4603521678bf24e8f35 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 11 Jun 2009 12:43:48 +0000 Subject: [PATCH 4/7] Monotone-Parent: d3d21b70ee927b400d90095e3cd2ed9de1afc2f4 Monotone-Revision: b0e5ee564933daba4086caf8c388552e1777cf7c Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-06-11T12:43:48 Monotone-Branch: ca.inverse.sogo --- UI/WebServerResources/dtree.js | 569 +++++++++++++++++---------------- 1 file changed, 285 insertions(+), 284 deletions(-) diff --git a/UI/WebServerResources/dtree.js b/UI/WebServerResources/dtree.js index b2eedb938..57dbed7c1 100644 --- a/UI/WebServerResources/dtree.js +++ b/UI/WebServerResources/dtree.js @@ -73,294 +73,295 @@ function dTree(objName) { return this; }; -// Adds a new node to the node array -dTree.prototype.add = function(id, pid, name, isParent, url, datatype, - title, target, icon, iconOpen, open, hasUnseen) { - this.aNodes[this.aNodes.length] = new Node(id, pid, name, isParent, url, - datatype, title, target, icon, - iconOpen, open, false, hasUnseen); -}; +dTree.prototype = { + // Adds a new node to the node array + add: function(id, pid, name, isParent, url, datatype, + title, target, icon, iconOpen, open, hasUnseen) { + this.aNodes[this.aNodes.length] = new Node(id, pid, name, isParent, url, + datatype, title, target, icon, + iconOpen, open, false, hasUnseen); + }, -// Open/close all nodes -dTree.prototype.openAll = function() { - this.oAll(true); -}; -dTree.prototype.closeAll = function() { - this.oAll(false); -}; + // Open/close all nodes + openAll: function() { + this.oAll(true); + }, + closeAll: function() { + this.oAll(false); + }, -// Outputs the tree to the page -dTree.prototype.toString = function() { - var str = '
\n'; - if (document.getElementById) { - if (this.config.useCookies) - this.selectedNode = this.getSelected(); - str += this.addNode(this.root); - } else str += 'Browser not supported.'; - str += '
'; - if (!this.selectedFound) this.selectedNode = null; - this.completed = true; - return str; -}; + // Outputs the tree to the page + toString: function() { + var str = '
\n'; + if (document.getElementById) { + if (this.config.useCookies) + this.selectedNode = this.getSelected(); + str += this.addNode(this.root); + } else str += 'Browser not supported.'; + str += '
'; + if (!this.selectedFound) this.selectedNode = null; + this.completed = true; + return str; + }, -// Creates the tree structure -dTree.prototype.addNode = function(pNode) { - var str = ''; - var n=0; - if (this.config.inOrder) n = pNode._ai; - for (n; n'; + if (this.config.useIcons) { + if (!node.icon) node.icon = (this.root.id == node.pid) ? this.icon.root : ((node._hc) ? this.icon.folder : this.icon.node); + if (!node.iconOpen) node.iconOpen = (node._hc) ? this.icon.folderOpen : this.icon.node; + if (this.root.id == node.pid) { + node.icon = this.icon.root; + node.iconOpen = this.icon.root; + } + str += ''; + } + str += '' + node.name + ''; + if (node.url || ((!this.config.folderLinks || !node.url) && node._hc)) str += ''; + str += ''; + } + if (node._hc) { + str += '
'; + str += this.addNode(node); + str += '
'; + } + this.aIndent.pop(); + return str; + }, + + // Adds the empty and line icons + indent: function(node, nodeId) { + var str = ''; + if (this.root.id != node.pid) + { + for (var n=0; n'; + (node._ls) ? this.aIndent.push(0) : this.aIndent.push(1); + if (node._hc) + { + str += ''; + } + else + str += ''; + } + return str; + }, + + // Checks if a node has any children and if it is the last sibling + setCS: function(node) { + var lastId; + for (var n=0; n'; - if (this.config.useIcons) { - if (!node.icon) node.icon = (this.root.id == node.pid) ? this.icon.root : ((node._hc) ? this.icon.folder : this.icon.node); - if (!node.iconOpen) node.iconOpen = (node._hc) ? this.icon.folderOpen : this.icon.node; - if (this.root.id == node.pid) { - node.icon = this.icon.root; - node.iconOpen = this.icon.root; - } - str += ''; - } - str += '' + node.name + ''; - if (node.url || ((!this.config.folderLinks || !node.url) && node._hc)) str += ''; - str += ''; - } - if (node._hc) { - str += '
'; - str += this.addNode(node); - str += '
'; - } - this.aIndent.pop(); - return str; -}; - -// Adds the empty and line icons -dTree.prototype.indent = function(node, nodeId) { - var str = ''; - if (this.root.id != node.pid) - { - for (var n=0; n'; - (node._ls) ? this.aIndent.push(0) : this.aIndent.push(1); - if (node._hc) - { - str += ''; - } - else - str += ''; - } - return str; -}; - -// Checks if a node has any children and if it is the last sibling -dTree.prototype.setCS = function(node) { - var lastId; - for (var n=0; n Date: Thu, 11 Jun 2009 12:47:26 +0000 Subject: [PATCH 5/7] Monotone-Parent: b0e5ee564933daba4086caf8c388552e1777cf7c Monotone-Revision: 87a9edec020f812d113ea5bde21c2d30b040ab87 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-06-11T12:47:26 Monotone-Branch: ca.inverse.sogo --- UI/WebServerResources/dtree.js | 70 +++++++++++++++++----------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/UI/WebServerResources/dtree.js b/UI/WebServerResources/dtree.js index 57dbed7c1..856069738 100644 --- a/UI/WebServerResources/dtree.js +++ b/UI/WebServerResources/dtree.js @@ -34,46 +34,48 @@ function Node(id, pid, name, isParent, url, dataname, datatype, title, target, // Tree object function dTree(objName) { - this.config = { - target : null, - hideRoot : false, - folderLinks : true, - useSelection : true, - useCookies : false, - useLines : true, - useIcons : true, - useStatusText : false, - closeSameLevel : false, - inOrder : false - } - this.icon = { - root : 'img/base.gif', - folder : 'img/folder.gif', - folderOpen : 'img/folderopen.gif', - node : 'img/page.gif', - empty : 'img/empty.gif', - line : 'img/line.gif', - join : 'img/join.gif', - joinBottom : 'img/joinbottom.gif', - plus : 'img/plus.gif', - plusBottom : 'img/plusbottom.gif', - minus : 'img/minus.gif', - minusBottom : 'img/minusbottom.gif', - nlPlus : 'img/nolines_plus.gif', - nlMinus : 'img/nolines_minus.gif' - }; this.obj = objName; - this.aNodes = []; - this.aIndent = []; - this.root = new Node(-1); - this.selectedNode = null; - this.selectedFound = false; - this.completed = false; return this; }; dTree.prototype = { + obj: null, + config: { + target: null, + hideRoot: false, + folderLinks: true, + useSelection: true, + useCookies: false, + useLines: true, + useIcons: true, + useStatusText: false, + closeSameLevel: false, + inOrder: false + }, + icon: { + root: 'img/base.gif', + folder: 'img/folder.gif', + folderOpen: 'img/folderopen.gif', + node: 'img/page.gif', + empty: 'img/empty.gif', + line: 'img/line.gif', + join: 'img/join.gif', + joinBottom: 'img/joinbottom.gif', + plus: 'img/plus.gif', + plusBottom: 'img/plusbottom.gif', + minus: 'img/minus.gif', + minusBottom: 'img/minusbottom.gif', + nlPlus: 'img/nolines_plus.gif', + nlMinus: 'img/nolines_minus.gif' + }, + aNodes: [], + aIndent: [], + root: new Node(-1), + selectedNode: null, + selectedFound: false, + completed: false, + // Adds a new node to the node array add: function(id, pid, name, isParent, url, datatype, title, target, icon, iconOpen, open, hasUnseen) { From 5643fd2f3f048ce26842874356c15595288b4ed2 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 11 Jun 2009 19:55:13 +0000 Subject: [PATCH 6/7] Monotone-Parent: 87a9edec020f812d113ea5bde21c2d30b040ab87 Monotone-Revision: c00d2fadae3d5733fb53c91e14b43a56d1e1ca58 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-06-11T19:55:13 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 8 +++ SoObjects/Contacts/SOGoUserFolder+Contacts.h | 1 - SoObjects/SOGo/SOGoGCSFolder.m | 2 +- SoObjects/SOGo/SOGoUserFolder.m | 3 +- UI/MainUI/SOGoUserHomePage.m | 65 +++++++++---------- .../UIxContactsUserFolders.js | 6 +- UI/WebServerResources/generic.js | 17 ++++- 7 files changed, 60 insertions(+), 42 deletions(-) diff --git a/ChangeLog b/ChangeLog index d5cc529f0..8e7a3278e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2009-06-11 Wolfgang Sourdeau + + * UI/MainUI/SOGoUserHomePage.m (-usersSearchAction): do not return + the user information for the current user. + (-foldersSearchAction): the method only search folders for the + owner of the current folder. The "user" parameter has thus been + removed. + 2009-06-10 Wolfgang Sourdeau * SoObjects/SOGo/NSString+Utilities.m (-stringByDetectingURLs): diff --git a/SoObjects/Contacts/SOGoUserFolder+Contacts.h b/SoObjects/Contacts/SOGoUserFolder+Contacts.h index 9d8b9d3be..89f1ca0a3 100644 --- a/SoObjects/Contacts/SOGoUserFolder+Contacts.h +++ b/SoObjects/Contacts/SOGoUserFolder+Contacts.h @@ -24,7 +24,6 @@ #define SOGOUSERFOLDER_CONTACTS_H @class NSArray; -@class NSString; #import diff --git a/SoObjects/SOGo/SOGoGCSFolder.m b/SoObjects/SOGo/SOGoGCSFolder.m index 62ff946c2..e5f219abf 100644 --- a/SoObjects/SOGo/SOGoGCSFolder.m +++ b/SoObjects/SOGo/SOGoGCSFolder.m @@ -718,7 +718,7 @@ static NSArray *childRecordFields = nil; currentUser = [localContext activeUser]; - if (delegatedUsers && [delegatedUsers count]) + if ([delegatedUsers count]) { if (![currentUser isSuperUser]) { diff --git a/SoObjects/SOGo/SOGoUserFolder.m b/SoObjects/SOGo/SOGoUserFolder.m index 2f9505dfc..99bdaec51 100644 --- a/SoObjects/SOGo/SOGoUserFolder.m +++ b/SoObjects/SOGo/SOGoUserFolder.m @@ -129,7 +129,8 @@ static NSString *LDAPContactInfoAttribute = nil; for (count = 0; count < max; count++) { node = [children objectAtIndex: count]; - componentName = [[(id)node attribute: @"name"] lowercaseString]; + componentName = [[(id)node attribute: @"name"] + lowercaseString]; [filter setObject: [node textValue] forKey: componentName]; } diff --git a/UI/MainUI/SOGoUserHomePage.m b/UI/MainUI/SOGoUserHomePage.m index 793d0878b..3dee81769 100644 --- a/UI/MainUI/SOGoUserHomePage.m +++ b/UI/MainUI/SOGoUserHomePage.m @@ -289,16 +289,17 @@ static NSString *LDAPContactInfoAttribute = nil; return response; } -- (WOResponse *) _usersResponseForResults: (NSEnumerator *) users +- (WOResponse *) _usersResponseForResults: (NSArray *) users { WOResponse *response; NSString *uid; NSMutableString *responseString; NSDictionary *contact; - NSString *contactInfo; + NSString *contactInfo, *login; NSArray *allUsers; int i; + login = [[context activeUser] login]; response = [context response]; [response setStatus: 200]; [response setHeader: @"text/plain; charset=utf-8" @@ -308,25 +309,28 @@ static NSString *LDAPContactInfoAttribute = nil; // We sort our array - this is pretty useful for the Web // interface of SOGo. - allUsers = [[users allObjects] - sortedArrayUsingSelector: @selector(caseInsensitiveDisplayNameCompare:)]; + allUsers = [users + sortedArrayUsingSelector: @selector (caseInsensitiveDisplayNameCompare:)]; for (i = 0; i < [allUsers count]; i++) { contact = [allUsers objectAtIndex: i]; uid = [contact objectForKey: @"c_uid"]; - if ([LDAPContactInfoAttribute length]) - { - contactInfo = [contact objectForKey: LDAPContactInfoAttribute]; - if (!contactInfo) - contactInfo = @""; - } - else - contactInfo = @""; - [responseString appendFormat: @"%@:%@:%@:%@\n", uid, - [contact objectForKey: @"cn"], - [contact objectForKey: @"c_email"], - contactInfo]; + if (![uid isEqualToString: login]) + { + if ([LDAPContactInfoAttribute length]) + { + contactInfo = [contact objectForKey: LDAPContactInfoAttribute]; + if (!contactInfo) + contactInfo = @""; + } + else + contactInfo = @""; + [responseString appendFormat: @"%@:%@:%@:%@\n", uid, + [contact objectForKey: @"cn"], + [contact objectForKey: @"c_email"], + contactInfo]; + } } [response appendContentString: responseString]; [responseString release]; @@ -339,14 +343,13 @@ static NSString *LDAPContactInfoAttribute = nil; NSString *contact; id result; LDAPUserManager *um; - NSEnumerator *users; um = [LDAPUserManager sharedUserManager]; contact = [self queryParameterForKey: @"search"]; if ([contact length]) { - users = [[um fetchUsersMatching: contact] objectEnumerator]; - result = [self _usersResponseForResults: users]; + result + = [self _usersResponseForResults: [um fetchUsersMatching: contact]]; } else result = [NSException exceptionWithHTTPStatus: 400 @@ -375,27 +378,23 @@ static NSString *LDAPContactInfoAttribute = nil; - (id ) foldersSearchAction { - NSString *contact, *folderType; + NSString *folderType; NSArray *folders; id result; + SOGoUserFolder *userFolder; - contact = [self queryParameterForKey: @"user"]; - if ([contact length]) + folderType = [self queryParameterForKey: @"type"]; + if ([folderType length]) { - folderType = [self queryParameterForKey: @"type"]; - if ([folderType length]) - { - folders = [[self clientObject] foldersOfType: folderType - forUID: contact]; - result = [self _foldersResponseForResults: folders]; - } - else - result = [NSException exceptionWithHTTPStatus: 400 - reason: @"missing 'type' parameter"]; + userFolder = [self clientObject]; + folders + = [userFolder foldersOfType: folderType + forUID: [userFolder ownerInContext: context]]; + result = [self _foldersResponseForResults: folders]; } else result = [NSException exceptionWithHTTPStatus: 400 - reason: @"missing 'user' parameter"]; + reason: @"missing 'type' parameter"]; return result; } diff --git a/UI/WebServerResources/UIxContactsUserFolders.js b/UI/WebServerResources/UIxContactsUserFolders.js index 68449cdd9..ded19b9fb 100644 --- a/UI/WebServerResources/UIxContactsUserFolders.js +++ b/UI/WebServerResources/UIxContactsUserFolders.js @@ -94,9 +94,9 @@ function onUserNodeToggle(event) { this.stopObserving("click", onUserNodeToggle); var person = this.parentNode.getAttribute("dataname"); - var url = (UserFolderURL + "foldersSearch" - + "?user=" + escape(person) - + "&type=" + window.opener.userFolderType); + + var url = (UserFolderURLForUser(person) + "foldersSearch" + + "?type=" + window.opener.userFolderType); var nodeId = this.getAttribute("id").substr(3); triggerAjaxRequest(url, foldersSearchCallback, { nodeId: nodeId, user: person }); diff --git a/UI/WebServerResources/generic.js b/UI/WebServerResources/generic.js index fa11b3858..d1523957f 100644 --- a/UI/WebServerResources/generic.js +++ b/UI/WebServerResources/generic.js @@ -352,9 +352,7 @@ function getContrastingTextColor(bgColor) { // Consider all colors with less than 56% brightness as dark colors and // use white as the foreground color, otherwise use black. - return ((brightness < 144) - ? "white" - : "black"); + return ((brightness < 144) ? "white" : "black"); } function triggerAjaxRequest(url, callback, userdata, content, headers) { @@ -1615,6 +1613,19 @@ function configureLinkBanner() { } } +/* accessing another user's data */ +function UserFolderURLForUser(user) { + var folderArray = UserFolderURL.split("/"); + var count; + if (UserFolderURL.endsWith('/')) + count = folderArray.length - 2; + else + count = folderArray.length - 1; + folderArray[count] = escape(user); + + return folderArray.join("/"); +} + /* folder creation */ function createFolder(name, okCB, notOkCB) { if (name) { From 6b61cd87013af2f3d622636c993789b5f00626e3 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 11 Jun 2009 22:13:10 +0000 Subject: [PATCH 7/7] Monotone-Parent: c00d2fadae3d5733fb53c91e14b43a56d1e1ca58 Monotone-Revision: b8d56bd5a31be825cfe66b8fe9f9a15269a09fbc Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2009-06-11T22:13:10 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 3 +++ SoObjects/SOGo/SOGoUserFolder.m | 40 +++++++++++++++++---------------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8e7a3278e..5673f01e6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2009-06-11 Wolfgang Sourdeau + * SoObjects/SOGo/SOGoUserFolder.m (-davUserQuery:): do not return + the user information for the current user. + * UI/MainUI/SOGoUserHomePage.m (-usersSearchAction): do not return the user information for the current user. (-foldersSearchAction): the method only search folders for the diff --git a/SoObjects/SOGo/SOGoUserFolder.m b/SoObjects/SOGo/SOGoUserFolder.m index 99bdaec51..bd82de9ad 100644 --- a/SoObjects/SOGo/SOGoUserFolder.m +++ b/SoObjects/SOGo/SOGoUserFolder.m @@ -382,13 +382,14 @@ static NSString *LDAPContactInfoAttribute = nil; LDAPUserManager *um; NSMutableString *fetch; NSDictionary *currentUser; - NSString *field; + NSString *field, *login; NSArray *users; int i; #warning the attributes returned here should match the one requested in the query fetch = [NSMutableString string]; + login = [[context activeUser] login]; um = [LDAPUserManager sharedUserManager]; // We sort our array - this is pretty useful for the @@ -398,25 +399,26 @@ static NSString *LDAPContactInfoAttribute = nil; for (i = 0; i < [users count]; i++) { currentUser = [users objectAtIndex: i]; - - [fetch appendString: @""]; field = [currentUser objectForKey: @"c_uid"]; - [fetch appendFormat: @"%@", - [field stringByEscapingXMLString]]; - field = [currentUser objectForKey: @"cn"]; - [fetch appendFormat: @"%@", - [field stringByEscapingXMLString]]; - field = [currentUser objectForKey: @"c_email"]; - [fetch appendFormat: @"%@", - [field stringByEscapingXMLString]]; - if (LDAPContactInfoAttribute) - { - field = [currentUser objectForKey: LDAPContactInfoAttribute]; - if ([field length]) - [fetch appendFormat: @"%@", - [field stringByEscapingXMLString]]; - } - [fetch appendString: @""]; + if (![field isEqualToString: login]) + { + [fetch appendFormat: @"%@", + [field stringByEscapingXMLString]]; + field = [currentUser objectForKey: @"cn"]; + [fetch appendFormat: @"%@", + [field stringByEscapingXMLString]]; + field = [currentUser objectForKey: @"c_email"]; + [fetch appendFormat: @"%@", + [field stringByEscapingXMLString]]; + if (LDAPContactInfoAttribute) + { + field = [currentUser objectForKey: LDAPContactInfoAttribute]; + if ([field length]) + [fetch appendFormat: @"%@", + [field stringByEscapingXMLString]]; + } + [fetch appendString: @""]; + } } return fetch;