]> git.xolatile.top Git - public-moontalk.git/commitdiff
init
authorEmil Williams <emilwilliams@tuta.io>
Sat, 3 Feb 2024 17:27:55 +0000 (17:27 +0000)
committerEmil Williams <emilwilliams@tuta.io>
Sat, 3 Feb 2024 17:27:55 +0000 (17:27 +0000)
moontalk.c [new file with mode: 0644]
moontalk.rb [new file with mode: 0644]
moontalk.tcl [new file with mode: 0755]

diff --git a/moontalk.c b/moontalk.c
new file mode 100644 (file)
index 0000000..de3532f
--- /dev/null
@@ -0,0 +1,165 @@
+/* moontalk.c - @BAKE cc -O2 -std=gnu99 -Wall -Wextra -pedantic $@ -o $* -lncurses -ltinfo $+ @STOP */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <time.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include <ncurses.h>
+
+#define SERV "7ks473deh6ggtwqsvbqdurepv5i6iblpbkx33b6cydon3ajph73sssad.onion"
+#define PORT "50000"
+
+#define streq(a,b) (!strcmp(a,b))
+
+int g_row, g_col;
+
+void free_screen(void) {
+       endwin();
+}
+
+void init_screen(void) {
+       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);
+}
+
+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 */
+int init_connection(char * serv, char * port) {
+       int status, sockfd;
+       struct addrinfo hints, * res;
+
+       memset(&hints, 0, sizeof(struct addrinfo));
+       hints.ai_family = AF_UNSPEC;     // don't care IPv4 or IPv6
+       hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
+
+       if ((status = getaddrinfo(serv, port, &hints, &res)) != 0) {
+               fprintf(stderr, "init_connection: %s\n", gai_strerror(status));
+               exit(1);
+       }
+
+       if ((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1)
+       { goto error; }
+       if (connect(sockfd, res->ai_addr, res->ai_addrlen))
+       { goto error; }
+
+       freeaddrinfo(res);
+
+       g_sockfd = sockfd;
+       return sockfd;
+error:
+       perror("init_connection");
+       exit(1);
+       __builtin_unreachable();
+}
+
+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;
+
+       int sockfd;
+
+       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")) {
+                       printf("serv: %s\n", *argv);
+                       serv = *argv;
+               }
+               else if (streq(*(argv-1), "-port")) {
+                       printf("port: %s\n", *argv);
+               }
+               else if (streq(*(argv-1), "-name")) {
+                       printf("name: %s\n", *argv);
+               }
+       }
+
+       atexit(free_screen);
+       init_screen();
+       signal(SIGWINCH, handle_winch);
+       printw("Connecting to %s:%s as %s\n", serv, port, name);
+       refresh();
+       sockfd = init_connection(serv, port);
+       float interval = 1 / 30;
+       int ch;
+       time_t t;
+       struct tm * tm;
+       while (1) {
+               /* 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);
+               }
+               /* recv */
+               recvlen = recv(sockfd, recvbuf, recvmax, MSG_DONTWAIT);
+               /* render */
+               clear();
+               mvaddnstr(0, 0, recvbuf, recvlen);
+               mvaddnstr(g_row - 1, 0, sendbuf, sendlen);
+               refresh();
+               /* sleep */
+               sleep(interval);
+       }
+}
diff --git a/moontalk.rb b/moontalk.rb
new file mode 100644 (file)
index 0000000..4696af4
--- /dev/null
@@ -0,0 +1,118 @@
+#!/usr/bin/ruby
+# written by emil
+#
+# short guide
+#
+# -serv specifies server,
+# -port specifies port,
+# -name specifies your display name,
+#
+# Type "BYE" to stop it after it connects to the moon.
+# Type Enter and nothing else to refresh the messages.
+# Type messages and send them, hopefully everyone hears you just fine.
+#
+# h = { "BYE" => 1, "QUIT" => 1, "SAY" => 2, "CLEAR" => 3, "NICK" => 4, "RECONNECT" => 5, "DELAY" => 6 }
+# 1 exits,
+# 2 says something verbatim (including a raw newline),
+# 3 clears the terminal,
+# 4 sets the nick (needs arg),
+# 5 reconnects,
+# 6 sets delays ( needs arg)
+
+require 'socket'
+require 'readline'
+
+@serv = '7ks473deh6ggtwqsvbqdurepv5i6iblpbkx33b6cydon3ajph73sssad.onion'
+@port = 50000
+
+@name = "anonymous"
+
+def read_from(socket)
+  begin # probably too large of a read size...
+    puts socket.read_nonblock(2 << 16)
+  rescue
+  end
+end
+
+def post(socket, msg)
+  update_prefix
+  socket.puts(@prefix + msg)
+end
+
+def update_prefix
+  date = Time.now.utc.strftime("%Y/%m/%d %k:%M:%S")
+  @prefix = "<#{date} #{@name}> "
+end
+
+def connect
+  puts "Connecting to " + @serv + ":" + @port.to_s + " as " + @name
+  socket = TCPSocket.new(@serv, @port)
+  if not socket
+    puts "Failed to connect."
+    exit 1
+  end
+  return socket
+end
+
+def main
+  begin
+    ARGV.each_with_index do |element,index|
+      if element == "-name"
+        @name = ARGV[index + 1]
+      end
+      if element == "-serv"
+        @serv = ARGV[index + 1]
+      end
+      if element == "-port"
+        @port = ARGV[index + 1].to_i
+      end
+    end
+  rescue
+  end
+  socket = connect
+  begin
+    delay = 0
+
+    h = { "BYE" => 1, "QUIT" => 1, "SAY" => 2, "CLEAR" => 3, "NICK" => 4, "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("")
+          end
+          post(socket, word[1])
+        else
+          post(socket, msg)
+        end
+      end
+
+      read_from(socket)
+      sleep delay
+      update_prefix
+    end
+  ensure
+    puts "\nSTOPPING NOW."
+    socket.close
+  end
+end
+
+main
diff --git a/moontalk.tcl b/moontalk.tcl
new file mode 100755 (executable)
index 0000000..0d680a4
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/tclsh
+package require Tk
+
+set ::name anonymous
+set ::usernu x
+
+set ::host 7ks473deh6ggtwqsvbqdurepv5i6iblpbkx33b6cydon3ajph73sssad.onion
+
+pack [text .msgs] -fill both -expand 1
+pack [entry .entry] -fill x
+
+proc add_msg { msg } {
+    .msgs insert end "$msg\n"
+    .msgs yview end
+}
+
+proc get_msg {} {
+    set curdate [clock format [clock seconds] -format "%Y/%m/%d %T"]
+    return "<$curdate $::name:$::usernu> [.entry get]"
+}
+
+bind .entry <Return> {
+    set msg [get_msg]
+    puts $::fd $msg
+    flush $::fd
+    add_msg $msg
+    .entry delete 0 end
+}
+
+fileevent [set fd [socket $::host 50000]] readable {
+    add_msg [gets $::fd]
+}
+
+chan configure $::fd -translation binary