Annotation of libwww/Library/src/HTAccess.c, revision 1.25
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: {
1.25 ! frystyk 367: char *arg = NULL;
! 368: HTProtocol *p;
! 369: int status;
! 370:
1.22 luotonen 371: if (request->method == METHOD_INVALID)
372: request->method = METHOD_GET;
1.21 luotonen 373: status = get_physical(request);
1.2 timbl 374: if (status == HT_FORBIDDEN) {
1.21 luotonen 375: return HTLoadError(request, 500,
376: "Access forbidden by rule");
1.2 timbl 377: }
378: if (status < 0) return status; /* Can't resolve or forbidden */
1.25 ! frystyk 379:
! 380: /* THIS HAS BEEN MOVED FROM HTTP.C HTLoadHTTP() BECAUSE OF NON-COSISTENCE
! 381: BETWEEN request->anchor and request->argument. Henrik 14/02-94 */
! 382: if(!(arg = HTAnchor_physical(request->anchor)) || !*arg)
! 383: return (-1);
! 384: StrAllocCopy(request->argument, arg);
1.2 timbl 385:
1.15 timbl 386: p = HTAnchor_protocol(request->anchor);
1.17 timbl 387: return (*(p->load))(request);
1.2 timbl 388: }
389:
390:
391: /* Get a save stream for a document
392: ** --------------------------------
393: */
1.19 timbl 394: PUBLIC HTStream *HTSaveStream ARGS1(HTRequest *, request)
1.15 timbl 395: {
396: HTProtocol * p;
1.19 timbl 397: int status;
1.22 luotonen 398: request->method = METHOD_PUT;
1.21 luotonen 399: status = get_physical(request);
1.19 timbl 400: if (status == HT_FORBIDDEN) {
1.21 luotonen 401: HTLoadError(request, 500,
402: "Access forbidden by rule");
1.19 timbl 403: return NULL; /* should return error status? */
404: }
405: if (status < 0) return NULL; /* @@ error. Can't resolve or forbidden */
406:
1.15 timbl 407: p = HTAnchor_protocol(request->anchor);
1.2 timbl 408: if (!p) return NULL;
409:
1.15 timbl 410: return (*p->saveStream)(request);
1.2 timbl 411:
412: }
413:
414:
415: /* Load a document - with logging etc
416: ** ----------------------------------
417: **
418: ** - Checks or documents already loaded
419: ** - Logs the access
420: ** - Allows stdin filter option
421: ** - Trace ouput and error messages
422: **
1.1 timbl 423: ** On Entry,
1.19 timbl 424: ** request->anchor valid for of the document to be accessed.
425: ** request->childAnchor optional anchor within doc to be selected
426: **
1.2 timbl 427: ** filter if YES, treat stdin as HTML
1.1 timbl 428: **
1.15 timbl 429: ** request->anchor is the node_anchor for the document
430: ** request->output_format is valid
431: **
1.1 timbl 432: ** On Exit,
433: ** returns YES Success in opening document
434: ** NO Failure
435: **
436: */
437:
1.19 timbl 438: PRIVATE BOOL HTLoadDocument ARGS1(HTRequest *, request)
1.1 timbl 439:
440: {
441: int status;
442: HText * text;
1.19 timbl 443: char * full_address = HTAnchor_address((HTAnchor*)request->anchor);
444:
1.1 timbl 445: if (TRACE) fprintf (stderr,
446: "HTAccess: loading document %s\n", full_address);
447:
1.18 timbl 448: request->using_cache = NULL;
449:
1.15 timbl 450: if (!request->output_format) request->output_format = WWW_PRESENT;
1.25 ! frystyk 451:
1.20 luotonen 452: if ((text=(HText *)HTAnchor_document(request->anchor)))
1.15 timbl 453: { /* Already loaded */
1.1 timbl 454: if (TRACE) fprintf(stderr, "HTAccess: Document already in memory.\n");
1.19 timbl 455: if (request->childAnchor) {
456: HText_selectAnchor(text, request->childAnchor);
457: } else {
458: HText_select(text);
459: }
460: free(full_address);
1.1 timbl 461: return YES;
462: }
1.17 timbl 463:
464: /* Check the Cache
465: */
466: /* Bug: for each format, we only check whether it is ok, we
467: don't check them all and chose the best */
468: if (request->anchor->cacheItems) {
469: HTList * list = request->anchor->cacheItems;
1.20 luotonen 470: HTList * cur = list;
471: HTCacheItem * item;
472:
473: while ((item = (HTCacheItem*)HTList_nextObject(cur))) {
1.18 timbl 474: HTStream * s;
475:
476: request->using_cache = item;
477:
478: s = HTStreamStack(item->format, request);
1.17 timbl 479: if (s) { /* format was suitable */
480: FILE * fp = fopen(item->filename, "r");
1.18 timbl 481: if (TRACE) fprintf(stderr, "Cache: HIT file %s for %s\n",
1.20 luotonen 482: item->filename,
483: full_address);
1.17 timbl 484: if (fp) {
485: HTFileCopy(fp, s);
1.24 timbl 486: (*s->isa->free)(s); /* close up pipeline */
1.17 timbl 487: fclose(fp);
1.19 timbl 488: free(full_address);
1.17 timbl 489: return YES;
490: } else {
491: fprintf(stderr, "***** Can't read cache file %s !\n",
1.20 luotonen 492: item->filename);
1.17 timbl 493: } /* file open ok */
494: } /* stream ok */
495: } /* next cache item */
496: } /* if cache available for this anchor */
1.1 timbl 497:
1.15 timbl 498: status = HTLoad(full_address, request);
1.2 timbl 499:
500:
1.1 timbl 501: /* Log the access if necessary
502: */
503: if (logfile) {
504: time_t theTime;
505: time(&theTime);
506: fprintf(logfile, "%24.24s %s %s %s\n",
507: ctime(&theTime),
508: HTClientHost ? HTClientHost : "local",
509: status<0 ? "FAIL" : "GET",
510: full_address);
511: fflush(logfile); /* Actually update it on disk */
512: if (TRACE) fprintf(stderr, "Log: %24.24s %s %s %s\n",
513: ctime(&theTime),
514: HTClientHost ? HTClientHost : "local",
515: status<0 ? "FAIL" : "GET",
516: full_address);
517: }
518:
519:
520: if (status == HT_LOADED) {
521: if (TRACE) {
522: fprintf(stderr, "HTAccess: `%s' has been accessed.\n",
523: full_address);
524: }
1.19 timbl 525: free(full_address);
1.1 timbl 526: return YES;
527: }
528:
529: if (status == HT_NO_DATA) {
530: if (TRACE) {
531: fprintf(stderr,
532: "HTAccess: `%s' has been accessed, No data left.\n",
533: full_address);
534: }
1.19 timbl 535: free(full_address);
1.1 timbl 536: return NO;
537: }
538:
1.2 timbl 539: if (status<0) { /* Failure in accessing a document */
1.1 timbl 540: #ifdef CURSES
541: user_message("Can't access `%s'", full_address);
542: #else
1.5 timbl 543: if (TRACE) fprintf(stderr,
544: "HTAccess: Can't access `%s'\n", full_address);
1.1 timbl 545: #endif
1.21 luotonen 546: HTLoadError(request, 500, "Unable to access document.");
1.19 timbl 547: free(full_address);
1.1 timbl 548: return NO;
549: }
1.9 timbl 550:
551: /* If you get this, then please find which routine is returning
552: a positive unrecognised error code! */
553:
1.1 timbl 554: fprintf(stderr,
1.2 timbl 555: "**** HTAccess: socket or file number returned by obsolete load routine!\n");
1.9 timbl 556: fprintf(stderr,
1.19 timbl 557: "**** HTAccess: Internal software error. Please mail www-bug@info.cern.ch quoting the version number of this software and the URL: %s!\n",
558: full_address);
559: free(full_address);
560:
1.1 timbl 561: exit(-6996);
1.20 luotonen 562: return NO; /* For gcc :-( */
1.2 timbl 563: } /* HTLoadDocument */
1.1 timbl 564:
565:
566:
567: /* Load a document from absolute name
568: ** ---------------
569: **
570: ** On Entry,
571: ** addr The absolute address of the document to be accessed.
572: ** filter if YES, treat document as HTML
573: **
574: ** On Exit,
575: ** returns YES Success in opening document
576: ** NO Failure
577: **
578: **
579: */
580:
1.15 timbl 581: PUBLIC BOOL HTLoadAbsolute ARGS2(CONST char *,addr, HTRequest*, request)
1.2 timbl 582: {
1.19 timbl 583: HTAnchor * anchor = HTAnchor_findAddress(addr);
584: request->anchor = HTAnchor_parent(anchor);
585: request->childAnchor = ((HTAnchor*)request->anchor == anchor) ?
586: NULL : (HTChildAnchor*) anchor;
587: return HTLoadDocument(request);
1.2 timbl 588: }
589:
590:
591: /* Load a document from absolute name to stream
592: ** --------------------------------------------
593: **
594: ** On Entry,
595: ** addr The absolute address of the document to be accessed.
1.15 timbl 596: ** request->output_stream if non-NULL, send data down this stream
1.2 timbl 597: **
598: ** On Exit,
599: ** returns YES Success in opening document
600: ** NO Failure
601: **
602: **
603: */
604:
605: PUBLIC BOOL HTLoadToStream ARGS3(
606: CONST char *, addr,
607: BOOL, filter,
1.15 timbl 608: HTRequest*, request)
1.1 timbl 609: {
1.19 timbl 610: HTAnchor * anchor = HTAnchor_findAddress(addr);
611: request->anchor = HTAnchor_parent(anchor);
612: request->childAnchor = ((HTAnchor*)request->anchor == anchor) ? NULL :
613: (HTChildAnchor*) anchor;
1.15 timbl 614: request->output_stream = request->output_stream;
1.19 timbl 615: return HTLoadDocument(request);
1.1 timbl 616: }
617:
618:
1.2 timbl 619:
620:
1.1 timbl 621: /* Load a document from relative name
622: ** ---------------
623: **
624: ** On Entry,
1.2 timbl 625: ** relative_name The relative address of the document
626: ** to be accessed.
1.1 timbl 627: **
628: ** On Exit,
629: ** returns YES Success in opening document
630: ** NO Failure
631: **
632: **
633: */
634:
1.15 timbl 635: PUBLIC BOOL HTLoadRelative ARGS3(
1.2 timbl 636: CONST char *, relative_name,
1.15 timbl 637: HTParentAnchor *, here,
1.20 luotonen 638: HTRequest *, request)
1.1 timbl 639: {
640: char * full_address = 0;
641: BOOL result;
642: char * mycopy = 0;
643: char * stripped = 0;
644: char * current_address =
1.2 timbl 645: HTAnchor_address((HTAnchor*)here);
1.1 timbl 646:
647: StrAllocCopy(mycopy, relative_name);
648:
649: stripped = HTStrip(mycopy);
650: full_address = HTParse(stripped,
651: current_address,
652: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1.15 timbl 653: result = HTLoadAbsolute(full_address, request);
1.1 timbl 654: free(full_address);
655: free(current_address);
656: free(mycopy); /* Memory leak fixed 10/7/92 -- JFG */
657: return result;
658: }
659:
660:
661: /* Load if necessary, and select an anchor
662: ** --------------------------------------
663: **
664: ** On Entry,
665: ** destination The child or parenet anchor to be loaded.
666: **
667: ** On Exit,
668: ** returns YES Success
669: ** NO Failure
670: **
671: */
672:
1.15 timbl 673: PUBLIC BOOL HTLoadAnchor ARGS2(HTAnchor*, anchor, HTRequest *, request)
1.1 timbl 674: {
1.15 timbl 675: if (!anchor) return NO; /* No link */
1.1 timbl 676:
1.15 timbl 677: request->anchor = HTAnchor_parent(anchor);
1.19 timbl 678: request->childAnchor = ((HTAnchor*)request->anchor == anchor) ? NULL
679: : (HTChildAnchor*) anchor;
1.1 timbl 680:
1.19 timbl 681: return HTLoadDocument(request) ? YES : NO;
1.1 timbl 682:
683: } /* HTLoadAnchor */
684:
685:
686: /* Search
687: ** ------
688: ** Performs a keyword search on word given by the user. Adds the keyword to
689: ** the end of the current address and attempts to open the new address.
690: **
691: ** On Entry,
692: ** *keywords space-separated keyword list or similar search list
1.2 timbl 693: ** here is anchor search is to be done on.
1.1 timbl 694: */
695:
1.2 timbl 696: PRIVATE char hex(i)
697: int i;
698: {
1.13 timbl 699: char * hexchars = "0123456789ABCDEF";
700: return hexchars[i];
1.2 timbl 701: }
1.1 timbl 702:
1.15 timbl 703: PUBLIC BOOL HTSearch ARGS3(
1.2 timbl 704: CONST char *, keywords,
1.15 timbl 705: HTParentAnchor *, here,
706: HTRequest *, request)
1.1 timbl 707: {
1.2 timbl 708:
709: #define acceptable \
710: "1234567890abcdefghijlkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_"
711:
712: char *q, *u;
713: CONST char * p, *s, *e; /* Pointers into keywords */
714: char * address = HTAnchor_address((HTAnchor*)here);
1.1 timbl 715: BOOL result;
1.2 timbl 716: char * escaped = malloc(strlen(keywords)*3+1);
717:
718: static CONST BOOL isAcceptable[96] =
719:
720: /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
721: { 0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,0, /* 2x !"#$%&'()*+,-./ */
722: 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */
723: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4x @ABCDEFGHIJKLMNO */
724: 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1, /* 5X PQRSTUVWXYZ[\]^_ */
725: 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6x `abcdefghijklmno */
726: 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0 }; /* 7X pqrstuvwxyz{\}~ DEL */
727:
728: if (escaped == NULL) outofmem(__FILE__, "HTSearch");
729:
730:
731: /* Convert spaces to + and hex escape unacceptable characters
732: */
733: for(s=keywords; *s && WHITE(*s); s++) /*scan */ ; /* Skip white space */
734: for(e = s + strlen(s); e>s && WHITE(*(e-1)) ; e--); /* Skip trailers */
735: for(q=escaped, p=s; p<e; p++) { /* scan stripped field */
736: int c = (int)TOASCII(*p);
737: if (WHITE(*p)) {
738: *q++ = '+';
739: } else if (c>=32 && c<=(char)127 && isAcceptable[c-32]) {
1.13 timbl 740: *q++ = *p; /* 930706 TBL for MVS bug */
1.2 timbl 741: } else {
742: *q++ = '%';
743: *q++ = hex(c / 16);
744: *q++ = hex(c % 16);
745: }
746: } /* Loop over string */
1.1 timbl 747:
1.2 timbl 748: *q=0;
749: /* terminate escaped sctring */
750: u=strchr(address, '?'); /* Find old search string */
751: if (u) *u = 0; /* Chop old search off */
1.1 timbl 752:
753: StrAllocCat(address, "?");
1.2 timbl 754: StrAllocCat(address, escaped);
755: free(escaped);
1.15 timbl 756: result = HTLoadRelative(address, here, request);
1.1 timbl 757: free(address);
1.2 timbl 758:
1.1 timbl 759: return result;
1.2 timbl 760: }
761:
762:
763: /* Search Given Indexname
764: ** ------
765: ** Performs a keyword search on word given by the user. Adds the keyword to
766: ** the end of the current address and attempts to open the new address.
767: **
768: ** On Entry,
769: ** *keywords space-separated keyword list or similar search list
770: ** *addres is name of object search is to be done on.
771: */
772:
1.15 timbl 773: PUBLIC BOOL HTSearchAbsolute ARGS3(
1.2 timbl 774: CONST char *, keywords,
1.15 timbl 775: CONST char *, indexname,
776: HTRequest *, request)
1.2 timbl 777: {
778: HTParentAnchor * anchor =
779: (HTParentAnchor*) HTAnchor_findAddress(indexname);
1.15 timbl 780: return HTSearch(keywords, anchor, request);
1.2 timbl 781: }
782:
783:
784: /* Generate the anchor for the home page
785: ** -------------------------------------
786: **
787: ** As it involves file access, this should only be done once
788: ** when the program first runs.
1.10 timbl 789: ** This is a default algorithm -- browser don't HAVE to use this.
790: ** But consistency betwen browsers is STRONGLY recommended!
1.2 timbl 791: **
1.10 timbl 792: ** Priority order is:
793: **
794: ** 1 WWW_HOME environment variable (logical name, etc)
795: ** 2 ~/WWW/default.html
796: ** 3 /usr/local/bin/default.html
797: ** 4 http://info.cern.ch/default.html
798: **
1.2 timbl 799: */
800: PUBLIC HTParentAnchor * HTHomeAnchor NOARGS
801: {
1.12 timbl 802: char * my_home_document = NULL;
803: char * home = (char *)getenv(LOGICAL_DEFAULT);
1.2 timbl 804: char * ref;
805: HTParentAnchor * anchor;
1.1 timbl 806:
1.12 timbl 807: if (home) {
808: StrAllocCopy(my_home_document, home);
809:
810: /* Someone telnets in, they get a special home.
811: */
812: #define MAX_FILE_NAME 1024 /* @@@ */
813: } else if (HTClientHost) { /* Telnet server */
814: FILE * fp = fopen(REMOTE_POINTER, "r");
815: char * status;
816: if (fp) {
817: my_home_document = (char*) malloc(MAX_FILE_NAME);
818: status = fgets(my_home_document, MAX_FILE_NAME, fp);
819: if (!status) {
820: free(my_home_document);
821: my_home_document = NULL;
822: }
823: fclose(fp);
824: }
825: if (!my_home_document) StrAllocCopy(my_home_document, REMOTE_ADDRESS);
826: }
827:
828:
829:
1.2 timbl 830: #ifdef unix
1.12 timbl 831:
1.10 timbl 832: if (!my_home_document) {
833: FILE * fp = NULL;
834: CONST char * home = (CONST char*)getenv("HOME");
835: if (home) {
836: my_home_document = (char *)malloc(
837: strlen(home)+1+ strlen(PERSONAL_DEFAULT)+1);
838: if (my_home_document == NULL) outofmem(__FILE__, "HTLocalName");
839: sprintf(my_home_document, "%s/%s", home, PERSONAL_DEFAULT);
840: fp = fopen(my_home_document, "r");
841: }
842:
843: if (!fp) {
844: StrAllocCopy(my_home_document, LOCAL_DEFAULT_FILE);
845: fp = fopen(my_home_document, "r");
846: }
1.2 timbl 847: if (fp) {
848: fclose(fp);
849: } else {
850: if (TRACE) fprintf(stderr,
1.10 timbl 851: "HTBrowse: No local home document ~/%s or %s\n",
852: PERSONAL_DEFAULT, LOCAL_DEFAULT_FILE);
1.11 timbl 853: free(my_home_document);
854: my_home_document = NULL;
1.2 timbl 855: }
856: }
857: #endif
1.10 timbl 858: ref = HTParse( my_home_document ? my_home_document :
859: HTClientHost ? REMOTE_ADDRESS
860: : LAST_RESORT,
861: "file:",
1.2 timbl 862: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1.10 timbl 863: if (my_home_document) {
1.2 timbl 864: if (TRACE) fprintf(stderr,
865: "HTAccess: Using custom home page %s i.e. address %s\n",
1.10 timbl 866: my_home_document, ref);
867: free(my_home_document);
1.2 timbl 868: }
869: anchor = (HTParentAnchor*) HTAnchor_findAddress(ref);
870: free(ref);
871: return anchor;
1.1 timbl 872: }
Webmaster