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