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

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: 
1.1       timbl      14: #define GOPHER_PORT 70         /* See protocol spec */
                     15: #define BIG 1024               /* Bug */
                     16: #define LINE_LENGTH 256                /* Bug */
                     17: 
                     18: /*     Gopher entity types:
                     19: */
                     20: #define GOPHER_TEXT            '0'
                     21: #define GOPHER_MENU            '1'
                     22: #define GOPHER_CSO             '2'
                     23: #define GOPHER_ERROR           '3'
                     24: #define GOPHER_MACBINHEX       '4'
                     25: #define GOPHER_PCBINHEX                '5'
                     26: #define GOPHER_UUENCODED       '6'
                     27: #define GOPHER_INDEX           '7'
                     28: #define GOPHER_TELNET          '8'
2.7       secret     29: #define GOPHER_BINARY           '9'
1.3       timbl      30: #define GOPHER_GIF              'g'
2.7       secret     31: #define GOPHER_HTML            'h'             /* HTML */
                     32: #define GOPHER_SOUND            's'
                     33: #define GOPHER_WWW             'w'             /* W3 address */
1.3       timbl      34: #define GOPHER_IMAGE            'I'
2.7       secret     35: #define GOPHER_TN3270           'T'
1.1       timbl      36: #define GOPHER_DUPLICATE       '+'
                     37: 
                     38: #include <ctype.h>
                     39: #include "HTUtils.h"           /* Coding convention macros */
                     40: #include "tcp.h"
                     41: 
                     42: 
                     43: #include "HTParse.h"
                     44: #include "HTFormat.h"
                     45: #include "HTTCP.h"
2.16    ! luotonen   46: #include "HTFile.h"            /* HTFileFormat() */
1.1       timbl      47: 
1.2       timbl      48: /*             Hypertext object building machinery
                     49: */
                     50: #include "HTML.h"
                     51: 
                     52: #define PUTC(c) (*targetClass.put_character)(target, c)
                     53: #define PUTS(s) (*targetClass.put_string)(target, s)
                     54: #define START(e) (*targetClass.start_element)(target, e, 0, 0)
                     55: #define END(e) (*targetClass.end_element)(target, e)
                     56: #define FREE_TARGET (*targetClass.free)(target)
                     57: struct _HTStructured {
                     58:        CONST HTStructuredClass *       isa;
                     59:        /* ... */
                     60: };
                     61: 
                     62: PRIVATE HTStructured *target;                  /* the new hypertext */
                     63: PRIVATE HTStructuredClass targetClass;         /* Its action routines */
                     64: 
                     65: 
2.8       timbl      66: #define GOPHER_PROGRESS(foo) HTAlert(foo)
1.1       timbl      67: 
                     68: 
2.12      timbl      69: #define NEXT_CHAR HTInputSocket_getCharacter(isoc) 
1.1       timbl      70: 
                     71: 
2.8       timbl      72: 
1.1       timbl      73: /*     Module-wide variables
                     74: */
                     75: PRIVATE int s;                                 /* Socket for GopherHost */
                     76: 
                     77: 
