<!--

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-filter"><title>Using Filter Configuration Files With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>filter configuration files</secondary>
</indexterm><highlights>
<para>This chapter explains how to use LDAP C API functions to work with filter
configuration files.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="bdafi">Understanding Filter Configuration Files for Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdafq">Loading Filter Configuration Files With Directory SDK for C</olink></para>
</listitem>
<listitem><para><olink targetptr="bdafs">Filter Prefixes and Suffixes for Directory SDK for C</olink></para>
</listitem>
<listitem><para><olink targetptr="bdaft">Freeing Filters From Memory With Directory SDK for C</olink></para>
</listitem>
<listitem><para><olink targetptr="bdafu">Creating Filters Programmatically With Directory SDK for C</olink></para>
</listitem>
</itemizedlist>
</highlights>
<sect1 id="bdafi"><title>Understanding Filter Configuration Files for Directory
SDK for C</title>
<para>Filter configuration files can help simplify the process of selecting
the appropriate filter for a search request. A <firstterm>filter configuration
file</firstterm> contains a list of filters that you can load and use in your
searches. You might be writing a client that allows users to search the directory.
Use different search filters tailored for specific types of search criteria.</para>
<para>For example, if the user wants to search for the email address <literal>bjensen@example.com
</literal>, you might want to use this search filter:</para>
<programlisting>(mail=bjensen@example.com)</programlisting>
<para>Similarly, suppose the search term entered by the user contains numbers,
as in <literal>555-1212</literal>. In this case, you might want to use this
search filter:</para>
<programlisting>(telephoneNumber=555-1212)</programlisting>
<para>Rather than write code to find and select the appropriate filter, you
can include the filters in a filter configuration file. For example, the following
section of a filter configuration file specifies one filter for telephone
numbers and two filters for email addresses. The telephone number filter is
used if the search criteria contain one or more numbers. The email filters
are used if the search criteria contain an at sign, <literal>@</literal>.</para>
<example id="filter-conf-example"><title>Section of Filter Configuration File</title>
<programlisting>"people"
  "^[0-9][0-9-]*$"           " "
  "(telephoneNumber=*%v))"   "phone number ends with"
  "@"    " "  "(mail=%v)"    "email address is"
  "(mail=%v*)"               "email address starts with"</programlisting>
</example>
<para>You should specify the filters in the order that you want the filters
to be used. For example, if you want to apply the <literal>(mail=%v)</literal> filter
before the <literal>(mail=%v*)</literal> filter, make sure that the filters
appear in that order.</para>
<sect2 id="bdafj"><title>Syntax for Filter Configuration Files</title>
<indexterm>
<primary>filter configuration files</primary>
<secondary>syntax</secondary>
</indexterm>
<para>A filter configuration file has the following format. The variables
are discussed in the following sections.</para>
<example id="filter-config-syntax"><title>Syntax for a Filter Configuration
File</title>
<programlisting><replaceable>tag</replaceable>
  <replaceable>pattern1</replaceable>    <replaceable>delimiters</replaceable>    <replaceable>
filter1-1</replaceable>  <replaceable>desc1-1</replaceable>  [<replaceable>scope</replaceable>]
  <replaceable>filter1-2</replaceable>   <replaceable>desc1-2</replaceable>                           [<replaceable>
scope</replaceable>]
  <replaceable>pattern2</replaceable>    <replaceable>delimiters</replaceable>    <replaceable>
filter2-1</replaceable>  <replaceable>desc2-1</replaceable>  [<replaceable>scope</replaceable>]
&hellip;</programlisting>
</example>
<sect3 id="bdafk"><title>Tag for Filter Groups</title>
<para>A <replaceable>tag</replaceable> identifies a group of filters. You
can use different tags to distinguish filters for different types of objects.
For example, you can use one tag to represent filters for person entries,
another tag to represent filters for organization entries, and so on.</para>
<programlisting>"people"
    &hellip; (<replaceable>filters for searching "person" entries</replaceable>) &hellip;
"organization"
    &hellip; (<replaceable>filters for "organization" entries</replaceable>) &hellip;
</programlisting>
<para>When you call functions like <function>ldap_getfirstfilter</function> to
retrieve a filter, you can specify a tag, or part of a tag, as a parameter.
The tag narrows the list of filters that the function can retrieve.</para>
</sect3>
<sect3 id="bdafl"><title>Patterns to Select Filters</title>
<para><replaceable>pattern1</replaceable> and <replaceable>pattern2</replaceable> are
regular expressions used to determine which filter is selected, based on the
search criteria. For example, if you specify <literal>"^[0-9]"</literal> as
the pattern for a filter, the filter is selected for all search criteria that
begin with a number.</para>
<programlisting>"people"
  "^[0-9]"      &hellip;</programlisting>
</sect3>
<sect3 id="bdafm"><title>Delimiters for Fields</title>
<para><replaceable>Delimiters</replaceable> specifies the delimiters used
to distinguish one field from another field within the search criteria. For
example, if the search criteria consist of a city name and a state abbreviation
separated by a comma, specify a comma as the delimiter.</para></sect3>
<sect3 id="bdafn"><title>Filter Lists</title>
<para><replaceable>filter1-1</replaceable>, <replaceable>filter1-2</replaceable>,
and <replaceable>filter2-1</replaceable> are filters. Use <literal>%v</literal> to
represent the search criteria. For example, to search email addresses, use
the filter <literal>(mail=%v)</literal>. During runtime, if the search criteria <literal>
bjensen@example.com</literal> is entered, the filter becomes <literal>(mail=bjensen@example.com)
</literal>.</para>
<para>The search criteria might consist of a number of delimited fields. For
example, the criteria might have a last name, first name format such as <literal>
Jensen, Barbara</literal>. Use <literal>%v1, %v2, &hellip;, %vn</literal> to
represent the different fields within the search criteria as shown here:</para>
<programlisting>"people"
  "^[A-Z]*,"      ","    (&amp;(sn=%v1)(givenName=%v2))</programlisting>
