/// <summary>
        /// Create and save message.
        /// </summary>
        /// <param name="folderHandle">Folder Handle </param>
        /// <param name="folderId">Folder Id  which messages will be create in.</param>
        /// <param name="associatedFlag">Specifies whether the message is a Folder Associated Information message.</param>
        /// <param name="messageId"> Message Id which will be returned by server.</param>
        /// <param name="messageHandle">Message Handle which will be returned by server.</param>
        protected void CreateSaveMessage(uint folderHandle, ulong folderId, byte associatedFlag, ref ulong messageId, ref uint messageHandle)
        {
            // Create a Message.
            RopCreateMessageRequest createMessageRequest = new RopCreateMessageRequest();
            RopCreateMessageResponse createMessageResponse = new RopCreateMessageResponse();
            object ropResponse = null;
            createMessageRequest.RopId = (byte)RopId.RopCreateMessage;
            createMessageRequest.LogonId = Constants.CommonLogonId;
            createMessageRequest.InputHandleIndex = Constants.CommonInputHandleIndex;
            createMessageRequest.OutputHandleIndex = Constants.CommonOutputHandleIndex;
            createMessageRequest.CodePageId = 0x0FFF;
            createMessageRequest.FolderId = folderId;
            createMessageRequest.AssociatedFlag = associatedFlag;
            this.Adapter.DoRopCall(createMessageRequest, folderHandle, ref ropResponse, ref this.responseHandles);

            createMessageResponse = (RopCreateMessageResponse)ropResponse;
            Site.Assert.AreEqual<uint>(0, createMessageResponse.ReturnValue, "Creating Message should succeed");
            messageHandle = this.responseHandles[0][createMessageResponse.OutputHandleIndex];

            // Save a Message.
            RopSaveChangesMessageRequest saveChangesMessageRequest = new RopSaveChangesMessageRequest();
            RopSaveChangesMessageResponse saveChangesMessageResponse = new RopSaveChangesMessageResponse();
            saveChangesMessageRequest.RopId = (byte)RopId.RopSaveChangesMessage;
            saveChangesMessageRequest.LogonId = Constants.CommonLogonId;
            saveChangesMessageRequest.InputHandleIndex = Constants.CommonInputHandleIndex;
            saveChangesMessageRequest.ResponseHandleIndex = 0x01;
            saveChangesMessageRequest.SaveFlags = 0x0C;
            this.Adapter.DoRopCall(saveChangesMessageRequest, messageHandle, ref ropResponse, ref this.responseHandles);

            saveChangesMessageResponse = (RopSaveChangesMessageResponse)ropResponse;
            Site.Assert.AreEqual<uint>(
                0,
                createMessageResponse.ReturnValue,
                "Save Messages Success.");
            messageId = saveChangesMessageResponse.MessageId;
        }
        /// <summary>
        /// Prepare the ROP request for RopCreateMessage, RopSaveChangesMessage and RopRelease.
        /// </summary>
        /// <param name="logonResponse">The response of RopLogon.</param>
        /// <param name="createMessageRequest">The request of RopCreateMessage.</param>
        /// <param name="saveChangesMessageRequest">The request of RopSaveChangesMessage.</param>
        /// <param name="releaseRequest">The request of RopRelease.</param>
        protected void PrepareRops(RopLogonResponse logonResponse, ref RopCreateMessageRequest createMessageRequest, ref RopSaveChangesMessageRequest saveChangesMessageRequest, ref RopReleaseRequest releaseRequest)
        {
            #region prepare rops for createmessage, savemessage and release
            createMessageRequest.RopId = (byte)RopId.RopCreateMessage;
            createMessageRequest.LogonId = TestSuiteBase.LogonId;
            createMessageRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;
            createMessageRequest.OutputHandleIndex = TestSuiteBase.OutputHandleIndex1;

            // Set CodePageId to 0x0FFF, which specified the code page of Logon object will be used.
            createMessageRequest.CodePageId = TestSuiteBase.CodePageId;

            createMessageRequest.FolderId = logonResponse.FolderIds[4];
            createMessageRequest.AssociatedFlag = Convert.ToByte(TestSuiteBase.Zero);

            // Save message 
            saveChangesMessageRequest.RopId = (byte)RopId.RopSaveChangesMessage;
            saveChangesMessageRequest.LogonId = TestSuiteBase.LogonId;
            saveChangesMessageRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;
            saveChangesMessageRequest.ResponseHandleIndex = TestSuiteBase.ResponseHandleIndex1;
            saveChangesMessageRequest.SaveFlags = (byte)SaveFlags.ForceSave;

            releaseRequest.RopId = (byte)RopId.RopRelease;
            releaseRequest.LogonId = TestSuiteBase.LogonId;
            releaseRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;
            #endregion        
        }
        public void MSOXCSTOR_S03_TC01_ReadPerUserInformationForPublicLogon()
        {
            this.CheckTransportIsSupported();

            #region Step 1: Connect to the server.
            this.returnStatus = this.oxcstorAdapter.ConnectEx(ConnectionType.PublicFolderServer);
            Site.Assert.IsTrue(this.returnStatus, "Connection is successful");
            #endregion

            #region Step 2: Logon to public folder.
            this.oxcstorAdapter.DoRopCall(this.logonRequestForPublicFolder, this.insideObjHandle, ROPCommandType.RopLogonPublicFolder, out this.outputBuffer);
            this.logonResponse = (RopLogonResponse)this.outputBuffer.RopsList[0];
            this.outObjHandle = this.outputBuffer.ServerObjectHandleTable[0];

            Site.Assert.AreEqual<uint>(
                0,
                this.logonResponse.ReturnValue,
                "0 indicates the ROP succeeds, other value indicates error occurs.");
            #endregion

            #region step 3: Open a public folder
            RopOpenFolderRequest openFolderRequest;
            openFolderRequest.RopId = 0x02;
            openFolderRequest.LogonId = ConstValues.LoginId;
            openFolderRequest.InputHandleIndex = ConstValues.InputHandleIndex;
            openFolderRequest.OutputHandleIndex = ConstValues.OutputHandleIndex;
            openFolderRequest.FolderId = this.logonResponse.FolderIds[1];
            openFolderRequest.OpenModeFlags = 0x0;

            this.oxcstorAdapter.DoRopCall(openFolderRequest, this.outObjHandle, ROPCommandType.Others, out this.outputBuffer);

            RopOpenFolderResponse openFolderResponse = (RopOpenFolderResponse)this.outputBuffer.RopsList[0];
            Site.Assert.AreEqual<uint>(
                0x0,
                openFolderResponse.ReturnValue,
                "0 indicates the ROP succeeds, other value indicates error occurs.");
            uint openedFolderHandle = this.outputBuffer.ServerObjectHandleTable[openFolderRequest.OutputHandleIndex];
            #endregion

            #region step 4: Create a public folder
            string publicFolderName = Common.GenerateResourceName(Site, "PublicFolder") + "\0";
            RopCreateFolderRequest createFolderRequest;
            createFolderRequest.RopId = 0x1C;
            createFolderRequest.LogonId = ConstValues.LoginId;
            createFolderRequest.InputHandleIndex = ConstValues.InputHandleIndex;
            createFolderRequest.OutputHandleIndex = ConstValues.OutputHandleIndex;
            createFolderRequest.FolderType = 0x01;
            createFolderRequest.UseUnicodeStrings = 0x0;
            createFolderRequest.OpenExisting = 0xFF;
            createFolderRequest.Reserved = 0x0;
            createFolderRequest.DisplayName = System.Text.Encoding.ASCII.GetBytes(publicFolderName);
            createFolderRequest.Comment = System.Text.Encoding.ASCII.GetBytes(publicFolderName);
            this.oxcstorAdapter.DoRopCall(createFolderRequest, openedFolderHandle, ROPCommandType.Others, out this.outputBuffer);
            RopCreateFolderResponse createFolderResponse = (RopCreateFolderResponse)this.outputBuffer.RopsList[0];
            Site.Assert.AreEqual<uint>(
                0x0,
                createFolderResponse.ReturnValue,
                "0 indicates the ROP succeeds, other value indicates error occurs.");
            ulong folderId = createFolderResponse.FolderId;
            uint folderHandle = this.outputBuffer.ServerObjectHandleTable[createFolderRequest.OutputHandleIndex];

            #endregion

            #region Step 5: Get LongTermID of the folder created in step 4.
            LongTermId longTermId = this.GetLongTermIdFromId(folderId);
            #endregion

            #region Step 6: Call RopReadPerUserInformation ROP request to check if user information exists.
            this.readPerUserInformationRequest.FolderId = longTermId;
            this.oxcstorAdapter.DoRopCall(this.readPerUserInformationRequest, this.outObjHandle, ROPCommandType.RopReadPerUserInformation, out this.outputBuffer);
            this.readPerUserInformationResponse = (RopReadPerUserInformationResponse)this.outputBuffer.RopsList[0];
            Site.Assert.AreEqual<uint>(0, this.readPerUserInformationResponse.ReturnValue, "0 indicates the ROP succeeds, other value indicates error occurs.");

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1257.
            Site.CaptureRequirementIfIsNull(
                this.readPerUserInformationResponse.Data,
                1257,
                @"[In Public Folders Specific Behavior] If the row does not exist, then the server returns an empty array in the Data field of the response.");
            #endregion

            #region Step 7: Create a message in the public folder created in step 4.
            RopCreateMessageRequest createMessageRequest = new RopCreateMessageRequest();
            createMessageRequest.RopId = (byte)RopId.RopCreateMessage;
            createMessageRequest.LogonId = ConstValues.LoginId;
            createMessageRequest.InputHandleIndex = ConstValues.InputHandleIndex;
            createMessageRequest.OutputHandleIndex = ConstValues.OutputHandleIndex;
            createMessageRequest.CodePageId = 0x0FFF;
            createMessageRequest.FolderId = folderId;
            createMessageRequest.AssociatedFlag = 0x0;
            this.oxcstorAdapter.DoRopCall(createMessageRequest, folderHandle, ROPCommandType.Others, out this.outputBuffer);

            RopCreateMessageResponse createMessageResponse = (RopCreateMessageResponse)this.outputBuffer.RopsList[0];
            Site.Assert.AreEqual<uint>(0, createMessageResponse.ReturnValue, "Creating Message should succeed");
            uint messageHandle = this.outputBuffer.ServerObjectHandleTable[createMessageRequest.OutputHandleIndex];

            // Save a Message.
            RopSaveChangesMessageRequest saveChangesMessageRequest = new RopSaveChangesMessageRequest();
            saveChangesMessageRequest.RopId = (byte)RopId.RopSaveChangesMessage;
            saveChangesMessageRequest.LogonId = ConstValues.LoginId;
            saveChangesMessageRequest.InputHandleIndex = ConstValues.InputHandleIndex;
            saveChangesMessageRequest.ResponseHandleIndex = ConstValues.OutputHandleIndex;
            saveChangesMessageRequest.SaveFlags = 0x0C;
            this.oxcstorAdapter.DoRopCall(saveChangesMessageRequest, messageHandle, ROPCommandType.Others, out this.outputBuffer);
            RopSaveChangesMessageResponse saveChangesMessageResponse = (RopSaveChangesMessageResponse)this.outputBuffer.RopsList[0];
            Site.Assert.AreEqual<uint>(
                0,
                saveChangesMessageResponse.ReturnValue,
                "Save Messages Success.");
            ulong messageId = saveChangesMessageResponse.MessageId;
            #endregion

            #region Step 8: Call RopReadPerUserInformation ROP request to get data.
            this.oxcstorAdapter.DoRopCall(this.readPerUserInformationRequest, this.outObjHandle, ROPCommandType.RopReadPerUserInformation, out this.outputBuffer);
            this.readPerUserInformationResponse = (RopReadPerUserInformationResponse)this.outputBuffer.RopsList[0];
            Site.Assert.AreEqual<uint>(0, this.readPerUserInformationResponse.ReturnValue, "0 indicates the ROP succeeds, other value indicates error occurs.");
            Site.Assert.IsNotNull(this.readPerUserInformationResponse.Data, "Data should be exist if user reads mail in public folder.");
            byte[] data = this.readPerUserInformationResponse.Data;

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R965.
            Site.CaptureRequirementIfAreEqual<uint>(
                0,
                this.readPerUserInformationResponse.ReturnValue,
                965,
                @"[In Receiving a RopReadPerUserInformation ROP Request] This operation [RopReadPerUserInformation] can be issued against either a private mailbox logon or a public folders logon.");
            #endregion

            #region Step 9: Call RopReadPerUserInformation MaxDataSize set to zero.
            this.readPerUserInformationRequest.MaxDataSize = 0;
            this.oxcstorAdapter.DoRopCall(this.readPerUserInformationRequest, this.outObjHandle, ROPCommandType.RopReadPerUserInformation, out this.outputBuffer);
            this.readPerUserInformationResponse = (RopReadPerUserInformationResponse)this.outputBuffer.RopsList[0];
            Site.Assert.AreEqual<uint>(0, this.readPerUserInformationResponse.ReturnValue, "0 indicates the ROP succeeds, other value indicates error occurs.");

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1005
            // MaxDataSize be set to 0 server will use the default value 4096
            int adjMaxDataSize = 4096;
            int blobMinDataOffset = data.Length - (int)this.readPerUserInformationRequest.DataOffset;
            bool isVerify_R1005 = (blobMinDataOffset > adjMaxDataSize)
                ? (this.readPerUserInformationResponse.DataSize == adjMaxDataSize)
                : (this.readPerUserInformationResponse.DataSize == blobMinDataOffset);
            Site.CaptureRequirementIfIsTrue(
                isVerify_R1005,
                1005,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The server MUST set DataSize to the lesser of the following two values [the adjusted value of MaxDataSize, the entire BLOB minus the value of DataOffset.].");

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1000.
            // The DataSize field in the RopReadPerUserInformation is the lesser of the following two values [the adjusted value of MaxDataSize, the entire BLOB minus the value of DataOffset.], it indicates the server compares the adjusted value of MaxDataSize to the size of the remaining BLOB segment.
            // MS-OXCSTOR_R1000 can be verified directly.
            Site.CaptureRequirement(
                1000,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] 	The server compares the adjusted value of MaxDataSize to the size of the remaining BLOB segment.");

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R517.
            Site.CaptureRequirementIfIsNotNull(
                this.readPerUserInformationResponse.Data,
                517,
                @"[In RopReadPerUserInformation ROP] When this ROP is issued against a public folders logon, the current per-user read/unread data for the public folder is retrieved.");

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R971.
            // MS-OXCSTOR_R517 has verified the server returned current per-user read/unread data for the public folder successfully, MS-OXCSTOR_R971 can be verified directly.
            Site.CaptureRequirement(
                971,
                @"[In Public Folders Specific Behavior] The server searches the per-user data table for the only row with an FID equal to the value of the FolderId field and the user ID equal to the logged on user.");

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R975
            // Verify the data is a BLOB which is formatted as a serialized IDSET with REPLGUID
            bool isVerify_R975 = this.VerifyDataIsIDSETStructure(this.readPerUserInformationResponse.Data);

            Site.CaptureRequirementIfIsTrue(
                isVerify_R975,
                975,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] [The change number set is serialized into a binary large object (BLOB) that is formatted as a serialized IDSET with REPLGUID structure, as specified in [MS-OXCFXICS] section 2.2.2.4.2.] The server then returns the BLOB in the Data field of the response.");

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R974.
            // MS-OXCSTOR_R975 has verified the change number set structure, MS-OXCSTOR_R545 can be verified directly.
            Site.CaptureRequirement(
                974,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The change number set MUST be serialized into a binary large object (BLOB) that is formatted as a serialized IDSET with REPLGUID structure, as specified in [MS-OXCFXICS] section 2.2.2.4.2.");

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1003
            Site.CaptureRequirementIfAreEqual<ushort>(
                (ushort)this.readPerUserInformationResponse.DataSize,
                (ushort)this.readPerUserInformationResponse.Data.Length,
                1003,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The DataSize field specifies the actual number of bytes that are returned in the response.");
            #endregion

            #region Step 10: RopReadPerUserInformation with DataOffset less than zero.
            this.readPerUserInformationRequest.DataOffset = 0xffffffff;
            this.oxcstorAdapter.DoRopCall(this.readPerUserInformationRequest, this.outObjHandle, ROPCommandType.RopReadPerUserInformation, out this.outputBuffer);
            this.readPerUserInformationResponse = (RopReadPerUserInformationResponse)this.outputBuffer.RopsList[0];

            #region Capture

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

                // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1042.
                Site.CaptureRequirementIfAreEqual<uint>(
                    0x80004005,
                    this.readPerUserInformationResponse.ReturnValue,
                    1042,
                    @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The implementation does fail the operation with 0x80004005 (ecError) in the ReturnValue field, if the value of the DataOffset field is less than zero. (Exchange 2013 and above follow this behavior.)");
            }

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

                // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R554.
                Site.CaptureRequirementIfAreEqual<uint>(
                    0x000004B6,
                    this.readPerUserInformationResponse.ReturnValue,
                    554,
                    @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The error code ecRpcFormat: Its value is 0x000004B6.");

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

                // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R555.
                // MS-OXCSTOR_R554 was captured by calling RopReadPerUserInformation with DataOffset value less than zero, MS-OXCSTOR_R555 can be verified directly.
                Site.CaptureRequirement(
                    555,
                    @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The error code ecRpcFormat: The DataOffset value was less than zero.");

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

                // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1007.
                Site.CaptureRequirementIfAreEqual<uint>(
                    0x000004B6,
                    this.readPerUserInformationResponse.ReturnValue,
                    1007,
                    @"[In Appendix A: Product Behavior] The implementation does fail the operation with 0x000004B6 (ecRpcFormat) in the ReturnValue field, if the value of the DataOffset field is less than zero. (<46> Section 3.2.5.12.1: Exchange 2003, Exchange 2007, and Exchange 2010 fail the operation with 0x000004B6 (ecRpcFormat).)");
            }
            #endregion
            #endregion

            #region Step 11: The first call of RopReadPerUserInformation with MaxDataSize field set to 1.

            // In the response hasFinished should be false, only the first byte should be returned.
            this.readPerUserInformationRequest.DataOffset = 0;
            this.readPerUserInformationRequest.MaxDataSize = 1;
            this.oxcstorAdapter.DoRopCall(this.readPerUserInformationRequest, this.outObjHandle, ROPCommandType.RopReadPerUserInformation, out this.outputBuffer);
            RopReadPerUserInformationResponse perUserInformationPart1 = (RopReadPerUserInformationResponse)this.outputBuffer.RopsList[0];

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R552.
            Site.CaptureRequirementIfAreEqual<uint>(
                0,
                perUserInformationPart1.ReturnValue,
                552,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The error code ecNone: Its value is 0x00000000.");

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R553.
            // The RopReadPerUserInformation ROP performs successfully and the ecNone error code was captured by MS-OXCSTOR_R552, MS-OXCSTOR_R553 can be verified directly.
            Site.CaptureRequirement(
                553,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The error code ecNone: Success.");

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1284.
            Site.CaptureRequirementIfAreEqual<byte>(
                0,
                perUserInformationPart1.HasFinished,
                1284,
                @"[In RopReadPerUserInformation ROP Success Response Buffer] HasFinished: The value of this field is FALSE if the last block of data is not being returned.");

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-OXCSTOR_R543,
                the value of the MaxDataSize field of the RopReadPerUserInformation ROP request is {0},
                the value of the DataSize field of the RopReadPerUserInformation ROP response is {1}.",
                this.readPerUserInformationRequest.MaxDataSize,
                perUserInformationPart1.DataSize);

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R543.
            bool isVerifiedR543 = perUserInformationPart1.DataSize <= this.readPerUserInformationRequest.MaxDataSize;

            Site.CaptureRequirementIfIsTrue(
                isVerifiedR543,
                543,
                @"[In RopReadPerUserInformation ROP Success Response Buffer] DataSize: The value of this field MUST be less than or equal to the value of the MaxDataSize field of the request.");
            #endregion

            #region Step 12: The second call of RopReadPerUserInformation with DataOffset field set to "1" and MaxDataSize field set to 0.

            // The remained bytes should be returned, and HasFinished should be true.
            this.readPerUserInformationRequest.DataOffset = 1;
            this.readPerUserInformationRequest.MaxDataSize = 0;
            this.oxcstorAdapter.DoRopCall(this.readPerUserInformationRequest, this.outObjHandle, ROPCommandType.RopReadPerUserInformation, out this.outputBuffer);
            RopReadPerUserInformationResponse perUserInformationPart2 = (RopReadPerUserInformationResponse)this.outputBuffer.RopsList[0];

            Site.Assert.AreEqual<uint>(
                0,
                perUserInformationPart2.ReturnValue,
                "0 indicates the ROP succeeds, other value indicates error occurs.");

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1002
            // At step8, read again for the remaining Blob segment
            // verify if the size of returned data is equal to dataSizeWritten(entire blob size) minus the value of DataOffset
            bool isVerify_R1002 = perUserInformationPart2.Data.Length == data.Length - this.readPerUserInformationRequest.DataOffset;
            Site.CaptureRequirementIfIsTrue(
                isVerify_R1002,
                1002,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The size of the remaining BLOB segment is equal to the size of the entire BLOB minus the value of DataOffset.");

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1009.
            // At step8, read again for the remaining Blob segment, 
            // verify if the size of returned data is equal to dataSizeWritten(entire blob size) minus the value of DataOffset.
            bool isVerify_R1009 = perUserInformationPart2.Data.Length == data.Length - this.readPerUserInformationRequest.DataOffset;
            Site.CaptureRequirementIfIsTrue(
                isVerify_R1009,
                1009,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] This [The size of the remaining BLOB segment] is equal to the size of the entire BLOB minus the value of DataOffset.");

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1010
            // Verify "HasFinshed" field is true "0x01" when the dataSize plus data offset equals the size of entire BloB
            Site.CaptureRequirementIfAreEqual<byte>(
                0x01,
                perUserInformationPart2.HasFinished,
                1010,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The server MUST set HasFinished to TRUE if DataOffset plus DataSize equals the size of the entire BLOB.");

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1011
            // "In other words" means a different statement, but for same verification logic with R1010
            Site.CaptureRequirementIfAreNotEqual<byte>(
                0x00,
                perUserInformationPart2.HasFinished,
                1011,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] In other words, when the server sends the last segment of the BLOB, HasFinished MUST be set to TRUE.");

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1008
            // Step8 is to read the remaining data after the first read at step7.
            // If the data size read at step8 is the remaining BLOB segment size, then could verify R1008
            bool isVerifiedR1008 = perUserInformationPart2.DataSize == perUserInformationPart1.DataSize + perUserInformationPart2.DataSize - this.readPerUserInformationRequest.DataOffset;

            Site.CaptureRequirementIfIsTrue(
                isVerifiedR1008,
                1008,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] This [The size of the remaining BLOB segment] is the size of the portion of the BLOB that remains to be sent to the client.");

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R540.
            Site.CaptureRequirementIfAreNotEqual<byte>(
                0,
                perUserInformationPart2.HasFinished,
                540,
                @"[In RopReadPerUserInformation ROP Success Response Buffer] HasFinished: The value of this field is TRUE if the last block of data is being returned.");

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R539.
            // MS-OXCSTOR_R540 and MS-OXCSTOR_R1284 was verified, MS-OXCSTOR_R539 can be verified directly.
            Site.CaptureRequirement(
                539,
                @"[In RopReadPerUserInformation ROP Success Response Buffer] HasFinished: Indicates whether the last block of data is being returned.");
            #endregion

            #region Step 13: RopReadPerUserInformation, read once with the DataOffset field is greater than the size of the next BLOB segment to be returned.

            this.readPerUserInformationRequest.DataOffset = 0;
            this.readPerUserInformationRequest.MaxDataSize = (ushort)(data.Length - 1);
            this.oxcstorAdapter.DoRopCall(this.readPerUserInformationRequest, this.outObjHandle, ROPCommandType.RopReadPerUserInformation, out this.outputBuffer);
            this.readPerUserInformationResponse = (RopReadPerUserInformationResponse)this.outputBuffer.RopsList[0];

            // Read once with MaxDataSize = entireBlobSize -1, the returned value of hasFinished in the response will be false,
            // all the data except the last byte will be returned, remaining data in the server will be 1
            this.readPerUserInformationRequest.DataOffset = (ushort)(data.Length + 1);
            this.readPerUserInformationRequest.MaxDataSize = (ushort)(data.Length - 1);
            this.oxcstorAdapter.DoRopCall(this.readPerUserInformationRequest, this.outObjHandle, ROPCommandType.RopReadPerUserInformation, out this.outputBuffer);
            this.readPerUserInformationResponse = (RopReadPerUserInformationResponse)this.outputBuffer.RopsList[0];

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1260
            Site.CaptureRequirementIfAreEqual<uint>(
                0x80004005,
                this.readPerUserInformationResponse.ReturnValue,
                1260,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] If the value of the DataOffset field is greater than the size of the next BLOB segment to be returned, the server MUST fail the operation with 0x80004005 (ecError) in the ReturnValue field.");

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R556
            Site.CaptureRequirementIfAreEqual<uint>(
                0x80004005,
                this.readPerUserInformationResponse.ReturnValue,
                556,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The error code ecError: Its value is 0x80004005.");

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R557.
            // MS-OXCSTOR_R556 has captured error code 0x80004005, MS-OXCSTOR_R557 can be verified directly.
            Site.CaptureRequirement(
                557,
                @"[In Behavior Common to Both Private Mailbox and Public Folder Logon] The error code ecError: The DataOffset value was greater than the data size.");
            #endregion

            #region Step 14: Disconnect and re-connect.
            this.oxcstorAdapter.DisconnectEx();
            this.oxcstorAdapter.ConnectEx(ConnectionType.PublicFolderServer);

            this.oxcstorAdapter.DoRopCall(this.logonRequestForPublicFolder, this.insideObjHandle, ROPCommandType.RopLogonPublicFolder, out this.outputBuffer);
            this.logonResponse = (RopLogonResponse)this.outputBuffer.RopsList[0];
            this.outObjHandle = this.outputBuffer.ServerObjectHandleTable[0];

            Site.Assert.AreEqual<uint>(
                0,
                this.logonResponse.ReturnValue,
                "0 indicates the ROP succeeds, other value indicates error occurs.");
            #endregion

            #region Step 15: Open the folder and get folder handle.
            // Root public folder
            openFolderRequest.FolderId = this.logonResponse.FolderIds[1];
            openFolderRequest.OpenModeFlags = 0x0;
            this.oxcstorAdapter.DoRopCall(openFolderRequest, this.outObjHandle, ROPCommandType.Others, out this.outputBuffer);
            openFolderResponse = (RopOpenFolderResponse)this.outputBuffer.RopsList[0];
            Site.Assert.AreEqual<uint>(
                0x0,
                openFolderResponse.ReturnValue,
                "0 indicates the ROP succeeds, other value indicates error occurs.");
            openedFolderHandle = this.outputBuffer.ServerObjectHandleTable[openFolderRequest.OutputHandleIndex];

            // Created public folder
            openFolderRequest.FolderId = folderId;
            openFolderRequest.OpenModeFlags = 0x0;
            this.oxcstorAdapter.DoRopCall(openFolderRequest, this.outObjHandle, ROPCommandType.Others, out this.outputBuffer);
            openFolderResponse = (RopOpenFolderResponse)this.outputBuffer.RopsList[0];
            Site.Assert.AreEqual<uint>(
                0x0,
                openFolderResponse.ReturnValue,
                "0 indicates the ROP succeeds, other value indicates error occurs.");
            folderHandle = this.outputBuffer.ServerObjectHandleTable[openFolderRequest.OutputHandleIndex];
            #endregion

            #region Step 16: Create a message in the folder again.
            this.oxcstorAdapter.DoRopCall(createMessageRequest, folderHandle, ROPCommandType.Others, out this.outputBuffer);

            createMessageResponse = (RopCreateMessageResponse)this.outputBuffer.RopsList[0];
            Site.Assert.AreEqual<uint>(0, createMessageResponse.ReturnValue, "Creating Message should succeed");
            uint messageHandle2 = this.outputBuffer.ServerObjectHandleTable[createMessageRequest.OutputHandleIndex];

            // Save a Message.
            saveChangesMessageRequest = new RopSaveChangesMessageRequest();
            saveChangesMessageRequest.RopId = (byte)RopId.RopSaveChangesMessage;
            saveChangesMessageRequest.LogonId = ConstValues.LoginId;
            saveChangesMessageRequest.InputHandleIndex = ConstValues.InputHandleIndex;
            saveChangesMessageRequest.ResponseHandleIndex = ConstValues.OutputHandleIndex;
            saveChangesMessageRequest.SaveFlags = 0x0C;
            this.oxcstorAdapter.DoRopCall(saveChangesMessageRequest, messageHandle2, ROPCommandType.Others, out this.outputBuffer);
            saveChangesMessageResponse = (RopSaveChangesMessageResponse)this.outputBuffer.RopsList[0];
            Site.Assert.AreEqual<uint>(
                0,
                saveChangesMessageResponse.ReturnValue,
                "Save Messages Success.");
            ulong messageId2 = saveChangesMessageResponse.MessageId;
            #endregion

            #region Step 17: Call RopReadPerUserInformation ROP request again.
            this.readPerUserInformationRequest.FolderId = longTermId;
            this.readPerUserInformationRequest.MaxDataSize = 0x100;
            this.readPerUserInformationRequest.DataOffset = 0;
            this.oxcstorAdapter.DoRopCall(this.readPerUserInformationRequest, this.outObjHandle, ROPCommandType.RopReadPerUserInformation, out this.outputBuffer);
            this.readPerUserInformationResponse = (RopReadPerUserInformationResponse)this.outputBuffer.RopsList[0];
            Site.Assert.AreEqual<uint>(0, this.readPerUserInformationResponse.ReturnValue, "0 indicates the ROP succeeds, other value indicates error occurs.");
            Site.Assert.IsNotNull(this.readPerUserInformationResponse.Data, "Data should be exist if user marks mail as un-read in public folder.");
            bool isChanged = !this.ByteArrayEquals(this.readPerUserInformationResponse.Data, data);

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1027.
            Site.CaptureRequirementIfIsTrue(
                isChanged,
                1027,
                @"[In Public Folders Specific Behavior] If the row exists, the accumulated change number information MUST replace any existing values in the table.");

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

            // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1026.
            Site.CaptureRequirementIfIsTrue(
                isChanged,
                1026,
                @"[In Public Folders Specific Behavior] The server searches the per-user data table for the only row with a user ID equal to user ID associated with the session logon and an FID equal to a value of the FolderId field.");
            #endregion

            #region Step 17: Delete the folder created in step 4.
            RopDeleteFolderRequest deleteFolderRequest;
            deleteFolderRequest.RopId = 0x1D;
            deleteFolderRequest.LogonId = 0x00;
            deleteFolderRequest.InputHandleIndex = 0x00;

            // The folder and all of the Message objects in the folder are deleted.
            deleteFolderRequest.DeleteFolderFlags = 0x01;

            // Folder to be deleted
            deleteFolderRequest.FolderId = folderId;
            this.oxcstorAdapter.DoRopCall(deleteFolderRequest, openedFolderHandle, ROPCommandType.Others, out this.outputBuffer);
            RopDeleteFolderResponse deleteFolderResponse = (RopDeleteFolderResponse)this.outputBuffer.RopsList[0];
            Site.Assert.AreEqual<uint>(
                0x00000000,
                deleteFolderResponse.ReturnValue,
                "0 indicates the ROP succeeds, other value indicates error occurs.");
            #endregion
        }
        /// <summary>
        /// Create Vast Messages In InBox
        /// </summary>
        /// <param name="logonResponse">the logon response be used to create message</param>
        /// <param name="tableHandle">The tableHanlder of the new folder</param>
        /// <param name="count">The count of created messages</param>
        /// <param name="createMessageRequest">The ROP CreateMessageRequest</param>
        /// <param name="saveChangesMessageRequest">The ROP SaveChangesMessageRequest</param>
        /// <param name="releaseRequest">The ROP ReleaseRequest</param>
        protected void CreateVastMessages(ref RopLogonResponse logonResponse, out uint tableHandle, int count, RopCreateMessageRequest createMessageRequest, RopSaveChangesMessageRequest saveChangesMessageRequest, RopReleaseRequest releaseRequest)
        {
            RopCreateMessageResponse createMessageResponse;
            RopSaveChangesMessageResponse saveChangesMessageResponse;
            #region Preparing the table: CreateFolder

            // Open a folder first
            RopOpenFolderRequest openFolderRequest;
            RopOpenFolderResponse openFolderResponse;

            openFolderRequest.RopId = (byte)RopId.RopOpenFolder;

            openFolderRequest.LogonId = TestSuiteBase.LogonId;
            openFolderRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;
            openFolderRequest.OutputHandleIndex = TestSuiteBase.OutputHandleIndex1;
            openFolderRequest.FolderId = logonResponse.FolderIds[4];
            openFolderRequest.OpenModeFlags = (byte)FolderOpenModeFlags.None;

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

            this.responseSOHs = this.cropsAdapter.ProcessSingleRop(
                openFolderRequest,
                this.inputObjHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            openFolderResponse = (RopOpenFolderResponse)this.response;
            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                openFolderResponse.ReturnValue,
                "if ROP succeeds, the ReturnValue of its response is 0(success)");
            uint openedFolderHandle = this.responseSOHs[0][openFolderResponse.OutputHandleIndex];

            // Create a new subfolder in the opened folder
            // The new subfolder will be used as target folder
            RopCreateFolderRequest createFolderRequest;
            RopCreateFolderResponse createFolderResponse;

            createFolderRequest.RopId = (byte)RopId.RopCreateFolder;
            createFolderRequest.LogonId = TestSuiteBase.LogonId;
            createFolderRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;
            createFolderRequest.OutputHandleIndex = TestSuiteBase.OutputHandleIndex1;
            createFolderRequest.FolderType = (byte)FolderType.Genericfolder;
            createFolderRequest.UseUnicodeStrings = Convert.ToByte(TestSuiteBase.Zero);
            createFolderRequest.OpenExisting = TestSuiteBase.NonZero;
            createFolderRequest.Reserved = TestSuiteBase.Reserved;
            createFolderRequest.DisplayName = Encoding.ASCII.GetBytes(TestSuiteBase.DisplayNameAndCommentForNonSearchFolder + "\0");
            createFolderRequest.Comment = Encoding.ASCII.GetBytes(TestSuiteBase.DisplayNameAndCommentForNonSearchFolder + "\0");

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

            this.responseSOHs = this.cropsAdapter.ProcessSingleRop(
                createFolderRequest,
                openedFolderHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            createFolderResponse = (RopCreateFolderResponse)this.response;
            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                createFolderResponse.ReturnValue,
                "if ROP succeeds, the ReturnValue of its response is 0(success)");
            uint targetFolderHandle = this.responseSOHs[0][openFolderResponse.OutputHandleIndex];
            tableHandle = this.GetContentsTableHandle(targetFolderHandle);
            ulong folderId = createFolderResponse.FolderId;

            #endregion

            int waitTime = int.Parse(Common.GetConfigurationPropertyValue("WaitTime", this.Site));
            int maxRetryCount = int.Parse(Common.GetConfigurationPropertyValue("RetryCount", this.Site));
            int retryCount;
            bool needRetry = false;
            uint returnValue = 0;
            int loopcount = 50;
            List<ISerializable> multipleRopRequests = new List<ISerializable>();
            List<IDeserializable> multipleRopResponses = new List<IDeserializable>();
            List<uint> multipleInputObjects = new List<uint>();
            List<uint> multipleOutputObjects = new List<uint>();

            for (int i = 0; i < count; i++)
            {
                // If the RPC report error code reported by the following three ROP methods is 1726 (The remote procedure call failed), 
                // re-do the common steps of this case.
                if (returnValue == 1726)
                {
                    // Step 1: Create a message.
                    #region Create message
                    // Add the debug information
                    Site.Log.Add(LogEntryKind.Debug, "If RPC error code is 1726, re-connect to server.");
                    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));
                    logonResponse = this.Logon(LogonType.Mailbox, this.userDN, out this.inputObjHandle);
                    #endregion

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

                    this.responseSOHs = this.cropsAdapter.ProcessSingleRop(
                        openFolderRequest,
                        this.inputObjHandle,
                        ref this.response,
                        ref this.rawData,
                        RopResponseType.SuccessResponse);
                    openFolderResponse = (RopOpenFolderResponse)this.response;

                    Site.Assert.AreEqual<uint>(
                        TestSuiteBase.SuccessReturnValue,
                        openFolderResponse.ReturnValue,
                        "if ROP succeeds, the ReturnValue of its response is 0(success)");
                    openedFolderHandle = this.responseSOHs[0][openFolderResponse.OutputHandleIndex];

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

                    this.responseSOHs = this.cropsAdapter.ProcessSingleRop(
                        createFolderRequest,
                        openedFolderHandle,
                        ref this.response,
                        ref this.rawData,
                        RopResponseType.SuccessResponse);
                    createFolderResponse = (RopCreateFolderResponse)this.response;
                    Site.Assert.AreEqual<uint>(
                        TestSuiteBase.SuccessReturnValue,
                        createFolderResponse.ReturnValue,
                        "if ROP succeeds, the ReturnValue of its response is 0(success)");
                    targetFolderHandle = this.responseSOHs[0][openFolderResponse.OutputHandleIndex];
                    tableHandle = this.GetContentsTableHandle(targetFolderHandle);
                    folderId = createFolderResponse.FolderId;
                }

                // Step 1: Create a message.
                #region Create message

                createMessageRequest.FolderId = logonResponse.FolderIds[4];

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

                retryCount = maxRetryCount;
                do
                {
                    multipleRopRequests.Clear();
                    multipleRopResponses.Clear();
                    multipleOutputObjects.Clear();
                    multipleInputObjects.Clear();

                    // Send multiple RopCreateMessage to create messages.
                    for (int t = 0; t < loopcount; t++)
                    {
                        createMessageRequest.FolderId = folderId;
                        createMessageRequest.InputHandleIndex = 0;
                        createMessageRequest.OutputHandleIndex = Convert.ToByte(t + 1);
                        multipleRopRequests.Add(createMessageRequest);
                        if (t == 0)
                        {
                            multipleInputObjects.Add(this.inputObjHandle);
                        }
                        else
                        {
                            multipleInputObjects.Add(TestSuiteBase.DefaultFolderHandle);
                        }
                    }

                    // An additional default handle is needed since the output handle index is from 1 to t+1 in the above loop, and the last one is not added in the above loop.
                    multipleInputObjects.Add(TestSuiteBase.DefaultFolderHandle);

                    this.responseSOHs = this.cropsAdapter.ProcessMutipleRops(
                      multipleRopRequests,
                      multipleInputObjects,
                      ref multipleRopResponses,
                      ref this.rawData,
                      RopResponseType.SuccessResponse);

                    for (int t = 0; t < multipleRopResponses.Count; t++)
                    {
                        if (multipleRopResponses[t] is RopBackoffResponse)
                        {
                            needRetry = true;
                            break;
                        }
                    }

                    System.Threading.Thread.Sleep(waitTime);
                    retryCount--;
                }
                while (needRetry && retryCount >= 0);

                Site.Assert.IsTrue(retryCount >= 0, "The case {0} failed since server is busy, reduce your server load and try again.", this.TestContext.TestName);

                // If the error code is 1726, continue this loop.
                if (returnValue == 1726)
                {
                    continue;
                }

                for (int t = 0; t < multipleRopResponses.Count; t++)
                {
                    if (multipleRopResponses[t] is RopCreateMessageResponse)
                    {
                        createMessageResponse = (RopCreateMessageResponse)multipleRopResponses[t];
                        Site.Assert.AreEqual<uint>(
                            TestSuiteBase.SuccessReturnValue,
                            createMessageResponse.ReturnValue,
                            "if ROP succeeds, the ReturnValue of its response is 0(success)");
                        uint targetMessageHandle = this.responseSOHs[0][createMessageResponse.OutputHandleIndex];
                        multipleOutputObjects.Add(targetMessageHandle);
                    }
                }
                #endregion

                // Step 2: Save the created message.
                #region Save message

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

                needRetry = false;
                retryCount = maxRetryCount;

                do
                {
                    multipleRopRequests.Clear();
                    multipleRopResponses.Clear();

                    // Send multiple RopSaveChangesMessage requests to save the created messages.
                    for (int t = 0; t < loopcount; t++)
                    {
                        saveChangesMessageRequest.InputHandleIndex = Convert.ToByte(t);
                        multipleRopRequests.Add(saveChangesMessageRequest);
                    }

                    this.responseSOHs = this.cropsAdapter.ProcessMutipleRops(
                     multipleRopRequests,
                     multipleOutputObjects,
                     ref multipleRopResponses,
                     ref this.rawData,
                     RopResponseType.SuccessResponse);

                    for (int t = 0; t < multipleRopResponses.Count; t++)
                    {
                        if (multipleRopResponses[t] is RopSaveChangesMessageResponse)
                        {
                            saveChangesMessageResponse = (RopSaveChangesMessageResponse)multipleRopResponses[t];
                            if (saveChangesMessageResponse.ReturnValue == 0x80040401)
                            {
                                needRetry = true;
                                break;
                            }
                        }
                        else if (this.response is RopBackoffResponse)
                        {
                            needRetry = false;
                            break;
                        }
                    }

                    System.Threading.Thread.Sleep(waitTime);
                    retryCount--;
                }
                while (this.response is RopBackoffResponse && retryCount >= 0);

                Site.Assert.IsTrue(retryCount >= 0, "The case {0} failed since server is busy, reduce your server load and try again.", this.TestContext.TestName);

                // If the error code is 1726, continue this loop.
                if (returnValue == 1726)
                {
                    continue;
                }

                for (int t = 0; t < multipleRopResponses.Count; t++)
                {
                    if (multipleRopResponses[t] is RopSaveChangesMessageResponse)
                    {
                        saveChangesMessageResponse = (RopSaveChangesMessageResponse)multipleRopResponses[t];
                        Site.Assert.AreEqual<uint>(
                            TestSuiteBase.SuccessReturnValue,
                            saveChangesMessageResponse.ReturnValue,
                        "if ROP succeeds, the ReturnValue of its response is 0(success)");
                    }
                }

                #endregion

                // Step 3: Send the RopRelease request to release all resources associated with a Server object.
                #region Release all resources

                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Step 2:Begin to send the RopRelease request in CreateVastMessages method.");
                needRetry = false;
                retryCount = maxRetryCount;

                do
                {
                    multipleRopRequests.Clear();
                    multipleRopResponses.Clear();
                    for (int t = 0; t < loopcount; t++)
                    {
                        releaseRequest.InputHandleIndex = Convert.ToByte(t);
                        multipleRopRequests.Add(releaseRequest);
                    }

                    this.responseSOHs = this.cropsAdapter.ProcessMutipleRops(
                     multipleRopRequests,
                     multipleOutputObjects,
                     ref multipleRopResponses,
                     ref this.rawData,
                     RopResponseType.SuccessResponse);

                    if (multipleRopResponses.Count != 0)
                    {
                        for (int t = 0; t < multipleRopResponses.Count; t++)
                        {
                            if (multipleRopResponses[t] is RopBackoffResponse)
                            {
                                needRetry = true;
                                break;
                            }
                        }
                    }

                    System.Threading.Thread.Sleep(waitTime);
                    retryCount--;
                }
                while (needRetry && retryCount >= 0);

                Site.Assert.IsTrue(retryCount >= 0, "The case {0} failed since server is busy, reduce your server load and try again.", this.TestContext.TestName);

                // If the error code is 1726, continue this loop.
                if (returnValue == 1726)
                {
                    continue;
                }
                #endregion
            }

            // If the error code 1726 occurs on the last time of the above "for" loop, re-do the common steps.
            if (returnValue == 1726)
            {
                #region The common steps
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "If RPC error code is 1726, re-connect to server.");
                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));
                logonResponse = this.Logon(LogonType.Mailbox, this.userDN, out this.inputObjHandle);
                #endregion
            }
        }
        /// <summary>
        /// Create message each one loop In InBox
        /// </summary>
        /// <param name="logonResponse">the logon response be used to create message</param>
        /// <param name="tableHandle">The tableHanlder of the new folder</param>
        /// <param name="count">The count of created messages</param>
        /// <param name="createMessageRequest">The ROP CreateMessageRequest</param>
        /// <param name="saveChangesMessageRequest">The ROP SaveChangesMessageRequest</param>
        /// <param name="releaseRequest">The ROP ReleaseRequest</param>
        protected void CreateSingleProcessEachLoop(ref RopLogonResponse logonResponse, out uint tableHandle, int count, RopCreateMessageRequest createMessageRequest, RopSaveChangesMessageRequest saveChangesMessageRequest, RopReleaseRequest releaseRequest)
        {
            RopCreateMessageResponse createMessageResponse = new RopCreateMessageResponse();
            RopSaveChangesMessageResponse saveChangesMessageResponse = new RopSaveChangesMessageResponse();
            #region Preparing the table: CreateFolder

            // Open a folder first
            RopOpenFolderRequest openFolderRequest;
            RopOpenFolderResponse openFolderResponse;

            openFolderRequest.RopId = (byte)RopId.RopOpenFolder;

            openFolderRequest.LogonId = TestSuiteBase.LogonId;
            openFolderRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;
            openFolderRequest.OutputHandleIndex = TestSuiteBase.OutputHandleIndex1;
            openFolderRequest.FolderId = logonResponse.FolderIds[4];
            openFolderRequest.OpenModeFlags = (byte)FolderOpenModeFlags.None;

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

            this.responseSOHs = this.cropsAdapter.ProcessSingleRop(
                openFolderRequest,
                this.inputObjHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            openFolderResponse = (RopOpenFolderResponse)this.response;
            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                openFolderResponse.ReturnValue,
                "if ROP succeeds, the ReturnValue of its response is 0(success)");
            uint openedFolderHandle = this.responseSOHs[0][openFolderResponse.OutputHandleIndex];

            // Create a new subfolder in the opened folder
            // The new subfolder will be used as target folder
            RopCreateFolderRequest createFolderRequest;
            RopCreateFolderResponse createFolderResponse;

            createFolderRequest.RopId = (byte)RopId.RopCreateFolder;
            createFolderRequest.LogonId = TestSuiteBase.LogonId;
            createFolderRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;
            createFolderRequest.OutputHandleIndex = TestSuiteBase.OutputHandleIndex1;
            createFolderRequest.FolderType = (byte)FolderType.Genericfolder;
            createFolderRequest.UseUnicodeStrings = Convert.ToByte(TestSuiteBase.Zero);
            createFolderRequest.OpenExisting = TestSuiteBase.NonZero;
            createFolderRequest.Reserved = TestSuiteBase.Reserved;
            createFolderRequest.DisplayName = Encoding.ASCII.GetBytes(TestSuiteBase.DisplayNameAndCommentForNonSearchFolder + "\0");
            createFolderRequest.Comment = Encoding.ASCII.GetBytes(TestSuiteBase.DisplayNameAndCommentForNonSearchFolder + "\0");

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

            this.responseSOHs = this.cropsAdapter.ProcessSingleRop(
                createFolderRequest,
                openedFolderHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            createFolderResponse = (RopCreateFolderResponse)this.response;
            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                createFolderResponse.ReturnValue,
                "if ROP succeeds, the ReturnValue of its response is 0(success)");
            uint targetFolderHandle = this.responseSOHs[0][openFolderResponse.OutputHandleIndex];
            tableHandle = this.GetContentsTableHandle(targetFolderHandle);
            ulong folderId = createFolderResponse.FolderId;

            #endregion

            #region Preparing the table: RopCreateAndSaveMessages

            int waitTime = int.Parse(Common.GetConfigurationPropertyValue("WaitTime", this.Site));
            int maxRetryCount = int.Parse(Common.GetConfigurationPropertyValue("RetryCount", this.Site));
            int retryCount;
            uint returnValue = 0;
            for (int i = 1; i < count; i++)
            {
                // If the RPC report error code reported by the following three ROP methods is 1726 (The remote procedure call failed), 
                // re-do the common steps of this case.
                if (returnValue == 1726)
                {
                    #region The common steps
                    // Add the debug information
                    Site.Log.Add(LogEntryKind.Debug, "If RPC error code is 1726, re-connect to server.");
                    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));
                    logonResponse = this.Logon(LogonType.Mailbox, this.userDN, out this.inputObjHandle);

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

                    this.responseSOHs = this.cropsAdapter.ProcessSingleRop(
                        openFolderRequest,
                        this.inputObjHandle,
                        ref this.response,
                        ref this.rawData,
                        RopResponseType.SuccessResponse);
                    openFolderResponse = (RopOpenFolderResponse)this.response;

                    Site.Assert.AreEqual<uint>(
                        TestSuiteBase.SuccessReturnValue,
                        openFolderResponse.ReturnValue,
                        "if ROP succeeds, the ReturnValue of its response is 0(success)");
                    openedFolderHandle = this.responseSOHs[0][openFolderResponse.OutputHandleIndex];

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

                    this.responseSOHs = this.cropsAdapter.ProcessSingleRop(
                        createFolderRequest,
                        openedFolderHandle,
                        ref this.response,
                        ref this.rawData,
                        RopResponseType.SuccessResponse);
                    createFolderResponse = (RopCreateFolderResponse)this.response;
                    Site.Assert.AreEqual<uint>(
                        TestSuiteBase.SuccessReturnValue,
                        createFolderResponse.ReturnValue,
                        "if ROP succeeds, the ReturnValue of its response is 0(success)");
                    targetFolderHandle = this.responseSOHs[0][openFolderResponse.OutputHandleIndex];
                    tableHandle = this.GetContentsTableHandle(targetFolderHandle);
                    folderId = createFolderResponse.FolderId;
                    #endregion
                }

                #region Create message
                createMessageRequest.FolderId = folderId;

                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Step 2:Begin to send the RopCreateMessage request:loop counter i={0}", i);
                retryCount = maxRetryCount;

                do
                {
                    // Send the RopCreateMessage to create message.
                    this.responseSOHs = this.cropsAdapter.ProcessSingleRopWithReturnValue(
                        createMessageRequest,
                        this.inputObjHandle,
                        ref this.response,
                        ref this.rawData,
                        RopResponseType.SuccessResponse,
                        out returnValue);
                    System.Threading.Thread.Sleep(waitTime);
                    retryCount--;
                }
                while (this.response is RopBackoffResponse && retryCount >= 0);

                Site.Assert.IsTrue(retryCount >= 0, "The case {0} failed since server is busy and always returns RopBackoff in the response, reduce your server load and try again.", this.TestContext.TestName);

                // If the error code is 1726, continue this loop.
                if (returnValue == 1726)
                {
                    continue;
                }

                createMessageResponse = (RopCreateMessageResponse)this.response;
                Site.Assert.AreEqual<uint>(
                    TestSuiteBase.SuccessReturnValue,
                    createMessageResponse.ReturnValue,
                "if ROP succeeds, the ReturnValue of its response is 0(success)");
                uint targetMessageHandle = this.responseSOHs[0][createMessageResponse.OutputHandleIndex];
                #endregion

                #region Save message
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Step 2:Begin to send the RopSaveChangesMessage request:loop counter i={0}", i);

                retryCount = maxRetryCount;

                // Do the loop when response is RopBackoffResponse or saveChangesMessageResponse is 0x80040401 (ecTimeout).
                do
                {
                    // Send the RopSaveChangesMessage request to save the created message.
                    this.responseSOHs = this.cropsAdapter.ProcessSingleRopWithReturnValue(
                        saveChangesMessageRequest,
                        targetMessageHandle,
                        ref this.response,
                        ref this.rawData,
                        RopResponseType.SuccessResponse,
                        out returnValue);

                    if (this.response is RopSaveChangesMessageResponse)
                    {
                        saveChangesMessageResponse = (RopSaveChangesMessageResponse)this.response;
                    }

                    System.Threading.Thread.Sleep(waitTime);
                    retryCount--;
                }
                while ((this.response is RopBackoffResponse || saveChangesMessageResponse.ReturnValue == 0x80040401) && retryCount >= 0);

                Site.Assert.IsTrue(retryCount >= 0, "The case {0} failed since server is busy and always returns RopBackoff in the response, reduce your server load and try again.", this.TestContext.TestName);

                // If the error code is 1726, continue this loop.
                if (returnValue == 1726)
                {
                    continue;
                }

                saveChangesMessageResponse = (RopSaveChangesMessageResponse)this.response;
                Site.Assert.AreEqual<uint>(
                    TestSuiteBase.SuccessReturnValue,
                    saveChangesMessageResponse.ReturnValue,
                "if ROP succeeds, the ReturnValue of its response is 0(success)");
                #endregion

                #region Release all resources
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Step 2:Begin to send the RopRelease request.");

                retryCount = maxRetryCount;

                do
                {
                    this.responseSOHs = this.cropsAdapter.ProcessSingleRopWithReturnValue(
                        releaseRequest,
                        targetMessageHandle,
                        ref this.response,
                        ref this.rawData,
                        RopResponseType.SuccessResponse,
                        out returnValue);
                    System.Threading.Thread.Sleep(waitTime);
                    retryCount--;
                }
                while (this.response is RopBackoffResponse && retryCount >= 0);

                Site.Assert.IsTrue(retryCount >= 0, "The case {0} failed since server is busy and always returns RopBackoff in the response, reduce your server load and try again.", this.TestContext.TestName);

                // If the error code is 1726, continue this loop.
                if (returnValue == 1726)
                {
                    continue;
                }
                #endregion
            }

            // If the error code 1726 occurs on the last time of the above "for" loop, re-do the common steps.
            if (returnValue == 1726)
            {
                #region The common steps
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "If RPC error code is 1726, re-connect to server.");
                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));
                logonResponse = this.Logon(LogonType.Mailbox, this.userDN, out this.inputObjHandle);

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

                this.responseSOHs = this.cropsAdapter.ProcessSingleRop(
                    openFolderRequest,
                    this.inputObjHandle,
                    ref this.response,
                    ref this.rawData,
                    RopResponseType.SuccessResponse);
                openFolderResponse = (RopOpenFolderResponse)this.response;

                Site.Assert.AreEqual<uint>(
                    TestSuiteBase.SuccessReturnValue,
                    openFolderResponse.ReturnValue,
                    "if ROP succeeds, the ReturnValue of its response is 0(success)");
                openedFolderHandle = this.responseSOHs[0][openFolderResponse.OutputHandleIndex];

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

                this.responseSOHs = this.cropsAdapter.ProcessSingleRop(
                    createFolderRequest,
                    openedFolderHandle,
                    ref this.response,
                    ref this.rawData,
                    RopResponseType.SuccessResponse);
                createFolderResponse = (RopCreateFolderResponse)this.response;
                Site.Assert.AreEqual<uint>(
                    TestSuiteBase.SuccessReturnValue,
                    createFolderResponse.ReturnValue,
                    "if ROP succeeds, the ReturnValue of its response is 0(success)");
                targetFolderHandle = this.responseSOHs[0][openFolderResponse.OutputHandleIndex];
                tableHandle = this.GetContentsTableHandle(targetFolderHandle);
                folderId = createFolderResponse.FolderId;
                #endregion
            }

            #endregion
        }
        public void MSOXCROPS_S06_TC03_TestRopProgress()
        {
            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));

            // Refer to MS-OXCPRPT: The initial release version of Exchange 2010 does not implement the RopProgress ROP.
            if (Common.IsRequirementEnabled(86601, this.Site))
            {
                // Step 1: Preparations-Open a folder and construct emptyFolderRequest.
                #region Common methods

                // Log on to a private mailbox.
                RopLogonResponse logonResponse = Logon(LogonType.Mailbox, this.userDN, out inputObjHandle);
                RopCreateMessageRequest createMessageRequest = new RopCreateMessageRequest();
                RopSaveChangesMessageRequest saveChangesMessageRequest = new RopSaveChangesMessageRequest();
                RopReleaseRequest releaseRequest = new RopReleaseRequest();
                this.PrepareRops(logonResponse, ref createMessageRequest, ref saveChangesMessageRequest, ref releaseRequest);
                uint tableHandle;

                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Step 1:Call CreateVastMessages method to create Vast Messages In InBox.");

                string transportSeq = Common.GetConfigurationPropertyValue("TransportSeq", this.Site).ToLower();
                if (transportSeq == "mapi_http")
                {
                    this.CreateVastMessages(ref logonResponse, out tableHandle, TestSuiteBase.MessagesCount / 50, createMessageRequest, saveChangesMessageRequest, releaseRequest);
                }
                else
                {
                    this.CreateSingleProcessEachLoop(ref logonResponse, out tableHandle, TestSuiteBase.MessagesCount, createMessageRequest, saveChangesMessageRequest, releaseRequest);
                }

                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Step 1:Call CreateVastMessages method to create Vast Messages In InBox.");

                // Call GetOpenedFolderHandle to get the opened folder handle.
                uint openedFolderHandle = this.GetOpenedFolderHandle(logonResponse.FolderIds[4], inputObjHandle);

                #endregion

                // Step 2: Verify the RopProgress success response.
                #region RopProgress success response

                // Send the RopEmptyFolder request to delete all messages and subfolders from opened folder.
                #region RopEmptyFolder request

                RopProgressRequest progressRequest;
                RopEmptyFolderRequest emptyFolderRequest;

                emptyFolderRequest.RopId = (byte)RopId.RopEmptyFolder;
                emptyFolderRequest.LogonId = TestSuiteBase.LogonId;
                emptyFolderRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;
                emptyFolderRequest.WantAsynchronous = TestSuiteBase.NonZero;
                emptyFolderRequest.WantDeleteAssociated = TestSuiteBase.NonZero;

                #endregion

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

                // Send the RopEmptyFolder request.
                this.responseSOHs = cropsAdapter.ProcessSingleRop(
                    emptyFolderRequest,
                    openedFolderHandle,
                    ref this.response,
                    ref this.rawData,
                    RopResponseType.SuccessResponse);

                if (response is RopProgressResponse)
                {
                    RopProgressResponse ropProgressResponse = (RopProgressResponse)response;

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

                    // Verify MS-OXCROPS requirement: MS-OXCROPS_R86601
                    Site.CaptureRequirementIfAreEqual<uint>(
                        TestSuiteBase.SuccessReturnValue,
                        ropProgressResponse.ReturnValue,
                        86601,
                        @"[In Appendix A: Product Behavior] Implementation does implement the RopProgress ROP ([MS-OXCROPS] section 2.2.8.13). (Exchange 2007 and Exchange 2013 follow this behavior.)");
                }

                #endregion

                if (Common.IsRequirementEnabled(3155, this.Site))
                {
                    // Step 3: Send the RopProgress request and verify the failure response.
                    #region Step 3: Send the RopProgress request and verify the failure response.

                    progressRequest.RopId = (byte)RopId.RopProgress;
                    progressRequest.LogonId = TestSuiteBase.LogonId;
                    progressRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex1;
                    progressRequest.WantCancel = Convert.ToByte(TestSuiteBase.Zero);

                    Site.Log.Add(LogEntryKind.Debug, "Step 3: Begin to send the RopProgress request.");

                    // Send the RopProgress request and verify the success response.
                    this.responseSOHs = cropsAdapter.ProcessSingleRop(
                        progressRequest,
                        this.inputObjHandle,
                        ref this.response,
                        ref this.rawData,
                        RopResponseType.FailureResponse);

                    #endregion
                }
            }
        }
        /// <summary>
        /// This ROP commits the changes made to a message. 
        /// </summary>
        /// <param name="handle">The handle to operate.</param>
        /// <param name="needVerify">Whether need to verify the response.</param>
        /// <returns>The response of this ROP.</returns>
        private RopSaveChangesMessageResponse RopSaveChangesMessage(uint handle, bool needVerify)
        {
            this.rawDataValue = null;
            this.responseValue = null;
            this.responseSOHsValue = null;

            RopSaveChangesMessageRequest saveChangesMessageRequest = new RopSaveChangesMessageRequest()
            {
                RopId = (byte)RopId.RopSaveChangesMessage,
                LogonId = LogonId,
                InputHandleIndex = (byte)HandleIndex.FirstIndex,
                ResponseHandleIndex = (byte)HandleIndex.SecondIndex,

                // Set the SaveFlags flag to ForceSave, which indicates the client requests server to commit the changes. 
                SaveFlags = (byte)SaveFlags.ForceSave,
            };

            this.responseSOHsValue = this.ProcessSingleRop(saveChangesMessageRequest, handle, ref this.responseValue, ref this.rawDataValue, RopResponseType.SuccessResponse);
            RopSaveChangesMessageResponse saveChangesMessageResponse = (RopSaveChangesMessageResponse)this.responseValue;

            if (needVerify)
            {
                this.Site.Assert.AreEqual((uint)RopResponseType.SuccessResponse, saveChangesMessageResponse.ReturnValue, string.Format("RopSaveChangesMessage Failed! Error: 0x{0:X8}", saveChangesMessageResponse.ReturnValue));
            }

            return saveChangesMessageResponse;
        }
        public void MSOXCMSG_S01_TC12_RopSaveChangeMessageWithReadOnlyProperty()
        {
            this.CheckMapiHttpIsSupported();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);

            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 RopSaveChangesMessage to save a Message object and server return an error.
            if (Common.IsRequirementEnabled(1644, this.Site))
            {
                #region Call RopSetProperties to set PidTagHasAttachments that is a read-only property.
                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 = 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.AreEqual<uint>(0x80004005, saveChangesMessageResponse.ReturnValue, "Call RopSaveChangesMessage should failed.");
                #endregion

                #region Call RopSetProperties to set PidTagMessageSize that is a read-only property.
                propertyList = new List<PropertyObj>
                {
                    new PropertyObj(PropertyNames.PidTagMessageSize, BitConverter.GetBytes(0))
                };
                this.SetPropertiesForMessage(targetMessageHandle, propertyList);

                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.AreEqual<uint>(0x80004005, saveChangesMessageResponse.ReturnValue, "Call RopSaveChangesMessage should failed.");
                #endregion

                #region Call RopSetProperties to set PidTagAccess that is a read-only property.
                propertyList = new List<PropertyObj>
                {
                    new PropertyObj(PropertyNames.PidTagAccess, BitConverter.GetBytes(0x00000001))
                };
                this.SetPropertiesForMessage(targetMessageHandle, propertyList);

                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.AreEqual<uint>(0x80004005, saveChangesMessageResponse.ReturnValue, "Call RopSaveChangesMessage should failed.");
                #endregion

                #region Call RopSetProperties to set PidTagAccessLevel that is a read-only property.
                propertyList = new List<PropertyObj>
                {
                    new PropertyObj(PropertyNames.PidTagAccessLevel, BitConverter.GetBytes(0x00000001))
                };
                this.SetPropertiesForMessage(targetMessageHandle, propertyList);

                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.AreEqual<uint>(0x80004005, saveChangesMessageResponse.ReturnValue, "Call RopSaveChangesMessage should failed.");
                #endregion

                #region Call RopSetProperties to set PidTagObjectType that is a read-only property.
                propertyList = new List<PropertyObj>
                {
                    new PropertyObj(PropertyNames.PidTagObjectType, BitConverter.GetBytes(0x00000005))
                };
                this.SetPropertiesForMessage(targetMessageHandle, propertyList);

                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.AreEqual<uint>(0x80004005, saveChangesMessageResponse.ReturnValue, "Call RopSaveChangesMessage should failed.");
                #endregion

                #region Call RopSetProperties to set PidTagRecordKey that is a read-only property.
                propertyList = new List<PropertyObj>
                {
                    new PropertyObj(PropertyNames.PidTagRecordKey, new byte[] { 0x10, 0x00, 0xa1, 0x3e, 0x25, 0x6f, 0xbb, 0x2c, 0x26, 0x44, 0x8c, 0x8a, 0x2c, 0x52, 0x0c, 0x85, 0xfb, 0x08})
                };
                this.SetPropertiesForMessage(targetMessageHandle, propertyList);

                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.AreEqual<uint>(0x80004005, saveChangesMessageResponse.ReturnValue, "Call RopSaveChangesMessage should failed.");
                #endregion

                #region Call RopSetProperties to set PidTagMessageStatus that is a read-only property.
                propertyList = new List<PropertyObj>
                {
                    new PropertyObj(PropertyNames.PidTagMessageStatus, BitConverter.GetBytes(0x00001000))
                };
                this.SetPropertiesForMessage(targetMessageHandle, propertyList);

                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.AreEqual<uint>(0x80004005, saveChangesMessageResponse.ReturnValue, "Call RopSaveChangesMessage should failed.");
                #endregion

                #region Call RopSetProperties to set PidTagChangeKey that is a read-only property.
                propertyList = new List<PropertyObj>
                {
                    new PropertyObj(PropertyNames.PidTagChangeKey,new byte[] { 0x10, 0x00, 0xa1, 0x3e, 0x25, 0x6f, 0xbb, 0x2c, 0x26, 0x44, 0x8c, 0x8a, 0x2c, 0x52, 0x0c, 0x85, 0xfb, 0x08})
                };
                this.SetPropertiesForMessage(targetMessageHandle, propertyList);

                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.AreEqual<uint>(0x80004005, saveChangesMessageResponse.ReturnValue, "Call RopSaveChangesMessage should failed.");
                #endregion

                #region Call RopSetProperties to set PidTagSearchKey that is a read-only property.
                propertyList = new List<PropertyObj>
                {
                    new PropertyObj(PropertyNames.PidTagSearchKey,new byte[] { 0x10, 0x00, 0xa1, 0x3e, 0x25, 0x6f, 0xbb, 0x2c, 0x26, 0x44, 0x8c, 0x8a, 0x2c, 0x52, 0x0c, 0x85, 0xfb, 0x08})
                };
                this.SetPropertiesForMessage(targetMessageHandle, propertyList);

                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.AreEqual<uint>(0x80004005, saveChangesMessageResponse.ReturnValue, "Call RopSaveChangesMessage should failed.");
                #endregion

                #region Call RopSetProperties to set PidTagCreationTime that is a read-only property.
                propertyList = new List<PropertyObj>
                {
                    new PropertyObj(PropertyNames.PidTagCreationTime, BitConverter.GetBytes(DateTime.Parse(TestDataOfDateTime).ToFileTimeUtc()))
                };
                this.SetPropertiesForMessage(targetMessageHandle, propertyList);

                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.AreEqual<uint>(0x80004005, saveChangesMessageResponse.ReturnValue, "Call RopSaveChangesMessage should failed.");
                #endregion

                #region Call RopSetProperties to set PidTagLastModificationTime that is a read-only property.
                propertyList = new List<PropertyObj>
                {
                    new PropertyObj(PropertyNames.PidTagLastModificationTime, BitConverter.GetBytes(DateTime.Parse(TestDataOfDateTime).ToFileTimeUtc()))
                };
                this.SetPropertiesForMessage(targetMessageHandle, propertyList);

                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.AreEqual<uint>(0x80004005, saveChangesMessageResponse.ReturnValue, "Call RopSaveChangesMessage should failed.");
                #endregion

                #region Call RopSetProperties to set PidTagLastModifierName that is a read-only property.
                propertyList = new List<PropertyObj>
                {
                    new PropertyObj(PropertyNames.PidTagLastModifierName,Common.GetBytesFromUnicodeString("Last modifier name"))
                };
                this.SetPropertiesForMessage(targetMessageHandle, propertyList);

                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.AreEqual<uint>(0x80004005, saveChangesMessageResponse.ReturnValue, "Call RopSaveChangesMessage should failed.");
                #endregion

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R1724
                this.Site.CaptureRequirement(
                    1724,
                    @"[In General Properties] These properties are read-only for the client: PidTagAccess, PidTagChangeKey, PidTagCreationTime, PidTagLastModificationTime, PidTagLastModifierName, PidTagObjectType, PidTagRecordKey and PidTagSearchKey.");

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R1078
                this.Site.CaptureRequirement(
                    1078,
                    @"[In General Properties] These properties [PidTagAccessLevel, PidTagObjectType and PidTagRecordKey] are read-only for the client.");

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R1644
                this.Site.CaptureRequirement(
                    1644,
                    @"[In Appendix A: Product Behavior] Implementation does return a GeneralFailure error if pending changes include changes to read-only properties PidTagMessageSize, PidTagAccess, PidTagAccessLevel, PidTagObjectType, PidTagRecordKey, PidTagMessageStatus, and PidTagHasAttachments [about RopSaveChangeMessage]. (Exchange 2010 and above follow this behavior.)");
            }

            this.ReleaseRop(targetMessageHandle);
            #endregion

            #region Call RopRelease to release created message.
            this.ReleaseRop(targetMessageHandle);
            #endregion
        }
        public void MSOXCMSG_S01_TC04_RopSaveChangesMessageWithInvalidSaveFlags()
        {
            this.CheckMapiHttpIsSupported();
            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);
            #endregion

            #region Call RopSaveChangesMessage which contains an incorrect value of SaveFlags field.
            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 = NotSupportedSaveFlags
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(saveChangesMessageRequest, targetMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopSaveChangesMessageResponse saveChangesMessageResponse = (RopSaveChangesMessageResponse)this.response;

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R1052
            Site.CaptureRequirementIfAreEqual<uint>(
                0x80040102,
                saveChangesMessageResponse.ReturnValue,
                1052,
                @"[In Receiving a RopSaveChangesMessage ROP Request] [ecNotSupported (0x80040102)] The values of the SaveFlags are not a supported combination.");
            #endregion
        }
        public void MSOXCMSG_S01_TC10_RopSaveChangeMessageWithReadOnlyProperty()
        {
            this.CheckMapiHttpIsSupported();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);
            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 as read-only.
            targetMessageHandle = this.OpenSpecificMessage(logonResponse.FolderIds[4], messageID, this.insideObjHandle, MessageOpenModeFlags.ReadOnly);
            #endregion

            #region Call RopSaveChangesMessage to commit the Message object created and keep the message open with read-only.
           
            if(Common.IsRequirementEnabled(3019,this.Site))
            {
                RopSaveChangesMessageRequest saveChangesMessageRequest = new RopSaveChangesMessageRequest()
                {
                    RopId = (byte)RopId.RopSaveChangesMessage,
                    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. 
                    ResponseHandleIndex = CommonOutputHandleIndex, // This index specifies the location in the Server object handle table that is referenced in the response. 
                    SaveFlags = (byte)SaveFlags.KeepOpenReadOnly
                };
                uint returnValue = 0;
                this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(saveChangesMessageRequest, targetMessageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None,out returnValue);

                bool isR3019Verifed = false;

                if (returnValue == 0)
                {
                    if (((RopSaveChangesMessageResponse)this.response).ReturnValue == 0x80004005)
                    {
                        isR3019Verifed = true;
                    }
                }
                else
                {
                    if (returnValue == 0x80004005)
                    {
                        isR3019Verifed = true;
                    }
                }

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R3019
                this.Site.CaptureRequirementIfIsTrue(
                    isR3019Verifed,
                    3019,
                    @"[In Appendix A: Product Behavior] [ecError (0x80004005)] The message has been opened or previously saved as read only; changes cannot be saved. (<27> Section 3.2.5.3: Exchange 2010, Exchange 2013, and Exchange 2016 follow this behavior.)");

            }
            #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
        }
   /// <summary>
   /// Save Message
   /// </summary>
   /// <param name="messagesHandle">An unsigned integer value indicates a Message object handle.</param>
   /// <param name="saveFlags">A byte value indicates value of SaveFlags.</param>
   /// <returns>Return a RopSaveChangesMessageResponse object.</returns>
   protected RopSaveChangesMessageResponse SaveMessage(uint messagesHandle, byte saveFlags)
   {
       RopSaveChangesMessageRequest saveChangesMessageRequest = new RopSaveChangesMessageRequest()
       {
           RopId = (byte)RopId.RopSaveChangesMessage,
           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. 
           ResponseHandleIndex = CommonOutputHandleIndex, // This index specifies the location in the Server object handle table that is referenced in the response. 
           SaveFlags = saveFlags// Read write
       };
       this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(saveChangesMessageRequest, messagesHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
       RopSaveChangesMessageResponse saveChangesMessageResponse = (RopSaveChangesMessageResponse)this.response;
 
       return (RopSaveChangesMessageResponse)this.response;
   }
        public void MSOXCROPS_S12_TC01_TestRopPending()
        {
            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 RopRegisterNotification request and verify the success response.
            #region RopRegisterNotification success response

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

            RopRegisterNotificationRequest registerNotificationRequest;
            RopRegisterNotificationResponse registerNotificationResponse;

            registerNotificationRequest.RopId = (byte)RopId.RopRegisterNotification;

            registerNotificationRequest.LogonId = TestSuiteBase.LogonId;
            registerNotificationRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;
            registerNotificationRequest.OutputHandleIndex = TestSuiteBase.OutputHandleIndex0;

            // The server MUST send notifications to the client when CriticalError events occur within the scope of interest
            registerNotificationRequest.NotificationTypes = (byte)NotificationTypes.NewMail;
            registerNotificationRequest.Reserved = TestSuiteBase.Reserved;

            // TRUE: the scope for notifications is the entire database
            registerNotificationRequest.WantWholeStore = TestSuiteBase.NonZero;

            registerNotificationRequest.FolderId = logonResponse.FolderIds[4];
            registerNotificationRequest.MessageId = MS_OXCROPSAdapter.MessageIdForRops;

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 1: Begin to send the RopRegisterNotification request:NotificationTypes=0x02.");

            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                registerNotificationRequest,
                this.inputObjHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            registerNotificationResponse = (RopRegisterNotificationResponse)response;

            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                registerNotificationResponse.ReturnValue,
                "If ROP succeeds, the ReturnValue of its response is 0 (success)");

            // Set NotificationTypes to 0x04, which means the server sends notifications to the client when ObjectCreated events occur
            // within the scope of interest, as specified in [MS-OXCNOTIF].
            registerNotificationRequest.NotificationTypes = (byte)NotificationTypes.ObjectCreated;

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 1: Begin to send the RopRegisterNotification request:NotificationTypes=0x04.");

            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                registerNotificationRequest,
                this.inputObjHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            registerNotificationResponse = (RopRegisterNotificationResponse)response;

            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                registerNotificationResponse.ReturnValue,
                "If ROP succeeds, the ReturnValue of its response is 0 (success)");

            // Set NotificationTypes to 0x08, which means the server sends notifications to the client when ObjectDeleted events occur
            // within the scope of interest, as specified in [MS-OXCNOTIF].
            registerNotificationRequest.NotificationTypes = (byte)NotificationTypes.ObjectDeleted;

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 1: Begin to send the RopRegisterNotification request:NotificationTypes=0x08.");

            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                registerNotificationRequest,
                this.inputObjHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            registerNotificationResponse = (RopRegisterNotificationResponse)response;

            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                registerNotificationResponse.ReturnValue,
                "If ROP succeeds, the ReturnValue of its response is 0 (success)");

            // Set NotificationTypes to 0x10, which means the server sends notifications to the client when ObjectModified events occur
            // within the scope of interest, as specified in [MS-OXCNOTIF].
            registerNotificationRequest.NotificationTypes = (byte)NotificationTypes.ObjectModified;

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 1: Begin to send the RopRegisterNotification request:NotificationTypes=0x10.");

            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                registerNotificationRequest,
                this.inputObjHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            registerNotificationResponse = (RopRegisterNotificationResponse)response;

            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                registerNotificationResponse.ReturnValue,
                "If ROP succeeds, the ReturnValue of its response is 0 (success)");

            // Set NotificationTypes to 0x20, which means the server sends notifications to the client when ObjectMoved events occur
            // within the scope of interest, as specified in [MS-OXCNOTIF].
            registerNotificationRequest.NotificationTypes = (byte)NotificationTypes.ObjectMoved;

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 1: Begin to send the RopRegisterNotification request:NotificationTypes=0x20.");

            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                registerNotificationRequest,
                this.inputObjHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            registerNotificationResponse = (RopRegisterNotificationResponse)response;

            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                registerNotificationResponse.ReturnValue,
                "If ROP succeeds, the ReturnValue of its response is 0 (success)");

            // Set NotificationTypes to 0x40, which means the server sends notifications to the client when ObjectCopied events occur
            // within the scope of interest, as specified in [MS-OXCNOTIF].
            registerNotificationRequest.NotificationTypes = (byte)NotificationTypes.ObjectCopied;

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 1: Begin to send the RopRegisterNotification request:NotificationTypes=0x40.");

            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                registerNotificationRequest,
                this.inputObjHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            registerNotificationResponse = (RopRegisterNotificationResponse)response;

            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                registerNotificationResponse.ReturnValue,
                "If ROP succeeds, the ReturnValue of its response is 0 (success)");

            // Set NotificationTypes to 0x80, which means the server sends notifications to the client when SearchCompleted events occur
            // within the scope of interest, as specified in [MS-OXCNOTIF].
            registerNotificationRequest.NotificationTypes = (byte)NotificationTypes.SearchCompleted;

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 1: Begin to send the RopRegisterNotification request:NotificationTypes=0x80.");

            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                registerNotificationRequest,
                this.inputObjHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            registerNotificationResponse = (RopRegisterNotificationResponse)response;

            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                registerNotificationResponse.ReturnValue,
                "If ROP succeeds, the ReturnValue of its response is 0 (success)");

            #endregion

            // Step 2: Create message,Save message to test RopPending, RopNotify and RopBufferTooSmall
            #region RopRegisterNotification success response

            #region prepare rops for createmessage, savemessage and release
            RopCreateMessageRequest createMessageRequest = new RopCreateMessageRequest();
            RopSaveChangesMessageRequest saveChangesMessageRequest = new RopSaveChangesMessageRequest();
            RopReleaseRequest releaseRequest = new RopReleaseRequest();
            this.PrepareRops(logonResponse, ref createMessageRequest, ref saveChangesMessageRequest, ref releaseRequest);
            #endregion
            // Totally create message loop count.
            int loopCount;
            uint tableHandle = 0;

            string transportSeq = Common.GetConfigurationPropertyValue("TransportSeq", this.Site).ToLower();
            if (transportSeq == "mapi_http")
            {
                loopCount = 20;
                this.CreateVastMessages(ref logonResponse, out tableHandle, loopCount, createMessageRequest, saveChangesMessageRequest, releaseRequest);
            }
            else
            {
                loopCount = 1000;
                this.CreateSingleProcessEachLoop(ref logonResponse, out tableHandle, loopCount, createMessageRequest, saveChangesMessageRequest, releaseRequest);
            }

            #region RopBufferTooSmall response

            List<ISerializable> ropRequests1 = new List<ISerializable>();
            List<uint> inputObjects1 = new List<uint>
            {
                this.inputObjHandle
            };
            List<IDeserializable> ropResponses1 = new List<IDeserializable>();
            RopGetPropertiesAllRequest getPropertiesAllRequest;

            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 = Convert.ToUInt16(TestSuiteBase.Zero);
            byte count = 255;
            for (byte i = 1; i < count; i++)
            {
                ropRequests1.Add(getPropertiesAllRequest);
            }

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

            // Verify the RopBufferTooSmall
            this.responseSOHs = cropsAdapter.ProcessMutipleRops(ropRequests1, inputObjects1, ref ropResponses1, ref this.rawData, RopResponseType.FailureResponse);

            #endregion

            List<IDeserializable> ropResponses4 = new List<IDeserializable>();

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

            // All the requests are GetPropertiesAllRequest, resubmit the request in another call and get the responses in the ropResponses4
            this.responseSOHs = cropsAdapter.ProcessMutipleRops(ropRequests1, inputObjects1, ref ropResponses4, ref this.rawData, RopResponseType.SuccessResponse);

            #region RopSetColumns success response

            RopSetColumnsRequest setColumnsRequest;
            RopSetColumnsResponse setColumnsResponse;

            PropertyTag[] propertyTags = CreateSampleContentsTablePropertyTags();
            setColumnsRequest.RopId = (byte)RopId.RopSetColumns;
            setColumnsRequest.LogonId = TestSuiteBase.LogonId;
            setColumnsRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;
            setColumnsRequest.SetColumnsFlags = (byte)AsynchronousFlags.None;
            setColumnsRequest.PropertyTagCount = (ushort)propertyTags.Length;
            setColumnsRequest.PropertyTags = propertyTags;

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

            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                setColumnsRequest,
                tableHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            setColumnsResponse = (RopSetColumnsResponse)response;
            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                setColumnsResponse.ReturnValue,
                "if ROP succeeds, the ReturnValue of its response is 0(success)");

            #endregion

            #region RopQueryRows success response: send RopSetColumns and RopQueryRows in a request buffer
            RopQueryRowsRequest queryRowsRequest;

            queryRowsRequest.RopId = (byte)RopId.RopQueryRows;
            queryRowsRequest.LogonId = TestSuiteBase.LogonId;
            queryRowsRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;
            queryRowsRequest.QueryRowsFlags = (byte)QueryRowsFlags.Advance;
            queryRowsRequest.ForwardRead = TestSuiteBase.NonZero;

            // Set RowCount to 0x01, which the number of requested rows, as specified in [MS-OXCROPS].
            queryRowsRequest.RowCount = TestSuiteBase.RowCount;

            List<ISerializable> ropRequests = new List<ISerializable>
            {
                setColumnsRequest, queryRowsRequest
            };
            createMessageRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex2;
            createMessageRequest.OutputHandleIndex = TestSuiteBase.OutputHandleIndex3;
            createMessageRequest.FolderId = logonResponse.FolderIds[4];
            ropRequests.Add(createMessageRequest);
            saveChangesMessageRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex3;
            ropRequests.Add(saveChangesMessageRequest);
            List<uint> inputObjects = new List<uint>
            {
                tableHandle,
                0xFFFF,
                this.inputObjHandle,
                0xFFFF
            };

            // 0xFFFF indicates a default input handle.
            List<IDeserializable> ropResponses = new List<IDeserializable>();

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 2: Begin to send the multiple ROPs request to verify the RopNotify response.");

            // Verify the RopNotify
            this.responseSOHs = cropsAdapter.ProcessMutipleRops(ropRequests, inputObjects, ref ropResponses, ref this.rawData, RopResponseType.SuccessResponse);

            // Set RowCount to 0x0600, which the number of requested rows, as specified in [MS-OXCROPS].
            queryRowsRequest.RowCount = TestSuiteBase.RowCount;

            List<ISerializable> ropRequests2 = new List<ISerializable>
            {
                setColumnsRequest, queryRowsRequest
            };
            createMessageRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex2;
            createMessageRequest.OutputHandleIndex = TestSuiteBase.OutputHandleIndex3;
            createMessageRequest.FolderId = logonResponse.FolderIds[4];
            ropRequests2.Add(createMessageRequest);
            saveChangesMessageRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex3;
            ropRequests2.Add(saveChangesMessageRequest);
            List<uint> inputObjects2 = new List<uint>
            {
                tableHandle,
                0xFFFF,
                this.inputObjHandle,
                0xFFFF
            };

            // 0xFFFF indicates a default input handle.
            List<IDeserializable> ropResponses2 = new List<IDeserializable>();

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 2: Begin to send the multiple ROPs request to verify the RopPending response.");

            // Verify the RopPending
            this.responseSOHs = cropsAdapter.ProcessMutipleRops(ropRequests2, inputObjects2, ref ropResponses2, ref this.rawData, RopResponseType.SuccessResponse);

            bool isContainedRopPending = false;
            for (int i = 1; i < ropResponses2.Count; i++)
            {
                if (ropResponses2[i] is RopPendingResponse)
                {
                    isContainedRopPending = true;
                    break;
                }
            }

            // Send an empty ROP to verify all queued RopNotify response have got in last step.
            List<ISerializable> ropRequestsEmpty = new List<ISerializable>(0x02);
            List<IDeserializable> ropResponsesNull = new List<IDeserializable>();

            this.responseSOHs = cropsAdapter.ProcessMutipleRops(ropRequestsEmpty, inputObjects, ref ropResponsesNull, ref this.rawData, RopResponseType.SuccessResponse);

            if (ropResponsesNull.Count == 0)
            {
                if (Common.IsRequirementEnabled(469303, this.Site))
                {
                    // Add the debug information
                    Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCROPS_R469303");

                    // Verify MS-OXCROPS requirement: MS-OXCROPS_R469303
                    Site.CaptureRequirementIfIsTrue(
                        isContainedRopPending,
                        469303,
                        @"[In Appendix B: Product Behavior] Implementation does include a RopPending ROP response (section 2.2.14.3) even though the ROP output buffer contains all queued RopNotify ROP responses (section 2.2.14.2). (<16> Section 3.1.5.1.3: Exchange 2007 follows this behavior.)");
                }

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

                    // Verify MS-OXCROPS requirement: MS-OXCROPS_R4693031
                    Site.CaptureRequirementIfIsFalse(
                        isContainedRopPending,
                        4693031,
                        @"[In Appendix B: Product Behavior] Implementation does not include a RopPending ROP response if the ROP output buffer contain all queued RopNotify ROP responses. (Exchange 2010 and above follow this behavior.)");
                }
            }
            #endregion

            #endregion
        }