dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libldap5 / sources / ldap / common / getvalues.c
blobf40c4b53a3947e649782224bdd9e636cdc9bfd8e
1 #pragma ident "%Z%%M% %I% %E% SMI"
3 /*
4 * The contents of this file are subject to the Netscape Public
5 * License Version 1.1 (the "License"); you may not use this file
6 * except in compliance with the License. You may obtain a copy of
7 * the License at http://www.mozilla.org/NPL/
9 * Software distributed under the License is distributed on an "AS
10 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11 * implied. See the License for the specific language governing
12 * rights and limitations under the License.
14 * The Original Code is Mozilla Communicator client code, released
15 * March 31, 1998.
17 * The Initial Developer of the Original Code is Netscape
18 * Communications Corporation. Portions created by Netscape are
19 * Copyright (C) 1998-1999 Netscape Communications Corporation. All
20 * Rights Reserved.
22 * Contributor(s):
25 * Copyright (c) 1990 Regents of the University of Michigan.
26 * All rights reserved.
29 * getvalues.c
32 #if 0
33 static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
34 #endif
36 #include "ldap-int.h"
39 static void **
40 internal_ldap_get_values( LDAP *ld, LDAPMessage *entry, const char *target,
41 int lencall )
43 struct berelement ber;
44 char *attr;
45 int rc;
46 void **vals;
48 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_values\n", 0, 0, 0 );
50 if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
51 return( NULL ); /* punt */
53 if ( target == NULL ||
54 !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
55 LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
56 return( NULL );
59 ber = *entry->lm_ber;
61 /* skip sequence, dn, sequence of, and snag the first attr */
62 if ( ber_scanf( &ber, "{x{{a", &attr ) == LBER_ERROR ) {
63 LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
64 return( NULL );
67 rc = strcasecmp( (char *)target, attr );
68 NSLDAPI_FREE( attr );
69 if ( rc != 0 ) {
70 while ( 1 ) {
71 if ( ber_scanf( &ber, "x}{a", &attr ) == LBER_ERROR ) {
72 LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR,
73 NULL, NULL );
74 return( NULL );
77 rc = strcasecmp( (char *)target, attr );
78 if ( rc == 0 ) {
79 NSLDAPI_FREE( attr );
80 break;
82 NSLDAPI_FREE( attr );
86 /*
87 * if we get this far, we've found the attribute and are sitting
88 * just before the set of values.
91 if ( lencall ) {
92 rc = ber_scanf( &ber, "[V]", &vals );
93 } else {
94 rc = ber_scanf( &ber, "[v]", &vals );
97 if ( rc == LBER_ERROR ) {
98 rc = LDAP_DECODING_ERROR;
99 } else {
100 rc = LDAP_SUCCESS;
103 LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
105 return(( rc == LDAP_SUCCESS ) ? vals : NULL );
109 /* For language-sensitive attribute matching, we are looking for a
110 language tag that looks like one of the following:
113 cn;lang-en
114 cn;lang-en-us
115 cn;lang-ja
116 cn;lang-ja-JP-kanji
118 The base language specification consists of two letters following
119 "lang-". After that, there may be additional language-specific
120 narrowings preceded by a "-". In our processing we go from the
121 specific to the general, preferring a complete subtype match, but
122 accepting a partial one. For example:
124 For a request for "cn;lang-en-us", we would return cn;lang-en-us
125 if present, otherwise cn;lang-en if present, otherwise cn.
127 Besides the language subtype, there may be other subtypes:
129 cn;lang-ja;binary (Unlikely!)
130 cn;lang-ja;phonetic
132 If not in the target, they are ignored. If they are in the target,
133 they must be in the attribute to match.
135 #define LANG_SUBTYPE_INDEX_NONE -1
136 #define LANG_SUBTYPE_INDEX_DUPLICATE -2
138 typedef struct {
139 int start;
140 int length;
141 } _SubStringIndex;
143 static int
144 parse_subtypes( const char *target, int *baseLenp, char **langp,
145 _SubStringIndex **subs, int *nsubtypes )
147 int nSubtypes = 0;
148 int ind = 0;
149 char *nextToken;
150 _SubStringIndex *result = NULL;
151 int langIndex;
152 int targetLen;
153 int subtypeStart;
155 langIndex = LANG_SUBTYPE_INDEX_NONE;
156 *subs = NULL;
157 *langp = NULL;
158 *baseLenp = 0;
159 *nsubtypes = 0;
160 targetLen = strlen( target );
162 /* Parse past base attribute */
163 nextToken = strchr( target, ';' );
164 if ( NULL != nextToken ) {
165 subtypeStart = nextToken - target + 1;
166 *baseLenp = subtypeStart - 1;
168 else {
169 subtypeStart = targetLen;
170 *baseLenp = subtypeStart;
172 ind = subtypeStart;
174 /* How many subtypes? */
175 nextToken = (char *)target + subtypeStart;
176 while ( nextToken && *nextToken ) {
177 char *thisToken = nextToken;
178 nextToken = strchr( thisToken, ';' );
179 if ( NULL != nextToken )
180 nextToken++;
181 if ( 0 == strncasecmp( thisToken, "lang-", 5 ) ) {
182 /* If there was a previous lang tag, this is illegal! */
183 if ( langIndex != LANG_SUBTYPE_INDEX_NONE ) {
184 langIndex = LANG_SUBTYPE_INDEX_DUPLICATE;
185 return langIndex;
187 else {
188 langIndex = nSubtypes;
190 } else {
191 nSubtypes++;
194 /* No language subtype? */
195 if ( langIndex < 0 )
196 return langIndex;
198 /* Allocate array of non-language subtypes */
199 if ( nSubtypes > 0 ) {
200 result = (_SubStringIndex *)NSLDAPI_MALLOC( sizeof(*result)
201 * nSubtypes );
202 if (result == NULL) {
203 return LANG_SUBTYPE_INDEX_NONE; /* Error */
205 memset( result, 0, sizeof(*result) * nSubtypes );
207 ind = 0;
208 nSubtypes = 0;
209 ind = subtypeStart;
210 nextToken = (char *)target + subtypeStart;
211 while ( nextToken && *nextToken ) {
212 char *thisToken = nextToken;
213 int len;
214 nextToken = strchr( thisToken, ';' );
215 if ( NULL != nextToken ) {
216 len = nextToken - thisToken;
217 nextToken++;
219 else {
220 nextToken = (char *)target + targetLen;
221 len = nextToken - thisToken;
223 if ( 0 == strncasecmp( thisToken, "lang-", 5 ) ) {
224 int i;
225 *langp = (char *)NSLDAPI_MALLOC( len + 1 );
226 if (*langp == NULL) {
227 if (result != NULL)
228 NSLDAPI_FREE(result);
229 return LANG_SUBTYPE_INDEX_NONE; /* Error */
231 for( i = 0; i < len; i++ )
232 (*langp)[i] = toupper( target[ind+i] );
233 (*langp)[len] = 0;
235 else {
236 result[nSubtypes].start = thisToken - target;
237 result[nSubtypes].length = len;
238 nSubtypes++;
241 *subs = result;
242 *nsubtypes = nSubtypes;
243 return langIndex;
247 static int
248 check_lang_match( const char *target, const char *baseTarget,
249 _SubStringIndex *targetTypes,
250 int ntargetTypes, char *targetLang, char *attr )
252 int langIndex;
253 _SubStringIndex *subtypes;
254 int baseLen;
255 char *lang;
256 int nsubtypes;
257 int mismatch = 0;
258 int match = -1;
259 int i;
261 /* Get all subtypes in the attribute name */
262 langIndex = parse_subtypes( attr, &baseLen, &lang, &subtypes, &nsubtypes );
264 /* Check if there any required non-language subtypes which are
265 not in this attribute */
266 for( i = 0; i < ntargetTypes; i++ ) {
267 char *t = (char *)target+targetTypes[i].start;
268 int tlen = targetTypes[i].length;
269 int j;
270 for( j = 0; j < nsubtypes; j++ ) {
271 char *a = attr + subtypes[j].start;
272 int alen = subtypes[j].length;
273 if ( (tlen == alen) && !strncasecmp( t, a, tlen ) )
274 break;
276 if ( j >= nsubtypes ) {
277 mismatch = 1;
278 break;
281 if ( mismatch ) {
282 if ( NULL != subtypes )
283 NSLDAPI_FREE( subtypes );
284 if ( NULL != lang )
285 NSLDAPI_FREE( lang );
286 return -1;
289 /* If there was no language subtype... */
290 if ( langIndex < 0 ) {
291 if ( NULL != subtypes )
292 NSLDAPI_FREE( subtypes );
293 if ( NULL != lang )
294 NSLDAPI_FREE( lang );
295 if ( LANG_SUBTYPE_INDEX_NONE == langIndex )
296 return 0;
297 else
298 return -1;
301 /* Okay, now check the language subtag */
302 i = 0;
303 while( targetLang[i] && lang[i] &&
304 (toupper(targetLang[i]) == toupper(lang[i])) )
305 i++;
307 /* The total length can't be longer than the requested subtype */
308 if ( !lang[i] || (lang[i] == ';') ) {
309 /* If the found subtype is shorter than the requested one, the next
310 character in the requested one should be "-" */
311 if ( !targetLang[i] || (targetLang[i] == '-') )
312 match = i;
314 return match;
317 static int check_base_match( const char *target, char *attr )
319 int i = 0;
320 int rc;
321 while( target[i] && attr[i] && (toupper(target[i]) == toupper(attr[i])) )
322 i++;
323 rc = ( !target[i] && (!attr[i] || (';' == attr[i])) );
324 return rc;
327 static void **
328 internal_ldap_get_lang_values( LDAP *ld, LDAPMessage *entry,
329 const char *target, char **type, int lencall )
331 struct berelement ber;
332 char *attr = NULL;
333 int rc;
334 void **vals = NULL;
335 int langIndex;
336 _SubStringIndex *subtypes;
337 int nsubtypes;
338 char *baseTarget = NULL;
339 int bestMatch = 0;
340 char *lang = NULL;
341 int len;
342 int firstAttr = 1;
343 char *bestType = NULL;
345 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_values\n", 0, 0, 0 );
347 if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
348 return( NULL );
350 if ( (target == NULL) ||
351 !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
352 LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
353 return( NULL );
356 /* A language check was requested, so see if there really is a
357 language subtype in the attribute spec */
358 langIndex = parse_subtypes( target, &len, &lang,
359 &subtypes, &nsubtypes );
360 if ( langIndex < 0 ) {
361 if ( NULL != subtypes ) {
362 NSLDAPI_FREE( subtypes );
363 subtypes = NULL;
365 vals = internal_ldap_get_values( ld, entry, target, lencall );
366 if ( NULL != type )
367 *type = nsldapi_strdup( target );
368 return vals;
369 } else {
370 /* Get just the base attribute name */
371 baseTarget = (char *)NSLDAPI_MALLOC( len + 1 );
372 if (baseTarget == NULL) {
373 return( NULL );
375 memcpy( baseTarget, target, len );
376 baseTarget[len] = 0;
379 ber = *entry->lm_ber;
381 /* Process all attributes in the entry */
382 while ( 1 ) {
383 int foundMatch = 0;
384 if ( NULL != attr )
385 NSLDAPI_FREE( attr );
386 if ( firstAttr ) {
387 firstAttr = 0;
388 /* skip sequence, dn, sequence of, and snag the first attr */
389 if ( ber_scanf( &ber, "{x{{a", &attr ) == LBER_ERROR ) {
390 break;
392 } else {
393 if ( ber_scanf( &ber, "{a", &attr ) == LBER_ERROR ) {
394 break;
398 if ( check_base_match( (const char *)baseTarget, attr ) ) {
399 int thisMatch = check_lang_match( target, baseTarget,
400 subtypes, nsubtypes, lang, attr );
401 if ( thisMatch > bestMatch ) {
402 if ( vals )
403 NSLDAPI_FREE( vals );
404 foundMatch = 1;
405 bestMatch = thisMatch;
406 if ( NULL != bestType )
407 NSLDAPI_FREE( bestType );
408 bestType = attr;
409 attr = NULL;
412 if ( foundMatch ) {
413 if ( lencall ) {
414 rc = ber_scanf( &ber, "[V]}", &vals );
415 } else {
416 rc = ber_scanf( &ber, "[v]}", &vals );
418 } else {
419 ber_scanf( &ber, "x}" );
423 NSLDAPI_FREE( lang );
424 NSLDAPI_FREE( baseTarget );
425 NSLDAPI_FREE( subtypes );
427 if ( NULL != type )
428 *type = bestType;
429 else if ( NULL != bestType )
430 NSLDAPI_FREE( bestType );
432 if ( NULL == vals ) {
433 rc = LDAP_DECODING_ERROR;
434 } else {
435 rc = LDAP_SUCCESS;
438 LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
440 return( vals );
444 char **
445 LDAP_CALL
446 ldap_get_values( LDAP *ld, LDAPMessage *entry, const char *target )
448 return( (char **) internal_ldap_get_values( ld, entry, target, 0 ) );
451 struct berval **
452 LDAP_CALL
453 ldap_get_values_len( LDAP *ld, LDAPMessage *entry, const char *target )
455 return( (struct berval **) internal_ldap_get_values( ld, entry, target,
456 1 ) );
459 char **
460 LDAP_CALL
461 ldap_get_lang_values( LDAP *ld, LDAPMessage *entry, const char *target,
462 char **type )
464 return( (char **) internal_ldap_get_lang_values( ld, entry,
465 target, type, 0 ) );
468 struct berval **
469 LDAP_CALL
470 ldap_get_lang_values_len( LDAP *ld, LDAPMessage *entry, const char *target,
471 char **type )
473 return( (struct berval **) internal_ldap_get_lang_values( ld, entry,
474 target, type, 1 ) );