/// <summary>
        /// The NspiBind method initiates a session between a client and the server.
        /// </summary>
        /// <param name="flags">A DWORD value that contains a set of bit flags.</param>
        /// <param name="stat">A STAT block that describes a logical position in a specific address book container.</param>
        /// <param name="serverGuid">The value NULL or a pointer to a GUID value that is associated with the specific server.</param>
        /// <returns>Status of NSPI method.</returns>
        public ErrorCodeValue Bind(uint flags, STAT stat, ref FlatUID_r? serverGuid)
        {
            ErrorCodeValue result;
            BindRequestBody bindRequestBody = this.BuildBindRequestBody(stat, flags);
            byte[] rawBuffer = null;
            ChunkedResponse chunkedResponse = null;
            BindResponseBody bindResponseBody = null;

            // Send the execute HTTP request and get the response
            HttpWebResponse response = MapiHttpAdapter.SendMAPIHttpRequest(this.site, this.addressBookUrl, this.userName, this.domainName, this.password, bindRequestBody, RequestType.Bind.ToString(), AdapterHelper.SessionContextCookies);

            // Read the HTTP response buffer and parse the response to correct format
            rawBuffer = MapiHttpAdapter.ReadHttpResponse(response);
            result = (ErrorCodeValue)int.Parse(response.Headers["X-ResponseCode"]);
            if (result == ErrorCodeValue.Success)
            {
                chunkedResponse = ChunkedResponse.ParseChunkedResponse(rawBuffer);
                bindResponseBody = BindResponseBody.Parse(chunkedResponse.ResponseBodyRawData);
                result = (ErrorCodeValue)bindResponseBody.ErrorCode;
                if (bindResponseBody.ServerGuid != null)
                {
                    FlatUID_r newGuid = new FlatUID_r();
                    newGuid.Ab = bindResponseBody.ServerGuid.ToByteArray();
                    serverGuid = newGuid;
                }
                else
                {
                    serverGuid = null;
                }
            }

            response.GetResponseStream().Close();
            AdapterHelper.SessionContextCookies = response.Cookies;
            return result;
        }
        public void MSOXNSPI_S02_TC22_ResortRestrictionSuccess()
        {
            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 NspiDNToMId method to get valid MIDs.
            uint reserved = 0;
            StringsArray_r names = new StringsArray_r
            {
                CValues = 3,
                LppszA = new string[3]
                {
                    Common.GetConfigurationPropertyValue("User2Essdn", this.Site),
                    Common.GetConfigurationPropertyValue("User1Essdn", this.Site),
                    Common.GetConfigurationPropertyValue("User3Essdn", this.Site),
                }
            };

            PropertyTagArray_r? mids;
            this.Result = this.ProtocolAdatper.NspiDNToMId(reserved, names, out mids);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiDNToMId should return Success!");
            #endregion

            #region Call NspiResortRestriction method with all valid parameters.
            uint reservedOfResortRestriction = 0;
            PropertyTagArray_r inmids = new PropertyTagArray_r();
            inmids = mids.Value;
            stat.InitiateStat();

            PropertyTagArray_r? outMIds = null;
            this.Result = this.ProtocolAdatper.NspiResortRestriction(reservedOfResortRestriction, ref stat, inmids, ref outMIds);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiResortRestriction method should succeed.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R538
            Site.CaptureRequirementIfAreEqual<uint>(
                stat.TotalRecs,
                outMIds.Value.CValues,
                538,
                @"[In Absolute Positioning] [step 3] The server reports this[the number of objects in the sorted table] in the TotalRecs field of the STAT structure.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1209
            Site.CaptureRequirementIfAreEqual(
                ErrorCodeValue.Success,
                this.Result,
                1209,
                @"[In NspiResortRestriction] [Server Processing Rules: Upon receiving message NspiResortRestriction, 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"".");

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

            // Verify MS-OXCDATA requirement: MS-OXCDATA_R897
            Site.CaptureRequirementIfAreEqual(
                ErrorCodeValue.Success,
                this.Result,
                "MS-OXCDATA",
                897,
                @"[In Error Codes] Success(S_OK, SUCCESS_SUCCESS) will be returned, if the operation succeeded.");

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

            // Verify MS-OXCDATA requirement: MS-OXCDATA_R898
            Site.CaptureRequirementIfAreEqual<uint>(
                0x0,
                (uint)this.Result,
                "MS-OXCDATA",
                898,
                @"[In Error Codes] The numeric value (hex) for error code Success is 0x00000000, %x00.00.00.00.");
            #endregion

            #endregion

            #region Call NspiQueryRows method to query rows which contain the specific properties.
            uint flagsOfQueryRows = (uint)RetrievePropertyFlag.fSkipObjects;
            uint tableCount = outMIds.Value.CValues;
            uint[] table = outMIds.Value.AulPropTag;
            uint count = outMIds.Value.CValues;
            PropertyRowSet_r? rowsOfQueryRows;

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

            this.Result = this.ProtocolAdatper.NspiQueryRows(flagsOfQueryRows, ref stat, tableCount, table, count, propTags, out rowsOfQueryRows);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiQueryRows should return Success");

            #region Capture

            // Add the debug information
            bool isCorrectOrder = false;
            for (int i = 0; i < count - 1; i++)
            {
                string displayName = System.Text.Encoding.Default.GetString(rowsOfQueryRows.Value.ARow[i].LpProps[0].Value.LpszA);
                string nextDisplayName = System.Text.Encoding.Default.GetString(rowsOfQueryRows.Value.ARow[i + 1].LpProps[0].Value.LpszA);
                if (i == 0)
                {
                    this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1168. The display name of the No.{0} object in the table is {1}.", i, displayName);
                }

                this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1168. The display name of the No.{0} object in the table is {1}.", i + 1, nextDisplayName);
                if (string.Compare(displayName, nextDisplayName, StringComparison.Ordinal) > 0)
                {
                    isCorrectOrder = false;
                    break;
                }
                else
                {
                    isCorrectOrder = true;
                }
            }

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1168
            this.Site.CaptureRequirementIfIsTrue(
                isCorrectOrder,
                1168,
                @"[In NspiResortRestriction] The NspiResortRestriction method applies a sort order to the objects in a restricted address book container.");

            #endregion Capture
            #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_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_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_S03_TC01_ResolveNamesSuccess()
        {
            this.CheckProductSupported();
            if (this.Transport == "mapi_http")
            {
                Site.Assert.Inconclusive("This case cannot run, since MAPIHTTP transport does not support ResolveNames operation for 8-bit character set string.");
            }

            #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 NspiResolveNames method with a specific list of names and propertyTag value with null.
            StringsArray_r strArray;
            strArray.CValues = 5;
            strArray.LppszA = new string[strArray.CValues];
            strArray.LppszA[0] = Common.GetConfigurationPropertyValue("User1Name", this.Site);
            strArray.LppszA[1] = string.Empty;
            strArray.LppszA[2] = Common.GetConfigurationPropertyValue("AmbiguousName", this.Site);
            strArray.LppszA[3] = null;
            strArray.LppszA[4] = Constants.UnresolvedName;

            PropertyTagArray_r? propTags = null;
            PropertyTagArray_r? mids;
            PropertyRowSet_r? rowOfResolveNames;

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

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

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

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1342
            // If the mids which contains Minimal Entry ID returned from the server is not null, 
            // it illustrates that the server must report the Minimal Entry ID that is the result of the ANR process.
            this.Site.CaptureRequirementIfIsNotNull(
                mids,
                1342,
                @"[In NspiResolveNames] The server reports the Minimal Entry ID that is the result of the ANR process.");

            this.VerifyPropertyRowSetIsNotNullForNspiResolveNames(rowOfResolveNames);

            this.VerifyIsRESOLVEDMIDInANRMatchString(mids.Value.AulPropTag[0]);
            this.VerifyIsUNRESOLVEDMIDInANREmptyString(mids.Value.AulPropTag[1]);
            this.VerifyIsAMBIGUOUSMIDInANRAmbiguousString(mids.Value.AulPropTag[2]);
            this.VerifyIsUNRESOLVEDMIDInANRNullString(mids.Value.AulPropTag[3]);
            this.VerifyIsUNRESOLVEDMIDInANRNotFound(mids.Value.AulPropTag[4]);
            this.VerifyIsResultOfANRProcessIsMID(mids);

            // Since if the whole ANR results are verified and the NspiResolveNames is invoked, 
            // it must take a set of string values in an 8-bit character set and perform ANR on those strings, 
            // this requirement can be captured directly.
            this.Site.CaptureRequirement(
                1341,
                @"[In NspiResolveNames] The NspiResolveNames method takes a set of string values in an 8-bit character set and performs ANR (as specified in section 3.1.4.7) on those strings.");

            // Since all the returned Minimal Entry IDs are verified according to the order of the input string array, this requirement can be captured directly.
            this.Site.CaptureRequirement(
                1375,
                @"[In NspiResolveNames] [Server Processing Rules: Upon receiving message NspiResolveNames, the server MUST process the data from the message subject to the following constraints:] [Constraint 6] These Minimal Entry IDs [IDs which server constructs and returns to client] are those that result from applying the ANR process, as specified in section 3.1.4.7, to the strings in the input parameter paStr.");

            #endregion Capture
            #endregion

            #region Call NspiResolveNames method with a specific list of names and propertyTag value without null.
            PropertyTagArray_r propTagsWithProperties = new PropertyTagArray_r
            {
                CValues = 3,
                AulPropTag = new uint[3]
                {
                    (uint)AulProp.PidTagEntryId,
                    (uint)AulProp.PidTagDisplayName,
                    (uint)AulProp.PidTagObjectType
                }
            };

            this.Result = this.ProtocolAdatper.NspiResolveNames((uint)0, stat, propTagsWithProperties, strArray, out mids, out rowOfResolveNames);
            Site.Assert.AreEqual(ErrorCodeValue.Success, this.Result, "NspiResolveNames should return Success!");

            PropertyRow_r rowValue = rowOfResolveNames.Value.ARow[0];

            string resolvedName = System.Text.UnicodeEncoding.UTF8.GetString(rowValue.LpProps[1].Value.LpszA);

            #region Capture

            // Check whether MID_RESOLVED is returned.
            bool isMIDRESOLVEDContained = false;
            for (int i = 0; i < mids.Value.CValues; i++)
            {
                if (mids.Value.AulPropTag[i] == 0x0000002)
                {
                    isMIDRESOLVEDContained = true;
                    break;
                }
            }

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1343
            // The rowOfResolveNames which contains a PropertyRowSet_r structure is returned from the server. If it is not null and MID_RESOLVED is returned,
            // it illustrates that certain property values are returned for any valid Minimal Entry IDs identified by the ANR process.
            this.Site.CaptureRequirementIfIsTrue(
                rowOfResolveNames != null && isMIDRESOLVEDContained,
                1343,
                @"[In NspiResolveNames] Certain property values are returned for any valid Minimal Entry IDs identified by the ANR process.");

            // Add the debug information
            this.Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-OXNSPI_R1349, the display name of the resolved address book for paStr {0} is {1}.",
                Common.GetConfigurationPropertyValue("User1Name", this.Site),
                resolvedName);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1349
            this.Site.CaptureRequirementIfIsTrue(
                resolvedName.Equals(Common.GetConfigurationPropertyValue("User1Name", this.Site), StringComparison.CurrentCultureIgnoreCase),
                1349,
                "[In NspiResolveNames] [paStr] Specifies the values the client is requesting the server to do ANR on.");

            Site.Assert.AreEqual<uint>((uint)AulProp.PidTagEntryId, rowOfResolveNames.Value.ARow[0].LpProps[0].PropTag, "The first property returned should be PidTagEntryId. Now the returned property is {0}.", rowOfResolveNames.Value.ARow[0].LpProps[0].PropTag);
            Site.Assert.AreEqual<uint>((uint)AulProp.PidTagDisplayName, rowOfResolveNames.Value.ARow[0].LpProps[1].PropTag, "The second property returned should be PidTagDisplayName. Now the returned property is {0}.", rowOfResolveNames.Value.ARow[0].LpProps[1].PropTag);
            Site.Assert.AreEqual<uint>((uint)AulProp.PidTagObjectType, rowOfResolveNames.Value.ARow[0].LpProps[2].PropTag, "The third property returned should be PidTagObjectType. Now the returned property is {0}.", rowOfResolveNames.Value.ARow[0].LpProps[2].PropTag);

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1347
            // Since the null value of pPropTags has been set in step "Call NspiResolveNames method with a specific list of names", 
            // and the above three asserts ensure that it is a reference to a PropertyTagArray_r value containing a list of the proptags of the columns that the client requests to be returned for each row.
            // So R1347 can be captured directly.
            this.Site.CaptureRequirement(
                1347,
                @"[In NspiResolveNames] pPropTags: The value NULL or a reference to a PropertyTagArray_r value containing a list of the proptags of the columns that the client requests to be returned for each row returned.");

            #endregion Capture
            #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_S02_TC37_MinimalEntryIDVerification()
        {
            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();
            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 method to get a set of valid rows.
            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 = 4;
            propTagsInstance.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.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiQueryRows should return Success!");

            // Get mid and entry id of corresponding name.
            string administratorName = Common.GetConfigurationPropertyValue("User1Name", this.Site);
            string mailUserName = Common.GetConfigurationPropertyValue("User2Name", this.Site);

            // The DN string of administrator.
            string administratorESSDN = string.Empty;

            // The DN string of mailUserName.
            string mailUserNameESSDN = string.Empty;

            // Parse PermanentEntryID in rows to get the DN of administrator and mailUserName.
            for (int i = 0; i < rowsOfQueryRows.Value.CRows; i++)
            {
                string name = System.Text.Encoding.UTF8.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(administratorName.ToLower(System.Globalization.CultureInfo.CurrentCulture)))
                {
                    PermanentEntryID administratorEntryID = AdapterHelper.ParsePermanentEntryIDFromBytes(rowsOfQueryRows.Value.ARow[i].LpProps[0].Value.Bin.Lpb);
                    administratorESSDN = administratorEntryID.DistinguishedName;
                }
                else if (name.ToLower(System.Globalization.CultureInfo.CurrentCulture).Equals(mailUserName.ToLower(System.Globalization.CultureInfo.CurrentCulture)))
                {
                    PermanentEntryID mailUserEntryID = AdapterHelper.ParsePermanentEntryIDFromBytes(rowsOfQueryRows.Value.ARow[i].LpProps[0].Value.Bin.Lpb);
                    mailUserNameESSDN = mailUserEntryID.DistinguishedName;
                }

                if (!string.IsNullOrEmpty(administratorESSDN) && !string.IsNullOrEmpty(mailUserNameESSDN))
                {
                    break;
                }
            }
            #endregion

            #region Call NspiDNToMId method to map the DNs to a set of Minimal Entry ID.
            uint reserved = 0;
            StringsArray_r names = new StringsArray_r();
            names.CValues = 2;
            names.LppszA = new string[2];
            names.LppszA[0] = administratorESSDN;
            names.LppszA[1] = mailUserNameESSDN;
            PropertyTagArray_r? mids;
            this.Result = this.ProtocolAdatper.NspiDNToMId(reserved, names, out mids);
            #endregion

            #region Call NspiGetMatches using the MID gotten in previous step to get the display name of the object.
            uint reserved1 = 0;
            uint reserver2 = 0;
            PropertyTagArray_r? proReserved = null;
            uint requested = Constants.GetMatchesRequestedRowNumber;
            Restriction_r? filter = null;
            PropertyTagArray_r prop = new PropertyTagArray_r();
            prop.AulPropTag = new uint[]
            {
                (uint)AulProp.PidTagDisplayName
            };
            prop.CValues = (uint)prop.AulPropTag.Length;
            PropertyTagArray_r? propTagsOfGetMatches = prop;
            PropertyName_r? propNameOfGetMatches = null;

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

            STAT statGetMatches = new STAT();
            statGetMatches.InitiateStat();
            uint administratorMID = mids.Value.AulPropTag[0];
            statGetMatches.CurrentRec = administratorMID;
            this.Result = this.ProtocolAdatper.NspiGetMatches(reserved1, ref statGetMatches, proReserved, reserver2, filter, propNameOfGetMatches, requested, out outMIds, propTagsOfGetMatches, out rowsOfGetMatches);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiGetMatches should return Success.");
            Site.Assert.AreEqual<int>(1, rowsOfGetMatches.Value.ARow.Length, "Only one address book object should be matched.");

            string displayName = System.Text.Encoding.UTF8.GetString(rowsOfGetMatches.Value.ARow[0].LpProps[0].Value.LpszA);

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R347
            // The Minimal Entry ID of the object the server is to read values from is specified in the CurrentRec field of the input parameter pStat.
            // If the two display name matched, MS-OXNSPI_R347 can be verified.
            Site.CaptureRequirementIfAreEqual<string>(
                administratorName.ToLower(System.Globalization.CultureInfo.CurrentCulture),
                displayName.ToLower(System.Globalization.CultureInfo.CurrentCulture),
                347,
                @"[In MinimalEntryID] A Minimal Entry ID is a single DWORD value that identifies a specific object in the address book.");

            // As the MinimalEntryID is a Minimal Identifier and MS-OXNSPI_R347 has been verified, MS-OXNSPI_R609 can be verified directly.
            Site.CaptureRequirement(
                609,
                @"[In Object Identity] Minimal Identifier: Specifies a specific object in a single NSPI session.");
            #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_S02_TC05_UpdateStatFractionalPosition()
        {
            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 NspiUpdateStat with the CurrentRec field set to MID_CURRENT to point to the fractional position and Delta set to 1 to move forward one row towards the end of the table.
            stat.InitiateStat();
            stat.Delta = 1;
            stat.CurrentRec = (uint)MinimalEntryID.MID_CURRENT;
            uint reserved = 0;
            int? delta = 0;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiUpdateStat should return Success!");

            #region Capture code

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R588. The position after moving is {0}.", stat.NumPos);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R588
            // If the currentPosition greater than the first position, it specifies that server moves towards the end of the table.
            this.Site.CaptureRequirementIfIsTrue(
                stat.NumPos > 0,
                588,
                @"[In Fractional Positioning] If the value of Delta is positive, the Current Position is moved toward the end of the table.");

            #endregion
            #endregion

            #region Call NspiUpdateStat with Delta set to 0 to keep the position in the table.
            // Record the position before updating stat in this step.
            uint previousPosition = stat.NumPos;
            stat.Delta = 0;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiUpdateStat should return Success!");

            #region Capture code

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R589. The position after moving is {0}.", stat.NumPos);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R589
            // If the current position equals the previous position, it specifies that server keeps the position in the table.
            this.Site.CaptureRequirementIfAreEqual<uint>(
                previousPosition,
                stat.NumPos,
                589,
                @"[In Fractional Positioning] A Delta field with the value 0 results in no change to the Current Position.");
            #endregion
            #endregion

            #region Call NspiUpdateStat with Delta set to -1 to move forward one row towards the beginning of the table.
            int supposedValueOfTotalRecs = (int)stat.TotalRecs;
            stat.Delta = -1;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiUpdateStat should return Success!");

            #region Capture code

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R328
            // In this step, the current position is moved to the initial position of the table. So if stat.NumPos is 0, this requirement can be verified.
            this.Site.CaptureRequirementIfAreEqual<uint>(
                0,
                stat.NumPos,
                328,
                @"[In STAT] [NumPos] This value [the approximate fractional position] is a zero index; the first element in a table has the numeric position 0.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R598
            // In this step, the current position is moved to the initial position of the table. So if stat.NumPos is 0, this requirement can be verified.
            this.Site.CaptureRequirementIfAreEqual<uint>(
                0,
                stat.NumPos,
                598,
                @"[In Fractional Positioning] This numeric row [the numeric row of the Current Position] is 0-based.");

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R587. The position after moving is {0}.", stat.NumPos);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R587
            // In the previous steps, the current position is moved one row from the beginning of the table towards the end of the table. Delta is set to -1 in this step, so if currentPosition equals 0, 
            // it indicates server moves towards the beginning of the table, and MS-OXNSPI_R587 can be verified.
            this.Site.CaptureRequirementIfAreEqual<uint>(
                0,
                stat.NumPos,
                587,
                @"[In Fractional Positioning] If the value of Delta is negative, the Current Position is moved toward the beginning of the table.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R793
            // MS-OXNSPI_R587, MS-OXNSPI_588 and MS-OXNSPI_R589 have been verified, MS-OXNSPI_R793 can be verified directly.
            this.Site.CaptureRequirement(
                793,
                @"[In NspiUpdateStat] [Server Processing Rules: Upon receiving message NspiUpdateStat, the server MUST process the data from the message subject to the following constraints:] [Constraint 5: The server locates the initial position row in the table specified by the ContainerID field of the input parameter pStat as follows:] If the row specified by the CurrentRec field of the input parameter pStat is MID_CURRENT, the server locates the initial position row using the fractional position specified in the NumPos field of the input parameter pStat as specified in section 3.1.4.5.2.");

            // Calculate the intended numeric position.
            float intendedNumericPosition = stat.TotalRecs * stat.NumPos / supposedValueOfTotalRecs;

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R577. The intended numeric position is {0}, the actual NumPos is {1}.", intendedNumericPosition, stat.NumPos);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R577
            this.Site.CaptureRequirementIfAreEqual<uint>(
                (uint)intendedNumericPosition,
                stat.NumPos,
                577,
                @"[In Fractional Positioning] [step 4] The server calculates the Intended Numeric Position in the table as the TotalRecs reported by the server multiplied by the NumPos field of the STAT structure divided by the value of TotalRecs as specified by the client.");

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R578. The intended numeric position is {0}, the actual NumPos is {1}.", intendedNumericPosition, stat.NumPos);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R578
            this.Site.CaptureRequirementIfAreEqual<uint>(
                (uint)intendedNumericPosition,
                stat.NumPos,
                578,
                @"[In Fractional Positioning] [step 4] The value is truncated to its integral part.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R584
            // In step 6 of Fractional Positioning: The server identifies the numeric row of the Current Position in the sorted table.
            // In this step, the first row is chosen to be moved to, so if stat.NumPos points to the first row in the table, MS-OXNSPI_R584 can be verified.
            this.Site.CaptureRequirementIfAreEqual<uint>(
                (uint)MinimalEntryID.MID_BEGINNING_OF_TABLE,
                stat.NumPos,
                584,
                @"[In Fractional Positioning] The server moves the Current Position to the row chosen in step 6.");
            #endregion
            #endregion

            #region Call NspiUpdateStat with Delta set to -1 to move the Current Position to be before the beginning of the table.
            stat.Delta = -1;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiUpdateStat should return Success!");

            #region Capture code

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1745. The position after moving is {0}.", stat.NumPos);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1745
            // In this step, the current position should be moved to be before the first row of the table.
            this.Site.CaptureRequirementIfAreEqual<uint>(
                (uint)MinimalEntryID.MID_BEGINNING_OF_TABLE,
                stat.NumPos,
                1745,
                @"[In Fractional Positioning] If applying the Delta as described in step 8 would move the Current Position to be before the beginning of the table, the server sets the Current Position to the beginning of the table.");
            #endregion
            #endregion

            #region Call NspiUpdateStat with Delta set to TotalRecs + 1 to move the Current Position to be after the end of the table.
            supposedValueOfTotalRecs = (int)stat.TotalRecs - 1; // A nonzero value which is less than the actual value of stat.TotalRecs used to build the pre-condition for capture code R580.
            stat.Delta = (int)stat.TotalRecs + 1;
            uint totalRecsSpecifiedByClient = 10;
            stat.TotalRecs = totalRecsSpecifiedByClient;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiUpdateStat should return Success!");

            #region Capture code

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R797", "The value of NumPos is {0}, the value of TotalRecs is {1}.", stat.NumPos, stat.TotalRecs);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R797
            // According to section 3.1.4.5.2 of this Open Specification, the NumPos field is calculated as follows: 
            // TotalRecs reported by the server multiplied by the NumPos field of the STAT structure divided by the value of TotalRecs
            // as specified by the client. And then, approximate fractional position is the integral part.
            this.Site.CaptureRequirementIfIsTrue(
                stat.NumPos == stat.NumPos * stat.TotalRecs / totalRecsSpecifiedByClient || stat.NumPos == stat.TotalRecs,
                797,
                @"[In NspiUpdateStat] [Server Processing Rules: Upon receiving message NspiUpdateStat, the server MUST process the data from the message subject to the following constraints:] [Constraint 9] The server MUST set the NumPos field of the parameter pStat to the approximate numeric position of the current row of the current address book container according to section 3.1.4.5.2.");

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R327
            // MS-OXNSPI_R797 has been verified, MS-OXNSPI_R327 can be verified directly.
            this.Site.CaptureRequirement(
                327,
                @"[In STAT] [NumPos] The server sets this field to specify the approximate fractional position at the end of an NSPI method.");

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1747. The position after moving is {0}.", stat.NumPos);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1747
            // If the currentPosition equals the TotalRecs+1, it specifies that server sets the Current Position to a location one row past the last valid row of the table.
            this.Site.CaptureRequirementIfAreEqual<uint>(
                stat.TotalRecs,
                stat.NumPos,
                1747,
                @"[In Fractional Positioning] If applying Delta as described in step 8 would move the Current Position to be after the end of the table, the server sets the Current Position to a location one row past the last valid row of the table.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R595
            this.Site.CaptureRequirementIfAreEqual<uint>(
                (uint)MinimalEntryID.MID_END_OF_TABLE,
                stat.CurrentRec,
                595,
                @"[In Fractional Positioning] The server sets the field CurrentRec to the Minimal Entry ID of the object occupying the row specified by the Current Position.");

            // Calculate the intended numeric position.
            intendedNumericPosition = stat.TotalRecs * stat.NumPos / supposedValueOfTotalRecs;

            if (intendedNumericPosition > stat.TotalRecs)
            {
                // Add the debug information
                this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R580");

                // Verify MS-OXNSPI requirement: MS-OXNSPI_R580
                this.Site.CaptureRequirementIfAreEqual<uint>(
                    stat.TotalRecs,
                    stat.NumPos,
                    580,
                    @"[In Fractional Positioning] [step 5] If the Intended Numeric Position thus calculated is greater than TotalRecs, the intended Intended Numeric Position is TotalRecs (that is, the last row in the table).");
            }
            else
            {
                Site.Assert.Fail("The Intended Numeric Position {0} not as expected to be greater than TotalRecs {1}.", intendedNumericPosition, stat.TotalRecs);
            }

            #endregion
            #endregion

            #region Call NspiUnbind to destroy the context handle.
            uint returnValue = this.ProtocolAdatper.NspiUnbind(reserved);
            Site.Assert.AreEqual<uint>(1, returnValue, "NspiUnbind method should return 1 (Success).");
            #endregion
        }
        public void MSOXNSPI_S02_TC27_CompareMIdsIgnoreReserved()
        {
            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 NspiDNToMId to get a set of Minimal Entry ID. These IDs will be used as the parameter of NspiCompareMIds.
            uint reserved = 0;
            StringsArray_r 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);
            PropertyTagArray_r? mids;
            this.Result = this.ProtocolAdatper.NspiDNToMId(reserved, names, out mids);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiDNToMId should return Success!");
            #endregion

            #region Call NspiCompareMIds with Reserved set to 0.
            uint reservedOfCompareMIds = 0;
            uint mid1 = mids.Value.AulPropTag[0];
            uint mid2 = mids.Value.AulPropTag[1];
            int results1;
            this.Result = this.ProtocolAdatper.NspiCompareMIds(reservedOfCompareMIds, stat, mid1, mid2, out results1);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiCompareMIds should return Success!");
            #endregion

            #region Call NspiCompareMIds with Reserved set to 1.
            int results2;
            reservedOfCompareMIds = 0x1;
            this.Result = this.ProtocolAdatper.NspiCompareMIds(reservedOfCompareMIds, stat, mid1, mid2, out results2);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiCompareMIds should return Success!");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1699
            Site.CaptureRequirementIfAreEqual<int>(
                results1,
                results2,
                1699,
                @"[In NspiCompareMIds] If this field[Reserved] is set to different values, the server will return the same result.");

            #endregion Capture
            #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_S02_TC28_DNToMIdSuccess()
        {
            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.
            uint flagsOfQueryRows = (uint)RetrievePropertyFlag.fSkipObjects;
            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.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiQueryRows should return Success!");

            // Get mid and entry id of corresponding name.
            string administratorName = Common.GetConfigurationPropertyValue("User1Name", this.Site);
            string mailUserName = Common.GetConfigurationPropertyValue("User2Name", this.Site);

            // The DN string of administrator.
            string administratorESSDN = string.Empty;

            // The DN string of mailUserName.
            string mailUserNameESSDN = string.Empty;

            // Parse PermanentEntryID in rows to get the DN of administrator and mailUserName.
            for (int i = 0; i < rowsOfQueryRows.Value.CRows; i++)
            {
                string name = System.Text.Encoding.UTF8.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(administratorName.ToLower(System.Globalization.CultureInfo.CurrentCulture)))
                {
                    PermanentEntryID administratorEntryID = AdapterHelper.ParsePermanentEntryIDFromBytes(rowsOfQueryRows.Value.ARow[i].LpProps[0].Value.Bin.Lpb);
                    administratorESSDN = administratorEntryID.DistinguishedName;
                }
                else if (name.ToLower(System.Globalization.CultureInfo.CurrentCulture).Equals(mailUserName.ToLower(System.Globalization.CultureInfo.CurrentCulture)))
                {
                    PermanentEntryID mailUserEntryID = AdapterHelper.ParsePermanentEntryIDFromBytes(rowsOfQueryRows.Value.ARow[i].LpProps[0].Value.Bin.Lpb);
                    mailUserNameESSDN = mailUserEntryID.DistinguishedName;
                }

                if (!string.IsNullOrEmpty(administratorESSDN) && !string.IsNullOrEmpty(mailUserNameESSDN))
                {
                    break;
                }
            }
            #endregion

            #region Call NspiDNToMId method to map the DNs to a set of Minimal Entry ID.
            uint reserved = 0;
            StringsArray_r names = new StringsArray_r
            {
                CValues = 2,
                LppszA = new string[2]
            };
            names.LppszA[0] = administratorESSDN;
            names.LppszA[1] = mailUserNameESSDN;
            PropertyTagArray_r? mids;
            this.Result = this.ProtocolAdatper.NspiDNToMId(reserved, names, out mids);

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

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

            #endregion Capture
            #endregion

            #region Call NspiUpdateStat to update the positioning changes in a table.
            reserved = 0;
            int? delta = 1;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiUpdateStat should return Success!");
            #endregion

            #region Call NspiGetProps to get the Permanent Entry ID using one Minimal Entry ID returned from step 3.
            PropertyTagArray_r prop = new PropertyTagArray_r
            {
                CValues = 1
            };
            prop.AulPropTag = new uint[prop.CValues];
            prop.AulPropTag[0] = (uint)AulProp.PidTagEntryId;

            propTags = prop;
            PropertyRow_r? rows;

            uint flagsOfGetProps = (uint)RetrievePropertyFlag.fSkipObjects;
            stat.CurrentRec = mids.Value.AulPropTag[0];

            this.Result = this.ProtocolAdatper.NspiGetProps(flagsOfGetProps, stat, propTags, out rows);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiGetProps should return Success.");
            PermanentEntryID entryID1 = AdapterHelper.ParsePermanentEntryIDFromBytes(rows.Value.LpProps[0].Value.Bin.Lpb);
            bool firstDNMapright = entryID1.DistinguishedName.Equals(names.LppszA[0], StringComparison.OrdinalIgnoreCase);
            #endregion

            #region Call NspiGetProps to get the Permanent Entry ID using another Minimal Entry ID returned from step 3.
            stat.CurrentRec = mids.Value.AulPropTag[1];
            this.Result = this.ProtocolAdatper.NspiGetProps(flagsOfGetProps, stat, propTags, out rows);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiGetProps should return Success.");
            PermanentEntryID entryID2 = AdapterHelper.ParsePermanentEntryIDFromBytes(rows.Value.LpProps[0].Value.Bin.Lpb);
            bool secondDNMapright = entryID2.DistinguishedName.Equals(names.LppszA[1], StringComparison.OrdinalIgnoreCase);

            #region Capture
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1263: the first DN map right result is {0}, the second DN map right result is {1}", firstDNMapright, secondDNMapright);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1263
            Site.CaptureRequirementIfIsTrue(
                firstDNMapright && secondDNMapright,
                1263,
                @"[In NspiDNToMId] [Server Processing Rules: Upon receiving message NspiDNToMId, the server MUST process the data from the message subject to the following constraints:] [Constraint 4] The list is in a one-to-one order preserving correspondence with the list of DNs in the input parameter pNames.");

            // Since the mapping work has been done in this step, so MS-OXNSPI_R1243 can be captured directly.
            this.Site.CaptureRequirement(
                1243,
                @"[In NspiDNToMId] The NspiDNToMId method maps a set of DNs to a set of Minimal Entry ID.");
            #endregion Capture
            #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_S02_TC25_ResortRestrictionCurrentRecFieldNotInETable()
        {
            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 NspiDNToMId to get a set of Minimal Entry ID. These IDs will be used as the parameter of NspiResortRestriction.
            uint reserved = 0;
            StringsArray_r names = new StringsArray_r
            {
                CValues = 3,
                LppszA = new string[3]
                {
                    Common.GetConfigurationPropertyValue("User1Essdn", this.Site),
                    Common.GetConfigurationPropertyValue("User3Essdn", this.Site),
                    Common.GetConfigurationPropertyValue("User2Essdn", this.Site),
                }
            };

            PropertyTagArray_r? mids;
            this.Result = this.ProtocolAdatper.NspiDNToMId(reserved, names, out mids);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiDNToMId should return Success!");
            #endregion

            #region Call NspiResortRestriction with CurrentRec field not in the constructed Explicit Table.
            uint reservedOfResortRestriction = 0;
            PropertyTagArray_r inmids = new PropertyTagArray_r
            {
                CValues = mids.Value.CValues - 1
            };
            inmids.AulPropTag = new uint[inmids.CValues];
            for (int i = 0; i < inmids.CValues; i++)
            {
                inmids.AulPropTag[i] = mids.Value.AulPropTag[i];
            }

            // 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_TELETEX;
            stat.SortType = (uint)TableSortOrder.SortTypeDisplayName;
            stat.CurrentRec = mids.Value.AulPropTag[mids.Value.CValues - 1];
            PropertyTagArray_r? outMIds = null;
            this.Result = this.ProtocolAdatper.NspiResortRestriction(reservedOfResortRestriction, ref stat, inmids, ref outMIds);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiResortRestriction should return Success!");

            #region Capture

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1205
            Site.CaptureRequirementIfAreEqual<uint>(
                0,
                stat.NumPos,
                1205,
                @"[In NspiResortRestriction] [Server Processing Rules: Upon receiving message NspiResortRestriction, the server MUST process the data from the message subject to the following constraints:] [Constraint 8 The Server MUST update the output parameter pStat as follows:] If the object specified by the CurrentRec field of the input parameter pStat is not in the constructed Explicit Table, the NumPos field of the output parameter pStat is set to the value 0.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1759
            Site.CaptureRequirementIfAreEqual<uint>(
                (uint)MinimalEntryID.MID_BEGINNING_OF_TABLE,
                stat.CurrentRec,
                1759,
                @"[In NspiResortRestriction] [Server Processing Rules: Upon receiving message NspiResortRestriction, the server MUST process the data from the message subject to the following constraints:] [Constraint 8 The Server MUST update the output parameter pStat as follows:] If the object specified by the CurrentRec field of the input parameter pStat is not in the constructed Explicit Table, the CurrentRec field of the output parameter pStat is set to the value MID_BEGINNING_OF_TABLE.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R80
            this.Site.CaptureRequirementIfAreEqual<uint>(
                (uint)MinimalEntryID.MID_BEGINNING_OF_TABLE,
                stat.CurrentRec,
                80,
                @"[In Positioning Minimal Entry IDs] MID_BEGINNING_OF_TABLE (0x00000000): Specifies the position before the first row in the current address book container.");

            #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_S02_TC26_CompareMIdsSuccessWithCompareMid1AndMid2()
        {
            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 NspiDNToMId method to get two MIDs.
            uint reserved = 0;
            StringsArray_r 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);
            PropertyTagArray_r? mids;
            this.Result = this.ProtocolAdatper.NspiDNToMId(reserved, names, out mids);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiDNToMId should return Success!");
            #endregion

            #region Call NspiCompareMIds to compare two MIDs.
            uint firstMId = mids.Value.AulPropTag[0];
            uint secondMId = mids.Value.AulPropTag[1];

            // MId1 before MId2.
            uint reservedOfCompareMIds = 0;
            uint mid1 = firstMId;
            uint mid2 = secondMId;
            int compareResult;

            this.Result = this.ProtocolAdatper.NspiCompareMIds(reservedOfCompareMIds, stat, mid1, mid2, out compareResult);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiCompareMIds method should return Success.");

            #region Capture
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1236: the returned compare result is {0}.", compareResult);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1236
            Site.CaptureRequirementIfIsTrue(
                compareResult < 0,
                1236,
                @"[In NspiCompareMIds] [Server Processing Rules: Upon receiving message NspiCompareMIds, the server MUST process the data from the message subject to the following constraints:] [Constraint 6] If the position of the object specified by MId1 comes before the position of the object specified by MId2 in the table specified by the field ContainerID of the input parameter pStat, the server MUST return a value less than 0 in the output parameter plResult.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1242
            Site.CaptureRequirementIfAreEqual(
                ErrorCodeValue.Success,
                this.Result,
                1242,
                @"[In NspiCompareMIds] [Server Processing Rules: Upon receiving message NspiCompareMIds, 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"".");
            #endregion Capture

            #endregion

            #region Swap the two MIDs and then call NspiCompareMIds to compare the two MIDs again.
            mid1 = secondMId;
            mid2 = firstMId;
            this.Result = this.ProtocolAdatper.NspiCompareMIds(reservedOfCompareMIds, stat, mid1, mid2, out compareResult);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiCompareMIds should return Success.");

            #region Capture
            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1238: the returned compare result is {0}.", compareResult);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1238
            Site.CaptureRequirementIfIsTrue(
                compareResult > 0,
                1238,
                @"[In NspiCompareMIds] [Server Processing Rules: Upon receiving message NspiCompareMIds, the server MUST process the data from the message subject to the following constraints:] [Constraint 7] If the position of the object specified by MId1 comes after the position of the object specified by MId2 in the table specified by the field ContainerID of the input parameter pStat, the server MUST return a value greater than 0 in the output parameter plResult.");

            #endregion Capture
            #endregion

            #region Assign MID1 and MID2 to the same MID and then call NspiCompareMIds to compare MID1 and MID2.
            mid2 = mid1;
            this.Result = this.ProtocolAdatper.NspiCompareMIds(reservedOfCompareMIds, stat, mid1, mid2, out compareResult);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiCompareMIds should return Success.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1240
            Site.CaptureRequirementIfAreEqual<int>(
                0,
                compareResult,
                1240,
                @"[In NspiCompareMIds] [Server Processing Rules: Upon receiving message NspiCompareMIds, the server MUST process the data from the message subject to the following constraints:] [Constraint 8] If the position of the object specified by MId1 is the same as the position of the object specified by MId2 in the table specified by the ContainerID field of the input parameter pStat (that is, they specify the same object), the server MUST return a value of 0 in the output parameter plResult.");

            // Since the comparing work has been done in all above steps, so MS-OXNSPI_R1210 can be captured directly.
            this.Site.CaptureRequirement(
                1210,
                @"[In NspiCompareMIds] The NspiCompareMIds method compares the position in an address book container of two objects identified by Minimal Entry ID and returns the value of the comparison.");
            #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_S02_TC24_ResortRestrictionIgnoreSomeFields()
        {
            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 NspiResortRestriction method by specifying the inMIDs parameter with a Minimal Entry ID which does not specify an object.
            uint reservedOfResortRestriction = 0;
            PropertyTagArray_r inmids = new PropertyTagArray_r
            {
                CValues = 1,
                AulPropTag = new uint[1]
                {
                    uint.Parse(Constants.UnrecognizedMID)
                }
            };

            stat.CodePage = (uint)RequiredCodePage.CP_WINUNICODE;
            stat.SortType = (uint)TableSortOrder.SortTypeDisplayName;
            PropertyTagArray_r? outMIds = null;
            this.Result = this.ProtocolAdatper.NspiResortRestriction(reservedOfResortRestriction, ref stat, inmids, ref outMIds);

            #region Capture
            // pStat is defined to the type of STAT in this test suite, and the CurrentRec describes the logical position. So this requirement can be captured if code can reach here.
            this.Site.CaptureRequirement(
                1172,
                @"[In NspiResortRestriction] pStat: A reference to a STAT block describing a logical position in a specific address book container.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R494
            Site.CaptureRequirementIfAreEqual<ErrorCodeValue>(
                ErrorCodeValue.Success,
                this.Result,
                494,
                @"[In String Sorting] Every server MUST support sorting on Unicode string representations for the PidTagDisplayName property.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1197
            Site.CaptureRequirementIfAreEqual<uint>(
                0x0,
                outMIds.Value.CValues,
                1197,
                @"[In NspiResortRestriction] [Server Processing Rules: Upon receiving message NspiResortRestriction, the server MUST process the data from the message subject to the following constraints:] [Constraint 6] The server MUST ignore any Minimal Entry IDs that do not specify an object.");

            #endregion Capture
            #endregion

            #region Call NspiResortRestriction method with Reserved field set to another value different from that in the above step.
            reservedOfResortRestriction = 1;
            PropertyTagArray_r? outMIds1 = null;
            this.Result = this.ProtocolAdatper.NspiResortRestriction(reservedOfResortRestriction, ref stat, inmids, ref outMIds1);

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1915
            this.Site.CaptureRequirementIfIsTrue(
                AdapterHelper.AreTwoPropertyTagArrayEqual(outMIds, outMIds1),
                1915,
                @"[In NspiResortRestriction] If this field [Reserved] is set to different values, the server will return the same result.");
            #endregion
            #endregion

            #region Call NspiResortRestriction method with ppOutMIds set to another value different from that in the above step.
            PropertyTagArray_r? outMIds2 = inmids;
            this.Result = this.ProtocolAdatper.NspiResortRestriction(reservedOfResortRestriction, ref stat, inmids, ref outMIds2);

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1870
            this.Site.CaptureRequirementIfIsTrue(
                AdapterHelper.AreTwoPropertyTagArrayEqual(outMIds, outMIds2),
                1870,
                @"[In NspiResortRestriction] [ppOutMIds] If this field is set to different values, the server will return the same result.");

            #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_S02_TC23_ResortRestrictionSuccessCheckRowNumber()
        {
            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 method to get a list of valid MIDs (Minimal Entry ID).
            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;

            PropertyTagArray_r propTags1 = new PropertyTagArray_r
            {
                CValues = 3,
                AulPropTag = new uint[3]
                {
                    (uint)AulProp.PidTagEntryId,
                    (uint)AulProp.PidTagDisplayType,
                    (uint)AulProp.PidTagObjectType
                }
            };
            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>(ErrorCodeValue.Success, this.Result, "NspiGetMatches should return Success!");
            #endregion

            #region Call NspiResortRestriction method to resort MIDs got from NspiGetMatches method.
            uint reservedOfResortRestriction = 0;
            PropertyTagArray_r inmids = outMIds.Value;

            PropertyTagArray_r? outMIdOfResort = null;
            this.Result = this.ProtocolAdatper.NspiResortRestriction(reservedOfResortRestriction, ref stat, inmids, ref outMIdOfResort);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiResortRestriction should return Success!");
            #endregion

            #region Call NspiQueryRows method using MIDs of NspiResortRestriction as the input parameter lpETable to check whether the specified row is inserted.
            uint flagsOfQueryRows = (uint)RetrievePropertyFlag.fEphID;
            uint tableCount = outMIds.Value.CValues;
            uint[] table = new uint[outMIds.Value.CValues];
            Array.Copy(outMIds.Value.AulPropTag, table, outMIds.Value.CValues);
            uint count = tableCount + 1;
            PropertyRowSet_r? rowsOfQueryRows;

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

            this.Result = this.ProtocolAdatper.NspiQueryRows(flagsOfQueryRows, ref stat, tableCount, table, count, propTags, out rowsOfQueryRows);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiQueryRows should return Success!");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1198
            // If the number of the queried row equals the number of minimal entry id in outMids, 
            // it means the when each object located, a row is inserted into the constructed Explicit Table.
            Site.CaptureRequirementIfAreEqual<uint>(
                outMIdOfResort.Value.CValues,
                rowsOfQueryRows.Value.CRows,
                1198,
                @"[In NspiResortRestriction] [Server Processing Rules: Upon receiving message NspiResortRestriction, the server MUST process the data from the message subject to the following constraints:] [Constraint 6] For each such object located, a row is inserted into the constructed Explicit Table.");

            #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_S02_TC01_UpdateStatSuccessWithDifferentCurrentRec()
        {
            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 NspiUpdateStat with the CurrentRec field of the input parameter pStat not set to MID_CURRENT.
            stat.InitiateStat();
            stat.CurrentRec = (uint)MinimalEntryID.MID_BEGINNING_OF_TABLE;
            uint reserved = 0;
            stat.Delta = 0;
            int? delta = 2;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R542
            Site.CaptureRequirementIfAreEqual<ErrorCodeValue>(
                ErrorCodeValue.Success,
                this.Result,
                542,
                @"[In Absolute Positioning] [step 4] The server MUST support the special Minimal Entry ID MID_BEGINNING_OF_TABLE, as specified in section 2.2.1.8.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R800
            Site.CaptureRequirementIfAreEqual<ErrorCodeValue>(
                ErrorCodeValue.Success,
                this.Result,
                800,
                @"[In NspiUpdateStat] [Server Processing Rules: Upon receiving message NspiUpdateStat, the server MUST process the data from the message subject to the following constraints:] [Constraint 12] If no error condition has been specified by the previous constraints, the server MUST return ""Success"".");

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

            uint objectNum = this.SutControlAdapter.GetNumberOfAddressBookObject();

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R798
            Site.CaptureRequirementIfAreEqual<uint>(
                objectNum,
                stat.TotalRecs,
                798,
                @"[In NspiUpdateStat] [Server Processing Rules: Upon receiving message NspiUpdateStat, the server MUST process the data from the message subject to the following constraints:] [Constraint 10] The server MUST set the TotalRecs field of the parameter pStat to the number of rows in the current address book container according to section 3.1.4.5.2.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R332
            Site.CaptureRequirementIfAreEqual<uint>(
                objectNum,
                stat.TotalRecs,
                332,
                @"[In STAT] [TotalRecs] The server sets this field to specify the total number of rows in the table.");

            #endregion
            #endregion

            #region Call NspiUpdateStat with the CurrentRec field of the input parameter pStat set to MID_CURRENT.
            stat.InitiateStat();
            stat.CurrentRec = (uint)MinimalEntryID.MID_CURRENT;
            reserved = 0;
            delta = 2;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiUpdateStat should return Success!");

            #region Capture code

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R575
            this.Site.CaptureRequirementIfAreNotEqual<uint>(
                0,
                stat.TotalRecs,
                575,
                @"[In Fractional Positioning] [step 3] The server reports this [the number of objects] in the TotalRecs field of the STAT structure.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1742
            // CurrentRec in stat is set to MID_Current, if server returns success, it means the MID_Current is valid in method NspiUpdateStat and related requirements are verified.
            Site.CaptureRequirementIfAreEqual<ErrorCodeValue>(
                ErrorCodeValue.Success,
                this.Result,
                1742,
                @"[In Positioning Minimal Entry IDs] [MID_CURRENT] This Minimal Entry ID is valid in the NspiUpdateStat method.");

            #endregion
            #endregion

            #region Call NspiUpdateStat with the CurrentRec field of the input parameter pStat set to MID_END_OF_TABLE.
            delta = 0;
            stat.CurrentRec = (uint)MinimalEntryID.MID_END_OF_TABLE;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1758
            Site.CaptureRequirementIfAreEqual<ErrorCodeValue>(
                ErrorCodeValue.Success,
                this.Result,
                1758,
                @"[In Absolute Positioning] The server MUST support the special Minimal Entry ID MID_END_OF_TABLE, as specified in section 2.2.8.");

            #endregion Capture
            #endregion

            #region Call NspiUpdateStat to move CurrentRec to be before the first row of the table.
            stat.InitiateStat();
            stat.CurrentRec = (uint)MinimalEntryID.MID_BEGINNING_OF_TABLE;
            reserved = 0;
            stat.Delta = -1;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiUpdateStat should return Success!");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R558
            // According to the Open Specification, if applying the Delta would move the Current Position to be before the first row of the table, 
            // the server sets the Current Position to the first row of the table. So if stat.NumPos equals 0, it indicates the numeric row is 0-based.
            Site.CaptureRequirementIfAreEqual<uint>(
                0x0,
                stat.NumPos,
                558,
                @"[In Absolute Positioning] This numeric row [the numeric row of the Current Position in the sorted table] is 0-based.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R561
            // Now the current position is pointed to be the first row of the table, and the numeric row is 0-based. So if stat.NumPos equals 0, 
            // it indicates server reports the current position in the NumPos field of the STAT structure.
            Site.CaptureRequirementIfAreEqual<uint>(
                0x0,
                stat.NumPos,
                561,
                @"[In Absolute Positioning] The server reports this [the Numeric Position of the Current Position of the table] 
                in the NumPos field of the STAT structure.");

            #endregion Capture
            #endregion

            #region Call NspiUpdateStat to move CurrentRec to be after the end of the table.
            stat.InitiateStat();
            stat.CurrentRec = (uint)MinimalEntryID.MID_END_OF_TABLE;
            reserved = 0;
            stat.Delta = 1;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiUpdateStat should return Success!");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1704
            Site.CaptureRequirementIfAreEqual<uint>(
                (uint)MinimalEntryID.MID_END_OF_TABLE,
                stat.CurrentRec,
                1704,
                @"[In Absolute Positioning] [step 8] If applying the Delta as described in step 6 would move the Current Position to
                be after the end of the table, the server sets the CurrentRec to the value MID_END_OF_TABLE.");

            #endregion Capture
            #endregion

            #region Call NspiUnbind to destroy the context handle.
            uint returnValue = this.ProtocolAdatper.NspiUnbind(reserved);
            Site.Assert.AreEqual<uint>(1, returnValue, "NspiUnbind method should return 1 (Success).");
            #endregion
        }
        public void MSOXNSPI_S02_TC35_NspiSeekEntriesStringConversion()
        {
            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.Success, this.Result, "NspiBind should return Success!");
            #endregion

            #region Call NspiUpdateStat to update the STAT block that represents the position in a table to reflect positioning changes requested by the client.
            uint reserved = 0;
            int? delta = 1;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiUpdateStat should return Success!");
            #endregion

            #region Call NspiGetPropList method with dwFlags set to fEphID and CodePage field of STAT block not set to CP_WINUNICODE.
            uint flagsOfGetPropList = (uint)RetrievePropertyFlag.fEphID;
            PropertyTagArray_r? propTagsOfGetPropList;
            uint codePage = (uint)RequiredCodePage.CP_TELETEX;

            this.Result = this.ProtocolAdatper.NspiGetPropList(flagsOfGetPropList, stat.CurrentRec, codePage, out propTagsOfGetPropList);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiGetPropList should return Success!");
            #endregion

            #region Call NspiSeekentries to request the string properties to be different with their native types.
            uint reservedOfSeekEntries = 0;

            PropertyValue_r target = new PropertyValue_r
            {
                PropTag = AdapterHelper.ConvertString8ToString((uint)AulProp.PidTagDisplayName),
                Reserved = (uint)0x00,
            };
            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 propTags = new PropertyTagArray_r
            {
                AulPropTag = new uint[]
                {
                    AdapterHelper.ConvertStringToString8((uint)AulProp.PidTagAddressBookDisplayNamePrintable),
                    AdapterHelper.ConvertString8ToString((uint)AulProp.PidTagDisplayName)
                }
            };
            propTags.CValues = (uint)propTags.AulPropTag.Length;
            PropertyTagArray_r? propTagsOfSeekEntries = propTags;

            PropertyTagArray_r? tableOfSeekEntries = null;
            PropertyRowSet_r? rowsOfSeekEntries;

            this.Result = this.ProtocolAdatper.NspiSeekEntries(reservedOfSeekEntries, ref stat, target, tableOfSeekEntries, propTagsOfSeekEntries, out rowsOfSeekEntries);
            Site.Assert.AreEqual(ErrorCodeValue.Success, this.Result, "NspiSeekEntries should return Success!");
            Site.Assert.IsNotNull(rowsOfSeekEntries, "PropertyRowSet_r value should not null. The row number is {0}.", rowsOfSeekEntries == null ? 0 : rowsOfSeekEntries.Value.CRows);
            Site.Assert.AreNotEqual<int>(0, rowsOfSeekEntries.Value.ARow.Length, "At least one address book object should be matched.");
            PropertyRow_r rowValue = rowsOfSeekEntries.Value.ARow[0];

            displayName = System.Text.UnicodeEncoding.Unicode.GetString(rowValue.LpProps[1].Value.LpszW);

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1974: The value of PidTagDisplayName is {0}.", displayName);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1974
            // The field LpszW indicates a single Unicode string value.
            Site.CaptureRequirementIfIsNotNull(
                rowValue.LpProps[1].Value.LpszW,
                1974,
                "[In Conversion Rules for String Values Specified by the Server to the Client] In NspiSeekEntries method, String values can be returned in Unicode representation in the output parameter ppRows.");

            string displayNamePrintable = System.Text.UnicodeEncoding.UTF8.GetString(rowValue.LpProps[0].Value.LpszA);

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1975: The value of PidTagAddressBookDisplayNamePrintable is {0}.", displayNamePrintable);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1975
            // The field LpszA indicates a 8-bit character string value.
            Site.CaptureRequirementIfIsNotNull(
                rowValue.LpProps[0].Value.LpszA,
                1975,
                "[In Conversion Rules for String Values Specified by the Server to the Client] In NspiSeekEntries method, String values can be returned in 8-bit character representation in the output parameter ppRows.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1937
            // The native type of PidTagAddressBookDisplayNamePrintable is PtypString and the client has requested this property with PtypString8.
            Site.CaptureRequirementIfAreEqual<uint>(
                AdapterHelper.ConvertStringToString8((uint)AulProp.PidTagAddressBookDisplayNamePrintable),
                rowValue.LpProps[0].PropTag,
                1937,
                "[In Conversion Rules for String Values Specified by the Server to the Client] [For method NspiSeekEntries] If the native type of a property is PtypString and the client has requested that property with the type PtypString8, the server MUST convert the Unicode representation to an 8-bit character representation in the code page specified by the CodePage field of the pStat parameter prior to returning the value.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1953
            // The native type of PidTagDisplayName is PtypString8 and the client has requested this property with PtypString.
            Site.CaptureRequirementIfAreEqual<uint>(
                AdapterHelper.ConvertString8ToString((uint)AulProp.PidTagDisplayName),
                rowValue.LpProps[1].PropTag,
                1953,
                "[In Conversion Rules for String Values Specified by the Server to the Client] [For method NspiSeekEntries] If the native type of a property is PtypString8 and the client has requested that property with the type PtypString, the server MUST convert the 8-bit character representation to a Unicode representation prior to returning the value.");
            #endregion

            #region Call NspiSeekEntries to request the string properties to be the same as their native types.

            target = new PropertyValue_r
            {
                PropTag = (uint)AulProp.PidTagDisplayName,
                Reserved = (uint)0x00,
            };
            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.LpszA = System.Text.Encoding.UTF8.GetBytes(displayName);

            propTags = new PropertyTagArray_r
            {
                AulPropTag = new uint[]
                {
                    (uint)AulProp.PidTagAddressBookDisplayNamePrintable,
                    (uint)AulProp.PidTagDisplayName
                }
            };
            propTags.CValues = (uint)propTags.AulPropTag.Length;
            propTagsOfSeekEntries = propTags;

            this.Result = this.ProtocolAdatper.NspiSeekEntries(reservedOfSeekEntries, ref stat, target, tableOfSeekEntries, propTagsOfSeekEntries, out rowsOfSeekEntries);
            Site.Assert.AreEqual(ErrorCodeValue.Success, this.Result, "NspiSeekEntries should return Success!");
            Site.Assert.IsNotNull(rowsOfSeekEntries, "PropertyRowSet_r value should not null. The row number is {0}.", rowsOfSeekEntries == null ? 0 : rowsOfSeekEntries.Value.CRows);
            Site.Assert.AreNotEqual<int>(0, rowsOfSeekEntries.Value.ARow.Length, "At least one address book object should be matched.");

            rowValue = rowsOfSeekEntries.Value.ARow[0];

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1945
            // The native type of PidTagAddressBookDisplayNamePrintable is PtypString and the client has requested this property with PtypString.
            Site.CaptureRequirementIfAreEqual<uint>(
                (uint)AulProp.PidTagAddressBookDisplayNamePrintable,
                rowValue.LpProps[0].PropTag,
                1945,
                "[In Conversion Rules for String Values Specified by the Server to the Client] [For method NspiSeekEntries] If the native type of a property is PtypString and the client has requested that property with the type PtypString, the server MUST return the Unicode representation unmodified.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1961
            // The native type of PidTagDisplayName is PtypString8 and the client has requested this property with PtypString8.
            Site.CaptureRequirementIfAreEqual<uint>(
                (uint)AulProp.PidTagDisplayName,
                rowValue.LpProps[1].PropTag,
                1961,
                "[In Conversion Rules for String Values Specified by the Server to the Client] [For method NspiSeekEntries] If the native type of a property is PtypString8 and the client has requested that property with the type PtypString8, the server MUST return the 8-bit character representation unmodified.");
            #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_S02_TC29_DNToMIdUnableToLocate()
        {
            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 NspiDNToMId method with a DN which is unable to be located.
            uint reserved = 0;
            StringsArray_r names = new StringsArray_r
            {
                CValues = 1,
                LppszA = new string[1]
            };
            names.LppszA[0] = "UnableToLocate";
            PropertyTagArray_r? mids;

            this.Result = this.ProtocolAdatper.NspiDNToMId(reserved, names, out mids);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiDNToMId method should return Success.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1260
            Site.CaptureRequirementIfAreEqual<uint>(
                0x0,
                mids.Value.AulPropTag[0],
                1260,
                @"[In NspiDNToMId] [Server Processing Rules: Upon receiving message NspiDNToMId, the server MUST process the data from the message subject to the following constraints:] [Constraint 3] If the server is unable to locate an appropriate mapping between a DN and a Minimal Entry ID, it [server] MUST map the DN to a Minimal Entry ID with the value 0.");

            #endregion Capture
            #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_S02_TC36_NspiSeekEntriesWithpPropTagsSetNull()
        {
            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.Success, this.Result, "NspiBind should return Success!");
            #endregion

            #region Call NspiQueryRows method with propTags set to null.
            uint flagsOfQueryRows = (uint)RetrievePropertyFlag.fSkipObjects;
            uint tableCount = 0;
            uint[] table = null;
            uint count = Constants.QueryRowsRequestedRowNumber;
            PropertyRowSet_r? rowsOfQueryRows;
            string displayName = Common.GetConfigurationPropertyValue("AgentName", this.Site);

            PropertyTagArray_r? propTags = null;
            this.Result = this.ProtocolAdatper.NspiQueryRows(flagsOfQueryRows, ref stat, tableCount, table, count, propTags, out rowsOfQueryRows);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiQueryRows should return Success.");
            Site.Assert.IsNotNull(rowsOfQueryRows.Value.ARow, "The returned rows should not be empty. The row number is {0}", rowsOfQueryRows == null ? 0 : rowsOfQueryRows.Value.CRows);

            uint[] outMids1 = new uint[rowsOfQueryRows.Value.CRows];
            uint position = 0xffffffff;
            for (uint i = 0; i < rowsOfQueryRows.Value.CRows; i++)
            {
                string name = System.Text.Encoding.UTF8.GetString(rowsOfQueryRows.Value.ARow[i].LpProps[3].Value.LpszA);
                if (displayName.Equals(name, StringComparison.CurrentCultureIgnoreCase))
                {
                    position = i;
                }

                outMids1[i] = (uint)rowsOfQueryRows.Value.ARow[i].LpProps[0].Value.L;
            }
            #endregion

            #region Call NspiUpdateStat to update the STAT block that represents the position in a table to reflect positioning changes requested by the client.
            uint reserved = 0;
            int? delta = 1;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiUpdateStat should return Success!");
            #endregion

            #region Call NspiSeekEntries method with requesting 1 prop tag.
            uint reservedOfSeekEntries = 0;
            PropertyValue_r target = new PropertyValue_r
            {
                PropTag = (uint)AulProp.PidTagDisplayName,
                Reserved = (uint)0x00
            };
            if (this.Transport == "ncacn_http" || this.Transport == "ncacn_ip_tcp")
            {
                target.Value.LpszA = System.Text.Encoding.UTF8.GetBytes(displayName);
            }
            else
            {
                target.Value.LpszA = System.Text.Encoding.UTF8.GetBytes(displayName + "\0");
            }

            PropertyTagArray_r tags = new PropertyTagArray_r
            {
                CValues = 1,
                AulPropTag = new uint[1]
                {
                    (uint)AulProp.PidTagDisplayName
                }
            };
            PropertyTagArray_r? propTagsOfSeekEntries = tags;

            PropertyTagArray_r table1 = new PropertyTagArray_r
            {
                AulPropTag = outMids1
            };
            table1.CValues = (uint)table1.AulPropTag.Length;
            PropertyTagArray_r? tableOfSeekEntries = table1;
            PropertyRowSet_r? rowsOfSeekEntries;

            stat.CurrentRec = 0;
            stat.NumPos = 0;
            this.Result = this.ProtocolAdatper.NspiSeekEntries(reservedOfSeekEntries, ref stat, target, tableOfSeekEntries, propTagsOfSeekEntries, out rowsOfSeekEntries);
            Site.Assert.AreEqual(ErrorCodeValue.Success, this.Result, "NspiSeekEntries should return Success!");

            Site.CaptureRequirementIfAreEqual<uint>(
                position,
                stat.NumPos,
                1052,
                "[In NspiSeekEntries] [Server Processing Rules: Upon receiving message NspiSeekEntries, the server MUST process the data from the message subject to the following constraints:] [Constraint 14] If the server is using the table specified by the input parameter lpETable, the server MUST set the NumPos field of the parameter pStat to the accurate numeric position of the qualifying row in the table.");

            #endregion

            #region Call NspiQueryRows method using parameters of NspiSeekEntries method.
            uint flagsOfQueryRows1 = (uint)RetrievePropertyFlag.fEphID;

            // Create a new table used as the NspiQueryRows input parameter.
            uint[] newTable = new uint[outMids1.Length - stat.NumPos];
            Array.Copy(outMids1, stat.NumPos, newTable, 0, newTable.Length);
            uint tableCount1 = (uint)newTable.Length;
            uint count1 = tableCount1;
            PropertyRowSet_r? rowsOfQueryRows1;
            PropertyTagArray_r? propTags1 = tags;
            this.Result = this.ProtocolAdatper.NspiQueryRows(flagsOfQueryRows1, ref stat, tableCount1, newTable, count1, propTags1, out rowsOfQueryRows1);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiQueryRows should return Success!");

            // The returned rows may be empty for the NspiSeekEntries method as indicated in section 3.1.4.1.9 of the specification MS-OXNSPI. SO if it is empty, this method needs to be called again.
            if (rowsOfSeekEntries == null || rowsOfSeekEntries.Value.ARow.Length != rowsOfQueryRows1.Value.ARow.Length)
            {
                this.Result = this.ProtocolAdatper.NspiSeekEntries(reservedOfSeekEntries, ref stat, target, tableOfSeekEntries, propTagsOfSeekEntries, out rowsOfSeekEntries);
                Site.Assert.AreEqual(ErrorCodeValue.Success, this.Result, "NspiSeekEntries should return Success!");
            }

            Site.Assert.IsNotNull(rowsOfSeekEntries, "The NspiSeekEntries method should return rows when called again!");

            #region Capture
            foreach (PropertyRow_r row in rowsOfSeekEntries.Value.ARow)
            {
                Site.Assert.AreEqual<int>(1, row.LpProps.Length, "The input parameter pPropTags specified 1 property tag.");
                Site.Assert.AreEqual<uint>((uint)AulProp.PidTagDisplayName, row.LpProps[0].PropTag, "The input parameter pPropTags specified property tag PidTagDisplayName.");
            }

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1058
            // All the property tag returned in ppRows were checked and same as specified by the client, MS-OXNSPI_R1058 can be verified directly.
            Site.CaptureRequirement(
                1058,
                @"[In NspiSeekEntries] [Server Processing Rules: Upon receiving message NspiSeekEntries, the server MUST process the data from the message subject to the following constraints:] [Constraint 15] Subject to the prior constraints [If the input parameter pPropTags is not NULL], the server MUST construct an PropertyRowSet_r to return to the client in the output parameter ppRows.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1755
            Site.CaptureRequirementIfIsTrue(
                AdapterHelper.AreTwoPropertyRowSetEqual(rowsOfSeekEntries, rowsOfQueryRows1),
                1755,
                @"This PropertyRowSet_r MUST be exactly the same PropertyRowSet_r that would be returned in the ppRows parameter of a call to the NspiQueryRows method with the following parameters:
The NspiSeekEntries parameter hRpc is used as the NspiQueryRows parameter hRpc.
The value fEphID is used as the NspiQueryRows parameter dwFlags.
The NspiSeekEntries output parameter pStat (as modified by the prior constraints) is used as the NspiQueryRows parameter pStat.
If the NspiSeekEntries input parameter lpETable is not NULL, the server constructs an explicit table from the table specified by lpETable by copying rows in order from lpETable to the new explicit table. The server begins copying from the row specified by the NumPos field of the pStat parameter (as modified by the prior constraints), and continues until all remaining rows are added to the new table. The number of rows in this new table is used as the NspiQueryRows parameter dwETableCount, and the new table is used as the NspiQueryRows lpETable parameter.
The list of Minimal Entry IDs in the input parameter lpETable starting with the qualifying row is used as the NspiQueryRows parameter lpETable. These Minimal Entry IDs [the list of Minimal Entry IDs in the input parameter lpETable] are expressed as a simple array of DWORD values rather than as a PropertyTagArray_r value. Note that the qualifying row is included in this list, and that the order of the Minimal Entry IDs from the input parameter lpETable is preserved in this list.
If the NspiSeekEntries input parameter lpETable is not NULL, the value used for the NspiQueryRows parameter dwETableCount is used for the NspiQueryRows parameter Count.
The NspiSeekEntries parameter pPropTags is used as the NspiQueryRows parameter pPropTags.");
            #endregion Capture
            #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_S02_TC30_DNToMIdIgnoreReserved()
        {
            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 NspiDNToMId with Reserved field set to 0.
            uint reserved = 0;
            StringsArray_r names = new StringsArray_r
            {
                CValues = 2,
                LppszA = new string[2]
            };
            names.LppszA[0] = Common.GetConfigurationPropertyValue("User3Essdn", this.Site);
            names.LppszA[1] = Common.GetConfigurationPropertyValue("User2Essdn", this.Site);
            PropertyTagArray_r? mids1;
            this.Result = this.ProtocolAdatper.NspiDNToMId(reserved, names, out mids1);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiDNToMId should return Success!");
            #endregion

            #region Call NspiDNToMId with Reserved field set to 1.
            PropertyTagArray_r? mids2;
            reserved = 0x1;
            this.Result = this.ProtocolAdatper.NspiDNToMId(reserved, names, out mids2);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiDNToMId method should return Success.");

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

            bool temp = true;
            if (mids1.Value.CValues == mids2.Value.CValues)
            {
                for (int i = 0; i < mids1.Value.CValues; i++)
                {
                    if (mids1.Value.AulPropTag[i] != mids2.Value.AulPropTag[i])
                    {
                        temp = false;
                        break;
                    }
                }
            }
            else
            {
                temp = false;
            }

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1700
            Site.CaptureRequirementIfIsTrue(
                temp,
                1700,
                @"[In NspiDNToMId] if this field[Reserved] is set to different values, the server will return the same result.");

            #endregion Capture
            #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_S02_TC39_GetMatchesWithDifferentDeltaAndContainerID()
        {
            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 to get the DN of the 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
            {
                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.AreEqual(ErrorCodeValue.Success, this.Result, "NspiQueryRows should return Success!");

            string userName = Common.GetConfigurationPropertyValue("User1Name", 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 the specified user.
            uint reserved = 0;
            StringsArray_r names = new StringsArray_r
            {
                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 twice with different Delta and ContainerID fields in input parameters.
            uint reserved1 = 0;
            uint reserver2 = 0;
            PropertyTagArray_r? proReserved = null;
            uint requested = Constants.GetMatchesRequestedRowNumber;
            Restriction_r? filter = null;
            PropertyTagArray_r? outMIds1;
            stat.CurrentRec = mids.Value.AulPropTag[0];
            stat.Delta = 1;
            stat.ContainerID = 1;

            PropertyTagArray_r propTag = new PropertyTagArray_r
            {
                CValues = 3,
                AulPropTag = new uint[3]
                {
                    (uint)AulProp.PidTagEntryId,
                    (uint)AulProp.PidTagDisplayType,
                    (uint)AulProp.PidTagObjectType
                }
            };

            PropertyTagArray_r? propTagsOfGetMatches = propTag;
            PropertyName_r? propNameOfGetMatches = null;

            // Output parameters.
            PropertyRowSet_r? rowsOfGetMatches;

            this.Result = this.ProtocolAdatper.NspiGetMatches(reserved1, ref stat, proReserved, reserver2, filter, propNameOfGetMatches, requested, out outMIds1, propTagsOfGetMatches, out rowsOfGetMatches);
            Site.Assert.AreEqual(ErrorCodeValue.Success, this.Result, "NspiGetMatches should return Success!");
            Site.Assert.IsNotNull(outMIds1.Value, "The Minimal Entry IDs returned successfully. The MId number is {0}.", outMIds1 == null ? 0 : outMIds1.Value.CValues);

            stat.Delta = 2;
            stat.ContainerID = (uint)AulProp.PidTagDisplayName;
            PropertyTagArray_r? outMIds2;
            this.Result = this.ProtocolAdatper.NspiGetMatches(reserved1, ref stat, proReserved, reserver2, filter, propNameOfGetMatches, requested, out outMIds2, propTagsOfGetMatches, out rowsOfGetMatches);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiGetMatches should return Success!");
            Site.Assert.IsNotNull(outMIds2.Value, "The Minimal Entry IDs returned successfully. The MId number is {0}.", outMIds2 == null ? 0 : outMIds2.Value.CValues);

            Site.Assert.AreEqual<uint>(outMIds1.Value.CValues, outMIds2.Value.CValues, "The Minimal Entry IDs count should be same.");

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

            for (uint i = 0; i < outMIds1.Value.CValues; i++)
            {
                Site.Assert.AreEqual<uint>(outMIds1.Value.AulPropTag[i], outMIds2.Value.AulPropTag[i], "The Minimal Entry ID should be same.");
            }

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1131
            // The Delta and ContainerID fields are different but the server returned the same Minimal Entry IDs, MS-OXNSPI_R1131 can be verified directly.
            Site.CaptureRequirement(
                1131,
                @"[In NspiGetMatches] [Server Processing Rules: Upon receiving message NspiGetMatches, the server MUST process the data from the message subject to the following constraints:] [Constraint 9] The server MUST ignore any values of the Delta and ContainerID fields while locating the object.");
            #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_S02_TC31_NspiGetMatchesRestrictionVerification()
        {
            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.Success, this.Result, "NspiBind should return Success!");
            #endregion

            #region Call NspiGetMatches with ExistRestriction and AndRestriction.
            uint reserved1 = 0;
            uint reserver2 = 0;
            PropertyTagArray_r? proReserved = null;
            uint requested = Constants.GetMatchesRequestedRowNumber;

            Restriction_r resExist_r = new Restriction_r
            {
                Rt = 0x08,
                Res = new RestrictionUnion_r
                {
                    ResExist =
                        new ExistRestriction_r
                        {
                            Reserved1 = 0,
                            Reserved2 = 0,
                            PropTag = (uint)AulProp.PidTagEntryId
                        }
                }
            };

            Restriction_r resExist_r1 = new Restriction_r
            {
                Rt = 0x08,
                Res =
                    new RestrictionUnion_r
                    {
                        ResExist =
                            new ExistRestriction_r
                            {
                                Reserved1 = 0,
                                Reserved2 = 0,
                                PropTag = (uint)AulProp.PidTagAddressBookPhoneticDisplayName
                            }
                    }
            };

            Restriction_r addRestriction = new Restriction_r
            {
                Rt = 0x00,
                Res =
                    new RestrictionUnion_r
                    {
                        ResAnd = new AndRestriction_r
                        {
                            CRes = 2,
                            LpRes = new Restriction_r[]
                            {
                                resExist_r, resExist_r1
                            }
                        }
                    }
            };

            Restriction_r? filter = addRestriction;

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

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

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

            uint sortType = stat.SortType;
            uint currentRec = stat.CurrentRec;
            int delta = stat.Delta;
            uint numPos = stat.NumPos;
            uint totalRecs = stat.TotalRecs;
            uint codePage = stat.CodePage;
            uint templateLocale = stat.TemplateLocale;
            uint sortLocale = stat.SortLocale;

            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!");

            int index = 0;
            foreach (PropertyRow_r rows in rowsOfGetMatches.Value.ARow)
            {
                uint propTag = outMIds.Value.AulPropTag[index];

                // Fetch the value of PidTagEntryId.
                EphemeralEntryID entryId = AdapterHelper.ParseEphemeralEntryIDFromBytes(rows.LpProps[0].Value.Bin.Lpb);
                Site.Assert.AreEqual<uint>(propTag, entryId.Mid, "The Minimal ID of the object (index {0}) is inserted into the Explicit Table.", index);
                index++;
            }

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1144
            // The Minimal ID of the object is inserted into the Explicit Table according to the above assert, so MS-OXNSPI_R1144 can be verified directly.
            Site.CaptureRequirement(
                1144,
                "[In NspiGetMatches] [Server Processing Rules: Upon receiving message NspiGetMatches, the server MUST process the data from the message subject to the following constraints:] [Constraint 13] If a specific object is located, the Minimal ID of the object is inserted into the Explicit Table.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1146
            Site.CaptureRequirementIfAreEqual<uint>(
                currentRec,
                stat.ContainerID,
                1146,
                @"[In NspiGetMatches] [Server Processing Rules: Upon receiving message NspiGetMatches, the server MUST process the data from the message subject to the following constraints:] [Constraint 15] If the server returns ""Success"", the server MUST set the ContainerID field of the output parameter pStat to be equal to the CurrentRec field of the input parameter pStat.");

            Site.Assert.AreEqual<uint>(sortType, stat.SortType, "The server MUST NOT modify SortType field in pStat parameter.");
            Site.Assert.AreEqual<uint>(currentRec, stat.CurrentRec, "The server MUST NOT modify CurrentRec field in pStat parameter.");
            Site.Assert.AreEqual<int>(delta, stat.Delta, "The server MUST NOT modify Delta field in pStat parameter.");
            Site.Assert.AreEqual<uint>(numPos, stat.NumPos, "The server MUST NOT modify NumPos field in pStat parameter.");
            Site.Assert.AreEqual<uint>(totalRecs, stat.TotalRecs, "The server MUST NOT modify TotalRecs field in pStat parameter.");
            Site.Assert.AreEqual<uint>(codePage, stat.CodePage, "The server MUST NOT modify CodePage field in pStat parameter.");
            Site.Assert.AreEqual<uint>(templateLocale, stat.TemplateLocale, "The server MUST NOT modify TemplateLocale field in pStat parameter.");
            Site.Assert.AreEqual<uint>(sortLocale, stat.SortLocale, "The server MUST NOT modify SortLocale field in pStat parameter.");

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1147
            // The server didn't modify any other fields except ContainerID field in pStat parameter, MS-OXNSPI_R1147 can be verified directly.
            Site.CaptureRequirement(
                1147,
                @"[In NspiGetMatches] [Server Processing Rules: Upon receiving message NspiGetMatches, the server MUST process the data from the message subject to the following constraints:] [Constraint 15] The server MUST NOT modify any other fields in this parameter [pStat].");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1908
            // The AndRestriction_r is specified to the server and the NspiGetMatches method performs successfully, if the list of Minimal Entry IDs is not null, MS-OXNSPI_R1908 can be verified.
            Site.CaptureRequirementIfIsNotNull(
                outMIds,
                1908,
                @"[In NspiGetMatches] When AndRestriction_r is specified to the server via the NspiGetMatches method, the server locates all the objects that meet the restriction criteria, and the list of the Minimal Entry IDs of those objects is constructed.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1914
            // The ExistRestriction_r is specified to the server and the NspiGetMatches method performs successfully, if the list of Minimal Entry IDs is not null, MS-OXNSPI_R1914 can be verified.
            Site.CaptureRequirementIfIsNotNull(
                outMIds,
                1914,
                @"[In NspiGetMatches] When ExistRestriction_r is specified to the server via the NspiGetMatches method, the server locates all the objects that meet the restriction criteria, and the list of the Minimal Entry IDs of those objects is constructed.");
            #endregion

            #region Call NspiGetMatches with ExistRestriction and OrRestriction.

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

            filter = restrictionOr;

            propTags1 = new PropertyTagArray_r
            {
                CValues = 3,
                AulPropTag = new uint[3]
                {
                    (uint)AulProp.PidTagEntryId,
                    (uint)AulProp.PidTagDisplayType,
                    (uint)AulProp.PidTagObjectType
                }
            };
            propTagsOfGetMatches = propTags1;

            // Set value for propNameOfGetMatches.
            propNameOfGetMatches = null;

            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!");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1909
            // The OrRestriction_r is specified to the server and the NspiGetMatches method performs successfully, if the list of Minimal Entry IDs is not null, MS-OXNSPI_R1909 can be verified.
            Site.CaptureRequirementIfIsNotNull(
                outMIds,
                1909,
                @"[In NspiGetMatches] When OrRestriction_r is specified to the server via the NspiGetMatches method, the server locates all the objects that meet the restriction criteria, and the list of the Minimal Entry IDs of those objects is constructed.");
            #endregion

            #region Call NspiGetMatches with ContentRestriction.
            Restriction_r contentRestriction = new Restriction_r
            {
                Rt = 0x03,
                Res = new RestrictionUnion_r
                {
                    ResContent = new ContentRestriction_r
                    {
                        FuzzyLevel = 0x00010002 // The value stored in the TaggedValue field matches a starting portion of the value of the column property tag and the comparison does not consider case.
                    }
                }
            };

            PropertyValue_r target = new PropertyValue_r
            {
                PropTag = (uint)AulProp.PidTagDisplayName,
                Reserved = 0
            };
            string displayName = Common.GetConfigurationPropertyValue("User1Name", this.Site);
            if (this.Transport == "ncacn_http" || this.Transport == "ncacn_ip_tcp")
            {
                target.Value.LpszA = System.Text.Encoding.UTF8.GetBytes(displayName);
            }
            else
            {
                target.Value.LpszA = System.Text.Encoding.UTF8.GetBytes(displayName + "\0");
            }

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

            filter = contentRestriction;

            propTags1 = new PropertyTagArray_r
            {
                CValues = 3,
                AulPropTag = new uint[3]
                {
                    (uint)AulProp.PidTagEntryId,
                    (uint)AulProp.PidTagDisplayType,
                    (uint)AulProp.PidTagObjectType
                }
            };
            propTagsOfGetMatches = propTags1;

            // Set value for propNameOfGetMatches.
            propNameOfGetMatches = null;

            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!");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1911
            // The ContentRestriction_r is specified to the server and the NspiGetMatches method performs successfully, if the list of Minimal Entry IDs is not null, MS-OXNSPI_R1911 can be verified.
            Site.CaptureRequirementIfIsNotNull(
                outMIds,
                1911,
                @"[In NspiGetMatches] When ContentRestriction_r is specified to the server via the NspiGetMatches method, the server locates all the objects that meet the restriction criteria, and the list of the Minimal Entry IDs of those objects is constructed.");

            #endregion

            #region Call NspiGetMatches with PropertyRestriction.
            Restriction_r propertyRestriction = new Restriction_r
            {
                Rt = 0x04,
                Res = new RestrictionUnion_r
                {
                    ResProperty = new Propertyrestriction_r
                    {
                        Relop = 0x04
                    }
                }
            };
            target = new PropertyValue_r
            {
                PropTag = (uint)AulProp.PidTagDisplayName,
                Reserved = 0
            };
            displayName = Common.GetConfigurationPropertyValue("User1Name", this.Site);
            if (this.Transport == "ncacn_http" || this.Transport == "ncacn_ip_tcp")
            {
                target.Value.LpszA = System.Text.Encoding.UTF8.GetBytes(displayName);
            }
            else
            {
                target.Value.LpszA = System.Text.Encoding.UTF8.GetBytes(displayName + "\0");
            }

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

            filter = propertyRestriction;

            propTags1 = new PropertyTagArray_r
            {
                CValues = 3,
                AulPropTag = new uint[3]
                {
                    (uint)AulProp.PidTagEntryId,
                    (uint)AulProp.PidTagDisplayType,
                    (uint)AulProp.PidTagObjectType
                }
            };
            propTagsOfGetMatches = propTags1;

            // Set null value to input parameter property names of NspiGetMatches.
            propNameOfGetMatches = null;

            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!");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1912
            // The PropertyRestriction_r is specified to the server and the NspiGetMatches method performs successfully, if the list of Minimal Entry IDs is not null, MS-OXNSPI_R1912 can be verified.
            Site.CaptureRequirementIfIsNotNull(
                outMIds,
                1912,
                @"[In NspiGetMatches] When PropertyRestriction_r is specified to the server via the NspiGetMatches method, the server locates all the objects that meet the restriction criteria, and the list of the Minimal Entry IDs of those objects is constructed.");

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1913
            // AndRestriction_r, OrRestriction_r, ContentRestriction_r, PropertyRestriction_r and ExistRestriction_r are verified successfully, MS-OXNSPI_R1913 can be verified directly.
            Site.CaptureRequirement(
                1913,
                @"[In NspiGetMatches] When RestrictionUnion_r is specified to the server via the NspiGetMatches method, the server locates all the objects that meet the restriction criteria, and the list of the Minimal Entry IDs of those objects is constructed.");
            #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_S03_TC02_ResolveNamesWSuccess()
        {
            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 NspiResolveNamesW method with a specific list of names and propertyTag value with null.
            uint reservedOfResolveNamesW = 0;
            WStringsArray_r wstrArray;
            wstrArray.CValues = 5;
            wstrArray.LppszW = new string[wstrArray.CValues];
            wstrArray.LppszW[0] = Common.GetConfigurationPropertyValue("User1Name", this.Site);
            wstrArray.LppszW[1] = string.Empty;
            wstrArray.LppszW[2] = Common.GetConfigurationPropertyValue("AmbiguousName", this.Site);
            wstrArray.LppszW[3] = null;
            wstrArray.LppszW[4] = Constants.UnresolvedName;

            PropertyTagArray_r? propTags = null;
            PropertyTagArray_r? mids;
            PropertyRowSet_r? rowOfResolveNamesW;

            this.Result = this.ProtocolAdatper.NspiResolveNamesW(reservedOfResolveNamesW, stat, propTags, wstrArray, out mids, out rowOfResolveNamesW);

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

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

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1394
            // If the mids which contains Minimal Entry ID returned from the server is not null, 
            // it illustrates that the server must report the Minimal Entry ID that is the result of the ANR process.
            this.Site.CaptureRequirementIfIsNotNull(
                mids,
                1394,
                @"[In NspiResolveNamesW] The server reports the Minimal Entry IDs that are the result of the ANR process.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1650
            Site.CaptureRequirementIfIsNotNull(
                mids,
                1650,
                "[In NspiResolveNamesW] [ppMIds] On return, contains a list of Minimal Entry IDs that match the array of strings, as specified in the input parameter paWStr.");

            this.VerifyPropertyRowSetIsNotNullForNspiResolveNamesW(rowOfResolveNamesW);

            this.VerifyIsRESOLVEDMIDInANRMatchString(mids.Value.AulPropTag[0]);
            this.VerifyIsUNRESOLVEDMIDInANREmptyString(mids.Value.AulPropTag[1]);
            this.VerifyIsAMBIGUOUSMIDInANRAmbiguousString(mids.Value.AulPropTag[2]);
            this.VerifyIsUNRESOLVEDMIDInANRNullString(mids.Value.AulPropTag[3]);
            this.VerifyIsUNRESOLVEDMIDInANRNotFound(mids.Value.AulPropTag[4]);
            this.VerifyIsResultOfANRProcessIsMID(mids);

            // Since if the whole ANR results are verified and the NspiResolveNamesW is invoked, 
            // it must take a set of string values in an 8-bit character set and perform ANR on those strings, 
            // this requirement can be captured directly.
            this.Site.CaptureRequirement(
                1393,
                @"[In NspiResolveNamesW] The NspiResolveNamesW method takes a set of string values in the Unicode character set and performs ANR (as specified in section 3.1.4.7) on those strings.");

            // Since all the returned Minimal Entry IDs are verified according to the order of the input string array, this requirement can be captured directly.
            this.Site.CaptureRequirement(
                1426,
                @"[In NspiResolveNamesW] [Server Processing Rules: Upon receiving message NspiResolveNamesW, the server MUST process the data from the message subject to the following constraints:] [Constraint 6] These Minimal Entry IDs are those that result from the ANR process, as specified in section 3.1.4.7, to the strings in the input parameter paWStr.");

            #endregion Capture
            #endregion

            #region Call NspiResolveNamesW method with a specific list of names and propertyTag value without null.

            PropertyTagArray_r propTagsWithProperties = new PropertyTagArray_r
            {
                CValues = 3,
                AulPropTag = new uint[3]
                {
                    (uint)AulProp.PidTagEntryId,
                    (uint)AulProp.PidTagDisplayName,
                    (uint)AulProp.PidTagObjectType
                }
            };

            this.Result = this.ProtocolAdatper.NspiResolveNamesW(reservedOfResolveNamesW, stat, propTagsWithProperties, wstrArray, out mids, out rowOfResolveNamesW);
            Site.Assert.AreEqual(ErrorCodeValue.Success, this.Result, "NspiResolveNamesW should return Success!");
            Site.Assert.AreNotEqual<int>(0, rowOfResolveNamesW.Value.ARow.Length, "At least one address book object should be matched.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1395
            // The rowOfResolveNamesW which contains a PropertyRowSet_r structure is returned from the server. If it is not null, 
            // it illustrates that certain property values are returned for any valid Minimal Entry IDs identified by the ANR process.
            this.Site.CaptureRequirementIfIsNotNull(
                rowOfResolveNamesW,
                1395,
                @"[In NspiResolveNamesW] Certain property values are returned for any valid Minimal Entry IDs identified by the ANR process.");

            Site.Assert.AreEqual<uint>((uint)AulProp.PidTagEntryId, rowOfResolveNamesW.Value.ARow[0].LpProps[0].PropTag, "The first property returned should be PidTagEntryId. Now the returned property is {0}.", rowOfResolveNamesW.Value.ARow[0].LpProps[0].PropTag);
            Site.Assert.AreEqual<uint>((uint)AulProp.PidTagDisplayName, rowOfResolveNamesW.Value.ARow[0].LpProps[1].PropTag, "The second property returned should be PidTagDisplayName. Now the returned property is {0}.", rowOfResolveNamesW.Value.ARow[0].LpProps[1].PropTag);
            Site.Assert.AreEqual<uint>((uint)AulProp.PidTagObjectType, rowOfResolveNamesW.Value.ARow[0].LpProps[2].PropTag, "The third property returned should be PidTagObjectType. Now the returned property is {0}.", rowOfResolveNamesW.Value.ARow[0].LpProps[2].PropTag);

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1399
            // Since the null value of pPropTags has been set in step "Call NspiResolveNamesW method with a specific list of names", 
            // and the above three asserts ensure that it is a reference to a PropertyTagArray_r value containing a list of the proptags of the columns that the client requests to be returned for each row.
            // So R1347 can be captured directly.
            this.Site.CaptureRequirement(
                1399,
                @"[In NspiResolveNamesW] pPropTags: The value NULL or a reference to a PropertyTagArray_r containing a list of the proptags of the columns that the client requests to be returned for each row returned.");

            #endregion Capture
            #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_S02_TC04_UpdateStatAbsolutePosition()
        {
            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 NspiUpdateStat with the CurrentRec field set to MID_BEGINNING_OF_TABLE (0x00) rather than MID_CURRENT (0x1) to point to the absolute position, and Delta set to 1 to move forward one row towards the end of the table.
            // Record the position before updating stat in this step.
            uint previousPosition = stat.NumPos;
            stat.InitiateStat();
            stat.Delta = 1;
            uint reserved = 0;
            int? delta = 0;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiUpdateStat should return Success!");

            #region Capture code

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R549. The position after moving is {0}.", stat.NumPos);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R549
            // If the currentPosition greater than the position before moving, it specifies that the current position is moved toward the end of the table.
            this.Site.CaptureRequirementIfIsTrue(
                stat.NumPos > previousPosition,
                549,
                @"[In Absolute Positioning] [step 6] If the value of Delta is positive, the Current Position is moved toward the end of the table.");
            #endregion

            uint previousTotalRecs = stat.TotalRecs;
            previousPosition = stat.NumPos;
            stat.InitiateStat();
            stat.NumPos = 1;
            stat.Delta = 1;
            delta = 0;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiUpdateStat should return Success!");

            #region Capture code

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R326001
            // NumPos returned are same regardless of the value of NumPos set in request, this requirement can be captured.
            this.Site.CaptureRequirementIfAreEqual<uint>(
                previousPosition,
                stat.NumPos,
                326001,
                @"[In STAT] [NumPos] If absolute positioning, as specified in section 3.1.4.5.1, is used, the value of this field specified by the client will be ignored by the server. ");
            #endregion

            stat.InitiateStat();
            stat.TotalRecs = 1;
            stat.Delta = 1;
            delta = 0;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiUpdateStat should return Success!");

            #region Capture code

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R331001
            this.Site.CaptureRequirementIfAreEqual<uint>(
                previousTotalRecs,
                stat.TotalRecs,
                331001,
                @"[In STAT] [TotalRecs] If absolute positioning, as specified in section 3.1.4.5.1, is used, the value of this field specified by the client will be ignored by the server. ");
            #endregion

            #endregion

            #region Call NspiUpdateStat with Delta set to 0 to keep the position in the table.
            // Record the position before updating stat in this step.
            previousPosition = stat.NumPos;
            stat.Delta = 0;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiUpdateStat should return Success!");

            #region Capture code

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R550. The position after moving is {0}.", stat.NumPos);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R550
            // If the currentPosition equals the position before moving, it specifies that the current position is not changed.
            this.Site.CaptureRequirementIfAreEqual<uint>(
                previousPosition,
                stat.NumPos,
                550,
                @"[In Absolute Positioning] [step 6] A Delta with the value 0 results in no change to the Current Position.");

            #endregion
            #endregion

            #region Call NspiUpdateStat with Delta set to -1 to move forward one row towards the beginning of the table.
            // Record the position before updating stat in this step.
            previousPosition = stat.NumPos;
            stat.Delta = -1;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiUpdateStat should return Success!");

            #region Capture code

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R548. The position after moving is {0}.", stat.NumPos);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R548
            // If the currentPosition less than the position before moving, it specifies that the current position is moved toward the beginning of the table.
            this.Site.CaptureRequirementIfIsTrue(
                stat.NumPos < previousPosition,
                548,
                @"[In Absolute Positioning] [step 6] If the value of Delta is negative, the Current Position is moved toward the beginning of the table.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R791
            // MS-OXNSPI_R548 has been verified with the CurrentRec field set to MID_BEGINNING_OF_TABLE and the server locates that row as the initial position row, MS-OXNSPI_R791 can be verified directly.
            this.Site.CaptureRequirement(
                791,
                @"[In NspiUpdateStat] [Server Processing Rules: Upon receiving message NspiUpdateStat, the server MUST process the data from the message subject to the following constraints:] [Constraint 5: The server locates the initial position row in the table specified by the ContainerID field of the input parameter pStat as follows:] If the row specified by the CurrentRec field of the input parameter pStat is not MID_CURRENT, the server locates that row as the initial position row using the absolute position, as specified in section 3.1.4.5.1. ");

            #endregion
            #endregion

            #region Call NspiUpdateStat with Delta set to -1 to move the current position to be before the first row of the table.
            stat.Delta = -1;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiUpdateStat should return Success!");

            #region Capture code

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1743. The position after moving is {0}.", stat.NumPos);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1743
            // In this step, the current position should be moved to be before the first row of the table.
            this.Site.CaptureRequirementIfAreEqual<uint>(
                (uint)MinimalEntryID.MID_BEGINNING_OF_TABLE,
                stat.NumPos,
                1743,
                @"[In Absolute Positioning] [step 7] If applying the Delta as described in step 6 would move the Current Position to be before the first row of the table, the server sets the Current Position to the first row of the table.");
            #endregion
            #endregion

            #region Call NspiUpdateStat set Delta to the value greater than TotalRecs to move the current position to be after the end of the table.
            stat.Delta = (int)stat.TotalRecs + 1;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiUpdateStat should return Success!");

            #region Capture code

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R554. The position after moving is {0}.", stat.NumPos);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R554
            // In this step, the current position is moved to be after the end of the table.
            // If the currentPosition equals the total number of rows, it indicates that server sets the current position to a location which is one row past the last valid row of the table.
            this.Site.CaptureRequirementIfAreEqual<uint>(
                stat.TotalRecs,
                stat.NumPos,
                554,
                @"[In Absolute Positioning] [step 8] If applying the Delta as described in step 6 would move the Current Position to be after the end of the table, the server sets the Current Position to a location one row past the last valid row of the table.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R556
            this.Site.CaptureRequirementIfAreEqual<uint>(
                (uint)MinimalEntryID.MID_END_OF_TABLE,
                stat.CurrentRec,
                556,
                @"[In Absolute Positioning] [step 9] The server sets the field CurrentRec to the Minimal Entry ID of the object occupying the row specified by the Current Position.");

            if (Common.IsRequirementEnabled(1992, this.Site))
            {
                // All values got from NumPos field are accurate values rather than approximate values, so MS-OXNSPI_R1992 can be verified directly.
                this.Site.CaptureRequirement(
                    1992,
                    @"[In Appendix B: Product Behavior] Implementation doesn't report an approximate value for the Numeric Position. (Exchange server 2010 and above follow this behavior.)");
            }

            #endregion
            #endregion

            #region Call NspiUnbind to destroy the context handle.
            uint returnValue = this.ProtocolAdatper.NspiUnbind(reserved);
            Site.Assert.AreEqual<uint>(1, returnValue, "NspiUnbind method should return 1 (Success).");
            #endregion
        }
        public void MSOXNSPI_S03_TC04_ResolveNamesWStringConversion()
        {
            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.Success, this.Result, "NspiBind should return Success!");
            #endregion

            #region Call NspiResolveNamesW to require the string properties to be different with their native type.
            uint reservedOfResolveNamesW = 0;
            WStringsArray_r wstrArray;
            wstrArray.CValues = 1;
            wstrArray.LppszW = new string[wstrArray.CValues];
            wstrArray.LppszW[0] = Common.GetConfigurationPropertyValue("User2Name", this.Site);

            PropertyTagArray_r propTags = new PropertyTagArray_r
            {
                CValues = 2,
                AulPropTag = new uint[]
                {
                    AdapterHelper.ConvertStringToString8((uint)AulProp.PidTagAddressBookDisplayNamePrintable),
                    AdapterHelper.ConvertString8ToString((uint)AulProp.PidTagDisplayName)
                }
            };
            PropertyTagArray_r? mids;
            PropertyRowSet_r? rowOfResolveNamesW;

            this.Result = this.ProtocolAdatper.NspiResolveNamesW(reservedOfResolveNamesW, stat, propTags, wstrArray, out mids, out rowOfResolveNamesW);
            Site.Assert.AreEqual(ErrorCodeValue.Success, this.Result, "NspiResolveNamesW should return Success!");
            Site.Assert.IsNotNull(rowOfResolveNamesW, "PropertyRowSet_r value should not null. The row number is {0}.", rowOfResolveNamesW == null ? 0 : rowOfResolveNamesW.Value.CRows);
            Site.Assert.AreNotEqual<int>(0, rowOfResolveNamesW.Value.ARow.Length, "At least one address book object should be matched.");

            PropertyRow_r rowValue = rowOfResolveNamesW.Value.ARow[0];

            string resolvedDisplayNamePrintable = System.Text.UnicodeEncoding.UTF8.GetString(rowValue.LpProps[0].Value.LpszA);

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1979: The value of PidTagAddressBookDisplayNamePrintable is {0}.", resolvedDisplayNamePrintable);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1979
            // The field LpszA indicates an 8-bit character string value.
            Site.CaptureRequirementIfIsTrue(
                resolvedDisplayNamePrintable.StartsWith(wstrArray.LppszW[0], StringComparison.Ordinal),
                1979,
                "[In Conversion Rules for String Values Specified by the Server to the Client] In NspiResolveNamesW method, String values can be returned in 8-bit character representation in the output parameter ppRows.");

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

            string reslovedName = System.Text.UnicodeEncoding.Unicode.GetString(rowValue.LpProps[1].Value.LpszW);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1978
            // The field LpszW indicates a single Unicode string value.
            Site.CaptureRequirementIfAreEqual<string>(
                wstrArray.LppszW[0].ToLower(System.Globalization.CultureInfo.CurrentCulture),
                reslovedName.ToLower(System.Globalization.CultureInfo.CurrentCulture),
                1978,
                "[In Conversion Rules for String Values Specified by the Server to the Client] In NspiResolveNamesW method, String values can be returned in Unicode representation in the output parameter ppRows.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1939
            // The native type of PidTagAddressBookDisplayNamePrintable is PtypString and the client has requested this property with PtypString8.
            Site.CaptureRequirementIfAreEqual<uint>(
                AdapterHelper.ConvertStringToString8((uint)AulProp.PidTagAddressBookDisplayNamePrintable),
                rowValue.LpProps[0].PropTag,
                1939,
                "[In Conversion Rules for String Values Specified by the Server to the Client] [For method NspiResolveNamesW] If the native type of a property is PtypString and the client has requested that property with the type PtypString8, the server MUST convert the Unicode representation to an 8-bit character representation in the code page specified by the CodePage field of the pStat parameter prior to returning the value.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1955
            // The native type of PidTagDisplayName is PtypString8 and the client has requested this property with PtypString.
            Site.CaptureRequirementIfAreEqual<uint>(
                AdapterHelper.ConvertString8ToString((uint)AulProp.PidTagDisplayName),
                rowValue.LpProps[1].PropTag,
                1955,
                "[In Conversion Rules for String Values Specified by the Server to the Client] [For method NspiResolveNamesW] If the native type of a property is PtypString8 and the client has requested that property with the type PtypString, the server MUST convert the 8-bit character representation to a Unicode representation prior to returning the value.");

            #endregion

            #region Call NspiResolveNamesW to require the string properties to be the same as their native types.
            wstrArray.CValues = 1;
            wstrArray.LppszW = new string[wstrArray.CValues];
            wstrArray.LppszW[0] = Common.GetConfigurationPropertyValue("User2Name", this.Site);

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

            this.Result = this.ProtocolAdatper.NspiResolveNamesW(reservedOfResolveNamesW, stat, propTags, wstrArray, out mids, out rowOfResolveNamesW);
            Site.Assert.AreEqual(ErrorCodeValue.Success, this.Result, "NspiResolveNamesW should return Success!");
            Site.Assert.IsNotNull(rowOfResolveNamesW, "PropertyRowSet_r value should not null. The row number is {0}.", rowOfResolveNamesW == null ? 0 : rowOfResolveNamesW.Value.CRows);
            Site.Assert.AreNotEqual<int>(0, rowOfResolveNamesW.Value.ARow.Length, "At least one address book object should be matched.");

            rowValue = rowOfResolveNamesW.Value.ARow[0];

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1947
            // The native type of PidTagAddressBookDisplayNamePrintable is PtypString and the client has requested this property with PtypString.
            Site.CaptureRequirementIfAreEqual<uint>(
                (uint)AulProp.PidTagAddressBookDisplayNamePrintable,
                rowValue.LpProps[0].PropTag,
                1947,
                "[In Conversion Rules for String Values Specified by the Server to the Client] [For method NspiResolveNamesW] If the native type of a property is PtypString and the client has requested that property with the type PtypString, the server MUST return the Unicode representation unmodified.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1963
            // The native type of PidTagDisplayName is PtypString8 and the client has requested this property with PtypString8.
            Site.CaptureRequirementIfAreEqual<uint>(
                (uint)AulProp.PidTagDisplayName,
                rowValue.LpProps[1].PropTag,
                1963,
                "[In Conversion Rules for String Values Specified by the Server to the Client] [For method NspiResolveNamesW] If the native type of a property is PtypString8 and the client has requested that property with the type PtypString8, the server MUST return the 8-bit character representation unmodified.");

            #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_S02_TC32_NspiGetPropsStringConversion()
        {
            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.Success, this.Result, "NspiBind should return Success!");
            #endregion

            #region Call NspiUpdateStat to update the STAT block.
            uint reserved = 0;
            int? delta = 1;
            this.Result = this.ProtocolAdatper.NspiUpdateStat(reserved, ref stat, ref delta);
            Site.Assert.AreEqual(ErrorCodeValue.Success, this.Result, "NspiUpdateStat should return Success!");
            #endregion

            #region Call NspiGetProps to request the string properties to be different from their native types.
            PropertyTagArray_r prop = new PropertyTagArray_r
            {
                CValues = 2
            };
            prop.AulPropTag = new uint[prop.CValues];

            prop.AulPropTag[0] = AdapterHelper.ConvertStringToString8((uint)AulProp.PidTagAddressBookDisplayNamePrintable);
            prop.AulPropTag[1] = AdapterHelper.ConvertString8ToString((uint)AulProp.PidTagDisplayName);
            PropertyTagArray_r? propTags = prop;

            uint flagsOfGetProps = (uint)RetrievePropertyFlag.fEphID;
            PropertyRow_r? rows;

            // Save the CurrentRec value of stat structure.
            this.Result = this.ProtocolAdatper.NspiGetProps(flagsOfGetProps, stat, propTags, out rows);
            Site.Assert.AreEqual(ErrorCodeValue.Success, this.Result, "NspiGetProps should return Success.");
            Site.Assert.IsNotNull(rows, "The reference to the PropertyRow_r value should not be null. The row number is {0}.", rows == null ? 0 : rows.Value.CValues);

            string diplayName = System.Text.UnicodeEncoding.Unicode.GetString(rows.Value.LpProps[1].Value.LpszW);

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1968: The value of PidTagDisplayNamePrintable of the specified address book returned in Unicode representation is {0}.", diplayName);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1968
            // The field LpszW indicates a single Unicode string value.
            Site.CaptureRequirementIfIsNotNull(
                rows.Value.LpProps[1].Value.LpszW,
                1968,
                "[In Conversion Rules for String Values Specified by the Server to the Client] In NspiGetProps method, String values can be returned in Unicode representation in the output parameter ppRows.");

            string displayNamePrintable = System.Text.UnicodeEncoding.UTF8.GetString(rows.Value.LpProps[0].Value.LpszA);

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1969: The value of PidTagAddressBookDisplayNamePrintable of the specified address book returned in Unicode representation is {0}.", displayNamePrintable);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1969
            // The field LpszA indicates a 8-bit character string value.
            Site.CaptureRequirementIfIsNotNull(
                rows.Value.LpProps[0].Value.LpszA,
                1969,
                "[In Conversion Rules for String Values Specified by the Server to the Client] In NspiGetProps method, String values can be returned in 8-bit character representation in the output parameter ppRows.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1934
            // The native type of PidTagAddressBookDisplayNamePrintable is PtypString and the client has requested this property with PtypString8.
            Site.CaptureRequirementIfAreEqual<uint>(
                AdapterHelper.ConvertStringToString8((uint)AulProp.PidTagAddressBookDisplayNamePrintable),
                rows.Value.LpProps[0].PropTag,
                1934,
                "[In Conversion Rules for String Values Specified by the Server to the Client] [For method NspiGetProps] If the native type of a property is PtypString and the client has requested that property with the type PtypString8, the server MUST convert the Unicode representation to an 8-bit character representation in the code page specified by the CodePage field of the pStat parameter prior to returning the value.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1950
            // The native type of PidTagDisplayName is PtypString8 and the client has requested this property with PtypString.
            Site.CaptureRequirementIfAreEqual<uint>(
                AdapterHelper.ConvertString8ToString((uint)AulProp.PidTagDisplayName),
                rows.Value.LpProps[1].PropTag,
                1950,
                "[In Conversion Rules for String Values Specified by the Server to the Client] [For method NspiGetProps] If the native type of a property is PtypString8 and the client has requested that property with the type PtypString, the server MUST convert the 8-bit character representation to a Unicode representation prior to returning the value.");
            #endregion

            #region Call NspiGetProps to request the string properties to be the same as their native types.
            prop = new PropertyTagArray_r
            {
                CValues = 2
            };
            prop.AulPropTag = new uint[prop.CValues];

            prop.AulPropTag[0] = (uint)AulProp.PidTagAddressBookDisplayNamePrintable;
            prop.AulPropTag[1] = (uint)AulProp.PidTagDisplayName;
            propTags = prop;

            this.Result = this.ProtocolAdatper.NspiGetProps(flagsOfGetProps, stat, propTags, out rows);
            Site.Assert.AreEqual(ErrorCodeValue.Success, this.Result, "NspiGetProps should return Success.");
            Site.Assert.IsNotNull(rows, "The reference to the PropertyRow_r value should not be null. The row number is {0}.", rows == null ? 0 : rows.Value.CValues);

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1942
            // The native type of PidTagAddressBookDisplayNamePrintable is PtypString and the client has requested this property with PtypString.
            Site.CaptureRequirementIfAreEqual<uint>(
                (uint)AulProp.PidTagAddressBookDisplayNamePrintable,
                rows.Value.LpProps[0].PropTag,
                1942,
                "[In Conversion Rules for String Values Specified by the Server to the Client] [For method NspiGetProps] If the native type of a property is PtypString and the client has requested that property with the type PtypString, the server MUST return the Unicode representation unmodified.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1958
            // The native type of PidTagDisplayName is PtypString8 and the client has requested this property with PtypString8.
            Site.CaptureRequirementIfAreEqual<uint>(
                (uint)AulProp.PidTagDisplayName,
                rows.Value.LpProps[1].PropTag,
                1958,
                "[In Conversion Rules for String Values Specified by the Server to the Client] [For method NspiGetProps] If the native type of a property is PtypString8 and the client has requested that property with the type PtypString8, the server MUST return the 8-bit character representation unmodified.");

            #endregion

            #region Call NspiUnbind method to destroy the context handle.
            uint returnValue = this.ProtocolAdatper.NspiUnbind(0);
            Site.Assert.AreEqual<uint>(1, returnValue, "NspiUnbind method should return 1 (Success).");
            #endregion
        }
        /// <summary>
        /// The NspiBind method initiates a session between a client and the server.
        /// </summary>
        /// <param name="flags">A DWORD value that contains a set of bit flags.</param>
        /// <param name="stat">A pointer to a STAT block that describes a logical position in a specific address book container.</param>
        /// <param name="serverGuid">The value NULL or a pointer to a GUID value that is associated with the specific server.</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 NspiBind(uint flags, STAT stat, ref FlatUID_r? serverGuid, bool needRetry = true)
        {
            ErrorCodeValue result;
            if (this.transport == "ncacn_http" || this.transport == "ncacn_ip_tcp")
            {
                result = this.nspiRpcAdapter.NspiBind(flags, stat, ref serverGuid, needRetry);
            }
            else
            {
                result = this.nspiMapiHttpAdapter.Bind(flags, stat, ref serverGuid);
            }

            this.VerifyNspiBind();
            this.VerifyTransport();
            return result;
        }
        public void MSOXNSPI_S02_TC33_NspiQueryRowsStringConversion()
        {
            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.Success, this.Result, "NspiBind should return Success!");
            #endregion

            #region Call NspiQueryRows to request the string properties to be different from their native types.
            uint flagsOfQueryRows = (uint)RetrievePropertyFlag.fEphID;
            PropertyRowSet_r? rowsOfQueryRows;

            uint tableCount = 0;
            uint[] table = null;
            uint count = 10;
            PropertyTagArray_r propTagsInstance = new PropertyTagArray_r
            {
                AulPropTag = new uint[]
                {
                    AdapterHelper.ConvertStringToString8((uint)AulProp.PidTagAddressBookDisplayNamePrintable),
                    AdapterHelper.ConvertString8ToString((uint)AulProp.PidTagDisplayName)
                }
            };
            propTagsInstance.CValues = (uint)propTagsInstance.AulPropTag.Length;
            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!");
            Site.Assert.IsNotNull(rowsOfQueryRows, "PropertyRowSet_r value should not null. The row number is {0}.", rowsOfQueryRows == null ? 0 : rowsOfQueryRows.Value.CRows);
            Site.Assert.AreNotEqual<int>(0, rowsOfQueryRows.Value.ARow.Length, "At least one address book object should be matched.");

            PropertyRow_r rowValue = rowsOfQueryRows.Value.ARow[0];

            string displayName = System.Text.UnicodeEncoding.Unicode.GetString(rowValue.LpProps[1].Value.LpszW);

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1970: The value of PidTagDisplayName is {0}.", displayName);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1970
            // The field LpszW indicates a single Unicode string value.
            Site.CaptureRequirementIfIsNotNull(
                rowValue.LpProps[1].Value.LpszW,
                1970,
                "[In Conversion Rules for String Values Specified by the Server to the Client] In NspiQueryRows method, String values can be returned in Unicode representation in the output parameter ppRows.");

            string displayNamePrintable = System.Text.UnicodeEncoding.UTF8.GetString(rowValue.LpProps[0].Value.LpszA);

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1971: The value of PidTagAddressBookDisplayNamePrintable is {0}.", displayNamePrintable);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1971
            // The field LpszA indicates a 8-bit character string value.
            Site.CaptureRequirementIfIsNotNull(
                rowValue.LpProps[0].Value.LpszA,
                1971,
                "[In Conversion Rules for String Values Specified by the Server to the Client] In NspiQueryRows method, String values can be returned in 8-bit character representation in the output parameter ppRows.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1935
            // The native type of PidTagAddressBookDisplayNamePrintable is PtypString and the client has requested this property with PtypString8.
            Site.CaptureRequirementIfAreEqual<uint>(
                AdapterHelper.ConvertStringToString8((uint)AulProp.PidTagAddressBookDisplayNamePrintable),
                rowValue.LpProps[0].PropTag,
                1935,
                "[In Conversion Rules for String Values Specified by the Server to the Client] [For method NspiQueryRows] If the native type of a property is PtypString and the client has requested that property with the type PtypString8, the server MUST convert the Unicode representation to an 8-bit character representation in the code page specified by the CodePage field of the pStat parameter prior to returning the value.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1951
            // The native type of PidTagDisplayName is PtypString8 and the client has requested this property with PtypString.
            Site.CaptureRequirementIfAreEqual<uint>(
                AdapterHelper.ConvertString8ToString((uint)AulProp.PidTagDisplayName),
                rowValue.LpProps[1].PropTag,
                1951,
                "[In Conversion Rules for String Values Specified by the Server to the Client] [For method NspiQueryRows] If the native type of a property is PtypString8 and the client has requested that property with the type PtypString, the server MUST convert the 8-bit character representation to a Unicode representation prior to returning the value.");
            #endregion

            #region Call NspiQueryRows to request the string properties to be the same as their native types.
            propTagsInstance = new PropertyTagArray_r
            {
                AulPropTag = new uint[]
                {
                    (uint)AulProp.PidTagAddressBookDisplayNamePrintable,
                    (uint)AulProp.PidTagDisplayName
                }
            };
            propTagsInstance.CValues = (uint)propTagsInstance.AulPropTag.Length;
            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!");
            Site.Assert.IsNotNull(rowsOfQueryRows, "PropertyRowSet_r value should not null. The row number is {0}.", rowsOfQueryRows == null ? 0 : rowsOfQueryRows.Value.CRows);
            Site.Assert.AreNotEqual<int>(0, rowsOfQueryRows.Value.ARow.Length, "At least one address book object should be matched.");

            rowValue = rowsOfQueryRows.Value.ARow[0];

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1943
            // The native type of PidTagAddressBookDisplayNamePrintable is PtypString and the client has requested this property with PtypString.
            Site.CaptureRequirementIfAreEqual<uint>(
                (uint)AulProp.PidTagAddressBookDisplayNamePrintable,
                rowValue.LpProps[0].PropTag,
                1943,
                "[In Conversion Rules for String Values Specified by the Server to the Client] [For method NspiQueryRows] If the native type of a property is PtypString and the client has requested that property with the type PtypString, the server MUST return the Unicode representation unmodified.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1959
            // The native type of PidTagDisplayName is PtypString8 and the client has requested this property with PtypString8.
            Site.CaptureRequirementIfAreEqual<uint>(
                (uint)AulProp.PidTagDisplayName,
                rowValue.LpProps[1].PropTag,
                1959,
                "[In Conversion Rules for String Values Specified by the Server to the Client] [For method NspiQueryRows] If the native type of a property is PtypString8 and the client has requested that property with the type PtypString8, the server MUST return the 8-bit character representation unmodified.");

            #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
        }
        public void MSOXNSPI_S02_TC34_NspiGetMatchesStringConversion()
        {
            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.Success, this.Result, "NspiBind should return Success!");
            #endregion

            #region Call NspiGetMatches to request the string properties to be different from their native types.
            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;

            PropertyTagArray_r propTags = new PropertyTagArray_r
            {
                AulPropTag = new uint[]
                {
                    AdapterHelper.ConvertStringToString8((uint)AulProp.PidTagAddressBookDisplayNamePrintable),
                    AdapterHelper.ConvertString8ToString((uint)AulProp.PidTagDisplayName)
                }
            };
            propTags.CValues = (uint)propTags.AulPropTag.Length;
            PropertyTagArray_r? propTagsOfGetMatches = propTags;
            PropertyName_r? propNameOfGetMatches = null;

            PropertyTagArray_r? outMIds;
            PropertyRowSet_r? rowsOfGetMatches;

            stat.SortType = (uint)TableSortOrder.SortTypeDisplayName_RO;
            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(rowsOfGetMatches, "PropertyRowSet_r value should not null. The row number is {0}.", rowsOfGetMatches == null ? 0 : rowsOfGetMatches.Value.CRows);
            Site.Assert.AreNotEqual<int>(0, rowsOfGetMatches.Value.ARow.Length, "At least one address book object should be matched.");

            PropertyRow_r rowValue = rowsOfGetMatches.Value.ARow[0];

            string displayName = System.Text.UnicodeEncoding.Unicode.GetString(rowValue.LpProps[1].Value.LpszW);

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1972: The value of PidTagDisplayName is {0}.", displayName);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1972
            // The field LpszW indicates a single Unicode string value.
            Site.CaptureRequirementIfIsNotNull(
                rowValue.LpProps[1].Value.LpszW,
                1972,
                "[In Conversion Rules for String Values Specified by the Server to the Client] In NspiGetMatches method, String values can be returned in Unicode representation in the output parameter ppRows.");

            string displayNamePrintable = System.Text.UnicodeEncoding.UTF8.GetString(rowValue.LpProps[0].Value.LpszA);

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXNSPI_R1973: The value of PidTagAddressBookDisplayNamePrintable is {0}.", displayNamePrintable);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1973
            // The field LpszA indicates a 8-bit character string value.
            Site.CaptureRequirementIfIsNotNull(
                rowValue.LpProps[0].Value.LpszA,
                1973,
                "[In Conversion Rules for String Values Specified by the Server to the Client] In NspiGetMatches method, String values can be returned in 8-bit character representation in the output parameter ppRows.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1936
            // The native type of PidTagAddressBookDisplayNamePrintable is PtypString and the client has requested this property with PtypString8.
            Site.CaptureRequirementIfAreEqual<uint>(
                AdapterHelper.ConvertStringToString8((uint)AulProp.PidTagAddressBookDisplayNamePrintable),
                rowValue.LpProps[0].PropTag,
                1936,
                "[In Conversion Rules for String Values Specified by the Server to the Client] [For method NspiGetMatches] If the native type of a property is PtypString and the client has requested that property with the type PtypString8, the server MUST convert the Unicode representation to an 8-bit character representation in the code page specified by the CodePage field of the pStat parameter prior to returning the value.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1952
            // The native type of PidTagDisplayName is PtypString8 and the client has requested this property with PtypString.
            Site.CaptureRequirementIfAreEqual<uint>(
                AdapterHelper.ConvertString8ToString((uint)AulProp.PidTagDisplayName),
                rowValue.LpProps[1].PropTag,
                1952,
                "[In Conversion Rules for String Values Specified by the Server to the Client] [For method NspiGetMatches] If the native type of a property is PtypString8 and the client has requested that property with the type PtypString, the server MUST convert the 8-bit character representation to a Unicode representation prior to returning the value.");
            #endregion

            #region Call NspiGetMatches to request the string properties to be the same as their native types.
            propTags = new PropertyTagArray_r
            {
                AulPropTag = new uint[]
                {
                    (uint)AulProp.PidTagAddressBookDisplayNamePrintable,
                    (uint)AulProp.PidTagDisplayName
                }
            };
            propTags.CValues = (uint)propTags.AulPropTag.Length;
            propTagsOfGetMatches = propTags;

            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(rowsOfGetMatches, "PropertyRowSet_r value should not null. The row number is {0}.", rowsOfGetMatches == null ? 0 : rowsOfGetMatches.Value.CRows);
            Site.Assert.AreNotEqual<int>(0, rowsOfGetMatches.Value.ARow.Length, "At least one address book object should be matched.");

            rowValue = rowsOfGetMatches.Value.ARow[0];

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1944
            // The native type of PidTagAddressBookDisplayNamePrintable is PtypString and the client has requested this property with PtypString.
            Site.CaptureRequirementIfAreEqual<uint>(
                (uint)AulProp.PidTagAddressBookDisplayNamePrintable,
                rowValue.LpProps[0].PropTag,
                1944,
                "[In Conversion Rules for String Values Specified by the Server to the Client] [For method NspiGetMatches] If the native type of a property is PtypString and the client has requested that property with the type PtypString, the server MUST return the Unicode representation unmodified.");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1960
            // The native type of PidTagDisplayName is PtypString8 and the client has requested this property with PtypString8.
            Site.CaptureRequirementIfAreEqual<uint>(
                (uint)AulProp.PidTagDisplayName,
                rowValue.LpProps[1].PropTag,
                1960,
                "[In Conversion Rules for String Values Specified by the Server to the Client] [For method NspiGetMatches] If the native type of a property is PtypString8 and the client has requested that property with the type PtypString8, the server MUST return the 8-bit character representation unmodified.");
            #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_S02_TC21_GetMatchesComparedWithNspiQueryRows()
        {
            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 method to restrict a specific table based on the input parameters and return the resultant Explicit Table.
            uint reserved1 = 0;
            uint reserver2 = 0;
            PropertyTagArray_r? proReserved = null;
            uint requested = Constants.GetMatchesRequestedRowNumber;
            PropertyName_r? propNameOfGetMatches = null;

            // 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;

            PropertyTagArray_r propTags = new PropertyTagArray_r
            {
                CValues = 4,
                AulPropTag = new uint[4]
                {
                    (uint)AulProp.PidTagEntryId,
                    (uint)AulProp.PidTagDisplayName,
                    (uint)AulProp.PidTagAddressBookDisplayNamePrintable,
                    (uint)AulProp.PidTagDisplayType
                }
            };
            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 NspiQueryRows method to compare with NspiGetMatches result.
            uint flagsOfQueryRows = (uint)RetrievePropertyFlag.fEphID;
            uint tableCount = outMIds.Value.CValues;
            uint[] table = new uint[outMIds.Value.CValues];
            Array.Copy(outMIds.Value.AulPropTag, table, outMIds.Value.CValues);

            uint count = outMIds.Value.CValues;
            PropertyRowSet_r? rowsOfQueryRows;
            STAT inputStat = stat;
            this.Result = this.ProtocolAdatper.NspiQueryRows(flagsOfQueryRows, ref stat, tableCount, table, count, propTags, out rowsOfQueryRows);
            Site.Assert.AreEqual<ErrorCodeValue>(ErrorCodeValue.Success, this.Result, "NspiQueryRows should return Success!");

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

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1696
            Site.CaptureRequirementIfIsTrue(
                AdapterHelper.AreTwoPropertyRowSetEqual(rowsOfGetMatches, rowsOfQueryRows),
                1696,
                @"[In NspiGetMatches] [Server Processing Rules: Upon receiving message NspiGetMatches, the server MUST process the data from the message subject to the following constraints:] [constraint 18] This PropertyRowSet_r MUST be exactly the same PropertyRowSet_r that would be returned in the ppRows parameter of a call to the NspiQueryRows method with the following parameters:
                The NspiGetMatches parameter hRpc is used as the NspiQueryRows parameter hRpc. 
                The value ""fEphID"" is used as the NspiQueryRows parameter dwFlags.
                The NspiGetMatches output parameter pStat (as modified by the prior constraints) is used as the NspiQueryRows parameter pStat.
                The number of Minimal Entry IDs in the constructed Explicit Table is used as the NspiQueryRows parameter dwETableCount.
                The constructed Explicit Table is used as the NspiQueryRows parameter lpETable. These Minimal Entry IDs are expressed as a simple array of DWORD values rather than as a PropertyTagArray_r value.
                The number of Minimal Entry IDs in the constructed Explicit Table is used as the NspiQueryRows parameter Count.
                The NspiGetMatches parameter proptags is used as the NspiQueryRows parameter proptags.");

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                "Verify MS-OXNSPI_R1165: the SortType of output stat is {0}, the ContainerID of output stat is {1}, the CurrentRec of output stat is {2}, the Delta of output stat is {3}, the NumPos of output stat is {4}, the TotalRecs of output stat is {5}, the CodePage of output stat is {6}, the TemplateLocale of output stat is {7}, the SortLocale of output stat is {8};" +
                "the SortType of inputStat is {9}, the ContainerID of inputStat is {10}, the CurrentRec of inputStat is {11}, the Delta of inputStat is {12}, the NumPos of inputStat is {13}, the TotalRecs of inputStat is {13}, the CodePage of inputStat is {14}, the TemplateLocale of inputStat is {15}, the SortLocale of inputStat is {16}",
                stat.SortType,
                stat.ContainerID,
                stat.CurrentRec,
                stat.Delta,
                stat.NumPos,
                stat.TotalRecs,
                stat.CodePage,
                stat.TemplateLocale,
                stat.SortLocale,
                inputStat.SortType,
                inputStat.ContainerID,
                inputStat.CurrentRec,
                inputStat.Delta,
                inputStat.NumPos,
                inputStat.TotalRecs,
                inputStat.CodePage,
                inputStat.TemplateLocale,
                inputStat.SortLocale);

            // Verify MS-OXNSPI requirement: MS-OXNSPI_R1165
            bool isVerifyR1165 = (stat.SortType == inputStat.SortType)
                                && (stat.ContainerID == inputStat.ContainerID)
                                && (stat.CurrentRec == inputStat.CurrentRec)
                                && (stat.Delta == inputStat.Delta)
                                && (stat.NumPos == inputStat.NumPos)
                                && (stat.TotalRecs == inputStat.TotalRecs)
                                && (stat.CodePage == inputStat.CodePage)
                                && (stat.TemplateLocale == inputStat.TemplateLocale)
                                && (stat.SortLocale == inputStat.SortLocale);

            Site.CaptureRequirementIfIsTrue(
                isVerifyR1165,
                1165,
                @"[In NspiGetMatches] Note that the server MUST NOT modify the return value of 
                the NspiGetMatches method output parameter pStat in any way in the process of constructing the output PropertyRowSet_r.");

            #endregion Capture
            #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
        }