From a110bb6254df6f286467caa3e98b8265804bca19 Mon Sep 17 00:00:00 2001 From: helge Date: Tue, 28 Sep 2004 17:04:42 +0000 Subject: [PATCH] added caching of folder hierarchies git-svn-id: http://svn.opengroupware.org/SOGo/trunk@328 d1b88da0-ebda-0310-925b-ed51d893ca5b --- SOGo/SoObjects/Mailer/ChangeLog | 2 + SOGo/SoObjects/Mailer/SOGoMailManager.m | 118 +++++++++++++++--- SOGo/SoObjects/Mailer/Version | 2 +- .../Mailer/Images/tbtv_leaf_corner_17x17.gif | Bin 625 -> 602 bytes 4 files changed, 107 insertions(+), 15 deletions(-) diff --git a/SOGo/SoObjects/Mailer/ChangeLog b/SOGo/SoObjects/Mailer/ChangeLog index a09f9772..07169710 100644 --- a/SOGo/SoObjects/Mailer/ChangeLog +++ b/SOGo/SoObjects/Mailer/ChangeLog @@ -1,5 +1,7 @@ 2004-09-28 Helge Hess + * SOGoMailManager.m: added caching of folder hierarchy (v0.9.11) + * SOGoMailManager.m: added connection pooling (v0.9.10) * v0.9.9 diff --git a/SOGo/SoObjects/Mailer/SOGoMailManager.m b/SOGo/SoObjects/Mailer/SOGoMailManager.m index 89ce31fd..96a5026e 100644 --- a/SOGo/SoObjects/Mailer/SOGoMailManager.m +++ b/SOGo/SoObjects/Mailer/SOGoMailManager.m @@ -40,6 +40,9 @@ - (NSDate *)creationTime; +- (void)cacheHierarchyResults:(NSDictionary *)_hierarchy; +- (NSDictionary *)cachedHierarchyResults; + @end @implementation SOGoMailManager @@ -92,6 +95,17 @@ static NSTimeInterval PoolScanInterval = 5 * 60; [_url scheme], [_url user], [_url host], [_url port]]; } +- (SOGoMailConnectionEntry *)entryForURL:(NSURL *)_url { + if (_url == nil) + return nil; + + return [self->urlToEntry objectForKey:[self cacheKeyForURL:_url]]; +} +- (void)cacheEntry:(SOGoMailConnectionEntry *)_entry forURL:(NSURL *)_url { + if (_entry == nil) _entry = (id)[NSNull null]; + [self->urlToEntry setObject:_entry forKey:[self cacheKeyForURL:_url]]; +} + - (void)_garbageCollect:(NSTimer *)_timer { // TODO: scan for old IMAP4 channels [self debugWithFormat:@"should collect IMAP4 channels (%d active)", @@ -105,14 +119,13 @@ static NSTimeInterval PoolScanInterval = 5 * 60; SOGoMailConnectionEntry *entry; NGImap4Client *client; NSDictionary *result; - NSString *cacheKey; if (_url == nil) return nil; - cacheKey = [self cacheKeyForURL:_url]; + /* check connection pool */ - if ((entry = [self->urlToEntry objectForKey:cacheKey]) != nil) { + if ((entry = [self entryForURL:_url]) != nil) { if ([entry isValidPassword:_pwd]) { [self debugWithFormat:@"reused IMAP4 connection for URL: %@", _url]; return [entry client]; @@ -122,6 +135,8 @@ static NSTimeInterval PoolScanInterval = 5 * 60; entry = nil; } + /* setup connection and attempt login */ + if ((client = [NGImap4Client clientWithURL:_url]) == nil) return nil; @@ -130,20 +145,22 @@ static NSTimeInterval PoolScanInterval = 5 * 60; [self logWithFormat:@"ERROR: IMAP4 login failed!"]; return nil; } - + [self debugWithFormat:@"created new IMAP4 connection for URL: %@", _url]; + + /* cache connection in pool */ + entry = [[SOGoMailConnectionEntry alloc] initWithClient:client password:_pwd]; - [self->urlToEntry setObject:entry forKey:cacheKey]; + [self cacheEntry:entry forURL:_url]; [entry release]; entry = nil; + return client; } /* folder hierarchy */ - (NSArray *)_getDirectChildren:(NSArray *)_array folderName:(NSString *)_fn { - // TODO: we should get the full list of folders _once_ and work on that - // (we could cache it in the context) NSMutableArray *ma; unsigned i, count, prefixlen; @@ -159,8 +176,13 @@ static NSTimeInterval PoolScanInterval = 5 * 60; p = [_array objectAtIndex:i]; if ([p length] <= prefixlen) continue; + if (![p hasPrefix:_fn]) + continue; + + /* cut of common part */ p = [p substringFromIndex:prefixlen]; + /* check whether the path is a sub-subfolder path */ if ([p rangeOfString:@"/"].length > 0) continue; @@ -192,27 +214,88 @@ static NSTimeInterval PoolScanInterval = 5 * 60; [self imap4Separator]]; } +- (NSArray *)extractSubfoldersForURL:(NSURL *)_url + fromResultSet:(NSDictionary *)_result +{ + NSString *folderName; + NSDictionary *result; + NSArray *names; + NSArray *flags; + + /* Note: the result is normalized, that is, it contains / as the separator */ + folderName = [_url path]; + if ([folderName hasPrefix:@"/"]) + folderName = [folderName substringFromIndex:1]; + + result = [_result valueForKey:@"list"]; + + /* Cyrus already tells us whether we need to check for children */ + flags = [result objectForKey:folderName]; + if ([flags containsObject:@"hasnochildren"]) + return nil; + + names = [self _getDirectChildren:[result allKeys] folderName:folderName]; +#if 0 + [self debugWithFormat:@"subfolders of %@: %@", folderName, + [names componentsJoinedByString:@","]]; +#endif + return names; +} + - (NSArray *)subfoldersForURL:(NSURL *)_url password:(NSString *)_pwd { // TODO: add caching + SOGoMailConnectionEntry *entry; NGImap4Client *client; NSDictionary *result; - NSString *folderName; - if ((client = [self imap4ClientForURL:_url password:_pwd]) == nil) + /* check cache */ + + if ((entry = [self entryForURL:_url]) != nil) { + if ([entry isValidPassword:_pwd]) { + NSDictionary *allFolders; + + [self debugWithFormat:@"valid password, reusing folder cache .."]; + if ((allFolders = [entry cachedHierarchyResults]) != nil) + return [self extractSubfoldersForURL:_url fromResultSet:allFolders]; + + [self debugWithFormat:@" no folders cached yet .."]; + } + + /* different password, password could have changed! */ + entry = nil; + } + else + [self debugWithFormat:@"no connection cached yet for url: %@", _url]; + + /* get client */ + + client = [entry isValidPassword:_pwd] + ? [entry client] + : [self imap4ClientForURL:_url password:_pwd]; + if (client == nil) return nil; - folderName = [self imap4FolderNameForURL:_url]; + /* fetch _all_ folders */ - /* maybe we want to use a cache over here */ - result = [client list:folderName pattern:@"*"]; + result = [client list:@"INBOX" pattern:@"*"]; if (![[result valueForKey:@"result"] boolValue]) { [self logWithFormat:@"ERROR: listing of folder failed!"]; return nil; } + /* cache results */ + + if ([result isNotNull]) { + if (entry == nil) /* required in case the entry was not setup */ + entry = [self entryForURL:_url]; + + [entry cacheHierarchyResults:result]; + [self debugWithFormat:@"cached results in entry %@: %@", entry, result]; + } + /* extract list */ - result = [result valueForKey:@"list"]; - return [self _getDirectChildren:[result allKeys] folderName:folderName]; + + return [self extractSubfoldersForURL:_url fromResultSet:result]; } /* debugging */ @@ -264,4 +347,11 @@ static NSTimeInterval PoolScanInterval = 5 * 60; return self->creationTime; } +- (void)cacheHierarchyResults:(NSDictionary *)_hierarchy { + ASSIGNCOPY(self->subfolders, _hierarchy); +} +- (NSDictionary *)cachedHierarchyResults { + return self->subfolders; +} + @end /* SOGoMailConnectionEntry */ diff --git a/SOGo/SoObjects/Mailer/Version b/SOGo/SoObjects/Mailer/Version index 317960a7..c351558f 100644 --- a/SOGo/SoObjects/Mailer/Version +++ b/SOGo/SoObjects/Mailer/Version @@ -1,3 +1,3 @@ # $Id$ -SUBMINOR_VERSION:=10 +SUBMINOR_VERSION:=11 diff --git a/SOGo/UI/Mailer/Images/tbtv_leaf_corner_17x17.gif b/SOGo/UI/Mailer/Images/tbtv_leaf_corner_17x17.gif index 33c9708add5205e286fdeff727ea8d95301393ed..5c73acab2b9b2f0a62828fc54baab80a7ee60739 100644 GIT binary patch delta 214 zcmey!a*Jg{FJrw90}u!TAp`sVhLWb{me%GRJ3UQpm+-8%W>@FzqF5b^fQ$(xCh__6 zgH&ZC#6@kxbDOnN($=n98_KUA(yW%?W2~#Lq9iXXB`#>TqC_RiFmXa&9G^jWiE@~3 zaeC6V>+XfTtezzbf$9Y@kDtUirSdSjmB{(3WCnly@>Jd41F z{&Q@yit|_)4^4Q;Ct}I7V)5tXrdA$t4UdKk4F{Q6*%=f9oY=d0SXkIr#H^g;&?FUU Oc5;sAX0^Ev4AuY?-bY6O delta 237 zcmcb`@{wgjFJrypKT+qR)Wnk16ovB4k_?5Aj8p}8Pu~Cr9R?r}1VRS(y$vNz%`L5M z?H!%%Id*!Q+AiT)ovzN=MX@>-0T~@8@%ambRAnT@MQy`#o3&EX)^AuJ%C8^Ntd`(o ztgEh~Brhu^E@-x@L?y~Fu{|%2&mg=+IZU@WJ?X~HRQEz&R?iZJK=p!{r_W-XQhAu% zO5}W1GJ`*V3ATymW_&B-p_J^+z^u3Pp-ZEkm2^oG&pd|>KF+KNF3Ot>dnNNl@eH@A;4e_0LSA>aR2}S -- 2.39.5