]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/overlays/valsort.c
Merge remote branch 'origin/mdb.master' into OPENLDAP_REL_ENG_2_4
[openldap] / servers / slapd / overlays / valsort.c
index 68ad11035f90944d27f51ccc43c3cedd9bbb63ed..5d89eb0554c776d55c43969d259caf027671023a 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2005 The OpenLDAP Foundation.
+ * Copyright 2005-2012 The OpenLDAP Foundation.
  * Portions copyright 2005 Symas Corporation.
  * All rights reserved.
  *
@@ -51,6 +51,8 @@ typedef struct valsort_info {
        slap_mask_t vi_sort;
 } valsort_info;
 
+static int valsort_cid;
+
 static ConfigDriver valsort_cf_func;
 
 static ConfigTable valsort_cfats[] = {
@@ -76,17 +78,19 @@ static slap_verbmasks sorts[] = {
        { BER_BVC("alpha-ascend"), VALSORT_ASCEND|VALSORT_ALPHA },
        { BER_BVC("alpha-descend"), VALSORT_DESCEND|VALSORT_ALPHA },
        { BER_BVC("numeric-ascend"), VALSORT_ASCEND|VALSORT_NUMERIC },
-       { BER_BVC("numeric-ascend"), VALSORT_DESCEND|VALSORT_NUMERIC },
+       { BER_BVC("numeric-descend"), VALSORT_DESCEND|VALSORT_NUMERIC },
        { BER_BVC("weighted"), VALSORT_WEIGHTED },
        { BER_BVNULL, 0 }
 };
 
+static Syntax *syn_numericString;
+
 static int
 valsort_cf_func(ConfigArgs *c) {
        slap_overinst *on = (slap_overinst *)c->bi;
        valsort_info vitmp, *vi;
        const char *text = NULL;
-       int i;
+       int i, is_numeric;
        struct berval bv = BER_BVNULL;
 
        if ( c->op == SLAP_CONFIG_EMIT ) {
@@ -95,16 +99,17 @@ valsort_cf_func(ConfigArgs *c) {
                        char *ptr;
                        int len;
                        
-                       len = vi->vi_ad->ad_cname.bv_len + 1 + vi->vi_dn.bv_len + 3;
+                       len = vi->vi_ad->ad_cname.bv_len + 1 + vi->vi_dn.bv_len + 2;
                        i = vi->vi_sort;
                        if ( i & VALSORT_WEIGHTED ) {
                                enum_to_verb( sorts, VALSORT_WEIGHTED, &bv2 );
                                len += bv2.bv_len + 1;
                                i ^= VALSORT_WEIGHTED;
                        }
-                       BER_BVZERO( &bv );
-                       enum_to_verb( sorts, i, &bv );
-                       len += bv.bv_len;
+                       if ( i ) {
+                               enum_to_verb( sorts, i, &bv );
+                               len += bv.bv_len + 1;
+                       }
                        bvret.bv_val = ch_malloc( len+1 );
                        bvret.bv_len = len;
 
@@ -117,7 +122,7 @@ valsort_cf_func(ConfigArgs *c) {
                                *ptr++ = ' ';
                                ptr = lutil_strcopy( ptr, bv2.bv_val );
                        }
-                       if ( !BER_BVISNULL( &bv )) {
+                       if ( ) {
                                *ptr++ = ' ';
                                strcpy( ptr, bv.bv_val );
                        }
@@ -127,7 +132,7 @@ valsort_cf_func(ConfigArgs *c) {
                return i;
        } else if ( c->op == LDAP_MOD_DELETE ) {
                if ( c->valx < 0 ) {
-                       for ( vi = on->on_bi.bi_private; vi; vi = c->be->be_private ) {
+                       for ( vi = on->on_bi.bi_private; vi; vi = on->on_bi.bi_private ) {
                                on->on_bi.bi_private = vi->vi_next;
                                ch_free( vi->vi_dn.bv_val );
                                ch_free( vi );
@@ -147,44 +152,54 @@ valsort_cf_func(ConfigArgs *c) {
        vitmp.vi_ad = NULL;
        i = slap_str2ad( c->argv[1], &vitmp.vi_ad, &text );
        if ( i ) {
-               sprintf( c->msg, "<%s> %s", c->argv[0], text );
+               snprintf( c->cr_msg, sizeof( c->cr_msg), "<%s> %s", c->argv[0], text );
                Debug( LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
-                       c->log, c->msg, c->argv[1] );
+                       c->log, c->cr_msg, c->argv[1] );
                return(1);
        }
        if ( is_at_single_value( vitmp.vi_ad->ad_type )) {
-               sprintf( c->msg, "<%s> %s is single-valued, ignoring", c->argv[0],
+               snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> %s is single-valued, ignoring", c->argv[0],
                        vitmp.vi_ad->ad_cname.bv_val );
                Debug( LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
-                       c->log, c->msg, c->argv[1] );
+                       c->log, c->cr_msg, c->argv[1] );
                return(0);
        }
+       is_numeric = ( vitmp.vi_ad->ad_type->sat_syntax == syn_numericString ||
+               vitmp.vi_ad->ad_type->sat_syntax == slap_schema.si_syn_integer ) ? 1
+               : 0;
        ber_str2bv( c->argv[2], 0, 0, &bv );
        i = dnNormalize( 0, NULL, NULL, &bv, &vitmp.vi_dn, NULL );
        if ( i ) {
-               sprintf( c->msg, "<%s> unable to normalize DN", c->argv[0] );
+               snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to normalize DN", c->argv[0] );
                Debug( LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
-                       c->log, c->msg, c->argv[2] );
+                       c->log, c->cr_msg, c->argv[2] );
                return(1);
        }
        i = verb_to_mask( c->argv[3], sorts );
        if ( BER_BVISNULL( &sorts[i].word )) {
-               sprintf( c->msg, "<%s> unrecognized sort type", c->argv[0] );
+               snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unrecognized sort type", c->argv[0] );
                Debug( LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
-                       c->log, c->msg, c->argv[3] );
+                       c->log, c->cr_msg, c->argv[3] );
                return(1);
        }
        vitmp.vi_sort = sorts[i].mask;
        if ( sorts[i].mask == VALSORT_WEIGHTED && c->argc == 5 ) {
                i = verb_to_mask( c->argv[4], sorts );
                if ( BER_BVISNULL( &sorts[i].word )) {
-                       sprintf( c->msg, "<%s> unrecognized sort type", c->argv[0] );
+                       snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unrecognized sort type", c->argv[0] );
                        Debug( LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
-                               c->log, c->msg, c->argv[4] );
+                               c->log, c->cr_msg, c->argv[4] );
                        return(1);
                }
                vitmp.vi_sort |= sorts[i].mask;
        }
+       if (( vitmp.vi_sort & VALSORT_NUMERIC ) && !is_numeric ) {
+               snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> numeric sort specified for non-numeric syntax",
+                       c->argv[0] );
+               Debug( LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
+                       c->log, c->cr_msg, c->argv[1] );
+               return(1);
+       }
        vi = ch_malloc( sizeof(valsort_info) );
        *vi = vitmp;
        vi->vi_next = on->on_bi.bi_private;
@@ -197,7 +212,7 @@ static void
 do_sort( Operation *op, Attribute *a, int beg, int num, slap_mask_t sort )
 {
        int i, j, gotnvals;
-       struct berval tmp, ntmp, *vals, *nvals;
+       struct berval tmp, ntmp, *vals = NULL, *nvals;
 
        gotnvals = (a->a_vals != a->a_nvals );
 
@@ -257,9 +272,14 @@ valsort_response( Operation *op, SlapReply *rs )
        valsort_info *vi;
        Attribute *a;
 
-       /* We only want search responses */
-       if ( rs->sr_type != REP_SEARCH ) return SLAP_CB_CONTINUE;
-
+       /* If this is not a search response, or it is a syncrepl response,
+        * or the valsort control wants raw results, pass thru unmodified.
+        */
+       if ( rs->sr_type != REP_SEARCH ||
+               ( _SCM(op->o_sync) > SLAP_CONTROL_IGNORED ) ||
+               ( op->o_ctrlflag[valsort_cid] & SLAP_CONTROL_DATA0))
+               return SLAP_CB_CONTINUE;
+               
        on = (slap_overinst *) op->o_bd->bd_info;
        vi = on->on_bi.bi_private;
 
@@ -277,16 +297,11 @@ valsort_response( Operation *op, SlapReply *rs )
                a = attr_find( rs->sr_entry->e_attrs, vi->vi_ad );
                if ( !a ) continue;
 
-               if (( rs->sr_flags & ( REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED )) !=
-                       ( REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED )) {
-                       rs->sr_entry = entry_dup( rs->sr_entry );
-                       rs->sr_flags |= REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED;
+               if ( rs_entry2modifiable( op, rs, on )) {
                        a = attr_find( rs->sr_entry->e_attrs, vi->vi_ad );
                }
 
-               /* count values */
-               for ( n = 0; !BER_BVISNULL( &a->a_vals[n] ); n++ );
-
+               n = a->a_numvals;
                if ( vi->vi_sort & VALSORT_WEIGHTED ) {
                        int j, gotnvals;
                        long *index = op->o_tmpalloc( n * sizeof(long), op->o_tmpmemctx );
@@ -294,7 +309,7 @@ valsort_response( Operation *op, SlapReply *rs )
                        gotnvals = (a->a_vals != a->a_nvals );
 
                        for (i=0; i<n; i++) {
-                               char *ptr = strchr( a->a_nvals[i].bv_val, '{' );
+                               char *ptr = ber_bvchr( &a->a_nvals[i], '{' );
                                char *end = NULL;
                                if ( !ptr ) {
                                        Debug(LDAP_DEBUG_TRACE, "weights missing from attr %s "
@@ -319,7 +334,9 @@ valsort_response( Operation *op, SlapReply *rs )
 
                                if ( a->a_vals != a->a_nvals ) {
                                        ptr = a->a_vals[i].bv_val;
-                                       end = strchr( ptr, '}' ) + 1;
+                                       end = ber_bvchr( &a->a_vals[i], '}' );
+                                       assert( end != NULL );
+                                       end++;
                                        for (;*end;)
                                                *ptr++ = *end++;
                                        *ptr = '\0';
@@ -387,7 +404,7 @@ valsort_add( Operation *op, SlapReply *rs )
                if ( !a )
                        continue;
                for (i=0; !BER_BVISNULL( &a->a_vals[i] ); i++) {
-                       ptr = strchr(a->a_vals[i].bv_val, '{' );
+                       ptr = ber_bvchr(&a->a_vals[i], '{' );
                        if ( !ptr ) {
                                Debug(LDAP_DEBUG_TRACE, "weight missing from attribute %s\n",
                                        vi->vi_ad->ad_cname.bv_val, 0, 0);
@@ -425,13 +442,16 @@ valsort_modify( Operation *op, SlapReply *rs )
                if ( !(vi->vi_sort & VALSORT_WEIGHTED ))
                        continue;
                for (ml = op->orm_modlist; ml; ml=ml->sml_next ) {
+                       /* Must be a Delete Attr op, so no values to consider */
+                       if ( !ml->sml_values )
+                               continue;
                        if ( ml->sml_desc == vi->vi_ad )
                                break;
                }
                if ( !ml )
                        continue;
                for (i=0; !BER_BVISNULL( &ml->sml_values[i] ); i++) {
-                       ptr = strchr(ml->sml_values[i].bv_val, '{' );
+                       ptr = ber_bvchr(&ml->sml_values[i], '{' );
                        if ( !ptr ) {
                                Debug(LDAP_DEBUG_TRACE, "weight missing from attribute %s\n",
                                        vi->vi_ad->ad_cname.bv_val, 0, 0);
@@ -452,14 +472,28 @@ valsort_modify( Operation *op, SlapReply *rs )
        return SLAP_CB_CONTINUE;
 }
 
+static int
+valsort_db_open(
+       BackendDB *be,
+       ConfigReply *cr
+)
+{
+       return overlay_register_control( be, LDAP_CONTROL_VALSORT );
+}
+
 static int
 valsort_destroy(
-       BackendDB *be
+       BackendDB *be,
+       ConfigReply *cr
 )
 {
        slap_overinst *on = (slap_overinst *)be->bd_info;
        valsort_info *vi = on->on_bi.bi_private, *next;
 
+#ifdef SLAP_CONFIG_DELETE
+       overlay_unregister_control( be, LDAP_CONTROL_VALSORT );
+#endif /* SLAP_CONFIG_DELETE */
+
        for (; vi; vi = next) {
                next = vi->vi_next;
                ch_free( vi->vi_dn.bv_val );
@@ -469,14 +503,50 @@ valsort_destroy(
        return 0;
 }
 
+static int
+valsort_parseCtrl(
+       Operation *op,
+       SlapReply *rs,
+       LDAPControl *ctrl )
+{
+       ber_tag_t tag;
+       BerElementBuffer berbuf;
+       BerElement *ber = (BerElement *)&berbuf;
+       ber_int_t flag = 0;
+
+       if ( BER_BVISNULL( &ctrl->ldctl_value )) {
+               rs->sr_text = "valSort control value is absent";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+       if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
+               rs->sr_text = "valSort control value is empty";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+       ber_init2( ber, &ctrl->ldctl_value, 0 );
+       if (( tag = ber_scanf( ber, "{b}", &flag )) == LBER_ERROR ) {
+               rs->sr_text = "valSort control: flag decoding error";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+       op->o_ctrlflag[valsort_cid] = ctrl->ldctl_iscritical ?
+               SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL;
+       if ( flag )
+               op->o_ctrlflag[valsort_cid] |= SLAP_CONTROL_DATA0;
+
+       return LDAP_SUCCESS;
+}
+
 static slap_overinst valsort;
 
-int valsort_init()
+int valsort_initialize( void )
 {
-       int i, rc;
+       int rc;
 
        valsort.on_bi.bi_type = "valsort";
        valsort.on_bi.bi_db_destroy = valsort_destroy;
+       valsort.on_bi.bi_db_open = valsort_db_open;
 
        valsort.on_bi.bi_op_add = valsort_add;
        valsort.on_bi.bi_op_modify = valsort_modify;
@@ -485,6 +555,16 @@ int valsort_init()
 
        valsort.on_bi.bi_cf_ocs = valsort_cfocs;
 
+       rc = register_supported_control( LDAP_CONTROL_VALSORT,
+               SLAP_CTRL_SEARCH | SLAP_CTRL_HIDE, NULL, valsort_parseCtrl,
+               &valsort_cid );
+       if ( rc != LDAP_SUCCESS ) {
+               Debug( LDAP_DEBUG_ANY, "Failed to register control %d\n", rc, 0, 0 );
+               return rc;
+       }
+
+       syn_numericString = syn_find( "1.3.6.1.4.1.1466.115.121.1.36" );
+
        rc = config_register_schema( valsort_cfats, valsort_cfocs );
        if ( rc ) return rc;
 
@@ -493,7 +573,7 @@ int valsort_init()
 
 #if SLAPD_OVER_VALSORT == SLAPD_MOD_DYNAMIC
 int init_module( int argc, char *argv[]) {
-       return valsort_init();
+       return valsort_initialize();
 }
 #endif