Annotation of libwww/Library/src/HTAccess.c, revision 1.75.2.1

1.75.2.1! 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