--- /dev/null
+/*
+ Copyright (C) 2004 SKYRIX Software AG
+
+ This file is part of OpenGroupware.org.
+
+ OGo is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ OGo 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 Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with OGo; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __SOGo_SOGoMailConnectionEntry_H__
+#define __SOGo_SOGoMailConnectionEntry_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+ SOGoMailConnectionEntry
+
+ A cached connection to an IMAP4 server plus some cached objects.
+*/
+
+@class NSString, NSDate, NSArray, NSDictionary, NSURL;
+@class NGImap4Client;
+
+@interface SOGoMailConnectionEntry : NSObject
+{
+@public
+ NGImap4Client *client;
+ NSString *password;
+ NSDate *creationTime;
+ NSDictionary *subfolders;
+
+ /* uids cache */
+ NSArray *cachedUIDs;
+ NSURL *uidFolderURL;
+ id uidSortOrdering;
+}
+
+- (id)initWithClient:(NGImap4Client *)_client password:(NSString *)_pwd;
+
+/* accessors */
+
+- (NGImap4Client *)client;
+- (BOOL)isValidPassword:(NSString *)_pwd;
+
+- (NSDate *)creationTime;
+
+- (void)cacheHierarchyResults:(NSDictionary *)_hierarchy;
+- (NSDictionary *)cachedHierarchyResults;
+
+- (id)cachedUIDsForURL:(NSURL *)_url qualifier:(id)_q sortOrdering:(id)_so;
+- (void)cacheUIDs:(NSArray *)_uids forURL:(NSURL *)_url
+ qualifier:(id)_q sortOrdering:(id)_so;
+
+@end
+
+#endif /* __SOGo_SOGoMailConnectionEntry_H__ */
--- /dev/null
+/*
+ Copyright (C) 2004 SKYRIX Software AG
+
+ This file is part of OpenGroupware.org.
+
+ OGo is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ OGo 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 Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with OGo; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "SOGoMailConnectionEntry.h"
+#include "common.h"
+
+@implementation SOGoMailConnectionEntry
+
+- (id)initWithClient:(NGImap4Client *)_client password:(NSString *)_pwd {
+ if (_client == nil || _pwd == nil) {
+ [self release];
+ return nil;
+ }
+
+ if ((self = [super init])) {
+ self->client = [_client retain];
+ self->password = [_pwd copy];
+
+ self->creationTime = [[NSDate alloc] init];
+ }
+ return self;
+}
+- (id)init {
+ return [self initWithClient:nil password:nil];
+}
+
+- (void)dealloc {
+ [self->cachedUIDs release];
+ [self->uidFolderURL release];
+ [self->uidSortOrdering release];
+ [self->creationTime release];
+ [self->subfolders release];
+ [self->password release];
+ [self->client release];
+ [super dealloc];
+}
+
+/* accessors */
+
+- (NGImap4Client *)client {
+ return self->client;
+}
+- (BOOL)isValidPassword:(NSString *)_pwd {
+ return [self->password isEqualToString:_pwd];
+}
+
+- (NSDate *)creationTime {
+ return self->creationTime;
+}
+
+- (void)cacheHierarchyResults:(NSDictionary *)_hierarchy {
+ ASSIGNCOPY(self->subfolders, _hierarchy);
+}
+- (NSDictionary *)cachedHierarchyResults {
+ return self->subfolders;
+}
+
+- (id)cachedUIDsForURL:(NSURL *)_url qualifier:(id)_q sortOrdering:(id)_so {
+ if (_q != nil)
+ return nil;
+ if (![_so isEqual:self->uidSortOrdering])
+ return nil;
+ if (![self->uidFolderURL isEqual:_url])
+ return nil;
+
+ return self->cachedUIDs;
+}
+
+- (void)cacheUIDs:(NSArray *)_uids forURL:(NSURL *)_url
+ qualifier:(id)_q sortOrdering:(id)_so
+{
+ if (_q != nil)
+ return;
+
+ ASSIGNCOPY(self->uidSortOrdering, _so);
+ ASSIGNCOPY(self->uidFolderURL, _url);
+ ASSIGNCOPY(self->cachedUIDs, _uids);
+}
+
+@end /* SOGoMailConnectionEntry */
*/
#include "SOGoMailManager.h"
+#include "SOGoMailConnectionEntry.h"
#include "common.h"
-@interface SOGoMailConnectionEntry : NSObject
-{
-@public
- NGImap4Client *client;
- NSString *password;
- NSDate *creationTime;
- NSDictionary *subfolders;
-}
-
-- (id)initWithClient:(NGImap4Client *)_client password:(NSString *)_pwd;
-
-/* accessors */
-
-- (NGImap4Client *)client;
-- (BOOL)isValidPassword:(NSString *)_pwd;
-
-- (NSDate *)creationTime;
-
-- (void)cacheHierarchyResults:(NSDictionary *)_hierarchy;
-- (NSDictionary *)cachedHierarchyResults;
-
-@end
+// TODO: need a way to refresh caches on get mail!
@implementation SOGoMailManager
[self->urlToEntry count]];
}
+- (id)entryForURL:(NSURL *)_url password:(NSString *)_pwd {
+ /*
+ Three cases:
+ a) not yet connected => create new entry and connect
+ b) connected, correct password => return cached entry
+ c) connected, different password => try to recreate entry
+ */
+ SOGoMailConnectionEntry *entry;
+ NGImap4Client *client;
+
+ /* check cache */
+
+ if ((entry = [self entryForURL:_url]) != nil) {
+ if ([entry isValidPassword:_pwd]) {
+ if (debugCache)
+ [self logWithFormat:@"valid password, reusing cache entry ..."];
+ return entry;
+ }
+
+ /* different password, password could have changed! */
+ if (debugCache)
+ [self logWithFormat:@"different password than cached entry: %@", _url];
+ entry = nil;
+ }
+ else
+ [self debugWithFormat:@"no connection cached yet for url: %@", _url];
+
+ /* try to login */
+
+ client = [entry isValidPassword:_pwd]
+ ? [entry client]
+ : [self imap4ClientForURL:_url password:_pwd];
+
+ if (client == nil)
+ return nil;
+
+ /* sideeffect of -imap4ClientForURL:password: is to create a cache entry */
+ return [self entryForURL:_url];
+}
+
/* client object */
- (NGImap4Client *)imap4ClientForURL:(NSURL *)_url password:(NSString *)_pwd {
- (NSArray *)subfoldersForURL:(NSURL *)_url password:(NSString *)_pwd {
// TODO: add caching
SOGoMailConnectionEntry *entry;
- NGImap4Client *client;
NSDictionary *result;
if (debugKeys)
[self debugWithFormat:@"subfolders for URL: %@ ...",[_url absoluteString]];
- /* check cache */
-
- if ((entry = [self entryForURL:_url]) != nil) {
- if ([entry isValidPassword:_pwd]) {
- NSDictionary *allFolders;
-
- if (debugCache)
- [self logWithFormat:@"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 */
+ /* check connection cache */
- client = [entry isValidPassword:_pwd]
- ? [entry client]
- : [self imap4ClientForURL:_url password:_pwd];
- if (client == nil)
+ if ((entry = [self entryForURL:_url password:_pwd]) == nil)
return nil;
+ /* check hierarchy cache */
+
+ if ((result = [entry cachedHierarchyResults]) != nil)
+ return [self extractSubfoldersForURL:_url fromResultSet:result];
+
+ [self debugWithFormat:@" no folders cached yet .."];
+
/* fetch _all_ folders */
- result = [client list:@"INBOX" pattern:@"*"];
+ result = [[entry client] list:@"INBOX" pattern:@"*"];
if (![[result valueForKey:@"result"] boolValue]) {
[self logWithFormat:@"ERROR: listing of folder failed!"];
return nil;
/* messages */
- (NSArray *)fetchUIDsInURL:(NSURL *)_url qualifier:(id)_qualifier
- sortOrdering:(id)_so range:(NSRange)_range password:(NSString *)_pwd
+ sortOrdering:(id)_so password:(NSString *)_pwd
{
/*
sortOrdering can be an NSString, an EOSortOrdering or an array of EOS.
*/
- NGImap4Client *client;
+ SOGoMailConnectionEntry *entry;
NSDictionary *result;
NSArray *uids;
- if ((client = [self imap4ClientForURL:_url password:_pwd]) == nil)
+ /* check connection cache */
+
+ if ((entry = [self entryForURL:_url password:_pwd]) == nil)
return nil;
- result = [client select:[self imap4FolderNameForURL:_url]];
+ /* check cache */
+
+ uids = [entry cachedUIDsForURL:_url qualifier:_qualifier sortOrdering:_so];
+ if (uids != nil) {
+ [self logWithFormat:@"REUSE UID CACHE!"];
+ return [uids isNotNull] ? uids : nil;
+ }
+
+ /* select folder and fetch */
+
+ result = [[entry client] select:[self imap4FolderNameForURL:_url]];
if (![[result valueForKey:@"result"] boolValue]) {
[self logWithFormat:@"ERROR: could not select URL: %@: %@", _url, result];
return nil;
}
- result = [client sort:_so qualifier:_qualifier encoding:@"UTF-8"];
+ result = [[entry client] sort:_so qualifier:_qualifier encoding:@"UTF-8"];
if (![[result valueForKey:@"result"] boolValue]) {
[self logWithFormat:@"ERROR: could not sort contents of URL: %@", _url];
return nil;
return nil;
}
- // TODO: improve to use a single range call?
- if (_range.location > 0) {
- uids = [uids subarrayWithRange:NSMakeRange(_range.location,
- [uids count]-_range.location)];
- }
- if ([uids count] > _range.length && _range.length != 0)
- uids = [uids subarrayWithRange:NSMakeRange(0, _range.length)];
+ /* cache */
+ [entry cacheUIDs:uids forURL:_url qualifier:_qualifier sortOrdering:_so];
return uids;
}
/* fetch parts */
-#warning TODO: split uids into batches, otherwise Cyrus will complain
- // not really important because we batch before (in the sort)
- // if the list is too long, we get a:
- // "* BYE Fatal error: word too long"
+ // TODO: split uids into batches, otherwise Cyrus will complain
+ // => not really important because we batch before (in the sort)
+ // if the list is too long, we get a:
+ // "* BYE Fatal error: word too long"
result = [client fetchUids:_uids parts:_parts];
if (![[result valueForKey:@"result"] boolValue]) {
[_uids count],_url];
return nil;
}
+
//[self logWithFormat:@"RESULT: %@", result];
return (id)result;
}
}
@end /* SOGoMailManager */
-
-@implementation SOGoMailConnectionEntry
-
-- (id)initWithClient:(NGImap4Client *)_client password:(NSString *)_pwd {
- if (_client == nil || _pwd == nil) {
- [self release];
- return nil;
- }
-
- if ((self = [super init])) {
- self->client = [_client retain];
- self->password = [_pwd copy];
-
- self->creationTime = [[NSDate alloc] init];
- }
- return self;
-}
-- (id)init {
- return [self initWithClient:nil password:nil];
-}
-
-- (void)dealloc {
- [self->creationTime release];
- [self->subfolders release];
- [self->password release];
- [self->client release];
- [super dealloc];
-}
-
-/* accessors */
-
-- (NGImap4Client *)client {
- return self->client;
-}
-- (BOOL)isValidPassword:(NSString *)_pwd {
- return [self->password isEqualToString:_pwd];
-}
-
-- (NSDate *)creationTime {
- return self->creationTime;
-}
-
-- (void)cacheHierarchyResults:(NSDictionary *)_hierarchy {
- ASSIGNCOPY(self->subfolders, _hierarchy);
-}
-- (NSDictionary *)cachedHierarchyResults {
- return self->subfolders;
-}
-
-@end /* SOGoMailConnectionEntry */