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