about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--Makefile17
-rwxr-xr-xadapter/protocol/cha-finger45
-rwxr-xr-xadapter/protocol/finger29
-rwxr-xr-xadapter/protocol/spartan15
-rw-r--r--adapter/tools/nc.nim50
-rw-r--r--bonus/Makefile28
-rw-r--r--doc/protocols.md14
-rw-r--r--res/urimethodmap2
8 files changed, 114 insertions, 86 deletions
diff --git a/Makefile b/Makefile
index 85dc38c5..587d0ba6 100644
--- a/Makefile
+++ b/Makefile
@@ -48,13 +48,13 @@ endif
 all: $(OUTDIR_BIN)/cha $(OUTDIR_BIN)/mancha $(OUTDIR_CGI_BIN)/http \
 	$(OUTDIR_CGI_BIN)/gemini $(OUTDIR_LIBEXEC)/gmi2html \
 	$(OUTDIR_CGI_BIN)/gopher $(OUTDIR_LIBEXEC)/gopher2html \
-	$(OUTDIR_CGI_BIN)/cha-finger $(OUTDIR_CGI_BIN)/about \
+	$(OUTDIR_CGI_BIN)/finger $(OUTDIR_CGI_BIN)/about \
 	$(OUTDIR_CGI_BIN)/file $(OUTDIR_CGI_BIN)/ftp $(OUTDIR_CGI_BIN)/sftp \
 	$(OUTDIR_LIBEXEC)/dirlist2html \
 	$(OUTDIR_CGI_BIN)/man $(OUTDIR_CGI_BIN)/spartan \
 	$(OUTDIR_CGI_BIN)/stbi $(OUTDIR_CGI_BIN)/jebp $(OUTDIR_CGI_BIN)/canvas \
 	$(OUTDIR_CGI_BIN)/sixel $(OUTDIR_CGI_BIN)/resize \
-	$(OUTDIR_LIBEXEC)/urldec $(OUTDIR_LIBEXEC)/urlenc \
+	$(OUTDIR_LIBEXEC)/urldec $(OUTDIR_LIBEXEC)/urlenc $(OUTDIR_LIBEXEC)/nc \
 	$(OUTDIR_LIBEXEC)/md2html $(OUTDIR_LIBEXEC)/ansi2html
 	ln -sf "$(OUTDIR)/$(TARGET)/bin/cha" cha
 
@@ -170,10 +170,10 @@ manpages = $(manpages1) $(manpages5)
 .PHONY: manpage
 manpage: $(manpages:%=doc/%)
 
-protocols = http about file ftp sftp gopher gemini cha-finger man spartan stbi \
+protocols = http about file ftp sftp gopher gemini finger man spartan stbi \
 	jebp sixel canvas resize
 converters = gopher2html md2html ansi2html gmi2html dirlist2html
-tools = urlenc
+tools = urlenc nc
 
 .PHONY: install
 install:
@@ -201,12 +201,15 @@ uninstall:
 	rm -f "$(DESTDIR)$(PREFIX)/bin/mancha"
 # intentionally not quoted
 	for f in $(protocols); do rm -f $(LIBEXECDIR_CHAWAN)/cgi-bin/$$f; done
-# note: png has been removed in favor of stbi.
+# notes:
+# * png has been removed in favor of stbi
+# * data has been moved back into the main binary
+# * gmifetch has been replaced by gemini
+# * cha-finger has been renamed to finger
 	rm -f $(LIBEXECDIR_CHAWAN)/cgi-bin/png
-# note: data has been moved back into the main binary.
 	rm -f $(LIBEXECDIR_CHAWAN)/cgi-bin/data
-# note: gmifetch has been replaced by gemini
 	rm -f $(LIBEXECDIR_CHAWAN)/cgi-bin/gmifetch
+	rm -f $(LIBEXECDIR_CHAWAN)/cgi-bin/cha-finger
 	rmdir $(LIBEXECDIR_CHAWAN)/cgi-bin || true
 	for f in $(converters) $(tools); do rm -f $(LIBEXECDIR_CHAWAN)/$$f; done
 # urldec is just a symlink to urlenc
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()
diff --git a/bonus/Makefile b/bonus/Makefile
index 6365e7c0..cab38f89 100644
--- a/bonus/Makefile
+++ b/bonus/Makefile
@@ -9,6 +9,19 @@ bindir = $(DESTDIR)$(prefix)/bin
 none:
 	@echo "Run make install-{file} to install a script."
 
+.PHONY: install-git.cgi
+install-git.cgi: git.cgi
+	mkdir -p $(CHA_CGI_DIR)
+	cp git.cgi $(CHA_CGI_DIR)
+	./addurimethod git git.cgi
+#TODO this will almost never work unless the user is root...
+	ln -s $(CHA_CGI_DIR)/git.cgi $(bindir)/gitcha
+
+.PHONY: install-filei.cgi
+install-filei.cgi: filei.cgi
+	mkdir -p $(CHA_CGI_DIR)
+	cp filei.cgi $(CHA_CGI_DIR)
+
 stbir2_url=https://raw.githubusercontent.com/nothings/stb/master/stb_image_resize2.h
 
 stbir2/stb_image_resize2.h:
@@ -24,30 +37,19 @@ install-stbir2: stbir2/stbir2.nim stbir2/stb_image_resize2.h stbir2/stb_image_re
 	mkdir -p $(CHA_CGI_DIR)
 	nim c -d:release -d:lto -o:$(CHA_CGI_DIR)/resize stbir2/stbir2.nim
 
-.PHONY: install-git.cgi
-install-git.cgi: git.cgi
-	mkdir -p $(CHA_CGI_DIR)
-	cp git.cgi $(CHA_CGI_DIR)
-	./addurimethod git git.cgi
-#TODO this will almost never work unless the user is root...
-	ln -s $(CHA_CGI_DIR)/git.cgi $(bindir)/gitcha
-
-.PHONY: install-filei.cgi
-install-filei.cgi: filei.cgi
-	mkdir -p $(CHA_CGI_DIR)
-	cp filei.cgi $(CHA_CGI_DIR)
-
 .PHONY: install-libfetch.c
 install-libfetch-http.c: $(CHA_CGI_DIR)/libfetch-http
 	$(CC) -Wall -O2 -g -std=c89 $< -lfetch -o $@
 	./addurimethod http libfetch-http
 	./addurimethod https libfetch-http
 
+.PHONY: install-magnet.cgi
 install-magnet.cgi: magnet.cgi
 	mkdir -p $(CHA_CGI_DIR)
 	cp magnet.cgi $(CHA_CGI_DIR)
 	./addurimethod magnet magnet.cgi
 
+.PHONY: install-trans.cgi
 install-trans.cgi: trans.cgi
 	mkdir -p $(CHA_CGI_DIR)
 	cp trans.cgi $(CHA_CGI_DIR)
diff --git a/doc/protocols.md b/doc/protocols.md
index 9fa07f06..dbf271bf 100644
--- a/doc/protocols.md
+++ b/doc/protocols.md
@@ -94,19 +94,17 @@ HTML.
 
 ## Finger
 
-Finger is supported through the `adapter/protocol/cha-finger` shell script.
-It is implemented as a shell script because of the protocol's simplicity.
-cha-finger uses the `curl` program's telnet:// protocol to make requests.
-As such, it will not work if `curl` is not installed.
+Finger is supported through the `finger` shell script. It is implemented
+as a shell script because of the protocol's simplicity.
 
-Aspiring protocol adapter writers are encouraged to study cha-finger for
-a simple example of how a custom protocol handler could be written.
+For portability, `finger` uses Chawan's `nc` tool (a very limited netcat
+clone) to make requests.
 
 ## Spartan
 
 Spartan is a protocol similar to Gemini, but without TLS. It is supported
-through the `adapter/protocol/spartan` shell script, which uses `nc` to make
-requests.
+through the `spartan` shell script, and like Finger, it uses Chawan's `nc` to
+make requests.
 
 Spartan has the very strange property of extending gemtext with a
 protocol-specific line type. This is sort of supported through a sed filter
diff --git a/res/urimethodmap b/res/urimethodmap
index 5f0a2b28..bdeb5b20 100644
--- a/res/urimethodmap
+++ b/res/urimethodmap
@@ -2,7 +2,7 @@
 
 http:			cgi-bin:http
 https:			cgi-bin:http
-finger:			cgi-bin:cha-finger
+finger:			cgi-bin:finger
 gemini:			cgi-bin:gemini
 about:			cgi-bin:about
 file:			cgi-bin:file