An extended rule's PidTagExtendedRuleMessageActions property contains additional information about the Version of the rule and the named properties stored in the rule action, as well as information about the actions to be performed by this rule.
Inheritance: IActionData
        public void MSOXORULE_S01_TC09_AddExtendedRuleForThreeTimes()
        {
            this.CheckMAPIHTTPTransportSupported();
            Site.Assume.IsTrue(Common.IsRequirementEnabled(646, this.Site), "This case runs only when the server supports processing more than two extended rules it encounters per folder.");

            #region TestUser1 creates an FAI message for the first extended rule.
            RopCreateMessageResponse ropCreateMessageResponse;
            uint extendedRuleMessageHandle1 = this.OxoruleAdapter.RopCreateMessage(this.InboxFolderHandle, this.InboxFolderID, Convert.ToByte(true), out ropCreateMessageResponse);
            Site.Assert.AreEqual<uint>(0, ropCreateMessageResponse.ReturnValue, "Creating the first FAI message should succeed.");

            NamedPropertyInfo namedPropertyInfo1 = new NamedPropertyInfo
            {
                NoOfNamedProps = 0
            };
            TaggedPropertyValue[] extendedRuleProperties1 = AdapterHelper.GenerateExtendedRuleTestData(Common.GenerateResourceName(this.Site, Constants.ExtendRulename1), 0, (uint)RuleState.ST_ENABLED, Constants.PidTagRuleProvider, ActionType.OP_MARK_AS_READ, new DeleteMarkReadActionData(), Constants.ExtendRuleCondition1, namedPropertyInfo1);

            // Set properties for extended rule FAI message.
            RopSetPropertiesResponse ropSetPropertiesResponse = this.OxoruleAdapter.RopSetProperties(extendedRuleMessageHandle1, extendedRuleProperties1);
            Site.Assert.AreEqual<uint>(0, ropSetPropertiesResponse.ReturnValue, "Setting property for Extended rule FAI message should succeed.");

            // Save changes of message.
            RopSaveChangesMessageResponse ropSaveChangesMessagResponse = this.OxoruleAdapter.RopSaveChangesMessage(extendedRuleMessageHandle1);
            Site.Assert.AreEqual(0, (int)ropSaveChangesMessagResponse.ReturnValue, "Saving Extend rule message should succeed.");
            #endregion

            #region TestUser1 retrieves data of the extended rule.
            this.OxoruleAdapter.TargetOfRop = TargetOfRop.ForExtendedRules;
            RopGetPropertiesAllResponse ropGetExtendRuleMessageResponse = this.OxoruleAdapter.RopGetPropertiesAll(extendedRuleMessageHandle1, this.PropertySizeLimitFlag, (ushort)WantUnicode.Want);
            Site.Assert.AreEqual<uint>(0, ropGetExtendRuleMessageResponse.ReturnValue, "Getting all properties operation should succeed.");
            Site.Assert.IsTrue(ropGetExtendRuleMessageResponse.PropertyValues.Length != 0, "Extended Rule data should be found in related FAI message!");
            this.OxoruleAdapter.TargetOfRop = TargetOfRop.OtherTarget;

            ExtendedRuleActions extendedRuleMessageActions = new ExtendedRuleActions();

            // Check the properties set on Extended Rule, and find the Extended Rule Actions.
            for (int i = 0; i < ropGetExtendRuleMessageResponse.PropertyValues.Length; i++)
            {
                // propertyId indicates the Id of a property set on Extended Rule.
                ushort propertyId = ropGetExtendRuleMessageResponse.PropertyValues[i].PropertyTag.PropertyId;
                if (propertyId == (ushort)PropertyId.PidTagExtendedRuleMessageActions)
                {
                    byte[] propertyValue = ropGetExtendRuleMessageResponse.PropertyValues[i].Value;
                    extendedRuleMessageActions = AdapterHelper.PropertyValueConvertToExtendedRuleActions(propertyValue);
                    break;
                }
            }

            // Get the Property Names saved by server in the extendedRuleMessageActions.
            PropertyName[] propertyNames = extendedRuleMessageActions.NamedPropertyInformation.NamedProperty;
            uint[] propertyIds = extendedRuleMessageActions.NamedPropertyInformation.PropId;
            Site.Assert.AreEqual<uint>(0, extendedRuleMessageActions.NamedPropertyInformation.NoOfNamedProps, "The property NoOfNamedProps of NamedPropertyInformation should be zero!");

            #region Capture Code
            // Add the debug information.
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R696.");

            // NoOfNamedProps set to 0, it means no named properties are used in the structure that follows the Named Property Information buffer.
            // So if NamedProperty of NamedPropertyInformation in the extendedRuleMessageActions is null. This requirement can be verified. 
            bool isVerifyR696 = propertyNames == null;

            Site.CaptureRequirementIfIsTrue(
                isVerifyR696,
                696,
                @"[In NamedPropertyInformation Structure] NoOfNamedProps (2 bytes): If no named properties are used in the structure that follows the NamedPropertyInformation structure, the value of this field MUST be 0x0000.");

            // Add the debug information.
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R936");

            // NoOfNamedProps set to 0, it means no named properties are used in the structure that follows the Named Property Information buffer.
            // So if NamedProperty, PropIds of NamedPropertyInformation in the extendedRuleMessageActions is null. This requirement can be verified. 
            bool isVerifyR936 = propertyNames == null && propertyIds == null;

            Site.CaptureRequirementIfIsTrue(
                isVerifyR936,
                936,
                @"[In NamedPropertyInformation Structure] [If no named properties are used in the structure that follows the NamedPropertyInformation structure] no other fields [except NoOfNamedProps] are present.");

            // Add the debug information.
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R697");

            // When NoOfNamedProps is set to 0, NamedPropertyInformation in ExtendedRuleActions reduces to a 2-byte WORD value of NoOfNamedProps.
            Site.CaptureRequirement(
                697,
                @"[In NamedPropertyInformation Structure] Note that if there are no named properties to be listed, the NamedPropertyInformation structure reduces to a 2-byte value of 0x0000.");
            #endregion
            #endregion

            #region TestUser2 delivers a message to TestUser1 to trigger the rule.
            Thread.Sleep(this.WaitForTheRuleToTakeEffect);

            // TestUser2 delivers a message to TestUser1 to trigger the rule.
            string mailSubject1 = Common.GenerateResourceName(this.Site, Constants.ExtendRuleCondition1);
            this.SUTAdapter.SendMailToRecipient(this.User2Name, this.User2Password, this.User1Name, mailSubject1);
            Thread.Sleep(this.WaitForTheRuleToTakeEffect);
            PropertyTag[] propertyTagList = new PropertyTag[2];
            propertyTagList[0].PropertyId = (ushort)PropertyId.PidTagSubject;
            propertyTagList[0].PropertyType = (ushort)PropertyType.PtypString;
            propertyTagList[1].PropertyId = (ushort)PropertyId.PidTagMessageFlags;
            propertyTagList[1].PropertyType = (ushort)PropertyType.PtypInteger32;

            int messageFlag1 = 1;
            uint contentTableHandle1 = 0;
            int expectedMessageIndex1 = 0;
            RopQueryRowsResponse getMailMessageContent1 = this.GetExpectedMessage(this.InboxFolderHandle, ref contentTableHandle1, propertyTagList, ref expectedMessageIndex1, mailSubject1);
            mailSubject1 = AdapterHelper.PropertyValueConvertToString(getMailMessageContent1.RowData.PropertyRows[expectedMessageIndex1].PropertyValues[0].Value);
            messageFlag1 = BitConverter.ToInt32(getMailMessageContent1.RowData.PropertyRows[expectedMessageIndex1].PropertyValues[1].Value, 0);

            #endregion

            #region TestUser1 creates an FAI message for the second extended rule.
            uint extendedRuleMessageHandle2 = this.OxoruleAdapter.RopCreateMessage(this.InboxFolderHandle, this.InboxFolderID, Convert.ToByte(true), out ropCreateMessageResponse);
            Site.Assert.AreEqual<uint>(0, ropCreateMessageResponse.ReturnValue, "Creating the second FAI message should succeed.");
            #endregion

            #region TestUser1 creates the second extended rule with no NamedProperty.
            NamedPropertyInfo namedPropertyInfo2 = new NamedPropertyInfo();
            namedPropertyInfo1.NoOfNamedProps = 0;
            TaggedPropertyValue[] extendedRuleProperties2 = AdapterHelper.GenerateExtendedRuleTestData(Common.GenerateResourceName(this.Site, Constants.ExtendRulename2), 0, (uint)RuleState.ST_ENABLED, Constants.PidTagRuleProvider, ActionType.OP_MARK_AS_READ, new DeleteMarkReadActionData(), Constants.ExtendRuleCondition2, namedPropertyInfo2);

            // Set properties for extended rule FAI message.
            ropSetPropertiesResponse = this.OxoruleAdapter.RopSetProperties(extendedRuleMessageHandle2, extendedRuleProperties2);
            Site.Assert.AreEqual<uint>(0, ropSetPropertiesResponse.ReturnValue, "Setting property for Extended rule FAI message should succeed.");

            // Save changes of message.
            ropSaveChangesMessagResponse = this.OxoruleAdapter.RopSaveChangesMessage(extendedRuleMessageHandle2);
            Site.Assert.AreEqual(0, (int)ropSaveChangesMessagResponse.ReturnValue, "Saving Extend rule message should succeed.");
            #endregion

            #region TestUser2 delivers a message to TestUser1 to trigger the rule.
            Thread.Sleep(this.WaitForTheRuleToTakeEffect);

            // TestUser2 delivers a message to TestUser1 to trigger the rule.
            string mailSubject2 = Common.GenerateResourceName(this.Site, Constants.ExtendRuleCondition2);
            this.SUTAdapter.SendMailToRecipient(this.User2Name, this.User2Password, this.User1Name, mailSubject2);
            Thread.Sleep(this.WaitForTheRuleToTakeEffect);

            int messageFlag2 = 1;
            uint contentTableHandle2 = 0;
            int expectedMessageIndex2 = 0;
            RopQueryRowsResponse getMailMessageContent2 = this.GetExpectedMessage(this.InboxFolderHandle, ref contentTableHandle2, propertyTagList, ref expectedMessageIndex2, mailSubject2);
            mailSubject2 = AdapterHelper.PropertyValueConvertToString(getMailMessageContent2.RowData.PropertyRows[expectedMessageIndex2].PropertyValues[0].Value);
            messageFlag2 = BitConverter.ToInt32(getMailMessageContent2.RowData.PropertyRows[expectedMessageIndex2].PropertyValues[1].Value, 0);
            #endregion

            #region TestUser1 creates an FAI message for the third extended rule.
            uint extendedRuleMessageHandle3 = this.OxoruleAdapter.RopCreateMessage(this.InboxFolderHandle, this.InboxFolderID, Convert.ToByte(true), out ropCreateMessageResponse);
            Site.Assert.AreEqual<uint>(0, ropCreateMessageResponse.ReturnValue, "Creating the second FAI message should succeed.");
            #endregion

            #region TestUser1 creates the third extended rule with no NamedProperty.
            NamedPropertyInfo namedPropertyInfo3 = new NamedPropertyInfo();
            namedPropertyInfo1.NoOfNamedProps = 0;
            TaggedPropertyValue[] extendedRuleProperties3 = AdapterHelper.GenerateExtendedRuleTestData(Common.GenerateResourceName(this.Site, Constants.ExtendRulename3), 0, (uint)RuleState.ST_ENABLED, Constants.PidTagRuleProvider, ActionType.OP_MARK_AS_READ, new DeleteMarkReadActionData(), Constants.ExtendRuleCondition3, namedPropertyInfo3);

            // Set properties for extended rule FAI message.
            ropSetPropertiesResponse = this.OxoruleAdapter.RopSetProperties(extendedRuleMessageHandle3, extendedRuleProperties3);
            Site.Assert.AreEqual<uint>(0, ropSetPropertiesResponse.ReturnValue, "Setting property for Extended rule FAI message should succeed.");

            // Save changes of the message.
            ropSaveChangesMessagResponse = this.OxoruleAdapter.RopSaveChangesMessage(extendedRuleMessageHandle3);
            Site.Assert.AreEqual(0, (int)ropSaveChangesMessagResponse.ReturnValue, "Saving Extend rule message should succeed.");
            #endregion

            #region TestUser2 delivers a message to TestUser1 to trigger the rule.
            Thread.Sleep(this.WaitForTheRuleToTakeEffect);

            // TestUser2 delivers a message to TestUser1 to trigger the rule.
            string mailSubject3 = Common.GenerateResourceName(this.Site, Constants.ExtendRuleCondition3);
            this.SUTAdapter.SendMailToRecipient(this.User2Name, this.User2Password, this.User1Name, mailSubject3);
            Thread.Sleep(this.WaitForTheRuleToTakeEffect);

            int messageFlag3 = 1;
            uint contentTableHandle3 = 0;
            int expectedMessageIndex3 = 0;
            RopQueryRowsResponse getMailMessageContent3 = this.GetExpectedMessage(this.InboxFolderHandle, ref contentTableHandle3, propertyTagList, ref expectedMessageIndex3, mailSubject3);
            mailSubject3 = AdapterHelper.PropertyValueConvertToString(getMailMessageContent3.RowData.PropertyRows[expectedMessageIndex3].PropertyValues[0].Value);
            messageFlag3 = BitConverter.ToInt32(getMailMessageContent3.RowData.PropertyRows[expectedMessageIndex3].PropertyValues[1].Value, 0);

            // Add the debug information.
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R646: the third message is {0} marked as read.", (messageFlag3 & 0x00000001) == 0x00000001 ? string.Empty : "not");

            // Verify MS-OXORULE requirement: MS-OXORULE_R646.
            // 0x00000001 is the flag which represents the message has been read. If messageFlag doesn't set this flag, it means the incoming message 
            // isn't marked as read, which indicates the server doesn't evaluate the third rule.
            bool isVerifyR646 = (messageFlag3 & 0x00000001) == 0x00000000 && (messageFlag2 & 0x00000001) == 0x00000001 && (messageFlag1 & 0x00000001) == 0x00000001;

            Site.CaptureRequirementIfIsTrue(
                isVerifyR646,
                646,
                @"[In Appendix A: Product Behavior] Implementation does process the standard rule for a message but does only process the first two extended rules it encounters per folder. [<15> Section 3.2.4.1: Exchange 2007 by default will process the standard rule for a message but will only process the first two extended rules it encounters per folder.]");
            #endregion
        }
        public void MSOXORULE_S01_TC11_AddExtendedRule_OP_OOF_REPLY()
        {
            this.CheckMAPIHTTPTransportSupported();

            #region Prepare value for ruleProperties variable
            RuleProperties ruleProperties = AdapterHelper.GenerateRuleProperties(this.Site, Constants.RuleNameOOFReply);
            #endregion

            #region Create a reply template in the TestUser1's Inbox folder.
            ulong replyTemplateMessageId;
            uint replyTemplateMessageHandler;
            string replyTemplateSubject = Common.GenerateResourceName(this.Site, Constants.ReplyTemplateSubject);

            TaggedPropertyValue[] replyTemplateProperties = new TaggedPropertyValue[1];
            replyTemplateProperties[0] = new TaggedPropertyValue();
            PropertyTag replyTemplatePropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagBody,
                PropertyType = (ushort)PropertyType.PtypString
            };
            replyTemplateProperties[0].PropertyTag = replyTemplatePropertyTag;
            replyTemplateProperties[0].Value = Encoding.Unicode.GetBytes(Constants.ReplyTemplateBody + "\0");

            byte[] guidByte = this.OxoruleAdapter.CreateReplyTemplate(this.InboxFolderHandle, this.InboxFolderID, true, replyTemplateSubject, replyTemplateProperties, out replyTemplateMessageId, out replyTemplateMessageHandler);
            #endregion

            #region TestUser1 gets the reply template.
            #region Step1: TestUser1 gets a table of the messages.
            uint contentsTableHandleOfFAIMessage;
            RopGetContentsTableResponse ropGetContentsTableResponseOfFAIMessage = this.OxoruleAdapter.RopGetContentsTable(this.InboxFolderHandle, ContentTableFlag.Associated, out contentsTableHandleOfFAIMessage);
            Site.Assert.AreEqual<uint>(0, ropGetContentsTableResponseOfFAIMessage.ReturnValue, "Getting DAF contents table should succeed");
            #endregion

            #region Step2: TestUser1 sets the interested columns of the message table.

            // Here are 2 interested columns listed as below.
            PropertyTag[] propertyTagOfFAIMessage = new PropertyTag[2];
            PropertyTag pidTagMessageSubject = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagSubject,
                PropertyType = (ushort)PropertyType.PtypString
            };
            propertyTagOfFAIMessage[0] = pidTagMessageSubject;
            PropertyTag pidTagReplyTemplateId = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagReplyTemplateId,
                PropertyType = (ushort)PropertyType.PtypBinary
            };
            propertyTagOfFAIMessage[1] = pidTagReplyTemplateId;

            // Query rows which include the property values of the interested columns. 
            RopQueryRowsResponse ropQueryRowsResponseOfFAIMessage = this.OxoruleAdapter.QueryPropertiesInTable(contentsTableHandleOfFAIMessage, propertyTagOfFAIMessage);
            Site.Assert.AreNotEqual<ushort>(0, ropQueryRowsResponseOfFAIMessage.RowCount, "There should be message generated in TestUser1's Inbox folder");
            byte[] replyTemplateId = null;
            for (int i = 0; i < ropQueryRowsResponseOfFAIMessage.RowCount; i++)
            {
                string messageSubject = AdapterHelper.PropertyValueConvertToString(ropQueryRowsResponseOfFAIMessage.RowData.PropertyRows[i].PropertyValues[0].Value);
                if (messageSubject.Equals(replyTemplateSubject, StringComparison.CurrentCultureIgnoreCase))
                {
                    replyTemplateId = ropQueryRowsResponseOfFAIMessage.RowData.PropertyRows[i].PropertyValues[1].Value;
                }
            }

            byte[] pidTagReplyTemplateIdValue = new byte[replyTemplateId.Length - 2];
            Array.Copy(replyTemplateId, 2, pidTagReplyTemplateIdValue, 0, replyTemplateId.Length - 2);
            #endregion
            #endregion

            #region TestUser1 gets the message entry ID and the Inbox folder's entry ID.
            byte[] messageEntryId = this.OxoruleAdapter.GetMessageEntryId(this.InboxFolderHandle, this.InboxFolderID, replyTemplateMessageHandler, replyTemplateMessageId);
            #endregion

            #region Prepare rules' data
            ReplyActionDataOfExtendedRule ruleActionData = new ReplyActionDataOfExtendedRule();
            ruleActionData.MessageEIDSize = 0x46;
            ruleActionData.ReplyTemplateMessageEID = messageEntryId;
            ruleActionData.ReplyTemplateGUID = guidByte;
            #endregion

            #region TestUser1 creates an FAI message for the OP_OOF_REPLY extended rule.
            RopCreateMessageResponse ropCreateMessageResponse;
            uint extendedRuleMessageHandle1 = this.OxoruleAdapter.RopCreateMessage(this.InboxFolderHandle, this.InboxFolderID, Convert.ToByte(true), out ropCreateMessageResponse);
            Site.Assert.AreEqual<uint>(0, ropCreateMessageResponse.ReturnValue, "Creating the FAI message should succeed.");

            NamedPropertyInfo namedPropertyInfo1 = new NamedPropertyInfo
            {
                NoOfNamedProps = 0
            };
            TaggedPropertyValue[] extendedRuleProperties1 = AdapterHelper.GenerateExtendedRuleTestData(ruleProperties.Name, 0, (uint)RuleState.ST_ENABLED, Constants.PidTagRuleProvider, ActionType.OP_OOF_REPLY, ruleActionData, ruleProperties.ConditionSubjectName, namedPropertyInfo1);

            // Set properties for extended rule FAI message.
            RopSetPropertiesResponse ropSetPropertiesResponse = this.OxoruleAdapter.RopSetProperties(extendedRuleMessageHandle1, extendedRuleProperties1);
            Site.Assert.AreEqual<uint>(0, ropSetPropertiesResponse.ReturnValue, "Setting property for Extended rule FAI message should succeed.");

            // Save changes of message.
            RopSaveChangesMessageResponse ropSaveChangesMessagResponse = this.OxoruleAdapter.RopSaveChangesMessage(extendedRuleMessageHandle1);
            Site.Assert.AreEqual(0, (int)ropSaveChangesMessagResponse.ReturnValue, "Saving Extend rule message should succeed.");
            #endregion

            #region TestUser1 gets the OP_OOF_REPLY extended rule.
            #region Step1: TestUser1 gets a table of all messages which are placed in the Inbox folder.

            ropGetContentsTableResponseOfFAIMessage = this.OxoruleAdapter.RopGetContentsTable(this.InboxFolderHandle, ContentTableFlag.Associated, out contentsTableHandleOfFAIMessage);
            Site.Assert.AreEqual<uint>(0, ropGetContentsTableResponseOfFAIMessage.ReturnValue, "Getting DAF contents table should succeed");
            #endregion

            #region Step2: TestUser1 sets the interested columns of the message table in the Inbox folder.

            // Here are 6 interested columns listed as below.
            propertyTagOfFAIMessage = new PropertyTag[6];
            PropertyTag pidTagRuleMessageNameTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagRuleMessageName,
                PropertyType = (ushort)PropertyType.PtypString
            };
            propertyTagOfFAIMessage[0] = pidTagRuleMessageNameTag;
            PropertyTag pidTagMessageClassTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagMessageClass,
                PropertyType = (ushort)PropertyType.PtypString
            };
            propertyTagOfFAIMessage[1] = pidTagMessageClassTag;
            PropertyTag pidTagRuleMessageStatePropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagRuleMessageState,
                PropertyType = (ushort)PropertyType.PtypInteger32
            };
            propertyTagOfFAIMessage[2] = pidTagRuleMessageStatePropertyTag;
            PropertyTag pidTagRuleMessageProviderPropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagRuleMessageProvider,
                PropertyType = (ushort)PropertyType.PtypString
            };
            propertyTagOfFAIMessage[3] = pidTagRuleMessageProviderPropertyTag;
            PropertyTag pidTagExtendedRuleMessageActionsPropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagExtendedRuleMessageActions,
                PropertyType = (ushort)PropertyType.PtypBinary
            };
            propertyTagOfFAIMessage[4] = pidTagExtendedRuleMessageActionsPropertyTag;
            PropertyTag pidTagExtendedRuleMessageConditionPropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagExtendedRuleMessageCondition,
                PropertyType = (ushort)PropertyType.PtypBinary
            };
            propertyTagOfFAIMessage[5] = pidTagExtendedRuleMessageConditionPropertyTag;

            // Query rows which include the property values of the interested columns. 
            ropQueryRowsResponseOfFAIMessage = this.OxoruleAdapter.QueryPropertiesInTable(contentsTableHandleOfFAIMessage, propertyTagOfFAIMessage);
            Site.Assert.AreEqual<uint>(0, ropQueryRowsResponseOfFAIMessage.ReturnValue, "Querying Rows Response of FAI Message should succeed, the actual returned value is {0}", ropQueryRowsResponseOfFAIMessage.ReturnValue);
            ExtendedRuleActions extendedRuleAction = new ExtendedRuleActions();
            ReplyActionDataOfExtendedRule replyActionData = new ReplyActionDataOfExtendedRule();
            for (int i = 0; i < ropQueryRowsResponseOfFAIMessage.RowCount; i++)
            {
                // Since the PidTagMessageClass property of Extended rule MUST have a value of "IPM.ExtendedRule.Message", use PidTagMessageClass property to get the extended rule data.
                System.Text.UnicodeEncoding converter = new UnicodeEncoding();
                string messageClass = converter.GetString(ropQueryRowsResponseOfFAIMessage.RowData.PropertyRows.ToArray()[i].PropertyValues[1].Value);
                if (messageClass == "IPM.ExtendedRule.Message" + "\0")
                {
                    byte[] extendedRuleMessageActionBinary = ropQueryRowsResponseOfFAIMessage.RowData.PropertyRows[i].PropertyValues[4].Value;
                    byte[] extendedRuleMessageActionBuffer = new byte[extendedRuleMessageActionBinary.Length - 2];

                    // Remove the two length bytes to get the extended rule action data.
                    Array.Copy(extendedRuleMessageActionBinary, 2, extendedRuleMessageActionBuffer, 0, extendedRuleMessageActionBinary.Length - 2);
                    extendedRuleAction.Deserialize(extendedRuleMessageActionBuffer);
                    replyActionData.Deserialize(extendedRuleAction.RuleActionBuffer.Actions[0].ActionDataValue.Serialize());
                    break;
                }
            }
            #endregion

            #region Capture Code

            // Add the debug information.
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R998: the Message EntryID is {0}, and the ReplyTemplateMessageEID in the action data is {1}", messageEntryId, replyActionData.ReplyTemplateMessageEID);

            bool isVerifiedR998 = Common.CompareByteArray(ruleActionData.ReplyTemplateMessageEID, replyActionData.ReplyTemplateMessageEID);

            // Verify MS-OXORULE requirement: MS-OXORULE_R998.
            Site.CaptureRequirementIfIsTrue(
                isVerifiedR998,
                998,
                @"[OP_REPLY and OP_OOF_REPLY ActionData Structure] [Buffer Format for Extended Rules] ReplyTemplateMessageEID (70 bytes): A Message EntryID structure, as specified in [MS-OXCDATA] section 2.2.4.2, that contains the entry ID of the reply template.");

            // Add the debug information.
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R1000");

            bool isVerifiedR1000 = Common.CompareByteArray(ruleActionData.ReplyTemplateGUID, replyActionData.ReplyTemplateGUID);

            // Verify MS-OXORULE requirement: MS-OXORULE_R1000.
            // IF the value of the ReplyTemplateGUID field in OP_OOF_REPLY action data is equal to the value of the PidTagReplyTemplateId property that is set on the reply template, R1000 can be verified.
            Site.CaptureRequirementIfIsTrue(
                isVerifiedR1000,
                1000,
                @"[OP_REPLY and OP_OOF_REPLY ActionData Structure] [Buffer Format for Extended Rules] ReplyTemplateGUID (16 bytes): A GUID that is generated by the client in the process of creating a reply template.");

            // Add the debug information.
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R1002: the value of PidTagReplyTemplateId property is {0}, and the ReplyTemplateGUID in the action data is {1}", pidTagReplyTemplateIdValue, replyActionData.ReplyTemplateGUID);

            bool isVerifiedR1002 = isVerifiedR998 && isVerifiedR1000 && replyActionData.MessageEIDSize == ruleActionData.MessageEIDSize;

            // Verify MS-OXORULE requirement: MS-OXORULE_R1002.
            Site.CaptureRequirementIfIsTrue(
                isVerifiedR1002,
                1002,
                @"[OP_REPLY and OP_OOF_REPLY ActionData Structure] [Buffer Format for Extended Rules] The value of the ReplyTemplateGUID field in OP_OOF_REPLY action data is equal to the value of the PidTagReplyTemplateId property that is set on the reply template.");
            #endregion
            #endregion
        }
        public void MSOXORULE_S02_TC16_ServerExecuteExtendedRule_Action_OP_COPY()
        {
            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_COPY", out createFolderResponse);
            ulong newFolderId = createFolderResponse.FolderId;
            Site.Assert.AreEqual<uint>(0, createFolderResponse.ReturnValue, "Creating folder operation should succeed.");
            #endregion

            #region Prepare rules' data
            MoveCopyActionDataOfExtendedRule copyActionData = new MoveCopyActionDataOfExtendedRule();

            // Get the created folder1 entry id.
            byte[] folder1EId = this.OxoruleAdapter.GetFolderEntryId(StoreObjectType.Mailbox, newFolderHandle, newFolderId);

            // Get the store object's entry id
            byte[] storeEId = this.GetStoreObjectEntryID(StoreObjectType.Mailbox, this.Server, this.User1ESSDN);
            copyActionData.FolderEID = folder1EId;
            copyActionData.StoreEID = storeEId;
            copyActionData.FolderEIDSize = (uint)folder1EId.Length;
            copyActionData.StoreEIDSize = (uint)storeEId.Length;
            #endregion

            #region TestUser1 creates an FAI message for the extended rule.
            RopCreateMessageResponse ropCreateMessageResponse;
            uint extendedRuleMessageHandle1 = this.OxoruleAdapter.RopCreateMessage(this.InboxFolderHandle, this.InboxFolderID, Convert.ToByte(true), out ropCreateMessageResponse);
            Site.Assert.AreEqual<uint>(0, ropCreateMessageResponse.ReturnValue, "Creating the FAI message should succeed.");

            NamedPropertyInfo namedPropertyInfo1 = new NamedPropertyInfo
            {
                NoOfNamedProps = 0
            };
            TaggedPropertyValue[] extendedRuleProperties1 = AdapterHelper.GenerateExtendedRuleTestData(ruleProperties.Name, 0, (uint)RuleState.ST_ENABLED, Constants.PidTagRuleProvider, ActionType.OP_COPY, copyActionData, ruleProperties.ConditionSubjectName, namedPropertyInfo1);

            // Set properties for extended rule FAI message.
            RopSetPropertiesResponse ropSetPropertiesResponse = this.OxoruleAdapter.RopSetProperties(extendedRuleMessageHandle1, extendedRuleProperties1);
            Site.Assert.AreEqual<uint>(0, ropSetPropertiesResponse.ReturnValue, "Setting property for Extended rule FAI message should succeed.");

            // Save changes of message.
            RopSaveChangesMessageResponse ropSaveChangesMessagResponse = this.OxoruleAdapter.RopSaveChangesMessage(extendedRuleMessageHandle1);
            Site.Assert.AreEqual(0, (int)ropSaveChangesMessagResponse.ReturnValue, "Saving Extend rule message should succeed.");
            #endregion

            #region TestUser1 gets the extended rule.
            #region Step1: TestUser1 gets a table of all messages which are placed in the Inbox folder.
            uint contentsTableHandleOfFAIMessage;
            RopGetContentsTableResponse ropGetContentsTableResponseOfFAIMessage = this.OxoruleAdapter.RopGetContentsTable(this.InboxFolderHandle, ContentTableFlag.Associated, out contentsTableHandleOfFAIMessage);
            Site.Assert.AreEqual<uint>(0, ropGetContentsTableResponseOfFAIMessage.ReturnValue, "Getting contents table should succeed, the actual returned value is {0}", ropGetContentsTableResponseOfFAIMessage.ReturnValue);
            #endregion

            #region Step2: TestUser1 sets the interested columns of the message table in the Inbox folder.

            // Here are 6 interested columns listed as below.
            PropertyTag[] propertyTagOfFAIMessage = new PropertyTag[6];
            PropertyTag pidTagRuleMessageNameTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagRuleMessageName,
                PropertyType = (ushort)PropertyType.PtypString
            };
            propertyTagOfFAIMessage[0] = pidTagRuleMessageNameTag;
            PropertyTag pidTagMessageClassTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagMessageClass,
                PropertyType = (ushort)PropertyType.PtypString
            };
            propertyTagOfFAIMessage[1] = pidTagMessageClassTag;
            PropertyTag pidTagRuleMessageStatePropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagRuleMessageState,
                PropertyType = (ushort)PropertyType.PtypInteger32
            };
            propertyTagOfFAIMessage[2] = pidTagRuleMessageStatePropertyTag;
            PropertyTag pidTagRuleMessageProviderPropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagRuleMessageProvider,
                PropertyType = (ushort)PropertyType.PtypString
            };
            propertyTagOfFAIMessage[3] = pidTagRuleMessageProviderPropertyTag;
            PropertyTag pidTagExtendedRuleMessageActionsPropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagExtendedRuleMessageActions,
                PropertyType = (ushort)PropertyType.PtypBinary
            };
            propertyTagOfFAIMessage[4] = pidTagExtendedRuleMessageActionsPropertyTag;
            PropertyTag pidTagExtendedRuleMessageConditionPropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagExtendedRuleMessageCondition,
                PropertyType = (ushort)PropertyType.PtypBinary
            };
            propertyTagOfFAIMessage[5] = pidTagExtendedRuleMessageConditionPropertyTag;

            // Query rows which include the property values of the interested columns.
            RopQueryRowsResponse ropQueryRowsResponseOfFAIMessage = this.OxoruleAdapter.QueryPropertiesInTable(contentsTableHandleOfFAIMessage, propertyTagOfFAIMessage);
            Site.Assert.AreEqual<uint>(0, ropQueryRowsResponseOfFAIMessage.ReturnValue, "Querying Rows Response of FAI Message should succeed, the actual returned value is {0}", ropQueryRowsResponseOfFAIMessage.ReturnValue);
            MoveCopyActionDataOfExtendedRule copyActionDataOfQueryRowsResponse = new MoveCopyActionDataOfExtendedRule();
            for (int i = 0; i < ropQueryRowsResponseOfFAIMessage.RowCount; i++)
            {
                System.Text.UnicodeEncoding converter = new UnicodeEncoding();
                string messageName = converter.GetString(ropQueryRowsResponseOfFAIMessage.RowData.PropertyRows.ToArray()[i].PropertyValues[0].Value);
                if (messageName == ruleProperties.Name + "\0")
                {
                    byte[] extendedRuleMessageActionBinary = ropQueryRowsResponseOfFAIMessage.RowData.PropertyRows.ToArray()[i].PropertyValues[4].Value;
                    byte[] extendedRuleMessageActionBuffer = new byte[extendedRuleMessageActionBinary.Length - 2];
                    Array.Copy(extendedRuleMessageActionBinary, 2, extendedRuleMessageActionBuffer, 0, extendedRuleMessageActionBinary.Length - 2);
                    ExtendedRuleActions extendedRuleActions = new ExtendedRuleActions();
                    extendedRuleActions.Deserialize(extendedRuleMessageActionBuffer);
                    copyActionDataOfQueryRowsResponse.Deserialize(extendedRuleActions.RuleActionBuffer.Actions[0].ActionDataValue.Serialize());
                }
            }

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R977");

            bool isVerifiedR977 = Common.CompareByteArray(folder1EId, copyActionDataOfQueryRowsResponse.FolderEID);

            // Verify MS-OXORULE requirement: MS-OXORULE_R977
            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR977,
                977,
                @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Extended Rules] FolderEID (variable): A Folder EntryID structure, as specified in [MS-OXCDATA] section 2.2.4.1, [In OP_COPY action data] identifies the destination folder.");
            #endregion
            #endregion

            #region TestUser2 delivers a message to TestUser1 to trigger the rule.

            // TestUser2 deliver a message to trigger these rules.
            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;

            uint rowCount = 0;
            RopQueryRowsResponse getInboxMailMessageContent = this.GetExpectedMessage(this.InboxFolderHandle, ref inboxFolderContentsTableHandle, propertyTagList, ref rowCount, 1, mailSubject);
            uint newFolder1ContentsTableHandle = 0;
            rowCount = 0;
            RopQueryRowsResponse getNewFolder1MailMessageContent = this.GetExpectedMessage(newFolderHandle, ref newFolder1ContentsTableHandle, propertyTagList, ref rowCount, 1, mailSubject);
            Site.Assert.AreEqual<uint>(0, getNewFolder1MailMessageContent.ReturnValue, "getNewFolder1MailMessageContent should succeed.");

            #region Capture code

            this.VerifyActionTypeOP_COPY(mailSubject, getNewFolder1MailMessageContent, getInboxMailMessageContent, ruleProperties);

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R969, since the destination folder is created in the user's mailbox, try to verify the message was copy to the folder");

            // Verify MS-OXORULE requirement: MS-OXORULE_R969
            bool isVerifiedR969 = getInboxMailMessageContent.RowCount != 0 && getNewFolder1MailMessageContent.RowCount != 0;

            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR969,
                969,
                @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Extended Rules] The destination folder for a Copy action in an extended rule MUST be in the user's mailbox.");
            #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
        }
        /// <summary>
        /// This method help to convert the property value, which is of variable bytes, to ExtendedRuleActions structure.
        /// </summary>
        /// <param name="byteArray">The byte array to be converted.</param>
        /// <returns>Return the ExtendedRuleActions structure.</returns>
        public static ExtendedRuleActions PropertyValueConvertToExtendedRuleActions(byte[] byteArray)
        {
            // The first 2 bytes of byteArray only indicates the total number of subsequent bytes,
            // byteArrayTobeConvert is the actual bytes used to convert to the ExtendedRuleActions structure,
            // which should not include the first 2 bytes of byteArray.
            byte[] byteArrayTobeConvert = new byte[byteArray.Length - 2];
            Array.Copy(byteArray, 2, byteArrayTobeConvert, 0, byteArray.Length - 2);

            // De-serialize the byte array into the ExtendedRuleActions structure.
            ExtendedRuleActions extendedRuleActions = new ExtendedRuleActions();
            extendedRuleActions.Deserialize(byteArrayTobeConvert);

            return extendedRuleActions;
        }
        /// <summary>
        /// Generate test data for creating extended rule.
        /// </summary>
        /// <param name="rulename">The rule name.</param>
        /// <param name="ruleSequence">The rule sequence.</param>
        /// <param name="ruleState">The rule state.</param>
        /// <param name="provider">The rule provider.</param>
        /// <param name="actionType">The rule action Type.</param>
        /// <param name="actionData">The rule action data.</param>
        /// <param name="contentRestrictSubjectName">The subject name of the rule content restriction.</param>
        /// <param name="namedPropertyInfo">The namedPropertyInfo that needed for construct the rule data.</param>
        /// <returns>An array of TaggedPropertyValue of an extended rule.</returns>
        public static TaggedPropertyValue[] GenerateExtendedRuleTestData(string rulename, int ruleSequence, uint ruleState, string provider, ActionType actionType, IActionData actionData, string contentRestrictSubjectName, NamedPropertyInfo namedPropertyInfo)
        {
            List<TaggedPropertyValue> propList = new List<TaggedPropertyValue>();
            TaggedPropertyValue pidTagRuleMessageName = new TaggedPropertyValue();
            PropertyTag pidTagRuleMessageNameTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagRuleMessageName,
                PropertyType = (ushort)PropertyType.PtypString
            };
            pidTagRuleMessageName.PropertyTag = pidTagRuleMessageNameTag;
            pidTagRuleMessageName.Value = Encoding.Unicode.GetBytes(rulename + "\0");
            propList.Add(pidTagRuleMessageName);

            TaggedPropertyValue pidTagMessageClass = new TaggedPropertyValue();
            PropertyTag pidTagMessageClassTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagMessageClass,
                PropertyType = (ushort)PropertyType.PtypString
            };
            pidTagMessageClass.PropertyTag = pidTagMessageClassTag;
            pidTagMessageClass.Value = Encoding.Unicode.GetBytes(Constants.ExtendedRuleMessageClass + "\0");
            propList.Add(pidTagMessageClass);

            TaggedPropertyValue pidTagRuleMessageSequence = new TaggedPropertyValue();
            PropertyTag pidTagRuleMessageSequencePropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagRuleMessageSequence,
                PropertyType = (ushort)PropertyType.PtypInteger32
            };
            pidTagRuleMessageSequence.PropertyTag = pidTagRuleMessageSequencePropertyTag;
            pidTagRuleMessageSequence.Value = BitConverter.GetBytes(ruleSequence);
            propList.Add(pidTagRuleMessageSequence);

            TaggedPropertyValue pidTagRuleMessageState = new TaggedPropertyValue();
            PropertyTag pidTagRuleMessageStatePropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagRuleMessageState,
                PropertyType = (ushort)PropertyType.PtypInteger32
            };
            pidTagRuleMessageState.PropertyTag = pidTagRuleMessageStatePropertyTag;
            pidTagRuleMessageState.Value = BitConverter.GetBytes(ruleState);
            propList.Add(pidTagRuleMessageState);

            TaggedPropertyValue pidTagRuleMessageLevel = new TaggedPropertyValue();
            PropertyTag pidTagRuleMessageLevelPropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagRuleMessageLevel,
                PropertyType = (ushort)PropertyType.PtypInteger32
            };
            pidTagRuleMessageLevel.PropertyTag = pidTagRuleMessageLevelPropertyTag;
            pidTagRuleMessageLevel.Value = BitConverter.GetBytes(Constants.ExtendedRuleMessageLevel);
            propList.Add(pidTagRuleMessageLevel);

            TaggedPropertyValue pidTagRuleMessageProvider = new TaggedPropertyValue();
            PropertyTag pidTagRuleMessageProviderPropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagRuleMessageProvider,
                PropertyType = (ushort)PropertyType.PtypString
            };
            pidTagRuleMessageProvider.PropertyTag = pidTagRuleMessageProviderPropertyTag;
            pidTagRuleMessageProvider.Value = Encoding.Unicode.GetBytes(provider + "\0");
            propList.Add(pidTagRuleMessageProvider);

            ExtendedRuleActions extendedRuleActions = new ExtendedRuleActions
            {
                NamedPropertyInformation = namedPropertyInfo
            };

            extendedRuleActions.RuleVersion = Constants.ExtendedRuleVersion;
            extendedRuleActions.RuleActionBuffer = GetRuleAction(actionType, CountByte.FourBytesCount, actionData, Constants.CommonActionFlavor, Constants.RuleActionFlags);

            TaggedPropertyValue pidTagExtendedRuleMessageActions = new TaggedPropertyValue();
            PropertyTag pidTagExtendedRuleMessageActionsPropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagExtendedRuleMessageActions,
                PropertyType = (ushort)PropertyType.PtypBinary
            };
            pidTagExtendedRuleMessageActions.PropertyTag = pidTagExtendedRuleMessageActionsPropertyTag;
            pidTagExtendedRuleMessageActions.Value = Common.AddInt16LengthBeforeBinaryArray(extendedRuleActions.Serialize());
            propList.Add(pidTagExtendedRuleMessageActions);

            TaggedPropertyValue pidTagExtendedRuleMessageCondition = new TaggedPropertyValue();
            PropertyTag pidTagExtendedRuleMessageConditionPropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagExtendedRuleMessageCondition,
                PropertyType = (ushort)PropertyType.PtypBinary
            };
            pidTagExtendedRuleMessageCondition.PropertyTag = pidTagExtendedRuleMessageConditionPropertyTag;

            TaggedPropertyValue taggedProperty = new TaggedPropertyValue();
            PropertyTag taggedPropertyPropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagSubject,
                PropertyType = (ushort)PropertyType.PtypString
            };
            taggedProperty.PropertyTag = taggedPropertyPropertyTag;
            taggedProperty.Value = Encoding.Unicode.GetBytes(contentRestrictSubjectName + "\0");
            ContentRestriction contentRestriction = new ContentRestriction
            {
                FuzzyLevelLow = ContentRestriction.FuzzyLevelLowValue.FL_SUBSTRING,
                FuzzyLevelHigh = ContentRestriction.FuzzyLevelHighValue.FL_IGNORECASE,
                PropertyTag = taggedProperty.PropertyTag,
                TaggedValue = taggedProperty
            };

            ExtendedRuleCondition extendedRuleCondition = new ExtendedRuleCondition
            {
                NamedPropertyInformation = namedPropertyInfo,
                RuleRestriction = contentRestriction
            };
            pidTagExtendedRuleMessageCondition.Value = Common.AddInt16LengthBeforeBinaryArray(extendedRuleCondition.Serialize());
            propList.Add(pidTagExtendedRuleMessageCondition);
            return propList.ToArray();
        }
        /// <summary>
        /// Verify ExtendedRuleActions buffer.
        /// </summary>
        /// <param name="extendeRuleActions">ExtendedRuleActions structure to be verified.</param>
        private void VerifyExtendedRuleMessageActions(ExtendedRuleActions extendeRuleActions)
        {
            // Get all of the Named Properties contained in the action buffer.
            PropertyName[] propertyNames = extendeRuleActions.NamedPropertyInformation.NamedProperty;

            // If the propertyNames exists, check whether the names' value contained in this structure are all in Unicode format.
            if (propertyNames != null)
            {
                // isContainNameValue is used to indicate whether exist nameValue in the PropertyName array.
                bool isContainNameValue = false;
                bool isVerifyR192 = true;

                // Check whether every name value contained in the PropertyName structure is in Unicode format.
                for (int i = 0; i < propertyNames.Length; i++)
                {
                    // Get the name value contained in the action buffer.
                    byte[] nameValue = propertyNames[i].Name;
                    if (nameValue != null)
                    {
                        isContainNameValue = true;

                        // If the nameValue cannot be converted to a Unicode string, it means the name value is not in Unicode format.
                        if (Encoding.Unicode.GetString(nameValue) == null)
                        {
                            isVerifyR192 = false;
                            break;
                        }
                    }
                }

                if (isContainNameValue)
                {
                    // Add the debug information.
                    Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R192");

                    // Verify MS-OXORULE requirement: MS-OXORULE_R192.
                    Site.CaptureRequirementIfIsTrue(
                        isVerifyR192,
                        192,
                        @"[In PidTagExtendedRuleMessageActions Property] All string values contained in any part of the RuleAction structure MUST be in Unicode format.");
                }
            }

            // Add the debug information.
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R208.");

            // Verify MS-OXORULE requirement: MS-OXORULE_R208.
            Site.CaptureRequirementIfAreEqual<uint>(
                0x00000001,
                extendeRuleActions.RuleVersion,
                208,
                @"[In PidTagExtendedRuleMessageActions Property] RuleVersion (4 bytes): This document defines version 1, and thus this value MUST be set to 0x00000001.");

            // Verify the requirement related to the NamedPropertyInformation.
            this.VerifyNamedPropertyInformation(extendeRuleActions.NamedPropertyInformation);

            // Verify the requirement related to the RuleAction.
            this.VerifyExtendRuleAction(extendeRuleActions.RuleActionBuffer);

            // Add the debug information.
            // The format of the PidTagExtendedRuleMessageActions property: NamedPropertyInformation, RuleVersion, RuleActionsBuffer has been verified by above capture code, so R194 can be verified directly. 
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R194");

            // Verify MS-OXORULE requirement: MS-OXORULE_R194.
            Site.CaptureRequirement(
                194,
                @"[In PidTagExtendedRuleMessageActions Property] The format of the PidTagExtendedRuleMessageActions property is as follows: NamedPropertyInformation, RuleVersion, RuleActionsBuffer.");
        }
        /// <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;
        }