www.pudn.com > socks5.zip > aquery.c


/*                                                                           */ 
/*  * aquery.c : Programmatic Prospero interface to Archie                   */ 
/*  *                                                                        */ 
/*  * Copyright (c) 1991 by the University of Washington                     */ 
/*  *                                                                        */ 
/*  * For copying and distribution information, please see the file          */ 
/*  * .                                                         */ 
 
#include "pmachine.h" 
#include "pfs.h" 
#include "perrno.h" 
#include "archie.h" 
 
static void translateArchieResponse(); 
inline static int hostnamecmp(); 
 
extern int pwarn; 
extern char p_warn_string[]; 
 
/*                                                                           */ 
/*  * archie_query : Sends a request to _host_, telling it to search for     */ 
/*  * _string_ using _query_ 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.                   */ 
/*  * If _flags_ does not include AQ_NOTRANS, then the Archie                */ 
/*  * responses will be translated. If _flags_ does not include              */ 
/*  * AQ_NOSORT, then the list will be sorted using _cmp_proc_ to            */ 
/*  * compare pairs of links.  If _cmp_proc_ is NULL or AQ_DEFCMP,           */ 
/*  * then the default comparison procedure, defcmplink(), is used           */ 
/*  * sorting by host, then filename. If cmp_proc is AQ_INVDATECMP           */ 
/*  * then invdatecmplink() is used, sorting inverted by date.               */ 
/*  * otherwise a user-defined comparison procedure is called.               */ 
/*  *                                                                        */ 
/*  * 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: 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.                                                          */ 
/*  *                                                                        */ 
/*  * cmp_proc: AQ_DEFCMP Sort by host, then filename                        */ 
/*  * AQ_INVDATECMP Sort inverted by date                                    */ 
/*  *                                                                        */ 
/*  * flags: AQ_NOSORT Don't sort results                                    */ 
/*  * AQ_NOTRANS Don't translate results                                     */ 
VLINK  
archie_query(host,string,max_hits,offset,query,cmp_proc,flags) 
    char	*host,*string; 
    int		max_hits,offset; 
    Query	query; 
    int		(*cmp_proc)(); 
    int		flags; 
    { 
	char qstring[MAX_VPATH];    /* For construting the query             */ 
	VLINK	links;		/* Matches returned by server                */ 
	VDIR_ST	dir_st;         /* Filled in by get_vdir                     */ 
	PVDIR	dir= &dir_st; 
	 
	VLINK	p,q,r,lowest,nextp,pnext,pprev; 
	int	tmp; 
 
	/* Set the cmp_proc if not given                                     */ 
	if (cmp_proc == NULL) cmp_proc = defcmplink; 
 
	/* Make the query string                                             */ 
	sprintf(qstring,"ARCHIE/MATCH(%d,%d,%c)/%s", 
		max_hits,offset, (char) query,string); 
 
	/* Initialize Prospero structures                                    */ 
	perrno = PSUCCESS; *p_err_string = '\0'; 
	pwarn = PNOWARN; *p_warn_string = '\0'; 
	vdir_init(dir); 
	 
	/* Retrieve the list of matches, return error if there was one       */ 
	if((tmp = get_vdir(host,qstring,"",dir,GVD_ATTRIB|GVD_NOSORT,NULL,NULL))) { 
	    perrno = tmp; 
	    return(NULL); 
	} 
 
	/* 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; 
	    } 
	} 
 
	/* Translate the filenames unless NOTRANS was given                  */ 
	if (!(flags & AQ_NOTRANS)) 
	    for (p = links; p != NULL; p = p->next) 
		translateArchieResponse(p); 
 
	/* If NOSORT given, then just hand it back                           */ 
	if (flags & AQ_NOSORT) { 
	    perrno = PSUCCESS; 
	    return(links); 
	} 
 
	/* Otherwise sort it using a selection sort and the given cmp_proc   */ 
	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 the links                                                  */ 
	perrno = PSUCCESS; 
	return(links); 
    } 
 
/*                                                                           */ 
/*  * translateArchieResponse:                                               */ 
/*  *                                                                        */ 
/*  * If the given link is for an archie-pseudo directory, fix it.           */ 
/*  * This is called unless AQ_NOTRANS was given to archie_query().          */ 
static void 
translateArchieResponse(l) 
    VLINK l; 
    { 
	char *slash; 
 
	if (strcmp(l->type,"DIRECTORY") == 0) { 
	    if (strncmp(l->filename,"ARCHIE/HOST",11) == 0) { 
		l->type = stcopyr("EXTERNAL(AFTP,DIRECTORY)",l->type); 
		l->host = stcopyr(l->filename+12,l->host); 
		slash = (char *)index(l->host,'/'); 
		if (slash) { 
		    l->filename = stcopyr(slash,l->filename); 
		    *slash++ = '\0'; 
		} else 
		    l->filename = stcopyr("",l->filename); 
	    } 
	} 
    } 
 
 
/* hostnamecmp: Compare two hostnames based on domain,                       */ 
/*  * right-to-left.  Returns <0 if a belongs before b, >0                   */ 
/*  * if b belongs before a, and 0 if they are identical.                    */ 
/*  * Contributed by asami@cs.berkeley.edu (Satoshi ASAMI).                  */ 
inline  
static int 
hostnamecmp(a,b) 
    char *a,*b; 
    { 
	char	*pa, *pb; 
	int	result; 
 
	for (pa = a ; *pa ; pa++) 
	    ; 
	for (pb = b ; *pb ; pb++) 
	    ; 
 
	while (pa > a && pb > b) { 
	    for (; pa > a ; pa--) 
		if (*pa == '.')	{ 
		    pa++; 
		    break; 
		} 
	    for (; pb > b ; pb--) 
		if (*pb == '.')	{ 
		    pb++; 
		    break; 
		} 
	    if ((result = strcmp(pa, pb))) 
		return (result); 
	    pa -= 2; 
	    pb -= 2; 
	} 
	if (pa <= a) { 
	    if (pb <= b) 
		return (0); 
	    else 
		return (-1); 
	} else 
	    return (1); 
    } 
 
/*                                                                           */ 
/*  * 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=hostnamecmp(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); 
    }