Re: [patch] Gopher DPI
| Newsgroups | gmane.comp.web.dillo.devel |
|---|---|
| Message-ID | <20121215184512.GA19019@darkstar> |
I am trying to make search work. Now (latest version of patch is included) I process type '7' (FullText search) is the same as '1'. So link "Search Veronica-2" on [1]/ is just a link that leads to [2]. Search terms can be added manually, like [3]. It works and it is what gopher URI Scheme RFC4266 says. DPI dialogs don't support text input, though it should not be hard to add. Another option is HTML forms and redirections. [1] gopher://gopherproject.org:70/1/ [2] gopher://gopher.floodgap.com:70/7/v2/vs [3] gopher://gopher.floodgap.com:70/7/v2/vs%09dillo _______________________________________________ Dillo-dev mailing list [email protected] http://lists.auriga.wearlab.de/cgi-bin/mailman/listinfo/dillo-dev
gopher.patch
(text/plain, 8.8 KB)
# HG changeset patch
# Parent 8d38d50f877390aebcc631402fe8102b8e52e4bc
diff -r 8d38d50f8773 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 8d38d50f8773 dpi/gopher.c
--- /dev/null
+++ b/dpi/gopher.c
@@ -0,0 +1,281 @@
+/*
+ * 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)
+{
+ ssize_t n;
+ size_t len;
+ 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");
+ line = NULL;
+ while ((n = getline(&line, &len, fp)) != -1) {
+ if (len == 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_html_str(str->str);
+ 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;
+ 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;
+ }
+
+ /* 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;
+ }
+
+ 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);
+
+ fp = fdopen(sockfd, "rw+");
+ if (!fp) {
+ MSG("fdopen\n");
+ return 1;
+ }
+
+ selector = Unescape_uri_str(selector);
+ MSG("sending selector: %s\n", selector);
+ fprintf(fp, "%s\r\n", selector);
+
+ /* 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[256], *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 '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':
+ 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";
+ 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 8d38d50f8773 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