Annotation of libwww/Library/src/HTWAIS.c, revision 2.55

2.29      frystyk     1: /*                                                                    HTWAIS.c
                      2: **     WORLDWIDEWEB - WIDE AREA INFORMAION SERVER ACCESS
                      3: **
2.33      frystyk     4: **     (c) COPYRIGHT MIT 1995.
2.29      frystyk     5: **     Please first read the full copyright statement in the file COPYRIGH.
2.55    ! frystyk     6: **     @(#) $Id: HTWAIS.c,v 2.54 1998/03/20 17:53:10 frystyk Exp $
2.1       timbl       7: **
                      8: **     This module allows a WWW server or client to read data from a
2.29      frystyk     9: **     remote  WAIS server, and provide that data to a WWW client in
                     10: **     hypertext form. Source files, once retrieved, are stored and used
                     11: **     to provide information about the index when that is acessed.
2.1       timbl      12: **
                     13: ** Authors
                     14: **     BK      Brewster Kahle, Thinking Machines, <Brewster@think.com>
2.35      frystyk    15: **     TBL     Tim Berners-Lee, CERN <timbl@w3.org>
2.1       timbl      16: **
2.54      frystyk    17: ** Contributors
                     18: **     QL      QingLong, Yggdrasil Inc., <qinglong@Yggdrasil.com>
                     19: **
2.1       timbl      20: ** History
                     21: **        Sep 91       TBL adapted shell-ui.c (BK) with HTRetrieve.c from WWW.
                     22: **        Feb 91       TBL Generated HTML cleaned up a bit (quotes, escaping)
                     23: **                         Refers to lists of sources. 
2.2       timbl      24: **        Mar 93       TBL   Lib 2.0 compatible module made.   
2.34      frystyk    25: **        May 95       CHJ modified for freeWAIS-0.5
2.54      frystyk    26: **        Jun 97       QL  modified for w3c-libwww-5.0a.
                     27: **        Mar 98       QL  modified for w3c-libwww-5.1i.
2.1       timbl      28: **
                     29: ** Bugs
                     30: **     Uses C stream i/o to read and write sockets, which won't work
                     31: **     on VMS TCP systems.
                     32: **
                     33: **     Should cache connections.
                     34: **
                     35: **     ANSI C only as written
                     36: **
2.11      secret     37: ** Bugs fixed
                     38: **      NT Nathan Torkington (Nathan.Torkington@vuw.ac.nz)
                     39: **
2.1       timbl      40: ** WAIS comments:
                     41: **
                     42: **     1.      Separate directories for different system's .o would help
                     43: **     2.      Document ids are rather long!
                     44: **
                     45: ** WWW Address mapping convention:
                     46: **
                     47: **     /servername/database/type/length/document-id
                     48: **
                     49: **     /servername/database?word+word+word
                     50: */
                     51: /* WIDE AREA INFORMATION SERVER SOFTWARE:
                     52:    No guarantees or restrictions.  See the readme file for the full standard
                     53:    disclaimer.
                     54: 
                     55:    Brewster@think.com
                     56: */
                     57: 
                     58: 
2.8       timbl      59: #define DIRECTORY "/cnidr.org:210/directory-of-servers"
2.1       timbl      60: 
                     61: #define BIG 1024       /* identifier size limit  @@@@@ */
                     62: 
2.54      frystyk    63: /* Library include files */
                     64: #include "sysdep.h"
                     65: #include "WWWUtil.h"
                     66: #include "WWWCore.h"
                     67: #include "WWWHTML.h"
                     68: #include "HTReqMan.h"
                     69:  
2.55    ! frystyk    70: #ifdef HAVE_WAIS_WAIS_H
        !            71: #include "wais/wais.h"
        !            72: #else
2.54      frystyk    73: #ifdef HAVE_WAIS_H
                     74: #include "wais.h"
                     75: #else
                     76: #ifdef WAIS_INCLUDE
                     77: #include WAIS_INCLUDE
2.55    ! frystyk    78: #else
        !            79: #include "wais/wais.h"
2.54      frystyk    80: #endif
                     81: #endif
                     82: #endif
                     83: 
2.2       timbl      84: /*                     From WAIS
                     85: **                     ---------
2.1       timbl      86: */
2.54      frystyk    87: #undef MAX_MESSAGE_LEN
2.1       timbl      88: #define MAX_MESSAGE_LEN 100000
2.54      frystyk    89: #undef CHARS_PER_PAGE
                     90: #define CHARS_PER_PAGE   10000 /* number of chars retrieved in each request */
                     91: #undef WAISSEARCH_DATE
2.1       timbl      92: #define WAISSEARCH_DATE "Fri Jul 19 1991"
                     93: 
2.2       timbl      94: /*                     FROM WWW
                     95: **                     --------
2.1       timbl      96: */
2.54      frystyk    97: #define      BUFFER_SIZE 4096  /* Arbitrary size for efficiency */
                     98: #define LINE_BUFFER_SIZE 2048
2.1       timbl      99: 
2.2       timbl     100: #define HEX_ESCAPE '%'
2.24      frystyk   101: 
2.54      frystyk   102: extern FILE * logfile;            /* Log file output */
2.1       timbl     103: 
2.54      frystyk   104: PRIVATE int HTMaxWAISLines = 200; /* Max number of entries from a search */
2.21      frystyk   105: 
2.2       timbl     106: 
2.25      frystyk   107: /* Hypertext object building machinery */
2.54      frystyk   108: #define PUTC(c)     (*target->isa->put_character)(target, c)
                    109: #define PUTS(s)     (*target->isa->put_string)(target, s)
                    110: #define START(e)    (*target->isa->start_element)(target, e, 0, 0)
                    111: #define END(e)      (*target->isa->end_element)(target, e)
2.23      frystyk   112: #define FREE_TARGET (*target->isa->_free)(target)
2.2       timbl     113: 
2.54      frystyk   114: 
                    115: 
                    116: /*
                    117:  * Type definitions and global variables etc. local to this module
                    118:  */
                    119: 
                    120: 
                    121: /* Final states have negative value */
                    122: typedef enum _HTWAISState
                    123: {
                    124:   HTWAIS_ERROR            = -2,
                    125:   HTWAIS_OK               = -1,
                    126:   HTWAIS_BEGIN            =  0,
                    127:   HTWAIS_PARSING_URL      =  1,
                    128:   HTWAIS_NEED_CONNECTION  =  2,
                    129:   HTWAIS_NEED_REQUEST     =  3,
                    130:   HTWAIS_NEED_RESPONSE    =  4,
                    131:   HTWAIS_PARSING_RESPONSE =  5,
                    132:   HTWAIS_FETCH_DOCUMENT   =  6,
                    133:   HTWAIS_CLEANUP          =  7
                    134: } HTWAISState;
                    135: 
                    136: 
                    137: /*
                    138:  * This is the context structure for this module
                    139:  */
                    140: typedef struct _wais_info
                    141: {
                    142:   BOOL        as_gate;          /* Client is using us as gateway */
                    143:   HTWAISState state;            /* Current State */
                    144:   int         result;           /* Result to report to the after filter */
                    145:   HTNet*      net;             /* Net object */
                    146:   FILE*       connection;
                    147:   char*       names;            /* Copy of arg to be hacked up */
                    148:   char*       basetitle;
                    149:   char*       wais_database;    /* name of current database */
                    150:   char*        www_database;    /* Same name escaped */
                    151:   char*       request_message;  /* arbitrary message limit */
                    152:   char*       response_message; /* arbitrary message limit */
                    153: } wais_info;
                    154: 
                    155: 
                    156: struct _HTStream
                    157: {
                    158:   const HTStreamClass* isa;
                    159:   HTStream*            target;
                    160:   HTRequest*           request;
                    161:   wais_info*           wais;
                    162:   int                  status;
                    163:   /* ... */
2.2       timbl     164: };
                    165: 
