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

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.84    ! frystyk    41: #include "HTFWrite.h"
        !            42: #include "HTCache.h"
1.70      frystyk    43: #include "HTLog.h"
1.77      frystyk    44: #include "HTSocket.h"
1.57      howcome    45: #include "HTTCP.h"      /* HWL: for HTFindRelatedName */
1.59      frystyk    46: #include "HTThread.h"
1.83      frystyk    47: #include "HTEvntrg.h"
1.73      frystyk    48: #include "HTBind.h"
1.81      frystyk    49: #include "HTProt.h"
1.70      frystyk    50: #include "HTInit.h"
1.77      frystyk    51: #include "HTProxy.h"
1.78      frystyk    52: #include "HTML.h"              /* SCW */
                     53: #include "HText.h"     /* See bugs above */
1.74      frystyk    54: 
1.67      frystyk    55: #ifndef NO_RULES
                     56: #include "HTRules.h"
                     57: #endif
1.74      frystyk    58: 
1.67      frystyk    59: #include "HTAccess.h"                                   /* Implemented here */
1.2       timbl      60: 
1.54      frystyk    61: /* These flags may be set to modify the operation of this module */
1.73      frystyk    62: PUBLIC int  HTMaxRedirections = 10;           /* Max number of redirections */
                     63: 
1.78      frystyk    64: PUBLIC char * HTClientHost = NULL;      /* Name of remote login host if any */
1.70      frystyk    65: PUBLIC BOOL HTSecure = NO;              /* Disable access for telnet users? */
1.41      luotonen   66: 
1.43      luotonen   67: PUBLIC char * HTImServer = NULL;/* cern_httpd sets this to the translated URL*/
1.70      frystyk    68: PUBLIC BOOL HTImProxy = NO;                       /* cern_httpd as a proxy? */
1.1       timbl      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 */
        !           100:     me->ForceReload = HT_NO_UPDATE;
        !           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.84    ! frystyk   503:     ** Check local the Disk Cache (if we are not forced to reload), then
        !           504:     ** for proxy, and finally gateways
1.77      frystyk   505:     */
                    506:     {
1.84    ! frystyk   507:        char *newaddr;
        !           508:        if (req->ForceReload != HT_UPDATE_DISK &&
        !           509:            (newaddr = HTCache_getObject(addr))) {
        !           510:            HTAnchor_setPhysical(req->anchor, newaddr);
        !           511:            HTAnchor_setCacheHit(req->anchor, YES);
        !           512:            free(newaddr);
        !           513:        } else if ((newaddr = HTProxy_getProxy(addr))) {
        !           514:            StrAllocCat(newaddr, addr);
1.70      frystyk   515:            req->using_proxy = YES;
1.84    ! frystyk   516:            HTAnchor_setPhysical(req->anchor, newaddr);
        !           517:            free(newaddr);
        !           518:        } else if ((newaddr = HTProxy_getGateway(addr))) {
1.9       timbl     519:            char * path = HTParse(addr, "",
1.77      frystyk   520:                                  PARSE_HOST + PARSE_PATH + PARSE_PUNCTUATION);
1.9       timbl     521:                /* Chop leading / off to make host into part of path */
1.84    ! frystyk   522:            char * gatewayed = HTParse(path+1, newaddr, PARSE_ALL);
1.77      frystyk   523:             HTAnchor_setPhysical(req->anchor, gatewayed);
1.9       timbl     524:            free(path);
                    525:            free(gatewayed);
1.84    ! frystyk   526:            free(newaddr);
1.77      frystyk   527:        } else {
                    528:            req->using_proxy = NO;          /* We don't use proxy or gateway */
1.2       timbl     529:        }
                    530:     }
1.77      frystyk   531:     FREE(addr);
1.1       timbl     532: 
1.81      frystyk   533:     /* Set the access scheme on our way out */
1.82      frystyk   534:     return (HTProtocol_get(req->anchor)==YES) ? HT_OK : HT_NO_ACCESS;
1.1       timbl     535: }
                    536: 
1.59      frystyk   537: /* --------------------------------------------------------------------------*/
                    538: /*                             Document Loader                              */
                    539: /* --------------------------------------------------------------------------*/
1.1       timbl     540: 
                    541: /*             Load a document
                    542: **             ---------------
                    543: **
1.2       timbl     544: **     This is an internal routine, which has an address AND a matching
                    545: **     anchor.  (The public routines are called with one OR the other.)
                    546: **
                    547: ** On entry,
1.15      timbl     548: **     request->
1.35      luotonen  549: **         anchor              a parent anchor with fully qualified
                    550: **                             hypertext reference as its address set
1.15      timbl     551: **         output_format       valid
                    552: **         output_stream       valid on NULL
1.2       timbl     553: **
                    554: ** On exit,
1.59      frystyk   555: **     returns         HT_WOULD_BLOCK  An I/O operation would block
                    556: **                     HT_ERROR        Error has occured
1.2       timbl     557: **                     HT_LOADED       Success
                    558: **                     HT_NO_DATA      Success, but no document loaded.
1.8       timbl     559: **                                     (telnet sesssion started etc)
1.72      frystyk   560: **                     HT_RETRY        if service isn't available before
                    561: **                                     request->retry_after
1.2       timbl     562: */
1.52      frystyk   563: PUBLIC int HTLoad ARGS2(HTRequest *, request, BOOL, keep_error_stack)
1.2       timbl     564: {
1.25      frystyk   565:     char       *arg = NULL;
                    566:     HTProtocol *p;
                    567:     int        status;
                    568: 
1.22      luotonen  569:     if (request->method == METHOD_INVALID)
                    570:        request->method = METHOD_GET;
1.52      frystyk   571:     if (!keep_error_stack) {
                    572:        HTErrorFree(request);
                    573:        request->error_block = NO;
                    574:     }
                    575: 
1.59      frystyk   576:     if ((status = get_physical(request)) < 0) {
                    577:        if (status == HT_FORBIDDEN) {
                    578:            char *url = HTAnchor_address((HTAnchor *) request->anchor);
                    579:            if (url) {
                    580:                HTUnEscape(url);
                    581:                HTErrorAdd(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
                    582:                           (void *) url, (int) strlen(url), "HTLoad");
                    583:                free(url);
                    584:            } else {
                    585:                HTErrorAdd(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
                    586:                           NULL, 0, "HTLoad");
                    587:            }
                    588:        } 
                    589:        return HT_ERROR;                       /* Can't resolve or forbidden */
1.2       timbl     590:     }
1.25      frystyk   591: 
                    592:     if(!(arg = HTAnchor_physical(request->anchor)) || !*arg) 
1.59      frystyk   593:        return HT_ERROR;
1.27      luotonen  594: 
1.56      frystyk   595:     p = (HTProtocol *) HTAnchor_protocol(request->anchor);
1.17      timbl     596:     return (*(p->load))(request);
1.2       timbl     597: }
                    598: 
                    599: 
