From f4979cb5a45e80d154350e7b13579fab0cba2cfe Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Mon, 16 May 2022 22:01:41 +0200 Subject: [PATCH] [dgi] Beginning. Not compilable code --- configure.ac | 3 + meson.build | 1 + meson_options.txt | 2 + src/protocol/file/Makefile | 1 + src/protocol/file/dgi.c | 243 ++++++++++++++++++++++++++++++++++ src/protocol/file/dgi.h | 19 +++ src/protocol/file/meson.build | 3 + 7 files changed, 272 insertions(+) create mode 100644 src/protocol/file/dgi.c create mode 100644 src/protocol/file/dgi.h diff --git a/configure.ac b/configure.ac index ecc70051..d9b7032f 100644 --- a/configure.ac +++ b/configure.ac @@ -1478,6 +1478,9 @@ EL_ARG_ENABLE(CONFIG_URI_REWRITE, uri-rewrite, [URI rewriting], EL_ARG_DEPEND(CONFIG_CGI, cgi, [HAVE_SETENV_OR_PUTENV:yes], [Local CGI], [ --enable-cgi enable local CGI support]) +EL_ARG_ENABLE(CONFIG_DGI, dgi, [DOS Gateway Interface], + [ --enable-dgi enable DGI support]) + EL_ARG_ENABLE(CONFIG_FINGER, finger, [Finger protocol], [ --enable-finger enable finger protocol support]) diff --git a/meson.build b/meson.build index 068a915d..39939ce9 100644 --- a/meson.build +++ b/meson.build @@ -31,6 +31,7 @@ conf_data.set('CONFIG_GEMINI', get_option('gemini')) conf_data.set('CONFIG_URI_REWRITE', get_option('uri-rewrite')) conf_data.set('CONFIG_CGI', get_option('cgi')) +conf_data.set('CONFIG_DGI', get_option('dgi')) conf_data.set('CONFIG_FINGER', get_option('finger')) conf_data.set('CONFIG_FSP', get_option('fsp')) conf_data.set('CONFIG_FTP', get_option('ftp')) diff --git a/meson_options.txt b/meson_options.txt index c6ee87ee..334f0a66 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -68,3 +68,5 @@ option('static', type: 'boolean', value: false, description: 'link static binary option('reproducible', type: 'boolean', value: false, description: 'reproducible build') option('source-date-epoch', type: 'string', value: '', description: 'source date epoch for reproducible builds') + +option('dgi', type: 'boolean', value: false, description: 'DOS Gateway Interface support') diff --git a/src/protocol/file/Makefile b/src/protocol/file/Makefile index 99e51b9a..88292235 100644 --- a/src/protocol/file/Makefile +++ b/src/protocol/file/Makefile @@ -2,6 +2,7 @@ top_builddir=../../.. include $(top_builddir)/Makefile.config OBJS-$(CONFIG_CGI) += cgi.o +OBJS-$(CONFIG_DGI) += dgi.o OBJS = file.o mailcap.o diff --git a/src/protocol/file/dgi.c b/src/protocol/file/dgi.c new file mode 100644 index 00000000..7dd7edd3 --- /dev/null +++ b/src/protocol/file/dgi.c @@ -0,0 +1,243 @@ +/* Internal "dgi" protocol implementation */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#ifdef HAVE_SYS_SOCKET_H +#include /* OS/2 needs this after sys/types.h */ +#endif +#include /* OS/2 needs this after sys/types.h */ +#ifdef HAVE_FCNTL_H +#include /* OS/2 needs this after sys/types.h */ +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "elinks.h" + +#include "config/options.h" +#include "cookies/cookies.h" +#include "intl/libintl.h" +#include "mime/backend/common.h" +#include "network/connection.h" +#include "network/progress.h" +#include "network/socket.h" +#include "osdep/osdep.h" +#include "osdep/sysname.h" +#include "osdep/types.h" +#include "protocol/common.h" +#include "protocol/file/dgi.h" +#include "protocol/http/http.h" +#include "protocol/uri.h" +#include "terminal/terminal.h" +#include "util/conv.h" +#include "util/env.h" +#include "util/string.h" + +static union option_info dgi_options[] = { + INIT_OPT_TREE("protocol.file", N_("DGI"), + "dgi", OPT_ZERO, + N_("Dos gateway interface specific options.")), + + NULL_OPTION_INFO, +}; + +struct dgi_entry { + const char *name; + const char *cmdline; +}; + +struct dgi_entry *entries[] = { + { "cdplayer.dgi", "cdplayer.exe $q" }, + NULL +}; + +struct module dgi_protocol_module = struct_module( + /* name: */ N_("Dos Gateway Interface (DGI)"), + /* options: */ dgi_options, + /* hooks: */ NULL, + /* submodules: */ NULL, + /* data: */ NULL, + /* init: */ NULL, + /* done: */ NULL +); + +static struct dgi_entry * +find_dgi(const char *name) +{ + if (!strcmp(name, "cdplayer.dgi")) { + return entries[0]; + } + + return NULL; +} + +static void +write_request_to_file(struct connection *conn, const char *filename) +{ + if (!conn->uri->post) { + return; + } + FILE *f = fopen(filename, "wb"); + + if (f) { + char *post = conn->uri->post; + char *postend = strchr(post, '\n'); + if (postend) { + post = postend + 1; + } + struct http_connection_info *http = (struct http_connection_info *)conn->info; + fwrite(post, 1, http->post.total_upload_length, f); + fclose(f); + } +} + +enum dgi_state { + NORMAL, + DOLAR +}; + +static void +prepare_command(struct dgi_entry *entry, struct string *cmd, char **temp, char **out) +{ + const char *ch; + dgi_state state = NORMAL; + + for (ch = entry->cmdline; *ch; ch++) { + switch (state) { + NORMAL: + default: + if (*ch == '$') { + state = DOLAR; + } else { + add_char_to_string(cmd, *ch); + } + break; + case DOLAR: + switch(*ch) { + case 'q': + add_to_string(cmd, post); + state = NORMAL; + case 't': + *temp = tempnam(); + state = NORMAL; + break; + case 'o': + *out = tempnam(); + state = NORMAL; + break; + default: + add_to_string(cmd, *ch); + break; + } + break; + } + } +} + +int +execute_dgi(struct connection *conn) +{ + char *script; + struct dgi_entry *entry; + struct string command; + char *tempfilename = NULL; + char *outputfilename = NULL; + struct connection_state state = connection_state(S_OK); + + /* Not file referrer */ + if (conn->referrer && conn->referrer->protocol != PROTOCOL_FILE) { + return 1; + } + + script = get_uri_string(conn->uri, URI_PATH); + if (!script) { + state = connection_state(S_OUT_OF_MEM); + abort_connection(conn, state); + return 0; + } + + entry = find_dgi(script); + if (!entry) { + mem_free(script); + return 0; + } + + if (!init_string(&command)) { + mem_free(script); + return 0; + } + + prepare_command(entry, &command, &tempfilename, &outputfilename); + + if (tempfilename) { + write_request_to_file(conn, tempfilename); + } + + system(command.source); + done_string(&command); + mem_free(script); + + if (tempfilename) { + unlink(tempfilename); + } + + if (!outputfilename) { + return 0; + } + + struct string page; + struct string name; + + if (!init_string(&name)) { + unlink(outputfilename); + return 0; + } + add_to_string(&name, outputfilename); + state = read_encoded_file(&name, &page); + unlink(outputfilename); + done_string(&name); + + if (is_in_state(state, S_OK)) { + struct cache_entry *cached; + + /* Try to add fragment data to the connection cache if either + * file reading or directory listing worked out ok. */ + cached = conn->cached = get_cache_entry(conn->uri); + if (!conn->cached) { + state = connection_state(S_OUT_OF_MEM); + } else { + add_fragment(cached, 0, page.source, page.length); + conn->from += page.length; + + if (1) { + char *head; + + /* If the system charset somehow + * changes after the directory listing + * has been generated, it should be + * parsed with the original charset. */ + head = straconcat("\r\nContent-Type: text/html; charset=", + get_cp_mime_name(get_cp_index("System")), + "\r\n", (char *) NULL); + + /* Not so gracefully handle failed memory + * allocation. */ + if (!head) + state = connection_state(S_OUT_OF_MEM); + + /* Setup directory listing for viewing. */ + mem_free_set(&cached->head, head); + } + done_string(&page); + } + } + abort_connection(conn, state); + return 0; +} diff --git a/src/protocol/file/dgi.h b/src/protocol/file/dgi.h new file mode 100644 index 00000000..fedbba91 --- /dev/null +++ b/src/protocol/file/dgi.h @@ -0,0 +1,19 @@ + +#ifndef EL__PROTOCOL_FILE_DGI_H +#define EL__PROTOCOL_FILE_DGI_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct connection; +struct module; + +extern struct module dgi_protocol_module; +int execute_dgi(struct connection *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/protocol/file/meson.build b/src/protocol/file/meson.build index 8fdf0054..5063594d 100644 --- a/src/protocol/file/meson.build +++ b/src/protocol/file/meson.build @@ -1,4 +1,7 @@ if conf_data.get('CONFIG_CGI') srcs += files('cgi.c') endif +if conf_data.get('CONFIG_DGI') + srcs += files('dgi.c') +endif srcs += files('file.c', 'mailcap.c')