Monotone-Parent: 584371c66b4989feaab5012db26f19d8ed7cd7ad

Monotone-Revision: 72a4f60ec4a14476e485da2ce400df860572fa48

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2010-01-05T22:34:35
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Wolfgang Sourdeau 2010-01-05 22:34:35 +00:00
parent 7c3b61134a
commit aa7e1d2f5a
15 changed files with 987 additions and 241 deletions

View File

@ -1,7 +1,34 @@
2010-01-05 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* UI/WebServerResources/MailerUI.js (Mailbox): "this.name" is now
an escaped form of the mailbox name, that can thus be used to
generate folder URLs.
(Mailbox.findMailboxByName): escape the name passed as parameter
prior to doing a search.
* UI/WebServerResources/JavascriptAPIExtensions.js
(asCSSIdentifier): use two arrays rather than an "Object" in order
to improve performance.
* SoObjects/SOGo/NSString+Utilities.m (-fromCSSIdentifier): new
method that converts an escaped string back to a normal one.
(-asCSSIdentifier): no longer use "replaceString:withString:" in
order to avoid parsing the string multiple times. This probably
enhance performances a bit and also avoid double-encoding
problems.
* SoObjects/SOGo/NSArray+Utilities.m (-resultsOfSelector): new
method that applies a selector on the contained objects and
collect the result objects in a new array.
* SoObjects/Mailer/SOGoMailFolder.m
(-lookupName:inContext:acquire:): we must check and create the
current folder even if the looked up key is a subfolder or a web
method.
* SOPE/sope-patchset-r1664.diff: new patchset replacing
-r1660.diff.
Added code to handle IMAP namespaces.
2010-01-04 Wolfgang Sourdeau <wsourdeau@inverse.ca>

File diff suppressed because it is too large Load Diff

View File

@ -11,12 +11,13 @@ Mailer_OBJC_FILES += \
\
SOGoMailManager.m \
\
SOGoDraftObject.m \
SOGoMailBaseObject.m \
SOGoMailAccounts.m \
SOGoMailAccount.m \
SOGoMailFolder.m \
SOGoMailNamespace.m \
SOGoMailObject.m \
SOGoDraftObject.m \
SOGoMailObject+Draft.m \
SOGoSentFolder.m \
SOGoDraftsFolder.m \

View File

