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>
26 #ifdef HAVE_SYS_FILE_H
33 static void free_disptmpl LDAP_P(( struct ldap_disptmpl *tmpl ));
34 static int read_next_tmpl LDAP_P(( char **bufp, long *blenp,
35 struct ldap_disptmpl **tmplp, int dtversion ));
37 static char *tmploptions[] = {
44 static unsigned long tmploptvals[] = {
45 LDAP_DTMPL_OPT_ADDABLE, LDAP_DTMPL_OPT_ALLOWMODRDN,
46 LDAP_DTMPL_OPT_ALTVIEW,
50 static char *itemtypes[] = {
52 "bool", "jpeg", "jpegbtn",
53 "fax", "faxbtn", "audiobtn",
54 "time", "date", "url",
55 "searchact", "linkact", "adddnact",
56 "addact", "verifyact", "mail",
60 static unsigned long itemsynids[] = {
61 LDAP_SYN_CASEIGNORESTR, LDAP_SYN_MULTILINESTR, LDAP_SYN_DN,
62 LDAP_SYN_BOOLEAN, LDAP_SYN_JPEGIMAGE, LDAP_SYN_JPEGBUTTON,
63 LDAP_SYN_FAXIMAGE, LDAP_SYN_FAXBUTTON, LDAP_SYN_AUDIOBUTTON,
64 LDAP_SYN_TIME, LDAP_SYN_DATE, LDAP_SYN_LABELEDURL,
65 LDAP_SYN_SEARCHACTION, LDAP_SYN_LINKACTION, LDAP_SYN_ADDDNACTION,
66 LDAP_SYN_ADDDNACTION, LDAP_SYN_VERIFYDNACTION,LDAP_SYN_RFC822ADDR,
70 static char *itemoptions[] = {
73 "required", "hideiffalse",
78 static unsigned long itemoptvals[] = {
79 LDAP_DITEM_OPT_READONLY, LDAP_DITEM_OPT_SORTVALUES,
80 LDAP_DITEM_OPT_SINGLEVALUED, LDAP_DITEM_OPT_HIDEIFEMPTY,
81 LDAP_DITEM_OPT_VALUEREQUIRED, LDAP_DITEM_OPT_HIDEIFFALSE,
85 #define ADDEF_CONSTANT "constant"
86 #define ADDEF_ADDERSDN "addersdn"
90 ldap_init_templates( char *file, struct ldap_disptmpl **tmpllistp )
97 *tmpllistp = NULLDISPTMPL;
99 if (( fp = fopen( file, "r" )) == NULL ) {
100 return( LDAP_TMPL_ERR_FILE );
103 if ( fseek( fp, 0L, SEEK_END ) != 0 ) { /* move to end to get len */
105 return( LDAP_TMPL_ERR_FILE );
110 if ( fseek( fp, 0L, SEEK_SET ) != 0 ) { /* back to start of file */
112 return( LDAP_TMPL_ERR_FILE );
115 if (( buf = malloc( (size_t)len )) == NULL ) {
117 return( LDAP_TMPL_ERR_MEM );
120 rlen = fread( buf, 1, (size_t)len, fp );
124 if ( rlen != len && !eof ) { /* error: didn't get the whole file */
126 return( LDAP_TMPL_ERR_FILE );
129 rc = ldap_init_templates_buf( buf, rlen, tmpllistp );
137 ldap_init_templates_buf( char *buf, long buflen,
138 struct ldap_disptmpl **tmpllistp )
142 struct ldap_disptmpl *prevtmpl, *tmpl;
144 *tmpllistp = prevtmpl = NULLDISPTMPL;
146 if ( next_line_tokens( &buf, &buflen, &toks ) != 2 ||
147 strcasecmp( toks[ 0 ], "version" ) != 0 ) {
148 free_strarray( toks );
149 return( LDAP_TMPL_ERR_SYNTAX );
151 version = atoi( toks[ 1 ] );
152 free_strarray( toks );
153 if ( version != LDAP_TEMPLATE_VERSION ) {
154 return( LDAP_TMPL_ERR_VERSION );
157 while ( buflen > 0 && ( rc = read_next_tmpl( &buf, &buflen, &tmpl,
158 version )) == 0 && tmpl != NULLDISPTMPL ) {
159 if ( prevtmpl == NULLDISPTMPL ) {
162 prevtmpl->dt_next = tmpl;
168 ldap_free_templates( *tmpllistp );
177 ldap_free_templates( struct ldap_disptmpl *tmpllist )
179 struct ldap_disptmpl *tp, *nexttp;
181 if ( tmpllist != NULL ) {
182 for ( tp = tmpllist; tp != NULL; tp = nexttp ) {
183 nexttp = tp->dt_next;
191 free_disptmpl( struct ldap_disptmpl *tmpl )
193 if ( tmpl != NULL ) {
194 if ( tmpl->dt_name != NULL ) {
195 free( tmpl->dt_name );
198 if ( tmpl->dt_pluralname != NULL ) {
199 free( tmpl->dt_pluralname );
202 if ( tmpl->dt_iconname != NULL ) {
203 free( tmpl->dt_iconname );
206 if ( tmpl->dt_authattrname != NULL ) {
207 free( tmpl->dt_authattrname );
210 if ( tmpl->dt_defrdnattrname != NULL ) {
211 free( tmpl->dt_defrdnattrname );
214 if ( tmpl->dt_defaddlocation != NULL ) {
215 free( tmpl->dt_defaddlocation );
218 if ( tmpl->dt_oclist != NULL ) {
219 struct ldap_oclist *ocp, *nextocp;
221 for ( ocp = tmpl->dt_oclist; ocp != NULL; ocp = nextocp ) {
222 nextocp = ocp->oc_next;
223 free_strarray( ocp->oc_objclasses );
228 if ( tmpl->dt_adddeflist != NULL ) {
229 struct ldap_adddeflist *adp, *nextadp;
231 for ( adp = tmpl->dt_adddeflist; adp != NULL; adp = nextadp ) {
232 nextadp = adp->ad_next;
233 if( adp->ad_attrname != NULL ) {
234 free( adp->ad_attrname );
236 if( adp->ad_value != NULL ) {
237 free( adp->ad_value );
243 if ( tmpl->dt_items != NULL ) {
244 struct ldap_tmplitem *rowp, *nextrowp, *colp, *nextcolp;
246 for ( rowp = tmpl->dt_items; rowp != NULL; rowp = nextrowp ) {
247 nextrowp = rowp->ti_next_in_col;
248 for ( colp = rowp; colp != NULL; colp = nextcolp ) {
249 nextcolp = colp->ti_next_in_row;
250 if ( colp->ti_attrname != NULL ) {
251 free( colp->ti_attrname );
253 if ( colp->ti_label != NULL ) {
254 free( colp->ti_label );
256 if ( colp->ti_args != NULL ) {
257 free_strarray( colp->ti_args );
269 struct ldap_disptmpl *
270 ldap_first_disptmpl( struct ldap_disptmpl *tmpllist )
276 struct ldap_disptmpl *
277 ldap_next_disptmpl( struct ldap_disptmpl *tmpllist,
278 struct ldap_disptmpl *tmpl )
280 return( tmpl == NULLDISPTMPL ? tmpl : tmpl->dt_next );
284 struct ldap_disptmpl *
285 ldap_name2template( char *name, struct ldap_disptmpl *tmpllist )
287 struct ldap_disptmpl *dtp;
289 for ( dtp = ldap_first_disptmpl( tmpllist ); dtp != NULLDISPTMPL;
290 dtp = ldap_next_disptmpl( tmpllist, dtp )) {
291 if ( strcasecmp( name, dtp->dt_name ) == 0 ) {
296 return( NULLDISPTMPL );
300 struct ldap_disptmpl *
301 ldap_oc2template( char **oclist, struct ldap_disptmpl *tmpllist )
303 struct ldap_disptmpl *dtp;
304 struct ldap_oclist *oclp;
305 int i, j, needcnt, matchcnt;
307 if ( tmpllist == NULL || oclist == NULL || oclist[ 0 ] == NULL ) {
308 return( NULLDISPTMPL );
311 for ( dtp = ldap_first_disptmpl( tmpllist ); dtp != NULLDISPTMPL;
312 dtp = ldap_next_disptmpl( tmpllist, dtp )) {
313 for ( oclp = dtp->dt_oclist; oclp != NULLOCLIST;
314 oclp = oclp->oc_next ) {
315 needcnt = matchcnt = 0;
316 for ( i = 0; oclp->oc_objclasses[ i ] != NULL; ++i ) {
317 for ( j = 0; oclist[ j ] != NULL; ++j ) {
318 if ( strcasecmp( oclist[ j ], oclp->oc_objclasses[ i ] )
326 if ( matchcnt == needcnt ) {
332 return( NULLDISPTMPL );
336 struct ldap_tmplitem *
337 ldap_first_tmplrow( struct ldap_disptmpl *tmpl )
339 return( tmpl->dt_items );
343 struct ldap_tmplitem *
344 ldap_next_tmplrow( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row )
346 return( row == NULLTMPLITEM ? row : row->ti_next_in_col );
350 struct ldap_tmplitem *
351 ldap_first_tmplcol( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row )
357 struct ldap_tmplitem *
358 ldap_next_tmplcol( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row,
359 struct ldap_tmplitem *col )
361 return( col == NULLTMPLITEM ? col : col->ti_next_in_row );
366 ldap_tmplattrs( struct ldap_disptmpl *tmpl, char **includeattrs,
367 int exclude, unsigned long syntaxmask )
370 * this routine should filter out duplicate attributes...
372 struct ldap_tmplitem *tirowp, *ticolp;
373 int i, attrcnt, memerr;
379 if (( attrs = (char **)malloc( sizeof( char * ))) == NULL ) {
383 if ( includeattrs != NULL ) {
384 for ( i = 0; !memerr && includeattrs[ i ] != NULL; ++i ) {
385 if (( attrs = (char **)realloc( attrs, ( attrcnt + 2 ) *
386 sizeof( char * ))) == NULL || ( attrs[ attrcnt++ ] =
387 ldap_strdup( includeattrs[ i ] )) == NULL ) {
390 attrs[ attrcnt ] = NULL;
395 for ( tirowp = ldap_first_tmplrow( tmpl );
396 !memerr && tirowp != NULLTMPLITEM;
397 tirowp = ldap_next_tmplrow( tmpl, tirowp )) {
398 for ( ticolp = ldap_first_tmplcol( tmpl, tirowp );
399 ticolp != NULLTMPLITEM;
400 ticolp = ldap_next_tmplcol( tmpl, tirowp, ticolp )) {
402 if ( syntaxmask != 0 ) {
404 ( syntaxmask & ticolp->ti_syntaxid ) != 0 ) ||
406 ( syntaxmask & ticolp->ti_syntaxid ) == 0 )) {
411 if ( ticolp->ti_attrname != NULL ) {
412 if (( attrs = (char **)realloc( attrs, ( attrcnt + 2 ) *
413 sizeof( char * ))) == NULL || ( attrs[ attrcnt++ ] =
414 ldap_strdup( ticolp->ti_attrname )) == NULL ) {
417 attrs[ attrcnt ] = NULL;
423 if ( memerr || attrcnt == 0 ) {
424 for ( i = 0; i < attrcnt; ++i ) {
425 if ( attrs[ i ] != NULL ) {
430 free( (char *)attrs );
439 read_next_tmpl( char **bufp, long *blenp, struct ldap_disptmpl **tmplp,
442 int i, j, tokcnt, samerow, adsource;
443 char **toks, *itemopts;
444 struct ldap_disptmpl *tmpl;
445 struct ldap_oclist *ocp, *prevocp = NULL;
446 struct ldap_adddeflist *adp, *prevadp = NULL;
447 struct ldap_tmplitem *rowp = NULL, *ip, *previp = NULL;
452 * template name comes first
454 if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
455 free_strarray( toks );
456 return( tokcnt == 0 ? 0 : LDAP_TMPL_ERR_SYNTAX );
459 if (( tmpl = (struct ldap_disptmpl *)calloc( 1,
460 sizeof( struct ldap_disptmpl ))) == NULL ) {
461 free_strarray( toks );
462 return( LDAP_TMPL_ERR_MEM );
464 tmpl->dt_name = toks[ 0 ];
465 free( (char *)toks );
468 * template plural name comes next
470 if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
471 free_strarray( toks );
472 free_disptmpl( tmpl );
473 return( LDAP_TMPL_ERR_SYNTAX );
475 tmpl->dt_pluralname = toks[ 0 ];
476 free( (char *)toks );
479 * template icon name is next
481 if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
482 free_strarray( toks );
483 free_disptmpl( tmpl );
484 return( LDAP_TMPL_ERR_SYNTAX );
486 tmpl->dt_iconname = toks[ 0 ];
487 free( (char *)toks );
490 * template options come next
492 if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) < 1 ) {
493 free_strarray( toks );
494 free_disptmpl( tmpl );
495 return( LDAP_TMPL_ERR_SYNTAX );
497 for ( i = 0; toks[ i ] != NULL; ++i ) {
498 for ( j = 0; tmploptions[ j ] != NULL; ++j ) {
499 if ( strcasecmp( toks[ i ], tmploptions[ j ] ) == 0 ) {
500 tmpl->dt_options |= tmploptvals[ j ];
504 free_strarray( toks );
507 * object class list is next
509 while (( tokcnt = next_line_tokens( bufp, blenp, &toks )) > 0 ) {
510 if (( ocp = (struct ldap_oclist *)calloc( 1,
511 sizeof( struct ldap_oclist ))) == NULL ) {
512 free_strarray( toks );
513 free_disptmpl( tmpl );
514 return( LDAP_TMPL_ERR_MEM );
516 ocp->oc_objclasses = toks;
517 if ( tmpl->dt_oclist == NULL ) {
518 tmpl->dt_oclist = ocp;
520 prevocp->oc_next = ocp;
525 free_disptmpl( tmpl );
526 return( LDAP_TMPL_ERR_SYNTAX );
530 * read name of attribute to authenticate as
532 if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
533 free_strarray( toks );
534 free_disptmpl( tmpl );
535 return( LDAP_TMPL_ERR_SYNTAX );
537 if ( toks[ 0 ][ 0 ] != '\0' ) {
538 tmpl->dt_authattrname = toks[ 0 ];
542 free( (char *)toks );
545 * read default attribute to use for RDN
547 if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
548 free_strarray( toks );
549 free_disptmpl( tmpl );
550 return( LDAP_TMPL_ERR_SYNTAX );
552 tmpl->dt_defrdnattrname = toks[ 0 ];
553 free( (char *)toks );
556 * read default location for new entries
558 if (( tokcnt = next_line_tokens( bufp, blenp, &toks )) != 1 ) {
559 free_strarray( toks );
560 free_disptmpl( tmpl );
561 return( LDAP_TMPL_ERR_SYNTAX );
563 if ( toks[ 0 ][ 0 ] != '\0' ) {
564 tmpl->dt_defaddlocation = toks[ 0 ];
568 free( (char *)toks );
571 * read list of rules used to define default values for new entries
573 while (( tokcnt = next_line_tokens( bufp, blenp, &toks )) > 0 ) {
574 if ( strcasecmp( ADDEF_CONSTANT, toks[ 0 ] ) == 0 ) {
575 adsource = LDAP_ADSRC_CONSTANTVALUE;
576 } else if ( strcasecmp( ADDEF_ADDERSDN, toks[ 0 ] ) == 0 ) {
577 adsource = LDAP_ADSRC_ADDERSDN;
581 if ( adsource == 0 || tokcnt < 2 ||
582 ( adsource == LDAP_ADSRC_CONSTANTVALUE && tokcnt != 3 ) ||
583 ( adsource == LDAP_ADSRC_ADDERSDN && tokcnt != 2 )) {
584 free_strarray( toks );
585 free_disptmpl( tmpl );
586 return( LDAP_TMPL_ERR_SYNTAX );
589 if (( adp = (struct ldap_adddeflist *)calloc( 1,
590 sizeof( struct ldap_adddeflist ))) == NULL ) {
591 free_strarray( toks );
592 free_disptmpl( tmpl );
593 return( LDAP_TMPL_ERR_MEM );
595 adp->ad_source = adsource;
596 adp->ad_attrname = toks[ 1 ];
597 if ( adsource == LDAP_ADSRC_CONSTANTVALUE ) {
598 adp->ad_value = toks[ 2 ];
601 free( (char *)toks );
603 if ( tmpl->dt_adddeflist == NULL ) {
604 tmpl->dt_adddeflist = adp;
606 prevadp->ad_next = adp;
615 while (( tokcnt = next_line_tokens( bufp, blenp, &toks )) > 0 ) {
616 if ( strcasecmp( toks[ 0 ], "item" ) == 0 ) {
618 free_strarray( toks );
619 free_disptmpl( tmpl );
620 return( LDAP_TMPL_ERR_SYNTAX );
623 if (( ip = (struct ldap_tmplitem *)calloc( 1,
624 sizeof( struct ldap_tmplitem ))) == NULL ) {
625 free_strarray( toks );
626 free_disptmpl( tmpl );
627 return( LDAP_TMPL_ERR_MEM );
631 * find syntaxid from config file string
633 while (( itemopts = strrchr( toks[ 1 ], ',' )) != NULL ) {
635 for ( i = 0; itemoptions[ i ] != NULL; ++i ) {
636 if ( strcasecmp( itemopts, itemoptions[ i ] ) == 0 ) {
640 if ( itemoptions[ i ] == NULL ) {
641 free_strarray( toks );
642 free_disptmpl( tmpl );
643 return( LDAP_TMPL_ERR_SYNTAX );
645 ip->ti_options |= itemoptvals[ i ];
648 for ( i = 0; itemtypes[ i ] != NULL; ++i ) {
649 if ( strcasecmp( toks[ 1 ], itemtypes[ i ] ) == 0 ) {
653 if ( itemtypes[ i ] == NULL ) {
654 free_strarray( toks );
655 free_disptmpl( tmpl );
656 return( LDAP_TMPL_ERR_SYNTAX );
661 ip->ti_syntaxid = itemsynids[ i ];
662 ip->ti_label = toks[ 2 ];
663 if ( toks[ 3 ][ 0 ] == '\0' ) {
664 ip->ti_attrname = NULL;
667 ip->ti_attrname = toks[ 3 ];
669 if ( toks[ 4 ] != NULL ) { /* extra args. */
670 for ( i = 0; toks[ i + 4 ] != NULL; ++i ) {
673 if (( ip->ti_args = (char **) calloc( i + 1, sizeof( char * )))
675 free_disptmpl( tmpl );
676 return( LDAP_TMPL_ERR_MEM );
678 for ( i = 0; toks[ i + 4 ] != NULL; ++i ) {
679 ip->ti_args[ i ] = toks[ i + 4 ];
682 free( (char *)toks );
684 if ( tmpl->dt_items == NULL ) {
685 tmpl->dt_items = rowp = ip;
686 } else if ( samerow ) {
687 previp->ti_next_in_row = ip;
689 rowp->ti_next_in_col = ip;
694 } else if ( strcasecmp( toks[ 0 ], "samerow" ) == 0 ) {
695 free_strarray( toks );
698 free_strarray( toks );
699 free_disptmpl( tmpl );
700 return( LDAP_TMPL_ERR_SYNTAX );
704 free_disptmpl( tmpl );
705 return( LDAP_TMPL_ERR_SYNTAX );