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