<para>In this example, the delimiter is a comma. The word before the delimiter
replaces <literal>%v1</literal> in the filter. The word after the delimiter
replaces <literal>%v2</literal> in the filter. If the user searches for <literal>
Jensen, Barbara</literal> , the resulting filter is as follows:</para>
<programlisting>(&amp;(sn=Jensen)(givenName=Barbara))</programlisting>
<para>You can also specify ranges of fields. For example, to specify the values
in the first three fields, use <literal>%v1-3</literal>. To specify values
from the third field to the last field, use <literal>%v3-</literal>. To specify
the value in the last field, use <literal>%v$</literal>.</para></sect3>
<sect3 id="bdafo"><title>Descriptions of Filters</title>
<para><replaceable>desc1-1</replaceable>, <replaceable>desc1-2</replaceable>,
and <replaceable>desc2-1</replaceable> are phrases that briefly describe the
filters.</para></sect3>
</sect2>
<sect2 id="bdafp"><title>Filter Parameters</title>
<indexterm>
<primary>search filters</primary>
<secondary>parameters</secondary>
</indexterm>
<para>Filter specifications in the configuration file support the following
parameters:</para>
<variablelist>
<varlistentry><term><literal>%v</literal></term>
<listitem><para>Insert the search criterion as is in place of <literal>%v</literal>.
</para>
<para>For example, if the filter specification is <literal>(mail=%v)</literal>,
entering <literal>bjensen</literal> results in the filter <literal>(mail=bjensen)
</literal>.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>%v$</literal></term>
<listitem><para>Insert the last word of the search criterion as is in place
of <literal>%v</literal>.</para>
<para>For example, if the filter specification is <literal>(sn=%v$)</literal>,
entering <literal>Barbara Jensen</literal> results in the filter <literal>(sn=Jensen)
</literal>.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>%v</literal><replaceable>N</replaceable></term>
<listitem><para>Insert the <replaceable>N</replaceable>th word of the criteria
in place of <literal>%v</literal>, where <replaceable>N</replaceable> is a
single digit between 1 and 9.</para>
<para>For example, if the filter specification is <literal>(sn=%v2)</literal>,
entering <literal>Barbara Jensen</literal> results in the filter <literal>(sn=Jensen)
</literal>.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>%v</literal><replaceable>M</replaceable><literal>-</literal><replaceable>
N</replaceable></term>
<listitem><para>Insert the sequence of the <replaceable>M</replaceable>th
through <replaceable>N</replaceable>th words of the criteria in place of <literal>
%v</literal>. Here, <replaceable>M</replaceable> and <replaceable>N</replaceable> are
single digits between 1 and 9.</para>
<para>For example, if the filter specification is <literal>(cn=%v1-2)</literal>,
entering <literal>Barbara Jensen</literal> results in the filter <literal>(cn=Barbara
Jensen)</literal>.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>%v</literal><replaceable>N</replaceable><literal>-</literal></term>
<listitem><para>Insert the sequence of the <replaceable>N</replaceable>th
through last words of the criteria in place of <literal>%v</literal>. Here, <replaceable>
N</replaceable> is a single digit between 1 and 9.</para>
<para>For example, if the filter specification is <literal>(cn=%v2-)</literal>,
entering <literal>Ms. Barbara Jensen</literal> results in the filter <literal>(cn=Barbara
Jensen)</literal>.</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
</sect1>
<sect1 id="bdafq"><title>Loading Filter Configuration Files With Directory
SDK for C</title>
<indexterm>
<primary>filter configuration files</primary>
<secondary>loading</secondary>
</indexterm><indexterm>
<primary>loading filter configuration files</primary>
</indexterm>
<para>To load a filter configuration file, call the <function>ldap_init_getfilter
</function> function. You can also read the filter configuration file from
a buffer in memory by calling the <function>ldap_init_getfilter_buf</function> function.
Both functions return a pointer to an <structname>LDAPFiltDesc</structname> structure,
which contains information about the filter. If an error occurs, both functions
return <literal>NULL</literal>.</para>
<sect2 id="bdafr"><title>Retrieving Filters</title>
<indexterm>
<primary>filter configuration file</primary>
<secondary>retrieving</secondary>
</indexterm>
<para>After loading a filter configuration file into memory, you can retrieve
filters based on the search criteria. For example, the search criteria might
be an email address, <literal>(bjensen@example.com)</literal>. Have your client
automatically search for this value in the <literal>mail</literal> attribute
of person entries.</para>
<para>To retrieve the first filter that matches the search criteria, call
the <function>ldap_getfirstfilter</function> function. To get the next filter
that matches the search criteria, call the <function>ldap_getnextfilter</function> function.
Both functions return a pointer to an <structname>LDAPFiltInfo</structname> structure,
which contains information about the filter, as shown here.<?Pub Caret></para>
<example id="filter-retrieve-conf-example"><title>Retrieving Configuration
Filters</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
&hellip;
LDAP          *ld;
LDAPMessage   *result, *e;
BerElement    *ber;
char          *a, *dn;
char          **vals;
int i;
LDAPFiltDesc *ldfp;
LDAPFiltInfo *ldfi;
char buf[ 80 ]; /* contains the search criteria */
int found;
&hellip;
/* Load the filter configuration file into an LDAPFiltDesc structure. */
if ( ( ldfp = ldap_init_getfilter( "myfilters.conf" ) ) == NULL ) {
  perror( "Cannot open filter configuration file" );
}

/* Select a filter to use when searching for the value in buf.
Use filters under the "people" tag in the filter configuration file. */
found = 0;
for ( ldfi = ldap_getfirstfilter( ldfp, "people", buf ); ldfi != NULL;
  ldfi = ldap_getnextfilter( ldfp ) ) {

  /* Use the selected filter to search the directory. */
  if ( ldap_search_s( ld, "dc=example,dc=com", ldfi->lfi_scope,
   ldfi->lfi_filter, NULL, 0, &amp;result ) != LDAP_SUCCESS ) {
    ldap_perror( ld, "ldap_search_s" );
    return( 1 );
  } else {

    /* Once a filter gets results back, stop iterating through
    the different filters. */
    if ( ( found = ldap_count_entries( ld, result ) > 0 ) ) {
      break;
    } else {
      ldap_msgfree( result );
    }
  }
}

if ( found == 0 ) {
  printf( "No matching entries found.\n" );
} else {
  printf( "Found %d match%s where %s \"%s\"\n\n", found,
   found == 1 ? "" : "es", ldfi->lfi_desc, buf );
}

