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