TELNETクライアント(簡易版)

TELNETクライアントの簡易版です。オプション交渉は必要最低限ですが、通常のTELNETサーバーならば接続できると思います。

<制限事項>

  • Stabilizer ver3.00以降で実行してください。
  • Stabilizer がエスケープシーケンスの処理に対応していないため、完全なTELNETクライアントとして動作させるのには難があります。スクリプトのサンプルとしてのご利用にとどめてください。
-------------------------------------------------
-- TELNETクライアント(簡易版)
-------------------------------------------------
-- TELNETコマンド
IAC         = 255
DONT        = 254       -- 送り手は受け手にオプションを無効にさせたい。
DO          = 253       -- 送り手は受け手にオプションを有効にさせたい。
WONT        = 252       -- 送り手はオプションを無効にしたい。
WILL        = 251       -- 送り手はオプションを有効にしたい。
SB          = 250       -- サブオプション開始
SE          = 240       -- サブオプション終了

-- オプションID
OPT_ECHO    = 1         -- echo
OPT_GA      = 3         -- suppress go ahead
OPT_TYPE    = 24        -- terminal type

-- オプション交渉状態ステータス
STS_IDLE    = 0         -- アイドル状態
STS_IAC     = 1         -- IAC受信
STS_DONT    = 2         -- DONT受信
STS_DO      = 3         -- DO受信
STS_WONT    = 4         -- WONT受信
STS_WILL    = 5         -- WILL受信
STS_SB      = 6         -- サブオプション開始

-- TELNETステータス
TEL_NONE    = 0         -- 未接続
TEL_NEG     = 1         -- オプション交渉
TEL_ONLINE  = 2         -- TELNET接続中

-- 変数定義
local g_optsts   = STS_IDLE  -- オプション交渉状態ステータス
local g_telsts   = TEL_NONE  -- TELNETステータス
local g_connect  = false     -- 接続監視
local g_cur_echo             -- ローカルエコー設定

-------------------------------------------------
-- 受信ハンドラ
-------------------------------------------------
function rx_handler( buf, len )

    -- オプション交渉
    if g_telsts == TEL_NEG or g_telsts == TEL_NONE then
        do_negotiation( buf, len )
    end

    return 1
end

-------------------------------------------------
-- オプション交渉
-------------------------------------------------
function do_negotiation( buf, len )
    for i=1, len, 1 do
        local c = string.byte( buf, i )

        if g_optsts == STS_IDLE then
            if do_opt_idle( c ) then 
                break
        end

        elseif g_optsts == STS_IAC then
            do_opt_iac( c )

        elseif g_optsts == STS_DONT then
            do_opt_dont( c )

        elseif g_optsts == STS_DO then
            do_opt_do( c )

        elseif g_optsts == STS_WONT then
            do_opt_wont( c )

        elseif g_optsts == STS_WILL then
            do_opt_will( c )

        elseif g_optsts == STS_SB then
            if c == OPT_TYPE then
                do_opt_type( buf, i, len )
            end
        end
    end
end

-------------------------------------------------
-- アイドル時の処理
-------------------------------------------------
neg_buf = {}
neg_idx = 1
function do_opt_idle( c )
    if c == IAC then
        neg_idx = 1
        g_optsts = STS_IAC
    else
        if c == "l" then
            neg_idx = 1
        end

        neg_buf[ neg_idx ] = c
        neg_idx = neg_idx + 1

        if neg_idx >= 7 then
            -- login移行でオプション交渉終了
            if string.find( Tbl2Str( neg_buf ), "login" ) ~= nil then
                g_telsts = TEL_ONLINE
            else
                neg_idx = 1
            end
        end
    end

    return ( g_telsts == TEL_ONLINE )
end

-------------------------------------------------
-- IAC
-------------------------------------------------
function do_opt_iac( c )
    if c == DONT then
        g_optsts = STS_DONT
    elseif c == DO then
        g_optsts = STS_DO
    elseif c == WONT then
        g_optsts = STS_WONT
    elseif c == WILL then
        g_optsts = STS_WILL
    elseif c == SB then
        g_optsts = STS_SB
    else
        g_optsts = STS_IDLE
    end
end

-------------------------------------------------
-- DONT
-- DONTに対しては、OK(WONT)と応答しなければなりません。
-------------------------------------------------
function do_opt_dont( c )
    sendbuf = { IAC, WONT, c }
    SendData( sendbuf )
    g_optsts = STS_IDLE
end

