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

1.1       timbl       1: /*             Access Manager                                  HTAccess.c
                      2: **             ==============
                      3: **
                      4: ** Authors
                      5: **     TBL     Tim Berners-Lee timbl@info.cern.ch
1.4       timbl       6: **     JFG     Jean-Francois Groff jfg@dxcern.cern.ch
1.1       timbl       7: **     DD      Denis DeLaRoca (310) 825-4580  <CSP1DWD@mvs.oac.ucla.edu>
                      8: ** History
                      9: **       8 Jun 92 Telnet hopping prohibited as telnet is not secure TBL
                     10: **     26 Jun 92 When over DECnet, suppressed FTP, Gopher and News. JFG
                     11: **      6 Oct 92 Moved HTClientHost and logfile into here. TBL
                     12: **     17 Dec 92 Tn3270 added, bug fix. DD
1.2       timbl      13: **      4 Feb 93 Access registration, Search escapes bad chars TBL
1.9       timbl      14: **               PARAMETERS TO HTSEARCH AND HTLOADRELATIVE CHANGED
                     15: **     28 May 93 WAIS gateway explicit if no WAIS library linked in.
1.19      timbl      16: **        Dec 93 Bug change around, more reentrant, etc
1.2       timbl      17: ** Bugs
                     18: **     This module assumes that that the graphic object is hypertext, as it
1.9       timbl      19: **     needs to select it when it has been loaded.  A superclass needs to be
1.2       timbl      20: **     defined which accepts select and select_anchor.
1.1       timbl      21: */
                     22: 
1.9       timbl      23: #ifndef DEFAULT_WAIS_GATEWAY
1.8       timbl      24: #define DEFAULT_WAIS_GATEWAY "http://info.cern.ch:8001/"
1.9       timbl      25: #endif
1.8       timbl      26: 
1.1       timbl      27: /* Implements:
                     28: */
                     29: #include "HTAccess.h"
                     30: 
                     31: /* Uses:
                     32: */
                     33: 
                     34: #include "HTParse.h"
                     35: #include "HTUtils.h"
1.4       timbl      36: #include "HTML.h"              /* SCW */
1.2       timbl      37: 
                     38: #ifndef NO_RULES
                     39: #include "HTRules.h"
                     40: #endif
                     41: 
1.1       timbl      42: #include <stdio.h>
                     43: 
1.2       timbl      44: #include "HTList.h"
                     45: #include "HText.h"     /* See bugs above */
                     46: #include "HTAlert.h"
1.17      timbl      47: #include "HTFWriter.h" /* for cache stuff */
                     48: #include "HTTee.h"
1.2       timbl      49: 
1.1       timbl      50: /*     These flags may be set to modify the operation of this module
                     51: */
                     52: PUBLIC char * HTClientHost = 0;        /* Name of remote login host if any */
                     53: PUBLIC FILE * logfile = 0;     /* File to which to output one-liners */
1.12      timbl      54: PUBLIC BOOL HTSecure = NO;     /* Disable access for telnet users? */
1.1       timbl      55: 
1.2       timbl      56: /*     To generate other things, play with these:
                     57: */
                     58: 
1.15      timbl      59: /* PUBLIC HTFormat HTOutputFormat = NULL;      use request->output_format */
                     60: /* PUBLIC HTStream* HTOutputStream = NULL;     use request->output_stream */ 
1.1       timbl      61: 
                     62: PRIVATE HTList * protocols = NULL;   /* List of registered protocol descriptors */
                     63: 
                     64: 
1.15      timbl      65: /*     Create  a request structure
                     66: **     ---------------------------
                     67: */
                     68: 
                     69: PUBLIC HTRequest * HTRequest_new NOARGS
                     70: {
                     71:     HTRequest * me = (HTRequest*) calloc(sizeof(*me), 1);  /* zero fill */
                     72:     if (!me) outofmem(__FILE__, "HTRequest_new()");
                     73:     
1.20      luotonen   74:     me->conversions    = HTList_new(); /* No conversions registerd yet */
                     75:     me->output_format  = WWW_PRESENT;  /* default it to present to user */
                     76:     me->scheme         = HTAA_NONE;
                     77: 
1.15      timbl      78:     return me;
                     79: }
                     80: 
                     81: 
1.20      luotonen   82: /*     Delete a request structure
                     83: **     --------------------------
                     84: */
                     85: PUBLIC void HTRequest_delete ARGS1(HTRequest *, req)
                     86: {
                     87:     if (req) {
                     88:        HTList *cur = req->conversions;
                     89:        HTPresentation *pres;
                     90: 
                     91:        while ((pres = (HTPresentation*)HTList_nextObject(cur)))
                     92:            free(pres);
                     93: 
                     94:        free(req);
                     95:     }
                     96: }
                     97: 
                     98: 
