M README.md => README.md +34 -0
@@ 26,6 26,11 @@ the connection is done entirely over $sok, so set that to whatever.
if you want to include e.g. tcltls, go ahead. the config file is saved
to/read from ~/.config/ntalk/cscript.tcl.
+there is a `connect` proc available to the config, that automatically sets up the socket
+with the right encoding and line endings. it is called the same as `socket`. it is
+provided to make interacting with nanobnc.py easier. its use is not mandatory, ntalk will
+ensure the socket is setup right later.
+
right click on any sixel in the chatlog, and you can save it under a custom name.
saved sixels can be accessed through the "sixels" option in the top menu.
slashes are interpreted, so naming one e.g. "faces / :D" will create a submenu called "faces".
@@ 61,6 66,35 @@ consists of the following scripts:
- `9talk/motd addr`: checks for the most recent MOTD of $addr, and echos it. the most recent MOTD and last-seen message id are stored in $home/lib/9talk/$addr.motd and $home/lib/9talk/$addr.id, respectively.
+## `nanobnc.py`: simple nanochat bouncer
+
+this script should be run behind a connection broker, like socat. it assumes a client is
+attached to stdio. run it like:
+
+```
+socat TCP-LISTEN:22344,fork EXEC:'python nanobnc.py <password> [timeout]'
+```
+
+timeout is in seconds. it defaults to 1800, 30 minutes.
+
+when a client connects, it should send a line of the form `<addr> <port> <password>`. if
+the password matches the one passed as an argument, the script will connect to the
+upstream nanochat server at addr:port. data is blindly copied between the client and the
+upstream, until either the client and server are idle for timeout seconds, or until the
+client sends QUIT, at which point the script gracefully disconnects from the upstream
+server, and exits
+
+to use this with ntalk, replace the `set sok ...` line in your config with the following:
+
+```
+set sok [connect <bnc addr> <bnc port>]
+puts $sok "<upstream addr> <upstream port> <password>"
+```
+
+as this script is essentially an open TCP proxy, be very careful with your choice of
+password, and with who you allow to access the server.
+
+
## `scrollbackup.sh`: simple backup script
just sends HIST and QUIT and logs it to a file whose name indicates
A nanobnc.py => nanobnc.py +104 -0
@@ 0,0 1,104 @@
+#!/usr/bin/env python
+
+import socket
+import threading
+from sys import exit, argv, stderr, stdout, stdin
+from signal import alarm, signal, SIGALRM
+
+argv0 = 'nanobnc.py'
+sok = None
+
+def usage():
+ print(f'usage: {argv0} passphrase [timeout]')
+ exit(1)
+
+def handle_args():
+ global argv0, argv
+ if len(argv) > 0:
+ argv0 = argv[0]
+ argv = argv[1:]
+ if len(argv) not in (1, 2):
+ usage()
+
+ passphrase = argv[0]
+ if len(argv) == 1:
+ timeout = 1800
+ else:
+ timeout = int(argv[1])
+
+ return passphrase, timeout
+
+def handle_req(passphrase):
+ req = input().split(maxsplit=2)
+ if len(req) != 3:
+ print('bad # of connection args')
+ exit(3)
+ host, port, pw = req
+
+ if pw != passphrase:
+ print('bad passphrase')
+ print(f'bad passphrase trying to connect to {host}:{port}', file=stderr)
+ exit(4)
+
+ try:
+ port = int(port)
+ except:
+ print('bad port')
+ exit(3)
+
+ return host, port
+
+def shutdown():
+ if sok is not None:
+ try:
+ sok.sendall(b'QUIT\n')
+ sok.shutdown(socket.SHUT_RDWR)
+ except:
+ pass
+
+def onalarm(sig, stk):
+ try:
+ print('timeout!')
+ stdout.flush()
+ except:
+ pass
+ try:
+ print('timeout!', file=stderr)
+ stderr.flush()
+ except:
+ pass
+
+ shutdown()
+ exit(2)
+
+signal(SIGALRM, onalarm)
+
+passphrase, timeout = handle_args()
+alarm(timeout)
+host, port = handle_req(passphrase)
+
+try:
+ sok = socket.create_connection((host, port))
+except Exception as e:
+ print(f'connection failed: {e}')
+ exit(5)
+
+def toserver():
+ while (s := stdin.readline()) != '':
+ if s == 'QUIT\n':
+ break
+ sok.sendall(s.encode())
+ shutdown()
+ exit(0)
+
+def toclient():
+ fp = sok.makefile('r', encoding='ascii', errors='ignore')
+ while (s := fp.readline()) != '':
+ stdout.write(s)
+ stdout.flush()
+ shutdown()
+ exit(0)
+
+t = threading.Thread(target=toclient)
+t.start()
+toserver()
M ntalk.tcl => ntalk.tcl +7 -1
@@ 502,6 502,12 @@ bind .buffer <Button-3> {
### SERVER MANAGEMENT ###
+proc connect {addr port} {
+ set sok [socket $addr $port]
+ fconfigure $sok -translation lf -blocking false -encoding iso8859-1
+ return $sok
+}
+
proc gencscript {{server localhost} {port 44322}} {
set server [list $server]
set port [list $port]
@@ 516,7 522,7 @@ proc gencscript {{server localhost} {port 44322}} {
set server $server
set port $port
}]
- append ret {set sok [socket $server $port]}
+ append ret {set sok [connect $server $port]}
return [string trim $ret]
}