1.2       timbl      78: 
1.1       timbl      79: /*     Matrix of allowed characters in filenames
                     80: **     -----------------------------------------
                     81: */
                     82: 
                     83: PRIVATE BOOL acceptable[256];
                     84: PRIVATE BOOL acceptable_inited = NO;
                     85: 
                     86: PRIVATE void init_acceptable NOARGS
                     87: {
                     88:     unsigned int i;
                     89:     char * good = 
                     90:       "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_$";
                     91:     for(i=0; i<256; i++) acceptable[i] = NO;
                     92:     for(;*good; good++) acceptable[(unsigned int)*good] = YES;
                     93:     acceptable_inited = YES;
                     94: }
                     95: 
                     96: PRIVATE CONST char hex[17] = "0123456789abcdef";
                     97: 
                     98: /*     Decdoe one hex character
                     99: */
                    100: 
                    101: PRIVATE char from_hex ARGS1(char, c)
                    102: {
                    103:     return               (c>='0')&&(c<='9') ? c-'0'
                    104:                        : (c>='A')&&(c<='F') ? c-'A'+10
                    105:                        : (c>='a')&&(c<='f') ? c-'a'+10
                    106:                        :                      0;
                    107: }
                    108: 
                    109: 
                    110: 
                    111: /*     Paste in an Anchor
                    112: **     ------------------
                    113: **
                    114: **     The title of the destination is set, as there is no way
                    115: **     of knowing what the title is when we arrive.
                    116: **
                    117: ** On entry,
                    118: **     HT      is in append mode.
                    119: **     text    points to the text to be put into the file, 0 terminated.
                    120: **     addr    points to the hypertext refernce address 0 terminated.
                    121: */
                    122: PRIVATE void write_anchor ARGS2(CONST char *,text, CONST char *,addr)
                    123: {
1.2       timbl     124: 
                    125: 
                    126:     
                    127:     BOOL present[HTML_A_ATTRIBUTES];
                    128:     CONST char * value[HTML_A_ATTRIBUTES];
1.1       timbl     129:     
1.2       timbl     130:     int i;
                    131:     
                    132:     for (i=0; i<HTML_A_ATTRIBUTES; i++) present[i]=0;
                    133:     present[HTML_A_HREF] = YES;
                    134:     value[HTML_A_HREF] = addr;
                    135:     present[HTML_A_TITLE] = YES;
                    136:     value[HTML_A_TITLE] = text;
                    137:     
                    138:     (*targetClass.start_element)(target, HTML_A, present, value);
1.1       timbl     139:            
1.2       timbl     140:     PUTS(text);
                    141:     END(HTML_A);
1.1       timbl     142: }
                    143: 
                    144: 
                    145: /*     Parse a Gopher Menu document
                    146: **     ============================
                    147: **
                    148: */
                    149: 
2.11      timbl     150: PRIVATE void parse_menu ARGS3 (
                    151:        int ,                   s,
1.2       timbl     152:        CONST char *,           arg,
                    153:        HTParentAnchor *,       anAnchor)