@ -23,7 +23,7 @@
#ifndef __Mailer_SOGoMailAccount_H__
#define __Mailer_SOGoMailAccount_H__
#import <SoObjects/Mailer/SOGoMailBaseObject.h>
#import <Mailer/SOGoMailBaseObject.h>
/*
SOGoMailAccount
@ -37,9 +37,10 @@
@class NSArray;
@class NSString;
#import "SOGoDraftsFolder.h"
#import "SOGoSentFolder.h"
#import "SOGoTrashFolder.h"
@class SOGoMailFolder;
@class SOGoDraftsFolder;
@class SOGoSentFolder;
@class SOGoTrashFolder;
typedef enum {
undefined = -1,

View File

@ -39,6 +39,7 @@
#import <NGImap4/NGSieveClient.h>
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoDomainDefaults.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
@ -47,6 +48,7 @@
#import "SOGoDraftsFolder.h"
#import "SOGoMailFolder.h"
#import "SOGoMailManager.h"
#import "SOGoMailNamespace.h"
#import "SOGoSentFolder.h"
#import "SOGoTrashFolder.h"
@ -94,25 +96,56 @@ static NSString *sieveScriptName = @"sogo";
return NO;
}
- (void) _appendNamespace: (NSArray *) namespace
toFolders: (NSMutableArray *) folders
{
NSString *newFolder;
NSDictionary *currentPart;
int count, max;
max = [namespace count];
for (count = 0; count < max; count++)
{
currentPart = [namespace objectAtIndex: count];
newFolder
= [[currentPart objectForKey: @"prefix"] substringFromIndex: 1];
if ([newFolder length])
[folders addObject: newFolder];
}
}
- (void) _appendNamespaces: (NSMutableArray *) folders
{
NSDictionary *namespaceDict;
NSArray *namespace;
NGImap4Client *client;
client = [[self imap4Connection] client];
namespaceDict = [client namespace];
namespace = [namespaceDict objectForKey: @"personal"];
if (namespace)
[self _appendNamespace: namespace toFolders: folders];
namespace = [namespaceDict objectForKey: @"other users"];
if (namespace)
[self _appendNamespace: namespace toFolders: folders];
namespace = [namespaceDict objectForKey: @"shared"];
if (namespace)
[self _appendNamespace: namespace toFolders: folders];
}
- (NSArray *) toManyRelationshipKeys
{
NSMutableArray *folders;
NSArray *imapFolders, *additionalFolders;
folders = [NSMutableArray array];
NSArray *imapFolders;
imapFolders = [[self imap4Connection] subfoldersForURL: [self imap4URL]];
additionalFolders
= [NSArray arrayWithObject: [self draftsFolderNameInContext: nil]];
if ([imapFolders count] > 0)
[folders addObjectsFromArray: imapFolders];
if ([additionalFolders count] > 0)
{
[folders removeObjectsInArray: additionalFolders];
[folders addObjectsFromArray: additionalFolders];
}
return [folders stringsWithFormat: @"folder%@"];
folders = [imapFolders mutableCopy];
[folders autorelease];
[folders addObjectUniquely: [self draftsFolderNameInContext: nil]];
[self _appendNamespaces: folders];
return [[folders stringsWithFormat: @"folder%@"]
resultsOfSelector: @selector (asCSSIdentifier)];
}
- (SOGoIMAPAclStyle) imapAclStyle
@ -300,15 +333,32 @@ static NSString *sieveScriptName = @"sogo";
return self;
}
- (NSArray *) _allFoldersFromNS: (NSString *) namespace
subscribedOnly: (BOOL) subscribedOnly
{
NSArray *folders;
NSURL *nsURL;
NSString *baseURLString, *urlString;
baseURLString = [[self imap4URL] absoluteString];
urlString = [NSString stringWithFormat: @"%@%@/", baseURLString, [namespace stringByEscapingURL]];
nsURL = [NSURL URLWithString: urlString];
folders = [[self imap4Connection] allFoldersForURL: nsURL
onlySubscribedFolders: subscribedOnly];
return folders;
}
- (NSArray *) allFolderPaths
{
NSMutableArray *folderPaths;
NSArray *rawFolders, *mainFolders;
NSMutableArray *folderPaths, *namespaces;
NSArray *folders, *mainFolders;
SOGoUserDefaults *ud;
BOOL subscribedOnly;
int count, max;
ud = [[context activeUser] userDefaults];
rawFolders = [[self imap4Connection] allFoldersForURL: [self imap4URL]
onlySubscribedFolders: [ud mailShowSubscribedFoldersOnly]];
subscribedOnly = [ud mailShowSubscribedFoldersOnly];
mainFolders = [[NSArray arrayWithObjects:
[self inboxFolderNameInContext: context],
@ -316,8 +366,24 @@ static NSString *sieveScriptName = @"sogo";
[self sentFolderNameInContext: context],
[self trashFolderNameInContext: context],
nil] stringsWithFormat: @"/%@"];
folderPaths = [NSMutableArray arrayWithArray: rawFolders];
folders = [[self imap4Connection] allFoldersForURL: [self imap4URL]
onlySubscribedFolders: subscribedOnly];
folderPaths = [folders mutableCopy];
[folderPaths autorelease];
[folderPaths removeObjectsInArray: mainFolders];
namespaces = [NSMutableArray arrayWithCapacity: 10];
[self _appendNamespaces: namespaces];
max = [namespaces count];
for (count = 0; count < max; count++)
{
folders = [self _allFoldersFromNS: [namespaces objectAtIndex: count]
subscribedOnly: subscribedOnly];
if ([folders count])
{
[folderPaths removeObjectsInArray: folders];
[folderPaths addObjectsFromArray: folders];
}
}
[folderPaths
sortUsingSelector: @selector (localizedCaseInsensitiveCompare:)];
[folderPaths replaceObjectsInRange: NSMakeRange (0, 0)
@ -417,14 +483,22 @@ static NSString *sieveScriptName = @"sogo";
acquire: (BOOL) _flag
{
NSString *folderName;
NSMutableArray *namespaces;
Class klazz;
id obj;
[[[self imap4Connection] client] namespace];
if ([_key hasPrefix: @"folder"])
{
folderName = [_key substringFromIndex: 6];
if ([folderName
isEqualToString: [self sentFolderNameInContext: _ctx]])
folderName = [[_key substringFromIndex: 6] fromCSSIdentifier];
namespaces = [NSMutableArray array];
[self _appendNamespaces: namespaces];
if ([namespaces containsObject: folderName])
klazz = [SOGoMailNamespace class];
else if ([folderName
isEqualToString: [self sentFolderNameInContext: _ctx]])
klazz = [SOGoSentFolder class];
else if ([folderName
isEqualToString: [self draftsFolderNameInContext: _ctx]])

View File

@ -44,6 +44,7 @@
#import <SOGo/DOMNode+SOGo.h>
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/NSString+DAV.h>
#import <SOGo/NSArray+DAV.h>
#import <SOGo/NSObject+DAV.h>
@ -59,6 +60,7 @@
#import "SOGoMailAccount.h"
#import "SOGoMailManager.h"
#import "SOGoMailFolder.h"
#import "SOGoTrashFolder.h"
#define XMLNS_INVERSEDAV @"urn:inverse:params:xml:ns:inverse-dav"
@ -113,7 +115,7 @@ static NSString *defaultUserID = @"anyone";
- (void) dealloc
{
[filenames release];
[filenames release];
[folderType release];
[mailboxACL release];
[super dealloc];
@ -123,7 +125,7 @@ static NSString *defaultUserID = @"anyone";
- (NSString *) relativeImap4Name
{
return [nameInContainer substringFromIndex: 6];
return [[nameInContainer substringFromIndex: 6] fromCSSIdentifier];
}
- (NSString *) absoluteImap4Name
@ -151,7 +153,11 @@ static NSString *defaultUserID = @"anyone";
- (NSArray *) toManyRelationshipKeys
{
return [self subfolders];
NSArray *subfolders;
subfolders = [[self subfolders] stringsWithFormat: @"folder%@"];
return [subfolders resultsOfSelector: @selector (asCSSIdentifier)];
}
- (NSArray *) subfolders
@ -251,7 +257,6 @@ static NSString *defaultUserID = @"anyone";
id result;
BOOL b;
trashFolder = [[self mailAccountFolder] trashFolderInContext: localContext];
if ([trashFolder isNotNull])
{
@ -392,35 +397,35 @@ static NSString *defaultUserID = @"anyone";
toFolder: (NSString *) destinationFolder
inContext: (id) localContext
{
NSEnumerator *folders;
NSArray *folders;
NSString *currentFolderName;
NSMutableString *imapDestinationFolder;
NGImap4Client *client;
id result;
int count, max;
#warning this code will fail on implementation using something else than '/' as delimiter
imapDestinationFolder = [NSMutableString string];
folders = [[destinationFolder componentsSeparatedByString: @"/"] objectEnumerator];
currentFolderName = [folders nextObject];
while (currentFolderName)
{
if ([currentFolderName hasPrefix: @"folder"])
folders = [[destinationFolder componentsSeparatedByString: @"/"]
resultsOfSelector: @selector (fromCSSIdentifier)];
max = [folders count];
for (count = 2; count < max; count++)
{
[imapDestinationFolder appendString: @"/"];
[imapDestinationFolder appendString: [currentFolderName substringFromIndex: 6]];
currentFolderName
= [[folders objectAtIndex: count] substringFromIndex: 6];
[imapDestinationFolder appendFormat: @"/%@", currentFolderName];
}
currentFolderName = [folders nextObject];
}
client = [[self imap4Connection] client];
[imap4 selectFolder: [self imap4URL]];
// We make sure the destination IMAP folder exist, if not, we create it.
result = [[client status: imapDestinationFolder flags: [NSArray arrayWithObject: @"UIDVALIDITY"]]
result = [[client status: imapDestinationFolder
flags: [NSArray arrayWithObject: @"UIDVALIDITY"]]
objectForKey: @"result"];
if (![result boolValue])
result = [[self imap4Connection] createMailbox: imapDestinationFolder atURL: [[self mailAccountFolder] imap4URL]];
result = [[self imap4Connection] createMailbox: imapDestinationFolder
atURL: [[self mailAccountFolder] imap4URL]];
if (!result || [result boolValue])
result = [client copyUids: uids toFolder: imapDestinationFolder];
@ -442,11 +447,10 @@ static NSString *defaultUserID = @"anyone";
client = [[self imap4Connection] client];
result = [self copyUIDs: uids toFolder: destinationFolder inContext: localContext];
if ( ![result isNotNull] )
if (![result isNotNull])
{
result = [client storeFlags: [NSArray arrayWithObject: @"Deleted"]
forUIDs: uids addOrRemove: YES];
forUIDs: uids addOrRemove: YES];
if ([[result valueForKey: @"result"] boolValue])
{
[self markForExpunge];
@ -555,51 +559,51 @@ static NSString *defaultUserID = @"anyone";
inContext: (id)_ctx
acquire: (BOOL) _acquire
{
NSString *folderName, *className;
NSString *folderName, *fullFolderName, *className;
SOGoMailAccount *mailAccount;
id obj;
if ([_key hasPrefix: @"folder"])
// We automatically create mailboxes that don't exist but that we're
// trying to open. This shouldn't happen unless a mailbox has been
// deleted "behind our back" or if we're trying to open a special
// mailbox that doesn't yet exist.
if ([[self imap4Connection] doesMailboxExistAtURL: [self imap4URL]]
|| ![[self imap4Connection] createMailbox: [self relativeImap4Name]
atURL: [[self mailAccountFolder] imap4URL]])
{
mailAccount = [self mailAccountFolder];
folderName = [NSString stringWithFormat: @"%@/%@",
[self traversalFromMailAccount],
[_key substringFromIndex: 6]];
if ([folderName
isEqualToString: [mailAccount sentFolderNameInContext: _ctx]])
className = @"SOGoSentFolder";
else if ([folderName isEqualToString:
[mailAccount draftsFolderNameInContext: _ctx]])
className = @"SOGoDraftsFolder";
else if ([folderName isEqualToString:
[mailAccount trashFolderNameInContext: _ctx]])
className = @"SOGoTrashFolder";
/* else if ([folderName isEqualToString:
[mailAccount sieveFolderNameInContext: _ctx]])
obj = [self lookupFiltersFolder: _key inContext: _ctx]; */
else
className = @"SOGoMailFolder";
obj = [super lookupName: _key inContext: _ctx acquire: NO];
if (!obj)
{
if ([_key hasPrefix: @"folder"])
{
mailAccount = [self mailAccountFolder];
folderName = [[_key substringFromIndex: 6] fromCSSIdentifier];
fullFolderName = [NSString stringWithFormat: @"%@/%@",
[self traversalFromMailAccount], folderName];
if ([fullFolderName
isEqualToString: [mailAccount sentFolderNameInContext: _ctx]])
className = @"SOGoSentFolder";
else if ([fullFolderName isEqualToString:
[mailAccount draftsFolderNameInContext: _ctx]])
className = @"SOGoDraftsFolder";
else if ([fullFolderName isEqualToString:
[mailAccount trashFolderNameInContext: _ctx]])
className = @"SOGoTrashFolder";
/* else if ([folderName isEqualToString:
[mailAccount sieveFolderNameInContext: _ctx]])
obj = [self lookupFiltersFolder: _key inContext: _ctx]; */
else
className = @"SOGoMailFolder";
obj = [NSClassFromString (className)
objectWithName: _key inContainer: self];
obj = [NSClassFromString (className) objectWithName: _key
inContainer: self];
}
else if (isdigit ([_key characterAtIndex: 0]))
obj = [SOGoMailObject objectWithName: _key inContainer: self];
}
}
else
{
// We automatically create mailboxes that don't exist but that we're
// trying to open. This shouldn't happen unless a mailbox has been
// deleted "behind our back" or if we're trying to open a special
// mailbox that doesn't yet exist.
if ([[self imap4Connection] doesMailboxExistAtURL: [self imap4URL]] ||
![[self imap4Connection] createMailbox: [self relativeImap4Name] atURL: [[self mailAccountFolder] imap4URL]])
{
if (isdigit ([_key characterAtIndex: 0]))
obj = [SOGoMailObject objectWithName: _key inContainer: self];
else
obj = [super lookupName: _key inContext: _ctx acquire: NO];
}
else
obj = nil;
}
obj = nil;
if (!obj && _acquire)
obj = [NSException exceptionWithHTTPStatus: 404 /* Not Found */];

