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