From 90f617dcf0381ded783e7e0d3e77576b19fb0024 Mon Sep 17 00:00:00 2001 From: Emil Williams Date: Sat, 3 Feb 2024 17:27:55 +0000 Subject: [PATCH] init --- moontalk.c | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ moontalk.rb | 118 ++++++++++++++++++++++++++++++++++++++++++ moontalk.tcl | 34 ++++++++++++ 3 files changed, 317 insertions(+) create mode 100644 moontalk.c create mode 100644 moontalk.rb create mode 100755 moontalk.tcl diff --git a/moontalk.c b/moontalk.c new file mode 100644 index 0000000..de3532f --- /dev/null +++ b/moontalk.c @@ -0,0 +1,165 @@ +/* moontalk.c - @BAKE cc -O2 -std=gnu99 -Wall -Wextra -pedantic $@ -o $* -lncurses -ltinfo $+ @STOP */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#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 index 0000000..4696af4 --- /dev/null +++ b/moontalk.rb @@ -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 index 0000000..0d680a4 --- /dev/null +++ b/moontalk.tcl @@ -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 { + 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