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