+ /* Isolate how many words there are. There will be a key for each */
+ for( count = 0,c = val->bv_val; *c; c++) {
+ len = strcspn(c, SLAPD_APPROX_DELIMITER);
+ if( len >= SLAPD_APPROX_WORDLEN ) count++;
+ c+= len;
+ if (*c == '\0') break;
+ *c = '\0';
+ }
+
+ /* Allocate storage for new keys */
+ keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
+
+ /* Get a phonetic copy of each word */
+ for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
+ len = strlen(c);
+ if( len < SLAPD_APPROX_WORDLEN ) continue;
+ ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
+ i++;
+ }
+
+ ber_bvfree( val );
+
+ keys[count].bv_val = NULL;
+ *keysp = keys;
+
+ return LDAP_SUCCESS;
+}
+
+
+#else
+/* No other form of Approximate Matching is defined */
+
+static int
+approxMatch(
+ int *matchp,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *value,
+ void *assertedValue )
+{
+ char *vapprox, *avapprox;
+ char *s, *t;
+
+ /* Yes, this is necessary */
+ s = UTF8normalize( value, UTF8_NOCASEFOLD );
+ if( s == NULL ) {
+ *matchp = 1;
+ return LDAP_SUCCESS;
+ }
+
+ /* Yes, this is necessary */
+ t = UTF8normalize( ((struct berval *)assertedValue),
+ UTF8_NOCASEFOLD );
+ if( t == NULL ) {
+ free( s );
+ *matchp = -1;
+ return LDAP_SUCCESS;
+ }
+
+ vapprox = phonetic( strip8bitChars( s ) );
+ avapprox = phonetic( strip8bitChars( t ) );
+
+ free( s );
+ free( t );
+
+ *matchp = strcmp( vapprox, avapprox );
+
+ ch_free( vapprox );
+ ch_free( avapprox );
+
+ return LDAP_SUCCESS;
+}
+
+static int
+approxIndexer(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ BerVarray values,
+ BerVarray *keysp )
+{
+ int i;
+ BerVarray *keys;
+ char *s;
+
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ /* empty - just count them */
+ }
+
+ /* we should have at least one value at this point */
+ assert( i > 0 );
+
+ keys = (struct berval *)ch_malloc( sizeof( struct berval ) * (i+1) );
+
+ /* Copy each value and run it through phonetic() */
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ /* Yes, this is necessary */
+ s = UTF8normalize( &values[i], UTF8_NOCASEFOLD );
+
+ /* strip 8-bit chars and run through phonetic() */
+ ber_str2bv( phonetic( strip8bitChars( s ) ), 0, 0, &keys[i] );
+ free( s );
+ }
+ keys[i].bv_val = NULL;
+
+ *keysp = keys;
+ return LDAP_SUCCESS;
+}
+
+
+static int
+approxFilter(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ void * assertValue,
+ BerVarray *keysp )
+{
+ BerVarray keys;
+ char *s;
+
+ keys = (struct berval *)ch_malloc( sizeof( struct berval * ) * 2 );
+
+ /* Yes, this is necessary */
+ s = UTF8normalize( ((struct berval *)assertValue),
+ UTF8_NOCASEFOLD );
+ if( s == NULL ) {
+ keys[0] = NULL;
+ } else {
+ /* strip 8-bit chars and run through phonetic() */
+ keys[0] = ber_bvstr( phonetic( strip8bitChars( s ) ) );
+ free( s );
+ keys[1] = NULL;
+ }
+
+ *keysp = keys;
+ return LDAP_SUCCESS;
+}
+#endif
+
+
+static int
+caseExactMatch(
+ int *matchp,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *value,
+ void *assertedValue )
+{
+ *matchp = UTF8bvnormcmp( value,
+ (struct berval *) assertedValue,
+ LDAP_UTF8_NOCASEFOLD );
+ return LDAP_SUCCESS;
+}
+
+static int
+caseExactIgnoreSubstringsMatch(
+ int *matchp,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *value,
+ void *assertedValue )
+{
+ int match = 0;
+ SubstringsAssertion *sub = NULL;
+ struct berval left = { 0, NULL };
+ int i;
+ ber_len_t inlen=0;
+ char *nav = NULL;
+ unsigned casefold;
+
+ casefold = ( mr != caseExactSubstringsMatchingRule )
+ ? LDAP_UTF8_CASEFOLD : LDAP_UTF8_NOCASEFOLD;
+
+ if ( UTF8bvnormalize( value, &left, casefold ) == NULL ) {
+ match = 1;
+ goto done;
+ }
+ nav = left.bv_val;
+
+ sub = UTF8SubstringsassertionNormalize( assertedValue, casefold );
+ if( sub == NULL ) {
+ match = -1;
+ goto done;
+ }
+
+ /* Add up asserted input length */
+ if( sub->sa_initial.bv_val ) {
+ inlen += sub->sa_initial.bv_len;
+ }
+ if( sub->sa_any ) {
+ for(i=0; sub->sa_any[i].bv_val != NULL; i++) {
+ inlen += sub->sa_any[i].bv_len;
+ }
+ }
+ if( sub->sa_final.bv_val ) {
+ inlen += sub->sa_final.bv_len;
+ }
+
+ if( sub->sa_initial.bv_val ) {
+ if( inlen > left.bv_len ) {
+ match = 1;
+ goto done;
+ }
+
+ match = memcmp( sub->sa_initial.bv_val, left.bv_val,
+ sub->sa_initial.bv_len );
+
+ if( match != 0 ) {
+ goto done;
+ }
+
+ left.bv_val += sub->sa_initial.bv_len;
+ left.bv_len -= sub->sa_initial.bv_len;
+ inlen -= sub->sa_initial.bv_len;
+ }
+
+ if( sub->sa_final.bv_val ) {
+ if( inlen > left.bv_len ) {
+ match = 1;
+ goto done;
+ }
+
+ match = memcmp( sub->sa_final.bv_val,
+ &left.bv_val[left.bv_len - sub->sa_final.bv_len],
+ sub->sa_final.bv_len );
+
+ if( match != 0 ) {
+ goto done;
+ }
+
+ left.bv_len -= sub->sa_final.bv_len;
+ inlen -= sub->sa_final.bv_len;
+ }
+
+ if( sub->sa_any ) {
+ for(i=0; sub->sa_any[i].bv_val; i++) {
+ ber_len_t idx;
+ char *p;
+
+retry:
+ if( inlen > left.bv_len ) {
+ /* not enough length */
+ match = 1;
+ goto done;
+ }
+
+ if( sub->sa_any[i].bv_len == 0 ) {
+ continue;
+ }
+
+ p = ber_bvchr( &left, *sub->sa_any[i].bv_val );
+ if ( p == NULL ) {
+ match = 1;
+ goto done;
+ }
+
+ idx = p - left.bv_val;
+
+ if( idx >= left.bv_len ) {
+ /* this shouldn't happen */
+ free( nav );
+ if ( sub->sa_final.bv_val )
+ ch_free( sub->sa_final.bv_val );
+ if ( sub->sa_any )
+ ber_bvarray_free( sub->sa_any );
+ if ( sub->sa_initial.bv_val )
+ ch_free( sub->sa_initial.bv_val );
+ ch_free( sub );
+ return LDAP_OTHER;
+ }
+
+ left.bv_val = p;
+ left.bv_len -= idx;
+
+ if( sub->sa_any[i].bv_len > left.bv_len ) {
+ /* not enough left */
+ match = 1;
+ goto done;
+ }
+
+ match = memcmp( left.bv_val,
+ sub->sa_any[i].bv_val,
+ sub->sa_any[i].bv_len );
+
+ if( match != 0 ) {
+ left.bv_val++;
+ left.bv_len--;
+ goto retry;
+ }
+
+ left.bv_val += sub->sa_any[i].bv_len;
+ left.bv_len -= sub->sa_any[i].bv_len;
+ inlen -= sub->sa_any[i].bv_len;
+ }
+ }
+
+done:
+ free( nav );
+ if( sub != NULL ) {
+ if ( sub->sa_final.bv_val ) free( sub->sa_final.bv_val );
+ if ( sub->sa_any ) ber_bvarray_free( sub->sa_any );
+ if ( sub->sa_initial.bv_val ) free( sub->sa_initial.bv_val );
+ ch_free( sub );
+ }
+ *matchp = match;
+ return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+static int caseExactIgnoreIndexer(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ BerVarray values,
+ BerVarray *keysp )
+{
+ int i;
+ unsigned casefold;
+ size_t slen, mlen;
+ BerVarray keys;
+ HASH_CONTEXT HASHcontext;
+ unsigned char HASHdigest[HASH_BYTES];
+ struct berval digest;
+ digest.bv_val = HASHdigest;
+ digest.bv_len = sizeof(HASHdigest);
+
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ /* empty - just count them */
+ }
+
+ /* we should have at least one value at this point */
+ assert( i > 0 );
+
+ keys = ch_malloc( sizeof( struct berval ) * (i+1) );
+
+ slen = syntax->ssyn_oidlen;
+ mlen = mr->smr_oidlen;
+
+ casefold = ( mr != caseExactMatchingRule )
+ ? LDAP_UTF8_CASEFOLD : LDAP_UTF8_NOCASEFOLD;
+
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ struct berval value;
+ UTF8bvnormalize( &values[i], &value, casefold );
+
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ value.bv_val, value.bv_len );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ free( value.bv_val );
+
+ ber_dupbv( &keys[i], &digest );
+ }
+
+ keys[i].bv_val = NULL;
+ *keysp = keys;
+ return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+static int caseExactIgnoreFilter(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ void * assertValue,
+ BerVarray *keysp )
+{
+ unsigned casefold;
+ size_t slen, mlen;
+ BerVarray keys;
+ HASH_CONTEXT HASHcontext;
+ unsigned char HASHdigest[HASH_BYTES];
+ struct berval value = { 0, NULL };
+ struct berval digest;
+
+ digest.bv_val = HASHdigest;
+ digest.bv_len = sizeof(HASHdigest);
+
+ slen = syntax->ssyn_oidlen;
+ mlen = mr->smr_oidlen;
+
+ casefold = ( mr != caseExactMatchingRule )
+ ? LDAP_UTF8_CASEFOLD : LDAP_UTF8_NOCASEFOLD;
+
+ UTF8bvnormalize( (struct berval *) assertValue, &value, casefold );
+ /* This usually happens if filter contains bad UTF8 */
+ if( value.bv_val == NULL ) {
+ keys = ch_malloc( sizeof( struct berval ) );
+ keys[0].bv_val = NULL;
+ return LDAP_SUCCESS;
+ }
+
+ keys = ch_malloc( sizeof( struct berval ) * 2 );
+
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ value.bv_val, value.bv_len );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( keys, &digest );
+ keys[1].bv_val = NULL;
+
+ free( value.bv_val );
+
+ *keysp = keys;
+ return LDAP_SUCCESS;
+}
+
+/* Substrings Index generation function */
+static int caseExactIgnoreSubstringsIndexer(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ BerVarray values,
+ BerVarray *keysp )
+{
+ unsigned casefold;
+ ber_len_t i, nkeys;
+ size_t slen, mlen;
+ BerVarray keys;
+ BerVarray nvalues;
+
+ HASH_CONTEXT HASHcontext;
+ unsigned char HASHdigest[HASH_BYTES];
+ struct berval digest;
+ digest.bv_val = HASHdigest;
+ digest.bv_len = sizeof(HASHdigest);
+
+ nkeys=0;
+
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ /* empty - just count them */
+ }
+
+ /* we should have at least one value at this point */
+ assert( i > 0 );
+
+ casefold = ( mr != caseExactSubstringsMatchingRule )
+ ? LDAP_UTF8_CASEFOLD : LDAP_UTF8_NOCASEFOLD;
+
+ nvalues = ch_malloc( sizeof( struct berval ) * (i+1) );
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ UTF8bvnormalize( &values[i], &nvalues[i], casefold );
+ }
+ nvalues[i].bv_val = NULL;
+ values = nvalues;
+
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ /* count number of indices to generate */
+ if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) {
+ continue;
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
+ if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+ nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
+ ( SLAP_INDEX_SUBSTR_MINLEN - 1);
+ } else {
+ nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
+ }
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_ANY ) {
+ if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+ nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
+ }
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
+ if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+ nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
+ ( SLAP_INDEX_SUBSTR_MINLEN - 1);
+ } else {
+ nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
+ }
+ }
+ }
+
+ if( nkeys == 0 ) {
+ /* no keys to generate */
+ *keysp = NULL;
+ ber_bvarray_free( nvalues );
+ return LDAP_SUCCESS;
+ }
+
+ keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) );
+
+ slen = syntax->ssyn_oidlen;
+ mlen = mr->smr_oidlen;
+
+ nkeys=0;
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ ber_len_t j,max;
+
+ if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue;
+
+ if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
+ ( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) )
+ {
+ char pre = SLAP_INDEX_SUBSTR_PREFIX;
+ max = values[i].bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1);
+
+ for( j=0; j<max; j++ ) {
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+
+ HASH_Update( &HASHcontext,
+ &pre, sizeof( pre ) );
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ &values[i].bv_val[j],
+ SLAP_INDEX_SUBSTR_MAXLEN );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[nkeys++], &digest );
+ }
+ }
+
+ max = SLAP_INDEX_SUBSTR_MAXLEN < values[i].bv_len
+ ? SLAP_INDEX_SUBSTR_MAXLEN : values[i].bv_len;
+
+ for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) {
+ char pre;
+
+ if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
+ pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ &pre, sizeof( pre ) );
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ values[i].bv_val, j );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[nkeys++], &digest );
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
+ pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ &pre, sizeof( pre ) );
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ &values[i].bv_val[values[i].bv_len-j], j );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[nkeys++], &digest );
+ }
+
+ }
+
+ }
+
+ if( nkeys > 0 ) {
+ keys[nkeys].bv_val = NULL;
+ *keysp = keys;
+ } else {
+ ch_free( keys );
+ *keysp = NULL;
+ }
+
+ ber_bvarray_free( nvalues );
+
+ return LDAP_SUCCESS;
+}
+
+static int caseExactIgnoreSubstringsFilter(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ void * assertValue,
+ BerVarray *keysp )
+{
+ SubstringsAssertion *sa;
+ char pre;
+ unsigned casefold;
+ ber_len_t nkeys = 0;
+ size_t slen, mlen, klen;
+ BerVarray keys;
+ HASH_CONTEXT HASHcontext;
+ unsigned char HASHdigest[HASH_BYTES];
+ struct berval *value;
+ struct berval digest;
+
+ casefold = ( mr != caseExactSubstringsMatchingRule )
+ ? LDAP_UTF8_CASEFOLD : LDAP_UTF8_NOCASEFOLD;
+
+ sa = UTF8SubstringsassertionNormalize( assertValue, casefold );
+ if( sa == NULL ) {
+ *keysp = NULL;
+ return LDAP_SUCCESS;
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial.bv_val != NULL &&
+ sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+ {
+ nkeys++;
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
+ ber_len_t i;
+ for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
+ if( sa->sa_any[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+ /* don't bother accounting for stepping */
+ nkeys += sa->sa_any[i].bv_len -
+ ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
+ }
+ }
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final.bv_val != NULL &&
+ sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+ {
+ nkeys++;
+ }
+
+ if( nkeys == 0 ) {
+ if ( sa->sa_final.bv_val ) free( sa->sa_final.bv_val );
+ if ( sa->sa_any ) ber_bvarray_free( sa->sa_any );
+ if ( sa->sa_initial.bv_val ) free( sa->sa_initial.bv_val );
+ ch_free( sa );
+ *keysp = NULL;
+ return LDAP_SUCCESS;
+ }
+
+ digest.bv_val = HASHdigest;
+ digest.bv_len = sizeof(HASHdigest);
+
+ slen = syntax->ssyn_oidlen;
+ mlen = mr->smr_oidlen;
+
+ keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) );
+ nkeys = 0;
+
+ if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial.bv_val != NULL &&
+ sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+ {
+ pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
+ value = &sa->sa_initial;
+
+ klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
+ ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
+
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ &pre, sizeof( pre ) );
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ value->bv_val, klen );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[nkeys++], &digest );
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
+ ber_len_t i, j;
+ pre = SLAP_INDEX_SUBSTR_PREFIX;
+ klen = SLAP_INDEX_SUBSTR_MAXLEN;
+
+ for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
+ if( sa->sa_any[i].bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) {
+ continue;
+ }
+
+ value = &sa->sa_any[i];
+
+ for(j=0;
+ j <= value->bv_len - SLAP_INDEX_SUBSTR_MAXLEN;
+ j += SLAP_INDEX_SUBSTR_STEP )
+ {
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ &pre, sizeof( pre ) );
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ &value->bv_val[j], klen );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[nkeys++], &digest );
+ }
+
+ }
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final.bv_val != NULL &&
+ sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+ {
+ pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
+ value = &sa->sa_final;
+
+ klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
+ ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
+
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ &pre, sizeof( pre ) );
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ &value->bv_val[value->bv_len-klen], klen );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[nkeys++], &digest );
+ }
+
+ if( nkeys > 0 ) {
+ keys[nkeys].bv_val = NULL;
+ *keysp = keys;
+ } else {
+ ch_free( keys );
+ *keysp = NULL;
+ }
+ if ( sa->sa_final.bv_val ) free( sa->sa_final.bv_val );
+ if ( sa->sa_any ) ber_bvarray_free( sa->sa_any );
+ if ( sa->sa_initial.bv_val ) free( sa->sa_initial.bv_val );
+ ch_free( sa );
+
+ return LDAP_SUCCESS;
+}
+
+static int
+caseIgnoreMatch(
+ int *matchp,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *value,
+ void *assertedValue )
+{
+ *matchp = UTF8bvnormcmp( value,
+ (struct berval *) assertedValue,
+ LDAP_UTF8_CASEFOLD );
+ return LDAP_SUCCESS;
+}
+
+/* Remove all spaces and '-' characters */
+static int
+telephoneNumberNormalize(
+ Syntax *syntax,
+ struct berval *val,
+ struct berval *normalized )
+{
+ char *p, *q;
+
+ /* validator should have refused an empty string */
+ assert( val->bv_len );
+
+ q = normalized->bv_val = ch_malloc( val->bv_len + 1 );
+
+ for( p = val->bv_val; *p; p++ ) {
+ if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
+ *q++ = *p;
+ }
+ }
+ *q = '\0';
+
+ normalized->bv_len = q - normalized->bv_val;
+
+ if( normalized->bv_len == 0 ) {
+ free( normalized->bv_val );
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+oidValidate(
+ Syntax *syntax,
+ struct berval *val )
+{
+ ber_len_t i;
+
+ if( val->bv_len == 0 ) {
+ /* disallow empty strings */
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ if( OID_LEADCHAR(val->bv_val[0]) ) {
+ int dot = 0;
+ for(i=1; i < val->bv_len; i++) {
+ if( OID_SEPARATOR( val->bv_val[i] ) ) {
+ if( dot++ ) return 1;
+ } else if ( OID_CHAR( val->bv_val[i] ) ) {
+ dot = 0;
+ } else {
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+
+ return !dot ? LDAP_SUCCESS : LDAP_INVALID_SYNTAX;
+
+ } else if( DESC_LEADCHAR(val->bv_val[0]) ) {
+ for(i=1; i < val->bv_len; i++) {
+ if( !DESC_CHAR(val->bv_val[i] ) ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+
+ return LDAP_SUCCESS;
+ }
+
+ return LDAP_INVALID_SYNTAX;
+}
+
+static int
+integerMatch(
+ int *matchp,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *value,
+ void *assertedValue )
+{
+ char *v, *av;
+ int vsign = 1, avsign = 1; /* default sign = '+' */
+ struct berval *asserted;
+ ber_len_t vlen, avlen;
+ int match;
+
+ /* Skip leading space/sign/zeroes, and get the sign of the *value number */
+ v = value->bv_val;
+ vlen = value->bv_len;
+ if( mr == integerFirstComponentMatchingRule ) {
+ char *tmp = memchr( v, '$', vlen );
+ if( tmp )
+ vlen = tmp - v;
+ while( vlen && ASCII_SPACE( v[vlen-1] ))
+ vlen--;
+ }
+ for( ; vlen && ( *v < '1' || '9' < *v ); v++, vlen-- ) /* ANSI 2.2.1 */
+ if( *v == '-' )
+ vsign = -1;
+ if( vlen == 0 )
+ vsign = 0;
+
+ /* Do the same with the *assertedValue number */
+ asserted = (struct berval *) assertedValue;
+ av = asserted->bv_val;
+ avlen = asserted->bv_len;
+ for( ; avlen && ( *av < '1' || '9' < *av ); av++, avlen-- )
+ if( *av == '-' )
+ avsign = -1;
+ if( avlen == 0 )
+ avsign = 0;
+
+ match = vsign - avsign;
+ if( match == 0 ) {
+ match = (vlen != avlen
+ ? ( vlen < avlen ? -1 : 1 )
+ : memcmp( v, av, vlen ));
+ if( vsign < 0 )
+ match = -match;
+ }
+
+ *matchp = match;
+ return LDAP_SUCCESS;
+}
+
+static int
+integerValidate(
+ Syntax *syntax,
+ struct berval *val )
+{
+ ber_len_t i;
+
+ if( !val->bv_len ) return LDAP_INVALID_SYNTAX;
+
+ if(( val->bv_val[0] == '+' ) || ( val->bv_val[0] == '-' )) {
+ if( val->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
+ } else if( !ASCII_DIGIT(val->bv_val[0]) ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ for( i=1; i < val->bv_len; i++ ) {
+ if( !ASCII_DIGIT(val->bv_val[i]) ) return LDAP_INVALID_SYNTAX;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+integerNormalize(
+ Syntax *syntax,
+ struct berval *val,
+ struct berval *normalized )
+{
+ char *p;
+ int negative=0;
+ ber_len_t len;
+
+
+ p = val->bv_val;
+ len = val->bv_len;
+
+ /* Ignore leading spaces */
+ while ( len && ( *p == ' ' )) {
+ p++;
+ len--;
+ }
+
+ /* save sign */
+ if( len ) {
+ negative = ( *p == '-' );
+ if(( *p == '-' ) || ( *p == '+' )) {
+ p++;
+ len--;
+ }
+ }
+
+ /* Ignore leading zeros */
+ while ( len && ( *p == '0' )) {
+ p++;
+ len--;
+ }
+
+ /* If there are no non-zero digits left, the number is zero, otherwise
+ allocate space for the number and copy it into the buffer */
+ if( len == 0 ) {
+ normalized->bv_val = ch_strdup("0");
+ normalized->bv_len = 1;
+ }
+ else {
+ normalized->bv_len = len+negative;
+ normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
+ if( negative ) {
+ normalized->bv_val[0] = '-';
+ }
+ AC_MEMCPY( normalized->bv_val + negative, p, len );
+ normalized->bv_val[len+negative] = '\0';
+ }
+
+ return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+static int integerIndexer(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ BerVarray values,
+ BerVarray *keysp )
+{
+ int i;
+ size_t slen, mlen;
+ BerVarray keys;
+ HASH_CONTEXT HASHcontext;
+ unsigned char HASHdigest[HASH_BYTES];
+ struct berval digest;
+ digest.bv_val = HASHdigest;
+ digest.bv_len = sizeof(HASHdigest);
+
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ /* empty - just count them */
+ }
+
+ /* we should have at least one value at this point */
+ assert( i > 0 );
+
+ keys = ch_malloc( sizeof( struct berval ) * (i+1) );
+
+ slen = syntax->ssyn_oidlen;
+ mlen = mr->smr_oidlen;
+
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ struct berval norm;
+ integerNormalize( syntax, &values[i], &norm );
+
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ norm.bv_val, norm.bv_len );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[i], &digest );
+ ch_free( norm.bv_val );
+ }
+
+ keys[i].bv_val = NULL;
+ *keysp = keys;
+ return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+static int integerFilter(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ void * assertValue,
+ BerVarray *keysp )
+{
+ size_t slen, mlen;
+ BerVarray keys;
+ HASH_CONTEXT HASHcontext;
+ unsigned char HASHdigest[HASH_BYTES];
+ struct berval norm;
+ struct berval digest;
+ digest.bv_val = HASHdigest;
+ digest.bv_len = sizeof(HASHdigest);
+
+ slen = syntax->ssyn_oidlen;
+ mlen = mr->smr_oidlen;
+
+ integerNormalize( syntax, assertValue, &norm );
+
+ keys = ch_malloc( sizeof( struct berval ) * 2 );
+
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ norm.bv_val, norm.bv_len );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[0], &digest );
+ keys[1].bv_val = NULL;
+ ch_free( norm.bv_val );
+
+ *keysp = keys;
+ return LDAP_SUCCESS;
+}
+
+
+static int
+countryStringValidate(
+ Syntax *syntax,
+ struct berval *val )
+{
+ if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;