public void MSOXCFOLD_S04_TC01_PublicFolderNonGhostedFolderValidation()
        {
            this.CheckWhetherSupportTransport();
            this.Logon();
            this.PublicFolderInitialization();

            RopCreateFolderRequest createFolderRequest;
            RopCreateFolderResponse createFolderResponse;

            #region Step 1. The client calls RopCreateFolder to create a search folder named [MSOXCFOLDSearchFolder1] under the root public folder.
            createFolderRequest = new RopCreateFolderRequest()
            {
                RopId = (byte)RopId.RopCreateFolder,
                LogonId = Constants.CommonLogonId,
                InputHandleIndex = Constants.CommonInputHandleIndex,
                OutputHandleIndex = Constants.CommonOutputHandleIndex,
                FolderType = (byte)FolderType.Searchfolder,
                UseUnicodeStrings = 0x0,
                OpenExisting = 0x01,
                Reserved = 0x0,
                DisplayName = Encoding.ASCII.GetBytes(Constants.SearchFolder),
                Comment = Encoding.ASCII.GetBytes(Constants.SearchFolder)
            };
            object response = null;
            uint result = this.Adapter.DoRopCall(createFolderRequest, this.publicRootFolderHandle, ref response, ref this.responseHandles);

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

                // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R10660201
                Site.CaptureRequirementIfAreEqual<uint>(
                    0x80004005,
                    result,
                    10660201,
                    @"[In Appendix A: Product Behavior] If the ROP was called to create a search folder on a public folders message store, the implemetation does return ecError <12> Section 3.2.5.2:  Exchange 2010 and Exchange 2007 return ecError.");
            }

            if (Common.IsRequirementEnabled(10660202, this.Site))
            {
                createFolderResponse = (RopCreateFolderResponse)response;

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

                // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R10660202
                Site.CaptureRequirementIfAreEqual<uint>(
                    0x80040102,
                    createFolderResponse.ReturnValue,
                    10660202,
                    @"[In Appendix A: Product Behavior] If the ROP was called to create a search folder on a public folders message store, the implemetation does return ecNotSupported. <12> Exchange 2013 and Exchange 2016 return ecNotSupported.");
            }
            #endregion

            #region Step 2. The client calls RopCreateFolder to create a generic folder named [MSOXCFOLDSubfolder1].

            uint subfolderHandle1 = 0;
            ulong subfolderId1 = 0;
            createFolderResponse = this.CreateFolder(this.publicRootFolderHandle, Constants.Subfolder1, ref subfolderId1, ref subfolderHandle1);

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

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R3802
            Site.CaptureRequirementIfAreEqual<uint>(
                Constants.SuccessCode,
                createFolderResponse.ReturnValue,
                3802,
                @"[In RopCreateFolder ROP] The folder can be either a public folder [or a private mailbox folder].");

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

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R61.
            Site.CaptureRequirementIfAreEqual<byte>(
                0x00,
                createFolderResponse.IsExistingFolder,
                61,
                @"[RopCreateFolder ROP Response Buffer] IsExistingFolder (1 byte): The value is zero (FALSE) if a public folder with that name does not exist.");

            byte isExistingFolder = createFolderResponse.IsExistingFolder;
            bool isHasRulesInExistingFolder = createFolderResponse.HasRules == null;
            bool isIsGhostedInExistingFolder = createFolderResponse.IsGhosted == null;
            #endregion

            #region Step 3. The client calls RopOpenFolder to open folder named [MSOXCFOLDSubfolder1].
            RopOpenFolderRequest openFolderRequest = new RopOpenFolderRequest
            {
                RopId = (byte)RopId.RopOpenFolder,
                LogonId = Constants.CommonLogonId,
                InputHandleIndex = Constants.CommonInputHandleIndex,
                OutputHandleIndex = Constants.CommonOutputHandleIndex,
                OpenModeFlags = (byte)FolderOpenModeFlags.None,
                FolderId = subfolderId1
            };
            RopOpenFolderResponse openFolderResponse = this.Adapter.OpenFolder(openFolderRequest, this.publicLogonHandle, ref this.responseHandles);

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

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R90002
            Site.CaptureRequirementIfAreEqual<uint>(
                Constants.SuccessCode,
                openFolderResponse.ReturnValue,
                90002,
                @"[In RopOpenFolder ROP] The folder can be either a public folder [or a private mailbox folder].");

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

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R30
            Site.CaptureRequirementIfIsNotNull(
                openFolderResponse.IsGhosted,
                30,
                @"[In RopOpenFolder ROP Response Buffer] IsGhosted (1 byte): This field [IsGhosted] is present only for folders that are in a public store.");

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

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R29.
            Site.CaptureRequirementIfAreEqual<byte?>(
                0x00,
                openFolderResponse.IsGhosted,
                29,
                @"[In RopOpenFolder ROP Response Buffer] IsGhosted (1 byte): otherwise [If the server hosts an active replica of the folder], this field [IsGhosted] is set to zero (FALSE).");
            #endregion

            #region Step 4. The client calls RopCreateFolder to create [MSOXCFOLD_PublicFolderMailEnabled] which is an existing folder with 'OpeningExisting' flag set to non-zero.

            string folderDisplayName = Common.GetConfigurationPropertyValue("MailEnabledPublicFolder", this.Site) + Constants.StringNullTerminated;
            createFolderRequest = new RopCreateFolderRequest()
            {
                RopId = (byte)RopId.RopCreateFolder,
                LogonId = Constants.CommonLogonId,
                InputHandleIndex = Constants.CommonInputHandleIndex,
                OutputHandleIndex = Constants.CommonOutputHandleIndex,
                FolderType = (byte)FolderType.Genericfolder,
                UseUnicodeStrings = 0x1,
                OpenExisting = 0x01,
                Reserved = 0x0,
                DisplayName = Encoding.Unicode.GetBytes(folderDisplayName),
                Comment = Encoding.Unicode.GetBytes(folderDisplayName)
            };

            // Invoke the CreateFolder operation with valid parameters, use root folder handle to indicate that the new folder will be created under the root folder.
            createFolderResponse = this.Adapter.CreateFolder(createFolderRequest, this.publicFoldersHandle, ref this.responseHandles);

            Site.Assert.AreEqual<uint>(Constants.SuccessCode, createFolderResponse.ReturnValue, "RopCreateFolder ROP operation performs successfully!");

            subfolderHandle1 = this.responseHandles[0][createFolderResponse.OutputHandleIndex];
 
            if (Common.IsRequirementEnabled(60001, this.Site))
            {
                // Regardless of the existence of the named public folder, if the IsExistingFolder in response is always set to zero, R60001 can be verified.
                bool isR60001Verified = isExistingFolder == 0 && createFolderResponse.IsExistingFolder == 0;
                
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCFOLD_R60001, regardless of the existence of the public folder, the IsExistingFolder in response should be always set to {0}, actually, when public folder exists the IsExistingFolder in response is {1}, when public folder does not exist the IsExistingFolder in response is {2}.", 0, createFolderResponse.IsExistingFolder, isExistingFolder);

                // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R60001
                Site.CaptureRequirementIfIsTrue(
                    isR60001Verified,
                    60001,
                    @"[In Appendix A: Product Behavior] Implementation does return zero (FALSE) in the IsExistingFolder field regardless of the existence of the named public folder. <3> Section 2.2.1.2.2: Exchange 2010 Exchange 2013 and Exchange 2016 always return zero (FALSE) in the IsExistingFolder field regardless of the existence of the named public folder.");
            }

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

                // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R60002.
                Site.CaptureRequirementIfAreNotEqual<byte>(
                    0x00,
                    createFolderResponse.IsExistingFolder,
                    60002,
                    @"[In Appendix A: Product Behavior] If a public folder with the name given by the DisplayName field of the request buffer already exists, implementation does set a nonzero (TRUE) value to IsExistingFolder field. (Microsoft Exchange Server 2007 follows this behavior.)");

                bool isHasRules = createFolderResponse.HasRules != null;
                bool isIsGhosted = createFolderResponse.IsGhosted != null;
                bool isR926Verified = isHasRules && isHasRulesInExistingFolder;
                bool isR931Verified = isIsGhosted && isIsGhostedInExistingFolder;

                // Add the debug information.
                Site.Log.Add(
                    LogEntryKind.Debug,
                    @"Verify MS-OXCFOLD_R926: When the IsExistingFolder field is set to a zero, the compare result of HasRules and null is {0}; When the IsExistingFolder field is set to a nonzero, the compare result of HasRules and null is {1}",
                    isHasRulesInExistingFolder,
                    isHasRules);

                // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R926.
                Site.CaptureRequirementIfIsTrue(
                    isR926Verified,
                    926,
                    @"[In RopCreateFolder ROP Response Buffer] This field [HasRules] is present only if the IsExistingFolder field is set to a nonzero (TRUE) value.");

                // Add the debug information.
                Site.Log.Add(
                    LogEntryKind.Debug,
                    @"Verify MS-OXCFOLD_R931: When the IsExistingFolder field is set to a zero, the compare result of IsGhosted and null is {0}; When the IsExistingFolder field is set to a nonzero, the compare result of IsGhosted and null is {1}",
                    isIsGhostedInExistingFolder,
                    isIsGhosted);

                // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R931.
                Site.CaptureRequirementIfIsTrue(
                    isR931Verified,
                    931,
                    @"[In RopCreateFolder ROP Response Buffer] This field [IsGhosted] is present only if the IsExistingFolder field is set to a nonzero (TRUE) value and only for folders that are in a public message store.");

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

                // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R68.
                Site.CaptureRequirementIfAreEqual<byte?>(
                    0x00,
                    createFolderResponse.IsGhosted,
                    68,
                    @"[In RopCreateFolder ROP Response Buffer] IsGhosted (1 byte): otherwise [If the server hosts an active replica of the folder], this field [IsGhosted] is set to zero (FALSE).");
            }
            #endregion

            #region Step 5. The client gets the PidTagAddressBookEntryId property of the [MSOXCFOLD_PublicFolderMailEnabled].
            if (Common.IsRequirementEnabled(350002, this.Site))
            {
                PropertyTag[] propertyTagArray = new PropertyTag[1];
                PropertyTag propertyTag = new PropertyTag
                {
                    PropertyId = (ushort)FolderPropertyId.PidTagAddressBookEntryId,
                    PropertyType = (ushort)PropertyType.PtypBinary
                };
                propertyTagArray[0] = propertyTag;

                RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest();
                RopGetPropertiesSpecificResponse getPropertiesSpecificResponse;
                getPropertiesSpecificRequest.RopId = (byte)RopId.RopGetPropertiesSpecific;
                getPropertiesSpecificRequest.LogonId = Constants.CommonLogonId;
                getPropertiesSpecificRequest.InputHandleIndex = Constants.CommonInputHandleIndex;
                getPropertiesSpecificRequest.PropertySizeLimit = 0xFFFF;
                getPropertiesSpecificRequest.PropertyTagCount = (ushort)propertyTagArray.Length;
                getPropertiesSpecificRequest.PropertyTags = propertyTagArray;

                getPropertiesSpecificResponse = this.Adapter.GetFolderObjectSpecificProperties(getPropertiesSpecificRequest, subfolderHandle1, ref this.responseHandles);
                Site.Assert.AreEqual<uint>(0, getPropertiesSpecificResponse.ReturnValue, "RopGetPropertiesSpecific ROP operation performs successfully!");

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

                // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R350002.
                // The property value is returned if Flag value is 0x00.
                Site.CaptureRequirementIfAreEqual<byte>(
                    0x00,
                    getPropertiesSpecificResponse.RowData.Flag,
                    350002,
                    @"[In Appendix A: Product Behavior] The implementation does support the PidTagAddressBookEntryId property. (Exchange 2007 and Exchange 2010 follow this behavior).");

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

                // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R350.
                // The property value is returned if Flag value is 0x00.
                Site.CaptureRequirementIfAreEqual<byte>(
                    0x00,
                    getPropertiesSpecificResponse.RowData.Flag,
                    350,
                    @"[In PidTagAddressBookEntryId Property] This property is set only for public folders.");
            }
            #endregion

            #region Step 6. The client calls RopGetPropertiesAll on [MSOXCFOLD_PublicFolderGhosted].
            RopGetPropertiesAllResponse getAllPropertiesResponse = this.Adapter.GetFolderPropertiesAll(subfolderHandle1, ref this.responseHandles);
            Site.Assert.AreEqual<uint>(0, getAllPropertiesResponse.ReturnValue, "RopGetPropertiesAllResponse ROP operation performs successfully!");
            #endregion
        }
        public void MSOXCMSG_S07_TC01_RopModifyRemoveRecipientSuccessfully()
        {
            this.CheckMapiHttpIsSupported();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);

            #region Call RopLogon to log on a mailbox.
            RopLogonResponse logonResponse = this.Logon(LogonType.Mailbox, out this.insideObjHandle);
            #endregion

            #region Call RopCreateMessage to create a message
            uint targetMessageHandle = this.CreatedMessage(logonResponse.FolderIds[4], this.insideObjHandle);
            #endregion

            #region Call RopSaveChangesMessage to save the message
            RopSaveChangesMessageResponse saveChangesMessageResponse;
            saveChangesMessageResponse = this.SaveMessage(targetMessageHandle, (byte)SaveFlags.ForceSave);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, saveChangesMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopOpenMessage to open the message.
            RopOpenMessageResponse openMessageResponse;
            uint openedMessageHandle = this.OpenSpecificMessage(logonResponse.FolderIds[4], saveChangesMessageResponse.MessageId, this.insideObjHandle, MessageOpenModeFlags.ReadWrite, out openMessageResponse);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, openMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopRemoveAllRecipients to remove all recipients of the newly created message in step 2, and expected to get a successful response.
            RopRemoveAllRecipientsRequest removeAllRecipientsRequest = new RopRemoveAllRecipientsRequest()
            {
                RopId = (byte)RopId.RopRemoveAllRecipients,
                LogonId = CommonLogonId, // The logonId 0x00 is associated with RopRemoveAllRecipients.
                InputHandleIndex = CommonInputHandleIndex, // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the input Server Object is stored. 
                Reserved = 0x00000000
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(removeAllRecipientsRequest, openedMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopRemoveAllRecipientsResponse removeAllRecipientsResponse = (RopRemoveAllRecipientsResponse)this.response;

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R1491
            this.Site.CaptureRequirementIfAreEqual<uint>(
                TestSuiteBase.Success,
                removeAllRecipientsResponse.ReturnValue,
                1491,
                @"[In Receiving a RopRemoveAllRecipients ROP Request] The call to the RopRemoveAllRecipients ROP succeeds even if the Message object on which it is executed has no recipients (2).");
            #endregion

            #region Call RopModifyRecipients to modify the recipient and expect a successful response.
            PropertyTag[] propertyTag = null;
            ModifyRecipientRow[] modifyRecipientRow = null;
            this.CreateRecipientColumnsAndRecipientRows(out propertyTag, out modifyRecipientRow);

            RopModifyRecipientsRequest modifyRecipientsRequest = new RopModifyRecipientsRequest()
            {
                RopId = (byte)RopId.RopModifyRecipients,
                LogonId = CommonLogonId, // The logonId 0x00 is associated with RopModifyRecipients.
                InputHandleIndex = CommonInputHandleIndex, // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the input Server Object is stored. In example, the value is 0x08
                ColumnCount = Convert.ToUInt16(propertyTag.Length),
                RowCount = Convert.ToUInt16(modifyRecipientRow.Length),
                RecipientColumns = propertyTag,
                RecipientRows = modifyRecipientRow
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(modifyRecipientsRequest, openedMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopModifyRecipientsResponse modifyRecipientsResponse = (RopModifyRecipientsResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, modifyRecipientsResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopSaveChangesMessage to save the changes of the message.
            saveChangesMessageResponse = this.SaveMessage(openedMessageHandle, (byte)SaveFlags.ForceSave);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, saveChangesMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopOpenMessage to open the message.
            openedMessageHandle = this.OpenSpecificMessage(logonResponse.FolderIds[4], saveChangesMessageResponse.MessageId, this.insideObjHandle, MessageOpenModeFlags.ReadWrite, out openMessageResponse);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, openMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopRemoveAllRecipients to remove all recipients.
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(removeAllRecipientsRequest, openedMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            removeAllRecipientsResponse = (RopRemoveAllRecipientsResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, removeAllRecipientsResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopGetPropertiesSpecific to get property PidTagRowid.

            // Prepare property Tag 
            PropertyTag[] tagArray = this.GetModifiedProperties();

            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest()
            {
                RopId = (byte)RopId.RopGetPropertiesSpecific,
                LogonId = CommonLogonId, // The logonId 0x00 is associated with RopGetPropertiesSpecific.
                InputHandleIndex = CommonInputHandleIndex, // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the input Server Object is stored. 
                PropertySizeLimit = 0xFFFF, // This value specifies the maximum number of the property
                PropertyTagCount = (ushort)tagArray.Length,
                PropertyTags = tagArray,
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, openedMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

            List<PropertyObj> ps = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);

            // Parse getPropertiesSpecificResponse to get the value of properties which are modified when calling RopModifyRecipients to verify MS-OXCMSG_R381.
            PropertyObj pidTagRowid = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagRowid);
            PropertyObj pidTagDisplayType = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagDisplayType);
            PropertyObj pidTagAddressBookDisplayNamePrintable = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagAddressBookDisplayNamePrintable);
            PropertyObj pidTagSmtpAddress = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagSmtpAddress);
            PropertyObj pidTagSendInternetEncoding = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagSendInternetEncoding);
            PropertyObj pidTagDisplayTypeEx = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagDisplayTypeEx);
            PropertyObj pidTagRecipientDisplayName = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagRecipientDisplayName);
            PropertyObj pidTagRecipientFlags = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagRecipientFlags);
            PropertyObj pidTagRecipientTrackStatus = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagRecipientTrackStatus);
            PropertyObj pidTagRecipientResourceState = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagRecipientResourceState);
            PropertyObj pidTagRecipientOrder = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagRecipientOrder);
            PropertyObj pidTagRecipientEntryId = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagRecipientEntryId);

            // Add the debug information
            this.Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-OXCMSG_R381. pidTagRowid = {0}, pidTagDisplayType = {1}, pidTagAddressBookDisplayNamePrintable = {2}, pidTagSmtpAddress = {3}, pidTagSendInternetEncoding = {4}, pidTagDisplayTypeEx = {5}, pidTagRecipientDisplayName = {6}, pidTagRecipientFlags = {7}, pidTagRecipientTrackStatus {8}, pidTagRecipientResourceState = {9}, pidTagRecipientOrder = {10}, pidTagRecipientEntryId = {11}",
                pidTagRowid,
                pidTagDisplayType,
                pidTagAddressBookDisplayNamePrintable,
                pidTagSmtpAddress,
                pidTagSendInternetEncoding,
                pidTagDisplayTypeEx,
                pidTagRecipientDisplayName,
                pidTagRecipientFlags,
                pidTagRecipientTrackStatus,
                pidTagRecipientResourceState,
                pidTagRecipientOrder,
                pidTagRecipientEntryId);

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R381
            bool isVerifiedR381 = (pidTagRowid == null || BitConverter.ToUInt32((byte[])pidTagRowid.Value, 0) == 0x8004010F)
                && (pidTagDisplayType == null || BitConverter.ToUInt32((byte[])pidTagDisplayType.Value, 0) == 0x8004010F)
                && (pidTagAddressBookDisplayNamePrintable == null || BitConverter.ToUInt32((byte[])pidTagAddressBookDisplayNamePrintable.Value, 0) == 0x8004010F)
                && (pidTagSmtpAddress == null || BitConverter.ToUInt32((byte[])pidTagSmtpAddress.Value, 0) == 0x8004010F)
                && (pidTagSendInternetEncoding == null || BitConverter.ToUInt32((byte[])pidTagSendInternetEncoding.Value, 0) == 0x8004010F)
                && (pidTagDisplayTypeEx == null || BitConverter.ToUInt32((byte[])pidTagDisplayTypeEx.Value, 0) == 0x8004010F)
                && (pidTagRecipientDisplayName == null || BitConverter.ToUInt32((byte[])pidTagRecipientDisplayName.Value, 0) == 0x8004010F)
                && (pidTagRecipientFlags == null || BitConverter.ToUInt32((byte[])pidTagRecipientFlags.Value, 0) == 0x8004010F)
                && (pidTagRecipientTrackStatus == null || BitConverter.ToUInt32((byte[])pidTagRecipientTrackStatus.Value, 0) == 0x8004010F)
                && (pidTagRecipientResourceState == null || BitConverter.ToUInt32((byte[])pidTagRecipientResourceState.Value, 0) == 0x8004010F)
                && (pidTagRecipientOrder == null || BitConverter.ToUInt32((byte[])pidTagRecipientOrder.Value, 0) == 0x8004010F)
                && (pidTagRecipientEntryId == null || BitConverter.ToUInt32((byte[])pidTagRecipientEntryId.Value, 0) == 0x8004010F);

            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR381,
                381,
                @"[In Receiving a RopRemoveAllRecipients ROP Request] Until the server receives a RopSaveChangesMessage ROP request ([MS-OXCROPS] section 2.2.6.3) from the client, the server adheres to the following: The PidTagRowid property (section 2.2.1.38) and associated data of removed recipients (2) MUST NOT be returned as part of any subsequent handling of ROPs for the opened Message object on the same Message object handle.");
            #endregion

            #region Call RopRelease to release the created message.
            this.ReleaseRop(targetMessageHandle);
            #endregion
        }
        /// <summary>
        /// This method is used to send the ROP of RopGetPropertiesSpecificRequest to get the specific property value.
        /// </summary>
        /// <param name="propTag">The specified property</param>
        /// <returns>Return byte array</returns>
        protected byte[] TryGetLogonPropertyValue(PropertyTag propTag)
        {
            PropertyTag[] tags = new PropertyTag[1];
            tags[0] = propTag;
            #region Construct the request buffer
            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest
            {
                RopId = 0x07,
                LogonId = 0x0,
                InputHandleIndex = 0x0,
                PropertySizeLimit = 0xFFFF, // Specifies the maximum size allowed for a property value returned
                PropertyTagCount = (ushort)tags.Length,
                PropertyTags = tags
            };
            #endregion

            this.oxcstorAdapter.DoRopCall(getPropertiesSpecificRequest, this.outObjHandle, ROPCommandType.RopGetPropertiesSpecific, out this.outputBuffer);
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.outputBuffer.RopsList[0];

            #region Check the response and return
            if ((getPropertiesSpecificResponse.ReturnValue == 0) && (getPropertiesSpecificResponse.RowData != null))
            {
                return getPropertiesSpecificResponse.RowData.PropertyValues[0].Value;
            }
            else
            {
                return null;
            }
            #endregion Check the response and return
        }
        public void MSOXCMSG_S05_TC01_TransactionOnMessage()
        {
            this.CheckMapiHttpIsSupported();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);

            #region Call RopLogon to logon the private mailbox.
            RopLogonResponse logonResponse = this.Logon(LogonType.Mailbox, out this.insideObjHandle);
            #endregion

            #region Call RopCreateMessage to create a Message object.
            // Create a message in InBox
            this.MessageHandle = this.CreatedMessage(logonResponse.FolderIds[4], this.insideObjHandle);
            #endregion

            #region Call SetPropertiesSpecific to set PidTagPriority property to 0x00000001 in created message.
            // Set PidTagPriority to 0x00000001
            List<PropertyObj> propertyValues = new List<PropertyObj>
            {
                new PropertyObj(PropertyNames.PidTagSensitivity, BitConverter.GetBytes(0x00000001))
            };
            this.SetPropertiesForMessage(this.MessageHandle, propertyValues);
            #endregion

            #region Call RopSaveChangesMessage to save the created message.
            RopSaveChangesMessageResponse saveChangesMessageResponse = this.SaveMessage(this.MessageHandle, (byte)SaveFlags.KeepOpenReadWrite);
            ulong messageId = saveChangesMessageResponse.MessageId;
            this.ReleaseRop(this.MessageHandle);
            #endregion

            #region Call RopOpenMessage to open created message on different transactions.
            uint messageHandleFirst = this.OpenSpecificMessage(logonResponse.FolderIds[4], messageId, this.insideObjHandle, MessageOpenModeFlags.BestAccess);
            uint messageHandleSecond = this.OpenSpecificMessage(logonResponse.FolderIds[4], messageId, this.insideObjHandle, MessageOpenModeFlags.BestAccess);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R703
            this.Site.CaptureRequirementIfAreNotEqual<uint>(
                messageHandleFirst,
                messageHandleSecond,
                703,
                @"[In Receiving a RopSaveChangesMessage ROP Request] When the server receives multiple requests to open the same Message object, it [server] returns a different handle and maintains a separate transaction (3) for each.");
            #endregion
            #endregion

            #region Call RopSetProperties to set PidTagSensitivity to 0x00000000 of created message on first transaction.
            propertyValues.Clear();
            propertyValues.Add(new PropertyObj(PropertyNames.PidTagSensitivity, BitConverter.GetBytes(0x00000000)));
            this.SetPropertiesForMessage(messageHandleFirst, propertyValues);
            #endregion

            #region Call RopGetPropertiesSpecific to get the PidTagPriority property of created message on second transaction.
            uint messageHandle = this.OpenSpecificMessage(logonResponse.FolderIds[4], messageId, this.insideObjHandle, MessageOpenModeFlags.BestAccess);
            PropertyTag[] tagArray = new PropertyTag[1];
            tagArray[0] = PropertyHelper.PropertyTagDic[PropertyNames.PidTagSensitivity];

            // Get specific property for created message
            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest()
            {
                RopId = (byte)RopId.RopGetPropertiesSpecific,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                PropertySizeLimit = 0xFFFF, // This value specifies the maximum number of the propert
                PropertyTagCount = (ushort)tagArray.Length,
                PropertyTags = tagArray
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, messageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, "Call RopGetPropertiesSpecific should success.");

            propertyValues = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);
            PropertyObj pidTagSensitivityBeforeSave = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagSensitivity);

            this.ReleaseRop(messageHandle);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R321
            this.Site.CaptureRequirementIfAreEqual<uint>(
                TestSuiteBase.Success,
                getPropertiesSpecificResponse.ReturnValue,
                321,
                @"[In Receiving a RopOpenMessage ROP Request] The Message object returned by the RopOpenMessage ROP ([MS-OXCROPS] section 2.2.6.1) is used in subsequent ROPs, such as a RopGetPropertiesSpecific ROP request ([MS-OXCROPS] section 2.2.8.3).");
            #endregion
            #endregion

            #region Call RopSetProperties to set PidTagSensitivity to 0x00000002 of created message on second transaction.
            propertyValues.Clear();
            propertyValues.Add(new PropertyObj(PropertyNames.PidTagSensitivity, BitConverter.GetBytes(0x00000002)));
            this.SetPropertiesForMessage(messageHandleSecond, propertyValues);
            #endregion

            #region Call RopSaveChangesMessage to save the created message on first transaction.
            saveChangesMessageResponse = this.SaveMessage(messageHandleFirst, (byte)SaveFlags.KeepOpenReadWrite);

            messageHandle = this.OpenSpecificMessage(logonResponse.FolderIds[4], messageId, this.insideObjHandle, MessageOpenModeFlags.BestAccess);

            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, messageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, "Call RopGetPropertiesSpecific should success.");

            propertyValues = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);
            PropertyObj pidTagSensitivityAfterSave = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagSensitivity);
            this.ReleaseRop(messageHandle);

            Site.Assert.AreNotEqual<int>(0x00000000, Convert.ToInt32(pidTagSensitivityBeforeSave.Value), "The second transaction should not visible the changes that be generated by first transaction changed before first transaction committed.");

            Site.Assert.AreEqual<int>(0x00000000, Convert.ToInt32(pidTagSensitivityAfterSave.Value), "The second transaction should not visible the changes that be generated by first transaction changed after first transaction committed.");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R704
            // Because the above steps have verified that any changes made on one transaction MUST NOT be visible to another transaction until the changes are committed via the RopSaveChangesMessage ROP.
            // R704 will be direct verified.
            this.Site.CaptureRequirement(
                704,
                @"[In Receiving a RopSaveChangesMessage ROP Request] Any changes made on one transaction (3) MUST NOT be visible to another transaction (3) until the changes are committed via the RopSaveChangesMessage ROP.");
            #endregion

            #region Call RopSaveChangesMessage to save the created message on second transaction with not force save.
            if (Common.IsRequirementEnabled(1643, this.Site))
            {
                saveChangesMessageResponse = this.SaveMessage(messageHandleSecond, (byte)SaveFlags.KeepOpenReadWrite);

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R1643
                this.Site.CaptureRequirementIfAreEqual<uint>(
                    TestSuiteBase.Success,
                    saveChangesMessageResponse.ReturnValue,
                    1643,
                    @"[In Appendix A: Product Behavior] Implementation does return Success for RopSaveChangesMessage ROP requests ([MS-OXCROPS] section 2.2.6.3) when a previous request has already been committed against the Message object, even though the changes to the object are not actually committed to the server message store. (Exchange 2010 and above follow this behavior.)");
            }

            if (Common.IsRequirementEnabled(1916, this.Site))
            {
                saveChangesMessageResponse = this.SaveMessage(messageHandleSecond, (byte)SaveFlags.KeepOpenReadWrite);

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R1916
                this.Site.CaptureRequirementIfAreNotEqual<uint>(
                    TestSuiteBase.Success,
                    saveChangesMessageResponse.ReturnValue,
                    1916,
                    @"[In Appendix A: Product Behavior] Implementation doesn't return Success for RopSaveChangesMessage ROP requests when a previous request has already been committed against the Message object, even though the changes to the object are not actually committed to the server message store. (Exchange 2007 follows this behavior.)");

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R1053
                this.Site.CaptureRequirementIfAreEqual<uint>(
                    0x80040109,
                    saveChangesMessageResponse.ReturnValue,
                    1053,
                    @"[In Receiving a RopSaveChangesMessage ROP Request] The value of the ecObjectModified is 0x80040109, which indicates that the underlying data for this Message object was changed through another transaction (3) context.");
            }
            #endregion

            #region Call RopSaveChangesMessage to save the created message on second transaction with force save.
            saveChangesMessageResponse = this.SaveMessage(messageHandleSecond, (byte)SaveFlags.ForceSave);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, "Call RopSaveChangesMessage should success.");

            #region Call RopGetPropertiesSpecific to get the PidTagPriority property of created message on second transaction.
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, messageHandleSecond, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, "Call RopGetPropertiesSpecific should success.");

            propertyValues = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);
            pidTagSensitivityBeforeSave = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagSensitivity);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R724
            this.Site.CaptureRequirementIfAreEqual<int>(
                0x00000002,
                Convert.ToInt32(pidTagSensitivityBeforeSave.Value),
                724,
                @"[In RopSaveChangesMessage ROP Request Buffer] [SaveFlags] [ForceSave (0x04)] The ecObjectModified error code is not valid when this flag [ForceSave] is set; the server overwrites any changes instead.");
            #endregion
            #endregion

            #region Call RopRelease to release the created message.
            this.ReleaseRop(messageHandleFirst);
            this.ReleaseRop(messageHandleSecond);
            #endregion
        }
        /// <summary>
        /// Get specific property value.
        /// </summary>
        /// <param name="serverId">A 32-bit signed integer represent the Identity of server.</param>
        /// <param name="handleindex">Identify from which the property will be gotten.</param>
        /// <param name="propertyTag">A list of propertyTags.</param>
        /// <returns>Indicate the result of this ROP operation. </returns>
        public RopResult GetPropertiesSpecific(int serverId, int handleindex, Sequence<string> propertyTag)
        {
            // Initialize ROP data.
            uint handle = this.handleContainer[handleindex];
            RopResult result = RopResult.InvalidParameter;
            PropertyTag[] propertyTags = new PropertyTag[propertyTag.Count];

            // Initial propertyTag.
            for (int i = 0; i < propertyTag.Count; i++)
            {
                propertyTags[i] = this.propertyTagsDictionary[propertyTag[i]];
            }

            // Generate ROP request.
            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest
            {
                RopId = 0x07,
                LogonId = 0x00,
                InputHandleIndex = 0x00,
                PropertySizeLimit = 0xFFFF
            };

            // Set PropertySizeLimit, which specifies the maximum size allowed for a property value returned,
            PropertyTag[] tagArray = propertyTags;
            getPropertiesSpecificRequest.PropertyTagCount = (ushort)tagArray.Length;
            getPropertiesSpecificRequest.PropertyTags = tagArray;

            // Send the RopGetPropertiesSpecific request
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.Process(serverId, getPropertiesSpecificRequest, handle);
            result = (RopResult)getPropertiesSpecificResponse.ReturnValue;

            if (result == RopResult.Success)
            {
                for (int i = 0; i < propertyTag.Count; i++)
                {
                    if (this.propertyValuesSpecific.ContainsKey(propertyTag[i]))
                    {
                        // If the property has been already existed modify it, otherwise add it.
                        this.propertyValuesSpecific[propertyTag[i]] = getPropertiesSpecificResponse.RowData.PropertyValues[i].Serialize();
                    }
                    else
                    {
                        this.propertyValuesSpecific.Add(propertyTag[i], getPropertiesSpecificResponse.RowData.PropertyValues[i].Serialize());
                    }

                    if (propertyTag[i] == "PidTagResolveMethod")
                    {
                        this.VerifyPidTagResolveMethodValue();
                    }
                    else if (propertyTag[i] == "PidTagMessageFlags")
                    {
                        this.VerifySyncImportReadStateChanged(getPropertiesSpecificResponse.RowData.PropertyValues[i]);
                    }
                    else if (propertyTag[i] == "PidTagChangeNumber" || propertyTag[i] == "PidTagDeletedCountTotal" || propertyTag[i] == "PidTagLocalCommitTimeMax")
                    {
                        this.VerifyPidTagChangeNumberValueRelated(propertyTag[i], getPropertiesSpecificResponse.RowData.PropertyValues[i]);
                    }
                }
            }

            return result;
        }
        /// <summary>
        /// This method is used to send the ROP of RopGetPropertiesSpecificRequest to get the specific property.
        /// </summary>
        /// <param name="propTag">The specified property</param>
        /// <param name="responseFlag">When get the property successfully the responseFlag is 0, otherwise return the errorCode </param>
        /// <param name="propertyValue">When  get the property successfully the responseFlag is 0, the propertyValue is the property value, otherwise the propertyValue is 0 </param>
        /// <returns>0 indicates success, others indicates error occurs.</returns>
        protected uint GetPropertyValue(PropertyTag propTag, out uint responseFlag, out byte[] propertyValue)
        {
            uint retValue = 0;
            propertyValue = null;
            PropertyTag[] tags = new PropertyTag[1];
            responseFlag = 1;
            tags[0] = propTag;

            #region Construct the request buffer
            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest
            {
                RopId = 0x07,
                LogonId = 0x0,
                InputHandleIndex = 0x0,
                PropertySizeLimit = 0xFFFF, // Specifies the maximum size allowed for a property value returned
                PropertyTagCount = (ushort)tags.Length,
                PropertyTags = tags
            };
            #endregion

            this.oxcstorAdapter.DoRopCall(getPropertiesSpecificRequest, this.outObjHandle, ROPCommandType.RopGetPropertiesSpecific, out this.outputBuffer);
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.outputBuffer.RopsList[0];
            #region Check the response

            if (getPropertiesSpecificResponse.ReturnValue == 0)
            {
                // The return value is 0 to indicate that the method invoking successfully.
                if (getPropertiesSpecificResponse.RowData.PropertyValues == null ||
                    getPropertiesSpecificResponse.RowData.PropertyValues.Count <= 0)
                {
                    // The case that the operation of set property executes failed for other reasons.
                    Site.Assert.Fail("The property value is not returned when calling RopGetPropertiesSpecific ROP.");
                }

                int lenthProperty = getPropertiesSpecificResponse.RowData.PropertyValues[0].Value.Length;
                propertyValue = new byte[lenthProperty];
                System.Array.Copy(getPropertiesSpecificResponse.RowData.PropertyValues[0].Value, propertyValue, lenthProperty);
            }
            else
            {
                retValue = getPropertiesSpecificResponse.ReturnValue;
            }

            if (null != getPropertiesSpecificResponse.RowData)
            {
                responseFlag = getPropertiesSpecificResponse.RowData.Flag;

                if (1 == responseFlag)
                {
                    responseFlag = Common.ConvertByteArrayToUint(getPropertiesSpecificResponse.RowData.PropertyValues[0].Value);
                }
            }
            #endregion

            return retValue;
        }
        public void MSOXCMSG_S03_TC01_RopSetReadFlags()
        {
            this.CheckMapiHttpIsSupported();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);

            List<PropertyTag> propertyTags = new List<PropertyTag>
            {
                PropertyHelper.PropertyTagDic[PropertyNames.PidTagMessageFlags],
                PropertyHelper.PropertyTagDic[PropertyNames.PidTagChangeKey],
                PropertyHelper.PropertyTagDic[PropertyNames.PidTagLastModificationTime],
                PropertyHelper.PropertyTagDic[PropertyNames.PidTagCreatorEntryId],
                PropertyHelper.PropertyTagDic[PropertyNames.PidTagRead],
                PropertyHelper.PropertyTagDic[PropertyNames.PidTagRecipientDisplayName]
            };

            List<PropertyObj> ps = new List<PropertyObj>();

            #region Call RopLogon to logon the specific private mailbox.
            RopLogonResponse logonResponse = this.Logon(LogonType.Mailbox, out this.insideObjHandle);
            #endregion

            #region Call RopCreateMessage to create a new Message object in inbox folder.
            uint targetMessageHandle = this.CreatedMessage(logonResponse.FolderIds[5], this.insideObjHandle);
            #endregion

            #region Call RopModifyRecipients to add recipient to message created by step2
            PropertyTag[] propertyTag = this.CreateRecipientColumns();
            List<ModifyRecipientRow> modifyRecipientRow = new List<ModifyRecipientRow>
            {
                this.CreateModifyRecipientRow(Common.GetConfigurationPropertyValue("AdminUserName", this.Site), 0)
            };
            this.AddRecipients(modifyRecipientRow, targetMessageHandle, propertyTag);
            #endregion

            #region Call RopSetProperties to set the properties of message created by step 2.
            PropertyTag[] tagArray = propertyTags.ToArray();

            // Get properties for Created Message
            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest()
            {
                RopId = (byte)RopId.RopGetPropertiesSpecific,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                PropertySizeLimit = 0xFFFF, // This value specifies the maximum number of the property
                PropertyTagCount = (ushort)tagArray.Length,
                PropertyTags = tagArray
            };

            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, targetMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

            ps = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);
            
            List<PropertyObj> propertyList = new List<PropertyObj>();
            string title = Common.GenerateResourceName(Site, "Mail");
            propertyList.Add(new PropertyObj(PropertyNames.PidTagNormalizedSubject, Common.GetBytesFromUnicodeString(title)));

            // Set PidTagReadReceiptRequested property.
            propertyList.Add(new PropertyObj(0x0029, (ushort)PropertyType.PtypBoolean, new byte[] { 0x01 }));

            // Set PidTagNonReceiptNotificationRequested property.
            propertyList.Add(new PropertyObj(0x0C06, (ushort)PropertyType.PtypBoolean, new byte[] { 0x01 }));

            // Set PidTagReadReceiptAddressType property.
            propertyList.Add(new PropertyObj(0x4029, (ushort)PropertyType.PtypString, Common.GetBytesFromUnicodeString("EX")));

            // Set PidTagReadReceiptEmailAddress property.
            string userName = Common.GetConfigurationPropertyValue("AdminUserName", this.Site);
            string domain = Common.GetConfigurationPropertyValue("Domain", this.Site);
            string mailAddress = string.Format("{0}@{1}", userName, domain);

            propertyList.Add(new PropertyObj(0x402A, (ushort)PropertyType.PtypString, Common.GetBytesFromUnicodeString(mailAddress)));

            this.SetPropertiesForMessage(targetMessageHandle, propertyList);
            #endregion

            #region Call RopSaveChangesMessage to save the Message object created by step 2.
            RopSaveChangesMessageResponse saveChangesMessageResponse = this.SaveMessage(targetMessageHandle, (byte)SaveFlags.ForceSave);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, saveChangesMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopSubmitMessage to submit message
            RopSubmitMessageRequest submitMessageRequest = new RopSubmitMessageRequest()
            {
                RopId = (byte)RopId.RopSubmitMessage,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                SubmitFlags = (byte)SubmitFlags.None
            };

            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(submitMessageRequest, targetMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopSubmitMessageResponse submitMessageResponse = (RopSubmitMessageResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, submitMessageResponse.ReturnValue, "Call RopSubmitMessage should success.");
            #endregion

            #region Receive the message sent by step 2.
            ulong messageId = 0;
            bool isMessageReceived = this.WaitEmailBeDelivered(title, logonResponse.FolderIds[4], this.insideObjHandle, out messageId);

            Site.Assert.IsTrue(isMessageReceived, "The message should be received.");
            #endregion

            #region Verify requirements
            ulong[] messageIds = new ulong[1];
            messageIds[0] = messageId;

            ps = this.GetSpecificPropertiesOfMessage(logonResponse.FolderIds[4], messageId, this.insideObjHandle, propertyTags);
            PropertyObj pidTagMessageFlagsSetBefore = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagMessageFlags);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R529
            this.Site.CaptureRequirementIfAreEqual<int>(
                0x00000100,
                Convert.ToInt32(pidTagMessageFlagsSetBefore.Value) & (int)MessageFlags.MfNotifyRead,
                529,
                @"[In PidTagMessageFlags Property] [mfNotifyRead (0x00000100)] The user who sent the message has requested notification when a recipient (1) first reads it.");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R531
            this.Site.CaptureRequirementIfAreEqual<int>(
                0x00000200,
                Convert.ToInt32(pidTagMessageFlagsSetBefore.Value) & (int)MessageFlags.MfNotifyUnread,
                531,
                @"[In PidTagMessageFlags Property] [mfNotifyUnread (0x00000200)] The user who sent the message has requested notification when a recipient (1) deletes it before reading or the Message object expires.");
            #endregion

            #region Call RopOpenFolder to open inbox folder.
            uint folderHandle = this.OpenSpecificFolder(logonResponse.FolderIds[4], this.insideObjHandle);
            #endregion

            #region Call RopSetReadFlags to change the state of the PidTagMessageFlags property to rfDefault on Message object within inbox Folder.
            RopSetReadFlagsRequest setReadFlagsRequet = new RopSetReadFlagsRequest()
            {
                RopId = (byte)RopId.RopSetReadFlags,
                LogonId = CommonLogonId, // The logonId 0x00 is associated with this operation.
                InputHandleIndex = CommonInputHandleIndex, // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the input Server Object is stored. 
                WantAsynchronous = 0x00, // Does not asynchronous 
                MessageIds = messageIds,
                MessageIdCount = Convert.ToUInt16(messageIds.Length),
                ReadFlags = (byte)ReadFlags.Default
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(setReadFlagsRequet, folderHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopSetReadFlagsResponse setReadFlagesResponse = (RopSetReadFlagsResponse)this.response;

            ps = this.GetSpecificPropertiesOfMessage(logonResponse.FolderIds[4], messageIds[0], this.insideObjHandle, propertyTags);
            PropertyObj pidTagMessageFlagsSetDefault = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagMessageFlags);
            PropertyObj pidTagChangeKeyBeforeSet = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagChangeKey);
            PropertyObj pidTagLastModificationTimeBeforeSet = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagLastModificationTime);
            PropertyObj pidTagRead = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagRead);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R815
            this.Site.CaptureRequirementIfAreEqual<int>(
                (int)MessageFlags.MfRead,
                Convert.ToInt32(pidTagMessageFlagsSetDefault.Value) & (int)MessageFlags.MfRead,
                815,
                @"[In RopSetReadFlags ROP Request Buffer] [ReadFlags] [rfDefault (0x00)] The server sets the read flag and sends the receipt.");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R2045
            this.Site.CaptureRequirementIfIsTrue(
                Convert.ToBoolean(pidTagRead.Value),
                2045,
                @"[In PidTagRead Property] The PidTagRead property ([MS-OXPROPS] section 2.867) indicates whether a message has been read.");    
            #endregion

            #region Call RopSetReadFlags to change the state of the PidTagMessageFlags property to rfClearReadFlag on Message object within inbox Folder.
            setReadFlagsRequet.ReadFlags = (byte)ReadFlags.ClearReadFlag;
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(setReadFlagsRequet, folderHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            setReadFlagesResponse = (RopSetReadFlagsResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, setReadFlagesResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

            ps = this.GetSpecificPropertiesOfMessage(logonResponse.FolderIds[4], messageIds[0], this.insideObjHandle, propertyTags);
            PropertyObj pidTagMessageFlagsSetClearReadFlag = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagMessageFlags);
            PropertyObj pidTagChangeKeyAfterSet = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagChangeKey);
            PropertyObj pidTagLastModificationTimeAfterSet = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagLastModificationTime);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R822
            this.Site.CaptureRequirementIfAreNotEqual<int>(
                (int)MessageFlags.MfRead,
                Convert.ToInt32(pidTagMessageFlagsSetClearReadFlag.Value) & (int)MessageFlags.MfRead,
                822,
                @"[In RopSetReadFlags ROP Request Buffer] [ReadFlags] [rfClearReadFlag (0x04)] Server clears the mfRead bit.");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R795
            this.Site.CaptureRequirementIfAreNotEqual<int>(
                Convert.ToInt32(pidTagMessageFlagsSetDefault.Value),
                Convert.ToInt32(pidTagMessageFlagsSetClearReadFlag.Value),
                795,
                @"[In RopSetReadFlags ROP] The RopSetReadFlags ROP ([MS-OXCROPS] section 2.2.6.10) changes the state of the PidTagMessageFlags property (section 2.2.1.6) on one or more Message objects within a Folder object.");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R1145
            this.Site.CaptureRequirementIfAreNotEqual<int>(
                Convert.ToInt32(pidTagMessageFlagsSetDefault.Value),
                Convert.ToInt32(pidTagMessageFlagsSetClearReadFlag.Value),
                1145,
                @"[In PidTagMessageFlags Property] The pidTagMessageFlages property is modified using the RopSetReadFlags ROP ([MS-OXCROPS] section 2.2.6.10), as described in section 2.2.3.10.");

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R1703, the PidTagMessageFlags value is {0}.", pidTagMessageFlagsSetClearReadFlag.Value);

            bool isSameChangekey = Common.CompareByteArray((byte[])pidTagChangeKeyBeforeSet.Value, (byte[])pidTagChangeKeyAfterSet.Value);
            Site.Assert.IsTrue(isSameChangekey, "The PidTagChangeKey property should not be changed.");

            Site.Assert.AreEqual<DateTime>(
                Convert.ToDateTime(pidTagLastModificationTimeBeforeSet.Value),
                Convert.ToDateTime(pidTagLastModificationTimeAfterSet.Value),
                "The PidTagLastModificationTime property should not be changed.");

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R1703
            // Because above step has verified only changes the PidTagMessageFlags property, not the PidTagChangeKey property and PidTagLastModificationTime property.
            // R1703 will be direct verified.
            this.Site.CaptureRequirement(
               1703,
               @"[In Receiving a RopSetReadFlags ROP Request] The server immediately commits the changes to the Message objects as if the Message objects had been opened and the RopSaveMessageChanges ROP ([MS-OXCROPS] section 2.2.6.3) had been called, except that it [server] only changes the PidTagMessageFlags property (section 2.2.1.6), not the PidTagChangeKey property ([MS-OXCFXICS] section 2.2.1.2.7), the PidTagLastModificationTime property (section 2.2.2.2), or any other property that is modified during a RopSaveChangesMessage ROP request ([MS-OXCROPS] section 2.2.6.3).");

            #endregion

            #region Call RopSetReadFlags to change the state of the PidTagMessageFlags property to rfSuppressReceipt on Message object within inbox Folder.
            setReadFlagsRequet.ReadFlags = (byte)ReadFlags.SuppressReceipt;
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(setReadFlagsRequet, folderHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            setReadFlagesResponse = (RopSetReadFlagsResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, setReadFlagesResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

            ps = this.GetSpecificPropertiesOfMessage(logonResponse.FolderIds[4], messageIds[0], this.insideObjHandle, propertyTags);
            PropertyObj pidTagMessageFlagsSetSuppressReceipt = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagMessageFlags);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R818
            this.Site.CaptureRequirementIfAreEqual<int>(
                (int)MessageFlags.MfRead,
                Convert.ToInt32(pidTagMessageFlagsSetSuppressReceipt.Value) & (int)MessageFlags.MfRead,
                818,
                @"[In RopSetReadFlags ROP Request Buffer] [ReadFlags] [rfSuppressReceipt (0x01)] The server sets the mfRead bit.");
            #endregion

            #region Call RopSetReadFlags to change the state of the PidTagMessageFlags property to rfGenerateReceiptOnly on Message object within inbox Folder.
            setReadFlagsRequet.ReadFlags = (byte)ReadFlags.GenerateReceiptOnly;
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(setReadFlagsRequet, folderHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            setReadFlagesResponse = (RopSetReadFlagsResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, setReadFlagesResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R825
            this.Site.CaptureRequirementIfAreEqual<uint>(
                TestSuiteBase.Success,
                setReadFlagesResponse.ReturnValue,
                825,
                @"[In RopSetReadFlags ROP Request Buffer] [ReadFlags] [rfGenerateReceiptOnly (0x10)] The server sends a read receipt if one is pending, but does not change the mfRead bit.");
            #endregion

            #region Call RopSetReadFlags to change the state of the PidTagMessageFlags property to rfClearNotifyRead on Message object within inbox Folder.
            setReadFlagsRequet.ReadFlags = (byte)ReadFlags.ClearNotifyRead; // rfClearNotifyRead
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(setReadFlagsRequet, folderHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            setReadFlagesResponse = (RopSetReadFlagsResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, setReadFlagesResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

            ps = this.GetSpecificPropertiesOfMessage(logonResponse.FolderIds[4], messageIds[0], this.insideObjHandle, propertyTags);
            PropertyObj pidTagMessageFlagsSetClearNotifyRead = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagMessageFlags);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R827
            this.Site.CaptureRequirementIfAreNotEqual<int>(
                (int)MessageFlags.MfNotifyRead,
                Convert.ToInt32(pidTagMessageFlagsSetClearNotifyRead.Value) & (int)MessageFlags.MfNotifyRead,
                827,
                @"[In RopSetReadFlags ROP Request Buffer] [ReadFlags] [rfClearNotifyRead (0x20)] The server clears the mfNotifyRead bit but does not send a read receipt.");
            #endregion

            #region Call RopSetReadFlags to change the state of the PidTagMessageFlags property to rfClearNotifyUnread on Message object within inbox Folder.
            setReadFlagsRequet.ReadFlags = (byte)ReadFlags.ClearNotifyUnread; // rfClearNotifyUnread
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(setReadFlagsRequet, folderHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            setReadFlagesResponse = (RopSetReadFlagsResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, setReadFlagesResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

            ps = this.GetSpecificPropertiesOfMessage(logonResponse.FolderIds[4], messageIds[0], this.insideObjHandle, propertyTags);
            PropertyObj pidTagMessageFlagsSetClearNotifyUnread = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagMessageFlags);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R829
            this.Site.CaptureRequirementIfAreNotEqual<int>(
                (int)MessageFlags.MfNotifyUnread,
                Convert.ToInt32(pidTagMessageFlagsSetClearNotifyUnread.Value) & (int)MessageFlags.MfNotifyUnread,
                829,
                @"[In RopSetReadFlags ROP Request Buffer] [ReadFlags] [rfClearNotifyUnread (0x40)] The server clears the mfNotifyUnread bit but does not send a nonread receipt.");
            #endregion

            #region Call RopRelease to release all resources.
            this.ReleaseRop(targetMessageHandle);
            this.ReleaseRop(folderHandle);
            #endregion
        }
        public void MSOXCFOLD_S03_TC16_GetPropertyPidTagFolderFlags()
        {
            this.CheckWhetherSupportTransport();
            this.Adapter.DoConnect(ConnectionType.PrivateMailboxServer);
            this.GenericFolderInitialization();

            #region Step 1. Call RopCreateFolder to create [MSOXCFOLDSubfolder1] under the root folder.
            uint subfolderHandle1 = 0;
            ulong subfolderId1 = 0;
            this.CreateFolder(this.RootFolderHandle, Constants.Subfolder1, ref subfolderId1, ref subfolderHandle1);
            #endregion

            #region Step 2. Creates a none-FAI message in [MSOXCFOLDSubfolder1].
            ulong messageId = 0;
            uint messageHandle = 0;
            this.CreateSaveMessage(subfolderHandle1, subfolderId1, ref messageId, ref messageHandle);
            #endregion

            #region Step 3. Create a FAI message and saves it in [MSOXCFOLDSubfolder1].
            uint messageHandle2 = 0;
            ulong messageId2 = 0;
            this.CreateSaveMessage(subfolderHandle1, subfolderId1, 0x01, ref messageId2, ref messageHandle2);
            #endregion

            #region Step 4. The client calls RopCreateFolder to create the search folder [MSOXCFOLDSearchFolder1] under the root folder.
            RopCreateFolderRequest createFolderRequest = new RopCreateFolderRequest
            {
                RopId = (byte)RopId.RopCreateFolder,
                LogonId = Constants.CommonLogonId,
                InputHandleIndex = Constants.CommonInputHandleIndex,
                OutputHandleIndex = Constants.CommonOutputHandleIndex,
                FolderType = (byte)FolderType.Searchfolder,
                UseUnicodeStrings = 0x0,
                OpenExisting = 0x00,
                Reserved = 0x0,
                DisplayName = Encoding.ASCII.GetBytes(Constants.SearchFolder),
                Comment = Encoding.ASCII.GetBytes(Constants.SearchFolder)
            };
            RopCreateFolderResponse createFolderResponse = this.Adapter.CreateFolder(createFolderRequest, this.RootFolderHandle, ref this.responseHandles);
            Site.Assert.AreEqual<uint>(Constants.SuccessCode, createFolderResponse.ReturnValue, "RopCreateFolder ROP operation performs successfully!");
            uint searchFolderHandle = this.responseHandles[0][createFolderResponse.OutputHandleIndex];
            #endregion            

            #region Step 5. The client calls RopSetSearchCriteria to establish search criteria for [MSOXCFOLDSearchFolder1].
            RopSetSearchCriteriaRequest setSearchCriteriaRequest = new RopSetSearchCriteriaRequest
            {
                RopId = (byte)RopId.RopSetSearchCriteria,
                LogonId = Constants.CommonLogonId,
                InputHandleIndex = Constants.CommonInputHandleIndex
            };
            PropertyTag propertyTag = new PropertyTag
            {
                PropertyId = (ushort)MessagePropertyId.PidTagMessageClass,
                PropertyType = (ushort)PropertyType.PtypString
            };
            ExistRestriction existRestriction = new ExistRestriction
            {
                PropTag = propertyTag
            };
            setSearchCriteriaRequest.RestrictionDataSize = (ushort)existRestriction.Size();
            setSearchCriteriaRequest.RestrictionData = existRestriction.Serialize();
            setSearchCriteriaRequest.FolderIds = new ulong[] { subfolderId1 };
            setSearchCriteriaRequest.FolderIdCount = (ushort)setSearchCriteriaRequest.FolderIds.Length;
            setSearchCriteriaRequest.SearchFlags = (uint)SetSearchFlags.NonContentIndexedSearch | (uint)SetSearchFlags.RestartSearch;
            RopSetSearchCriteriaResponse setSearchCriteriaResponse = this.Adapter.SetSearchCriteria(setSearchCriteriaRequest, searchFolderHandle, ref this.responseHandles);
            Site.Assert.AreEqual<uint>(Constants.SuccessCode, setSearchCriteriaResponse.ReturnValue, "RopSearchCriteria ROP operation performs successfully!");
            #endregion

            #region Step 6. The client calls RopGetContentsTable to retrieve the contents table for the search folder [MSOXCFOLDSearchFolder1].
            RopGetContentsTableRequest getContentsTableRequest = new RopGetContentsTableRequest();
            RopGetContentsTableResponse getContentsTableResponse;
            getContentsTableRequest.RopId = (byte)RopId.RopGetContentsTable;
            getContentsTableRequest.LogonId = Constants.CommonLogonId;
            getContentsTableRequest.InputHandleIndex = Constants.CommonInputHandleIndex;
            getContentsTableRequest.OutputHandleIndex = Constants.CommonOutputHandleIndex;
            getContentsTableRequest.TableFlags = (byte)FolderTableFlags.None;

            int count = 0;
            do
            {
                getContentsTableResponse = this.Adapter.GetContentsTable(getContentsTableRequest, searchFolderHandle, ref this.responseHandles);
                Site.Assert.AreEqual<uint>(Constants.SuccessCode, getContentsTableResponse.ReturnValue, "RopGetContentsTable ROP operation performs successfully!");
                if (getContentsTableResponse.RowCount != 1)
                {
                    Thread.Sleep(this.WaitTime);
                }
                else
                {
                    break;
                }

                count++;
            }
            while (count < this.RetryCount);
            #endregion

            #region Step 7. The client creates rules on [MSOXCFOLDSubfolder1] folder.
            RuleData[] sampleRuleDataArray;
            object ropResponse = null;
            sampleRuleDataArray = this.CreateSampleRuleDataArrayForAdd();

            RopModifyRulesRequest modifyRulesRequest = new RopModifyRulesRequest()
            {
                RopId = (byte)RopId.RopModifyRules,
                LogonId = Constants.CommonLogonId,
                InputHandleIndex = Constants.CommonInputHandleIndex,
                ModifyRulesFlags = 0x00,
                RulesCount = (ushort)sampleRuleDataArray.Length,
                RulesData = sampleRuleDataArray,
            };

            modifyRulesRequest.RopId = (byte)RopId.RopModifyRules;
            modifyRulesRequest.LogonId = Constants.CommonLogonId;
            modifyRulesRequest.InputHandleIndex = Constants.CommonInputHandleIndex;
            sampleRuleDataArray = this.CreateSampleRuleDataArrayForAdd();
            modifyRulesRequest.ModifyRulesFlags = 0x00;
            modifyRulesRequest.RulesCount = (ushort)sampleRuleDataArray.Length;
            modifyRulesRequest.RulesData = sampleRuleDataArray;
            this.Adapter.DoRopCall(modifyRulesRequest, subfolderHandle1, ref ropResponse, ref this.responseHandles);
            RopModifyRulesResponse modifyRulesResponse = (RopModifyRulesResponse)ropResponse;
            Site.Assert.AreEqual<uint>(Constants.SuccessCode, modifyRulesResponse.ReturnValue, "RopModifyRules ROP operation performs successfully!");           
            #endregion

            #region Step 8. The client calls RopOpenFolder to open [MSOXCFOLDSubfolder1] folder.

            RopOpenFolderRequest openFolderRequest = new RopOpenFolderRequest
            {
                RopId = (byte)RopId.RopOpenFolder,
                LogonId = Constants.CommonLogonId,
                InputHandleIndex = Constants.CommonInputHandleIndex,
                OutputHandleIndex = Constants.CommonOutputHandleIndex,
                FolderId = subfolderId1,
                OpenModeFlags = (byte)FolderOpenModeFlags.None
            };
            RopOpenFolderResponse openFolderResponse = this.Adapter.OpenFolder(openFolderRequest, subfolderHandle1, ref this.responseHandles);
            Site.Assert.AreEqual<uint>(Constants.SuccessCode, openFolderResponse.ReturnValue, "RopOpenFolder ROP operation performs successfully!");
            #endregion
            
            #region Step 9. The client gets the PidTagFolderFlags propertie from [MSOXCFOLDSubfolder1].
            PropertyTag[] propertyTagArray = new PropertyTag[1];
            propertyTag = new PropertyTag
            {
                PropertyId = (ushort)FolderPropertyId.PidTagFolderFlags,
                PropertyType = (ushort)PropertyType.PtypInteger32
            };
            propertyTagArray[0] = propertyTag;
                        
            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest();
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse;
            getPropertiesSpecificRequest.RopId = (byte)RopId.RopGetPropertiesSpecific;
            getPropertiesSpecificRequest.LogonId = Constants.CommonLogonId;
            getPropertiesSpecificRequest.InputHandleIndex = Constants.CommonInputHandleIndex;
            getPropertiesSpecificRequest.PropertySizeLimit = 0xFFFF;
            getPropertiesSpecificRequest.PropertyTagCount = (ushort)propertyTagArray.Length;
            getPropertiesSpecificRequest.PropertyTags = propertyTagArray;

            getPropertiesSpecificResponse = this.Adapter.GetFolderObjectSpecificProperties(getPropertiesSpecificRequest, subfolderHandle1, ref this.responseHandles);
            Site.Assert.AreEqual<uint>(0, getPropertiesSpecificResponse.ReturnValue, "RopGetPropertiesSpecific ROP operation performs successfully!");
            uint pidTagFolderFlags = BitConverter.ToUInt32(getPropertiesSpecificResponse.RowData.PropertyValues[0].Value, 0);

            #region Verify MS-OXCFOLD_R1035110, MS-OXCFOLD_R1035111, MS-OXCFOLD_R1035103 and MS-OXCFOLD_R1035107
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, @"Verify MS-OXCFOLD_R1035110: [In PidTagFolderFlags Property] The PidTagFolderId property ([MS-OXPROPS] section 2.692) contains a computed value that specifies the type or state of a folder.");

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R1035110
            Site.CaptureRequirement(
                1035110,
                @"[In PidTagFolderFlags Property] The PidTagFolderId property ([MS-OXPROPS] section 2.692) contains a computed value that specifies the type or state of a folder.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, @"Verify MS-OXCFOLD_R1035111: [In PidTagFolderFlags Property] The value is a bitwise OR of zero or more values [1: IPM, 2: SEARCH, 4: NORMAL, 8: RULES] from the following table.");

            bool isR1035111Verified = false;
            if (((pidTagFolderFlags & 1) == 1) || ((pidTagFolderFlags & 2) == 2) || ((pidTagFolderFlags & 4) == 4) || ((pidTagFolderFlags & 8) == 8))
            {
                isR1035111Verified = true;
            }

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R1035111
            Site.CaptureRequirementIfIsTrue(
                isR1035111Verified,
                1035111,
                @"[In PidTagFolderFlags Property] The value is a bitwise OR of zero or more values [1: IPM, 2: SEARCH, 4: NORMAL, 8: RULES] from the following table.");
            

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, @"Verify MS-OXCFOLD_R1035103: [In PidTagFolderFlags Property] [The folder flag named ""IPM"" specified] the folder belongs to the IPM subtree portion of the mailbox.");

            bool isR1035103Verified = false;
            if ((pidTagFolderFlags & 1) == 1)
            {
                isR1035103Verified = true;
            }

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R1035103
            Site.CaptureRequirementIfIsTrue(
                isR1035103Verified,
                1035103,
                @"[In PidTagFolderFlags Property] [The folder flag named ""IPM"" specified] the folder belongs to the IPM subtree portion of the mailbox.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, @"Verify MS-OXCFOLD_R1035107: [In PidTagFolderFlags Property] [The folder flag named ""NORMAL"" specified] the folder is a generic folder that contains messages and other folders.");

            bool isR1035107Verified = false;
            if ((pidTagFolderFlags & 4) == 4)
            {
                isR1035107Verified = true;
            }

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R1035107
            Site.CaptureRequirementIfIsTrue(
                isR1035107Verified,
                1035107,
                @"[In PidTagFolderFlags Property] [The folder flag named ""NORMAL"" specified] the folder is a generic folder that contains messages and other folders.");
            #endregion
            #endregion
        }
        /// <summary>
        /// Get folder object specific properties.
        /// </summary>
        /// <param name="ropGetPropertiesSpecificRequest">RopGetPropertiesSpecificRequest object</param>
        /// <param name="insideObjHandle">Server object handle in GetPropertiesSpecific.</param>
        /// <param name="responseSOHTable">Server objects handles in RopGetPropertiesSpecificResponse.</param>
        /// <returns>RopGetPropertiesSpecificResponse object.</returns>
        public RopGetPropertiesSpecificResponse GetFolderObjectSpecificProperties(RopGetPropertiesSpecificRequest ropGetPropertiesSpecificRequest, uint insideObjHandle, ref List<List<uint>> responseSOHTable)
        {
            object ropResponse = new object();
            this.ExcuteRopCall((ISerializable)ropGetPropertiesSpecificRequest, insideObjHandle, ref ropResponse, ref responseSOHTable, ref this.rawData);
            RopGetPropertiesSpecificResponse response = (RopGetPropertiesSpecificResponse)ropResponse;

            if (0x00000000 == response.ReturnValue)
            {
                // The getPropertiesSpecificResponse.ReturnValue equals 0 means that this Rop is successful.
                // So the propertyTags in getPropertiesSpecificRequest is correct
                this.VerifyGetFolderSpecificProperties(ropGetPropertiesSpecificRequest.PropertyTags);
            }

            return response;
        }
        public void MSOXCROPS_S06_TC01_TestRopsGetProperties()
        {
            this.CheckTransportIsSupported();

            this.cropsAdapter.RpcConnect(
                Common.GetConfigurationPropertyValue("SutComputerName", this.Site),
                ConnectionType.PrivateMailboxServer,
                Common.GetConfigurationPropertyValue("UserEssdn", this.Site),
                Common.GetConfigurationPropertyValue("Domain", this.Site),
                Common.GetConfigurationPropertyValue("AdminUserName", this.Site),
                Common.GetConfigurationPropertyValue("PassWord", this.Site));

            // Step 1: Send the RopGetPropertiesAll request and verify the success response.
            #region RopGetPropertiesAll success response

            // Log on to the private mailbox.
            this.Logon(LogonType.Mailbox, this.userDN, out this.inputObjHandle);

            RopGetPropertiesAllRequest getPropertiesAllRequest;
            RopGetPropertiesAllResponse getPropertiesAllResponse;

            getPropertiesAllRequest.RopId = (byte)RopId.RopGetPropertiesAll;

            getPropertiesAllRequest.LogonId = TestSuiteBase.LogonId;
            getPropertiesAllRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;

            // Set PropertySizeLimit, which specifies the maximum size allowed for a property value returned.
            getPropertiesAllRequest.PropertySizeLimit = TestSuiteBase.PropertySizeLimit;

            getPropertiesAllRequest.WantUnicode = (ushort)Zero;

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 1: Begin to send the RopGetPropertiesAll request.");

            // Send the RopGetPropertiesAll request and verify the success response.
            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                getPropertiesAllRequest,
                this.inputObjHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            getPropertiesAllResponse = (RopGetPropertiesAllResponse)response;

            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                getPropertiesAllResponse.ReturnValue,
                "if ROP succeeds, ReturnValue of its response will be 0 (success)");

            #endregion

            // Step 2: Send the RopGetPropertiesAll request and verify the failure response.
            #region RopGetPropertiesAll failure response

            getPropertiesAllRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex1;

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 2: Begin to send the RopGetPropertiesAll request.");

            // Send the RopGetPropertiesAll request and verify the failure response.
            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                getPropertiesAllRequest,
                this.inputObjHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.FailureResponse);
            getPropertiesAllResponse = (RopGetPropertiesAllResponse)response;

            Site.Assert.AreNotEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                getPropertiesAllResponse.ReturnValue,
                "if ROP failure, ReturnValue of its response will not be 0");

            #endregion

            // Step 3: Send the RopGetPropertiesList request and verify the success response.
            #region RopGetPropertiesList success response

            RopGetPropertiesListRequest getPropertiesListRequest;
            RopGetPropertiesListResponse getPropertiesListResponse;

            getPropertiesListRequest.RopId = (byte)RopId.RopGetPropertiesList;
            getPropertiesListRequest.LogonId = TestSuiteBase.LogonId;
            getPropertiesListRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 3: Begin to send the RopGetPropertiesList request.");

            // Send the RopGetPropertiesList request and verify the success response.
            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                getPropertiesListRequest,
                this.inputObjHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            getPropertiesListResponse = (RopGetPropertiesListResponse)response;

            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                getPropertiesListResponse.ReturnValue,
                "if ROP succeeds, ReturnValue of its response will be 0 (success)");

            #endregion

            // Step 4: Send the RopGetPropertiesList request and verify the failure response.
            #region RopGetPropertiesList failure response

            getPropertiesListRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex1;

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 4: Begin to send the RopGetPropertiesList request.");

            // Send the RopGetPropertiesList request and verify the failure response.
            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                getPropertiesListRequest,
                this.inputObjHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.FailureResponse);
            getPropertiesListResponse = (RopGetPropertiesListResponse)response;

            Site.Assert.AreNotEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                getPropertiesListResponse.ReturnValue,
                "if ROP failure, ReturnValue of its response will not be 0");

            #endregion

            // Step 5: Send the RopGetPropertiesSpecific request and verify the success response.
            #region RopGetPropertiesSpecific success response

            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest();
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse;

            getPropertiesSpecificRequest.RopId = (byte)RopId.RopGetPropertiesSpecific;
            getPropertiesSpecificRequest.LogonId = TestSuiteBase.LogonId;
            getPropertiesSpecificRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;

            // Set PropertySizeLimit, which specifies the maximum size allowed for a property value returned.
            getPropertiesSpecificRequest.PropertySizeLimit = TestSuiteBase.PropertySizeLimit;

            PropertyTag[] tagArray = this.CreateFolderPropertyTags();
            getPropertiesSpecificRequest.PropertyTagCount = (ushort)tagArray.Length;
            getPropertiesSpecificRequest.PropertyTags = tagArray;

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 5: Begin to send the RopGetPropertiesSpecific request.");

            // Send the RopGetPropertiesSpecific request and verify the success response.
            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                getPropertiesSpecificRequest,
                this.inputObjHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)response;

            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                getPropertiesSpecificResponse.ReturnValue,
                "if ROP succeeds, ReturnValue of its response will be 0 (success)");

            #endregion

            // Step 6: Send the RopGetPropertiesSpecific request and verify the failure response.
            #region RopGetPropertiesSpecific failure response

            getPropertiesSpecificRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex1;

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 6: Begin to send the RopGetPropertiesSpecific request.");

            // Send the RopGetPropertiesSpecific request and verify the failure response.
            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                getPropertiesSpecificRequest,
                this.inputObjHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.FailureResponse);
            getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)response;

            Site.Assert.AreNotEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                getPropertiesSpecificResponse.ReturnValue,
                "if ROP failure, ReturnValue of its response will not be 0 (success)");

            #endregion
        }
        public void MSOXCMSG_S01_TC03_PropertiesInRopCreateMessageInitialization()
        {
            this.CheckMapiHttpIsSupported();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);

            #region Call RopLogon to logon the private mailbox.
            RopLogonResponse logonResponse = this.Logon(LogonType.Mailbox, out this.insideObjHandle);
            #endregion

            #region Call RopCreateMessage to create a Message object.
            uint targetMessageHandle = this.CreatedMessage(logonResponse.FolderIds[4], this.insideObjHandle);
            #endregion

            #region Call RopGetPropertiesSpecific to get properties for created message before save message.
            // Prepare property Tag 
            PropertyTag[] tagArray = this.GetPropertyTagsForInitializeMessage();

            // Get properties for Created Message
            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest()
            {
                RopId = (byte)RopId.RopGetPropertiesSpecific,
                LogonId = CommonLogonId, // The logonId 0x00 is associated with this operation.
                InputHandleIndex = CommonInputHandleIndex, // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the input Server Object is stored. 
                PropertySizeLimit = 0xFFFF, // This value specifies the maximum number of the property
                PropertyTagCount = (ushort)tagArray.Length,
                PropertyTags = tagArray
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, targetMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, "Call RopGetPropertiesSpecific should success.");

            List<PropertyObj> ps = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);

            // Parse property response get Property Value to verify test  case requirement
            PropertyObj pidTagImportance = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagImportance);
            PropertyObj pidTagMessageClass = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagMessageClass);
            PropertyObj pidTagSensitivity = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagSensitivity);
            PropertyObj pidTagDisplayBcc = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagDisplayBcc);
            PropertyObj pidTagDisplayCc = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagDisplayCc);
            PropertyObj pidTagDisplayTo = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagDisplayTo);
            PropertyObj pidTagHasAttachments = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagHasAttachments);
            PropertyObj pidTagTrustSender = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagTrustSender);
            PropertyObj pidTagAccess = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagAccess);
            PropertyObj pidTagAccessLevel = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagAccessLevel);
            PropertyObj pidTagCreationTime = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagCreationTime);
            PropertyObj pidTagLastModificationTime = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagLastModificationTime);
            PropertyObj pidTagSearchKey = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagSearchKey);
            PropertyObj pidTagCreatorName = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagCreatorName);
            PropertyObj pidTagLastModifierName = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagLastModifierName);
            PropertyObj pidTagHasNamedProperties = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagHasNamedProperties);
            PropertyObj pidTagLocalCommitTime = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagLocalCommitTime);
            PropertyObj pidTagMessageFlags = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagMessageFlags);
            PropertyObj pidTagCreatorEntryId = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagCreatorEntryId);
            PropertyObj pidTagLastModifierEntryId = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagLastModifierEntryId);
            PropertyObj pidTagMessageLocaleId = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagMessageLocaleId);
            PropertyObj pidTagLocaleId = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagLocaleId);


            #region Verify requirements
            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R987");

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R987
            this.Site.CaptureRequirementIfAreNotEqual<uint>(
                0x00000040,
                Convert.ToUInt32(pidTagMessageFlags.Value) & 0x00000040,
                987,
                @"[In RopCreateMessage ROP Request Buffer] [AssociatedFlag] Value 0x00 means the message to be created is not an FAI message.");

            int pidTagImportanceInitialValue = Convert.ToInt32(pidTagImportance.Value);

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-OXCMSG_R341,the actual initial Data of PidTagImportance is {0}",
                pidTagImportanceInitialValue);

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R341
            Site.CaptureRequirementIfAreEqual<int>(
                0x00000001,
                pidTagImportanceInitialValue,
                341,
                @"[In Receiving a RopCreateMessage ROP Request] [The Initial data of PidTagImportance is] 0x00000001.");

            string pidTagMessageClassInitialValue = Convert.ToString(pidTagMessageClass.Value);

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R342,the actual initial Data of PidTagMessageClass is {0}", pidTagMessageClassInitialValue);

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R342
            Site.CaptureRequirementIfAreEqual<string>(
                "IPM.Note",
                pidTagMessageClassInitialValue,
                342,
                @"[In Receiving a RopCreateMessage ROP Request] [The Initial Data of PidTagMessageClass is] IPM.Note.");

            int pidTagSensitivityInitialValue = Convert.ToInt32(pidTagSensitivity.Value);

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R343,the actual initial Data of PidTagSensitivity is {0}", pidTagSensitivityInitialValue);

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R343
            Site.CaptureRequirementIfAreEqual<int>(
                0x00000000,
                pidTagSensitivityInitialValue,
                343,
                @"[In Receiving a RopCreateMessage ROP Request] [The Initial Data of PidTagSensitivity is] 0x00000000.");

            string pidTagDisplayBccInitialValue = Convert.ToString(pidTagDisplayBcc.Value);

            if (Common.IsRequirementEnabled(344, this.Site))
            {
                // Add the debug information
                Site.Log.Add(
                    LogEntryKind.Debug,
                    "Verify MS-OXCMSG_R344,the actual initial Data of PidTagDisplayBcc is {0}",
                    pidTagDisplayBccInitialValue);

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R344
                Site.CaptureRequirementIfAreEqual<string>(
                    string.Empty,
                    pidTagDisplayBccInitialValue,
                    344,
                    @"[In Receiving a RopCreateMessage ROP Request] [The Initial Data of PidTagDisplayBcc is] """".");
            }

            if (Common.IsRequirementEnabled(345, this.Site))
            {
                string pidTagDisplayCcInitialValue = Convert.ToString(pidTagDisplayCc.Value);

                // Add the debug information
                Site.Log.Add(
                    LogEntryKind.Debug,
                    "Verify MS-OXCMSG_R345,the actual initial Data of PidTagDisplayCc is {0}",
                    pidTagDisplayCcInitialValue);

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R345
                Site.CaptureRequirementIfAreEqual<string>(
                    string.Empty,
                    pidTagDisplayCcInitialValue,
                    345,
                    @"[In Receiving a RopCreateMessage ROP Request] [The Initial Data of PidTagDisplayCc is] """".");
            }

            if (Common.IsRequirementEnabled(346, this.Site))
            {
                string pidTagDisplayToInitialValue = Convert.ToString(pidTagDisplayTo.Value);

                // Add the debug information
                Site.Log.Add(
                    LogEntryKind.Debug,
                    "Verify MS-OXCMSG_R346,the actual initial Data of PidTagDisplayTo is {0}",
                    pidTagDisplayToInitialValue);

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R346
                Site.CaptureRequirementIfAreEqual<string>(
                    string.Empty,
                    pidTagDisplayToInitialValue,
                    346,
                    @"[In Receiving a RopCreateMessage ROP Request] [The Initial Data of PidTagDisplayTo is] """".");
            }

            int pidTagHasAttachmentsInitialValue = Convert.ToInt32(pidTagHasAttachments.Value);

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-OXCMSG_R349,the actual initial Data of PidTagHasAttachments is {0}",
                pidTagHasAttachmentsInitialValue);

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R349
            Site.CaptureRequirementIfAreEqual<int>(
                0x00,
                pidTagHasAttachmentsInitialValue,
                349,
                @"[In Receiving a RopCreateMessage ROP Request] [The Initial Data of PidTagHasAttachments is] 0x00.");

            if (Common.IsRequirementEnabled(1713, this.Site))
            {
                int pidTagTrustSenderInitialValue = Convert.ToInt32(pidTagTrustSender.Value);

                // Add the debug information
                Site.Log.Add(
                    LogEntryKind.Debug,
                    "Verify MS-OXCMSG_R352,the actual initial Data of PidTagTrustSender is {0}",
                    pidTagTrustSenderInitialValue);

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R352
                Site.CaptureRequirementIfAreEqual<int>(
                    0x00000001,
                    pidTagTrustSenderInitialValue,
                    352,
                    @"[In Receiving a RopCreateMessage ROP Request] [The Initial Data of PidTagTrustSender is] 0x00000001.");

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

                // It indicates that Exchange 2007 supports the PidTagTrustSender property if code can run here.
                this.Site.CaptureRequirement(
                    1713,
                    @"[In Appendix A: Product Behavior] Implementation does support the PidTagTrustSender property. (Exchange 2007 follows this behavior.)");
            }

            int pidTagAccessInitialValue = Convert.ToInt32(pidTagAccess.Value);
            if (Common.IsRequirementEnabled(1915, this.Site))
            {
                // Add the debug information
                Site.Log.Add(
                    LogEntryKind.Debug,
                    "Verify MS-OXCMSG_R1915,the actual initial Data of PidTagAccess is {0}",
                    pidTagAccessInitialValue);

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R1915
                Site.CaptureRequirementIfAreEqual<int>(
                    0x00000003,
                    pidTagAccessInitialValue,
                    1915,
                    @"[In Appendix A: Product Behavior] Implementation does initialize the PidTagAccess property to 0x00000003. (Exchange 2007 and 2010 follow this behavior.)");
            }

            if (Common.IsRequirementEnabled(1914, this.Site))
            {
                // Add the debug information
                Site.Log.Add(
                    LogEntryKind.Debug,
                    "Verify MS-OXCMSG_R1914,the actual initial Data of PidTagAccess is {0}",
                    pidTagAccessInitialValue);

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R1914
                this.Site.CaptureRequirementIfAreEqual<int>(
                    0x00000007,
                    pidTagAccessInitialValue,
                    1914,
                    @"[In Appendix A: Product Behavior] Implementation does initialize the PidTagAccess property to 0x00000007. (<23> Section 3.2.5.2: Exchange 2013 follows this behavior.)");
            }

            int pidTagAccessLevelInitialValue = Convert.ToInt32(pidTagAccessLevel.Value);

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-OXCMSG_R354,the actual initial Data of PidTagAccessLevel is {0}",
                pidTagAccessLevelInitialValue);

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R354
            Site.CaptureRequirementIfAreEqual<int>(
                0x00000001,
                pidTagAccessLevelInitialValue,
                354,
                @"[In Receiving a RopCreateMessage ROP Request] [The Initial Data of PidTagAccessLevel is] 0x00000001.");

            DateTime pidTagCreationTimeInitialValue = Convert.ToDateTime(pidTagCreationTime.Value);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R2034
            this.Site.CaptureRequirementIfIsNotNull(
                pidTagCreationTimeInitialValue,
                2034,
                @"[In Receiving a RopCreateMessage ROP Request] PidTagCreationTime (section 2.2.2.3) [will be initialized when calling RopCreateMessage ROP].");

            if (Common.IsRequirementEnabled(1912, this.Site))
            {
                string pidTagCreatorNameInitialValue = Convert.ToString(pidTagCreatorName.Value).ToLower();
                string creatorName = Common.GetConfigurationPropertyValue("AdminUserName", this.Site).ToLower();

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R360
                Site.CaptureRequirementIfAreEqual<string>(
                    creatorName,
                    pidTagCreatorNameInitialValue,
                    360,
                    @"[In Receiving a RopCreateMessage ROP Request] [The Initial Data of PidTagCreatorName is] Name of the creator.");

                bool isVerifyR357 = Convert.ToDateTime(pidTagLastModificationTime.Value) == pidTagCreationTimeInitialValue;

                // Above If condition has verified the initial data of PidTagLastModificationTime.
                Site.CaptureRequirementIfIsTrue(
                    isVerifyR357,
                    357,
                    @"[In Receiving a RopCreateMessage ROP Request] [The Initial Data of PidTagLastModification is Same] as PidTagCreationTime property.");

                string pidTagLastModifierNameInitialValue = Convert.ToString(pidTagLastModifierName.Value).ToLower();

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R362
                Site.CaptureRequirementIfAreEqual<string>(
                    pidTagCreatorNameInitialValue,
                    pidTagLastModifierNameInitialValue,
                    362,
                    @"[In Receiving a RopCreateMessage ROP Request] [The Initial Data of PidTagLastModifierName is] Same as PidTagCreatorName property.");

                AddressBookEntryID creatorEntryId = new AddressBookEntryID();
                creatorEntryId.Deserialize((byte[])pidTagCreatorEntryId.Value, 0);

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R361
                this.Site.CaptureRequirementIfIsInstanceOfType(
                    creatorEntryId,
                    typeof(AddressBookEntryID),
                    361,
                    @"[In Receiving a RopCreateMessage ROP Request] [The Initial Data of PidTagCreatorEntryId is] Address Book EntryID of the creator.");

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R1182
                this.Site.CaptureRequirementIfIsInstanceOfType(
                     creatorEntryId,
                     typeof(AddressBookEntryID),
                    1182,
                    @"[In PidTagCreatorEntryId Property] The PidTagCreatorEntryId property ([MS-OXPROPS] section 2.646) specifies the original author of the message according to their address book EntryID.");

                AddressBookEntryID modifierEntryId = new AddressBookEntryID();
                modifierEntryId.Deserialize((byte[])pidTagLastModifierEntryId.Value, 0);

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R363
                this.Site.CaptureRequirementIfAreEqual<AddressBookEntryID>(
                    creatorEntryId,
                    modifierEntryId,
                    363,
                    @"[In Receiving a RopCreateMessage ROP Request] [The Initial Data of PidTagLastModifierEntryId is] Same as PidTagCreatorEntryId property.");

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R1185
                this.Site.CaptureRequirementIfIsInstanceOfType(
                    modifierEntryId,
                    typeof(AddressBookEntryID),
                    1185,
                    @"[In PidTagLastModifierEntryId Property] The PidTagLastModifierEntryId property ([MS-OXPROPS] section 2.754) specifies the last user to modify the contents of the message according to their address book EntryID.");

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R359
                this.Site.CaptureRequirementIfIsNotNull(
                    pidTagMessageLocaleId.Value,
                    359,
                    @"[In Receiving a RopCreateMessage ROP Request] [The Initial Data of PidTagMessageLocaleId is] The Logon object LocaleID.");

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R365
                this.Site.CaptureRequirementIfAreEqual<object>(
                    pidTagMessageLocaleId.Value,
                    pidTagLocaleId.Value,
                    365,
                    @"[In Receiving a RopCreateMessage ROP Request] [The Initial Data of PidTagLocaleId is] Same as PidTagMessageLocaleId property.");

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

                // MS-OXCMSG_R1912 can be verified if code can run here.
                this.Site.CaptureRequirement(
                    1912,
                    @"[In Appendix A: Product Behavior] Implementation does initialize the properties: PidTagCreatorName, PidTagCreatorEntryId, PidTagLastModifierName, PidTagLastModifierEntryId, PidTagLastModificationTime, PidTagMessageLocaleId  and PidTagLocaleId. (Exchange 2007 and Exchange 2010 follow this behavior.)");
            }

            // MS-OXCMSG_R358 can be verified if the value of PidTagSearchKey is not null since whether server generated SearchKey is unknown to client.
            Site.CaptureRequirementIfIsNotNull(
                pidTagSearchKey,
                358,
                @"[In Receiving a RopCreateMessage ROP Request] [The Initial Data of PidTagSearchKey is] Server generated Search Key.");

            int pidTagHasNamedPropertiesInitialValue = Convert.ToInt32(pidTagHasNamedProperties.Value);

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-OXCMSG_R364,the actual initial Data of PidTagHasNamedProperties is {0}",
                pidTagHasNamedPropertiesInitialValue);

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R364
            Site.CaptureRequirementIfAreEqual<int>(
                0x00,
                pidTagHasNamedPropertiesInitialValue,
                364,
                @"[In Receiving a RopCreateMessage ROP Request] [The Initial Data of PidTagHasNamedProperties is] 0x00.");

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R3015
                this.Site.CaptureRequirementIfAreEqual<int>(
                    0x00000009,
                    Convert.ToInt32(pidTagMessageFlags.Value),
                    3015,
                    @"[In Appendix A: Product Behavior] [The Initial data of PidTagMessageFlags] will be 0x00000009 (the mfEverRead flag combined by using the bitwise OR operation with the value 0x00000009) if the client does not explicitly set the read state. (<22> Section 3.2.5.2: Exchange 2007 follows this behavior.)");
            }

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R3016
                this.Site.CaptureRequirementIfAreEqual<int>(
                    0x00000409,
                    Convert.ToInt32(pidTagMessageFlags.Value),
                    3016,
                    @"[In Appendix A: Product Behavior] [The Initial data of PidTagMessageFlags] will be 0x00000409 (the mfEverRead flag combined by using the bitwise OR operation with the value 0x00000009) if the client does not explicitly set the read state. (Exchange 2010 and above follow this behavior.)");

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R1140
                this.Site.CaptureRequirementIfAreEqual<int>(
                    0x00000400,
                    Convert.ToInt32(pidTagMessageFlags.Value)& 0x00000400,
                    1140,
                    @"[In PidTagMessageFlags Property] [mfEverRead (0x00000400)] The message has been read at least once.");
            }

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R3006
                this.Site.CaptureRequirementIfIsTrue(
                    (Convert.ToInt32(pidTagMessageFlags.Value) & 0x00000400)== 0x00000400 && (Convert.ToInt32(pidTagMessageFlags.Value) & 0x00000001) == 0x00000001,
                    3006,
                    @"[In Appendix A: Product Behavior] [mfEverRead (0x00000400)] This flag is set by the implementation whenever the mfRead flag is set. (Exchange 2010 and above follow this behavior.)");
            }

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R510
            this.Site.CaptureRequirementIfAreEqual<uint>(
                0x00000001,
                Convert.ToUInt32(pidTagMessageFlags.Value) & 0x00000001,
                510,
                @"[In PidTagMessageFlags Property] [mfRead (0x00000001)] The message is marked as having been read.");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R512
            this.Site.CaptureRequirementIfAreEqual<uint>(
                0x00000008,
                Convert.ToUInt32(pidTagMessageFlags.Value) & 0x00000008,
                512,
                @"[In PidTagMessageFlags Property] [mfUnsent (0x00000008)] The message is still being composed and is treated as a Draft Message object.");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R73
            this.Site.CaptureRequirementIfAreEqual<uint>(
                0x00000001,
                Convert.ToUInt32(pidTagImportance.Value),
                73,
                @"[In PidTagImportance Property] [The value 0x00000001 indicates the level of importance assigned by the end user to the Message object is] Normal importance.");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R513
            this.Site.CaptureRequirementIfAreEqual<int>(
                0x00000008,
                Convert.ToInt32(pidTagMessageFlags.Value) & (int)MessageFlags.MfUnsent,
                513,
                @"[In PidTagMessageFlags Property] [mfUnsent (0x00000008)] This bit is cleared by the server when responding to the RopSubmitMessage ROP ([MS-OXCROPS] section 2.2.7.1) with a success code.");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R84
            this.Site.CaptureRequirementIfAreEqual<int>(
                0x00000000,
                Convert.ToInt32(pidTagSensitivity.Value),
                84,
                @"[In PidTagSensitivity Property] [The value 0x00000000 indicates the sender's assessment of the sensitivity of the Message object is] Normal.");
            #endregion
            #endregion

            #region Call RopSaveChangesMessage to save created message.
            RopSaveChangesMessageResponse saveChangesMessageResponse = this.SaveMessage(targetMessageHandle, (byte)SaveFlags.ForceSave);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, saveChangesMessageResponse.ReturnValue, "Call RopSaveChangesMessage should success.");
            #endregion

            #region Call RopGetPropertiesSpecific to get properties for created message after save message.
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, targetMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, "Call RopGetPropertiesSpecific should success.");

            ps = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);

            PropertyObj pidTagLocalCommitTimeAfterSave = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagLocalCommitTime);
            #region Verify MS-OXCMSG_R1890
            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R1890, The value of PidTagLocalCommitTime is {0}", pidTagLocalCommitTimeAfterSave.Value);

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R1890
            bool isVerifiedR1890 = pidTagLocalCommitTime.Value != pidTagLocalCommitTimeAfterSave.Value;

            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR1890,
                1890,
                @"[In Receiving a RopSaveChangesMessage ROP Request] The server sets the PidTagLocalCommitTime property (section 2.2.1.49) when the RopSaveChangesMessage ROP is processed.");
            #endregion
            #endregion

            #region Call RopRelease to release created message.
            this.ReleaseRop(targetMessageHandle);
            #endregion
        }
        public void MSOXCMSG_S01_TC09_RopSaveChangeMessageFailure()
        {
            if (Common.IsRequirementEnabled(1916, this.Site))
            {
                this.CheckMapiHttpIsSupported();
                this.ConnectToServer(ConnectionType.PrivateMailboxServer);

                List<PropertyTag> propertyTags = new List<PropertyTag>
                {
                    PropertyHelper.PropertyTagDic[PropertyNames.PidTagAccessLevel]
                };
                List<PropertyObj> propertyValues;
                RopSaveChangesMessageResponse saveChangesMessageResponse;

                #region Call RopLogon to log on a private mailbox.
                RopLogonResponse logonResponse = this.Logon(LogonType.Mailbox, out this.insideObjHandle);
                #endregion

                #region Call RopCreateMessage to create new Message object.
                uint targetMessageHandle = this.CreatedMessage(logonResponse.FolderIds[4], this.insideObjHandle);
                saveChangesMessageResponse = this.SaveMessage(targetMessageHandle, (byte)SaveFlags.ForceSave);
                ulong messageID = saveChangesMessageResponse.MessageId;
                this.ReleaseRop(targetMessageHandle);
                #endregion

                #region Call RopOpenMessage to open the message object created by step above.
                targetMessageHandle = this.OpenSpecificMessage(logonResponse.FolderIds[4], messageID, this.insideObjHandle, MessageOpenModeFlags.ReadWrite);
                #endregion

                #region Call RopGetPropertiesSpecific to get PidTagAccessLevel property for created message before save message.
                // Prepare property Tag 
                PropertyTag[] tagArray = new PropertyTag[1];
                tagArray[0] = PropertyHelper.PropertyTagDic[PropertyNames.PidTagAccessLevel];

                // Get properties for Created Message
                RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest()
                {
                    RopId = (byte)RopId.RopGetPropertiesSpecific,
                    LogonId = CommonLogonId, // The logonId 0x00 is associated with this operation.
                    InputHandleIndex = CommonInputHandleIndex, // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the input Server Object is stored. 
                    PropertySizeLimit = 0xFFFF, // This value specifies the maximum number of the property
                    PropertyTagCount = (ushort)tagArray.Length,
                    PropertyTags = tagArray
                };
                this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, targetMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
                RopGetPropertiesSpecificResponse getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
                Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, "Call RopGetPropertiesSpecific should success.");

                propertyValues = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);
                PropertyObj accesssLevelBeforeSave = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagAccessLevel);
                #endregion

                #region Call RopSaveChangesMessage to save the created Message object on one transaction.
                // Call RopSaveChangesMessage to save the created message on one transaction.
                // The server will return an error when call RopSaveChangesMessage if property R1916Enabled is true in SHOULD/MAY ptfconfig file.
                uint messageHandleSecond = this.OpenSpecificMessage(logonResponse.FolderIds[4], messageID, this.insideObjHandle, MessageOpenModeFlags.ReadWrite);
                saveChangesMessageResponse = this.SaveMessage(messageHandleSecond, (byte)SaveFlags.ForceSave);
                this.ReleaseRop(messageHandleSecond);
                #endregion

                #region Call RopSaveChangesMessage and Saveflag field is KeepOpenReadOnly.
                RopSaveChangesMessageRequest saveChangesMessageRequest = new RopSaveChangesMessageRequest()
                {
                    RopId = (byte)RopId.RopSaveChangesMessage,
                    LogonId = CommonLogonId,
                    InputHandleIndex = CommonInputHandleIndex,
                    ResponseHandleIndex = CommonOutputHandleIndex, // This index specifies the location in the Server object handle table that is referenced in the response.
                    SaveFlags = (byte)SaveFlags.KeepOpenReadOnly
                };

                this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(saveChangesMessageRequest, targetMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
                saveChangesMessageResponse = (RopSaveChangesMessageResponse)this.response;

                Site.Assert.AreNotEqual<uint>(TestSuiteBase.Success, saveChangesMessageResponse.ReturnValue, "Call RopSaveChangesMessage should failed.");

                this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, targetMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
                getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
                Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

                propertyValues = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);

                PropertyObj accesssLevelAfterReadOnlyFail = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagAccessLevel);

                Site.Assert.AreEqual<int>(Convert.ToInt32(accesssLevelBeforeSave.Value), Convert.ToInt32(accesssLevelAfterReadOnlyFail.Value), "The Message object access level should be unchanged.");

                // Because server return error code when call RopSaveChangesMessage and 
                // the access level has not been changed between call RopSaveChangesMessage before and after.
                // So R1670 will be verified.
                this.Site.CaptureRequirement(
                    1670,
                    @"[In RopSaveChangesMessage ROP Request Buffer] [SaveFlags] [KeepOpenReadOnly (0x01)] [If the RopSaveChangesMessage ROP failed] The server returns an error and leaves the Message object open with unchanged access level.");
                #endregion

                #region Call RopSaveChangesMessage and SaveFlag field is KeepOpenReadWrite.
                saveChangesMessageRequest = new RopSaveChangesMessageRequest()
                {
                    RopId = (byte)RopId.RopSaveChangesMessage,
                    LogonId = CommonLogonId,
                    InputHandleIndex = CommonInputHandleIndex,
                    ResponseHandleIndex = CommonOutputHandleIndex, // This index specifies the location in the Server object handle table that is referenced in the response.
                    SaveFlags = (byte)SaveFlags.KeepOpenReadWrite
                };

                this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(saveChangesMessageRequest, targetMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
                saveChangesMessageResponse = (RopSaveChangesMessageResponse)this.response;

                Site.Assert.AreNotEqual<uint>(TestSuiteBase.Success, saveChangesMessageResponse.ReturnValue, "Call RopSaveChangesMessage should failed.");

                this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, targetMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
                getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
                Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

                propertyValues = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);

                PropertyObj accesssLevelAfterReadWriteFail = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagAccessLevel);

                Site.Assert.AreEqual<int>(Convert.ToInt32(accesssLevelBeforeSave.Value), Convert.ToInt32(accesssLevelAfterReadWriteFail.Value), "The Message object access level should be unchanged.");

                // Because server return error code when call RopSaveChangesMessage and 
                // the access level has not been changed between call RopSaveChangesMessage before and after.
                // So R718 will be verified.
                this.Site.CaptureRequirement(
                    718,
                    @"[In RopSaveChangesMessage ROP Request Buffer] [SaveFlags] [KeepOpenReadWrite (0x02)] [If the RopSaveChangesMessage ROP failed] The server returns an error and leaves the Message object open with unchanged access level.");
                #endregion

                #region Call RopSaveChangesMessage and SaveFlag field is ForceSave.
                saveChangesMessageRequest = new RopSaveChangesMessageRequest()
                {
                    RopId = (byte)RopId.RopSaveChangesMessage,
                    LogonId = CommonLogonId,
                    InputHandleIndex = InvalidInputHandleIndex,
                    ResponseHandleIndex = CommonOutputHandleIndex, // This index specifies the location in the Server object handle table that is referenced in the response.
                    SaveFlags = (byte)SaveFlags.ForceSave
                };
                this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(saveChangesMessageRequest, targetMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
                saveChangesMessageResponse = (RopSaveChangesMessageResponse)this.response;

                Site.Assert.AreNotEqual<uint>(TestSuiteBase.Success, saveChangesMessageResponse.ReturnValue, "Call RopSaveChangesMessage should failed.");

                this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, targetMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
                getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
                Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

                propertyValues = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);
                PropertyObj accesssLevelAfterForceSaveFail = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagAccessLevel);

                Site.Assert.AreEqual<int>(Convert.ToInt32(accesssLevelBeforeSave.Value), Convert.ToInt32(accesssLevelAfterForceSaveFail.Value), "The Message object access level should be unchanged.");

                // Because server return error code when call RopSaveChangesMessage and 
                // the access level has not been changed between call RopSaveChangesMessage before and after.
                // So R722 will be verified.
                this.Site.CaptureRequirement(
                    722,
                    @"[In RopSaveChangesMessage ROP Request Buffer] [SaveFlags] [ForceSave (0x04)] [If the RopSaveChangesMessage ROP failed] The server returns an error and leaves the Message object open with unchanged access level.");
                #endregion

                #region Call RopRelease to release created message.
                this.ReleaseRop(targetMessageHandle);
                #endregion
            }
            else
            {
                this.isNotNeedCleanupPrivateMailbox = true;
                Site.Assume.Inconclusive("This case runs only if the implementation does not return Success for RopSaveChangesMessage ROP requests when a previous request has already been committed against the Message object, even though the changes to the object are not actually committed to the server store.");
            }
        }
        public void MSOXCMSG_S01_TC08_RopSaveChangeMessageWithForceSave()
        {
            this.CheckMapiHttpIsSupported();
            List<PropertyTag> propertyTags = new List<PropertyTag>
            {
                PropertyHelper.PropertyTagDic[PropertyNames.PidTagAccessLevel]
            };
            List<PropertyObj> propertyValues;
            RopSaveChangesMessageResponse saveChangesMessageResponse;

            this.ConnectToServer(ConnectionType.PrivateMailboxServer);

            #region Call RopLogon to log on a private mailbox.
            RopLogonResponse logonResponse = this.Logon(LogonType.Mailbox, out this.insideObjHandle);
            #endregion

            #region Call RopCreateMessage to create new Message object.
            uint targetMessageHandle = this.CreatedMessage(logonResponse.FolderIds[4], this.insideObjHandle);
            saveChangesMessageResponse = this.SaveMessage(targetMessageHandle, (byte)SaveFlags.ForceSave);
            ulong messageID = saveChangesMessageResponse.MessageId;
            this.ReleaseRop(targetMessageHandle);
            #endregion

            #region Call RopOpenMessage to open the message object created by step above.
            targetMessageHandle = this.OpenSpecificMessage(logonResponse.FolderIds[4], messageID, this.insideObjHandle, MessageOpenModeFlags.ReadWrite);
            #endregion

            #region Call RopGetPropertiesSpecific to get properties for created message before save message.
            // Prepare property Tag 
            PropertyTag[] tagArray = new PropertyTag[1];
            tagArray[0] = PropertyHelper.PropertyTagDic[PropertyNames.PidTagAccessLevel];

            // Get properties for Created Message
            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest()
            {
                RopId = (byte)RopId.RopGetPropertiesSpecific,
                LogonId = CommonLogonId, // The logonId 0x00 is associated with this operation.
                InputHandleIndex = CommonInputHandleIndex, // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the input Server Object is stored. 
                PropertySizeLimit = 0xFFFF, // This value specifies the maximum number of the property
                PropertyTagCount = (ushort)tagArray.Length,
                PropertyTags = tagArray
            };

            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, targetMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

            propertyValues = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);
            PropertyObj accesssLevelBeforeSave = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagAccessLevel);
            #endregion

            #region Call RopSaveChangesMessage to save a Message object and server return an error.
            if (Common.IsRequirementEnabled(1644, this.Site))
            {
                // Call RopSetProperties to set PidTagHasAttachments that is a read-only property.
                // The server will return a GeneralFailure error when call RopSaveChangesMessage if property R1644Enabled is true in SHOULD/MAY ptfconfig file.
                List<PropertyObj> propertyList = new List<PropertyObj>
                {
                    new PropertyObj(PropertyNames.PidTagHasAttachments, BitConverter.GetBytes(true))
                };
                this.SetPropertiesForMessage(targetMessageHandle, propertyList);

                RopSaveChangesMessageRequest saveChangesMessageRequest = new RopSaveChangesMessageRequest()
                {
                    RopId = (byte)RopId.RopSaveChangesMessage,
                    LogonId = CommonLogonId,
                    InputHandleIndex = InvalidInputHandleIndex,
                    ResponseHandleIndex = CommonOutputHandleIndex, // This index specifies the location in the Server object handle table that is referenced in the response.
                    SaveFlags = (byte)SaveFlags.ForceSave
                };
                this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(saveChangesMessageRequest, targetMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
                saveChangesMessageResponse = (RopSaveChangesMessageResponse)this.response;

                Site.Assert.AreNotEqual<uint>(TestSuiteBase.Success, saveChangesMessageResponse.ReturnValue, "Call RopSaveChangesMessage should failed.");

                this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, targetMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
                getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
                Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

                propertyValues = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);
                PropertyObj accesssLevelAfterForceSaveFail = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagAccessLevel);

                Site.Assert.AreEqual<int>(Convert.ToInt32(accesssLevelBeforeSave.Value), Convert.ToInt32(accesssLevelAfterForceSaveFail.Value), "The Message object access level should be unchanged.");

                // Because server return error code when call RopSaveChangesMessage and 
                // the access level has not been changed between call RopSaveChangesMessage before and after.
                // So R722 will be verified.
                this.Site.CaptureRequirement(
                    722,
                    @"[In RopSaveChangesMessage ROP Request Buffer] [SaveFlags] [ForceSave (0x04)] [If the RopSaveChangesMessage ROP failed] The server returns an error and leaves the Message object open with unchanged access level.");

                this.ReleaseRop(targetMessageHandle);
            }
            #endregion

            #region Call RopOpenMessage to open the message object created by step above.
            targetMessageHandle = this.OpenSpecificMessage(logonResponse.FolderIds[4], messageID, this.insideObjHandle, MessageOpenModeFlags.ReadWrite);
            #endregion

            #region Call RopSaveChangesMessage to commit the Message object created and keep the message open with ForceSave.
            if (Common.IsRequirementEnabled(3011, this.Site))
            {
                saveChangesMessageResponse = this.SaveMessage(targetMessageHandle, 0x0C);
                Site.Assert.AreEqual<uint>(TestSuiteBase.Success, saveChangesMessageResponse.ReturnValue, "Call RopSaveChangesMessage should success.");

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R3011
                this.Site.CaptureRequirementIfAreEqual<uint>(
                    TestSuiteBase.Success,
                    saveChangesMessageResponse.ReturnValue,
                    3011,
                    @"[In Appendix A: Product Behavior] <14> Section 2.2.3.3.1:  The value of ForceSave is 0x0C in Microsoft Exchange Server 2007 Service Pack 3 (SP3).");
            }

            if (Common.IsRequirementEnabled(3022,this.Site))
            {
                saveChangesMessageResponse = this.SaveMessage(targetMessageHandle, 0x04);

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R3022
                this.Site.CaptureRequirementIfAreEqual<uint>(
                    TestSuiteBase.Success,
                    saveChangesMessageResponse.ReturnValue,
                    3022,
                    @"[In Appendix A: Product Behavior] The value of ForceSave is 0x04. (Exchange 2010 and above follow this behavior.)");
            }

            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, targetMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, "Call RopGetPropertiesSpecific should success.");

            propertyValues = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);
            PropertyObj accesssLevelAfterForceSaveSuccess = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagAccessLevel);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R723
            // Because the server has returned a success code when call RopSaveChangesMessage.
            // If the PidTagAccessLevel property is 0x00000001 (Modify) then R719 will be verified.
            this.Site.CaptureRequirementIfAreEqual<int>(
                0x00000001,
                Convert.ToInt32(accesssLevelAfterForceSaveSuccess.Value),
                723,
                @"[In RopSaveChangesMessage ROP Request Buffer] [SaveFlags] [ForceSave (0x04)] [If the RopSaveChangesMessage ROP succeeded] The server returns a success code and keeps the Message object open with read/write access.");
            #endregion

            #region Call RopRelease to release created message.
            this.ReleaseRop(targetMessageHandle);
            #endregion
        }
        public void MSOXCFOLD_S03_TC07_GetReadOnlyProperties()
        {
            this.CheckWhetherSupportTransport();
            this.Adapter.DoConnect(ConnectionType.PrivateMailboxServer);
            this.GenericFolderInitialization();

            #region Step 1. The client calls RopCreateFolder to create [MSOXCFOLDSubfolder1] under the root folder.

            uint subfolderHandle1 = 0;
            ulong subfolderId1 = 0;
            this.CreateFolder(this.RootFolderHandle, Constants.Subfolder1, ref subfolderId1, ref subfolderHandle1);

            #endregion

            #region Step 2. The client creates a Non-FAI message and saves it in [MSOXCFOLDSubfolder1].

            uint messageHandle1 = 0;
            ulong messageId1 = 0;
            this.CreateSaveMessage(subfolderHandle1, subfolderId1, ref messageId1, ref messageHandle1);

            #endregion

            #region Step 3. The client create a FAI message and saves it in [MSOXCFOLDSubfolder1].

            uint messageHandle2 = 0;
            ulong messageId2 = 0;
            this.CreateSaveMessage(subfolderHandle1, subfolderId1, 0x01, ref messageId2, ref messageHandle2);

            #endregion

            #region Step 4. The client gets the read-only properties from [MSOXCFOLDSubfolder1].

            PropertyTag[] propertyTagArray = new PropertyTag[11];

            PropertyTag propertyTag = new PropertyTag
            {
                PropertyId = (ushort)FolderPropertyId.PidTagContentCount,
                PropertyType = (ushort)PropertyType.PtypInteger32
            };
            propertyTagArray[0] = propertyTag;

            propertyTag = new PropertyTag
            {
                PropertyId = (ushort)FolderPropertyId.PidTagContentUnreadCount,
                PropertyType = (ushort)PropertyType.PtypInteger32
            };
            propertyTagArray[1] = propertyTag;

            propertyTag = new PropertyTag
            {
                PropertyId = (ushort)FolderPropertyId.PidTagDeletedOn,
                PropertyType = (ushort)PropertyType.PtypTime
            };
            propertyTagArray[2] = propertyTag;

            propertyTag = new PropertyTag
            {
                PropertyId = (ushort)FolderPropertyId.PidTagFolderId,
                PropertyType = (ushort)PropertyType.PtypInteger64
            };
            propertyTagArray[3] = propertyTag;

            propertyTag = new PropertyTag
            {
                PropertyId = (ushort)FolderPropertyId.PidTagParentEntryId,
                PropertyType = (ushort)PropertyType.PtypBinary
            };
            propertyTagArray[4] = propertyTag;

            propertyTag = new PropertyTag
            {
                PropertyId = (ushort)FolderPropertyId.PidTagHierarchyChangeNumber,
                PropertyType = (ushort)PropertyType.PtypInteger32
            };
            propertyTagArray[5] = propertyTag;

            propertyTag = new PropertyTag
            {
                PropertyId = (ushort)FolderPropertyId.PidTagSubfolders,
                PropertyType = (ushort)0x000B
            };
            propertyTagArray[6] = propertyTag;

            propertyTag = new PropertyTag
            {
                PropertyId = (ushort)FolderPropertyId.PidTagMessageSize,
                PropertyType = (ushort)PropertyType.PtypInteger32
            };
            propertyTagArray[7] = propertyTag;

            propertyTag = new PropertyTag
            {
                PropertyId = (ushort)FolderPropertyId.PidTagMessageSizeExtended,
                PropertyType = (ushort)PropertyType.PtypInteger64
            };
            propertyTagArray[8] = propertyTag;

            propertyTag = new PropertyTag
            {
                PropertyId = (ushort)FolderPropertyId.PidTagDeletedCountTotal,
                PropertyType = (ushort)PropertyType.PtypInteger32
            };
            propertyTagArray[9] = propertyTag;

            propertyTag = new PropertyTag
            {
                PropertyId = (ushort)FolderPropertyId.PidTagHierRev,
                PropertyType = (ushort)PropertyType.PtypTime
            };
            propertyTagArray[10] = propertyTag;

            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest();
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse;
            getPropertiesSpecificRequest.RopId = (byte)RopId.RopGetPropertiesSpecific;
            getPropertiesSpecificRequest.LogonId = Constants.CommonLogonId;
            getPropertiesSpecificRequest.InputHandleIndex = Constants.CommonInputHandleIndex;
            getPropertiesSpecificRequest.PropertySizeLimit = 0xFFFF;
            getPropertiesSpecificRequest.PropertyTagCount = (ushort)propertyTagArray.Length;
            getPropertiesSpecificRequest.PropertyTags = propertyTagArray;

            getPropertiesSpecificResponse = this.Adapter.GetFolderObjectSpecificProperties(getPropertiesSpecificRequest, subfolderHandle1, ref this.responseHandles);
            Site.Assert.AreEqual<uint>(0, getPropertiesSpecificResponse.ReturnValue, "RopGetPropertiesSpecific ROP operation performs successfully!");
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse1 = getPropertiesSpecificResponse;
            #endregion

            #region Verify the requirements: MS-OXCFOLD_R10347, MS-OXCFOLD_R10345, MS-OXCFOLD_R346, MS-OXCFOLD_R10351 and MS-OXCFOLD_R1030, MS-OXCFOLD_R10027, MS-OXCFOLD_R10353, MS-OXCFOLD_R10354, MS-OXCFOLD_R352001 and MS-OXCFOLD_R352002.
            uint pidTagMessageSize = BitConverter.ToUInt32(getPropertiesSpecificResponse1.RowData.PropertyValues[7].Value, 0);
            
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCFOLD_R10353");

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R10353
            Site.CaptureRequirementIfAreNotEqual<uint>(
                0,
                pidTagMessageSize,
                10353,
                @"[In PidTagMessageSize Property] The PidTagMessageSize property ([MS-OXPROPS] section 2.787) specifies the aggregate size of messages in the folder.");
            ulong pidTagMessageSizeExtended = BitConverter.ToUInt64(getPropertiesSpecificResponse1.RowData.PropertyValues[8].Value, 0);
            
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCFOLD_R10354: the 64 bit value of the pidTagMessageSize property is {0}, and the value of the pidTagMessageSizeExtended is {1}", pidTagMessageSize, pidTagMessageSizeExtended);

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R10354
            Site.CaptureRequirementIfAreEqual<ulong>(
                (ulong)pidTagMessageSize,
                pidTagMessageSizeExtended,
                10354,
                @"[In PidTagMessageSizeExtended Property] The PidTagMessageSizeExtended property ([MS-OXPROPS] section 2.788) specifies the 64-bit version of the PidTagMessageSize property (section 2.2.2.2.1.7).");

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

            // Client call RopGetPropertiesSpecific to get the PidTagMessageSizeExtended property.
            // If the value of PidTagMessageSizeExtended property can return and type of this property is ulong, then R354 will be verified.
            Site.CaptureRequirementIfIsInstanceOfType(
                pidTagMessageSizeExtended,
                typeof(ulong),
                354,
                @"[In PidTagMessageSizeExtended Property] Type: PtypInteger64 ([MS-OXCDATA] section 2.11.1)");

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

            Site.CaptureRequirementIfIsInstanceOfType(
                pidTagMessageSizeExtended,
                typeof(ulong),
                Constants.MSOXPROPS,
                7009,
                @"[In PidTagMessageSizeExtended] Data type: PtypInteger64, 0x0014.");

            // [MSOXCFOLDSubfolder1] should have no unread message.
            uint unreadMessagesCountExpect = 0;

            // The index of PidTagContentUnreadCount is 1 according to the RopGetPropertiesSpecific ROP request.
            uint unreadMessagesCountActual = BitConverter.ToUInt32(getPropertiesSpecificResponse1.RowData.PropertyValues[1].Value, 0);

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

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R10347.
            Site.CaptureRequirementIfAreEqual<uint>(
                unreadMessagesCountExpect,
                unreadMessagesCountActual,
                10347,
                @"[In PidTagContentUnreadCount Property] The PidTagContentUnreadCount property ([MS-OXPROPS] section 2.639) specifies the number of unread messages in a folder, as computed by the message store.");

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

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R10345
            Site.CaptureRequirementIfAreEqual<int>(
                1,
                BitConverter.ToInt32(getPropertiesSpecificResponse1.RowData.PropertyValues[0].Value, 0),
                10345,
                @"[In PidTagContentCount Property] The PidTagContentCount property ([MS-OXPROPS] section 2.637) specifies the number of messages in a folder, as computed by the message store.");

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

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R346
            Site.CaptureRequirementIfAreEqual<int>(
                1,
                BitConverter.ToInt32(getPropertiesSpecificResponse1.RowData.PropertyValues[0].Value, 0),
                346,
                @"[In PidTagContentCount Property] The value does not include FAI entries in the folder.");

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

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R10351
            Site.CaptureRequirementIfAreEqual<ulong>(
                subfolderId1,
                BitConverter.ToUInt64(getPropertiesSpecificResponse1.RowData.PropertyValues[3].Value, 0),
                10351,
                @"[In PidTagFolderId Property] The PidTagFolderId property ([MS-OXPROPS] section 2.691) contains a FID structure ([MS-OXCDATA] section 2.2.1.1) that uniquely identifies a folder.");

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

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R1030
            Site.CaptureRequirementIfAreEqual<bool>(
                false,
                BitConverter.ToBoolean(getPropertiesSpecificResponse1.RowData.PropertyValues[6].Value, 0),
                1030,
                @"[In PidTagSubfolders Property] [if the folder does not have subfolders,] the value is zero otherwise.");

            uint pidTagDeletedCountTotal = BitConverter.ToUInt32(getPropertiesSpecificResponse1.RowData.PropertyValues[9].Value, 0);

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCFOLD_R3006");
        
            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R3006
            // Because no message has been deleted on [MSOXCFOLDSubfolder1]. So if the PidTagDeletedCountTotal property is 0, then R3006 will be verified.
            this.Site.CaptureRequirementIfAreEqual<uint>(
                0,
                pidTagDeletedCountTotal,
                3006,
                @"[In PidTagDeletedCountTotal Property] The PidTagDeletedCountTotal property ([MS-OXPROPS] section 2.660) specifies the total number of messages that have been deleted from a folder, excluding messages that have been deleted from the folder's subfolders.");
 
            // Add the debug information.
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCFOLD_R352001");

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R352001
            Site.CaptureRequirementIfAreEqual<ushort>(
                (ushort)PropertyType.PtypTime,
                propertyTagArray[10].PropertyType,
                352001,
                "[In PidTagHierRev Property] Type: PtypTime ([MS-OXCDATA] section 2.11.1)");

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

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R352002
            // If the property value in getPropertiesSpecificResponse1 is not null, then the PidTagHierRev property is returned from server.
            this.Site.CaptureRequirementIfIsTrue(
                getPropertiesSpecificResponse1.RowData.PropertyValues[10].Value.Length > 0,
                352002,
                @"[In PidTagHierRev Property] The PidTagHierRev property ([MS-OXPROPS] section 2.712) specifies the time, in Coordinated Universal Time (UTC), to trigger the client in cached mode to synchronize the folder hierarchy.");
            #endregion

            #region Step 5. The client calls RopCreateFolder to create [MSOXCFOLDSubfolder2] under [MSOXCFOLDSubfolder1].

            uint subfolderHandle2 = 0;
            ulong subfolderId2 = 0;
            this.CreateFolder(subfolderHandle1, Constants.Subfolder2, ref subfolderId2, ref subfolderHandle2);

            #endregion

            #region Step 6. The client gets the read-only properties from [MSOXCFOLDSubfolder1] after creating [MSOXCFOLDSubfolder2] under [MSOXCFOLDSubfolder1].

            getPropertiesSpecificResponse = this.Adapter.GetFolderObjectSpecificProperties(getPropertiesSpecificRequest, subfolderHandle1, ref this.responseHandles);
            Site.Assert.AreEqual<uint>(0, getPropertiesSpecificResponse.ReturnValue, "RopGetPropertiesSpecific ROP operation performs successfully!");
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse2 = getPropertiesSpecificResponse;

            #endregion

            #region Verify the requirements: MS-OXCFOLD_R1029, MS-OXCFOLD_R10355.

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

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R1029
            Site.CaptureRequirementIfIsTrue(
                BitConverter.ToBoolean(getPropertiesSpecificResponse.RowData.PropertyValues[6].Value, 0),
                1029,
                @"[In PidTagSubfolders Property] The value of this property [PidTagSubfolders] is nonzero if the folder has subfolders.");

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

            // MS-OXCFOLD_R1029 and MS-OXCFOLD_R1030 is verified, MS-OXCFOLD_R10355 can be verified directly.
            Site.CaptureRequirement(
                10355,
                @"[In PidTagSubfolders Property] The PidTagSubfolders property ([MS-OXPROPS] section 2.1022) specifies whether the folder has any subfolders.");

            #endregion

            #region Step 7. The client calls RopDeleteFolder to delete [MSOXCFOLDSubfolder2] under [MSOXCFOLDSubfolder1].

            RopDeleteFolderRequest deleteFolderRequest = new RopDeleteFolderRequest
            {
                RopId = (byte)RopId.RopDeleteFolder,
                LogonId = Constants.CommonLogonId,
                InputHandleIndex = Constants.CommonInputHandleIndex,
                DeleteFolderFlags = (byte)DeleteFolderFlags.DelFolders | (byte)DeleteFolderFlags.DelMessages,
                FolderId = subfolderId2
            };
            RopDeleteFolderResponse deleteFolderResponse = this.Adapter.DeleteFolder(deleteFolderRequest, subfolderHandle1, ref this.responseHandles);
            Site.Assert.AreEqual<uint>(0, deleteFolderResponse.ReturnValue, "RopDeleteFolderResponse ROP operation performs successfully!");
            #endregion

            #region Step 8. The client gets the read-only properties from [MSOXCFOLDSubfolder1] after deleting [MSOXCFOLDSubfolder2] under [MSOXCFOLDSubfolder1].

            getPropertiesSpecificResponse = this.Adapter.GetFolderObjectSpecificProperties(getPropertiesSpecificRequest, subfolderHandle1, ref this.responseHandles);
            Site.Assert.AreEqual<uint>(0, getPropertiesSpecificResponse.ReturnValue, "RopGetPropertiesSpecific ROP operation performs successfully!");

            #region Verify the requirements: MS-OXCFOLD_R10028, MS-OXCFOLD_R352.

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCFOLD_R10028, the value of property PidTagHierarchyChangeNumber after getting the read-only properties from [MSOXCFOLDSubfolder1] is {0}, the value of property PidTagHierarchyChangeNumber after getting the read-only properties from [MSOXCFOLDSubfolder1] after creating [MSOXCFOLDSubfolder2] under [MSOXCFOLDSubfolder1] is {1}, the value of property PidTagHierarchyChangeNumber after getting the read-only properties from [MSOXCFOLDSubfolder1] after deleting [MSOXCFOLDSubfolder2] under [MSOXCFOLDSubfolder1] is {2}.", getPropertiesSpecificResponse1.RowData.PropertyValues[5].Value, getPropertiesSpecificResponse2.RowData.PropertyValues[5].Value, getPropertiesSpecificResponse.RowData.PropertyValues[5].Value);

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R10028
            bool changeNumberIncreased =
                BitConverter.ToInt32(getPropertiesSpecificResponse1.RowData.PropertyValues[5].Value, 0) < BitConverter.ToInt32(getPropertiesSpecificResponse2.RowData.PropertyValues[5].Value, 0) &&
                BitConverter.ToInt32(getPropertiesSpecificResponse2.RowData.PropertyValues[5].Value, 0) < BitConverter.ToInt32(getPropertiesSpecificResponse.RowData.PropertyValues[5].Value, 0);

            Site.CaptureRequirementIfIsTrue(
                changeNumberIncreased,
                10028,
                @"[In PidTagHierarchyChangeNumber Property] The PidTagHierarchyChangeNumber property ([MS-OXPROPS] section 2.711) specifies the number of subfolders in the folder.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCFOLD_R352, the value of property PidTagHierarchyChangeNumber after getting the read-only properties from [MSOXCFOLDSubfolder1] is {0}, the value of property PidTagHierarchyChangeNumber after getting the read-only properties from [MSOXCFOLDSubfolder1] after creating [MSOXCFOLDSubfolder2] under [MSOXCFOLDSubfolder1] is {1}, the value of property PidTagHierarchyChangeNumber after getting the read-only properties from [MSOXCFOLDSubfolder1] after deleting [MSOXCFOLDSubfolder2] under [MSOXCFOLDSubfolder1] is {2}.", getPropertiesSpecificResponse1.RowData.PropertyValues[5].Value, getPropertiesSpecificResponse2.RowData.PropertyValues[5].Value, getPropertiesSpecificResponse.RowData.PropertyValues[5].Value);

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R352.
            Site.CaptureRequirementIfIsTrue(
                changeNumberIncreased,
                352,
                @"[In PidTagHierarchyChangeNumber Property] The value of this property [PidTagHierarchyChangeNumber] monotonically increases every time a subfolder is added to or deleted from the folder.");

            #endregion
            #endregion
        }
        public void MSOXCMSG_S04_TC01_GeneralPropertiesOnMessageObject()
        {
            this.CheckMapiHttpIsSupported();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);

            #region Call RopLogon to logon the private mailbox.
            RopLogonResponse logonResponse = this.Logon(LogonType.Mailbox, out this.insideObjHandle);
            #endregion

            #region Call RopOpenFolder to open inbox folder.
            uint folderHandle = this.OpenSpecificFolder(logonResponse.FolderIds[4], this.insideObjHandle);
            #endregion

            #region Call RopCreateMessage to create Message object.
            uint targetMessageHandle = this.CreatedMessage(logonResponse.FolderIds[4], this.insideObjHandle);
            #endregion

            #region Call RopModifyRecipients to add recipient to message created by step2
            PropertyTag[] recipientColumns = this.CreateRecipientColumns();
            List<ModifyRecipientRow> modifyRecipientRow = new List<ModifyRecipientRow>
            {
                this.CreateModifyRecipientRow(Common.GetConfigurationPropertyValue("AdminUserName", this.Site), 0)
            };
            this.AddRecipients(modifyRecipientRow, targetMessageHandle, recipientColumns);
            #endregion

            #region Call RopGetPropertiesSpecific to get PidTagMessageFlags property for created message before save message.
            // Prepare property Tag 
            PropertyTag[] tagArray = new PropertyTag[1];
            tagArray[0] = PropertyHelper.PropertyTagDic[PropertyNames.PidTagMessageFlags];

            // Get properties for Created Message
            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest()
            {
                RopId = (byte)RopId.RopGetPropertiesSpecific,
                LogonId = CommonLogonId, // The logonId 0x00 is associated with this operation.
                InputHandleIndex = CommonInputHandleIndex, // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the input Server Object is stored. 
                PropertySizeLimit = 0xFFFF, // This value specifies the maximum number of the property
                PropertyTagCount = (ushort)tagArray.Length,
                PropertyTags = tagArray
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, targetMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

            List<PropertyObj> ps = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);

            PropertyObj pidTagMessageFlags = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagMessageFlags);
            #endregion

            #region Call RopSetProperties to set PidTagMessageFlags property of created message.
            List<PropertyObj> propertyList = this.SetGeneralPropertiesOfMessage();
            int messageFlags = Convert.ToInt32(pidTagMessageFlags.Value) | (int)MessageFlags.MfResend;
            propertyList.Add(new PropertyObj(PropertyNames.PidTagMessageFlags, BitConverter.GetBytes(messageFlags)));
            this.SetPropertiesForMessage(targetMessageHandle, propertyList);
            #endregion

            #region Call RopSaveChangesMessage to save created message.
            RopSaveChangesMessageResponse saveChangesMessageResponse = this.SaveMessage(targetMessageHandle, (byte)SaveFlags.ForceSave);

            // The message ID of specific message created by above step.
            ulong messageId = saveChangesMessageResponse.MessageId;
            #endregion

            #region Call RopGetContentsTable to get the contents table of inbox folder before submit message.
            RopGetContentsTableResponse getContentsTableResponse = this.GetContentTableSuccess(folderHandle);
            uint contentTableHandle = this.ResponseSOHs[0][getContentsTableResponse.OutputHandleIndex];
            uint rowCountBeforeSubmit = getContentsTableResponse.RowCount;
            this.ReleaseRop(contentTableHandle);
            #endregion

            #region Call RopSubmitMessage to submit message
            RopSubmitMessageRequest submitMessageRequest = new RopSubmitMessageRequest()
            {
                RopId = (byte)RopId.RopSubmitMessage,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                SubmitFlags = (byte)SubmitFlags.None
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(submitMessageRequest, targetMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopSubmitMessageResponse submitMessageResponse = (RopSubmitMessageResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, submitMessageResponse.ReturnValue, "Call RopSubmitMessage should success.");
            #endregion

            #region Call RopOpenMessage to open created message.
            RopOpenMessageRequest openMessageRequest = new RopOpenMessageRequest
            {
                RopId = (byte)RopId.RopOpenMessage,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                OutputHandleIndex = CommonOutputHandleIndex,
                CodePageId = 0x0FFF,
                FolderId = logonResponse.FolderIds[4],
                OpenModeFlags = (byte)MessageOpenModeFlags.ReadOnly,
                MessageId = messageId
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(openMessageRequest, this.insideObjHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopOpenMessageResponse openMessageResponse = (RopOpenMessageResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, openMessageResponse.ReturnValue, "Call RopOpenMessage should success.");
            targetMessageHandle = this.ResponseSOHs[0][openMessageResponse.OutputHandleIndex];

            #region Verify MS-OXCMSG_R676, MS-OXCMSG_R678 and MS-OXCMSG_R1298
            string subjectPrefixInOpenResponse = System.Text.ASCIIEncoding.ASCII.GetString(openMessageResponse.SubjectPrefix.String);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R676
            this.Site.CaptureRequirementIfAreEqual<string>(
                TestDataOfPidTagSubjectPrefix,
                subjectPrefixInOpenResponse.Substring(0, subjectPrefixInOpenResponse.Length - 1),
                676,
                @"[In RopOpenMessage ROP Response Buffer] [SubjectPrefix] The SubjectPrefix field contains the value of the PidTagSubjectPrefix property (section 2.2.1.9).");

            string normalizedSubjectInOpenResponse = System.Text.ASCIIEncoding.ASCII.GetString(openMessageResponse.NormalizedSubject.String);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R678
            this.Site.CaptureRequirementIfAreEqual<string>(
                TestSuiteBase.TestDataOfPidTagNormalizedSubject,
                normalizedSubjectInOpenResponse.Substring(0, normalizedSubjectInOpenResponse.Length - 1),
                678,
                @"[In RopOpenMessage ROP Response Buffer] [NormalizedSubject] The NormalizedSubject field contains the value of the PidTagNormalizedSubject property (section 2.2.1.10).");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R1298
            this.Site.CaptureRequirementIfAreEqual<int>(
                0x10,
                openMessageResponse.RecipientRows[0].RecipientType,
                1298,
                @"[In RopOpenMessage ROP Response Buffer] [RecipientRows] The value 0x10 means when resending a previous failure, this flag indicates that this recipient (1) did not successfully receive the message on the previous attempt.");

            #endregion
            #endregion

            #region Call RopGetPropertiesAll to get all properties of created message.
            RopGetPropertiesAllRequest getPropertiesAllRequest = new RopGetPropertiesAllRequest()
            {
                RopId = (byte)RopId.RopGetPropertiesAll,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,

                // Set PropertySizeLimit,which specifies the maximum size allowed for a property value returned,
                // as specified in [MS-OXCROPS] section 2.2.8.4.1.
                PropertySizeLimit = 0xFFFF,
                WantUnicode = 1,
            };

            // In process, call capture code to verify adapter requirement
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesAllRequest, targetMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.MessageProperties);
            RopGetPropertiesAllResponse getPropertiesAllResponse = (RopGetPropertiesAllResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesAllResponse.ReturnValue, "Call RopGetPropertiesAll should success.");
            List<PropertyObj> propertyValues = PropertyHelper.GetPropertyObjFromBuffer(getPropertiesAllResponse);

            PropertyObj pidTagImportance = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagImportance);
            PropertyObj pidTagPriority = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagPriority);
            PropertyObj pidTagSensitivity = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagSensitivity);
            PropertyObj pidTagTrustSender = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagTrustSender);
            PropertyObj pidTagSubject = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagSubject);
            PropertyObj pidTagSubjectPrefix = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagSubjectPrefix);
            PropertyObj pidTagNormalizedSubject = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagNormalizedSubject);

            #region Verify requirements
            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R1668 ,the property count is {0}.", getPropertiesAllResponse.PropertyValueCount);

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R1668
            bool isVerifiedR1668 = getPropertiesAllResponse.PropertyValueCount > 0;

            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR1668,
                1668,
                @"[In RopOpenMessage ROP Response Buffer] [HasNamedProperties] Nonzero: Named properties are defined for this Message object and can be obtained through a RopGetPropertiesAll ROP request ([MS-OXCROPS] section 2.2.8.4).");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R72
            this.Site.CaptureRequirementIfAreEqual<int>(
                0x00000000,
                Convert.ToInt32(pidTagImportance.Value),
                72,
                @"[In PidTagImportance Property] [The value 0x00000000 indicates the level of importance assigned by the end user to the Message object is] Low importance.");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R80
            this.Site.CaptureRequirementIfAreEqual<int>(
                -1,
                Convert.ToInt32(pidTagPriority.Value),
                80,
                @"[In PidTagPriority Property] [The value 0xFFFFFFFF indicates  the client's request for the priority is] Not urgent.");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R86
            this.Site.CaptureRequirementIfAreEqual<int>(
                0x00000001,
                Convert.ToInt32(pidTagSensitivity.Value),
                86,
                @"[In PidTagSensitivity Property] [The value 0x00000001 indicates the sender's assessment of the sensitivity of the Message object is] Personal.");

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R1236
                this.Site.CaptureRequirementIfAreEqual<int>(
                    0x00000001,
                    (int)pidTagTrustSender.Value,
                    1236,
                    @"[In PidTagTrustSender] The value 0x00000001 indicates that the message was delivered through a trusted transport channel.");

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R1713
                this.Site.CaptureRequirementIfIsNotNull(
                    pidTagTrustSender.Value,
                    1713,
                    @"[In Appendix A: Product Behavior] Implementation does support the PidTagTrustSender property. (Exchange 2007 follows this behavior.)");
            }

            PropertyObj pidTagPurportedSenderDomain = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagPurportedSenderDomain);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R1214
            this.Site.CaptureRequirementIfAreEqual<string>(
                Common.GetConfigurationPropertyValue("Domain", this.Site),
                pidTagPurportedSenderDomain.Value.ToString(),
                1214,
                @"[In PidTagPurportedSenderDomain Property] The PidTagPurportedSenderDomain property ([MS-OXPROPS] section 2.865) contains the domain name of the last sender responsible for transmitting the current message.");

            PropertyObj pidTagAlternateRecipientAllowed = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagAlternateRecipientAllowed);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R1797
            this.Site.CaptureRequirementIfIsTrue(
                Convert.ToBoolean(pidTagAlternateRecipientAllowed.Value),
                1797,
                @"[In PidTagAlternateRecipientAllowed Property] This property [PidTagAlternateRecipientAllowed] is set to ""TRUE"" if autoforwarding is allowed.");

            PropertyObj pidTagResponsibility = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagResponsibility);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R1198
            this.Site.CaptureRequirementIfIsTrue(
                Convert.ToBoolean(pidTagResponsibility.Value),
                1198,
                @"[In PidTagResponsibility Property] This property [PidTagResponsibility] is set to ""TRUE"" if another agent has accepted responsibility.");

            pidTagMessageFlags = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagMessageFlags);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R515
            this.Site.CaptureRequirementIfAreEqual<int>(
                0x00000080,
                Convert.ToInt32(pidTagMessageFlags.Value) & 0x00000080,
                515,
                @"[In PidTagMessageFlags Property] [mfResend (0x00000080)] The message includes a request for a resend operation with a non-delivery report.");
            #endregion
            #endregion

            #region Call RopGetPropertiesSpecific to get the specific properties of created message.
            List<PropertyTag> propertiesOfMessage = this.GetPropertyTagListOfMessageObject();
            propertyValues = this.GetSpecificPropertiesOfMessage(logonResponse.FolderIds[4], messageId, this.insideObjHandle, propertiesOfMessage);

            // Parse property response get Property Value to verify test  case requirement
            pidTagImportance = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagImportance);
            pidTagSubjectPrefix = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagSubjectPrefix);
            pidTagNormalizedSubject = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagNormalizedSubject);
            pidTagSubject = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagSubject);
            PropertyObj pidTagRecipientDisplayName = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagRecipientDisplayName);

            #region Verify requirements
            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R58");

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R58
            this.Site.CaptureRequirementIfAreEqual<string>(
                TestDataOfPidTagSubjectPrefix,
                pidTagSubjectPrefix.Value.ToString(),
                58,
                @"[In PidTagSubjectPrefix Property] The PidTagSubjectPrefix property ([MS-OXPROPS] section 2.1096) contains the prefix for the subject of the message.");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R64
            this.Site.CaptureRequirementIfAreEqual<string>(
                TestSuiteBase.TestDataOfPidTagNormalizedSubject,
                pidTagNormalizedSubject.Value.ToString(),
                64,
                @"[In PidTagNormalizedSubject Property] The PidTagNormalizedSubject property ([MS-OXPROPS] section 2.877) contains the normalized subject of the message, as specified in [MS-OXCMAIL] section 2.2.3.2.6.1.");

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

            string mailSubject = TestDataOfPidTagSubjectPrefix + TestDataOfPidTagNormalizedSubject;

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R1238
            this.Site.CaptureRequirementIfAreEqual<string>(
                mailSubject,
                pidTagSubject.Value.ToString(),
                1238,
                @"[In PidTagSubject Property] The PidTagSubject property ([MS-OXPROPS] section 2.1021) contains the full subject of an e-mail message.");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R1239
            this.Site.CaptureRequirementIfAreEqual<string>(
                mailSubject,
                pidTagSubject.Value.ToString(),
                1239,
                @"[In PidTagSubject Property] The full subject is a concatenation of the subject prefix, as identified by the PidTagSubjectPrefix property (section 2.2.1.9), and the normalized subject, as identified by the PidTagNormalizedSubject property (section 2.2.1.10).");

            PropertyObj pidTagAutoForwarded = PropertyHelper.GetPropertyByName(propertyValues, PropertyNames.PidTagAutoForwarded);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R1108
            this.Site.CaptureRequirementIfAreEqual<byte>(
                0x00,
                Convert.ToByte(pidTagAutoForwarded.Value),
                1108,
                @"[In PidTagAutoForwarded Property] If this property [PidTagAutoForwarded] is unset, a default value of 0x00 is assumed.");
            
            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R2047");
        
            // Verify MS-OXCMSG requirement: MS-OXCMSG_R2047
            this.Site.CaptureRequirementIfAreEqual<string>(
                Common.GetConfigurationPropertyValue("AdminUserName", this.Site),
                pidTagRecipientDisplayName.Value.ToString(),
                2047,
                @"[In PidTagRecipientDisplayName Property] The PidTagRecipientDisplayName property ([MS-OXPROPS] section 2.888) specifies the display name of a recipient (2).");
            #endregion
            #endregion

            #region Receive the message sent by step 9.
            bool isMessageReceived = WaitEmailBeDelivered(folderHandle, rowCountBeforeSubmit);
            Site.Assert.IsTrue(isMessageReceived, "The message should be received.");
            #endregion

            #region Call RopRelease to release all resources.
            this.ReleaseRop(targetMessageHandle);
            this.ReleaseRop(folderHandle);
            #endregion
        }
        public void MSOXCFOLD_S03_TC08_SetAndGetProperties()
        {
            this.CheckWhetherSupportTransport();
            this.Adapter.DoConnect(ConnectionType.PrivateMailboxServer);
            this.GenericFolderInitialization();

            #region Step 1. The client calls RopCreateFolder to create [MSOXCFOLDSubfolder1] under the root folder.

            RopCreateFolderRequest createFolderRequest = new RopCreateFolderRequest
            {
                RopId = (byte)RopId.RopCreateFolder,
                LogonId = Constants.CommonLogonId,
                InputHandleIndex = Constants.CommonInputHandleIndex,
                OutputHandleIndex = Constants.CommonOutputHandleIndex,
                FolderType = 0x01,
                UseUnicodeStrings = 0x1,
                OpenExisting = 0x00,
                Reserved = 0x0,
                DisplayName = Encoding.Unicode.GetBytes(Constants.Subfolder1),
                Comment = Encoding.Unicode.GetBytes(Constants.Subfolder1)
            };

            RopCreateFolderResponse createFolderResponse = this.Adapter.CreateFolder(createFolderRequest, this.RootFolderHandle, ref this.responseHandles);
            Site.Assert.AreEqual<uint>(Constants.SuccessCode, createFolderResponse.ReturnValue, "RopCreateFolder ROP operation performs successfully!");
            ulong subfolderId1 = createFolderResponse.FolderId;
            uint subfolderHandle1 = this.responseHandles[0][createFolderResponse.OutputHandleIndex];

            #endregion

            #region Step 2. The client calls RopCreateFolder to create [MSOXCFOLDSubfolder2] under the root folder.

            createFolderRequest.FolderType = 0x02;
            createFolderRequest.DisplayName = Encoding.Unicode.GetBytes(Constants.Subfolder2);
            createFolderRequest.Comment = Encoding.Unicode.GetBytes(Constants.StringNullTerminated);

            createFolderResponse = this.Adapter.CreateFolder(createFolderRequest, this.RootFolderHandle, ref this.responseHandles);
            Site.Assert.AreEqual<uint>(Constants.SuccessCode, createFolderResponse.ReturnValue, "RopCreateFolder ROP operation performs successfully!");
            uint subfolderHandle2 = this.responseHandles[0][createFolderResponse.OutputHandleIndex];

            #endregion

            #region Step 3. The client creates a Non-FAI message and saves it in [MSOXCFOLDSubfolder1].

            uint messageHandle1 = 0;
            ulong messageId1 = 0;
            this.CreateSaveMessage(subfolderHandle1, subfolderId1, ref messageId1, ref messageHandle1);

            #endregion

            #region Step 4. The client create a FAI message and saves it in [MSOXCFOLDSubfolder2].

            uint messageHandle2 = 0;
            ulong messageId2 = 0;
            this.CreateSaveMessage(subfolderHandle2, subfolderId1, 0x01, ref messageId2, ref messageHandle2);

            #endregion

            #region Step 5. The client get the properties from the [MSOXCFOLDSubfolder1] under the root folder.

            PropertyTag[] tags = new PropertyTag[7];
            PropertyTag tag;

            tag.PropertyId = (ushort)FolderPropertyId.PidTagAttributeHidden;
            tag.PropertyType = (ushort)PropertyType.PtypBoolean;
            tags[0] = tag;

            tag.PropertyId = (ushort)FolderPropertyId.PidTagComment;
            tag.PropertyType = (ushort)PropertyType.PtypString;
            tags[1] = tag;

            tag.PropertyId = (ushort)FolderPropertyId.PidTagContainerClass;
            tag.PropertyType = (ushort)PropertyType.PtypString;
            tags[2] = tag;

            tag.PropertyId = (ushort)FolderPropertyId.PidTagDisplayName;
            tag.PropertyType = (ushort)PropertyType.PtypString;
            tags[3] = tag;

            tag.PropertyId = (ushort)FolderPropertyId.PidTagFolderType;
            tag.PropertyType = (ushort)PropertyType.PtypInteger32;
            tags[4] = tag;

            tag.PropertyId = (ushort)FolderPropertyId.PidTagRights;
            tag.PropertyType = (ushort)PropertyType.PtypInteger32;
            tags[5] = tag;

            tag.PropertyId = (ushort)FolderPropertyId.PidTagAccessControlListData;
            tag.PropertyType = (ushort)PropertyType.PtypBinary;
            tags[6] = tag;

            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest();
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse = new RopGetPropertiesSpecificResponse();
            getPropertiesSpecificRequest.RopId = (byte)RopId.RopGetPropertiesSpecific;
            getPropertiesSpecificRequest.LogonId = Constants.CommonLogonId;
            getPropertiesSpecificRequest.InputHandleIndex = Constants.CommonInputHandleIndex;
            getPropertiesSpecificRequest.PropertySizeLimit = 0xFFFF;
            getPropertiesSpecificRequest.PropertyTagCount = (ushort)tags.Length;
            getPropertiesSpecificRequest.PropertyTags = tags;
            getPropertiesSpecificRequest.WantUnicode = 0x01;
            getPropertiesSpecificResponse = this.Adapter.GetFolderObjectSpecificProperties(getPropertiesSpecificRequest, subfolderHandle1, ref this.responseHandles);
            Site.Assert.AreEqual<uint>(0, getPropertiesSpecificResponse.ReturnValue, "RopGetPropertiesSpecific ROP operation performs successfully!");
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse1 = getPropertiesSpecificResponse;

            #region Verify the requirements: MS_OXCFOLD_R1033, MS-OXCFOLD_R10359, and MS-OXCFOLD_R811.

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

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R1033.
            Site.CaptureRequirementIfAreEqual<byte>(
                0,
                getPropertiesSpecificResponse.RowData.PropertyValues[0].Value[0],
                1033,
                @"[In PidTagAttributeHidden Property] The value is zero otherwise [If the folder is not hidden].");

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

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R10359
            Site.CaptureRequirementIfAreEqual<string>(
                Constants.Subfolder1,
                Encoding.Unicode.GetString(getPropertiesSpecificResponse.RowData.PropertyValues[1].Value),
                10359,
                @"[In PidTagComment Property] The PidTagComment property ([MS-OXPROPS] section 2.628) contains a comment about the purpose or content of the folder.");

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

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R811
            Site.CaptureRequirementIfAreEqual<int>(
                1,
                BitConverter.ToInt32(getPropertiesSpecificResponse.RowData.PropertyValues[4].Value, 0),
                811,
                @"[In PidTagFolderType Property] FOLDER_GENERIC (1): A generic folder that contains messages and other folders.");
            #endregion

            #endregion

            #region Step 6. The client set the read/write properties for the folder.

            TaggedPropertyValue[] taggedPropertyValueArray = new TaggedPropertyValue[6];
            PropertyTag tempPropertyTag = new PropertyTag();
            int size = 0;

            // Set PidTagAttributeHidden property for the folder.
            taggedPropertyValueArray[0] = new TaggedPropertyValue();
            tempPropertyTag.PropertyId = (ushort)FolderPropertyId.PidTagAttributeHidden;
            tempPropertyTag.PropertyType = (ushort)PropertyType.PtypBoolean;
            taggedPropertyValueArray[0].PropertyTag = tempPropertyTag;
            taggedPropertyValueArray[0].Value = new byte[1] { 0x01 };

            // Set PidTagComment property for the folder.
            taggedPropertyValueArray[1] = new TaggedPropertyValue();
            tempPropertyTag.PropertyId = (ushort)FolderPropertyId.PidTagComment;
            tempPropertyTag.PropertyType = (ushort)PropertyType.PtypString;
            taggedPropertyValueArray[1].PropertyTag = tempPropertyTag;
            taggedPropertyValueArray[1].Value = Encoding.Unicode.GetBytes(Constants.Subfolder3);

            // Set PidTagContainerClass property for the folder.
            taggedPropertyValueArray[2] = new TaggedPropertyValue();
            tempPropertyTag.PropertyId = (ushort)FolderPropertyId.PidTagContainerClass;
            tempPropertyTag.PropertyType = (ushort)PropertyType.PtypString;
            taggedPropertyValueArray[2].PropertyTag = tempPropertyTag;
            taggedPropertyValueArray[2].Value = Encoding.Unicode.GetBytes("IPF.Note\0");

            // Set PidTagDisplayName property for the folder.
            taggedPropertyValueArray[3] = new TaggedPropertyValue();
            tempPropertyTag.PropertyId = (ushort)FolderPropertyId.PidTagDisplayName;
            tempPropertyTag.PropertyType = (ushort)PropertyType.PtypString;
            taggedPropertyValueArray[3].PropertyTag = tempPropertyTag;
            taggedPropertyValueArray[3].Value = Encoding.Unicode.GetBytes(Constants.Subfolder3);

            // Set PidTagFolderType property for the folder.
            taggedPropertyValueArray[4] = new TaggedPropertyValue();
            tempPropertyTag.PropertyId = (ushort)FolderPropertyId.PidTagFolderType;
            tempPropertyTag.PropertyType = (ushort)PropertyType.PtypInteger32;
            taggedPropertyValueArray[4].PropertyTag = tempPropertyTag;
            taggedPropertyValueArray[4].Value = BitConverter.GetBytes(0x00000001);

            // Set PidTagRights property for the folder.
            taggedPropertyValueArray[5] = new TaggedPropertyValue();
            tempPropertyTag.PropertyId = (ushort)FolderPropertyId.PidTagRights;
            tempPropertyTag.PropertyType = (ushort)PropertyType.PtypInteger32;
            taggedPropertyValueArray[5].PropertyTag = tempPropertyTag;
            taggedPropertyValueArray[5].Value = BitConverter.GetBytes(0x00000400);

            for (int i = 0; i < taggedPropertyValueArray.Length; i++)
            {
                size += taggedPropertyValueArray[i].Size();
            }

            RopSetPropertiesRequest setPropertiesRequest = new RopSetPropertiesRequest
            {
                RopId = (byte)RopId.RopSetProperties,
                LogonId = Constants.CommonLogonId,
                InputHandleIndex = Constants.CommonInputHandleIndex,
                PropertyValueSize = (ushort)(size + 2),
                PropertyValueCount = (ushort)taggedPropertyValueArray.Length,
                PropertyValues = taggedPropertyValueArray
            };

            RopSetPropertiesResponse setPropertiesResponse = this.Adapter.SetFolderObjectProperties(setPropertiesRequest, subfolderHandle1, ref this.responseHandles);
            Site.Assert.AreEqual<uint>(0, setPropertiesResponse.ReturnValue, "RopSetProperties ROP operation performs successfully!");

            #endregion

            #region Step 7. The client get the properties from the [MSOXCFOLDSubfolder1] under the root folder after execute the RopSetProperties operation.

            getPropertiesSpecificResponse = this.Adapter.GetFolderObjectSpecificProperties(getPropertiesSpecificRequest, subfolderHandle1, ref this.responseHandles);
            Site.Assert.AreEqual<uint>(0, getPropertiesSpecificResponse.ReturnValue, "RopGetPropertiesSpecific ROP operation performs successfully!");

            #region Verify the requirements: MS_OXCFOLD_R1032, MS-OXCFOLD_R10356.

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

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R1032.
            Site.CaptureRequirementIfAreNotEqual<byte>(
                0,
                getPropertiesSpecificResponse.RowData.PropertyValues[0].Value[0],
                1032,
                @"[In PidTagAttributeHidden Property] The value of this property [PidTagAttributeHidden] is nonzero if the folder is hidden.");

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

            // MS-OXCFOLD_R1032 and MS-OXCFOLD_R1033 were verified, MS-OXCFOLD_R10356 can be verified directly.
            Site.CaptureRequirement(
                10356,
                @"[In PidTagAttributeHidden Property] The PidTagAttributeHidden property ([MS-OXPROPS] section 2.602) specifies whether the folder is hidden.");

            string pidTagContainerClass = System.Text.Encoding.Unicode.GetString(getPropertiesSpecificResponse.RowData.PropertyValues[2].Value);
            
            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCFOLD_R1038: the PidTagContainerClass property value is {0}", pidTagContainerClass.Replace("\0", string.Empty));
        
            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R1038
            this.Site.CaptureRequirementIfIsTrue(
                pidTagContainerClass.StartsWith("IPF."),
                1038,
                @"[In PidTagContainerClass Property] The value of this property [PidTagContainerClass] MUST begin with ""IPF."".");

            // According to step above, the folder object includes the PidTagContainerClass property and the value of the PidTagContainerClass property follow the definition in Open Specification.
            // So R10036 will be verfied.
            this.Site.CaptureRequirement(
                10036,
                @"[In PidTagContainerClass Property] The PidTagContainerClass property ([MS-OXPROPS] section 2.633) specifies the type of Message object that the folder contains.");
            #endregion

            #endregion

            #region Step 8. The client get the properties from the [MSOXCFOLDSubfolder2] under the root folder.

            getPropertiesSpecificResponse = this.Adapter.GetFolderObjectSpecificProperties(getPropertiesSpecificRequest, subfolderHandle2, ref this.responseHandles);
            Site.Assert.AreEqual<uint>(0, getPropertiesSpecificResponse.ReturnValue, "RopGetPropertiesSpecific ROP operation performs successfully!");
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse3 = getPropertiesSpecificResponse;

            #region Verify the requirement: MS-OXCFOLD_R812 and  MS-OXCFOLD_R1034.

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

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R812
            Site.CaptureRequirementIfAreEqual<int>(
                2,
                BitConverter.ToInt32(getPropertiesSpecificResponse.RowData.PropertyValues[4].Value, 0),
                812,
                @"[In PidTagFolderType Property] FOLDER_SEARCH (2): A folder that contains the results of a search, in the form of links to messages that meet search criteria.");

            bool isVerifyR1034 = Encoding.Unicode.GetString(getPropertiesSpecificResponse1.RowData.PropertyValues[1].Value) == Constants.Subfolder1 &&
                Encoding.Unicode.GetString(getPropertiesSpecificResponse3.RowData.PropertyValues[1].Value) == Constants.StringNullTerminated;

            // Add the debug information.
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCFOLD_R1034, the property [PidTagComment] is present {0} only if the client sets it.", isVerifyR1034 ? string.Empty : "not");

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R1034.
            Site.CaptureRequirementIfIsTrue(
                isVerifyR1034,
                1034,
                @"[In PidTagComment Property] This property [PidTagComment] is present only if the client sets it when the folder is created.");

            #endregion

            #endregion

            #region Step 8. The client set the same read/write properties for the [MSOXCFOLDSubfolder2] as [MSOXCFOLDSubfolder1].
            taggedPropertyValueArray = new TaggedPropertyValue[1];
            tempPropertyTag = new PropertyTag();

            // Set PidTagDisplayName property for the folder.
            taggedPropertyValueArray[0] = new TaggedPropertyValue();
            tempPropertyTag.PropertyId = (ushort)FolderPropertyId.PidTagDisplayName;
            tempPropertyTag.PropertyType = (ushort)PropertyType.PtypString;
            taggedPropertyValueArray[0].PropertyTag = tempPropertyTag;
            taggedPropertyValueArray[0].Value = Encoding.Unicode.GetBytes(Constants.Subfolder3);

            setPropertiesRequest = new RopSetPropertiesRequest
            {
                RopId = (byte)RopId.RopSetProperties,
                LogonId = Constants.CommonLogonId,
                InputHandleIndex = Constants.CommonInputHandleIndex,
                PropertyValueSize = (ushort)(taggedPropertyValueArray[0].Size() + 2),
                PropertyValueCount = (ushort)taggedPropertyValueArray.Length,
                PropertyValues = taggedPropertyValueArray
            };
            setPropertiesResponse = this.Adapter.SetFolderObjectProperties(setPropertiesRequest, subfolderHandle2, ref this.responseHandles);

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

            // Only set one property in RopSetProperties ROP request, use 0 as index here.
            int expectedIndex = 0;
            bool isVerifiedR1039 = false;
            if (setPropertiesResponse.PropertyProblems != null)
            {
                Site.Log.Add(
                    LogEntryKind.Debug,
                    "The PropertyProblems of index {0} in RopSetProperties ROP response return value is: {1}",
                    expectedIndex,
                    setPropertiesResponse.PropertyProblems[expectedIndex].ErrorCode);
                isVerifiedR1039 = setPropertiesResponse.PropertyProblems[expectedIndex].ErrorCode != Constants.SuccessCode;
            }
            else
            {
                Site.Log.Add(LogEntryKind.Debug, "The RopSetProperties ROP response return value is: {0}", setPropertiesResponse.ReturnValue);
                isVerifiedR1039 = setPropertiesResponse.ReturnValue != Constants.SuccessCode;
            }

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R1039.
            Site.CaptureRequirementIfIsTrue(
                isVerifiedR1039,
                1039,
                @"[In PidTagDisplayName Property] Sibling folders MUST have unique display names.");
            #endregion

            #region Step 9. The client calls RopOpenFolder to get the Root folder handle.

            RopOpenFolderRequest openFolderRequest = new RopOpenFolderRequest
            {
                RopId = (byte)RopId.RopOpenFolder,
                LogonId = Constants.CommonLogonId,
                InputHandleIndex = Constants.CommonInputHandleIndex,
                OutputHandleIndex = Constants.CommonOutputHandleIndex,
                FolderId = this.DefaultFolderIds[0],
                OpenModeFlags = (byte)FolderOpenModeFlags.OpenSoftDeleted
            };

            RopOpenFolderResponse openFolderResponse = this.Adapter.OpenFolder(openFolderRequest, this.LogonHandle, ref this.responseHandles);
            Site.Assert.AreEqual<uint>(Constants.SuccessCode, openFolderResponse.ReturnValue, "RopOpenFolder ROP operation performs successfully!");
            uint rootFolderHandle = this.responseHandles[0][openFolderResponse.OutputHandleIndex];

            #endregion

            #region Step 10. The client get the properties from the Root folder.

            getPropertiesSpecificResponse = this.Adapter.GetFolderObjectSpecificProperties(getPropertiesSpecificRequest, rootFolderHandle, ref this.responseHandles);
            Site.Assert.AreEqual<uint>(0, getPropertiesSpecificResponse.ReturnValue, "RopGetPropertiesSpecific ROP operation performs successfully!");

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

            // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R810.
            Site.CaptureRequirementIfAreEqual<int>(
                0,
                BitConverter.ToInt32(getPropertiesSpecificResponse.RowData.PropertyValues[4].Value, 0),
                810,
                @"[In PidTagFolderType Property] FOLDER_ROOT (0): The Root folder of the folder hierarchy table; that is, a folder that has no parent folder.");

            RopGetPropertiesAllResponse getPropertiesAllResponse = this.Adapter.GetFolderPropertiesAll(this.RootFolderHandle, ref this.responseHandles);
            Site.Assert.AreEqual<uint>(0, getPropertiesAllResponse.ReturnValue, "RopGetPropertiesAllResponse ROP operation performs successfully!");
            #endregion

            #region Step 11. The client get property PidTagAddressBookEntryId
            if (Common.IsRequirementEnabled(350002, this.Site))
            {
                PropertyTag[] propertyTagArray = new PropertyTag[1];
                PropertyTag propertyTag = new PropertyTag
                {
                    PropertyId = (ushort)FolderPropertyId.PidTagAddressBookEntryId,
                    PropertyType = (ushort)PropertyType.PtypBinary
                };
                propertyTagArray[0] = propertyTag;

                getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest();
                getPropertiesSpecificRequest.RopId = (byte)RopId.RopGetPropertiesSpecific;
                getPropertiesSpecificRequest.LogonId = Constants.CommonLogonId;
                getPropertiesSpecificRequest.InputHandleIndex = Constants.CommonInputHandleIndex;
                getPropertiesSpecificRequest.PropertySizeLimit = 0xFFFF;
                getPropertiesSpecificRequest.PropertyTagCount = (ushort)propertyTagArray.Length;
                getPropertiesSpecificRequest.PropertyTags = propertyTagArray;

                getPropertiesSpecificResponse = this.Adapter.GetFolderObjectSpecificProperties(getPropertiesSpecificRequest, subfolderHandle1, ref this.responseHandles);
                Site.Assert.AreEqual<uint>(0, getPropertiesSpecificResponse.ReturnValue, "RopGetPropertiesSpecific ROP operation performs successfully!");

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

                // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R350.
                // Flag value 0x01 indicates there is error.
                Site.CaptureRequirementIfAreEqual<byte>(
                    0x01,
                    getPropertiesSpecificResponse.RowData.Flag,
                    350,
                    @"[In PidTagAddressBookEntryId Property] This property is set only for public folders.");
            }
            #endregion
        }
        public void MSOXCMSG_S08_TC06_MIMEProperties()
        {
            this.CheckMapiHttpIsSupported();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);

            #region Call RopLogon to log on a mailbox.
            RopLogonResponse logonResponse = this.Logon(LogonType.Mailbox, out this.insideObjHandle);
            #endregion

            #region Call RopCreateMessage to create a message
            uint targetMessageHandle = this.CreatedMessage(logonResponse.FolderIds[4], this.insideObjHandle);
            #endregion

            #region Call RopSaveChangesMessage to save the message
            RopSaveChangesMessageResponse saveChangesMessageResponse;
            saveChangesMessageResponse = this.SaveMessage(targetMessageHandle, (byte)SaveFlags.ForceSave);
            #endregion

            #region Call RopOpenMessage to open the message.
            RopOpenMessageResponse openMessageResponse;
            uint openedMessageHandle = this.OpenSpecificMessage(logonResponse.FolderIds[4], saveChangesMessageResponse.MessageId, this.insideObjHandle, MessageOpenModeFlags.ReadWrite, out openMessageResponse);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, openMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopCreateAttachment to create an attachment.
            RopCreateAttachmentResponse createAttachmentResponse;
            uint attachmentId;
            uint attachmentHandle = this.CreateAttachment(openedMessageHandle, out createAttachmentResponse, out attachmentId);
            #endregion

            #region Call RopSaveChangesAttachment to save the attachment.
            RopSaveChangesAttachmentResponse saveChangesAttachmentResponse;
            this.SaveAttachment(attachmentHandle, out saveChangesAttachmentResponse);
            #endregion

            #region Call RopSaveChangesMessage to save the message
            saveChangesMessageResponse = this.SaveMessage(openedMessageHandle, (byte)SaveFlags.ForceSave);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, saveChangesMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Set MIME properties which are not initialized during creating the attachment
            List<PropertyObj> specificProperties = new List<PropertyObj>
            {
                new PropertyObj(PropertyNames.PidTagAttachLongFilename, Common.GetBytesFromUnicodeString(TestDataOfPidTagAttachLongFileName)),
                new PropertyObj(PropertyNames.PidTagAttachExtension, Common.GetBytesFromUnicodeString(TestDataOfPidTagAttachExtension)),
                new PropertyObj(PropertyNames.PidTagAttachMimeTag, Common.GetBytesFromUnicodeString(TestDataOfPidTagAttachMimeTag)),
                new PropertyObj(PropertyNames.PidTagAttachContentId, Common.GetBytesFromUnicodeString(TestDataOfPidTagAttachContentId)),
                new PropertyObj(PropertyNames.PidTagAttachContentLocation, Common.GetBytesFromUnicodeString(TestDataOfPidTagAttachContentLocation)),
                new PropertyObj(PropertyNames.PidTagAttachContentBase, Common.GetBytesFromUnicodeString(TestDataOfPidTagAttachContentBase)),
                new PropertyObj(PropertyNames.PidTagAttachPayloadClass, Common.GetBytesFromUnicodeString(TestDataOfPidTagAttachPayloadClass)),
                new PropertyObj(PropertyNames.PidTagAttachPayloadProviderGuidString, Common.GetBytesFromUnicodeString(TestDataOfPidTagAttachPayloadProviderGuidString))
            };
            
            this.SetPropertiesForMessage(attachmentHandle, specificProperties);
            #endregion

            #region Send a RopGetPropertiesSpecific request to get all properties of specific message object.
            PropertyTag[] tagArray = this.CreateMIMEAttachmentPropertyTagsForCapture();
            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest()
            {
                RopId = (byte)RopId.RopGetPropertiesSpecific,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                PropertySizeLimit = 0xFFFF,
                PropertyTagCount = (ushort)tagArray.Length,
                PropertyTags = tagArray
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, attachmentHandle, ref this.response, ref this.rawData, GetPropertiesFlags.AttachmentProperties);
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

            List<PropertyObj> ps = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);
            PropertyObj pidTagAttachExtension = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagAttachExtension);
            PropertyObj pidTagAttachLongFilename = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagAttachLongFilename);
            PropertyObj pidTagAttachContentBase = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagAttachContentBase);
            PropertyObj pidTagAttachContentLocation = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagAttachContentLocation);
            PropertyObj pidTagAttachContentId = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagAttachContentId);
            PropertyObj pidTagAttachPayloadClass = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagAttachPayloadClass);
            PropertyObj pidTagAttachPayloadProviderGuidString = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagAttachPayloadProviderGuidString);
            PropertyObj pidTagAttachMimeTag = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagAttachMimeTag);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R963
            this.Site.CaptureRequirementIfAreEqual<string>(
                TestDataOfPidTagAttachMimeTag,
                Convert.ToString(pidTagAttachMimeTag.Value),
                963,
                @"[In MIME Properties] PidTagAttachMimeTag: The Content-Type header (2).");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R964
            this.Site.CaptureRequirementIfAreEqual<string>(
                TestDataOfPidTagAttachContentId,
                Convert.ToString(pidTagAttachContentId.Value),
                964,
                @"[In MIME properties] PidTagAttachContentId: A content identifier unique to this Message object that matches a corresponding ""cid:"" URI scheme reference in the HTML body of the Message object.");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R1284
            this.Site.CaptureRequirementIfAreEqual<string>(
                TestDataOfPidTagAttachPayloadClass,
                Convert.ToString(pidTagAttachPayloadClass.Value),
                1284,
                @"[In MIME Properties] PidTagAttachPayloadClass: The class name of an object that can display the contents of the message.");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R1286
            this.Site.CaptureRequirementIfAreEqual<string>(
                TestDataOfPidTagAttachPayloadProviderGuidString,
                Convert.ToString(pidTagAttachPayloadProviderGuidString.Value),
                1286,
                @"[In MIME Properties] PidTagAttachPayloadProviderGuidString: The GUID of the software application that can display the contents of the message.");

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R965, the value of PidTagBodyContentLocation is {0}.", pidTagAttachContentLocation.Value.ToString());

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R965
            bool isVerifiedR965 = Uri.IsWellFormedUriString(pidTagAttachContentLocation.Value.ToString(), UriKind.RelativeOrAbsolute);

            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR965,
                965,
                @"[In MIME properties] PidTagAttachContentLocation: A relative or full URI that matches a corresponding reference in the HTML body of the Message object.");

            if (Uri.IsWellFormedUriString(pidTagAttachContentLocation.Value.ToString(), UriKind.Relative))
            {
                // Add the debug information
                this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R967, the value of PidTagAttachContentBase is {0}.", pidTagAttachContentBase.Value.ToString());

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R967
                this.Site.CaptureRequirementIfIsNotNull(
                    pidTagAttachContentBase.Value,
                    967,
                    @"[In MIME properties] [PidTagAttachContentBase] MUST be set if the PidTagAttachContentLocation property contains a relative URI.");
            }

            int length = Convert.ToString(pidTagAttachLongFilename.Value).Length;
            string fileName = Convert.ToString(pidTagAttachLongFilename.Value);
            char[] longFileName = Convert.ToString(pidTagAttachLongFilename.Value).ToCharArray();

            int temp = length;
            while (temp > 0)
            {
                temp--;
                if (Convert.ToInt32(longFileName[temp]) == Convert.ToInt32('.'))
                {
                    break;
                }
            }

            string fileNameExtension = fileName.Substring(temp, length - temp);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R604
            this.Site.CaptureRequirementIfAreEqual<string>(
                fileNameExtension,
                Convert.ToString(pidTagAttachExtension.Value),
                604,
                @"[In PidTagAttachExtension Property] The PidTagAttachExtension property ([MS-OXPROPS] section 2.583) contains a file name extension that indicates the document type of an attachment.");
            #endregion

            #region Call RopRelease to release the created message and the created attachment
            this.ReleaseRop(attachmentHandle);
            this.ReleaseRop(targetMessageHandle);
            #endregion
        }
        /// <summary>
        /// Imports message read state changes into the server replica.
        /// </summary>
        /// <param name="serverId">A 32-bit signed integer represent the Identity of server.</param>
        /// <param name="objHandleIndex">Sync handle.</param>
        /// <param name="objectHandleIndex">Message handle or folder handle or attachments handle.</param>
        /// <param name="readStatus">A boolean value indicating the message read status, true means read.</param>
        /// <returns>Indicate the result of this ROP operation.</returns>
        public RopResult SynchronizationImportReadStateChanges(int serverId, int objHandleIndex, int objectHandleIndex, bool readStatus)
        {
            uint synchronizationImportReadStateChangesHandle = this.handleContainer[objHandleIndex];
            uint messageHandle = this.handleContainer[objectHandleIndex];
            RopResult result = RopResult.InvalidParameter;

            // Construct RopGetPropertiesSpecificRequest.
            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest
            {
                RopId = 0x07,
                LogonId = 0x00,
                InputHandleIndex = 0x00,
                PropertySizeLimit = 0xFFFF
            };

            // Set PropertySizeLimit, which specifies the maximum size allowed for a property value returned,
            PropertyTag[] tagArray = new PropertyTag[1];
            PropertyTag tag = new PropertyTag(0x65E0, 0x0102);
            tagArray[0] = tag;
            getPropertiesSpecificRequest.PropertyTagCount = (ushort)tagArray.Length;
            getPropertiesSpecificRequest.PropertyTags = tagArray;

            // Get specific properties value.
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.Process(serverId, getPropertiesSpecificRequest, messageHandle);

            MessageReadState[] messageReadStates = new MessageReadState[1];
            MessageReadState messageReadState = new MessageReadState
            {
                MarkAsRead = readStatus ? (byte)0x01 : (byte)0x00,
                MessageId = new byte[22]
            };
            Array.Copy(getPropertiesSpecificResponse.RowData.PropertyValues[0].Value, 2, messageReadState.MessageId, 0, 22);
            messageReadState.MessageIdSize = (ushort)(getPropertiesSpecificResponse.RowData.PropertyValues[0].Value.Length - 2);
            messageReadStates[0] = messageReadState;

            // Construct the RopSynchronizationImportReadStateChanges request.
            RopSynchronizationImportReadStateChangesRequest synchronizationImportReadStateChangesRequest = new RopSynchronizationImportReadStateChangesRequest
            {
                RopId = 0x80,
                LogonId = 0x00,
                InputHandleIndex = 0x00,
                MessageReadStates = messageReadStates,
                MessageReadStateSize = (ushort)messageReadStates[0].Size()
            };

            RopSynchronizationImportReadStateChangesResponse synchronizationImportReadStateChangesResponse = (RopSynchronizationImportReadStateChangesResponse)this.Process(serverId, synchronizationImportReadStateChangesRequest, synchronizationImportReadStateChangesHandle);
            result = (RopResult)synchronizationImportReadStateChangesResponse.ReturnValue;

            if (result == RopResult.Success)
            {
                // Verify ROP SynchronizationImportReadStateChanges
                this.VerifyRopSynchronizationImportReadStateChanges(synchronizationImportReadStateChangesResponse);
            }

            return result;
        }
        public void MSOXCMSG_S08_TC03_PropertiesInCreateAttachmentInitialization()
        {
            this.CheckMapiHttpIsSupported();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);

            #region Call RopLogon to log on a mailbox.
            RopLogonResponse logonResponse = this.Logon(LogonType.Mailbox, out this.insideObjHandle);
            #endregion

            #region Call RopCreateMessage to create a message
            uint targetMessageHandle = this.CreatedMessage(logonResponse.FolderIds[4], this.insideObjHandle);
            #endregion

            #region Call RopSaveChangesMessage to save the message
            RopSaveChangesMessageResponse saveChangesMessageResponse;
            saveChangesMessageResponse = this.SaveMessage(targetMessageHandle, (byte)SaveFlags.ForceSave);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, saveChangesMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopOpenMessage to open the message.
            RopOpenMessageResponse openMessageResponse;
            uint openedMessageHandle = this.OpenSpecificMessage(logonResponse.FolderIds[4], saveChangesMessageResponse.MessageId, this.insideObjHandle, MessageOpenModeFlags.ReadWrite, out openMessageResponse);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, openMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopCreateAttachment to create the attachment of the message
            RopCreateAttachmentResponse createAttachmentResponse;
            uint attachmentId;
            uint attachmentHandle = this.CreateAttachment(openedMessageHandle, out createAttachmentResponse, out attachmentId);
            #endregion

            #region Call RopGetPropertiesSpecific to get specific properties for the created attachment.
            PropertyTag[] tagArray = this.CreateAttachmentPropertyTagsForInitial();
            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest()
            {
                RopId = (byte)RopId.RopGetPropertiesSpecific,
                LogonId = CommonLogonId, // The logonId 0x00 is associated with this operation.
                InputHandleIndex = CommonInputHandleIndex, // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the input Server Object is stored. 
                PropertySizeLimit = 0xFFFF, // This value specifies the maximum number of the property
                PropertyTagCount = (ushort)tagArray.Length,
                PropertyTags = tagArray
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, attachmentHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Verify requirements related with RopCreateAttachment initialization
            List<PropertyObj> ps = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);

            // Parse property response to get Property Value to verify test case requirement
            PropertyObj pidTagAccessLevel = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagAccessLevel);
            PropertyObj pidTagCreationTime = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagCreationTime);
            PropertyObj pidTagLastModificationTime = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagLastModificationTime);
            PropertyObj pidTagAttachSize = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagAttachSize);
            PropertyObj pidTagAttachNumber = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagAttachNumber);
            PropertyObj pidTagRenderingPosition = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagRenderingPosition);

            DateTime tagCreationTime = Convert.ToDateTime(pidTagCreationTime.Value);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R2035
            // tagCreationTime is not null indicates that PidTagCreationTime is initialized when calling RopCreateAttachment ROP.
            this.Site.CaptureRequirementIfIsNotNull(
                tagCreationTime,
                2035,
                @"[In Receiving a RopCreateAttachment ROP Request] PidTagCreationTime (section 2.2.2.3) [will be initialized when calling RopCreateAttachment ROP].");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R448
            this.Site.CaptureRequirementIfAreEqual<uint>(
                attachmentId,
                Convert.ToUInt32(pidTagAttachNumber.Value),
                448,
                @"[In Receiving a RopCreateAttachment ROP Request] [The initial data of PidTagAttachNumber is] Varies, depending on the number of existing attachments on the Message object.");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R451
            this.Site.CaptureRequirementIfAreEqual<int>(
                unchecked((int)0xffffffff),
                Convert.ToInt32(pidTagRenderingPosition.Value),
                451,
                @"[In Receiving a RopCreateAttachment ROP Request] [The initial data of PidTagRenderingPosition is] 0xFFFFFFFF.");

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R1919
                this.Site.CaptureRequirementIfAreEqual<int>(
                    0x00000040,
                    Convert.ToInt32(pidTagAttachSize.Value),
                    1919,
                    @"[In Appendix A: Product Behavior] Implementation does set the PidTagAttachSize property (section 2.2.2.5) to 0x00000040. (Exchange 2007 and 2010 follow this behavior.)");
            }

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R1649
                this.Site.CaptureRequirementIfAreEqual<int>(
                    0x00000000,
                    Convert.ToInt32(pidTagAttachSize.Value),
                    1649,
                    @"[In Appendix A: Product Behavior] Implementation does set the PidTagAttachSize property (section 2.2.2.5) to 0x00000000. (Exchange 2013 and above follow this behavior.)");
            }

            int pidTagAccessLevelInitialValue = Convert.ToInt32(pidTagAccessLevel.Value);
            if (Common.IsRequirementEnabled(1920, this.Site))
            {
                // Add the debug information
                Site.Log.Add(
                    LogEntryKind.Debug,
                    "Verify MS-OXCMSG_R1920,the actual initial Data of PidTagAccessLevel is {0}",
                    pidTagAccessLevelInitialValue);

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R1920
                Site.CaptureRequirementIfAreEqual<int>(
                    0x00000001,
                    pidTagAccessLevelInitialValue,
                    1920,
                    @"[In Appendix A: Product Behavior] Implementation does set the PidTagAccessLevel property ([MS-OXCPRPT] section 2.2.1.2) to 0x00000001. (Exchange 2007 and 2010 follow this behavior.)");
            }

            if (Common.IsRequirementEnabled(1921, this.Site))
            {
                bool isVerifyR1921 = Convert.ToDateTime(pidTagLastModificationTime.Value) == tagCreationTime;

                // Above If condition has verified the initial data of PidTagLastModificationTime.
                Site.CaptureRequirementIfIsTrue(
                    isVerifyR1921,
                    1921,
                    @"[In Appendix A: Product Behavior] Implementation does set PidTagLastModificationTime the same as the PidTagCreationTime property. (Exchange 2007 and 2010 follow this behavior.)");
            }

            if (Common.IsRequirementEnabled(1651, this.Site))
            {
                DateTime lastModificationTime = Convert.ToDateTime(pidTagLastModificationTime.Value);
                TimeSpan dateOffsetModificationTime = lastModificationTime - tagCreationTime;

                bool isVerifyR1651 = dateOffsetModificationTime.Milliseconds < 0.1 && dateOffsetModificationTime.Milliseconds > -0.1;

                // Add the debug information
                this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R1651, the time period between PidTagLastModificationTime and PidTagCreationTime  is {0}.", dateOffsetModificationTime.Milliseconds);

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R1651
                this.Site.CaptureRequirementIfIsTrue(
                    isVerifyR1651,
                    1651,
                    @"[In Appendix A: Product Behavior] Implementation does set the PidTagLastModificationTime property (section 2.2.2.2) to a value that is within 100 nanoseconds of the value of the PidTagCreationTime property (section 2.2.2.3). (Exchange 2013 and above follow this behavior.)");
            }

            if (Common.IsRequirementEnabled(1650, this.Site))
            {
                // Add the debug information
                this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R1650,the actual initial Data of PidTagAccessLevel is {0}", pidTagAccessLevelInitialValue);

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R1650
                this.Site.CaptureRequirementIfAreEqual<int>(
                    0x00000000,
                    pidTagAccessLevelInitialValue,
                    1650,
                    @"[In Appendix A: Product Behavior] Implementation does set the PidTagAccessLevel property ([MS-OXCPRPT] section 2.2.1.2) to 0x00000000. (Exchange 2013 and above follow this behavior.)");
            }
            #endregion

            #region Call RopRelease to release the created message and the created attachment.
            this.ReleaseRop(attachmentHandle);
            this.ReleaseRop(targetMessageHandle);
            #endregion
        }
        /// <summary>
        /// Get changeNmuber of a specific message object.
        /// </summary>
        /// <param name="serverId">Server id.</param>
        /// <param name="messageId">ID of the message object.</param>
        /// <param name="folderId">ID of the message's parent folder.</param>
        /// <param name="folderHandle">Handle of the message's parent folder</param>
        /// <returns>Change number.</returns>
        private byte[] GetChangeNumber(int serverId, ulong messageId, ulong folderId, uint folderHandle)
        {
            // Open message to get message handle.
            RopOpenMessageRequest openMessageRequest = new RopOpenMessageRequest();
            RopOpenMessageResponse openMessageResponse = new RopOpenMessageResponse();
            openMessageRequest.CodePageId = 0x0fff;
            openMessageRequest.FolderId = folderId;
            openMessageRequest.InputHandleIndex = 0x00;
            openMessageRequest.LogonId = 0x00;
            openMessageRequest.MessageId = messageId;
            openMessageRequest.OpenModeFlags = 0x01;
            openMessageRequest.OutputHandleIndex = 0x01;
            openMessageRequest.RopId = 0x03;
            openMessageResponse = (RopOpenMessageResponse)this.Process(serverId, openMessageRequest, folderHandle);
            uint handle = this.responseSOHs[openMessageResponse.OutputHandleIndex];

            // Get message PidTagChangeKey value.
            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest();
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse = new RopGetPropertiesSpecificResponse();
            PropertyTag[] propertyTags = new PropertyTag[1];
            PropertyTag tag = new PropertyTag(0x65E2, 0x0102);
            propertyTags[0] = tag;

            getPropertiesSpecificRequest.RopId = 0x07;
            getPropertiesSpecificRequest.LogonId = 0x00;
            getPropertiesSpecificRequest.InputHandleIndex = 0x00;

            // Set PropertySizeLimit, which specifies the maximum size allowed for a property value returned,
            getPropertiesSpecificRequest.PropertySizeLimit = 0xFFFF;
            PropertyTag[] tagArray = propertyTags;
            getPropertiesSpecificRequest.PropertyTagCount = (ushort)tagArray.Length;
            getPropertiesSpecificRequest.PropertyTags = tagArray;

            // Send the RopGetPropertiesSpecific request
            getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.Process(serverId, getPropertiesSpecificRequest, handle);

            if (getPropertiesSpecificResponse.ReturnValue == 0x0)
            {
                byte[] tempChangeNumber = new byte[getPropertiesSpecificResponse.RowData.PropertyValues[0].Value.Length - 2];
                Array.Copy(getPropertiesSpecificResponse.RowData.PropertyValues[0].Value, 2, tempChangeNumber, 0, getPropertiesSpecificResponse.RowData.PropertyValues[0].Value.Length - 2);
                return tempChangeNumber;
            }
            else
            {
                return new byte[0];
            }
        }
        public void MSOXCMSG_S08_TC04_AttachmentObjectProperties()
        {
            this.CheckMapiHttpIsSupported();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);

            #region Call RopLogon to log on a mailbox.
            RopLogonResponse logonResponse = this.Logon(LogonType.Mailbox, out this.insideObjHandle);
            #endregion

            #region Call RopCreateMessage to create a message
            uint targetMessageHandle = this.CreatedMessage(logonResponse.FolderIds[4], this.insideObjHandle);
            #endregion

            #region Call RopSaveChangesMessage to save the message
            RopSaveChangesMessageResponse saveChangesMessageResponse;
            saveChangesMessageResponse = this.SaveMessage(targetMessageHandle, (byte)SaveFlags.ForceSave);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, saveChangesMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopOpenMessage to open the message.
            RopOpenMessageResponse openMessageResponse;
            uint openedMessageHandle = this.OpenSpecificMessage(logonResponse.FolderIds[4], saveChangesMessageResponse.MessageId, this.insideObjHandle, MessageOpenModeFlags.ReadWrite, out openMessageResponse);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, openMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopCreateAttachment to create an attachment.
            RopCreateAttachmentResponse createAttachmentResponse;
            uint attachmentId;
            uint attachmentHandle = this.CreateAttachment(openedMessageHandle, out createAttachmentResponse, out attachmentId);
            #endregion

            #region Call RopSaveChangesAttachment to save the attachment.
            RopSaveChangesAttachmentResponse saveChangesAttachmentResponse;
            this.SaveAttachment(attachmentHandle, out saveChangesAttachmentResponse);
            #endregion

            #region Call RopSaveChangesMessage to save the message
            saveChangesMessageResponse = this.SaveMessage(openedMessageHandle, (byte)SaveFlags.ForceSave);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, saveChangesMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopGetPropertiesAll to get all properties of the newly created attachment.
            RopGetPropertiesAllRequest getPropertiesAllRequest = new RopGetPropertiesAllRequest()
            {
                RopId = (byte)RopId.RopGetPropertiesAll,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,

                // Set PropertySizeLimit, which specifies the maximum size allowed for a property value returned, as specified in [MS-OXCROPS].
                PropertySizeLimit = 0xFFFF,
                WantUnicode = (ushort)0
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesAllRequest, attachmentHandle, ref this.response, ref this.rawData, GetPropertiesFlags.AttachmentProperties);
            #endregion

            #region Set specific properties which are not initialized during creating the attachment
            List<PropertyObj> specificProperties = new List<PropertyObj>
            {
                new PropertyObj(PropertyNames.PidTagAttachDataBinary, Common.AddInt16LengthBeforeBinaryArray(Common.GetBytesFromUnicodeString(TestDataOfPidTagAttachDataBinary))),
                new PropertyObj(PropertyNames.PidTagAttachLongPathname, Common.GetBytesFromUnicodeString(TestDataOfPidTagAttachLongPathname)),
                new PropertyObj(PropertyNames.PidTagAttachTag, Common.AddInt16LengthBeforeBinaryArray(this.testDataOfPidTagAttachTag)),
                new PropertyObj(PropertyNames.PidTagAttachRendering, Common.AddInt16LengthBeforeBinaryArray(Common.GetBytesFromUnicodeString(TestDataOfPidTagAttachRendering))),
                new PropertyObj(PropertyNames.PidTagAttachFlags, BitConverter.GetBytes(0x00000004)),
                new PropertyObj(PropertyNames.PidTagAttachTransportName, Common.GetBytesFromUnicodeString(TestDataOfPidTagAttachTransportName)),
                new PropertyObj(PropertyNames.PidTagAttachEncoding, Common.AddInt16LengthBeforeBinaryArray(this.testDataOfPidTagAttachEncoding)),
                new PropertyObj(PropertyNames.PidTagAttachmentLinkId, BitConverter.GetBytes(0x00000000)),
                new PropertyObj(PropertyNames.PidTagAttachmentFlags, BitConverter.GetBytes(0x00000000)),
                new PropertyObj(PropertyNames.PidTagAttachMethod, BitConverter.GetBytes(0x00000001)),
                new PropertyObj(PropertyNames.PidTagAttachmentHidden, BitConverter.GetBytes(true)),
                new PropertyObj(PropertyNames.PidTagAttachMimeTag, Common.GetBytesFromUnicodeString(TestDataOfPidTagAttachMimeTag)),
                new PropertyObj(PropertyNames.PidTagAttachContentId, Common.GetBytesFromUnicodeString(TestDataOfPidTagAttachContentId)),
                new PropertyObj(PropertyNames.PidTagAttachContentLocation, Common.GetBytesFromUnicodeString(TestDataOfPidTagAttachContentLocation)),
                new PropertyObj(PropertyNames.PidTagAttachContentBase, Common.GetBytesFromUnicodeString(TestDataOfPidTagAttachContentBase))
            };

            this.SetPropertiesForMessage(attachmentHandle, specificProperties);
            #endregion

            #region Send a RopGetPropertiesSpecific request to get all properties of specific message object.
            PropertyTag[] tagArray = this.CreateAttachmentPropertyTagsForCapture();
            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest()
            {
                RopId = (byte)RopId.RopGetPropertiesSpecific,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                PropertySizeLimit = 0xFFFF,
                PropertyTagCount = (ushort)tagArray.Length,
                PropertyTags = tagArray
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, attachmentHandle, ref this.response, ref this.rawData, GetPropertiesFlags.AttachmentProperties);
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

            List<PropertyObj> ps = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);
            PropertyObj pidTagAttachDataBinary = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagAttachDataBinary);
            PropertyObj pidTagAttachMethod = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagAttachMethod);

            byte[] testDataOfPidTagAttachDataBinary = Common.GetBytesFromUnicodeString(TestDataOfPidTagAttachDataBinary);
            byte[] valueOfPidTagAttachDataBinary = new byte[testDataOfPidTagAttachDataBinary.Length];
            Buffer.BlockCopy((byte[])pidTagAttachDataBinary.Value, 2, valueOfPidTagAttachDataBinary, 0, testDataOfPidTagAttachDataBinary.Length);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R236
            bool isVerfiedR236 = Common.CompareByteArray(testDataOfPidTagAttachDataBinary, valueOfPidTagAttachDataBinary);
            this.Site.CaptureRequirementIfIsTrue(
                isVerfiedR236,
                236,
                @"[In PidTagAttachDataBinary Property] The PidTagAttachDataBinary property ([MS-OXPROPS] section 2.580) contains the contents of the file to be attached.");

            if (Convert.ToInt32(pidTagAttachMethod.Value) == 0x00000001)
            {
                // Add the debug information
                this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R590");

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R590
                this.Site.CaptureRequirementIfIsNotNull(
                    pidTagAttachDataBinary.Value,
                    590,
                    @"[In PidTagAttachMethod Property] [afByValue (0x00000001)] The PidTagAttachDataBinary property (section 2.2.2.7) contains the attachment data.");
            }

            if(Common.IsRequirementEnabled(3008,this.Site))
            {
                PropertyObj pidTagObjectType = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagObjectType);

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R3008
                this.Site.CaptureRequirementIfIsNotNull(
                    pidTagObjectType.Value,
                    3008,
                    @"[In Appendix A: Product Behavior] Implementation does support the PidTagObjectType property. (Exchange 2007 follows this behavior.)");
            }
            #endregion

            #region Call RopRelease to release the created message and the created attachment
            this.ReleaseRop(attachmentHandle);
            this.ReleaseRop(targetMessageHandle);
            #endregion
        }
        /// <summary>
        /// This method is used to send the ROP of RopGetPropertiesSpecificRequest to get the specific property.
        /// </summary>
        /// <param name="propTag">The specified property</param>
        /// <returns>0 indicates success, others indicates error occurs.</returns>
        protected uint TryGetLogonProperty(PropertyTag propTag)
        {
            uint retValue = 0;
            PropertyTag[] tags = new PropertyTag[1];
            tags[0] = propTag;

            #region Construct the request buffer
            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest
            {
                RopId = 0x07,
                LogonId = 0x0,
                InputHandleIndex = 0x0,
                PropertySizeLimit = 0xFFFF, // Specifies the maximum size allowed for a property value returned
                PropertyTagCount = (ushort)tags.Length,
                PropertyTags = tags
            };
            #endregion

            this.oxcstorAdapter.DoRopCall(getPropertiesSpecificRequest, this.outObjHandle, ROPCommandType.RopGetPropertiesSpecific, out this.outputBuffer);
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.outputBuffer.RopsList[0];

            #region Check the response
            if (getPropertiesSpecificResponse.ReturnValue == 0)
            {
                // The return value is 0 to indicate that the method invoking successfully.
                if (getPropertiesSpecificResponse.RowData.PropertyValues == null ||
                    getPropertiesSpecificResponse.RowData.PropertyValues.Count <= 0)
                {
                    // The case that the operation of set property executes failed for other reasons.
                    Site.Assert.Fail("The property value is not returned when calling RopGetPropertiesSpecific ROP.");
                }
            }
            else
            {
                retValue = getPropertiesSpecificResponse.ReturnValue;
            }
            #endregion

            return retValue;
        }
        public void MSOXCMSG_S08_TC05_RopDeleteAttachmentSuccessfully()
        {
            this.CheckMapiHttpIsSupported();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);

            #region Call RopLogon to log on a mailbox.
            RopLogonResponse logonResponse = this.Logon(LogonType.Mailbox, out this.insideObjHandle);
            #endregion

            #region Call RopCreateMessage to create a message
            uint targetMessageHandle = this.CreatedMessage(logonResponse.FolderIds[4], this.insideObjHandle);
            #endregion

            #region Call RopSaveChangesMessage to save the message
            RopSaveChangesMessageResponse saveChangesMessageResponse;
            saveChangesMessageResponse = this.SaveMessage(targetMessageHandle, (byte)SaveFlags.ForceSave);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, saveChangesMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopOpenMessage to open the message.
            RopOpenMessageResponse openMessageResponse;
            uint openedMessageHandle = this.OpenSpecificMessage(logonResponse.FolderIds[4], saveChangesMessageResponse.MessageId, this.insideObjHandle, MessageOpenModeFlags.ReadWrite, out openMessageResponse);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, openMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopGetPropertiesSpecific to get the PidTagHasAttachments and pidTagMessageFlags properties of the opened message.
            PropertyTag[] tagArray = this.MessageProperties();
            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest()
            {
                RopId = (byte)RopId.RopGetPropertiesSpecific,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                PropertySizeLimit = 0xFFFF,
                PropertyTagCount = (ushort)tagArray.Length,
                PropertyTags = tagArray
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, openedMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

            List<PropertyObj> ptsFirst = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);

            // Parse property response to get Property Value to verify test case requirement
            PropertyObj pidTagHasAttachmentsFirst = PropertyHelper.GetPropertyByName(ptsFirst, PropertyNames.PidTagHasAttachments);
            PropertyObj pidTagMessageFlagsFirst = PropertyHelper.GetPropertyByName(ptsFirst, PropertyNames.PidTagMessageFlags);
            bool isHasAttachmentFirst = (Convert.ToInt32(pidTagMessageFlagsFirst.Value) & 0x00000010) == 0x00000010;
            Site.Assert.IsFalse(isHasAttachmentFirst, "The message should not contains any attachment.");
            #endregion

            #region Call RopCreateAttachment to create an attachment.
            RopCreateAttachmentResponse createAttachmentResponse;
            uint attachmentId;
            uint attachmentHandle = this.CreateAttachment(openedMessageHandle, out createAttachmentResponse, out attachmentId);
            #endregion

            #region Call RopSaveChangesAttachment to save the newly created attachment.
            RopSaveChangesAttachmentResponse saveChangesAttachmentResponse;
            this.SaveAttachment(attachmentHandle, out saveChangesAttachmentResponse);
            #endregion

            #region Call RopSaveChangesMessage to save the message
            saveChangesMessageResponse = this.SaveMessage(openedMessageHandle, (byte)SaveFlags.ForceSave);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, saveChangesMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopOpenMessage to open the message.
            openedMessageHandle = this.OpenSpecificMessage(logonResponse.FolderIds[4], saveChangesMessageResponse.MessageId, this.insideObjHandle, MessageOpenModeFlags.ReadWrite, out openMessageResponse);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, openMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopOpenAttachment to open the attachment as read/write.
            RopOpenAttachmentResponse openAttachmentResponse;
            this.OpenAttachment(openedMessageHandle, out openAttachmentResponse, attachmentId, OpenAttachmentFlags.ReadWrite);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, openAttachmentResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopGetPropertiesSpecific to get the PidTagHasAttachments and pidTagMessageFlags properties of the message.
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, openedMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

            List<PropertyObj> ptsSecond = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);

            // Parse property response to get Property Value to verify test case requirement
            PropertyObj pidTagHasAttachmentsSecond = PropertyHelper.GetPropertyByName(ptsSecond, PropertyNames.PidTagHasAttachments);
            PropertyObj pidTagMessageFlagsSecond = PropertyHelper.GetPropertyByName(ptsSecond, PropertyNames.PidTagMessageFlags);
            bool isHasAttachmentSecond = (Convert.ToInt32(pidTagMessageFlagsSecond.Value) & 0x00000010) == 0x00000010;

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R16
            this.Site.CaptureRequirementIfAreEqual<bool>(
                isHasAttachmentSecond,
                Convert.ToBoolean(pidTagHasAttachmentsSecond.Value),
                16,
                @"[In PidTagHasAttachments Property] The server computes this property [PidTagHasAttachments] from the mfHasAttach flag of the PidTagMessageFlags property ([MS-OXPROPS] section 2.780).");

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R498. The value of PidTagHasAttachments before creating the attachment is {0}, the value of PidTagHasAttachments after creating the attachment is {1}.", pidTagHasAttachmentsFirst.Value, pidTagHasAttachmentsSecond.Value);

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R498
            // MS-OXCMSG_R498 can be verified if the value of PidTagHasAttachments before creating the attachment is false and the value of PidTagHasAttachments after creating the attachment is true.
            bool isVerifiedR498 = !Convert.ToBoolean(pidTagHasAttachmentsFirst.Value) && Convert.ToBoolean(pidTagHasAttachmentsSecond.Value);

            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR498,
                498,
                @"[In PidTagHasAttachments Property] The PidTagHasAttachments property ([MS-OXPROPS] section 2.706) indicates whether the Message object contains at least one attachment.");

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R875. The value of PidTagHasAttachments before creating the attachment is {0}, the value of PidTagHasAttachments after creating the attachment is {1}.", pidTagHasAttachmentsFirst.Value, pidTagHasAttachmentsSecond.Value);

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R875
            // The value of PidTagHasAttachments before creating the attachment is false and the value of PidTagHasAttachments after creating the attachment is true indicate that RopSaveChangesAttachment commits the changes made to the attachment object.
            bool isVerifiedR875 = !Convert.ToBoolean(pidTagHasAttachmentsFirst.Value) && Convert.ToBoolean(pidTagHasAttachmentsSecond.Value);

            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR875,
                875,
                @"[In RopSaveChangesAttachment ROP] The RopSaveChangesAttachment ROP ([MS-OXCROPS] section 2.2.6.15) commits the changes made to the Attachment object.");

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R522. The value of isHasAttachmentSecond is {0}.", isHasAttachmentSecond);

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R522
            // One attachment is created in the previous step, so MS-OXCMSG_R522 can be verified if the value of isHasAttachmentSecond is true.
            this.Site.CaptureRequirementIfIsTrue(
                isHasAttachmentSecond,
                522,
                @"[In PidTagMessageFlags Property] [mfHasAttach (0x00000010)] The message has at least one attachment.");
            #endregion

            #region Call RopDeleteAttachment to delete the attachment and expect a successful response.
            RopDeleteAttachmentRequest deleteAttachmentRequest = new RopDeleteAttachmentRequest()
            {
                RopId = (byte)RopId.RopDeleteAttachment,
                LogonId = CommonLogonId, // The logonId 0x00 is associated with this operation.
                InputHandleIndex = CommonInputHandleIndex, // This index specifies the location 0x01 in the Server Object Handle Table where the handle for the input Server Object is stored.
                AttachmentID = attachmentId
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(deleteAttachmentRequest, openedMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopDeleteAttachmentResponse deleteAttachmentResponse = (RopDeleteAttachmentResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, deleteAttachmentResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopOpenAttachment to open the deleted attachment and expect a failure response.
            this.OpenAttachment(openedMessageHandle, out openAttachmentResponse, attachmentId, OpenAttachmentFlags.ReadWrite);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R868
            // The deleted attachment can't be opened indicates that RopDeleteAttachment deletes an existing Attachment object from the Message object.
            this.Site.CaptureRequirementIfAreNotEqual<uint>(
                TestSuiteBase.Success,
                openAttachmentResponse.ReturnValue,
                868,
                @"[In RopDeleteAttachment ROP] The RopDeleteAttachment ROP ([MS-OXCROPS] section 2.2.6.14) deletes an existing Attachment object from the Message object.");
            #endregion

            #region Call RopSaveChangesMessage to save the message
            saveChangesMessageResponse = this.SaveMessage(openedMessageHandle, (byte)SaveFlags.ForceSave);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, saveChangesMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopOpenMessage to open the message.
            openedMessageHandle = this.OpenSpecificMessage(logonResponse.FolderIds[4], saveChangesMessageResponse.MessageId, this.insideObjHandle, MessageOpenModeFlags.ReadWrite, out openMessageResponse);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, openMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopGetPropertiesSpecific to get the PidTagHasAttachments property of the opened message and expect a successful response with its value is false
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, openedMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

            List<PropertyObj> ptsThird = PropertyHelper.GetPropertyObjFromBuffer(tagArray, getPropertiesSpecificResponse);

            // Parse property response to get Property Value to verify test case requirement
            PropertyObj pidTagHasAttachmentsThird = PropertyHelper.GetPropertyByName(ptsThird, PropertyNames.PidTagHasAttachments);
            PropertyObj pidTagMessageFlagsThird = PropertyHelper.GetPropertyByName(ptsThird, PropertyNames.PidTagMessageFlags);
            bool isHasAttachmentThird = (Convert.ToInt32(pidTagMessageFlagsThird.Value) & 0x00000010) == 0x00000010;
            Site.Assert.IsFalse(isHasAttachmentThird, "The message should not contains any attachment.");

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R469. The value of PidTagHasAttachments before calling RopDeleteAttachment is {0}, the value of PidTagHasAttachments after calling RopDeleteAttachment is {1}", pidTagHasAttachmentsSecond.Value, pidTagHasAttachmentsThird.Value);

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R469
            // The value of PidTagHasAttachments before calling RopDeleteAttachment is true and after calling RopDeleteAttachment is false indicate that server recalculates the PidTagHasAttachments property while processing the RopDeleteAttachment ROP.
            bool isVerifiedR469 = !Convert.ToBoolean(pidTagHasAttachmentsThird.Value) && Convert.ToBoolean(pidTagHasAttachmentsSecond.Value);

            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR469,
                469,
                @"[In Receiving a RopDeleteAttachment ROP Request] The server recalculates the PidTagHasAttachments property (section 2.2.1.2) while processing the RopDeleteAttachment ROP ([MS-OXCROPS] section 2.2.6.14).");
            #endregion

            #region Call RopRelease to release the created message and attachment.
            this.ReleaseRop(attachmentHandle);
            this.ReleaseRop(targetMessageHandle);
            #endregion
        }
        /// <summary>
        /// Get the named properties value of specified Message object.
        /// </summary>
        /// <param name="longIdProperties">The list of named properties</param>
        /// <param name="messageHandle">The object handle of specified Message object.</param>
        /// <returns>Returns named property values of specified Message object.</returns>
        public Dictionary<PropertyNames, byte[]> GetNamedPropertyValues(List<PropertyNameObject> longIdProperties, uint messageHandle)
        {
            object response = null;
            byte[] rawData = null;

            #region Call RopGetPropertyIdsFromNames to get property ID.
            PropertyName[] propertyNames = new PropertyName[longIdProperties.Count];

            for (int i = 0; i < longIdProperties.Count; i++)
            {
                propertyNames[i] = longIdProperties[i].PropertyName;
            }

            RopGetPropertyIdsFromNamesRequest getPropertyIdsFromNamesRequest;
            RopGetPropertyIdsFromNamesResponse getPropertyIdsFromNamesResponse;
            getPropertyIdsFromNamesRequest.RopId = (byte)RopId.RopGetPropertyIdsFromNames;
            getPropertyIdsFromNamesRequest.LogonId = 0x00;
            getPropertyIdsFromNamesRequest.InputHandleIndex = 0x00;
            getPropertyIdsFromNamesRequest.Flags = (byte)GetPropertyIdsFromNamesFlags.Create;
            getPropertyIdsFromNamesRequest.PropertyNameCount = (ushort)propertyNames.Length;
            getPropertyIdsFromNamesRequest.PropertyNames = propertyNames;

            this.DoRopCall(getPropertyIdsFromNamesRequest, messageHandle, ref response, ref rawData, GetPropertiesFlags.None);
            getPropertyIdsFromNamesResponse = (RopGetPropertyIdsFromNamesResponse)response;
            Site.Assert.AreEqual<uint>(0, getPropertyIdsFromNamesResponse.ReturnValue, "Call RopGetPropertyIdsFromNames should success.");
            #endregion

            #region Call RopGetPropertiesSpecific to get the specific properties of specific message object.
            // Get specific property for created message
            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest();
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse;
            getPropertiesSpecificRequest.RopId = (byte)RopId.RopGetPropertiesSpecific;
            getPropertiesSpecificRequest.LogonId = 0x00;
            getPropertiesSpecificRequest.InputHandleIndex = 0x00;
            getPropertiesSpecificRequest.PropertySizeLimit = 0xFFFF;

            PropertyTag[] tagArray = new PropertyTag[longIdProperties.Count];
            for (int j = 0; j < getPropertyIdsFromNamesResponse.PropertyIds.Length; j++)
            {
                tagArray[j] = new PropertyTag
                {
                    PropertyId = getPropertyIdsFromNamesResponse.PropertyIds[j].ID,
                    PropertyType = (ushort)longIdProperties[j].PropertyType
                };
            }

            getPropertiesSpecificRequest.PropertyTagCount = (ushort)tagArray.Length;
            getPropertiesSpecificRequest.PropertyTags = tagArray;

            this.DoRopCall(getPropertiesSpecificRequest, messageHandle, ref response, ref rawData, GetPropertiesFlags.None);
            getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)response;
            Site.Assert.AreEqual<uint>(0, getPropertiesSpecificResponse.ReturnValue, "Calling RopGetPropertiesSpecific should be successful.");

            Dictionary<PropertyNames, byte[]> propertyList = new Dictionary<PropertyNames, byte[]>();
            PropertyObj propertyObjPidLidCommonStart = null;
            PropertyObj propertyObjPidLidCommonEnd = null;

            for (int i = 0; i < getPropertiesSpecificResponse.RowData.PropertyValues.Count; i++)
            {
                PropertyObj propertyObj = new PropertyObj
                {
                    PropertyName = longIdProperties[i].DisplayName,
                    ValueType = longIdProperties[i].PropertyType
                };
                PropertyHelper.GetPropertyObjFromBuffer(propertyObj, getPropertiesSpecificResponse.RowData.PropertyValues[i].Value);

                // Verify requirements related with named properties PidNameKeywords, PidNameContentBase, PidNameAcceptLanguage and PidNameContentClass.
                this.VerifyMessageSyntaxDataType(propertyObj);

                if (propertyObj.PropertyName == PropertyNames.PidLidCommonStart)
                {
                    propertyObjPidLidCommonStart = propertyObj;
                }

                if (propertyObj.PropertyName == PropertyNames.PidLidCommonEnd)
                {
                    propertyObjPidLidCommonEnd = propertyObj;
                }

                propertyList.Add(longIdProperties[i].DisplayName, getPropertiesSpecificResponse.RowData.PropertyValues[i].Value);
            }

            // Verify the requirements of PidLidCommonStart and PidLidCommonEnd.
            if (PropertyHelper.IsPropertyValid(propertyObjPidLidCommonStart) || PropertyHelper.IsPropertyValid(propertyObjPidLidCommonEnd))
            {
                this.VerifyMessageSyntaxPidLidCommonStartAndPidLidCommonEnd(propertyObjPidLidCommonStart, propertyObjPidLidCommonEnd);
            }
            #endregion

            return propertyList;
        }
 /// <summary>
 /// Get value of specific properties in Message object.
 /// </summary>
 /// <param name="messageHandle">The message handle.</param>
 /// <param name="propertyList">The specific properties list.</param>
 /// <returns>The response of calling RopGetPropertiesSpecific.</returns>
 protected RopGetPropertiesSpecificResponse GetSpecificPropertiesOfMessage(uint messageHandle, List<PropertyTag> propertyList)
 {
     RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest()
     {
         RopId = (byte)RopId.RopGetPropertiesSpecific,
         LogonId = CommonLogonId, // The logonId 0x00 is associated with this operation.
         InputHandleIndex = CommonInputHandleIndex, // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the input Server Object is stored. 
         PropertySizeLimit = 0xFFFF, // This value specifies the maximum number of the property
         PropertyTagCount = (ushort)propertyList.Count,
         PropertyTags = propertyList.ToArray()
     };
     this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertiesSpecificRequest, messageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
     RopGetPropertiesSpecificResponse getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.response;
     Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertiesSpecificResponse.ReturnValue, "Call RopGetPropertiesSpecific should success.");
     return getPropertiesSpecificResponse;
 }