diff --git a/Makefile b/Makefile index a664f60..af3e708 100644 --- a/Makefile +++ b/Makefile @@ -20,3 +20,7 @@ testgemparse: testurllib: mkdir -p $(BUILD_DIR)/test $(CC) -o $(BUILD_DIR)/test/urllib-$(OS) -D TESTURLLIB lib/url.c + +testgemini: + mkdir -p $(BUILD_DIR)/test + $(CC) -o $(BUILD_DIR)/test/gemini-$(OS) -Iinclude lib/gemini.c -lssl -lcrypto -D TESTGEMLIB diff --git a/include/gemini.h b/include/gemini.h new file mode 100644 index 0000000..2926d63 --- /dev/null +++ b/include/gemini.h @@ -0,0 +1,7 @@ +#ifndef _GEMLIB_H +#define _GEMLIB_H + +int GEM_send_request (const char *request, const char *host, FILE *answerFile); +void GEM_init (void); + +#endif diff --git a/lib/gemini.c b/lib/gemini.c new file mode 100644 index 0000000..e06b592 --- /dev/null +++ b/lib/gemini.c @@ -0,0 +1,133 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef TESTGEMLIB +int +main (int argc, + char **argv) +{ + GEM_init (); + + if (argc >= 3) + { + char request[1030]; + sprintf(request, "%s\r\n", argv[1]); + + return GEM_send_request (request, argv[2], stdout); + } + + return 1; +} +#endif + +void GEM_init (void) +{ + SSL_load_error_strings(); + SSL_library_init(); +} + +int GEM_send_request (const char *request, const char *host, FILE *answerFile) +{ + const SSL_METHOD *method = TLS_client_method(); + SSL *ssl = NULL; + SSL_CTX *ctx = NULL; + BIO *bio = NULL; + int n; + int code_init = 0; + int meta_init = 0; + char answer_code[3] = {'\0'}; + char answer_meta[1024] = {'\0'}; + char buffer[1024] = {'\0'}; + + if (method == NULL) + { + perror("Method"); + ERR_print_errors_fp(stderr); + return 1; + } + + ctx = SSL_CTX_new(method); + + if (ctx == NULL) + { + perror("ctx"); + ERR_print_errors_fp(stderr); + return 1; + } + + bio = BIO_new_ssl_connect(ctx); + + if (bio == NULL) + { + perror("bio"); + ERR_print_errors_fp(stderr); + SSL_CTX_free(ctx); + return 1; + } + + BIO_get_ssl(bio, &ssl); + SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); + BIO_set_conn_hostname(bio, host); + + if (BIO_do_connect(bio) <= 0) + { + BIO_free_all(bio); + SSL_CTX_free(ctx); + perror("bio connect"); + ERR_print_errors_fp(stderr); + return 1; + } + + BIO_puts(bio, request); + + n = BIO_read(bio, buffer, 1); + + while (n > 0 && code_init == 0) + { + if (answer_code[0] == '\0') + answer_code[0] = *buffer; + else + { + answer_code[1] = *buffer; + code_init = 1; + } + n = BIO_read(bio, buffer, 1); + } + + while (n > 0 && meta_init == 0) + { + if (*buffer != '\n') + answer_meta[strlen (answer_meta)] = *buffer; + else if (answer_meta[strlen (answer_meta) - 1] == '\r') + { + answer_meta[strlen (answer_meta) - 1] = '\0'; + meta_init = 1; + } + else + { + fprintf (stderr, "Gemlib : Invalid answer header (should be CRLF terminated"); + meta_init = 1; + } + n = BIO_read(bio, buffer, 1); + } + + while (n > 0) + { + buffer[n] = '\0'; + fwrite(buffer, sizeof(char), n, answerFile); + n = BIO_read(bio, buffer, 1024); + } + + BIO_free_all(bio); + SSL_CTX_free(ctx); + + return 0; +}