2 * Copyright (c) 1993, 1994 Regents of the University of Michigan.
5 * Redistribution and use in source and binary forms are permitted
6 * provided that this notice is preserved and that due credit is given
7 * to the University of Michigan at Ann Arbor. The name of the University
8 * may not be used to endorse or promote products derived from this
9 * software without specific prior written permission. This software
10 * is provided ``as is'' without express or implied warranty.
12 * disptmpl.c: display template library routines for LDAP clients
13 * 7 March 1994 by Mark C Smith
22 #include <ac/string.h>
24 #include <ac/unistd.h>
25 extern char *strdup (const char *);
27 #ifdef HAVE_SYS_FILE_H
34 static void free_disptmpl LDAP_P(( struct ldap_disptmpl *tmpl ));
35 static int read_next_tmpl LDAP_P(( char **bufp, long *blenp,
36 struct ldap_disptmpl **tmplp, int dtversion ));
38 static char *tmploptions[] = {
45 static unsigned long tmploptvals[] = {
46 LDAP_DTMPL_OPT_ADDABLE, LDAP_DTMPL_OPT_ALLOWMODRDN,
47 LDAP_DTMPL_OPT_ALTVIEW,
51 static char *itemtypes[] = {
53 "bool", "jpeg", "jpegbtn",
54 "fax", "faxbtn", "audiobtn",
55 "time", "date", "url",
56 "searchact", "linkact", "adddnact",
57 "addact", "verifyact", "mail",
61 static unsigned long itemsynids[] = {
62 LDAP_SYN_CASEIGNORESTR, LDAP_SYN_MULTILINESTR, LDAP_SYN_DN,
63 LDAP_SYN_BOOLEAN, LDAP_SYN_JPEGIMAGE, LDAP_SYN_JPEGBUTTON,
64 LDAP_SYN_FAXIMAGE, LDAP_SYN_FAXBUTTON, LDAP_SYN_AUDIOBUTTON,
65 LDAP_SYN_TIME, LDAP_SYN_DATE, LDAP_SYN_LABELEDURL,
66 LDAP_SYN_SEARCHACTION, LDAP_SYN_LINKACTION, LDAP_SYN_ADDDNACTION,
67 LDAP_SYN_ADDDNACTION, LDAP_SYN_VERIFYDNACTION,LDAP_SYN_RFC822ADDR,
71 static char *itemoptions[] = {
74 "required", "hideiffalse",
79 static unsigned long itemoptvals[] = {
80 LDAP_DITEM_OPT_READONLY, LDAP_DITEM_OPT_SORTVALUES,
81 LDAP_DITEM_OPT_SINGLEVALUED, LDAP_DITEM_OPT_HIDEIFEMPTY,
82 LDAP_DITEM_OPT_VALUEREQUIRED, LDAP_DITEM_OPT_HIDEIFFALSE,
86 #define ADDEF_CONSTANT "constant"
87 #define ADDEF_ADDERSDN "addersdn"
91 ldap_init_templates( char *file, struct ldap_disptmpl **tmpllistp )
98 *tmpllistp = NULLDISPTMPL;
100 if (( fp = fopen( file, "r" )) == NULL ) {
101 return( LDAP_TMPL_ERR_FILE );
104 if ( fseek( fp, 0L, SEEK_END ) != 0 ) { /* move to end to get len */
106 return( LDAP_TMPL_ERR_FILE );
111 if ( fseek( fp, 0L, SEEK_SET ) != 0 ) { /* back to start of file */
113 return( LDAP_TMPL_ERR_FILE );
116 if (( buf = malloc( (size_t)len )) == NULL ) {
118 return( LDAP_TMPL_ERR_MEM );
121 rlen = fread( buf, 1, (size_t)len, fp );
125 if ( rlen != len && !eof ) { /* error: didn't get the whole file */
127 return( LDAP_TMPL_ERR_FILE );
130 rc = ldap_init_templates_buf( buf, rlen, tmpllistp );
138 ldap_init_templates_buf( char *buf, long buflen,
139 struct ldap_disptmpl **tmpllistp )
143 struct ldap_disptmpl *prevtmpl, *tmpl;
145 *tmpllistp = prevtmpl = NULLDISPTMPL;
147 if ( next_line_tokens( &buf, &buflen, &toks ) != 2 ||
148 strcasecmp( toks[ 0 ], "version" ) != 0 ) {
149 free_strarray( toks );
150 return( LDAP_TMPL_ERR_SYNTAX );
152 version = atoi( toks[ 1 ] );
153 free_strarray( toks );
154 if ( version != LDAP_TEMPLATE_VERSION ) {
155 return( LDAP_TMPL_ERR_VERSION );
158 while ( buflen > 0 && ( rc = read_next_tmpl( &buf, &buflen, &tmpl,
159 version )) == 0 && tmpl != NULLDISPTMPL ) {
160 if ( prevtmpl == NULLDISPTMPL ) {
163 prevtmpl->dt_next = tmpl;
169 ldap_free_templates( *tmpllistp );
178 ldap_free_templates( struct ldap_disptmpl *tmpllist )
180 struct ldap_disptmpl *tp, *nexttp;
182 if ( tmpllist != NULL ) {
183 for ( tp = tmpllist; tp != NULL; tp = nexttp ) {
184 nexttp = tp->dt_next;
192 free_disptmpl( struct ldap_disptmpl *tmpl )
194 if ( tmpl != NULL ) {
195 if ( tmpl->dt_name != NULL ) {
196 free( tmpl->dt_name );
199 if ( tmpl->dt_pluralname != NULL ) {
200 free( tmpl->dt_pluralname );
203 if ( tmpl->dt_iconname != NULL ) {
204 free( tmpl->dt_iconname );
207 if ( tmpl->dt_authattrname != NULL ) {
208 free( tmpl->dt_authattrname );
211 if ( tmpl->dt_defrdnattrname != NULL ) {
212 free( tmpl->dt_defrdnattrname );
215 if ( tmpl->dt_defaddlocation != NULL ) {
216 free( tmpl->dt_defaddlocation );
219 if ( tmpl->dt_oclist != NULL ) {
220 struct ldap_oclist *ocp, *nextocp;
222 for ( ocp = tmpl->dt_oclist; ocp != NULL; ocp = nextocp ) {
223 nextocp = ocp->oc_next;
224 free_strarray( ocp->oc_objclasses );
229 if ( tmpl->dt_adddeflist != NULL ) {
230 struct ldap_adddeflist *adp, *nextadp;
232 for ( adp = tmpl->dt_adddeflist; adp != NULL; adp = nextadp ) {
233 nextadp = adp->ad_next;
234 if( adp->ad_attrname != NULL ) {
235 free( adp->ad_attrname );
237 if( adp->ad_value != NULL ) {
238 free( adp->ad_value );
244 if ( tmpl->dt_items != NULL ) {
245 struct ldap_tmplitem *rowp, *nextrowp, *colp, *nextcolp;
247 for ( rowp = tmpl->dt_items; rowp != NULL; rowp = nextrowp ) {
248 nextrowp = rowp->ti_next_in_col;
249 for ( colp = rowp; colp != NULL; colp = nextcolp ) {
250 nextcolp = colp->ti_next_in_row;
251 if ( colp->ti_attrname != NULL ) {
252 free( colp->ti_attrname );
254 if ( colp->ti_label != NULL ) {
255 free( colp->ti_label );
257 if ( colp->ti_args != NULL ) {
258 free_strarray( colp->ti_args );
270 struct ldap_disptmpl *
271 ldap_first_disptmpl( struct ldap_disptmpl *tmpllist )
277 struct ldap_disptmpl *
278 ldap_next_disptmpl( struct ldap_disptmpl *tmpllist,
279 struct ldap_disptmpl *tmpl )
281 return( tmpl == NULLDISPTMPL ? tmpl : tmpl->dt_next );
285 struct ldap_disptmpl *
286 ldap_name2template( char *name, struct ldap_disptmpl *tmpllist )
288 struct ldap_disptmpl *dtp;
290 for ( dtp = ldap_first_disptmpl( tmpllist ); dtp != NULLDISPTMPL;
291 dtp = ldap_next_disptmpl( tmpllist, dtp )) {
292 if ( strcasecmp( name, dtp->dt_name ) == 0 ) {
297 return( NULLDISPTMPL );
301 struct ldap_disptmpl *
302 ldap_oc2template( char **oclist, struct ldap_disptmpl *tmpllist )
304 struct ldap_disptmpl *dtp;
305 struct ldap_oclist *oclp;
306 int i, j, needcnt, matchcnt;
308 if ( tmpllist == NULL || oclist == NULL || oclist[ 0 ] == NULL ) {
309 return( NULLDISPTMPL );
312 for ( dtp = ldap_first_disptmpl( tmpllist ); dtp != NULLDISPTMPL;
313 dtp = ldap_next_disptmpl( tmpllist, dtp )) {
314 for ( oclp = dtp->dt_oclist; oclp != NULLOCLIST;
315 oclp = oclp->oc_next ) {
316 needcnt = matchcnt = 0;
317 for ( i = 0; oclp->oc_objclasses[ i ] != NULL; ++i ) {
318 for ( j = 0; oclist[ j ] != NULL; ++j ) {
319 if ( strcasecmp( oclist[ j ], oclp->oc_objclasses[ i ] )
327 if ( matchcnt == needcnt ) {
333 return( NULLDISPTMPL );
337 struct ldap_tmplitem *
338 ldap_first_tmplrow( struct ldap_disptmpl *tmpl )
340 return( tmpl->dt_items );
344 struct ldap_tmplitem *
345 ldap_next_tmplrow( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row )
347 return( row == NULLTMPLITEM ? row : row->ti_next_in_col );
351 struct ldap_tmplitem *
352 ldap_first_tmplcol( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row )
358 struct ldap_tmplitem *
359 ldap_next_tmplcol( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row,
360 struct ldap_tmplitem *col )
362 return( col == NULLTMPLITEM ? col : col->ti_next_in_row );
367 ldap_tmplattrs( struct ldap_disptmpl *tmpl, char **includeattrs,
368 int exclude, unsigned long syntaxmask )
371 * this routine should filter out duplicate attributes...
373 struct ldap_tmplitem *tirowp, *ticolp;
374 int i, attrcnt, memerr;
380 if (( attrs = (char **)malloc( sizeof( char * ))) == NULL ) {
384 if ( includeattrs != NULL ) {
385 for ( i = 0; !memerr && includeattrs[ i ] != NULL; ++i ) {
386 if (( attrs = (char **)realloc( attrs, ( attrcnt + 2 ) *
387 sizeof( char * ))) == NULL || ( attrs[ attrcnt++ ] =
388 strdup( includeattrs[ i ] )) == NULL ) {
391 attrs[ attrcnt ] = NULL;
396 for ( tirowp = ldap_first_tmplrow( tmpl );
397 !memerr && tirowp != NULLTMPLITEM;
398 tirowp = ldap_next_tmplrow( tmpl, tirowp )) {
399 for ( ticolp = ldap_first_tmplcol( tmpl, tirowp );
400 ticolp != NULLTMPLITEM;
401 ticolp = ldap_next_tmplcol( tmpl, tirowp, ticolp )) {
403 if ( syntaxmask != 0 ) {
405 ( syntaxmask & ticolp->ti_syntaxid ) != 0 ) ||
407 ( syntaxmask & ticolp->ti_syntaxid ) == 0 )) {
412 if ( ticolp->ti_attrname != NULL ) {
413 if (( attrs = (char **)realloc( attrs, ( attrcnt + 2 ) *
414 sizeof( char * ))) == NULL || ( attrs[ attrcnt++ ] =
415 strdup( ticolp->ti_attrname )) == NULL ) {
418 attrs[ attrcnt ] = NULL;
424 if ( memerr || attrcnt == 0 ) {
425 for ( i = 0; i < attrcnt; ++i ) {
426 if ( attrs[ i ] != NULL ) {
431 free( (char *)attrs );
440 read_next_tmpl( char **bufp, long *blenp, struct ldap_disptmpl **tmplp,
443 int i, j, tokcnt, samerow, adsource;
444 char **toks, *itemopts;
445 struct ldap_disptmpl *tmpl;
446 struct ldap_oclist *ocp, *prevocp = NULL;
447 struct ldap_adddeflist *adp, *prevadp = NULL;
448 struct ldap_tmplitem *rowp = NULL, *ip, *previp = NULL;
453 * template name comes first
455 if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
456 free_strarray( toks );
457 return( tokcnt == 0 ? 0 : LDAP_TMPL_ERR_SYNTAX );
460 if (( tmpl = (struct ldap_disptmpl *)calloc( 1,
461 sizeof( struct ldap_disptmpl ))) == NULL ) {
462 free_strarray( toks );
463 return( LDAP_TMPL_ERR_MEM );
465 tmpl->dt_name = toks[ 0 ];
466 free( (char *)toks );
469 * template plural name comes next
471 if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
472 free_strarray( toks );
473 free_disptmpl( tmpl );
474 return( LDAP_TMPL_ERR_SYNTAX );
476 tmpl->dt_pluralname = toks[ 0 ];
477 free( (char *)toks );
480 * template icon name is next
482 if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
483 free_strarray( toks );
484 free_disptmpl( tmpl );
485 return( LDAP_TMPL_ERR_SYNTAX );
487 tmpl->dt_iconname = toks[ 0 ];
488 free( (char *)toks );
491 * template options come next
493 if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) < 1 ) {
494 free_strarray( toks );
495 free_disptmpl( tmpl );
496 return( LDAP_TMPL_ERR_SYNTAX );
498 for ( i = 0; toks[ i ] != NULL; ++i ) {
499 for ( j = 0; tmploptions[ j ] != NULL; ++j ) {
500 if ( strcasecmp( toks[ i ], tmploptions[ j ] ) == 0 ) {
501 tmpl->dt_options |= tmploptvals[ j ];
505 free_strarray( toks );
508 * object class list is next
510 while (( tokcnt = next_line_tokens( bufp, blenp, &toks )) > 0 ) {
511 if (( ocp = (struct ldap_oclist *)calloc( 1,
512 sizeof( struct ldap_oclist ))) == NULL ) {
513 free_strarray( toks );
514 free_disptmpl( tmpl );
515 return( LDAP_TMPL_ERR_MEM );
517 ocp->oc_objclasses = toks;
518 if ( tmpl->dt_oclist == NULL ) {
519 tmpl->dt_oclist = ocp;
521 prevocp->oc_next = ocp;
526 free_disptmpl( tmpl );
527 return( LDAP_TMPL_ERR_SYNTAX );
531 * read name of attribute to authenticate as
533 if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
534 free_strarray( toks );
535 free_disptmpl( tmpl );
536 return( LDAP_TMPL_ERR_SYNTAX );
538 if ( toks[ 0 ][ 0 ] != '\0' ) {
539 tmpl->dt_authattrname = toks[ 0 ];
543 free( (char *)toks );
546 * read default attribute to use for RDN
548 if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
549 free_strarray( toks );
550 free_disptmpl( tmpl );
551 return( LDAP_TMPL_ERR_SYNTAX );
553 tmpl->dt_defrdnattrname = toks[ 0 ];
554 free( (char *)toks );
557 * read default location for new entries
559 if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
560 free_strarray( toks );
561 free_disptmpl( tmpl );
562 return( LDAP_TMPL_ERR_SYNTAX );
564 if ( toks[ 0 ][ 0 ] != '\0' ) {
565 tmpl->dt_defaddlocation = toks[ 0 ];
569 free( (char *)toks );
572 * read list of rules used to define default values for new entries
574 while (( tokcnt = next_line_tokens( bufp, blenp, &toks )) > 0 ) {
575 if ( strcasecmp( ADDEF_CONSTANT, toks[ 0 ] ) == 0 ) {
576 adsource = LDAP_ADSRC_CONSTANTVALUE;
577 } else if ( strcasecmp( ADDEF_ADDERSDN, toks[ 0 ] ) == 0 ) {
578 adsource = LDAP_ADSRC_ADDERSDN;
582 if ( adsource == 0 || tokcnt < 2 ||
583 ( adsource == LDAP_ADSRC_CONSTANTVALUE && tokcnt != 3 ) ||
584 ( adsource == LDAP_ADSRC_ADDERSDN && tokcnt != 2 )) {
585 free_strarray( toks );
586 free_disptmpl( tmpl );
587 return( LDAP_TMPL_ERR_SYNTAX );
590 if (( adp = (struct ldap_adddeflist *)calloc( 1,
591 sizeof( struct ldap_adddeflist ))) == NULL ) {
592 free_strarray( toks );
593 free_disptmpl( tmpl );
594 return( LDAP_TMPL_ERR_MEM );
596 adp->ad_source = adsource;
597 adp->ad_attrname = toks[ 1 ];
598 if ( adsource == LDAP_ADSRC_CONSTANTVALUE ) {
599 adp->ad_value = toks[ 2 ];
602 free( (char *)toks );
604 if ( tmpl->dt_adddeflist == NULL ) {
605 tmpl->dt_adddeflist = adp;
607 prevadp->ad_next = adp;
616 while (( tokcnt = next_line_tokens( bufp, blenp, &toks )) > 0 ) {
617 if ( strcasecmp( toks[ 0 ], "item" ) == 0 ) {
619 free_strarray( toks );
620 free_disptmpl( tmpl );
621 return( LDAP_TMPL_ERR_SYNTAX );
624 if (( ip = (struct ldap_tmplitem *)calloc( 1,
625 sizeof( struct ldap_tmplitem ))) == NULL ) {
626 free_strarray( toks );
627 free_disptmpl( tmpl );
628 return( LDAP_TMPL_ERR_MEM );
632 * find syntaxid from config file string
634 while (( itemopts = strrchr( toks[ 1 ], ',' )) != NULL ) {
636 for ( i = 0; itemoptions[ i ] != NULL; ++i ) {
637 if ( strcasecmp( itemopts, itemoptions[ i ] ) == 0 ) {
641 if ( itemoptions[ i ] == NULL ) {
642 free_strarray( toks );
643 free_disptmpl( tmpl );
644 return( LDAP_TMPL_ERR_SYNTAX );
646 ip->ti_options |= itemoptvals[ i ];
649 for ( i = 0; itemtypes[ i ] != NULL; ++i ) {
650 if ( strcasecmp( toks[ 1 ], itemtypes[ i ] ) == 0 ) {
654 if ( itemtypes[ i ] == NULL ) {
655 free_strarray( toks );
656 free_disptmpl( tmpl );
657 return( LDAP_TMPL_ERR_SYNTAX );
662 ip->ti_syntaxid = itemsynids[ i ];
663 ip->ti_label = toks[ 2 ];
664 if ( toks[ 3 ][ 0 ] == '\0' ) {
665 ip->ti_attrname = NULL;
668 ip->ti_attrname = toks[ 3 ];
670 if ( toks[ 4 ] != NULL ) { /* extra args. */
671 for ( i = 0; toks[ i + 4 ] != NULL; ++i ) {
674 if (( ip->ti_args = (char **) calloc( i + 1, sizeof( char * )))
676 free_disptmpl( tmpl );
677 return( LDAP_TMPL_ERR_MEM );
679 for ( i = 0; toks[ i + 4 ] != NULL; ++i ) {
680 ip->ti_args[ i ] = toks[ i + 4 ];
683 free( (char *)toks );
685 if ( tmpl->dt_items == NULL ) {
686 tmpl->dt_items = rowp = ip;
687 } else if ( samerow ) {
688 previp->ti_next_in_row = ip;
690 rowp->ti_next_in_col = ip;
695 } else if ( strcasecmp( toks[ 0 ], "samerow" ) == 0 ) {
696 free_strarray( toks );
699 free_strarray( toks );
700 free_disptmpl( tmpl );
701 return( LDAP_TMPL_ERR_SYNTAX );
705 free_disptmpl( tmpl );
706 return( LDAP_TMPL_ERR_SYNTAX );