View File

@ -0,0 +1,32 @@
/* SOGoMailNamespace.h - this file is part of SOGo
*
* Copyright (C) 2010 Wolfgang Sourdeau
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* 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 SOGOMAILNAMESPACE_H
#define SOGOMAILNAMESPACE_H
#import "SOGoMailFolder.h"
@interface SOGoMailNamespace : SOGoMailFolder
@end
#endif /* SOGOMAILNAMESPACE_H */

View File

@ -0,0 +1,32 @@
/* SOGoMailNamespace.m - this file is part of SOGo
*
* Copyright (C) 2010 Wolfgang Sourdeau
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* 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.
*/
#import "SOGoMailNamespace.h"
@implementation SOGoMailNamespace
- (NSArray *) toOneRelationshipKeys
{
return nil;
}
@end

View File

@ -51,6 +51,8 @@
withObject: (id) object1
withObject: (id) object2;
#endif
/* foreach ... */
- (NSArray *) resultsOfSelector: (SEL) operation;
@end

View File

@ -36,7 +36,7 @@
unsigned int max;
max = [self count];
pointers = NSZoneMalloc (NULL, sizeof(id) * (max + 1));
pointers = NSZoneMalloc (NULL, sizeof (id) * (max + 1));
[self getObjects: pointers];
*(pointers + max) = nil;
@ -154,6 +154,12 @@
return newArray;
}
- (NSArray *) trimmedComponents
{
return [self resultsOfSelector: @selector (stringByTrimmingSpaces)];
}
#ifdef GNUSTEP_BASE_LIBRARY
- (void) makeObjectsPerform: (SEL) selector
withObject: (id) object1
withObject: (id) object2
@ -166,6 +172,24 @@
withObject: object1
withObject: object2];
}
#endif
- (NSArray *) resultsOfSelector: (SEL) operation
{
NSMutableArray *results;
int count, max;
id result;
max = [self count];
results = [NSMutableArray arrayWithCapacity: max];
for (count = 0; count < max; count++)
{
result = [[self objectAtIndex: count] performSelector: operation];
[results addObject: result];
}
return results;
}
- (NSString *) jsonRepresentation
{
@ -204,23 +228,6 @@
return response;
}
- (NSArray *) trimmedComponents
{
NSMutableArray *newComponents;
NSString *currentString;
unsigned int count, max;
max = [self count];
newComponents = [NSMutableArray arrayWithCapacity: max];
for (count = 0; count < max; count++)
{
currentString = [[self objectAtIndex: count] stringByTrimmingSpaces];
[newComponents addObject: currentString];
}
return newComponents;
}
@end
@implementation NSMutableArray (SOGoArrayUtilities)

