diff -urN links-2.1pre7.orig/Makefile.am links-2.1pre7/Makefile.am
--- links-2.1pre7.orig/Makefile.am      Sat Jun  8 14:11:51 2002
+++ links-2.1pre7/Makefile.am   Tue Feb  4 19:59:00 2003
@@ -13,7 +13,7 @@
else
endif

-links_SOURCES=af_unix.c beos.c bfu.c bookmarks.c builtin.c cache.c charsets.c connect.c context.c cookies.c default.c dip.c dither.c dns.c drivers.c error.c file.c finger.c font_include.c framebuffer.c ftp.c gif.c html.c html_gr.c html_r.c html_tbl.c http.c https.c img.c imgcache.c ipret.c javascr.c javascript.c jpeg.c jsint.c kbd.c language.c links_icon.c listedit.c lru.c mailto.c main.c menu.c memory.c md5.c md5hl.c ns.c objreq.c os_dep.c pmshell.c png.c pomocny.c sched.c select.c session.c svgalib.c terminal.c tiff.c types.c url.c view.c view_gr.c win32.c x.c xbm.c links.h cfg.h os_dep.h os_depx.h setup.h codepage.h language.h codepage.inc entity.inc uni_7b.inc language.inc arrow.inc md5.h ns.h struct.h tree.h typy.h ipret.h javascript.h builtin.h builtin_keys.h bits.h
+links_SOURCES=af_unix.c beos.c bfu.c bookmarks.c builtin.c cache.c charsets.c connect.c context.c cookies.c default.c dip.c dither.c dns.c drivers.c error.c file.c lynxcgi.c finger.c font_include.c framebuffer.c ftp.c gif.c html.c html_gr.c html_r.c html_tbl.c http.c https.c img.c imgcache.c ipret.c javascr.c javascript.c jpeg.c jsint.c kbd.c language.c links_icon.c listedit.c lru.c mailto.c main.c menu.c memory.c md5.c md5hl.c ns.c objreq.c os_dep.c pmshell.c png.c pomocny.c sched.c select.c session.c svgalib.c terminal.c tiff.c types.c url.c view.c view_gr.c win32.c x.c xbm.c links.h cfg.h os_dep.h os_depx.h setup.h codepage.h language.h codepage.inc entity.inc uni_7b.inc language.inc arrow.inc md5.h ns.h struct.h tree.h typy.h ipret.h javascript.h builtin.h builtin_keys.h bits.h

dist-hook:
#remove the symlinka:
diff -urN links-2.1pre7.orig/links.h links-2.1pre7/links.h
--- links-2.1pre7.orig/links.h  Sat Nov  2 17:22:41 2002
+++ links-2.1pre7/links.h       Tue Feb  4 19:53:50 2003
@@ -1124,6 +1124,10 @@
void telnet_func(struct session *, unsigned char *);
void tn3270_func(struct session *, unsigned char *);

+/* lynxcgi.c */
+
+void lynxcgi_func(struct connection *);
+
/* kbd.c */

