diff --git a/src/gmnlm.c b/src/gmnlm.c

index 2375151c7f5fced09a80e41d26809730827f8925..4b844200eeb4318d694566d7a84eb3e64c7c7668 100644

--- a/src/gmnlm.c

+++ b/src/gmnlm.c

@@ -82,6 +82,7 @@ if (curl_url_set(browser->url, CURLUPART_URL, new_url, 0) != CURLUE_OK) {

fprintf(stderr, "Error: invalid URL\n");

return false;

}

+ curl_url_get(browser->url, CURLUPART_URL, &browser->plain_url, 0);

if (history) {

struct history *next = calloc(1, sizeof(struct history));

curl_url_get(browser->url, CURLUPART_URL, &next->url, 0);

@@ -118,19 +119,23 @@ case '\0':

result = PROMPT_MORE;

goto exit;

case 'q':

+ if (in[1]) break;

result = PROMPT_QUIT;

goto exit;

case 'b':

+ if (in[1]) break;

if (!browser->history->prev) {

fprintf(stderr, "At beginning of history\n");

result = PROMPT_AGAIN;

goto exit;

}

+ if (in[1]) break;

browser->history = browser->history->prev;

set_url(browser, browser->history->url, NULL);

result = PROMPT_ANSWERED;

goto exit;

case 'f':

+ if (in[1]) break;

if (!browser->history->next) {

fprintf(stderr, "At end of history\n");

result = PROMPT_AGAIN;

@@ -141,6 +146,7 @@ set_url(browser, browser->history->url, NULL);

result = PROMPT_ANSWERED;

goto exit;

case '/':

+ if (in[1]) break;

if ((r = regcomp(&browser->regex, &in[1], REG_EXTENDED)) != 0) {

static char buf[1024];

r = regerror(r, &browser->regex, buf, sizeof(buf));

@@ -153,6 +159,7 @@ result = PROMPT_ANSWERED;

}

goto exit_re;

case 'n':

+ if (in[1]) break;

if (browser->searching) {

result = PROMPT_NEXT;

goto exit_re;

@@ -162,6 +169,7 @@ result = PROMPT_AGAIN;

goto exit;

}

case '?':

+ if (in[1]) break;

fprintf(browser->tty, "%s", help_msg);

result = PROMPT_AGAIN;

goto exit;

@@ -465,6 +473,17 @@ }

return input;

}

+static bool

+has_suffix(char *str, char *suff)

+{

+ size_t suffl = strlen(suff);

+ size_t strl = strlen(str);

+ if (strl < suffl) {

+ return false;

+ }

+ return strcmp(&str[strl - suffl], suff) == 0;

+}

+

// Returns true to skip prompting

static bool

do_requests(struct browser *browser, struct gemini_response *resp)

@@ -472,9 +491,40 @@ {

int nredir = 0;

bool requesting = true;

while (requesting) {

+ char *scheme;

CURLUcode uc = curl_url_get(browser->url,

- CURLUPART_URL, &browser->plain_url, 0);

+ CURLUPART_SCHEME, &scheme, 0);

assert(uc == CURLUE_OK); // Invariant

+ if (strcmp(scheme, "file") == 0) {

+ requesting = false;

+

+ char *path;

+ uc = curl_url_get(browser->url,

+ CURLUPART_PATH, &path, 0);

+ if (uc != CURLUE_OK) {

+ resp->status = GEMINI_STATUS_BAD_REQUEST;

+ break;

+ }

+

+ FILE *fp = fopen(path, "r");

+ if (!fp) {

+ resp->status = GEMINI_STATUS_NOT_FOUND;

+ break;

+ }

+

+ BIO *file = BIO_new_fp(fp, BIO_CLOSE);

+ resp->bio = BIO_new(BIO_f_buffer());

+ BIO_push(resp->bio, file);

+ if (has_suffix(path, ".gmi") || has_suffix(path, ".gemini")) {

+ resp->meta = strdup("text/gemini");

+ } else if (has_suffix(path, ".txt")) {

+ resp->meta = strdup("text/plain");

+ } else {

+ resp->meta = strdup("application/x-octet-stream");

+ }

+ resp->status = GEMINI_STATUS_SUCCESS;

+ return display_response(browser, resp);

+ }

enum gemini_result res = gemini_request(browser->plain_url,

&browser->opts, resp);