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

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

Webmaster