📄 htgopher.c
字号:
/* GOPHER ACCESS HTGopher.c** =============**** History:** 26 Sep 90 Adapted from other accesses (News, HTTP) TBL** 29 Nov 91 Downgraded to C, for portable implementation.** 10 Mar 96 Foteos Macrides (macrides@sci.wfbr.edu). Added a** form-based CSO/PH gateway. Can be invoked via a** "cso://host[:port]/" or "gopher://host:105/2"** URL. If a gopher URL is used with a query token** ('?'), the old ISINDEX procedure will be used** instead of the form-based gateway.** 15 Mar 96 Foteos Macrides (macrides@sci.wfbr.edu). Pass** port 79, gtype 0 gopher URLs to the finger** gateway.*/#include <HTUtils.h> /* Coding convention macros */#ifndef DISABLE_GOPHER#include <HTAlert.h>#include <HTParse.h>#include <HTTCP.h>#include <HTFinger.h>/*** Implements.*/#include <HTGopher.h>#define GOPHER_PORT 70 /* See protocol spec */#define CSO_PORT 105 /* See protocol spec */#define BIG 1024 /* Bug */#define LINE_LENGTH 256 /* Bug *//*** Gopher entity types.*/#define GOPHER_TEXT '0'#define GOPHER_MENU '1'#define GOPHER_CSO '2'#define GOPHER_ERROR '3'#define GOPHER_MACBINHEX '4'#define GOPHER_PCBINARY '5'#define GOPHER_UUENCODED '6'#define GOPHER_INDEX '7'#define GOPHER_TELNET '8'#define GOPHER_BINARY '9'#define GOPHER_GIF 'g'#define GOPHER_HTML 'h' /* HTML */#define GOPHER_CHTML 'H' /* HTML */#define GOPHER_SOUND 's'#define GOPHER_WWW 'w' /* W3 address */#define GOPHER_IMAGE 'I'#define GOPHER_TN3270 'T'#define GOPHER_INFO 'i'#define GOPHER_DUPLICATE '+'#define GOPHER_PLUS_IMAGE ':' /* Addition from Gopher Plus */#define GOPHER_PLUS_MOVIE ';'#define GOPHER_PLUS_SOUND '<'#define GOPHER_PLUS_PDF 'P'#include <HTFormat.h>/*** Hypertext object building machinery.*/#include <HTML.h>#include <LYStrings.h>#include <LYUtils.h>#include <LYLeaks.h>#define PUTC(c) (*targetClass.put_character)(target, c)#define PUTS(s) (*targetClass.put_string)(target, s)#define START(e) (*targetClass.start_element)(target, e, 0, 0, -1, 0)#define END(e) (*targetClass.end_element)(target, e, 0)#define FREE_TARGET (*targetClass._free)(target)#define GOPHER_PROGRESS(foo) HTAlert(foo)#define NEXT_CHAR HTGetCharacter()/*** Module-wide variables.*/PRIVATE int s; /* Socket for gopher or CSO host */struct _HTStructured { CONST HTStructuredClass * isa; /* For gopher streams */ /* ... */};PRIVATE HTStructured *target; /* the new gopher hypertext */PRIVATE HTStructuredClass targetClass; /* Its action routines */struct _HTStream{ HTStreamClass * isa; /* For form-based CSO gateway - FM */};typedef struct _CSOfield_info { /* For form-based CSO gateway - FM */ struct _CSOfield_info * next; char * name; char * attributes; char * description; int id; int lookup; int indexed; int url; int max_size; int defreturn; int explicit_return; int reserved; int public; char name_buf[16]; /* Avoid malloc if we can */ char desc_buf[32]; /* Avoid malloc if we can */ char attr_buf[80]; /* Avoid malloc if we can */} CSOfield_info;PRIVATE CSOfield_info *CSOfields = NULL; /* For form-based CSO gateway - FM */typedef struct _CSOformgen_context { /* For form-based CSO gateway - FM */ char * host; char * seek; CSOfield_info * fld; int port; int cur_line; int cur_off; int rep_line; int rep_off; int public_override; int field_select;} CSOformgen_context;/* Matrix of allowed characters in filenames** =========================================*/PRIVATE BOOL acceptable[256];PRIVATE BOOL acceptable_inited = NO;PRIVATE void init_acceptable NOARGS{ unsigned int i; char * good = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_$"; for(i = 0; i < 256; i++) acceptable[i] = NO; for(; *good; good++) acceptable[(unsigned int)*good] = YES; acceptable_inited = YES;}/* Decode one hex character** ========================*/PRIVATE CONST char hex[17] = "0123456789abcdef";PRIVATE char from_hex ARGS1(char, c){ return (char) ( (c>='0')&&(c<='9') ? c-'0' : (c>='A')&&(c<='F') ? c-'A'+10 : (c>='a')&&(c<='f') ? c-'a'+10 : 0);}/* Paste in an Anchor** ==================**** The title of the destination is set, as there is no way** of knowing what the title is when we arrive.**** On entry,** HT is in append mode.** text points to the text to be put into the file, 0 terminated.** addr points to the hypertext refernce address 0 terminated.*/PUBLIC BOOLEAN HT_Is_Gopher_URL=FALSE;PRIVATE void write_anchor ARGS2(CONST char *,text, CONST char *,addr){ BOOL present[HTML_A_ATTRIBUTES]; CONST char * value[HTML_A_ATTRIBUTES]; int i; for (i = 0; i < HTML_A_ATTRIBUTES; i++) present[i] = 0; present[HTML_A_HREF] = YES; ((CONST char **)value)[HTML_A_HREF] = addr; present[HTML_A_TITLE] = YES; ((CONST char **)value)[HTML_A_TITLE] = text; CTRACE((tfp,"HTGopher: adding URL: %s\n",addr)); HT_Is_Gopher_URL = TRUE; /* tell HTML.c that this is a Gopher URL */ (*targetClass.start_element)(target, HTML_A, present, (CONST char **)value, -1, 0); PUTS(text); END(HTML_A);}/* Parse a Gopher Menu document** ============================*/PRIVATE void parse_menu ARGS2( CONST char *, arg GCC_UNUSED, HTParentAnchor *, anAnchor){ char gtype; int ich; char line[BIG]; char *name = NULL, *selector = NULL; /* Gopher menu fields */ char *host = NULL; char *port; char *p = line; CONST char *title; int bytes = 0; int BytesReported = 0; char buffer[128];#define TAB '\t'#define HEX_ESCAPE '%' START(HTML_HTML); PUTC('\n'); START(HTML_HEAD); PUTC('\n'); START(HTML_TITLE); if ((title = HTAnchor_title(anAnchor))) PUTS(title); else PUTS(GOPHER_MENU_TITLE); END(HTML_TITLE); PUTC('\n'); END(HTML_HEAD); PUTC('\n'); START(HTML_BODY); PUTC('\n'); START(HTML_H1); if ((title = HTAnchor_title(anAnchor))) PUTS(title); else PUTS(GOPHER_MENU_TITLE); END(HTML_H1); PUTC('\n'); START(HTML_PRE); while ((ich=NEXT_CHAR) != EOF) { if (interrupted_in_htgetcharacter) { CTRACE((tfp, "HTGopher: Interrupted in HTGetCharacter, apparently.\n")); goto end_html; } if ((char)ich != LF) { *p = (char) ich; /* Put character in line */ if (p< &line[BIG-1]) p++; } else { *p++ = '\0'; /* Terminate line */ bytes += p-line; /* add size */ p = line; /* Scan it to parse it */ port = 0; /* Flag "not parsed" */ CTRACE((tfp, "HTGopher: Menu item: %s\n", line)); gtype = *p++; if (bytes > BytesReported + 1024) { sprintf(buffer, TRANSFERRED_X_BYTES, bytes); HTProgress(buffer); BytesReported = bytes; } /* Break on line with a dot by itself */ if ((gtype=='.') && ((*p=='\r') || (*p==0))) break; if (gtype && *p) { name = p; selector = strchr(name, TAB); if (selector) { *selector++ = '\0'; /* Terminate name */ /* * Gopher+ Type=0+ objects can be binary, and will * have 9 or 5 beginning their selector. Make sure * we don't trash the terminal by treating them as * text. - FM */ if (gtype == GOPHER_TEXT && (*selector == GOPHER_BINARY || *selector == GOPHER_PCBINARY)) gtype = *selector; host = strchr(selector, TAB); if (host) { *host++ = '\0'; /* Terminate selector */ port = strchr(host, TAB); if (port) { char *junk; port[0] = ':'; /* delimit host a la W3 */ junk = strchr(port, TAB); if (junk) *junk++ = '\0'; /* Chop port */ if ((port[1]=='0') && (!port[2])) port[0] = '\0'; /* 0 means none */ } /* no port */ } /* host ok */ } /* selector ok */ } /* gtype and name ok */ /* Nameless files are a separator line */ if (gtype == GOPHER_TEXT) { int i = strlen(name)-1; while (name[i] == ' ' && i >= 0) name[i--] = '\0'; if (i < 0) gtype = GOPHER_INFO; } if (gtype == GOPHER_WWW) { /* Gopher pointer to W3 */ PUTS("(HTML) "); write_anchor(name, selector); } else if (gtype == GOPHER_INFO) { /* Information or separator line */ PUTS(" "); PUTS(name); } else if (port) { /* Other types need port */ char *address = 0; char *format = *selector ? "%s//%s@%s/" : "%s//%s/"; if (gtype == GOPHER_TELNET) { PUTS(" (TEL) "); HTSprintf0(&address, format, STR_TELNET_URL, selector, host); } else if (gtype == GOPHER_TN3270) { PUTS("(3270) "); HTSprintf0(&address, format, STR_TN3270_URL, selector, host); } else { /* If parsed ok */ char *r; switch(gtype) { case GOPHER_TEXT: PUTS("(FILE) "); break; case GOPHER_MENU: PUTS(" (DIR) "); break; case GOPHER_CSO: PUTS(" (CSO) "); break; case GOPHER_PCBINARY: PUTS(" (BIN) "); break; case GOPHER_UUENCODED: PUTS(" (UUE) "); break; case GOPHER_INDEX: PUTS(" (?) "); break; case GOPHER_BINARY: PUTS(" (BIN) "); break; case GOPHER_GIF: case GOPHER_IMAGE: case GOPHER_PLUS_IMAGE: PUTS(" (IMG) "); break; case GOPHER_SOUND: case GOPHER_PLUS_SOUND: PUTS(" (SND) "); break; case GOPHER_MACBINHEX: PUTS(" (HQX) "); break; case GOPHER_HTML: case GOPHER_CHTML: PUTS("(HTML) "); break; case 'm': PUTS("(MIME) "); break; case GOPHER_PLUS_MOVIE: PUTS(" (MOV) "); break; case GOPHER_PLUS_PDF: PUTS(" (PDF) "); break; default: PUTS("(UNKN) "); break; } HTSprintf0(&address, "//%s/%c", host, gtype); for(r = selector; *r; r++) { /* Encode selector string */ if (acceptable[UCH(*r)]) { HTSprintf(&address, "%c", *r); } else { HTSprintf(&address, "%c%c%c", HEX_ESCAPE, /* Means hex coming */ hex[(TOASCII(*r)) >> 4], hex[(TOASCII(*r)) & 15]); } } } /* Error response from Gopher doesn't deserve to be a hyperlink. */ if (strcmp (address, "gopher://error.host:1/0")) write_anchor(name, address); else PUTS(name); FREE(address); } else { /* parse error */ CTRACE((tfp, "HTGopher: Bad menu item.\n")); PUTS(line); } /* parse error */ PUTC('\n'); p = line; /* Start again at beginning of line */ } /* if end of line */ } /* Loop over characters */end_html: END(HTML_PRE); PUTC('\n'); END(HTML_BODY); PUTC('\n'); END(HTML_HTML); PUTC('\n'); FREE_TARGET; return;}/* Parse a Gopher CSO document from an ISINDEX query.** ==================================================**** Accepts an open socket to a CSO server waiting to send us** data and puts it on the screen in a reasonable manner.**** Perhaps this data can be automatically linked to some** other source as well???**** Taken from hacking by Lou Montulli@ukanaix.cc.ukans.edu** on XMosaic-1.1, and put on libwww 2.11 by Arthur Secret,** secret@dxcern.cern.ch .*/PRIVATE void parse_cso ARGS2( CONST char *, arg, HTParentAnchor *, anAnchor){ int ich; char line[BIG]; char *p = line; char *second_colon, last_char='\0'; CONST char *title; START(HTML_HEAD); PUTC('\n'); START(HTML_TITLE); if ((title = HTAnchor_title(anAnchor))) PUTS(title); else PUTS(GOPHER_CSO_SEARCH_RESULTS); END(HTML_TITLE); PUTC('\n'); END(HTML_HEAD); PUTC('\n'); START(HTML_H1); if ((title = HTAnchor_title(anAnchor))) PUTS(title); else { PUTS(arg); PUTS(GOPHER_SEARCH_RESULTS); } END(HTML_H1); PUTC('\n'); START(HTML_PRE); /* ** Start grabbing chars from the network.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -