AmendHub

Download:

jcs

/

detritus

/

amendments

/

17

gopher: Pass type in URIs, add plain-text file displaying


jcs made amendment 17 about 1 year ago
--- gopher.c Sat Oct 26 20:34:01 2024 +++ gopher.c Tue Oct 29 11:56:09 2024 @@ -25,6 +25,7 @@ struct gopher_request { struct browser *browser; struct URI *uri; + char type; unsigned char tcp_buf[(4 * 1500) + 2048]; /* 4*MTU + tcp_input */ char response[2048]; @@ -47,7 +48,7 @@ bool gopher_process_request(void *cookie); void gopher_free(void *cookie); static bool parse_response(struct gopher_request *req); static void consume_response(struct gopher_request *req, size_t len); -static void gopher_print(struct gopher_request *req, size_t len); +static void gopher_print_menu(struct gopher_request *req, size_t len); struct request_handler gopher_handler = { gopher_parse_uri, @@ -119,10 +120,23 @@ gopher_init_request(struct browser *browser, struct UR goto fail; } - /* send selector without leading slash */ - req->message_len = snprintf(req->message, sizeof(req->message), - "%s\r\n", req->uri->path[1] == '\0' ? "" : req->uri->path + 1); - + /* + * If we have a path other than /, assume the first character is the + * type and should not be sent, per RFC 4266. + */ + if (req->uri->path[0] == '\0' || + (req->uri->path[0] == '/' && req->uri->path[1] == '\0')) { + req->type = '1'; + req->message_len = snprintf(req->message, sizeof(req->message), + "\r\n"); + } else { + /* /0/blah -> blah */ + req->type = req->uri->path[1]; + req->message_len = snprintf(req->message, sizeof(req->message), + "%s\r\n", req->uri->path + 2); + } + + browser_commit_to_uri(browser, req->uri); browser_statusf(browser, "Connected to %s, sending request...", req->uri->hostname); @@ -136,7 +150,7 @@ gopher_init_request(struct browser *browser, struct UR browser_statusf(req->browser, "Error: TCPSend failed: %d", err); goto fail; } - + return req; fail: @@ -172,7 +186,8 @@ gopher_process_request(void *cookie) size_t len, n; short err; unsigned short slen; - + bool ret; + if (req->tcp_iopb.ioResult > 0 || CommandPeriodPressed()) { BROWSER_DEBUGF((req->browser, "TCP I/O Result %d, disconnecting", req->tcp_iopb.ioResult)); @@ -221,9 +236,20 @@ gopher_process_request(void *cookie) } parse: - if (req->response_len) - return parse_response(req); - + if (req->response_len) { + TVAutoCalc(req->browser->output_tv, false); + ret = parse_response(req); + TVAutoCalc(req->browser->output_tv, true); + TVCalcLines(req->browser->output_tv); + TVUpdate(req->browser->output_tv); + TVUpdateScrollbar(req->browser->output_tv, + req->browser->output_tv_scroller); + if (ret == false) + browser_statusf(req->browser, + "Finished parsing %ld bytes", req->total_response_len); + return ret; + } + return true; } @@ -232,23 +258,69 @@ parse_response(struct gopher_request *req) { long n; -restart_parse: - for (n = 0; n < req->response_len; n++) { - if (n + 3 <= req->response_len && req->response[0] == '.' && - req->response[1] == '\r' && req->response[2] == '\n') { - /* end of transfer */ - browser_statusf(req->browser, - "Finished reading %ld bytes", req->total_response_len); - return false; + if (req->type == '1') { + /* gopher menu */ +parse_menu: + for (n = 0; n < req->response_len; n++) { + if (n > 0 && req->response[n - 1] == '\r' && + req->response[n] == '\n') { + /* print line */ + req->response[n - 1] = '\0'; + if (req->response[0] == '.' && n == 2 && + req->response_len - n == 1) + /* ".\r\n" is end of transfer */ + req->tcp_done_reading = true; + else + gopher_print_menu(req, n + 1); + consume_response(req, n + 1); + goto parse_menu; + } + + /* otherwise leave data in the buffer */ } - - if (n > 1 && req->response[n - 1] == '\r' && - req->response[n] == '\n') { - req->response[n - 1] = '\0'; - gopher_print(req, n + 1); - consume_response(req, n + 1); - goto restart_parse; + if (req->response_len == sizeof(req->response)) { + /* just dump it so we can move on */ + gopher_print_menu(req, req->response_len); + consume_response(req, req->response_len); } + } else if (req->type == '0') { + /* text file, convert newlines and display */ +find_lines: + for (n = 0; n < req->response_len; n++) { + if (n > 0 && req->response[n - 1] == '\r' && + req->response[n] == '\n') { + /* \r\n -> \r */ + if (req->response[0] == '.' && n == 2 && + req->response_len - n == 1) + /* ".\r\n" is end of transfer */ + req->tcp_done_reading = true; + else + browser_print(req->browser, req->response, n); + consume_response(req, n + 1); + goto find_lines; + } else if (n > 0 && req->response[n - 1] == '\r') { + /* lone \r */ + browser_print(req->browser, req->response, n); + consume_response(req, n); + goto find_lines; + } else if (n > 0 && req->response[n] == '\n') { + /* lone \n */ + req->response[n] = '\r'; + browser_print(req->browser, req->response, n); + consume_response(req, n); + goto find_lines; + } + /* otherwise leave data in the buffer */ + } + if (req->response_len == sizeof(req->response)) { + /* gosh this is one long line */ + browser_print(req->browser, req->response, req->response_len); + consume_response(req, req->response_len); + } + } else { + /* anything else, just download it */ + browser_print(req->browser, req->response, req->response_len); + consume_response(req, req->response_len); } return true; @@ -270,7 +342,7 @@ consume_response(struct gopher_request *req, size_t le } static void -gopher_print(struct gopher_request *req, size_t len) +gopher_print_menu(struct gopher_request *req, size_t len) { static char uri[member_size(struct URI, str)], prefix[5]; char type, *label, *selector = NULL, *hostname = NULL; @@ -312,8 +384,8 @@ gopher_print(struct gopher_request *req, size_t len) snprintf(prefix, sizeof(prefix), "[%c] ", type); browser_print(req->browser, prefix, 4); - len = snprintf(uri, sizeof(uri), "gopher://%s%s", hostname, - selector); + len = snprintf(uri, sizeof(uri), "gopher://%s/%c%s", hostname, + type, selector); browser_print_link(req->browser, uri, len, label, strlen(label)); browser_print(req->browser, "\r", 1); break;