Back to index

lightning-sunbird  0.9+nobinonly
getvalues.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 /*
00038  *  Copyright (c) 1990 Regents of the University of Michigan.
00039  *  All rights reserved.
00040  */
00041 /*
00042  *  getvalues.c
00043  */
00044 
00045 #if 0
00046 #ifndef lint 
00047 static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
00048 #endif
00049 #endif
00050 
00051 #include "ldap-int.h"
00052 
00053 
00054 static void **
00055 internal_ldap_get_values( LDAP *ld, LDAPMessage *entry, const char *target,
00056        int lencall )
00057 {
00058        struct berelement    ber;
00059        char                  *attr;
00060        int                          rc;
00061        void                     **vals;
00062 
00063        LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_values\n", 0, 0, 0 );
00064 
00065        if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
00066               return( NULL );      /* punt */
00067        }
00068        if ( target == NULL ||
00069            !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
00070               LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
00071               return( NULL );
00072        }
00073 
00074        ber = *entry->lm_ber;
00075 
00076        /* skip sequence, dn, sequence of, and snag the first attr */
00077        if ( ber_scanf( &ber, "{x{{a", &attr ) == LBER_ERROR ) {
00078               LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
00079               return( NULL );
00080        }
00081 
00082        rc = strcasecmp( (char *)target, attr );
00083        NSLDAPI_FREE( attr );
00084        if ( rc != 0 ) {
00085               while ( 1 ) {
00086                      if ( ber_scanf( &ber, "x}{a", &attr ) == LBER_ERROR ) {
00087                             LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR,
00088                                 NULL, NULL );
00089                             return( NULL );
00090                      }
00091 
00092                      rc = strcasecmp( (char *)target, attr );
00093                      if ( rc == 0 ) {
00094                             NSLDAPI_FREE( attr );
00095                             break;
00096                      }
00097                      NSLDAPI_FREE( attr );
00098               }
00099        }
00100 
00101        /* 
00102         * if we get this far, we've found the attribute and are sitting
00103         * just before the set of values.
00104         */
00105 
00106        if ( lencall ) {
00107               rc = ber_scanf( &ber, "[V]", &vals );
00108        } else {
00109               rc = ber_scanf( &ber, "[v]", &vals );
00110        }
00111 
00112        if ( rc == LBER_ERROR ) {
00113               rc = LDAP_DECODING_ERROR;
00114        } else {
00115               rc = LDAP_SUCCESS;
00116        }
00117 
00118        LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
00119 
00120        return(( rc == LDAP_SUCCESS ) ? vals : NULL );
00121 }
00122 
00123 
00124 /* For language-sensitive attribute matching, we are looking for a
00125    language tag that looks like one of the following:
00126 
00127    cn
00128    cn;lang-en
00129    cn;lang-en-us
00130    cn;lang-ja
00131    cn;lang-ja-JP-kanji
00132 
00133    The base language specification consists of two letters following
00134    "lang-". After that, there may be additional language-specific
00135    narrowings preceded by a "-". In our processing we go from the
00136    specific to the general, preferring a complete subtype match, but
00137    accepting a partial one. For example:
00138 
00139    For a request for "cn;lang-en-us", we would return cn;lang-en-us
00140    if present, otherwise cn;lang-en if present, otherwise cn.
00141 
00142    Besides the language subtype, there may be other subtypes:
00143 
00144    cn;lang-ja;binary         (Unlikely!)
00145    cn;lang-ja;phonetic
00146 
00147    If not in the target, they are ignored. If they are in the target,
00148    they must be in the attribute to match.
00149 */
00150 #define LANG_SUBTYPE_INDEX_NONE      -1
00151 #define LANG_SUBTYPE_INDEX_DUPLICATE -2
00152 
00153 typedef struct {
00154        int    start;
00155        int    length;
00156 } _SubStringIndex;
00157 
00158 static int
00159 parse_subtypes( const char *target, int *baseLenp, char **langp,
00160                             _SubStringIndex **subs, int *nsubtypes )
00161 {
00162        int nSubtypes = 0;
00163        int ind = 0;
00164        char *nextToken;
00165        _SubStringIndex *result = NULL;
00166        int langIndex;
00167        int targetLen;
00168        int subtypeStart;
00169 
00170        langIndex = LANG_SUBTYPE_INDEX_NONE;
00171        *subs = NULL;
00172        *langp = NULL;
00173        *baseLenp = 0;
00174        *nsubtypes = 0;
00175        targetLen = strlen( target );
00176 
00177        /* Parse past base attribute */
00178        nextToken = strchr( target, ';' );
00179        if ( NULL != nextToken ) {
00180               subtypeStart = nextToken - target + 1;
00181               *baseLenp = subtypeStart - 1;
00182        }
00183        else {
00184               subtypeStart = targetLen;
00185               *baseLenp = subtypeStart;
00186        }
00187        ind = subtypeStart;
00188 
00189        /* How many subtypes? */
00190        nextToken = (char *)target + subtypeStart;
00191        while ( nextToken && *nextToken ) {
00192               char *thisToken = nextToken;
00193               nextToken = strchr( thisToken, ';' );
00194               if ( NULL != nextToken )
00195                      nextToken++;
00196               if ( 0 == strncasecmp( thisToken, "lang-", 5 ) ) {
00197                      /* If there was a previous lang tag, this is illegal! */
00198                      if ( langIndex != LANG_SUBTYPE_INDEX_NONE ) {
00199                             langIndex = LANG_SUBTYPE_INDEX_DUPLICATE;
00200                             return langIndex;
00201                      }
00202                      else {
00203                             langIndex = nSubtypes;
00204                      }
00205               } else {
00206                      nSubtypes++;
00207               }
00208        }
00209        /* No language subtype? */
00210        if ( langIndex < 0 )
00211               return langIndex;
00212 
00213        /* Allocate array of non-language subtypes */
00214        if ( nSubtypes > 0 ) {
00215               result = (_SubStringIndex *)NSLDAPI_MALLOC( sizeof(*result)
00216                   * nSubtypes );
00217               memset( result, 0, sizeof(*result) * nSubtypes );
00218        }
00219        ind = 0;
00220        nSubtypes = 0;
00221        ind = subtypeStart;
00222        nextToken = (char *)target + subtypeStart;
00223        while ( nextToken && *nextToken ) {
00224               char *thisToken = nextToken;
00225               int len;
00226               nextToken = strchr( thisToken, ';' );
00227               if ( NULL != nextToken ) {
00228                      len = nextToken - thisToken;
00229                      nextToken++;
00230               }
00231               else {
00232                      nextToken = (char *)target + targetLen;
00233                      len = nextToken - thisToken;
00234               }
00235               if ( 0 == strncasecmp( thisToken, "lang-", 5 ) ) {
00236                      int i;
00237                      *langp = (char *)NSLDAPI_MALLOC( len + 1 );
00238                      for( i = 0; i < len; i++ )
00239                             (*langp)[i] = toupper( target[ind+i] );
00240                      (*langp)[len] = 0;
00241               }
00242               else {
00243                      result[nSubtypes].start = thisToken - target;
00244                      result[nSubtypes].length = len;
00245                      nSubtypes++;
00246               }
00247        }
00248        *subs = result;
00249        *nsubtypes = nSubtypes;
00250        return langIndex;
00251 }
00252               
00253 
00254 static int
00255 check_lang_match( const char *target, const char *baseTarget,
00256                               _SubStringIndex *targetTypes,
00257                               int ntargetTypes, char *targetLang, char *attr )
00258 {
00259        int langIndex;
00260        _SubStringIndex *subtypes;
00261        int baseLen;
00262        char *lang;
00263        int nsubtypes;
00264        int mismatch = 0;
00265        int match = -1;
00266        int i;
00267 
00268        /* Get all subtypes in the attribute name */
00269        langIndex = parse_subtypes( attr, &baseLen, &lang, &subtypes, &nsubtypes );
00270 
00271        /* Check if there any required non-language subtypes which are
00272           not in this attribute */
00273        for( i = 0; i < ntargetTypes; i++ ) {
00274               char *t = (char *)target+targetTypes[i].start;
00275               int tlen = targetTypes[i].length;
00276               int j;
00277               for( j = 0; j < nsubtypes; j++ ) {
00278                      char *a = attr + subtypes[j].start;
00279                      int alen = subtypes[j].length;
00280                      if ( (tlen == alen) && !strncasecmp( t, a, tlen ) )
00281                             break;
00282               }
00283               if ( j >= nsubtypes ) {
00284                      mismatch = 1;
00285                      break;
00286               }
00287        }
00288        if ( mismatch ) {
00289            if ( NULL != subtypes )
00290                   NSLDAPI_FREE( subtypes );
00291               if ( NULL != lang )
00292                   NSLDAPI_FREE( lang );
00293               return -1;
00294        }
00295 
00296        /* If there was no language subtype... */
00297        if ( langIndex < 0 ) {
00298            if ( NULL != subtypes )
00299                   NSLDAPI_FREE( subtypes );
00300               if ( NULL != lang )
00301                   NSLDAPI_FREE( lang );
00302               if ( LANG_SUBTYPE_INDEX_NONE == langIndex )
00303                      return 0;
00304               else
00305                      return -1;
00306        }
00307 
00308        /* Okay, now check the language subtag */
00309        i = 0;
00310        while( targetLang[i] && lang[i] &&
00311                      (toupper(targetLang[i]) == toupper(lang[i])) )
00312               i++;
00313 
00314        /* The total length can't be longer than the requested subtype */
00315        if ( !lang[i] || (lang[i] == ';') ) {
00316               /* If the found subtype is shorter than the requested one, the next
00317                  character in the requested one should be "-" */
00318               if ( !targetLang[i] || (targetLang[i] == '-') )
00319                      match = i;
00320        }
00321        return match;
00322 }
00323 
00324 static int check_base_match( const char *target, char *attr )
00325 {
00326     int i = 0;
00327        int rc;
00328        while( target[i] && attr[i] && (toupper(target[i]) == toupper(attr[i])) )
00329            i++;
00330        rc = ( !target[i] && (!attr[i] || (';' == attr[i])) );
00331        return rc;
00332 }
00333 
00334 static void **
00335 internal_ldap_get_lang_values( LDAP *ld, LDAPMessage *entry,
00336                                                  const char *target, char **type, int lencall )
00337 {
00338        struct berelement    ber;
00339        char                  *attr = NULL;
00340        int                          rc;
00341        void                     **vals = NULL;
00342        int                 langIndex;
00343        _SubStringIndex     *subtypes;
00344        int                 nsubtypes;
00345        char                *baseTarget = NULL;
00346        int                 bestMatch = 0;
00347        char                *lang = NULL;
00348        int                 len;
00349        int                                firstAttr = 1;
00350        char                        *bestType = NULL;
00351 
00352        LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_values\n", 0, 0, 0 );
00353 
00354        if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
00355               return( NULL );
00356        }
00357        if ( (target == NULL) ||
00358            !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
00359               LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
00360               return( NULL );
00361        }
00362 
00363        /* A language check was requested, so see if there really is a
00364           language subtype in the attribute spec */
00365        langIndex = parse_subtypes( target, &len, &lang,
00366                                                     &subtypes, &nsubtypes );
00367        if ( langIndex < 0 ) {
00368               if ( NULL != subtypes ) {
00369                      NSLDAPI_FREE( subtypes );
00370                      subtypes = NULL;
00371               }
00372               vals = internal_ldap_get_values( ld, entry, target, lencall );
00373               if ( NULL != type )
00374                      *type = nsldapi_strdup( target );
00375               return vals;
00376        } else {
00377               /* Get just the base attribute name */
00378               baseTarget = (char *)NSLDAPI_MALLOC( len + 1 );
00379               memcpy( baseTarget, target, len );
00380               baseTarget[len] = 0;
00381        }
00382 
00383        ber = *entry->lm_ber;
00384 
00385        /* Process all attributes in the entry */
00386        while ( 1 ) {
00387               int foundMatch = 0;
00388               if ( NULL != attr )
00389                      NSLDAPI_FREE( attr );
00390               if ( firstAttr ) {
00391                      firstAttr = 0;
00392                      /* skip sequence, dn, sequence of, and snag the first attr */
00393                      if ( ber_scanf( &ber, "{x{{a", &attr ) == LBER_ERROR ) {
00394                             break;
00395                      }
00396               } else {
00397                      if ( ber_scanf( &ber, "{a", &attr ) == LBER_ERROR ) {
00398                             break;
00399                      }
00400               }
00401 
00402               if ( check_base_match( (const char *)baseTarget, attr ) ) {
00403                      int thisMatch = check_lang_match( target, baseTarget,
00404                                                                                subtypes, nsubtypes, lang, attr );
00405                      if ( thisMatch > bestMatch ) {
00406                             if ( vals )
00407                                    NSLDAPI_FREE( vals );
00408                             foundMatch = 1;
00409                             bestMatch = thisMatch;
00410                             if ( NULL != bestType )
00411                                    NSLDAPI_FREE( bestType );
00412                             bestType = attr;
00413                             attr = NULL;
00414                      }
00415               }
00416               if ( foundMatch ) {
00417                      if ( lencall ) {
00418                             rc = ber_scanf( &ber, "[V]}", &vals );
00419                      } else {
00420                             rc = ber_scanf( &ber, "[v]}", &vals );
00421                      }
00422               } else {
00423                      ber_scanf( &ber, "x}" );
00424               }
00425        }
00426 
00427        NSLDAPI_FREE( lang );
00428        NSLDAPI_FREE( baseTarget );
00429        NSLDAPI_FREE( subtypes );
00430 
00431        if ( NULL != type )
00432               *type = bestType;
00433        else if ( NULL != bestType )
00434               NSLDAPI_FREE( bestType );
00435 
00436        if ( NULL == vals ) {
00437               rc = LDAP_DECODING_ERROR;
00438        } else {
00439               rc = LDAP_SUCCESS;
00440        }
00441 
00442        LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
00443 
00444        return( vals );
00445 }
00446 
00447 
00448 char **
00449 LDAP_CALL
00450 ldap_get_values( LDAP *ld, LDAPMessage *entry, const char *target )
00451 {
00452        return( (char **) internal_ldap_get_values( ld, entry, target, 0 ) );
00453 }
00454 
00455 struct berval **
00456 LDAP_CALL
00457 ldap_get_values_len( LDAP *ld, LDAPMessage *entry, const char *target )
00458 {
00459        return( (struct berval **) internal_ldap_get_values( ld, entry, target,
00460            1 ) );
00461 }
00462 
00463 char **
00464 LDAP_CALL
00465 ldap_get_lang_values( LDAP *ld, LDAPMessage *entry, const char *target,
00466                                           char **type )
00467 {
00468        return( (char **) internal_ldap_get_lang_values( ld, entry,
00469                                                                              target, type, 0 ) );
00470 }
00471 
00472 struct berval **
00473 LDAP_CALL
00474 ldap_get_lang_values_len( LDAP *ld, LDAPMessage *entry, const char *target,
00475                                           char **type )
00476 {
00477        return( (struct berval **) internal_ldap_get_lang_values( ld, entry,
00478                                                                          target, type, 1 ) );
00479 }
00480