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

📄 gopher.c

📁 一个很有名的浏览器
💻 C
📖 第 1 页 / 共 2 页
字号:
		return;	}	if (*name) {		selector = strchr(name, ASCII_TAB);		if (selector) {			/* Terminate name */			*selector++ = '\0';			/* 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 (entity == GOPHER_FILE			    && (*selector == GOPHER_BINARY ||				*selector == GOPHER_PCBINARY))				entity = *selector;		}		host = selector ? strchr(selector, ASCII_TAB) : NULL;		if (host) {			/* Terminate selector */			*host++ = '\0';		}		port = host ? strchr(host, ASCII_TAB) : NULL;		if (port) {			unsigned char *end;			int portno;			errno = 0;			portno = strtol(port + 1, (char **) &end, 10);			if (errno || !uri_port_is_valid(portno)) {				port = NULL;			} else {				/* Try to wipe out the default gopher port				 * number from being appended to links. */				if (portno == 70				    && entity_needs_gopher_access(entity))					portno = 0;				/* If the port number is 0 it means no port				 * number is needed in which case it can be				 * wiped out completely. Else append it to the				 * host string a la W3.  */				if (portno == 0) {					*port = '\0';				} else {					*port = ':';					/* Chop port if there is junk after the					 * number */					*end = '\0';				}			}		}	}	/* Nameless files are separator lines */	if (entity == GOPHER_FILE) {		int i = strlen(name) - 1;		while (name[i] == ' ' && i >= 0)			name[i--] = '\0';		if (i < 0)			entity = GOPHER_INFO;	}	if (entity != GOPHER_INDEX) {		add_gopher_description(buffer, entity);	}	switch (entity) {	case GOPHER_WWW:		/* Gopher pointer to W3 */		if (selector) {			add_gopher_link(buffer, name, selector);			break;		}		/* Fall through if no selector is defined so the		 * text is just displayed. */	case GOPHER_INFO:		/* Information or separator line */		add_to_string(buffer, name);		break;	default:	{		struct string address;		unsigned char *format = *selector ? "%s://%s@%s/" : "%s://%s%s/";		/* If port is defined it means that both @selector and @host		 * was correctly parsed. */		if (!port || !init_string(&address)) {			/* Parse error: Bad menu item */			add_to_string(buffer, name);			break;		}		assert(selector && host);		if (entity == GOPHER_TELNET) {			add_format_to_string(&address, format,					     "telnet", selector, host);		} else if (entity == GOPHER_TN3270) {			add_format_to_string(&address, format,					     "tn3270", selector, host);		} else {			add_format_to_string(&address, "gopher://%s/%c",				host, entity);			/* Encode selector string */			encode_selector_string(&address, selector);		}		/* Error response from Gopher doesn't deserve to		 * be a hyperlink. */		if (entity == GOPHER_INDEX) {			add_gopher_search_field(buffer, name, address.source);		} else if (address.length > 0			   && strlcmp(address.source, address.length - 1,				      "gopher://error.host:1/", -1)) {			add_gopher_link(buffer, name, address.source);		} else {			add_to_string(buffer, name);		}		done_string(&address);	}	}	add_char_to_string(buffer, '\n');}/* Search for line ending \r\n pair */static unsigned char *get_gopher_line_end(unsigned char *data, int datalen){	for (; datalen > 1; data++, datalen--)		if (data[0] == ASCII_CR && data[1] == ASCII_LF)			return data + 2;	return NULL;}static inline unsigned char *check_gopher_last_line(unsigned char *line, unsigned char *end){	assert(line < end);	/* Just to be safe NUL terminate the line */	end[-2] = 0;	return line[0] == '.' && !line[1] ? NULL : line;}/* Parse a Gopher Menu document */static enum connection_stateread_gopher_directory_data(struct connection *conn, struct read_buffer *rb){	enum connection_state state = S_TRANS;	struct string buffer;	unsigned char *end;	if (!init_string(&buffer))		return S_OUT_OF_MEM;	if (conn->from == 0) {		unsigned char *where = get_uri_string(conn->uri, URI_PUBLIC);		if (where) decode_uri_for_display(where);		add_format_to_string(&buffer,			"<html>\n"			"<head>\n"			"<title>Gopher menu at %s</title>\n"			"</head>\n"			"<body>\n"			"<h1>Gopher menu at %s</h1>\n"			"<pre>",			empty_string_or_(where), empty_string_or_(where));		mem_free_if(where);	}	while ((end = get_gopher_line_end(rb->data, rb->len))) {		unsigned char *line = check_gopher_last_line(rb->data, end);		/* Break on line with a dot by itself */		if (!line) {			state = S_OK;			break;		}		add_gopher_menu_line(&buffer, line);		conn->received += end - rb->data;		kill_buffer_data(rb, end - rb->data);	}	if (state != S_TRANS || rb->close == READ_BUFFER_END)		add_to_string(&buffer,			"</pre>\n"			"</body>\n"			"</html>\n");	add_fragment(conn->cached, conn->from, buffer.source, buffer.length);	conn->from += buffer.length;	done_string(&buffer);	return state;}static struct cache_entry *init_gopher_cache_entry(struct connection *conn){	struct gopher_connection_info *gopher = conn->info;	struct cache_entry *cached = get_cache_entry(conn->uri);	if (!cached) return NULL;	conn->cached = cached;	if (!cached->content_type	    && gopher	    && gopher->entity	    && gopher->entity->content_type) {		cached->content_type = stracpy(gopher->entity->content_type);		if (!cached->content_type) return NULL;	}	return cached;}/* Display a Gopher Index document. */static enum connection_stateinit_gopher_index_cache_entry(struct connection *conn){	unsigned char *where;	struct string buffer;	if (!init_gopher_cache_entry(conn)	    || !init_string(&buffer))		return S_OUT_OF_MEM;	where = get_uri_string(conn->uri, URI_PUBLIC);	if (where) decode_uri_for_display(where);	add_format_to_string(&buffer,		"<html>\n"		"<head>\n"		"<title>Searchable gopher index at %s</title>\n"		"</head>\n"		"<body>\n"		"<h1>Searchable gopher index at %s</h1>\n",		empty_string_or_(where), empty_string_or_(where));	if (where) {		add_gopher_search_field(&buffer, "Please enter search keywords",					where);	}	mem_free_if(where);	/* FIXME: I think this needs a form or something */	add_fragment(conn->cached, conn->from, buffer.source, buffer.length);	conn->from += buffer.length;	done_string(&buffer);	conn->cached->content_type = stracpy("text/html");	return conn->cached->content_type ? S_OK : S_OUT_OF_MEM;}static voidread_gopher_response_data(struct connection *conn, struct read_buffer *rb){	struct gopher_connection_info *gopher = conn->info;	enum connection_state state = S_TRANS;	assert(gopher && gopher->entity);	set_connection_timeout(conn);	if (!conn->cached && !init_gopher_cache_entry(conn)) {		end_gopher_connection(conn, S_OUT_OF_MEM);		return;	}	/* Now read the data from the socket */	switch (gopher->entity->type) {	case GOPHER_DIRECTORY:	case GOPHER_INDEX:		state = read_gopher_directory_data(conn, rb);		break;	case GOPHER_CSO:#if 0		/* FIXME: Merge CSO support */		state = read_gopher_cso_data(conn, rb);#endif		state = S_GOPHER_CSO_ERROR;		break;	case GOPHER_SOUND:	case GOPHER_PLUS_SOUND:	case GOPHER_PLUS_MOVIE:	case GOPHER_PLUS_PDF:	case GOPHER_MACBINHEX:	case GOPHER_PCBINARY:	case GOPHER_UUENCODED:	case GOPHER_BINARY:	case GOPHER_FILE:	case GOPHER_HTML:	case GOPHER_CHTML:	case GOPHER_GIF:	case GOPHER_IMAGE:	case GOPHER_PLUS_IMAGE:	default:		/* Add the received data as a new cache entry fragment and do		 * the connection data accounting. */		add_fragment(conn->cached, conn->from, rb->data, rb->len);		conn->received += rb->len;		conn->from     += rb->len;		kill_buffer_data(rb, rb->len);	}	/* Has the transport layer forced a shut down? */	if (rb->close == READ_BUFFER_END) {		state = S_OK;	}	if (state != S_TRANS) {		end_gopher_connection(conn, state);		return;	}	read_from_socket(conn, &conn->socket, rb, read_gopher_response_data);	set_connection_state(conn, S_TRANS);}static voidreceive_gopher_response(struct connection *conn){	struct read_buffer *rb = alloc_read_buffer(conn);	if (!rb) return;	set_connection_timeout(conn);	rb->close = READ_BUFFER_END_ONCLOSE;	read_from_socket(conn, &conn->socket, rb, read_gopher_response_data);}static voidsend_gopher_command(struct connection *conn){	struct gopher_connection_info *gopher = conn->info;	write_to_socket(conn, &conn->socket,			gopher->command, gopher->commandlen,			receive_gopher_response);	set_connection_state(conn, S_SENT);}/* FIXME: No decoding of strange data types as yet. */voidgopher_protocol_handler(struct connection *conn){	struct uri *uri = conn->uri;	enum connection_state state = S_CONN;	switch (get_uri_port(uri)) {	case 105:		/* If it's a port 105 GOPHER_CSO gopher_entity with no ISINDEX		 * token ('?'), use the form-based CSO gateway (otherwise,		 * return an ISINDEX cover page or do the ISINDEX search).		 * - FM */		if (uri->datalen == 1 && *uri->data == GOPHER_CSO) {			/* FIXME: redirect_cache() */			end_gopher_connection(conn, S_GOPHER_CSO_ERROR);		}		break;	case 79:#if 0		/* This is outcommented because it apparently means that the		 * finger protocol handler needs to be extended for handling		 * this the way Lynx does. --jonas */		/* If it's a port 79/0[/...] URL, use the finger gateway.		 * - FM */		if (uri->datalen >= 1 && *uri->data == GOPHER_FILE) {			/* FIXME: redirect_cache() */			end_gopher_connection(conn, S_OK);		}		break;#endif	default:		break;	}	state = init_gopher_connection_info(conn);	if (state != S_CONN) {		/* FIXME: Handle bad selector ... */		end_gopher_connection(conn, state);		return;	}	/* Set up a socket to the server for the data */	set_connection_timeout(conn);	conn->from = 0;	make_connection(conn, &conn->socket, send_gopher_command);}

⌨️ 快捷键说明

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