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