2.54      frystyk   166: 
                    167: struct _HTInputStream
                    168: {
                    169:   const HTInputStreamClass *   isa;
                    170: };
                    171: 
                    172: 
                    173: struct _HTStructured
                    174: {
                    175:   const HTStructuredClass *    isa;
                    176:   /* ... */
2.2       timbl     177: };
                    178: 
                    179: 
2.54      frystyk   180: /* ------------------------------------------------------------------------- */
                    181: /*                           Auxilliary Functions                           */
                    182: /* ------------------------------------------------------------------------- */
                    183: 
                    184: 
                    185: /*                                                             HTshowDiags
                    186:  */
2.1       timbl     187: /* modified from Jonny G's version in ui/question.c */
                    188: 
2.54      frystyk   189: void HTshowDiags (
2.42      frystyk   190:        HTStream *              target,
                    191:        diagnosticRecord **     d)
2.1       timbl     192: {
                    193:   long i;
                    194: 
                    195:   for (i = 0; d[i] != NULL; i++) {
                    196:     if (d[i]->ADDINFO != NULL) {
                    197:       PUTS("Diagnostic code is ");
                    198:       PUTS(d[i]->DIAG);
                    199:       PUTC(' ');
                    200:       PUTS(d[i]->ADDINFO);
                    201:       PUTC('\n'); ;
                    202:     }
                    203:   }
                    204: }
                    205: 
                    206: /*     Matrix of allowed characters in filenames
                    207: **     -----------------------------------------
                    208: */
                    209: 
                    210: PRIVATE BOOL acceptable[256];
                    211: PRIVATE BOOL acceptable_inited = NO;
                    212: 
2.42      frystyk   213: PRIVATE void init_acceptable (void)
2.1       timbl     214: {
2.54      frystyk   215:  unsigned int i;
                    216:  char * good = 
                    217:          "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_$";
                    218: 
                    219:  if (acceptable_inited == YES) return;
                    220: 
                    221:  for(i=256; i--; ) acceptable[i] = NO;
                    222:  for(;*good; good++) acceptable[(unsigned int)*good] = YES;
                    223:  acceptable_inited = YES;
2.1       timbl     224: }
                    225: 
2.54      frystyk   226: 
2.1       timbl     227: /*     Transform file identifier into WWW address
                    228: **     ------------------------------------------
                    229: **
                    230: **
                    231: ** On exit,
                    232: **     returns         nil if error
                    233: **                     pointer to malloced string (must be freed) if ok
                    234: */
2.42      frystyk   235: char * WWW_from_archie  (char * file)
2.1       timbl     236: {
                    237:     char * end;
                    238:     char * result;
                    239:     char * colon;
                    240:     for(end=file; *end > ' '; end++);  /* assumes ASCII encoding*/
2.44      frystyk   241:     if ((result = (char  *) HT_MALLOC(10 + (end-file))) == NULL)
                    242:         HT_OUTOFMEM("result ");
2.1       timbl     243:     if (!result) return result;                /* Malloc error */
                    244:     strcpy(result, "file://");
                    245:     strncat(result, file, end-file);
                    246:     colon = strchr(result+7, ':');     /* Expect colon after host */
                    247:     if (colon) {
                    248:        for(; colon[0]; colon[0]=colon[1], colon++);    /* move down */
                    249:     }
                    250:     return result;
                    251: } /* WWW_from_archie */
                    252: 
2.54      frystyk   253: 
2.2       timbl     254: /*     Transform document identifier into URL
                    255: **     --------------------------------------
2.1       timbl     256: **
                    257: ** Bugs: A static buffer of finite size is used!
                    258: **     The format of the docid MUST be good!
                    259: **
                    260: ** On exit,
                    261: **     returns         nil if error
                    262: **                     pointer to malloced string (must be freed) if ok
                    263: */
2.9       timbl     264: PRIVATE char hex [17] = "0123456789ABCDEF";
2.2       timbl     265: 
2.42      frystyk   266: PRIVATE char * WWW_from_WAIS (any * docid)
2.2       timbl     267: 
2.1       timbl     268: {
2.21      frystyk   269:     static unsigned char buf[BIG];
                    270:     char num[10];
                    271:     unsigned char * q = buf;
2.1       timbl     272:     char * p = (docid->bytes);
                    273:     int i, l;
2.25      frystyk   274:     if (PROT_TRACE) {
2.1       timbl     275:        char *p;
2.45      eric      276:        HTTrace("HTLoadWAIS.. id (%d bytes) is ", (int)docid->size);
2.1       timbl     277:        for(p=docid->bytes; p<docid->bytes+docid->size; p++) {
                    278:            if ((*p >= ' ') && (*p<= '~')) /* Assume ASCII! */
2.45      eric      279:                HTTrace("%c", *p);
2.1       timbl     280:            else
2.45      eric      281:                HTTrace("<%x>", (unsigned)*p);
2.1       timbl     282:        }
2.45      eric      283:        HTTrace("\n");
2.1       timbl     284:     }   
                    285:     for (p=docid->bytes; (p<docid->bytes+docid->size) && (q<&buf[BIG]);) {
2.25      frystyk   286:        if (PROT_TRACE)
2.45      eric      287:            HTTrace("............ Record type %d, length %d\n",
2.24      frystyk   288:                    (unsigned char) p[0], (unsigned char) p[1]);
2.21      frystyk   289:        sprintf(num, "%d", (int)*p);
                    290:        memcpy(q, num, strlen(num));
                    291:        q += strlen(num);
                    292:        p++;
                    293:        *q++ = '=';             /* Separate */
                    294:        l = (int)((unsigned char)*p);
                    295:        p++;
                    296:        if (l > 127)
                    297:            {
                    298:                l = (l - 128) * 128;
                    299:                l = l + (int)((unsigned char)*p);
                    300:                p++;
                    301:            }
                    302:        
                    303:        for (i = 0; i < l; i++, p++)
                    304:            {
                    305:                if (!acceptable[(unsigned char)*p]) 
                    306:                    {
                    307:                        *q++ = HEX_ESCAPE;
                    308:                        *q++ = hex[((unsigned char)*p) >> 4];
                    309:                        *q++ = hex[((unsigned char)*p) & 15];
                    310:                    }
                    311:                else *q++ = (unsigned char)*p;
                    312:            }
                    313:        *q++= ';';              /* Terminate field */
                    314: #ifdef OLD_CODE
2.1       timbl     315:         if (*p>10) {
2.25      frystyk   316:            if (PROT_TRACE)
2.45      eric      317:                HTTrace("WAIS........ DOCID record type of %d!\n", *p);
2.1       timbl     318:            return 0;
                    319:        }
2.2       timbl     320:        {       /* Bug fix -- allow any byte value 15 Apr 93 */
                    321:            unsigned int i = (unsigned) *p++;
                    322:            
                    323:            if (i > 99) {
                    324:                *q++ = (i/100) + '0';
                    325:                i = i % 100;
                    326:            }
                    327:            if (i > 9) {
                    328:                *q++ = (i/10) + '0';
                    329:                i = i % 10;
                    330:            }
                    331:            *q++ = i + '0';     /* Record type */
                    332:        }
2.1       timbl     333:        *q++ = '=';             /* Separate */
                    334:        l = *p++;               /* Length */
                    335:        for(i=0; i<l; i++, p++){
2.18      luotonen  336:            if (!acceptable[(int)*p]) {
2.1       timbl     337:                *q++ = HEX_ESCAPE;      /* Means hex commming */
                    338:                *q++ = hex[(*p) >> 4];
                    339:                *q++ = hex[(*p) & 15];
                    340:            }
                    341:            else *q++ = *p;
                    342:        }
                    343:        *q++= ';';              /* Terminate field */
2.21      frystyk   344: #endif /* OLD_CODE */
2.1       timbl     345:     }
                    346:     *q++ = 0;                  /* Terminate string */
2.45      eric      347:     if (PROT_TRACE) HTTrace("HTLoadWAIS.. WWW form of id: %s\n", buf); 
2.1       timbl     348:     {
2.24      frystyk   349:         char *result;
2.49      frystyk   350:        if ((result = (char *) HT_MALLOC((int) strlen((char *) buf)+1))==NULL)
2.44      frystyk   351:            HT_OUTOFMEM("WWW_from_WAIS");
2.49      frystyk   352:        strcpy(result, (char *) buf);
2.1       timbl     353:        return result;
                    354:     }
                    355: } /* WWW_from_WAIS */
                    356: 
                    357: 
