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