]> git.xolatile.top Git - public-moontalk.git/commitdiff
updated clients
authorEmil Williams <emilwilliams@tuta.io>
Mon, 5 Feb 2024 21:20:06 +0000 (21:20 +0000)
committerEmil Williams <emilwilliams@tuta.io>
Mon, 5 Feb 2024 21:20:06 +0000 (21:20 +0000)
client/moontalk-cli.c
client/moontalk.rb
client/moontalk.sh [new file with mode: 0644]

index 7cdd855a3928e6b68ce529a9d5ea7bc5c4961d57..57c1f946708262e9eff694ad23b54fb68de58330 100644 (file)
@@ -1,7 +1,11 @@
-/* moontalk.c - @BAKE cc -O2 -std=gnu99 -Wall -Wextra -pedantic $@ -o $* -lncurses -ltinfo $+
- * Written by Emil.
- * Licensed under the GPLv3 only.
- */
+/* 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
+   */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <netinet/in.h>
 
 #include <ncurses.h>
+#include <readline/readline.h>
 
 #define SERV "7ks473deh6ggtwqsvbqdurepv5i6iblpbkx33b6cydon3ajph73sssad.onion"
 #define PORT "50000"
 
+#define BACKSPACE 263 /* ^G */
+
+#define TIMESTR "<%Y/%m/%d %H:%M:%S "
+#define TIMESTRMAX 21
+
+#define SENDMAX (1 << 8) - 1
+#define RECVMAX (1 << 11)
+
 #define streq(a,b) (!strcmp(a,b))
+#define strneq(a,b,c) (!memcmp(a,b,c))
 
-int g_row, g_col;
+int g_y, g_x;
+int g_sockfd = -1;
 
-void free_screen(void) {
-       endwin();
-}
+void  init_screen(int x) {
+       (void)x;
+       signal(SIGWINCH, SIG_IGN);
 
-void init_screen(void) {
+       endwin();
+       struct winsize w;
+       ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
+       g_y = w.ws_row;
+       g_x = w.ws_col;
        initscr();
        cbreak();
        noecho();
        keypad(stdscr, ERR);
        nodelay(stdscr, TRUE);
-}
-
-void  handle_winch(int x) {
-       (void)x;
-       struct winsize w;
-       signal(SIGWINCH, SIG_IGN);
-
-       endwin();
-       init_screen();
-       refresh();
        clear();
 
-       ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
-       g_row = w.ws_row;
-       g_col = w.ws_col;
-
-       signal(SIGWINCH, handle_winch);
+       signal(SIGWINCH, init_screen);
 }
 
-int g_sockfd = -1;
-
 void free_connection(void) {
        close(g_sockfd);
        g_sockfd = -1;
-
-       /* the program should be at an end. If we're reconnecting, then at
-          the top level (main) we'd free, even though the main's sockfd is now
-          out-of-date, we can simply ignore that and take the result of socket
-          init */
 }
 
 /* always returns an accessible socket */
@@ -96,15 +94,48 @@ 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;
+}
+
+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; }
+       }
+       return 0;
+}
+
+void clearline(int y) {
+       int x = g_x;
+       int oldy, oldx;
+       getyx(stdscr, oldy, oldx);
+       move(y, x);
+       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 = "anonymous";
-
-       #define PREFIX_MAX 21
-       char raw[(2 << 9) + (2 << 13)];
-       char * sendbuf = raw + PREFIX_MAX, * recvbuf = raw + (2 << 9);
-       size_t sendlen = 0, sendmax = (2 << 9) - PREFIX_MAX,
-              recvlen = 0, recvmax = 2 << 13;
+       char * serv = SERV, * port = PORT, name[32] = "anonymous";
 
        int sockfd;
 
@@ -125,44 +156,115 @@ int main (int argc, char ** 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(free_screen);
-       init_screen();
-       signal(SIGWINCH, handle_winch);
+       /* atexit(void (*endwin)(void)); */
+       init_screen(-1);
        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();
+
        sockfd = init_connection(serv, port);
-       float interval = 1 / 30;
-       int ch;
+
+       char raw[SENDMAX + RECVMAX];
+       char * sendbuf = raw, * recvbuf = raw + SENDMAX;
+       size_t sendminlen;
+       size_t sendlen = sendminlen, recvlen = 0;
+
        time_t t;
        struct tm * tm;
+       int frame = 15.;
+       float interval = 1. / frame;
+       int32_t ct = 0;
+       int ch;
+       int ret;
+
+       sendminlen = TIMESTRMAX;
+       UPDATE_TIME();
+
+       memcpy(sendbuf + sendminlen, name, strlen(name));
+       sendminlen += strlen(name);
+       memcpy(sendbuf + sendminlen, "> ", 2);
+       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
+
+
        while (1) {
+               /* update */
+               if (ct % frame == 0) {
+                       UPDATE_TIME();
+               }
+               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);
+               }
                /* send */
                ch = getch();
-               if (ch != -1 && ch != '\n') {
-                       sendbuf[sendlen++] = ch;
-               } else if (ch == '\n') {
-                       t = time(NULL);
-                       tm = gmtime(&t);
-                       strftime(sendbuf - PREFIX_MAX, PREFIX_MAX, "<%Y/%m/%d %H:%M:%S ", tm);
-                       sendbuf[sendlen++] = '\n';
-                       send(sockfd, sendbuf - PREFIX_MAX, sendlen + PREFIX_MAX, 0);
-                       sendlen = 0;
-                       memset(sendbuf, 0, sendlen);
+               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);
                }
