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