1.22    ! luotonen   99: PRIVATE char * method_names[(int)MAX_METHODS + 1] =
        !           100: {
        !           101:     "INVALID-METHOD",
        !           102:     "GET",
        !           103:     "HEAD",
        !           104:     "POST",
        !           105:     "PUT",
        !           106:     "DELETE",
        !           107:     "CHECKOUT",
        !           108:     "CHECKIN",
        !           109:     "SHOWMETHOD",
        !           110:     "LINK",
        !           111:     "UNLINK",
        !           112:     NULL
        !           113: };
        !           114: 
        !           115: /*     Get method enum value
        !           116: **     ---------------------
        !           117: */
        !           118: PUBLIC HTMethod HTMethod_enum ARGS1(char *, name)
        !           119: {
        !           120:     if (name) {
        !           121:        int i;
        !           122:        for (i=1; i < (int)MAX_METHODS; i++)
        !           123:            if (!strcmp(name, method_names[i]))
        !           124:                return (HTMethod)i;
        !           125:     }
        !           126:     return METHOD_INVALID;
        !           127: }
        !           128: 
        !           129: 
        !           130: /*     Get method name
        !           131: **     ---------------
        !           132: */
        !           133: PUBLIC char * HTMethod_name ARGS1(HTMethod, method)
        !           134: {
        !           135:     if ((int)method > (int)METHOD_INVALID  && 
        !           136:        (int)method < (int)MAX_METHODS)
        !           137:        return method_names[(int)method];
        !           138:     else
        !           139:        return method_names[(int)METHOD_INVALID];
        !           140: }
        !           141: 
        !           142: 
        !           143: /*     Is method in a list of method names?
        !           144: **     -----------------------------------
        !           145: */
        !           146: PUBLIC BOOL HTMethod_inList ARGS2(HTMethod,    method,
        !           147:                                  HTList *,     list)
        !           148: {
        !           149:     char * method_name = HTMethod_name(method);
        !           150:     HTList *cur = list;
        !           151:     char *item;
        !           152: 
        !           153:     while (NULL != (item = (char*)HTList_nextObject(cur))) {
        !           154:        CTRACE(stderr, " %s", item);
        !           155:        if (0==strcasecomp(item, method_name))
        !           156:            return YES;
        !           157:     }
        !           158:     return NO; /* Not found */
        !           159: }
        !           160: 
        !           161: 
        !           162: 
        !           163: 
1.20      luotonen  164: 
1.1       timbl     165: /*     Register a Protocol                             HTRegisterProtocol
                    166: **     -------------------
                    167: */
                    168: 
                    169: PUBLIC BOOL HTRegisterProtocol(protocol)
                    170:        HTProtocol * protocol;
                    171: {
                    172:     if (!protocols) protocols = HTList_new();
                    173:     HTList_addObject(protocols, protocol);
                    174:     return YES;
                    175: }
                    176: 
                    177: 
                    178: /*     Register all known protocols
                    179: **     ----------------------------
                    180: **
                    181: **     Add to or subtract from this list if you add or remove protocol modules.
                    182: **     This routine is called the first time the protocol list is needed,
                    183: **     unless any protocols are already registered, in which case it is not called.
                    184: **     Therefore the application can override this list.
                    185: **
                    186: **     Compiling with NO_INIT prevents all known protocols from being forced
                    187: **     in at link time.
                    188: */
                    189: #ifndef NO_INIT
                    190: PRIVATE void HTAccessInit NOARGS                       /* Call me once */
                    191: {
1.14      duns      192: GLOBALREF HTProtocol HTTP, HTFile, HTTelnet, HTTn3270, HTRlogin;
1.1       timbl     193: #ifndef DECNET
1.14      duns      194: GLOBALREF  HTProtocol HTFTP, HTNews, HTGopher;
1.3       timbl     195: #ifdef DIRECT_WAIS
1.14      duns      196: GLOBALREF  HTProtocol HTWAIS;
1.3       timbl     197: #endif
1.2       timbl     198:     HTRegisterProtocol(&HTFTP);
                    199:     HTRegisterProtocol(&HTNews);
                    200:     HTRegisterProtocol(&HTGopher);
1.3       timbl     201: #ifdef DIRECT_WAIS
                    202:     HTRegisterProtocol(&HTWAIS);
                    203: #endif
1.1       timbl     204: #endif
                    205: 
1.2       timbl     206:     HTRegisterProtocol(&HTTP);
                    207:     HTRegisterProtocol(&HTFile);
                    208:     HTRegisterProtocol(&HTTelnet);
                    209:     HTRegisterProtocol(&HTTn3270);
                    210:     HTRegisterProtocol(&HTRlogin);
1.1       timbl     211: }
                    212: #endif
                    213: 
                    214: 
