#require "netclient";;
(* This is an example for the telnet client. The function below
* connects with localhost, and logs the user in. It simulates
* keyboard typing for the username and the password, and finally
* starts the command "ls".
*
* The example may or may not work with your version of telnetd.
* The program expects the string "login" before the user name must
* be typed in, and it expects the string "password" before the password
* must be entered. Furthermore, a new command line is recognized
* by the characters >, # or $.
*)
open Telnet_client;;
type state =
Start (* just connected *)
| Username_sent (* the user name has been sent to the server *)
| Password_sent (* the password has been sent to the server *)
| Command_sent (* the command to execute has been sent to the server *)
;;
let login_re = Str.regexp_case_fold "\\(.\\|\n\\)*login";;
let passwd_re = Str.regexp_case_fold "\\(.\\|\n\\)*password";;
let cmd_re = Str.regexp "\\(.\\|\n\\)*[>$#]";;
let login_and_ls username password =
(* Create a new event system, and the telnet session. We need the
* event system only to call Unixqueue.once.
*)
let esys = Unixqueue.create_unix_event_system() in
let session = new telnet_session in
let state = ref Start in
let send_string s new_state =
(* Emulate keyboard typing of the string s. Between the characters there
* is a delay of 0.1 seconds.
* When the string has been completely sent, change the state to
* new_state.
*)
let t = ref 0.1 in
let g = Unixqueue.new_group esys in
let l = String.length s in
for i = 0 to l - 1 do
let c = s.[i] in
let cs = if c = '\n' then "\r\n" else String.make 1 c in
(* Do the function !t seconds in the future: *)
Unixqueue.once esys g !t
(fun () ->
Queue.add (Telnet_data cs) session#output_queue;
(* We must call update because we are outside of the regular
* callback function. Otherwise the session object would not
* notice that the queue has been extended.
*)
session # update();
if i = l-1 then
state := new_state
);
t := !t +. 0.1;
done
in
let got_input is_urgent =
(* This is the callback function. The session object calls it when
* telnet commands have been added to the input queue.
*)
let oq = session # output_queue in
let iq = session # input_queue in
(* Process the input queue command by command: *)
while Queue.length iq > 0 do
let cmd = Queue.take iq in
match cmd with
| Telnet_will _
| Telnet_wont _
| Telnet_do _
| Telnet_dont _ ->
(* These are the commands used to negotiate the telnet options.
* The session object can do it for you.
*)
session # process_option_command cmd
| Telnet_data s ->
(* The data string s has been received. *)
( match !state with
Start ->
if Str.string_match login_re s 0 then begin
(* Assume the host wants our username, and send it. *)
send_string (username ^ "\n") Username_sent
end
| Username_sent ->
if Str.string_match passwd_re s 0 then begin
(* Assume the host wants our password, and send it. *)
send_string (password ^ "\n") Password_sent;
end
| Password_sent ->
if Str.string_match cmd_re s 0 then begin
(* Assume the host wants the command: *)
(* Disable now echoing: *)
session # disable_remote_option Telnet_echo;
(* Send the command "ls" 0.1 seconds in the future.
* This way Telnet_echo can be disabled in the
* meantime.
*)
let g = Unixqueue.new_group esys in
Unixqueue.once esys g 0.1
(fun () ->
Queue.add (Telnet_data("ls\n")) oq;
session # update();
state := Command_sent
)
end;
| Command_sent ->
print_string s;
(* Again the command-line prompt? *)
if Str.string_match cmd_re s 0 then
Queue.add Telnet_eof oq; (* terminate the session *)
)
| Telnet_eof ->
()
| _ ->
(* Unexpected command. *)
()
done
in
session # set_event_system esys;
let opts = session # get_options in
session # set_options { opts with
verbose_connection = false;
verbose_input = false;
verbose_output = false };
session # set_connection (Telnet_connect("localhost", 23));
session # enable_remote_option Telnet_suppress_GA;
session # enable_remote_option Telnet_echo;
session # set_callback got_input;
session # attach();
session # run()
;;