/// <summary>
        /// Set the specific object's property value.
        /// </summary>
        /// <param name="serverId">A 32-bit signed integer represent the Identity of server.</param>
        /// <param name="handleindex">Server object handle index.</param>
        /// <param name="taggedPropertyValueArray">The list of property values.</param>
        /// <returns>Indicate the result of this ROP operation.</returns>
        public RopResult SetProperties(int serverId, int handleindex, Sequence<string> taggedPropertyValueArray)
        {
            // Initialize ROP data.
            TaggedPropertyValue[] taggedPropertyValueArrays = new TaggedPropertyValue[taggedPropertyValueArray.Count];

            // Set a large property to test TransferStatus (Partial and NoRoom)
            for (int i = 0; i < taggedPropertyValueArray.Count; i++)
            {
                if (taggedPropertyValueArray[i] == "PidTagPolicyTag")
                {
                    // Set the property PidTagPolicyTag
                    taggedPropertyValueArrays[i] = new TaggedPropertyValue
                    {
                        PropertyTag = new PropertyTag(0x3019, 0x0102)
                    };
                    string value = string.Empty;
                    for (int j = 0; j < 30000; j++)
                    {
                        value += "a";
                    }

                    taggedPropertyValueArrays[i].Value = Common.AddInt16LengthBeforeBinaryArray(Encoding.ASCII.GetBytes(value));
                }
                else
                {
                    taggedPropertyValueArrays[i] = this.taggedPropertyValuesDictionary[taggedPropertyValueArray[i]];
                }
            }

            uint setPropertiesHandle = this.handleContainer[handleindex];
            RopResult result = RopResult.InvalidParameter;

            // Construct ROP request.
            RopSetPropertiesRequest setPropertiesRequest = new RopSetPropertiesRequest
            {
                RopId = 0x0A,
                LogonId = 0x00,
                InputHandleIndex = 0x00
            };
            int arraySize = 0;
            for (int i = 0; i < taggedPropertyValueArrays.Length; i++)
            {
                arraySize += taggedPropertyValueArrays[i].Size();
            }

            // This value specifies the number of bytes used for the PropertyValueCount field and the PropertyValues field.
            setPropertiesRequest.PropertyValueSize = (ushort)(arraySize + 2);
            setPropertiesRequest.PropertyValueCount = (ushort)taggedPropertyValueArrays.Length;
            setPropertiesRequest.PropertyValues = taggedPropertyValueArrays;

            // Send the RopSetProperties request 
            RopSetPropertiesResponse setPropertiesResponse = (RopSetPropertiesResponse)this.Process(serverId, setPropertiesRequest, setPropertiesHandle);
            result = (RopResult)setPropertiesResponse.ReturnValue;
            if (result == RopResult.Success)
            {
                this.lastChangeMadeByServer = true;
            }

            return result;
        }
