clii/src/main.c
reemo 1b775f59cc i finally get to go home
not touching a computer for a while weow
2023-12-28 18:08:23 +00:00

250 lines
4.9 KiB
C

#include <ncurses.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include "wsock.h"
#include "ctx.h"
/** CONSTS & UTILITIES **/
/**************************/
const char FII_ADDR[] = "chatsrv-neru.flashii.net";
const char USAGE[] =
"clii -- Command-Line Flashii Chat\n"
"USAGE: clii [session key]\n\n"
"Session key will be stored for future use until\n"
"a new session key is given to the program.\n\n"
"If you do not know your session key, visit\n"
" https://flashii.net/_sockchat/token\n"
"on any web browser that is logged in.";
const char* _home(const char*);
void _ping();
/** GLOBALS **/
/***************/
struct {
int running, exit_poll;
char session[256];
wsock_t* sock;
WINDOW *wchat, *wentry;
user_t bot;
} _G;
/** MAIN **/
/************/
void print_msg(const user_t*, const char*);
void parse(char*);
int main(int argc, char** argv) {
srand(time(NULL));
FILE* fp;
switch(argc) {
case 1:
printf("Loading session key ...\n");
if((fp = fopen(_home(".fiikey"), "r")) == NULL) {
printf("No previous session key found.\n");
printf("%s\n", USAGE);
return -1;
}
fgets(_G.session, sizeof(_G.session), fp);
fclose(fp);
break;
case 2:
if(strncmp(argv[1], "--h", 3) == 0) {
printf("%s\n", USAGE);
return 0;
}
printf("New session key provided. Storing ...\n");
strcpy(_G.session, argv[1]);
if((fp = fopen(_home(".fiikey"), "w")) != NULL) {
fputs(_G.session, fp);
fclose(fp);
} else
printf("Could not write to ~/.fiikey. Session key will not be stored.\n");
break;
default:
printf("%s\n", USAGE);
return -1;
}
int in_at = 0;
char buf[2048], input[256], *get;
printf("Connecting to Flashii ...\n");
_G.sock = wsock_open(FII_ADDR, "/", 80);
fd_set fds;
struct timeval tout;
initscr();
start_color();
raw(); noecho();
keypad(stdscr, TRUE);
_G.wchat = newwin(LINES - 2, COLS, 0, 0);
scrollok(_G.wchat, TRUE);
idlok(_G.wchat, TRUE);
_G.wentry = newwin(1, COLS, LINES - 1, 0);
scrollok(_G.wentry, TRUE);
idlok(_G.wentry, TRUE);
mvhline(LINES - 2, 0, ACS_HLINE, COLS - 1);
refresh();
wprintw(_G.wchat, "Authenticating ...\n");
sprintf(buf, "1\tMisuzu\t%s", _G.session);
wsock_send_str(_G.sock, buf);
_G.bot.id = -1;
_G.bot.name = "SERVER";
memset(_G.bot.perms, 0, sizeof(_G.bot.perms));
_G.bot.color = 0; // todo: change to gray
ctx_init();
_G.exit_poll = 0;
_G.running = 1;
while(_G.running) {
_ping();
int fds_max;
FD_ZERO(&fds);
FD_SET(fileno(stdin), &fds);
if(wsock_is_open(_G.sock)) {
FD_SET(_G.sock->sock, &fds);
fds_max = _G.sock->sock;
} else
fds_max = fileno(stdin);
tout.tv_sec = 5;
tout.tv_usec = 0;
int sel = select(fds_max + 1, &fds, NULL, NULL, &tout);
if(sel > 0) {
if(FD_ISSET(fileno(stdin), &fds)) {
//if(_G.exit_poll)
// break;
int ch = getch();
if(ch == 27)
break;
if(ch == '\n') {
input[in_at] = '\0';
sprintf(buf, "2\t%i\t%s", get_self_id(), input);
in_at = 0;
wclear(_G.wentry);
}
input[in_at++] = ch;
waddch(_G.wentry, ch);
//printf("%s\n", buf);
}
if(FD_ISSET(_G.sock->sock, &fds)) {
int got = wsock_recv(_G.sock, &get);
if(got > 0) {
parse(get);
free(get);
}
}
}
wrefresh(_G.wchat);
wrefresh(_G.wentry);
}
wprintw(_G.wchat, "\nQuitting ...");
wrefresh(_G.wchat);
wsock_free(_G.sock);
ctx_free();
delwin(_G.wentry);
delwin(_G.wchat);
endwin();
return 0;
}
void chat_msg(const user_t* user, const char* msg) {
static int last_user = -1;
wprintw(_G.wchat, "\n%s: %s", user->name, msg);
}
void parse(char* msg) {
if(strlen(msg) == 0)
return;
wprintw(_G.wchat, "\n");
wprintw(_G.wchat, msg);
char *ptr = msg, count;
for(count = 1; (ptr = strchr(ptr + 1, '\t')) != NULL; ++count);
char** parts = malloc(sizeof(char*) * count);
parts[0] = ptr = msg;
for(int i = 1; (ptr = strchr(ptr + 1, '\t')) != NULL; ++i) {
*ptr = '\0';
parts[i] = ptr + 1;
}
user_t user, *puser;
channel_t chan, *pchan;
int id = strtol(parts[0], NULL, 10);
switch(id) {
case 1:
if(parts[1][0] == 'y') {
user.id = (int)strtol(parts[2], NULL, 10);
strncpy(user.name, parts[3], sizeof(user.name));
user.color = parse_color(parts[4]);
parse_perms(parts[5], USER_PERMS, user.perms);
add_user(&user);
set_self(user.id);
} else {
wprintw(_G.wchat, "Your authentication was rejected: ");
wprintw(_G.wchat, parts[2]);
wprintw(_G.wchat, "\nPress ESC to quit.\n");
_G.exit_poll = 1;
}
break;
case 2:
break;
}
free(parts);
}
const char* _home(const char* path) {
static char full_path[4096];
strcpy(full_path, getenv("HOME"));
strcat(full_path, "/");
strcat(full_path, path);
return full_path;
}
void _ping() {
static char buffer[32];
static time_t last_ping = 0;
time_t now;
int self = get_self_id();
if(self == -1)
return;
sprintf(buffer, "0\t%i", self);
if(difftime(time(&now), last_ping) >= 15) {
wsock_send_str(_G.sock, buffer);
last_ping = now;
}
}