⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 htgopher.c

📁 www工具包
💻 C
📖 第 1 页 / 共 2 页
字号:
/*							       	     HTGopher.c**	GOPHER ACCESS****	(c) COPYRIGHT MIT 1995.**	Please first read the full copyright statement in the file COPYRIGH.**** History:**	26 Sep 90	Adapted from other accesses (News, HTTP) TBL**	29 Nov 91	Downgraded to C, for portable implementation.**	28 Apr 94	target no more global and icons implemented**			HF, frystyk@w3.org**	 2 May 94	Fixed possible security hole when the URL contains**			a newline, that could cause multiple commands to be**			sent to a Gopher server. AL, luotonen@www.cern.ch**	12 May 94	Checked and made ready for multi-threads, Frystyk**	 8 Jul 94  FM	Insulate free() from _free structure element.**	   Sep 95  HFN	Made non-blocking and state stream oriented*//* Library include files */#include "wwwsys.h"#include "WWWUtil.h"#include "WWWCore.h"#include "WWWHTML.h"#include "WWWDir.h"#include "WWWTrans.h"#include "HTNetMan.h"#include "HTGopher.h"					 /* Implemented here *//* Macros and other defines */#ifndef GOPHER_PORT#define GOPHER_PORT 70					/* See protocol spec */#endif/* Hypertext object building machinery */#define PUTC(c) (*target->isa->put_character)(target, c)#define PUTS(s) (*target->isa->put_string)(target, s)#define START(e) (*target->isa->start_element)(target, e, 0, 0)#define END(e) (*target->isa->end_element)(target, e)/* Type definitions and global variables etc. local to this module */typedef enum _HTGopherType {    GT_TEXT		= '0',    GT_MENU		= '1',    GT_CSO		= '2',    GT_ERROR		= '3',    GT_MACBINHEX	= '4',    GT_PCBINHEX		= '5',    GT_UUENCODED	= '6',    GT_INDEX		= '7',    GT_TELNET		= '8',    GT_BINARY		= '9',    GT_GIF		= 'g',    GT_HTML		= 'h',        				     /* HTML */    GT_INFO		= 'i',    GT_SOUND		= 's',    GT_WWW		= 'w',				       /* W3 address */    GT_IMAGE		= 'I',    GT_TN3270		= 'T',    GT_DUPLICATE	= '+',    GT_PLUS_IMAGE	= ':',			/* Addition from Gopher Plus */    GT_PLUS_MOVIE	= ';',    GT_PLUS_SOUND	= '<',    GT_EOF		= '.'} HTGopherType;/* Final states have negative value */typedef enum _GopherState {    GOPHER_ERROR	= -3,    GOPHER_NO_DATA	= -2,    GOPHER_GOT_DATA	= -1,    GOPHER_BEGIN	= 0,    GOPHER_NEED_CONNECTION,    GOPHER_NEED_REQUEST,    GOPHER_NEED_RESPONSE} GopherState;/* This is the context structure for the this module */typedef struct _gopher_info {    HTGopherType	type; 		                 /* Gopher item type */    GopherState		state;    char *		cmd;    HTNet *		net;} gopher_info;#define MAX_GOPHER_LINE		256struct _HTStructured {    const HTStructuredClass *	isa;};struct _HTStream {    const HTStreamClass *	isa;    HTStructured *	  	target;    HTRequest *			request;    HTEOLState			state;    char *			url;    BOOL			pre;		       /* Preformatted mode? */    BOOL			junk;		       /* For too long lines */    BOOL			CSO;    char			cso_rec[10];		/* CSO record number */    char 			buffer[MAX_GOPHER_LINE+1];    int				buflen;};struct _HTInputStream {    const HTInputStreamClass *	isa;};PRIVATE HTDirShow	dir_show = HT_DS_ICON;/* ------------------------------------------------------------------------- *//*	GopherIcon**	----------**	This function finds an appopriate icon for the item in the gopher**	list. Actually it is only a shell build upon HTIcon_find().*/PRIVATE HTIconNode *GopherIcon (HTGopherType type){    HTFormat   content_type = NULL;    HTEncoding content_encoding = NULL;    HTFileMode mode = HT_IS_FILE;    switch(type) {      case GT_MENU:	mode = HT_IS_DIR;      case GT_TEXT:	content_type = HTAtom_for("text/void");	break;      case GT_IMAGE:      case GT_PLUS_IMAGE:      case GT_GIF:	content_type = HTAtom_for("image/void");	break;      case GT_WWW:      case GT_HTML:	content_type = HTAtom_for("text/void");	break;      case GT_SOUND:      case GT_PLUS_SOUND:	content_type = HTAtom_for("audio/void");	break;      case GT_PLUS_MOVIE:	content_type = HTAtom_for("video/void");	break;      case GT_INDEX:	content_type = HTAtom_for("application/x-gopher-index");	break;      case GT_CSO:	content_type = HTAtom_for("application/x-gopher-cso");	break;      case GT_TELNET:	content_type = HTAtom_for("application/x-gopher-telnet");	break;      case GT_TN3270:	content_type = HTAtom_for("application/x-gopher-tn3270");	break;      case GT_DUPLICATE:	content_type = HTAtom_for("application/x-gopher-duplicate");	break;      case GT_ERROR:	content_type = HTAtom_for("www/unknown");	break;      case GT_BINARY:	content_type = WWW_BINARY;	break;      default:	content_type = HTAtom_for("www/unknown");	break;    }    return HTIcon_find(mode, content_type, content_encoding);}/* ------------------------------------------------------------------------- *//*				    STREAMS				     *//* ------------------------------------------------------------------------- *//*	GopherTitle**	-----------**	Create the top part of the page*/PRIVATE BOOL GopherTitle (HTStream *me){    HTStructured *target = me->target;    char *str = NULL;    StrAllocCopy(str, me->CSO ? "CSO Search " : "GopherMenu");    START(HTML_HTML);    START(HTML_HEAD);    START(HTML_TITLE);    if (me->CSO) {	char *keyword = strchr(me->url, '?');	if (keyword) {	    StrAllocCat(str, "for ");	    StrAllocCat(str, ++keyword);	}    }    PUTS(str);    END(HTML_TITLE);    END(HTML_HEAD);    START(HTML_BODY);    START(HTML_H1);    PUTS(str);    END(HTML_H1);    HT_FREE(str);    return YES;}/*	GopherBottom**	------------**	Create the bottom part of the page*/PRIVATE BOOL GopherBottom (HTStream *me){    HTStructured *target = me->target;    if (me->pre)	END(HTML_PRE);    END(HTML_BODY);    END(HTML_HTML);    return YES;}/*	GopherMenuLine**	--------------**	Parses a Gopher Menu Line**	Return YES if more data else NO*/PRIVATE BOOL GopherMenuLine (HTStream *me, char *line){    HTStructured *target = me->target;    HTGopherType gtype = (HTGopherType) *line++;    HTTRACE(PROT_TRACE, "HTGopher.... Menu line: `%s\'\n" _ line);    if (gtype == GT_INFO) {	char *stop = strchr(line, '\t');	if (stop) *stop = '\0';	PUTS(line);    } else if (gtype == GT_ERROR) {	char *stop = strchr(line, '\t');	if (stop) *stop = '\0';	PUTS(line);    } else if ((strstr(line, "error.host") || strstr(line, "errorhost"))) {	char *stop = strchr(line, '\t');	      /* Chop off error.host */	if (stop) *stop = '\0';	PUTS(line);    } else if (gtype == GT_EOF) {	return NO;    } else {				    /* Parse normal gopher menu line */	char *name = line;			     /* Get link information */	char *selector = strchr(name, '\t');	char *host = NULL;	char *port = NULL;	if (selector) {	    *selector++ = '\0';	    if ((host = strchr(selector, '\t'))) {		*host++ = '\0';		if ((port = strchr(host, '\t'))) {		    char *junk;		    *port = ':';	 	     /* delimit host a la W3 */		    if ((junk = strchr(port, '\t')) != NULL)			*junk = '\0';				/* Chop port */		    if (*(port+1) == '0' && !*(port+2))			*port = '\0';		}	    }	}	if (!me->pre) {		      /* For now we use preformatted listing */	    START(HTML_PRE);	    me->pre = YES;	}	if (dir_show & HT_DS_ICON) {		 	 /* Put out the icon */	    HTIconNode *icon = GopherIcon(gtype);	    if (icon) {		char * alt = HTIcon_alternative(icon, YES);		HTMLPutImg(target, HTIcon_url(icon), alt, NULL);		HT_FREE(alt);		PUTC(' ');	    }	}	if (gtype == GT_WWW) {			     /* Gopher pointer to W3 */	    char *escaped = NULL;	    escaped = HTEscape(selector, URL_PATH);	    HTStartAnchor(target, NULL, escaped);	    PUTS(name);	    END(HTML_A);	    HT_FREE(escaped);	} else if (port) {			    /* Other types need port */	    char *escaped = NULL;	    char *address = NULL;	    int addr_len;	    	    /* Calculate the length of the WWW-address */	    if (selector && *selector) {		escaped = HTEscape(selector, URL_PATH);		addr_len = 15 + strlen(escaped) + strlen(host) + 1;	    } else {		addr_len = 15 + strlen(host) + 1;	    }	    if ((address = (char *) HT_MALLOC(addr_len)) == NULL)	        HT_OUTOFMEM("GopherMenuLine");	    *address = '\0';	    if (gtype == GT_TELNET) {		if (escaped)		    sprintf(address, "telnet://%s@%s/", escaped, host);		else		    sprintf(address, "telnet://%s/", host);	    } else if (gtype == GT_TN3270) {		if (escaped)		    sprintf(address, "tn3270://%s@%s/", escaped, host);		else		    sprintf(address, "tn3270://%s/", host);	    } else {		if (escaped)		    sprintf(address, "//%s/%c%s", host, gtype, escaped);		else		    sprintf(address, "//%s/%c", host, gtype);	    }	    	    HTStartAnchor(target, NULL, address);	    PUTS(name);	    END(HTML_A);	    HT_FREE(address);	    HT_FREE(escaped);	    PUTC('\n');	} else {					   /* If parse error */	    HTTRACE(PROT_TRACE, "HTGopher.... Bad menu item, `%s\'\n" _ line);	}    }    return YES;}/*	GopherCSOLine**	--------------**	Parses a Gopher Menu Line**	Return YES if more data else NO*/PRIVATE BOOL GopherCSOLine (HTStream *me, char *line){    HTStructured *target = me->target;    if (*line == '1') {					 /* Information line */	char *start = strchr(line, ':');	start = start ? ++start : line;	PUTS(start);    } else if (*line == '2') {				/* Transfer complete */	return NO;    } else if (*line == '5') {					    /* Error */	char *start = strchr(line, ':');	start = start ? ++start : line;	PUTS(start);    } else if (*line == '-') {					     /* data */	/*  data lines look like '-200:code:field:value'	 *  where code is the search result number and can be  	 *  multiple digits (infinte?)	 *  find the second colon and check the digit to the	 *  left of it to see if they are diferent	 *  if they are then a different person is starting. 	 */	char *code;	char *field;	if ((code = strchr(line, ':')) && (field = strchr(++code, ':'))) {	    BOOL newrec = YES;	    *field++ = '\0';	    if (!*me->cso_rec) {		   /* Header of first record */		START(HTML_DL);	    } else if (strcmp(me->cso_rec, code)) {    /* Another new record */		START(HTML_B);	    } else		newrec = NO;	    START(HTML_DT);	    	    /* I'm not sure whether the name field comes in any	     *  special order or if its even required in a 	     *  record, so for now the first line is the header	     *  no matter what it is (it's almost always the	     *  alias)	     */	    {		char *value = strchr(field, ':');		if (!value)		    value = "Empty value";		else		    *value++ = '\0';		{		    char *strip = HTStrip(field);		    PUTS(strip);		    START(HTML_DD);		    strip = HTStrip(value);		    if (newrec) {			PUTS(strip);			END(HTML_B);		    } else			PUTS(strip);	    }	    /* Save the code for comparison on the next pass */	    strcpy(me->cso_rec, code);	    }	}    } else {						     /* Unknown line */	char *start = strchr(line, ':');	start = start ? ++start : line;	PUTS(start);    }    return YES;}/***  Searches for Gopher line until buffer fills up or a CRLF or LF is found*/PRIVATE int GopherMenu_put_block (HTStream * me, const char * b, int l){    while (l-- > 0) {	if (me->state == EOL_FCR) {	    if (*b == LF && me->buflen) {		if (!me->junk) {		    BOOL cont;		    *(me->buffer+me->buflen) = '\0';

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -