Annotation of libwww/Library/src/HTAccess.c, revision 1.80.2.1
1.61 frystyk 1: /* HTAccess.c
2: ** ACCESS MANAGER
3: **
1.75 frystyk 4: ** (c) COPYRIGHT MIT 1995.
1.61 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
1.1 timbl 6: **
7: ** Authors
1.79 frystyk 8: ** TBL Tim Berners-Lee timbl@w3.org
1.4 timbl 9: ** JFG Jean-Francois Groff jfg@dxcern.cern.ch
1.1 timbl 10: ** DD Denis DeLaRoca (310) 825-4580 <CSP1DWD@mvs.oac.ucla.edu>
11: ** History
12: ** 8 Jun 92 Telnet hopping prohibited as telnet is not secure TBL
13: ** 26 Jun 92 When over DECnet, suppressed FTP, Gopher and News. JFG
1.42 frystyk 14: ** 6 Oct 92 Moved HTClientHost and HTlogfile into here. TBL
1.1 timbl 15: ** 17 Dec 92 Tn3270 added, bug fix. DD
1.2 timbl 16: ** 4 Feb 93 Access registration, Search escapes bad chars TBL
1.9 timbl 17: ** PARAMETERS TO HTSEARCH AND HTLOADRELATIVE CHANGED
18: ** 28 May 93 WAIS gateway explicit if no WAIS library linked in.
1.19 timbl 19: ** Dec 93 Bug change around, more reentrant, etc
1.42 frystyk 20: ** 09 May 94 logfile renamed to HTlogfile to avoid clash with WAIS
1.53 duns 21: ** 8 Jul 94 Insulate free() from _free structure element.
1.2 timbl 22: ** Bugs
23: ** This module assumes that that the graphic object is hypertext, as it
1.9 timbl 24: ** needs to select it when it has been loaded. A superclass needs to be
1.2 timbl 25: ** defined which accepts select and select_anchor.
1.1 timbl 26: */
27:
1.68 frystyk 28: #if !defined(HT_DIRECT_WAIS) && !defined(HT_DEFAULT_WAIS_GATEWAY)
29: #define HT_DEFAULT_WAIS_GATEWAY "http://www.w3.org:8001/"
1.54 frystyk 30: #endif
1.8 timbl 31:
1.67 frystyk 32: /* Library include files */
33: #include "tcp.h"
34: #include "HTUtils.h"
1.78 frystyk 35: #include "HTString.h"
1.1 timbl 36: #include "HTParse.h"
1.78 frystyk 37: #include "HTAlert.h"
38: #include "HTError.h"
1.2 timbl 39: #include "HTList.h"
1.78 frystyk 40: #include "HTAABrow.h" /* Should be HTAAUtil.html! */
1.67 frystyk 41: #include "HTFWrite.h" /* for cache stuff */
1.70 frystyk 42: #include "HTLog.h"
1.77 frystyk 43: #include "HTSocket.h"
1.57 howcome 44: #include "HTTCP.h" /* HWL: for HTFindRelatedName */
1.59 frystyk 45: #include "HTThread.h"
1.80.2.1! cbrooks 46: #include "HTEvntrg.h"
1.73 frystyk 47: #include "HTBind.h"
1.70 frystyk 48: #include "HTInit.h"
1.77 frystyk 49: #include "HTProxy.h"
1.78 frystyk 50: #include "HTML.h" /* SCW */
51: #include "HText.h" /* See bugs above */
1.74 frystyk 52:
1.67 frystyk 53: #ifndef NO_RULES
54: #include "HTRules.h"
55: #endif
1.74 frystyk 56:
1.67 frystyk 57: #include "HTAccess.h" /* Implemented here */
1.2 timbl 58:
1.54 frystyk 59: /* These flags may be set to modify the operation of this module */
1.73 frystyk 60: PUBLIC int HTMaxRedirections = 10; /* Max number of redirections */
61:
1.78 frystyk 62: PUBLIC char * HTClientHost = NULL; /* Name of remote login host if any */
1.70 frystyk 63: PUBLIC BOOL HTSecure = NO; /* Disable access for telnet users? */
1.41 luotonen 64:
1.43 luotonen 65: PUBLIC char * HTImServer = NULL;/* cern_httpd sets this to the translated URL*/
1.70 frystyk 66: PUBLIC BOOL HTImProxy = NO; /* cern_httpd as a proxy? */
1.1 timbl 67:
1.74 frystyk 68: #ifdef _WINDOWS
69: PUBLIC HWND HTsocketWin = 0 ;
70: unsigned long HTwinMsg = 0 ;
71: #endif
72:
1.78 frystyk 73: /* Variables and typedefs local to this module */
74: PRIVATE HTList * protocols = NULL; /* List of registered protocols */
75:
1.63 frystyk 76: /* Superclass defn */
1.24 timbl 77: struct _HTStream {
78: HTStreamClass * isa;
79: /* ... */
80: };
81:
1.59 frystyk 82: /* --------------------------------------------------------------------------*/
83: /* Management of the HTRequest structure */
84: /* --------------------------------------------------------------------------*/
85:
1.15 timbl 86: /* Create a request structure
87: ** ---------------------------
88: */
89: PUBLIC HTRequest * HTRequest_new NOARGS
90: {
1.28 luotonen 91: HTRequest * me = (HTRequest*) calloc(1, sizeof(*me)); /* zero fill */
1.15 timbl 92: if (!me) outofmem(__FILE__, "HTRequest_new()");
93:
1.77 frystyk 94: /* User preferences for this particular request. Only empty lists! */
95: me->conversions = HTList_new();
96: me->encodings = HTList_new();
97: me->languages = HTList_new();
98: me->charsets = HTList_new();
99:
100: /* Format of output */
1.70 frystyk 101: me->output_format = WWW_PRESENT; /* default it to present to user */
1.72 frystyk 102: me->error_format = WWW_HTML; /* default format of error messages */
1.77 frystyk 103:
104: /* HTTP headers */
105: me->GenMask = DEFAULT_GENERAL_HEADERS;
106: me->RequestMask = DEFAULT_REQUEST_HEADERS;
107: me->EntityMask = DEFAULT_ENTITY_HEADERS;
108:
109: /* Content negotiation */
110: me->ContentNegotiation = NO; /* Do this by default */
1.74 frystyk 111:
112: #ifdef _WINDOWS
113: me->hwnd = HTsocketWin;
114: me->winMsg = HTwinMsg;
115: #endif
116:
1.15 timbl 117: return me;
118: }
119:
120:
1.20 luotonen 121: /* Delete a request structure
122: ** --------------------------
123: */
124: PUBLIC void HTRequest_delete ARGS1(HTRequest *, req)
125: {
126: if (req) {
1.59 frystyk 127: FREE(req->redirect);
128: FREE(req->authenticate);
129: HTFormatDelete(req);
1.46 frystyk 130: HTErrorFree(req);
1.34 frystyk 131: HTAACleanup(req);
1.61 frystyk 132:
133: /* These are temporary until we get a MIME thingy */
134: FREE(req->redirect);
135: FREE(req->WWWAAScheme);
136: FREE(req->WWWAARealm);
137: FREE(req->WWWprotection);
138:
1.34 frystyk 139: FREE(req);
1.20 luotonen 140: }
141: }
142:
1.80 frystyk 143: /*
144: ** Add a destination request to this source request structure so that we
145: ** build the internal request representation of the POST web
146: ** Returns YES if OK, else NO
147: */
148: PUBLIC BOOL HTRequest_addDestination ARGS2(HTRequest *, src, HTRequest *, dest)
149: {
150: if (src && dest) {
151: if (!src->mainDestination) {
152: src->mainDestination = dest;
153: src->destRequests = 1;
154: return YES;
155: } else {
156: if (!src->destinations)
157: src->destinations = HTList_new();
158: if (HTList_addObject(src->destinations, (void *) dest)==YES) {
159: src->destRequests++;
160: return YES;
161: }
162: }
163: }
164: return NO;
165: }
166:
1.20 luotonen 167:
1.80 frystyk 168: /*
169: ** Remove a destination request from this source request structure
170: ** Remember not to delete the main destination as it comes from the
171: ** application!
172: ** Returns YES if OK, else NO
173: */
174: PUBLIC BOOL HTRequest_removeDestination ARGS1(HTRequest *, dest)
175: {
176: BOOL found=NO;
177: if (dest && dest->source) {
178: HTRequest *src = dest->source;
179: if (src->mainDestination == dest) {
180: dest->source = NULL;
181: src->mainDestination = NULL;
182: src->destRequests--;
183: found = YES;
184: } if (src->destinations) {
185: if (HTList_removeObject(src->destinations, (void *) dest)) {
186: HTRequest_delete(dest);
187: src->destRequests--;
188: found = YES;
189: }
190: }
191: if (found) {
192: if (TRACE)
193: fprintf(TDEST, "Destination. %p removed from %p\n",
194: dest, src);
195: }
196: if (!src->destRequests) {
197: if (TRACE)
198: fprintf(TDEST, "Destination. PostWeb terminated\n");
199: HTRequest_delete(src);
200: }
201: }
202: return found;
1.22 luotonen 203: }
204:
205:
1.80 frystyk 206: /*
207: ** Find the source request structure and make the link between the
208: ** source output stream and the destination input stream. There can be
209: ** a conversion between the two streams!
210: **
211: ** Returns YES if link is made, NO otherwise
212: */
213: PUBLIC BOOL HTRequest_linkDestination ARGS1(HTRequest *, dest)
214: {
215: if (dest && dest->input_stream && dest->source && dest!=dest->source) {
216: HTRequest *source = dest->source;
217: HTStream *pipe = HTStreamStack(source->output_format,
218: dest->input_format,
219: dest->input_stream,
220: dest, YES);
221:
222: /* Check if we are the only one - else spawn off T streams */
223:
224: /* @@@ We don't do this yet @@@ */
225:
226: source->output_stream = pipe ? pipe : dest->input_stream;
227:
228: if (STREAM_TRACE)
229: fprintf(TDEST,"Destination. Linked %p to source %p\n",dest,source);
230: if (++source->destStreams == source->destRequests) {
231: if (STREAM_TRACE)
232: fprintf(TDEST, "Destination. All destinations ready!\n");
233: if (source->net_info) /* Might already have finished */
234: HTThreadState(source->net_info->sockfd, THD_SET_READ);
235: return YES;
236: }
237: }
238: return NO;
239: }
240:
241: /*
242: ** Remove a feed stream to a destination request from this source
243: ** request structure. When all feeds are removed the request tree is
244: ** ready to take down and the operation can be terminated.
245: ** Returns YES if removed, else NO
246: */
247: PUBLIC BOOL HTRequest_unlinkDestination ARGS1(HTRequest *, dest)
248: {
249: BOOL found = NO;
250: if (dest && dest->source && dest != dest->source) {
251: HTRequest *src = dest->source;
252: if (src->mainDestination == dest) {
253: src->output_stream = NULL;
254: if (dest->input_stream)
255: (*dest->input_stream->isa->_free)(dest->input_stream);
256: found = YES;
257: } else if (src->destinations) {
258:
259: /* LOOK THROUGH THE LIST AND FIND THE RIGHT ONE */
260:
261: }
262: if (found) {
263: src->destStreams--;
264: if (STREAM_TRACE)
265: fprintf(TDEST, "Destination. Unlinked %p from source %p\n",
266: dest, src);
1.22 luotonen 267: return YES;
1.80 frystyk 268: }
1.22 luotonen 269: }
1.80 frystyk 270: return NO;
271: }
272:
273: /*
274: ** Removes all request structures in this PostWeb.
275: */
276: PUBLIC BOOL HTRequest_removePostWeb ARGS1(HTRequest *, me)
277: {
278: if (me && me->source) {
279: HTRequest *source = me->source;
280:
281: /* Kill main destination */
282: if (source->mainDestination)
283: HTRequest_removeDestination(source->mainDestination);
284:
285: /* Kill all other destinations */
286: if (source->destinations) {
287: HTList *cur = source->destinations;
288: HTRequest *pres;
289: while ((pres = (HTRequest *) HTList_nextObject(cur)) != NULL)
290: HTRequest_removeDestination(pres);
291: }
292:
293: /* Remove source request */
294: HTRequest_removeDestination(source);
295: return YES;
296: }
297: return NO;
298: }
299:
300: /*
301: ** Kills all threads in a POST WEB connected to this request but
302: ** keep the request structures.
303: ** Some requests might be preemtive, for example a SMTP request (when
304: ** that has been implemented). However, this will be handled internally
305: ** in the load function.
306: */
307: PUBLIC BOOL HTRequest_killPostWeb ARGS1(HTRequest *, me)
308: {
309: if (me && me->source) {
310: HTRequest *source = me->source;
311:
312: /* Kill main destination */
313: if (source->mainDestination)
314: HTThread_kill(source->mainDestination->net_info);
315:
316: /* Kill all other destinations */
317: if (source->destinations) {
318: HTList *cur = source->destinations;
319: HTRequest *pres;
320: while ((pres = (HTRequest *) HTList_nextObject(cur)) != NULL)
321: HTThread_kill(pres->net_info);
322: }
323: /*
324: ** Kill source. The stream tree is now freed so we have to build
325: ** that again. This is done in HTRequest_linkDestination()
326: */
327: HTThread_kill(source->net_info);
328: source->output_stream = NULL;
329: return YES;
330: }
331: return NO;
1.22 luotonen 332: }
333:
1.59 frystyk 334: /* --------------------------------------------------------------------------*/
335: /* Management of the HTProtocol structure */
336: /* --------------------------------------------------------------------------*/
1.22 luotonen 337:
1.63 frystyk 338: /*
339: ** Register a Protocol as an active access method
1.1 timbl 340: */
1.56 frystyk 341: PUBLIC BOOL HTRegisterProtocol ARGS1(HTProtocol *, protocol)
1.1 timbl 342: {
343: if (!protocols) protocols = HTList_new();
1.59 frystyk 344: HTList_addObject(protocols, (void *) protocol);
1.1 timbl 345: return YES;
346: }
347:
1.63 frystyk 348:
349: /*
350: ** Delete the list of registered access methods. This is called from
351: ** within HTLibTerminate. Written by Eric Sink, eric@spyglass.com
352: */
353: PUBLIC void HTDisposeProtocols NOARGS
354: {
355: if (protocols) {
356: HTList_delete(protocols);
357: protocols = NULL;
358: }
359: }
360:
361:
362: /*
1.65 frystyk 363: ** Is a protocol registered as BLOCKING? The default behavior registered
364: ** when the protocol module was registered can be overridden by the
365: ** BlockingIO field in the HTRequest structure
1.63 frystyk 366: */
1.59 frystyk 367: PUBLIC BOOL HTProtocolBlocking ARGS1(HTRequest *, me)
368: {
1.65 frystyk 369: if (me) {
370: return (me->BlockingIO || (me->anchor && me->anchor->protocol &&
371: ((HTProtocol *) (me->anchor->protocol))->block == SOC_BLOCK));
372: }
373: return NO;
1.59 frystyk 374: }
375:
1.61 frystyk 376: /* --------------------------------------------------------------------------*/
377: /* Initialization and Termination of the Library */
378: /* --------------------------------------------------------------------------*/
379:
380: /* HTLibInit
381: **
382: ** This function initiates the Library and it MUST be called when
383: ** starting up an application. See also HTLibTerminate()
384: */
385: PUBLIC BOOL HTLibInit NOARGS
386: {
1.67 frystyk 387: #ifdef NO_STDIO /* Open trace file */
388: if ((TDEST = fopen(TRACE_FILE, "a")) != NULL) {
389: if (setvbuf(TDEST, NULL, _IOLBF, 0) < 0) { /* Change to line buffer */
1.70 frystyk 390: printf("WWWLibInit.. Can't initialize TRACE buffer - no TRACE\n");
1.67 frystyk 391: fclose(TDEST);
392: TDEST = NULL;
393: WWW_TraceFlag = 0;
394: }
395: } else
396: WWW_TraceFlag = 0;
397: #endif
398:
1.61 frystyk 399: if (TRACE)
1.67 frystyk 400: fprintf(TDEST, "WWWLibInit.. INITIALIZING LIBRARY OF COMMON CODE\n");
1.63 frystyk 401:
1.77 frystyk 402: /* Set up User preferences, but leave initialization to the application */
1.73 frystyk 403: if (!HTConversions)
404: HTConversions = HTList_new();
1.77 frystyk 405: if (!HTEncodings)
406: HTEncodings = HTList_new();
407: if (!HTLanguages)
408: HTLanguages = HTList_new();
409: if (!HTCharsets)
410: HTCharsets = HTList_new();
411:
412: /* Set up bindings to the local file system */
413: HTBind_init();
1.73 frystyk 414:
1.70 frystyk 415: #ifndef HT_NO_INIT
416: HTAccessInit(); /* Bind access schemes and protocol modules */
417: HTFileInit(); /* Bind file extensions and media types */
1.63 frystyk 418: #endif
1.61 frystyk 419:
1.77 frystyk 420: #ifndef HT_DIRECT_WAIS
421: HTProxy_setGateway("wais", HT_DEFAULT_WAIS_GATEWAY);
422: #endif
423:
1.62 frystyk 424: #ifdef WWWLIB_SIG
1.61 frystyk 425: /* On Solaris (and others?) we get a BROKEN PIPE signal when connecting
1.67 frystyk 426: ** to a port where we should get `connection refused'. We ignore this
1.61 frystyk 427: ** using the following function call
428: */
429: HTSetSignal(); /* Set signals in library */
1.1 timbl 430: #endif
431:
1.67 frystyk 432: #ifdef _WINDOWS
433: /*
434: ** Initialise WinSock DLL. This must also be shut down! PMH
435: */
436: {
437: WSADATA wsadata;
438: if (WSAStartup(DESIRED_WINSOCK_VERSION, &wsadata)) {
439: if (TRACE)
440: fprintf(TDEST, "WWWLibInit.. Can't initialize WinSoc\n");
441: WSACleanup();
442: return NO;
443: }
444: if (wsadata.wVersion < MINIMUM_WINSOCK_VERSION) {
445: if (TRACE)
446: fprintf(TDEST, "WWWLibInit.. Bad version of WinSoc\n");
447: WSACleanup();
448: return NO;
449: }
450: }
451: #endif /* _WINDOWS */
452:
1.71 frystyk 453: #ifndef NO_TIMEGM
454: HTGetTimeZoneOffset(); /* Find offset from GMT if using mktime() */
455: #endif
1.70 frystyk 456: HTTmp_setRoot(NULL); /* Set up default tmp directory */
1.61 frystyk 457: HTThreadInit(); /* Initialize bit arrays */
458: return YES;
459: }
460:
461:
462: /* HTLibTerminate
463: **
464: ** This function frees memory kept by the Library and should be called
1.63 frystyk 465: ** before exit of an application (if you are on a PC platform)
1.61 frystyk 466: */
467: PUBLIC BOOL HTLibTerminate NOARGS
468: {
469: if (TRACE)
1.67 frystyk 470: fprintf(TDEST, "WWWLibTerm.. Cleaning up LIBRARY OF COMMON CODE\n");
1.63 frystyk 471: HTAtom_deleteAll();
472: HTDisposeConversions();
473: HTTCPCacheRemoveAll();
1.73 frystyk 474:
475: #ifndef HT_NO_INIT
476: HTDisposeProtocols(); /* Remove bindings between access and protocols */
477: HTBind_deleteAll(); /* Remove bindings between suffixes, media types */
478: #endif
479:
1.77 frystyk 480: HTProxy_deleteProxy(); /* Clean up lists of proxies and gateways */
481: HTProxy_deleteNoProxy();
482: HTProxy_deleteGateway();
483:
484: HTFreeHostName(); /* Free up some internal strings */
1.63 frystyk 485: HTFreeMailAddress();
1.70 frystyk 486: HTCache_freeRoot();
487: HTTmp_freeRoot();
1.67 frystyk 488:
489: #ifdef _WINDOWS
490: WSACleanup();
491: #endif
492:
493: #ifdef NO_STDIO /* Close trace file */
494: if (TDEST) {
495: fclose(TDEST);
496: TDEST = NULL;
497: WWW_TraceFlag = 0;
498: }
499: #endif
1.61 frystyk 500: return YES;
501: }
502:
1.59 frystyk 503: /* --------------------------------------------------------------------------*/
504: /* Physical Anchor Address Manager */
505: /* --------------------------------------------------------------------------*/
1.33 luotonen 506:
1.77 frystyk 507: #ifdef OLD_CODE
1.33 luotonen 508: /* override_proxy()
509: **
510: ** Check the no_proxy environment variable to get the list
511: ** of hosts for which proxy server is not consulted.
512: **
513: ** no_proxy is a comma- or space-separated list of machine
514: ** or domain names, with optional :port part. If no :port
515: ** part is present, it applies to all ports on that domain.
516: **
517: ** Example:
518: ** no_proxy="cern.ch,some.domain:8001"
519: **
520: */
521: PRIVATE BOOL override_proxy ARGS1(CONST char *, addr)
522: {
523: CONST char * no_proxy = getenv("no_proxy");
524: char * p = NULL;
525: char * host = NULL;
526: int port = 0;
527: int h_len = 0;
528:
529: if (!no_proxy || !addr || !(host = HTParse(addr, "", PARSE_HOST)))
530: return NO;
531: if (!*host) { free(host); return NO; }
532:
1.34 frystyk 533: if ((p = strchr(host, ':')) != NULL) { /* Port specified */
1.33 luotonen 534: *p++ = 0; /* Chop off port */
535: port = atoi(p);
536: }
537: else { /* Use default port */
538: char * access = HTParse(addr, "", PARSE_ACCESS);
539: if (access) {
540: if (!strcmp(access,"http")) port = 80;
541: else if (!strcmp(access,"gopher")) port = 70;
542: else if (!strcmp(access,"ftp")) port = 21;
543: free(access);
544: }
545: }
546: if (!port) port = 80; /* Default */
547: h_len = strlen(host);
548:
549: while (*no_proxy) {
550: CONST char * end;
551: CONST char * colon = NULL;
552: int templ_port = 0;
553: int t_len;
554:
555: while (*no_proxy && (WHITE(*no_proxy) || *no_proxy==','))
556: no_proxy++; /* Skip whitespace and separators */
557:
558: end = no_proxy;
559: while (*end && !WHITE(*end) && *end != ',') { /* Find separator */
560: if (*end==':') colon = end; /* Port number given */
561: end++;
562: }
563:
564: if (colon) {
565: templ_port = atoi(colon+1);
566: t_len = colon - no_proxy;
567: }
568: else {
569: t_len = end - no_proxy;
570: }
571:
572: if ((!templ_port || templ_port == port) &&
573: (t_len > 0 && t_len <= h_len &&
574: !strncmp(host + h_len - t_len, no_proxy, t_len))) {
575: free(host);
576: return YES;
577: }
578: if (*end) no_proxy = end+1;
579: else break;
580: }
581:
582: free(host);
583: return NO;
584: }
1.77 frystyk 585: #endif /* OLD_CODE */
1.33 luotonen 586:
587:
1.2 timbl 588: /* Find physical name and access protocol
589: ** --------------------------------------
1.1 timbl 590: **
591: **
592: ** On entry,
593: ** addr must point to the fully qualified hypertext reference.
594: ** anchor a pareent anchor with whose address is addr
595: **
1.59 frystyk 596: ** On exit,
597: ** returns HT_NO_ACCESS no protocol module found
598: ** HT_FORBIDDEN Error has occured.
1.2 timbl 599: ** HT_OK Success
1.1 timbl 600: **
601: */
1.21 luotonen 602: PRIVATE int get_physical ARGS1(HTRequest *, req)
603: {
604: char * addr = HTAnchor_address((HTAnchor*)req->anchor); /* free me */
1.27 luotonen 605:
1.70 frystyk 606: #ifndef HT_NO_RULES
1.47 luotonen 607: if (HTImServer) { /* cern_httpd has already done its own translations */
1.45 luotonen 608: HTAnchor_setPhysical(req->anchor, HTImServer);
1.47 luotonen 609: StrAllocCopy(addr, HTImServer); /* Oops, queries thru many proxies */
610: /* didn't work without this -- AL */
611: }
1.21 luotonen 612: else {
1.27 luotonen 613: char * physical = HTTranslate(addr);
1.21 luotonen 614: if (!physical) {
1.47 luotonen 615: free(addr);
1.21 luotonen 616: return HT_FORBIDDEN;
617: }
618: HTAnchor_setPhysical(req->anchor, physical);
619: free(physical); /* free our copy */
1.2 timbl 620: }
621: #else
1.21 luotonen 622: HTAnchor_setPhysical(req->anchor, addr);
1.70 frystyk 623: #endif /* HT_NO_RULES */
1.2 timbl 624:
1.77 frystyk 625: #ifdef OLDCODE
1.21 luotonen 626: access = HTParse(HTAnchor_physical(req->anchor),
1.27 luotonen 627: "file:", PARSE_ACCESS);
1.1 timbl 628:
1.77 frystyk 629: if (!override_proxy(addr)) {
1.39 luotonen 630: /* make sure the using_proxy variable is false */
1.70 frystyk 631: req->using_proxy = NO;
1.39 luotonen 632:
1.27 luotonen 633: char * gateway_parameter, *gateway, *proxy;
634:
1.2 timbl 635: gateway_parameter = (char *)malloc(strlen(access)+20);
636: if (gateway_parameter == NULL) outofmem(__FILE__, "HTLoad");
1.27 luotonen 637:
638: /* search for proxy gateways */
1.2 timbl 639: strcpy(gateway_parameter, "WWW_");
640: strcat(gateway_parameter, access);
641: strcat(gateway_parameter, "_GATEWAY");
642: gateway = (char *)getenv(gateway_parameter); /* coerce for decstation */
1.27 luotonen 643:
644: /* search for proxy servers */
645: strcpy(gateway_parameter, access);
646: strcat(gateway_parameter, "_proxy");
647: proxy = (char *)getenv(gateway_parameter);
648:
1.2 timbl 649: free(gateway_parameter);
1.27 luotonen 650:
1.68 frystyk 651: #ifndef HT_DIRECT_WAIS
1.9 timbl 652: if (!gateway && 0==strcmp(access, "wais")) {
1.69 frystyk 653: gateway = HT_DEFAULT_WAIS_GATEWAY;
1.8 timbl 654: }
655: #endif
1.27 luotonen 656:
1.70 frystyk 657: if (TRACE && gateway)
658: fprintf(TDEST,"Gateway..... Found: `%s\'\n", gateway);
659: if (TRACE && proxy)
660: fprintf(TDEST,"Proxy....... Found: `%s\'\n", proxy);
1.77 frystyk 661: #endif /* OLD_CODE */
1.70 frystyk 662:
1.77 frystyk 663: /*
664: ** Check whether gateway or proxy access has been set up for this url
665: */
666: {
667: char *proxy = HTProxy_getProxy(addr);
668: char *gateway = HTProxy_getGateway(addr);
1.27 luotonen 669:
1.77 frystyk 670: /* Proxy servers have precedence over gateway servers */
671: if (proxy) {
672: StrAllocCat(proxy, addr);
1.70 frystyk 673: req->using_proxy = YES;
1.77 frystyk 674: HTAnchor_setPhysical(req->anchor, proxy);
675: free(proxy);
676: } else if (gateway) {
1.9 timbl 677: char * path = HTParse(addr, "",
1.77 frystyk 678: PARSE_HOST + PARSE_PATH + PARSE_PUNCTUATION);
1.9 timbl 679: /* Chop leading / off to make host into part of path */
680: char * gatewayed = HTParse(path+1, gateway, PARSE_ALL);
1.77 frystyk 681: HTAnchor_setPhysical(req->anchor, gatewayed);
1.9 timbl 682: free(path);
683: free(gatewayed);
1.77 frystyk 684: free(gateway);
685: } else {
686: req->using_proxy = NO; /* We don't use proxy or gateway */
1.2 timbl 687: }
688: }
1.77 frystyk 689: FREE(addr);
1.1 timbl 690:
1.77 frystyk 691: /*
692: ** Search registered protocols to find suitable one
693: */
1.1 timbl 694: {
1.77 frystyk 695: char *access = HTParse(HTAnchor_physical(req->anchor),"",PARSE_ACCESS);
1.61 frystyk 696: HTList *cur = protocols;
1.20 luotonen 697: HTProtocol *p;
1.61 frystyk 698: if (!cur) {
699: if (TRACE)
1.67 frystyk 700: fprintf(TDEST, "HTAccess.... NO PROTOCOL MODULES INITIATED\n");
1.61 frystyk 701: } else {
702: while ((p = (HTProtocol*)HTList_nextObject(cur))) {
1.77 frystyk 703: if (strcmp(p->name, access)==0) { /* Case insensitive? */
1.61 frystyk 704: HTAnchor_setProtocol(req->anchor, p);
705: free(access);
706: return (HT_OK);
707: }
1.1 timbl 708: }
709: }
1.77 frystyk 710: free(access);
1.1 timbl 711: }
1.2 timbl 712: return HT_NO_ACCESS;
1.1 timbl 713: }
714:
1.59 frystyk 715: /* --------------------------------------------------------------------------*/
716: /* Document Loader */
717: /* --------------------------------------------------------------------------*/
1.1 timbl 718:
719: /* Load a document
720: ** ---------------
721: **
1.2 timbl 722: ** This is an internal routine, which has an address AND a matching
723: ** anchor. (The public routines are called with one OR the other.)
724: **
725: ** On entry,
1.15 timbl 726: ** request->
1.35 luotonen 727: ** anchor a parent anchor with fully qualified
728: ** hypertext reference as its address set
1.15 timbl 729: ** output_format valid
730: ** output_stream valid on NULL
1.2 timbl 731: **
732: ** On exit,
1.59 frystyk 733: ** returns HT_WOULD_BLOCK An I/O operation would block
734: ** HT_ERROR Error has occured
1.2 timbl 735: ** HT_LOADED Success
736: ** HT_NO_DATA Success, but no document loaded.
1.8 timbl 737: ** (telnet sesssion started etc)
1.72 frystyk 738: ** HT_RETRY if service isn't available before
739: ** request->retry_after
1.2 timbl 740: */
1.52 frystyk 741: PUBLIC int HTLoad ARGS2(HTRequest *, request, BOOL, keep_error_stack)
1.2 timbl 742: {
1.25 frystyk 743: char *arg = NULL;
744: HTProtocol *p;
745: int status;
746:
1.22 luotonen 747: if (request->method == METHOD_INVALID)
748: request->method = METHOD_GET;
1.52 frystyk 749: if (!keep_error_stack) {
750: HTErrorFree(request);
751: request->error_block = NO;
752: }
753:
1.59 frystyk 754: if ((status = get_physical(request)) < 0) {
755: if (status == HT_FORBIDDEN) {
756: char *url = HTAnchor_address((HTAnchor *) request->anchor);
757: if (url) {
758: HTUnEscape(url);
759: HTErrorAdd(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
760: (void *) url, (int) strlen(url), "HTLoad");
761: free(url);
762: } else {
763: HTErrorAdd(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
764: NULL, 0, "HTLoad");
765: }
766: }
767: return HT_ERROR; /* Can't resolve or forbidden */
1.2 timbl 768: }
1.25 frystyk 769:
770: if(!(arg = HTAnchor_physical(request->anchor)) || !*arg)
1.59 frystyk 771: return HT_ERROR;
1.27 luotonen 772:
1.56 frystyk 773: p = (HTProtocol *) HTAnchor_protocol(request->anchor);
1.17 timbl 774: return (*(p->load))(request);
1.2 timbl 775: }
776:
777:
1.61 frystyk 778: /* Terminate a LOAD
779: ** ----------------
780: **
781: ** This function looks at the status code from the HTLoadDocument
782: ** function and updates logfiles, creates error messages etc.
783: **
784: ** On Entry,
785: ** Status code from load function
786: */
787: PUBLIC BOOL HTLoadTerminate ARGS2(HTRequest *, request, int, status)
788: {
789: char * uri = HTAnchor_address((HTAnchor*)request->anchor);
790:
1.70 frystyk 791: HTLog_request(request);
1.61 frystyk 792:
793: /* The error stack might contain general information to the client
794: about what has been going on in the library (not only errors) */
795: if (!HTImProxy && request->error_stack)
796: HTErrorMsg(request);
797:
798: switch (status) {
799: case HT_LOADED:
800: if (PROT_TRACE) {
1.72 frystyk 801: fprintf(TDEST, "HTAccess.... OK: `%s\' has been accessed.\n", uri);
1.61 frystyk 802: }
803: break;
804:
1.78 frystyk 805: case HT_OK:
806: if (PROT_TRACE) {
1.80 frystyk 807: fprintf(TDEST,"HTAccess.... FRIEND FINISHED ACCESS: `%s\'\n",uri);
1.78 frystyk 808: }
809: break;
810:
1.61 frystyk 811: case HT_NO_DATA:
812: if (PROT_TRACE) {
1.72 frystyk 813: fprintf(TDEST, "HTAccess.... OK BUT NO DATA: `%s\'\n", uri);
1.61 frystyk 814: }
815: break;
816:
817: case HT_WOULD_BLOCK:
818: if (PROT_TRACE) {
1.72 frystyk 819: fprintf(TDEST, "HTAccess.... WOULD BLOCK: `%s\'\n", uri);
820: }
821: break;
822:
823: case HT_RETRY:
824: if (PROT_TRACE) {
825: fprintf(TDEST, "HTAccess.... NOT AVAILABLE, RETRY AT `%s\'\n",uri);
1.61 frystyk 826: }
827: break;
828:
829: case HT_ERROR:
830: if (HTImProxy)
831: HTErrorMsg(request); /* Only on a real error */
832: if (PROT_TRACE) {
1.72 frystyk 833: fprintf(TDEST, "HTAccess.... ERROR: Can't access `%s\'\n", uri);
1.61 frystyk 834: }
835: break;
836:
837: default:
838: if (PROT_TRACE) {
1.67 frystyk 839: fprintf(TDEST, "HTAccess.... **** Internal software error in CERN WWWLib version %s ****\n", HTLibraryVersion);
1.79 frystyk 840: fprintf(TDEST, "............ Please mail libwww@w3.org quoting what software\n");
1.67 frystyk 841: fprintf(TDEST, "............ and version you are using including the URL:\n");
842: fprintf(TDEST, "............ `%s\'\n", uri);
843: fprintf(TDEST, "............ that caused the problem, thanks!\n");
1.61 frystyk 844: }
845: break;
846: }
847: free(uri);
848: return YES;
849: }
850:
851:
1.2 timbl 852: /* Load a document - with logging etc
853: ** ----------------------------------
854: **
855: ** - Checks or documents already loaded
856: ** - Logs the access
857: ** - Trace ouput and error messages
858: **
1.1 timbl 859: ** On Entry,
1.19 timbl 860: ** request->anchor valid for of the document to be accessed.
861: ** request->childAnchor optional anchor within doc to be selected
862: **
1.15 timbl 863: ** request->anchor is the node_anchor for the document
864: ** request->output_format is valid
865: **
1.59 frystyk 866: ** On exit,
867: ** returns HT_WOULD_BLOCK An I/O operation would block
868: ** HT_ERROR Error has occured
869: ** HT_LOADED Success
870: ** HT_NO_DATA Success, but no document loaded.
871: ** (telnet sesssion started etc)
1.72 frystyk 872: ** HT_RETRY if service isn't available before
873: ** request->retry_after
1.1 timbl 874: */
1.59 frystyk 875: PRIVATE int HTLoadDocument ARGS2(HTRequest *, request,
876: BOOL, keep_error_stack)
1.1 timbl 877:
878: {
879: int status;
880: HText * text;
1.19 timbl 881: char * full_address = HTAnchor_address((HTAnchor*)request->anchor);
1.54 frystyk 882:
1.80 frystyk 883: if (PROT_TRACE) fprintf (TDEST, "HTAccess.... Accessing document %s\n",
1.59 frystyk 884: full_address);
1.1 timbl 885:
1.18 timbl 886: request->using_cache = NULL;
887:
1.15 timbl 888: if (!request->output_format) request->output_format = WWW_PRESENT;
1.25 frystyk 889:
1.67 frystyk 890: /* Check if document is already loaded or in cache */
1.70 frystyk 891: if (!request->ForceReload) {
1.67 frystyk 892: if ((text=(HText *)HTAnchor_document(request->anchor))) {
893: if (PROT_TRACE)
894: fprintf(TDEST, "HTAccess.... Document already in memory.\n");
895: if (request->childAnchor) {
896: HText_selectAnchor(text, request->childAnchor);
897: } else {
1.80 frystyk 898: HText_select(text);
1.67 frystyk 899: }
900: free(full_address);
901: return HT_LOADED;
1.19 timbl 902: }
1.67 frystyk 903:
904: /* Check the Cache */
905: /* Bug: for each format, we only check whether it is ok, we
906: don't check them all and chose the best */
907: if (request->anchor->cacheItems) {
908: HTList * list = request->anchor->cacheItems;
909: HTList * cur = list;
910: HTCacheItem * item;
911: while ((item = (HTCacheItem*)HTList_nextObject(cur))) {
912: HTStream * s;
913: request->using_cache = item;
914: s = HTStreamStack(item->format, request->output_format,
915: request->output_stream, request, NO);
916: if (s) { /* format was suitable */
917: FILE * fp = fopen(item->filename, "r");
918: if (PROT_TRACE)
1.70 frystyk 919: fprintf(TDEST, "Cache....... HIT file %s for %s\n",
1.67 frystyk 920: item->filename,
921: full_address);
922: if (fp) {
923: HTFileCopy(fp, s);
924: (*s->isa->_free)(s); /* close up pipeline */
925: fclose(fp);
926: free(full_address);
927: return HT_LOADED;
928: } else {
929: fprintf(TDEST, "***** Can't read cache file %s !\n",
930: item->filename);
931: } /* file open ok */
932: } /* stream ok */
933: } /* next cache item */
934: } /* if cache available for this anchor */
1.70 frystyk 935: } else { /* Make sure that we don't use old headers */
936: HTAnchor_clearHeader(request->anchor);
1.77 frystyk 937: request->RequestMask += HT_PRAGMA; /* Force reload through proxy */
1.1 timbl 938: }
1.61 frystyk 939: if ((status = HTLoad(request, keep_error_stack)) != HT_WOULD_BLOCK)
940: HTLoadTerminate(request, status);
1.19 timbl 941: free(full_address);
1.59 frystyk 942: return status;
1.58 frystyk 943: }
1.1 timbl 944:
945:
946: /* Load a document from absolute name
947: ** ---------------
948: **
1.59 frystyk 949: ** On Entry,
1.1 timbl 950: ** addr The absolute address of the document to be accessed.
951: **
1.59 frystyk 952: ** On exit,
953: ** returns HT_WOULD_BLOCK An I/O operation would block
954: ** HT_ERROR Error has occured
955: ** HT_LOADED Success
956: ** HT_NO_DATA Success, but no document loaded.
957: ** (telnet sesssion started etc)
1.72 frystyk 958: ** HT_RETRY if service isn't available before
959: ** request->retry_after
1.1 timbl 960: */
1.59 frystyk 961: PUBLIC int HTLoadAbsolute ARGS2(CONST char *,addr, HTRequest*, request)
1.2 timbl 962: {
1.19 timbl 963: HTAnchor * anchor = HTAnchor_findAddress(addr);
964: request->anchor = HTAnchor_parent(anchor);
965: request->childAnchor = ((HTAnchor*)request->anchor == anchor) ?
966: NULL : (HTChildAnchor*) anchor;
1.52 frystyk 967: return HTLoadDocument(request, NO);
1.2 timbl 968: }
969:
970:
971: /* Load a document from absolute name to stream
972: ** --------------------------------------------
973: **
1.59 frystyk 974: ** On Entry,
1.2 timbl 975: ** addr The absolute address of the document to be accessed.
1.15 timbl 976: ** request->output_stream if non-NULL, send data down this stream
1.2 timbl 977: **
1.59 frystyk 978: ** On exit,
979: ** returns HT_WOULD_BLOCK An I/O operation would block
980: ** HT_ERROR Error has occured
981: ** HT_LOADED Success
982: ** HT_NO_DATA Success, but no document loaded.
983: ** (telnet sesssion started etc)
1.72 frystyk 984: ** HT_RETRY if service isn't available before
985: ** request->retry_after
1.2 timbl 986: */
1.59 frystyk 987: PUBLIC int HTLoadToStream ARGS3(CONST char *, addr,
988: BOOL, filter,
989: HTRequest*, request)
1.1 timbl 990: {
1.63 frystyk 991: HTAnchor * anchor = HTAnchor_findAddress(addr);
992: request->anchor = HTAnchor_parent(anchor);
993: request->childAnchor = ((HTAnchor*)request->anchor == anchor) ? NULL :
1.19 timbl 994: (HTChildAnchor*) anchor;
1.15 timbl 995: request->output_stream = request->output_stream;
1.52 frystyk 996: return HTLoadDocument(request, NO);
1.1 timbl 997: }
998:
999:
1000: /* Load a document from relative name
1001: ** ---------------
1002: **
1.59 frystyk 1003: ** On Entry,
1.2 timbl 1004: ** relative_name The relative address of the document
1005: ** to be accessed.
1.1 timbl 1006: **
1.59 frystyk 1007: ** On exit,
1008: ** returns HT_WOULD_BLOCK An I/O operation would block
1009: ** HT_ERROR Error has occured
1010: ** HT_LOADED Success
1011: ** HT_NO_DATA Success, but no document loaded.
1012: ** (telnet sesssion started etc)
1.72 frystyk 1013: ** HT_RETRY if service isn't available before
1014: ** request->retry_after
1.1 timbl 1015: */
1.59 frystyk 1016: PUBLIC int HTLoadRelative ARGS3(CONST char *, relative_name,
1017: HTParentAnchor *, here,
1018: HTRequest *, request)
1.1 timbl 1019: {
1020: char * full_address = 0;
1.65 frystyk 1021: int result;
1.1 timbl 1022: char * mycopy = 0;
1023: char * stripped = 0;
1024: char * current_address =
1.2 timbl 1025: HTAnchor_address((HTAnchor*)here);
1.1 timbl 1026:
1027: StrAllocCopy(mycopy, relative_name);
1028:
1029: stripped = HTStrip(mycopy);
1030: full_address = HTParse(stripped,
1031: current_address,
1032: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1.15 timbl 1033: result = HTLoadAbsolute(full_address, request);
1.1 timbl 1034: free(full_address);
1035: free(current_address);
1036: free(mycopy); /* Memory leak fixed 10/7/92 -- JFG */
1037: return result;
1038: }
1039:
1040:
1041: /* Load if necessary, and select an anchor
1042: ** --------------------------------------
1043: **
1.59 frystyk 1044: ** On Entry,
1.1 timbl 1045: ** destination The child or parenet anchor to be loaded.
1046: **
1.59 frystyk 1047: ** On exit,
1048: ** returns HT_WOULD_BLOCK An I/O operation would block
1049: ** HT_ERROR Error has occured
1050: ** HT_LOADED Success
1051: ** HT_NO_DATA Success, but no document loaded.
1052: ** (telnet sesssion started etc)
1.72 frystyk 1053: ** HT_RETRY if service isn't available before
1054: ** request->retry_after
1.1 timbl 1055: */
1.59 frystyk 1056: PUBLIC int HTLoadAnchor ARGS2(HTAnchor*, anchor, HTRequest *, request)
1.1 timbl 1057: {
1.70 frystyk 1058: if (!anchor || !request)
1059: return HT_ERROR;
1060: request->anchor = HTAnchor_parent(anchor);
1.59 frystyk 1061: request->childAnchor = ((HTAnchor *) request->anchor == anchor) ?
1062: NULL : (HTChildAnchor*) anchor;
1063: return HTLoadDocument(request, NO);
1064: }
1.52 frystyk 1065:
1066:
1067: /* Load if necessary, and select an anchor
1068: ** --------------------------------------
1069: **
1070: ** This function is almost identical to HTLoadAnchor, but it doesn't
1071: ** clear the error stack so that the information in there is kept.
1072: **
1.59 frystyk 1073: ** On Entry,
1.52 frystyk 1074: ** destination The child or parenet anchor to be loaded.
1075: **
1.59 frystyk 1076: ** On exit,
1077: ** returns HT_WOULD_BLOCK An I/O operation would block
1078: ** HT_ERROR Error has occured
1079: ** HT_LOADED Success
1080: ** HT_NO_DATA Success, but no document loaded.
1081: ** (telnet sesssion started etc)
1.72 frystyk 1082: ** HT_RETRY if service isn't available before
1083: ** request->retry_after
1.52 frystyk 1084: */
1.59 frystyk 1085: PUBLIC int HTLoadAnchorRecursive ARGS2(HTAnchor*, anchor,
1086: HTRequest *, request)
1.52 frystyk 1087: {
1.59 frystyk 1088: if (!anchor) return HT_ERROR; /* No link */
1.52 frystyk 1089:
1090: request->anchor = HTAnchor_parent(anchor);
1.59 frystyk 1091: request->childAnchor = ((HTAnchor *) request->anchor == anchor) ?
1092: NULL : (HTChildAnchor*) anchor;
1.52 frystyk 1093:
1.59 frystyk 1094: return HTLoadDocument(request, YES);
1095: }
1.1 timbl 1096:
1097:
1098: /* Search
1099: ** ------
1100: ** Performs a keyword search on word given by the user. Adds the keyword to
1101: ** the end of the current address and attempts to open the new address.
1102: **
1103: ** On Entry,
1104: ** *keywords space-separated keyword list or similar search list
1.2 timbl 1105: ** here is anchor search is to be done on.
1.59 frystyk 1106: **
1107: ** On exit,
1108: ** returns HT_WOULD_BLOCK An I/O operation would block
1109: ** HT_ERROR Error has occured
1110: ** HT_LOADED Success
1111: ** HT_NO_DATA Success, but no document loaded.
1112: ** (telnet sesssion started etc)
1.72 frystyk 1113: ** HT_RETRY if service isn't available before
1114: ** request->retry_after
1.1 timbl 1115: */
1.56 frystyk 1116: PRIVATE char hex ARGS1(int, i)
1.2 timbl 1117: {
1.13 timbl 1118: char * hexchars = "0123456789ABCDEF";
1119: return hexchars[i];
1.2 timbl 1120: }
1.1 timbl 1121:
1.59 frystyk 1122: PUBLIC int HTSearch ARGS3(CONST char *, keywords,
1123: HTParentAnchor *, here,
1124: HTRequest *, request)
1.1 timbl 1125: {
1.2 timbl 1126:
1127: #define acceptable \
1128: "1234567890abcdefghijlkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_"
1129:
1130: char *q, *u;
1131: CONST char * p, *s, *e; /* Pointers into keywords */
1132: char * address = HTAnchor_address((HTAnchor*)here);
1.65 frystyk 1133: int result;
1.56 frystyk 1134: char * escaped = (char *) malloc(strlen(keywords)*3+1);
1.2 timbl 1135:
1.29 frystyk 1136: /* static CONST BOOL isAcceptable[96] = */
1137: /* static AND const is not good for a gnu compiler! Frystyk 25/02-94 */
1.30 luotonen 1138: static BOOL isAcceptable[96] =
1.2 timbl 1139: /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
1140: { 0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,0, /* 2x !"#$%&'()*+,-./ */
1141: 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */
1142: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4x @ABCDEFGHIJKLMNO */
1143: 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1, /* 5X PQRSTUVWXYZ[\]^_ */
1144: 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6x `abcdefghijklmno */
1145: 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0 }; /* 7X pqrstuvwxyz{\}~ DEL */
1146:
1147: if (escaped == NULL) outofmem(__FILE__, "HTSearch");
1148:
1.29 frystyk 1149: /* Convert spaces to + and hex escape unacceptable characters */
1.2 timbl 1150:
1.29 frystyk 1151: for(s=keywords; *s && WHITE(*s); s++); /*scan */ /* Skip white space */
1152: for(e = s + strlen(s); e>s && WHITE(*(e-1)) ; e--); /* Skip trailers */
1153: for(q=escaped, p=s; p<e; p++) { /* scan stripped field */
1.2 timbl 1154: int c = (int)TOASCII(*p);
1155: if (WHITE(*p)) {
1156: *q++ = '+';
1.29 frystyk 1157: } else if (c>=32 && c<=127 && isAcceptable[c-32] != 0) {
1.13 timbl 1158: *q++ = *p; /* 930706 TBL for MVS bug */
1.2 timbl 1159: } else {
1160: *q++ = '%';
1161: *q++ = hex(c / 16);
1162: *q++ = hex(c % 16);
1163: }
1164: } /* Loop over string */
1.1 timbl 1165:
1.2 timbl 1166: *q=0;
1167: /* terminate escaped sctring */
1168: u=strchr(address, '?'); /* Find old search string */
1169: if (u) *u = 0; /* Chop old search off */
1.1 timbl 1170:
1171: StrAllocCat(address, "?");
1.2 timbl 1172: StrAllocCat(address, escaped);
1173: free(escaped);
1.15 timbl 1174: result = HTLoadRelative(address, here, request);
1.1 timbl 1175: free(address);
1.2 timbl 1176:
1.1 timbl 1177: return result;
1.2 timbl 1178: }
1179:
1180:
1181: /* Search Given Indexname
1182: ** ------
1183: ** Performs a keyword search on word given by the user. Adds the keyword to
1184: ** the end of the current address and attempts to open the new address.
1185: **
1.59 frystyk 1186: ** On Entry,
1.2 timbl 1187: ** *keywords space-separated keyword list or similar search list
1188: ** *addres is name of object search is to be done on.
1.59 frystyk 1189: ** On exit,
1190: ** returns HT_WOULD_BLOCK An I/O operation would block
1191: ** HT_ERROR Error has occured
1192: ** HT_LOADED Success
1193: ** HT_NO_DATA Success, but no document loaded.
1194: ** (telnet sesssion started etc)
1.72 frystyk 1195: ** HT_RETRY if service isn't available before
1196: ** request->retry_after
1.2 timbl 1197: */
1.59 frystyk 1198: PUBLIC int HTSearchAbsolute ARGS3(CONST char *, keywords,
1199: CONST char *, indexname,
1200: HTRequest *, request)
1.2 timbl 1201: {
1202: HTParentAnchor * anchor =
1203: (HTParentAnchor*) HTAnchor_findAddress(indexname);
1.15 timbl 1204: return HTSearch(keywords, anchor, request);
1.57 howcome 1205: }
1206:
1.70 frystyk 1207: /* --------------------------------------------------------------------------*/
1208: /* Document Poster */
1209: /* --------------------------------------------------------------------------*/
1210:
1211: /* Get a save stream for a document
1212: ** --------------------------------
1213: */
1214: PUBLIC HTStream *HTSaveStream ARGS1(HTRequest *, request)
1215: {
1216: HTProtocol * p;
1217: int status;
1218: request->method = METHOD_PUT;
1219: status = get_physical(request);
1220: if (status == HT_FORBIDDEN) {
1221: char *url = HTAnchor_address((HTAnchor *) request->anchor);
1222: if (url) {
1223: HTUnEscape(url);
1224: HTErrorAdd(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
1225: (void *) url, (int) strlen(url), "HTLoad");
1226: free(url);
1227: } else {
1228: HTErrorAdd(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
1229: NULL, 0, "HTLoad");
1230: }
1231: return NULL; /* should return error status? */
1232: }
1233: if (status < 0) return NULL; /* @@ error. Can't resolve or forbidden */
1234:
1235: p = (HTProtocol *) HTAnchor_protocol(request->anchor);
1236: if (!p) return NULL;
1237:
1238: return (*p->saveStream)(request);
1239:
1240: }
1241:
1242: /* COPY AN ANCHOR
1243: ** --------------
1244: ** Fetch the URL (possibly local file URL) and send it using either PUT
1245: ** or POST to the remote destination using HTTP. The caller can decide the
1246: ** exact method used and which HTTP header fields to transmit by setting the
1247: ** user fields in the request structure.
1248: **
1.80 frystyk 1249: ** BUGS: Should take ALL links in the destination anchor and PUT/POST to
1250: ** all of them!
1251: **
1.70 frystyk 1252: ** returns HT_WOULD_BLOCK An I/O operation would block
1253: ** HT_ERROR Error has occured
1254: ** HT_LOADED Success
1255: ** HT_NO_DATA Success, but no document loaded.
1.72 frystyk 1256: ** HT_RETRY if service isn't available before
1257: ** request->retry_after
1.70 frystyk 1258: */
1.80 frystyk 1259: PUBLIC int HTCopyAnchor ARGS2(HTAnchor *, src_anchor,
1260: HTRequest *, main_dest)
1261: {
1.78 frystyk 1262: HTRequest *src_req;
1.80 frystyk 1263: if (!src_anchor || !main_dest)
1.70 frystyk 1264: return HT_ERROR;
1265:
1.80 frystyk 1266: /* Build the POST web if not already there */
1267: if (!main_dest->source) {
1268: src_req = HTRequest_new(); /* First set up the source */
1269: HTAnchor_clearHeader((HTParentAnchor *) src_anchor);
1270: src_req->ForceReload = YES;
1271: src_req->source = src_req; /* Point to myself */
1272: src_req->output_format = WWW_SOURCE; /* We want source (for now) */
1273:
1274: /* Set up the main link in the source anchor */
1275: {
1276: HTAnchor *main = HTAnchor_followMainLink(src_anchor);
1277: HTMethod method = HTAnchor_mainLinkMethod(src_anchor);
1278: if (!main || method==METHOD_INVALID) {
1279: if (TRACE)
1280: fprintf(TDEST, "Copy Anchor. No destination found or unspecified method");
1281: HTRequest_delete(src_req);
1282: return HT_ERROR;
1283: }
1284: main_dest->GenMask += HT_DATE; /* Send date header */
1285: main_dest->source = src_req;
1286: main_dest->ForceReload = YES;
1287: main_dest->method = method;
1288: HTRequest_addDestination(src_req, main_dest);
1289: main_dest->input_format = WWW_SOURCE; /* for now :-( @@@ */
1290: if (HTLoadAnchor(main, main_dest) == HT_ERROR)
1291: return HT_ERROR;
1292: }
1.78 frystyk 1293:
1.80 frystyk 1294: /* For all other links in the source anchor */
1295: if (src_anchor->links) {
1296: HTList *cur = src_anchor->links;
1297: HTLink *pres;
1298: while ((pres = (HTLink *) HTList_nextObject(cur)) != NULL) {
1299: HTAnchor *dest = pres->dest;
1300: HTMethod method = pres->method;
1301: HTRequest *dest_req;
1302: if (!dest || method==METHOD_INVALID) {
1303: if (TRACE)
1304: fprintf(TDEST, "Copy Anchor. Bad anchor setup %p\n",
1305: dest);
1306: return HT_ERROR;
1307: }
1308: dest_req = HTRequest_new();
1309: dest_req->GenMask += HT_DATE; /* Send date header */
1310: dest_req->source = src_req;
1311: dest_req->ForceReload = YES;
1312: dest_req->method = method;
1313: HTRequest_addDestination(src_req, dest_req);
1314: dest_req->input_format = WWW_SOURCE; /* for now :-( @@@ */
1315: if (HTLoadAnchor(dest, dest_req) == HT_ERROR)
1316: return HT_ERROR;
1317: }
1318: }
1319: } else { /* Use the existing Post Web and restart it */
1320: src_req = main_dest->source;
1321: if (src_req->mainDestination)
1322: if (HTLoadDocument(main_dest, NO) == HT_ERROR)
1323: return HT_ERROR;
1324: if (src_req->destinations) {
1325: HTList *cur = src_anchor->links;
1326: HTRequest *pres;
1327: while ((pres = (HTRequest *) HTList_nextObject(cur)) != NULL) {
1328: if (HTLoadDocument(pres, NO) == HT_ERROR)
1329: return HT_ERROR;
1330: }
1331: }
1.78 frystyk 1332: }
1333:
1.80 frystyk 1334: /* Now open the source */
1335: return HTLoadAnchor(src_anchor, src_req);
1.70 frystyk 1336: }
1337:
1338:
1339: /* UPLOAD AN ANCHOR
1340: ** ----------------
1341: ** Send the contents (in hyperdoc) of the source anchor using either PUT
1342: ** or POST to the remote destination using HTTP. The caller can decide the
1343: ** exact method used and which HTTP header fields to transmit by setting the
1344: ** user fields in the request structure.
1345: **
1346: ** returns HT_WOULD_BLOCK An I/O operation would block
1347: ** HT_ERROR Error has occured
1348: ** HT_LOADED Success
1349: ** HT_NO_DATA Success, but no document loaded.
1.72 frystyk 1350: ** HT_RETRY if service isn't available before
1351: ** request->retry_after
1.70 frystyk 1352: */
1353: PUBLIC int HTUploadAnchor ARGS3(HTAnchor *, src_anchor,
1354: HTParentAnchor *, dest_anchor,
1355: HTRequest *, dest_req)
1356: {
1357: if (!(src_anchor && dest_anchor && dest_req))
1358: return HT_ERROR;
1359:
1360: if (!(dest_anchor->methods & dest_req->method)) {
1361: char buf[80];
1362: sprintf(buf, "It might not be allowed to %s to this destination, continue?", HTMethod_name(dest_req->method));
1363: if (!HTConfirm(buf))
1364: return HT_ERROR;
1365: }
1.77 frystyk 1366:
1367: /* @@@ NOT FINISHED @@@ */
1.70 frystyk 1368:
1369: return HT_ERROR;
1370: }
1371:
1372: /* --------------------------------------------------------------------------*/
1373: /* Anchor help routines */
1374: /* --------------------------------------------------------------------------*/
1.57 howcome 1375:
1376: /*
1377: ** Find Related Name
1378: **
1379: ** Creates a string that can be used as a related name when
1380: ** calling HTParse initially.
1381: **
1382: ** The code for this routine originates from the Linemode
1.79 frystyk 1383: ** browser and was moved here by howcome@w3.org
1.57 howcome 1384: ** in order for all clients to take advantage.
1385: **
1.59 frystyk 1386: ** The string returned must be freed by the caller
1.57 howcome 1387: */
1388: PUBLIC char * HTFindRelatedName NOARGS
1389: {
1.59 frystyk 1390: char* default_default = NULL; /* Parse home relative to this */
1391: CONST char *host = HTGetHostName();
1.57 howcome 1392: StrAllocCopy(default_default, "file://");
1.59 frystyk 1393: if (host)
1394: StrAllocCat(default_default, host);
1395: else
1396: StrAllocCat(default_default, "localhost");
1397: {
1398: char wd[HT_MAX_PATH+1];
1.67 frystyk 1399:
1400: #ifdef NO_GETWD
1401: #ifdef HAS_GETCWD /* System V variant SIGN CHANGED TBL 921006 !! */
1402: char *result = (char *) getcwd(wd, sizeof(wd));
1403: #else
1404: char *result = NULL;
1405: HTAlert("This platform does not support neither getwd nor getcwd\n");
1406: #endif
1407: #else
1408: char *result = (char *) getwd(wd);
1409: #endif
1.59 frystyk 1410: *(wd+HT_MAX_PATH) = '\0';
1.57 howcome 1411: if (result) {
1412: #ifdef VMS
1413: /* convert directory name to Unix-style syntax */
1414: char * disk = strchr (wd, ':');
1415: char * dir = strchr (wd, '[');
1416: if (disk) {
1417: *disk = '\0';
1418: StrAllocCat (default_default, "/"); /* needs delimiter */
1419: StrAllocCat (default_default, wd);
1420: }
1421: if (dir) {
1422: char *p;
1423: *dir = '/'; /* Convert leading '[' */
1424: for (p = dir ; *p != ']'; ++p)
1425: if (*p == '.') *p = '/';
1426: *p = '\0'; /* Cut on final ']' */
1427: StrAllocCat (default_default, dir);
1428: }
1.74 frystyk 1429: #else /* not VMS */
1.70 frystyk 1430: #ifdef WIN32
1431: char * p = wd ; /* a colon */
1432: StrAllocCat(default_default, "/");
1433: while( *p != 0 ) {
1434: if (*p == '\\') /* change to one true slash */
1435: *p = '/' ;
1436: p++;
1437: }
1.74 frystyk 1438: StrAllocCat( default_default, wd);
1439: #else /* not WIN32 */
1.57 howcome 1440: StrAllocCat (default_default, wd);
1.70 frystyk 1441: #endif /* not WIN32 */
1.67 frystyk 1442: #endif /* not VMS */
1.57 howcome 1443: }
1.67 frystyk 1444: }
1.57 howcome 1445: StrAllocCat(default_default, "/default.html");
1446: return default_default;
1.2 timbl 1447: }
1448:
1449:
1450: /* Generate the anchor for the home page
1451: ** -------------------------------------
1452: **
1453: ** As it involves file access, this should only be done once
1454: ** when the program first runs.
1.10 timbl 1455: ** This is a default algorithm -- browser don't HAVE to use this.
1456: ** But consistency betwen browsers is STRONGLY recommended!
1.2 timbl 1457: **
1.10 timbl 1458: ** Priority order is:
1459: **
1460: ** 1 WWW_HOME environment variable (logical name, etc)
1461: ** 2 ~/WWW/default.html
1462: ** 3 /usr/local/bin/default.html
1.70 frystyk 1463: ** 4 http://www.w3.org/default.html
1.10 timbl 1464: **
1.2 timbl 1465: */
1466: PUBLIC HTParentAnchor * HTHomeAnchor NOARGS
1467: {
1.12 timbl 1468: char * my_home_document = NULL;
1.70 frystyk 1469: char * home = (char *) getenv(LOGICAL_DEFAULT);
1.2 timbl 1470: char * ref;
1471: HTParentAnchor * anchor;
1.1 timbl 1472:
1.70 frystyk 1473: /* Someone telnets in, they get a special home */
1.12 timbl 1474: if (home) {
1475: StrAllocCopy(my_home_document, home);
1.70 frystyk 1476: } else if (HTClientHost) { /* Telnet server */
1.12 timbl 1477: FILE * fp = fopen(REMOTE_POINTER, "r");
1478: char * status;
1479: if (fp) {
1.59 frystyk 1480: my_home_document = (char*) malloc(HT_MAX_PATH);
1481: status = fgets(my_home_document, HT_MAX_PATH, fp);
1.12 timbl 1482: if (!status) {
1483: free(my_home_document);
1484: my_home_document = NULL;
1485: }
1486: fclose(fp);
1487: }
1488: if (!my_home_document) StrAllocCopy(my_home_document, REMOTE_ADDRESS);
1489: }
1490:
1.67 frystyk 1491: #ifdef unix
1.10 timbl 1492: if (!my_home_document) {
1493: FILE * fp = NULL;
1.70 frystyk 1494: char * home = (char *) getenv("HOME");
1.10 timbl 1495: if (home) {
1496: my_home_document = (char *)malloc(
1497: strlen(home)+1+ strlen(PERSONAL_DEFAULT)+1);
1498: if (my_home_document == NULL) outofmem(__FILE__, "HTLocalName");
1499: sprintf(my_home_document, "%s/%s", home, PERSONAL_DEFAULT);
1500: fp = fopen(my_home_document, "r");
1501: }
1502:
1503: if (!fp) {
1504: StrAllocCopy(my_home_document, LOCAL_DEFAULT_FILE);
1505: fp = fopen(my_home_document, "r");
1506: }
1.2 timbl 1507: if (fp) {
1508: fclose(fp);
1509: } else {
1.62 frystyk 1510: if (TRACE)
1.67 frystyk 1511: fprintf(TDEST,
1.62 frystyk 1512: "HTBrowse: No local home document ~/%s or %s\n",
1513: PERSONAL_DEFAULT, LOCAL_DEFAULT_FILE);
1.11 timbl 1514: free(my_home_document);
1515: my_home_document = NULL;
1.2 timbl 1516: }
1517: }
1.67 frystyk 1518: #endif
1.70 frystyk 1519: ref = HTParse(my_home_document ? my_home_document :
1520: HTClientHost ? REMOTE_ADDRESS : LAST_RESORT, "file:",
1521: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1.10 timbl 1522: if (my_home_document) {
1.62 frystyk 1523: if (TRACE)
1.67 frystyk 1524: fprintf(TDEST,
1.62 frystyk 1525: "HTAccess.... `%s\' used for custom home page as\n`%s\'\n",
1526: my_home_document, ref);
1.10 timbl 1527: free(my_home_document);
1.2 timbl 1528: }
1529: anchor = (HTParentAnchor*) HTAnchor_findAddress(ref);
1530: free(ref);
1531: return anchor;
1.1 timbl 1532: }
1.26 frystyk 1533:
1534:
1535: /* Bind an Anchor to the request structure
1536: ** ---------------------------------------
1537: **
1538: ** On Entry,
1539: ** anchor The child or parenet anchor to be binded
1540: ** request The request sturcture
1541: ** On Exit,
1542: ** returns YES Success
1543: ** NO Failure
1544: **
1545: ** Note: Actually the same as HTLoadAnchor() but DOES NOT do the loading
1546: ** Henrik Frystyk 17/02-94
1547: */
1548:
1549: PUBLIC BOOL HTBindAnchor ARGS2(HTAnchor*, anchor, HTRequest *, request)
1550: {
1551: if (!anchor) return NO; /* No link */
1552:
1553: request->anchor = HTAnchor_parent(anchor);
1554: request->childAnchor = ((HTAnchor*)request->anchor == anchor) ? NULL
1555: : (HTChildAnchor*) anchor;
1556:
1.29 frystyk 1557: return YES;
1.70 frystyk 1558: }
1.59 frystyk 1559:
1.26 frystyk 1560:
Webmaster