File: telnet.ml

package info (click to toggle)
netclient 0.90.4-3
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 1,228 kB
  • ctags: 809
  • sloc: ml: 6,369; sh: 495; makefile: 245
file content (141 lines) | stat: -rw-r--r-- 4,603 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#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()
;;