Re: [patch] Gopher DPI

[email protected]
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.