2.2       timbl     358: /*     Transform URL into WAIS document identifier
                    359: **     -------------------------------------------
2.1       timbl     360: **
                    361: ** On entry,
                    362: **     docname         points to valid name produced originally by
                    363: **                     WWW_from_WAIS
                    364: ** On exit,
                    365: **     docid->size     is valid
                    366: **     docid->bytes    is malloced and must later be freed.
                    367: */
2.42      frystyk   368: PRIVATE any * WAIS_from_WWW  (any * docid, char * docname)
2.1       timbl     369: {
                    370:     char *z;   /* Output pointer */
                    371:     char *sor; /* Start of record - points to size field. */
                    372:     char *p;   /* Input pointer */
                    373:     char *q;   /* Poisition of "=" */
                    374:     char *s;   /* Position of semicolon */
                    375:     int n;     /* size */
2.25      frystyk   376:     if (PROT_TRACE)
2.45      eric      377:        HTTrace("HTLoadWAIS.. WWW id (to become WAIS id): %s\n",
2.24      frystyk   378:                docname); 
2.1       timbl     379:     for(n=0, p = docname; *p; p++) {   /* Count sizes of strings */
                    380:         n++;
                    381:        if (*p == ';')  n--;            /* Not converted */
                    382:        else if (*p == HEX_ESCAPE) n=n-2;       /* Save two bytes */
                    383:         docid->size = n;
                    384:     }
                    385:     
2.44      frystyk   386:     /* result record */
                    387:     if ((docid->bytes = (char *) HT_MALLOC(docid->size+32)) == NULL)
                    388:        HT_OUTOFMEM("docid->bytes");
2.1       timbl     389:     z = docid->bytes;
                    390:     
2.21      frystyk   391:     for(p = docname; *p; ) {
                    392:        q = strchr(p, '=');
                    393:        if (!q) 
                    394:            return 0;
                    395:        *q = '\0';
                    396:        *z++ = atoi(p);
                    397:        *q = '=';
                    398:        s = strchr(q, ';');     /* (Check only) */
                    399:        if (!s) 
                    400:            return 0;   /* Bad! No ';'; */
                    401:        sor = z;          /* Remember where the size field was */
                    402:        z++;              /* Skip record size for now */
                    403:        
                    404:        {
                    405:            int len;
                    406:            int tmp;
                    407:            for(p=q+1; *p!=';' ; ) {
                    408:                if (*p == HEX_ESCAPE) {
                    409:                    char c;
                    410:                    unsigned int b;
                    411:                    p++;
                    412:                    c = *p++;
2.54      frystyk   413:                    b = HTAsciiHexToChar(c);
2.21      frystyk   414:                    c = *p++;
                    415:                    if (!c) 
                    416:                        break;  /* Odd number of chars! */
2.54      frystyk   417:                    *z++ = (b<<4) + HTAsciiHexToChar(c);
2.21      frystyk   418:                } else {
                    419:                    *z++ = *p++;        /* Record */
                    420:                }
                    421:            }
                    422:            len = (z-sor-1);
                    423:            
                    424:            z = sor;
                    425:            if (len > 127) {
                    426:                tmp = (len / 128);
                    427:                len = len - (tmp * 128);
                    428:                tmp = tmp + 128;
                    429:                *z++ = (char)tmp;
                    430:                *z = (char)len;
                    431:            } else {
                    432:                *z = (char)len;
                    433:            }
                    434:            z++;
                    435:        }
                    436:        
                    437:        for(p=q+1; *p!=';' ; )  {
                    438:            if (*p == HEX_ESCAPE) {
                    439:                char c;
                    440:                unsigned int b;
                    441:                p++;
                    442:                c = *p++;
2.54      frystyk   443:                b = HTAsciiHexToChar(c);
2.21      frystyk   444:                c = *p++;
                    445:                if (!c) 
                    446:                    break;      /* Odd number of chars! */
2.54      frystyk   447:                *z++ = (b<<4) + HTAsciiHexToChar(c);
2.21      frystyk   448:            } else {
                    449:                *z++ = *p++;    /* Record */
                    450:            }
                    451:        }
                    452:        p++;                    /* After semicolon: start of next record */
                    453:     }
                    454: 
                    455: #ifdef OLD_CODE
2.1       timbl     456:     for(p = docname; *p; ) {   /* Convert of strings */
2.2       timbl     457:                                /* Record type */
                    458:                                
                    459:        *z = 0;                 /* Initialize record type */
                    460:        while (*p >= '0' && *p <= '9') {
                    461:            *z = *z*10 + (*p++ - '0');  /* Decode decimal record type */
                    462:        }
                    463:        z++;
                    464:        if (*p != '=') return 0;
                    465:        q = p;
                    466:        
                    467: /*        *z++ = *p++ - '0';
2.1       timbl     468:        q = strchr(p , '=');
                    469:        if (!q) return 0;
2.2       timbl     470: */
2.1       timbl     471:        s = strchr(q, ';');     /* (Check only) */
                    472:        if (!s) return 0;       /* Bad! No ';'; */
                    473:         sor = z;               /* Remember where the size field was */
                    474:        z++;                    /* Skip record size for now     */
                    475:        for(p=q+1; *p!=';' ; ) {
                    476:           if (*p == HEX_ESCAPE) {
                    477:                char c;
                    478:                unsigned int b;
                    479:                p++;
                    480:                c = *p++;
2.54      frystyk   481:                b =   HTAsciiHexToChar(c);
2.1       timbl     482:                c = *p++;
                    483:                if (!c) break;  /* Odd number of chars! */
2.54      frystyk   484:                *z++ = (b<<4) + HTAsciiHexToChar(c);
2.1       timbl     485:            } else {
                    486:                *z++ = *p++;    /* Record */
                    487:            }
                    488:        }
                    489:        *sor = (z-sor-1);       /* Fill in size -- not counting size itself */
                    490:        p++;                    /* After semicolon: start of next record */
                    491:     }
2.21      frystyk   492: #endif /* OLD_CODE */
2.25      frystyk   493:     if (PROT_TRACE) {
2.1       timbl     494:        char *p;
2.45      eric      495:        HTTrace("WAIS........ id (%d bytes) is ", (int)docid->size);
2.1       timbl     496:        for(p=docid->bytes; p<docid->bytes+docid->size; p++) {
                    497:            if ((*p >= ' ') && (*p<= '~')) /* Assume ASCII! */
2.45      eric      498:                HTTrace("%c", *p);
2.1       timbl     499:            else
2.45      eric      500:                HTTrace("<%x>", (unsigned)*p);
2.1       timbl     501:        }
2.45      eric      502:        HTTrace("\n");
2.1       timbl     503:     }   
                    504:     return docid;              /* Ok */
                    505:     
                    506: } /* WAIS_from_WWW */
                    507: 
                    508: 
                    509: /*     Send a plain text record to the client          output_text_record()
                    510: **     --------------------------------------
                    511: */
2.2       timbl     512: 
2.42      frystyk   513: PRIVATE void output_text_record (
                    514:     HTStream *                 target,
                    515:     WAISDocumentText *         record,
                    516:     boolean                    quote_string_quotes,
                    517:     boolean                    binary)
