3 * Copyright 1998-2000 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>
32 static char *time2text(char *ldtimestr, int dateonly);
33 static long gtime(struct tm *tm);
36 * When displaying entries, display only these attributes, and in this
39 static char *person_attr_print_order[] = {
43 "facsimileTelephoneNumber",
48 "multiLineDescription",
63 static char *group_attr_print_order[] = {
65 "facsimileTelephoneNumber",
68 "multiLineDescription",
91 parse_answer( LDAPMessage *s )
95 register LDAPMessage *ep;
100 printf("->parse_answer(%x)\n", s);
107 printf(" Done clearing entry\n");
109 for (ep = ldap_first_entry(ld, s); ep != NULL; ep = ldap_next_entry(ld, ep)) {
110 BerElement *cookie = NULL;
113 printf(" Determining DN and name\n");
115 Entry.DN = ldap_get_dn(ld, ep);
118 printf(" DN = %s\n", Entry.DN);
120 rdns = ldap_explode_dn(Entry.DN, TRUE);
123 printf(" Name = %s\n", *rdns);
125 Entry.name = strdup(*rdns);
126 ldap_value_free(rdns);
127 for (ap = ldap_first_attribute(ld, ep, &cookie); ap != NULL; ap = ldap_next_attribute(ld, ep, cookie)) {
131 printf("parsing ap = %s\n", ap);
133 if ((idx = attr_to_index(ap)) < 0) {
134 printf(" Unknown attribute \"%s\"\n", ap);
137 add_value(&(Entry.attrs[idx]), ep, ap);
140 if( cookie != NULL ) {
141 ber_free( cookie, 0 );
146 printf(" Done parsing entry\n");
151 add_value( struct attribute *attr, LDAPMessage *ep, char *ap )
154 char **vp, **tp, **avp;
158 printf("->add_value(%x, %x, %s)\n", attr, ep, ap);
160 vp = (char **) ldap_get_values(ld, ep, ap);
163 * Fill in the attribute structure for this attribute. This
164 * stores away the values (using strdup()) and the count. Terminate
165 * the list with a NULL pointer.
167 * attr->quipu_name has already been set during initialization.
169 if ((attr->number_of_values = ldap_count_values(vp)) > 0) {
170 attr->values = (char **) Malloc((unsigned) ((attr->number_of_values + 1) * sizeof(char *)));
173 for (i = 1, tp = vp; *tp != NULL; i++, tp++) {
176 printf(" value #%d %s\n", i, *tp);
179 * The 'name' field of the Entry structure already has
180 * has the first part of the DN copied into it. Thus,
181 * we don't need to save it away here again. Also, by
182 * tossing it away here, we make printing this info out
183 * a bit easier later.
185 if (!strcmp(ap, "cn") && !strcmp(*tp, Entry.name)) {
186 attr->number_of_values--;
189 *avp++ = strdup(*tp);
197 print_an_entry( void )
200 char is_a_group, **order;
201 char *sub_list[MAX_VALUES], buf[SMALL_BUF_SIZE];
205 printf("->print_an_entry()\n");
208 if( Entry.name == NULL ) {
209 printf(" No Entry found.\n");
213 printf(" \"%s\"\n", Entry.name);
216 * If the entry is a group, find all of the subscribers to that
217 * group. A subscriber is an entry that *points* to a group entry,
218 * and a member is an entry that is included as part of a group
221 * We also need to select the appropriate output format here.
223 is_a_group = isgroup();
225 order = (char **) group_attr_print_order;
226 n = find_all_subscribers(sub_list, Entry.DN);
229 printf(" Group \"%s\" has %d subscribers\n",
234 order = (char **) person_attr_print_order;
236 for (i = 0; order[i] != NULL; i++) {
237 idx = attr_to_index(order[i]);
239 if (debug & D_PRINT) {
240 printf(" ATTR #%2d = %s [%s] (%d values)\n", i + 1,
241 Entry.attrs[idx].output_string,
242 Entry.attrs[idx].quipu_name,
243 Entry.attrs[idx].number_of_values);
248 if (Entry.attrs[idx].number_of_values == 0)
251 print_DN(Entry.attrs[idx]);
252 else if (isaurl(order[i]))
253 print_URL(Entry.attrs[idx]);
254 else if (isadate(order[i])) {
255 /* fix time and date, then call usual routine */
256 Entry.attrs[idx].values[0] =
257 time2text(Entry.attrs[idx].values[0], FALSE);
258 print_values(Entry.attrs[idx]);
261 print_values(Entry.attrs[idx]);
265 * If it is a group, then we should print the subscriber list (if
266 * there are any). If there are a lot of them, prompt the user
267 * before printing them.
269 if (is_a_group && (n > 0)) {
270 char *label = "Subscribers: ";
272 if (n > TOO_MANY_TO_PRINT) {
273 printf(" There are %d subscribers. Print them? ", n);
275 fetch_buffer(buf, sizeof(buf), stdin);
276 if (!((buf[0] == 'y') || (buf[0] == 'Y')))
279 format2((char *) my_ldap_dn2ufn(sub_list[n - 1]), label, (char *) NULL, 2,
280 2 + strlen(label) + 1, col_size);
281 for (n--; n > 0; n--)
282 format2((char *) my_ldap_dn2ufn(sub_list[n - 1]), (char *) NULL,
283 (char *) NULL, 2 + strlen(label),
284 2 + strlen(label) + 2, col_size);
290 #define OUT_LABEL_LEN 20
292 /* prints the values associated with an attribute */
294 print_values( struct attribute A )
297 register char *cp, **vp;
298 char out_buf[MED_BUF_SIZE], *padding = NULL;
303 printf("->print_values(%x)\n", A);
305 if (A.number_of_values == 0)
307 if ((vp = A.values) == NULL)
311 * Pad out the output string label so that it fills the
312 * whole field of length OUT_LABEL_LEN.
315 i = OUT_LABEL_LEN - strlen(A.output_string);
317 printf("Output string for \"%s\" is too long. Maximum length is %d characters\n", A.quipu_name, OUT_LABEL_LEN);
320 if (isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values == 0)) {
321 A.output_string = "Members";
322 i = OUT_LABEL_LEN - strlen(A.output_string);
323 padding = (char *) Malloc((unsigned) (i + 1));
324 (void) memset(padding, ' ', i);
325 *(padding + i) = '\0';
326 sprintf(out_buf, "%s:%s", A.output_string, padding);
328 else if (!(isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values > 0))) {
329 padding = (char *) Malloc((unsigned) (i + 1));
330 (void) memset(padding, ' ', i);
331 *(padding + i) = '\0';
332 sprintf(out_buf, "%s:%s", A.output_string, padding);
335 * If this happens to be a group, then do not print the output
336 * string if we have already printed out some members.
338 else if (isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values > 0)) {
339 padding = (char *) Malloc((unsigned) (OUT_LABEL_LEN + 2));
340 (void) memset(padding, ' ', OUT_LABEL_LEN + 1);
341 *(padding + OUT_LABEL_LEN + 1) = '\0';
342 sprintf(out_buf, "%s", padding);
344 lead = strlen(out_buf) + 2;
346 printf(" %s", out_buf);
347 for (i = 0; *vp != NULL; i++, vp++) {
349 if (!strncmp(A.output_string, "Home a", 6) || !strncmp(A.output_string, "Business a", 10)) {
350 printf(" %s", out_buf);
353 for (k = lead; k > 0; k--)
357 for (cp = *vp; *cp != '\0'; cp++) {
360 if (!strncmp(A.output_string, "Home a", 6) || !strncmp(A.output_string, "Business a", 10) || !strcmp(A.quipu_name, "multiLineDescription")) {
362 for (k = lead; k > 0; k--)
364 while (isspace((unsigned char) cp[1]))
385 /* prints the DN's associated with an attribute */
387 print_DN( struct attribute A )
391 char out_buf[MED_BUF_SIZE], *padding = NULL;
395 printf("->print_DN(%x)\n", A);
397 if (A.number_of_values == 0)
400 * Pad out the output string label so that it fills the
401 * whole field of length OUT_LABEL_LEN.
403 i = OUT_LABEL_LEN - strlen(A.output_string);
405 padding = (char *) Malloc((unsigned) (i + 1));
406 (void) memset(padding, ' ', i);
407 *(padding + i) = '\0';
408 sprintf(out_buf, "%s:%s", A.output_string, padding);
409 (void) Free(padding);
411 lead = strlen(out_buf) + 2;
414 format2((char *) my_ldap_dn2ufn(*vp), out_buf, (char *) NULL, 2, lead + 1, col_size);
415 for (vp++; *vp != NULL; vp++) {
416 format2((char *) my_ldap_dn2ufn(*vp), (char *) NULL, (char *) NULL, lead,
429 printf("->clear_entry()\n");
430 if ((debug & D_PRINT) && (Entry.name != NULL))
431 printf(" Clearing entry \"%s\"\n", Entry.name);
433 if (Entry.DN != NULL)
434 ldap_memfree(Entry.DN);
435 if (Entry.name != NULL)
437 Entry.may_join = FALSE;
438 Entry.subscriber_count = -1;
439 Entry.DN = Entry.name = NULL;
441 /* clear all of the values associated with all attributes */
442 for (i = 0; attrlist[i].quipu_name != NULL; i++) {
445 printf(" Clearing attribute \"%s\" -- ",
446 Entry.attrs[i].quipu_name);
448 if (Entry.attrs[i].values == NULL) {
451 printf(" no values, skipping\n");
457 printf(" freeing %d values\n",
458 Entry.attrs[i].number_of_values);
460 Entry.attrs[i].number_of_values = 0;
461 ldap_value_free(Entry.attrs[i].values);
462 Entry.attrs[i].values = (char **) NULL;
465 * Note: We do not clear either of the char * fields
466 * since they will always be applicable.
472 attr_to_index( char *s )
476 for (i = 0; attrlist[i].quipu_name != NULL; i++)
477 if (!strcasecmp(s, attrlist[i].quipu_name))
483 initialize_attribute_strings( void )
487 for (i = 0; attrlist[i].quipu_name != NULL; i++)
488 Entry.attrs[i].quipu_name = attrlist[i].quipu_name;
489 for (i = 0; attrlist[i].quipu_name != NULL; i++)
490 Entry.attrs[i].output_string = attrlist[i].output_string;
493 /* prints the URL/label pairs associated with an attribute */
495 print_URL( struct attribute A )
499 char out_buf[MED_BUF_SIZE], *padding = NULL;
503 printf("->print_URL(%x)\n", A);
505 if (A.number_of_values == 0)
508 * Pad out the output string label so that it fills the
509 * whole field of length OUT_LABEL_LEN.
511 i = OUT_LABEL_LEN - strlen(A.output_string);
513 padding = (char *) Malloc((unsigned) (i + 1));
514 (void) memset(padding, ' ', i);
515 *(padding + i) = '\0';
516 sprintf(out_buf, "%s:%s", A.output_string, padding);
518 lead = strlen(out_buf) + 2;
521 print_one_URL(*vp, 2, out_buf, lead);
522 for (vp++; *vp != NULL; vp++)
523 print_one_URL(*vp, lead, (char *) NULL, lead);
530 print_one_URL( char *s, int label_lead, char *tag, int url_lead )
535 for (cp = s; !isspace((unsigned char)*cp) && (*cp != '\0'); cp++)
542 for (cp++; isspace((unsigned char)*cp); cp++)
546 cp = "(no description available)";
547 format2(cp, tag, (char *) NULL, label_lead, label_lead + 1, col_size);
548 for (i = url_lead + 2; i > 0; i--)
555 #define GET2BYTENUM( p ) (( *(p) - '0' ) * 10 + ( *((p)+1) - '0' ))
558 time2text( char *ldtimestr, int dateonly )
561 char *p, *timestr, zone, *fmterr = "badly formatted time";
565 if (strlen( ldtimestr ) < 12 ) {
569 for ( ndigits=0; isdigit((unsigned char) ldtimestr[ndigits]); ndigits++) {
573 if ( ndigits != 12 && ndigits != 14) {
577 memset( (char *)&t, '\0', sizeof( struct tm ));
582 /* came with a century */
583 /* POSIX says tm_year should be year - 1900 */
584 t.tm_year = 100 * GET2BYTENUM( p ) - 1900;
589 t.tm_year += GET2BYTENUM( p ); p += 2;
591 t.tm_mon = GET2BYTENUM( p ) - 1; p += 2;
592 t.tm_mday = GET2BYTENUM( p ); p += 2;
593 t.tm_hour = GET2BYTENUM( p ); p += 2;
594 t.tm_min = GET2BYTENUM( p ); p += 2;
595 t.tm_sec = GET2BYTENUM( p ); p += 2;
597 if (( zone = *p ) == 'Z' ) { /* GMT */
598 zone = '\0'; /* no need to indicate on screen, so we make it null */
601 gmttime = gtime( &t );
602 timestr = ctime( &gmttime );
604 timestr[ strlen( timestr ) - 1 ] = zone; /* replace trailing newline */
606 AC_MEMCPY( timestr + 11, timestr + 20, strlen( timestr + 20 ) + 1 );
609 return( strdup( timestr ) );
613 /* gtime.c - inverse gmtime */
617 /* gtime(): the inverse of localtime().
618 This routine was supplied by Mike Accetta at CMU many years ago.
622 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
626 (((y) % 4) ? 365 : (((y) % 100) ? 366 : (((y) % 400) ? 365 : 366)))
631 /* per STDC & POSIX tm_year *should* be offset by 1900 */
632 #define YEAR_POSIX(y) ((y) + 1900)
635 * year is < 1900, year is offset by 1900
637 #define YEAR_CAREFUL(y) ((y) < 1900 ? (y) + 1900 : (y))
639 #define YEAR(y) YEAR_CAREFUL(y)
645 gtime( struct tm *tm )
654 register long result;
656 if ((sec = tm -> tm_sec) < 0 || sec > 59
657 || (mins = tm -> tm_min) < 0 || mins > 59
658 || (hour = tm -> tm_hour) < 0 || hour > 24
659 || (mday = tm -> tm_mday) < 1 || mday > 31
660 || (mon = tm -> tm_mon + 1) < 1 || mon > 12)
666 year = YEAR (tm -> tm_year);
669 for (i = 1970; i < year; i++)
670 result += dysize (i);
671 if (dysize (year) == 366 && mon >= 3)
674 result += dmsize[mon - 1];
676 result = 24 * result + hour;
677 result = 60 * result + mins;
678 result = 60 * result + sec;