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

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

Webmaster