2.1       timbl     518: {
                    519:   long count;
2.9       timbl     520:   if (binary) {
                    521:     (*target->isa->put_block)(target,
                    522:                              record->DocumentText->bytes,
                    523:                              record->DocumentText->size);
                    524:     return;
                    525:   }
                    526: 
2.1       timbl     527:   for(count = 0; count < record->DocumentText->size; count++){
                    528:     long ch = (unsigned char)record->DocumentText->bytes[count];
2.2       timbl     529:     if (ch == 27) {    /* What is this in for? Tim */
2.1       timbl     530: 
                    531:            /* then we have an escape code */
                    532:            /* if the next letter is '(' or ')', then ignore two letters */
                    533:            if('(' == record->DocumentText->bytes[count + 1] ||
                    534:                ')' == record->DocumentText->bytes[count + 1])
                    535:            count += 1;             /* it is a term marker */
                    536:            else count += 4;            /* it is a paragraph marker */
                    537:     } else if (ch == '\n' || ch == '\r') {
2.2       timbl     538:            PUTC('\n');
2.1       timbl     539:     } else if ((ch=='\t') || isprint(ch)){
2.2       timbl     540:            PUTC(ch);
2.1       timbl     541:     } 
                    542:   }
                    543: } /* output text record */
                    544: 
                    545: 
2.2       timbl     546: 
2.1       timbl     547: /*     Format A Search response for the client         display_search_response
                    548: **     ---------------------------------------
2.42      frystyk   549: ** modified from tracy shen's version in wutil.c
                    550: ** displays either a text record or a set of headlines.
2.1       timbl     551: */
2.42      frystyk   552: void display_search_response (HTStructured *           target,
                    553:                              SearchResponseAPDU *      response,
                    554:                              char *                    database,
                    555:                              char *                    keywords)
2.1       timbl     556: {
                    557:   WAISSearchResponse  *info;
                    558:   long i, k;
2.54      frystyk   559:   char line[LINE_BUFFER_SIZE]; /* For building strings to display */
2.1       timbl     560:   
                    561:   BOOL archie =  strstr(database, "archie")!=0;        /* Specical handling */
2.54      frystyk   562: 
2.1       timbl     563:   
2.45      eric      564:   if (PROT_TRACE) HTTrace("WAIS........ Displaying search response\n");
2.1       timbl     565:   sprintf(line,
2.21      frystyk   566:          "Index %s contains the following %d item%s relevant to '%s'.\n",
                    567:          database,
                    568:          (int)(response->NumberOfRecordsReturned),
                    569:          response->NumberOfRecordsReturned ==1 ? "" : "s",
                    570:          keywords);
2.2       timbl     571:   PUTS(line);
                    572:   PUTS("The first figure for each entry is its relative score, ");
                    573:   PUTS("the second the number of lines in the item.");
                    574:   START(HTML_MENU);
                    575: 
2.1       timbl     576:   if ( response->DatabaseDiagnosticRecords != 0 ) {
                    577:     info = (WAISSearchResponse *)response->DatabaseDiagnosticRecords;
                    578:     i =0; 
                    579: 
                    580:     if (info->Diagnostics != NULL)
2.54      frystyk   581:       HTshowDiags((HTStream*)target, info->Diagnostics);
2.1       timbl     582: 
                    583:     if ( info->DocHeaders != 0 ) {
                    584:       for (k=0; info->DocHeaders[k] != 0; k++ ) {
                    585:        WAISDocumentHeader* head = info->DocHeaders[k];
                    586:        char * headline = trim_junk(head->Headline);
                    587:        any * docid = head->DocumentID;
                    588:        char * docname;                 /* printable version of docid */
                    589:        i++;
                    590: 
                    591: /*     Make a printable string out of the document id.
                    592: */
2.25      frystyk   593:        if (PROT_TRACE)
2.45      eric      594:            HTTrace("HTWAIS:  %2ld: Score: %4ld, lines:%4ld '%s'\n", i,
2.24      frystyk   595:                    (long int)(info->DocHeaders[k]->Score),
                    596:                    (long int)(info->DocHeaders[k]->Lines),
                    597:                    headline);
2.1       timbl     598: 
2.2       timbl     599:        START(HTML_LI);
                    600:        sprintf(line, "%4ld  %4ld  ",
                    601:            head->Score,
                    602:            head->Lines);
2.23      frystyk   603:        PUTS(line);
2.2       timbl     604: 
2.1       timbl     605:        if (archie) {
                    606:            char * www_name = WWW_from_archie(headline);
                    607:            if (www_name) {
2.2       timbl     608:                HTStartAnchor(target, NULL, www_name);
2.1       timbl     609:                PUTS(headline);
2.2       timbl     610:                
                    611:                END(HTML_A);
2.44      frystyk   612:                HT_FREE(www_name);
2.1       timbl     613:            } else {
2.2       timbl     614:                 PUTS(headline);
                    615:                 PUTS(" (bad file name)");
2.1       timbl     616:            }
                    617:        } else { /* Not archie */
                    618:            docname =  WWW_from_WAIS(docid);
                    619:            if (docname) {
2.6       timbl     620:                char * dbname = HTEscape(database, URL_XPALPHAS);
2.21      frystyk   621:                 char types_array[1000]; /* bad */
                    622:                 char *type_escaped;
                    623:                 types_array[0] = 0;
                    624:                 if (head->Types) {
                    625:                     int i;
                    626:                     for (i = 0; head->Types[i]; i++)
                    627:                       {
                    628:                         if (i)
                    629:                           strcat (types_array, ",");
                    630: 
                    631:                         type_escaped = HTEscape (head->Types[i], URL_XALPHAS);
                    632:                         strcat (types_array, type_escaped);
2.44      frystyk   633:                         HT_FREE(type_escaped);
2.21      frystyk   634:                       }
2.25      frystyk   635:                     if (PROT_TRACE)
2.45      eric      636:                       HTTrace("WAIS........ Types_array `%s\'\n",
2.24      frystyk   637:                               types_array);
2.21      frystyk   638:                } else {
                    639:                     strcat (types_array, "TEXT");
                    640:                }
                    641:                sprintf(line, "%s/%s/%d/%s",
                    642:                         dbname,
                    643:                         types_array,
                    644:                         (int)(head->DocumentLength),
                    645:                         docname);
                    646: #ifdef OLD_CODE
2.1       timbl     647:                sprintf(line, "%s/%s/%d/%s",            /* W3 address */
                    648:                                    dbname,
                    649:                    head->Types ? head->Types[0] : "TEXT",
2.2       timbl     650:                    (int)(head->DocumentLength),
2.1       timbl     651:                    docname);
2.21      frystyk   652: #endif /* OLD_CODE */
2.11      secret    653:                HTStartAnchor(target, NULL, ( (head->Types) 
                    654:                      && (!strcmp(head->Types[0], "URL"))) ? 
                    655:                              headline : line); /* NT, Sep 93 */
2.2       timbl     656:                PUTS(headline);
                    657:                END(HTML_A);
2.44      frystyk   658:                HT_FREE(dbname);
                    659:                HT_FREE(docname);
2.1       timbl     660:            } else {
2.2       timbl     661:                 PUTS("(bad doc id)");
2.1       timbl     662:            }
                    663:          }
                    664:       } /* next document header */
                    665:     } /* if there were any document headers */
                    666:     
                    667:     if ( info->ShortHeaders != 0 ) {
                    668:       k =0;
                    669:       while (info->ShortHeaders[k] != 0 ) {
                    670:        i++;
2.2       timbl     671:        PUTS( "(Short Header record, can't display)");
2.1       timbl     672:       }
                    673:     }
                    674:     if ( info->LongHeaders != 0 ) {
                    675:       k =0;
                    676:       while (info->LongHeaders[k] != 0) {
                    677:        i++;
                    678:        PUTS( "\nLong Header record, can't display\n");
                    679:       }
                    680:     }
                    681:     if ( info->Text != 0 ) {
                    682:       k =0;
                    683:       while (info->Text[k] != 0) {
                    684:        i++;
                    685:        PUTS( "\nText record\n");
2.9       timbl     686:        output_text_record((HTStream*)target, info->Text[k++], false, false);
2.1       timbl     687:       }
                    688:     }
                    689:     if ( info->Headlines != 0 ) {
                    690:       k =0;
                    691:       while (info->Headlines[k] != 0) {
                    692:        i++;
                    693:        PUTS( "\nHeadline record, can't display\n");
                    694:        /* dsply_headline_record( info->Headlines[k++]); */
                    695:       }
                    696:     }
                    697:     if ( info->Codes != 0 ) {
                    698:       k =0;
                    699:       while (info->Codes[k] != 0) {
                    700:        i++;
                    701:        PUTS( "\nCode record, can't display\n");
                    702:        /* dsply_code_record( info->Codes[k++]); */
                    703:       }
                    704:     }
                    705:   }                            /* Loop: display user info */
2.2       timbl     706:   END(HTML_MENU);
2.1       timbl     707:   PUTC('\n'); ;
                    708: }
                    709: 
                    710: 
