<!--

Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.

The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.

See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.

-->
<chapter id="csdk-compare"><title>Comparing Attribute Values
With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>comparing attribute values</secondary>
</indexterm><highlights>
<para>This chapter describes how to compare the value of an attribute in an
entry against a specified value.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="bdahc">Functions for Comparing Attribute
Values With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdahd">Performing Synchronous Comparison
Operations With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdahe">Performing Asynchronous Comparison
Operations With Directory SDK for C</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="bdahc"><title>Functions for Comparing Attribute Values With Directory
SDK for C</title>
<para>&DirectorySDKForC; has functions to determine if an attribute contains
a certain string or binary value.</para>
<itemizedlist>
<para>To determine if an attribute contains a certain <emphasis>string</emphasis> value,
call either of the following functions:</para>
<listitem><para>The synchronous <function>ldap_compare_s</function> function</para>
</listitem>
<listitem><para>The asynchronous <function>ldap_compare</function> function</para>
</listitem>
</itemizedlist>
<itemizedlist>
<para>To determine if an attribute contains a certain <emphasis>binary</emphasis> value,
call either of the following functions:</para>
<listitem><para>The synchronous <function>ldap_compare_ext_s</function> function</para>
</listitem>
<listitem><para>The asynchronous <function>ldap_compare_ext</function> function</para>
</listitem>
</itemizedlist>
</sect1>
<sect1 id="bdahd"><title>Performing Synchronous Comparison Operations With
Directory SDK for C</title>
<indexterm>
<primary>synchronous functions</primary>
<secondary>comparison operation</secondary>
</indexterm>
<para>You can wait for the results of the compare operation to complete before
continuing. Call the synchronous <function>ldap_compare_ext_s</function> function
to compare values in <structname>berval</structname> structures or the synchronous <function>
ldap_compare_s</function> function to compare string values. These functions
send a compare request to the server and block work until the server sends
the results of the operation back to your client.</para>
<itemizedlist>
<para>Both functions return one of the following values after the compare
operation completes:</para>
<listitem><para><errorcode>LDAP_COMPARE_TRUE</errorcode> indicates that the
attribute contains the specified value.</para></listitem>
<listitem><para><errorcode>LDAP_COMPARE_FALSE</errorcode> indicates that the
attribute does not contain the specified value.</para></listitem>
</itemizedlist>
<para>An error code indicates that a problem has occurred during the operation.</para>
<para>The following example calls the synchronous <function>ldap_compare_s</function> function
to determine if an entry has the value <literal>bjensen@example.com</literal> in
the <literal>mail</literal> attribute.</para>
<example id="compare-sync-example"><title>Performing a Synchronous Compare
Operation</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
...
#define COMPARE_DN "uid=bjensen,ou=People,dc=example,dc=com"
#define COMPARE_ATTR "mail"
#define COMPARE_VALUE "bjensen@example.com"
...
LDAP      *ld;
char      *matched_msg = NULL, *error_msg = NULL;
int       rc;
...
/* Perform the compare operation. */
rc = ldap_compare_s( ld, COMPARE_DN, COMPARE_ATTR, COMPARE_VALUE );
switch( rc ) {
case LDAP_COMPARE_TRUE:
  printf( "%s has the value %s in the %s attribute.\n", COMPARE_DN,
    COMPARE_VALUE, COMPARE_ATTR );
  break;
case LDAP_COMPARE_FALSE:
  printf( "%s does not have the value %s in the %s attribute.\n",
    COMPARE_DN, COMPARE_VALUE, COMPARE_ATTR );
  break;
default:
  fprintf( stderr, "ldap_compare_s: %s\n", ldap_err2string( rc ) );
  ldap_get_lderrno( ld, &amp;matched_msg, &amp;error_msg );
  if ( error_msg != NULL &amp;&amp; *error_msg != '\0' ) {
    fprintf( stderr, "%s\n", error_msg );
  }
  if ( matched_msg != NULL &amp;&amp; *matched_msg != '\0' ) {
    fprintf( stderr,
      "Part of the DN that matches an existing entry: %s\n",
      matched_msg );
  }
  break;
}
ldap_unbind_s( ld );
...</programlisting>
</example>
<para>The following sample program calls the synchronous <function>ldap_compare_s
</function> function. The sample program uses this function to determine if
a user entry has the value <literal>bjensen@example.com</literal> in the <literal>
mail</literal> attribute.</para>
<example id="compare-sync-full-example"><title>Sample Synchronous Compare
Program</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"

/* Change these as needed. */
#define HOSTNAME "localhost"
#define PORTNUMBER LDAP_PORT
#define COMPARE_DN "uid=bjensen,ou=People,dc=example,dc=com"
#define COMPARE_ATTR "mail"
#define COMPARE_VALUE "bjensen@example.com"
int
main( int argc, char **argv )
{
  LDAP      *ld;
  char      *matched_msg = NULL, *error_msg = NULL;
  int        rc;
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
  if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
    perror( "ldap_init" );
    return( 1 );
  }
/* Bind anonymously to the server. */
  rc = ldap_simple_bind_s( ld, NULL, NULL );
  if ( rc != LDAP_SUCCESS ) {
    fprintf( stderr, "ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
    ldap_get_lderrno( ld, &amp;matched_msg, &amp;error_msg );
    if ( error_msg != NULL &amp;&amp; *error_msg != '\0' ) {
      fprintf( stderr, "%s\n", error_msg );
    }
    if ( matched_msg != NULL &amp;&amp; *matched_msg != '\0' ) {
      fprintf( stderr,
        "Part of the DN that matches an existing entry: %s\n",
        matched_msg );
    }
    ldap_unbind_s( ld );
    return( 1 );
  }
/* Perform the compare operation. */
  rc = ldap_compare_s( ld, COMPARE_DN, COMPARE_ATTR, COMPARE_VALUE );
  switch( rc ) {
  case LDAP_COMPARE_TRUE:
    printf( "%s has the value %s in the %s attribute.\n",
      COMPARE_DN, COMPARE_VALUE, COMPARE_ATTR );
    break;
  case LDAP_COMPARE_FALSE:
    printf( "%s does not have the value %s in the %s attribute.\n",
      COMPARE_DN, COMPARE_VALUE, COMPARE_ATTR );
    break;
  default:
    fprintf( stderr, "ldap_compare_s: %s\n", ldap_err2string( rc ) );
    ldap_get_lderrno( ld, &amp;matched_msg, &amp;error_msg );
    if ( error_msg != NULL &amp;&amp; *error_msg != '\0' ) {
      fprintf( stderr, "%s\n", error_msg );
    }
    if ( matched_msg != NULL &amp;&amp; *matched_msg != '\0' ) {
      fprintf( stderr,
        "Part of the DN that matches an existing entry: %s\n",
        matched_msg );
    }
    break;
  }
  ldap_unbind_s( ld );
  return 0;
}</programlisting>
</example>
</sect1>
<sect1 id="bdahe"><title>Performing Asynchronous Comparison Operations With
Directory SDK for C</title>
<indexterm>
<primary>asynchronous functions</primary>
<secondary>comparison operation</secondary>
</indexterm>
<para>You can perform other work in parallel while waiting for the comparison
to complete. Call the asynchronous <function>ldap_compare_ext</function> function
to compare values in <structname>berval</structname> structures or the asynchronous <function>
ldap_compare</function> function to compare string values. These functions
send a compare request to the server and return an <errorcode>LDAP_SUCCESS</errorcode> result
code if the request was successfully sent, or an LDAP result code if an error
occurred.</para>
<para>Both functions pass back a message ID identifying the compare operation.
To determine whether the server sent a response for this operation to your
client, call the <function>ldap_result</function> function and pass in the
message ID. The <function>ldap_result</function> function uses the message
ID to determine if the server sent the results of the compare operation. The <function>
ldap_result</function> function passes back the results in an <structname>LDAPMessage
</structname> structure. You can call the <function>ldap_parse_result</function> function
to parse the <structname>LDAPMessage</structname> structure to determine if
the operation was successful.</para>
<itemizedlist>
<para>The result code should be one of the following:</para>
<listitem><para><errorcode>LDAP_COMPARE_TRUE</errorcode> indicates that the
attribute contains the specified value.</para></listitem>
<listitem><para><errorcode>LDAP_COMPARE_FALSE</errorcode> indicates that the
attribute does not contain the specified value.</para></listitem>
</itemizedlist>
<para>An error code indicates that a problem occurred during the operation.</para>
<para>The following example calls the asynchronous <function>ldap_compare</function> function
to determine if an entry has the value <literal>bjensen@example.com</literal> in
the <literal>mail</literal> attribute.</para>
<example id="compare-async-example"><title>Performing an Asynchronous Compare
Operation</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
...
#define COMPARE_DN "uid=bjensen,ou=People,dc=example,dc=com"
#define COMPARE_ATTR "mail"
#define COMPARE_VALUE "bjensen@example.com"
...
LDAP      *ld;
LDAPMessage    *res;
LDAPControl    **serverctrls;
char      *matched_msg = NULL, *error_msg = NULL;
char      **referrals;
int        rc, parse_rc, msgid, finished = 0;
struct timeval  zerotime;
zerotime.tv_sec = zerotime.tv_usec = 0L;
...
/* Send the LDAP compare request. */
msgid = ldap_compare( ld, COMPARE_DN, COMPARE_ATTR, COMPARE_VALUE );
if ( msgid &lt; 0 ) {
  fprintf( stderr, "ldap_compare: %s\n", ldap_err2string( rc ) );
  ldap_unbind( ld );
  return( 1 );
}
/* Poll the server for the results of the LDAP compare operation. */
while ( !finished ) {
  rc = ldap_result( ld, msgid, 0, &amp;zerotime, &amp;res );
  switch ( rc ) {

  case -1:
    /* An error occurred. */
    rc = ldap_get_lderrno( ld, NULL, NULL );
    fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
    ldap_unbind( ld );
    return( 1 );

  case 0:
      /* The timeout period specified by zerotime was exceeded, so
         call ldap_result() again and continue to poll for the
        results. */
    break;

  default:
    /* The client has received the results of the
       LDAP compare operation from the server. */
    finished = 1;

    /* Parse the results received from the server.*/
    parse_rc = ldap_parse_result( ld, res, &amp;rc, &amp;matched_msg,
      &amp;error_msg, &amp;referrals, &amp;serverctrls, 1 );
    if ( parse_rc != LDAP_SUCCESS ) {
      fprintf( stderr, "ldap_parse_result: %s\n",
        ldap_err2string( parse_rc ) );
      ldap_unbind( ld );
      return( 1 );
    }

    /* Check the results of the LDAP compare operation. */
    switch ( rc ) {
    case LDAP_COMPARE_TRUE:
      printf( "%s has the value %s in the %s attribute.\n",
        COMPARE_DN, COMPARE_VALUE, COMPARE_ATTR );
      break;
    case LDAP_COMPARE_FALSE:
      printf( "%s does not have the value %s in the %s attribute.\n",
        COMPARE_DN, COMPARE_VALUE, COMPARE_ATTR );
      break;
    default:
      fprintf( stderr, "ldap_compare: %s\n", ldap_err2string( rc ) );
      if ( error_msg != NULL &amp; *error_msg != '\0' ) {
        fprintf( stderr, "%s\n", error_msg );
      }
      if ( matched_msg != NULL &amp;&amp; *matched_msg != '\0' ) {
        fprintf( stderr,
          "Part of the DN that matches an existing entry: %s\n",
          matched_msg );
      }
      break;
    }
  }
}
...</programlisting>
</example>
<para>The following sample program calls the asynchronous <function>ldap_compare</function> function.
The sample program uses this function to determine if a user entry has the
value <literal>bjensen@example.com</literal> in the <literal>mail</literal> attribute.
</para>
<example id="compare-async-full-example"><title>Sample Asynchronous Compare
Program</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
void do_other_work();
int global_counter = 0;
/* Change these as needed. */
#define HOSTNAME "localhost"
#define PORTNUMBER LDAP_PORT
#define COMPARE_DN "uid=bjensen,ou=People,dc=example,dc=com"
#define COMPARE_ATTR "mail"
#define COMPARE_VALUE "bjensen@example.com"
int
main( int argc, char **argv )
{
  LDAP      *ld;
  LDAPMessage    *res;
  LDAPControl    **serverctrls;
  char      *matched_msg = NULL, *error_msg = NULL;
  char      **referrals;
  int        rc, parse_rc, msgid, finished = 0;
  struct timeval  zerotime;
  zerotime.tv_sec = zerotime.tv_usec = 0L;
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
  if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
    perror( "ldap_init" );
    return( 1 );
  }
/* Bind anonymously to the server. */
  rc = ldap_simple_bind_s( ld, NULL, NULL );
  if ( rc != LDAP_SUCCESS ) {
    fprintf( stderr, "ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
    ldap_get_lderrno( ld, NULL, &amp;error_msg );
    if ( error_msg != NULL &amp;&amp; *error_msg != '\0' ) {
      fprintf( stderr, "%s\n", error_msg );
    }
    ldap_unbind_s( ld );
    return( 1 );
  }
  /* Send the LDAP compare request. */
  msgid = ldap_compare( ld, COMPARE_DN, COMPARE_ATTR, COMPARE_VALUE );
  if ( msgid &lt; 0 ) {
    fprintf( stderr, "ldap_compare: %s\n", ldap_err2string( rc ) );
    ldap_unbind( ld );
    return( 1 );
  }
/* Poll the server for the results of the LDAP compare operation. */
  while ( !finished ) {
    rc = ldap_result( ld, msgid, 0, &amp;zerotime, &amp;res );
    switch ( rc ) {
    case -1:
      /* An error occurred. */
      rc = ldap_get_lderrno( ld, NULL, NULL );
      fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
      ldap_unbind( ld );
      return( 1 );
    case 0:
      /* The timeout period specified by zerotime was exceeded.
         This means that your client has not yet received the
         results of the LDAP compare operation.
         Break out of this switch statement, and continue calling
         ldap_result() to poll for the results. */
      break;
    default:
      /* The client has received the results of the
         LDAP compare operation from the server. */
      finished = 1;
      /* Parse the results received from the server. Note the last
         argument is a non-zero value, which indicates that the
         LDAPMessage structure will be freed when done.  (No need
         to call ldap_msgfree().) */
      parse_rc = ldap_parse_result( ld, res, &amp;rc, &amp;matched_msg,
                   &amp;error_msg, &amp;referrals, &amp;serverctrls, 1 );
      if ( parse_rc != LDAP_SUCCESS ) {
        fprintf( stderr,
                 "ldap_parse_result: %s\n", 
                 ldap_err2string( parse_rc ) );
        ldap_unbind( ld );
        return( 1 );
      }
      /* Check the results of the LDAP compare operation. */
      switch ( rc ) {
      case LDAP_COMPARE_TRUE:
        printf( "%s has the value %s in the %s attribute.\n"
          "Counted to %d while waiting for the compare operation.\n",
          COMPARE_DN, COMPARE_VALUE, COMPARE_ATTR, global_counter );
        break;
      case LDAP_COMPARE_FALSE:
        printf( "%s does not have the value %s in the %s attribute.\n"
          "Counted to %d while waiting for the compare operation.\n",
          COMPARE_DN, COMPARE_VALUE, COMPARE_ATTR, global_counter );
        break;
      default:
        fprintf( stderr, "ldap_compare: %s\n", ldap_err2string( rc ) );
        if ( error_msg != NULL &amp; *error_msg != '\0' ) {
          fprintf( stderr, "%s\n", error_msg );
        }
        if ( matched_msg != NULL &amp;&amp; *matched_msg != '\0' ) {
          fprintf( stderr,
            "Part of the DN that matches an existing entry: %s\n",
            matched_msg );
        }
        break;
      }
    }
    /* Do other work while waiting for the results of the
       compare operation. */
    if ( !finished ) {
      do_other_work();
    }
  }
  ldap_unbind( ld );
  return 0;
}
/*
 * Perform other work while polling for results.  This
 * doesn't do anything useful, but it could.
 */
void
do_other_work()
{
    global_counter++;
}</programlisting>
</example>
</sect1>
</chapter>
