Annotation of libwww/Library/src/HTAccess.c, revision 1.41
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: */
1.34 frystyk 52: PUBLIC char * HTCacheDir = 0; /* Root for cached files or 0 for no cache */
53: PUBLIC char * HTSaveLocallyDir = SAVE_LOCALLY_HOME_DIR; /* Save & exe files */
1.1 timbl 54: PUBLIC char * HTClientHost = 0; /* Name of remote login host if any */
1.41 ! luotonen 55:
! 56: #ifdef OLD_CODE /* WAIS now defines its own logfile */
1.1 timbl 57: PUBLIC FILE * logfile = 0; /* File to which to output one-liners */
1.41 ! luotonen 58: #endif
! 59:
1.34 frystyk 60: PUBLIC BOOL HTForceReload = NO; /* Force reload from cache or net */
1.12 timbl 61: PUBLIC BOOL HTSecure = NO; /* Disable access for telnet users? */
1.27 luotonen 62: PUBLIC BOOL using_proxy = NO; /* are we using a proxy gateway? */
63: PUBLIC BOOL HTImServer = NO; /* cern_httpd sets this */
64: PUBLIC BOOL HTImProxy = NO; /* cern_httpd as a proxy? */
1.1 timbl 65:
1.2 timbl 66: /* To generate other things, play with these:
67: */
68:
1.15 timbl 69: /* PUBLIC HTFormat HTOutputFormat = NULL; use request->output_format */
70: /* PUBLIC HTStream* HTOutputStream = NULL; use request->output_stream */
1.1 timbl 71:
72: PRIVATE HTList * protocols = NULL; /* List of registered protocol descriptors */
73:
1.24 timbl 74: /* Superclass defn */
1.1 timbl 75:
1.24 timbl 76: struct _HTStream {
77: HTStreamClass * isa;
78: /* ... */
79: };
80:
1.15 timbl 81: /* Create a request structure
82: ** ---------------------------
83: */
84:
85: PUBLIC HTRequest * HTRequest_new NOARGS
86: {
1.28 luotonen 87: HTRequest * me = (HTRequest*) calloc(1, sizeof(*me)); /* zero fill */
1.15 timbl 88: if (!me) outofmem(__FILE__, "HTRequest_new()");
89:
1.20 luotonen 90: me->conversions = HTList_new(); /* No conversions registerd yet */
91: me->output_format = WWW_PRESENT; /* default it to present to user */
92:
1.15 timbl 93: return me;
94: }
95:
96:
1.20 luotonen 97: /* Delete a request structure
98: ** --------------------------
99: */
100: PUBLIC void HTRequest_delete ARGS1(HTRequest *, req)
101: {
102: if (req) {
1.34 frystyk 103: HTFormatDelete(req->conversions);
104: HTAACleanup(req);
1.37 luotonen 105: FREE(req->from);
1.34 frystyk 106: FREE(req);
1.20 luotonen 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.33 luotonen 227:
228: /* override_proxy()
229: **
230: ** Check the no_proxy environment variable to get the list
231: ** of hosts for which proxy server is not consulted.
232: **
233: ** no_proxy is a comma- or space-separated list of machine
234: ** or domain names, with optional :port part. If no :port
235: ** part is present, it applies to all ports on that domain.
236: **
237: ** Example:
238: ** no_proxy="cern.ch,some.domain:8001"
239: **
240: */
241: PRIVATE BOOL override_proxy ARGS1(CONST char *, addr)
242: {
243: CONST char * no_proxy = getenv("no_proxy");
244: char * p = NULL;
245: char * host = NULL;
246: int port = 0;
247: int h_len = 0;
248:
249: if (!no_proxy || !addr || !(host = HTParse(addr, "", PARSE_HOST)))
250: return NO;
251: if (!*host) { free(host); return NO; }
252:
1.34 frystyk 253: if ((p = strchr(host, ':')) != NULL) { /* Port specified */
1.33 luotonen 254: *p++ = 0; /* Chop off port */
255: port = atoi(p);
256: }
257: else { /* Use default port */
258: char * access = HTParse(addr, "", PARSE_ACCESS);
259: if (access) {
260: if (!strcmp(access,"http")) port = 80;
261: else if (!strcmp(access,"gopher")) port = 70;
262: else if (!strcmp(access,"ftp")) port = 21;
263: free(access);
264: }
265: }
266: if (!port) port = 80; /* Default */
267: h_len = strlen(host);
268:
269: while (*no_proxy) {
270: CONST char * end;
271: CONST char * colon = NULL;
272: int templ_port = 0;
273: int t_len;
274:
275: while (*no_proxy && (WHITE(*no_proxy) || *no_proxy==','))
276: no_proxy++; /* Skip whitespace and separators */
277:
278: end = no_proxy;
279: while (*end && !WHITE(*end) && *end != ',') { /* Find separator */
280: if (*end==':') colon = end; /* Port number given */
281: end++;
282: }
283:
284: if (colon) {
285: templ_port = atoi(colon+1);
286: t_len = colon - no_proxy;
287: }
288: else {
289: t_len = end - no_proxy;
290: }
291:
292: if ((!templ_port || templ_port == port) &&
293: (t_len > 0 && t_len <= h_len &&
294: !strncmp(host + h_len - t_len, no_proxy, t_len))) {
295: free(host);
296: return YES;
297: }
298: if (*end) no_proxy = end+1;
299: else break;
300: }
301:
302: free(host);
303: return NO;
304: }
305:
306:
307:
1.2 timbl 308: /* Find physical name and access protocol
309: ** --------------------------------------
1.1 timbl 310: **
311: **
312: ** On entry,
313: ** addr must point to the fully qualified hypertext reference.
314: ** anchor a pareent anchor with whose address is addr
315: **
316: ** On exit,
1.2 timbl 317: ** returns HT_NO_ACCESS Error has occured.
318: ** HT_OK Success
1.1 timbl 319: **
320: */
1.21 luotonen 321: PRIVATE int get_physical ARGS1(HTRequest *, req)
322: {
1.1 timbl 323: char * access=0; /* Name of access method */
1.21 luotonen 324: char * addr = HTAnchor_address((HTAnchor*)req->anchor); /* free me */
1.27 luotonen 325:
1.35 luotonen 326: /*
327: ** This HACK is here until we have redirection implemented.
328: ** This is used when we are recursively calling HTLoad().
329: ** We then take the physical address, because currently the
330: ** virtual address is kept in a hash table so it can't be
331: ** changed -- otherwise it wouldn't be found anymore.
332: */
1.36 luotonen 333: if (HTAnchor_physical(req->anchor))
334: StrAllocCopy(addr, HTAnchor_physical(req->anchor));
1.35 luotonen 335:
1.2 timbl 336: #ifndef NO_RULES
1.27 luotonen 337: if (HTImServer) /* cern_httpd has already done its own translations */
338: HTAnchor_setPhysical(req->anchor, addr);
1.21 luotonen 339: else {
1.27 luotonen 340: char * physical = HTTranslate(addr);
1.21 luotonen 341: if (!physical) {
342: free(addr);
343: return HT_FORBIDDEN;
344: }
345: HTAnchor_setPhysical(req->anchor, physical);
346: free(physical); /* free our copy */
1.2 timbl 347: }
348: #else
1.21 luotonen 349: HTAnchor_setPhysical(req->anchor, addr);
1.2 timbl 350: #endif
351:
1.21 luotonen 352: access = HTParse(HTAnchor_physical(req->anchor),
1.27 luotonen 353: "file:", PARSE_ACCESS);
1.1 timbl 354:
355: /* Check whether gateway access has been set up for this
1.8 timbl 356: **
357: ** This function can be replaced by the rule system above.
1.1 timbl 358: */
1.8 timbl 359: #define USE_GATEWAYS
1.1 timbl 360: #ifdef USE_GATEWAYS
1.39 luotonen 361:
362: /* make sure the using_proxy variable is false */
363: using_proxy = NO;
364:
1.33 luotonen 365: if (!override_proxy(addr)) {
1.27 luotonen 366: char * gateway_parameter, *gateway, *proxy;
367:
1.2 timbl 368: gateway_parameter = (char *)malloc(strlen(access)+20);
369: if (gateway_parameter == NULL) outofmem(__FILE__, "HTLoad");
1.27 luotonen 370:
371: /* search for proxy gateways */
1.2 timbl 372: strcpy(gateway_parameter, "WWW_");
373: strcat(gateway_parameter, access);
374: strcat(gateway_parameter, "_GATEWAY");
375: gateway = (char *)getenv(gateway_parameter); /* coerce for decstation */
1.27 luotonen 376:
377: /* search for proxy servers */
378: strcpy(gateway_parameter, access);
379: strcat(gateway_parameter, "_proxy");
380: proxy = (char *)getenv(gateway_parameter);
381:
1.2 timbl 382: free(gateway_parameter);
1.27 luotonen 383:
384: if (TRACE && gateway)
385: fprintf(stderr,"Gateway found: %s\n",gateway);
386: if (TRACE && proxy)
387: fprintf(stderr,"Proxy server found: %s\n",proxy);
388:
1.8 timbl 389: #ifndef DIRECT_WAIS
1.9 timbl 390: if (!gateway && 0==strcmp(access, "wais")) {
1.8 timbl 391: gateway = DEFAULT_WAIS_GATEWAY;
392: }
393: #endif
1.27 luotonen 394:
395: /* proxy servers have precedence over gateway servers */
396: if (proxy) {
397: char * gatewayed=0;
398:
399: StrAllocCopy(gatewayed,proxy);
400: StrAllocCat(gatewayed,addr);
401: using_proxy = YES;
402: HTAnchor_setPhysical(req->anchor, gatewayed);
403: free(gatewayed);
404: free(access);
405:
406: access = HTParse(HTAnchor_physical(req->anchor),
407: "http:", PARSE_ACCESS);
408: } else if (gateway) {
1.9 timbl 409: char * path = HTParse(addr, "",
410: PARSE_HOST + PARSE_PATH + PARSE_PUNCTUATION);
411: /* Chop leading / off to make host into part of path */
412: char * gatewayed = HTParse(path+1, gateway, PARSE_ALL);
413: free(path);
1.21 luotonen 414: HTAnchor_setPhysical(req->anchor, gatewayed);
1.9 timbl 415: free(gatewayed);
1.2 timbl 416: free(access);
1.9 timbl 417:
1.21 luotonen 418: access = HTParse(HTAnchor_physical(req->anchor),
1.8 timbl 419: "http:", PARSE_ACCESS);
1.2 timbl 420: }
421: }
1.1 timbl 422: #endif
423:
1.19 timbl 424: free(addr);
1.1 timbl 425:
426:
427: /* Search registered protocols to find suitable one
428: */
429: {
1.20 luotonen 430: HTList *cur;
431: HTProtocol *p;
1.1 timbl 432: #ifndef NO_INIT
1.2 timbl 433: if (!protocols) HTAccessInit();
1.1 timbl 434: #endif
1.20 luotonen 435: cur = protocols;
436: while ((p = (HTProtocol*)HTList_nextObject(cur))) {
1.2 timbl 437: if (strcmp(p->name, access)==0) {
1.21 luotonen 438: HTAnchor_setProtocol(req->anchor, p);
1.2 timbl 439: free(access);
440: return (HT_OK);
1.1 timbl 441: }
442: }
443: }
444:
445: free(access);
1.2 timbl 446: return HT_NO_ACCESS;
1.1 timbl 447: }
448:
449:
450: /* Load a document
451: ** ---------------
452: **
1.2 timbl 453: ** This is an internal routine, which has an address AND a matching
454: ** anchor. (The public routines are called with one OR the other.)
455: **
456: ** On entry,
1.15 timbl 457: ** request->
1.35 luotonen 458: ** anchor a parent anchor with fully qualified
459: ** hypertext reference as its address set
1.15 timbl 460: ** output_format valid
461: ** output_stream valid on NULL
1.2 timbl 462: **
463: ** On exit,
464: ** returns <0 Error has occured.
465: ** HT_LOADED Success
466: ** HT_NO_DATA Success, but no document loaded.
1.8 timbl 467: ** (telnet sesssion started etc)
1.2 timbl 468: **
469: */
1.35 luotonen 470: PUBLIC int HTLoad ARGS1(HTRequest *, request)
1.2 timbl 471: {
1.25 frystyk 472: char *arg = NULL;
473: HTProtocol *p;
474: int status;
475:
1.22 luotonen 476: if (request->method == METHOD_INVALID)
477: request->method = METHOD_GET;
1.21 luotonen 478: status = get_physical(request);
1.2 timbl 479: if (status == HT_FORBIDDEN) {
1.21 luotonen 480: return HTLoadError(request, 500,
481: "Access forbidden by rule");
1.2 timbl 482: }
483: if (status < 0) return status; /* Can't resolve or forbidden */
1.25 frystyk 484:
485: if(!(arg = HTAnchor_physical(request->anchor)) || !*arg)
486: return (-1);
1.27 luotonen 487:
1.15 timbl 488: p = HTAnchor_protocol(request->anchor);
1.17 timbl 489: return (*(p->load))(request);
1.2 timbl 490: }
491:
492:
493: /* Get a save stream for a document
494: ** --------------------------------
495: */
1.19 timbl 496: PUBLIC HTStream *HTSaveStream ARGS1(HTRequest *, request)
1.15 timbl 497: {
498: HTProtocol * p;
1.19 timbl 499: int status;
1.22 luotonen 500: request->method = METHOD_PUT;
1.21 luotonen 501: status = get_physical(request);
1.19 timbl 502: if (status == HT_FORBIDDEN) {
1.21 luotonen 503: HTLoadError(request, 500,
504: "Access forbidden by rule");
1.19 timbl 505: return NULL; /* should return error status? */
506: }
507: if (status < 0) return NULL; /* @@ error. Can't resolve or forbidden */
508:
1.15 timbl 509: p = HTAnchor_protocol(request->anchor);
1.2 timbl 510: if (!p) return NULL;
511:
1.15 timbl 512: return (*p->saveStream)(request);
1.2 timbl 513:
514: }
515:
516:
517: /* Load a document - with logging etc
518: ** ----------------------------------
519: **
520: ** - Checks or documents already loaded
521: ** - Logs the access
522: ** - Allows stdin filter option
523: ** - Trace ouput and error messages
524: **
1.1 timbl 525: ** On Entry,
1.19 timbl 526: ** request->anchor valid for of the document to be accessed.
527: ** request->childAnchor optional anchor within doc to be selected
528: **
1.2 timbl 529: ** filter if YES, treat stdin as HTML
1.1 timbl 530: **
1.15 timbl 531: ** request->anchor is the node_anchor for the document
532: ** request->output_format is valid
533: **
1.1 timbl 534: ** On Exit,
535: ** returns YES Success in opening document
536: ** NO Failure
537: **
538: */
539:
1.19 timbl 540: PRIVATE BOOL HTLoadDocument ARGS1(HTRequest *, request)
1.1 timbl 541:
542: {
543: int status;
544: HText * text;
1.19 timbl 545: char * full_address = HTAnchor_address((HTAnchor*)request->anchor);
546:
1.1 timbl 547: if (TRACE) fprintf (stderr,
548: "HTAccess: loading document %s\n", full_address);
549:
1.18 timbl 550: request->using_cache = NULL;
551:
1.15 timbl 552: if (!request->output_format) request->output_format = WWW_PRESENT;
1.25 frystyk 553:
1.31 frystyk 554: if (!HTForceReload && (text=(HText *)HTAnchor_document(request->anchor)))
1.15 timbl 555: { /* Already loaded */
1.1 timbl 556: if (TRACE) fprintf(stderr, "HTAccess: Document already in memory.\n");
1.19 timbl 557: if (request->childAnchor) {
558: HText_selectAnchor(text, request->childAnchor);
559: } else {
560: HText_select(text);
561: }
562: free(full_address);
1.1 timbl 563: return YES;
564: }
1.17 timbl 565:
1.34 frystyk 566: /* Check the Cache */
567: /* Caching is ONLY done if (char*) HTCacheDir is set. Henrik 09/03-94 */
1.17 timbl 568: /* Bug: for each format, we only check whether it is ok, we
569: don't check them all and chose the best */
1.38 timbl 570: if (/* HTCacheDir && */ request->anchor->cacheItems) {
1.17 timbl 571: HTList * list = request->anchor->cacheItems;
1.20 luotonen 572: HTList * cur = list;
573: HTCacheItem * item;
574:
575: while ((item = (HTCacheItem*)HTList_nextObject(cur))) {
1.18 timbl 576: HTStream * s;
577:
578: request->using_cache = item;
579:
1.37 luotonen 580: s = HTStreamStack(item->format, request, NO);
1.17 timbl 581: if (s) { /* format was suitable */
582: FILE * fp = fopen(item->filename, "r");
1.18 timbl 583: if (TRACE) fprintf(stderr, "Cache: HIT file %s for %s\n",
1.20 luotonen 584: item->filename,
585: full_address);
1.17 timbl 586: if (fp) {
587: HTFileCopy(fp, s);
1.24 timbl 588: (*s->isa->free)(s); /* close up pipeline */
1.17 timbl 589: fclose(fp);
1.19 timbl 590: free(full_address);
1.17 timbl 591: return YES;
592: } else {
593: fprintf(stderr, "***** Can't read cache file %s !\n",
1.20 luotonen 594: item->filename);
1.17 timbl 595: } /* file open ok */
596: } /* stream ok */
597: } /* next cache item */
598: } /* if cache available for this anchor */
1.1 timbl 599:
1.35 luotonen 600: status = HTLoad(request);
1.2 timbl 601:
602:
1.1 timbl 603: /* Log the access if necessary
604: */
1.41 ! luotonen 605: #ifdef OLD_CODE /* WAIS now defines its own logfile */
1.1 timbl 606: if (logfile) {
607: time_t theTime;
608: time(&theTime);
609: fprintf(logfile, "%24.24s %s %s %s\n",
610: ctime(&theTime),
611: HTClientHost ? HTClientHost : "local",
612: status<0 ? "FAIL" : "GET",
613: full_address);
614: fflush(logfile); /* Actually update it on disk */
615: if (TRACE) fprintf(stderr, "Log: %24.24s %s %s %s\n",
616: ctime(&theTime),
617: HTClientHost ? HTClientHost : "local",
618: status<0 ? "FAIL" : "GET",
619: full_address);
620: }
1.41 ! luotonen 621: #endif
1.1 timbl 622:
623:
624: if (status == HT_LOADED) {
625: if (TRACE) {
626: fprintf(stderr, "HTAccess: `%s' has been accessed.\n",
627: full_address);
628: }
1.19 timbl 629: free(full_address);
1.1 timbl 630: return YES;
631: }
632:
633: if (status == HT_NO_DATA) {
634: if (TRACE) {
635: fprintf(stderr,
636: "HTAccess: `%s' has been accessed, No data left.\n",
637: full_address);
638: }
1.19 timbl 639: free(full_address);
1.1 timbl 640: return NO;
641: }
642:
1.34 frystyk 643: /* Bug fix thanks to Lou Montulli. Henrik 10/03-94 */
644: if (status<=0) { /* Failure in accessing a document */
1.1 timbl 645: #ifdef CURSES
646: user_message("Can't access `%s'", full_address);
647: #else
1.5 timbl 648: if (TRACE) fprintf(stderr,
649: "HTAccess: Can't access `%s'\n", full_address);
1.1 timbl 650: #endif
1.32 frystyk 651: /* This is done in the specific load procedures... Henrik 07/03-94 */
1.39 luotonen 652: if (request->error_stack)
653: HTLoadError(request, 500, "Unable to access document.");
1.19 timbl 654: free(full_address);
1.1 timbl 655: return NO;
656: }
1.9 timbl 657:
658: /* If you get this, then please find which routine is returning
659: a positive unrecognised error code! */
660:
1.1 timbl 661: fprintf(stderr,
1.2 timbl 662: "**** HTAccess: socket or file number returned by obsolete load routine!\n");
1.9 timbl 663: fprintf(stderr,
1.19 timbl 664: "**** HTAccess: Internal software error. Please mail www-bug@info.cern.ch quoting the version number of this software and the URL: %s!\n",
665: full_address);
666: free(full_address);
667:
1.1 timbl 668: exit(-6996);
1.20 luotonen 669: return NO; /* For gcc :-( */
1.2 timbl 670: } /* HTLoadDocument */
1.1 timbl 671:
672:
673:
674: /* Load a document from absolute name
675: ** ---------------
676: **
677: ** On Entry,
678: ** addr The absolute address of the document to be accessed.
679: ** filter if YES, treat document as HTML
680: **
681: ** On Exit,
682: ** returns YES Success in opening document
683: ** NO Failure
684: **
685: **
686: */
687:
1.15 timbl 688: PUBLIC BOOL HTLoadAbsolute ARGS2(CONST char *,addr, HTRequest*, request)
1.2 timbl 689: {
1.19 timbl 690: HTAnchor * anchor = HTAnchor_findAddress(addr);
691: request->anchor = HTAnchor_parent(anchor);
692: request->childAnchor = ((HTAnchor*)request->anchor == anchor) ?
693: NULL : (HTChildAnchor*) anchor;
694: return HTLoadDocument(request);
1.2 timbl 695: }
696:
697:
698: /* Load a document from absolute name to stream
699: ** --------------------------------------------
700: **
701: ** On Entry,
702: ** addr The absolute address of the document to be accessed.
1.15 timbl 703: ** request->output_stream if non-NULL, send data down this stream
1.2 timbl 704: **
705: ** On Exit,
706: ** returns YES Success in opening document
707: ** NO Failure
708: **
709: **
710: */
711:
712: PUBLIC BOOL HTLoadToStream ARGS3(
713: CONST char *, addr,
714: BOOL, filter,
1.15 timbl 715: HTRequest*, request)
1.1 timbl 716: {
1.19 timbl 717: HTAnchor * anchor = HTAnchor_findAddress(addr);
718: request->anchor = HTAnchor_parent(anchor);
719: request->childAnchor = ((HTAnchor*)request->anchor == anchor) ? NULL :
720: (HTChildAnchor*) anchor;
1.15 timbl 721: request->output_stream = request->output_stream;
1.19 timbl 722: return HTLoadDocument(request);
1.1 timbl 723: }
724:
725:
1.2 timbl 726:
727:
1.1 timbl 728: /* Load a document from relative name
729: ** ---------------
730: **
731: ** On Entry,
1.2 timbl 732: ** relative_name The relative address of the document
733: ** to be accessed.
1.1 timbl 734: **
735: ** On Exit,
736: ** returns YES Success in opening document
737: ** NO Failure
738: **
739: **
740: */
741:
1.15 timbl 742: PUBLIC BOOL HTLoadRelative ARGS3(
1.2 timbl 743: CONST char *, relative_name,
1.15 timbl 744: HTParentAnchor *, here,
1.20 luotonen 745: HTRequest *, request)
1.1 timbl 746: {
747: char * full_address = 0;
748: BOOL result;
749: char * mycopy = 0;
750: char * stripped = 0;
751: char * current_address =
1.2 timbl 752: HTAnchor_address((HTAnchor*)here);
1.1 timbl 753:
754: StrAllocCopy(mycopy, relative_name);
755:
756: stripped = HTStrip(mycopy);
757: full_address = HTParse(stripped,
758: current_address,
759: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1.15 timbl 760: result = HTLoadAbsolute(full_address, request);
1.1 timbl 761: free(full_address);
762: free(current_address);
763: free(mycopy); /* Memory leak fixed 10/7/92 -- JFG */
764: return result;
765: }
766:
767:
768: /* Load if necessary, and select an anchor
769: ** --------------------------------------
770: **
771: ** On Entry,
772: ** destination The child or parenet anchor to be loaded.
773: **
774: ** On Exit,
775: ** returns YES Success
776: ** NO Failure
777: **
778: */
779:
1.15 timbl 780: PUBLIC BOOL HTLoadAnchor ARGS2(HTAnchor*, anchor, HTRequest *, request)
1.1 timbl 781: {
1.15 timbl 782: if (!anchor) return NO; /* No link */
1.1 timbl 783:
1.15 timbl 784: request->anchor = HTAnchor_parent(anchor);
1.19 timbl 785: request->childAnchor = ((HTAnchor*)request->anchor == anchor) ? NULL
786: : (HTChildAnchor*) anchor;
1.1 timbl 787:
1.19 timbl 788: return HTLoadDocument(request) ? YES : NO;
1.1 timbl 789:
790: } /* HTLoadAnchor */
791:
792:
793: /* Search
794: ** ------
795: ** Performs a keyword search on word given by the user. Adds the keyword to
796: ** the end of the current address and attempts to open the new address.
797: **
798: ** On Entry,
799: ** *keywords space-separated keyword list or similar search list
1.2 timbl 800: ** here is anchor search is to be done on.
1.1 timbl 801: */
802:
1.2 timbl 803: PRIVATE char hex(i)
804: int i;
805: {
1.13 timbl 806: char * hexchars = "0123456789ABCDEF";
807: return hexchars[i];
1.2 timbl 808: }
1.1 timbl 809:
1.15 timbl 810: PUBLIC BOOL HTSearch ARGS3(
1.2 timbl 811: CONST char *, keywords,
1.15 timbl 812: HTParentAnchor *, here,
813: HTRequest *, request)
1.1 timbl 814: {
1.2 timbl 815:
816: #define acceptable \
817: "1234567890abcdefghijlkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_"
818:
819: char *q, *u;
820: CONST char * p, *s, *e; /* Pointers into keywords */
821: char * address = HTAnchor_address((HTAnchor*)here);
1.1 timbl 822: BOOL result;
1.2 timbl 823: char * escaped = malloc(strlen(keywords)*3+1);
824:
1.29 frystyk 825: /* static CONST BOOL isAcceptable[96] = */
826: /* static AND const is not good for a gnu compiler! Frystyk 25/02-94 */
1.30 luotonen 827: static BOOL isAcceptable[96] =
1.2 timbl 828: /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
829: { 0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,0, /* 2x !"#$%&'()*+,-./ */
830: 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */
831: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4x @ABCDEFGHIJKLMNO */
832: 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1, /* 5X PQRSTUVWXYZ[\]^_ */
833: 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6x `abcdefghijklmno */
834: 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0 }; /* 7X pqrstuvwxyz{\}~ DEL */
835:
836: if (escaped == NULL) outofmem(__FILE__, "HTSearch");
837:
1.29 frystyk 838: /* Convert spaces to + and hex escape unacceptable characters */
1.2 timbl 839:
1.29 frystyk 840: for(s=keywords; *s && WHITE(*s); s++); /*scan */ /* Skip white space */
841: for(e = s + strlen(s); e>s && WHITE(*(e-1)) ; e--); /* Skip trailers */
842: for(q=escaped, p=s; p<e; p++) { /* scan stripped field */
1.2 timbl 843: int c = (int)TOASCII(*p);
844: if (WHITE(*p)) {
845: *q++ = '+';
1.29 frystyk 846: } else if (c>=32 && c<=127 && isAcceptable[c-32] != 0) {
1.13 timbl 847: *q++ = *p; /* 930706 TBL for MVS bug */
1.2 timbl 848: } else {
849: *q++ = '%';
850: *q++ = hex(c / 16);
851: *q++ = hex(c % 16);
852: }
853: } /* Loop over string */
1.1 timbl 854:
1.2 timbl 855: *q=0;
856: /* terminate escaped sctring */
857: u=strchr(address, '?'); /* Find old search string */
858: if (u) *u = 0; /* Chop old search off */
1.1 timbl 859:
860: StrAllocCat(address, "?");
1.2 timbl 861: StrAllocCat(address, escaped);
862: free(escaped);
1.15 timbl 863: result = HTLoadRelative(address, here, request);
1.1 timbl 864: free(address);
1.2 timbl 865:
1.1 timbl 866: return result;
1.2 timbl 867: }
868:
869:
870: /* Search Given Indexname
871: ** ------
872: ** Performs a keyword search on word given by the user. Adds the keyword to
873: ** the end of the current address and attempts to open the new address.
874: **
875: ** On Entry,
876: ** *keywords space-separated keyword list or similar search list
877: ** *addres is name of object search is to be done on.
878: */
879:
1.15 timbl 880: PUBLIC BOOL HTSearchAbsolute ARGS3(
1.2 timbl 881: CONST char *, keywords,
1.15 timbl 882: CONST char *, indexname,
883: HTRequest *, request)
1.2 timbl 884: {
885: HTParentAnchor * anchor =
886: (HTParentAnchor*) HTAnchor_findAddress(indexname);
1.15 timbl 887: return HTSearch(keywords, anchor, request);
1.2 timbl 888: }
889:
890:
891: /* Generate the anchor for the home page
892: ** -------------------------------------
893: **
894: ** As it involves file access, this should only be done once
895: ** when the program first runs.
1.10 timbl 896: ** This is a default algorithm -- browser don't HAVE to use this.
897: ** But consistency betwen browsers is STRONGLY recommended!
1.2 timbl 898: **
1.10 timbl 899: ** Priority order is:
900: **
901: ** 1 WWW_HOME environment variable (logical name, etc)
902: ** 2 ~/WWW/default.html
903: ** 3 /usr/local/bin/default.html
904: ** 4 http://info.cern.ch/default.html
905: **
1.2 timbl 906: */
907: PUBLIC HTParentAnchor * HTHomeAnchor NOARGS
908: {
1.12 timbl 909: char * my_home_document = NULL;
910: char * home = (char *)getenv(LOGICAL_DEFAULT);
1.2 timbl 911: char * ref;
912: HTParentAnchor * anchor;
1.1 timbl 913:
1.12 timbl 914: if (home) {
915: StrAllocCopy(my_home_document, home);
916:
917: /* Someone telnets in, they get a special home.
918: */
919: #define MAX_FILE_NAME 1024 /* @@@ */
920: } else if (HTClientHost) { /* Telnet server */
921: FILE * fp = fopen(REMOTE_POINTER, "r");
922: char * status;
923: if (fp) {
924: my_home_document = (char*) malloc(MAX_FILE_NAME);
925: status = fgets(my_home_document, MAX_FILE_NAME, fp);
926: if (!status) {
927: free(my_home_document);
928: my_home_document = NULL;
929: }
930: fclose(fp);
931: }
932: if (!my_home_document) StrAllocCopy(my_home_document, REMOTE_ADDRESS);
933: }
934:
935:
936:
1.2 timbl 937: #ifdef unix
1.12 timbl 938:
1.10 timbl 939: if (!my_home_document) {
940: FILE * fp = NULL;
941: CONST char * home = (CONST char*)getenv("HOME");
942: if (home) {
943: my_home_document = (char *)malloc(
944: strlen(home)+1+ strlen(PERSONAL_DEFAULT)+1);
945: if (my_home_document == NULL) outofmem(__FILE__, "HTLocalName");
946: sprintf(my_home_document, "%s/%s", home, PERSONAL_DEFAULT);
947: fp = fopen(my_home_document, "r");
948: }
949:
950: if (!fp) {
951: StrAllocCopy(my_home_document, LOCAL_DEFAULT_FILE);
952: fp = fopen(my_home_document, "r");
953: }
1.2 timbl 954: if (fp) {
955: fclose(fp);
956: } else {
957: if (TRACE) fprintf(stderr,
1.10 timbl 958: "HTBrowse: No local home document ~/%s or %s\n",
959: PERSONAL_DEFAULT, LOCAL_DEFAULT_FILE);
1.11 timbl 960: free(my_home_document);
961: my_home_document = NULL;
1.2 timbl 962: }
963: }
964: #endif
1.10 timbl 965: ref = HTParse( my_home_document ? my_home_document :
966: HTClientHost ? REMOTE_ADDRESS
967: : LAST_RESORT,
968: "file:",
1.2 timbl 969: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1.10 timbl 970: if (my_home_document) {
1.2 timbl 971: if (TRACE) fprintf(stderr,
972: "HTAccess: Using custom home page %s i.e. address %s\n",
1.10 timbl 973: my_home_document, ref);
974: free(my_home_document);
1.2 timbl 975: }
976: anchor = (HTParentAnchor*) HTAnchor_findAddress(ref);
977: free(ref);
978: return anchor;
1.1 timbl 979: }
1.26 frystyk 980:
981:
982: /* Bind an Anchor to the request structure
983: ** ---------------------------------------
984: **
985: ** On Entry,
986: ** anchor The child or parenet anchor to be binded
987: ** request The request sturcture
988: ** On Exit,
989: ** returns YES Success
990: ** NO Failure
991: **
992: ** Note: Actually the same as HTLoadAnchor() but DOES NOT do the loading
993: ** Henrik Frystyk 17/02-94
994: */
995:
996: PUBLIC BOOL HTBindAnchor ARGS2(HTAnchor*, anchor, HTRequest *, request)
997: {
998: if (!anchor) return NO; /* No link */
999:
1000: request->anchor = HTAnchor_parent(anchor);
1001: request->childAnchor = ((HTAnchor*)request->anchor == anchor) ? NULL
1002: : (HTChildAnchor*) anchor;
1003:
1.29 frystyk 1004: return YES;
1.26 frystyk 1005: } /* HTBindAnchor */
1.39 luotonen 1006:
1007:
1008:
1009: /*
1010: * Error diagnostics
1011: */
1012: PUBLIC void HTAddError ARGS2(HTRequest *, req,
1.40 luotonen 1013: CONST char *, msg)
1.39 luotonen 1014: {
1015: HTAddError2(req,msg,NULL);
1016: }
1017:
1018: PUBLIC void HTAddError2 ARGS3(HTRequest *, req,
1.40 luotonen 1019: CONST char *, msg,
1020: CONST char *, param)
1.39 luotonen 1021: {
1022: int mlen = msg ? strlen(msg) : 0;
1023: int plen = param ? strlen(param) : 0;
1024: char * str;
1025:
1026: if (!req) return;
1027: if (!req->error_stack) req->error_stack = HTList_new();
1028:
1029: str = (char*)malloc(mlen + plen + 2);
1030: if (!str) outofmem(__FILE__,"HTAddError2");
1031:
1032: if (msg) strcpy(str,msg);
1033: strcpy(str+mlen," ");
1034: if (param) strcpy(str+mlen+1,param);
1035:
1036: HTList_addObject(req->error_stack, (void*)str);
1037: CTRACE(stderr, "libwww error: %s\n", str);
1038: }
1039:
1040: PUBLIC void HTAddErrorN ARGS3(HTRequest *, req,
1.40 luotonen 1041: CONST char *, msg,
1.39 luotonen 1042: int, num)
1043: {
1044: char buf[20];
1045: sprintf(buf,"%d",num);
1046: HTAddError2(req,msg,buf);
1047: }
1048:
1049: PUBLIC void HTClearErrors ARGS1(HTRequest *, req)
1050: {
1051: if (req && req->error_stack) {
1052: HTList * cur = req->error_stack;
1053: char * str;
1054: while ((str = (char*)HTList_nextObject(cur)))
1055: free(str);
1056: HTList_delete(req->error_stack);
1057: req->error_stack = NULL;
1058: }
1059: }
1.26 frystyk 1060:
Webmaster