2.54      frystyk   711: /*     HTWAISCleanup
                    712: **     -----------
                    713: **      This function closes the connection and frees memory.
                    714: **      Returns YES on OK, else NO
                    715: */
                    716: PRIVATE int HTWAISCleanup (HTRequest *req, int status)
                    717: {
                    718:  HTNet* net;
                    719:  HTStream* input;
                    720:  wais_info* theWAISinfo = NULL;
                    721: 
                    722: 
                    723:  if (req)
                    724:    {
                    725:     net = HTRequest_net(req);
                    726:     input = HTRequest_inputStream(req);
                    727: 
                    728:     /* Free stream with data TO network */
                    729:     if (HTRequest_isDestination(req))
                    730:       HTRequest_removeDestination(req);
                    731:      else
                    732:       if (input)
                    733:        {
                    734:         if (status == HT_INTERRUPTED)
                    735:           (*input->isa->abort)(input, NULL);
                    736:          else
                    737:           (*input->isa->_free)(input);
                    738: 
                    739:         HTRequest_setInputStream(req, NULL);
                    740:        }
                    741: 
                    742:     if (net)
                    743:       {
                    744:        if ((theWAISinfo = (wais_info*)HTNet_context(net)))
                    745:         {
                    746:          theWAISinfo->state = HTWAIS_CLEANUP;
                    747: 
                    748:          if (theWAISinfo->connection)
                    749:            close_connection_to_server(theWAISinfo->connection);
                    750: 
                    751:          if (theWAISinfo->wais_database)
                    752:            HT_FREE(theWAISinfo->wais_database);
                    753: 
                    754:          if (theWAISinfo->request_message)
                    755:            s_free(theWAISinfo->request_message);
                    756: 
                    757:          if (theWAISinfo->response_message)
                    758:            s_free(theWAISinfo->response_message);
                    759: 
                    760:          HT_FREE(theWAISinfo->names);
                    761:          HT_FREE(theWAISinfo->basetitle);
                    762: 
                    763:          if (status < 0)
                    764:            {
                    765:             HTParentAnchor* anchor;
                    766:             char* unescaped = NULL;
                    767:             void* err_par;
                    768:             unsigned int err_par_length;
                    769: 
                    770:             if ((anchor = HTRequest_anchor(req)))   /* Be robust */
                    771:               {
                    772:                char* arg;
                    773: 
                    774:                if ((arg = HTAnchor_physical(anchor)))
                    775:                  {
                    776:                   StrAllocCopy(unescaped, arg);
                    777:                   HTUnEscape(unescaped);
                    778:                  }
                    779:               }
                    780: 
                    781:             if (unescaped)
                    782:               {
                    783:                err_par = (void*)unescaped;
                    784:                err_par_length = (unsigned int)(strlen(unescaped));
                    785:               }
                    786:              else
                    787:               {
                    788:                err_par = (void*)"???";
                    789:                err_par_length = 3;
                    790:               }
                    791: 
                    792:             HTRequest_addError(req, ERR_FATAL, NO, HTERR_INTERNAL,
                    793:                                err_par, err_par_length, "HTLoadWAIS");
                    794:             if (unescaped) HT_FREE(unescaped);
                    795:            }
                    796: 
                    797:          /* Free and remove our own context structure for wais */
                    798:          HT_FREE(theWAISinfo);
                    799:          HTNet_setContext(net, NULL);
                    800:         }
                    801:        /* End ``if (theWAISinfo)'' */
                    802: 
                    803:        /* Remove the request object */
                    804:        HTNet_delete(net, status);
                    805:       }
                    806: 
                    807:     return YES;
                    808:    }
                    809:   else
                    810:    return NO;
                    811: }
                    812: 
                    813: 
2.1       timbl     814: 
2.2       timbl     815: 
2.20      frystyk   816: /*     Load Document from WAIS Server                          HTLoadWAIS()
                    817: **     ------------------------------
2.2       timbl     818: **
2.20      frystyk   819: ** On entry,
                    820: **     request         This is the request structure
                    821: ** On exit,
                    822: **     returns         <0              Error has occured
                    823: **                     HT_LOADED       OK
2.1       timbl     824: */
                    825: 
