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