From a5550cff18db6f7b17ba3fbb30b0b155f06fa03f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Fri, 20 Jun 2014 17:12:26 +0200 Subject: [PATCH 001/120] avoid decode @ from url with username on it --- OpenChange/MAPIStoreContext.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/OpenChange/MAPIStoreContext.m b/OpenChange/MAPIStoreContext.m index 5b73173d8..82de03b75 100644 --- a/OpenChange/MAPIStoreContext.m +++ b/OpenChange/MAPIStoreContext.m @@ -367,8 +367,9 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri) NSString *objectURL, *url; // TDB_DATA key, dbuf; - url = [[contextUrl absoluteString] - stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; + url = [contextUrl absoluteString]; + // FIXME transform percent escapes but not for user part of the url + //stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; objectURL = [[userContext mapping] urlFromID: fmid]; if (objectURL) { From f1d14fdeca522120a5350b30cf958b456fdef613 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Fri, 27 Jun 2014 15:40:21 +0200 Subject: [PATCH 002/120] multitenancy: adapt openchangedb_* calls --- OpenChange/MAPIStoreContext.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenChange/MAPIStoreContext.m b/OpenChange/MAPIStoreContext.m index 82de03b75..1b370c2f3 100644 --- a/OpenChange/MAPIStoreContext.m +++ b/OpenChange/MAPIStoreContext.m @@ -550,7 +550,7 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri) { uint64_t newVersionNumber; - if (openchangedb_get_new_changeNumber (connInfo->oc_ctx, &newVersionNumber) + if (openchangedb_get_new_changeNumber (connInfo->oc_ctx, connInfo->username, &newVersionNumber) != MAPI_E_SUCCESS) abort (); @@ -567,9 +567,9 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri) memCtx = talloc_zero(NULL, TALLOC_CTX); newChangeNumbers = [NSMutableArray arrayWithCapacity: max]; - + if (openchangedb_get_new_changeNumbers (connInfo->oc_ctx, - memCtx, max, &numbers) + memCtx, connInfo->username, max, &numbers) != MAPI_E_SUCCESS || numbers->cValues != max) abort (); for (count = 0; count < max; count++) From 68c38e2b5c0958a4ec96b56c2e0c16948fa73307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Tue, 29 Jul 2014 18:51:37 +0200 Subject: [PATCH 003/120] openchange: return proper url for folders with non-ascii chars toManyRelationshipKeysWithNamespaces applies asCSSIdentifier function to the names which are already "Imap4Encoded". So we need to remove the CSSIdentifier function first and then "Imap4Decode" to get the real name. Once we have the real name, to create the url we have to use the same logic as the function that creates the folder and creates this url for the first time (this function is createRootSecondaryFolderWithFID) which is to apply, in this order: - asCSSIdentifier - stringByEncodingImap4FolderName - stringByAddingPercentEscapesUsingEncoding --- OpenChange/MAPIStoreMailContext.m | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/OpenChange/MAPIStoreMailContext.m b/OpenChange/MAPIStoreMailContext.m index 24d974e5a..0cddee582 100644 --- a/OpenChange/MAPIStoreMailContext.m +++ b/OpenChange/MAPIStoreMailContext.m @@ -87,7 +87,7 @@ MakeDisplayFolderName (NSString *folderName) inMemCtx: (TALLOC_CTX *) memCtx { struct mapistore_contexts_list *firstContext = NULL, *context; - NSString *urlBase, *stringData, *currentName, *inboxName, *draftsName, *sentName, *trashName; + NSString *urlBase, *stringData, *currentName, *realName, *inboxName, *draftsName, *sentName, *trashName; NSArray *unprefixedFolders; NSMutableArray *secondaryFolders; enum mapistore_context_role role[] = {MAPISTORE_MAIL_ROLE, @@ -153,12 +153,23 @@ MakeDisplayFolderName (NSString *folderName) for (count = 0; count < max; count++) { context = talloc_zero (memCtx, struct mapistore_contexts_list); + // secondaryFolders has the names (1) Imap4Encoded and (2) asCSSIdentifier + // e.g.: Probl&AOg-mes_SP_de_SP_synchronisation currentName = [secondaryFolders objectAtIndex: count]; - stringData = [NSString stringWithFormat: @"%@%@", - urlBase, [currentName stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]]; - context->url = [stringData asUnicodeInMemCtx: context]; - stringData = [[[currentName substringFromIndex: 6] fromCSSIdentifier] stringByDecodingImap4FolderName]; - context->name = [stringData asUnicodeInMemCtx: context]; + // To get the real name we have to revert that (applying the decode functions) + // in reverse order + // e.g.: Problèmes de synchronisation + realName = [[currentName fromCSSIdentifier] + stringByDecodingImap4FolderName]; + // And finally to represent that as URI we have to (1) asCSSIdentifier, + // (2) Imap4Encode and (3) AddPercentEscapes + // e.g.: Probl&AOg-mes_SP_de_SP_synchronisation + // In the example there are no percent escapes added because is already ok + stringData = [[[realName asCSSIdentifier] + stringByEncodingImap4FolderName] + stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; + context->url = [[NSString stringWithFormat: @"%@%@", urlBase, stringData] asUnicodeInMemCtx: context]; + context->name = [[realName substringFromIndex: 6] asUnicodeInMemCtx: context]; context->main_folder = false; context->role = MAPISTORE_MAIL_ROLE; context->tag = "tag"; From 4e3a242f2fe32230819eb175b55e62e9934cbf8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Thu, 31 Jul 2014 20:44:14 +0200 Subject: [PATCH 004/120] oc-rtf: Don't crash when we don't know the specified font --- OpenChange/RTFHandler.m | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/OpenChange/RTFHandler.m b/OpenChange/RTFHandler.m index 1e15ebaa8..5cc619b49 100644 --- a/OpenChange/RTFHandler.m +++ b/OpenChange/RTFHandler.m @@ -814,20 +814,28 @@ const unsigned short ansicpg874[256] = { if (!formattingOptions) continue; - + if (formattingOptions->font_index >= 0 && font_index != formattingOptions->font_index) { [_html appendBytes: "" length: 7]; } - + formattingOptions->font_index = font_index; fontInfo = [fontTable fontInfoAtIndex: font_index]; - - char *v = malloc(128*sizeof(char)); - memset(v, 0, 128); - sprintf(v, "", [fontInfo->name UTF8String]); + char *v = calloc(128, sizeof(char)); + if (fontInfo) + { + sprintf(v, "", [fontInfo->name UTF8String]); + } + else + { + // RTF badformed? We don't know about that font (font_index). + // Anyhow, we still open the html tag because in the future + // we will close it (e.g. when new font is used). + sprintf(v, ""); + } [_html appendBytes: v length: strlen(v)]; free(v); } From 5ee8cb3a3fd31e8d445c77e616d8dcb1334fac13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Mon, 4 Aug 2014 10:35:04 +0200 Subject: [PATCH 005/120] oc-rtf: check valid font name when generating tag --- OpenChange/RTFHandler.m | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/OpenChange/RTFHandler.m b/OpenChange/RTFHandler.m index 5cc619b49..65d5660ca 100644 --- a/OpenChange/RTFHandler.m +++ b/OpenChange/RTFHandler.m @@ -824,16 +824,29 @@ const unsigned short ansicpg874[256] = { formattingOptions->font_index = font_index; fontInfo = [fontTable fontInfoAtIndex: font_index]; - char *v = calloc(128, sizeof(char)); - if (fontInfo) + char *v = NULL; + if (fontInfo && fontInfo->name) { - sprintf(v, "", [fontInfo->name UTF8String]); + if (fontInfo->name.length < 128) + { + int tag_size = 15 + fontInfo->name.length; + v = calloc(tag_size, sizeof(char)); + snprintf(v, tag_size, "", [fontInfo->name UTF8String]); + } + else + { + NSLog(@"RTFHandler: Font %u has %d chars length, parse error? " + "Ignored", font_index, fontInfo->name.length); + v = calloc(7, sizeof(char)); + sprintf(v, ""); + } } else { // RTF badformed? We don't know about that font (font_index). // Anyhow, we still open the html tag because in the future // we will close it (e.g. when new font is used). + v = calloc(7, sizeof(char)); sprintf(v, ""); } [_html appendBytes: v length: strlen(v)]; From b8366d796d5628ee821dd3c5c9c855512adfbce8 Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Thu, 31 Jul 2014 12:12:35 +0200 Subject: [PATCH 006/120] oc/util: Tune dbmsgreader for new caching classes names --- OpenChange/dbmsgreader.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenChange/dbmsgreader.m b/OpenChange/dbmsgreader.m index 8e56655b8..3d892ca34 100644 --- a/OpenChange/dbmsgreader.m +++ b/OpenChange/dbmsgreader.m @@ -39,7 +39,7 @@ #import #import "NSObject+PropertyList.h" -Class MAPIStoreUserContextK, SOGoMAPIDBObjectK; +Class MAPIStoreUserContextK, SOGoCacheGCSObjectK; static void DumpBSONData(NSData *data) @@ -60,7 +60,7 @@ DbDumpObject (NSString *username, NSString *path) ctx = [MAPIStoreUserContextK userContextWithUsername: username andTDBIndexing: NULL]; - dbobject = [SOGoMAPIDBObjectK new]; + dbobject = [SOGoCacheGCSObjectK new]; [dbobject setTableUrl: [ctx folderTableURL]]; record = [dbobject lookupRecord: path newerThanVersion: -1]; if (record) @@ -107,7 +107,7 @@ int main (int argc, char *argv[], char *envp[]) [loader loadProducts: [NSArray arrayWithObject: BACKEND_BUNDLE_NAME]]; MAPIStoreUserContextK = NSClassFromString (@"MAPIStoreUserContext"); - SOGoMAPIDBObjectK = NSClassFromString (@"SOGoMAPIDBObject"); + SOGoCacheGCSObjectK = NSClassFromString (@"SOGoCacheGCSObject"); arguments = [[NSProcessInfo processInfo] arguments]; if ([arguments count] > 2) { From 0a23f18fc99930246d891f5f059c0d9e0c9b466e Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Mon, 4 Aug 2014 13:55:41 +0200 Subject: [PATCH 007/120] oc: Set log level to 0 in samba-get-config script - it is very chatty during builds This script is very "chatty" when "log level" is set to a high number (usual scenario on developer machine) --- OpenChange/samba-get-config.py | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenChange/samba-get-config.py b/OpenChange/samba-get-config.py index c91c3ed44..06311d996 100755 --- a/OpenChange/samba-get-config.py +++ b/OpenChange/samba-get-config.py @@ -4,5 +4,6 @@ import sys import samba.param a = samba.param.LoadParm() +a.set('debug level', '0') a.load_default() print a.get(sys.argv[1]) From 18acdf20a61e2d865facc6b1798d9a1e75a06440 Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Mon, 4 Aug 2014 13:56:22 +0200 Subject: [PATCH 008/120] oc: Make sure we always use NSString keys in 'messages' dictionary Different types for keys in Dictionaries leads to not finding expected entry - we should make sure that everythime we set/get entry from a dictionary, key object type is same --- OpenChange/MAPIStoreMailFolder.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index f0912d8f0..6a99fda18 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -639,7 +639,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) changeNumber = nil; for (count = 0; count < max; count++) { - uid = [fetchResults objectAtIndex: count]; + uid = [[fetchResults objectAtIndex: count] stringValue]; if ([messages objectForKey: uid]) { newChangeNum = [[changeNumbers objectAtIndex: count] From dc8b73b12bf8388c0bfce5af652b8e3957461c0c Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Mon, 4 Aug 2014 13:56:30 +0200 Subject: [PATCH 009/120] oc/MailFolder: Add more logging so we can trace invalid message kyes --- OpenChange/MAPIStoreMailFolder.m | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 6a99fda18..585b684b4 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -646,7 +646,11 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) unsignedLongLongValue]; changeNumber = [NSString stringWithUnsignedLongLong: newChangeNum]; [messages removeObjectForKey: uid]; - [self logWithFormat: @"removed message entry for uid %@", uid]; + [self logWithFormat: @"Removed message entry for UID %@", uid]; + } + else + { + [self logWithFormat:@"Message entry not found for UID %@", uid]; } } if (changeNumber) @@ -688,7 +692,11 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) if (dotRange.location != NSNotFound) messageUid = [messageKey substringToIndex: dotRange.location]; else - messageUid = nil; + { + messageUid = nil; + [self errorWithFormat:@"%s: Unexpected messageKey value [%@]", + __PRETTY_FUNCTION__, messageKey]; + } return messageUid; } From 52ad0e0e5b12d88d0d8259284537d360084cfb2a Mon Sep 17 00:00:00 2001 From: Julien Kerihuel Date: Tue, 19 Aug 2014 22:24:34 +0200 Subject: [PATCH 010/120] Prevent SOGo backend from crashing when mapistore_set_connection_info is not called beforehand and connInfo is not initialized. --- OpenChange/MAPIStoreContext.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/OpenChange/MAPIStoreContext.m b/OpenChange/MAPIStoreContext.m index 1b370c2f3..376a96623 100644 --- a/OpenChange/MAPIStoreContext.m +++ b/OpenChange/MAPIStoreContext.m @@ -276,6 +276,11 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri) { NSString *username; + if (newConnInfo == NULL) + { + return nil; + } + if ((self = [self init])) { ASSIGN (contextUrl, newUrl); From a7c2054cce0d3dd1a093d9f369e715b519751d3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Fri, 22 Aug 2014 17:05:49 +0200 Subject: [PATCH 011/120] oc: cached usercontext updates indexing_context Instead of use always the one given on initialization --- OpenChange/MAPIStoreMapping.h | 1 + OpenChange/MAPIStoreMapping.m | 5 +++++ OpenChange/MAPIStoreUserContext.h | 2 ++ OpenChange/MAPIStoreUserContext.m | 14 +++++++++++++- 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/OpenChange/MAPIStoreMapping.h b/OpenChange/MAPIStoreMapping.h index 620112d76..13a8ba768 100644 --- a/OpenChange/MAPIStoreMapping.h +++ b/OpenChange/MAPIStoreMapping.h @@ -42,6 +42,7 @@ - (id) initForUsername: (NSString *) username withIndexing: (struct indexing_context *) indexing; +- (void) updateIndexing: (struct indexing_context *) indexing; - (void) increaseUseCount; - (void) decreaseUseCount; diff --git a/OpenChange/MAPIStoreMapping.m b/OpenChange/MAPIStoreMapping.m index 194488bc7..9346b156f 100644 --- a/OpenChange/MAPIStoreMapping.m +++ b/OpenChange/MAPIStoreMapping.m @@ -119,6 +119,11 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr) return self; } +- (void) updateIndexing: (struct indexing_context *) newIndexing +{ + indexing = newIndexing; +} + - (void) dealloc { [username release]; diff --git a/OpenChange/MAPIStoreUserContext.h b/OpenChange/MAPIStoreUserContext.h index f9867d15a..32582271d 100644 --- a/OpenChange/MAPIStoreUserContext.h +++ b/OpenChange/MAPIStoreUserContext.h @@ -68,6 +68,8 @@ - (id) initWithUsername: (NSString *) newUsername andTDBIndexing: (struct indexing_context *) indexing; +- (void) updateIndexing: (struct indexing_context *) indexing; + - (NSString *) username; - (SOGoUser *) sogoUser; diff --git a/OpenChange/MAPIStoreUserContext.m b/OpenChange/MAPIStoreUserContext.m index 04300fd35..68d063e02 100644 --- a/OpenChange/MAPIStoreUserContext.m +++ b/OpenChange/MAPIStoreUserContext.m @@ -65,7 +65,14 @@ static NSMapTable *contextsTable = nil; id userContext; userContext = [contextsTable objectForKey: username]; - if (!userContext) + if (userContext) + { + // The indexing_context used when this user context was created + // could had been freed, so we have to update it and use the one + // that we receive as parameter (which is a valid one for sure). + [userContext updateIndexing: indexing]; + } + else { userContext = [[self alloc] initWithUsername: username andTDBIndexing: indexing]; @@ -76,6 +83,11 @@ static NSMapTable *contextsTable = nil; return userContext; } +- (void) updateIndexing: (struct indexing_context *) indexing +{ + [mapping updateIndexing: indexing]; +} + - (id) init { if ((self = [super init])) From 05578bfcb6e753fdce2f0b5d7c4167fe326b4a17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Mon, 25 Aug 2014 18:27:11 +0200 Subject: [PATCH 012/120] oc-rtf: control words can also have a space before next tag This was causing to parse a single space as an empty control word with length 0, which was the source of several crashes. Example: \f0\fbidi \fcharset0 --------^ font index is 0, font family is bidi but when parsing charset we were assuming control word was '' instead of 'charset0'. This only fixes the crashes, the parseFontTable function works quite awful right now. --- OpenChange/RTFHandler.m | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/OpenChange/RTFHandler.m b/OpenChange/RTFHandler.m index 65d5660ca..2f3b16ad4 100644 --- a/OpenChange/RTFHandler.m +++ b/OpenChange/RTFHandler.m @@ -412,16 +412,17 @@ const unsigned short ansicpg874[256] = { - (const char *) parseControlWord: (unsigned int *) len { const char *start, *end; - + start = ADVANCE; - - while (isalnum(*_bytes) || *_bytes == '-') + + while (isalnum(*_bytes) || *_bytes == '-' || isspace(*_bytes)) { ADVANCE; } end = _bytes; - + *len = end-start-1; + return start+1; } From bb9764bc6bef8633bdeda51860e4cc0db3ad4e35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Thu, 28 Aug 2014 04:14:06 +0200 Subject: [PATCH 013/120] Revert "oc: cached usercontext updates indexing_context" This reverts commit 0750f64b787db088e944756b66fbd0883cf44cbf. --- OpenChange/MAPIStoreMapping.h | 1 - OpenChange/MAPIStoreMapping.m | 5 ----- OpenChange/MAPIStoreUserContext.h | 2 -- OpenChange/MAPIStoreUserContext.m | 14 +------------- 4 files changed, 1 insertion(+), 21 deletions(-) diff --git a/OpenChange/MAPIStoreMapping.h b/OpenChange/MAPIStoreMapping.h index 13a8ba768..620112d76 100644 --- a/OpenChange/MAPIStoreMapping.h +++ b/OpenChange/MAPIStoreMapping.h @@ -42,7 +42,6 @@ - (id) initForUsername: (NSString *) username withIndexing: (struct indexing_context *) indexing; -- (void) updateIndexing: (struct indexing_context *) indexing; - (void) increaseUseCount; - (void) decreaseUseCount; diff --git a/OpenChange/MAPIStoreMapping.m b/OpenChange/MAPIStoreMapping.m index 9346b156f..194488bc7 100644 --- a/OpenChange/MAPIStoreMapping.m +++ b/OpenChange/MAPIStoreMapping.m @@ -119,11 +119,6 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr) return self; } -- (void) updateIndexing: (struct indexing_context *) newIndexing -{ - indexing = newIndexing; -} - - (void) dealloc { [username release]; diff --git a/OpenChange/MAPIStoreUserContext.h b/OpenChange/MAPIStoreUserContext.h index 32582271d..f9867d15a 100644 --- a/OpenChange/MAPIStoreUserContext.h +++ b/OpenChange/MAPIStoreUserContext.h @@ -68,8 +68,6 @@ - (id) initWithUsername: (NSString *) newUsername andTDBIndexing: (struct indexing_context *) indexing; -- (void) updateIndexing: (struct indexing_context *) indexing; - - (NSString *) username; - (SOGoUser *) sogoUser; diff --git a/OpenChange/MAPIStoreUserContext.m b/OpenChange/MAPIStoreUserContext.m index 68d063e02..04300fd35 100644 --- a/OpenChange/MAPIStoreUserContext.m +++ b/OpenChange/MAPIStoreUserContext.m @@ -65,14 +65,7 @@ static NSMapTable *contextsTable = nil; id userContext; userContext = [contextsTable objectForKey: username]; - if (userContext) - { - // The indexing_context used when this user context was created - // could had been freed, so we have to update it and use the one - // that we receive as parameter (which is a valid one for sure). - [userContext updateIndexing: indexing]; - } - else + if (!userContext) { userContext = [[self alloc] initWithUsername: username andTDBIndexing: indexing]; @@ -83,11 +76,6 @@ static NSMapTable *contextsTable = nil; return userContext; } -- (void) updateIndexing: (struct indexing_context *) indexing -{ - [mapping updateIndexing: indexing]; -} - - (id) init { if ((self = [super init])) From ed4ca3bd1b2cba344892cf80fc94af288ca15e03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Thu, 28 Aug 2014 04:19:28 +0200 Subject: [PATCH 014/120] oc: add talloc reference to indexing context We have a cache with user contexts (objc) which have mapping contexts (objc) where we store the indexing context (c) which will be freed by openchange code once the connection is closed. Right now all indexing context created for an user are the same, independently when in time was created or by which connection, etc... So this is a valid workaround, but this has to be refactored to used the indexing context of the current connection that is performing the call to SOGo backend. --- OpenChange/MAPIStoreMapping.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OpenChange/MAPIStoreMapping.m b/OpenChange/MAPIStoreMapping.m index 194488bc7..516f1a079 100644 --- a/OpenChange/MAPIStoreMapping.m +++ b/OpenChange/MAPIStoreMapping.m @@ -114,6 +114,9 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr) { ASSIGN (username, newUsername); indexing = newIndexing; + /* Workaround so all indexing context are valid and won't be freed. */ + // TODO refactor indexing interface + talloc_reference(memCtx, indexing); } return self; From c866bce8e8b0ff4540571b58d580244ecff5b2e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Sat, 27 Sep 2014 18:04:45 +0200 Subject: [PATCH 015/120] Store FreeBusySimple and FreeBusyDetailed rights as roles Map: FreeBusySimple -> PublicDAndTViewer FreeBusyDetailed -> ConfidentialDAndTViewer Although SOGo is not really used AFAIK, we can now keep it and keep Calendar permission issues consistent. --- OpenChange/MAPIStoreCalendarFolder.m | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/OpenChange/MAPIStoreCalendarFolder.m b/OpenChange/MAPIStoreCalendarFolder.m index 8c0830683..27ab9c3e1 100644 --- a/OpenChange/MAPIStoreCalendarFolder.m +++ b/OpenChange/MAPIStoreCalendarFolder.m @@ -100,6 +100,14 @@ [roles addObject: SOGoCalendarRole_PrivateViewer]; [roles addObject: SOGoCalendarRole_ConfidentialViewer]; } + if (rights & RightsFreeBusySimple) + { + [roles addObject: SOGoCalendarRole_PublicDAndTViewer]; + } + if (rights & RightsFreeBusyDetailed) + { + [roles addObject: SOGoCalendarRole_ConfidentialDAndTViewer]; + } // [self logWithFormat: @"roles for rights %.8x = (%@)", rights, roles]; @@ -121,12 +129,21 @@ else if ([roles containsObject: SOGoCalendarRole_PublicViewer] && [roles containsObject: SOGoCalendarRole_PrivateViewer] && [roles containsObject: SOGoCalendarRole_ConfidentialViewer]) - rights |= RightsReadItems | 0x1800; + // We have to set by hand other rights as only the highest role is returned + // See SOGoAppointmentFolder.m:aclsForUser for details + rights |= RightsReadItems | RightsFreeBusySimple | RightsFreeBusyDetailed; + + if ([roles containsObject: SOGoCalendarRole_PublicDAndTViewer]) + rights |= RightsFreeBusySimple; + + if ([roles containsObject: SOGoCalendarRole_ConfidentialDAndTViewer]) + rights |= RightsFreeBusyDetailed; + if (rights != 0) rights |= RoleNone; /* actually "folder visible" */ // [self logWithFormat: @"rights for roles (%@) = %.8x", roles, rights]; - + return rights; } From 445a1fb2d6b6eb24d4fb04c2610e517247d7f47f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Thu, 2 Oct 2014 17:40:12 +0200 Subject: [PATCH 016/120] oc: MailMessages return correct codepage --- OpenChange/Codepages.h | 34 ++++ OpenChange/Codepages.m | 214 ++++++++++++++++++++++ OpenChange/GNUmakefile | 4 +- OpenChange/MAPIStoreMailMessage.m | 17 +- OpenChange/MAPIStoreMailVolatileMessage.m | 19 +- 5 files changed, 263 insertions(+), 25 deletions(-) create mode 100644 OpenChange/Codepages.h create mode 100644 OpenChange/Codepages.m diff --git a/OpenChange/Codepages.h b/OpenChange/Codepages.h new file mode 100644 index 000000000..60d8223d8 --- /dev/null +++ b/OpenChange/Codepages.h @@ -0,0 +1,34 @@ +/* Codepages.h - this file is part of SOGo + * + * Copyright (C) 2014 Jesús García Sáez + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import +#import +#import + + +@interface Codepages + ++ (NSDictionary *) getCodepagesTable; ++ (NSDictionary *) getReverseCodepagesTable; + ++ (NSNumber *) getCodepageFromName: (NSString *) name; ++ (NSString *) getNameFromCodepage: (NSNumber *) codepage; + +@end diff --git a/OpenChange/Codepages.m b/OpenChange/Codepages.m new file mode 100644 index 000000000..d8574f9c5 --- /dev/null +++ b/OpenChange/Codepages.m @@ -0,0 +1,214 @@ +/* Codepages.m - this file is part of SOGo + * + * Copyright (C) 2014 Jesús García Sáez + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import "Codepages.h" +#import + +@implementation Codepages + ++ (NSDictionary *) getCodepagesTable +{ + static NSDictionary *table = nil; + + if (table == nil) + { + /* http://msdn.microsoft.com/en-us/library/dd317756%28v=vs.85%29.aspx */ + table = [[NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithInt: 37], @"IBM037", + [NSNumber numberWithInt: 437], @"IBM437", + [NSNumber numberWithInt: 500], @"IBM500", + [NSNumber numberWithInt: 708], @"ASMO-708", + [NSNumber numberWithInt: 720], @"DOS-720", + [NSNumber numberWithInt: 737], @"ibm737", + [NSNumber numberWithInt: 775], @"ibm775", + [NSNumber numberWithInt: 850], @"ibm850", + [NSNumber numberWithInt: 852], @"ibm852", + [NSNumber numberWithInt: 855], @"IBM855", + [NSNumber numberWithInt: 857], @"ibm857", + [NSNumber numberWithInt: 858], @"IBM00858", + [NSNumber numberWithInt: 860], @"IBM860", + [NSNumber numberWithInt: 861], @"ibm861", + [NSNumber numberWithInt: 862], @"DOS-862", + [NSNumber numberWithInt: 863], @"IBM863", + [NSNumber numberWithInt: 864], @"IBM864", + [NSNumber numberWithInt: 865], @"IBM865", + [NSNumber numberWithInt: 866], @"cp866", + [NSNumber numberWithInt: 869], @"ibm869", + [NSNumber numberWithInt: 870], @"IBM870", + [NSNumber numberWithInt: 874], @"windows-874", + [NSNumber numberWithInt: 875], @"cp875", + [NSNumber numberWithInt: 932], @"shift_jis", + [NSNumber numberWithInt: 936], @"gb2312", + [NSNumber numberWithInt: 949], @"ks_c_5601-1987", + [NSNumber numberWithInt: 950], @"big5", + [NSNumber numberWithInt: 1026], @"IBM1026", + [NSNumber numberWithInt: 1047], @"IBM01047", + [NSNumber numberWithInt: 1140], @"IBM01140", + [NSNumber numberWithInt: 1141], @"IBM01141", + [NSNumber numberWithInt: 1142], @"IBM01142", + [NSNumber numberWithInt: 1143], @"IBM01143", + [NSNumber numberWithInt: 1144], @"IBM01144", + [NSNumber numberWithInt: 1145], @"IBM01145", + [NSNumber numberWithInt: 1146], @"IBM01146", + [NSNumber numberWithInt: 1147], @"IBM01147", + [NSNumber numberWithInt: 1148], @"IBM01148", + [NSNumber numberWithInt: 1149], @"IBM01149", + [NSNumber numberWithInt: 1200], @"utf-16", + [NSNumber numberWithInt: 1201], @"unicodeFFFE", + [NSNumber numberWithInt: 1250], @"windows-1250", + [NSNumber numberWithInt: 1251], @"windows-1251", + [NSNumber numberWithInt: 1252], @"Windows-1252", + [NSNumber numberWithInt: 1253], @"windows-1253", + [NSNumber numberWithInt: 1254], @"windows-1254", + [NSNumber numberWithInt: 1255], @"windows-1255", + [NSNumber numberWithInt: 1256], @"windows-1256", + [NSNumber numberWithInt: 1257], @"windows-1257", + [NSNumber numberWithInt: 1258], @"windows-1258", + [NSNumber numberWithInt: 1361], @"Johab", + [NSNumber numberWithInt: 10000], @"macintosh", + [NSNumber numberWithInt: 10001], @"x-mac-japanese", + [NSNumber numberWithInt: 10002], @"x-mac-chinesetrad", + [NSNumber numberWithInt: 10003], @"x-mac-korean", + [NSNumber numberWithInt: 10004], @"x-mac-arabic", + [NSNumber numberWithInt: 10005], @"x-mac-hebrew", + [NSNumber numberWithInt: 10006], @"x-mac-greek", + [NSNumber numberWithInt: 10007], @"x-mac-cyrillic", + [NSNumber numberWithInt: 10008], @"x-mac-chinesesimp", + [NSNumber numberWithInt: 10010], @"x-mac-romanian", + [NSNumber numberWithInt: 10017], @"x-mac-ukrainian", + [NSNumber numberWithInt: 10021], @"x-mac-thai", + [NSNumber numberWithInt: 10029], @"x-mac-ce", + [NSNumber numberWithInt: 10079], @"x-mac-icelandic", + [NSNumber numberWithInt: 10081], @"x-mac-turkish", + [NSNumber numberWithInt: 10082], @"x-mac-croatian", + [NSNumber numberWithInt: 12000], @"utf-32", + [NSNumber numberWithInt: 12001], @"utf-32BE", + [NSNumber numberWithInt: 20000], @"x-Chinese-CNS", + [NSNumber numberWithInt: 20001], @"x-cp20001", + [NSNumber numberWithInt: 20002], @"x-Chinese-Eten", + [NSNumber numberWithInt: 20003], @"x-cp20003", + [NSNumber numberWithInt: 20004], @"x-cp20004", + [NSNumber numberWithInt: 20005], @"x-cp20005", + [NSNumber numberWithInt: 20105], @"x-IA5", + [NSNumber numberWithInt: 20106], @"x-IA5-German", + [NSNumber numberWithInt: 20107], @"x-IA5-Swedish", + [NSNumber numberWithInt: 20108], @"x-IA5-Norwegian", + [NSNumber numberWithInt: 20127], @"us-ascii", + [NSNumber numberWithInt: 20261], @"x-cp20261", + [NSNumber numberWithInt: 20269], @"x-cp20269", + [NSNumber numberWithInt: 20273], @"IBM273", + [NSNumber numberWithInt: 20277], @"IBM277", + [NSNumber numberWithInt: 20278], @"IBM278", + [NSNumber numberWithInt: 20280], @"IBM280", + [NSNumber numberWithInt: 20284], @"IBM284", + [NSNumber numberWithInt: 20285], @"IBM285", + [NSNumber numberWithInt: 20290], @"IBM290", + [NSNumber numberWithInt: 20297], @"IBM297", + [NSNumber numberWithInt: 20420], @"IBM420", + [NSNumber numberWithInt: 20423], @"IBM423", + [NSNumber numberWithInt: 20424], @"IBM424", + [NSNumber numberWithInt: 20833], @"x-EBCDIC-KoreanExtended", + [NSNumber numberWithInt: 20838], @"IBM-Thai", + [NSNumber numberWithInt: 20866], @"koi8-r", + [NSNumber numberWithInt: 20871], @"IBM871", + [NSNumber numberWithInt: 20880], @"IBM880", + [NSNumber numberWithInt: 20905], @"IBM905", + [NSNumber numberWithInt: 20924], @"IBM00924", + [NSNumber numberWithInt: 20932], @"EUC-JP", + [NSNumber numberWithInt: 20936], @"x-cp20936", + [NSNumber numberWithInt: 20949], @"x-cp20949", + [NSNumber numberWithInt: 21025], @"cp1025", + [NSNumber numberWithInt: 21866], @"koi8-u", + [NSNumber numberWithInt: 28591], @"iso-8859-1", + [NSNumber numberWithInt: 28592], @"iso-8859-2", + [NSNumber numberWithInt: 28593], @"iso-8859-3", + [NSNumber numberWithInt: 28594], @"iso-8859-4", + [NSNumber numberWithInt: 28595], @"iso-8859-5", + [NSNumber numberWithInt: 28596], @"iso-8859-6", + [NSNumber numberWithInt: 28597], @"iso-8859-7", + [NSNumber numberWithInt: 28598], @"iso-8859-8", + [NSNumber numberWithInt: 28599], @"iso-8859-9", + [NSNumber numberWithInt: 28603], @"iso-8859-13", + [NSNumber numberWithInt: 28605], @"iso-8859-15", + [NSNumber numberWithInt: 29001], @"x-Europa", + [NSNumber numberWithInt: 38598], @"iso-8859-8-i", + [NSNumber numberWithInt: 50220], @"iso-2022-jp", + [NSNumber numberWithInt: 50221], @"csISO2022JP", + [NSNumber numberWithInt: 50222], @"iso-2022-jp", + [NSNumber numberWithInt: 50225], @"iso-2022-kr", + [NSNumber numberWithInt: 50227], @"x-cp50227", + [NSNumber numberWithInt: 51932], @"euc-jp", + [NSNumber numberWithInt: 51936], @"EUC-CN", + [NSNumber numberWithInt: 51949], @"euc-kr", + [NSNumber numberWithInt: 52936], @"hz-gb-2312", + [NSNumber numberWithInt: 54936], @"GB18030", + [NSNumber numberWithInt: 57002], @"x-iscii-de", + [NSNumber numberWithInt: 57003], @"x-iscii-be", + [NSNumber numberWithInt: 57004], @"x-iscii-ta", + [NSNumber numberWithInt: 57005], @"x-iscii-te", + [NSNumber numberWithInt: 57006], @"x-iscii-as", + [NSNumber numberWithInt: 57007], @"x-iscii-or", + [NSNumber numberWithInt: 57008], @"x-iscii-ka", + [NSNumber numberWithInt: 57009], @"x-iscii-ma", + [NSNumber numberWithInt: 57010], @"x-iscii-gu", + [NSNumber numberWithInt: 57011], @"x-iscii-pa", + [NSNumber numberWithInt: 65000], @"utf-7", + [NSNumber numberWithInt: 65001], @"utf-8", + nil] retain]; + } + return table; +} + ++ (NSDictionary *) getReverseCodepagesTable +{ + static NSDictionary *table = nil; + + if (table == nil) + { + NSDictionary *codepages_table; + NSEnumerator *enumerator; + NSMutableArray *codepages, *names; + id key; + // Build reverse table: (NSNumber) codepage -> (NSString) encoding name + codepages_table = [self getCodepagesTable]; + codepages = [NSMutableArray arrayWithCapacity: [codepages_table count]]; + names = [NSMutableArray arrayWithCapacity: [codepages_table count]]; + enumerator = [codepages_table keyEnumerator]; + while ((key = [enumerator nextObject])) + { + [names addObject: key]; + [codepages addObject: [codepages_table objectForKey: key]]; + } + table = [[NSDictionary dictionaryWithObjects: names forKeys: codepages] retain]; + } + return table; +} + ++ (NSNumber *) getCodepageFromName: (NSString *) name +{ + return [[self getCodepagesTable] objectForKey: name]; +} + ++ (NSString *) getNameFromCodepage: (NSNumber *) codepage +{ + return [[self getReverseCodepagesTable] objectForKey: codepage]; +} + +@end diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index e3adc5f7e..9329b2ece 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -120,7 +120,9 @@ $(SOGOBACKEND)_OBJC_FILES += \ iCalEvent+MAPIStore.m \ iCalTimeZone+MAPIStore.m \ \ - RTFHandler.m + RTFHandler.m \ + \ + Codepages.m $(SOGOBACKEND)_RESOURCE_FILES += \ diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index 0515f0163..3a00796c4 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -40,6 +40,7 @@ #import #import +#import "Codepages.h" #import "NSData+MAPIStore.h" #import "NSObject+MAPIStore.h" #import "NSString+MAPIStore.h" @@ -923,15 +924,13 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) - (int) getPidTagInternetCodepage: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - /* ref: - http://msdn.microsoft.com/en-us/library/dd317756%28v=vs.85%29.aspx - - minimal list that should be handled: - us-ascii: 20127 - iso-8859-1: 28591 - iso-8859-15: 28605 - utf-8: 65001 */ - *data = MAPILongValue(memCtx, 65001); + NSNumber *codepage; + + codepage = [Codepages getCodepageFromName: headerCharset]; + if (!codepage) + codepage = [Codepages getCodepageFromName: @"utf-8"]; + + *data = MAPILongValue(memCtx, [codepage intValue]); return MAPISTORE_SUCCESS; } diff --git a/OpenChange/MAPIStoreMailVolatileMessage.m b/OpenChange/MAPIStoreMailVolatileMessage.m index 7df01fdf1..528b7e7e8 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.m +++ b/OpenChange/MAPIStoreMailVolatileMessage.m @@ -50,6 +50,7 @@ #import #import +#import "Codepages.h" #import "MAPIStoreAttachment.h" #import "MAPIStoreAttachmentTable.h" #import "MAPIStoreContext.h" @@ -672,21 +673,9 @@ MakeTextHtmlBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, { /* charset */ codePage = [mailProperties objectForKey: MAPIPropertyKey (PR_INTERNET_CPID)]; - switch ([codePage intValue]) - { - case 20127: - charset = @"us-ascii"; - break; - case 28605: - charset = @"iso-8859-15"; - break; - case 65001: - charset = @"utf-8"; - break; - case 28591: - default: - charset = @"iso-8859-1"; - } + charset = [Codepages getNameFromCodepage: codePage]; + if (!charset) + charset = @"utf-8"; htmlContentType = [NSString stringWithFormat: @"text/html; charset=%@", charset]; From 415fb6034e76dc666970070b9ac437bf4e1e9834 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Thu, 18 Sep 2014 10:23:51 +0200 Subject: [PATCH 017/120] oc-calendar: Retrieve properly event description created on SOGo As it is stored as plain text without triming string. The correct comparison here is NSNotFound as stated in Apple documentation. --- OpenChange/MAPIStoreAppointmentWrapper.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index 24c6e1ad3..c256081b7 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -1231,7 +1231,7 @@ static NSCharacterSet *hexCharacterSet = nil; /* Avoiding those trail weird characters at event description */ range = [stringValue rangeOfString: trimingString options: NSBackwardsSearch]; - if (range.location > 0) + if (range.location != NSNotFound) { stringValue = [stringValue substringToIndex: (NSMaxRange(range) -1)]; } From cbfcd548581849ede2d6bbd0edbe580300f5d4af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Fri, 19 Sep 2014 16:51:26 +0200 Subject: [PATCH 018/120] oc-rtf: Use what RTF Spec 1.9.1 for control words This reverts 7581c0a. --- OpenChange/RTFHandler.m | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/OpenChange/RTFHandler.m b/OpenChange/RTFHandler.m index 2f3b16ad4..91d7fd2d8 100644 --- a/OpenChange/RTFHandler.m +++ b/OpenChange/RTFHandler.m @@ -415,10 +415,39 @@ const unsigned short ansicpg874[256] = { start = ADVANCE; - while (isalnum(*_bytes) || *_bytes == '-' || isspace(*_bytes)) + /* + A control word is defined by: + + \ + */ + while (isalpha(*_bytes)) { ADVANCE; } + + /* + The can be one of the following: + + - A space. This serves only to delimit a control word and is + ignored in subsequent processing. + + - A numeric digit or an ASCII minus sign (-), which indicates + that a numeric parameter is associated with the control word. + Only this case requires to include it in the control word. + + - Any character other than a letter or a digit + */ + if (*_bytes == '-' || isdigit(*_bytes)) + { + ADVANCE; + while (isdigit(*_bytes)) // TODO: Allow up to 10 digits + { + ADVANCE; + } + } + /* In this case, the delimiting character terminates the control + word and is not part of the control word. */ + end = _bytes; *len = end-start-1; From 75ce59d010c92a89453136300ec2c5f9c8e42c8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Fri, 3 Oct 2014 23:23:01 +0200 Subject: [PATCH 019/120] oc-rtf: Fix current position to match where _bytes pointer is This avoids to have extra unknown bytes at the end of the RTF document as _len would have been reached but _current_pos had incorrect less value. --- OpenChange/RTFHandler.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OpenChange/RTFHandler.m b/OpenChange/RTFHandler.m index 91d7fd2d8..fbcea8121 100644 --- a/OpenChange/RTFHandler.m +++ b/OpenChange/RTFHandler.m @@ -756,16 +756,16 @@ const unsigned short ansicpg874[256] = { { // We rewind our buffer so we start at the beginning of {\fonttbl... _bytes = cw-2; - _current_pos -= 10; + _current_pos -= 9; // Length: {\fonttbl fontTable = [self parseFontTable]; - // We go back 1 byte in order to end our section properly ('}' character + // We go back 1 byte in order to end our section properly ('}' character) REWIND; } else if (strncmp(cw, "stylesheet", 10) == 0) { _bytes = cw-2; - _current_pos -= 13; + _current_pos -= 12; // Length: {\stylesheet [self parseStyleSheet]; REWIND; } @@ -776,7 +776,7 @@ const unsigned short ansicpg874[256] = { else if (strncmp(cw, "pict", 4) == 0) { _bytes = cw-2; - _current_pos -= 7; + _current_pos -= 6; // Length: {\pict [self parsePicture]; REWIND; } From 258444bb93b974825c428ef45db58e288d742f18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Sat, 4 Oct 2014 00:58:13 +0200 Subject: [PATCH 020/120] oc-rtf: Be more resilient to spaces while parsing font tables This avoids to crash on this example: \f0\fibi \fcharset0 -------^ Or: \f0 \fibi\fcharset0 --^ Take into account that I found lots of RTF documents with this format: \f0\fbidi \froman\fcharset0 \f0\froman\fprq2 \fcharset0 Which are not unsupported by this handler. --- OpenChange/RTFHandler.m | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/OpenChange/RTFHandler.m b/OpenChange/RTFHandler.m index fbcea8121..f9dd47db3 100644 --- a/OpenChange/RTFHandler.m +++ b/OpenChange/RTFHandler.m @@ -573,7 +573,7 @@ const unsigned short ansicpg874[256] = { // Skip our control word if (strncmp((const char*)cw, "fonttbl", len) == 0) continue; - + // We must at least parse s = [[NSString alloc] initWithBytesNoCopy: (void *)cw+1 length: len-1 @@ -588,12 +588,18 @@ const unsigned short ansicpg874[256] = { // We now parse cw = [self parseControlWord: &len]; + if (len == 0) // Possibly parsing a space + cw = [self parseControlWord: &len]; + fontInfo->family = [[NSString alloc] initWithBytesNoCopy: (void *)cw+1 length: len-1 encoding: NSASCIIStringEncoding freeWhenDone: NO]; cw = [self parseControlWord: &len]; + if (len == 0) // Possibly parsing a space + cw = [self parseControlWord: &len]; + fontInfo->charset = [[NSString alloc] initWithBytesNoCopy: (void *)cw+1 length: len-1 encoding: NSASCIIStringEncoding From 7e0cddc06bc520c8eefe1b9190e92443853a15bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Tue, 7 Oct 2014 00:51:45 +0200 Subject: [PATCH 021/120] oc-mailfolder: Avoid setting seen flag on preloading message bodies Fetching a body[text] property using IMAP makes IMAP server set seen flag. This commit fetches the flag beforehand to restore the previous state once the body has been fetched. --- OpenChange/MAPIStoreMailFolder.m | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 585b684b4..40857d39c 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -1274,8 +1274,10 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) NSUInteger count, max; NSString *messageKey, *messageUid, *bodyPartKey; NGImap4Client *client; - NSArray *fetch; + NSArray *fetch, *flags; NSData *bodyContent; + BOOL unseen; + NSMutableArray *unseenUIDs; if (tableType == MAPISTORE_MESSAGE_TABLE) { @@ -1305,6 +1307,25 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) client = [[(SOGoMailFolder *) sogoObject imap4Connection] client]; [client select: [sogoObject absoluteImap4Name]]; + + /* Fetch flags to remove seen flag if required, + as fetching a message body set the seen flag */ + response = [client fetchUids: [keyAssoc allKeys] + parts: [NSArray arrayWithObjects: @"flags", nil]]; + fetch = [response objectForKey: @"fetch"]; + max = [fetch count]; + unseenUIDs = [NSMutableArray arrayWithCapacity: max]; + for (count = 0; count < max; count++) + { + response = [fetch objectAtIndex: count]; + messageUid = [[response objectForKey: @"uid"] stringValue]; + flags = [response objectForKey: @"flags"]; + unseen = [flags indexOfObject: @"seen"] == NSNotFound; + if (unseen) { + [unseenUIDs addObject: messageUid]; + } + } + response = [client fetchUids: [keyAssoc allKeys] parts: [bodyPartKeys allObjects]]; fetch = [response objectForKey: @"fetch"]; @@ -1326,6 +1347,14 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) } } } + + // Restore unseen state once the body has been fetched + if ([unseenUIDs count] > 0) + { + response = [client storeFlags: [NSArray arrayWithObjects: @"seen", nil] + forUIDs: unseenUIDs + addOrRemove: NO]; + } } } From d076e04ad47c8938531450af9f002552328f8fa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Tue, 7 Oct 2014 12:37:23 +0200 Subject: [PATCH 022/120] oc-mailfolder: Get seen flag directly from message in preloading To avoid a loop and a server-call. We are not using body.peek[text] directly because bodyContentPart message is explicitly avoiding it. --- OpenChange/MAPIStoreMailFolder.m | 33 +++++++++++-------------------- OpenChange/MAPIStoreMailMessage.h | 1 + OpenChange/MAPIStoreMailMessage.m | 8 ++++++++ 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 40857d39c..28fcca431 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -1274,9 +1274,8 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) NSUInteger count, max; NSString *messageKey, *messageUid, *bodyPartKey; NGImap4Client *client; - NSArray *fetch, *flags; + NSArray *fetch; NSData *bodyContent; - BOOL unseen; NSMutableArray *unseenUIDs; if (tableType == MAPISTORE_MESSAGE_TABLE) @@ -1288,6 +1287,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) { bodyPartKeys = [NSMutableSet setWithCapacity: max]; + unseenUIDs = [NSMutableArray arrayWithCapacity: max]; keyAssoc = [NSMutableDictionary dictionaryWithCapacity: max]; for (count = 0; count < max; count++) { @@ -1301,6 +1301,15 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) [bodyPartKeys addObject: bodyPartKey]; messageUid = [self messageUIDFromMessageKey: messageKey]; [keyAssoc setObject: bodyPartKey forKey: messageUid]; + /* Fetch flags to remove seen flag if required, + as fetching a message body set the seen flag. + We are not using body.peek[] as + bodyContentPartKey explicitly avoids it. + */ + if (![message read]) + { + [unseenUIDs addObject: messageUid]; + } } } } @@ -1308,24 +1317,6 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) client = [[(SOGoMailFolder *) sogoObject imap4Connection] client]; [client select: [sogoObject absoluteImap4Name]]; - /* Fetch flags to remove seen flag if required, - as fetching a message body set the seen flag */ - response = [client fetchUids: [keyAssoc allKeys] - parts: [NSArray arrayWithObjects: @"flags", nil]]; - fetch = [response objectForKey: @"fetch"]; - max = [fetch count]; - unseenUIDs = [NSMutableArray arrayWithCapacity: max]; - for (count = 0; count < max; count++) - { - response = [fetch objectAtIndex: count]; - messageUid = [[response objectForKey: @"uid"] stringValue]; - flags = [response objectForKey: @"flags"]; - unseen = [flags indexOfObject: @"seen"] == NSNotFound; - if (unseen) { - [unseenUIDs addObject: messageUid]; - } - } - response = [client fetchUids: [keyAssoc allKeys] parts: [bodyPartKeys allObjects]]; fetch = [response objectForKey: @"fetch"]; @@ -1348,7 +1339,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) } } - // Restore unseen state once the body has been fetched + /* Restore unseen state once the body has been fetched */ if ([unseenUIDs count] > 0) { response = [client storeFlags: [NSArray arrayWithObjects: @"seen", nil] diff --git a/OpenChange/MAPIStoreMailMessage.h b/OpenChange/MAPIStoreMailMessage.h index 22d9e3320..6bae6647a 100644 --- a/OpenChange/MAPIStoreMailMessage.h +++ b/OpenChange/MAPIStoreMailMessage.h @@ -73,6 +73,7 @@ /* batch-mode helpers */ - (NSString *) bodyContentPartKey; - (void) setBodyContentFromRawData: (NSData *) rawContent; +- (BOOL) read; /* Unseen from sogoObject */ @end diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index 3a00796c4..c64f60c22 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -1598,4 +1598,12 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) } } +- (BOOL) read +{ + if (!headerSetup) + [self _fetchHeaderData]; + + return [sogoObject read]; +} + @end From be60fdebcc1e92ab13ce93dcc019457e5c4d7722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Tue, 14 Oct 2014 23:48:36 +0200 Subject: [PATCH 023/120] oc-folder: Flags are now used in indexing db when deleting a msg Unregistering the URL in indexing db accordingly to the flags (SOFT or HARD) --- OpenChange/MAPIStoreFolder.m | 5 ++++- OpenChange/MAPIStoreMapping.h | 2 ++ OpenChange/MAPIStoreMapping.m | 9 +++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index a0455efb6..472f2b7c7 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -568,6 +568,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe struct mapistore_object_notification_parameters *notif_parameters; int rc; + /* flags that control the behaviour of the operation + (MAPISTORE_SOFT_DELETE or MAPISTORE_PERMANENT_DELETE) */ [self logWithFormat: @"-deleteMessageWithMID: mid: 0x%.16llx flags: %d", mid, flags]; mapping = [self mapping]; @@ -646,7 +648,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe notifyChangesForChild: message]; } [self logWithFormat: @"successfully deleted object at URL: %@", childURL]; - [mapping unregisterURLWithID: mid]; + /* Ensure we are respecting flags parameter */ + [mapping unregisterURLWithID: mid andFlags: flags]; [self cleanupCaches]; rc = MAPISTORE_SUCCESS; } diff --git a/OpenChange/MAPIStoreMapping.h b/OpenChange/MAPIStoreMapping.h index 620112d76..3210f1eb0 100644 --- a/OpenChange/MAPIStoreMapping.h +++ b/OpenChange/MAPIStoreMapping.h @@ -54,6 +54,8 @@ - (void) registerURLs: (NSArray *) urlString withIDs: (NSArray *) idNbrs; - (void) unregisterURLWithID: (uint64_t) idNbr; +- (void) unregisterURLWithID: (uint64_t) idNbr + andFlags: (uint8_t) flags; - (void) updateID: (uint64_t) idNbr withURL: (NSString *) urlString; diff --git a/OpenChange/MAPIStoreMapping.m b/OpenChange/MAPIStoreMapping.m index 516f1a079..1b2e4a0e7 100644 --- a/OpenChange/MAPIStoreMapping.m +++ b/OpenChange/MAPIStoreMapping.m @@ -278,4 +278,13 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr) idNbr, MAPISTORE_PERMANENT_DELETE); } +- (void) unregisterURLWithID: (uint64_t) idNbr + andFlags: (uint8_t) flags +{ + indexing->del_fmid(indexing, [username UTF8String], + idNbr, + (flags == MAPISTORE_SOFT_DELETE) ? MAPISTORE_SOFT_DELETE : MAPISTORE_PERMANENT_DELETE); +} + + @end From cd64ca199a9846d9dc9a36a99fac39285303b9c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Thu, 16 Oct 2014 16:11:43 +0200 Subject: [PATCH 024/120] oc-calendar: wDay field cannot be negative Furthermore, [MS-OXOCAL] Section 2.2.1.41.1 indicates: The wDay field is set to indicate the occurrence of the day of the week within the month (1 to 5, where 5 indicates the final occurrence during the month if that day of the week does not occur 5 times). [rule firstOccurrence] may return negative values according to iCal spec for recurrent rules iCal 4.8.5.4 Recurrence Rule. For instance, for defining a timezone whose recurrent rule is done using this rule: RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU This fixes the problem when editing a recurrent appointment in Outlook were incorrectly shifted when SOGo provides back the event. --- OpenChange/iCalTimeZone+MAPIStore.m | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/OpenChange/iCalTimeZone+MAPIStore.m b/OpenChange/iCalTimeZone+MAPIStore.m index 8e9bf7c14..f692272db 100644 --- a/OpenChange/iCalTimeZone+MAPIStore.m +++ b/OpenChange/iCalTimeZone+MAPIStore.m @@ -51,6 +51,7 @@ NSArray *byMonth; iCalByDayMask *mask; NSCalendarDate *dateValue; + int16_t wDay; rrule = [self recurrenceRule]; byMonth = [rrule byMonth]; @@ -59,7 +60,14 @@ tzData->wMonth = [[byMonth objectAtIndex: 0] intValue]; mask = [rrule byDayMask]; tzData->wDayOfWeek = [mask firstDay]; - tzData->wDay = [mask firstOccurrence]; + wDay = [mask firstOccurrence]; + if (wDay < 0) + /* [MS-OXOCAL] the wDay field is set to indicate the + occurrence of the day of the week within the month (1 to + 5, where 5 indicates the final occurrence during the + month if that day of the week does not occur 5 times). */ + wDay += 6; + tzData->wDay = (uint16_t) wDay; dateValue = [self startDate]; tzData->wHour = [dateValue hourOfDay]; From c631689975a4532abc4f3d184ad199d15f29bd6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Thu, 16 Oct 2014 16:26:57 +0200 Subject: [PATCH 025/120] oc-calendar: getPidLidClipEnd now follows [MS-OXOCAL] On recurrent events when there is no end, the time to set is 31 August 4500, 11:59 P.M ([MS-OXOCAL] Section 2.2.1.15) --- OpenChange/MAPIStoreAppointmentWrapper.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index c256081b7..968b3dc66 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -894,7 +894,7 @@ static NSCharacterSet *hexCharacterSet = nil; } else dateValue = [NSCalendarDate dateWithYear: 4500 month: 8 day: 31 - hour: 23 minute: 59 second: 59 + hour: 23 minute: 59 second: 00 timeZone: utcTZ]; *data = [dateValue asFileTimeInMemCtx: memCtx]; rc = MAPISTORE_SUCCESS; From 35ca313c37c2efbf99c62a81b1ef8b5564e74884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Thu, 16 Oct 2014 16:29:23 +0200 Subject: [PATCH 026/120] oc-calendar: Fix PidLidClipStart on recurrent events The midnight value must be in user's timezone and returned back in UTC. --- OpenChange/MAPIStoreAppointmentWrapper.m | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index 968b3dc66..f459462be 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -791,11 +791,20 @@ static NSCharacterSet *hexCharacterSet = nil; inMemCtx: (TALLOC_CTX *) memCtx { enum mapistore_error rc; - NSCalendarDate *dateValue; + NSCalendarDate *dateValue, *start; if ([event isRecurrent]) { - dateValue = [[event startDate] hour: 0 minute: 0 second: 0]; + /* [MS-OXOCAL] For a recurring series, this property specifies + midnight in the user's machine time zone, on the date of the + first instance, then is persisted in UTC. */ + start = [event startDate]; + dateValue = [NSCalendarDate dateWithYear: [start yearOfCommonEra] + month: [start monthOfYear] + day: [start dayOfMonth] + hour: 0 minute: 0 second: 0 + timeZone: timeZone]; + [dateValue setTimeZone: utcTZ]; *data = [dateValue asFileTimeInMemCtx: memCtx]; rc = MAPISTORE_SUCCESS; } From b67e1deda55ffc702d090629587f8a85b5967d8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Wed, 15 Oct 2014 00:35:17 +0200 Subject: [PATCH 027/120] oc-folder: Make deleted items synched when shared By keeping mid on moving messages by soft deleting and only if srcMid is different from targetMid. This makes restore/shared deleted items work. It also requires to do the following to work smoothly: * Do not add soft-deleted messages in ensureIDsForChildKeys * Return soft-deleted messages on getDeletedFMIDs * Do not register a new mid if the URL is matched with soft deleted messages --- OpenChange/MAPIStoreFolder.m | 15 ++++++++++----- OpenChange/MAPIStoreMapping.h | 2 ++ OpenChange/MAPIStoreMapping.m | 30 ++++++++++++++++++++++++------ 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index 472f2b7c7..733ce6114 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -679,6 +679,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe //TALLOC_CTX *memCtx; struct SRow aRow; struct SPropValue property; + uint8_t deleteFlags; [self logWithFormat: @"-moveCopyMessageWithMID: 0x%.16llx .. withMID: 0x%.16llx .. wantCopy: %d", srcMid, targetMid, wantCopy]; @@ -709,7 +710,9 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe } [destMsg save: memCtx]; if (!wantCopy) - rc = [sourceFolder deleteMessageWithMID: srcMid andFlags: 0]; + /* We want to keep mid for restoring/shared data to work if mids are different. */ + deleteFlags = (srcMid == targetMid) ? MAPISTORE_PERMANENT_DELETE : MAPISTORE_SOFT_DELETE; + rc = [sourceFolder deleteMessageWithMID: srcMid andFlags: deleteFlags]; end: //talloc_free (memCtx); @@ -949,6 +952,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe NSString *baseURL, *URL, *key; NSArray *newIDs; uint64_t idNbr; + bool softDeleted; baseURL = [self url]; @@ -959,8 +963,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe { key = [keys objectAtIndex: count]; URL = [NSString stringWithFormat: @"%@%@", baseURL, key]; - idNbr = [mapping idFromURL: URL]; - if (idNbr == NSNotFound) + idNbr = [mapping idFromURL: URL isSoftDeleted: &softDeleted]; + if (idNbr == NSNotFound && !softDeleted) [missingURLs addObject: URL]; } @@ -1091,6 +1095,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe MAPIStoreMapping *mapping; struct UI8Array_r *fmids; uint64_t fmid; + bool softDeleted; keys = [self getDeletedKeysFromChangeNumber: changeNum andCN: &cnNbr inTableType: tableType]; @@ -1117,10 +1122,10 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe { url = [NSString stringWithFormat: format, baseURL, [keys objectAtIndex: count]]; - fmid = [mapping idFromURL: url]; + fmid = [mapping idFromURL: url isSoftDeleted: &softDeleted]; if (fmid != NSNotFound) /* if no fmid is returned, then the object "never existed" in the OpenChange - databases */ + databases. Soft-deleted messages are returned back */ { fmids->lpui8[fmids->cValues] = fmid; fmids->cValues++; diff --git a/OpenChange/MAPIStoreMapping.h b/OpenChange/MAPIStoreMapping.h index 3210f1eb0..827cddf38 100644 --- a/OpenChange/MAPIStoreMapping.h +++ b/OpenChange/MAPIStoreMapping.h @@ -49,6 +49,8 @@ - (NSString *) urlFromID: (uint64_t) idKey; - (uint64_t) idFromURL: (NSString *) url; +- (uint64_t) idFromURL: (NSString *) url + isSoftDeleted: (bool *) softDeleted; - (BOOL) registerURL: (NSString *) urlString withID: (uint64_t) idNbr; - (void) registerURLs: (NSArray *) urlString diff --git a/OpenChange/MAPIStoreMapping.m b/OpenChange/MAPIStoreMapping.m index 1b2e4a0e7..6a910ea4c 100644 --- a/OpenChange/MAPIStoreMapping.m +++ b/OpenChange/MAPIStoreMapping.m @@ -160,6 +160,21 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr) return NSNotFound; } +- (uint64_t) idFromURL: (NSString *) url + isSoftDeleted: (bool *) softDeleted +{ + enum mapistore_error ret; + uint64_t idNbr; + + ret = indexing->get_fmid(indexing, [username UTF8String], [url UTF8String], + false, &idNbr, softDeleted); + + if (ret != MAPISTORE_SUCCESS) + return NSNotFound; + + return idNbr; +} + - (void) _updateFolderWithURL: (NSString *) oldURL withURL: (NSString *) urlString { @@ -217,7 +232,7 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr) { NSString *oldURL; uint64_t oldIdNbr; - bool rc; + bool rc, softDeleted; oldURL = [self urlFromID: idNbr]; if (oldURL != NULL) @@ -228,13 +243,16 @@ MAPIStoreMappingKeyFromId (uint64_t idNbr) return NO; } - oldIdNbr = [self idFromURL: urlString]; + oldIdNbr = [self idFromURL: urlString isSoftDeleted: &softDeleted]; if (oldIdNbr != NSNotFound) { - [self errorWithFormat: - @"attempt to double register an entry with idNbr ('%@', %lld," - @" 0x%.16"PRIx64", oldid=0x%.16"PRIx64")", - urlString, idNbr, idNbr, oldIdNbr]; + if (softDeleted) + [self logWithFormat: @"Attempt to register a soft-deleted %@", urlString]; + else + [self errorWithFormat: + @"attempt to double register an entry with idNbr ('%@', %lld," + @" 0x%.16"PRIx64", oldid=0x%.16"PRIx64")", + urlString, idNbr, idNbr, oldIdNbr]; return NO; } else From 3910769ae86d6a58c44702ef4c09bf88c4912914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Wed, 15 Oct 2014 00:39:49 +0200 Subject: [PATCH 028/120] oc-folder: Uniform call to deleteMessageWithMID To make sure flags argument is used accordingly with the specs and not working by chance. --- OpenChange/MAPIStoreFolder.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index 733ce6114..2c0bade3b 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -851,7 +851,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe if (isMove) { fmid = [mapping idFromURL: [message url]]; - [self deleteMessageWithMID: fmid andFlags: 0]; + [self deleteMessageWithMID: fmid andFlags: MAPISTORE_PERMANENT_DELETE]; [mapping registerURL: [targetMessage url] withID: fmid]; } @@ -872,7 +872,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe if (isMove) { fmid = [mapping idFromURL: [message url]]; - [self deleteMessageWithMID: fmid andFlags: 0]; + [self deleteMessageWithMID: fmid andFlags: MAPISTORE_PERMANENT_DELETE]; [mapping registerURL: [targetMessage url] withID: fmid]; } From 616f2abbb218c1dc9417162d4b95b2a1c4269660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Mon, 20 Oct 2014 11:47:46 +0200 Subject: [PATCH 029/120] Fix compilation when samba file is not others readable This happens when any smb.conf or included file is not others readable, thus we are fallbacking to the default installation path. --- OpenChange/GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index 9329b2ece..88d639220 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -31,7 +31,7 @@ endif all:: @echo " Python executable: ${PYTHON}" -SAMBA_PRIVATE_DIR = $(shell $(PYTHON) ./samba-get-config.py "private dir") +SAMBA_PRIVATE_DIR = $(shell $(PYTHON) ./samba-get-config.py 'private dir' || echo /var/lib/samba/private) $(SOGOBACKEND)_PRINCIPAL_CLASS = MAPIApplication From 24e35103ff0a5094f81b9f241cb8164293ac7b83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Wed, 22 Oct 2014 15:01:41 +0200 Subject: [PATCH 030/120] oc: monkeypatched NGImap4Connection class from sope To improve fetchUids method so we can retrieve uids in batches. Otherwise we will face an error 'too long request' kind --- OpenChange/GNUmakefile | 4 +- OpenChange/NGImap4Connection+Monkeypatching.h | 37 ++++++ OpenChange/NGImap4Connection+Monkeypatching.m | 108 ++++++++++++++++++ 3 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 OpenChange/NGImap4Connection+Monkeypatching.h create mode 100644 OpenChange/NGImap4Connection+Monkeypatching.m diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index 88d639220..633f53226 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -122,7 +122,9 @@ $(SOGOBACKEND)_OBJC_FILES += \ \ RTFHandler.m \ \ - Codepages.m + Codepages.m \ + \ + NGImap4Connection+Monkeypatching.m $(SOGOBACKEND)_RESOURCE_FILES += \ diff --git a/OpenChange/NGImap4Connection+Monkeypatching.h b/OpenChange/NGImap4Connection+Monkeypatching.h new file mode 100644 index 000000000..3a188b8c7 --- /dev/null +++ b/OpenChange/NGImap4Connection+Monkeypatching.h @@ -0,0 +1,37 @@ +/* NGImap4Connection+Monkeypatching.h - this file is part of SOGo + * + * Copyright (C) 2014 Jesús García Sáez + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __OpenChange_NGImap4Connection_Monkeypatching_H__ +#define __OpenChange_NGImap4Connection_Monkeypatching_H__ + +#import +#import +#import + + +@interface NGImap4Connection (Monkeypatching) + +- (NSArray *)fetchUIDs:(NSArray *)_uids inURL:(NSURL *)_url + parts:(NSArray *)_parts; + +@end + + +#endif // __OpenChange_NGImap4Connection_Monkeypatching_H__ diff --git a/OpenChange/NGImap4Connection+Monkeypatching.m b/OpenChange/NGImap4Connection+Monkeypatching.m new file mode 100644 index 000000000..d94a145a1 --- /dev/null +++ b/OpenChange/NGImap4Connection+Monkeypatching.m @@ -0,0 +1,108 @@ +/* NGImap4Connection+Monkeypatching.m - this file is part of SOGo + * + * Copyright (C) 2014 Jesús García Sáez + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#import "NGImap4Connection+Monkeypatching.h" + +#import +#import + +#import + + +@implementation NGImap4Connection (Monkeypatching) + +- (NSArray *)fetchUIDs:(NSArray *)_uids inURL:(NSURL *)_url + parts:(NSArray *)_parts +{ + // currently returns a dict?! + /* + Allowed fetch keys: + UID + BODY.PEEK[
]<> + BODY [this is the bodystructure, supported] + BODYSTRUCTURE [not supported yet!] + ENVELOPE [this is a parsed header, but does not include type] + FLAGS + INTERNALDATE + RFC822 + RFC822.HEADER + RFC822.SIZE + RFC822.TEXT + */ + NSMutableDictionary *result = nil; + NSUInteger i, total, step = 1000; + + if (_uids == nil || [_uids count] == 0) + return nil; + + /* select folder */ + + if (![self selectFolder:_url]) + return nil; + + /* fetch parts */ + + total = [_uids count]; + for (i = 0; i < total; i += step) { + NSRange range; + NSArray *partial_uids; + NSDictionary *partial_result; + + range = NSMakeRange(i, (i + step) > total ? (total - i) : step); + partial_uids = [_uids subarrayWithRange: range]; + + /* We will only fetch "step" uids each time */ + partial_result = [[self client] fetchUids:partial_uids parts:_parts]; + + if (![[partial_result valueForKey:@"result"] boolValue]) { + [self errorWithFormat: @"could not fetch %d uids for url: %@", [_uids count], _url]; + return nil; + } + + if (!result) { + /* First iteration, first result */ + result = [[partial_result mutableCopy] autorelease]; + /* RawResponse has already been processed, ignore it */ + [result removeObjectForKey: @"RawResponse"]; + continue; + } + + /* Merge partial_result into previous result */ + for (id key in [partial_result keyEnumerator]) { + id obj, current_obj; + + current_obj = [result objectForKey: key]; + if (!current_obj) continue; + + obj = [partial_result objectForKey: key]; + if ([obj isKindOfClass: [NSArray class]]) { + NSArray *data, *current_data, *new_data; + data = obj; + current_data = current_obj; + new_data = [current_data arrayByAddingObjectsFromArray: data]; + [result setObject: new_data forKey: key]; + } + } + } + + return (id)result; +} + +@end From c410a9fc3ff7694d179e69e5d9a904396f0ab07e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Wed, 22 Oct 2014 19:21:17 +0200 Subject: [PATCH 031/120] oc: NGImap4Connection:fetchUids don't delete RawResponse --- OpenChange/NGImap4Connection+Monkeypatching.h | 12 ++- OpenChange/NGImap4Connection+Monkeypatching.m | 95 ++++++++++++++----- 2 files changed, 80 insertions(+), 27 deletions(-) diff --git a/OpenChange/NGImap4Connection+Monkeypatching.h b/OpenChange/NGImap4Connection+Monkeypatching.h index 3a188b8c7..acbf26cd5 100644 --- a/OpenChange/NGImap4Connection+Monkeypatching.h +++ b/OpenChange/NGImap4Connection+Monkeypatching.h @@ -24,12 +24,20 @@ #import #import #import +#import @interface NGImap4Connection (Monkeypatching) -- (NSArray *)fetchUIDs:(NSArray *)_uids inURL:(NSURL *)_url - parts:(NSArray *)_parts; +- (NSArray *) fetchUIDs: (NSArray *) _uids + inURL: (NSURL *) _url + parts: (NSArray *) _parts; + +- (void) _mergeDict: (NSDictionary *) source + into: (NSMutableDictionary *) target; + +- (void) _mergeNGHashMap: (NGMutableHashMap *) source + into: (NGMutableHashMap *) target; @end diff --git a/OpenChange/NGImap4Connection+Monkeypatching.m b/OpenChange/NGImap4Connection+Monkeypatching.m index d94a145a1..bdeca87ff 100644 --- a/OpenChange/NGImap4Connection+Monkeypatching.m +++ b/OpenChange/NGImap4Connection+Monkeypatching.m @@ -20,7 +20,7 @@ #import "NGImap4Connection+Monkeypatching.h" -#import +#import #import #import @@ -28,8 +28,9 @@ @implementation NGImap4Connection (Monkeypatching) -- (NSArray *)fetchUIDs:(NSArray *)_uids inURL:(NSURL *)_url - parts:(NSArray *)_parts +- (NSArray *) fetchUIDs: (NSArray *) _uids + inURL: (NSURL *) _url + parts: (NSArray *) _parts { // currently returns a dict?! /* @@ -72,37 +73,81 @@ partial_result = [[self client] fetchUids:partial_uids parts:_parts]; if (![[partial_result valueForKey:@"result"] boolValue]) { - [self errorWithFormat: @"could not fetch %d uids for url: %@", [_uids count], _url]; + [self errorWithFormat: @"could not fetch %d uids for url: %@", + [_uids count], _url]; return nil; } - if (!result) { + if (result == nil) { /* First iteration, first result */ result = [[partial_result mutableCopy] autorelease]; - /* RawResponse has already been processed, ignore it */ - [result removeObjectForKey: @"RawResponse"]; - continue; - } - - /* Merge partial_result into previous result */ - for (id key in [partial_result keyEnumerator]) { - id obj, current_obj; - - current_obj = [result objectForKey: key]; - if (!current_obj) continue; - - obj = [partial_result objectForKey: key]; - if ([obj isKindOfClass: [NSArray class]]) { - NSArray *data, *current_data, *new_data; - data = obj; - current_data = current_obj; - new_data = [current_data arrayByAddingObjectsFromArray: data]; - [result setObject: new_data forKey: key]; - } + } else { + /* Merge partial_result into previous result */ + [self _mergeDict: partial_result into: result]; } } return (id)result; } +- (void) _mergeDict: (NSDictionary *) source + into: (NSMutableDictionary *) target +{ + for (id key in [source keyEnumerator]) { + id obj, current_obj; + + current_obj = [target objectForKey: key]; + if (current_obj == nil) { + /* This should never happen but just in case... */ + [self errorWithFormat: @"Error while merging results: nonexistent key " + @"%@ on current target", key]; + continue; + } + + obj = [source objectForKey: key]; + if ([obj isKindOfClass: [NSArray class]]) { + NSArray *data, *current_data, *new_data; + data = obj; + current_data = current_obj; + new_data = [current_data arrayByAddingObjectsFromArray: data]; + [target setObject: new_data forKey: key]; + } else if ([obj isKindOfClass: [NGMutableHashMap class]]) { + [self _mergeNGHashMap: obj into: current_obj]; + } else if ([obj isKindOfClass: [NSNumber class]]) { + if (obj != current_obj) { + [self errorWithFormat: @"While fetching uids problem happened " + @"merging results for key %@: %@ != %@", + key, obj, current_obj]; + } + } else { + [self errorWithFormat: @"While fetching uids and mergin results ignored " + @"%@ (%@) key", key, [key class]]; + } + } +} + +- (void) _mergeNGHashMap: (NGMutableHashMap *) source + into: (NGMutableHashMap *) target +{ + for (id key in [source keyEnumerator]) { + NSArray *obj, *current_obj; + + current_obj = [target objectsForKey: key]; + if (current_obj == nil) { + /* This should never happen but just in case... */ + [self errorWithFormat: @"Error while merging results: nonexistent key " + @"%@ on current target", key]; + continue; + } + + if ([current_obj count] == 1) { + /* Merge only results, that means fields with more than 1 object */ + continue; + } + + obj = [source objectsForKey: key]; + [target addObjects: obj forKey: key]; + } +} + @end From 41320a4813e232b02780eea42792b108c7f4bf3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Thu, 23 Oct 2014 12:47:43 +0200 Subject: [PATCH 032/120] oc: NGImap4Connection:fetchUids changed error messages --- OpenChange/NGImap4Connection+Monkeypatching.m | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/OpenChange/NGImap4Connection+Monkeypatching.m b/OpenChange/NGImap4Connection+Monkeypatching.m index bdeca87ff..1a09948e7 100644 --- a/OpenChange/NGImap4Connection+Monkeypatching.m +++ b/OpenChange/NGImap4Connection+Monkeypatching.m @@ -73,8 +73,8 @@ partial_result = [[self client] fetchUids:partial_uids parts:_parts]; if (![[partial_result valueForKey:@"result"] boolValue]) { - [self errorWithFormat: @"could not fetch %d uids for url: %@", - [_uids count], _url]; + [self errorWithFormat: @"Error fetching %u uids for url: %@", + total, _url]; return nil; } @@ -99,8 +99,8 @@ current_obj = [target objectForKey: key]; if (current_obj == nil) { /* This should never happen but just in case... */ - [self errorWithFormat: @"Error while merging results: nonexistent key " - @"%@ on current target", key]; + [self errorWithFormat: @"Error merging fetchUids results: " + @"nonexistent key %@ on current target", key]; continue; } @@ -115,13 +115,13 @@ [self _mergeNGHashMap: obj into: current_obj]; } else if ([obj isKindOfClass: [NSNumber class]]) { if (obj != current_obj) { - [self errorWithFormat: @"While fetching uids problem happened " - @"merging results for key %@: %@ != %@", + [self errorWithFormat: @"Error merging fetchUids results: " + @"incorrect value for key %@: %@ != %@", key, obj, current_obj]; } } else { - [self errorWithFormat: @"While fetching uids and mergin results ignored " - @"%@ (%@) key", key, [key class]]; + [self errorWithFormat: @"Error merging fetchUids results: " + @"ignored %@ (%@) key", key, [key class]]; } } } @@ -135,8 +135,8 @@ current_obj = [target objectsForKey: key]; if (current_obj == nil) { /* This should never happen but just in case... */ - [self errorWithFormat: @"Error while merging results: nonexistent key " - @"%@ on current target", key]; + [self errorWithFormat: @"Error merging fetchUids results: " + @"nonexistent key %@ on current target", key]; continue; } From c4b0ac209b3913897c9d59b5d04d12d46df9e1a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Fri, 24 Oct 2014 12:38:11 +0200 Subject: [PATCH 033/120] NSString:objectFromJSONString now can parse single values Like null => [NSNull null] --- SoObjects/SOGo/NSString+Utilities.m | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/SoObjects/SOGo/NSString+Utilities.m b/SoObjects/SOGo/NSString+Utilities.m index 70fd860ab..46f42af8e 100644 --- a/SoObjects/SOGo/NSString+Utilities.m +++ b/SoObjects/SOGo/NSString+Utilities.m @@ -560,9 +560,9 @@ static int cssEscapingCount; - (id) objectFromJSONString { SBJsonParser *parser; - NSObject *object; + NSArray *object; NSError *error; - NSString *unescaped; + NSString *unescaped, *json; object = nil; @@ -571,13 +571,16 @@ static int cssEscapingCount; parser = [SBJsonParser new]; [parser autorelease]; error = nil; - object = [parser objectWithString: self + + /* Parse it this way so we can parse simple values, like "null" */ + json = [NSString stringWithFormat: @"[%@]", self]; + object = [parser objectWithString: json error: &error]; if (error) { [self errorWithFormat: @"json parser: %@," @" attempting once more after unescaping...", error]; - unescaped = [self stringByReplacingString: @"\\\\" + unescaped = [json stringByReplacingString: @"\\\\" withString: @"\\"]; object = [parser objectWithString: unescaped error: &error]; @@ -591,7 +594,7 @@ static int cssEscapingCount; } } - return object; + return [object objectAtIndex: 0]; } - (NSString *) asSafeSQLString From 973ab78761453a24bac1f19b417f8c7c5e851f81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Thu, 6 Nov 2014 17:42:45 +0100 Subject: [PATCH 034/120] oc: synchronize folders ChangeNumber <-> modseq --- OpenChange/MAPIStoreMailFolder.h | 2 + OpenChange/MAPIStoreMailFolder.m | 64 +++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/OpenChange/MAPIStoreMailFolder.h b/OpenChange/MAPIStoreMailFolder.h index d7ec7aaaf..0a01476fe 100644 --- a/OpenChange/MAPIStoreMailFolder.h +++ b/OpenChange/MAPIStoreMailFolder.h @@ -44,6 +44,8 @@ /* synchronisation & versioning */ - (BOOL) synchroniseCache; +- (void) synchronizeUpdatedFolder: (NSNumber *) lastModseq + withMapping: (NSMutableDictionary *) mapping; - (NSNumber *) modseqFromMessageChangeNumber: (NSString *) changeNum; - (NSString *) messageUIDFromMessageKey: (NSString *) messageKey; - (NSString *) changeNumberForMessageUID: (NSString *) messageUid; diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 28fcca431..c9e168d81 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -70,6 +70,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; #undef DEBUG #include #include +#include #include #include @@ -663,15 +664,76 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) if (foundChange) { + [self synchronizeUpdatedFolder: lastModseq + withMapping: mapping]; + ti = [NSNumber numberWithDouble: [now timeIntervalSince1970]]; [currentProperties setObject: ti forKey: @"SyncLastSynchronisationDate"]; [versionsMessage save]; } + return rc; } - + +- (void) synchronizeUpdatedFolder: (NSNumber *) lastModseq + withMapping: (NSMutableDictionary *) mapping +{ + /* This method should be called whenever something has changed on the folder. + Then we will perform two actions: + 1 - Update its PidTagChangeNumber property. + 2 - Store relationship PidTagChangenumber with lastModseq value on the + mapping given as parameter */ + uint64_t *current_cn; + struct SRow row; + struct SPropValue prop; + uint64_t fid; + const char *username; + struct openchangedb_context *oc_ctx; + enum MAPISTATUS retval; + TALLOC_CTX *local_mem_ctx = NULL; + + row.cValues = 1; + prop.ulPropTag = PidTagChangeNumber; + prop.value.d = 0; // It doesn't matter, it will be autogenerated + row.lpProps = ∝ + + /* We are doing a "touch" operation to update change number of this folder */ + username = [[self context] connectionInfo]->username; + oc_ctx = [[self context] connectionInfo]->oc_ctx; + fid = [self objectId]; + retval = openchangedb_set_folder_properties(oc_ctx, username, fid, &row); + if (retval != MAPI_E_SUCCESS) + { + [self errorWithFormat:@"%s: Error setting change number on %"PRIu64, + __PRETTY_FUNCTION__, fid]; + return; + } + + local_mem_ctx = talloc_named(NULL, 0, __PRETTY_FUNCTION__); + if (local_mem_ctx == NULL) + { + [self errorWithFormat:@"%s: Error with talloc_named, out of memory?", + __PRETTY_FUNCTION__]; + return; + } + retval = openchangedb_get_folder_property(local_mem_ctx, oc_ctx, username, + PidTagChangeNumber, fid, + (void **) ¤t_cn); + if (retval != MAPI_E_SUCCESS) + { + [self errorWithFormat:@"%s: Error getting change number on %"PRIu64, + __PRETTY_FUNCTION__, fid]; + talloc_free(local_mem_ctx); + return; + } + + [mapping setObject: lastModseq + forKey: [NSString stringWithUnsignedLongLong: *current_cn]]; + talloc_free(local_mem_ctx); +} + - (NSNumber *) modseqFromMessageChangeNumber: (NSString *) changeNum { NSDictionary *mapping; From ef7b919175636b9c15c2a7f48a97925f26a280bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Wed, 12 Nov 2014 16:21:44 +0100 Subject: [PATCH 035/120] Return MAPISTORE_ERR_NOT_FOUND when a mail is indexed but not in IMAP server And remove that entry from the indexing table. This avoids to crash getting properties from a no longer available message in the IMAP server, for instance, the `PidTagPredecessorChangeList` attribute. --- OpenChange/MAPIStoreFolder.m | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index 2c0bade3b..5bc292458 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -52,6 +52,7 @@ #import #import "SOGoMAPIDBMessage.h" #import "SOGoCacheGCSObject+MAPIStore.h" +#import #include @@ -278,6 +279,12 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe msgObject = [sogoObject lookupName: messageKey inContext: nil acquire: NO]; + /* If the lookup in the indexing table works, but the IMAP does + not have the message, then the message does not exist in this + folder */ + if (msgObject && [msgObject isKindOfClass: [SOGoMailObject class]] + && ! [(SOGoMailObject *)msgObject doesMailExist]) + return nil; if (msgObject && ![msgObject isKindOfClass: NSExceptionK]) { [msgObject setContext: [[self userContext] woContext]]; @@ -503,6 +510,12 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe else rc = MAPISTORE_ERR_DENIED; } + else + { + /* Unregistering from indexing table as the backend says the + object was not found */ + [mapping unregisterURLWithID: mid]; + } } return rc; @@ -571,7 +584,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe /* flags that control the behaviour of the operation (MAPISTORE_SOFT_DELETE or MAPISTORE_PERMANENT_DELETE) */ [self logWithFormat: @"-deleteMessageWithMID: mid: 0x%.16llx flags: %d", mid, flags]; - + mapping = [self mapping]; childURL = [mapping urlFromID: mid]; if (childURL) From a8b716fbaa87f617781565963ecd3594fe455475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Wed, 19 Nov 2014 00:23:16 +0100 Subject: [PATCH 036/120] oc: sync old messages as last resort if there are not in cache This is happening when the lastModSeq is greater than the modseq from an old message and that message is not in cache. This is used as last resort before crashing and it is only used in objectVersion as it is the first place to call on sync. Other related properties would work. --- OpenChange/MAPIStoreMailFolder.h | 1 + OpenChange/MAPIStoreMailFolder.m | 64 +++++++++++++++++++++++++++++++ OpenChange/MAPIStoreMailMessage.m | 16 +++++++- 3 files changed, 79 insertions(+), 2 deletions(-) diff --git a/OpenChange/MAPIStoreMailFolder.h b/OpenChange/MAPIStoreMailFolder.h index 0a01476fe..2263f955b 100644 --- a/OpenChange/MAPIStoreMailFolder.h +++ b/OpenChange/MAPIStoreMailFolder.h @@ -46,6 +46,7 @@ - (BOOL) synchroniseCache; - (void) synchronizeUpdatedFolder: (NSNumber *) lastModseq withMapping: (NSMutableDictionary *) mapping; +- (BOOL) synchroniseCacheForUID: (NSString *) messageUID; - (NSNumber *) modseqFromMessageChangeNumber: (NSString *) changeNum; - (NSString *) messageUIDFromMessageKey: (NSString *) messageKey; - (NSString *) changeNumberForMessageUID: (NSString *) messageUid; diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index c9e168d81..2d4a20fbb 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -734,6 +734,70 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) talloc_free(local_mem_ctx); } +- (BOOL) synchroniseCacheForUID: (NSString *) messageUID +{ + /* Try to synchronise old UIDs in versions.plist cache using an + specific UID. It returns a boolean indicating if the + synchronisation were done. + + It should be used as last resort, keeping synchroniseCache to main + sync entry point. + */ + NSMutableDictionary *currentProperties, *messages, *messageEntry, *mapping; + NSArray *fetchResults; + uint64_t changeNumber; + NSDictionary *result; + NSNumber *modseq; + NSString *changeNumberStr; + NSData *changeKey; + + [versionsMessage reloadIfNeeded]; + currentProperties = [versionsMessage properties]; + messages = [currentProperties objectForKey: @"Messages"]; + messageEntry = [messages objectForKey: messageUID]; + if (!messageEntry) + { + [messages removeObjectForKey: messageUID]; + changeNumber = [[self context] getNewChangeNumber]; + fetchResults = [(NSDictionary *) [sogoObject fetchUIDs: [NSArray arrayWithObject: messageUID] + parts: [NSArray arrayWithObject: @"modseq"]] + objectForKey: @"fetch"]; + if ([fetchResults count] == 1) + { + result = [fetchResults objectAtIndex: 0]; + modseq = [result objectForKey: @"modseq"]; + changeNumberStr = [NSString stringWithUnsignedLongLong: changeNumber]; + + /* Create new message entry in Messages dict */ + messageEntry = [NSMutableDictionary new]; + [messages setObject: messageEntry forKey: messageUID]; + [messageEntry release]; + + /* Store the modseq and change number */ + [messageEntry setObject: modseq forKey: @"modseq"]; + [messageEntry setObject: changeNumberStr forKey: @"version"]; + + /* Store the change key */ + changeKey = [self getReplicaKeyFromGlobCnt: changeNumber >> 16]; + [self _setChangeKey: changeKey forMessageEntry: messageEntry]; + + /* Store the changeNumber -> modseq mapping */ + mapping = [currentProperties objectForKey: @"VersionMapping"]; + [mapping setObject: modseq forKey: changeNumberStr]; + + /* Save the message */ + [versionsMessage save]; + return YES; + } + else + { + return NO; + } + } + /* If message entry exists, then synchroniseCache did its job */ + return YES; +} + - (NSNumber *) modseqFromMessageChangeNumber: (NSString *) changeNum { NSDictionary *mapping; diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index c64f60c22..f2ab615a1 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -369,6 +369,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) { uint64_t version = ULLONG_MAX; NSString *uid, *changeNumber; + BOOL synced; uid = [(MAPIStoreMailFolder *) container messageUIDFromMessageKey: [self nameInContainer]]; @@ -387,8 +388,19 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) [self logWithFormat: @"got one"]; else { - [self errorWithFormat: @"still nothing. We crash!"]; - abort(); + [self warnWithFormat: @"attempting to get change number" + @" by synchronising this specific message..."]; + synced = [(MAPIStoreMailFolder *) container synchroniseCacheForUID: uid]; + if (synced) + { + changeNumber = [(MAPIStoreMailFolder *) container + changeNumberForMessageUID: uid]; + } + else + { + [self errorWithFormat: @"still nothing. We crash!"]; + abort(); + } } } version = [changeNumber unsignedLongLongValue] >> 16; From f4e15e2db8fdda0ff6d94d1690e35ebab1d334a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Wed, 26 Nov 2014 09:20:45 +0100 Subject: [PATCH 037/120] Fix memory leak on getPidTagSubject Valgrind crafted report: =40967== 128,927 (53,750 direct, 75,177 indirect) bytes in 383 blocks are definitely lost in loss record 10,104 of 10,179 ==40967== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==40967== by 0x86EDE3D: talloc_strndup (talloc.c:613) ==40967== by 0x34D2BB9E: _i_NSString_MAPIStoreDataTypes_asUnicodeInMemCtx_ (in /usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore/SOGoBackend) ==40967== by 0x34D2025B: _i_MAPIStoreMailMessage__getPidTagNormalizedSubject_inMemCtx_ (in /usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore/SOGoBackend) ==40967== by 0x34CFCD40: _i_MAPIStoreObject__getProperty_withTag_inMemCtx_ (in /usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore/SOGoBackend) ==40967== by 0x34CFBE21: _i_MAPIStoreMessage__getPidTagSubject_inMemCtx_ (in /usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore/SOGoBackend) ==40967== by 0x34CFBEB6: _i_MAPIStoreMessage__getPidTagOriginalSubject_inMemCtx_ (in /usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore/SOGoBackend) ==40967== by 0x34CFCD40: _i_MAPIStoreObject__getProperty_withTag_inMemCtx_ (in /usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore/SOGoBackend) ==40967== by 0x34CFD07E: _i_MAPIStoreObject__getProperties_withTags_andCount_inMemCtx_ (in /usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore/SOGoBackend) --- OpenChange/MAPIStoreMessage.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenChange/MAPIStoreMessage.m b/OpenChange/MAPIStoreMessage.m index 444ecd0fb..fc20dd0d0 100644 --- a/OpenChange/MAPIStoreMessage.m +++ b/OpenChange/MAPIStoreMessage.m @@ -795,7 +795,7 @@ rtf2html (NSData *compressedRTF) TALLOC_CTX *localMemCtx; char *prefix, *normalizedSubject; - localMemCtx = talloc_zero (NULL, TALLOC_CTX); + localMemCtx = talloc_zero (memCtx, TALLOC_CTX); if ([self getProperty: (void **) &prefix withTag: PidTagSubjectPrefix inMemCtx: localMemCtx] @@ -807,6 +807,8 @@ rtf2html (NSData *compressedRTF) if (rc == MAPISTORE_SUCCESS) *data = talloc_asprintf (memCtx, "%s%s", prefix, normalizedSubject); + talloc_free(localMemCtx); + return rc; } From 2c6d833c118d26d13d9689f371008043bf510cb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Thu, 27 Nov 2014 17:13:02 +0100 Subject: [PATCH 038/120] Remove an attempt to double free content As content is freed by resetExceptResult message received by reset which has been called by dealloc as well --- SOPE/NGCards/NGCardsSaxHandler.m | 2 -- 1 file changed, 2 deletions(-) diff --git a/SOPE/NGCards/NGCardsSaxHandler.m b/SOPE/NGCards/NGCardsSaxHandler.m index fca1a64e6..a70255863 100644 --- a/SOPE/NGCards/NGCardsSaxHandler.m +++ b/SOPE/NGCards/NGCardsSaxHandler.m @@ -55,8 +55,6 @@ static NSArray *privilegedTagNames = nil; - (void) dealloc { - if (content) - free (content); [self reset]; [cards release]; [currentGroup release]; From 7691d616a9ff46d4540d1a0c5a0ecbf64b3ecad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Sat, 29 Nov 2014 08:07:41 +0100 Subject: [PATCH 039/120] Attempt to sync an UID in setChangeKey to avoid crashing This may happen if between sync cache and setChangeKey a modSeq is making synchroniseCache not retrieve the newly stored message. This should fix the following crash: https://tracker.zentyal.org/issues/2673 --- OpenChange/MAPIStoreMailFolder.m | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 2d4a20fbb..6140eb141 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -757,7 +757,6 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) messageEntry = [messages objectForKey: messageUID]; if (!messageEntry) { - [messages removeObjectForKey: messageUID]; changeNumber = [[self context] getNewChangeNumber]; fetchResults = [(NSDictionary *) [sogoObject fetchUIDs: [NSArray arrayWithObject: messageUID] parts: [NSArray arrayWithObject: @"modseq"]] @@ -844,12 +843,21 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) { NSMutableDictionary *messages, *messageEntry; NSString *messageUid; + BOOL synced; messageUid = [self messageUIDFromMessageKey: messageKey]; messages = [[versionsMessage properties] objectForKey: @"Messages"]; messageEntry = [messages objectForKey: messageUid]; if (!messageEntry) - abort (); + { + [self warnWithFormat: @"attempting to synchronise to set the change key for " + @"this message %@", messageKey]; + synced = [self synchroniseCacheForUID: messageUid]; + if (synced) + messageEntry = [[[versionsMessage properties] objectForKey: @"Messages"] objectForKey: messageUid]; + else + abort (); + } [self _setChangeKey: changeKey forMessageEntry: messageEntry]; [versionsMessage save]; From 97201c56a45ac51ea744fe85ca4e875a87c5fe68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Mon, 1 Dec 2014 10:47:16 +0100 Subject: [PATCH 040/120] abort if attemp to sync an UID in setChangekey fails --- OpenChange/MAPIStoreMailFolder.m | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 6140eb141..58cab6105 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -855,8 +855,11 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) synced = [self synchroniseCacheForUID: messageUid]; if (synced) messageEntry = [[[versionsMessage properties] objectForKey: @"Messages"] objectForKey: messageUid]; - else - abort (); + if (!messageEntry) + { + [self errorWithFormat: @"still nothing. We crash!"]; + abort (); + } } [self _setChangeKey: changeKey forMessageEntry: messageEntry]; From 067809ef1c314becd908a0af48edc8a4a3aabcba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Mon, 1 Dec 2014 23:19:38 +0100 Subject: [PATCH 041/120] Store changeNumber maps with modseq in cache for subfolders By getting the root folder/container whose properties are stored in OpenChange DB. This makes the synchronisation of sub-folders faster as when we evaluate restrictions for this folder, we are able to get the modseq from where to get the latest messages unseen by the client. --- OpenChange/MAPIStoreFolder.h | 1 + OpenChange/MAPIStoreFolder.m | 11 +++++++++++ OpenChange/MAPIStoreMailFolder.m | 9 +++++---- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/OpenChange/MAPIStoreFolder.h b/OpenChange/MAPIStoreFolder.h index 94a1cb634..e5440bd95 100644 --- a/OpenChange/MAPIStoreFolder.h +++ b/OpenChange/MAPIStoreFolder.h @@ -150,6 +150,7 @@ /* helpers */ - (uint64_t) idForObjectWithKey: (NSString *) childKey; +- (MAPIStoreFolder *) rootContainer; /* subclasses */ - (MAPIStoreMessage *) createMessage; diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index 5bc292458..644f88965 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -1885,6 +1885,17 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe inFolderURL: [self url]]; } +- (MAPIStoreFolder *) rootContainer +{ + /* Return the oldest ancestor, which does not have + container. If there is not container, it returns itself. + */ + if (container) + return [container rootContainer]; + else + return self; +} + - (NSDate *) creationTime { return [dbFolder creationDate]; diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 2d4a20fbb..99d2d3274 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -682,9 +682,9 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) { /* This method should be called whenever something has changed on the folder. Then we will perform two actions: - 1 - Update its PidTagChangeNumber property. + 1 - Update the PidTagChangeNumber property of the root container. 2 - Store relationship PidTagChangenumber with lastModseq value on the - mapping given as parameter */ + mapping given as parameter for this folder */ uint64_t *current_cn; struct SRow row; struct SPropValue prop; @@ -699,10 +699,11 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) prop.value.d = 0; // It doesn't matter, it will be autogenerated row.lpProps = ∝ - /* We are doing a "touch" operation to update change number of this folder */ + /* We are doing a "touch" operation to update change number of the root container. + We get the root container as it has the properties in the OpenChange DB */ username = [[self context] connectionInfo]->username; oc_ctx = [[self context] connectionInfo]->oc_ctx; - fid = [self objectId]; + fid = [[self rootContainer] objectId]; retval = openchangedb_set_folder_properties(oc_ctx, username, fid, &row); if (retval != MAPI_E_SUCCESS) { From dba17fbcbcd3c8725385df5273911499a6321bdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Tue, 16 Dec 2014 23:39:42 +0100 Subject: [PATCH 042/120] Create child folder objects using parent context for real We activate the user for the context using the root folder context as there are times where the active user is not matching with the one stored in the application context and SOGo object is storing cached data with the wrong user leading to create folders in wrong mailboxes, etc. As this application is single-threaded, no problems are expected. Indeed, the same code is available at getting the root folder (ie INBOX). --- OpenChange/MAPIStoreFolder.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index 644f88965..15f3ca431 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -29,6 +29,7 @@ #import #import #import +#import #import #import #import @@ -235,6 +236,11 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe if ([[self folderKeys] containsObject: folderKey]) { woContext = [[self userContext] woContext]; + /* We activate the user for the context using the root folder + context as there are times where the active user is not + matching with the one stored in the application context + and SOGo object is storing cached data with the wrong user */ + [[self userContext] activateWithUser: [woContext activeUser]]; sogoFolder = [sogoObject lookupName: folderKey inContext: woContext acquire: NO]; if (sogoFolder && ![sogoFolder isKindOfClass: NSExceptionK]) From a56fc93a9afbeaf2323296d2843be0ca9aa80238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Tue, 23 Dec 2014 00:54:16 +0100 Subject: [PATCH 043/120] oc: Guess recipients from some properties while importing PST This is happening when importing a PST file. From -> PidTagSenderEntryId To -> PidTagOriginalDisplayTo CC -> PidTagOriginalDisplayCc The tested EntryID are the local users and OneOffEntries when the users are not from the directory. It requires https://github.com/openchange/openchange/pull/175 to work. --- OpenChange/MAPIStoreMailVolatileMessage.m | 84 ++++++++++++++++++++++- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/OpenChange/MAPIStoreMailVolatileMessage.m b/OpenChange/MAPIStoreMailVolatileMessage.m index 528b7e7e8..55d62309e 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.m +++ b/OpenChange/MAPIStoreMailVolatileMessage.m @@ -537,8 +537,9 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers, NSDictionary *mailProperties, BOOL withBcc, struct mapistore_connection_info *connInfo) { + NSData *senderEntryId; NSMutableString *subject; - NSString *from, *recId, *messageId, *subjectData; + NSString *from, *recId, *messageId, *subjectData, *recipientsStr; NSArray *list; NSCalendarDate *date; NSDictionary *recipients; @@ -575,7 +576,86 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers, [headers setObjects: list forKey: @"from"]; } else - NSLog (@"message without recipients"); + { + NSLog (@"Message without recipients." + @"Guessing recipients from PidTagSenderEntryId, PidTagOriginalDisplayTo" + @"and PidTagOriginalCc"); + senderEntryId = [mailProperties objectForKey: MAPIPropertyKey (PR_SENDER_ENTRYID)]; + if (senderEntryId) + { + struct Binary_r bin32; + struct AddressBookEntryId *addrBookEntryId; + NSString *username; + NSMutableDictionary *fromRecipient; + + fromRecipient = [NSMutableDictionary dictionaryWithCapacity: 2]; + + bin32.cb = [senderEntryId length]; + bin32.lpb = (uint8_t *) [senderEntryId bytes]; + addrBookEntryId = get_AddressBookEntryId (connInfo->sam_ctx, &bin32); + if (addrBookEntryId && [[NSString stringWithGUID: &addrBookEntryId->ProviderUID] + hasSuffix: @"08002b2fe182"]) + { + /* TODO: better way to distinguish local and other ones */ + username = MAPIStoreSamDBUserAttribute (connInfo->sam_ctx, @"legacyExchangeDN", + [NSString stringWithUTF8String: addrBookEntryId->X500DN], @"sAMAccountName"); + if (username) + { + SOGoUser *fromUser; + + fromUser = [SOGoUser userWithLogin: [username lowercaseString]]; + [fromRecipient setObject: [fromUser cn] forKey: @"fullName"]; + [fromRecipient setObject: [[fromUser allEmails] objectAtIndex: 0] + forKey: @"email"]; + } + else + [fromRecipient setObject: [NSString stringWithUTF8String: addrBookEntryId->X500DN] + forKey: @"email"]; + + } + else + { + /* Try with One-Off EntryId */ + struct OneOffEntryId *oneOffEntryId; + + oneOffEntryId = get_OneOffEntryId (connInfo->sam_ctx, &bin32); + if (oneOffEntryId && [[NSString stringWithGUID: &oneOffEntryId->ProviderUID] + hasSuffix: @"00dd010f5402"]) + { + [fromRecipient setObject: [NSString stringWithUTF8String: oneOffEntryId->DisplayName.lpszW] + forKey: @"fullName"]; + [fromRecipient setObject: [NSString stringWithUTF8String: oneOffEntryId->EmailAddress.lpszW] + forKey: @"email"]; + } + talloc_free (oneOffEntryId); + } + talloc_free (addrBookEntryId); + + if ([[fromRecipient allKeys] count] > 0) + { + list = MakeRecipientsList ([NSArray arrayWithObjects: fromRecipient, nil]); + if ([list count]) + [headers setObjects: list forKey: @"from"]; + } + + } + + recipientsStr = [mailProperties objectForKey: MAPIPropertyKey (PidTagOriginalDisplayTo)]; + if (recipientsStr) + { + list = [recipientsStr componentsSeparatedByString:@", "]; + if ([list count]) + [headers setObjects: list forKey: @"to"]; + } + + recipientsStr = [mailProperties objectForKey: MAPIPropertyKey (PidTagOriginalDisplayCc)]; + if (recipientsStr) + { + list = [recipientsStr componentsSeparatedByString:@", "]; + if ([list count]) + [headers setObjects: list forKey: @"cc"]; + } + } subject = [NSMutableString stringWithCapacity: 128]; subjectData = [mailProperties objectForKey: MAPIPropertyKey (PR_SUBJECT_PREFIX_UNICODE)]; From 501ee7976664629616089cf88b9f779c6c9fe75e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Tue, 23 Dec 2014 10:59:01 +0100 Subject: [PATCH 044/120] oc-rtf: fix parse \pict tag with \bin data --- OpenChange/RTFHandler.m | 43 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/OpenChange/RTFHandler.m b/OpenChange/RTFHandler.m index f9dd47db3..801159552 100644 --- a/OpenChange/RTFHandler.m +++ b/OpenChange/RTFHandler.m @@ -26,6 +26,7 @@ // Useful macros // #define ADVANCE _bytes++; _current_pos++; +#define ADVANCE_N(N) _bytes += (N); _current_pos += (N); #define REWIND _bytes--; _current_pos--; @@ -663,8 +664,46 @@ const unsigned short ansicpg874[256] = { // - (void) parsePicture { - // Do the same as -parseStyleSheet for now, that is, ignore everything. - [self parseStyleSheet]; + // Ignore everything. But we cannot parse it blindly because it could have + // binary data with '}' and '{' bytes, so disasters can happen and they will + unsigned int count = 0; + const char *cw; + + do + { + if (*_bytes == '\\') + { + unsigned int binary_size, len = 0, cw_len; + cw = [self parseControlWord: &len]; + cw_len = strlen("bin"); + if (strncmp(cw, "bin", cw_len) == 0 && len > cw_len) + { + NSString *s; + s = [[NSString alloc] initWithBytesNoCopy: (void *) cw + cw_len + length: len - cw_len + encoding: NSASCIIStringEncoding + freeWhenDone: NO]; + [s autorelease]; + binary_size = [s intValue]; + ADVANCE_N(binary_size); + } + else if (len > 0) + { + ADVANCE_N(len); + } + else + { + ADVANCE; + } + } + else + { + if (*_bytes == '{') count++; + if (*_bytes == '}') count--; + ADVANCE; + } + } + while (count > 0); } // From 838ae8995ff592d4526194a37c8f5554082cbca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Mon, 29 Dec 2014 19:20:16 +0100 Subject: [PATCH 045/120] oc: ignore unhandled properties instead of abort When setting a row with properties not handled right now, ignore them like they were never there instead of abort() --- OpenChange/MAPIStoreObject.m | 3 +++ OpenChange/MAPIStoreTypes.m | 6 ++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/OpenChange/MAPIStoreObject.m b/OpenChange/MAPIStoreObject.m index 1d468915c..1c85caf04 100644 --- a/OpenChange/MAPIStoreObject.m +++ b/OpenChange/MAPIStoreObject.m @@ -256,6 +256,9 @@ static Class NSExceptionK, MAPIStoreFolderK; { cValue = aRow->lpProps + counter; value = NSObjectFromSPropValue (cValue); + if (value == nil) + continue; + switch (cValue->ulPropTag & 0xffff) { case PT_STRING8: diff --git a/OpenChange/MAPIStoreTypes.m b/OpenChange/MAPIStoreTypes.m index f8e32c824..01b650463 100644 --- a/OpenChange/MAPIStoreTypes.m +++ b/OpenChange/MAPIStoreTypes.m @@ -154,8 +154,7 @@ NSObjectFromMAPISPropValue (const struct mapi_SPropValue *value) // #define PT_I8 0x14 // #define PT_SRESTRICT 0xFD // #define PT_ACTIONS 0xFE - result = [NSNull null]; - abort(); + result = nil; NSLog (@"%s: object type not handled: %d (0x%.4x)", __PRETTY_FUNCTION__, valueType, valueType); } @@ -250,8 +249,7 @@ NSObjectFromSPropValue (const struct SPropValue *value) // #define PT_I8 0x14 // #define PT_SRESTRICT 0xFD // #define PT_ACTIONS 0xFE - result = [NSNull null]; - abort(); + result = nil; NSLog (@"%s: object type not handled: %d (0x%.4x)", __PRETTY_FUNCTION__, valueType, valueType); } From d052356724fdde9a5b1777e81edceb5e0a794696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Thu, 15 Jan 2015 13:27:37 +0100 Subject: [PATCH 046/120] oc: encoding names must be case insensitive --- OpenChange/Codepages.m | 116 ++++++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/OpenChange/Codepages.m b/OpenChange/Codepages.m index d8574f9c5..8776ffe22 100644 --- a/OpenChange/Codepages.m +++ b/OpenChange/Codepages.m @@ -31,57 +31,57 @@ { /* http://msdn.microsoft.com/en-us/library/dd317756%28v=vs.85%29.aspx */ table = [[NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInt: 37], @"IBM037", - [NSNumber numberWithInt: 437], @"IBM437", - [NSNumber numberWithInt: 500], @"IBM500", - [NSNumber numberWithInt: 708], @"ASMO-708", - [NSNumber numberWithInt: 720], @"DOS-720", + [NSNumber numberWithInt: 37], @"ibm037", + [NSNumber numberWithInt: 437], @"ibm437", + [NSNumber numberWithInt: 500], @"ibm500", + [NSNumber numberWithInt: 708], @"asmo-708", + [NSNumber numberWithInt: 720], @"dos-720", [NSNumber numberWithInt: 737], @"ibm737", [NSNumber numberWithInt: 775], @"ibm775", [NSNumber numberWithInt: 850], @"ibm850", [NSNumber numberWithInt: 852], @"ibm852", - [NSNumber numberWithInt: 855], @"IBM855", + [NSNumber numberWithInt: 855], @"ibm855", [NSNumber numberWithInt: 857], @"ibm857", - [NSNumber numberWithInt: 858], @"IBM00858", - [NSNumber numberWithInt: 860], @"IBM860", + [NSNumber numberWithInt: 858], @"ibm00858", + [NSNumber numberWithInt: 860], @"ibm860", [NSNumber numberWithInt: 861], @"ibm861", - [NSNumber numberWithInt: 862], @"DOS-862", - [NSNumber numberWithInt: 863], @"IBM863", - [NSNumber numberWithInt: 864], @"IBM864", - [NSNumber numberWithInt: 865], @"IBM865", + [NSNumber numberWithInt: 862], @"dos-862", + [NSNumber numberWithInt: 863], @"ibm863", + [NSNumber numberWithInt: 864], @"ibm864", + [NSNumber numberWithInt: 865], @"ibm865", [NSNumber numberWithInt: 866], @"cp866", [NSNumber numberWithInt: 869], @"ibm869", - [NSNumber numberWithInt: 870], @"IBM870", + [NSNumber numberWithInt: 870], @"ibm870", [NSNumber numberWithInt: 874], @"windows-874", [NSNumber numberWithInt: 875], @"cp875", [NSNumber numberWithInt: 932], @"shift_jis", [NSNumber numberWithInt: 936], @"gb2312", [NSNumber numberWithInt: 949], @"ks_c_5601-1987", [NSNumber numberWithInt: 950], @"big5", - [NSNumber numberWithInt: 1026], @"IBM1026", - [NSNumber numberWithInt: 1047], @"IBM01047", - [NSNumber numberWithInt: 1140], @"IBM01140", - [NSNumber numberWithInt: 1141], @"IBM01141", - [NSNumber numberWithInt: 1142], @"IBM01142", - [NSNumber numberWithInt: 1143], @"IBM01143", - [NSNumber numberWithInt: 1144], @"IBM01144", - [NSNumber numberWithInt: 1145], @"IBM01145", - [NSNumber numberWithInt: 1146], @"IBM01146", - [NSNumber numberWithInt: 1147], @"IBM01147", - [NSNumber numberWithInt: 1148], @"IBM01148", - [NSNumber numberWithInt: 1149], @"IBM01149", + [NSNumber numberWithInt: 1026], @"ibm1026", + [NSNumber numberWithInt: 1047], @"ibm01047", + [NSNumber numberWithInt: 1140], @"ibm01140", + [NSNumber numberWithInt: 1141], @"ibm01141", + [NSNumber numberWithInt: 1142], @"ibm01142", + [NSNumber numberWithInt: 1143], @"ibm01143", + [NSNumber numberWithInt: 1144], @"ibm01144", + [NSNumber numberWithInt: 1145], @"ibm01145", + [NSNumber numberWithInt: 1146], @"ibm01146", + [NSNumber numberWithInt: 1147], @"ibm01147", + [NSNumber numberWithInt: 1148], @"ibm01148", + [NSNumber numberWithInt: 1149], @"ibm01149", [NSNumber numberWithInt: 1200], @"utf-16", - [NSNumber numberWithInt: 1201], @"unicodeFFFE", + [NSNumber numberWithInt: 1201], @"unicodefffe", [NSNumber numberWithInt: 1250], @"windows-1250", [NSNumber numberWithInt: 1251], @"windows-1251", - [NSNumber numberWithInt: 1252], @"Windows-1252", + [NSNumber numberWithInt: 1252], @"windows-1252", [NSNumber numberWithInt: 1253], @"windows-1253", [NSNumber numberWithInt: 1254], @"windows-1254", [NSNumber numberWithInt: 1255], @"windows-1255", [NSNumber numberWithInt: 1256], @"windows-1256", [NSNumber numberWithInt: 1257], @"windows-1257", [NSNumber numberWithInt: 1258], @"windows-1258", - [NSNumber numberWithInt: 1361], @"Johab", + [NSNumber numberWithInt: 1361], @"johab", [NSNumber numberWithInt: 10000], @"macintosh", [NSNumber numberWithInt: 10001], @"x-mac-japanese", [NSNumber numberWithInt: 10002], @"x-mac-chinesetrad", @@ -99,39 +99,39 @@ [NSNumber numberWithInt: 10081], @"x-mac-turkish", [NSNumber numberWithInt: 10082], @"x-mac-croatian", [NSNumber numberWithInt: 12000], @"utf-32", - [NSNumber numberWithInt: 12001], @"utf-32BE", - [NSNumber numberWithInt: 20000], @"x-Chinese-CNS", + [NSNumber numberWithInt: 12001], @"utf-32be", + [NSNumber numberWithInt: 20000], @"x-chinese-cns", [NSNumber numberWithInt: 20001], @"x-cp20001", - [NSNumber numberWithInt: 20002], @"x-Chinese-Eten", + [NSNumber numberWithInt: 20002], @"x-chinese-eten", [NSNumber numberWithInt: 20003], @"x-cp20003", [NSNumber numberWithInt: 20004], @"x-cp20004", [NSNumber numberWithInt: 20005], @"x-cp20005", - [NSNumber numberWithInt: 20105], @"x-IA5", - [NSNumber numberWithInt: 20106], @"x-IA5-German", - [NSNumber numberWithInt: 20107], @"x-IA5-Swedish", - [NSNumber numberWithInt: 20108], @"x-IA5-Norwegian", + [NSNumber numberWithInt: 20105], @"x-ia5", + [NSNumber numberWithInt: 20106], @"x-ia5-german", + [NSNumber numberWithInt: 20107], @"x-ia5-swedish", + [NSNumber numberWithInt: 20108], @"x-ia5-norwegian", [NSNumber numberWithInt: 20127], @"us-ascii", [NSNumber numberWithInt: 20261], @"x-cp20261", [NSNumber numberWithInt: 20269], @"x-cp20269", - [NSNumber numberWithInt: 20273], @"IBM273", - [NSNumber numberWithInt: 20277], @"IBM277", - [NSNumber numberWithInt: 20278], @"IBM278", - [NSNumber numberWithInt: 20280], @"IBM280", - [NSNumber numberWithInt: 20284], @"IBM284", - [NSNumber numberWithInt: 20285], @"IBM285", - [NSNumber numberWithInt: 20290], @"IBM290", - [NSNumber numberWithInt: 20297], @"IBM297", - [NSNumber numberWithInt: 20420], @"IBM420", - [NSNumber numberWithInt: 20423], @"IBM423", - [NSNumber numberWithInt: 20424], @"IBM424", - [NSNumber numberWithInt: 20833], @"x-EBCDIC-KoreanExtended", - [NSNumber numberWithInt: 20838], @"IBM-Thai", + [NSNumber numberWithInt: 20273], @"ibm273", + [NSNumber numberWithInt: 20277], @"ibm277", + [NSNumber numberWithInt: 20278], @"ibm278", + [NSNumber numberWithInt: 20280], @"ibm280", + [NSNumber numberWithInt: 20284], @"ibm284", + [NSNumber numberWithInt: 20285], @"ibm285", + [NSNumber numberWithInt: 20290], @"ibm290", + [NSNumber numberWithInt: 20297], @"ibm297", + [NSNumber numberWithInt: 20420], @"ibm420", + [NSNumber numberWithInt: 20423], @"ibm423", + [NSNumber numberWithInt: 20424], @"ibm424", + [NSNumber numberWithInt: 20833], @"x-ebcdic-koreanextended", + [NSNumber numberWithInt: 20838], @"ibm-thai", [NSNumber numberWithInt: 20866], @"koi8-r", - [NSNumber numberWithInt: 20871], @"IBM871", - [NSNumber numberWithInt: 20880], @"IBM880", - [NSNumber numberWithInt: 20905], @"IBM905", - [NSNumber numberWithInt: 20924], @"IBM00924", - [NSNumber numberWithInt: 20932], @"EUC-JP", + [NSNumber numberWithInt: 20871], @"ibm871", + [NSNumber numberWithInt: 20880], @"ibm880", + [NSNumber numberWithInt: 20905], @"ibm905", + [NSNumber numberWithInt: 20924], @"ibm00924", + [NSNumber numberWithInt: 20932], @"euc-jp", [NSNumber numberWithInt: 20936], @"x-cp20936", [NSNumber numberWithInt: 20949], @"x-cp20949", [NSNumber numberWithInt: 21025], @"cp1025", @@ -147,18 +147,18 @@ [NSNumber numberWithInt: 28599], @"iso-8859-9", [NSNumber numberWithInt: 28603], @"iso-8859-13", [NSNumber numberWithInt: 28605], @"iso-8859-15", - [NSNumber numberWithInt: 29001], @"x-Europa", + [NSNumber numberWithInt: 29001], @"x-europa", [NSNumber numberWithInt: 38598], @"iso-8859-8-i", [NSNumber numberWithInt: 50220], @"iso-2022-jp", - [NSNumber numberWithInt: 50221], @"csISO2022JP", + [NSNumber numberWithInt: 50221], @"csiso2022jp", [NSNumber numberWithInt: 50222], @"iso-2022-jp", [NSNumber numberWithInt: 50225], @"iso-2022-kr", [NSNumber numberWithInt: 50227], @"x-cp50227", [NSNumber numberWithInt: 51932], @"euc-jp", - [NSNumber numberWithInt: 51936], @"EUC-CN", + [NSNumber numberWithInt: 51936], @"euc-cn", [NSNumber numberWithInt: 51949], @"euc-kr", [NSNumber numberWithInt: 52936], @"hz-gb-2312", - [NSNumber numberWithInt: 54936], @"GB18030", + [NSNumber numberWithInt: 54936], @"gb18030", [NSNumber numberWithInt: 57002], @"x-iscii-de", [NSNumber numberWithInt: 57003], @"x-iscii-be", [NSNumber numberWithInt: 57004], @"x-iscii-ta", @@ -203,7 +203,7 @@ + (NSNumber *) getCodepageFromName: (NSString *) name { - return [[self getCodepagesTable] objectForKey: name]; + return [[self getCodepagesTable] objectForKey: [name lowercaseString]]; } + (NSString *) getNameFromCodepage: (NSNumber *) codepage From 7e7d302165061964a8730e5b42f1ef5c27a20465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Thu, 15 Jan 2015 13:50:26 +0100 Subject: [PATCH 047/120] oc: warning if codepage not found from headerCharset --- OpenChange/MAPIStoreMailMessage.m | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index f2ab615a1..8a9bd1918 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -940,7 +940,11 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) codepage = [Codepages getCodepageFromName: headerCharset]; if (!codepage) - codepage = [Codepages getCodepageFromName: @"utf-8"]; + { + [self warnWithFormat: @"Couldn't find codepage from `%@`. " + @"Using UTF-8 by default", headerCharset]; + codepage = [Codepages getCodepageFromName: @"utf-8"]; + } *data = MAPILongValue(memCtx, [codepage intValue]); From b35fee8efc206b92d55c30757005df484f764cbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Fri, 16 Jan 2015 01:34:16 +0100 Subject: [PATCH 048/120] oc-contacts: Implement Wedding Anniversary As specified by Microsoft using x-ms-anniversary custom vcard element [MS-OXVCARD] Section 2.1.3.9.6 --- OpenChange/MAPIStoreContactsMessage.m | 30 +++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/OpenChange/MAPIStoreContactsMessage.m b/OpenChange/MAPIStoreContactsMessage.m index 3b35f9c34..c866670f2 100644 --- a/OpenChange/MAPIStoreContactsMessage.m +++ b/OpenChange/MAPIStoreContactsMessage.m @@ -723,6 +723,27 @@ return rc; } +- (int) getPidTagWeddingAnniversary: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSCalendarDate *dateValue; + NSString *stringValue; + int rc = MAPISTORE_SUCCESS; + + stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-ms-anniversary"] + flattenedValuesForKey: @""]; + if (stringValue && ! [stringValue isEqualToString: @""]) + { + dateValue = [NSCalendarDate dateWithString: stringValue + calendarFormat: @"%Y-%m-%d"]; + *data = [dateValue asFileTimeInMemCtx: memCtx]; + } + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; +} + // // Decomposed fullname getters // @@ -1173,6 +1194,15 @@ fromProperties: (NSDictionary *) attachmentProps [newCard setBday: [value descriptionWithCalendarFormat: @"%Y-%m-%d"]]; } + /* wedding anniversary */ + value = [properties objectForKey: MAPIPropertyKey(PidTagWeddingAnniversary)]; + if (value) + { + [[newCard uniqueChildWithTag: @"x-ms-anniversary"] + setSingleValue: [value descriptionWithCalendarFormat: @"%Y-%m-%d"] + forKey: @""]; + } + /* photo */ if ([attachmentParts count] > 0) { From f9550b91812248b12657943fd81d3524399eb4ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Mon, 19 Jan 2015 15:35:44 +0100 Subject: [PATCH 049/120] oc: several uninitialized variables --- OpenChange/MAPIStoreDBFolder.m | 2 ++ OpenChange/MAPIStoreFolder.m | 3 +++ OpenChange/MAPIStoreMailFolder.m | 3 +++ OpenChange/MAPIStoreMessage.m | 4 +++- OpenChange/MAPIStoreObject.m | 1 + OpenChange/RTFHandler.m | 2 ++ 6 files changed, 14 insertions(+), 1 deletion(-) diff --git a/OpenChange/MAPIStoreDBFolder.m b/OpenChange/MAPIStoreDBFolder.m index f9b2e128d..ec7207062 100644 --- a/OpenChange/MAPIStoreDBFolder.m +++ b/OpenChange/MAPIStoreDBFolder.m @@ -138,6 +138,8 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; MAPIStoreMapping *mapping; NSRange slashRange; + pathComponent = nil; + if (isMove && [targetFolder isKindOfClass: MAPIStoreDBFolderK]) { path = [sogoObject path]; diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index 15f3ca431..a939b9610 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -102,6 +102,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe NSUInteger lastPartIdx; MAPIStoreUserContext *userContext; + parts = 0; + lastPartIdx = 0; folderURL = [NSURL URLWithString: [self url]]; /* note: -[NSURL path] returns an unescaped representation */ path = [folderURL path]; @@ -233,6 +235,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe SOGoFolder *sogoFolder; WOContext *woContext; + childFolder = nil; if ([[self folderKeys] containsObject: folderKey]) { woContext = [[self userContext] woContext]; diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 12db06a08..57679c1f1 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -164,6 +164,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; int i; nameInContainer = nil; + rc = MAPISTORE_ERROR; folderName = nil; for (i = 0; !folderName && i < aRow->cValues; i++) @@ -1003,6 +1004,8 @@ _parseIMAPRange (const unichar *uniString, NSArray **UIDsP) uint32_t currentUid, rangeMin; BOOL done = NO, inRange = NO; + rangeMin = 0; + currentUid = 0; UIDs = [NSMutableArray array]; while (!done) { diff --git a/OpenChange/MAPIStoreMessage.m b/OpenChange/MAPIStoreMessage.m index fc20dd0d0..2c5707158 100644 --- a/OpenChange/MAPIStoreMessage.m +++ b/OpenChange/MAPIStoreMessage.m @@ -474,7 +474,9 @@ rtf2html (NSData *compressedRTF) MAPIStoreMessage *mainMessage; //[self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__]; - + + containerTables = nil; + max = 0; context = [self context]; ownerUser = [[self userContext] sogoUser]; userIsOwner = [[context activeUser] isEqual: ownerUser]; diff --git a/OpenChange/MAPIStoreObject.m b/OpenChange/MAPIStoreObject.m index 1c85caf04..1c4b26be4 100644 --- a/OpenChange/MAPIStoreObject.m +++ b/OpenChange/MAPIStoreObject.m @@ -250,6 +250,7 @@ static Class NSExceptionK, MAPIStoreFolderK; id value; tz = nil; + tzOffset = 0; newProperties = [NSMutableDictionary dictionaryWithCapacity: aRow->cValues]; for (counter = 0; counter < aRow->cValues; counter++) diff --git a/OpenChange/RTFHandler.m b/OpenChange/RTFHandler.m index 801159552..6d3a225b4 100644 --- a/OpenChange/RTFHandler.m +++ b/OpenChange/RTFHandler.m @@ -539,6 +539,7 @@ const unsigned short ansicpg874[256] = { fontTable = [[[RTFFontTable alloc] init] autorelease]; fontName = nil; + fontInfo = nil; count = 0; do @@ -723,6 +724,7 @@ const unsigned short ansicpg874[256] = { fontTable = nil; colorTable = nil; charset = NULL; + formattingOptions = nil; _html = [[NSMutableData alloc] init]; [_html appendBytes: "" length: 34]; From 00cef845b75ec2859e412a63a1a97fecfe21463d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20P=C3=A9rez-Aradros=20Herce?= Date: Mon, 19 Jan 2015 19:04:06 +0100 Subject: [PATCH 050/120] Restore multitenancy changes for OpenChange --- OpenChange/MAPIStoreFallbackContext.m | 10 ++++++++-- OpenChange/MAPIStoreGCSBaseContext.m | 8 ++++++-- OpenChange/MAPIStoreMailContext.m | 19 +++++++++++++++---- OpenChange/MAPIStoreNotesContext.m | 3 ++- OpenChange/MAPIStoreSOGo.m | 5 ++++- 5 files changed, 35 insertions(+), 10 deletions(-) diff --git a/OpenChange/MAPIStoreFallbackContext.m b/OpenChange/MAPIStoreFallbackContext.m index 41463542a..5b1a40ad1 100644 --- a/OpenChange/MAPIStoreFallbackContext.m +++ b/OpenChange/MAPIStoreFallbackContext.m @@ -55,7 +55,10 @@ NSString *baseURL, *url, *name; MAPIStoreUserContext *userContext; - baseURL = [NSString stringWithFormat: @"sogo://%@@fallback/", userName]; + baseURL = [NSString stringWithFormat: @"sogo://%@@fallback/", + [userName stringByReplacingOccurrencesOfString: @"@" + withString: @"%40"]]; + context = talloc_zero (memCtx, struct mapistore_contexts_list); context->url = [baseURL asUnicodeInMemCtx: context]; @@ -99,7 +102,10 @@ forUser: (NSString *) userName { return [NSString stringWithFormat: @"sogo://%@@fallback/0x%.16"PRIx64"/", - userName, (unsigned long long) fid]; + [userName stringByReplacingOccurrencesOfString: @"@" + withString: @"%40"], + (unsigned long long) fid]; + } @end diff --git a/OpenChange/MAPIStoreGCSBaseContext.m b/OpenChange/MAPIStoreGCSBaseContext.m index 216eab01c..384859c5d 100644 --- a/OpenChange/MAPIStoreGCSBaseContext.m +++ b/OpenChange/MAPIStoreGCSBaseContext.m @@ -82,7 +82,9 @@ andTDBIndexing: indexing]; parentFolder = [[userContext rootFolders] objectForKey: moduleName]; baseUrl = [NSString stringWithFormat: @"sogo://%@@%@/", - userName, moduleName]; + [userName stringByReplacingOccurrencesOfString: @"@" + withString: @"%40"], + moduleName]; subfolders = [parentFolder subFolders]; max = [subfolders count]; @@ -127,7 +129,9 @@ if (![parentFolder newFolderWithName: folderName nameInContainer: &nameInContainer]) mapistoreURI = [NSString stringWithFormat: @"sogo://%@@%@/%@/", - userName, moduleName, nameInContainer]; + [userName stringByReplacingOccurrencesOfString: @"@" + withString: @"%40"], + moduleName, nameInContainer]; else mapistoreURI = nil; [MAPIApp setUserContext: nil]; diff --git a/OpenChange/MAPIStoreMailContext.m b/OpenChange/MAPIStoreMailContext.m index 0cddee582..87493ff09 100644 --- a/OpenChange/MAPIStoreMailContext.m +++ b/OpenChange/MAPIStoreMailContext.m @@ -126,7 +126,11 @@ MakeDisplayFolderName (NSString *folderName) trashName = [NSString stringWithFormat: @"folder%@", [unprefixedFolders componentsJoinedByString: @"/folder"]]; - urlBase = [NSString stringWithFormat: @"sogo://%@:%@@mail/", userName, userName]; + urlBase = [NSString stringWithFormat: @"sogo://%@:%@@mail/", + [userName stringByReplacingOccurrencesOfString: @"@" + withString: @"%40"], + [userName stringByReplacingOccurrencesOfString: @"@" + withString: @"%40"]]; for (count = 0; count < 3; count++) { context = talloc_zero (memCtx, struct mapistore_contexts_list); @@ -199,7 +203,10 @@ MakeDisplayFolderName (NSString *folderName) inContainer: accountFolder]; if ([newFolder create]) mapistoreURI = [NSString stringWithFormat: @"sogo://%@:%@@mail/%@/", - userName, userName, + [userName stringByReplacingOccurrencesOfString: @"@" + withString: @"%40"], + [userName stringByReplacingOccurrencesOfString: @"@" + withString: @"%40"], [[folderName stringByEncodingImap4FolderName] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]]; else mapistoreURI = nil; @@ -275,8 +282,12 @@ MakeDisplayFolderName (NSString *folderName) componentsSeparatedByString: @"/"]; folderName = [NSString stringWithFormat: @"folder%@", [unprefixedFolders componentsJoinedByString: @"/folder"]]; - url = [NSString stringWithFormat: @"sogo://%@:%@@outbox/%@", userName, - userName, folderName]; + url = [NSString stringWithFormat: @"sogo://%@:%@@outbox/%@", + [userName stringByReplacingOccurrencesOfString: @"@" + withString: @"%40"], + [userName stringByReplacingOccurrencesOfString: @"@" + withString: @"%40"], + folderName]; context = talloc_zero (memCtx, struct mapistore_contexts_list); context->url = [url asUnicodeInMemCtx: context]; diff --git a/OpenChange/MAPIStoreNotesContext.m b/OpenChange/MAPIStoreNotesContext.m index 594a819b5..725b0d158 100644 --- a/OpenChange/MAPIStoreNotesContext.m +++ b/OpenChange/MAPIStoreNotesContext.m @@ -45,7 +45,8 @@ context = talloc_zero(memCtx, struct mapistore_contexts_list); context->url = talloc_asprintf (context, "sogo://%s@notes/", - [userName UTF8String]); + [[userName stringByReplacingOccurrencesOfString: @"@" + withString: @"%40"] UTF8String]); // context->name = "Notes personnelles"; context->main_folder = true; context->role = MAPISTORE_NOTES_ROLE; diff --git a/OpenChange/MAPIStoreSOGo.m b/OpenChange/MAPIStoreSOGo.m index 923541764..56d9cd4d0 100644 --- a/OpenChange/MAPIStoreSOGo.m +++ b/OpenChange/MAPIStoreSOGo.m @@ -1693,7 +1693,10 @@ sogo_manager_generate_uri (TALLOC_CTX *mem_ctx, username = [NSString stringWithUTF8String: (user ? user : "*")]; /* Do proper directory lookup here */ directory = [NSString stringWithUTF8String: (folder ? folder : "*")]; - partialURLString = [NSString stringWithFormat: @"sogo://%@:*@%@", username, directory]; + partialURLString = [NSString stringWithFormat: @"sogo://%@:*@%@", + [username stringByReplacingOccurrencesOfString: @"@" + withString: @"%40"], + directory]; } if (![partialURLString hasSuffix: @"/"]) partialURLString = [partialURLString stringByAppendingString: @"/"]; From d5d97db8e8d64ddbc0797325ce023723fd1227bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Fri, 16 Jan 2015 00:02:01 +0100 Subject: [PATCH 051/120] oc: PT_SYSTIME is an absolute timestamp As the epoch is in UTC timezone, we set this timezone for NSCalendarDate. --- OpenChange/MAPIStoreObject.m | 16 ---------------- OpenChange/MAPIStoreTypes.m | 1 + 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/OpenChange/MAPIStoreObject.m b/OpenChange/MAPIStoreObject.m index 1c4b26be4..ecb00dba3 100644 --- a/OpenChange/MAPIStoreObject.m +++ b/OpenChange/MAPIStoreObject.m @@ -23,7 +23,6 @@ #import #import #import -#import #import #import #import @@ -245,13 +244,8 @@ static Class NSExceptionK, MAPIStoreFolderK; struct SPropValue *cValue; NSUInteger counter; NSMutableDictionary *newProperties; - NSTimeZone *tz; - NSInteger tzOffset; id value; - tz = nil; - tzOffset = 0; - newProperties = [NSMutableDictionary dictionaryWithCapacity: aRow->cValues]; for (counter = 0; counter < aRow->cValues; counter++) { @@ -268,16 +262,6 @@ static Class NSExceptionK, MAPIStoreFolderK; @"attempting to set string property as PR_STRING8: %.8x", cValue->ulPropTag]; break; - case PT_SYSTIME: - if (!tz) - { - tz = [[self userContext] timeZone]; - tzOffset = -[tz secondsFromGMT]; - } - value = [value addYear: 0 month: 0 day: 0 - hour: 0 minute: 0 second: tzOffset]; - [value setTimeZone: tz]; - break; } [newProperties setObject: value forKey: MAPIPropertyKey (cValue->ulPropTag)]; diff --git a/OpenChange/MAPIStoreTypes.m b/OpenChange/MAPIStoreTypes.m index 01b650463..76e72c5d6 100644 --- a/OpenChange/MAPIStoreTypes.m +++ b/OpenChange/MAPIStoreTypes.m @@ -119,6 +119,7 @@ NSObjectFromMAPISPropValue (const struct mapi_SPropValue *value) break; case PT_SYSTIME: result = [NSCalendarDate dateFromFileTime: &(value->value.ft)]; + [result setTimeZone: utcTZ]; break; case PT_BINARY: case PT_SVREID: From c6b976a83077b94b043d38b4e1bb7c16ccbc1898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Fri, 16 Jan 2015 00:06:11 +0100 Subject: [PATCH 052/120] oc-mail: Remove unnecessary time shift in date for new mails The MIME type can store the date in UTC and the clients are responsible on showing correctly to the client as it does. --- OpenChange/MAPIStoreMailVolatileMessage.m | 3 --- 1 file changed, 3 deletions(-) diff --git a/OpenChange/MAPIStoreMailVolatileMessage.m b/OpenChange/MAPIStoreMailVolatileMessage.m index 55d62309e..6c340a721 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.m +++ b/OpenChange/MAPIStoreMailVolatileMessage.m @@ -29,7 +29,6 @@ #import #import #import -#import #import #import #import @@ -673,8 +672,6 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers, date = [mailProperties objectForKey: MAPIPropertyKey (PR_CLIENT_SUBMIT_TIME)]; if (date) { - date = [date addYear: 0 month: 0 day: 0 - hour: 0 minute: 0 second: [[date timeZone] secondsFromGMT]]; [headers addObject: [date rfc822DateString] forKey: @"date"]; } [headers addObject: @"1.0" forKey: @"MIME-Version"]; From c893963da592bc56d0d95b7c18e7085907a9fdeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Fri, 16 Jan 2015 00:09:01 +0100 Subject: [PATCH 053/120] oc-tasks: Set right start, due and complete dates As explained in [MS-OXOTASK], we have to shift the given date to store the right point in time with the correct timezone. --- OpenChange/MAPIStoreTasksMessage.m | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/OpenChange/MAPIStoreTasksMessage.m b/OpenChange/MAPIStoreTasksMessage.m index 9215bc409..20bf67f8b 100644 --- a/OpenChange/MAPIStoreTasksMessage.m +++ b/OpenChange/MAPIStoreTasksMessage.m @@ -367,13 +367,15 @@ NSString *status, *priority, *tzName; NSCalendarDate *now; NSInteger tzOffset; + NSTimeZone *userTZ; double doubleValue; vToDo = [sogoObject component: YES secure: NO]; vCalendar = [vToDo parent]; [vCalendar setProdID: @"-//Inverse inc.//OpenChange+SOGo//EN"]; - tzName = [[[self userContext] timeZone] name]; + userTZ = [[self userContext] timeZone]; + tzName = [userTZ name]; tz = [iCalTimeZone timeZoneForName: tzName]; [vCalendar addTimeZone: tz]; @@ -428,6 +430,13 @@ { date = (iCalDateTime *) [vToDo uniqueChildWithTag: @"dtstart"]; [date setTimeZone: tz]; + /* The property is set to user's local time zone. + See: [MS-OXOTASK] 2.2.2.2.4 + TODO: Ignore when the PT_SYSTIME is 0x5AE980E0*/ + tzOffset = [userTZ secondsFromGMTForDate: value]; + value = [value dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: -tzOffset]; [date setDateTime: value]; } @@ -437,6 +446,13 @@ { date = (iCalDateTime *) [vToDo uniqueChildWithTag: @"due"]; [date setTimeZone: tz]; + /* The property is set to user's local time zone. + See: [MS-OXOTASK] 2.2.2.2.5 + TODO: Ignore when the PT_SYSTIME is 0x5AE980E0*/ + tzOffset = [userTZ secondsFromGMTForDate: value]; + value = [value dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: -tzOffset]; [date setDateTime: value]; } @@ -445,7 +461,9 @@ if (value) { date = (iCalDateTime *) [vToDo uniqueChildWithTag: @"completed"]; - tzOffset = [[value timeZone] secondsFromGMTForDate: value]; + /* The property is set to midnight in local time zone converted to UTC: + See: [MS-OXOTASK] 2.2.2.2.9 */ + tzOffset = [userTZ secondsFromGMTForDate: value]; value = [value dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: -tzOffset]; From 8b44c08a32375b8386b24d518e3fdc0b906ec3cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Fri, 16 Jan 2015 00:12:24 +0100 Subject: [PATCH 054/120] oc-calendar: Remove unnecessary shifts on start,end and replace time props As the data is sent in UTC, no shifts are longer required. --- OpenChange/iCalEvent+MAPIStore.m | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/OpenChange/iCalEvent+MAPIStore.m b/OpenChange/iCalEvent+MAPIStore.m index 40eb0c0ef..c5c70a686 100644 --- a/OpenChange/iCalEvent+MAPIStore.m +++ b/OpenChange/iCalEvent+MAPIStore.m @@ -207,16 +207,7 @@ value = [properties objectForKey: MAPIPropertyKey (PidLidExceptionReplaceTime)]; if (value) - { - if (!isAllDay) - { - tzOffset = [userTimeZone secondsFromGMTForDate: value]; - value = [value dateByAddingYears: 0 months: 0 days: 0 - hours: 0 minutes: 0 - seconds: tzOffset]; - } - [self setRecurrenceId: value]; - } + [self setRecurrenceId: value]; // start value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentStartWhole)]; @@ -241,13 +232,7 @@ [start setTimeZone: nil]; } else - { - tzOffset = [userTimeZone secondsFromGMTForDate: value]; - value = [value dateByAddingYears: 0 months: 0 days: 0 - hours: 0 minutes: 0 - seconds: tzOffset]; [start setDateTime: value]; - } } /* end */ @@ -273,13 +258,7 @@ [end setTimeZone: nil]; } else - { - tzOffset = [[value timeZone] secondsFromGMTForDate: value]; - value = [value dateByAddingYears: 0 months: 0 days: 0 - hours: 0 minutes: 0 - seconds: tzOffset]; [end setDateTime: value]; - } } /* priority */ From 99a36be03403ced16f6c3952a4086252fdc3f7e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Wed, 21 Jan 2015 12:44:31 +0100 Subject: [PATCH 055/120] oc: Remove a source folder on move folder operation Calling deleteFolder message to actually remove it from DB/IMAP depending on the class. --- OpenChange/MAPIStoreFolder.m | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index a939b9610..5aa59f8c4 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -449,16 +449,11 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe return rc; } -- (void) deleteFolderImpl +- (int) deleteFolder { // TODO: raise exception in case underlying delete fails? // [propsMessage delete]; [dbFolder delete]; -} - -- (int) deleteFolder -{ - [self deleteFolderImpl]; [self cleanupCaches]; @@ -924,7 +919,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe { fmid = [mapping idFromURL: [self url]]; [mapping unregisterURLWithID: fmid]; - [self deleteFolderImpl]; + [self deleteFolder]; [mapping registerURL: [newFolder url] withID: fmid]; } From 8e7f6d1aec1ebf05afe3330447cea4cf6797d3a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Fri, 23 Jan 2015 18:15:44 +0100 Subject: [PATCH 056/120] oc: avoid change number leaking when refreshing folder. Everytime a folder where its last operation was delete some email was requesting change numbers that were not used. --- OpenChange/MAPIStoreMailFolder.m | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 57679c1f1..3d85f3e62 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -637,16 +637,18 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) fetchResults = [(SOGoMailFolder *) sogoObject fetchUIDsOfVanishedItems: lastModseqNbr]; max = [fetchResults count]; - changeNumbers = [[self context] getNewChangeNumbers: max]; + changeNumber = nil; for (count = 0; count < max; count++) { uid = [[fetchResults objectAtIndex: count] stringValue]; if ([messages objectForKey: uid]) { - newChangeNum = [[changeNumbers objectAtIndex: count] - unsignedLongLongValue]; - changeNumber = [NSString stringWithUnsignedLongLong: newChangeNum]; + if (!changeNumber) + { + newChangeNum = [[self context] getNewChangeNumber]; + changeNumber = [NSString stringWithUnsignedLongLong: newChangeNum]; + } [messages removeObjectForKey: uid]; [self logWithFormat: @"Removed message entry for UID %@", uid]; } From 34efcfee4e4bc593d01efe64c0db2b7e20b1a994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Fri, 23 Jan 2015 18:17:45 +0100 Subject: [PATCH 057/120] oc: synchroniseCache store modseq for last delete change number. This will be the more frequent change number used to obtain updates on the folder related with deleted messages --- OpenChange/MAPIStoreMailFolder.m | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 3d85f3e62..11af956b2 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -661,6 +661,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) { [currentProperties setObject: changeNumber forKey: @"SyncLastDeleteChangeNumber"]; + [mapping setObject: lastModseq forKey: changeNumber]; foundChange = YES; } } From 47be392d4f92c6afb1954244fe52cc4344c2ae1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Fri, 23 Jan 2015 18:18:25 +0100 Subject: [PATCH 058/120] oc: avoid request change number until necessary Minor changenumber leak, but avoid it anyway --- OpenChange/MAPIStoreMailFolder.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 11af956b2..38e54b7af 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -762,7 +762,6 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) messageEntry = [messages objectForKey: messageUID]; if (!messageEntry) { - changeNumber = [[self context] getNewChangeNumber]; fetchResults = [(NSDictionary *) [sogoObject fetchUIDs: [NSArray arrayWithObject: messageUID] parts: [NSArray arrayWithObject: @"modseq"]] objectForKey: @"fetch"]; @@ -770,6 +769,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) { result = [fetchResults objectAtIndex: 0]; modseq = [result objectForKey: @"modseq"]; + changeNumber = [[self context] getNewChangeNumber]; changeNumberStr = [NSString stringWithUnsignedLongLong: changeNumber]; /* Create new message entry in Messages dict */ From 312084243b664932f55457738b30bc345457f5a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Fri, 23 Jan 2015 18:19:24 +0100 Subject: [PATCH 059/120] oc: improve modseqFromMessageChangeNumber to return an approximation. Only for scenarios where we hadn't store the cn <-> modseq relationship --- OpenChange/MAPIStoreMailFolder.m | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 38e54b7af..8c3983f7e 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -802,13 +802,43 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) return YES; } + - (NSNumber *) modseqFromMessageChangeNumber: (NSString *) changeNum { NSDictionary *mapping; NSNumber *modseq; + NSEnumerator *enumerator; + id key; + uint64_t found, target, current, replica_id, current_cn; + NSString *closestChangeNum; mapping = [[versionsMessage properties] objectForKey: @"VersionMapping"]; modseq = [mapping objectForKey: changeNum]; + if (modseq) return modseq; + + // Not found from stored change numbers for this folder. + // Get the closest modseq for the change number given. + // O(n) cost but will be unusual behaviour. + target = exchange_globcnt([changeNum unsignedLongLongValue] >> 16); + replica_id = [changeNum unsignedLongLongValue] & 0xFFFF; + found = 0; + enumerator = [mapping keyEnumerator]; + while ((key = [enumerator nextObject])) + { + current_cn = [(NSString *)key unsignedLongLongValue]; + if ((current_cn & 0xFFFF) != replica_id) + continue; + current = exchange_globcnt(current_cn >> 16); + if (current < target && current > found) + found = current; + } + + if (found) + { + closestChangeNum = [NSString stringWithUnsignedLongLong: + (exchange_globcnt(found) << 16 | replica_id)]; + modseq = [mapping objectForKey: closestChangeNum]; + } return modseq; } From 0e8bf0d2390c848154de4f9c9fa864b7c4b03002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Mon, 26 Jan 2015 15:55:22 +0100 Subject: [PATCH 060/120] oc-mail: Move mail folders with reserved chars The URL was incorrectly set when any of ;/?:@&=+$,# was used in the folder name. We have to mimetise what it is done in createFolder message selector. That is, perform the IMAP4 encoding + URL encoding without CSS encoding. The IMAP4 + CSS encoding (without URL encoding) is used to store the folder in SOGo and OpenChange Indexing database as we do right now. --- OpenChange/MAPIStoreMailFolder.m | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 57679c1f1..5c93e11d2 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -1217,7 +1217,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) NGImap4Connection *connection; NGImap4Client *client; NSString *newURL, *parentDBFolderPath, *childKey, *folderIMAPName, - *urlNamePart, *newFolderIMAPName; + *urlNamePart, *newFolderIMAPName, *newFolderDBName; NSException *error; MAPIStoreMapping *mapping; NSDictionary *result; @@ -1230,7 +1230,8 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) targetSOGoFolder = [targetFolder sogoObject]; if (isMove) { - urlNamePart = [newFolderName stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; + /* Mimetise [SOGoMailFolderK imap4URLString] */ + urlNamePart = [[newFolderName stringByEncodingImap4FolderName] stringByEscapingURL]; newFolderURL = [NSURL URLWithString: urlNamePart relativeToURL: [targetSOGoFolder imap4URL]]; error = [[sogoObject imap4Connection] @@ -1242,8 +1243,9 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) { rc = MAPISTORE_SUCCESS; mapping = [self mapping]; + newFolderDBName = [[newFolderName stringByEncodingImap4FolderName] asCSSIdentifier]; newURL = [NSString stringWithFormat: @"%@folder%@/", - [targetFolder url], urlNamePart]; + [targetFolder url], newFolderDBName]; [mapping updateID: [self objectId] withURL: newURL]; parentDBFolderPath = [[targetFolder dbFolder] path]; if (!parentDBFolderPath) @@ -1251,7 +1253,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) [dbFolder changePathTo: [NSString stringWithFormat: @"%@/folder%@", parentDBFolderPath, - newFolderName]]; + newFolderDBName]]; } } else From b01de763dafde3d8b7f083b53814ba9a074b4541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Tue, 27 Jan 2015 18:27:11 +0100 Subject: [PATCH 061/120] oc: Move back and forth folders now are in sync Two different indexing entries were created on move operation making impossible to restore old folder position in the original parent folder. This was due to cleanupCaches message calls to objectId which requires to have the indexing entry available. Use case: * Restore a folder from "Deleted items" folders --- OpenChange/MAPIStoreFolder.m | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index 5aa59f8c4..19c826d7f 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -916,16 +916,23 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe } if (isMove) - { - fmid = [mapping idFromURL: [self url]]; - [mapping unregisterURLWithID: fmid]; [self deleteFolder]; - [mapping registerURL: [newFolder url] - withID: fmid]; - } + [targetFolder cleanupCaches]; } [self cleanupCaches]; + + /* We perform the mapping operations at the + end as objectId is required to be available + until the caches are cleaned up */ + if (isMove && rc == MAPISTORE_SUCCESS) + { + fmid = [mapping idFromURL: [self url]]; + [mapping unregisterURLWithID: fmid]; + [mapping registerURL: [newFolder url] + withID: fmid]; + } + } else rc = MAPISTORE_ERR_DENIED; From 57d591c427b2d7897bcd57717545d6aea2084381 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Wed, 28 Jan 2015 11:26:56 +0100 Subject: [PATCH 062/120] oc: Set right container in dbFolder when moving a folder The path attribute from SOGoCacheGCSFolder is properly updated in the database but not when returning from path message as the container is the old one. --- OpenChange/MAPIStoreDBFolder.m | 3 ++- OpenChange/MAPIStoreMailFolder.m | 3 ++- SoObjects/SOGo/SOGoCacheGCSFolder.h | 2 ++ SoObjects/SOGo/SOGoCacheGCSFolder.m | 8 ++++++++ SoObjects/SOGo/SOGoObject.h | 2 ++ 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/OpenChange/MAPIStoreDBFolder.m b/OpenChange/MAPIStoreDBFolder.m index ec7207062..798af041b 100644 --- a/OpenChange/MAPIStoreDBFolder.m +++ b/OpenChange/MAPIStoreDBFolder.m @@ -152,7 +152,8 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; targetPath = [[targetFolder sogoObject] path]; newPath = [NSString stringWithFormat: @"%@/%@", targetPath, pathComponent]; - [dbFolder changePathTo: newPath]; + [dbFolder changePathTo: newPath + intoNewContainer: [targetFolder dbFolder]]; mapping = [self mapping]; newURL = [NSString stringWithFormat: @"%@%@/", diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index b8fae1e71..69f235783 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -1286,7 +1286,8 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) [dbFolder changePathTo: [NSString stringWithFormat: @"%@/folder%@", parentDBFolderPath, - newFolderDBName]]; + newFolderDBName] + intoNewContainer: [targetFolder dbFolder]]; } } else diff --git a/SoObjects/SOGo/SOGoCacheGCSFolder.h b/SoObjects/SOGo/SOGoCacheGCSFolder.h index 1b63ae683..3495dc0d6 100644 --- a/SoObjects/SOGo/SOGoCacheGCSFolder.h +++ b/SoObjects/SOGo/SOGoCacheGCSFolder.h @@ -49,6 +49,8 @@ andSortOrderings: (NSArray *) sortOrderings; - (void) changePathTo: (NSString *) newPath; +- (void) changePathTo: (NSString *) newPath + intoNewContainer: (id) newContainer; @end diff --git a/SoObjects/SOGo/SOGoCacheGCSFolder.m b/SoObjects/SOGo/SOGoCacheGCSFolder.m index f8d25d381..b29287fcb 100644 --- a/SoObjects/SOGo/SOGoCacheGCSFolder.m +++ b/SoObjects/SOGo/SOGoCacheGCSFolder.m @@ -308,6 +308,14 @@ Class SOGoCacheGCSObjectK = Nil; [super changePathTo: newPath]; } +- (void) changePathTo: (NSString *) newPath intoNewContainer: (id) newContainer +{ + [self changePathTo: newPath]; + container = newContainer; + if ([self doesRetainContainer]) + [container retain]; +} + // - (NSArray *) toOneRelationshipKeysMatchingQualifier: (EOQualifier *) qualifier // andSortOrderings: (NSArray *) sortOrderings // { diff --git a/SoObjects/SOGo/SOGoObject.h b/SoObjects/SOGo/SOGoObject.h index 114b0c55d..dafd5f06e 100644 --- a/SoObjects/SOGo/SOGoObject.h +++ b/SoObjects/SOGo/SOGoObject.h @@ -82,6 +82,8 @@ - (BOOL) isInPublicZone; +- (BOOL) doesRetainContainer; + /* accessors */ - (void) setContext: (WOContext *) newContext; From 5258ee2e76e85d053917fb52f1c1954a162e54de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Tue, 27 Jan 2015 19:07:26 +0100 Subject: [PATCH 063/120] oc-appointments: ignore alarms already triggered --- OpenChange/MAPIStoreAppointmentWrapper.m | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index f459462be..c6fc58c8a 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -1835,16 +1835,25 @@ ReservedBlockEE2Size: 00 00 00 00 NSArray *alarms; NSUInteger count, max; iCalAlarm *currentAlarm; - NSString *action; + NSString *action, *webstatus; alarms = [event alarms]; max = [alarms count]; for (count = 0; !alarm && count < max; count++) { currentAlarm = [alarms objectAtIndex: count]; - action = [[currentAlarm action] lowercaseString]; - if (!action || [action isEqualToString: @"display"]) - ASSIGN (alarm, currentAlarm); + + // Only handle 'display' alarms + action = [currentAlarm action]; + if ([action caseInsensitiveCompare: @"display"] != NSOrderedSame) + continue; + + // Ignore alarms already triggered + webstatus = [[currentAlarm trigger] value: 0 ofAttribute: @"x-webstatus"]; + if ([webstatus caseInsensitiveCompare: @"triggered"] == NSOrderedSame) + continue; + + ASSIGN (alarm, currentAlarm); } alarmSet = YES; From dc8012e3d34c76c2dbc4302361fdf02b6147ead6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Thu, 5 Feb 2015 23:48:46 +0100 Subject: [PATCH 064/120] oc-mail: Implement move a mail subfolder to root By moving at IMAP level the mailbox and update the indexing DB and local db path. --- OpenChange/MAPIStoreMailFolder.m | 57 +++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 69f235783..0a439e29e 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -1243,6 +1243,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) struct SRow folderRow; struct SPropValue nameProperty; MAPIStoreMailFolder *newFolder; + SOGoMailAccount *accountFolder; SOGoMailFolder *targetSOGoFolder; NSMutableArray *uids; NSArray *childKeys; @@ -1255,7 +1256,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) MAPIStoreMapping *mapping; NSDictionary *result; - if ([targetFolder isKindOfClass: MAPIStoreMailFolderK]) + if ([targetFolder isKindOfClass: MAPIStoreMailFolderK] || (!targetFolder && isMove)) { folderURL = [sogoObject imap4URL]; if (!newFolderName) @@ -1263,10 +1264,23 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) targetSOGoFolder = [targetFolder sogoObject]; if (isMove) { - /* Mimetise [SOGoMailFolderK imap4URLString] */ - urlNamePart = [[newFolderName stringByEncodingImap4FolderName] stringByEscapingURL]; - newFolderURL = [NSURL URLWithString: urlNamePart - relativeToURL: [targetSOGoFolder imap4URL]]; + newFolderDBName = [[newFolderName stringByEncodingImap4FolderName] asCSSIdentifier]; + if (targetSOGoFolder) + { + /* Mimetise [SOGoMailFolderK imap4URLString] */ + urlNamePart = [[newFolderName stringByEncodingImap4FolderName] stringByEscapingURL]; + newFolderURL = [NSURL URLWithString: urlNamePart + relativeToURL: [targetSOGoFolder imap4URL]]; + } + else + { + /* Mimetise what createRootSecondaryFolderWithFID does */ + accountFolder = [[[self userContext] rootFolders] objectForKey: @"mail"]; + targetSOGoFolder = [SOGoMailFolder objectWithName: [NSString stringWithFormat: @"folder%@", + newFolderDBName] + inContainer: accountFolder]; + newFolderURL = [targetSOGoFolder imap4URL]; + } error = [[sogoObject imap4Connection] moveMailboxAtURL: folderURL toURL: newFolderURL]; @@ -1276,18 +1290,29 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) { rc = MAPISTORE_SUCCESS; mapping = [self mapping]; - newFolderDBName = [[newFolderName stringByEncodingImap4FolderName] asCSSIdentifier]; - newURL = [NSString stringWithFormat: @"%@folder%@/", - [targetFolder url], newFolderDBName]; + if (targetFolder) + newURL = [NSString stringWithFormat: @"%@folder%@/", + [targetFolder url], newFolderDBName]; + else + newURL = [NSString stringWithFormat: @"sogo://%@:%@@mail/folder%@/", + [[self userContext] username], [[self userContext] username], + newFolderDBName]; [mapping updateID: [self objectId] withURL: newURL]; - parentDBFolderPath = [[targetFolder dbFolder] path]; - if (!parentDBFolderPath) - parentDBFolderPath = @""; - [dbFolder changePathTo: [NSString stringWithFormat: - @"%@/folder%@", - parentDBFolderPath, - newFolderDBName] - intoNewContainer: [targetFolder dbFolder]]; + if (targetFolder) + { + parentDBFolderPath = [[targetFolder dbFolder] path]; + if (!parentDBFolderPath) + parentDBFolderPath = @""; + [dbFolder changePathTo: [NSString stringWithFormat: + @"%@/folder%@", + parentDBFolderPath, + newFolderDBName] + intoNewContainer: [targetFolder dbFolder]]; + } + else + [dbFolder changePathTo: [NSString stringWithFormat: + @"/mail/folder%@", newFolderDBName] + intoNewContainer: nil]; } } else From 142deeb5f0ed97cbc78f7641a7c5141d30aefd70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Thu, 5 Feb 2015 23:49:59 +0100 Subject: [PATCH 065/120] oc: Implement move a DB subfolder to root DB folders are Notes and Fallback (Journal, InfoPath Form and Deleted Items). By moving the DB path and update the indexing DB. --- OpenChange/MAPIStoreDBFolder.m | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/OpenChange/MAPIStoreDBFolder.m b/OpenChange/MAPIStoreDBFolder.m index 798af041b..4dd7fbfd9 100644 --- a/OpenChange/MAPIStoreDBFolder.m +++ b/OpenChange/MAPIStoreDBFolder.m @@ -140,7 +140,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; pathComponent = nil; - if (isMove && [targetFolder isKindOfClass: MAPIStoreDBFolderK]) + if (isMove && ([targetFolder isKindOfClass: MAPIStoreDBFolderK] || !targetFolder)) { path = [sogoObject path]; slashRange = [path rangeOfString: @"/" options: NSBackwardsSearch]; @@ -149,15 +149,28 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; format: @"db folder path must start with a '/'"]; else pathComponent = [path substringFromIndex: slashRange.location + 1]; - targetPath = [[targetFolder sogoObject] path]; - newPath = [NSString stringWithFormat: @"%@/%@", - targetPath, pathComponent]; - [dbFolder changePathTo: newPath - intoNewContainer: [targetFolder dbFolder]]; + + if (targetFolder) + { + targetPath = [[targetFolder sogoObject] path]; + newPath = [NSString stringWithFormat: @"%@/%@", + targetPath, pathComponent]; + [dbFolder changePathTo: newPath + intoNewContainer: [targetFolder dbFolder]]; + } + else + [dbFolder changePathTo: [NSString stringWithFormat: @"/fallback/%@", pathComponent] + intoNewContainer: nil]; mapping = [self mapping]; - newURL = [NSString stringWithFormat: @"%@%@/", - [targetFolder url], pathComponent]; + + if (targetFolder) + newURL = [NSString stringWithFormat: @"%@%@/", + [targetFolder url], pathComponent]; + else + newURL = [NSString stringWithFormat: @"sogo://%@@fallback/%@/", + [[self userContext] username], pathComponent]; + [mapping updateID: [self objectId] withURL: newURL]; From 96986812f458922f012ccb7af3f149266d6ea93a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Sat, 7 Feb 2015 00:22:45 +0100 Subject: [PATCH 066/120] oc-mail: Set content type for a message after upgrading sope 2.2.15 Now that message headers can be set dynamically, we can set the body-related headers using `setHeader` selector. This fixes emails sent using this sope version are all in plain text. --- OpenChange/MAPIStoreMailVolatileMessage.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenChange/MAPIStoreMailVolatileMessage.m b/OpenChange/MAPIStoreMailVolatileMessage.m index 6c340a721..ed9fbf8d2 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.m +++ b/OpenChange/MAPIStoreMailVolatileMessage.m @@ -900,7 +900,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS messageBody = MakeMessageBody (properties, attachmentParts, &contentType); if (messageBody) { - [headers setObject: contentType forKey: @"content-type"]; + [message setHeader: contentType forKey: @"content-type"]; [message setBody: messageBody]; } From 68ebc9e0ff64f1baebbd9f5adbd38cfd1fcf0b76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Tue, 10 Feb 2015 23:34:51 +0100 Subject: [PATCH 067/120] oc: Use dlinklist from samba for now Due to https://github.com/openchange/openchange/pull/204. Until it is published by OC or dismissed. --- OpenChange/MAPIStoreContext.m | 1 + OpenChange/MAPIStoreFallbackContext.m | 1 + 2 files changed, 2 insertions(+) diff --git a/OpenChange/MAPIStoreContext.m b/OpenChange/MAPIStoreContext.m index 376a96623..fca045b17 100644 --- a/OpenChange/MAPIStoreContext.m +++ b/OpenChange/MAPIStoreContext.m @@ -51,6 +51,7 @@ #import "MAPIStoreContext.h" #undef DEBUG +#include #include #include #include diff --git a/OpenChange/MAPIStoreFallbackContext.m b/OpenChange/MAPIStoreFallbackContext.m index 5b1a40ad1..1555226d5 100644 --- a/OpenChange/MAPIStoreFallbackContext.m +++ b/OpenChange/MAPIStoreFallbackContext.m @@ -30,6 +30,7 @@ #undef DEBUG #include +#include #include @implementation MAPIStoreFallbackContext From d3a4b497c69c39de6130cd5861d0f43e5a91614e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Sun, 15 Feb 2015 18:34:28 +0100 Subject: [PATCH 068/120] oc-calendar: Remove commented code Available at MAPIStoreAppointmentWrapper class --- OpenChange/MAPIStoreCalendarMessage.m | 79 --------------------------- 1 file changed, 79 deletions(-) diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index de89eb487..bc4b33136 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -333,85 +333,6 @@ static Class NSArrayK; *dataPtr = msgData; } -/* sender representing */ -// - (int) getPidTagSentRepresentingEmailAddress: (void **) data -// inMemCtx: (TALLOC_CTX *) memCtx -// { -// return [self getPidTagSenderEmailAddress: data inMemCtx: memCtx]; -// } - -// - (int) getPidTagSentRepresentingAddressType: (void **) data -// inMemCtx: (TALLOC_CTX *) memCtx -// { -// return [self getSMTPAddrType: data inMemCtx: memCtx]; -// } - -// - (int) getPidTagSentRepresentingName: (void **) data -// inMemCtx: (TALLOC_CTX *) memCtx -// { -// return [self getPidTagSenderName: data inMemCtx: memCtx]; -// } - -// - (int) getPidTagSentRepresentingEntryId: (void **) data -// inMemCtx: (TALLOC_CTX *) memCtx -// { -// return [self getPidTagSenderEntryId: data inMemCtx: memCtx]; -// } - -/* attendee */ -// - (int) getPidTagReceivedByAddressType: (void **) data -// inMemCtx: (TALLOC_CTX *) memCtx -// { -// return [appointmentWrapper getPidTagReceivedByAddressType: data -// inMemCtx: memCtx]; -// } - -// - (int) getPidTagReceivedByEmailAddress: (void **) data -// inMemCtx: (TALLOC_CTX *) memCtx -// { -// return [appointmentWrapper getPidTagReceivedByEmailAddress: data -// inMemCtx: memCtx]; -// } - -// - (int) getPidTagReceivedByName: (void **) data -// inMemCtx: (TALLOC_CTX *) memCtx -// { -// return [appointmentWrapper getPidTagReceivedByName: data -// inMemCtx: memCtx]; -// } - -// - (int) getPidTagReceivedByEntryId: (void **) data -// inMemCtx: (TALLOC_CTX *) memCtx -// { -// return [appointmentWrapper getPidTagReceivedByEntryId: data -// inMemCtx: memCtx]; -// } - -// /* attendee representing */ -// - (int) getPidTagReceivedRepresentingEmailAddress: (void **) data -// inMemCtx: (TALLOC_CTX *) memCtx -// { -// return [self getPidTagReceivedByEmailAddress: data inMemCtx: memCtx]; -// } - -// - (int) getPidTagReceivedRepresentingAddressType: (void **) data -// inMemCtx: (TALLOC_CTX *) memCtx -// { -// return [self getSMTPAddrType: data inMemCtx: memCtx]; -// } - -// - (int) getPidTagReceivedRepresentingName: (void **) data -// inMemCtx: (TALLOC_CTX *) memCtx -// { -// return [self getPidTagReceivedByName: data inMemCtx: memCtx]; -// } - -// - (int) getPidTagReceivedRepresentingEntryId: (void **) data -// inMemCtx: (TALLOC_CTX *) memCtx -// { -// return [self getPidTagReceivedByEntryId: data inMemCtx: memCtx]; -// } - - (int) getPidTagResponseRequested: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { From eaec3c061074ff7bf42bc54569acb8f066243a9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Sun, 15 Feb 2015 18:38:59 +0100 Subject: [PATCH 069/120] oc-calendar: Remove useless method Better off implemented by AppointmentWrapper proxy --- OpenChange/MAPIStoreCalendarMessage.m | 3 --- 1 file changed, 3 deletions(-) diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index bc4b33136..53de64b51 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -206,10 +206,7 @@ static Class NSArrayK; } /* getters */ -- (int) getPidLidFInvited: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx { - return [self getYes: data inMemCtx: memCtx]; } - (int) getPidTagMessageClass: (void **) data From 2a1b363feedf77f1bcc1c848d8468d93817d7023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Sun, 15 Feb 2015 18:39:43 +0100 Subject: [PATCH 070/120] oc-calendar: Proper getter for AppointmentWrapper proxy object Do not assume it is in 0 position any longer --- OpenChange/MAPIStoreCalendarMessage.m | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index 53de64b51..b5d65678c 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -81,7 +81,7 @@ // extern void ndr_print_AppointmentRecurrencePattern(struct ndr_print *ndr, const char *name, const struct AppointmentRecurrencePattern *r); -static Class NSArrayK; +static Class NSArrayK, MAPIStoreAppointmentWrapperK; @implementation SOGoAppointmentObject (MAPIStoreExtension) @@ -97,6 +97,7 @@ static Class NSArrayK; + (void) initialize { NSArrayK = [NSArray class]; + MAPIStoreAppointmentWrapperK = [MAPIStoreAppointmentWrapper class]; } + (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP @@ -205,10 +206,23 @@ static Class NSArrayK; [super dealloc]; } -/* getters */ +- (MAPIStoreAppointmentWrapper *) _appointmentWrapper { + NSUInteger i, max; + id proxy; + max = [proxies count]; + for (i = 0; i < max; i++) { + proxy = [proxies objectAtIndex: i]; + if ([proxy isKindOfClass: MAPIStoreAppointmentWrapperK]) + { + return proxy; + } + } + return nil; } + +/* getters */ - (int) getPidTagMessageClass: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -321,10 +335,8 @@ static Class NSArrayK; } else { - /* HACK: we know the first (and only) proxy is our appointment wrapper - instance, but this might not always be true */ - [[proxies objectAtIndex: 0] fillMessageData: msgData - inMemCtx: memCtx]; + [[self _appointmentWrapper] fillMessageData: msgData + inMemCtx: memCtx]; } *dataPtr = msgData; From e6ba15bbae0633bf4a8bbd327a1578217cb2128f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Sun, 15 Feb 2015 18:41:03 +0100 Subject: [PATCH 071/120] oc-calendar: PidTagImportance and PidTagNormalizedSubject working It wasn't being called because the proxy (AppointmentWrapper) is not being called as there is a base implementation for these properties in MAPIStoreMessage making them impossible to be shared between Outlook profiles. --- OpenChange/MAPIStoreCalendarMessage.m | 32 +++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index b5d65678c..73684df3d 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -348,6 +348,38 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK; return [self getYes: data inMemCtx: memCtx]; } +/* This three methods: getPidTagNormalizedSubject, + getPidTagSensitivity and getPidTagImportance are implemented in + MAPIStoreMessage base class, then the proxy method is not reached + (see MAPIStoreObject). +*/ +- (int) getPidTagNormalizedSubject: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + MAPIStoreAppointmentWrapper *appointmentWrapper; + + appointmentWrapper = [self _appointmentWrapper]; + if (appointmentWrapper) + return [appointmentWrapper getPidTagNormalizedSubject: data inMemCtx: memCtx]; + + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidTagImportance: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + MAPIStoreAppointmentWrapper *appointmentWrapper; + + appointmentWrapper = [self _appointmentWrapper]; + if (appointmentWrapper) + return [appointmentWrapper getPidTagImportance: data inMemCtx: memCtx]; + + *data = MAPILongValue (memCtx, 1); + + return MAPISTORE_SUCCESS; +} + + - (NSString *) _uidFromGlobalObjectId: (TALLOC_CTX *) memCtx { NSData *objectId; From 624967c60b5d4c2bb23051f6995e323163f0c12d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Sun, 15 Feb 2015 18:44:47 +0100 Subject: [PATCH 072/120] oc-calendar: Implement PidTagSensitivity As described in [MS-OXCICAL] Section 2.1.3.11.20.4 by using access CLASS iCal field. Although Outlook does not support confidential level, it is properly exported and imported. --- OpenChange/MAPIStoreAppointmentWrapper.m | 26 +++++++++++++++++++++--- OpenChange/MAPIStoreCalendarMessage.m | 12 +++++++++++ OpenChange/MAPIStoreMessage.m | 2 +- OpenChange/iCalEvent+MAPIStore.m | 26 +++++++++++++++++++++++- 4 files changed, 61 insertions(+), 5 deletions(-) diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index c6fc58c8a..3f3708915 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -1200,11 +1200,31 @@ static NSCharacterSet *hexCharacterSet = nil; return [self getYes: data inMemCtx: memCtx]; } -- (int) getPidTagSensitivity: (void **) data // not implemented, depends on CLASS +- (int) getPidTagSensitivity: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - // normal = 0, personal?? = 1, private = 2, confidential = 3 - return [self getLongZero: data inMemCtx: memCtx]; + /* See [MS-OXCICAL] Section 2.1.3.11.20.4 */ + uint32_t v; + NSString *accessClass; + + accessClass = [event accessClass]; + if (accessClass) + { + if ([accessClass isEqualToString: @"X-PERSONAL"]) + v = 0x1; + else if ([accessClass isEqualToString: @"PRIVATE"]) + v = 0x2; + else if ([accessClass isEqualToString: @"CONFIDENTIAL"]) + v = 0x3; + else + v = 0x0; /* PUBLIC */ + } + else + v = 0x0; /* PUBLIC */ + + *data = MAPILongValue (memCtx, v); + + return MAPISTORE_SUCCESS; } - (int) getPidTagImportance: (void **) data diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index 73684df3d..290a50bcd 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -365,6 +365,18 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK; return MAPISTORE_ERR_NOT_FOUND; } +- (int) getPidTagSensitivity: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + MAPIStoreAppointmentWrapper *appointmentWrapper; + + appointmentWrapper = [self _appointmentWrapper]; + if (appointmentWrapper) + return [appointmentWrapper getPidTagSensitivity: data inMemCtx: memCtx]; + + return [self getLongZero: data inMemCtx: memCtx]; +} + - (int) getPidTagImportance: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { diff --git a/OpenChange/MAPIStoreMessage.m b/OpenChange/MAPIStoreMessage.m index 2c5707158..e922d4a18 100644 --- a/OpenChange/MAPIStoreMessage.m +++ b/OpenChange/MAPIStoreMessage.m @@ -784,7 +784,7 @@ rtf2html (NSData *compressedRTF) return [self getLongZero: data inMemCtx: memCtx]; } -- (int) getPidTagSensitivity: (void **) data // TODO -> subclass in calendar +- (int) getPidTagSensitivity: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self getLongZero: data inMemCtx: memCtx]; diff --git a/OpenChange/iCalEvent+MAPIStore.m b/OpenChange/iCalEvent+MAPIStore.m index c5c70a686..1c94b8ee3 100644 --- a/OpenChange/iCalEvent+MAPIStore.m +++ b/OpenChange/iCalEvent+MAPIStore.m @@ -140,7 +140,7 @@ iCalDateTime *start, *end; iCalTimeZone *tz; NSTimeZone *userTimeZone; - NSString *priority; + NSString *priority, *class = nil; NSUInteger responseStatus = 0; NSInteger tzOffset; SOGoUser *ownerUser; @@ -281,6 +281,30 @@ priority = @"0"; // None [self setPriority: priority]; + /* class */ + /* See [MS-OXCICAL] Section 2.1.3.11.20.4 */ + value = [properties objectForKey: MAPIPropertyKey(PR_SENSITIVITY)]; + if (value) + { + switch ([value intValue]) + { + case 1: + class = @"X-PERSONAL"; + break; + case 2: + class = @"PRIVATE"; + break; + case 3: + class = @"CONFIDENTIAL"; + break; + default: /* 0 as well */ + class = @"PUBLIC"; + } + } + + if (class) + [self setAccessClass: class]; + /* show time as free/busy/tentative/out of office. Possible values are: 0x00000000 - olFree 0x00000001 - olTentative From 9b847a276c5bf442a67975078d13c028a112a579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Sun, 15 Feb 2015 23:52:06 +0100 Subject: [PATCH 073/120] oc-calendar: Implement categories to share the colour See [MS-OXCICAL] Section 2.1.3.1.1.20.3 for details. It requires https://github.com/openchange/openchange/pull/216 to retrieve the value from MAPI client --- OpenChange/MAPIStoreAppointmentWrapper.m | 17 +++++++++++++++++ OpenChange/iCalEvent+MAPIStore.m | 6 ++++++ 2 files changed, 23 insertions(+) diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index 3f3708915..7fa60c5c5 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -45,6 +45,7 @@ #import "MAPIStoreRecurrenceUtils.h" #import "MAPIStoreSamDBUtils.h" #import "MAPIStoreTypes.h" +#import "NSArray+MAPIStore.h" #import "NSData+MAPIStore.h" #import "NSDate+MAPIStore.h" #import "NSObject+MAPIStore.h" @@ -1243,6 +1244,22 @@ static NSCharacterSet *hexCharacterSet = nil; return MAPISTORE_SUCCESS; } +- (int) getPidNameKeywords: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + /* See [MS-OXCICAL] Section 2.1.3.1.1.20.3 */ + NSArray *categories; + + categories = [event categories]; + if (categories) + { + *data = [categories asMVUnicodeInMemCtx: memCtx]; + return MAPISTORE_SUCCESS; + } + else + return MAPISTORE_ERR_NOT_FOUND; +} + - (int) getPidTagBody: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { diff --git a/OpenChange/iCalEvent+MAPIStore.m b/OpenChange/iCalEvent+MAPIStore.m index 1c94b8ee3..8d7269620 100644 --- a/OpenChange/iCalEvent+MAPIStore.m +++ b/OpenChange/iCalEvent+MAPIStore.m @@ -305,6 +305,12 @@ if (class) [self setAccessClass: class]; + /* Categories */ + /* See [MS-OXCICAL] Section 2.1.3.1.1.20.3 */ + value = [properties objectForKey: MAPIPropertyKey (PidNameKeywords)]; + if (value) + [self setCategories: value]; + /* show time as free/busy/tentative/out of office. Possible values are: 0x00000000 - olFree 0x00000001 - olTentative From 731934f0618c17760bd6c2cac53e9d97d485914c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Thu, 19 Feb 2015 15:00:27 +0100 Subject: [PATCH 074/120] oc: Add fai properties for custom views Without this outlook clients with custom views set on folders will crash because this are needed properties and were not being saved --- OpenChange/MAPIStoreDBMessage.m | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/OpenChange/MAPIStoreDBMessage.m b/OpenChange/MAPIStoreDBMessage.m index 074c205ea..077f2c708 100644 --- a/OpenChange/MAPIStoreDBMessage.m +++ b/OpenChange/MAPIStoreDBMessage.m @@ -50,19 +50,22 @@ NSUInteger count; enum MAPITAGS faiProperties[] = { 0x68350102, 0x683c0102, 0x683e0102, 0x683f0102, 0x68410003, 0x68420102, - 0x68450102, 0x68460003 }; + 0x68450102, 0x68460003, + // PR_VD_NAME_W, PR_VD_FLAGS, PR_VD_VERSION, PR_VIEW_CLSID + 0x7006001F, 0x70030003, 0x70070003, 0x68330048 }; + size_t faiSize = sizeof(faiProperties) / sizeof(enum MAPITAGS); properties = talloc_zero (memCtx, struct SPropTagArray); - properties->cValues = MAPIStoreSupportedPropertiesCount + 8; + properties->cValues = MAPIStoreSupportedPropertiesCount + faiSize; properties->aulPropTag = talloc_array (properties, enum MAPITAGS, - MAPIStoreSupportedPropertiesCount + 8); + MAPIStoreSupportedPropertiesCount + faiSize); for (count = 0; count < MAPIStoreSupportedPropertiesCount; count++) properties->aulPropTag[count] = MAPIStoreSupportedProperties[count]; /* FIXME (hack): append a few undocumented properties that can be added to FAI messages */ - for (count = 0; count < 8; count++) + for (count = 0; count < faiSize; count++) properties->aulPropTag[MAPIStoreSupportedPropertiesCount+count] = faiProperties[count]; From 4c3c741d9f6b05eb67c0bb1c454b5f9027682493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Vall=C3=A9s?= Date: Mon, 23 Feb 2015 14:45:16 +0100 Subject: [PATCH 075/120] oc-contacts: Save missing contact properties in database --- OpenChange/MAPIStoreContactsMessage.m | 142 +++++++++++++++++++++++++- 1 file changed, 140 insertions(+), 2 deletions(-) diff --git a/OpenChange/MAPIStoreContactsMessage.m b/OpenChange/MAPIStoreContactsMessage.m index c866670f2..cccb495e1 100644 --- a/OpenChange/MAPIStoreContactsMessage.m +++ b/OpenChange/MAPIStoreContactsMessage.m @@ -170,6 +170,21 @@ return MAPISTORE_SUCCESS; } +- (int) getPidTagProfession: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSString *stringValue; + int rc = MAPISTORE_SUCCESS; + + stringValue = [[sogoObject vCard] role]; + if (stringValue) + *data = [stringValue asUnicodeInMemCtx: memCtx]; + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; +} + - (int) getPidTagCompanyName: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -744,6 +759,86 @@ return rc; } +- (int) getPidTagSpouseName: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSString *stringValue; + int rc = MAPISTORE_SUCCESS; + + stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-ms-spouse"] + flattenedValuesForKey: @""]; + if (stringValue) + *data = [stringValue asUnicodeInMemCtx: memCtx]; + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; +} + +- (int) getPidTagManagerName: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSString *stringValue; + int rc = MAPISTORE_SUCCESS; + + stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-ms-manager"] + flattenedValuesForKey: @""]; + if (stringValue) + *data = [stringValue asUnicodeInMemCtx: memCtx]; + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; +} + +- (int) getPidTagAssistant: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSString *stringValue; + int rc = MAPISTORE_SUCCESS; + + stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-ms-assistant"] + flattenedValuesForKey: @""]; + if (stringValue) + *data = [stringValue asUnicodeInMemCtx: memCtx]; + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; +} + +- (int) getPidTagOfficeLocation: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSString *stringValue; + int rc = MAPISTORE_SUCCESS; + + stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"x-ms-office"] + flattenedValuesForKey: @""]; + if (stringValue) + *data = [stringValue asUnicodeInMemCtx: memCtx]; + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; +} + +- (int) getPidLidFreeBusyLocation: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSString *stringValue; + int rc = MAPISTORE_SUCCESS; + + stringValue = [[[sogoObject vCard] uniqueChildWithTag: @"fburl"] + flattenedValuesForKey: @""]; + if (stringValue) + *data = [stringValue asUnicodeInMemCtx: memCtx]; + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; +} + // // Decomposed fullname getters // @@ -1154,12 +1249,18 @@ fromProperties: (NSDictionary *) attachmentProps // - // job title, nickname, company name, deparment, work url, im address/screen name and birthday + // job title, profession, nickname, company name, deparment, work url, im address/screen name and birthday // value = [properties objectForKey: MAPIPropertyKey(PR_TITLE_UNICODE)]; if (value) [newCard setTitle: value]; + value = [properties objectForKey: MAPIPropertyKey(PR_PROFESSION_UNICODE)]; + if (value) + { + [newCard setRole: value]; + } + value = [properties objectForKey: MAPIPropertyKey(PR_NICKNAME_UNICODE)]; if (value) [newCard setNickname: value]; @@ -1194,7 +1295,9 @@ fromProperties: (NSDictionary *) attachmentProps [newCard setBday: [value descriptionWithCalendarFormat: @"%Y-%m-%d"]]; } - /* wedding anniversary */ + // + // wedding anniversary, spouse's name, manager's name, assistant's name, office location, freebusy location + // value = [properties objectForKey: MAPIPropertyKey(PidTagWeddingAnniversary)]; if (value) { @@ -1203,6 +1306,41 @@ fromProperties: (NSDictionary *) attachmentProps forKey: @""]; } + value = [properties objectForKey: MAPIPropertyKey(PR_SPOUSE_NAME_UNICODE)]; + if (value) + { + [[newCard uniqueChildWithTag: @"x-ms-spouse"] + setSingleValue: value forKey: @""]; + } + + value = [properties objectForKey: MAPIPropertyKey(PR_MANAGER_NAME_UNICODE)]; + if (value) + { + [[newCard uniqueChildWithTag: @"x-ms-manager"] + setSingleValue: value forKey: @""]; + } + + value = [properties objectForKey: MAPIPropertyKey(PR_ASSISTANT_UNICODE)]; + if (value) + { + [[newCard uniqueChildWithTag: @"x-ms-assistant"] + setSingleValue: value forKey: @""]; + } + + value = [properties objectForKey: MAPIPropertyKey(PR_OFFICE_LOCATION_UNICODE)]; + if (value) + { + [[newCard uniqueChildWithTag: @"x-ms-office"] + setSingleValue: value forKey: @""]; + } + + value = [properties objectForKey: MAPIPropertyKey(PidLidFreeBusyLocation)]; + if (value) + { + [[newCard uniqueChildWithTag: @"fburl"] + setSingleValue: value forKey: @""]; + } + /* photo */ if ([attachmentParts count] > 0) { From 22196e0054f9040ba33557e693701afc9ee16ec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Wed, 25 Feb 2015 12:01:31 +0100 Subject: [PATCH 076/120] Fix change password with DomainBasedUID When users use full domain to login (SOGoEnableDomainBasedUID) the user attributes in the cache were not being properly updated because in this case the key is `uid@domain` instead of just `uid`. --- SoObjects/SOGo/SOGoUserManager.m | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/SoObjects/SOGo/SOGoUserManager.m b/SoObjects/SOGo/SOGoUserManager.m index d8e09ba6c..4d6a5b911 100644 --- a/SoObjects/SOGo/SOGoUserManager.m +++ b/SoObjects/SOGo/SOGoUserManager.m @@ -595,10 +595,11 @@ static Class NSNullK; newPassword: (NSString *) newPassword perr: (SOGoPasswordPolicyError *) perr { - NSString *jsonUser; + NSString *jsonUser, *userLogin; NSMutableDictionary *currentUser; BOOL didChange; - + SOGoSystemDefaults *sd; + jsonUser = [[SOGoCache sharedCache] userAttributesForLogin: login]; currentUser = [jsonUser objectFromJSONString]; @@ -611,9 +612,7 @@ static Class NSNullK; didChange = YES; if (!currentUser) - { - currentUser = [NSMutableDictionary dictionary]; - } + currentUser = [NSMutableDictionary dictionary]; // It's important to cache the password here as we might have cached the // user's entry in -contactInfosForUserWithUIDorEmail: and if we don't @@ -621,9 +620,13 @@ static Class NSNullK; // cached for the user unless its entry expires from memcached's // internal cache. [currentUser setObject: [newPassword asSHA1String] forKey: @"password"]; - [[SOGoCache sharedCache] - setUserAttributes: [currentUser jsonRepresentation] - forLogin: login]; + sd = [SOGoSystemDefaults sharedSystemDefaults]; + if ([sd enableDomainBasedUID]) + userLogin = [NSString stringWithFormat: @"%@@%@", login, domain]; + else + userLogin = login; + [[SOGoCache sharedCache] setUserAttributes: [currentUser jsonRepresentation] + forLogin: userLogin]; } else didChange = NO; From ef6aab63c900f7fe3d6ee2b00c540a4e54e3b286 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Amor=20Garc=C3=ADa?= Date: Mon, 23 Feb 2015 15:21:16 +0100 Subject: [PATCH 077/120] oc-calendar: Don't change event recurrence if parse failed. get_AppointmentRecurrencePattern() can fail to parse the input data, added a check to avoid setup the recurrence pattern in that case. This should only happen when input data is incorrect. --- OpenChange/iCalEvent+MAPIStore.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OpenChange/iCalEvent+MAPIStore.m b/OpenChange/iCalEvent+MAPIStore.m index 1c94b8ee3..ee1b0d6ec 100644 --- a/OpenChange/iCalEvent+MAPIStore.m +++ b/OpenChange/iCalEvent+MAPIStore.m @@ -81,6 +81,12 @@ blob = [mapiRecurrenceData asBinaryInMemCtx: memCtx]; pattern = get_AppointmentRecurrencePattern (memCtx, blob); + + if (pattern == NULL) { + [self logWithFormat: @"Error parsing recurrence pattern. No changes in event recurrence will be done"]; + return; + } + [(iCalCalendar *) parent setupRecurrenceWithMasterEntity: self fromRecurrencePattern: &pattern->RecurrencePattern]; From cd47c926c92c29c7ee63c3990417883d60be2be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Garc=C3=ADa?= Date: Mon, 2 Mar 2015 10:12:20 +0100 Subject: [PATCH 078/120] Update news for next release --- NEWS | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/NEWS b/NEWS index 8177e4989..cf81a2201 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,15 @@ +master +------ + +Enhancements + - Missing contact fields are now saved and available when sharing it + (Office, Profession, Manager's name, Assistant's name, Spouse/Partner, Anniversary) + - Appointment color and importance work now between Outlooks + +Bug fixes + - Fix Outlook crashes when modifying the view of a folder + - Fix server side crash when reading some recurrence appointments + 2.2.15 (2015-01-30) ------------------- From 575600cabc57b29f3161b999389e50497307506e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Mon, 2 Mar 2015 23:36:28 +0100 Subject: [PATCH 079/120] oc-calendar: Return PidTagContainerClass for Calendar folders And it must "IPF.Appointment" as described in [MS-OXOCAL] Section 2.2.11.1 --- OpenChange/MAPIStoreCalendarFolder.m | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/OpenChange/MAPIStoreCalendarFolder.m b/OpenChange/MAPIStoreCalendarFolder.m index 27ab9c3e1..5f57c0560 100644 --- a/OpenChange/MAPIStoreCalendarFolder.m +++ b/OpenChange/MAPIStoreCalendarFolder.m @@ -186,6 +186,14 @@ [(SOGoAppointmentFolder *) sogoObject aclSQLListingFilter]]; } +- (int) getPidTagContainerClass: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = [@"IPF.Appointment" asUnicodeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + - (int) getPidTagDefaultPostMessageClass: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { From 44dfd35521b4f94420fb674e00ada395fab7a370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Tue, 3 Mar 2015 22:52:42 +0100 Subject: [PATCH 080/120] oc-mail: Set sender on email messages without an orig recipient But it has recipients. This is for sure happening with event invitations messages. --- NEWS | 1 + OpenChange/MAPIStoreMailVolatileMessage.m | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index cf81a2201..cb2d6ef24 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,7 @@ Enhancements - Appointment color and importance work now between Outlooks Bug fixes + - Fix sender on importing email messages like event invitations - Fix Outlook crashes when modifying the view of a folder - Fix server side crash when reading some recurrence appointments diff --git a/OpenChange/MAPIStoreMailVolatileMessage.m b/OpenChange/MAPIStoreMailVolatileMessage.m index ed9fbf8d2..747cd18bf 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.m +++ b/OpenChange/MAPIStoreMailVolatileMessage.m @@ -536,6 +536,7 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers, NSDictionary *mailProperties, BOOL withBcc, struct mapistore_connection_info *connInfo) { + BOOL fromResolved = NO; NSData *senderEntryId; NSMutableString *subject; NSString *from, *recId, *messageId, *subjectData, *recipientsStr; @@ -572,13 +573,15 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers, list = MakeRecipientsList ([recipients objectForKey: @"orig"]); if ([list count]) - [headers setObjects: list forKey: @"from"]; + { + [headers setObjects: list forKey: @"from"]; + fromResolved = YES; + } } - else + + if (!fromResolved) { - NSLog (@"Message without recipients." - @"Guessing recipients from PidTagSenderEntryId, PidTagOriginalDisplayTo" - @"and PidTagOriginalCc"); + NSLog (@"Message without an orig from, try to guess it from PidTagSenderEntryId"); senderEntryId = [mailProperties objectForKey: MAPIPropertyKey (PR_SENDER_ENTRYID)]; if (senderEntryId) { @@ -638,7 +641,12 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers, } } + } + if (!recipients) + { + NSLog (@"Message without recipients." + @"Guessing recipients from PidTagOriginalDisplayTo and PidTagOriginalCc"); recipientsStr = [mailProperties objectForKey: MAPIPropertyKey (PidTagOriginalDisplayTo)]; if (recipientsStr) { From 3b2cbb945c86b4a9fdfea7f6f66ff64d0005daf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20P=C3=A9rez-Aradros=20Herce?= Date: Wed, 21 Jan 2015 00:27:14 +0100 Subject: [PATCH 081/120] oc: Free headerEncoding variable --- OpenChange/MAPIStoreMailMessage.m | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index 8a9bd1918..81d8cd385 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -133,6 +133,7 @@ static Class NSExceptionK; [bodyContent release]; [headerMimeType release]; [headerCharset release]; + [headerEncoding release]; [appointmentWrapper release]; [super dealloc]; } From 316ade13f84798006c3cdaf2c0fa5e884d7a29c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Mon, 2 Mar 2015 23:41:04 +0100 Subject: [PATCH 082/120] oc: Implement Sharing Message Object It acts as a proxy of MAPIStoreMailMessage and it manages the properties defined in [MS-OXSHARE] Section 2.2 by storing them in the mail message as eXtensible MIME headers which starts with X-MS-Sharing. --- OpenChange/GNUmakefile | 2 + OpenChange/MAPIStoreMailMessage.h | 1 + OpenChange/MAPIStoreMailMessage.m | 21 ++ OpenChange/MAPIStoreMailVolatileMessage.m | 89 +++++- OpenChange/MAPIStoreSharingMessage.h | 94 ++++++ OpenChange/MAPIStoreSharingMessage.m | 372 ++++++++++++++++++++++ 6 files changed, 575 insertions(+), 4 deletions(-) create mode 100644 OpenChange/MAPIStoreSharingMessage.h create mode 100644 OpenChange/MAPIStoreSharingMessage.m diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index d9eaf92a4..688ef19e1 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -110,6 +110,8 @@ $(SOGOBACKEND)_OBJC_FILES += \ \ MAPIStoreFallbackContext.m \ \ + MAPIStoreSharingMessage.m \ + \ NSArray+MAPIStore.m \ NSData+MAPIStore.m \ NSDate+MAPIStore.m \ diff --git a/OpenChange/MAPIStoreMailMessage.h b/OpenChange/MAPIStoreMailMessage.h index 6bae6647a..2f6192c16 100644 --- a/OpenChange/MAPIStoreMailMessage.h +++ b/OpenChange/MAPIStoreMailMessage.h @@ -35,6 +35,7 @@ { BOOL headerSetup; BOOL mailIsEvent; + BOOL mailIsSharingObject; NSString *mimeKey; NSString *headerCharset; NSString *headerEncoding; diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index 8a9bd1918..cf6e019de 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -51,6 +51,7 @@ #import "MAPIStoreMailFolder.h" #import "MAPIStoreMapping.h" #import "MAPIStoreSamDBUtils.h" +#import "MAPIStoreSharingMessage.h" #import "MAPIStoreTypes.h" #import "MAPIStoreUserContext.h" @@ -115,6 +116,7 @@ static Class NSExceptionK; { mimeKey = nil; mailIsEvent = NO; + mailIsSharingObject = NO; headerCharset = nil; headerEncoding = nil; headerMimeType = nil; @@ -201,9 +203,11 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) - (void) _fetchHeaderData { + MAPIStoreSharingMessage *sharingMessage; NSMutableArray *keys; NSArray *acceptedTypes; NSDictionary *messageData, *partHeaderData, *parameters; + NSString *sharingHeader; acceptedTypes = [NSArray arrayWithObjects: @"text/calendar", @"application/ics", @@ -228,6 +232,21 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) if ([headerMimeType isEqualToString: @"text/calendar"] || [headerMimeType isEqualToString: @"application/ics"]) mailIsEvent = YES; + else + { + sharingHeader = [[sogoObject mailHeaders] objectForKey: @"x-ms-sharing-localtype"]; + if (sharingHeader) + { + mailIsSharingObject = YES; + /* It is difficult to subclass this in folder class, that's why + a sharing object is a proxy in a mail message */ + sharingMessage = [[MAPIStoreSharingMessage alloc] + initWithMailHeaders: [sogoObject mailHeaders] + andConnectionInfo: [[self context] connectionInfo]]; + [self addProxy: sharingMessage]; + [sharingMessage release]; + } + } } headerSetup = YES; @@ -517,6 +536,8 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) if (mailIsEvent) [[self _appointmentWrapper] getPidTagMessageClass: data inMemCtx: memCtx]; + else if (mailIsSharingObject) + *data = talloc_strdup (memCtx, "IPM.Sharing"); else *data = talloc_strdup (memCtx, "IPM.Note"); diff --git a/OpenChange/MAPIStoreMailVolatileMessage.m b/OpenChange/MAPIStoreMailVolatileMessage.m index ed9fbf8d2..a2aac76ee 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.m +++ b/OpenChange/MAPIStoreMailVolatileMessage.m @@ -30,6 +30,7 @@ #import #import #import +#import #import #import #import @@ -42,6 +43,7 @@ #import #import #import +#import #import #import #import @@ -62,13 +64,13 @@ #import "NSData+MAPIStore.h" #import "NSObject+MAPIStore.h" #import "NSString+MAPIStore.h" -#import #import "MAPIStoreMailVolatileMessage.h" #undef DEBUG #include #include +#include static Class NSNumberK = Nil; @@ -531,6 +533,78 @@ QuoteSpecials (NSString *address) return result; } +static inline void +FillMessageHeadersFromSharingProperties (NGMutableHashMap *headers, NSDictionary *mailProperties) +{ + /* Store the *important* properties related with a sharing object as + MIME eXtension headers. See [MS-OXSHARE] Section 2.2 for details + about the properties */ + + id value; + + value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingCapabilities)]; + if (value) + [headers setObject: value + forKey: @"X-MS-Sharing-Capabilities"]; + + value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingFlavor)]; + if (value) + [headers setObject: value + forKey: @"X-MS-Sharing-Flavor"]; + + value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingInitiatorEntryId)]; + if (value) + [headers setObject: [[value stringByEncodingBase64] stringByReplacingOccurrencesOfString: @"\n" + withString: @""] + forKey: @"X-MS-Sharing-InitiatorEntryId"]; + + value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingInitiatorName)]; + if (value) + [headers setObject: value + forKey: @"X-MS-Sharing-InitiatorName"]; + + value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingInitiatorSmtp)]; + if (value) + [headers setObject: value + forKey: @"X-MS-Sharing-InitiatorSmtp"]; + + value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingLocalType)]; + if (value) + [headers setObject: value + forKey: @"X-MS-Sharing-LocalType"]; + + value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingProviderName)]; + if (value) + [headers setObject: value + forKey: @"X-MS-Sharing-ProviderName"]; + + value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingRemoteName)]; + if (value) + [headers setObject: value + forKey: @"X-MS-Sharing-RemoteName"]; + + value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingRemoteStoreUid)]; + if (value) + [headers setObject: value + forKey: @"X-MS-Sharing-RemoteStoreUid"]; + + value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingRemoteUid)]; + if (value) + [headers setObject: value + forKey: @"X-MS-Sharing-RemoteUid"]; + + value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingResponseTime)]; + if (value) + [headers setObject: value + forKey: @"X-MS-Sharing-ResponseTime"]; + + value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingResponseType)]; + if (value) + [headers setObject: value + forKey: @"X-MS-Sharing-ResponseType"]; + +} + static inline void FillMessageHeadersFromProperties (NGMutableHashMap *headers, NSDictionary *mailProperties, BOOL withBcc, @@ -538,7 +612,7 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers, { NSData *senderEntryId; NSMutableString *subject; - NSString *from, *recId, *messageId, *subjectData, *recipientsStr; + NSString *from, *recId, *messageId, *subjectData, *recipientsStr, *msgClass; NSArray *list; NSCalendarDate *date; NSDictionary *recipients; @@ -690,6 +764,13 @@ FillMessageHeadersFromProperties (NGMutableHashMap *headers, { [headers addObject: @"5 (Lowest)" forKey: @"X-Priority"]; } + + msgClass = [mailProperties objectForKey: MAPIPropertyKey (PidTagMessageClass)]; + if ([msgClass isEqualToString: @"IPM.Sharing"]) + { + FillMessageHeadersFromSharingProperties (headers, mailProperties); + } + } static NSArray * @@ -939,12 +1020,12 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS id authenticator; msgClass = [properties objectForKey: MAPIPropertyKey (PidTagMessageClass)]; - if ([msgClass isEqualToString: @"IPM.Note"]) /* we skip invitation replies */ + if ([msgClass isEqualToString: @"IPM.Note"] || [msgClass isEqualToString: @"IPM.Sharing"]) /* we skip invitation replies */ { /* send mail */ messageData = [self _generateMailDataWithBcc: NO]; - + recipientEmails = [NSMutableArray arrayWithCapacity: 32]; recipients = [properties objectForKey: @"recipients"]; for (type = MAPI_ORIG; type <= MAPI_BCC; type++) diff --git a/OpenChange/MAPIStoreSharingMessage.h b/OpenChange/MAPIStoreSharingMessage.h new file mode 100644 index 000000000..9b62389a0 --- /dev/null +++ b/OpenChange/MAPIStoreSharingMessage.h @@ -0,0 +1,94 @@ +/* MAPIStoreSharingMessage.h - this file is part of SOGo-OpenChange + * + * Copyright (C) 2015 Enrique J. Hernández + * + * Author: Enrique J. Hernández + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef MAPISTORESHARINGMESSAGE_H +#define MAPISTORESHARINGMESSAGE_H + +#import "MAPIStoreObjectProxy.h" + + +@interface MAPIStoreSharingMessage : MAPIStoreObjectProxy +{ + struct mapistore_connection_info *connInfo; + NSMutableDictionary *properties; +} + +- (id) initWithMailHeaders: (NSDictionary *) mailHeaders + andConnectionInfo: (struct mapistore_connection_info *) newConnInfo; + +/* getters */ +- (int) getPidLidSharingCapabilities: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidNameXSharingCapabilities: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidLidSharingConfigurationUrl: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidNameXSharingConfigUrl: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidLidSharingFlavor: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidNameXSharingFlavor: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidLidSharingInitiatorEntryId: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidLidSharingInitiatorName: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidLidSharingInitiatorSmtp: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidLidSharingLocalType: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidNameXSharingLocalType: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidLidSharingProviderGuid: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidNameXSharingProviderGuid: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidLidSharingProviderName: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidNameXSharingProviderName: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidLidSharingProviderUrl: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidNameXSharingProviderUrl: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidLidSharingRemoteName: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidNameXSharingRemoteName: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidLidSharingRemoteStoreUid: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidNameXSharingRemoteStoreUid: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidLidSharingRemoteType: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidTypeXSharingRemoteType: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidLidSharingResponseTime: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidLidSharingResponseType: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidNameContentClass: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; + +@end + +#endif /* MAPISTORECALENDARWRAPPER_H */ diff --git a/OpenChange/MAPIStoreSharingMessage.m b/OpenChange/MAPIStoreSharingMessage.m new file mode 100644 index 000000000..b25db2444 --- /dev/null +++ b/OpenChange/MAPIStoreSharingMessage.m @@ -0,0 +1,372 @@ +/* MAPIStoreSharingMessage.m - this file is part of SOGo-OpenChange + * + * Copyright (C) 2015 Enrique J. Hernández + * + * Author: Enrique J. Hernández + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#import +#import + +#import + +#import "MAPIStoreTypes.h" +#import "NSData+MAPIStore.h" +#import "NSDate+MAPIStore.h" +#import "NSString+MAPIStore.h" +#import "NSValue+MAPIStore.h" + +#import "MAPIStoreSharingMessage.h" + +#include + +@implementation MAPIStoreSharingMessage + +- (id) init +{ + if ((self = [super init])) + { + connInfo = NULL; + properties = nil; + } + + return self; +} + +- (id) initWithMailHeaders: (NSDictionary *) mailHeaders + andConnectionInfo: (struct mapistore_connection_info *) newConnInfo +{ + NSEnumerator *enumerator; + NSString *key; + + if ((self = [self init])) + { + connInfo = newConnInfo; + enumerator = [mailHeaders keyEnumerator]; + properties = [NSMutableDictionary new]; + while ((key = [enumerator nextObject])) + { + if ([key hasPrefix: @"x-ms-sharing-"]) + [properties setObject: [mailHeaders objectForKey: key] + forKey: key]; + } + } + + return self; +} + +- (void) dealloc +{ + [properties release]; + [super dealloc]; +} + +- (enum mapistore_error) _getStringProperty: (NSString *) propertyName + inData: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND; + id value; + + value = [properties objectForKey: propertyName]; + if (value) + { + *data = [value asUnicodeInMemCtx: memCtx]; + rc = MAPISTORE_SUCCESS; + } + + return rc; + +} + +- (int) getPidLidSharingCapabilities: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + + enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND; + id value; + + value = [properties objectForKey: @"x-ms-sharing-capabilities"]; + if (value) + { + *data = MAPILongValue (memCtx, [value intValue]); + rc = MAPISTORE_SUCCESS; + } + + return rc; +} + +- (int) getPidNameXSharingCapabilities: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + + enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND; + id value; + + value = [properties objectForKey: @"x-ms-sharing-capabilities"]; + if (value) + { + *data = [[value stringValue] asUnicodeInMemCtx: memCtx]; + rc = MAPISTORE_SUCCESS; + } + + return rc; +} + +- (int) getPidLidSharingConfigurationUrl: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + + *data = [@"" asUnicodeInMemCtx: memCtx]; + return MAPISTORE_SUCCESS; +} + +- (int) getPidNameXSharingConfigUrl: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getPidLidSharingConfigurationUrl: data inMemCtx: memCtx]; +} + +- (int) getPidLidSharingFlavor: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND; + id value; + + value = [properties objectForKey: @"x-ms-sharing-flavor"]; + if (value) + { + *data = MAPILongValue (memCtx, [value intValue]); + rc = MAPISTORE_SUCCESS; + } + + return rc; +} + +- (int) getPidNameXSharingFlavor: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND; + id value; + + value = [properties objectForKey: @"x-ms-sharing-flavor"]; + if (value) + { + *data = [[value stringValue] asUnicodeInMemCtx: memCtx]; + rc = MAPISTORE_SUCCESS; + } + + return rc; +} + +- (int) getPidLidSharingInitiatorEntryId: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND; + id value; + NSData *entryId; + + value = [properties objectForKey: @"x-ms-sharing-initiatorentryid"]; + if (value) + { + entryId = [value dataByDecodingBase64]; + if (entryId) + { + *data = [entryId asBinaryInMemCtx: memCtx]; + rc = MAPISTORE_SUCCESS; + } + } + + return rc; +} + +- (int) getPidLidSharingInitiatorName: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self _getStringProperty: @"x-ms-sharing-initiatorname" + inData: data + inMemCtx: memCtx]; +} + +- (int) getPidLidSharingInitiatorSmtp: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self _getStringProperty: @"x-ms-sharing-initiatorsmtp" + inData: data + inMemCtx: memCtx]; +} + +- (int) getPidLidSharingLocalType: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self _getStringProperty: @"x-ms-sharing-localtype" + inData: data + inMemCtx: memCtx]; +} + +- (int) getPidNameXSharingLocalType: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getPidLidSharingLocalType: data inMemCtx: memCtx]; +} + +- (int) getPidLidSharingProviderGuid: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + const unsigned char providerGuidBytes[] = {0xAE, 0xF0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}; + NSData *providerGuid = [NSData dataWithBytes: providerGuidBytes length: 16]; + *data = [providerGuid asBinaryInMemCtx: memCtx]; + return MAPISTORE_SUCCESS; +} + +- (int) getPidNameXSharingProviderGuid: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = [@"AEF0060000000000C000000000000046" asUnicodeInMemCtx: memCtx]; + return MAPISTORE_SUCCESS; +} + +- (int) getPidLidSharingProviderName: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + + return [self _getStringProperty: @"x-ms-sharing-providername" + inData: data + inMemCtx: memCtx]; +} + +- (int) getPidNameXSharingProviderName: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getPidLidSharingProviderName: data inMemCtx: memCtx]; +} + +- (int) getPidLidSharingProviderUrl: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self _getStringProperty: @"x-ms-sharing-providerurl" + inData: data + inMemCtx: memCtx]; +} + +- (int) getPidNameXSharingProviderUrl: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getPidLidSharingProviderUrl: data inMemCtx: memCtx]; +} + +- (int) getPidLidSharingRemoteName: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self _getStringProperty: @"x-ms-sharing-remotename" + inData: data + inMemCtx: memCtx]; +} + +- (int) getPidNameXSharingRemoteName: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getPidLidSharingRemoteName: data inMemCtx: memCtx]; +} + +- (int) getPidLidSharingRemoteStoreUid: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self _getStringProperty: @"x-ms-sharing-remotestoreuid" + inData: data + inMemCtx: memCtx]; +} + +- (int) getPidNameXSharingRemoteStoreUid: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getPidLidSharingRemoteStoreUid: data inMemCtx: memCtx]; +} + +- (int) getPidLidSharingRemoteType: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self _getStringProperty: @"x-ms-sharing-remotetype" + inData: data + inMemCtx: memCtx]; +} + +- (int) getPidTypeXSharingRemoteType: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getPidLidSharingRemoteType: data inMemCtx: memCtx]; +} + +- (int) getPidLidSharingRemoteUid: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self _getStringProperty: @"x-ms-sharing-remoteuid" + inData: data + inMemCtx: memCtx]; +} + +- (int) getPidUidXSharingRemoteUid: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getPidLidSharingRemoteUid: data inMemCtx: memCtx]; +} + +- (int) getPidLidSharingResponseTime: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND; + id value; + + value = [properties objectForKey: @"x-ms-sharing-responsetime"]; + if (value) + { + *data = [value asFileTimeInMemCtx: memCtx]; + rc = MAPISTORE_SUCCESS; + } + + return rc; +} + +- (int) getPidLidSharingResponseType: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + + enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND; + id value; + + value = [properties objectForKey: @"x-ms-sharing-responsetype"]; + if (value) + { + *data = MAPILongValue (memCtx, [value intValue]); + rc = MAPISTORE_SUCCESS; + } + + return rc; +} + +- (int) getPidNameContentClass: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = talloc_strdup (memCtx, "Sharing"); + return MAPISTORE_SUCCESS; +} + +@end From 6af8b486df521274082f312e57614c0e88b68e0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Tue, 3 Mar 2015 00:08:34 +0100 Subject: [PATCH 083/120] oc-mail: Return special properties on sharing_metadata.xml attachment As required by [MS-OXWSMSHR] Section 3.1.1 to display the share object message correctly and be able to open the shared calendar directly from the message. --- NEWS | 1 + OpenChange/MAPIStoreMailAttachment.m | 25 +++++++++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index cf81a2201..1562d099d 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ master ------ Enhancements + - Give support to calendar sharing invitations - Missing contact fields are now saved and available when sharing it (Office, Profession, Manager's name, Assistant's name, Spouse/Partner, Anniversary) - Appointment color and importance work now between Outlooks diff --git a/OpenChange/MAPIStoreMailAttachment.m b/OpenChange/MAPIStoreMailAttachment.m index e21fc7925..388ad924d 100644 --- a/OpenChange/MAPIStoreMailAttachment.m +++ b/OpenChange/MAPIStoreMailAttachment.m @@ -163,8 +163,15 @@ - (int) getPidTagDisplayName: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - *data = [[bodyInfo objectForKey: @"description"] - asUnicodeInMemCtx: memCtx]; + NSString *fileName; + + fileName = [self _fileName]; + if ([fileName isEqualToString: @"sharing_metadata.xml"]) + /* Required to disallow user from seeing the attachment by default */ + *data = [@"sharing_metadata.xml" asUnicodeInMemCtx: memCtx]; + else + *data = [[bodyInfo objectForKey: @"description"] + asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } @@ -181,11 +188,17 @@ - (int) getPidTagAttachMimeTag: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - NSString *mimeTag; + NSString *mimeTag, *fileName; + + fileName = [self _fileName]; + if ([fileName isEqualToString: @"sharing_metadata.xml"]) + /* Required by [MS-OXWSMSHR] Section 3.1.1 */ + mimeTag = [NSString stringWithFormat: @"application/x-sharing-metadata-xml"]; + else + mimeTag = [NSString stringWithFormat: @"%@/%@", + [bodyInfo objectForKey: @"type"], + [bodyInfo objectForKey: @"subtype"]]; - mimeTag = [NSString stringWithFormat: @"%@/%@", - [bodyInfo objectForKey: @"type"], - [bodyInfo objectForKey: @"subtype"]]; *data = [[mimeTag lowercaseString] asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; From ae7ac1be296ab362ac98c55345c66811ce591f9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Thu, 5 Mar 2015 00:02:19 +0100 Subject: [PATCH 084/120] oc-mail: Return sharing properties on sharing object mail message When it is asked for available properties for an specific message. --- OpenChange/MAPIStoreMailMessage.m | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index cf6e019de..156d7e558 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -154,6 +154,30 @@ static Class NSExceptionK; return [sogoObject date]; } +- (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP + inMemCtx: (TALLOC_CTX *) memCtx +{ + BOOL listedProperties[65536]; + NSUInteger count; + uint16_t propId; + + if (mailIsSharingObject) + { + memset (listedProperties, NO, 65536 * sizeof (BOOL)); + [super getAvailableProperties: propertiesP inMemCtx: memCtx]; + for (count = 0; count < (*propertiesP)->cValues; count++) + { + propId = ((*propertiesP)->aulPropTag[count] >> 16) & 0xffff; + listedProperties[propId] = YES; + } + [MAPIStoreSharingMessage fillAvailableProperties: *propertiesP + withExclusions: listedProperties]; + return MAPISTORE_SUCCESS; + } + else + return [super getAvailableProperties: propertiesP inMemCtx: memCtx]; +} + static NSComparisonResult _compareBodyKeysByPriority (id entry1, id entry2, void *data) { From 2b54897d29cf6beeadd602acb4620229858623d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Thu, 5 Mar 2015 00:05:02 +0100 Subject: [PATCH 085/120] oc-sharing: Guess PidLidSharingFlavor from other props When it is not set by the client on the first place. See [MS-OXSHARE] Section 2.2.2.5 for details on returned values. --- OpenChange/MAPIStoreSharingMessage.m | 35 +++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/OpenChange/MAPIStoreSharingMessage.m b/OpenChange/MAPIStoreSharingMessage.m index b25db2444..594863e0e 100644 --- a/OpenChange/MAPIStoreSharingMessage.m +++ b/OpenChange/MAPIStoreSharingMessage.m @@ -147,8 +147,9 @@ - (int) getPidLidSharingFlavor: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { + /* See [MS-OXSHARE] Section 2.2.2.5 for details */ enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND; - id value; + id value, auxValue; value = [properties objectForKey: @"x-ms-sharing-flavor"]; if (value) @@ -156,6 +157,38 @@ *data = MAPILongValue (memCtx, [value intValue]); rc = MAPISTORE_SUCCESS; } + else + { + /* Guess its value required by old clients based on other properties */ + value = [properties objectForKey: @"x-ms-sharing-capabilities"]; + if (value) + { + if ([value intValue] == 0x40290) /* Special folder */ + { + value = [properties objectForKey: @"x-ms-sharing-responsetime"]; + auxValue = [properties objectForKey: @"x-ms-sharing-remotename"]; + if (value) /* A sharing request */ + { + if (auxValue) + *data = MAPILongValue (memCtx, 0x20710); + else + *data = MAPILongValue (memCtx, 0x20500); + } + else + { + if (auxValue) /* It SHOULD be an invitation or response acceptance */ + *data = MAPILongValue (memCtx, 0x20310); + else + *data = MAPILongValue (memCtx, 0x23310); + } + } + else + { + *data = MAPILongValue (memCtx, 0x310); + } + rc = MAPISTORE_SUCCESS; + } + } return rc; } From 6e0027498814f27a2cac3cdbdd472431a700c259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Wed, 11 Mar 2015 11:22:41 +0100 Subject: [PATCH 086/120] oc-rtf: safe parse ignoring content Be able to parse safely \*\xxxxx control words with \binXXXX elements inside it (before final }) --- NEWS | 1 + OpenChange/RTFHandler.m | 51 +++++++++++++---------------------------- 2 files changed, 17 insertions(+), 35 deletions(-) diff --git a/NEWS b/NEWS index bae4a7cd6..0fadce1bc 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ Enhancements - Appointment color and importance work now between Outlooks Bug fixes + - Fix server side crash parsing rtf emails with images (with word97 format) - Fix sender on importing email messages like event invitations - Fix Outlook crashes when modifying the view of a folder - Fix server side crash when reading some recurrence appointments diff --git a/OpenChange/RTFHandler.m b/OpenChange/RTFHandler.m index 6d3a225b4..4535626e3 100644 --- a/OpenChange/RTFHandler.m +++ b/OpenChange/RTFHandler.m @@ -660,22 +660,17 @@ const unsigned short ansicpg874[256] = { } while (count != 0); } -// -// -// -- (void) parsePicture +- (void) parseIgnoringEverything { + unsigned int count = 1; // Ignore everything. But we cannot parse it blindly because it could have // binary data with '}' and '{' bytes, so disasters can happen and they will - unsigned int count = 0; - const char *cw; - do { if (*_bytes == '\\') { unsigned int binary_size, len = 0, cw_len; - cw = [self parseControlWord: &len]; + const char *cw = [self parseControlWord: &len]; cw_len = strlen("bin"); if (strncmp(cw, "bin", cw_len) == 0 && len > cw_len) { @@ -688,25 +683,23 @@ const unsigned short ansicpg874[256] = { binary_size = [s intValue]; ADVANCE_N(binary_size); } - else if (len > 0) - { - ADVANCE_N(len); - } - else - { - ADVANCE; - } - } - else - { - if (*_bytes == '{') count++; - if (*_bytes == '}') count--; - ADVANCE; } + + if (*_bytes == '{') count++; + if (*_bytes == '}') count--; + ADVANCE; } while (count > 0); } +// +// +// +- (void) parsePicture +{ + [self parseIgnoringEverything]; +} + // // // @@ -771,19 +764,7 @@ const unsigned short ansicpg874[256] = { } else if (*(_bytes+1) == '*') { - int cc = 1; - - do - { - if (*_bytes == '{') - cc++; - if (*_bytes == '}') - cc--; - - ADVANCE; - } - while (cc != 0); - + [self parseIgnoringEverything]; continue; } From 6d6053865f970f40e6dc4e6ac37df8c4d5bf29d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Fri, 13 Mar 2015 00:00:29 +0100 Subject: [PATCH 087/120] Revert "oc-mailfolder: Get seen flag directly from message in preloading" This reverts commit d076e04ad47c8938531450af9f002552328f8fa1. --- OpenChange/MAPIStoreMailFolder.m | 33 ++++++++++++++++++++----------- OpenChange/MAPIStoreMailMessage.h | 1 - OpenChange/MAPIStoreMailMessage.m | 8 -------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 0a439e29e..e4c4b8a9b 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -1476,8 +1476,9 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) NSUInteger count, max; NSString *messageKey, *messageUid, *bodyPartKey; NGImap4Client *client; - NSArray *fetch; + NSArray *fetch, *flags; NSData *bodyContent; + BOOL unseen; NSMutableArray *unseenUIDs; if (tableType == MAPISTORE_MESSAGE_TABLE) @@ -1489,7 +1490,6 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) { bodyPartKeys = [NSMutableSet setWithCapacity: max]; - unseenUIDs = [NSMutableArray arrayWithCapacity: max]; keyAssoc = [NSMutableDictionary dictionaryWithCapacity: max]; for (count = 0; count < max; count++) { @@ -1503,15 +1503,6 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) [bodyPartKeys addObject: bodyPartKey]; messageUid = [self messageUIDFromMessageKey: messageKey]; [keyAssoc setObject: bodyPartKey forKey: messageUid]; - /* Fetch flags to remove seen flag if required, - as fetching a message body set the seen flag. - We are not using body.peek[] as - bodyContentPartKey explicitly avoids it. - */ - if (![message read]) - { - [unseenUIDs addObject: messageUid]; - } } } } @@ -1519,6 +1510,24 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) client = [[(SOGoMailFolder *) sogoObject imap4Connection] client]; [client select: [sogoObject absoluteImap4Name]]; + /* Fetch flags to remove seen flag if required, + as fetching a message body set the seen flag */ + response = [client fetchUids: [keyAssoc allKeys] + parts: [NSArray arrayWithObjects: @"flags", nil]]; + fetch = [response objectForKey: @"fetch"]; + max = [fetch count]; + unseenUIDs = [NSMutableArray arrayWithCapacity: max]; + for (count = 0; count < max; count++) + { + response = [fetch objectAtIndex: count]; + messageUid = [[response objectForKey: @"uid"] stringValue]; + flags = [response objectForKey: @"flags"]; + unseen = [flags indexOfObject: @"seen"] == NSNotFound; + if (unseen) { + [unseenUIDs addObject: messageUid]; + } + } + response = [client fetchUids: [keyAssoc allKeys] parts: [bodyPartKeys allObjects]]; fetch = [response objectForKey: @"fetch"]; @@ -1541,7 +1550,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) } } - /* Restore unseen state once the body has been fetched */ + // Restore unseen state once the body has been fetched if ([unseenUIDs count] > 0) { response = [client storeFlags: [NSArray arrayWithObjects: @"seen", nil] diff --git a/OpenChange/MAPIStoreMailMessage.h b/OpenChange/MAPIStoreMailMessage.h index 2f6192c16..fffd0c422 100644 --- a/OpenChange/MAPIStoreMailMessage.h +++ b/OpenChange/MAPIStoreMailMessage.h @@ -74,7 +74,6 @@ /* batch-mode helpers */ - (NSString *) bodyContentPartKey; - (void) setBodyContentFromRawData: (NSData *) rawContent; -- (BOOL) read; /* Unseen from sogoObject */ @end diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index 4c6fba488..b5caf3355 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -1660,12 +1660,4 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) } } -- (BOOL) read -{ - if (!headerSetup) - [self _fetchHeaderData]; - - return [sogoObject read]; -} - @end From f0488607299e7941be4315ad1407ab125b6b7032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Fri, 13 Mar 2015 00:00:40 +0100 Subject: [PATCH 088/120] Revert "oc-mailfolder: Avoid setting seen flag on preloading message bodies" This reverts commit 7e0cddc06bc520c8eefe1b9190e92443853a15bc. --- OpenChange/MAPIStoreMailFolder.m | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index e4c4b8a9b..43f8e4d25 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -1476,10 +1476,8 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) NSUInteger count, max; NSString *messageKey, *messageUid, *bodyPartKey; NGImap4Client *client; - NSArray *fetch, *flags; + NSArray *fetch; NSData *bodyContent; - BOOL unseen; - NSMutableArray *unseenUIDs; if (tableType == MAPISTORE_MESSAGE_TABLE) { @@ -1509,25 +1507,6 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) client = [[(SOGoMailFolder *) sogoObject imap4Connection] client]; [client select: [sogoObject absoluteImap4Name]]; - - /* Fetch flags to remove seen flag if required, - as fetching a message body set the seen flag */ - response = [client fetchUids: [keyAssoc allKeys] - parts: [NSArray arrayWithObjects: @"flags", nil]]; - fetch = [response objectForKey: @"fetch"]; - max = [fetch count]; - unseenUIDs = [NSMutableArray arrayWithCapacity: max]; - for (count = 0; count < max; count++) - { - response = [fetch objectAtIndex: count]; - messageUid = [[response objectForKey: @"uid"] stringValue]; - flags = [response objectForKey: @"flags"]; - unseen = [flags indexOfObject: @"seen"] == NSNotFound; - if (unseen) { - [unseenUIDs addObject: messageUid]; - } - } - response = [client fetchUids: [keyAssoc allKeys] parts: [bodyPartKeys allObjects]]; fetch = [response objectForKey: @"fetch"]; @@ -1549,14 +1528,6 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) } } } - - // Restore unseen state once the body has been fetched - if ([unseenUIDs count] > 0) - { - response = [client storeFlags: [NSArray arrayWithObjects: @"seen", nil] - forUIDs: unseenUIDs - addOrRemove: NO]; - } } } From 1c1a75d2c16b5b331c90695f8bee31f1d3ccfd00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Fri, 13 Mar 2015 09:34:21 +0100 Subject: [PATCH 089/120] oc-mail: Use body.peek to preload message bodies In this way, we do not modify the flags (\Seen) on preloading. The IMAP server returns the content without .peek section so it is removed. This also performs the modification intended by the following Pull Request: https://github.com/Zentyal/sogo/pull/50 That tried to avoid set \Seen flag when preloading message bodies on synchronisation. But in this case we are not incrementing the modseq as we are not modifying any messages flags. --- NEWS | 1 + OpenChange/MAPIStoreMailFolder.m | 9 +++++++++ OpenChange/MAPIStoreMailMessage.m | 6 +----- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index bae4a7cd6..e05997040 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ master ------ Enhancements + - Improve sync speed from Outlook by non-reprocessing already downloaded unread mails - Give support to calendar sharing invitations - Missing contact fields are now saved and available when sharing it (Office, Profession, Manager's name, Assistant's name, Spouse/Partner, Anniversary) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 43f8e4d25..78471e49c 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -1500,6 +1500,15 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) { [bodyPartKeys addObject: bodyPartKey]; messageUid = [self messageUIDFromMessageKey: messageKey]; + /* If the bodyPartKey include peek, remove it as it is not returned + as key in the IMAP server response. + + IMAP conversation example: + a4 UID FETCH 1 (UID BODY.PEEK[text]) + * 1 FETCH (UID 1 BODY[TEXT] {1677} + */ + bodyPartKey = [bodyPartKey stringByReplacingOccurrencesOfString: @"body.peek" + withString: @"body"]; [keyAssoc setObject: bodyPartKey forKey: messageUid]; } } diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index b5caf3355..8c35f4265 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -1627,11 +1627,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) if (!headerSetup) [self _fetchHeaderData]; - if ([mimeKey hasPrefix: @"body.peek"]) - bodyPartKey = [NSString stringWithFormat: @"body[%@]", - [mimeKey _strippedBodyKey]]; - else - bodyPartKey = mimeKey; + bodyPartKey = mimeKey; return bodyPartKey; } From 0be36df21173a33d1494d2ed1e09507a525b5c02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Garc=C3=ADa?= Date: Mon, 16 Mar 2015 13:22:52 +0100 Subject: [PATCH 090/120] Preparing release for 2.2.15-zentyal2 --- NEWS | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 0fadce1bc..25166e99b 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,12 @@ master ------ +Bug fixes + - Fix server side crash parsing rtf emails with images (with word97 format) + +2.2.15-zentyal2 (2015-03-16) +---------------------------- + Enhancements - Give support to calendar sharing invitations - Missing contact fields are now saved and available when sharing it @@ -8,7 +14,6 @@ Enhancements - Appointment color and importance work now between Outlooks Bug fixes - - Fix server side crash parsing rtf emails with images (with word97 format) - Fix sender on importing email messages like event invitations - Fix Outlook crashes when modifying the view of a folder - Fix server side crash when reading some recurrence appointments From 9f3f2aebe458a6cb6ea94aa9e32d2607f83afb39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Thu, 12 Mar 2015 20:24:06 +0100 Subject: [PATCH 091/120] oc-mail: Register source message as soft deleted on movement This makes sent mails are not longer automatically copied to Drafts folder. Reasoning: When Outlook sends a mail, OpenChange submits the message and copy the message to Drafts folder. Afterwards, the client asks to move this message using SyncImportMessageMove ROP from Drafts to Sent. During this movement, the message is unregistered from the indexing database. If the client has updated Drafts folder before that movement, then the client will keep this message as the MID is not returned in oxcfxics download sync as deleted. Setting the message as soft deleted, make it work. --- NEWS | 1 + OpenChange/MAPIStoreMailFolder.m | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index bae4a7cd6..808c508e6 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ Enhancements - Appointment color and importance work now between Outlooks Bug fixes + - Sent mails are not longer in Drafts folder using Outlook - Fix sender on importing email messages like event invitations - Fix Outlook crashes when modifying the view of a folder - Fix server side crash when reading some recurrence appointments diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 0a439e29e..5c70dc634 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -1163,13 +1163,20 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) if (![[result objectForKey: @"result"] boolValue]) return MAPISTORE_ERROR; - /* "Move" treatment: Store \Deleted and unregister urls */ + /* "Move" treatment: Store \Deleted and unregister urls as soft-deleted */ if (!wantCopy) { [client storeFlags: [NSArray arrayWithObject: @"Deleted"] forUIDs: uids addOrRemove: YES]; for (count = 0; count < midCount; count++) - [mapping unregisterURLWithID: srcMids[count]]; + { + /* Using soft-deleted to make deleted fmids to return the + srcMids. + See [MAPIStoreFolder getDeletedFMIDs:andCN:fromChangeNumber:inTableType:inMemCtx] + for details */ + [mapping unregisterURLWithID: srcMids[count] + andFlags: MAPISTORE_SOFT_DELETE]; + } } /* Registration of target messages */ From 6f44ec42c1bdf934f8035bdd1fb3035bc74925d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Fri, 6 Mar 2015 13:23:17 +0100 Subject: [PATCH 092/120] oc-calendar: Fix import in SOGo exceptions from recurring series According to [MS-OXICAL] Section 2.1.3.1.1.20.13, the EXDATE property must be written only if there are ocurrences from the series that have been deleted and before this commit ModifiedInstanceDates were also included. We check against every ExceptionInfo from exception ocurrences of the series to know if the ocurrence was deleted or only modified. --- NEWS | 1 + OpenChange/MAPIStoreRecurrenceUtils.h | 7 ++- OpenChange/MAPIStoreRecurrenceUtils.m | 63 ++++++++++++++++----------- OpenChange/iCalEvent+MAPIStore.m | 12 +++-- 4 files changed, 53 insertions(+), 30 deletions(-) diff --git a/NEWS b/NEWS index 506495dc7..3069604c5 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ Enhancements - Improve sync speed from Outlook by non-reprocessing already downloaded unread mails Bug fixes + - Fix exception modifications import in recurrence series - Sent mails are not longer in Drafts folder using Outlook - Fix server side crash parsing rtf emails with images (with word97 format) diff --git a/OpenChange/MAPIStoreRecurrenceUtils.h b/OpenChange/MAPIStoreRecurrenceUtils.h index 68c84361e..df3700575 100644 --- a/OpenChange/MAPIStoreRecurrenceUtils.h +++ b/OpenChange/MAPIStoreRecurrenceUtils.h @@ -25,6 +25,8 @@ #include +#import + #import #import @@ -41,7 +43,10 @@ @interface iCalCalendar (MAPIStoreRecurrence) - (void) setupRecurrenceWithMasterEntity: (iCalRepeatableEntityObject *) entity - fromRecurrencePattern: (struct RecurrencePattern *) rp; + fromRecurrencePattern: (struct RecurrencePattern *) rp + withExceptions: (struct ExceptionInfo *) exInfos + andExceptionCount: (uint16_t) exInfoCount + inTimeZone: (NSTimeZone *) tz; @end diff --git a/OpenChange/MAPIStoreRecurrenceUtils.m b/OpenChange/MAPIStoreRecurrenceUtils.m index ebf588000..28b1be22c 100644 --- a/OpenChange/MAPIStoreRecurrenceUtils.m +++ b/OpenChange/MAPIStoreRecurrenceUtils.m @@ -24,6 +24,7 @@ #import #import #import +#import #import #import @@ -48,6 +49,10 @@ - (void) setupRecurrenceWithMasterEntity: (iCalRepeatableEntityObject *) entity fromRecurrencePattern: (struct RecurrencePattern *) rp + withExceptions: (struct ExceptionInfo *) exInfos + andExceptionCount: (uint16_t) exInfoCount + inTimeZone: (NSTimeZone *) tz + { NSCalendarDate *startDate, *olEndDate, *untilDate, *exDate; NSString *monthDay, *month; @@ -214,34 +219,42 @@ /* exception dates: - take all deleted instances - - remove all modified instances from the above set + - remove all modified instances available in ExceptionInfo from the above set - add remaining instances, in chronological order */ - exceptionDates = [NSMutableSet set]; - for (count = 0; count < rp->DeletedInstanceCount; count++) - { - exDate - = [NSDate dateFromMinutesSince1601: rp->DeletedInstanceDates[count]]; - exDate = [exDate hour: [startDate hourOfDay] - minute: [startDate minuteOfHour] - second: [startDate secondOfMinute]]; - [exceptionDates addObject: exDate]; - } - for (count = 0; count < rp->ModifiedInstanceCount; count++) - { - exDate - = [NSDate dateFromMinutesSince1601: rp->ModifiedInstanceDates[count]]; - exDate = [exDate hour: [startDate hourOfDay] - minute: [startDate minuteOfHour] - second: [startDate secondOfMinute]]; - [exceptionDates removeObject: exDate]; - } - realExDates = [[exceptionDates allObjects] - sortedArrayUsingSelector: @selector (compare:)]; - max = [realExDates count]; - for (count = 0; count < max; count++) - [entity addToExceptionDates: [realExDates objectAtIndex: count]]; + /* Heuristic to avoid these loops */ + if (rp->DeletedInstanceCount != rp->ModifiedInstanceCount) { + exceptionDates = [NSMutableSet set]; + for (count = 0; count < rp->DeletedInstanceCount; count++) + { + exDate + = [NSDate dateFromMinutesSince1601: rp->DeletedInstanceDates[count]]; + exDate = [exDate hour: [startDate hourOfDay] + minute: [startDate minuteOfHour] + second: [startDate secondOfMinute]]; + [exceptionDates addObject: exDate]; + } + /* Read the exceptions to remove the instances that are modified and not deleted */ + if (exInfos && exInfoCount > 0) + { + for (count = 0; count < exInfoCount; count++) + { + /* The OriginalStartDate is in local time */ + exDate = [NSDate dateFromMinutesSince1601: exInfos[count].OriginalStartDate]; + exDate = [exDate dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: - [tz secondsFromGMT]]; + [exceptionDates removeObject: exDate]; + } + } + + realExDates = [[exceptionDates allObjects] + sortedArrayUsingSelector: @selector (compare:)]; + max = [realExDates count]; + for (count = 0; count < max; count++) + [entity addToExceptionDates: [realExDates objectAtIndex: count]]; + } } @end diff --git a/OpenChange/iCalEvent+MAPIStore.m b/OpenChange/iCalEvent+MAPIStore.m index 3ccc31a6c..d8c016250 100644 --- a/OpenChange/iCalEvent+MAPIStore.m +++ b/OpenChange/iCalEvent+MAPIStore.m @@ -74,6 +74,7 @@ @implementation iCalEvent (MAPIStoreProperties) - (void) _setupEventRecurrence: (NSData *) mapiRecurrenceData + inTimeZone: (NSTimeZone *) tz inMemCtx: (TALLOC_CTX *) memCtx { struct Binary_r *blob; @@ -87,9 +88,12 @@ return; } - [(iCalCalendar *) parent - setupRecurrenceWithMasterEntity: self - fromRecurrencePattern: &pattern->RecurrencePattern]; + [(iCalCalendar *) parent setupRecurrenceWithMasterEntity: self + fromRecurrencePattern: &pattern->RecurrencePattern + withExceptions: pattern->ExceptionInfo + andExceptionCount: pattern->ExceptionCount + inTimeZone: tz + ]; //talloc_free (blob); } @@ -362,7 +366,7 @@ value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentRecur)]; if (value) - [self _setupEventRecurrence: value inMemCtx: memCtx]; + [self _setupEventRecurrence: value inTimeZone: userTimeZone inMemCtx: memCtx]; /* alarm */ [self _setupEventAlarmFromProperties: properties]; From fb4c3a4730a05238ef88b29715f6716b4c0057e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Tue, 10 Mar 2015 00:36:36 +0100 Subject: [PATCH 093/120] oc-calendar: Fix weekly recurring events exported to Outlook from SOGo SOGo does not create BYDAY mask in weekly recurrence, so we have to guess it from the start date's day of week. In other case, the event is not exported to Outlook and it says that is corrupted. --- NEWS | 1 + OpenChange/MAPIStoreRecurrenceUtils.m | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 3069604c5..6d01c3ea2 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ Enhancements - Improve sync speed from Outlook by non-reprocessing already downloaded unread mails Bug fixes + - Weekly recurring events created in SOGo web interface are now shown in Outlook - Fix exception modifications import in recurrence series - Sent mails are not longer in Drafts folder using Outlook - Fix server side crash parsing rtf emails with images (with word97 format) diff --git a/OpenChange/MAPIStoreRecurrenceUtils.m b/OpenChange/MAPIStoreRecurrenceUtils.m index 28b1be22c..9e0bf29c3 100644 --- a/OpenChange/MAPIStoreRecurrenceUtils.m +++ b/OpenChange/MAPIStoreRecurrenceUtils.m @@ -325,15 +325,25 @@ rp->RecurFrequency = RecurFrequency_Weekly; rp->PatternType = PatternType_Week; rp->Period = repeatInterval; + + dayOfWeek = [startDate dayOfWeek]; + mask = 0; byDayMask = [self byDayMask]; - for (count = 0; count < 7; count++) - if ([byDayMask occursOnDay: count]) - mask |= 1 << count; + if (byDayMask) + { + for (count = 0; count < 7; count++) + if ([byDayMask occursOnDay: count]) + mask |= 1 << count; + } + else + { + /* Set the recurrence pattern using start date */ + mask |= 1 << dayOfWeek; + } rp->PatternTypeSpecific.WeekRecurrencePattern = mask; /* FirstDateTime */ - dayOfWeek = [startDate dayOfWeek]; if (dayOfWeek) beginOfWeek = [startDate dateByAddingYears: 0 months: 0 days: -dayOfWeek From 637ac1e98a720fb7e1ca07d5d72ee8ad0b72d13d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Thu, 12 Mar 2015 21:36:50 +0100 Subject: [PATCH 094/120] oc-rtf: no color table definition Be able to parse rtf files without color table defined \colortbl --- NEWS | 1 + OpenChange/RTFHandler.m | 18 +++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/NEWS b/NEWS index 6d01c3ea2..2d7d7ec7a 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ Enhancements - Improve sync speed from Outlook by non-reprocessing already downloaded unread mails Bug fixes + - Fix server side crash parsing rtf without color table - Weekly recurring events created in SOGo web interface are now shown in Outlook - Fix exception modifications import in recurrence series - Sent mails are not longer in Drafts folder using Outlook diff --git a/OpenChange/RTFHandler.m b/OpenChange/RTFHandler.m index 4535626e3..e7be0f14e 100644 --- a/OpenChange/RTFHandler.m +++ b/OpenChange/RTFHandler.m @@ -824,19 +824,19 @@ const unsigned short ansicpg874[256] = { int color_index; char *v; + if (!formattingOptions) continue; + color_index = [[s substringFromIndex: 2] intValue]; - - if (!formattingOptions) - continue; - - if (formattingOptions->color_index >= 0) // && color_index != formattingOptions->color_index) + colorDef = [colorTable colorDefAtIndex: color_index]; + if (!colorDef) continue; + + if (formattingOptions->color_index >= 0) { [_html appendBytes: "" length: 7]; } - - formattingOptions->color_index = color_index; - colorDef = [colorTable colorDefAtIndex: color_index]; - + + formattingOptions->color_index = color_index; + v = malloc(23*sizeof(char)); memset(v, 0, 23); sprintf(v, "", colorDef->red, colorDef->green, colorDef->blue); From 2668bc313cdd517c7f127e921e277ea8e672b018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Antonio=20Calvo?= Date: Fri, 13 Mar 2015 18:50:10 +0100 Subject: [PATCH 095/120] oc-calendar: Fix event invitations for optional attendees Outlook sets recipient type of Required attendees as MAPI_TO and optional ones as MAPI_CC, so the fix is just to not only iterate over the "to" list of recipients but also the "cc" one. We're also setting the proper iCal value for this case (OPT-PARTICIPANT instead of REQ-PARTICIPANT) In [MS-OXOCAL] Section 2.2.4.10.7 says the recipient type is 0x01 as Required and 0x02 as Optional and other documents such as [MS-OXCMSG] 2.2.3.1.2 indicates that MAPI_TO is 0x01 and MAPI_CC is 0x02, that's why is stored in 'to' and 'cc' respectively. --- NEWS | 1 + OpenChange/iCalEvent+MAPIStore.m | 226 ++++++++++++++++--------------- 2 files changed, 117 insertions(+), 110 deletions(-) diff --git a/NEWS b/NEWS index 2d7d7ec7a..10a3737c1 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ Enhancements - Improve sync speed from Outlook by non-reprocessing already downloaded unread mails Bug fixes + - Fix reception of calendar event invitations on optional attendees - Fix server side crash parsing rtf without color table - Weekly recurring events created in SOGo web interface are now shown in Outlook - Fix exception modifications import in recurrence series diff --git a/OpenChange/iCalEvent+MAPIStore.m b/OpenChange/iCalEvent+MAPIStore.m index d8c016250..90bf4e8bd 100644 --- a/OpenChange/iCalEvent+MAPIStore.m +++ b/OpenChange/iCalEvent+MAPIStore.m @@ -141,6 +141,107 @@ } } +- (int) _updateFromAttendeeMAPIProperties: (NSArray *) recipients + withRole: (NSString *) role + outParam: (BOOL *) organizerIsSet +{ + NSDictionary *dict; + NSString *attEmail; + iCalPerson *person; + iCalPersonPartStat newPartStat; + NSNumber *flags, *trackStatus; + int i, effective; + + effective = 0; + for (i = 0; i < [recipients count]; i++) + { + dict = [recipients objectAtIndex: i]; + person = [iCalPerson new]; + [person setCn: [dict objectForKey: @"fullName"]]; + attEmail = [dict objectForKey: @"email"]; + [person setEmail: attEmail]; + + flags = [dict objectForKey: MAPIPropertyKey (PR_RECIPIENT_FLAGS)]; + if (!flags) + { + [self logWithFormat: + @"no recipient flags specified: skipping recipient"]; + continue; + } + + if (([flags unsignedIntValue] & 0x0002)) /* recipOrganizer */ + { + [self setOrganizer: person]; + *organizerIsSet = YES; + [self logWithFormat: @"organizer set via recipient flags"]; + } + else + { + BOOL isOrganizer = NO; + + // /* Work-around: it happens that Outlook still passes the + // organizer as a recipient, maybe because of a feature + // documented in a pre-mesozoic PDF still buried in a + // cavern... In that case we remove it, and we keep the + // number of effective recipients in "effective". If the + // total is 0, we remove the "ORGANIZER" too. */ + // if ([attEmail isEqualToString: orgEmail]) + // { + // [self logWithFormat: + // @"avoiding setting organizer as recipient"]; + // continue; + // } + + trackStatus = [dict objectForKey: MAPIPropertyKey (PidTagRecipientTrackStatus)]; + if (trackStatus) + { + /* FIXME: we should provide a data converter between OL + partstats and SOGo */ + switch ([trackStatus unsignedIntValue]) + { + case 0x01: /* respOrganized */ + isOrganizer = YES; + break; + case 0x02: /* respTentative */ + newPartStat = iCalPersonPartStatTentative; + break; + case 0x03: /* respAccepted */ + newPartStat = iCalPersonPartStatAccepted; + break; + case 0x04: /* respDeclined */ + newPartStat = iCalPersonPartStatDeclined; + break; + default: + newPartStat = iCalPersonPartStatNeedsAction; + } + + if (isOrganizer) + { + [self setOrganizer: person]; + *organizerIsSet = YES; + [self logWithFormat: @"organizer set via track status"]; + } + else + { + [person setParticipationStatus: newPartStat]; + [person setRsvp: @"TRUE"]; + [person setRole: role]; + [self addToAttendees: person]; + effective++; + } + } + else + [self errorWithFormat: @"skipped recipient due" + @" to missing track status"]; + } + + [person release]; + } + + return effective; +} + + - (void) updateFromMAPIProperties: (NSDictionary *) properties inUserContext: (MAPIStoreUserContext *) userContext withActiveUser: (SOGoUser *) activeUser @@ -375,106 +476,28 @@ value = [properties objectForKey: @"recipients"]; if (value) { - NSArray *recipients; NSDictionary *dict; - NSString *orgEmail, *sentBy, *attEmail; + NSString *orgEmail, *sentBy; iCalPerson *person; iCalPersonPartStat newPartStat; - NSNumber *flags, *trackStatus; - int i, effective; + int effective; BOOL organizerIsSet = NO; [self setOrganizer: nil]; [self removeAllAttendees]; - recipients = [value objectForKey: @"to"]; - effective = 0; - for (i = 0; i < [recipients count]; i++) - { - dict = [recipients objectAtIndex: i]; - person = [iCalPerson new]; - [person setCn: [dict objectForKey: @"fullName"]]; - attEmail = [dict objectForKey: @"email"]; - [person setEmail: attEmail]; - - flags = [dict objectForKey: MAPIPropertyKey (PR_RECIPIENT_FLAGS)]; - if (!flags) - { - [self logWithFormat: - @"no recipient flags specified: skipping recipient"]; - continue; - } + /* In [MS-OXOCAL] Section 2.2.4.10.7 says the recipient type is 0x01 as Required + and 0x02 as Optional and other documents such [MS-OXCMSG] 2.2.3.1.2 indicates + that MAPI_TO is 0x01 and MAPI_CC is 0x02, that's why in SOGo is in 'to' and 'cc' + respectively. */ + effective = [self _updateFromAttendeeMAPIProperties: [value objectForKey: @"to"] + withRole: @"REQ-PARTICIPANT" + outParam: &organizerIsSet]; + effective += [self _updateFromAttendeeMAPIProperties: [value objectForKey: @"cc"] + withRole: @"OPT-PARTICIPANT" + outParam: &organizerIsSet]; - if (([flags unsignedIntValue] & 0x0002)) /* recipOrganizer */ - { - [self setOrganizer: person]; - organizerIsSet = YES; - [self logWithFormat: @"organizer set via recipient flags"]; - } - else - { - BOOL isOrganizer = NO; - - // /* Work-around: it happens that Outlook still passes the - // organizer as a recipient, maybe because of a feature - // documented in a pre-mesozoic PDF still buried in a - // cavern... In that case we remove it, and we keep the - // number of effective recipients in "effective". If the - // total is 0, we remove the "ORGANIZER" too. */ - // if ([attEmail isEqualToString: orgEmail]) - // { - // [self logWithFormat: - // @"avoiding setting organizer as recipient"]; - // continue; - // } - - trackStatus = [dict objectForKey: MAPIPropertyKey (PidTagRecipientTrackStatus)]; - if (trackStatus) - { - /* FIXME: we should provide a data converter between OL - partstats and SOGo */ - switch ([trackStatus unsignedIntValue]) - { - case 0x01: /* respOrganized */ - isOrganizer = YES; - break; - case 0x02: /* respTentative */ - newPartStat = iCalPersonPartStatTentative; - break; - case 0x03: /* respAccepted */ - newPartStat = iCalPersonPartStatAccepted; - break; - case 0x04: /* respDeclined */ - newPartStat = iCalPersonPartStatDeclined; - break; - default: - newPartStat = iCalPersonPartStatNeedsAction; - } - - if (isOrganizer) - { - [self setOrganizer: person]; - organizerIsSet = YES; - [self logWithFormat: @"organizer set via track status"]; - } - else - { - [person setParticipationStatus: newPartStat]; - [person setRsvp: @"TRUE"]; - [person setRole: @"REQ-PARTICIPANT"]; - [self addToAttendees: person]; - effective++; - } - } - else - [self errorWithFormat: @"skipped recipient due" - @" to missing track status"]; - } - - [person release]; - } - - if (effective == 0) /* See work-around above */ + if (effective == 0) /* See work-around inside _updateFromAttendeeMAPIProperties */ [self setOrganizer: nil]; else { @@ -500,7 +523,7 @@ = [properties objectForKey: MAPIPropertyKey (PidLidResponseStatus)]; if (value) responseStatus = [value unsignedLongValue]; - + /* FIXME: we should provide a data converter between OL partstats and SOGo */ switch (responseStatus) @@ -522,23 +545,6 @@ value = [properties objectForKey: MAPIPropertyKey (PidLidAttendeeCriticalChange)]; if (value && ![value isNever]) [self setTimeStampAsDate: value]; - // if (newPartStat // != iCalPersonPartStatUndefined - // ) - // { - // // iCalPerson *participant; - - // // participant = [self userAsAttendee: ownerUser]; - // // [participant setParticipationStatus: newPartStat]; - // // [sogoObject saveComponent: self]; - - // [sogoObject changeParticipationStatus: newPartStat - // withDelegate: nil]; - // // [[self context] tearDownRequest]; - // } - // // }1005 - - // // else - // // { } } else @@ -553,7 +559,7 @@ [person setCn: [dict objectForKey: @"fullName"]]; orgEmail = [dict objectForKey: @"email"]; [person setEmail: orgEmail]; - + if (![activeUser isEqual: ownerUser]) { dict = [activeUser primaryIdentity]; From 8ee2303e781056d512c4d83ba76683c7c1496669 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Thu, 19 Mar 2015 00:06:14 +0100 Subject: [PATCH 096/120] oc: Empty ACL from a folder works with several users The `[SOGoFolder:aclUsers]` returns a reference to a `NSArray` which is being modified in the `for` loop making fail when more than one user is in the ACL with `NSRangeException`. --- OpenChange/MAPIStoreFolder.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index 19c826d7f..0d862b85e 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -1745,10 +1745,12 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe aclFolder = [self aclFolder]; - users = [aclFolder aclUsers]; + users = [[aclFolder aclUsers] copy]; max = [users count]; for (count = 0; count < max; count++) [aclFolder removeUserFromAcls: [users objectAtIndex: count]]; + + [users release]; } - (int) modifyPermissions: (struct PermissionData *) permissions From 6204aebf2c9143d1b124c82d9a8046944115492e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Mon, 23 Mar 2015 23:57:33 +0100 Subject: [PATCH 097/120] oc-calendar: do not crash with invalid events A failure in parsing an ICS makes return a nil calendar object. Instead of creating an appointment with nil information which can lead to crashes like the one generated creating PidLidCleanGlobalObjectId property. We return an empty message with no information which is taken into account in Outlook but not displayed like in SOGo webmail does. --- OpenChange/MAPIStoreCalendarMessage.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index 290a50bcd..f5d00e8d4 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -181,6 +181,12 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK; else { origCalendar = [sogoObject calendar: YES secure: YES]; + if (!origCalendar) + { + [self errorWithFormat: @"Incorrect calendar event %@. Empty message is created", + [self url]]; + return self; + } calendar = [origCalendar mutableCopy]; masterEvent = [[calendar events] objectAtIndex: 0]; [self _setupAttachmentParts]; From a663fdd260e0bed5e3f09b3ff1ad709037b4a553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Wed, 18 Mar 2015 23:54:10 +0100 Subject: [PATCH 098/120] oc-mail: Give support to store extra properties in versions message This is handy when you want to store properties once a mail has hit the server and thus cannot be changed. --- OpenChange/MAPIStoreMailFolder.h | 5 +++++ OpenChange/MAPIStoreMailFolder.m | 31 +++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/OpenChange/MAPIStoreMailFolder.h b/OpenChange/MAPIStoreMailFolder.h index 2263f955b..c56e74862 100644 --- a/OpenChange/MAPIStoreMailFolder.h +++ b/OpenChange/MAPIStoreMailFolder.h @@ -55,6 +55,11 @@ - (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey; - (NSData *) predecessorChangeListForMessageWithKey: (NSString *) messageKey; +/* Extra properties from mail messages that already hit the server */ +- (void) setExtraProperties: (NSDictionary *) props + forMessage: (NSString *) messageKey; +- (NSDictionary *) extraPropertiesForMessage: (NSString *) messageKey; + @end /* MAPIStoreOutboxFolder is a special subclass of MAPIStoreMailFolder where diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index ba2339586..f0a6c33bc 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -964,6 +964,37 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) return list; } +/* Management for extra properties once they already hit the IMAP server */ +- (void) setExtraProperties: (NSDictionary *) props + forMessage: (NSString *) messageKey +{ + NSMutableDictionary *extraProps, *currentProperties; + NSString *messageUid; + + messageUid = [self messageUIDFromMessageKey: messageKey]; + currentProperties = [versionsMessage properties]; + extraProps = [currentProperties objectForKey: @"ExtraMessagesProperties"]; + if (!extraProps) + { + extraProps = [NSMutableDictionary new]; + [currentProperties setObject: extraProps forKey: @"ExtraMessagesProperties"]; + [extraProps release]; + } + + [extraProps setObject: props + forKey: messageUid]; + [versionsMessage save]; +} + +- (NSDictionary *) extraPropertiesForMessage: (NSString *) messageKey +{ + NSString *messageUid; + + messageUid = [self messageUIDFromMessageKey: messageKey]; + return [[[versionsMessage properties] objectForKey: @"ExtraMessagesProperties"] + objectForKey: messageUid]; +} + - (NSArray *) getDeletedKeysFromChangeNumber: (uint64_t) changeNum andCN: (NSNumber **) cnNbr inTableType: (uint8_t) tableType From 514b1c03be190f065f45e5e205e2efd0a2d241d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Wed, 18 Mar 2015 23:57:33 +0100 Subject: [PATCH 099/120] oc-mail: Store request properties Save them in extra properties from folder container. This is required because the client once a request is accepted or denied sets these two properties and save the message again. As we cannot modify an IMAP message, we use this utility. See [MS-OXSHARE] Section 3.1.4.3 for details. --- OpenChange/MAPIStoreMailMessage.m | 26 +++++++++++- OpenChange/MAPIStoreSharingMessage.h | 9 +++- OpenChange/MAPIStoreSharingMessage.m | 63 ++++++++++++++++++++++++++-- 3 files changed, 90 insertions(+), 8 deletions(-) diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index 8c35f4265..c0ca8f9b6 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -65,7 +65,7 @@ @class iCalCalendar, iCalEvent; -static Class NSExceptionK; +static Class NSExceptionK, MAPIStoreSharingMessageK; @interface NSString (MAPIStoreMIME) @@ -108,6 +108,7 @@ static Class NSExceptionK; + (void) initialize { NSExceptionK = [NSException class]; + MAPIStoreSharingMessageK = [MAPIStoreSharingMessage class]; } - (id) init @@ -267,7 +268,8 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) a sharing object is a proxy in a mail message */ sharingMessage = [[MAPIStoreSharingMessage alloc] initWithMailHeaders: [sogoObject mailHeaders] - andConnectionInfo: [[self context] connectionInfo]]; + andConnectionInfo: [[self context] connectionInfo] + fromMessage: self]; [self addProxy: sharingMessage]; [sharingMessage release]; } @@ -1641,6 +1643,21 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) bodySetup = YES; } +- (MAPIStoreSharingMessage *) _sharingObject +{ + /* Get the sharing object if available */ + NSUInteger i, max; + id proxy; + + max = [proxies count]; + for (i = 0; i < max; i++) { + proxy = [proxies objectAtIndex: i]; + if ([proxy isKindOfClass: MAPIStoreSharingMessageK]) + return proxy; + } + return nil; +} + - (void) save: (TALLOC_CTX *) memCtx { NSNumber *value; @@ -1654,6 +1671,11 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) else /* 0: unflagged, 1: follow up complete */ [sogoObject removeFlags: @"\\Flagged"]; } + + if (mailIsSharingObject) + [[self _sharingObject] saveWithMessage: self + andSOGoObject: sogoObject]; + } @end diff --git a/OpenChange/MAPIStoreSharingMessage.h b/OpenChange/MAPIStoreSharingMessage.h index 9b62389a0..c3ca14feb 100644 --- a/OpenChange/MAPIStoreSharingMessage.h +++ b/OpenChange/MAPIStoreSharingMessage.h @@ -23,9 +23,9 @@ #ifndef MAPISTORESHARINGMESSAGE_H #define MAPISTORESHARINGMESSAGE_H +#import "MAPIStoreMailMessage.h" #import "MAPIStoreObjectProxy.h" - @interface MAPIStoreSharingMessage : MAPIStoreObjectProxy { struct mapistore_connection_info *connInfo; @@ -33,7 +33,8 @@ } - (id) initWithMailHeaders: (NSDictionary *) mailHeaders - andConnectionInfo: (struct mapistore_connection_info *) newConnInfo; + andConnectionInfo: (struct mapistore_connection_info *) newConnInfo + fromMessage: (MAPIStoreMailMessage *) msg; /* getters */ - (int) getPidLidSharingCapabilities: (void **) data @@ -89,6 +90,10 @@ - (int) getPidNameContentClass: (void **) data inMemCtx: (TALLOC_CTX *) memCtx; +/* Save */ +- (void) saveWithMessage: (MAPIStoreMailMessage *) msg + andSOGoObject: (SOGoMailObject *) sogoObject; + @end #endif /* MAPISTORECALENDARWRAPPER_H */ diff --git a/OpenChange/MAPIStoreSharingMessage.m b/OpenChange/MAPIStoreSharingMessage.m index 594863e0e..339ca0750 100644 --- a/OpenChange/MAPIStoreSharingMessage.m +++ b/OpenChange/MAPIStoreSharingMessage.m @@ -22,9 +22,11 @@ #include +#import #import #import +#import #import #import "MAPIStoreTypes.h" @@ -33,9 +35,11 @@ #import "NSString+MAPIStore.h" #import "NSValue+MAPIStore.h" +#import "MAPIStoreMailFolder.h" #import "MAPIStoreSharingMessage.h" #include +#include @implementation MAPIStoreSharingMessage @@ -52,6 +56,7 @@ - (id) initWithMailHeaders: (NSDictionary *) mailHeaders andConnectionInfo: (struct mapistore_connection_info *) newConnInfo + fromMessage: (MAPIStoreMailMessage *) msg { NSEnumerator *enumerator; NSString *key; @@ -67,6 +72,12 @@ [properties setObject: [mailHeaders objectForKey: key] forKey: key]; } + + /* Set request properties from container folder */ + NSDictionary *requestProps = [(MAPIStoreMailFolder *)[msg container] + extraPropertiesForMessage: [msg nameInContainer]]; + if (requestProps) + [properties addEntriesFromDictionary: requestProps]; } return self; @@ -368,7 +379,18 @@ enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND; id value; - value = [properties objectForKey: @"x-ms-sharing-responsetime"]; + value = [properties objectForKey: MAPIPropertyKey (PidLidSharingResponseTime)]; + if (!value) + { + value = [properties objectForKey: @"x-ms-sharing-responsetime"]; + if (value) + { + /* Here the value is a GSCBufferString */ + NSString * responseTime = [NSString stringWithUTF8String: [value UTF8String]]; + value = [NSDate dateWithString: responseTime]; + } + } + if (value) { *data = [value asFileTimeInMemCtx: memCtx]; @@ -385,7 +407,10 @@ enum mapistore_error rc = MAPISTORE_ERR_NOT_FOUND; id value; - value = [properties objectForKey: @"x-ms-sharing-responsetype"]; + value = [properties objectForKey: MAPIPropertyKey (PidLidSharingResponseType)]; + if (!value) + value = [properties objectForKey: @"x-ms-sharing-responsetype"]; + if (value) { *data = MAPILongValue (memCtx, [value intValue]); @@ -398,8 +423,38 @@ - (int) getPidNameContentClass: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - *data = talloc_strdup (memCtx, "Sharing"); - return MAPISTORE_SUCCESS; + *data = talloc_strdup (memCtx, "Sharing"); + return MAPISTORE_SUCCESS; +} + +- (void) saveWithMessage: (MAPIStoreMailMessage *) msg + andSOGoObject: (SOGoMailObject *) sogoObject +{ + /* Store PidLidSharingResponseType and PidLidSharingResponseTime if + required in versions message from the container as I don't see + other straightforward place to put that information */ + id response; + NSDictionary *propsToStore; + + response = [[msg properties] objectForKey: MAPIPropertyKey (PidLidSharingResponseType)]; + if (response) + { + /* FIXME: Is there any better way to increase the modseq? */ + [sogoObject addFlags: @"\\Draft"]; + [sogoObject removeFlags: @"\\Draft"]; + + /* Store this modification in container folder along the property values */ + propsToStore = [NSDictionary dictionaryWithObjects: + [NSArray arrayWithObjects: response, + [[msg properties] objectForKey: MAPIPropertyKey (PidLidSharingResponseTime)], + nil] + forKeys: + [NSArray arrayWithObjects: MAPIPropertyKey (PidLidSharingResponseType), + MAPIPropertyKey (PidLidSharingResponseTime), nil]]; + + [(MAPIStoreMailFolder *)[msg container] setExtraProperties: propsToStore + forMessage: [msg nameInContainer]]; + } } @end From 661b6694af3e2dacb1daa560c489b6ac9553db4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Thu, 19 Mar 2015 00:00:55 +0100 Subject: [PATCH 100/120] oc-mail: Fix several sharing properties managing * PidNameXSharingFlavor is used by Outlook 2010 so we have to store it * 0x5100 is used although it is not in spec as Sharing Flavour value when the request is denied from a message where Request + Invitation was sent. * Return properly PidNameXSharingCapabilities and PidNameXSharingFlavor as it is an string representation of a hex number * Try to guess proper sharing flavour value when it is missing --- OpenChange/MAPIStoreMailVolatileMessage.m | 30 +++++++++++++++++++++-- OpenChange/MAPIStoreSharingMessage.m | 14 ++++++----- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/OpenChange/MAPIStoreMailVolatileMessage.m b/OpenChange/MAPIStoreMailVolatileMessage.m index 77d6294ab..7ef2c2c96 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.m +++ b/OpenChange/MAPIStoreMailVolatileMessage.m @@ -28,6 +28,7 @@ #import #import #import +#import #import #import #import @@ -541,6 +542,7 @@ FillMessageHeadersFromSharingProperties (NGMutableHashMap *headers, NSDictionary about the properties */ id value; + NSNumber *sharingFlavourNum = nil; value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingCapabilities)]; if (value) @@ -549,8 +551,32 @@ FillMessageHeadersFromSharingProperties (NGMutableHashMap *headers, NSDictionary value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingFlavor)]; if (value) - [headers setObject: value - forKey: @"X-MS-Sharing-Flavor"]; + sharingFlavourNum = (NSNumber *)value; + else + { + value = [mailProperties objectForKey: MAPIPropertyKey (PidNameXSharingFlavor)]; + if (value) + { + /* Transform the hex string to unsigned int */ + NSScanner *scanner; + unsigned int sharingFlavour; + scanner = [NSScanner scannerWithString:value]; + if ([scanner scanHexInt:&sharingFlavour]) + sharingFlavourNum =[NSNumber numberWithUnsignedInt: sharingFlavour]; + } + } + if (sharingFlavourNum) + { + if ([sharingFlavourNum unsignedIntegerValue] == 0x5100) + { + /* 0x5100 sharing flavour is not in standard but it seems to + be a denial of request + invitation message so we store + deny sharing flavour */ + sharingFlavourNum = [NSNumber numberWithUnsignedInt: 0x25100]; + } + [headers setObject: sharingFlavourNum + forKey: @"X-MS-Sharing-Flavor"]; + } value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingInitiatorEntryId)]; if (value) diff --git a/OpenChange/MAPIStoreSharingMessage.m b/OpenChange/MAPIStoreSharingMessage.m index 339ca0750..67a133bd8 100644 --- a/OpenChange/MAPIStoreSharingMessage.m +++ b/OpenChange/MAPIStoreSharingMessage.m @@ -134,7 +134,8 @@ value = [properties objectForKey: @"x-ms-sharing-capabilities"]; if (value) { - *data = [[value stringValue] asUnicodeInMemCtx: memCtx]; + *data = [[NSString stringWithFormat:@"%X", [value intValue]] + asUnicodeInMemCtx: memCtx]; rc = MAPISTORE_SUCCESS; } @@ -177,7 +178,7 @@ if ([value intValue] == 0x40290) /* Special folder */ { value = [properties objectForKey: @"x-ms-sharing-responsetime"]; - auxValue = [properties objectForKey: @"x-ms-sharing-remotename"]; + auxValue = [properties objectForKey: @"x-ms-sharing-remoteuid"]; if (value) /* A sharing request */ { if (auxValue) @@ -187,10 +188,10 @@ } else { - if (auxValue) /* It SHOULD be an invitation or response acceptance */ + if (auxValue) /* It SHOULD be an invitation or response */ *data = MAPILongValue (memCtx, 0x20310); - else - *data = MAPILongValue (memCtx, 0x23310); + else /* No remote info, then denial */ + *data = MAPILongValue (memCtx, 0x25100); } } else @@ -213,7 +214,8 @@ value = [properties objectForKey: @"x-ms-sharing-flavor"]; if (value) { - *data = [[value stringValue] asUnicodeInMemCtx: memCtx]; + *data = [[NSString stringWithFormat:@"%X", [value intValue]] + asUnicodeInMemCtx: memCtx]; rc = MAPISTORE_SUCCESS; } From f9c8661fe6308e795ac098f85de2407344342869 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Wed, 25 Mar 2015 00:03:51 +0100 Subject: [PATCH 101/120] oc-mail: Use constant names in props value This gives to the developer more information about the property values for PidLidSharingFlavor and PidLidSharingCapabilities. --- OpenChange/MAPIStoreMailVolatileMessage.m | 2 +- OpenChange/MAPIStoreSharingMessage.h | 2 ++ OpenChange/MAPIStoreSharingMessage.m | 13 +++++++------ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/OpenChange/MAPIStoreMailVolatileMessage.m b/OpenChange/MAPIStoreMailVolatileMessage.m index 7ef2c2c96..b5239f193 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.m +++ b/OpenChange/MAPIStoreMailVolatileMessage.m @@ -572,7 +572,7 @@ FillMessageHeadersFromSharingProperties (NGMutableHashMap *headers, NSDictionary /* 0x5100 sharing flavour is not in standard but it seems to be a denial of request + invitation message so we store deny sharing flavour */ - sharingFlavourNum = [NSNumber numberWithUnsignedInt: 0x25100]; + sharingFlavourNum = [NSNumber numberWithUnsignedInt: SHARING_DENY_REQUEST]; } [headers setObject: sharingFlavourNum forKey: @"X-MS-Sharing-Flavor"]; diff --git a/OpenChange/MAPIStoreSharingMessage.h b/OpenChange/MAPIStoreSharingMessage.h index c3ca14feb..7db7f552f 100644 --- a/OpenChange/MAPIStoreSharingMessage.h +++ b/OpenChange/MAPIStoreSharingMessage.h @@ -26,6 +26,8 @@ #import "MAPIStoreMailMessage.h" #import "MAPIStoreObjectProxy.h" +#define SHARING_SPECIAL_FOLDER 0x40290 + @interface MAPIStoreSharingMessage : MAPIStoreObjectProxy { struct mapistore_connection_info *connInfo; diff --git a/OpenChange/MAPIStoreSharingMessage.m b/OpenChange/MAPIStoreSharingMessage.m index 67a133bd8..ba0c74132 100644 --- a/OpenChange/MAPIStoreSharingMessage.m +++ b/OpenChange/MAPIStoreSharingMessage.m @@ -38,6 +38,7 @@ #import "MAPIStoreMailFolder.h" #import "MAPIStoreSharingMessage.h" +#include #include #include @@ -175,28 +176,28 @@ value = [properties objectForKey: @"x-ms-sharing-capabilities"]; if (value) { - if ([value intValue] == 0x40290) /* Special folder */ + if ([value intValue] == SHARING_SPECIAL_FOLDER) { value = [properties objectForKey: @"x-ms-sharing-responsetime"]; auxValue = [properties objectForKey: @"x-ms-sharing-remoteuid"]; if (value) /* A sharing request */ { if (auxValue) - *data = MAPILongValue (memCtx, 0x20710); + *data = MAPILongValue (memCtx, SHARING_INVITATION_REQUEST_FOLDER); else - *data = MAPILongValue (memCtx, 0x20500); + *data = MAPILongValue (memCtx, SHARING_REQUEST_SPECIAL_FOLDER); } else { if (auxValue) /* It SHOULD be an invitation or response */ - *data = MAPILongValue (memCtx, 0x20310); + *data = MAPILongValue (memCtx, SHARING_INVITATION_SPECIAL_FOLDER); else /* No remote info, then denial */ - *data = MAPILongValue (memCtx, 0x25100); + *data = MAPILongValue (memCtx, SHARING_DENY_REQUEST); } } else { - *data = MAPILongValue (memCtx, 0x310); + *data = MAPILongValue (memCtx, SHARING_INVITATION_FOLDER); } rc = MAPISTORE_SUCCESS; } From 82fb03b67b7106aea8b489e21b03225bcb761faa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Wed, 25 Mar 2015 16:53:42 +0100 Subject: [PATCH 102/120] oc-mail: Ensure we are creating folder to the right user As it happened with dba17fb if we interleave requests from different users while creating a folder we can create the folder in other user's mailbox as latest activeUser is the one from latest sogo_context_get_root_folder call. This is for me a lack of right design and a workaround only fixing this issue but not the root cause. --- OpenChange/MAPIStoreMailFolder.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index ba2339586..72f909d2a 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -179,6 +179,12 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; { nameInContainer = [NSString stringWithFormat: @"folder%@", [[folderName stringByEncodingImap4FolderName] asCSSIdentifier]]; + + /* it may be the operation is interleaved with operations + from other users having cached information in the thread + with the other user, so it'd better activate the user again here... */ + [[self userContext] activateWithUser: [[[self userContext] woContext] activeUser]]; + newFolder = [SOGoMailFolderK objectWithName: nameInContainer inContainer: sogoObject]; if ([newFolder create]) From a47f1de6074c7604b794c2ba507e96a2b63cfd86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Thu, 26 Mar 2015 14:18:34 +0100 Subject: [PATCH 103/120] oc-mail: Update place for Sharing Flavour prop values It has been moved in OpenChange --- OpenChange/MAPIStoreSharingMessage.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenChange/MAPIStoreSharingMessage.m b/OpenChange/MAPIStoreSharingMessage.m index ba0c74132..e1e0e79da 100644 --- a/OpenChange/MAPIStoreSharingMessage.m +++ b/OpenChange/MAPIStoreSharingMessage.m @@ -29,7 +29,6 @@ #import #import -#import "MAPIStoreTypes.h" #import "NSData+MAPIStore.h" #import "NSDate+MAPIStore.h" #import "NSString+MAPIStore.h" @@ -37,8 +36,9 @@ #import "MAPIStoreMailFolder.h" #import "MAPIStoreSharingMessage.h" +#import "MAPIStoreTypes.h" -#include +#include #include #include From dc869ce106dad20c0fc8595ae283e77de3042a64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Tue, 24 Mar 2015 18:05:58 +0100 Subject: [PATCH 104/120] oc-mail: Support for PidTagTransportMessageHeaders property This property is needed to show the 'Internet Headers' in Outlook. Outlook 2010 shows them in the properties dialog of a message. Outlook 2007 show them in message options section from context menu of a mail message. The property is defined in [MS-OXOMSG] section 2.2.1.61. The property is formed concatenating the mail message headers properly mime encoded. The headers are appended in no defined order. --- NEWS | 3 +++ OpenChange/MAPIStoreMailMessage.m | 36 +++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/NEWS b/NEWS index de3f185d6..35bba884d 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ master ------ +New features + - Internet headers are now shown in Outlook + Enhancements - Sharing request among different Outlook versions - Improve sync speed from Outlook by non-reprocessing already downloaded unread mails diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index c0ca8f9b6..11eb24d03 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -32,6 +32,7 @@ #import #import #import +#import #import #import #import @@ -1396,6 +1397,41 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) : MAPISTORE_ERR_NOT_FOUND); } +- (int) getPidTagTransportMessageHeaders: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSDictionary *mailHeaders; + NSEnumerator *keyEnumerator; + NSMutableArray *headers; + NGMimeMessageGenerator *g; + NSString *headerKey, *fullHeader, *headerGenerated; + id headerValue; + NSData *headerData; + + /* Let's encode each mail header and put them on 'headers' array */ + mailHeaders = [sogoObject mailHeaders]; + headers = [NSMutableArray arrayWithCapacity: [mailHeaders count]]; + + g = [[NGMimeMessageGenerator alloc] init]; + keyEnumerator = [mailHeaders keyEnumerator]; + while ((headerKey = [keyEnumerator nextObject])) + { + headerValue = [mailHeaders objectForKey: headerKey]; + + headerData = [g generateDataForHeaderField: headerKey value: headerValue]; + headerGenerated = [[NSString alloc] initWithData: headerData encoding:NSUTF8StringEncoding]; + fullHeader = [NSString stringWithFormat:@"%@: %@", headerKey, headerGenerated]; + [headerGenerated release]; + + [headers addObject: fullHeader]; + } + [g release]; + + *data = [[headers componentsJoinedByString:@"\n"] asUnicodeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + - (void) getMessageData: (struct mapistore_message **) dataPtr inMemCtx: (TALLOC_CTX *) memCtx { From 06476abdf7018337116b1608ffe2016196f3924c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Thu, 26 Mar 2015 22:05:43 +0100 Subject: [PATCH 105/120] oc-mail: return soft-deleted mails while syncing As well as hard deleted As explained in [MS-OXCFXICS] Section 2.2.1.3.1, the property MetaTagIdsetDeleted must include both types of messages and this idset is filled with the return value of this message. --- OpenChange/MAPIStoreMailFolder.m | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index e8f25e183..11e1154be 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -1009,6 +1009,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) NSString *changeNumber; uint64_t modseq; NSDictionary *versionProperties; + EOQualifier *deletedQualifier, *kvQualifier, *searchQualifier; if (tableType == MAPISTORE_MESSAGE_TABLE) { @@ -1017,8 +1018,33 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) unsignedLongLongValue]; if (modseq > 0) { + /* Hard deleted items */ deletedUIDs = [(SOGoMailFolder *) sogoObject fetchUIDsOfVanishedItems: modseq]; + + /* Soft deleted items */ + kvQualifier = [[EOKeyValueQualifier alloc] + initWithKey: @"modseq" + operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo + value: [NSNumber numberWithUnsignedLongLong: modseq]]; + deletedQualifier + = [[EOKeyValueQualifier alloc] + initWithKey: @"FLAGS" + operatorSelector: EOQualifierOperatorContains + value: [NSArray arrayWithObject: @"Deleted"]]; + + searchQualifier = [[EOAndQualifier alloc] + initWithQualifiers: + kvQualifier, deletedQualifier, nil]; + + deletedUIDs = [deletedUIDs arrayByAddingObjectsFromArray: + [sogoObject fetchUIDsMatchingQualifier: searchQualifier + sortOrdering: nil]]; + + [deletedQualifier release]; + [kvQualifier release]; + [searchQualifier release]; + deletedKeys = [deletedUIDs stringsWithFormat: @"%@.eml"]; if ([deletedUIDs count] > 0) { From dfde498b7c170cd0c92bf75e74dd8c47d8764fa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Thu, 26 Mar 2015 22:45:13 +0100 Subject: [PATCH 106/120] oc-mail: Include Deleted flagged messages on syncing cache This gives an accurate value for SyncLastDeletedMessage --- OpenChange/MAPIStoreMailFolder.m | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 11e1154be..07d1debe2 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -519,7 +519,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) *nextModseq; NSString *changeNumber, *uid, *messageKey; uint64_t lastModseqNbr; - EOQualifier *kvQualifier, *searchQualifier; + EOQualifier *searchQualifier; NSArray *uids, *changeNumbers; NSUInteger count, max; NSArray *fetchResults; @@ -560,14 +560,11 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) { lastModseqNbr = [lastModseq unsignedLongLongValue]; nextModseq = [NSNumber numberWithUnsignedLongLong: lastModseqNbr + 1]; - kvQualifier = [[EOKeyValueQualifier alloc] + searchQualifier = [[EOKeyValueQualifier alloc] initWithKey: @"modseq" operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo value: nextModseq]; - searchQualifier = [[EOAndQualifier alloc] - initWithQualifiers: - kvQualifier, [self nonDeletedQualifier], nil]; - [kvQualifier release]; + [searchQualifier autorelease]; } else @@ -595,7 +592,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) fetchResults = [(NSDictionary *) [sogoObject fetchUIDs: uids - parts: [NSArray arrayWithObject: @"modseq"]] + parts: [NSArray arrayWithObjects: @"modseq", @"flags", nil]] objectForKey: @"fetch"]; /* NOTE: we sort items manually because Cyrus does not properly sort @@ -631,17 +628,22 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) if (!lastModseq || ([lastModseq compare: modseq] == NSOrderedAscending)) lastModseq = modseq; + + if ([[result objectForKey: @"flags"] containsObject: @"deleted"]) + [currentProperties setObject: changeNumber + forKey: @"SyncLastDeleteChangeNumber"]; } [currentProperties setObject: lastModseq forKey: @"SyncLastModseq"]; foundChange = YES; } - /* 2. we synchronise deleted UIDs */ + /* 2. we synchronise expunged UIDs */ if (initialLastModseq) { fetchResults = [(SOGoMailFolder *) sogoObject fetchUIDsOfVanishedItems: lastModseqNbr]; + max = [fetchResults count]; changeNumber = nil; @@ -769,7 +771,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) if (!messageEntry) { fetchResults = [(NSDictionary *) [sogoObject fetchUIDs: [NSArray arrayWithObject: messageUID] - parts: [NSArray arrayWithObject: @"modseq"]] + parts: [NSArray arrayWithObjects: @"modseq", @"flags", nil]] objectForKey: @"fetch"]; if ([fetchResults count] == 1) { @@ -795,6 +797,11 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) mapping = [currentProperties objectForKey: @"VersionMapping"]; [mapping setObject: modseq forKey: changeNumberStr]; + /* Store the last deleted change number if it is soft-deleted */ + if ([[result objectForKey: @"flags"] containsObject: @"deleted"]) + [currentProperties setObject: changeNumberStr + forKey: @"SyncLastDeleteChangeNumber"]; + /* Save the message */ [versionsMessage save]; return YES; From 95a8a9316a8723999fc12de4c97fcc4f0c95c0c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Thu, 26 Mar 2015 23:43:28 +0100 Subject: [PATCH 107/120] oc: Use new OC_DEBUG macro Avoiding the usage of __FUNCTION__ and __LINE__ and more related with the logging system is being in place for OpenChange. As well as set the proper level to some debug messages. --- OpenChange/MAPIStoreSOGo.m | 107 +++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 45 deletions(-) diff --git a/OpenChange/MAPIStoreSOGo.m b/OpenChange/MAPIStoreSOGo.m index 56d9cd4d0..4ec0ba53a 100644 --- a/OpenChange/MAPIStoreSOGo.m +++ b/OpenChange/MAPIStoreSOGo.m @@ -47,6 +47,7 @@ #import "NSObject+MAPIStore.h" #import "NSString+MAPIStore.h" +#include #include #include #include @@ -58,8 +59,8 @@ static BOOL initialization_done = NO; #define NS_CURRENT_THREAD_REGISTER() \ BOOL __nsrct_thread_registered = GSRegisterCurrentThread(); \ if (!initialization_done) { \ - DEBUG(5, ("[SOGo: %s:%d] You should call sogo_backend_init() first. Current thread: %p, pid: %d\n", \ - __FUNCTION__, __LINE__, GSCurrentThread(), getpid())); \ + OC_DEBUG(5, "[SOGo] You should call sogo_backend_init() first. Current thread: %p, pid: %d\n", \ + GSCurrentThread(), getpid()); \ } #define NS_CURRENT_THREAD_TRY_UNREGISTER() \ if (__nsrct_thread_registered) { \ @@ -144,7 +145,7 @@ sogo_backend_init (void) GSRegisterCurrentThread(); if (initialization_done) { - DEBUG(0, ("SOGo backend already initialized.\n")); + OC_DEBUG(5, "[SOGo] SOGo backend already initialized.\n"); return MAPISTORE_SUCCESS; } @@ -189,7 +190,7 @@ sogo_backend_init (void) [pool release]; - DEBUG(0, ("[SOGo: %s:%d] backend init SUCCESS. Current thread: %p, pid: %d\n", __FUNCTION__, __LINE__, GSCurrentThread(), getpid())); + OC_DEBUG(5, "[SOGo] backend init SUCCESS. Current thread: %p, pid: %d\n", GSCurrentThread(), getpid()); initialization_done = YES; return MAPISTORE_SUCCESS; @@ -213,7 +214,7 @@ sogo_backend_create_context(TALLOC_CTX *mem_ctx, MAPIStoreContext *context; int rc; - DEBUG(0, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); NS_CURRENT_THREAD_REGISTER(); pool = [NSAutoreleasePool new]; @@ -250,7 +251,7 @@ sogo_backend_create_root_folder (const char *username, NSString *mapistoreUri; int rc; - DEBUG(0, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); NS_CURRENT_THREAD_REGISTER(); pool = [NSAutoreleasePool new]; @@ -287,7 +288,7 @@ sogo_backend_list_contexts(const char *username, struct indexing_context *indexi NSString *userName; int rc; - DEBUG(0, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); NS_CURRENT_THREAD_REGISTER(); pool = [NSAutoreleasePool new]; @@ -335,7 +336,7 @@ sogo_context_get_path(void *backend_object, TALLOC_CTX *mem_ctx, MAPIStoreContext *context; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (backend_object) { @@ -369,7 +370,7 @@ sogo_context_get_root_folder(void *backend_object, TALLOC_CTX *mem_ctx, MAPIStoreFolder *folder; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (backend_object) { @@ -412,7 +413,7 @@ sogo_folder_open_folder(void *folder_object, TALLOC_CTX *mem_ctx, uint64_t fid, MAPIStoreFolder *folder, *childFolder; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (folder_object) { @@ -456,7 +457,7 @@ sogo_folder_create_folder(void *folder_object, TALLOC_CTX *mem_ctx, MAPIStoreFolder *folder, *childFolder; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (folder_object) { @@ -499,7 +500,7 @@ sogo_folder_delete(void *folder_object) MAPIStoreFolder *folder; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (folder_object) { @@ -531,7 +532,7 @@ sogo_folder_get_child_count(void *folder_object, enum mapistore_table_type table MAPIStoreFolder *folder; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (folder_object) { @@ -567,7 +568,7 @@ sogo_folder_open_message(void *folder_object, MAPIStoreMessage *message; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (folder_object) { @@ -609,7 +610,7 @@ sogo_folder_create_message(void *folder_object, MAPIStoreMessage *message; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (folder_object) { @@ -645,7 +646,7 @@ sogo_folder_delete_message(void *folder_object, uint64_t mid, uint8_t flags) MAPIStoreFolder *folder; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (folder_object) { @@ -683,7 +684,7 @@ sogo_folder_move_copy_messages(void *folder_object, struct MAPIStoreTallocWrapper *wrapper; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (folder_object) { @@ -727,7 +728,7 @@ sogo_folder_move_folder(void *folder_object, void *target_folder_object, struct MAPIStoreTallocWrapper *wrapper; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (folder_object) { @@ -777,7 +778,7 @@ sogo_folder_copy_folder(void *folder_object, void *target_folder_object, TALLOC_ struct MAPIStoreTallocWrapper *wrapper; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (folder_object) { @@ -821,7 +822,7 @@ sogo_folder_get_deleted_fmids(void *folder_object, TALLOC_CTX *mem_ctx, MAPIStoreFolder *folder; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (folder_object) { @@ -860,7 +861,7 @@ sogo_folder_open_table(void *folder_object, TALLOC_CTX *mem_ctx, MAPIStoreTable *table; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (folder_object) { @@ -899,7 +900,7 @@ sogo_folder_modify_permissions(void *folder_object, uint8_t flags, MAPIStoreFolder *folder; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (folder_object) { @@ -933,7 +934,7 @@ sogo_folder_preload_message_bodies(void *folder_object, enum mapistore_table_typ MAPIStoreFolder *folder; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (folder_object) { @@ -968,7 +969,7 @@ sogo_message_get_message_data(void *message_object, MAPIStoreMessage *message; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (message_object) { @@ -1003,7 +1004,7 @@ sogo_message_create_attachment (void *message_object, TALLOC_CTX *mem_ctx, void MAPIStoreAttachment *attachment; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (message_object) { @@ -1040,7 +1041,7 @@ sogo_message_open_attachment (void *message_object, TALLOC_CTX *mem_ctx, MAPIStoreAttachment *attachment; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (message_object) { @@ -1076,7 +1077,7 @@ sogo_message_get_attachment_table (void *message_object, TALLOC_CTX *mem_ctx, vo MAPIStoreAttachmentTable *table; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (message_object) { @@ -1115,7 +1116,8 @@ sogo_message_modify_recipients (void *message_object, MAPIStoreMessage *message; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); + if (message_object) { @@ -1150,7 +1152,8 @@ sogo_message_set_read_flag (void *message_object, uint8_t flag) MAPIStoreMessage *message; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); + if (message_object) { @@ -1183,7 +1186,8 @@ sogo_message_save (void *message_object, TALLOC_CTX *mem_ctx) MAPIStoreMessage *message; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); + if (message_object) { @@ -1216,7 +1220,8 @@ sogo_message_submit (void *message_object, enum SubmitFlags flags) MAPIStoreMailVolatileMessage *message; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); + if (message_object) { @@ -1254,7 +1259,8 @@ sogo_message_attachment_open_embedded_message (void *attachment_object, MAPIStoreEmbeddedMessage *message; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); + if (attachment_object) { @@ -1295,7 +1301,8 @@ sogo_message_attachment_create_embedded_message (void *attachment_object, MAPIStoreEmbeddedMessage *message; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); + if (attachment_object) { @@ -1331,7 +1338,8 @@ static enum mapistore_error sogo_table_get_available_properties(void *table_obje MAPIStoreTable *table; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); + if (table_object) { @@ -1363,7 +1371,8 @@ sogo_table_set_columns (void *table_object, uint16_t count, enum MAPITAGS *prope MAPIStoreTable *table; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); + if (table_object) { @@ -1396,7 +1405,8 @@ sogo_table_set_restrictions (void *table_object, struct mapi_SRestriction *restr MAPIStoreTable *table; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); + if (table_object) { @@ -1431,7 +1441,8 @@ sogo_table_set_sort_order (void *table_object, struct SSortOrderSet *sort_order, MAPIStoreTable *table; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); + if (table_object) { @@ -1468,7 +1479,8 @@ sogo_table_get_row (void *table_object, TALLOC_CTX *mem_ctx, MAPIStoreTable *table; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); + if (table_object) { @@ -1503,7 +1515,8 @@ sogo_table_get_row_count (void *table_object, MAPIStoreTable *table; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); + if (table_object) { @@ -1536,7 +1549,8 @@ sogo_table_handle_destructor (void *table_object, uint32_t handle_id) MAPIStoreTable *table; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); + if (table_object) { @@ -1570,7 +1584,8 @@ static enum mapistore_error sogo_properties_get_available_properties(void *objec MAPIStoreObject *propObject; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); + if (object) { @@ -1605,7 +1620,8 @@ sogo_properties_get_properties (void *object, MAPIStoreObject *propObject; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); + if (object) { @@ -1639,7 +1655,8 @@ sogo_properties_set_properties (void *object, struct SRow *aRow) MAPIStoreObject *propObject; int rc; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); + if (object) { @@ -1674,7 +1691,7 @@ sogo_manager_generate_uri (TALLOC_CTX *mem_ctx, NSAutoreleasePool *pool; NSString *partialURLString, *username, *directory; - DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + OC_DEBUG(5, "[SOGo]"); if (uri == NULL) return MAPISTORE_ERR_INVALID_PARAMETER; @@ -1779,7 +1796,7 @@ int mapistore_init_backend(void) /* Register ourselves with the MAPISTORE subsystem */ ret = mapistore_backend_register (&backend); if (ret != MAPISTORE_SUCCESS) - DEBUG(0, ("Failed to register the '%s' mapistore backend!\n", backend.backend.name)); + OC_DEBUG(0, "[SOGo] Failed to register the '%s' mapistore backend!\n", backend.backend.name); } return ret; From 914e7b7418128dbc112746d4b58a81eef2a64d88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Garc=C3=ADa?= Date: Tue, 14 Apr 2015 11:44:32 +0200 Subject: [PATCH 108/120] Prepare for new 2.2.15-zentyal3 version --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 38c6e8f3e..ca588d178 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -master +2.2.15-zentyal3 (2015-04-14) ------ New features From 1d6f1a83af84b563914e5f47ddafdb093b9b2016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Tue, 14 Apr 2015 13:08:21 +0200 Subject: [PATCH 109/120] use full login for sogo_cache_folder tables So when multidomain is enabled we will have tables like sogo_cache_folder_user_A_domain_D_com instead of just sogo_cache_folder_user If multidomain is disabled the folders will still be like sogo_cache_folder_user --- ActiveSync/SOGoActiveSyncDispatcher.m | 2 +- OpenChange/MAPIStoreUserContext.m | 6 +++--- Tools/SOGoToolManageEAS.m | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ActiveSync/SOGoActiveSyncDispatcher.m b/ActiveSync/SOGoActiveSyncDispatcher.m index ff9321f92..d6b854df9 100644 --- a/ActiveSync/SOGoActiveSyncDispatcher.m +++ b/ActiveSync/SOGoActiveSyncDispatcher.m @@ -2644,7 +2644,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. parts in this url. We strip the '-' character in case we have this in the domain part - like foo@bar-zot.com */ ocFSTableName = [NSMutableString stringWithFormat: @"sogo_cache_folder_%@", - [[user loginInDomain] asCSSIdentifier]]; + [[user login] asCSSIdentifier]]; [ocFSTableName replaceOccurrencesOfString: @"-" withString: @"_" options: 0 diff --git a/OpenChange/MAPIStoreUserContext.m b/OpenChange/MAPIStoreUserContext.m index 04300fd35..159748519 100644 --- a/OpenChange/MAPIStoreUserContext.m +++ b/OpenChange/MAPIStoreUserContext.m @@ -311,9 +311,9 @@ static NSMapTable *contextsTable = nil; parts in this url. We strip the '-' character in case we have this in the domain part - like foo@bar-zot.com */ ocFSTableName = [NSString stringWithFormat: @"sogo_cache_folder_%@", - [[[user loginInDomain] asCSSIdentifier] - stringByReplacingOccurrencesOfString: @"-" - withString: @"_"]]; + [[[user login] asCSSIdentifier] + stringByReplacingOccurrencesOfString: @"-" + withString: @"_"]]; [parts replaceObjectAtIndex: 4 withObject: ocFSTableName]; folderTableURL = [NSURL URLWithString: [parts componentsJoinedByString: @"/"]]; diff --git a/Tools/SOGoToolManageEAS.m b/Tools/SOGoToolManageEAS.m index 0d8a7d772..0e01da733 100644 --- a/Tools/SOGoToolManageEAS.m +++ b/Tools/SOGoToolManageEAS.m @@ -142,7 +142,7 @@ typedef enum parts in this url. We strip the '-' character in case we have this in the domain part - like foo@bar-zot.com */ ocFSTableName = [NSMutableString stringWithFormat: @"sogo_cache_folder_%@", - [[user loginInDomain] asCSSIdentifier]]; + [[user login] asCSSIdentifier]]; [ocFSTableName replaceOccurrencesOfString: @"-" withString: @"_" options: 0 From 210053ea20ef9b803b7486e700576bc33e70330f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Garc=C3=ADa?= Date: Fri, 10 Apr 2015 18:50:47 +0200 Subject: [PATCH 110/120] Adding missing build dependency gnulib --- SoObjects/SOGo/NSData+Crypto.m | 1 + packaging/debian/control | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/SoObjects/SOGo/NSData+Crypto.m b/SoObjects/SOGo/NSData+Crypto.m index d869f9b68..b449664e2 100644 --- a/SoObjects/SOGo/NSData+Crypto.m +++ b/SoObjects/SOGo/NSData+Crypto.m @@ -39,6 +39,7 @@ #include #include #include +#include #define MD4_DIGEST_LENGTH 16 #define MD5_DIGEST_LENGTH 16 #define SHA_DIGEST_LENGTH 20 diff --git a/packaging/debian/control b/packaging/debian/control index ceee29543..cbe90d8e4 100644 --- a/packaging/debian/control +++ b/packaging/debian/control @@ -1,7 +1,7 @@ Source: sogo Priority: optional Maintainer: Inverse Support -Build-Depends: debhelper (>= 7.0.15), gobjc | objc-compiler, libgnustep-base-dev, libsope-appserver4.9-dev, libsope-core4.9-dev, libsope-gdl1-4.9-dev, libsope-ldap4.9-dev, libsope-mime4.9-dev, libsope-xml4.9-dev, libmemcached-dev, libxml2-dev, libsbjson-dev, libssl-dev, libcurl4-openssl-dev | libcurl4-gnutls-dev, libwbxml2-dev (>= 0.11.2), liblasso3-dev (>= 2.3.5) +Build-Depends: debhelper (>= 7.0.15), gobjc | objc-compiler, libgnustep-base-dev, libsope-appserver4.9-dev, libsope-core4.9-dev, libsope-gdl1-4.9-dev, libsope-ldap4.9-dev, libsope-mime4.9-dev, libsope-xml4.9-dev, libmemcached-dev, libxml2-dev, libsbjson-dev, libssl-dev, libcurl4-openssl-dev | libcurl4-gnutls-dev, libwbxml2-dev (>= 0.11.2), liblasso3-dev (>= 2.3.5), gnulib Section: web Standards-Version: 3.9.1 From f0a3fdae5bdfa242d8b4a6b01025195c0eb4a620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Wed, 15 Apr 2015 14:31:42 +0200 Subject: [PATCH 111/120] configure: Fix gnulib/crypto/md4 dependency Gnulib project needs Autoconf to be able to import their modules with gnulib-tool http://www.gnu.org/software/gnulib/manual/html_node/Initial-import.html#Initial-import We only need md4.c file so this is a workaround to compile it without using gnulib-tool --import --- SoObjects/SOGo/.gitignore | 2 ++ SoObjects/SOGo/GNUmakefile.preamble | 2 ++ configure | 39 +++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 SoObjects/SOGo/.gitignore diff --git a/SoObjects/SOGo/.gitignore b/SoObjects/SOGo/.gitignore new file mode 100644 index 000000000..8fa5151fd --- /dev/null +++ b/SoObjects/SOGo/.gitignore @@ -0,0 +1,2 @@ +config.h +md4.c diff --git a/SoObjects/SOGo/GNUmakefile.preamble b/SoObjects/SOGo/GNUmakefile.preamble index b7456f8bd..8a484d3a1 100644 --- a/SoObjects/SOGo/GNUmakefile.preamble +++ b/SoObjects/SOGo/GNUmakefile.preamble @@ -30,6 +30,8 @@ SOGo_LIBRARIES_DEPEND_UPON += \ ifeq ($(HAS_LIBRARY_gnutls),yes) ADDITIONAL_CPPFLAGS += -DHAVE_GNUTLS=1 SOGo_LIBRARIES_DEPEND_UPON += -lgnutls +ADDITIONAL_INCLUDE_DIRS += -I$(GNULIB_INCLUDE) +SOGo_C_FILES += $(GNULIB_FILES) else ifeq ($(HAS_LIBRARY_ssl),yes) ADDITIONAL_CPPFLAGS += -DHAVE_OPENSSL=1 diff --git a/configure b/configure index 94d933fe7..0a3acdc06 100755 --- a/configure +++ b/configure @@ -374,6 +374,41 @@ EOF return $LINK_RESULT } + +# gnulib requires autoconf https://www.gnu.org/software/gnulib/manual/html_node/Initial-import.html +# We only require crypyo/md4 module (no dependencies, two files) when using gnutls +# Workaround: copy manually the files to the project needed (md4.c) +# Really ugly but it works, glad to change this to better alternative. +gnulib_dir=/usr/share/gnulib/lib + +checkGnulib() { + if test ! -d $gnulib_dir; then + echo "When using --with-ssl=gnutls option gnulib package is required to be installed in $gnulib_dir" + exit 1 + fi + cfgwrite "GNULIB_INCLUDE := $gnulib_dir" +} + +gnulibMd4() { + local source_files="md4.c" + local local_gnulib_dir="SoObjects/SOGo" + + for source_file in $source_files; do + if test -f $gnulib_dir/$source_file; then + cp $gnulib_dir/$source_file $local_gnulib_dir + else + echo "Error with gnulib file $source_file, gnulib package not installed?" + exit 1 + fi + done + + # md4.c requires config.h, create empty one + touch $local_gnulib_dir/config.h + + cfgwrite "GNULIB_FILES := $source_files" +} +# End of gnulib stuff + checkDependencies() { cfgwrite "BASE_LIBS := `gnustep-config --base-libs`" if test "x$ARG_ENABLE_SAML2" = "x1"; then @@ -389,11 +424,15 @@ checkDependencies() { checkLinking "ssl" optional; if test $? != 0; then checkLinking "gnutls" optional; + checkGnulib + gnulibMd4 fi; elif test "x$ARG_CFGSSL" = "xssl"; then checkLinking "ssl" required; elif test "x$ARG_CFGSSL" = "xgnutls"; then checkLinking "gnutls" required; + checkGnulib + gnulibMd4 fi } From 8706443685ff3cb4e71d79e08204e826698db597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Garc=C3=ADa?= Date: Wed, 15 Apr 2015 16:10:03 +0200 Subject: [PATCH 112/120] Prepare for 2.2.17a-zentyal1 --- NEWS | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/NEWS b/NEWS index 2a8958ee1..4bc7d920a 100644 --- a/NEWS +++ b/NEWS @@ -1,24 +1,7 @@ -2.2.15-zentyal3 (2015-04-14) ------- +2.2.17a-zentyal1 (2014-04-15) +-------------------- -New features - - Internet headers are now shown in Outlook - -Enhancements - - Sharing request among different Outlook versions - - Improve sync speed from Outlook by non-reprocessing already downloaded unread mails - -Bug fixes - - Sent mails are not longer in Drafts folder using Outlook - - Deleted mails are properly synced between Outlook profiles from the same account - - Does not create a mail folder in other user's mailbox - - Fix server-side crash with invalid events - - Fix setting permissions for a folder with several users - - Fix reception of calendar event invitations on optional attendees - - Fix server side crash parsing rtf without color table - - Weekly recurring events created in SOGo web interface are now shown in Outlook - - Fix exception modifications import in recurrence series - - Fix server side crash parsing rtf emails with images (with word97 format) +Zentyal Release 2.2.17a (2014-03-15) -------------------- @@ -79,6 +62,28 @@ Bug fixes - fixed plain/text mails showing on one line on Android/EAS (#3055) - fixed exception in sogo-tool when parsing arguments of a set operation +2.2.15-zentyal3 (2015-04-14) +------ + +New features + - Internet headers are now shown in Outlook + +Enhancements + - Sharing request among different Outlook versions + - Improve sync speed from Outlook by non-reprocessing already downloaded unread mails + +Bug fixes + - Sent mails are not longer in Drafts folder using Outlook + - Deleted mails are properly synced between Outlook profiles from the same account + - Does not create a mail folder in other user's mailbox + - Fix server-side crash with invalid events + - Fix setting permissions for a folder with several users + - Fix reception of calendar event invitations on optional attendees + - Fix server side crash parsing rtf without color table + - Weekly recurring events created in SOGo web interface are now shown in Outlook + - Fix exception modifications import in recurrence series + - Fix server side crash parsing rtf emails with images (with word97 format) + 2.2.15-zentyal2 (2015-03-16) ---------------------------- From 6b3454376eee8f81f023f91dc982c5d40f48e76f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Garc=C3=ADa?= Date: Thu, 16 Apr 2015 09:55:22 +0200 Subject: [PATCH 113/120] Revert "configure: Fix gnulib/crypto/md4 dependency" This reverts commit f0a3fdae5bdfa242d8b4a6b01025195c0eb4a620. --- SoObjects/SOGo/.gitignore | 2 -- SoObjects/SOGo/GNUmakefile.preamble | 2 -- configure | 39 ----------------------------- 3 files changed, 43 deletions(-) delete mode 100644 SoObjects/SOGo/.gitignore diff --git a/SoObjects/SOGo/.gitignore b/SoObjects/SOGo/.gitignore deleted file mode 100644 index 8fa5151fd..000000000 --- a/SoObjects/SOGo/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -config.h -md4.c diff --git a/SoObjects/SOGo/GNUmakefile.preamble b/SoObjects/SOGo/GNUmakefile.preamble index 8a484d3a1..b7456f8bd 100644 --- a/SoObjects/SOGo/GNUmakefile.preamble +++ b/SoObjects/SOGo/GNUmakefile.preamble @@ -30,8 +30,6 @@ SOGo_LIBRARIES_DEPEND_UPON += \ ifeq ($(HAS_LIBRARY_gnutls),yes) ADDITIONAL_CPPFLAGS += -DHAVE_GNUTLS=1 SOGo_LIBRARIES_DEPEND_UPON += -lgnutls -ADDITIONAL_INCLUDE_DIRS += -I$(GNULIB_INCLUDE) -SOGo_C_FILES += $(GNULIB_FILES) else ifeq ($(HAS_LIBRARY_ssl),yes) ADDITIONAL_CPPFLAGS += -DHAVE_OPENSSL=1 diff --git a/configure b/configure index 0a3acdc06..94d933fe7 100755 --- a/configure +++ b/configure @@ -374,41 +374,6 @@ EOF return $LINK_RESULT } - -# gnulib requires autoconf https://www.gnu.org/software/gnulib/manual/html_node/Initial-import.html -# We only require crypyo/md4 module (no dependencies, two files) when using gnutls -# Workaround: copy manually the files to the project needed (md4.c) -# Really ugly but it works, glad to change this to better alternative. -gnulib_dir=/usr/share/gnulib/lib - -checkGnulib() { - if test ! -d $gnulib_dir; then - echo "When using --with-ssl=gnutls option gnulib package is required to be installed in $gnulib_dir" - exit 1 - fi - cfgwrite "GNULIB_INCLUDE := $gnulib_dir" -} - -gnulibMd4() { - local source_files="md4.c" - local local_gnulib_dir="SoObjects/SOGo" - - for source_file in $source_files; do - if test -f $gnulib_dir/$source_file; then - cp $gnulib_dir/$source_file $local_gnulib_dir - else - echo "Error with gnulib file $source_file, gnulib package not installed?" - exit 1 - fi - done - - # md4.c requires config.h, create empty one - touch $local_gnulib_dir/config.h - - cfgwrite "GNULIB_FILES := $source_files" -} -# End of gnulib stuff - checkDependencies() { cfgwrite "BASE_LIBS := `gnustep-config --base-libs`" if test "x$ARG_ENABLE_SAML2" = "x1"; then @@ -424,15 +389,11 @@ checkDependencies() { checkLinking "ssl" optional; if test $? != 0; then checkLinking "gnutls" optional; - checkGnulib - gnulibMd4 fi; elif test "x$ARG_CFGSSL" = "xssl"; then checkLinking "ssl" required; elif test "x$ARG_CFGSSL" = "xgnutls"; then checkLinking "gnutls" required; - checkGnulib - gnulibMd4 fi } From cdb608551018fe6de9696393cd4b021cfe46dd7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Garc=C3=ADa?= Date: Thu, 16 Apr 2015 09:55:32 +0200 Subject: [PATCH 114/120] Revert "Adding missing build dependency gnulib" This reverts commit 210053ea20ef9b803b7486e700576bc33e70330f. --- SoObjects/SOGo/NSData+Crypto.m | 1 - packaging/debian/control | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/SoObjects/SOGo/NSData+Crypto.m b/SoObjects/SOGo/NSData+Crypto.m index b449664e2..d869f9b68 100644 --- a/SoObjects/SOGo/NSData+Crypto.m +++ b/SoObjects/SOGo/NSData+Crypto.m @@ -39,7 +39,6 @@ #include #include #include -#include #define MD4_DIGEST_LENGTH 16 #define MD5_DIGEST_LENGTH 16 #define SHA_DIGEST_LENGTH 20 diff --git a/packaging/debian/control b/packaging/debian/control index cbe90d8e4..ceee29543 100644 --- a/packaging/debian/control +++ b/packaging/debian/control @@ -1,7 +1,7 @@ Source: sogo Priority: optional Maintainer: Inverse Support -Build-Depends: debhelper (>= 7.0.15), gobjc | objc-compiler, libgnustep-base-dev, libsope-appserver4.9-dev, libsope-core4.9-dev, libsope-gdl1-4.9-dev, libsope-ldap4.9-dev, libsope-mime4.9-dev, libsope-xml4.9-dev, libmemcached-dev, libxml2-dev, libsbjson-dev, libssl-dev, libcurl4-openssl-dev | libcurl4-gnutls-dev, libwbxml2-dev (>= 0.11.2), liblasso3-dev (>= 2.3.5), gnulib +Build-Depends: debhelper (>= 7.0.15), gobjc | objc-compiler, libgnustep-base-dev, libsope-appserver4.9-dev, libsope-core4.9-dev, libsope-gdl1-4.9-dev, libsope-ldap4.9-dev, libsope-mime4.9-dev, libsope-xml4.9-dev, libmemcached-dev, libxml2-dev, libsbjson-dev, libssl-dev, libcurl4-openssl-dev | libcurl4-gnutls-dev, libwbxml2-dev (>= 0.11.2), liblasso3-dev (>= 2.3.5) Section: web Standards-Version: 3.9.1 From f6370d10cba1f75c59b837addc5d4236a579c744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Garc=C3=ADa?= Date: Mon, 20 Apr 2015 09:47:40 +0200 Subject: [PATCH 115/120] Revert "Prepare for new 2.2.15-zentyal3 version" This reverts commit 914e7b7418128dbc112746d4b58a81eef2a64d88. Conflicts: NEWS --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 55f030370..52f9f7989 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -2.2.19 (2015-05-XX) +master ------ New features From 8e39f03f834679bc8f0073daaf286849da919da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Garc=C3=ADa?= Date: Mon, 20 Apr 2015 09:48:52 +0200 Subject: [PATCH 116/120] Revert "Prepare for 2.2.17a-zentyal1" This reverts commit 8706443685ff3cb4e71d79e08204e826698db597. Conflicts: NEWS --- NEWS | 46 +++++++++++++++++----------------------------- 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/NEWS b/NEWS index 52f9f7989..6b138dd08 100644 --- a/NEWS +++ b/NEWS @@ -1,32 +1,3 @@ -master ------- - -New features - - Internet headers are now shown in Outlook - -Enhancements - - Sharing request among different Outlook versions - - Improve sync speed from Outlook by non-reprocessing already downloaded unread mails - - Give support to calendar sharing invitations - - Missing contact fields are now saved and available when sharing it - (Office, Profession, Manager's name, Assistant's name, Spouse/Partner, Anniversary) - - Appointment color and importance work now between Outlooks - -Bug fixes - - Sent mails are not longer in Drafts folder using Outlook - - Deleted mails are properly synced between Outlook profiles from the same account - - Does not create a mail folder in other user's mailbox - - Fix server-side crash with invalid events - - Fix setting permissions for a folder with several users - - Fix reception of calendar event invitations on optional attendees - - Fix server side crash parsing rtf without color table - - Weekly recurring events created in SOGo web interface are now shown in Outlook - - Fix exception modifications import in recurrence series - - Fix server side crash parsing rtf emails with images (with word97 format) - - Fix sender on importing email messages like event invitations - - Fix Outlook crashes when modifying the view of a folder - - Fix server side crash when reading some recurrence appointments - 2.2.18 (2015-04-XX) ------------------- @@ -105,6 +76,23 @@ Bug fixes - fixed plain/text mails showing on one line on Android/EAS (#3055) - fixed exception in sogo-tool when parsing arguments of a set operation +<<<<<<< HEAD +======= +2.2.15-zentyal2 (2015-03-16) +---------------------------- + +Enhancements + - Give support to calendar sharing invitations + - Missing contact fields are now saved and available when sharing it + (Office, Profession, Manager's name, Assistant's name, Spouse/Partner, Anniversary) + - Appointment color and importance work now between Outlooks + +Bug fixes + - Fix sender on importing email messages like event invitations + - Fix Outlook crashes when modifying the view of a folder + - Fix server side crash when reading some recurrence appointments + +>>>>>>> parent of 8706443... Prepare for 2.2.17a-zentyal1 2.2.15 (2015-01-30) ------------------- From 9901788db67cb09843752652d6170aeeead50e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Garc=C3=ADa?= Date: Mon, 20 Apr 2015 09:51:02 +0200 Subject: [PATCH 117/120] Revert "Update news for next release" This reverts commit cd47c926c92c29c7ee63c3990417883d60be2be7. Conflicts: NEWS --- NEWS | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/NEWS b/NEWS index 6b138dd08..08b83e687 100644 --- a/NEWS +++ b/NEWS @@ -76,23 +76,6 @@ Bug fixes - fixed plain/text mails showing on one line on Android/EAS (#3055) - fixed exception in sogo-tool when parsing arguments of a set operation -<<<<<<< HEAD -======= -2.2.15-zentyal2 (2015-03-16) ----------------------------- - -Enhancements - - Give support to calendar sharing invitations - - Missing contact fields are now saved and available when sharing it - (Office, Profession, Manager's name, Assistant's name, Spouse/Partner, Anniversary) - - Appointment color and importance work now between Outlooks - -Bug fixes - - Fix sender on importing email messages like event invitations - - Fix Outlook crashes when modifying the view of a folder - - Fix server side crash when reading some recurrence appointments - ->>>>>>> parent of 8706443... Prepare for 2.2.17a-zentyal1 2.2.15 (2015-01-30) ------------------- From 1d9e085658cdb8ca93a44b8066a3907f14f0047b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Garc=C3=ADa?= Date: Mon, 20 Apr 2015 13:15:04 +0200 Subject: [PATCH 118/120] Revert "oc: NGImap4Connection:fetchUids changed error messages" This reverts commit 41320a4813e232b02780eea42792b108c7f4bf3f. --- OpenChange/NGImap4Connection+Monkeypatching.m | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/OpenChange/NGImap4Connection+Monkeypatching.m b/OpenChange/NGImap4Connection+Monkeypatching.m index 1a09948e7..bdeca87ff 100644 --- a/OpenChange/NGImap4Connection+Monkeypatching.m +++ b/OpenChange/NGImap4Connection+Monkeypatching.m @@ -73,8 +73,8 @@ partial_result = [[self client] fetchUids:partial_uids parts:_parts]; if (![[partial_result valueForKey:@"result"] boolValue]) { - [self errorWithFormat: @"Error fetching %u uids for url: %@", - total, _url]; + [self errorWithFormat: @"could not fetch %d uids for url: %@", + [_uids count], _url]; return nil; } @@ -99,8 +99,8 @@ current_obj = [target objectForKey: key]; if (current_obj == nil) { /* This should never happen but just in case... */ - [self errorWithFormat: @"Error merging fetchUids results: " - @"nonexistent key %@ on current target", key]; + [self errorWithFormat: @"Error while merging results: nonexistent key " + @"%@ on current target", key]; continue; } @@ -115,13 +115,13 @@ [self _mergeNGHashMap: obj into: current_obj]; } else if ([obj isKindOfClass: [NSNumber class]]) { if (obj != current_obj) { - [self errorWithFormat: @"Error merging fetchUids results: " - @"incorrect value for key %@: %@ != %@", + [self errorWithFormat: @"While fetching uids problem happened " + @"merging results for key %@: %@ != %@", key, obj, current_obj]; } } else { - [self errorWithFormat: @"Error merging fetchUids results: " - @"ignored %@ (%@) key", key, [key class]]; + [self errorWithFormat: @"While fetching uids and mergin results ignored " + @"%@ (%@) key", key, [key class]]; } } } @@ -135,8 +135,8 @@ current_obj = [target objectsForKey: key]; if (current_obj == nil) { /* This should never happen but just in case... */ - [self errorWithFormat: @"Error merging fetchUids results: " - @"nonexistent key %@ on current target", key]; + [self errorWithFormat: @"Error while merging results: nonexistent key " + @"%@ on current target", key]; continue; } From 255b3d2d006a6acf2aeb854aa20d88f8e77f8c1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Garc=C3=ADa?= Date: Mon, 20 Apr 2015 13:15:13 +0200 Subject: [PATCH 119/120] Revert "oc: NGImap4Connection:fetchUids don't delete RawResponse" This reverts commit c410a9fc3ff7694d179e69e5d9a904396f0ab07e. --- OpenChange/NGImap4Connection+Monkeypatching.h | 12 +-- OpenChange/NGImap4Connection+Monkeypatching.m | 95 +++++-------------- 2 files changed, 27 insertions(+), 80 deletions(-) diff --git a/OpenChange/NGImap4Connection+Monkeypatching.h b/OpenChange/NGImap4Connection+Monkeypatching.h index acbf26cd5..3a188b8c7 100644 --- a/OpenChange/NGImap4Connection+Monkeypatching.h +++ b/OpenChange/NGImap4Connection+Monkeypatching.h @@ -24,20 +24,12 @@ #import #import #import -#import @interface NGImap4Connection (Monkeypatching) -- (NSArray *) fetchUIDs: (NSArray *) _uids - inURL: (NSURL *) _url - parts: (NSArray *) _parts; - -- (void) _mergeDict: (NSDictionary *) source - into: (NSMutableDictionary *) target; - -- (void) _mergeNGHashMap: (NGMutableHashMap *) source - into: (NGMutableHashMap *) target; +- (NSArray *)fetchUIDs:(NSArray *)_uids inURL:(NSURL *)_url + parts:(NSArray *)_parts; @end diff --git a/OpenChange/NGImap4Connection+Monkeypatching.m b/OpenChange/NGImap4Connection+Monkeypatching.m index bdeca87ff..d94a145a1 100644 --- a/OpenChange/NGImap4Connection+Monkeypatching.m +++ b/OpenChange/NGImap4Connection+Monkeypatching.m @@ -20,7 +20,7 @@ #import "NGImap4Connection+Monkeypatching.h" -#import +#import #import #import @@ -28,9 +28,8 @@ @implementation NGImap4Connection (Monkeypatching) -- (NSArray *) fetchUIDs: (NSArray *) _uids - inURL: (NSURL *) _url - parts: (NSArray *) _parts +- (NSArray *)fetchUIDs:(NSArray *)_uids inURL:(NSURL *)_url + parts:(NSArray *)_parts { // currently returns a dict?! /* @@ -73,81 +72,37 @@ partial_result = [[self client] fetchUids:partial_uids parts:_parts]; if (![[partial_result valueForKey:@"result"] boolValue]) { - [self errorWithFormat: @"could not fetch %d uids for url: %@", - [_uids count], _url]; + [self errorWithFormat: @"could not fetch %d uids for url: %@", [_uids count], _url]; return nil; } - if (result == nil) { + if (!result) { /* First iteration, first result */ result = [[partial_result mutableCopy] autorelease]; - } else { - /* Merge partial_result into previous result */ - [self _mergeDict: partial_result into: result]; + /* RawResponse has already been processed, ignore it */ + [result removeObjectForKey: @"RawResponse"]; + continue; + } + + /* Merge partial_result into previous result */ + for (id key in [partial_result keyEnumerator]) { + id obj, current_obj; + + current_obj = [result objectForKey: key]; + if (!current_obj) continue; + + obj = [partial_result objectForKey: key]; + if ([obj isKindOfClass: [NSArray class]]) { + NSArray *data, *current_data, *new_data; + data = obj; + current_data = current_obj; + new_data = [current_data arrayByAddingObjectsFromArray: data]; + [result setObject: new_data forKey: key]; + } } } return (id)result; } -- (void) _mergeDict: (NSDictionary *) source - into: (NSMutableDictionary *) target -{ - for (id key in [source keyEnumerator]) { - id obj, current_obj; - - current_obj = [target objectForKey: key]; - if (current_obj == nil) { - /* This should never happen but just in case... */ - [self errorWithFormat: @"Error while merging results: nonexistent key " - @"%@ on current target", key]; - continue; - } - - obj = [source objectForKey: key]; - if ([obj isKindOfClass: [NSArray class]]) { - NSArray *data, *current_data, *new_data; - data = obj; - current_data = current_obj; - new_data = [current_data arrayByAddingObjectsFromArray: data]; - [target setObject: new_data forKey: key]; - } else if ([obj isKindOfClass: [NGMutableHashMap class]]) { - [self _mergeNGHashMap: obj into: current_obj]; - } else if ([obj isKindOfClass: [NSNumber class]]) { - if (obj != current_obj) { - [self errorWithFormat: @"While fetching uids problem happened " - @"merging results for key %@: %@ != %@", - key, obj, current_obj]; - } - } else { - [self errorWithFormat: @"While fetching uids and mergin results ignored " - @"%@ (%@) key", key, [key class]]; - } - } -} - -- (void) _mergeNGHashMap: (NGMutableHashMap *) source - into: (NGMutableHashMap *) target -{ - for (id key in [source keyEnumerator]) { - NSArray *obj, *current_obj; - - current_obj = [target objectsForKey: key]; - if (current_obj == nil) { - /* This should never happen but just in case... */ - [self errorWithFormat: @"Error while merging results: nonexistent key " - @"%@ on current target", key]; - continue; - } - - if ([current_obj count] == 1) { - /* Merge only results, that means fields with more than 1 object */ - continue; - } - - obj = [source objectsForKey: key]; - [target addObjects: obj forKey: key]; - } -} - @end From 78f5f60b16194f502871ec77270bef8ac1265fdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Garc=C3=ADa?= Date: Mon, 20 Apr 2015 13:15:22 +0200 Subject: [PATCH 120/120] Revert "oc: monkeypatched NGImap4Connection class from sope" This reverts commit 24e35103ff0a5094f81b9f241cb8164293ac7b83. --- OpenChange/GNUmakefile | 4 +- OpenChange/NGImap4Connection+Monkeypatching.h | 37 ------ OpenChange/NGImap4Connection+Monkeypatching.m | 108 ------------------ 3 files changed, 1 insertion(+), 148 deletions(-) delete mode 100644 OpenChange/NGImap4Connection+Monkeypatching.h delete mode 100644 OpenChange/NGImap4Connection+Monkeypatching.m diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index 688ef19e1..e443ec3f6 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -124,9 +124,7 @@ $(SOGOBACKEND)_OBJC_FILES += \ \ RTFHandler.m \ \ - Codepages.m \ - \ - NGImap4Connection+Monkeypatching.m + Codepages.m $(SOGOBACKEND)_RESOURCE_FILES += \ diff --git a/OpenChange/NGImap4Connection+Monkeypatching.h b/OpenChange/NGImap4Connection+Monkeypatching.h deleted file mode 100644 index 3a188b8c7..000000000 --- a/OpenChange/NGImap4Connection+Monkeypatching.h +++ /dev/null @@ -1,37 +0,0 @@ -/* NGImap4Connection+Monkeypatching.h - this file is part of SOGo - * - * Copyright (C) 2014 Jesús García Sáez - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __OpenChange_NGImap4Connection_Monkeypatching_H__ -#define __OpenChange_NGImap4Connection_Monkeypatching_H__ - -#import -#import -#import - - -@interface NGImap4Connection (Monkeypatching) - -- (NSArray *)fetchUIDs:(NSArray *)_uids inURL:(NSURL *)_url - parts:(NSArray *)_parts; - -@end - - -#endif // __OpenChange_NGImap4Connection_Monkeypatching_H__ diff --git a/OpenChange/NGImap4Connection+Monkeypatching.m b/OpenChange/NGImap4Connection+Monkeypatching.m deleted file mode 100644 index d94a145a1..000000000 --- a/OpenChange/NGImap4Connection+Monkeypatching.m +++ /dev/null @@ -1,108 +0,0 @@ -/* NGImap4Connection+Monkeypatching.m - this file is part of SOGo - * - * Copyright (C) 2014 Jesús García Sáez - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#import "NGImap4Connection+Monkeypatching.h" - -#import -#import - -#import - - -@implementation NGImap4Connection (Monkeypatching) - -- (NSArray *)fetchUIDs:(NSArray *)_uids inURL:(NSURL *)_url - parts:(NSArray *)_parts -{ - // currently returns a dict?! - /* - Allowed fetch keys: - UID - BODY.PEEK[
]<> - BODY [this is the bodystructure, supported] - BODYSTRUCTURE [not supported yet!] - ENVELOPE [this is a parsed header, but does not include type] - FLAGS - INTERNALDATE - RFC822 - RFC822.HEADER - RFC822.SIZE - RFC822.TEXT - */ - NSMutableDictionary *result = nil; - NSUInteger i, total, step = 1000; - - if (_uids == nil || [_uids count] == 0) - return nil; - - /* select folder */ - - if (![self selectFolder:_url]) - return nil; - - /* fetch parts */ - - total = [_uids count]; - for (i = 0; i < total; i += step) { - NSRange range; - NSArray *partial_uids; - NSDictionary *partial_result; - - range = NSMakeRange(i, (i + step) > total ? (total - i) : step); - partial_uids = [_uids subarrayWithRange: range]; - - /* We will only fetch "step" uids each time */ - partial_result = [[self client] fetchUids:partial_uids parts:_parts]; - - if (![[partial_result valueForKey:@"result"] boolValue]) { - [self errorWithFormat: @"could not fetch %d uids for url: %@", [_uids count], _url]; - return nil; - } - - if (!result) { - /* First iteration, first result */ - result = [[partial_result mutableCopy] autorelease]; - /* RawResponse has already been processed, ignore it */ - [result removeObjectForKey: @"RawResponse"]; - continue; - } - - /* Merge partial_result into previous result */ - for (id key in [partial_result keyEnumerator]) { - id obj, current_obj; - - current_obj = [result objectForKey: key]; - if (!current_obj) continue; - - obj = [partial_result objectForKey: key]; - if ([obj isKindOfClass: [NSArray class]]) { - NSArray *data, *current_data, *new_data; - data = obj; - current_data = current_obj; - new_data = [current_data arrayByAddingObjectsFromArray: data]; - [result setObject: new_data forKey: key]; - } - } - } - - return (id)result; -} - -@end