2.21      frystyk   826: #define MAX_KEYWORDS_LENGTH 4000
2.54      frystyk   827: #define MAX_SERVER_LENGTH   1000
2.1       timbl     828: #define MAX_DATABASE_LENGTH 1000
2.54      frystyk   829: #define MAX_SERVICE_LENGTH  1000
2.1       timbl     830: 
2.54      frystyk   831: PRIVATE int HTWAISEvent(SOCKET soc, void * pVoid, HTEventType type)
2.1       timbl     832: {
2.54      frystyk   833:  wais_info* theWAISinfo;  /* Specific protocol information */
                    834:  HTNet* net;              /* Generic protocol information */
                    835:  HTRequest* request;
                    836:  HTParentAnchor* anchor;
                    837:  const char * arg;
                    838:  HTStream* sink;
                    839:  HTFormat format_out;
                    840: #if 0
                    841:  static const char * error_header = "<h1>Access error</h1>\n<p>The following error occured in accesing a WAIS server:\n</p>\n";
                    842: #endif
                    843:  char* key;                      /* pointer to keywords in URL */
                    844:  long request_buffer_length;   /* how of the request is left */
                    845:  SearchResponseAPDU* retrieval_response = 0;
                    846:  char keywords[MAX_KEYWORDS_LENGTH + 1];
                    847:  char* server_name = NULL;
                    848:  char* service;
                    849:  char* docname = NULL;
                    850:  char* doctype = NULL;
                    851:  long document_length = -1;
                    852:  BOOL ok = NO;
                    853:  int status = HT_ERROR;
                    854: 
                    855: #if 0
                    856:  FILE* connection = 0;
                    857:  char* names;          /* Copy of arg to be hacked up */
                    858:  char* basetitle = NULL;
                    859:  char* wais_database = NULL;    /* name of current database */
                    860:  char*  www_database = NULL;    /* Same name escaped */
                    861:  char*  request_message = NULL; /* arbitrary message limit */
                    862:  char* response_message = NULL; /* arbitrary message limit */
2.20      frystyk   863: #endif
2.1       timbl     864:     
2.31      frystyk   865: #if 0
2.54      frystyk   866:  extern FILE * connect_to_server();
2.31      frystyk   867: #endif
2.54      frystyk   868: 
                    869: 
                    870:  if ((theWAISinfo = (wais_info*)pVoid))   /* Be robust */
                    871:    {
                    872:     if ((net = theWAISinfo->net) == NULL) return HT_ERROR;
                    873:     if ((request = HTNet_request(net)) == NULL) return HT_ERROR;
                    874:     if ((anchor = HTRequest_anchor(request)))
                    875:       arg = HTAnchor_physical(anchor);
                    876:      else
                    877:       return HT_ERROR;
                    878: 
                    879:     sink = HTRequest_outputStream(request);
                    880:     format_out = HTRequest_outputFormat(request);
                    881:    }
                    882:   else
                    883:    return HT_ERROR;
2.1       timbl     884:     
2.54      frystyk   885: 
                    886:  if (type == HTEvent_BEGIN)
                    887:    {
                    888:     theWAISinfo->state  = HTWAIS_BEGIN;
                    889:     theWAISinfo->result = HT_ERROR;
                    890:    }
                    891:   else
                    892:    if (type == HTEvent_CLOSE)
                    893:      {
                    894:      /* Interrupted */
                    895:       char interrupted[] = "request interruption";
                    896: 
                    897:       HTRequest_addError(request, ERR_FATAL, NO, HTERR_INTERRUPTED,
                    898:                         (void*)interrupted, (unsigned int)strlen(interrupted),
                    899:                         "HTLoadWAIS");
                    900:       HTWAISCleanup(request, HT_INTERRUPTED);
                    901:       return HT_OK;
2.1       timbl     902:      }
2.54      frystyk   903:     else
                    904:      if (type == HTEvent_END)
                    905:        {
                    906:        HTWAISCleanup(request, (theWAISinfo ? theWAISinfo->result : HT_ERROR));
                    907:        return HT_OK;
                    908:        }
                    909: 
                    910: 
                    911:  /*    Decipher and check syntax of WWW address:
                    912:  **    ----------------------------------------
                    913:  **
                    914:  **    First we remove the "wais:" if it was spcified.  920110
                    915:  */
                    916: 
                    917:  if (!acceptable_inited) init_acceptable();
                    918:  theWAISinfo->state = HTWAIS_PARSING_URL;
                    919:  if (PROT_TRACE) HTTrace("HTLoadWAIS.. Looking for \"%s\"\n", arg);
                    920: 
                    921:  theWAISinfo->names = HTParse(arg, "",
                    922:                              PARSE_HOST | PARSE_PATH | PARSE_PUNCTUATION);
                    923:  key = strchr(theWAISinfo->names, '?');
                    924: 
                    925:  if (key)
                    926:    {
                    927:     char* p;
                    928: 
                    929:     *key++ = 0;        /* Split off keywords */
                    930: 
                    931:     for (p=key; *p; p++) if (*p == '+') *p = ' ';
                    932:     HTUnEscape(key);
                    933:    }
                    934: 
                    935:  if (theWAISinfo->names[0] == '/')
                    936:    {
                    937:     server_name = theWAISinfo->names+1;
                    938: 
                    939:        /* Accept one or two */
                    940:     if ((theWAISinfo->as_gate = (*server_name == '/'))) server_name++;
                    941: 
                    942:     if ((theWAISinfo->www_database = strchr(server_name, '/')))
                    943:       {
                    944:        *(theWAISinfo->www_database)++ = 0;  /* Separate database name */
                    945:        doctype = strchr(theWAISinfo->www_database, '/');
                    946: 
                    947:        if (key)
                    948:         ok = YES;      /* Don't need doc details */
                    949:         else
                    950:         if (doctype)
                    951:           {    /* If not search parse doc details */
                    952:            char* doclength;
                    953: 
                    954:            *doctype++ = 0;     /* Separate rest of doc address */
                    955:            doclength = strchr(doctype, '/');
                    956:            if (doclength)
                    957:              {
                    958:               *doclength++ = 0;
                    959:               document_length = atol(doclength);
                    960:               if (document_length)
                    961:                 {
                    962:                  docname = strchr(doclength, '/');
                    963:                  if (docname)
                    964:                    {
                    965:                     *docname++ = 0;
                    966:                     ok = YES;  /* To avoid a goto! */
                    967:                    } /* if docname */
                    968:                 } /* if document_length valid */
                    969:              } /* if doclength */
                    970:           }
                    971:          else
                    972:           { /* no doctype?  Assume index required */
                    973:            if (!key) key = "";
                    974:            ok = YES;
                    975:           } /* if doctype */
                    976:       } /* if database */
                    977:    }
2.1       timbl     978:      
2.54      frystyk   979:  if (!ok)
                    980:    {
                    981:     char *unescaped = NULL;
                    982: 
                    983:     StrAllocCopy(unescaped, arg);
                    984:     HTUnEscape(unescaped);
                    985:     HTRequest_addError(request, ERR_FATAL, NO, HTERR_BAD_REQUEST,
                    986:                       (void *) unescaped, (int) strlen(unescaped),
                    987:                       "HTLoadWAIS");
                    988:     HT_FREE(unescaped);
                    989:     HT_FREE(theWAISinfo->names);
                    990:     return -1;
                    991:    }
2.21      frystyk   992:     
2.54      frystyk   993:  if (PROT_TRACE) HTTrace("HTLoadWAIS.. URL Parsed OK\n");
                    994:  theWAISinfo->state = HTWAIS_NEED_CONNECTION;
                    995: 
                    996:  if ((service = strchr(theWAISinfo->names, ':')))
                    997:    *service++ = 0;
                    998:   else
                    999:    service = "210";
                   1000: 
                   1001:  if ((server_name ? server_name[0] : 0))
                   1002:    {
                   1003:     boolean do_need_to_connect_to_server = true;
                   1004: 
                   1005:     if (key) if ((*key) == 0) do_need_to_connect_to_server = false;
                   1006: 
                   1007:     if (do_need_to_connect_to_server)
                   1008:       {
                   1009:        if ((theWAISinfo->connection = connect_to_server(server_name,
                   1010:                                                        atoi(service)))
                   1011:           == NULL)
                   1012:         {
                   1013:          char* host = HTParse(arg, "", PARSE_HOST);
2.1       timbl    1014: 
2.25      frystyk  1015:          if (PROT_TRACE)
2.54      frystyk  1016:            HTTrace("HTLoadWAIS.."
                   1017:                    " Can't open connection to %s via service %s.\n",
                   1018:                    server_name, service);
                   1019: 
2.40      frystyk  1020:          HTRequest_addError(request, ERR_FATAL, NO, HTERR_WAIS_NO_CONNECT,
2.54      frystyk  1021:                             (void *) host, (int) strlen(host), "HTLoadWAIS");
                   1022:          theWAISinfo->result = HT_ERROR;
                   1023:          HTWAISCleanup(request, status);
                   1024:          return status;
                   1025:         }
2.20      frystyk  1026:       }
2.54      frystyk  1027:    }
                   1028:   else
                   1029:    theWAISinfo->connection = NULL;
                   1030: 
                   1031:  StrAllocCopy(theWAISinfo->wais_database, theWAISinfo->www_database);
                   1032:  HTUnEscape(theWAISinfo->wais_database);
                   1033: 
                   1034: 
                   1035:  /* Make title name without the .src */
                   1036:  {
                   1037:   char *srcstr;
                   1038: 
                   1039:   StrAllocCopy(theWAISinfo->basetitle, theWAISinfo->wais_database);
                   1040:   if ((srcstr = strstr(theWAISinfo->basetitle, ".src")) != NULL)
                   1041:     *srcstr = '\0';
                   1042:  }
                   1043:     
2.1       timbl    1044: 
2.54      frystyk  1045:  /* This below fixed size stuff is terrible */
                   1046:  if ((theWAISinfo->request_message =
                   1047:                        (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char)))
                   1048:      == NULL)
                   1049:    HT_OUTOFMEM("WAIS request message");
                   1050: 
                   1051:  if ((theWAISinfo->response_message =
                   1052:                        (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char)))
                   1053:      == NULL)
                   1054:    HT_OUTOFMEM("WAIS response message");
                   1055: 
                   1056: 
                   1057:  /*    If keyword search is performed but there are no keywords,
                   1058:  **    the user has followed a link to the index itself.
                   1059:  **     It would be appropriate at this point to send him the .SRC file - how?
                   1060:  */
                   1061: 
                   1062:  if (key)
                   1063:    {
                   1064:     if (*key)
                   1065:       {
                   1066:       /*
                   1067:        *   S E A R C H   (nonempty key (*key != 0))
                   1068:        */
                   1069:        char *p;
                   1070:        HTStructured* target;
                   1071: 
                   1072:        theWAISinfo->state = HTWAIS_NEED_RESPONSE;
                   1073: 
                   1074:        strncpy(keywords, key, MAX_KEYWORDS_LENGTH);
                   1075:        while ((p = strchr(keywords,'+'))) *p = ' ';
                   1076: 
                   1077:        /* Send advance title to get something fast to the other end */
                   1078: 
                   1079:        target = HTMLGenerator(request, NULL, WWW_HTML, format_out, sink);
                   1080: 
                   1081:        START(HTML_HTML);
                   1082:        START(HTML_HEAD);
                   1083:        START(HTML_TITLE);
                   1084:        PUTS(keywords);
                   1085:        PUTS(" in ");
                   1086:        PUTS(theWAISinfo->basetitle);
                   1087:        END(HTML_TITLE);
                   1088:        END(HTML_HEAD);
                   1089: 
                   1090:        START(HTML_BODY);
                   1091:        START(HTML_H1);
                   1092:        PUTS("WAIS Search of \"");
                   1093:        PUTS(keywords);
                   1094:        PUTS("\" in ");
                   1095:        PUTS(theWAISinfo->basetitle);
                   1096:        END(HTML_H1);
                   1097: 
                   1098:        START(HTML_ISINDEX);
                   1099: 
                   1100:        request_buffer_length = MAX_MESSAGE_LEN; /* Amount left */
                   1101:        if (PROT_TRACE)
                   1102:         HTTrace("HTLoadWAIS.. Search for `%s' in `%s'\n",
                   1103:                 keywords, theWAISinfo->wais_database);
2.21      frystyk  1104: 
2.54      frystyk  1105:        if (generate_search_apdu(theWAISinfo->request_message + HEADER_LENGTH, 
                   1106:                                &request_buffer_length, 
                   1107:                                keywords, theWAISinfo->wais_database, NULL,
                   1108:                                HTMaxWAISLines) == NULL)
                   1109:         {
                   1110:          if (PROT_TRACE)
                   1111:            HTTrace("WAIS Search. Too many lines in response\n");
                   1112: 
                   1113:          HTRequest_addError(request, ERR_WARN, NO, HTERR_WAIS_OVERFLOW, 
                   1114:                             NULL, 0, "HTLoadWAIS");
                   1115:         }
                   1116: 
                   1117:        if (!interpret_message(theWAISinfo->request_message, 
                   1118:                              MAX_MESSAGE_LEN - request_buffer_length, 
                   1119:                              theWAISinfo->response_message,
                   1120:                              MAX_MESSAGE_LEN,
                   1121:                              theWAISinfo->connection,
                   1122:                              false     /* true verbose */
                   1123:                              ))
                   1124:         {
                   1125:          if (PROT_TRACE)
                   1126:            HTTrace("WAIS Search. Too many lines in response\n");
                   1127: 
                   1128:          HTRequest_addError(request, ERR_WARN, NO, HTERR_WAIS_OVERFLOW, 
                   1129:                             NULL, 0, "HTLoadWAIS");
                   1130:         }
                   1131:         else
                   1132:         {      /* returned message ok */
                   1133:          SearchResponseAPDU  *query_response = 0;
                   1134: 
                   1135:          readSearchResponseAPDU(&query_response,
                   1136:                                theWAISinfo->response_message + HEADER_LENGTH);
                   1137:          display_search_response(target, 
                   1138:                                  query_response, theWAISinfo->wais_database,
                   1139:                                  keywords);
                   1140:          if (query_response->DatabaseDiagnosticRecords)
                   1141:            freeWAISSearchResponse(query_response->DatabaseDiagnosticRecords);
                   1142: 
                   1143:          freeSearchResponseAPDU(query_response);
                   1144:         }      /* returned message not too large */
                   1145: 
                   1146:        END(HTML_BODY);
                   1147:        END(HTML_HTML);
                   1148:        FREE_TARGET;
                   1149: 
                   1150:        HTAnchor_setFormat(anchor, WWW_HTML);
2.1       timbl    1151: 
2.54      frystyk  1152:        theWAISinfo->result = status = HT_LOADED;
                   1153:       }
                   1154:      else
                   1155:       {
                   1156:       /*
                   1157:        *   I N D E X   (key is empty (*key = 0))
                   1158:        */
2.7       timbl    1159: #ifdef CACHE_FILE_PREFIX
2.54      frystyk  1160:        char filename[256];
                   1161:        FILE * fp;
2.7       timbl    1162: #endif
2.54      frystyk  1163:        HTStructured* target = HTMLGenerator(request, NULL,
                   1164:                                            WWW_HTML, format_out, sink);
2.21      frystyk  1165: 
2.54      frystyk  1166:        theWAISinfo->state = HTWAIS_NEED_REQUEST;
2.2       timbl    1167: 
2.54      frystyk  1168:        {
2.23      frystyk  1169:        START(HTML_HTML);
                   1170:        START(HTML_HEAD);
2.2       timbl    1171:        START(HTML_TITLE);
2.54      frystyk  1172:        PUTS(theWAISinfo->basetitle);
                   1173:        PUTS(" Index");
2.2       timbl    1174:        END(HTML_TITLE);
2.23      frystyk  1175:        END(HTML_HEAD);
2.54      frystyk  1176: 
2.23      frystyk  1177:        START(HTML_BODY);
2.2       timbl    1178:        START(HTML_H1);
2.54      frystyk  1179:        PUTS("WAIS Index: ");
                   1180:        PUTS(theWAISinfo->basetitle);
2.2       timbl    1181:        END(HTML_H1);
2.54      frystyk  1182:        }
                   1183: 
                   1184:        START(HTML_ISINDEX);
2.1       timbl    1185: 
2.54      frystyk  1186:        /* If we have seen a source file for this database, use that: */
2.21      frystyk  1187: 
2.54      frystyk  1188: #ifdef CACHE_FILE_PREFIX
                   1189:        sprintf(filename,
                   1190:               "%sWSRC-%s:%s:%.100s.txt",
                   1191:               CACHE_FILE_PREFIX,
                   1192:               server_name, service, theWAISinfo->www_database);
                   1193: 
                   1194:        fp = fopen(filename, "r");      /* Have we found this already? */
                   1195:        if (PROT_TRACE)
                   1196:         HTTrace("HTLoadWAIS.. Description of server %s %s.\n",
                   1197:                 filename,
                   1198:                 fp ? "exists already" : "does NOT exist!");
                   1199: 
                   1200:        if (fp)
                   1201:         {
                   1202:          int c;
                   1203: 
                   1204:          START(HTML_PRE);   /* Preformatted description */
                   1205:          while((c=getc(fp)) != EOF) PUTC(c);   /* Transfer file */
                   1206:          END(HTML_PRE);
                   1207:          fclose(fp);
                   1208:         }
                   1209: #endif
                   1210: 
                   1211:        END(HTML_BODY);
                   1212:        END(HTML_HTML);
                   1213:        FREE_TARGET;
                   1214:       }
                   1215: 
                   1216:     HTAnchor_setFormat(anchor, WWW_HTML);
                   1217: 
                   1218:     theWAISinfo->result = status = HT_LOADED;
                   1219:    }
                   1220:   else
                   1221:    {/* document rather than search */
                   1222:    /*
                   1223:     *   D O C U M E N T    F E T C H   (no key (key == NULL))
                   1224:     */
                   1225:     boolean binary = true;     /* how to transfer stuff coming over */
                   1226:     HTStream* target;
                   1227:     HTAtom* document_type_atom = HTAtom_for("application/octet-stream");
                   1228:     long count;
                   1229:     any   doc_chunk;
                   1230:     any * docid = &doc_chunk;
                   1231: 
                   1232:     theWAISinfo->state = HTWAIS_FETCH_DOCUMENT;
                   1233:     if (PROT_TRACE)
                   1234:       HTTrace("HTLoadWAIS.. Retrieve document `%s'\n"
                   1235:              "............ type `%s' length %ld\n",
                   1236:              (docname ? docname : "unknown"),
                   1237:              (doctype ? doctype : "unknown"),
                   1238:              document_length);
                   1239: 
                   1240:     if (doctype)
                   1241:       {
                   1242:        if (strcmp(doctype, "WSRC") == 0)
                   1243:         {
                   1244:          document_type_atom = HTAtom_for("application/x-wais-source");
                   1245:          binary = false;
                   1246:         }
                   1247:         else
                   1248:         if (strcmp(doctype, "TEXT") == 0)
                   1249:           {
                   1250:            document_type_atom = WWW_UNKNOWN;
                   1251:            binary = false;
                   1252:           }
                   1253:          else
                   1254:           if (strcmp(doctype, "HTML") == 0)
                   1255:             {
                   1256:              document_type_atom = WWW_HTML;
                   1257:              binary = false;
                   1258:             }
                   1259:            else
                   1260:             if (strcmp(doctype, "GIF") == 0) document_type_atom = WWW_GIF;
                   1261:       }
                   1262: 
                   1263:     HTAnchor_setFormat(anchor, document_type_atom);
2.1       timbl    1264: 
2.54      frystyk  1265:     /* Guess on TEXT format as it might be HTML */
                   1266:     if ((target = HTStreamStack(HTAnchor_format(anchor),
                   1267:                                HTRequest_outputFormat(request),
                   1268:                                HTRequest_outputStream(request),
                   1269:                                request, YES))
                   1270:        == NULL)
                   1271:       {
                   1272:        theWAISinfo->result = HT_ERROR;
                   1273:        status = -1;
                   1274:        HTWAISCleanup(request, status);
                   1275:        return status;
                   1276:       }
2.2       timbl    1277: 
2.54      frystyk  1278:     /* Decode hex or litteral format for document ID */
                   1279:     WAIS_from_WWW(docid, docname);
2.2       timbl    1280: 
2.54      frystyk  1281:     /* Loop over slices of the document */
                   1282:     for (count = 0; count * CHARS_PER_PAGE < document_length; count++)
                   1283:       {
                   1284:        char *type = s_strdup(doctype);
                   1285: 
                   1286:        request_buffer_length = MAX_MESSAGE_LEN;              /* Amount left */
                   1287:        if (PROT_TRACE) HTTrace("HTLoadWAIS.. Slice number %ld\n", count);
                   1288:        if (generate_retrieval_apdu(theWAISinfo->request_message + HEADER_LENGTH,
                   1289:                                   &request_buffer_length, 
                   1290:                                   docid, CT_byte,
                   1291:                                   count * CHARS_PER_PAGE,
                   1292:                                   HTMIN((count + 1) * CHARS_PER_PAGE,
                   1293:                                         document_length),
                   1294:                                     type,
                   1295:                                   theWAISinfo->wais_database) == 0)
                   1296:         {
                   1297:          HTRequest_addError(request, ERR_WARN, NO, HTERR_WAIS_OVERFLOW, 
                   1298:                             NULL, 0, "HTLoadWAIS");
                   1299:         }
                   1300: 
                   1301:        HT_FREE(type);
                   1302: 
                   1303:        /* Actually do the transaction given by request_message */   
                   1304:        if (interpret_message(theWAISinfo->request_message, 
                   1305:                             MAX_MESSAGE_LEN - request_buffer_length, 
                   1306:                             theWAISinfo->response_message,
                   1307:                             MAX_MESSAGE_LEN,
                   1308:                             theWAISinfo->connection,
                   1309:                             false /* true verbose */   
                   1310:                             )
                   1311:           == 0)
                   1312:         {
                   1313:          HTRequest_addError(request, ERR_WARN, NO, HTERR_WAIS_OVERFLOW, 
                   1314:                             NULL, 0, "HTLoadWAIS");
                   1315:         }
                   1316: 
                   1317:        /* Parse the result which came back into memory. */
                   1318:        readSearchResponseAPDU(&retrieval_response, 
                   1319:                              theWAISinfo->response_message + HEADER_LENGTH);
                   1320:        {
                   1321:        WAISSearchResponse* searchres = (WAISSearchResponse*)retrieval_response->DatabaseDiagnosticRecords;
                   1322: 
                   1323:        if (!searchres->Text)
                   1324:          {
                   1325:           if (searchres->Diagnostics &&
                   1326:               *searchres->Diagnostics &&
                   1327:               (*searchres->Diagnostics)->ADDINFO)
                   1328:             {
                   1329:              char *errmsg = (*searchres->Diagnostics)->ADDINFO;
                   1330: 
                   1331:              HTRequest_addError(request, ERR_WARN, NO, HTERR_WAIS_MODULE,
                   1332:                                 (void *) errmsg, (int) strlen(errmsg),
                   1333:                                 "HTLoadWAIS");
                   1334:             }
                   1335:            else
                   1336:             {
                   1337:              HTRequest_addError(request, ERR_WARN, NO, HTERR_WAIS_MODULE,
                   1338:                                 NULL, 0, "HTLoadWAIS");
                   1339:             }
                   1340: 
                   1341:           (*target->isa->_free)(target);
                   1342:           HTRequest_setOutputStream(request, NULL);
                   1343:           HT_FREE(docid->bytes);
                   1344:           freeWAISSearchResponse(retrieval_response->DatabaseDiagnosticRecords); 
                   1345:           freeSearchResponseAPDU(retrieval_response);
                   1346:           theWAISinfo->result = HT_OK;
                   1347:           HTWAISCleanup(request, status);
                   1348:          }
                   1349:         else
                   1350:          {
                   1351:           output_text_record(target, *searchres->Text,
                   1352:                              false, binary);
                   1353:           freeWAISSearchResponse(retrieval_response->DatabaseDiagnosticRecords);
                   1354:           freeSearchResponseAPDU(retrieval_response);
                   1355:          } /* If text existed */
                   1356:        }
                   1357:       } /* Loop over slices */
                   1358: 
                   1359:     (*target->isa->_free)(target);
                   1360:     HTRequest_setOutputStream(request, NULL);
                   1361:     HT_FREE(docid->bytes);
                   1362: 
                   1363:     theWAISinfo->result = status = HT_LOADED;
                   1364:    }
                   1365:  /* End ``if (key)'' */
