Procházet zdrojové kódy

notice 19919

master
Emil Williams před 3 měsíci
rodič
revize
41c46be8a2
V databázi nebyl nalezen žádný známý klíč pro tento podpis ID GPG klíče: 5432DB986FDBCF8A
2 změnil soubory, kde provedl 239 přidání a 237 odebrání
  1. +31
    -9
      client/README
  2. +208
    -228
      client/moontalk-cli.c

+ 31
- 9
client/README Zobrazit soubor

@@ -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 Zobrazit soubor

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

Načítá se…
Zrušit
Uložit