Annotation of libwww/Library/src/HTGopher.c, revision 2.7

1.1       timbl       1: /*                     GOPHER ACCESS                           HTGopher.c
                      2: **                     =============
                      3: **
                      4: ** History:
                      5: **     26 Sep 90       Adapted from other accesses (News, HTTP) TBL
                      6: **     29 Nov 91       Downgraded to C, for portable implementation.
                      7: */
                      8: 
1.2       timbl       9: /* Implements:
                     10: */
                     11: #include "HTGopher.h"
                     12: 
1.3       timbl      13: #define CR         FROMASCII('\015')   /* Carriage return */
                     14: #define LF         FROMASCII('\012')   /* ASCII line feed
                     15:                                   (sometimes \n is CR on Mac) */
                     16: 
1.1       timbl      17: #define GOPHER_PORT 70         /* See protocol spec */
                     18: #define BIG 1024               /* Bug */
                     19: #define LINE_LENGTH 256                /* Bug */
                     20: 
                     21: /*     Gopher entity types:
                     22: */
                     23: #define GOPHER_TEXT            '0'
                     24: #define GOPHER_MENU            '1'
                     25: #define GOPHER_CSO             '2'
                     26: #define GOPHER_ERROR           '3'
                     27: #define GOPHER_MACBINHEX       '4'
                     28: #define GOPHER_PCBINHEX                '5'
                     29: #define GOPHER_UUENCODED       '6'
                     30: #define GOPHER_INDEX           '7'
                     31: #define GOPHER_TELNET          '8'
2.7     ! secret     32: #define GOPHER_BINARY           '9'
1.3       timbl      33: #define GOPHER_GIF              'g'
2.7     ! secret     34: #define GOPHER_HTML            'h'             /* HTML */
        !            35: #define GOPHER_SOUND            's'
        !            36: #define GOPHER_WWW             'w'             /* W3 address */
1.3       timbl      37: #define GOPHER_IMAGE            'I'
2.7     ! secret     38: #define GOPHER_TN3270           'T'
1.1       timbl      39: #define GOPHER_DUPLICATE       '+'
                     40: 
                     41: #include <ctype.h>
                     42: #include "HTUtils.h"           /* Coding convention macros */
                     43: #include "tcp.h"
                     44: 
                     45: 
                     46: #include "HTParse.h"
                     47: #include "HTFormat.h"
                     48: #include "HTTCP.h"
                     49: 
1.2       timbl      50: /*             Hypertext object building machinery
                     51: */
                     52: #include "HTML.h"
                     53: 
                     54: #define PUTC(c) (*targetClass.put_character)(target, c)
                     55: #define PUTS(s) (*targetClass.put_string)(target, s)
                     56: #define START(e) (*targetClass.start_element)(target, e, 0, 0)
                     57: #define END(e) (*targetClass.end_element)(target, e)
                     58: #define END_TARGET (*targetClass.end_document)(target)
                     59: #define FREE_TARGET (*targetClass.free)(target)
                     60: struct _HTStructured {
                     61:        CONST HTStructuredClass *       isa;
                     62:        /* ... */
                     63: };
                     64: 
                     65: PRIVATE HTStructured *target;                  /* the new hypertext */
                     66: PRIVATE HTStructuredClass targetClass;         /* Its action routines */
                     67: 
                     68: 
1.1       timbl      69: #ifdef NeXTStep
                     70: #include <appkit/defaults.h>
                     71: #define GOPHER_PROGRESS(foo)
                     72: #else
                     73: #define GOPHER_PROGRESS(foo) fprintf(stderr, "%s\n", (foo))
                     74: #endif
                     75: 
                     76: #define NEXT_CHAR HTGetChararcter()
                     77: 
                     78: 
                     79: 
                     80: /*     Module-wide variables
                     81: */
                     82: PRIVATE int s;                                 /* Socket for GopherHost */
                     83: 
                     84: 
