ftp.nice.ch/pub/next/connectivity/infosystems/Archie.2.18.s.tar.gz#/Archie/prospero.subproj/query.c

This is query.c in view mode; [Download] [Up]

/*
 * query.c : Programmatic Prospero interface to Archie
 *
 * Copyright (c) 1991 by the University of Washington
 *
 * For copying and distribution information, please see the file
 * <copyright.h>.
 *
 * Originally part of the Prospero Archie client by Clifford 
 * Neuman (bcn@isi.edu).  Modifications, addition of programmatic interface,
 * and new sorting code by George Ferguson (ferguson@cs.rochester.edu) 
 * and Brendan Kehoe (brendan@cs.widener.edu).
 *
 * v2.0   - 11/29/92 (gf)  - for xarchie 2.0 - and now we part company...
 * v1.3.2 - bpk - for Archie client 1.3.2
 * v1.2.0 - 09/17/91 (bpk) - added BULL & USG stuff, thanks to Jim Sillas
 * v1.1.3 - 08/30/91 (bpk) - cast index()
 * v1.1.2 - 08/20/91 (bcn) - make it do it properly (new invdatecmplink)
 * v1.1.1 - 08/20/91 (bpk) - made sorting go inverted as we purport it does
 */
#include <copyright.h>
#include <stdio.h>
#include <pfs.h>
#include <perrno.h>
#include <pmachine.h>
#include <archie.h>
#include <libc.h>

#include "query.h"

#ifdef NEED_TIME_H
# include <time.h>
#else
# ifndef VMS
#  include <sys/time.h>
# endif
#endif

/* These are in dirsend.c */
extern int client_dirsrv_timeout, client_dirsrv_retry, rdgram_priority;

/* Functions defined here: */
void queryAndParse();
VLINK archieQuery(), stringQuery();
int parseArchieQueryResults(), parseStringQueryResults();
void parseHostAndFilename(), parseAttributes();
int handleProsperoErrors();

/* Data defined here */
int pfs_debug;
/* The fd for the read end of the pipe that NeXTArchie uses to signal
	that the user has aborted the select() system call.  It is set by the
	QueryThreadProc() by calling SetThreadAbortFD(). */
int threadAbortFD;

/* Functions to set the propsero/archie globals used by NeXTArchie */
void SetThreadAbortFD(int fd)
{
	threadAbortFD = fd;
}
void SetServerRetries(int count)
{
	client_dirsrv_retry = count;
}
void SetServerTimeout(int time)
{
	client_dirsrv_timeout = time;
}
void SetNiceLevel(int nice)
{
	rdgram_priority = nice;
}

#ifdef NO_NETWORK
PATTRIB_ST attribs[] = {
{  'C',  "SIZE",  "ASCII", "2048", 0x0, &attribs[1]},
{  'C',  "UNIX-MODES",  "ASCII", "drwxrwxr-x", &attribs[0], &attribs[2]},
{  'C',  "LAST-MODIFIED",  "ASCII", "19900808000000Z", &attribs[2], 0x0},
{  'C',  "SIZE",  "ASCII", "512", 0x0, &attribs[4]},
{  'C',  "UNIX-MODES",  "ASCII", "drwxrwxr-x", &attribs[3], &attribs[5]},
{  'C',  "LAST-MODIFIED",  "ASCII", "19900503000000Z", &attribs[5], 0x0}
};
static VLINK_ST dummy[] = {
{0, "XNeXT",  'L',  0,  "DIRECTORY",  0x0,  0x0, "INTERNET-D", "NIC.SURA.NET", 
	"ASCII", "ARCHIE/HOST/ascwide.ascii.co.jp/pub/NEXT/XNeXT", 0,  0,  0x0, 
	0, 0,  0x0, &attribs[0],  0x0,  0x0, &dummy[1]},
{ 0,  "XNeXT",  'L', 0, "DIRECTORY",  0x0,  0x0,  "INTERNET-D",  "NIC.SURA.NET", 
	"ASCII", "ARCHIE/HOST/src.doc.ic.ac.uk/computing/graphics/systems/X11/contrib/XNeXT", 
	0,  0, 0x0,  0,  0,  0x0, &attribs[3],  0x0,  &dummy[0],  0x0}
};
#endif

