Action Data buffer format for ActionType: OP_REPLY, OP_OOF_REPLY
Inheritance: IActionData
        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_TC03_ServerExecuteRule_Action_OP_REPLY_ActionFlavor_NS()
        {
            this.CheckMAPIHTTPTransportSupported();

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

            #region Create a reply template in the TestUser1's Inbox folder.
            ulong replyTemplateMessageId;
            uint replyTemplateMessageHandler;

            TaggedPropertyValue[] replyTemplateProperties;

            // Add recipient information .
            TaggedPropertyValue[] temp = AdapterHelper.GenerateRecipientPropertiesBlock(this.User2Name, this.User2ESSDN);
            replyTemplateProperties = new TaggedPropertyValue[4];
            replyTemplateProperties[0] = new TaggedPropertyValue();
            PropertyTag propertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagBody,
                PropertyType = (ushort)PropertyType.PtypString
            };
            replyTemplateProperties[0].PropertyTag = propertyTag;
            replyTemplateProperties[0].Value = Encoding.Unicode.GetBytes(Constants.ReplyTemplateBody + "\0");
            Array.Copy(temp, 0, replyTemplateProperties, 1, temp.Length - 1);

            string replyTemplateSubject = Common.GenerateResourceName(this.Site, Constants.ReplyTemplateSubject);
            byte[] guidBytes = this.OxoruleAdapter.CreateReplyTemplate(this.InboxFolderHandle, this.InboxFolderID, false, replyTemplateSubject, replyTemplateProperties, out replyTemplateMessageId, out replyTemplateMessageHandler);
            #endregion

            #region TestUser1 adds a reply rule with actionFlavor set to NS(0x00000001).
            ReplyActionData replyActionDataWithFlavor = new ReplyActionData
            {
                ReplyTemplateGUID = new byte[guidBytes.Length]
            };
            Array.Copy(guidBytes, 0, replyActionDataWithFlavor.ReplyTemplateGUID, 0, guidBytes.Length);

            replyActionDataWithFlavor.ReplyTemplateFID = this.InboxFolderID;
            replyActionDataWithFlavor.ReplyTemplateMID = replyTemplateMessageId;
            uint actionFlavor_NS = (uint)ActionFlavorsReply.NS;

            RuleData ruleForReplyWithFlavor = AdapterHelper.GenerateValidRuleDataWithFlavor(ActionType.OP_REPLY, 0, RuleState.ST_ENABLED, replyActionDataWithFlavor, actionFlavor_NS, ruleProperties);
            RopModifyRulesResponse ropModifyRulesResponse = this.OxoruleAdapter.RopModifyRules(this.InboxFolderHandle, ModifyRuleFlag.Modify_ReplaceAll, new RuleData[] { ruleForReplyWithFlavor });
            Site.Assert.AreEqual<uint>(0, ropModifyRulesResponse.ReturnValue, "Adding rule with actionFlavor set to NS should succeed.");
            #endregion

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

            // TestUser2 delivers a message to trigger the rules.
            string mailSubject = Common.GenerateResourceName(this.Site, ruleProperties.ConditionSubjectName + "Title");
            this.SUTAdapter.SendMailToRecipient(this.User2Name, this.User2Password, this.User1Name, mailSubject);
            Thread.Sleep(this.WaitForTheRuleToTakeEffect);
            #endregion

            #region TestUser1 gets the message sent by TestUser2.
            uint inboxFolderContentsTableHandle = 0;
            PropertyTag[] propertyTags = new PropertyTag[1];
            propertyTags[0].PropertyId = (ushort)PropertyId.PidTagSubject;
            propertyTags[0].PropertyType = (ushort)PropertyType.PtypString;

            uint rowCount = 0;
            RopQueryRowsResponse getInboxMailMessageContent = this.GetExpectedMessage(this.InboxFolderHandle, ref inboxFolderContentsTableHandle, propertyTags, ref rowCount, 1, mailSubject);
            Site.Assert.AreEqual<uint>(0, getInboxMailMessageContent.ReturnValue, "Getting the message should succeed.");
            #endregion

            #region TestUser2 verifies there is no new message in the Inbox folder.
            // Let TestUser2 log on to the server.
            this.LogonMailbox(TestUser.TestUser2);

            // Specify the message properties to be got.
            PropertyTag[] propertyTagList = new PropertyTag[1];
            propertyTagList[0].PropertyId = (ushort)PropertyId.PidTagSubject;
            propertyTagList[0].PropertyType = (ushort)PropertyType.PtypString;

            uint contentsTableHandle = 0;
            bool doesUnexpectedMessageExist = this.CheckUnexpectedMessageExist(this.InboxFolderHandle, ref contentsTableHandle, propertyTagList, replyTemplateSubject);

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

            // Verify MS-OXORULE requirement: MS-OXORULE_R288.
            // TestUser2 has sent a message to TestUser1. If TestUser2 doesn't get the replied message, this requirement can be verified.
            Site.CaptureRequirementIfIsFalse(
                doesUnexpectedMessageExist,
                288,
                @"[In Action Flavors] NS (Bitmask 0x00000001): [OP_REPLY ActionType] Do not send the message to the message sender.");

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

            // Verify MS-OXORULE requirement: MS-OXORULE_R663
            // The recipients (2) information is added in the reply template when it is created. Since the rule works as expected, this requirement can be captured.
            Site.CaptureRequirement(
                663,
                @"[In Action Flavors] NS (Bitmask 0x00000001): [OP_REPLY ActionType] The reply template MUST contain recipients (2) in this case [if the NS flag is set].");

            #endregion
            #endregion
        }
        public void MSOXORULE_S02_TC04_ServerExecuteRule_Action_OP_REPLY_PidTagAutoResponseSuppress()
        {
            this.CheckMAPIHTTPTransportSupported();

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

            #region Create a reply template in the TestUser1's Inbox folder.
            ulong replyTemplateMessageId;
            uint replyTemplateMessageHandler;
            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");

            string replyTemplateSubject = Common.GenerateResourceName(this.Site, Constants.ReplyTemplateSubject);
            byte[] guidBytes = this.OxoruleAdapter.CreateReplyTemplate(this.InboxFolderHandle, this.InboxFolderID, false, replyTemplateSubject, replyTemplateProperties, out replyTemplateMessageId, out replyTemplateMessageHandler);
            #endregion

            #region TestUser1 adds a reply rule with 0x00000000 action flavor to TestUser1's Inbox folder.
            ReplyActionData replyActionData = new ReplyActionData
            {
                ReplyTemplateGUID = new byte[guidBytes.Length]
            };
            Array.Copy(guidBytes, 0, replyActionData.ReplyTemplateGUID, 0, guidBytes.Length);
            replyActionData.ReplyTemplateFID = this.InboxFolderID;
            replyActionData.ReplyTemplateMID = replyTemplateMessageId;

            RuleData ruleForReply = AdapterHelper.GenerateValidRuleDataWithFlavor(ActionType.OP_REPLY, 0, RuleState.ST_ENABLED, replyActionData, 0x00000000, ruleProperties);
            RopModifyRulesResponse ropModifyRulesResponse = this.OxoruleAdapter.RopModifyRules(this.InboxFolderHandle, ModifyRuleFlag.Modify_ReplaceAll, new RuleData[] { ruleForReply });
            Site.Assert.AreEqual<uint>(0, ropModifyRulesResponse.ReturnValue, "Adding reply rule with actionFlavor set to 0x00000000 should succeed.");
            #endregion

            #region TestUser2 sends a mail to TestUser1 with PidTagAutoResponseSuppress set to 0x00000020.
            // Let TestUser2 log on to the server.
            this.LogonMailbox(TestUser.TestUser2);

            TaggedPropertyValue autoResponseSuppressProperty = new TaggedPropertyValue();
            PropertyTag autoResponseSuppressPropertyPropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagAutoResponseSuppress,
                PropertyType = (ushort)PropertyType.PtypInteger32
            };
            autoResponseSuppressProperty.PropertyTag = autoResponseSuppressPropertyPropertyTag;
            autoResponseSuppressProperty.Value = BitConverter.GetBytes(0x00000020);

            string subject = Common.GenerateResourceName(this.Site, ruleProperties.ConditionSubjectName + "Title");
            this.DeliverMessageToTriggerRule(this.User1Name, this.User1ESSDN, subject, new TaggedPropertyValue[1] { autoResponseSuppressProperty });
            Thread.Sleep(this.WaitForTheRuleToTakeEffect);
            #endregion

            #region TestUser2 verifies the server doesn't send a reply to normal user.
            uint contentsTableHandle = 0;
            int expectedMessageIndex = 0;

            // Specify the message properties to be got.
            PropertyTag[] propertyTagarray = new PropertyTag[1];

            // PidTagSubject
            propertyTagarray[0].PropertyId = (ushort)PropertyId.PidTagSubject;
            propertyTagarray[0].PropertyType = (ushort)PropertyType.PtypString;
            bool doesUnexpectedMessageExist = this.CheckUnexpectedMessageExist(this.InboxFolderHandle, ref contentsTableHandle, propertyTagarray, replyTemplateSubject);

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

            // Verify MS-OXORULE requirement: MS-OXORULE_R526.
            // This test case is designed based on the PidTagAutoResponseSuppress property on the message that has the 0x00000020 bit set.
            // TestUser2 has sent a message to TestUser1. If TestUser2 doesn't get the replied message, this requirement can be verified.
            Site.CaptureRequirementIfIsFalse(
                doesUnexpectedMessageExist,
                526,
                @"[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_REPLY"": The server MUST NOT send a reply if the PidTagAutoResponseSuppress property ([MS-OXOMSG] section 2.2.1.77) on the message that has the 0x00000020 bit set.");

            #endregion

            #region TestUser1 verifies there are messages which are the sent message in the Inbox folder.
            // Let TestUser1 logon to the server
            this.LogonMailbox(TestUser.TestUser1);

            PropertyTag[] propertyTags = new PropertyTag[1];
            propertyTags[0].PropertyId = (ushort)PropertyId.PidTagSubject;
            propertyTags[0].PropertyType = (ushort)PropertyType.PtypString;

            expectedMessageIndex = 0;
            RopQueryRowsResponse mailMessageContentInUser1 = this.GetExpectedMessage(this.InboxFolderHandle, ref contentsTableHandle, propertyTags, ref expectedMessageIndex, subject);
            Site.Assert.AreEqual<uint>(0, mailMessageContentInUser1.ReturnValue, "Getting mail message operation should succeed.");
            #endregion
        }
        public void MSOXORULE_S02_TC02_ServerExecuteRule_Action_OP_REPLY()
        {
            this.CheckMAPIHTTPTransportSupported();

            #region Prepare value for ruleProperties variable
            RuleProperties ruleProperties = AdapterHelper.GenerateRuleProperties(this.Site, Constants.RuleNameReply);
            #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[] guidBytes = this.OxoruleAdapter.CreateReplyTemplate(this.InboxFolderHandle, this.InboxFolderID, false, replyTemplateSubject, replyTemplateProperties, out replyTemplateMessageId, out replyTemplateMessageHandler);
            #endregion

            #region TestUser1 adds a reply rule with 0x00000000 action flavor to TestUser1's Inbox folder.
            ReplyActionData replyActionData = new ReplyActionData
            {
                ReplyTemplateGUID = new byte[guidBytes.Length]
            };
            Array.Copy(guidBytes, 0, replyActionData.ReplyTemplateGUID, 0, guidBytes.Length);

            replyActionData.ReplyTemplateFID = this.InboxFolderID;
            replyActionData.ReplyTemplateMID = replyTemplateMessageId;

            RuleData ruleForReply = AdapterHelper.GenerateValidRuleDataWithFlavor(ActionType.OP_REPLY, 0, RuleState.ST_ENABLED, replyActionData, 0x00000000, ruleProperties);
            RopModifyRulesResponse ropModifyRulesResponse = this.OxoruleAdapter.RopModifyRules(this.InboxFolderHandle, ModifyRuleFlag.Modify_ReplaceAll, new RuleData[] { ruleForReply });
            Site.Assert.AreEqual<uint>(0, ropModifyRulesResponse.ReturnValue, "Adding rule with actionFlavor set to 0x00000000 should succeed.");
            #endregion

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

            // 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);
            Thread.Sleep(this.WaitForTheRuleToTakeEffect);
            #endregion

            #region TestUser1 verifies there are messages in the specific folder then get the sentRepresentingEmailAddress.
            // Specify the message properties to be got.
            PropertyTag[] propertyTagList = new PropertyTag[4];
            propertyTagList[0].PropertyId = (ushort)PropertyId.PidTagSubject;
            propertyTagList[0].PropertyType = (ushort)PropertyType.PtypString;
            propertyTagList[1].PropertyId = (ushort)PropertyId.PidTagBody;
            propertyTagList[1].PropertyType = (ushort)PropertyType.PtypString;
            propertyTagList[2].PropertyId = (ushort)PropertyId.PidTagSentRepresentingEmailAddress;
            propertyTagList[2].PropertyType = (ushort)PropertyType.PtypString;
            propertyTagList[3].PropertyId = (ushort)PropertyId.PidTagHasDeferredActionMessages;
            propertyTagList[3].PropertyType = (ushort)PropertyType.PtypBoolean;

            uint contentTableHandler = 0;
            int expectedMessageIndex = 0;
            RopQueryRowsResponse getNormalMailMessageContentOnFlavorRule = this.GetExpectedMessage(this.InboxFolderHandle, ref contentTableHandler, propertyTagList, ref expectedMessageIndex, mailSubject);

            string sentRepresentingEmailAddress = AdapterHelper.PropertyValueConvertToString(getNormalMailMessageContentOnFlavorRule.RowData.PropertyRows[expectedMessageIndex].PropertyValues[2].Value);

            // Get the value of PidTagHasDeferredActionMessages.
            byte[] pidTagHasDeferredActionMessagesOfMessageInInboxFolder = getNormalMailMessageContentOnFlavorRule.RowData.PropertyRows[expectedMessageIndex].PropertyValues[3].Value;

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

            // Verify MS-OXORULE requirement: MS-OXORULE_R886.
            // If a rule has no DAM, its pidTagHasDeferredActionMessages property is false or not existing.
            // So if check whether this property exists and its value is false (0x00) or it does not exist (the value is 0x8004010f), it means the rule has no DAM.
            bool isVerifyR886 = Common.CompareByteArray(pidTagHasDeferredActionMessagesOfMessageInInboxFolder, new byte[] { 0x00 }) ||
                             Common.CompareByteArray(pidTagHasDeferredActionMessagesOfMessageInInboxFolder, new byte[] { 0x0f, 0x01, 0x04, 0x80 });

            Site.CaptureRequirementIfIsTrue(
                isVerifyR886,
                886,
                @"[In PidTagHasDeferredActionMessages Property] This property MUST be set to ""false"" if a message has no associated DAM.");
            #endregion

            #region TestUser2 verifies there are reply messages in the specific folder.
            // Let TestUser2 log on to the server.
            this.LogonMailbox(TestUser.TestUser2);

            PropertyTag[] propertyTagList1 = new PropertyTag[3];
            propertyTagList1[0].PropertyId = (ushort)PropertyId.PidTagSubject;
            propertyTagList1[0].PropertyType = (ushort)PropertyType.PtypString;
            propertyTagList1[1].PropertyId = (ushort)PropertyId.PidTagBody;
            propertyTagList1[1].PropertyType = (ushort)PropertyType.PtypString;
            propertyTagList1[2].PropertyId = (ushort)PropertyId.PidTagReceivedByEmailAddress;
            propertyTagList1[2].PropertyType = (ushort)PropertyType.PtypString;

            expectedMessageIndex = 0;
            getNormalMailMessageContentOnFlavorRule = this.GetExpectedMessage(this.InboxFolderHandle, ref contentTableHandler, propertyTagList1, ref expectedMessageIndex, replyTemplateSubject);

            #region Capture Code
            // Subject, bodyText and originalMessageSender are the properties set by the server on the replied message.
            string subject = AdapterHelper.PropertyValueConvertToString(getNormalMailMessageContentOnFlavorRule.RowData.PropertyRows[expectedMessageIndex].PropertyValues[0].Value);
            string bodyText = AdapterHelper.PropertyValueConvertToString(getNormalMailMessageContentOnFlavorRule.RowData.PropertyRows[expectedMessageIndex].PropertyValues[1].Value);
            string receivedByEmailAddress = AdapterHelper.PropertyValueConvertToString(getNormalMailMessageContentOnFlavorRule.RowData.PropertyRows[expectedMessageIndex].PropertyValues[2].Value);

            // Add the debug information.
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R525: the actual value of property PidTagSubject and PidTagReceivedByEmailAddress separately is {0}, {1}", subject, receivedByEmailAddress.ToUpperInvariant());

            // Verify MS-OXORULE requirement: MS-OXORULE_R525.
            // Subject is the property from the reply template, ReceivedByEmailAddress is the property from the original message's SentRepresentingEmailAddress property, message body is the text in the reply template.
            // The message class property is set to IPM.Note in sutcontrolAdapter when being sent.
            bool isVerifyR525 = subject == replyTemplateSubject && receivedByEmailAddress.ToUpperInvariant() == sentRepresentingEmailAddress.ToUpperInvariant() && bodyText.ToUpperInvariant() == Constants.ReplyTemplateBody.ToUpperInvariant();

            Site.CaptureRequirementIfIsTrue(
                isVerifyR525,
                525,
                @"[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_REPLY"": The server MUST use properties from the reply template and from the original message to create a reply to the message and then send the reply.");

            // Add the debug information.
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R253: the actual value of the PidTagSubject is {0}, and the name of the template is {1}", subject, replyTemplateSubject);

            // Verify MS-OXORULE requirement: MS-OXORULE_R253.
            // Subject is the property from the reply template, and the name of the template is replyTemplateSubject,
            // if they are same with each other this requirement can be verified.
            bool isVerifyR253 = subject == replyTemplateSubject;

            Site.CaptureRequirementIfIsTrue(
                isVerifyR253,
                253,
                @"[In ActionBlock Structure] The meaning of action type OP_REPLY: Replies to the message.");

            // Add the debug information.
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R952: the actual value of the PidTagSubject is {0}, and the name of the template is {1}", subject, replyTemplateSubject);
            bool isVerifiedR952 = subject == replyTemplateSubject && bodyText.ToUpperInvariant() == Constants.ReplyTemplateBody.ToUpperInvariant();

            // Verify MS-OXORULE requirement: MS-OXORULE_R952.
            // The ActionFlavor is set to zero in the OP_REPLY rule, so if the messages template is the same with the reply template, means this reply is not use server-defined text in the reply message, and it's a standard reply. 
            Site.CaptureRequirementIfIsTrue(
                isVerifiedR952,
                952,
                @"[In Action Flavors] [If the ActionType field value is ""OP_REPLY"", the ActionFlavor field MUST have one of the values specified in the following table [XXXXXX (ST) (NS) XXXXXXXXXXXXXXXXXXXXXXXX] or zero (0x00000000)] A value of zero (0x00000000) indicates standard reply behavior, as specified in section 3.1.4.2.5).");
            #endregion
            #endregion
        }
        public void MSOXORULE_S02_TC20_ServerExecuteRule_Action_OP_REPLY_AutoGeneratedMsg()
        {
            this.CheckMAPIHTTPTransportSupported();
            Site.Assume.IsTrue(Common.IsRequirementEnabled(5281, this.Site), "This test case only runs when implementation does not avoid sending replies to automatically generated messages to avoid generating endless autoreply loops for \"OP_REPLY\"");

            #region Prepare value for ruleProperties variable
            RuleProperties ruleProperties = AdapterHelper.GenerateRuleProperties(this.Site, Constants.RuleNameReply);
            #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[] guidBytes = this.OxoruleAdapter.CreateReplyTemplate(this.InboxFolderHandle, this.InboxFolderID, false, replyTemplateSubject, replyTemplateProperties, out replyTemplateMessageId, out replyTemplateMessageHandler);
            #endregion

            #region TestUser1 adds a reply rule to TestUser1's Inbox folder.
            ReplyActionData replyActionData = new ReplyActionData
            {
                ReplyTemplateGUID = new byte[guidBytes.Length]
            };
            Array.Copy(guidBytes, 0, replyActionData.ReplyTemplateGUID, 0, guidBytes.Length);

            replyActionData.ReplyTemplateFID = this.InboxFolderID;
            replyActionData.ReplyTemplateMID = replyTemplateMessageId;

            RuleData ruleForReply = AdapterHelper.GenerateValidRuleDataWithFlavor(ActionType.OP_REPLY, 0, RuleState.ST_ENABLED, replyActionData, 0x00000000, ruleProperties);
            RopModifyRulesResponse ropModifyRulesResponse = this.OxoruleAdapter.RopModifyRules(this.InboxFolderHandle, ModifyRuleFlag.Modify_ReplaceAll, new RuleData[] { ruleForReply });
            Site.Assert.AreEqual<uint>(0, ropModifyRulesResponse.ReturnValue, "Adding rule with actionFlavor set to 0x00000000 should succeed.");
            #endregion

            #region TestUser2 sends a mail with PidTagAutoForwarded setting to true to the TestUser1 to trigger this rule.
            // Sleep enough time to wait for the rule to take effect.
            Thread.Sleep(this.WaitForTheRuleToTakeEffect);

            // Let TestUser2 log on to the server
            this.LogonMailbox(TestUser.TestUser2);

            TaggedPropertyValue autoForwarded = new TaggedPropertyValue();
            PropertyTag autoForwardedTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagAutoForwarded,
                PropertyType = (ushort)PropertyType.PtypBoolean
            };
            autoForwarded.PropertyTag = autoForwardedTag;
            autoForwarded.Value = BitConverter.GetBytes(true);
            string subject = Common.GenerateResourceName(this.Site, ruleProperties.ConditionSubjectName);
            this.DeliverMessageToTriggerRule(this.User1Name, this.User1ESSDN, subject, new TaggedPropertyValue[1] { autoForwarded });

            // Sleep enough time to wait for the rule to be executed on the delivered message.
            Thread.Sleep(this.WaitForTheRuleToTakeEffect);
            #endregion

            #region TestUser2 verifies there are reply messages in the specific folder.
            PropertyTag[] propertyTagList1 = new PropertyTag[3];
            propertyTagList1[0].PropertyId = (ushort)PropertyId.PidTagSubject;
            propertyTagList1[0].PropertyType = (ushort)PropertyType.PtypString;
            propertyTagList1[1].PropertyId = (ushort)PropertyId.PidTagBody;
            propertyTagList1[1].PropertyType = (ushort)PropertyType.PtypString;
            propertyTagList1[2].PropertyId = (ushort)PropertyId.PidTagReceivedByEmailAddress;
            propertyTagList1[2].PropertyType = (ushort)PropertyType.PtypString;

            uint contentTableHandler = 0;
            int expectedMessageIndex = 0;
            RopQueryRowsResponse getNormalMailMessageContent = this.GetExpectedMessage(this.InboxFolderHandle, ref contentTableHandler, propertyTagList1, ref expectedMessageIndex, replyTemplateSubject);

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

            // Verify MS-OXORULE requirement: MS-OXORULE_R5281.
            Site.CaptureRequirementIfAreEqual<int>(
                1,
                getNormalMailMessageContent.RowData.PropertyRows.Count,
                5281,
                @"[In Appendix A: Product Behavior] Implementation does not avoid sending replies to automatically generated messages to avoid generating endless autoreply loops for ""OP_REPLY"". (Exchange 2003 and above follow this behavior.)");
            #endregion
            #endregion
        }
        /// <summary>
        /// Verify RuleAction buffer for stand rule.
        /// </summary>
        /// <param name="ruleAction">RuleAction structure to be verified.</param>
        private void VerifyRuleAction(RuleAction ruleAction)
        {
            // Add the debug information.
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R232, The value of NoOfActions is {0}", ruleAction.NoOfActions);

            // Verify MS-OXORULE requirement: MS-OXORULE_R232.
            // NoOfActions can be either unsigned-integer or unsigned-short.
            uint actionsNumber = (ruleAction.NoOfActions is uint) ? ((uint)ruleAction.NoOfActions) : ((ushort)ruleAction.NoOfActions);
            bool isVerifyR232 = actionsNumber > 0;

            Site.CaptureRequirementIfIsTrue(
                isVerifyR232,
                232,
                @"[In RuleAction Structure] NoOfActions (2 bytes): This number MUST be greater than zero.");
            foreach (ActionBlock actionBlock in ruleAction.Actions)
            {
                // Add the debug information.
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R236");

                // Verify MS-OXORULE requirement: MS-OXORULE_R236.
                // There are 2 or 4 bytes of the ActionLength in the ActionBlocks,
                // so the cumulative length in bytes of the subsequent fields of the ActionLength must equal to the length of  ActionBlock.length - lengthOfActionLength.
                int lengthOfActionLength = actionBlock.ActionLength is ushort ? 2 : 4;
                bool isVerifyR236 = (actionBlock.ActionLength is ushort ? (ushort)actionBlock.ActionLength : (uint)actionBlock.ActionLength) == (actionBlock.Serialize().Length - lengthOfActionLength);

                Site.CaptureRequirementIfIsTrue(
                    isVerifyR236,
                    236,
                    @"[In ActionBlock Structure] ActionLength (2 bytes): An integer that specifies the cumulative length, in bytes, of the subsequent fields in this ActionBlock structure.");

                // Verify MS-OXORULE requirement: MS-OXORULE_R947.
                bool isVerifyR947 = (byte)actionBlock.ActionType == 0x01 ||
                                    (byte)actionBlock.ActionType == 0x02 ||
                                    (byte)actionBlock.ActionType == 0x03 ||
                                    (byte)actionBlock.ActionType == 0x04 ||
                                    (byte)actionBlock.ActionType == 0x05 ||
                                    (byte)actionBlock.ActionType == 0x06 ||
                                    (byte)actionBlock.ActionType == 0x07 ||
                                    (byte)actionBlock.ActionType == 0x08 ||
                                    (byte)actionBlock.ActionType == 0x09 ||
                                    (byte)actionBlock.ActionType == 0x0A ||
                                    (byte)actionBlock.ActionType == 0x0B;

                Site.CaptureRequirementIfIsTrue(
                    isVerifyR947,
                    947,
                    @"[In RuleAction Structure] ActionBlocks (variable):  An array of ActionBlock structures, each of which specifies an action (2) of the rule (2), as specified in section 2.2.5.1.");
            }

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

            // Verify MS-OXORULE requirement: MS-OXORULE_R231.
            Site.CaptureRequirementIfAreEqual<uint>(
                (uint)ruleAction.Actions.Length,
                actionsNumber,
                231,
                @"[In RuleAction Structure] NoOfActions (2 bytes): Specifies the number of structures that are contained in the ActionBlocks field.");

            // isVerifyR274 is used to verify R274 and R272.
            bool isVerifyR274 = false;

            // isVerifyR287 is used to verify R287 and R272.
            bool isVerifyR287 = false;

            // isVerifyR879 is used to verify R879 and R272.
            bool isVerifyR879 = false;

            for (int i = 0; i < ruleAction.Actions.Length; i++)
            {
                ActionBlock actionBlock = ruleAction.Actions[i];

                // Add the debug information.
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R245", "The value of the actionBlock.ActionType{0} should be one of 0x01 to 0x0b", actionBlock.ActionType);

                // Verify MS-OXORULE requirement: MS-OXORULE_R245.
                bool isVerifyR245 = (byte)actionBlock.ActionType == 0x01 ||
                                    (byte)actionBlock.ActionType == 0x02 ||
                                    (byte)actionBlock.ActionType == 0x03 ||
                                    (byte)actionBlock.ActionType == 0x04 ||
                                    (byte)actionBlock.ActionType == 0x05 ||
                                    (byte)actionBlock.ActionType == 0x06 ||
                                    (byte)actionBlock.ActionType == 0x07 ||
                                    (byte)actionBlock.ActionType == 0x08 ||
                                    (byte)actionBlock.ActionType == 0x09 ||
                                    (byte)actionBlock.ActionType == 0x0A ||
                                    (byte)actionBlock.ActionType == 0x0B;

                Site.CaptureRequirementIfIsTrue(
                    isVerifyR245,
                    245,
                    @"[In ActionBlock Structure] The valid actions (2) [of ActionType] are listed in the following table: OP_MOVE, OP_COPY, OP_REPLY, OP_OOF_REPLY, OP_DEFER_ACTION, OP_BOUNCE, OP_FORWARD, OP_DELEGATE, OP_TAG, OP_DELETE, OP_MARK_AS_READ.");

                if ((actionBlock.ActionType == ActionType.OP_MOVE) || (actionBlock.ActionType == ActionType.OP_COPY))
                {
                    MoveCopyActionData moveCopyActionData = (MoveCopyActionData)actionBlock.ActionDataValue;
                    ServerEID serverEID = new ServerEID(moveCopyActionData.FolderEID);

                    // The storeObjectEntryID structure could only verified in ExchangeServer2007, R632 also only executed in ExchangeServer2007.
                    if (Common.IsRequirementEnabled(632, this.Site))
                    {
                        StoreObjectEntryID storeObjectEntryID = new StoreObjectEntryID();
                        storeObjectEntryID.Deserialize(moveCopyActionData.StoreEID);
                        this.VerifyStoreObjectEntryID(storeObjectEntryID);
                    }

                    // Add the debug information.
                    Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R982: the value of Ours is {0}", serverEID.Ours);

                    // Verify MS-OXORULE_R982.
                    Site.CaptureRequirementIfAreEqual<ushort>(
                        0x01,
                        serverEID.Ours,
                        982,
                        @"[In ServerEid Structure] Ours (1 byte): This field MUST be set to 0x01.");

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

                    // Verify MS-OXORULE requirement: MS-OXORULE_R980
                    // Verify MS-OXORULE_R982 has verified the value of Ours is 0x01, MS-OXORULE_R980 verifies the instance's type.
                    this.Site.CaptureRequirementIfIsInstanceOfType(
                        serverEID,
                        typeof(ServerEID),
                        980,
                        @"[In ServerEid Structure] Ours (1 byte): The value 0x01 indicates that the remaining bytes conform to this structure [ServerEid].");

                    if (moveCopyActionData.StoreEIDSize != 0)
                    {
                        // Add the debug information.
                        Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R297");

                        // Verify MS-OXORULE_R297.
                        Site.CaptureRequirementIfAreEqual<ushort>(
                            (ushort)moveCopyActionData.StoreEID.Length,
                            moveCopyActionData.StoreEIDSize,
                            297,
                            @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Standard Rules] StoreEIDSize (2 bytes): An integer that specifies the size, in bytes, of the StoreEID field.");
                    }

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

                    // Verify MS-OXORULE_R300.
                    Site.CaptureRequirementIfAreEqual<ushort>(
                        (ushort)moveCopyActionData.FolderEID.Length,
                        moveCopyActionData.FolderEIDSize,
                        300,
                        @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Standard Rules] FolderEIDSize (2 bytes): An integer that specifies the size, in bytes, of the FolderEID field.");

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

                    // Verify MS-OXORULE_R294.
                    // The structure of the OP_MOVE Action Date Buffer is verified by the requirements MS-OXORULE_R297, MS-OXORULE_R298, MS-OXORULE_R300, and MS-OXORULE_R301.
                    Site.CaptureRequirement(
                        294,
                        @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Standard Rules] The OP_MOVE ActionData structure MUST be in the following format for a standard rule. [FolderInThisStore, StoreEIDSize, StoreEID, FolderEIDSize, and FolderEID].");

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

                    // Verify MS-OXORULE_R880.
                    // The structure of the OP_MOVE Action Date Buffer is verified by the requirements MS-OXORULE_R297, MS-OXORULE_R298, MS-OXORULE_R300, and MS-OXORULE_R301.
                    Site.CaptureRequirement(
                        880,
                        @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Standard Rules] The OP_COPY ActionData structure MUST be in the following format for a standard rule. [FolderInThisStore, StoreEIDSize, StoreEID, FolderEIDSize, and FolderEID].");
                }

                if (actionBlock.ActionType == ActionType.OP_COPY)
                {
                    // Add the debug information.
                    Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R249");

                    // Verify MS-OXORULE requirement: MS-OXORULE_R249.
                    // If the ActionType of the actionBlock equals the value ActionType.OP_COPY means server could parse the ActionType 0x02.
                    Site.CaptureRequirement(
                        249,
                        @"[In ActionBlock Structure] The value of action type OP_COPY: 0x02.");
                }

                if (actionBlock.ActionType == ActionType.OP_MOVE)
                {
                    // Add the debug information.
                    Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R246");

                    // Verify MS-OXORULE requirement: MS-OXORULE_R246.
                    // If the ActionType of the actionBlock equals the value ActionType.OP_MOVE means server could parse the ActionType 0x01.
                    Site.CaptureRequirement(
                        246,
                        @"[In ActionBlock Structure] The value of action type OP_MOVE: 0x01.");
                }

                if (actionBlock.ActionType == ActionType.OP_FORWARD)
                {
                    // Add the debug information.
                    Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R261");

                    // Verify MS-OXORULE requirement: MS-OXORULE_R261.
                    // If the ActionType of the actionBlock equals the value ActionType.OP_FORWARD means server could parse the ActionType 0x07.
                    Site.CaptureRequirement(
                        261,
                        @"[In ActionBlock Structure] The value of action type OP_FORWARD: 0x07.");

                    // Add the debug information.
                    Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R274, the value of ActionFlavor is {0}, the ActionFlavorsForward.x is {1}.", actionBlock.ActionFlavor, ActionFlavorsForward.x);

                    // Verify MS-OXORULE requirement: MS-OXORULE_R274.
                    // In ActionFlavor, the not used Flags must not be set, the used Flags can be set or all the bits are not set, it means ActionFlavor is set according to the description in this requirement.
                    isVerifyR274 = (actionBlock.ActionFlavor & (uint)ActionFlavorsForward.x) == 0;

                    Site.CaptureRequirementIfIsTrue(
                        isVerifyR274,
                        274,
                        @"[In Action Flavors] If the value of the ActionType field is ""OP_FORWARD"", the ActionFlavor field contains a combination of the bitwise flags [XXXX (TM) (AT) (NC) (PR) XXXXXXXXXXXXXXXXXXXXXXXXXX] specified as follows.");
                }

                if ((actionBlock.ActionType == ActionType.OP_REPLY) || (actionBlock.ActionType == ActionType.OP_OOF_REPLY))
                {
                    ReplyActionData actionData = new ReplyActionData();
                    actionData.Deserialize(ruleAction.Actions[0].ActionDataValue.Serialize());

                    if (actionBlock.ActionType == ActionType.OP_REPLY)
                    {
                        // Add the debug information.
                        Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R287, the value of ActionFlavor is {0}, it should be one of ActionFlavorsReply.NS({1}), ActionFlavorsReply.ST({2}), or 0x00000000", actionBlock.ActionFlavor, ActionFlavorsReply.NS, ActionFlavorsReply.ST);

                        // Verify MS-OXORULE requirement: MS-OXORULE_R287.
                        // According to open specification, in this condition, the allowed value of ActionFlavor are NS, ST and 0x00000000.
                        isVerifyR287 = (actionBlock.ActionFlavor == (uint)ActionFlavorsReply.NS) ||
                                            (actionBlock.ActionFlavor == (uint)ActionFlavorsReply.ST) ||
                                            (actionBlock.ActionFlavor == 0x00000000);

                        Site.CaptureRequirementIfIsTrue(
                            isVerifyR287,
                            287,
                            @"[In Action Flavors] If the ActionType field value is ""OP_REPLY"", the ActionFlavor field MUST have one of the values specified in the following table [XXXXXX (ST) (NS) XXXXXXXXXXXXXXXXXXXXXXXX] or zero (0x00000000).");

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

                        // Verify MS-OXORULE requirement: MS-OXORULE_R252.
                        // If the ActionType of the actionBlock equals the value ActionType.OP_REPLY means server could parse the ActionType 0x03.
                        Site.CaptureRequirement(
                            252,
                            @"[In ActionBlock Structure] The value of action type OP_REPLY: 0x03.");

                        bool isVerifyR992 = actionData.ReplyTemplateGUID.Length != 0 && actionData.ReplyTemplateFID != 0 && actionData.ReplyTemplateMID != 0;

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

                        // Verify MS-OXORULE requirement: MS-OXORULE_R992.
                        // If ReplyTemplateFID, ReplyTemplateMID, ReplyTemplateGUID in the ActionData is not null, R992 can be verified.
                        Site.CaptureRequirementIfIsTrue(
                            isVerifyR992,
                            992,
                            @"[OP_REPLY and OP_OOF_REPLY ActionData Structure] [Buffer Format for Standard Rules] The OP_REPLY ActionData structure MUST be in the following format for a standard rule. [ReplyTemplateFID, ReplyTemplateMID, ReplyTemplateGUID]");
                    }

                    ReplyActionData replyActionData = (ReplyActionData)actionBlock.ActionDataValue;

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

                    // Verify MS-OXORULE requirement: MS-OXORULE_R308.
                    Site.CaptureRequirementIfIsTrue(
                        Common.IsGUID(replyActionData.ReplyTemplateGUID),
                        308,
                        @"[OP_REPLY and OP_OOF_REPLY ActionData Structure] [Buffer Format for Standard Rules] ReplyTemplateGUID (16 bytes): A GUID that is generated by the client in the process of creating a reply template.");

                    if (actionBlock.ActionType == ActionType.OP_OOF_REPLY)
                    {
                        // Add the debug information.
                        Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R879, the value of ActionFlavor is {0}", "it should be one of ActionFlavorsReply.NS({1}), ActionFlavorsReply.ST({2}), or 0x00000000", actionBlock.ActionFlavor, ActionFlavorsReply.NS, ActionFlavorsReply.ST);

                        // Verify MS-OXORULE requirement: MS-OXORULE_R879.
                        // According to open specification, in this condition, the allowed value of ActionFlavor are NS, ST and 0x00000000.
                        isVerifyR879 = (actionBlock.ActionFlavor == (uint)ActionFlavorsReply.NS) ||
                                            (actionBlock.ActionFlavor == (uint)ActionFlavorsReply.ST) ||
                                            (actionBlock.ActionFlavor == 0x00000000);

                        Site.CaptureRequirementIfIsTrue(
                            isVerifyR879,
                            879,
                            @"[In Action Flavors] If the ActionType field value is ""OP_OOF_REPLY"", the ActionFlavor field MUST have one of the values specified in the following table [XXXXXX (ST) (NS) XXXXXXXXXXXXXXXXXXXXXXXX] or zero (0x00000000). ");

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

                        // Verify MS-OXORULE requirement: MS-OXORULE_R254.
                        // If the ActionType of the actionBlock equals the value ActionType. OP_OOF_REPLY means server could parse the ActionType and its value must be 0x04.
                        Site.CaptureRequirement(
                            254,
                            @"[In ActionBlock Structure] The value of action type OP_OOF_REPLY: 0x04.");

                        bool isVerifyR993 = actionData.ReplyTemplateGUID.Length != 0 && actionData.ReplyTemplateFID != 0 && actionData.ReplyTemplateMID != 0;

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

                        // Verify MS-OXORULE requirement: MS-OXORULE_R993.
                        // If ReplyTemplateFID, ReplyTemplateMID, ReplyTemplateGUID in the ActionData is not null, R993 can be verified.
                        Site.CaptureRequirementIfIsTrue(
                            isVerifyR993,
                            993,
                            @"[OP_REPLY and OP_OOF_REPLY ActionData Structure] [Buffer Format for Standard Rules] The OP_OOF_REPLY ActionData structure MUST be in the following format for a standard rule. [ReplyTemplateFID, ReplyTemplateMID, ReplyTemplateGUID]");
                    }

                    FolderID folderID = new FolderID();
                    folderID.Deserialize(replyActionData.ReplyTemplateFID);
                    if (folderID != null)
                    {
                        // Add the debug information.
                        Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R2175");

                        // Verify MS-OXCDATA requirement: MS-OXCDATA_R2175.
                        Site.CaptureRequirementIfAreEqual<int>(
                            8,
                            folderID.Size,
                            "MS-OXCDATA",
                            2175,
                            @"[In Folder ID Structure] It [Folder ID] is an 8-byte structure.");

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

                        // Verify MS-OXCDATA requirement: MS-OXCDATA_R2176.
                        // "Identifying a Store object" is informative.
                        Site.CaptureRequirementIfAreEqual<int>(
                            2,
                            folderID.ReplicaId.Length,
                            "MS-OXCDATA",
                            2176,
                            @"[In Folder ID Structure] ReplicaId (2 bytes): An unsigned integer identifying a Store object.");

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

                        // Verify MS-OXCDATA requirement: MS-OXCDATA_R2177.
                        // "Identifying the folder within its Store object" is informative.
                        Site.CaptureRequirementIfAreEqual<int>(
                            6,
                            folderID.GlobalCounter.Length,
                            "MS-OXCDATA",
                            2177,
                            @"[In Folder ID Structure] GlobalCounter (6 bytes): An unsigned integer identifying the folder within its Store object.");
                    }

                    MessageID messageID = new MessageID();
                    messageID.Deserialize(replyActionData.ReplyTemplateMID);
                    if (messageID != null)
                    {
                        // Add the debug information.
                        Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R2180");

                        // Verify MS-OXCDATA requirement: MS-OXCDATA_R2180.
                        Site.CaptureRequirementIfAreEqual<int>(
                            8,
                            messageID.Size,
                            "MS-OXCDATA",
                            2180,
                            @"[In Message ID Structure] It [Message ID] is an 8-byte structure.");

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

                        // Verify MS-OXCDATA requirement: MS-OXCDATA_R2181.
                        // "Identifying a Store object" is informative.
                        Site.CaptureRequirementIfAreEqual<int>(
                            2,
                            messageID.ReplicaId.Length,
                            "MS-OXCDATA",
                            2181,
                            @"[In Message ID Structure] ReplicaId (2 bytes): An unsigned integer identifying a Store object.");

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

                        // Verify MS-OXCDATA requirement: MS-OXCDATA_R2182.
                        // "Identifying the message within its Store object" is informative.
                        Site.CaptureRequirementIfAreEqual<int>(
                            6,
                            messageID.GlobalCounter.Length,
                            "MS-OXCDATA",
                            2182,
                            @"[In Message ID Structure] GlobalCounter (6 bytes): An unsigned integer identifying the message within its Store object.");
                    }
                }

                if (actionBlock.ActionType == ActionType.OP_DEFER_ACTION)
                {
                    // Add the debug information.
                    Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R256");

                    // Verify MS-OXORULE requirement: MS-OXORULE_R256.
                    // If the ActionType of the actionBlock equals the value ActionType.OP_DEFER_ACTION means server could parse the ActionType 0x05.
                    Site.CaptureRequirement(
                        256,
                        @"[In ActionBlock Structure] The value of action type OP_DEFER_ACTION: 0x05.");
                }

                if (actionBlock.ActionType == ActionType.OP_TAG)
                {
                    // Add the debug information.
                    Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R265");

                    // Verify MS-OXORULE requirement: MS-OXORULE_R265.
                    // If the ActionType of the actionBlock equals the value ActionType.OP_TAG means server could parse the ActionType 0x09.
                    Site.CaptureRequirement(
                        265,
                        @"[In ActionBlock Structure] The value of action type OP_TAG: 0x09.");

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

                    // Verify MS-OXORULE requirement: MS-OXORULE_R739.
                    // If the taggedPropertyValueOP_TAG is not null means the action data buffer can be parsed by the TaggedPropertyValue.
                    TaggedPropertyValue taggedPropertyValueOP_Tag = AdapterHelper.ReadTaggedProperty(actionBlock.ActionDataValue.Serialize());

                    Site.CaptureRequirementIfIsNotNull(
                        taggedPropertyValueOP_Tag,
                        739,
                        @"[In OP_TAG ActionData Structure] An OP_TAG ActionData structure is a TaggedPropertyValue structure, packaged as specified in [MS-OXCDATA] section 2.11.4.");
                }

                if ((actionBlock.ActionType == ActionType.OP_FORWARD) ||
                    (actionBlock.ActionType == ActionType.OP_REPLY) ||
                    (actionBlock.ActionType == ActionType.OP_OOF_REPLY))
                {
                    // Add the debug information.
                    Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R272", "The value of the ActionFlavor is {0}, and the ActionType is {1}", actionBlock.ActionFlavor, actionBlock.ActionType);

                    // Verify MS-OXORULE requirement: MS-OXORULE_R272.
                    // According to open specification, the only action types that support the Action Flavor are OP_REPLY, OP_OOF_REPLY and OP_FORWARD.
                    // The setting of ActionFlavor is verified in R274 and R287, so the condition to verify R272 is "isVerifyR274 || isVerifyR287".
                    Site.CaptureRequirementIfIsTrue(
                        isVerifyR274 || isVerifyR287 || isVerifyR879,
                        272,
                        @"[In Action Flavors] The only ActionType field values that currently support an Action Flavor are ""OP_REPLY"", ""OP_OOF_REPLY"" and ""OP_FORWARD"".");
                }
                else
                {
                    // Add the debug information.
                    Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R273");

                    // Verify MS-OXORULE requirement: MS-OXORULE_R273.
                    Site.CaptureRequirementIfAreEqual<uint>(
                        0,
                        actionBlock.ActionFlavor,
                        273,
                        @"[In Action Flavors] The value of the ActionFlavor field MUST be 0x00000000 if the value of the ActionType field is not one of these values [OP_REPLY, OP_OOF_REPLY, and OP_FORWARD].");
                }

                // When the AT flag in ActionFlavor is set.
                if ((actionBlock.ActionFlavor & (uint)ActionFlavorsForward.AT) == (uint)ActionFlavorsForward.AT)
                {
                    // Verify MS-OXORULE requirement: MS-OXORULE_R280.
                    uint otherActionFlavorFlags = (uint)ActionFlavorsForward.PR |
                                                  (uint)ActionFlavorsForward.NC |
                                                  (uint)ActionFlavorsForward.TM |
                                                  (uint)ActionFlavorsForward.x;

                    // Add the debug information.
                    Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R280, the value of ActionFlavor is {0}, this value should not be combined with otherActionFlavorFlags({1}).", actionBlock.ActionFlavor, otherActionFlavorFlags);

                    // To verify whether the other ActionFlavor Flags are 0 when the AT flag in ActionFlavor is set.
                    bool isVerifyR280 = (actionBlock.ActionFlavor & otherActionFlavorFlags) == 0;

                    Site.CaptureRequirementIfIsTrue(
                        isVerifyR280,
                        280,
                        @"[In Action Flavors] AT (Bitmask 0x00000004): This value MUST NOT be combined with other ActionFlavor flags.");
                }

                // When the TM flag in ActionFlavor is set.
                if ((actionBlock.ActionFlavor & (uint)ActionFlavorsForward.TM) == (uint)ActionFlavorsForward.TM)
                {
                    // Verify MS-OXORULE requirement: MS-OXORULE_R283.
                    uint otherActionFlavorFlags = (uint)ActionFlavorsForward.PR |
                                                  (uint)ActionFlavorsForward.NC |
                                                  (uint)ActionFlavorsForward.AT |
                                                  (uint)ActionFlavorsForward.x;

                    // Add the debug information.
                    Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R283, the value of ActionFlavor is {0}, this value should not be combined with otherActionFlavorFlags({1}).", actionBlock.ActionFlavor, otherActionFlavorFlags);

                    // To verify whether the other ActionFlavor Flags are 0 when the TM flag in ActionFlavor is set.
                    bool isVerifyR283 = (actionBlock.ActionFlavor & otherActionFlavorFlags) == 0;

                    Site.CaptureRequirementIfIsTrue(
                        isVerifyR283,
                        283,
                        @"[In Action Flavors] TM (Bitmask 0x00000008): This value MUST NOT be combined with other ActionFlavor flags.");
                }

                if (actionBlock.ActionType == ActionType.OP_FORWARD && Common.IsRequirementEnabled(636, this.Site))
                {
                    ForwardDelegateActionData forwardOrDelegateData = (ForwardDelegateActionData)actionBlock.ActionDataValue;

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

                    // Verify MS-OXORULE requirement: MS-OXORULE_R636.
                    bool isVerifyR636 = true;
                    foreach (RecipientBlock recipientBlock in forwardOrDelegateData.RecipientsData)
                    {
                        // Whether the PidTagEntryId exists.
                        bool hasPidTagEntryId = false;
                        foreach (TaggedPropertyValue property in recipientBlock.PropertiesData)
                        {
                            // propertyID of PidTagEntryId is 0x0FFF.
                            if (property.PropertyTag.PropertyId == 0x0FFF)
                            {
                                hasPidTagEntryId = true;
                            }
                        }

                        if (!hasPidTagEntryId)
                        {
                            isVerifyR636 = false;
                            break;
                        }
                    }

                    Site.CaptureRequirementIfIsTrue(
                        isVerifyR636,
                        636,
                        @"[In Appendix A: Product Behavior] Implementation does require the PidTagEntryId property for action ""OP_FORWARD"". [<8> Section 2.2.5.1.2.4.1: Exchange 2003 and Exchange 2007 also require the PidTagEntryId property for action ""OP_FORWARD"".]");
                }

                if ((actionBlock.ActionType == ActionType.OP_FORWARD) || (actionBlock.ActionType == ActionType.OP_DELEGATE))
                {
                    if (actionBlock.ActionType == ActionType.OP_DELEGATE)
                    {
                        // Add the debug information.
                        Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R263");

                        // Verify MS-OXORULE requirement: MS-OXORULE_R263.
                        // If the ActionType of the actionBlock equals the value ActionType.DELEGATE means server could parse the ActionType 0x08.
                        Site.CaptureRequirement(
                            263,
                            @"[In ActionBlock Structure] The value of action type OP_DELEGATE: 0x08.");
                    }

                    ForwardDelegateActionData forwardOrDelegateData = (ForwardDelegateActionData)actionBlock.ActionDataValue;

                    // Add the debug information.
                    Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R323, the recipient count is {0}.", forwardOrDelegateData.RecipientCount);

                    // Verify MS-OXORULE requirement: MS-OXORULE_R323.
                    bool isVerifyR323 = (forwardOrDelegateData.RecipientCount is ushort ? (ushort)forwardOrDelegateData.RecipientCount : (uint)forwardOrDelegateData.RecipientCount) == forwardOrDelegateData.RecipientsData.Length;

                    Site.CaptureRequirementIfIsTrue(
                        isVerifyR323,
                        323,
                        @"[In OP_FORWARD and OP_DELEGATE ActionData Structure] RecipientCount (4 bytes): An integer that specifies the number of RecipientBlockData structures, as specified in section 2.2.5.1.2.4.1, contained in the RecipientBlocks field. ");

                    // Add the debug information.
                    Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R324", "The value of the RecipientCount is {0}, it should greater than 0.", forwardOrDelegateData.RecipientCount);

                    // Verify MS-OXORULE requirement: MS-OXORULE_R324.
                    // The RecipientCount can be either unsigned-integer or unsigned-short.
                    uint recipientCount = (forwardOrDelegateData.RecipientCount is uint) ? ((uint)forwardOrDelegateData.RecipientCount) : ((ushort)forwardOrDelegateData.RecipientCount);
                    bool isVerifyR324 = recipientCount > 0;

                    Site.CaptureRequirementIfIsTrue(
                        isVerifyR324,
                        324,
                        @"[In OP_FORWARD and OP_DELEGATE ActionData Structure] RecipientCount (4 bytes): This number MUST be greater than zero.");

                    bool isVerifyR633 = true;
                    bool isVerifyR632 = true;
                    bool isVerifyR331 = true;
                    foreach (RecipientBlock recipientBlock in forwardOrDelegateData.RecipientsData)
                    {
                        if (Common.IsRequirementEnabled(633, this.Site))
                        {
                            if (recipientBlock.Reserved != 0x00)
                            {
                                isVerifyR633 = false;
                                break;
                            }
                        }

                        if (Common.IsRequirementEnabled(632, this.Site))
                        {
                            if (recipientBlock.Reserved != 0x01)
                            {
                                isVerifyR632 = false;
                                break;
                            }
                        }

                        // Add the debug information.
                        Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R330, the NoOfProperties of the RecipientBlock is {0}.", recipientBlock.NoOfProperties);

                        // Verify MS-OXORULE requirement: MS-OXORULE_R330.
                        bool isVerifyR330 = (recipientBlock.NoOfProperties is ushort ? (ushort)recipientBlock.NoOfProperties : (uint)recipientBlock.NoOfProperties) == (ulong)recipientBlock.PropertiesData.Length;

                        Site.CaptureRequirementIfIsTrue(
                            isVerifyR330,
                            330,
                            @"[In RecipientBlockData Structure] NoOfProperties (4 bytes): An integer that specifies the number of structures present in the PropertyValues field.");

                        TaggedPropertyValue[] taggedPropertyValue = recipientBlock.PropertiesData;
                        bool isVerifyR468 = taggedPropertyValue[0].PropertyTag.PropertyId != 0 && taggedPropertyValue[0].PropertyTag.PropertyType != 0;

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

                        // Verify MS-OXCDATA requirement: MS-OXCDATA_R468.
                        Site.CaptureRequirementIfIsTrue(
                            isVerifyR468,
                            "MS-OXCDATA",
                            468,
                            @"[In TaggedPropertyValue Structure] PropertyTag (4 bytes): A PropertyTag structure, as specified in section 2.9, giving the values of the PropertyId and PropertyType fields for the property.");

                        // Add the debug information.
                        Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCDATA_R469");
                        PropertyValue propertyValue = (PropertyValue)taggedPropertyValue[0];

                        // Verify MS-OXCDATA requirement: MS-OXCDATA_R469.
                        Site.CaptureRequirementIfIsInstanceOfType(
                            propertyValue,
                            typeof(PropertyValue),
                            "MS-OXCDATA",
                            469,
                            @"[In TaggedPropertyValue Structure] PropertyValue (variable): A PropertyValue structure, as specified in section 2.11.2.1.");

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

                        // Verify MS-OXORULE requirement: MS-OXORULE_R1008.
                        // The format of the TaggedPropertyValue structure has been verified by MS-OXCDATA_R468, and MS-OXCDATA_R469.
                        Site.CaptureRequirement(
                            1008,
                            @"[In RecipientBlockData Structure] The format of the TaggedPropertyValue structure is specified in [MS-OXCDATA] section 2.11.4.");

                        // Verify MS-OXORULE requirement: MS-OXORULE_R331.
                        uint properties = (recipientBlock.NoOfProperties is uint) ? ((uint)recipientBlock.NoOfProperties) : ((ushort)recipientBlock.NoOfProperties);
                        if (properties <= 0)
                        {
                            isVerifyR331 = false;
                            break;
                        }
                    }

                    if (Common.IsRequirementEnabled(633, this.Site))
                    {
                        // Add the debug information.
                        Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R633");
                        Site.CaptureRequirementIfIsTrue(
                            isVerifyR633,
                            633,
                            @"[[In Appendix A: Product Behavior] Implementation does set this value [Reserved (1 byte)] to 0x00. [<9> Section 2.2.5.1.2.4.1: Exchange 2010, Exchange 2013, and Exchange 2016 set this value to 0x00.]");
                    }

                    if (Common.IsRequirementEnabled(632, this.Site))
                    {
                        // Add the debug information.
                        Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R632");

                        Site.CaptureRequirementIfIsTrue(
                            isVerifyR632,
                            632,
                            @"[In Appendix A: Product Behavior] Implementation does set this value [Reserved (1 byte)] to 0x01. [<9> Section 2.2.5.1.2.4.1: Exchange 2003 and Exchange 2007 set this value to 0x01.]");
                    }

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

                    // Verify MS-OXORULE requirement: MS-OXORULE_R331.
                    Site.CaptureRequirementIfIsTrue(
                        isVerifyR331,
                        331,
                        @"[In RecipientBlockData Structure] NoOfProperties (4 bytes): This number MUST be greater than zero.");

                    if (Common.IsRequirementEnabled(895, this.Site))
                    {
                        // Add the debug information.
                        Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R895");

                        // Verify requirement: MS-OXORULE_R895.
                        bool isVerifyR895 = true;
                        foreach (RecipientBlock recipientBlock in forwardOrDelegateData.RecipientsData)
                        {
                            // Whether the PidTagDisplayName exists.
                            bool hasPidTagDisplayName = false;

                            // Whether the PidTagEmailAddress exists.
                            bool hasPidTagEmailAddress = false;

                            // Whether the PidTagRecipientType exists.
                            bool hasPidTagRecipientType = false;
                            foreach (TaggedPropertyValue property in recipientBlock.PropertiesData)
                            {
                                // propertyID of hasPidTagDisplayName is 0x3001.
                                if (property.PropertyTag.PropertyId == 0x3001)
                                {
                                    hasPidTagDisplayName = true;
                                }

                                // propertyID of PidTagEmailAddress is 0x3003.
                                if (property.PropertyTag.PropertyId == 0x3003)
                                {
                                    hasPidTagEmailAddress = true;
                                }

                                // propertyID of PidTagRecipientType is 0x0C15.
                                if (property.PropertyTag.PropertyId == 0x0C15)
                                {
                                    hasPidTagRecipientType = true;
                                }
                            }

                            if (!(hasPidTagDisplayName && hasPidTagEmailAddress && hasPidTagRecipientType))
                            {
                                isVerifyR895 = false;
                                break;
                            }
                        }

                        // Verify MS-OXORULE requirement: MS-OXORULE_R895.
                        Site.CaptureRequirementIfIsTrue(
                            isVerifyR895,
                            895,
                            @"[In RecipientBlock Data Buffer Packet Structure] No rules (2) does require more [specify values for more properties besides the PidTagDisplayName, PidTagEmailAddress, and PidTagRecipientType in the forward/delegate ActionData buffer] on the implementation. (Exchange 2010 and above follow this behavior.)");
                    }
                }

                if (actionBlock.ActionType == ActionType.OP_BOUNCE)
                {
                    // Add the debug information.
                    Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R259");

                    // Verify MS-OXORULE requirement: MS-OXORULE_R259.
                    // If the ActionType of the actionBlock equals the value ActionType.OP_COPY means server could parse the ActionType 0x06.
                    Site.CaptureRequirement(
                        259,
                        @"[In ActionBlock Structure] The value of action type OP_BOUNCE: 0x06.");

                    BounceActionData bounceActionData = (BounceActionData)actionBlock.ActionDataValue;

                    // Add the debug information.
                    Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R340", "The value of the BounceCode field is {0}.", bounceActionData.Bounce);

                    // Verify MS-OXORULE requirement: MS-OXORULE_R340.
                    bool isVerifyR340 =
                          (uint)bounceActionData.Bounce == 0x0000000D
                        || (uint)bounceActionData.Bounce == 0x0000001F
                        || (uint)bounceActionData.Bounce == 0x00000026;
                    Site.CaptureRequirementIfIsTrue(
                        isVerifyR340,
                        340,
                        @"[In OP_BOUNCE ActionData Structure] The bounce code MUST be one of the following values. [0x0000000D, 0x0000001F, and 0x00000026].");
                }

                if ((actionBlock.ActionType == ActionType.OP_DELETE) || (actionBlock.ActionType == ActionType.OP_MARK_AS_READ))
                {
                    if (actionBlock.ActionType == ActionType.OP_DELETE)
                    {
                        // Add the debug information.
                        Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R267");

                        // If the ActionType of the actionBlock equals the value ActionType.OP_MOVE means server could parse the ActionType 0x0A.
                        Site.CaptureRequirement(
                                      267,
                                       @"[In ActionBlock Structure] The value of action type OP_DELETE: 0x0A.");
                    }

                    if (actionBlock.ActionType == ActionType.OP_MARK_AS_READ)
                    {
                        // Add the debug information.
                        Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R269");

                        // If the ActionType of the actionBlock equals the value ActionType.OP_COPY means server could parse the ActionType 0x0B.
                        Site.CaptureRequirement(
                                      269,
                                       @"[In ActionBlock Structure] The value of action type OP_MARK_AS_READ: 0x0B.");
                    }

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

                    // Verify MS-OXORULE requirement: MS-OXORULE_R346.
                    // If the Size of ActionDataValue is 0, it means these actions have no ActionData buffer.
                    Site.CaptureRequirementIfAreEqual<int>(
                        0,
                        actionBlock.ActionDataValue.Size(),
                        346,
                        @"[In OP_DELETE or OP_MARK_AS_READ ActionData Structure] These actions [OP_DELETE, OP_MARK_AS_READ] (3) have no ActionData structure.");
                }
            }
        }
        public void MSOXORULE_S03_TC05_OOFBehaviorsForOP_OOF_REPLY()
        {
            this.CheckMAPIHTTPTransportSupported();

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

            #region Create one reply template for OP_OOF_REPLY action Type in TestUser1's Inbox folder.
            ulong replyTemplateMessageID;
            uint replyTemplateMessageHandle;
            TaggedPropertyValue[] addReplyBody = new TaggedPropertyValue[1];
            addReplyBody[0] = new TaggedPropertyValue();
            PropertyTag addReplyBodyPropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagBody,
                PropertyType = (ushort)PropertyType.PtypString
            };
            addReplyBody[0].PropertyTag = addReplyBodyPropertyTag;
            string replyMessageBody = Common.GenerateResourceName(this.Site, Constants.MessageOfOOFReply);
            addReplyBody[0].Value = Encoding.Unicode.GetBytes(replyMessageBody + "\0");
            string replyTemplateSubject = Common.GenerateResourceName(this.Site, Constants.ReplyTemplateSubject);
            byte[] replyTemplateGUID = this.OxoruleAdapter.CreateReplyTemplate(this.InboxFolderHandle, this.InboxFolderID, true, replyTemplateSubject, addReplyBody, out replyTemplateMessageID, out replyTemplateMessageHandle);
            #endregion

            #region TestUser1 adds OP_OOF_REPLY rule with PidTagRuleState set to ST_ENABLED.
            ReplyActionData replyRuleActionData = new ReplyActionData
            {
                ReplyTemplateGUID = replyTemplateGUID,
                ReplyTemplateFID = this.InboxFolderID,
                ReplyTemplateMID = replyTemplateMessageID
            };

            RuleData ruleDataForReplyRule = AdapterHelper.GenerateValidRuleDataWithFlavor(ActionType.OP_OOF_REPLY, 1, RuleState.ST_ENABLED, replyRuleActionData, 0x00000000, ruleProperties);
            RopModifyRulesResponse ropModifyRulesResponse = this.OxoruleAdapter.RopModifyRules(this.InboxFolderHandle, ModifyRuleFlag.Modify_ReplaceAll, new RuleData[] { ruleDataForReplyRule });
            Site.Assert.AreEqual<uint>(0, ropModifyRulesResponse.ReturnValue, "Adding reply rule should succeed.");
            #endregion

            #region TestUser2 delivers a message to TestUser1 to trigger these rules.
            // Sleep enough time to wait for the rule to take effect.
            Thread.Sleep(this.WaitForTheRuleToTakeEffect);
            string mailSubject = Common.GenerateResourceName(this.Site, ruleProperties.ConditionSubjectName + "Title");
            this.SUTAdapter.SendMailToRecipient(this.User2Name, this.User2Password, this.User1Name, mailSubject);

            // Sleep enough time to wait for the rule to be executed on the delivered message.
            Thread.Sleep(this.WaitForTheRuleToTakeEffect);
            #endregion

            #region TestUser2 verifies whether can receive the OOF replied message.
            // Let Testuser2 logon to the server
            this.LogonMailbox(TestUser.TestUser2);

            PropertyTag[] propertyTagList = new PropertyTag[4];
            propertyTagList[0].PropertyId = (ushort)PropertyId.PidTagAutoForwarded;
            propertyTagList[0].PropertyType = (ushort)PropertyType.PtypBoolean;
            propertyTagList[1].PropertyId = (ushort)PropertyId.PidTagBody;
            propertyTagList[1].PropertyType = (ushort)PropertyType.PtypString;
            propertyTagList[2].PropertyId = (ushort)PropertyId.PidTagSubject;
            propertyTagList[2].PropertyType = (ushort)PropertyType.PtypString;
            propertyTagList[3].PropertyId = (ushort)PropertyId.PidTagMessageClass;
            propertyTagList[3].PropertyType = (ushort)PropertyType.PtypString;

            uint contentsTableHandle = 0;
            int expectedMessageIndex = 0;
            RopQueryRowsResponse ropQueryRowsResponse = this.GetExpectedMessage(this.InboxFolderHandle, ref contentsTableHandle, propertyTagList, ref expectedMessageIndex, mailSubject);

            string mailBodyTestUser2 = AdapterHelper.PropertyValueConvertToString(ropQueryRowsResponse.RowData.PropertyRows[expectedMessageIndex].PropertyValues[1].Value);
            string subject = AdapterHelper.PropertyValueConvertToString(ropQueryRowsResponse.RowData.PropertyRows[expectedMessageIndex].PropertyValues[2].Value);
            bool isBodyContainsReplyTemplateBody = mailBodyTestUser2.Contains(replyMessageBody);
            Site.Assert.IsTrue(isBodyContainsReplyTemplateBody, "Message should contain the template body!");

            #region Capture Code
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R255: the replied message count is {0}, and whether the message body contains the reply template body is {1}", ropQueryRowsResponse.RowCount, isBodyContainsReplyTemplateBody);

            // Verify MS-OXORULE requirement: MS-OXORULE_R255
            // Testuser2 sent message to Testuser1,Testuser2 can receive a reply means the server send the reply
            bool isVerifyR255 = ropQueryRowsResponse.RowCount > 0 && isBodyContainsReplyTemplateBody;

            Site.CaptureRequirementIfIsTrue(
                isVerifyR255,
                255,
                @"[In ActionBlock Structure] The meaning of action type OP_OOF_REPLY: Sends an OOF reply to the message.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R922: the replied message count is {0}, and whether the message body contains the reply template body is {1}", ropQueryRowsResponse.RowCount, isBodyContainsReplyTemplateBody);

            // Verify MS-OXORULE requirement: MS-OXORULE_R922
            // Testuser2 sent message to Testuser1,Testuser2 can receive a reply means the server send the reply
            bool isVerifyR922 = ropQueryRowsResponse.RowCount > 0 && isBodyContainsReplyTemplateBody;

            Site.CaptureRequirementIfIsTrue(
                isVerifyR922,
                922,
                @"[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_OOF_REPLY"": The server MUST behave as specified for the ""OP_REPLY"" action (2). [The server MUST use properties from the reply template and from the original message to create a reply to the message and then send the reply.]");

            // Add the debug information.
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R953: the replied message count is {0}, and whether the message body contains the reply template body is {1}", ropQueryRowsResponse.RowCount, isBodyContainsReplyTemplateBody);

            bool isVerifyR953 = ropQueryRowsResponse.RowCount > 0 && isBodyContainsReplyTemplateBody;

            // Verify MS-OXORULE requirement: MS-OXORULE_R953.
            // The ActionFlavor is set to zero in the OP_REPLY rule, so if the messages template is the same with the reply template, means this reply is not use server-defined text in the reply message, and it's a standard reply. 
            Site.CaptureRequirementIfIsTrue(
                isVerifyR953,
                953,
                @"[In Action Flavors] [If the ActionType field value is ""OP_OOF_REPLY"", the ActionFlavor field MUST have one of the values specified in the following table [XXXXXX (ST) (NS) XXXXXXXXXXXXXXXXXXXXXXXX] or zero (0x00000000)] A value of zero (0x00000000) indicates standard reply behavior, as specified in section 3.1.4.2.5.");

            string propertyValue = AdapterHelper.PropertyValueConvertToString(ropQueryRowsResponse.RowData.PropertyRows[expectedMessageIndex].PropertyValues[3].Value);
            if (Common.IsRequirementEnabled(906, this.Site))
            {
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R906: whether the message body contains the reply template body is {0}, and the PidTagMessageClass is {1}", isBodyContainsReplyTemplateBody, propertyValue);

                // Verify MS-OXORULE requirement: MS-OXORULE_R906
                // The value of PidTagMessageClass is a prefix, and the client can append a client-specific value at the end of this property,
                // so if propertyValue is start with "IPM.Note.rules.OOFTemplate", R906 can be verified.
                string prefixOfPidTagMessageClass = "IPM.Note.rules.OOFTemplate";
                bool isVerifyR906 = isBodyContainsReplyTemplateBody && propertyValue.ToUpperInvariant().StartsWith(prefixOfPidTagMessageClass.ToUpperInvariant());

                Site.CaptureRequirementIfIsTrue(
                    isVerifyR906,
                    906,
                    @"[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_OOF_REPLY"": The implementation does set the value of the PidTagMessageClass property ([MS-OXCMSG] section 2.2.1.3) on the reply message to ""IPM.Note.rules.OOFTemplate"" in addition. (Exchange 2003 and above follow this behavior.)");
            }
            #endregion
            #endregion
        }
        public void MSOXORULE_S03_TC04_OOFBehaviorsForST_KEEP_OOF_HIST()
        {
            this.CheckMAPIHTTPTransportSupported();
            Site.Assume.IsTrue(Common.IsRequirementEnabled(583, this.Site), "This case runs only when the server supports to keep a list of rules with ST_KEEP_OOF_HIST flag.");

            #region Prepare value for ruleProperties variable.
            RuleProperties ruleProperties = AdapterHelper.GenerateRuleProperties(this.Site, Constants.RuleNameOOFReply);
            string setOOFMailAddress = this.User1Name + "@" + this.Domain;
            string userPassword = this.User1Password;
            #endregion

            #region Set TestUser1 to OOF state.
            bool isSetOOFSuccess = this.SUTSetOOFAdapter.SetUserOOFSettings(setOOFMailAddress, userPassword, true);
            Site.Assert.IsTrue(isSetOOFSuccess, "Turn Out of Office on for {0} should succeed.", this.User1Name);
            Thread.Sleep(this.WaitForSetOOFComplete);
            #endregion

            #region Create one reply template for OP_OOF_REPLY action Type.
            ulong replyTemplateMessageID;
            uint replyTemplateMessageHandle;
            TaggedPropertyValue[] addReplyBody = new TaggedPropertyValue[1];
            addReplyBody[0] = new TaggedPropertyValue();
            PropertyTag addReplyBodyPropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagBody,
                PropertyType = (ushort)PropertyType.PtypString
            };
            addReplyBody[0].PropertyTag = addReplyBodyPropertyTag;
            string replyMessageBody = Common.GenerateResourceName(this.Site, Constants.MessageOfOOFReply);
            addReplyBody[0].Value = Encoding.Unicode.GetBytes(replyMessageBody + "\0");
            string replyTemplateSubject = Common.GenerateResourceName(this.Site, Constants.ReplyTemplateSubject);
            byte[] replyTemplateGUID = this.OxoruleAdapter.CreateReplyTemplate(this.InboxFolderHandle, this.InboxFolderID, true, replyTemplateSubject, addReplyBody, out replyTemplateMessageID, out replyTemplateMessageHandle);
            #endregion

            #region TestUser1 adds OP_OOF_REPLY rule with PidTagRuleState set to ST_ENABLED | ST_KEEP_OOF_HIST.

            ReplyActionData replyRuleActionData = new ReplyActionData
            {
                ReplyTemplateGUID = replyTemplateGUID,
                ReplyTemplateFID = this.InboxFolderID,
                ReplyTemplateMID = replyTemplateMessageID
            };

            RuleData ruleDataForReplyRule = AdapterHelper.GenerateValidRuleData(ActionType.OP_OOF_REPLY, TestRuleDataType.ForAdd, 1, RuleState.ST_ENABLED | RuleState.ST_KEEP_OOF_HIST, replyRuleActionData, ruleProperties, null);
            RopModifyRulesResponse ropModifyRulesResponse = this.OxoruleAdapter.RopModifyRules(this.InboxFolderHandle, ModifyRuleFlag.Modify_ReplaceAll, new RuleData[] { ruleDataForReplyRule });
            Site.Assert.AreEqual<uint>(0, ropModifyRulesResponse.ReturnValue, "Adding reply rule should succeed.");
            #endregion

            #region TestUser2 delivers a message to TestUser1 to trigger these rules.
            // Sleep enough time to wait for the rule to take effect.
            Thread.Sleep(this.WaitForTheRuleToTakeEffect);

            // TestUser2 log on to the server.
            this.LogonMailbox(TestUser.TestUser2);
            string mailSubject = Common.GenerateResourceName(this.Site, ruleProperties.ConditionSubjectName + "Title", 1);
            this.DeliverMessageToTriggerRule(this.User1Name, this.User1ESSDN, mailSubject, null);

            // Sleep enough time to wait for the rule to be executed on the delivered message.
            Thread.Sleep(this.WaitForTheRuleToTakeEffect);

            PropertyTag[] propertyTagList = new PropertyTag[2];
            propertyTagList[0].PropertyId = (ushort)PropertyId.PidTagBody;
            propertyTagList[0].PropertyType = (ushort)PropertyType.PtypString;
            propertyTagList[1].PropertyId = (ushort)PropertyId.PidTagSubject;
            propertyTagList[1].PropertyType = (ushort)PropertyType.PtypString;

            uint contentTableHandler = 0;
            int expectedMessageIndex = 0;
            RopQueryRowsResponse getNormalMailMessageContent = this.GetExpectedMessage(this.InboxFolderHandle, ref contentTableHandler, propertyTagList, ref expectedMessageIndex, mailSubject);
            string mailBody = AdapterHelper.PropertyValueConvertToString(getNormalMailMessageContent.RowData.PropertyRows[expectedMessageIndex].PropertyValues[0].Value);
            bool isBodyContainsReplyTemplateBody = mailBody.Contains(replyMessageBody);
            #endregion

            #region TestUser2 delivers a message to TestUser1 to trigger these rules again.
            // Sleep enough time to wait for the rule to take effect.
            Thread.Sleep(this.WaitForTheRuleToTakeEffect);
            mailSubject = Common.GenerateResourceName(this.Site, ruleProperties.ConditionSubjectName + "Title", 2);
            this.DeliverMessageToTriggerRule(this.User1Name, this.User1ESSDN, mailSubject, null);

            // Sleep enough time to wait for the rule to be executed on the delivered message.
            Thread.Sleep(this.WaitForTheRuleToTakeEffect);
            #endregion

            #region TestUser1 gets the message sent by TestUser2.
            // TestUser1 log on to the server.
            this.LogonMailbox(TestUser.TestUser1);
            uint inboxFolderContentsTableHandle = 0;
            PropertyTag[] propertyTags = new PropertyTag[1];
            propertyTags[0].PropertyId = (ushort)PropertyId.PidTagSubject;
            propertyTags[0].PropertyType = (ushort)PropertyType.PtypString;

            uint rowCount = 0;
            RopQueryRowsResponse getInboxMailMessageContent = this.GetExpectedMessage(this.InboxFolderHandle, ref inboxFolderContentsTableHandle, propertyTags, ref rowCount, 1, mailSubject);
            Site.Assert.AreEqual<uint>(0, getInboxMailMessageContent.ReturnValue, "getInboxMailMessageContent should succeed.");
            #endregion

            #region TestUser2 verifies whether can receive the replied message.
            
            // TestUser2 log on to the server.
            this.LogonMailbox(TestUser.TestUser2);
            bool doesUnexpectedMessageExist = this.CheckUnexpectedMessageExist(this.InboxFolderHandle, ref contentTableHandler, propertyTagList, mailSubject);

            #region Capture code
            if (Common.IsRequirementEnabled(5572, this.Site))
            {
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R5572: the expected reply message index is {0} and the total message count is {1}, and whether the message body contains the reply template body is {2}", expectedMessageIndex, getNormalMailMessageContent.RowCount, isBodyContainsReplyTemplateBody);

                // Verify MS-OXORULE requirement: MS-OXORULE_R5572.
                // The above case shows the rule was not executed twice, which indirectly indicates server adds the normal user into 
                // History List after the rule was executed once.
                Site.CaptureRequirementIfIsFalse(
                    doesUnexpectedMessageExist,
                    5572,
                    @"[In Appendix A: Product Behavior] Implementation does not evaluate the rule (2) if the sender is on the list. (Exchange 2007, Exchange 2010 and Exchange 2016 follow this behavior.)");
            }
            // If R577 is verified, which means the sender was added to the list of recipients.
            this.Site.CaptureRequirement(
                558,
                @"[In Processing Out of Office Rules] If not [the sender is not on the list] and the rule (2) condition evaluates to ""TRUE"", the server MUST add the sender to the list of recipients (2) for the rule (2) in addition to executing the rule (2) action (2).");

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

            // Verify MS-OXORULE requirement: MS-OXORULE_R583
            // That is verified means when sending two messages, only the first one will execute the rule that has ST_KEEP_OOF_HIST flag, so the server must have kept a list for rules.
            bool isVerifyR583 = isBodyContainsReplyTemplateBody;

            Site.CaptureRequirementIfIsTrue(
                isVerifyR583,
                583,
                @"[In Entering and Exiting the Out of Office State] The server MUST also keep a list for rules (2) that have the ST_KEEP_OOF_HIST flag in the PidTagRuleState property specified in section 3.2.1.2.");
            #endregion
            #endregion

            #region Set TestUser1 back to normal state (not in OOF state)
            // Testuser1 logon to the server
            this.LogonMailbox(TestUser.TestUser1);

            isSetOOFSuccess = this.SUTSetOOFAdapter.SetUserOOFSettings(setOOFMailAddress, userPassword, false);
            Site.Assert.IsTrue(isSetOOFSuccess, "Cancelling Out of Office state for {0} should succeed.", this.User1Name);
            Thread.Sleep(this.WaitForSetOOFComplete);
            #endregion
        }
        public void MSOXORULE_S03_TC09_OOFBehaviorsForOP_OOF_REPLY_ActionFlavor_NS()
        {
            this.CheckMAPIHTTPTransportSupported();

            #region Prepare value for ruleProperties variable.
            RuleProperties ruleProperties = AdapterHelper.GenerateRuleProperties(this.Site, Constants.RuleNameOOFReply);
            string setOOFMailAddress = this.User1Name + "@" + this.Domain;
            string userPassword = this.User1Password;
            #endregion

            #region Set TestUser1 to OOF state.
            bool isSetOOFSuccess = this.SUTSetOOFAdapter.SetUserOOFSettings(setOOFMailAddress, userPassword, true);
            Site.Assert.IsTrue(isSetOOFSuccess, "Turn Out of Office on for {0} should succeed.", this.User1Name);
            Thread.Sleep(this.WaitForSetOOFComplete);
            #endregion

            #region Create one reply template for OP_OOF_REPLY action Type in TestUser1's Inbox folder.
            ulong replyTemplateMessageID;
            uint replyTemplateMessageHandle;

            TaggedPropertyValue[] replyTemplateProperties;
            TaggedPropertyValue[] temp = AdapterHelper.GenerateRecipientPropertiesBlock(this.User2Name, this.User2ESSDN);
            replyTemplateProperties = new TaggedPropertyValue[4];
            replyTemplateProperties[0] = new TaggedPropertyValue();
            PropertyTag addReplyBodyPropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagBody,
                PropertyType = (ushort)PropertyType.PtypString
            };
            replyTemplateProperties[0].PropertyTag = addReplyBodyPropertyTag;
            string replyMessageBody = Common.GenerateResourceName(this.Site, Constants.MessageOfOOFReply);
            replyTemplateProperties[0].Value = Encoding.Unicode.GetBytes(replyMessageBody + "\0");
            Array.Copy(temp, 0, replyTemplateProperties, 1, temp.Length - 1);
            string replyTemplateSubject = Common.GenerateResourceName(this.Site, Constants.ReplyTemplateSubject);
            byte[] replyTemplateGUID = this.OxoruleAdapter.CreateReplyTemplate(this.InboxFolderHandle, this.InboxFolderID, true, replyTemplateSubject, replyTemplateProperties, out replyTemplateMessageID, out replyTemplateMessageHandle);
            #endregion

            #region TestUser1 adds OP_OOF_REPLY rule with actionFlavor set to NS(0x00000001).
            ReplyActionData replyRuleActionData = new ReplyActionData
            {
                ReplyTemplateGUID = replyTemplateGUID,
                ReplyTemplateFID = this.InboxFolderID,
                ReplyTemplateMID = replyTemplateMessageID
            };
            uint actionFlavor_NS = (uint)ActionFlavorsReply.NS;

            RuleData ruleDataForReplyRule = AdapterHelper.GenerateValidRuleDataWithFlavor(ActionType.OP_OOF_REPLY, 1, RuleState.ST_ENABLED, replyRuleActionData, actionFlavor_NS, ruleProperties);
            RopModifyRulesResponse ropModifyRulesResponse = this.OxoruleAdapter.RopModifyRules(this.InboxFolderHandle, ModifyRuleFlag.Modify_ReplaceAll, new RuleData[] { ruleDataForReplyRule });
            Site.Assert.AreEqual<uint>(0, ropModifyRulesResponse.ReturnValue, "Adding reply rule should succeed.");
            #endregion

            #region TestUser2 delivers a message to TestUser1 to trigger these rules.
            // Sleep enough time to wait for the rule to take effect.
            Thread.Sleep(this.WaitForTheRuleToTakeEffect);
            string mailSubject = Common.GenerateResourceName(this.Site, ruleProperties.ConditionSubjectName + "Title");
            this.SUTAdapter.SendMailToRecipient(this.User2Name, this.User2Password, this.User1Name, mailSubject);

            // Sleep enough time to wait for the rule to be executed on the delivered message.
            Thread.Sleep(this.WaitForTheRuleToTakeEffect);
            #endregion

            #region TestUser2 verifies whether can receive the OOF replied message.
            // Let Testuser2 logon to the server
            this.LogonMailbox(TestUser.TestUser2);

            PropertyTag[] propertyTagList = new PropertyTag[4];
            propertyTagList[0].PropertyId = (ushort)PropertyId.PidTagAutoForwarded;
            propertyTagList[0].PropertyType = (ushort)PropertyType.PtypBoolean;
            propertyTagList[1].PropertyId = (ushort)PropertyId.PidTagBody;
            propertyTagList[1].PropertyType = (ushort)PropertyType.PtypString;
            propertyTagList[2].PropertyId = (ushort)PropertyId.PidTagSubject;
            propertyTagList[2].PropertyType = (ushort)PropertyType.PtypString;
            propertyTagList[3].PropertyId = (ushort)PropertyId.PidTagMessageClass;
            propertyTagList[3].PropertyType = (ushort)PropertyType.PtypString;

            uint contentsTableHandle = 0;
            int expectedMessageIndex = 0;            

            if (Common.IsRequirementEnabled(10191, this.Site))
            {
                RopQueryRowsResponse ropQueryRowsResponse = this.GetExpectedMessage(this.InboxFolderHandle, ref contentsTableHandle, propertyTagList, ref expectedMessageIndex, mailSubject);
                string mailBodyTestUser2 = AdapterHelper.PropertyValueConvertToString(ropQueryRowsResponse.RowData.PropertyRows[expectedMessageIndex].PropertyValues[1].Value);
                string subject = AdapterHelper.PropertyValueConvertToString(ropQueryRowsResponse.RowData.PropertyRows[expectedMessageIndex].PropertyValues[2].Value);
                bool isBodyContainsReplyTemplateBody = mailBodyTestUser2.Contains(replyMessageBody);
                Site.Assert.IsTrue(isBodyContainsReplyTemplateBody, "Message should contain the template body!");

                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R10191: the replied message count is {0}, and whether the message body contains the reply template body is {1}", ropQueryRowsResponse.RowCount, isBodyContainsReplyTemplateBody);

                // Verify MS-OXORULE requirement: MS-OXORULE_R10191
                // Testuser2 sent message to Testuser1,Testuser2 can receive a reply means the server send the reply
                bool isVerifyR10191 = ropQueryRowsResponse.RowCount > 0 && isBodyContainsReplyTemplateBody;

                Site.CaptureRequirementIfIsTrue(
                    isVerifyR10191,
                    10191,
                    @"[In Appendix A: Product Behavior] Implementation does send a reply message if the ActionType is ""OP_OOF_REPLY"" if action flavor is NS. (<6> Section 2.2.5.1.1:  Exchange 2007, Exchange 2010, and Exchange 2013 send a reply message if the ActionType is ""OP_OOF_REPLY"".)");

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

                // Verify MS-OXORULE requirement: MS-OXORULE_R1020
                // The recipients information is added in the reply template when it is created. Since the rule works as expected, this requirement can be captured.
                Site.CaptureRequirement(
                    1020,
                    @"[In Action Flavors] NS (Bitmask 0x00000001): [OP_OOF_REPLY ActionType] [The server SHOULD<6> not send the message to the message sender]The reply template MUST contain recipients (2) in this case [if the NS flag is set].");
            }

            #endregion
        }
        public void MSOXORULE_S03_TC08_OOFBehaviorsNotExecuteOOFReplyRuleForOOFReplySuppressMessage()
        {
            this.CheckMAPIHTTPTransportSupported();

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

            #region Create one reply template for OP_OOF_REPLY action Type in TestUser1's Inbox folder.
            ulong replyTemplateMessageID;
            uint replyTemplateMessageHandle;
            TaggedPropertyValue[] addReplyBody = new TaggedPropertyValue[1];
            addReplyBody[0] = new TaggedPropertyValue();
            PropertyTag addReplyBodyPropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagBody,
                PropertyType = (ushort)PropertyType.PtypString
            };
            addReplyBody[0].PropertyTag = addReplyBodyPropertyTag;
            string replyMessageBody = Common.GenerateResourceName(this.Site, Constants.MessageOfOOFReply);
            addReplyBody[0].Value = Encoding.Unicode.GetBytes(replyMessageBody + "\0");
            string replyTemplateSubject = Common.GenerateResourceName(this.Site, Constants.ReplyTemplateSubject);
            byte[] replyTemplateGUID = this.OxoruleAdapter.CreateReplyTemplate(this.InboxFolderHandle, this.InboxFolderID, true, replyTemplateSubject, addReplyBody, out replyTemplateMessageID, out replyTemplateMessageHandle);
            #endregion

            #region TestUser1 adds OP_OOF_REPLY rule with PidTagRuleState set to ST_ENABLED.
            ReplyActionData replyRuleActionData = new ReplyActionData
            {
                ReplyTemplateGUID = replyTemplateGUID,
                ReplyTemplateFID = this.InboxFolderID,
                ReplyTemplateMID = replyTemplateMessageID
            };

            RuleData ruleDataForReplyRule = AdapterHelper.GenerateValidRuleDataWithFlavor(ActionType.OP_OOF_REPLY, 1, RuleState.ST_ENABLED, replyRuleActionData, 0x00000000, ruleProperties);
            RopModifyRulesResponse ropModifyRulesResponse = this.OxoruleAdapter.RopModifyRules(this.InboxFolderHandle, ModifyRuleFlag.Modify_ReplaceAll, new RuleData[] { ruleDataForReplyRule });
            Site.Assert.AreEqual<uint>(0, ropModifyRulesResponse.ReturnValue, "Adding reply rule should succeed.");
            #endregion

            #region TestUser2 deliver a message by ROPs to TestUser1 to trigger these rules, and PidTagAutoResponseSuppress on the message has the 0x00000010 bit set.
            // Let Testuser2 logon to the server
            this.LogonMailbox(TestUser.TestUser2);

            TaggedPropertyValue[] mailProperty = new TaggedPropertyValue[1];
            mailProperty[0] = new TaggedPropertyValue();
            PropertyTag mailPropertyPropertyTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagAutoResponseSuppress,
                PropertyType = (ushort)PropertyType.PtypInteger32
            };
            mailProperty[0].PropertyTag = mailPropertyPropertyTag;
            mailProperty[0].Value = BitConverter.GetBytes(0x00000010);
            string mailSubject = Common.GenerateResourceName(this.Site, ruleProperties.ConditionSubjectName + "Title");
            uint submitMsgReturnValue = this.DeliverMessageToTriggerRule(this.User1Name, this.User1ESSDN, mailSubject, mailProperty);
            Site.Assert.AreEqual(0, (int)submitMsgReturnValue, "Delivering message should succeed.");
            #endregion

            #region TestUser1 gets the message sent by TestUser2.
            // TestUser1 log on to the server.
            this.LogonMailbox(TestUser.TestUser1);
            uint inboxFolderContentsTableHandle = 0;
            PropertyTag[] propertyTags = new PropertyTag[1];
            propertyTags[0].PropertyId = (ushort)PropertyId.PidTagSubject;
            propertyTags[0].PropertyType = (ushort)PropertyType.PtypString;

            uint rowCount = 0;
            RopQueryRowsResponse getInboxMailMessageContent = this.GetExpectedMessage(this.InboxFolderHandle, ref inboxFolderContentsTableHandle, propertyTags, ref rowCount, 1, mailSubject);
            Site.Assert.AreEqual<uint>(0, getInboxMailMessageContent.ReturnValue, "Getting the message should succeed.");
            #endregion

            #region TestUser2 verifies whether can receive the OOF replied message.

            // TestUser2 log on to the server.
            this.LogonMailbox(TestUser.TestUser2);
            PropertyTag[] propertyTagList = new PropertyTag[2];
            propertyTagList[0].PropertyId = (ushort)PropertyId.PidTagBody;
            propertyTagList[0].PropertyType = (ushort)PropertyType.PtypString;
            propertyTagList[1].PropertyId = (ushort)PropertyId.PidTagSubject;
            propertyTagList[1].PropertyType = (ushort)PropertyType.PtypString;
            uint contentsTableHandle = 0;
            bool doesUnexpectedMessageExist = this.CheckUnexpectedMessageExist(this.InboxFolderHandle, ref contentsTableHandle, propertyTagList, replyMessageBody, PropertyId.PidTagBody);

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

            // Verify MS-OXORULE requirement: MS-OXORULE_R533
            // TestUser2 has sent a message to TestUser1. If TestUser2 doesn't get the replied message, it means the rule is not executed. This requirement can be verified.
            Site.CaptureRequirementIfIsFalse(
                doesUnexpectedMessageExist,
                533,
                @"[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_OOF_REPLY"": The server MUST NOT send a reply if the PidTagAutoResponseSuppress property on the message has the 0x00000010 bit set.");
            #endregion
        }