3 * Copyright (c) 1991, 1993
4 * Regents of the University of Michigan. All rights reserved.
6 * Redistribution and use in source and binary forms are permitted
7 * provided that this notice is preserved and that due credit is given
8 * to the University of Michigan at Ann Arbor. The name of the University
9 * may not be used to endorse or promote products derived from this
10 * software without specific prior written permission. This software
11 * is provided ``as is'' without express or implied warranty.
19 #include <ac/string.h>
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 )
86 register LDAPMessage *ep;
91 printf("->parse_answer(%x)\n", s);
98 printf(" Done clearing entry\n");
100 for (ep = ldap_first_entry(ld, s); ep != NULL; ep = ldap_next_entry(ld, ep)) {
101 BerElement *cookie = NULL;
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);
131 if( cookie != NULL ) {
132 ber_free( cookie, 0 );
137 printf(" Done parsing entry\n");
142 add_value( struct attribute *attr, LDAPMessage *ep, char *ap )
145 char **vp, **tp, **avp;
149 printf("->add_value(%x, %x, %s)\n", attr, ep, ap);
151 vp = (char **) ldap_get_values(ld, ep, ap);
154 * Fill in the attribute structure for this attribute. This
155 * stores away the values (using strdup()) and the count. Terminate
156 * the list with a NULL pointer.
158 * attr->quipu_name has already been set during initialization.
160 if ((attr->number_of_values = ldap_count_values(vp)) > 0) {
161 attr->values = (char **) Malloc((unsigned) ((attr->number_of_values + 1) * sizeof(char *)));
164 for (i = 1, tp = vp; *tp != NULL; i++, tp++) {
167 printf(" value #%d %s\n", i, *tp);
170 * The 'name' field of the Entry structure already has
171 * has the first part of the DN copied into it. Thus,
172 * we don't need to save it away here again. Also, by
173 * tossing it away here, we make printing this info out
174 * a bit easier later.
176 if (!strcmp(ap, "cn") && !strcmp(*tp, Entry.name)) {
177 attr->number_of_values--;
180 *avp++ = strdup(*tp);
188 print_an_entry( void )
191 char is_a_group, **order;
192 char *sub_list[MAX_VALUES], buf[SMALL_BUF_SIZE];
196 printf("->print_an_entry()\n");
198 printf(" \"%s\"\n", Entry.name);
201 * If the entry is a group, find all of the subscribers to that
202 * group. A subscriber is an entry that *points* to a group entry,
203 * and a member is an entry that is included as part of a group
206 * We also need to select the appropriate output format here.
208 is_a_group = isgroup();
210 order = (char **) group_attr_print_order;
211 n = find_all_subscribers(sub_list, Entry.DN);
214 printf(" Group \"%s\" has %d subscribers\n",
219 order = (char **) person_attr_print_order;
221 for (i = 0; order[i] != NULL; i++) {
222 idx = attr_to_index(order[i]);
224 if (debug & D_PRINT) {
225 printf(" ATTR #%2d = %s [%s] (%d values)\n", i + 1,
226 Entry.attrs[idx].output_string,
227 Entry.attrs[idx].quipu_name,
228 Entry.attrs[idx].number_of_values);
233 if (Entry.attrs[idx].number_of_values == 0)
236 print_DN(Entry.attrs[idx]);
237 else if (isaurl(order[i]))
238 print_URL(Entry.attrs[idx]);
239 else if (isadate(order[i])) {
240 /* fix time and date, then call usual routine */
241 Entry.attrs[idx].values[0] =
242 time2text(Entry.attrs[idx].values[0], FALSE);
243 print_values(Entry.attrs[idx]);
246 print_values(Entry.attrs[idx]);
250 * If it is a group, then we should print the subscriber list (if
251 * there are any). If there are a lot of them, prompt the user
252 * before printing them.
254 if (is_a_group && (n > 0)) {
255 char *label = "Subscribers: ";
257 if (n > TOO_MANY_TO_PRINT) {
258 printf(" There are %d subscribers. Print them? ", n);
260 fetch_buffer(buf, sizeof(buf), stdin);
261 if (!((buf[0] == 'y') || (buf[0] == 'Y')))
264 format2((char *) my_ldap_dn2ufn(sub_list[n - 1]), label, (char *) NULL, 2,
265 2 + strlen(label) + 1, col_size);
266 for (n--; n > 0; n--)
267 format2((char *) my_ldap_dn2ufn(sub_list[n - 1]), (char *) NULL,
268 (char *) NULL, 2 + strlen(label),
269 2 + strlen(label) + 2, col_size);
275 #define OUT_LABEL_LEN 20
277 /* prints the values associated with an attribute */
279 print_values( struct attribute A )
282 register char *cp, **vp;
283 char out_buf[MED_BUF_SIZE], *padding = NULL;
288 printf("->print_values(%x)\n", A);
290 if (A.number_of_values == 0)
292 if ((vp = A.values) == NULL)
296 * Pad out the output string label so that it fills the
297 * whole field of length OUT_LABEL_LEN.
300 i = OUT_LABEL_LEN - strlen(A.output_string);
302 printf("Output string for \"%s\" is too long. Maximum length is %d characters\n", A.quipu_name, OUT_LABEL_LEN);
305 if (isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values == 0)) {
306 A.output_string = "Members";
307 i = OUT_LABEL_LEN - strlen(A.output_string);
308 padding = (char *) Malloc((unsigned) (i + 1));
309 (void) memset(padding, ' ', i);
310 *(padding + i) = '\0';
311 sprintf(out_buf, "%s:%s", A.output_string, padding);
313 else if (!(isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values > 0))) {
314 padding = (char *) Malloc((unsigned) (i + 1));
315 (void) memset(padding, ' ', i);
316 *(padding + i) = '\0';
317 sprintf(out_buf, "%s:%s", A.output_string, padding);
320 * If this happens to be a group, then do not print the output
321 * string if we have already printed out some members.
323 else if (isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values > 0)) {
324 padding = (char *) Malloc((unsigned) (OUT_LABEL_LEN + 2));
325 (void) memset(padding, ' ', OUT_LABEL_LEN + 1);
326 *(padding + OUT_LABEL_LEN + 1) = '\0';
327 sprintf(out_buf, "%s", padding);
329 lead = strlen(out_buf) + 2;
331 printf(" %s", out_buf);
332 for (i = 0; *vp != NULL; i++, vp++) {
334 if (!strncmp(A.output_string, "Home a", 6) || !strncmp(A.output_string, "Business a", 10)) {
335 printf(" %s", out_buf);
338 for (k = lead; k > 0; k--)
342 for (cp = *vp; *cp != '\0'; cp++) {
345 if (!strncmp(A.output_string, "Home a", 6) || !strncmp(A.output_string, "Business a", 10) || !strcmp(A.quipu_name, "multiLineDescription")) {
347 for (k = lead; k > 0; k--)
349 while (isspace((unsigned char) cp[1]))
370 /* prints the DN's associated with an attribute */
372 print_DN( struct attribute A )
376 char out_buf[MED_BUF_SIZE], *padding = NULL;
380 printf("->print_DN(%x)\n", A);
382 if (A.number_of_values == 0)
385 * Pad out the output string label so that it fills the
386 * whole field of length OUT_LABEL_LEN.
388 i = OUT_LABEL_LEN - strlen(A.output_string);
390 padding = (char *) Malloc((unsigned) (i + 1));
391 (void) memset(padding, ' ', i);
392 *(padding + i) = '\0';
393 sprintf(out_buf, "%s:%s", A.output_string, padding);
394 (void) Free(padding);
396 lead = strlen(out_buf) + 2;
399 format2((char *) my_ldap_dn2ufn(*vp), out_buf, (char *) NULL, 2, lead + 1, col_size);
400 for (vp++; *vp != NULL; vp++) {
401 format2((char *) my_ldap_dn2ufn(*vp), (char *) NULL, (char *) NULL, lead,
414 printf("->clear_entry()\n");
415 if ((debug & D_PRINT) && (Entry.name != NULL))
416 printf(" Clearing entry \"%s\"\n", Entry.name);
418 if (Entry.DN != NULL)
419 ldap_memfree(Entry.DN);
420 if (Entry.name != NULL)
422 Entry.may_join = FALSE;
423 Entry.subscriber_count = -1;
424 Entry.DN = Entry.name = NULL;
426 /* clear all of the values associated with all attributes */
427 for (i = 0; attrlist[i].quipu_name != NULL; i++) {
430 printf(" Clearing attribute \"%s\" -- ",
431 Entry.attrs[i].quipu_name);
433 if (Entry.attrs[i].values == NULL) {
436 printf(" no values, skipping\n");
442 printf(" freeing %d values\n",
443 Entry.attrs[i].number_of_values);
445 Entry.attrs[i].number_of_values = 0;
446 ldap_value_free(Entry.attrs[i].values);
447 Entry.attrs[i].values = (char **) NULL;
450 * Note: We do not clear either of the char * fields
451 * since they will always be applicable.
457 attr_to_index( char *s )
461 for (i = 0; attrlist[i].quipu_name != NULL; i++)
462 if (!strcasecmp(s, attrlist[i].quipu_name))
468 initialize_attribute_strings( void )
472 for (i = 0; attrlist[i].quipu_name != NULL; i++)
473 Entry.attrs[i].quipu_name = attrlist[i].quipu_name;
474 for (i = 0; attrlist[i].quipu_name != NULL; i++)
475 Entry.attrs[i].output_string = attrlist[i].output_string;
478 /* prints the URL/label pairs associated with an attribute */
480 print_URL( struct attribute A )
484 char out_buf[MED_BUF_SIZE], *padding = NULL;
488 printf("->print_URL(%x)\n", A);
490 if (A.number_of_values == 0)
493 * Pad out the output string label so that it fills the
494 * whole field of length OUT_LABEL_LEN.
496 i = OUT_LABEL_LEN - strlen(A.output_string);
498 padding = (char *) Malloc((unsigned) (i + 1));
499 (void) memset(padding, ' ', i);
500 *(padding + i) = '\0';
501 sprintf(out_buf, "%s:%s", A.output_string, padding);
503 lead = strlen(out_buf) + 2;
506 print_one_URL(*vp, 2, out_buf, lead);
507 for (vp++; *vp != NULL; vp++)
508 print_one_URL(*vp, lead, (char *) NULL, lead);
515 print_one_URL( char *s, int label_lead, char *tag, int url_lead )
520 for (cp = s; !isspace((unsigned char)*cp) && (*cp != '\0'); cp++)
527 for (cp++; isspace((unsigned char)*cp); cp++)
531 cp = "(no description available)";
532 format2(cp, tag, (char *) NULL, label_lead, label_lead + 1, col_size);
533 for (i = url_lead + 2; i > 0; i--)
540 #define GET2BYTENUM( p ) (( *(p) - '0' ) * 10 + ( *((p)+1) - '0' ))
543 time2text( char *ldtimestr, int dateonly )
546 char *p, *timestr, zone, *fmterr = "badly formatted time";
550 if (strlen( ldtimestr ) < 12 ) {
554 for ( ndigits=0; isdigit((unsigned char) ldtimestr[ndigits]); ndigits++) {
558 if ( ndigits != 12 && ndigits != 14) {
562 memset( (char *)&t, 0, sizeof( struct tm ));
567 /* came with a century */
568 /* POSIX says tm_year should be year - 1900 */
569 t.tm_year = 100 * GET2BYTENUM( p ) - 1900;
572 t.tm_year = GET2BYTENUM( p ); p += 2;
574 t.tm_mon = GET2BYTENUM( p ) - 1; p += 2;
575 t.tm_mday = GET2BYTENUM( p ); p += 2;
576 t.tm_hour = GET2BYTENUM( p ); p += 2;
577 t.tm_min = GET2BYTENUM( p ); p += 2;
578 t.tm_sec = GET2BYTENUM( p ); p += 2;
580 if (( zone = *p ) == 'Z' ) { /* GMT */
581 zone = '\0'; /* no need to indicate on screen, so we make it null */
584 gmttime = gtime( &t );
585 timestr = ctime( &gmttime );
587 timestr[ strlen( timestr ) - 1 ] = zone; /* replace trailing newline */
589 SAFEMEMCPY( timestr + 11, timestr + 20, strlen( timestr + 20 ) + 1 );
592 return( strdup( timestr ) );
596 /* gtime.c - inverse gmtime */
600 /* gtime(): the inverse of localtime().
601 This routine was supplied by Mike Accetta at CMU many years ago.
605 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
609 (((y) % 4) ? 365 : (((y) % 100) ? 366 : (((y) % 400) ? 365 : 366)))
614 /* per STDC & POSIX tm_year *should* be offset by 1900 */
615 #define YEAR_POSIX(y) ((y) + 1900)
618 * year is < 1900, year is offset by 1900
620 #define YEAR_CAREFUL(y) ((y) < 1900 ? (y) + 1900 : (y))
622 #define YEAR(y) YEAR_CAREFUL(y)
628 gtime( struct tm *tm )
637 register long result;
639 if ((sec = tm -> tm_sec) < 0 || sec > 59
640 || (mins = tm -> tm_min) < 0 || mins > 59
641 || (hour = tm -> tm_hour) < 0 || hour > 24
642 || (mday = tm -> tm_mday) < 1 || mday > 31
643 || (mon = tm -> tm_mon + 1) < 1 || mon > 12)
649 year = YEAR (tm -> tm_year);
652 for (i = 1970; i < year; i++)
653 result += dysize (i);
654 if (dysize (year) == 366 && mon >= 3)
657 result += dmsize[mon - 1];
659 result = 24 * result + hour;
660 result = 60 * result + mins;
661 result = 60 * result + sec;