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
        }
        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
        }
        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_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>
        /// Verify BinaryArray_r structure.
        /// </summary>
        /// <param name="binaryArray">A BinaryArray_r value to be verified.</param>
        private void VerifyBinaryArray_r(BinaryArray_r binaryArray)
        {
            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1568
            // Because the underlying parser code has parsed out the structure which contains it, this requirement can be captured directly.
            this.Site.CaptureRequirement(
                1568,
                @"[In BinaryArray_r Structure] [The type is defined as following:] typedef struct _BinaryArray_r {
                    [range(0,100000)] DWORD cValues;
                    [size_is(cValues)] Binary_r* lpbin;
                } BinaryArray_r;");

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R163: the cValues in BinaryArray_r Structure is {0}.", binaryArray.CValues);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R163
            this.Site.CaptureRequirementIfIsTrue(
                binaryArray.CValues <= 100000,
                163,
                @"[In BinaryArray_r Structure] [cValues] This value MUST NOT exceed 100,000.");

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R161
            // 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(
                161,
                @"[In BinaryArray_r Structure] The BinaryArray_r structure is an array of Binary_r data structures.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R162
            this.Site.CaptureRequirementIfAreEqual<int>(
                binaryArray.Lpbin.Length,
                (int)binaryArray.CValues,
                162,
                @"[In BinaryArray_r Structure] cValues: The number of Binary_r data structures represented in the BinaryArray_r structure.");

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R164
            // 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(
                164,
                @"[In BinaryArray_r Structure] lpbin: The Binary_r data structures.");

            this.VerifyPropertyStructures();

            foreach (Binary_r binary in binaryArray.Lpbin)
            {
                this.VerifyBinary_r(binary);
            }
        }
        /// <summary>
        /// The NspiModLinkAtt method modifies the values of a specific property of a specific row in the address book.
        /// </summary>
        /// <param name="flags">A DWORD value that contains a set of bit flags.</param>
        /// <param name="propTag">A DWORD value. It contains the proptag of the property that the client wants to modify.</param>
        /// <param name="mid">A DWORD value that contains the Minimal Entry ID of the address book row that the client wants to modify.</param>
        /// <param name="entryIds">A BinaryArray value. It contains a list of EntryIDs to be used to modify the requested property on the requested 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 NspiModLinkAtt(uint flags, uint propTag, uint mid, BinaryArray_r entryIds, bool needRetry = true)
        {
            ErrorCodeValue result;
            if (this.transport == "ncacn_http" || this.transport == "ncacn_ip_tcp")
            {
                result = this.nspiRpcAdapter.NspiModLinkAtt(flags, propTag, mid, entryIds, needRetry);
            }
            else
            {
                result = this.nspiMapiHttpAdapter.ModLinkAtt(flags, propTag, mid, entryIds);
            }

            this.VerifyNspiModLinkAtt(result);
            this.VerifyTransport();
            return result;
        }
        /// <summary>
        /// The NspiModLinkAtt method modifies the values of a specific property of a specific row in the address book.
        /// </summary>
        /// <param name="flags">A DWORD value that contains a set of bit flags.</param>
        /// <param name="propTag">A DWORD value. It contains the proptag of the property that the client wants to modify.</param>
        /// <param name="mid">A DWORD value that contains the Minimal Entry ID of the address book row that the client wants to modify.</param>
        /// <param name="entryIds">A BinaryArray value. It contains a list of EntryIDs to be used to modify the requested property on the requested address book row.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue ModLinkAtt(uint flags, uint propTag, uint mid, BinaryArray_r entryIds)
        {
            ErrorCodeValue result;
            ModLinkAttRequestBody modLinkAttRequestBody = new ModLinkAttRequestBody();
            modLinkAttRequestBody.Flags = flags;
            modLinkAttRequestBody.PropertyTag = new PropertyTag()
            {
                PropertyId = (ushort)((propTag & 0xFFFF0000) >> 16),
                PropertyType = (ushort)(propTag & 0x0000FFFF)
            };
            modLinkAttRequestBody.MinimalId = mid;
            if (entryIds.CValues != 0)
            {
                modLinkAttRequestBody.HasEntryIds = true;
                modLinkAttRequestBody.EntryIdCount = entryIds.CValues;
                modLinkAttRequestBody.EntryIDs = new byte[entryIds.CValues][];
                for (int i = 0; i < entryIds.CValues; i++)
                {
                    List<byte> entryIDBytes = new List<byte>();
                    entryIDBytes.AddRange(BitConverter.GetBytes((uint)entryIds.Lpbin[i].Lpb.Length));
                    entryIDBytes.AddRange(entryIds.Lpbin[i].Lpb);
                    modLinkAttRequestBody.EntryIDs[i] = entryIDBytes.ToArray();
                }
            }
            else
            {
                modLinkAttRequestBody.HasEntryIds = false;
            }

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

            ChunkedResponse chunkedResponse = this.SendAddressBookRequest(modLinkAttRequestBody, RequestType.ModLinkAtt);
            ModLinkAttResponseBody modLinkAttResponseBody = ModLinkAttResponseBody.Parse(chunkedResponse.ResponseBodyRawData);
            result = (ErrorCodeValue)modLinkAttResponseBody.ErrorCode;
            return result;
        }
        public void MSOXNSPI_S05_TC24_ModPropsFailedWithInvalidParameter()
        {
            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 NspiGetSpecialTable method to get a special table from the server.
            uint version = 0;
            PropertyRowSet_r? rows;

            // Set flags to the value "NspiUnicodeStrings".
            uint flagsOfGetSpecialTable = (uint)NspiGetSpecialTableFlags.NspiUnicodeStrings;
            this.Result = this.ProtocolAdatper.NspiGetSpecialTable(flagsOfGetSpecialTable, ref stat, ref version, out rows);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiGetSpecialTable should return Success!");
            #endregion

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R750
            Site.CaptureRequirementIfAreNotEqual<uint>(
                0,
                version,
                750,
                @"[In NspiGetSpecialTable] [Server Processing Rules: Upon receiving message NspiGetSpecialTable, the server MUST process the data from the message subject to the following constraints:] [Constraint 8] If the client is requesting the rows of the server's address book hierarchy table and the server returns the value ""Success"", the server MUST set the output parameter lpVersion to the version of the server's address book hierarchy table.");

            #endregion

            #region Call NspiModProps with pPropTags set to NULL.
            uint reservedOfModProps = 0;
            PropertyRow_r rowOfModProps = rows.Value.ARow[0];
            PropertyTagArray_r? propTagsOfModProps = null;
            if (this.Transport == "ncacn_http" || this.Transport == "ncacn_ip_tcp")
            {
                this.Result = this.ProtocolAdatper.NspiModProps(reservedOfModProps, stat, propTagsOfModProps, rowOfModProps);

                #region Capture code
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1291: the value of the NspiModProps result is {0}", this.Result);

                // Verify MS-OXNSPI requirement: MS-OXNSPI_R1291
                Site.CaptureRequirementIfIsTrue(
                    propTagsOfModProps == null && this.Result == ErrorCodeValue.InvalidParameter,
                    1291,
                    @"[In NspiModProps] [Server Processing Rules: Upon receiving message NspiModProps, the server MUST process the data from the message subject to the following constraints:] [Constraint 5] If the input parameter pPropTags is NULL, the server MUST return the value ""InvalidParameter"".");

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

                // Verify MS-OXCDATA requirement: MS-OXCDATA_R903
                Site.CaptureRequirementIfAreEqual<ErrorCodeValue>(
                    ErrorCodeValue.InvalidParameter,
                    this.Result,
                    "MS-OXCDATA",
                    903,
                    @"[In Error Codes] InvalidParameter(E_INVALIDARG, MAPI_E_INVALID_PARAMETER, ecInvalidParam, ecInvalidSession, ecBadBuffer,
                SYNC_E_INVALID_PARAMETER) will be returned, if an invalid parameter was passed to a remote procedure call (RPC).");

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

                // Verify MS-OXCDATA requirement: MS-OXCDATA_R904
                Site.CaptureRequirementIfAreEqual<uint>(
                    0x80070057,
                    (uint)this.Result,
                    "MS-OXCDATA",
                    904,
                    @"[In Error Codes] The numeric value (hex) for error code InvalidParameter is 0x80070057, %x57.00.07.80.");
                #endregion
            }
            #endregion

            #region Call NspiGetSpecialTable method to get the special table again.
            PropertyRowSet_r? rows1;
            this.Result = this.ProtocolAdatper.NspiGetSpecialTable(flagsOfGetSpecialTable, ref stat, ref version, out rows1);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiGetSpecialTable should return Success!");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1284
            Site.CaptureRequirementIfIsTrue(
                AdapterHelper.AreTwoPropertyRowSetEqual(rows, rows1),
                1284,
                @"[In NspiModProps] [Server Processing Rules: Upon receiving message NspiModProps, the server MUST process the data from the message subject to the following constraints:] [Constraint 2] If the server returns any return value other than ""Success"", the server MUST NOT modify any properties of any objects in the address book.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R750001
            Site.CaptureRequirementIfIsTrue(
                AdapterHelper.AreTwoPropertyRowSetEqual(rows, rows1),
                750001,
                @"[In NspiGetSpecialTable] The Exchange server behavior is considered special as the Ipversion here does not impact any search results. ");
            #endregion
            #endregion

            #region Call NspiModProps again with the CurrentRec field of the input parameter pStat set to an invalid value, so that the server cannot locate the object specified by the invalid CurrentRec.
            reservedOfModProps = 0;
            BinaryArray_r certificate = new BinaryArray_r();
            rowOfModProps = new PropertyRow_r
            {
                LpProps = new PropertyValue_r[1]
            };
            rowOfModProps.LpProps[0].PropTag = (uint)AulProp.PidTagAddressBookX509Certificate;
            rowOfModProps.LpProps[0].Value.MVbin = certificate;

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

            // Set CurrentRec to a value which server is unable to locate.
            stat.CurrentRec = (uint)MinimalEntryID.MID_CURRENT;
            this.Result = this.ProtocolAdatper.NspiModProps(reservedOfModProps, stat, propTagsOfModProps, rowOfModProps);

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1293
            Site.CaptureRequirementIfAreEqual<ErrorCodeValue>(
                ErrorCodeValue.InvalidParameter,
                this.Result,
                1293,
                @"[In NspiModProps] [Server Processing Rules: Upon receiving message NspiModProps, the server MUST process the data from the message subject to the following constraints:] [Constraint 6] If the server is unable to locate the object specified by the CurrentRec field of the input parameter pStat, the server MUST return the value ""InvalidParameter"".");
            #endregion
            #endregion

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

            #region Call NspiBind to initiate a session between the client and the server.
            uint flags = 0; // A value which does not contain fDelete flag (0x1).
            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 to get an Explicit Table.
            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 agentName = Common.GetConfigurationPropertyValue("AgentName", this.Site);
            if (this.Transport == "ncacn_http" || this.Transport == "ncacn_ip_tcp")
            {
                target.Value.LpszA = System.Text.Encoding.UTF8.GetBytes(agentName);
            }
            else
            {
                target.Value.LpszA = System.Text.Encoding.UTF8.GetBytes(agentName + "\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 to modify the value of the PidTagAddressBookMember property of an address book object with display type DT_AGENT, which is not allowed by the server.

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

            for (int i = 0; i < rowsOfGetMatches.Value.CRows; i++)
            {
                string 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(agentName.ToLower(System.Globalization.CultureInfo.CurrentCulture)))
                {
                    midOfModLinkAtt = outMIds.Value.AulPropTag[i];
                }
                else if (name.ToLower(System.Globalization.CultureInfo.CurrentCulture).Equals(memberName.ToLower(System.Globalization.CultureInfo.CurrentCulture)))
                {
                    entryId.Lpbin[0] = rowsOfGetMatches.Value.ARow[i].LpProps[0].Value.Bin;
                }

                if (midOfModLinkAtt != 0 && entryId.Lpbin[0].Cb != 0)
                {
                    break;
                }
            }
            
            // Modify the PidTagAddressBookMember.
            this.Result = this.ProtocolAdatper.NspiModLinkAtt(flagsOfModLinkAtt, propTagOfModLinkAtt, midOfModLinkAtt, entryId);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.AccessDenied, this.Result, "NspiModLinkAtt method should return access denied.");
            #endregion

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1647
            Site.CaptureRequirementIfAreEqual<ErrorCodeValue>(
                ErrorCodeValue.AccessDenied,
                this.Result,
                1647,
                @"[In NspiModLinkAtt] [Server Processing Rules: Upon receiving message NspiModLinkAtt, the server MUST process the data from the message subject to the following constraints:] [Constraint 5] [If the server is able to locate the object, but will not allow modifications to the object due to its display type,] the server MUST return the value AccessDenied (0x80070005).");
            #endregion

            #region Call NspiGetMatches to get an Explicit Table.
            // Output parameters.
            PropertyTagArray_r? outMIds1;
            PropertyRowSet_r? rowsOfGetMatches1;

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

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1646
            Site.CaptureRequirementIfIsTrue(
                AdapterHelper.AreTwoPropertyRowSetEqual(rowsOfGetMatches, rowsOfGetMatches1),
                1646,
                @"[In NspiModLinkAtt] [Server Processing Rules: Upon receiving message NspiModLinkAtt, the server MUST process the data from the message subject to the following constraints:] [Constraint 5] If the server is able to locate the object, but will not allow modifications to the object due to its display type, the server MUST NOT modify any properties of any objects in the address book.");
            #endregion

            #region Call NspiModLinkAtt to modify the value of the PidTagAddressBookPublicDelegates property of an address book object with display type DT_AGENT, which is not allowed by the server.
            // Set an invalid mail user name.
            string userName = Common.GetConfigurationPropertyValue("AgentName", this.Site);
            for (int i = 0; i < rowsOfGetMatches.Value.CRows; i++)
            {
                string 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)))
                {
                    midOfModLinkAtt = outMIds.Value.AulPropTag[i];
                    entryId.Lpbin[0] = rowsOfGetMatches.Value.ARow[i].LpProps[0].Value.Bin;
                    break;
                }
            }

            // Modify PidTagAddressBookPublicDelegates.
            propTagOfModLinkAtt = (uint)AulProp.PidTagAddressBookPublicDelegates;
            this.Result = this.ProtocolAdatper.NspiModLinkAtt(flagsOfModLinkAtt, propTagOfModLinkAtt, midOfModLinkAtt, entryId);

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1338
            Site.CaptureRequirementIfAreEqual<ErrorCodeValue>(
                ErrorCodeValue.AccessDenied,
                this.Result,
                1338,
                @"[In NspiModLinkAtt] [Server Processing Rules: Upon receiving message NspiModLinkAtt, the server MUST process the data from the message subject to the following constraints:] [Constraint 8] If the server is unable to apply the modifications specified, the server MUST return the value ""AccessDenied"" (0x80070005).");

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

            // Verify MS-OXCDATA requirement: MS-OXCDATA_R907
            Site.CaptureRequirementIfAreEqual<ErrorCodeValue>(
                ErrorCodeValue.AccessDenied,
                this.Result,
                "MS-OXCDATA",
                907,
                @"[In Error Codes] AccessDenied(E_ACCESSDENIED, MAPI_E_NO_ACCESS, ecaccessdenied, ecpropsecurityviolation) will be returned, if the caller does not have sufficient access rights to perform the operation.");

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

            // Verify MS-OXCDATA requirement: MS-OXCDATA_R908
            Site.CaptureRequirementIfAreEqual<uint>(
                0x80070005,
                (uint)this.Result,
                "MS-OXCDATA",
                908,
                @"[In Error Codes] The numeric value (hex) for error code AccessDenied is 0x80070005, %x05.00.07.80.");

            #endregion
            #endregion

            #region Call NspiUnbind to destroy the session between the client and the server.
            uint returnValue = this.ProtocolAdatper.NspiUnbind(0);
            Site.Assert.AreEqual<uint>(1, returnValue, "NspiUnbind method should return 1 (Success).");
            #endregion
        }
        public void MSOXNSPI_S05_TC13_ModLinkAttFailedWithNotFound()
        {
            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 NspiGetMatches to get an Explicit Table.
            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 propertyRestriction = 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");
            }

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

            Restriction_r? filter = propertyRestriction;

            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 with an invalid input parameter ulPropTag, so that the server cannot recognize the proptag specified by the invalid ulPropTag.
            uint flagsOfModLinkAtt = 0; // A value which does not contain fDelete flag (0x1).
            uint midOfModLinkAtt = 0;
            BinaryArray_r entryId = new BinaryArray_r
            {
                CValues = 1,
                Lpbin = new Binary_r[1]
            };

            // Get user name.
            for (int i = 0; i < rowsOfGetMatches.Value.CRows; i++)
            {
                string 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)))
                {
                    midOfModLinkAtt = outMIds.Value.AulPropTag[i];
                    entryId.Lpbin[0] = rowsOfGetMatches.Value.ARow[i].LpProps[0].Value.Bin;
                    break;
                }
            }

            uint propTagOfModLinkAtt = (uint)AulProp.PidTagDisplayName;
            this.Result = this.ProtocolAdatper.NspiModLinkAtt(flagsOfModLinkAtt, propTagOfModLinkAtt, midOfModLinkAtt, entryId);

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1326
            Site.CaptureRequirementIfAreEqual<ErrorCodeValue>(
                ErrorCodeValue.NotFound,
                this.Result,
                1326,
                @"[In NspiModLinkAtt] [Server Processing Rules: Upon receiving message NspiModLinkAtt, the server MUST process the data from the message subject to the following constraints:] [Constraint 3] If the input parameter ulPropTag does not specify a proptag the server recognizes, the server MUST return NotFound.");

            #endregion
            #endregion

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

            #region Call NspiBind to initiate a session between the client and the server. The CodePage field of the input parameter pStat in this request is set to “CP_WINUNICODE”.
            STAT stat = new STAT();
            stat.InitiateStat();
            stat.CodePage = (uint)RequiredCodePage.CP_WINUNICODE;
            FlatUID_r guid = new FlatUID_r
            {
                Ab = new byte[16]
            };
            FlatUID_r? serverGuid = guid;

            uint flags = 0x0;
            this.Result = this.ProtocolAdatper.NspiBind(flags, stat, ref serverGuid);

            #region Capture
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R680, the value of the result is {0}", this.Result);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R680
            Site.CaptureRequirementIfIsTrue(
                Enum.IsDefined(typeof(ErrorCodeValue), this.Result),
                680,
                @"[In NspiBind] [Server Processing Rules: Upon receiving message NspiBind, the server MUST process the data from the message subject to the following constraints:] [constraint 1] If the CodePage field of the input parameter pStat contains the value CP_WINUNICODE, the server MUST return one of the return values [Success, UnbindSuccess, UnbindFailure, ErrorsReturned, GeneralFailure, NotSupported, InvalidObject, OutOfResources, NotFound, LogonFailed, TooComplex, InvalidCodepage, InvalidLocale, TableTooBig, InvalidBookmark, AccessDenied, NotEnoughMemory and InvalidParameter] specified in section 2.2.1.2.");

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R696, the value of the result is {0}", this.Result);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R696
            Site.CaptureRequirementIfAreEqual<ErrorCodeValue>(
                ErrorCodeValue.InvalidCodepage,
                this.Result,
                696,
                @"[In NspiBind] [Server Processing Rules: Upon receiving message NspiBind, the server MUST process the data from the message subject to the following constraints:] [constraint 5] If the server will not service connections using that code page, the server MUST return the error code ""InvalidCodepage"".");

            #endregion

            #endregion

            #region Call NspiBind to initiate a session between the client and the server.

            // Previous Bind operation should be failed, the following Bind operation may fail several times for same reason, so need retry.
            int tryTimes = Convert.ToInt32(Common.GetConfigurationPropertyValue("RetryCount", this.Site));
            stat.InitiateStat();
            for (int i = 0; i < tryTimes; i++)
            {
                this.Result = this.ProtocolAdatper.NspiBind(flags, stat, ref serverGuid);
                if (this.Result == ErrorCodeValue.Success)
                {
                    break;
                }
            }

            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiBind should return Success!");
            #endregion

            #region Call NspiGetSpecialTable with the CodePage field of the input parameter pStat in this request is set to “CP_WINUNICODE”.
            uint version = 0;
            PropertyRowSet_r? rows;

            // Set flags not to containing the flag NspiUnicodeStrings (0x04) and NspiAddressCreationTemplates (0x02).
            uint flagsOfGetSpecialTable = 0;

            // Set CodePage field of pStat to containing the value CP_WINUNICODE
            stat.CodePage = (uint)RequiredCodePage.CP_WINUNICODE;
            this.Result = this.ProtocolAdatper.NspiGetSpecialTable(flagsOfGetSpecialTable, ref stat, ref version, out rows, false);

            #region Capture code
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R732, the value of the result is {0}", this.Result);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R732
            Site.CaptureRequirementIfIsTrue(
                Enum.IsDefined(typeof(ErrorCodeValue), this.Result),
                732,
                @"[In NspiGetSpecialTable] [Server Processing Rules: Upon receiving message NspiGetSpecialTable, the server MUST process the data from the message subject to the following constraints:] [Constraint 1] If the input parameter dwFlags does not contain the value ""NspiUnicodeStrings"", and the input parameter dwFlags does not contain the value ""NspiAddressCreationTemplates"", and the CodePage field of the input parameter pStat contains the value CP_WINUNICODE, the server MUST return one of the return values [Success, UnbindSuccess, UnbindFailure, ErrorsReturned, GeneralFailure, NotSupported, InvalidObject, OutOfResources, NotFound, LogonFailed, TooComplex, InvalidCodepage, InvalidLocale, TableTooBig, InvalidBookmark, AccessDenied, NotEnoughMemory and InvalidParameter] specified in section 2.2.1.2.");
            #endregion
            #endregion

            #region Call NspiGetSpecialTable with the CodePage field of the input parameter pStat in this request is set to an invalid code page.
            stat.CodePage = 0xff;
            this.Result = this.ProtocolAdatper.NspiGetSpecialTable(flagsOfGetSpecialTable, ref stat, ref version, out rows, false);
            Site.Assert.AreNotEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiGetSpecialTable should not return Success!");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R736
            Site.CaptureRequirementIfIsNull(
                rows,
                736,
                @"[In NspiGetSpecialTable] [Server Processing Rules: Upon receiving message NspiGetSpecialTable, the server MUST process the data from the message subject to the following constraints:] [Constraint 2] If the server returns any return value other than ""Success"", the server MUST return a NULL for the output parameter ppRows.");
            #endregion

            #region Call NspiUpdateStat with CP_WINUNICODE CodePage.
            stat.CodePage = (uint)RequiredCodePage.CP_WINUNICODE;
            uint reserved = 0;
            int? delta = 0;
            stat.Delta = 2;
            ErrorCodeValue result1 = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta, false);

            #region Capture code
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R780, the value of the result1 is {0}", result1);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R780
            Site.CaptureRequirementIfIsTrue(
                Enum.IsDefined(typeof(ErrorCodeValue), result1),
                780,
                @"[In NspiUpdateStat] [Server Processing Rules: Upon receiving message NspiUpdateStat, the server MUST process the data from the message subject to the following constraints:] [Constraint 1] If the CodePage field of the input parameter pStat contains the value CP_WINUNICODE, the server MUST return one of the return values [Success, UnbindSuccess, UnbindFailure, ErrorsReturned, GeneralFailure, NotSupported, InvalidObject, OutOfResources, NotFound, LogonFailed, TooComplex, InvalidCodepage, InvalidLocale, TableTooBig, InvalidBookmark, AccessDenied, NotEnoughMemory and InvalidParameter] specified in section 2.2.1.2.");
            #endregion
            #endregion

            #region Call NspiGetProps with CP_WINUNICODE CodePage.

            PropertyTagArray_r? propTags;
            if (this.Transport == "ncacn_http" || this.Transport == "ncacn_ip_tcp")
            {
                PropertyTagArray_r? prop = null;
                propTags = prop;
            }
            else
            {
                PropertyTagArray_r prop = new PropertyTagArray_r
                {
                    CValues = 2
                };
                prop.AulPropTag = new uint[prop.CValues];
                prop.AulPropTag[0] = (uint)AulProp.PidTagEntryId;
                prop.AulPropTag[1] = (uint)AulProp.PidTagDisplayName;
                propTags = prop;
            }

            uint flagsOfGetProps = (uint)RetrievePropertyFlag.fEphID;
            stat.CodePage = (uint)RequiredCodePage.CP_WINUNICODE;
            PropertyRow_r? row;
            this.Result = this.ProtocolAdatper.NspiGetProps(flagsOfGetProps, stat, propTags, out row, false);

            #region Capture code
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R873, the value of the result is {0}", this.Result);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R873
            Site.CaptureRequirementIfIsTrue(
                Enum.IsDefined(typeof(ErrorCodeValue), this.Result),
                873,
                @"[In NspiGetProps] [Server Processing Rules: Upon receiving message NspiGetProps, the server MUST process the data from the message subject to the following constraints:] [Constraint 1] If the CodePage field of the input parameter pStat is set to the value CP_WINUNICODE and the type of the proptags in the input parameter pPropTags is PtypString8, the server MUST return one of the return values [Success, UnbindSuccess, UnbindFailure, ErrorsReturned, GeneralFailure, NotSupported, InvalidObject, OutOfResources, NotFound, LogonFailed, TooComplex, InvalidCodepage, InvalidLocale, TableTooBig, InvalidBookmark, AccessDenied, NotEnoughMemory and InvalidParameter] specified in section 2.2.1.2.");
            #endregion
            #endregion

            #region Call NspiGetProps with invalid CodePage.
            stat.CodePage = 0xff;
            ErrorCodeValue invalidCodePageNspiGetProps = this.ProtocolAdatper.NspiGetProps(flagsOfGetProps, stat, propTags, out row, false);
            Site.Assert.AreNotEqual<ErrorCodeValue>(ErrorCodeValue.Success, invalidCodePageNspiGetProps, "NspiGetProps should not return Success!");
            Site.Assert.AreNotEqual<ErrorCodeValue>(ErrorCodeValue.ErrorsReturned, invalidCodePageNspiGetProps, "NspiGetProps should not return ErrorsReturned!");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R877
            Site.CaptureRequirementIfIsNull(
                row,
                877,
                @"[In NspiGetProps] [Server Processing Rules: Upon receiving message NspiGetProps, the server MUST process the data from the message subject to the following constraints:] [Constraint 2] If the server returns any return values other than""ErrorsReturned"" (0x00040380) or ""Success"" (0x00000000), the server MUST return a NULL for the output parameter ppRows.");

            #endregion

            #region Call NspiQueryRows with CP_WINUNICODE CodePage.
            uint flagsOfQueryRows = (uint)RetrievePropertyFlag.fEphID;
            uint tableCount = 0;
            uint[] table = null;
            uint count = 10;
            PropertyRowSet_r? rowsOfQueryRows;

            PropertyTagArray_r propTagsInstance = new PropertyTagArray_r
            {
                CValues = 1,
                AulPropTag = new uint[1]
                {
                    (uint)AulProp.PidTagDisplayName,
                }
            };
            propTags = propTagsInstance;

            // Set the CodePage field of the input parameter pStat to containing the value CP_WINUNICODE.
            stat.CodePage = (uint)RequiredCodePage.CP_WINUNICODE;
            this.Result = this.ProtocolAdatper.NspiQueryRows(flagsOfQueryRows, ref stat, tableCount, table, count, propTags, out rowsOfQueryRows, false);

            #region Capture
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R935, the value of the result is {0}", this.Result);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R935
            Site.CaptureRequirementIfIsTrue(
                Enum.IsDefined(typeof(ErrorCodeValue), this.Result),
                935,
                @"[In NspiQueryRows] [Server Processing Rules: Upon receiving message NspiQueryRows, the server MUST process the data from the message subject to the following constraints:] [Constraint 1] If the CodePage field of the input parameter pStat contains the value CP_WINUNICODE, the server MUST return one of the return values [Success, UnbindSuccess, UnbindFailure, ErrorsReturned, GeneralFailure, NotSupported, InvalidObject, OutOfResources, NotFound, LogonFailed, TooComplex, InvalidCodepage, InvalidLocale, TableTooBig, InvalidBookmark, AccessDenied, NotEnoughMemory and InvalidParameter] specified in section 2.2.1.2.");
            #endregion Capture
            #endregion

            #region Call NspiQueryRows with invalid CodePage.
            stat.CodePage = 0xff;

            // Here use the same input parameter to call NspiQueryRows.
            ErrorCodeValue invalidCodePageNspiQueryRows = this.ProtocolAdatper.NspiQueryRows(flagsOfGetProps, ref stat, tableCount, table, count, propTags, out rowsOfQueryRows, false);
            Site.Assert.AreNotEqual<ErrorCodeValue>(ErrorCodeValue.Success, invalidCodePageNspiQueryRows, "NspiGetProps should not return Success!");
            Site.Assert.AreNotEqual<ErrorCodeValue>(ErrorCodeValue.ErrorsReturned, invalidCodePageNspiQueryRows, "NspiGetProps should not return ErrorsReturned!");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R982
            Site.CaptureRequirementIfAreEqual<ErrorCodeValue>(
                invalidCodePageNspiGetProps,
                invalidCodePageNspiQueryRows,
                982,
                @"[In NspiQueryRows] [Server Processing Rules: Upon receiving message NspiQueryRows, the server MUST process the data from the message subject to the following constraints:] [Constraint 14] If a call to the NspiGetProps method with these parameters [hRpc, dwFlags, pStat and pPropTags] would return any value other than ""Success"" or ""ErrorsReturned"", the server MUST return that error code as the return value for the NspiQueryRows method.");

            #endregion

            #region Call NspiSeekEntries with CP_WINUNICODE CodePage.
            uint reservedOfSeekEntries = 0;
            PropertyValue_r target = new PropertyValue_r
            {
                PropTag = 0x3001001F,
                Reserved = (uint)0x00
            };

            // Set property PidTagDisplayName (0x3001) with PtypString type (0x001F).
            string displayName;
            if (this.Transport == "ncacn_http" || this.Transport == "ncacn_ip_tcp")
            {
                displayName = Common.GetConfigurationPropertyValue("User1Name", this.Site);
            }
            else
            {
                displayName = Common.GetConfigurationPropertyValue("User1Name", this.Site) + "\0";
            }

            target.Value.LpszW = System.Text.Encoding.Unicode.GetBytes(displayName);

            PropertyTagArray_r tags = new PropertyTagArray_r
            {
                CValues = 1,
                AulPropTag = new uint[1]
                {
                    target.PropTag
                }
            };
            PropertyTagArray_r? propTagsOfSeekEntries = tags;

            PropertyTagArray_r? tableOfSeekEntries = null;
            PropertyRowSet_r? rowsOfSeekEntries;

            stat.CodePage = (uint)RequiredCodePage.CP_WINUNICODE;
            this.Result = this.ProtocolAdatper.NspiSeekEntries(reservedOfSeekEntries, ref stat, target, tableOfSeekEntries, propTagsOfSeekEntries, out rowsOfSeekEntries, false);

            #region Capture
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1016, the value of the result is {0}", this.Result);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1016
            Site.CaptureRequirementIfIsTrue(
                Enum.IsDefined(typeof(ErrorCodeValue), this.Result),
                1016,
                @"[In NspiSeekEntries] [Server Processing Rules: Upon receiving message NspiSeekEntries, the server MUST process the data from the message subject to the following constraints:] [Constraint 1] If the CodePage field of the input parameter pStat contains the value CP_WINUNICODE, the server MUST return one of the return values [Success, UnbindSuccess, UnbindFailure, ErrorsReturned, GeneralFailure, NotSupported, InvalidObject, OutOfResources, NotFound, LogonFailed, TooComplex, InvalidCodepage, InvalidLocale, TableTooBig, InvalidBookmark, AccessDenied, NotEnoughMemory and InvalidParameter] specified in section 2.2.1.2.");
            #endregion
            #endregion

            #region Call NspiGetMatches with CP_WINUNICODE CodePage.
            uint reserved1 = 0;
            uint reserver2 = 0;
            PropertyTagArray_r? proReserved = null;
            uint requested = Constants.GetMatchesRequestedRowNumber;

            Restriction_r res_r = new Restriction_r
            {
                Rt = 0x8,
                Res =
                    new RestrictionUnion_r
                    {
                        ResExist =
                            new ExistRestriction_r
                            {
                                Reserved1 = 0,
                                Reserved2 = 0,
                                PropTag = (uint)AulProp.PidTagEntryId
                            }
                    }
            };
            Restriction_r? filter = res_r;

            propTagsInstance = new PropertyTagArray_r
            {
                CValues = 3,
                AulPropTag = new uint[3]
                {
                    (uint)AulProp.PidTagEntryId,
                    (uint)AulProp.PidTagDisplayType,
                    (uint)AulProp.PidTagObjectType
                }
            };
            PropertyTagArray_r? propTagsOfGetMatches = propTagsInstance;
            PropertyName_r? propNameOfGetMatches = null;

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

            stat.CodePage = (uint)RequiredCodePage.CP_WINUNICODE;
            this.Result = this.ProtocolAdatper.NspiGetMatches(reserved1, ref stat, proReserved, reserver2, filter, propNameOfGetMatches, requested, out outMIds, propTagsOfGetMatches, out rowsOfGetMatches, false);

            #region Capture
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1101, the value of the result is {0}", this.Result);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1101
            Site.CaptureRequirementIfIsTrue(
                Enum.IsDefined(typeof(ErrorCodeValue), this.Result),
                1101,
                @"[In NspiGetMatches] [Server Processing Rules: Upon receiving message NspiGetMatches, the server MUST process the data from the message subject to the following constraints:] [Constraint 1] If the CodePage field of the input parameter pStat contains the value CP_WINUNICODE, the server MUST return one of the return values [Success, UnbindSuccess, UnbindFailure, ErrorsReturned, GeneralFailure, NotSupported, InvalidObject, OutOfResources, NotFound, LogonFailed, TooComplex, InvalidCodepage, InvalidLocale, TableTooBig, InvalidBookmark, AccessDenied, NotEnoughMemory and InvalidParameter] specified in section 2.2.1.2.");
            #endregion
            #endregion

            #region Call NspiResortRestriction with CP_WINUNICODE CodePage.
            #region NspiDNToMId
            reserved = 0;
            StringsArray_r names = new StringsArray_r
            {
                CValues = 3,
                LppszA = new string[3]
                {
                    Common.GetConfigurationPropertyValue("User1Essdn", this.Site),
                    Common.GetConfigurationPropertyValue("User2Essdn", this.Site),
                    Common.GetConfigurationPropertyValue("User3Essdn", this.Site),
                }
            };

            PropertyTagArray_r? mids;
            this.Result = this.ProtocolAdatper.NspiDNToMId(reserved, names, out mids);
            #endregion

            #region NspiResortRestriction

            uint reservedOfResortRestriction = 0;
            PropertyTagArray_r inmids = new PropertyTagArray_r();
            inmids = mids.Value;

            // If the object specified by the CurrentRec field of the input parameter pStat is in the constructed Explicit Table, the NumPos field of the output parameter pStat is set to the numeric position in the Explicit Table.
            stat.CodePage = (uint)RequiredCodePage.CP_WINUNICODE;
            stat.SortType = (uint)TableSortOrder.SortTypeDisplayName;
            outMIds = null;
            this.Result = this.ProtocolAdatper.NspiResortRestriction(reservedOfResortRestriction, ref stat, inmids, ref outMIds, false);

            #region Capture
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1181, the value of the result is {0}", this.Result);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1181
            Site.CaptureRequirementIfIsTrue(
                Enum.IsDefined(typeof(ErrorCodeValue), this.Result),
                1181,
                @"[In NspiResortRestriction] [Server Processing Rules: Upon receiving message NspiResortRestriction, the server MUST process the data from the message subject to the following constraints:] [Constraint 1] If the CodePage field of the input parameter pStat contains the value CP_WINUNICODE, the server MUST return one of the return values [Success, UnbindSuccess, UnbindFailure, ErrorsReturned, GeneralFailure, NotSupported, InvalidObject, OutOfResources, NotFound, LogonFailed, TooComplex, InvalidCodepage, InvalidLocale, TableTooBig, InvalidBookmark, AccessDenied, NotEnoughMemory and InvalidParameter] specified in section 2.2.1.2.");
            #endregion
            #endregion
            #endregion

            #region Call NspiCompareMIds with CP_WINUNICODE CodePage.
            #region NspiDNToMId
            reserved = 0;
            names = new StringsArray_r
            {
                CValues = 2,
                LppszA = new string[2]
            };
            names.LppszA[0] = Common.GetConfigurationPropertyValue("User3Essdn", this.Site);
            names.LppszA[1] = Common.GetConfigurationPropertyValue("User1Essdn", this.Site);
            this.Result = this.ProtocolAdatper.NspiDNToMId(reserved, names, out mids);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiDnToMId should return Success!");
            #endregion

            #region NspiCompareMIds
            uint mid1 = mids.Value.AulPropTag[0];
            uint mid2 = mids.Value.AulPropTag[1];
            uint reservedOfCompareMIds = 0;
            int results;

            stat.CodePage = (uint)RequiredCodePage.CP_WINUNICODE;
            this.Result = this.ProtocolAdatper.NspiCompareMIds(reservedOfCompareMIds, stat, mid1, mid2, out results, false);

            #region Capture
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1223, the value of the result is {0}", this.Result);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1223
            Site.CaptureRequirementIfIsTrue(
                Enum.IsDefined(typeof(ErrorCodeValue), this.Result),
                1223,
                @"[In NspiCompareMIds] [Server Processing Rules: Upon receiving message NspiCompareMIds, the server MUST process the data from the message subject to the following constraints:] [Constraint 1] If the CodePage field of the input parameter pStat contains the value CP_WINUNICODE, the server MUST return one of the return values [Success, UnbindSuccess, UnbindFailure, ErrorsReturned, GeneralFailure, NotSupported, InvalidObject, OutOfResources, NotFound, LogonFailed, TooComplex, InvalidCodepage, InvalidLocale, TableTooBig, InvalidBookmark, AccessDenied, NotEnoughMemory and InvalidParameter] specified in section 2.2.1.2.");
            #endregion
            #endregion
            #endregion

            #region Call NspiModProps with CP_WINUNICODE CodePage.
            #region NspiGetMatches
            // Call NspiGetMatches to get valid MIDs and rows.
            reserved1 = 0;
            reserver2 = 0;
            proReserved = null;
            requested = Constants.GetMatchesRequestedRowNumber;

            res_r = new Restriction_r
            {
                Rt = 0x8,
                Res =
                    new RestrictionUnion_r
                    {
                        ResExist =
                            new ExistRestriction_r
                            {
                                Reserved1 = 0,
                                Reserved2 = 0,
                                PropTag = (uint)AulProp.PidTagDisplayName
                            }
                    }
            };
            filter = res_r;

            propNameOfGetMatches = null;
            propTagsInstance = new PropertyTagArray_r
            {
                CValues = 1,
                AulPropTag = new uint[1]
                {
                    (uint)AulProp.PidTagDisplayName,
                }
            };
            propTagsOfGetMatches = propTagsInstance;

            stat.CodePage = (uint)RequiredCodePage.CP_TELETEX;
            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 NspiModProps
            // Call NspiModProps method with specific PidTagAddressBookX509Certificate tag.
            uint reservedOfModProps = 0;
            BinaryArray_r certificate = new BinaryArray_r();
            PropertyRow_r rowOfModProps = new PropertyRow_r
            {
                LpProps = new PropertyValue_r[1]
            };
            rowOfModProps.LpProps[0].PropTag = (uint)AulProp.PidTagAddressBookX509Certificate;
            rowOfModProps.LpProps[0].Value.MVbin = certificate;

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

            // Get user name.
            string userName = Common.GetConfigurationPropertyValue("User2Name", this.Site);

            // Set the CurrentRec field with the minimal entry ID of mail user name.
            for (int i = 0; i < rowsOfGetMatches.Value.CRows; i++)
            {
                string name = System.Text.Encoding.Default.GetString(rowsOfGetMatches.Value.ARow[i].LpProps[0].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)))
                {
                    stat.CurrentRec = outMIds.Value.AulPropTag[i];
                    break;
                }
            }

            stat.CodePage = (uint)RequiredCodePage.CP_WINUNICODE;
            this.Result = this.ProtocolAdatper.NspiModProps(reservedOfModProps, stat, propTagsOfModProps, rowOfModProps, false);

            #region Capture
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1280, the value of the result is {0}", this.Result);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1280
            Site.CaptureRequirementIfIsTrue(
                Enum.IsDefined(typeof(ErrorCodeValue), this.Result),
                1280,
                @"[In NspiModProps] [Server Processing Rules: Upon receiving message NspiModProps, the server MUST process the data from the message subject to the following constraints:] [Constraint 1] If the CodePage field of the input parameter pStat contains the value CP_WINUNICODE, the server MUST return one of the return values [Success, UnbindSuccess, UnbindFailure, ErrorsReturned, GeneralFailure, NotSupported, InvalidObject, OutOfResources, NotFound, LogonFailed, TooComplex, InvalidCodepage, InvalidLocale, TableTooBig, InvalidBookmark, AccessDenied, NotEnoughMemory and InvalidParameter] specified in section 2.2.1.2.");
            #endregion

            #endregion
            #endregion

            #region Call NspiResolveNames with CP_WINUNICODE CodePage.
            if (this.Transport == "ncacn_http" || this.Transport == "ncacn_ip_tcp")
            {
                StringsArray_r strArray;
                strArray.CValues = 2;
                strArray.LppszA = new string[strArray.CValues];
                strArray.LppszA[0] = Common.GetConfigurationPropertyValue("User1Name", this.Site);
                strArray.LppszA[1] = string.Empty;

                propTags = null;
                PropertyRowSet_r? rowOfResolveNames;

                stat.CodePage = (uint)RequiredCodePage.CP_WINUNICODE;
                this.Result = this.ProtocolAdatper.NspiResolveNames((uint)0, stat, propTags, strArray, out mids, out rowOfResolveNames, false);

                #region Capture
                // Add the debug information
                Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1359, the value of the result is {0}", this.Result);

                // Verify MS-OXNSPI requirement: MS-OXNSPI_R1359
                Site.CaptureRequirementIfIsTrue(
                    Enum.IsDefined(typeof(ErrorCodeValue), this.Result),
                    1359,
                    @"[In NspiResolveNames] [Server Processing Rules: Upon receiving message NspiResolveNames, the server MUST process the data from the message subject to the following constraints:] 
                [Constraint 1] If the CodePage field of the input parameter pStat contains the value CP_WINUNICODE, the server MUST return one of the return values [Success, UnbindSuccess, 
                UnbindFailure, ErrorsReturned, GeneralFailure, NotSupported, InvalidObject, OutOfResources, NotFound, LogonFailed, TooComplex, InvalidCodepage, InvalidLocale, TableTooBig, InvalidBookmark,
                AccessDenied, NotEnoughMemory and InvalidParameter] specified in section 2.2.2.");

                #endregion
            }
            #endregion

            #region Call NspiResolveNamesW with CP_WINUNICODE CodePage.
            uint reservedOfResolveNamesW = 0;
            WStringsArray_r wstrArray;
            wstrArray.CValues = 2;
            wstrArray.LppszW = new string[wstrArray.CValues];
            wstrArray.LppszW[0] = Common.GetConfigurationPropertyValue("User1Name", this.Site);
            wstrArray.LppszW[1] = Common.GetConfigurationPropertyValue("User2Name", this.Site);

            propTags = null;
            PropertyRowSet_r? rowOfResolveNamesW;

            stat.CodePage = (uint)RequiredCodePage.CP_WINUNICODE;
            this.Result = this.ProtocolAdatper.NspiResolveNamesW(reservedOfResolveNamesW, stat, propTags, wstrArray, out mids, out rowOfResolveNamesW, false);

            #region Capture
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1410, the value of the result is {0}", this.Result);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1410
            Site.CaptureRequirementIfIsTrue(
                Enum.IsDefined(typeof(ErrorCodeValue), this.Result),
                1410,
                @"[In NspiResolveNamesW] [Server Processing Rules: Upon receiving message NspiResolveNamesW, the server MUST process the data from the message subject to the following constraints:] [Constraint 1] If the CodePage field of the input parameter pStat contains the value CP_WINUNICODE, the server MUST return one of the return values [Success, UnbindSuccess, UnbindFailure, ErrorsReturned, GeneralFailure, NotSupported, InvalidObject, OutOfResources, NotFound, LogonFailed, TooComplex, InvalidCodepage, InvalidLocale, TableTooBig, InvalidBookmark, AccessDenied, NotEnoughMemory and InvalidParameter] specified in section 2.2.1.2.");
            #endregion
            #endregion

            #region Call NspiUnbind to destroy the session between the client and the server.
            uint returnValue = this.ProtocolAdatper.NspiUnbind(0);
            Site.Assert.AreEqual<uint>(1, returnValue, "NspiUnbind method should return 1 (Success).");
            #endregion
        }