#define BM_BUTT                15
diff -urN links-2.1pre7.orig/lynxcgi.c links-2.1pre7/lynxcgi.c
--- links-2.1pre7.orig/lynxcgi.c        Thu Jan  1 01:00:00 1970
+++ links-2.1pre7/lynxcgi.c     Tue Feb  4 21:59:10 2003
@@ -0,0 +1,315 @@
+/*
+ * lynxcgi.c:
+ * Implementation of lynxcgi: protocol.
+ *
+ * Cf. http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html
+ *
+ * Copyright (c) 2003 Chris Lightfoot. All rights reserved.
+ * Email: [email protected]; WWW: http://www.ex-parrot.com/~chris/
+ *
+ */
+
+static const char rcsid[] = "$Id:$";
+
+#include <string.h>
+
+#include "links.h"
+
+unsigned char *get_line_from_stream(FILE *fp) {
+    unsigned char *buf;
+    int c;
+    size_t i, len;
+    buf = malloc(len = 128);
+    i = 0;
+    while ((c = getc(fp)) != EOF) {
+        if (c == '\n') {
+            if (i > 0 && buf[i - 1] == '\r')
+                buf[i - 1] = 0;
+            else
+                buf[i] = 0;
+            break;
+        }
+        buf[i] = (unsigned char)c;
+        ++i;
+        if (i == len)
+            buf = realloc(buf, len *= 2);
+    }
+
+    if (c == EOF && (ferror(fp) || i == 0)) {
+        free(buf);
+        return NULL;
+    }
+
+    return buf;
+}
+
+int parse_nph_response_from_stream(struct cache_entry *e, FILE *fp, unsigned char *firstline) {
+    return 0;
+        /* not implemented yet */
+}
+
+int parse_cgi_response_from_stream(struct cache_entry *e, FILE *fp) {
+    unsigned char *line, *hdr, *val, *http_resp_line = NULL, *http_hdrs = NULL, *data;
+    size_t http_hdrs_len = 0, http_hdrs_alloc, data_len = 0, data_alloc;
+    int c;
+
+    fseek(fp, 0, SEEK_SET);
+
+    line = get_line_from_stream(fp);
+    if (!line)
+        return 0;
+
+    /* Handle NPH case. */
+    if (strncmp(line, "HTTP/1.1 ", 9) == 0 || strncmp(line, "HTTP/1.0 ", 9) == 0)
+        return parse_nph_response_from_stream(e, fp, line);
+
+    http_hdrs = malloc(http_hdrs_alloc = 1024);
+    *http_hdrs = 0;
+
+    /* Handle normal response. */
+    do {
+        size_t hdr_len, val_len;
+        /* end of headers; rest of data is just regular output. */
+        if (*line == 0) {
+            free(line);
+            break;
+        }
+
+        hdr = line;
+        val = strchr(line, ':');
+        if (!val)
+            /* Bogus header. */
+            continue;
+
+        *val++ = 0;
+        val += strspn(val, " ");
+
+        hdr_len = strlen(hdr);
+        val_len = strlen(val);
+
+        if (strcasecmp(hdr, "Status") == 0 && !http_resp_line) {
+            /* Have HTTP header. */
+            http_resp_line = malloc(10 + strlen(val));
+            strcpy(http_resp_line, "HTTP/1.1 ");
+            strcat(http_resp_line, val);
+        } else if (strcasecmp(hdr, "Location") == 0) {
+            /* Do something about this. */
+        } else {
+            /* Generic header, just save it. */
+            while (http_hdrs_len + hdr_len + val_len + 4 > http_hdrs_alloc)
+                http_hdrs = realloc(http_hdrs, http_hdrs_alloc *= 2);
+
+            strcpy(http_hdrs + http_hdrs_len, hdr);     http_hdrs_len += hdr_len;
+            strcpy(http_hdrs + http_hdrs_len, ": ");    http_hdrs_len += 2;
+            strcpy(http_hdrs + http_hdrs_len, val);     http_hdrs_len += val_len;
+            strcpy(http_hdrs + http_hdrs_len, "\r\n");  http_hdrs_len += 2;
+        }
+
+        free(line);
+    } while (line = get_line_from_stream(fp));
+
+    if (ferror(fp)) {
+        free(http_hdrs);
+        if (http_resp_line)
+            free(http_resp_line);
+        return 0;
+    }
+
+    if (!http_resp_line)
+        http_resp_line = strdup("HTTP/1.1 200 OK");
+
+    data = mem_alloc(data_alloc = 1024);
+    while ((c = getc(fp)) != EOF) {
+        data[data_len++] = (unsigned char)c;
+        if (data_len == data_alloc)
+            data = mem_realloc(data, data_alloc *= 2);
+    }
+
+    if (ferror(fp)) {
+        free(http_hdrs);
+        free(http_resp_line);
+        mem_free(data);
+        return 0;
+    }
+
+    /* OK, now have header and data. Save in cache object. */
+    e->head = mem_alloc(strlen(http_resp_line) + 2 + http_hdrs_len + 1);
+    strcpy(e->head, http_resp_line);
+    strcat(e->head, "\r\n");
+    strcat(e->head, http_hdrs);
+
+    add_fragment(e, 0, data, data_len); /* copies data, apparently */
+    truncate_entry(e, data_len, 1);
+
+    mem_free(data);
+
+    free(http_resp_line);
+    free(http_hdrs);
+
+    return 1;
+}
+
+/* Lazy. All done with temporary files.... */
+int run_cgi_script(struct cache_entry *e, unsigned char *script, unsigned char *query, unsigned char *post_ct, unsigned char *post_data, size_t post_len) {
+    pid_t scriptpid;
+    FILE *input = NULL, *output = NULL;
+    int ret = 0;
+
+    if (post_data) {
+        input = tmpfile();
+        fwrite(post_data, 1, post_len, input);
+        fflush(input);
+        fseek(input, 0, SEEK_SET);
+    }
+
+    output = tmpfile();
+
+    scriptpid = fork();
+    if (scriptpid == -1) {
+        if (input)
+            fclose(input);
+        fclose(output);
+        return 0;
+    } else if (scriptpid == 0) {
+        unsigned char *sn;
+        char **argv[] = {NULL, NULL};
+
+        /* Never call stdio stuff on input/output no more.... */
+        close(0);
+        close(1);
+        if (input)
+            dup2(fileno(input), 0);
+        dup2(fileno(output), 1);
+
+        /* Environment variables for the script. */
+        putenv("GATEWAY_INTERFACE=CGI/1.1");
+        sn = malloc(strlen(script) + sizeof("SCRIPT_NAME=lynxcgi:"));
+        sprintf(sn, "SCRIPT_NAME=lynxcgi:%s", script);
+        if (query) {
+            unsigned char *qs;
+            qs = malloc(strlen(query) + sizeof("QUERY_STRING="));
+            sprintf(qs, "QUERY_STRING=%s", query);
+            putenv(qs);
+        }
+        putenv("REMOTE_ADDR=127.0.0.1");
+        putenv("REMOTE_HOST=localhost");
+        /* REMOTE_IDENT/REMOTE_USER? */
+        putenv("SERVER_NAME=localhost");
+        putenv("SERVER_PORT=0");
+        putenv("SERVER_PROTOCOL=HTTP/1.1"); /* bogus */
+        putenv("SERVER_SOFTWARE=links-lynxcgi");
+
+        if (post_data) {
+            unsigned char *ct, *cl;
+            ct = malloc(strlen(post_ct) + sizeof("CONTENT_TYPE="));
+            sprintf(ct, "CONTENT_TYPE=%s", post_ct);
+            putenv(ct);
+            cl = malloc(16 + sizeof("CONTENT_LENGTH"));
+            sprintf(cl, "CONTENT_LENGTH=%d", post_len);
+            putenv(cl);
+        } else
+            putenv("REQUEST_METHOD=GET");
+
+        /* Have a go at execing the script.... */
+        execl(script, script, NULL);
+
+        /* Oops, well, that didn't work. But hey! we have a protocol for
+         * dealing with that! ... but sadly links isn't very good with
+         * error messages. Oh well. */
+        printf("Content-Type: text/plain\nStatus: 500 script error; %s: %s\n\nScript error: %s: %s\n\n", script, strerror(errno), script, strerror(errno));
+
+        _exit(255);
+    } else {
+        /* Wait for script to complete. */
+        int status;
+        void (*oldsigchld)(int);
+
+        /* Hack. We switch off the main SIGCHLD signal handler until our child
+         * process completes. */
+        oldsigchld = signal(SIGCHLD, SIG_DFL);
+
+        while (waitpid(scriptpid, &status, 0) == -1 && errno == EINTR);
+            /* XXX need timeout here. */
+
+        signal(SIGCHLD, oldsigchld);
+
+        if (!WIFEXITED(status)) {
+            /* Something bad happened. */
+        } else {
+            /* OK, parse script output. */
+            ret = parse_cgi_response_from_stream(e, output);
+        }
+    }
+
+    fclose(output);
+
+    return ret;
+}
+
+void lynxcgi_func(struct connection *c) {
+    unsigned char *script = NULL, *query, *post_ct = NULL, *post_data = NULL, *p;
+    size_t post_len;
+    struct cache_entry *e;
+
+    if (anonymous || strlen(c->url) < 9 || c->url[8] != '/') {
+        setcstate(c, S_BAD_URL);
+        abort_connection(c);
+        return;
+    }
+
+    /* Obtain name of script and query. */
+    script = strdup(c->url + 8);
+
+    if ((p = strchr(script, POST_CHAR))) {
+        /* This is mindlessly ugly. POST data is appended to the URL after
+         * an occurence of POST_CHAR. The sentinel is followed by the
+         * content-type of the data, then a \n, then the data itself encoded
+         * in hex. Gag me with a spoon. */
+        *p = 0;
+        post_ct = ++p;
+        p = strchr(p, '\n');
+
+        if (!p) {
+            setcstate(c, S_BAD_URL);
+            goto finish;
+        }
+        *p++ = 0;
+
+        post_data = p;
+        post_len = 0;
+        while (p[0] && p[1]) {
+            int h1, h2;
+            /* from http.c */
+            h1 = p[0] <= '9' ? p[0] - '0' : p[0] >= 'A' ? upcase(p[0]) - 'A' + 10 : 0;
+            if (h1 < 0 || h1 >= 16) h1 = 0;
+            h2 = p[1] <= '9' ? p[1] - '0' : p[1] >= 'A' ? upcase(p[1]) - 'A' + 10 : 0;
+            if (h2 < 0 || h2 >= 16) h2 = 0;
+            post_data[post_len++] = h1 * 16 + h2;
+            p += 2;
+        }
+        post_data[post_len] = 0;
+    }
+
+    /* Extract query if present. */
+    query = strchr(script, '?');
+    if (query)
+        *query++ = 0;
+
+    /* OK, now we need to fork and exec the CGI script. */
+    get_cache_entry(c->url, &e);
+    if (e->head)
+        mem_free(e->head);
+
+    if (run_cgi_script(e, script, query, post_ct, post_data, post_len)) {
+        c->cache = e;
+        c->cache->incomplete = 0;
+        setcstate(c, S_OK);
+    } else
+        setcstate(c, S_FILE_ERROR); /* close enough */
+
+
+finish:
+    if (script)
+        free(script);
+    abort_connection(c);
+}
diff -urN links-2.1pre7.orig/test.html links-2.1pre7/test.html
--- links-2.1pre7.orig/test.html        Thu Jan  1 01:00:00 1970
+++ links-2.1pre7/test.html     Tue Feb  4 21:19:46 2003
@@ -0,0 +1,4 @@
+<form method="post" action="lynxcgi:/tmp/testcgi">
+<input type="text" name="fish">
+<input type="submit">
+</form>
diff -urN links-2.1pre7.orig/url.c links-2.1pre7/url.c
--- links-2.1pre7.orig/url.c    Mon Jun 17 14:25:42 2002
+++ links-2.1pre7/url.c Tue Feb  4 19:53:49 2003
@@ -26,6 +26,7 @@
#ifdef JS
               {"javascript", 0, NULL, javascript_func, 1, 0, 0},
#endif
+                {"lynxcgi", 0, lynxcgi_func, NULL, 1, 0, 0},
               {NULL, 0, NULL}
};