Net2/usr/src/contrib/isode/others/quipu/uips/fred/whois.c

Compare this file to the similar file:
Show the results in this format:

/* whois.c - fred whois function */

#ifndef	lint
static char *rcsid = "$Header: /f/osi/others/quipu/uips/fred/RCS/whois.c,v 7.26 91/02/22 09:30:58 mrose Interim $";
#endif

/* 
 * $Header: /f/osi/others/quipu/uips/fred/RCS/whois.c,v 7.26 91/02/22 09:30:58 mrose Interim $
 *
 *
 * $Log:	whois.c,v $
 * Revision 7.26  91/02/22  09:30:58  mrose
 * Interim 6.8
 * 
 * Revision 7.25  91/02/19  09:21:17  mrose
 * ufn
 * 
 * Revision 7.24  91/02/12  18:25:42  mrose
 * update
 * 
 * Revision 7.23  91/01/10  04:03:10  mrose
 * update
 * 
 * Revision 7.22  91/01/07  12:43:30  mrose
 * update
 * 
 * Revision 7.21  90/11/20  15:33:45  mrose
 * update
 * 
 * Revision 7.20  90/11/11  09:57:40  mrose
 * touch-up
 * 
 * Revision 7.19  90/11/01  22:02:52  mrose
 * update
 * 
 * Revision 7.18  90/10/29  11:50:22  mrose
 * more stuff
 * 
 * Revision 7.17  90/10/28  22:41:07  mrose
 * update
 * 
 * Revision 7.16  90/10/23  20:42:28  mrose
 * update
 * 
 * Revision 7.15  90/10/18  11:33:55  mrose
 * psi
 * 
 * Revision 7.14  90/07/27  08:45:10  mrose
 * update
 * 
 * Revision 7.13  90/07/09  14:41:21  mrose
 * sync
 * 
 * Revision 7.12  90/06/11  21:17:12  mrose
 * touch-up
 * 
 * Revision 7.11  90/06/11  10:55:38  mrose
 * UFN
 * 
 * Revision 7.10  90/03/23  02:39:29  mrose
 * network
 * 
 * Revision 7.9  90/03/15  11:20:45  mrose
 * quipu-sync
 * 
 * Revision 7.8  90/03/08  08:05:10  mrose
 * phone
 * 
 * Revision 7.7  90/01/16  20:43:45  mrose
 * last check-out
 * 
 * Revision 7.6  90/01/11  18:36:41  mrose
 * real-sync
 * 
 * Revision 7.5  89/12/18  08:44:23  mrose
 * typo
 * 
 * Revision 7.4  89/12/14  18:49:05  mrose
 * KIS project
 * 
 * Revision 7.3  89/12/01  10:45:11  mrose
 * touch-up
 * 
 * Revision 7.2  89/11/26  15:09:32  mrose
 * sync
 * 
 * Revision 7.1  89/11/26  14:25:22  mrose
 * sync
 * 
 * Revision 7.0  89/11/23  22:09:06  mrose
 * Release 6.0
 * 
 */

/*
 *				  NOTICE
 *
 *    Acquisition, use, and distribution of this module and related
 *    materials are subject to the restrictions of a license agreement.
 *    Consult the Preface in the User's Manual for the full terms of
 *    this agreement.
 *
 */


#include <ctype.h>
#include <signal.h>
#include "fred.h"

/*    DATA */

struct whois {
    char   *w_input;
    int	    w_inputype;
#define	W_NULL		0x00
#define	W_HANDLE	0x01
#define	W_MAILBOX	0x02
#define	W_NAME		0x03

    int	    w_nametype;
#define	W_COMMONAME	0x01
#define	W_SURNAME	0x02

    int	    w_record;	/* same values as ag_record */

    char   *w_title;

    char   *w_area;
    int	    w_areatype;
    char   *w_geography;

    int	    w_output;
#define	W_EXPAND	0x01
#define	W_FULL		0x02
#define	W_SUMMARY	0x04
#define	W_SUBDISPLAY	0x08
};


char   *eqstr (), *limits ();
FILE   *capture ();

/*  */

char *whois_help[] = {
    "whois input-field [record-type] [area-designator] [output-control]",
    "    input-field is one of:",
    "\tname NAME\t\te.g., surname \"smith\", or fullname \"john smith\"",
    "\thandle HANDLE\t\te.g., handle @c=US@cn=Manager",
    "\tmailbox LOCAL@DOMAIN\te.g., mailbox postmaster@nisc.psi.net",
    "    record-type is one of:",
    "\tperson or -title NAME\te.g., -title scientist",
    "\torganization",
    "\tunit (a division under an organization)",
    "\trole (a role within an organization)",
    "\tlocality",
    "\tdsa (white pages server)",
    "    area-designator is one of:",
    "\t-org NAME\t\te.g., -org psi",
    "\t-unit NAME\t\te.g., -unit engineering",
    "\t-locality NAME\t\te.g., -locality rensselaer",
    "\t-area HANDLE\t\te.g., -area \"@c=US@o=Performance Systems...\"",
    "\t    and may be optionally followed by -geo HANDLE, e.g., -geo @c=GB",
    "    output-control is any of:",
    "\texpand\t   - give a detailed listing, followed by children",
    "\tsubdisplay - give a one-listing listing, followed by children",
    "\tfull\t   - give a detailed listing, even on ambiguous matches",
    "\tsummary\t   - give a one-line listing, even on unique matches",

    NULL
};

/*    WHOIS */

int	f_whois (vec)
char  **vec;
{
    if (strcmp (*vec, "whois") == 0)
	vec++;

    return (nametype > 1 ? f_ufn (vec) : f_whois_aux (vec));
}

/*  */

static int  f_whois_aux (vec)
char  **vec;
{
    int	    c,
	    mailbox,
	    multiple,
	    result;
    register char *bp,
		  *cp,
		  *dp;
    char    buffer[BUFSIZ],
	    orgname[BUFSIZ];
    register struct area_guide *ag;
    struct whois ws;
    register struct whois *w = &ws;
    FILE   *fp;

    bzero ((char *) w, sizeof *w);

    while (cp = *vec++) {
postscan: ;

	switch (*cp) {
	    case '.':
	        if (w -> w_inputype != W_NULL) {
too_many_fields: ;
		    advise (NULLCP,
			   "only one of NAME, HANDLE, or MAILBOX allowed");
		    goto you_really_lose;
		}
		if (*++cp == NULL) {
		    advise (NULLCP, "expecting NAME after \".\"");
		    goto you_really_lose;
		}
		w -> w_inputype = W_NAME;
		w -> w_input = cp;
		break;

	    case '!':
		if (w -> w_inputype != W_NULL)
		    goto too_many_fields;
		if (*++cp == NULL) {
		    advise (NULLCP, "expecting HANDLE after \"!\"");
		    goto you_really_lose;
		}
		goto got_handle;

	    case '*':
		if (cp[1] == '*') {
		    cp++;
		    goto name_or_something;
		}
		w -> w_output |= W_EXPAND;
	        if (*++cp)
		    goto postscan;
		break;
		
	    case '~':
		w -> w_output &= ~W_EXPAND;
	        if (*++cp)
		    goto postscan;
		break;
		
	    case '|':
		w -> w_output |= W_FULL;
	        if (*++cp)
		    goto postscan;
		break;
		
	    case '$':
		w -> w_output |= W_SUMMARY;
	        if (*++cp)
		    goto postscan;
		break;
		
	    case '%':
		w -> w_output |= W_SUBDISPLAY;
	        if (*++cp)
		    goto postscan;
		break;
		
	    case '-':
		if (test_arg (cp, "-area", 4)) {
		    result = W_NULL;

stuff_area: ;
		    if (w -> w_area != NULL) {
			advise (NULLCP, "only one AREA specification allowed");
			goto you_really_lose;
		    }
		    if (*vec == NULL) {
			advise (NULLCP, "expecting %s after \"%s\"",
				result != W_NULL ? "NAME" : "HANDLE", cp);
			goto you_really_lose;
		    }
		    if (*(dp = *vec) == '!')
			result = W_NULL;
		    else {
			for (; *dp; dp++)
			    if (!isdigit (*dp))
				break;
			if (!*dp)
			    result = NULL;
		    }
		    w -> w_area = *vec++, w -> w_areatype = result;
		    break;

		}
		if (test_arg (cp, "-expand", 4)) {
		    w -> w_output |= W_EXPAND;
		    break;
		}
		if (test_arg (cp, "-full", 4)) {
		    w -> w_output |= W_FULL;
		    break;
		}
		if (test_arg (cp, "-geography", 4)) {
		    if (*vec == NULL) {
			advise (NULLCP,
				"expecting location after \"-geography\"");
			goto you_really_lose;
		    }
		    w -> w_geography = *vec++;
		    break;
		}
		if (test_arg (cp, "-help", 5))
		    goto print_help;
		if (test_arg (cp, "-locality", 4)) {
		    result = W_LOCALITY;
		    goto stuff_area;
		}
		if (test_arg (cp, "-organization", 4)) {
		    result = W_ORGANIZATION;
		    goto stuff_area;
		}
		if (test_arg (cp, "-summary", 4)) {
		    w -> w_output |= W_SUMMARY;
		    break;
		}
		if (test_arg (cp, "-subdisplay", 4)) {
		    w -> w_output |= W_SUBDISPLAY;
		    break;
		}
		if (test_arg (cp, "-title", 4)) {
		    if (*vec == NULL) {
			advise (NULLCP,
				"expecting something after \"-title\"");
			goto you_really_lose;
		    }
		    w -> w_title = *vec++;
		    break;
		}
		if (test_arg (cp, "-unit", 4)) {
		    result = W_UNIT;
		    goto stuff_area;
		}

		advise (NULLCP, "unknown switch: %s", cp);
you_really_lose: ;
		if (mail) {
		    fprintf (stdfp, "\n\n");
		    goto print_help;
		}
		return NOTOK;

	    case 'd':
		if (strcmp (cp, "dsa"))
		    goto name_or_something;
		if (w -> w_record != W_NULL)
		    goto too_many_fields;
		w -> w_record = W_DSA;
		break;
		
	    case 'e':
		if (strcmp (cp, "expand"))
		    goto name_or_something;
		w -> w_output |= W_EXPAND;
		break;
		
	    case 'f':
		if (strcmp (cp, "full") == 0) {
		    w -> w_output |= W_FULL;
		    break;
		}
		if (strcmp (cp, "fullname") == 0) {
		    w -> w_nametype = W_COMMONAME;
		    goto name;
		}
		goto name_or_something;
		
	    case 'h':
		if (strcmp (cp, "handle"))
		    goto name_or_something;
		if (w -> w_inputype != W_NULL)
		    goto too_many_fields;
		if ((cp = *vec++) == NULL) {
		    advise (NULLCP, "expecting HANDLE after \"handle\"");
		    goto you_really_lose;
		}
got_handle: ;
		if (!mail && strcmp (cp, "me") == 0) {
		    if (mydn == NULL) {
			advise (NULLCP,
				"who are you?  use the \"thisis\" command first...");
			return NOTOK;
		    }
		    cp = mydn;
		}
		w -> w_inputype = W_HANDLE;
		w -> w_input = cp;
		break;

	    case 'l':
		if (strcmp (cp, "locality"))
		    goto name_or_something;
		if (w -> w_record != W_NULL)
		    goto too_many_fields;
		w -> w_record = W_LOCALITY;
		break;
		
	    case 'm':
		if (strcmp (cp, "mailbox"))
		    goto name_or_something;
		if (w -> w_inputype != W_NULL)
		    goto too_many_fields;
		if ((cp = *vec++) == NULL) {
		    advise (NULLCP, "expecting MAILBOX after \"mailbox\"");
		    goto you_really_lose;
		}
		w -> w_inputype = W_MAILBOX;
		w -> w_input = cp;
		break;

	    case 'n':
		if (strcmp (cp, "name"))
		    goto name_or_something;
name: ;
		if (w -> w_inputype != W_NULL)
		    goto too_many_fields;
		if ((cp = *vec++) == NULL) {
		    advise (NULLCP, "expecting NAME after \"%sname\"",
			    w -> w_nametype == W_COMMONAME ? "full"
			  : w -> w_nametype == W_SURNAME ? "sur" : "");
		    goto you_really_lose;
		}
		w -> w_inputype = W_NAME;
		w -> w_input = cp;
		break;

	    case 'o':
		if (strcmp (cp, "organization") && strcmp (cp, "org"))
		    goto name_or_something;
		if (w -> w_record != W_NULL)
		    goto too_many_fields;
		w -> w_record = W_ORGANIZATION;
		break;
		
	    case 'p':
		if (strcmp (cp, "person"))
		    goto name_or_something;
		if (w -> w_record != W_NULL)
		    goto too_many_fields;
		w -> w_record = W_PERSON;
		break;
		
	    case 'r':
		if (strcmp (cp, "role"))
		    goto name_or_something;
		if (w -> w_record != W_NULL)
		    goto too_many_fields;
		w -> w_record = W_ROLE;
		break;
		
	    case 's':
		if (strcmp (cp, "subdisplay") == 0) {
		    w -> w_output |= W_SUBDISPLAY;
		    break;
		}
		if (strcmp (cp, "summary") == 0) {
		    w -> w_output |= W_SUMMARY;
		    break;
		}
		if (strcmp (cp, "surname") == 0) {
		    w -> w_nametype = W_SURNAME;
		    goto name;
		}
		goto name_or_something;
		
	    case 'u':
		if (strcmp (cp, "unit"))
		    goto name_or_something;
		if (w -> w_record != W_NULL)
		    goto too_many_fields;
		w -> w_record = W_UNIT;
		break;
		
	    default:
name_or_something: ;
		if (w -> w_inputype != W_NULL)
		    goto too_many_fields;
		for (dp = cp; *dp; dp++)
		    if (!isdigit (*dp))
			break;
		if (!*dp)
		    goto got_handle;
		if ((dp = index (cp, '@')) == NULL) {
		    w -> w_inputype = W_NAME;
		    w -> w_input = cp;
		    break;
		}
		if (index (dp + 1, '@') || index (dp + 1, '=')) {
		    w -> w_inputype = W_HANDLE;
		    w -> w_input = cp;
		    break;
		}
		if (!index (dp + 1, '.')) {
		    if (w -> w_area != W_NULL) {
			advise (NULLCP, "only one AREA specification allowed");
			goto you_really_lose;
		    }

		    *dp++ = NULL;

		    w -> w_inputype = W_NAME;
		    w -> w_input = cp;

		    w -> w_area = dp, w -> w_areatype = W_ORGANIZATION;
		    break;
		}
		w -> w_inputype = W_MAILBOX;
		w -> w_input = cp;
		break;
	}
    }

    if (w -> w_nametype != W_NULL)
	switch (w -> w_record) {
	    default:
	        advise (NULLCP, "record-type ignored with \"%sname\"",
			w -> w_nametype == W_COMMONAME ? "full" : "sur");
		/* and fall... */

	    case W_NULL:
		w -> w_record = W_PERSON;
		/* and fall... */

	    case W_PERSON:
		break;
	}

    if (w -> w_input && strcmp (w -> w_input, "*") == 0)
	w -> w_input = NULL, w -> w_inputype = W_NULL;
    if (w -> w_title && strcmp (w -> w_title, "*") == 0)
	w -> w_title = NULL;
    if ((w -> w_input || w -> w_title)
	    && w -> w_area
	    && strcmp (w -> w_area, "*") == 0)
	w -> w_area = NULL, w -> w_areatype = W_NULL;

    if (w -> w_title) {
	if (w -> w_inputype == W_NULL)
	    w -> w_inputype = W_NAME;
	if (w -> w_inputype != W_NAME) {
	    advise (NULLCP, "title specification ignored with %s",
		    w -> w_inputype == W_HANDLE ? "HANDLE" : "MAILBOX");
	    w -> w_title = NULL;
	}
	else
	    if (w -> w_record == W_NULL)
		w -> w_record = W_PERSON;
    }

    if (w -> w_inputype == W_HANDLE && w -> w_geography) {
	advise (NULLCP, "geography specification ignored with HANDLE");
	w -> w_geography = NULL;
    }
    if (w -> w_geography)
	if (w -> w_area == NULL) {
	    w -> w_area = w -> w_geography, w -> w_areatype = W_LOCALITY;
	    w -> w_geography = NULL;
	}
	else
	    if (*w -> w_geography == '!')
		w -> w_geography++;

    if (w -> w_inputype == W_HANDLE && w -> w_area) {
	advise (NULLCP, "area specification ignored with HANDLE");
	w -> w_area = NULL, w -> w_areatype = W_NULL;
    }
    if (w -> w_area)
	if (w -> w_inputype == W_NULL) {
	    if (*w -> w_area != '!') {
		for (dp = w -> w_area; *dp; dp++)
		    if (!isdigit (*dp))
			break;
		w -> w_inputype = *dp ? W_NAME : W_HANDLE,
		w -> w_input = w -> w_area;
	    }
	    else
		w -> w_inputype = W_HANDLE, w -> w_input = w -> w_area + 1;
	    w -> w_record = w -> w_areatype;
	    w -> w_area = NULL, w -> w_areatype = W_NULL;
	}
	else
	    if (*w -> w_area == '!')
		w -> w_area++;

    if (w -> w_inputype == W_NULL) {
	register char **ap;

	if (w -> w_record != W_NULL || w -> w_output != W_NULL) {
	     advise (NULLCP, "input-field missing");
	     return NOTOK;
	}

print_help: ;
	for (ap = whois_help; *ap; ap++)
	    fprintf (stdfp, "%s%s", *ap, EOLN);

	return OK;
    }
    else
	if (w -> w_inputype == W_NAME && w -> w_nametype == W_NULL)
	    w -> w_nametype = nametype ? W_SURNAME : W_COMMONAME;

    bp = buffer;

    mailbox = 0;
    if (w -> w_areatype == W_NULL) {
	if (w -> w_inputype == W_MAILBOX
	        && w -> w_area == NULL
	        && (cp = index (w -> w_input, '@'))
		&& !index (++cp, '*')) {
	    (void) sprintf (bp, "fred -dm2dn %s", cp);
	    bp += strlen (bp);
	    mailbox = 1;

	    goto multiple_searching;
	}

	return whois_aux (w);
    }

    (void) sprintf (bp,
		    "search %s -norelative -singlelevel -dontdereference -sequence default -types aliasedObjectName -value -nosearchalias ",
		    limits (-1));
    bp += strlen (bp);

    for (ag = areas; ag -> ag_record; ag++)
	if (ag -> ag_record == w -> w_areatype)
	    break;
    if (w -> w_geography) {
	(void) sprintf (bp, "\"%s\" ", w -> w_geography);
	bp += strlen (bp);

	w -> w_geography = NULL;
    }
    else
	if (ag -> ag_area) {
	    (void) sprintf (bp, "\"%s\" ", ag -> ag_area);
	    bp += strlen (bp);
	}

    (void) sprintf (bp, "-filter \"objectClass=%s & %s%s\"",
		    ag -> ag_class, ag -> ag_rdn, eqstr (w -> w_area, 0));
    bp += strlen (bp);

multiple_searching: ;
    if ((fp = capture (buffer)) == NULL)
	return NOTOK;

    if (interrupted) {
you_lose: ;
	(void) fclose (fp);
	return NOTOK;
    }

    w -> w_area = orgname, w -> w_areatype = W_NULL;

    multiple = 0;
    while (fgets (buffer, sizeof buffer, fp) && !interrupted) {
	if ((cp = index (buffer, '\n')) == NULL) {
	    advise (NULLCP, "internal error(1)");
	    goto you_lose;
	}
	*cp = NULL;
    
	if (!isdigit (*buffer)) {
	    fprintf (stderr, "%s\n", buffer);
	    continue;
	}

	if ((cp = index (buffer, ' ')) == NULL) {
	    advise (NULLCP, "internal error(2)");
	    goto you_lose;
	}
	*cp++ = NULL;
	while (*cp == ' ')
	    cp++;
	
	if (multiple == 0 && (c = getc (fp)) != EOF) {
	    (void) ungetc (c, fp);
	    multiple = 1;
	}

	if (mailbox && !index (cp, '@')) {
	    advise (NULLCP, "Unable to resolve domain beyond national level.");
	    continue;
	}
	if (multiple && query && !network)
	    switch (ask ("try %s [y/n] ? ", cp)) {
		case NOTOK:
		    continue;

	       case OK:
	       default:
		    break;

	       case DONE:
		    goto out;
	    }
	else
	    if (verbose) {
		fprintf (stdfp, "Trying @%s ...\n", cp);
		(void) fflush (stdfp);
	    }

	(void) sprintf (orgname, "@%s", cp);
	(void) whois_aux (w);

	fprintf (stdfp, EOLN);
	(void) fflush (stdfp);
    }

out: ;
    (void) fclose (fp);

    return OK;
}
    
