From 98e1c33ba9a63bf38771628c11976dcd58a5cc93 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 30 Dec 2010 14:37:07 +0000 Subject: [PATCH] Monotone-Parent: 0c8a4c1cec3f6885752564a67a291de836bfa2a5 Monotone-Revision: 872ee9805088c05c6b69effae74f5577b87221c9 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2010-12-30T14:37:07 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 + OpenChange/MAPIStoreMailContext.m | 589 ++----------------------- OpenChange/MAPIStoreMailMessageTable.h | 31 ++ OpenChange/MAPIStoreMailMessageTable.m | 538 ++++++++++++++++++++++ 4 files changed, 611 insertions(+), 552 deletions(-) create mode 100644 OpenChange/MAPIStoreMailMessageTable.h create mode 100644 OpenChange/MAPIStoreMailMessageTable.m diff --git a/ChangeLog b/ChangeLog index 3975110fe..7e3a81e14 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2010-12-30 Wolfgang Sourdeau + * OpenChange/MAPIStoreMailContext.m: Old table methods (see + below) split into the new "MAPIStoreMailMessageTable" class. + (+registerFixedMappings:): changed handled uri to + @"sogo://openchange:openchange@inbox/". + * OpenChange/MAPIStoreGCSBaseContext.m: Old table methods (see below) split into the new "MAPIStoreGCSMessageTable" class. diff --git a/OpenChange/MAPIStoreMailContext.m b/OpenChange/MAPIStoreMailContext.m index 2e4078c64..fb4f0ce58 100644 --- a/OpenChange/MAPIStoreMailContext.m +++ b/OpenChange/MAPIStoreMailContext.m @@ -20,480 +20,107 @@ * Boston, MA 02111-1307, USA. */ -#import -#import -#import - #import #import #import +#import #import #import #import -#import #import "MAPIApplication.h" #import "MAPIStoreAuthenticator.h" +#import "MAPIStoreMailFolderTable.h" +#import "MAPIStoreMailMessageTable.h" #import "MAPIStoreMapping.h" #import "MAPIStoreTypes.h" -#import "NSData+MAPIStore.h" -#import "NSCalendarDate+MAPIStore.h" #import "NSString+MAPIStore.h" #import "MAPIStoreMailContext.h" #undef DEBUG -#include -#include #include -#include - -static Class NSDataK, NSStringK; @implementation MAPIStoreMailContext -+ (void) initialize -{ - NSDataK = [NSData class]; - NSStringK = [NSString class]; -} - + (NSString *) MAPIModuleName { - return @"mail"; + return @"inbox"; } + (void) registerFixedMappings: (MAPIStoreMapping *) mapping { - [mapping registerURL: @"sogo://openchange:openchange@mail/folderINBOX/" - withID: 0x160001]; + [mapping registerURL: @"sogo://openchange:openchange@inbox/" + withID: 0x160001]; } - (void) setupModuleFolder { - id userFolder, accountsFolder; + SOGoUserFolder *userFolder; + SOGoMailAccounts *accountsFolder; + SOGoMailAccount *accountFolder; + SOGoFolder *currentContainer; userFolder = [SOGoUserFolder objectWithName: [authenticator username] inContainer: MAPIApp]; [parentFoldersBag addObject: userFolder]; - [self logWithFormat: @"userFolder: %@", userFolder]; [woContext setClientObject: userFolder]; accountsFolder = [userFolder lookupName: @"Mail" inContext: woContext acquire: NO]; [parentFoldersBag addObject: accountsFolder]; - [self logWithFormat: @"accountsFolder: %@", accountsFolder]; [woContext setClientObject: accountsFolder]; - moduleFolder = [accountsFolder lookupName: @"0" - inContext: woContext - acquire: NO]; + accountFolder = [accountsFolder lookupName: @"0" + inContext: woContext + acquire: NO]; + [parentFoldersBag addObject: accountFolder]; + [woContext setClientObject: accountFolder]; + + moduleFolder = [accountFolder inboxFolderInContext: nil]; [moduleFolder retain]; + currentContainer = [moduleFolder container]; + while (currentContainer != (SOGoFolder *) accountFolder) + { + [parentFoldersBag addObject: currentContainer]; + currentContainer = [currentContainer container]; + } + [self logWithFormat: @"moduleFolder: %@", moduleFolder]; } -- (NSArray *) getFolderMessageKeys: (SOGoFolder *) folder - matchingQualifier: (EOQualifier *) qualifier +- (Class) messageTableClass { - NSArray *keys; - - if (qualifier) - keys = [(SOGoMailFolder *) folder fetchUIDsMatchingQualifier: qualifier - sortOrdering: @"ARRIVAL"]; - else - keys = [(SOGoMailFolder *) folder toOneRelationshipKeys]; - - return keys; + return [MAPIStoreMailMessageTable class]; } -// - (enum MAPISTATUS) getCommonTableChildproperty: (void **) data -// atURL: (NSString *) childURL -// withTag: (enum MAPITAGS) proptag -// inFolder: (SOGoFolder *) folder -// withFID: (uint64_t) fid -// { -// int rc; - -// rc = MAPI_E_SUCCESS; -// switch (proptag) { -// default: -// rc = [super getCommonTableChildproperty: data -// atURL: childURL -// withTag: proptag -// inFolder: folder -// withFID: fid]; -// } - -// return rc; -// } - -- (enum MAPISTATUS) getMessageTableChildproperty: (void **) data - atURL: (NSString *) childURL - withTag: (enum MAPITAGS) proptag - inFolder: (SOGoFolder *) folder - withFID: (uint64_t) fid +- (Class) folderTableClass { - id child; - // NSCalendarDate *offsetDate; - enum MAPISTATUS rc; - - rc = MAPI_E_SUCCESS; - switch (proptag) - { - case PR_ICON_INDEX: // TODO - /* read mail, see http://msdn.microsoft.com/en-us/library/cc815472.aspx */ - *data = MAPILongValue (memCtx, 0x00000100); - break; - case PR_CONVERSATION_TOPIC: - case PR_CONVERSATION_TOPIC_UNICODE: - case PR_SUBJECT: - case PR_SUBJECT_UNICODE: - child = [self lookupObject: childURL]; - *data = [[child decodedSubject] asUnicodeInMemCtx: memCtx]; - break; - case PR_MESSAGE_CLASS_UNICODE: - *data = talloc_strdup (memCtx, "IPM.Note"); - break; - case PR_HASATTACH: // TODO - *data = MAPIBoolValue (memCtx, NO); - break; - case PR_CREATION_TIME: // DOUBT - case PR_LAST_MODIFICATION_TIME: // DOUBT - case PR_LATEST_DELIVERY_TIME: // DOUBT - case PR_MESSAGE_DELIVERY_TIME: - child = [self lookupObject: childURL]; - // offsetDate = [[child date] addYear: -1 month: 0 day: 0 - // hour: 0 minute: 0 second: 0]; - // *data = [offsetDate asFileTimeInMemCtx: memCtx]; - *data = [[child date] asFileTimeInMemCtx: memCtx]; - break; - case PR_MESSAGE_FLAGS: // TODO - // NSDictionary *coreInfos; - // NSArray *flags; - // child = [self lookupObject: childURL]; - // coreInfos = [child fetchCoreInfos]; - // flags = [coreInfos objectForKey: @"flags"]; - *data = MAPILongValue (memCtx, 0x02 | 0x20); // fromme + unmodified - break; - - case PR_FLAG_STATUS: // TODO - case PR_SENSITIVITY: // TODO - case PR_ORIGINAL_SENSITIVITY: // TODO - case PR_FOLLOWUP_ICON: // TODO - *data = MAPILongValue (memCtx, 0); - break; - - case PR_EXPIRY_TIME: // TODO - case PR_REPLY_TIME: - *data = [[NSCalendarDate date] asFileTimeInMemCtx: memCtx]; - break; - - case PR_BODY: - case PR_BODY_UNICODE: - { - NSMutableArray *keys; - NSArray *acceptedTypes; - - child = [self lookupObject: childURL]; - - acceptedTypes = [NSArray arrayWithObjects: @"text/plain", - @"text/html", nil]; - keys = [NSMutableArray array]; - [child addRequiredKeysOfStructure: [child bodyStructure] - path: @"" toArray: keys - acceptedTypes: acceptedTypes]; - if ([keys count] == 0 || [keys count] == 2) - { - *data = NULL; - rc = MAPI_E_NOT_FOUND; - } - else - { - acceptedTypes = [NSArray arrayWithObject: @"text/plain"]; - [keys removeAllObjects]; - [child addRequiredKeysOfStructure: [child bodyStructure] - path: @"" toArray: keys - acceptedTypes: acceptedTypes]; - if ([keys count] > 0) - { - id result; - NSData *content; - NSString *key, *stringContent; - - result = [child fetchParts: [keys objectsForKey: @"key" - notFoundMarker: nil]]; - result = [[result valueForKey: @"RawResponse"] objectForKey: @"fetch"]; - key = [[keys objectAtIndex: 0] objectForKey: @"key"]; - content = [[result objectForKey: key] objectForKey: @"data"]; - if ([content length] > 3999) - { - [self registerValue: content - asProperty: proptag - forURL: childURL]; - *data = NULL; - rc = MAPI_E_NOT_ENOUGH_MEMORY; - } - else - { - stringContent = [[NSString alloc] initWithData: content - encoding: NSISOLatin1StringEncoding]; - - // *data = NULL; - // rc = MAPI_E_NOT_FOUND; - *data = [stringContent asUnicodeInMemCtx: memCtx]; - } - } - else - { - rc = MAPI_E_NOT_FOUND; - } - } - } - break; - - case PR_HTML: - { - NSMutableArray *keys; - NSArray *acceptedTypes; - - child = [self lookupObject: childURL]; - - acceptedTypes = [NSArray arrayWithObject: @"text/html"]; - keys = [NSMutableArray array]; - [child addRequiredKeysOfStructure: [child bodyStructure] - path: @"" toArray: keys acceptedTypes: acceptedTypes]; - if ([keys count] > 0) - { - id result; - NSString *key; - NSData *content; - - result = [child fetchParts: [keys objectsForKey: @"key" - notFoundMarker: nil]]; - result = [[result valueForKey: @"RawResponse"] objectForKey: - @"fetch"]; - key = [[keys objectAtIndex: 0] objectForKey: @"key"]; - content = [[result objectForKey: key] objectForKey: @"data"]; - if ([content length] > 3999) - { - [self registerValue: content - asProperty: proptag - forURL: childURL]; - *data = NULL; - rc = MAPI_E_NOT_ENOUGH_MEMORY; - } - else - *data = [content asBinaryInMemCtx: memCtx]; - } - else - { - *data = NULL; - rc = MAPI_E_NOT_FOUND; - } - } - - // *data = NULL; - // rc = MAPI_E_NOT_FOUND; - break; - - /* We don't handle any RTF content. */ - case PR_RTF_COMPRESSED: - rc = MAPI_E_NOT_ENOUGH_MEMORY; - break; - case PR_RTF_IN_SYNC: - *data = MAPIBoolValue (memCtx, NO); - break; - - - // #define PR_ITEM_TEMPORARY_FLAGS PROP_TAG(PT_LONG , 0x1097) /* 0x10970003 */ - - // 36030003 - PR_CONTENT_UNREAD - // 36020003 - PR_CONTENT_COUNT - // 10970003 - - // 81f80003 - // 10950003 - // 819d0003 - // 300b0102 - // 81fa000b - // 00300040 - // 00150040 - - case PR_RECEIVED_BY_NAME: - child = [self lookupObject: childURL]; - *data = [[child to] asUnicodeInMemCtx: memCtx]; - break; - - case PR_SENT_REPRESENTING_NAME_UNICODE: - child = [self lookupObject: childURL]; - *data = [[child from] asUnicodeInMemCtx: memCtx]; - break; - case PR_INTERNET_MESSAGE_ID: - case PR_INTERNET_MESSAGE_ID_UNICODE: - child = [self lookupObject: childURL]; - *data = [[child messageId] asUnicodeInMemCtx: memCtx]; - break; - - case PR_READ_RECEIPT_REQUESTED: // TODO - *data = MAPIBoolValue (memCtx, NO); - break; - - // /* BOOL */ - // case PR_ALTERNATE_RECIPIENT_ALLOWED: - // case PR_AUTO_FORWARDED: - // case PR_DL_EXPANSION_PROHIBITED: - // case PR_RESPONSE_REQUESTED: - // case PR_REPLY_REQUESTED: - // case PR_DELETE_AFTER_SUBMIT: - // case PR_PROCESSED: - // case PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED: - // case PR_RECIPIENT_REASSIGNMENT_PROHIBITED: - // rc = MAPI_E_NOT_FOUND; - // break; - - // /* PT_SYSTIME */ - // case PR_START_DATE: - // case PR_END_DATE: - // case PR_ACTION_DATE: - // case PR_FLAG_COMPLETE: - // case PR_DEFERRED_DELIVERY_TIME: - // case PR_REPORT_TIME: - // case PR_CLIENT_SUBMIT_TIME: - // case PR_DEFERRED_SEND_TIME: - // case PR_ORIGINAL_SUBMIT_TIME: - // rc = MAPI_E_NOT_FOUND; - // break; - - // /* PT_BINARY */ - // case PR_CONVERSATION_KEY: - // case PR_ORIGINALLY_INTENDED_RECIPIENT_NAME: - // case PR_PARENT_KEY: - // case PR_REPORT_TAG: - // case PR_SENT_REPRESENTING_SEARCH_KEY: - // case PR_RECEIVED_BY_ENTRYID: - // case PR_SENT_REPRESENTING_ENTRYID: - // case PR_RCVD_REPRESENTING_ENTRYID: - // case PR_ORIGINAL_AUTHOR_ENTRYID: - // case PR_REPLY_RECIPIENT_ENTRIES: - // case PR_RECEIVED_BY_SEARCH_KEY: - // case PR_RCVD_REPRESENTING_SEARCH_KEY: - // case PR_SEARCH_KEY: - // case PR_CHANGE_KEY: - // case PR_ORIGINAL_AUTHOR_SEARCH_KEY: - // case PR_CONVERSATION_INDEX: - // case PR_SENDER_ENTRYID: - // case PR_SENDER_SEARCH_KEY: - // rc = MAPI_E_NOT_FOUND; - // break; - - // /* PT_SVREID*/ - // case PR_SENT_MAILSVR_EID: - // rc = MAPI_E_NOT_FOUND; - // break; - - // /* PR_LONG */ - // case PR_OWNER_APPT_ID: - // case PR_ACTION_FLAG: - // case PR_INTERNET_CPID: - // case PR_INET_MAIL_OVERRIDE_FORMAT: - // rc = MAPI_E_NOT_FOUND; - // break; - - case PR_MSG_EDITOR_FORMAT: - { - NSMutableArray *keys; - NSArray *acceptedTypes; - uint32_t format; - - child = [self lookupObject: childURL]; - - format = 0; /* EDITOR_FORMAT_DONTKNOW */ - - acceptedTypes = [NSArray arrayWithObject: @"text/plain"]; - keys = [NSMutableArray array]; - [child addRequiredKeysOfStructure: [child bodyStructure] - path: @"" toArray: keys - acceptedTypes: acceptedTypes]; - if ([keys count] == 1) - format = EDITOR_FORMAT_PLAINTEXT; - - acceptedTypes = [NSArray arrayWithObject: @"text/html"]; - [keys removeAllObjects]; - [child addRequiredKeysOfStructure: [child bodyStructure] - path: @"" toArray: keys - acceptedTypes: acceptedTypes]; - if ([keys count] == 1) - format = EDITOR_FORMAT_HTML; - - *data = MAPILongValue (memCtx, format); - } - break; - - default: - rc = [super getMessageTableChildproperty: data - atURL: childURL - withTag: proptag - inFolder: folder - withFID: fid]; - } - - return rc; -} - -- (enum MAPISTATUS) getFolderTableChildproperty: (void **) data - atURL: (NSString *) childURL - withTag: (enum MAPITAGS) proptag - inFolder: (SOGoFolder *) folder - withFID: (uint64_t) fid -{ - enum MAPISTATUS rc; - - rc = MAPI_E_SUCCESS; - switch (proptag) - { - case PR_CONTENT_UNREAD: - *data = MAPILongValue (memCtx, 0); - break; - case PR_CONTAINER_CLASS_UNICODE: - *data = talloc_strdup (memCtx, "IPF.Note"); - break; - default: - rc = [super getFolderTableChildproperty: data - atURL: childURL - withTag: proptag - inFolder: folder - withFID: fid]; - } - - return rc; + return [MAPIStoreMailFolderTable class]; } - (int) openMessage: (struct mapistore_message *) msg - atURL: (NSString *) childURL + forKey: (NSString *) childKey + inTable: (MAPIStoreTable *) table { - id child; + SOGoMailObject *child; int rc; struct SRowSet *recipients; - struct SRow *properties; NSArray *to; NSInteger count, max; NGImap4EnvelopeAddress *currentAddress; NSString *name; - enum MAPITAGS tags[] = { PR_SUBJECT_UNICODE, PR_HASATTACH, - PR_MESSAGE_DELIVERY_TIME, PR_MESSAGE_FLAGS, - PR_FLAG_STATUS, PR_SENSITIVITY, - PR_SENT_REPRESENTING_NAME_UNICODE, - PR_INTERNET_MESSAGE_ID_UNICODE, - PR_READ_RECEIPT_REQUESTED }; - void *propValue; - child = [self lookupObject: childURL]; - if (child) + rc = [super openMessage: msg forKey: childKey inTable: table]; + + if (rc == MAPI_E_SUCCESS && table == messageTable) { + child = [[table folder] lookupName: childKey inContext: nil acquire: NO]; /* Retrieve recipients from the message */ to = [child toEnvelopeAddresses]; max = [to count]; @@ -517,155 +144,13 @@ static Class NSDataK, NSStringK; // name = [currentAddress personalName]; // if (![name length]) name = [currentAddress baseEMail]; + if (!name) + name = @""; set_SPropValue_proptag (&(recipients->aRow[count].lpProps[1]), PR_DISPLAY_NAME, [name asUnicodeInMemCtx: recipients->aRow[count].lpProps]); } msg->recipients = recipients; - - max = 9; - - properties = talloc_zero (memCtx, struct SRow); - properties->cValues = 0; - properties->ulAdrEntryPad = 0; - properties->lpProps = talloc_array (properties, struct SPropValue, max); - for (count = 0; count < max; count++) - { - if ([self getMessageTableChildproperty: &propValue - atURL: childURL - withTag: tags[count] - inFolder: nil - withFID: 0] - == MAPI_E_SUCCESS) - { - set_SPropValue_proptag (&(properties->lpProps[properties->cValues]), - tags[count], - propValue); - properties->cValues++; - // talloc_free (propValue); - } - } - - msg->properties = properties; - - rc = MAPI_E_SUCCESS; - } - else - rc = MAPI_E_NOT_FOUND; - - return rc; -} - -- (NSString *) backendIdentifierForProperty: (enum MAPITAGS) property -{ - static NSMutableDictionary *knownProperties = nil; - - if (!knownProperties) - { - knownProperties = [NSMutableDictionary new]; - [knownProperties setObject: @"DATE" - forKey: MAPIPropertyKey (PR_MESSAGE_DELIVERY_TIME)]; - } - - return [knownProperties objectForKey: MAPIPropertyKey (property)]; -} - -/* restrictions */ - -- (MAPIRestrictionState) evaluatePropertyRestriction: (struct mapi_SPropertyRestriction *) res - intoQualifier: (EOQualifier **) qualifier -{ - MAPIRestrictionState rc; - id value; - - value = NSObjectFromMAPISPropValue (&res->lpProp); - switch (res->ulPropTag) - { - case PR_MESSAGE_CLASS_UNICODE: - if ([value isEqualToString: @"IPM.Note"]) - rc = MAPIRestrictionStateAlwaysTrue; - else - rc = MAPIRestrictionStateAlwaysFalse; - break; - - case 0x0ff600fb: - /* resProperty: struct mapi_SPropertyRestriction - relop : 0x04 (4) - ulPropTag : UNKNOWN_ENUM_VALUE (0xFF600FB) - lpProp: struct mapi_SPropValue - ulPropTag : UNKNOWN_ENUM_VALUE (0xFF600FB) - value : union mapi_SPropValue_CTR(case 251) - bin : SBinary_short cb=21 -[0000] 01 01 00 1A 00 00 00 00 00 9C 83 E8 0F 00 00 00 ........ ........ -[0010] 00 00 00 00 00 ..... */ - rc = MAPIRestrictionStateAlwaysFalse; - break; - - case PR_CONVERSATION_KEY: - rc = MAPIRestrictionStateAlwaysFalse; - break; - - default: - rc = [super evaluatePropertyRestriction: res intoQualifier: qualifier]; - } - - return rc; -} - -- (MAPIRestrictionState) evaluateContentRestriction: (struct mapi_SContentRestriction *) res - intoQualifier: (EOQualifier **) qualifier -{ - MAPIRestrictionState rc; - id value; - - value = NSObjectFromMAPISPropValue (&res->lpProp); - if ([value isKindOfClass: NSDataK]) - { - value = [[NSString alloc] initWithData: value - encoding: NSUTF8StringEncoding]; - [value autorelease]; - } - else if (![value isKindOfClass: NSStringK]) - [NSException raise: @"MAPIStoreTypeConversionException" - format: @"unhandled content restriction for class '%@'", - NSStringFromClass ([value class])]; - - switch (res->ulPropTag) - { - case PR_MESSAGE_CLASS_UNICODE: - if ([value isEqualToString: @"IPM.Note"]) - rc = MAPIRestrictionStateAlwaysTrue; - else - rc = MAPIRestrictionStateAlwaysFalse; - break; - case PR_CONVERSATION_KEY: - rc = MAPIRestrictionStateAlwaysFalse; - break; - default: - rc = [super evaluateContentRestriction: res intoQualifier: qualifier]; - } - - return rc; -} - -- (MAPIRestrictionState) evaluateExistRestriction: (struct mapi_SExistRestriction *) res - intoQualifier: (EOQualifier **) qualifier -{ - MAPIRestrictionState rc; - - switch (res->ulPropTag) - { - case PR_MESSAGE_CLASS_UNICODE: - rc = MAPIRestrictionStateAlwaysFalse; - break; - case PR_MESSAGE_DELIVERY_TIME: - rc = MAPIRestrictionStateAlwaysTrue; - break; - case PR_PROCESSED: - rc = MAPIRestrictionStateAlwaysFalse; - break; - default: - rc = [super evaluateExistRestriction: res intoQualifier: qualifier]; } return rc; diff --git a/OpenChange/MAPIStoreMailMessageTable.h b/OpenChange/MAPIStoreMailMessageTable.h new file mode 100644 index 000000000..e3435398b --- /dev/null +++ b/OpenChange/MAPIStoreMailMessageTable.h @@ -0,0 +1,31 @@ +/* MAPIStoreMailMessageTable.h - this file is part of SOGo + * + * Copyright (C) 2010 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * 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 MAPISTOREMAILMESSAGETABLE_H +#define MAPISTOREMAILMESSAGETABLE_H + +#import "MAPIStoreMessageTable.h" + +@interface MAPIStoreMailMessageTable : MAPIStoreMessageTable +@end + +#endif /* MAPISTOREMAILMESSAGETABLE_H */ diff --git a/OpenChange/MAPIStoreMailMessageTable.m b/OpenChange/MAPIStoreMailMessageTable.m new file mode 100644 index 000000000..903acaf38 --- /dev/null +++ b/OpenChange/MAPIStoreMailMessageTable.m @@ -0,0 +1,538 @@ +/* MAPIStoreMailMessageTable.m - this file is part of SOGo + * + * Copyright (C) 2010 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * 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 + +#import + +#import + +#import +#import + +#import "MAPIStoreContext.h" +#import "MAPIStoreTypes.h" +#import "NSData+MAPIStore.h" +#import "NSCalendarDate+MAPIStore.h" +#import "NSString+MAPIStore.h" + +#import "MAPIStoreMailMessageTable.h" + +#include +#include + +@implementation MAPIStoreMailMessageTable + +static Class NSDataK, NSStringK; + ++ (void) initialize +{ + NSDataK = [NSData class]; + NSStringK = [NSString class]; +} + +- (NSArray *) childKeys +{ + return [folder toOneRelationshipKeys]; +} + +- (NSArray *) restrictedChildKeys +{ + NSArray *keys; + + if (restrictionState == MAPIRestrictionStateAlwaysTrue) + keys = [self cachedChildKeys]; + else if (restrictionState == MAPIRestrictionStateAlwaysFalse) + keys = [NSArray array]; + else + { + keys = [[folder fetchUIDsMatchingQualifier: restriction + sortOrdering: @"ARRIVAL"] + stringsWithFormat: @"%@.eml"]; + [self logWithFormat: @" restricted keys: %@", keys]; + } + + return keys; +} + +- (enum MAPISTATUS) getChildProperty: (void **) data + forKey: (NSString *) childKey + withTag: (enum MAPITAGS) propTag +{ + SOGoMailObject *child; + NSString *childURL, *stringValue; + enum MAPISTATUS rc; + + rc = MAPI_E_SUCCESS; + switch (propTag) + { + case PR_ICON_INDEX: // TODO + /* read mail, see http://msdn.microsoft.com/en-us/library/cc815472.aspx */ + *data = MAPILongValue (memCtx, 0x00000100); + break; + case PR_CONVERSATION_TOPIC: + case PR_CONVERSATION_TOPIC_UNICODE: + case PR_SUBJECT: + case PR_SUBJECT_UNICODE: + child = [self lookupChild: childKey]; + stringValue = [child decodedSubject]; + if (!stringValue) + stringValue = @""; + *data = [stringValue asUnicodeInMemCtx: memCtx]; + break; + case PR_MESSAGE_CLASS_UNICODE: + case PR_ORIG_MESSAGE_CLASS_UNICODE: + *data = talloc_strdup (memCtx, "IPM.Note"); + break; + case PidLidRemoteAttachment: // TODO + case PR_HASATTACH: // TODO + *data = MAPIBoolValue (memCtx, NO); + break; + case PidLidHeaderItem: + *data = MAPILongValue (memCtx, 0x00000000); + break; + case PidLidRemoteTransferSize: + rc = [self getChildProperty: data + forKey: childKey + withTag: PR_MESSAGE_SIZE]; + break; + case PR_CREATION_TIME: // DOUBT + case PR_LAST_MODIFICATION_TIME: // DOUBT + case PR_LATEST_DELIVERY_TIME: // DOUBT + case PR_ORIGINAL_SUBMIT_TIME: + case PR_CLIENT_SUBMIT_TIME: + case PR_MESSAGE_DELIVERY_TIME: + child = [self lookupChild: childKey]; + // offsetDate = [[child date] addYear: -1 month: 0 day: 0 + // hour: 0 minute: 0 second: 0]; + // *data = [offsetDate asFileTimeInMemCtx: memCtx]; + *data = [[child date] asFileTimeInMemCtx: memCtx]; + break; + case PR_MESSAGE_FLAGS: // TODO + // NSDictionary *coreInfos; + // NSArray *flags; + // child = [self lookupChild: childKey]; + // coreInfos = [child fetchCoreInfos]; + // flags = [coreInfos objectForKey: @"flags"]; + *data = MAPILongValue (memCtx, 0x02 | 0x20); // fromme + unmodified + break; + + case PR_FLAG_STATUS: // TODO + case PR_SENSITIVITY: // TODO + case PR_ORIGINAL_SENSITIVITY: // TODO + case PR_FOLLOWUP_ICON: // TODO + *data = MAPILongValue (memCtx, 0); + break; + + case PR_EXPIRY_TIME: // TODO + case PR_REPLY_TIME: + *data = [[NSCalendarDate date] asFileTimeInMemCtx: memCtx]; + break; + + case PR_SENT_REPRESENTING_ADDRTYPE_UNICODE: + *data = [@"SMTP" asUnicodeInMemCtx: memCtx]; + break; + case PR_SENT_REPRESENTING_EMAIL_ADDRESS_UNICODE: + case PR_SENT_REPRESENTING_NAME_UNICODE: + child = [self lookupChild: childKey]; + *data = [[child from] asUnicodeInMemCtx: memCtx]; + break; + + /* TODO: the following are supposed to be display names, separated by a semicolumn */ + case PR_RECEIVED_BY_NAME: + case PR_DISPLAY_TO: + case PR_DISPLAY_TO_UNICODE: + child = [self lookupChild: childKey]; + *data = [[child to] asUnicodeInMemCtx: memCtx]; + break; + case PR_DISPLAY_CC: + case PR_DISPLAY_CC_UNICODE: + child = [self lookupChild: childKey]; + *data = [[child cc] asUnicodeInMemCtx: memCtx]; + break; + case PR_DISPLAY_BCC: + case PR_DISPLAY_BCC_UNICODE: + *data = NULL; + rc = MAPI_E_NOT_FOUND; + break; + + case PidNameContentType: + *data = [@"message/rfc822" asUnicodeInMemCtx: memCtx]; + break; + + case PR_BODY: + case PR_BODY_UNICODE: + { + NSMutableArray *keys; + NSArray *acceptedTypes; + + child = [self lookupChild: childKey]; + + acceptedTypes = [NSArray arrayWithObjects: @"text/plain", + @"text/html", nil]; + keys = [NSMutableArray array]; + [child addRequiredKeysOfStructure: [child bodyStructure] + path: @"" toArray: keys + acceptedTypes: acceptedTypes]; + if ([keys count] == 0 || [keys count] == 2) + { + *data = NULL; + rc = MAPI_E_NOT_FOUND; + } + else + { + acceptedTypes = [NSArray arrayWithObject: @"text/plain"]; + [keys removeAllObjects]; + [child addRequiredKeysOfStructure: [child bodyStructure] + path: @"" toArray: keys + acceptedTypes: acceptedTypes]; + if ([keys count] > 0) + { + id result; + NSData *content; + NSString *key, *stringContent; + + result = [child fetchParts: [keys objectsForKey: @"key" + notFoundMarker: nil]]; + result = [[result valueForKey: @"RawResponse"] objectForKey: @"fetch"]; + key = [[keys objectAtIndex: 0] objectForKey: @"key"]; + content = [[result objectForKey: key] objectForKey: @"data"]; + if ([content length] > 3999) + { + childURL = [NSString stringWithFormat: @"%@%@", folderURL, childKey]; + [context registerValue: content + asProperty: propTag + forURL: childURL]; + *data = NULL; + rc = MAPI_E_NOT_ENOUGH_MEMORY; + } + else + { + stringContent = [[NSString alloc] initWithData: content + encoding: NSISOLatin1StringEncoding]; + + // *data = NULL; + // rc = MAPI_E_NOT_FOUND; + *data = [stringContent asUnicodeInMemCtx: memCtx]; + } + } + else + { + rc = MAPI_E_NOT_FOUND; + } + } + } + break; + + case PR_HTML: + { + NSMutableArray *keys; + NSArray *acceptedTypes; + + child = [self lookupChild: childKey]; + + acceptedTypes = [NSArray arrayWithObject: @"text/html"]; + keys = [NSMutableArray array]; + [child addRequiredKeysOfStructure: [child bodyStructure] + path: @"" toArray: keys acceptedTypes: acceptedTypes]; + if ([keys count] > 0) + { + id result; + NSString *key; + NSData *content; + + result = [child fetchParts: [keys objectsForKey: @"key" + notFoundMarker: nil]]; + result = [[result valueForKey: @"RawResponse"] objectForKey: + @"fetch"]; + key = [[keys objectAtIndex: 0] objectForKey: @"key"]; + content = [[result objectForKey: key] objectForKey: @"data"]; + if ([content length] > 3999) + { + childURL = [NSString stringWithFormat: @"%@%@", folderURL, childKey]; + [context registerValue: content + asProperty: propTag + forURL: childURL]; + *data = NULL; + rc = MAPI_E_NOT_ENOUGH_MEMORY; + } + else + *data = [content asBinaryInMemCtx: memCtx]; + } + else + { + *data = NULL; + rc = MAPI_E_NOT_FOUND; + } + } + break; + + /* We don't handle any RTF content. */ + case PR_RTF_COMPRESSED: + rc = MAPI_E_NOT_ENOUGH_MEMORY; + break; + case PR_RTF_IN_SYNC: + *data = MAPIBoolValue (memCtx, NO); + break; + case PR_INTERNET_MESSAGE_ID: + case PR_INTERNET_MESSAGE_ID_UNICODE: + child = [self lookupChild: childKey]; + *data = [[child messageId] asUnicodeInMemCtx: memCtx]; + break; + case PR_READ_RECEIPT_REQUESTED: // TODO + *data = MAPIBoolValue (memCtx, NO); + break; + case PidLidPrivate: + *data = MAPIBoolValue (memCtx, NO); + break; + case PidLidImapDeleted: + *data = MAPILongValue (memCtx, 0); + break; + + case PR_MSG_EDITOR_FORMAT: + { + NSMutableArray *keys; + NSArray *acceptedTypes; + uint32_t format; + + child = [self lookupChild: childKey]; + + format = 0; /* EDITOR_FORMAT_DONTKNOW */ + + acceptedTypes = [NSArray arrayWithObject: @"text/plain"]; + keys = [NSMutableArray array]; + [child addRequiredKeysOfStructure: [child bodyStructure] + path: @"" toArray: keys + acceptedTypes: acceptedTypes]; + if ([keys count] == 1) + format = EDITOR_FORMAT_PLAINTEXT; + + acceptedTypes = [NSArray arrayWithObject: @"text/html"]; + [keys removeAllObjects]; + [child addRequiredKeysOfStructure: [child bodyStructure] + path: @"" toArray: keys + acceptedTypes: acceptedTypes]; + if ([keys count] == 1) + format = EDITOR_FORMAT_HTML; + + *data = MAPILongValue (memCtx, format); + } + break; + + case PidLidReminderSet: // TODO + case PidLidUseTnef: // TODO + *data = MAPIBoolValue (memCtx, NO); + break; + case PidLidRemoteStatus: // TODO + *data = MAPILongValue (memCtx, 0); + break; + case PidLidSmartNoAttach: // TODO + case PidLidAgingDontAgeMe: // TODO + *data = MAPIBoolValue (memCtx, YES); + break; + +// PidLidFlagRequest +// PidLidBillingInformation +// PidLidMileage +// PidLidCommonEnd +// PidLidCommonStart +// PidLidNonSendableBcc +// PidLidNonSendableCc +// PidLidNonSendtableTo +// PidLidNonSendBccTrackStatus +// PidLidNonSendCcTrackStatus +// PidLidNonSendToTrackStatus +// PidLidReminderDelta +// PidLidReminderFileParameter +// PidLidReminderSignalTime +// PidLidReminderOverride +// PidLidReminderPlaySound +// PidLidReminderTime +// PidLidReminderType +// PidLidSmartNoAttach +// PidLidTaskGlobalId +// PidLidTaskMode +// PidLidVerbResponse +// PidLidVerbStream +// PidLidInternetAccountName +// PidLidInternetAccountStamp +// PidLidContactLinkName +// PidLidContactLinkEntry +// PidLidContactLinkSearchKey +// PidLidSpamOriginalFolder + + default: + rc = [super getChildProperty: data + forKey: childKey + withTag: propTag]; + } + + return rc; +} + + +- (NSString *) backendIdentifierForProperty: (enum MAPITAGS) property +{ + static NSMutableDictionary *knownProperties = nil; + + if (!knownProperties) + { + knownProperties = [NSMutableDictionary new]; + [knownProperties setObject: @"DATE" + forKey: MAPIPropertyKey (PR_CLIENT_SUBMIT_TIME)]; + [knownProperties setObject: @"DATE" + forKey: MAPIPropertyKey (PR_MESSAGE_DELIVERY_TIME)]; + [knownProperties setObject: @"MESSAGE-ID" + forKey: MAPIPropertyKey (PR_INTERNET_MESSAGE_ID_UNICODE)]; + } + + return [knownProperties objectForKey: MAPIPropertyKey (property)]; +} + +/* restrictions */ + +- (void) setRestrictions: (const struct mapi_SRestriction *) res +{ + [super setRestrictions: res]; +} + +- (MAPIRestrictionState) evaluatePropertyRestriction: (struct mapi_SPropertyRestriction *) res + intoQualifier: (EOQualifier **) qualifier +{ + MAPIRestrictionState rc; + id value; + + value = NSObjectFromMAPISPropValue (&res->lpProp); + switch (res->ulPropTag) + { + case PR_MESSAGE_CLASS_UNICODE: + if ([value isEqualToString: @"IPM.Note"]) + rc = MAPIRestrictionStateAlwaysTrue; + else + rc = MAPIRestrictionStateAlwaysFalse; + break; + + case PidLidAppointmentStartWhole: + case PidLidAppointmentEndWhole: + case PidLidRecurring: + [self logWithFormat: @"apt restriction on mail folder?"]; + rc = MAPIRestrictionStateAlwaysFalse; + break; + + case PidLidAutoProcessState: + if ([value intValue] == 0) + rc = MAPIRestrictionStateAlwaysTrue; + else + rc = MAPIRestrictionStateAlwaysFalse; + break; + + case PR_SEARCH_KEY: + rc = MAPIRestrictionStateAlwaysFalse; + break; + + case 0x0fff00fb: /* PR_ENTRY_ID in PtyServerId form */ + case 0x0ff600fb: + /* resProperty: struct mapi_SPropertyRestriction + relop : 0x04 (4) + ulPropTag : UNKNOWN_ENUM_VALUE (0xFF600FB) + lpProp: struct mapi_SPropValue + ulPropTag : UNKNOWN_ENUM_VALUE (0xFF600FB) + value : union mapi_SPropValue_CTR(case 251) + bin : SBinary_short cb=21 +[0000] 01 01 00 1A 00 00 00 00 00 9C 83 E8 0F 00 00 00 ........ ........ +[0010] 00 00 00 00 00 ..... */ + rc = MAPIRestrictionStateAlwaysFalse; + break; + + case PR_CONVERSATION_KEY: + rc = MAPIRestrictionStateAlwaysFalse; + break; + + default: + rc = [super evaluatePropertyRestriction: res intoQualifier: qualifier]; + } + + return rc; +} + +- (MAPIRestrictionState) evaluateContentRestriction: (struct mapi_SContentRestriction *) res + intoQualifier: (EOQualifier **) qualifier +{ + MAPIRestrictionState rc; + id value; + + value = NSObjectFromMAPISPropValue (&res->lpProp); + if ([value isKindOfClass: NSDataK]) + { + value = [[NSString alloc] initWithData: value + encoding: NSUTF8StringEncoding]; + [value autorelease]; + } + else if (![value isKindOfClass: NSStringK]) + [NSException raise: @"MAPIStoreTypeConversionException" + format: @"unhandled content restriction for class '%@'", + NSStringFromClass ([value class])]; + + switch (res->ulPropTag) + { + case PR_MESSAGE_CLASS_UNICODE: + if ([value isEqualToString: @"IPM.Note"]) + rc = MAPIRestrictionStateAlwaysTrue; + else + rc = MAPIRestrictionStateAlwaysFalse; + break; + case PR_CONVERSATION_KEY: + rc = MAPIRestrictionStateAlwaysFalse; + break; + default: + rc = [super evaluateContentRestriction: res intoQualifier: qualifier]; + } + + return rc; +} + +- (MAPIRestrictionState) evaluateExistRestriction: (struct mapi_SExistRestriction *) res + intoQualifier: (EOQualifier **) qualifier +{ + MAPIRestrictionState rc; + + switch (res->ulPropTag) + { + case PR_MESSAGE_CLASS_UNICODE: + rc = MAPIRestrictionStateAlwaysFalse; + break; + case PR_MESSAGE_DELIVERY_TIME: + rc = MAPIRestrictionStateAlwaysTrue; + break; + case PR_PROCESSED: + rc = MAPIRestrictionStateAlwaysFalse; + break; + default: + rc = [super evaluateExistRestriction: res intoQualifier: qualifier]; + } + + return rc; +} + +@end