1.1       timbl     154: {
                    155:     char gtype;
                    156:     char ch;
                    157:     char line[BIG];
                    158:     char address[BIG];
2.14      luotonen  159:     char *name = "";
                    160:     char *selector = "";               /* Gopher menu fields */
                    161:     char *host = "";
1.1       timbl     162:     char *port;
                    163:     char *p = line;
1.2       timbl     164:     CONST char *title;
2.12      timbl     165:     HTInputSocket * isoc = HTInputSocket_new(s);
2.11      timbl     166:     
1.1       timbl     167: #define TAB            '\t'
                    168: #define HEX_ESCAPE     '%'
                    169: 
                    170:     
1.2       timbl     171:     title = HTAnchor_title(anAnchor);
                    172:     if (title) {
                    173:         START(HTML_H1);
                    174:        PUTS(title);
                    175:        END(HTML_H1);
                    176:     } else
                    177:         PUTS("Select one of:\n\n");
1.1       timbl     178:     
1.2       timbl     179:     START(HTML_MENU);
1.1       timbl     180:     while ((ch=NEXT_CHAR) != (char)EOF) {
1.3       timbl     181:         if (ch != LF) {
1.1       timbl     182:            *p = ch;            /* Put character in line */
                    183:            if (p< &line[BIG-1]) p++;
                    184:            
                    185:        } else {
                    186:            *p++ = 0;           /* Terminate line */
                    187:            p = line;           /* Scan it to parse it */
                    188:            port = 0;           /* Flag "not parsed" */
                    189:            if (TRACE) fprintf(stderr, "HTGopher: Menu item: %s\n", line);
                    190:            gtype = *p++;
                    191:            
                    192:            /* Break on line with a dot by itself */
                    193:            if ((gtype=='.') && ((*p=='\r') || (*p==0))) break;
                    194: 
                    195:            if (gtype && *p) {
                    196:                name = p;
                    197:                selector = strchr(name, TAB);
1.3       timbl     198:                START(HTML_LI);
1.1       timbl     199:                if (selector) {
                    200:                    *selector++ = 0;    /* Terminate name */
                    201:                    host = strchr(selector, TAB);
                    202:                    if (host) {
                    203:                        *host++ = 0;    /* Terminate selector */
                    204:                        port = strchr(host, TAB);
                    205:                        if (port) {
                    206:                            char *junk;
                    207:                            port[0] = ':';      /* delimit host a la W3 */
                    208:                            junk = strchr(port, TAB);
                    209:                            if (junk) *junk++ = 0;      /* Chop port */
                    210:                            if ((port[1]=='0') && (!port[2]))
                    211:                                port[0] = 0;    /* 0 means none */
                    212:                        } /* no port */
                    213:                    } /* host ok */
                    214:                } /* selector ok */
                    215:            } /* gtype and name ok */
                    216:            
                    217:            if (gtype == GOPHER_WWW) {  /* Gopher pointer to W3 */
                    218:                write_anchor(name, selector);
2.7       secret    219:                
1.1       timbl     220:            } else if (port) {          /* Other types need port */
                    221:                if (gtype == GOPHER_TELNET) {
                    222:                    if (*selector) sprintf(address, "telnet://%s@%s/",
2.7       secret    223:                                           selector, host);
1.1       timbl     224:                    else sprintf(address, "telnet://%s/", host);
2.7       secret    225:                }
                    226:                else if (gtype == GOPHER_TN3270) 
                    227:                {
                    228:                    if (*selector) 
                    229:                        sprintf(address, "tn3270://%s@%s/",
                    230:                                selector, host);
                    231:                    else 
                    232:                        sprintf(address, "tn3270://%s/", host);
                    233:                }
                    234:                else {                  /* If parsed ok */
1.1       timbl     235:                    char *q;
                    236:                    char *p;
                    237:                    sprintf(address, "//%s/%c", host, gtype);
                    238:                    q = address+ strlen(address);
                    239:                    for(p=selector; *p; p++) {  /* Encode selector string */
2.14      luotonen  240:                        if (acceptable[(int)*p]) *q++ = *p;
1.1       timbl     241:                        else {
                    242:                            *q++ = HEX_ESCAPE;  /* Means hex coming */
                    243:                            *q++ = hex[(TOASCII(*p)) >> 4];
                    244:                            *q++ = hex[(TOASCII(*p)) & 15];
                    245:                        }
                    246:                    }
                    247:                    *q++ = 0;                   /* terminate address */
                    248:                }
1.2       timbl     249:                PUTS("        "); /* Prettier JW/TBL */
2.7       secret    250:                /* Error response from Gopher doesn't deserve to
                    251:                   be a hyperlink. */
                    252:                if (strcmp (address, "gopher://error.host:1/0"))
                    253:                    write_anchor(name, address);
                    254:                else
                    255:                    PUTS(name);
                    256:                PUTS("\n");
1.1       timbl     257:            } else { /* parse error */
                    258:                if (TRACE) fprintf(stderr,
                    259:                        "HTGopher: Bad menu item.\n");
1.2       timbl     260:                PUTS(line);
                    261: 
1.1       timbl     262:            } /* parse error */
                    263:            
                    264:            p = line;   /* Start again at beginning of line */
                    265:            
                    266:        } /* if end of line */
                    267:        
                    268:     } /* Loop over characters */
                    269:        
1.2       timbl     270:     END(HTML_MENU);
                    271:     FREE_TARGET;
                    272:     
2.11      timbl     273:     HTInputSocket_free(isoc);
1.1       timbl     274:     return;
                    275: }
2.11      timbl     276: 
                    277: 
2.7       secret    278: /*     Parse a Gopher CSO document
                    279:  **    ============================
                    280:  **
                    281:  **   Accepts an open socket to a CSO server waiting to send us
                    282:  **   data and puts it on the screen in a reasonable manner.
                    283:  **
                    284:  **   Perhaps this data can be automatically linked to some
                    285:  **   other source as well???
                    286:  **
                    287:  **  Taken from hacking by Lou Montulli@ukanaix.cc.ukans.edu
                    288:  **  on XMosaic-1.1, and put on libwww 2.11 by Arthur Secret, 
                    289:  **  secret@dxcern.cern.ch .
                    290:  */
                    291: 
2.11      timbl     292: PRIVATE void parse_cso ARGS3 (
                    293:                        int,    s,
                    294:                        CONST char *,           arg,
                    295:                        HTParentAnchor *,       anAnchor)
