#include "SOGoMailManager.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;
+
+@end
+
@implementation SOGoMailManager
-static BOOL debugOn = YES;
+static BOOL debugOn = YES;
+static BOOL poolingOff = NO;
+static NSTimeInterval PoolScanInterval = 5 * 60;
+
++ (void)initialize {
+ NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+
+ debugOn = [ud boolForKey:@"SOGoEnableIMAP4Debug"];
+ poolingOff = [ud boolForKey:@"SOGoDisableIMAP4Pooling"];
+}
+ (id)defaultMailManager {
static SOGoMailManager *manager = nil; // THREAD
return manager;
}
+- (id)init {
+ if ((self = [super init])) {
+ if (!poolingOff) {
+ self->urlToEntry = [[NSMutableDictionary alloc] initWithCapacity:256];
+ }
+
+ self->gcTimer = [[NSTimer scheduledTimerWithTimeInterval:
+ PoolScanInterval
+ target:self selector:@selector(_garbageCollect:)
+ userInfo:nil repeats:YES] retain];
+ }
+ return self;
+}
+
- (void)dealloc {
+ if (self->gcTimer) [self->gcTimer invalidate];
+ [self->gcTimer release];
+
+ [self->urlToEntry release];
[super dealloc];
}
+/* cache */
+
+- (id)cacheKeyForURL:(NSURL *)_url {
+ // protocol, user, host, port
+ return [NSString stringWithFormat:@"%@://%@@%@:%@",
+ [_url scheme], [_url user], [_url host], [_url port]];
+}
+
+- (void)_garbageCollect:(NSTimer *)_timer {
+ // TODO: scan for old IMAP4 channels
+ [self debugWithFormat:@"should collect IMAP4 channels (%d active)",
+ [self->urlToEntry count]];
+}
+
/* client object */
- (NGImap4Client *)imap4ClientForURL:(NSURL *)_url password:(NSString *)_pwd {
// TODO: move to some global IMAP4 connection pool manager
+ SOGoMailConnectionEntry *entry;
NGImap4Client *client;
NSDictionary *result;
+ NSString *cacheKey;
if (_url == nil)
return nil;
+
+ cacheKey = [self cacheKeyForURL:_url];
+
+ if ((entry = [self->urlToEntry objectForKey:cacheKey]) != nil) {
+ if ([entry isValidPassword:_pwd]) {
+ [self debugWithFormat:@"reused IMAP4 connection for URL: %@", _url];
+ return [entry client];
+ }
+
+ /* different password, password could have changed! */
+ entry = nil;
+ }
if ((client = [NGImap4Client clientWithURL:_url]) == nil)
return nil;
[self logWithFormat:@"ERROR: IMAP4 login failed!"];
return nil;
}
-
+
+ [self debugWithFormat:@"created new IMAP4 connection for URL: %@", _url];
+ entry = [[SOGoMailConnectionEntry alloc] initWithClient:client
+ password:_pwd];
+ [self->urlToEntry setObject:entry forKey:cacheKey];
+ [entry release]; entry = nil;
return client;
}
}
@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;
+}
+
+@end /* SOGoMailConnectionEntry */