]> err.no Git - scalable-opengroupware.org/commitdiff
added caching of folder hierarchies
authorhelge <helge@d1b88da0-ebda-0310-925b-ed51d893ca5b>
Tue, 28 Sep 2004 17:04:42 +0000 (17:04 +0000)
committerhelge <helge@d1b88da0-ebda-0310-925b-ed51d893ca5b>
Tue, 28 Sep 2004 17:04:42 +0000 (17:04 +0000)
git-svn-id: http://svn.opengroupware.org/SOGo/trunk@328 d1b88da0-ebda-0310-925b-ed51d893ca5b

SOGo/SoObjects/Mailer/ChangeLog
SOGo/SoObjects/Mailer/SOGoMailManager.m
SOGo/SoObjects/Mailer/Version
SOGo/UI/Mailer/Images/tbtv_leaf_corner_17x17.gif

index a09f9772d79c72f2fcf4ba6e77c9928ed159a524..07169710990d7f54f369c8e6bc777fdbefe50a09 100644 (file)
@@ -1,5 +1,7 @@
 2004-09-28  Helge Hess  <helge.hess@opengroupware.org>
 
+       * SOGoMailManager.m: added caching of folder hierarchy (v0.9.11)
+
        * SOGoMailManager.m: added connection pooling (v0.9.10)
 
        * v0.9.9
index 89ce31fd2f5f316689f663b3448d5c718e39e7fc..96a5026ee1dcf8e6205c2b17ab402bcb981c26b6 100644 (file)
@@ -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 */
index 317960a726fc24e656b0d801367866c318018c26..c351558f441a4d159527ee99c46d76a467ff4349 100644 (file)
@@ -1,3 +1,3 @@
 # $Id$
 
-SUBMINOR_VERSION:=10
+SUBMINOR_VERSION:=11
index 33c9708add5205e286fdeff727ea8d95301393ed..5c73acab2b9b2f0a62828fc54baab80a7ee60739 100644 (file)
Binary files a/SOGo/UI/Mailer/Images/tbtv_leaf_corner_17x17.gif and b/SOGo/UI/Mailer/Images/tbtv_leaf_corner_17x17.gif differ