Back to index

lightning-sunbird  0.9+nobinonly
sortctrl.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla Communicator client code, released
00015  * March 31, 1998.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 #include "ldap-int.h"
00038 
00039 /* ldap_create_sort_control:
00040 
00041    Parameters are  
00042 
00043    ld              LDAP pointer to the desired connection 
00044 
00045    sortKeyList     an array of sortkeys 
00046 
00047    ctl_iscritical  Indicates whether the control is critical of not. If
00048                    this field is non-zero, the operation will only be car-
00049                    ried out if the control is recognized by the server
00050                    and/or client
00051 
00052    ctrlp           the address of a place to put the constructed control 
00053 */
00054 
00055 int
00056 LDAP_CALL
00057 ldap_create_sort_control (  
00058      LDAP *ld, 
00059      LDAPsortkey **sortKeyList,
00060      const char ctl_iscritical,
00061      LDAPControl **ctrlp   
00062 )
00063 {
00064        BerElement           *ber;
00065        int                         i, rc;
00066 
00067        if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
00068               return( LDAP_PARAM_ERROR );
00069        }
00070 
00071        if ( sortKeyList == NULL || ctrlp == NULL ) {
00072               LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
00073               return ( LDAP_PARAM_ERROR );
00074        }
00075 
00076        /* create a ber package to hold the controlValue */
00077        if ( ( nsldapi_alloc_ber_with_options( ld, &ber ) ) != LDAP_SUCCESS ) {
00078               LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
00079               return( LDAP_NO_MEMORY );
00080        }
00081 
00082        /* encode the start of the sequence of sequences into the ber */
00083        if ( ber_printf( ber, "{" ) == -1 ) {
00084               goto encoding_error_exit;
00085        }
00086 
00087        /* the sort control value will be encoded as a sequence of sequences
00088           which are each encoded as one of the following: {s} or {sts} or {stb} or {ststb} 
00089           since the orderingRule and reverseOrder flag are both optional */
00090        for ( i = 0; sortKeyList[i] != NULL; i++ ) {
00091 
00092               /* encode the attributeType into the ber */
00093               if ( ber_printf( ber, "{s", (sortKeyList[i])->sk_attrtype  )
00094                   == -1 ) {
00095                      goto encoding_error_exit;
00096               }
00097               
00098               /* encode the optional orderingRule into the ber */
00099               if ( (sortKeyList[i])->sk_matchruleoid != NULL ) {
00100                      if ( ber_printf( ber, "ts", LDAP_TAG_SK_MATCHRULE,
00101                          (sortKeyList[i])->sk_matchruleoid )
00102                          == -1 ) {
00103                             goto encoding_error_exit;
00104                      }
00105               } 
00106 
00107               /* Encode the optional reverseOrder flag into the ber. */
00108               /* If the flag is false, it should be absent. */
00109               if ( (sortKeyList[i])->sk_reverseorder ) {
00110                      if ( ber_printf( ber, "tb}", LDAP_TAG_SK_REVERSE,
00111                          (sortKeyList[i])->sk_reverseorder ) == -1 ) {
00112                             goto encoding_error_exit;
00113                      }
00114               } else {
00115                      if ( ber_printf( ber, "}" ) == -1 ) {
00116                             goto encoding_error_exit;
00117                      }
00118               }
00119        }
00120 
00121        /* encode the end of the sequence of sequences into the ber */
00122        if ( ber_printf( ber, "}" ) == -1 ) {
00123               goto encoding_error_exit;
00124        }
00125 
00126        rc = nsldapi_build_control( LDAP_CONTROL_SORTREQUEST, ber, 1,
00127            ctl_iscritical, ctrlp );
00128 
00129        LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
00130        return( rc );
00131 
00132 encoding_error_exit:
00133        LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
00134        ber_free( ber, 1 );
00135        return( LDAP_ENCODING_ERROR );
00136 }
00137 
00138 /* ldap_parse_sort_control:
00139 
00140    Parameters are  
00141 
00142    ld              LDAP pointer to the desired connection 
00143 
00144    ctrlp           An array of controls obtained from calling  
00145                    ldap_parse_result on the set of results returned by 
00146                    the server     
00147 
00148    result          the address of a place to put the result code 
00149 
00150    attribute       the address of a place to put the name of the 
00151                    attribute which cause the operation to fail, optionally 
00152                    returned by the server */
00153 
00154 int
00155 LDAP_CALL
00156 ldap_parse_sort_control (   
00157      LDAP *ld, 
00158      LDAPControl **ctrlp,  
00159      unsigned long *result,
00160      char **attribute
00161 )
00162 {
00163        BerElement *ber;
00164        int i, foundSortControl;
00165        LDAPControl *sortCtrlp;
00166        unsigned long len, tag;
00167        char *attr;
00168 
00169        if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || result == NULL ||
00170               attribute == NULL ) {
00171            return( LDAP_PARAM_ERROR );
00172        }
00173 
00174 
00175        /* find the sortControl in the list of controls if it exists */
00176        if ( ctrlp == NULL ) {
00177               LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
00178               return ( LDAP_CONTROL_NOT_FOUND );
00179        } 
00180        foundSortControl = 0;
00181        for ( i = 0; (( ctrlp[i] != NULL ) && ( !foundSortControl )); i++ ) {
00182               foundSortControl = !strcmp( ctrlp[i]->ldctl_oid, LDAP_CONTROL_SORTRESPONSE );
00183        }
00184        if ( !foundSortControl ) {
00185               LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
00186               return ( LDAP_CONTROL_NOT_FOUND );
00187        } else {
00188               /* let local var point to the sortControl */
00189               sortCtrlp = ctrlp[i-1];                   
00190        }
00191 
00192        /*  allocate a Ber element with the contents of the sort_control's struct berval */
00193        if ( ( ber = ber_init( &sortCtrlp->ldctl_value ) ) == NULL ) {
00194               LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
00195               return( LDAP_NO_MEMORY );
00196        }             
00197 
00198        /* decode the result from the Berelement */
00199        if ( ber_scanf( ber, "{i", result ) == LBER_ERROR ) {
00200               LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
00201               ber_free( ber, 1 );
00202               return( LDAP_DECODING_ERROR );
00203        }
00204 
00205        /* if the server returned one, decode the attribute from the Ber element */
00206        if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SR_ATTRTYPE ) {
00207               if ( ber_scanf( ber, "ta", &tag, &attr ) == LBER_ERROR ) {
00208                      LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
00209                      ber_free( ber, 1 );
00210                      return( LDAP_DECODING_ERROR );
00211               }
00212               *attribute = attr;            
00213        } else {
00214               *attribute = NULL;
00215        }
00216 
00217        if ( ber_scanf( ber, "}" ) == LBER_ERROR ) {
00218               LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
00219               ber_free( ber, 1 );
00220               return( LDAP_DECODING_ERROR );
00221        }
00222 
00223        /* the ber encoding is no longer needed */
00224        ber_free(ber,1);
00225 
00226        return( LDAP_SUCCESS );
00227 }
00228 
00229 /* Routines for the manipulation of string-representations of sort control keylists */
00230 
00231 static int count_tokens(const char *s)
00232 {
00233        int count = 0;
00234        const char *p = s;
00235        int whitespace = 1;
00236        /* Loop along the string counting the number of times we see the
00237         * beginning of non-whitespace. This tells us
00238         * the number of tokens in the string
00239         */
00240        while (*p != '\0') {
00241               if (whitespace) {
00242                      if (!isspace(*p)) {
00243                             whitespace = 0;
00244                             count++;
00245                      }
00246               } else {
00247                      if (isspace(*p)) {
00248                             whitespace = 1;
00249                      }
00250               }
00251               p++;
00252        }
00253        return count;
00254 }
00255 
00256 
00257 static int read_next_token(const char **s,LDAPsortkey **key)
00258 {
00259        char c = 0;
00260        const char *pos = *s;
00261        int retval = 0;
00262        LDAPsortkey *new_key = NULL;
00263 
00264        const char *matchrule_source = NULL;
00265        int matchrule_size = 0;
00266        const char *attrdesc_source = NULL;
00267        int attrdesc_size = 0;
00268        int reverse = 0;
00269 
00270        int state = 0;
00271        
00272        while ( ((c = *pos++) != '\0') && (state != 4) ) {
00273               switch (state) {
00274               case 0:
00275               /* case where we've not seen the beginning of the attr yet */
00276                      /* If we still see whitespace, nothing to do */
00277                      if (!isspace(c)) {
00278                             /* Otherwise, something to look at */
00279                             /* Is it a minus sign ? */
00280                             if ('-' == c) {
00281                                    reverse = 1;
00282                             } else {
00283                                    attrdesc_source = pos - 1;
00284                                    state = 1;
00285                             }
00286                      }
00287                      break;
00288               case 1:
00289               /* case where we've seen the beginning of the attr, but not the end */
00290                      /* Is this char either whitespace or a ';' ? */
00291                      if ( isspace(c) || (':' == c)) {
00292                             attrdesc_size = (pos - attrdesc_source) - 1;
00293                             if (':' == c) {
00294                                    state = 2;
00295                             } else {
00296                                    state = 4;
00297                             }
00298                      } 
00299                      break;
00300               case 2:
00301               /* case where we've seen the end of the attr and want the beginning of match rule */
00302                      if (!isspace(c)) {
00303                             matchrule_source = pos - 1;
00304                             state = 3;
00305                      } else {
00306                             state = 4;
00307                      }
00308                      break;
00309               case 3:
00310               /* case where we've seen the beginning of match rule and want to find the end */
00311                      if (isspace(c)) {
00312                             matchrule_size = (pos - matchrule_source) - 1;
00313                             state = 4;
00314                      }
00315                      break;
00316               default:
00317                      break;
00318               }
00319        }
00320        
00321        if (3 == state) {
00322               /* means we fell off the end of the string looking for the end of the marching rule */
00323               matchrule_size = (pos - matchrule_source) - 1;
00324        }
00325 
00326        if (1 == state) {
00327               /* means we fell of the end of the string looking for the end of the attribute */
00328               attrdesc_size = (pos - attrdesc_source) - 1;
00329        }
00330 
00331        if (NULL == attrdesc_source)  {
00332               /* Didn't find anything */
00333               return -1;
00334        }
00335 
00336        new_key = (LDAPsortkey*)NSLDAPI_MALLOC(sizeof(LDAPsortkey));
00337        if (0 == new_key) {
00338               return LDAP_NO_MEMORY;
00339        }
00340        
00341        /* Allocate the strings */
00342        new_key->sk_attrtype = (char *)NSLDAPI_MALLOC(attrdesc_size + 1);
00343        if (NULL != matchrule_source) {
00344               new_key->sk_matchruleoid = (char *)NSLDAPI_MALLOC(
00345                   matchrule_size + 1);
00346        } else {
00347               new_key->sk_matchruleoid = NULL;
00348        }
00349        /* Copy over the strings */
00350        memcpy(new_key->sk_attrtype,attrdesc_source,attrdesc_size);
00351        *(new_key->sk_attrtype + attrdesc_size) = '\0';
00352        if (NULL != matchrule_source) {
00353               memcpy(new_key->sk_matchruleoid,matchrule_source,matchrule_size);
00354               *(new_key->sk_matchruleoid + matchrule_size) = '\0';
00355        }
00356 
00357        new_key->sk_reverseorder = reverse;
00358 
00359        *s = pos - 1;
00360        *key = new_key;
00361        return retval;
00362 }
00363 
00364 int
00365 LDAP_CALL
00366 ldap_create_sort_keylist (
00367        LDAPsortkey ***sortKeyList,
00368        const char *string_rep
00369 )
00370 {
00371        int count = 0;
00372        LDAPsortkey **pointer_array = NULL;
00373        const char *current_position = NULL;
00374        int retval = 0;
00375        int i = 0;
00376 
00377        /* Figure out how many there are */
00378        if (NULL == string_rep) {
00379               return LDAP_PARAM_ERROR;
00380        }
00381        if (NULL == sortKeyList) {
00382               return LDAP_PARAM_ERROR;
00383        }
00384        count = count_tokens(string_rep);
00385        if (0 == count) {
00386               *sortKeyList = NULL;
00387               return LDAP_PARAM_ERROR;
00388        }
00389        /* Allocate enough memory for the pointers */
00390        pointer_array = (LDAPsortkey**)NSLDAPI_MALLOC(sizeof(LDAPsortkey*)
00391            * (count + 1) );
00392        if (NULL == pointer_array) {
00393               return LDAP_NO_MEMORY;
00394        }
00395        /* Now walk along the string, allocating and filling in the LDAPsearchkey structure */
00396        current_position = string_rep;
00397 
00398        for (i = 0; i < count; i++) {
00399               if (0 != (retval = read_next_token(&current_position,&(pointer_array[i])))) {
00400                      pointer_array[count] = NULL;
00401                      ldap_free_sort_keylist(pointer_array);
00402                      *sortKeyList = NULL;
00403                      return retval;
00404               }
00405        }
00406        pointer_array[count] = NULL;
00407        *sortKeyList = pointer_array;
00408        return LDAP_SUCCESS;
00409 }
00410 
00411 void
00412 LDAP_CALL
00413 ldap_free_sort_keylist (
00414        LDAPsortkey **sortKeyList
00415 )
00416 {
00417        LDAPsortkey *this_one = NULL;
00418        int i = 0;
00419 
00420        if ( NULL == sortKeyList ) {
00421               return;
00422        }
00423 
00424        /* Walk down the list freeing the LDAPsortkey structures */
00425        for (this_one = sortKeyList[0]; this_one ; this_one = sortKeyList[++i]) {
00426               /* Free the strings, if present */
00427               if (NULL != this_one->sk_attrtype) {
00428                      NSLDAPI_FREE(this_one->sk_attrtype);
00429               }
00430               if (NULL != this_one->sk_matchruleoid) {
00431                      NSLDAPI_FREE(this_one->sk_matchruleoid);
00432               }
00433               NSLDAPI_FREE(this_one);
00434        }
00435        /* Free the pointer list */
00436        NSLDAPI_FREE(sortKeyList);
00437 }