diff --git a/NEWS b/NEWS index a8965419a..8b396584d 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ master ------ Enhancements + - Sharing request among different Outlook versions - Improve sync speed from Outlook by non-reprocessing already downloaded unread mails Bug fixes 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 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/MAPIStoreMailVolatileMessage.m b/OpenChange/MAPIStoreMailVolatileMessage.m index 77d6294ab..b5239f193 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: SHARING_DENY_REQUEST]; + } + [headers setObject: sharingFlavourNum + forKey: @"X-MS-Sharing-Flavor"]; + } value = [mailProperties objectForKey: MAPIPropertyKey (PidLidSharingInitiatorEntryId)]; if (value) diff --git a/OpenChange/MAPIStoreSharingMessage.h b/OpenChange/MAPIStoreSharingMessage.h index 9b62389a0..7db7f552f 100644 --- a/OpenChange/MAPIStoreSharingMessage.h +++ b/OpenChange/MAPIStoreSharingMessage.h @@ -23,8 +23,10 @@ #ifndef MAPISTORESHARINGMESSAGE_H #define MAPISTORESHARINGMESSAGE_H +#import "MAPIStoreMailMessage.h" #import "MAPIStoreObjectProxy.h" +#define SHARING_SPECIAL_FOLDER 0x40290 @interface MAPIStoreSharingMessage : MAPIStoreObjectProxy { @@ -33,7 +35,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 +92,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..ba0c74132 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,12 @@ #import "NSString+MAPIStore.h" #import "NSValue+MAPIStore.h" +#import "MAPIStoreMailFolder.h" #import "MAPIStoreSharingMessage.h" +#include #include +#include @implementation MAPIStoreSharingMessage @@ -52,6 +57,7 @@ - (id) initWithMailHeaders: (NSDictionary *) mailHeaders andConnectionInfo: (struct mapistore_connection_info *) newConnInfo + fromMessage: (MAPIStoreMailMessage *) msg { NSEnumerator *enumerator; NSString *key; @@ -67,6 +73,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; @@ -123,7 +135,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; } @@ -163,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-remotename"]; + 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 acceptance */ - *data = MAPILongValue (memCtx, 0x20310); - else - *data = MAPILongValue (memCtx, 0x23310); + if (auxValue) /* It SHOULD be an invitation or response */ + *data = MAPILongValue (memCtx, SHARING_INVITATION_SPECIAL_FOLDER); + else /* No remote info, then denial */ + *data = MAPILongValue (memCtx, SHARING_DENY_REQUEST); } } else { - *data = MAPILongValue (memCtx, 0x310); + *data = MAPILongValue (memCtx, SHARING_INVITATION_FOLDER); } rc = MAPISTORE_SUCCESS; } @@ -202,7 +215,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; } @@ -368,7 +382,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 +410,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 +426,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