2.7       secret    296: {
                    297:     char ch;
                    298:     char line[BIG];
                    299:     char *p = line;
                    300:     char *second_colon, last_char='\0';
                    301:     CONST char *title;
2.11      timbl     302:     HTInputSocket * isoc = HTInputSocket_new(s);
2.7       secret    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:     FREE_TARGET;
2.11      timbl     407:     HTInputSocket_free(isoc);
2.7       secret    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:     FREE_TARGET;
                    433:     return;
                    434: }
                    435: 
                    436: 
                    437: /*      Display a CSO index document
                    438: **      -------------------------------
                    439: */
                    440: 
                    441: PRIVATE void display_cso ARGS2 (
                    442:         CONST char *,   arg,
                    443:         HTParentAnchor *,anAnchor)
                    444: {
                    445:     START(HTML_H1);
                    446:     PUTS(arg);
                    447:     PUTS(" index");
                    448:     END(HTML_H1);
                    449:     START(HTML_ISINDEX);
                    450:     PUTS("\nThis is a searchable index of a CSO database.\n");
                    451:     PUTS(" Please enter keywords to search for. The keywords that you enter");
                    452:     PUTS(" will allow you to search on a person's name in the database.\n");
                    453: 
1.1       timbl     454:     if (!HTAnchor_title(anAnchor))
1.2       timbl     455:        HTAnchor_setTitle(anAnchor, arg);
1.1       timbl     456:     
1.2       timbl     457:     FREE_TARGET;
1.1       timbl     458:     return;
                    459: }
                    460: 
                    461: 
                    462: /*             De-escape a selector into a command
                    463: **             -----------------------------------
                    464: **
                    465: **     The % hex escapes are converted. Otheriwse, the string is copied.
                    466: */
                    467: PRIVATE void de_escape ARGS2(char *, command, CONST char *, selector)
                    468: {
                    469:     CONST char * p = selector;
                    470:     char * q = command;
                    471:        if (command == NULL) outofmem(__FILE__, "HTLoadGopher");
                    472:     while (*p) {               /* Decode hex */
                    473:        if (*p == HEX_ESCAPE) {
                    474:            char c;
                    475:            unsigned int b;
                    476:            p++;
                    477:            c = *p++;
                    478:            b =   from_hex(c);
                    479:            c = *p++;
                    480:            if (!c) break;      /* Odd number of chars! */
                    481:            *q++ = FROMASCII((b<<4) + from_hex(c));
                    482:        } else {
                    483:            *q++ = *p++;        /* Record */
                    484:        }
                    485:     }
                    486:     *q++ = 0;  /* Terminate command */
                    487: 
                    488: }
                    489: 
                    490: 
                    491: /*             Load by name                                    HTLoadGopher
                    492: **             ============
                    493: **
                    494: **      Bug:   No decoding of strange data types as yet.
                    495: **
                    496: */
