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

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

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

Webmaster

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