jcs
/detritus
/amendments
/13
gemini: No need for a header file for this, it's all local functions
jcs made amendment 13 about 1 year ago
--- browser.c Thu Oct 24 17:21:12 2024
+++ browser.c Sat Oct 26 14:59:58 2024
@@ -27,12 +27,18 @@
#define BROWSER_FONT_SIZE 10
#define BROWSER_STATUS_FONT geneva
#define BROWSER_STATUS_FONT_SIZE 9
+#define BROWSER_PRE_FONT monaco
+#define BROWSER_PRE_FONT_SIZE 9
static Rect zerorect = { 0, 0, 0, 0 };
static Pattern fill_pattern;
+extern struct request_handler gemini_handler;
+extern struct request_handler gopher_handler;
+
struct request_handler * request_handlers[] = {
&gemini_handler,
+ &gopher_handler,
};
void browser_setup_shadow(struct browser *browser);
@@ -606,6 +612,10 @@ browser_print(struct browser *browser, const char *str
style.style |= italic;
if (browser->style & STYLE_LINK)
style.style |= underline;
+ if (browser->style & STYLE_PRE) {
+ style.font = BROWSER_PRE_FONT;
+ style.size = BROWSER_PRE_FONT_SIZE;
+ }
if (browser->style & STYLE_H1)
style.size += 8;
@@ -614,84 +624,6 @@ browser_print(struct browser *browser, const char *str
else if (browser->style & STYLE_H3)
style.size += 2;
- if (browser->style & STYLE_LINK) {
- if (browser->links_count == browser->links_size) {
- browser->links_size += BROWSER_LINKS_CHUNK_SIZE;
- browser->links = xreallocarray(browser->links,
- browser->links_size, sizeof(struct browser_link));
- if (browser->links == NULL) {
- warn("Out of memory allocating links");
- return 0;
- }
- memset(&browser->links[browser->links_count], 0,
- sizeof(struct browser_link) * BROWSER_LINKS_CHUNK_SIZE);
- }
-
- link = &browser->links[browser->links_count++];
-
- HLock(browser->output_tv);
- link->pos = (*(browser->output_tv))->text_length;
- HUnlock(browser->output_tv);
-
- /* [<whitespace>]<URL>[<whitespace><title>] */
-
- /* eat leading whitespace */
- while (len && (str[0] == ' ' || str[0] == '\t')) {
- str++;
- len--;
- }
-
- /* url, up to whitespace or end of str */
- for (n = 0; n <= len; n++) {
- if (!(n == len || str[n] == ' ' || str[n] == '\t' ||
- str[n] == '\r'))
- continue;
-
- if (n == len)
- n--;
-
- link->link = xmalloc(n + 1);
- if (link->link == NULL) {
- warn("Out of memory allocating link");
- return 0;
- }
- memcpy(link->link, str, n);
- link->link[n] = '\0';
- link->len = n;
- str += n;
- len -= n;
- break;
- }
-
- /* eat separating white space */
- while (len && (str[0] == ' ' || str[0] == '\t')) {
- str++;
- len--;
- }
-
- /* optional title */
- if (len > 1) {
- /* len will include trailing \r */
-
- link->title = xmalloc(len);
- if (link->title == NULL) {
- warn("Out of memory allocating link title");
- return 0;
- }
- memcpy(link->title, str, len - 1);
- link->title[len - 1] = '\0';
- link->len = len - 1;
-
- TVAppend(browser->output_tv, &style, link->title, len - 1);
-
- str += len - 1;
- len = 1;
- } else
- TVAppend(browser->output_tv, &style, (char *)str, len);
-
- browser->style &= ~(STYLE_LINK);
- }
-
if (str[len - 1] == '\r' &&
(browser->style & (STYLE_H1 | STYLE_H2 | STYLE_H3))) {
/* print newlines in a small size */
@@ -706,6 +638,63 @@ browser_print(struct browser *browser, const char *str
TVUpdateScrollbar(browser->output_tv, browser->output_tv_scroller);
return len;
+}
+
+size_t
+browser_print_link(struct browser *browser, const char *url, size_t url_len,
+ const char *title, size_t title_len)
+{
+ struct TVStyle style;
+ struct browser_link *link;
+ size_t n;
+
+ if (browser->links_count == browser->links_size) {
+ browser->links_size += BROWSER_LINKS_CHUNK_SIZE;
+ browser->links = xreallocarray(browser->links,
+ browser->links_size, sizeof(struct browser_link));
+ if (browser->links == NULL) {
+ warn("Out of memory allocating links");
+ return 0;
+ }
+ memset(&browser->links[browser->links_count], 0,
+ sizeof(struct browser_link) * BROWSER_LINKS_CHUNK_SIZE);
+ }
+
+ link = &browser->links[browser->links_count++];
+
+ HLock(browser->output_tv);
+ link->pos = (*(browser->output_tv))->text_length;
+ HUnlock(browser->output_tv);
+
+ link->link = xmalloc(url_len + 1);
+ if (link->link == NULL) {
+ warn("Out of memory allocating link");
+ return 0;
+ }
+ memcpy(link->link, url, url_len);
+ link->link[n] = '\0';
+
+ browser->style |= STYLE_LINK;
+
+ /* optional title */
+ if (title_len > 1) {
+ link->title = xmalloc(title_len);
+ if (link->title == NULL) {
+ warn("Out of memory allocating link title");
+ return 0;
+ }
+ memcpy(link->title, title, title_len + 1);
+ link->title[title_len] = '\0';
+ link->len = title_len;
+
+ browser_print(browser, link->title, title_len);
+ } else {
+ link->len = url_len;
+ browser_print(browser, url, url_len);
+ }
+
+ browser->style &= ~(STYLE_LINK);
+ return link->len;
}
void
--- browser.h Thu Oct 24 20:08:10 2024
+++ browser.h Sat Oct 26 14:53:08 2024
@@ -65,6 +65,8 @@ struct browser {
struct browser * browser_init(void);
size_t browser_statusf(struct browser *browser, const char *format, ...);
+size_t browser_print_link(struct browser *browser, const char *url,
+ size_t url_len, const char *title, size_t title_len);
size_t browser_print(struct browser *browser, const char *str, size_t len);
//#define BROWSER_DEBUGF(x) browser_statusf
#define BROWSER_DEBUGF(x)
--- detritus.h Thu Oct 24 13:20:34 2024
+++ detritus.h Fri Oct 25 21:47:44 2024
@@ -18,7 +18,6 @@
#define __GEMINO_H__
#include "browser.h"
-#include "gemini.h"
#include "util.h"
#define PROGRAM_NAME "Detritus"
@@ -54,7 +53,7 @@ struct URI {
#define URI_PATH_LEN 512
char path[URI_PATH_LEN + 1];
unsigned short port;
- char str[1024];
+ char str[800];
};
struct request_handler {
@@ -67,6 +66,7 @@ struct request_handler {
extern MenuHandle file_menu, edit_menu;
void menu_defaults(void);
+struct URI * generic_parse_uri(char *protocol, char *uristr);
short scsi_find_tls(void);
uint8_t scsi_tls_init(struct tls_init_request *req);
--- gemini.c Thu Oct 24 20:19:40 2024
+++ gemini.c Sat Oct 26 14:54:01 2024
@@ -20,64 +20,74 @@
#include "detritus.h"
-struct request_handler gemini_handler = {
- gemini_parse_uri,
- gemini_init_request,
- gemini_process_request,
- gemini_free,
+#define GEMINI_PORT 1965
+
+enum {
+ REQ_STATE_NEGOTIATING = 1,
+ REQ_STATE_SENDING_REQUEST,
+ REQ_STATE_PARSING_RESPONSE
};
-bool shuffle_read_tls_ciphertext(struct gemini_request *req);
-bool shuffle_read_tcp_ciphertext(struct gemini_request *req, short space);
-bool shuffle_tls_send_plaintext(struct gemini_request *req, short space);
-bool shuffle_tls_read_plaintext(struct gemini_request *req);
-bool parse_response(struct gemini_request *req);
-bool parse_header(struct gemini_request *req, char *str);
-void consume_response(struct gemini_request *req, size_t len);
+enum {
+ GEM_STATE_HEADER,
+ GEM_STATE_GEMTEXT,
+ GEM_STATE_REDIRECT,
+ GEM_STATE_DOWNLOAD
+};
-struct URI *
-gemini_parse_uri(char *uristr)
-{
+struct gemini_request {
+ struct browser *browser;
struct URI *uri;
- short count;
- uri = xmalloczero(sizeof(struct URI));
- if (uri == NULL)
- return NULL;
+ uint8_t tls_id;
+ unsigned char tcp_buf[(4 * 1500) + 2048]; /* 4*MTU + tcp_input */
+ unsigned char tcp_input[2048];
+ size_t tcp_input_len;
+ short state;
- uri->port = GEMINI_PORT;
- snprintf(uri->protocol, sizeof(uri->protocol), "gemini");
+ TCPiopb tcp_iopb;
+ StreamPtr tcp_stream;
+ wdsEntry tcp_wds[2];
+ TCPStatusPB tcp_status_pb;
+ bool tcp_done_reading;
- /* gemini://host/path */
- if (count = 0, sscanf(uristr,
- "gemini://%" STR(URI_HOSTNAME_LEN) "[^/]/%" STR(URI_PATH_LEN) "s%n",
- &uri->hostname, &uri->path + 1, &count) == 2 && count > 10)
- goto parse_ok;
+ char message[member_size(struct URI, str) + 3];
+ size_t message_len;
- /* gemini://host/ */
- if (count = 0, sscanf(uristr,
- "gemini://%" STR(URI_HOSTNAME_LEN) "[^/]/%n",
- &uri->hostname, &count) == 1 && count > 10) {
- snprintf(uri->path, sizeof(uri->path), "/");
- goto parse_ok;
- }
+ short gem_state;
+ char response[1024];
+ size_t response_len;
+ size_t total_response_len;
- /* gemini://host */
- if (count = 0, sscanf(uristr,
- "gemini://%" STR(URI_HOSTNAME_LEN) "[^/]%n",
- &uri->hostname, &count) == 1 && count > 10) {
- snprintf(uri->path, sizeof(uri->path), "/");
- goto parse_ok;
- }
-
- /* failed */
- xfree(&uri);
- return NULL;
+ char mime_type[64];
+ unsigned long style;
+};
-parse_ok:
- snprintf(uri->str, sizeof(uri->str), "%s://%s%s",
- uri->protocol, uri->hostname, uri->path);
- return uri;
+struct URI * gemini_parse_uri(char *uristr);
+void * gemini_init_request(struct browser *browser, struct URI *uri);
+bool gemini_process_request(void *cookie);
+void gemini_free(void *cookie);
+static bool shuffle_read_tls_ciphertext(struct gemini_request *req);
+static bool shuffle_read_tcp_ciphertext(struct gemini_request *req,
+ short space);
+static bool shuffle_tls_send_plaintext(struct gemini_request *req,
+ short space);
+static bool shuffle_tls_read_plaintext(struct gemini_request *req);
+static bool parse_response(struct gemini_request *req);
+static bool parse_header(struct gemini_request *req, char *str);
+static void consume_response(struct gemini_request *req, size_t len);
+
+struct request_handler gemini_handler = {
+ gemini_parse_uri,
+ gemini_init_request,
+ gemini_process_request,
+ gemini_free,
+};
+
+struct URI *
+gemini_parse_uri(char *uristr)
+{
+ return generic_parse_uri("gemini", uristr);
}
void *
@@ -99,6 +109,8 @@ gemini_init_request(struct browser *browser, struct UR
req->browser = browser;
req->uri = uri;
+ if (req->uri->port == 0)
+ req->uri->port = GEMINI_PORT;
browser_statusf(browser, "Resolving \"%s\"...", req->uri->hostname);
@@ -261,7 +273,7 @@ gemini_process_request(void *cookie)
return true;
}
-bool
+static bool
shuffle_read_tls_ciphertext(struct gemini_request *req)
{
size_t len;
@@ -297,7 +309,7 @@ shuffle_read_tls_ciphertext(struct gemini_request *req
return true;
}
-bool
+static bool
shuffle_read_tcp_ciphertext(struct gemini_request *req, short space)
{
size_t len, n;
@@ -375,7 +387,7 @@ forward_ciphertext:
return true;
}
-bool
+static bool
shuffle_tls_send_plaintext(struct gemini_request *req, short space)
{
size_t slen, len;
@@ -417,7 +429,7 @@ shuffle_tls_send_plaintext(struct gemini_request *req,
return true;
}
-bool
+static bool
shuffle_tls_read_plaintext(struct gemini_request *req)
{
size_t len;
@@ -452,7 +464,7 @@ shuffle_tls_read_plaintext(struct gemini_request *req)
return true;
}
-bool
+static bool
parse_response(struct gemini_request *req)
{
size_t n, trail, skip, len;
@@ -542,10 +554,10 @@ restart_parse:
skip++;
len--;
}
- req->browser->style = STYLE_LINK;
- browser_print(req->browser, req->response + skip, len);
- consume_response(req, skip + len + trail);
+ browser_print_link(req->browser, req->response + skip,
+ len, NULL, 0);
req->browser->style = STYLE_NONE;
+ consume_response(req, skip + len + trail);
goto restart_parse;
}
@@ -651,7 +663,7 @@ restart_parse:
return true;
}
-void
+static void
consume_response(struct gemini_request *req, size_t len)
{
if (len == req->response_len) {
@@ -666,7 +678,7 @@ consume_response(struct gemini_request *req, size_t le
}
}
-bool
+static bool
parse_header(struct gemini_request *req, char *str)
{
short status;
--- gemini.h Thu Oct 24 16:48:34 2024
+++ gemini.h Sat Oct 26 14:54:01 2024
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2021-2024 joshua stein <jcs@jcs.org>
- *
- * 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 <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "detritus.h"
-
-#ifndef __GEMINI_H__
-#define __GEMINI_H__
-
-#define GEMINI_PORT 1965
-
-extern struct request_handler gemini_handler;
-
-enum {
- REQ_STATE_NEGOTIATING = 1,
- REQ_STATE_SENDING_REQUEST,
- REQ_STATE_PARSING_RESPONSE
-};
-
-enum {
- GEM_STATE_HEADER,
- GEM_STATE_GEMTEXT,
- GEM_STATE_REDIRECT,
- GEM_STATE_DOWNLOAD
-};
-
-struct gemini_request {
- struct browser *browser;
- struct URI *uri;
-
- uint8_t tls_id;
- unsigned char tcp_buf[(4 * 1500) + 2048]; /* 4*MTU + tcp_input */
- unsigned char tcp_input[2048];
- size_t tcp_input_len;
- short state;
-
- TCPiopb tcp_iopb;
- StreamPtr tcp_stream;
- wdsEntry tcp_wds[2];
- TCPStatusPB tcp_status_pb;
- bool tcp_done_reading;
-
- char message[1024 + 3];
- size_t message_len;
-
- short gem_state;
- char response[1024];
- size_t response_len;
- size_t total_response_len;
-
- char mime_type[64];
- unsigned long style;
-};
-
-struct URI * gemini_parse_uri(char *uristr);
-void * gemini_init_request(struct browser *browser, struct URI *uri);
-bool gemini_process_request(void *cookie);
-void gemini_free(void *cookie);
-
-#endif
\ No newline at end of file
--- main.c Wed Oct 23 09:12:46 2024
+++ main.c Fri Oct 25 21:50:14 2024
@@ -231,3 +231,51 @@ handle_exit(void)
{
focusables_quit();
}
+
+struct URI *
+generic_parse_uri(char *protocol, char *uristr)
+{
+ struct URI *uri;
+ short count;
+
+ uri = xmalloczero(sizeof(struct URI));
+ if (uri == NULL)
+ return NULL;
+
+ /* protocol://host/path */
+ if (count = 0, sscanf(uristr,
+ "%" STR(URI_PROTOCOL_LEN) "[^:]://%" STR(URI_HOSTNAME_LEN) "[^/]/%"
+ STR(URI_PATH_LEN) "s%n",
+ &uri->protocol, &uri->hostname, &uri->path + 1, &count) == 3 &&
+ count > 10)
+ goto parse_ok;
+
+ /* protocol://host/ */
+ if (count = 0, sscanf(uristr,
+ "%" STR(URI_PROTOCOL_LEN) "[^:]://%" STR(URI_HOSTNAME_LEN) "[^/]/%n",
+ &uri->protocol, &uri->hostname, &count) == 2 && count > 10) {
+ snprintf(uri->path, sizeof(uri->path), "/");
+ goto parse_ok;
+ }
+
+ /* gemini://host */
+ if (count = 0, sscanf(uristr,
+ "%" STR(URI_PROTOCOL_LEN) "[^:]://%" STR(URI_HOSTNAME_LEN) "[^/]%n",
+ &uri->protocol, &uri->hostname, &count) == 2 && count > 10) {
+ snprintf(uri->path, sizeof(uri->path), "/");
+ goto parse_ok;
+ }
+
+ /* failed */
+ xfree(&uri);
+ return NULL;
+
+parse_ok:
+ if (protocol != NULL && strcasecmp(protocol, uri->protocol) != 0) {
+ xfree(&uri);
+ return NULL;
+ }
+ snprintf(uri->str, sizeof(uri->str), "%s://%s%s",
+ uri->protocol, uri->hostname, uri->path);
+ return uri;
+}