/*  */

static whois_aux (w)
register struct whois *w;
{
    register char *bp,
		  *cp;
    char   *handle,
	    buffer[BUFSIZ];
    register struct area_guide *ag;

    for (ag = areas; ag -> ag_record; ag++)
	if (ag -> ag_record == w -> w_record)
	    break;

    bp = buffer;
    switch (w -> w_inputype) {
	case W_NULL:
	default:
	    advise (NULLCP, "internal error(8)");
	    return NOTOK;

	case W_HANDLE:
	    (void) sprintf (bp, "showentry \"%s\" %s -fred -dontdereference",
			    w -> w_input, limits (0));
	    bp += strlen (bp);
	    goto options;

	case W_MAILBOX:
	    (void) sprintf (bp, "search %s -fred ", limits (1));
	    bp += strlen (bp);

	    if (w -> w_area) {
		(void) sprintf (bp, "\"%s\" ", w -> w_area);
		bp += strlen (bp);
	    }

	    (void) sprintf (bp, "-subtree -filter \"");
	    bp += strlen (bp);

	    cp = w -> w_input;
	    if (*cp == '@')
		(void) sprintf (bp, "mail=*%s", cp);
	    else
		if (*(cp + strlen (cp) - 1) == '@' || !index (cp, '@'))
		    (void) sprintf (bp, "mail=%s*", cp);
	        else
		    if (index (cp, '*'))
			(void) sprintf (bp, "mail=%s", cp);
	    	    else
			(void) sprintf (bp,
					"(mail=%s | otherMailbox=internet$%s)",
					cp, cp);
	    bp += strlen (bp);
	    break;

	case W_NAME:
	    if (cp = w -> w_input) {
		cp += strlen (cp) - 1;
		if (*cp == '.')
		    *cp = '*';
	    }

	    (void) sprintf (bp, "search %s -%s ", limits (1),
			    kflag ? "show" : "fred");
	    bp += strlen (bp);

	    if (w -> w_area) {
		(void) sprintf (bp, "\"%s\" -subtree ", w -> w_area);
		bp += strlen (bp);
	    }
	    else
		if (w -> w_geography) {
		    (void) sprintf (bp, "\"%s\" ", w -> w_geography);
		    bp += strlen (bp);
		}
		else
		    if (ag -> ag_area) {
			(void) sprintf (bp, "\"%s\" %s ", ag -> ag_area,
					ag -> ag_search);
			bp += strlen (bp);
		    }
		    else {
			(void) sprintf (bp, "-subtree ");
			bp += strlen (bp);
		    }
	    (void) sprintf (bp, "-filter \"");
	    bp += strlen (bp);

	    handle = eqstr (w -> w_input, 0);
	    switch (w -> w_record) {
		case W_NULL:
		case W_PERSON:
		    if (handle) {
			if (w -> w_title
			        && (w -> w_record == W_NULL
				    || w -> w_nametype == W_SURNAME)) {
			    (void) sprintf (bp, "( ");
			    bp += strlen (bp);
			}
			if (w -> w_record == W_NULL) {
			    (void) sprintf (bp, "o%s | ou%s | l%s | ",
					    handle, handle, handle, handle);
			    bp += strlen (bp);
			}

			if (w -> w_nametype == W_SURNAME) {
			    if (w -> w_record == W_PERSON && !w -> w_title) {
				(void) sprintf (bp, "( ");
				bp += strlen (bp);
			    }
			    (void) sprintf (bp, "surname%s | mail=%s@* ",
					    eqstr (w -> w_input, 1),
					    w -> w_input);
			    bp += strlen (bp);
			    if (w -> w_record == W_PERSON && !w -> w_title) {
				(void) sprintf (bp, ") ");
				bp += strlen (bp);
			    }
			}
			else {
			    (void) sprintf (bp, "cn%s ", handle);
			    bp += strlen (bp);
			}

			if (w -> w_title
			        && (w -> w_record == W_NULL
				    || w -> w_nametype == W_SURNAME)) {
			    (void) sprintf (bp, ") ");
			    bp += strlen (bp);
			}
		    }
		    if (w -> w_title) {
			(void) sprintf (bp, "%stitle%s",
					handle ? "& " : "",
					eqstr (w -> w_title, 1));
			bp += strlen (bp);
		    }
		    break;

		default:
		    if (strcmp (handle, "=*")) {
			(void) sprintf (bp, "%s%s", ag -> ag_rdn, handle);
			bp += strlen (bp);
		    }
		    break;
	    }
	    break;
    }

    if (w -> w_record == W_PERSON
	    || (w -> w_record != W_NULL && strcmp (handle, "=*"))) {
	(void) sprintf (bp, " & ");
	bp += strlen (bp);
    }

    if (w -> w_record != W_NULL) {
	(void) sprintf (bp, "objectClass=%s", ag -> ag_class);
	bp += strlen (bp);
    }

    (void) sprintf (bp, "\"");
    bp += strlen (bp);
    
options: ;
    if (w -> w_output & W_EXPAND) {
	(void) sprintf (bp, " -expand");
	bp += strlen (bp);
    }
    if (w -> w_output & W_FULL) {
	(void) sprintf (bp, " -full");
	bp += strlen (bp);
    }
    if (w -> w_output & W_SUMMARY) {
	(void) sprintf (bp, " -summary");
	bp += strlen (bp);
    }
    if (w -> w_output & W_SUBDISPLAY) {
	(void) sprintf (bp, " -subdisplay");
	bp += strlen (bp);
    }

    (void) sprintf (bp, " -sequence %s", "default");
    bp += strlen (bp);

    return dish (buffer, 0);
}

/*  */

static int  test_arg (user, full, minlen)
char   *user,
       *full;
int	minlen;
{
    int	    i;

    if ((i = strlen (user)) < minlen
	    || i > strlen (full)
	    || strncmp (user, full, i))
	return 0;

    return 1;
}

/*  */

static char *eqstr (s, exact)
char   *s;
int	exact;
{
    static char buffer[BUFSIZ];

    if (s == NULL)
	return NULL;

    if (index (s, '*'))
	(void) sprintf (buffer, "=%s", s);
    else
	if (soundex)
	    (void) sprintf (buffer, "~=%s", s);
	else
	    if (exact)
		(void) sprintf (buffer, "=%s", s);
	    else
		(void) sprintf (buffer, "=%s*", s);

    return buffer;
}

/*  */

static char  *limits (isearch)
int	isearch;
{
    register char *bp;
    static char buffer[100];

    bp = buffer;

    if (phone) {
	(void) strcpy (bp, "-phone ");
	bp += strlen (bp);
    }

#ifdef	notdef	/* don't do this! */
    if (isearch) {
	(void) strcpy (bp, "-searchalias ");
	bp += strlen (bp);
    }
#endif

    (void) strcpy (bp, "-nosizelimit ");
    bp += strlen (bp);

    if (timelimit > 0)
	(void) sprintf (bp, "-timelimit %d", timelimit);
    else
	(void) strcpy (bp, "-notimelimit");
    bp += strlen (bp);

    if (isearch >= 0 && (network || oneshot)) {
	(void) strcpy (bp, " -nofredseq");
	bp += strlen (bp);
    }

    return buffer;
}

