erysdren's WWW site

software, gameware, strangeware

RSS Feed

Finger Protocol in Python 3
2024-09-12

As I detailed in my other post, the Finger protocol is extremely simple and easy to implement. But I didn't show any details on how to actually implement it! A while back I wrote this test server/client pair in Python 3, so I will print the code here for posterity.

The following code snippets are licensed as CC0/Public Domain, and I claim no ownership or responsibility thereof.

finger_client.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import socket, sys

def print_help():
	print("python3 finger_client.py username@hostname")
	sys.exit(0)

if __name__ == "__main__":

	if len(sys.argv) != 2:
		print_help()

	args = sys.argv[1].split("@")
	if not args or len(args) != 2:
		print_help()

	username = args[0]
	hostname = args[1]

	try:
		s = socket.create_connection((hostname, 79), 5)
	except OSError as msg:
		print(msg, file=sys.stderr)
		sys.exit(1)

	s.sendall(f"{username}\r\n".encode("ascii"))
	plan = s.recv(8192)
	print(f"[{hostname}]")
	print(plan.decode("ascii"), end="")

	s.shutdown(socket.SHUT_RDWR)
	s.close()

finger_server.py

Some notes:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import socket, sys

PORT=79
TIMEOUT=15
MAX_CONNECTS=10

def get_plan(username, verbose):
	return f"username={username} verbose={verbose}"

if __name__ == "__main__":

	try:
		addr = ("", PORT)
		if socket.has_dualstack_ipv6():
			s = socket.create_server(addr, family=socket.AF_INET6, dualstack_ipv6=True)
		else:
			s = socket.create_server(addr, backlog=MAX_CONNECTS)
	except OSError as msg:
		print(msg, file=sys.stderr)
		sys.exit(1)

	print(f"Now listening on port: {PORT}\nConnection timeout: {TIMEOUT} seconds\nMax simultaneous connections: {MAX_CONNECTS}")

	while True:
		try:
			conn, addr = s.accept()
			with conn:
				conn.settimeout(TIMEOUT)
				print(f"Connected by: {addr[0]}:{addr[1]}")
				while True:
					command = conn.recv(128)
					if not command: break
					print(f"Finger command: {repr(command)}")
					cmd = command.decode("ascii").strip()
					if cmd[:3].casefold() == "/W ".casefold():
						username = cmd[3:]
						verbose = True
					else:
						username = cmd
						verbose = False
					plan = get_plan(username, verbose)
					conn.sendall(f"{plan}\n\n".encode("ascii"))
					conn.shutdown(socket.SHUT_RDWR)
					conn.close()
					break
		except KeyboardInterrupt:
			print("Shutting down")
			break

	s.shutdown(socket.SHUT_RDWR)
	s.close()