1.2       timbl      85: 
1.1       timbl      86: /*     Matrix of allowed characters in filenames
                     87: **     -----------------------------------------
                     88: */
                     89: 
                     90: PRIVATE BOOL acceptable[256];
                     91: PRIVATE BOOL acceptable_inited = NO;
                     92: 
                     93: PRIVATE void init_acceptable NOARGS
                     94: {
                     95:     unsigned int i;
                     96:     char * good = 
                     97:       "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_$";
                     98:     for(i=0; i<256; i++) acceptable[i] = NO;
                     99:     for(;*good; good++) acceptable[(unsigned int)*good] = YES;
                    100:     acceptable_inited = YES;
                    101: }
                    102: 
                    103: PRIVATE CONST char hex[17] = "0123456789abcdef";
                    104: 
                    105: /*     Decdoe one hex character
                    106: */
                    107: 
                    108: PRIVATE char from_hex ARGS1(char, c)
                    109: {
                    110:     return               (c>='0')&&(c<='9') ? c-'0'
                    111:                        : (c>='A')&&(c<='F') ? c-'A'+10
                    112:                        : (c>='a')&&(c<='f') ? c-'a'+10
                    113:                        :                      0;
                    114: }
                    115: 
                    116: 
                    117: 
                    118: /*     Paste in an Anchor
                    119: **     ------------------
                    120: **
                    121: **     The title of the destination is set, as there is no way
                    122: **     of knowing what the title is when we arrive.
                    123: **
                    124: ** On entry,
                    125: **     HT      is in append mode.
                    126: **     text    points to the text to be put into the file, 0 terminated.
                    127: **     addr    points to the hypertext refernce address 0 terminated.
                    128: */
                    129: PRIVATE void write_anchor ARGS2(CONST char *,text, CONST char *,addr)
                    130: {
1.2       timbl     131: 
                    132: 
                    133:     
                    134:     BOOL present[HTML_A_ATTRIBUTES];
                    135:     CONST char * value[HTML_A_ATTRIBUTES];
1.1       timbl     136:     
1.2       timbl     137:     int i;
                    138:     
                    139:     for (i=0; i<HTML_A_ATTRIBUTES; i++) present[i]=0;
                    140:     present[HTML_A_HREF] = YES;
                    141:     value[HTML_A_HREF] = addr;
                    142:     present[HTML_A_TITLE] = YES;
                    143:     value[HTML_A_TITLE] = text;
                    144:     
                    145:     (*targetClass.start_element)(target, HTML_A, present, value);
1.1       timbl     146:            
1.2       timbl     147:     PUTS(text);
                    148:     END(HTML_A);
1.1       timbl     149: }
                    150: 
                    151: 
                    152: /*     Parse a Gopher Menu document
                    153: **     ============================
                    154: **
                    155: */
                    156: 
                    157: PRIVATE void parse_menu ARGS2 (
1.2       timbl     158:        CONST char *,           arg,
                    159:        HTParentAnchor *,       anAnchor)
1.1       timbl     160: {
                    161:     char gtype;
                    162:     char ch;
                    163:     char line[BIG];
                    164:     char address[BIG];
                    165:     char *name, *selector;             /* Gopher menu fields */
                    166:     char *host;
                    167:     char *port;
                    168:     char *p = line;
1.2       timbl     169:     CONST char *title;
1.1       timbl     170: 
                    171: #define TAB            '\t'
                    172: #define HEX_ESCAPE     '%'
                    173: 
                    174:     
1.2       timbl     175:     title = HTAnchor_title(anAnchor);
                    176:     if (title) {
                    177:         START(HTML_H1);
                    178:        PUTS(title);
                    179:        END(HTML_H1);
                    180:     } else
                    181:         PUTS("Select one of:\n\n");
1.1       timbl     182:     
1.2       timbl     183:     START(HTML_MENU);
1.1       timbl     184:     while ((ch=NEXT_CHAR) != (char)EOF) {
1.3       timbl     185:         if (ch != LF) {
1.1       timbl     186:            *p = ch;            /* Put character in line */
                    187:            if (p< &line[BIG-1]) p++;
                    188:            
                    189:        } else {
                    190:            *p++ = 0;           /* Terminate line */
                    191:            p = line;           /* Scan it to parse it */
                    192:            port = 0;           /* Flag "not parsed" */
                    193:            if (TRACE) fprintf(stderr, "HTGopher: Menu item: %s\n", line);
                    194:            gtype = *p++;
                    195:            
                    196:            /* Break on line with a dot by itself */
                    197:            if ((gtype=='.') && ((*p=='\r') || (*p==0))) break;
                    198: 
                    199:            if (gtype && *p) {
                    200:                name = p;
                    201:                selector = strchr(name, TAB);
1.3       timbl     202:                START(HTML_LI);
1.1       timbl     203:                if (selector) {
                    204:                    *selector++ = 0;    /* Terminate name */
                    205:                    host = strchr(selector, TAB);
                    206:                    if (host) {
                    207:                        *host++ = 0;    /* Terminate selector */
                    208:                        port = strchr(host, TAB);
                    209:                        if (port) {
                    210:                            char *junk;
                    211:                            port[0] = ':';      /* delimit host a la W3 */
                    212:                            junk = strchr(port, TAB);
                    213:                            if (junk) *junk++ = 0;      /* Chop port */
                    214:                            if ((port[1]=='0') && (!port[2]))
                    215:                                port[0] = 0;    /* 0 means none */
                    216:                        } /* no port */
                    217:                    } /* host ok */
                    218:                } /* selector ok */
                    219:            } /* gtype and name ok */
                    220:            
                    221:            if (gtype == GOPHER_WWW) {  /* Gopher pointer to W3 */
                    222:                write_anchor(name, selector);
2.7     ! secret    223:                
1.1       timbl     224:            } else if (port) {          /* Other types need port */
                    225:                if (gtype == GOPHER_TELNET) {
                    226:                    if (*selector) sprintf(address, "telnet://%s@%s/",
2.7     ! secret    227:                                           selector, host);
1.1       timbl     228:                    else sprintf(address, "telnet://%s/", host);
2.7     ! secret    229:                }
        !           230:                else if (gtype == GOPHER_TN3270) 
        !           231:                {
        !           232:                    if (*selector) 
        !           233:                        sprintf(address, "tn3270://%s@%s/",
        !           234:                                selector, host);
        !           235:                    else 
        !           236:                        sprintf(address, "tn3270://%s/", host);
        !           237:                }
        !           238:                else {                  /* If parsed ok */
1.1       timbl     239:                    char *q;
                    240:                    char *p;
                    241:                    sprintf(address, "//%s/%c", host, gtype);
                    242:                    q = address+ strlen(address);
                    243:                    for(p=selector; *p; p++) {  /* Encode selector string */
                    244:                        if (acceptable[*p]) *q++ = *p;
                    245:                        else {
                    246:                            *q++ = HEX_ESCAPE;  /* Means hex coming */
                    247:                            *q++ = hex[(TOASCII(*p)) >> 4];
                    248:                            *q++ = hex[(TOASCII(*p)) & 15];
                    249:                        }
                    250:                    }
                    251:                    *q++ = 0;                   /* terminate address */
                    252:                }
1.2       timbl     253:                PUTS("        "); /* Prettier JW/TBL */
2.7     ! secret    254:                /* Error response from Gopher doesn't deserve to
        !           255:                   be a hyperlink. */
        !           256:                if (strcmp (address, "gopher://error.host:1/0"))
        !           257:                    write_anchor(name, address);
        !           258:                else
        !           259:                    PUTS(name);
        !           260:                PUTS("\n");
1.1       timbl     261:            } else { /* parse error */
                    262:                if (TRACE) fprintf(stderr,
                    263:                        "HTGopher: Bad menu item.\n");
1.2       timbl     264:                PUTS(line);
                    265: 
1.1       timbl     266:            } /* parse error */
                    267:            
                    268:            p = line;   /* Start again at beginning of line */
                    269:            
                    270:        } /* if end of line */
                    271:        
                    272:     } /* Loop over characters */
                    273:        
1.2       timbl     274:     END(HTML_MENU);
                    275:     END_TARGET;
                    276:     FREE_TARGET;
                    277:     
1.1       timbl     278:     return;
                    279: }
