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