/// <summary>
        /// The NspiQueryRows method returns a number of rows from a specified table to the client.
        /// </summary>
        /// <param name="flags">A DWORD value that contains a set of bit flags.</param>
        /// <param name="stat">A STAT block that describes a logical position in a specific address book container.</param>
        /// <param name="tableCount">A DWORD value that contains the number values in the input parameter table. 
        /// This value is limited to 100,000.</param>
        /// <param name="table">An array of DWORD values, representing an Explicit Table.</param>
        /// <param name="count">A DWORD value that contains the number of rows the client is requesting.</param>
        /// <param name="propTags">The value NULL or a reference to a PropertyTagArray_r value, 
        /// containing a list of the proptags of the properties that the client requires to be returned for each row returned.</param>
        /// <param name="rows">A nullable PropertyRowSet_r value, it contains the address book container rows that the server returns in response to the request.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue QueryRows(uint flags, ref STAT stat, uint tableCount, uint[] table, uint count, PropertyTagArray_r? propTags, out PropertyRowSet_r? rows)
        {
            ErrorCodeValue result;
            QueryRowsRequestBody queryRowsRequestBody = new QueryRowsRequestBody();
            LargePropTagArray propetyTags = new LargePropTagArray();
            if (propTags != null)
            {
                propetyTags.PropertyTagCount = propTags.Value.CValues;
                propetyTags.PropertyTags = new PropertyTag[propetyTags.PropertyTagCount];
                for (int i = 0; i < propTags.Value.CValues; i++)
                {
                    propetyTags.PropertyTags[i].PropertyId = (ushort)((propTags.Value.AulPropTag[i] & 0xFFFF0000) >> 16);
                    propetyTags.PropertyTags[i].PropertyType = (ushort)(propTags.Value.AulPropTag[i] & 0x0000FFFF);
                }

                queryRowsRequestBody.HasColumns = true;
                queryRowsRequestBody.Columns = propetyTags;
            }

            queryRowsRequestBody.Flags = flags;
            queryRowsRequestBody.HasState = true;
            queryRowsRequestBody.State = stat;
            queryRowsRequestBody.ExplicitTableCount = tableCount;
            queryRowsRequestBody.ExplicitTable = table;
            queryRowsRequestBody.RowCount = count;
            byte[] auxIn = new byte[] { };
            queryRowsRequestBody.AuxiliaryBuffer = auxIn;
            queryRowsRequestBody.AuxiliaryBufferSize = (uint)auxIn.Length;

            ChunkedResponse chunkedResponse = this.SendAddressBookRequest(queryRowsRequestBody, RequestType.QueryRows);
            QueryRowsResponseBody queryRowsResponseBody = QueryRowsResponseBody.Parse(chunkedResponse.ResponseBodyRawData);
            result = (ErrorCodeValue)queryRowsResponseBody.ErrorCode;
            if (queryRowsResponseBody.RowCount != null)
            {
                PropertyRowSet_r newRows = AdapterHelper.ParsePropertyRowSet_r(queryRowsResponseBody.Columns.Value, queryRowsResponseBody.RowCount.Value, queryRowsResponseBody.RowData);
                rows = newRows;
            }
            else
            {
                rows = null;
            }

            if (queryRowsResponseBody.HasState)
            {
                stat = queryRowsResponseBody.State.Value;
            }

            return result;
        }
        public void MSOXNSPI_S04_TC02_ModLinkAttSuccessWithPidTagAddressBookMember()
        {
            this.CheckProductSupported();
            this.CheckMAPIHTTPTransportSupported();
            bool isR2003009Enabled = Common.IsRequirementEnabled(2003009, this.Site);

            #region Call NspiBind to initiate a session between the client and the server.
            uint flags = 0;
            STAT stat = new STAT();
            stat.InitiateStat();
            FlatUID_r guid = new FlatUID_r
            {
                Ab = new byte[16]
            };
            FlatUID_r? serverGuid = guid;

            this.Result = this.ProtocolAdatper.NspiBind(flags, stat, ref serverGuid);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiBind should return Success!");

            #endregion

            #region Call NspiGetMatches method to get the valid Minimal Entry IDs and rows.
            uint reserved1 = 0;
            uint reserver2 = 0;
            PropertyTagArray_r? proReserved = null;
            uint requested = Constants.GetMatchesRequestedRowNumber;

            // Create Restriction_r structure to use the display name of specific user as the filter parameter of NspiGetMatches method.
            Restriction_r propertyRestriction1 = new Restriction_r
            {
                Rt = 0x04,
                Res = new RestrictionUnion_r
                {
                    ResProperty = new Propertyrestriction_r
                    {
                        Relop = 0x04
                    }
                }
            };
            PropertyValue_r target = new PropertyValue_r
            {
                PropTag = (uint)AulProp.PidTagDisplayName,
                Reserved = 0
            };
            string memberName = Common.GetConfigurationPropertyValue("User2Name", this.Site);
            if (this.Transport == "ncacn_http" || this.Transport == "ncacn_ip_tcp")
            {
                target.Value.LpszA = System.Text.Encoding.UTF8.GetBytes(memberName);
            }
            else
            {
                target.Value.LpszA = System.Text.Encoding.UTF8.GetBytes(memberName + "\0");
            }

            propertyRestriction1.Res.ResProperty.Prop = new PropertyValue_r[] { target };
            propertyRestriction1.Res.ResProperty.PropTag = (uint)AulProp.PidTagDisplayName;

            Restriction_r propertyRestriction2 = new Restriction_r
            {
                Rt = 0x04,
                Res = new RestrictionUnion_r
                {
                    ResProperty = new Propertyrestriction_r
                    {
                        Relop = 0x04
                    }
                }
            };
            string dlistName = Common.GetConfigurationPropertyValue("DistributionListName", this.Site);
            if (this.Transport == "ncacn_http" || this.Transport == "ncacn_ip_tcp")
            {
                target.Value.LpszA = System.Text.Encoding.UTF8.GetBytes(dlistName);
            }
            else
            {
                target.Value.LpszA = System.Text.Encoding.UTF8.GetBytes(dlistName + "\0");
            }

            propertyRestriction2.Res.ResProperty.Prop = new PropertyValue_r[] { target };
            propertyRestriction2.Res.ResProperty.PropTag = (uint)AulProp.PidTagDisplayName;

            Restriction_r restrictionOr = new Restriction_r
            {
                Rt = 0x01,
                Res =
                    new RestrictionUnion_r
                    {
                        ResOr = new OrRestriction_r
                        {
                            CRes = 2,
                            LpRes = new Restriction_r[]
                            {
                                propertyRestriction1, propertyRestriction2
                            }
                        }
                    }
            };

            Restriction_r? filter = restrictionOr;

            PropertyName_r? propNameOfGetMatches = null;
            PropertyTagArray_r propTags = new PropertyTagArray_r
            {
                CValues = 3,
                AulPropTag = new uint[3]
                {
                    (uint)AulProp.PidTagEntryId,
                    (uint)AulProp.PidTagDisplayName,
                    unchecked((uint)AulProp.PidTagAddressBookMember),
                }
            };

            PropertyTagArray_r? propTagsOfGetMatches = propTags;

            // Output parameters.
            PropertyTagArray_r? outMIds;
            PropertyRowSet_r? rowsOfGetMatches;

            this.Result = this.ProtocolAdatper.NspiGetMatches(reserved1, ref stat, proReserved, reserver2, filter, propNameOfGetMatches, requested, out outMIds, propTagsOfGetMatches, out rowsOfGetMatches);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiGetMatches should return Success!");
            #endregion

            #region Call NspiModLinkAtt method with the specified PidTagAddressBookMember value.
            uint flagsOfModLinkAtt = 0; // A value which does not contain fDelete flag (0x1).
            uint propTagOfModLinkAtt = (uint)AulProp.PidTagAddressBookMember;
            uint midOfModLinkAtt = 0;
            BinaryArray_r entryId = new BinaryArray_r
            {
                CValues = 1,
                Lpbin = new Binary_r[1]
            };

            int i;
            string name = string.Empty;
            for (i = 0; i < rowsOfGetMatches.Value.CRows; i++)
            {
                name = System.Text.Encoding.Default.GetString(rowsOfGetMatches.Value.ARow[i].LpProps[1].Value.LpszA);

                // Server will ignore cases when comparing string according to section 2.2.6 in Open Specification MS-OXNSPI.
                if (name.ToLower(System.Globalization.CultureInfo.CurrentCulture).Equals(dlistName.ToLower(System.Globalization.CultureInfo.CurrentCulture)))
                {
                    // The current Address Book object is a distribution list.
                    // Save the distribution list location.
                    midOfModLinkAtt = outMIds.Value.AulPropTag[i];
                    this.MidToBeModified = midOfModLinkAtt;
                }
                else if (name.ToLower(System.Globalization.CultureInfo.CurrentCulture).Equals(memberName.ToLower(System.Globalization.CultureInfo.CurrentCulture)))
                {
                    // Save the EntryID of this user which will be added as a member of the distribution list.
                    entryId.Lpbin[0] = rowsOfGetMatches.Value.ARow[i].LpProps[0].Value.Bin;
                    this.EntryIdToBeDeleted = entryId;
                }

                if (this.MidToBeModified != 0 && this.EntryIdToBeDeleted.Lpbin[0].Cb != 0)
                {
                    break;
                }
            }

            Site.Assert.AreEqual<uint>(0x87, entryId.Lpbin[0].Lpb[0], "Ephemeral Entry ID's ID Type should be 0x87.");
            this.IsEphemeralEntryID = true;

            // Add the property value.
            ErrorCodeValue result1;
            if (!isR2003009Enabled)
            {
                result1 = this.ProtocolAdatper.NspiModLinkAtt(flagsOfModLinkAtt, propTagOfModLinkAtt, midOfModLinkAtt, entryId);

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

                // Verify MS-OXNSPI requirement: MS-OXNSPI_R1340
                Site.CaptureRequirementIfAreEqual<ErrorCodeValue>(
                    ErrorCodeValue.Success,
                    result1,
                    1340,
                    @"[In NspiModLinkAtt] [Server Processing Rules: Upon receiving message NspiModLinkAtt, the server MUST process the data from the message subject to the following constraints:] [Constraint 9] If no other return values have been specified by these constraints [constraints 1-8], the server MUST return the return value ""Success"" (0x00000000).");
            }
            else
            {
                result1 = this.ProtocolAdatper.NspiModLinkAtt(flagsOfModLinkAtt, propTagOfModLinkAtt, midOfModLinkAtt, entryId, false);

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

                // Verify MS-OXNSPI requirement: MS-OXNSPI_R2003009
                Site.CaptureRequirementIfAreEqual<ErrorCodeValue>(
                    ErrorCodeValue.GeneralFailure,
                    result1,
                    2003009,
                    @"[In Appendix A: Product Behavior] Implementation does return ""GeneralFailure"" when modify either the PidTagAddressBookMember property or the PidTagAddressBookPublicDelegates property of any objects in the address book. <6> Section 3.1.4.1.15:  Exchange 2013 and Exchange 2016 return ""GeneralFailure"" (0x80004005) when modification of either the PidTagAddressBookMember property ([MS-OXOABK] section 2.2.6.1) or the PidTagAddressBookPublicDelegates property ([MS-OXOABK] section 2.2.5.5) is attempted.");
            }

            this.IsRequireToDeleteAddressBookMember = true;
            #endregion

            #region Call NspiGetMatches to check the NspiModLinkAtt result.
            this.Result = this.ProtocolAdatper.NspiGetMatches(reserved1, ref stat, proReserved, reserver2, filter, propNameOfGetMatches, requested, out outMIds, propTagsOfGetMatches, out rowsOfGetMatches);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiGetMatches should return Success!");

            #region Capture code
            // PidTagAddressBookMember proptag after adding value.
            uint addressBookMemberTagAfterAdd = 0;
            for (i = 0; i < rowsOfGetMatches.Value.CRows; i++)
            {
                name = System.Text.Encoding.Default.GetString(rowsOfGetMatches.Value.ARow[i].LpProps[1].Value.LpszA);

                // Server will ignore cases when comparing string according to section 2.2.6 in Open Specification MS-OXNSPI.
                if (name.ToLower(System.Globalization.CultureInfo.CurrentCulture).Equals(dlistName.ToLower(System.Globalization.CultureInfo.CurrentCulture)))
                {
                    // After adding value this value should not be 0x8009000a.
                    addressBookMemberTagAfterAdd = rowsOfGetMatches.Value.ARow[i].LpProps[2].PropTag;

                    break;
                }
            }

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-OXNSPI_R1335, the property tag of address book member after adding value is {0}",
                addressBookMemberTagAfterAdd);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1335
            // The proptag of PidTagAddressBookMember property is 0x8009101e as defined in [MS-OXPROPS]. If the last four bytes is 0x000a when being returned, it means that the property has no value.
            // Since the property has no value before the NspiModLinkAtt method is called and has value after that, this requirement can be verified.
            Site.CaptureRequirementIfIsTrue(
                addressBookMemberTagAfterAdd != 0x8009000a,
                1335,
                @"[In NspiModLinkAtt] [Server Processing Rules: Upon receiving message NspiModLinkAtt, the server MUST process the data from the message subject to the following constraints:] [Constraint 7] If the input parameter dwFlags does not contain the bit value fDelete, the server MUST add all values specified by the input parameter lpEntryIDs to the property specified by ulPropTag for the object specified by the input parameter dwMId.");

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-OXNSPI_R129, the property tag of address book member after adding value is {0}",
                addressBookMemberTagAfterAdd);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R129
            // Since the property has no value before the NspiModLinkAtt method is called and has value after that, this requirement can be verified.
            Site.CaptureRequirementIfIsTrue(
                addressBookMemberTagAfterAdd != 0x8009000a,
                129,
                @"[In NspiModLinkAtt Flags] If the fDelete flag is not set, the server adds values when modifying.");

            // MS-OXNSPI_R129 has already verified that modifying property PidTagAddressBookMember succeeds, so MS-OXNSPI_R1893 can be verified directly here.
            this.Site.CaptureRequirement(
                1893,
                @"[In NspiModLinkAtt] This protocol supports modifying the value of the PidTagAddressBookMember ([MS-OXPROPS] section 2.541) property of an address book object with display type DT_DISTLIST.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1306
            this.Site.CaptureRequirement(
                1306,
                @"[In NspiModLinkAtt] The NspiModLinkAtt method modifies the values of a specific property of a specific row in the address book.");

            #endregion
            #endregion

            #region Call NspiModLinkAtt with fDelete flag to delete the specified value.
            flagsOfModLinkAtt = (uint)NspiModLinkAtFlag.fDelete;
            ErrorCodeValue result2;
            if (!isR2003009Enabled)
            {
                result2 = this.ProtocolAdatper.NspiModLinkAtt(flagsOfModLinkAtt, propTagOfModLinkAtt, midOfModLinkAtt, entryId);
                Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, result2, "NspiModLinkAtt method should return Success.");
            }
            else
            {
                result2 = this.ProtocolAdatper.NspiModLinkAtt(flagsOfModLinkAtt, propTagOfModLinkAtt, midOfModLinkAtt, entryId, false);
            }

            this.IsRequireToDeleteAddressBookMember = false;
            #endregion

            #region Call NspiGetMatches to check the NspiModLinkAtt delete result.
            this.Result = this.ProtocolAdatper.NspiGetMatches(reserved1, ref stat, proReserved, reserver2, filter, propNameOfGetMatches, requested, out outMIds, propTagsOfGetMatches, out rowsOfGetMatches);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiGetMatches should return Success!");

            #region Capture code
            bool isDeleteSuccess = false;
            for (i = 0; i < rowsOfGetMatches.Value.CRows; i++)
            {
                name = System.Text.Encoding.Default.GetString(rowsOfGetMatches.Value.ARow[i].LpProps[1].Value.LpszA);

                // Server will ignore cases when comparing string according to section 2.2.6 in Open Specification MS-OXNSPI.
                if (name.ToLower(System.Globalization.CultureInfo.CurrentCulture).Equals(dlistName.ToLower(System.Globalization.CultureInfo.CurrentCulture)))
                {
                    // 0x8009000A means that no member exists in distribute list, so the added member has been deleted.
                    if (rowsOfGetMatches.Value.ARow[i].LpProps[2].PropTag == 0x8009000A)
                    {
                        isDeleteSuccess = true;
                        break;
                    }
                }
            }

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1332: the returned PidTagAddressBookMember proptag value of the address book object named {0} is {1}", name, rowsOfGetMatches.Value.ARow[i].LpProps[2].PropTag);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1332
            // 0x8009000A means that no member exists in distribute list, so the added member has been deleted.
            Site.CaptureRequirementIfIsTrue(
                isDeleteSuccess,
                1332,
                @"[In NspiModLinkAtt] [Server Processing Rules: Upon receiving message NspiModLinkAtt, the server MUST process the data from the message subject to the following constraints:] [Constraint 6] If the input parameter dwFlags contains the bit value fDelete, the server MUST remove all values specified by the input parameter lpEntryIDs from the property specified by ulPropTag for the object specified by input parameter dwMId.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R128: the returned PidTagAddressBookMember property tag value of the address book object named {0} is {1}", name, rowsOfGetMatches.Value.ARow[i].LpProps[2].PropTag);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R128
            // 0x8009000A means that no member exists in distribute list, so the added member has been deleted.
            Site.CaptureRequirementIfIsTrue(
                isDeleteSuccess,
                128,
                @"[In NspiModLinkAtt Flags] fDelete (0x00000001): Specifies that the server is to remove values when modifying.");

            #endregion
            #endregion

            #region Call NspiModLinkAtt to add value with the changed Display Type in EphemeralEntryID.
            // If the original display type is DT_MAILUSER (0x00), change it to DT_PRIVATE_DISTLIST (0x05), otherwise to DT_MAILUSER (0x00), to see if the server ignores this field.
            // The Display Type begins with the 25th position in the Entry ID structure.
            if (entryId.Lpbin[0].Lpb[24] == 0x00)
            {
                entryId.Lpbin[0].Lpb[24] = 0x05;
            }
            else
            {
                entryId.Lpbin[0].Lpb[24] = 0x00;
            }

            ErrorCodeValue result3;
            if (!isR2003009Enabled)
            {
                result3 = this.ProtocolAdatper.NspiModLinkAtt(flagsOfModLinkAtt, propTagOfModLinkAtt, midOfModLinkAtt, entryId);
                Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, result3, "NspiModLinkAtt method should return Success.");
            }
            else
            {
                result3 = this.ProtocolAdatper.NspiModLinkAtt(flagsOfModLinkAtt, propTagOfModLinkAtt, midOfModLinkAtt, entryId, false);
            }

            this.IsRequireToDeleteAddressBookMember = true;
            this.EntryIdToBeDeleted = entryId;
            #endregion

            #region Call NspiModLinkAtt to delete value with the changed Display Type in EphemeralEntryID.
            flagsOfModLinkAtt = (uint)NspiModLinkAtFlag.fDelete;
            ErrorCodeValue result4;
            if (!isR2003009Enabled)
            {
                result4 = this.ProtocolAdatper.NspiModLinkAtt(flagsOfModLinkAtt, propTagOfModLinkAtt, midOfModLinkAtt, entryId);
                Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, result4, "NspiModLinkAtt method should return Success.");
            }
            else
            {
                result4 = this.ProtocolAdatper.NspiModLinkAtt(flagsOfModLinkAtt, propTagOfModLinkAtt, midOfModLinkAtt, entryId, false);
            }

            this.IsRequireToDeleteAddressBookMember = false;

            #region Capture code
            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-OXNSPI_R1665, the value of result1 is {0}, the value of result2 is {1}, the value of result3 is {2}, the value of result4 is {3}",
                result1,
                result2,
                result3,
                result4);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1665
            // Since the server returns the same value when the display type field is set to different values in the input parameter, whenever the property value is to be added (result1 and result3) or to be deleted (result2 and result4), this requirement can be verified.
            Site.CaptureRequirementIfIsTrue(
                result1 == result3 && result2 == result4,
                1665,
                @"[In EphemeralEntryID] If this field[Display Type ] is set to different values, the server will return the same value.");

            #endregion
            #endregion

            #region Call NspiUnbind method to destroy the context handle.
            uint returnValue = this.ProtocolAdatper.NspiUnbind(0);
            Site.Assert.AreEqual<uint>(1, returnValue, "NspiUnbind method should return 1 (Success).");
            #endregion
        }
        public void MSOXNSPI_S04_TC03_ModLinkAttSuccessWithDifferentDisplayTypePermanentEntryID()
        {
            this.CheckProductSupported();
            this.CheckMAPIHTTPTransportSupported();

            #region Call NspiBind to initiate a session between the client and the server.
            uint flags = 0;
            STAT stat = new STAT();
            stat.InitiateStat();
            FlatUID_r guid = new FlatUID_r
            {
                Ab = new byte[16]
            };
            FlatUID_r? serverGuid = guid;

            this.Result = this.ProtocolAdatper.NspiBind(flags, stat, ref serverGuid);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiBind should return Success!");
            #endregion

            #region Call NspiQueryRows method to get a set of valid rows used to get matched entry ID as the input parameter of NspiModLinkAtt method.
            uint flagsOfQueryRows = (uint)RetrievePropertyFlag.fSkipObjects; // Since the flag fEphID (0x2) is not set, the returned Entry ID is Permanent Entry ID.
            uint tableCount = 0;
            uint[] table = null;
            uint count = Constants.QueryRowsRequestedRowNumber;
            PropertyRowSet_r? rowsOfQueryRows;

            PropertyTagArray_r propTagsInstance = new PropertyTagArray_r
            {
                CValues = 4,
                AulPropTag = new uint[4]
                {
                    (uint)AulProp.PidTagEntryId,
                    (uint)AulProp.PidTagDisplayName,
                    (uint)AulProp.PidTagDisplayType,
                    (uint)AulProp.PidTagAddressBookMember
                }
            };
            PropertyTagArray_r? propTags = propTagsInstance;
            this.Result = this.ProtocolAdatper.NspiQueryRows(flagsOfQueryRows, ref stat, tableCount, table, count, propTags, out rowsOfQueryRows);
            Site.Assert.IsTrue(this.Result == ErrorCodeValue.Success || this.Result == ErrorCodeValue.ErrorsReturned, "NspiQueryRows should return Success or ErrorsReturned (which just specify some properties in the result have no value)!");
            #endregion

            #region Call NspiModLinkAtt to add the specified PidTagAddressBookMember value.
            uint flagsOfModLinkAtt = 0; // A value which does not contain fDelete flag (0x1).
            uint propTagOfModLinkAtt = (uint)AulProp.PidTagAddressBookMember;
            uint midOfModLinkAtt = 0;
            BinaryArray_r entryId = new BinaryArray_r
            {
                CValues = 1,
                Lpbin = new Binary_r[1]
            };

            string dlistName = Common.GetConfigurationPropertyValue("DistributionListName", this.Site);
            string memberName = Common.GetConfigurationPropertyValue("User2Name", this.Site);

            for (int i = 0; i < rowsOfQueryRows.Value.CRows; i++)
            {
                string name = System.Text.Encoding.Default.GetString(rowsOfQueryRows.Value.ARow[i].LpProps[1].Value.LpszA);

                // Server will ignore cases when comparing string according to section 2.2.6 in Open Specification MS-OXNSPI.
                if (name.ToLower(System.Globalization.CultureInfo.CurrentCulture).Equals(dlistName.ToLower(System.Globalization.CultureInfo.CurrentCulture)))
                {
                    PermanentEntryID entryID = AdapterHelper.ParsePermanentEntryIDFromBytes(rowsOfQueryRows.Value.ARow[i].LpProps[0].Value.Bin.Lpb);

                    // To get MId of the DN in Entry Id.
                    #region NspiDNToMId
                    uint reserved = 0;
                    StringsArray_r names = new StringsArray_r
                    {
                        CValues = 1,
                        LppszA = new string[1]
                    };
                    names.LppszA[0] = entryID.DistinguishedName;
                    PropertyTagArray_r? mids;
                    this.Result = this.ProtocolAdatper.NspiDNToMId(reserved, names, out mids);
                    #endregion

                    midOfModLinkAtt = mids.Value.AulPropTag[0];
                    this.MidToBeModified = midOfModLinkAtt;
                }
                else if (name.ToLower(System.Globalization.CultureInfo.CurrentCulture).Equals(memberName.ToLower(System.Globalization.CultureInfo.CurrentCulture)))
                {
                    entryId.Lpbin[0] = rowsOfQueryRows.Value.ARow[i].LpProps[0].Value.Bin;
                    this.EntryIdToBeDeleted = entryId;
                }

                if (midOfModLinkAtt != 0 && entryId.Lpbin[0].Cb != 0)
                {
                    break;
                }
            }

            Site.Assert.AreEqual<uint>(0x00, entryId.Lpbin[0].Lpb[0], "Permanent Entry ID's ID Type should be 0x00.");

            // Add the specified PidTagAddressBookMember value.
            ErrorCodeValue result1 = this.ProtocolAdatper.NspiModLinkAtt(flagsOfModLinkAtt, propTagOfModLinkAtt, midOfModLinkAtt, entryId);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, result1, "NspiModLinkAtt method should return Success.");
            this.IsRequireToDeleteAddressBookMember = true;
            #endregion

            #region Call NspiModLinkAtt to delete the specified PidTagAddressBookMember value.
            flagsOfModLinkAtt = (uint)NspiModLinkAtFlag.fDelete;
            ErrorCodeValue result2 = this.ProtocolAdatper.NspiModLinkAtt(flagsOfModLinkAtt, propTagOfModLinkAtt, midOfModLinkAtt, entryId);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, result2, "NspiModLinkAtt method should return Success.");
            this.IsRequireToDeleteAddressBookMember = false;
            #endregion

            #region Call NspiModLinkAtt to add the specified PidTagAddressBookMember value with the changed display type in PermanentEntryID.
            flagsOfModLinkAtt = 0; // A value which does not contain fDelete flag (0x1).

            // If the original display type is DT_MAILUSER (0x00), change it to DT_PRIVATE_DISTLIST (0x05), otherwise to DT_MAILUSER (0x00), to see if the server ignores this field.
            // The Display Type begins with the 24th position in the Entry ID structure.
            if (entryId.Lpbin[0].Lpb[24] == 0x00)
            {
                entryId.Lpbin[0].Lpb[24] = 0x05;
            }
            else
            {
                entryId.Lpbin[0].Lpb[24] = 0x00;
            }

            ErrorCodeValue result3 = this.ProtocolAdatper.NspiModLinkAtt(flagsOfModLinkAtt, propTagOfModLinkAtt, midOfModLinkAtt, entryId);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, result3, "NspiModLinkAtt method should return Success.");
            this.IsRequireToDeleteAddressBookMember = true;
            #endregion

            #region Call NspiModLinkAtt to delete the specified PidTagAddressBookMember value with the changed display type in PermanentEntryID.
            flagsOfModLinkAtt = (uint)NspiModLinkAtFlag.fDelete;
            ErrorCodeValue result4 = this.ProtocolAdatper.NspiModLinkAtt(flagsOfModLinkAtt, propTagOfModLinkAtt, midOfModLinkAtt, entryId);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, result4, "NspiModLinkAtt method should return Success.");
            this.IsRequireToDeleteAddressBookMember = false;

            #region Capture code
            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-OXNSPI_R1666:�Call NspiModLinkAtt to add address book member�{0} and�delete�it�{1}, then�add address book member with different display type�{2} and�delete�it�{3}.",
                result1.ToString(),
                result2.ToString(),
                result3.ToString(),
                result4.ToString());

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1666
            // Since the server returns the same value when the display type field is set to different values in the input parameter, whenever the property value is to be added (result1 and result3) or to be deleted (result2 and result4), this requirement can be verified.
            Site.CaptureRequirementIfIsTrue(
                result1 == result3 && result2 == result4,
                1666,
                @"[In PermanentEntryID] If this field [Display Type String ] is set to different values, the server will return the same result.");

            #endregion

            #endregion

            #region Call NspiUnbind method to destroy the context handle.
            uint returnValue = this.ProtocolAdatper.NspiUnbind(0);
            Site.Assert.AreEqual<uint>(1, returnValue, "NspiUnbind method should return 1 (Success).");
            #endregion
        }
        /// <summary>
        /// The NspiDNToMId method maps a set of DN to a set of Minimal Entry ID.
        /// </summary>
        /// <param name="reserved">A DWORD value reserved for future use. Ignored by the server.</param>
        /// <param name="names">A StringsArray_r value. It holds a list of strings that contain DNs.</param>
        /// <param name="mids">A PropertyTagArray_r value. On return, it holds a list of Minimal Entry IDs.</param>
        /// <param name="needRetry">A Boolean value indicates if need to retry to get an expected result. This parameter is designed to avoid meaningless retry when an error response is expected.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue NspiDNToMId(uint reserved, StringsArray_r names, out PropertyTagArray_r? mids, bool needRetry = true)
        {
            ErrorCodeValue result;
            if (this.transport == "ncacn_http" || this.transport == "ncacn_ip_tcp")
            {
                result = this.nspiRpcAdapter.NspiDNToMId(reserved, names, out mids, needRetry);
            }
            else
            {
                result = this.nspiMapiHttpAdapter.DNToMId(reserved, names, out mids);
            }

            this.VerifyNspiDNToMId(result, mids);
            this.VerifyTransport();
            return result;
        }
        /// <summary>
        /// The NspiResolveNames method takes a set of string values in an 8-bit character set and performs ANR on those strings. 
        /// The NspiResolveNames method taking string values in an 8-bit character set is not supported when mapi_http transport is used. 
        /// </summary>
        /// <param name="reserved">A DWORD reserved for future use.</param>
        /// <param name="stat">A STAT block that describes a logical position in a specific address book container.</param>
        /// <param name="propTags">The value NULL or a reference to a PropertyTagArray_r value containing a list of the proptags of the columns 
        /// that the client requests to be returned for each row returned.</param>
        /// <param name="stringArray">A StringsArray_r value. It specifies the values on which the client is requesting the server to do ANR.</param>
        /// <param name="mids">A PropertyTagArray_r value. On return, it contains a list of Minimal Entry IDs that match the array of strings.</param>
        /// <param name="rows">A reference to a PropertyRowSet_r value. 
        /// It contains the address book container rows that the server returns in response to the request.</param>
        /// <param name="needRetry">A Boolean value indicates if need to retry to get an expected result. This parameter is designed to avoid meaningless retry when an error response is expected.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue NspiResolveNames(uint reserved, STAT stat, PropertyTagArray_r? propTags, StringsArray_r? stringArray, out PropertyTagArray_r? mids, out PropertyRowSet_r? rows, bool needRetry = true)
        {
            ErrorCodeValue result;
            result = this.nspiRpcAdapter.NspiResolveNames(reserved, stat, propTags, stringArray, out mids, out rows, needRetry);

            this.VerifyNspiResolveNames(result, mids, rows);
            this.VerifyTransport();
            return result;
        }
        /// <summary>
        /// The NspiQueryRows method returns a number of rows from a specified table to the client.
        /// </summary>
        /// <param name="flags">A DWORD value that contains a set of bit flags.</param>
        /// <param name="stat">A STAT block that describes a logical position in a specific address book container.</param>
        /// <param name="tableCount">A DWORD value that contains the number values in the input parameter table. 
        /// This value is limited to 100,000.</param>
        /// <param name="table">An array of DWORD values, representing an Explicit Table.</param>
        /// <param name="count">A DWORD value that contains the number of rows the client is requesting.</param>
        /// <param name="propTags">The value NULL or a reference to a PropertyTagArray_r value, 
        /// containing a list of the proptags of the properties that the client requires to be returned for each row returned.</param>
        /// <param name="rows">A nullable PropertyRowSet_r value, it contains the address book container rows that the server returns in response to the request.</param>
        /// <param name="needRetry">A Boolean value indicates if need to retry to get an expected result. This parameter is designed to avoid meaningless retry when an error response is expected.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue NspiQueryRows(uint flags, ref STAT stat, uint tableCount, uint[] table, uint count, PropertyTagArray_r? propTags, out PropertyRowSet_r? rows, bool needRetry = true)
        {
            ErrorCodeValue result;
            STAT inputStat = stat;

            if (this.transport == "ncacn_http" || this.transport == "ncacn_ip_tcp")
            {
                result = this.nspiRpcAdapter.NspiQueryRows(flags, ref stat, tableCount, table, count, propTags, out rows, needRetry);
            }
            else
            {
                result = this.nspiMapiHttpAdapter.QueryRows(flags, ref stat, tableCount, table, count, propTags, out rows);
            }

            this.VerifyNspiQueryRows(result, rows, inputStat, stat);
            this.VerifyTransport();
            return result;
        }
        /// <summary>
        /// The NspiGetMatches method returns an Explicit Table. 
        /// </summary>
        /// <param name="reserved">A DWORD value reserved for future use.</param>
        /// <param name="stat">A STAT block describing a logical position in a specific address book container.</param>
        /// <param name="proReserved">A PropertyTagArray_r reserved for future use.</param>
        /// <param name="reserved2">A DWORD value reserved for future use. Ignored by the server.</param>
        /// <param name="filter">The value NULL or a Restriction_r value. 
        /// It holds a logical restriction to apply to the rows in the address book container specified in the stat parameter.</param>
        /// <param name="propName">The value NULL or a PropertyName_r value. 
        /// It holds the property to be opened as a restricted address book container.</param>
        /// <param name="requested">A DWORD value. It contains the maximum number of rows to return in a restricted address book container.</param>
        /// <param name="outMids">A PropertyTagArray_r value. On return, it holds a list of Minimal Entry IDs that comprise a restricted address book container.</param>
        /// <param name="propTags">The value NULL or a reference to a PropertyTagArray_r value. 
        /// It contains a list of the proptags of the columns that client wants to be returned for each row returned.</param>
        /// <param name="rows">A reference to a PropertyRowSet_r value. It contains the address book container rows the server returns in response to the request.</param>
        /// <param name="needRetry">A Boolean value indicates if need to retry to get an expected result. This parameter is designed to avoid meaningless retry when an error response is expected.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue NspiGetMatches(uint reserved, ref STAT stat, PropertyTagArray_r? proReserved, uint reserved2, Restriction_r? filter, PropertyName_r? propName, uint requested, out PropertyTagArray_r? outMids, PropertyTagArray_r? propTags, out PropertyRowSet_r? rows, bool needRetry = true)
        {
            ErrorCodeValue result = 0;
            STAT inputStat = stat;

            if (this.transport == "ncacn_http" || this.transport == "ncacn_ip_tcp")
            {
                result = this.nspiRpcAdapter.NspiGetMatches(reserved, ref stat, proReserved, reserved2, filter, propName, requested, out outMids, propTags, out rows, needRetry);
            }
            else
            {
                result = this.nspiMapiHttpAdapter.GetMatches(reserved, ref stat, proReserved, reserved2, filter, propName, requested, out outMids, propTags, out rows);
            }

            this.VerifyNspiGetMatches(result, rows, outMids, inputStat, stat);
            this.VerifyTransport();
            return result;
        }
        /// <summary>
        /// The NspiResolveNamesW method takes a set of string values in the Unicode character set 
        /// and performs ANR on those strings. 
        /// </summary>
        /// <param name="reserved">A DWORD value that is reserved for future use.</param>
        /// <param name="stat">A STAT block that describes a logical position in a specific address book container.</param>
        /// <param name="propTags">The value NULL or a reference to a PropertyTagArray_r containing a list of the proptags of the columns 
        /// that the client requests to be returned for each row returned.</param>
        /// <param name="wstr">A WStringsArray_r value. It specifies the values on which the client is requesting the server to perform ANR.</param>
        /// <param name="mids">A PropertyTagArray_r value. On return, it contains a list of Minimal Entry IDs that match the array of strings.</param>
        /// <param name="rows">A reference to a PropertyRowSet_r structure. It contains the address book container rows that the server returns in response to the request.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue ResolveNames(uint reserved, STAT stat, PropertyTagArray_r? propTags, WStringsArray_r? wstr, out PropertyTagArray_r? mids, out PropertyRowSet_r? rows)
        {
            ErrorCodeValue result;
            byte[] auxIn = new byte[] { };
            ResolveNamesRequestBody resolveNamesRequestBody = new ResolveNamesRequestBody()
            {
                Reserved = reserved,
                HasState = true,
                State = stat,
                AuxiliaryBuffer = auxIn,
                AuxiliaryBufferSize = (uint)auxIn.Length
            };

            if (propTags != null)
            {
                LargePropTagArray propetyTags = new LargePropTagArray();
                propetyTags.PropertyTagCount = propTags.Value.CValues;
                propetyTags.PropertyTags = new PropertyTag[propetyTags.PropertyTagCount];
                for (int i = 0; i < propTags.Value.CValues; i++)
                {
                    propetyTags.PropertyTags[i].PropertyId = (ushort)((propTags.Value.AulPropTag[i] & 0xFFFF0000) >> 16);
                    propetyTags.PropertyTags[i].PropertyType = (ushort)(propTags.Value.AulPropTag[i] & 0x0000FFFF);
                }

                resolveNamesRequestBody.HasPropertyTags = true;
                resolveNamesRequestBody.PropertyTags = propetyTags;
            }
            else
            {
                resolveNamesRequestBody.HasPropertyTags = false;
                resolveNamesRequestBody.PropertyTags = new LargePropTagArray();
            }

            if (wstr != null)
            {
                resolveNamesRequestBody.HasNames = true;
                resolveNamesRequestBody.Names = wstr.Value;
            }
            else
            {
                resolveNamesRequestBody.HasNames = false;
            }

            ChunkedResponse chunkedResponse = this.SendAddressBookRequest(resolveNamesRequestBody, RequestType.ResolveNames);
            ResolveNamesResponseBody resolveNamesResponseBody = ResolveNamesResponseBody.Parse(chunkedResponse.ResponseBodyRawData);
            result = (ErrorCodeValue)resolveNamesResponseBody.ErrorCode;
            if (resolveNamesResponseBody.RowCount != null)
            {
                PropertyRowSet_r newRows = AdapterHelper.ParsePropertyRowSet_r(resolveNamesResponseBody.PropertyTags.Value, resolveNamesResponseBody.RowCount.Value, resolveNamesResponseBody.RowData);
                rows = newRows;
            }
            else
            {
                rows = null;
            }

            if (resolveNamesResponseBody.HasMinimalIds)
            {
                PropertyTagArray_r propertyTagArray = new PropertyTagArray_r();
                propertyTagArray.CValues = resolveNamesResponseBody.MinimalIdCount.Value;
                propertyTagArray.AulPropTag = resolveNamesResponseBody.MinimalIds;
                mids = propertyTagArray;
            }
            else
            {
                mids = null;
            }

            return result;
        }
        /// <summary>
        /// The capture code in NspiQueryColumns.
        /// </summary>
        /// <param name="returnValue">The return value of NspiQueryColumns.</param>
        /// <param name="columns">The parameter indicates which columns to be returned.</param>
        private void VerifyNspiQueryColumns(ErrorCodeValue returnValue, PropertyTagArray_r? columns)
        {
            // The IDL code parses the return value. If the IDL code can return success, the server must return the right result.
            this.Site.CaptureRequirement(
                810,
                @"[In NspiQueryColumns] Return Values: The server returns a LONG [MS-DTYP] value that specifies the return status of the method.");

            if (this.transport == "ncacn_http" || this.transport == "ncacn_ip_tcp")
            {
                // If the operation can be called successfully, the interface must be correct.
                this.Site.CaptureRequirement(
                    1677,
                    @"[In NspiQueryColumns] The interface definition is:
                long NspiQueryColumns(
                    [in] NSPI_HANDLE hRpc,
                    [in] DWORD Reserved,
                    [in] DWORD dwFlags,
                    [out] PropertyTagArray_r** ppColumns
                );");
            }

            this.VerifyReturnValues(returnValue);

            // Because the underlying code parses ppColumns based on this structure, this requirement can be captured directly.
            this.Site.CaptureRequirement(
                809,
                @"[In NspiQueryColumns] [ppColumns] On return, contains a list of proptags.");

            // Because the underlying code parses ppColumns based on this structure, this requirement can be captured directly.
            this.Site.CaptureRequirement(
                824,
                @"[In NspiQueryColumns] [Server Processing Rules: Upon receiving message NspiQueryColumns, the server MUST process the data from the message subject to the following constraints:] [Constraint 5] Subject to the prior constraints, the server MUST construct a list of all the properties it [server] is aware of and return that list as a PropertyTagArray_r structure, as specified in section 2.2.2.2, in the output parameter ppColumns.");

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R808
            // This test suite parses code according to this definition. So if the codes can reach here, this requirement can be captured directly.
            this.Site.CaptureRequirement(
                808,
                @"[In NspiQueryColumns] ppColumns: A reference to a PropertyTagArray_r structure.");

            if (columns != null)
            {
                this.VerifyPropertyTagArray_r();
                foreach (uint propTag in columns.Value.AulPropTag)
                {
                    this.VerifyPropertyTag(propTag);
                }
            }
        }
        /// <summary>
        /// The NspiDNToMId method maps a set of DN to a set of Minimal Entry ID.
        /// </summary>
        /// <param name="reserved">A DWORD value reserved for future use. Ignored by the server.</param>
        /// <param name="names">A StringsArray_r value. It holds a list of strings that contain DNs.</param>
        /// <param name="mids">A PropertyTagArray_r value. On return, it holds a list of Minimal Entry IDs.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue DNToMId(uint reserved, StringsArray_r names, out PropertyTagArray_r? mids)
        {
            ErrorCodeValue result;
            byte[] auxIn = new byte[] { };
            StringArray_r nameArray = new StringArray_r();
            nameArray.CValues = names.CValues;
            nameArray.LppszA = names.LppszA;
            DNToMinIdRequestBody requestBodyOfdnToMId = new DNToMinIdRequestBody()
            {
                Reserved = reserved,
                HasNames = true,
                Names = nameArray,
                AuxiliaryBuffer = auxIn,
                AuxiliaryBufferSize = (uint)auxIn.Length
            };

            ChunkedResponse chunkedResponse = this.SendAddressBookRequest(requestBodyOfdnToMId, RequestType.DNToMId);
            DnToMinIdResponseBody distinguishedNameToMinIdResponseBody = DnToMinIdResponseBody.Parse(chunkedResponse.ResponseBodyRawData);
            result = (ErrorCodeValue)distinguishedNameToMinIdResponseBody.ErrorCode;
            if (distinguishedNameToMinIdResponseBody.HasMinimalIds)
            {
                PropertyTagArray_r propertyTagArray = AdapterHelper.ParsePropertyTagArray_r(distinguishedNameToMinIdResponseBody.MinimalIdCount.Value, distinguishedNameToMinIdResponseBody.MinimalIds);
                mids = propertyTagArray;
            }
            else
            {
                mids = null;
            }

            return result;
        }
        /// <summary>
        /// The NspiModProps method is used to modify the properties of an object in the address book. 
        /// </summary>
        /// <param name="stat">A STAT block that describes a logical position in a specific address book container.</param>
        /// <param name="propTags">The value NULL or a reference to a PropertyTagArray_r. 
        /// It contains a list of the proptags of the columns from which the client requests all the values to be removed.</param>
        /// <param name="row">A PropertyRow_r value. It contains an address book row.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue ModProps(STAT stat, PropertyTagArray_r? propTags, PropertyRow_r row)
        {
            ErrorCodeValue result;
            ModPropsRequestBody modPropsRequestBody = new ModPropsRequestBody();
            modPropsRequestBody.HasState = true;
            modPropsRequestBody.State = stat;
            if (propTags != null)
            {
                LargePropTagArray largePropTagArray = new LargePropTagArray();
                largePropTagArray.PropertyTagCount = propTags.Value.CValues;
                largePropTagArray.PropertyTags = new PropertyTag[propTags.Value.CValues];
                for (int i = 0; i < propTags.Value.CValues; i++)
                {
                    largePropTagArray.PropertyTags[i].PropertyId = (ushort)((propTags.Value.AulPropTag[i] & 0xFFFF0000) >> 16);
                    largePropTagArray.PropertyTags[i].PropertyType = (ushort)(propTags.Value.AulPropTag[i] & 0x0000FFFF);
                }

                modPropsRequestBody.HasPropertyTagsToRemove = true;
                modPropsRequestBody.PropertyTagsToRemove = largePropTagArray;
            }
            else
            {
                modPropsRequestBody.HasPropertyTagsToRemove = false;
            }

            modPropsRequestBody.HasPropertyValues = true;
            AddressBookPropValueList addressBookPropValueList = new AddressBookPropValueList();
            addressBookPropValueList.PropertyValueCount = row.CValues;
            addressBookPropValueList.PropertyValues = new TaggedPropertyValue[row.CValues];
            for (int i = 0; i < row.CValues; i++)
            {
                addressBookPropValueList.PropertyValues[i] = new TaggedPropertyValue();
                byte[] propertyBytes = new byte[row.LpProps[i].Serialize().Length - 8];
                Array.Copy(row.LpProps[i].Serialize(), 8, propertyBytes, 0, row.LpProps[i].Serialize().Length - 8);
                addressBookPropValueList.PropertyValues[i].Value = propertyBytes;
                PropertyTag propertyTagOfRow = new PropertyTag();
                propertyTagOfRow.PropertyId = (ushort)((row.LpProps[i].PropTag & 0xFFFF0000) >> 16);
                propertyTagOfRow.PropertyType = (ushort)(row.LpProps[i].PropTag & 0x0000FFFF);
                addressBookPropValueList.PropertyValues[i].PropertyTag = propertyTagOfRow;
            }

            modPropsRequestBody.PropertyVaules = addressBookPropValueList;

            byte[] auxIn = new byte[] { };
            modPropsRequestBody.AuxiliaryBuffer = auxIn;
            modPropsRequestBody.AuxiliaryBufferSize = (uint)auxIn.Length;

            ChunkedResponse chunkedResponse = this.SendAddressBookRequest(modPropsRequestBody, RequestType.ModProps);
            ModPropsResponseBody modPropsResponseBody = ModPropsResponseBody.Parse(chunkedResponse.ResponseBodyRawData);
            result = (ErrorCodeValue)modPropsResponseBody.ErrorCode;
            return result;
        }
        /// <summary>
        /// The NspiResortRestriction method applies to a sort order to the objects in a restricted address book container.
        /// </summary>
        /// <param name="reserved">A DWORD value reserved for future use. Ignored by the server.</param>
        /// <param name="stat">A STAT block that describes a logical position in a specific address book container.</param>
        /// <param name="proInMIds">A PropertyTagArray_r value. 
        /// It holds a list of Minimal Entry IDs that comprise a restricted address book container.</param>
        /// <param name="outMIds">A PropertyTagArray_r value. On return, it holds a list of Minimal Entry IDs 
        /// that comprise a restricted address book container.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue ResortRestriction(uint reserved, ref STAT stat, PropertyTagArray_r proInMIds, ref PropertyTagArray_r? outMIds)
        {
            ErrorCodeValue result;
            byte[] auxIn = new byte[] { };
            ResortRestrictionRequestBody resortRestrictionRequestBody = new ResortRestrictionRequestBody()
            {
                // Reserved. The client MUST set this field to 0x00000000 and the server MUST ignore this field.
                Reserved = reserved,
                HasState = true,
                State = stat,
                HasMinimalIds = true,
                MinimalIdCount = proInMIds.CValues,
                MinimalIds = proInMIds.AulPropTag,
                AuxiliaryBuffer = auxIn,
                AuxiliaryBufferSize = (uint)auxIn.Length
            };

            ChunkedResponse chunkedResponse = this.SendAddressBookRequest(resortRestrictionRequestBody, RequestType.ResortRestriction);
            ResortRestrictionResponseBody resortRestrictionResponseBody = ResortRestrictionResponseBody.Parse(chunkedResponse.ResponseBodyRawData);
            result = (ErrorCodeValue)resortRestrictionResponseBody.ErrorCode;
            if (resortRestrictionResponseBody.HasMinimalIds)
            {
                PropertyTagArray_r propertyTagArray = AdapterHelper.ParsePropertyTagArray_r(resortRestrictionResponseBody.MinimalIdCount.Value, resortRestrictionResponseBody.MinimalIds);
                outMIds = propertyTagArray;
            }
            else
            {
                outMIds = null;
            }

            if (resortRestrictionResponseBody.HasState)
            {
                stat = resortRestrictionResponseBody.State.Value;
            }

            return result;
        }
        /// <summary>
        /// The NspiGetMatches method returns an Explicit Table. 
        /// </summary>
        /// <param name="reserved">A DWORD value reserved for future use.</param>
        /// <param name="stat">A STAT block that describes a logical position in a specific address book container.</param>
        /// <param name="proReserved">A PropertyTagArray_r reserved for future use.</param>
        /// <param name="reserved2">A DWORD value reserved for future use. Ignored by the server.</param>
        /// <param name="filter">The value NULL or a Restriction_r value. 
        /// It holds a logical restriction to apply to the rows in the address book container specified in the stat parameter.</param>
        /// <param name="propName">The value NULL or a PropertyName_r value. 
        /// It holds the property to be opened as a restricted address book container.</param>
        /// <param name="requested">A DWORD value. It contains the maximum number of rows to return in a restricted address book container.</param>
        /// <param name="outMids">A PropertyTagArray_r value. On return, it holds a list of Minimal Entry IDs that comprise a restricted address book container.</param>
        /// <param name="propTags">The value NULL or a reference to a PropertyTagArray_r value. 
        /// It contains a list of the proptags of the columns that client wants to be returned for each row returned.</param>
        /// <param name="rows">A reference to a PropertyRowSet_r value. It contains the address book container rows the server returns in response to the request.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue GetMatches(uint reserved, ref STAT stat, PropertyTagArray_r? proReserved, uint reserved2, Restriction_r? filter, PropertyName_r? propName, uint requested, out PropertyTagArray_r? outMids, PropertyTagArray_r? propTags, out PropertyRowSet_r? rows)
        {
            ErrorCodeValue result;
            byte[] auxIn = new byte[] { };
            GetMatchesRequestBody getMatchesRequestBody = new GetMatchesRequestBody()
            {
                Reserved = reserved,
                HasState = true,
                State = stat,
                InterfaceOptionFlags = reserved2,
                HasPropertyName = false,
                RowCount = requested,
                AuxiliaryBuffer = auxIn,
                AuxiliaryBufferSize = (uint)auxIn.Length
            };

            if (propTags != null)
            {
                LargePropTagArray propetyTags = new LargePropTagArray();
                propetyTags.PropertyTagCount = propTags.Value.CValues;
                propetyTags.PropertyTags = new PropertyTag[propetyTags.PropertyTagCount];
                for (int i = 0; i < propTags.Value.CValues; i++)
                {
                    propetyTags.PropertyTags[i].PropertyId = (ushort)((propTags.Value.AulPropTag[i] & 0xFFFF0000) >> 16);
                    propetyTags.PropertyTags[i].PropertyType = (ushort)(propTags.Value.AulPropTag[i] & 0x0000FFFF);
                }

                getMatchesRequestBody.HasColumns = true;
                getMatchesRequestBody.Columns = propetyTags;
            }

            if (proReserved != null)
            {
                getMatchesRequestBody.HasMinimalIds = true;
                getMatchesRequestBody.MinimalIdCount = proReserved.Value.CValues;
                getMatchesRequestBody.MinimalIds = proReserved.Value.AulPropTag;
            }

            if (filter != null)
            {
                getMatchesRequestBody.HasFilter = true;
                getMatchesRequestBody.Filter = AdapterHelper.ConvertRestriction_rToRestriction(filter.Value);
            }

            ChunkedResponse chunkedResponse = this.SendAddressBookRequest(getMatchesRequestBody, RequestType.GetMatches);
            GetMatchesResponseBody getMatchesResponseBody = GetMatchesResponseBody.Parse(chunkedResponse.ResponseBodyRawData);
            result = (ErrorCodeValue)getMatchesResponseBody.ErrorCode;
            if (getMatchesResponseBody.HasMinimalIds)
            {
                PropertyTagArray_r propertyTagArray = new PropertyTagArray_r();
                propertyTagArray.CValues = getMatchesResponseBody.MinimalIdCount.Value;
                propertyTagArray.AulPropTag = getMatchesResponseBody.MinimalIds;
                outMids = propertyTagArray;
            }
            else
            {
                outMids = null;
            }

            if (getMatchesResponseBody.RowCount != null)
            {
                PropertyRowSet_r newRows = AdapterHelper.ParsePropertyRowSet_r(getMatchesResponseBody.Columns.Value, getMatchesResponseBody.RowCount.Value, getMatchesResponseBody.RowData);
                rows = newRows;
            }
            else
            {
                rows = null;
            }

            if (getMatchesResponseBody.HasState)
            {
                stat = getMatchesResponseBody.State.Value;
            }

            return result;
        }
        /// <summary>
        /// The NspiSeekEntries method searches for and sets the logical position in a specific table
        /// to the first entry greater than or equal to a specified value. 
        /// </summary>
        /// <param name="reserved">A DWORD value that is reserved for future use. Ignored by the server.</param>
        /// <param name="stat">A STAT block that describes a logical position in a specific address book container.</param>
        /// <param name="target">A PropertyValue_r value holding the value that is being sought.</param>
        /// <param name="table">The value NULL or a PropertyTagArray_r value. 
        /// It holds a list of Minimal Entry IDs that comprise a restricted address book container.</param>
        /// <param name="propTags">It contains a list of the proptags of the columns 
        /// that client wants to be returned for each row returned.</param>
        /// <param name="rows">It contains the address book container rows the server returns in response to the request.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue SeekEntries(uint reserved, ref STAT stat, PropertyValue_r target, PropertyTagArray_r? table, PropertyTagArray_r? propTags, out PropertyRowSet_r? rows)
        {
            ErrorCodeValue result;
            SeekEntriesRequestBody seekEntriesRequestBody = new SeekEntriesRequestBody();
            TaggedPropertyValue targetValue = new TaggedPropertyValue();
            targetValue.PropertyTag = new PropertyTag((ushort)((target.PropTag & 0xFFFF0000) >> 16), (ushort)(target.PropTag & 0x0000FFFF));
            targetValue.Value = new byte[target.Serialize().Length - 8];
            Array.Copy(target.Serialize(), 8, targetValue.Value, 0, target.Serialize().Length - 8);

            // Reserved. The client MUST set this field to 0x00000000 and the server MUST ignore this field.
            seekEntriesRequestBody.Reserved = reserved;
            seekEntriesRequestBody.HasState = true;
            seekEntriesRequestBody.State = stat;
            seekEntriesRequestBody.HasTarget = true;
            seekEntriesRequestBody.Target = targetValue;
            if (table != null)
            {
                seekEntriesRequestBody.HasExplicitTable = true;
                seekEntriesRequestBody.ExplicitTable = table.Value.AulPropTag;
            }

            LargePropTagArray propetyTags = new LargePropTagArray();
            if (propTags != null)
            {
                propetyTags.PropertyTagCount = propTags.Value.CValues;
                propetyTags.PropertyTags = new PropertyTag[propetyTags.PropertyTagCount];
                for (int i = 0; i < propTags.Value.CValues; i++)
                {
                    propetyTags.PropertyTags[i].PropertyId = (ushort)((propTags.Value.AulPropTag[i] & 0xFFFF0000) >> 16);
                    propetyTags.PropertyTags[i].PropertyType = (ushort)(propTags.Value.AulPropTag[i] & 0x0000FFFF);
                }

                seekEntriesRequestBody.HasColumns = true;
                seekEntriesRequestBody.Columns = propetyTags;
            }

            seekEntriesRequestBody.AuxiliaryBufferSize = 0;
            seekEntriesRequestBody.AuxiliaryBuffer = new byte[] { };
            ChunkedResponse chunkedResponse = this.SendAddressBookRequest(seekEntriesRequestBody, RequestType.SeekEntries);
            SeekEntriesResponseBody seekEntriesResponseBody = SeekEntriesResponseBody.Parse(chunkedResponse.ResponseBodyRawData);
            result = (ErrorCodeValue)seekEntriesResponseBody.ErrorCode;
            if (seekEntriesResponseBody.HasColumnsAndRows)
            {
                PropertyRowSet_r newRows = AdapterHelper.ParsePropertyRowSet_r(seekEntriesResponseBody.Columns.Value, seekEntriesResponseBody.RowCount.Value, seekEntriesResponseBody.RowData);
                rows = newRows;
            }
            else
            {
                rows = null;
            }

            if (seekEntriesResponseBody.HasState)
            {
                stat = seekEntriesResponseBody.State.Value;
            }

            return result;
        }
        /// <summary>
        /// The NspiGetPropList method returns a list of all the properties that have values on a specified object.
        /// </summary>
        /// <param name="flags">A DWORD value that contains a set of bit flags.</param>
        /// <param name="mid">A DWORD value that contains a Minimal Entry ID.</param>
        /// <param name="codePage">The code page in which the client wants the server to express string values properties.</param>
        /// <param name="propTags">A PropertyTagArray_r value. On return, it holds a list of properties.</param>
        /// <param name="needRetry">A Boolean value indicates if need to retry to get an expected result. This parameter is designed to avoid meaningless retry when an error response is expected.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue NspiGetPropList(uint flags, uint mid, uint codePage, out PropertyTagArray_r? propTags, bool needRetry = true)
        {
            ErrorCodeValue result;

            if (this.transport == "ncacn_http" || this.transport == "ncacn_ip_tcp")
            {
                result = this.nspiRpcAdapter.NspiGetPropList(flags, mid, codePage, out propTags, needRetry);
            }
            else
            {
                result = this.nspiMapiHttpAdapter.GetPropList(flags, mid, codePage, out propTags);
            }

            this.VerifyNspiGetPropList(result, propTags);
            this.VerifyTransport();
            return result;
        }
        /// <summary>
        /// The capture code in NspiGetPropList.
        /// </summary>
        /// <param name="returnValue">The return value of NspiGetPropList.</param>
        /// <param name="propTags">The parameter indicates which columns to be returned.</param>
        private void VerifyNspiGetPropList(ErrorCodeValue returnValue, PropertyTagArray_r? propTags)
        {
            // The IDL code parses the return value. If the IDL code can return success, the server must return the right result.
            this.Site.CaptureRequirement(
                836,
                @"[In NspiGetPropList] Return Values: The server returns a long value that specifies the return status of the method.");

            if (this.transport == "ncacn_http" || this.transport == "ncacn_ip_tcp")
            {
                // The following IDL definition is used to generate the stub class, which is used to communicate with server. So if the operation can be called successfully, the following requirement can be captured directly.
                this.Site.CaptureRequirement(
                    1678,
                    @"[In NspiGetPropList] The interface definition is:
                long NspiGetPropList(
                    [in] NSPI_HANDLE hRpc,
                    [in] DWORD dwFlags,
                    [in] DWORD dwMId,
                    [in] DWORD CodePage,
                    [out] PropertyTagArray_r** ppPropTags
                );");
            }

            this.VerifyReturnValues(returnValue);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R834
            // This test suite parses code according to this definition. So if the codes can reach here, this requirement can be captured directly.
            this.Site.CaptureRequirement(
                834,
                @"[In NspiGetPropList] ppPropTags: A PropertyTagArray_r value.");

            if (propTags != null)
            {
                this.VerifyPropertyTagArray_r();
            }
        }
        /// <summary>
        /// The NspiGetProps method returns an address book row that contains a set of the properties
        /// and values that exist on an object.
        /// </summary>
        /// <param name="flags">A DWORD value that contains a set of bit flags.</param>
        /// <param name="stat">A STAT block that describes a logical position in a specific address book container.</param>
        /// <param name="propTags">The value NULL or a reference to a PropertyTagArray_r value. 
        /// It contains a list of the proptags of the properties that the client wants to be returned.</param>
        /// <param name="rows">A nullable PropertyRow_r value. 
        /// It contains the address book container row the server returns in response to the request.</param>
        /// <param name="needRetry">A Boolean value indicates if need to retry to get an expected result. This parameter is designed to avoid meaningless retry when an error response is expected.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue NspiGetProps(uint flags, STAT stat, PropertyTagArray_r? propTags, out PropertyRow_r? rows, bool needRetry = true)
        {
            ErrorCodeValue result;

            if (this.transport == "ncacn_http" || this.transport == "ncacn_ip_tcp")
            {
                result = this.nspiRpcAdapter.NspiGetProps(flags, stat, propTags, out rows, needRetry);
            }
            else
            {
                result = this.nspiMapiHttpAdapter.GetProps(flags, stat, propTags, out rows);
            }

            this.VerifyNspiGetProps(result, rows);
            this.VerifyTransport();
            return result;
        }
        /// <summary>
        /// The capture code in NspiGetMatches.
        /// </summary>
        /// <param name="returnValue">The return value of NspiGetMatches.</param>
        /// <param name="rows">The rows that the server returns.</param>
        /// <param name="outMIds">A PropertyTagArray_r value which contains a list of Minimal Entry IDs that comprise a restricted address book container.</param>
        /// <param name="inputStat">The input parameter STAT.</param>
        /// <param name="outputStat">The output parameter STAT.</param>
        private void VerifyNspiGetMatches(ErrorCodeValue returnValue, PropertyRowSet_r? rows, PropertyTagArray_r? outMIds, STAT inputStat, STAT outputStat)
        {
            if (outMIds != null)
            {
                this.VerifyPropertyTagArray_r();

                // According to the description in the Open Specification, outMIds holds a list of Minimal Entry IDs that comprise a restricted address book container.
                // So if outMIds is not null, it specifies that the list is instantiated as a PropertyTagArray_r structure.
                this.Site.CaptureRequirement(
                    507,
                    @"[In Explicit Tables] The list [a list of Minimal Entry IDs] is instantiated in the protocol either as an array of DWORDs or as a PropertyTagArray_r structure.");
            }

            // The IDL code parses the returned value. If the IDL code can return success, the server must return the right result.
            this.Site.CaptureRequirement(
                1097,
                @"[In NspiGetMatches] Return Values: The server returns a long value specifying the return status of the method.");

            // This parameter is defined as PropertyTagArray_r structure. If the parser code can parse the structure successfully, it illustrates that the server returns the result correctly.
            this.Site.CaptureRequirement(
                1091,
                @"[In NspiGetMatches] ppOutMIds: A PropertyTagArray_r value.");

            if (this.transport == "ncacn_http" || this.transport == "ncacn_ip_tcp")
            {
                // The following IDL definition is used to generate the stub class, which is used to communicate with server. So if the operation can be called successfully, the following requirement can be captured directly.
                this.Site.CaptureRequirement(
                    1682,
                    @"[In NspiGetMatches] The interface definition is:

                long NspiGetMatches(
                    [in] NSPI_HANDLE hRpc,
                    [in] DWORD Reserved1,
                    [in, out] STAT* pStat,
                    [in, unique] PropertyTagArray_r* pReserved,
                    [in] DWORD Reserved2,
                    [in, unique] Restriction_r* Filter,
                    [in, unique] PropertyName_r* lpPropName,
                    [in] DWORD ulRequested,
                    [out] PropertyTagArray_r** ppOutMIds,
                    [in, unique] PropertyTagArray_r* pPropTags,
                    [out] PropertyRowSet_r** ppRows
                );");
            }

            if (returnValue == ErrorCodeValue.Success)
            {
                // Add the debug information
                this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1166");

                // Verify MS-OXNSPI requirement: MS-OXNSPI_R1166
                // The parameter rows is returned from the server. If it is not null, it illustrates that the 
                // server has returned the PropertyRowSet_r structure in the output parameter pProws.
                this.Site.CaptureRequirementIfIsNotNull(
                    rows,
                    1166,
                    @"[In NspiGetMatches] The server MUST return the constructed PropertyRowSet_r in the output parameter ppRows.");
            }

            this.VerifyReturnValues(returnValue);

            if (rows != null)
            {
                // Verify MS-OXNSPI requirement: MS-OXNSPI_R1095
                // This test suite parses code according to this definition. So if the codes can reach here, this requirement can be captured directly.
                this.Site.CaptureRequirement(
                    1095,
                    @"[In NspiGetMatches] ppRows: A reference to a PropertyRowSet_r value.");

                foreach (PropertyRow_r propertyRow in rows.Value.ARow)
                {
                    this.VerifyStringOrString8Value(propertyRow);

                    // Parse the Minimal Entry ID if it exists.
                    if (propertyRow.LpProps[0].Value.Bin.Cb > 0)
                    {
                        EphemeralEntryID ephemeralEntryID = AdapterHelper.ParseEphemeralEntryIDFromBytes(propertyRow.LpProps[0].Value.Bin.Lpb);

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

                        // Verify MS-OXNSPI requirement: MS-OXNSPI_R506
                        // The NspiGetMatches method returns an Explicit Table. So if the parsed ephemeralEntryID is not null, it means that the Explicit Table is implemented as a list of Minimal Entry IDs.
                        this.Site.CaptureRequirementIfIsNotNull(
                            ephemeralEntryID,
                            506,
                            @"[In Explicit Tables] This table [Explicit Table] is implemented as a list of Minimal Entry IDs.");
                    }
                }

                this.VerifyPropertyRowSetStructure(rows.Value);
            }

            this.VerifySTATStructure(returnValue, inputStat, outputStat, true);
            this.VerifyMinimalEntryIDStructure();
        }
        /// <summary>
        /// The NspiSeekEntries method searches for and sets the logical position in a specific table
        /// to the first entry greater than or equal to a specified value. 
        /// </summary>
        /// <param name="reserved">A DWORD value that is reserved for future use. Ignored by the server.</param>
        /// <param name="stat">A STAT block that describes a logical position in a specific address book container.</param>
        /// <param name="target">A PropertyValue_r value holding the value that is being sought.</param>
        /// <param name="table">The value NULL or a PropertyTagArray_r value. 
        /// It holds a list of Minimal Entry IDs that comprise a restricted address book container.</param>
        /// <param name="propTags">It contains a list of the proptags of the columns 
        /// that client wants to be returned for each row returned.</param>
        /// <param name="rows">It contains the address book container rows the server returns in response to the request.</param>
        /// <param name="needRetry">A Boolean value indicates if need to retry to get an expected result. This parameter is designed to avoid meaningless retry when an error response is expected.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue NspiSeekEntries(uint reserved, ref STAT stat, PropertyValue_r target, PropertyTagArray_r? table, PropertyTagArray_r? propTags, out PropertyRowSet_r? rows, bool needRetry = true)
        {
            ErrorCodeValue result = 0;
            STAT inputStat = stat;

            if (this.transport == "ncacn_http" || this.transport == "ncacn_ip_tcp")
            {
                result = this.nspiRpcAdapter.NspiSeekEntries(reserved, ref stat, target, table, propTags, out rows, needRetry);
            }
            else
            {
                result = this.nspiMapiHttpAdapter.SeekEntries(reserved, ref stat, target, table, propTags, out rows);
            }

            this.VerifyNspiSeekEntries(result, rows, inputStat, stat);
            this.VerifyTransport();
            return result;
        }
        /// <summary>
        /// The capture code in NspiResortRestriction.
        /// </summary>
        /// <param name="returnValue">The return value of NspiResortRestriction.</param>
        /// <param name="outMIds">The outMIds parameter of NspiResortRestriction</param>
        /// <param name="inputStat">The input parameter STAT.</param>
        /// <param name="outputStat">The output parameter STAT.</param>
        private void VerifyNspiResortRestriction(ErrorCodeValue returnValue, PropertyTagArray_r? outMIds, STAT inputStat, STAT outputStat)
        {
            // The IDL code parses return value. If the IDL code can return success, the server must return the right result.
            this.Site.CaptureRequirement(
                1177,
                @"[In NspiResortRestriction] Return Values: The server returns a long value that specifies the return status of the method.");

            if (this.transport == "ncacn_http" || this.transport == "ncacn_ip_tcp")
            {
                // The following IDL definition is used to generate the stub class, which is used to communicate with server. So if the operation can be called successfully, the following requirement can be captured directly.
                this.Site.CaptureRequirement(
                    1683,
                    @"[In NspiResortRestriction] The interface definition is:

                long NspiResortRestriction(
                    [in] NSPI_HANDLE hRpc,
                    [in] DWORD Reserved,
                    [in, out] STAT* pStat,
                    [in] PropertyTagArray_r* pInMIds,
                    [in, out] PropertyTagArray_r** ppOutMIds
                );");
            }

            this.VerifyReturnValues(returnValue);

            if (returnValue == ErrorCodeValue.Success)
            {
                // Add the debug information
                this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1201");

                // Verify MS-OXNSPI requirement: MS-OXNSPI_R1201
                // The outMIds, which is returned from the server, contains a Explicit Table. If it is not null, it 
                // illustrates that the server has returned the Explicit Table in the output parameter pProws.
                this.Site.CaptureRequirementIfIsNotNull(
                    outMIds,
                    1201,
                    @"[In NspiResortRestriction] [Server Processing Rules: Upon receiving message NspiResortRestriction, the server MUST process the data from the message subject to the following constraints:] [Constraint 7] The server MUST return the constructed Explicit Table in the output parameter ppOutMIds.");

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

                // Verify MS-OXNSPI requirement: MS-OXNSPI_R1204
                this.Site.CaptureRequirementIfAreEqual<uint>(
                    outMIds.Value.CValues,
                    outputStat.TotalRecs,
                    1204,
                    @"[In NspiResortRestriction] [Server Processing Rules: Upon receiving message NspiResortRestriction, the server MUST process the data from the message subject to the following constraints:] [Constraint 8] The Server MUST update the output parameter pStat as follows: The TotalRecs field is set to the number of objects in the constructed Explicit Table.");
            }

            // Add the debug information
            this.Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-OXNSPI_R1207. The value of CodePage in the output stat is {0}. The value of ContainerID in the output stat is {1}. The value of Delta in the output stat is {2}. The value of SortLocale in the output stat is {3}. The value of SortType in the output stat is {4}. The value of TemplateLocale in the output stat is {5}.",
                outputStat.CodePage,
                outputStat.ContainerID,
                outputStat.Delta,
                outputStat.SortLocale,
                outputStat.SortType,
                outputStat.TemplateLocale);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1207
            bool isVerifyR1207 = (outputStat.CodePage == inputStat.CodePage)
                                && (outputStat.ContainerID == inputStat.ContainerID)
                                && (outputStat.Delta == inputStat.Delta)
                                && (outputStat.SortLocale == inputStat.SortLocale)
                                && (outputStat.SortType == inputStat.SortType)
                                && (outputStat.TemplateLocale == inputStat.TemplateLocale);

            this.Site.CaptureRequirementIfIsTrue(
                isVerifyR1207,
                1207,
                @"[In NspiResortRestriction] [Server Processing Rules: Upon receiving message NspiResortRestriction, the server MUST process the data from the message subject to the following constraints:] [Constraint 8 The Server MUST update the output parameter pStat as follows:] The server MUST NOT modify any other fields of the output parameter pStat.");

            if (outMIds != null)
            {
                // Verify MS-OXNSPI requirement: MS-OXNSPI_R1175
                // This test suite parses code according to this definition. So if the codes can reach here, this requirement can be captured directly.
                this.Site.CaptureRequirement(
                    1175,
                    @"[In NspiResortRestriction] ppOutMIds: A PropertyTagArray_r value.");
            }

            this.VerifySTATStructure(returnValue, inputStat, outputStat, false);
            this.VerifyMinimalEntryIDStructure();
            this.VerifyContainerIDCanNotBeModified(inputStat, outputStat);
        }
        /// <summary>
        /// The NspiResortRestriction method applies to a sort order to the objects in a restricted address book container.
        /// </summary>
        /// <param name="reserved">A DWORD value reserved for future use. Ignored by the server.</param>
        /// <param name="stat">A reference to a STAT block describing a logical position in a specific address book container.</param>
        /// <param name="proInMIds">A PropertyTagArray_r value. 
        /// It holds a list of Minimal Entry IDs that comprise a restricted address book container.</param>
        /// <param name="outMIds">A PropertyTagArray_r value. On return, it holds a list of Minimal Entry IDs 
        /// that comprise a restricted address book container.</param>
        /// <param name="needRetry">A Boolean value indicates if need to retry to get an expected result. This parameter is designed to avoid meaningless retry when an error response is expected.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue NspiResortRestriction(uint reserved, ref STAT stat, PropertyTagArray_r proInMIds, ref PropertyTagArray_r? outMIds, bool needRetry = true)
        {
            ErrorCodeValue result;
            STAT inputStat = stat;

            if (this.transport == "ncacn_http" || this.transport == "ncacn_ip_tcp")
            {
                result = this.nspiRpcAdapter.NspiResortRestriction(reserved, ref stat, proInMIds, ref outMIds, needRetry);
            }
            else
            {
                result = this.nspiMapiHttpAdapter.ResortRestriction(reserved, ref stat, proInMIds, ref outMIds);
            }

            this.VerifyNspiResortRestriction(result, outMIds, inputStat, stat);
            this.VerifyTransport();
            return result;
        }
        /// <summary>
        /// The capture code in NspiDNToMId.
        /// </summary>
        /// <param name="returnValue">The NspiDNToMId return value.</param>
        /// <param name="mids">The mids parameter of NspiDNToMId.</param>
        private void VerifyNspiDNToMId(ErrorCodeValue returnValue, PropertyTagArray_r? mids)
        {
            // The IDL code parses the return value. If the IDL code can return success, the server must return the right result.
            this.Site.CaptureRequirement(
                1251,
                @"[In NspiDNToMId] Return Values: The server returns a long value that specifies the return status of the method.");

            if (this.transport == "ncacn_http" || this.transport == "ncacn_ip_tcp")
            {
                // The following IDL definition is used to generate the stub class, which is used to communicate with server. So if the operation can be called successfully, the following requirement can be captured directly.
                this.Site.CaptureRequirement(
                    1685,
                    @"[In NspiDNToMId] The interface definition is:
                long NspiDNToMId(
                    [in] NSPI_HANDLE hRpc,
                    [in] DWORD Reserved,
                    [in] stringsArray_r* pNames,
                    [out] PropertyTagArray_r** ppMIds
                );");
            }

            this.VerifyReturnValues(returnValue);

            if (returnValue == ErrorCodeValue.Success)
            {
                // Add the debug information
                this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1262");

                // Verify MS-OXNSPI requirement: MS-OXNSPI_R1262
                // This structure, which is returned from the server, contains a list of Minimal Entry IDs. 
                // If it's not null, it illustrates that the server must have constructed the list.
                this.Site.CaptureRequirementIfIsNotNull(
                    mids,
                    1262,
                    @"[In NspiDNToMId] [Server Processing Rules: Upon receiving message NspiDNToMId, the server MUST process the data from the message subject to the following constraints:] [Constraint 4] The server constructs a list of Minimal Entry IDs to return to the client, encoding the mappings.");
            }

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1264
            // This structure, which is returned from the server, contains a list of Minimal Entry IDs. If it's not null, 
            // it illustrates that the server has returned the list of Minimal Entry IDs in the output parameter ppMIds.
            this.Site.CaptureRequirementIfIsNotNull(
                mids,
                1264,
                @"[In NspiDNToMId] [Server Processing Rules: Upon receiving message NspiDNToMId, the server MUST process the data from the message subject to the following constraints:] [Constraint 4] The server MUST return the list in the output parameter ppMIds.");

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1249
            // This test suite parses code according to this definition. So if the codes can reach here, this requirement can be captured directly.
            this.Site.CaptureRequirement(
                1249,
                @"[In NspiDNToMId] ppMIds: A PropertyTagArray_r value.");

            if (mids != null)
            {
                this.VerifyPropertyTagArray_r();
            }

            this.VerifyMinimalEntryIDStructure();
        }
        /// <summary>
        /// The NspiModProps method is used to modify the properties of an object in the address book. 
        /// </summary>
        /// <param name="reserved">A DWORD value reserved for future use.</param>
        /// <param name="stat">A STAT block that describes a logical position in a specific address book container.</param>
        /// <param name="propTags">The value NULL or a reference to a PropertyTagArray_r. 
        /// It contains a list of the proptags of the columns from which the client requests all the values to be removed.</param>
        /// <param name="row">A PropertyRow_r value. It contains an address book row.</param>
        /// <param name="needRetry">A Boolean value indicates if need to retry to get an expected result. This parameter is designed to avoid meaningless retry when an error response is expected.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue NspiModProps(uint reserved, STAT stat, PropertyTagArray_r? propTags, PropertyRow_r row, bool needRetry = true)
        {
            ErrorCodeValue result;
            if (this.transport == "ncacn_http" || this.transport == "ncacn_ip_tcp")
            {
                result = this.nspiRpcAdapter.NspiModProps(reserved, stat, propTags, row, needRetry);
            }
            else
            {
                result = this.nspiMapiHttpAdapter.ModProps(stat, propTags, row);
            }

            this.VerifyNspiModProps(result);
            this.VerifyTransport();
            return result;
        }
        /// <summary>
        /// Verify there are three possible outcomes to the ANR process.
        /// </summary>
        /// <param name="mids">The mids parameter of NspiResolveNames or NspiResolveNamesW.</param>
        /// <param name="rows">The PropertyRowSet_r structure the server returns.</param>
        private void VerifyThreePossbleOutcomesOfANRProcess(PropertyTagArray_r? mids, PropertyRowSet_r? rows)
        {
            if (rows != null)
            {
                foreach (PropertyRow_r propertyRow in rows.Value.ARow)
                {
                    this.VerifyStringOrString8Value(propertyRow);
                }
            }

            if (mids != null)
            {
                // Add the debug information
                this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1611.");

                bool validAnrResult = true;
                this.Site.Assert.IsTrue(mids.Value.CValues > 0, "There should be values returned from server.");
                foreach (uint minimalEntryID in mids.Value.AulPropTag)
                {
                    if (!(minimalEntryID == (uint)ANRMinEntryID.MID_AMBIGUOUS
                        || minimalEntryID == (uint)ANRMinEntryID.MID_RESOLVED
                        || minimalEntryID == (uint)ANRMinEntryID.MID_UNRESOLVED))
                    {
                        validAnrResult = false;
                        break;
                    }
                }

                // Verify MS-OXNSPI requirement: MS-OXNSPI_R1611
                this.Site.CaptureRequirementIfIsTrue(
                    validAnrResult,
                    1611,
                    @"[In Ambiguous Name Resolution] There are three possible outcomes [MID_UNRESOLVED, MID_AMBIGUOUS and MID_RESOLVED] to the ANR process.");

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

                this.Site.CaptureRequirementIfIsTrue(
                    validAnrResult,
                    87,
                    @"[In Ambiguous Name Resolution Minimal Entry IDs] The following table lists the possible values [MID_UNRESOLVED, MID_AMBIGUOUS and MID_RESOLVED].");
            }
        }
        /// <summary>
        /// The NspiResolveNamesW method takes a set of string values in the Unicode character set and performs ANR on those strings. 
        /// </summary>
        /// <param name="reserved">A DWORD value that is reserved for future use.</param>
        /// <param name="stat">A STAT block that describes a logical position in a specific address book container.</param>
        /// <param name="propTags">The value NULL or a reference to a PropertyTagArray_r containing a list of the proptags of the columns 
        /// that the client requests to be returned for each row returned.</param>
        /// <param name="wstr">A WStringsArray_r value. It specifies the values on which the client is requesting the server to perform ANR.</param>
        /// <param name="mids">A PropertyTagArray_r value. On return, it contains a list of Minimal Entry IDs that match the array of strings.</param>
        /// <param name="rowOfResolveNamesW">A reference to a PropertyRowSet_r structure. It contains the address book container rows that the server returns in response to the request.</param>
        /// <param name="needRetry">A Boolean value indicates if need to retry to get an expected result. This parameter is designed to avoid meaningless retry when an error response is expected.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue NspiResolveNamesW(uint reserved, STAT stat, PropertyTagArray_r? propTags, WStringsArray_r? wstr, out PropertyTagArray_r? mids, out PropertyRowSet_r? rowOfResolveNamesW, bool needRetry = true)
        {
            ErrorCodeValue result;

            if (this.transport == "ncacn_http" || this.transport == "ncacn_ip_tcp")
            {
                result = this.nspiRpcAdapter.NspiResolveNamesW(reserved, stat, propTags, wstr, out mids, out rowOfResolveNamesW, needRetry);
            }
            else
            {
                result = this.nspiMapiHttpAdapter.ResolveNames(reserved, stat, propTags, wstr, out mids, out rowOfResolveNamesW);
            }

            this.VerifyNspiResolveNamesW(result, mids, rowOfResolveNamesW);
            this.VerifyTransport();
            return result;
        }
        /// <summary>
        /// The capture code in NspiResolveNamesW.
        /// </summary>
        /// <param name="returnValue">The return value of NspiResolveNamesW.</param>
        /// <param name="mids">The mids parameter of NspiResolveNamesW.</param>
        /// <param name="rows">The PropertyRowSet_r structure the server returns.</param>
        private void VerifyNspiResolveNamesW(ErrorCodeValue returnValue, PropertyTagArray_r? mids, PropertyRowSet_r? rows)
        {
            // The IDL code parses the return value. If the IDL code can return success, the server must return the right result.
            this.Site.CaptureRequirement(
                1406,
                @"[In NspiResolveNamesW] Return Values: The server returns a long value that specifies the return status of the method.");

            if (this.transport == "ncacn_http" || this.transport == "ncacn_ip_tcp")
            {
                // The following IDL definition is used to generate the stub class, which is used to communicate with server. So if the operation can be called successfully, the following requirement can be captured directly.
                this.Site.CaptureRequirement(
                    1689,
                    @"[In NspiResolveNamesW] The interface definition is:

                long NspiResolveNamesW(
                    [in] NSPI_HANDLE hRpc,
                    [in] DWORD Reserved,
                    [in] STAT* pStat,
                    [in, unique] PropertyTagArray_r* pPropTags,
                    [in] WstringsArray_r* paWStr,
                    [out] PropertyTagArray_r** ppMIds,
                    [out] PropertyRowSet_r** ppRows
                );");
            }

            if ((returnValue == ErrorCodeValue.Success) || (returnValue == ErrorCodeValue.ErrorsReturned))
            {
                // Add the debug information
                this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1425");

                // Verify MS-OXNSPI requirement: MS-OXNSPI_R1425
                // This structure, which is returned from the server, contains a list of Minimal Entry IDs. 
                // If it's not null, it illustrates that the server must have constructed the list.
                this.Site.CaptureRequirementIfIsNotNull(
                    mids,
                    1425,
                    @"[In NspiResolveNamesW] [Server Processing Rules: Upon receiving message NspiResolveNamesW, the server MUST process the data from the message subject to the following constraints:] [Constraint 6] The server constructs a list of the Minimal Entry IDs specified in section 2.2.1.9 to return to the client.");

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

                // Verify MS-OXNSPI requirement: MS-OXNSPI_R1428
                // This structure, which is returned from the server, contains a list of Minimal Entry IDs. If it's not null, it illustrates that the 
                // server has returned the list of Minimal Entry IDs in the output parameter ppMIds.
                this.Site.CaptureRequirementIfIsNotNull(
                    mids,
                    1428,
                    @"[In NspiResolveNamesW] [Server Processing Rules: Upon receiving message NspiResolveNamesW, the server MUST process the data from the message subject to the following constraints:] [Constraint 6] The server MUST return this list of Minimal Entry IDs [Minimal Entry IDs resulted from the ANR process] in the output parameter ppMIds.");
            }

            if (mids != null)
            {
                this.VerifyPropertyTagArray_r();

                // Verify MS-OXNSPI requirement: MS-OXNSPI_R1403
                // This test suite parses code according to this definition. So if the codes can reach here, this requirement can be captured directly.
                this.Site.CaptureRequirement(
                    1403,
                    @"[In NspiResolveNamesW] ppMIds: A PropertyTagArray_r value.");
            }

            if (rows != null)
            {
                // Verify MS-OXNSPI requirement: MS-OXNSPI_R1404
                // This test suite parses code according to this definition. So if the codes can reach here, this requirement can be captured directly.
                this.Site.CaptureRequirement(
                    1404,
                    @"[In NspiResolveNamesW] ppRows: A reference to a PropertyRowSet_r structure (section 2.2.4), [which contains the address book container rows that the server returns in response to the request.] ");

                this.VerifyPropertyRowSetStructure(rows.Value);
            }

            this.VerifyReturnValues(returnValue);
            this.VerifyThreePossbleOutcomesOfANRProcess(mids, rows);
            this.VerifyMinimalEntryIDStructure();
        }
        public void MSOXNSPI_S04_TC01_ModPropsSuccess()
        {
            this.CheckProductSupported();
            this.CheckMAPIHTTPTransportSupported();

            #region Call NspiBind to initiate a session between a client and the server.
            uint flags = 0;
            STAT stat = new STAT();
            stat.InitiateStat();
            FlatUID_r guid = new FlatUID_r();
            guid.Ab = new byte[16];
            FlatUID_r? serverGuid = guid;
            this.Result = this.ProtocolAdatper.NspiBind(flags, stat, ref serverGuid);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiBind should return Success!");

            #endregion

            #region Call NspiQueryRows to get the DN of specified user.
            uint flagsOfQueryRows = (uint)RetrievePropertyFlag.fSkipObjects;
            uint tableCount = 0;
            uint[] table = null;
            uint count = Constants.QueryRowsRequestedRowNumber;
            PropertyRowSet_r? rowsOfQueryRows;

            PropertyTagArray_r propTagsInstance = new PropertyTagArray_r();
            propTagsInstance.CValues = 3;
            propTagsInstance.AulPropTag = new uint[3]
            {
                (uint)AulProp.PidTagEntryId,
                (uint)AulProp.PidTagDisplayName,
                (uint)AulProp.PidTagDisplayType,
            };
            PropertyTagArray_r? propTags = propTagsInstance;
            this.Result = this.ProtocolAdatper.NspiQueryRows(flagsOfQueryRows, ref stat, tableCount, table, count, propTags, out rowsOfQueryRows);
            Site.Assert.AreEqual(ErrorCodeValue.Success, this.Result, "NspiQueryRows should return success!");

            string userName = Common.GetConfigurationPropertyValue("User2Name", this.Site);
            string userESSDN = string.Empty;

            for (int i = 0; i < rowsOfQueryRows.Value.CRows; i++)
            {
                string name = System.Text.Encoding.Default.GetString(rowsOfQueryRows.Value.ARow[i].LpProps[1].Value.LpszA);

                // Server will ignore cases when comparing string according to section 2.2.6 in Open Specification MS-OXNSPI.
                if (name.ToLower(System.Globalization.CultureInfo.CurrentCulture).Equals(userName.ToLower(System.Globalization.CultureInfo.CurrentCulture)))
                {
                    PermanentEntryID administratorEntryID = AdapterHelper.ParsePermanentEntryIDFromBytes(rowsOfQueryRows.Value.ARow[i].LpProps[0].Value.Bin.Lpb);
                    userESSDN = administratorEntryID.DistinguishedName;

                    break;
                }
            }
            #endregion

            #region Call NspiDNToMId to get the MIDs of specified user.
            uint reserved = 0;
            StringsArray_r names = new StringsArray_r();
            names.LppszA = new string[]
            {
                userESSDN
            };
            names.CValues = (uint)names.LppszA.Length;
            PropertyTagArray_r? mids;
            this.Result = this.ProtocolAdatper.NspiDNToMId(reserved, names, out mids);
            #endregion

            #region Call NspiGetMatches to get the specific PidTagAddressBookX509Certificate property to be modified.
            uint reserved1 = 0;
            uint reserver2 = 0;
            PropertyTagArray_r? proReserved = null;
            uint requested = 1;
            stat.CurrentRec = mids.Value.AulPropTag[0];
            Restriction_r? filter = null;
            PropertyTagArray_r propTags1 = new PropertyTagArray_r();
            propTags1.CValues = 2;
            propTags1.AulPropTag = new uint[2]
            {
                (uint)AulProp.PidTagAddressBookX509Certificate,
                (uint)AulProp.PidTagUserX509Certificate
            };
            PropertyTagArray_r? propTagsOfGetMatches = propTags1;

            // Set value for propNameOfGetMatches.
            PropertyName_r? propNameOfGetMatches = null;

            // Output parameters.
            PropertyTagArray_r? outMIds;
            PropertyRowSet_r? rowsOfGetMatches;

            this.Result = this.ProtocolAdatper.NspiGetMatches(reserved1, ref stat, proReserved, reserver2, filter, propNameOfGetMatches, requested, out outMIds, propTagsOfGetMatches, out rowsOfGetMatches);
            Site.Assert.AreEqual(ErrorCodeValue.Success, this.Result, "NspiGetMatches should return success!");
            Site.Assert.IsNotNull(outMIds.Value, "The Minimal Entry IDs returned successfully.");
            #endregion

            #region Call NspiModProps method with specific PidTagAddressBookX509Certificate property value.
            uint reservedOfModProps = 1;
            BinaryArray_r emptyValue = new BinaryArray_r();
            PropertyRow_r rowOfModProps = new PropertyRow_r();
            rowOfModProps.LpProps = new PropertyValue_r[2];
            rowOfModProps.LpProps[0].PropTag = (uint)AulProp.PidTagAddressBookX509Certificate;
            rowOfModProps.LpProps[0].Value.MVbin = emptyValue;
            rowOfModProps.LpProps[1].PropTag = (uint)AulProp.PidTagUserX509Certificate;
            rowOfModProps.LpProps[1].Value.MVbin = emptyValue;

            PropertyTagArray_r instanceOfModProps = new PropertyTagArray_r();
            instanceOfModProps.CValues = 2;
            instanceOfModProps.AulPropTag = new uint[2]
            {
                (uint)AulProp.PidTagAddressBookX509Certificate,
                (uint)AulProp.PidTagUserX509Certificate
            };
            PropertyTagArray_r? propTagsOfModProps = instanceOfModProps;

            this.Result = this.ProtocolAdatper.NspiModProps(reservedOfModProps, stat, propTagsOfModProps, rowOfModProps);

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1305
            Site.CaptureRequirementIfAreEqual<ErrorCodeValue>(
                ErrorCodeValue.Success,
                this.Result,
                1305,
                @"[In NspiModProps] [Server Processing Rules: Upon receiving message NspiModProps, the server MUST process the data from the message subject to the following constraints:] [constraint 12] If no other return values have been specified by these constraints [constraints 1-11], the server MUST return the return value ""Success"".");

            // If the codes can reach here, the requirement based on this must have been captured, so it can be captured directly.
            Site.CaptureRequirement(
                "MS-OXPROPS",
                5309,
                @"[In PidTagAddressBookX509Certificate] Property ID: 0x8C6A.");

            // If the codes can reach here, the requirement based on this must have been captured, so it can be captured directly.
            Site.CaptureRequirement(
                "MS-OXPROPS",
                5310,
                @"[In PidTagAddressBookX509Certificate] Data type: PtypMultipleBinary, 0x1102.");

            // If the codes can reach here, the requirement based on this must have been captured, so it can be captured directly.
            Site.CaptureRequirement(
                "MS-OXPROPS",
                8875,
                @"[In PidTagUserX509Certificate] Property ID: 0x3A70.");

            // If the codes can reach here, the requirement based on this must have been captured, so it can be captured directly.
            Site.CaptureRequirement(
                "MS-OXPROPS",
                8876,
                @"[In PidTagUserX509Certificate] Data type: PtypMultipleBinary, 0x1102.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1267
            Site.CaptureRequirementIfAreEqual<ErrorCodeValue>(
                ErrorCodeValue.Success,
                this.Result,
                1267,
                @"[In NspiModProps] The NspiModProps method is used to modify the properties of an object in the address book.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1268
            Site.CaptureRequirementIfAreEqual<ErrorCodeValue>(
                ErrorCodeValue.Success,
                this.Result,
                1268,
                @"[In NspiModProps] This protocol supports the PidTagUserX509Certificate ([MS-OXPROPS] section 2.1044) and PidTagAddressBookX509Certificate ([MS-OXPROPS] section 2.566) properties.");

            bool isR1289Verified = reservedOfModProps != 0 && ErrorCodeValue.Success == this.Result;

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1289
            Site.CaptureRequirementIfIsTrue(
                isR1289Verified,
                1289,
                @"[In NspiModProps] [Server Processing Rules: Upon receiving message NspiModProps, the server MUST process the data from the message subject to the following constraints:] [Constraint 4] If the Reserved input parameter contains any value other than 0, the server MUST ignore the value.");
            #endregion
            #endregion

            #region Call NspiUnbind method to destroy the context handle.
            uint returnValue = this.ProtocolAdatper.NspiUnbind(0);
            Site.Assert.AreEqual<uint>(1, returnValue, "NspiUnbind method should return 1 (Success).");
            #endregion
        }
        /// <summary>
        /// The NspiQueryColumns method returns a list of all the properties that the server is aware of. 
        /// </summary>
        /// <param name="reserved">A DWORD value reserved for future use. Ignored by the server.</param>
        /// <param name="flags">A DWORD value that contains a set of bit flags.</param>
        /// <param name="columns">A PropertyTagArray_r structure that contains a list of proptags.</param>
        /// <param name="needRetry">A Boolean value indicates if need to retry to get an expected result. This parameter is designed to avoid meaningless retry when an error response is expected.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue NspiQueryColumns(uint reserved, uint flags, out PropertyTagArray_r? columns, bool needRetry = true)
        {
            ErrorCodeValue result;

            if (this.transport == "ncacn_http" || this.transport == "ncacn_ip_tcp")
            {
                result = this.nspiRpcAdapter.NspiQueryColumns(reserved, flags, out columns, needRetry);
            }
            else
            {
                result = this.nspiMapiHttpAdapter.QueryColumns(flags, out columns);
            }

            this.VerifyNspiQueryColumns(result, columns);
            this.VerifyTransport();
            return result;
        }
        public void MSOXNSPI_S04_TC04_ModLinkAttSuccessWithPidTagAddressBookPublicDelegates()
        {
            this.CheckProductSupported();
            this.CheckMAPIHTTPTransportSupported();
            bool isR2003009Enabled = Common.IsRequirementEnabled(2003009, this.Site);

            #region Call NspiBind to initiate a session between the client and the server.
            uint flags = 0;
            STAT stat = new STAT();
            stat.InitiateStat();
            FlatUID_r guid = new FlatUID_r();
            guid.Ab = new byte[16];
            FlatUID_r? serverGuid = guid;

            this.Result = this.ProtocolAdatper.NspiBind(flags, stat, ref serverGuid);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiBind should return Success!");

            #endregion

            #region Call NspiGetMatches method to get valid Minimal Entry IDs and rows.
            uint reserved1 = 0;
            uint reserver2 = 0;
            PropertyTagArray_r? proReserved = null;
            uint requested = Constants.GetMatchesRequestedRowNumber;

            // Create Restriction_r structure to use the display name of specific user as the filter parameter of NspiGetMatches method.
            Restriction_r propertyRestriction1 = new Restriction_r
            {
                Rt = 0x04,
                Res = new RestrictionUnion_r
                {
                    ResProperty = new Propertyrestriction_r
                    {
                        Relop = 0x04
                    }
                }
            };
            PropertyValue_r target = new PropertyValue_r
            {
                PropTag = (uint)AulProp.PidTagDisplayName,
                Reserved = 0
            };
            string userName = Common.GetConfigurationPropertyValue("User2Name", this.Site);
            if (this.Transport == "ncacn_http" || this.Transport == "ncacn_ip_tcp")
            {
                target.Value.LpszA = System.Text.Encoding.UTF8.GetBytes(userName);
            }
            else
            {
                target.Value.LpszA = System.Text.Encoding.UTF8.GetBytes(userName + "\0");
            }

            propertyRestriction1.Res.ResProperty.Prop = new PropertyValue_r[] { target };
            propertyRestriction1.Res.ResProperty.PropTag = (uint)AulProp.PidTagDisplayName;

            Restriction_r propertyRestriction2 = new Restriction_r
            {
                Rt = 0x04,
                Res = new RestrictionUnion_r
                {
                    ResProperty = new Propertyrestriction_r
                    {
                        Relop = 0x04
                    }
                }
            };
            string administratorName = Common.GetConfigurationPropertyValue("User1Name", this.Site);
            if (this.Transport == "ncacn_http" || this.Transport == "ncacn_ip_tcp")
            {
                target.Value.LpszA = System.Text.Encoding.UTF8.GetBytes(administratorName);
            }
            else
            {
                target.Value.LpszA = System.Text.Encoding.UTF8.GetBytes(administratorName + "\0");
            }

            propertyRestriction2.Res.ResProperty.Prop = new PropertyValue_r[] { target };
            propertyRestriction2.Res.ResProperty.PropTag = (uint)AulProp.PidTagDisplayName;

            Restriction_r restrictionOr = new Restriction_r
            {
                Rt = 0x01,
                Res =
                    new RestrictionUnion_r
                    {
                        ResOr = new OrRestriction_r
                        {
                            CRes = 2,
                            LpRes = new Restriction_r[]
                            {
                                propertyRestriction1, propertyRestriction2
                            }
                        }
                    }
            };

            Restriction_r? filter = restrictionOr;

            PropertyName_r? propNameOfGetMatches = null;
            PropertyTagArray_r propTags = new PropertyTagArray_r
            {
                CValues = 3,
                AulPropTag = new uint[3]
                {
                    (uint)AulProp.PidTagEntryId,
                    (uint)AulProp.PidTagDisplayName,
                    unchecked((uint)AulProp.PidTagAddressBookPublicDelegates),
                }
            };
            PropertyTagArray_r? propTagsOfGetMatches = propTags;

            // Output parameters.
            PropertyTagArray_r? outMIds;
            PropertyRowSet_r? rowsOfGetMatches;

            this.Result = this.ProtocolAdatper.NspiGetMatches(reserved1, ref stat, proReserved, reserver2, filter, propNameOfGetMatches, requested, out outMIds, propTagsOfGetMatches, out rowsOfGetMatches);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiGetMatches should return Success!");
            #endregion

            #region Call NspiModLinkAtt method to add the specified PidTagAddressBookPublicDelegates value.
            uint flag1 = 0x00;
            uint propTagOfModLinkAtt = (uint)AulProp.PidTagAddressBookPublicDelegates;
            uint midOfModLinkAtt = 0;
            BinaryArray_r entryId = new BinaryArray_r
            {
                CValues = 1,
                Lpbin = new Binary_r[1]
            };

            // Get user name
            string name = string.Empty;
            int i = 0;
            for (i = 0; i < rowsOfGetMatches.Value.CRows; i++)
            {
                name = System.Text.Encoding.UTF8.GetString(rowsOfGetMatches.Value.ARow[i].LpProps[1].Value.LpszA);

                // Server will ignore cases when comparing string according to section 2.2.6 in Open Specification MS-OXNSPI.
                if (name.ToLower(System.Globalization.CultureInfo.CurrentCulture).Equals(userName.ToLower(System.Globalization.CultureInfo.CurrentCulture)))
                {
                    midOfModLinkAtt = outMIds.Value.AulPropTag[i];
                    this.MidToBeModified = midOfModLinkAtt;
                }
                else if (name.ToLower(System.Globalization.CultureInfo.CurrentCulture).Equals(administratorName.ToLower(System.Globalization.CultureInfo.CurrentCulture)))
                {
                    entryId.Lpbin[0] = rowsOfGetMatches.Value.ARow[i].LpProps[0].Value.Bin;
                    this.EntryIdToBeDeleted = entryId;
                }

                if (this.MidToBeModified != 0 && this.EntryIdToBeDeleted.Lpbin[0].Cb != 0)
                {
                    break;
                }
            }

            ErrorCodeValue flag1Result;
            if (!isR2003009Enabled)
            {
                flag1Result = this.ProtocolAdatper.NspiModLinkAtt(flag1, propTagOfModLinkAtt, midOfModLinkAtt, entryId);
                Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, flag1Result, "NspiModLinkAtt method should return Success.");
            }
            else
            {
                flag1Result = this.ProtocolAdatper.NspiModLinkAtt(flag1, propTagOfModLinkAtt, midOfModLinkAtt, entryId, false);
            }

            this.IsRequireToDeleteAddressBookPublicDelegate = true;
            #endregion

            #region Call NspiGetMatches to check the NspiModLinkAtt result.
            this.Result = this.ProtocolAdatper.NspiGetMatches(reserved1, ref stat, proReserved, reserver2, filter, propNameOfGetMatches, requested, out outMIds, propTagsOfGetMatches, out rowsOfGetMatches);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiGetMatches should return Success!");

            // PidTagAddressBookPublicDelegates proptag after adding value.
            uint addressBookPublicDelegatesTagAfterAdd = 0;
            for (i = 0; i < rowsOfGetMatches.Value.CRows; i++)
            {
                name = System.Text.Encoding.Default.GetString(rowsOfGetMatches.Value.ARow[i].LpProps[1].Value.LpszA);

                // Server will ignore cases when comparing string according to section 2.2.6 in Open Specification MS-OXNSPI.
                if (name.ToLower(System.Globalization.CultureInfo.CurrentCulture).Equals(userName.ToLower(System.Globalization.CultureInfo.CurrentCulture)))
                {
                    // After adding value this value should not be 0x8015000a
                    addressBookPublicDelegatesTagAfterAdd = rowsOfGetMatches.Value.ARow[i].LpProps[2].PropTag;

                    break;
                }
            }

            #endregion

            #region Call NspiModLinkAtt method to delete the specified PidTagAddressBookPublicDelegates value.
            uint flagsOfModLinkAtt = (uint)NspiModLinkAtFlag.fDelete;
            if (!isR2003009Enabled)
            {
                this.Result = this.ProtocolAdatper.NspiModLinkAtt(flagsOfModLinkAtt, propTagOfModLinkAtt, midOfModLinkAtt, entryId);
                Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiModLinkAtt method should return Success.");
            }
            else
            {
                this.Result = this.ProtocolAdatper.NspiModLinkAtt(flagsOfModLinkAtt, propTagOfModLinkAtt, midOfModLinkAtt, entryId, false);
            }

            this.IsRequireToDeleteAddressBookPublicDelegate = false;
            #endregion

            #region Call NspiGetMatches to check the NspiModLinkAtt result.
            this.Result = this.ProtocolAdatper.NspiGetMatches(reserved1, ref stat, proReserved, reserver2, filter, propNameOfGetMatches, requested, out outMIds, propTagsOfGetMatches, out rowsOfGetMatches);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiGetMatches should return Success!");

            #region Capture code
            // PidTagAddressBookPublicDelegates proptag after deleting value.
            uint addressBookPublicDelegatesTagAfterDelete = 0;
            for (i = 0; i < rowsOfGetMatches.Value.CRows; i++)
            {
                name = System.Text.Encoding.Default.GetString(rowsOfGetMatches.Value.ARow[i].LpProps[1].Value.LpszA);

                // Server will ignore cases when comparing string according to section 2.2.6 in Open Specification MS-OXNSPI.
                if (name.ToLower(System.Globalization.CultureInfo.CurrentCulture).Equals(userName.ToLower(System.Globalization.CultureInfo.CurrentCulture)))
                {
                    // After deleting value this value should be 0x8015000a
                    addressBookPublicDelegatesTagAfterDelete = rowsOfGetMatches.Value.ARow[i].LpProps[2].PropTag;

                    break;
                }
            }

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-OXNSPI_R2002, the property tag of address book delegate after adding value is {0}, and the property tag of it after deleting value is {1}",
                addressBookPublicDelegatesTagAfterAdd,
                addressBookPublicDelegatesTagAfterDelete);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R2002
            // The proptag of PidTagAddressBookPublicDelegates property is 0x8015101e as defined in [MS-OXPROPS]. If the last four bytes is 0x000a when returned, it means the property has no value.
            // Since the property has no value before the NspiModLinkAtt method is called to add value, and has value after that, then has no value after deleting the value, this requirement can be verified.
            Site.CaptureRequirementIfIsTrue(
                addressBookPublicDelegatesTagAfterAdd != 0x8015000a && addressBookPublicDelegatesTagAfterDelete == 0x8015000a,
                2002,
                @"[In NspiModLinkAtt] This protocol supports modifying the value of the PidTagAddressBookPublicDelegates ([MS-OXPROPS] section 2.557) property of an address book object with display type DT_MAILUSER.");

            #endregion
            #endregion

            #region Call NspiModLinkAtt method twice with different flag value.
            flag1 = 0xff;
            uint flag2 = 0xfe;

            if (!isR2003009Enabled)
            {
                flag1Result = this.ProtocolAdatper.NspiModLinkAtt(flag1, propTagOfModLinkAtt, midOfModLinkAtt, entryId);
                Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, flag1Result, "NspiModLinkAtt method should return Success.");
            }
            else
            {
                flag1Result = this.ProtocolAdatper.NspiModLinkAtt(flag1, propTagOfModLinkAtt, midOfModLinkAtt, entryId, false);
            }

            this.IsRequireToDeleteAddressBookPublicDelegate = true;

            ErrorCodeValue flag2Result;
            if (!isR2003009Enabled)
            {
                flag2Result = this.ProtocolAdatper.NspiModLinkAtt(flag2, propTagOfModLinkAtt, midOfModLinkAtt, entryId);
                Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, flag2Result, "NspiModLinkAtt method should return Success.");
            }
            else
            {
                flag2Result = this.ProtocolAdatper.NspiModLinkAtt(flag2, propTagOfModLinkAtt, midOfModLinkAtt, entryId, false);
            }

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1927
            Site.CaptureRequirementIfAreEqual<ErrorCodeValue>(
                flag1Result,
                flag2Result,
                1927,
                @"[In NspiModLinkAtt] If dwFlags is set to different values other than the bit flag fDelete, server will return the same result.");
            #endregion

            #region Call NspiModLinkAtt method to delete the specified PidTagAddressBookPublicDelegates value.
            if (!isR2003009Enabled)
            {
                this.Result = this.ProtocolAdatper.NspiModLinkAtt(flagsOfModLinkAtt, propTagOfModLinkAtt, midOfModLinkAtt, entryId);
                Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiModLinkAtt method should return Success.");
            }
            else
            {
                this.Result = this.ProtocolAdatper.NspiModLinkAtt(flagsOfModLinkAtt, propTagOfModLinkAtt, midOfModLinkAtt, entryId, false);
            }

            this.IsRequireToDeleteAddressBookPublicDelegate = false;
            #endregion

            #region Call NspiUnbind method to destroy the context handle.
            uint returnValue = this.ProtocolAdatper.NspiUnbind(0);
            Site.Assert.AreEqual<uint>(1, returnValue, "NspiUnbind method should return 1 (Success).");
            #endregion
        }
        /// <summary>
        /// The NspiGetProps method returns an address book row that contains a set of the properties
        /// and values that exist on an object.
        /// </summary>
        /// <param name="flags">A DWORD value that contains a set of bit flags.</param>
        /// <param name="stat">A STAT block that describes a logical position in a specific address book container.</param>
        /// <param name="propTags">The value NULL or a reference to a PropertyTagArray_r value. 
        /// It contains a list of the proptags of the properties that the client wants to be returned.</param>
        /// <param name="rows">A nullable PropertyRow_r value. 
        /// It contains the address book container row the server returns in response to the request.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue GetProps(uint flags, STAT stat, PropertyTagArray_r? propTags, out PropertyRow_r? rows)
        {
            ErrorCodeValue result;
            GetPropsRequestBody getPropertyRequestBody = null;
            LargePropTagArray propetyTags = new LargePropTagArray();
            if (propTags != null)
            {
                propetyTags.PropertyTagCount = propTags.Value.CValues;
                propetyTags.PropertyTags = new PropertyTag[propetyTags.PropertyTagCount];
                for (int i = 0; i < propTags.Value.CValues; i++)
                {
                    propetyTags.PropertyTags[i].PropertyId = (ushort)((propTags.Value.AulPropTag[i] & 0xFFFF0000) >> 16);
                    propetyTags.PropertyTags[i].PropertyType = (ushort)(propTags.Value.AulPropTag[i] & 0x0000FFFF);
                }

                getPropertyRequestBody = this.BuildGetPropsRequestBody(flags, true, stat, true, propetyTags);
            }
            else
            {
                getPropertyRequestBody = this.BuildGetPropsRequestBody(flags, true, stat, false, propetyTags);
            }

            ChunkedResponse chunkedResponse = this.SendAddressBookRequest(getPropertyRequestBody, RequestType.GetProps);
            GetPropsResponseBody getPropsResponseBody = GetPropsResponseBody.Parse(chunkedResponse.ResponseBodyRawData);
            result = (ErrorCodeValue)getPropsResponseBody.ErrorCode;
            if (getPropsResponseBody.HasPropertyValues)
            {
                PropertyRow_r propertyRow = AdapterHelper.ParsePropertyRow_r(getPropsResponseBody.PropertyValues.Value);
                rows = propertyRow;
            }
            else
            {
                rows = null;
            }

            return result;
        }