ldap_msgfree( result );
ldap_getfilter_free( ldfp );
&hellip;</programlisting>
</example>
<para>Suppose that the search criteria is <literal>bjensen@example.com</literal> and
that the client application finds a single matching entry. Then the application
prints the following output:</para>
<programlisting>Found 1 match where email address is bjensen@example.com</programlisting>
</sect2>
</sect1>
<sect1 id="bdafs"><title>Filter Prefixes and Suffixes for Directory SDK for
C</title>
<indexterm>
<primary>search filters</primary>
<secondary>prefixes</secondary>
</indexterm><indexterm>
<primary>search filters</primary>
<secondary>suffixes</secondary>
</indexterm>
<para>If you need to apply a filter to all searches, add a filter prefix and
suffix to all filters. Do not add the criteria to all filters. The prefix
is automatically added to any filter retrieved through the <function>ldap_getfirstfilter
</function> and <function>ldap_getnextfilter</function> functions. The required
suffix <literal>)</literal> needed to balance the number of parentheses is
also added. For example, suppose you use this filter in a filter configuration
file:</para>
<programlisting>(cn=Babs Jensen)</programlisting>
<para>You can retrieve this filter by using <function>ldap_getfirstfilter</function> or <function>
ldap_getnextfilter</function>. These functions get a filter that constrains
your client searches to person entries for the defined filter:</para>
<programlisting>(&amp;(objectClass=person)(cn=Babs Jensen))</programlisting>
<para>To add a prefix and suffix automatically to all filters retrieved from
the filter configuration file, call the <function>ldap_set_filter_additions</function> function.
The following example adds the prefix <literal>(&amp;(objectClass=person)</literal> and
the suffix <literal>)</literal> to each filter retrieved.</para>
<example id="filter-add-affixes-example"><title>Adding Prefixes and Suffixes
to Filters</title>
<programlisting>#include "ldap.h"
&hellip;
LDAPFiltDesc *lfdp;
char *filter_file = "myfilters.conf";
char *prefix = "(&amp;(objectClass=person)";
char *suffix = ")";
&hellip;
lfdp = ldap_init_getfilter( filter_file );
ldap_setfilteraffixes( lfdp, prefix, suffix );
&hellip;</programlisting>
</example>
</sect1>
<sect1 id="bdaft"><title>Freeing Filters From Memory With Directory SDK for
C</title>
<indexterm>
<primary>search filters</primary>
<secondary>freeing from memory</secondary>
</indexterm><indexterm>
<primary>memory</primary>
<secondary>freeing search filters from</secondary>
</indexterm>
<para>When you complete your search, free the <structname>LDAPFiltDesc</structname> structure
from memory. To free <structname>LDAPFiltDesc</structname>, call the <function>ldap_getfilter_free
</function> function as shown here. </para>
<example id="filter-free-example"><title>Freeing Filters From Memory</title>
<programlisting>#include "ldap.h"
&hellip;
LDAPFiltDesc *lfdp;
char *filter_file = "myfilters.conf";
&hellip;
/* Read the filter configuration file into an LDAPFiltDesc structure. */
lfdp = ldap_init_getfilter( filter_file );
&hellip;
/* Retrieve filters and perform searches. */
&hellip;
/* Free the configuration file (the LDAPFiltDesc structure). */
ldap_getfilter_free( lfdp );
&hellip;</programlisting>
</example>
</sect1>
<sect1 id="bdafu"><title>Creating Filters Programmatically With Directory
SDK for C</title>
<indexterm>
<primary>search filters</primary>
<secondary>creating programmatically</secondary>
</indexterm>
<para>You can build your own filters by calling the <function>ldap_create_filter</function> function.
The following example builds the filter <literal>(mail=bjensen@example.com)</literal>.
</para>
<example id="filter-create-example"><title>Creating Filters</title>
<programlisting>char buf[LDAP_FILT_MAXSIZ];
char *pattern = "(%a=%v);
char *attr = "mail";
char *value = "bjensen@example.com";
&hellip;
ldap_create_filter( buf, LDAP_FILT_MAXSIZ, pattern, NULL, NULL, attr,
    value, NULL );
&hellip;</programlisting>
</example>
</sect1>
</chapter>
