The Named Property Information Format provides context to any named property tags which are present in the structure it precedes. For every distinct (unique) named property used in the structure it precedes, the Named Property Information structure MUST contain one PropId-NamedProperty pair. Each PropId field is a property ID that MUST have a value of 0x8000 or greater and uniquely identifies the named property within an extended rule.
Esempio n. 1
0
        public void MSOXORULE_S04_TC02_AddModifyDeleteExtendedRule_OnPublicFolder()
        {
            this.CheckMAPIHTTPTransportSupported();

            #region TestUser1 logs on to the public folder.
            RopOpenFolderResponse openFolderResponse;
            RopLogonResponse      logonResponse;
            bool ret = this.OxoruleAdapter.Connect(ConnectionType.PublicFolderServer, this.User1Name, this.User1ESSDN, this.User1Password);
            Site.Assert.IsTrue(ret, "connect to public folder server should be successful");
            uint publicFolderLogonHandler = this.OxoruleAdapter.RopLogon(LogonType.PublicFolder, this.User1ESSDN, out logonResponse);

            // Assert the client to log on to the public folder successfully.
            Site.Assert.AreEqual <uint>(0, logonResponse.ReturnValue, "Logon the public folder should be successful.");

            // Folder index 1 is the Interpersonal Messages subtree, and this is defined in MS-OXCSTOR.
            uint publicfolderHandler = this.OxoruleAdapter.RopOpenFolder(publicFolderLogonHandler, logonResponse.FolderIds[1], out openFolderResponse);

            // Get the store object's entry ID.
            this.GetStoreObjectEntryID(StoreObjectType.PublicFolder, this.Server, this.User1ESSDN);

            RopCreateFolderResponse createFolderResponse;
            string newFolderName   = Common.GenerateResourceName(this.Site, Constants.FolderDisplayName);
            uint   newFolderHandle = this.OxoruleAdapter.RopCreateFolder(publicfolderHandler, newFolderName, Constants.FolderComment, out createFolderResponse);
            ulong  newFolderID     = createFolderResponse.FolderId;
            Site.Assert.AreEqual <uint>(0, createFolderResponse.ReturnValue, "Creating folder operation should succeed.");
            #endregion

            #region TestUser1 creates an FAI message.
            RopCreateMessageResponse ropCreateMessageResponse;
            uint extendedRuleMessageHandle = this.OxoruleAdapter.RopCreateMessage(newFolderHandle, newFolderID, Convert.ToByte(true), out ropCreateMessageResponse);
            Site.Assert.AreEqual <uint>(0, ropCreateMessageResponse.ReturnValue, "Creating the first FAI message should succeed.");
            #endregion

            #region TestUser1 adds the extended rule with NamedProperty successfully.
            string            ruleConditionSubjectNameForAdd = Constants.RuleConditionSubjectContainString;
            NamedPropertyInfo namedPropertyInfo = new NamedPropertyInfo
            {
                NoOfNamedProps = 2,
                PropId         = new uint[2]
                {
                    0x8001, 0x8002
                }
            };
            PropertyName testPropertyName = new PropertyName
            {
                Guid = System.Guid.NewGuid().ToByteArray(),
                Kind = 0x01,
                Name = Encoding.Unicode.GetBytes(Constants.NameOfPropertyName + "\0")
            };

            // 0x01 means the property is identified by the name property.
            testPropertyName.NameSize = (byte)testPropertyName.Name.Length;

            PropertyName secondPropertyName = new PropertyName
            {
                Guid = System.Guid.NewGuid().ToByteArray(),
                Kind = 0x00,
                LID  = 0x88888888
            };

            // 0x00 means the property is identified by the LID.
            namedPropertyInfo.NamedProperty = new PropertyName[2] {
                testPropertyName, secondPropertyName
            };
            namedPropertyInfo.NamedPropertiesSize = (uint)(testPropertyName.Serialize().Length + secondPropertyName.Serialize().Length);
            string ruleName = Common.GenerateResourceName(this.Site, Constants.ExtendRulename1);
            TaggedPropertyValue[] extendedRulePropertiesForAdd = AdapterHelper.GenerateExtendedRuleTestData(ruleName, 0, (uint)RuleState.ST_ENABLED, Constants.PidTagRuleProvider, ActionType.OP_MARK_AS_READ, new DeleteMarkReadActionData(), ruleConditionSubjectNameForAdd, namedPropertyInfo);

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

            // Save changes of message.
            RopSaveChangesMessageResponse ropSaveChangesMessagResponse = this.OxoruleAdapter.RopSaveChangesMessage(extendedRuleMessageHandle);
            Site.Assert.AreEqual <uint>(0, ropSaveChangesMessagResponse.ReturnValue, "Saving Extend rule message should succeed.");

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

            // PidTagRuleMessageProvider
            propertyTagArray[0].PropertyId   = (ushort)PropertyId.PidTagRuleMessageProvider;
            propertyTagArray[0].PropertyType = (ushort)PropertyType.PtypString;

            // Get the specific properties of the extended rule.
            RopGetPropertiesSpecificResponse ropGetPropertiesSpecificResponse = this.OxoruleAdapter.RopGetPropertiesSpecific(extendedRuleMessageHandle, propertyTagArray);
            Site.Assert.AreEqual <uint>(0, ropGetPropertiesSpecificResponse.ReturnValue, "Getting specific properties operation should succeed.");
            string pidTagRuleMessageProviderData = AdapterHelper.PropertyValueConvertToString(ropGetPropertiesSpecificResponse.RowData.PropertyValues[0].Value);
            Site.Assert.AreEqual <string>(Constants.PidTagRuleProvider, pidTagRuleMessageProviderData, "The rule provider data should be RuleOrganizer.");
            #endregion

            #region Modify the created rule.
            ruleName = Common.GenerateResourceName(this.Site, Constants.ExtendRulename2);
            TaggedPropertyValue[] extendedRulePropertiesForModify = AdapterHelper.GenerateExtendedRuleTestData(ruleName, 0, (uint)RuleState.ST_ENABLED, Constants.PidTagRuleProvider, ActionType.OP_MARK_AS_READ, new DeleteMarkReadActionData(), ruleConditionSubjectNameForAdd, namedPropertyInfo);

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

            // Save changes of message.
            ropSaveChangesMessagResponse = this.OxoruleAdapter.RopSaveChangesMessage(extendedRuleMessageHandle);
            Site.Assert.AreEqual <uint>(0, ropSaveChangesMessagResponse.ReturnValue, "Saving Extend rule message should succeed.");

            // PidTagSubject
            propertyTagArray[0].PropertyId   = (ushort)PropertyId.PidTagRuleMessageName;
            propertyTagArray[0].PropertyType = (ushort)PropertyType.PtypString;

            // Get the specific properties of the extended rule.
            ropGetPropertiesSpecificResponse = this.OxoruleAdapter.RopGetPropertiesSpecific(extendedRuleMessageHandle, propertyTagArray);
            Site.Assert.AreEqual <uint>(0, ropGetPropertiesSpecificResponse.ReturnValue, "Getting specific properties operation should succeed.");
            string messageName = AdapterHelper.PropertyValueConvertToString(ropGetPropertiesSpecificResponse.RowData.PropertyValues[0].Value);
            Site.Assert.AreEqual <string>(ruleName, messageName, "The rule subject should be {0}.", ruleName);
            #endregion

            #region Release the created message to delete the created rule.
            this.OxoruleAdapter.ReleaseRop(extendedRuleMessageHandle);

            // Get the specific properties of the extended rule.
            ropGetPropertiesSpecificResponse = this.OxoruleAdapter.RopGetPropertiesSpecific(extendedRuleMessageHandle, propertyTagArray);
            Site.Assert.IsNull(ropGetPropertiesSpecificResponse.RowData, "The property value of the extended rule should be null!");
            #endregion

            #region Delete the folder.
            RopDeleteFolderResponse deleteFolder = this.OxoruleAdapter.RopDeleteFolder(publicfolderHandler, newFolderID);
            Site.Assert.AreEqual <uint>(0, deleteFolder.ReturnValue, "Deleting folder should succeed.");
            #endregion
        }
        public void MSOXORULE_S01_TC11_AddExtendedRule_OP_OOF_REPLY()
        {
            this.CheckMAPIHTTPTransportSupported();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            #region Capture Code

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

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

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

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

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

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

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

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

            // Verify MS-OXORULE requirement: MS-OXORULE_R1002.
            Site.CaptureRequirementIfIsTrue(
                isVerifiedR1002,
                1002,
                @"[OP_REPLY and OP_OOF_REPLY ActionData Structure] [Buffer Format for Extended Rules] The value of the ReplyTemplateGUID field in OP_OOF_REPLY action data is equal to the value of the PidTagReplyTemplateId property that is set on the reply template.");
            #endregion
            #endregion
        }
        public void MSOXORULE_S01_TC03_AddExtendedRule_WithLargeMessageCondition()
        {
            this.CheckMAPIHTTPTransportSupported();

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

            #region TestUser1 adds the extended rule with NamedProperty successfully.
            string ruleConditionSubjectName = Constants.RuleConditionSubjectContainString;
            NamedPropertyInfo namedPropertyInfo = new NamedPropertyInfo
            {
                NoOfNamedProps = 2,
                PropId = new uint[2]
                {
                    0x8001, 0x8002
                }
            };

            // 0x01 means the property is identified by the name property.
            PropertyName testPropertyName = new PropertyName
            {
                Guid = System.Guid.NewGuid().ToByteArray(),
                Kind = 0x01,
                Name = Encoding.Unicode.GetBytes(Constants.NameOfPropertyName + "\0")
            };
            testPropertyName.NameSize = (byte)testPropertyName.Name.Length;

            // 0x00 means the property is identified by the LID.
            PropertyName secondPropertyName = new PropertyName
            {
                Guid = System.Guid.NewGuid().ToByteArray(),
                Kind = 0x00,
                LID = 0x88888888
            };
            namedPropertyInfo.NamedProperty = new PropertyName[2] { testPropertyName, secondPropertyName };
            namedPropertyInfo.NamedPropertiesSize = (uint)(testPropertyName.Serialize().Length + secondPropertyName.Serialize().Length);
            string ruleName = Common.GenerateResourceName(this.Site, Constants.ExtendRulename1);
            TaggedPropertyValue[] extendedRuleProperties = AdapterHelper.GenerateExtendedRuleTestData(ruleName, 0, (uint)RuleState.ST_ENABLED, Constants.PidTagRuleProvider, ActionType.OP_MARK_AS_READ, new DeleteMarkReadActionData(), ruleConditionSubjectName, namedPropertyInfo);

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

            // Save changes of message.
            RopSaveChangesMessageResponse ropSaveChangesMessagResponse = this.OxoruleAdapter.RopSaveChangesMessage(extendedRuleMessageHandle);
            Site.Assert.AreEqual<uint>(0, ropSaveChangesMessagResponse.ReturnValue, "Saving Extend rule message should succeed.");

            // Specify the properties to be got. 
            PropertyTag[] propertyTagArray = new PropertyTag[2];

            // PidTagRuleMessageProviderData
            propertyTagArray[0].PropertyId = (ushort)PropertyId.PidTagRuleMessageProvider;
            propertyTagArray[0].PropertyType = (ushort)PropertyType.PtypString;

            // PidTagRuleMessageName
            propertyTagArray[1].PropertyId = (ushort)PropertyId.PidTagRuleMessageName;
            propertyTagArray[1].PropertyType = (ushort)PropertyType.PtypString;

            // Get the specific properties of the extended rule.
            RopGetPropertiesSpecificResponse ropGetPropertiesSpecificResponse = this.OxoruleAdapter.RopGetPropertiesSpecific(extendedRuleMessageHandle, propertyTagArray);
            Site.Assert.AreEqual<uint>(0, ropGetPropertiesSpecificResponse.ReturnValue, "Getting folder id property operation should succeed.");

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

            // Verify MS-OXORULE requirement: MS-OXORULE_R184
            string pidTagRuleMessageProviderData = AdapterHelper.PropertyValueConvertToString(ropGetPropertiesSpecificResponse.RowData.PropertyValues[0].Value);
            Site.CaptureRequirementIfAreEqual<string>(
                Constants.PidTagRuleProvider,
                pidTagRuleMessageProviderData,
                184,
                @"[In PidTagRuleMessageProvider Property] This property has the same semantics as the PidTagRuleProvider property (section 2.2.1.3.1.5). [The PidTagRuleMessageProvider property identifies the client application that owns the rule (2).]");

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

            // Verify MS-OXORULE requirement: MS-OXORULE_R164
            // The rule name set by client is "ExtendRulename1".
            string pidTagRuleMessageNameValue = AdapterHelper.PropertyValueConvertToString(ropGetPropertiesSpecificResponse.RowData.PropertyValues[1].Value);
            Site.CaptureRequirementIfAreEqual<string>(
                 ruleName,
                 pidTagRuleMessageNameValue,
                 164,
                 @"[In PidTagRuleMessageName Property] This property has the same semantics as the PidTagRuleName property (section 2.2.1.3.1.4). [The PidTagRuleMessageName property specifies the name of the rule (2).]");
            #endregion
            #endregion

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

            ExtendedRuleActions extendedRuleMessageActions = null;

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

            Site.Assert.AreNotEqual<ExtendedRuleActions>(null, extendedRuleMessageActions, "extendedRuleMessageActions should not be null.");

            // Get the Property Names saved by server in the extendedRuleMessageActions.
            PropertyName[] propertyNames = extendedRuleMessageActions.NamedPropertyInformation.NamedProperty;
            PropertyName testPropertyNameSavedOnServer = new PropertyName();
            PropertyName secondPropertyNameSavedOnServer = new PropertyName();
            if (propertyNames != null && propertyNames.Length > 0)
            {
                for (int i = 0; i < propertyNames.Length; i++)
                {
                    // If the Kind is 0x01, it means this PropertyName is the testPropertyName.
                    if (propertyNames[i].Kind == 0x01)
                    {
                        testPropertyNameSavedOnServer = propertyNames[i];
                    }
                    else if (propertyNames[i].Kind == 0x00)
                    {
                        // If the Kind is 0x00, it means this PropertyName is the secondPropertyName.
                        secondPropertyNameSavedOnServer = propertyNames[i];
                    }
                }
            }

            Site.Assert.IsNotNull(testPropertyNameSavedOnServer.Guid, "testPropertyNameSavedOnServer should not be null.");
            Site.Assert.IsNotNull(secondPropertyNameSavedOnServer.Guid, "secondPropertyNameSavedOnServer should not be null.");
            #endregion

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

            #region TestUser1 creates an extended rule with PidTagExtendedRuleMessageCondition property value size larger than the size set by the server.
            propertyTagArray = new PropertyTag[1];
            propertyTagArray[0].PropertyId = (ushort)PropertyId.PidTagExtendedRuleSizeLimit;
            propertyTagArray[0].PropertyType = (ushort)PropertyType.PtypInteger32;

            ropGetPropertiesSpecificResponse = this.OxoruleAdapter.RopGetPropertiesSpecific(this.LogonHandle, propertyTagArray);
            uint pidTagExtendedRuleSizeLimit = Common.ConvertByteArrayToUint(ropGetPropertiesSpecificResponse.RowData.PropertyValues[0].Value);
            
            // According to MS-OXCRPC, "The server SHOULD fail with the RPC status code of RPC_X_BAD_STUB_DATA (0x000006F7) if the request buffer is larger than 0x00040000 bytes in size."
            if (pidTagExtendedRuleSizeLimit < 0x00040000)
            {
                ruleConditionSubjectName = Constants.RuleConditionSubjectContainString;
                namedPropertyInfo = new NamedPropertyInfo
                {
                    NoOfNamedProps = 2,
                    PropId = new uint[2]
                    {
                        0x8001, 0x8002
                    }
                };

                // Generate a string value whose size lager than the one specified by the PidTagExtendedRuleSizeLimit property.
                StringBuilder stringByteValue = new StringBuilder("ExtentRuleSize");
                stringByteValue.Append('a', (int)pidTagExtendedRuleSizeLimit);

                // If the value of Kind is 0x01, it means that the property is identified by the name property.
                testPropertyName = new PropertyName
                {
                    Guid = System.Guid.NewGuid().ToByteArray(),
                    Kind = 0x01,
                    Name = Encoding.Unicode.GetBytes(stringByteValue + "\0")
                };

                testPropertyName.NameSize = (byte)testPropertyName.Name.Length;

                // If the value of Kind is 0x00, it means that the property is identified by the LID.
                secondPropertyName = new PropertyName
                {
                    Guid = System.Guid.NewGuid().ToByteArray(),
                    Kind = 0x00,
                    LID = 0x88888888
                };

                namedPropertyInfo.NamedProperty = new PropertyName[2] { testPropertyName, secondPropertyName };
                namedPropertyInfo.NamedPropertiesSize = (uint)(testPropertyName.Serialize().Length + secondPropertyName.Serialize().Length);
                extendedRuleProperties = AdapterHelper.GenerateExtendedRuleTestData(Common.GenerateResourceName(this.Site, Constants.ExtendRulename1), 0, (uint)RuleState.ST_ENABLED, Constants.PidTagRuleProvider, ActionType.OP_MARK_AS_READ, new DeleteMarkReadActionData(), ruleConditionSubjectName, namedPropertyInfo);
                TaggedPropertyValue pidTagExtendedRuleMessageCondition = new TaggedPropertyValue();
                foreach (TaggedPropertyValue propertyValue in extendedRuleProperties)
                {
                    if (propertyValue.PropertyTag.PropertyId == (ushort)PropertyId.PidTagExtendedRuleMessageCondition)
                    {
                        pidTagExtendedRuleMessageCondition = propertyValue;
                        break;
                    }
                }

                uint pidTagExtendedRuleMessageConditionSize = uint.Parse(pidTagExtendedRuleMessageCondition.Value.Length.ToString());

                // Set properties for extended rule FAI message.
                ropSetPropertiesResponse = this.OxoruleAdapter.RopSetProperties(extendedRuleMessageHandle, extendedRuleProperties);

                // Save changes of message.
                ropSaveChangesMessagResponse = this.OxoruleAdapter.RopSaveChangesMessage(extendedRuleMessageHandle);

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

                // Verify MS-OXORULE requirement: MS-OXORULE_R1016.
                if (pidTagExtendedRuleMessageConditionSize > pidTagExtendedRuleSizeLimit)
                {
                    Site.CaptureRequirementIfAreNotEqual<uint>(
                        0x0000,
                        ropSaveChangesMessagResponse.ReturnValue,
                        1016,
                        @"[In Processing Incoming Messages to a Folder] If the PidTagExtendedRuleSizeLimit property is set and the size of the PidTagExtendedRuleMessageCondition property (section 2.2.4.1.10) exceeds the value specified by the PidTagExtendedRuleSizeLimit property, the server MUST return an error.");
                }
                else
                {
                    Site.Assert.Fail("The size of the PidTagExtendedRuleMessageCondition property should exceeds the value specified by the PidTagExtendedRuleSizeLimit property.");
                }
            }
            #endregion
        }
        public void MSOXORULE_S01_TC09_AddExtendedRuleForThreeTimes()
        {
            this.CheckMAPIHTTPTransportSupported();
            Site.Assume.IsTrue(Common.IsRequirementEnabled(646, this.Site), "This case runs only when the server supports processing more than two extended rules it encounters per folder.");

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

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

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

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

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

            ExtendedRuleActions extendedRuleMessageActions = new ExtendedRuleActions();

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

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

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

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

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

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

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

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

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

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

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

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

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

            #endregion

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            #region TestUser1 creates folder1 in server store.
            RopCreateFolderResponse createFolderResponse;
            uint newFolderHandle = this.OxoruleAdapter.RopCreateFolder(this.InboxFolderHandle, Common.GenerateResourceName(this.Site, "User1Folder01"), "TestForOP_COPY", out createFolderResponse);
            ulong newFolderId = createFolderResponse.FolderId;
            Site.Assert.AreEqual<uint>(0, createFolderResponse.ReturnValue, "Creating folder operation should succeed.");
            #endregion

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            // TestUser2 deliver a message to trigger these rules.
            string mailSubject = Common.GenerateResourceName(this.Site, ruleProperties.ConditionSubjectName + "Title");
            this.SUTAdapter.SendMailToRecipient(this.User2Name, this.User2Password, this.User1Name, mailSubject);

            // Wait for the mail to be received and the rule to take effect.
            Thread.Sleep(this.WaitForTheRuleToTakeEffect);
            #endregion

            #region TestUser1 gets the message content to verify the rule evaluation.
            uint inboxFolderContentsTableHandle = 0;
            PropertyTag[] propertyTagList = new PropertyTag[1];
            propertyTagList[0].PropertyId = (ushort)PropertyId.PidTagSubject;
            propertyTagList[0].PropertyType = (ushort)PropertyType.PtypString;

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

            #region Capture code

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

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

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

            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR969,
                969,
                @"[In OP_MOVE and OP_COPY ActionData Structure] [Buffer Format for Extended Rules] The destination folder for a Copy action in an extended rule MUST be in the user's mailbox.");
            #endregion
            #endregion

            #region Delete the newly created folder.
            RopDeleteFolderResponse deleteFolder = this.OxoruleAdapter.RopDeleteFolder(this.InboxFolderHandle, newFolderId);
            Site.Assert.AreEqual<uint>(0, deleteFolder.ReturnValue, "Deleting folder should succeed.");
            #endregion
        }
        /// <summary>
        /// Generate test data for creating extended rule.
        /// </summary>
        /// <param name="rulename">The rule name.</param>
        /// <param name="ruleSequence">The rule sequence.</param>
        /// <param name="ruleState">The rule state.</param>
        /// <param name="provider">The rule provider.</param>
        /// <param name="actionType">The rule action Type.</param>
        /// <param name="actionData">The rule action data.</param>
        /// <param name="contentRestrictSubjectName">The subject name of the rule content restriction.</param>
        /// <param name="namedPropertyInfo">The namedPropertyInfo that needed for construct the rule data.</param>
        /// <returns>An array of TaggedPropertyValue of an extended rule.</returns>
        public static TaggedPropertyValue[] GenerateExtendedRuleTestData(string rulename, int ruleSequence, uint ruleState, string provider, ActionType actionType, IActionData actionData, string contentRestrictSubjectName, NamedPropertyInfo namedPropertyInfo)
        {
            List<TaggedPropertyValue> propList = new List<TaggedPropertyValue>();
            TaggedPropertyValue pidTagRuleMessageName = new TaggedPropertyValue();
            PropertyTag pidTagRuleMessageNameTag = new PropertyTag
            {
                PropertyId = (ushort)PropertyId.PidTagRuleMessageName,
                PropertyType = (ushort)PropertyType.PtypString
            };
            pidTagRuleMessageName.PropertyTag = pidTagRuleMessageNameTag;
            pidTagRuleMessageName.Value = Encoding.Unicode.GetBytes(rulename + "\0");
            propList.Add(pidTagRuleMessageName);

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

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

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

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

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

            ExtendedRuleActions extendedRuleActions = new ExtendedRuleActions
            {
                NamedPropertyInformation = namedPropertyInfo
            };

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

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

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

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

            ExtendedRuleCondition extendedRuleCondition = new ExtendedRuleCondition
            {
                NamedPropertyInformation = namedPropertyInfo,
                RuleRestriction = contentRestriction
            };
            pidTagExtendedRuleMessageCondition.Value = Common.AddInt16LengthBeforeBinaryArray(extendedRuleCondition.Serialize());
            propList.Add(pidTagExtendedRuleMessageCondition);
            return propList.ToArray();
        }
        /// <summary>
        /// Verify NamedPropertyInformation buffer.
        /// </summary>
        /// <param name="namedPropertyInformation">NamedPropertyInfo structure to be verified.</param>
        private void VerifyNamedPropertyInformation(NamedPropertyInfo namedPropertyInformation)
        {
            // propIds indicates a list of Property Ids of the named property used in the Named Property Information structure it precedes.
            uint[] propIds = namedPropertyInformation.PropId;
            uint namedPropertiesCount = 0;

            // namedProperties indicates a list of Property Names of the named property used in the Named Property Information structure it precedes.
            PropertyName[] namedProperties = namedPropertyInformation.NamedProperty;
            if (namedProperties != null)
            {
                foreach (PropertyName propertyName in namedProperties)
                {
                    this.VerifyPropertyName(propertyName);
                    namedPropertiesCount++;
                }

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

                // Verify MS-OXORULE requirement: MS-OXORULE_R940.
                Site.CaptureRequirement(
                    940,
                    @"[In NamedPropertyInformation Structure] NamedProperties (variable): An array of PropertyName structures.");

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

                // Verify MS-OXORULE requirement: MS-OXORULE_R221.
                Site.CaptureRequirementIfAreEqual<uint>(
                    namedPropertiesCount,
                    namedPropertyInformation.NoOfNamedProps,
                    221,
                    @"[In NamedPropertyInformation Structure] NoOfNamedProps (2 bytes): An integer that specifies the number of named property mappings that are packed in this structure [NamedPropertyInformation].");

                if (namedPropertyInformation.NoOfNamedProps > 0)
                {
                    // Add the debug information.
                    Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R225");

                    // Verify MS-OXORULE requirement: MS-OXORULE_R225.
                    uint sizeOfNamedProperty = 0;
                    for (int i = 0; i < namedPropertiesCount; i++)
                    {
                        sizeOfNamedProperty += Convert.ToUInt32(namedProperties[i].Size());
                    }

                    Site.CaptureRequirementIfAreEqual<uint>(
                        sizeOfNamedProperty,
                        namedPropertyInformation.NamedPropertiesSize,
                        225,
                        @"[In NamedPropertyInformation Structure] NamedPropertiesSize (4 bytes): The total size, in bytes, of the following fields [NamedProperties].");
                }
            }

            // According to open specification, the Named Property Information structure must contain the PropId-NamedProperty pair.
            // So if some named properties are used, the corresponding property Ids of these named properties must exist,
            // or else, both of them are null.
            // If the named properties are actually used.
            if (propIds != null && namedProperties != null)
            {
                // Add the debug information.
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R217, the number of propIds is {0}, the number of namedProperties is {1}", propIds.Length, namedProperties.Length);

                // Verify MS-OXORULE requirement: MS-OXORULE_R217
                // If the number of PropId and NamedProperty are the same, it means the Named Property Information structure contains a list of PropId-NamedProperty pair,
                // and each pair represents a distinct named property used in the structure it precedes.
                Site.CaptureRequirementIfAreEqual<int>(
                    propIds.Length,
                    namedProperties.Length,
                    217,
                    @"[In NamedPropertyInformation Structure] For every distinct (unique) named property used in the structure it precedes, the NamedPropertyInformation structure contains one property ID - named property pair.");

                // Add the debug information.
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R938, the number of propIds is {0}, the number of namedProperties is {1}", propIds.Length, namedProperties.Length);

                // Verify MS-OXORULE requirement: MS-OXORULE_R938
                // If the number of PropId and NamedProperty are the same, it means there are one property ID in PropIds array for each PropertyName structure in the NamedProperties field.
                Site.CaptureRequirementIfAreEqual<int>(
                    propIds.Length,
                    namedProperties.Length,
                    938,
                    @"[In NamedPropertyInformation Structure] There MUST be one property ID in this array [PropIds] for each PropertyName structure in the NamedProperties field.");

                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R218");

                // Verify MS-OXORULE requirement: MS-OXORULE_R218.
                bool isVerifyR218 = true;

                // To verify whether each property ID is less than 0x8000.
                foreach (uint propId in propIds)
                {
                    if (propId < 0x8000)
                    {
                        isVerifyR218 = false;
                    }
                }

                // If there doesn't contain the same value in the propIds array, IsContainSameValue(propIds) equals to false,
                // which means each property Id uniquely identifies the named property within an extended rule. 
                isVerifyR218 = isVerifyR218 && (AdapterHelper.IsContainSameValue(propIds) == false);
                Site.CaptureRequirementIfIsTrue(
                    isVerifyR218,
                    218,
                    @"[In NamedPropertyInformation Structure] PropIds (variable): An array of property IDs, each of which is a value of 0x8000 or greater.");
            }

            if (namedPropertyInformation.NoOfNamedProps > 0)
            {
                // Add the debug information.
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXORULE_R226");

                // Verify MS-OXORULE requirement: MS-OXORULE_R226.
                // NamedPropertiesSize is not zero means it is present.
                Site.CaptureRequirementIfAreNotEqual<uint>(
                    0x00000000,
                    namedPropertyInformation.NamedPropertiesSize,
                    226,
                    @"[In NamedPropertyInformation Structure] NamedPropertiesSize (4 bytes): Only present if NoOfNamedProps is greater than zero.");
            }
        }
        public void MSOXORULE_S04_TC02_AddModifyDeleteExtendedRule_OnPublicFolder()
        {
            this.CheckMAPIHTTPTransportSupported();

            #region TestUser1 logs on to the public folder.
            RopOpenFolderResponse openFolderResponse;
            RopLogonResponse logonResponse;
            bool ret = this.OxoruleAdapter.Connect(ConnectionType.PublicFolderServer, this.User1Name, this.User1ESSDN, this.User1Password);
            Site.Assert.IsTrue(ret, "connect to public folder server should be successful");
            uint publicFolderLogonHandler = this.OxoruleAdapter.RopLogon(LogonType.PublicFolder, this.User1ESSDN, out logonResponse);

            // Assert the client to log on to the public folder successfully.
            Site.Assert.AreEqual<uint>(0, logonResponse.ReturnValue, "Logon the public folder should be successful.");

            // Folder index 1 is the Interpersonal Messages subtree, and this is defined in MS-OXCSTOR.
            uint publicfolderHandler = this.OxoruleAdapter.RopOpenFolder(publicFolderLogonHandler, logonResponse.FolderIds[1], out openFolderResponse);

            // Get the store object's entry ID.
            this.GetStoreObjectEntryID(StoreObjectType.PublicFolder, this.Server, this.User1ESSDN);

            RopCreateFolderResponse createFolderResponse;
            string newFolderName = Common.GenerateResourceName(this.Site, Constants.FolderDisplayName);
            uint newFolderHandle = this.OxoruleAdapter.RopCreateFolder(publicfolderHandler, newFolderName, Constants.FolderComment, out createFolderResponse);
            ulong newFolderID = createFolderResponse.FolderId;
            Site.Assert.AreEqual<uint>(0, createFolderResponse.ReturnValue, "Creating folder operation should succeed.");
            #endregion

            #region TestUser1 creates an FAI message.
            RopCreateMessageResponse ropCreateMessageResponse;
            uint extendedRuleMessageHandle = this.OxoruleAdapter.RopCreateMessage(newFolderHandle, newFolderID, Convert.ToByte(true), out ropCreateMessageResponse);
            Site.Assert.AreEqual<uint>(0, ropCreateMessageResponse.ReturnValue, "Creating the first FAI message should succeed.");
            #endregion

            #region TestUser1 adds the extended rule with NamedProperty successfully.
            string ruleConditionSubjectNameForAdd = Constants.RuleConditionSubjectContainString;
            NamedPropertyInfo namedPropertyInfo = new NamedPropertyInfo
            {
                NoOfNamedProps = 2,
                PropId = new uint[2]
                {
                    0x8001, 0x8002
                }
            };
            PropertyName testPropertyName = new PropertyName
            {
                Guid = System.Guid.NewGuid().ToByteArray(),
                Kind = 0x01,
                Name = Encoding.Unicode.GetBytes(Constants.NameOfPropertyName + "\0")
            };

            // 0x01 means the property is identified by the name property.
            testPropertyName.NameSize = (byte)testPropertyName.Name.Length;

            PropertyName secondPropertyName = new PropertyName
            {
                Guid = System.Guid.NewGuid().ToByteArray(),
                Kind = 0x00,
                LID = 0x88888888
            };

            // 0x00 means the property is identified by the LID.
            namedPropertyInfo.NamedProperty = new PropertyName[2] { testPropertyName, secondPropertyName };
            namedPropertyInfo.NamedPropertiesSize = (uint)(testPropertyName.Serialize().Length + secondPropertyName.Serialize().Length);
            string ruleName = Common.GenerateResourceName(this.Site, Constants.ExtendRulename1);
            TaggedPropertyValue[] extendedRulePropertiesForAdd = AdapterHelper.GenerateExtendedRuleTestData(ruleName, 0, (uint)RuleState.ST_ENABLED, Constants.PidTagRuleProvider, ActionType.OP_MARK_AS_READ, new DeleteMarkReadActionData(), ruleConditionSubjectNameForAdd, namedPropertyInfo);

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

            // Save changes of message.
            RopSaveChangesMessageResponse ropSaveChangesMessagResponse = this.OxoruleAdapter.RopSaveChangesMessage(extendedRuleMessageHandle);
            Site.Assert.AreEqual<uint>(0, ropSaveChangesMessagResponse.ReturnValue, "Saving Extend rule message should succeed.");

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

            // PidTagRuleMessageProvider
            propertyTagArray[0].PropertyId = (ushort)PropertyId.PidTagRuleMessageProvider;
            propertyTagArray[0].PropertyType = (ushort)PropertyType.PtypString;

            // Get the specific properties of the extended rule.
            RopGetPropertiesSpecificResponse ropGetPropertiesSpecificResponse = this.OxoruleAdapter.RopGetPropertiesSpecific(extendedRuleMessageHandle, propertyTagArray);
            Site.Assert.AreEqual<uint>(0, ropGetPropertiesSpecificResponse.ReturnValue, "Getting specific properties operation should succeed.");
            string pidTagRuleMessageProviderData = AdapterHelper.PropertyValueConvertToString(ropGetPropertiesSpecificResponse.RowData.PropertyValues[0].Value);
            Site.Assert.AreEqual<string>(Constants.PidTagRuleProvider, pidTagRuleMessageProviderData, "The rule provider data should be RuleOrganizer.");
            #endregion

            #region Modify the created rule.
            ruleName = Common.GenerateResourceName(this.Site, Constants.ExtendRulename2);
            TaggedPropertyValue[] extendedRulePropertiesForModify = AdapterHelper.GenerateExtendedRuleTestData(ruleName, 0, (uint)RuleState.ST_ENABLED, Constants.PidTagRuleProvider, ActionType.OP_MARK_AS_READ, new DeleteMarkReadActionData(), ruleConditionSubjectNameForAdd, namedPropertyInfo);

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

            // Save changes of message.
            ropSaveChangesMessagResponse = this.OxoruleAdapter.RopSaveChangesMessage(extendedRuleMessageHandle);
            Site.Assert.AreEqual<uint>(0, ropSaveChangesMessagResponse.ReturnValue, "Saving Extend rule message should succeed.");

            // PidTagSubject
            propertyTagArray[0].PropertyId = (ushort)PropertyId.PidTagRuleMessageName;
            propertyTagArray[0].PropertyType = (ushort)PropertyType.PtypString;

            // Get the specific properties of the extended rule.
            ropGetPropertiesSpecificResponse = this.OxoruleAdapter.RopGetPropertiesSpecific(extendedRuleMessageHandle, propertyTagArray);
            Site.Assert.AreEqual<uint>(0, ropGetPropertiesSpecificResponse.ReturnValue, "Getting specific properties operation should succeed.");
            string messageName = AdapterHelper.PropertyValueConvertToString(ropGetPropertiesSpecificResponse.RowData.PropertyValues[0].Value);
            Site.Assert.AreEqual<string>(ruleName, messageName, "The rule subject should be {0}.", ruleName);
            #endregion

            #region Release the created message to delete the created rule.
            this.OxoruleAdapter.ReleaseRop(extendedRuleMessageHandle);

            // Get the specific properties of the extended rule.
            ropGetPropertiesSpecificResponse = this.OxoruleAdapter.RopGetPropertiesSpecific(extendedRuleMessageHandle, propertyTagArray);
            Site.Assert.IsNull(ropGetPropertiesSpecificResponse.RowData, "The property value of the extended rule should be null!");
            #endregion

            #region Delete the folder.
            RopDeleteFolderResponse deleteFolder = this.OxoruleAdapter.RopDeleteFolder(publicfolderHandler, newFolderID);
            Site.Assert.AreEqual<uint>(0, deleteFolder.ReturnValue, "Deleting folder should succeed.");
            #endregion
        }