home *** CD-ROM | disk | FTP | other *** search
- /*
- * aquery.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>.
- */
-
- #include <stdio.h>
-
- #include <pfs.h>
- #include <perrno.h>
- #include <archie.h>
-
- #include <pmachine.h>
- #ifdef NEED_STRING_H
- # include <string.h> /* for char *index() */
- #else
- # include <strings.h> /* for char *index() */
- #endif
-
- #ifdef __GNUC__
- #define INLINE __inline__
- #else
- #define INLINE
- #endif
-
- 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 defined(MSDOS)
- if(tmp = get_vdir(host, qstring, "", dir, (long)GVD_ATTRIB|GVD_NOSORT,
- NULL, NULL)) {
- #else
- if(tmp = get_vdir(host,qstring,"",dir,GVD_ATTRIB|GVD_NOSORT,NULL,NULL)) {
- # endif
- 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);
- }
-