|
|
@@ -1,11 +1,10 @@ |
|
|
|
/* moontalk.c - @BAKE cc -O2 -std=gnu99 -Wall -Wextra -pedantic -Wno-format-truncation $@ -o $* \ |
|
|
|
-D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -lncurses -ltinfo -lreadline $+ |
|
|
|
* Written by Emil. |
|
|
|
* Licensed under the GPLv3 only. |
|
|
|
* |
|
|
|
* TODO Add proper editing facilities |
|
|
|
* TODO Print sent messages |
|
|
|
*/ |
|
|
|
/* moontalk.c - @BAKE cc -O2 -std=gnu99 -Wall -Wextra -Wpedantic -Wno-format-truncation $@ -o $* \ |
|
|
|
-D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -lncurses -ltinfo $+ |
|
|
|
* Written by Emil. |
|
|
|
* Licensed under the GPLv3 only. |
|
|
|
* |
|
|
|
* TODO Add proper editing facilities |
|
|
|
*/ |
|
|
|
|
|
|
|
#include <stdio.h> |
|
|
|
#include <stdlib.h> |
|
|
@@ -13,6 +12,7 @@ |
|
|
|
#include <unistd.h> |
|
|
|
#include <signal.h> |
|
|
|
#include <time.h> |
|
|
|
#include <errno.h> |
|
|
|
|
|
|
|
#include <sys/ioctl.h> |
|
|
|
#include <sys/types.h> |
|
|
@@ -22,18 +22,33 @@ |
|
|
|
#include <netinet/in.h> |
|
|
|
|
|
|
|
#include <ncurses.h> |
|
|
|
#include <readline/readline.h> |
|
|
|
|
|
|
|
#define SERV "7ks473deh6ggtwqsvbqdurepv5i6iblpbkx33b6cydon3ajph73sssad.onion" |
|
|
|
#define PORT "50000" |
|
|
|
|
|
|
|
#define TAB 9 /* */ |
|
|
|
#define BACKSPACE 263 /* ^G */ |
|
|
|
#define C_C 4 /* ... */ |
|
|
|
#define C_D 4 /* quit */ |
|
|
|
#define C_A 1 /* BOL */ |
|
|
|
#define C_B 2 /* BOL */ |
|
|
|
#define C_E 5 /* EOL */ |
|
|
|
#define C_U 21 /* CLR TO BOL */ |
|
|
|
#define C_H 8 /* BACKSPACE */ |
|
|
|
#define C_W 23 /* DELETE PREVWORD */ |
|
|
|
#define C_L 12 /* Signal SIGWINCH */ |
|
|
|
#define C_R 18 /* hah not going to implement that */ |
|
|
|
|
|
|
|
#define UP 258 |
|
|
|
#define DOWN 259 |
|
|
|
#define LEFT 260 |
|
|
|
#define RIGHT 261 |
|
|
|
|
|
|
|
#define TIMESTR "<%Y/%m/%d %H:%M:%S " |
|
|
|
#define TIMESTRMAX 21 |
|
|
|
|
|
|
|
#define SENDMAX (1 << 8) - 1 |
|
|
|
#define RECVMAX (1 << 11) |
|
|
|
#define RECVMAX 17663 /* (1 << 11) */ |
|
|
|
|
|
|
|
#define streq(a,b) (!strcmp(a,b)) |
|
|
|
#define strneq(a,b,c) (!memcmp(a,b,c)) |
|
|
@@ -41,6 +56,24 @@ |
|
|
|
int g_y, g_x; |
|
|
|
int g_sockfd = -1; |
|
|
|
|
|
|
|
void fillline(int y, int xstart, char c) { |
|
|
|
int i = xstart, x = g_x; |
|
|
|
for (; i < x; ++i) |
|
|
|
{ mvaddch(y,i,c); } |
|
|
|
} |
|
|
|
|
|
|
|
#define TITLE(str) do { mvprintw(0,0,str); fillline(0,strlen(str),'-'); } while (0) |
|
|
|
|
|
|
|
void hardrefresh(void) { |
|
|
|
mvprintw(g_y - 2, 0, "max screen %d; max ours %d", (g_y - 3) * SENDMAX, RECVMAX); |
|
|
|
TITLE("-- MOONTALK "); |
|
|
|
fillline(g_y - 3, 0, '-'); |
|
|
|
} |
|
|
|
|
|
|
|
#undef TITLE |
|
|
|
|
|
|
|
int g_hardrefresh = 0; |
|
|
|
|
|
|
|
void init_screen(int x) { |
|
|
|
(void)x; |
|
|
|
signal(SIGWINCH, SIG_IGN); |
|
|
@@ -51,17 +84,23 @@ void init_screen(int x) { |
|
|
|
g_y = w.ws_row; |
|
|
|
g_x = w.ws_col; |
|
|
|
initscr(); |
|
|
|
cbreak(); |
|
|
|
raw(); |
|
|
|
noecho(); |
|
|
|
keypad(stdscr, ERR); |
|
|
|
nodelay(stdscr, TRUE); |
|
|
|
ESCDELAY = 0; |
|
|
|
clear(); |
|
|
|
hardrefresh(); |
|
|
|
g_hardrefresh = 1; |
|
|
|
|
|
|
|
signal(SIGWINCH, init_screen); |
|
|
|
} |
|
|
|
|
|
|
|
void free_connection(void) { |
|
|
|
close(g_sockfd); |
|
|
|
void stop(void) { |
|
|
|
int sockfd = g_sockfd; |
|
|
|
endwin(); |
|
|
|
printf("stopping now. maybe you forgot torify?\n"); |
|
|
|
if (sockfd > -1) { close(sockfd); } |
|
|
|
g_sockfd = -1; |
|
|
|
} |
|
|
|
|
|
|
@@ -71,11 +110,11 @@ int init_connection(char * serv, char * port) { |
|
|
|
struct addrinfo hints, * res; |
|
|
|
|
|
|
|
memset(&hints, 0, sizeof(struct addrinfo)); |
|
|
|
hints.ai_family = AF_UNSPEC; // don't care IPv4 or IPv6 |
|
|
|
hints.ai_socktype = SOCK_STREAM; // TCP stream sockets |
|
|
|
hints.ai_family = AF_UNSPEC; |
|
|
|
hints.ai_socktype = SOCK_STREAM; |
|
|
|
|
|
|
|
if ((status = getaddrinfo(serv, port, &hints, &res)) != 0) { |
|
|
|
fprintf(stderr, "init_connection: %s\n", gai_strerror(status)); |
|
|
|
perror("init_connection"); |
|
|
|
exit(1); |
|
|
|
} |
|
|
|
|
|
|
@@ -89,6 +128,7 @@ int init_connection(char * serv, char * port) { |
|
|
|
g_sockfd = sockfd; |
|
|
|
return sockfd; |
|
|
|
error: |
|
|
|
if (sockfd > -1) { close(sockfd); } |
|
|
|
perror("init_connection"); |
|
|
|
exit(1); |
|
|
|
__builtin_unreachable(); |
|
|
@@ -107,6 +147,15 @@ int countlines(char * buf, size_t len) { |
|
|
|
return i; |
|
|
|
} |
|
|
|
|
|
|
|
size_t getoff(char * buf, size_t len, size_t count, char c) { |
|
|
|
size_t i; |
|
|
|
for (i = 0; count && i < len; ++i) { |
|
|
|
count -= (buf[i] == c) * 1; |
|
|
|
++buf; |
|
|
|
} |
|
|
|
return i; |
|
|
|
} |
|
|
|
|
|
|
|
size_t lastline(char * buf, size_t len) { |
|
|
|
size_t ret; |
|
|
|
char * start = buf; |
|
|
@@ -151,39 +200,38 @@ int main (int argc, char ** argv) { |
|
|
|
return 1; |
|
|
|
} |
|
|
|
if (streq(*(argv-1), "-serv")) { |
|
|
|
printf("serv: %s\n", *argv); |
|
|
|
serv = *argv; |
|
|
|
} |
|
|
|
else if (streq(*(argv-1), "-port")) { |
|
|
|
printf("port: %s\n", *argv); |
|
|
|
port = *argv; |
|
|
|
} |
|
|
|
else if (streq(*(argv-1), "-name")) { |
|
|
|
printf("name: %s\n", *argv); |
|
|
|
memset(name, 0, 31); |
|
|
|
strncpy(name, *argv, 31); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* atexit(void (*endwin)(void)); */ |
|
|
|
init_screen(-1); |
|
|
|
move(1,0); |
|
|
|
printw("Connecting to %s:%s as %s\n", serv, port, name); |
|
|
|
printw("g_y: %d; g_x: %d\n", g_y, g_x); |
|
|
|
refresh(); |
|
|
|
clear(); |
|
|
|
|
|
|
|
atexit(stop); |
|
|
|
sockfd = init_connection(serv, port); |
|
|
|
|
|
|
|
char raw[SENDMAX + RECVMAX]; |
|
|
|
char * sendbuf = raw, * recvbuf = raw + SENDMAX; |
|
|
|
size_t sendminlen; |
|
|
|
size_t sendlen = sendminlen, recvlen = 0; |
|
|
|
size_t sendlen = sendminlen, recvlen = 1; |
|
|
|
|
|
|
|
time_t t; |
|
|
|
struct tm * tm; |
|
|
|
int frame = 15.; |
|
|
|
float interval = 1. / frame; |
|
|
|
useconds_t frame = 25; |
|
|
|
useconds_t interval = 1000000 / frame; |
|
|
|
int32_t ct = 0; |
|
|
|
int lc, off; |
|
|
|
int ch; |
|
|
|
int ret; |
|
|
|
|
|
|
@@ -196,75 +244,60 @@ int main (int argc, char ** argv) { |
|
|
|
sendminlen += 2; |
|
|
|
sendlen = sendminlen; |
|
|
|
|
|
|
|
rl_bind_key('\t', rl_insert); |
|
|
|
rl_catch_signals = 0; |
|
|
|
rl_catch_sigwinch = 0; |
|
|
|
rl_prep_term_function = NULL; |
|
|
|
rl_deprep_term_function = NULL; |
|
|
|
rl_change_environment = 0; |
|
|
|
|
|
|
|
#if 0 |
|
|
|
rl_getc_function = +[](FILE* ignore){ |
|
|
|
input_available = false; |
|
|
|
return (int)input; |
|
|
|
}; |
|
|
|
rl_input_available_hook = +[]{ |
|
|
|
return input_available; |
|
|
|
}; |
|
|
|
rl_redisplay_function = +[]{ |
|
|
|
wmove(myWindow, 1, 1); |
|
|
|
wclrtoeol(myWindow); |
|
|
|
box(myWindow, 0, 0); |
|
|
|
waddstr(myWindow, rl_line_buffer); |
|
|
|
wrefresh(myWindow); |
|
|
|
return; |
|
|
|
}; |
|
|
|
rl_callback_handler_install("", +[](char *line){ |
|
|
|
wmove(stdscr, 0, 0); |
|
|
|
wclrtoeol(stdscr); |
|
|
|
addstr(line); |
|
|
|
refresh(); |
|
|
|
return; |
|
|
|
}); |
|
|
|
#endif |
|
|
|
|
|
|
|
hardrefresh(); |
|
|
|
mvaddnstr(g_y - 1, 0, sendbuf, sendlen); |
|
|
|
|
|
|
|
while (1) { |
|
|
|
/* update */ |
|
|
|
if (ct % frame == 0) { |
|
|
|
if (ct % (frame) == 0) { |
|
|
|
UPDATE_TIME(); |
|
|
|
mvaddnstr(g_y - 1, 0, sendbuf, sendlen); |
|
|
|
} |
|
|
|
if (ct % (frame * 2) == 0) { |
|
|
|
ret = recv(sockfd, recvbuf + recvlen, RECVMAX - recvlen, MSG_DONTWAIT); |
|
|
|
recvlen += (ret > 0) * ret; |
|
|
|
mvaddnstr(0, 0, recvbuf, recvlen); |
|
|
|
mvprintw(g_y - 2, 0, "recvlen %ld", recvlen); |
|
|
|
if (ret > 0 || g_hardrefresh) { |
|
|
|
recvlen += ret; |
|
|
|
lc = countlines(recvbuf, recvlen); |
|
|
|
off = lc - g_y - 4; |
|
|
|
off = getoff(recvbuf, recvlen, (off > 0) * off, '\n'); |
|
|
|
mvaddnstr(1, 0, recvbuf + off, recvlen - off); |
|
|
|
g_hardrefresh = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
/* send */ |
|
|
|
ch = getch(); |
|
|
|
if (ch == -1); |
|
|
|
else if (ch == '\n') { |
|
|
|
if (sendlen == sendminlen) { continue; } |
|
|
|
sendbuf[sendlen++] = '\n'; /* terminator */ |
|
|
|
send(sockfd, sendbuf, sendlen, 0); |
|
|
|
memset(sendbuf + sendminlen, 0, sendlen - sendminlen); |
|
|
|
sendlen = sendminlen; |
|
|
|
clearline(g_y - 1); |
|
|
|
} |
|
|
|
else if (ch == BACKSPACE) { |
|
|
|
clearline(g_y - 1); |
|
|
|
if (sendlen - 1 >= sendminlen) |
|
|
|
{ --sendlen; } |
|
|
|
while ((ch = getch()) != -1) { |
|
|
|
if (ch == '\n') { |
|
|
|
if (sendlen == sendminlen) { continue; } |
|
|
|
UPDATE_TIME(); |
|
|
|
sendbuf[sendlen++] = '\n'; /* terminator */ |
|
|
|
send(sockfd, sendbuf, sendlen, 0); |
|
|
|
memcpy(recvbuf + recvlen, sendbuf, (sendlen + recvlen < RECVMAX) * sendlen); |
|
|
|
recvlen += sendlen; |
|
|
|
mvaddnstr(1, 0, recvbuf, recvlen); |
|
|
|
mvaddch(g_y - 1, sendminlen, ' '); |
|
|
|
clearline(g_y - 1); |
|
|
|
sendlen = sendminlen; |
|
|
|
} |
|
|
|
else if (ch == C_D) { |
|
|
|
exit(0); |
|
|
|
} |
|
|
|
else if (ch == BACKSPACE) { |
|
|
|
clearline(g_y - 1); |
|
|
|
if (sendlen - 1 >= sendminlen) |
|
|
|
{ mvaddch(g_y - 1, --sendlen, ' '); } |
|
|
|
mvaddnstr(g_y - 1, 0, sendbuf, sendlen); |
|
|
|
move(g_y - 1, sendlen); |
|
|
|
} |
|
|
|
else if (ch > 31 && ch < 127) { |
|
|
|
if (sendlen + 1 < SENDMAX) |
|
|
|
{ sendbuf[sendlen++] = ch; } |
|
|
|
mvaddnstr(g_y - 1, 0, sendbuf, sendlen); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (ch > 31 && ch < 127) { |
|
|
|
if (sendlen + 1 < SENDMAX) |
|
|
|
{ sendbuf[sendlen++] = ch; } |
|
|
|
} |
|
|
|
mvaddnstr(g_y - 1, 0, sendbuf, sendlen); |
|
|
|
move(g_y - 1, sendlen); |
|
|
|
/* sleep */ |
|
|
|
++ct; |
|
|
|
sleep(interval); |
|
|
|
refresh(); |
|
|
|
usleep(interval); |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |