Re: [patch] Gopher DPI
| Newsgroups | gmane.comp.web.dillo.devel |
|---|---|
| Message-ID | <20121217232935.GA28693@darkstar> |
Small changes - Added 'p' filetype for images (used by some gopher servers) - Use dGetline instead of getline _______________________________________________ Dillo-dev mailing list [email protected] http://lists.auriga.wearlab.de/cgi-bin/mailman/listinfo/dillo-dev
gopher.patch
(text/plain, 9.4 KB)
# HG changeset patch
# Parent 7394132dce381c53d23bab66c75847531a000f80
diff -r 7394132dce38 dpi/Makefile.am
--- a/dpi/Makefile.am
+++ b/dpi/Makefile.am
@@ -4,6 +4,7 @@
bookmarksdir = $(libdir)/dillo/dpi/bookmarks
downloadsdir = $(libdir)/dillo/dpi/downloads
ftpdir = $(libdir)/dillo/dpi/ftp
+gopherdir = $(libdir)/dillo/dpi/gopher
httpsdir = $(libdir)/dillo/dpi/https
hellodir = $(libdir)/dillo/dpi/hello
vsourcedir = $(libdir)/dillo/dpi/vsource
@@ -13,6 +14,7 @@
bookmarks_PROGRAMS = bookmarks.dpi
downloads_PROGRAMS = downloads.dpi
ftp_PROGRAMS = ftp.filter.dpi
+gopher_PROGRAMS = gopher.filter.dpi
https_PROGRAMS = https.filter.dpi
hello_PROGRAMS = hello.filter.dpi
vsource_PROGRAMS = vsource.filter.dpi
@@ -29,6 +31,9 @@
ftp_filter_dpi_LDADD = \
$(top_builddir)/dpip/libDpip.a \
$(top_builddir)/dlib/libDlib.a
+gopher_filter_dpi_LDADD = \
+ $(top_builddir)/dpip/libDpip.a \
+ $(top_builddir)/dlib/libDlib.a
https_filter_dpi_LDADD = @LIBSSL_LIBS@ \
$(top_builddir)/dpip/libDpip.a \
$(top_builddir)/dlib/libDlib.a
@@ -53,6 +58,7 @@
bookmarks_dpi_SOURCES = bookmarks.c dpiutil.c dpiutil.h
downloads_dpi_SOURCES = downloads.cc dpiutil.c dpiutil.h
ftp_filter_dpi_SOURCES = ftp.c dpiutil.c dpiutil.h
+gopher_filter_dpi_SOURCES = gopher.c dpiutil.c dpiutil.h
https_filter_dpi_SOURCES = https.c dpiutil.c dpiutil.h
hello_filter_dpi_SOURCES = hello.c dpiutil.c dpiutil.h
vsource_filter_dpi_SOURCES = vsource.c dpiutil.c dpiutil.h
diff -r 7394132dce38 dpi/gopher.c
--- /dev/null
+++ b/dpi/gopher.c
@@ -0,0 +1,300 @@
+/*
+ * DPI for Gopher.
+ *
+ * Standards:
+ * https://tools.ietf.org/html/rfc1436 - The Internet Gopher Protocol
+ * https://tools.ietf.org/html/rfc4266 - The gopher URI Scheme
+ * http://gopher.quux.org:70/Archives/Mailing%20Lists/gopher/gopher.2002-02|/MBOX-MESSAGE/34
+ */
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "../dpip/dpip.h"
+#include "dpiutil.h"
+
+#define _MSG(...)
+#define MSG(...) fprintf(stderr, "[gopher dpi]: " __VA_ARGS__ )
+
+static Dsh *sh;
+
+static int connectto(char *host, char *port)
+{
+ struct addrinfo hints, *servinfo, *p;
+ int sockfd, r;
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ r = getaddrinfo(host, port, &hints, &servinfo);
+ if (r != 0) {
+ fprintf(stderr, "gopher: getaddrinfo: %s\n", gai_strerror(r));
+ return -1;
+ }
+
+ for(p = servinfo; p != NULL; p = p->ai_next) {
+ if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
+ perror("gopher: socket");
+ continue;
+ }
+
+ if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
+ close(sockfd);
+ perror("gopher: connect");
+ continue;
+ }
+
+ break;
+ }
+
+ if (p == NULL)
+ return -1;
+
+ freeaddrinfo(servinfo);
+ return sockfd;
+}
+
+/*
+ * Read and display Menu Entity.
+ */
+static void displaymenu(FILE *fp)
+{
+ char *line, type, *username, *selector, *host, *port, *p;
+
+ a_Dpip_dsh_write_str(sh, 0, "Content-type: text/html\n\n"
+ "<!doctype html>\n"
+ "<title>Gopher</title>\n"
+ "<pre>\n");
+ while ((line = dGetline(fp)) != NULL) {
+ if (line[0] == '\0') {
+ MSG("no type\n");
+ continue;
+ }
+ type = line[0];
+ username = line + 1;
+
+ selector = strchr(username, '\t');
+ if (!selector) {
+ MSG("no selector\n");
+ continue;
+ }
+ *selector++ = '\0';
+ host = strchr(selector, '\t');
+ if (!host) {
+ MSG("no host\n");
+ continue;
+ }
+ *host++ = '\0';
+ port = strchr(host, '\t');
+ if (!port) {
+ MSG("no port\n");
+ continue;
+ }
+ *port++ = '\0';
+ p = strpbrk(port, "\r\t");
+ if (p == NULL) {
+ MSG("no CR\n");
+ continue;
+ }
+ *p = '\0';
+
+ username = Escape_html_str(username);
+ if (type == 'i')
+ a_Dpip_dsh_printf(sh, 0, "%s\n", username);
+ else if (type == '3')
+ a_Dpip_dsh_printf(sh, 0, "<b>%s</b>\n", username);
+ else {
+ Dstr *str;
+ char *url;
+
+ str = dStr_new(NULL);
+ dStr_sprintf(str, "gopher://%s:%s/%c%s", host, port, type, selector, username);
+ url = Escape_uri_str(str->str, "'");
+ if (type == '7') {
+ a_Dpip_dsh_printf(sh, 0, "</pre><form action='%s'>\n", url);
+ a_Dpip_dsh_printf(sh, 0, "<label for=query>%s</label>\n", username);
+ a_Dpip_dsh_printf(sh, 0, "<input name=query>\n");
+ a_Dpip_dsh_printf(sh, 0, "</form><pre>\n");
+ } else {
+ a_Dpip_dsh_printf(sh, 0, "<a href='%s'>%s</a>\n", url, username);
+ }
+ dFree(url);
+ dStr_free(str, 1);
+ }
+ dFree(username);
+ }
+ free(line);
+}
+
+int main(int argc, char *argv[])
+{
+ char *dpip_tag, *cmd, *url, *d_cmd;
+ int sockfd;
+ char *host, *port, type, *path, *selector, *p;
+ FILE *fp;
+
+ sh = a_Dpip_dsh_new(STDIN_FILENO, STDOUT_FILENO, 1024);
+ if (argc == 2) {
+ /* For debugging */
+ dpip_tag = NULL;
+ cmd = NULL;
+ url = dStrdup(argv[1]);
+ } else {
+ /* Authenticate client. */
+ dpip_tag = a_Dpip_dsh_read_token(sh, 1);
+ if (!dpip_tag || a_Dpip_check_auth(dpip_tag) < 0) {
+ MSG("can't authenticate request: %s\n", dStrerror(errno));
+ a_Dpip_dsh_close(sh);
+ return 1;
+ }
+ dFree(dpip_tag);
+ /* Read the DPI command. */
+ dpip_tag = a_Dpip_dsh_read_token(sh, 1);
+
+ cmd = a_Dpip_get_attr(dpip_tag, "cmd");
+ url = a_Dpip_get_attr(dpip_tag, "url");
+ if (!cmd || !url)
+ return 1;
+ }
+
+ d_cmd = a_Dpip_build_cmd("cmd=%s url=%s", "start_send_page", url);
+ a_Dpip_dsh_write_str(sh, 0, d_cmd);
+ dFree(d_cmd);
+
+ /* Search forms */
+ p = strstr(url, "?query=");
+ if (p != NULL) {
+ *p++ = '%';
+ *p++ = '0';
+ *p++ = '9';
+ memmove(p, p + 4, strlen(p + 4) + 1);
+ }
+
+ /* Parse URI */
+ if (dStrnAsciiCasecmp(url, "gopher://", 9) != 0) {
+ MSG("URI scheme is not gopher\n");
+ return 1;
+ }
+
+ host = url + 9;
+ port = strpbrk(host, ":/");
+ if (port == NULL) {
+ type = '1';
+ port = "70";
+ selector = "";
+ } else {
+ if (*port == ':') {
+ *port = '\0';
+ port++;
+ path = strchr(port, '/');
+ if (path == NULL) {
+ MSG("no path in URL\n");
+ return 1;
+ }
+ *path = '\0';
+ path++;
+ } else {
+ *port = '\0';
+ path = port + 1;
+ port = "70";
+ }
+ type = path[0];
+ if (type == '\0') {
+ type = '1'; /* RFC 4266 says <gophertype> defaults to 1 */
+ selector = "";
+ } else
+ selector = path + 1;
+ }
+
+ /* Connect to gopher server */
+ MSG("host: %s, port: %s\n", host, port);
+ sockfd = connectto(host, port);
+ if(sockfd == -1) {
+ MSG("failed to connect\n");
+ return 1;
+ }
+
+ fp = fdopen(sockfd, "w+");
+ if (!fp) {
+ MSG("fdopen\n");
+ return 1;
+ }
+ setbuf(fp, NULL);
+
+ selector = Unescape_uri_str(selector);
+
+ MSG("sending selector: %s\n", selector);
+ fprintf(fp, "%s\r\n", selector);
+ fflush(fp);
+
+ /* Menu Transaction (Type 1 item) */
+ /* Full-Text Search Transaction (Type 7 item) */
+ if (type == '1' || type == '7')
+ displaymenu(fp);
+ else {
+ size_t n;
+ char buf[4096], *mime, *ext;
+
+ mime = "application/octet-stream";
+ ext = strrchr(selector, '.');
+ if(ext)
+ ext++;
+ switch (type) {
+ case '0':
+ /* TextFile */
+ mime = "text/plain";
+ break;
+ case 'h':
+ mime = "text/html";
+ break;
+ case 'g':
+ mime = "image/gif";
+ break;
+ case '4':
+ case '5':
+ case '9':
+ if (!ext)
+ break;
+ if (dStrAsciiCasecmp(ext, "zip") == 0)
+ mime = "application/zip";
+ else if (dStrAsciiCasecmp(ext, "gz") == 0)
+ mime = "application/gzip";
+ break;
+ case 'I':
+ case 'p':
+ if (!ext)
+ break;
+ if (dStrAsciiCasecmp(ext, "jpeg") == 0 ||
+ dStrAsciiCasecmp(ext, "jpg") == 0)
+ mime = "image/jpeg";
+ else if (dStrAsciiCasecmp(ext, "png") == 0)
+ mime = "image/png";
+ else if (dStrAsciiCasecmp(ext, "bmp") == 0)
+ mime = "image/bmp";
+ else if (dStrAsciiCasecmp(ext, "gif") == 0)
+ mime = "image/gif";
+ break;
+ }
+
+ a_Dpip_dsh_printf(sh, 1, "Content-type: %s\r\n\r\n", mime);
+ while ((n = fread (buf, 1, sizeof buf, fp)) > 0)
+ a_Dpip_dsh_write(sh, 1, buf, n);
+ }
+
+ dFree(selector);
+ dFree(cmd);
+ dFree(url);
+ dFree(dpip_tag);
+
+ a_Dpip_dsh_close(sh);
+ a_Dpip_dsh_free(sh);
+ return 0;
+}
diff -r 7394132dce38 dpid/dpidrc.in
--- a/dpid/dpidrc.in
+++ b/dpid/dpidrc.in
@@ -2,5 +2,6 @@
proto.file=file/file.dpi
proto.ftp=ftp/ftp.filter.dpi
+proto.gopher=gopher/gopher.filter.dpi
proto.https=https/https.filter.dpi
proto.data=datauri/datauri.filter.dpi