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 #import <Foundation/NSArray.h>
23 #import <Foundation/NSURL.h>
24 #import <Foundation/NSString.h>
25 #import <Foundation/NSUserDefaults.h>
27 #import <NGObjWeb/NSException+HTTP.h>
28 #import <NGObjWeb/SoHTTPAuthenticator.h>
29 #import <NGObjWeb/WORequest.h>
30 #import <NGObjWeb/WOContext+SoObjects.h>
31 #import <NGExtensions/NSObject+Logs.h>
32 #import <NGExtensions/NSNull+misc.h>
33 #import <NGImap4/NGImap4Connection.h>
35 #import <SoObjects/SOGo/NSArray+Utilities.h>
36 #import <SoObjects/SOGo/SOGoUser.h>
38 #import "SOGoMailFolder.h"
39 #import "SOGoMailManager.h"
40 #import "SOGoDraftsFolder.h"
42 #import "SOGoMailAccount.h"
44 @implementation SOGoMailAccount
46 static NSArray *rootFolderNames = nil;
47 static NSString *inboxFolderName = @"INBOX";
48 static NSString *draftsFolderName = @"Drafts";
49 static NSString *sieveFolderName = @"Filters";
50 static NSString *sentFolderName = nil;
51 static NSString *trashFolderName = nil;
52 static NSString *sharedFolderName = @""; // TODO: add English default
53 static NSString *otherUsersFolderName = @""; // TODO: add English default
57 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
58 NSString *cfgDraftsFolderName;
60 sharedFolderName = [ud stringForKey:@"SOGoSharedFolderName"];
61 otherUsersFolderName = [ud stringForKey:@"SOGoOtherUsersFolderName"];
62 cfgDraftsFolderName = [ud stringForKey:@"SOGoDraftsFolderName"];
65 sentFolderName = [ud stringForKey: @"SOGoSentFolderName"];
67 sentFolderName = @"Sent";
68 [sentFolderName retain];
72 trashFolderName = [ud stringForKey: @"SOGoTrashFolderName"];
74 trashFolderName = @"Trash";
75 [trashFolderName retain];
77 if ([cfgDraftsFolderName length] > 0)
79 ASSIGN (draftsFolderName, cfgDraftsFolderName);
80 NSLog(@"Note: using drafts folder named: '%@'", draftsFolderName);
83 NSLog(@"Note: using shared-folders name: '%@'", sharedFolderName);
84 NSLog(@"Note: using other-users-folders name: '%@'", otherUsersFolderName);
85 if ([ud boolForKey: @"SOGoEnableSieveFolder"])
86 rootFolderNames = [[NSArray alloc] initWithObjects:
91 rootFolderNames = [[NSArray alloc] initWithObjects:
98 if ((self = [super init]))
111 [inboxFolder release];
112 [draftsFolder release];
113 [sentFolder release];
114 [trashFolder release];
118 /* shared accounts */
120 - (BOOL) isSharedAccount
125 s = [self nameInContainer];
126 r = [s rangeOfString:@"@"];
127 if (r.length == 0) /* regular HTTP logins are never a shared mailbox */
130 s = [s substringToIndex:r.location];
131 return [s rangeOfString:@".-."].length > 0 ? YES : NO;
134 - (NSString *) sharedAccountName
139 /* listing the available folders */
141 - (NSArray *) additionalRootFolderNames
143 return rootFolderNames;
146 - (BOOL) isInDraftsFolder
151 - (NSArray *) toManyRelationshipKeys
153 NSMutableArray *folders;
154 NSArray *imapFolders, *additionalFolders;
156 folders = [NSMutableArray array];
158 imapFolders = [[self imap4Connection] subfoldersForURL: [self imap4URL]];
159 additionalFolders = [self additionalRootFolderNames];
160 if ([imapFolders count] > 0)
161 [folders addObjectsFromArray: imapFolders];
162 if ([additionalFolders count] > 0)
164 [folders removeObjectsInArray: additionalFolders];
165 [folders addObjectsFromArray: additionalFolders];
173 - (SOGoMailAccount *) mailAccountFolder
178 - (NSArray *) allFolderPaths
180 NSMutableArray *newFolders;
181 NSArray *rawFolders, *mainFolders;
182 NSString *realDraftsFolderName, *realSentFolderName, *realTrashFolderName;
184 rawFolders = [[self imap4Connection] allFoldersForURL: [self imap4URL]];
187 = [[self draftsFolderInContext: context] traversalFromMailAccount];
189 = [[self sentFolderInContext: context] traversalFromMailAccount];
191 = [[self trashFolderInContext: context] traversalFromMailAccount];
193 mainFolders = [NSArray arrayWithObjects: inboxFolderName,
194 realDraftsFolderName,
196 realTrashFolderName, nil];
197 newFolders = [NSMutableArray arrayWithArray: rawFolders];
198 [newFolders removeObjectsInArray: mainFolders];
199 [newFolders sortUsingSelector: @selector (caseInsensitiveCompare:)];
200 [newFolders replaceObjectsInRange: NSMakeRange (0, 0)
201 withObjectsFromArray: mainFolders];
213 - (NSString *) imap4LoginFromHTTP
219 rq = [context request];
221 s = [rq headerForKey:@"x-webobjects-remote-user"];
225 if ((s = [rq headerForKey:@"authorization"]) == nil) {
230 creds = [SoHTTPAuthenticator parseCredentials:s];
231 if ([creds count] < 2)
232 /* somehow invalid */
235 return [creds objectAtIndex:0]; /* the user */
238 - (NSMutableString *) imap4URLString
240 /* private, overridden by SOGoSharedMailAccount */
241 NSMutableString *urlString;
244 urlString = [NSMutableString string];
247 [urlString appendString: @"imaps://"];
249 [urlString appendString: @"imap://"];
251 host = [self nameInContainer];
252 if (![host rangeOfString: @"@"].length)
253 [urlString appendFormat: @"%@@", [self imap4LoginFromHTTP]];
254 [urlString appendFormat: @"%@/", host];
259 - (NSMutableString *) traversalFromMailAccount
261 return [NSMutableString string];
264 - (NSString *) imap4Login
266 return [[self imap4URL] user];
271 - (id) lookupFolder: (NSString *) _key
272 ofClassNamed: (NSString *) _cn
276 SOGoMailFolder *folder;
278 if ((clazz = NSClassFromString(_cn)) == Nil)
280 [self logWithFormat:@"ERROR: did not find class '%@' for key: '%@'",
282 return [NSException exceptionWithHTTPStatus:500 /* server error */
283 reason:@"did not find mail folder class!"];
286 folder = [clazz objectWithName: _key inContainer: self];
291 - (id) lookupSentFolder: (NSString *) _key
294 return [self lookupFolder: _key ofClassNamed: @"SOGoSentFolder"
298 - (id) lookupDraftsFolder: (NSString *) _key
301 return [self lookupFolder: _key ofClassNamed: @"SOGoDraftsFolder"
305 - (id) lookupTrashFolder: (NSString *) _key
308 return [self lookupFolder: _key ofClassNamed: @"SOGoTrashFolder"
312 - (id) lookupFiltersFolder: (NSString *) _key inContext: (id) _ctx
314 return [self lookupFolder:_key ofClassNamed:@"SOGoSieveScriptsFolder"
318 - (id) lookupName: (NSString *) _key
320 acquire: (BOOL) _flag
324 if ([_key hasPrefix: @"folder"])
326 // TODO: those should be product.plist bindings? (can't be class bindings
327 // though because they are 'per-account')
328 if ([_key isEqualToString: [self sentFolderNameInContext: _ctx]])
329 obj = [self lookupSentFolder: _key inContext: _ctx];
330 else if ([_key isEqualToString: [self draftsFolderNameInContext: _ctx]])
331 obj = [self lookupDraftsFolder: _key inContext: _ctx];
332 else if ([_key isEqualToString: [self trashFolderNameInContext: _ctx]])
333 obj = [self lookupTrashFolder: _key inContext: _ctx];
334 // else if ([_key isEqualToString: [self sieveFolderNameInContext: _ctx]])
335 // obj = [self lookupFiltersFolder: _key inContext: _ctx];
337 obj = [self lookupFolder: _key ofClassNamed: @"SOGoMailFolder"
341 obj = [super lookupName: _key inContext: _ctx acquire: NO];
343 /* return 404 to stop acquisition */
345 obj = [NSException exceptionWithHTTPStatus: 404 /* Not Found */];
350 /* special folders */
352 - (NSString *) inboxFolderNameInContext: (id)_ctx
354 /* cannot be changed in Cyrus ? */
355 return [NSString stringWithFormat: @"folder%@", inboxFolderName];
358 - (NSString *) _userFolderNameWithPurpose: (NSString *) purpose
361 NSMutableDictionary *mailSettings;
362 NSString *folderName;
365 ud = [[context activeUser] userSettings];
366 mailSettings = [ud objectForKey: @"Mail"];
369 = [mailSettings objectForKey: [NSString stringWithFormat: @"%@Folder",
375 - (NSString *) draftsFolderNameInContext: (id) _ctx
377 NSString *folderName;
379 folderName = [self _userFolderNameWithPurpose: @"Drafts"];
381 folderName = draftsFolderName;
383 return [NSString stringWithFormat: @"folder%@", folderName];
386 - (NSString *) sieveFolderNameInContext: (id) _ctx
388 return [NSString stringWithFormat: @"folder%@", sieveFolderName];
391 - (NSString *) sentFolderNameInContext: (id)_ctx
393 NSString *folderName;
395 folderName = [self _userFolderNameWithPurpose: @"Sent"];
397 folderName = sentFolderName;
399 return [NSString stringWithFormat: @"folder%@", folderName];
402 - (NSString *) trashFolderNameInContext: (id)_ctx
404 NSString *folderName;
406 folderName = [self _userFolderNameWithPurpose: @"Trash"];
408 folderName = trashFolderName;
410 return [NSString stringWithFormat: @"folder%@", folderName];
413 - (SOGoMailFolder *) inboxFolderInContext: (id) _ctx
415 // TODO: use some profile to determine real location, use a -traverse lookup
418 inboxFolder = [self lookupName: [self inboxFolderNameInContext: _ctx]
419 inContext: _ctx acquire: NO];
420 [inboxFolder retain];
426 - (SOGoDraftsFolder *) draftsFolderInContext: (id) _ctx
428 // TODO: use some profile to determine real location, use a -traverse lookup
433 = [self lookupName: [self draftsFolderNameInContext:_ctx]
434 inContext: _ctx acquire: NO];
435 // if (![draftsFolder isNotNull])
436 // draftsFolder = [NSException exceptionWithHTTPStatus: 404 /* not found */
437 // reason: @"did not find Drafts folder!"];
438 [draftsFolder retain];
444 - (SOGoMailFolder *) sentFolderInContext: (id) _ctx
446 // TODO: use some profile to determine real location, use a -traverse lookup
450 sentFolder = [self lookupName: [self sentFolderNameInContext:_ctx]
451 inContext: _ctx acquire: NO];
452 // if (![sentFolder isNotNull])
453 // sentFolder = [NSException exceptionWithHTTPStatus: 404 /* not found */
454 // reason: @"did not find Sent folder!"];
461 - (SOGoMailFolder *) trashFolderInContext: (id) _ctx
465 trashFolder = [self lookupName: [self trashFolderNameInContext: _ctx]
466 inContext: _ctx acquire: NO];
467 // if (![trashFolder isNotNull])
468 // trashFolder = [NSException exceptionWithHTTPStatus: 404 /* not found */
469 // reason: @"did not find Trash folder!"];
470 [trashFolder retain];
478 - (NSString *) davContentType
480 return @"httpd/unix-directory";
483 - (BOOL) davIsCollection
488 - (NSException *) davCreateCollection: (NSString *) _name
491 return [[self imap4Connection] createMailbox:_name atURL:[self imap4URL]];
494 - (NSString *) shortTitle
496 NSString *s, *login, *host;
499 s = [self nameInContainer];
501 r = [s rangeOfString:@"@"];
503 login = [s substringToIndex:r.location];
504 host = [s substringFromIndex:(r.location + r.length)];
511 r = [host rangeOfString:@"."];
513 host = [host substringToIndex:r.location];
515 if ([login length] == 0)
518 r = [login rangeOfString:@"."];
520 login = [login substringToIndex:r.location];
522 return [NSString stringWithFormat:@"%@@%@", login, host];
525 - (NSString *) davDisplayName
527 return [self shortTitle];
530 - (NSString *) sharedFolderName
532 return sharedFolderName;
535 - (NSString *) otherUsersFolderName
537 return otherUsersFolderName;
540 @end /* SOGoMailAccount */