1.2       timbl     215: /*             Find physical name and access protocol
                    216: **             --------------------------------------
1.1       timbl     217: **
                    218: **
                    219: ** On entry,
                    220: **     addr            must point to the fully qualified hypertext reference.
                    221: **     anchor          a pareent anchor with whose address is addr
                    222: **
                    223: ** On exit,
1.2       timbl     224: **     returns         HT_NO_ACCESS            Error has occured.
                    225: **                     HT_OK                   Success
1.1       timbl     226: **
                    227: */
1.21      luotonen  228: PRIVATE int get_physical ARGS1(HTRequest *, req)
                    229: {    
1.1       timbl     230:     char * access=0;   /* Name of access method */
1.2       timbl     231:     char * physical = 0;
1.21      luotonen  232:     char * addr = HTAnchor_address((HTAnchor*)req->anchor);    /* free me */
1.1       timbl     233:     
1.2       timbl     234: #ifndef NO_RULES
1.22    ! luotonen  235:     if (req->translated)
1.21      luotonen  236:        HTAnchor_setPhysical(req->anchor, req->translated);
                    237:     else {
                    238:        physical = HTTranslate(addr);
                    239:        if (!physical) {
                    240:            free(addr);
                    241:            return HT_FORBIDDEN;
                    242:        }
                    243:        HTAnchor_setPhysical(req->anchor, physical);
                    244:        free(physical);                 /* free our copy */
1.2       timbl     245:     }
                    246: #else
1.21      luotonen  247:     HTAnchor_setPhysical(req->anchor, addr);
1.2       timbl     248: #endif
                    249: 
1.21      luotonen  250:     access =  HTParse(HTAnchor_physical(req->anchor),
1.2       timbl     251:                "file:", PARSE_ACCESS);
1.1       timbl     252: 
                    253: /*     Check whether gateway access has been set up for this
1.8       timbl     254: **
                    255: **     This function can be replaced by the rule system above.
1.1       timbl     256: */
1.8       timbl     257: #define USE_GATEWAYS
1.1       timbl     258: #ifdef USE_GATEWAYS
1.2       timbl     259:     {
1.9       timbl     260:        char * gateway_parameter, *gateway;
1.2       timbl     261:        gateway_parameter = (char *)malloc(strlen(access)+20);
                    262:        if (gateway_parameter == NULL) outofmem(__FILE__, "HTLoad");
                    263:        strcpy(gateway_parameter, "WWW_");
                    264:        strcat(gateway_parameter, access);
                    265:        strcat(gateway_parameter, "_GATEWAY");
                    266:        gateway = (char *)getenv(gateway_parameter); /* coerce for decstation */
                    267:        free(gateway_parameter);
1.8       timbl     268:        
                    269: #ifndef DIRECT_WAIS
1.9       timbl     270:        if (!gateway && 0==strcmp(access, "wais")) {
1.8       timbl     271:            gateway = DEFAULT_WAIS_GATEWAY;
                    272:        }
                    273: #endif
1.2       timbl     274:        if (gateway) {
1.9       timbl     275:            char * path = HTParse(addr, "",
                    276:                PARSE_HOST + PARSE_PATH + PARSE_PUNCTUATION);
                    277:                /* Chop leading / off to make host into part of path */
                    278:            char * gatewayed = HTParse(path+1, gateway, PARSE_ALL);
                    279:            free(path);
1.21      luotonen  280:             HTAnchor_setPhysical(req->anchor, gatewayed);
1.9       timbl     281:            free(gatewayed);
1.2       timbl     282:            free(access);
1.9       timbl     283:            
1.21      luotonen  284:            access =  HTParse(HTAnchor_physical(req->anchor),
1.8       timbl     285:                "http:", PARSE_ACCESS);
1.2       timbl     286:        }
                    287:     }
1.1       timbl     288: #endif
                    289: 
1.19      timbl     290:     free(addr);
1.1       timbl     291: 
                    292: 
                    293: /*     Search registered protocols to find suitable one
                    294: */
                    295:     {
1.20      luotonen  296:        HTList *cur;
                    297:        HTProtocol *p;
1.1       timbl     298: #ifndef NO_INIT
1.2       timbl     299:         if (!protocols) HTAccessInit();
1.1       timbl     300: #endif
1.20      luotonen  301:        cur = protocols;
                    302:        while ((p = (HTProtocol*)HTList_nextObject(cur))) {
1.2       timbl     303:            if (strcmp(p->name, access)==0) {
1.21      luotonen  304:                HTAnchor_setProtocol(req->anchor, p);
1.2       timbl     305:                free(access);
                    306:                return (HT_OK);
1.1       timbl     307:            }
                    308:        }
                    309:     }
                    310: 
                    311:     free(access);
1.2       timbl     312:     return HT_NO_ACCESS;
1.1       timbl     313: }
                    314: 
                    315: 
                    316: /*             Load a document
                    317: **             ---------------
                    318: **
1.2       timbl     319: **     This is an internal routine, which has an address AND a matching
                    320: **     anchor.  (The public routines are called with one OR the other.)
                    321: **
                    322: ** On entry,
                    323: **     addr            must point to the fully qualified hypertext reference.
1.15      timbl     324: **     request->
                    325: **         anchor              a parent anchor with whose address is addr
                    326: **         output_format       valid
                    327: **         output_stream       valid on NULL
1.2       timbl     328: **
                    329: ** On exit,
                    330: **     returns         <0              Error has occured.
                    331: **                     HT_LOADED       Success
                    332: **                     HT_NO_DATA      Success, but no document loaded.
1.8       timbl     333: **                                     (telnet sesssion started etc)
1.2       timbl     334: **
                    335: */
