Monotone-Parent: 584371c66b4989feaab5012db26f19d8ed7cd7ad
Monotone-Revision: 72a4f60ec4a14476e485da2ce400df860572fa48 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2010-01-05T22:34:35 Monotone-Branch: ca.inverse.sogomaint-2.0.2
parent
7c3b61134a
commit
aa7e1d2f5a
27
ChangeLog
27
ChangeLog
|
@ -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
|
@ -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 \
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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]])
|
||||
|
|
|
@ -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 */];
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
|
@ -51,6 +51,8 @@
|
|||
withObject: (id) object1
|
||||
withObject: (id) object2;
|
||||
#endif
|
||||
/* foreach ... */
|
||||
- (NSArray *) resultsOfSelector: (SEL) operation;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
- (NSString *) jsonRepresentation;
|
||||
|
||||
- (NSString *) asCSSIdentifier;
|
||||
|
||||
- (NSString *) fromCSSIdentifier;
|
||||
|
||||
/* bare email addresses */
|
||||
- (NSString *) pureEMailAddress;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue