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>
20 extern char *strdup (const char *);
29 static char *time2text(char *ldtimestr, int dateonly);
30 static long gtime(struct tm *tm);
33 * When displaying entries, display only these attributes, and in this
36 static char *person_attr_print_order[] = {
40 "facsimileTelephoneNumber",
45 "multiLineDescription",
58 static char *group_attr_print_order[] = {
60 "facsimileTelephoneNumber",
63 "multiLineDescription",
82 parse_answer( LDAPMessage *s )
87 register LDAPMessage *ep;
92 printf("->parse_answer(%x)\n", s);
99 printf(" Done clearing entry\n");
101 for (ep = ldap_first_entry(ld, s); ep != NULL; ep = ldap_next_entry(ld, ep)) {
104 printf(" Determining DN and name\n");
106 Entry.DN = ldap_get_dn(ld, ep);
109 printf(" DN = %s\n", Entry.DN);
111 rdns = ldap_explode_dn(Entry.DN, TRUE);
114 printf(" Name = %s\n", *rdns);
116 Entry.name = strdup(*rdns);
117 ldap_value_free(rdns);
118 for (ap = ldap_first_attribute(ld, ep, &cookie); ap != NULL; ap = ldap_next_attribute(ld, ep, cookie)) {
122 printf("parsing ap = %s\n", ap);
124 if ((idx = attr_to_index(ap)) < 0) {
125 printf(" Unknown attribute \"%s\"\n", ap);
128 add_value(&(Entry.attrs[idx]), ep, ap);
133 printf(" Done parsing entry\n");
138 add_value( struct attribute *attr, LDAPMessage *ep, char *ap )
141 char **vp, **tp, **avp;
145 printf("->add_value(%x, %x, %s)\n", attr, ep, ap);
147 vp = (char **) ldap_get_values(ld, ep, ap);
150 * Fill in the attribute structure for this attribute. This
151 * stores away the values (using strdup()) and the count. Terminate
152 * the list with a NULL pointer.
154 * attr->quipu_name has already been set during initialization.
156 if ((attr->number_of_values = ldap_count_values(vp)) > 0) {
157 attr->values = (char **) Malloc((unsigned) ((attr->number_of_values + 1) * sizeof(char *)));
160 for (i = 1, tp = vp; *tp != NULL; i++, tp++) {
163 printf(" value #%d %s\n", i, *tp);
166 * The 'name' field of the Entry structure already has
167 * has the first part of the DN copied into it. Thus,
168 * we don't need to save it away here again. Also, by
169 * tossing it away here, we make printing this info out
170 * a bit easier later.
172 if (!strcmp(ap, "cn") && !strcmp(*tp, Entry.name)) {
173 attr->number_of_values--;
176 *avp++ = strdup(*tp);
184 print_an_entry( void )
187 char is_a_group, **order;
188 char *sub_list[MAX_VALUES], buf[SMALL_BUF_SIZE];
192 printf("->print_an_entry()\n");
194 printf(" \"%s\"\n", Entry.name);
197 * If the entry is a group, find all of the subscribers to that
198 * group. A subscriber is an entry that *points* to a group entry,
199 * and a member is an entry that is included as part of a group
202 * We also need to select the appropriate output format here.
204 is_a_group = isgroup();
206 order = (char **) group_attr_print_order;
207 n = find_all_subscribers(sub_list, Entry.DN);
210 printf(" Group \"%s\" has %d subscribers\n",
215 order = (char **) person_attr_print_order;
217 for (i = 0; order[i] != NULL; i++) {
218 idx = attr_to_index(order[i]);
220 if (debug & D_PRINT) {
221 printf(" ATTR #%2d = %s [%s] (%d values)\n", i + 1,
222 Entry.attrs[idx].output_string,
223 Entry.attrs[idx].quipu_name,
224 Entry.attrs[idx].number_of_values);
229 if (Entry.attrs[idx].number_of_values == 0)
232 print_DN(Entry.attrs[idx]);
233 else if (isaurl(order[i]))
234 print_URL(Entry.attrs[idx]);
235 else if (isadate(order[i])) {
236 /* fix time and date, then call usual routine */
237 Entry.attrs[idx].values[0] =
238 time2text(Entry.attrs[idx].values[0], FALSE);
239 print_values(Entry.attrs[idx]);
242 print_values(Entry.attrs[idx]);
246 * If it is a group, then we should print the subscriber list (if
247 * there are any). If there are a lot of them, prompt the user
248 * before printing them.
250 if (is_a_group && (n > 0)) {
251 char *label = "Subscribers: ";
253 if (n > TOO_MANY_TO_PRINT) {
254 printf(" There are %d subscribers. Print them? ", n);
256 fetch_buffer(buf, sizeof(buf), stdin);
257 if (!((buf[0] == 'y') || (buf[0] == 'Y')))
260 format2((char *) my_ldap_dn2ufn(sub_list[n - 1]), label, (char *) NULL, 2,
261 2 + strlen(label) + 1, col_size);
262 for (n--; n > 0; n--)
263 format2((char *) my_ldap_dn2ufn(sub_list[n - 1]), (char *) NULL,
264 (char *) NULL, 2 + strlen(label),
265 2 + strlen(label) + 2, col_size);
271 #define OUT_LABEL_LEN 20
273 /* prints the values associated with an attribute */
275 print_values( struct attribute A )
278 register char *cp, **vp;
279 char out_buf[MED_BUF_SIZE], *padding = NULL;
284 printf("->print_values(%x)\n", A);
286 if (A.number_of_values == 0)
288 if ((vp = A.values) == NULL)
292 * Pad out the output string label so that it fills the
293 * whole field of length OUT_LABEL_LEN.
296 i = OUT_LABEL_LEN - strlen(A.output_string);
298 printf("Output string for \"%s\" is too long. Maximum length is %d characters\n", A.quipu_name, OUT_LABEL_LEN);
301 if (isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values == 0)) {
302 A.output_string = "Members";
303 i = OUT_LABEL_LEN - strlen(A.output_string);
304 padding = (char *) Malloc((unsigned) (i + 1));
305 (void) memset(padding, ' ', i);
306 *(padding + i) = '\0';
307 sprintf(out_buf, "%s:%s", A.output_string, padding);
309 else if (!(isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values > 0))) {
310 padding = (char *) Malloc((unsigned) (i + 1));
311 (void) memset(padding, ' ', i);
312 *(padding + i) = '\0';
313 sprintf(out_buf, "%s:%s", A.output_string, padding);
316 * If this happens to be a group, then do not print the output
317 * string if we have already printed out some members.
319 else if (isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values > 0)) {
320 padding = (char *) Malloc((unsigned) (OUT_LABEL_LEN + 2));
321 (void) memset(padding, ' ', OUT_LABEL_LEN + 1);
322 *(padding + OUT_LABEL_LEN + 1) = '\0';
323 sprintf(out_buf, "%s", padding);
325 lead = strlen(out_buf) + 2;
327 printf(" %s", out_buf);
328 for (i = 0; *vp != NULL; i++, vp++) {
330 if (!strncmp(A.output_string, "Home a", 6) || !strncmp(A.output_string, "Business a", 10)) {
331 printf(" %s", out_buf);
334 for (k = lead; k > 0; k--)
338 for (cp = *vp; *cp != '\0'; cp++) {
341 if (!strncmp(A.output_string, "Home a", 6) || !strncmp(A.output_string, "Business a", 10) || !strcmp(A.quipu_name, "multiLineDescription")) {
343 for (k = lead; k > 0; k--)
345 while (isspace(*(cp + 1)))
366 /* prints the DN's associated with an attribute */
368 print_DN( struct attribute A )
372 char out_buf[MED_BUF_SIZE], *padding = NULL;
376 printf("->print_DN(%x)\n", A);
378 if (A.number_of_values == 0)
381 * Pad out the output string label so that it fills the
382 * whole field of length OUT_LABEL_LEN.
384 i = OUT_LABEL_LEN - strlen(A.output_string);
386 padding = (char *) Malloc((unsigned) (i + 1));
387 (void) memset(padding, ' ', i);
388 *(padding + i) = '\0';
389 sprintf(out_buf, "%s:%s", A.output_string, padding);
390 (void) Free(padding);
392 lead = strlen(out_buf) + 2;
395 format2((char *) my_ldap_dn2ufn(*vp), out_buf, (char *) NULL, 2, lead + 1, col_size);
396 for (vp++; *vp != NULL; vp++) {
397 format2((char *) my_ldap_dn2ufn(*vp), (char *) NULL, (char *) NULL, lead,
410 printf("->clear_entry()\n");
411 if ((debug & D_PRINT) && (Entry.name != NULL))
412 printf(" Clearing entry \"%s\"\n", Entry.name);
414 if (Entry.DN != NULL)
416 if (Entry.name != NULL)
418 Entry.may_join = FALSE;
419 Entry.subscriber_count = -1;
420 Entry.DN = Entry.name = NULL;
422 /* clear all of the values associated with all attributes */
423 for (i = 0; attrlist[i].quipu_name != NULL; i++) {
426 printf(" Clearing attribute \"%s\" -- ",
427 Entry.attrs[i].quipu_name);
429 if (Entry.attrs[i].values == NULL) {
432 printf(" no values, skipping\n");
438 printf(" freeing %d values\n",
439 Entry.attrs[i].number_of_values);
441 Entry.attrs[i].number_of_values = 0;
442 ldap_value_free(Entry.attrs[i].values);
443 Entry.attrs[i].values = (char **) NULL;
446 * Note: We do not clear either of the char * fields
447 * since they will always be applicable.
453 attr_to_index( char *s )
457 for (i = 0; attrlist[i].quipu_name != NULL; i++)
458 if (!strcasecmp(s, attrlist[i].quipu_name))
464 initialize_attribute_strings( void )
468 for (i = 0; attrlist[i].quipu_name != NULL; i++)
469 Entry.attrs[i].quipu_name = attrlist[i].quipu_name;
470 for (i = 0; attrlist[i].quipu_name != NULL; i++)
471 Entry.attrs[i].output_string = attrlist[i].output_string;
474 /* prints the URL/label pairs associated with an attribute */
476 print_URL( struct attribute A )
480 char out_buf[MED_BUF_SIZE], *padding = NULL;
484 printf("->print_URL(%x)\n", A);
486 if (A.number_of_values == 0)
489 * Pad out the output string label so that it fills the
490 * whole field of length OUT_LABEL_LEN.
492 i = OUT_LABEL_LEN - strlen(A.output_string);
494 padding = (char *) Malloc((unsigned) (i + 1));
495 (void) memset(padding, ' ', i);
496 *(padding + i) = '\0';
497 sprintf(out_buf, "%s:%s", A.output_string, padding);
499 lead = strlen(out_buf) + 2;
502 print_one_URL(*vp, 2, out_buf, lead);
503 for (vp++; *vp != NULL; vp++)
504 print_one_URL(*vp, lead, (char *) NULL, lead);
511 print_one_URL( char *s, int label_lead, char *tag, int url_lead )
516 for (cp = s; !isspace(*cp) && (*cp != '\0'); cp++)
523 for (cp++; isspace(*cp); cp++)
527 cp = "(no description available)";
528 format2(cp, tag, (char *) NULL, label_lead, label_lead + 1, col_size);
529 for (i = url_lead + 2; i > 0; i--)
536 #define GET2BYTENUM( p ) (( *p - '0' ) * 10 + ( *(p+1) - '0' ))
539 time2text( char *ldtimestr, int dateonly )
542 char *p, *timestr, zone, *fmterr = "badly formatted time";
545 memset( (char *)&t, 0, sizeof( struct tm ));
546 if ( strlen( ldtimestr ) < 13 ) {
550 for ( p = ldtimestr; p - ldtimestr < 12; ++p ) {
551 if ( !isdigit( *p )) {
557 t.tm_year = GET2BYTENUM( p ); p += 2;
558 t.tm_mon = GET2BYTENUM( p ) - 1; p += 2;
559 t.tm_mday = GET2BYTENUM( p ); p += 2;
560 t.tm_hour = GET2BYTENUM( p ); p += 2;
561 t.tm_min = GET2BYTENUM( p ); p += 2;
562 t.tm_sec = GET2BYTENUM( p ); p += 2;
564 if (( zone = *p ) == 'Z' ) { /* GMT */
565 zone = '\0'; /* no need to indicate on screen, so we make it null */
568 gmttime = gtime( &t );
569 timestr = ctime( &gmttime );
571 timestr[ strlen( timestr ) - 1 ] = zone; /* replace trailing newline */
573 strcpy( timestr + 11, timestr + 20 );
577 return( strdup( timestr ) );
581 /* gtime.c - inverse gmtime */
585 /* gtime(): the inverse of localtime().
586 This routine was supplied by Mike Accetta at CMU many years ago.
590 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
594 (((y) % 4) ? 365 : (((y) % 100) ? 366 : (((y) % 400) ? 365 : 366)))
596 #define YEAR(y) ((y) >= 100 ? (y) : (y) + 1900)
601 gtime( struct tm *tm )
610 register long result;
612 if ((sec = tm -> tm_sec) < 0 || sec > 59
613 || (mins = tm -> tm_min) < 0 || mins > 59
614 || (hour = tm -> tm_hour) < 0 || hour > 24
615 || (mday = tm -> tm_mday) < 1 || mday > 31
616 || (mon = tm -> tm_mon + 1) < 1 || mon > 12)
622 year = YEAR (tm -> tm_year);
625 for (i = 1970; i < year; i++)
626 result += dysize (i);
627 if (dysize (year) == 366 && mon >= 3)
630 result += dmsize[mon - 1];
632 result = 24 * result + hour;
633 result = 60 * result + mins;
634 result = 60 * result + sec;