[BACK] Return to HTGopher.c CVS log [TXT] [DIR] Up to [Public] / libwww / Library / src

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

AltStyle によって変換されたページ (->オリジナル) /