about summary refs log tree commit diff stats
path: root/adapter
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-10-12 17:14:01 +0200
committerbptato <nincsnevem662@gmail.com>2024-10-12 17:19:44 +0200
commitc4a75720959a968004fec1996d6870d0874c953d (patch)
tree428407444b6aa0199060629047f5393f3b590218 /adapter
parent828716e78b5b1a9fea93c2839d89e189c1fcb252 (diff)
downloadchawan-c4a75720959a968004fec1996d6870d0874c953d.tar.gz
Add `nc' tool & adjust finger/spartan to use it
Simple netcat clone, useful for portable scripts. Especially because
some netcats will close the connection as soon as I close stdin... this
one only quits when either stdout or the socket refuses new data.

Also, it uses our standard TCP connection routine, meaning it respects
ALL_PROXY. (i.e. now spartan works with socks5 too)
Diffstat (limited to 'adapter')
-rwxr-xr-xadapter/protocol/cha-finger45
-rwxr-xr-xadapter/protocol/finger29
-rwxr-xr-xadapter/protocol/spartan15
-rw-r--r--adapter/tools/nc.nim50
4 files changed, 82 insertions, 57 deletions
diff --git a/adapter/protocol/cha-finger b/adapter/protocol/cha-finger
deleted file mode 100755
index 42472e21..00000000
--- a/adapter/protocol/cha-finger
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/bin/sh
-# Finger protocol adapter for Chawan. Requires curl.
-# (It does *not* work without the environment variables MAPPED_URI_*, so no
-# w3m support.)
-#
-# Usage: put this script in your cgi-bin folder, then add the following line to
-# your urimethodmap:
-#
-# finger: /cgi-bin/cha-finger
-#
-# Note: the Chawan default configuration already does this, so normally you
-# don't need to do anything to use the finger protocol.
-
-# Check for errors.
-die() {
-	echo "Cha-Control: ConnectionError $1 $2"
-	exit 1
-}
-
-type curl >/dev/null || \
-	die 1 "curl must be installed on your computer to use finger"
-
-PORT="${MAPPED_URI_PORT:-79}"
-test "$PORT" = 79 || die 3 "invalid port; only port 79 is supported"
-
-# Parse the URL. Roughly based on Lynx finger URL parsing, but less
-# sophisticated.
-if test -n "$MAPPED_URI_USERNAME"
-then	USER="$MAPPED_URI_USERNAME"
-else	case "$MAPPED_URI_PATH" in
-	/w*) USER="/w ${MAPPED_URI_PATH#/w}" ;;
-	*) USER="${MAPPED_URI_PATH#/}" ;;
-	esac
-fi
-URL="telnet://$MAPPED_URI_HOST:$PORT"
-
-# Headers.
-printf 'Content-Type: text/plain\n'
-# Newline; from here on we are sending the content body.
-printf '\n'
-# Finger request, the output of which goes to stdout.
-printf '%s\r\n' "$USER" | if test -n "$ALL_PROXY"
-then	curl -x "$ALL_PROXY" -- "$URL"
-else	curl -- "$URL"
-fi 2>/dev/null
diff --git a/adapter/protocol/finger b/adapter/protocol/finger
new file mode 100755
index 00000000..4404c8a6
--- /dev/null
+++ b/adapter/protocol/finger
@@ -0,0 +1,29 @@
+#!/bin/sh
+# Finger protocol adapter for Chawan.
+
+die() {
+	echo "Cha-Control: ConnectionError $1 $2"
+	exit 1
+}
+
+PORT=${MAPPED_URI_PORT:-79}
+test "$PORT" = 79 || die InvalidURL "wrong port, only port 79 is supported"
+
+# Parse the URL. Roughly based on Lynx finger URL parsing, but less
+# sophisticated.
+USER=$MAPPED_URI_USERNAME
+if test -z "$USER"
+then	case "$MAPPED_URI_PATH" in
+	/w/*)	USER="/w ${MAPPED_URI_PATH#/w/}" ;;
+	*)	USER=${MAPPED_URI_PATH#/} ;;
+	esac
+fi
+
+# Headers.
+printf 'Content-Type: text/plain\n'
+
+# Newline; from here on we are sending the content body.
+printf '\n'
+
+# Finger request, the output of which goes to stdout.
+printf '%s\r\n' "$USER" | "$CHA_LIBEXEC_DIR"/nc "$MAPPED_URI_HOST" "$PORT"
diff --git a/adapter/protocol/spartan b/adapter/protocol/spartan
index ac0f590e..2f232fb1 100755
--- a/adapter/protocol/spartan
+++ b/adapter/protocol/spartan
@@ -1,22 +1,13 @@
 #!/bin/sh
 # Adapter for the spartan protocol. See: spartan://mozz.us
-# Requires netcat (nc).
-#
-# Usage: add the following line to your urimethodmap:
-#
-# spartan: /cgi-bin/spartan.cgi
 
-if ! type nc >/dev/null 2>/dev/null
-then	printf 'Cha-Control: ConnectionError 1 nc not found\n'
-	exit 1
-fi
 MAPPED_URI_PORT=${MAPPED_URI_PORT:=300} # default port is 300
 MAPPED_URI_PATH=${MAPPED_URI_PATH:=/} # needs / for root
 if test "$REQUEST_METHOD" != POST && test "$MAPPED_URI_QUERY" = "input"
 then	printf "Content-Type: text/html
 
 <!DOCTYPE html>
-<form method=POST action=\"$MAPPED_URI_PATH\">
+<form method=POST action='\"$MAPPED_URI_PATH\"'>
 Input text to upload:
 <p>
 <textarea name=q></textarea>
@@ -30,7 +21,7 @@ CONTENT_LENGTH=${CONTENT_LENGTH:=0} # if missing, set to 0
 {
 	printf '%s %d\n' "$MAPPED_URI_HOST $MAPPED_URI_PATH" "$CONTENT_LENGTH"
 	tail -c+3 # skip q=
-} | nc "$MAPPED_URI_HOST" "$MAPPED_URI_PORT" 2>/dev/null | {
+} | "$CHA_LIBEXEC_DIR"/nc "$MAPPED_URI_HOST" "$MAPPED_URI_PORT" | {
 	IFS= read -r line
 	case $line in
 	'2 '*)	ctype=${line#2 }
@@ -42,6 +33,6 @@ CONTENT_LENGTH=${CONTENT_LENGTH:=0} # if missing, set to 0
 	'3 '*)	printf "Status: 301\nLocation: %s\n" "${line#3 }" ;;
 	'4 '*)	printf "Status: 403\n\n%s" "${line#4 }" ;;
 	'5 '*)	printf "Status: 500\n\n%s" "${line#5 }" ;;
-	*)	printf "Cha-Control: ConnectionError 1 malformed response\n"
+	*)	printf "Cha-Control: ConnectionError InvalidResponse\n"
 	esac
 }
diff --git a/adapter/tools/nc.nim b/adapter/tools/nc.nim
new file mode 100644
index 00000000..c9e3735b
--- /dev/null
+++ b/adapter/tools/nc.nim
@@ -0,0 +1,50 @@
+# Minimal, TCP-only nc clone. Intended for use in shell scripts in
+# simple protocols (e.g. finger, spartan).
+#
+# This program respects ALL_PROXY (if set).
+import std/os
+import std/posix
+
+import ../protocol/lcgi
+import io/poll
+
+proc usage() {.noreturn.} =
+  stderr.write("Usage: " & paramStr(0) & " [host] [port]\n")
+  quit(1)
+
+proc main() =
+  if paramCount() != 2:
+    usage()
+  let os = newPosixStream(STDOUT_FILENO)
+  let ips = newPosixStream(STDIN_FILENO)
+  let ps = os.connectSocket(paramStr(1), paramStr(2))
+  var pollData = PollData()
+  pollData.register(STDIN_FILENO, POLLIN)
+  pollData.register(ps.fd, POLLIN)
+  var buf {.noinit.}: array[4096, uint8]
+  var i = 0 # unregister counter
+  while i < 2:
+    pollData.poll(-1)
+    for event in pollData.events:
+      assert (event.revents and POLLOUT) == 0
+      if (event.revents and POLLIN) != 0:
+        if event.fd == STDIN_FILENO:
+          let n = ips.recvData(buf)
+          if n == 0:
+            pollData.unregister(ips.fd)
+            inc i
+            continue
+          ps.sendDataLoop(buf.toOpenArray(0, n - 1))
+        else:
+          assert event.fd == ps.fd
+          let n = ps.recvData(buf)
+          if n == 0:
+            pollData.unregister(ips.fd)
+            inc i
+            continue
+          os.sendDataLoop(buf.toOpenArray(0, n - 1))
+      if (event.revents and POLLERR) != 0 or (event.revents and POLLHUP) != 0:
+        pollData.unregister(event.fd)
+        inc i
+
+main()