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