1.15      timbl     336: PRIVATE int HTLoad ARGS2(
1.19      timbl     337:        CONST char *,           addr,   /* not used */
1.15      timbl     338:        HTRequest *,            request)
1.2       timbl     339: {
                    340:     HTProtocol* p;
1.19      timbl     341:     int status;
1.22    ! luotonen  342:     if (request->method == METHOD_INVALID)
        !           343:        request->method = METHOD_GET;
1.21      luotonen  344:     status = get_physical(request);
1.2       timbl     345:     if (status == HT_FORBIDDEN) {
1.21      luotonen  346:         return HTLoadError(request, 500,
                    347:                           "Access forbidden by rule");
1.2       timbl     348:     }
                    349:     if (status < 0) return status;     /* Can't resolve or forbidden */
                    350:     
1.15      timbl     351:     p = HTAnchor_protocol(request->anchor);
1.17      timbl     352:     return (*(p->load))(request);
1.2       timbl     353: }
                    354: 
                    355: 
                    356: /*             Get a save stream for a document
                    357: **             --------------------------------
                    358: */
1.19      timbl     359: PUBLIC HTStream *HTSaveStream ARGS1(HTRequest *, request)
1.15      timbl     360: {
                    361:     HTProtocol * p;
1.19      timbl     362:     int status;
1.22    ! luotonen  363:     request->method = METHOD_PUT;
1.21      luotonen  364:     status = get_physical(request);
1.19      timbl     365:     if (status == HT_FORBIDDEN) {
1.21      luotonen  366:         HTLoadError(request, 500,
                    367:                    "Access forbidden by rule");
1.19      timbl     368:        return NULL;    /* should return error status? */
                    369:     }
                    370:     if (status < 0) return NULL; /* @@ error. Can't resolve or forbidden */
                    371:     
1.15      timbl     372:     p = HTAnchor_protocol(request->anchor);
1.2       timbl     373:     if (!p) return NULL;
                    374:     
1.15      timbl     375:     return (*p->saveStream)(request);
1.2       timbl     376:     
                    377: }
                    378: 
                    379: 
                    380: /*             Load a document - with logging etc
                    381: **             ----------------------------------
                    382: **
                    383: **     - Checks or documents already loaded
                    384: **     - Logs the access
                    385: **     - Allows stdin filter option
                    386: **     - Trace ouput and error messages
                    387: **
1.1       timbl     388: **    On Entry,
1.19      timbl     389: **        request->anchor      valid for of the document to be accessed.
                    390: **      request->childAnchor   optional anchor within doc to be selected
                    391: **
1.2       timbl     392: **        filter            if YES, treat stdin as HTML
1.1       timbl     393: **
1.15      timbl     394: **       request->anchor   is the node_anchor for the document
                    395: **       request->output_format is valid
                    396: **
1.1       timbl     397: **    On Exit,
                    398: **        returns    YES     Success in opening document
                    399: **                   NO      Failure 
                    400: **
                    401: */
                    402: 
1.19      timbl     403: PRIVATE BOOL HTLoadDocument ARGS1(HTRequest *,         request)
1.1       timbl     404: 
                    405: {
                    406:     int                status;
                    407:     HText *    text;
1.19      timbl     408:     char * full_address = HTAnchor_address((HTAnchor*)request->anchor);
                    409:     
1.1       timbl     410:     if (TRACE) fprintf (stderr,
                    411:       "HTAccess: loading document %s\n", full_address);
                    412: 
1.18      timbl     413:     request->using_cache = NULL;
                    414:     
1.15      timbl     415:     if (!request->output_format) request->output_format = WWW_PRESENT;
                    416:     
1.20      luotonen  417:     if ((text=(HText *)HTAnchor_document(request->anchor)))
1.15      timbl     418:     {  /* Already loaded */
1.1       timbl     419:         if (TRACE) fprintf(stderr, "HTAccess: Document already in memory.\n");
1.19      timbl     420:        if (request->childAnchor) {
                    421:            HText_selectAnchor(text, request->childAnchor);
                    422:        } else {
                    423:            HText_select(text); 
                    424:        }
                    425:        free(full_address);
1.1       timbl     426:        return YES;
                    427:     }
1.17      timbl     428:     
                    429:     /* Check the Cache
                    430:     */
                    431:     /* Bug: for each format, we only check whether it is ok, we
                    432:        don't check them all and chose the best */
                    433:     if (request->anchor->cacheItems) {
                    434:         HTList * list = request->anchor->cacheItems;
1.20      luotonen  435:        HTList * cur = list;
                    436:        HTCacheItem * item;
                    437: 
                    438:        while ((item = (HTCacheItem*)HTList_nextObject(cur))) {
1.18      timbl     439:            HTStream * s;
                    440:            
                    441:            request->using_cache = item;
                    442:            
                    443:            s = HTStreamStack(item->format, request);
1.17      timbl     444:            if (s) {            /* format was suitable */
                    445:                FILE * fp = fopen(item->filename, "r");
1.18      timbl     446:                if (TRACE) fprintf(stderr, "Cache: HIT file %s for %s\n",
1.20      luotonen  447:                                   item->filename, 
                    448:                                   full_address);
1.17      timbl     449:                if (fp) {
                    450:                    HTFileCopy(fp, s);
                    451:                    fclose(fp);
1.19      timbl     452:                    free(full_address);
1.17      timbl     453:                    return YES;
                    454:                } else {
                    455:                    fprintf(stderr, "***** Can't read cache file %s !\n",
1.20      luotonen  456:                            item->filename);
1.17      timbl     457:                } /* file open ok */
                    458:            } /* stream ok */
                    459:        } /* next cache item */
                    460:     } /* if cache available for this anchor */
1.1       timbl     461:     
1.15      timbl     462:     status = HTLoad(full_address, request);
1.2       timbl     463: 
                    464:     
1.1       timbl     465: /*     Log the access if necessary
                    466: */
                    467:     if (logfile) {
                    468:        time_t theTime;
                    469:        time(&theTime);
                    470:        fprintf(logfile, "%24.24s %s %s %s\n",
                    471:            ctime(&theTime),
                    472:            HTClientHost ? HTClientHost : "local",
                    473:            status<0 ? "FAIL" : "GET",
                    474:            full_address);
                    475:        fflush(logfile);        /* Actually update it on disk */
                    476:        if (TRACE) fprintf(stderr, "Log: %24.24s %s %s %s\n",
                    477:            ctime(&theTime),
                    478:            HTClientHost ? HTClientHost : "local",
                    479:            status<0 ? "FAIL" : "GET",
                    480:            full_address);
                    481:     }
                    482:     
                    483: 
                    484:     if (status == HT_LOADED) {
                    485:        if (TRACE) {
                    486:            fprintf(stderr, "HTAccess: `%s' has been accessed.\n",
                    487:            full_address);
                    488:        }
1.19      timbl     489:        free(full_address);
1.1       timbl     490:        return YES;
                    491:     }
                    492:     
                    493:     if (status == HT_NO_DATA) {
                    494:        if (TRACE) {
                    495:            fprintf(stderr, 
                    496:            "HTAccess: `%s' has been accessed, No data left.\n",
                    497:            full_address);
                    498:        }
1.19      timbl     499:        free(full_address);
1.1       timbl     500:        return NO;
                    501:     }
                    502:     
1.2       timbl     503:     if (status<0) {                  /* Failure in accessing a document */
1.1       timbl     504: #ifdef CURSES
                    505:         user_message("Can't access `%s'", full_address);
                    506: #else
1.5       timbl     507:        if (TRACE) fprintf(stderr, 
                    508:                "HTAccess: Can't access `%s'\n", full_address);
1.1       timbl     509: #endif
1.21      luotonen  510:        HTLoadError(request, 500, "Unable to access document.");
1.19      timbl     511:        free(full_address);
1.1       timbl     512:        return NO;
                    513:     }
1.9       timbl     514:  
                    515:     /* If you get this, then please find which routine is returning
                    516:        a positive unrecognised error code! */
                    517:  
1.1       timbl     518:     fprintf(stderr,
1.2       timbl     519:     "**** HTAccess: socket or file number returned by obsolete load routine!\n");
1.9       timbl     520:     fprintf(stderr,
1.19      timbl     521:     "**** HTAccess: Internal software error. Please mail www-bug@info.cern.ch quoting the version number of this software and the URL: %s!\n",
                    522:        full_address);
                    523:     free(full_address);
                    524:    
1.1       timbl     525:     exit(-6996);
1.20      luotonen  526:     return NO; /* For gcc :-( */
1.2       timbl     527: } /* HTLoadDocument */
1.1       timbl     528: 
                    529: 
                    530: 
                    531: /*             Load a document from absolute name
                    532: **             ---------------
                    533: **
                    534: **    On Entry,
                    535: **        addr     The absolute address of the document to be accessed.
                    536: **        filter   if YES, treat document as HTML
                    537: **
                    538: **    On Exit,
                    539: **        returns    YES     Success in opening document
                    540: **                   NO      Failure 
                    541: **
                    542: **
                    543: */
                    544: 
1.15      timbl     545: PUBLIC BOOL HTLoadAbsolute ARGS2(CONST char *,addr, HTRequest*, request)
1.2       timbl     546: {
1.19      timbl     547:    HTAnchor * anchor = HTAnchor_findAddress(addr);
                    548:    request->anchor = HTAnchor_parent(anchor);
                    549:    request->childAnchor = ((HTAnchor*)request->anchor == anchor) ?
                    550:                        NULL : (HTChildAnchor*) anchor;
                    551:    return HTLoadDocument(request);
1.2       timbl     552: }
                    553: 
                    554: 
                    555: /*             Load a document from absolute name to stream
                    556: **             --------------------------------------------
                    557: **
                    558: **    On Entry,
                    559: **        addr     The absolute address of the document to be accessed.
1.15      timbl     560: **        request->output_stream     if non-NULL, send data down this stream
1.2       timbl     561: **
                    562: **    On Exit,
                    563: **        returns    YES     Success in opening document
                    564: **                   NO      Failure 
                    565: **
                    566: **
                    567: */
                    568: 
                    569: PUBLIC BOOL HTLoadToStream ARGS3(
                    570:                CONST char *,   addr,
                    571:                BOOL,           filter,
1.15      timbl     572:                HTRequest*,     request)
1.1       timbl     573: {
1.19      timbl     574:    HTAnchor * anchor = HTAnchor_findAddress(addr);
                    575:    request->anchor = HTAnchor_parent(anchor);
                    576:    request->childAnchor = ((HTAnchor*)request->anchor == anchor) ? NULL :
                    577:        (HTChildAnchor*) anchor;
1.15      timbl     578:     request->output_stream = request->output_stream;
1.19      timbl     579:     return HTLoadDocument(request);
1.1       timbl     580: }
                    581: 
                    582: 
1.2       timbl     583: 
                    584: 
1.1       timbl     585: /*             Load a document from relative name
                    586: **             ---------------
                    587: **
                    588: **    On Entry,
1.2       timbl     589: **        relative_name     The relative address of the document
                    590: **                         to be accessed.
1.1       timbl     591: **
                    592: **    On Exit,
                    593: **        returns    YES     Success in opening document
                    594: **                   NO      Failure 
                    595: **
                    596: **
                    597: */
                    598: 
