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