From 9258996b4ff1b3293023192594dea22de09514c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Mon, 17 Aug 2020 22:32:36 +0200 Subject: [PATCH] initial commit --- .gitignore | 1 + Cargo.lock | 21 + Cargo.toml | 11 + a.out | Bin 0 -> 32256 bytes cgo.c | 854 ++++++++++++++++++++++ cgo.rs | 1417 +++++++++++++++++++++++++++++++++++ compile_commands.json | 11 + src/main.rs | 1625 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 3940 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100755 a.out create mode 100644 cgo.c create mode 100644 cgo.rs create mode 100644 compile_commands.json create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..003063d --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,21 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10" + +[[package]] +name = "rgp" +version = "0.1.0" +dependencies = [ + "lazy_static", + "libc", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..0ead06e --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rgp" +version = "0.1.0" +authors = ["Lukáš Hozda "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +libc = "*" +lazy_static = "1.4.0" diff --git a/a.out b/a.out new file mode 100755 index 0000000000000000000000000000000000000000..e6032f716655b7e2334e948734c0ad63c5058589 GIT binary patch literal 32256 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 literal 0 HcmV?d00001 diff --git a/cgo.c b/cgo.c new file mode 100644 index 0000000..89d2470 --- /dev/null +++ b/cgo.c @@ -0,0 +1,854 @@ +/* + * cgo - a simple terminal based gopher client + * Copyright (c) 2019 Sebastian Steinhauer + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* some "configuration" */ +#define START_URI "gopher://gopher.floodgap.com:70" +#define CMD_TEXT "less" +#define CMD_IMAGE "display" +#define CMD_BROWSER "firefox" +#define CMD_PLAYER "mplayer" +#define CMD_TELNET "telnet" +#define COLOR_PROMPT "1;34" +#define COLOR_SELECTOR "1;32" +#define HEAD_CHECK_LEN 5 +#define GLOBAL_CONFIG_FILE "/etc/cgorc" +#define LOCAL_CONFIG_FILE "/.cgorc" +#define NUM_BOOKMARKS 20 +#define VERBOSE "true" + +/* some internal defines */ +#define KEY_RANGE (('z' - 'a') + 1) + +/* structs */ +typedef struct link_s link_t; +struct link_s { + link_t *next; + char which; + short key; + char *host; + char *port; + char *selector; +}; + +typedef struct config_s config_t; +struct config_s { + char start_uri[512]; + char cmd_text[512]; + char cmd_image[512]; + char cmd_browser[512]; + char cmd_player[512]; + char color_prompt[512]; + char color_selector[512]; + char verbose[512]; +}; + +char tmpfilename[256]; +link_t *links = NULL; +link_t *history = NULL; +int link_key; +char current_host[512], current_port[64], current_selector[1024]; +char parsed_host[512], parsed_port[64], parsed_selector[1024]; +char bookmarks[NUM_BOOKMARKS][512]; +config_t config; + +/* function prototypes */ +int parse_uri(const char *uri); + +/* implementation */ +void usage() +{ + fputs("usage: cgo [-v] [-H] [gopher URI]\n", + stderr); + exit(EXIT_SUCCESS); +} + +void banner(FILE *f) +{ + fputs("cgo 0.6.1 Copyright (c) 2020 Sebastian Steinhauer\n", f); +} + +int check_option_true(const char *option) +{ + return strcasecmp(option, "false") && strcasecmp(option, "off"); +} + +void parse_config_line(const char *line) +{ + char token[1024]; + char bkey[128]; + char *value = NULL; + int i, j; + + while (*line == ' ' || *line == '\t') line++; + for (i = 0; *line && *line != ' ' && *line != '\t'; line++) + if (i < sizeof(token) - 1) token[i++] = *line; + token[i] = 0; + + if (! strcmp(token, "start_uri")) value = &config.start_uri[0]; + else if (! strcmp(token, "cmd_text")) value = &config.cmd_text[0]; + else if (! strcmp(token, "cmd_browser")) value = &config.cmd_browser[0]; + else if (! strcmp(token, "cmd_image")) value = &config.cmd_image[0]; + else if (! strcmp(token, "cmd_player")) value = &config.cmd_player[0]; + else if (! strcmp(token, "color_prompt")) value = &config.color_prompt[0]; + else if (! strcmp(token, "color_selector")) value = &config.color_selector[0]; + else if (! strcmp(token, "verbose")) value = &config.verbose[0]; + else { + for (j = 0; j < NUM_BOOKMARKS; j++) { + snprintf(bkey, sizeof(bkey), "bookmark%d", j+1); + if (! strcmp(token, bkey)) { + value = &bookmarks[j][0]; + break; + } + } + if (! value) return; + }; + + while (*line == ' ' || *line == '\t') line++; + for (i = 0; *line; line++) + if (i < 512-1) value[i++] = *line; + for (i--; i > 0 && (value[i] == ' ' || value[i] == '\t'); i--) ; + value[++i] = 0; + +} + +void load_config(const char *filename) +{ + FILE *fp; + int ch, i; + char line[1024]; + + fp = fopen(filename, "r"); + if (! fp) return; + + memset(line, 0, sizeof(line)); + i = 0; + ch = fgetc(fp); + while (1) { + switch (ch) { + case '#': + while (ch != '\n' && ch != -1) + ch = fgetc(fp); + break; + case -1: + parse_config_line(line); + fclose(fp); + return; + case '\r': + ch = fgetc(fp); + break; + case '\n': + parse_config_line(line); + memset(line, 0, sizeof(line)); + i = 0; + ch = fgetc(fp); + break; + default: + if (i < sizeof(line) - 1) + line[i++] = ch; + ch = fgetc(fp); + break; + } + } +} + +void init_config() +{ + char filename[1024]; + const char *home; + int i; + + /* copy defaults */ + snprintf(config.start_uri, sizeof(config.start_uri), START_URI); + snprintf(config.cmd_text, sizeof(config.cmd_text), "%s", CMD_TEXT); + snprintf(config.cmd_image, sizeof(config.cmd_image), "%s", CMD_IMAGE); + snprintf(config.cmd_browser, sizeof(config.cmd_browser), "%s", CMD_BROWSER); + snprintf(config.cmd_player, sizeof(config.cmd_player), "%s", CMD_PLAYER); + snprintf(config.color_prompt, sizeof(config.color_prompt), "%s", COLOR_PROMPT); + snprintf(config.color_selector, sizeof(config.color_selector), "%s", COLOR_SELECTOR); + snprintf(config.verbose, sizeof(config.verbose), "%s", VERBOSE); + for (i = 0; i < NUM_BOOKMARKS; i++) bookmarks[i][0] = 0; + /* read configs */ + load_config(GLOBAL_CONFIG_FILE); + home = getenv("HOME"); + if (home) { + snprintf(filename, sizeof(filename), "%s%s", home, LOCAL_CONFIG_FILE); + load_config(filename); + } +} + +int dial(const char *host, const char *port, const char *selector) +{ + struct addrinfo hints; + struct addrinfo *res, *r; + int srv = -1, l; + char request[512]; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + if (getaddrinfo(host, port, &hints, &res) != 0) { + fprintf(stderr, "error: cannot resolve hostname '%s:%s': %s\n", + host, port, strerror(errno)); + return -1; + } + for (r = res; r; r = r->ai_next) { + srv = socket(r->ai_family, r->ai_socktype, r->ai_protocol); + if (srv == -1) + continue; + if (connect(srv, r->ai_addr, r->ai_addrlen) == 0) + break; + close(srv); + } + freeaddrinfo(res); + if (! r) { + fprintf(stderr, "error: cannot connect to host '%s:%s'\n", + host, port); + return -1; + } + snprintf(request, sizeof(request), "%s\r\n", selector); + l = strlen(request); + if (write(srv, request, l) != l) { + fprintf(stderr, "error: cannot complete request\n"); + close(srv); + return -1; + } + return srv; +} + +int read_line(int fd, char *buf, size_t buf_len) +{ + size_t i = 0; + char c = 0; + + do { + if (read(fd, &c, sizeof(char)) != sizeof(char)) + return 0; + if (c != '\r') + buf[i++] = c; + } while (c != '\n' && i < buf_len); + buf[i - 1] = '\0'; + return 1; +} + +int download_file(const char *host, const char *port, + const char *selector, int fd) +{ + int srvfd, len; + unsigned long total = 0; + char buffer[4096]; + + if (check_option_true(config.verbose)) + printf("downloading [%s]...\r", selector); + srvfd = dial(host, port, selector); + if (srvfd == -1) { + printf("\033[2Kerror: downloading [%s] failed\n", selector); + close(fd); + return 0; + } + while ((len = read(srvfd, buffer, sizeof(buffer))) > 0) { + write(fd, buffer, len); + total += len; + if (check_option_true(config.verbose)) + printf("downloading [%s] (%ld kb)...\r", selector, total / 1024); + } + close(fd); + close(srvfd); + if (check_option_true(config.verbose)) + printf("\033[2Kdownloading [%s] complete\n", selector); + return 1; +} + +int download_temp(const char *host, const char *port, const char *selector) +{ + int tmpfd; + +#if defined(__OpenBSD__) + strlcpy(tmpfilename, "/tmp/cgoXXXXXX", sizeof(tmpfilename)); +#else + strcpy(tmpfilename, "/tmp/cgoXXXXXX"); +#endif + tmpfd = mkstemp(tmpfilename); + if (tmpfd == -1) { + fputs("error: unable to create tmp file\n", stderr); + return 0; + } + if (! download_file(host, port, selector, tmpfd)) { + unlink(tmpfilename); + return 0; + } + return 1; +} + +int make_key(char c1, char c2, char c3) +{ + if (! c1 || ! c2) + return -1; + + if (! c3) + return ((c1 - 'a') * KEY_RANGE) + (c2 - 'a'); + else + return (((c1 - 'a' + 1) * KEY_RANGE * KEY_RANGE) + ((c2 - 'a') * KEY_RANGE) + (c3 - 'a')); +} + +void make_key_str(int key, char *c1, char *c2, char *c3) { + if (key < (KEY_RANGE * KEY_RANGE)) { + *c1 = 'a' + (key / KEY_RANGE); + *c2 = 'a' + (key % KEY_RANGE); + *c3 = 0; + } else { + *c1 = 'a' + (key / (KEY_RANGE * KEY_RANGE)) - 1; + *c2 = 'a' + ((key / KEY_RANGE) % KEY_RANGE); + *c3 = 'a' + (key % KEY_RANGE); + } +} + +void add_link(char which, const char *name, + const char *host, const char *port, const char *selector) +{ + link_t *link; + char a = 0, b = 0, c = 0; + + if (! host || ! port || ! selector) + return; /* ignore incomplete selectors */ + link = calloc(1, sizeof(link_t)); + link->which = which; + link->key = link_key; + link->host = strdup(host); + link->port = strdup(port); + link->selector = strdup(selector); + if (! links) + link->next = NULL; + else + link->next = links; + links = link; + + make_key_str(link_key++, &a, &b, &c); + printf("\033[%sm%c%c%c\033[0m \033[1m%s\033[0m\n", + config.color_selector, a, b, c, name); +} + +void clear_links() +{ + link_t *link, *next; + + for (link = links; link; ) { + next = link->next; + free(link->host); + free(link->port); + free(link->selector); + free(link); + link = next; + } + links = NULL; + link_key = 0; +} + +void add_history() +{ + link_t *link; + + link = calloc(1, sizeof(link_t)); + link->host = strdup(current_host); + link->port = strdup(current_port); + link->selector = strdup(current_selector); + link->which = 0; /* not needed for history...just clear them */ + link->key = 0; + if (! history) + link->next = NULL; + else + link->next = history; + history = link; +} + +void handle_directory_line(char *line) +{ + int i; + char *lp, *last, *fields[4]; + + /* tokenize */ + for (i = 0; i < 4; i++) + fields[i] = NULL; + last = &line[1]; + for (lp = last, i = 0; i < 4; lp++) { + if (*lp == '\t' || *lp == '\0') { + fields[i] = last; + last = lp + 1; + if (*lp == '\0') + break; + *lp = '\0'; + i++; + } + } + /* determine listing type */ + switch (line[0]) { + case 'i': + case '3': + printf(" %s\n", fields[0]); + break; + case '.': /* some gopher servers use this */ + puts(""); + break; + case '0': + case '1': + case '5': + case '7': + case '8': + case '9': + case 'g': + case 'I': + case 'p': + case 'h': + case 's': + add_link(line[0], fields[0], fields[2], fields[3], fields[1]); + break; + default: + printf("miss [%c]: %s\n", line[0], fields[0]); + break; + } +} + +int is_valid_directory_entry(const char *line) +{ + switch (line[0]) { + case 'i': + case '3': + case '.': /* some gopher servers use this */ + case '0': + case '1': + case '5': + case '7': + case '8': + case '9': + case 'g': + case 'I': + case 'p': + case 'h': + case 's': + return 1; + default: + return 0; + } +} + +void view_directory(const char *host, const char *port, + const char *selector, int make_current) +{ + int is_dir; + int srvfd, i, head_read; + char line[1024]; + char head[HEAD_CHECK_LEN][1024]; + + srvfd = dial(host, port, selector); + if (srvfd != -1) { /* only adapt current prompt when successful */ + /* make history entry */ + if (make_current) + add_history(); + /* don't overwrite the current_* things... */ + if (host != current_host) + snprintf(current_host, sizeof(current_host), "%s", host); + if (port != current_port) + snprintf(current_port, sizeof(current_port), "%s", port); + if (selector != current_selector) + snprintf(current_selector, sizeof(current_selector), + "%s", selector); + } + clear_links(); /* clear links *AFTER* dialing out!! */ + if (srvfd == -1) + return; /* quit if not successful */ + head_read = 0; + is_dir = 1; + while (head_read < HEAD_CHECK_LEN && read_line(srvfd, line, sizeof(line))) { + strcpy(head[head_read], line); + if (!is_valid_directory_entry(head[head_read])) { + is_dir = 0; + break; + } + head_read++; + } + if (!is_dir) { + puts("error: Not a directory."); + close(srvfd); + return; + } + for (i = 0; i < head_read; i++) { + handle_directory_line(head[i]); + } + while (read_line(srvfd, line, sizeof(line))) { + handle_directory_line(line); + } + close(srvfd); +} + +void view_file(const char *cmd, const char *host, + const char *port, const char *selector) +{ + pid_t pid; + int status, i, j; + char buffer[1024], *argv[32], *p; + + if (check_option_true(config.verbose)) + printf("h(%s) p(%s) s(%s)\n", host, port, selector); + + if (! download_temp(host, port, selector)) + return; + + /* parsed command line string */ + argv[0] = &buffer[0]; + for (p = (char*) cmd, i = 0, j = 1; *p && i < sizeof(buffer) - 1 && j < 30; ) { + if (*p == ' ' || *p == '\t') { + buffer[i++] = 0; + argv[j++] = &buffer[i]; + while (*p == ' ' || *p == '\t') p++; + } else buffer[i++] = *p++; + } + buffer[i] = 0; + argv[j++] = tmpfilename; + argv[j] = NULL; + + /* fork and execute */ + if (check_option_true(config.verbose)) + printf("executing: %s %s\n", cmd, tmpfilename); + pid = fork(); + if (pid == 0) { + if (execvp(argv[0], argv) == -1) + puts("error: execvp() failed!"); + } else if (pid == -1) puts("error: fork() failed"); + sleep(1); /* to wait for browsers etc. that return immediatly */ + waitpid(pid, &status, 0); + unlink(tmpfilename); +} + +void view_telnet(const char *host, const char *port) +{ + pid_t pid; + int status; + + printf("executing: %s %s %s\n", CMD_TELNET, host, port); + pid = fork(); + if (pid == 0) { + if (execlp(CMD_TELNET, CMD_TELNET, host, port, NULL) == -1) + puts("error: execlp() failed!"); + } else if (pid == -1) puts("error: fork() failed!"); + waitpid(pid, &status, 0); + puts("(done)"); +} + +void view_download(const char *host, const char *port, const char *selector) +{ + int fd; + char filename[1024], line[1024]; + + snprintf(filename, sizeof(filename), "%s", strrchr(selector, '/') + 1); + printf("enter filename for download [%s]: ", filename); + fflush(stdout); + if (! read_line(0, line, sizeof(line))) { + puts("download aborted"); + return; + } + if (strlen(line) > 0) +#if defined(__OpenBSD__) + strlcpy(filename, line, sizeof(filename)); +#else + strcpy(filename, line); +#endif + fd = open(filename, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); + if (fd == -1) { + printf("error: unable to create file [%s]: %s\n", + filename, strerror(errno)); + return; + } + if (! download_file(host, port, selector, fd)) { + printf("error: unable to download [%s]\n", selector); + unlink(filename); + return; + } +} + +void view_search(const char *host, const char *port, const char *selector) +{ + char search_selector[1024]; + char line[1024]; + + printf("enter search string: "); + fflush(stdout); + if (! read_line(0, line, sizeof(line))) { + puts("search aborted"); + return; + } + snprintf(search_selector, sizeof(search_selector), "%s\t%s", + selector, line); + view_directory(host, port, search_selector, 1); +} + +void view_history(int key) +{ + int history_key = 0; + char a, b, c; + link_t *link; + + if (! history) { + puts("(empty history)"); + return; + } + if ( key < 0 ) { + puts("(history)"); + for ( link = history; link; link = link->next ) { + make_key_str(history_key++, &a, &b, &c); + printf("\033[%sm%c%c%c\033[0m \033[1m%s:%s/1%s\033[0m\n", + COLOR_SELECTOR, a, b, c, link->host, link->port, link->selector); + } + } else { + /* traverse history list */ + for ( link = history; link; link = link->next, ++history_key ) { + if ( history_key == key ) { + view_directory(link->host, link->port, link->selector, 0); + return; + } + } + puts("history item not found"); + } +} + +void view_bookmarks(int key) +{ + int i; + char a, b, c; + + if (key < 0) { + puts("(bookmarks)"); + for (i = 0; i < NUM_BOOKMARKS; i++) { + if (bookmarks[i][0]) { + make_key_str(i, &a, &b, &c); + printf("\033[%sm%c%c%c\033[0m \033[1m%s\033[0m\n", + COLOR_SELECTOR, a, b, c, &bookmarks[i][0]); + } + } + } else { + for (i = 0; i < NUM_BOOKMARKS; i++) { + if (bookmarks[i][0] && i == key) { + if (parse_uri(&bookmarks[i][0])) view_directory(parsed_host, parsed_port, parsed_selector, 0); + else printf("invalid gopher URI: %s", &bookmarks[i][0]); + return; + } + } + } +} + +void pop_history() +{ + link_t *next; + + if (! history) { + puts("(empty history)"); + return; + } + /* reload page from history (and don't count as history) */ + view_directory(history->host, history->port, history->selector, 0); + /* history is history... :) */ + next = history->next; + free(history->host); + free(history->port); + free(history->selector); + free(history); + history = next; +} + +int follow_link(int key) +{ + link_t *link; + + for (link = links; link; link = link->next) { + if (link->key != key) + continue; + switch (link->which) { + case '0': + view_file(&config.cmd_text[0], link->host, link->port, link->selector); + break; + case '1': + view_directory(link->host, link->port, link->selector, 1); + break; + case '7': + view_search(link->host, link->port, link->selector); + break; + case '5': + case '9': + view_download(link->host, link->port, link->selector); + break; + case '8': + view_telnet(link->host, link->port); + break; + case 'g': + case 'I': + case 'p': + view_file(&config.cmd_image[0], link->host, link->port, link->selector); + break; + case 'h': + view_file(&config.cmd_browser[0], link->host, link->port, link->selector); + break; + case 's': + view_file(&config.cmd_player[0], link->host, link->port, link->selector); + break; + default: + printf("missing handler [%c]\n", link->which); + break; + } + return 1; /* return the array is broken after view! */ + } + return 0; +} + +void download_link(int key) +{ + link_t *link; + + for (link = links; link; link = link->next) { + if (link->key != key) + continue; + view_download(link->host, link->port, link->selector); + return; + } + puts("link not found"); +} + +int parse_uri(const char *uri) +{ + int i; + + /* strip gopher:// */ + if (! strncmp(uri, "gopher://", 9)) + uri += 9; + /* parse host */ + for (i = 0; *uri && *uri != ':' && *uri != '/'; uri++) { + if (*uri != ' ' && i < sizeof(parsed_host) - 1) + parsed_host[i++] = *uri; + } + if (i > 0) parsed_host[i] = 0; + else return 0; + /* parse port */ + if (*uri == ':') { + uri++; + for (i = 0; *uri && *uri != '/'; uri++) + if (*uri != ' ' && i < sizeof(parsed_port) - 1) + parsed_port[i++] = *uri; + parsed_port[i] = 0; + } else snprintf(parsed_port, sizeof(parsed_port), "%d", 70); + /* parse selector (ignore slash and selector type) */ + if (*uri) ++uri; + if (*uri) ++uri; + for (i = 0; *uri && i < sizeof(parsed_selector) - 1; ++uri, ++i) + parsed_selector[i] = *uri; + parsed_selector[i] = '\0'; + + return 1; +} + +int main(int argc, char *argv[]) +{ + int i; + char line[1024], *uri; + + /* copy defaults */ + init_config(); + uri = &config.start_uri[0]; + + /* parse command line */ + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-') switch(argv[i][1]) { + case 'H': + usage(); + break; + case 'v': + banner(stdout); + exit(EXIT_SUCCESS); + default: + usage(); + } else { + uri = argv[i]; + } + } + + /* parse uri */ + if (! parse_uri(uri)) { + banner(stderr); + fprintf(stderr, "invalid gopher URI: %s", argv[i]); + exit(EXIT_FAILURE); + } + + /* main loop */ + view_directory(parsed_host, parsed_port, parsed_selector, 0); + for (;;) { + printf("\033[%sm%s:%s%s\033[0m ", config.color_prompt, + current_host, current_port, current_selector); + fflush(stdout); /* to display the prompt */ + if (! read_line(0, line, sizeof(line))) { + puts("QUIT"); + return EXIT_SUCCESS; + } + i = strlen(line); + switch (line[0]) { + case '?': + puts( + "? - help\n" + "* - reload directory\n" + "< - go back in history\n" + ".[LINK] - download the given link\n" + "H - show history\n" + "H[LINK] - jump to the specified history item\n" + "G[URI] - jump to the given gopher URI\n" + "B - show bookmarks\n" + "B[LINK] - jump to the specified bookmark item\n" + "C^d - quit"); + break; + case '<': + pop_history(); + break; + case '*': + view_directory(current_host, current_port, + current_selector, 0); + break; + case '.': + download_link(make_key(line[1], line[2], line[3])); + break; + case 'H': + if (i == 1 || i == 3 || i == 4) view_history(make_key(line[1], line[2], line[3])); + break; + case 'G': + if (parse_uri(&line[1])) view_directory(parsed_host, parsed_port, parsed_selector, 1); + else puts("invalid gopher URI"); + break; + case 'B': + if (i == 1 || i == 3 || i == 4) view_bookmarks(make_key(line[1], line[2], line[3])); + break; + default: + follow_link(make_key(line[0], line[1], line[2])); + break; + } + } + return EXIT_SUCCESS; /* never get's here but stops cc complaining */ +} diff --git a/cgo.rs b/cgo.rs new file mode 100644 index 0000000..23f2b7a --- /dev/null +++ b/cgo.rs @@ -0,0 +1,1417 @@ +#![allow(dead_code, mutable_transmutes, non_camel_case_types, non_snake_case, + non_upper_case_globals, unused_assignments, unused_mut)] +#![register_tool(c2rust)] +#![feature(const_raw_ptr_to_usize_cast, extern_types, main, register_tool)] +extern "C" { + pub type _IO_wide_data; + pub type _IO_codecvt; + pub type _IO_marker; + #[no_mangle] + fn waitpid(__pid: __pid_t, __stat_loc: *mut libc::c_int, + __options: libc::c_int) -> __pid_t; + #[no_mangle] + fn socket(__domain: libc::c_int, __type: libc::c_int, + __protocol: libc::c_int) -> libc::c_int; + #[no_mangle] + fn connect(__fd: libc::c_int, __addr: *const sockaddr, __len: socklen_t) + -> libc::c_int; + #[no_mangle] + fn getaddrinfo(__name: *const libc::c_char, + __service: *const libc::c_char, __req: *const addrinfo, + __pai: *mut *mut addrinfo) -> libc::c_int; + #[no_mangle] + fn freeaddrinfo(__ai: *mut addrinfo); + #[no_mangle] + fn open(__file: *const libc::c_char, __oflag: libc::c_int, _: ...) + -> libc::c_int; + #[no_mangle] + fn close(__fd: libc::c_int) -> libc::c_int; + #[no_mangle] + fn read(__fd: libc::c_int, __buf: *mut libc::c_void, __nbytes: size_t) + -> ssize_t; + #[no_mangle] + fn write(__fd: libc::c_int, __buf: *const libc::c_void, __n: size_t) + -> ssize_t; + #[no_mangle] + fn sleep(__seconds: libc::c_uint) -> libc::c_uint; + #[no_mangle] + fn execvp(__file: *const libc::c_char, __argv: *const *mut libc::c_char) + -> libc::c_int; + #[no_mangle] + fn execlp(__file: *const libc::c_char, __arg: *const libc::c_char, _: ...) + -> libc::c_int; + #[no_mangle] + fn fork() -> __pid_t; + #[no_mangle] + fn unlink(__name: *const libc::c_char) -> libc::c_int; + #[no_mangle] + fn __errno_location() -> *mut libc::c_int; + #[no_mangle] + static mut stdout: *mut FILE; + #[no_mangle] + static mut stderr: *mut FILE; + #[no_mangle] + fn fclose(__stream: *mut FILE) -> libc::c_int; + #[no_mangle] + fn fflush(__stream: *mut FILE) -> libc::c_int; + #[no_mangle] + fn fopen(_: *const libc::c_char, _: *const libc::c_char) -> *mut FILE; + #[no_mangle] + fn fprintf(_: *mut FILE, _: *const libc::c_char, _: ...) -> libc::c_int; + #[no_mangle] + fn printf(_: *const libc::c_char, _: ...) -> libc::c_int; + #[no_mangle] + fn snprintf(_: *mut libc::c_char, _: libc::c_ulong, + _: *const libc::c_char, _: ...) -> libc::c_int; + #[no_mangle] + fn fgetc(__stream: *mut FILE) -> libc::c_int; + #[no_mangle] + fn fputs(__s: *const libc::c_char, __stream: *mut FILE) -> libc::c_int; + #[no_mangle] + fn puts(__s: *const libc::c_char) -> libc::c_int; + #[no_mangle] + fn calloc(_: libc::c_ulong, _: libc::c_ulong) -> *mut libc::c_void; + #[no_mangle] + fn free(__ptr: *mut libc::c_void); + #[no_mangle] + fn exit(_: libc::c_int) -> !; + #[no_mangle] + fn getenv(__name: *const libc::c_char) -> *mut libc::c_char; + #[no_mangle] + fn mkstemp(__template: *mut libc::c_char) -> libc::c_int; + #[no_mangle] + fn memset(_: *mut libc::c_void, _: libc::c_int, _: libc::c_ulong) + -> *mut libc::c_void; + #[no_mangle] + fn strcpy(_: *mut libc::c_char, _: *const libc::c_char) + -> *mut libc::c_char; + #[no_mangle] + fn strcmp(_: *const libc::c_char, _: *const libc::c_char) -> libc::c_int; + #[no_mangle] + fn strncmp(_: *const libc::c_char, _: *const libc::c_char, + _: libc::c_ulong) -> libc::c_int; + #[no_mangle] + fn strdup(_: *const libc::c_char) -> *mut libc::c_char; + #[no_mangle] + fn strrchr(_: *const libc::c_char, _: libc::c_int) -> *mut libc::c_char; + #[no_mangle] + fn strcasecmp(_: *const libc::c_char, _: *const libc::c_char) + -> libc::c_int; + #[no_mangle] + fn strlen(_: *const libc::c_char) -> libc::c_ulong; + #[no_mangle] + fn strerror(_: libc::c_int) -> *mut libc::c_char; +} +pub type __off_t = libc::c_long; +pub type __off64_t = libc::c_long; +pub type __pid_t = libc::c_int; +pub type __ssize_t = libc::c_long; +pub type __socklen_t = libc::c_uint; +pub type pid_t = __pid_t; +pub type ssize_t = __ssize_t; +pub type size_t = libc::c_ulong; +pub type socklen_t = __socklen_t; +pub type __socket_type = libc::c_uint; +pub const SOCK_NONBLOCK: __socket_type = 2048; +pub const SOCK_CLOEXEC: __socket_type = 524288; +pub const SOCK_PACKET: __socket_type = 10; +pub const SOCK_DCCP: __socket_type = 6; +pub const SOCK_SEQPACKET: __socket_type = 5; +pub const SOCK_RDM: __socket_type = 4; +pub const SOCK_RAW: __socket_type = 3; +pub const SOCK_DGRAM: __socket_type = 2; +pub const SOCK_STREAM: __socket_type = 1; +pub type sa_family_t = libc::c_ushort; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [libc::c_char; 14], +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct addrinfo { + pub ai_flags: libc::c_int, + pub ai_family: libc::c_int, + pub ai_socktype: libc::c_int, + pub ai_protocol: libc::c_int, + pub ai_addrlen: socklen_t, + pub ai_addr: *mut sockaddr, + pub ai_canonname: *mut libc::c_char, + pub ai_next: *mut addrinfo, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct _IO_FILE { + pub _flags: libc::c_int, + pub _IO_read_ptr: *mut libc::c_char, + pub _IO_read_end: *mut libc::c_char, + pub _IO_read_base: *mut libc::c_char, + pub _IO_write_base: *mut libc::c_char, + pub _IO_write_ptr: *mut libc::c_char, + pub _IO_write_end: *mut libc::c_char, + pub _IO_buf_base: *mut libc::c_char, + pub _IO_buf_end: *mut libc::c_char, + pub _IO_save_base: *mut libc::c_char, + pub _IO_backup_base: *mut libc::c_char, + pub _IO_save_end: *mut libc::c_char, + pub _markers: *mut _IO_marker, + pub _chain: *mut _IO_FILE, + pub _fileno: libc::c_int, + pub _flags2: libc::c_int, + pub _old_offset: __off_t, + pub _cur_column: libc::c_ushort, + pub _vtable_offset: libc::c_schar, + pub _shortbuf: [libc::c_char; 1], + pub _lock: *mut libc::c_void, + pub _offset: __off64_t, + pub _codecvt: *mut _IO_codecvt, + pub _wide_data: *mut _IO_wide_data, + pub _freeres_list: *mut _IO_FILE, + pub _freeres_buf: *mut libc::c_void, + pub __pad5: size_t, + pub _mode: libc::c_int, + pub _unused2: [libc::c_char; 20], +} +pub type _IO_lock_t = (); +pub type FILE = _IO_FILE; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct link_s { + pub next: *mut link_t, + pub which: libc::c_char, + pub key: libc::c_short, + pub host: *mut libc::c_char, + pub port: *mut libc::c_char, + pub selector: *mut libc::c_char, +} +/* structs */ +pub type link_t = link_s; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct config_s { + pub start_uri: [libc::c_char; 512], + pub cmd_text: [libc::c_char; 512], + pub cmd_image: [libc::c_char; 512], + pub cmd_browser: [libc::c_char; 512], + pub cmd_player: [libc::c_char; 512], + pub color_prompt: [libc::c_char; 512], + pub color_selector: [libc::c_char; 512], + pub verbose: [libc::c_char; 512], +} +pub type config_t = config_s; +#[no_mangle] +pub static mut tmpfilename: [libc::c_char; 256] = [0; 256]; +#[no_mangle] +pub static mut links: *mut link_t = 0 as *const link_t as *mut link_t; +#[no_mangle] +pub static mut history: *mut link_t = 0 as *const link_t as *mut link_t; +#[no_mangle] +pub static mut link_key: libc::c_int = 0; +#[no_mangle] +pub static mut current_host: [libc::c_char; 512] = [0; 512]; +#[no_mangle] +pub static mut current_port: [libc::c_char; 64] = [0; 64]; +#[no_mangle] +pub static mut current_selector: [libc::c_char; 1024] = [0; 1024]; +#[no_mangle] +pub static mut parsed_host: [libc::c_char; 512] = [0; 512]; +#[no_mangle] +pub static mut parsed_port: [libc::c_char; 64] = [0; 64]; +#[no_mangle] +pub static mut parsed_selector: [libc::c_char; 1024] = [0; 1024]; +#[no_mangle] +pub static mut bookmarks: [[libc::c_char; 512]; 20] = [[0; 512]; 20]; +#[no_mangle] +pub static mut config: config_t = + config_t{start_uri: [0; 512], + cmd_text: [0; 512], + cmd_image: [0; 512], + cmd_browser: [0; 512], + cmd_player: [0; 512], + color_prompt: [0; 512], + color_selector: [0; 512], + verbose: [0; 512],}; +/* implementation */ +#[no_mangle] +pub unsafe extern "C" fn usage() { + fputs(b"usage: cgo [-v] [-H] [gopher URI]\n\x00" as *const u8 as + *const libc::c_char, stderr); + exit(0 as libc::c_int); +} +#[no_mangle] +pub unsafe extern "C" fn banner(mut f: *mut FILE) { + fputs(b"cgo 0.6.1 Copyright (c) 2020 Sebastian Steinhauer\n\x00" as + *const u8 as *const libc::c_char, f); +} +#[no_mangle] +pub unsafe extern "C" fn check_option_true(mut option: *const libc::c_char) + -> libc::c_int { + return (strcasecmp(option, + b"false\x00" as *const u8 as *const libc::c_char) != 0 + && + strcasecmp(option, + b"off\x00" as *const u8 as *const libc::c_char) != + 0) as libc::c_int; +} +#[no_mangle] +pub unsafe extern "C" fn parse_config_line(mut line: *const libc::c_char) { + let mut token: [libc::c_char; 1024] = [0; 1024]; + let mut bkey: [libc::c_char; 128] = [0; 128]; + let mut value: *mut libc::c_char = 0 as *mut libc::c_char; + let mut i: libc::c_int = 0; + let mut j: libc::c_int = 0; + while *line as libc::c_int == ' ' as i32 || + *line as libc::c_int == '\t' as i32 { + line = line.offset(1) + } + i = 0 as libc::c_int; + while *line as libc::c_int != 0 && *line as libc::c_int != ' ' as i32 && + *line as libc::c_int != '\t' as i32 { + if (i as libc::c_ulong) < + (::std::mem::size_of::<[libc::c_char; 1024]>() as + libc::c_ulong).wrapping_sub(1 as libc::c_int as + libc::c_ulong) { + let fresh0 = i; + i = i + 1; + token[fresh0 as usize] = *line + } + line = line.offset(1) + } + token[i as usize] = 0 as libc::c_int as libc::c_char; + if strcmp(token.as_mut_ptr(), + b"start_uri\x00" as *const u8 as *const libc::c_char) == 0 { + value = + &mut *config.start_uri.as_mut_ptr().offset(0 as libc::c_int as + isize) as + *mut libc::c_char + } else if strcmp(token.as_mut_ptr(), + b"cmd_text\x00" as *const u8 as *const libc::c_char) == 0 + { + value = + &mut *config.cmd_text.as_mut_ptr().offset(0 as libc::c_int as + isize) as + *mut libc::c_char + } else if strcmp(token.as_mut_ptr(), + b"cmd_browser\x00" as *const u8 as *const libc::c_char) + == 0 { + value = + &mut *config.cmd_browser.as_mut_ptr().offset(0 as libc::c_int as + isize) as + *mut libc::c_char + } else if strcmp(token.as_mut_ptr(), + b"cmd_image\x00" as *const u8 as *const libc::c_char) == + 0 { + value = + &mut *config.cmd_image.as_mut_ptr().offset(0 as libc::c_int as + isize) as + *mut libc::c_char + } else if strcmp(token.as_mut_ptr(), + b"cmd_player\x00" as *const u8 as *const libc::c_char) == + 0 { + value = + &mut *config.cmd_player.as_mut_ptr().offset(0 as libc::c_int as + isize) as + *mut libc::c_char + } else if strcmp(token.as_mut_ptr(), + b"color_prompt\x00" as *const u8 as *const libc::c_char) + == 0 { + value = + &mut *config.color_prompt.as_mut_ptr().offset(0 as libc::c_int as + isize) as + *mut libc::c_char + } else if strcmp(token.as_mut_ptr(), + b"color_selector\x00" as *const u8 as + *const libc::c_char) == 0 { + value = + &mut *config.color_selector.as_mut_ptr().offset(0 as libc::c_int + as isize) as + *mut libc::c_char + } else if strcmp(token.as_mut_ptr(), + b"verbose\x00" as *const u8 as *const libc::c_char) == 0 + { + value = + &mut *config.verbose.as_mut_ptr().offset(0 as libc::c_int as + isize) as + *mut libc::c_char + } else { + j = 0 as libc::c_int; + while j < 20 as libc::c_int { + snprintf(bkey.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 128]>() as + libc::c_ulong, + b"bookmark%d\x00" as *const u8 as *const libc::c_char, + j + 1 as libc::c_int); + if strcmp(token.as_mut_ptr(), bkey.as_mut_ptr()) == 0 { + value = + &mut *(*bookmarks.as_mut_ptr().offset(j as + isize)).as_mut_ptr().offset(0 + as + libc::c_int + as + isize) + as *mut libc::c_char; + break ; + } else { j += 1 } + } + if value.is_null() { return } + } + while *line as libc::c_int == ' ' as i32 || + *line as libc::c_int == '\t' as i32 { + line = line.offset(1) + } + i = 0 as libc::c_int; + while *line != 0 { + if i < 512 as libc::c_int - 1 as libc::c_int { + let fresh1 = i; + i = i + 1; + *value.offset(fresh1 as isize) = *line + } + line = line.offset(1) + } + i -= 1; + while i > 0 as libc::c_int && + (*value.offset(i as isize) as libc::c_int == ' ' as i32 || + *value.offset(i as isize) as libc::c_int == '\t' as i32) { + i -= 1 + } + i += 1; + *value.offset(i as isize) = 0 as libc::c_int as libc::c_char; +} +#[no_mangle] +pub unsafe extern "C" fn load_config(mut filename: *const libc::c_char) { + let mut fp: *mut FILE = 0 as *mut FILE; + let mut ch: libc::c_int = 0; + let mut i: libc::c_int = 0; + let mut line: [libc::c_char; 1024] = [0; 1024]; + fp = fopen(filename, b"r\x00" as *const u8 as *const libc::c_char); + if fp.is_null() { return } + memset(line.as_mut_ptr() as *mut libc::c_void, 0 as libc::c_int, + ::std::mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong); + i = 0 as libc::c_int; + ch = fgetc(fp); + loop { + match ch { + 35 => { + while ch != '\n' as i32 && ch != -(1 as libc::c_int) { + ch = fgetc(fp) + } + } + -1 => { parse_config_line(line.as_mut_ptr()); fclose(fp); return } + 13 => { ch = fgetc(fp) } + 10 => { + parse_config_line(line.as_mut_ptr()); + memset(line.as_mut_ptr() as *mut libc::c_void, + 0 as libc::c_int, + ::std::mem::size_of::<[libc::c_char; 1024]>() as + libc::c_ulong); + i = 0 as libc::c_int; + ch = fgetc(fp) + } + _ => { + if (i as libc::c_ulong) < + (::std::mem::size_of::<[libc::c_char; 1024]>() as + libc::c_ulong).wrapping_sub(1 as libc::c_int as + libc::c_ulong) { + let fresh2 = i; + i = i + 1; + line[fresh2 as usize] = ch as libc::c_char + } + ch = fgetc(fp) + } + } + }; +} +#[no_mangle] +pub unsafe extern "C" fn init_config() { + let mut filename: [libc::c_char; 1024] = [0; 1024]; + let mut home: *const libc::c_char = 0 as *const libc::c_char; + let mut i: libc::c_int = 0; + /* copy defaults */ + snprintf(config.start_uri.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong, + b"gopher://gopher.floodgap.com:70\x00" as *const u8 as + *const libc::c_char); + snprintf(config.cmd_text.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, + b"less\x00" as *const u8 as *const libc::c_char); + snprintf(config.cmd_image.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, + b"display\x00" as *const u8 as *const libc::c_char); + snprintf(config.cmd_browser.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, + b"firefox\x00" as *const u8 as *const libc::c_char); + snprintf(config.cmd_player.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, + b"mplayer\x00" as *const u8 as *const libc::c_char); + snprintf(config.color_prompt.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, + b"1;34\x00" as *const u8 as *const libc::c_char); + snprintf(config.color_selector.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, + b"1;32\x00" as *const u8 as *const libc::c_char); + snprintf(config.verbose.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, + b"true\x00" as *const u8 as *const libc::c_char); + i = 0 as libc::c_int; + while i < 20 as libc::c_int { + bookmarks[i as usize][0 as libc::c_int as usize] = + 0 as libc::c_int as libc::c_char; + i += 1 + } + /* read configs */ + load_config(b"/etc/cgorc\x00" as *const u8 as + *const libc::c_char); /* ignore incomplete selectors */ + home = + getenv(b"HOME\x00" as *const u8 as + *const libc::c_char); /* not needed for history...just clear them */ + if !home.is_null() { + snprintf(filename.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 1024]>() as + libc::c_ulong, + b"%s%s\x00" as *const u8 as *const libc::c_char, home, + b"/.cgorc\x00" as *const u8 as *const libc::c_char); + load_config(filename.as_mut_ptr()); + }; +} +#[no_mangle] +pub unsafe extern "C" fn dial(mut host: *const libc::c_char, + mut port: *const libc::c_char, + mut selector: *const libc::c_char) + -> libc::c_int { + let mut hints: addrinfo = + addrinfo{ai_flags: 0, + ai_family: 0, + ai_socktype: 0, + ai_protocol: 0, + ai_addrlen: 0, + ai_addr: 0 as *mut sockaddr, + ai_canonname: 0 as *mut libc::c_char, + ai_next: 0 as *mut addrinfo,}; + let mut res: *mut addrinfo = 0 as *mut addrinfo; + let mut r: *mut addrinfo = 0 as *mut addrinfo; + let mut srv: libc::c_int = -(1 as libc::c_int); + let mut l: libc::c_int = 0; + let mut request: [libc::c_char; 512] = [0; 512]; + memset(&mut hints as *mut addrinfo as *mut libc::c_void, 0 as libc::c_int, + ::std::mem::size_of::() as libc::c_ulong); + hints.ai_family = 0 as libc::c_int; + hints.ai_socktype = SOCK_STREAM as libc::c_int; + if getaddrinfo(host, port, &mut hints, &mut res) != 0 as libc::c_int { + fprintf(stderr, + b"error: cannot resolve hostname \'%s:%s\': %s\n\x00" as + *const u8 as *const libc::c_char, host, port, + strerror(*__errno_location())); + return -(1 as libc::c_int) + } + r = res; + while !r.is_null() { + srv = socket((*r).ai_family, (*r).ai_socktype, (*r).ai_protocol); + if !(srv == -(1 as libc::c_int)) { + if connect(srv, (*r).ai_addr, (*r).ai_addrlen) == 0 as libc::c_int + { + break ; + } + close(srv); + } + r = (*r).ai_next + } + freeaddrinfo(res); + if r.is_null() { + fprintf(stderr, + b"error: cannot connect to host \'%s:%s\'\n\x00" as *const u8 + as *const libc::c_char, host, port); + return -(1 as libc::c_int) + } + snprintf(request.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong, + b"%s\r\n\x00" as *const u8 as *const libc::c_char, selector); + l = strlen(request.as_mut_ptr()) as libc::c_int; + if write(srv, request.as_mut_ptr() as *const libc::c_void, l as size_t) != + l as libc::c_long { + fprintf(stderr, + b"error: cannot complete request\n\x00" as *const u8 as + *const libc::c_char); + close(srv); + return -(1 as libc::c_int) + } + return srv; +} +#[no_mangle] +pub unsafe extern "C" fn read_line(mut fd: libc::c_int, + mut buf: *mut libc::c_char, + mut buf_len: size_t) -> libc::c_int { + let mut i: size_t = 0 as libc::c_int as size_t; + let mut c: libc::c_char = 0 as libc::c_int as libc::c_char; + loop { + if read(fd, &mut c as *mut libc::c_char as *mut libc::c_void, + ::std::mem::size_of::() as libc::c_ulong) as + libc::c_ulong != + ::std::mem::size_of::() as libc::c_ulong { + return 0 as libc::c_int + } + if c as libc::c_int != '\r' as i32 { + let fresh3 = i; + i = i.wrapping_add(1); + *buf.offset(fresh3 as isize) = c + } + if !(c as libc::c_int != '\n' as i32 && i < buf_len) { break ; } + } + *buf.offset(i.wrapping_sub(1 as libc::c_int as libc::c_ulong) as isize) = + '\u{0}' as i32 as libc::c_char; + return 1 as libc::c_int; +} +#[no_mangle] +pub unsafe extern "C" fn download_file(mut host: *const libc::c_char, + mut port: *const libc::c_char, + mut selector: *const libc::c_char, + mut fd: libc::c_int) -> libc::c_int { + let mut srvfd: libc::c_int = 0; + let mut len: libc::c_int = 0; + let mut total: libc::c_ulong = 0 as libc::c_int as libc::c_ulong; + let mut buffer: [libc::c_char; 4096] = [0; 4096]; + if check_option_true(config.verbose.as_mut_ptr()) != 0 { + printf(b"downloading [%s]...\r\x00" as *const u8 as + *const libc::c_char, selector); + } + srvfd = dial(host, port, selector); + if srvfd == -(1 as libc::c_int) { + printf(b"\x1b[2Kerror: downloading [%s] failed\n\x00" as *const u8 as + *const libc::c_char, selector); + close(fd); + return 0 as libc::c_int + } + loop { + len = + read(srvfd, buffer.as_mut_ptr() as *mut libc::c_void, + ::std::mem::size_of::<[libc::c_char; 4096]>() as + libc::c_ulong) as libc::c_int; + if !(len > 0 as libc::c_int) { break ; } + write(fd, buffer.as_mut_ptr() as *const libc::c_void, len as size_t); + total = total.wrapping_add(len as libc::c_ulong); + if check_option_true(config.verbose.as_mut_ptr()) != 0 { + printf(b"downloading [%s] (%ld kb)...\r\x00" as *const u8 as + *const libc::c_char, selector, + total.wrapping_div(1024 as libc::c_int as libc::c_ulong)); + } + } + close(fd); + close(srvfd); + if check_option_true(config.verbose.as_mut_ptr()) != 0 { + printf(b"\x1b[2Kdownloading [%s] complete\n\x00" as *const u8 as + *const libc::c_char, selector); + } + return 1 as libc::c_int; +} +#[no_mangle] +pub unsafe extern "C" fn download_temp(mut host: *const libc::c_char, + mut port: *const libc::c_char, + mut selector: *const libc::c_char) + -> libc::c_int { + let mut tmpfd: libc::c_int = 0; + strcpy(tmpfilename.as_mut_ptr(), + b"/tmp/cgoXXXXXX\x00" as *const u8 as *const libc::c_char); + tmpfd = mkstemp(tmpfilename.as_mut_ptr()); + if tmpfd == -(1 as libc::c_int) { + fputs(b"error: unable to create tmp file\n\x00" as *const u8 as + *const libc::c_char, stderr); + return 0 as libc::c_int + } + if download_file(host, port, selector, tmpfd) == 0 { + unlink(tmpfilename.as_mut_ptr()); + return 0 as libc::c_int + } + return 1 as libc::c_int; +} +#[no_mangle] +pub unsafe extern "C" fn make_key(mut c1: libc::c_char, mut c2: libc::c_char, + mut c3: libc::c_char) -> libc::c_int { + if c1 == 0 || c2 == 0 { return -(1 as libc::c_int) } + if c3 == 0 { + return (c1 as libc::c_int - 'a' as i32) * + ('z' as i32 - 'a' as i32 + 1 as libc::c_int) + + (c2 as libc::c_int - 'a' as i32) + } else { + return (c1 as libc::c_int - 'a' as i32 + 1 as libc::c_int) * + ('z' as i32 - 'a' as i32 + 1 as libc::c_int) * + ('z' as i32 - 'a' as i32 + 1 as libc::c_int) + + (c2 as libc::c_int - 'a' as i32) * + ('z' as i32 - 'a' as i32 + 1 as libc::c_int) + + (c3 as libc::c_int - 'a' as i32) + }; +} +#[no_mangle] +pub unsafe extern "C" fn make_key_str(mut key: libc::c_int, + mut c1: *mut libc::c_char, + mut c2: *mut libc::c_char, + mut c3: *mut libc::c_char) { + if key < + ('z' as i32 - 'a' as i32 + 1 as libc::c_int) * + ('z' as i32 - 'a' as i32 + 1 as libc::c_int) { + *c1 = + ('a' as i32 + key / ('z' as i32 - 'a' as i32 + 1 as libc::c_int)) + as libc::c_char; + *c2 = + ('a' as i32 + key % ('z' as i32 - 'a' as i32 + 1 as libc::c_int)) + as libc::c_char; + *c3 = 0 as libc::c_int as libc::c_char + } else { + *c1 = + ('a' as i32 + + key / + (('z' as i32 - 'a' as i32 + 1 as libc::c_int) * + ('z' as i32 - 'a' as i32 + 1 as libc::c_int)) - + 1 as libc::c_int) as libc::c_char; + *c2 = + ('a' as i32 + + key / ('z' as i32 - 'a' as i32 + 1 as libc::c_int) % + ('z' as i32 - 'a' as i32 + 1 as libc::c_int)) as + libc::c_char; + *c3 = + ('a' as i32 + key % ('z' as i32 - 'a' as i32 + 1 as libc::c_int)) + as libc::c_char + }; +} +#[no_mangle] +pub unsafe extern "C" fn add_link(mut which: libc::c_char, + mut name: *const libc::c_char, + mut host: *const libc::c_char, + mut port: *const libc::c_char, + mut selector: *const libc::c_char) { + let mut link: *mut link_t = 0 as *mut link_t; + let mut a: libc::c_char = 0 as libc::c_int as libc::c_char; + let mut b: libc::c_char = 0 as libc::c_int as libc::c_char; + let mut c: libc::c_char = 0 as libc::c_int as libc::c_char; + if host.is_null() || port.is_null() || selector.is_null() { return } + link = + calloc(1 as libc::c_int as libc::c_ulong, + ::std::mem::size_of::() as libc::c_ulong) as + *mut link_t; + (*link).which = which; + (*link).key = link_key as libc::c_short; + (*link).host = strdup(host); + (*link).port = strdup(port); + (*link).selector = strdup(selector); + if links.is_null() { + (*link).next = 0 as *mut link_t + } else { (*link).next = links } + links = link; + let fresh4 = link_key; + link_key = link_key + 1; + make_key_str(fresh4, &mut a, &mut b, &mut c); + printf(b"\x1b[%sm%c%c%c\x1b[0m \x1b[1m%s\x1b[0m\n\x00" as *const u8 as + *const libc::c_char, config.color_selector.as_mut_ptr(), + a as libc::c_int, b as libc::c_int, c as libc::c_int, name); +} +#[no_mangle] +pub unsafe extern "C" fn clear_links() { + let mut link: *mut link_t = 0 as *mut link_t; + let mut next: *mut link_t = 0 as *mut link_t; + link = links; + while !link.is_null() { + next = (*link).next; + free((*link).host as *mut libc::c_void); + free((*link).port as *mut libc::c_void); + free((*link).selector as *mut libc::c_void); + free(link as *mut libc::c_void); + link = next + } + links = 0 as *mut link_t; + link_key = 0 as libc::c_int; +} +#[no_mangle] +pub unsafe extern "C" fn add_history() { + let mut link: *mut link_t = 0 as *mut link_t; + link = + calloc(1 as libc::c_int as libc::c_ulong, + ::std::mem::size_of::() as libc::c_ulong) as + *mut link_t; + (*link).host = strdup(current_host.as_mut_ptr()); + (*link).port = strdup(current_port.as_mut_ptr()); + (*link).selector = strdup(current_selector.as_mut_ptr()); + (*link).which = 0 as libc::c_int as libc::c_char; + (*link).key = 0 as libc::c_int as libc::c_short; + if history.is_null() { + (*link).next = 0 as *mut link_t + } else { (*link).next = history } + history = link; +} +#[no_mangle] +pub unsafe extern "C" fn handle_directory_line(mut line: *mut libc::c_char) { + let mut i: libc::c_int = 0; + let mut lp: *mut libc::c_char = 0 as *mut libc::c_char; + let mut last: *mut libc::c_char = 0 as *mut libc::c_char; + let mut fields: [*mut libc::c_char; 4] = [0 as *mut libc::c_char; 4]; + /* tokenize */ + i = 0 as libc::c_int; + while i < 4 as libc::c_int { + fields[i as usize] = 0 as *mut libc::c_char; + i += 1 + } + last = &mut *line.offset(1 as libc::c_int as isize) as *mut libc::c_char; + lp = last; + i = 0 as libc::c_int; + while i < 4 as libc::c_int { + if *lp as libc::c_int == '\t' as i32 || + *lp as libc::c_int == '\u{0}' as i32 { + fields[i as usize] = last; + last = lp.offset(1 as libc::c_int as isize); + if *lp as libc::c_int == '\u{0}' as i32 { break ; } + *lp = '\u{0}' as i32 as libc::c_char; + i += 1 + } + lp = lp.offset(1) + } + /* determine listing type */ + match *line.offset(0 as libc::c_int as isize) as libc::c_int { + 105 | 51 => { + printf(b" %s\n\x00" as *const u8 as *const libc::c_char, + fields[0 as libc::c_int as usize]); + } + 46 => { + /* some gopher servers use this */ + puts(b"\x00" as *const u8 as *const libc::c_char); + } + 48 | 49 | 53 | 55 | 56 | 57 | 103 | 73 | 112 | 104 | 115 => { + add_link(*line.offset(0 as libc::c_int as isize), + fields[0 as libc::c_int as usize], + fields[2 as libc::c_int as usize], + fields[3 as libc::c_int as usize], + fields[1 as libc::c_int as usize]); + } + _ => { + printf(b"miss [%c]: %s\n\x00" as *const u8 as *const libc::c_char, + *line.offset(0 as libc::c_int as isize) as libc::c_int, + fields[0 as libc::c_int as usize]); + } + }; +} +#[no_mangle] +pub unsafe extern "C" fn is_valid_directory_entry(mut line: + *const libc::c_char) + -> libc::c_int { + match *line.offset(0 as libc::c_int as isize) as libc::c_int { + 105 | 51 | 46 | 48 | 49 | 53 | 55 | 56 | 57 | 103 | 73 | 112 | 104 | + 115 => { + /* some gopher servers use this */ + return 1 as libc::c_int + } + _ => { return 0 as libc::c_int } + }; +} +#[no_mangle] +pub unsafe extern "C" fn view_directory(mut host: *const libc::c_char, + mut port: *const libc::c_char, + mut selector: *const libc::c_char, + mut make_current: libc::c_int) { + let mut is_dir: libc::c_int = 0; + let mut srvfd: libc::c_int = 0; + let mut i: libc::c_int = 0; + let mut head_read: libc::c_int = 0; + let mut line: [libc::c_char; 1024] = [0; 1024]; + let mut head: [[libc::c_char; 1024]; 5] = [[0; 1024]; 5]; + srvfd = dial(host, port, selector); + if srvfd != -(1 as libc::c_int) { + /* only adapt current prompt when successful */ + /* make history entry */ + if make_current != 0 { add_history(); } + /* don't overwrite the current_* things... */ + if host != current_host.as_mut_ptr() as *const libc::c_char { + snprintf(current_host.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 512]>() as + libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, + host); /* clear links *AFTER* dialing out!! */ + } /* quit if not successful */ + if port != current_port.as_mut_ptr() as *const libc::c_char { + snprintf(current_port.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 64]>() as + libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, port); + } + if selector != current_selector.as_mut_ptr() as *const libc::c_char { + snprintf(current_selector.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 1024]>() as + libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, selector); + } + } + clear_links(); + if srvfd == -(1 as libc::c_int) { return } + head_read = 0 as libc::c_int; + is_dir = 1 as libc::c_int; + while head_read < 5 as libc::c_int && + read_line(srvfd, line.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 1024]>() as + libc::c_ulong) != 0 { + strcpy(head[head_read as usize].as_mut_ptr(), line.as_mut_ptr()); + if is_valid_directory_entry(head[head_read as usize].as_mut_ptr()) == + 0 { + is_dir = 0 as libc::c_int; + break ; + } else { head_read += 1 } + } + if is_dir == 0 { + puts(b"error: Not a directory.\x00" as *const u8 as + *const libc::c_char); + close(srvfd); + return + } + i = 0 as libc::c_int; + while i < head_read { + handle_directory_line(head[i as usize].as_mut_ptr()); + i += 1 + } + while read_line(srvfd, line.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 1024]>() as + libc::c_ulong) != 0 { + handle_directory_line(line.as_mut_ptr()); + } + close(srvfd); +} +#[no_mangle] +pub unsafe extern "C" fn view_file(mut cmd: *const libc::c_char, + mut host: *const libc::c_char, + mut port: *const libc::c_char, + mut selector: *const libc::c_char) { + let mut pid: pid_t = 0; + let mut status: libc::c_int = 0; + let mut i: libc::c_int = 0; + let mut j: libc::c_int = 0; + let mut buffer: [libc::c_char; 1024] = [0; 1024]; + let mut argv: [*mut libc::c_char; 32] = [0 as *mut libc::c_char; 32]; + let mut p: *mut libc::c_char = 0 as *mut libc::c_char; + if check_option_true(config.verbose.as_mut_ptr()) != 0 { + printf(b"h(%s) p(%s) s(%s)\n\x00" as *const u8 as *const libc::c_char, + host, port, selector); + } + if download_temp(host, port, selector) == 0 { return } + /* parsed command line string */ + argv[0 as libc::c_int as usize] = + &mut *buffer.as_mut_ptr().offset(0 as libc::c_int as isize) as + *mut libc::c_char; + p = cmd as *mut libc::c_char; + i = 0 as libc::c_int; + j = 1 as libc::c_int; + while *p as libc::c_int != 0 && + (i as libc::c_ulong) < + (::std::mem::size_of::<[libc::c_char; 1024]>() as + libc::c_ulong).wrapping_sub(1 as libc::c_int as + libc::c_ulong) && + j < 30 as libc::c_int { + if *p as libc::c_int == ' ' as i32 || *p as libc::c_int == '\t' as i32 + { + let fresh5 = i; + i = i + 1; + buffer[fresh5 as usize] = 0 as libc::c_int as libc::c_char; + let fresh6 = j; + j = j + 1; + argv[fresh6 as usize] = + &mut *buffer.as_mut_ptr().offset(i as isize) as + *mut libc::c_char; + while *p as libc::c_int == ' ' as i32 || + *p as libc::c_int == '\t' as i32 { + p = p.offset(1) + } + } else { + let fresh7 = p; + p = p.offset(1); + let fresh8 = i; + i = i + 1; + buffer[fresh8 as usize] = *fresh7 + } + } + buffer[i as usize] = 0 as libc::c_int as libc::c_char; + let fresh9 = j; + j = j + 1; + argv[fresh9 as usize] = tmpfilename.as_mut_ptr(); + argv[j as usize] = 0 as *mut libc::c_char; + /* fork and execute */ + if check_option_true(config.verbose.as_mut_ptr()) != 0 { + printf(b"executing: %s %s\n\x00" as *const u8 as *const libc::c_char, + cmd, + tmpfilename.as_mut_ptr()); /* to wait for browsers etc. that return immediatly */ + } + pid = fork(); + if pid == 0 as libc::c_int { + if execvp(argv[0 as libc::c_int as usize], + argv.as_mut_ptr() as *const *mut libc::c_char) == + -(1 as libc::c_int) { + puts(b"error: execvp() failed!\x00" as *const u8 as + *const libc::c_char); + } + } else if pid == -(1 as libc::c_int) { + puts(b"error: fork() failed\x00" as *const u8 as *const libc::c_char); + } + sleep(1 as libc::c_int as libc::c_uint); + waitpid(pid, &mut status, 0 as libc::c_int); + unlink(tmpfilename.as_mut_ptr()); +} +#[no_mangle] +pub unsafe extern "C" fn view_telnet(mut host: *const libc::c_char, + mut port: *const libc::c_char) { + let mut pid: pid_t = 0; + let mut status: libc::c_int = 0; + printf(b"executing: %s %s %s\n\x00" as *const u8 as *const libc::c_char, + b"telnet\x00" as *const u8 as *const libc::c_char, host, port); + pid = fork(); + if pid == 0 as libc::c_int { + if execlp(b"telnet\x00" as *const u8 as *const libc::c_char, + b"telnet\x00" as *const u8 as *const libc::c_char, host, + port, 0 as *mut libc::c_void) == -(1 as libc::c_int) { + puts(b"error: execlp() failed!\x00" as *const u8 as + *const libc::c_char); + } + } else if pid == -(1 as libc::c_int) { + puts(b"error: fork() failed!\x00" as *const u8 as + *const libc::c_char); + } + waitpid(pid, &mut status, 0 as libc::c_int); + puts(b"(done)\x00" as *const u8 as *const libc::c_char); +} +#[no_mangle] +pub unsafe extern "C" fn view_download(mut host: *const libc::c_char, + mut port: *const libc::c_char, + mut selector: *const libc::c_char) { + let mut fd: libc::c_int = 0; + let mut filename: [libc::c_char; 1024] = [0; 1024]; + let mut line: [libc::c_char; 1024] = [0; 1024]; + snprintf(filename.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, + strrchr(selector, '/' as i32).offset(1 as libc::c_int as isize)); + printf(b"enter filename for download [%s]: \x00" as *const u8 as + *const libc::c_char, filename.as_mut_ptr()); + fflush(stdout); + if read_line(0 as libc::c_int, line.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 1024]>() as + libc::c_ulong) == 0 { + puts(b"download aborted\x00" as *const u8 as *const libc::c_char); + return + } + if strlen(line.as_mut_ptr()) > 0 as libc::c_int as libc::c_ulong { + strcpy(filename.as_mut_ptr(), line.as_mut_ptr()); + } + fd = + open(filename.as_mut_ptr(), 0o100 as libc::c_int | 0o1 as libc::c_int, + 0o400 as libc::c_int | 0o200 as libc::c_int); + if fd == -(1 as libc::c_int) { + printf(b"error: unable to create file [%s]: %s\n\x00" as *const u8 as + *const libc::c_char, filename.as_mut_ptr(), + strerror(*__errno_location())); + return + } + if download_file(host, port, selector, fd) == 0 { + printf(b"error: unable to download [%s]\n\x00" as *const u8 as + *const libc::c_char, selector); + unlink(filename.as_mut_ptr()); + return + }; +} +#[no_mangle] +pub unsafe extern "C" fn view_search(mut host: *const libc::c_char, + mut port: *const libc::c_char, + mut selector: *const libc::c_char) { + let mut search_selector: [libc::c_char; 1024] = [0; 1024]; + let mut line: [libc::c_char; 1024] = [0; 1024]; + printf(b"enter search string: \x00" as *const u8 as *const libc::c_char); + fflush(stdout); + if read_line(0 as libc::c_int, line.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 1024]>() as + libc::c_ulong) == 0 { + puts(b"search aborted\x00" as *const u8 as *const libc::c_char); + return + } + snprintf(search_selector.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong, + b"%s\t%s\x00" as *const u8 as *const libc::c_char, selector, + line.as_mut_ptr()); + view_directory(host, port, search_selector.as_mut_ptr(), + 1 as libc::c_int); +} +#[no_mangle] +pub unsafe extern "C" fn view_history(mut key: libc::c_int) { + let mut history_key: libc::c_int = 0 as libc::c_int; + let mut a: libc::c_char = 0; + let mut b: libc::c_char = 0; + let mut c: libc::c_char = 0; + let mut link: *mut link_t = 0 as *mut link_t; + if history.is_null() { + puts(b"(empty history)\x00" as *const u8 as *const libc::c_char); + return + } + if key < 0 as libc::c_int { + puts(b"(history)\x00" as *const u8 as *const libc::c_char); + link = history; + while !link.is_null() { + let fresh10 = history_key; + history_key = history_key + 1; + make_key_str(fresh10, &mut a, &mut b, &mut c); + printf(b"\x1b[%sm%c%c%c\x1b[0m \x1b[1m%s:%s/1%s\x1b[0m\n\x00" as + *const u8 as *const libc::c_char, + b"1;32\x00" as *const u8 as *const libc::c_char, + a as libc::c_int, b as libc::c_int, c as libc::c_int, + (*link).host, (*link).port, (*link).selector); + link = (*link).next + } + } else { + /* traverse history list */ + link = history; + while !link.is_null() { + if history_key == key { + view_directory((*link).host, (*link).port, (*link).selector, + 0 as libc::c_int); + return + } + link = (*link).next; + history_key += 1 + } + puts(b"history item not found\x00" as *const u8 as + *const libc::c_char); + }; +} +#[no_mangle] +pub unsafe extern "C" fn view_bookmarks(mut key: libc::c_int) { + let mut i: libc::c_int = 0; + let mut a: libc::c_char = 0; + let mut b: libc::c_char = 0; + let mut c: libc::c_char = 0; + if key < 0 as libc::c_int { + puts(b"(bookmarks)\x00" as *const u8 as *const libc::c_char); + i = 0 as libc::c_int; + while i < 20 as libc::c_int { + if bookmarks[i as usize][0 as libc::c_int as usize] != 0 { + make_key_str(i, &mut a, &mut b, &mut c); + printf(b"\x1b[%sm%c%c%c\x1b[0m \x1b[1m%s\x1b[0m\n\x00" as + *const u8 as *const libc::c_char, + b"1;32\x00" as *const u8 as *const libc::c_char, + a as libc::c_int, b as libc::c_int, c as libc::c_int, + &mut *(*bookmarks.as_mut_ptr().offset(i as + isize)).as_mut_ptr().offset(0 + as + libc::c_int + as + isize) + as *mut libc::c_char); + } + i += 1 + } + } else { + i = 0 as libc::c_int; + while i < 20 as libc::c_int { + if bookmarks[i as usize][0 as libc::c_int as usize] as libc::c_int + != 0 && i == key { + if parse_uri(&mut *(*bookmarks.as_mut_ptr().offset(i as + isize)).as_mut_ptr().offset(0 + as + libc::c_int + as + isize)) + != 0 { + view_directory(parsed_host.as_mut_ptr(), + parsed_port.as_mut_ptr(), + parsed_selector.as_mut_ptr(), + 0 as libc::c_int); + } else { + printf(b"invalid gopher URI: %s\x00" as *const u8 as + *const libc::c_char, + &mut *(*bookmarks.as_mut_ptr().offset(i as + isize)).as_mut_ptr().offset(0 + as + libc::c_int + as + isize) + as *mut libc::c_char); + } + return + } + i += 1 + } + }; +} +#[no_mangle] +pub unsafe extern "C" fn pop_history() { + let mut next: *mut link_t = 0 as *mut link_t; + if history.is_null() { + puts(b"(empty history)\x00" as *const u8 as *const libc::c_char); + return + } + /* reload page from history (and don't count as history) */ + view_directory((*history).host, (*history).port, (*history).selector, + 0 as libc::c_int); + /* history is history... :) */ + next = (*history).next; + free((*history).host as *mut libc::c_void); + free((*history).port as *mut libc::c_void); + free((*history).selector as *mut libc::c_void); + free(history as *mut libc::c_void); + history = next; +} +#[no_mangle] +pub unsafe extern "C" fn follow_link(mut key: libc::c_int) -> libc::c_int { + let mut link: *mut link_t = 0 as *mut link_t; + link = links; + while !link.is_null() { + if (*link).key as libc::c_int != key { + link = (*link).next + } else { + match (*link).which as libc::c_int { + 48 => { + view_file(&mut *config.cmd_text.as_mut_ptr().offset(0 as + libc::c_int + as + isize), + (*link).host, (*link).port, (*link).selector); + } + 49 => { + view_directory((*link).host, (*link).port, + (*link).selector, 1 as libc::c_int); + } + 55 => { + view_search((*link).host, (*link).port, (*link).selector); + } + 53 | 57 => { + view_download((*link).host, (*link).port, + (*link).selector); + } + 56 => { view_telnet((*link).host, (*link).port); } + 103 | 73 | 112 => { + view_file(&mut *config.cmd_image.as_mut_ptr().offset(0 as + libc::c_int + as + isize), + (*link).host, (*link).port, (*link).selector); + } + 104 => { + view_file(&mut *config.cmd_browser.as_mut_ptr().offset(0 + as + libc::c_int + as + isize), + (*link).host, (*link).port, (*link).selector); + } + 115 => { + view_file(&mut *config.cmd_player.as_mut_ptr().offset(0 as + libc::c_int + as + isize), + (*link).host, (*link).port, (*link).selector); + } + _ => { + printf(b"missing handler [%c]\n\x00" as *const u8 as + *const libc::c_char, + (*link).which as libc::c_int); + } + } + return 1 as libc::c_int + } + /* return the array is broken after view! */ + } + return 0 as libc::c_int; +} +#[no_mangle] +pub unsafe extern "C" fn download_link(mut key: libc::c_int) { + let mut link: *mut link_t = 0 as *mut link_t; + link = links; + while !link.is_null() { + if (*link).key as libc::c_int != key { + link = (*link).next + } else { + view_download((*link).host, (*link).port, (*link).selector); + return + } + } + puts(b"link not found\x00" as *const u8 as *const libc::c_char); +} +/* function prototypes */ +#[no_mangle] +pub unsafe extern "C" fn parse_uri(mut uri: *const libc::c_char) + -> libc::c_int { + let mut i: libc::c_int = 0; + /* strip gopher:// */ + if strncmp(uri, b"gopher://\x00" as *const u8 as *const libc::c_char, + 9 as libc::c_int as libc::c_ulong) == 0 { + uri = uri.offset(9 as libc::c_int as isize) + } + /* parse host */ + i = 0 as libc::c_int; + while *uri as libc::c_int != 0 && *uri as libc::c_int != ':' as i32 && + *uri as libc::c_int != '/' as i32 { + if *uri as libc::c_int != ' ' as i32 && + (i as libc::c_ulong) < + (::std::mem::size_of::<[libc::c_char; 512]>() as + libc::c_ulong).wrapping_sub(1 as libc::c_int as + libc::c_ulong) { + let fresh11 = i; + i = i + 1; + parsed_host[fresh11 as usize] = *uri + } + uri = uri.offset(1) + } + if i > 0 as libc::c_int { + parsed_host[i as usize] = 0 as libc::c_int as libc::c_char + } else { return 0 as libc::c_int } + /* parse port */ + if *uri as libc::c_int == ':' as i32 { + uri = uri.offset(1); + i = 0 as libc::c_int; + while *uri as libc::c_int != 0 && *uri as libc::c_int != '/' as i32 { + if *uri as libc::c_int != ' ' as i32 && + (i as libc::c_ulong) < + (::std::mem::size_of::<[libc::c_char; 64]>() as + libc::c_ulong).wrapping_sub(1 as libc::c_int as + libc::c_ulong) { + let fresh12 = i; + i = i + 1; + parsed_port[fresh12 as usize] = *uri + } + uri = uri.offset(1) + } + parsed_port[i as usize] = 0 as libc::c_int as libc::c_char + } else { + snprintf(parsed_port.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 64]>() as libc::c_ulong, + b"%d\x00" as *const u8 as *const libc::c_char, + 70 as libc::c_int); + } + /* parse selector (ignore slash and selector type) */ + if *uri != 0 { uri = uri.offset(1) } + if *uri != 0 { uri = uri.offset(1) } + i = 0 as libc::c_int; + while *uri as libc::c_int != 0 && + (i as libc::c_ulong) < + (::std::mem::size_of::<[libc::c_char; 1024]>() as + libc::c_ulong).wrapping_sub(1 as libc::c_int as + libc::c_ulong) { + parsed_selector[i as usize] = *uri; + uri = uri.offset(1); + i += 1 + } + parsed_selector[i as usize] = '\u{0}' as i32 as libc::c_char; + return 1 as libc::c_int; +} +unsafe fn main_0(mut argc: libc::c_int, mut argv: *mut *mut libc::c_char) + -> libc::c_int { + let mut i: libc::c_int = 0; + let mut line: [libc::c_char; 1024] = [0; 1024]; + let mut uri: *mut libc::c_char = 0 as *mut libc::c_char; + /* copy defaults */ + init_config(); + uri = + &mut *config.start_uri.as_mut_ptr().offset(0 as libc::c_int as isize) + as *mut libc::c_char; + /* parse command line */ + i = 1 as libc::c_int; + while i < argc { + if *(*argv.offset(i as isize)).offset(0 as libc::c_int as isize) as + libc::c_int == '-' as i32 { + match *(*argv.offset(i as + isize)).offset(1 as libc::c_int as isize) + as libc::c_int { + 72 => { usage(); } + 118 => { banner(stdout); exit(0 as libc::c_int); } + _ => { usage(); } + } + } else { uri = *argv.offset(i as isize) } + i += 1 + } + /* parse uri */ + if parse_uri(uri) == 0 { + banner(stderr); + fprintf(stderr, + b"invalid gopher URI: %s\x00" as *const u8 as + *const libc::c_char, *argv.offset(i as isize)); + exit(1 as libc::c_int); + } + /* main loop */ + view_directory(parsed_host.as_mut_ptr(), parsed_port.as_mut_ptr(), + parsed_selector.as_mut_ptr(), + 0 as libc::c_int); /* to display the prompt */ + loop { + printf(b"\x1b[%sm%s:%s%s\x1b[0m \x00" as *const u8 as + *const libc::c_char, config.color_prompt.as_mut_ptr(), + current_host.as_mut_ptr(), current_port.as_mut_ptr(), + current_selector.as_mut_ptr()); + fflush(stdout); + if read_line(0 as libc::c_int, line.as_mut_ptr(), + ::std::mem::size_of::<[libc::c_char; 1024]>() as + libc::c_ulong) == 0 { + puts(b"QUIT\x00" as *const u8 as *const libc::c_char); + return 0 as libc::c_int + } + i = strlen(line.as_mut_ptr()) as libc::c_int; + match line[0 as libc::c_int as usize] as libc::c_int { + 63 => { + puts(b"? - help\n* - reload directory\n< - go back in history\n.[LINK] - download the given link\nH - show history\nH[LINK] - jump to the specified history item\nG[URI] - jump to the given gopher URI\nB - show bookmarks\nB[LINK] - jump to the specified bookmark item\nC^d - quit\x00" + as *const u8 as *const libc::c_char); + } + 60 => { pop_history(); } + 42 => { + view_directory(current_host.as_mut_ptr(), + current_port.as_mut_ptr(), + current_selector.as_mut_ptr(), + 0 as libc::c_int); + } + 46 => { + download_link(make_key(line[1 as libc::c_int as usize], + line[2 as libc::c_int as usize], + line[3 as libc::c_int as usize])); + } + 72 => { + if i == 1 as libc::c_int || i == 3 as libc::c_int || + i == 4 as libc::c_int { + view_history(make_key(line[1 as libc::c_int as usize], + line[2 as libc::c_int as usize], + line[3 as libc::c_int as usize])); + } + } + 71 => { + if parse_uri(&mut *line.as_mut_ptr().offset(1 as libc::c_int + as isize)) != + 0 { + view_directory(parsed_host.as_mut_ptr(), + parsed_port.as_mut_ptr(), + parsed_selector.as_mut_ptr(), + 1 as libc::c_int); + } else { + puts(b"invalid gopher URI\x00" as *const u8 as + *const libc::c_char); + } + } + 66 => { + if i == 1 as libc::c_int || i == 3 as libc::c_int || + i == 4 as libc::c_int { + view_bookmarks(make_key(line[1 as libc::c_int as usize], + line[2 as libc::c_int as usize], + line[3 as libc::c_int as usize])); + } + } + _ => { + follow_link(make_key(line[0 as libc::c_int as usize], + line[1 as libc::c_int as usize], + line[2 as libc::c_int as usize])); + } + } + }; + /* never get's here but stops cc complaining */ +} +#[main] +pub fn main() { + let mut args: Vec<*mut libc::c_char> = Vec::new(); + for arg in ::std::env::args() { + args.push(::std::ffi::CString::new(arg).expect("Failed to convert argument into CString.").into_raw()); + }; + args.push(::std::ptr::null_mut()); + unsafe { + ::std::process::exit(main_0((args.len() - 1) as libc::c_int, + args.as_mut_ptr() as + *mut *mut libc::c_char) as i32) + } +} diff --git a/compile_commands.json b/compile_commands.json new file mode 100644 index 0000000..969ee11 --- /dev/null +++ b/compile_commands.json @@ -0,0 +1,11 @@ +[ + { + "arguments": [ + "cc", + "-c", + "cgo.c" + ], + "directory": "/root/rgp", + "file": "cgo.c" + } +] \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..1ed61f0 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,1625 @@ +#![allow( + dead_code, + mutable_transmutes, + non_camel_case_types, + non_snake_case, + non_upper_case_globals, + unused_assignments, + unused_mut +)] +#![register_tool(c2rust)] +#![feature(const_raw_ptr_to_usize_cast, extern_types, main, register_tool)] + +extern crate libc; +#[macro_use] extern crate lazy_static; + +use std::env; +use std::process::exit; +use std::thread::sleep; +use std::time::Duration; +use std::ffi::{CStr, CString}; +use std::mem; +use std::ptr; + +extern "C" { + pub type _IO_wide_data; + pub type _IO_codecvt; + pub type _IO_marker; + #[no_mangle] + fn waitpid( + __pid: __pid_t, + __stat_loc: *mut libc::c_int, + __options: libc::c_int, + ) -> __pid_t; + #[no_mangle] + fn socket( + __domain: libc::c_int, + __type: libc::c_int, + __protocol: libc::c_int, + ) -> libc::c_int; + #[no_mangle] + fn connect( + __fd: libc::c_int, + __addr: *const sockaddr, + __len: socklen_t, + ) -> libc::c_int; + #[no_mangle] + fn getaddrinfo( + __name: *const libc::c_char, + __service: *const libc::c_char, + __req: *const addrinfo, + __pai: *mut *mut addrinfo, + ) -> libc::c_int; + #[no_mangle] + fn freeaddrinfo(__ai: *mut addrinfo); + #[no_mangle] + fn open(__file: *const libc::c_char, __oflag: libc::c_int, _: ...) -> libc::c_int; + #[no_mangle] + fn close(__fd: libc::c_int) -> libc::c_int; + #[no_mangle] + fn read(__fd: libc::c_int, __buf: *mut libc::c_void, __nbytes: size_t) -> ssize_t; + #[no_mangle] + fn write(__fd: libc::c_int, __buf: *const libc::c_void, __n: size_t) -> ssize_t; + #[no_mangle] + fn execvp( + __file: *const libc::c_char, + __argv: *const *mut libc::c_char, + ) -> libc::c_int; + #[no_mangle] + fn execlp( + __file: *const libc::c_char, + __arg: *const libc::c_char, + _: ... + ) -> libc::c_int; + #[no_mangle] + fn fork() -> __pid_t; + #[no_mangle] + fn unlink(__name: *const libc::c_char) -> libc::c_int; + #[no_mangle] + fn __errno_location() -> *mut libc::c_int; + #[no_mangle] + static mut stderr: *mut FILE; + #[no_mangle] + fn fclose(__stream: *mut FILE) -> libc::c_int; + #[no_mangle] + fn fopen(_: *const libc::c_char, _: *const libc::c_char) -> *mut FILE; + #[no_mangle] + fn fprintf(_: *mut FILE, _: *const libc::c_char, _: ...) -> libc::c_int; + #[no_mangle] + fn printf(_: *const libc::c_char, _: ...) -> libc::c_int; + #[no_mangle] + fn snprintf( + _: *mut libc::c_char, + _: libc::c_ulong, + _: *const libc::c_char, + _: ... + ) -> libc::c_int; + #[no_mangle] + fn fgetc(__stream: *mut FILE) -> libc::c_int; + #[no_mangle] + fn fputs(__s: *const libc::c_char, __stream: *mut FILE) -> libc::c_int; + #[no_mangle] + fn puts(__s: *const libc::c_char) -> libc::c_int; + #[no_mangle] + fn calloc(_: libc::c_ulong, _: libc::c_ulong) -> *mut libc::c_void; + #[no_mangle] + fn free(__ptr: *mut libc::c_void); + #[no_mangle] + fn getenv(__name: *const libc::c_char) -> *mut libc::c_char; + #[no_mangle] + fn mkstemp(__template: *mut libc::c_char) -> libc::c_int; + #[no_mangle] + fn memset( + _: *mut libc::c_void, + _: libc::c_int, + _: libc::c_ulong, + ) -> *mut libc::c_void; + #[no_mangle] + fn strcpy(_: *mut libc::c_char, _: *const libc::c_char) -> *mut libc::c_char; + #[no_mangle] + fn strcmp(_: *const libc::c_char, _: *const libc::c_char) -> libc::c_int; + #[no_mangle] + fn strncmp( + _: *const libc::c_char, + _: *const libc::c_char, + _: libc::c_ulong, + ) -> libc::c_int; + #[no_mangle] + fn strdup(_: *const libc::c_char) -> *mut libc::c_char; + #[no_mangle] + fn strrchr(_: *const libc::c_char, _: libc::c_int) -> *mut libc::c_char; + #[no_mangle] + fn strcasecmp(_: *const libc::c_char, _: *const libc::c_char) -> libc::c_int; + #[no_mangle] + fn strlen(_: *const libc::c_char) -> libc::c_ulong; + #[no_mangle] + fn strerror(_: libc::c_int) -> *mut libc::c_char; +} +pub type __off_t = libc::c_long; +pub type __off64_t = libc::c_long; +pub type __pid_t = libc::c_int; +pub type __ssize_t = libc::c_long; +pub type __socklen_t = libc::c_uint; +pub type pid_t = __pid_t; +pub type ssize_t = __ssize_t; +pub type size_t = libc::c_ulong; +pub type socklen_t = __socklen_t; +pub type __socket_type = libc::c_uint; +pub const SOCK_NONBLOCK: __socket_type = 2048; +pub const SOCK_CLOEXEC: __socket_type = 524288; +pub const SOCK_PACKET: __socket_type = 10; +pub const SOCK_DCCP: __socket_type = 6; +pub const SOCK_SEQPACKET: __socket_type = 5; +pub const SOCK_RDM: __socket_type = 4; +pub const SOCK_RAW: __socket_type = 3; +pub const SOCK_DGRAM: __socket_type = 2; +pub const SOCK_STREAM: __socket_type = 1; +pub type sa_family_t = libc::c_ushort; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [libc::c_char; 14], +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct addrinfo { + pub ai_flags: libc::c_int, + pub ai_family: libc::c_int, + pub ai_socktype: libc::c_int, + pub ai_protocol: libc::c_int, + pub ai_addrlen: socklen_t, + pub ai_addr: *mut sockaddr, + pub ai_canonname: *mut libc::c_char, + pub ai_next: *mut addrinfo, +} +#[derive(Copy, Clone)] +#[repr(C)] +pub struct _IO_FILE { + pub _flags: libc::c_int, + pub _IO_read_ptr: *mut libc::c_char, + pub _IO_read_end: *mut libc::c_char, + pub _IO_read_base: *mut libc::c_char, + pub _IO_write_base: *mut libc::c_char, + pub _IO_write_ptr: *mut libc::c_char, + pub _IO_write_end: *mut libc::c_char, + pub _IO_buf_base: *mut libc::c_char, + pub _IO_buf_end: *mut libc::c_char, + pub _IO_save_base: *mut libc::c_char, + pub _IO_backup_base: *mut libc::c_char, + pub _IO_save_end: *mut libc::c_char, + pub _markers: *mut _IO_marker, + pub _chain: *mut _IO_FILE, + pub _fileno: libc::c_int, + pub _flags2: libc::c_int, + pub _old_offset: __off_t, + pub _cur_column: libc::c_ushort, + pub _vtable_offset: libc::c_schar, + pub _shortbuf: [libc::c_char; 1], + pub _lock: *mut libc::c_void, + pub _offset: __off64_t, + pub _codecvt: *mut _IO_codecvt, + pub _wide_data: *mut _IO_wide_data, + pub _freeres_list: *mut _IO_FILE, + pub _freeres_buf: *mut libc::c_void, + pub __pad5: size_t, + pub _mode: libc::c_int, + pub _unused2: [libc::c_char; 20], +} +pub type _IO_lock_t = (); +pub type FILE = _IO_FILE; + +/* structs */ +#[derive(Copy, Clone)] +pub struct Link { + pub next: *mut Link, + pub which: libc::c_char, + pub key: libc::c_short, + pub host: *mut libc::c_char, + pub port: *mut libc::c_char, + pub selector: *mut libc::c_char, +} +#[derive(Clone)] +pub struct Config { + pub start_uri: String, //[libc::c_char; 512], + pub cmd_text: String, //[libc::c_char; 512], + pub cmd_image: String, //[libc::c_char; 512], + pub cmd_browser: String, //[libc::c_char; 512], + pub cmd_player: String, //[libc::c_char; 512], + pub color_prompt: String, //[libc::c_char; 512], + pub color_selector: String, //[libc::c_char; 512], + pub verbose: String, //[libc::c_char; 512], +} + +pub static mut tmpfilename: [libc::c_char; 256] = [0; 256]; +pub static mut links: *mut Link = 0 as *const Link as *mut Link; +pub static mut history: *mut Link = 0 as *const Link as *mut Link; +pub static mut link_key: libc::c_int = 0; +pub static mut current_host: [libc::c_char; 512] = [0; 512]; +pub static mut current_port: [libc::c_char; 64] = [0; 64]; +pub static mut current_selector: [libc::c_char; 1024] = [0; 1024]; +pub static mut parsed_host: [libc::c_char; 512] = [0; 512]; +pub static mut parsed_port: [libc::c_char; 64] = [0; 64]; +pub static mut parsed_selector: [libc::c_char; 1024] = [0; 1024]; +pub static mut bookmarks: [[libc::c_char; 512]; 20] = [[0; 512]; 20]; + +lazy_static! { + pub static ref config: Config = Config { + start_uri: String::from("gopher://gopher.floodgap.com:70"), + cmd_text: String::from("less"), + cmd_image: String::from("display"), + cmd_browser: String::from("firefox"), + cmd_player: String::from("mplayer"), + color_prompt: String::from("1;34"), + color_selector: String::from("1;32"), + verbose: String::from("true"), + }; +} + +/* implementation */ +pub fn usage() { + eprintln!("usage: cgo [-v] [-H] [gopher URI]"); + exit(0); +} +#[no_mangle] +pub fn banner(to_error: bool) { + if to_error { + eprintln!("cgo 0.6.1 Copyright (c) 2020 Sebastian Steinhauer"); + } else { + println!("cgo 0.6.1 Copyright (c) 2020 Sebastian Steinhauer"); + } +} +#[no_mangle] +pub unsafe extern "C" fn check_option_true( + mut option: *const libc::c_char, +) -> libc::c_int { + return (strcasecmp(option, b"false\x00" as *const u8 as *const libc::c_char) != 0 + && strcasecmp(option, b"off\x00" as *const u8 as *const libc::c_char) != 0) + as libc::c_int; +} +#[no_mangle] +pub unsafe extern "C" fn parse_config_line(mut line: *const libc::c_char) { + let mut token: [libc::c_char; 1024] = [0; 1024]; + let mut bkey: [libc::c_char; 128] = [0; 128]; + let mut value: *mut libc::c_char = 0 as *mut libc::c_char; + let mut i: libc::c_int = 0; + let mut j: libc::c_int = 0; + while *line as libc::c_int == ' ' as i32 || *line as libc::c_int == '\t' as i32 { + line = line.offset(1) + } + i = 0 as libc::c_int; + while *line as libc::c_int != 0 + && *line as libc::c_int != ' ' as i32 + && *line as libc::c_int != '\t' as i32 + { + if (i as libc::c_ulong) + < (mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong) + .wrapping_sub(1 as libc::c_int as libc::c_ulong) + { + let fresh0 = i; + i = i + 1; + token[fresh0 as usize] = *line + } + line = line.offset(1) + } + token[i as usize] = 0 as libc::c_int as libc::c_char; + if strcmp(token.as_mut_ptr(), b"start_uri\x00" as *const u8 as *const libc::c_char) + == 0 + { + value = CString::new(config.start_uri.clone()).unwrap().into_raw(); + } else if strcmp( + token.as_mut_ptr(), + b"cmd_text\x00" as *const u8 as *const libc::c_char, + ) == 0 + { + value = CString::new(config.cmd_text.clone()).unwrap().into_raw(); + } else if strcmp( + token.as_mut_ptr(), + b"cmd_browser\x00" as *const u8 as *const libc::c_char, + ) == 0 + { + value = CString::new(config.cmd_browser.clone()).unwrap().into_raw(); + } else if strcmp( + token.as_mut_ptr(), + b"cmd_image\x00" as *const u8 as *const libc::c_char, + ) == 0 + { + value = CString::new(config.cmd_image.clone()).unwrap().into_raw(); + } else if strcmp( + token.as_mut_ptr(), + b"cmd_player\x00" as *const u8 as *const libc::c_char, + ) == 0 + { + value = CString::new(config.cmd_player.clone()).unwrap().into_raw(); + } else if strcmp( + token.as_mut_ptr(), + b"color_prompt\x00" as *const u8 as *const libc::c_char, + ) == 0 + { + value = CString::new(config.color_prompt.clone()).unwrap().into_raw(); + } else if strcmp( + token.as_mut_ptr(), + b"color_selector\x00" as *const u8 as *const libc::c_char, + ) == 0 + { + value = CString::new(config.color_selector.clone()).unwrap().into_raw(); + } else if strcmp( + token.as_mut_ptr(), + b"verbose\x00" as *const u8 as *const libc::c_char, + ) == 0 + { + value = CString::new(config.verbose.clone()).unwrap().into_raw(); + } else { + j = 0 as libc::c_int; + while j < 20 as libc::c_int { + snprintf( + bkey.as_mut_ptr(), + mem::size_of::<[libc::c_char; 128]>() as libc::c_ulong, + b"bookmark%d\x00" as *const u8 as *const libc::c_char, + j + 1 as libc::c_int, + ); + if strcmp(token.as_mut_ptr(), bkey.as_mut_ptr()) == 0 { + value = &mut *(*bookmarks.as_mut_ptr().offset(j as isize)) + .as_mut_ptr() + .offset(0 as libc::c_int as isize) as *mut libc::c_char; + break; + } else { + j += 1 + } + } + if value.is_null() { + return; + } + } + while *line as libc::c_int == ' ' as i32 || *line as libc::c_int == '\t' as i32 { + line = line.offset(1) + } + i = 0 as libc::c_int; + while *line != 0 { + if i < 512 as libc::c_int - 1 as libc::c_int { + let fresh1 = i; + i = i + 1; + *value.offset(fresh1 as isize) = *line + } + line = line.offset(1) + } + i -= 1; + while i > 0 as libc::c_int + && (*value.offset(i as isize) as libc::c_int == ' ' as i32 + || *value.offset(i as isize) as libc::c_int == '\t' as i32) + { + i -= 1 + } + i += 1; + *value.offset(i as isize) = 0 as libc::c_int as libc::c_char; +} +#[no_mangle] +pub unsafe extern "C" fn load_config(mut filename: *const libc::c_char) { + let mut fp: *mut FILE = 0 as *mut FILE; + let mut ch: libc::c_int = 0; + let mut i: libc::c_int = 0; + let mut line: [libc::c_char; 1024] = [0; 1024]; + fp = fopen(filename, b"r\x00" as *const u8 as *const libc::c_char); + if fp.is_null() { + return; + } + memset( + line.as_mut_ptr() as *mut libc::c_void, + 0 as libc::c_int, + mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong, + ); + i = 0 as libc::c_int; + ch = fgetc(fp); + loop { + match ch { + 35 => + while ch != '\n' as i32 && ch != -(1 as libc::c_int) { + ch = fgetc(fp) + }, + -1 => { + parse_config_line(line.as_mut_ptr()); + fclose(fp); + return; + } + 13 => ch = fgetc(fp), + 10 => { + parse_config_line(line.as_mut_ptr()); + memset( + line.as_mut_ptr() as *mut libc::c_void, + 0 as libc::c_int, + mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong, + ); + i = 0 as libc::c_int; + ch = fgetc(fp) + } + _ => { + if (i as libc::c_ulong) + < (mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong) + .wrapping_sub(1 as libc::c_int as libc::c_ulong) + { + let fresh2 = i; + i = i + 1; + line[fresh2 as usize] = ch as libc::c_char + } + ch = fgetc(fp) + } + } + } +} +pub unsafe extern "C" fn init_config() { + let mut filename: [libc::c_char; 1024] = [0; 1024]; + let mut home: *const libc::c_char = 0 as *const libc::c_char; + let mut i: libc::c_int = 0; + /* copy defaults */ + snprintf( + CString::new(config.start_uri.clone()).unwrap().into_raw(), + mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong, + b"gopher://gopher.floodgap.com:70\x00" as *const u8 as *const libc::c_char, + ); + snprintf( + CString::new(config.cmd_text.clone()).unwrap().into_raw(), + mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, + b"less\x00" as *const u8 as *const libc::c_char, + ); + snprintf( + CString::new(config.cmd_image.clone()).unwrap().into_raw(), + mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, + b"display\x00" as *const u8 as *const libc::c_char, + ); + snprintf( + CString::new(config.cmd_browser.clone()).unwrap().into_raw(), + mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, + b"firefox\x00" as *const u8 as *const libc::c_char, + ); + snprintf( + CString::new(config.cmd_player.clone()).unwrap().into_raw(), + mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, + b"mplayer\x00" as *const u8 as *const libc::c_char, + ); + snprintf( + CString::new(config.color_prompt.clone()).unwrap().into_raw(), + mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, + b"1;34\x00" as *const u8 as *const libc::c_char, + ); + snprintf( + CString::new(config.color_selector.clone()).unwrap().into_raw(), + mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, + b"1;32\x00" as *const u8 as *const libc::c_char, + ); + snprintf( + CString::new(config.verbose.clone()).unwrap().into_raw(), + mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, + b"true\x00" as *const u8 as *const libc::c_char, + ); + i = 0 as libc::c_int; + while i < 20 as libc::c_int { + bookmarks[i as usize][0 as libc::c_int as usize] = + 0 as libc::c_int as libc::c_char; + i += 1 + } + /* read configs */ + load_config(b"/etc/cgorc\x00" as *const u8 as *const libc::c_char); /* ignore incomplete selectors */ + home = getenv(b"HOME\x00" as *const u8 as *const libc::c_char); /* not needed for history...just clear them */ + if !home.is_null() { + snprintf( + filename.as_mut_ptr(), + mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong, + b"%s%s\x00" as *const u8 as *const libc::c_char, + home, + b"/.cgorc\x00" as *const u8 as *const libc::c_char, + ); + load_config(filename.as_mut_ptr()); + }; +} +pub unsafe extern "C" fn dial( + mut host: *const libc::c_char, + mut port: *const libc::c_char, + mut selector: *const libc::c_char, +) -> libc::c_int { + let mut hints: addrinfo = addrinfo { + ai_flags: 0, + ai_family: 0, + ai_socktype: 0, + ai_protocol: 0, + ai_addrlen: 0, + ai_addr: 0 as *mut sockaddr, + ai_canonname: 0 as *mut libc::c_char, + ai_next: 0 as *mut addrinfo, + }; + let mut res: *mut addrinfo = 0 as *mut addrinfo; + let mut r: *mut addrinfo = 0 as *mut addrinfo; + let mut srv: libc::c_int = -(1 as libc::c_int); + let mut l: libc::c_int = 0; + let mut request: [libc::c_char; 512] = [0; 512]; + memset( + &mut hints as *mut addrinfo as *mut libc::c_void, + 0 as libc::c_int, + mem::size_of::() as libc::c_ulong, + ); + hints.ai_family = 0 as libc::c_int; + hints.ai_socktype = SOCK_STREAM as libc::c_int; + if getaddrinfo(host, port, &mut hints, &mut res) != 0 as libc::c_int { + eprintln!( + "error: cannot resolve hostname '{}:{}': {}", + CStr::from_ptr(host).to_str().unwrap(), + CStr::from_ptr(port).to_str().unwrap(), + CStr::from_ptr(strerror(*__errno_location())).to_str().unwrap() + ); + return -(1 as libc::c_int); + } + r = res; + while !r.is_null() { + srv = socket((*r).ai_family, (*r).ai_socktype, (*r).ai_protocol); + if !(srv == -(1 as libc::c_int)) { + if connect(srv, (*r).ai_addr, (*r).ai_addrlen) == 0 as libc::c_int { + break; + } + close(srv); + } + r = (*r).ai_next + } + freeaddrinfo(res); + if r.is_null() { + fprintf( + stderr, + b"error: cannot connect to host \'%s:%s\'\n\x00" as *const u8 + as *const libc::c_char, + host, + port, + ); + return -(1 as libc::c_int); + } + snprintf( + request.as_mut_ptr(), + mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong, + b"%s\r\n\x00" as *const u8 as *const libc::c_char, + selector, + ); + l = strlen(request.as_mut_ptr()) as libc::c_int; + if write(srv, request.as_mut_ptr() as *const libc::c_void, l as size_t) + != l as libc::c_long + { + fprintf( + stderr, + b"error: cannot complete request\n\x00" as *const u8 as *const libc::c_char, + ); + close(srv); + return -(1 as libc::c_int); + } + return srv; +} +pub unsafe extern "C" fn read_line( + mut fd: libc::c_int, + mut buf: *mut libc::c_char, + mut buf_len: size_t, +) -> libc::c_int { + let mut i: size_t = 0 as libc::c_int as size_t; + let mut c: libc::c_char = 0 as libc::c_int as libc::c_char; + loop { + if read( + fd, + &mut c as *mut libc::c_char as *mut libc::c_void, + mem::size_of::() as libc::c_ulong, + ) as libc::c_ulong + != mem::size_of::() as libc::c_ulong + { + return 0 as libc::c_int; + } + if c as libc::c_int != '\r' as i32 { + let fresh3 = i; + i = i.wrapping_add(1); + *buf.offset(fresh3 as isize) = c + } + if !(c as libc::c_int != '\n' as i32 && i < buf_len) { + break; + } + } + *buf.offset(i.wrapping_sub(1 as libc::c_int as libc::c_ulong) as isize) = + '\u{0}' as i32 as libc::c_char; + return 1 as libc::c_int; +} +pub unsafe extern "C" fn download_file( + mut host: *const libc::c_char, + mut port: *const libc::c_char, + mut selector: *const libc::c_char, + mut fd: libc::c_int, +) -> libc::c_int { + let mut srvfd: libc::c_int = 0; + let mut len: libc::c_int = 0; + let mut total: libc::c_ulong = 0 as libc::c_int as libc::c_ulong; + let mut buffer: [libc::c_char; 4096] = [0; 4096]; + if check_option_true(CString::new(config.verbose.clone()).unwrap().into_raw()) != 0 { + printf( + b"downloading [%s]...\r\x00" as *const u8 as *const libc::c_char, + selector, + ); + } + srvfd = dial(host, port, selector); + if srvfd == -(1 as libc::c_int) { + printf( + b"\x1b[2Kerror: downloading [%s] failed\n\x00" as *const u8 + as *const libc::c_char, + selector, + ); + close(fd); + return 0 as libc::c_int; + } + loop { + len = read( + srvfd, + buffer.as_mut_ptr() as *mut libc::c_void, + mem::size_of::<[libc::c_char; 4096]>() as libc::c_ulong, + ) as libc::c_int; + if !(len > 0 as libc::c_int) { + break; + } + write(fd, buffer.as_mut_ptr() as *const libc::c_void, len as size_t); + total = total.wrapping_add(len as libc::c_ulong); + if check_option_true(CString::new(config.verbose.clone()).unwrap().into_raw()) != 0 { + printf( + b"downloading [%s] (%ld kb)...\r\x00" as *const u8 as *const libc::c_char, + selector, + total.wrapping_div(1024 as libc::c_int as libc::c_ulong), + ); + } + } + close(fd); + close(srvfd); + if check_option_true(CString::new(config.verbose.clone()).unwrap().into_raw()) != 0 { + printf( + b"\x1b[2Kdownloading [%s] complete\n\x00" as *const u8 as *const libc::c_char, + selector, + ); + } + return 1 as libc::c_int; +} +pub unsafe extern "C" fn download_temp( + mut host: *const libc::c_char, + mut port: *const libc::c_char, + mut selector: *const libc::c_char, +) -> libc::c_int { + let mut tmpfd: libc::c_int = 0; + strcpy( + tmpfilename.as_mut_ptr(), + b"/tmp/cgoXXXXXX\x00" as *const u8 as *const libc::c_char, + ); + tmpfd = mkstemp(tmpfilename.as_mut_ptr()); + if tmpfd == -(1 as libc::c_int) { + fputs( + b"error: unable to create tmp file\n\x00" as *const u8 as *const libc::c_char, + stderr, + ); + return 0 as libc::c_int; + } + if download_file(host, port, selector, tmpfd) == 0 { + unlink(tmpfilename.as_mut_ptr()); + return 0 as libc::c_int; + } + return 1 as libc::c_int; +} +pub unsafe extern "C" fn make_key( + mut c1: libc::c_char, + mut c2: libc::c_char, + mut c3: libc::c_char, +) -> libc::c_int { + if c1 == 0 || c2 == 0 { + return -(1 as libc::c_int); + } + if c3 == 0 { + return (c1 as libc::c_int - 'a' as i32) + * ('z' as i32 - 'a' as i32 + 1 as libc::c_int) + + (c2 as libc::c_int - 'a' as i32); + } else { + return (c1 as libc::c_int - 'a' as i32 + 1 as libc::c_int) + * ('z' as i32 - 'a' as i32 + 1 as libc::c_int) + * ('z' as i32 - 'a' as i32 + 1 as libc::c_int) + + (c2 as libc::c_int - 'a' as i32) + * ('z' as i32 - 'a' as i32 + 1 as libc::c_int) + + (c3 as libc::c_int - 'a' as i32); + }; +} +pub unsafe extern "C" fn make_key_str( + mut key: libc::c_int, + mut c1: *mut libc::c_char, + mut c2: *mut libc::c_char, + mut c3: *mut libc::c_char, +) { + if key + < ('z' as i32 - 'a' as i32 + 1 as libc::c_int) + * ('z' as i32 - 'a' as i32 + 1 as libc::c_int) + { + *c1 = ('a' as i32 + key / ('z' as i32 - 'a' as i32 + 1 as libc::c_int)) + as libc::c_char; + *c2 = ('a' as i32 + key % ('z' as i32 - 'a' as i32 + 1 as libc::c_int)) + as libc::c_char; + *c3 = 0 as libc::c_int as libc::c_char + } else { + *c1 = ('a' as i32 + + key + / (('z' as i32 - 'a' as i32 + 1 as libc::c_int) + * ('z' as i32 - 'a' as i32 + 1 as libc::c_int)) + - 1 as libc::c_int) as libc::c_char; + *c2 = ('a' as i32 + + key / ('z' as i32 - 'a' as i32 + 1 as libc::c_int) + % ('z' as i32 - 'a' as i32 + 1 as libc::c_int)) as libc::c_char; + *c3 = ('a' as i32 + key % ('z' as i32 - 'a' as i32 + 1 as libc::c_int)) + as libc::c_char + }; +} +pub unsafe extern "C" fn add_link( + mut which: libc::c_char, + mut name: *const libc::c_char, + mut host: *const libc::c_char, + mut port: *const libc::c_char, + mut selector: *const libc::c_char, +) { + let mut link: *mut Link = 0 as *mut Link; + let mut a: libc::c_char = 0 as libc::c_int as libc::c_char; + let mut b: libc::c_char = 0 as libc::c_int as libc::c_char; + let mut c: libc::c_char = 0 as libc::c_int as libc::c_char; + if host.is_null() || port.is_null() || selector.is_null() { + return; + } + link = calloc( + 1 as libc::c_int as libc::c_ulong, + mem::size_of::() as libc::c_ulong, + ) as *mut Link; + (*link).which = which; + (*link).key = link_key as libc::c_short; + (*link).host = strdup(host); + (*link).port = strdup(port); + (*link).selector = strdup(selector); + if links.is_null() { + (*link).next = 0 as *mut Link + } else { + (*link).next = links + } + links = link; + let fresh4 = link_key; + link_key = link_key + 1; + make_key_str(fresh4, &mut a, &mut b, &mut c); + printf( + b"\x1b[%sm%c%c%c\x1b[0m \x1b[1m%s\x1b[0m\n\x00" as *const u8 + as *const libc::c_char, + CString::new(config.color_selector.clone()).unwrap().into_raw(), + a as libc::c_int, + b as libc::c_int, + c as libc::c_int, + name, + ); +} +pub unsafe extern "C" fn clear_links() { + let mut link: *mut Link = 0 as *mut Link; + let mut next: *mut Link = 0 as *mut Link; + link = links; + while !link.is_null() { + next = (*link).next; + free((*link).host as *mut libc::c_void); + free((*link).port as *mut libc::c_void); + free((*link).selector as *mut libc::c_void); + free(link as *mut libc::c_void); + link = next + } + links = 0 as *mut Link; + link_key = 0 as libc::c_int; +} +pub unsafe extern "C" fn add_history() { + let mut link: *mut Link = 0 as *mut Link; + link = calloc( + 1 as libc::c_int as libc::c_ulong, + mem::size_of::() as libc::c_ulong, + ) as *mut Link; + (*link).host = strdup(current_host.as_mut_ptr()); + (*link).port = strdup(current_port.as_mut_ptr()); + (*link).selector = strdup(current_selector.as_mut_ptr()); + (*link).which = 0 as libc::c_int as libc::c_char; + (*link).key = 0 as libc::c_int as libc::c_short; + if history.is_null() { + (*link).next = 0 as *mut Link + } else { + (*link).next = history + } + history = link; +} +pub unsafe extern "C" fn handle_directory_line(mut line: *mut libc::c_char) { + let mut i: libc::c_int = 0; + let mut lp: *mut libc::c_char = 0 as *mut libc::c_char; + let mut last: *mut libc::c_char = 0 as *mut libc::c_char; + let mut fields: [*mut libc::c_char; 4] = [0 as *mut libc::c_char; 4]; + /* tokenize */ + i = 0 as libc::c_int; + while i < 4 as libc::c_int { + fields[i as usize] = 0 as *mut libc::c_char; + i += 1 + } + last = &mut *line.offset(1 as libc::c_int as isize) as *mut libc::c_char; + lp = last; + i = 0 as libc::c_int; + while i < 4 as libc::c_int { + if *lp as libc::c_int == '\t' as i32 || *lp as libc::c_int == '\u{0}' as i32 { + fields[i as usize] = last; + last = lp.offset(1 as libc::c_int as isize); + if *lp as libc::c_int == '\u{0}' as i32 { + break; + } + *lp = '\u{0}' as i32 as libc::c_char; + i += 1 + } + lp = lp.offset(1) + } + /* determine listing type */ + match *line.offset(0 as libc::c_int as isize) as libc::c_int { + 105 | 51 => { + printf( + b" %s\n\x00" as *const u8 as *const libc::c_char, + fields[0 as libc::c_int as usize], + ); + } + 46 => { + /* some gopher servers use this */ + puts(b"\x00" as *const u8 as *const libc::c_char); + } + 48 | 49 | 53 | 55 | 56 | 57 | 103 | 73 | 112 | 104 | 115 => { + add_link( + *line.offset(0 as libc::c_int as isize), + fields[0 as libc::c_int as usize], + fields[2 as libc::c_int as usize], + fields[3 as libc::c_int as usize], + fields[1 as libc::c_int as usize], + ); + } + _ => { + printf( + b"miss [%c]: %s\n\x00" as *const u8 as *const libc::c_char, + *line.offset(0 as libc::c_int as isize) as libc::c_int, + fields[0 as libc::c_int as usize], + ); + } + }; +} +pub unsafe extern "C" fn is_valid_directory_entry( + mut line: *const libc::c_char, +) -> libc::c_int { + match *line.offset(0 as libc::c_int as isize) as libc::c_int { + 105 | 51 | 46 | 48 | 49 | 53 | 55 | 56 | 57 | 103 | 73 | 112 | 104 | 115 => { + /* some gopher servers use this */ + return 1 as libc::c_int; + } + _ => return 0 as libc::c_int, + }; +} +pub unsafe extern "C" fn view_directory( + mut host: *const libc::c_char, + mut port: *const libc::c_char, + mut selector: *const libc::c_char, + mut make_current: libc::c_int, +) { + let mut is_dir: libc::c_int = 0; + let mut srvfd: libc::c_int = 0; + let mut i: libc::c_int = 0; + let mut head_read: libc::c_int = 0; + let mut line: [libc::c_char; 1024] = [0; 1024]; + let mut head: [[libc::c_char; 1024]; 5] = [[0; 1024]; 5]; + srvfd = dial(host, port, selector); + if srvfd != -(1 as libc::c_int) { + /* only adapt current prompt when successful */ + /* make history entry */ + if make_current != 0 { + add_history(); + } + /* don't overwrite the current_* things... */ + if host != current_host.as_mut_ptr() as *const libc::c_char { + snprintf( + current_host.as_mut_ptr(), + mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, + host, + ); /* clear links *AFTER* dialing out!! */ + } /* quit if not successful */ + if port != current_port.as_mut_ptr() as *const libc::c_char { + snprintf( + current_port.as_mut_ptr(), + mem::size_of::<[libc::c_char; 64]>() as libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, + port, + ); + } + if selector != current_selector.as_mut_ptr() as *const libc::c_char { + snprintf( + current_selector.as_mut_ptr(), + mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, + selector, + ); + } + } + clear_links(); + if srvfd == -(1 as libc::c_int) { + return; + } + head_read = 0 as libc::c_int; + is_dir = 1 as libc::c_int; + while head_read < 5 as libc::c_int + && read_line( + srvfd, + line.as_mut_ptr(), + mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong, + ) != 0 + { + strcpy(head[head_read as usize].as_mut_ptr(), line.as_mut_ptr()); + if is_valid_directory_entry(head[head_read as usize].as_mut_ptr()) == 0 { + is_dir = 0 as libc::c_int; + break; + } else { + head_read += 1 + } + } + if is_dir == 0 { + puts(b"error: Not a directory.\x00" as *const u8 as *const libc::c_char); + close(srvfd); + return; + } + i = 0 as libc::c_int; + while i < head_read { + handle_directory_line(head[i as usize].as_mut_ptr()); + i += 1 + } + while read_line( + srvfd, + line.as_mut_ptr(), + mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong, + ) != 0 + { + handle_directory_line(line.as_mut_ptr()); + } + close(srvfd); +} +pub unsafe extern "C" fn view_file( + mut cmd: *const libc::c_char, + mut host: *const libc::c_char, + mut port: *const libc::c_char, + mut selector: *const libc::c_char, +) { + let mut pid: pid_t = 0; + let mut status: libc::c_int = 0; + let mut i: libc::c_int = 0; + let mut j: libc::c_int = 0; + let mut buffer: [libc::c_char; 1024] = [0; 1024]; + let mut argv: [*mut libc::c_char; 32] = [0 as *mut libc::c_char; 32]; + let mut p: *mut libc::c_char = 0 as *mut libc::c_char; + if check_option_true(CString::new(config.verbose.clone()).unwrap().into_raw()) != 0 { + printf( + b"h(%s) p(%s) s(%s)\n\x00" as *const u8 as *const libc::c_char, + host, + port, + selector, + ); + } + if download_temp(host, port, selector) == 0 { + return; + } + /* parsed command line string */ + argv[0 as libc::c_int as usize] = + &mut *buffer.as_mut_ptr().offset(0 as libc::c_int as isize) as *mut libc::c_char; + p = cmd as *mut libc::c_char; + i = 0 as libc::c_int; + j = 1 as libc::c_int; + while *p as libc::c_int != 0 + && (i as libc::c_ulong) + < (mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong) + .wrapping_sub(1 as libc::c_int as libc::c_ulong) + && j < 30 as libc::c_int + { + if *p as libc::c_int == ' ' as i32 || *p as libc::c_int == '\t' as i32 { + let fresh5 = i; + i = i + 1; + buffer[fresh5 as usize] = 0 as libc::c_int as libc::c_char; + let fresh6 = j; + j = j + 1; + argv[fresh6 as usize] = + &mut *buffer.as_mut_ptr().offset(i as isize) as *mut libc::c_char; + while *p as libc::c_int == ' ' as i32 || *p as libc::c_int == '\t' as i32 { + p = p.offset(1) + } + } else { + let fresh7 = p; + p = p.offset(1); + let fresh8 = i; + i = i + 1; + buffer[fresh8 as usize] = *fresh7 + } + } + buffer[i as usize] = 0 as libc::c_int as libc::c_char; + let fresh9 = j; + j = j + 1; + argv[fresh9 as usize] = tmpfilename.as_mut_ptr(); + argv[j as usize] = 0 as *mut libc::c_char; + /* fork and execute */ + if check_option_true(CString::new(config.verbose.clone()).unwrap().into_raw()) != 0 { + printf( + b"executing: %s %s\n\x00" as *const u8 as *const libc::c_char, + cmd, + tmpfilename.as_mut_ptr(), + ); /* to wait for browsers etc. that return immediatly */ + } + pid = fork(); + if pid == 0 as libc::c_int { + if execvp( + argv[0 as libc::c_int as usize], + argv.as_mut_ptr() as *const *mut libc::c_char, + ) == -(1 as libc::c_int) + { + puts(b"error: execvp() failed!\x00" as *const u8 as *const libc::c_char); + } + } else if pid == -(1 as libc::c_int) { + puts(b"error: fork() failed\x00" as *const u8 as *const libc::c_char); + } + sleep(Duration::from_secs(1)); + waitpid(pid, &mut status, 0 as libc::c_int); + unlink(tmpfilename.as_mut_ptr()); +} +pub unsafe extern "C" fn view_telnet( + mut host: *const libc::c_char, + mut port: *const libc::c_char, +) { + let mut pid: pid_t = 0; + let mut status: libc::c_int = 0; + printf( + b"executing: %s %s %s\n\x00" as *const u8 as *const libc::c_char, + b"telnet\x00" as *const u8 as *const libc::c_char, + host, + port, + ); + pid = fork(); + if pid == 0 as libc::c_int { + if execlp( + b"telnet\x00" as *const u8 as *const libc::c_char, + b"telnet\x00" as *const u8 as *const libc::c_char, + host, + port, + 0 as *mut libc::c_void, + ) == -(1 as libc::c_int) + { + puts(b"error: execlp() failed!\x00" as *const u8 as *const libc::c_char); + } + } else if pid == -(1 as libc::c_int) { + puts(b"error: fork() failed!\x00" as *const u8 as *const libc::c_char); + } + waitpid(pid, &mut status, 0 as libc::c_int); + puts(b"(done)\x00" as *const u8 as *const libc::c_char); +} +pub unsafe extern "C" fn view_download( + mut host: *const libc::c_char, + mut port: *const libc::c_char, + mut selector: *const libc::c_char, +) { + let mut fd: libc::c_int = 0; + let mut filename: [libc::c_char; 1024] = [0; 1024]; + let mut line: [libc::c_char; 1024] = [0; 1024]; + snprintf( + filename.as_mut_ptr(), + mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong, + b"%s\x00" as *const u8 as *const libc::c_char, + strrchr(selector, '/' as i32).offset(1 as libc::c_int as isize), + ); + printf( + b"enter filename for download [%s]: \x00" as *const u8 as *const libc::c_char, + filename.as_mut_ptr(), + ); + if read_line( + 0 as libc::c_int, + line.as_mut_ptr(), + mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong, + ) == 0 + { + puts(b"download aborted\x00" as *const u8 as *const libc::c_char); + return; + } + if strlen(line.as_mut_ptr()) > 0 as libc::c_int as libc::c_ulong { + strcpy(filename.as_mut_ptr(), line.as_mut_ptr()); + } + fd = open( + filename.as_mut_ptr(), + 0o100 as libc::c_int | 0o1 as libc::c_int, + 0o400 as libc::c_int | 0o200 as libc::c_int, + ); + if fd == -(1 as libc::c_int) { + printf( + b"error: unable to create file [%s]: %s\n\x00" as *const u8 + as *const libc::c_char, + filename.as_mut_ptr(), + strerror(*__errno_location()), + ); + return; + } + if download_file(host, port, selector, fd) == 0 { + printf( + b"error: unable to download [%s]\n\x00" as *const u8 as *const libc::c_char, + selector, + ); + unlink(filename.as_mut_ptr()); + return; + }; +} +pub unsafe extern "C" fn view_search( + mut host: *const libc::c_char, + mut port: *const libc::c_char, + mut selector: *const libc::c_char, +) { + let mut search_selector: [libc::c_char; 1024] = [0; 1024]; + let mut line: [libc::c_char; 1024] = [0; 1024]; + printf(b"enter search string: \x00" as *const u8 as *const libc::c_char); + if read_line( + 0 as libc::c_int, + line.as_mut_ptr(), + mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong, + ) == 0 + { + puts(b"search aborted\x00" as *const u8 as *const libc::c_char); + return; + } + snprintf( + search_selector.as_mut_ptr(), + mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong, + b"%s\t%s\x00" as *const u8 as *const libc::c_char, + selector, + line.as_mut_ptr(), + ); + view_directory(host, port, search_selector.as_mut_ptr(), 1 as libc::c_int); +} +pub unsafe extern "C" fn view_history(mut key: libc::c_int) { + let mut history_key: libc::c_int = 0 as libc::c_int; + let mut a: libc::c_char = 0; + let mut b: libc::c_char = 0; + let mut c: libc::c_char = 0; + let mut link: *mut Link = 0 as *mut Link; + if history.is_null() { + puts(b"(empty history)\x00" as *const u8 as *const libc::c_char); + return; + } + if key < 0 as libc::c_int { + puts(b"(history)\x00" as *const u8 as *const libc::c_char); + link = history; + while !link.is_null() { + let fresh10 = history_key; + history_key = history_key + 1; + make_key_str(fresh10, &mut a, &mut b, &mut c); + printf( + b"\x1b[%sm%c%c%c\x1b[0m \x1b[1m%s:%s/1%s\x1b[0m\n\x00" as *const u8 + as *const libc::c_char, + b"1;32\x00" as *const u8 as *const libc::c_char, + a as libc::c_int, + b as libc::c_int, + c as libc::c_int, + (*link).host, + (*link).port, + (*link).selector, + ); + link = (*link).next + } + } else { + /* traverse history list */ + link = history; + while !link.is_null() { + if history_key == key { + view_directory( + (*link).host, + (*link).port, + (*link).selector, + 0 as libc::c_int, + ); + return; + } + link = (*link).next; + history_key += 1 + } + puts(b"history item not found\x00" as *const u8 as *const libc::c_char); + }; +} +pub unsafe extern "C" fn view_bookmarks(mut key: libc::c_int) { + let mut i: libc::c_int = 0; + let mut a: libc::c_char = 0; + let mut b: libc::c_char = 0; + let mut c: libc::c_char = 0; + if key < 0 as libc::c_int { + puts(b"(bookmarks)\x00" as *const u8 as *const libc::c_char); + i = 0 as libc::c_int; + while i < 20 as libc::c_int { + if bookmarks[i as usize][0 as libc::c_int as usize] != 0 { + make_key_str(i, &mut a, &mut b, &mut c); + printf( + b"\x1b[%sm%c%c%c\x1b[0m \x1b[1m%s\x1b[0m\n\x00" as *const u8 + as *const libc::c_char, + b"1;32\x00" as *const u8 as *const libc::c_char, + a as libc::c_int, + b as libc::c_int, + c as libc::c_int, + &mut *(*bookmarks.as_mut_ptr().offset(i as isize)) + .as_mut_ptr() + .offset(0 as libc::c_int as isize) as *mut libc::c_char, + ); + } + i += 1 + } + } else { + i = 0 as libc::c_int; + while i < 20 as libc::c_int { + if bookmarks[i as usize][0 as libc::c_int as usize] as libc::c_int != 0 + && i == key + { + if parse_uri( + &mut *(*bookmarks.as_mut_ptr().offset(i as isize)) + .as_mut_ptr() + .offset(0 as libc::c_int as isize), + ) != 0 + { + view_directory( + parsed_host.as_mut_ptr(), + parsed_port.as_mut_ptr(), + parsed_selector.as_mut_ptr(), + 0 as libc::c_int, + ); + } else { + printf( + b"invalid gopher URI: %s\x00" as *const u8 as *const libc::c_char, + &mut *(*bookmarks.as_mut_ptr().offset(i as isize)) + .as_mut_ptr() + .offset(0 as libc::c_int as isize) as *mut libc::c_char, + ); + } + return; + } + i += 1 + } + }; +} +pub unsafe extern "C" fn pop_history() { + let mut next: *mut Link = 0 as *mut Link; + if history.is_null() { + puts(b"(empty history)\x00" as *const u8 as *const libc::c_char); + return; + } + /* reload page from history (and don't count as history) */ + view_directory( + (*history).host, + (*history).port, + (*history).selector, + 0 as libc::c_int, + ); + /* history is history... :) */ + next = (*history).next; + free((*history).host as *mut libc::c_void); + free((*history).port as *mut libc::c_void); + free((*history).selector as *mut libc::c_void); + free(history as *mut libc::c_void); + history = next; +} +pub unsafe extern "C" fn follow_link(mut key: libc::c_int) -> libc::c_int { + let mut link: *mut Link = 0 as *mut Link; + link = links; + while !link.is_null() { + if (*link).key as libc::c_int != key { + link = (*link).next + } else { + match (*link).which as libc::c_int { + 48 => { + view_file( + CString::new(config.cmd_text.clone()) + .unwrap() + .into_raw(), + (*link).host, + (*link).port, + (*link).selector, + ); + } + 49 => { + view_directory( + (*link).host, + (*link).port, + (*link).selector, + 1 as libc::c_int, + ); + } + 55 => { + view_search((*link).host, (*link).port, (*link).selector); + } + 53 | 57 => { + view_download((*link).host, (*link).port, (*link).selector); + } + 56 => { + view_telnet((*link).host, (*link).port); + } + 103 | 73 | 112 => { + view_file( + CString::new(config.cmd_image.clone()) + .unwrap() + .into_raw(), + (*link).host, + (*link).port, + (*link).selector, + ); + } + 104 => { + view_file( + CString::new(config.cmd_browser.clone()) + .unwrap() + .into_raw(), + (*link).host, + (*link).port, + (*link).selector, + ); + } + 115 => { + view_file( + CString::new(config.cmd_player.clone()) + .unwrap() + .into_raw(), + (*link).host, + (*link).port, + (*link).selector, + ); + } + _ => { + printf( + b"missing handler [%c]\n\x00" as *const u8 as *const libc::c_char, + (*link).which as libc::c_int, + ); + } + } + return 1 as libc::c_int; + } + /* return the array is broken after view! */ + } + return 0 as libc::c_int; +} +pub unsafe extern "C" fn download_link(mut key: libc::c_int) { + let mut link: *mut Link = 0 as *mut Link; + link = links; + while !link.is_null() { + if (*link).key as libc::c_int != key { + link = (*link).next + } else { + view_download((*link).host, (*link).port, (*link).selector); + return; + } + } + puts(b"link not found\x00" as *const u8 as *const libc::c_char); +} +/* function prototypes */ +pub unsafe extern "C" fn parse_uri(mut uri: *const libc::c_char) -> libc::c_int { + let mut i: libc::c_int = 0; + /* strip gopher:// */ + if strncmp( + uri, + b"gopher://\x00" as *const u8 as *const libc::c_char, + 9 as libc::c_int as libc::c_ulong, + ) == 0 + { + uri = uri.offset(9 as libc::c_int as isize) + } + /* parse host */ + i = 0 as libc::c_int; + while *uri as libc::c_int != 0 + && *uri as libc::c_int != ':' as i32 + && *uri as libc::c_int != '/' as i32 + { + if *uri as libc::c_int != ' ' as i32 + && (i as libc::c_ulong) + < (mem::size_of::<[libc::c_char; 512]>() as libc::c_ulong) + .wrapping_sub(1 as libc::c_int as libc::c_ulong) + { + let fresh11 = i; + i = i + 1; + parsed_host[fresh11 as usize] = *uri + } + uri = uri.offset(1) + } + if i > 0 as libc::c_int { + parsed_host[i as usize] = 0 as libc::c_int as libc::c_char + } else { + return 0 as libc::c_int; + } + /* parse port */ + if *uri as libc::c_int == ':' as i32 { + uri = uri.offset(1); + i = 0 as libc::c_int; + while *uri as libc::c_int != 0 && *uri as libc::c_int != '/' as i32 { + if *uri as libc::c_int != ' ' as i32 + && (i as libc::c_ulong) + < (mem::size_of::<[libc::c_char; 64]>() as libc::c_ulong) + .wrapping_sub(1 as libc::c_int as libc::c_ulong) + { + let fresh12 = i; + i = i + 1; + parsed_port[fresh12 as usize] = *uri + } + uri = uri.offset(1) + } + parsed_port[i as usize] = 0 as libc::c_int as libc::c_char + } else { + snprintf( + parsed_port.as_mut_ptr(), + mem::size_of::<[libc::c_char; 64]>() as libc::c_ulong, + b"%d\x00" as *const u8 as *const libc::c_char, + 70 as libc::c_int, + ); + } + /* parse selector (ignore slash and selector type) */ + if *uri != 0 { + uri = uri.offset(1) + } + if *uri != 0 { + uri = uri.offset(1) + } + i = 0 as libc::c_int; + while *uri as libc::c_int != 0 + && (i as libc::c_ulong) + < (mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong) + .wrapping_sub(1 as libc::c_int as libc::c_ulong) + { + parsed_selector[i as usize] = *uri; + uri = uri.offset(1); + i += 1 + } + parsed_selector[i as usize] = '\u{0}' as i32 as libc::c_char; + return 1 as libc::c_int; +} +unsafe fn main_0(mut argc: libc::c_int, mut argv: *mut *mut libc::c_char) -> libc::c_int { + let mut i: libc::c_int = 0; + let mut line: [libc::c_char; 1024] = [0; 1024]; + let mut uri: *mut libc::c_char = 0 as *mut libc::c_char; + /* copy defaults */ + init_config(); + uri = CString::new(config.start_uri.clone()).unwrap().into_raw(); + /* parse command line */ + i = 1 as libc::c_int; + while i < argc { + if *(*argv.offset(i as isize)).offset(0 as libc::c_int as isize) as libc::c_int + == '-' as i32 + { + match *(*argv.offset(i as isize)).offset(1 as libc::c_int as isize) + as libc::c_int + { + 72 => { + usage(); + } + 118 => { + banner(true); + exit(0); + } + _ => { + usage(); + } + } + } else { + uri = *argv.offset(i as isize) + } + i += 1 + } + /* parse uri */ + if parse_uri(uri) == 0 { + banner(false); + eprintln!( + "invalid gopher URI: {}", + CStr::from_ptr(*argv.offset(i as isize)).to_str().unwrap() + ); + exit(1); + } + /* main loop */ + view_directory( + parsed_host.as_mut_ptr(), + parsed_port.as_mut_ptr(), + parsed_selector.as_mut_ptr(), + 0 as libc::c_int, + ); /* to display the prompt */ + loop { + printf( + b"\x1b[%sm%s:%s%s\x1b[0m \x00" as *const u8 as *const libc::c_char, + CString::new(config.color_prompt.clone()).unwrap().into_raw(), + current_host.as_mut_ptr(), + current_port.as_mut_ptr(), + current_selector.as_mut_ptr(), + ); + if read_line( + 0 as libc::c_int, + line.as_mut_ptr(), + mem::size_of::<[libc::c_char; 1024]>() as libc::c_ulong, + ) == 0 + { + puts(b"QUIT\x00" as *const u8 as *const libc::c_char); + return 0 as libc::c_int; + } + i = strlen(line.as_mut_ptr()) as libc::c_int; + match line[0 as libc::c_int as usize] as libc::c_int { + 63 => { + puts(b"? - help\n* - reload directory\n< - go back in history\n.[LINK] - download the given link\nH - show history\nH[LINK] - jump to the specified history item\nG[URI] - jump to the given gopher URI\nB - show bookmarks\nB[LINK] - jump to the specified bookmark item\nC^d - quit\x00" + as *const u8 as *const libc::c_char); + } + 60 => { + pop_history(); + } + 42 => { + view_directory( + current_host.as_mut_ptr(), + current_port.as_mut_ptr(), + current_selector.as_mut_ptr(), + 0 as libc::c_int, + ); + } + 46 => { + download_link(make_key( + line[1 as libc::c_int as usize], + line[2 as libc::c_int as usize], + line[3 as libc::c_int as usize], + )); + } + 72 => { + if i == 1 as libc::c_int || i == 3 as libc::c_int || i == 4 as libc::c_int + { + view_history(make_key( + line[1 as libc::c_int as usize], + line[2 as libc::c_int as usize], + line[3 as libc::c_int as usize], + )); + } + } + 71 => { + if parse_uri(&mut *line.as_mut_ptr().offset(1 as libc::c_int as isize)) + != 0 + { + view_directory( + parsed_host.as_mut_ptr(), + parsed_port.as_mut_ptr(), + parsed_selector.as_mut_ptr(), + 1 as libc::c_int, + ); + } else { + puts(b"invalid gopher URI\x00" as *const u8 as *const libc::c_char); + } + } + 66 => { + if i == 1 as libc::c_int || i == 3 as libc::c_int || i == 4 as libc::c_int + { + view_bookmarks(make_key( + line[1 as libc::c_int as usize], + line[2 as libc::c_int as usize], + line[3 as libc::c_int as usize], + )); + } + } + _ => { + follow_link(make_key( + line[0 as libc::c_int as usize], + line[1 as libc::c_int as usize], + line[2 as libc::c_int as usize], + )); + } + } + } + /* never get's here but stops cc complaining */ +} +#[main] +pub fn main() { + let mut args: Vec<*mut libc::c_char> = Vec::new(); + for arg in env::args() { + args.push( + CString::new(arg) + .expect("Failed to convert argument into CString.") + .into_raw(), + ); + } + args.push(ptr::null_mut()); + unsafe { + exit(main_0( + (args.len() - 1) as libc::c_int, + args.as_mut_ptr() as *mut *mut libc::c_char, + ) as i32) + } +}