diff --git a/include/client.h b/include/client.h
index dbd73234311331ea52650d59dbd9cf535b73298b..f711eea91c3842ac29a884b38e0d7a0ab99cb7fb 100644
--- a/include/client.h
+++ b/include/client.h
@@ -46,6 +46,7 @@ GEMINI_ERR_CONNECT,
// use SSL_get_error(resp->ssl, resp->status) to get details
GEMINI_ERR_SSL,
GEMINI_ERR_IO,
};
// Requests the specified URL via the gemini protocol. If options is non-NULL,
@@ -63,5 +64,8 @@ // allocated during the request. If you intend to re-use the SSL_CTX provided by
// gemini_options, set the ctx pointer to NULL before calling
// gemini_response_finish.
void gemini_response_finish(struct gemini_response *resp);
+// Returns a user-friendly string describing an error.
+const char *gemini_strerr(enum gemini_result r, struct gemini_response *resp);
#endif
diff --git a/src/client.c b/src/client.c
index 5f2debb52c310f88e82ad83ca2251ba233d6a704..67671ccca2a25a460681bdffacb981c7f26c1407 100644
--- a/src/client.c
+++ b/src/client.c
@@ -2,6 +2,7 @@ #include <assert.h>
#include <errno.h>
#include <netdb.h>
#include <openssl/bio.h>
+#include <openssl/err.h>
#include <openssl/ssl.h>
#include <stdlib.h>
#include <string.h>
@@ -168,6 +169,21 @@ res = GEMINI_ERR_IO;
goto cleanup;
}
res = GEMINI_ERR_PROTOCOL;
goto cleanup;
res = GEMINI_ERR_PROTOCOL;
goto cleanup;
cleanup:
curl_url_cleanup(uri);
return res;
@@ -188,3 +204,29 @@ SSL_free(resp->ssl);
SSL_CTX_free(resp->ssl_ctx);
free(resp->meta);
}
+const char *
+gemini_strerr(enum gemini_result r, struct gemini_response *resp)
+{
return "OK";
return "Out of memory";
return "Invalid URL";
return gai_strerror(resp->status);
return strerror(errno);
return ERR_error_string(
SSL_get_error(resp->ssl, resp->status),
NULL);
return "I/O error";
return "Protocol error";
+}
diff --git a/src/gmnic.c b/src/gmnic.c
index 7b2eb183ebfe67dce0aaf8c6010bf6785b503df6..014211dc3784ba3eadcf1885ef7bcf6fe84d8462 100644
--- a/src/gmnic.c
+++ b/src/gmnic.c
@@ -1,9 +1,13 @@
#include <assert.h>
+#include <errno.h>
#include <getopt.h>
+#include <openssl/bio.h>
#include <openssl/err.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include "client.h"
static void
@@ -17,11 +21,15 @@
int
main(int argc, char *argv[])
{
OMIT_HEADERS,
SHOW_HEADERS,
ONLY_HEADERS,
int c;
switch (c) {
case '4':
assert(0); // TODO
@@ -30,25 +38,29 @@ case '6':
assert(0); // TODO
break;
case 'C':
certificate = optarg;
assert(0); // TODO: Client certificates
break;
case 'd':
input = optarg;
assert(0); // TODO: Input
break;
case 'h':
usage(argv[0]);
return 0;
case 'L':
follow_redirect = true;
assert(0); // TODO: Follow redirects
break;
case 'i':
headers = SHOW_HEADERS;
break;
case 'I':
headers = true;
headers = ONLY_HEADERS;
break;
default:
fprintf(stderr, "fatal: unknown flag %c", c);
return 1;
}
}
if (optind != argc - 1) {
usage(argv[0]);
return 1;
@@ -59,33 +71,41 @@ ERR_load_crypto_strings();
struct gemini_response resp;
enum gemini_result r = gemini_request(argv[optind], NULL, &resp);
printf("OK\n");
break;
printf("OOM\n");
break;
printf("INVALID_URL\n");
break;
printf("RESOLVE\n");
break;
printf("CONNECT\n");
fprintf(stderr, "Error: %s\n", gemini_strerr(r, &resp));
gemini_response_finish(&resp);
return (int)r;
printf("%d %s\n", resp.status, resp.meta);
break;
fprintf(stderr, "SSL error: %s\n", ERR_error_string(
SSL_get_error(resp.ssl, resp.status), NULL));
printf("%d %s\n", resp.status, resp.meta);
/* fallthrough */
for (int n = 1; n > 0;) {
char buf[BUFSIZ];
n = BIO_read(resp.bio, buf, BUFSIZ);
if (n == -1) {
fprintf(stderr, "Error: read\n");
return 1;
}
ssize_t w = 0;
while (w < (ssize_t)n) {
ssize_t x = write(STDOUT_FILENO, &buf[w], n - w);
if (x == -1) {
fprintf(stderr, "Error: write: %s\n",
strerror(errno));
return 1;
}
w += x;
}
}
break;
}
gemini_response_finish(&resp);
return 0;
}
text/gemini
This content has been proxied by September (ba2dc).