/// <summary> /// Deserialized byte array to an ActionData instance /// </summary> /// <param name="buffer">Byte array contain data of an ActionData instance.</param> /// <returns>Bytes count that deserialized in buffer.</returns> public uint Deserialize(byte[] buffer) { BufferReader bufferReader = new BufferReader(buffer); this.NamedPropertyInformation = new NamedPropertyInfo(); uint namedPropertyInfoLength = this.NamedPropertyInformation.Deserialize(buffer); bufferReader = new BufferReader(bufferReader.ReadBytes(namedPropertyInfoLength, (uint)(buffer.Length - namedPropertyInfoLength))); this.RuleVersion = bufferReader.ReadUInt32(); this.RuleActionBuffer = new RuleAction(CountByte.FourBytesCount); uint actionLength = this.RuleActionBuffer.Deserialize(bufferReader.ReadToEnd()); uint length = namedPropertyInfoLength + sizeof(uint) + actionLength; return(length); }
public void MSOXORULE_S01_TC08_AddReplyAndOOF_ReplyRules() { this.CheckMAPIHTTPTransportSupported(); #region TestUser1 prepares value for rule properties variable. RuleProperties ruleProperties = AdapterHelper.GenerateRuleProperties(this.Site, Constants.RuleNameOOFReply); #endregion #region Create a Reply template. RopCreateMessageResponse ropCreateMessageResponse; uint replyTemplateMessageHandler = this.OxoruleAdapter.RopCreateMessage(this.InboxFolderHandle, this.InboxFolderID, Convert.ToByte(true), out ropCreateMessageResponse); Site.Assert.AreEqual<uint>(0, ropCreateMessageResponse.ReturnValue, "Creating FAI message should succeed."); TaggedPropertyValue[] replyTemplateProperties = new TaggedPropertyValue[3]; // PidTagMessageClass replyTemplateProperties[0] = new TaggedPropertyValue(); PropertyTag pidTagMessageClassPropertyTag1 = new PropertyTag { PropertyId = (ushort)PropertyId.PidTagMessageClass, PropertyType = (ushort)PropertyType.PtypString }; replyTemplateProperties[0].PropertyTag = pidTagMessageClassPropertyTag1; replyTemplateProperties[0].Value = Encoding.Unicode.GetBytes(Constants.ReplyTemplate + "\0"); // PidTagReplyTemplateId replyTemplateProperties[1] = new TaggedPropertyValue(); PropertyTag pidTagReplyTemplateIdPropertyTag1 = new PropertyTag { PropertyId = (ushort)PropertyId.PidTagReplyTemplateId, PropertyType = (ushort)PropertyType.PtypBinary }; replyTemplateProperties[1].PropertyTag = pidTagReplyTemplateIdPropertyTag1; Guid newReplyTemplateGuid = System.Guid.NewGuid(); replyTemplateProperties[1].Value = Common.AddInt16LengthBeforeBinaryArray(newReplyTemplateGuid.ToByteArray()); // PidTagSubject replyTemplateProperties[2] = new TaggedPropertyValue(); PropertyTag pidTagSubjectPropertyTag1 = new PropertyTag { PropertyId = (ushort)PropertyId.PidTagSubject, PropertyType = (ushort)PropertyType.PtypString }; replyTemplateProperties[2].PropertyTag = pidTagSubjectPropertyTag1; replyTemplateProperties[2].Value = Encoding.Unicode.GetBytes(Common.GenerateResourceName(this.Site, Constants.ReplyTemplateSubject) + "\0"); RopSetPropertiesResponse ropSetPropertiesResponse = this.OxoruleAdapter.RopSetProperties(replyTemplateMessageHandler, replyTemplateProperties); Site.Assert.AreEqual<uint>(0, ropSetPropertiesResponse.ReturnValue, "Setting property for Extended rule FAI message should succeed."); // Save changes of message. RopSaveChangesMessageResponse ropSaveChangesMessagResponseReply = this.OxoruleAdapter.RopSaveChangesMessage(replyTemplateMessageHandler); Site.Assert.AreEqual(0, (int)ropSaveChangesMessagResponseReply.ReturnValue, "Saving Extend rule message should succeed."); // Get the newly created message's folder ID. PropertyTag fidTagReplyTemplate = new PropertyTag { PropertyId = (ushort)PropertyId.PidTagFolderId, PropertyType = (ushort)PropertyType.PtypInteger64 }; RopGetPropertiesSpecificResponse ropGetPropertiesSpecificResponseReply = this.OxoruleAdapter.RopGetPropertiesSpecific(replyTemplateMessageHandler, new PropertyTag[1] { fidTagReplyTemplate }); Site.Assert.AreEqual<uint>(0, ropGetPropertiesSpecificResponseReply.ReturnValue, "Getting folder id operation should succeed."); // Get the reply template's guid. PropertyTag fidTagOOFReply = new PropertyTag { PropertyId = (ushort)PropertyId.PidTagReplyTemplateId, PropertyType = (ushort)PropertyType.PtypBinary }; RopGetPropertiesSpecificResponse ropGetGuid = this.OxoruleAdapter.RopGetPropertiesSpecific(replyTemplateMessageHandler, new PropertyTag[1] { fidTagOOFReply }); Site.Assert.AreEqual<uint>(0, ropGetGuid.ReturnValue, "Getting guid property operation should succeed."); #endregion #region TestUser1 adds rule OOF_REPLY. ReplyActionData oofReplyActionData = new ReplyActionData { ReplyTemplateGUID = new byte[ropGetGuid.RowData.PropertyValues[0].Value.Length - 2] }; Array.Copy(ropGetGuid.RowData.PropertyValues[0].Value, 2, oofReplyActionData.ReplyTemplateGUID, 0, ropGetGuid.RowData.PropertyValues[0].Value.Length - 2); oofReplyActionData.ReplyTemplateFID = BitConverter.ToUInt64(ropGetPropertiesSpecificResponseReply.RowData.PropertyValues[0].Value, 0); oofReplyActionData.ReplyTemplateMID = ropSaveChangesMessagResponseReply.MessageId; RuleData ruleForOOFReply = AdapterHelper.GenerateValidRuleData(ActionType.OP_OOF_REPLY, TestRuleDataType.ForAdd, 100, RuleState.ST_ONLY_WHEN_OOF, oofReplyActionData, ruleProperties, null); RopModifyRulesResponse modifyRulesResponse = this.OxoruleAdapter.RopModifyRules(this.InboxFolderHandle, ModifyRuleFlag.Modify_ReplaceAll, new RuleData[] { ruleForOOFReply }); Site.Assert.AreEqual<uint>(0, modifyRulesResponse.ReturnValue, "Adding OOF_REPLY rule should succeed."); #endregion #region TestUser1 adds rule REPLY. ruleProperties.Name = Common.GenerateResourceName(this.Site, Constants.RuleNameReply); ReplyActionData replyActionData = new ReplyActionData { ReplyTemplateGUID = new byte[ropGetGuid.RowData.PropertyValues[0].Value.Length - 2] }; Array.Copy(ropGetGuid.RowData.PropertyValues[0].Value, 2, replyActionData.ReplyTemplateGUID, 0, ropGetGuid.RowData.PropertyValues[0].Value.Length - 2); replyActionData.ReplyTemplateFID = BitConverter.ToUInt64(ropGetPropertiesSpecificResponseReply.RowData.PropertyValues[0].Value, 0); replyActionData.ReplyTemplateMID = ropSaveChangesMessagResponseReply.MessageId; RuleData ruleForReply = AdapterHelper.GenerateValidRuleData(ActionType.OP_REPLY, TestRuleDataType.ForAdd, 0, RuleState.ST_ENABLED, replyActionData, ruleProperties, null); modifyRulesResponse = this.OxoruleAdapter.RopModifyRules(this.InboxFolderHandle, ModifyRuleFlag.Modify_OnExisting, new RuleData[] { ruleForReply }); Site.Assert.AreEqual<uint>(0, modifyRulesResponse.ReturnValue, "Adding Reply rule should succeed."); #endregion #region TestUser1 gets ruleActions of the two rules. RopGetRulesTableResponse ropGetRulesTableResponse; uint ruleTableHandle = this.OxoruleAdapter.RopGetRulesTable(this.InboxFolderHandle, TableFlags.Normal, out ropGetRulesTableResponse); Site.Assert.AreEqual<uint>(0, ropGetRulesTableResponse.ReturnValue, "Getting rule table should succeed."); PropertyTag[] propertyTags = new PropertyTag[2]; // PidTagRuleName propertyTags[0].PropertyId = (ushort)PropertyId.PidTagRuleName; propertyTags[0].PropertyType = (ushort)PropertyType.PtypString; // PidTagRuleActions propertyTags[1].PropertyId = (ushort)PropertyId.PidTagRuleActions; propertyTags[1].PropertyType = (ushort)PropertyType.PtypRuleAction; // Set the query target to standardardRules. this.OxoruleAdapter.TargetOfRop = TargetOfRop.ForStandardRules; RopQueryRowsResponse getAllActionsResponse = this.OxoruleAdapter.QueryPropertiesInTable(ruleTableHandle, propertyTags); Site.Assert.AreEqual<uint>(0, getAllActionsResponse.ReturnValue, "Getting the rule actions should succeed."); // Two rules have been added to the Inbox folder, so the row count in the rule table should be 2. Site.Assert.AreEqual<uint>(2, getAllActionsResponse.RowCount, "The rule number in the rule table is {0}", getAllActionsResponse.RowCount); this.VerifyRuleTable(); RuleAction ruleActionForReply = new RuleAction(); ReplyActionData actionDataForReply = new ReplyActionData(); RuleAction ruleActionForOOFReply = new RuleAction(); ReplyActionData actionDataForOOFReply = new ReplyActionData(); bool hasActionDataForReply = false; bool hasActionDataForOOFReply = false; for (int i = 0; i < getAllActionsResponse.RowCount; i++) { System.Text.UnicodeEncoding converter = new UnicodeEncoding(); string ruleName = converter.GetString(getAllActionsResponse.RowData.PropertyRows[i].PropertyValues[0].Value); if (ruleName.Contains(Constants.RuleNameReply) && !hasActionDataForReply) { ruleActionForReply.Deserialize(getAllActionsResponse.RowData.PropertyRows[i].PropertyValues[1].Value); actionDataForReply.Deserialize(ruleActionForReply.Actions[0].ActionDataValue.Serialize()); hasActionDataForReply = true; } if (ruleName.Contains(Constants.RuleNameOOFReply) && !hasActionDataForOOFReply) { ruleActionForOOFReply.Deserialize(getAllActionsResponse.RowData.PropertyRows[i].PropertyValues[1].Value); actionDataForOOFReply.Deserialize(ruleActionForOOFReply.Actions[0].ActionDataValue.Serialize()); hasActionDataForOOFReply = true; } if (hasActionDataForReply && hasActionDataForOOFReply) { break; } } // Add a variable to verify R727 and R928. bool isPidTagReplyTemplateIdEqualtemplateGUIDForOOFReply = false; if (Common.CompareByteArray(newReplyTemplateGuid.ToByteArray(), actionDataForOOFReply.ReplyTemplateGUID)) { isPidTagReplyTemplateIdEqualtemplateGUIDForOOFReply = true; } // Add a variable to verify R309 bool isPidTagReplyTemplateIdEqualtemplateGUIDForReply = false; if (Common.CompareByteArray(newReplyTemplateGuid.ToByteArray(), actionDataForReply.ReplyTemplateGUID)) { isPidTagReplyTemplateIdEqualtemplateGUIDForReply = true; } #region Capture Code // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R727: the actual value of PidTagReplyTemplateId property is {0}", BitConverter.ToString(actionDataForOOFReply.ReplyTemplateGUID)); // Verify MS-OXORULE requirement: MS-OXORULE_R727. // ReplyTemplateGUID of the actionDataForOOFReply is the value of PidTagReplyTemplateId property, and newGuidOOFReplyGUID is the GUID of the reply template. bool isVerifyR727 = isPidTagReplyTemplateIdEqualtemplateGUIDForOOFReply; Site.CaptureRequirementIfIsTrue( isVerifyR727, 727, @"[In PidTagReplyTemplateId Property] The PidTagReplyTemplateId property ([MS-OXPROPS] section 2.909) specifies the GUID for the reply template."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R928: the actual value of PidTagReplyTemplateId property is {0}", BitConverter.ToString(actionDataForOOFReply.ReplyTemplateGUID)); // Verify MS-OXORULE requirement: MS-OXORULE_R928. // ReplyTemplateGUID of the actionDataForOOFReply is the value of PidTagReplyTemplateId property, and newGuidOOFReplyGUID is the GUID of the reply template. bool isVerifyR928 = isPidTagReplyTemplateIdEqualtemplateGUIDForOOFReply; Site.CaptureRequirementIfIsTrue( isVerifyR928, 928, @"[OP_REPLY and OP_OOF_REPLY ActionData Structure] [Buffer Format for Standard Rules] The value of the ReplyTemplateGUID field in OP_OOF_REPLY action data is equal to the value of the PidTagReplyTemplateId property (section 2.2.9.2) that is set on the reply template."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R309: the actual value of PidTagReplyTemplateId property is {0}", BitConverter.ToString(actionDataForReply.ReplyTemplateGUID)); // Verify MS-OXORULE requirement: MS-OXORULE_R309. // ReplyTemplateGUID of the actionDataForReply is the value of PidTagReplyTemplateId property, and newGuidOOFReplyGUID is the GUID of the reply template. bool isVerifyR309 = isPidTagReplyTemplateIdEqualtemplateGUIDForReply; Site.CaptureRequirementIfIsTrue( isVerifyR309, 309, @"[OP_REPLY and OP_OOF_REPLY ActionData Structure] [Buffer Format for Standard Rules] The value of the ReplyTemplateGUID field in OP_REPLY action data is equal to the value of the PidTagReplyTemplateId property (section 2.2.9.2) that is set on the reply template."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R305, the folder ID which contains the reply template is {0}, and actually the value is {1} in the actionDataForReply, and the value is {2} in actionDataForOOFReply", replyActionData.ReplyTemplateFID, actionDataForReply.ReplyTemplateFID, actionDataForOOFReply.ReplyTemplateFID); bool isVerifiedR305 = replyActionData.ReplyTemplateFID == actionDataForReply.ReplyTemplateFID && replyActionData.ReplyTemplateFID == actionDataForOOFReply.ReplyTemplateFID; // Verify MS-OXORULE requirement: MS-OXORULE_R305. // ReplyTemplateFID in the replyActionData is set to the folder ID that contains the reply template, so if the value in the rule actionData is the same as it, R305 can be verified. Site.CaptureRequirementIfIsTrue( isVerifiedR305, 305, @"[OP_REPLY and OP_OOF_REPLY ActionData Structure] [Buffer Format for Standard Rules] ReplyTemplateFID (8 bytes): A Folder ID structure, as specified in [MS-OXCDATA] section 2.2.1.1, that identifies the folder that contains the reply template."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R307, the Message ID which is used as the reply template is {0}, and actually the value is {1} in the actionDataForReply, and the value is {2} in the actionDataForOOFReply", replyActionData.ReplyTemplateMID, actionDataForReply.ReplyTemplateMID, actionDataForOOFReply.ReplyTemplateMID); bool isVerifiedR307 = replyActionData.ReplyTemplateMID == actionDataForReply.ReplyTemplateMID && replyActionData.ReplyTemplateMID == actionDataForOOFReply.ReplyTemplateMID; // Verify MS-OXORULE requirement: MS-OXORULE_R307. // ReplyTemplateMID in the replyActionData is set to the message ID which is used as the reply template, so if the value in the rule actionData is the same as it, R307 can be verified. Site.CaptureRequirementIfIsTrue( isVerifiedR307, 307, @"[OP_REPLY and OP_OOF_REPLY ActionData Structure] [Buffer Format for Standard Rules] ReplyTemplateMID (8 bytes): A Message ID structure, as specified in [MS-OXCDATA] section 2.2.1.2, that identifies the FAI message being used as the reply template."); #endregion // Clear the status of the adapter. this.OxoruleAdapter.TargetOfRop = TargetOfRop.OtherTarget; #endregion }
public void MSOXORULE_S02_TC13_ServerExecuteRule_Action_OP_MOVE_FolderInThisStore() { this.CheckMAPIHTTPTransportSupported(); #region Prepare value for ruleProperties variable. RuleProperties ruleProperties = AdapterHelper.GenerateRuleProperties(this.Site, Constants.RuleNameMoveOne); #endregion #region TestUser1 creates folder1 in server store. RopCreateFolderResponse createFolderResponse; uint newFolderHandle = this.OxoruleAdapter.RopCreateFolder(this.InboxFolderHandle, Common.GenerateResourceName(this.Site, "User1Folder01"), "TestForOP_MOVE", out createFolderResponse); ulong newFolderId = createFolderResponse.FolderId; Site.Assert.AreEqual<uint>(0, createFolderResponse.ReturnValue, "Creating folder operation should succeed."); #endregion #region Prepare rules' data MoveCopyActionData moveCopyActionData = new MoveCopyActionData(); // Get the created folder1 entry id. ServerEID serverEID = new ServerEID(BitConverter.GetBytes(newFolderId)); byte[] folder1EId = serverEID.Serialize(); // Get the store object's entry id byte[] storeEId = this.GetStoreObjectEntryID(StoreObjectType.Mailbox, this.Server, this.User1ESSDN); moveCopyActionData.FolderInThisStore = 1; moveCopyActionData.FolderEID = folder1EId; moveCopyActionData.StoreEID = storeEId; moveCopyActionData.FolderEIDSize = (ushort)folder1EId.Length; moveCopyActionData.StoreEIDSize = (ushort)storeEId.Length; IActionData[] moveCopyAction = { moveCopyActionData }; #endregion #region Generate test RuleData. // Add rule for move without rule Provider Data. ruleProperties.ProviderData = string.Empty; RuleData ruleForMoveFolder = AdapterHelper.GenerateValidRuleDataWithFlavor(new ActionType[] { ActionType.OP_MOVE }, 0, RuleState.ST_ENABLED, moveCopyAction, new uint[] { 0 }, ruleProperties); #endregion #region TestUser1 adds OP_MOVE rule to the Inbox folder. RopModifyRulesResponse modifyRulesResponse = this.OxoruleAdapter.RopModifyRules(this.InboxFolderHandle, ModifyRuleFlag.Modify_ReplaceAll, new RuleData[] { ruleForMoveFolder }); Site.Assert.AreEqual<uint>(0, modifyRulesResponse.ReturnValue, "Adding Move rule should succeed."); #endregion #region TestUser2 delivers a message to TestUser1 to trigger the rule. // TestUser2 deliver a message to trigger the rule. string mailSubject = Common.GenerateResourceName(this.Site, ruleProperties.ConditionSubjectName + "Title"); this.SUTAdapter.SendMailToRecipient(this.User2Name, this.User2Password, this.User1Name, mailSubject); // Wait for the mail to be received and the rule to take effect. Thread.Sleep(this.WaitForTheRuleToTakeEffect); #endregion #region TestUser1 gets the message content to verify the rule evaluation. uint inboxFolderContentsTableHandle = 0; PropertyTag[] propertyTagList = new PropertyTag[1]; propertyTagList[0].PropertyId = (ushort)PropertyId.PidTagSubject; propertyTagList[0].PropertyType = (ushort)PropertyType.PtypString; bool doesOriginalMessageExist = this.CheckUnexpectedMessageExist(this.InboxFolderHandle, ref inboxFolderContentsTableHandle, propertyTagList, mailSubject); uint newFolder1ContentsTableHandle = 0; uint rowCount = 0; RopQueryRowsResponse getNewFolder1MailMessageContent = this.GetExpectedMessage(newFolderHandle, ref newFolder1ContentsTableHandle, propertyTagList, ref rowCount, 1, mailSubject); Site.Assert.IsFalse(doesOriginalMessageExist, "The original message shouldn't exist anymore."); Site.Assert.AreEqual<uint>(0, getNewFolder1MailMessageContent.ReturnValue, "getNewFolder1MailMessageContent should succeed."); // Add the debug information this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R956"); // Verify MS-OXORULE requirement: MS-OXORULE_R956 // Since the destination folder is created in the user's mailbox, if the Email can be found in the destination folder, MS-OXORULE_R956 can be verified. this.Site.CaptureRequirementIfAreNotEqual<uint>( 0, getNewFolder1MailMessageContent.RowCount, 956, @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Standard Rules] The destination folder for a Move action in a standard rule can be in the user's mailbox."); #endregion if (Common.IsRequirementEnabled(294, this.Site)) { #region TestUser1 gets a rule table. RopGetRulesTableResponse ropGetRulesTableResponse; uint ruleTableHandle = this.OxoruleAdapter.RopGetRulesTable(this.InboxFolderHandle, TableFlags.Normal, out ropGetRulesTableResponse); Site.Assert.AreEqual<uint>(0, ropGetRulesTableResponse.ReturnValue, "Getting rule table should succeed."); #endregion #region TestUser1 retrieves rule information to check if the rule exists. PropertyTag[] propertyTags = new PropertyTag[2]; propertyTags[0].PropertyId = (ushort)PropertyId.PidTagRuleName; propertyTags[0].PropertyType = (ushort)PropertyType.PtypString; propertyTags[1].PropertyId = (ushort)PropertyId.PidTagRuleActions; propertyTags[1].PropertyType = (ushort)PropertyType.PtypRuleAction; // Retrieves rows from the rule table. RopQueryRowsResponse queryRowResponse = this.OxoruleAdapter.QueryPropertiesInTable(ruleTableHandle, propertyTags); Site.Assert.AreEqual<uint>(0, queryRowResponse.ReturnValue, "Retrieving rows from the rule table should succeed."); MoveCopyActionData moveActionDataOfQueryRowsResponse = new MoveCopyActionData(); RuleAction ruleAction = new RuleAction(); for (int i = 0; i < queryRowResponse.RowCount; i++) { System.Text.UnicodeEncoding converter = new UnicodeEncoding(); string ruleName = converter.GetString(queryRowResponse.RowData.PropertyRows.ToArray()[i].PropertyValues[0].Value); if (ruleName == ruleProperties.Name + "\0") { // Verify structure RuleAction ruleAction.Deserialize(queryRowResponse.RowData.PropertyRows[i].PropertyValues[1].Value); moveActionDataOfQueryRowsResponse.Deserialize(ruleAction.Actions[0].ActionDataValue.Serialize()); break; } } #region Capture Code // Add the debug information this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R736"); ServerEID serverEIDOfResponse = new ServerEID(new byte[] { }); serverEIDOfResponse.Deserialize(moveActionDataOfQueryRowsResponse.FolderEID); bool isVerifiedR736 = moveActionDataOfQueryRowsResponse.FolderInThisStore == 0x01 && serverEIDOfResponse.FolderID != null && serverEIDOfResponse.MessageID != null && serverEIDOfResponse.Instance != null; // Verify MS-OXORULE requirement: MS-OXORULE_R736 this.Site.CaptureRequirementIfIsTrue( isVerifiedR736, 736, @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Standard Rules] If the value of the FolderInThisStore field is 0x01, this field [FolderEID] contains a ServerEid structure, as specified in section 2.2.5.1.2.1.1. "); FolderID folderId = new FolderID(); folderId.Deserialize(BitConverter.ToUInt64(serverEIDOfResponse.FolderID, 0)); // Add the debug information this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R983"); bool isVerifiedR983 = folderId.ReplicaId != null && folderId.GlobalCounter != null; // Verify MS-OXORULE requirement: MS-OXORULE_R983 this.Site.CaptureRequirementIfIsTrue( isVerifiedR983, 983, @"[In ServerEid Structure] FolderId (8 bytes): A Folder ID structure, as specified in [MS-OXCDATA] section 2.2.1.1, identifies the destination folder."); if (Common.IsRequirementEnabled(7032, this.Site)) { // Add the debug information this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R7032"); bool isVerifiedR703 = moveActionDataOfQueryRowsResponse.FolderInThisStore == 0x01 && getNewFolder1MailMessageContent.RowCount != 0; // Verify MS-OXORULE requirement: MS-OXORULE_R7032 this.Site.CaptureRequirementIfIsTrue( isVerifiedR703, 7032, @"[In Appendix A: Product Behavior] Implementation does set this field (FolderInThisStore) to 0x01 if the destination folder is in the user's mailbox. (Exchange 2007 and Exchange 2016 follow this behavior)."); } #endregion #endregion } #region Delete the newly created folder. RopDeleteFolderResponse deleteFolder = this.OxoruleAdapter.RopDeleteFolder(this.InboxFolderHandle, newFolderId); Site.Assert.AreEqual<uint>(0, deleteFolder.ReturnValue, "Deleting folder should succeed."); #endregion }
public void MSOXORULE_S02_TC08_ServerExecuteRule_Action_OP_DELEGATE() { this.CheckMAPIHTTPTransportSupported(); #region Prepare value for ruleProperties variable. RuleProperties ruleProperties = AdapterHelper.GenerateRuleProperties(this.Site, Constants.RuleNameDelegate); #endregion #region TestUser1 adds an OP_DELEGATE rule. ForwardDelegateActionData delegateActionData = new ForwardDelegateActionData { RecipientCount = (ushort)0x01 }; RecipientBlock recipientBlock = new RecipientBlock { Reserved = 0x01, NoOfProperties = (ushort)0x05u }; #region Prepare recipient Block. TaggedPropertyValue[] recipientProperties = new TaggedPropertyValue[5]; TaggedPropertyValue[] temp = AdapterHelper.GenerateRecipientPropertiesBlock(this.User2Name, this.User2ESSDN); Array.Copy(temp, 0, recipientProperties, 0, temp.Length); // Add PidTagSmtpEmailAdderss. recipientProperties[4] = new TaggedPropertyValue(); PropertyTag pidTagSmtpEmailAdderssPropertyTag = new PropertyTag { PropertyId = (ushort)PropertyId.PidTagSmtpAddress, PropertyType = (ushort)PropertyType.PtypString }; recipientProperties[4].PropertyTag = pidTagSmtpEmailAdderssPropertyTag; recipientProperties[4].Value = Encoding.Unicode.GetBytes(this.User2Name + "@" + this.Domain + "\0"); recipientBlock.PropertiesData = recipientProperties; #endregion delegateActionData.RecipientsData = new RecipientBlock[1] { recipientBlock }; RuleData ruleDelegate = AdapterHelper.GenerateValidRuleData(ActionType.OP_DELEGATE, TestRuleDataType.ForAdd, 1, RuleState.ST_ENABLED, delegateActionData, ruleProperties, null); RopModifyRulesResponse ropModifyRulesResponse = this.OxoruleAdapter.RopModifyRules(this.InboxFolderHandle, ModifyRuleFlag.Modify_ReplaceAll, new RuleData[] { ruleDelegate }); Site.Assert.AreEqual<uint>(0, ropModifyRulesResponse.ReturnValue, "Adding delegate rule should succeed."); #endregion #region TestUser1 delivers a message to itself to trigger the rule. Thread.Sleep(this.WaitForTheRuleToTakeEffect); // TestUser1 delivers a message to itself to trigger the rule. string mailSubject = Common.GenerateResourceName(this.Site, ruleProperties.ConditionSubjectName + "Title"); this.SUTAdapter.SendMailToRecipient(this.User1Name, this.User1Password, this.User1Name, mailSubject); Thread.Sleep(this.WaitForTheRuleToTakeEffect); #endregion #region TestUser2 gets the delegate message to verify the rule evaluation. // Let TestUser2 log on to the server. this.LogonMailbox(TestUser.TestUser2); PropertyTag[] propertyTagList = new PropertyTag[7]; propertyTagList[0].PropertyId = (ushort)PropertyId.PidTagSubject; propertyTagList[0].PropertyType = (ushort)PropertyType.PtypString; propertyTagList[1].PropertyId = (ushort)PropertyId.PidTagReceivedRepresentingEntryId; propertyTagList[1].PropertyType = (ushort)PropertyType.PtypBinary; propertyTagList[2].PropertyId = (ushort)PropertyId.PidTagReceivedRepresentingAddressType; propertyTagList[2].PropertyType = (ushort)PropertyType.PtypString; propertyTagList[3].PropertyId = (ushort)PropertyId.PidTagReceivedRepresentingEmailAddress; propertyTagList[3].PropertyType = (ushort)PropertyType.PtypString; propertyTagList[4].PropertyId = (ushort)PropertyId.PidTagReceivedRepresentingName; propertyTagList[4].PropertyType = (ushort)PropertyType.PtypString; propertyTagList[5].PropertyId = (ushort)PropertyId.PidTagReceivedRepresentingSearchKey; propertyTagList[5].PropertyType = (ushort)PropertyType.PtypBinary; propertyTagList[6].PropertyId = (ushort)PropertyId.PidTagDelegatedByRule; propertyTagList[6].PropertyType = (ushort)PropertyType.PtypBoolean; uint contentTableHandler = 0; int expectedMessageIndex = 0; RopQueryRowsResponse getNormalMailMessageContent = this.GetExpectedMessage(this.InboxFolderHandle, ref contentTableHandler, propertyTagList, ref expectedMessageIndex, mailSubject); #endregion #region Get TestUser1's information from address book // Let TestUser1 log on to the server. this.LogonMailbox(TestUser.TestUser1); PropertyTagArray_r ptags = new PropertyTagArray_r { Values = 5, AulPropTag = AdapterHelper.SerializeRecipientProperties() }; // The Windows NSPI will be invoked when the first parameter is domain name instead of server address. PropertyRowSet_r? propertyRows = this.OxoruleAdapter.GetRecipientInfo(this.Domain, this.User1Name, this.Domain, this.User1Password, ptags); Site.Assert.IsNotNull(propertyRows, "The recipient information returned by the NSPI service should not be null"); int user1Index = 0; for (int i = 0; i < propertyRows.Value.Rows; i++) { if (Encoding.Unicode.GetString(propertyRows.Value.PropertyRowSet[i].Props[3].Value.LpszW).ToLower(System.Globalization.CultureInfo.CurrentCulture) == this.User1Name.ToLower(System.Globalization.CultureInfo.CurrentCulture)) { user1Index = i; break; } } // The two EntryId should be the same. AddressBookEntryID addressbookEntryId = new AddressBookEntryID(); addressbookEntryId.Deserialize(propertyRows.Value.PropertyRowSet[user1Index].Props[0].Value.Bin.Lpb); byte[] pidTagReceivedRepresentingEntryIdbytesTemp = getNormalMailMessageContent.RowData.PropertyRows[expectedMessageIndex].PropertyValues[1].Value; byte[] pidTagReceivedRepresentingEntryIdbytes = new byte[pidTagReceivedRepresentingEntryIdbytesTemp.Length - 2]; Array.Copy(pidTagReceivedRepresentingEntryIdbytesTemp, 2, pidTagReceivedRepresentingEntryIdbytes, 0, pidTagReceivedRepresentingEntryIdbytes.Length); AddressBookEntryID mailEntryID = new AddressBookEntryID(); mailEntryID.Deserialize(pidTagReceivedRepresentingEntryIdbytes); string subject = AdapterHelper.PropertyValueConvertToString(getNormalMailMessageContent.RowData.PropertyRows[expectedMessageIndex].PropertyValues[0].Value); #region Capture Code // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R539"); // Verify MS-OXORULE requirement: MS-OXORULE_R539. Site.CaptureRequirementIfAreEqual<string>( mailSubject, subject, 539, @"[In Processing Incoming Messages to a Folder] [Following is a description of what the server does when it executes each action (2) type, as specified in section 2.2.5.1.1, for an incoming message] ""OP_DELEGATE"": the server MUST resend the message to the recipients (2) specified in the action buffer structure."); string pidTagEntryIdOfMailboxUser = addressbookEntryId.ValueOfX500DN.ToLower(System.Globalization.CultureInfo.CurrentCulture); string pidTagReceivedRepresentingEntryId = mailEntryID.ValueOfX500DN.ToLower(System.Globalization.CultureInfo.CurrentCulture); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R540"); // Verify MS-OXORULE requirement: MS-OXORULE_R540. Site.CaptureRequirementIfAreEqual<string>( pidTagReceivedRepresentingEntryId, pidTagEntryIdOfMailboxUser, 540, @"[In Processing Incoming Messages to a Folder] [Following is a description of what the server does when it executes each action (2) type, as specified in section 2.2.5.1.1, for an incoming message] ""OP_DELEGATE"": The server also MUST set the values of the following properties to match the current user's properties in the address book: The PidTagReceivedRepresentingEntryId property ([MS-OXOMSG] section 2.2.1.25) MUST be set to the same value as the mailbox user's PidTagEntryId property ([MS-OXOABK] section 2.2.3.3)."); string pidTagReceivedRepresentingAddressType = Encoding.Unicode.GetString(getNormalMailMessageContent.RowData.PropertyRows[expectedMessageIndex].PropertyValues[2].Value); // The actual value of pidTagReceivedRepresentingAddressType should not contain the last '\0' character. pidTagReceivedRepresentingAddressType = pidTagReceivedRepresentingAddressType.Substring(0, pidTagReceivedRepresentingAddressType.Length - 1); // In this test case, the mailbox user's PidTagAddressType is "EX". string pidTagAddressTypeOfMailboxUser = System.Text.UTF8Encoding.Unicode.GetString(propertyRows.Value.PropertyRowSet[user1Index].Props[1].Value.LpszW); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R541"); // Verify MS-OXORULE requirement: MS-OXORULE_R541. Site.CaptureRequirementIfAreEqual<string>( pidTagReceivedRepresentingAddressType, pidTagAddressTypeOfMailboxUser, 541, @"[In Processing Incoming Messages to a Folder] [Following is a description of what the server does when it executes each action (2) type, as specified in section 2.2.5.1.1, for an incoming message] ""OP_DELEGATE"": The PidTagReceivedRepresentingAddressType property ([MS-OXOMSG] section 2.2.1.23) MUST be set to the same value as the mailbox user's PidTagAddressType property ([MS-OXOABK] section 2.2.3.13)."); string pidTagReceivedRepresentingEmailAddress = Encoding.Unicode.GetString(getNormalMailMessageContent.RowData.PropertyRows[expectedMessageIndex].PropertyValues[3].Value); // The actual value of PidTagReceivedRepresentingEmailAddress should not contain the last '\0' character. pidTagReceivedRepresentingEmailAddress = pidTagReceivedRepresentingEmailAddress.Substring(0, pidTagReceivedRepresentingEmailAddress.Length - 1).ToUpperInvariant(); // In this test case, the mailbox user's PidTagEmailAddress is the adminUserDN. string pidTagEmailAddressOfMailboxUser = Encoding.Unicode.GetString(propertyRows.Value.PropertyRowSet[user1Index].Props[2].Value.LpszW).ToUpperInvariant(); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R542"); // Verify MS-OXORULE requirement: MS-OXORULE_R542. Site.CaptureRequirementIfAreEqual<string>( pidTagReceivedRepresentingEmailAddress, pidTagEmailAddressOfMailboxUser, 542, @"[In Processing Incoming Messages to a Folder] [Following is a description of what the server does when it executes each action (2) type, as specified in section 2.2.5.1.1, for an incoming message] ""OP_DELEGATE"": The PidTagReceivedRepresentingEmailAddress property ([MS-OXOMSG] section 2.2.1.24) MUST be set to the same value as the mailbox user's PidTagEmailAddress property ([MS-OXOABK] section 2.2.3.14)."); string pidTagReceivedRepresentingName = AdapterHelper.PropertyValueConvertToString(getNormalMailMessageContent.RowData.PropertyRows[expectedMessageIndex].PropertyValues[4].Value).ToLower(System.Globalization.CultureInfo.CurrentCulture); // In this test case, the mailbox user's PidTagDisplayName is "administrator". string pidTagDisplayNameOfMailboxUser = Encoding.Unicode.GetString(propertyRows.Value.PropertyRowSet[user1Index].Props[3].Value.LpszW).ToLower(System.Globalization.CultureInfo.CurrentCulture); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R543"); // Verify MS-OXORULE requirement: MS-OXORULE_R543. Site.CaptureRequirementIfAreEqual<string>( pidTagReceivedRepresentingName, pidTagDisplayNameOfMailboxUser, 543, @"[In Processing Incoming Messages to a Folder] [Following is a description of what the server does when it executes each action (2) type, as specified in section 2.2.5.1.1, for an incoming message] ""OP_DELEGATE"": The PidTagReceivedRepresentingName property ([MS-OXOMSG] section 2.2.1.26) MUST be set to the same value as the mailbox user's PidTagDisplayName property ([MS-OXCFOLD] section 2.2.2.2.2.5)."); byte[] pidTagReceivedRepresentingSearchKeyOfbytes = getNormalMailMessageContent.RowData.PropertyRows[expectedMessageIndex].PropertyValues[5].Value; byte[] pidTagReceivedRepresentingSearchKey = AdapterHelper.PropertyValueConvertToBinary(pidTagReceivedRepresentingSearchKeyOfbytes); byte[] pidTagSearchKeyOfMailboxUser = propertyRows.Value.PropertyRowSet[user1Index].Props[4].Value.Bin.Lpb; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R544: the value of PidTagReceivedRepresentingSearchKey is {0}", pidTagSearchKeyOfMailboxUser); // Verify MS-OXORULE requirement: MS-OXORULE_R544. bool isVerifyR544 = Common.CompareByteArray(pidTagSearchKeyOfMailboxUser, pidTagReceivedRepresentingSearchKey); Site.CaptureRequirementIfIsTrue( isVerifyR544, 544, @"[In Processing Incoming Messages to a Folder] [Following is a description of what the server does when it executes each action (2) type, as specified in section 2.2.5.1.1, for an incoming message] ""OP_DELEGATE"": The PidTagReceivedRepresentingSearchKey property ([MS-OXOMSG] section 2.2.1.27) MUST be set to the same value as the mailbox user's PidTagSearchKey property ([MS-OXCPRPT] section 2.2.1.9)."); // BitConverter.ToBoolean() is used to convert a byte array to a bool value from the byte array index of 0. bool pidTagDelegatedByRule = BitConverter.ToBoolean(getNormalMailMessageContent.RowData.PropertyRows[expectedMessageIndex].PropertyValues[6].Value, 0); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R545"); // Verify MS-OXORULE requirement: MS-OXORULE_R545. Site.CaptureRequirementIfIsTrue( pidTagDelegatedByRule, 545, @"[In Processing Incoming Messages to a Folder] [Following is a description of what the server does when it executes each action (2) type, as specified in section 2.2.5.1.1, for an incoming message] ""OP_DELEGATE"": The PidTagDelegatedByRule property ([MS-OXOMSG] section 2.2.1.84) MUST be set to ""TRUE""."); #endregion #endregion #region TestUser1 calls RopGetRulesTable with valid TableFlags. RopGetRulesTableResponse ropGetRulesTableResponse; uint ruleTableHandle = this.OxoruleAdapter.RopGetRulesTable(this.InboxFolderHandle, TableFlags.Normal, out ropGetRulesTableResponse); Site.Assert.AreEqual<uint>(0, ropGetRulesTableResponse.ReturnValue, "Getting rule table should succeed."); #endregion #region TestUser1 calls RopQueryRows to retrieve rows from the rule table PropertyTag[] propertyTags = new PropertyTag[2]; propertyTags[0].PropertyId = (ushort)PropertyId.PidTagRuleName; propertyTags[0].PropertyType = (ushort)PropertyType.PtypString; propertyTags[1].PropertyId = (ushort)PropertyId.PidTagRuleActions; propertyTags[1].PropertyType = (ushort)PropertyType.PtypRuleAction; // Retrieves rows from the rule table. RopQueryRowsResponse queryRowResponse = this.OxoruleAdapter.QueryPropertiesInTable(ruleTableHandle, propertyTags); Site.Assert.AreEqual<uint>(0, queryRowResponse.ReturnValue, "Retrieving rows from the rule table should succeed."); ForwardDelegateActionData forwardDelegateActionDataOfQueryRowResponse = new ForwardDelegateActionData(); RuleAction ruleAction = new RuleAction(); for (int i = 0; i < queryRowResponse.RowCount; i++) { System.Text.UnicodeEncoding converter = new UnicodeEncoding(); string ruleName = converter.GetString(queryRowResponse.RowData.PropertyRows.ToArray()[i].PropertyValues[0].Value); if (ruleName == ruleProperties.Name + "\0") { // Verify structure RuleAction ruleAction.Deserialize(queryRowResponse.RowData.PropertyRows[i].PropertyValues[1].Value); forwardDelegateActionDataOfQueryRowResponse.Deserialize(ruleAction.Actions[0].ActionDataValue.Serialize()); break; } } #region Capture Code // Add the debug information this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R1003"); // Verify MS-OXORULE requirement: MS-OXORULE_R1003 this.Site.CaptureRequirementIfIsInstanceOfType( forwardDelegateActionDataOfQueryRowResponse.RecipientsData, typeof(RecipientBlock[]), 1003, @"[In OP_FORWARD and OP_DELEGATE ActionData Structure] RecipientBlocks (variable): An array of RecipientBlockData structures, each of which specifies information about one recipient (2)."); for (int i = 0; i < forwardDelegateActionDataOfQueryRowResponse.RecipientsData.Length; i++) { // Add the debug information this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R1006"); // Verify MS-OXORULE requirement: MS-OXORULE_R1006 this.Site.CaptureRequirementIfIsInstanceOfType( forwardDelegateActionDataOfQueryRowResponse.RecipientsData[i].PropertiesData, typeof(TaggedPropertyValue[]), 1006, @"[In RecipientBlockData Structure] PropertyValues (variable): An array of TaggedPropertyValue structures, each of which contains a property that provides some information about the recipient (2)."); } #endregion #endregion }
/// <summary> /// This method help to convert the property value, which is of variable bytes, to RuleAction structure. /// </summary> /// <param name="byteArray">The byte array to be converted.</param> /// <returns>Return the RuleAction structure.</returns> public static RuleAction PropertyValueConvertToRuleAction(byte[] byteArray) { // The first 2 bytes of byteArray only indicates the total number of subsequent bytes, // byteArrayTobeConverted is the actual bytes used to convert to the RuleAction structure, // which should not include the first 2 bytes of byteArray. byte[] byteArrayToBeConverted = new byte[byteArray.Length - 2]; Array.Copy(byteArray, 2, byteArrayToBeConverted, 0, byteArray.Length - 2); // Deserialize the byte array to the RuleAction structure. RuleAction ruleAction = new RuleAction(); ruleAction.Deserialize(byteArrayToBeConverted); return ruleAction; }
/// <summary> /// Read a value from buffer for special Type. /// </summary> /// <param name="type">The Type of value.</param> /// <param name="buffer">Buffer contains value.</param> /// <returns>Byte array of the value.</returns> public static byte[] ReadValueByType(ushort type, byte[] buffer) { byte[] value = null; BufferReader bufferReader = new BufferReader(buffer); uint length = 0; byte[] tmpArray = null; uint startIndex = 0; uint endIndex = 0; switch (type) { // 2-byte // PtypInteger16 case 0x0002: value = bufferReader.ReadBytes(2); break; // 4-byte // PtypInteger32 case 0x0003: // PtypFloating32 case 0x0004: // PtypErrorCode case 0x000A: value = bufferReader.ReadBytes(4); break; // 8-byte // PtypFloating64 case 0x0005: // PtypCurrency case 0x0006: // PtypFloatingTime case 0x0007: // PtypInteger64 case 0x0014: // PtypTime case 0x0040: value = bufferReader.ReadBytes(8); break; // 1 byte // PtypBoolean case 0x000B: value = new byte[1] { bufferReader.ReadByte() }; break; // PtypString PT_UNICODE case 0x001F: value = Encoding.Unicode.GetBytes(bufferReader.ReadUnicodeString()); break; // PtypString8 case 0x001E: value = Encoding.ASCII.GetBytes(bufferReader.ReadASCIIString()); break; // 16-byte // PtypGuid 16bytes case 0x0048: // PtypServerId case 0x00FB: value = bufferReader.ReadBytes(16); break; // PtypRestriction case 0x00FD: tmpArray = bufferReader.ReadToEnd(); IRestriction restriction = null; RestrictionType restrictionType = (RestrictionType)tmpArray[0]; switch (restrictionType) { case RestrictionType.AndRestriction: restriction = new AndRestriction(); break; case RestrictionType.BitMaskRestriction: restriction = new BitMaskRestriction(); break; case RestrictionType.CommentRestriction: restriction = new CommentRestriction(); break; case RestrictionType.ComparePropertiesRestriction: restriction = new ComparePropertiesRestriction(); break; case RestrictionType.ContentRestriction: restriction = new ContentRestriction(); break; case RestrictionType.CountRestriction: restriction = new CountRestriction(); break; case RestrictionType.ExistRestriction: restriction = new ExistRestriction(); break; case RestrictionType.NotRestriction: restriction = new NotRestriction(); break; case RestrictionType.OrRestriction: restriction = new OrRestriction(); break; case RestrictionType.PropertyRestriction: restriction = new PropertyRestriction(); break; case RestrictionType.SizeRestriction: restriction = new SizeRestriction(); break; case RestrictionType.SubObjectRestriction: restriction = new SubObjectRestriction(); break; } length += restriction.Deserialize(tmpArray); value = bufferReader.ReadBytes(0, length); break; // PtypRuleAction case 0x00FE: tmpArray = bufferReader.ReadToEnd(); RuleAction ruleAction = new RuleAction(); length = ruleAction.Deserialize(tmpArray); bufferReader = new BufferReader(tmpArray); value = bufferReader.ReadBytes(length); break; // PtypBinary case 0x0102: length = (uint)(buffer[bufferReader.Position] + (buffer[bufferReader.Position + 1] << 8) + 2); value = bufferReader.ReadBytes(length); break; // PtypMultipleInteger16 case 0x1002: length = (uint)(buffer[bufferReader.Position] + (buffer[bufferReader.Position + 1] << 8)); length = (length * 2) + 2; value = bufferReader.ReadBytes(length); break; // PtypMultipleInteger32 case 0x1003: // PtypMultipleFloating32 case 0x1004: length = (uint)(buffer[bufferReader.Position] + (buffer[bufferReader.Position + 1] << 8)); length = (length * 4) + 2; value = bufferReader.ReadBytes(length); break; // PtypMultipleFloating64 case 0x1005: // PtypMultipleCurrency case 0x1006: // PtypMultipleFloatingTime case 0x1007: // PtypMultipleInteger64 case 0x1014: // PtypMultipleTime case 0x1040: length = (uint)(buffer[bufferReader.Position] + (buffer[bufferReader.Position + 1] << 8)); length = (length * 8) + 2; value = bufferReader.ReadBytes(length); break; // PtypMultipleString case 0x101F: startIndex = bufferReader.Position; ushort strCount = bufferReader.ReadUInt16(); for (int istr = 0; istr < strCount; istr++) { bufferReader.ReadUnicodeString(); } endIndex = bufferReader.Position; length = endIndex - startIndex; value = bufferReader.ReadBytes(startIndex, length); break; // PtypMultipleString8 case 0x101E: startIndex = bufferReader.Position; ushort str8Count = bufferReader.ReadUInt16(); for (int istr8 = 0; istr8 < str8Count; istr8++) { bufferReader.ReadASCIIString(); } endIndex = bufferReader.Position; length = endIndex - startIndex; value = bufferReader.ReadBytes(startIndex, length); break; // PtypMultipleGuid case 0x1048: length = (uint)(buffer[bufferReader.Position] + (buffer[bufferReader.Position + 1] << 8)); length = (length * 16) + 2; value = bufferReader.ReadBytes(length); break; // PtypMultipleBinary case 0x1102: startIndex = bufferReader.Position; ushort binCount = bufferReader.ReadUInt16(); for (int ibin = 0; ibin < binCount; ibin++) { uint binLength = bufferReader.ReadUInt16(); bufferReader.ReadBytes(binLength); } endIndex = bufferReader.Position; length = endIndex - startIndex; value = bufferReader.ReadBytes(startIndex, length); break; // PtypUnspecified case 0x0000: throw new NotImplementedException(); // PtypNull case 0x0001: value = null; break; // PtypObject or PtypEmbeddedTable case 0x000D: throw new NotImplementedException(); } return value; }
/// <summary> /// Generate a rule action. /// </summary> /// <param name="actionTypes">The action Type.</param> /// <param name="countBytes">The length of the bytes count.</param> /// <param name="actionDataBufferValue">The actionData buffer.</param> /// <param name="actionFlavor">Action flavor value.</param> /// <param name="actionFlags">Action flag value.</param> /// <returns>An instance of the RuleAction.</returns> private static RuleAction GetRuleAction(ActionType[] actionTypes, CountByte countBytes, IActionData[] actionDataBufferValue, uint[] actionFlavor, uint[] actionFlags) { ActionBlock[] actionBlocks = new ActionBlock[actionTypes.Length]; for (int i = 0; i < actionDataBufferValue.Length; i++) { ActionBlock actionBlock = new ActionBlock(countBytes) { ActionType = actionTypes[i], ActionFlags = actionFlags[i], ActionDataValue = actionDataBufferValue[i], ActionFlavor = actionFlavor[i] }; // Get actionBlock size int lengthOfActionLength = 0; if (actionBlock.CountType == CountByte.TwoBytesCount) { lengthOfActionLength += 2; } else if (actionBlock.CountType == CountByte.FourBytesCount) { lengthOfActionLength += 4; } // Length of ActionType is 1 // Length of ActionFlavor is 4 // Length of ActionFlags is 4 int size = lengthOfActionLength + 1 + 4 + 4 + actionBlock.ActionDataValue.Size(); actionBlock.ActionLength = (countBytes == CountByte.TwoBytesCount) ? (size - 2) : (size - 4); actionBlocks[i] = actionBlock; } RuleAction ruleAction = new RuleAction(countBytes) { NoOfActions = actionBlocks.Length, Actions = actionBlocks }; return ruleAction; }
/// <summary> /// Generate a rule action. /// </summary> /// <param name="actionType">The action Type.</param> /// <param name="countBytes">The length of the bytes count.</param> /// <param name="actionDataBufferValue">The actionData buffer.</param> /// <param name="actionFlavor">Action flavor value.</param> /// <param name="actionFlags">Action flag value.</param> /// <returns>An instance of the RuleAction.</returns> private static RuleAction GetRuleAction(ActionType actionType, CountByte countBytes, IActionData actionDataBufferValue, uint actionFlavor, uint actionFlags) { ActionBlock actionBlock = new ActionBlock(countBytes) { ActionType = actionType, ActionFlags = actionFlags, ActionDataValue = actionDataBufferValue, ActionFlavor = actionFlavor }; // Get actionBlock size int lengthOfActionLength = 0; if (actionBlock.CountType == CountByte.TwoBytesCount) { lengthOfActionLength += 2; } else if (actionBlock.CountType == CountByte.FourBytesCount) { lengthOfActionLength += 4; } // Length of ActionType is 1 // Length of ActionFlavor is 4 // Length of ActionFlags is 4 int size = lengthOfActionLength + 1 + 4 + 4 + actionBlock.ActionDataValue.Size(); actionBlock.ActionLength = (countBytes == CountByte.TwoBytesCount) ? (size - 2) : (size - 4); RuleAction ruleAction = new RuleAction(countBytes) { NoOfActions = 0x01, Actions = new ActionBlock[1] { actionBlock } }; // Only one rule action is generated. return ruleAction; }
/// <summary> /// Verify RuleAction buffer for stand rule. /// </summary> /// <param name="ruleAction">RuleAction structure to be verified.</param> private void VerifyRuleAction(RuleAction ruleAction) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R232, The value of NoOfActions is {0}", ruleAction.NoOfActions); // Verify MS-OXORULE requirement: MS-OXORULE_R232. // NoOfActions can be either unsigned-integer or unsigned-short. uint actionsNumber = (ruleAction.NoOfActions is uint) ? ((uint)ruleAction.NoOfActions) : ((ushort)ruleAction.NoOfActions); bool isVerifyR232 = actionsNumber > 0; Site.CaptureRequirementIfIsTrue( isVerifyR232, 232, @"[In RuleAction Structure] NoOfActions (2 bytes): This number MUST be greater than zero."); foreach (ActionBlock actionBlock in ruleAction.Actions) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R236"); // Verify MS-OXORULE requirement: MS-OXORULE_R236. // There are 2 or 4 bytes of the ActionLength in the ActionBlocks, // so the cumulative length in bytes of the subsequent fields of the ActionLength must equal to the length of ActionBlock.length - lengthOfActionLength. int lengthOfActionLength = actionBlock.ActionLength is ushort ? 2 : 4; bool isVerifyR236 = (actionBlock.ActionLength is ushort ? (ushort)actionBlock.ActionLength : (uint)actionBlock.ActionLength) == (actionBlock.Serialize().Length - lengthOfActionLength); Site.CaptureRequirementIfIsTrue( isVerifyR236, 236, @"[In ActionBlock Structure] ActionLength (2 bytes): An integer that specifies the cumulative length, in bytes, of the subsequent fields in this ActionBlock structure."); // Verify MS-OXORULE requirement: MS-OXORULE_R947. bool isVerifyR947 = (byte)actionBlock.ActionType == 0x01 || (byte)actionBlock.ActionType == 0x02 || (byte)actionBlock.ActionType == 0x03 || (byte)actionBlock.ActionType == 0x04 || (byte)actionBlock.ActionType == 0x05 || (byte)actionBlock.ActionType == 0x06 || (byte)actionBlock.ActionType == 0x07 || (byte)actionBlock.ActionType == 0x08 || (byte)actionBlock.ActionType == 0x09 || (byte)actionBlock.ActionType == 0x0A || (byte)actionBlock.ActionType == 0x0B; Site.CaptureRequirementIfIsTrue( isVerifyR947, 947, @"[In RuleAction Structure] ActionBlocks (variable): An array of ActionBlock structures, each of which specifies an action (2) of the rule (2), as specified in section 2.2.5.1."); } // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R231"); // Verify MS-OXORULE requirement: MS-OXORULE_R231. Site.CaptureRequirementIfAreEqual<uint>( (uint)ruleAction.Actions.Length, actionsNumber, 231, @"[In RuleAction Structure] NoOfActions (2 bytes): Specifies the number of structures that are contained in the ActionBlocks field."); // isVerifyR274 is used to verify R274 and R272. bool isVerifyR274 = false; // isVerifyR287 is used to verify R287 and R272. bool isVerifyR287 = false; // isVerifyR879 is used to verify R879 and R272. bool isVerifyR879 = false; for (int i = 0; i < ruleAction.Actions.Length; i++) { ActionBlock actionBlock = ruleAction.Actions[i]; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R245", "The value of the actionBlock.ActionType{0} should be one of 0x01 to 0x0b", actionBlock.ActionType); // Verify MS-OXORULE requirement: MS-OXORULE_R245. bool isVerifyR245 = (byte)actionBlock.ActionType == 0x01 || (byte)actionBlock.ActionType == 0x02 || (byte)actionBlock.ActionType == 0x03 || (byte)actionBlock.ActionType == 0x04 || (byte)actionBlock.ActionType == 0x05 || (byte)actionBlock.ActionType == 0x06 || (byte)actionBlock.ActionType == 0x07 || (byte)actionBlock.ActionType == 0x08 || (byte)actionBlock.ActionType == 0x09 || (byte)actionBlock.ActionType == 0x0A || (byte)actionBlock.ActionType == 0x0B; Site.CaptureRequirementIfIsTrue( isVerifyR245, 245, @"[In ActionBlock Structure] The valid actions (2) [of ActionType] are listed in the following table: OP_MOVE, OP_COPY, OP_REPLY, OP_OOF_REPLY, OP_DEFER_ACTION, OP_BOUNCE, OP_FORWARD, OP_DELEGATE, OP_TAG, OP_DELETE, OP_MARK_AS_READ."); if ((actionBlock.ActionType == ActionType.OP_MOVE) || (actionBlock.ActionType == ActionType.OP_COPY)) { MoveCopyActionData moveCopyActionData = (MoveCopyActionData)actionBlock.ActionDataValue; ServerEID serverEID = new ServerEID(moveCopyActionData.FolderEID); // The storeObjectEntryID structure could only verified in ExchangeServer2007, R632 also only executed in ExchangeServer2007. if (Common.IsRequirementEnabled(632, this.Site)) { StoreObjectEntryID storeObjectEntryID = new StoreObjectEntryID(); storeObjectEntryID.Deserialize(moveCopyActionData.StoreEID); this.VerifyStoreObjectEntryID(storeObjectEntryID); } // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R982: the value of Ours is {0}", serverEID.Ours); // Verify MS-OXORULE_R982. Site.CaptureRequirementIfAreEqual<ushort>( 0x01, serverEID.Ours, 982, @"[In ServerEid Structure] Ours (1 byte): This field MUST be set to 0x01."); // Add the debug information this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R980"); // Verify MS-OXORULE requirement: MS-OXORULE_R980 // Verify MS-OXORULE_R982 has verified the value of Ours is 0x01, MS-OXORULE_R980 verifies the instance's type. this.Site.CaptureRequirementIfIsInstanceOfType( serverEID, typeof(ServerEID), 980, @"[In ServerEid Structure] Ours (1 byte): The value 0x01 indicates that the remaining bytes conform to this structure [ServerEid]."); if (moveCopyActionData.StoreEIDSize != 0) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R297"); // Verify MS-OXORULE_R297. Site.CaptureRequirementIfAreEqual<ushort>( (ushort)moveCopyActionData.StoreEID.Length, moveCopyActionData.StoreEIDSize, 297, @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Standard Rules] StoreEIDSize (2 bytes): An integer that specifies the size, in bytes, of the StoreEID field."); } // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R300"); // Verify MS-OXORULE_R300. Site.CaptureRequirementIfAreEqual<ushort>( (ushort)moveCopyActionData.FolderEID.Length, moveCopyActionData.FolderEIDSize, 300, @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Standard Rules] FolderEIDSize (2 bytes): An integer that specifies the size, in bytes, of the FolderEID field."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R294"); // Verify MS-OXORULE_R294. // The structure of the OP_MOVE Action Date Buffer is verified by the requirements MS-OXORULE_R297, MS-OXORULE_R298, MS-OXORULE_R300, and MS-OXORULE_R301. Site.CaptureRequirement( 294, @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Standard Rules] The OP_MOVE ActionData structure MUST be in the following format for a standard rule. [FolderInThisStore, StoreEIDSize, StoreEID, FolderEIDSize, and FolderEID]."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R880"); // Verify MS-OXORULE_R880. // The structure of the OP_MOVE Action Date Buffer is verified by the requirements MS-OXORULE_R297, MS-OXORULE_R298, MS-OXORULE_R300, and MS-OXORULE_R301. Site.CaptureRequirement( 880, @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Standard Rules] The OP_COPY ActionData structure MUST be in the following format for a standard rule. [FolderInThisStore, StoreEIDSize, StoreEID, FolderEIDSize, and FolderEID]."); } if (actionBlock.ActionType == ActionType.OP_COPY) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R249"); // Verify MS-OXORULE requirement: MS-OXORULE_R249. // If the ActionType of the actionBlock equals the value ActionType.OP_COPY means server could parse the ActionType 0x02. Site.CaptureRequirement( 249, @"[In ActionBlock Structure] The value of action type OP_COPY: 0x02."); } if (actionBlock.ActionType == ActionType.OP_MOVE) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R246"); // Verify MS-OXORULE requirement: MS-OXORULE_R246. // If the ActionType of the actionBlock equals the value ActionType.OP_MOVE means server could parse the ActionType 0x01. Site.CaptureRequirement( 246, @"[In ActionBlock Structure] The value of action type OP_MOVE: 0x01."); } if (actionBlock.ActionType == ActionType.OP_FORWARD) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R261"); // Verify MS-OXORULE requirement: MS-OXORULE_R261. // If the ActionType of the actionBlock equals the value ActionType.OP_FORWARD means server could parse the ActionType 0x07. Site.CaptureRequirement( 261, @"[In ActionBlock Structure] The value of action type OP_FORWARD: 0x07."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R274, the value of ActionFlavor is {0}, the ActionFlavorsForward.x is {1}.", actionBlock.ActionFlavor, ActionFlavorsForward.x); // Verify MS-OXORULE requirement: MS-OXORULE_R274. // In ActionFlavor, the not used Flags must not be set, the used Flags can be set or all the bits are not set, it means ActionFlavor is set according to the description in this requirement. isVerifyR274 = (actionBlock.ActionFlavor & (uint)ActionFlavorsForward.x) == 0; Site.CaptureRequirementIfIsTrue( isVerifyR274, 274, @"[In Action Flavors] If the value of the ActionType field is ""OP_FORWARD"", the ActionFlavor field contains a combination of the bitwise flags [XXXX (TM) (AT) (NC) (PR) XXXXXXXXXXXXXXXXXXXXXXXXXX] specified as follows."); } if ((actionBlock.ActionType == ActionType.OP_REPLY) || (actionBlock.ActionType == ActionType.OP_OOF_REPLY)) { ReplyActionData actionData = new ReplyActionData(); actionData.Deserialize(ruleAction.Actions[0].ActionDataValue.Serialize()); if (actionBlock.ActionType == ActionType.OP_REPLY) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R287, the value of ActionFlavor is {0}, it should be one of ActionFlavorsReply.NS({1}), ActionFlavorsReply.ST({2}), or 0x00000000", actionBlock.ActionFlavor, ActionFlavorsReply.NS, ActionFlavorsReply.ST); // Verify MS-OXORULE requirement: MS-OXORULE_R287. // According to open specification, in this condition, the allowed value of ActionFlavor are NS, ST and 0x00000000. isVerifyR287 = (actionBlock.ActionFlavor == (uint)ActionFlavorsReply.NS) || (actionBlock.ActionFlavor == (uint)ActionFlavorsReply.ST) || (actionBlock.ActionFlavor == 0x00000000); Site.CaptureRequirementIfIsTrue( isVerifyR287, 287, @"[In Action Flavors] If the ActionType field value is ""OP_REPLY"", the ActionFlavor field MUST have one of the values specified in the following table [XXXXXX (ST) (NS) XXXXXXXXXXXXXXXXXXXXXXXX] or zero (0x00000000)."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R252"); // Verify MS-OXORULE requirement: MS-OXORULE_R252. // If the ActionType of the actionBlock equals the value ActionType.OP_REPLY means server could parse the ActionType 0x03. Site.CaptureRequirement( 252, @"[In ActionBlock Structure] The value of action type OP_REPLY: 0x03."); bool isVerifyR992 = actionData.ReplyTemplateGUID.Length != 0 && actionData.ReplyTemplateFID != 0 && actionData.ReplyTemplateMID != 0; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R992"); // Verify MS-OXORULE requirement: MS-OXORULE_R992. // If ReplyTemplateFID, ReplyTemplateMID, ReplyTemplateGUID in the ActionData is not null, R992 can be verified. Site.CaptureRequirementIfIsTrue( isVerifyR992, 992, @"[OP_REPLY and OP_OOF_REPLY ActionData Structure] [Buffer Format for Standard Rules] The OP_REPLY ActionData structure MUST be in the following format for a standard rule. [ReplyTemplateFID, ReplyTemplateMID, ReplyTemplateGUID]"); } ReplyActionData replyActionData = (ReplyActionData)actionBlock.ActionDataValue; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R308"); // Verify MS-OXORULE requirement: MS-OXORULE_R308. Site.CaptureRequirementIfIsTrue( Common.IsGUID(replyActionData.ReplyTemplateGUID), 308, @"[OP_REPLY and OP_OOF_REPLY ActionData Structure] [Buffer Format for Standard Rules] ReplyTemplateGUID (16 bytes): A GUID that is generated by the client in the process of creating a reply template."); if (actionBlock.ActionType == ActionType.OP_OOF_REPLY) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R879, the value of ActionFlavor is {0}", "it should be one of ActionFlavorsReply.NS({1}), ActionFlavorsReply.ST({2}), or 0x00000000", actionBlock.ActionFlavor, ActionFlavorsReply.NS, ActionFlavorsReply.ST); // Verify MS-OXORULE requirement: MS-OXORULE_R879. // According to open specification, in this condition, the allowed value of ActionFlavor are NS, ST and 0x00000000. isVerifyR879 = (actionBlock.ActionFlavor == (uint)ActionFlavorsReply.NS) || (actionBlock.ActionFlavor == (uint)ActionFlavorsReply.ST) || (actionBlock.ActionFlavor == 0x00000000); Site.CaptureRequirementIfIsTrue( isVerifyR879, 879, @"[In Action Flavors] If the ActionType field value is ""OP_OOF_REPLY"", the ActionFlavor field MUST have one of the values specified in the following table [XXXXXX (ST) (NS) XXXXXXXXXXXXXXXXXXXXXXXX] or zero (0x00000000). "); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R254"); // Verify MS-OXORULE requirement: MS-OXORULE_R254. // If the ActionType of the actionBlock equals the value ActionType. OP_OOF_REPLY means server could parse the ActionType and its value must be 0x04. Site.CaptureRequirement( 254, @"[In ActionBlock Structure] The value of action type OP_OOF_REPLY: 0x04."); bool isVerifyR993 = actionData.ReplyTemplateGUID.Length != 0 && actionData.ReplyTemplateFID != 0 && actionData.ReplyTemplateMID != 0; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R993"); // Verify MS-OXORULE requirement: MS-OXORULE_R993. // If ReplyTemplateFID, ReplyTemplateMID, ReplyTemplateGUID in the ActionData is not null, R993 can be verified. Site.CaptureRequirementIfIsTrue( isVerifyR993, 993, @"[OP_REPLY and OP_OOF_REPLY ActionData Structure] [Buffer Format for Standard Rules] The OP_OOF_REPLY ActionData structure MUST be in the following format for a standard rule. [ReplyTemplateFID, ReplyTemplateMID, ReplyTemplateGUID]"); } FolderID folderID = new FolderID(); folderID.Deserialize(replyActionData.ReplyTemplateFID); if (folderID != null) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R2175"); // Verify MS-OXCDATA requirement: MS-OXCDATA_R2175. Site.CaptureRequirementIfAreEqual<int>( 8, folderID.Size, "MS-OXCDATA", 2175, @"[In Folder ID Structure] It [Folder ID] is an 8-byte structure."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R2176"); // Verify MS-OXCDATA requirement: MS-OXCDATA_R2176. // "Identifying a Store object" is informative. Site.CaptureRequirementIfAreEqual<int>( 2, folderID.ReplicaId.Length, "MS-OXCDATA", 2176, @"[In Folder ID Structure] ReplicaId (2 bytes): An unsigned integer identifying a Store object."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R2177"); // Verify MS-OXCDATA requirement: MS-OXCDATA_R2177. // "Identifying the folder within its Store object" is informative. Site.CaptureRequirementIfAreEqual<int>( 6, folderID.GlobalCounter.Length, "MS-OXCDATA", 2177, @"[In Folder ID Structure] GlobalCounter (6 bytes): An unsigned integer identifying the folder within its Store object."); } MessageID messageID = new MessageID(); messageID.Deserialize(replyActionData.ReplyTemplateMID); if (messageID != null) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R2180"); // Verify MS-OXCDATA requirement: MS-OXCDATA_R2180. Site.CaptureRequirementIfAreEqual<int>( 8, messageID.Size, "MS-OXCDATA", 2180, @"[In Message ID Structure] It [Message ID] is an 8-byte structure."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R2181"); // Verify MS-OXCDATA requirement: MS-OXCDATA_R2181. // "Identifying a Store object" is informative. Site.CaptureRequirementIfAreEqual<int>( 2, messageID.ReplicaId.Length, "MS-OXCDATA", 2181, @"[In Message ID Structure] ReplicaId (2 bytes): An unsigned integer identifying a Store object."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R2182"); // Verify MS-OXCDATA requirement: MS-OXCDATA_R2182. // "Identifying the message within its Store object" is informative. Site.CaptureRequirementIfAreEqual<int>( 6, messageID.GlobalCounter.Length, "MS-OXCDATA", 2182, @"[In Message ID Structure] GlobalCounter (6 bytes): An unsigned integer identifying the message within its Store object."); } } if (actionBlock.ActionType == ActionType.OP_DEFER_ACTION) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R256"); // Verify MS-OXORULE requirement: MS-OXORULE_R256. // If the ActionType of the actionBlock equals the value ActionType.OP_DEFER_ACTION means server could parse the ActionType 0x05. Site.CaptureRequirement( 256, @"[In ActionBlock Structure] The value of action type OP_DEFER_ACTION: 0x05."); } if (actionBlock.ActionType == ActionType.OP_TAG) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R265"); // Verify MS-OXORULE requirement: MS-OXORULE_R265. // If the ActionType of the actionBlock equals the value ActionType.OP_TAG means server could parse the ActionType 0x09. Site.CaptureRequirement( 265, @"[In ActionBlock Structure] The value of action type OP_TAG: 0x09."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R739"); // Verify MS-OXORULE requirement: MS-OXORULE_R739. // If the taggedPropertyValueOP_TAG is not null means the action data buffer can be parsed by the TaggedPropertyValue. TaggedPropertyValue taggedPropertyValueOP_Tag = AdapterHelper.ReadTaggedProperty(actionBlock.ActionDataValue.Serialize()); Site.CaptureRequirementIfIsNotNull( taggedPropertyValueOP_Tag, 739, @"[In OP_TAG ActionData Structure] An OP_TAG ActionData structure is a TaggedPropertyValue structure, packaged as specified in [MS-OXCDATA] section 2.11.4."); } if ((actionBlock.ActionType == ActionType.OP_FORWARD) || (actionBlock.ActionType == ActionType.OP_REPLY) || (actionBlock.ActionType == ActionType.OP_OOF_REPLY)) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R272", "The value of the ActionFlavor is {0}, and the ActionType is {1}", actionBlock.ActionFlavor, actionBlock.ActionType); // Verify MS-OXORULE requirement: MS-OXORULE_R272. // According to open specification, the only action types that support the Action Flavor are OP_REPLY, OP_OOF_REPLY and OP_FORWARD. // The setting of ActionFlavor is verified in R274 and R287, so the condition to verify R272 is "isVerifyR274 || isVerifyR287". Site.CaptureRequirementIfIsTrue( isVerifyR274 || isVerifyR287 || isVerifyR879, 272, @"[In Action Flavors] The only ActionType field values that currently support an Action Flavor are ""OP_REPLY"", ""OP_OOF_REPLY"" and ""OP_FORWARD""."); } else { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R273"); // Verify MS-OXORULE requirement: MS-OXORULE_R273. Site.CaptureRequirementIfAreEqual<uint>( 0, actionBlock.ActionFlavor, 273, @"[In Action Flavors] The value of the ActionFlavor field MUST be 0x00000000 if the value of the ActionType field is not one of these values [OP_REPLY, OP_OOF_REPLY, and OP_FORWARD]."); } // When the AT flag in ActionFlavor is set. if ((actionBlock.ActionFlavor & (uint)ActionFlavorsForward.AT) == (uint)ActionFlavorsForward.AT) { // Verify MS-OXORULE requirement: MS-OXORULE_R280. uint otherActionFlavorFlags = (uint)ActionFlavorsForward.PR | (uint)ActionFlavorsForward.NC | (uint)ActionFlavorsForward.TM | (uint)ActionFlavorsForward.x; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R280, the value of ActionFlavor is {0}, this value should not be combined with otherActionFlavorFlags({1}).", actionBlock.ActionFlavor, otherActionFlavorFlags); // To verify whether the other ActionFlavor Flags are 0 when the AT flag in ActionFlavor is set. bool isVerifyR280 = (actionBlock.ActionFlavor & otherActionFlavorFlags) == 0; Site.CaptureRequirementIfIsTrue( isVerifyR280, 280, @"[In Action Flavors] AT (Bitmask 0x00000004): This value MUST NOT be combined with other ActionFlavor flags."); } // When the TM flag in ActionFlavor is set. if ((actionBlock.ActionFlavor & (uint)ActionFlavorsForward.TM) == (uint)ActionFlavorsForward.TM) { // Verify MS-OXORULE requirement: MS-OXORULE_R283. uint otherActionFlavorFlags = (uint)ActionFlavorsForward.PR | (uint)ActionFlavorsForward.NC | (uint)ActionFlavorsForward.AT | (uint)ActionFlavorsForward.x; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R283, the value of ActionFlavor is {0}, this value should not be combined with otherActionFlavorFlags({1}).", actionBlock.ActionFlavor, otherActionFlavorFlags); // To verify whether the other ActionFlavor Flags are 0 when the TM flag in ActionFlavor is set. bool isVerifyR283 = (actionBlock.ActionFlavor & otherActionFlavorFlags) == 0; Site.CaptureRequirementIfIsTrue( isVerifyR283, 283, @"[In Action Flavors] TM (Bitmask 0x00000008): This value MUST NOT be combined with other ActionFlavor flags."); } if (actionBlock.ActionType == ActionType.OP_FORWARD && Common.IsRequirementEnabled(636, this.Site)) { ForwardDelegateActionData forwardOrDelegateData = (ForwardDelegateActionData)actionBlock.ActionDataValue; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R636"); // Verify MS-OXORULE requirement: MS-OXORULE_R636. bool isVerifyR636 = true; foreach (RecipientBlock recipientBlock in forwardOrDelegateData.RecipientsData) { // Whether the PidTagEntryId exists. bool hasPidTagEntryId = false; foreach (TaggedPropertyValue property in recipientBlock.PropertiesData) { // propertyID of PidTagEntryId is 0x0FFF. if (property.PropertyTag.PropertyId == 0x0FFF) { hasPidTagEntryId = true; } } if (!hasPidTagEntryId) { isVerifyR636 = false; break; } } Site.CaptureRequirementIfIsTrue( isVerifyR636, 636, @"[In Appendix A: Product Behavior] Implementation does require the PidTagEntryId property for action ""OP_FORWARD"". [<8> Section 2.2.5.1.2.4.1: Exchange 2003 and Exchange 2007 also require the PidTagEntryId property for action ""OP_FORWARD"".]"); } if ((actionBlock.ActionType == ActionType.OP_FORWARD) || (actionBlock.ActionType == ActionType.OP_DELEGATE)) { if (actionBlock.ActionType == ActionType.OP_DELEGATE) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R263"); // Verify MS-OXORULE requirement: MS-OXORULE_R263. // If the ActionType of the actionBlock equals the value ActionType.DELEGATE means server could parse the ActionType 0x08. Site.CaptureRequirement( 263, @"[In ActionBlock Structure] The value of action type OP_DELEGATE: 0x08."); } ForwardDelegateActionData forwardOrDelegateData = (ForwardDelegateActionData)actionBlock.ActionDataValue; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R323, the recipient count is {0}.", forwardOrDelegateData.RecipientCount); // Verify MS-OXORULE requirement: MS-OXORULE_R323. bool isVerifyR323 = (forwardOrDelegateData.RecipientCount is ushort ? (ushort)forwardOrDelegateData.RecipientCount : (uint)forwardOrDelegateData.RecipientCount) == forwardOrDelegateData.RecipientsData.Length; Site.CaptureRequirementIfIsTrue( isVerifyR323, 323, @"[In OP_FORWARD and OP_DELEGATE ActionData Structure] RecipientCount (4 bytes): An integer that specifies the number of RecipientBlockData structures, as specified in section 2.2.5.1.2.4.1, contained in the RecipientBlocks field. "); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R324", "The value of the RecipientCount is {0}, it should greater than 0.", forwardOrDelegateData.RecipientCount); // Verify MS-OXORULE requirement: MS-OXORULE_R324. // The RecipientCount can be either unsigned-integer or unsigned-short. uint recipientCount = (forwardOrDelegateData.RecipientCount is uint) ? ((uint)forwardOrDelegateData.RecipientCount) : ((ushort)forwardOrDelegateData.RecipientCount); bool isVerifyR324 = recipientCount > 0; Site.CaptureRequirementIfIsTrue( isVerifyR324, 324, @"[In OP_FORWARD and OP_DELEGATE ActionData Structure] RecipientCount (4 bytes): This number MUST be greater than zero."); bool isVerifyR633 = true; bool isVerifyR632 = true; bool isVerifyR331 = true; foreach (RecipientBlock recipientBlock in forwardOrDelegateData.RecipientsData) { if (Common.IsRequirementEnabled(633, this.Site)) { if (recipientBlock.Reserved != 0x00) { isVerifyR633 = false; break; } } if (Common.IsRequirementEnabled(632, this.Site)) { if (recipientBlock.Reserved != 0x01) { isVerifyR632 = false; break; } } // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R330, the NoOfProperties of the RecipientBlock is {0}.", recipientBlock.NoOfProperties); // Verify MS-OXORULE requirement: MS-OXORULE_R330. bool isVerifyR330 = (recipientBlock.NoOfProperties is ushort ? (ushort)recipientBlock.NoOfProperties : (uint)recipientBlock.NoOfProperties) == (ulong)recipientBlock.PropertiesData.Length; Site.CaptureRequirementIfIsTrue( isVerifyR330, 330, @"[In RecipientBlockData Structure] NoOfProperties (4 bytes): An integer that specifies the number of structures present in the PropertyValues field."); TaggedPropertyValue[] taggedPropertyValue = recipientBlock.PropertiesData; bool isVerifyR468 = taggedPropertyValue[0].PropertyTag.PropertyId != 0 && taggedPropertyValue[0].PropertyTag.PropertyType != 0; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R468"); // Verify MS-OXCDATA requirement: MS-OXCDATA_R468. Site.CaptureRequirementIfIsTrue( isVerifyR468, "MS-OXCDATA", 468, @"[In TaggedPropertyValue Structure] PropertyTag (4 bytes): A PropertyTag structure, as specified in section 2.9, giving the values of the PropertyId and PropertyType fields for the property."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R469"); PropertyValue propertyValue = (PropertyValue)taggedPropertyValue[0]; // Verify MS-OXCDATA requirement: MS-OXCDATA_R469. Site.CaptureRequirementIfIsInstanceOfType( propertyValue, typeof(PropertyValue), "MS-OXCDATA", 469, @"[In TaggedPropertyValue Structure] PropertyValue (variable): A PropertyValue structure, as specified in section 2.11.2.1."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R1008"); // Verify MS-OXORULE requirement: MS-OXORULE_R1008. // The format of the TaggedPropertyValue structure has been verified by MS-OXCDATA_R468, and MS-OXCDATA_R469. Site.CaptureRequirement( 1008, @"[In RecipientBlockData Structure] The format of the TaggedPropertyValue structure is specified in [MS-OXCDATA] section 2.11.4."); // Verify MS-OXORULE requirement: MS-OXORULE_R331. uint properties = (recipientBlock.NoOfProperties is uint) ? ((uint)recipientBlock.NoOfProperties) : ((ushort)recipientBlock.NoOfProperties); if (properties <= 0) { isVerifyR331 = false; break; } } if (Common.IsRequirementEnabled(633, this.Site)) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R633"); Site.CaptureRequirementIfIsTrue( isVerifyR633, 633, @"[[In Appendix A: Product Behavior] Implementation does set this value [Reserved (1 byte)] to 0x00. [<9> Section 2.2.5.1.2.4.1: Exchange 2010, Exchange 2013, and Exchange 2016 set this value to 0x00.]"); } if (Common.IsRequirementEnabled(632, this.Site)) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R632"); Site.CaptureRequirementIfIsTrue( isVerifyR632, 632, @"[In Appendix A: Product Behavior] Implementation does set this value [Reserved (1 byte)] to 0x01. [<9> Section 2.2.5.1.2.4.1: Exchange 2003 and Exchange 2007 set this value to 0x01.]"); } // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R331"); // Verify MS-OXORULE requirement: MS-OXORULE_R331. Site.CaptureRequirementIfIsTrue( isVerifyR331, 331, @"[In RecipientBlockData Structure] NoOfProperties (4 bytes): This number MUST be greater than zero."); if (Common.IsRequirementEnabled(895, this.Site)) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R895"); // Verify requirement: MS-OXORULE_R895. bool isVerifyR895 = true; foreach (RecipientBlock recipientBlock in forwardOrDelegateData.RecipientsData) { // Whether the PidTagDisplayName exists. bool hasPidTagDisplayName = false; // Whether the PidTagEmailAddress exists. bool hasPidTagEmailAddress = false; // Whether the PidTagRecipientType exists. bool hasPidTagRecipientType = false; foreach (TaggedPropertyValue property in recipientBlock.PropertiesData) { // propertyID of hasPidTagDisplayName is 0x3001. if (property.PropertyTag.PropertyId == 0x3001) { hasPidTagDisplayName = true; } // propertyID of PidTagEmailAddress is 0x3003. if (property.PropertyTag.PropertyId == 0x3003) { hasPidTagEmailAddress = true; } // propertyID of PidTagRecipientType is 0x0C15. if (property.PropertyTag.PropertyId == 0x0C15) { hasPidTagRecipientType = true; } } if (!(hasPidTagDisplayName && hasPidTagEmailAddress && hasPidTagRecipientType)) { isVerifyR895 = false; break; } } // Verify MS-OXORULE requirement: MS-OXORULE_R895. Site.CaptureRequirementIfIsTrue( isVerifyR895, 895, @"[In RecipientBlock Data Buffer Packet Structure] No rules (2) does require more [specify values for more properties besides the PidTagDisplayName, PidTagEmailAddress, and PidTagRecipientType in the forward/delegate ActionData buffer] on the implementation. (Exchange 2010 and above follow this behavior.)"); } } if (actionBlock.ActionType == ActionType.OP_BOUNCE) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R259"); // Verify MS-OXORULE requirement: MS-OXORULE_R259. // If the ActionType of the actionBlock equals the value ActionType.OP_COPY means server could parse the ActionType 0x06. Site.CaptureRequirement( 259, @"[In ActionBlock Structure] The value of action type OP_BOUNCE: 0x06."); BounceActionData bounceActionData = (BounceActionData)actionBlock.ActionDataValue; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R340", "The value of the BounceCode field is {0}.", bounceActionData.Bounce); // Verify MS-OXORULE requirement: MS-OXORULE_R340. bool isVerifyR340 = (uint)bounceActionData.Bounce == 0x0000000D || (uint)bounceActionData.Bounce == 0x0000001F || (uint)bounceActionData.Bounce == 0x00000026; Site.CaptureRequirementIfIsTrue( isVerifyR340, 340, @"[In OP_BOUNCE ActionData Structure] The bounce code MUST be one of the following values. [0x0000000D, 0x0000001F, and 0x00000026]."); } if ((actionBlock.ActionType == ActionType.OP_DELETE) || (actionBlock.ActionType == ActionType.OP_MARK_AS_READ)) { if (actionBlock.ActionType == ActionType.OP_DELETE) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R267"); // If the ActionType of the actionBlock equals the value ActionType.OP_MOVE means server could parse the ActionType 0x0A. Site.CaptureRequirement( 267, @"[In ActionBlock Structure] The value of action type OP_DELETE: 0x0A."); } if (actionBlock.ActionType == ActionType.OP_MARK_AS_READ) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R269"); // If the ActionType of the actionBlock equals the value ActionType.OP_COPY means server could parse the ActionType 0x0B. Site.CaptureRequirement( 269, @"[In ActionBlock Structure] The value of action type OP_MARK_AS_READ: 0x0B."); } // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R346"); // Verify MS-OXORULE requirement: MS-OXORULE_R346. // If the Size of ActionDataValue is 0, it means these actions have no ActionData buffer. Site.CaptureRequirementIfAreEqual<int>( 0, actionBlock.ActionDataValue.Size(), 346, @"[In OP_DELETE or OP_MARK_AS_READ ActionData Structure] These actions [OP_DELETE, OP_MARK_AS_READ] (3) have no ActionData structure."); } } }
/// <summary> /// Verify the RopGetProperties in Rules Table. /// </summary> /// <param name="propertyTags">PropertyTag array.</param> /// <param name="quertyRowsResponse">Response of quertyRows.</param> private void VerifyPropertiesInTable(PropertyTag[] propertyTags, RopQueryRowsResponse quertyRowsResponse) { // propertyTags contains a list of PropertyTag. for (int i = 0; i < propertyTags.Length; i++) { // propertyId indicates the Id of a property. ushort propertyId = propertyTags[i].PropertyId; // propertyType indicates the Type of a property. ushort propertyType = propertyTags[i].PropertyType; // propertyValue indicates the value of a property. byte[] propertyValue = quertyRowsResponse.RowData.PropertyRows[quertyRowsResponse.RowData.PropertyRows.Count - 1].PropertyValues[i].Value; // If propertyId is 0x6674, it means the property is PidTagRuleId. if (propertyId == 0x6674) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R2699", "The length({0}) of the propertyValue should be 8 and the value of the propertyType({1}) should be 0x0014.", propertyValue.Length, propertyType); // Verify MS-OXCDATA requirement: MS-OXCDATA_R2699. bool isVerifyR2699 = propertyValue.Length == 8 && propertyType == 0x0014; Site.CaptureRequirementIfIsTrue( isVerifyR2699, "MS-OXCDATA", 2699, @"[In Property Data Types] PtypInteger64 (PT_LONGLONG, PT_I8, i8, ui8) is that 8 bytes; a 64-bit integer [MS-DTYP]: LONGLONG with Property Type Value 0x0014,%x14.00."); } // If propertyId is 0x001A, it means the property is PidTagMessageClass. if (propertyId == 0x001A) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R351"); // Verify MS-OXORULE requirement: MS-OXORULE_R351. Site.CaptureRequirementIfAreEqual<ushort>( (ushort)PropertyType.PtypString, propertyType, 351, @"[In PidTagMessageClass] Type: PtypString ([MS-OXCDATA] section 2.11.1)."); if (this.targetOfRop == TargetOfRop.ForDAM) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R352"); // Verify MS-OXORULE requirement: MS-OXORULE_R352. Site.CaptureRequirementIfAreEqual<string>( "IPC.Microsoft Exchange 4.0.Deferred Action", AdapterHelper.PropertyValueConvertToString(propertyValue), 352, @"[In PidTagMessageClass] The PidTagMessageClass property ([MS-OXCMSG] section 2.2.1.3) MUST be set to ""IPC.Microsoft Exchange 4.0.Deferred Action""."); } } // If propertyId is 0x6647, it means the property is PidTagDamBackPatched. if (propertyId == 0x6647) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R2698", "The length({0}) of the propertyValue should be 1 and the value of the propertyType({1}) should be 0x000b.", propertyValue.Length, propertyType); // Verify MS-OXCDATA requirement: MS-OXCDATA_R2698. bool isVerifyR2698 = propertyValue.Length == 1 && propertyType == 0x000B; Site.CaptureRequirementIfIsTrue( isVerifyR2698, "MS-OXCDATA", 2698, @"[In Property Data Types] PtypBoolean (PT_BOOLEAN. bool) is that 1 byte, restricted to 1 or 0 [MS-DTYP]: BOOLEAN with Property Type Value 0x000B, %x0B.00."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R353"); // Verify MS-OXORULE requirement: MS-OXORULE_R353. Site.CaptureRequirementIfAreEqual<ushort>( (ushort)PropertyType.PtypBoolean, propertyType, 353, @"[In PidTagDamBackPatched property] Type: PtypBoolean ([MS-OXCDATA] section 2.11.1)."); } // If propertyId is 0x6646, it means the property is PidTagDamOriginalEntryId. if (propertyId == 0x6646) { if (this.targetOfRop == TargetOfRop.ForDAM) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R356"); // Verify MS-OXORULE requirement: MS-OXORULE_R356. Site.CaptureRequirementIfAreEqual<ushort>( (ushort)PropertyType.PtypBinary, propertyType, 356, @"[In PidTagDamOriginalEntryId] Type: PtypBinary ([MS-OXCDATA] section 2.11.1)."); } else if (this.targetOfRop == TargetOfRop.ForDEM) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R712"); // Verify MS-OXORULE requirement: MS-OXORULE_R712. Site.CaptureRequirementIfAreEqual<ushort>( (ushort)PropertyType.PtypBinary, propertyType, 712, @"[In PidTagDamOriginalEntryId Property] Type: PtypBinary ([MS-OXCDATA] section 2.11.1)."); } } // If propertyId is 0x6681, it means the property is PidTagRuleProvider. if (propertyId == 0x6681) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R358"); // Verify MS-OXORULE requirement: MS-OXORULE_R358. Site.CaptureRequirementIfAreEqual<ushort>( (ushort)PropertyType.PtypString, propertyType, 358, @"[In PidTagRuleProvider] Type: PtypString ([MS-OXCDATA] section 2.11.1)."); } // If propertyId is 0x6651, it means the property is PidTagRuleFolderEntryId. if (propertyId == 0x6651) { if (this.targetOfRop == TargetOfRop.ForDAM) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R360"); // Verify MS-OXORULE requirement: MS-OXORULE_R360. Site.CaptureRequirementIfAreEqual<ushort>( (ushort)PropertyType.PtypBinary, propertyType, 360, @"[In PidTagRuleFolderEntryId] Type: PtypBinary ([MS-OXCDATA] section 2.11.1)."); } else if (this.targetOfRop == TargetOfRop.ForDEM) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R714"); // Verify MS-OXORULE requirement: MS-OXORULE_R714. Site.CaptureRequirementIfAreEqual<ushort>( (ushort)PropertyType.PtypBinary, propertyType, 714, @"[In PidTagRuleFolderEntryId Property] Type: PtypBinary ([MS-OXCDATA] section 2.11.1)."); } } // If propertyId is 0x6645, it means the property is PidTagClientActions. if (propertyId == 0x6645) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R362"); // Verify MS-OXORULE requirement: MS-OXORULE_R362. Site.CaptureRequirementIfAreEqual<ushort>( (ushort)PropertyType.PtypBinary, propertyType, 362, @"[In PidTagClientActions] Type: PtypBinary ([MS-OXCDATA] section 2.11.1)."); if (this.targetOfRop == TargetOfRop.ForDAM) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R364"); // Verify MS-OXORULE requirement: MS-OXORULE_R364. // Stack has constructed the rule action buffer according to section 2.2.5. // If ruleAction is not null, it means the propertyValue of PidTagClientActions can be parsed as the RuleAction format successfully, // which indicates this buffer has been packed according to this requirement. RuleAction ruleAction = new RuleAction(); ruleAction = AdapterHelper.PropertyValueConvertToRuleAction(propertyValue); Site.CaptureRequirementIfIsNotNull( ruleAction, 364, @"[In PidTagClientActions] The buffer MUST be packed according to the RuleAction structure specified in section 2.2.5."); } } // If propertyId is 0x6675, it means the property is PidTagRuleIds. if (propertyId == 0x6675) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R367"); // Verify MS-OXORULE requirement: MS-OXORULE_R367. Site.CaptureRequirementIfAreEqual<ushort>( (ushort)PropertyType.PtypBinary, propertyType, 367, @"[In PidTagRuleIds] Type: PtypBinary ([MS-OXCDATA] section 2.11.1)."); if (this.targetOfRop == TargetOfRop.ForDAM) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R369"); // Verify MS-OXORULE requirement: MS-OXORULE_R369. bool isVerifyR369 = AdapterHelper.PropertyValueConvertToBinary(propertyValue).Length % 8 == 0; Site.CaptureRequirementIfIsTrue( isVerifyR369, 369, @"[In PidTagRuleIds] The length of this binary property[PidTagRuleIds] MUST be a multiple of 8 bytes."); } } // If propertyId is 0x6741, it means the property is PidTagDeferredActionMessageOriginalEntryId. if (propertyId == 0x6741) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R2704"); // Verify MS-OXCDATA requirement: MS-OXCDATA_R2704. Site.CaptureRequirementIfAreEqual<ushort>( 0x00FB, propertyType, "MS-OXCDATA", 2704, @"[In Property Value Types] PtypServerId (PT_SVREID) is that variable size; a 16-bit COUNT field followed by a structure specified in section 2.11.1.4. with Property Type Value 0x00FB,%xFB.00."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R370"); // Verify MS-OXORULE requirement: MS-OXORULE_R370. Site.CaptureRequirementIfAreEqual<ushort>( (ushort)PropertyType.PtypServerId, propertyType, 370, @"[In PidTagDeferredActionMessageOriginalEntryId Property] Type: PtypServerId ([MS-OXCDATA] section 2.11.1)."); } // propertyID of PidTagHasDeferredActionMessages is 0x3FEA. if (propertyId == 0x3FEA) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R722, the propertyType of the PidTagHasDeferredActionMessages is {0}", propertyType); // Verify MS-OXORULE requirement: MS-OXORULE_R722. Site.CaptureRequirementIfAreEqual<ushort>( (ushort)PropertyType.PtypBoolean, propertyType, 722, @"[In PidTagHasDeferredActionMessages Property] Type: PtypBoolean ([MS-OXCDATA] section 2.11.1)."); } // propertyID of PidTagRwRulesStream is 0x6802. if (propertyId == 0x6802) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R1010, the propertyType of the PidTagRwRulesStream is {0}", propertyType); // Verify MS-OXORULE requirement: MS-OXORULE_R1010. Site.CaptureRequirementIfAreEqual<ushort>( (ushort)PropertyType.PtypBoolean, propertyType, 1010, @"[PidTagRwRulesStream Property] Type: PtypBinary ([MS-OXCDATA] section 2.11.1)."); } } }
/// <summary> /// Verify the RopGetProperties in RuleData Structure. /// </summary> /// <param name="ruleData">RuleData Structure.</param> private void VerifyPropertiesInRuleData(RuleData ruleData) { // RuleData contains a list of properties. for (int i = 0; i < ruleData.PropertyValues.Length; i++) { // propertyId indicates the Id of a property. ushort propertyId = (ruleData.PropertyValues[i] as TaggedPropertyValue).PropertyTag.PropertyId; // propertyType indicates the Type of a property. ushort propertyType = (ruleData.PropertyValues[i] as TaggedPropertyValue).PropertyTag.PropertyType; // propertyValue indicates the value of a property. byte[] propertyValue = (ruleData.PropertyValues[i] as TaggedPropertyValue).Value; switch (propertyId) { // If propertyId is 0x6679, it means the property is PidTagRuleCondition. case 0x6679: { RuleCondition ruleCondition = new RuleCondition(); ruleCondition.Deserialize(propertyValue); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R2705, the value of the propertyType is {0}.", propertyType); // Verify MS-OXCDATA requirement: MS-OXCDATA_R2705. // Stack De-serialize this structure as this requirement, if ruleCondition is not null, // "a byte array representing one or more Restriction structures" can be covered. bool isVerifyR2705 = ruleCondition != null && propertyType == 0x00FD; Site.CaptureRequirementIfIsTrue( isVerifyR2705, "MS-OXCDATA", 2705, @"[In Property Value Types] PtypRestriction (PT_SRESTRICT) is that variable size; a byte array representing one or more Restriction structures as specified in section 2.12. with Property Type Value 0x00FD,%xFD.00."); } break; // If propertyId is 0x6680, it means the property is PidTagRuleActions. case 0x6680: { RuleAction ruleAction = new RuleAction(); ruleAction.Deserialize(propertyValue); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R2706, the value of the propertyType is {0}.", propertyType); // Verify MS-OXCDATA requirement: MS-OXCDATA_R2706. // Stack De-serialize this structure as this requirement, if ruleAction is not null, // "a 16-bit COUNT of actions (not bytes) followed by that many Rule Action structures" can be covered. bool isVerifyR2706 = ruleAction != null && propertyType == 0x00FE; Site.CaptureRequirementIfIsTrue( isVerifyR2706, "MS-OXCDATA", 2706, @"[In Property Value Types] PtypRuleAction (PT_ACTIONS) is that variable size; a 16-bit COUNT field followed by that many rule (2) action (2) structures, as specified in [MS-OXORULE] section 2.2.5. with Property Type Value 0x00FE,%xFE.00."); } break; // If propertyId is 0x6674, it means the property is PidTagRuleId. case 0x6674: { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R2699", "The length({0}) of the propertyValue should be 8 and the value of the propertyType({1}) should be 0x0014.", propertyValue.Length, propertyType); // Verify MS-OXCDATA requirement: MS-OXCDATA_R2699. bool isVerifyR2699 = propertyValue.Length == 8 && propertyType == 0x0014; Site.CaptureRequirementIfIsTrue( isVerifyR2699, "MS-OXCDATA", 2699, @"[In Property Data Types] PtypInteger64 (PT_LONGLONG, PT_I8, i8, ui8) is that 8 bytes; a 64-bit integer [MS-DTYP]: LONGLONG with Property Type Value 0x0014,%x14.00."); } break; } } }
/// <summary> /// Verify RuleAction buffer for extend rule. /// </summary> /// <param name="ruleAction">RuleAction structure to be verified.</param> private void VerifyExtendRuleAction(RuleAction ruleAction) { // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R945: the size of the NoOfActions field is {0} bytes", (uint)ruleAction.NoOfActions); // Verify MS-OXORULE requirement: MS-OXORULE_R945. Site.CaptureRequirementIfAreEqual<Type>( typeof(uint), ruleAction.NoOfActions.GetType(), 945, @"[In RuleAction Structure] For extended rules, the size of the NoOfActions field is 4 bytes instead of 2 bytes."); for (int i = 0; i < ruleAction.Actions.Length; i++) { ActionBlock actionBlock = ruleAction.Actions[i]; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R949: the size of the ActionLength field is {0} bytes", (uint)actionBlock.ActionLength); // Verify MS-OXORULE requirement: MS-OXORULE_R949. Site.CaptureRequirementIfAreEqual<Type>( typeof(uint), actionBlock.ActionLength.GetType(), 949, @"[In ActionBlock Structure] ActionLength (2 bytes): For extended rules, the size of the ActionLength field is 4 bytes instead of 2 bytes."); if ((actionBlock.ActionType == ActionType.OP_MOVE) || (actionBlock.ActionType == ActionType.OP_COPY)) { MoveCopyActionDataOfExtendedRule actionData = (MoveCopyActionDataOfExtendedRule)actionBlock.ActionDataValue; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R970."); // Verify MS-OXORULE_R970. Site.CaptureRequirementIfAreEqual<uint>( (uint)actionData.StoreEID.Length, actionData.StoreEIDSize, 970, @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Extended Rules] StoreEIDSize (4 bytes): An integer that specifies the size, in bytes, of the StoreEID field."); // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R975."); // Verify MS-OXORULE_R975. Site.CaptureRequirementIfAreEqual<uint>( (uint)actionData.FolderEID.Length, actionData.FolderEIDSize, 975, @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Extended Rules] FolderEIDSize (4 bytes): An integer that specifies the size, in bytes, of the FolderEID field."); if (actionBlock.ActionType == ActionType.OP_COPY) { bool isVerifyR967 = actionData.FolderEID.Length != 0 && actionData.StoreEID.Length != 0; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R967"); // Verify MS-OXORULE requirement: MS-OXORULE_R967. // If StoreEIDSize, StoreEID, FolderEIDSize, and FolderEID in the ActionData is not null, R967 can be verified. Site.CaptureRequirementIfIsTrue( isVerifyR967, 967, @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Extended Rules] The OP_COPY ActionData structure MUST be in the following format for an extended rule. [StoreEIDSize, StoreEID, FolderEIDSize, and FolderEID]."); } if (actionBlock.ActionType == ActionType.OP_MOVE) { bool isVerifyR966 = actionData.FolderEID.Length != 0 && actionData.StoreEID.Length != 0; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R966, the length of FolderEID is {0}, and the length of StoreEID is {1}", actionData.FolderEID.Length, actionData.StoreEID.Length); // Verify MS-OXORULE requirement: MS-OXORULE_R966. // If StoreEIDSize, StoreEID, FolderEIDSize, and FolderEID in the ActionData is not null, R966 can be verified. Site.CaptureRequirementIfIsTrue( isVerifyR966, 966, @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Extended Rules] The OP_MOVE ActionData structure MUST be in the following format for an extended rule. [StoreEIDSize, StoreEID, FolderEIDSize, and FolderEID]."); } } if ((actionBlock.ActionType == ActionType.OP_REPLY) || (actionBlock.ActionType == ActionType.OP_OOF_REPLY)) { ReplyActionDataOfExtendedRule actionData = (ReplyActionDataOfExtendedRule)actionBlock.ActionDataValue; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R997."); // Verify MS-OXORULE_R997. Site.CaptureRequirementIfAreEqual<uint>( (uint)actionData.ReplyTemplateMessageEID.Length, actionData.MessageEIDSize, 997, @"[OP_REPLY and OP_OOF_REPLY ActionData Structure] [Buffer Format for Extended Rules] MessageEIDSize (4 bytes): An integer that specifies the size, in bytes, of the ReplyTemplateMessageEID field."); if (actionBlock.ActionType == ActionType.OP_REPLY) { bool isVerifyR995 = actionData.ReplyTemplateMessageEID.Length != 0 && actionData.ReplyTemplateGUID.Length != 0; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R995, the length of ReplyTemplateMessageEID is {0}, and the actionData.ReplyTemplateGUID is {1}", (uint)actionData.ReplyTemplateMessageEID.Length, actionData.ReplyTemplateGUID.Length); // Verify MS-OXORULE requirement: MS-OXORULE_R995. // If ReplyTemplateFID, ReplyTemplateMID, ReplyTemplateGUID in the ActionData is not null, R995 can be verified. Site.CaptureRequirementIfIsTrue( isVerifyR995, 995, @"[OP_REPLY and OP_OOF_REPLY ActionData Structure] [Buffer Format for Extended Rules] The OP_REPLY ActionData structure MUST be in the following format for an extended rule. [MessageEIDSize, ReplyTemplateMessageEID, ReplyTemplateGUID]"); } if (actionBlock.ActionType == ActionType.OP_OOF_REPLY) { bool isVerifyR996 = actionData.ReplyTemplateMessageEID.Length != 0 && actionData.ReplyTemplateGUID.Length != 0; // Add the debug information. Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R996, the length of ReplyTemplateMessageEID is {0}, and the actionData.ReplyTemplateGUID is {1}", (uint)actionData.ReplyTemplateMessageEID.Length, actionData.ReplyTemplateGUID.Length); // Verify MS-OXORULE requirement: MS-OXORULE_R996. // If ReplyTemplateFID, ReplyTemplateMID, ReplyTemplateGUID in the ActionData is not null, R996 can be verified. Site.CaptureRequirementIfIsTrue( isVerifyR996, 996, @"[OP_REPLY and OP_OOF_REPLY ActionData Structure] [Buffer Format for Extended Rules] The OP_OOF_REPLY ActionData structure MUST be in the following format for an extended rule. [MessageEIDSize, ReplyTemplateMessageEID, ReplyTemplateGUID]"); } } } }
/// <summary> /// Deserialized byte array to an ActionData instance /// </summary> /// <param name="buffer">Byte array contain data of an ActionData instance.</param> /// <returns>Bytes count that deserialized in buffer.</returns> public uint Deserialize(byte[] buffer) { BufferReader bufferReader = new BufferReader(buffer); this.NamedPropertyInformation = new NamedPropertyInfo(); uint namedPropertyInfoLength = this.NamedPropertyInformation.Deserialize(buffer); bufferReader = new BufferReader(bufferReader.ReadBytes(namedPropertyInfoLength, (uint)(buffer.Length - namedPropertyInfoLength))); this.RuleVersion = bufferReader.ReadUInt32(); this.RuleActionBuffer = new RuleAction(CountByte.FourBytesCount); uint actionLength = this.RuleActionBuffer.Deserialize(bufferReader.ReadToEnd()); uint length = namedPropertyInfoLength + sizeof(uint) + actionLength; return length; }
/// <summary> /// Query properties in contents table. /// </summary> /// <param name="tableHandle">Handle of a specific contents table.</param> /// <param name="propertyTags">Array of PropertyTag structures. This field specifies the property values that are visible in table rows.</param> /// <returns>Response of this query rows.</returns> public RopQueryRowsResponse QueryPropertiesInTable(uint tableHandle, PropertyTag[] propertyTags) { // Set the properties in propertyTags to be visible. RopSetColumnsResponse setColumnsResponse = this.RopSetColumns(tableHandle, 0x00, propertyTags); // Query properties values specified in propertyTags. RopQueryRowsResponse queryRowsResponse = this.RopQueryRows(tableHandle, 0x00, 0x01, 1000); // That the two Rops are successful means that the propertyTags in request is correct if (setColumnsResponse.ReturnValue == 0 && queryRowsResponse.ReturnValue == 0 && queryRowsResponse.RowData.PropertyRows != null) { // Verify PropertyTags this.VerifyPropertiesInTable(propertyTags, queryRowsResponse); for (int i = 0; i < propertyTags.Length; i++) { // If the property queried is PidTagRuleActions if (propertyTags[i].PropertyId == (ushort)PropertyId.PidTagRuleActions) { for (int j = 0; j < queryRowsResponse.RowData.PropertyRows.Count; j++) { // Verify structure RuleAction RuleAction ruleAction = new RuleAction(); ruleAction.Deserialize(queryRowsResponse.RowData.PropertyRows[j].PropertyValues[i].Value); this.VerifyRuleAction(ruleAction); } } // If the property queried is PidTagExtendedRuleMessageActions if (propertyTags[i].PropertyId == (ushort)PropertyId.PidTagExtendedRuleMessageActions) { for (int j = 0; j < queryRowsResponse.RowData.PropertyRows.Count; j++) { if (BitConverter.ToUInt32(queryRowsResponse.RowData.PropertyRows[j].PropertyValues[i].Value, 0) != (uint)ErrorCodeValue.NotFound) { // Verify structure RuleAction ExtendedRuleActions ruleAction = new ExtendedRuleActions(); byte[] extendedRuleMessageActionBuffer = new byte[queryRowsResponse.RowData.PropertyRows[j].PropertyValues[i].Value.Length - 2]; Array.Copy(queryRowsResponse.RowData.PropertyRows[j].PropertyValues[i].Value, 2, extendedRuleMessageActionBuffer, 0, queryRowsResponse.RowData.PropertyRows[j].PropertyValues[i].Value.Length - 2); ruleAction.Deserialize(extendedRuleMessageActionBuffer); this.VerifyExtendRuleAction(ruleAction.RuleActionBuffer); } } } } } return queryRowsResponse; }