-------------------------------------------------
-- DO
-------------------------------------------------
function do_opt_do( c )
    sendbuf = {}
    sendbuf[ 1 ] = IAC

    -- クライアントエコーはNO
    if c == OPT_ECHO then
        sendbuf[ 2 ] = WONT
    -- 進行抑止
    elseif c == OPT_GA then
        sendbuf[ 2 ] = WILL
    -- ターミナルタイプ
    elseif c == OPT_TYPE then
        sendbuf[ 2 ] = WILL
    -- その他はNO
    else
        sendbuf[ 2 ] = WONT
    end

    sendbuf[ 3 ] = c
    SendData( sendbuf )
    g_optsts = STS_IDLE
end

-------------------------------------------------
-- WONT
-- WONTに対しては、OK(DONT)と応答しなければなりません。
-------------------------------------------------
function do_opt_wont( c )
    sendbuf = { IAC, DONT, c }
    SendData( sendbuf )
    g_optsts = STS_IDLE
end

-------------------------------------------------
-- WILL
-------------------------------------------------
function do_opt_will( c )
    sendbuf = {}
    sendbuf[ 1 ] = IAC

    -- サーバーエコー
    if c == OPT_ECHO then
        sendbuf[ 2 ] = DO
    -- 進行抑止
    elseif c == OPT_GA then
        sendbuf[ 2 ] = DO
    -- その他はOK
    else
        sendbuf[ 2 ] = DO
    end

    sendbuf[ 3 ] = c
    SendData( sendbuf )
    g_optsts = STS_IDLE
end

-------------------------------------------------
-- ターミナルタイプ
-------------------------------------------------
function do_opt_type( buf, pos, len )
    if pos+3 <= len and
       string.byte( buf, pos+1 ) == 1 and
       string.byte( buf, pos+2 ) == IAC and
       string.byte( buf, pos+3 ) == SE then
        sendbuf = { IAC, SB, OPT_TYPE, 0, "IBMPC", IAC, SE }
        SendData( sendbuf )
        g_optsts = STS_IDLE
    end
end

-------------------------------------------------
-- 1秒タイマ(接続監視)
-------------------------------------------------
function timer_handler()
    connect = IsConnect( 0 )
    
    -- 未接続の場合
    if g_connect == false then
        if connect then
            g_connect = true

            -- オプション交渉へ移行
            g_telsts = TEL_NEG
            g_optsts = STS_IDLE
        --  DOut( "Connected.\n" )
        end

    -- 接続中
    else
        if connect == false then
            g_connect = false

            -- TELNETステータスリセット
            g_telsts = TEL_NONE
        --  DOut( "Disconnected.\n" )
        end
    end
end


-------------------------------------------------
-- 初期化
-------------------------------------------------
function init()
--  ShowMon( true )
--  ClrMon()

    local rtn = false

    -- 動作モードをTCPに設定
    run_mode = GetRunModeParam()
    if run_mode ~= 1 then
        rtn = false
        SetRunModeParam( 1, 3 )
    end

    -- TCPクライアントの設定確認
    mode, s_port, s_valid_ip, s_ip, c_port, c_ip, c_valid_lport, c_lport,
    c_valid_lip, c_lip = GetTcpParam( 0 )
    if mode ~= 1 then
        ShowMessageDlg( "TCPの動作はクライアントに設定してください。",
                        "ネットワーク設定エラー", false )
    elseif c_port ~= 23 then
        ShowMessageDlg( "接続先ポート番号を23に設定してください。",
                        "ネットワーク設定エラー", false )
    else
        rtn = true
    end

    return rtn
end

-------------------------------------------------
-- 終了処理
-------------------------------------------------
function exit_handler()
    CloseTcp( 0 )
    SetNetAutoCtrl( true )

    -- パラメータを元に戻す
    SetLocalEcho( g_cur_echo )
end

-------------------------------------------------
-- メイン
-------------------------------------------------
-- ローカルエコー状態取得
g_cur_echo = GetLocalEcho()

if init() then
    -- [オプション] - [送信] の設定で、入力文字送信あり、
    -- 入力後すぐに送信 に設定しておきます。

    -- 実行中は、ネットワーク自動制御を無効にします。
    SetNetAutoCtrl( false )

    -- 受信ハンドラ登録
    SetRxHandler( "rx_handler" )
    -- タイマハンドラ登録
    StartTimer( 1, 1000, "timer_handler" )
    -- 終了ハンドラ登録
    SetExitHandler( "exit_handler" )

    -- TCPは再オープンします。
    CloseTcp( 0 )
    Wait( 1000 )
    OpenTcp( 0 )
end