From: Malte Bublitz Date: Wed, 12 Nov 2025 12:34:14 +0000 (+0100) Subject: ✨ Implemented a pure Python QOTD server X-Git-Url: https://git.rt3x.de/?a=commitdiff_plain;h=816d0b24309e38986f87154d18283021c14ed67b;p=bbs.git ✨ Implemented a pure Python QOTD server Tje previous QOTD server was a shell script executed by inetd, calling fortune and doing some shitty UTF-8 to ASCII convertion which did not support special characters like dashes. The new server in the module `bbs.qotd` is based on Python's `socketserver.TCPServer` and supports UTF-8 as expected nowadays. The quotes are still those found in fortunes-mod databases, but we now read them directly from the data files in `bbs.fortune`. --- diff --git a/bbs/fortune.py b/bbs/fortune.py new file mode 100644 index 0000000..ca4d5bc --- /dev/null +++ b/bbs/fortune.py @@ -0,0 +1,65 @@ +"""Parse fortune database files and get fortunes. + +Open and parse fortunes-mod database files into a +cache and get random fortunes from that cache. + +Example: + for db in ["de/unfug", "de/computer"]: + bbs.fortune.load_database(db) + print(bbs.fortune.get()) +""" + +import os +import re +import random + + +# All fortunes read from databases using `load_database()`. +fortunes = [] + + +def load_database(db: str, db_location: str = "/usr/share/games/fortunes"): + """Parse a fortunes-mod database and add the fortunes to a cache. + + Read all fortunes from a database file and store them in the global + variable *fortunes*. + + Args: + db: The database name, like "bofh-excuses" or "de/computer" + db_location: The direcory where your fortunes databases are stored. + Defaults to /usr/share/games/fortunes, which is used on Debian. + """ + global fortunes + + dbfile = os.path.join(db_location, db) + f = open(dbfile, "r") + db_fortunes = re.split(r'\r?\n%\r?\n', f.read()) + f.close() + + fortunes += db_fortunes + + # # @see https://codeberg.org/jamesansley/fortune + # text = [fortune for fortune in text if fortune.strip("\n\r")] + # fortunes += text + + +def get(): + global fortunes + if len(fortunes) < 1: + load_database() + + return random.choice(fortunes) + + +def main(): + if len(sys.argv) > 1: + for arg in sys.argv[1:]: + if arg[0] != "-": + load_database(arg) + + print(get()) + + +if __name__ == "__main__": + main() + diff --git a/bbs/qotd.py b/bbs/qotd.py new file mode 100644 index 0000000..260d556 --- /dev/null +++ b/bbs/qotd.py @@ -0,0 +1,51 @@ +"""QOTD server using socketserver. + +TODO +""" + + +import sys +import os +import socketserver +import bbs.fortune + + +class QOTDHandler(socketserver.StreamRequestHandler): + def handle(self): + quote = bbs.fortune.get() + self.wfile.write(quote.encode("utf-8") + b"\n") + + +def main(fortune_databases: list = ["bofh-excuses", "de/unfug", "de/computer"]): + try: + PORT = int(os.getenv("QOTD_PORT", 17)) + except ValueError: + print("Environment variable QOTD_PORT is not a valid integer. Falling back to port 17.", file=sys.stderr) + PORT = 17 + + for db in fortune_databases: + bbs.fortune.load_database(db) + + listen_on = ("", PORT) + + try: + server = socketserver.TCPServer( + listen_on, + QOTDHandler + ) + except OSError: + print("Failed to bind to TCP socket " + str(listen_on), file=sys.stderr) + sys.exit(2) + + try: + server.serve_forever() + + except KeyboardInterrupt: + print("\nCtr+C pressed.\nStopping...") + server.shutdown() + server.server_close() + + +if __name__=='__main__': + main() + diff --git a/bin/qotd b/bin/qotd deleted file mode 100755 index 140aaef..0000000 --- a/bin/qotd +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash -# -# See also: -# RFC 865 - Quote of the Day Protocol -# - -PATH=/usr/games:$PATH - -fortune \ - letzteworte \ - ms \ - murphy \ - namen \ - quiz \ - regeln \ - sicherheitshinweise \ - sprueche \ - stilblueten \ - tips \ - translations \ - unfug \ - vornamen \ - witze \ - woerterbuch \ - wusstensie \ - zitate \ - | sed \ - -e's/Ä/Ae/g' \ - -e's/Ö/Oe/g' \ - -e's/Ü/Ue/g' \ - -e's/ä/ae/g' \ - -e's/ö/oe/g' \ - -e's/ü/ue/g' \ - -e's/ß/ss/g' \ - | iconv -f UTF-8 -t US-ASCII - -# | uni2ascii \ -# -c -d -e -f -x \ -# -S U+00E4:ae \ -# -S U+00C4:Ae \ -# -S U+00F6:oe \ -# -S U+00D6:Oe \ -# -S U+00FC:ue \ -# -S U+00DC:Ue \ -# -S U+00DF:ss \ -# -q -