2.13      timbl     497: PUBLIC int HTLoadGopher ARGS1(HTRequest *, request)
1.1       timbl     498: {
2.13      timbl     499:     CONST char * arg = HTAnchor_physical(request->anchor);
1.1       timbl     500:     char *command;                     /* The whole command */
                    501:     int status;                                /* tcp return */
                    502:     char gtype;                                /* Gopher Node type */
                    503:     char * selector;                   /* Selector string */
                    504:     struct sockaddr_in soc_address;    /* Binary network address */
                    505:     struct sockaddr_in* sin = &soc_address;
                    506:     
                    507:     if (!acceptable_inited) init_acceptable();
                    508:     
                    509:     if (!arg) return -3;               /* Bad if no name sepcified     */
                    510:     if (!*arg) return -2;              /* Bad if name had zero length  */
                    511:     
                    512:     if (TRACE) fprintf(stderr, "HTGopher: Looking for %s\n", arg);
                    513:     
                    514:     
                    515: /*  Set up defaults:
                    516: */
                    517:     sin->sin_family = AF_INET;                 /* Family, host order  */
                    518:     sin->sin_port = htons(GOPHER_PORT);                /* Default: new port,  */
                    519: 
                    520: /* Get node name and optional port number:
                    521: */
                    522:     {
                    523:        char *p1 = HTParse(arg, "", PARSE_HOST);
                    524:        int status = HTParseInet(sin, p1);
                    525:         free(p1);
                    526:         if (status) return status;   /* Bad */
                    527:     }
                    528:     
                    529: /* Get entity type, and selector string.
                    530: */        
                    531:     {
                    532:        char * p1 = HTParse(arg, "", PARSE_PATH|PARSE_PUNCTUATION);
                    533:         gtype = '1';           /* Default = menu */
                    534:        selector = p1;
                    535:        if ((*selector++=='/') && (*selector)) {        /* Skip first slash */
                    536:            gtype = *selector++;                        /* Pick up gtype */
                    537:        }
                    538:        if (gtype == GOPHER_INDEX) {
                    539:            char * query;
2.10      timbl     540:             HTAnchor_setIndex(request->anchor);        /* Search is allowed */
1.1       timbl     541:            query = strchr(selector, '?');      /* Look for search string */
                    542:            if (!query || !query[1]) {          /* No search required */
2.11      timbl     543:                target = HTML_new(request, NULL, WWW_HTML,
                    544:                        request->output_format, request->output_stream);
1.2       timbl     545:                targetClass = *target->isa;
2.10      timbl     546:                display_index(arg, request->anchor);    /* Display "cover page" */
2.15      luotonen  547:                free(p1);               /* Leak fixed Henrik 27 Feb 94 */
2.6       timbl     548:                return HT_LOADED;               /* Local function only */
1.1       timbl     549:            }
                    550:            *query++ = 0;                       /* Skip '?'     */
                    551:            command = malloc(strlen(selector)+ 1 + strlen(query)+ 2 + 1);
                    552:               if (command == NULL) outofmem(__FILE__, "HTLoadGopher");
                    553:              
                    554:            de_escape(command, selector);       /* Bug fix TBL 921208 */
                    555: 
                    556:            strcat(command, "\t");
                    557:          
                    558:            {                                   /* Remove plus signs 921006 */
                    559:                char *p;
                    560:                for (p=query; *p; p++) {
                    561:                    if (*p == '+') *p = ' ';
                    562:                }
                    563:            }
                    564:            strcat(command, query);
2.7       secret    565:         } else if (gtype == GOPHER_CSO) {
                    566:             char * query;
2.10      timbl     567:             HTAnchor_setIndex(request->anchor);        /* Search is allowed */
2.7       secret    568:             query = strchr(selector, '?');      /* Look for search string */
                    569:             if (!query || !query[1]) {          /* No search required */
2.11      timbl     570:                target = HTML_new(request, NULL, WWW_HTML,
                    571:                        request->output_format, request->output_stream);
2.7       secret    572:                targetClass = *target->isa;
2.10      timbl     573:                 display_cso(arg, request->anchor);     /* Display "cover page" */
2.15      luotonen  574:                free(p1);               /* Leak fixed Henrik 27 Feb 94 */
2.7       secret    575:                 return HT_LOADED;                 /* Local function only */
                    576:             }
                    577:             *query++ = 0;                       /* Skip '?'     */
                    578:             command = malloc(strlen("query")+ 1 + strlen(query)+ 2 + 1);
                    579:               if (command == NULL) outofmem(__FILE__, "HTLoadGopher");
                    580: 
                    581:             de_escape(command, selector);       /* Bug fix TBL 921208 */
                    582: 
                    583:             strcpy(command, "query ");
                    584: 
                    585:             {                                   /* Remove plus signs 921006 */
                    586:                 char *p;
                    587:                 for (p=query; *p; p++) {
                    588:                     if (*p == '+') *p = ' ';
                    589:                 }
                    590:             }
                    591:             strcat(command, query);
                    592: 
1.1       timbl     593:            
                    594:        } else {                                /* Not index */
                    595:            command = command = malloc(strlen(selector)+2+1);
                    596:            de_escape(command, selector);
                    597:        }
                    598:        free(p1);
                    599:     }
                    600:     
1.3       timbl     601:     {
                    602:        char * p = command + strlen(command);
                    603:        *p++ = CR;              /* Macros to be correct on Mac */
                    604:        *p++ = LF;
                    605:        *p++ = 0;
                    606:        /* strcat(command, "\r\n");     */      /* CR LF, as in rfc 977 */
                    607:     }
1.1       timbl     608: 
                    609: /*     Set up a socket to the server for the data:
                    610: */      
                    611:     s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
                    612:     status = connect(s, (struct sockaddr*)&soc_address, sizeof(soc_address));
                    613:     if (status<0){
                    614:        if (TRACE) fprintf(stderr, "HTTPAccess: Unable to connect to remote host for `%s'.\n",
                    615:            arg);
                    616:        free(command);
                    617:        return HTInetStatus("connect");
                    618:     }
                    619:     
                    620:     
                    621:     if (TRACE) fprintf(stderr, "HTGopher: Connected, writing command `%s' to socket %d\n", command, s);
                    622:     
                    623: #ifdef NOT_ASCII
                    624:     {
                    625:        char * p;
                    626:        for(p = command; *p; p++) {
                    627:            *p = TOASCII(*p);
                    628:        }
                    629:     }
                    630: #endif
                    631: 
                    632:     status = NETWRITE(s, command, (int)strlen(command));
                    633:     free(command);
                    634:     if (status<0){
                    635:        if (TRACE) fprintf(stderr, "HTGopher: Unable to send command.\n");
                    636:            return HTInetStatus("send");
                    637:     }
                    638: 
                    639: /*     Now read the data from the socket:
                    640: */    
                    641:     switch (gtype) {
                    642:     
                    643:     case GOPHER_HTML :
2.11      timbl     644:        HTParseSocket(WWW_HTML,  s, request);
1.2       timbl     645:        break;
1.1       timbl     646: 
1.3       timbl     647:     case GOPHER_GIF:
                    648:     case GOPHER_IMAGE:
2.11      timbl     649:        HTParseSocket(HTAtom_for("image/gif"), s, request);
1.3       timbl     650:        break;
1.1       timbl     651:     case GOPHER_MENU :
                    652:     case GOPHER_INDEX :
2.11      timbl     653:        target = HTML_new(request, NULL, WWW_HTML,
                    654:                        request->output_format, request->output_stream);
1.2       timbl     655:        targetClass = *target->isa;
2.11      timbl     656:         parse_menu(s,arg, request->anchor);
1.2       timbl     657:        break;
2.7       secret    658:         
                    659:     case GOPHER_CSO:
2.11      timbl     660:        target = HTML_new(request, NULL, WWW_HTML,
                    661:                        request->output_format, request->output_stream);
2.7       secret    662:        targetClass = *target->isa;
2.11      timbl     663:        parse_cso(s, arg, request->anchor);
2.7       secret    664:        break;
                    665:        
                    666:       case GOPHER_MACBINHEX:
                    667:       case GOPHER_PCBINHEX:
                    668:       case GOPHER_UUENCODED:
                    669:       case GOPHER_BINARY:
2.16    ! luotonen  670:        {       /* Do our own filetyping -- maybe we get lucky */
        !           671:            HTFormat format = HTFileFormat(arg,
        !           672:                                           &request->content_encoding,
        !           673:                                           &request->content_language);
        !           674:            if (format) {
        !           675:                CTRACE(stderr,
        !           676:                       "Gopher...... figured out content-type myself: %s\n",
        !           677:                       HTAtom_name(format));
        !           678:                HTParseSocket(format, s, request);
        !           679:            }
        !           680:            else {
        !           681:                CTRACE(stderr,"Gopher...... using www/unknown\n");
        !           682:                /* Specifying WWW_UNKNOWN forces dump to local disk. */
        !           683:                HTParseSocket (WWW_UNKNOWN, s, request);
        !           684:            }
        !           685:        }
2.7       secret    686:        break;
                    687: 
1.1       timbl     688:     case GOPHER_TEXT :
                    689:     default:                   /* @@ parse as plain text */
2.11      timbl     690:        HTParseSocket(WWW_PLAINTEXT, s, request);
2.7       secret    691:        break;
                    692: 
                    693:       case GOPHER_SOUND :
2.11      timbl     694:        HTParseSocket(WWW_AUDIO,  s, request);
1.2       timbl     695:        break;
                    696:        
1.1       timbl     697:     } /* switch(gtype) */
1.2       timbl     698: 
                    699:     NETCLOSE(s);
                    700:     return HT_LOADED;
1.1       timbl     701: }
1.2       timbl     702: 
2.10      timbl     703: GLOBALDEF PUBLIC HTProtocol HTGopher = { "gopher", HTLoadGopher, NULL, NULL };
1.1       timbl     704: 

Webmaster