ろうとるがPythonを扱う、、続き（telnetlib, expect()）

# Pythonでtelnet
[こちらの記事「ろうとるがPythonでWindowsプログラムをつくる」](https://qiita.com/infinite1oop/items/5b1c5656303eea0c66c1)の関連で、sshではなく、telnetを扱う機会があった。Pythonの[telnetlib](https://docs.python.org/ja/3/library/telnetlib.html)を利用し、[Telnet.expect()](https://docs.python.org/ja/3/library/telnetlib.html#telnetlib.Telnet.expect)のサンプルとして、日本語で記載されたものがほとんど見つからないので、ここに記録する。

## telnetサーバーへのログイン
やることは単純。telnetサーバーへのログインスクリプトをPythonで実現する。

### telnetサーバー
テストで用いたtelnetサーバーは、「HK-TELNET-SERVER」。[ここ](https://sourceforge.net/projects/hk-telnet-server/)からダウンロードできる。起動すると下記のようになる。
![hk telnet server.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/583d1a6b-8e92-1588-c083-bb4e61e3e42e.png)
ユーザーを作成（CREATE USER）し、STARTする。

### ソースコード
importなど。
```python
import telnetlib
import logging
import logging.handlers
from datetime import datetime
import time
import getpass

SUCCESS = 0
FAILURE = 1
```
パスワード入力（見えないように）のために、「getpass」が使われている。

telnetサーバーへの接続。
```python
### Connect to Server
def connect_srv():
    ret = FAILURE
    log.debug("== connect_srv ==")
    dst = input("Enter IP address: ")
    log.debug(f"IP address:{dst}")
    try:
        tn = telnetlib.Telnet(dst, 23, 3)
    except IOError:
        print('Connection Error.')
        log.debug('Connection Error.')
        return ret, 1
    except Exception:
        print('Other Erros in Open.')
        log.debug('Other Errors in Open')
        return ret, 1

    while True:
        id = input("Enter ID: ")
        key = getpass.getpass()
        log.debug(f"Input - User:{id}  Password:{key}")
        tn.read_until(b"Username")
        tn.read_very_eager();
        log.debug('-- Send Username --')
        tn.write(id.encode('ascii') + b"\r\n")
        tn.read_until(b"Password")
        tn.read_very_eager();
        log.debug('-- Send Password --')
        tn.write(key.encode('ascii') + b"\r\n")
        time.sleep(1)
        index, match, text = tn.expect([b">", b"Invalid"], 3) # ここがポイント
        log.debug(text.decode() + "\r\n")
        if index == 0:
            #log.debug('Connected.')
            print('Connected.')
            ret = SUCCESS
            break
        elif index == 1:
            print('Authentication Error. Please retry.')
            log.debug('Authentication Error. Please retry.' + '\r\n')
            time.sleep(1)
            # retry
        else:
            print('Other Errors.')
            log.debug('Other Errors.')
            tn.close()
            break
        #end while        

    tn.read_very_eager();
    return ret, tn   
### End of connect_src()
```
「index, match, text = tn.expect([b">", b"Invalid"], 3) 」がポイント。用いたtelnetサーバーは、ログイン成功時のプロンプトの最後の文字は「>」となり、ログイン失敗時は「Invalid」を返すため、リストを用いて双方を待ち受ける。「3」はタイムアウト（秒）。「>」を受信すればindexは「0」となり、「Invalid」を受信すればindexは「1」となる。それによって、処理を分ける。ここでは、「Invalid」（認証エラー）時には、再度IDとパスワードとの入力に戻る。

メイン部分。
```python
# ログファイル
log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
fh = logging.FileHandler('{:LogT-%Y%m%d-%H%M%S}.log'.format(datetime.now()))
log.addHandler(fh)

log.debug('=== Start ===')

# telnetサーバーへの接続
ret, tns = connect_srv()
if ret == SUCCESS:
    print('>> Can do commmands. <<')
    # Do something by using tns like sending commands
    tns.close()

log.debug('=== End ===')
```
ログファイル設定、telnetサーバーへの接続、成功時のメッセージ出力。

## テスト
```
$ python このファイル.py
```

### ログファイル
#### 接続エラー
```
=== Start ===
== connect_srv ==
IP address:192.168.250.4
Connection Error.
=== End ===
```

#### 認証失敗およびリトライ後の成功
```
=== Start ===
== connect_srv ==
IP address:192.168.250.2
Input - User:test  Password:test
-- Send Username --
-- Send Password --
****

Invalid

Authentication Error. Please retry.

Input - User:test  Password:Himitsu
-- Send Username --
-- Send Password --
****

 [ USERNAME = test ] YOUR IP ADDRESS : 192.168.250.1
 Welcome to Hadi Kiamarsi TELNET Server.

TELNET # H:\Software\hk-telnet-server-version-3-0-1\>

=== End ===
```
期待どおり。

### 画面出力
#### 接続エラー
```
Enter IP address: 192.168.250.4
Connection Error.
```

#### 認証失敗および成功
```
Enter IP address: 192.168.250.2
Enter ID: test
Password: 
Authentication Error. Please retry.
Enter ID: test
Password: 
Connected.
>> Can do commmands. <<
```

## その他
Windows10でのtelnetの情報は、[ここ](https://techwiser.com/enable-telnet-server-in-windows-10/)などに見つかる。

EOF