/*  */

static FILE *capture (command)
char   *command;
{
    int	    savnet,
	    savpage;
    char    tmpfil[BUFSIZ];
    FILE   *fp,
    	   *savfp;

    (void) strcpy (tmpfil, "/tmp/fredXXXXXX");
    (void) unlink (mktemp (tmpfil));
    
    if ((fp = fopen (tmpfil, "w+")) == NULL) {
	advise (tmpfil, "unable to create");
	return NULL;
    }
    (void) unlink (tmpfil);

    savfp = stdfp, stdfp = fp;
    savnet = network, network = 0;
    savpage = dontpage, dontpage = 1;
    
    (void) dish (command, 0);

    dontpage = savpage;
    network = savnet;
    stdfp = savfp;

    rewind (fp);

    return fp;
}

/*  */

static int  f_ufn (vec)
char  **vec;
{
    char   *cp,
    	    buffer[BUFSIZ];
    static int lastq = -1;

    if ((cp = vec[0]) == NULL || strcmp (cp, "-help") == 0) {
        fprintf (stdfp, "whois name...\n");
	fprintf (stdfp, "    find something in the white pages\n");

        return OK;
    }
    
    if (!test_ufn (cp)) {
	(void) strcpy (buffer, cp);
	(void) str2vec (buffer, vec);
	return f_whois_aux (vec);
    }

    (void) sprintf (buffer, "fred -ufn %s-options %x,%s",
		    phone ? "-phone," : "", ufn_options, cp);

    if (lastq != area_quantum) {
	(void) sync_ufnrc ();

	lastq = area_quantum;
    }

    return dish (buffer, 0);
}

/*  */

int	test_ufn (cp)
char   *cp;
{
    register char *dp;

    if (*(dp = cp) == '!')
	dp++;
    for (; *dp; dp++)
	if (!isdigit (*dp))
	    break;
    if (!*dp || *dp == '-') 			/* a handle, or oldstyle */
	return 0;

    if (!index (dp = cp, ',')) {
	while (dp = index (dp, ' '))
	    if (*++dp == '-')
		return 0;
	if (index (cp, '@'))
	    return 0;
    }

    if (strcmp (cp, "!me") == 0)
	return 0;

    return 1;
}