]> git.sur5r.net Git - openldap/blob - clients/ud/print.c
Merge in all devel changes since 2.0-alpha2.
[openldap] / clients / ud / print.c
1 /*
2  * Copyright (c) 1991, 1993 
3  * Regents of the University of Michigan.  All rights reserved.
4  *
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.
11  */
12
13 #include <stdio.h>
14 #include <string.h>
15 #include <ctype.h>
16 #ifndef __STDC__
17 #include <memory.h>
18 #endif
19 #include <time.h>
20 #include <lber.h>
21 #include <ldap.h>
22 #include "ud.h"
23
24 #ifdef DEBUG
25 extern int debug;
26 #endif
27
28 struct entry Entry;
29 extern LDAP *ld;
30
31 extern void * Malloc();
32 extern void Free();
33 extern char * my_ldap_dn2ufn();
34
35 /*
36  *  When displaying entries, display only these attributes, and in this
37  *  order.
38  */
39 static char *person_attr_print_order[] = {
40         "cn",
41         "mail",
42         "telephoneNumber",
43         "facsimileTelephoneNumber",
44         "pager",
45         "postalAddress",
46         "title",
47         "uid",
48         "multiLineDescription",
49         "homePhone",
50         "homePostalAddress",
51         "drink",
52         "labeledURL",
53         "onVacation",
54         "vacationMessage",
55         "memberOfGroup",
56         "lastModifiedBy",
57         "lastModifiedTime",
58         NULL
59 };
60
61 static char *group_attr_print_order[] = {
62         "cn",
63         "facsimileTelephoneNumber",
64         "telephoneNumber",
65         "postalAddress",
66         "multiLineDescription",
67         "joinable",
68         "associatedDomain",
69         "owner",
70         "moderator",
71         "ErrorsTo",
72         "rfc822ErrorsTo",
73         "RequestsTo",
74         "rfc822RequestsTo",
75         "member",
76         "mail",
77         "labeledURL",
78         "lastModifiedBy",
79         "lastModifiedTime",
80         NULL
81 };
82
83 parse_answer(s)
84 LDAPMessage *s;
85 {
86         int idx;
87         char **rdns;
88         BerElement *cookie;
89         register LDAPMessage *ep;
90         register char *ap;
91         void clear_entry();
92
93 #ifdef DEBUG
94         if (debug & D_TRACE)
95                 printf("->parse_answer(%x)\n", s);
96 #endif
97
98         clear_entry();
99
100 #ifdef DEBUG
101         if (debug & D_PARSE)
102                 printf(" Done clearing entry\n");
103 #endif
104         for (ep = ldap_first_entry(ld, s); ep != NULL; ep = ldap_next_entry(ld, ep)) {
105 #ifdef DEBUG
106                 if (debug & D_PARSE)
107                         printf(" Determining DN and name\n");
108 #endif
109                 Entry.DN = ldap_get_dn(ld, ep);
110 #ifdef DEBUG
111                 if (debug & D_PARSE)
112                         printf(" DN = %s\n", Entry.DN);
113 #endif
114                 rdns = ldap_explode_dn(Entry.DN, TRUE);
115 #ifdef DEBUG
116                 if (debug & D_PARSE)
117                         printf(" Name = %s\n", *rdns);
118 #endif
119                 Entry.name = strdup(*rdns);
120                 ldap_value_free(rdns);
121                 for (ap = ldap_first_attribute(ld, ep, &cookie); ap != NULL; ap = ldap_next_attribute(ld, ep, cookie)) {
122
123 #ifdef DEBUG
124                         if (debug & D_PARSE)
125                                 printf("parsing ap = %s\n", ap);
126 #endif
127                         if ((idx = attr_to_index(ap)) < 0) {
128                                 printf("  Unknown attribute \"%s\"\n", ap);
129                                 continue;
130                         }
131                         add_value(&(Entry.attrs[idx]), ep, ap);
132                 }
133         }
134 #ifdef DEBUG
135         if (debug & D_PARSE)
136                 printf(" Done parsing entry\n");
137 #endif
138 }
139
140 add_value(attr, ep, ap)
141 struct attribute *attr;
142 LDAPMessage *ep;
143 char *ap;
144 {
145         register int i = 0;
146         char **vp, **tp, **avp;
147
148 #ifdef DEBUG
149         if (debug & D_TRACE)
150                 printf("->add_value(%x, %x, %s)\n", attr, ep, ap);
151 #endif
152         vp = (char **) ldap_get_values(ld, ep, ap);
153
154         /*
155          *  Fill in the attribute structure for this attribute.  This
156          *  stores away the values (using strdup()) and the count.  Terminate
157          *  the list with a NULL pointer.
158          *
159          *  attr->quipu_name has already been set during initialization.
160          */
161         if ((attr->number_of_values = ldap_count_values(vp)) > 0) {
162                 attr->values = (char **) Malloc((unsigned) ((attr->number_of_values + 1) * sizeof(char *)));
163                 avp = attr->values;
164
165                 for (i = 1, tp = vp; *tp != NULL; i++, tp++) {
166 #ifdef DEBUG
167                         if (debug & D_PARSE)
168                                 printf("  value #%d  %s\n", i, *tp);
169 #endif
170                         /*
171                          *  The 'name' field of the Entry structure already has
172                          *  has the first part of the DN copied into it.  Thus,
173                          *  we don't need to save it away here again.  Also, by
174                          *  tossing it away here, we make printing this info out
175                          *  a bit easier later.
176                          */
177                         if (!strcmp(ap, "cn") && !strcmp(*tp, Entry.name)) {
178                                 attr->number_of_values--;
179                                 continue;
180                         }
181                         *avp++ = strdup(*tp);
182                 }
183                 *avp = NULL;
184         }
185         ldap_value_free(vp);
186 }
187
188 print_an_entry()
189 {
190         int n = 0, i, idx;
191         char is_a_group, **order;
192         char *sub_list[MAX_VALUES], buf[SMALL_BUF_SIZE];
193         extern int col_size, isaurl(), isadn();
194         static char *time2text();
195
196 #ifdef DEBUG
197         if (debug & D_TRACE)
198                 printf("->print_an_entry()\n");
199 #endif
200         printf(" \"%s\"\n", Entry.name);
201         
202         /*
203          *  If the entry is a group, find all of the subscribers to that
204          *  group.  A subscriber is an entry that *points* to a group entry,
205          *  and a member is an entry that is included as part of a group
206          *  entry.
207          *
208          *  We also need to select the appropriate output format here.
209          */
210         is_a_group = isgroup();
211         if (is_a_group) {
212                 order = (char **) group_attr_print_order;
213                 n = find_all_subscribers(sub_list, Entry.DN);
214 #ifdef DEBUG
215                 if (debug & D_PRINT)
216                         printf(" Group \"%s\" has %d subscribers\n", 
217                                                                 Entry.name, n);
218 #endif
219         }
220         else
221                 order = (char **) person_attr_print_order;
222
223         for (i = 0; order[i] != NULL; i++) {
224                 idx = attr_to_index(order[i]);
225 #ifdef DEBUG
226                 if (debug & D_PRINT) {
227                         printf("  ATTR #%2d = %s [%s] (%d values)\n", i + 1,
228                                 Entry.attrs[idx].output_string,
229                                 Entry.attrs[idx].quipu_name,
230                                 Entry.attrs[idx].number_of_values);
231                 }
232 #endif
233                 if (idx < 0)
234                         continue;
235                 if (Entry.attrs[idx].number_of_values == 0)
236                         continue;
237                 if (isadn(order[i]))
238                         print_DN(Entry.attrs[idx]);
239                 else if (isaurl(order[i]))
240                         print_URL(Entry.attrs[idx]);
241                 else if (isadate(order[i])) {
242                         /* fix time and date, then call usual routine */
243                         Entry.attrs[idx].values[0] = 
244                                 time2text(Entry.attrs[idx].values[0], FALSE);
245                         print_values(Entry.attrs[idx]);
246                 }
247                 else
248                         print_values(Entry.attrs[idx]);
249         }
250
251         /*
252          *  If it is a group, then we should print the subscriber list (if
253          *  there are any).  If there are a lot of them, prompt the user
254          *  before printing them.
255          */
256         if (is_a_group && (n > 0)) {
257                 char *label = "Subscribers:         ";
258
259                 if (n > TOO_MANY_TO_PRINT) {
260                         printf("  There are %d subscribers.  Print them? ", n);
261                         fflush(stdout);
262                         fetch_buffer(buf, sizeof(buf), stdin);
263                         if (!((buf[0] == 'y') || (buf[0] == 'Y')))
264                                 return;
265                 }
266                 format2((char *) my_ldap_dn2ufn(sub_list[n - 1]), label, (char *) NULL, 2, 
267                                                 2 + strlen(label) + 1, col_size); 
268                 for (n--; n > 0; n--)
269                         format2((char *) my_ldap_dn2ufn(sub_list[n - 1]), (char *) NULL, 
270                                 (char *) NULL, 2 + strlen(label), 
271                                 2 + strlen(label) + 2, col_size); 
272         }
273
274         return;
275 }
276
277 #define OUT_LABEL_LEN   20
278
279 /* prints the values associated with an attribute */
280 print_values(A)
281 struct attribute A;
282 {
283         register int i, k;
284         register char *cp, **vp;
285         char out_buf[MED_BUF_SIZE], *padding = NULL;
286         int lead;
287
288 #ifdef DEBUG
289         if (debug & D_TRACE)
290                 printf("->print_values(%x)\n", A);
291 #endif
292         if (A.number_of_values == 0)
293                 return;
294         if ((vp = A.values) == NULL)
295                 return;
296
297         /*
298          *  Pad out the output string label so that it fills the
299          *  whole field of length OUT_LABEL_LEN.
300          */
301         out_buf[0] = '\0';
302         i = OUT_LABEL_LEN - strlen(A.output_string);
303         if (i < 0) {
304                 printf("Output string for \"%s\" is too long.  Maximum length is %d characters\n", A.quipu_name, OUT_LABEL_LEN);
305                 return;
306         }
307         if (isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values == 0)) {
308                 A.output_string = "Members";
309                 i = OUT_LABEL_LEN - strlen(A.output_string);
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);
314         }
315         else if (!(isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values > 0))) {
316                 padding = (char *) Malloc((unsigned) (i + 1));
317                 (void) memset(padding, ' ', i);
318                 *(padding + i) = '\0';
319                 sprintf(out_buf, "%s:%s", A.output_string, padding);
320         }
321         /*
322          *  If this happens to be a group, then do not print the output
323          *  string if we have already printed out some members.
324          */
325         else if (isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values > 0)) {
326                 padding = (char *) Malloc((unsigned) (OUT_LABEL_LEN + 2));
327                 (void) memset(padding, ' ', OUT_LABEL_LEN + 1);
328                 *(padding + OUT_LABEL_LEN + 1) = '\0';
329                 sprintf(out_buf, "%s", padding);
330         }
331         lead = strlen(out_buf) + 2;
332
333         printf("  %s", out_buf);
334         for (i = 0; *vp != NULL; i++, vp++) {
335                 if (i > 0) {
336                         if (!strncmp(A.output_string, "Home a", 6) || !strncmp(A.output_string, "Business a", 10)) {
337                                 printf("  %s", out_buf);
338                         }
339                         else {
340                                 for (k = lead; k > 0; k--)
341                                         putchar(' ');
342                         }
343                 }
344                 for (cp = *vp; *cp != '\0'; cp++) {
345                         switch (*cp) {
346                         case '$' :
347                                 if (!strncmp(A.output_string, "Home a", 6) || !strncmp(A.output_string, "Business a", 10) || !strcmp(A.quipu_name, "multiLineDescription")) {
348                                         putchar('\n');
349                                         for (k = lead; k > 0; k--)
350                                                 putchar(' ');
351                                         while (isspace(*(cp + 1)))
352                                                 cp++;
353                                 }
354                                 else
355                                         putchar(*cp);
356                                 break;
357                         case '\n' :
358                                 putchar('%');
359                                 putchar('\n');
360                                 break;
361                         default:
362                                 putchar(*cp);
363                         }
364                 }
365                 putchar('\n');
366         }
367         if (padding != NULL)
368                 Free(padding);
369         return;
370 }
371
372 /* prints the DN's associated with an attribute */
373 print_DN(A)
374 struct attribute A;
375 {
376         int i, lead;
377         register char **vp;
378         char out_buf[MED_BUF_SIZE], *padding = NULL;
379         extern int col_size;
380
381 #ifdef DEBUG
382         if (debug & D_TRACE)
383                 printf("->print_DN(%x)\n", A);
384 #endif
385         if (A.number_of_values == 0)
386                 return;
387         /*
388          *  Pad out the output string label so that it fills the
389          *  whole field of length OUT_LABEL_LEN.
390          */
391         i = OUT_LABEL_LEN - strlen(A.output_string);
392         if (i > 0) {
393                 padding = (char *) Malloc((unsigned) (i + 1));
394                 (void) memset(padding, ' ', i);
395                 *(padding + i) = '\0';
396                 sprintf(out_buf, "%s:%s", A.output_string, padding);
397                 (void) Free(padding);
398         }
399         lead = strlen(out_buf) + 2;
400
401         vp = A.values;
402         format2((char *) my_ldap_dn2ufn(*vp), out_buf, (char *) NULL, 2, lead + 1, col_size); 
403         for (vp++; *vp != NULL; vp++) {
404                 format2((char *) my_ldap_dn2ufn(*vp), (char *) NULL, (char *) NULL, lead, 
405                         lead + 1, col_size); 
406         }
407         return;
408 }
409
410 void clear_entry()
411 {
412         register int i;
413         extern struct attribute attrlist[];
414
415 #ifdef DEBUG
416         if (debug & D_TRACE)
417                 printf("->clear_entry()\n");
418         if ((debug & D_PRINT) && (Entry.name != NULL))
419                 printf(" Clearing entry \"%s\"\n", Entry.name);
420 #endif
421         if (Entry.DN != NULL)
422                 Free(Entry.DN);
423         if (Entry.name != NULL)
424                 Free(Entry.name);
425         Entry.may_join = FALSE;
426         Entry.subscriber_count = -1;
427         Entry.DN = Entry.name = NULL;
428
429         /*  clear all of the values associated with all attributes */
430         for (i = 0; attrlist[i].quipu_name != NULL; i++) {
431 #ifdef DEBUG
432                 if (debug & D_PRINT)
433                         printf(" Clearing attribute \"%s\" -- ", 
434                                 Entry.attrs[i].quipu_name);
435 #endif
436                 if (Entry.attrs[i].values == NULL) {
437 #ifdef DEBUG
438                         if (debug & D_PRINT)
439                                 printf(" no values, skipping\n");
440 #endif
441                         continue;
442                 }
443 #ifdef DEBUG
444                 if (debug & D_PRINT)
445                         printf(" freeing %d values\n", 
446                                         Entry.attrs[i].number_of_values);
447 #endif
448                 Entry.attrs[i].number_of_values = 0;
449                 ldap_value_free(Entry.attrs[i].values);
450                 Entry.attrs[i].values = (char **) NULL;
451
452                 /*
453                  *  Note:  We do not clear either of the char * fields
454                  *  since they will always be applicable.
455                  */
456         }
457 }
458
459 attr_to_index(s)
460 char *s;
461 {
462         register int i;
463         extern struct attribute attrlist[];
464
465         for (i = 0; attrlist[i].quipu_name != NULL; i++)
466                 if (!strcasecmp(s, attrlist[i].quipu_name))
467                         return(i);
468         return(-1);
469 }
470
471 void initialize_attribute_strings()
472 {
473         register int i;
474         extern struct entry Entry;
475         extern struct attribute attrlist[];
476
477         for (i = 0; attrlist[i].quipu_name != NULL; i++)
478                 Entry.attrs[i].quipu_name = attrlist[i].quipu_name;
479         for (i = 0; attrlist[i].quipu_name != NULL; i++)
480                 Entry.attrs[i].output_string = attrlist[i].output_string;
481 }
482
483 /* prints the URL/label pairs associated with an attribute */
484 print_URL(A)
485 struct attribute A;
486 {
487         int i, lead;
488         register char **vp;
489         char out_buf[MED_BUF_SIZE], *padding = NULL;
490
491 #ifdef DEBUG
492         if (debug & D_TRACE)
493                 printf("->print_URL(%x)\n", A);
494 #endif
495         if (A.number_of_values == 0)
496                 return;
497         /*
498          *  Pad out the output string label so that it fills the
499          *  whole field of length OUT_LABEL_LEN.
500          */
501         i = OUT_LABEL_LEN - strlen(A.output_string);
502         if (i > 0) {
503                 padding = (char *) Malloc((unsigned) (i + 1));
504                 (void) memset(padding, ' ', i);
505                 *(padding + i) = '\0';
506                 sprintf(out_buf, "%s:%s", A.output_string, padding);
507         }
508         lead = strlen(out_buf) + 2;
509
510         vp = A.values;
511         print_one_URL(*vp, 2, out_buf, lead);
512         for (vp++; *vp != NULL; vp++)
513                 print_one_URL(*vp, lead, (char *) NULL, lead);
514         if (padding != NULL)
515                 Free(padding);
516         return;
517 }
518
519 print_one_URL(s, label_lead, tag, url_lead)
520 char *s;
521 int label_lead;
522 char *tag;
523 int url_lead;
524 {
525         register int i;
526         char c, *cp, *url;
527         extern int col_size;
528         extern void Free();
529
530         for (cp = s; !isspace(*cp) && (*cp != '\0'); cp++)
531                 ;
532         c = *cp;
533         *cp = '\0';
534         url = strdup(s);
535         *cp = c;
536         if (*cp != '\0') {
537                 for (cp++; isspace(*cp); cp++)
538                         ;
539         }
540         else
541                 cp = "(no description available)";
542         format2(cp, tag, (char *) NULL, label_lead, label_lead + 1, col_size);
543         for (i = url_lead + 2; i > 0; i--)
544                 printf(" ");
545         printf("%s\n", url);
546         Free(url);
547 }
548
549
550 #define GET2BYTENUM( p )        (( *p - '0' ) * 10 + ( *(p+1) - '0' ))
551
552 static char *
553 time2text( char *ldtimestr, int dateonly )
554 {
555     struct tm           t;
556     char                *p, *timestr, zone, *fmterr = "badly formatted time";
557     time_t              gmttime;
558     static long         gtime();
559
560     memset( (char *)&t, 0, sizeof( struct tm ));
561     if ( strlen( ldtimestr ) < 13 ) {
562         return( fmterr );
563     }
564
565     for ( p = ldtimestr; p - ldtimestr < 12; ++p ) {
566         if ( !isdigit( *p )) {
567             return( fmterr );
568         }
569     }
570
571     p = ldtimestr;
572     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;
578
579     if (( zone = *p ) == 'Z' ) {        /* GMT */
580         zone = '\0';    /* no need to indicate on screen, so we make it null */
581     }
582
583     gmttime = gtime( &t );
584     timestr = ctime( &gmttime );
585
586     timestr[ strlen( timestr ) - 1 ] = zone;    /* replace trailing newline */
587     if ( dateonly ) {
588         strcpy( timestr + 11, timestr + 20 );
589     }
590
591     Free ( ldtimestr );
592     return( strdup( timestr ) );
593 }
594
595
596 /* gtime.c - inverse gmtime */
597
598 #if !defined( MACOS ) && !defined( _WIN32 ) && !defined( DOS )
599 #include <sys/time.h>
600 #endif /* !MACOS */
601
602 /* gtime(): the inverse of localtime().
603         This routine was supplied by Mike Accetta at CMU many years ago.
604  */
605
606 int     dmsize[] = {
607     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
608 };
609
610 #define dysize(y)       \
611         (((y) % 4) ? 365 : (((y) % 100) ? 366 : (((y) % 400) ? 365 : 366)))
612
613 #define YEAR(y)         ((y) >= 100 ? (y) : (y) + 1900)
614
615 /* \f */
616
617 static long     gtime ( struct tm *tm )
618 {
619     register int    i,
620                     sec,
621                     mins,
622                     hour,
623                     mday,
624                     mon,
625                     year;
626     register long   result;
627
628     if ((sec = tm -> tm_sec) < 0 || sec > 59
629             || (mins = tm -> tm_min) < 0 || mins > 59
630             || (hour = tm -> tm_hour) < 0 || hour > 24
631             || (mday = tm -> tm_mday) < 1 || mday > 31
632             || (mon = tm -> tm_mon + 1) < 1 || mon > 12)
633         return ((long) -1);
634     if (hour == 24) {
635         hour = 0;
636         mday++;
637     }
638     year = YEAR (tm -> tm_year);
639
640     result = 0L;
641     for (i = 1970; i < year; i++)
642         result += dysize (i);
643     if (dysize (year) == 366 && mon >= 3)
644         result++;
645     while (--mon)
646         result += dmsize[mon - 1];
647     result += mday - 1;
648     result = 24 * result + hour;
649     result = 60 * result + mins;
650     result = 60 * result + sec;
651
652     return result;
653 }