notice 19919
This commit is contained in:
parent
81eeb80bc8
commit
41c46be8a2
@ -1,20 +1,42 @@
|
||||
USE moontalk.rb, or moontalk.tcl!
|
||||
-- "Raw" Clients --
|
||||
|
||||
The classic:
|
||||
requires netcat and torify
|
||||
torify netcat 7ks473deh6ggtwqsvbqdurepv5i6iblpbkx33b6cydon3ajph73sssad.onion 50000
|
||||
|
||||
The socat:
|
||||
requires socat and tor daemon
|
||||
socat - SOCKS4A:127.0.0.1:7ks473deh6ggtwqsvbqdurepv5i6iblpbkx33b6cydon3ajph73sssad.onion:50000,socksport=9050
|
||||
|
||||
Extension for raw clients:
|
||||
You can attach rlwrap (readline, bundled seperately) to connect, it'll provide a better experience than going in raw.
|
||||
Consider using this if your messages ever get split.
|
||||
|
||||
-- CLI Clients --
|
||||
|
||||
moontalk.rb:
|
||||
|
||||
Runs off of ruby, just werks.
|
||||
|
||||
You'll need to install ruby to run it.
|
||||
See source code for usage.
|
||||
|
||||
moontalk-cli.c:
|
||||
|
||||
particually functional, should just werk for normal chatting.
|
||||
Not as nice for editing text, full NCurses interface.
|
||||
|
||||
To compile it, use bake <https://git.lain.church/emil/bake> or just run:
|
||||
gcc -O2 -std=gnu99 moontalk-cli.c -o moontalk-cli -lncurses -ltinfo
|
||||
|
||||
Run -help for usage.
|
||||
|
||||
-- GUI Clients --
|
||||
|
||||
moontalk.tcl:
|
||||
|
||||
Runs off of tcl/tk, just werks.
|
||||
|
||||
you'll need tcl and tk to run it.
|
||||
Click the bottom bar to talk.
|
||||
|
||||
moontalk.c:
|
||||
|
||||
Is incomplete, and limited, but is usable.
|
||||
|
||||
To compile it, use bake <https://git.lain.church/emil/bake> or just run:
|
||||
gcc -O2 -std=gnu99 moontalk.c -o moontalk -lncurses -ltinfo
|
||||
|
||||
Run -help for further details for usage.
|
||||
Graceful about reconnections.
|
||||
|
@ -2,8 +2,6 @@
|
||||
-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>
|
||||
@ -26,6 +24,29 @@
|
||||
|
||||
#define SERV "7ks473deh6ggtwqsvbqdurepv5i6iblpbkx33b6cydon3ajph73sssad.onion"
|
||||
#define PORT "50000"
|
||||
#define NAME "anonymous"
|
||||
|
||||
#define streq(a,b) (!strcmp(a,b))
|
||||
#define strneq(a,b,c) (!memcmp(a,b,c))
|
||||
|
||||
int g_sockfd;
|
||||
|
||||
#define g_y LINES
|
||||
#define g_x COLS
|
||||
|
||||
#define HELP \
|
||||
"%s [options ...]\n" \
|
||||
"\n-serv SERVER Sets the server to connect to [default: " SERV "]" \
|
||||
"\n-port PORT Sets the port [default: " PORT "]" \
|
||||
"\n-name NAME Sets your display name [default: " NAME "]\n" \
|
||||
"\nControls\n" \
|
||||
"\nC-l Refreshes the screen" \
|
||||
"\nC-w Delete the previous word" \
|
||||
"\nC-c Close the client" \
|
||||
"\nUp/Down Scrolls all the way up/Scrolls down by a line\n"
|
||||
|
||||
|
||||
/* I know, and I don't care */
|
||||
|
||||
#define TAB 9 /* */
|
||||
#define BACKSPACE 263 /* ^G */
|
||||
@ -38,74 +59,12 @@
|
||||
#define C_L 12 /* REFRESH */
|
||||
#define C_U 21 /* CLR TO BOL */
|
||||
#define C_W 23 /* DELETE PREVWORD */
|
||||
#define C_L 12 /* Signal SIGWINCH */
|
||||
#define C_R 18 /* hah not going to implement that */
|
||||
#define C_L 12 /* Signal full refresh */
|
||||
|
||||
#define C_T 20 /* scroll up */
|
||||
#define C_N 14 /* scroll down */
|
||||
/****/
|
||||
|
||||
#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 17663 /* (1 << 11) */
|
||||
|
||||
#define streq(a,b) (!strcmp(a,b))
|
||||
#define strneq(a,b,c) (!memcmp(a,b,c))
|
||||
|
||||
#define g_y COLS
|
||||
#define g_x LINES
|
||||
|
||||
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 decoration(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;
|
||||
WINDOW * header, * body, * input;
|
||||
signal(SIGWINCH, SIG_IGN);
|
||||
|
||||
endwin();
|
||||
struct winsize w;
|
||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||
initscr();
|
||||
raw();
|
||||
noecho();
|
||||
keypad(stdscr, ERR);
|
||||
nodelay(stdscr, TRUE);
|
||||
ESCDELAY = 0;
|
||||
clear();
|
||||
decoration();
|
||||
g_hardrefresh = 1;
|
||||
|
||||
signal(SIGWINCH, init_screen);
|
||||
}
|
||||
|
||||
void stop(void) {
|
||||
void disconnect(void) {
|
||||
int sockfd = g_sockfd;
|
||||
endwin();
|
||||
printf("stopping now.\n");
|
||||
if (sockfd > -1) { close(sockfd); }
|
||||
g_sockfd = -1;
|
||||
}
|
||||
@ -140,63 +99,41 @@ error:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#if 0
|
||||
int getanonval(char * buf, size_t len) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
//
|
||||
|
||||
int countlines(char * buf, size_t len) {
|
||||
size_t i = 0;
|
||||
for (buf += len - 1; *buf; --buf)
|
||||
{ i += (*buf == '\n'); }
|
||||
return i;
|
||||
void fillline(WINDOW * w, int y, int xstart, char c) {
|
||||
int i = xstart, x = g_x;
|
||||
for (; i < x; ++i)
|
||||
{ mvwaddch(w,y,i,c); }
|
||||
}
|
||||
|
||||
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;
|
||||
void clearline(WINDOW * w, int y) {
|
||||
wmove(w, y, 0);
|
||||
wclrtoeol(w);
|
||||
}
|
||||
|
||||
size_t lastline(char * buf, size_t len) {
|
||||
size_t ret;
|
||||
char * start = buf;
|
||||
for (buf += len - 1; *buf; --buf) {
|
||||
ret = (*buf == '\n') ? buf - start : 0;
|
||||
if (ret) { return ret; }
|
||||
void sanitize(char * buf, size_t rem) {
|
||||
char * base = buf;
|
||||
buf += rem;
|
||||
while (buf - base) {
|
||||
if (*buf < ' ' || *buf > '~') {
|
||||
if (*buf != '\n')
|
||||
{ *buf = '!'; }
|
||||
}
|
||||
return 0;
|
||||
--buf;
|
||||
}
|
||||
|
||||
void clearline(int y) {
|
||||
int oldy, oldx;
|
||||
getyx(stdscr, oldy, oldx);
|
||||
move(y, 0);
|
||||
clrtoeol();
|
||||
move(oldy, oldx);
|
||||
}
|
||||
|
||||
#define UPDATE_TIME() do { \
|
||||
t = time(NULL); \
|
||||
tm = gmtime(&t); \
|
||||
strftime(sendbuf, TIMESTRMAX, TIMESTR, tm); \
|
||||
sendbuf[TIMESTRMAX - 1] = ' '; } while (0)
|
||||
|
||||
|
||||
int main (int argc, char ** argv) {
|
||||
char * argv0 = argv[0];
|
||||
char * serv = SERV, * port = PORT, name[32] = "anonymous";
|
||||
|
||||
char * serv = SERV, * port = PORT, name[32] = NAME;
|
||||
int sockfd;
|
||||
{
|
||||
char * argv0 = argv[0];
|
||||
|
||||
while (++argv, --argc) {
|
||||
if (streq(*argv, "-help")) {
|
||||
printf("%s: HELP\n", argv0);
|
||||
return 1;
|
||||
printf(HELP, argv0);
|
||||
exit(1);
|
||||
}
|
||||
if (argc - 1)
|
||||
{ --argc; ++argv; }
|
||||
@ -206,149 +143,192 @@ int main (int argc, char ** argv) {
|
||||
}
|
||||
if (streq(*(argv-1), "-serv")) {
|
||||
serv = *argv;
|
||||
}
|
||||
else if (streq(*(argv-1), "-port")) {
|
||||
} else if (streq(*(argv-1), "-port")) {
|
||||
port = *argv;
|
||||
}
|
||||
else if (streq(*(argv-1), "-name")) {
|
||||
} else if (streq(*(argv-1), "-name")) {
|
||||
memset(name, 0, 31);
|
||||
strncpy(name, *argv, 31);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
printf("Connecting to %s:%s as %s\n", serv, port, name);
|
||||
|
||||
atexit(disconnect);
|
||||
sockfd = init_connection(serv, port);
|
||||
}
|
||||
|
||||
initscr();
|
||||
noecho();
|
||||
keypad(stdscr, ERR);
|
||||
nodelay(stdscr, TRUE);
|
||||
ESCDELAY = 0;
|
||||
curs_set(0);
|
||||
clear();
|
||||
|
||||
atexit(stop);
|
||||
sockfd = init_connection(serv, port);
|
||||
#define WINCOUNT 3
|
||||
WINDOW * w[WINCOUNT];
|
||||
#define header w[0]
|
||||
#define body w[1]
|
||||
#define input w[2]
|
||||
|
||||
#define SENDMAX (1 << 8) - 1
|
||||
#define RECVMAX 17663 /* (1 << 11) */
|
||||
|
||||
char raw[SENDMAX + RECVMAX];
|
||||
char * sendbuf = raw, * recvbuf = raw + SENDMAX, * off = recvbuf;
|
||||
size_t sendminlen;
|
||||
size_t sendlen = sendminlen, recvlen = 1, offlen = (g_y - 4) * 255;
|
||||
size_t sendminlen, sendlen, recvlen = 0, offlen = recvlen;
|
||||
size_t edit;
|
||||
|
||||
#define TIMESTR "<%Y/%m/%d %H:%M:%S "
|
||||
#define TIMESTRMAX 21
|
||||
|
||||
|
||||
#define UPDATE_TIME()\
|
||||
do { \
|
||||
t = time(NULL); \
|
||||
tm = gmtime(&t); \
|
||||
strftime(sendbuf, TIMESTRMAX, TIMESTR, tm); \
|
||||
sendbuf[TIMESTRMAX - 1] = ' '; \
|
||||
} while (0)
|
||||
|
||||
time_t t;
|
||||
struct tm * tm;
|
||||
|
||||
useconds_t frame = 30;
|
||||
useconds_t interval = 1000000 / frame;
|
||||
int32_t ct = 0;
|
||||
/* int lc, off; */
|
||||
int hardrefresh = 0, inputrefresh = 1;
|
||||
int ch;
|
||||
int ret;
|
||||
useconds_t interval = 1000000. / frame;
|
||||
int32_t ct;
|
||||
|
||||
sendminlen = TIMESTRMAX;
|
||||
int ch, ret;
|
||||
size_t i;
|
||||
|
||||
memcpy(sendbuf + sendminlen, name, strlen(name));
|
||||
sendminlen += strlen(name);
|
||||
memcpy(sendbuf + sendminlen, "> ", 2);
|
||||
sendminlen += 2;
|
||||
sendlen = sendminlen;
|
||||
size_t namelen = strlen(name);
|
||||
|
||||
decoration();
|
||||
mvaddnstr(g_y - 1, 0, sendbuf, sendlen);
|
||||
edit = sendlen = sendminlen = TIMESTRMAX + namelen + 2;
|
||||
|
||||
/* fill in the name */
|
||||
memcpy(sendbuf + TIMESTRMAX, name, namelen);
|
||||
memcpy(sendbuf + TIMESTRMAX + namelen, "> ", 2);
|
||||
|
||||
int inputrefresh, bodyrefresh;
|
||||
|
||||
hardrefresh:
|
||||
ct = 0;
|
||||
inputrefresh = bodyrefresh = 1;
|
||||
|
||||
header = newwin(1, g_x, 0, 0);
|
||||
body = newwin(g_y - 4, g_x, 1, 0);
|
||||
input = newwin(3, g_x, g_y - 3, 0);
|
||||
|
||||
fillline(header, 0, 0, '-');
|
||||
mvwprintw(header, 0, 2, " moontalk ");
|
||||
fillline(input, 0, 0, '-');
|
||||
|
||||
while (1) {
|
||||
nextloop:
|
||||
hardrefresh |= g_hardrefresh;
|
||||
/* update */
|
||||
if (ct % (frame) == 0 || inputrefresh) {
|
||||
UPDATE_TIME();
|
||||
mvaddnstr(g_y - 1, 0, sendbuf, sendlen);
|
||||
}
|
||||
/* recv */
|
||||
if (ct % (frame * 2) == 0) {
|
||||
ret = recv(sockfd, recvbuf + recvlen - 1, RECVMAX - recvlen + 1, MSG_DONTWAIT);
|
||||
mvprintw(g_y - 2, 150, "ct:%d:%d:called", ct, ret);
|
||||
if (ret > -1) {
|
||||
recvlen += ret;
|
||||
|
||||
mvprintw(g_y - 2, 50, "rendstat ct:%d:%d:%ld", ct, ret, recvlen);
|
||||
if (ret > 0 && recvbuf[recvlen-1] == '\n') {
|
||||
mvprintw(g_y - 2, 0, "newline at %ld", recvlen-1);
|
||||
}
|
||||
mvprintw(g_y - 2, 130, "ct:%d:rendered", ct);
|
||||
hardrefresh = 1;
|
||||
}
|
||||
}
|
||||
if (hardrefresh) {
|
||||
mvprintw(g_y - 2, 100, "ct:%d:REFRESH INVOKED", ct);
|
||||
mvaddnstr(1, 0, off, offlen);
|
||||
hardrefresh = 0;
|
||||
g_hardrefresh = 0;
|
||||
}
|
||||
/* send */
|
||||
/* input */
|
||||
while ((ch = getch()) != -1) {
|
||||
if (ch == '\n') {
|
||||
if (sendlen == sendminlen) {
|
||||
continue;
|
||||
}
|
||||
if (sendlen + 1 < SENDMAX)
|
||||
{ sendbuf[sendlen++] = '\n'; }
|
||||
if (send(sockfd, sendbuf, sendlen, 0) > 0) {
|
||||
memcpy(recvbuf + recvlen - 1, sendbuf, (sendlen + recvlen - 1 < RECVMAX) * sendlen);
|
||||
recvlen += sendlen;
|
||||
hardrefresh = 1;
|
||||
} else {
|
||||
mvprintw(g_y - 2, 0, "message failed: %s", strerror(errno));
|
||||
}
|
||||
mvaddch(g_y - 1, sendminlen, ' ');
|
||||
inputrefresh = 1;
|
||||
clearline(g_y - 1);
|
||||
sendlen = sendminlen;
|
||||
if (ch == KEY_RESIZE || ch == C_L) {
|
||||
for (i = 0; i < WINCOUNT; ++i)
|
||||
{ delwin(w[i]); }
|
||||
endwin();
|
||||
erase();
|
||||
refresh();
|
||||
clear();
|
||||
flushinp();
|
||||
goto hardrefresh;
|
||||
}
|
||||
else if ((ch > 31 && ch < 127)) {
|
||||
if (sendlen + 1 < SENDMAX)
|
||||
{ sendbuf[sendlen++] = ch; }
|
||||
mvaddnstr(g_y - 1, 0, sendbuf, sendlen);
|
||||
{ sendbuf[edit++] = ch; ++sendlen; }
|
||||
/* mvwchgat(input, 2, sendlen - 1, 1, A_REVERSE, 0, NULL); */
|
||||
mvwaddnstr(input, 2, 0, sendbuf, sendlen);
|
||||
}
|
||||
else if (ch == '\n') {
|
||||
if (sendlen == sendminlen)
|
||||
{ continue; }
|
||||
if (sendlen + 1 < SENDMAX)
|
||||
{ sendbuf[sendlen++] = '\n'; }
|
||||
if (send(sockfd, sendbuf, sendlen, 0) > 0) {
|
||||
memcpy(recvbuf + recvlen, sendbuf, (sendlen + recvlen < RECVMAX) * sendlen);
|
||||
recvlen += sendlen;
|
||||
offlen += sendlen;
|
||||
} else {
|
||||
mvwprintw(input, 1, 0, "message failed: %s", strerror(errno));
|
||||
}
|
||||
/* mvwaddch(0, sendminlen, ' '); */
|
||||
/* mvwchgat(input, 2, 0, 1, A_STANDOUT, 0, NULL); */
|
||||
bodyrefresh = inputrefresh = 1;
|
||||
clearline(input, 2);
|
||||
edit = sendlen = sendminlen;
|
||||
}
|
||||
else if (ch == BACKSPACE || ch == C_H) {
|
||||
inputrefresh = 1;
|
||||
clearline(g_y - 1);
|
||||
clearline(input, 2);
|
||||
if (sendlen - 1 >= sendminlen)
|
||||
{ mvaddch(g_y - 1, --sendlen, ' '); }
|
||||
mvaddnstr(g_y - 1, 0, sendbuf, sendlen);
|
||||
move(g_y - 1, sendlen);
|
||||
goto nextloop;
|
||||
{ mvwaddch(input, 2, --sendlen, ' '); --edit; }
|
||||
mvwaddnstr(input, 2, 0, sendbuf, sendlen);
|
||||
wmove(input, 2, sendlen);
|
||||
}
|
||||
else if (ch == C_T) {
|
||||
while (*off != '\n') { --off; }
|
||||
if (*off == '\n') { ++off; }
|
||||
hardrefresh = 1;
|
||||
else if (ch == KEY_LEFT) {
|
||||
/* if (edit > sendminlen) { --edit; } */
|
||||
}
|
||||
else if (ch == C_N) {
|
||||
while (*off != '\n') { ++off; }
|
||||
else if (ch == KEY_RIGHT) {
|
||||
/* if (edit - 1 < sendlen) { ++edit; } */
|
||||
}
|
||||
else if (ch == KEY_DOWN) {
|
||||
mvwprintw(input, 1, 150, "scroll down %ld", offlen);
|
||||
while (off - recvbuf < RECVMAX && *off != '\n') { ++off; }
|
||||
if (*off == '\n') { ++off; }
|
||||
hardrefresh = 1;
|
||||
wclear(body);
|
||||
bodyrefresh = 1;
|
||||
}
|
||||
else if (ch == KEY_UP) {
|
||||
mvwprintw(input, 1, 150, "scroll up %ld", offlen);
|
||||
while (off - recvbuf > 0) { --off; }
|
||||
/* wclear(body); */
|
||||
bodyrefresh = 1;
|
||||
}
|
||||
else if (ch == C_W) {
|
||||
while (sendlen > sendminlen && ispunct(sendbuf[sendlen - 1])) { --sendlen; }
|
||||
while (sendlen > sendminlen && isspace(sendbuf[sendlen - 1])) { --sendlen; }
|
||||
while (sendlen > sendminlen && isalnum(sendbuf[sendlen - 1])) { --sendlen; }
|
||||
inputrefresh = 1;
|
||||
clearline(g_y - 1);
|
||||
goto nextloop;
|
||||
clearline(input, 2);
|
||||
}
|
||||
else if (ch == C_L) {
|
||||
clear();
|
||||
decoration();
|
||||
hardrefresh = 1;
|
||||
ct = 0;
|
||||
goto nextloop;
|
||||
|
||||
}
|
||||
else if (ch == C_D) {
|
||||
exit(0);
|
||||
/* update and rendering */
|
||||
if (ct % frame == 0 || inputrefresh || bodyrefresh) {
|
||||
UPDATE_TIME();
|
||||
/* wclear(input); */
|
||||
mvwaddnstr(input, 2, 0, sendbuf, sendlen);
|
||||
|
||||
ret = recv(sockfd, recvbuf + recvlen, RECVMAX - recvlen, MSG_DONTWAIT);
|
||||
if (errno != EAGAIN)
|
||||
{ mvwaddstr(input, 1, 0, strerror(errno)); }
|
||||
if (bodyrefresh) {
|
||||
bodyrefresh = 0;
|
||||
if (!(ret > -1))
|
||||
goto _bodyrefresh;
|
||||
}
|
||||
if (ret > -1) {
|
||||
sanitize(recvbuf + recvlen, ret);
|
||||
if (ret + recvlen < RECVMAX)
|
||||
{
|
||||
recvlen += ret;
|
||||
offlen += ret;
|
||||
}
|
||||
_bodyrefresh:
|
||||
mvwprintw(input, 1, 50, "render ct:%d ret:%d", ct, ret);
|
||||
mvwaddnstr(body, 0,0, off, offlen);
|
||||
}
|
||||
}
|
||||
/* frame update */
|
||||
move(g_y - 1, sendlen);
|
||||
++ct;
|
||||
refresh();
|
||||
for (i = 0; i < WINCOUNT; ++i)
|
||||
{ wnoutrefresh(w[i]); }
|
||||
doupdate();
|
||||
usleep(interval);
|
||||
++ct;
|
||||
}
|
||||
return 0;
|
||||
|
||||
endwin();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user