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