2 Copyright (C) 2004-2005 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include "NGImap4ConnectionManager.h"
23 #include "NGImap4Connection.h"
24 #include "NGImap4Client.h"
27 @implementation NGImap4ConnectionManager
29 static BOOL debugOn = NO;
30 static BOOL debugCache = NO;
31 static BOOL poolingOff = NO;
32 static NSTimeInterval PoolScanInterval = 5 * 60 /* every five minutes */;
35 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
37 debugOn = [ud boolForKey:@"NGImap4EnableIMAP4Debug"];
38 debugCache = [ud boolForKey:@"NGImap4EnableIMAP4CacheDebug"];
39 poolingOff = [ud boolForKey:@"NGImap4DisableIMAP4Pooling"];
41 if (debugOn) NSLog(@"Note: NGImap4EnableIMAP4Debug is enabled!");
42 if (poolingOff) NSLog(@"WARNING: IMAP4 connection pooling is disabled!");
45 + (id)defaultConnectionManager {
46 static NGImap4ConnectionManager *manager = nil; // THREAD
48 manager = [[self alloc] init];
53 if ((self = [super init])) {
55 self->urlToEntry = [[NSMutableDictionary alloc] initWithCapacity:256];
58 self->gcTimer = [[NSTimer scheduledTimerWithTimeInterval:
60 target:self selector:@selector(_garbageCollect:)
61 userInfo:nil repeats:YES] retain];
67 if (self->gcTimer) [self->gcTimer invalidate];
68 [self->urlToEntry release];
69 [self->gcTimer release];
75 - (id)cacheKeyForURL:(NSURL *)_url {
76 // protocol, user, host, port
77 return [NSString stringWithFormat:@"%@://%@@%@:%@",
78 [_url scheme], [_url user], [_url host], [_url port]];
81 - (NGImap4Connection *)entryForURL:(NSURL *)_url {
85 return [self->urlToEntry objectForKey:[self cacheKeyForURL:_url]];
87 - (void)cacheEntry:(NGImap4Connection *)_entry forURL:(NSURL *)_url {
88 if (_entry == nil) _entry = (id)[NSNull null];
89 [self->urlToEntry setObject:_entry forKey:[self cacheKeyForURL:_url]];
92 - (void)_garbageCollect:(NSTimer *)_timer {
93 // TODO: scan for old IMAP4 channels
94 [self debugWithFormat:@"should collect IMAP4 channels (%d active)",
95 [self->urlToEntry count]];
98 - (NGImap4Connection *)connectionForURL:(NSURL *)_url password:(NSString *)_p {
101 a) not yet connected => create new entry and connect
102 b) connected, correct password => return cached entry
103 c) connected, different password => try to recreate entry
105 NGImap4Connection *entry;
106 NGImap4Client *client;
110 if ((entry = [self entryForURL:_url]) != nil) {
111 if ([entry isValidPassword:_p]) {
113 [self logWithFormat:@"valid password, reusing cache entry ..."];
117 /* different password, password could have changed! */
119 [self logWithFormat:@"different password than cached entry: %@", _url];
123 [self debugWithFormat:@"no connection cached yet for url: %@", _url];
127 client = [entry isValidPassword:_p]
129 : [self imap4ClientForURL:_url password:_p];
134 /* sideeffect of -imap4ClientForURL:password: is to create a cache entry */
135 return [self entryForURL:_url];
140 - (NGImap4Client *)imap4ClientForURL:(NSURL *)_url password:(NSString *)_pwd {
141 // TODO: move to some global IMAP4 connection pool manager
142 NGImap4Connection *entry;
143 NGImap4Client *client;
144 NSDictionary *result;
149 /* check connection pool */
151 if ((entry = [self entryForURL:_url]) != nil) {
152 if ([entry isValidPassword:_pwd]) {
153 [self debugWithFormat:@"reused IMAP4 connection for URL: %@", _url];
154 return [entry client];
157 /* different password, password could have changed! */
161 /* setup connection and attempt login */
163 if ((client = [NGImap4Client clientWithURL:_url]) == nil)
166 result = [client login:[_url user] password:_pwd];
167 if (![[result valueForKey:@"result"] boolValue]) {
168 [self errorWithFormat:
169 @"IMAP4 login failed:\n"
170 @" host=%@, user=%@, pwd=%s\n"
171 @" url=%@\n base=%@\n base-class=%@)\n"
173 [_url host], [_url user], [_pwd length] > 0 ? "yes" : "no",
174 [_url absoluteString],
176 NSStringFromClass([[_url baseURL] class]),
181 [self debugWithFormat:@"created new IMAP4 connection for URL: %@", _url];
183 /* cache connection in pool */
185 entry = [[NGImap4Connection alloc] initWithClient:client
187 [self cacheEntry:entry forURL:_url];
188 [entry release]; entry = nil;
193 - (void)flushCachesForURL:(NSURL *)_url {
194 NGImap4Connection *entry;
196 if ((entry = [self entryForURL:_url]) == nil) /* nothing cached */
199 [entry flushFolderHierarchyCache];
200 [entry flushMailCaches];
205 - (BOOL)isDebuggingEnabled {
209 @end /* NGImap4ConnectionManager */