2 * Copyright (c) 1991, 1993
3 * Regents of the University of Michigan. All rights reserved.
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.
18 #include <ac/string.h>
28 static char *time2text(char *ldtimestr, int dateonly);
29 static long gtime(struct tm *tm);
32 * When displaying entries, display only these attributes, and in this
35 static char *person_attr_print_order[] = {
39 "facsimileTelephoneNumber",
44 "multiLineDescription",
57 static char *group_attr_print_order[] = {
59 "facsimileTelephoneNumber",
62 "multiLineDescription",
81 parse_answer( LDAPMessage *s )
85 register LDAPMessage *ep;
90 printf("->parse_answer(%x)\n", s);
97 printf(" Done clearing entry\n");
99 for (ep = ldap_first_entry(ld, s); ep != NULL; ep = ldap_next_entry(ld, ep)) {
100 BerElement *cookie = NULL;
103 printf(" Determining DN and name\n");
105 Entry.DN = ldap_get_dn(ld, ep);
108 printf(" DN = %s\n", Entry.DN);
110 rdns = ldap_explode_dn(Entry.DN, TRUE);
113 printf(" Name = %s\n", *rdns);
115 Entry.name = strdup(*rdns);
116 ldap_value_free(rdns);
117 for (ap = ldap_first_attribute(ld, ep, &cookie); ap != NULL; ap = ldap_next_attribute(ld, ep, cookie)) {
121 printf("parsing ap = %s\n", ap);
123 if ((idx = attr_to_index(ap)) < 0) {
124 printf(" Unknown attribute \"%s\"\n", ap);
127 add_value(&(Entry.attrs[idx]), ep, ap);
130 if( cookie != NULL ) {
131 ber_free( cookie, 0 );
136 printf(" Done parsing entry\n");
141 add_value( struct attribute *attr, LDAPMessage *ep, char *ap )
144 char **vp, **tp, **avp;
148 printf("->add_value(%x, %x, %s)\n", attr, ep, ap);
150 vp = (char **) ldap_get_values(ld, ep, ap);
153 * Fill in the attribute structure for this attribute. This
154 * stores away the values (using strdup()) and the count. Terminate
155 * the list with a NULL pointer.
157 * attr->quipu_name has already been set during initialization.
159 if ((attr->number_of_values = ldap_count_values(vp)) > 0) {
160 attr->values = (char **) Malloc((unsigned) ((attr->number_of_values + 1) * sizeof(char *)));
163 for (i = 1, tp = vp; *tp != NULL; i++, tp++) {
166 printf(" value #%d %s\n", i, *tp);
169 * The 'name' field of the Entry structure already has
170 * has the first part of the DN copied into it. Thus,
171 * we don't need to save it away here again. Also, by
172 * tossing it away here, we make printing this info out
173 * a bit easier later.
175 if (!strcmp(ap, "cn") && !strcmp(*tp, Entry.name)) {
176 attr->number_of_values--;
179 *avp++ = strdup(*tp);
187 print_an_entry( void )
190 char is_a_group, **order;
191 char *sub_list[MAX_VALUES], buf[SMALL_BUF_SIZE];
195 printf("->print_an_entry()\n");
197 printf(" \"%s\"\n", Entry.name);
200 * If the entry is a group, find all of the subscribers to that
201 * group. A subscriber is an entry that *points* to a group entry,
202 * and a member is an entry that is included as part of a group
205 * We also need to select the appropriate output format here.
207 is_a_group = isgroup();
209 order = (char **) group_attr_print_order;
210 n = find_all_subscribers(sub_list, Entry.DN);
213 printf(" Group \"%s\" has %d subscribers\n",
218 order = (char **) person_attr_print_order;
220 for (i = 0; order[i] != NULL; i++) {
221 idx = attr_to_index(order[i]);
223 if (debug & D_PRINT) {
224 printf(" ATTR #%2d = %s [%s] (%d values)\n", i + 1,
225 Entry.attrs[idx].output_string,
226 Entry.attrs[idx].quipu_name,
227 Entry.attrs[idx].number_of_values);
232 if (Entry.attrs[idx].number_of_values == 0)
235 print_DN(Entry.attrs[idx]);
236 else if (isaurl(order[i]))
237 print_URL(Entry.attrs[idx]);
238 else if (isadate(order[i])) {
239 /* fix time and date, then call usual routine */
240 Entry.attrs[idx].values[0] =
241 time2text(Entry.attrs[idx].values[0], FALSE);
242 print_values(Entry.attrs[idx]);
245 print_values(Entry.attrs[idx]);
249 * If it is a group, then we should print the subscriber list (if
250 * there are any). If there are a lot of them, prompt the user
251 * before printing them.
253 if (is_a_group && (n > 0)) {
254 char *label = "Subscribers: ";
256 if (n > TOO_MANY_TO_PRINT) {
257 printf(" There are %d subscribers. Print them? ", n);
259 fetch_buffer(buf, sizeof(buf), stdin);
260 if (!((buf[0] == 'y') || (buf[0] == 'Y')))
263 format2((char *) my_ldap_dn2ufn(sub_list[n - 1]), label, (char *) NULL, 2,
264 2 + strlen(label) + 1, col_size);
265 for (n--; n > 0; n--)
266 format2((char *) my_ldap_dn2ufn(sub_list[n - 1]), (char *) NULL,
267 (char *) NULL, 2 + strlen(label),
268 2 + strlen(label) + 2, col_size);
274 #define OUT_LABEL_LEN 20
276 /* prints the values associated with an attribute */
278 print_values( struct attribute A )
281 register char *cp, **vp;
282 char out_buf[MED_BUF_SIZE], *padding = NULL;
287 printf("->print_values(%x)\n", A);
289 if (A.number_of_values == 0)
291 if ((vp = A.values) == NULL)
295 * Pad out the output string label so that it fills the
296 * whole field of length OUT_LABEL_LEN.
299 i = OUT_LABEL_LEN - strlen(A.output_string);
301 printf("Output string for \"%s\" is too long. Maximum length is %d characters\n", A.quipu_name, OUT_LABEL_LEN);
304 if (isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values == 0)) {
305 A.output_string = "Members";
306 i = OUT_LABEL_LEN - strlen(A.output_string);
307 padding = (char *) Malloc((unsigned) (i + 1));
308 (void) memset(padding, ' ', i);
309 *(padding + i) = '\0';
310 sprintf(out_buf, "%s:%s", A.output_string, padding);
312 else if (!(isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values > 0))) {
313 padding = (char *) Malloc((unsigned) (i + 1));
314 (void) memset(padding, ' ', i);
315 *(padding + i) = '\0';
316 sprintf(out_buf, "%s:%s", A.output_string, padding);
319 * If this happens to be a group, then do not print the output
320 * string if we have already printed out some members.
322 else if (isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values > 0)) {
323 padding = (char *) Malloc((unsigned) (OUT_LABEL_LEN + 2));
324 (void) memset(padding, ' ', OUT_LABEL_LEN + 1);
325 *(padding + OUT_LABEL_LEN + 1) = '\0';
326 sprintf(out_buf, "%s", padding);
328 lead = strlen(out_buf) + 2;
330 printf(" %s", out_buf);
331 for (i = 0; *vp != NULL; i++, vp++) {
333 if (!strncmp(A.output_string, "Home a", 6) || !strncmp(A.output_string, "Business a", 10)) {
334 printf(" %s", out_buf);
337 for (k = lead; k > 0; k--)
341 for (cp = *vp; *cp != '\0'; cp++) {
344 if (!strncmp(A.output_string, "Home a", 6) || !strncmp(A.output_string, "Business a", 10) || !strcmp(A.quipu_name, "multiLineDescription")) {
346 for (k = lead; k > 0; k--)
348 while (isspace((unsigned char) cp[1]))
369 /* prints the DN's associated with an attribute */
371 print_DN( struct attribute A )
375 char out_buf[MED_BUF_SIZE], *padding = NULL;
379 printf("->print_DN(%x)\n", A);
381 if (A.number_of_values == 0)
384 * Pad out the output string label so that it fills the
385 * whole field of length OUT_LABEL_LEN.
387 i = OUT_LABEL_LEN - strlen(A.output_string);
389 padding = (char *) Malloc((unsigned) (i + 1));
390 (void) memset(padding, ' ', i);
391 *(padding + i) = '\0';
392 sprintf(out_buf, "%s:%s", A.output_string, padding);
393 (void) Free(padding);
395 lead = strlen(out_buf) + 2;
398 format2((char *) my_ldap_dn2ufn(*vp), out_buf, (char *) NULL, 2, lead + 1, col_size);
399 for (vp++; *vp != NULL; vp++) {
400 format2((char *) my_ldap_dn2ufn(*vp), (char *) NULL, (char *) NULL, lead,
413 printf("->clear_entry()\n");
414 if ((debug & D_PRINT) && (Entry.name != NULL))
415 printf(" Clearing entry \"%s\"\n", Entry.name);
417 if (Entry.DN != NULL)
418 ldap_memfree(Entry.DN);
419 if (Entry.name != NULL)
421 Entry.may_join = FALSE;
422 Entry.subscriber_count = -1;
423 Entry.DN = Entry.name = NULL;
425 /* clear all of the values associated with all attributes */
426 for (i = 0; attrlist[i].quipu_name != NULL; i++) {
429 printf(" Clearing attribute \"%s\" -- ",
430 Entry.attrs[i].quipu_name);
432 if (Entry.attrs[i].values == NULL) {
435 printf(" no values, skipping\n");
441 printf(" freeing %d values\n",
442 Entry.attrs[i].number_of_values);
444 Entry.attrs[i].number_of_values = 0;
445 ldap_value_free(Entry.attrs[i].values);
446 Entry.attrs[i].values = (char **) NULL;
449 * Note: We do not clear either of the char * fields
450 * since they will always be applicable.
456 attr_to_index( char *s )
460 for (i = 0; attrlist[i].quipu_name != NULL; i++)
461 if (!strcasecmp(s, attrlist[i].quipu_name))
467 initialize_attribute_strings( void )
471 for (i = 0; attrlist[i].quipu_name != NULL; i++)
472 Entry.attrs[i].quipu_name = attrlist[i].quipu_name;
473 for (i = 0; attrlist[i].quipu_name != NULL; i++)
474 Entry.attrs[i].output_string = attrlist[i].output_string;
477 /* prints the URL/label pairs associated with an attribute */
479 print_URL( struct attribute A )
483 char out_buf[MED_BUF_SIZE], *padding = NULL;
487 printf("->print_URL(%x)\n", A);
489 if (A.number_of_values == 0)
492 * Pad out the output string label so that it fills the
493 * whole field of length OUT_LABEL_LEN.
495 i = OUT_LABEL_LEN - strlen(A.output_string);
497 padding = (char *) Malloc((unsigned) (i + 1));
498 (void) memset(padding, ' ', i);
499 *(padding + i) = '\0';
500 sprintf(out_buf, "%s:%s", A.output_string, padding);
502 lead = strlen(out_buf) + 2;
505 print_one_URL(*vp, 2, out_buf, lead);
506 for (vp++; *vp != NULL; vp++)
507 print_one_URL(*vp, lead, (char *) NULL, lead);
514 print_one_URL( char *s, int label_lead, char *tag, int url_lead )
519 for (cp = s; !isspace((unsigned char)*cp) && (*cp != '\0'); cp++)
526 for (cp++; isspace((unsigned char)*cp); cp++)
530 cp = "(no description available)";
531 format2(cp, tag, (char *) NULL, label_lead, label_lead + 1, col_size);
532 for (i = url_lead + 2; i > 0; i--)
539 #define GET2BYTENUM( p ) (( *(p) - '0' ) * 10 + ( *((p)+1) - '0' ))
542 time2text( char *ldtimestr, int dateonly )
545 char *p, *timestr, zone, *fmterr = "badly formatted time";
549 if (strlen( ldtimestr ) < 12 ) {
553 for ( ndigits=0; isdigit((unsigned char) ldtimestr[ndigits]); ndigits++) {
557 if ( ndigits != 12 && ndigits != 14) {
561 memset( (char *)&t, 0, sizeof( struct tm ));
566 /* came with a century */
567 /* POSIX says tm_year should be year - 1900 */
568 t.tm_year = 100 * GET2BYTENUM( p ) - 1900;
571 t.tm_year = GET2BYTENUM( p ); p += 2;
573 t.tm_mon = GET2BYTENUM( p ) - 1; p += 2;
574 t.tm_mday = GET2BYTENUM( p ); p += 2;
575 t.tm_hour = GET2BYTENUM( p ); p += 2;
576 t.tm_min = GET2BYTENUM( p ); p += 2;
577 t.tm_sec = GET2BYTENUM( p ); p += 2;
579 if (( zone = *p ) == 'Z' ) { /* GMT */
580 zone = '\0'; /* no need to indicate on screen, so we make it null */
583 gmttime = gtime( &t );
584 timestr = ctime( &gmttime );
586 timestr[ strlen( timestr ) - 1 ] = zone; /* replace trailing newline */
588 SAFEMEMCPY( timestr + 11, timestr + 20, strlen( timestr + 20 ) + 1 );
591 return( strdup( timestr ) );
595 /* gtime.c - inverse gmtime */
599 /* gtime(): the inverse of localtime().
600 This routine was supplied by Mike Accetta at CMU many years ago.
604 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
608 (((y) % 4) ? 365 : (((y) % 100) ? 366 : (((y) % 400) ? 365 : 366)))
613 /* per STDC & POSIX tm_year *should* be offset by 1900 */
614 #define YEAR_POSIX(y) ((y) + 1900)
617 * year is < 1900, year is offset by 1900
619 #define YEAR_CAREFUL(y) ((y) < 1900 ? (y) + 1900 : (y))
621 #define YEAR(y) YEAR_CAREFUL(y)
627 gtime( struct tm *tm )
636 register long result;
638 if ((sec = tm -> tm_sec) < 0 || sec > 59
639 || (mins = tm -> tm_min) < 0 || mins > 59
640 || (hour = tm -> tm_hour) < 0 || hour > 24
641 || (mday = tm -> tm_mday) < 1 || mday > 31
642 || (mon = tm -> tm_mon + 1) < 1 || mon > 12)
648 year = YEAR (tm -> tm_year);
651 for (i = 1970; i < year; i++)
652 result += dysize (i);
653 if (dysize (year) == 366 && mon >= 3)
656 result += dmsize[mon - 1];
658 result = 24 * result + hour;
659 result = 60 * result + mins;
660 result = 60 * result + sec;