diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index 1b9570a94..8006b21b9 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/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index ab8cd78b2..4b96a3515 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; @@ -2069,17 +2073,23 @@ 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]; + else + icalTZ = nil; + + 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; 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]; 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..3e24145c1 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,19 +365,54 @@ 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"]; + /* 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]; [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 + 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 {