This is query.c in view mode; [Download] [Up]
/* * query.c : Programmatic Prospero interface to Archie * * Copyright (c) 1991 by the University of Washington * * For copying and distribution information, please see the file * <copyright.h>. * * Originally part of the Prospero Archie client by Clifford * Neuman (bcn@isi.edu). Modifications, addition of programmatic interface, * and new sorting code by George Ferguson (ferguson@cs.rochester.edu) * and Brendan Kehoe (brendan@cs.widener.edu). * * v2.0 - 11/29/92 (gf) - for xarchie 2.0 - and now we part company... * v1.3.2 - bpk - for Archie client 1.3.2 * v1.2.0 - 09/17/91 (bpk) - added BULL & USG stuff, thanks to Jim Sillas * v1.1.3 - 08/30/91 (bpk) - cast index() * v1.1.2 - 08/20/91 (bcn) - make it do it properly (new invdatecmplink) * v1.1.1 - 08/20/91 (bpk) - made sorting go inverted as we purport it does */ #include <copyright.h> #include <stdio.h> #include <pfs.h> #include <perrno.h> #include <pmachine.h> #include <archie.h> #include <libc.h> #include "query.h" #ifdef NEED_TIME_H # include <time.h> #else # ifndef VMS # include <sys/time.h> # endif #endif /* These are in dirsend.c */ extern int client_dirsrv_timeout, client_dirsrv_retry, rdgram_priority; /* Functions defined here: */ void queryAndParse(); VLINK archieQuery(), stringQuery(); int parseArchieQueryResults(), parseStringQueryResults(); void parseHostAndFilename(), parseAttributes(); int handleProsperoErrors(); /* Data defined here */ int pfs_debug; /* The fd for the read end of the pipe that NeXTArchie uses to signal that the user has aborted the select() system call. It is set by the QueryThreadProc() by calling SetThreadAbortFD(). */ int threadAbortFD; /* Functions to set the propsero/archie globals used by NeXTArchie */ void SetThreadAbortFD(int fd) { threadAbortFD = fd; } void SetServerRetries(int count) { client_dirsrv_retry = count; } void SetServerTimeout(int time) { client_dirsrv_timeout = time; } void SetNiceLevel(int nice) { rdgram_priority = nice; } #ifdef NO_NETWORK PATTRIB_ST attribs[] = { { 'C', "SIZE", "ASCII", "2048", 0x0, &attribs[1]}, { 'C', "UNIX-MODES", "ASCII", "drwxrwxr-x", &attribs[0], &attribs[2]}, { 'C', "LAST-MODIFIED", "ASCII", "19900808000000Z", &attribs[2], 0x0}, { 'C', "SIZE", "ASCII", "512", 0x0, &attribs[4]}, { 'C', "UNIX-MODES", "ASCII", "drwxrwxr-x", &attribs[3], &attribs[5]}, { 'C', "LAST-MODIFIED", "ASCII", "19900503000000Z", &attribs[5], 0x0} }; static VLINK_ST dummy[] = { {0, "XNeXT", 'L', 0, "DIRECTORY", 0x0, 0x0, "INTERNET-D", "NIC.SURA.NET", "ASCII", "ARCHIE/HOST/ascwide.ascii.co.jp/pub/NEXT/XNeXT", 0, 0, 0x0, 0, 0, 0x0, &attribs[0], 0x0, 0x0, &dummy[1]}, { 0, "XNeXT", 'L', 0, "DIRECTORY", 0x0, 0x0, "INTERNET-D", "NIC.SURA.NET", "ASCII", "ARCHIE/HOST/src.doc.ic.ac.uk/computing/graphics/systems/X11/contrib/XNeXT", 0, 0, 0x0, 0, 0, 0x0, &attribs[3], 0x0, &dummy[0], 0x0} }; #endif /* * archie_query : Sends a request to _host_, telling it to search for * _string_ using _query_type_ as the search method. * No more than _max_hits_ matches are to be returned * skipping over _offset_ matches. * * archie_query returns a linked list of virtual links. * * archie_query returns NULL and sets perrno if the query * failed. Note that it can return NULL with perrno == PSUCCESS * if the query didn't fail but there were simply no matches. * * query_type: S Substring search ignoring case * C Substring search with case significant * R Regular expression search * = Exact String Match * s,c,e Tries exact match first and falls back to S, C, or R * if not found. */ VLINK archieQuery(host,string,max_hits,offset,query_type,cmp_proc,flags, msg) char *host,*string; int max_hits,offset; char query_type; int (*cmp_proc)(); int flags; StatusMsgPtr msg; { char qstring[MAX_VPATH]; VLINK links; VLINK SortList(VLINK links, int (*cmp_proc)()); status0("Sending query..."); #ifdef NO_NETWORK links = &dummy[0]; done("Query complete"); #else sprintf(qstring,"ARCHIE/MATCH(%d,%d,%c)/%s", max_hits,offset,query_type,string); links = stringQuery(host, qstring, msg); if( perrno != PSUCCESS ) return links; /* If NOSORT given, then just hand it back */ if ( flags & AQ_NOSORT || cmp_proc == NULL ) return links; /* Otherwise sort it using a selection sort and the given cmp_proc */ links = SortList(links, cmp_proc); #endif /* Return the links */ perrno = PSUCCESS; return links; } /* * Returns an unsorted, untranslated list of vlinks for string from host */ VLINK stringQuery(host, string, msg) char *host,*string; StatusMsgPtr msg; { VLINK links; /* Matches returned by server */ VDIR_ST dir_st; /* Filled in by get_vdir */ PVDIR dir = &dir_st; VLINK p,nextp,r; int tmp; /* initialize Prospero globals from appResources */ pfs_debug = DEBUG_LEVEL; if( client_dirsrv_timeout == 0 ) { /* Set default values */ rdgram_priority = NICE_LEVEL; client_dirsrv_timeout = TIMEOUT; client_dirsrv_retry = RETRIES; } /* Initialize Prospero structures */ perrno = PSUCCESS; *p_err_string = '\0'; pwarn = PNOWARN; *p_warn_string = '\0'; vdir_init(dir); #ifdef DEBUG fprintf(stderr, "p<%d>,timeout<%d>,retry<%d>\n", rdgram_priority, client_dirsrv_timeout, client_dirsrv_retry); fprintf(stderr, "stringQuery(%s, %s)\n", host, string); #endif /* Retrieve the list of matches, return error if there was one */ #if defined(MSDOS) if (tmp=get_vdir(host,string,"",dir,(long)GVD_ATTRIB|GVD_NOSORT, NULL, NULL)) { #else if (tmp=get_vdir(host,string,"",dir,GVD_ATTRIB|GVD_NOSORT,NULL,NULL, msg)) { # endif perrno = tmp; done("Query failed"); return 0; } /* Save the links, and clear in dir in case it's used again */ links = dir->links; dir->links = NULL; /* As returned, list is sorted by suffix, and conflicting */ /* suffixes appear on a list of "replicas". We want to */ /* create a one-dimensional list sorted by host then filename */ /* and maybe by some other parameter */ /* First flatten the doubly-linked list */ for (p = links; p != NULL; p = nextp) { nextp = p->next; if (p->replicas != NULL) { p->next = p->replicas; p->next->previous = p; for (r = p->replicas; r->next != NULL; r = r->next) /*EMPTY*/ ; r->next = nextp; nextp->previous = r; p->replicas = NULL; } } perrno = PSUCCESS; done("Query complete"); return links; } /* * Here take the list of untranslated unsorted links and put them into the * database, translating and sorting as needed. The entries are added to * make a host-location-file hierarchy as appropriate for the top of the * database query for a query. Returns number of entries returned from query. */ int parseArchieQueryResults(links,cmp_proc) VLINK links; int (*cmp_proc)(); { VLINK vl; char hostname[MAX_VPATH],location[MAX_VPATH],filename[MAX_VPATH]; int type; #ifdef MSDOS unsigned long size; #else int size; #endif char *modes,*gt_date,*archie_date; int num; #ifdef DEBUG printf("parsing links...\n"); #endif num = 0; for (vl=links; vl != NULL; vl = vl->next) { parseHostAndFilename(vl,hostname,location,filename); parseAttributes(vl,&type,&size,&modes,&archie_date,>_date); num += 1; } #ifdef DEBUG printf(" sorting entries...\n"); #endif #ifdef DEBUG printf("parse done -- returning %d matches\n",num); #endif return(num); } /* * Like parseArchieQueryresults(), but all the entries for the links are * added as immediate children of parent, rather than a three-level tree. * */ int parseStringQueryResults(links,cmp_proc) VLINK links; int (*cmp_proc)(); { VLINK vl; char hostname[MAX_VPATH],location[MAX_VPATH],filename[MAX_VPATH]; int type,size; char *modes,*gt_date,*archie_date; int num; #ifdef DEBUG printf("parsing links...\n"); #endif num = 0; for (vl=links; vl != NULL; vl = vl->next) { parseHostAndFilename(vl,hostname,location,filename); parseAttributes(vl,&type,&size,&modes,&archie_date,>_date); num += 1; } #ifdef DEBUG printf(" sorting entries...\n"); #endif #ifdef DEBUG printf("parse done -- returning %d matches\n",num); #endif return(num); } /* * Fills in hostname, location, and filename with the appropriately-translated * and adjusted information from the link vl. */ void parseHostAndFilename(vl,hostname,location,filename) VLINK vl; char *hostname,*location,*filename; { char *slash; #ifdef DEBUG1 printf(" input: host=\"%s\"\n filename=\"%s\"\n name=\"%s\"\n",vl->host,vl->filename,vl->name); #endif /* If the link is for an Archie pseudo-directory, adjust names. */ if (strcmp(vl->type,"DIRECTORY") == 0 && strncmp(vl->filename,"ARCHIE/HOST",11) == 0) { strcpy(hostname,vl->filename+12); slash = index(hostname,'/'); if (slash != NULL) { strcpy(filename,slash); *slash = '\0'; } else strcpy(filename,"/"); } else { /* else just use the names as is */ strcpy(hostname,vl->host); strcpy(filename,vl->filename); } /* The "location" is the leading part of the pathname */ strcpy(location,filename); slash = rindex(location,'/'); /* If filename ends with slash, try going back one more slash */ if (slash && *(slash+1) == '\0') slash = (char *)rindex(slash,'/'); if (slash) { strcpy(filename,slash+1); *slash = '\0'; } else strcpy(location,"/"); /* If filename was /foo, then we need to leave the slash there */ if (*location == '\0') strcpy(location,"/"); #ifdef DEBUG1 printf(" output: host=\"%s\"\n location=\"%s\"\n filename=\"%s\"\n", hostname,location,filename); #endif } /* * Fills in *sizep, *modesp, and archie_date with the information in the * attribute list of the link vl. */ void parseAttributes(vl,typep,sizep,modesp,archie_datep,gt_datep) VLINK vl; int *typep; #ifdef MSDOS unsigned long *sizep; #else int *sizep; #endif char **modesp,**archie_datep,**gt_datep; { static char date[64]; PATTRIB ap; int gt_year,gt_mon,gt_day,gt_hour,gt_min; struct tm *presenttime; long now; (void)time(&now); presenttime = localtime(&now); if (strcmp(vl->type,"DIRECTORY") == 0) { *typep = DIRECTORY_t; } else { *typep = FILE_t; } *sizep = 0; *modesp = ""; *archie_datep = ""; *gt_datep = ""; gt_year = gt_mon = gt_day = gt_hour = gt_min = 0; for (ap = vl->lattrib; ap; ap = ap->next) { if (strcmp(ap->aname,"SIZE") == 0) { #ifdef MSDOS sscanf(ap->value.ascii,"%lu",sizep); #else sscanf(ap->value.ascii,"%d",sizep); #endif } else if(strcmp(ap->aname,"UNIX-MODES") == 0) { *modesp = ap->value.ascii; } else if(strcmp(ap->aname,"LAST-MODIFIED") == 0) { *gt_datep = ap->value.ascii; sscanf(*gt_datep,"%4d%2d%2d%2d%2d",>_year, >_mon, >_day, >_hour, >_min); if ((12 * (presenttime->tm_year + 1900 - gt_year) + presenttime->tm_mon - gt_mon) > 6) sprintf(date,"%s %2d %4d",month_sname(gt_mon), gt_day, gt_year); else sprintf(date,"%s %2d %02d:%02d",month_sname(gt_mon), gt_day, gt_hour, gt_min); *archie_datep = date; } } } int handleProsperoErrors() {return 0;} /* * Pops up alerts depending on perrno and pwarn. int handleProsperoErrors() { int err = 0; if (perrno != PSUCCESS) { if (p_err_text[perrno]) { if (*p_err_string) alert2("Prospero error: %.100s - %.100s",p_err_text[perrno], p_err_string); else alert1("Prospero error: %.200s",p_err_text[perrno]); } else alert1("Prospero error: Undefined error %d (prospero)",(char*)perrno); err = 1; } if (pwarn != PNOWARN) { if (*p_warn_string) alert2("Prospero warning: %.100s - %.100s", p_warn_text[pwarn], p_warn_string); else alert1("Prospero warning: %.200s",p_warn_text[pwarn]); status0("Ready"); } return(err); } */ VLINK SortList(VLINK links, int (*cmp_proc)(VLINK, VLINK)) { VLINK p, q, lowest, nextp, pnext, pprev; for (p = links; p != NULL; p = nextp) { nextp = p->next; lowest = p; for (q = p->next; q != NULL; q = q->next) if ((*cmp_proc)(q,lowest) < 0) lowest = q; if (p != lowest) { /* swap the two links */ pnext = p->next; pprev = p->previous; if (lowest->next != NULL) lowest->next->previous = p; p->next = lowest->next; if (nextp == lowest) { p->previous = lowest; } else { lowest->previous->next = p; p->previous = lowest->previous; } if (nextp == lowest) { lowest->next = p; } else { pnext->previous = lowest; lowest->next = pnext; } if (pprev != NULL) pprev->next = lowest; lowest->previous = pprev; /* keep the head of the list in the right place */ if (links == p) links = lowest; } } return links; } /* * defcmplink: The default link comparison function for sorting. Compares * links p and q first by host then by filename. Returns < 0 if p * belongs before q, > 0 if p belongs after q, and == 0 if their * host and filename fields are identical. */ int defcmplink(p,q) VLINK p,q; { int result; if ((result=strcmp(p->host,q->host)) != 0) return(result); else return(strcmp(p->filename,q->filename)); } /* * invdatecmplink: An alternative comparison function for sorting that * compares links p and q first by LAST-MODIFIED date, * if they both have that attribute. If both links * don't have that attribute or the dates are the * same, it then calls defcmplink() and returns its * value. */ int invdatecmplink(p,q) VLINK p,q; { PATTRIB pat,qat; char *pdate,*qdate; int result; pdate = qdate = NULL; for (pat = p->lattrib; pat; pat = pat->next) if(strcmp(pat->aname,"LAST-MODIFIED") == 0) pdate = pat->value.ascii; for (qat = q->lattrib; qat; qat = qat->next) if(strcmp(qat->aname,"LAST-MODIFIED") == 0) qdate = qat->value.ascii; if(!pdate && !qdate) return(defcmplink(p,q)); if(!pdate) return(1); if(!qdate) return(-1); if((result=strcmp(qdate,pdate)) == 0) return(defcmplink(p,q)); else return(result); } /* RCS Information: $Author: me $; $Date: 92/10/30 22:16:52 $; $Source: /usr1/me/NeXTSrc/Archie/RCS/aquery.c,v $; $Revision: 1.5 $; */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.