gemclient/tls2.c

188 lines
3.9 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tls.h>
#include <ncurses.h>
const char towrite[] = "gemini://tilde.club/\r\n";
typedef struct ll {
void *data;
struct ll *next;
struct ll *prev; /* optional */
} ll;
char *tls_incremental_line_read(struct tls *context) {
char buffer;
int bufsize = 40;
int current = 0;
int read;
char *initial = malloc(bufsize);
for(;;) {
if(!(read = tls_read(context, &buffer, 1))) {
free(initial);
return NULL;
}
switch(buffer) {
case '\n':
case '\r':
case '\0':
initial[current] = '\0';
return initial;
}
initial[current++] = buffer;
if(current == bufsize - 2) {
initial = realloc(initial, bufsize *= 2);
}
}
}
struct tls_config *tls_defconfig(void) {
struct tls_config *r = tls_config_new();
tls_config_insecure_noverifycert(r);
tls_config_insecure_noverifyname(r);
return r;
}
struct tls *dial(char *addr, char *port) {
struct tls_config *t = tls_defconfig();
struct tls *client = tls_client();
tls_configure(client, t);
tls_connect(client, addr, port);
tls_config_free(t);
return client;
}
void ncurses_init(void) {
initscr();
keypad(stdscr, TRUE);
nonl();
cbreak();
noecho();
if(has_colors()) {
init_pair(COLOR_BLACK, COLOR_BLACK, COLOR_BLACK);
init_pair(COLOR_GREEN, COLOR_GREEN, COLOR_BLACK);
init_pair(COLOR_RED, COLOR_RED, COLOR_BLACK);
init_pair(COLOR_CYAN, COLOR_CYAN, COLOR_BLACK);
init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK);
init_pair(COLOR_MAGENTA, COLOR_MAGENTA, COLOR_BLACK);
init_pair(COLOR_BLUE, COLOR_BLUE, COLOR_BLACK);
init_pair(COLOR_YELLOW, COLOR_YELLOW, COLOR_BLACK);
}
}
void ncurses_cleanup(void) {
endwin();
}
void manager(void *newdata, ll **ptr, ll **head) {
if(*ptr == NULL) {
*ptr = malloc(sizeof **ptr);
*head = *ptr;
(*ptr)->prev = NULL;
} else {
(*ptr)->next = malloc(sizeof **ptr);
(*ptr)->next->prev = *ptr;
*ptr = (*ptr)->next;
}
(*ptr)->next = NULL;
(*ptr)->data = newdata;
}
int is_link(char *c) {
return c[0] == '=' && c[1] == '>';
}
ll *scroll_ll(int direction, ll *current) {
if(direction) {
if(current->next) {
return current->next;
}
} else {
if(current->prev) {
return current->prev;
}
}
return current;
}
void render(int yinit, int ymax, ll *data) {
ll *ptr2 = data;
erase();
while(ptr2) {
mvprintw(yinit++, 0, "%s", ptr2->data);
ptr2 = ptr2->next;
if(yinit == ymax) break;
}
}
ll *fetch_and_render(struct tls *ctx, int yinit, int ymax, char *url) {
tls_write(ctx, url, strlen(url));
tls_write(ctx, "\r\n", 2);
ll *doc = NULL, *dochead = NULL, *links = NULL, *linkhead = NULL;
char *c;
int to_screen = 0;
while(c = tls_incremental_line_read(ctx)) {
manager(c, &doc, &dochead);
if(is_link(c)) manager(c, &links, &linkhead);
if(!to_screen) {
mvwprintw(stdscr, yinit++, 0, "%s", c);
} else if(to_screen == 1) {
refresh();
to_screen++;
}
if(yinit == ymax) to_screen = 1;
}
ll *document = malloc(sizeof *document);
ll *rlinks = malloc(sizeof *rlinks);
document->data = dochead;
document->next = rlinks;
document->prev = NULL;
rlinks->data = linkhead;
rlinks->next = NULL;
rlinks->prev = document;
return document;
}
int main(void) {
struct tls *ctx = dial("tilde.club", "1965");
int tx, ty;
getmaxyx(stdscr, ty, tx);
char getchb;
ll *ptr = NULL, *head = NULL;
tls_write(ctx, &towrite, sizeof towrite);
ncurses_init();
ll *docdata = fetch_and_render(ctx, 1, ty, "gemini://tilde.club/");
ptr = docdata->data;
while(ptr) {
getchb = getch();
if(getchb == 'k') {
ptr = scroll_ll(TRUE, ptr);
} else if(getchb == 'q') {
ptr = NULL;
} else {
ptr = scroll_ll(FALSE, ptr);
}
render(1, ty, ptr);
}
ncurses_cleanup();
return 0;
}