View File

@ -47,7 +47,7 @@
- (NSString *) jsonRepresentation;
- (NSString *) asCSSIdentifier;
- (NSString *) fromCSSIdentifier;
/* bare email addresses */
- (NSString *) pureEMailAddress;

View File

@ -27,6 +27,7 @@
#import <EOControl/EOQualifier.h>
#import <NGExtensions/NSDictionary+misc.h>
#import <NGExtensions/NGQuotedPrintableCoding.h>
#import "NSArray+Utilities.h"
@ -39,6 +40,10 @@ static NSMutableCharacterSet *urlNonEndingChars = nil;
static NSMutableCharacterSet *urlAfterEndingChars = nil;
static NSMutableCharacterSet *urlStartChars = nil;
static NSString **cssEscapingStrings = NULL;
static unichar *cssEscapingCharacters = NULL;
static int cssEscapingCount = 0;
@implementation NSString (SOGoURLExtension)
- (NSString *) composeURLWithAction: (NSString *) action
@ -305,23 +310,109 @@ static NSMutableCharacterSet *urlStartChars = nil;
return [self doubleQuotedString];
}
- (void) _setupCSSEscaping
{
NSArray *strings, *characters;
int count;
strings = [NSArray arrayWithObjects: @"_U_", @"_D_", @"_H_", @"_A_", @"_S_",
@"_C_", @"_CO_", @"_SP_", nil];
cssEscapingStrings = [strings asPointersOfObjects];
characters = [NSArray arrayWithObjects: @"_", @".", @"#", @"@", @"*", @":",
@",", @" ", nil];
cssEscapingCharacters
= NSZoneMalloc (NULL, sizeof ((cssEscapingCount + 1) * sizeof (unichar)));
cssEscapingCount = [strings count];
for (count = 0; count < cssEscapingCount; count++)
*(cssEscapingCharacters + count)
= [[characters objectAtIndex: count] characterAtIndex: 0];
*(cssEscapingCharacters + cssEscapingCount) = 0;
}
- (int) _cssCharacterIndex: (unichar) character
{
int idx, count;
idx = -1;
for (count = 0; idx == -1 && count < cssEscapingCount; count++)
if (*(cssEscapingCharacters + count) == character)
idx = count;
return idx;
}
- (NSString *) asCSSIdentifier
{
NSMutableString *cssIdentifier;
unichar currentChar;
int count, max, idx;
cssIdentifier = [NSMutableString stringWithString: self];
[cssIdentifier replaceString: @"_" withString: @"_U_"];
[cssIdentifier replaceString: @"." withString: @"_D_"];
[cssIdentifier replaceString: @"#" withString: @"_H_"];
[cssIdentifier replaceString: @"@" withString: @"_A_"];
[cssIdentifier replaceString: @"*" withString: @"_S_"];
[cssIdentifier replaceString: @":" withString: @"_C_"];
[cssIdentifier replaceString: @"," withString: @"_CO_"];
[cssIdentifier replaceString: @" " withString: @"_SP_"];
if (!cssEscapingStrings)
[self _setupCSSEscaping];
cssIdentifier = [NSMutableString string];
max = [self length];
for (count = 0; count < max; count++)
{
currentChar = [self characterAtIndex: count];
idx = [self _cssCharacterIndex: currentChar];
if (idx > -1)
[cssIdentifier appendString: cssEscapingStrings[idx]];
else
[cssIdentifier appendFormat: @"%lc", currentChar];
}
return cssIdentifier;
}
- (int) _cssStringIndex: (NSString *) string
{
int idx, count;
idx = -1;
for (count = 0; idx == -1 && count < cssEscapingCount; count++)
if ([string hasPrefix: *(cssEscapingStrings + count)])
idx = count;
return idx;
}
- (NSString *) fromCSSIdentifier
{
NSMutableString *newString;
NSString *currentString;
int count, length, max, idx;
if (!cssEscapingStrings)
[self _setupCSSEscaping];
newString = [NSMutableString string];
max = [self length];
for (count = 0; count < max - 2; count++)
{
/* The difficulty here is that most escaping strings are 3 chars long
except one. Therefore we must juggle a little bit with the lengths in
order to avoid an overflow exception. */
length = 4;
if (count + length > max)
length = max - count;
currentString = [self substringFromRange: NSMakeRange (count, length)];
idx = [self _cssStringIndex: currentString];
if (idx > -1)
{
[newString appendFormat: @"%lc", cssEscapingCharacters[idx]];
count += [cssEscapingStrings[idx] length] - 1;
}
else
[newString appendFormat: @"%lc", [self characterAtIndex: count]];
}
currentString = [self substringFromRange: NSMakeRange (count, max - count)];
[newString appendString: currentString];
return newString;
}
- (NSString *) pureEMailAddress
{
NSString *pureAddress;

View File

@ -59,21 +59,14 @@ String.prototype.asDate = function () {
return newDate;
};
String.prototype.asCSSIdentifier = function () {
var substitutions = { '_': '_U_',
'\\.': '_D_',
'#': '_H_',
'@': '_A_',
'\\*': '_S_',
':': '_C_',
',': '_CO_',
' ': '_SP_' };
var newString = this;
var re;
String.prototype.asCSSIdentifier = function() {
var characters = [ '_' , '\\.', '#' , '@' , '\\*', ':' , ',' , ' ' ];
var escapeds = [ '_U_', '_D_', '_H_', '_A_', '_S_', '_C_', '_CO_', '_SP_' ];
for (var key in substitutions) {
re = new RegExp(key, 'g');
newString = newString.replace(re, substitutions[key]);
var newString = this;
for (var i = 0; i < characters.length; i++) {
var re = new RegExp(characters[i], 'g');
newString = newString.replace(re, escapeds[i]);
}
return newString;

View File

@ -42,7 +42,7 @@ var messageCheckTimer;
/* We need to override this method since it is adapted to GCS-based folder
references, which we do not use here */
function URLForFolderID(folderID) {
var url = ApplicationBaseURL + encodeURI(folderID);
var url = ApplicationBaseURL + encodeURI(folderID.substr(1));
if (url[url.length-1] == '/')
url = url.substr(0, url.length-1);
@ -296,7 +296,6 @@ function ml_lowlight(sender) {
sender.className = "tableview";
}
function onUnload(event) {
var url = ApplicationBaseURL + encodeURI(Mailer.currentMailbox) + "/expunge";
@ -533,17 +532,17 @@ function onMailboxMenuMove(event) {
}
function onMailboxMenuCopy(event) {
var targetMailbox;
var messageList = $("messageList").down("TBODY");
var rows = messageList.getSelectedNodes();
var uids = new Array(); // message IDs
var paths = new Array(); // row IDs
var targetMailbox;
if (this.tagName == 'LI') // from contextual menu
targetMailbox = this.mailbox.fullName();
else // from DnD
targetMailbox = this.readAttribute("dataname");
for (var i = 0; i < rows.length; i++) {
var uid = rows[i].readAttribute("id").substr(4);
var path = Mailer.currentMailbox + "/" + uid;
@ -1748,7 +1747,7 @@ function updateMailboxTreeInPage() {
}
}
function mailboxMenuNode(type, name) {
function mailboxMenuNode(type, displayName) {
var newNode = document.createElement("li");
var icon = MailerUIdTreeExtension.folderIcons[type];
if (!icon)
@ -1756,9 +1755,9 @@ function mailboxMenuNode(type, name) {
var image = document.createElement("img");
image.src = ResourcesURL + "/" + icon;
newNode.appendChild(image);
var displayName = MailerUIdTreeExtension.folderNames[type];
if (!displayName)
displayName = name;
var dnOverride = MailerUIdTreeExtension.folderNames[type];
if (dnOverride)
displayName = dnOverride;
newNode.appendChild(document.createTextNode(" " + displayName));
return newNode;
@ -1804,7 +1803,7 @@ function generateMenuForMailbox(mailbox, prefix, callback) {
var submenuCount = 0;
var newNode;
for (var i = 0; i < mailbox.children.length; i++) {
if ( menu.offsetHeight > windowHeight-offset ) {
if (menu.offsetHeight > windowHeight-offset) {
var menuWidth = parseInt(menu.offsetWidth) + 15
menuWidth = menuWidth + "px";
menu.style.width = menuWidth;
@ -1814,7 +1813,7 @@ function generateMenuForMailbox(mailbox, prefix, callback) {
menuDIV.appendChild(menu);
}
var child = mailbox.children[i];
newNode = mailboxMenuNode(child.type, child.name);
newNode = mailboxMenuNode(child.type, child.displayName);
newNode.style.width = "auto";
menu.appendChild(newNode);
if (child.children.length > 0) {
@ -1831,8 +1830,7 @@ function generateMenuForMailbox(mailbox, prefix, callback) {
var menuWidth = parseInt(menu.offsetWidth) + 15
menuWidth = menuWidth + "px";
menu.style.width = menuWidth;
initMenu(menuDIV, callbacks);
return menuDIV.getAttribute("id");
@ -1912,7 +1910,7 @@ function onLoadMailboxesCallback(http) {
}
function buildMailboxes(accountKeys, encoded) {
var account = new Mailbox("account", accountKeys[0],
var account = new Mailbox("account", accountKeys[1],
undefined, //necessary, null will cause issues
accountKeys[1]);
var data = encoded.evalJSON(true);
@ -1926,9 +1924,10 @@ function buildMailboxes(accountKeys, encoded) {
var currentNode = account;
var names = mailboxes[i].path.split("/");
for (var j = 1; j < (names.length - 1); j++) {
var node = currentNode.findMailboxByName(names[j]);
var name = names[j];
var node = currentNode.findMailboxByName(name);
if (!node) {
node = new Mailbox("additional", names[j]);
node = new Mailbox("additional", name);
currentNode.addMailbox(node);
}
currentNode = node;
@ -2327,11 +2326,12 @@ document.observe("dom:loaded", initMailer);
function Mailbox(type, name, unseen, displayName) {
this.type = type;
this.name = name;
if (displayName)
this.displayName = displayName;
else
this.displayName = name;
// log("name: " + name + "; dn: " + displayName);
this.name = name.asCSSIdentifier();
this.unseen = unseen;
this.parentFolder = null;
this.children = new Array();
@ -2361,9 +2361,11 @@ Mailbox.prototype = {
findMailboxByName: function(name) {
var mailbox = null;
var searchName = name.asCSSIdentifier();
var i = 0;
while (!mailbox && i < this.children.length)
if (this.children[i].name == name
if (this.children[i].name == searchName
|| this.children[i].displayName == name)
mailbox = this.children[i];
else

View File

@ -26,7 +26,7 @@ var MailerUIdTreeExtension = {
displayName += "<span id=\"unseenCount\"> (<span>" + parseInt(unseen) + "</span>)</span>";
}
this.add(this.elementCounter, parent, displayName, 1, '#', fullName,
type, '', '', icon, icon, hasUnseen);
type, '', '', icon, icon, hasUnseen);
this.elementCounter++;
},
_addFolder: function (parent, folder) {