From 030d34343271f3e41a3d8c7715bd917bbaf791d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Mon, 13 Apr 2015 11:55:43 +0200 Subject: [PATCH 1/7] oc: Do not create indexing entry for a root folder This is done by OpenChange after this patchset is merged: https://github.com/openchange/openchange/pull/273 --- OpenChange/MAPIStoreContext.m | 5 ----- 1 file changed, 5 deletions(-) diff --git a/OpenChange/MAPIStoreContext.m b/OpenChange/MAPIStoreContext.m index fca045b17..2f4592cb8 100644 --- a/OpenChange/MAPIStoreContext.m +++ b/OpenChange/MAPIStoreContext.m @@ -419,7 +419,6 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri) withFID: (uint64_t) newFid { enum mapistore_error rc; - MAPIStoreMapping *mapping; MAPIStoreFolder *baseFolder; SOGoFolder *currentFolder; WOContext *woContext; @@ -427,10 +426,6 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri) NSArray *pathComponents; NSUInteger count, max; - mapping = [userContext mapping]; - if (![mapping urlFromID: newFid]) - [mapping registerURL: [contextUrl absoluteString] - withID: newFid]; [userContext activateWithUser: activeUser]; woContext = [userContext woContext]; From 7e89c43919a258dc4f41d309b58408dab307b6d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Vall=C3=A9s?= Date: Tue, 5 May 2015 10:01:09 +0200 Subject: [PATCH 2/7] oc-calendar: Compute time offset in floating time in all-day recurring events --- OpenChange/MAPIStoreAppointmentWrapper.m | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index ab8cd78b2..b1a6fc511 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -1461,8 +1461,6 @@ static NSCharacterSet *hexCharacterSet = nil; firstStartDate = [event firstRecurrenceStartDate]; if (firstStartDate) { - [firstStartDate setTimeZone: timeZone]; - arp = talloc_zero (NULL, struct AppointmentRecurrencePattern); [rule fillRecurrencePattern: &arp->RecurrencePattern withEvent: event @@ -1472,6 +1470,12 @@ static NSCharacterSet *hexCharacterSet = nil; arp->WriterVersion2 = 0x00003008; /* 0x3008 for compatibility with ol2003 */ + /* All day events' dates are specified in floating time + ([MS-OXCICAL] 2.1.3.1.1.20.10). The StartTimeOffset and EndTimeOffset + fields are relative to midnight of those days ([MS-OXOCAL] 2.2.1.44.5), + so no time zone adjustment is needed */ + if (![event isAllDay]) + [firstStartDate setTimeZone: timeZone]; startMinutes = ([firstStartDate hourOfDay] * 60 + [firstStartDate minuteOfHour]); arp->StartTimeOffset = startMinutes; From ebe2a466e7ac3d6aa0f10befc9367555224ac752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Vall=C3=A9s?= Date: Tue, 5 May 2015 10:28:58 +0200 Subject: [PATCH 3/7] oc-calendar: Compute PidLidAppointmentDefinitionStartWhole for all-day events --- OpenChange/MAPIStoreAppointmentWrapper.m | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index b1a6fc511..85f923463 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -2073,17 +2073,21 @@ ReservedBlockEE2Size: 00 00 00 00 enum mapistore_error rc; iCalTimeZone *icalTZ; - if ([event isRecurrent]) + /* [MS-OXOCAL] 3.1.5.5.1: This property is used in floating (all-day) events, + specified in floating time, to convert the start date from UTC to the user's + time zone */ + if ([event isAllDay]) + icalTZ = [iCalTimeZone timeZoneForName: [timeZone timeZoneName]]; + else if ([event isRecurrent]) + icalTZ = [(iCalDateTime *) [event firstChildWithTag: @"dtstart"] timeZone]; + + if (icalTZ) { - icalTZ = [(iCalDateTime *) [event firstChildWithTag: @"dtstart"] timeZone]; - if (icalTZ) - { - *data = [icalTZ asZoneTimeDefinitionWithFlags: TZRULE_FLAG_EFFECTIVE_TZREG | TZRULE_FLAG_RECUR_CURRENT_TZREG - inMemCtx: memCtx]; - rc = MAPISTORE_SUCCESS; - } - else - rc = MAPISTORE_ERR_NOT_FOUND; + /* [MS-OXOCAL] 2.2.1.42: This property can only have the E flag set in the + TimeZoneDefinition struct */ + *data = [icalTZ asZoneTimeDefinitionWithFlags: TZRULE_FLAG_EFFECTIVE_TZREG + inMemCtx: memCtx]; + rc = MAPISTORE_SUCCESS; } else rc = MAPISTORE_ERR_NOT_FOUND; From 2d65b75b56c43f105ff7982864f0fa7cab2a0f83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Tue, 5 May 2015 10:46:53 +0200 Subject: [PATCH 4/7] oc-mail: Flush IMAP hierarchy cache to update Outlook folders This fixes two scenarios: * An IMAP subfolder has updated its hierarchy when it is asked to be synchronised * An IMAP root folder is created on Outlook when you logon. OpenChange changes are required to be refreshed on synchronisation. --- OpenChange/MAPIStoreMailContext.m | 3 +++ OpenChange/MAPIStoreMailFolder.m | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/OpenChange/MAPIStoreMailContext.m b/OpenChange/MAPIStoreMailContext.m index 87493ff09..f7a62fcd8 100644 --- a/OpenChange/MAPIStoreMailContext.m +++ b/OpenChange/MAPIStoreMailContext.m @@ -146,6 +146,9 @@ MakeDisplayFolderName (NSString *folderName) DLIST_ADD_END (firstContext, context, void); } + /* FIXME: Flush any cache before retrieving the hierarchy */ + [accountFolder flushMailCaches]; + secondaryFolders = [[accountFolder toManyRelationshipKeysWithNamespaces: NO] mutableCopy]; [secondaryFolders autorelease]; diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index d2036454a..0e98b4af4 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -368,6 +368,11 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; if (sortOrderings) [self errorWithFormat: @"sort orderings are not used for folders"]; + /* FIXME: Flush any cache before retrieving the hierarchy, this + slows things down but it is safer */ + if (!qualifier) + [sogoObject flushMailCaches]; + subfolderKeys = [[sogoObject toManyRelationshipKeys] mutableCopy]; [subfolderKeys autorelease]; From 15f95c4956b897eb5927c65abc5adcdd172a768a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Thu, 30 Apr 2015 00:16:24 +0200 Subject: [PATCH 5/7] oc-mail: Support restricitions on name for MAPIStoreMailFolderTable This allows us to search for a subfolder in a mail folder successfully. This is happening, for instance, on folder creation. --- OpenChange/GNUmakefile | 1 + OpenChange/MAPIStoreMailFolder.m | 38 +++++++++++++++++++++++- OpenChange/MAPIStoreMailFolderTable.h | 31 ++++++++++++++++++++ OpenChange/MAPIStoreMailFolderTable.m | 42 +++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 OpenChange/MAPIStoreMailFolderTable.h create mode 100644 OpenChange/MAPIStoreMailFolderTable.m diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index 688ef19e1..654dd46e2 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -100,6 +100,7 @@ $(SOGOBACKEND)_OBJC_FILES += \ MAPIStoreMailAttachment.m \ MAPIStoreMailContext.m \ MAPIStoreMailFolder.m \ + MAPIStoreMailFolderTable.m \ MAPIStoreMailMessage.m \ MAPIStoreMailVolatileMessage.m \ MAPIStoreMailMessageTable.m \ diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index d2036454a..2bd9b4c20 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -52,6 +52,7 @@ #import "MAPIStoreFAIMessage.h" #import "MAPIStoreMailContext.h" #import "MAPIStoreMailMessage.h" +#import "MAPIStoreMailFolderTable.h" #import "MAPIStoreMailMessageTable.h" #import "MAPIStoreMapping.h" #import "MAPIStoreTypes.h" @@ -154,6 +155,11 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; return [MAPIStoreMailMessageTable tableForContainer: self]; } +- (MAPIStoreFolderTable *) folderTable +{ + return [MAPIStoreMailFolderTable tableForContainer: self]; +} + - (enum mapistore_error) createFolder: (struct SRow *) aRow withFID: (uint64_t) newFID andKey: (NSString **) newKeyP @@ -359,12 +365,17 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; - (NSArray *) folderKeysMatchingQualifier: (EOQualifier *) qualifier andSortOrderings: (NSArray *) sortOrderings { + NSArray *filteredSubfolderKeys; NSMutableArray *subfolderKeys; + NSMutableArray *subfolderKeysQualifying; + NSString *subfolderKey; + NSUInteger count, max; if ([self ensureFolderExists]) { + /* Only folder name can be used as qualifier key */ if (qualifier) - [self errorWithFormat: @"qualifier is not used for folders"]; + [self warnWithFormat: @"qualifier is only used for folders with name"]; if (sortOrderings) [self errorWithFormat: @"sort orderings are not used for folders"]; @@ -372,6 +383,31 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; [subfolderKeys autorelease]; [self _cleanupSubfolderKeys: subfolderKeys]; + + if (qualifier) + { + subfolderKeysQualifying = [NSMutableArray array]; + max = [subfolderKeys count]; + for (count = 0; count < max; count++) { + subfolderKey = [subfolderKeys objectAtIndex: count]; + /* Remove "folder" prefix */ + subfolderKey = [subfolderKey substringFromIndex: 6]; + subfolderKey = [[subfolderKey fromCSSIdentifier] stringByDecodingImap4FolderName]; + [subfolderKeysQualifying addObject: [NSDictionary dictionaryWithObject: subfolderKey + forKey: @"name"]]; + } + filteredSubfolderKeys = [subfolderKeysQualifying filteredArrayUsingQualifier: qualifier]; + + max = [filteredSubfolderKeys count]; + subfolderKeys = [NSMutableArray arrayWithCapacity: max]; + for (count = 0; count < max; count++) + { + subfolderKey = [[filteredSubfolderKeys objectAtIndex: count] valueForKey: @"name"]; + subfolderKey = [NSString stringWithFormat: @"folder%@", [[subfolderKey stringByEncodingImap4FolderName] asCSSIdentifier]]; + [subfolderKeys addObject: subfolderKey]; + } + + } } else subfolderKeys = nil; diff --git a/OpenChange/MAPIStoreMailFolderTable.h b/OpenChange/MAPIStoreMailFolderTable.h new file mode 100644 index 000000000..5ec2c4a5b --- /dev/null +++ b/OpenChange/MAPIStoreMailFolderTable.h @@ -0,0 +1,31 @@ +/* MAPIStoreMailFolderTable.h - this file is part of SOGo + * + * 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 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 MAPISTOREMAILFOLDERTABLE_H +#define MAPISTOREMAILFOLDERTABLE_H + +#import "MAPIStoreFolderTable.h" + +@interface MAPIStoreMailFolderTable : MAPIStoreFolderTable +@end + +#endif /* MAPISTOREMAILFOLDERTABLE_H */ diff --git a/OpenChange/MAPIStoreMailFolderTable.m b/OpenChange/MAPIStoreMailFolderTable.m new file mode 100644 index 000000000..542e1dc8f --- /dev/null +++ b/OpenChange/MAPIStoreMailFolderTable.m @@ -0,0 +1,42 @@ +/* MAPIStoreMailFolderTable.m - this file is part of SOGo + * + * Copyright (C) 2015 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 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 "MAPIStoreMailFolderTable.h" +#import "MAPIStoreTypes.h" + +@implementation MAPIStoreMailFolderTable + +- (NSString *) backendIdentifierForProperty: (enum MAPITAGS) property +{ + switch(property) + { + case PR_DISPLAY_NAME: + case PR_DISPLAY_NAME_UNICODE: + return @"name"; + default: + return nil; + } +} + + +@end + From 0a285eedec327c8ea7f285f228c6083bcf5438d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Vall=C3=A9s?= Date: Wed, 6 May 2015 16:22:06 +0200 Subject: [PATCH 6/7] oc-calendar: Fix property values of invitation responses The value of `PidTagResponseRequested` property in the invitation mail wasn't being set properly, while the `PidTagReplyRequested` property wasn't being set at all. This caused invitation response mails not to be sent. Both properties are expected to be `true`. --- OpenChange/MAPIStoreMailMessage.h | 1 + OpenChange/MAPIStoreMailMessage.m | 32 +++++++++++++++---------------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/OpenChange/MAPIStoreMailMessage.h b/OpenChange/MAPIStoreMailMessage.h index fffd0c422..60922feaf 100644 --- a/OpenChange/MAPIStoreMailMessage.h +++ b/OpenChange/MAPIStoreMailMessage.h @@ -35,6 +35,7 @@ { BOOL headerSetup; BOOL mailIsEvent; + BOOL mailIsMeetingRequest; BOOL mailIsSharingObject; NSString *mimeKey; NSString *headerCharset; diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index 9d7342272..77ab5be40 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -118,6 +118,7 @@ static Class NSExceptionK, MAPIStoreSharingMessageK; { mimeKey = nil; mailIsEvent = NO; + mailIsMeetingRequest = NO; mailIsSharingObject = NO; headerCharset = nil; headerEncoding = nil; @@ -258,7 +259,11 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) ASSIGN (headerCharset, [parameters objectForKey: @"charset"]); if ([headerMimeType isEqualToString: @"text/calendar"] || [headerMimeType isEqualToString: @"application/ics"]) + { mailIsEvent = YES; + if ([[parameters objectForKey: @"method"] isEqualToString: @"REQUEST"]) + mailIsMeetingRequest = YES; + } else { sharingHeader = [[sogoObject mailHeaders] objectForKey: @"x-ms-sharing-localtype"]; @@ -572,30 +577,23 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) return MAPISTORE_SUCCESS; } -/* Note: this applies to regular mails... */ -// - (int) getPidTagReplyRequested: (void **) data // TODO -// inMemCtx: (TALLOC_CTX *) memCtx -// { -// if (!headerSetup) -// [self _fetchHeaderData]; - -// return (mailIsEvent -// ? [self getYes: data inMemCtx: memCtx] -// : [self getNo: data inMemCtx: memCtx]); -// } - -/* ... while this applies to invitations. */ -- (int) getPidTagResponseRequested: (void **) data // TODO - inMemCtx: (TALLOC_CTX *) memCtx +- (int) getPidTagReplyRequested: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx { if (!headerSetup) [self _fetchHeaderData]; - return (mailIsEvent - ? [self getNo: data inMemCtx: memCtx] + return (mailIsMeetingRequest + ? [self getYes: data inMemCtx: memCtx] : MAPISTORE_ERR_NOT_FOUND); } +- (int) getPidTagResponseRequested: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getPidTagReplyRequested: data inMemCtx: memCtx]; +} + - (int) getPidTagLatestDeliveryTime: (void **) data // DOUBT inMemCtx: (TALLOC_CTX *) memCtx { From e2ef0103c4c05c38354b620a09fc83c8c299da0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Tue, 19 May 2015 00:01:47 +0200 Subject: [PATCH 7/7] oc-calendar: Fix regression on AppointmentTimeZoneDefinitionStartDisplay Introduced by ebe2a466e7 in PR #132 when the event is not all day neither recurrent one. The fix is just to initialise to nil when it is a normal event and it returns NOT_FOUND for this property. --- OpenChange/MAPIStoreAppointmentWrapper.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index 85f923463..4b96a3515 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -2080,6 +2080,8 @@ ReservedBlockEE2Size: 00 00 00 00 icalTZ = [iCalTimeZone timeZoneForName: [timeZone timeZoneName]]; else if ([event isRecurrent]) icalTZ = [(iCalDateTime *) [event firstChildWithTag: @"dtstart"] timeZone]; + else + icalTZ = nil; if (icalTZ) {