From b8804341794906a7a4c8ed9d5120d9a5e0993ff3 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 6 Aug 2010 14:25:59 +0000 Subject: [PATCH] Monotone-Parent: ec44ffcb951f3db4e0041a44e56a9f0d5df4ef3b Monotone-Revision: 4363c5abe7a96c858bbccbbad1061ca3229e0217 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2010-08-06T14:25:59 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 41 +++++++ SoObjects/Mailer/SOGoDraftObject.m | 2 +- SoObjects/Mailer/SOGoMailAccount.h | 4 + SoObjects/Mailer/SOGoMailAccount.m | 155 +++++++++++------------ SoObjects/Mailer/SOGoMailBaseObject.h | 1 - SoObjects/Mailer/SOGoMailBaseObject.m | 45 +++---- SoObjects/Mailer/SOGoMailFolder.m | 63 ++++++---- SoObjects/Mailer/SOGoMailForward.m | 3 +- SoObjects/SOGo/SOGoUser.m | 170 ++++++++++++++------------ UI/MailerUI/UIxMailAccountActions.m | 5 +- 10 files changed, 263 insertions(+), 226 deletions(-) diff --git a/ChangeLog b/ChangeLog index b12a54e42..a651500de 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,46 @@ 2010-08-06 Wolfgang Sourdeau + * SoObjects/Mailer/SOGoMailForward.m (-signature): same as below. + + * UI/MailerUI/UIxMailAccountActions.m (-composeAction): same as below. + + * SoObjects/Mailer/SOGoDraftObject.m (-fetchMailForForwarding): + the signature is now taken from the original mail's corresponding + account. + + * SoObjects/Mailer/SOGoMailFolder.m + (-copyUIDs:toFolder:inContext:): we now ensure that the operation + is not attempted on two separate accounts. + (-httpURLForAdvisoryToUser): the returned mail account is now + always "0". + + * SoObjects/Mailer/SOGoMailBaseObject.m (-imap4URL): we now add + the "tls=YES" url parameter if the corresponding account + encryption is set to "tls". + (-imap4Login): removed useless method. + (-imap4PasswordRenewed:): now a proxy to the same method on the + instance account folder. + + * SoObjects/Mailer/SOGoMailAccount.m (-identities, -signature) + (encryption): new helper methods that return the corresponding key + in the appropriate mail account dictionary. + (-_migrateFolderWithPurpose:): moved method in SOGoMailAccount.m. + (-_userFolderNameWithPurpose): rewrote method to make use of the + mail account dictionaries. Fallback on the main account of the + auxiliary ones do not have the required entry. + (-imap4PasswordRenewed:): moved method from SOGoMailBaseObject.m + and use the "password" entry in auxiliary account dicts depending + on "nameInContainer". + (-imap4LoginFromHTTP, -imap4Login): removed useless methods. + + * SoObjects/SOGo/SOGoUser.m (-mailAccounts): we now conditionnally + append the array of auxiliary user accounts, if enabled in the + domain defaults. + (-_appendSystemMailAccount): the user main signature and the + sent, drafts, trash folder location are now stored in the account + dictionaries. Added migration code from us to ud from + SOGoMailAccount.m. + * SoObjects/SOGo/SOGoDomainDefaults.m (-mailAuxiliaryUserAccountsEnabled): new method returning a BOOL describing whether the domain users can access auxiliary mail diff --git a/SoObjects/Mailer/SOGoDraftObject.m b/SoObjects/Mailer/SOGoDraftObject.m index 294bb431e..6333cd51d 100644 --- a/SoObjects/Mailer/SOGoDraftObject.m +++ b/SoObjects/Mailer/SOGoDraftObject.m @@ -722,7 +722,7 @@ static NSString *userAgent = nil; { // TODO: use subject for filename? // error = [newDraft saveAttachment:content withName:@"forward.eml"]; - signature = [ud mailSignature]; + signature = [[self mailAccountFolder] signature]; if ([signature length]) [self setText: [NSString stringWithFormat: @"\n-- \n%@", signature]]; attachment = [NSDictionary dictionaryWithObjectsAndKeys: diff --git a/SoObjects/Mailer/SOGoMailAccount.h b/SoObjects/Mailer/SOGoMailAccount.h index 2e9026ff6..ea90d7195 100644 --- a/SoObjects/Mailer/SOGoMailAccount.h +++ b/SoObjects/Mailer/SOGoMailAccount.h @@ -63,6 +63,10 @@ typedef enum { - (BOOL) supportsQuotas; - (BOOL) updateFilters; +- (NSArray *) identities; +- (NSString *) signature; +- (NSString *) encryption; + /* folder pathes */ - (NSArray *) allFolderPaths; diff --git a/SoObjects/Mailer/SOGoMailAccount.m b/SoObjects/Mailer/SOGoMailAccount.m index 70ab35325..f94e0be8d 100644 --- a/SoObjects/Mailer/SOGoMailAccount.m +++ b/SoObjects/Mailer/SOGoMailAccount.m @@ -40,6 +40,7 @@ #import #import +#import #import #import #import @@ -468,31 +469,6 @@ static NSString *sieveScriptName = @"sogo"; /* IMAP4 */ -- (NSString *) imap4LoginFromHTTP -{ - WORequest *rq; - NSString *s; - NSArray *creds; - - rq = [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 */ -} - - (NSDictionary *) _mailAccount { NSDictionary *mailAccount; @@ -506,6 +482,36 @@ static NSString *sieveScriptName = @"sogo"; return mailAccount; } +- (NSArray *) identities +{ + return [[self _mailAccount] objectForKey: @"identities"]; +} + +- (NSString *) signature +{ + NSArray *identities; + NSString *signature; + + identities = [self identities]; + if ([identities count] > 0) + signature = [[identities objectAtIndex: 0] objectForKey: @"signature"]; + else + signature = nil; + + return signature; +} + +- (NSString *) encryption +{ + NSString *encryption; + + encryption = [[self _mailAccount] objectForKey: @"encryption"]; + if (![encryption length]) + encryption = @"none"; + + return encryption; +} + - (NSMutableString *) imap4URLString { NSMutableString *imap4URLString; @@ -546,9 +552,33 @@ static NSString *sieveScriptName = @"sogo"; return [NSMutableString string]; } -- (NSString *) imap4Login +- (NSString *) imap4PasswordRenewed: (BOOL) renewed { - return [[self imap4URL] user]; + /* + Extract password from basic authentication. + */ + NSURL *imapURL; + NSString *password; + + if ([nameInContainer isEqualToString: @"0"]) + { + imapURL = [self imap4URL]; + + password = [[self authenticatorInContext: context] + imapPasswordInContext: context + forServer: [imapURL host] + forceRenew: renewed]; + if (!password) + [self errorWithFormat: @"no IMAP4 password available"]; + } + else + { + password = [[self _mailAccount] objectForKey: @"password"]; + if (!password) + password = @""; + } + + return password; } /* name lookup */ @@ -604,70 +634,27 @@ static NSString *sieveScriptName = @"sogo"; return inboxFolderName; } -- (BOOL) _migrateFolderWithPurpose: (NSString *) purpose - withName: (NSString *) folderName -{ - SOGoUserDefaults *ud; - NSString *methodName; - SEL methodSel; - BOOL rc; - - ud = [[context activeUser] userDefaults]; - methodName = [NSString stringWithFormat: @"set%@FolderName:", purpose]; - methodSel = NSSelectorFromString (methodName); - if ([ud respondsToSelector: methodSel]) - { - [ud performSelector: methodSel withObject: folderName]; - [ud synchronize]; - rc = YES; - } - else - { - [self errorWithFormat: @"method '%@' not available with user defaults" - @" object, folder migration fails", methodName]; - rc = NO; - } - - return rc; -} - - (NSString *) _userFolderNameWithPurpose: (NSString *) purpose { SOGoUser *user; - SOGoUserSettings *us; - SOGoUserDefaults *ud; - NSMutableDictionary *mailSettings; - NSString *folderName, *key, *methodName; - SEL methodSel; + NSArray *accounts; + int accountIdx; + NSDictionary *account; + NSString *folderName; folderName = nil; - user = [context activeUser]; - /* migration part: */ - us = [user userSettings]; - mailSettings = [us objectForKey: @"Mail"]; - if (mailSettings) + user = [SOGoUser userWithLogin: [self ownerInContext: nil]]; + accounts = [user mailAccounts]; + accountIdx = [nameInContainer intValue]; + account = [accounts objectAtIndex: accountIdx]; + folderName = [[account objectForKey: @"mailboxes"] + objectForKey: purpose]; + if (!folderName && accountIdx > 0) { - key = [NSString stringWithFormat: @"%@Folder", purpose]; - folderName = [mailSettings objectForKey: key]; - if ([folderName length] - && [self _migrateFolderWithPurpose: purpose withName: folderName]) - { - [mailSettings removeObjectForKey: key]; - [us synchronize]; - folderName = nil; - } - } - else - folderName = nil; - - if (!folderName) - { - ud = [[context activeUser] userDefaults]; - methodName = [NSString stringWithFormat: @"%@FolderName", - [purpose lowercaseString]]; - methodSel = NSSelectorFromString (methodName); - folderName = [ud performSelector: methodSel]; + account = [accounts objectAtIndex: 0]; + folderName = [[account objectForKey: @"mailboxes"] + objectForKey: purpose]; } return folderName; diff --git a/SoObjects/Mailer/SOGoMailBaseObject.h b/SoObjects/Mailer/SOGoMailBaseObject.h index 11c56105c..e7878b73d 100644 --- a/SoObjects/Mailer/SOGoMailBaseObject.h +++ b/SoObjects/Mailer/SOGoMailBaseObject.h @@ -69,7 +69,6 @@ - (NSMutableString *) traversalFromMailAccount; - (NSURL *) imap4URL; -- (NSString *) imap4Login; - (NSString *) imap4PasswordRenewed: (BOOL) renew; - (void) flushMailCaches; diff --git a/SoObjects/Mailer/SOGoMailBaseObject.m b/SoObjects/Mailer/SOGoMailBaseObject.m index eb77fa2f9..be239344a 100644 --- a/SoObjects/Mailer/SOGoMailBaseObject.m +++ b/SoObjects/Mailer/SOGoMailBaseObject.m @@ -30,8 +30,7 @@ #import #import -#import - +#import "SOGoMailAccount.h" #import "SOGoMailManager.h" #import "SOGoMailBaseObject.h" @@ -187,44 +186,28 @@ static BOOL debugOn = YES; - (NSURL *) imap4URL { + SOGoMailAccount *account; + NSString *urlString; + /* this could probably be handled better from NSURL but it's buggy in GNUstep */ if (!imap4URL) - imap4URL = [[NSURL alloc] initWithString: [self imap4URLString]]; + { + account = [self mailAccountFolder]; + if ([[account encryption] isEqualToString: @"tls"]) + urlString = [NSString stringWithFormat: @"%@?tls=YES", + [self imap4URLString]]; + else + urlString = [self imap4URLString]; + imap4URL = [[NSURL alloc] initWithString: urlString]; + } return imap4URL; } -- (NSString *) imap4Login -{ - if (![container respondsToSelector:_cmd]) - return nil; - - return [container imap4Login]; -} - - (NSString *) imap4PasswordRenewed: (BOOL) renewed { - /* - Extract password from basic authentication. - - TODO: we might want to - a) move the primary code to SOGoMailAccount - b) cache the password - */ - NSURL *imapURL; - NSString *password; - - imapURL = [[self mailAccountFolder] imap4URL]; - - password = [[self authenticatorInContext: context] - imapPasswordInContext: context - forServer: [imapURL host] - forceRenew: renewed]; - if (!password) - [self errorWithFormat: @"no IMAP4 password available"]; - - return password; + return [[self mailAccountFolder] imap4PasswordRenewed: renewed]; } - (NSMutableString *) traversalFromMailAccount diff --git a/SoObjects/Mailer/SOGoMailFolder.m b/SoObjects/Mailer/SOGoMailFolder.m index 1d60f8d43..e0b321eeb 100644 --- a/SoObjects/Mailer/SOGoMailFolder.m +++ b/SoObjects/Mailer/SOGoMailFolder.m @@ -447,7 +447,7 @@ static NSString *defaultUserID = @"anyone"; inContext: (id) localContext { NSArray *folders; - NSString *currentFolderName; + NSString *currentFolderName, *currentAccountName; NSMutableString *imapDestinationFolder; NGImap4Client *client; id result; @@ -458,31 +458,45 @@ static NSString *defaultUserID = @"anyone"; folders = [[destinationFolder componentsSeparatedByString: @"/"] resultsOfSelector: @selector (fromCSSIdentifier)]; max = [folders count]; - for (count = 2; count < max; count++) + if (max > 1) { - currentFolderName - = [[folders objectAtIndex: count] substringFromIndex: 6]; - [imapDestinationFolder appendFormat: @"/%@", currentFolderName]; + currentAccountName = [[self mailAccountFolder] nameInContainer]; + if ([[folders objectAtIndex: 1] isEqualToString: currentAccountName]) + { + for (count = 2; count < max; count++) + { + currentFolderName + = [[folders objectAtIndex: count] substringFromIndex: 6]; + [imapDestinationFolder appendFormat: @"/%@", currentFolderName]; + } + + client = [[self imap4Connection] client]; + [imap4 selectFolder: [self imap4URL]]; + + // We make sure the destination IMAP folder exist, if not, we create it. + result = [[client status: imapDestinationFolder + flags: [NSArray arrayWithObject: @"UIDVALIDITY"]] + objectForKey: @"result"]; + if (![result boolValue]) + result = [[self imap4Connection] createMailbox: imapDestinationFolder + atURL: [[self mailAccountFolder] imap4URL]]; + if (!result || [result boolValue]) + result = [client copyUids: uids toFolder: imapDestinationFolder]; + + if ([[result valueForKey: @"result"] boolValue]) + result = nil; + else + result = [NSException exceptionWithHTTPStatus: 500 + reason: @"Couldn't copy UIDs."]; + } + else + result = [NSException exceptionWithHTTPStatus: 500 + reason: @"Cannot copy messages across different accounts."]; } - - client = [[self imap4Connection] client]; - [imap4 selectFolder: [self imap4URL]]; - - // We make sure the destination IMAP folder exist, if not, we create it. - result = [[client status: imapDestinationFolder - flags: [NSArray arrayWithObject: @"UIDVALIDITY"]] - objectForKey: @"result"]; - if (![result boolValue]) - result = [[self imap4Connection] createMailbox: imapDestinationFolder - atURL: [[self mailAccountFolder] imap4URL]]; - if (!result || [result boolValue]) - result = [client copyUids: uids toFolder: imapDestinationFolder]; - - if ([[result valueForKey: @"result"] boolValue]) - result = nil; else - result = [NSException exceptionWithHTTPStatus: 500 reason: @"Couldn't copy UIDs."]; - + result = [NSException exceptionWithHTTPStatus: 500 + reason: @"Invalid destination."]; + return result; } @@ -1061,9 +1075,8 @@ static NSString *defaultUserID = @"anyone"; { thisAccount = [self mailAccountFolder]; mailAccount = [[user mailAccounts] objectAtIndex: 0]; - url = [NSString stringWithFormat: @"%@/%@%@", + url = [NSString stringWithFormat: @"%@/0%@", [self soURLToBaseContainerForUser: uid], - [mailAccount objectForKey: @"name"], otherUsersPath]; } else diff --git a/SoObjects/Mailer/SOGoMailForward.m b/SoObjects/Mailer/SOGoMailForward.m index d1f7261d7..b9b474e17 100644 --- a/SoObjects/Mailer/SOGoMailForward.m +++ b/SoObjects/Mailer/SOGoMailForward.m @@ -29,6 +29,7 @@ #import #import +#import "SOGoMailAccount.h" #import "SOGoMailObject+Draft.h" #import "SOGoMailForward.h" @@ -221,7 +222,7 @@ SOGoUserDefaults *ud; ud = [[context activeUser] userDefaults]; - signature = [ud mailSignature]; + signature = [[sourceMail mailAccountFolder] signature]; if ([signature length]) mailSignature = [NSString stringWithFormat: @"-- \n%@", signature]; else diff --git a/SoObjects/SOGo/SOGoUser.m b/SoObjects/SOGo/SOGoUser.m index 6a7c88176..a2014c405 100644 --- a/SoObjects/SOGo/SOGoUser.m +++ b/SoObjects/SOGo/SOGoUser.m @@ -436,11 +436,73 @@ } /* mail */ +- (BOOL) _migrateFolderWithPurpose: (NSString *) purpose + withName: (NSString *) folderName +{ + NSString *methodName; + SEL methodSel; + BOOL rc; + + [self userDefaults]; + methodName = [NSString stringWithFormat: @"set%@FolderName:", purpose]; + methodSel = NSSelectorFromString (methodName); + if ([_defaults respondsToSelector: methodSel]) + { + [_defaults performSelector: methodSel withObject: folderName]; + rc = YES; + } + else + { + [self errorWithFormat: @"method '%@' not available with user defaults" + @" object, folder migration fails", methodName]; + rc = NO; + } + + return rc; +} + +- (void) _migrateFolderSettings +{ + NSMutableDictionary *mailSettings; + NSString *folderName, *key; + BOOL migrated; + NSString **purpose; + NSString *purposes[] = { @"Drafts", @"Sent", @"Trash", nil }; + + [self userSettings]; + mailSettings = [_settings objectForKey: @"Mail"]; + if (mailSettings) + { + migrated = NO; + purpose = purposes; + while (*purpose) + { + key = [NSString stringWithFormat: @"%@Folder", purpose]; + folderName = [mailSettings objectForKey: key]; + if ([folderName length] + && [self _migrateFolderWithPurpose: *purpose + withName: folderName]) + { + migrated = YES; + [mailSettings removeObjectForKey: key]; + folderName = nil; + } + purpose++; + } + if (migrated) + { + [_settings synchronize]; + [self userDefaults]; + [_defaults synchronize]; + } + } +} + - (void) _appendSystemMailAccount { - NSMutableDictionary *mailAccount, *identity; + NSMutableDictionary *mailAccount, *identity, *mailboxes; NSMutableArray *identities; - NSString *fullName, *imapLogin, *imapServer; + NSString *fullName, *imapLogin, *imapServer, *signature; NSArray *mails; unsigned int count, max; @@ -451,6 +513,7 @@ imapServer = [self _fetchFieldForUser: @"c_imaphostname"]; if (!imapServer) imapServer = [[self domainDefaults] imapServer]; + [mailAccount setObject: imapLogin forKey: @"userName"]; [mailAccount setObject: imapServer forKey: @"serverName"]; @@ -469,6 +532,9 @@ fullName = login; [identity setObject: fullName forKey: @"fullName"]; [identity setObject: [mails objectAtIndex: count] forKey: @"email"]; + signature = [[self userDefaults] mailSignature]; + if (signature) + [identity setObject: signature forKey: @"signature"]; [identities addObject: identity]; [identity release]; } @@ -477,16 +543,38 @@ [mailAccount setObject: identities forKey: @"identities"]; [identities release]; - [mailAccounts addObject: mailAccount]; + + mailboxes = [NSMutableDictionary new]; + + [self userDefaults]; + [self _migrateFolderSettings]; + [mailboxes setObject: [_defaults draftsFolderName] + forKey: @"Drafts"]; + [mailboxes setObject: [_defaults sentFolderName] + forKey: @"Sent"]; + [mailboxes setObject: [_defaults trashFolderName] + forKey: @"Trash"]; + [mailAccount setObject: mailboxes forKey: @"mailboxes"]; + [mailboxes release]; + + [mailAccounts addObject: mailAccount]; [mailAccount release]; } - (NSArray *) mailAccounts { + NSArray *auxAccounts; + if (!mailAccounts) { mailAccounts = [NSMutableArray new]; [self _appendSystemMailAccount]; + if ([[self domainDefaults] mailAuxiliaryUserAccountsEnabled]) + { + auxAccounts = [[self userDefaults] auxiliaryMailAccounts]; + if (auxAccounts) + [mailAccounts addObjectsFromArray: auxAccounts]; + } } return mailAccounts; @@ -509,60 +597,6 @@ return mailAccount; } -/* -@interface SOGoMailIdentity : NSObject -{ - NSString *name; - NSString *email; - NSString *replyTo; - NSString *organization; - NSString *signature; - NSString *vCard; - NSString *sentFolderName; - NSString *sentBCC; - NSString *draftsFolderName; - NSString *templatesFolderName; - struct - { - int composeHTML:1; - int reserved:31; - } idFlags; -} - -- (void) setName: (NSString *) _value; -- (NSString *) name; - -- (void) setEmail: (NSString *) _value; -- (NSString *) email; - -- (void) setReplyTo: (NSString *) _value; -- (NSString *) replyTo; - -- (void) setOrganization: (NSString *) _value; -- (NSString *) organization; - -- (void) setSignature: (NSString *) _value; -- (NSString *) signature; -- (BOOL) hasSignature; - -- (void) setVCard: (NSString *) _value; -- (NSString *) vCard; -- (BOOL) hasVCard; - -- (void) setSentFolderName: (NSString *) _value; -- (NSString *) sentFolderName; - -- (void) setSentBCC: (NSString *) _value; -- (NSString *) sentBCC; - -- (void) setDraftsFolderName: (NSString *) _value; -- (NSString *) draftsFolderName; - -- (void) setTemplatesFolderName: (NSString *) _value; -- (NSString *) templatesFolderName; - -@end */ - - (NSArray *) allIdentities { NSArray *identities; @@ -607,28 +641,6 @@ ignoringRights: YES]; } -// - (id) schedulingCalendarInContext: (id) _ctx -// { -// /* Note: watch out for cyclic references */ -// id folder; - -// folder = [(WOContext *)_ctx objectForKey:@"ActiveUserCalendar"]; -// if (folder != nil) -// return [folder isNotNull] ? folder : nil; - -// folder = [self homeFolderInContext:_ctx]; -// if ([folder isKindOfClass:[NSException class]]) -// return folder; - -// folder = [folder lookupName:@"Calendar" inContext:_ctx acquire:NO]; -// if ([folder isKindOfClass:[NSException class]]) -// return folder; - -// [(WOContext *)_ctx setObject:folder ? folder : [NSNull null] -// forKey:@"ActiveUserCalendar"]; -// return folder; -// } - - (NSArray *) rolesForObject: (NSObject *) object inContext: (WOContext *) context { diff --git a/UI/MailerUI/UIxMailAccountActions.m b/UI/MailerUI/UIxMailAccountActions.m index 954ee4a23..a26443fbd 100644 --- a/UI/MailerUI/UIxMailAccountActions.m +++ b/UI/MailerUI/UIxMailAccountActions.m @@ -41,7 +41,6 @@ #import #import #import -#import #import "../Common/WODirectAction+SOGo.h" @@ -232,7 +231,6 @@ { SOGoDraftsFolder *drafts; SOGoDraftObject *newDraftMessage; - SOGoUserDefaults *ud; NSString *urlBase, *url, *value, *signature; NSArray *mailTo; NSMutableDictionary *headers; @@ -262,8 +260,7 @@ if (save) [newDraftMessage setHeaders: headers]; - ud = [[context activeUser] userDefaults]; - signature = [ud mailSignature]; + signature = [[self clientObject] signature]; if ([signature length]) { [newDraftMessage