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 "SOGoMailAccount.h"
23 #include "SOGoMailFolder.h"
24 #include "SOGoMailManager.h"
25 #include "SOGoDraftsFolder.h"
26 #include "SOGoUser+Mail.h"
27 #include <NGObjWeb/SoHTTPAuthenticator.h>
30 @implementation SOGoMailAccount
32 static NSArray *rootFolderNames = nil;
33 static NSString *inboxFolderName = @"INBOX";
34 static NSString *draftsFolderName = @"Drafts";
35 static NSString *sieveFolderName = @"Filters";
36 static NSString *sharedFolderName = @""; // TODO: add English default
37 static NSString *otherUsersFolderName = @""; // TODO: add English default
38 static BOOL useAltNamespace = NO;
41 return [super version] + 0 /* v1 */;
45 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
46 NSString *cfgDraftsFolderName;
48 NSAssert2([super version] == 1,
49 @"invalid superclass (%@) version %i !",
50 NSStringFromClass([self superclass]), [super version]);
52 useAltNamespace = [ud boolForKey:@"SOGoSpecialFoldersInRoot"];
54 sharedFolderName = [ud stringForKey:@"SOGoSharedFolderName"];
55 otherUsersFolderName = [ud stringForKey:@"SOGoOtherUsersFolderName"];
56 cfgDraftsFolderName = [ud stringForKey:@"SOGoDraftsFolderName"];
57 if ([cfgDraftsFolderName length] > 0)
59 ASSIGN (draftsFolderName, cfgDraftsFolderName);
60 NSLog(@"Note: using drafts folder named: '%@'", draftsFolderName);
63 NSLog(@"Note: using shared-folders name: '%@'", sharedFolderName);
64 NSLog(@"Note: using other-users-folders name: '%@'", otherUsersFolderName);
65 if ([ud boolForKey:@"SOGoEnableSieveFolder"]) {
66 rootFolderNames = [[NSArray alloc] initWithObjects:
72 rootFolderNames = [[NSArray alloc] initWithObjects:
80 - (BOOL)isSharedAccount {
84 s = [self nameInContainer];
85 r = [s rangeOfString:@"@"];
86 if (r.length == 0) /* regular HTTP logins are never a shared mailbox */
89 s = [s substringToIndex:r.location];
90 return [s rangeOfString:@".-."].length > 0 ? YES : NO;
93 - (NSString *)sharedAccountName {
97 /* listing the available folders */
99 - (NSArray *)additionalRootFolderNames {
100 return rootFolderNames;
103 - (NSArray *) toManyRelationshipKeys
105 NSMutableArray *folders;
106 NSArray *imapFolders, *additionalFolders;
108 folders = [NSMutableArray new];
109 [folders autorelease];
111 imapFolders = [[self imap4Connection] subfoldersForURL: [self imap4URL]];
112 additionalFolders = [self additionalRootFolderNames];
113 if ([imapFolders count] > 0)
114 [folders addObjectsFromArray: imapFolders];
115 if ([additionalFolders count] > 0)
117 [folders removeObjectsInArray: additionalFolders];
118 [folders addObjectsFromArray: additionalFolders];
126 - (SOGoMailIdentity *)preferredIdentity {
127 return [[context activeUser] primaryMailIdentityForAccount:
128 [self nameInContainer]];
133 - (SOGoMailAccount *)mailAccountFolder {
137 - (NSArray *) allFolderPaths
139 NSMutableArray *newFolders;
140 NSArray *rawFolders, *mainFolders;
142 rawFolders = [[self imap4Connection]
143 allFoldersForURL: [self imap4URL]];
145 mainFolders = [NSArray arrayWithObjects: inboxFolderName, draftsFolderName,
146 sentFolder, trashFolder, nil];
147 newFolders = [NSMutableArray arrayWithArray: rawFolders];
148 [newFolders removeObjectsInArray: mainFolders];
149 [newFolders sortUsingSelector: @selector (caseInsensitiveCompare:)];
150 [newFolders replaceObjectsInRange: NSMakeRange (0, 0)
151 withObjectsFromArray: mainFolders];
162 - (NSString *)imap4LoginFromHTTP {
167 rq = [context request];
169 s = [rq headerForKey:@"x-webobjects-remote-user"];
173 if ((s = [rq headerForKey:@"authorization"]) == nil) {
178 creds = [SoHTTPAuthenticator parseCredentials:s];
179 if ([creds count] < 2)
180 /* somehow invalid */
183 return [creds objectAtIndex:0]; /* the user */
186 - (NSString *)imap4URLString {
187 /* private, overridden by SOGoSharedMailAccount */
191 s = [self nameInContainer];
192 r = [s rangeOfString:@"@"];
196 u = [self imap4LoginFromHTTP];
197 if ([u length] == 0) {
198 [self errorWithFormat:@"missing login in account folder name: %@", s];
201 s = [[u stringByAppendingString:@"@"] stringByAppendingString:s];
203 if ([s hasSuffix:@":80"]) { // HACK
204 [self logWithFormat:@"WARNING: incorrect value for IMAP4 URL: '%@'", s];
205 s = [s substringToIndex:([s length] - 3)];
208 s = [([self useSSL] ? @"imaps://" : @"imap://") stringByAppendingString:s];
209 s = [s stringByAppendingString:@"/"];
213 - (NSURL *)imap4URL {
214 /* imap://agenortest@mail.opengroupware.org/ */
217 if (self->imap4URL != nil)
218 return self->imap4URL;
220 if ((s = [self imap4URLString]) == nil)
223 self->imap4URL = [[NSURL alloc] initWithString:s];
224 return self->imap4URL;
227 - (NSString *)imap4Login {
228 return [[self imap4URL] user];
233 - (id)lookupFolder:(NSString *)_key ofClassNamed:(NSString *)_cn
238 if ((clazz = NSClassFromString(_cn)) == Nil) {
239 [self logWithFormat:@"ERROR: did not find class '%@' for key: '%@'",
241 return [NSException exceptionWithHTTPStatus:500 /* server error */
242 reason:@"did not find mail folder class!"];
244 return [[[clazz alloc] initWithName:_key inContainer:self] autorelease];
247 - (id)lookupImap4Folder:(NSString *)_key inContext:(id)_cx {
250 s = [_key isEqualToString:[self trashFolderNameInContext:_cx]]
251 ? @"SOGoTrashFolder" : @"SOGoMailFolder";
253 return [self lookupFolder:_key ofClassNamed:s inContext:_cx];
256 - (id)lookupDraftsFolder:(NSString *)_key inContext:(id)_ctx {
257 return [self lookupFolder:_key ofClassNamed:@"SOGoDraftsFolder"
260 - (id)lookupFiltersFolder:(NSString *)_key inContext:(id)_ctx {
261 return [self lookupFolder:_key ofClassNamed:@"SOGoSieveScriptsFolder"
265 - (id)lookupName:(NSString *)_key inContext:(id)_ctx acquire:(BOOL)_flag {
268 /* first check attributes directly bound to the application */
269 if ((obj = [super lookupName:_key inContext:_ctx acquire:NO]) != nil)
272 // TODO: those should be product.plist bindings? (can't be class bindings
273 // though because they are 'per-account')
274 if ([_key isEqualToString: draftsFolderName]) {
275 if ((obj = [self lookupDraftsFolder:_key inContext:_ctx]) != nil)
278 if ([_key isEqualToString: sieveFolderName]) {
279 if ((obj = [self lookupFiltersFolder:_key inContext:_ctx]) != nil)
283 if ((obj = [self lookupImap4Folder:_key inContext:_ctx]) != nil)
286 /* return 404 to stop acquisition */
287 return [NSException exceptionWithHTTPStatus:404 /* Not Found */];
290 /* special folders */
292 - (NSString *)inboxFolderNameInContext:(id)_ctx {
293 return inboxFolderName; /* cannot be changed in Cyrus ? */
295 - (NSString *)draftsFolderNameInContext:(id)_ctx {
296 return draftsFolderName; /* SOGo managed folder */
298 - (NSString *)sieveFolderNameInContext:(id)_ctx {
299 return sieveFolderName; /* SOGo managed folder */
301 - (NSString *)sentFolderNameInContext:(id)_ctx {
302 /* OGo issue #1225 */
303 static NSString *s = nil;
308 ud = [NSUserDefaults standardUserDefaults];
309 s = [[ud stringForKey:@"SOGoSentFolderName"] copy];
310 if ([s length] == 0) s = @"Sent";
311 [self logWithFormat:@"Note: using SOGoSentFolderName: '%@'", s];
315 - (NSString *)trashFolderNameInContext:(id)_ctx {
316 /* OGo issue #1225 */
317 static NSString *s = nil;
322 ud = [NSUserDefaults standardUserDefaults];
323 s = [[ud stringForKey:@"SOGoTrashFolderName"] copy];
324 if ([s length] == 0) s = @"Trash";
325 NSLog(@"Note: using SOGoTrashFolderName: '%@'", s);
330 - (SOGoMailFolder *)inboxFolderInContext:(id)_ctx {
331 // TODO: use some profile to determine real location, use a -traverse lookup
332 SOGoMailFolder *folder;
334 if (self->inboxFolder != nil)
335 return self->inboxFolder;
337 folder = [self lookupName:[self inboxFolderNameInContext:_ctx]
338 inContext:_ctx acquire:NO];
339 if ([folder isKindOfClass:[NSException class]]) return folder;
341 return ((self->inboxFolder = [folder retain]));
344 - (SOGoMailFolder *)sentFolderInContext:(id)_ctx {
345 // TODO: use some profile to determine real location, use a -traverse lookup
346 SOGoMailFolder *folder;
348 if (self->sentFolder != nil)
349 return self->sentFolder;
351 folder = useAltNamespace ? (id)self : [self inboxFolderInContext:_ctx];
352 if ([folder isKindOfClass:[NSException class]]) return folder;
354 folder = [folder lookupName:[self sentFolderNameInContext:_ctx]
355 inContext:_ctx acquire:NO];
356 if ([folder isKindOfClass:[NSException class]]) return folder;
358 if (![folder isNotNull]) {
359 return [NSException exceptionWithHTTPStatus:404 /* not found */
360 reason:@"did not find Sent folder!"];
363 return ((self->sentFolder = [folder retain]));
366 - (SOGoMailFolder *)trashFolderInContext:(id)_ctx {
367 // TODO: use some profile to determine real location
368 SOGoMailFolder *folder;
370 if (self->trashFolder != nil)
371 return self->trashFolder;
373 folder = useAltNamespace ? (id)self : [self inboxFolderInContext:_ctx];
374 if ([folder isKindOfClass:[NSException class]]) return folder;
376 folder = [folder lookupName:[self trashFolderNameInContext:_ctx]
377 inContext:_ctx acquire:NO];
378 if ([folder isKindOfClass:[NSException class]]) return folder;
380 if (![folder isNotNull]) {
381 return [NSException exceptionWithHTTPStatus:404 /* not found */
382 reason:@"did not find Trash folder!"];
385 return ((self->trashFolder = [folder retain]));
390 - (NSString *) davContentType
392 return @"httpd/unix-directory";
395 - (BOOL) davIsCollection
400 - (NSException *) davCreateCollection: (NSString *) _name
403 return [[self imap4Connection] createMailbox:_name atURL:[self imap4URL]];
406 - (NSString *) shortTitle
408 NSString *s, *login, *host;
411 s = [self nameInContainer];
413 r = [s rangeOfString:@"@"];
415 login = [s substringToIndex:r.location];
416 host = [s substringFromIndex:(r.location + r.length)];
423 r = [host rangeOfString:@"."];
425 host = [host substringToIndex:r.location];
427 if ([login length] == 0)
430 r = [login rangeOfString:@"."];
432 login = [login substringToIndex:r.location];
434 return [NSString stringWithFormat:@"%@@%@", login, host];
437 - (NSString *) davDisplayName
439 return [self shortTitle];
442 - (NSString *) sharedFolderName
444 return sharedFolderName;
447 - (NSString *) otherUsersFolderName
449 return otherUsersFolderName;
452 @end /* SOGoMailAccount */