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/SOGoUser.h>
37 #import "SOGoMailFolder.h"
38 #import "SOGoMailManager.h"
39 #import "SOGoDraftsFolder.h"
41 #import "SOGoMailAccount.h"
43 @implementation SOGoMailAccount
45 static NSArray *rootFolderNames = nil;
46 static NSString *inboxFolderName = @"INBOX";
47 static NSString *draftsFolderName = @"Drafts";
48 static NSString *sieveFolderName = @"Filters";
49 static NSString *sentFolderName = nil;
50 static NSString *trashFolderName = nil;
51 static NSString *sharedFolderName = @""; // TODO: add English default
52 static NSString *otherUsersFolderName = @""; // TODO: add English default
53 static BOOL useAltNamespace = NO;
57 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
58 NSString *cfgDraftsFolderName;
60 useAltNamespace = [ud boolForKey:@"SOGoSpecialFoldersInRoot"];
62 sharedFolderName = [ud stringForKey:@"SOGoSharedFolderName"];
63 otherUsersFolderName = [ud stringForKey:@"SOGoOtherUsersFolderName"];
64 cfgDraftsFolderName = [ud stringForKey:@"SOGoDraftsFolderName"];
67 sentFolderName = [ud stringForKey: @"SOGoSentFolderName"];
69 sentFolderName = @"Sent";
70 [sentFolderName retain];
74 trashFolderName = [ud stringForKey: @"SOGoTrashFolderName"];
76 trashFolderName = @"Trash";
77 [trashFolderName retain];
79 if ([cfgDraftsFolderName length] > 0)
81 ASSIGN (draftsFolderName, cfgDraftsFolderName);
82 NSLog(@"Note: using drafts folder named: '%@'", draftsFolderName);
85 NSLog(@"Note: using shared-folders name: '%@'", sharedFolderName);
86 NSLog(@"Note: using other-users-folders name: '%@'", otherUsersFolderName);
87 if ([ud boolForKey: @"SOGoEnableSieveFolder"])
88 rootFolderNames = [[NSArray alloc] initWithObjects:
93 rootFolderNames = [[NSArray alloc] initWithObjects:
100 if ((self = [super init]))
113 [inboxFolder release];
114 [draftsFolder release];
115 [sentFolder release];
116 [trashFolder release];
120 /* shared accounts */
122 - (BOOL) isSharedAccount
127 s = [self nameInContainer];
128 r = [s rangeOfString:@"@"];
129 if (r.length == 0) /* regular HTTP logins are never a shared mailbox */
132 s = [s substringToIndex:r.location];
133 return [s rangeOfString:@".-."].length > 0 ? YES : NO;
136 - (NSString *) sharedAccountName
141 /* listing the available folders */
143 - (NSArray *) additionalRootFolderNames
145 return rootFolderNames;
148 - (BOOL) isInDraftsFolder
153 - (NSArray *) toManyRelationshipKeys
155 NSMutableArray *folders;
156 NSArray *imapFolders, *additionalFolders;
158 folders = [NSMutableArray array];
160 imapFolders = [[self imap4Connection] subfoldersForURL: [self imap4URL]];
161 additionalFolders = [self additionalRootFolderNames];
162 if ([imapFolders count] > 0)
163 [folders addObjectsFromArray: imapFolders];
164 if ([additionalFolders count] > 0)
166 [folders removeObjectsInArray: additionalFolders];
167 [folders addObjectsFromArray: additionalFolders];
175 - (SOGoMailAccount *) mailAccountFolder
180 - (NSArray *) allFolderPaths
182 NSMutableArray *newFolders;
183 NSArray *rawFolders, *mainFolders;
185 rawFolders = [[self imap4Connection]
186 allFoldersForURL: [self imap4URL]];
188 mainFolders = [NSArray arrayWithObjects: inboxFolderName, draftsFolderName,
189 sentFolder, trashFolder, nil];
190 newFolders = [NSMutableArray arrayWithArray: rawFolders];
191 [newFolders removeObjectsInArray: mainFolders];
192 [newFolders sortUsingSelector: @selector (caseInsensitiveCompare:)];
193 [newFolders replaceObjectsInRange: NSMakeRange (0, 0)
194 withObjectsFromArray: mainFolders];
206 - (NSString *) imap4LoginFromHTTP
212 rq = [context request];
214 s = [rq headerForKey:@"x-webobjects-remote-user"];
218 if ((s = [rq headerForKey:@"authorization"]) == nil) {
223 creds = [SoHTTPAuthenticator parseCredentials:s];
224 if ([creds count] < 2)
225 /* somehow invalid */
228 return [creds objectAtIndex:0]; /* the user */
231 - (NSMutableString *) imap4URLString
233 /* private, overridden by SOGoSharedMailAccount */
234 NSMutableString *urlString;
237 urlString = [NSMutableString string];
240 [urlString appendString: @"imaps://"];
242 [urlString appendString: @"imap://"];
244 host = [self nameInContainer];
245 if (![host rangeOfString: @"@"].length)
246 [urlString appendFormat: @"%@@", [self imap4LoginFromHTTP]];
247 [urlString appendFormat: @"%@/", host];
252 - (NSString *) imap4Login
254 return [[self imap4URL] user];
259 - (id) lookupFolder: (NSString *) _key
260 ofClassNamed: (NSString *) _cn
264 SOGoMailFolder *folder;
266 if ((clazz = NSClassFromString(_cn)) == Nil)
268 [self logWithFormat:@"ERROR: did not find class '%@' for key: '%@'",
270 return [NSException exceptionWithHTTPStatus:500 /* server error */
271 reason:@"did not find mail folder class!"];
274 folder = [clazz objectWithName: _key inContainer: self];
279 - (id) lookupImap4Folder: (NSString *) _key
284 s = [_key isEqualToString: [self trashFolderNameInContext:_cx]]
285 ? @"SOGoTrashFolder" : @"SOGoMailFolder";
287 return [self lookupFolder:_key ofClassNamed:s inContext:_cx];
290 - (id) lookupDraftsFolder: (NSString *) _key
293 return [self lookupFolder: _key ofClassNamed: @"SOGoDraftsFolder"
297 - (id) lookupFiltersFolder: (NSString *) _key inContext: (id) _ctx
299 return [self lookupFolder:_key ofClassNamed:@"SOGoSieveScriptsFolder"
303 - (id) lookupName: (NSString *) _key
305 acquire: (BOOL) _flag
309 if ([_key hasPrefix: @"folder"])
311 // TODO: those should be product.plist bindings? (can't be class bindings
312 // though because they are 'per-account')
313 if ([_key isEqualToString: [self draftsFolderNameInContext: _ctx]])
314 obj = [self lookupDraftsFolder: _key inContext: _ctx];
315 else if ([_key isEqualToString: [self sieveFolderNameInContext: _ctx]])
316 obj = [self lookupFiltersFolder: _key inContext: _ctx];
318 obj = [self lookupImap4Folder: _key inContext: _ctx];
321 obj = [super lookupName: _key inContext: _ctx acquire: NO];
323 /* return 404 to stop acquisition */
325 obj = [NSException exceptionWithHTTPStatus: 404 /* Not Found */];
330 /* special folders */
332 - (NSString *) inboxFolderNameInContext: (id)_ctx
334 /* cannot be changed in Cyrus ? */
335 return [NSString stringWithFormat: @"folder%@", inboxFolderName];
338 - (NSString *) _userFolderNameWithPurpose: (NSString *) purpose
341 NSMutableDictionary *mailSettings;
342 NSString *folderName;
345 ud = [[context activeUser] userSettings];
346 mailSettings = [ud objectForKey: @"Mail"];
349 = [mailSettings objectForKey: [NSString stringWithFormat: @"%@Folder",
355 - (NSString *) draftsFolderNameInContext: (id) _ctx
357 NSString *folderName;
359 folderName = [self _userFolderNameWithPurpose: @"Drafts"];
361 folderName = draftsFolderName;
363 return [NSString stringWithFormat: @"folder%@", folderName];
366 - (NSString *) sieveFolderNameInContext: (id) _ctx
368 return [NSString stringWithFormat: @"folder%@", sieveFolderName];
371 - (NSString *) sentFolderNameInContext: (id)_ctx
373 NSString *folderName;
375 folderName = [self _userFolderNameWithPurpose: @"Sent"];
377 folderName = sentFolderName;
379 return [NSString stringWithFormat: @"folder%@", folderName];
382 - (NSString *) trashFolderNameInContext: (id)_ctx
384 NSString *folderName;
386 folderName = [self _userFolderNameWithPurpose: @"Trash"];
388 folderName = trashFolderName;
390 return [NSString stringWithFormat: @"folder%@", folderName];
393 - (SOGoMailFolder *) inboxFolderInContext: (id) _ctx
395 // TODO: use some profile to determine real location, use a -traverse lookup
398 inboxFolder = [self lookupName: [self inboxFolderNameInContext: _ctx]
399 inContext: _ctx acquire: NO];
400 [inboxFolder retain];
406 - (SOGoDraftsFolder *) draftsFolderInContext: (id) _ctx
408 SOGoMailFolder *lookupFolder;
409 // TODO: use some profile to determine real location, use a -traverse lookup
413 lookupFolder = (useAltNamespace
415 : [self inboxFolderInContext:_ctx]);
416 if (![lookupFolder isKindOfClass: [NSException class]])
418 = [lookupFolder lookupName: [self draftsFolderNameInContext:_ctx]
419 inContext: _ctx acquire: NO];
420 if (![draftsFolder isNotNull])
421 draftsFolder = [NSException exceptionWithHTTPStatus: 404 /* not found */
422 reason: @"did not find Drafts folder!"];
423 [draftsFolder retain];
429 - (SOGoMailFolder *) sentFolderInContext: (id) _ctx
431 SOGoMailFolder *lookupFolder;
432 // TODO: use some profile to determine real location, use a -traverse lookup
436 lookupFolder = (useAltNamespace
438 : [self inboxFolderInContext:_ctx]);
439 if (![lookupFolder isKindOfClass: [NSException class]])
440 sentFolder = [lookupFolder lookupName: [self sentFolderNameInContext:_ctx]
441 inContext: _ctx acquire: NO];
442 if (![sentFolder isNotNull])
443 sentFolder = [NSException exceptionWithHTTPStatus: 404 /* not found */
444 reason: @"did not find Sent folder!"];
451 - (SOGoMailFolder *) trashFolderInContext: (id) _ctx
453 SOGoMailFolder *lookupFolder;
454 // TODO: use some profile to determine real location, use a -traverse lookup
458 lookupFolder = (useAltNamespace
460 : [self inboxFolderInContext:_ctx]);
461 if (![lookupFolder isKindOfClass: [NSException class]])
462 trashFolder = [lookupFolder lookupName: [self trashFolderNameInContext: _ctx]
463 inContext: _ctx acquire: NO];
464 if (![trashFolder isNotNull])
465 trashFolder = [NSException exceptionWithHTTPStatus: 404 /* not found */
466 reason: @"did not find Trash folder!"];
467 [trashFolder retain];
475 - (NSString *) davContentType
477 return @"httpd/unix-directory";
480 - (BOOL) davIsCollection
485 - (NSException *) davCreateCollection: (NSString *) _name
488 return [[self imap4Connection] createMailbox:_name atURL:[self imap4URL]];
491 - (NSString *) shortTitle
493 NSString *s, *login, *host;
496 s = [self nameInContainer];
498 r = [s rangeOfString:@"@"];
500 login = [s substringToIndex:r.location];
501 host = [s substringFromIndex:(r.location + r.length)];
508 r = [host rangeOfString:@"."];
510 host = [host substringToIndex:r.location];
512 if ([login length] == 0)
515 r = [login rangeOfString:@"."];
517 login = [login substringToIndex:r.location];
519 return [NSString stringWithFormat:@"%@@%@", login, host];
522 - (NSString *) davDisplayName
524 return [self shortTitle];
527 - (NSString *) sharedFolderName
529 return sharedFolderName;
532 - (NSString *) otherUsersFolderName
534 return otherUsersFolderName;
537 @end /* SOGoMailAccount */