Ver código fonte

notice 19919

master
Emil Williams 3 meses atrás
pai
commit
41c46be8a2
Nenhuma chave conhecida encontrada para esta assinatura no banco de dados ID da chave GPG: 5432DB986FDBCF8A
2 arquivos alterados com 239 adições e 237 exclusões
  1. +31
    -9
      client/README
  2. +208
    -228
      client/moontalk-cli.c

+ 31
- 9
client/README Ver arquivo

@@ -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.tcl:
moontalk-cli.c:

you'll need tcl and tk to run it.
Click the bottom bar to talk.
particually functional, should just werk for normal chatting.
Not as nice for editing text, full NCurses interface.

moontalk.c:
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

Is incomplete, and limited, but is usable.
Run -help for usage.

To compile it, use bake <https://git.lain.church/emil/bake> or just run:
gcc -O2 -std=gnu99 moontalk.c -o moontalk -lncurses -ltinfo
-- GUI Clients --

moontalk.tcl:

Run -help for further details for usage.
Runs off of tcl/tk, just werks.

you'll need tcl and tk to run it.
Click the bottom bar to talk.
Graceful about reconnections.

+ 208
- 228
client/moontalk-cli.c Ver arquivo

@@ -1,10 +1,8 @@
/* 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
*/
-D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -lncurses -ltinfo $+
* Written by Emil.
* Licensed under the GPLv3 only.
*/

#include <stdio.h>
#include <stdlib.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_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 C_L 12 /* Signal full refresh */

#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;
}
@@ -116,7 +75,7 @@ int init_connection(char * serv, char * port) {
struct addrinfo hints, * res;

memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;

if ((status = getaddrinfo(serv, port, &hints, &res)) != 0) {
@@ -140,215 +99,236 @@ 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 = '!'; }
}
--buf;
}
return 0;
}

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;
}
if (argc - 1)
{ --argc; ++argv; }
else {
printf("%s: %s requires argument\n", argv0, *argv);
return 1;
}
if (streq(*(argv-1), "-serv")) {
serv = *argv;
}
else if (streq(*(argv-1), "-port")) {
port = *argv;
}
else if (streq(*(argv-1), "-name")) {
memset(name, 0, 31);
strncpy(name, *argv, 31);
while (++argv, --argc) {
if (streq(*argv, "-help")) {
printf(HELP, argv0);
exit(1);
}
if (argc - 1)
{ --argc; ++argv; }
else {
printf("%s: %s requires argument\n", argv0, *argv);
return 1;
}
if (streq(*(argv-1), "-serv")) {
serv = *argv;
} else if (streq(*(argv-1), "-port")) {
port = *argv;
} else if (streq(*(argv-1), "-name")) {
memset(name, 0, 31);
strncpy(name, *argv, 31);
}
}

printf("Connecting to %s:%s as %s\n", serv, port, name);

atexit(disconnect);
sockfd = init_connection(serv, port);
}

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();
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;

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;
/* fill in the name */
memcpy(sendbuf + TIMESTRMAX, name, namelen);
memcpy(sendbuf + TIMESTRMAX + namelen, "> ", 2);

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 */
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) {
/* input */
while ((ch = getch()) != -1) {
if (ch == '\n') {
if (sendlen == sendminlen) {
continue;
}
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[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 - 1, sendbuf, (sendlen + recvlen - 1 < RECVMAX) * sendlen);
memcpy(recvbuf + recvlen, sendbuf, (sendlen + recvlen < RECVMAX) * sendlen);
recvlen += sendlen;
hardrefresh = 1;
offlen += sendlen;
} else {
mvprintw(g_y - 2, 0, "message failed: %s", strerror(errno));
mvwprintw(input, 1, 0, "message failed: %s", strerror(errno));
}
mvaddch(g_y - 1, sendminlen, ' ');
inputrefresh = 1;
clearline(g_y - 1);
sendlen = sendminlen;
}
else if ((ch > 31 && ch < 127)) {
if (sendlen + 1 < SENDMAX)
{ sendbuf[sendlen++] = ch; }
mvaddnstr(g_y - 1, 0, sendbuf, sendlen);
/* 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 == KEY_RIGHT) {
/* if (edit - 1 < sendlen) { ++edit; } */
}
else if (ch == C_N) {
while (*off != '\n') { ++off; }
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;

}
/* 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;
}
else if (ch == C_D) {
exit(0);
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();
}

Carregando…
Cancelar
Salvar