A driver for property initialization.
        public void MSOXCMSG_S09_TC01_RopOpenEmbeddedMessageSuccessfully()
        {
            this.CheckMapiHttpIsSupported();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);

            // Set property size
            int size = 0;

            TaggedPropertyValue[] taggedPropertyValueArray = this.CreateMessageTaggedPropertyValueArrays(out size, PidTagAttachMethodFlags.afEmbeddedMessage);

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

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

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

            #region Call RopSetProperties to set PidTagAttachMethod property, that is the attachment is the embedded attachment.
            RopSetPropertiesRequest setPropertiesRequest = new RopSetPropertiesRequest()
            {
                RopId              = (byte)RopId.RopSetProperties,
                LogonId            = CommonLogonId,          // The logonId 0x00 is associated with RopSetProperties.
                InputHandleIndex   = CommonInputHandleIndex, // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the input Server Object is stored.
                PropertyValueSize  = (ushort)(size + 2),
                PropertyValueCount = (ushort)taggedPropertyValueArray.Length,
                PropertyValues     = taggedPropertyValueArray
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(setPropertiesRequest, attachmentHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopSetPropertiesResponse setPropertiesResponse = (RopSetPropertiesResponse)this.response;
            Site.Assert.AreEqual <uint>(TestSuiteBase.Success, setPropertiesResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopGetPropertiesSpecific to get property PidTagAttachMethod of created Attachment
            List <PropertyTag> tagArray = new List <PropertyTag>
            {
                PropertyHelper.PropertyTagDic[PropertyNames.PidTagAttachMethod]
            };

            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse;
            getPropertiesSpecificResponse = this.GetSpecificPropertiesOfMessage(attachmentHandle, tagArray);
            List <PropertyObj> pts = PropertyHelper.GetPropertyObjFromBuffer(tagArray.ToArray(), getPropertiesSpecificResponse);

            // Parse property response get Property Value to verify test  case requirement
            PropertyObj pidTagAttachMethod = PropertyHelper.GetPropertyByName(pts, PropertyNames.PidTagAttachMethod);
            #endregion

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R596
            this.Site.CaptureRequirementIfAreEqual <int>(
                0x00000005,
                Convert.ToInt32(pidTagAttachMethod.Value),
                596,
                @"[In PidTagAttachMethod Property] [afEmbeddedMessage (0x00000005)] The attachment is an embedded message that is accessed via the RopOpenEmbeddedMessage ROP ([MS-OXCROPS] section 2.2.6.16).");

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

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

            #region Call RopOpenEmbeddedMessage with OpenModeFlags set to 0x02 to create the attachment if it doesn't exist, and expect to get a successful response
            RopOpenEmbeddedMessageRequest openEmbeddedMessageRequest = new RopOpenEmbeddedMessageRequest()
            {
                RopId             = (byte)RopId.RopOpenEmbeddedMessage,
                LogonId           = CommonLogonId,           // The logonId 0x00 is associated with RopOpenEmbeddedMessage.
                InputHandleIndex  = CommonInputHandleIndex,  // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the input Server Object is stored.
                OutputHandleIndex = CommonOutputHandleIndex, // This index specifies the location 0x01 in the Server Object Handle Table where the handle for the output Server Object is stored.
                CodePageId        = 0x0FFF,                  // Code page of Logon object is used
                OpenModeFlags     = 0x02                     // Create the attachment if it does not already exist and open the message for both reading and writing
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(openEmbeddedMessageRequest, attachmentHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopOpenEmbeddedMessageResponse openEmbeddedMessageResponse = (RopOpenEmbeddedMessageResponse)this.response;
            Site.Assert.AreEqual <uint>(TestSuiteBase.Success, openEmbeddedMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            uint embeddedMessageHandle = this.ResponseSOHs[0][openEmbeddedMessageResponse.OutputHandleIndex];
            #endregion

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

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R913
            // The embedded message hasn't been created, so MS-OXCMSG_R913 can be verified if the response of calling RopOpenEmbeddedMessage with OpenModeFlags set to 0x02 is successful.
            this.Site.CaptureRequirementIfAreEqual <uint>(
                TestSuiteBase.Success,
                openEmbeddedMessageResponse.ReturnValue,
                913,
                @"[In RopOpenEmbeddedMessage ROP Request Buffer] [OpenModeFlags] [Create (0x02)] Create the attachment if it does not already exist and open the message for both reading and writing.");

            #region Call RopRelease to release the embedded message
            this.ReleaseRop(embeddedMessageHandle);
            #endregion

            #region Call RopOpenEmbeddedMessage with OpenModeFlags set to 0x00 to open the embedded message as read-only.
            openEmbeddedMessageRequest.CodePageId    = 0x0FFF; // Code page of Logon object is used
            openEmbeddedMessageRequest.OpenModeFlags = 0x00;   // Open the message as read-only.
            this.ResponseSOHs           = this.MSOXCMSGAdapter.DoRopCall(openEmbeddedMessageRequest, attachmentHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            openEmbeddedMessageResponse = (RopOpenEmbeddedMessageResponse)this.response;
            Site.Assert.AreEqual <uint>(TestSuiteBase.Success, openEmbeddedMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            embeddedMessageHandle = this.ResponseSOHs[0][openEmbeddedMessageResponse.OutputHandleIndex];
            #endregion

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R881
            // MS-OXCMSG_R881 can be verified when the handle returned from calling RopOpenEmbeddedMessage is not null.
            this.Site.CaptureRequirementIfIsNotNull(
                embeddedMessageHandle,
                881,
                @"[In RopOpenEmbeddedMessage ROP] The RopOpenEmbeddedMessage ROP ([MS-OXCROPS] section 2.2.6.16) retrieves a handle to a Message object from the given Attachment object.");

            #region Call RopModifyRecipients to add recipient to the read-only embedded message and expect to get the failure response
            // Initialize TestUser1
            PropertyTag[]             propertyTag        = this.CreateRecipientColumns();
            List <ModifyRecipientRow> modifyRecipientRow = new List <ModifyRecipientRow>
            {
                this.CreateModifyRecipientRow(TestUser1, 0)
            };

            RopModifyRecipientsResponse modifyRecipientsResponse;
            this.AddRecipients(modifyRecipientRow, embeddedMessageHandle, propertyTag, out modifyRecipientsResponse);
            #endregion

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R3014
                // The response of RopModifyRecipients is not successful because the embedded message is opened as read-only, so MS-OXCMSG_R3014 can be verified.
                this.Site.CaptureRequirementIfAreNotEqual <uint>(
                    TestSuiteBase.Success,
                    modifyRecipientsResponse.ReturnValue,
                    3014,
                    @"[In Appendix A: Product Behavior] [OpenModeFlags] [ReadOnly (0x00)] Message will be opened as read only. (Exchange 2007 follows this behavior.)");
            }

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

                // Verify MS-OXCMSG requirement: MS-OXCMSG_R3013
                // The response of RopModifyRecipients is successful because the embedded message is opened as read/write, so MS-OXCMSG_R3013 can be verified.
                this.Site.CaptureRequirementIfAreEqual <uint>(
                    TestSuiteBase.Success,
                    modifyRecipientsResponse.ReturnValue,
                    3013,
                    @"[In Appendix A: Product Behavior]  [OpenModeFlags] [ReadOnly (0x00)] Message will be opened as read/write. (&lt;17&gt; Section 2.2.3.16.1:  Exchange 2010, Exchange 2013, Exchange 2016 and Exchange 2019 Preview  follow this behavior.)");
            }

            #region Call RopRelease to release the embedded message.
            this.ReleaseRop(embeddedMessageHandle);
            #endregion

            #region Call RopOpenEmbeddedMessage with OpenModeFlags set to 0x01 to open the embedded message as read/write
            openEmbeddedMessageRequest.InputHandleIndex = 0x00;
            openEmbeddedMessageRequest.OpenModeFlags    = 0x01; // Open the message for both reading and writing.
            this.ResponseSOHs           = this.MSOXCMSGAdapter.DoRopCall(openEmbeddedMessageRequest, attachmentHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            openEmbeddedMessageResponse = (RopOpenEmbeddedMessageResponse)this.response;
            embeddedMessageHandle       = this.ResponseSOHs[0][openEmbeddedMessageResponse.OutputHandleIndex];
            #endregion

            #region Call RopModifyRecipients to add recipient to the read/write embedded message and expect to get the successful response.
            this.AddRecipients(modifyRecipientRow, embeddedMessageHandle, propertyTag, out modifyRecipientsResponse);
            Site.Assert.AreEqual <uint>(TestSuiteBase.Success, modifyRecipientsResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R912
            // The response of RopModifyRecipients is success because the embedded message is opened as read/write, so MS-OXCMSG_R912 can be verified.
            this.Site.CaptureRequirementIfAreEqual <uint>(
                TestSuiteBase.Success,
                modifyRecipientsResponse.ReturnValue,
                912,
                @"[In RopOpenEmbeddedMessage ROP Request Buffer] [OpenModeFlags] [ReadWrite (0x01)] Message will be opened for both reading and writing.");

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

            byte[] rawData = null;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            return(propertyList);
        }
        public void MSOXCMSG_S02_TC01_SetAndGetMessageStatus()
        {
            this.CheckMapiHttpIsSupported();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);

            List <PropertyTag> propertyTags = new List <PropertyTag>
            {
                PropertyHelper.PropertyTagDic[PropertyNames.PidTagMessageStatus],
                PropertyHelper.PropertyTagDic[PropertyNames.PidTagChangeKey],
                PropertyHelper.PropertyTagDic[PropertyNames.PidTagLastModificationTime]
            };

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

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

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

            #region Call RopRelease to release all resources.
            this.ReleaseRop(targetMessageHandle);
            #endregion

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

            #region Call RopGetPropertiesSpecific to get the PidTagMessageStatus,PidTagChangeKey and PidTagLastModificationTime property before set MessagStatus.
            List <PropertyObj> ps = this.GetSpecificPropertiesOfMessage(logonResponse.FolderIds[4], saveChangesMessageResponse.MessageId, this.insideObjHandle, propertyTags);
            PropertyObj        pidTagMessageStatusBeforeSet        = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagMessageStatus);
            PropertyObj        pidTagChangeKeyBeforeSet            = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagChangeKey);
            PropertyObj        pidTagLastModificationTimeBeforeSet = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagLastModificationTime);
            #endregion

            #region Call RopSetMessageStatus to set the MessageStatusFlags property of specific message to 0x00001000.
            RopSetMessageStatusRequest setMessageStatusRequest = new RopSetMessageStatusRequest()
            {
                RopId              = (byte)RopId.RopSetMessageStatus,
                LogonId            = CommonLogonId,
                InputHandleIndex   = CommonInputHandleIndex,
                MessageId          = saveChangesMessageResponse.MessageId,
                MessageStatusFlags = (uint)MessageStatusFlags.MsRemoteDownload,
                MessageStatusMask  = (uint)MessageStatusFlags.MsInConflict | (uint)MessageStatusFlags.MsRemoteDownload | (uint)MessageStatusFlags.MsRemoteDelete
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(setMessageStatusRequest, folderHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopSetMessageStatusResponse setMessageStatusResponse = (RopSetMessageStatusResponse)this.response;

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R773
            this.Site.CaptureRequirementIfAreEqual <uint>(
                TestSuiteBase.Success,
                setMessageStatusResponse.ReturnValue,
                773,
                @"[In RopSetMessageStatus ROP] The RopSetMessageStatus ROP ([MS-OXCROPS] section 2.2.6.8) sets the PidTagMessageStatus property ([MS-OXPROPS] section 2.798) on a message in a folder without the need to open or save the Message object.");

            // Because the MS-OXCMSG_R773 has been captured and verify that the RopSetMessthatageStatus ROP sets the PidTagMessageStatus property.
            // So MS-OXCMSG_R549 can be captured directly.
            this.Site.CaptureRequirement(
                549,
                @"[In Sending a RopSetProperties ROP Request] Instead, the client calls the RopSetMessageStatus ROP ([MS-OXCROPS] section 2.2.6.8), as specified in section 2.2.3.8.");
            #endregion
            #endregion

            #region Call RopGetMessageStatus to get the message status of specific message created step 2.
            RopGetMessageStatusRequest getMessageStatusRequest = new RopGetMessageStatusRequest()
            {
                RopId            = (byte)RopId.RopGetMessageStatus,
                LogonId          = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                MessageId        = saveChangesMessageResponse.MessageId
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getMessageStatusRequest, folderHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);

            // The response buffers for RopGetMessageStatus are the same as those for RopSetMessageStatus.
            RopSetMessageStatusResponse getMessageStatusRespnse = (RopSetMessageStatusResponse)this.response;

            #region MS-OXCMSG_R786, MS-OXCMSG_R2028, MS-OXCMSG_R421
            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R786, the MessageStatusFlags is {0}.", getMessageStatusRespnse.MessageStatusFlags);

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R786
            bool isVerifiedR786 = getMessageStatusRespnse.ReturnValue == TestSuiteBase.Success && getMessageStatusRespnse.MessageStatusFlags == 0x00001000;

            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR786,
                786,
                @"[In RopGetMessageStatus ROP] The RopGetMessageStatus ROP ([MS-OXCROPS] section 2.2.6.9) gets the message status of a message in a folder.");

            // Because the MS-OXCMSG_R786 has been captured and verify that the RopGetMessageStatus gets the message status of a message.
            // So OXCMSG_R55 can be captured directly.
            this.Site.CaptureRequirement(
                55,
                @"[In Sending a RopGetPropertiesSpecific ROP Request] Instead, the client calls the RopGetMessageStatus ROP ([MS-OXCROPS] section 2.2.6.9), as specified in section 2.2.3.9.");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R2028
            this.Site.CaptureRequirementIfAreEqual <uint>(
                0x00001000,
                getMessageStatusRespnse.MessageStatusFlags,
                2028,
                @"[In PidTagMessageStatus Property] [The value of flag msRemoteDownload is] 0x00001000.");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R421
            // Because the message handle has been release in above step.
            // If RopGetMessageStatus execute successfully then R421 will be verified.
            this.Site.CaptureRequirementIfAreEqual <uint>(
                TestSuiteBase.Success,
                getMessageStatusRespnse.ReturnValue,
                421,
                @"[In Receiving a RopGetMessageStatus ROP Request] When processing the RopGetMessageStatus ROP ([MS-OXCROPS] section 2.2.6.9), the server MUST NOT require the Message object to be opened.");
            #endregion
            #endregion

            #region Call RopGetPropertiesSpecific to get the PidTagMessageStatus,PidTagChangeKey and PidTagLastModificationTime property after set MessagStatus.
            ps = this.GetSpecificPropertiesOfMessage(logonResponse.FolderIds[4], saveChangesMessageResponse.MessageId, this.insideObjHandle, propertyTags);
            PropertyObj pidTagMessageStatusAfterSet        = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagMessageStatus);
            PropertyObj pidTagChangeKeyAfterSet            = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagChangeKey);
            PropertyObj pidTagLastModificationTimeAfterSet = PropertyHelper.GetPropertyByName(ps, PropertyNames.PidTagLastModificationTime);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R1501
            bool isVerifiedR1501 =
                Common.CompareByteArray((byte[])pidTagChangeKeyBeforeSet.Value, (byte[])pidTagChangeKeyAfterSet.Value) == true &&
                pidTagLastModificationTimeBeforeSet.Value.Equals(pidTagLastModificationTimeAfterSet.Value) &&
                pidTagMessageStatusBeforeSet.Value != pidTagMessageStatusAfterSet.Value;

            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR1501,
                1501,
                @"[In Receiving a RopSetMessageStatus ROP Request] The server immediately commits the changes to the Message object as if the Message object had been opened and the RopSaveChangesMessage ROP ([MS-OXCROPS] section 2.2.6.3) had been called, except that it [server] changes only the PidTagMessageStatus property, not the PidTagChangeKey property ([MS-OXCFXICS] section 2.2.1.2.7), the PidTagLastModificationTime property (section 2.2.2.2), or any other property that is modified during the RopSaveChangesMessage ROP request.");
            #endregion
            #endregion

            #region Call RopSetMessageStatus to set the MessageStatusFlags property of specific message to 0x00000800.
            setMessageStatusRequest = new RopSetMessageStatusRequest()
            {
                RopId              = (byte)RopId.RopSetMessageStatus,
                LogonId            = CommonLogonId,
                InputHandleIndex   = CommonInputHandleIndex,
                MessageId          = saveChangesMessageResponse.MessageId,
                MessageStatusFlags = (uint)MessageStatusFlags.MsInConflict,
                MessageStatusMask  = (uint)MessageStatusFlags.MsInConflict | (uint)MessageStatusFlags.MsRemoteDownload | (uint)MessageStatusFlags.MsRemoteDelete
            };
            this.ResponseSOHs        = this.MSOXCMSGAdapter.DoRopCall(setMessageStatusRequest, folderHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            setMessageStatusResponse = (RopSetMessageStatusResponse)this.response;
            Site.Assert.AreEqual <uint>(TestSuiteBase.Success, setMessageStatusResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R784
            this.Site.CaptureRequirementIfAreEqual <uint>(
                getMessageStatusRespnse.MessageStatusFlags,
                setMessageStatusResponse.MessageStatusFlags,
                784,
                @"[In RopSetMessageStatus ROP Response Buffer] MessageStatusFlags: 4 bytes indicating the status flags that were set on the Message object before processing this request.");
            #endregion
            #endregion

            #region Call RopGetMessageStatus to get the message status of specific message created step 2.
            // RopGetMessageStatusResponse getMessageStatusResponse;
            getMessageStatusRequest.MessageId = saveChangesMessageResponse.MessageId;
            this.ResponseSOHs       = this.MSOXCMSGAdapter.DoRopCall(getMessageStatusRequest, folderHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            getMessageStatusRespnse = (RopSetMessageStatusResponse)this.response;
            Site.Assert.AreEqual <uint>(TestSuiteBase.Success, setMessageStatusResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R2029
            this.Site.CaptureRequirementIfAreEqual <uint>(
                0x00000800,
                getMessageStatusRespnse.MessageStatusFlags,
                2029,
                @"[In PidTagMessageStatus Property] [The value of flag msInConflict is] 0x00000800.");

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R416, the MessageStatusFlags value is {0}.", setMessageStatusResponse.MessageStatusFlags);

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R416
            bool isVerifiedR416 = getMessageStatusRespnse.MessageStatusFlags == (setMessageStatusRequest.MessageStatusMask & setMessageStatusRequest.MessageStatusFlags);

            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR416,
                416,
                @"[In Receiving a RopSetMessageStatus ROP Request] When processing the RopSetMessageStatus ROP ([MS-OXCROPS] section 2.2.6.8), the server modifies the bits on the PidTagMessageStatus property (section 2.2.1.8) specified by the MessageStatusMask field, preserving only those flags that are set in both the MessageStatusMask field and the MessageStatusFlags field, and clearing any other flags set only in the MessageStatusMask field.");

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R1500
            bool isVerifiedR1500 = (getMessageStatusRespnse.MessageStatusFlags & (~setMessageStatusRequest.MessageStatusFlags & setMessageStatusRequest.MessageStatusMask)) == 0x00000000;

            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR1500,
                1500,
                @"[In Receiving a RopSetMessageStatus ROP Request] [When processing the RopSetMessageStatus ROP, the server] clearing any other flags set only in the MessageStatusMask field.");
            #endregion
            #endregion

            #region Call RopSetMessageStatus to set the MessageStatusFlags property of specific message to 0x00002000.
            setMessageStatusRequest = new RopSetMessageStatusRequest()
            {
                RopId              = (byte)RopId.RopSetMessageStatus,
                LogonId            = CommonLogonId,
                InputHandleIndex   = CommonInputHandleIndex,
                MessageId          = saveChangesMessageResponse.MessageId,
                MessageStatusFlags = (uint)MessageStatusFlags.MsRemoteDelete,
                MessageStatusMask  = (uint)MessageStatusFlags.MsInConflict | (uint)MessageStatusFlags.MsRemoteDownload | (uint)MessageStatusFlags.MsRemoteDelete
            };
            this.ResponseSOHs        = this.MSOXCMSGAdapter.DoRopCall(setMessageStatusRequest, folderHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            setMessageStatusResponse = (RopSetMessageStatusResponse)this.response;
            Site.Assert.AreEqual <uint>(TestSuiteBase.Success, setMessageStatusResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopGetMessageStatus get the message status of specific message created step 2.
            getMessageStatusRequest.MessageId = saveChangesMessageResponse.MessageId;
            this.ResponseSOHs       = this.MSOXCMSGAdapter.DoRopCall(getMessageStatusRequest, folderHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            getMessageStatusRespnse = (RopSetMessageStatusResponse)this.response;
            Site.Assert.AreEqual <uint>(TestSuiteBase.Success, setMessageStatusResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

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

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R2030
            this.Site.CaptureRequirementIfAreEqual <uint>(
                0x00002000,
                getMessageStatusRespnse.MessageStatusFlags,
                2030,
                @"[In PidTagMessageStatus Property] [The value of flag msRemoteDelete is] 0x00002000.");
            #endregion
            #endregion
        }
        /// <summary>
        /// Send ROP request with single operation.
        /// </summary>
        /// <param name="ropRequest">ROP request objects.</param>
        /// <param name="insideObjHandle">Server object handle in request.</param>
        /// <param name="response">ROP response objects.</param>
        /// <param name="rawData">The ROP response payload.</param>
        /// <param name="getPropertiesFlag">The flag indicate the test cases expect to get which object type's properties(message's properties or attachment's properties).</param>
        /// <param name="returnValue">An unsigned integer value indicates the return value of call EcDoRpcExt2 method.</param>
        /// <returns>Server objects handles in response.</returns>
        public List <List <uint> > DoRopCall(ISerializable ropRequest, uint insideObjHandle, ref object response, ref byte[] rawData, GetPropertiesFlags getPropertiesFlag, out uint returnValue)
        {
            List <ISerializable> requestRops = new List <ISerializable>
            {
                ropRequest
            };

            List <uint> requestSOH = new List <uint>
            {
                insideObjHandle
            };

            if (Common.IsOutputHandleInRopRequest(ropRequest))
            {
                // Add an element for server output object handle, set default value to 0xFFFFFFFF
                requestSOH.Add(DefaultOutputHandle);
            }

            List <IDeserializable> responseRops = new List <IDeserializable>();
            List <List <uint> >    responseSOHs = new List <List <uint> >();

            // 0x10008 specifies the maximum size of the rgbOut buffer to place in Response.
            uint ret = this.oxcropsClient.RopCall(requestRops, requestSOH, ref responseRops, ref responseSOHs, ref rawData, 0x10008);

            returnValue = ret;
            if (ret == OxcRpcErrorCode.ECRpcFormat)
            {
                this.Site.Assert.Fail("Error RPC Format");
            }

            if (ret != 0)
            {
                return(responseSOHs);
            }

            if (responseRops != null)
            {
                if (responseRops.Count > 0)
                {
                    response = responseRops[0];
                }
            }
            else
            {
                response = null;
            }

            if (ropRequest.GetType() == typeof(RopReleaseRequest))
            {
                return(responseSOHs);
            }

            byte ropId = (byte)BitConverter.ToInt16(ropRequest.Serialize(), 0);

            List <PropertyObj> pts = null;

            switch (ropId)
            {
            case (byte)RopId.RopOpenMessage:
                RopOpenMessageResponse openMessageResponse = (RopOpenMessageResponse)response;

                // This check is for the open specification expectation for a particular request with some valid input parameters.
                if (openMessageResponse.ReturnValue == 0x00000000)
                {
                    this.VerifyRopOpenMessageResponse(openMessageResponse);
                }

                break;

            case (byte)RopId.RopGetPropertiesSpecific:
                // RopGetPropertiesSpecificRequest
                pts = PropertyHelper.GetPropertyObjFromBuffer(((RopGetPropertiesSpecificRequest)ropRequest).PropertyTags, (RopGetPropertiesSpecificResponse)response);

                foreach (PropertyObj pitem in pts)
                {
                    // Verify capture code for MS-OXCMSG.
                    this.VerifyMessageSyntaxDataType(pitem);
                }

                PropertyObj propertyObjPidTagSubjectPrefix     = PropertyHelper.GetPropertyByName(pts, PropertyNames.PidTagSubjectPrefix);
                PropertyObj propertyObjPidTagNormalizedSubject = PropertyHelper.GetPropertyByName(pts, PropertyNames.PidTagNormalizedSubject);

                // Verify the message of PidTagSubjectPrefixAndPidTagNormalizedSubject
                if (PropertyHelper.IsPropertyValid(propertyObjPidTagSubjectPrefix) || PropertyHelper.IsPropertyValid(propertyObjPidTagNormalizedSubject))
                {
                    this.VerifyMessageSyntaxPidTagSubjectPrefixAndPidTagNormalizedSubject(propertyObjPidTagSubjectPrefix, propertyObjPidTagNormalizedSubject);
                }

                // Verify the requirements of PidTagAttachmentLinkId and PidTagAttachmentFlags.
                PropertyObj pidTagAttachmentLinkId = PropertyHelper.GetPropertyByName(pts, PropertyNames.PidTagAttachmentLinkId);
                if (PropertyHelper.IsPropertyValid(pidTagAttachmentLinkId))
                {
                    this.VerifyMessageSyntaxPidTagAttachmentLinkIdAndPidTagAttachmentFlags(pidTagAttachmentLinkId);
                }

                PropertyObj pidTagAttachmentFlags = PropertyHelper.GetPropertyByName(pts, PropertyNames.PidTagAttachmentFlags);
                if (PropertyHelper.IsPropertyValid(pidTagAttachmentFlags))
                {
                    this.VerifyMessageSyntaxPidTagAttachmentLinkIdAndPidTagAttachmentFlags(pidTagAttachmentFlags);
                }

                // Verify the requirements of PidTagDisplayName
                PropertyObj pidTagDisplayName        = PropertyHelper.GetPropertyByName(pts, PropertyNames.PidTagDisplayName);
                PropertyObj pidTagAttachLongFilename = PropertyHelper.GetPropertyByName(pts, PropertyNames.PidTagAttachLongFilename);

                if (PropertyHelper.IsPropertyValid(pidTagDisplayName) && PropertyHelper.IsPropertyValid(pidTagAttachLongFilename))
                {
                    this.VerifyMessageSyntaxPidTagDisplayName(pidTagDisplayName, pidTagAttachLongFilename);
                }

                PropertyObj pidTagObjectType = PropertyHelper.GetPropertyByName(pts, PropertyNames.PidTagObjectType);
                PropertyObj pidTagRecordKey  = PropertyHelper.GetPropertyByName(pts, PropertyNames.PidTagRecordKey);

                this.VerifyPidTagObjectTypeAndPidTagRecordKey(pidTagObjectType, pidTagRecordKey);
                break;

            case (byte)RopId.RopGetPropertiesAll:
                RopGetPropertiesAllResponse getPropertiesAllResponse = (RopGetPropertiesAllResponse)response;
                pts = PropertyHelper.GetPropertyObjFromBuffer(getPropertiesAllResponse);

                foreach (PropertyObj pitem in pts)
                {
                    // Verify capture code for MS-OXCMSG.
                    this.VerifyMessageSyntaxDataType(pitem);
                }

                // Verify the requirements of PidTagArchiveDate
                PropertyObj pidTagArchiveDateObj = PropertyHelper.GetPropertyByName(pts, PropertyNames.PidTagArchiveDate);
                PropertyObj pidTagStartDateEtc   = PropertyHelper.GetPropertyByName(pts, PropertyNames.PidTagStartDateEtc);

                if (PropertyHelper.IsPropertyValid(pidTagArchiveDateObj))
                {
                    if (PropertyHelper.IsPropertyValid(pidTagStartDateEtc))
                    {
                        byte[] byteDest = new byte[8];
                        Array.Copy((byte[])pidTagStartDateEtc.Value, 6, byteDest, 0, 8);
                        this.VerifyMessageSyntaxPidTagArchiveDate(pidTagArchiveDateObj, DateTime.FromFileTimeUtc(BitConverter.ToInt64(byteDest, 0)));
                    }
                }

                PropertyObj pidTagAccessLevel = PropertyHelper.GetPropertyByName(pts, PropertyNames.PidTagAccessLevel);
                pidTagRecordKey = PropertyHelper.GetPropertyByName(pts, PropertyNames.PidTagRecordKey);

                if (getPropertiesFlag == GetPropertiesFlags.MessageProperties)
                {
                    PropertyObj pidTagAccess = PropertyHelper.GetPropertyByName(pts, PropertyNames.PidTagAccess);

                    PropertyObj pidTagChangeKey            = PropertyHelper.GetPropertyByName(pts, PropertyNames.PidTagChangeKey);
                    PropertyObj pidTagCreationTime         = PropertyHelper.GetPropertyByName(pts, PropertyNames.PidTagCreationTime);
                    PropertyObj pidTagLastModificationTime = PropertyHelper.GetPropertyByName(pts, PropertyNames.PidTagLastModificationTime);
                    PropertyObj pidTagLastModifierName     = PropertyHelper.GetPropertyByName(pts, PropertyNames.PidTagLastModifierName);
                    PropertyObj pidTagSearchKey            = PropertyHelper.GetPropertyByName(pts, PropertyNames.PidTagSearchKey);

                    // Verify properties PidTagAccess, PidTagAccessLevel, PidTagChangeKey, PidTagCreationTime, PidTagLastModificationTime, PidTagLastModifierName and PidTagSearchKey exist on all Message objects.
                    this.VerifyPropertiesExistOnAllMessageObject(pidTagAccess, pidTagAccessLevel, pidTagChangeKey, pidTagCreationTime, pidTagLastModificationTime, pidTagLastModifierName, pidTagSearchKey);
                }

                if (getPropertiesFlag == GetPropertiesFlags.AttachmentProperties)
                {
                    // Verify properties PidTagAccessLevel and PidTagRecordKey exist on any Attachment object.
                    this.VerifyPropertiesExistOnAllAttachmentObject(pidTagAccessLevel, pidTagRecordKey);
                }

                break;

            case (byte)RopId.RopCreateMessage:
                RopCreateMessageResponse createMessageResponse = (RopCreateMessageResponse)response;

                // Adapter requirements related with RopCreateMessage will be verified if the response is a successful one.
                if (createMessageResponse.ReturnValue == 0x00000000)
                {
                    int hasMessageId = createMessageResponse.HasMessageId;
                    this.VerifyMessageSyntaxHasMessageId(hasMessageId);
                }

                break;

            case (byte)RopId.RopReadRecipients:
                RopReadRecipientsResponse readRecipientsResponse = (RopReadRecipientsResponse)response;

                // Adapter requirements related with RopReadRecipients will be verified if the response is a successful one.
                if (readRecipientsResponse.ReturnValue == 0x00000000)
                {
                    this.VerifyMessageSyntaxRowCount(readRecipientsResponse);
                }

                break;

            case (byte)RopId.RopSetMessageStatus:
                RopSetMessageStatusResponse setMessageStatusResponse = (RopSetMessageStatusResponse)response;

                // Adapter requirements related with RopSetMessageStatus will be verified if the response is a successful one.
                if (setMessageStatusResponse.ReturnValue == 0x00000000)
                {
                    this.VerifyMessageSyntaxMessageStatusFlags(setMessageStatusResponse);
                }

                break;

            case (byte)RopId.RopCreateAttachment:
                RopCreateAttachmentResponse createAttachmentResponse = (RopCreateAttachmentResponse)response;

                // Adapter requirements related with RopCreateAttachment will be verified if the response is a successful one.
                if (createAttachmentResponse.ReturnValue == 0x00000000)
                {
                    int id = (int)createAttachmentResponse.AttachmentID;
                    this.VerifyDataStructureRopCreateAttachmentResponse(createAttachmentResponse, id);
                }

                break;

            case (byte)RopId.RopOpenEmbeddedMessage:
                RopOpenEmbeddedMessageResponse openEmbeddedMessageResponse = (RopOpenEmbeddedMessageResponse)response;

                // Adapter requirements related with RopOpenEmbeddedMessage will be verified if the response is a successful one.
                if (openEmbeddedMessageResponse.ReturnValue == 0x00000000)
                {
                    ulong mid = openEmbeddedMessageResponse.MessageId;
                    this.VerifyDataStructureRopOpenEmbeddedMessageResponse(openEmbeddedMessageResponse, mid);
                }

                break;

            case (byte)RopId.RopSetMessageReadFlag:
                RopSetMessageReadFlagResponse setMessageReadFlagResponse = (RopSetMessageReadFlagResponse)response;

                // Adapter requirements related with RopSetMessageReadFlag will be verified if the response is a successful one.
                if (setMessageReadFlagResponse.ReturnValue == 0x00000000)
                {
                    this.VerifyMessageSyntaxReadStatusChanged(setMessageReadFlagResponse, (RopSetMessageReadFlagRequest)ropRequest);
                }

                break;

            case (byte)RopId.RopSetReadFlags:
                // Adapter requirements related with RopSetReadFlags will be verified if the response is a successful one.
                if (((RopSetReadFlagsResponse)response).ReturnValue == 0x00000000)
                {
                    this.VerifyRopSetReadFlagsResponse((RopSetReadFlagsResponse)response);
                }

                break;

            case (byte)RopId.RopGetMessageStatus:
                // Adapter requirements related with RopGetMessageStatus will be verified if the response is a successful one.
                if (((RopSetMessageStatusResponse)response).ReturnValue == 0x00000000)
                {
                    this.VerifyGetMessageStatusResponse((RopSetMessageStatusResponse)response);
                }

                break;

            default:
                break;
            }

            this.VerifyMAPITransport();

            return(responseSOHs);
        }