2.7     ! secret    280: /*     Parse a Gopher CSO document
        !           281:  **    ============================
        !           282:  **
        !           283:  **   Accepts an open socket to a CSO server waiting to send us
        !           284:  **   data and puts it on the screen in a reasonable manner.
        !           285:  **
        !           286:  **   Perhaps this data can be automatically linked to some
        !           287:  **   other source as well???
        !           288:  **
        !           289:  **  Taken from hacking by Lou Montulli@ukanaix.cc.ukans.edu
        !           290:  **  on XMosaic-1.1, and put on libwww 2.11 by Arthur Secret, 
        !           291:  **  secret@dxcern.cern.ch .
        !           292:  */
        !           293: 
        !           294: PRIVATE void parse_cso ARGS2 (
        !           295:                              CONST char *,     arg,
        !           296:                              HTParentAnchor *,anAnchor)
        !           297: {
        !           298:     char ch;
        !           299:     char line[BIG];
        !           300:     char *p = line;
        !           301:     char *second_colon, last_char='\0';
        !           302:     CONST char *title;
        !           303:     
        !           304:     title = HTAnchor_title(anAnchor);
        !           305:     START(HTML_H1);
        !           306:     PUTS("CSO Search Results");
        !           307:     END(HTML_H1);
        !           308:     START(HTML_PRE);
        !           309: 
        !           310:     /* start grabbing chars from the network */
        !           311:     while ((ch=NEXT_CHAR) != (char)EOF) 
        !           312:        {
        !           313:            if (ch != '\n') 
        !           314:                {
        !           315:                    *p = ch;            /* Put character in line */
        !           316:                    if (p< &line[BIG-1]) p++;
        !           317:                } 
        !           318:            else 
        !           319:                {
        !           320:                    *p++ = 0;           /* Terminate line */
        !           321:                    p = line;           /* Scan it to parse it */
        !           322:                    
        !           323:                    /* OK we now have a line in 'p' lets parse it and 
        !           324:                       print it */
        !           325:                    
        !           326:                    /* Break on line that begins with a 2. It's the end of
        !           327:                     * data.
        !           328:                     */
        !           329:                    if (*p == '2')
        !           330:                        break;
        !           331:                    
        !           332:                    /*  lines beginning with 5 are errors, 
        !           333:                     *  print them and quit
        !           334:                     */
        !           335:                    if (*p == '5') {
        !           336:                        START(HTML_H2);
        !           337:                        PUTS(p+4);
        !           338:                        END(HTML_H2);
        !           339:                        break;
        !           340:                    }
        !           341:                    
        !           342:                    if(*p == '-') {
        !           343:                        /*  data lines look like  -200:#:
        !           344:                         *  where # is the search result number and can be  
        !           345:                         *  multiple digits (infinate?)
        !           346:                         *  find the second colon and check the digit to the
        !           347:                         *  left of it to see if they are diferent
        !           348:                         *  if they are then a different person is starting. 
        !           349:                         *  make this line an <h2>
        !           350:                         */
        !           351:                        
        !           352:                        /* find the second_colon */
        !           353:                        second_colon = strchr( strchr(p,':')+1, ':');
        !           354:                        
        !           355:                        if(second_colon != NULL) {  /* error check */
        !           356:                            
        !           357:                            if (*(second_colon-1) != last_char)   
        !           358:                                /* print seperator */
        !           359:                            {
        !           360:                                END(HTML_PRE);
        !           361:                                START(HTML_H2);
        !           362:                            }
        !           363:                                
        !           364:                            
        !           365:                            /* right now the record appears with the alias 
        !           366:                             * (first line)
        !           367:                             * as the header and the rest as <pre> text
        !           368:                             * It might look better with the name as the
        !           369:                             * header and the rest as a <ul> with <li> tags
        !           370:                             * I'm not sure whether the name field comes in any
        !           371:                             * special order or if its even required in a 
        !           372:                             * record,
        !           373:                             * so for now the first line is the header no 
        !           374:                             * matter
        !           375:                             * what it is (it's almost always the alias)
        !           376:                             * A <dl> with the first line as the <DT> and
        !           377:                             * the rest as some form of <DD> might good also?
        !           378:                             */
        !           379:                            
        !           380:                            /* print data */
        !           381:                            PUTS(second_colon+1);
        !           382:                            PUTS("\n");
        !           383:                            
        !           384:                            if (*(second_colon-1) != last_char)   
        !           385:                                /* end seperator */
        !           386:                            {
        !           387:                                END(HTML_H2);
        !           388:                                START(HTML_PRE);
        !           389:                            }
        !           390:                                                            
        !           391:                            /* save the char before the second colon
        !           392:                             * for comparison on the next pass
        !           393:                             */
        !           394:                            last_char =  *(second_colon-1) ;
        !           395:                            
        !           396:                        } /* end if second_colon */
        !           397:                    } /* end if *p == '-' */
        !           398:                } /* if end of line */
        !           399:            
        !           400:        } /* Loop over characters */
        !           401:     
        !           402:     /* end the text block */
        !           403:     PUTS("\n");
        !           404:     END(HTML_PRE);
        !           405:     PUTS("\n");
        !           406:     END_TARGET;
        !           407:     FREE_TARGET;
        !           408: 
        !           409:     return;  /* all done */
        !           410: } /* end of procedure */