1.61      frystyk   600: /*             Terminate a LOAD
                    601: **             ----------------
                    602: **
                    603: **     This function looks at the status code from the HTLoadDocument
                    604: **     function and updates logfiles, creates error messages etc.
                    605: **
                    606: **    On Entry,
                    607: **     Status code from load function
                    608: */
                    609: PUBLIC BOOL HTLoadTerminate ARGS2(HTRequest *, request, int, status)
                    610: {
                    611:     char * uri = HTAnchor_address((HTAnchor*)request->anchor);
                    612: 
1.70      frystyk   613:     HTLog_request(request);
1.61      frystyk   614: 
                    615:     /* The error stack might contain general information to the client
                    616:        about what has been going on in the library (not only errors) */
                    617:     if (!HTImProxy && request->error_stack)
                    618:        HTErrorMsg(request);
                    619: 
                    620:     switch (status) {
                    621:       case HT_LOADED:
                    622:        if (PROT_TRACE) {
1.72      frystyk   623:            fprintf(TDEST, "HTAccess.... OK: `%s\' has been accessed.\n", uri);
1.61      frystyk   624:        }
                    625:        break;
                    626: 
1.78      frystyk   627:       case HT_OK:
                    628:        if (PROT_TRACE) {
1.80      frystyk   629:            fprintf(TDEST,"HTAccess.... FRIEND FINISHED ACCESS: `%s\'\n",uri);
1.78      frystyk   630:        }
                    631:        break;
                    632: 
1.61      frystyk   633:       case HT_NO_DATA:
                    634:        if (PROT_TRACE) {
1.72      frystyk   635:            fprintf(TDEST, "HTAccess.... OK BUT NO DATA: `%s\'\n", uri);
1.61      frystyk   636:        }
                    637:        break;
                    638: 
                    639:       case HT_WOULD_BLOCK:
                    640:        if (PROT_TRACE) {
1.72      frystyk   641:            fprintf(TDEST, "HTAccess.... WOULD BLOCK: `%s\'\n", uri);
                    642:        }
                    643:        break;
                    644: 
                    645:       case HT_RETRY:
                    646:        if (PROT_TRACE) {
                    647:            fprintf(TDEST, "HTAccess.... NOT AVAILABLE, RETRY AT `%s\'\n",uri);
1.61      frystyk   648:        }
                    649:        break;
                    650: 
                    651:       case HT_ERROR:
                    652:        if (HTImProxy)
                    653:            HTErrorMsg(request);                     /* Only on a real error */
                    654:        if (PROT_TRACE) {
1.72      frystyk   655:            fprintf(TDEST, "HTAccess.... ERROR: Can't access `%s\'\n", uri);
1.61      frystyk   656:        }
                    657:        break;
                    658: 
                    659:       default:
                    660:        if (PROT_TRACE) {
1.67      frystyk   661:            fprintf(TDEST, "HTAccess.... **** Internal software error in CERN WWWLib version %s ****\n", HTLibraryVersion);
1.79      frystyk   662:            fprintf(TDEST, "............ Please mail libwww@w3.org quoting what software\n");
1.67      frystyk   663:            fprintf(TDEST, "............ and version you are using including the URL:\n");
                    664:            fprintf(TDEST, "............ `%s\'\n", uri);
                    665:            fprintf(TDEST, "............ that caused the problem, thanks!\n");
1.61      frystyk   666:        }
                    667:        break;
                    668:     }
                    669:     free(uri);
                    670:     return YES;
                    671: }
                    672: 
                    673: 
1.2       timbl     674: /*             Load a document - with logging etc
                    675: **             ----------------------------------
                    676: **
                    677: **     - Checks or documents already loaded
                    678: **     - Logs the access
                    679: **     - Trace ouput and error messages
                    680: **
1.1       timbl     681: **    On Entry,
1.19      timbl     682: **        request->anchor      valid for of the document to be accessed.
                    683: **      request->childAnchor   optional anchor within doc to be selected
                    684: **
1.15      timbl     685: **       request->anchor   is the node_anchor for the document
                    686: **       request->output_format is valid
                    687: **
1.59      frystyk   688: ** On exit,
                    689: **     returns         HT_WOULD_BLOCK  An I/O operation would block
                    690: **                     HT_ERROR        Error has occured
                    691: **                     HT_LOADED       Success
                    692: **                     HT_NO_DATA      Success, but no document loaded.
                    693: **                                     (telnet sesssion started etc)
1.72      frystyk   694: **                     HT_RETRY        if service isn't available before
                    695: **                                     request->retry_after
1.1       timbl     696: */
1.59      frystyk   697: PRIVATE int HTLoadDocument ARGS2(HTRequest *,  request,
                    698:                                 BOOL,          keep_error_stack)
1.1       timbl     699: 
                    700: {
                    701:     int                status;
                    702:     HText *    text;
1.19      timbl     703:     char * full_address = HTAnchor_address((HTAnchor*)request->anchor);
1.54      frystyk   704: 
1.80      frystyk   705:     if (PROT_TRACE) fprintf (TDEST, "HTAccess.... Accessing document %s\n",
1.59      frystyk   706:                             full_address);
1.1       timbl     707: 
1.15      timbl     708:     if (!request->output_format) request->output_format = WWW_PRESENT;
1.25      frystyk   709: 
1.67      frystyk   710:     /* Check if document is already loaded or in cache */
1.84    ! frystyk   711:     if (request->ForceReload == HT_NO_UPDATE) {
1.67      frystyk   712:        if ((text=(HText *)HTAnchor_document(request->anchor))) {
                    713:            if (PROT_TRACE)
                    714:                fprintf(TDEST, "HTAccess.... Document already in memory.\n");
                    715:            if (request->childAnchor) {
                    716:                HText_selectAnchor(text, request->childAnchor);
                    717:            } else {
1.80      frystyk   718:                HText_select(text);
1.67      frystyk   719:            }
                    720:            free(full_address);
                    721:            return HT_LOADED;
1.19      timbl     722:        }
1.70      frystyk   723:     } else {                     /* Make sure that we don't use old headers */
                    724:        HTAnchor_clearHeader(request->anchor);
1.77      frystyk   725:        request->RequestMask += HT_PRAGMA;     /* Force reload through proxy */
1.1       timbl     726:     }
1.61      frystyk   727:     if ((status = HTLoad(request, keep_error_stack)) != HT_WOULD_BLOCK)
                    728:        HTLoadTerminate(request, status);
1.19      timbl     729:     free(full_address);
1.59      frystyk   730:     return status;
1.58      frystyk   731: }
1.1       timbl     732: 
                    733: 
                    734: /*             Load a document from absolute name
                    735: **             ---------------
                    736: **
1.59      frystyk   737: ** On Entry,
1.1       timbl     738: **        addr     The absolute address of the document to be accessed.
                    739: **
1.59      frystyk   740: ** On exit,
                    741: **     returns         HT_WOULD_BLOCK  An I/O operation would block
                    742: **                     HT_ERROR        Error has occured
                    743: **                     HT_LOADED       Success
                    744: **                     HT_NO_DATA      Success, but no document loaded.
                    745: **                                     (telnet sesssion started etc)
1.72      frystyk   746: **                     HT_RETRY        if service isn't available before
                    747: **                                     request->retry_after
1.1       timbl     748: */
1.59      frystyk   749: PUBLIC int HTLoadAbsolute ARGS2(CONST char *,addr, HTRequest*, request)
1.2       timbl     750: {
1.19      timbl     751:    HTAnchor * anchor = HTAnchor_findAddress(addr);
                    752:    request->anchor = HTAnchor_parent(anchor);
                    753:    request->childAnchor = ((HTAnchor*)request->anchor == anchor) ?
                    754:                        NULL : (HTChildAnchor*) anchor;
1.52      frystyk   755:    return HTLoadDocument(request, NO);
1.2       timbl     756: }
                    757: 
                    758: 
                    759: /*             Load a document from absolute name to stream
                    760: **             --------------------------------------------
                    761: **
1.59      frystyk   762: ** On Entry,
1.2       timbl     763: **        addr     The absolute address of the document to be accessed.
1.15      timbl     764: **        request->output_stream     if non-NULL, send data down this stream
1.2       timbl     765: **
1.59      frystyk   766: ** On exit,
                    767: **     returns         HT_WOULD_BLOCK  An I/O operation would block
                    768: **                     HT_ERROR        Error has occured
                    769: **                     HT_LOADED       Success
                    770: **                     HT_NO_DATA      Success, but no document loaded.
                    771: **                                     (telnet sesssion started etc)
1.72      frystyk   772: **                     HT_RETRY        if service isn't available before
                    773: **                                     request->retry_after
1.2       timbl     774: */
1.59      frystyk   775: PUBLIC int HTLoadToStream ARGS3(CONST char *,  addr,
                    776:                                BOOL,           filter,
                    777:                                HTRequest*,     request)
1.1       timbl     778: {
1.63      frystyk   779:     HTAnchor * anchor = HTAnchor_findAddress(addr);
                    780:     request->anchor = HTAnchor_parent(anchor);
                    781:     request->childAnchor = ((HTAnchor*)request->anchor == anchor) ? NULL :
1.19      timbl     782:        (HTChildAnchor*) anchor;
1.15      timbl     783:     request->output_stream = request->output_stream;
1.52      frystyk   784:     return HTLoadDocument(request, NO);
1.1       timbl     785: }
                    786: 
                    787: 
                    788: /*             Load a document from relative name
                    789: **             ---------------
                    790: **
1.59      frystyk   791: ** On Entry,
1.2       timbl     792: **        relative_name     The relative address of the document
                    793: **                         to be accessed.
1.1       timbl     794: **
1.59      frystyk   795: ** On exit,
                    796: **     returns         HT_WOULD_BLOCK  An I/O operation would block
                    797: **                     HT_ERROR        Error has occured
                    798: **                     HT_LOADED       Success
                    799: **                     HT_NO_DATA      Success, but no document loaded.
                    800: **                                     (telnet sesssion started etc)
1.72      frystyk   801: **                     HT_RETRY        if service isn't available before
                    802: **                                     request->retry_after
1.1       timbl     803: */
1.59      frystyk   804: PUBLIC int HTLoadRelative ARGS3(CONST char *,          relative_name,
                    805:                                HTParentAnchor *,       here,
                    806:                                HTRequest *,            request)
1.1       timbl     807: {
                    808:     char *             full_address = 0;
1.65      frystyk   809:     int                result;
1.1       timbl     810:     char *             mycopy = 0;
                    811:     char *             stripped = 0;
                    812:     char *             current_address =
1.2       timbl     813:                                HTAnchor_address((HTAnchor*)here);
1.1       timbl     814: 
                    815:     StrAllocCopy(mycopy, relative_name);
                    816: 
                    817:     stripped = HTStrip(mycopy);
                    818:     full_address = HTParse(stripped,
                    819:                   current_address,
                    820:                   PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1.15      timbl     821:     result = HTLoadAbsolute(full_address, request);
1.1       timbl     822:     free(full_address);
                    823:     free(current_address);
                    824:     free(mycopy);  /* Memory leak fixed 10/7/92 -- JFG */
                    825:     return result;
                    826: }
                    827: 
                    828: 
                    829: /*             Load if necessary, and select an anchor
                    830: **             --------------------------------------
                    831: **
1.59      frystyk   832: ** On Entry,
1.1       timbl     833: **        destination              The child or parenet anchor to be loaded.
                    834: **
1.59      frystyk   835: ** On exit,
                    836: **     returns         HT_WOULD_BLOCK  An I/O operation would block
                    837: **                     HT_ERROR        Error has occured
                    838: **                     HT_LOADED       Success
                    839: **                     HT_NO_DATA      Success, but no document loaded.
                    840: **                                     (telnet sesssion started etc)
1.72      frystyk   841: **                     HT_RETRY        if service isn't available before
                    842: **                                     request->retry_after
1.1       timbl     843: */
1.59      frystyk   844: PUBLIC int HTLoadAnchor ARGS2(HTAnchor*, anchor, HTRequest *, request)
1.1       timbl     845: {
1.70      frystyk   846:     if (!anchor || !request)
                    847:        return HT_ERROR;
                    848:     request->anchor = HTAnchor_parent(anchor);
1.59      frystyk   849:     request->childAnchor = ((HTAnchor *) request->anchor == anchor) ?
                    850:        NULL : (HTChildAnchor*) anchor;
                    851:     return HTLoadDocument(request, NO);
                    852: }
1.52      frystyk   853: 
                    854: 
                    855: /*             Load if necessary, and select an anchor
                    856: **             --------------------------------------
                    857: **
                    858: **     This function is almost identical to HTLoadAnchor, but it doesn't
                    859: **     clear the error stack so that the information in there is kept.
                    860: **
1.59      frystyk   861: ** On Entry,
1.52      frystyk   862: **        destination              The child or parenet anchor to be loaded.
                    863: **
1.59      frystyk   864: ** On exit,
                    865: **     returns         HT_WOULD_BLOCK  An I/O operation would block
                    866: **                     HT_ERROR        Error has occured
                    867: **                     HT_LOADED       Success
                    868: **                     HT_NO_DATA      Success, but no document loaded.
                    869: **                                     (telnet sesssion started etc)
1.72      frystyk   870: **                     HT_RETRY        if service isn't available before
                    871: **                                     request->retry_after
1.52      frystyk   872: */
1.59      frystyk   873: PUBLIC int HTLoadAnchorRecursive ARGS2(HTAnchor*,      anchor,
                    874:                                       HTRequest *,     request)
1.52      frystyk   875: {
1.59      frystyk   876:     if (!anchor) return HT_ERROR;                                /* No link */
1.52      frystyk   877:     
                    878:     request->anchor  = HTAnchor_parent(anchor);
1.59      frystyk   879:     request->childAnchor = ((HTAnchor *) request->anchor == anchor) ?
                    880:        NULL : (HTChildAnchor*) anchor;
1.52      frystyk   881:     
1.59      frystyk   882:     return HTLoadDocument(request, YES);
                    883: }
1.1       timbl     884: 
                    885: 
                    886: /*             Search
                    887: **             ------
                    888: **  Performs a keyword search on word given by the user. Adds the keyword to 
                    889: **  the end of the current address and attempts to open the new address.
                    890: **
                    891: **  On Entry,
                    892: **       *keywords     space-separated keyword list or similar search list
1.2       timbl     893: **     here            is anchor search is to be done on.
1.59      frystyk   894: **
                    895: ** On exit,
                    896: **     returns         HT_WOULD_BLOCK  An I/O operation would block
                    897: **                     HT_ERROR        Error has occured
                    898: **                     HT_LOADED       Success
                    899: **                     HT_NO_DATA      Success, but no document loaded.
                    900: **                                     (telnet sesssion started etc)
1.72      frystyk   901: **                     HT_RETRY        if service isn't available before
                    902: **                                     request->retry_after
1.1       timbl     903: */
1.56      frystyk   904: PRIVATE char hex ARGS1(int, i)
1.2       timbl     905: {
1.13      timbl     906:     char * hexchars = "0123456789ABCDEF";
                    907:     return hexchars[i];
1.2       timbl     908: }
1.1       timbl     909: 
1.59      frystyk   910: PUBLIC int HTSearch ARGS3(CONST char *,                keywords,
                    911:                          HTParentAnchor *,     here,
                    912:                          HTRequest *,          request)
1.1       timbl     913: {
1.2       timbl     914: 
                    915: #define acceptable \
                    916: "1234567890abcdefghijlkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_"
                    917: 
                    918:     char *q, *u;
                    919:     CONST char * p, *s, *e;            /* Pointers into keywords */
                    920:     char * address = HTAnchor_address((HTAnchor*)here);
1.65      frystyk   921:     int result;
1.56      frystyk   922:     char * escaped = (char *) malloc(strlen(keywords)*3+1);
1.2       timbl     923: 
1.29      frystyk   924:     /* static CONST BOOL isAcceptable[96] = */
                    925:     /* static AND const is not good for a gnu compiler! Frystyk 25/02-94 */
1.30      luotonen  926:     static BOOL isAcceptable[96] =
1.2       timbl     927:     /*   0 1 2 3 4 5 6 7 8 9 A B C D E F */
                    928:     {    0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,0,      /* 2x   !"#$%&'()*+,-./  */
                    929:          1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,      /* 3x  0123456789:;<=>?  */
                    930:         1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,       /* 4x  @ABCDEFGHIJKLMNO  */
                    931:         1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,       /* 5X  PQRSTUVWXYZ[\]^_  */
                    932:         0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,       /* 6x  `abcdefghijklmno  */
                    933:         1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0 };     /* 7X  pqrstuvwxyz{\}~  DEL */
                    934: 
                    935:     if (escaped == NULL) outofmem(__FILE__, "HTSearch");
                    936:     
1.29      frystyk   937: /* Convert spaces to + and hex escape unacceptable characters */
1.2       timbl     938: 
1.29      frystyk   939:     for(s=keywords; *s && WHITE(*s); s++); /*scan */    /* Skip white space */
                    940:     for(e = s + strlen(s); e>s && WHITE(*(e-1)) ; e--);     /* Skip trailers */
                    941:     for(q=escaped, p=s; p<e; p++) {                  /* scan stripped field */
1.2       timbl     942:         int c = (int)TOASCII(*p);
                    943:         if (WHITE(*p)) {
                    944:            *q++ = '+';
1.29      frystyk   945:        } else if (c>=32 && c<=127 && isAcceptable[c-32] != 0) {
1.13      timbl     946:            *q++ = *p;                  /* 930706 TBL for MVS bug */
1.2       timbl     947:        } else {
                    948:            *q++ = '%';
                    949:            *q++ = hex(c / 16);
                    950:            *q++ = hex(c % 16);
                    951:        }
                    952:     } /* Loop over string */
1.1       timbl     953:     
1.2       timbl     954:     *q=0;
                    955:                                /* terminate escaped sctring */
                    956:     u=strchr(address, '?');            /* Find old search string */
                    957:     if (u) *u = 0;                             /* Chop old search off */
1.1       timbl     958: 
                    959:     StrAllocCat(address, "?");
1.2       timbl     960:     StrAllocCat(address, escaped);
                    961:     free(escaped);
1.15      timbl     962:     result = HTLoadRelative(address, here, request);
1.1       timbl     963:     free(address);
1.2       timbl     964:     
1.1       timbl     965:     return result;
1.2       timbl     966: }
                    967: 
                    968: 
                    969: /*             Search Given Indexname
                    970: **             ------
                    971: **  Performs a keyword search on word given by the user. Adds the keyword to 
                    972: **  the end of the current address and attempts to open the new address.
                    973: **
1.59      frystyk   974: ** On Entry,
1.2       timbl     975: **       *keywords     space-separated keyword list or similar search list
                    976: **     *addres         is name of object search is to be done on.
1.59      frystyk   977: ** On exit,
                    978: **     returns         HT_WOULD_BLOCK  An I/O operation would block
                    979: **                     HT_ERROR        Error has occured
                    980: **                     HT_LOADED       Success
                    981: **                     HT_NO_DATA      Success, but no document loaded.
                    982: **                                     (telnet sesssion started etc)
1.72      frystyk   983: **                     HT_RETRY        if service isn't available before
                    984: **                                     request->retry_after
1.2       timbl     985: */
1.59      frystyk   986: PUBLIC int HTSearchAbsolute ARGS3(CONST char *,        keywords,
                    987:                                  CONST char *,         indexname,
                    988:                                  HTRequest *,          request)
1.2       timbl     989: {
                    990:     HTParentAnchor * anchor =
                    991:        (HTParentAnchor*) HTAnchor_findAddress(indexname);
1.15      timbl     992:     return HTSearch(keywords, anchor, request);
1.57      howcome   993: }
                    994: 
1.70      frystyk   995: /* --------------------------------------------------------------------------*/
                    996: /*                             Document Poster                              */
                    997: /* --------------------------------------------------------------------------*/
                    998: 
                    999: /*             Get a save stream for a document
                   1000: **             --------------------------------
                   1001: */
                   1002: PUBLIC HTStream *HTSaveStream ARGS1(HTRequest *, request)
                   1003: {
                   1004:     HTProtocol * p;
                   1005:     int status;
                   1006:     request->method = METHOD_PUT;
                   1007:     status = get_physical(request);
                   1008:     if (status == HT_FORBIDDEN) {
                   1009:        char *url = HTAnchor_address((HTAnchor *) request->anchor);
                   1010:        if (url) {
                   1011:            HTUnEscape(url);
                   1012:            HTErrorAdd(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
                   1013:                       (void *) url, (int) strlen(url), "HTLoad");
                   1014:            free(url);
                   1015:        } else {
                   1016:            HTErrorAdd(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
                   1017:                       NULL, 0, "HTLoad");
                   1018:        }
                   1019:        return NULL;    /* should return error status? */
                   1020:     }
                   1021:     if (status < 0) return NULL; /* @@ error. Can't resolve or forbidden */
                   1022:     
                   1023:     p = (HTProtocol *) HTAnchor_protocol(request->anchor);
                   1024:     if (!p) return NULL;
                   1025:     
                   1026:     return (*p->saveStream)(request);
                   1027:     
                   1028: }
                   1029: 
                   1030: /*     COPY AN ANCHOR
                   1031: **     --------------
                   1032: **  Fetch the URL (possibly local file URL) and send it using either PUT
                   1033: **  or POST to the remote destination using HTTP. The caller can decide the
                   1034: **  exact method used and which HTTP header fields to transmit by setting the
                   1035: **  user fields in the request structure.
                   1036: **
1.80      frystyk  1037: **  BUGS: Should take ALL links in the destination anchor and PUT/POST to
                   1038: **  all of them!
                   1039: **
1.70      frystyk  1040: **     returns         HT_WOULD_BLOCK  An I/O operation would block
                   1041: **                     HT_ERROR        Error has occured
                   1042: **                     HT_LOADED       Success
                   1043: **                     HT_NO_DATA      Success, but no document loaded.
1.72      frystyk  1044: **                     HT_RETRY        if service isn't available before
                   1045: **                                     request->retry_after
1.70      frystyk  1046: */
1.80      frystyk  1047: PUBLIC int HTCopyAnchor ARGS2(HTAnchor *,      src_anchor,
                   1048:                              HTRequest *,      main_dest)
                   1049: { 
1.78      frystyk  1050:     HTRequest *src_req;
1.80      frystyk  1051:     if (!src_anchor || !main_dest)
1.70      frystyk  1052:        return HT_ERROR;
                   1053: 
1.80      frystyk  1054:     /* Build the POST web if not already there */
                   1055:     if (!main_dest->source) {
                   1056:        src_req = HTRequest_new();                /* First set up the source */
                   1057:        HTAnchor_clearHeader((HTParentAnchor *) src_anchor);
1.84    ! frystyk  1058:        src_req->ForceReload = HT_UPDATE_MEM;
1.80      frystyk  1059:        src_req->source = src_req;                        /* Point to myself */
                   1060:        src_req->output_format = WWW_SOURCE;     /* We want source (for now) */
                   1061: 
                   1062:        /* Set up the main link in the source anchor */
                   1063:        {
                   1064:            HTAnchor *main = HTAnchor_followMainLink(src_anchor);
                   1065:            HTMethod method = HTAnchor_mainLinkMethod(src_anchor);
                   1066:            if (!main || method==METHOD_INVALID) {
                   1067:                if (TRACE)
                   1068:                    fprintf(TDEST, "Copy Anchor. No destination found or unspecified method");
                   1069:                HTRequest_delete(src_req);
                   1070:                return HT_ERROR;
                   1071:            }
                   1072:            main_dest->GenMask += HT_DATE;               /* Send date header */
                   1073:            main_dest->source = src_req;
1.84    ! frystyk  1074:            main_dest->ForceReload = HT_UPDATE_DISK;
1.80      frystyk  1075:            main_dest->method = method;
                   1076:            HTRequest_addDestination(src_req, main_dest);
                   1077:            main_dest->input_format = WWW_SOURCE;         /* for now :-( @@@ */
                   1078:            if (HTLoadAnchor(main, main_dest) == HT_ERROR)
                   1079:                return HT_ERROR;
                   1080:        }
1.78      frystyk  1081: 
1.80      frystyk  1082:        /* For all other links in the source anchor */
                   1083:        if (src_anchor->links) {
                   1084:            HTList *cur = src_anchor->links;
                   1085:            HTLink *pres;
                   1086:            while ((pres = (HTLink *) HTList_nextObject(cur)) != NULL) {
                   1087:                HTAnchor *dest = pres->dest;
                   1088:                HTMethod method = pres->method;
                   1089:                HTRequest *dest_req;
                   1090:                if (!dest || method==METHOD_INVALID) {
                   1091:                    if (TRACE)
                   1092:                        fprintf(TDEST, "Copy Anchor. Bad anchor setup %p\n",
                   1093:                                dest);
                   1094:                    return HT_ERROR;
                   1095:                }
                   1096:                dest_req = HTRequest_new();
                   1097:                dest_req->GenMask += HT_DATE;            /* Send date header */
                   1098:                dest_req->source = src_req;
1.84    ! frystyk  1099:                dest_req->ForceReload = HT_UPDATE_DISK;
1.80      frystyk  1100:                dest_req->method = method;
                   1101:                HTRequest_addDestination(src_req, dest_req);
                   1102:                dest_req->input_format = WWW_SOURCE;      /* for now :-( @@@ */
                   1103:                if (HTLoadAnchor(dest, dest_req) == HT_ERROR)
                   1104:                    return HT_ERROR;
                   1105:            }
                   1106:        }
                   1107:     } else {                    /* Use the existing Post Web and restart it */
                   1108:        src_req = main_dest->source;
                   1109:        if (src_req->mainDestination)
                   1110:            if (HTLoadDocument(main_dest, NO) == HT_ERROR)
                   1111:                return HT_ERROR;
                   1112:        if (src_req->destinations) {
                   1113:            HTList *cur = src_anchor->links;
                   1114:            HTRequest *pres;
                   1115:            while ((pres = (HTRequest *) HTList_nextObject(cur)) != NULL) {
                   1116:                if (HTLoadDocument(pres, NO) == HT_ERROR)
                   1117:                    return HT_ERROR;
                   1118:            }
                   1119:        }
1.78      frystyk  1120:     }
                   1121: 
1.80      frystyk  1122:     /* Now open the source */
                   1123:     return HTLoadAnchor(src_anchor, src_req);
1.70      frystyk  1124: }
                   1125: 
                   1126: 
                   1127: /*     UPLOAD AN ANCHOR
                   1128: **     ----------------
                   1129: **  Send the contents (in hyperdoc) of the source anchor using either PUT
                   1130: **  or POST to the remote destination using HTTP. The caller can decide the
                   1131: **  exact method used and which HTTP header fields to transmit by setting the
                   1132: **  user fields in the request structure.
                   1133: **
                   1134: **     returns         HT_WOULD_BLOCK  An I/O operation would block
                   1135: **                     HT_ERROR        Error has occured
                   1136: **                     HT_LOADED       Success
                   1137: **                     HT_NO_DATA      Success, but no document loaded.
1.72      frystyk  1138: **                     HT_RETRY        if service isn't available before
                   1139: **                                     request->retry_after
1.70      frystyk  1140: */
                   1141: PUBLIC int HTUploadAnchor ARGS3(HTAnchor *,            src_anchor,
                   1142:                                HTParentAnchor *,       dest_anchor,
                   1143:                                HTRequest *,            dest_req)
                   1144: {
                   1145:     if (!(src_anchor && dest_anchor && dest_req))
                   1146:        return HT_ERROR;
                   1147: 
                   1148:     if (!(dest_anchor->methods & dest_req->method)) {
                   1149:        char buf[80];
                   1150:        sprintf(buf, "It might not be allowed to %s to this destination, continue?", HTMethod_name(dest_req->method));
                   1151:        if (!HTConfirm(buf))
                   1152:            return HT_ERROR;
                   1153:     }
1.77      frystyk  1154: 
                   1155:     /* @@@ NOT FINISHED @@@ */
1.70      frystyk  1156: 
                   1157:     return HT_ERROR;
                   1158: }
                   1159: 
                   1160: /* --------------------------------------------------------------------------*/
                   1161: /*                             Anchor help routines                         */
                   1162: /* --------------------------------------------------------------------------*/
1.57      howcome  1163: 
                   1164: /*
                   1165: **             Find Related Name
                   1166: **
                   1167: **  Creates a string that can be used as a related name when 
                   1168: **  calling HTParse initially. 
                   1169: **  
                   1170: **  The code for this routine originates from the Linemode 
1.79      frystyk  1171: **  browser and was moved here by howcome@w3.org
1.57      howcome  1172: **  in order for all clients to take advantage.
                   1173: **
1.59      frystyk  1174: **  The string returned must be freed by the caller
1.57      howcome  1175: */
                   1176: PUBLIC char * HTFindRelatedName NOARGS
                   1177: {
1.59      frystyk  1178:     char* default_default = NULL;            /* Parse home relative to this */
                   1179:     CONST char *host = HTGetHostName(); 
1.57      howcome  1180:     StrAllocCopy(default_default, "file://");
1.59      frystyk  1181:     if (host)
                   1182:        StrAllocCat(default_default, host);
                   1183:     else
                   1184:        StrAllocCat(default_default, "localhost");
                   1185:     {
                   1186:        char wd[HT_MAX_PATH+1];
1.67      frystyk  1187: 
                   1188: #ifdef NO_GETWD
                   1189: #ifdef HAS_GETCWD            /* System V variant SIGN CHANGED TBL 921006 !! */
                   1190:        char *result = (char *) getcwd(wd, sizeof(wd)); 
                   1191: #else
                   1192:        char *result = NULL;
                   1193:        HTAlert("This platform does not support neither getwd nor getcwd\n");
                   1194: #endif
                   1195: #else
                   1196:        char *result = (char *) getwd(wd);
                   1197: #endif
1.59      frystyk  1198:        *(wd+HT_MAX_PATH) = '\0';
1.57      howcome  1199:        if (result) {
                   1200: #ifdef VMS 
                   1201:             /* convert directory name to Unix-style syntax */
                   1202:            char * disk = strchr (wd, ':');
                   1203:            char * dir = strchr (wd, '[');
                   1204:            if (disk) {
                   1205:                *disk = '\0';
                   1206:                StrAllocCat (default_default, "/");  /* needs delimiter */
                   1207:                StrAllocCat (default_default, wd);
                   1208:            }
                   1209:            if (dir) {
                   1210:                char *p;
                   1211:                *dir = '/';  /* Convert leading '[' */
                   1212:                for (p = dir ; *p != ']'; ++p)
                   1213:                        if (*p == '.') *p = '/';
                   1214:                *p = '\0';  /* Cut on final ']' */
                   1215:                StrAllocCat (default_default, dir);
                   1216:            }
1.74      frystyk  1217: #else  /* not VMS */
1.70      frystyk  1218: #ifdef WIN32
                   1219:            char * p = wd ;     /* a colon */
                   1220:            StrAllocCat(default_default, "/");
                   1221:            while( *p != 0 ) { 
                   1222:                if (*p == '\\')                  /* change to one true slash */
                   1223:                    *p = '/' ;
                   1224:                p++;
                   1225:            }
1.74      frystyk  1226:            StrAllocCat( default_default, wd);
                   1227: #else /* not WIN32 */
1.57      howcome  1228:            StrAllocCat (default_default, wd);
1.70      frystyk  1229: #endif /* not WIN32 */
1.67      frystyk  1230: #endif /* not VMS */
1.57      howcome  1231:        }
1.67      frystyk  1232:     }
1.57      howcome  1233:     StrAllocCat(default_default, "/default.html");
                   1234:     return default_default;
1.2       timbl    1235: }
                   1236: 
                   1237: 
                   1238: /*             Generate the anchor for the home page
                   1239: **             -------------------------------------
                   1240: **
                   1241: **     As it involves file access, this should only be done once
                   1242: **     when the program first runs.
1.10      timbl    1243: **     This is a default algorithm -- browser don't HAVE to use this.
                   1244: **     But consistency betwen browsers is STRONGLY recommended!
1.2       timbl    1245: **
1.10      timbl    1246: **     Priority order is:
                   1247: **
                   1248: **             1       WWW_HOME environment variable (logical name, etc)
                   1249: **             2       ~/WWW/default.html
                   1250: **             3       /usr/local/bin/default.html
1.70      frystyk  1251: **             4       http://www.w3.org/default.html
1.10      timbl    1252: **
1.2       timbl    1253: */
                   1254: PUBLIC HTParentAnchor * HTHomeAnchor NOARGS
                   1255: {
1.12      timbl    1256:     char * my_home_document = NULL;
1.70      frystyk  1257:     char * home = (char *) getenv(LOGICAL_DEFAULT);
1.2       timbl    1258:     char * ref;
                   1259:     HTParentAnchor * anchor;
1.1       timbl    1260:     
1.70      frystyk  1261:     /* Someone telnets in, they get a special home */
1.12      timbl    1262:     if (home) {
                   1263:         StrAllocCopy(my_home_document, home);
1.70      frystyk  1264:     } else  if (HTClientHost) {                                    /* Telnet server */
1.12      timbl    1265:        FILE * fp = fopen(REMOTE_POINTER, "r");
                   1266:        char * status;
                   1267:        if (fp) {
1.59      frystyk  1268:            my_home_document = (char*) malloc(HT_MAX_PATH);
                   1269:            status = fgets(my_home_document, HT_MAX_PATH, fp);
1.12      timbl    1270:            if (!status) {
                   1271:                free(my_home_document);
                   1272:                my_home_document = NULL;
                   1273:            }
                   1274:            fclose(fp);
                   1275:        }
                   1276:        if (!my_home_document) StrAllocCopy(my_home_document, REMOTE_ADDRESS);
                   1277:     }
                   1278: 
1.67      frystyk  1279: #ifdef unix
1.10      timbl    1280:     if (!my_home_document) {
                   1281:        FILE * fp = NULL;
1.70      frystyk  1282:        char * home = (char *) getenv("HOME");
1.10      timbl    1283:        if (home) { 
                   1284:            my_home_document = (char *)malloc(
                   1285:                strlen(home)+1+ strlen(PERSONAL_DEFAULT)+1);
                   1286:            if (my_home_document == NULL) outofmem(__FILE__, "HTLocalName");
                   1287:            sprintf(my_home_document, "%s/%s", home, PERSONAL_DEFAULT);
                   1288:            fp = fopen(my_home_document, "r");
                   1289:        }
                   1290:        
                   1291:        if (!fp) {
                   1292:            StrAllocCopy(my_home_document, LOCAL_DEFAULT_FILE);
                   1293:            fp = fopen(my_home_document, "r");
                   1294:        }
1.2       timbl    1295:        if (fp) {
                   1296:            fclose(fp);
                   1297:        } else {
1.62      frystyk  1298:            if (TRACE)
1.67      frystyk  1299:                fprintf(TDEST,
1.62      frystyk  1300:                        "HTBrowse: No local home document ~/%s or %s\n",
                   1301:                        PERSONAL_DEFAULT, LOCAL_DEFAULT_FILE);
1.11      timbl    1302:            free(my_home_document);
                   1303:            my_home_document = NULL;
1.2       timbl    1304:        }
                   1305:     }
1.67      frystyk  1306: #endif
1.70      frystyk  1307:     ref = HTParse(my_home_document ? my_home_document :
                   1308:                  HTClientHost ? REMOTE_ADDRESS : LAST_RESORT, "file:",
                   1309:                  PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1.10      timbl    1310:     if (my_home_document) {
1.62      frystyk  1311:        if (TRACE)
1.67      frystyk  1312:            fprintf(TDEST,
1.62      frystyk  1313:                   "HTAccess.... `%s\' used for custom home page as\n`%s\'\n",
                   1314:                    my_home_document, ref);
1.10      timbl    1315:        free(my_home_document);
1.2       timbl    1316:     }
                   1317:     anchor = (HTParentAnchor*) HTAnchor_findAddress(ref);
                   1318:     free(ref);
                   1319:     return anchor;
1.1       timbl    1320: }
1.26      frystyk  1321: 
                   1322: 
                   1323: /*             Bind an Anchor to the request structure
                   1324: **             ---------------------------------------
                   1325: **
                   1326: **    On Entry,
                   1327: **     anchor          The child or parenet anchor to be binded
                   1328: **     request         The request sturcture
                   1329: **    On Exit,
                   1330: **        returns    YES     Success
                   1331: **                   NO      Failure 
                   1332: **
                   1333: **  Note: Actually the same as HTLoadAnchor() but DOES NOT do the loading
                   1334: **                                             Henrik Frystyk 17/02-94
                   1335: */
                   1336: 
                   1337: PUBLIC BOOL HTBindAnchor ARGS2(HTAnchor*, anchor, HTRequest *, request)
                   1338: {
                   1339:     if (!anchor) return NO;    /* No link */
                   1340:     
                   1341:     request->anchor  = HTAnchor_parent(anchor);
                   1342:     request->childAnchor = ((HTAnchor*)request->anchor == anchor) ? NULL
                   1343:                                        : (HTChildAnchor*) anchor;
                   1344:        
1.29      frystyk  1345:     return YES;
1.70      frystyk  1346: }
1.59      frystyk  1347: 
1.26      frystyk  1348: 

Webmaster