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

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

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

Webmaster

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