1.1       timbl     411: 
                    412: /*     Display a Gopher Index document
2.7     ! secret    413:  **    -------------------------------
        !           414:  */
1.1       timbl     415: 
                    416: PRIVATE void display_index ARGS2 (
2.7     ! secret    417:                                  CONST char *, arg,
        !           418:                                  HTParentAnchor *,anAnchor)
1.1       timbl     419: {
1.2       timbl     420:     
                    421:     START(HTML_H1);
                    422:     PUTS(arg);
2.7     ! secret    423:     PUTS(" index");
1.2       timbl     424:     END(HTML_H1);
2.7     ! secret    425:     START(HTML_ISINDEX);
        !           426:     PUTS("\nThis is a searchable Gopher index.");
        !           427:     PUTS(" Please enter keywords to search for.\n");
        !           428:     
        !           429:     if (!HTAnchor_title(anAnchor))
        !           430:        HTAnchor_setTitle(anAnchor, arg);
1.2       timbl     431:     
2.7     ! secret    432:     END_TARGET;
        !           433:     FREE_TARGET;
        !           434:     return;
        !           435: }
        !           436: 
        !           437: 
        !           438: /*      Display a CSO index document
        !           439: **      -------------------------------
        !           440: */
        !           441: 
        !           442: PRIVATE void display_cso ARGS2 (
        !           443:         CONST char *,   arg,
        !           444:         HTParentAnchor *,anAnchor)
        !           445: {
        !           446:     START(HTML_H1);
        !           447:     PUTS(arg);
        !           448:     PUTS(" index");
        !           449:     END(HTML_H1);
        !           450:     START(HTML_ISINDEX);
        !           451:     PUTS("\nThis is a searchable index of a CSO database.\n");
        !           452:     PUTS(" Please enter keywords to search for. The keywords that you enter");
        !           453:     PUTS(" will allow you to search on a person's name in the database.\n");
        !           454: 
1.1       timbl     455:     if (!HTAnchor_title(anAnchor))
1.2       timbl     456:        HTAnchor_setTitle(anAnchor, arg);
1.1       timbl     457:     
1.2       timbl     458:     END_TARGET;
                    459:     FREE_TARGET;
1.1       timbl     460:     return;
                    461: }
                    462: 
                    463: 
                    464: /*             De-escape a selector into a command
                    465: **             -----------------------------------
                    466: **
                    467: **     The % hex escapes are converted. Otheriwse, the string is copied.
                    468: */
                    469: PRIVATE void de_escape ARGS2(char *, command, CONST char *, selector)
                    470: {
                    471:     CONST char * p = selector;
                    472:     char * q = command;
                    473:        if (command == NULL) outofmem(__FILE__, "HTLoadGopher");
                    474:     while (*p) {               /* Decode hex */
                    475:        if (*p == HEX_ESCAPE) {
                    476:            char c;
                    477:            unsigned int b;
                    478:            p++;
                    479:            c = *p++;
                    480:            b =   from_hex(c);
                    481:            c = *p++;
                    482:            if (!c) break;      /* Odd number of chars! */
                    483:            *q++ = FROMASCII((b<<4) + from_hex(c));
                    484:        } else {
                    485:            *q++ = *p++;        /* Record */
                    486:        }
                    487:     }
                    488:     *q++ = 0;  /* Terminate command */
                    489: 
                    490: }
                    491: 
                    492: 
                    493: /*             Load by name                                    HTLoadGopher
                    494: **             ============
                    495: **
                    496: **      Bug:   No decoding of strange data types as yet.
                    497: **
                    498: */
1.2       timbl     499: PUBLIC int HTLoadGopher ARGS4(
                    500:        CONST char *,           arg,
                    501:        HTParentAnchor *,       anAnchor,
                    502:        HTFormat,               format_out,
                    503:        HTStream*,              sink)
1.1       timbl     504: {
                    505:     char *command;                     /* The whole command */
                    506:     int status;                                /* tcp return */
                    507:     char gtype;                                /* Gopher Node type */
                    508:     char * selector;                   /* Selector string */
                    509:  
                    510:     struct sockaddr_in soc_address;    /* Binary network address */
                    511:     struct sockaddr_in* sin = &soc_address;
                    512:     
                    513:     if (!acceptable_inited) init_acceptable();
                    514:     
                    515:     if (!arg) return -3;               /* Bad if no name sepcified     */
                    516:     if (!*arg) return -2;              /* Bad if name had zero length  */
                    517:     
                    518:     if (TRACE) fprintf(stderr, "HTGopher: Looking for %s\n", arg);
                    519:     
                    520:     
                    521: /*  Set up defaults:
                    522: */
                    523:     sin->sin_family = AF_INET;                 /* Family, host order  */
                    524:     sin->sin_port = htons(GOPHER_PORT);                /* Default: new port,  */
                    525: 
                    526: /* Get node name and optional port number:
                    527: */
                    528:     {
                    529:        char *p1 = HTParse(arg, "", PARSE_HOST);
                    530:        int status = HTParseInet(sin, p1);
                    531:         free(p1);
                    532:         if (status) return status;   /* Bad */
                    533:     }
                    534:     
                    535: /* Get entity type, and selector string.
                    536: */        
                    537:     {
                    538:        char * p1 = HTParse(arg, "", PARSE_PATH|PARSE_PUNCTUATION);
                    539:         gtype = '1';           /* Default = menu */
                    540:        selector = p1;
                    541:        if ((*selector++=='/') && (*selector)) {        /* Skip first slash */
                    542:            gtype = *selector++;                        /* Pick up gtype */
                    543:        }
                    544:        if (gtype == GOPHER_INDEX) {
                    545:            char * query;
                    546:             HTAnchor_setIndex(anAnchor);       /* Search is allowed */
                    547:            query = strchr(selector, '?');      /* Look for search string */
                    548:            if (!query || !query[1]) {          /* No search required */
1.3       timbl     549:                target = HTML_new(anAnchor, format_out, sink);
1.2       timbl     550:                targetClass = *target->isa;
1.1       timbl     551:                display_index(arg, anAnchor);   /* Display "cover page" */
2.6       timbl     552:                return HT_LOADED;               /* Local function only */
1.1       timbl     553:            }
                    554:            *query++ = 0;                       /* Skip '?'     */
                    555:            command = malloc(strlen(selector)+ 1 + strlen(query)+ 2 + 1);
                    556:               if (command == NULL) outofmem(__FILE__, "HTLoadGopher");
                    557:              
                    558:            de_escape(command, selector);       /* Bug fix TBL 921208 */
                    559: 
                    560:            strcat(command, "\t");
                    561:          
                    562:            {                                   /* Remove plus signs 921006 */
                    563:                char *p;
                    564:                for (p=query; *p; p++) {
                    565:                    if (*p == '+') *p = ' ';
                    566:                }
                    567:            }
                    568:            strcat(command, query);
2.7     ! secret    569:         } else if (gtype == GOPHER_CSO) {
        !           570:             char * query;
        !           571:             HTAnchor_setIndex(anAnchor);        /* Search is allowed */
        !           572:             query = strchr(selector, '?');      /* Look for search string */
        !           573:             if (!query || !query[1]) {          /* No search required */
        !           574:                target = HTML_new(anAnchor, format_out, sink);
        !           575:                targetClass = *target->isa;
        !           576:                 display_cso(arg, anAnchor);     /* Display "cover page" */
        !           577:                 return HT_LOADED;                 /* Local function only */
        !           578:             }
        !           579:             *query++ = 0;                       /* Skip '?'     */
        !           580:             command = malloc(strlen("query")+ 1 + strlen(query)+ 2 + 1);
        !           581:               if (command == NULL) outofmem(__FILE__, "HTLoadGopher");
        !           582: 
        !           583:             de_escape(command, selector);       /* Bug fix TBL 921208 */
        !           584: 
        !           585:             strcpy(command, "query ");
        !           586: 
        !           587:             {                                   /* Remove plus signs 921006 */
        !           588:                 char *p;
        !           589:                 for (p=query; *p; p++) {
        !           590:                     if (*p == '+') *p = ' ';
        !           591:                 }
        !           592:             }
        !           593:             strcat(command, query);
        !           594: 
1.1       timbl     595:            
                    596:        } else {                                /* Not index */
                    597:            command = command = malloc(strlen(selector)+2+1);
                    598:            de_escape(command, selector);
                    599:        }
                    600:        free(p1);
                    601:     }
                    602:     
1.3       timbl     603:     {
                    604:        char * p = command + strlen(command);
                    605:        *p++ = CR;              /* Macros to be correct on Mac */
                    606:        *p++ = LF;
                    607:        *p++ = 0;
                    608:        /* strcat(command, "\r\n");     */      /* CR LF, as in rfc 977 */
                    609:     }
1.1       timbl     610: 
                    611: /*     Set up a socket to the server for the data:
                    612: */      
                    613:     s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
                    614:     status = connect(s, (struct sockaddr*)&soc_address, sizeof(soc_address));
                    615:     if (status<0){
                    616:        if (TRACE) fprintf(stderr, "HTTPAccess: Unable to connect to remote host for `%s'.\n",
                    617:            arg);
                    618:        free(command);
                    619:        return HTInetStatus("connect");
                    620:     }
                    621:     
                    622:     HTInitInput(s);            /* Set up input buffering */
                    623:     
                    624:     if (TRACE) fprintf(stderr, "HTGopher: Connected, writing command `%s' to socket %d\n", command, s);
                    625:     
                    626: #ifdef NOT_ASCII
                    627:     {
                    628:        char * p;
                    629:        for(p = command; *p; p++) {
                    630:            *p = TOASCII(*p);
                    631:        }
                    632:     }
                    633: #endif
                    634: 
                    635:     status = NETWRITE(s, command, (int)strlen(command));
                    636:     free(command);
                    637:     if (status<0){
                    638:        if (TRACE) fprintf(stderr, "HTGopher: Unable to send command.\n");
                    639:            return HTInetStatus("send");
                    640:     }
                    641: 
                    642: /*     Now read the data from the socket:
                    643: */    
                    644:     switch (gtype) {
                    645:     
                    646:     case GOPHER_HTML :
1.2       timbl     647:        HTParseSocket(WWW_HTML, format_out, anAnchor, s, sink);
                    648:        break;
1.1       timbl     649: 
1.3       timbl     650:     case GOPHER_GIF:
                    651:     case GOPHER_IMAGE:
                    652:        HTParseSocket(HTAtom_for("image/gif"), 
                    653:                           format_out, anAnchor, s, sink);
                    654:        break;
1.1       timbl     655:     case GOPHER_MENU :
                    656:     case GOPHER_INDEX :
1.3       timbl     657:        target = HTML_new(anAnchor, format_out, sink);
1.2       timbl     658:        targetClass = *target->isa;
1.1       timbl     659:         parse_menu(arg, anAnchor);
1.2       timbl     660:        break;
2.7     ! secret    661:         
        !           662:     case GOPHER_CSO:
        !           663:        target = HTML_new(anAnchor, format_out, sink);
        !           664:        targetClass = *target->isa;
        !           665:        parse_cso(arg, anAnchor);
        !           666:        break;
        !           667:        
        !           668:       case GOPHER_MACBINHEX:
        !           669:       case GOPHER_PCBINHEX:
        !           670:       case GOPHER_UUENCODED:
        !           671:       case GOPHER_BINARY:
        !           672:         /* Specifying WWW_UNKNOWN forces dump to local disk. */
        !           673:         HTParseSocket (WWW_UNKNOWN, format_out, anAnchor, s, sink);
        !           674:        break;
        !           675: 
1.1       timbl     676:     case GOPHER_TEXT :
                    677:     default:                   /* @@ parse as plain text */
1.2       timbl     678:        HTParseSocket(WWW_PLAINTEXT, format_out, anAnchor, s, sink);
2.7     ! secret    679:        break;
        !           680: 
        !           681:       case GOPHER_SOUND :
        !           682:        HTParseSocket(WWW_AUDIO, format_out, anAnchor, s, sink);
1.2       timbl     683:        break;
                    684:        
1.1       timbl     685:     } /* switch(gtype) */
1.2       timbl     686: 
                    687:     NETCLOSE(s);
                    688:     return HT_LOADED;
1.1       timbl     689: }
1.2       timbl     690: 
                    691: PUBLIC HTProtocol HTGopher = { "gopher", HTLoadGopher, NULL };
1.1       timbl     692: 

Webmaster