1 #pragma ident "%Z%%M% %I% %E% SMI"
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
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
25 * Copyright (c) 1990 Regents of the University of Michigan.
26 * All rights reserved.
33 static char copyright
[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
40 internal_ldap_get_values( LDAP
*ld
, LDAPMessage
*entry
, const char *target
,
43 struct berelement ber
;
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
);
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
);
67 rc
= strcasecmp( (char *)target
, attr
);
71 if ( ber_scanf( &ber
, "x}{a", &attr
) == LBER_ERROR
) {
72 LDAP_SET_LDERRNO( ld
, LDAP_DECODING_ERROR
,
77 rc
= strcasecmp( (char *)target
, attr
);
87 * if we get this far, we've found the attribute and are sitting
88 * just before the set of values.
92 rc
= ber_scanf( &ber
, "[V]", &vals
);
94 rc
= ber_scanf( &ber
, "[v]", &vals
);
97 if ( rc
== LBER_ERROR
) {
98 rc
= LDAP_DECODING_ERROR
;
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:
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!)
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
144 parse_subtypes( const char *target
, int *baseLenp
, char **langp
,
145 _SubStringIndex
**subs
, int *nsubtypes
)
150 _SubStringIndex
*result
= NULL
;
155 langIndex
= LANG_SUBTYPE_INDEX_NONE
;
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;
169 subtypeStart
= targetLen
;
170 *baseLenp
= 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
)
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
;
188 langIndex
= nSubtypes
;
194 /* No language subtype? */
198 /* Allocate array of non-language subtypes */
199 if ( nSubtypes
> 0 ) {
200 result
= (_SubStringIndex
*)NSLDAPI_MALLOC( sizeof(*result
)
202 if (result
== NULL
) {
203 return LANG_SUBTYPE_INDEX_NONE
; /* Error */
205 memset( result
, 0, sizeof(*result
) * nSubtypes
);
210 nextToken
= (char *)target
+ subtypeStart
;
211 while ( nextToken
&& *nextToken
) {
212 char *thisToken
= nextToken
;
214 nextToken
= strchr( thisToken
, ';' );
215 if ( NULL
!= nextToken
) {
216 len
= nextToken
- thisToken
;
220 nextToken
= (char *)target
+ targetLen
;
221 len
= nextToken
- thisToken
;
223 if ( 0 == strncasecmp( thisToken
, "lang-", 5 ) ) {
225 *langp
= (char *)NSLDAPI_MALLOC( len
+ 1 );
226 if (*langp
== 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
] );
236 result
[nSubtypes
].start
= thisToken
- target
;
237 result
[nSubtypes
].length
= len
;
242 *nsubtypes
= nSubtypes
;
248 check_lang_match( const char *target
, const char *baseTarget
,
249 _SubStringIndex
*targetTypes
,
250 int ntargetTypes
, char *targetLang
, char *attr
)
253 _SubStringIndex
*subtypes
;
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
;
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
) )
276 if ( j
>= nsubtypes
) {
282 if ( NULL
!= subtypes
)
283 NSLDAPI_FREE( subtypes
);
285 NSLDAPI_FREE( lang
);
289 /* If there was no language subtype... */
290 if ( langIndex
< 0 ) {
291 if ( NULL
!= subtypes
)
292 NSLDAPI_FREE( subtypes
);
294 NSLDAPI_FREE( lang
);
295 if ( LANG_SUBTYPE_INDEX_NONE
== langIndex
)
301 /* Okay, now check the language subtag */
303 while( targetLang
[i
] && lang
[i
] &&
304 (toupper(targetLang
[i
]) == toupper(lang
[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
] == '-') )
317 static int check_base_match( const char *target
, char *attr
)
321 while( target
[i
] && attr
[i
] && (toupper(target
[i
]) == toupper(attr
[i
])) )
323 rc
= ( !target
[i
] && (!attr
[i
] || (';' == attr
[i
])) );
328 internal_ldap_get_lang_values( LDAP
*ld
, LDAPMessage
*entry
,
329 const char *target
, char **type
, int lencall
)
331 struct berelement ber
;
336 _SubStringIndex
*subtypes
;
338 char *baseTarget
= NULL
;
343 char *bestType
= NULL
;
345 LDAPDebug( LDAP_DEBUG_TRACE
, "ldap_get_values\n", 0, 0, 0 );
347 if ( !NSLDAPI_VALID_LDAP_POINTER( ld
)) {
350 if ( (target
== NULL
) ||
351 !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry
)) {
352 LDAP_SET_LDERRNO( ld
, LDAP_PARAM_ERROR
, NULL
, 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
);
365 vals
= internal_ldap_get_values( ld
, entry
, target
, lencall
);
367 *type
= nsldapi_strdup( target
);
370 /* Get just the base attribute name */
371 baseTarget
= (char *)NSLDAPI_MALLOC( len
+ 1 );
372 if (baseTarget
== NULL
) {
375 memcpy( baseTarget
, target
, len
);
379 ber
= *entry
->lm_ber
;
381 /* Process all attributes in the entry */
385 NSLDAPI_FREE( attr
);
388 /* skip sequence, dn, sequence of, and snag the first attr */
389 if ( ber_scanf( &ber
, "{x{{a", &attr
) == LBER_ERROR
) {
393 if ( ber_scanf( &ber
, "{a", &attr
) == LBER_ERROR
) {
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
) {
403 NSLDAPI_FREE( vals
);
405 bestMatch
= thisMatch
;
406 if ( NULL
!= bestType
)
407 NSLDAPI_FREE( bestType
);
414 rc
= ber_scanf( &ber
, "[V]}", &vals
);
416 rc
= ber_scanf( &ber
, "[v]}", &vals
);
419 ber_scanf( &ber
, "x}" );
423 NSLDAPI_FREE( lang
);
424 NSLDAPI_FREE( baseTarget
);
425 NSLDAPI_FREE( subtypes
);
429 else if ( NULL
!= bestType
)
430 NSLDAPI_FREE( bestType
);
432 if ( NULL
== vals
) {
433 rc
= LDAP_DECODING_ERROR
;
438 LDAP_SET_LDERRNO( ld
, rc
, NULL
, NULL
);
446 ldap_get_values( LDAP
*ld
, LDAPMessage
*entry
, const char *target
)
448 return( (char **) internal_ldap_get_values( ld
, entry
, target
, 0 ) );
453 ldap_get_values_len( LDAP
*ld
, LDAPMessage
*entry
, const char *target
)
455 return( (struct berval
**) internal_ldap_get_values( ld
, entry
, target
,
461 ldap_get_lang_values( LDAP
*ld
, LDAPMessage
*entry
, const char *target
,
464 return( (char **) internal_ldap_get_lang_values( ld
, entry
,
470 ldap_get_lang_values_len( LDAP
*ld
, LDAPMessage
*entry
, const char *target
,
473 return( (struct berval
**) internal_ldap_get_lang_values( ld
, entry
,