diff --git a/ChangeLog b/ChangeLog index 5179e5f8b..942d0282a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -20,6 +20,31 @@ * UI/WebServerResources/ContactsUI.js (appendAddressBook): assume that lists can be created in the new addressbook. +2012-02-28 Wolfgang Sourdeau + + * OpenChange/MAPIStoreMailFolder.m + (-moveCopyMessagesWithMIDs:andCount:fromFolder:withMIDs:andChangeKeys:wantCopy:): + we sync the version cache with the folder in order to update the + target message change keys, which was causing versioning issues + with Outlook 2010. + + * OpenChange/gen-property-selectors.py: bannedProps is now an + array instead of a dict of "True" values. + Added "PrOabContainerGuid" to bannedProps. + +2012-02-27 Wolfgang Sourdeau + + * OpenChange/MAPIStoreUserContext.m (-rootFolders:): + -[NGImap4Connection enableExtensions:] now takes an array of + strings rather than a single string argument. + +2012-02-24 Wolfgang Sourdeau + + * SoObjects/Mailer/SOGoMailFolder.m: ensure the imap connection is + available before performing certain operations, otherwise return + an exception. This only applies on methods that return an + exception, others were left untouched. + 2012-02-23 Wolfgang Sourdeau * OpenChange/MAPIStoreMailContext.m diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 3aefb8931..592674ee5 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -902,7 +902,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) { NGImap4Connection *connection; NGImap4Client *client; - NSString *sourceFolderName, *targetFolderName, *messageURL, *v; + NSString *sourceFolderName, *targetFolderName, *messageURL, *messageKey, *v; NSMutableArray *uids, *oldMessageURLs; NSNumber *uid; NSArray *destUIDs; @@ -910,6 +910,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) NSDictionary *result; NSUInteger count; NSArray *a; + NSData *changeKey; if (![sourceFolder isKindOfClass: [MAPIStoreMailFolder class]]) return [super moveCopyMessagesWithMIDs: srcMids andCount: midCount @@ -989,6 +990,17 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) [mapping registerURL: messageURL withID: targetMids[count]]; } + /* Update the change keys */ + [self synchroniseCache]; + for (count = 0; count < midCount; count++) + { + changeKey = [NSData dataWithBinary: targetChangeKeys[count]]; + messageKey = [NSString stringWithFormat: @"%@.eml", + [destUIDs objectAtIndex: count]]; + [self setChangeKey: changeKey + forMessageWithKey: messageKey]; + } + [self postNotificationsForMoveCopyMessagesWithMIDs: srcMids andMessageURLs: oldMessageURLs andCount: midCount diff --git a/OpenChange/MAPIStoreUserContext.m b/OpenChange/MAPIStoreUserContext.m index 222f1d560..53f20d37c 100644 --- a/OpenChange/MAPIStoreUserContext.m +++ b/OpenChange/MAPIStoreUserContext.m @@ -188,7 +188,7 @@ static NSMapTable *contextsTable = nil; [rootFolders setObject: currentFolder forKey: @"mail"]; [[currentFolder imap4Connection] - enableExtension: @"QRESYNC"]; + enableExtensions: [NSArray arrayWithObject: @"QRESYNC"]]; } return rootFolders; diff --git a/OpenChange/gen-property-selectors.py b/OpenChange/gen-property-selectors.py index abf2fb283..cd638b351 100755 --- a/OpenChange/gen-property-selectors.py +++ b/OpenChange/gen-property-selectors.py @@ -106,15 +106,12 @@ extern const enum MAPITAGS MAPIStoreSupportedProperties[]; # hack: some properties have multiple and incompatible types. Sometimes those # props are not related at all... -bannedProps = { "PrBodyHtml": True, "PrFavAutosubfolders": True, - "PrAttachDataObj": True, "PrAclTable": True, - "PrAclData": True, "PrRulesTable": True, "PrRulesData": True, - "PrDisableWinsock": True, "PrHierarchyServer": True, - "PrOfflineAddrbookEntryid": True, - "PrShorttermEntryidFromObject": True, - "PrNormalMessageSizeExtended": True, - "PrAssocMessageSizeExtended": True, - "PrMessageSizeExtended": True } +bannedProps = [ "PrBodyHtml", "PrFavAutosubfolders", "PrAttachDataObj", + "PrAclTable", "PrAclData", "PrRulesTable", "PrRulesData", + "PrDisableWinsock", "PrHierarchyServer", + "PrOfflineAddrbookEntryid", "PrShorttermEntryidFromObject", + "PrNormalMessageSizeExtended", "PrAssocMessageSizeExtended", + "PrMessageSizeExtended", "PrOabContainerGuid" ] def ParseExchangeH(names, lines): state = 0 @@ -151,7 +148,7 @@ def ParseExchangeHDefinition(names, line): propName = GenExchangeHName(stripped[0:eqIdx]) if not propName.endswith("Error") and not propName.endswith("Unicode") \ and not propName.startswith("PrProfile") \ - and not bannedProps.has_key(propName): + and propName not in bannedProps: intIdx = stripped.find("(int", eqIdx) valueIdx = stripped.find("0x", intIdx + 1) endIdx = stripped.find(")", valueIdx) diff --git a/SoObjects/Mailer/SOGoMailFolder.m b/SoObjects/Mailer/SOGoMailFolder.m index 87cece7d8..886a9b032 100644 --- a/SoObjects/Mailer/SOGoMailFolder.m +++ b/SoObjects/Mailer/SOGoMailFolder.m @@ -279,32 +279,38 @@ static NSString *defaultUserID = @"anyone"; { [self imap4URL]; - [self imap4Connection]; - client = [imap4 client]; + if ([self imap4Connection]) + { + client = [imap4 client]; - inbox = [[self mailAccountFolder] inboxFolderInContext: context]; - [client select: [inbox absoluteImap4Name]]; + inbox = [[self mailAccountFolder] inboxFolderInContext: context]; + [client select: [inbox absoluteImap4Name]]; - path = [[imap4URL path] stringByDeletingLastPathComponent]; - if (![path hasSuffix: @"/"]) - path = [path stringByAppendingString: @"/"]; - destURL = [[NSURL alloc] initWithScheme: [imap4URL scheme] - host: [imap4URL host] - path: [NSString stringWithFormat: @"%@%@", - path, newName]]; - [destURL autorelease]; - error = [imap4 moveMailboxAtURL: imap4URL - toURL: destURL]; - if (!error) - { - // We unsubscribe to the old one, and subscribe back to the new one - if ([[[context activeUser] userDefaults] - mailShowSubscribedFoldersOnly]) - { - [client subscribe: [destURL path]]; - [client unsubscribe: [imap4URL path]]; - } - } + path = [[imap4URL path] stringByDeletingLastPathComponent]; + if (![path hasSuffix: @"/"]) + path = [path stringByAppendingString: @"/"]; + destURL = [[NSURL alloc] initWithScheme: [imap4URL scheme] + host: [imap4URL host] + path: [NSString stringWithFormat: @"%@%@", + path, newName]]; + [destURL autorelease]; + error = [imap4 moveMailboxAtURL: imap4URL + toURL: destURL]; + if (!error) + { + // We unsubscribe to the old one, and subscribe back to the new one + if ([[[context activeUser] userDefaults] + mailShowSubscribedFoldersOnly]) + { + [client subscribe: [destURL path]]; + [client unsubscribe: [imap4URL path]]; + } + } + } + else + error = [NSException exceptionWithName: @"SOGoMailException" + reason: @"IMAP connection is invalid" + userInfo: nil]; } else error = [NSException exceptionWithName: @"SOGoMailException" @@ -390,33 +396,41 @@ static NSString *defaultUserID = @"anyone"; error = (NSException *) trashFolder; else { - client = [[self imap4Connection] client]; - [imap4 selectFolder: [self imap4URL]]; - folderName = [imap4 imap4FolderNameForURL: [trashFolder imap4URL]]; - b = YES; + if ([self imap4Connection]) + { + error = nil; + client = [imap4 client]; + [imap4 selectFolder: [self imap4URL]]; + folderName = [imap4 imap4FolderNameForURL: [trashFolder imap4URL]]; + b = YES; - // If we are deleting messages within the Trash folder itself, we - // do not, of course, try to move messages to the Trash folder. - if ([folderName isEqualToString: [self relativeImap4Name]]) - { - *withTrash = NO; - } - else - { - // If our Trash folder doesn't exist when we try to copy messages - // to it, we create it. - result = [[client status: folderName flags: [NSArray arrayWithObject: @"UIDVALIDITY"]] - objectForKey: @"result"]; + // If we are deleting messages within the Trash folder itself, we + // do not, of course, try to move messages to the Trash folder. + if ([folderName isEqualToString: [self relativeImap4Name]]) + { + *withTrash = NO; + } + else + { + // If our Trash folder doesn't exist when we try to copy messages + // to it, we create it. + result = [[client status: folderName flags: [NSArray arrayWithObject: @"UIDVALIDITY"]] + objectForKey: @"result"]; - if (![result boolValue]) - [[self imap4Connection] createMailbox: folderName - atURL: [[self mailAccountFolder] imap4URL]]; + if (![result boolValue]) + [imap4 createMailbox: folderName + atURL: [[self mailAccountFolder] imap4URL]]; - result = [[client copyUids: uids toFolder: folderName] - objectForKey: @"result"]; + result = [[client copyUids: uids toFolder: folderName] + objectForKey: @"result"]; - b = [result boolValue]; + b = [result boolValue]; + } } + else + error = [NSException exceptionWithName: @"SOGoMailException" + reason: @"IMAP connection is invalid" + userInfo: nil]; } } else @@ -602,23 +616,32 @@ static NSString *defaultUserID = @"anyone"; } client = [[self imap4Connection] client]; - [imap4 selectFolder: [self imap4URL]]; + if (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]; + // 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; + if ([[result valueForKey: @"result"] boolValue]) + result = nil; + else + result = [NSException exceptionWithHTTPStatus: 500 + reason: [[[result objectForKey: @"RawResponse"] + objectForKey: @"ResponseResult"] + objectForKey: @"description"]]; + } else - result = [NSException exceptionWithHTTPStatus: 500 - reason: [[[result objectForKey: @"RawResponse"] objectForKey: @"ResponseResult"] objectForKey: @"description"]]; + result = [NSException exceptionWithName: @"SOGoMailException" + reason: @"IMAP connection is invalid" + userInfo: nil]; } else result = [NSException exceptionWithHTTPStatus: 500 @@ -639,18 +662,24 @@ static NSString *defaultUserID = @"anyone"; NGImap4Client *client; client = [[self imap4Connection] client]; - - result = [self copyUIDs: uids toFolder: destinationFolder inContext: localContext]; - if (![result isNotNull]) + if (client) { - result = [client storeFlags: [NSArray arrayWithObject: @"Deleted"] - forUIDs: uids addOrRemove: YES]; - if ([[result valueForKey: @"result"] boolValue]) - { - [self markForExpunge]; - result = nil; - } + result = [self copyUIDs: uids toFolder: destinationFolder inContext: localContext]; + if (![result isNotNull]) + { + result = [client storeFlags: [NSArray arrayWithObject: @"Deleted"] + forUIDs: uids addOrRemove: YES]; + if ([[result valueForKey: @"result"] boolValue]) + { + [self markForExpunge]; + result = nil; + } + } } + else + result = [NSException exceptionWithName: @"SOGoMailException" + reason: @"IMAP connection is invalid" + userInfo: nil]; return result; } @@ -734,7 +763,15 @@ static NSString *defaultUserID = @"anyone"; - (NSException *) expunge { - return [[self imap4Connection] expungeAtURL: [self imap4URL]]; + NSException *error; + + if ([self imap4Connection]) + error = [imap4 expungeAtURL: [self imap4URL]]; + else + error = [NSException exceptionWithName: @"SOGoMailException" + reason: @"IMAP connection is invalid" + userInfo: nil]; + return error; } - (void) markForExpunge @@ -790,8 +827,17 @@ static NSString *defaultUserID = @"anyone"; - (NSException *) addFlagsToAllMessages: (id) _f { - return [[self imap4Connection] addFlags:_f - toAllMessagesInURL: [self imap4URL]]; + NSException *error; + + if ([self imap4Connection]) + error = [imap4 addFlags:_f + toAllMessagesInURL: [self imap4URL]]; + else + error = [NSException exceptionWithName: @"SOGoMailException" + reason: @"IMAP connection is invalid" + userInfo: nil]; + + return error; } /* name lookup */ @@ -860,7 +906,16 @@ static NSString *defaultUserID = @"anyone"; - (NSException *) davCreateCollection: (NSString *) _name inContext: (id) _ctx { - return [[self imap4Connection] createMailbox:_name atURL:[self imap4URL]]; + NSException *error; + + if ([self imap4Connection]) + error = [imap4 createMailbox:_name atURL:[self imap4URL]]; + else + error = [NSException exceptionWithName: @"SOGoMailException" + reason: @"IMAP connection is invalid" + userInfo: nil]; + + return error; } - (BOOL) exists @@ -873,29 +928,43 @@ static NSString *defaultUserID = @"anyone"; NSException *error; BOOL rc; - [self imap4Connection]; - error = [imap4 createMailbox: [self relativeImap4Name] - atURL: [container imap4URL]]; - if (error) - rc = NO; - else + if ([self imap4Connection]) { - [[imap4 client] subscribe: [self absoluteImap4Name]]; - rc = YES; + error = [imap4 createMailbox: [self relativeImap4Name] + atURL: [container imap4URL]]; + if (error) + rc = NO; + else + { + [[imap4 client] subscribe: [self absoluteImap4Name]]; + rc = YES; + } } + else + rc = NO; return rc; } - (NSException *) delete { - return [[self imap4Connection] deleteMailboxAtURL:[self imap4URL]]; + NSException *error; + + if ([self imap4Connection]) + error = [imap4 deleteMailboxAtURL: [self imap4URL]]; + else + error = [NSException exceptionWithName: @"SOGoMailException" + reason: @"IMAP connection is invalid" + userInfo: nil]; + + return error; } - (NSException *) davMoveToTargetObject: (id) _target newName: (NSString *) _name inContext: (id)_ctx { + NSException *error; NSURL *destImapURL; if ([_name length] == 0) { /* target already exists! */ @@ -920,9 +989,16 @@ static NSString *defaultUserID = @"anyone"; [self logWithFormat:@"TODO: should move collection as '%@' to: %@", [[self imap4URL] absoluteString], [destImapURL absoluteString]]; - - return [[self imap4Connection] moveMailboxAtURL:[self imap4URL] - toURL:destImapURL]; + + if ([self imap4Connection]) + error = [imap4 moveMailboxAtURL: [self imap4URL] + toURL: destImapURL]; + else + error = [NSException exceptionWithName: @"SOGoMailException" + reason: @"IMAP connection is invalid" + userInfo: nil]; + + return error; } - (NSException *) davCopyToTargetObject: (id) _target diff --git a/Version b/Version index bf09603b5..09503ebca 100644 --- a/Version +++ b/Version @@ -2,6 +2,6 @@ # This file is included by library makefiles to set the version information # of the executable. -MAJOR_VERSION=1 -MINOR_VERSION=3 -SUBMINOR_VERSION=13 +MAJOR_VERSION=2 +MINOR_VERSION=0 +SUBMINOR_VERSION=0