Annotation of libwww/Library/src/HTAccess.c, revision 1.20
1.1 timbl 1: /* Access Manager HTAccess.c
2: ** ==============
3: **
4: ** Authors
5: ** TBL Tim Berners-Lee timbl@info.cern.ch
1.4 timbl 6: ** JFG Jean-Francois Groff jfg@dxcern.cern.ch
1.1 timbl 7: ** DD Denis DeLaRoca (310) 825-4580 <CSP1DWD@mvs.oac.ucla.edu>
8: ** History
9: ** 8 Jun 92 Telnet hopping prohibited as telnet is not secure TBL
10: ** 26 Jun 92 When over DECnet, suppressed FTP, Gopher and News. JFG
11: ** 6 Oct 92 Moved HTClientHost and logfile into here. TBL
12: ** 17 Dec 92 Tn3270 added, bug fix. DD
1.2 timbl 13: ** 4 Feb 93 Access registration, Search escapes bad chars TBL
1.9 timbl 14: ** PARAMETERS TO HTSEARCH AND HTLOADRELATIVE CHANGED
15: ** 28 May 93 WAIS gateway explicit if no WAIS library linked in.
1.19 timbl 16: ** Dec 93 Bug change around, more reentrant, etc
1.2 timbl 17: ** Bugs
18: ** This module assumes that that the graphic object is hypertext, as it
1.9 timbl 19: ** needs to select it when it has been loaded. A superclass needs to be
1.2 timbl 20: ** defined which accepts select and select_anchor.
1.1 timbl 21: */
22:
1.9 timbl 23: #ifndef DEFAULT_WAIS_GATEWAY
1.8 timbl 24: #define DEFAULT_WAIS_GATEWAY "http://info.cern.ch:8001/"
1.9 timbl 25: #endif
1.8 timbl 26:
1.1 timbl 27: /* Implements:
28: */
29: #include "HTAccess.h"
30:
31: /* Uses:
32: */
33:
34: #include "HTParse.h"
35: #include "HTUtils.h"
1.4 timbl 36: #include "HTML.h" /* SCW */
1.2 timbl 37:
38: #ifndef NO_RULES
39: #include "HTRules.h"
40: #endif
41:
1.1 timbl 42: #include <stdio.h>
43:
1.2 timbl 44: #include "HTList.h"
45: #include "HText.h" /* See bugs above */
46: #include "HTAlert.h"
1.17 timbl 47: #include "HTFWriter.h" /* for cache stuff */
48: #include "HTTee.h"
1.2 timbl 49:
1.1 timbl 50: /* These flags may be set to modify the operation of this module
51: */
52: PUBLIC char * HTClientHost = 0; /* Name of remote login host if any */
53: PUBLIC FILE * logfile = 0; /* File to which to output one-liners */
1.12 timbl 54: PUBLIC BOOL HTSecure = NO; /* Disable access for telnet users? */
1.1 timbl 55:
1.2 timbl 56: /* To generate other things, play with these:
57: */
58:
1.15 timbl 59: /* PUBLIC HTFormat HTOutputFormat = NULL; use request->output_format */
60: /* PUBLIC HTStream* HTOutputStream = NULL; use request->output_stream */
1.1 timbl 61:
62: PRIVATE HTList * protocols = NULL; /* List of registered protocol descriptors */
63:
64:
1.15 timbl 65: /* Create a request structure
66: ** ---------------------------
67: */
68:
69: PUBLIC HTRequest * HTRequest_new NOARGS
70: {
71: HTRequest * me = (HTRequest*) calloc(sizeof(*me), 1); /* zero fill */
72: if (!me) outofmem(__FILE__, "HTRequest_new()");
73:
1.20 ! luotonen 74: me->conversions = HTList_new(); /* No conversions registerd yet */
! 75: me->output_format = WWW_PRESENT; /* default it to present to user */
! 76: me->scheme = HTAA_NONE;
! 77:
1.15 timbl 78: return me;
79: }
80:
81:
1.20 ! luotonen 82: /* Delete a request structure
! 83: ** --------------------------
! 84: */
! 85: PUBLIC void HTRequest_delete ARGS1(HTRequest *, req)
! 86: {
! 87: if (req) {
! 88: HTList *cur = req->conversions;
! 89: HTPresentation *pres;
! 90:
! 91: while ((pres = (HTPresentation*)HTList_nextObject(cur)))
! 92: free(pres);
! 93:
! 94: free(req);
! 95: }
! 96: }
! 97:
! 98:
! 99:
1.1 timbl 100: /* Register a Protocol HTRegisterProtocol
101: ** -------------------
102: */
103:
104: PUBLIC BOOL HTRegisterProtocol(protocol)
105: HTProtocol * protocol;
106: {
107: if (!protocols) protocols = HTList_new();
108: HTList_addObject(protocols, protocol);
109: return YES;
110: }
111:
112:
113: /* Register all known protocols
114: ** ----------------------------
115: **
116: ** Add to or subtract from this list if you add or remove protocol modules.
117: ** This routine is called the first time the protocol list is needed,
118: ** unless any protocols are already registered, in which case it is not called.
119: ** Therefore the application can override this list.
120: **
121: ** Compiling with NO_INIT prevents all known protocols from being forced
122: ** in at link time.
123: */
124: #ifndef NO_INIT
125: PRIVATE void HTAccessInit NOARGS /* Call me once */
126: {
1.14 duns 127: GLOBALREF HTProtocol HTTP, HTFile, HTTelnet, HTTn3270, HTRlogin;
1.1 timbl 128: #ifndef DECNET
1.14 duns 129: GLOBALREF HTProtocol HTFTP, HTNews, HTGopher;
1.3 timbl 130: #ifdef DIRECT_WAIS
1.14 duns 131: GLOBALREF HTProtocol HTWAIS;
1.3 timbl 132: #endif
1.2 timbl 133: HTRegisterProtocol(&HTFTP);
134: HTRegisterProtocol(&HTNews);
135: HTRegisterProtocol(&HTGopher);
1.3 timbl 136: #ifdef DIRECT_WAIS
137: HTRegisterProtocol(&HTWAIS);
138: #endif
1.1 timbl 139: #endif
140:
1.2 timbl 141: HTRegisterProtocol(&HTTP);
142: HTRegisterProtocol(&HTFile);
143: HTRegisterProtocol(&HTTelnet);
144: HTRegisterProtocol(&HTTn3270);
145: HTRegisterProtocol(&HTRlogin);
1.1 timbl 146: }
147: #endif
148:
149:
1.2 timbl 150: /* Find physical name and access protocol
151: ** --------------------------------------
1.1 timbl 152: **
153: **
154: ** On entry,
155: ** addr must point to the fully qualified hypertext reference.
156: ** anchor a pareent anchor with whose address is addr
157: **
158: ** On exit,
1.2 timbl 159: ** returns HT_NO_ACCESS Error has occured.
160: ** HT_OK Success
1.1 timbl 161: **
162: */
1.19 timbl 163: PRIVATE int get_physical ARGS1(HTParentAnchor *, anchor)
1.1 timbl 164: {
165: char * access=0; /* Name of access method */
1.2 timbl 166: char * physical = 0;
1.19 timbl 167: char * addr = HTAnchor_address((HTAnchor*)anchor); /* free me */
1.1 timbl 168:
1.2 timbl 169: #ifndef NO_RULES
170: physical = HTTranslate(addr);
171: if (!physical) {
1.19 timbl 172: free(addr);
1.2 timbl 173: return HT_FORBIDDEN;
174: }
175: HTAnchor_setPhysical(anchor, physical);
176: free(physical); /* free our copy */
177: #else
178: HTAnchor_setPhysical(anchor, addr);
179: #endif
180:
181: access = HTParse(HTAnchor_physical(anchor),
182: "file:", PARSE_ACCESS);
1.1 timbl 183:
184: /* Check whether gateway access has been set up for this
1.8 timbl 185: **
186: ** This function can be replaced by the rule system above.
1.1 timbl 187: */
1.8 timbl 188: #define USE_GATEWAYS
1.1 timbl 189: #ifdef USE_GATEWAYS
1.2 timbl 190: {
1.9 timbl 191: char * gateway_parameter, *gateway;
1.2 timbl 192: gateway_parameter = (char *)malloc(strlen(access)+20);
193: if (gateway_parameter == NULL) outofmem(__FILE__, "HTLoad");
194: strcpy(gateway_parameter, "WWW_");
195: strcat(gateway_parameter, access);
196: strcat(gateway_parameter, "_GATEWAY");
197: gateway = (char *)getenv(gateway_parameter); /* coerce for decstation */
198: free(gateway_parameter);
1.8 timbl 199:
200: #ifndef DIRECT_WAIS
1.9 timbl 201: if (!gateway && 0==strcmp(access, "wais")) {
1.8 timbl 202: gateway = DEFAULT_WAIS_GATEWAY;
203: }
204: #endif
1.2 timbl 205: if (gateway) {
1.9 timbl 206: char * path = HTParse(addr, "",
207: PARSE_HOST + PARSE_PATH + PARSE_PUNCTUATION);
208: /* Chop leading / off to make host into part of path */
209: char * gatewayed = HTParse(path+1, gateway, PARSE_ALL);
210: free(path);
1.8 timbl 211: HTAnchor_setPhysical(anchor, gatewayed);
1.9 timbl 212: free(gatewayed);
1.2 timbl 213: free(access);
1.9 timbl 214:
1.8 timbl 215: access = HTParse(HTAnchor_physical(anchor),
216: "http:", PARSE_ACCESS);
1.2 timbl 217: }
218: }
1.1 timbl 219: #endif
220:
1.19 timbl 221: free(addr);
1.1 timbl 222:
223:
224: /* Search registered protocols to find suitable one
225: */
226: {
1.20 ! luotonen 227: HTList *cur;
! 228: HTProtocol *p;
1.1 timbl 229: #ifndef NO_INIT
1.2 timbl 230: if (!protocols) HTAccessInit();
1.1 timbl 231: #endif
1.20 ! luotonen 232: cur = protocols;
! 233: while ((p = (HTProtocol*)HTList_nextObject(cur))) {
1.2 timbl 234: if (strcmp(p->name, access)==0) {
235: HTAnchor_setProtocol(anchor, p);
236: free(access);
237: return (HT_OK);
1.1 timbl 238: }
239: }
240: }
241:
242: free(access);
1.2 timbl 243: return HT_NO_ACCESS;
1.1 timbl 244: }
245:
246:
247: /* Load a document
248: ** ---------------
249: **
1.2 timbl 250: ** This is an internal routine, which has an address AND a matching
251: ** anchor. (The public routines are called with one OR the other.)
252: **
253: ** On entry,
254: ** addr must point to the fully qualified hypertext reference.
1.15 timbl 255: ** request->
256: ** anchor a parent anchor with whose address is addr
257: ** output_format valid
258: ** output_stream valid on NULL
1.2 timbl 259: **
260: ** On exit,
261: ** returns <0 Error has occured.
262: ** HT_LOADED Success
263: ** HT_NO_DATA Success, but no document loaded.
1.8 timbl 264: ** (telnet sesssion started etc)
1.2 timbl 265: **
266: */
1.15 timbl 267: PRIVATE int HTLoad ARGS2(
1.19 timbl 268: CONST char *, addr, /* not used */
1.15 timbl 269: HTRequest *, request)
1.2 timbl 270: {
271: HTProtocol* p;
1.19 timbl 272: int status;
273: request->method = HTAtom_for("GET");
274: status = get_physical(request->anchor);
1.2 timbl 275: if (status == HT_FORBIDDEN) {
1.15 timbl 276: return HTLoadError(request->output_stream, 500,
277: "Access forbidden by rule");
1.2 timbl 278: }
279: if (status < 0) return status; /* Can't resolve or forbidden */
280:
1.15 timbl 281: p = HTAnchor_protocol(request->anchor);
1.17 timbl 282: return (*(p->load))(request);
1.2 timbl 283: }
284:
285:
286: /* Get a save stream for a document
287: ** --------------------------------
288: */
1.19 timbl 289: PUBLIC HTStream *HTSaveStream ARGS1(HTRequest *, request)
1.15 timbl 290: {
291: HTProtocol * p;
1.19 timbl 292: int status;
293: request->method = HTAtom_for("PUT");
294: status = get_physical(request->anchor);
295: if (status == HT_FORBIDDEN) {
296: HTLoadError(request->output_stream, 500,
297: "Access forbidden by rule");
298: return NULL; /* should return error status? */
299: }
300: if (status < 0) return NULL; /* @@ error. Can't resolve or forbidden */
301:
1.15 timbl 302: p = HTAnchor_protocol(request->anchor);
1.2 timbl 303: if (!p) return NULL;
304:
1.15 timbl 305: return (*p->saveStream)(request);
1.2 timbl 306:
307: }
308:
309:
310: /* Load a document - with logging etc
311: ** ----------------------------------
312: **
313: ** - Checks or documents already loaded
314: ** - Logs the access
315: ** - Allows stdin filter option
316: ** - Trace ouput and error messages
317: **
1.1 timbl 318: ** On Entry,
1.19 timbl 319: ** request->anchor valid for of the document to be accessed.
320: ** request->childAnchor optional anchor within doc to be selected
321: **
1.2 timbl 322: ** filter if YES, treat stdin as HTML
1.1 timbl 323: **
1.15 timbl 324: ** request->anchor is the node_anchor for the document
325: ** request->output_format is valid
326: **
1.1 timbl 327: ** On Exit,
328: ** returns YES Success in opening document
329: ** NO Failure
330: **
331: */
332:
1.19 timbl 333: PRIVATE BOOL HTLoadDocument ARGS1(HTRequest *, request)
1.1 timbl 334:
335: {
336: int status;
337: HText * text;
1.19 timbl 338: char * full_address = HTAnchor_address((HTAnchor*)request->anchor);
339:
1.1 timbl 340: if (TRACE) fprintf (stderr,
341: "HTAccess: loading document %s\n", full_address);
342:
1.18 timbl 343: request->using_cache = NULL;
344:
1.15 timbl 345: if (!request->output_format) request->output_format = WWW_PRESENT;
346:
1.20 ! luotonen 347: if ((text=(HText *)HTAnchor_document(request->anchor)))
1.15 timbl 348: { /* Already loaded */
1.1 timbl 349: if (TRACE) fprintf(stderr, "HTAccess: Document already in memory.\n");
1.19 timbl 350: if (request->childAnchor) {
351: HText_selectAnchor(text, request->childAnchor);
352: } else {
353: HText_select(text);
354: }
355: free(full_address);
1.1 timbl 356: return YES;
357: }
1.17 timbl 358:
359: /* Check the Cache
360: */
361: /* Bug: for each format, we only check whether it is ok, we
362: don't check them all and chose the best */
363: if (request->anchor->cacheItems) {
364: HTList * list = request->anchor->cacheItems;
1.20 ! luotonen 365: HTList * cur = list;
! 366: HTCacheItem * item;
! 367:
! 368: while ((item = (HTCacheItem*)HTList_nextObject(cur))) {
1.18 timbl 369: HTStream * s;
370:
371: request->using_cache = item;
372:
373: s = HTStreamStack(item->format, request);
1.17 timbl 374: if (s) { /* format was suitable */
375: FILE * fp = fopen(item->filename, "r");
1.18 timbl 376: if (TRACE) fprintf(stderr, "Cache: HIT file %s for %s\n",
1.20 ! luotonen 377: item->filename,
! 378: full_address);
1.17 timbl 379: if (fp) {
380: HTFileCopy(fp, s);
381: fclose(fp);
1.19 timbl 382: free(full_address);
1.17 timbl 383: return YES;
384: } else {
385: fprintf(stderr, "***** Can't read cache file %s !\n",
1.20 ! luotonen 386: item->filename);
1.17 timbl 387: } /* file open ok */
388: } /* stream ok */
389: } /* next cache item */
390: } /* if cache available for this anchor */
1.1 timbl 391:
1.15 timbl 392: status = HTLoad(full_address, request);
1.2 timbl 393:
394:
1.1 timbl 395: /* Log the access if necessary
396: */
397: if (logfile) {
398: time_t theTime;
399: time(&theTime);
400: fprintf(logfile, "%24.24s %s %s %s\n",
401: ctime(&theTime),
402: HTClientHost ? HTClientHost : "local",
403: status<0 ? "FAIL" : "GET",
404: full_address);
405: fflush(logfile); /* Actually update it on disk */
406: if (TRACE) fprintf(stderr, "Log: %24.24s %s %s %s\n",
407: ctime(&theTime),
408: HTClientHost ? HTClientHost : "local",
409: status<0 ? "FAIL" : "GET",
410: full_address);
411: }
412:
413:
414: if (status == HT_LOADED) {
415: if (TRACE) {
416: fprintf(stderr, "HTAccess: `%s' has been accessed.\n",
417: full_address);
418: }
1.19 timbl 419: free(full_address);
1.1 timbl 420: return YES;
421: }
422:
423: if (status == HT_NO_DATA) {
424: if (TRACE) {
425: fprintf(stderr,
426: "HTAccess: `%s' has been accessed, No data left.\n",
427: full_address);
428: }
1.19 timbl 429: free(full_address);
1.1 timbl 430: return NO;
431: }
432:
1.2 timbl 433: if (status<0) { /* Failure in accessing a document */
1.1 timbl 434: #ifdef CURSES
435: user_message("Can't access `%s'", full_address);
436: #else
1.5 timbl 437: if (TRACE) fprintf(stderr,
438: "HTAccess: Can't access `%s'\n", full_address);
1.1 timbl 439: #endif
1.15 timbl 440: HTLoadError(request->output_stream, 500, "Unable to access document.");
1.19 timbl 441: free(full_address);
1.1 timbl 442: return NO;
443: }
1.9 timbl 444:
445: /* If you get this, then please find which routine is returning
446: a positive unrecognised error code! */
447:
1.1 timbl 448: fprintf(stderr,
1.2 timbl 449: "**** HTAccess: socket or file number returned by obsolete load routine!\n");
1.9 timbl 450: fprintf(stderr,
1.19 timbl 451: "**** HTAccess: Internal software error. Please mail www-bug@info.cern.ch quoting the version number of this software and the URL: %s!\n",
452: full_address);
453: free(full_address);
454:
1.1 timbl 455: exit(-6996);
1.20 ! luotonen 456: return NO; /* For gcc :-( */
1.2 timbl 457: } /* HTLoadDocument */
1.1 timbl 458:
459:
460:
461: /* Load a document from absolute name
462: ** ---------------
463: **
464: ** On Entry,
465: ** addr The absolute address of the document to be accessed.
466: ** filter if YES, treat document as HTML
467: **
468: ** On Exit,
469: ** returns YES Success in opening document
470: ** NO Failure
471: **
472: **
473: */
474:
1.15 timbl 475: PUBLIC BOOL HTLoadAbsolute ARGS2(CONST char *,addr, HTRequest*, request)
1.2 timbl 476: {
1.19 timbl 477: HTAnchor * anchor = HTAnchor_findAddress(addr);
478: request->anchor = HTAnchor_parent(anchor);
479: request->childAnchor = ((HTAnchor*)request->anchor == anchor) ?
480: NULL : (HTChildAnchor*) anchor;
481: return HTLoadDocument(request);
1.2 timbl 482: }
483:
484:
485: /* Load a document from absolute name to stream
486: ** --------------------------------------------
487: **
488: ** On Entry,
489: ** addr The absolute address of the document to be accessed.
1.15 timbl 490: ** request->output_stream if non-NULL, send data down this stream
1.2 timbl 491: **
492: ** On Exit,
493: ** returns YES Success in opening document
494: ** NO Failure
495: **
496: **
497: */
498:
499: PUBLIC BOOL HTLoadToStream ARGS3(
500: CONST char *, addr,
501: BOOL, filter,
1.15 timbl 502: HTRequest*, request)
1.1 timbl 503: {
1.19 timbl 504: HTAnchor * anchor = HTAnchor_findAddress(addr);
505: request->anchor = HTAnchor_parent(anchor);
506: request->childAnchor = ((HTAnchor*)request->anchor == anchor) ? NULL :
507: (HTChildAnchor*) anchor;
1.15 timbl 508: request->output_stream = request->output_stream;
1.19 timbl 509: return HTLoadDocument(request);
1.1 timbl 510: }
511:
512:
1.2 timbl 513:
514:
1.1 timbl 515: /* Load a document from relative name
516: ** ---------------
517: **
518: ** On Entry,
1.2 timbl 519: ** relative_name The relative address of the document
520: ** to be accessed.
1.1 timbl 521: **
522: ** On Exit,
523: ** returns YES Success in opening document
524: ** NO Failure
525: **
526: **
527: */
528:
1.15 timbl 529: PUBLIC BOOL HTLoadRelative ARGS3(
1.2 timbl 530: CONST char *, relative_name,
1.15 timbl 531: HTParentAnchor *, here,
1.20 ! luotonen 532: HTRequest *, request)
1.1 timbl 533: {
534: char * full_address = 0;
535: BOOL result;
536: char * mycopy = 0;
537: char * stripped = 0;
538: char * current_address =
1.2 timbl 539: HTAnchor_address((HTAnchor*)here);
1.1 timbl 540:
541: StrAllocCopy(mycopy, relative_name);
542:
543: stripped = HTStrip(mycopy);
544: full_address = HTParse(stripped,
545: current_address,
546: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1.15 timbl 547: result = HTLoadAbsolute(full_address, request);
1.1 timbl 548: free(full_address);
549: free(current_address);
550: free(mycopy); /* Memory leak fixed 10/7/92 -- JFG */
551: return result;
552: }
553:
554:
555: /* Load if necessary, and select an anchor
556: ** --------------------------------------
557: **
558: ** On Entry,
559: ** destination The child or parenet anchor to be loaded.
560: **
561: ** On Exit,
562: ** returns YES Success
563: ** NO Failure
564: **
565: */
566:
1.15 timbl 567: PUBLIC BOOL HTLoadAnchor ARGS2(HTAnchor*, anchor, HTRequest *, request)
1.1 timbl 568: {
1.15 timbl 569: if (!anchor) return NO; /* No link */
1.1 timbl 570:
1.15 timbl 571: request->anchor = HTAnchor_parent(anchor);
1.19 timbl 572: request->childAnchor = ((HTAnchor*)request->anchor == anchor) ? NULL
573: : (HTChildAnchor*) anchor;
1.1 timbl 574:
1.19 timbl 575: return HTLoadDocument(request) ? YES : NO;
1.1 timbl 576:
577: } /* HTLoadAnchor */
578:
579:
580: /* Search
581: ** ------
582: ** Performs a keyword search on word given by the user. Adds the keyword to
583: ** the end of the current address and attempts to open the new address.
584: **
585: ** On Entry,
586: ** *keywords space-separated keyword list or similar search list
1.2 timbl 587: ** here is anchor search is to be done on.
1.1 timbl 588: */
589:
1.2 timbl 590: PRIVATE char hex(i)
591: int i;
592: {
1.13 timbl 593: char * hexchars = "0123456789ABCDEF";
594: return hexchars[i];
1.2 timbl 595: }
1.1 timbl 596:
1.15 timbl 597: PUBLIC BOOL HTSearch ARGS3(
1.2 timbl 598: CONST char *, keywords,
1.15 timbl 599: HTParentAnchor *, here,
600: HTRequest *, request)
1.1 timbl 601: {
1.2 timbl 602:
603: #define acceptable \
604: "1234567890abcdefghijlkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_"
605:
606: char *q, *u;
607: CONST char * p, *s, *e; /* Pointers into keywords */
608: char * address = HTAnchor_address((HTAnchor*)here);
1.1 timbl 609: BOOL result;
1.2 timbl 610: char * escaped = malloc(strlen(keywords)*3+1);
611:
612: static CONST BOOL isAcceptable[96] =
613:
614: /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
615: { 0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,0, /* 2x !"#$%&'()*+,-./ */
616: 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */
617: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4x @ABCDEFGHIJKLMNO */
618: 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1, /* 5X PQRSTUVWXYZ[\]^_ */
619: 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6x `abcdefghijklmno */
620: 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0 }; /* 7X pqrstuvwxyz{\}~ DEL */
621:
622: if (escaped == NULL) outofmem(__FILE__, "HTSearch");
623:
624:
625: /* Convert spaces to + and hex escape unacceptable characters
626: */
627: for(s=keywords; *s && WHITE(*s); s++) /*scan */ ; /* Skip white space */
628: for(e = s + strlen(s); e>s && WHITE(*(e-1)) ; e--); /* Skip trailers */
629: for(q=escaped, p=s; p<e; p++) { /* scan stripped field */
630: int c = (int)TOASCII(*p);
631: if (WHITE(*p)) {
632: *q++ = '+';
633: } else if (c>=32 && c<=(char)127 && isAcceptable[c-32]) {
1.13 timbl 634: *q++ = *p; /* 930706 TBL for MVS bug */
1.2 timbl 635: } else {
636: *q++ = '%';
637: *q++ = hex(c / 16);
638: *q++ = hex(c % 16);
639: }
640: } /* Loop over string */
1.1 timbl 641:
1.2 timbl 642: *q=0;
643: /* terminate escaped sctring */
644: u=strchr(address, '?'); /* Find old search string */
645: if (u) *u = 0; /* Chop old search off */
1.1 timbl 646:
647: StrAllocCat(address, "?");
1.2 timbl 648: StrAllocCat(address, escaped);
649: free(escaped);
1.15 timbl 650: result = HTLoadRelative(address, here, request);
1.1 timbl 651: free(address);
1.2 timbl 652:
1.1 timbl 653: return result;
1.2 timbl 654: }
655:
656:
657: /* Search Given Indexname
658: ** ------
659: ** Performs a keyword search on word given by the user. Adds the keyword to
660: ** the end of the current address and attempts to open the new address.
661: **
662: ** On Entry,
663: ** *keywords space-separated keyword list or similar search list
664: ** *addres is name of object search is to be done on.
665: */
666:
1.15 timbl 667: PUBLIC BOOL HTSearchAbsolute ARGS3(
1.2 timbl 668: CONST char *, keywords,
1.15 timbl 669: CONST char *, indexname,
670: HTRequest *, request)
1.2 timbl 671: {
672: HTParentAnchor * anchor =
673: (HTParentAnchor*) HTAnchor_findAddress(indexname);
1.15 timbl 674: return HTSearch(keywords, anchor, request);
1.2 timbl 675: }
676:
677:
678: /* Generate the anchor for the home page
679: ** -------------------------------------
680: **
681: ** As it involves file access, this should only be done once
682: ** when the program first runs.
1.10 timbl 683: ** This is a default algorithm -- browser don't HAVE to use this.
684: ** But consistency betwen browsers is STRONGLY recommended!
1.2 timbl 685: **
1.10 timbl 686: ** Priority order is:
687: **
688: ** 1 WWW_HOME environment variable (logical name, etc)
689: ** 2 ~/WWW/default.html
690: ** 3 /usr/local/bin/default.html
691: ** 4 http://info.cern.ch/default.html
692: **
1.2 timbl 693: */
694: PUBLIC HTParentAnchor * HTHomeAnchor NOARGS
695: {
1.12 timbl 696: char * my_home_document = NULL;
697: char * home = (char *)getenv(LOGICAL_DEFAULT);
1.2 timbl 698: char * ref;
699: HTParentAnchor * anchor;
1.1 timbl 700:
1.12 timbl 701: if (home) {
702: StrAllocCopy(my_home_document, home);
703:
704: /* Someone telnets in, they get a special home.
705: */
706: #define MAX_FILE_NAME 1024 /* @@@ */
707: } else if (HTClientHost) { /* Telnet server */
708: FILE * fp = fopen(REMOTE_POINTER, "r");
709: char * status;
710: if (fp) {
711: my_home_document = (char*) malloc(MAX_FILE_NAME);
712: status = fgets(my_home_document, MAX_FILE_NAME, fp);
713: if (!status) {
714: free(my_home_document);
715: my_home_document = NULL;
716: }
717: fclose(fp);
718: }
719: if (!my_home_document) StrAllocCopy(my_home_document, REMOTE_ADDRESS);
720: }
721:
722:
723:
1.2 timbl 724: #ifdef unix
1.12 timbl 725:
1.10 timbl 726: if (!my_home_document) {
727: FILE * fp = NULL;
728: CONST char * home = (CONST char*)getenv("HOME");
729: if (home) {
730: my_home_document = (char *)malloc(
731: strlen(home)+1+ strlen(PERSONAL_DEFAULT)+1);
732: if (my_home_document == NULL) outofmem(__FILE__, "HTLocalName");
733: sprintf(my_home_document, "%s/%s", home, PERSONAL_DEFAULT);
734: fp = fopen(my_home_document, "r");
735: }
736:
737: if (!fp) {
738: StrAllocCopy(my_home_document, LOCAL_DEFAULT_FILE);
739: fp = fopen(my_home_document, "r");
740: }
1.2 timbl 741: if (fp) {
742: fclose(fp);
743: } else {
744: if (TRACE) fprintf(stderr,
1.10 timbl 745: "HTBrowse: No local home document ~/%s or %s\n",
746: PERSONAL_DEFAULT, LOCAL_DEFAULT_FILE);
1.11 timbl 747: free(my_home_document);
748: my_home_document = NULL;
1.2 timbl 749: }
750: }
751: #endif
1.10 timbl 752: ref = HTParse( my_home_document ? my_home_document :
753: HTClientHost ? REMOTE_ADDRESS
754: : LAST_RESORT,
755: "file:",
1.2 timbl 756: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1.10 timbl 757: if (my_home_document) {
1.2 timbl 758: if (TRACE) fprintf(stderr,
759: "HTAccess: Using custom home page %s i.e. address %s\n",
1.10 timbl 760: my_home_document, ref);
761: free(my_home_document);
1.2 timbl 762: }
763: anchor = (HTParentAnchor*) HTAnchor_findAddress(ref);
764: free(ref);
765: return anchor;
1.1 timbl 766: }
767:
768:
Webmaster