mirror of
https://github.com/rkd77/elinks.git
synced 2024-09-27 02:56:18 -04:00
361b8f661d
AFAIK on Windows long is sizeof 4, while void * is sizeof 8. intptr_t is the same sizeof as void *.
185 lines
4.1 KiB
C
185 lines
4.1 KiB
C
/* Gemini response codes */
|
|
|
|
#ifndef _GNU_SOURCE
|
|
#define _GNU_SOURCE /* Needed for asprintf() */
|
|
#endif
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_STDINT_H
|
|
#include <stdint.h>
|
|
#endif
|
|
|
|
#include "elinks.h"
|
|
|
|
#include "cache/cache.h"
|
|
#include "intl/libintl.h"
|
|
#include "network/connection.h"
|
|
#include "protocol/gemini/codes.h"
|
|
#include "protocol/uri.h"
|
|
#include "session/session.h"
|
|
#include "session/task.h"
|
|
#include "terminal/terminal.h"
|
|
#include "terminal/window.h"
|
|
#include "util/snprintf.h"
|
|
#include "viewer/text/draw.h"
|
|
|
|
|
|
struct gemini_code {
|
|
int num;
|
|
const char *str;
|
|
};
|
|
|
|
static const struct gemini_code gemini_code[] = {
|
|
{ 10, "INPUT" },
|
|
{ 21, "SENSITIVE INPUT" },
|
|
{ 20, "SUCCESS" },
|
|
{ 30, "REDIRECT - TEMPORARY" },
|
|
{ 31, "REDIRECT - PERMANENT" },
|
|
{ 40, "TEMPORARY FAILURE" },
|
|
{ 41, "SERVER UNAVAILABLE" },
|
|
{ 42, "CGI ERROR" },
|
|
{ 43, "PROXY ERROR" },
|
|
{ 44, "SLOW DOWN" },
|
|
{ 50, "PERMANENT FAILURE" },
|
|
{ 51, "NOT FOUND" },
|
|
{ 52, "GONE" },
|
|
{ 53, "PROXY REQUEST REFUSED" },
|
|
{ 59, "BAD REQUEST" },
|
|
{ 60, "CLIENT CERTIFICATE REQUIRED" },
|
|
{ 61, "CERTIFICATE NOT AUTHORISED" },
|
|
{ 62, "CERTIFICATE NOT VALID" },
|
|
};
|
|
|
|
static int
|
|
compare_gemini_codes(const void *key, const void *element)
|
|
{
|
|
int first = (intptr_t) key;
|
|
int second = ((const struct gemini_code *) element)->num;
|
|
|
|
return first - second;
|
|
}
|
|
|
|
static const char *
|
|
gemini_code_to_string(int code)
|
|
{
|
|
const struct gemini_code *element
|
|
= (const struct gemini_code *)bsearch((void *) (intptr_t) code, gemini_code,
|
|
sizeof_array(gemini_code),
|
|
sizeof(*element),
|
|
compare_gemini_codes);
|
|
|
|
if (element) return element->str;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static char *
|
|
get_gemini_error_document(struct terminal *term, struct uri *uri, int code)
|
|
{
|
|
const char *codestr = gemini_code_to_string(code);
|
|
char *title = asprintfa(_("Gemini error %02d", term), code);
|
|
struct string string;
|
|
|
|
if (!codestr) codestr = "UNKNOWN ERROR";
|
|
|
|
if (!init_string(&string)) {
|
|
mem_free_if(title);
|
|
return NULL;
|
|
}
|
|
|
|
add_format_to_string(&string,
|
|
"<html>\n"
|
|
" <head><title>%s</title></head>\n"
|
|
" <body>\n"
|
|
" <h1 align=\"left\">%s: %s</h1>\n"
|
|
#ifndef CONFIG_SMALL
|
|
" <hr />\n"
|
|
" <p>\n"
|
|
#endif
|
|
, title, title, codestr);
|
|
|
|
#ifndef CONFIG_SMALL
|
|
add_format_to_string(&string, _(
|
|
" An error occurred on the server while fetching the document you\n"
|
|
" requested.\n",
|
|
term));
|
|
|
|
add_format_to_string(&string,
|
|
" </p>\n"
|
|
" <p>\n"
|
|
" URI: <a href=\"%s\">%s</a>\n", struri(uri), struri(uri));
|
|
#endif
|
|
add_format_to_string(&string,
|
|
#ifndef CONFIG_SMALL
|
|
" </p>\n"
|
|
" <hr />\n"
|
|
#endif
|
|
" </body>\n"
|
|
"</html>\n");
|
|
|
|
mem_free_if(title);
|
|
|
|
return string.source;
|
|
}
|
|
|
|
struct gemini_error_info {
|
|
int code;
|
|
struct uri *uri;
|
|
};
|
|
|
|
static void
|
|
show_gemini_error_document(struct session *ses, void *data)
|
|
{
|
|
struct gemini_error_info *info = (struct gemini_error_info *)data;
|
|
struct terminal *term = ses->tab->term;
|
|
struct cache_entry *cached = find_in_cache(info->uri);
|
|
struct cache_entry *cache = cached ? cached : get_cache_entry(info->uri);
|
|
char *str = NULL;
|
|
|
|
if (cache) str = get_gemini_error_document(term, info->uri, info->code);
|
|
|
|
if (str) {
|
|
/* The codepage that _("foo", term) used when it was
|
|
* called by get_gemini_error_document. */
|
|
const int gettext_codepage = get_terminal_codepage(term);
|
|
|
|
if (cached) delete_entry_content(cache);
|
|
|
|
/* If we run out of memory here, it's perhaps better
|
|
* to display a malformatted error message than none
|
|
* at all. */
|
|
mem_free_set(&cache->content_type, stracpy("text/html"));
|
|
mem_free_set(&cache->head,
|
|
straconcat("\r\nContent-Type: text/html; charset=",
|
|
get_cp_mime_name(gettext_codepage),
|
|
"\r\n", (char *) NULL));
|
|
add_fragment(cache, 0, str, strlen(str));
|
|
mem_free(str);
|
|
|
|
draw_formatted(ses, 1);
|
|
}
|
|
|
|
done_uri(info->uri);
|
|
mem_free(info);
|
|
}
|
|
|
|
|
|
void
|
|
gemini_error_document(struct connection *conn, int code)
|
|
{
|
|
struct gemini_error_info *info;
|
|
|
|
assert(conn && conn->uri);
|
|
|
|
info = (struct gemini_error_info *)mem_calloc(1, sizeof(*info));
|
|
if (!info) return;
|
|
|
|
info->code = code;
|
|
info->uri = get_uri_reference(conn->uri);
|
|
|
|
add_questions_entry(show_gemini_error_document, info);
|
|
}
|