home *** CD-ROM | disk | FTP | other *** search
/ Collection of Internet / Collection of Internet.iso / msdos / lynx / source / www / library / implemen / htgopher.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-25  |  19.9 KB  |  797 lines

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