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