Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bin/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# bin/ package — shell callbacks for telnetlib3 examples.
33 changes: 6 additions & 27 deletions bin/client_wargame.py
Original file line number Diff line number Diff line change
@@ -1,49 +1,28 @@
#!/usr/bin/env python
"""
Telnet client that plays the "war game" against a server.
Shell callback: telnet client that auto-answers the "war game".

This example connects to a telnet server and automatically answers
any question with 'y'. Run server_wargame.py first, then this client.
Run ``server_wargame`` first, then this client.

Example output::
Usage::

telnetlib3-client --shell=bin.client_wargame.shell localhost 6023

$ python client_wargame.py
Example output::

Would you like to play a game? y
They say the only way to win is to not play at all.
"""

# std imports
import asyncio

# local
import telnetlib3


async def shell(reader, writer):
"""Handle client session, auto-answering questions."""
while True:
# Read stream until '?' mark is found
outp = await reader.read(1024)
if not outp:
# End of File
break
if "?" in outp:
# Reply to all questions with 'y'
writer.write("y\r\n")

# Display all server output
print(outp, flush=True, end="")

# EOF
print()


async def main():
"""Connect to the telnet server."""
_reader, writer = await telnetlib3.open_connection(host="localhost", port=6023, shell=shell)
await writer.protocol.waiter_closed


if __name__ == "__main__":
asyncio.run(main())
36 changes: 5 additions & 31 deletions bin/server_binary.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
#!/usr/bin/env python
"""
Telnet server using binary (raw bytes) mode.
Shell callback: binary (raw bytes) echo server.

This example demonstrates using ``encoding=False`` for a server that works
with raw bytes instead of Unicode strings. This is useful for protocol
bridging, binary data transfer, or custom protocols over telnet.
Usage::

When encoding is set (the default), the shell callback receives
``TelnetReaderUnicode`` and ``TelnetWriterUnicode``, which read and write
``str``. When ``encoding=False``, the shell receives ``TelnetReader`` and
``TelnetWriter``, which read and write ``bytes``.
telnetlib3-server --encoding=false --shell=bin.server_binary.shell

Run this server, then connect with: telnet localhost 6023
When ``encoding=False``, the shell receives ``TelnetReader`` and
``TelnetWriter``, which read and write ``bytes`` instead of ``str``.

Example session::

Expand All @@ -23,12 +18,6 @@
Connection closed by foreign host.
"""

# std imports
import asyncio

# local
import telnetlib3 # pylint: disable=cyclic-import


async def shell(reader, writer):
"""Echo client input back as hex bytes."""
Expand All @@ -41,18 +30,3 @@ async def shell(reader, writer):
writer.write(f"hex: {hex_str}\r\n".encode("ascii"))
await writer.drain()
writer.close()


async def main():
"""Start the telnet server in binary mode."""
server = await telnetlib3.create_server(
host="127.0.0.1", port=6023, shell=shell, encoding=False
)
print("Binary telnet server running on localhost:6023")
print("Connect with: telnet localhost 6023")
print("Press Ctrl+C to stop")
await server.wait_closed()


if __name__ == "__main__":
asyncio.run(main())
36 changes: 36 additions & 0 deletions bin/server_tls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""
Shell callback: TLS-encrypted echo server (TELNETS).

Generate a self-signed certificate for testing::

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem \
-days 365 -nodes -subj '/CN=localhost'

Usage::

telnetlib3-server --ssl-certfile cert.pem --ssl-keyfile key.pem \
--shell=bin.server_tls.shell

Connect with the telnetlib3 client::

telnetlib3-client --ssl --ssl-cafile cert.pem localhost 6023

Or with openssl::

openssl s_client -connect localhost:6023 -quiet
"""


async def shell(reader, writer):
"""Simple echo shell over TLS."""
writer.write("Welcome to the TLS echo server!\r\n")
await writer.drain()

while True:
data = await reader.read(256)
if not data:
break
writer.write(f"echo: {data}\r\n")
await writer.drain()

writer.close()
26 changes: 5 additions & 21 deletions bin/server_wait_for_negotiation.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
#!/usr/bin/env python
"""
Telnet server demonstrating wait_for() negotiation states.
Shell callback: wait for terminal negotiation states.

This example shows how to use writer.wait_for() to await specific
telnet option negotiation states before proceeding.
Usage::

telnetlib3-server --shell=bin.server_wait_for_negotiation.shell

The server waits for:

- NAWS (window size) to be negotiated
- TTYPE (terminal type) negotiation to complete
- BINARY mode (bidirectional)
Expand All @@ -14,9 +15,6 @@
# std imports
import asyncio

# local
import telnetlib3


async def shell(_reader, writer):
"""Handle client with explicit negotiation waits."""
Expand Down Expand Up @@ -44,17 +42,3 @@ async def shell(_reader, writer):
writer.write("\r\nNegotiation complete. Goodbye!\r\n")
await writer.drain()
writer.close()


async def main():
"""Start the telnet server."""
server = await telnetlib3.create_server(host="127.0.0.1", port=6023, shell=shell)
print("Negotiation demo server running on localhost:6023")
await server.wait_closed()


if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
print("\nServer stopped")
31 changes: 8 additions & 23 deletions bin/server_wargame.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
#!/usr/bin/env python
"""
Telnet server that offers a basic "war game" question.
Shell callback: simple "war game" question.

This example demonstrates a simple telnet server using asyncio.
Run this server, then connect with: telnet localhost 6023
Usage::

telnetlib3-server --shell=bin.server_wargame.shell

Then connect with::

telnet localhost 6023

Example session::

Expand All @@ -15,12 +19,6 @@
Connection closed by foreign host.
"""

# std imports
import asyncio

# local
import telnetlib3 # pylint: disable=cyclic-import


async def shell(reader, writer):
"""Handle a single client connection."""
Expand All @@ -31,16 +29,3 @@ async def shell(reader, writer):
writer.write("\r\nThey say the only way to win is to not play at all.\r\n")
await writer.drain()
writer.close()


async def main():
"""Start the telnet server."""
server = await telnetlib3.create_server(host="127.0.0.1", port=6023, shell=shell)
print("Telnet server running on localhost:6023")
print("Connect with: telnet localhost 6023")
print("Press Ctrl+C to stop")
await server.wait_closed()


if __name__ == "__main__":
asyncio.run(main())
4 changes: 2 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@
# built documents.
#
# The short X.Y version.
version = "2.5"
version = "2.6"

# The full version, including alpha/beta/rc tags.
release = "2.5.0" # keep in sync with pyproject.toml and telnetlib3/accessories.py !!
release = "2.6.0" # keep in sync with pyproject.toml and telnetlib3/accessories.py !!

# The language for content auto-generated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
Loading
Loading