From: Malte Bublitz Date: Tue, 2 May 2023 12:54:51 +0000 (+0200) Subject: Current state on mcp at 2023-05-02 X-Git-Url: https://git.rt3x.de/?a=commitdiff_plain;h=refs%2Fheads%2Fmcp;p=bbs.git Current state on mcp at 2023-05-02 Just like the branch torchwood, created with commit c80b15a24ac02d864f0c6e794b903bdbef1a27f3, this is the whole current working directory on my Mac. --- diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..cee3f9c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +# EditorConfig is awesome: https://EditorConfig.org + +root = true + +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_style = tab +indent_size = 4 + diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..9b8fcdb --- /dev/null +++ b/.flake8 @@ -0,0 +1,9 @@ +[flake8] +# W191 indentation contains tabs +# E221 multiple spaces before operator +ignore = W191, E221, Q000 +exclude = .git, venv, malte70_flask +max-line-length = 120 +per-file-ignores = + wsgi.py: F401, E402 + malte70_flask/db.py: PLC0103, PLW0613 diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..50eb216 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,619 @@ +[MAIN] + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Load and enable all available extensions. Use --list-extensions to see a list +# all available extensions. +#enable-all-extensions= + +# In error mode, messages with a category besides ERROR or FATAL are +# suppressed, and no reports are done by default. Error mode is compatible with +# disabling specific errors. +#errors-only= + +# Always return a 0 (non-error) status code, even if lint errors are found. +# This is primarily useful in continuous integration scripts. +#exit-zero= + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. +extension-pkg-allow-list= + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. (This is an alternative name to extension-pkg-allow-list +# for backward compatibility.) +extension-pkg-whitelist= + +# Return non-zero exit code if any of these messages/categories are detected, +# even if score is above --fail-under value. Syntax same as enable. Messages +# specified are enabled, while categories only check already-enabled messages. +fail-on= + +# Specify a score threshold under which the program will exit with error. +fail-under=10 + +# Interpret the stdin as a python script, whose filename needs to be passed as +# the module_or_package argument. +#from-stdin= + +# Files or directories to be skipped. They should be base names, not paths. +ignore=CVS,.git + +# Add files or directories matching the regular expressions patterns to the +# ignore-list. The regex matches against paths and can be in Posix or Windows +# format. Because '\' represents the directory delimiter on Windows systems, it +# can't be used as an escape character. +ignore-paths= + +# Files or directories matching the regular expression patterns are skipped. +# The regex matches against base names, not paths. The default value ignores +# Emacs file locks +ignore-patterns=^\.# + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis). It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the +# number of processors available to use, and will cap the count on Windows to +# avoid hangs. +jobs=1 + +# Control the amount of potential inferred values when inferring a single +# object. This can help the performance when dealing with large functions or +# complex, nested conditions. +limit-inference-results=100 + +# List of plugins (as comma separated values of python module names) to load, +# usually to register additional checkers. +load-plugins= + +# Pickle collected data for later comparisons. +persistent=yes + +# Minimum Python version to use for version dependent checks. Will default to +# the version used to run pylint. +py-version=3.8 + +# Discover python modules and packages in the file system subtree. +recursive=no + +# When enabled, pylint would attempt to guess common misconfiguration and emit +# user-friendly hints instead of false-positive error messages. +suggestion-mode=yes + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + +# In verbose mode, extra non-checker-related info will be displayed. +#verbose= + + +[REPORTS] + +# Python expression which should return a score less than or equal to 10. You +# have access to the variables 'fatal', 'error', 'warning', 'refactor', +# 'convention', and 'info' which contain the number of messages in each +# category, as well as 'statement' which is the total number of statements +# analyzed. This score is used by the global evaluation report (RP0004). +evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details. +msg-template= + +# Set the output format. Available formats are text, parseable, colorized, json +# and msvs (visual studio). You can also give a reporter class, e.g. +# mypackage.mymodule.MyReporterClass. +#output-format= + +# Tells whether to display a full report or only the messages. +reports=no + +# Activate the evaluation score. +score=yes + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE, +# UNDEFINED. +confidence=HIGH, + CONTROL_FLOW, + INFERENCE, + INFERENCE_FAILURE, + UNDEFINED + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once). You can also use "--disable=all" to +# disable everything first and then re-enable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use "--disable=all --enable=classes +# --disable=W". +disable=raw-checker-failed, + bad-inline-option, + locally-disabled, + file-ignored, + suppressed-message, + useless-suppression, + deprecated-pragma, + use-symbolic-message-instead, + missing-module-docstring + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +enable=c-extension-no-member + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when caught. +overgeneral-exceptions=BaseException, + Exception + + +[CLASSES] + +# Warn about protected attribute access inside special methods +check-protected-access-in-special-methods=no + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__, + __new__, + setUp, + __post_init__ + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict, + _fields, + _replace, + _source, + _make + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=cls + + +[STRING] + +# This flag controls whether inconsistent-quotes generates a warning when the +# character used as a quote delimiter is used inconsistently within a module. +check-quote-consistency=no + +# This flag controls whether the implicit-str-concat should generate a warning +# on implicit string concatenation in sequences defined over several lines. +check-str-concat-over-line-jumps=no + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME, + XXX, + TODO + +# Regular expression of note tags to take in consideration. +notes-rgx= + + +[SPELLING] + +# Limits count of emitted suggestions for spelling mistakes. +max-spelling-suggestions=4 + +# Spelling dictionary name. Available dictionaries: none. To make it work, +# install the 'python-enchant' package. +spelling-dict= + +# List of comma separated words that should be considered directives if they +# appear at the beginning of a comment and should not be checked. +spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy: + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains the private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to the private dictionary (see the +# --spelling-private-dict-file option) instead of raising a message. +spelling-store-unknown-words=no + + +[BASIC] + +# Naming style matching correct argument names. +argument-naming-style=snake_case + +# Regular expression matching correct argument names. Overrides argument- +# naming-style. If left empty, argument names will be checked with the set +# naming style. +#argument-rgx= + +# Naming style matching correct attribute names. +attr-naming-style=snake_case + +# Regular expression matching correct attribute names. Overrides attr-naming- +# style. If left empty, attribute names will be checked with the set naming +# style. +#attr-rgx= + +# Bad variable names which should always be refused, separated by a comma. +bad-names=foo, + bar, + baz, + toto, + tutu, + tata + +# Bad variable names regexes, separated by a comma. If names match any regex, +# they will always be refused +bad-names-rgxs= + +# Naming style matching correct class attribute names. +class-attribute-naming-style=any + +# Regular expression matching correct class attribute names. Overrides class- +# attribute-naming-style. If left empty, class attribute names will be checked +# with the set naming style. +#class-attribute-rgx= + +# Naming style matching correct class constant names. +class-const-naming-style=UPPER_CASE + +# Regular expression matching correct class constant names. Overrides class- +# const-naming-style. If left empty, class constant names will be checked with +# the set naming style. +#class-const-rgx= + +# Naming style matching correct class names. +class-naming-style=PascalCase + +# Regular expression matching correct class names. Overrides class-naming- +# style. If left empty, class names will be checked with the set naming style. +#class-rgx= + +# Naming style matching correct constant names. +const-naming-style=UPPER_CASE + +# Regular expression matching correct constant names. Overrides const-naming- +# style. If left empty, constant names will be checked with the set naming +# style. +#const-rgx= + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + +# Naming style matching correct function names. +function-naming-style=snake_case + +# Regular expression matching correct function names. Overrides function- +# naming-style. If left empty, function names will be checked with the set +# naming style. +#function-rgx= + +# Good variable names which should always be accepted, separated by a comma. +good-names=i, + j, + k, + ex, + Run, + _ + +# Good variable names regexes, separated by a comma. If names match any regex, +# they will always be accepted +good-names-rgxs= + +# Include a hint for the correct naming format with invalid-name. +include-naming-hint=no + +# Naming style matching correct inline iteration names. +inlinevar-naming-style=any + +# Regular expression matching correct inline iteration names. Overrides +# inlinevar-naming-style. If left empty, inline iteration names will be checked +# with the set naming style. +#inlinevar-rgx= + +# Naming style matching correct method names. +method-naming-style=snake_case + +# Regular expression matching correct method names. Overrides method-naming- +# style. If left empty, method names will be checked with the set naming style. +#method-rgx= + +# Naming style matching correct module names. +module-naming-style=snake_case + +# Regular expression matching correct module names. Overrides module-naming- +# style. If left empty, module names will be checked with the set naming style. +#module-rgx= + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +# These decorators are taken in consideration only for invalid-name. +property-classes=abc.abstractproperty + +# Regular expression matching correct type variable names. If left empty, type +# variable names will be checked with the set naming style. +#typevar-rgx= + +# Naming style matching correct variable names. +variable-naming-style=snake_case + +# Regular expression matching correct variable names. Overrides variable- +# naming-style. If left empty, variable names will be checked with the set +# naming style. +#variable-rgx= + + +[METHOD_ARGS] + +# List of qualified names (i.e., library.method) which require a timeout +# parameter e.g. 'requests.api.get,requests.api.post' +timeout-methods=requests.api.delete,requests.api.get,requests.api.head,requests.api.options,requests.api.patch,requests.api.post,requests.api.put,requests.api.request + + +[DESIGN] + +# List of regular expressions of class ancestor names to ignore when counting +# public methods (see R0903) +exclude-too-few-public-methods= + +# List of qualified class names to ignore when counting class parents (see +# R0901) +ignored-parents= + +# Maximum number of arguments for function / method. +max-args=5 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Maximum number of boolean expressions in an if statement (see R0916). +max-bool-expr=5 + +# Maximum number of branch for function / method body. +max-branches=12 + +# Maximum number of locals for function / method body. +max-locals=15 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of return / yield for function / method body. +max-returns=6 + +# Maximum number of statements in function / method body. +max-statements=50 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + + +[LOGGING] + +# The type of string formatting that logging methods do. `old` means using % +# formatting, `new` is for `{}` formatting. +logging-format-style=old + +# Logging modules to check that the string format arguments are in logging +# function parameter format. +logging-modules=logging + + +[IMPORTS] + +# List of modules that can be imported at any level, not just the top level +# one. +allow-any-import-level= + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Deprecated modules which should not be used, separated by a comma. +deprecated-modules= + +# Output a graph (.gv or any supported image format) of external dependencies +# to the given file (report RP0402 must not be disabled). +ext-import-graph= + +# Output a graph (.gv or any supported image format) of all (i.e. internal and +# external) dependencies to the given file (report RP0402 must not be +# disabled). +import-graph= + +# Output a graph (.gv or any supported image format) of internal dependencies +# to the given file (report RP0402 must not be disabled). +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + +# Couples of modules and preferred modules, separated by a comma. +preferred-modules= + + +[VARIABLES] + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid defining new builtins when possible. +additional-builtins= + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of names allowed to shadow builtins +allowed-redefined-builtins= + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_, + _cb + +# A regular expression matching the name of dummy variables (i.e. expected to +# not be used). +dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ + +# Argument names that match this expression will be ignored. +ignored-argument-names=_.*|^ignored_|^unused_ + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members=app.logger + +# Tells whether to warn about missing members when the owner of the attribute +# is inferred to be None. +ignore-none=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# List of symbolic message names to ignore for Mixin members. +ignored-checks-for-mixins=no-member, + not-async-context-manager, + not-context-manager, + attribute-defined-outside-init + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + +# Regex pattern to define which classes are considered mixins. +mixin-class-rgx=.*[Mm]ixin + +# List of decorators that change the signature of a decorated function. +signature-mutators= + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + +# Complete name of functions that never returns. When checking for +# inconsistent-return-statements if a never returning function is called then +# it will be considered as an explicit return statement and no message will be +# printed. +never-returning-functions=sys.exit,argparse.parse_error + + +[FORMAT] + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format=LF + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Maximum number of characters on a single line. +max-line-length=120 + +# Maximum number of lines in a module. +max-module-lines=1000 + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + + +[SIMILARITIES] + +# Comments are removed from the similarity computation +ignore-comments=yes + +# Docstrings are removed from the similarity computation +ignore-docstrings=yes + +# Imports are removed from the similarity computation +ignore-imports=yes + +# Signatures are removed from the similarity computation +ignore-signatures=yes + +# Minimum lines number of a similarity. +min-similarity-lines=4 diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..8af9f76 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Verwendet IntelliSense zum Ermitteln möglicher Attribute. + // Zeigen Sie auf vorhandene Attribute, um die zugehörigen Beschreibungen anzuzeigen. + // Weitere Informationen finden Sie unter https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python-Modul", + "type": "python", + "request": "launch", + "module": "bbs.__main__", + "justMyCode": true + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d931f50 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "python.pythonPath": "/opt/homebrew/bin/python3", + "python.terminal.activateEnvInCurrentTerminal": true +} diff --git a/Makefile b/Makefile index f5604fe..fe6b7ad 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,101 @@ -WGET = wget -EXCUSES_URL = http://pages.cs.wisc.edu/~ballard/bofh/excuses +# +# malte70/bbs Makefile +# +# Programs +WGET = wget +INSTALL = install +PYTHON = python3 -all: excuses +# Excuses file +#EXCUSES = excuses +EXCUSES = bbs/excuses +EXCUSES_URL = http://pages.cs.wisc.edu/~ballard/bofh/excuses + +# Install: Destination directories and files +SYSTEMD_DEST = /etc/systemd/system +MFINGERD_UNIT = mfingerd.service + +# Virtual Environment +VENV = ./.venv + +# DEPRECATED +PICKLEDB_URL = https://raw.githubusercontent.com/patx/pickledb/master/pickledb.py + + + +######################################################################## +# Common make targets +# + +#all: $(EXCUSES) pickledb.py +all: build + @#echo " [ MAKE ] [ install_systemd ] " + +# build: Set up everything needed to run malte70/bbs +.PHONY: build +build: $(EXCUSES) venv requirements + @echo " [ MAKE ] [ build ] Target \"build\" done." + +# install: Install systemd services +.PHONY: install +install: install_inetd install_systemd + @echo " [ MAKE ] [ install ] Target \"install\" done." + +.PHONY: install_inetd +install_inetd: + @echo " [ MAKE ] [ install_inetd ] ERROR: Not implemented yet!" >&2 + +.PHONY: install_systemd +install_systemd: $(MFINGERD_UNIT) + @echo " [ MAKE ] [ install_systemd ] Installing systemd units ..." + $(INSTALL) -m644 $(MFINGERD_UNIT) $(SYSTEMD_DEST) + +.PHONY: clean +clean: + @echo " [ MAKE ] [ clean ] Removing Python __pycache__ folders ..." + find . -maxdepth 2 -name __pycache__ -exec rm -r '{}' ';' -excuses: - $(WGET) $(EXCUSES_URL) +.PHONY: clean-all +clean-all: clean + @echo " [ MAKE ] [ clean-all ] Removing virtual environment ..." + $(RM) -r $(VENV) + @echo " [ MAKE ] [ clean-all ] Removing BOFH excuses database ..." + $(RM) $(EXCUSES) + + + +######################################################################## +# Required files, virtual environment & Python packages +# + +# BOFH Excuses: Download database file "bbs/excuses" +$(EXCUSES): + @echo " [ MAKE ] [ bbs/excuses ] Downloading BOFH excuses database file ..." + $(WGET) -O $(EXCUSES) $(EXCUSES_URL) + +# venv: Fake-target to set up a virtual environment +.PHONY: venv +venv: $(VENV) + +# $(VENV): Set up a virtual environment +$(VENV): + @echo " [ MAKE ] [ venv ] Setting up virtual environment in \"$(VENV)\" ..." + $(PYTHON) -m venv $(VENV) + @# Moved to target "requirements" + @#source $(VENV)/bin/activate && pip install -r requirements.txt + +# requirements: Install required packages inside the virtual environment +.PHONY: requirements +requirements: requirements.txt venv + @echo " [ MAKE ] [ requirements ] Installing packages from requirements.txt" + source $(VENV)/bin/activate && pip install -r $< + + + +######################################################################## +# DEPRECATED +# + +pickledb.py: + $(WGET) $(PICKLEDB_URL) diff --git a/README.md b/README.md index 305b7bb..44f1185 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,60 @@ # Malte's BBS -# Installation +## Installation -- Copy all files to `/opt/bbs` -- Configure xinetd: +Although not necessary, you should copy all files to a directory. +The default is `/opt/bbs` (following the Filesystem Hierarchy Standard). + +Start by downloading required 3rd party files using the Makefile: + +``` +make all +``` + +### Install the BBS itself (Telnet) + +- Configure *inetd* in `/etc/inetd.conf`: ``` telnet stream tcp nowait nobody /usr/sbin/tcpd /usr/sbin/telnetd --no-hostinfo --exec-login=/opt/bbs/minishell ``` +### Quote of the Day + +Add the following line to `/etc/inetd.conf`: + +``` +qotd stream tcp nowait nobody /opt/bbs/qotd +``` + +### mFingerd + +mFingerd is started using it's own systemd unit file, and not by inetd. +You can install the `.service` unit using *make*: + +``` +make install_systemd +``` + +> Currently you need to manually change the install location in +> `mfingerd.service` if it differs from `/opt/bbs` (option +> `WorkingDirectory in the section `[Service]`) + +## Files + +- **Common files** + - `README.md` + - `LICENSE` + - `Makefile` + - `excuses` *(Downloaded by Makefile target)* +- **mFingerd** + - `mfingerd.service` + - `mfingerd.py` + - `bofh.py` + - `logo.txt` +- **QOTD** + - `qotd` *(Just a wrapper for fortune)* +- *BBS* + - `minishell` + - `bbs\_env.py + - `bofh.py` + diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..888de42 --- /dev/null +++ b/TODO.md @@ -0,0 +1,14 @@ +# TODO for `malte70/bbs` + +- Rewrite mfingerd without plain sockets + - *systemd* socket activation + - [An example network service with systemd-activated socket in Python. #systemd #python #socket #socket-activation](https://gist.github.com/kylemanna/d193aaa6b33a89f649524ad27ce47c4b) + - Implemented using *Twisted* + - [The Evolution of Finger: building a simple finger service — Twisted documentation](https://docs.twisted.org/en/latest/core/howto/tutorial/intro.html) + - [The Evolution of Finger: adding features to the finger service — Twisted documentation](https://docs.twisted.org/en/latest/core/howto/tutorial/protocol.html) + - [The Evolution of Finger: pluggable backends — Twisted documentation](https://docs.twisted.org/en/latest/core/howto/tutorial/backends.html) + - [The Evolution of Finger: using a single factory for multiple protocols — Twisted documentation](https://docs.twisted.org/en/latest/core/howto/tutorial/factory.html) + - [The Evolution of Finger: making a finger library — Twisted documentation](https://docs.twisted.org/en/latest/core/howto/tutorial/library.html) + - [The Evolution of Finger: configuration of the finger service — Twisted documentation](https://docs.twisted.org/en/latest/core/howto/tutorial/configuration.html) + - [Twisted Documentation: The Evolution of Finger: adding features to the finger service](Twisted Documentation: The Evolution of Finger: adding features to the finger service) + diff --git a/bbs/__init__.py b/bbs/__init__.py new file mode 100644 index 0000000..40a96af --- /dev/null +++ b/bbs/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/bbs/__main__.py b/bbs/__main__.py new file mode 100644 index 0000000..6ba9d3d --- /dev/null +++ b/bbs/__main__.py @@ -0,0 +1,4 @@ +from bbs.minishell import minishell + +if __name__ == "__main__": + minishell() diff --git a/bbs/bofh.py b/bbs/bofh.py new file mode 100644 index 0000000..cb3b116 --- /dev/null +++ b/bbs/bofh.py @@ -0,0 +1,26 @@ +import os +import random + +BOFH_EXCUSES = os.path.join( + os.path.dirname( + __file__ + ), + "excuses" +) + + +def get_excuse(excuses=BOFH_EXCUSES): + """Get a random excuse + + Returns a random line from the file excuses + """ + f = open(excuses, "r") + excuses = f.read().split("\n") + f.close() + n = len(excuses) + i = random.randint(0, n - 1) + return excuses[i] + + +if __name__ == "__main__": + print(get_excuse()) diff --git a/bbs/daemon2.py b/bbs/daemon2.py new file mode 100644 index 0000000..bfe3019 --- /dev/null +++ b/bbs/daemon2.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python + +import sys, os, time, atexit +from signal import SIGTERM + +class Daemon: + """ + A generic daemon class. + + Usage: subclass the Daemon class and override the run() method + """ + def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): + self.stdin = stdin + self.stdout = stdout + self.stderr = stderr + self.pidfile = pidfile + + def daemonize(self): + """ + do the UNIX double-fork magic, see Stevens' "Advanced + Programming in the UNIX Environment" for details (ISBN 0201563177) + http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 + """ + try: + pid = os.fork() + if pid > 0: + # exit first parent + sys.exit(0) + except OSError, e: + sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) + sys.exit(1) + + # decouple from parent environment + os.chdir("/") + os.setsid() + os.umask(0) + + # do second fork + try: + pid = os.fork() + if pid > 0: + # exit from second parent + sys.exit(0) + except OSError, e: + sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) + sys.exit(1) + + # redirect standard file descriptors + sys.stdout.flush() + sys.stderr.flush() + si = file(self.stdin, 'r') + so = file(self.stdout, 'a+') + se = file(self.stderr, 'a+', 0) + os.dup2(si.fileno(), sys.stdin.fileno()) + os.dup2(so.fileno(), sys.stdout.fileno()) + os.dup2(se.fileno(), sys.stderr.fileno()) + + # write pidfile + atexit.register(self.delpid) + pid = str(os.getpid()) + file(self.pidfile,'w+').write("%s\n" % pid) + + def delpid(self): + os.remove(self.pidfile) + + def start(self): + """ + Start the daemon + """ + # Check for a pidfile to see if the daemon already runs + try: + pf = file(self.pidfile,'r') + pid = int(pf.read().strip()) + pf.close() + except IOError: + pid = None + + if pid: + message = "pidfile %s already exist. Daemon already running?\n" + sys.stderr.write(message % self.pidfile) + sys.exit(1) + + # Start the daemon + self.daemonize() + self.run() + + def stop(self): + """ + Stop the daemon + """ + # Get the pid from the pidfile + try: + pf = file(self.pidfile,'r') + pid = int(pf.read().strip()) + pf.close() + except IOError: + pid = None + + if not pid: + message = "pidfile %s does not exist. Daemon not running?\n" + sys.stderr.write(message % self.pidfile) + return # not an error in a restart + + # Try killing the daemon process + try: + while 1: + os.kill(pid, SIGTERM) + time.sleep(0.1) + except OSError, err: + err = str(err) + if err.find("No such process") > 0: + if os.path.exists(self.pidfile): + os.remove(self.pidfile) + else: + print str(err) + sys.exit(1) + + def restart(self): + """ + Restart the daemon + """ + self.stop() + self.start() + + def run(self): + """ + You should override this method when you subclass Daemon. It will be called after the process has been + daemonized by start() or restart(). + """ \ No newline at end of file diff --git a/bbs/data/excuses b/bbs/data/excuses new file mode 100644 index 0000000..ca5c311 --- /dev/null +++ b/bbs/data/excuses @@ -0,0 +1,466 @@ +clock speed +solar flares +electromagnetic radiation from satellite debris +static from nylon underwear +static from plastic slide rules +global warming +poor power conditioning +static buildup +doppler effect +hardware stress fractures +magnetic interference from money/credit cards +dry joints on cable plug +we're waiting for [the phone company] to fix that line +sounds like a Windows problem, try calling Microsoft support +temporary routing anomaly +somebody was calculating pi on the server +fat electrons in the lines +excess surge protection +floating point processor overflow +divide-by-zero error +POSIX compliance problem +monitor resolution too high +improperly oriented keyboard +network packets travelling uphill (use a carrier pigeon) +Decreasing electron flux +first Saturday after first full moon in Winter +radiosity depletion +CPU radiator broken +It works the way the Wang did, what's the problem +positron router malfunction +cellular telephone interference +techtonic stress +piezo-electric interference +(l)user error +working as designed +dynamic software linking table corrupted +heavy gravity fluctuation, move computer to floor rapidly +secretary plugged hairdryer into UPS +terrorist activities +not enough memory, go get system upgrade +interrupt configuration error +spaghetti cable cause packet failure +boss forgot system password +bank holiday - system operating credits not recharged +virus attack, luser responsible +waste water tank overflowed onto computer +Complete Transient Lockout +bad ether in the cables +Bogon emissions +Change in Earth's rotational speed +Cosmic ray particles crashed through the hard disk platter +Smell from unhygienic janitorial staff wrecked the tape heads +Little hamster in running wheel had coronary; waiting for replacement to be Fedexed from Wyoming +Evil dogs hypnotised the night shift +Plumber mistook routing panel for decorative wall fixture +Electricians made popcorn in the power supply +Groundskeepers stole the root password +high pressure system failure +failed trials, system needs redesigned +system has been recalled +not approved by the FCC +need to wrap system in aluminum foil to fix problem +not properly grounded, please bury computer +CPU needs recalibration +system needs to be rebooted +bit bucket overflow +descramble code needed from software company +only available on a need to know basis +knot in cables caused data stream to become twisted and kinked +nesting roaches shorted out the ether cable +The file system is full of it +Satan did it +Daemons did it +You're out of memory +There isn't any problem +Unoptimized hard drive +Typo in the code +Yes, yes, its called a design limitation +Look, buddy: Windows 3.1 IS A General Protection Fault. +That's a great computer you have there; have you considered how it would work as a BSD machine? +Please excuse me, I have to circuit an AC line through my head to get this database working. +Yeah, yo mama dresses you funny and you need a mouse to delete files. +Support staff hung over, send aspirin and come back LATER. +Someone is standing on the ethernet cable, causing a kink in the cable +Windows 95 undocumented "feature" +Runt packets +Password is too complex to decrypt +Boss' kid fucked up the machine +Electromagnetic energy loss +Budget cuts +Mouse chewed through power cable +Stale file handle (next time use Tupperware(tm)!) +Feature not yet implemented +Internet outage +Pentium FDIV bug +Vendor no longer supports the product +Small animal kamikaze attack on power supplies +The vendor put the bug there. +SIMM crosstalk. +IRQ dropout +Collapsed Backbone +Power company testing new voltage spike (creation) equipment +operators on strike due to broken coffee machine +backup tape overwritten with copy of system manager's favourite CD +UPS interrupted the server's power +The electrician didn't know what the yellow cable was so he yanked the ethernet out. +The keyboard isn't plugged in +The air conditioning water supply pipe ruptured over the machine room +The electricity substation in the car park blew up. +The rolling stones concert down the road caused a brown out +The salesman drove over the CPU board. +The monitor is plugged into the serial port +Root nameservers are out of sync +electro-magnetic pulses from French above ground nuke testing. +your keyboard's space bar is generating spurious keycodes. +the real ttys became pseudo ttys and vice-versa. +the printer thinks its a router. +the router thinks its a printer. +evil hackers from Serbia. +we just switched to FDDI. +halon system went off and killed the operators. +because Bill Gates is a Jehovah's witness and so nothing can work on St. Swithin's day. +user to computer ratio too high. +user to computer ration too low. +we just switched to Sprint. +it has Intel Inside +Sticky bits on disk. +Power Company having EMP problems with their reactor +The ring needs another token +new management +telnet: Unable to connect to remote host: Connection refused +SCSI Chain overterminated +It's not plugged in. +because of network lag due to too many people playing deathmatch +You put the disk in upside down. +Daemons loose in system. +User was distributing pornography on server; system seized by FBI. +BNC (brain not connected) +UBNC (user brain not connected) +LBNC (luser brain not connected) +disks spinning backwards - toggle the hemisphere jumper. +new guy cross-connected phone lines with ac power bus. +had to use hammer to free stuck disk drive heads. +Too few computrons available. +Flat tire on station wagon with tapes. ("Never underestimate the bandwidth of a station wagon full of tapes hurling down the highway" Andrew S. Tannenbaum) +Communications satellite used by the military for star wars. +Party-bug in the Aloha protocol. +Insert coin for new game +Dew on the telephone lines. +Arcserve crashed the server again. +Some one needed the powerstrip, so they pulled the switch plug. +My pony-tail hit the on/off switch on the power strip. +Big to little endian conversion error +You can tune a file system, but you can't tune a fish (from most tunefs man pages) +Dumb terminal +Zombie processes haunting the computer +Incorrect time synchronization +Defunct processes +Stubborn processes +non-redundant fan failure +monitor VLF leakage +bugs in the RAID +no "any" key on keyboard +root rot +Backbone Scoliosis +/pub/lunch +excessive collisions & not enough packet ambulances +le0: no carrier: transceiver cable problem? +broadcast packets on wrong frequency +popper unable to process jumbo kernel +NOTICE: alloc: /dev/null: filesystem full +pseudo-user on a pseudo-terminal +Recursive traversal of loopback mount points +Backbone adjustment +OS swapped to disk +vapors from evaporating sticky-note adhesives +sticktion +short leg on process table +multicasts on broken packets +ether leak +Atilla the Hub +endothermal recalibration +filesystem not big enough for Jumbo Kernel Patch +loop found in loop in redundant loopback +system consumed all the paper for paging +permission denied +Reformatting Page. Wait... +..disk or the processor is on fire. +SCSI's too wide. +Proprietary Information. +Just type 'mv * /dev/null'. +runaway cat on system. +Did you pay the new Support Fee? +We only support a 1200 bps connection. +We only support a 28000 bps connection. +Me no internet, only janitor, me just wax floors. +I'm sorry a pentium won't do, you need an SGI to connect with us. +Post-it Note Sludge leaked into the monitor. +the curls in your keyboard cord are losing electricity. +The monitor needs another box of pixels. +RPC_PMAP_FAILURE +kernel panic: write-only-memory (/dev/wom0) capacity exceeded. +Write-only-memory subsystem too slow for this machine. Contact your local dealer. +Just pick up the phone and give modem connect sounds. "Well you said we should get more lines so we don't have voice lines." +Quantum dynamics are affecting the transistors +Police are examining all internet packets in the search for a narco-net-trafficker +We are currently trying a new concept of using a live mouse. Unfortunately, one has yet to survive being hooked up to the computer.....please bear with us. +Your mail is being routed through Germany ... and they're censoring us. +Only people with names beginning with 'A' are getting mail this week (a la Microsoft) +We didn't pay the Internet bill and it's been cut off. +Lightning strikes. +Of course it doesn't work. We've performed a software upgrade. +Change your language to Finnish. +Fluorescent lights are generating negative ions. If turning them off doesn't work, take them out and put tin foil on the ends. +High nuclear activity in your area. +What office are you in? Oh, that one. Did you know that your building was built over the universities first nuclear research site? And wow, aren't you the lucky one, your office is right over where the core is buried! +The MGs ran out of gas. +The UPS doesn't have a battery backup. +Recursivity. Call back if it happens again. +Someone thought The Big Red Button was a light switch. +The mainframe needs to rest. It's getting old, you know. +I'm not sure. Try calling the Internet's head office -- it's in the book. +The lines are all busy (busied out, that is -- why let them in to begin with?). +Jan 9 16:41:27 huber su: 'su root' succeeded for .... on /dev/pts/1 +It's those computer people in X {city of world}. They keep stuffing things up. +A star wars satellite accidently blew up the WAN. +Fatal error right in front of screen +That function is not currently supported, but Bill Gates assures us it will be featured in the next upgrade. +wrong polarity of neutron flow +Lusers learning curve appears to be fractal +We had to turn off that service to comply with the CDA Bill. +Ionization from the air-conditioning +TCP/IP UDP alarm threshold is set too low. +Someone is broadcasting pygmy packets and the router doesn't know how to deal with them. +The new frame relay network hasn't bedded down the software loop transmitter yet. +Fanout dropping voltage too much, try cutting some of those little traces +Plate voltage too low on demodulator tube +You did wha... oh _dear_.... +CPU needs bearings repacked +Too many little pins on CPU confusing it, bend back and forth until 10-20% are neatly removed. Do _not_ leave metal bits visible! +_Rosin_ core solder? But... +Software uses US measurements, but the OS is in metric... +The computer fleetly, mouse and all. +Your cat tried to eat the mouse. +The Borg tried to assimilate your system. Resistance is futile. +It must have been the lightning storm we had (yesterday) (last week) (last month) +Due to Federal Budget problems we have been forced to cut back on the number of users able to access the system at one time. (namely none allowed....) +Too much radiation coming from the soil. +Unfortunately we have run out of bits/bytes/whatever. Don't worry, the next supply will be coming next week. +Program load too heavy for processor to lift. +Processes running slowly due to weak power supply +Our ISP is having {switching,routing,SMDS,frame relay} problems +We've run out of licenses +Interference from lunar radiation +Standing room only on the bus. +You need to install an RTFM interface. +That would be because the software doesn't work. +That's easy to fix, but I can't be bothered. +Someone's tie is caught in the printer, and if anything else gets printed, he'll be in it too. +We're upgrading /dev/null +The Usenet news is out of date +Our POP server was kidnapped by a weasel. +It's stuck in the Web. +Your modem doesn't speak English. +The mouse escaped. +All of the packets are empty. +The UPS is on strike. +Neutrino overload on the nameserver +Melting hard drives +Someone has messed up the kernel pointers +The kernel license has expired +Netscape has crashed +The cord jumped over and hit the power switch. +It was OK before you touched it. +Bit rot +U.S. Postal Service +Your Flux Capacitor has gone bad. +The Dilithium Crystals need to be rotated. +The static electricity routing is acting up... +Traceroute says that there is a routing problem in the backbone. It's not our problem. +The co-locator cannot verify the frame-relay gateway to the ISDN server. +High altitude condensation from U.S.A.F prototype aircraft has contaminated the primary subnet mask. Turn off your computer for 9 days to avoid damaging it. +Lawn mower blade in your fan need sharpening +Electrons on a bender +Telecommunications is upgrading. +Telecommunications is downgrading. +Telecommunications is downshifting. +Hard drive sleeping. Let it wake up on it's own... +Interference between the keyboard and the chair. +The CPU has shifted, and become decentralized. +Due to the CDA, we no longer have a root account. +We ran out of dial tone and we're and waiting for the phone company to deliver another bottle. +You must've hit the wrong any key. +PCMCIA slave driver +The Token fell out of the ring. Call us when you find it. +The hardware bus needs a new token. +Too many interrupts +Not enough interrupts +The data on your hard drive is out of balance. +Digital Manipulator exceeding velocity parameters +appears to be a Slow/Narrow SCSI-0 Interface problem +microelectronic Riemannian curved-space fault in write-only file system +fractal radiation jamming the backbone +routing problems on the neural net +IRQ-problems with the Un-Interruptible-Power-Supply +CPU-angle has to be adjusted because of vibrations coming from the nearby road +emissions from GSM-phones +CD-ROM server needs recalibration +firewall needs cooling +asynchronous inode failure +transient bus protocol violation +incompatible bit-registration operators +your process is not ISO 9000 compliant +You need to upgrade your VESA local bus to a MasterCard local bus. +The recent proliferation of Nuclear Testing +Elves on strike. (Why do they call EMAG Elf Magic) +Internet exceeded Luser level, please wait until a luser logs off before attempting to log back on. +Your EMAIL is now being delivered by the USPS. +Your computer hasn't been returning all the bits it gets from the Internet. +You've been infected by the Telescoping Hubble virus. +Scheduled global CPU outage +Your Pentium has a heating problem - try cooling it with ice cold water.(Do not turn off your computer, you do not want to cool down the Pentium Chip while he isn't working, do you?) +Your processor has processed too many instructions. Turn it off immediately, do not type any commands!! +Your packets were eaten by the terminator +Your processor does not develop enough heat. +We need a licensed electrician to replace the light bulbs in the computer room. +The POP server is out of Coke +Fiber optics caused gas main leak +Server depressed, needs Prozac +quantum decoherence +those damn raccoons! +suboptimal routing experience +A plumber is needed, the network drain is clogged +50% of the manual is in .pdf readme files +the AA battery in the wallclock sends magnetic interference +the xy axis in the trackball is coordinated with the summer solstice +the butane lighter causes the pincushioning +old inkjet cartridges emanate barium-based fumes +manager in the cable duct +We'll fix that in the next (upgrade, update, patch release, service pack). +HTTPD Error 666 : BOFH was here +HTTPD Error 4004 : very old Intel cpu - insufficient processing power +The ATM board has run out of 10 pound notes. We are having a whip round to refill it, care to contribute ? +Network failure - call NBC +Having to manually track the satellite. +Your/our computer(s) had suffered a memory leak, and we are waiting for them to be topped up. +The rubber band broke +We're on Token Ring, and it looks like the token got loose. +Stray Alpha Particles from memory packaging caused Hard Memory Error on Server. +paradigm shift...without a clutch +PEBKAC (Problem Exists Between Keyboard And Chair) +The cables are not the same length. +Second-system effect. +Chewing gum on /dev/sd3c +Boredom in the Kernel. +the daemons! the daemons! the terrible daemons! +I'd love to help you -- it's just that the Boss won't let me near the computer. +struck by the Good Times virus +YOU HAVE AN I/O ERROR -> Incompetent Operator error +Your parity check is overdrawn and you're out of cache. +Communist revolutionaries taking over the server room and demanding all the computers in the building or they shoot the sysadmin. Poor misguided fools. +Plasma conduit breach +Out of cards on drive D: +Sand fleas eating the Internet cables +parallel processors running perpendicular today +ATM cell has no roaming feature turned on, notebooks can't connect +Webmasters kidnapped by evil cult. +Failure to adjust for daylight savings time. +Virus transmitted from computer to sysadmins. +Virus due to computers having unsafe sex. +Incorrectly configured static routes on the corerouters. +Forced to support NT servers; sysadmins quit. +Suspicious pointer corrupted virtual machine +It's the InterNIC's fault. +Root name servers corrupted. +Budget cuts forced us to sell all the power cords for the servers. +Someone hooked the twisted pair wires into the answering machine. +Operators killed by year 2000 bug bite. +We've picked COBOL as the language of choice. +Operators killed when huge stack of backup tapes fell over. +Robotic tape changer mistook operator's tie for a backup tape. +Someone was smoking in the computer room and set off the halon systems. +Your processor has taken a ride to Heaven's Gate on the UFO behind Hale-Bopp's comet. +it's an ID-10-T error +Dyslexics retyping hosts file on servers +The Internet is being scanned for viruses. +Your computer's union contract is set to expire at midnight. +Bad user karma. +/dev/clue was linked to /dev/null +Increased sunspot activity. +We already sent around a notice about that. +It's union rules. There's nothing we can do about it. Sorry. +Interference from the Van Allen Belt. +Jupiter is aligned with Mars. +Redundant ACLs. +Mail server hit by UniSpammer. +T-1's congested due to porn traffic to the news server. +Data for intranet got routed through the extranet and landed on the internet. +We are a 100% Microsoft Shop. +We are Microsoft. What you are experiencing is not a problem; it is an undocumented feature. +Sales staff sold a product we don't offer. +Secretary sent chain letter to all 5000 employees. +Sysadmin didn't hear pager go off due to loud music from bar-room speakers. +Sysadmin accidentally destroyed pager with a large hammer. +Sysadmins unavailable because they are in a meeting talking about why they are unavailable so much. +Bad cafeteria food landed all the sysadmins in the hospital. +Route flapping at the NAP. +Computers under water due to SYN flooding. +The vulcan-death-grip ping has been applied. +Electrical conduits in machine room are melting. +Traffic jam on the Information Superhighway. +Radial Telemetry Infiltration +Cow-tippers tipped a cow onto the server. +tachyon emissions overloading the system +Maintenance window broken +We're out of slots on the server +Computer room being moved. Our systems are down for the weekend. +Sysadmins busy fighting SPAM. +Repeated reboots of the system failed to solve problem +Feature was not beta tested +Domain controller not responding +Someone else stole your IP address, call the Internet detectives! +It's not RFC-822 compliant. +operation failed because: there is no message for this error (#1014) +stop bit received +internet is needed to catch the etherbunny +network down, IP packets delivered via UPS +Firmware update in the coffee machine +Temporal anomaly +Mouse has out-of-cheese-error +Borg implants are failing +Borg nanites have infested the server +error: one bad user found in front of screen +Please state the nature of the technical emergency +Internet shut down due to maintenance +Daemon escaped from pentagram +crop circles in the corn shell +sticky bit has come loose +Hot Java has gone cold +Cache miss - please take better aim next time +Hash table has woodworm +Trojan horse ran out of hay +Zombie processes detected, machine is haunted. +overflow error in /dev/null +Browser's cookie is corrupted -- someone's been nibbling on it. +Mailer-daemon is busy burning your message in hell. +According to Microsoft, it's by design +vi needs to be upgraded to vii +greenpeace free'd the mallocs +Terrorists crashed an airplane into the server room, have to remove /bin/laden. (rm -rf /bin/laden) +astropneumatic oscillations in the water-cooling +Somebody ran the operating system through a spelling checker. +Rhythmic variations in the voltage reaching the power supply. +Keyboard Actuator Failure. Order and Replace. +Packet held up at customs. +Propagation delay. +High line impedance. +Someone set us up the bomb. +Power surges on the Underground. +Don't worry; it's been deprecated. The new one is worse. +Excess condensation in cloud network +It is a layer 8 problem +The math co-processor had an overflow error that leaked out and shorted the RAM +Leap second overloaded RHEL6 servers +DNS server drank too much and had a hiccup +Your machine had the fuses in backwards. diff --git a/bbs/env.py b/bbs/env.py new file mode 100644 index 0000000..786871f --- /dev/null +++ b/bbs/env.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- + +import platform + +class BBSFakeUserEnv(object): + _user = "" + _node = "" + _name = "" + _hideRealUname = False + _runningInsideLXC = False + _pwd = "C:" + _fileSystem = { + "A:": { + "BOFH.TXT": "Easter Egg:\n\nRun `bofh` or `sry` to get an random BOFH excuse", + "DOCTOR.TXT": "Easter Egg 2:\n\nTry logging in as `doctor` or `doctorwho`, and run `hostname`...", + }, + "C:": { + "HELLO.TXT": "Hello World!", + "ROLLTREPPE3.URL": "https://rolltreppe3.de", + }, + } + + def setUser(self, _user): + self._user = _user + + def getUser(self): + return self._user + + def setNode(self, _node): + self._node = _node + + def getNode(self): + return self._node + + def getName(self): + return self._name + + def setHideRealUname(self, _hideRealUname): + self._hideRealUname = _hideRealUname + + def setRunningInsideLXC(self, _isInsideLXC): + self._runningInsideLXC = _isInsideLXC + + def getRunningInsideLXC(self): + return self._runningInsideLXC + + def getHome(self): + #return "/usr/home/" + self.getUser() + _user = self.getUser().upper() + if len(_user) > 10: + _user = _user[:8] + "~1" + return "C:\\DATA\\" + _user + "\\" + + def getCurrentDir(self, realPwd=False): + if not realPwd and self._pwd == "C:": + return self.getHome() + else: + return self._pwd + "\\" + + def setCurrentDir(self, new_pwd): + self._pwd = new_pwd + + def getDirListing(self): + return self._fileSystem[self._pwd].keys() + + def getFileContents(self, filename): + return self._fileSystem[self._pwd][filename] + + def getPrompt(self, ps1="%w>"): + return ps1.replace("%w", self.getCurrentDir(True)) + + def getUName(self): + if not self._hideRealUname: + return platform.uname()[0]+" "+platform.uname()[1]+" "+platform.uname()[2] + else: + return "BBS-UX "+self.getNode()+" r42" + + def __init__(self): + self._user = "doctor_who" + self._node = platform.node() + #self._node = platform.uname()[1] + self._name = "I am the Doctor!" + diff --git a/bbs/excuses b/bbs/excuses new file mode 100644 index 0000000..ca5c311 --- /dev/null +++ b/bbs/excuses @@ -0,0 +1,466 @@ +clock speed +solar flares +electromagnetic radiation from satellite debris +static from nylon underwear +static from plastic slide rules +global warming +poor power conditioning +static buildup +doppler effect +hardware stress fractures +magnetic interference from money/credit cards +dry joints on cable plug +we're waiting for [the phone company] to fix that line +sounds like a Windows problem, try calling Microsoft support +temporary routing anomaly +somebody was calculating pi on the server +fat electrons in the lines +excess surge protection +floating point processor overflow +divide-by-zero error +POSIX compliance problem +monitor resolution too high +improperly oriented keyboard +network packets travelling uphill (use a carrier pigeon) +Decreasing electron flux +first Saturday after first full moon in Winter +radiosity depletion +CPU radiator broken +It works the way the Wang did, what's the problem +positron router malfunction +cellular telephone interference +techtonic stress +piezo-electric interference +(l)user error +working as designed +dynamic software linking table corrupted +heavy gravity fluctuation, move computer to floor rapidly +secretary plugged hairdryer into UPS +terrorist activities +not enough memory, go get system upgrade +interrupt configuration error +spaghetti cable cause packet failure +boss forgot system password +bank holiday - system operating credits not recharged +virus attack, luser responsible +waste water tank overflowed onto computer +Complete Transient Lockout +bad ether in the cables +Bogon emissions +Change in Earth's rotational speed +Cosmic ray particles crashed through the hard disk platter +Smell from unhygienic janitorial staff wrecked the tape heads +Little hamster in running wheel had coronary; waiting for replacement to be Fedexed from Wyoming +Evil dogs hypnotised the night shift +Plumber mistook routing panel for decorative wall fixture +Electricians made popcorn in the power supply +Groundskeepers stole the root password +high pressure system failure +failed trials, system needs redesigned +system has been recalled +not approved by the FCC +need to wrap system in aluminum foil to fix problem +not properly grounded, please bury computer +CPU needs recalibration +system needs to be rebooted +bit bucket overflow +descramble code needed from software company +only available on a need to know basis +knot in cables caused data stream to become twisted and kinked +nesting roaches shorted out the ether cable +The file system is full of it +Satan did it +Daemons did it +You're out of memory +There isn't any problem +Unoptimized hard drive +Typo in the code +Yes, yes, its called a design limitation +Look, buddy: Windows 3.1 IS A General Protection Fault. +That's a great computer you have there; have you considered how it would work as a BSD machine? +Please excuse me, I have to circuit an AC line through my head to get this database working. +Yeah, yo mama dresses you funny and you need a mouse to delete files. +Support staff hung over, send aspirin and come back LATER. +Someone is standing on the ethernet cable, causing a kink in the cable +Windows 95 undocumented "feature" +Runt packets +Password is too complex to decrypt +Boss' kid fucked up the machine +Electromagnetic energy loss +Budget cuts +Mouse chewed through power cable +Stale file handle (next time use Tupperware(tm)!) +Feature not yet implemented +Internet outage +Pentium FDIV bug +Vendor no longer supports the product +Small animal kamikaze attack on power supplies +The vendor put the bug there. +SIMM crosstalk. +IRQ dropout +Collapsed Backbone +Power company testing new voltage spike (creation) equipment +operators on strike due to broken coffee machine +backup tape overwritten with copy of system manager's favourite CD +UPS interrupted the server's power +The electrician didn't know what the yellow cable was so he yanked the ethernet out. +The keyboard isn't plugged in +The air conditioning water supply pipe ruptured over the machine room +The electricity substation in the car park blew up. +The rolling stones concert down the road caused a brown out +The salesman drove over the CPU board. +The monitor is plugged into the serial port +Root nameservers are out of sync +electro-magnetic pulses from French above ground nuke testing. +your keyboard's space bar is generating spurious keycodes. +the real ttys became pseudo ttys and vice-versa. +the printer thinks its a router. +the router thinks its a printer. +evil hackers from Serbia. +we just switched to FDDI. +halon system went off and killed the operators. +because Bill Gates is a Jehovah's witness and so nothing can work on St. Swithin's day. +user to computer ratio too high. +user to computer ration too low. +we just switched to Sprint. +it has Intel Inside +Sticky bits on disk. +Power Company having EMP problems with their reactor +The ring needs another token +new management +telnet: Unable to connect to remote host: Connection refused +SCSI Chain overterminated +It's not plugged in. +because of network lag due to too many people playing deathmatch +You put the disk in upside down. +Daemons loose in system. +User was distributing pornography on server; system seized by FBI. +BNC (brain not connected) +UBNC (user brain not connected) +LBNC (luser brain not connected) +disks spinning backwards - toggle the hemisphere jumper. +new guy cross-connected phone lines with ac power bus. +had to use hammer to free stuck disk drive heads. +Too few computrons available. +Flat tire on station wagon with tapes. ("Never underestimate the bandwidth of a station wagon full of tapes hurling down the highway" Andrew S. Tannenbaum) +Communications satellite used by the military for star wars. +Party-bug in the Aloha protocol. +Insert coin for new game +Dew on the telephone lines. +Arcserve crashed the server again. +Some one needed the powerstrip, so they pulled the switch plug. +My pony-tail hit the on/off switch on the power strip. +Big to little endian conversion error +You can tune a file system, but you can't tune a fish (from most tunefs man pages) +Dumb terminal +Zombie processes haunting the computer +Incorrect time synchronization +Defunct processes +Stubborn processes +non-redundant fan failure +monitor VLF leakage +bugs in the RAID +no "any" key on keyboard +root rot +Backbone Scoliosis +/pub/lunch +excessive collisions & not enough packet ambulances +le0: no carrier: transceiver cable problem? +broadcast packets on wrong frequency +popper unable to process jumbo kernel +NOTICE: alloc: /dev/null: filesystem full +pseudo-user on a pseudo-terminal +Recursive traversal of loopback mount points +Backbone adjustment +OS swapped to disk +vapors from evaporating sticky-note adhesives +sticktion +short leg on process table +multicasts on broken packets +ether leak +Atilla the Hub +endothermal recalibration +filesystem not big enough for Jumbo Kernel Patch +loop found in loop in redundant loopback +system consumed all the paper for paging +permission denied +Reformatting Page. Wait... +..disk or the processor is on fire. +SCSI's too wide. +Proprietary Information. +Just type 'mv * /dev/null'. +runaway cat on system. +Did you pay the new Support Fee? +We only support a 1200 bps connection. +We only support a 28000 bps connection. +Me no internet, only janitor, me just wax floors. +I'm sorry a pentium won't do, you need an SGI to connect with us. +Post-it Note Sludge leaked into the monitor. +the curls in your keyboard cord are losing electricity. +The monitor needs another box of pixels. +RPC_PMAP_FAILURE +kernel panic: write-only-memory (/dev/wom0) capacity exceeded. +Write-only-memory subsystem too slow for this machine. Contact your local dealer. +Just pick up the phone and give modem connect sounds. "Well you said we should get more lines so we don't have voice lines." +Quantum dynamics are affecting the transistors +Police are examining all internet packets in the search for a narco-net-trafficker +We are currently trying a new concept of using a live mouse. Unfortunately, one has yet to survive being hooked up to the computer.....please bear with us. +Your mail is being routed through Germany ... and they're censoring us. +Only people with names beginning with 'A' are getting mail this week (a la Microsoft) +We didn't pay the Internet bill and it's been cut off. +Lightning strikes. +Of course it doesn't work. We've performed a software upgrade. +Change your language to Finnish. +Fluorescent lights are generating negative ions. If turning them off doesn't work, take them out and put tin foil on the ends. +High nuclear activity in your area. +What office are you in? Oh, that one. Did you know that your building was built over the universities first nuclear research site? And wow, aren't you the lucky one, your office is right over where the core is buried! +The MGs ran out of gas. +The UPS doesn't have a battery backup. +Recursivity. Call back if it happens again. +Someone thought The Big Red Button was a light switch. +The mainframe needs to rest. It's getting old, you know. +I'm not sure. Try calling the Internet's head office -- it's in the book. +The lines are all busy (busied out, that is -- why let them in to begin with?). +Jan 9 16:41:27 huber su: 'su root' succeeded for .... on /dev/pts/1 +It's those computer people in X {city of world}. They keep stuffing things up. +A star wars satellite accidently blew up the WAN. +Fatal error right in front of screen +That function is not currently supported, but Bill Gates assures us it will be featured in the next upgrade. +wrong polarity of neutron flow +Lusers learning curve appears to be fractal +We had to turn off that service to comply with the CDA Bill. +Ionization from the air-conditioning +TCP/IP UDP alarm threshold is set too low. +Someone is broadcasting pygmy packets and the router doesn't know how to deal with them. +The new frame relay network hasn't bedded down the software loop transmitter yet. +Fanout dropping voltage too much, try cutting some of those little traces +Plate voltage too low on demodulator tube +You did wha... oh _dear_.... +CPU needs bearings repacked +Too many little pins on CPU confusing it, bend back and forth until 10-20% are neatly removed. Do _not_ leave metal bits visible! +_Rosin_ core solder? But... +Software uses US measurements, but the OS is in metric... +The computer fleetly, mouse and all. +Your cat tried to eat the mouse. +The Borg tried to assimilate your system. Resistance is futile. +It must have been the lightning storm we had (yesterday) (last week) (last month) +Due to Federal Budget problems we have been forced to cut back on the number of users able to access the system at one time. (namely none allowed....) +Too much radiation coming from the soil. +Unfortunately we have run out of bits/bytes/whatever. Don't worry, the next supply will be coming next week. +Program load too heavy for processor to lift. +Processes running slowly due to weak power supply +Our ISP is having {switching,routing,SMDS,frame relay} problems +We've run out of licenses +Interference from lunar radiation +Standing room only on the bus. +You need to install an RTFM interface. +That would be because the software doesn't work. +That's easy to fix, but I can't be bothered. +Someone's tie is caught in the printer, and if anything else gets printed, he'll be in it too. +We're upgrading /dev/null +The Usenet news is out of date +Our POP server was kidnapped by a weasel. +It's stuck in the Web. +Your modem doesn't speak English. +The mouse escaped. +All of the packets are empty. +The UPS is on strike. +Neutrino overload on the nameserver +Melting hard drives +Someone has messed up the kernel pointers +The kernel license has expired +Netscape has crashed +The cord jumped over and hit the power switch. +It was OK before you touched it. +Bit rot +U.S. Postal Service +Your Flux Capacitor has gone bad. +The Dilithium Crystals need to be rotated. +The static electricity routing is acting up... +Traceroute says that there is a routing problem in the backbone. It's not our problem. +The co-locator cannot verify the frame-relay gateway to the ISDN server. +High altitude condensation from U.S.A.F prototype aircraft has contaminated the primary subnet mask. Turn off your computer for 9 days to avoid damaging it. +Lawn mower blade in your fan need sharpening +Electrons on a bender +Telecommunications is upgrading. +Telecommunications is downgrading. +Telecommunications is downshifting. +Hard drive sleeping. Let it wake up on it's own... +Interference between the keyboard and the chair. +The CPU has shifted, and become decentralized. +Due to the CDA, we no longer have a root account. +We ran out of dial tone and we're and waiting for the phone company to deliver another bottle. +You must've hit the wrong any key. +PCMCIA slave driver +The Token fell out of the ring. Call us when you find it. +The hardware bus needs a new token. +Too many interrupts +Not enough interrupts +The data on your hard drive is out of balance. +Digital Manipulator exceeding velocity parameters +appears to be a Slow/Narrow SCSI-0 Interface problem +microelectronic Riemannian curved-space fault in write-only file system +fractal radiation jamming the backbone +routing problems on the neural net +IRQ-problems with the Un-Interruptible-Power-Supply +CPU-angle has to be adjusted because of vibrations coming from the nearby road +emissions from GSM-phones +CD-ROM server needs recalibration +firewall needs cooling +asynchronous inode failure +transient bus protocol violation +incompatible bit-registration operators +your process is not ISO 9000 compliant +You need to upgrade your VESA local bus to a MasterCard local bus. +The recent proliferation of Nuclear Testing +Elves on strike. (Why do they call EMAG Elf Magic) +Internet exceeded Luser level, please wait until a luser logs off before attempting to log back on. +Your EMAIL is now being delivered by the USPS. +Your computer hasn't been returning all the bits it gets from the Internet. +You've been infected by the Telescoping Hubble virus. +Scheduled global CPU outage +Your Pentium has a heating problem - try cooling it with ice cold water.(Do not turn off your computer, you do not want to cool down the Pentium Chip while he isn't working, do you?) +Your processor has processed too many instructions. Turn it off immediately, do not type any commands!! +Your packets were eaten by the terminator +Your processor does not develop enough heat. +We need a licensed electrician to replace the light bulbs in the computer room. +The POP server is out of Coke +Fiber optics caused gas main leak +Server depressed, needs Prozac +quantum decoherence +those damn raccoons! +suboptimal routing experience +A plumber is needed, the network drain is clogged +50% of the manual is in .pdf readme files +the AA battery in the wallclock sends magnetic interference +the xy axis in the trackball is coordinated with the summer solstice +the butane lighter causes the pincushioning +old inkjet cartridges emanate barium-based fumes +manager in the cable duct +We'll fix that in the next (upgrade, update, patch release, service pack). +HTTPD Error 666 : BOFH was here +HTTPD Error 4004 : very old Intel cpu - insufficient processing power +The ATM board has run out of 10 pound notes. We are having a whip round to refill it, care to contribute ? +Network failure - call NBC +Having to manually track the satellite. +Your/our computer(s) had suffered a memory leak, and we are waiting for them to be topped up. +The rubber band broke +We're on Token Ring, and it looks like the token got loose. +Stray Alpha Particles from memory packaging caused Hard Memory Error on Server. +paradigm shift...without a clutch +PEBKAC (Problem Exists Between Keyboard And Chair) +The cables are not the same length. +Second-system effect. +Chewing gum on /dev/sd3c +Boredom in the Kernel. +the daemons! the daemons! the terrible daemons! +I'd love to help you -- it's just that the Boss won't let me near the computer. +struck by the Good Times virus +YOU HAVE AN I/O ERROR -> Incompetent Operator error +Your parity check is overdrawn and you're out of cache. +Communist revolutionaries taking over the server room and demanding all the computers in the building or they shoot the sysadmin. Poor misguided fools. +Plasma conduit breach +Out of cards on drive D: +Sand fleas eating the Internet cables +parallel processors running perpendicular today +ATM cell has no roaming feature turned on, notebooks can't connect +Webmasters kidnapped by evil cult. +Failure to adjust for daylight savings time. +Virus transmitted from computer to sysadmins. +Virus due to computers having unsafe sex. +Incorrectly configured static routes on the corerouters. +Forced to support NT servers; sysadmins quit. +Suspicious pointer corrupted virtual machine +It's the InterNIC's fault. +Root name servers corrupted. +Budget cuts forced us to sell all the power cords for the servers. +Someone hooked the twisted pair wires into the answering machine. +Operators killed by year 2000 bug bite. +We've picked COBOL as the language of choice. +Operators killed when huge stack of backup tapes fell over. +Robotic tape changer mistook operator's tie for a backup tape. +Someone was smoking in the computer room and set off the halon systems. +Your processor has taken a ride to Heaven's Gate on the UFO behind Hale-Bopp's comet. +it's an ID-10-T error +Dyslexics retyping hosts file on servers +The Internet is being scanned for viruses. +Your computer's union contract is set to expire at midnight. +Bad user karma. +/dev/clue was linked to /dev/null +Increased sunspot activity. +We already sent around a notice about that. +It's union rules. There's nothing we can do about it. Sorry. +Interference from the Van Allen Belt. +Jupiter is aligned with Mars. +Redundant ACLs. +Mail server hit by UniSpammer. +T-1's congested due to porn traffic to the news server. +Data for intranet got routed through the extranet and landed on the internet. +We are a 100% Microsoft Shop. +We are Microsoft. What you are experiencing is not a problem; it is an undocumented feature. +Sales staff sold a product we don't offer. +Secretary sent chain letter to all 5000 employees. +Sysadmin didn't hear pager go off due to loud music from bar-room speakers. +Sysadmin accidentally destroyed pager with a large hammer. +Sysadmins unavailable because they are in a meeting talking about why they are unavailable so much. +Bad cafeteria food landed all the sysadmins in the hospital. +Route flapping at the NAP. +Computers under water due to SYN flooding. +The vulcan-death-grip ping has been applied. +Electrical conduits in machine room are melting. +Traffic jam on the Information Superhighway. +Radial Telemetry Infiltration +Cow-tippers tipped a cow onto the server. +tachyon emissions overloading the system +Maintenance window broken +We're out of slots on the server +Computer room being moved. Our systems are down for the weekend. +Sysadmins busy fighting SPAM. +Repeated reboots of the system failed to solve problem +Feature was not beta tested +Domain controller not responding +Someone else stole your IP address, call the Internet detectives! +It's not RFC-822 compliant. +operation failed because: there is no message for this error (#1014) +stop bit received +internet is needed to catch the etherbunny +network down, IP packets delivered via UPS +Firmware update in the coffee machine +Temporal anomaly +Mouse has out-of-cheese-error +Borg implants are failing +Borg nanites have infested the server +error: one bad user found in front of screen +Please state the nature of the technical emergency +Internet shut down due to maintenance +Daemon escaped from pentagram +crop circles in the corn shell +sticky bit has come loose +Hot Java has gone cold +Cache miss - please take better aim next time +Hash table has woodworm +Trojan horse ran out of hay +Zombie processes detected, machine is haunted. +overflow error in /dev/null +Browser's cookie is corrupted -- someone's been nibbling on it. +Mailer-daemon is busy burning your message in hell. +According to Microsoft, it's by design +vi needs to be upgraded to vii +greenpeace free'd the mallocs +Terrorists crashed an airplane into the server room, have to remove /bin/laden. (rm -rf /bin/laden) +astropneumatic oscillations in the water-cooling +Somebody ran the operating system through a spelling checker. +Rhythmic variations in the voltage reaching the power supply. +Keyboard Actuator Failure. Order and Replace. +Packet held up at customs. +Propagation delay. +High line impedance. +Someone set us up the bomb. +Power surges on the Underground. +Don't worry; it's been deprecated. The new one is worse. +Excess condensation in cloud network +It is a layer 8 problem +The math co-processor had an overflow error that leaked out and shorted the RAM +Leap second overloaded RHEL6 servers +DNS server drank too much and had a hiccup +Your machine had the fuses in backwards. diff --git a/bbs/mfingerd.py b/bbs/mfingerd.py new file mode 100644 index 0000000..4e0d934 --- /dev/null +++ b/bbs/mfingerd.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- + +__doc__ = """ mFingerd + +Copyright (c) 2012,2013,2016 Malte Bublitz +All rights reserved. + +Configuration is done in the CONFIG variable. +Set CONFIG.ServerInfo to the server information that +should be returned to the user if no username was +specified. +CONFIG.UserInfo contains the information for the users +that can be queried. +CONFIG.UserNonExistentError is returned if a user was +specified, but not listed in CONFIG.UserInfo. +""" + +class AppInfo(object): + Name = "mFingerd" + Version = "0.2" + Vendor = "rolltreppe3" + WebsiteURL = "https://rolltreppe3.de" + DBFile = "fingerinfo.db" + + +import sys +import os +import logging +import socketserver +import string +from socket import getfqdn +import signal +import .bbs.bofh +import pickledb +import datetime + + +class FingerHandler(socketserver.StreamRequestHandler): + def handle(self): + self._db = pickledb.load(AppInfo.DBFile, False) + + # read a line (limited to 512 byte to + # avoid megabytes of data to process + #username = self.rfile.readline(512) + username = self.rfile.readline(32) + + # strip the username string + username = username.strip() + + logging.info(f"Got query from {self.client_address}: {username}") + + # send the requested username. + if username == '' and self._db.exists("@"): + info = self._db.get("@") + + elif username == '': + info = self._db.get("404") + + elif self._db.exists(username): + info = self._db.get(username) + + # if "%%IP%%" in info: + # info = info.replace("%%IP%%", self.client_address[0]) + # elif "%%FQDN%%" in info: + # info = info.replace("%%FQDN%%", getfqdn(self.client_address[0])) + # elif "%%BOFH%%" in info: + # info = info.replace("%%BOFH%%", bofh.get_excuse()) + info = info.replace( + "%%IP%%", + self.client_address[0] + ) + # elif "%%FQDN%%" in info: + # info = info.replace("%%FQDN%%", getfqdn(self.client_address[0])) + # elif "%%BOFH%%" in info: + # info = info.replace("%%BOFH%%", bofh.get_excuse()) + else: + info = self._db.get("404") + + self.wfile.write(info.encode("utf-8") + b"\n") + +def main(): + # Get UID + uid = os.getuid() + + # Port to listen on + # If running as root/uid=0, use default port 79; if not, + # use 7079 as a fallback. + if uid == 0: + PORT = 79 + else: + PORT = 7079 + #PORT = 7182 + + # IP + port to listen on + listen_on = ("", PORT) + + # Load database + global db + db = pickledb.load("fingerinfo.db", False) + + # + # Create an server instance + # + global server + server = socketserver.TCPServer( + listen_on, + FingerHandler + ) + + def stop_server(signum = 0, frame = 0): + global server + + # https://www.generacodice.com/en/articolo/4343888/python-2-does-not-handle-signals-if-tcpserver-is-running-in-another-thread + server.running = False + #print "stop_server(",signum,",",repr(frame),") :: server.shutdown()" + # + server.shutdown() + + #print "stop_server(",signum,",",repr(frame),") :: server.server_close()" + server.server_close() + + #print "stop_server(",signum,",",repr(frame),") :: sys.exit(0)" + sys.exit(0) + + # + # Allow terminating via SIGINT, SIGTERM or SIGUSR1 + # + signal.signal(signal.SIGINT, stop_server) + signal.signal(signal.SIGTERM, stop_server) + signal.signal(signal.SIGUSR2, stop_server) + + # + # Run the server + # + try: + logging.info(f"{AppInfo.Name} {AppInfo.Version} :: Listening on {str(listen_on[0])}:{str(listen_on[1])}") + # print("Press Ctrl+C at any time (or send SIGTERM/SIGUSR2) to exit...") + + server.serve_forever() + + except KeyboardInterrupt: + # print("\nCtr+C pressed.\nAborting...") + logging.warning("Shutting down after SIGTERM") + #stop_server() + server.shutdown() + server.server_close() + #sys.exit(0) + +if __name__=='__main__': + main() + diff --git a/bbs/mfingerd_daemon.py b/bbs/mfingerd_daemon.py new file mode 100755 index 0000000..c7a536c --- /dev/null +++ b/bbs/mfingerd_daemon.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +import sys, time +import bbs.daemon2 +import bbs.mfingerd + +class MyFingerDaemon(bbs.daemon2.Daemon): + def run(self): + bbs.mfingerd.main() + +def main(pidfile): + daemon = MyFingerDaemon(pidfile) + + if len(sys.argv) == 2: + if 'start' == sys.argv[1]: + daemon.start() + + elif 'stop' == sys.argv[1]: + daemon.stop() + + elif 'restart' == sys.argv[1]: + daemon.restart() + + else: + print "Unknown command" + sys.exit(2) + + sys.exit(0) + + else: + print(f"usage: {sys.argv[0]} start|stop|restart", file=sys.stderr) + sys.exit(2) + +if __name__ == "__main__": + main("/tmp/mfingerd.pid") + diff --git a/bbs/minishell.py b/bbs/minishell.py new file mode 100644 index 0000000..03bf1df --- /dev/null +++ b/bbs/minishell.py @@ -0,0 +1,244 @@ +#!/usr/bin/env python3 + +"""Minimal Shell + +Use whenever a user should be able to launch a shell, +but not to execute commands. +""" + + +import os +import sys +import getpass +# TODO: import readline + +import bbs.env +import bbs.bofh + + +def getuser(): + return "doctorwho" + + +def issue(): + # Escape codes for clearing the screen: + # ansi/vt100/vt220 + # \e[H\e[J + # xterm-256color + # \e[3J\e[H\e[2J + # + os.system("clear") + # print("") + # os.system("figlet -f slant T.A.R.D.I.S.") + # print("") + # print(chr(27)+"[H"+chr(27)+"[J", end="") + print(""" + ______ ___ ____ ____ ____ _____ + /_ __/ / | / __ \\ / __ \\ / _/ / ___/ + / / / /| | / /_/ / / / / / / / \\__ \\ + / / _ / ___ |_ / _, _/ / /_/ / _/ / _ ___/ / +/_/ (_)_/ |_(_)_/ |_(_)_____(_)___/(_)____(_) + +""") + + +def login(prompt1="login: ", prompt2="Password: ", clear_before=True): + if clear_before: + # os.system("clear") + pass + + login_data = ["", ""] + while len(login_data[0]) < 2: + try: + login_data[0] = input(prompt1) + except EOFError: + print("^D") + + login_data[1] = getpass.getpass(prompt2) + + return login_data + + +def minishell(ps1="%w> "): + """ + ps1 is used as the prompt, and %w will be replaced by the current working directory + """ + env = bbs.env.BBSFakeUserEnv() + # commands_allowed = ( + # "", + # "exit", + # "logout", + # "help", + # "whoami", + # "id", + # "hostname", + # "pwd", + # "ls", "dir", + # "cat", "type", + # "uname", + # "clear", + # "sry", "bofh", + # ) + command = "" + + # /etc/issue + issue() + + # Log in + try: + env.setUser(login(clear_before=False)[0]) + except KeyboardInterrupt: + # sys.exit(0) + env.setUser("john.doe") + + env.setHideRealUname(True) + env.setNode("bbs.malte70.de") + if env.getUser() in ["doctor", "doctorwho", "doctor_who"]: + # env.setNode("torchwood.tardis.malte70.de") + env.setNode("bbs.torchwood-cardiff.torchwood.gov.uk") + + if "--lxc" in sys.argv[1:]: + env.setRunningInsideLXC(True) + + print("\nWelcome on " + env.getNode() + ", " + env.getUser() + "!\n") + + if env.getRunningInsideLXC(): + # Show an unneccessary cryptic message if running inside LXC + print(" [SYS$LOG] Installing BBS-UX LXC services...\n") + + try: + while command != "exit": + # print(ps1, end="") + print(env.getPrompt(ps1), end="") + try: + command = input().lower() + + except KeyboardInterrupt: + print("") + continue + + # Split command from command_args + command_args = " ".join(command.split(" ")[1:]) + command = command.split(" ")[0] + + if command == "logout" or command == "exit": + command = "exit" + + elif command == "help" and len(command_args) < 1: + print("""Help +Commands: + whoami + id + hostname + pwd + ls + cat + uname + clear + help + logout/exit +""") + + elif command == "help" and len(command_args) > 1: + help_topic = command_args.split(" ")[0] + if help_topic == "sry": + print("SRY\n\tEaster Egg. Just try it!") + elif help_topic == "two": + print("TWO\n\tTime Wasting Option") + print("\tDon't conflate TWO with TSO in the OS/360") + print("\tfamily of mainframe systems!") + elif help_topic in ("shutdown", "poweroff", "halt"): + print("shutdown/poweroff/halt") + print("\tRunning them is interpreted as an act of violence") + print("\tagainst the Dalek!") + else: + print(help_topic) + print("\tFAKENEWS!") + + elif command == "whoami": + if not env.getUser() in ["doctor", "doctorwho", "doctor_who"]: + print(env.getUser()) + else: + # print("I am the Doctor!") + print(env.getName()) + print("") + print("I should behave politely, so maybe excuse for") + print("future mistakes with \"sry\" (Yes, an easter egg!)") + print("") + + elif command == "shutdown" or command == "poweroff" or command == "halt": + print("Exterminate!") + print("Exterminate!".upper()) + sys.exit(0) + + elif command == "id": + print("uid=42(" + env.getUser() + ") gid=100(users) groups=42(" + env.getUser() + "),9999(telnet)") + + elif command == "hostname": + print(env.getNode()) + + elif command == "pwd": + # print("/usr/home/"+getuser()) + print(env.getCurrentDir(True)) + + elif command == "ls" or command == "dir": + # print("A: TARDIS ZIP : DALEK EXE") + # print("A: CLARA DOC : ASHILDR GIF") + _dir = env.getDirListing() + for _entry in _dir: + print(" " + env.getCurrentDir()[:2] + " " + _entry) + + elif command == "cat" or command == "type": + # DEBUG: + # print("CMD = \"" + command + "\"") + # print("ARGS = \"" + command_args + "\"") + + filename = command_args.upper() + print(env.getFileContents(filename)) + + elif command == "uname": + print(env.getUName()) + + elif command == "clear": + # clear screen + os.system("clear") + + elif command == "sry" or command == "bofh": + # BOFH excuse + print(" " + bbs.bofh.get_excuse()) + + elif len(command) == 2 and command[1] == ":": + # Change drive/working directory + env.setCurrentDir(command.upper()) + + # elif not command in commands_allowed: + # print("-minishell: "+command.split(" ")[0]+": Command not found.") + elif len(command) > 0: + print("TWO: " + command.split(" ")[0] + ": Command not found.") + + except EOFError: + print("") + + print("Good bye.") + + +if __name__ == "__main__": + """ + ==> Prompt ideas: + - sh + -> ps1='$ ' + - CP/M and early MS-DOS versions + -> ps1='C>' + - MS-DOS (later versions) + -> ps1='C:\\> ' + -> ps1='%w> ' + - ITS + -> ps1=':' + - BASIC prompt for INPUT + -> ps1='? ' + """ + + # New default + ps1 = '%w> ' + + minishell(ps1) diff --git a/bbs_env.py b/bbs_env.py deleted file mode 100644 index 2b6e1fb..0000000 --- a/bbs_env.py +++ /dev/null @@ -1,40 +0,0 @@ -# -*- coding: utf-8 -*- - -import platform - -class BBSFakeUserEnv(object): - _user = "" - _node = "" - _name = "" - _hideRealUname = False - - def setUser(self, _user): - self._user = _user - - def getUser(self): - return self._user - - def getNode(self): - return self._node - - def getName(self): - return self._name - - def setHideRealUname(self, _hideRealUname): - self._hideRealUname = _hideRealUname - - def getHome(self): - return "/usr/home/" + self.getUser() - - def getUName(self): - if not self._hideRealUname: - return platform.uname()[0]+" "+platform.uname()[1]+" "+platform.uname()[2] - else: - return "Linux "+self.getNode()+" 0.13.37-42" - - def __init__(self): - self._user = "doctor_who" - self._node = platform.node() - #self._node = platform.uname()[1] - self._name = "I am the Doctor!" - diff --git a/bin/lxc-launcher b/bin/lxc-launcher new file mode 100755 index 0000000..08a978e --- /dev/null +++ b/bin/lxc-launcher @@ -0,0 +1,11 @@ +#!/bin/bash +# +# Usage: +# /lxc-fs-path/bin/lxc-launcher /lxc-fs-path +# + +cd "$1" + +pwd +python -m bbs.minishell + diff --git a/bin/tardis-minishell b/bin/tardis-minishell new file mode 100755 index 0000000..f0e1f88 --- /dev/null +++ b/bin/tardis-minishell @@ -0,0 +1,12 @@ +#!/bin/bash + +pwd + +#cd $(basename $0)/.. + + +python -m bbs.minishell + + +echo -n 'Press ... '; read + diff --git a/bofh.py b/bofh.py deleted file mode 100644 index ef698ea..0000000 --- a/bofh.py +++ /dev/null @@ -1,15 +0,0 @@ -# -*- coding: utf-8 -*- - -from random import randint - -def get_excuse(): - f = open("excuses", "r") - excuses = f.read().split("\n") - f.close() - n = len(excuses) - i = randint(0, n-1) - return excuses[i] - -if __name__ == "__main__": - print(get_excuse()) - diff --git a/config_backup_spandau.py b/config_backup_spandau.py new file mode 100644 index 0000000..5ed9e09 --- /dev/null +++ b/config_backup_spandau.py @@ -0,0 +1,35 @@ +CONFIG = { + #"ServerInfo": "This is host.example.com.", + "ServerInfo": """This is spandau.rolltreppe3.de. +Try: + finger ip@spandau.rolltreppe3.de + finger myip@spandau.rolltreppe3.de + finger malte70@spandau.rolltreppe3.de +""", + "UserInfo": { + "malte": "Lookup malte70 instead.", + "malte70": """Full name: Malte Bublitz +Twitter..: @malte70 +EMail....: malte@rolltreppe3.de +Web......: https://malte70.de +Work.....: https://rolltreppe3.de +XMPP.....: malte.bublitz@riseup.net""", + "timo": "Lookup stardustdestruktor instead.", + "stardustdestruktor": """Full name: Timo König +Twitter..: *hidden* +EMail....: *hidden* +Web......: https://tmkng.de +Work.....: https://rolltreppe3.de""", + "rolltreppe3": "%%LOGO%%", + "r3": "%%LOGO%%", + "rt3x": "%%LOGO%%", + "ip": "%%IP%%", + "fqdn": "%%FQDN%%", + "hostname": "%%FQDN%%", + #"john": "John Doe", + "myip": """Your IP: %%IP%% +Your Hostname: %%FQDN%%""", + "bofh": "%%BOFH%%" + }, + "UserNonExistentError": "The requested user does not exist." +} diff --git a/deepthought.fingerinfo.db b/deepthought.fingerinfo.db new file mode 100644 index 0000000..09b5c06 --- /dev/null +++ b/deepthought.fingerinfo.db @@ -0,0 +1 @@ +{"@": "This is spandau.rolltreppe3.de.\nTry:\n\tfinger ip@spandau.rolltreppe3.de\n\tfinger myip@spandau.rolltreppe3.de\n\tfinger malte70@spandau.rolltreppe3.de\n", "ip": "%%IP%%", "myip": "Your IP: %%IP%%\nYour Hostname: %%FQDN%%", "404": "The requested user does not exist.", "malte70": "Full name: Malte Bublitz\nTwitter: @malte70\nEMail: malte@rolltreppe3.de\nGnuPG: B214 8955 F6A6 6A8B 8FA3 F59B 605D A5C7 29F9 C184\nWeb: https://malte70.de\nWork: https://rolltreppe3.de\nXMPP: malte.bublitz@riseup.net", "bofh": "%%BOFH%%"} \ No newline at end of file diff --git a/fingerinfo.db b/fingerinfo.db new file mode 100644 index 0000000..09b5c06 --- /dev/null +++ b/fingerinfo.db @@ -0,0 +1 @@ +{"@": "This is spandau.rolltreppe3.de.\nTry:\n\tfinger ip@spandau.rolltreppe3.de\n\tfinger myip@spandau.rolltreppe3.de\n\tfinger malte70@spandau.rolltreppe3.de\n", "ip": "%%IP%%", "myip": "Your IP: %%IP%%\nYour Hostname: %%FQDN%%", "404": "The requested user does not exist.", "malte70": "Full name: Malte Bublitz\nTwitter: @malte70\nEMail: malte@rolltreppe3.de\nGnuPG: B214 8955 F6A6 6A8B 8FA3 F59B 605D A5C7 29F9 C184\nWeb: https://malte70.de\nWork: https://rolltreppe3.de\nXMPP: malte.bublitz@riseup.net", "bofh": "%%BOFH%%"} \ No newline at end of file diff --git a/logo.txt b/logo.txt new file mode 100644 index 0000000..37d94a4 --- /dev/null +++ b/logo.txt @@ -0,0 +1,32 @@ + + + .&&&&&&&&&&&&&&&&&&* + &%#((((((((((((((((%%%&% + &%#((%%%%%%%%%%%%%%((((%%& + &%#((%&* &&%(((%%% /################### + &%#((%&* /&%(((%& #////////////////////## + &%#((%&* #&%(((%& #///,,///////////////## + &%#((%&* &&%(((%%% #///,//(############# + &%#((%&&&&&&&&&%%%%(((#%&& #///,//## + &%#((((((((((((((((%%%&% #///,//## + &%#((%&&&&&&%#((%%%( ###############///,//## + &%#((%&* &%%(((%%& ##/////////////////,,//## + &%#((%&* (&%(((%%& #(//,,,////////////////## + &%#((%&* &%%(((%&% #(//,///###############* + &%#((%&* #&%(((%%& #(//,///# + &%#((%&* %%%(((%&& #(//,///# %%%######%%%* + &%#((%&* ##############(//,///# %%##(///////////##%/ + ,&&&& #/////////////////,,///# %#(/////######/////##% + #//*,,,////////////////# %%###%%, %##////#%, + #//*,///############### %%#////#%, + #//*///# %%%%%%###////##% + #//*///# %#(////////###% + #//*///# %#(//////////##%# + ##/////////////////,///# ,(%%%%%##////##% + #///****************///# /%#////#%/ + #(//////////////////(## %%###%% %%#////#%* + %##////####%%###/////##% + %%##//////////////##%( + %%%##########%%% + + diff --git a/mcbxDOS_bbs.py b/mcbxDOS_bbs.py new file mode 100644 index 0000000..373b29f --- /dev/null +++ b/mcbxDOS_bbs.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2012 Malte Bublitz, https://malte-bublitz.de +# All rights reserved. +# + +from twisted.internet.protocol import Factory +from twisted.protocols.basic import LineReceiver +from twisted.internet import reactor +import datetime + +MOTD = """ +Starting MCBX DOS... +""" + +class DOSBBS(LineReceiver): + _DOS = { + "Version": "1.0", + "Name": "MCBX DOS" + } + _DATA = { + "A": { + "DATA": { + "LETTER.DOC": "Hello my friend." + }, + "VER.COM": "0xEXE", + "DATE.COM": "0xEXE", + "SHELL.EXE": "0xEXE", + "CONFIG.SYS": "REM DOS CONFIG\nDEVICE=A:\\DOS.SYS\nDEVICE=A:\\BIOS.SYS\nDOS=UNIX", + "DOS.SYS": "0xSYS", + "BIOS.SYS": "0xSYS" + }, + "B": { + "ERROR.EXE": "0xEXE" + } + } + def getPath(self): + p = self.path[0] + ":" + if len(self.path) > 1: + for d in self.path[1:]: + p += "\\" + d + return p + + def connectionMade(self): + self.delimiter = '\n' + self.path = ["A", "DATA"] + self.transport.write("") + self.sendLine(MOTD) + p = self.path[0] + ":" + if len(self.path) > 1: + for d in self.path[1:]: + p += "\\" + d + self.transport.write(self.getPath()+">") + + def lineReceived(self, line): + command = line.upper() + #print + if command.startswith("VER"): + self.sendLine("") + self.sendLine(self._DOS["Name"] + " " + self._DOS["Version"]) + self.sendLine("") + elif command.startswith("EXIT") or command.startswith("QUIT") or command.startswith("LOGOUT"): + self.sendLine("bye.") + self.transport.loseConnection() + elif command.startswith("DATE"): + now = datetime.datetime.now() + self.sendLine(now.strftime("%Y-%m-%d")) + elif command.startswith("HELP"): + title = self._DOS["Name"] + " " + self._DOS["Version"] + " HELP" + self.sendLine(title) + self.sendLine(len(title) * "=") + self.sendLine("Commands:\n\tVER\n\tEXIT\n\tHELP\n") + elif command.startswith("DIR"): + listing = "\n" + listing += " Volume in drive " + self.path[0] + " is FLOPPY~" + self.path[0] + "\n" + listing += " Volume Serial Number is 1337-42-" + listing += "ACAB" if self.path[0] == "A" else "BEEF" + listing += "\n Directory of " + self.getPath() + "\n" + listing += "\n" + #for _name, _cont in + + self.sendLine(listing) + elif line.startswith("malte70"): + self.sendLine("Malte Bublitz\n@malte70\nMore coming soon.") + + # prevent printing prompt when user wantrs to disconnect. + if not command.startswith("EXIT"): + p = self.path[0] + ":" + if len(self.path) > 1: + for d in self.path[1:]: + p += "\\" + d + self.transport.write(p+">") + +factory = Factory() +factory.protocol = DOSBBS +reactor.listenTCP(7079, factory) +reactor.run() diff --git a/mfingerd.service b/mfingerd.service new file mode 100644 index 0000000..cd429bf --- /dev/null +++ b/mfingerd.service @@ -0,0 +1,16 @@ +# vim:set ft=systemd: + +[Unit] +Description=Malte's Finger Daemon +Requires=network.target +After=network.target + +[Service] +Type=simple +#ExecStart=/usr/bin/env python2 /opt/bbs/mfingerd.py +ExecStart=/usr/bin/env python2 mfingerd.py +WorkingDirectory=/opt/bbs + +[Install] +WantedBy=multi-user.target + diff --git a/minishell b/minishell deleted file mode 100755 index 930416b..0000000 --- a/minishell +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# Minimal Shell -# Use whenever a user should be able to launch a shell, -# but not to execute commands. -# -# Copyright (c) 2013-2015 Malte Bublitz. -# All rights reserved. -# -# Licensed under the terms of the 2-clause BSD license. -# See LICENSE for details. -# - -import platform -import os -import sys -import getpass - -os.chdir(os.path.dirname(sys.argv[0])) - -import bbs_env -import bofh - -def getuser(): - return "doctorwho" - -def login(prompt1="login: ", prompt2="Password: "): - login_data = ["", ""] - while len(login_data[0]) < 2: - login_data[0] = input(prompt1) - - login_data[1] = getpass.getpass(prompt2) - - return login_data - -def main(): - env = bbs_env.BBSFakeUserEnv() - commands_allowed = ( - "", - "exit", - "logout", - "help", - "whoami", - "id", - "hostname", - "pwd", - "uname", - "clear", - "sry" - ) - command = "" - - # Log in - env._user = login()[0] - env.setHideRealUname(True) - - print("\nWelcome on "+env.getNode()+", "+env.getUser()+"!\n") - - try: - while command != "exit": - print("$ ",end="") - try: - command = input() - - except KeyboardInterrupt: - print("") - continue - - if command == "logout" or command == "exit": - command = "exit" - - elif command == "help": - print("""Minimal Shell Help -Commands: - whoami - id - hostname - pwd - uname - clear - help - logout/exit -""") - elif command == "whoami": - if not env.getUser() in ["doctor", "doctorwho", "doctor_who"]: - print(env.getUser()) - else: - #print("I am the Doctor!") - print(env.getName()) - print("") - print("I should behave politely, so maybe excuse for") - print("future mistakes with \"sry\" (Yes, an easter egg!)") - print("") - - elif command == "id": - print("uid=42(" + env.getUser() + ") gid=100(users) groups=42(" + env.getUser() + "),9999(telnet)") - - elif command == "hostname": - print(env.getNode()) - - elif command == "pwd": - # print("/usr/home/"+getuser()) - print(env.getHome()) - - elif command == "uname": - print(env.getUName()) - - elif command == "clear": - ret_code = os.system("clear") - - elif command == "sry" or command == "bofh": - print(" "+bofh.get_excuse()) - - #elif not command in commands_allowed: - # print("-minishell: "+command.split(" ")[0]+": Command not found.") - elif len(command) > 0: - print("-minishell: "+command.split(" ")[0]+": Command not found.") - - except EOFError: - print("") - - print("Good bye.") - -if __name__ == "__main__": - main() - diff --git a/my_daemon2.py b/my_daemon2.py new file mode 100644 index 0000000..7fcb129 --- /dev/null +++ b/my_daemon2.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python + +import sys, time +from daemon import Daemon + +class MyDaemon(Daemon): + def run(self): + while True: + time.sleep(1) + +if __name__ == "__main__": + daemon = MyDaemon('/tmp/daemon-example.pid') + if len(sys.argv) == 2: + if 'start' == sys.argv[1]: + daemon.start() + elif 'stop' == sys.argv[1]: + daemon.stop() + elif 'restart' == sys.argv[1]: + daemon.restart() + else: + print "Unknown command" + sys.exit(2) + sys.exit(0) + else: + print "usage: %s start|stop|restart" % sys.argv[0] + sys.exit(2) \ No newline at end of file diff --git a/qotd b/qotd new file mode 100755 index 0000000..f9cd576 --- /dev/null +++ b/qotd @@ -0,0 +1,47 @@ +#!/bin/sh +# +# 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 + diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..32f307a --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,6 @@ +# requirements-dev.txt + +-r requirements.txt + +flake8 + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..6d2a675 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +# requirements.txt + +# bbs.mfingerd +pickleDB diff --git a/spandau.fingerinfo.db b/spandau.fingerinfo.db new file mode 100644 index 0000000..803fe73 --- /dev/null +++ b/spandau.fingerinfo.db @@ -0,0 +1 @@ +{"@": "This is spandau.rolltreppe3.de.\nTry:\n\tfinger ip@spandau.rolltreppe3.de\n\tfinger myip@spandau.rolltreppe3.de\n\tfinger malte70@spandau.rolltreppe3.de\n", "rt3x": "%%LOGO%%", "stardustdestruktor": "Full name: Timo K\u00f6nig\nTwitter..: *hidden*\nEMail....: *hidden*\nWeb......: https://tmkng.de\nWork.....: https://rolltreppe3.de", "r3": "%%LOGO%%", "ip": "%%IP%%", "malte": "Lookup malte70 instead.", "hostname": "%%FQDN%%", "fqdn": "%%FQDN%%", "rolltreppe3": "%%LOGO%%", "404": "The requested user does not exist.", "myip": "Your IP: %%IP%%\nYour Hostname: %%FQDN%%", "aribor": "Lookup malte70 instead.", "malte70": "Full name: Malte Bublitz\nTwitter..: @malte70\nEMail....: malte@rolltreppe3.de\nWeb......: https://malte70.de\nWork.....: https://rolltreppe3.de\nXMPP.....: malte.bublitz@riseup.net", "bofh": "%%BOFH%%", "timo": "Lookup stardustdestruktor instead.", "aribor42": "Lookup malte70 instead."} \ No newline at end of file diff --git a/test.py b/test.py new file mode 100644 index 0000000..97355aa --- /dev/null +++ b/test.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- + +import pickledb + +db = pickledb.load("fingerinfo.db", False) + +UserInfo = { + "@": """This is spandau.rolltreppe3.de. +Try: + finger ip@spandau.rolltreppe3.de + finger myip@spandau.rolltreppe3.de + finger malte70@spandau.rolltreppe3.de +""", + "404": "The requested user does not exist.", + "malte": "Lookup malte70 instead.", + "aribor": "Lookup malte70 instead.", + "aribor42": "Lookup malte70 instead.", + "malte70": """Full name: Malte Bublitz +Twitter..: @malte70 +EMail....: malte@rolltreppe3.de +Web......: https://malte70.de +Work.....: https://rolltreppe3.de +XMPP.....: malte.bublitz@riseup.net""", + "timo": "Lookup stardustdestruktor instead.", + "stardustdestruktor": """Full name: Timo König +Twitter..: *hidden* +EMail....: *hidden* +Web......: https://tmkng.de +Work.....: https://rolltreppe3.de""", + "rolltreppe3": "%%LOGO%%", + "r3": "%%LOGO%%", + "rt3x": "%%LOGO%%", + "ip": "%%IP%%", + "fqdn": "%%FQDN%%", + "hostname": "%%FQDN%%", + #"john": "John Doe", + "myip": """Your IP: %%IP%% +Your Hostname: %%FQDN%%""", + "bofh": "%%BOFH%%" +} +import pprint;print "--> UserInfo";pprint.pprint(UserInfo) + +for k in UserInfo.keys(): + if not db.exists(k): + print "Adding UserInfo[\""+k+"\"] to pickledb" + db.set(k, UserInfo[k]) + else: + print "Skipping \""+k+"\"" + +db.dump()