{ "info": { "author": "Ian Epperson", "author_email": "ian@epperson.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Environment :: Other Environment", "Intended Audience :: Developers", "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)", "Operating System :: OS Independent", "Programming Language :: Python", "Topic :: Communications", "Topic :: Communications :: BBS", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Shells", "Topic :: Terminals", "Topic :: Terminals :: Telnet" ], "description": "telnetsrvlib\n============\n\nTelnet server using gevent or threading.\n\nCopied from http://pytelnetsrvlib.sourceforge.net/\nand modified to support gevent, better input handling, clean asynchronous messages and much more.\nLicensed under the LGPL, as per the SourceForge notes.\n\nThis library allows you to easily create a Telnet server, powered by your Python code.\nThe library negotiates with a Telnet client, parses commands, provides an automated \nhelp command, optionally provides login queries, then allows you to define your own\ncommands.\n\nYou use the library to create your own handler, then pass that handler to a StreamServer\nor TCPServer to perform the actual connection tasks.\n\nThis library includes two flavors of the server handler, one uses separate threads,\nthe other uses greenlets (green pseudo-threads) via gevent.\n\nThe threaded version uses a separate thread to process the input buffer and\nsemaphores reading and writing. The provided test server only handles a single\nconnection at a time.\n\nThe green version moves the input buffer processing into a greenlet to allow \ncooperative multi-processing. This results in significantly less memory usage\nand nearly no idle processing. The provided test server handles a large number of connections.\n\n\nInstall\n-------\n\ntelnetsrv is available through the Cheeseshop. You can use easy_install or pip to perform the installation.\n\n:: \n\n easy_install telnetsrv\n\nor\n\n::\n\n pip install telnetsrv\n\nNote that there are no dependancies defined, but if you want to use the green version, you must also install gevent.\n\nTo Use\n------\n\nImport the ``TelnetHandler`` base class and ``command`` function decorator from either the green class or threaded class, \nthen subclass ``TelnetHandler`` to add your own commands which are methods decorated with ``@command``. \n\nThreaded\n++++++++\n\n.. code:: python\n\n from telnetsrv.threaded import TelnetHandler, command\n class MyHandler(TelnetHandler):\n ...\n\nGreen\n+++++\n\n.. code:: python\n\n from telnetsrv.green import TelnetHandler, command\n class MyHandler(TelnetHandler):\n ...\n\nAdding Commands\n---------------\n\nCommands can be defined by using the ``command`` function decorator.\n\n.. code:: python\n\n @command('echo')\n def command_echo(self, params):\n ...\n\nOld Style\n+++++++++\n\nCommands can also be defined by prefixing any method with \"cmd\". For example, \nthis also creates an ``echo`` command:\n\n.. code:: python\n\n def cmdECHO(self, params):\n ...\n\n*This method is less flexible and may not be supported in future versions.*\n\nCommand Parameters\n++++++++++++++++++\n\nAny command parameters will be passed to this function automatically. The parameters are\ncontained in a list. The user input is parsed similar to the way Bash parses text: space delimited,\nquoted parameters are kept together and default behavior can be modified with the ``\\`` character. \nIf you need to access the raw text input, inspect the self.input.raw variable.\n\n::\n\n Telnet Server> echo 1 \"2 3\"\n\n.. code:: python\n\n params == ['1', '2 3']\n self.input.raw == 'echo 1 \"2 3\"\\n'\n\n::\n\n Telnet Server> echo 1 \\\n ... 2 \"3\n ... 4\" \"5\\\n ... 6\"\n \n.. code:: python\n\n params == ['1', '2', '3\\n4', '56']\n\n::\n\n Telnet Server> echo 1\\ 2\n \n.. code:: python\n\n params == ['1 2']\n\nCommand Help Text\n+++++++++++++++++\n\nThe command's docstring is used for generating the console help information, and must be formatted\nwith at least 3 lines:\n\n- Line 0: Command parameter(s) if any. (Can be blank line)\n- Line 1: Short descriptive text. (Mandatory)\n- Line 2+: Long descriptive text. (Can be blank line)\n\nIf there is no line 2, line 1 will be used for the long description as well.\n\n.. code:: python\n\n @command('echo')\n def command_echo(self, params):\n '''\n Echo text back to the console.\n This command simply echos the provided text\n back to the console.\n '''\n pass\n\n\n::\n\n Telnet Server> help\n ? [] - Display help\n BYE - Exit the command shell\n ECHO - Echo text back to the console.\n ...\n\n\n Telnet Server> help echo\n ECHO \n\n This command simply echos the provided text\n back to the console.\n Telnet Server>\n\n\nCommand Aliases\n+++++++++++++++\n\nTo create an alias for the new command, set the method's name to a list:\n\n.. code:: python\n\n @command(['echo', 'copy'])\n def command_echo(self, params):\n ...\n\nThe decorator may be stacked, which adds each list to the aliases:\n\n.. code:: python\n\n @command('echo')\n @command(['copy', 'repeat'])\n @command('ditto')\n def command_echo(self, params):\n ...\n\n\n\nHidden Commands\n+++++++++++++++\n\nTo hide the command (and any alias for that command) from the help text output, pass in hidden=True to the decorator:\n\n.. code:: python\n\n @command('echo', hidden=True)\n def command_echo(self, params):\n ...\n\nThe command will not show when the user invokes ``help`` by itself, but the detailed help text will show if\nthe user invokes ``help echo``.\n\nWhen stacking decorators, any one of the stack may define the hidden parameter to hide the command.\n\nConsole Information\n-------------------\n\nThese will be provided for inspection.\n\n``TERM``\n String ID describing the currently connected terminal\n \n``username``\n Set after authentication succeeds, name of the logged in user.\n If no authentication was requested, will be ``None``.\n \n``history``\n List containing the command history. This can be manipulated directly.\n \n\n.. code:: python\n\n @command('info')\n def command_info(self, params):\n '''\n Provides some information about the current terminal.\n '''\n self.writeresponse( \"Username: %s, terminal type: %s\" % (self.username, self.TERM) )\n self.writeresponse( \"Command history:\" )\n for c in self.history:\n self.writeresponse(\" %r\" % c)\n\n\nConsole Communication\n---------------------\n\nSend Text to the Client\n+++++++++++++++++++++++\n \nLower level functions:\n\n``self.writeline( TEXT )``\n\n``self.write( TEXT )``\n\nHigher level functions:\n\n``self.writemessage( TEXT )`` - for clean, asynchronous writing. Any interrupted input is rebuilt.\n\n``self.writeresponse( TEXT )`` - to emit a line of expected output\n\n``self.writeerror( TEXT )`` - to emit error messages\n\nThe writemessage method is intended to send messages to the console without\ninterrupting any current input. If the user has entered text at the prompt, \nthe prompt and text will be seamlessly regenerated following the message. \nIt is ideal for asynchronous messages that aren't generated from the direct user input.\n\nReceive Text from the Client\n++++++++++++++++++++++++++++\n\n``self.readline( prompt=TEXT )``\n\nSetting the prompt is important to recreate the user input following a ``writemessage``\ninterruption.\n\nWhen requesting sensative information from the user (such as requesting a password) the input should\nnot be shown nor should it have access to or be written to the command history. ``readline`` accepts\ntwo optional parameters to control this, ``echo`` and ``user_history``.\n\n``self.readline( prompt=TEXT, echo=False, use_history=False )``\n\n\nHandler Options\n---------------\n\nOverride these class members to change the handler's behavior.\n\n``logging``\n Default: pass\n\n``PROMPT``\n Default: ``\"Telnet Server> \"``\n \n``CONTINUE_PROMPT``\n Default: ``\"... \"``\n \n``WELCOME``\n Displayed after a successful connection, after the username/password is accepted, if configured.\n \n Default: ``\"You have connected to the telnet server.\"``\n\n``session_start(self)``\n Called after the ``WELCOME`` text is displayed.\n \n Default: pass\n \n``session_end(self)``\n Called after the console is disconnected.\n \n Default: pass\n \n``authCallback(self, username, password)`` \n Reference to authentication function. If\n this is not defined, no username or password is requested. Should\n raise an exception if authentication fails\n \n Default: None\n\n``authNeedUser`` \n Should a username be requested?\n \n Default: ``False``\n\n``authNeedPass``\n Should a password be requested?\n \n Default: ``False``\n\n\nHandler Display Modification\n----------------------------\n\nIf you want to change how the output is displayed, override one or all of the\nwrite classes. Make sure you call back to the base class when doing so.\nThis is a good way to provide color to your console by using ANSI color commands.\nSee http://en.wikipedia.org/wiki/ANSI_escape_code\n\n- writemessage( TEXT ) \n- writeresponse( TEXT ) \n- writeerror( TEXT ) \n\n.. code:: python\n\n def writeerror(self, text):\n '''Write errors in red'''\n TelnetHandler.writeerror(self, \"\\x1b[91m%s\\x1b[0m\" % text )\n\nServing the Handler\n-------------------\n\nNow you have a shiny new handler class, but it doesn't serve itself - it must be called\nfrom an appropriate server. The server will create an instance of the TelnetHandler class\nfor each new connection. The handler class will work with either a gevent StreamServer instance\n(for the green version) or with a SocketServer.TCPServer instance (for the threaded version).\n\nThreaded\n++++++++\n\n.. code:: python\n\n import SocketServer\n class TelnetServer(SocketServer.TCPServer):\n allow_reuse_address = True\n \n server = TelnetServer((\"0.0.0.0\", 8023), MyHandler)\n server.serve_forever()\n\nGreen\n+++++\n\nThe TelnetHandler class includes a streamserver_handle class method to translate the \nrequired fields from a StreamServer, allowing use with the gevent StreamServer (and possibly\nothers).\n\n.. code:: python\n\n import gevent.server\n server = gevent.server.StreamServer((\"\", 8023), MyHandler.streamserver_handle)\n server.server_forever()\n\n\nShort Example\n-------------\n\n.. code:: python\n\n import gevent, gevent.server\n from telnetsrv.green import TelnetHandler, command\n \n class MyTelnetHandler(TelnetHandler):\n WELCOME = \"Welcome to my server.\"\n \n @command(['echo', 'copy', 'repeat'])\n def command_echo(self, params):\n '''\n Echo text back to the console.\n \n '''\n self.writeresponse( ' '.join(params) )\n \n @command('timer')\n def command_timer(self, params):\n '''