openldap/clients/ud/print.c
1998-10-25 01:41:42 +00:00

655 lines
15 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 1991, 1993
* Regents of the University of Michigan. All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of Michigan at Ann Arbor. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
*/
#include "portable.h"
#include <stdio.h>
#include <ac/ctype.h>
#include <ac/string.h>
#include <ac/time.h>
#include <lber.h>
#include <ldap.h>
#include "ud.h"
#ifdef DEBUG
extern int debug;
#endif
struct entry Entry;
extern LDAP *ld;
extern void * Malloc();
extern void Free();
extern char * my_ldap_dn2ufn();
static char *time2text();
static long gtime();
/*
* When displaying entries, display only these attributes, and in this
* order.
*/
static char *person_attr_print_order[] = {
"cn",
"mail",
"telephoneNumber",
"facsimileTelephoneNumber",
"pager",
"postalAddress",
"title",
"uid",
"multiLineDescription",
"homePhone",
"homePostalAddress",
"drink",
"labeledURL",
"onVacation",
"vacationMessage",
"memberOfGroup",
"lastModifiedBy",
"lastModifiedTime",
NULL
};
static char *group_attr_print_order[] = {
"cn",
"facsimileTelephoneNumber",
"telephoneNumber",
"postalAddress",
"multiLineDescription",
"joinable",
"associatedDomain",
"owner",
"moderator",
"ErrorsTo",
"rfc822ErrorsTo",
"RequestsTo",
"rfc822RequestsTo",
"member",
"mail",
"labeledURL",
"lastModifiedBy",
"lastModifiedTime",
NULL
};
parse_answer(s)
LDAPMessage *s;
{
int idx;
char **rdns;
BerElement *cookie;
register LDAPMessage *ep;
register char *ap;
void clear_entry();
#ifdef DEBUG
if (debug & D_TRACE)
printf("->parse_answer(%x)\n", s);
#endif
clear_entry();
#ifdef DEBUG
if (debug & D_PARSE)
printf(" Done clearing entry\n");
#endif
for (ep = ldap_first_entry(ld, s); ep != NULL; ep = ldap_next_entry(ld, ep)) {
#ifdef DEBUG
if (debug & D_PARSE)
printf(" Determining DN and name\n");
#endif
Entry.DN = ldap_get_dn(ld, ep);
#ifdef DEBUG
if (debug & D_PARSE)
printf(" DN = %s\n", Entry.DN);
#endif
rdns = ldap_explode_dn(Entry.DN, TRUE);
#ifdef DEBUG
if (debug & D_PARSE)
printf(" Name = %s\n", *rdns);
#endif
Entry.name = strdup(*rdns);
ldap_value_free(rdns);
for (ap = ldap_first_attribute(ld, ep, &cookie); ap != NULL; ap = ldap_next_attribute(ld, ep, cookie)) {
#ifdef DEBUG
if (debug & D_PARSE)
printf("parsing ap = %s\n", ap);
#endif
if ((idx = attr_to_index(ap)) < 0) {
printf(" Unknown attribute \"%s\"\n", ap);
continue;
}
add_value(&(Entry.attrs[idx]), ep, ap);
}
}
#ifdef DEBUG
if (debug & D_PARSE)
printf(" Done parsing entry\n");
#endif
}
add_value(attr, ep, ap)
struct attribute *attr;
LDAPMessage *ep;
char *ap;
{
register int i = 0;
char **vp, **tp, **avp;
#ifdef DEBUG
if (debug & D_TRACE)
printf("->add_value(%x, %x, %s)\n", attr, ep, ap);
#endif
vp = (char **) ldap_get_values(ld, ep, ap);
/*
* Fill in the attribute structure for this attribute. This
* stores away the values (using strdup()) and the count. Terminate
* the list with a NULL pointer.
*
* attr->quipu_name has already been set during initialization.
*/
if ((attr->number_of_values = ldap_count_values(vp)) > 0) {
attr->values = (char **) Malloc((unsigned) ((attr->number_of_values + 1) * sizeof(char *)));
avp = attr->values;
for (i = 1, tp = vp; *tp != NULL; i++, tp++) {
#ifdef DEBUG
if (debug & D_PARSE)
printf(" value #%d %s\n", i, *tp);
#endif
/*
* The 'name' field of the Entry structure already has
* has the first part of the DN copied into it. Thus,
* we don't need to save it away here again. Also, by
* tossing it away here, we make printing this info out
* a bit easier later.
*/
if (!strcmp(ap, "cn") && !strcmp(*tp, Entry.name)) {
attr->number_of_values--;
continue;
}
*avp++ = strdup(*tp);
}
*avp = NULL;
}
ldap_value_free(vp);
}
print_an_entry()
{
int n = 0, i, idx;
char is_a_group, **order;
char *sub_list[MAX_VALUES], buf[SMALL_BUF_SIZE];
extern int col_size, isaurl(), isadn();
#ifdef DEBUG
if (debug & D_TRACE)
printf("->print_an_entry()\n");
#endif
printf(" \"%s\"\n", Entry.name);
/*
* If the entry is a group, find all of the subscribers to that
* group. A subscriber is an entry that *points* to a group entry,
* and a member is an entry that is included as part of a group
* entry.
*
* We also need to select the appropriate output format here.
*/
is_a_group = isgroup();
if (is_a_group) {
order = (char **) group_attr_print_order;
n = find_all_subscribers(sub_list, Entry.DN);
#ifdef DEBUG
if (debug & D_PRINT)
printf(" Group \"%s\" has %d subscribers\n",
Entry.name, n);
#endif
}
else
order = (char **) person_attr_print_order;
for (i = 0; order[i] != NULL; i++) {
idx = attr_to_index(order[i]);
#ifdef DEBUG
if (debug & D_PRINT) {
printf(" ATTR #%2d = %s [%s] (%d values)\n", i + 1,
Entry.attrs[idx].output_string,
Entry.attrs[idx].quipu_name,
Entry.attrs[idx].number_of_values);
}
#endif
if (idx < 0)
continue;
if (Entry.attrs[idx].number_of_values == 0)
continue;
if (isadn(order[i]))
print_DN(Entry.attrs[idx]);
else if (isaurl(order[i]))
print_URL(Entry.attrs[idx]);
else if (isadate(order[i])) {
/* fix time and date, then call usual routine */
Entry.attrs[idx].values[0] =
time2text(Entry.attrs[idx].values[0], FALSE);
print_values(Entry.attrs[idx]);
}
else
print_values(Entry.attrs[idx]);
}
/*
* If it is a group, then we should print the subscriber list (if
* there are any). If there are a lot of them, prompt the user
* before printing them.
*/
if (is_a_group && (n > 0)) {
char *label = "Subscribers: ";
if (n > TOO_MANY_TO_PRINT) {
printf(" There are %d subscribers. Print them? ", n);
fflush(stdout);
fetch_buffer(buf, sizeof(buf), stdin);
if (!((buf[0] == 'y') || (buf[0] == 'Y')))
return;
}
format2((char *) my_ldap_dn2ufn(sub_list[n - 1]), label, (char *) NULL, 2,
2 + strlen(label) + 1, col_size);
for (n--; n > 0; n--)
format2((char *) my_ldap_dn2ufn(sub_list[n - 1]), (char *) NULL,
(char *) NULL, 2 + strlen(label),
2 + strlen(label) + 2, col_size);
}
return;
}
#define OUT_LABEL_LEN 20
/* prints the values associated with an attribute */
print_values(A)
struct attribute A;
{
register int i, k;
register char *cp, **vp;
char out_buf[MED_BUF_SIZE], *padding = NULL;
int lead;
#ifdef DEBUG
if (debug & D_TRACE)
printf("->print_values(%x)\n", A);
#endif
if (A.number_of_values == 0)
return;
if ((vp = A.values) == NULL)
return;
/*
* Pad out the output string label so that it fills the
* whole field of length OUT_LABEL_LEN.
*/
out_buf[0] = '\0';
i = OUT_LABEL_LEN - strlen(A.output_string);
if (i < 0) {
printf("Output string for \"%s\" is too long. Maximum length is %d characters\n", A.quipu_name, OUT_LABEL_LEN);
return;
}
if (isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values == 0)) {
A.output_string = "Members";
i = OUT_LABEL_LEN - strlen(A.output_string);
padding = (char *) Malloc((unsigned) (i + 1));
(void) memset(padding, ' ', i);
*(padding + i) = '\0';
sprintf(out_buf, "%s:%s", A.output_string, padding);
}
else if (!(isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values > 0))) {
padding = (char *) Malloc((unsigned) (i + 1));
(void) memset(padding, ' ', i);
*(padding + i) = '\0';
sprintf(out_buf, "%s:%s", A.output_string, padding);
}
/*
* If this happens to be a group, then do not print the output
* string if we have already printed out some members.
*/
else if (isgroup() && !strcmp(A.quipu_name, "mail") && (Entry.attrs[attr_to_index("member")].number_of_values > 0)) {
padding = (char *) Malloc((unsigned) (OUT_LABEL_LEN + 2));
(void) memset(padding, ' ', OUT_LABEL_LEN + 1);
*(padding + OUT_LABEL_LEN + 1) = '\0';
sprintf(out_buf, "%s", padding);
}
lead = strlen(out_buf) + 2;
printf(" %s", out_buf);
for (i = 0; *vp != NULL; i++, vp++) {
if (i > 0) {
if (!strncmp(A.output_string, "Home a", 6) || !strncmp(A.output_string, "Business a", 10)) {
printf(" %s", out_buf);
}
else {
for (k = lead; k > 0; k--)
putchar(' ');
}
}
for (cp = *vp; *cp != '\0'; cp++) {
switch (*cp) {
case '$' :
if (!strncmp(A.output_string, "Home a", 6) || !strncmp(A.output_string, "Business a", 10) || !strcmp(A.quipu_name, "multiLineDescription")) {
putchar('\n');
for (k = lead; k > 0; k--)
putchar(' ');
while (isspace(*(cp + 1)))
cp++;
}
else
putchar(*cp);
break;
case '\n' :
putchar('%');
putchar('\n');
break;
default:
putchar(*cp);
}
}
putchar('\n');
}
if (padding != NULL)
Free(padding);
return;
}
/* prints the DN's associated with an attribute */
print_DN(A)
struct attribute A;
{
int i, lead;
register char **vp;
char out_buf[MED_BUF_SIZE], *padding = NULL;
extern int col_size;
#ifdef DEBUG
if (debug & D_TRACE)
printf("->print_DN(%x)\n", A);
#endif
if (A.number_of_values == 0)
return;
/*
* Pad out the output string label so that it fills the
* whole field of length OUT_LABEL_LEN.
*/
i = OUT_LABEL_LEN - strlen(A.output_string);
if (i > 0) {
padding = (char *) Malloc((unsigned) (i + 1));
(void) memset(padding, ' ', i);
*(padding + i) = '\0';
sprintf(out_buf, "%s:%s", A.output_string, padding);
(void) Free(padding);
}
lead = strlen(out_buf) + 2;
vp = A.values;
format2((char *) my_ldap_dn2ufn(*vp), out_buf, (char *) NULL, 2, lead + 1, col_size);
for (vp++; *vp != NULL; vp++) {
format2((char *) my_ldap_dn2ufn(*vp), (char *) NULL, (char *) NULL, lead,
lead + 1, col_size);
}
return;
}
void clear_entry()
{
register int i;
extern struct attribute attrlist[];
#ifdef DEBUG
if (debug & D_TRACE)
printf("->clear_entry()\n");
if ((debug & D_PRINT) && (Entry.name != NULL))
printf(" Clearing entry \"%s\"\n", Entry.name);
#endif
if (Entry.DN != NULL)
Free(Entry.DN);
if (Entry.name != NULL)
Free(Entry.name);
Entry.may_join = FALSE;
Entry.subscriber_count = -1;
Entry.DN = Entry.name = NULL;
/* clear all of the values associated with all attributes */
for (i = 0; attrlist[i].quipu_name != NULL; i++) {
#ifdef DEBUG
if (debug & D_PRINT)
printf(" Clearing attribute \"%s\" -- ",
Entry.attrs[i].quipu_name);
#endif
if (Entry.attrs[i].values == NULL) {
#ifdef DEBUG
if (debug & D_PRINT)
printf(" no values, skipping\n");
#endif
continue;
}
#ifdef DEBUG
if (debug & D_PRINT)
printf(" freeing %d values\n",
Entry.attrs[i].number_of_values);
#endif
Entry.attrs[i].number_of_values = 0;
ldap_value_free(Entry.attrs[i].values);
Entry.attrs[i].values = (char **) NULL;
/*
* Note: We do not clear either of the char * fields
* since they will always be applicable.
*/
}
}
attr_to_index(s)
char *s;
{
register int i;
extern struct attribute attrlist[];
for (i = 0; attrlist[i].quipu_name != NULL; i++)
if (!strcasecmp(s, attrlist[i].quipu_name))
return(i);
return(-1);
}
void initialize_attribute_strings()
{
register int i;
extern struct entry Entry;
extern struct attribute attrlist[];
for (i = 0; attrlist[i].quipu_name != NULL; i++)
Entry.attrs[i].quipu_name = attrlist[i].quipu_name;
for (i = 0; attrlist[i].quipu_name != NULL; i++)
Entry.attrs[i].output_string = attrlist[i].output_string;
}
/* prints the URL/label pairs associated with an attribute */
print_URL(A)
struct attribute A;
{
int i, lead;
register char **vp;
char out_buf[MED_BUF_SIZE], *padding = NULL;
#ifdef DEBUG
if (debug & D_TRACE)
printf("->print_URL(%x)\n", A);
#endif
if (A.number_of_values == 0)
return;
/*
* Pad out the output string label so that it fills the
* whole field of length OUT_LABEL_LEN.
*/
i = OUT_LABEL_LEN - strlen(A.output_string);
if (i > 0) {
padding = (char *) Malloc((unsigned) (i + 1));
(void) memset(padding, ' ', i);
*(padding + i) = '\0';
sprintf(out_buf, "%s:%s", A.output_string, padding);
}
lead = strlen(out_buf) + 2;
vp = A.values;
print_one_URL(*vp, 2, out_buf, lead);
for (vp++; *vp != NULL; vp++)
print_one_URL(*vp, lead, (char *) NULL, lead);
if (padding != NULL)
Free(padding);
return;
}
print_one_URL(s, label_lead, tag, url_lead)
char *s;
int label_lead;
char *tag;
int url_lead;
{
register int i;
char c, *cp, *url;
extern int col_size;
extern void Free();
for (cp = s; !isspace(*cp) && (*cp != '\0'); cp++)
;
c = *cp;
*cp = '\0';
url = strdup(s);
*cp = c;
if (*cp != '\0') {
for (cp++; isspace(*cp); cp++)
;
}
else
cp = "(no description available)";
format2(cp, tag, (char *) NULL, label_lead, label_lead + 1, col_size);
for (i = url_lead + 2; i > 0; i--)
printf(" ");
printf("%s\n", url);
Free(url);
}
#define GET2BYTENUM( p ) (( *p - '0' ) * 10 + ( *(p+1) - '0' ))
static char *
time2text( char *ldtimestr, int dateonly )
{
struct tm t;
char *p, *timestr, zone, *fmterr = "badly formatted time";
time_t gmttime;
memset( (char *)&t, 0, sizeof( struct tm ));
if ( strlen( ldtimestr ) < 13 ) {
return( fmterr );
}
for ( p = ldtimestr; p - ldtimestr < 12; ++p ) {
if ( !isdigit( *p )) {
return( fmterr );
}
}
p = ldtimestr;
t.tm_year = GET2BYTENUM( p ); p += 2;
t.tm_mon = GET2BYTENUM( p ) - 1; p += 2;
t.tm_mday = GET2BYTENUM( p ); p += 2;
t.tm_hour = GET2BYTENUM( p ); p += 2;
t.tm_min = GET2BYTENUM( p ); p += 2;
t.tm_sec = GET2BYTENUM( p ); p += 2;
if (( zone = *p ) == 'Z' ) { /* GMT */
zone = '\0'; /* no need to indicate on screen, so we make it null */
}
gmttime = gtime( &t );
timestr = ctime( &gmttime );
timestr[ strlen( timestr ) - 1 ] = zone; /* replace trailing newline */
if ( dateonly ) {
strcpy( timestr + 11, timestr + 20 );
}
Free ( ldtimestr );
return( strdup( timestr ) );
}
/* gtime.c - inverse gmtime */
#include <ac/time.h>
/* gtime(): the inverse of localtime().
This routine was supplied by Mike Accetta at CMU many years ago.
*/
int dmsize[] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
#define dysize(y) \
(((y) % 4) ? 365 : (((y) % 100) ? 366 : (((y) % 400) ? 365 : 366)))
#define YEAR(y) ((y) >= 100 ? (y) : (y) + 1900)
/* */
static long gtime ( struct tm *tm )
{
register int i,
sec,
mins,
hour,
mday,
mon,
year;
register long result;
if ((sec = tm -> tm_sec) < 0 || sec > 59
|| (mins = tm -> tm_min) < 0 || mins > 59
|| (hour = tm -> tm_hour) < 0 || hour > 24
|| (mday = tm -> tm_mday) < 1 || mday > 31
|| (mon = tm -> tm_mon + 1) < 1 || mon > 12)
return ((long) -1);
if (hour == 24) {
hour = 0;
mday++;
}
year = YEAR (tm -> tm_year);
result = 0L;
for (i = 1970; i < year; i++)
result += dysize (i);
if (dysize (year) == 366 && mon >= 3)
result++;
while (--mon)
result += dmsize[mon - 1];
result += mday - 1;
result = 24 * result + hour;
result = 60 * result + mins;
result = 60 * result + sec;
return result;
}