2.1       timbl    1366: 
2.54      frystyk  1367:  HTWAISCleanup(request, status);
2.1       timbl    1368: 
2.54      frystyk  1369:  return status;
2.1       timbl    1370: }
                   1371: 
2.54      frystyk  1372: 
                   1373: PUBLIC int HTLoadWAIS (SOCKET soc, HTRequest* request)
                   1374: {
                   1375:  wais_info* theWAISinfo;  /* Specific protocol information */
                   1376:  HTNet* net;              /* Generic protocol information */
                   1377:  HTParentAnchor* anchor;
                   1378: 
                   1379:  /*
                   1380:   * Initiate a new wais structure and bind to request structure.
                   1381:   * This is actually state HTWAIS_BEGIN,
                   1382:   * but it can't be in the state machine,
                   1383:   * as we need the structure first.
                   1384:   */
                   1385: 
                   1386:  if (request)
                   1387:    {
                   1388:     if ((anchor = HTRequest_anchor(request)) == NULL) return HT_ERROR;
                   1389:     if ((net = HTRequest_net(request)) == NULL) return HT_ERROR;
                   1390:    }
                   1391:   else
                   1392:    return HT_ERROR;
                   1393: 
                   1394:  if (PROT_TRACE)
                   1395:    HTTrace("HTWAIS...... Looking for `%s\'\n", HTAnchor_physical(anchor));
                   1396: 
                   1397:                      /* Get existing copy */
                   1398:  if ((theWAISinfo = (wais_info*)HTNet_context(net)) == NULL)
                   1399:    {
                   1400:     if ((theWAISinfo = (wais_info*)HT_CALLOC(1, sizeof(wais_info))) == NULL)
                   1401:       HT_OUTOFMEM("HTLoadWAIS");
                   1402: 
                   1403:     HTNet_setEventCallback(net, HTWAISEvent);
                   1404:     HTNet_setEventParam(net, theWAISinfo);  /* callbacks get theWAISinfo* */
                   1405:     HTNet_setContext(net, theWAISinfo);
                   1406: 
                   1407:     theWAISinfo->state  = HTWAIS_BEGIN;
                   1408:     theWAISinfo->result = HT_ERROR;
                   1409:     theWAISinfo->net    = net;
                   1410:    }
                   1411: 
                   1412:  /* get it started - ops is ignored */
                   1413:  return HTWAISEvent(soc, theWAISinfo, HTEvent_BEGIN);
                   1414: }

Webmaster