aquery.c
上传用户:sddyfurun
上传日期:2007-01-04
资源大小:525k
文件大小:10k
源码类别:

代理服务器

开发平台:

Unix_Linux

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