/// <summary>
        /// This ROP logs on to a private mailbox or public folder. 
        /// </summary>
        /// <param name="logonType">This type specifies ongoing action on the private mailbox or public folder.</param>
        /// <param name="logonResponse">The response of this ROP.</param>
        /// <param name="userDN">This string specifies which mailbox to log on to.</param>
        /// <param name="needVerify">Whether need to verify the response.</param>
        /// <returns>The handle of logon object.</returns>
        private uint RopLogon(LogonType logonType, out RopLogonResponse logonResponse, string userDN, bool needVerify)
        {
            this.rawDataValue = null;
            this.responseValue = null;
            this.responseSOHsValue = null;
            userDN += "\0";
            uint insideObjHandle = 0;

            RopLogonRequest logonRequest = new RopLogonRequest()
            {
                RopId = (byte)RopId.RopLogon,
                LogonId = LogonId,
                OutputHandleIndex = (byte)HandleIndex.FirstIndex,
                StoreState = (uint)StoreState.None,

                // Set parameters for public folder logon type.
                LogonFlags = logonType == LogonType.PublicFolder ? (byte)LogonFlags.PublicFolder : (byte)LogonFlags.Private,
                OpenFlags = logonType == LogonType.PublicFolder ? (uint)(OpenFlags.UsePerMDBReplipMapping | OpenFlags.Public) : (uint)OpenFlags.UsePerMDBReplipMapping,

                // Set EssdnSize to 0, which specifies the size of the ESSDN field.
                EssdnSize = logonType == LogonType.PublicFolder ? (ushort)0 : (ushort)Encoding.ASCII.GetByteCount(userDN),
                Essdn = logonType == LogonType.PublicFolder ? null : Encoding.ASCII.GetBytes(userDN),
            };

            this.responseSOHsValue = this.ProcessSingleRop(logonRequest, insideObjHandle, ref this.responseValue, ref this.rawDataValue, RopResponseType.SuccessResponse);
            logonResponse = (RopLogonResponse)this.responseValue;
            if (needVerify)
            {
                this.Site.Assert.AreEqual((uint)RopResponseType.SuccessResponse, logonResponse.ReturnValue, string.Format("Logon Failed! Error: 0x{0:X8}", logonResponse.ReturnValue));
            }

            return this.responseSOHsValue[0][logonResponse.OutputHandleIndex];
        }
        /// <summary>
        /// Logon Mail server.
        /// </summary>
        /// <param name="logonType">Logon Type.</param>
        /// <param name="objHandle">Server response handle.</param>
        /// <param name="openFlags">The possible values are specified in [MS-OXCSTOR]. This structure contains more flags that control the behavior of the logon.</param>
        /// <returns>Logon Response.</returns>
        protected RopLogonResponse Logon(LogonFlags logonType, out uint objHandle, uint openFlags)
        {
            RopLogonRequest logonRequest = new RopLogonRequest();
            object ropResponse = null;

            string userDN = Common.GetConfigurationPropertyValue("AdminUserEssdn", this.Site) + Constants.StringNullTerminated;

            logonRequest.RopId = (byte)RopId.RopLogon;
            logonRequest.LogonId = Constants.CommonLogonId;
            logonRequest.OutputHandleIndex = 0x0;
            logonRequest.StoreState = 0;
            logonRequest.LogonFlags = (byte)logonType;
            logonRequest.OpenFlags = openFlags;

            if (LogonFlags.PublicFolder == logonType)
            {
                logonRequest.EssdnSize = 0;
                logonRequest.Essdn = null;
            }
            else if (LogonFlags.Private == logonType)
            {
                logonRequest.EssdnSize = (ushort)Encoding.ASCII.GetByteCount(userDN);
                logonRequest.Essdn = Encoding.ASCII.GetBytes(userDN);
            }

            this.Adapter.DoRopCall(logonRequest, this.LogonHandle, ref ropResponse, ref this.responseHandles);
            RopLogonResponse logonResponse = (RopLogonResponse)ropResponse;
            objHandle = this.responseHandles[0][logonResponse.OutputHandleIndex];
            this.defaultFolderIds = logonResponse.FolderIds;
            return logonResponse;
        }
        /// <summary>
        /// Compose a Logon ROP request.
        /// </summary>
        /// <returns>Return a Logon ROP request.</returns>
        private RopLogonRequest GetRopLogonRequest()
        {
            RopLogonRequest logonRop = new RopLogonRequest();
            logonRop.RopId = (byte)RopId.RopLogon; // RopId 0XFE indicates RopLogon.
            logonRop.LogonId = ConstValues.LogonId; // The logonId 0x00 is associated with this operation.
            logonRop.OutputHandleIndex = 0x00; // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the output Server Object is stored. 
            string userDN = this.AdminUserDN + "\0"; // A null-terminated string that specifies the DN of the AdminUser who is requesting the connection.
            logonRop.StoreState = 0; // A flags structure. This field MUST be set to 0x00000000.
            logonRop.LogonFlags = 0x01; // Logon to a private mailbox.
            logonRop.OpenFlags = 0x01000000; // For a private-mailbox logon, the USE_PER_MDB_REPLID_MAPPING flag should be set. 
            logonRop.EssdnSize = (ushort)System.Text.Encoding.ASCII.GetByteCount(userDN);
            logonRop.Essdn = System.Text.Encoding.ASCII.GetBytes(userDN);

            return logonRop;
        }
        /// <summary>
        /// Verify the response by sending the ROP RopLogon for the private mailbox.
        /// </summary>
        /// <param name="request">The structure of ROP RopLogon request.</param>
        /// <param name="response">The structure of ROP RopLogon response.</param>
        private void VerifyRopLogonForPrivateMailbox(RopLogonRequest request, RopLogonResponse response)
        {
            if (response.ReturnValue == 0)
            {
                // Add the debug information
                this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R13");

                // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R13
                // If calling RopLogon ROP successfully, indicates the logon session is established.
                this.Site.CaptureRequirement(
                    13,
                    @"[In RopLogon ROP] The RopLogon ROP ([MS-OXCROPS] section 2.2.3.1) establishes a logon session between the client and the server.");

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

                // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R106
                // If calling RopLogon ROP successfully, indicates the Essdn is right identifier to log on to mailbox.
                this.Site.CaptureRequirement(
                    106,
                    @"[In RopLogon ROP Request Buffer] Essdn: In the case of a private mailbox logon, this field contains an ASCII string that uniquely identifies a mailbox to log on to.");

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

                // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R123
                this.Site.CaptureRequirementIfAreEqual<byte>(
                    0x01,
                    (byte)(response.ResponseFlags & (byte)0x01),
                    123,
                    @"[In RopLogon ROP Success Response Buffer for Private Mailbox] [Response Flags] The description of flag Reserved: This bit [Reserved] MUST be set.");

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

                // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R122
                // Check if the flag Reserved is 0x01. 
                Site.CaptureRequirementIfAreEqual<byte>(
                    0x01,
                    (byte)(response.ResponseFlags & (byte)0x01),
                    122,
                    @"[In RopLogon ROP Success Response Buffer for Private Mailbox] [Response Flags] The value of flag Reserved: 0x01.");

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

                // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1062
                this.Site.CaptureRequirementIfAreEqual<byte>(
                    request.LogonFlags,
                    response.LogonFlags,
                    1062,
                    @"[In RopLogon ROP Success Response Buffer for Private Mailbox] LogonFlags: The server returns these flags [Private, Undercover, and Ghostedflags] unchanged from the LogonFlags field of the RopLogon request (section 2.2.1.1.1).");

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

                // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R118
                this.Site.CaptureRequirementIfAreEqual<byte>(
                    request.LogonFlags,
                    response.LogonFlags,
                    118,
                    @"[In RopLogon ROP Success Response Buffer for Private Mailbox] LogonFlags: This field is composed of the Private, Undercover, and Ghosted flags.");

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

                // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R117
                // The RopLogon ROP response structure for public folders is designated
                Site.CaptureRequirement(
                    117,
                    @"[In RopLogon ROP Success Response Buffer for Private Mailbox] The following field values [LogonFlags, FolderIds, Response Flags, ReplId, ReplGuid, Logon Time, GwartTime, StoreState] are included in the RopLogon response only when the Private bit is set in the LogonFlags field of the RopLogon request (section 2.2.1.1.1).");
            }
        }
        /// <summary>
        /// Verify the response by sending the ROP RopLogon for the public folders.
        /// </summary>
        /// <param name="request">The structure of ROP RopLogon request.</param>
        /// <param name="response">The structure of ROP ROPLogonForPublicFolder response.</param>
        private void VerifyRopLogonForPublicFolder(RopLogonRequest request, RopLogonResponse response)
        {
            // The returnValue is 0 to indicate that the response is successful.
            if (response.ReturnValue == 0)
            {
                // Add the debug information
                this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R13");

                // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R13
                this.Site.CaptureRequirementIfAreEqual<uint>(
                    0,
                    response.ReturnValue,
                    13,
                    @"[In RopLogon ROP] The RopLogon ROP ([MS-OXCROPS] section 2.2.3.1) establishes a logon session between the client and the server.");

                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R146, LogonFlags:{0}", response.LogonFlags);

                // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R146
                bool isVerifyR146 = ((LogonFlags)response.LogonFlags & ~(LogonFlags.Private | LogonFlags.PublicFolder | LogonFlags.Ghosted | LogonFlags.Undercover)) == 0;

                Site.CaptureRequirementIfIsTrue(
                    isVerifyR146,
                    146,
                    @"[In RopLogon ROP Success Response Buffer for Public Folders] LogonFlags: This field [LogonFlags] is composed of the Private, Undercover, and Ghosted flags.");

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

                // In the step2 logon a Public Folders.
                // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1071
                Site.CaptureRequirementIfAreEqual<byte>(
                    request.LogonFlags,
                    response.LogonFlags,
                    1071,
                    @"[In RopLogon ROP Success Response Buffer for Public Folders] LogonFlags: The server returns these flags [Private, Undercover, and Ghosted] unchanged from the LogonFlags field of the RopLogon request (section 2.2.1.1.1).");
                #endregion

                Guid perUserGuid = new Guid(response.PerUserGuid);

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

                    // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R1332
                    this.Site.CaptureRequirementIfAreNotEqual<Guid>(
                        Guid.Empty,
                        perUserGuid,
                        1332,
                        @"[In Appendix A: Product Behavior] The implementation does not set the PerUserGuid field to an empty GUID. (<9> Section 2.2.1.1.4: Exchange 2007 does not set the PerUserGuid field to an empty GUID.)");
                }

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

                    // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R163
                    this.Site.CaptureRequirementIfAreEqual<Guid>(
                        Guid.Empty,
                        perUserGuid,
                        163,
                        @"Implementation does set this field [PerUserGuid in RopLogon ROP Success Response Buffer for Public Folders] to an empty GUID (all zeroes). (Exchange 2003, Exchange 2010 and above follow this behavior.)");
                }

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

                // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R3012
                // Check if the LogonFlag is set.
                bool isVerifyR3012 = (response.LogonFlags & (byte)LogonFlags.Private) == (byte)LogonFlags.Private;

                // The server returns the LogonFlags unchanged from the LogonFlag filed of the RopLogon request , So
                // if the response LgonFlag don't contain Private flag, it is not set in the request, then this requirement 
                // will be verified.
                Site.CaptureRequirementIfIsFalse(
                    isVerifyR3012,
                    3012,
                    @"[In RopLogon ROP Success Response Buffer for Public Folders] The success response buffer for public folders is sent only when the Private bit is not set in the LogonFlags field of the RopLogon request (section 2.2.1.1.1).");
            }
            else if (response.ReturnValue == 0x00000478)
            {
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCSTOR_R112");

                // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R112
                bool isVerifyR112 = ((LogonFlags)response.LogonFlags & ~(LogonFlags.Private | LogonFlags.PublicFolder | LogonFlags.Ghosted | LogonFlags.Undercover)) == 0;

                Site.CaptureRequirementIfIsTrue(
                    isVerifyR112,
                    112,
                    @"[In RopLogon ROP Redirect Response Buffer] LogonFlags: This field contains the Private, Undercover, and Ghosted flags.");

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

                // Verify MS-OXCSTOR requirement: MS-OXCSTOR_R115
                bool isVerifyR115 = Common.IsNullTerminatedASCIIStr(response.ServerName);

                Site.CaptureRequirementIfIsTrue(
                    isVerifyR115,
                    115,
                    @"[In RopLogon ROP Redirect Response Buffer] ServerName: The string includes the terminating NULL character.");
            }
        }
        public void MSOXCMSG_S03_TC02_RopSetReadFlagsAsyncEnable()
        {
            this.CheckMapiHttpIsSupported();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);

            #region Call RopLogon to logon specific private mailbox and SUPPORT_PROGRESS flag is set in the OpenFlags field.
            string userDN = Common.GetConfigurationPropertyValue("AdminUserEssdn", this.Site) + "\0";
            RopLogonRequest logonRequest = new RopLogonRequest()
            {
                RopId = (byte)RopId.RopLogon,
                LogonId = CommonLogonId,
                OutputHandleIndex = 0x00, // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the output Server Object is stored. 
                StoreState = 0,
                LogonFlags = (byte)LogonFlags.Private,
                OpenFlags = (uint)OpenFlags.UsePerMDBReplipMapping | 0x20000000,
                EssdnSize = (ushort)Encoding.ASCII.GetByteCount(userDN),
                Essdn = Encoding.ASCII.GetBytes(userDN)
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(logonRequest, this.insideObjHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopLogonResponse logonResponse = (RopLogonResponse)this.response;
            uint objHandle = this.ResponseSOHs[0][logonResponse.OutputHandleIndex];
            #endregion

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

            #region Call RopSaveChangesMessage to save the message created by step 2.
            RopSaveChangesMessageResponse saveChangesMessageResponse = this.SaveMessage(targetMessageHandle, (byte)SaveFlags.ForceSave);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, saveChangesMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            ulong[] messageIds = new ulong[1];
            messageIds[0] = saveChangesMessageResponse.MessageId;
            #endregion

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

            #region Call RopSetReadFlags to change the state of the PidTagMessageFlags property and the WantAsynchronous flag is set in RopSetReadFlags.
            RopSetReadFlagsRequest setReadFlagsRequet = new RopSetReadFlagsRequest
            {
                RopId = (byte)RopId.RopSetReadFlags,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                WantAsynchronous = 0x01,
                ReadFlags = (byte)ReadFlags.ClearReadFlag,
                MessageIds = messageIds,
                MessageIdCount = Convert.ToUInt16(messageIds.Length)
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(setReadFlagsRequet, folderHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);

            #region Verify MS-OXCMSG_R1705, MS-OXCMSG_R1706
            if (Common.IsRequirementEnabled(1705, this.Site))
            {
                // Add the debug information
                this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R1705, server returns response type is {0}.", this.response.GetType());

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R1705
                bool isVerifiedR1705 = this.response is RopSetReadFlagsResponse;

                this.Site.CaptureRequirementIfIsTrue(
                    isVerifiedR1705,
                    1705,
                    @"[In Appendix A: Product Behavior] Implementation does return a RopSetReadFlags ROP response if the WantAsynchronous flag is nonzero. (Exchange 2007 and above follow this behavior.)");
            }

            if (Common.IsRequirementEnabled(1706, this.Site))
            {
                // Add the debug information
                this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R1706,server returns response type is {0}.", this.response.GetType());

                this.Site.CaptureRequirementIfIsNotInstanceOfType(
                    this.response,
                    typeof(RopProgressResponse),
                    1706,
                    @"[In Appendix A: Product Behavior] Implementation doesn't return a RopProgress ROP response instead if the WantAsynchronous flag is nonzero. (Exchange 2007 and above follow this behavior.)");
            }
            #endregion
            #endregion

            #region Call RopRelease to release all resources.
            this.ReleaseRop(targetMessageHandle);
            this.ReleaseRop(folderHandle);
            #endregion
        }
        public void MSOXCMSG_S01_TC11_CreateMessageWithoutPermissions()
        {
            this.CheckMapiHttpIsSupported();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);
            string commonUser = Common.GetConfigurationPropertyValue("CommonUser", Site);
            string commonUserPassword = Common.GetConfigurationPropertyValue("CommonUserPassword", Site);
            string commonUserEssdn = Common.GetConfigurationPropertyValue("CommonUserEssdn", Site);

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

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

            #region Add Read permission to "CommonUser" on inbox folder.
            // Add folder visible permission for the inbox.
            uint pidTagMemberRights = (uint)PidTagMemberRights.FolderVisible | (uint)PidTagMemberRights.ReadAny;
            this.AddPermission(commonUserEssdn, pidTagMemberRights, openedFolderHandle);
            #endregion

            #region Call RopLogon to logon the private mailbox with "CommonUser"
            this.rawData = null;
            this.insideObjHandle = 0;
            this.response = null;
            this.ResponseSOHs = null;
            this.MSOXCMSGAdapter.RpcDisconnect();
            this.MSOXCMSGAdapter.Reset();
            this.MSOXCMSGAdapter.RpcConnect(ConnectionType.PrivateMailboxServer, commonUser, commonUserPassword, commonUserEssdn);

            string userDN = Common.GetConfigurationPropertyValue("AdminUserEssdn", this.Site) + "\0";
            RopLogonRequest logonRequest = new RopLogonRequest()
            {
                RopId = (byte)RopId.RopLogon,
                LogonId = CommonLogonId,
                OutputHandleIndex = 0x00, // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the output Server Object is stored. 
                StoreState = 0,
                LogonFlags = 0x01, // Logon to a private mailbox
                OpenFlags = (uint)OpenFlags.UsePerMDBReplipMapping, // Requesting admin access to the mail box
                EssdnSize = (ushort)Encoding.ASCII.GetByteCount(userDN),
                Essdn = Encoding.ASCII.GetBytes(userDN)
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(logonRequest, this.insideObjHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            logonResponse = (RopLogonResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, logonResponse.ReturnValue, "Call RopLogon should success.");

            uint objHandle = this.ResponseSOHs[0][logonResponse.OutputHandleIndex];
            #endregion

            #region Call RopCreateMessage to create new Message object in folder without permission.
            RopCreateMessageRequest createMessageRequest = new RopCreateMessageRequest()
            {
                RopId = (byte)RopId.RopCreateMessage,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                OutputHandleIndex = CommonOutputHandleIndex,
                CodePageId = 0x0FFF, // Code page of Logon object is used
                FolderId = logonResponse.FolderIds[4], // Create a message in INBOX which root is mailbox 
                AssociatedFlag = 0x00 // NOT an FAI message
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(createMessageRequest, this.insideObjHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopCreateMessageResponse createMessageResponse = (RopCreateMessageResponse)this.response;
            
            if(Common.IsRequirementEnabled(3017,this.Site))
            {
                // Add the debug information
                this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R3017");

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R3017
                this.Site.CaptureRequirementIfAreEqual<uint>(
                    0x000004FF,
                    createMessageResponse.ReturnValue,
                    3017,
                    @"[In Appendix A: Product Behavior] [ecNoCreateRight (0x000004FF)] The user does not have permissions to create this message [RopCreateMessage]. (<24> Section 3.2.5.2:  Exchange 2007 and Exchange 2010 follow this behavior.)");
            }

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R3018
                this.Site.CaptureRequirementIfAreEqual<uint>(
                    0x80070005,
                    createMessageResponse.ReturnValue,
                    3018,
                    @"[In Appendix A: Product Behavior] [ecAccessDenied (0x80070005)] The user does not have permissions to create this message [RopCreateMessage]. (Exchange 2013 and above follow this behavior.)");
            }
            #endregion
        }
        public void MSOXCMSG_S05_TC08_RopOpenMessageWithoutRight()
        {
            this.CheckMapiHttpIsSupported();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);

            string commonUser = Common.GetConfigurationPropertyValue("CommonUser", Site);
            string commonUserPassword = Common.GetConfigurationPropertyValue("CommonUserPassword", Site);
            string commonUserEssdn = Common.GetConfigurationPropertyValue("CommonUserEssdn", Site);
            uint pidTagMemberRights;

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

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

            #region Call RopCreateFolder to create a new subfolder.
            ulong thirdSubfolderId;
            uint thirdSubFolderHandle = this.CreateSubFolder(openedInboxFolderHandle, out thirdSubfolderId);
            LongTermId thirdSubfolderLongTermID = this.GetLongTermIdFormID(thirdSubfolderId, this.insideObjHandle);
            #endregion

            #region Call RopCreateMessage and RopSaveChangesMessage to create a Message object in subfolder created.
            // Create a message in InBox
            this.MessageHandle = this.CreatedMessage(thirdSubfolderId, this.insideObjHandle);

            RopSaveChangesMessageResponse saveChangesMessageResponse = this.SaveMessage(this.MessageHandle, (byte)SaveFlags.KeepOpenReadWrite);
            ulong thirdMessageId = saveChangesMessageResponse.MessageId;
            LongTermId thirdMessageLongTermID = this.GetLongTermIdFormID(thirdMessageId, this.insideObjHandle);
            this.ReleaseRop(this.MessageHandle);
            #endregion

            #region Add Read permission to "CommonUser" on inbox folder.
            // Add folder visible permission for the inbox.
            pidTagMemberRights = (uint)PidTagMemberRights.FolderVisible | (uint)PidTagMemberRights.ReadAny;
            this.AddPermission(commonUserEssdn, pidTagMemberRights, openedInboxFolderHandle);
            #endregion

            #region Add Read and write permission to "CommonUser" on subfolder
            pidTagMemberRights = (uint)PidTagMemberRights.FolderVisible;
            this.AddPermission(commonUserEssdn, pidTagMemberRights, thirdSubFolderHandle);
            #endregion

            #region Call RopLogon to logon the private mailbox with "CommonUser"
            this.rawData = null;
            this.insideObjHandle = 0;
            this.response = null;
            this.ResponseSOHs = null;
            this.MSOXCMSGAdapter.RpcDisconnect();
            this.MSOXCMSGAdapter.Reset();
            this.MSOXCMSGAdapter.RpcConnect(ConnectionType.PrivateMailboxServer, commonUser, commonUserPassword, commonUserEssdn);

            string userDN = Common.GetConfigurationPropertyValue("AdminUserEssdn", this.Site) + "\0";
            RopLogonRequest logonRequest = new RopLogonRequest()
            {
                RopId = (byte)RopId.RopLogon,
                LogonId = CommonLogonId,
                OutputHandleIndex = 0x00, // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the output Server Object is stored. 
                StoreState = 0,
                LogonFlags = 0x01, // Logon to a private mailbox
                OpenFlags = (uint)OpenFlags.UsePerMDBReplipMapping, // Requesting admin access to the mail box
                EssdnSize = (ushort)Encoding.ASCII.GetByteCount(userDN),
                Essdn = Encoding.ASCII.GetBytes(userDN)
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(logonRequest, this.insideObjHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            logonResponse = (RopLogonResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, logonResponse.ReturnValue, "Call RopLogon should success.");

            uint objHandle = this.ResponseSOHs[0][logonResponse.OutputHandleIndex];
            #endregion

            #region Call RopOpenMessage to open a message that the user does not have rights to the message.
            thirdSubfolderId = this.GetObjectIdFormLongTermID(thirdSubfolderLongTermID, objHandle);
            thirdMessageId = this.GetObjectIdFormLongTermID(thirdMessageLongTermID, objHandle);

            RopOpenMessageRequest openMessageRequest = new RopOpenMessageRequest()
            {
                RopId = (byte)RopId.RopOpenMessage,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                OutputHandleIndex = CommonOutputHandleIndex,
                CodePageId = 0x0FFF, // Code page of Logon object is used
                FolderId = thirdSubfolderId,
                OpenModeFlags = (byte)MessageOpenModeFlags.ReadWrite,
                MessageId = thirdMessageId
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(openMessageRequest, objHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopOpenMessageResponse openMessageResponse = (RopOpenMessageResponse)this.response;

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R324
            this.Site.CaptureRequirementIfAreNotEqual<uint>(
                TestSuiteBase.Success,
                openMessageResponse.ReturnValue,
                324,
                @"[in Receiving a RopOpenMessage ROP Request] RopOpenMessage MUST NOT succeed if the client has insufficient access rights to the folder in which the Message object is stored.");
            
            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R2184");
        
            // Verify MS-OXCMSG requirement: MS-OXCMSG_R2184
            this.Site.CaptureRequirementIfAreEqual<uint>(
                0x80070005,
                openMessageResponse.ReturnValue,
                2184,
                @"[In Receiving a RopOpenMessage ROP Request] [ecAccessDenied(0x80070005)] The user does not have rights to the message.");
            #endregion
            #endregion

            #region Call RopLogon to logon the private mailbox with administrator
            this.rawData = null;
            this.insideObjHandle = 0;
            this.response = null;
            this.ResponseSOHs = null;
            this.MSOXCMSGAdapter.RpcDisconnect();
            this.MSOXCMSGAdapter.Reset();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);
            logonResponse = this.Logon(LogonType.Mailbox, out this.insideObjHandle);
            openedInboxFolderHandle = this.OpenSpecificFolder(logonResponse.FolderIds[4], this.insideObjHandle);
            #endregion

            #region Call RopDeleteFolder to delete the subfolder created
            thirdSubfolderId = this.GetObjectIdFormLongTermID(thirdSubfolderLongTermID, this.insideObjHandle);
            RopDeleteFolderRequest deleteFolderRequest = new RopDeleteFolderRequest()
            {
                RopId = (byte)RopId.RopDeleteFolder,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                DeleteFolderFlags = (byte)DeleteFolderFlags.DeleteHardDelete | (byte)DeleteFolderFlags.DelMessages,
                FolderId = thirdSubfolderId
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(deleteFolderRequest, openedInboxFolderHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopDeleteFolderResponse deleteFolderresponse = (RopDeleteFolderResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, deleteFolderresponse.ReturnValue, "Call RopDeleteFolder should success.");
            #endregion
        }
        public void MSOXCMSG_S05_TC07_RopOpenMessageAsBestAccess()
        {
            this.CheckMapiHttpIsSupported();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);

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

            List<PropertyObj> propertyValues = new List<PropertyObj>
            {
                new PropertyObj(PropertyNames.PidTagNormalizedSubject, Common.GetBytesFromUnicodeString(TestDataOfPidTagNormalizedSubject))
            };
            string commonUser = Common.GetConfigurationPropertyValue("CommonUser", Site);
            string commonUserPassword = Common.GetConfigurationPropertyValue("CommonUserPassword", Site);
            string commonUserEssdn = Common.GetConfigurationPropertyValue("CommonUserEssdn", Site);
            uint pidTagMemberRights;
            RopSetPropertiesResponse rpmSetResponse;

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

            #region Call RopCreateFolder to create a subfolder in inbox folder.
            ulong firstSubfolderId;
            uint firstSubFolderHandle = this.CreateSubFolder(openedInboxFolderHandle, out firstSubfolderId);
            LongTermId firstSubfolderLongTermID = this.GetLongTermIdFormID(firstSubfolderId, this.insideObjHandle);
            #endregion

            #region Call RopCreateMessage and RopSaveChangesMessage to create a Message object in subfolder created by step 3.
            // Create a message in InBox
            this.MessageHandle = this.CreatedMessage(firstSubfolderId, this.insideObjHandle);

            RopSaveChangesMessageResponse saveChangesMessageResponse = this.SaveMessage(this.MessageHandle, (byte)SaveFlags.KeepOpenReadWrite);
            ulong firstMessageId = saveChangesMessageResponse.MessageId;
            LongTermId firstMessageLongTermID = this.GetLongTermIdFormID(firstMessageId, this.insideObjHandle);
            this.ReleaseRop(this.MessageHandle);
            #endregion

            #region Call RopCreateFolder to create a new subfolder.
            ulong secondSubfolderId;
            System.Threading.Thread.Sleep(1); // Sleep 1 millisecond to generate different named folder
            uint secondSubFolderHandle = this.CreateSubFolder(openedInboxFolderHandle, out secondSubfolderId);
            LongTermId secondSubfolderLongTermID = this.GetLongTermIdFormID(secondSubfolderId, this.insideObjHandle);
            #endregion

            #region Call RopCreateMessage and RopSaveChangesMessage to create a Message object in subfolder created by step 5.
            // Create a message in InBox
            this.MessageHandle = this.CreatedMessage(secondSubfolderId, this.insideObjHandle);

            saveChangesMessageResponse = this.SaveMessage(this.MessageHandle, (byte)SaveFlags.KeepOpenReadWrite);
            ulong secondMessageId = saveChangesMessageResponse.MessageId;
            LongTermId secondMessageLongTermID = this.GetLongTermIdFormID(secondMessageId, this.insideObjHandle);
            this.ReleaseRop(this.MessageHandle);
            #endregion

            #region Add Read permission to "CommonUser" on inbox folder.
            // Add folder visible permission for the inbox.
            pidTagMemberRights = (uint)PidTagMemberRights.FolderVisible | (uint)PidTagMemberRights.ReadAny;
            this.AddPermission(commonUserEssdn, pidTagMemberRights, openedInboxFolderHandle);
            #endregion

            #region Add Read permission to "CommonUser" on subfolder created by step 3.
            // Add folder visible permission for the subfolder1.
            pidTagMemberRights = (uint)PidTagMemberRights.FolderVisible | (uint)PidTagMemberRights.ReadAny;
            this.AddPermission(commonUserEssdn, pidTagMemberRights, firstSubFolderHandle);
            #endregion

            #region Add Read and write permission to "CommonUser" on subfolder by step 5
            pidTagMemberRights = (uint)PidTagMemberRights.FolderVisible | (uint)PidTagMemberRights.ReadAny | (uint)PidTagMemberRights.EditAny;
            this.AddPermission(commonUserEssdn, pidTagMemberRights, secondSubFolderHandle);
            #endregion

            #region Call RopLogon to logon the private mailbox with "CommonUser"
            this.rawData = null;
            this.insideObjHandle = 0;
            this.response = null;
            this.ResponseSOHs = null;
            this.MSOXCMSGAdapter.RpcDisconnect();
            this.MSOXCMSGAdapter.Reset();
            this.MSOXCMSGAdapter.RpcConnect(ConnectionType.PrivateMailboxServer, commonUser, commonUserPassword, commonUserEssdn);

            string userDN = Common.GetConfigurationPropertyValue("AdminUserEssdn", this.Site) + "\0";
            RopLogonRequest logonRequest = new RopLogonRequest()
            {
                RopId = (byte)RopId.RopLogon,
                LogonId = CommonLogonId,
                OutputHandleIndex = 0x00, // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the output Server Object is stored. 
                StoreState = 0,
                LogonFlags = 0x01, // Logon to a private mailbox
                OpenFlags = (uint)OpenFlags.UsePerMDBReplipMapping, // Requesting admin access to the mail box
                EssdnSize = (ushort)Encoding.ASCII.GetByteCount(userDN),
                Essdn = Encoding.ASCII.GetBytes(userDN),
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(logonRequest, this.insideObjHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            logonResponse = (RopLogonResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, logonResponse.ReturnValue, "Call RopLogon should success.");

            uint objHandle = this.ResponseSOHs[0][logonResponse.OutputHandleIndex];
            #endregion

            #region Call RopOpenMessage which OpenModeFlags is BestAccess to open the message in subfolder created by step 3.
            firstSubfolderId = this.GetObjectIdFormLongTermID(firstSubfolderLongTermID, objHandle);
            firstMessageId = this.GetObjectIdFormLongTermID(firstMessageLongTermID, objHandle);

            uint openedMessageBestReadOnlyHandle = this.OpenSpecificMessage(firstSubfolderId, firstMessageId, objHandle, MessageOpenModeFlags.BestAccess);
            #endregion

            #region Call RopSetProperties to set PidTagNormalizedSubject property of message in subfolder created by step 3.
            List<TaggedPropertyValue> taggedPropertyValueList = new List<TaggedPropertyValue>();

            int valueSize = 0;
            foreach (PropertyObj propertyObj in propertyValues)
            {
                PropertyTag propertyTag = new PropertyTag
                {
                    PropertyId = (ushort)propertyObj.PropertyID,
                    PropertyType = (ushort)propertyObj.ValueTypeCode
                };

                TaggedPropertyValue taggedPropertyValue = new TaggedPropertyValue
                {
                    PropertyTag = propertyTag,
                    Value = (byte[])propertyObj.Value
                };
                valueSize += taggedPropertyValue.Size();

                taggedPropertyValueList.Add(taggedPropertyValue);
            }

            RopSetPropertiesRequest rpmSetRequest = new RopSetPropertiesRequest()
            {
                RopId = (byte)RopId.RopSetProperties,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                PropertyValueCount = (ushort)taggedPropertyValueList.Count,
                PropertyValueSize = (ushort)(valueSize + 2),
                PropertyValues = taggedPropertyValueList.ToArray(),
            };
            uint returnValue;
            this.response = null;
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(rpmSetRequest, openedMessageBestReadOnlyHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None, out returnValue);
            
            if(Common.IsRequirementEnabled(3009,this.Site))
            {
                rpmSetResponse = (RopSetPropertiesResponse)this.response;

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R3009
                this.Site.CaptureRequirementIfAreEqual<uint>(
                    TestSuiteBase.Success,
                    rpmSetResponse.ReturnValue,
                    3009,
                    @"[In Appendix A: Product Behavior] BestAccess is read/write if the user don't have write permissions. (<12> Section 2.2.3.1.1:  Exchange 2010 and above follow this behavior.)");
            }

            if(Common.IsRequirementEnabled(3010,this.Site))
            {
                if (this.response == null)
                {
                    Site.Assert.AreNotEqual<uint>(0, returnValue, "Call RopSetProperties should fail.");
                }
                else
                {
                    rpmSetResponse = (RopSetPropertiesResponse)this.response;
                    Site.Assert.AreNotEqual<uint>(0, rpmSetResponse.ReturnValue, "Call RopSetProperties should fail.");
                }

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R661
                // Because when call RopSetProperties to set property of specified Message object that opened by read-only, server will fail and return error code.
                // R661 will be verified.
                this.Site.CaptureRequirement(
                    3010,
                    @"[In Appendix A: Product Behavior] BestAccess is read-only if the user don't have write permissions. (Exchange 2007 follows this behavior.)");
            }
            #endregion

            #region Call RopRelease to release created message in subfolder created by step 3.
            this.ReleaseRop(openedMessageBestReadOnlyHandle);
            #endregion

            #region Call RopOpenMessage which OpenModeFlags is BestAccess to open the message in subfolder created by step 5.
            secondSubfolderId = this.GetObjectIdFormLongTermID(secondSubfolderLongTermID, objHandle);
            secondMessageId = this.GetObjectIdFormLongTermID(secondMessageLongTermID, objHandle);
            uint openedMessageBestReadWrietHandle = this.OpenSpecificMessage(secondSubfolderId, secondMessageId, objHandle, MessageOpenModeFlags.BestAccess);
            #endregion

            #region Call RopSetProperties to set PidTagSubjectPrefix property of message in subfolder created by step 5.
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(rpmSetRequest, openedMessageBestReadWrietHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            rpmSetResponse = (RopSetPropertiesResponse)this.response;

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R665
            this.Site.CaptureRequirementIfAreEqual<uint>(
                TestSuiteBase.Success,
                rpmSetResponse.ReturnValue,
                665,
                @"[In RopOpenMessage ROP Request Buffer] [OpenModeFlags] [BestAccess (0x03)] Open for read/write if the user has write permissions for the folder.");
            #endregion

            #region Call RopRelease to release created message in subfolder created by step 5.
            this.ReleaseRop(openedMessageBestReadWrietHandle);
            #endregion

            #region Call RopLogon to logon the private mailbox with administrator
            this.rawData = null;
            this.insideObjHandle = 0;
            this.response = null;
            this.ResponseSOHs = null;
            this.MSOXCMSGAdapter.RpcDisconnect();
            this.MSOXCMSGAdapter.Reset();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);
            logonResponse = this.Logon(LogonType.Mailbox, out this.insideObjHandle);
            openedInboxFolderHandle = this.OpenSpecificFolder(logonResponse.FolderIds[4], this.insideObjHandle);
            #endregion

            #region Call RopDeleteFolder to delete the subfolder created by 3.
            firstSubfolderId = this.GetObjectIdFormLongTermID(firstSubfolderLongTermID, this.insideObjHandle);
            RopDeleteFolderRequest deleteFolderRequest = new RopDeleteFolderRequest()
            {
                RopId = (byte)RopId.RopDeleteFolder,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                DeleteFolderFlags = (byte)DeleteFolderFlags.DeleteHardDelete | (byte)DeleteFolderFlags.DelMessages,
                FolderId = firstSubfolderId
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(deleteFolderRequest, openedInboxFolderHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopDeleteFolderResponse deleteFolderresponse = (RopDeleteFolderResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, deleteFolderresponse.ReturnValue, "Call RopDeleteFolder should success.");
            #endregion

            #region Call RopDeleteFolder to delete the subfolder created by 5
            secondSubfolderId = this.GetObjectIdFormLongTermID(secondSubfolderLongTermID, this.insideObjHandle);
            deleteFolderRequest.FolderId = secondSubfolderId;
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(deleteFolderRequest, openedInboxFolderHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            deleteFolderresponse = (RopDeleteFolderResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, deleteFolderresponse.ReturnValue, "Call RopDeleteFolder should success.");
            #endregion

            this.ReleaseRop(openedInboxFolderHandle);
        }
        /// <summary>
        /// Call RopLogon to establish a logon session between the client and the server.
        /// </summary>
        /// <param name="logonType">LogonType value</param>
        /// <param name="objHandle">Unsigned integer value</param>
        /// <returns>Return RopLogonResponse</returns>
        protected RopLogonResponse Logon(LogonType logonType, out uint objHandle)
        {
            RopLogonRequest logonRequest = new RopLogonRequest()
            {
                RopId = (byte)RopId.RopLogon, // RopId 0XFE indicates RopLogon
                LogonId = CommonLogonId, // The logonId 0x00 is associated with this operation.
                OutputHandleIndex = 0x00 // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the output Server Object is stored. 
            };
            string userDN = Common.GetConfigurationPropertyValue("AdminUserEssdn", this.Site) + "\0";

            logonRequest.StoreState = 0;

            if (LogonType.PublicFolder == logonType)
            {
                logonRequest.LogonFlags = 0x00; // Logon to public folders
                logonRequest.OpenFlags = 0x01000002;
                logonRequest.EssdnSize = 0;
                logonRequest.Essdn = null;
            }
            else
            {
                logonRequest.LogonFlags = 0x01; // Logon to a private mailbox
                logonRequest.OpenFlags = 0x01000000;
                logonRequest.EssdnSize = (ushort)Encoding.ASCII.GetByteCount(userDN);
                logonRequest.Essdn = Encoding.ASCII.GetBytes(userDN);
            }
        
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(logonRequest, this.insideObjHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);

            RopLogonResponse logonResponse = (RopLogonResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, logonResponse.ReturnValue, "Call RopLogon should success.");
            objHandle = this.ResponseSOHs[0][logonResponse.OutputHandleIndex];
            return logonResponse;
        }