]> git.xolatile.top Git - public-moontalk.git/commitdiff
notice 19919
authorEmil Williams <emilwilliams@tuta.io>
Fri, 9 Feb 2024 21:48:08 +0000 (21:48 +0000)
committerEmil Williams <emilwilliams@tuta.io>
Fri, 9 Feb 2024 21:48:08 +0000 (21:48 +0000)
client/README
client/moontalk-cli.c

index 58b234b0696142eefdbcb6088da8e8c514a4c726..3e4102348ea4f3b7936b030844a34ed05ee95720 100644 (file)
@@ -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.
index f84698fba0ba030c64ab7d98ab0bf12d86fe77f8..be680583283d46e753b67db5804ff7f225c46b96 100644 (file)
@@ -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>
 
 #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 */
 #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();
 }