-               /* recv */
-               recvlen = recv(sockfd, recvbuf, recvmax, MSG_DONTWAIT);
-               /* render */
-               clear();
-               mvaddnstr(0, 0, recvbuf, recvlen);
-               mvaddnstr(g_row - 1, 0, sendbuf, sendlen);
-               refresh();
+               else if (ch == BACKSPACE) {
+                       clearline(g_y - 1);
+                       if (sendlen - 1 >= sendminlen)
+                       { --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();
        }
 }
index c7ad9b7681a649c33ee8d9a8c159024253ad2341..16c1e8c68c4defc2ae558dfde58d93671f870979 100644 (file)
@@ -73,49 +73,55 @@ def main
     end
   rescue
   end
-  socket = connect
-  begin
-    delay = 0
+  loop do
+    begin
+      socket = connect
+      delay = 0
 
-    h = { "BYE" => 1, "QUIT" => 1, "SAY" => 2, "CLEAR" => 3, "NICK" => 4, "RECONNECT" => 5, "DELAY" => 6 }
+      h = { "BYE" => 1, "QUIT" => 1, "SAY" => 2, "CLEAR" => 3, "NAME" => 4, "NICK" => 4,
+            "RC" => 5, "RECONNECT" => 5, "DELAY" => 6 }
 
-    update_prefix
-    while msg = Readline.readline(@prefix, true)
-      if not msg.empty?
-        msg.strip!
-        word = msg.split(/^([\w]*)$|^([\w]*) (.*)$/)[1..]
-        case h[word[0]]
-        when h["BYE"]
-          post(socket, "BYE")
-          exit 0
-        when h["CLEAR"]
-          puts "\e[1;1H\e[2J"
-        when h["NICK"]
-          if not word[1].empty?
-            @name = word[1]
-          end
-        when h["RECONNECT"]
-          socket.close
-          socket = connect
-        when h["DELAY"]
-          delay = word[1].to_i
-        when h["SAY"]
-          if not word.length > 1
-            word.push("")
+      update_prefix
+      while msg = Readline.readline(@prefix, true)
+        if not msg.empty?
+          msg.strip!
+          word = msg.split(/^\/([\w]*)$|^([\w]*) (.*)$/)[1..]
+          case h[word[0]]
+          when h["BYE"]
+            post(socket, "BYE")
+            exit 0
+          when h["CLEAR"]
+            puts "\e[1;1H\e[2J"
+          when h["NICK"]
+            if not word[1].empty?
+              @name = word[1]
+            end
+          when h["RC"]
+            puts "reconnecting..."
+            socket.close
+            socket = connect
+          when h["DELAY"]
+            delay = word[1].to_i
+          when h["SAY"]
+            if not word.length > 1
+              word.push("")
+            end
+            post(socket, word[1])
+          else
+            post(socket, msg)
           end
-          post(socket, word[1])
-        else
-          post(socket, msg)
         end
-      end
 
-      read_from(socket)
-      sleep delay
-      update_prefix
+        read_from(socket)
+        sleep delay
+        update_prefix
+      end
+    rescue (Errno::ECONNREFUSED Errno::EPIPE)
+      puts "\n THE HOUSE IS ON FIRE."
+    ensure
+      puts "\nSTOPPING NOW."
+      exit 1
     end
-  ensure
-    puts "\nSTOPPING NOW."
-    socket.close
   end
 end
 
diff --git a/client/moontalk.sh b/client/moontalk.sh
new file mode 100644 (file)
index 0000000..b72f0d7
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/bash
+# add this to your .bashrc
+
+# socat has a more reliable connection to the server than torify, it seems
+
+# if you want a more reliable client that isn't socat, run:
+
+# socat TCP-LISTEN:22222 SOCKS4a:localhost:7ks473deh6ggtwqsvbqdurepv5i6iblpbkx33b6cydon3ajph73sssad.onion:50000,socksport=9050 &
+# nc localhost 22222
+# ruby moontalk.rb -serv localhost -port 22222
+
+# or any other client with the server localhost and port 22222.
+
+# tail -1 moontalk.sh >> ~/.bashrc
+alias socat_moontalk="socat STDIO SOCKS4A:localhost:7ks473deh6ggtwqsvbqdurepv5i6iblpbkx33b6cydon3ajph73sssad.onion:50000,socksport=9150"