home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / UNIX / ARCHIE / CLIENTS / XARCHIE2.TAR / aquery.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-02  |  7.5 KB  |  251 lines

  1. /*
  2.  * aquery.c : Programmatic Prospero interface to Archie
  3.  *
  4.  * Copyright (c) 1991 by the University of Washington
  5.  *
  6.  * For copying and distribution information, please see the file
  7.  * <copyright.h>.
  8.  *
  9.  * Originally part of the Prospero Archie client by Clifford 
  10.  * Neuman (bcn@isi.edu).  Modifications, addition of programmatic interface,
  11.  * and new sorting code by George Ferguson (ferguson@cs.rochester.edu) 
  12.  * and Brendan Kehoe (brendan@cs.widener.edu).
  13.  *
  14.  * v1.2.0 - 09/17/91 (bpk) - added BULL & USG stuff, thanks to Jim Sillas
  15.  * v1.1.3 - 08/30/91 (bpk) - cast index()
  16.  * v1.1.2 - 08/20/91 (bcn) - make it do it properly (new invdatecmplink)
  17.  * v1.1.1 - 08/20/91 (bpk) - made sorting go inverted as we purport it does
  18.  */
  19. #include <copyright.h>
  20.  
  21. #include <stdio.h>
  22. #if defined(USG) || defined(UTS) || defined(_AIX)
  23. # include <string.h>            /* for char *index() */
  24. #else
  25. # include <strings.h>            /* for char *index() */
  26. #endif
  27.  
  28. #include <pfs.h>
  29. #include <perrno.h>
  30. #include <pmachine.h>
  31. #include <archie.h>
  32.  
  33. static void translateArchieResponse();
  34.  
  35. extern int pwarn;
  36. extern char p_warn_string[];
  37.  
  38. /*
  39.  * archie_query : Sends a request to _host_, telling it to search for
  40.  *                _string_ using _query_type_ as the search method.
  41.  *                No more than _max_hits_ matches are to be returned
  42.  *                skipping over _offset_ matches.
  43.  *
  44.  *          archie_query returns a linked list of virtual links. 
  45.  *                If _flags_ does not include AQ_NOTRANS, then the Archie
  46.  *                responses will be translated. If _flags_ does not include 
  47.  *                AQ_NOSORT, then the list will be sorted using _cmp_proc_ to
  48.  *                compare pairs of links.  If _cmp_proc_ is NULL or AQ_DEFCMP,
  49.  *                then the default comparison procedure, defcmplink(), is used
  50.  *                sorting by host, then filename. If cmp_proc is AQ_INVDATECMP
  51.  *                then invdatecmplink() is used, sorting inverted by date.
  52.  *                otherwise a user-defined comparison procedure is called.
  53.  *
  54.  *                archie_query returns NULL and sets perrno if the query
  55.  *                failed. Note that it can return NULL with perrno == PSUCCESS
  56.  *                if the query didn't fail but there were simply no matches.
  57.  *
  58.  *   query_type:  S  Substring search ignoring case   
  59.  *                C  Substring search with case significant
  60.  *                R  Regular expression search
  61.  *                =  Exact String Match
  62.  *            s,c,e  Tries exact match first and falls back to S, C, or R 
  63.  *                   if not found.
  64.  *
  65.  *     cmp_proc:  AQ_DEFCMP      Sort by host, then filename
  66.  *                AQ_INVDATECMP  Sort inverted by date
  67.  *
  68.  *        flags:  AQ_NOSORT      Don't sort results
  69.  *                AQ_NOTRANS     Don't translate results
  70.  */
  71. VLINK 
  72. archie_query(host,string,max_hits,offset,query_type,cmp_proc,flags)
  73.     char    *host,*string;
  74.     int        max_hits,offset;
  75.     char    query_type;
  76.     int        (*cmp_proc)();
  77.     int        flags;
  78.     {
  79.     char qstring[MAX_VPATH];    /* For construting the query  */
  80.     VLINK    links;        /* Matches returned by server */
  81.     VDIR_ST    dir_st;         /* Filled in by get_vdir      */
  82.     VDIR    dir= &dir_st;
  83.     
  84.     VLINK    p,q,r,lowest,nextp,pnext,pprev;
  85.     int    tmp;
  86.  
  87.     /* Set the cmp_proc if not given */
  88.     if (cmp_proc == NULL) cmp_proc = defcmplink;
  89.  
  90.     /* Make the query string */
  91.     sprintf(qstring,"ARCHIE/MATCH(%d,%d,%c)/%s",
  92.         max_hits,offset,query_type,string);
  93.  
  94.     /* Initialize Prospero structures */
  95.     perrno = PSUCCESS; *p_err_string = '\0';
  96.     pwarn = PNOWARN; *p_warn_string = '\0';
  97.     vdir_init(dir);
  98.     
  99.     /* Retrieve the list of matches, return error if there was one */
  100.     if(tmp = get_vdir(host,qstring,"",dir,GVD_ATTRIB|GVD_NOSORT,NULL,NULL)) {
  101.         perrno = tmp;
  102.         return(NULL);
  103.     }
  104.  
  105.     /* Save the links, and clear in dir in case it's used again   */
  106.     links = dir->links; dir->links = NULL;
  107.  
  108.     /* As returned, list is sorted by suffix, and conflicting     */
  109.     /* suffixes appear on a list of "replicas".  We want to       */
  110.     /* create a one-dimensional list sorted by host then filename */
  111.     /* and maybe by some other parameter                          */
  112.  
  113.     /* First flatten the doubly-linked list */
  114.     for (p = links; p != NULL; p = nextp) {
  115.         nextp = p->next;
  116.         if (p->replicas != NULL) {
  117.         p->next = p->replicas;
  118.         p->next->previous = p;
  119.         for (r = p->replicas; r->next != NULL; r = r->next)
  120.             /*EMPTY*/ ;
  121.         r->next = nextp;
  122.         nextp->previous = r;
  123.         p->replicas = NULL;
  124.         }
  125.     }
  126.  
  127.     /* Translate the filenames unless NOTRANS was given */
  128.     if (!(flags & AQ_NOTRANS))
  129.         for (p = links; p != NULL; p = p->next)
  130.         translateArchieResponse(p);
  131.  
  132.     /* If NOSORT given, then just hand it back */
  133.     if (flags & AQ_NOSORT) {
  134.         perrno = PSUCCESS;
  135.         return(links);
  136.     }
  137.  
  138.     /* Otherwise sort it using a selection sort and the given cmp_proc */
  139.     for (p = links; p != NULL; p = nextp) {
  140.         nextp = p->next;
  141.         lowest = p;
  142.         for (q = p->next; q != NULL; q = q->next)
  143.         if ((*cmp_proc)(q,lowest) < 0)
  144.             lowest = q;
  145.         if (p != lowest) {
  146.         /* swap the two links */
  147.         pnext = p->next;
  148.         pprev = p->previous;
  149.         if (lowest->next != NULL)
  150.             lowest->next->previous = p;
  151.         p->next = lowest->next;
  152.         if (nextp == lowest) {
  153.             p->previous = lowest;
  154.         } else {
  155.             lowest->previous->next = p;
  156.             p->previous = lowest->previous;
  157.         }
  158.         if (nextp == lowest) {
  159.             lowest->next = p;
  160.         } else {
  161.             pnext->previous = lowest;
  162.             lowest->next = pnext;
  163.         }
  164.         if (pprev != NULL)
  165.             pprev->next = lowest;
  166.         lowest->previous = pprev;
  167.         /* keep the head of the list in the right place */
  168.         if (links == p)
  169.             links = lowest;
  170.         }
  171.     }
  172.  
  173.     /* Return the links */
  174.     perrno = PSUCCESS;
  175.     return(links);
  176.     }
  177.  
  178. /*
  179.  * translateArchieResponse: 
  180.  *
  181.  *   If the given link is for an archie-pseudo directory, fix it. 
  182.  *   This is called unless AQ_NOTRANS was given to archie_query().
  183.  */
  184. static void
  185. translateArchieResponse(l)
  186.     VLINK l;
  187.     {
  188.     char *slash;
  189.  
  190.     if (strcmp(l->type,"DIRECTORY") == 0) {
  191.         if (strncmp(l->filename,"ARCHIE/HOST",11) == 0) {
  192.         l->type = stcopyr("EXTERNAL(AFTP,DIRECTORY)",l->type);
  193.         l->host = stcopyr(l->filename+12,l->host);
  194.         slash = (char *)index(l->host,'/');
  195.         if (slash) {
  196.             l->filename = stcopyr(slash,l->filename);
  197.             *slash++ = '\0';
  198.         } else
  199.             l->filename = stcopyr("",l->filename);
  200.         }
  201.     }
  202.     }
  203.  
  204. /*
  205.  * defcmplink: The default link comparison function for sorting. Compares
  206.  *           links p and q first by host then by filename. Returns < 0 if p
  207.  *             belongs before q, > 0 if p belongs after q, and == 0 if their
  208.  *             host and filename fields are identical.
  209.  */
  210. int
  211. defcmplink(p,q)
  212.     VLINK p,q;
  213.     {
  214.     int result;
  215.  
  216.     if ((result=strcmp(p->host,q->host)) != 0)
  217.         return(result);
  218.     else
  219.         return(strcmp(p->filename,q->filename));
  220.     }
  221.  
  222. /*
  223.  * invdatecmplink: An alternative comparison function for sorting that
  224.  *               compares links p and q first by LAST-MODIFIED date,
  225.  *                 if they both have that attribute. If both links
  226.  *                 don't have that attribute or the dates are the
  227.  *                 same, it then calls defcmplink() and returns its 
  228.  *           value.
  229.  */
  230. int
  231. invdatecmplink(p,q)
  232.     VLINK p,q;
  233.     {
  234.     PATTRIB pat,qat;
  235.     char *pdate,*qdate;
  236.     int result;
  237.     
  238.     pdate = qdate = NULL;
  239.     for (pat = p->lattrib; pat; pat = pat->next)
  240.         if(strcmp(pat->aname,"LAST-MODIFIED") == 0)
  241.         pdate = pat->value.ascii;
  242.     for (qat = q->lattrib; qat; qat = qat->next)
  243.         if(strcmp(qat->aname,"LAST-MODIFIED") == 0)
  244.         qdate = qat->value.ascii;
  245.     if(!pdate && !qdate) return(defcmplink(p,q));
  246.     if(!pdate) return(1); 
  247.     if(!qdate) return(-1);
  248.     if((result=strcmp(qdate,pdate)) == 0) return(defcmplink(p,q));
  249.     else return(result);
  250.     }
  251.