A class indicates the ModLinkAtt request type.
Inheritance: AddressBookRequestBodyBase
        /// <summary>
        /// This method is used by the client to modify a specific property of a row in the address book.
        /// </summary>
        /// <param name="modLinkAttRequestBody">The ModLinkAtt request type request body.</param>
        /// <returns>The response body of the ModLinkAtt request type.</returns>
        public ModLinkAttResponseBody ModLinkAtt(ModLinkAttRequestBody modLinkAttRequestBody)
        {
            CommonResponse         commonResponse         = this.SendAddressBookRequest(modLinkAttRequestBody, RequestType.ModLinkAtt);
            ModLinkAttResponseBody modLinkAttResponseBody = ModLinkAttResponseBody.Parse(commonResponse.ResponseBodyRawData);

            this.VerifyModLinkAttResponseBody(modLinkAttResponseBody);

            return(modLinkAttResponseBody);
        }
        /// <summary>
        /// Clean up the test suite.
        /// </summary>
        protected override void TestCleanup()
        {
            // Flags of ModLinkAtt for delete the address book member or address book public delegates.
            uint flagsOfModLinkAtt = 1;
            PropertyTag propTagOfAddressBookMember = new PropertyTag
            {
                PropertyType = (ushort)PropertyTypeValues.PtypEmbeddedTable,
                PropertyId = (ushort)PropertyID.PidTagAddressBookMember
            };

            PropertyTag propTagOfAddressBookPublicDelegate = new PropertyTag
            {
                PropertyType = (ushort)PropertyTypeValues.PtypEmbeddedTable,
                PropertyId = (ushort)PropertyID.PidTagAddressBookPublicDelegates
            };
            byte[] auxIn = new byte[] { };

            ModLinkAttRequestBody modLinkAttRequestBody = new ModLinkAttRequestBody();
            modLinkAttRequestBody.Flags = flagsOfModLinkAtt;
            modLinkAttRequestBody.HasEntryIds = true;
            modLinkAttRequestBody.EntryIdCount = 1;
            modLinkAttRequestBody.AuxiliaryBuffer = auxIn;
            modLinkAttRequestBody.AuxiliaryBufferSize = (uint)auxIn.Length;

            if (!this.isAddressBookMemberDeleted)
            {
                modLinkAttRequestBody.PropertyTag = propTagOfAddressBookMember;
                modLinkAttRequestBody.MinimalId = this.minimalIDForDeleteAddressBookMember;
                modLinkAttRequestBody.EntryIDs = new byte[][] { this.entryIDBufferForDeleteAddressBookMember };

                ModLinkAttResponseBody modLinkAttResponseBodyOfDelete = this.Adapter.ModLinkAtt(modLinkAttRequestBody);
                Site.Assert.AreEqual<uint>(0, modLinkAttResponseBodyOfDelete.ErrorCode, "ModLinkAtt request to delete the address book member should be executed successfully, the returned error code is {0}.", modLinkAttResponseBodyOfDelete.ErrorCode);
            }

            if (!this.isAddressBookPublicDelegateDeleted)
            {
                modLinkAttRequestBody.PropertyTag = propTagOfAddressBookPublicDelegate;
                modLinkAttRequestBody.MinimalId = this.minimalIDForDeleteAddressBookPublicDelegate;
                modLinkAttRequestBody.EntryIDs = new byte[][] { this.entryIDBufferForDeleteAddressBookPublicDelegate };

                ModLinkAttResponseBody modLinkAttResponseBodyForDeletePublicDelegates = this.Adapter.ModLinkAtt(modLinkAttRequestBody);
                this.Site.Assert.AreEqual<uint>((uint)0, modLinkAttResponseBodyForDeletePublicDelegates.ErrorCode, "The ModLinkAtt request to delete address book public delegates should be executed successfully, the returned value is {0}", modLinkAttResponseBodyForDeletePublicDelegates.ErrorCode);
            }

            base.TestCleanup();
        }
        public void MSOXCMAPIHTTP_S02_TC18_ModLinkAttRequestType()
        {
            this.CheckMapiHttpIsSupported();

            byte[] auxIn = new byte[] { };
   
            #region Call Bind request type to established a session context with the address book server.
            this.Bind();
            #endregion

            #region Call QueryRows request type to get a set of valid rows used to matched entry ID as the input paramter of ModLinkAtt method.
            STAT stat = new STAT();
            stat.InitiateStat();

            uint tableCount = 0;
            uint[] table = null;
            LargePropertyTagArray largePropTagArray = new LargePropertyTagArray()
            {
                PropertyTagCount = 4,
                PropertyTags = new PropertyTag[]
                {
                    new PropertyTag
                    {
                        PropertyType = (ushort)PropertyTypeValues.PtypString,
                        PropertyId = (ushort)PropertyID.PidTagDisplayName
                    }, 
                    new PropertyTag
                    {
                        PropertyType = (ushort)PropertyTypeValues.PtypBinary,
                        PropertyId = (ushort)PropertyID.PidTagEntryId
                    },
                    new PropertyTag
                    {
                        PropertyType = (ushort)PropertyTypeValues.PtypInteger32,
                        PropertyId = (ushort)PropertyID.PidTagDisplayType
                    },
                    new PropertyTag
                    {
                        PropertyType = (ushort)PropertyTypeValues.PtypMultipleString8,
                        PropertyId = (ushort)PropertyID.PidTagAddressBookMember
                    }
                }
            };

            QueryRowsRequestBody queryRowsRequestBody = new QueryRowsRequestBody();
            queryRowsRequestBody.Flags = (uint)RetrievePropertyFlags.fSkipObjects;
            queryRowsRequestBody.HasState = true;
            queryRowsRequestBody.State = stat;
            queryRowsRequestBody.ExplicitTableCount = tableCount;
            queryRowsRequestBody.ExplicitTable = table;
            queryRowsRequestBody.RowCount = ConstValues.QueryRowsRequestedRowNumber;
            queryRowsRequestBody.HasColumns = true;
            queryRowsRequestBody.Columns = largePropTagArray;
            queryRowsRequestBody.AuxiliaryBuffer = auxIn;
            queryRowsRequestBody.AuxiliaryBufferSize = (uint)auxIn.Length;

            QueryRowsResponseBody queryRowsResponseBody = this.Adapter.QueryRows(queryRowsRequestBody);
            Site.Assert.AreEqual<uint>(0, queryRowsResponseBody.ErrorCode, "QueryRows request should be executed successfully, the returned value {0}.", queryRowsResponseBody.ErrorCode);
            #endregion

            #region Capture code
            AddressBookPropertyRow[] rowData = queryRowsResponseBody.RowData;
            for (int i = 0; i < rowData.Length; i++)
            {
                List<AddressBookPropertyValue> valueArray = new List<AddressBookPropertyValue>(rowData[i].ValueArray);

                for (int j = 0; j < valueArray.Count; j++)
                {
                    if (largePropTagArray.PropertyTags[j].PropertyType == 0x001F)
                    {
                        // Add the debug information
                        this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMAPIHTTP_R2001");

                        // Verify MS-OXCMAPIHTTP requirement: MS-OXCMAPIHTTP_R2001
                        this.Site.CaptureRequirementIfIsInstanceOfType(
                            valueArray[j].HasValue,
                            typeof(byte),
                            2001,
                            @"[In AddressBookPropertyValue Structure] HasValue (optional) (1 byte): An unsigned integer when the PropertyType ([MS-OXCDATA] section 2.11.1) is known to be PtypString.");
                    }

                    if (largePropTagArray.PropertyTags[j].PropertyType == 0x0102)
                    {
                        // Add the debug information
                        this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMAPIHTTP_R2003");

                        // Verify MS-OXCMAPIHTTP requirement: MS-OXCMAPIHTTP_R2003
                        this.Site.CaptureRequirementIfIsInstanceOfType(
                            valueArray[j].HasValue,
                            typeof(byte),
                            2003,
                            @"[In AddressBookPropertyValue Structure] HasValue (optional) (1 byte): An unsigned integer when the PropertyType ([MS-OXCDATA] section 2.11.1) is known to be PtypBinary.");
                    }
                }
            }
            #endregion

            #region Call ModLinkAtt with flags 0x00000000 to add the specified PidTagAddressBookMember value.
            uint flagsOfModLinkAtt = 0;
            PropertyTag propTagOfModLinkAtt = new PropertyTag
            {
                PropertyType = (ushort)PropertyTypeValues.PtypEmbeddedTable,
                PropertyId = (ushort)PropertyID.PidTagAddressBookMember
            };
            uint midOfModLinkAtt = 0;
            byte[] entryId = null;
            GetPropsRequestBody getPropsRequestBodyForAddressBookMember = null;
            uint lengthOfErrorCodeValue = sizeof(uint);
            string dlistName = Common.GetConfigurationPropertyValue("DistributionListName", this.Site);
            string memberName = Common.GetConfigurationPropertyValue("GeneralUserName", this.Site);

            for (int i = 0; i < queryRowsResponseBody.RowCount; i++)
            {
                string name = System.Text.Encoding.Unicode.GetString(queryRowsResponseBody.RowData[i].ValueArray[0].Value);
                if (name.ToLower().Contains(dlistName.ToLower()))
                {
                    PermanentEntryID entryID = AdapterHelper.ParsePermanentEntryIDFromBytes(queryRowsResponseBody.RowData[i].ValueArray[1].Value);

                    DNToMinIdRequestBody requestBodyOfDNToMId = new DNToMinIdRequestBody()
                    {
                        Reserved = 0,
                        HasNames = true,
                        Names = new StringArray_r
                        {
                            CValues = 1,
                            LppzA = new string[]
                            {
                                entryID.DistinguishedName
                            }
                        },
                        AuxiliaryBuffer = auxIn,
                        AuxiliaryBufferSize = (uint)auxIn.Length
                    };
                    DnToMinIdResponseBody responseBodyOfDNToMinId = this.Adapter.DnToMinId(requestBodyOfDNToMId);
                    midOfModLinkAtt = responseBodyOfDNToMinId.MinimalIds[0];

                    stat.CurrentRec = midOfModLinkAtt;
                    STAT? statForGetProps = stat;
                    LargePropertyTagArray propertyTagForGetProps = new LargePropertyTagArray()
                    {
                        PropertyTagCount = 2,
                        PropertyTags = new PropertyTag[] 
                        {
                            new PropertyTag
                            {
                                PropertyType = (ushort)PropertyTypeValues.PtypInteger32,
                                PropertyId = (ushort)PropertyID.PidTagDisplayType
                            },
                            new PropertyTag
                            {
                                PropertyType = (ushort)PropertyTypeValues.PtypMultipleString8,
                                PropertyId = (ushort)PropertyID.PidTagAddressBookMember
                            },
                        }
                    };

                    getPropsRequestBodyForAddressBookMember = this.BuildGetPropsRequestBody((uint)0, true, statForGetProps, true, propertyTagForGetProps);
                    GetPropsResponseBody getPropsResponseBody = this.Adapter.GetProps(getPropsRequestBodyForAddressBookMember);
                    this.Site.Assert.AreEqual<uint>(0, getPropsResponseBody.StatusCode, "The GetProps request should be executed successfully, the returned status code is {0}", getPropsResponseBody.StatusCode);
                    this.Site.Assert.AreEqual<uint>(lengthOfErrorCodeValue, (uint)getPropsResponseBody.PropertyValues.Value.PropertyValues[1].Value.Length, "The length of the property value should be equal the ErrorCodeValue: Not Found(0x8004010F)");
                    uint propertyValue = BitConverter.ToUInt32(getPropsResponseBody.PropertyValues.Value.PropertyValues[1].Value, 0);
                    this.Site.Assert.AreEqual<uint>((uint)ErrorCodeValue.NotFound, propertyValue, "The property value of AddressBookMember should be Not Found(0x8004010F), actual value is {0}", propertyValue);
                }
                else if (name.ToLower().Contains(memberName.ToLower()))
                {
                    entryId = queryRowsResponseBody.RowData[i].ValueArray[1].Value;
                }

                if (midOfModLinkAtt != 0 && entryId != null)
                {
                    break;
                }
            }

            ModLinkAttRequestBody modLinkAttRequestBody = new ModLinkAttRequestBody();
            modLinkAttRequestBody.Flags = flagsOfModLinkAtt;
            modLinkAttRequestBody.PropertyTag = propTagOfModLinkAtt;
            modLinkAttRequestBody.MinimalId = midOfModLinkAtt;
            modLinkAttRequestBody.HasEntryIds = true;
            modLinkAttRequestBody.EntryIdCount = 1;
            modLinkAttRequestBody.EntryIDs = new byte[][] { entryId };
            modLinkAttRequestBody.AuxiliaryBuffer = auxIn;
            modLinkAttRequestBody.AuxiliaryBufferSize = (uint)auxIn.Length;
            this.minimalIDForDeleteAddressBookMember = midOfModLinkAtt;
            this.entryIDBufferForDeleteAddressBookMember = entryId;
            this.isAddressBookMemberDeleted = false;

            ModLinkAttResponseBody modLinkAttResponseBodyOfAdd = this.Adapter.ModLinkAtt(modLinkAttRequestBody);
            GetPropsResponseBody getPropsResponseBodyForAddAddressBookMember = this.Adapter.GetProps(getPropsRequestBodyForAddressBookMember);
            uint modifyDisplayType = BitConverter.ToUInt32(getPropsResponseBodyForAddAddressBookMember.PropertyValues.Value.PropertyValues[0].Value, 0);
            int propertyValuelength = getPropsResponseBodyForAddAddressBookMember.PropertyValues.Value.PropertyValues[1].Value.Length;

            if (getPropsResponseBodyForAddAddressBookMember.PropertyValues.Value.PropertyValues[1].PropertyType == 0x101E)
            {
                // Add the debug information
                this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMAPIHTTP_R2258");

                // Verify MS-OXCMAPIHTTP requirement: MS-OXCMAPIHTTP_R2258
                this.Site.CaptureRequirementIfIsInstanceOfType(
                getPropsResponseBodyForAddAddressBookMember.PropertyValues.Value.PropertyValues[1].HasValue,
                typeof(byte),
                2258,
                @"[In AddressBookPropertyValue Structure] HasValue (optional) (1 byte): An unsigned integer when the PropertyType ([MS-OXCDATA] section 2.11.1) is known to be PtypMultipleString8 ([MS-OXCDATA] section 2.11.1).");
            }

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

            // Verify MS-OXCMAPIHTTP requirement: MS-OXCMAPIHTTP_R724
            this.Site.CaptureRequirementIfAreEqual<uint>(
                0,
                modLinkAttResponseBodyOfAdd.ErrorCode,
                724,
                @"[In ModLinkAtt Request Type] The ModLinkAtt request type is used by the client to modify a specific property of a row in the address book.");

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMAPIHTTP_R1333, the DisplayTypeValues should be {0}, the length of the property value was changed from {1} to {2}.", DisplayTypeValues.DT_DISTLIST.ToString(), lengthOfErrorCodeValue, propertyValuelength);

            // Verify MS-OXCMAPIHTTP requirement: MS-OXCMAPIHTTP_R1333
            bool isVerifiedR1333 = (modifyDisplayType == (uint)DisplayTypeValues.DT_DISTLIST) && (propertyValuelength != lengthOfErrorCodeValue);

            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR1333,
                1333,
                @"[In ModLinkAtt Request Type Request Body] The PidTagAddressBookMember property ([MS-OXOABK] section 2.2.6.1) can be modified on an Address Book object that has a display type of DT_DISTLIST.");
            #endregion

            #region Call ModLinkAtt to delete the specified PidTagAddressBookMember value.
            modLinkAttRequestBody.Flags = 1;
            ModLinkAttResponseBody modLinkAttResponseBodyOfDelete = this.Adapter.ModLinkAtt(modLinkAttRequestBody);
            Site.Assert.AreEqual<uint>(0, modLinkAttResponseBodyOfDelete.ErrorCode, "ModLinkAtt request should be executed successfully, the returned error code is {0}.", modLinkAttResponseBodyOfDelete.ErrorCode);
            this.isAddressBookMemberDeleted = true;
            #endregion

            #region Call ModLinkAtt with flags 0x00000002 to add the specified PidTagAddressBookMember value.
            this.Site.Assert.IsTrue(this.isAddressBookMemberDeleted, "The previous added address book member should be deleted, actual is {0}", this.isAddressBookMemberDeleted);
            modLinkAttRequestBody.Flags = 2;
            ModLinkAttResponseBody modLinkAttResponseBodyFlags2 = this.Adapter.ModLinkAtt(modLinkAttRequestBody);
            Site.Assert.AreEqual<uint>(0, modLinkAttResponseBodyFlags2.ErrorCode, "ModLinkAtt request should be executed successfully, the returned error code is {0}.", modLinkAttResponseBodyFlags2.ErrorCode);
            this.isAddressBookMemberDeleted = false;

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

            // Verify MS-OXCMAPIHTTP requirement: MS-OXCMAPIHTTP_R1325
            this.Site.CaptureRequirementIfAreEqual<uint>(
                modLinkAttResponseBodyFlags2.ErrorCode,
                modLinkAttResponseBodyOfAdd.ErrorCode,
                1325,
                @"[In ModLinkAtt Request Type Request Body] If this field [Flags] is set to different values other than the bit flag fDelete (0x00000001), the server will return the same result.");
            #endregion

            #region Call ModLinkAtt to delete the specified PidTagAddressBookMember value.
            modLinkAttRequestBody.Flags = 1;
            ModLinkAttResponseBody modLinkAttResponseBodyOfDeleteWithFlags2 = this.Adapter.ModLinkAtt(modLinkAttRequestBody);
            Site.Assert.AreEqual<uint>(0, modLinkAttResponseBodyOfDeleteWithFlags2.ErrorCode, "The ModLinkAtt request to delete the address book member should be executed successfully, the actual returned error code is {0}.", modLinkAttResponseBodyOfDeleteWithFlags2.ErrorCode);
            this.isAddressBookMemberDeleted = true;
            #endregion

            #region Call ModLinkAtt request to add the specified PidTagAddressBookPublicDelegates value
            midOfModLinkAtt = 0;
            entryId = null;
            GetPropsRequestBody getPropsRequestBodyForPublicDelegates = null;
            memberName = Common.GetConfigurationPropertyValue("GeneralUserName", this.Site);

            PropertyTag pidTagAddressBookPublicDelegates = new PropertyTag();
            pidTagAddressBookPublicDelegates.PropertyType = (ushort)PropertyTypeValues.PtypMultipleString8;
            pidTagAddressBookPublicDelegates.PropertyId = (ushort)PropertyID.PidTagAddressBookPublicDelegates;

            for (int i = 0; i < queryRowsResponseBody.RowCount; i++)
            {
                string name = System.Text.Encoding.Unicode.GetString(queryRowsResponseBody.RowData[i].ValueArray[0].Value);
                if (name.ToLower().Contains(memberName.ToLower()))
                {
                    PermanentEntryID entryID = AdapterHelper.ParsePermanentEntryIDFromBytes(queryRowsResponseBody.RowData[i].ValueArray[1].Value);

                    DNToMinIdRequestBody requestBodyOfDNToMId = new DNToMinIdRequestBody()
                    {
                        Reserved = 0,
                        HasNames = true,
                        Names = new StringArray_r
                        {
                            CValues = 1,
                            LppzA = new string[]
                            {
                                entryID.DistinguishedName
                            }
                        },
                        AuxiliaryBuffer = auxIn,
                        AuxiliaryBufferSize = (uint)auxIn.Length
                    };

                    DnToMinIdResponseBody responseBodyOfDNToMinId = this.Adapter.DnToMinId(requestBodyOfDNToMId);
                    midOfModLinkAtt = responseBodyOfDNToMinId.MinimalIds[0];

                    stat.CurrentRec = midOfModLinkAtt;
                    STAT? statForGetProps = stat;
                    LargePropertyTagArray propertyTagForGetProps = new LargePropertyTagArray()
                    {
                        PropertyTagCount = 2,
                        PropertyTags = new PropertyTag[] 
                        {
                            new PropertyTag
                            {
                                PropertyType = (ushort)PropertyTypeValues.PtypInteger32,
                                PropertyId = (ushort)PropertyID.PidTagDisplayType
                            },
                            new PropertyTag
                            {
                                PropertyType = (ushort)PropertyTypeValues.PtypMultipleString8,
                                PropertyId = (ushort)PropertyID.PidTagAddressBookPublicDelegates
                            },
                        }
                    };

                    getPropsRequestBodyForPublicDelegates = this.BuildGetPropsRequestBody((uint)0, true, statForGetProps, true, propertyTagForGetProps);
                    GetPropsResponseBody getPropsResponseBody = this.Adapter.GetProps(getPropsRequestBodyForPublicDelegates);
                    this.Site.Assert.AreEqual<uint>(0, getPropsResponseBody.StatusCode, "The GetProps request should be executed successfully, the returned status code is {0}", getPropsResponseBody.StatusCode);
                    this.Site.Assert.AreEqual<uint>(lengthOfErrorCodeValue, (uint)getPropsResponseBody.PropertyValues.Value.PropertyValues[1].Value.Length, "The length of the property value should be equal the ErrorCodeValue: Not Found(0x8004010F)");
                    uint propertyValue = BitConverter.ToUInt32(getPropsResponseBody.PropertyValues.Value.PropertyValues[1].Value, 0);
                    this.Site.Assert.AreEqual<uint>((uint)ErrorCodeValue.NotFound, propertyValue, "The property value of AddressBookPublicDelegates should be Not Found(0x8004010F), actual value is {0}", propertyValue);
                }
                else if (name.ToLower().Contains(this.AdminUserName.ToLower()))
                {
                    entryId = queryRowsResponseBody.RowData[i].ValueArray[1].Value;
                }

                if (midOfModLinkAtt != 0 && entryId != null)
                {
                    break;
                }
            }

            ModLinkAttRequestBody modLinkAttRequestBodyForPublicDelegates = new ModLinkAttRequestBody();
            modLinkAttRequestBodyForPublicDelegates.Flags = 0;
            modLinkAttRequestBodyForPublicDelegates.PropertyTag = pidTagAddressBookPublicDelegates;
            modLinkAttRequestBodyForPublicDelegates.MinimalId = midOfModLinkAtt;
            modLinkAttRequestBodyForPublicDelegates.HasEntryIds = true;
            modLinkAttRequestBodyForPublicDelegates.EntryIdCount = 1;
            modLinkAttRequestBodyForPublicDelegates.EntryIDs = new byte[][] { entryId };
            modLinkAttRequestBodyForPublicDelegates.AuxiliaryBuffer = auxIn;
            modLinkAttRequestBodyForPublicDelegates.AuxiliaryBufferSize = (uint)auxIn.Length;
            this.minimalIDForDeleteAddressBookPublicDelegate = midOfModLinkAtt;
            this.entryIDBufferForDeleteAddressBookPublicDelegate = entryId;
            this.isAddressBookPublicDelegateDeleted = false;

            ModLinkAttResponseBody modLinkAttResponseBodyForAddPublicDelegates = this.Adapter.ModLinkAtt(modLinkAttRequestBodyForPublicDelegates);

            GetPropsResponseBody getPropsResponseBodyForAddPublicDelegates = this.Adapter.GetProps(getPropsRequestBodyForPublicDelegates);
            modifyDisplayType = BitConverter.ToUInt32(getPropsResponseBodyForAddPublicDelegates.PropertyValues.Value.PropertyValues[0].Value, 0);
            propertyValuelength = getPropsResponseBodyForAddPublicDelegates.PropertyValues.Value.PropertyValues[1].Value.Length;

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMAPIHTTP_R1335, the DisplayTypeValues should be {0}, the length of the property value was changed from {1} to {2}.", DisplayTypeValues.DT_MAILUSER.ToString(), lengthOfErrorCodeValue, propertyValuelength);

            // Verify MS-OXCMAPIHTTP requirement: MS-OXCMAPIHTTP_R1335
            bool isVerifiedR1335 = (modifyDisplayType == (uint)DisplayTypeValues.DT_MAILUSER) && (propertyValuelength != lengthOfErrorCodeValue);

            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR1335,
                1335,
                @"[In ModLinkAtt Request Type Request Body] The PidTagAddressBookPublicDelegates property ([MS-OXOABK] section 2.2.5.5) can be modified on an Address Book object that has a display type of DT_MAILUSER.");

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMAPIHTTP_R740, the minimal ID should be {0}, the length of the property value was changed from {1} to {2}.", midOfModLinkAtt, lengthOfErrorCodeValue, propertyValuelength);

            // Verify MS-OXCMAPIHTTP requirement: MS-OXCMAPIHTTP_R740
            bool isVerifiedR740 = (midOfModLinkAtt == (uint)getPropsRequestBodyForPublicDelegates.State.CurrentRec) && ((uint)propertyValuelength != lengthOfErrorCodeValue);

            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR740,
                740,
                @"[In ModLinkAtt Request Type Request Body] MinimalId (4 bytes): A MinimalEntryID structure ([MS-OXNSPI] section 2.3.8.1) that specifies the Minimal Entry ID of the address book row to be modified.");

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

            // Verify MS-OXCMAPIHTTP requirement: MS-OXCMAPIHTTP_R746, the length of the property value is different, means the property was modified.
            this.Site.CaptureRequirementIfAreNotEqual<uint>(
                lengthOfErrorCodeValue,
                (uint)propertyValuelength,
                746,
                @"[In ModLinkAtt Request Type Request Body] EntryIds: Each entry ID in the array specifies an address book row in which the specified property is to be modified.");
            #endregion

            #region Call ModLinkAtt request to delete the specified PidTagAddressBookPublicDelegates value
            modLinkAttRequestBodyForPublicDelegates.Flags = 1;
            ModLinkAttResponseBody modLinkAttResponseBodyForDeletePublicDelegates = this.Adapter.ModLinkAtt(modLinkAttRequestBodyForPublicDelegates);
            this.Site.Assert.AreEqual<uint>((uint)0, modLinkAttResponseBodyForDeletePublicDelegates.ErrorCode, "The ModLinkAtt request to delete address book public delegates should be executed successfully, the returned value is {0}", modLinkAttResponseBodyForDeletePublicDelegates.ErrorCode);
            this.isAddressBookPublicDelegateDeleted = true;
            #endregion

            #region Call Unbind request to destroy the session between the client and the server.
            this.Unbind();
            #endregion
        }
        public void MSOXCMAPIHTTP_S02_TC21_TestHasValueWithPropertyTypePtypMultipleString()
        {
            this.CheckMapiHttpIsSupported();

            byte[] auxIn = new byte[] { };

            #region Call Bind request type to established a session context with the address book server.
            this.Bind();
            #endregion

            #region Call QueryRows request type to get a set of valid rows used to matched entry ID as the input paramter of ModLinkAtt method.
            STAT stat = new STAT();
            stat.InitiateStat();

            uint tableCount = 0;
            uint[] table = null;
            LargePropertyTagArray largePropTagArray = new LargePropertyTagArray()
            {
                PropertyTagCount = 4,
                PropertyTags = new PropertyTag[]
                {
                    new PropertyTag
                    {
                        PropertyType = (ushort)PropertyTypeValues.PtypString,
                        PropertyId = (ushort)PropertyID.PidTagDisplayName
                    }, 
                    new PropertyTag
                    {
                        PropertyType = (ushort)PropertyTypeValues.PtypBinary,
                        PropertyId = (ushort)PropertyID.PidTagEntryId
                    },
                    new PropertyTag
                    {
                        PropertyType = (ushort)PropertyTypeValues.PtypInteger32,
                        PropertyId = (ushort)PropertyID.PidTagDisplayType
                    },
                    new PropertyTag
                    {
                        PropertyType = (ushort)PropertyTypeValues.PtypMultipleString,
                        PropertyId = (ushort)PropertyID.PidTagAddressBookMember
                    }
                }
            };

            QueryRowsRequestBody queryRowsRequestBody = new QueryRowsRequestBody();
            queryRowsRequestBody.Flags = (uint)RetrievePropertyFlags.fSkipObjects;
            queryRowsRequestBody.HasState = true;
            queryRowsRequestBody.State = stat;
            queryRowsRequestBody.ExplicitTableCount = tableCount;
            queryRowsRequestBody.ExplicitTable = table;
            queryRowsRequestBody.RowCount = ConstValues.QueryRowsRequestedRowNumber;
            queryRowsRequestBody.HasColumns = true;
            queryRowsRequestBody.Columns = largePropTagArray;
            queryRowsRequestBody.AuxiliaryBuffer = auxIn;
            queryRowsRequestBody.AuxiliaryBufferSize = (uint)auxIn.Length;

            QueryRowsResponseBody queryRowsResponseBody = this.Adapter.QueryRows(queryRowsRequestBody);
            Site.Assert.AreEqual<uint>(0, queryRowsResponseBody.ErrorCode, "QueryRows request should be executed successfully, the returned value {0}.", queryRowsResponseBody.ErrorCode);
            #endregion

            #region Call ModLinkAtt with flags 0x00000000 to add the specified PidTagAddressBookMember value.
            uint flagsOfModLinkAtt = 0;
            PropertyTag propTagOfModLinkAtt = new PropertyTag
            {
                PropertyType = (ushort)PropertyTypeValues.PtypEmbeddedTable,
                PropertyId = (ushort)PropertyID.PidTagAddressBookMember
            };
            uint midOfModLinkAtt = 0;
            byte[] entryId = null;
            GetPropsRequestBody getPropsRequestBodyForAddressBookMember = null;
            uint lengthOfErrorCodeValue = sizeof(uint);
            string dlistName = Common.GetConfigurationPropertyValue("DistributionListName", this.Site);
            string memberName = Common.GetConfigurationPropertyValue("GeneralUserName", this.Site);

            for (int i = 0; i < queryRowsResponseBody.RowCount; i++)
            {
                string name = System.Text.Encoding.Unicode.GetString(queryRowsResponseBody.RowData[i].ValueArray[0].Value);
                if (name.ToLower().Contains(dlistName.ToLower()))
                {
                    PermanentEntryID entryID = AdapterHelper.ParsePermanentEntryIDFromBytes(queryRowsResponseBody.RowData[i].ValueArray[1].Value);

                    DNToMinIdRequestBody requestBodyOfDNToMId = new DNToMinIdRequestBody()
                    {
                        Reserved = 0,
                        HasNames = true,
                        Names = new StringArray_r
                        {
                            CValues = 1,
                            LppzA = new string[]
                            {
                                entryID.DistinguishedName
                            }
                        },
                        AuxiliaryBuffer = auxIn,
                        AuxiliaryBufferSize = (uint)auxIn.Length
                    };
                    DnToMinIdResponseBody responseBodyOfDNToMinId = this.Adapter.DnToMinId(requestBodyOfDNToMId);
                    midOfModLinkAtt = responseBodyOfDNToMinId.MinimalIds[0];

                    stat.CurrentRec = midOfModLinkAtt;
                    STAT? statForGetProps = stat;
                    LargePropertyTagArray propertyTagForGetProps = new LargePropertyTagArray()
                    {
                        PropertyTagCount = 2,
                        PropertyTags = new PropertyTag[] 
                        {
                            new PropertyTag
                            {
                                PropertyType = (ushort)PropertyTypeValues.PtypInteger32,
                                PropertyId = (ushort)PropertyID.PidTagDisplayType
                            },
                            new PropertyTag
                            {
                                PropertyType = (ushort)PropertyTypeValues.PtypMultipleString,
                                PropertyId = (ushort)PropertyID.PidTagAddressBookMember
                            },
                        }
                    };

                    getPropsRequestBodyForAddressBookMember = this.BuildGetPropsRequestBody((uint)0, true, statForGetProps, true, propertyTagForGetProps);
                    GetPropsResponseBody getPropsResponseBody = this.Adapter.GetProps(getPropsRequestBodyForAddressBookMember);
                    this.Site.Assert.AreEqual<uint>(0, getPropsResponseBody.StatusCode, "The GetProps request should be executed successfully, the returned status code is {0}", getPropsResponseBody.StatusCode);
                    this.Site.Assert.AreEqual<uint>(lengthOfErrorCodeValue, (uint)getPropsResponseBody.PropertyValues.Value.PropertyValues[1].Value.Length, "The length of the property value should be equal the ErrorCodeValue: Not Found(0x8004010F)");
                    uint propertyValue = BitConverter.ToUInt32(getPropsResponseBody.PropertyValues.Value.PropertyValues[1].Value, 0);
                    this.Site.Assert.AreEqual<uint>((uint)ErrorCodeValue.NotFound, propertyValue, "The property value of AddressBookMember should be Not Found(0x8004010F), actual value is {0}", propertyValue);
                }
                else if (name.ToLower().Contains(memberName.ToLower()))
                {
                    entryId = queryRowsResponseBody.RowData[i].ValueArray[1].Value;
                }

                if (midOfModLinkAtt != 0 && entryId != null)
                {
                    break;
                }
            }

            ModLinkAttRequestBody modLinkAttRequestBody = new ModLinkAttRequestBody();
            modLinkAttRequestBody.Flags = flagsOfModLinkAtt;
            modLinkAttRequestBody.PropertyTag = propTagOfModLinkAtt;
            modLinkAttRequestBody.MinimalId = midOfModLinkAtt;
            modLinkAttRequestBody.HasEntryIds = true;
            modLinkAttRequestBody.EntryIdCount = 1;
            modLinkAttRequestBody.EntryIDs = new byte[][] { entryId };
            modLinkAttRequestBody.AuxiliaryBuffer = auxIn;
            modLinkAttRequestBody.AuxiliaryBufferSize = (uint)auxIn.Length;
            this.minimalIDForDeleteAddressBookMember = midOfModLinkAtt;
            this.entryIDBufferForDeleteAddressBookMember = entryId;
            this.isAddressBookMemberDeleted = false;

            ModLinkAttResponseBody modLinkAttResponseBodyOfAdd = this.Adapter.ModLinkAtt(modLinkAttRequestBody);
            GetPropsResponseBody getPropsResponseBodyForAddAddressBookMember = this.Adapter.GetProps(getPropsRequestBodyForAddressBookMember);
            uint modifyDisplayType = BitConverter.ToUInt32(getPropsResponseBodyForAddAddressBookMember.PropertyValues.Value.PropertyValues[0].Value, 0);
            int propertyValuelength = getPropsResponseBodyForAddAddressBookMember.PropertyValues.Value.PropertyValues[1].Value.Length;

            if (getPropsResponseBodyForAddAddressBookMember.PropertyValues.Value.PropertyValues[1].PropertyType == 0x101F)
            {
                // Add the debug information
                this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMAPIHTTP_R2257");

                // Verify MS-OXCMAPIHTTP requirement: MS-OXCMAPIHTTP_R2257
                this.Site.CaptureRequirementIfIsInstanceOfType(
                getPropsResponseBodyForAddAddressBookMember.PropertyValues.Value.PropertyValues[1].HasValue,
                typeof(byte),
                2257,
                @"[In AddressBookPropertyValue Structure] HasValue (optional) (1 byte): An unsigned integer when the PropertyType ([MS-OXCDATA] section 2.11.1) is known to be PtypMultipleString ([MS-OXCDATA] section 2.11.1).");
            }
            #endregion

            #region Call ModLinkAtt to delete the specified PidTagAddressBookMember value.
            modLinkAttRequestBody.Flags = 1;
            ModLinkAttResponseBody modLinkAttResponseBodyOfDelete = this.Adapter.ModLinkAtt(modLinkAttRequestBody);
            Site.Assert.AreEqual<uint>(0, modLinkAttResponseBodyOfDelete.ErrorCode, "ModLinkAtt request should be executed successfully, the returned error code is {0}.", modLinkAttResponseBodyOfDelete.ErrorCode);
            this.isAddressBookMemberDeleted = true;
            #endregion

            #region Call Unbind request to destroy the session between the client and the server.
            this.Unbind();
            #endregion
        }
        /// <summary>
        /// This method is used by the client to modify a specific property of a row in the address book.
        /// </summary>
        /// <param name="modLinkAttRequestBody">The ModLinkAtt request type request body.</param>
        /// <returns>The response body of the ModLinkAtt request type.</returns>
        public ModLinkAttResponseBody ModLinkAtt(ModLinkAttRequestBody modLinkAttRequestBody)
        {
            CommonResponse commonResponse = this.SendAddressBookRequest(modLinkAttRequestBody, RequestType.ModLinkAtt);
            ModLinkAttResponseBody modLinkAttResponseBody = ModLinkAttResponseBody.Parse(commonResponse.ResponseBodyRawData);
            this.VerifyModLinkAttResponseBody(modLinkAttResponseBody);

            return modLinkAttResponseBody;
        }