3 * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
7 * Copyright (c) 1991, 1993
8 * Regents of the University of Michigan. All rights reserved.
10 * Redistribution and use in source and binary forms are permitted
11 * provided that this notice is preserved and that due credit is given
12 * to the University of Michigan at Ann Arbor. The name of the University
13 * may not be used to endorse or promote products derived from this
14 * software without specific prior written permission. This software
15 * is provided ``as is'' without express or implied warranty.
23 #include <ac/string.h>
33 static char *time2text(char *ldtimestr, int dateonly);
34 static long gtime(struct tm *tm);
37 * When displaying entries, display only these attributes, and in this
40 static char *person_attr_print_order[] = {
44 "facsimileTelephoneNumber",
49 "multiLineDescription",
64 static char *group_attr_print_order[] = {
66 "facsimileTelephoneNumber",
69 "multiLineDescription",
92 parse_answer( LDAPMessage *s )
96 register LDAPMessage *ep;
101 printf("->parse_answer(%x)\n", s);
108 printf(" Done clearing entry\n");
110 for (ep = ldap_first_entry(ld, s); ep != NULL; ep = ldap_next_entry(ld, ep)) {
111 BerElement *cookie = NULL;
114 printf(" Determining DN and name\n");
116 Entry.DN = ldap_get_dn(ld, ep);
119 printf(" DN = %s\n", Entry.DN);
121 rdns = ldap_explode_dn(Entry.DN, TRUE);
124 printf(" Name = %s\n", *rdns);
126 Entry.name = strdup(*rdns);
127 ldap_value_free(rdns);
128 for (ap = ldap_first_attribute(ld, ep, &cookie); ap != NULL; ap = ldap_next_attribute(ld, ep, cookie)) {
132 printf("parsing ap = %s\n", ap);
134 if ((idx = attr_to_index(ap)) < 0) {
135 printf(" Unknown attribute \"%s\"\n", ap);
138 add_value(&(Entry.attrs[idx]), ep, ap);
141 if( cookie != NULL ) {
142 ber_free( cookie, 0 );
147 printf(" Done parsing entry\n");
152 add_value( struct attribute *attr, LDAPMessage *ep, char *ap )
155 char **vp, **tp, **avp;
159 printf("->add_value(%x, %x, %s)\n", attr, ep, ap);
161 vp = (char **) ldap_get_values(ld, ep, ap);
164 * Fill in the attribute structure for this attribute. This
165 * stores away the values (using strdup()) and the count. Terminate
166 * the list with a NULL pointer.
168 * attr->quipu_name has already been set during initialization.
170 if ((attr->number_of_values = ldap_count_values(vp)) > 0) {
171 attr->values = (char **) Malloc((unsigned) ((attr->number_of_values + 1) * sizeof(char *)));
174 for (i = 1, tp = vp; *tp != NULL; i++, tp++) {
177 printf(" value #%d %s\n", i, *tp);
180 * The 'name' field of the Entry structure already has
181 * has the first part of the DN copied into it. Thus,
182 * we don't need to save it away here again. Also, by
183 * tossing it away here, we make printing this info out
184 * a bit easier later.
186 if (!strcmp(ap, "cn") && !strcmp(*tp, Entry.name)) {
187 attr->number_of_values--;
190 *avp++ = strdup(*tp);
198 print_an_entry( void )
201 char is_a_group, **order;
202 char *sub_list[MAX_VALUES], buf[SMALL_BUF_SIZE];
206 printf("->print_an_entry()\n");
209 if( Entry.name == NULL ) {
210 printf(" No Entry found.\n");
214 printf(" \"%s\"\n", Entry.name);
217 * If the entry is a group, find all of the subscribers to that
218 * group. A subscriber is an entry that *points* to a group entry,
219 * and a member is an entry that is included as part of a group
222 * We also need to select the appropriate output format here.
224 is_a_group = isgroup();
226 order = (char **) group_attr_print_order;
227 n = find_all_subscribers(sub_list, Entry.DN);
230 printf(" Group \"%s\" has %d subscribers\n",
235 order = (char **) person_attr_print_order;
237 for (i = 0; order[i] != NULL; i++) {
238 idx = attr_to_index(order[i]);
240 if (debug & D_PRINT) {
241 printf(" ATTR #%2d = %s [%s] (%d values)\n", i + 1,
242 Entry.attrs[idx].output_string,
243 Entry.attrs[idx].quipu_name,
244 Entry.attrs[idx].number_of_values);
249 if (Entry.attrs[idx].number_of_values == 0)
252 print_DN(Entry.attrs[idx]);
253 else if (isaurl(order[i]))
254 print_URL(Entry.attrs[idx]);
255 else if (isadate(order[i])) {
256 /* fix time and date, then call usual routine */
257 Entry.attrs[idx].values[0] =
258 time2text(Entry.attrs[idx].values[0], FALSE);
259 print_values(Entry.attrs[idx]);
262 print_values(Entry.attrs[idx]);
266 * If it is a group, then we should print the subscriber list (if
267 * there are any). If there are a lot of them, prompt the user
268 * before printing them.
270 if (is_a_group && (n > 0)) {
271 char *label = "Subscribers: ";
273 if (n > TOO_MANY_TO_PRINT) {
274 printf(" There are %d subscribers. Print them? ", n);
276 fetch_buffer(buf, sizeof(buf), stdin);
277 if (!((buf[0] == 'y') || (buf[0] == 'Y')))
280 format2((char *) my_ldap_dn2ufn(sub_list[n - 1]), label, (char *) NULL, 2,
281 2 + strlen(label) + 1, col_size);
282 for (n--; n > 0; n--)
283 format2((char *) my_ldap_dn2ufn(sub_list[n - 1]), (char *) NULL,
284 (char *) NULL, 2 + strlen(label),
285 2 + strlen(label) + 2, col_size);
291 #define OUT_LABEL_LEN 20
293 /* prints the values associated with an attribute */
295 print_values( struct attribute A )
298 register char *cp, **vp;
299 char out_buf[MED_BUF_SIZE], *padding = NULL;
304 printf("->print_values(%x)\n", A);
306 if (A.number_of_values == 0)
308 if ((vp = A.values) == NULL)
312 * Pad out the output string label so that it fills the
313 * whole field of length OUT_LABEL_LEN.
316 i = OUT_LABEL_LEN - strlen(A.output_string);
318 printf("Output string for \"%s\" is too long. Maximum length is %d characters\n", A.quipu_name, OUT_LABEL_LEN);
321 if (isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values == 0)) {
322 A.output_string = "Members";
323 i = OUT_LABEL_LEN - strlen(A.output_string);
324 padding = (char *) Malloc((unsigned) (i + 1));
325 (void) memset(padding, ' ', i);
326 *(padding + i) = '\0';
327 sprintf(out_buf, "%s:%s", A.output_string, padding);
329 else if (!(isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values > 0))) {
330 padding = (char *) Malloc((unsigned) (i + 1));
331 (void) memset(padding, ' ', i);
332 *(padding + i) = '\0';
333 sprintf(out_buf, "%s:%s", A.output_string, padding);
336 * If this happens to be a group, then do not print the output
337 * string if we have already printed out some members.
339 else if (isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values > 0)) {
340 padding = (char *) Malloc((unsigned) (OUT_LABEL_LEN + 2));
341 (void) memset(padding, ' ', OUT_LABEL_LEN + 1);
342 *(padding + OUT_LABEL_LEN + 1) = '\0';
343 sprintf(out_buf, "%s", padding);
345 lead = strlen(out_buf) + 2;
347 printf(" %s", out_buf);
348 for (i = 0; *vp != NULL; i++, vp++) {
350 if (!strncmp(A.output_string, "Home a", 6) || !strncmp(A.output_string, "Business a", 10)) {
351 printf(" %s", out_buf);
354 for (k = lead; k > 0; k--)
358 for (cp = *vp; *cp != '\0'; cp++) {
361 if (!strncmp(A.output_string, "Home a", 6) || !strncmp(A.output_string, "Business a", 10) || !strcmp(A.quipu_name, "multiLineDescription")) {
363 for (k = lead; k > 0; k--)
365 while (isspace((unsigned char) cp[1]))
386 /* prints the DN's associated with an attribute */
388 print_DN( struct attribute A )
392 char out_buf[MED_BUF_SIZE], *padding = NULL;
396 printf("->print_DN(%x)\n", A);
398 if (A.number_of_values == 0)
401 * Pad out the output string label so that it fills the
402 * whole field of length OUT_LABEL_LEN.
404 i = OUT_LABEL_LEN - strlen(A.output_string);
406 padding = (char *) Malloc((unsigned) (i + 1));
407 (void) memset(padding, ' ', i);
408 *(padding + i) = '\0';
409 sprintf(out_buf, "%s:%s", A.output_string, padding);
410 (void) Free(padding);
412 lead = strlen(out_buf) + 2;
415 format2((char *) my_ldap_dn2ufn(*vp), out_buf, (char *) NULL, 2, lead + 1, col_size);
416 for (vp++; *vp != NULL; vp++) {
417 format2((char *) my_ldap_dn2ufn(*vp), (char *) NULL, (char *) NULL, lead,
430 printf("->clear_entry()\n");
431 if ((debug & D_PRINT) && (Entry.name != NULL))
432 printf(" Clearing entry \"%s\"\n", Entry.name);
434 if (Entry.DN != NULL)
435 ldap_memfree(Entry.DN);
436 if (Entry.name != NULL)
438 Entry.may_join = FALSE;
439 Entry.subscriber_count = -1;
440 Entry.DN = Entry.name = NULL;
442 /* clear all of the values associated with all attributes */
443 for (i = 0; attrlist[i].quipu_name != NULL; i++) {
446 printf(" Clearing attribute \"%s\" -- ",
447 Entry.attrs[i].quipu_name);
449 if (Entry.attrs[i].values == NULL) {
452 printf(" no values, skipping\n");
458 printf(" freeing %d values\n",
459 Entry.attrs[i].number_of_values);
461 Entry.attrs[i].number_of_values = 0;
462 ldap_value_free(Entry.attrs[i].values);
463 Entry.attrs[i].values = (char **) NULL;
466 * Note: We do not clear either of the char * fields
467 * since they will always be applicable.
473 attr_to_index( char *s )
477 for (i = 0; attrlist[i].quipu_name != NULL; i++)
478 if (!strcasecmp(s, attrlist[i].quipu_name))
484 initialize_attribute_strings( void )
488 for (i = 0; attrlist[i].quipu_name != NULL; i++)
489 Entry.attrs[i].quipu_name = attrlist[i].quipu_name;
490 for (i = 0; attrlist[i].quipu_name != NULL; i++)
491 Entry.attrs[i].output_string = attrlist[i].output_string;
494 /* prints the URL/label pairs associated with an attribute */
496 print_URL( struct attribute A )
500 char out_buf[MED_BUF_SIZE], *padding = NULL;
504 printf("->print_URL(%x)\n", A);
506 if (A.number_of_values == 0)
509 * Pad out the output string label so that it fills the
510 * whole field of length OUT_LABEL_LEN.
512 i = OUT_LABEL_LEN - strlen(A.output_string);
514 padding = (char *) Malloc((unsigned) (i + 1));
515 (void) memset(padding, ' ', i);
516 *(padding + i) = '\0';
517 sprintf(out_buf, "%s:%s", A.output_string, padding);
519 lead = strlen(out_buf) + 2;
522 print_one_URL(*vp, 2, out_buf, lead);
523 for (vp++; *vp != NULL; vp++)
524 print_one_URL(*vp, lead, (char *) NULL, lead);
531 print_one_URL( char *s, int label_lead, char *tag, int url_lead )
536 for (cp = s; !isspace((unsigned char)*cp) && (*cp != '\0'); cp++)
543 for (cp++; isspace((unsigned char)*cp); cp++)
547 cp = "(no description available)";
548 format2(cp, tag, (char *) NULL, label_lead, label_lead + 1, col_size);
549 for (i = url_lead + 2; i > 0; i--)
556 #define GET2BYTENUM( p ) (( *(p) - '0' ) * 10 + ( *((p)+1) - '0' ))
559 time2text( char *ldtimestr, int dateonly )
562 char *p, *timestr, zone, *fmterr = "badly formatted time";
566 if (strlen( ldtimestr ) < 12 ) {
570 for ( ndigits=0; isdigit((unsigned char) ldtimestr[ndigits]); ndigits++) {
574 if ( ndigits != 12 && ndigits != 14) {
578 memset( (char *)&t, 0, sizeof( struct tm ));
583 /* came with a century */
584 /* POSIX says tm_year should be year - 1900 */
585 t.tm_year = 100 * GET2BYTENUM( p ) - 1900;
590 t.tm_year += GET2BYTENUM( p ); p += 2;
592 t.tm_mon = GET2BYTENUM( p ) - 1; p += 2;
593 t.tm_mday = GET2BYTENUM( p ); p += 2;
594 t.tm_hour = GET2BYTENUM( p ); p += 2;
595 t.tm_min = GET2BYTENUM( p ); p += 2;
596 t.tm_sec = GET2BYTENUM( p ); p += 2;
598 if (( zone = *p ) == 'Z' ) { /* GMT */
599 zone = '\0'; /* no need to indicate on screen, so we make it null */
602 gmttime = gtime( &t );
603 timestr = ctime( &gmttime );
605 timestr[ strlen( timestr ) - 1 ] = zone; /* replace trailing newline */
607 SAFEMEMCPY( timestr + 11, timestr + 20, strlen( timestr + 20 ) + 1 );
610 return( strdup( timestr ) );
614 /* gtime.c - inverse gmtime */
618 /* gtime(): the inverse of localtime().
619 This routine was supplied by Mike Accetta at CMU many years ago.
623 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
627 (((y) % 4) ? 365 : (((y) % 100) ? 366 : (((y) % 400) ? 365 : 366)))
632 /* per STDC & POSIX tm_year *should* be offset by 1900 */
633 #define YEAR_POSIX(y) ((y) + 1900)
636 * year is < 1900, year is offset by 1900
638 #define YEAR_CAREFUL(y) ((y) < 1900 ? (y) + 1900 : (y))
640 #define YEAR(y) YEAR_CAREFUL(y)
646 gtime( struct tm *tm )
655 register long result;
657 if ((sec = tm -> tm_sec) < 0 || sec > 59
658 || (mins = tm -> tm_min) < 0 || mins > 59
659 || (hour = tm -> tm_hour) < 0 || hour > 24
660 || (mday = tm -> tm_mday) < 1 || mday > 31
661 || (mon = tm -> tm_mon + 1) < 1 || mon > 12)
667 year = YEAR (tm -> tm_year);
670 for (i = 1970; i < year; i++)
671 result += dysize (i);
672 if (dysize (year) == 366 && mon >= 3)
675 result += dmsize[mon - 1];
677 result = 24 * result + hour;
678 result = 60 * result + mins;
679 result = 60 * result + sec;