1.15      timbl     599: PUBLIC BOOL HTLoadRelative ARGS3(
1.2       timbl     600:                CONST char *,           relative_name,
1.15      timbl     601:                HTParentAnchor *,       here,
1.20      luotonen  602:                HTRequest *,            request)
1.1       timbl     603: {
                    604:     char *             full_address = 0;
                    605:     BOOL                       result;
                    606:     char *             mycopy = 0;
                    607:     char *             stripped = 0;
                    608:     char *             current_address =
1.2       timbl     609:                                HTAnchor_address((HTAnchor*)here);
1.1       timbl     610: 
                    611:     StrAllocCopy(mycopy, relative_name);
                    612: 
                    613:     stripped = HTStrip(mycopy);
                    614:     full_address = HTParse(stripped,
                    615:                   current_address,
                    616:                   PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1.15      timbl     617:     result = HTLoadAbsolute(full_address, request);
1.1       timbl     618:     free(full_address);
                    619:     free(current_address);
                    620:     free(mycopy);  /* Memory leak fixed 10/7/92 -- JFG */
                    621:     return result;
                    622: }
                    623: 
                    624: 
                    625: /*             Load if necessary, and select an anchor
                    626: **             --------------------------------------
                    627: **
                    628: **    On Entry,
                    629: **        destination              The child or parenet anchor to be loaded.
                    630: **
                    631: **    On Exit,
                    632: **        returns    YES     Success
                    633: **                   NO      Failure 
                    634: **
                    635: */
                    636: 
1.15      timbl     637: PUBLIC BOOL HTLoadAnchor ARGS2(HTAnchor*, anchor, HTRequest *, request)
1.1       timbl     638: {
1.15      timbl     639:     if (!anchor) return NO;    /* No link */
1.1       timbl     640:     
1.15      timbl     641:     request->anchor  = HTAnchor_parent(anchor);
1.19      timbl     642:     request->childAnchor = ((HTAnchor*)request->anchor == anchor) ? NULL
                    643:                                        : (HTChildAnchor*) anchor;
1.1       timbl     644:     
1.19      timbl     645:     return HTLoadDocument(request) ? YES : NO;
1.1       timbl     646:        
                    647: } /* HTLoadAnchor */
                    648: 
                    649: 
                    650: /*             Search
                    651: **             ------
                    652: **  Performs a keyword search on word given by the user. Adds the keyword to 
                    653: **  the end of the current address and attempts to open the new address.
                    654: **
                    655: **  On Entry,
                    656: **       *keywords     space-separated keyword list or similar search list
1.2       timbl     657: **     here            is anchor search is to be done on.
1.1       timbl     658: */
                    659: 
1.2       timbl     660: PRIVATE char hex(i)
                    661:     int i;
                    662: {
1.13      timbl     663:     char * hexchars = "0123456789ABCDEF";
                    664:     return hexchars[i];
1.2       timbl     665: }
1.1       timbl     666: 
1.15      timbl     667: PUBLIC BOOL HTSearch ARGS3(
1.2       timbl     668:        CONST char *,           keywords,
1.15      timbl     669:        HTParentAnchor *,       here,
                    670:        HTRequest *,            request)
1.1       timbl     671: {
1.2       timbl     672: 
                    673: #define acceptable \
                    674: "1234567890abcdefghijlkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_"
                    675: 
                    676:     char *q, *u;
                    677:     CONST char * p, *s, *e;            /* Pointers into keywords */
                    678:     char * address = HTAnchor_address((HTAnchor*)here);
1.1       timbl     679:     BOOL result;
1.2       timbl     680:     char * escaped = malloc(strlen(keywords)*3+1);
                    681: 
                    682:     static CONST BOOL isAcceptable[96] =
                    683: 
                    684:     /*   0 1 2 3 4 5 6 7 8 9 A B C D E F */
                    685:     {    0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,0,      /* 2x   !"#$%&'()*+,-./  */
                    686:          1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,      /* 3x  0123456789:;<=>?  */
                    687:         1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,       /* 4x  @ABCDEFGHIJKLMNO  */
                    688:         1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,       /* 5X  PQRSTUVWXYZ[\]^_  */
                    689:         0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,       /* 6x  `abcdefghijklmno  */
                    690:         1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0 };     /* 7X  pqrstuvwxyz{\}~  DEL */
                    691: 
                    692:     if (escaped == NULL) outofmem(__FILE__, "HTSearch");
                    693:     
                    694: 
                    695: /*     Convert spaces to + and hex escape unacceptable characters
                    696: */
                    697:     for(s=keywords; *s && WHITE(*s); s++) /*scan */ ;  /* Skip white space */
                    698:     for(e = s + strlen(s); e>s && WHITE(*(e-1)) ; e--); /* Skip trailers */
                    699:     for(q=escaped, p=s; p<e; p++) {                    /* scan stripped field */
                    700:         int c = (int)TOASCII(*p);
                    701:         if (WHITE(*p)) {
                    702:            *q++ = '+';
                    703:        } else if (c>=32 && c<=(char)127 && isAcceptable[c-32]) {
1.13      timbl     704:            *q++ = *p;                  /* 930706 TBL for MVS bug */
1.2       timbl     705:        } else {
                    706:            *q++ = '%';
                    707:            *q++ = hex(c / 16);
                    708:            *q++ = hex(c % 16);
                    709:        }
                    710:     } /* Loop over string */
1.1       timbl     711:     
1.2       timbl     712:     *q=0;
                    713:                                /* terminate escaped sctring */
                    714:     u=strchr(address, '?');            /* Find old search string */
                    715:     if (u) *u = 0;                             /* Chop old search off */
1.1       timbl     716: 
                    717:     StrAllocCat(address, "?");
1.2       timbl     718:     StrAllocCat(address, escaped);
                    719:     free(escaped);
1.15      timbl     720:     result = HTLoadRelative(address, here, request);
1.1       timbl     721:     free(address);
1.2       timbl     722:     
1.1       timbl     723:     return result;
1.2       timbl     724: }
                    725: 
                    726: 
                    727: /*             Search Given Indexname
                    728: **             ------
                    729: **  Performs a keyword search on word given by the user. Adds the keyword to 
                    730: **  the end of the current address and attempts to open the new address.
                    731: **
                    732: **  On Entry,
                    733: **       *keywords     space-separated keyword list or similar search list
                    734: **     *addres         is name of object search is to be done on.
                    735: */
                    736: 
1.15      timbl     737: PUBLIC BOOL HTSearchAbsolute ARGS3(
1.2       timbl     738:        CONST char *,   keywords,
1.15      timbl     739:        CONST char *,   indexname,
                    740:        HTRequest *,    request)
1.2       timbl     741: {
                    742:     HTParentAnchor * anchor =
                    743:        (HTParentAnchor*) HTAnchor_findAddress(indexname);
1.15      timbl     744:     return HTSearch(keywords, anchor, request);
1.2       timbl     745: }
                    746: 
                    747: 
                    748: /*             Generate the anchor for the home page
                    749: **             -------------------------------------
                    750: **
                    751: **     As it involves file access, this should only be done once
                    752: **     when the program first runs.
1.10      timbl     753: **     This is a default algorithm -- browser don't HAVE to use this.
                    754: **     But consistency betwen browsers is STRONGLY recommended!
1.2       timbl     755: **
1.10      timbl     756: **     Priority order is:
                    757: **
                    758: **             1       WWW_HOME environment variable (logical name, etc)
                    759: **             2       ~/WWW/default.html
                    760: **             3       /usr/local/bin/default.html
                    761: **             4       http://info.cern.ch/default.html
                    762: **
1.2       timbl     763: */
                    764: PUBLIC HTParentAnchor * HTHomeAnchor NOARGS
                    765: {
1.12      timbl     766:     char * my_home_document = NULL;
                    767:     char * home = (char *)getenv(LOGICAL_DEFAULT);
1.2       timbl     768:     char * ref;
                    769:     HTParentAnchor * anchor;
1.1       timbl     770:     
1.12      timbl     771:     if (home) {
                    772:         StrAllocCopy(my_home_document, home);
                    773:     
                    774: /*     Someone telnets in, they get a special home.
                    775: */
                    776: #define MAX_FILE_NAME 1024                                     /* @@@ */
                    777:     } else  if (HTClientHost) {                        /* Telnet server */
                    778:        FILE * fp = fopen(REMOTE_POINTER, "r");
                    779:        char * status;
                    780:        if (fp) {
                    781:            my_home_document = (char*) malloc(MAX_FILE_NAME);
                    782:            status = fgets(my_home_document, MAX_FILE_NAME, fp);
                    783:            if (!status) {
                    784:                free(my_home_document);
                    785:                my_home_document = NULL;
                    786:            }
                    787:            fclose(fp);
                    788:        }
                    789:        if (!my_home_document) StrAllocCopy(my_home_document, REMOTE_ADDRESS);
                    790:     }
                    791: 
                    792:     
                    793: 
1.2       timbl     794: #ifdef unix
1.12      timbl     795: 
1.10      timbl     796:     if (!my_home_document) {
                    797:        FILE * fp = NULL;
                    798:        CONST char * home =  (CONST char*)getenv("HOME");
                    799:        if (home) { 
                    800:            my_home_document = (char *)malloc(
                    801:                strlen(home)+1+ strlen(PERSONAL_DEFAULT)+1);
                    802:            if (my_home_document == NULL) outofmem(__FILE__, "HTLocalName");
                    803:            sprintf(my_home_document, "%s/%s", home, PERSONAL_DEFAULT);
                    804:            fp = fopen(my_home_document, "r");
                    805:        }
                    806:        
                    807:        if (!fp) {
                    808:            StrAllocCopy(my_home_document, LOCAL_DEFAULT_FILE);
                    809:            fp = fopen(my_home_document, "r");
                    810:        }
1.2       timbl     811:        if (fp) {
                    812:            fclose(fp);
                    813:        } else {
                    814:        if (TRACE) fprintf(stderr,
1.10      timbl     815:            "HTBrowse: No local home document ~/%s or %s\n",
                    816:            PERSONAL_DEFAULT, LOCAL_DEFAULT_FILE);
1.11      timbl     817:            free(my_home_document);
                    818:            my_home_document = NULL;
1.2       timbl     819:        }
                    820:     }
                    821: #endif
1.10      timbl     822:     ref = HTParse( my_home_document ?  my_home_document :
                    823:                                HTClientHost ? REMOTE_ADDRESS
                    824:                                : LAST_RESORT,
                    825:                    "file:",
1.2       timbl     826:                    PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1.10      timbl     827:     if (my_home_document) {
1.2       timbl     828:        if (TRACE) fprintf(stderr,
                    829:            "HTAccess: Using custom home page %s i.e. address %s\n",
1.10      timbl     830:            my_home_document, ref);
                    831:        free(my_home_document);
1.2       timbl     832:     }
                    833:     anchor = (HTParentAnchor*) HTAnchor_findAddress(ref);
                    834:     free(ref);
                    835:     return anchor;
1.1       timbl     836: }
                    837: 
                    838: 

Webmaster