Deserialize() публичный Метод

Parse method to obtain current structure from byte array
public Deserialize ( byte buffer ) : uint
buffer byte Byte array data.
Результат uint
        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_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_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>
        /// 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>
        /// 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;
        }