Annotation of libwww/Library/src/HTAccess.c, revision 1.87
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.1 timbl 22: */
23:
1.68 frystyk 24: #if !defined(HT_DIRECT_WAIS) && !defined(HT_DEFAULT_WAIS_GATEWAY)
25: #define HT_DEFAULT_WAIS_GATEWAY "http://www.w3.org:8001/"
1.54 frystyk 26: #endif
1.8 timbl 27:
1.67 frystyk 28: /* Library include files */
29: #include "tcp.h"
30: #include "HTUtils.h"
1.78 frystyk 31: #include "HTString.h"
1.1 timbl 32: #include "HTParse.h"
1.78 frystyk 33: #include "HTAlert.h"
34: #include "HTError.h"
1.2 timbl 35: #include "HTList.h"
1.78 frystyk 36: #include "HTAABrow.h" /* Should be HTAAUtil.html! */
1.84 frystyk 37: #include "HTFWrite.h"
38: #include "HTCache.h"
1.70 frystyk 39: #include "HTLog.h"
1.77 frystyk 40: #include "HTSocket.h"
1.57 howcome 41: #include "HTTCP.h" /* HWL: for HTFindRelatedName */
1.59 frystyk 42: #include "HTThread.h"
1.83 frystyk 43: #include "HTEvntrg.h"
1.73 frystyk 44: #include "HTBind.h"
1.81 frystyk 45: #include "HTProt.h"
1.70 frystyk 46: #include "HTInit.h"
1.77 frystyk 47: #include "HTProxy.h"
1.74 frystyk 48:
1.67 frystyk 49: #ifndef NO_RULES
50: #include "HTRules.h"
51: #endif
1.74 frystyk 52:
1.67 frystyk 53: #include "HTAccess.h" /* Implemented here */
1.2 timbl 54:
1.54 frystyk 55: /* These flags may be set to modify the operation of this module */
1.78 frystyk 56: PUBLIC char * HTClientHost = NULL; /* Name of remote login host if any */
1.70 frystyk 57: PUBLIC BOOL HTSecure = NO; /* Disable access for telnet users? */
1.41 luotonen 58:
1.43 luotonen 59: PUBLIC char * HTImServer = NULL;/* cern_httpd sets this to the translated URL*/
1.70 frystyk 60: PUBLIC BOOL HTImProxy = NO; /* cern_httpd as a proxy? */
1.1 timbl 61:
1.85 frystyk 62: /* Private flags */
63: PRIVATE HTExpiresMode HTExpMode = HT_EXPIRES_IGNORE;
64: PRIVATE int HTMaxReloads = 6;
65: PRIVATE char *HTExpNotify;
66:
1.87 ! frystyk 67: /* Memory cache handler */
! 68: PRIVATE HTMemoryCacheHandler HTMemoryCache = NULL;
! 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 */
1.85 frystyk 100: me->reload = HT_ANY_VERSION;
1.84 frystyk 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.85 frystyk 503: ** Check local Disk Cache (if we are not forced to reload), then
1.84 frystyk 504: ** for proxy, and finally gateways
1.77 frystyk 505: */
506: {
1.85 frystyk 507: char *newaddr=NULL;
508: if (req->reload != HT_FORCE_RELOAD &&
509: (newaddr = HTCache_getReference(addr))) {
510: if (req->reload != HT_CACHE_REFRESH) {
511: HTAnchor_setPhysical(req->anchor, newaddr);
512: HTAnchor_setCacheHit(req->anchor, YES);
513: } else { /* If refresh version in file cache */
514: req->RequestMask |= (HT_IMS + HT_NO_CACHE);
515: }
1.84 frystyk 516: } else if ((newaddr = HTProxy_getProxy(addr))) {
517: StrAllocCat(newaddr, addr);
1.70 frystyk 518: req->using_proxy = YES;
1.84 frystyk 519: HTAnchor_setPhysical(req->anchor, newaddr);
520: free(newaddr);
521: } else if ((newaddr = HTProxy_getGateway(addr))) {
1.9 timbl 522: char * path = HTParse(addr, "",
1.77 frystyk 523: PARSE_HOST + PARSE_PATH + PARSE_PUNCTUATION);
1.9 timbl 524: /* Chop leading / off to make host into part of path */
1.84 frystyk 525: char * gatewayed = HTParse(path+1, newaddr, PARSE_ALL);
1.77 frystyk 526: HTAnchor_setPhysical(req->anchor, gatewayed);
1.9 timbl 527: free(path);
528: free(gatewayed);
1.84 frystyk 529: free(newaddr);
1.77 frystyk 530: } else {
531: req->using_proxy = NO; /* We don't use proxy or gateway */
1.2 timbl 532: }
1.85 frystyk 533: FREE(newaddr);
1.2 timbl 534: }
1.77 frystyk 535: FREE(addr);
1.1 timbl 536:
1.81 frystyk 537: /* Set the access scheme on our way out */
1.82 frystyk 538: return (HTProtocol_get(req->anchor)==YES) ? HT_OK : HT_NO_ACCESS;
1.1 timbl 539: }
540:
1.59 frystyk 541: /* --------------------------------------------------------------------------*/
542: /* Document Loader */
543: /* --------------------------------------------------------------------------*/
1.1 timbl 544:
545: /* Load a document
546: ** ---------------
547: **
1.2 timbl 548: ** This is an internal routine, which has an address AND a matching
549: ** anchor. (The public routines are called with one OR the other.)
550: **
551: ** On entry,
1.15 timbl 552: ** request->
1.35 luotonen 553: ** anchor a parent anchor with fully qualified
554: ** hypertext reference as its address set
1.15 timbl 555: ** output_format valid
556: ** output_stream valid on NULL
1.2 timbl 557: **
558: ** On exit,
1.59 frystyk 559: ** returns HT_WOULD_BLOCK An I/O operation would block
560: ** HT_ERROR Error has occured
1.2 timbl 561: ** HT_LOADED Success
562: ** HT_NO_DATA Success, but no document loaded.
1.8 timbl 563: ** (telnet sesssion started etc)
1.72 frystyk 564: ** HT_RETRY if service isn't available before
565: ** request->retry_after
1.2 timbl 566: */
1.52 frystyk 567: PUBLIC int HTLoad ARGS2(HTRequest *, request, BOOL, keep_error_stack)
1.2 timbl 568: {
1.25 frystyk 569: char *arg = NULL;
570: HTProtocol *p;
571: int status;
572:
1.22 luotonen 573: if (request->method == METHOD_INVALID)
574: request->method = METHOD_GET;
1.52 frystyk 575: if (!keep_error_stack) {
576: HTErrorFree(request);
577: request->error_block = NO;
578: }
579:
1.59 frystyk 580: if ((status = get_physical(request)) < 0) {
581: if (status == HT_FORBIDDEN) {
582: char *url = HTAnchor_address((HTAnchor *) request->anchor);
583: if (url) {
584: HTUnEscape(url);
585: HTErrorAdd(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
586: (void *) url, (int) strlen(url), "HTLoad");
587: free(url);
588: } else {
589: HTErrorAdd(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
590: NULL, 0, "HTLoad");
591: }
592: }
593: return HT_ERROR; /* Can't resolve or forbidden */
1.2 timbl 594: }
1.25 frystyk 595:
596: if(!(arg = HTAnchor_physical(request->anchor)) || !*arg)
1.59 frystyk 597: return HT_ERROR;
1.27 luotonen 598:
1.56 frystyk 599: p = (HTProtocol *) HTAnchor_protocol(request->anchor);
1.17 timbl 600: return (*(p->load))(request);
1.2 timbl 601: }
602:
603:
1.61 frystyk 604: /* Terminate a LOAD
605: ** ----------------
606: **
607: ** This function looks at the status code from the HTLoadDocument
608: ** function and updates logfiles, creates error messages etc.
609: **
610: ** On Entry,
611: ** Status code from load function
612: */
613: PUBLIC BOOL HTLoadTerminate ARGS2(HTRequest *, request, int, status)
614: {
615: char * uri = HTAnchor_address((HTAnchor*)request->anchor);
616:
1.85 frystyk 617: HTLog_request(request, status);
1.61 frystyk 618:
619: /* The error stack might contain general information to the client
620: about what has been going on in the library (not only errors) */
621: if (!HTImProxy && request->error_stack)
622: HTErrorMsg(request);
623:
624: switch (status) {
625: case HT_LOADED:
626: if (PROT_TRACE) {
1.72 frystyk 627: fprintf(TDEST, "HTAccess.... OK: `%s\' has been accessed.\n", uri);
1.61 frystyk 628: }
629: break;
630:
1.78 frystyk 631: case HT_OK:
632: if (PROT_TRACE) {
1.85 frystyk 633: fprintf(TDEST, "HTAccess.... FRIEND FINISHED ACCESS: `%s\'\n",uri);
1.78 frystyk 634: }
635: break;
636:
1.61 frystyk 637: case HT_NO_DATA:
638: if (PROT_TRACE) {
1.72 frystyk 639: fprintf(TDEST, "HTAccess.... OK BUT NO DATA: `%s\'\n", uri);
1.61 frystyk 640: }
641: break;
642:
643: case HT_WOULD_BLOCK:
644: if (PROT_TRACE) {
1.72 frystyk 645: fprintf(TDEST, "HTAccess.... WOULD BLOCK: `%s\'\n", uri);
646: }
647: break;
648:
649: case HT_RETRY:
650: if (PROT_TRACE) {
651: fprintf(TDEST, "HTAccess.... NOT AVAILABLE, RETRY AT `%s\'\n",uri);
1.61 frystyk 652: }
653: break;
654:
655: case HT_ERROR:
656: if (HTImProxy)
657: HTErrorMsg(request); /* Only on a real error */
658: if (PROT_TRACE) {
1.72 frystyk 659: fprintf(TDEST, "HTAccess.... ERROR: Can't access `%s\'\n", uri);
1.61 frystyk 660: }
661: break;
662:
663: default:
664: if (PROT_TRACE) {
1.67 frystyk 665: fprintf(TDEST, "HTAccess.... **** Internal software error in CERN WWWLib version %s ****\n", HTLibraryVersion);
1.79 frystyk 666: fprintf(TDEST, "............ Please mail libwww@w3.org quoting what software\n");
1.67 frystyk 667: fprintf(TDEST, "............ and version you are using including the URL:\n");
668: fprintf(TDEST, "............ `%s\'\n", uri);
669: fprintf(TDEST, "............ that caused the problem, thanks!\n");
1.61 frystyk 670: }
671: break;
672: }
673: free(uri);
674: return YES;
675: }
676:
677:
1.2 timbl 678: /* Load a document - with logging etc
679: ** ----------------------------------
680: **
681: ** - Checks or documents already loaded
682: ** - Logs the access
683: ** - Trace ouput and error messages
684: **
1.1 timbl 685: ** On Entry,
1.19 timbl 686: ** request->anchor valid for of the document to be accessed.
687: ** request->childAnchor optional anchor within doc to be selected
688: **
1.15 timbl 689: ** request->anchor is the node_anchor for the document
690: ** request->output_format is valid
691: **
1.59 frystyk 692: ** On exit,
693: ** returns HT_WOULD_BLOCK An I/O operation would block
694: ** HT_ERROR Error has occured
695: ** HT_LOADED Success
696: ** HT_NO_DATA Success, but no document loaded.
697: ** (telnet sesssion started etc)
1.72 frystyk 698: ** HT_RETRY if service isn't available before
699: ** request->retry_after
1.1 timbl 700: */
1.59 frystyk 701: PRIVATE int HTLoadDocument ARGS2(HTRequest *, request,
702: BOOL, keep_error_stack)
1.1 timbl 703:
704: {
705: int status;
1.19 timbl 706: char * full_address = HTAnchor_address((HTAnchor*)request->anchor);
1.54 frystyk 707:
1.80 frystyk 708: if (PROT_TRACE) fprintf (TDEST, "HTAccess.... Accessing document %s\n",
1.59 frystyk 709: full_address);
1.1 timbl 710:
1.15 timbl 711: if (!request->output_format) request->output_format = WWW_PRESENT;
1.25 frystyk 712:
1.85 frystyk 713: /*
714: ** Check if document is already loaded. As the application handles the
1.87 ! frystyk 715: ** memory cache, we call the application to ask.
1.85 frystyk 716: */
717: if (request->reload != HT_FORCE_RELOAD) {
1.87 ! frystyk 718: if (HTMemoryCache) {
! 719: if (HTMemoryCache(request, HTExpMode, HTExpNotify) == HT_LOADED) {
! 720: free(full_address);
! 721: return HT_LOADED;
1.67 frystyk 722: }
1.87 ! frystyk 723: }
1.85 frystyk 724: } else {
725: request->RequestMask |= HT_NO_CACHE; /* no-cache pragma */
1.70 frystyk 726: HTAnchor_clearHeader(request->anchor);
1.1 timbl 727: }
1.85 frystyk 728:
729: /* Now do the load */
1.61 frystyk 730: if ((status = HTLoad(request, keep_error_stack)) != HT_WOULD_BLOCK)
731: HTLoadTerminate(request, status);
1.19 timbl 732: free(full_address);
1.59 frystyk 733: return status;
1.58 frystyk 734: }
1.1 timbl 735:
736:
737: /* Load a document from absolute name
738: ** ---------------
739: **
1.59 frystyk 740: ** On Entry,
1.1 timbl 741: ** addr The absolute address of the document to be accessed.
742: **
1.59 frystyk 743: ** On exit,
744: ** returns HT_WOULD_BLOCK An I/O operation would block
745: ** HT_ERROR Error has occured
746: ** HT_LOADED Success
747: ** HT_NO_DATA Success, but no document loaded.
748: ** (telnet sesssion started etc)
1.72 frystyk 749: ** HT_RETRY if service isn't available before
750: ** request->retry_after
1.1 timbl 751: */
1.59 frystyk 752: PUBLIC int HTLoadAbsolute ARGS2(CONST char *,addr, HTRequest*, request)
1.2 timbl 753: {
1.19 timbl 754: HTAnchor * anchor = HTAnchor_findAddress(addr);
755: request->anchor = HTAnchor_parent(anchor);
756: request->childAnchor = ((HTAnchor*)request->anchor == anchor) ?
757: NULL : (HTChildAnchor*) anchor;
1.52 frystyk 758: return HTLoadDocument(request, NO);
1.2 timbl 759: }
760:
761:
762: /* Load a document from absolute name to stream
763: ** --------------------------------------------
764: **
1.59 frystyk 765: ** On Entry,
1.2 timbl 766: ** addr The absolute address of the document to be accessed.
1.15 timbl 767: ** request->output_stream if non-NULL, send data down this stream
1.2 timbl 768: **
1.59 frystyk 769: ** On exit,
770: ** returns HT_WOULD_BLOCK An I/O operation would block
771: ** HT_ERROR Error has occured
772: ** HT_LOADED Success
773: ** HT_NO_DATA Success, but no document loaded.
774: ** (telnet sesssion started etc)
1.72 frystyk 775: ** HT_RETRY if service isn't available before
776: ** request->retry_after
1.2 timbl 777: */
1.59 frystyk 778: PUBLIC int HTLoadToStream ARGS3(CONST char *, addr,
779: BOOL, filter,
780: HTRequest*, request)
1.1 timbl 781: {
1.63 frystyk 782: HTAnchor * anchor = HTAnchor_findAddress(addr);
783: request->anchor = HTAnchor_parent(anchor);
784: request->childAnchor = ((HTAnchor*)request->anchor == anchor) ? NULL :
1.19 timbl 785: (HTChildAnchor*) anchor;
1.15 timbl 786: request->output_stream = request->output_stream;
1.52 frystyk 787: return HTLoadDocument(request, NO);
1.1 timbl 788: }
789:
790:
791: /* Load a document from relative name
792: ** ---------------
793: **
1.59 frystyk 794: ** On Entry,
1.2 timbl 795: ** relative_name The relative address of the document
796: ** to be accessed.
1.1 timbl 797: **
1.59 frystyk 798: ** On exit,
799: ** returns HT_WOULD_BLOCK An I/O operation would block
800: ** HT_ERROR Error has occured
801: ** HT_LOADED Success
802: ** HT_NO_DATA Success, but no document loaded.
803: ** (telnet sesssion started etc)
1.72 frystyk 804: ** HT_RETRY if service isn't available before
805: ** request->retry_after
1.1 timbl 806: */
1.59 frystyk 807: PUBLIC int HTLoadRelative ARGS3(CONST char *, relative_name,
808: HTParentAnchor *, here,
809: HTRequest *, request)
1.1 timbl 810: {
811: char * full_address = 0;
1.65 frystyk 812: int result;
1.1 timbl 813: char * mycopy = 0;
814: char * stripped = 0;
815: char * current_address =
1.2 timbl 816: HTAnchor_address((HTAnchor*)here);
1.1 timbl 817:
818: StrAllocCopy(mycopy, relative_name);
819:
820: stripped = HTStrip(mycopy);
821: full_address = HTParse(stripped,
822: current_address,
823: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1.15 timbl 824: result = HTLoadAbsolute(full_address, request);
1.1 timbl 825: free(full_address);
826: free(current_address);
827: free(mycopy); /* Memory leak fixed 10/7/92 -- JFG */
828: return result;
829: }
830:
831:
832: /* Load if necessary, and select an anchor
833: ** --------------------------------------
834: **
1.59 frystyk 835: ** On Entry,
1.1 timbl 836: ** destination The child or parenet anchor to be loaded.
837: **
1.59 frystyk 838: ** On exit,
839: ** returns HT_WOULD_BLOCK An I/O operation would block
840: ** HT_ERROR Error has occured
841: ** HT_LOADED Success
842: ** HT_NO_DATA Success, but no document loaded.
843: ** (telnet sesssion started etc)
1.72 frystyk 844: ** HT_RETRY if service isn't available before
845: ** request->retry_after
1.1 timbl 846: */
1.59 frystyk 847: PUBLIC int HTLoadAnchor ARGS2(HTAnchor*, anchor, HTRequest *, request)
1.1 timbl 848: {
1.70 frystyk 849: if (!anchor || !request)
850: return HT_ERROR;
851: request->anchor = HTAnchor_parent(anchor);
1.59 frystyk 852: request->childAnchor = ((HTAnchor *) request->anchor == anchor) ?
853: NULL : (HTChildAnchor*) anchor;
854: return HTLoadDocument(request, NO);
855: }
1.52 frystyk 856:
857:
858: /* Load if necessary, and select an anchor
859: ** --------------------------------------
860: **
861: ** This function is almost identical to HTLoadAnchor, but it doesn't
862: ** clear the error stack so that the information in there is kept.
863: **
1.59 frystyk 864: ** On Entry,
1.52 frystyk 865: ** destination The child or parenet anchor to be loaded.
866: **
1.59 frystyk 867: ** On exit,
868: ** returns HT_WOULD_BLOCK An I/O operation would block
869: ** HT_ERROR Error has occured
870: ** HT_LOADED Success
871: ** HT_NO_DATA Success, but no document loaded.
872: ** (telnet sesssion started etc)
1.72 frystyk 873: ** HT_RETRY if service isn't available before
874: ** request->retry_after
1.52 frystyk 875: */
1.59 frystyk 876: PUBLIC int HTLoadAnchorRecursive ARGS2(HTAnchor*, anchor,
877: HTRequest *, request)
1.52 frystyk 878: {
1.59 frystyk 879: if (!anchor) return HT_ERROR; /* No link */
1.52 frystyk 880:
881: request->anchor = HTAnchor_parent(anchor);
1.59 frystyk 882: request->childAnchor = ((HTAnchor *) request->anchor == anchor) ?
883: NULL : (HTChildAnchor*) anchor;
1.52 frystyk 884:
1.59 frystyk 885: return HTLoadDocument(request, YES);
886: }
1.1 timbl 887:
888:
889: /* Search
890: ** ------
891: ** Performs a keyword search on word given by the user. Adds the keyword to
892: ** the end of the current address and attempts to open the new address.
893: **
894: ** On Entry,
895: ** *keywords space-separated keyword list or similar search list
1.2 timbl 896: ** here is anchor search is to be done on.
1.59 frystyk 897: **
898: ** On exit,
899: ** returns HT_WOULD_BLOCK An I/O operation would block
900: ** HT_ERROR Error has occured
901: ** HT_LOADED Success
902: ** HT_NO_DATA Success, but no document loaded.
903: ** (telnet sesssion started etc)
1.72 frystyk 904: ** HT_RETRY if service isn't available before
905: ** request->retry_after
1.1 timbl 906: */
1.56 frystyk 907: PRIVATE char hex ARGS1(int, i)
1.2 timbl 908: {
1.13 timbl 909: char * hexchars = "0123456789ABCDEF";
910: return hexchars[i];
1.2 timbl 911: }
1.1 timbl 912:
1.59 frystyk 913: PUBLIC int HTSearch ARGS3(CONST char *, keywords,
914: HTParentAnchor *, here,
915: HTRequest *, request)
1.1 timbl 916: {
1.2 timbl 917:
918: #define acceptable \
919: "1234567890abcdefghijlkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_"
920:
921: char *q, *u;
922: CONST char * p, *s, *e; /* Pointers into keywords */
923: char * address = HTAnchor_address((HTAnchor*)here);
1.65 frystyk 924: int result;
1.56 frystyk 925: char * escaped = (char *) malloc(strlen(keywords)*3+1);
1.2 timbl 926:
1.29 frystyk 927: /* static CONST BOOL isAcceptable[96] = */
928: /* static AND const is not good for a gnu compiler! Frystyk 25/02-94 */
1.30 luotonen 929: static BOOL isAcceptable[96] =
1.2 timbl 930: /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
931: { 0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,0, /* 2x !"#$%&'()*+,-./ */
932: 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */
933: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4x @ABCDEFGHIJKLMNO */
934: 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1, /* 5X PQRSTUVWXYZ[\]^_ */
935: 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6x `abcdefghijklmno */
936: 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0 }; /* 7X pqrstuvwxyz{\}~ DEL */
937:
938: if (escaped == NULL) outofmem(__FILE__, "HTSearch");
939:
1.29 frystyk 940: /* Convert spaces to + and hex escape unacceptable characters */
1.2 timbl 941:
1.29 frystyk 942: for(s=keywords; *s && WHITE(*s); s++); /*scan */ /* Skip white space */
943: for(e = s + strlen(s); e>s && WHITE(*(e-1)) ; e--); /* Skip trailers */
944: for(q=escaped, p=s; p<e; p++) { /* scan stripped field */
1.2 timbl 945: int c = (int)TOASCII(*p);
946: if (WHITE(*p)) {
947: *q++ = '+';
1.29 frystyk 948: } else if (c>=32 && c<=127 && isAcceptable[c-32] != 0) {
1.13 timbl 949: *q++ = *p; /* 930706 TBL for MVS bug */
1.2 timbl 950: } else {
951: *q++ = '%';
952: *q++ = hex(c / 16);
953: *q++ = hex(c % 16);
954: }
955: } /* Loop over string */
1.1 timbl 956:
1.2 timbl 957: *q=0;
958: /* terminate escaped sctring */
959: u=strchr(address, '?'); /* Find old search string */
960: if (u) *u = 0; /* Chop old search off */
1.1 timbl 961:
962: StrAllocCat(address, "?");
1.2 timbl 963: StrAllocCat(address, escaped);
964: free(escaped);
1.15 timbl 965: result = HTLoadRelative(address, here, request);
1.1 timbl 966: free(address);
1.2 timbl 967:
1.1 timbl 968: return result;
1.2 timbl 969: }
970:
971:
972: /* Search Given Indexname
973: ** ------
974: ** Performs a keyword search on word given by the user. Adds the keyword to
975: ** the end of the current address and attempts to open the new address.
976: **
1.59 frystyk 977: ** On Entry,
1.2 timbl 978: ** *keywords space-separated keyword list or similar search list
979: ** *addres is name of object search is to be done on.
1.59 frystyk 980: ** On exit,
981: ** returns HT_WOULD_BLOCK An I/O operation would block
982: ** HT_ERROR Error has occured
983: ** HT_LOADED Success
984: ** HT_NO_DATA Success, but no document loaded.
985: ** (telnet sesssion started etc)
1.72 frystyk 986: ** HT_RETRY if service isn't available before
987: ** request->retry_after
1.2 timbl 988: */
1.59 frystyk 989: PUBLIC int HTSearchAbsolute ARGS3(CONST char *, keywords,
990: CONST char *, indexname,
991: HTRequest *, request)
1.2 timbl 992: {
993: HTParentAnchor * anchor =
994: (HTParentAnchor*) HTAnchor_findAddress(indexname);
1.15 timbl 995: return HTSearch(keywords, anchor, request);
1.57 howcome 996: }
997:
1.70 frystyk 998: /* --------------------------------------------------------------------------*/
999: /* Document Poster */
1000: /* --------------------------------------------------------------------------*/
1001:
1002: /* Get a save stream for a document
1003: ** --------------------------------
1004: */
1005: PUBLIC HTStream *HTSaveStream ARGS1(HTRequest *, request)
1006: {
1007: HTProtocol * p;
1008: int status;
1009: request->method = METHOD_PUT;
1010: status = get_physical(request);
1011: if (status == HT_FORBIDDEN) {
1012: char *url = HTAnchor_address((HTAnchor *) request->anchor);
1013: if (url) {
1014: HTUnEscape(url);
1015: HTErrorAdd(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
1016: (void *) url, (int) strlen(url), "HTLoad");
1017: free(url);
1018: } else {
1019: HTErrorAdd(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
1020: NULL, 0, "HTLoad");
1021: }
1022: return NULL; /* should return error status? */
1023: }
1024: if (status < 0) return NULL; /* @@ error. Can't resolve or forbidden */
1025:
1026: p = (HTProtocol *) HTAnchor_protocol(request->anchor);
1027: if (!p) return NULL;
1028:
1029: return (*p->saveStream)(request);
1030:
1031: }
1032:
1033: /* COPY AN ANCHOR
1034: ** --------------
1035: ** Fetch the URL (possibly local file URL) and send it using either PUT
1036: ** or POST to the remote destination using HTTP. The caller can decide the
1037: ** exact method used and which HTTP header fields to transmit by setting the
1038: ** user fields in the request structure.
1039: **
1.80 frystyk 1040: ** BUGS: Should take ALL links in the destination anchor and PUT/POST to
1041: ** all of them!
1042: **
1.70 frystyk 1043: ** returns HT_WOULD_BLOCK An I/O operation would block
1044: ** HT_ERROR Error has occured
1045: ** HT_LOADED Success
1046: ** HT_NO_DATA Success, but no document loaded.
1.72 frystyk 1047: ** HT_RETRY if service isn't available before
1048: ** request->retry_after
1.70 frystyk 1049: */
1.80 frystyk 1050: PUBLIC int HTCopyAnchor ARGS2(HTAnchor *, src_anchor,
1.85 frystyk 1051: HTRequest *, main_req)
1.80 frystyk 1052: {
1.78 frystyk 1053: HTRequest *src_req;
1.85 frystyk 1054: if (!src_anchor || !main_req)
1.70 frystyk 1055: return HT_ERROR;
1056:
1.80 frystyk 1057: /* Build the POST web if not already there */
1.85 frystyk 1058: if (!main_req->source) {
1.80 frystyk 1059: src_req = HTRequest_new(); /* First set up the source */
1060: HTAnchor_clearHeader((HTParentAnchor *) src_anchor);
1.85 frystyk 1061: src_req->reload = HT_MEM_REFRESH;
1.80 frystyk 1062: src_req->source = src_req; /* Point to myself */
1063: src_req->output_format = WWW_SOURCE; /* We want source (for now) */
1064:
1065: /* Set up the main link in the source anchor */
1066: {
1.85 frystyk 1067: HTLink *main_link = HTAnchor_findMainLink(src_anchor);
1068: HTAnchor *main_anchor = HTAnchor_linkDest(main_link);
1069: HTMethod method = HTAnchor_linkMethod(main_link);
1070: if (!main_link || method==METHOD_INVALID) {
1.80 frystyk 1071: if (TRACE)
1072: fprintf(TDEST, "Copy Anchor. No destination found or unspecified method");
1073: HTRequest_delete(src_req);
1074: return HT_ERROR;
1075: }
1.85 frystyk 1076: if (HTAnchor_linkResult(main_link) == HT_LINK_NONE) {
1077: main_req->GenMask |= HT_DATE; /* Send date header */
1078: main_req->source = src_req;
1079: main_req->reload = HT_CACHE_REFRESH;
1080: main_req->method = method;
1081: HTRequest_addDestination(src_req, main_req);
1082: main_req->input_format = WWW_SOURCE; /* for now :-( @@@ */
1083: if (HTLoadAnchor(main_anchor, main_req) == HT_ERROR)
1084: return HT_ERROR;
1085: }
1.80 frystyk 1086: }
1.78 frystyk 1087:
1.80 frystyk 1088: /* For all other links in the source anchor */
1089: if (src_anchor->links) {
1090: HTList *cur = src_anchor->links;
1091: HTLink *pres;
1.85 frystyk 1092: while ((pres = (HTLink *) HTList_nextObject(cur)) &&
1093: HTAnchor_linkResult(pres) == HT_LINK_NONE) {
1094: HTAnchor *dest = HTAnchor_linkDest(pres);
1095: HTMethod method = HTAnchor_linkMethod(pres);
1.80 frystyk 1096: HTRequest *dest_req;
1097: if (!dest || method==METHOD_INVALID) {
1098: if (TRACE)
1099: fprintf(TDEST, "Copy Anchor. Bad anchor setup %p\n",
1100: dest);
1101: return HT_ERROR;
1102: }
1103: dest_req = HTRequest_new();
1.85 frystyk 1104: dest_req->GenMask |= HT_DATE; /* Send date header */
1.80 frystyk 1105: dest_req->source = src_req;
1.85 frystyk 1106: dest_req->reload = HT_CACHE_REFRESH;
1.80 frystyk 1107: dest_req->method = method;
1108: HTRequest_addDestination(src_req, dest_req);
1109: dest_req->input_format = WWW_SOURCE; /* for now :-( @@@ */
1110: if (HTLoadAnchor(dest, dest_req) == HT_ERROR)
1111: return HT_ERROR;
1112: }
1113: }
1114: } else { /* Use the existing Post Web and restart it */
1.85 frystyk 1115: src_req = main_req->source;
1.80 frystyk 1116: if (src_req->mainDestination)
1.85 frystyk 1117: if (HTLoadDocument(main_req, NO) == HT_ERROR)
1.80 frystyk 1118: return HT_ERROR;
1119: if (src_req->destinations) {
1120: HTList *cur = src_anchor->links;
1121: HTRequest *pres;
1122: while ((pres = (HTRequest *) HTList_nextObject(cur)) != NULL) {
1123: if (HTLoadDocument(pres, NO) == HT_ERROR)
1124: return HT_ERROR;
1125: }
1126: }
1.78 frystyk 1127: }
1128:
1.80 frystyk 1129: /* Now open the source */
1130: return HTLoadAnchor(src_anchor, src_req);
1.70 frystyk 1131: }
1132:
1133:
1134: /* UPLOAD AN ANCHOR
1135: ** ----------------
1136: ** Send the contents (in hyperdoc) of the source anchor using either PUT
1137: ** or POST to the remote destination using HTTP. The caller can decide the
1138: ** exact method used and which HTTP header fields to transmit by setting the
1139: ** user fields in the request structure.
1140: **
1141: ** returns HT_WOULD_BLOCK An I/O operation would block
1142: ** HT_ERROR Error has occured
1143: ** HT_LOADED Success
1144: ** HT_NO_DATA Success, but no document loaded.
1.72 frystyk 1145: ** HT_RETRY if service isn't available before
1146: ** request->retry_after
1.70 frystyk 1147: */
1148: PUBLIC int HTUploadAnchor ARGS3(HTAnchor *, src_anchor,
1149: HTParentAnchor *, dest_anchor,
1150: HTRequest *, dest_req)
1151: {
1152: if (!(src_anchor && dest_anchor && dest_req))
1153: return HT_ERROR;
1154:
1155: if (!(dest_anchor->methods & dest_req->method)) {
1156: char buf[80];
1157: sprintf(buf, "It might not be allowed to %s to this destination, continue?", HTMethod_name(dest_req->method));
1.86 frystyk 1158: if (!HTConfirm(dest_req, buf))
1.70 frystyk 1159: return HT_ERROR;
1160: }
1.77 frystyk 1161:
1162: /* @@@ NOT FINISHED @@@ */
1.70 frystyk 1163:
1164: return HT_ERROR;
1165: }
1166:
1167: /* --------------------------------------------------------------------------*/
1168: /* Anchor help routines */
1169: /* --------------------------------------------------------------------------*/
1.57 howcome 1170:
1171: /*
1172: ** Find Related Name
1173: **
1174: ** Creates a string that can be used as a related name when
1175: ** calling HTParse initially.
1176: **
1177: ** The code for this routine originates from the Linemode
1.79 frystyk 1178: ** browser and was moved here by howcome@w3.org
1.57 howcome 1179: ** in order for all clients to take advantage.
1180: **
1.59 frystyk 1181: ** The string returned must be freed by the caller
1.57 howcome 1182: */
1183: PUBLIC char * HTFindRelatedName NOARGS
1184: {
1.59 frystyk 1185: char* default_default = NULL; /* Parse home relative to this */
1186: CONST char *host = HTGetHostName();
1.57 howcome 1187: StrAllocCopy(default_default, "file://");
1.59 frystyk 1188: if (host)
1189: StrAllocCat(default_default, host);
1190: else
1191: StrAllocCat(default_default, "localhost");
1192: {
1193: char wd[HT_MAX_PATH+1];
1.67 frystyk 1194:
1195: #ifdef NO_GETWD
1196: #ifdef HAS_GETCWD /* System V variant SIGN CHANGED TBL 921006 !! */
1197: char *result = (char *) getcwd(wd, sizeof(wd));
1198: #else
1199: char *result = NULL;
1200: HTAlert("This platform does not support neither getwd nor getcwd\n");
1201: #endif
1202: #else
1203: char *result = (char *) getwd(wd);
1204: #endif
1.59 frystyk 1205: *(wd+HT_MAX_PATH) = '\0';
1.57 howcome 1206: if (result) {
1207: #ifdef VMS
1208: /* convert directory name to Unix-style syntax */
1209: char * disk = strchr (wd, ':');
1210: char * dir = strchr (wd, '[');
1211: if (disk) {
1212: *disk = '\0';
1213: StrAllocCat (default_default, "/"); /* needs delimiter */
1214: StrAllocCat (default_default, wd);
1215: }
1216: if (dir) {
1217: char *p;
1218: *dir = '/'; /* Convert leading '[' */
1219: for (p = dir ; *p != ']'; ++p)
1220: if (*p == '.') *p = '/';
1221: *p = '\0'; /* Cut on final ']' */
1222: StrAllocCat (default_default, dir);
1223: }
1.74 frystyk 1224: #else /* not VMS */
1.70 frystyk 1225: #ifdef WIN32
1226: char * p = wd ; /* a colon */
1227: StrAllocCat(default_default, "/");
1228: while( *p != 0 ) {
1229: if (*p == '\\') /* change to one true slash */
1230: *p = '/' ;
1231: p++;
1232: }
1.74 frystyk 1233: StrAllocCat( default_default, wd);
1234: #else /* not WIN32 */
1.57 howcome 1235: StrAllocCat (default_default, wd);
1.70 frystyk 1236: #endif /* not WIN32 */
1.67 frystyk 1237: #endif /* not VMS */
1.57 howcome 1238: }
1.67 frystyk 1239: }
1.57 howcome 1240: StrAllocCat(default_default, "/default.html");
1241: return default_default;
1.2 timbl 1242: }
1243:
1244:
1245: /* Generate the anchor for the home page
1246: ** -------------------------------------
1247: **
1248: ** As it involves file access, this should only be done once
1249: ** when the program first runs.
1.10 timbl 1250: ** This is a default algorithm -- browser don't HAVE to use this.
1251: ** But consistency betwen browsers is STRONGLY recommended!
1.2 timbl 1252: **
1.10 timbl 1253: ** Priority order is:
1254: **
1255: ** 1 WWW_HOME environment variable (logical name, etc)
1256: ** 2 ~/WWW/default.html
1257: ** 3 /usr/local/bin/default.html
1.70 frystyk 1258: ** 4 http://www.w3.org/default.html
1.10 timbl 1259: **
1.2 timbl 1260: */
1261: PUBLIC HTParentAnchor * HTHomeAnchor NOARGS
1262: {
1.12 timbl 1263: char * my_home_document = NULL;
1.70 frystyk 1264: char * home = (char *) getenv(LOGICAL_DEFAULT);
1.2 timbl 1265: char * ref;
1266: HTParentAnchor * anchor;
1.1 timbl 1267:
1.70 frystyk 1268: /* Someone telnets in, they get a special home */
1.12 timbl 1269: if (home) {
1270: StrAllocCopy(my_home_document, home);
1.70 frystyk 1271: } else if (HTClientHost) { /* Telnet server */
1.12 timbl 1272: FILE * fp = fopen(REMOTE_POINTER, "r");
1273: char * status;
1274: if (fp) {
1.59 frystyk 1275: my_home_document = (char*) malloc(HT_MAX_PATH);
1276: status = fgets(my_home_document, HT_MAX_PATH, fp);
1.12 timbl 1277: if (!status) {
1278: free(my_home_document);
1279: my_home_document = NULL;
1280: }
1281: fclose(fp);
1282: }
1283: if (!my_home_document) StrAllocCopy(my_home_document, REMOTE_ADDRESS);
1284: }
1285:
1.67 frystyk 1286: #ifdef unix
1.10 timbl 1287: if (!my_home_document) {
1288: FILE * fp = NULL;
1.70 frystyk 1289: char * home = (char *) getenv("HOME");
1.10 timbl 1290: if (home) {
1291: my_home_document = (char *)malloc(
1292: strlen(home)+1+ strlen(PERSONAL_DEFAULT)+1);
1293: if (my_home_document == NULL) outofmem(__FILE__, "HTLocalName");
1294: sprintf(my_home_document, "%s/%s", home, PERSONAL_DEFAULT);
1295: fp = fopen(my_home_document, "r");
1296: }
1297:
1298: if (!fp) {
1299: StrAllocCopy(my_home_document, LOCAL_DEFAULT_FILE);
1300: fp = fopen(my_home_document, "r");
1301: }
1.2 timbl 1302: if (fp) {
1303: fclose(fp);
1304: } else {
1.62 frystyk 1305: if (TRACE)
1.67 frystyk 1306: fprintf(TDEST,
1.62 frystyk 1307: "HTBrowse: No local home document ~/%s or %s\n",
1308: PERSONAL_DEFAULT, LOCAL_DEFAULT_FILE);
1.11 timbl 1309: free(my_home_document);
1310: my_home_document = NULL;
1.2 timbl 1311: }
1312: }
1.67 frystyk 1313: #endif
1.70 frystyk 1314: ref = HTParse(my_home_document ? my_home_document :
1315: HTClientHost ? REMOTE_ADDRESS : LAST_RESORT, "file:",
1316: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1.10 timbl 1317: if (my_home_document) {
1.62 frystyk 1318: if (TRACE)
1.67 frystyk 1319: fprintf(TDEST,
1.62 frystyk 1320: "HTAccess.... `%s\' used for custom home page as\n`%s\'\n",
1321: my_home_document, ref);
1.10 timbl 1322: free(my_home_document);
1.2 timbl 1323: }
1324: anchor = (HTParentAnchor*) HTAnchor_findAddress(ref);
1325: free(ref);
1326: return anchor;
1.1 timbl 1327: }
1.26 frystyk 1328:
1329:
1330: /* Bind an Anchor to the request structure
1331: ** ---------------------------------------
1332: **
1333: ** On Entry,
1334: ** anchor The child or parenet anchor to be binded
1335: ** request The request sturcture
1336: ** On Exit,
1337: ** returns YES Success
1338: ** NO Failure
1339: **
1340: ** Note: Actually the same as HTLoadAnchor() but DOES NOT do the loading
1341: ** Henrik Frystyk 17/02-94
1342: */
1343:
1344: PUBLIC BOOL HTBindAnchor ARGS2(HTAnchor*, anchor, HTRequest *, request)
1345: {
1346: if (!anchor) return NO; /* No link */
1347:
1348: request->anchor = HTAnchor_parent(anchor);
1349: request->childAnchor = ((HTAnchor*)request->anchor == anchor) ? NULL
1350: : (HTChildAnchor*) anchor;
1351:
1.29 frystyk 1352: return YES;
1.70 frystyk 1353: }
1.59 frystyk 1354:
1.85 frystyk 1355: /* --------------------------------------------------------------------------*/
1.87 ! frystyk 1356: /* Flags and Other */
1.85 frystyk 1357: /* --------------------------------------------------------------------------*/
1358:
1359: /*
1360: ** Set the mode for how we handle Expires header from the local history
1361: ** list. The following modes are available:
1362: **
1363: ** HT_EXPIRES_IGNORE : No update in the history list
1364: ** HT_EXPIRES_NOTIFY : The user is notified but no reload
1365: ** HT_EXPIRES_AUTO : Automatic reload
1366: **
1367: ** The notify only makes sense when HT_EXPIRES_NOTIFY. NULL is valid.
1368: */
1369: PUBLIC void HTAccess_setExpiresMode ARGS2(HTExpiresMode, mode,
1370: char *, notify)
1371: {
1372: HTExpMode = mode;
1373: HTExpNotify = notify;
1374: }
1375:
1376: PUBLIC HTExpiresMode HTAccess_expiresMode ARGS1(char **, notify)
1377: {
1378: *notify = HTExpNotify ? HTExpNotify : "This version has expired!";
1379: return HTExpMode;
1380: }
1.26 frystyk 1381:
1.85 frystyk 1382: /*
1383: ** Set max number of automatic reload. Default is HT_MAX_RELOADS
1384: */
1385: PUBLIC void HTAccess_setMaxReload ARGS1(int, newmax)
1386: {
1387: if (newmax > 0)
1388: HTMaxReloads = newmax;
1389: }
1390:
1391: PUBLIC int HTAccess_maxReload NOARGS
1392: {
1393: return HTMaxReloads;
1.87 ! frystyk 1394: }
! 1395:
! 1396: /*
! 1397: ** Register a Memory Cache Handler. This function is introduced in order to
! 1398: ** avoid having references to HText module outside HTML.
! 1399: */
! 1400: PUBLIC BOOL HTMemoryCache_register ARGS1(HTMemoryCacheHandler, callback)
! 1401: {
! 1402: if (callback) {
! 1403: HTMemoryCache = callback;
! 1404: return YES;
! 1405: }
! 1406: return NO;
! 1407: }
! 1408:
! 1409: PUBLIC BOOL HTMemoryCache_unRegister NOARGS
! 1410: {
! 1411: HTMemoryCache = NULL;
! 1412: return YES;
1.85 frystyk 1413: }
Webmaster