Restructuration and add CLI tool
This commit is contained in:
parent
18ee823f95
commit
ac30a78245
|
@ -0,0 +1 @@
|
|||
build/
|
|
@ -0,0 +1,15 @@
|
|||
CC=gcc
|
||||
|
||||
all: gemcurl
|
||||
|
||||
gemlib.o: src/gemlib.c src/gemlib.h
|
||||
mkdir -p build
|
||||
$(CC) -o build/gemlib.o -c src/gemlib.c
|
||||
|
||||
gemcurl.o: src/gemlib.h src/gemcurl.c
|
||||
mkdir -p build
|
||||
$(CC) -o build/gemcurl.o -c src/gemcurl.c
|
||||
|
||||
gemcurl: gemcurl.o gemlib.o
|
||||
mkdir -p build
|
||||
$(CC) -o build/gemcurl build/gemcurl.o build/gemlib.o -lcrypto -lssl
|
94
gemini.c
94
gemini.c
|
@ -1,94 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
typedef struct _gemini_request {
|
||||
char request_content[1024];
|
||||
char hostname[256];
|
||||
char scheme[64];
|
||||
char path[1024];
|
||||
char answer_code[2];
|
||||
char answer_meta[2];
|
||||
char answer_content[8192];
|
||||
} Request;
|
||||
|
||||
Request *examineRequest(const char *request_content)
|
||||
{
|
||||
int i = 0, len = 0, len_req = strlen(request_content);
|
||||
Request *request = malloc(sizeof(Request));
|
||||
|
||||
if (request == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(request, 0, sizeof(Request));
|
||||
|
||||
strcpy(request->request_content, request_content);
|
||||
|
||||
/* We are trying to determine the protocol */
|
||||
while (i <= len_req - 3)
|
||||
if (request_content[i] != ':' || request_content[i + 1] != '/' || request_content[i + 2] != '/')
|
||||
{
|
||||
i++;
|
||||
len++;
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(request->scheme, request_content + i - len, len);
|
||||
break;
|
||||
}
|
||||
|
||||
/* If no protocol found error */
|
||||
if (request->scheme[0] == 0)
|
||||
{
|
||||
free(request);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We skip the :// */
|
||||
i += 3;
|
||||
len = 0;
|
||||
|
||||
/* We try to determine hostname + port */
|
||||
while (i < len_req && request_content[i] != '/')
|
||||
{
|
||||
i++;
|
||||
len++;
|
||||
}
|
||||
|
||||
strncpy(request->hostname, request_content + i - len, len);
|
||||
|
||||
/* if no hostname error */
|
||||
if (request->hostname[0] == 0)
|
||||
{
|
||||
free(request);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* now fill path in request struct */
|
||||
strncpy(request->path, request_content + i, strlen(request_content) - i);
|
||||
|
||||
/* if path is empty, so path is root */
|
||||
if(request->path[0] == 0)
|
||||
strcpy(request->path, "/");
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Request *request = examineRequest("http://[5f1f:fgeg::1]");
|
||||
|
||||
if (request == NULL)
|
||||
{
|
||||
printf("error during url parsing\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Request : %s\nScheme : %s\nHostname : %s\n", request->request_content, request->scheme, request->hostname);
|
||||
|
||||
free(request);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "gemlib.h"
|
||||
|
||||
#define VERSION_MAJ 0
|
||||
#define VERSION_MIN 0
|
||||
#define VERSION_REV 0
|
||||
#define NAME "gemcurl"
|
||||
|
||||
void printName (char *extra);
|
||||
void printVersion (void);
|
||||
void printLicence (void);
|
||||
void printUsage (char *command);
|
||||
void printHelp(void);
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
printUsage(argv[0]);
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "-v") == 0 | strcmp(argv[1], "--version") == 0)
|
||||
{
|
||||
printName(NULL);
|
||||
printVersion();
|
||||
printLicence();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "-h") == 0 | strcmp(argv[1], "--help") == 0)
|
||||
{
|
||||
printName("A dead simple Gemini client");
|
||||
printVersion();
|
||||
printf("\n");
|
||||
printUsage(argv[0]);
|
||||
printHelp();
|
||||
printf("\n");
|
||||
printLicence();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "-g") == 0 | strcmp(argv[1], "--get") == 0)
|
||||
{
|
||||
if (argc < 3)
|
||||
{
|
||||
printUsage(argv[0]);
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (getGem(argv[2], stdout) != 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
printUsage(argv[0]);
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
void printName (char *extra)
|
||||
{
|
||||
if (extra == NULL)
|
||||
printf("%s\n", NAME);
|
||||
else
|
||||
printf("%s : %s\n", NAME, extra);
|
||||
}
|
||||
|
||||
void printVersion (void)
|
||||
{
|
||||
if (VERSION_MIN == 0 && VERSION_REV == 0)
|
||||
printf("Version : %d\n", VERSION_MAJ);
|
||||
else if (VERSION_REV == 0)
|
||||
printf("Version : %d.%d\n", VERSION_MAJ, VERSION_MIN);
|
||||
else
|
||||
printf("Version : %d.%d.%d\n", VERSION_MAJ, VERSION_MIN, VERSION_REV);
|
||||
}
|
||||
|
||||
void printLicence (void)
|
||||
{
|
||||
printf("Written by Romain de Laage, Licence GPLv3\n");
|
||||
}
|
||||
|
||||
void printUsage (char *command)
|
||||
{
|
||||
if (command == NULL)
|
||||
printf("Usage : gemcurl CMD [URL]\n");
|
||||
else
|
||||
printf("Usage : %s CMD [URL]\n", command);
|
||||
}
|
||||
|
||||
void printHelp (void)
|
||||
{
|
||||
printf("CMD :\n\t-h | --help : Show this help\n\t-v | --version : Show version\n\t-g | --get : Get a gemini content, must be followed by the URL\n");
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include "gemlib.h"
|
||||
|
||||
Request *examineRequest(const char *request_content)
|
||||
{
|
||||
int i = 0, len = 0, len_req = strlen(request_content);
|
||||
Request *request = malloc(sizeof(Request));
|
||||
|
||||
if (request == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(request, 0, sizeof(Request));
|
||||
|
||||
strcpy(request->request_content, request_content);
|
||||
strcat(request->request_content, "\r\n");
|
||||
|
||||
/* We are trying to determine the protocol */
|
||||
while (i <= len_req - 3)
|
||||
if (request_content[i] != ':' || request_content[i + 1] != '/' || request_content[i + 2] != '/')
|
||||
{
|
||||
i++;
|
||||
len++;
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(request->scheme, request_content + i - len, len);
|
||||
break;
|
||||
}
|
||||
|
||||
/* If no protocol found error */
|
||||
if (request->scheme[0] == 0)
|
||||
{
|
||||
free(request);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We skip the :// */
|
||||
i += 3;
|
||||
len = 0;
|
||||
|
||||
/* We try to determine hostname + port */
|
||||
while (i < len_req && request_content[i] != '/')
|
||||
{
|
||||
i++;
|
||||
len++;
|
||||
}
|
||||
|
||||
strncpy(request->hostname, request_content + i - len, len);
|
||||
|
||||
/* if no hostname error */
|
||||
if (request->hostname[0] == 0)
|
||||
{
|
||||
free(request);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* now fill path in request struct */
|
||||
strncpy(request->path, request_content + i, strlen(request_content) - i);
|
||||
|
||||
/* if path is empty, so path is root */
|
||||
if (request->path[0] == 0)
|
||||
strcpy(request->path, "/");
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
void requestTheServer(Request *request, FILE *answerFile)
|
||||
{
|
||||
const SSL_METHOD *method = TLS_client_method();
|
||||
SSL *ssl = NULL;
|
||||
SSL_CTX *ctx = NULL;
|
||||
BIO *bio = NULL;
|
||||
int n;
|
||||
|
||||
if (method == NULL)
|
||||
{
|
||||
perror("Method");
|
||||
ERR_print_errors_fp(stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ctx = SSL_CTX_new(method);
|
||||
|
||||
if (ctx == NULL)
|
||||
{
|
||||
perror("ctx");
|
||||
ERR_print_errors_fp(stderr);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
bio = BIO_new_ssl_connect(ctx);
|
||||
|
||||
if (bio == NULL)
|
||||
{
|
||||
perror("bio");
|
||||
ERR_print_errors_fp(stderr);
|
||||
SSL_CTX_free(ctx);
|
||||
exit(3);
|
||||
}
|
||||
|
||||
BIO_get_ssl(bio, &ssl);
|
||||
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
|
||||
BIO_set_conn_hostname(bio, request->hostname);
|
||||
|
||||
if (BIO_do_connect(bio) <= 0)
|
||||
{
|
||||
BIO_free_all(bio);
|
||||
SSL_CTX_free(ctx);
|
||||
perror("bio connect");
|
||||
ERR_print_errors_fp(stderr);
|
||||
exit(4);
|
||||
}
|
||||
|
||||
BIO_puts(bio, request->request_content);
|
||||
|
||||
while (1)
|
||||
{
|
||||
memset(request->answer_content, 0, sizeof(request->answer_content));
|
||||
n = BIO_read(bio, request->answer_content, 1024);
|
||||
if (n <= 0) break;
|
||||
fprintf(answerFile, "%s", request->answer_content);
|
||||
}
|
||||
|
||||
BIO_free_all(bio);
|
||||
SSL_CTX_free(ctx);
|
||||
}
|
||||
|
||||
void initSSL (void)
|
||||
{
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
}
|
||||
|
||||
int getGem (const char *URL, FILE *answerFile)
|
||||
{
|
||||
Request *request = examineRequest(URL);
|
||||
|
||||
initSSL();
|
||||
|
||||
if (request == NULL)
|
||||
{
|
||||
printf("error during url parsing\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
requestTheServer(request, answerFile);
|
||||
|
||||
free(request);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef _GEMLIB_H
|
||||
#define _GEMLIB_H
|
||||
|
||||
typedef struct _gemini_request {
|
||||
char request_content[1024];
|
||||
char hostname[256];
|
||||
char scheme[64];
|
||||
char path[1024];
|
||||
char answer_code[2];
|
||||
char answer_meta[2];
|
||||
char answer_content[8192];
|
||||
} Request;
|
||||
|
||||
Request *examineRequest(const char *request_content);
|
||||
|
||||
void requestTheServer(Request *request, FILE *answerFile);
|
||||
|
||||
void initSSL (void);
|
||||
|
||||
int getGem (const char *URL, FILE *answerFile);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,39 @@
|
|||
extern char *test();
|
||||
int main (string[] args)
|
||||
{
|
||||
Gtk.init(ref args);
|
||||
|
||||
var window = new Gtk.Window ();
|
||||
window.border_width = 10;
|
||||
window.window_position = Gtk.WindowPosition.CENTER;
|
||||
window.set_default_size (350, 80);
|
||||
|
||||
var header_bar = new Gtk.HeaderBar ();
|
||||
header_bar.set_title("This is a test");
|
||||
header_bar.set_show_close_button(true);
|
||||
|
||||
var url_bar = new Gtk.Entry ();
|
||||
header_bar.pack_start(url_bar);
|
||||
|
||||
var url_go_button = new Gtk.Button.with_label("Go !");
|
||||
header_bar.pack_start(url_go_button);
|
||||
|
||||
window.destroy.connect (Gtk.main_quit);
|
||||
|
||||
window.set_titlebar(header_bar);
|
||||
|
||||
var content = new Gtk.TextView();
|
||||
content.set_editable(false);
|
||||
|
||||
window.add(content);
|
||||
|
||||
window.show_all ();
|
||||
|
||||
// content.buffer.text = (string)test();
|
||||
content.buffer.text = "This is an example of text.";
|
||||
content.set_cursor_visible(false);
|
||||
|
||||
Gtk.main();
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue