diff --git a/ChangeLog b/ChangeLog index f638884c0..6598183fd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,33 @@ 2010-12-03 Wolfgang Sourdeau + * OpenChange/MAPIStoreContext.m + (-setRestrictions:withFMID:andTableType:getTableStatus:): new + backend method that accepts a struct mapi_SRestriction * in order + to filter the table rows. + (-evaluateRestriction:intoQualifier:) + (-evaluateNotRestriction:intoQualifier:) + (-evaluateAndRestriction:intoQualifier:) + (-evaluateOrRestriction:intoQualifier:): new low-level restriction + handlers for converting MAPI restrictions into EOQualifier + equivalents. + (-evaluateContentRestriction:intoQualifier:) + (-evaluatePropertyRestriction:intoQualifier:) + (-evaluateBitmaskRestriction:intoQualifier:) + (-evaluateExistRestriction:intoQualifier:) new overridable + restriction handlers. + (-backendIdentifierForProperty:): new overridable restriction + helper for converting restriction attributes into database or IMAP + fields, depending on the module in use. Used by the topmost + version of -evaluatePropertyRestriction:intoQualifier: for + handling "needs eval" restriction types. + (-saveOrSubmitChangesInMessageWithMID:andFlags:save:) prevent any + creation or modification of messages with a type attribute of + "IPM.Microsoft.FolderDesign.NamedView", at least for now, because + no module is able to handle those view-related messages. + + * OpenChange/MAPIStoreSpoolerContext.m: new experimental subclass + of MAPIStoreOutboxContext. + * OpenChange/MAPIStoreTypes.m (NSObjectFromMAPISPropValue): new helper function, similar in semantics to NSObjectFromSPropValue but taking a struct mapi_SPropValue * as parameter. diff --git a/OpenChange/MAPIStoreCalendarContext.m b/OpenChange/MAPIStoreCalendarContext.m index 59fda2e3e..2aa4ab9c4 100644 --- a/OpenChange/MAPIStoreCalendarContext.m +++ b/OpenChange/MAPIStoreCalendarContext.m @@ -20,6 +20,8 @@ * Boston, MA 02111-1307, USA. */ +#import + #import #import @@ -201,4 +203,16 @@ // return rc; // } +- (NSString *) backendIdentifierForProperty: (enum MAPITAGS) property +{ + static NSMutableDictionary *knownProperties = nil; + + if (!knownProperties) + { + knownProperties = [NSMutableDictionary new]; + } + + return [knownProperties objectForKey: MAPIPropertyNumber (property)]; +} + @end diff --git a/OpenChange/MAPIStoreContactsContext.m b/OpenChange/MAPIStoreContactsContext.m index 73825db91..5f1734a0f 100644 --- a/OpenChange/MAPIStoreContactsContext.m +++ b/OpenChange/MAPIStoreContactsContext.m @@ -20,6 +20,7 @@ * Boston, MA 02111-1307, USA. */ +#import #import #import @@ -319,4 +320,58 @@ // return rc; // } +- (NSString *) backendIdentifierForProperty: (enum MAPITAGS) property +{ + static NSMutableDictionary *knownProperties = nil; + + if (!knownProperties) + { + knownProperties = [NSMutableDictionary new]; + [knownProperties setObject: @"c_mail" + forKey: MAPIPropertyNumber (0x81ae001f)]; + [knownProperties setObject: @"c_mail" + forKey: MAPIPropertyNumber (0x81b3001f)]; + [knownProperties setObject: @"c_mail" + forKey: MAPIPropertyNumber (PR_EMS_AB_GROUP_BY_ATTR_2_UNICODE)]; + [knownProperties setObject: @"c_cn" + forKey: MAPIPropertyNumber (PR_DISPLAY_NAME_UNICODE)]; + } + + return [knownProperties objectForKey: MAPIPropertyNumber (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 isKindOfClass: [NSString class]] + && [value isEqualToString: @"IPM.Contact"]) + rc = MAPIRestrictionStateAlwaysTrue; + else + rc = MAPIRestrictionStateAlwaysFalse; + break; + case PR_EMS_AB_RAS_ACCOUNT_UNICODE: + case 0x81b2001f: + case PR_EMS_AB_GROUP_BY_ATTR_1_UNICODE: + if ([value isEqualToString: @"SMTP"]) + rc = MAPIRestrictionStateAlwaysTrue; + else + rc = MAPIRestrictionStateAlwaysFalse; + break; + + default: + rc = [super evaluatePropertyRestriction: res intoQualifier: qualifier]; + } + + return rc; +} + @end diff --git a/OpenChange/MAPIStoreContext.h b/OpenChange/MAPIStoreContext.h index bef430dfb..b71ce8487 100644 --- a/OpenChange/MAPIStoreContext.h +++ b/OpenChange/MAPIStoreContext.h @@ -37,9 +37,12 @@ @class NSArray; @class NSFileHandle; +@class NSMutableArray; @class NSMutableDictionary; @class NSString; +@class EOQualifier; + @class WOContext; @class SOGoFolder; @@ -48,6 +51,13 @@ @class MAPIStoreAuthenticator; @class MAPIStoreMapping; +typedef enum { + MAPIRestrictionStateAlwaysFalse = NO, + MAPIRestrictionStateAlwaysTrue = YES, + MAPIRestrictionStateNeedsEval, /* needs passing of qualifier to underlying + database */ +} MAPIRestrictionState; + @interface MAPIStoreContext : NSObject { struct mapistore_context *memCtx; @@ -66,6 +76,9 @@ NSMutableDictionary *messageCache; NSMutableDictionary *subfolderCache; id moduleFolder; + + MAPIRestrictionState restrictionState; + EOQualifier *restriction; } + (id) contextFromURI: (const char *) newUri @@ -93,6 +106,11 @@ byName: (const char *) foldername inParentFID: (uint64_t) parent_fid; +- (int) setRestrictions: (struct mapi_SRestriction *) res + withFMID: (uint64_t) fmid + andTableType: (uint8_t) type + getTableStatus: (uint8_t *) tableStatus; + - (enum MAPISTATUS) getTableProperty: (void **) data withTag: (enum MAPITAGS) proptag atPosition: (uint32_t) pos @@ -146,6 +164,18 @@ asProperty: (enum MAPITAGS) property forURL: (NSString *) url; + +/* restrictions */ + +- (MAPIRestrictionState) evaluateRestriction: (struct mapi_SRestriction *) res + intoQualifier: (EOQualifier **) qualifier; +- (MAPIRestrictionState) evaluateNotRestriction: (struct mapi_SNotRestriction *) res + intoQualifier: (EOQualifier **) qualifierPtr; +- (MAPIRestrictionState) evaluateAndRestriction: (struct mapi_SAndRestriction *) res + intoQualifier: (EOQualifier **) qualifierPtr; +- (MAPIRestrictionState) evaluateOrRestriction: (struct mapi_SOrRestriction *) res + intoQualifier: (EOQualifier **) qualifierPtr; + /* subclass methods */ + (NSString *) MAPIModuleName; + (void) registerFixedMappings: (MAPIStoreMapping *) storeMapping; @@ -180,6 +210,18 @@ inRow: (struct SRow *) aRow atURL: (NSString *) childURL; +- (NSString *) backendIdentifierForProperty: (enum MAPITAGS) property; + +/* restrictions */ +- (MAPIRestrictionState) evaluateContentRestriction: (struct mapi_SContentRestriction *) res + intoQualifier: (EOQualifier **) qualifier; +- (MAPIRestrictionState) evaluatePropertyRestriction: (struct mapi_SPropertyRestriction *) res + intoQualifier: (EOQualifier **) qualifier; +- (MAPIRestrictionState) evaluateBitmaskRestriction: (struct mapi_SBitmaskRestriction *) res + intoQualifier: (EOQualifier **) qualifier; +- (MAPIRestrictionState) evaluateExistRestriction: (struct mapi_SExistRestriction *) res + intoQualifier: (EOQualifier **) qualifier; + @end #endif /* MAPISTORECONTEXT_H */ diff --git a/OpenChange/MAPIStoreContext.m b/OpenChange/MAPIStoreContext.m index a6270985d..c0057aa0b 100644 --- a/OpenChange/MAPIStoreContext.m +++ b/OpenChange/MAPIStoreContext.m @@ -27,6 +27,8 @@ #import #import +#import + #import #import @@ -73,6 +75,202 @@ @end +/* restriction helpers */ +static NSString * +MAPIStringForRestrictionState (MAPIRestrictionState state) +{ + NSString *stateStr; + + if (state == MAPIRestrictionStateAlwaysTrue) + stateStr = @"true"; + else if (state == MAPIRestrictionStateAlwaysFalse) + stateStr = @"false"; + else + stateStr = @"needs eval"; + + return stateStr; +} + +static NSString * +MAPIStringForRestriction (struct mapi_SRestriction *resPtr); + +// static NSString * +// _MAPIIndentString(int indent) +// { +// NSString *spaces; +// char *buffer; + +// if (indent > 0) +// { +// buffer = malloc (indent + 1); +// memset (buffer, 32, indent); +// *(buffer+indent) = 0; +// spaces = [NSString stringWithFormat: @"%s", buffer]; +// free (buffer); +// } +// else +// spaces = @""; + +// return spaces; +// } + +static NSString * +MAPIStringForAndRestriction (struct mapi_SAndRestriction *resAnd) +{ + NSMutableArray *restrictions; + uint16_t count; + + restrictions = [NSMutableArray arrayWithCapacity: 8]; + for (count = 0; count < resAnd->cRes; count++) + [restrictions addObject: MAPIStringForRestriction ((struct mapi_SRestriction *) resAnd->res + count)]; + + return [NSString stringWithFormat: @"(%@)", [restrictions componentsJoinedByString: @" && "]]; +} + +static NSString * +MAPIStringForOrRestriction (struct mapi_SOrRestriction *resOr) +{ + NSMutableArray *restrictions; + uint16_t count; + + restrictions = [NSMutableArray arrayWithCapacity: 8]; + for (count = 0; count < resOr->cRes; count++) + [restrictions addObject: MAPIStringForRestriction ((struct mapi_SRestriction *) resOr->res + count)]; + + return [NSString stringWithFormat: @"(%@)", [restrictions componentsJoinedByString: @" || "]]; +} + +static NSString * +MAPIStringForNotRestriction (struct mapi_SNotRestriction *resNot) +{ + return [NSString stringWithFormat: @"!(%@)", + MAPIStringForRestriction ((struct mapi_SRestriction *) &resNot->res)]; +} + +static NSString * +MAPIStringForContentRestriction (struct mapi_SContentRestriction *resContent) +{ + NSString *eqMatch, *caseMatch; + id value; + const char *propName; + + switch (resContent->fuzzy & 0xf) + { + case 0: eqMatch = @"eq"; break; + case 1: eqMatch = @"substring"; break; + case 2: eqMatch = @"prefix"; break; + default: eqMatch = @"[unknown]"; + } + + switch (((resContent->fuzzy) >> 16) & 0xf) + { + case 0: caseMatch = @"fl"; break; + case 1: caseMatch = @"nc"; break; + case 2: caseMatch = @"ns"; break; + case 4: caseMatch = @"lo"; break; + default: caseMatch = @"[unknown]"; + } + + propName = get_proptag_name (resContent->ulPropTag); + if (!propName) + propName = ""; + + value = NSObjectFromMAPISPropValue (&resContent->lpProp); + + return [NSString stringWithFormat: @"%s(0x%.8x) %@,%@ %@", + propName, resContent->ulPropTag, eqMatch, caseMatch, value]; +} + +static NSString * +MAPIStringForExistRestriction (struct mapi_SExistRestriction *resExist) +{ + const char *propName; + + propName = get_proptag_name (resExist->ulPropTag); + if (!propName) + propName = ""; + + return [NSString stringWithFormat: @"%s(0x%.8x) IS NOT NULL", propName, resExist->ulPropTag]; +} + +static NSString * +MAPIStringForPropertyRestriction (struct mapi_SPropertyRestriction *resProperty) +{ + static NSString *operators[] = { @"<", @"<=", @">", @">=", @"==", @"!=", + @"=~" }; + NSString *operator; + id value; + const char *propName; + + propName = get_proptag_name (resProperty->ulPropTag); + if (!propName) + propName = ""; + + if (resProperty->relop > 0 && resProperty->relop < 6) + operator = operators[resProperty->relop]; + else + operator = [NSString stringWithFormat: @"", resProperty->relop]; + value = NSObjectFromMAPISPropValue (&resProperty->lpProp); + + return [NSString stringWithFormat: @"%s(0x%.8x) %@ %@", + propName, resProperty->ulPropTag, operator, value]; +} + +static NSString * +MAPIStringForBitmaskRestriction (struct mapi_SBitmaskRestriction *resBitmask) +{ + NSString *format; + const char *propName; + + propName = get_proptag_name (resBitmask->ulPropTag); + if (!propName) + propName = ""; + + if (resBitmask->relMBR == 0) + format = @"((%s(0x%.8x) & 0x%.8x))"; + else + format = @"((^%s(0x%.8x) & 0x%.8x))"; + + return [NSString stringWithFormat: format, + propName, resBitmask->ulPropTag, resBitmask->ulMask]; +} + +static NSString * +MAPIStringForRestriction (struct mapi_SRestriction *resPtr) +{ + NSString *restrictionStr; + + if (resPtr) + { + switch (resPtr->rt) + { + // RES_CONTENT=(int)(0x3), + // RES_BITMASK=(int)(0x6), + // RES_EXIST=(int)(0x8), + + case 0: restrictionStr = MAPIStringForAndRestriction(&resPtr->res.resAnd); break; + case 1: restrictionStr = MAPIStringForOrRestriction(&resPtr->res.resOr); break; + case 2: restrictionStr = MAPIStringForNotRestriction(&resPtr->res.resNot); break; + case 3: restrictionStr = MAPIStringForContentRestriction(&resPtr->res.resContent); break; + case 4: restrictionStr = MAPIStringForPropertyRestriction(&resPtr->res.resProperty); break; + case 6: restrictionStr = MAPIStringForBitmaskRestriction(&resPtr->res.resBitmask); break; + case 8: restrictionStr = MAPIStringForExistRestriction(&resPtr->res.resExist); break; + // case 5: MAPIStringForComparePropsRestriction(&resPtr->res.resCompareProps); break; + // case 7: MAPIStringForPropertyRestriction(&resPtr->res.resProperty); break; + // case 9: MAPIStringForPropertyRestriction(&resPtr->res.resProperty); break; + // case 10: MAPIStringForPropertyRestriction(&resPtr->res.resProperty); break; + default: + restrictionStr + = [NSString stringWithFormat: @"[unhandled restriction type: %d]", + resPtr->rt]; + } + } + else + restrictionStr = @"[unrestricted]"; + + return restrictionStr; +} + @implementation MAPIStoreContext : NSObject /* sogo://username:password@{contacts,calendar,tasks,journal,notes,mail}/dossier/id */ @@ -212,6 +410,9 @@ _prepareContextClass (struct mapistore_context *newMemCtx, moduleFolder = nil; uri = nil; baseContextSet = NO; + + restrictionState = MAPIRestrictionStateAlwaysTrue; + restriction = nil; } [self logWithFormat: @"-init"]; @@ -224,6 +425,7 @@ _prepareContextClass (struct mapistore_context *newMemCtx, [self logWithFormat: @"-dealloc: %@", self]; [parentFoldersBag release]; + [restriction release]; [messageCache release]; [subfolderCache release]; @@ -479,7 +681,11 @@ _prepareContextClass (struct mapistore_context *newMemCtx, - (int) openDir: (uint64_t) fid inParentFID: (uint64_t) parentFID { - [self logWithFormat: @"UNIMPLEMENTED METHOD '%s' (%d)", __FUNCTION__, __LINE__]; + [self logWithFormat: + @"UNIMPLEMENTED METHOD '%s' (%d):\n fid=0x%.16x, parentFID=0x%.16x", + __FUNCTION__, __LINE__, + (unsigned long long) fid, + (unsigned long long) parentFID]; return MAPISTORE_ERROR; } @@ -565,36 +771,50 @@ _prepareContextClass (struct mapistore_context *newMemCtx, [self logWithFormat: @"METHOD '%s' (%d)", __FUNCTION__, __LINE__]; - url = [mapping urlFromID: fid]; - if (url) + [self logWithFormat: @"context restriction state is: %@", + MAPIStringForRestrictionState (restrictionState)]; + if (restriction) + [self logWithFormat: @" active qualifier: %@", restriction]; + + + if (restrictionState == MAPIRestrictionStateAlwaysFalse) { - switch (tableType) - { - case MAPISTORE_FOLDER_TABLE: - ids = [self _subfolderKeysForFolderURL: url]; - break; - case MAPISTORE_MESSAGE_TABLE: - ids = [self _messageKeysForFolderURL: url]; - break; - default: - [self errorWithFormat: @"%s: value of tableType not handled: %d", - __FUNCTION__, tableType]; - rc = MAPISTORE_ERR_INVALID_PARAMETER; - ids = nil; - } - - if ([ids isKindOfClass: NSArrayK]) - { - rc = MAPI_E_SUCCESS; - *rowCount = [ids count]; - } - else - rc = MAPISTORE_ERR_NO_DIRECTORY; + *rowCount = 0; + rc = MAPI_E_SUCCESS; } else { - [self errorWithFormat: @"No url found for FID: %lld", fid]; - rc = MAPISTORE_ERR_NOT_FOUND; + url = [mapping urlFromID: fid]; + if (url) + { + switch (tableType) + { + case MAPISTORE_FOLDER_TABLE: + ids = [self _subfolderKeysForFolderURL: url]; + break; + case MAPISTORE_MESSAGE_TABLE: + ids = [self _messageKeysForFolderURL: url]; + break; + default: + [self errorWithFormat: @"%s: value of tableType not handled: %d", + __FUNCTION__, tableType]; + rc = MAPISTORE_ERR_INVALID_PARAMETER; + ids = nil; + } + + if ([ids isKindOfClass: NSArrayK]) + { + rc = MAPI_E_SUCCESS; + *rowCount = [ids count]; + } + else + rc = MAPISTORE_ERR_NO_DIRECTORY; + } + else + { + [self errorWithFormat: @"No url found for FID: %lld", fid]; + rc = MAPISTORE_ERR_NOT_FOUND; + } } return rc; @@ -842,6 +1062,273 @@ _prepareContextClass (struct mapistore_context *newMemCtx, return rc; } +- (void) logRestriction: (struct mapi_SRestriction *) res + withState: (MAPIRestrictionState) state +{ + NSString *resStr; + + resStr = MAPIStringForRestriction (res); + + [self logWithFormat: @"%@ --> %@", resStr, MAPIStringForRestrictionState (state)]; +} + +- (MAPIRestrictionState) evaluateRestriction: (struct mapi_SRestriction *) res + intoQualifier: (EOQualifier **) qualifier +{ + MAPIRestrictionState state; + + switch (res->rt) + { + /* basic operators */ + case 0: state = [self evaluateAndRestriction: &res->res.resAnd + intoQualifier: qualifier]; + break; + case 1: state = [self evaluateOrRestriction: &res->res.resOr + intoQualifier: qualifier]; + break; + case 2: state = [self evaluateNotRestriction: &res->res.resNot + intoQualifier: qualifier]; + break; + + /* content restrictions */ + case 3: state = [self evaluateContentRestriction: &res->res.resContent + intoQualifier: qualifier]; + break; + case 4: state = [self evaluatePropertyRestriction: &res->res.resProperty + intoQualifier: qualifier]; + break; + case 6: state = [self evaluateBitmaskRestriction: &res->res.resBitmask + intoQualifier: qualifier]; + break; + case 8: state = [self evaluateExistRestriction: &res->res.resExist + intoQualifier: qualifier]; + break; + // case 5: MAPIStringForComparePropsRestriction(&resPtr->res.resCompareProps); break; + // case 7: MAPIStringForPropertyRestriction(&resPtr->res.resProperty); break; + // case 9: MAPIStringForPropertyRestriction(&resPtr->res.resProperty); break; + // case 10: MAPIStringForPropertyRestriction(&resPtr->res.resProperty); break; + default: + [NSException raise: @"MAPIStoreRestrictionException" + format: @"unhandled restriction type"]; + state = MAPIRestrictionStateAlwaysTrue; + } + + [self logRestriction: res withState: state]; + + return state; +} + +- (MAPIRestrictionState) evaluateNotRestriction: (struct mapi_SNotRestriction *) res + intoQualifier: (EOQualifier **) qualifierPtr +{ + MAPIRestrictionState state, subState; + EONotQualifier *qualifier; + EOQualifier *subQualifier; + + subState = [self evaluateRestriction: (struct mapi_SRestriction *)&res->res + intoQualifier: &subQualifier]; + if (subState == MAPIRestrictionStateAlwaysTrue) + state = MAPIRestrictionStateAlwaysFalse; + else if (subState == MAPIRestrictionStateAlwaysFalse) + state = MAPIRestrictionStateAlwaysTrue; + else + { + state = MAPIRestrictionStateNeedsEval; + qualifier = [[EONotQualifier alloc] initWithQualifier: subQualifier]; + [qualifier autorelease]; + *qualifierPtr = qualifier; + } + + return state; +} + +- (MAPIRestrictionState) evaluateAndRestriction: (struct mapi_SAndRestriction *) res + intoQualifier: (EOQualifier **) qualifierPtr +{ + MAPIRestrictionState state, subState; + EOAndQualifier *qualifier; + EOQualifier *subQualifier; + NSMutableArray *subQualifiers; + uint16_t count; + + state = MAPIRestrictionStateNeedsEval; + + subQualifiers = [NSMutableArray arrayWithCapacity: 8]; + for (count = 0; + state == MAPIRestrictionStateNeedsEval && count < res->cRes; + count++) + { + subState = [self evaluateRestriction: (struct mapi_SRestriction *) res->res + count + intoQualifier: &subQualifier]; + if (subState == MAPIRestrictionStateNeedsEval) + [subQualifiers addObject: subQualifier]; + else if (subState == MAPIRestrictionStateAlwaysFalse) + state = MAPIRestrictionStateAlwaysFalse; + } + + if (state == MAPIRestrictionStateNeedsEval) + { + if ([subQualifiers count] == 0) + state = MAPIRestrictionStateAlwaysTrue; + else + { + qualifier = [[EOAndQualifier alloc] + initWithQualifierArray: subQualifiers]; + [qualifier autorelease]; + *qualifierPtr = qualifier; + } + } + + return state; +} + +- (MAPIRestrictionState) evaluateOrRestriction: (struct mapi_SOrRestriction *) res + intoQualifier: (EOQualifier **) qualifierPtr +{ + MAPIRestrictionState state, subState; + EOOrQualifier *qualifier; + EOQualifier *subQualifier; + NSMutableArray *subQualifiers; + uint16_t count, falseCount; + + state = MAPIRestrictionStateNeedsEval; + + falseCount = 0; + subQualifiers = [NSMutableArray arrayWithCapacity: 8]; + for (count = 0; + state == MAPIRestrictionStateNeedsEval && count < res->cRes; + count++) + { + subState = [self evaluateRestriction: (struct mapi_SRestriction *) res->res + count + intoQualifier: &subQualifier]; + if (subState == MAPIRestrictionStateNeedsEval) + [subQualifiers addObject: subQualifier]; + else if (subState == MAPIRestrictionStateAlwaysTrue) + state = MAPIRestrictionStateAlwaysTrue; + else + falseCount++; + } + + if (falseCount == res->cRes) + state = MAPIRestrictionStateAlwaysFalse; + else if ([subQualifiers count] == 0) + state = MAPIRestrictionStateAlwaysTrue; + + if (state == MAPIRestrictionStateNeedsEval) + { + qualifier = [[EOOrQualifier alloc] + initWithQualifierArray: subQualifiers]; + [qualifier autorelease]; + *qualifierPtr = qualifier; + } + + return state; +} + +- (NSString *) backendIdentifierForProperty: (enum MAPITAGS) property +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + +- (MAPIRestrictionState) evaluateContentRestriction: (struct mapi_SContentRestriction *) res + intoQualifier: (EOQualifier **) qualifier +{ + [self subclassResponsibility: _cmd]; + + return MAPIRestrictionStateAlwaysTrue; +} + +- (void) _raiseUnhandledPropertyException: (enum MAPITAGS) property +{ + const char *propName; + + propName = get_proptag_name (property); + if (!propName) + propName = ""; + [NSException raise: @"MAPIStoreUnhandledPropertyException" + format: @"property %s (%.8x) has no matching field name (%@)", + propName, property, self]; +} + +- (MAPIRestrictionState) evaluatePropertyRestriction: (struct mapi_SPropertyRestriction *) res + intoQualifier: (EOQualifier **) qualifier +{ + static SEL operators[] = { EOQualifierOperatorLessThan, + EOQualifierOperatorLessThanOrEqualTo, + EOQualifierOperatorGreaterThan, + EOQualifierOperatorGreaterThanOrEqualTo, + EOQualifierOperatorEqual, + EOQualifierOperatorNotEqual, + EOQualifierOperatorContains }; + SEL operator; + id value; + NSString *property; + + property = [self backendIdentifierForProperty: res->ulPropTag]; + if (!property) + [self _raiseUnhandledPropertyException: res->ulPropTag]; + + if (res->relop > 0 && res->relop < 6) + operator = operators[res->relop]; + else + { + operator = NULL; + [NSException raise: @"MAPIStoreRestrictionException" + format: @"unhandled operator type"]; + } + + value = NSObjectFromMAPISPropValue (&res->lpProp); + *qualifier = [[EOKeyValueQualifier alloc] initWithKey: property + operatorSelector: operator + value: value]; + [*qualifier autorelease]; + + return MAPIRestrictionStateNeedsEval; +} + +- (MAPIRestrictionState) evaluateBitmaskRestriction: (struct mapi_SBitmaskRestriction *) res + intoQualifier: (EOQualifier **) qualifier +{ + [self subclassResponsibility: _cmd]; + + return MAPIRestrictionStateAlwaysTrue; +} + +- (MAPIRestrictionState) evaluateExistRestriction: (struct mapi_SExistRestriction *) res + intoQualifier: (EOQualifier **) qualifier +{ + [self subclassResponsibility: _cmd]; + + return MAPIRestrictionStateAlwaysTrue; +} + +- (int) setRestrictions: (struct mapi_SRestriction *) res + withFMID: (uint64_t) fmid + andTableType: (uint8_t) type + getTableStatus: (uint8_t *) tableStatus +{ + NSLog (@"set restriction to (table type: %d): %@", + type, MAPIStringForRestriction (res)); + + [restriction release]; + if (res) + restrictionState = [self evaluateRestriction: res + intoQualifier: &restriction]; + else + restrictionState = MAPIRestrictionStateAlwaysTrue; + + if (restrictionState == MAPIRestrictionStateNeedsEval) + [restriction retain]; + else + restriction = nil; + + [self logWithFormat: @" resulting EOQualifier: %@", restriction]; + + return MAPISTORE_SUCCESS; +} + - (enum MAPISTATUS) getTableProperty: (void **) data withTag: (enum MAPITAGS) proptag atPosition: (uint32_t) pos @@ -853,76 +1340,87 @@ _prepareContextClass (struct mapistore_context *newMemCtx, SOGoFolder *folder; int rc; - // [self logWithFormat: @"METHOD '%s' (%d) -- proptag: 0x%.8x, pos: %ld, tableType: %d, fid: %lld", - // __FUNCTION__, __LINE__, proptag, pos, tableType, fid]; + [self logWithFormat: @"METHOD '%s' (%d) -- proptag: 0x%.8x, pos: %ld, tableType: %d, fid: %lld", + __FUNCTION__, __LINE__, proptag, pos, tableType, fid]; - folderURL = [mapping urlFromID: fid]; - if (folderURL) - { - folder = [self lookupObject: folderURL]; - switch (tableType) - { - case MAPISTORE_FOLDER_TABLE: - children = [self _subfolderKeysForFolderURL: folderURL]; - break; - case MAPISTORE_MESSAGE_TABLE: - children = [self _messageKeysForFolderURL: folderURL]; - break; - default: - [self errorWithFormat: @"%s: value of tableType not handled: %d", - __FUNCTION__, tableType]; - children = nil; - break; - } + [self logWithFormat: @"context restriction state is: %@", + MAPIStringForRestrictionState (restrictionState)]; + if (restriction) + [self logWithFormat: @" active qualifier: %@", restriction]; - if ([children count] > pos) - { - childName = [children objectAtIndex: pos]; - childURL = [folderURL stringByAppendingFormat: @"/%@", - [childName stringByEscapingURL]]; - - if (tableType == MAPISTORE_FOLDER_TABLE) - { - [self logWithFormat: @" querying child folder at URL: %@", childURL]; - rc = [self getFolderTableChildproperty: data - atURL: childURL - withTag: proptag - inFolder: folder - withFID: fid]; - } - else - { - // [self logWithFormat: @" querying child message at URL: %@", childURL]; - rc = [self getMessageTableChildproperty: data - atURL: childURL - withTag: proptag - inFolder: folder - withFID: fid]; - } - /* Unhandled: */ - // #define PR_EXPIRY_TIME PROP_TAG(PT_SYSTIME , 0x0015) /* 0x00150040 */ - // #define PR_REPLY_TIME PROP_TAG(PT_SYSTIME , 0x0030) /* 0x00300040 */ - // #define PR_SENSITIVITY PROP_TAG(PT_LONG , 0x0036) /* 0x00360003 */ - // #define PR_MESSAGE_DELIVERY_TIME PROP_TAG(PT_SYSTIME , 0x0e06) /* 0x0e060040 */ - // #define PR_FOLLOWUP_ICON PROP_TAG(PT_LONG , 0x1095) /* 0x10950003 */ - // #define PR_ITEM_TEMPORARY_FLAGS PROP_TAG(PT_LONG , 0x1097) /* 0x10970003 */ - // #define PR_SEARCH_KEY PROP_TAG(PT_BINARY , 0x300b) /* 0x300b0102 */ - // #define PR_CONTENT_COUNT PROP_TAG(PT_LONG , 0x3602) /* 0x36020003 */ - // #define PR_CONTENT_UNREAD PROP_TAG(PT_LONG , 0x3603) /* 0x36030003 */ - // #define PR_FID PROP_TAG(PT_I8 , 0x6748) /* 0x67480014 */ - // unknown 36de0003 http://social.msdn.microsoft.com/Forums/en-US/os_exchangeprotocols/thread/17c68add-1f62-4b68-9d83-f9ec7c1c6c9b - // unknown 819d0003 - // unknown 81f80003 - // unknown 81fa000b - - } - else - rc = MAPISTORE_ERROR; - } + if (restrictionState == MAPIRestrictionStateAlwaysFalse + || restrictionState == MAPIRestrictionStateNeedsEval) /* TODO: tmp hack */ + rc = MAPI_E_NOT_FOUND; else { - [self errorWithFormat: @"No url found for FID: %lld", fid]; - rc = MAPISTORE_ERR_NOT_FOUND; + folderURL = [mapping urlFromID: fid]; + if (folderURL) + { + folder = [self lookupObject: folderURL]; + switch (tableType) + { + case MAPISTORE_FOLDER_TABLE: + children = [self _subfolderKeysForFolderURL: folderURL]; + break; + case MAPISTORE_MESSAGE_TABLE: + children = [self _messageKeysForFolderURL: folderURL]; + break; + default: + [self errorWithFormat: @"%s: value of tableType not handled: %d", + __FUNCTION__, tableType]; + children = nil; + break; + } + + if ([children count] > pos) + { + childName = [children objectAtIndex: pos]; + childURL = [folderURL stringByAppendingFormat: @"/%@", + [childName stringByEscapingURL]]; + + if (tableType == MAPISTORE_FOLDER_TABLE) + { + [self logWithFormat: @" querying child folder at URL: %@", childURL]; + rc = [self getFolderTableChildproperty: data + atURL: childURL + withTag: proptag + inFolder: folder + withFID: fid]; + } + else + { + // [self logWithFormat: @" querying child message at URL: %@", childURL]; + rc = [self getMessageTableChildproperty: data + atURL: childURL + withTag: proptag + inFolder: folder + withFID: fid]; + } + /* Unhandled: */ + // #define PR_EXPIRY_TIME PROP_TAG(PT_SYSTIME , 0x0015) /* 0x00150040 */ + // #define PR_REPLY_TIME PROP_TAG(PT_SYSTIME , 0x0030) /* 0x00300040 */ + // #define PR_SENSITIVITY PROP_TAG(PT_LONG , 0x0036) /* 0x00360003 */ + // #define PR_MESSAGE_DELIVERY_TIME PROP_TAG(PT_SYSTIME , 0x0e06) /* 0x0e060040 */ + // #define PR_FOLLOWUP_ICON PROP_TAG(PT_LONG , 0x1095) /* 0x10950003 */ + // #define PR_ITEM_TEMPORARY_FLAGS PROP_TAG(PT_LONG , 0x1097) /* 0x10970003 */ + // #define PR_SEARCH_KEY PROP_TAG(PT_BINARY , 0x300b) /* 0x300b0102 */ + // #define PR_CONTENT_COUNT PROP_TAG(PT_LONG , 0x3602) /* 0x36020003 */ + // #define PR_CONTENT_UNREAD PROP_TAG(PT_LONG , 0x3603) /* 0x36030003 */ + // #define PR_FID PROP_TAG(PT_I8 , 0x6748) /* 0x67480014 */ + // unknown 36de0003 http://social.msdn.microsoft.com/Forums/en-US/os_exchangeprotocols/thread/17c68add-1f62-4b68-9d83-f9ec7c1c6c9b + // unknown 819d0003 + // unknown 81f80003 + // unknown 81fa000b + + } + else + rc = MAPISTORE_ERROR; + } + else + { + [self errorWithFormat: @"No url found for FID: %lld", fid]; + rc = MAPISTORE_ERR_NOT_FOUND; + } } return rc; @@ -1023,31 +1521,44 @@ _prepareContextClass (struct mapistore_context *newMemCtx, NSMutableDictionary *messageProperties; NSString *messageURL; uint64_t fid; + BOOL viewMessage; + viewMessage = NO; messageProperties = [messages objectForKey: [NSNumber numberWithUnsignedLongLong: mid]]; if (messageProperties) { - messageURL = [mapping urlFromID: mid]; - if (messageURL) - message = [self lookupObject: messageURL]; + if ([[messageProperties + objectForKey: MAPIPropertyNumber (PR_MESSAGE_CLASS_UNICODE)] + isEqualToString: @"IPM.Microsoft.FolderDesign.NamedView"]) + { + [self logWithFormat: @"ignored message with view data:"]; + MAPIStoreDumpMessageProperties (messageProperties); + rc = MAPISTORE_SUCCESS; + } else - { - fid = [[messageProperties objectForKey: @"fid"] - unsignedLongLongValue]; - message = [self _createMessageWithMID: mid inFID: fid]; - } - if (message) - { - [message setMAPIProperties: messageProperties]; - if (isSave) - [message MAPISave]; - else - [message MAPISubmit]; - rc = MAPISTORE_SUCCESS; - } - else - rc = MAPISTORE_ERROR; + { + messageURL = [mapping urlFromID: mid]; + if (messageURL) + message = [self lookupObject: messageURL]; + else + { + fid = [[messageProperties objectForKey: @"fid"] + unsignedLongLongValue]; + message = [self _createMessageWithMID: mid inFID: fid]; + } + if (message) + { + [message setMAPIProperties: messageProperties]; + if (isSave) + [message MAPISave]; + else + [message MAPISubmit]; + rc = MAPISTORE_SUCCESS; + } + else + rc = MAPISTORE_ERROR; + } } else rc = MAPISTORE_ERR_NOT_FOUND; diff --git a/OpenChange/MAPIStoreMailContext.m b/OpenChange/MAPIStoreMailContext.m index 01bbeed04..80dfcac9b 100644 --- a/OpenChange/MAPIStoreMailContext.m +++ b/OpenChange/MAPIStoreMailContext.m @@ -21,6 +21,7 @@ */ #import +#import #import @@ -117,7 +118,7 @@ withFID: (uint64_t) fid { id child; - NSCalendarDate *offsetDate; + // NSCalendarDate *offsetDate; enum MAPISTATUS rc; rc = MAPI_E_SUCCESS; @@ -145,10 +146,10 @@ 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]; + // 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; @@ -534,4 +535,62 @@ return rc; } +- (NSString *) backendIdentifierForProperty: (enum MAPITAGS) property +{ + static NSMutableDictionary *knownProperties = nil; + + if (!knownProperties) + { + knownProperties = [NSMutableDictionary new]; + [knownProperties setObject: @"DATE" + forKey: MAPIPropertyNumber (PR_MESSAGE_DELIVERY_TIME)]; + } + + return [knownProperties objectForKey: MAPIPropertyNumber (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; + default: + rc = [super evaluatePropertyRestriction: 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; + default: + rc = [super evaluateExistRestriction: res intoQualifier: qualifier]; + } + + return rc; +} + @end diff --git a/OpenChange/MAPIStoreSOGo.m b/OpenChange/MAPIStoreSOGo.m index 6cf6f0fa8..c5481f2ae 100644 --- a/OpenChange/MAPIStoreSOGo.m +++ b/OpenChange/MAPIStoreSOGo.m @@ -44,8 +44,9 @@ \details Initialize sogo mapistore backend \return MAPISTORE_SUCCESS on success - */ -static int sogo_init (void) +*/ +static int +sogo_init (void) { NSAutoreleasePool *pool; SOGoProductLoader *loader; @@ -90,7 +91,8 @@ static int sogo_init (void) \param private_data pointer to the private backend context */ -static int sogo_create_context(TALLOC_CTX *mem_ctx, const char *uri, void **private_data) +static int +sogo_create_context(TALLOC_CTX *mem_ctx, const char *uri, void **private_data) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -106,7 +108,7 @@ static int sogo_create_context(TALLOC_CTX *mem_ctx, const char *uri, void **priv if (MAPIStoreContextK) { context = [MAPIStoreContextK contextFromURI: uri - inMemCtx: mem_ctx]; + inMemCtx: mem_ctx]; [context retain]; cContext = talloc_zero(mem_ctx, sogo_context); @@ -132,7 +134,8 @@ static int sogo_create_context(TALLOC_CTX *mem_ctx, const char *uri, void **priv \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR */ -static int sogo_delete_context(void *private_data) +static int +sogo_delete_context(void *private_data) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -158,7 +161,8 @@ static int sogo_delete_context(void *private_data) \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR */ -static int sogo_release_record(void *private_data, uint64_t fmid, uint8_t type) +static int +sogo_release_record(void *private_data, uint64_t fmid, uint8_t type) { NSAutoreleasePool *pool; @@ -190,8 +194,9 @@ static int sogo_release_record(void *private_data, uint64_t fmid, uint8_t type) \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error */ -static int sogo_get_path(void *private_data, uint64_t fmid, - uint8_t type, char **path) +static int +sogo_get_path(void *private_data, uint64_t fmid, + uint8_t type, char **path) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -215,7 +220,8 @@ static int sogo_get_path(void *private_data, uint64_t fmid, return rc; } -static int sogo_op_get_fid_by_name(void *private_data, uint64_t parent_fid, const char* foldername, uint64_t *fid) +static int +sogo_op_get_fid_by_name(void *private_data, uint64_t parent_fid, const char* foldername, uint64_t *fid) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -246,8 +252,9 @@ static int sogo_op_get_fid_by_name(void *private_data, uint64_t parent_fid, cons \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR */ -static int sogo_op_mkdir(void *private_data, uint64_t parent_fid, uint64_t fid, - struct SRow *aRow) +static int +sogo_op_mkdir(void *private_data, uint64_t parent_fid, uint64_t fid, + struct SRow *aRow) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -280,7 +287,8 @@ static int sogo_op_mkdir(void *private_data, uint64_t parent_fid, uint64_t fid, \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR */ -static int sogo_op_rmdir(void *private_data, uint64_t parent_fid, uint64_t fid) +static int +sogo_op_rmdir(void *private_data, uint64_t parent_fid, uint64_t fid) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -313,7 +321,8 @@ static int sogo_op_rmdir(void *private_data, uint64_t parent_fid, uint64_t fid) \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR */ -static int sogo_op_opendir(void *private_data, uint64_t parent_fid, uint64_t fid) +static int +sogo_op_opendir(void *private_data, uint64_t parent_fid, uint64_t fid) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -344,7 +353,8 @@ static int sogo_op_opendir(void *private_data, uint64_t parent_fid, uint64_t fid \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR */ -static int sogo_op_closedir(void *private_data) +static int +sogo_op_closedir(void *private_data) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -375,10 +385,11 @@ static int sogo_op_closedir(void *private_data) \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR */ -static int sogo_op_readdir_count(void *private_data, - uint64_t fid, - uint8_t table_type, - uint32_t *RowCount) +static int +sogo_op_readdir_count(void *private_data, + uint64_t fid, + uint8_t table_type, + uint32_t *RowCount) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -402,12 +413,13 @@ static int sogo_op_readdir_count(void *private_data, } -static int sogo_op_get_table_property(void *private_data, - uint64_t fid, - uint8_t table_type, - uint32_t pos, - uint32_t proptag, - void **data) +static int +sogo_op_get_table_property(void *private_data, + uint64_t fid, + uint8_t table_type, + uint32_t pos, + uint32_t proptag, + void **data) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -423,7 +435,7 @@ static int sogo_op_get_table_property(void *private_data, [context setupRequest]; rc = [context getTableProperty: data withTag: proptag atPosition: pos - withTableType: table_type inFID: fid]; + withTableType: table_type inFID: fid]; [context tearDownRequest]; [pool release]; @@ -431,10 +443,11 @@ static int sogo_op_get_table_property(void *private_data, return rc; } -static int sogo_op_openmessage(void *private_data, - uint64_t fid, - uint64_t mid, - struct mapistore_message *msg) +static int +sogo_op_openmessage(void *private_data, + uint64_t fid, + uint64_t mid, + struct mapistore_message *msg) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -458,9 +471,10 @@ static int sogo_op_openmessage(void *private_data, } -static int sogo_op_createmessage(void *private_data, - uint64_t fid, - uint64_t mid) +static int +sogo_op_createmessage(void *private_data, + uint64_t fid, + uint64_t mid) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -483,9 +497,10 @@ static int sogo_op_createmessage(void *private_data, return rc; } -static int sogo_op_savechangesmessage(void *private_data, - uint64_t mid, - uint8_t flags) +static int +sogo_op_savechangesmessage(void *private_data, + uint64_t mid, + uint8_t flags) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -508,9 +523,10 @@ static int sogo_op_savechangesmessage(void *private_data, return rc; } -static int sogo_op_submitmessage(void *private_data, - uint64_t mid, - uint8_t flags) +static int +sogo_op_submitmessage(void *private_data, + uint64_t mid, + uint8_t flags) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -533,11 +549,12 @@ static int sogo_op_submitmessage(void *private_data, return rc; } -static int sogo_op_getprops(void *private_data, - uint64_t fmid, - uint8_t type, - struct SPropTagArray *SPropTagArray, - struct SRow *aRow) +static int +sogo_op_getprops(void *private_data, + uint64_t fmid, + uint8_t type, + struct SPropTagArray *SPropTagArray, + struct SRow *aRow) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -563,10 +580,11 @@ static int sogo_op_getprops(void *private_data, } -static int sogo_op_setprops(void *private_data, - uint64_t fmid, - uint8_t type, - struct SRow *aRow) +static int +sogo_op_setprops(void *private_data, + uint64_t fmid, + uint8_t type, + struct SRow *aRow) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -589,9 +607,10 @@ static int sogo_op_setprops(void *private_data, return rc; } -static int sogo_op_set_property_from_fd(void *private_data, - uint64_t fmid, uint8_t type, - uint32_t property, int fd) +static int +sogo_op_set_property_from_fd(void *private_data, + uint64_t fmid, uint8_t type, + uint32_t property, int fd) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -619,9 +638,10 @@ static int sogo_op_set_property_from_fd(void *private_data, return rc; } -static int sogo_op_get_property_into_fd(void *private_data, - uint64_t fmid, uint8_t type, - uint32_t property, int fd) +static int +sogo_op_get_property_into_fd(void *private_data, + uint64_t fmid, uint8_t type, + uint32_t property, int fd) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -649,10 +669,11 @@ static int sogo_op_get_property_into_fd(void *private_data, return rc; } -static int sogo_op_modifyrecipients(void *private_data, - uint64_t mid, - struct ModifyRecipientRow *rows, - uint16_t count) +static int +sogo_op_modifyrecipients(void *private_data, + uint64_t mid, + struct ModifyRecipientRow *rows, + uint16_t count) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -677,9 +698,10 @@ static int sogo_op_modifyrecipients(void *private_data, return rc; } -static int sogo_op_deletemessage(void *private_data, - uint64_t mid, - uint8_t flags) +static int +sogo_op_deletemessage(void *private_data, + uint64_t mid, + uint8_t flags) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -702,9 +724,10 @@ static int sogo_op_deletemessage(void *private_data, return rc; } -static int sogo_op_get_folders_list(void *private_data, - uint64_t fmid, - struct indexing_folders_list **folders_list) +static int +sogo_op_get_folders_list(void *private_data, + uint64_t fmid, + struct indexing_folders_list **folders_list) { NSAutoreleasePool *pool; sogo_context *cContext; @@ -727,6 +750,41 @@ static int sogo_op_get_folders_list(void *private_data, return rc; } +static int +sogo_op_set_restrictions (void *private_data, uint64_t fmid, uint8_t type, + struct mapi_SRestriction *res, uint8_t *tableStatus) +{ + NSAutoreleasePool *pool; + sogo_context *cContext; + MAPIStoreContext *context; + int rc; + + DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + + pool = [NSAutoreleasePool new]; + + cContext = private_data; + context = cContext->objcContext; + if (context) + { + [context setupRequest]; + + rc = [context setRestrictions: res + withFMID: fmid andTableType: type + getTableStatus: tableStatus]; + + [context tearDownRequest]; + [pool release]; + } + else + { + NSLog (@" UNEXPECTED WEIRDNESS: RECEIVED NO CONTEXT"); + rc = MAPI_E_NOT_FOUND; + } + + return rc; +} + /** \details Entry point for mapistore SOGO backend @@ -751,12 +809,13 @@ int mapistore_init_backend(void) backend.description = "mapistore SOGo backend"; backend.namespace = "sogo://"; - /* Fill in all the operations */ backend.init = sogo_init; backend.create_context = sogo_create_context; backend.delete_context = sogo_delete_context; backend.release_record = sogo_release_record; + backend.get_path = sogo_get_path; + backend.op_get_fid_by_name = sogo_op_get_fid_by_name; backend.op_mkdir = sogo_op_mkdir; backend.op_rmdir = sogo_op_rmdir; @@ -764,18 +823,19 @@ int mapistore_init_backend(void) backend.op_closedir = sogo_op_closedir; backend.op_readdir_count = sogo_op_readdir_count; backend.op_get_table_property = sogo_op_get_table_property; + backend.op_get_folders_list = sogo_op_get_folders_list; + backend.op_set_restrictions = sogo_op_set_restrictions; backend.op_openmessage = sogo_op_openmessage; backend.op_createmessage = sogo_op_createmessage; + backend.op_modifyrecipients = sogo_op_modifyrecipients; backend.op_savechangesmessage = sogo_op_savechangesmessage; backend.op_submitmessage = sogo_op_submitmessage; - backend.op_getprops = sogo_op_getprops; - backend.op_get_fid_by_name = sogo_op_get_fid_by_name; + backend.op_deletemessage = sogo_op_deletemessage; + backend.op_setprops = sogo_op_setprops; + backend.op_getprops = sogo_op_getprops; backend.op_set_property_from_fd = sogo_op_set_property_from_fd; backend.op_get_property_into_fd = sogo_op_get_property_into_fd; - backend.op_modifyrecipients = sogo_op_modifyrecipients; - backend.op_deletemessage = sogo_op_deletemessage; - backend.op_get_folders_list = sogo_op_get_folders_list; /* Register ourselves with the MAPISTORE subsystem */ ret = mapistore_backend_register(&backend); diff --git a/OpenChange/MAPIStoreTasksContext.m b/OpenChange/MAPIStoreTasksContext.m index 4691cd5b4..c94432f06 100644 --- a/OpenChange/MAPIStoreTasksContext.m +++ b/OpenChange/MAPIStoreTasksContext.m @@ -20,6 +20,8 @@ * Boston, MA 02111-1307, USA. */ +#import + #import #import @@ -176,4 +178,42 @@ return newEntry; } +- (NSString *) backendIdentifierForProperty: (enum MAPITAGS) property +{ + static NSMutableDictionary *knownProperties = nil; + + if (!knownProperties) + { + knownProperties = [NSMutableDictionary new]; + } + + return [knownProperties objectForKey: MAPIPropertyNumber (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 isKindOfClass: [NSString class]] + && [value isEqualToString: @"IPM.Task"]) + rc = MAPIRestrictionStateAlwaysTrue; + else + rc = MAPIRestrictionStateAlwaysFalse; + break; + + default: + rc = [super evaluatePropertyRestriction: res intoQualifier: qualifier]; + } + + return rc; +} + @end