188 lines
3.9 KiB
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;
|
|
}
|