/*
 * archie_query : Sends a request to _host_, telling it to search for
 *                _string_ using _query_type_ as the search method.
 *                No more than _max_hits_ matches are to be returned
 *                skipping over _offset_ matches.
 *
 *		  archie_query returns a linked list of virtual links. 
 *
 *                archie_query returns NULL and sets perrno if the query
 *                failed. Note that it can return NULL with perrno == PSUCCESS
 *                if the query didn't fail but there were simply no matches.
 *
 *   query_type:  S  Substring search ignoring case   
 *                C  Substring search with case significant
 *                R  Regular expression search
 *                =  Exact String Match
 *            s,c,e  Tries exact match first and falls back to S, C, or R 
 *                   if not found.
 */
VLINK 
archieQuery(host,string,max_hits,offset,query_type,cmp_proc,flags, msg)
char *host,*string;
int max_hits,offset;
char query_type;
int (*cmp_proc)();
int flags;
StatusMsgPtr msg;
{
char qstring[MAX_VPATH];
VLINK links;
VLINK SortList(VLINK links, int (*cmp_proc)());

	status0("Sending query...");

#ifdef NO_NETWORK
	links = &dummy[0];
	done("Query complete");
#else
	sprintf(qstring,"ARCHIE/MATCH(%d,%d,%c)/%s",
		    max_hits,offset,query_type,string);
	links = stringQuery(host, qstring, msg);
	if( perrno != PSUCCESS )
		return links;

	/* If NOSORT given, then just hand it back */
	if ( flags & AQ_NOSORT || cmp_proc == NULL ) 
		return links;

	/* Otherwise sort it using a selection sort and the given cmp_proc */
	links = SortList(links, cmp_proc);
#endif

	/* Return the links */
	perrno = PSUCCESS;
	return links;
}

/*
 * Returns an unsorted, untranslated list of vlinks for string from host
 */
VLINK
stringQuery(host, string, msg)
char *host,*string;
StatusMsgPtr msg;
{
    VLINK links;		/* Matches returned by server */
    VDIR_ST dir_st;		/* Filled in by get_vdir      */
    PVDIR dir = &dir_st;
    VLINK p,nextp,r;
    int	tmp;
    
	/* initialize Prospero globals from appResources */
	pfs_debug = DEBUG_LEVEL;
	if( client_dirsrv_timeout == 0 )
	{	/* Set default values */
		rdgram_priority = NICE_LEVEL;
		client_dirsrv_timeout = TIMEOUT;
		client_dirsrv_retry = RETRIES;
	}

    /* Initialize Prospero structures */
    perrno = PSUCCESS; *p_err_string = '\0';
    pwarn = PNOWARN; *p_warn_string = '\0';
    vdir_init(dir);

#ifdef DEBUG
fprintf(stderr, "p<%d>,timeout<%d>,retry<%d>\n", rdgram_priority,
	client_dirsrv_timeout, client_dirsrv_retry);
fprintf(stderr, "stringQuery(%s, %s)\n", host, string);
#endif
    /* Retrieve the list of matches, return error if there was one */
#if defined(MSDOS)
        if (tmp=get_vdir(host,string,"",dir,(long)GVD_ATTRIB|GVD_NOSORT,
			 NULL, NULL)) {
#else
	if (tmp=get_vdir(host,string,"",dir,GVD_ATTRIB|GVD_NOSORT,NULL,NULL, msg)) {
# endif
		perrno = tmp;
		done("Query failed");
		return 0;
    }
    
    /* Save the links, and clear in dir in case it's used again   */
    links = dir->links; dir->links = NULL;
    
    /* As returned, list is sorted by suffix, and conflicting     */
    /* suffixes appear on a list of "replicas".  We want to       */
    /* create a one-dimensional list sorted by host then filename */
    /* and maybe by some other parameter                          */
    
    /* First flatten the doubly-linked list */
    for (p = links; p != NULL; p = nextp)
	{
		nextp = p->next;
		if (p->replicas != NULL)
		{
	    	p->next = p->replicas;
	    	p->next->previous = p;
	    	for (r = p->replicas; r->next != NULL; r = r->next)
			/*EMPTY*/ ;
	    	r->next = nextp;
	    	nextp->previous = r;
	    	p->replicas = NULL;
		}
    }
	perrno = PSUCCESS;
	done("Query complete");
	return links;
}

/*
 * Here take the list of untranslated unsorted links and put them into the
 * database, translating and sorting as needed. The entries are added to
 * make a host-location-file hierarchy as appropriate for the top of the
 * database query for a query. Returns number of entries returned from query.
 */
int
parseArchieQueryResults(links,cmp_proc)
VLINK links;
int (*cmp_proc)();
{
    VLINK vl;
    char hostname[MAX_VPATH],location[MAX_VPATH],filename[MAX_VPATH];
    int type;
#ifdef MSDOS
    unsigned long size;
#else
    int size;
#endif
    char *modes,*gt_date,*archie_date;
    int num;

#ifdef DEBUG
    printf("parsing links...\n");
#endif
    num = 0;
    for (vl=links; vl != NULL; vl = vl->next) {
	parseHostAndFilename(vl,hostname,location,filename);
	parseAttributes(vl,&type,&size,&modes,&archie_date,&gt_date);
	num += 1;
    }
#ifdef DEBUG
    printf(" sorting entries...\n");
#endif
#ifdef DEBUG
    printf("parse done -- returning %d matches\n",num);
#endif
    return(num);
}

/*
 * Like parseArchieQueryresults(), but all the entries for the links are
 * added as immediate children of parent, rather than a three-level tree.
 *
 */
int
parseStringQueryResults(links,cmp_proc)
VLINK links;
int (*cmp_proc)();
{
    VLINK vl;
    char hostname[MAX_VPATH],location[MAX_VPATH],filename[MAX_VPATH];
    int type,size;
    char *modes,*gt_date,*archie_date;
    int num;

#ifdef DEBUG
    printf("parsing links...\n");
#endif
    num = 0;
    for (vl=links; vl != NULL; vl = vl->next) {
	parseHostAndFilename(vl,hostname,location,filename);
	parseAttributes(vl,&type,&size,&modes,&archie_date,&gt_date);
	num += 1;
    }
#ifdef DEBUG
    printf(" sorting entries...\n");
#endif
#ifdef DEBUG
    printf("parse done -- returning %d matches\n",num);
#endif
    return(num);
}
    
/*
 * Fills in hostname, location, and filename with the appropriately-translated
 * and adjusted information from the link vl.
 */
void
parseHostAndFilename(vl,hostname,location,filename)
VLINK vl;
char *hostname,*location,*filename;
{
    char *slash;

#ifdef DEBUG1
    printf(" input: host=\"%s\"\n        filename=\"%s\"\n        name=\"%s\"\n",vl->host,vl->filename,vl->name);
#endif
    /* If the link is for an Archie pseudo-directory, adjust names. */
    if (strcmp(vl->type,"DIRECTORY") == 0 &&
	strncmp(vl->filename,"ARCHIE/HOST",11) == 0) {
	strcpy(hostname,vl->filename+12);
	slash = index(hostname,'/');
	if (slash != NULL) {
	    strcpy(filename,slash);
	    *slash = '\0';
	} else
	    strcpy(filename,"/");
    } else {
	/* else just use the names as is */
	strcpy(hostname,vl->host);
	strcpy(filename,vl->filename);
    }
    /* The "location" is the leading part of the pathname */
    strcpy(location,filename);
    slash = rindex(location,'/');
    /* If filename ends with slash, try going back one more slash */
    if (slash && *(slash+1) == '\0')
	slash = (char *)rindex(slash,'/');
    if (slash) {
	strcpy(filename,slash+1);
	*slash = '\0';
    } else
	strcpy(location,"/");
    /* If filename was /foo, then we need to leave the slash there */
    if (*location == '\0')
	strcpy(location,"/");
#ifdef DEBUG1
    printf(" output: host=\"%s\"\n         location=\"%s\"\n         filename=\"%s\"\n",
	   hostname,location,filename);
#endif
}

/*
 * Fills in *sizep, *modesp, and archie_date with the information in the
 * attribute list of the link vl.
 */
void
parseAttributes(vl,typep,sizep,modesp,archie_datep,gt_datep)
VLINK vl;
int *typep;
#ifdef MSDOS
unsigned long *sizep;
#else
int *sizep;
#endif
char **modesp,**archie_datep,**gt_datep;
{
    static char date[64];
    PATTRIB ap;
    int  gt_year,gt_mon,gt_day,gt_hour,gt_min;
    struct tm *presenttime;
    long now;

    (void)time(&now);
    presenttime = localtime(&now);
    if (strcmp(vl->type,"DIRECTORY") == 0) {
	*typep = DIRECTORY_t;
    } else {
	*typep = FILE_t;
    }
    *sizep = 0;
    *modesp = "";
    *archie_datep = "";
    *gt_datep = "";
    gt_year = gt_mon = gt_day = gt_hour = gt_min = 0;
    for (ap = vl->lattrib; ap; ap = ap->next) {
	if (strcmp(ap->aname,"SIZE") == 0) {
#ifdef MSDOS
	    sscanf(ap->value.ascii,"%lu",sizep);
#else
	    sscanf(ap->value.ascii,"%d",sizep);
#endif
	} else if(strcmp(ap->aname,"UNIX-MODES") == 0) {
	    *modesp = ap->value.ascii;
	} else if(strcmp(ap->aname,"LAST-MODIFIED") == 0) {
	    *gt_datep = ap->value.ascii;
	    sscanf(*gt_datep,"%4d%2d%2d%2d%2d",&gt_year,
		   &gt_mon, &gt_day, &gt_hour, &gt_min);
	    if ((12 * (presenttime->tm_year + 1900 - gt_year) +
		 presenttime->tm_mon - gt_mon) > 6)
		sprintf(date,"%s %2d %4d",month_sname(gt_mon),
			gt_day, gt_year);
	    else
		sprintf(date,"%s %2d %02d:%02d",month_sname(gt_mon),
			gt_day, gt_hour, gt_min);
	    *archie_datep = date;
	}
    }
}

int handleProsperoErrors() {return 0;}

/*
 * Pops up alerts depending on perrno and pwarn.
int
handleProsperoErrors()
{
    int err = 0;

    if (perrno != PSUCCESS) {
	if (p_err_text[perrno]) {
	  if (*p_err_string)
		alert2("Prospero error: %.100s - %.100s",p_err_text[perrno],
			p_err_string);
	  else
		alert1("Prospero error: %.200s",p_err_text[perrno]);
	} else
	    alert1("Prospero error: Undefined error %d (prospero)",(char*)perrno);
	err = 1;
    }
    if (pwarn != PNOWARN) {
        if (*p_warn_string)
            alert2("Prospero warning: %.100s - %.100s",
                   p_warn_text[pwarn], p_warn_string);
        else
            alert1("Prospero warning: %.200s",p_warn_text[pwarn]);
        status0("Ready");
    }
    return(err);
}
*/

VLINK SortList(VLINK links, int (*cmp_proc)(VLINK, VLINK))
{
VLINK p, q, lowest, nextp, pnext, pprev;

	for (p = links; p != NULL; p = nextp)
	{
	    nextp = p->next;
	    lowest = p;
	    for (q = p->next; q != NULL; q = q->next)
		if ((*cmp_proc)(q,lowest) < 0)
		    lowest = q;
	    if (p != lowest) {
		/* swap the two links */
		pnext = p->next;
		pprev = p->previous;
		if (lowest->next != NULL)
		    lowest->next->previous = p;
		p->next = lowest->next;
		if (nextp == lowest) {
		    p->previous = lowest;
		} else {
		    lowest->previous->next = p;
		    p->previous = lowest->previous;
		}
		if (nextp == lowest) {
		    lowest->next = p;
		} else {
		    pnext->previous = lowest;
		    lowest->next = pnext;
		}
		if (pprev != NULL)
		    pprev->next = lowest;
		lowest->previous = pprev;
		/* keep the head of the list in the right place */
		if (links == p)
		    links = lowest;
	    }
	}

	return links;
}

/*
 * defcmplink: The default link comparison function for sorting. Compares
 *	       links p and q first by host then by filename. Returns < 0 if p
 *             belongs before q, > 0 if p belongs after q, and == 0 if their
 *             host and filename fields are identical.
 */
int defcmplink(p,q)
    VLINK p,q;
    {
	int result;

	if ((result=strcmp(p->host,q->host)) != 0)
	    return(result);
	else
	    return(strcmp(p->filename,q->filename));
    }

/*
 * invdatecmplink: An alternative comparison function for sorting that
 *	           compares links p and q first by LAST-MODIFIED date,
 *                 if they both have that attribute. If both links
 *                 don't have that attribute or the dates are the
 *                 same, it then calls defcmplink() and returns its 
 *		   value.
 */
int invdatecmplink(p,q)
    VLINK p,q;
    {
	PATTRIB pat,qat;
	char *pdate,*qdate;
	int result;
	
	pdate = qdate = NULL;
	for (pat = p->lattrib; pat; pat = pat->next)
	    if(strcmp(pat->aname,"LAST-MODIFIED") == 0)
		pdate = pat->value.ascii;
	for (qat = q->lattrib; qat; qat = qat->next)
	    if(strcmp(qat->aname,"LAST-MODIFIED") == 0)
		qdate = qat->value.ascii;
	if(!pdate && !qdate) return(defcmplink(p,q));
	if(!pdate) return(1); 
	if(!qdate) return(-1);
	if((result=strcmp(qdate,pdate)) == 0) return(defcmplink(p,q));
	else return(result);
    }

/* RCS Information:
	$Author: me $;
	$Date: 92/10/30 22:16:52 $;
	$Source: /usr1/me/NeXTSrc/Archie/RCS/aquery.c,v $;
	$Revision: 1.5 $;
*/

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.