Пример #2
0
        /// <summary>
        /// This method is used to send the ROP of RopSetPropertiesRequest to set the specific property.
        /// </summary>
        /// <param name="propValue">The new property value</param>
        /// <returns>0 indicates success, others indicates error occurs.</returns>
        protected uint TrySetLogonProperty(TaggedPropertyValue propValue)
        {
            uint retValue = 0;
            TaggedPropertyValue[] tags = new TaggedPropertyValue[1];
            tags[0] = propValue;

            #region Construct the request buffer
            RopSetPropertiesRequest setPropertiesRequest = new RopSetPropertiesRequest
            {
                RopId = 0x0A,
                LogonId = 0x0,
                InputHandleIndex = 0x0,
                PropertyValueSize = (ushort)(tags[0].Size() + 2),
                PropertyValueCount = (ushort)tags.Length,
                PropertyValues = tags
            };

            #endregion

            this.oxcstorAdapter.DoRopCall(setPropertiesRequest, this.outObjHandle, ROPCommandType.RopSetProperties, out this.outputBuffer);
            RopSetPropertiesResponse setPropertiesResponse = (RopSetPropertiesResponse)this.outputBuffer.RopsList[0];

            #region Check the response
            if (setPropertiesResponse.ReturnValue == 0x00)
            {
                // The return value is 0 to indicate that the method invoking successfully.
                if (setPropertiesResponse.PropertyProblems != null
                && setPropertiesResponse.PropertyProblems.Length > 0)
                {
                    retValue = setPropertiesResponse.PropertyProblems[0].ErrorCode;
                }
            }
            else
            {
                retValue = setPropertiesResponse.ReturnValue;
            }
            #endregion

            return retValue;
        }
        public void MSOXCFOLD_S03_TC08_SetAndGetProperties()
        {
            this.CheckWhetherSupportTransport();
            this.Adapter.DoConnect(ConnectionType.PrivateMailboxServer);
            this.GenericFolderInitialization();

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

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

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

            #endregion

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

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

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

            #endregion

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

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

            #endregion

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

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

            #endregion

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            #endregion

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

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

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

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

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

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

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

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

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

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

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

            #endregion

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

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

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

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

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

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

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

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

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

            #endregion

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

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

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

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

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

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

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

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

            #endregion

            #endregion

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

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

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

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

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

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

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

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

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

            #endregion

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

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

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

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

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

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

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

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

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

                // Verify MS-OXCFOLD requirement: MS-OXCFOLD_R350.
                // Flag value 0x01 indicates there is error.
                Site.CaptureRequirementIfAreEqual<byte>(
                    0x01,
                    getPropertiesSpecificResponse.RowData.Flag,
                    350,
                    @"[In PidTagAddressBookEntryId Property] This property is set only for public folders.");
            }
            #endregion
        }
        /// <summary>
        /// Edit the message created by the owner of the mailbox or other user in Inbox.
        /// </summary>
        /// <param name="messageId">The message Id to edit.</param>
        /// <returns>The return value from the server. 0x00000000 indicates success, others indicate error occurs.</returns>
        private uint EditMessage(ulong messageId)
        {
            RopOpenMessageRequest openMessageRequest;
            RopOpenMessageResponse openMessageResponse;
            openMessageRequest.RopId = 0x03; // RopId 0x03 indicates RopOpenMessage
            openMessageRequest.LogonId = 0x00; // The logonId 0x00 is associated with this operation.
            openMessageRequest.InputHandleIndex = 0x00; // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the input Server Object is stored. 
            openMessageRequest.OutputHandleIndex = 0x01; // This index specifies the location 0x01 in the Server Object Handle Table where the handle for the output Server Object is stored. 
            openMessageRequest.CodePageId = 0x0FFF; // Code page of Logon object is used
            openMessageRequest.FolderId = this.ropLogonResponse.FolderIds[4]; // Open the message in INBOX folder in which message is created.
            openMessageRequest.OpenModeFlags = 0x01; // The message will be opened as read-write
            openMessageRequest.MessageId = messageId; // Open the saved message
            this.responseSOHs = this.DoRopCall(openMessageRequest, this.inobjHandle, ref this.response, ref this.rawData);
            openMessageResponse = (RopOpenMessageResponse)this.response;
            if (UINT32SUCCESS != openMessageResponse.ReturnValue)
            {
                return openMessageResponse.ReturnValue;
            }

            uint targetMessageHandle = this.responseSOHs[0][openMessageResponse.OutputHandleIndex];

            TaggedPropertyValue[] tags = new TaggedPropertyValue[2];

            // PidTagSubject
            PropertyTag pt = new PropertyTag
            {
                PropertyId = 0x0037,
                PropertyType = 0x001F
            };
            TaggedPropertyValue tpv0 = new TaggedPropertyValue
            {
                PropertyTag = pt
            };
            if (this.messageIdsCreatedByOther.Contains(messageId))
            {
                tpv0.Value = Encoding.Unicode.GetBytes("EditTheSubjectCreatedByAdminEditedbyUser1" + StringNullTerminator);
            }
            else
            {
                tpv0.Value = Encoding.Unicode.GetBytes("EditTheSubjectCreatedByCommUserEditedbyUser1: " + this.ownedMessageIndex++ + StringNullTerminator);
            }

            tags[0] = tpv0;

            // PidTagNormalizedSubject
            PropertyTag pt0 = new PropertyTag
            {
                PropertyId = 0x0E1D,
                PropertyType = 0x001F
            };
            TaggedPropertyValue tpv1 = new TaggedPropertyValue
            {
                PropertyTag = pt0,
                Value = tpv0.Value
            };
            tags[1] = tpv1;

            #region Construct the request buffer
            RopSetPropertiesRequest setPropertiesRequest = new RopSetPropertiesRequest
            {
                RopId = 0x0A,
                LogonId = 0x0,
                InputHandleIndex = 0x0,
                PropertyValueSize = (ushort)(tags[0].Size() + tags[1].Size() + 2),
                PropertyValueCount = (ushort)tags.Length,
                PropertyValues = tags
            };

            #endregion

            this.DoRopCall(setPropertiesRequest, targetMessageHandle, ref this.response, ref this.rawData);
            RopSetPropertiesResponse setPropertiesResponse = (RopSetPropertiesResponse)this.response;
            if (UINT32SUCCESS != setPropertiesResponse.ReturnValue)
            {
                return setPropertiesResponse.ReturnValue;
            }

            RopSaveChangesMessageRequest saveChangesMessageRequest;
            RopSaveChangesMessageResponse saveChangesMessageResponse;
            saveChangesMessageRequest.RopId = 0x0C; // RopId 0x0C indicates RopSaveChangesMessage 
            saveChangesMessageRequest.LogonId = 0x00; // The logonId 0x00 is associated with this operation.
            saveChangesMessageRequest.InputHandleIndex = 0x00; // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the input Server Object is stored. 
            saveChangesMessageRequest.ResponseHandleIndex = 0x01; // This index specifies the location 0x01 in the Server Object Handle Table where the handle for the output Server Object is stored. 
            saveChangesMessageRequest.SaveFlags = 0x0C; // ForceSave
            this.DoRopCall(saveChangesMessageRequest, targetMessageHandle, ref this.response, ref this.rawData);
            saveChangesMessageResponse = (RopSaveChangesMessageResponse)this.response;
            if (UINT32SUCCESS != saveChangesMessageResponse.ReturnValue)
            {
                return saveChangesMessageResponse.ReturnValue;
            }

            // Release the message 
            this.ReleaseObject(targetMessageHandle);

            return UINT32SUCCESS;
        }
        /// <summary>
        /// Set the value of properties identified by long ID or name in message.
        /// </summary>
        /// <param name="messageHandle">The specified message handle.</param>
        /// <param name="property">The PropertyName of specified property.</param>
        /// <param name="value">The value of specified property.</param>
        private void SetNamedProperty(uint messageHandle, PropertyNameObject property, byte[] value)
        {
            #region Call RopGetPropertyIdsFromNames to get property ID.
            PropertyName[] propertyNames = new PropertyName[1];
            propertyNames[0] = property.PropertyName;

            RopGetPropertyIdsFromNamesRequest getPropertyIdsFromNamesRequest = new RopGetPropertyIdsFromNamesRequest()
            {
                RopId = (byte)RopId.RopGetPropertyIdsFromNames,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                Flags = (byte)GetPropertyIdsFromNamesFlags.Create,
                PropertyNameCount = (ushort)propertyNames.Length,
                PropertyNames = propertyNames,
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getPropertyIdsFromNamesRequest, messageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopGetPropertyIdsFromNamesResponse getPropertyIdsFromNamesResponse = (RopGetPropertyIdsFromNamesResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getPropertyIdsFromNamesResponse.ReturnValue, "Call RopGetPropertyIdsFromNames should success.");
            #endregion

            #region Set property value.

            List<TaggedPropertyValue> taggedPropertyValues = new List<TaggedPropertyValue>();

            int valueSize = 0;
            PropertyTag propertyTag = new PropertyTag
            {
                PropertyId = getPropertyIdsFromNamesResponse.PropertyIds[0].ID,
                PropertyType = (ushort)property.PropertyType
            };
            TaggedPropertyValue taggedPropertyValue = new TaggedPropertyValue
            {
                PropertyTag = propertyTag,
                Value = value
            };
            valueSize += taggedPropertyValue.Size();
            taggedPropertyValues.Add(taggedPropertyValue);

            RopSetPropertiesRequest rpmSetRequest = new RopSetPropertiesRequest()
            {
                RopId = (byte)RopId.RopSetProperties,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                PropertyValueCount = (ushort)taggedPropertyValues.Count,
                PropertyValueSize = (ushort)(valueSize + 2),
                PropertyValues = taggedPropertyValues.ToArray()
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(rpmSetRequest, messageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);

            RopSetPropertiesResponse rpmSetResponse = (RopSetPropertiesResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, rpmSetResponse.PropertyProblemCount, "If ROP succeeds, the PropertyProblemCount of its response is 0(success).");
            #endregion
        }
 /// <summary>
 /// The method is used to set flag of PidTagAttachMethod.
 /// </summary>
 /// <param name="taggedPropertyValueArray">TaggedPropertyValue array </param>
 /// <param name="attachmentHandle">The attachment handle.</param>
 /// <param name="size">The size of TaggedPropertyValue array.</param>
 private void SetFlagsOfPidTagAttachMethod(TaggedPropertyValue[] taggedPropertyValueArray, uint attachmentHandle, int size)
 {
     RopSetPropertiesRequest setPropertiesRequest = new RopSetPropertiesRequest()
     {
         RopId = (byte)RopId.RopSetProperties,
         LogonId = CommonLogonId, // The logonId 0x00 is associated with this operation.
         InputHandleIndex = CommonInputHandleIndex, // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the input Server Object is stored. 
         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);
 }
 /// <summary>
 /// Set folder object properties.
 /// </summary>
 /// <param name="ropSetPropertiesRequest">RopSetPropertiesRequest object.</param>
 /// <param name="insideObjHandle">Server object handle in SetProperties.</param>
 /// <param name="responseSOHTable">Server objects handles in RopSetPropertiesResponse.</param>
 /// <returns>RopSetPropertiesResponse object.</returns>
 public RopSetPropertiesResponse SetFolderObjectProperties(RopSetPropertiesRequest ropSetPropertiesRequest, uint insideObjHandle, ref List<List<uint>> responseSOHTable)
 {
     object temp = new object();
     this.ExcuteRopCall((ISerializable)ropSetPropertiesRequest, insideObjHandle, ref temp, ref responseSOHTable, ref this.rawData);
     return (RopSetPropertiesResponse)temp;
 }
        public void MSOXCROPS_S06_TC05_TestRopsSetProperties()
        {
            this.CheckTransportIsSupported();

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

            // Step 1: Preparations-Create message and get the created message handle.
            #region Preparations

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

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 1:Call GetCreatedMessageHandle method to create message and get the created message handle.");

            // Call GetCreatedMessageHandle method to create message and get the created message handle.
            uint messageHandle = GetCreatedMessageHandle(logonResponse.FolderIds[4], inputObjHandle);

            int size = 0;
            TaggedPropertyValue[] taggedPropertyValueArray = this.CreateMessageTaggedPropertyValueArray(out size);

            #endregion

            // Step 2: Send the RopSetProperties request and verify the success response.
            #region RopSetProperties success response

            RopSetPropertiesRequest setPropertiesRequest = new RopSetPropertiesRequest();
            RopSetPropertiesResponse setPropertiesResponse;

            setPropertiesRequest.RopId = (byte)RopId.RopSetProperties;
            setPropertiesRequest.LogonId = TestSuiteBase.LogonId;
            setPropertiesRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;
            setPropertiesRequest.PropertyValueSize = (ushort)(size + 2);
            setPropertiesRequest.PropertyValueCount = (ushort)taggedPropertyValueArray.Length;
            setPropertiesRequest.PropertyValues = taggedPropertyValueArray;

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

            // Send the RopSetProperties request and verify the success response.
            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                setPropertiesRequest,
                messageHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            setPropertiesResponse = (RopSetPropertiesResponse)response;

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

            #endregion

            // Step 3: Send the RopSetProperties request and verify the failure response.
            #region RopSetProperties failure response

            setPropertiesRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex1;

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

            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                setPropertiesRequest,
                messageHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.FailureResponse);
            setPropertiesResponse = (RopSetPropertiesResponse)response;

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

            #endregion

            // Step 4: Send the RopSetPropertiesNoReplicate request and verify the success response.
            #region RopSetPropertiesNoReplicate success response

            RopSetPropertiesNoReplicateRequest setPropertiesNoReplicateRequest = new RopSetPropertiesNoReplicateRequest();
            RopSetPropertiesNoReplicateResponse setPropertiesNoReplicateResponse;

            setPropertiesNoReplicateRequest.RopId = (byte)RopId.RopSetPropertiesNoReplicate;
            setPropertiesNoReplicateRequest.LogonId = TestSuiteBase.LogonId;
            setPropertiesNoReplicateRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;
            setPropertiesNoReplicateRequest.PropertyValueSize = (ushort)(size + 2);
            setPropertiesNoReplicateRequest.PropertyValueCount = (ushort)taggedPropertyValueArray.Length;
            setPropertiesNoReplicateRequest.PropertyValues = taggedPropertyValueArray;

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

            // Send the RopSetPropertiesNoReplicate request and verify the success response.
            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                setPropertiesNoReplicateRequest,
                messageHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            setPropertiesNoReplicateResponse = (RopSetPropertiesNoReplicateResponse)response;

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

            #endregion

            // Step 5: Send the RopSetPropertiesNoReplicate request and verify the failure response.
            #region RopSetPropertiesNoReplicate failure response

            setPropertiesNoReplicateRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex1;

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

            // Send the RopSetPropertiesNoReplicate request and verify the failure response.
            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                setPropertiesNoReplicateRequest,
                messageHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.FailureResponse);
            setPropertiesNoReplicateResponse = (RopSetPropertiesNoReplicateResponse)response;

            Site.Assert.AreNotEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                setPropertiesNoReplicateResponse.ReturnValue,
                "If ROP failure, the ReturnValue of its response is not 0(success).");

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

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

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

            #region Call RopOpenMessage which OpenModeFlags is ReadWrite to open created message.
            uint openedMessageReadWriteHandle = this.OpenSpecificMessage(logonResponse.FolderIds[4], messageId, this.insideObjHandle, MessageOpenModeFlags.ReadWrite);
            #endregion

            #region Call RopSetProperties to set PidTagNormalizedSubject property of created message.
            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()
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(rpmSetRequest, openedMessageReadWriteHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopSetPropertiesResponse rpmSetResponse = (RopSetPropertiesResponse)this.response;
            #region Verify MS-OXCMSG_R663
            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R663");

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R663
            this.Site.CaptureRequirementIfAreEqual<uint>(
                TestSuiteBase.Success,
                rpmSetResponse.ReturnValue,
                663,
                @"[In RopOpenMessage ROP Request Buffer] [OpenModeFlags] [ReadWrite (0x01)] Message will be opened for both reading and writing.");
            #endregion
            #endregion

            #region Call RopRelease to release created message.
            this.ReleaseRop(openedMessageReadWriteHandle);
            #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);
        }
        public void MSOXCMSG_S05_TC05_RopOpenMessageAsReadOnly()
        {
            this.CheckMapiHttpIsSupported();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);

            List<PropertyObj> propertyValues = new List<PropertyObj>
            {
                new PropertyObj(PropertyNames.PidTagNormalizedSubject, Common.GetBytesFromUnicodeString(TestDataOfPidTagNormalizedSubject))
            };

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

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

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

            #region Call RopOpenMessage which OpenModeFlags is read-only to open created message.
            uint openedMessageReadOnlyHandle = this.OpenSpecificMessage(logonResponse.FolderIds[4], messageId, this.insideObjHandle, MessageOpenModeFlags.ReadOnly);
            #endregion

            #region Call RopSetProperties to set PidTagNormalizedSubject property of created message.
            if (Common.IsRequirementEnabled(661, this.Site))
            {
                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, openedMessageReadOnlyHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None, out returnValue);

                #region Verify MS-OXCMSG_R661
                if (this.response == null)
                {
                    Site.Assert.AreNotEqual<uint>(0, returnValue, "Call RopSetProperties should fail.");
                }
                else
                {
                    RopSetPropertiesResponse 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_R661");

                // 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(
                    661,
                    @"[In RopOpenMessage ROP Request Buffer] [OpenModeFlags] [ReadOnly (0x00)] Message will be opened as read only.");
                #endregion
            }
            #endregion

            #region Call RopRelease to release created message.
            this.ReleaseRop(openedMessageReadOnlyHandle);
            #endregion
        }
        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. (<17> Section 2.2.3.16.1:  Exchange 2010, Exchange 2013, and Exchange 2016 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
        }
        public void MSOXCMSG_S09_TC03_Transaction()
        {
            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 RopSaveChangesMessage to save the newly created message.
            RopSaveChangesMessageResponse saveChangesMessageResponse;
            saveChangesMessageResponse = this.SaveMessage(targetMessageHandle, (byte)SaveFlags.ForceSave);
             #endregion

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

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

            #region Call RopSetProperties to set PidTagAttachMethod property, that is the attachment is the embedded attachment.
            // Setting PidTagAttachMethod property means the attachment is the embedded message
            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 RopSaveChangesAttachment to save the attachment changes
            RopSaveChangesAttachmentResponse saveChangesAttachmentResponse;
            this.SaveAttachment(attachmentHandle, out saveChangesAttachmentResponse);
            #endregion

            #region Call RopOpenEmbeddedMessage with OpenModeFlags set to 0x02 to create an embedded message.
            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;
            uint embeddedMessageHandle = this.ResponseSOHs[0][openMessageResponse.OutputHandleIndex];
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, openEmbeddedMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
            #endregion

            #region Call RopOpenEmbeddedMessage with OpenModeFlags set to 0x01 to open the embedded message which is created in step 9 and expect a failure response
            RopOpenEmbeddedMessageResponse openEmbeddedMessageResponseFirst;
            openEmbeddedMessageRequest.OpenModeFlags = 0x01; // Try to open the embedded message as read/write.
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(openEmbeddedMessageRequest, attachmentHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            openEmbeddedMessageResponseFirst = (RopOpenEmbeddedMessageResponse)this.response;
            #endregion

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

            #region Call ReleaseRop to release the embedded message created in step 9.
            this.ReleaseRop(embeddedMessageHandle);
            #endregion

            #region Call RopOpenEmbeddedMessage with OpenModeFlags set to 0x01 to open the embedded message which is created in step 9 and expect a successful response.
            RopOpenEmbeddedMessageResponse openEmbeddedMessageResponseSecond;
            openEmbeddedMessageRequest.OpenModeFlags = 0x01; // Try to open the embedded message as read/write.
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(openEmbeddedMessageRequest, attachmentHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            openEmbeddedMessageResponseSecond = (RopOpenEmbeddedMessageResponse)this.response;
            #endregion

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R481. The return value of RopOpenEmbeddedMessage before calling RopSaveChangesMessage is {0}, the return value of RopOpenEmbeddedMessage after calling RopSaveChangesMessage is {1}.", openEmbeddedMessageResponseFirst.ReturnValue, openEmbeddedMessageResponseSecond.ReturnValue);
        
            // Verify MS-OXCMSG requirement: MS-OXCMSG_R481
            bool isVerifiedR481 = openEmbeddedMessageResponseFirst.ReturnValue != TestSuiteBase.Success && openEmbeddedMessageResponseSecond.ReturnValue == TestSuiteBase.Success;

            // The server doesn't commit the Message object to the containing Attachment object until the RopSaveChangesMessage ROP is called if isVerifiedR481 is true, then MS-OXCMSG_R481 can be verified.
            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR481,
                481,
                @"[In Receiving a RopOpenEmbeddedMessage ROP Request] The server MUST NOT commit the Message object to the containing Attachment object until the RopSaveChangesMessage ROP ([MS-OXCROPS] section 2.2.6.3) is called with the Embedded Message object's handle.");

            #region Call RopRelease to release the message created in step 2.
            this.ReleaseRop(targetMessageHandle);
            #endregion
        }
        public void MSOXCMSG_S09_TC02_RopOpenEmbeddedMessageFailed()
        {
            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 RopSaveChangesMessage to save the newly created message.
            RopSaveChangesMessageResponse saveChangesMessageResponse;
            saveChangesMessageResponse = this.SaveMessage(targetMessageHandle, (byte)SaveFlags.ForceSave);
            #endregion

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

            #region Call RopCreateAttachment to create an embedded attachment.
            RopCreateAttachmentResponse createAttachmentResponse;
            uint attachmentId;
            uint attachmentHandle = this.CreateAttachment(openedMessageHandle, 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 RopSaveChangesAttachment to save the attachment changes.
            RopSaveChangesAttachmentResponse saveChangesAttachmentResponse;
            this.SaveAttachment(attachmentHandle, out saveChangesAttachmentResponse);
            #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 RopRelease to release the embedded message
            this.ReleaseRop(embeddedMessageHandle);
            #endregion

            #region Call RopOpenEmbeddedMessage with CodePageId set to 0x000F and error code 0x000003ef is expected
            openEmbeddedMessageRequest.CodePageId = 0x000F;
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(openEmbeddedMessageRequest, attachmentHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            openEmbeddedMessageResponse = (RopOpenEmbeddedMessageResponse)this.response;
            #endregion

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R1068");
        
            // Verify MS-OXCMSG requirement: MS-OXCMSG_R1068
            this.Site.CaptureRequirementIfAreEqual<uint>(
                0x000003ef,
                openEmbeddedMessageResponse.ReturnValue,
                1068,
                @"[In Receiving a RopOpenEmbeddedMessage ROP Request] [ecUnknownCodePage (0x000003ef)] The code page is unknown.");

            #region Call RopOpenEmbeddedMessage with InputHandleIndex set to 0x01 to open the embedded message and expect to get the error code 0x000004B9 (ecNullObject).
            openEmbeddedMessageRequest.CodePageId = 0x0FFF; // Code page of Logon object is used
            openEmbeddedMessageRequest.InputHandleIndex = 0x01;
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(openEmbeddedMessageRequest, attachmentHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            openEmbeddedMessageResponse = (RopOpenEmbeddedMessageResponse)this.response;
            #endregion

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R1525");
        
            // Verify MS-OXCMSG requirement: MS-OXCMSG_R1525
            this.Site.CaptureRequirementIfAreEqual<uint>(
                0x000004B9,
                openEmbeddedMessageResponse.ReturnValue,
                1525,
                @"[In Receiving a RopOpenEmbeddedMessage ROP Request] [ecNullObject (0x000004B9)] The value of the InputHandleIndex field on which this ROP [RopOpenEmbeddedMessage] was called does not refer to an Attachment object.");

            #region Call RopRelease to release the embedded message.
            this.ReleaseRop(embeddedMessageHandle);
            this.ReleaseRop(targetMessageHandle);
            #endregion
        }
        /// <summary>
        /// Set properties' value for a message
        /// </summary>
        /// <param name="messageHandle">Unsigned integer value indicates a message object handle.</param>
        /// <param name="pts">PropertyObj list value</param>
        /// <param name="rpmSetResponse">The response of calling RopSetProperties.</param>
        protected void SetPropertiesForMessage(uint messageHandle, List<PropertyObj> pts, out RopSetPropertiesResponse rpmSetResponse)
        {
            List<TaggedPropertyValue> pvs = new List<TaggedPropertyValue>();

            int valueSize = 0;
            foreach (PropertyObj pt in pts)
            {
                PropertyTag pg = new PropertyTag
                {
                    PropertyId = (ushort)pt.PropertyID,
                    PropertyType = (ushort)pt.ValueTypeCode
                };

                TaggedPropertyValue pv = new TaggedPropertyValue
                {
                    PropertyTag = pg,
                    Value = (byte[])pt.Value
                };
                valueSize += pv.Size();

                pvs.Add(pv);
            }

            RopSetPropertiesRequest rpmSetRequest = new RopSetPropertiesRequest()
            {
                RopId = (byte)RopId.RopSetProperties,
                LogonId = CommonLogonId, // The logonId 0x00 is associated with this operation.
                InputHandleIndex = CommonInputHandleIndex, // This index specifies the location 0x00 in the Server Object Handle Table where the handle for the input Server Object is stored. 
                PropertyValueCount = (ushort)pvs.Count,
                PropertyValueSize = (ushort)(valueSize + 2),
                PropertyValues = pvs.ToArray()
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(rpmSetRequest, messageHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            rpmSetResponse = (RopSetPropertiesResponse)this.response;

            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, rpmSetResponse.PropertyProblemCount, "If ROP succeeds, the PropertyProblemCount of its response is 0(success).");
        }