/*
- Copyright (C) 2004 SKYRIX Software AG
+ Copyright (C) 2004-2005 SKYRIX Software AG
This file is part of OpenGroupware.org.
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
-// $Id: SOGoMailAccount.m 274 2004-08-26 13:10:49Z znek $
#include "SOGoMailAccount.h"
+#include "SOGoMailFolder.h"
+#include "SOGoMailManager.h"
+#include "SOGoDraftsFolder.h"
+#include <NGObjWeb/SoHTTPAuthenticator.h>
#include "common.h"
@implementation SOGoMailAccount
+static NSArray *rootFolderNames = nil;
+static NSString *inboxFolderName = @"INBOX";
+static NSString *draftsFolderName = @"Drafts";
+static NSString *sieveFolderName = @"Filters";
+static NSString *sharedFolderName = @""; // TODO: add English default
+static NSString *otherUsersFolderName = @""; // TODO: add English default
+static BOOL useAltNamespace = NO;
+
++ (int)version {
+ return [super version] + 0 /* v1 */;
+}
+
++ (void)initialize {
+ NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
+
+ NSAssert2([super version] == 1,
+ @"invalid superclass (%@) version %i !",
+ NSStringFromClass([self superclass]), [super version]);
+
+ useAltNamespace = [ud boolForKey:@"SOGoSpecialFoldersInRoot"];
+
+ sharedFolderName = [ud stringForKey:@"SOGoSharedFolderName"];
+ otherUsersFolderName = [ud stringForKey:@"SOGoOtherUsersFolderName"];
+
+ NSLog(@"Note: using shared-folders name: '%@'", sharedFolderName);
+ NSLog(@"Note: using other-users-folders name: '%@'", otherUsersFolderName);
+
+ if ([ud boolForKey:@"SOGoEnableSieveFolder"]) {
+ rootFolderNames = [[NSArray alloc] initWithObjects:
+ draftsFolderName,
+ sieveFolderName,
+ nil];
+ }
+ else {
+ rootFolderNames = [[NSArray alloc] initWithObjects:
+ draftsFolderName,
+ nil];
+ }
+}
+
+/* shared accounts */
+
+- (BOOL)isSharedAccount {
+ NSString *s;
+ NSRange r;
+
+ s = [self nameInContainer];
+ r = [s rangeOfString:@"@"];
+ if (r.length == 0) /* regular HTTP logins are never a shared mailbox */
+ return NO;
+
+ s = [s substringToIndex:r.location];
+ return [s rangeOfString:@".-."].length > 0 ? YES : NO;
+}
+
+- (NSString *)sharedAccountName {
+ return nil;
+}
+
+/* listing the available folders */
+
+- (NSArray *)additionalRootFolderNames {
+ return rootFolderNames;
+}
+
+- (NSArray *)toManyRelationshipKeys {
+ NSArray *a, *b;
+
+ a = [self additionalRootFolderNames];
+ b = [[self imap4Connection] subfoldersForURL:[self imap4URL]];
+ return [b count] > 0 ? [b arrayByAddingObjectsFromArray:a] : a;
+}
+
+/* hierarchy */
+
+- (SOGoMailAccount *)mailAccountFolder {
+ return self;
+}
+
+- (NSArray *)allFolderPathes {
+ NSArray *pathes;
+
+ pathes = [[self imap4Connection] allFoldersForURL:[self imap4URL] ];
+ pathes = [pathes sortedArrayUsingSelector:@selector(compare:)];
+ return pathes;
+}
+
+/* IMAP4 */
+
+- (BOOL)useSSL {
+ return NO;
+}
+
+- (NSString *)imap4LoginFromHTTP {
+ WORequest *rq;
+ NSString *s;
+ NSArray *creds;
+
+ rq = [[(WOApplication *)[WOApplication application] context] request];
+
+ s = [rq headerForKey:@"x-webobjects-remote-user"];
+ if ([s length] > 0)
+ return s;
+
+ if ((s = [rq headerForKey:@"authorization"]) == nil) {
+ /* no basic auth */
+ return nil;
+ }
+
+ creds = [SoHTTPAuthenticator parseCredentials:s];
+ if ([creds count] < 2)
+ /* somehow invalid */
+ return nil;
+
+ return [creds objectAtIndex:0]; /* the user */
+}
+
+- (NSString *)imap4URLString {
+ /* private, overridden by SOGoSharedMailAccount */
+ NSString *s;
+ NSRange r;
+
+ s = [self nameInContainer];
+ r = [s rangeOfString:@"@"];
+ if (r.length == 0) {
+ NSString *u;
+
+ u = [self imap4LoginFromHTTP];
+ if ([u length] == 0) {
+ [self errorWithFormat:@"missing login in account folder name: %@", s];
+ return nil;
+ }
+ s = [[u stringByAppendingString:@"@"] stringByAppendingString:s];
+ }
+ if ([s hasSuffix:@":80"]) { // HACK
+ [self logWithFormat:@"WARNING: incorrect value for IMAP4 URL: '%@'", s];
+ s = [s substringToIndex:([s length] - 3)];
+ }
+
+ s = [([self useSSL] ? @"imaps://" : @"imap://") stringByAppendingString:s];
+ s = [s stringByAppendingString:@"/"];
+ return s;
+}
+
+- (NSURL *)imap4URL {
+ /* imap://agenortest@mail.opengroupware.org/ */
+ NSString *s;
+
+ if (self->imap4URL != nil)
+ return self->imap4URL;
+
+ if ((s = [self imap4URLString]) == nil)
+ return nil;
+
+ self->imap4URL = [[NSURL alloc] initWithString:s];
+ return self->imap4URL;
+}
+
+- (NSString *)imap4Login {
+ return [[self imap4URL] user];
+}
+
+/* name lookup */
+
+- (id)lookupFolder:(NSString *)_key ofClassNamed:(NSString *)_cn
+ inContext:(id)_cx
+{
+ Class clazz;
+
+ if ((clazz = NSClassFromString(_cn)) == Nil) {
+ [self logWithFormat:@"ERROR: did not find class '%@' for key: '%@'",
+ _cn, _key];
+ return [NSException exceptionWithHTTPStatus:500 /* server error */
+ reason:@"did not find mail folder class!"];
+ }
+ return [[[clazz alloc] initWithName:_key inContainer:self] autorelease];
+}
+
+- (id)lookupImap4Folder:(NSString *)_key inContext:(id)_cx {
+ NSString *s;
+
+ s = [_key isEqualToString:[self trashFolderNameInContext:_cx]]
+ ? @"SOGoTrashFolder" : @"SOGoMailFolder";
+
+ return [self lookupFolder:_key ofClassNamed:s inContext:_cx];
+}
+
+- (id)lookupDraftsFolder:(NSString *)_key inContext:(id)_ctx {
+ return [self lookupFolder:_key ofClassNamed:@"SOGoDraftsFolder"
+ inContext:_ctx];
+}
+- (id)lookupFiltersFolder:(NSString *)_key inContext:(id)_ctx {
+ return [self lookupFolder:_key ofClassNamed:@"SOGoSieveScriptsFolder"
+ inContext:_ctx];
+}
+
+- (id)lookupName:(NSString *)_key inContext:(id)_ctx acquire:(BOOL)_flag {
+ id obj;
+
+ /* first check attributes directly bound to the application */
+ if ((obj = [super lookupName:_key inContext:_ctx acquire:NO]) != nil)
+ return obj;
+
+ // TODO: those should be product.plist bindings? (can't be class bindings
+ // though because they are 'per-account')
+ if ([_key isEqualToString:draftsFolderName]) {
+ if ((obj = [self lookupDraftsFolder:_key inContext:_ctx]) != nil)
+ return obj;
+ }
+ if ([_key isEqualToString:sieveFolderName]) {
+ if ((obj = [self lookupFiltersFolder:_key inContext:_ctx]) != nil)
+ return obj;
+ }
+
+ if ((obj = [self lookupImap4Folder:_key inContext:_ctx]) != nil)
+ return obj;
+
+ /* return 404 to stop acquisition */
+ return [NSException exceptionWithHTTPStatus:404 /* Not Found */];
+}
+
+/* special folders */
+
+- (NSString *)inboxFolderNameInContext:(id)_ctx {
+ return inboxFolderName; /* cannot be changed in Cyrus ? */
+}
+- (NSString *)draftsFolderNameInContext:(id)_ctx {
+ return draftsFolderName; /* SOGo managed folder */
+}
+- (NSString *)sieveFolderNameInContext:(id)_ctx {
+ return sieveFolderName; /* SOGo managed folder */
+}
+- (NSString *)sentFolderNameInContext:(id)_ctx {
+ /* OGo issue #1225 */
+ static NSString *s = nil;
+
+ if (s == nil) {
+ NSUserDefaults *ud;
+
+ ud = [NSUserDefaults standardUserDefaults];
+ s = [[ud stringForKey:@"SOGoSentFolderName"] copy];
+ if ([s length] == 0) s = @"Sent";
+ [self logWithFormat:@"Note: using SOGoSentFolderName: '%@'", s];
+ }
+ return s;
+}
+- (NSString *)trashFolderNameInContext:(id)_ctx {
+ /* OGo issue #1225 */
+ static NSString *s = nil;
+
+ if (s == nil) {
+ NSUserDefaults *ud;
+
+ ud = [NSUserDefaults standardUserDefaults];
+ s = [[ud stringForKey:@"SOGoTrashFolderName"] copy];
+ if ([s length] == 0) s = @"Trash";
+ NSLog(@"Note: using SOGoTrashFolderName: '%@'", s);
+ }
+ return s;
+}
+
+- (SOGoMailFolder *)inboxFolderInContext:(id)_ctx {
+ // TODO: use some profile to determine real location, use a -traverse lookup
+ SOGoMailFolder *folder;
+
+ if (self->inboxFolder != nil)
+ return self->inboxFolder;
+
+ folder = [self lookupName:[self inboxFolderNameInContext:_ctx]
+ inContext:_ctx acquire:NO];
+ if ([folder isKindOfClass:[NSException class]]) return folder;
+
+ return ((self->inboxFolder = [folder retain]));
+}
+
+- (SOGoMailFolder *)sentFolderInContext:(id)_ctx {
+ // TODO: use some profile to determine real location, use a -traverse lookup
+ SOGoMailFolder *folder;
+
+ if (self->sentFolder != nil)
+ return self->sentFolder;
+
+ folder = useAltNamespace ? (id)self : [self inboxFolderInContext:_ctx];
+ if ([folder isKindOfClass:[NSException class]]) return folder;
+
+ folder = [folder lookupName:[self sentFolderNameInContext:_ctx]
+ inContext:_ctx acquire:NO];
+ if ([folder isKindOfClass:[NSException class]]) return folder;
+
+ if (![folder isNotNull]) {
+ return [NSException exceptionWithHTTPStatus:404 /* not found */
+ reason:@"did not find Sent folder!"];
+ }
+
+ return ((self->sentFolder = [folder retain]));
+}
+
+- (SOGoMailFolder *)trashFolderInContext:(id)_ctx {
+ // TODO: use some profile to determine real location
+ SOGoMailFolder *folder;
+
+ if (self->trashFolder != nil)
+ return self->trashFolder;
+
+ folder = useAltNamespace ? (id)self : [self inboxFolderInContext:_ctx];
+ if ([folder isKindOfClass:[NSException class]]) return folder;
+
+ folder = [folder lookupName:[self trashFolderNameInContext:_ctx]
+ inContext:_ctx acquire:NO];
+ if ([folder isKindOfClass:[NSException class]]) return folder;
+
+ if (![folder isNotNull]) {
+ return [NSException exceptionWithHTTPStatus:404 /* not found */
+ reason:@"did not find Trash folder!"];
+ }
+
+ return ((self->trashFolder = [folder retain]));
+}
+
+/* WebDAV */
+
+- (BOOL)davIsCollection {
+ return YES;
+}
+
+- (NSException *)davCreateCollection:(NSString *)_name inContext:(id)_ctx {
+ return [[self imap4Connection] createMailbox:_name atURL:[self imap4URL]];
+}
+
+- (NSString *)shortTitle {
+ NSString *s, *login, *host;
+ NSRange r;
+
+ s = [self nameInContainer];
+
+ r = [s rangeOfString:@"@"];
+ if (r.length > 0) {
+ login = [s substringToIndex:r.location];
+ host = [s substringFromIndex:(r.location + r.length)];
+ }
+ else {
+ login = nil;
+ host = s;
+ }
+
+ r = [host rangeOfString:@"."];
+ if (r.length > 0)
+ host = [host substringToIndex:r.location];
+
+ if ([login length] == 0)
+ return host;
+
+ r = [login rangeOfString:@"."];
+ if (r.length > 0)
+ login = [login substringToIndex:r.location];
+
+ return [NSString stringWithFormat:@"%@@%@", login, host];
+}
+
+- (NSString *)davDisplayName {
+ return [self shortTitle];
+}
+
@end /* SOGoMailAccount */