Created
January 9, 2023 16:57
-
-
Save ryanwinchester/7266e8c1ad21afa45e45f0a658d86612 to your computer and use it in GitHub Desktop.
Elixir (clunky) Telnet Client
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule TelnetClient do | |
use GenServer | |
require Logger | |
@doc """ | |
Starts a connection to the telnet server. | |
""" | |
def start_link({host, port}) do | |
GenServer.start_link(__MODULE__, {host, port}, name: __MODULE__) | |
end | |
@doc """ | |
Log in to the telnet server. | |
""" | |
@spec login(iodata(), iodata()) :: :ok | |
def login(user, pass) do | |
GenServer.cast(__MODULE__, {:login, user, pass}) | |
end | |
@doc """ | |
Send a message to the telnet server. | |
""" | |
@spec send_message(iodata()) :: :ok | |
def send_message(message) do | |
GenServer.cast(__MODULE__, {:send, to_charlist(message)}) | |
end | |
@doc """ | |
Quits the telnet client. | |
""" | |
@spec quit() :: :ok | |
def quit do | |
GenServer.stop(__MODULE__, :normal) | |
end | |
## Callbacks | |
@impl GenServer | |
def init({host, port}) do | |
{:ok, socket} = :gen_tcp.connect(to_charlist(host), port, []) | |
{:ok, %{state: :connected, socket: socket, login: nil}} | |
end | |
@impl GenServer | |
def handle_cast({:login, user, pass}, state) do | |
send_message(user) | |
{:noreply, %{state | state: :login, login: {user, pass}}} | |
end | |
@impl GenServer | |
def handle_call({:send, msg}, _from, %{state: :login} = state) do | |
{:reply, {:error, :not_logged_in}, state} | |
end | |
def handle_call({:send, msg}, %{state: :ready, socket: socket} = state) do | |
:ok = :gen_tcp.send(socket, [msg, '\r\n']) | |
{:noreply, state} | |
end | |
@impl GenServer | |
def handle_info({:tcp, _socket, 'user\r\n'}, %{state: :login} = state) do | |
Logger.debug("USER ACCEPTED") | |
{:noreply, state} | |
end | |
def handle_info({:tcp, _socket, 'user\r\nPassword: '}, %{state: :login, login: {_user, pass}} = state) do | |
Logger.debug("SENDING PASS 1") | |
send_message(pass) | |
{:noreply, state} | |
end | |
def handle_info({:tcp, _socket, 'Password: '}, %{state: :login, login: {_user, pass}} = state) do | |
Logger.debug("SENDING PASS 2") | |
send_message(pass) | |
{:noreply, state} | |
end | |
def handle_info({:tcp, _socket, message}, %{state: :login} = state) do | |
message = to_string(message) | |
cond do | |
String.ends_with?(message, ":~$ \e[6n") -> | |
Logger.debug("LOGGED IN") | |
{:noreply, %{state | state: :ready, login: nil}} | |
true -> | |
IO.inspect(message) | |
{:noreply, state} | |
end | |
end | |
def handle_info({:tcp, _socket, msg}, state) do | |
Logger.debug("SERVER: #{msg}") | |
IO.inspect(msg) | |
{:noreply, state} | |
end | |
def handle_info({:tcp_closed, _socket}, state) do | |
Logger.debug("Closing TCP and shutting down") | |
{:stop, :normal, state} | |
end | |
def handle_info(msg, state) do | |
Logger.debug("HUH?") | |
Logger.debug(inspect(msg)) | |
{:noreply, state} | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment