pepoとネットワークを語ろう

40年前からこれまでとこれからのネットワークを語る

telnetクライアントへの道その6

2009-08-06 19:31:58 | Linux

LinuxやFreeBSDへtelnetプロトコルでloginできたところで、manでマニュアルを見てみよう

[pepo1@~]$ man ls

 

LS(1)                            User Commands                           LS(1)

NAME
       ls - list directory contents

SYNOPSIS
       ls [OPTION]... [FILE]...

DESCRIPTION
       List  information  about  the FILEs (the current directory by default).
       Sort entries alphabetically if none of -cftuvSUX nor --sort.

       Mandatory arguments to long options are  mandatory  for  short  options
       too.

       -a, --all
              do not ignore entries starting with .

: ←カーソルがこの位置に表示してしまう・・正解は画面の最下段に表示
              do not list implied . and ..

       --author
              with -l, print the author of each file
中略

直ぐに分かる事なのだが、↓↑でmanualの前後の表示をさせようとするが、まともに表示ない

理由は現在の端末の画面サイズがtelnetサーバ側へ伝わっていないからだ 

と言うことで、以下のシーケンスのようにサーバへWill Negotiate About Window Sizeを送信、応答を待って現在の端末Window Sizeを取得しサーバへ送出するようにします

クライアント→サーバ
    Command: Will Negotiate About Window Size
サーバ→クライアント
    Command: Do Negotiate About Window Size
クライアント→サーバ
    Suboption Begin: Negotiate About Window Size
    Command: Suboption End

実際の処理は以下ように

zmodem_check() { /* zmodem check & telnet option */
  int chh;
  chh = ch & 0377;
  ch3 = chh;
  if ( iac_step_flag != 0 ) {
    if ( iac_step_flag == 1 ) {
      dont_flag = do_flag = will_flag = 0;
      iac_step_flag++;
      switch(chh) {
        case DONT:
          dont_flag = 1;
          break;
        case WILL:
          will_flag = 1;
          break;
        case DO:
          do_flag = 1;
          break;
        case SB:
          sb_flag = 1;
          break;
      }
      return;
    }
    if ( iac_step_flag == 2 ) {
      iac_step_flag = 0;
      display_flag = 1;
      switch(chh) {
        case TELOPT_ECHO:
          if (dont_flag == 1) display_flag = 0;
          if (do_flag == 1) {
            display_flag = 1;
            send_wont_char(ch3);
          }
          if (will_flag == 1) {
            display_flag = 1;
          }
          break;
        case TELOPT_ENCRYPT:
          if (do_flag == 1) send_wont_char(ch3);
          if (will_flag == 1) send_dont_char(ch3);
          break;
        case TELOPT_AUTHENTICATION:
          if (do_flag == 1) send_wont_char(ch3);
          if (will_flag == 1) send_dont_char(ch3);
          break;
        case TELOPT_STATUS:
          if (will_flag == 1 || do_flag == 1) send_wont_char(ch3);
          if (dont_flag == 1) send_dont_char(ch3);
          break;
        case TELOPT_NAWS:
          if (send_window_flag == 1 && do_flag == 1) {
            send_window_size();
          }
          break;
        case TELOPT_TTYPE:
          if (send_ttype_flag == 1 && sb_flag == 1) {
            send_ttype();
          }
          break;
        default:
          if (will_flag == 1) send_dont_char(ch3);
          if (do_flag == 1) send_wont_char(ch3);
          if (send_window_flag == 0) {
            send_will_window();
            send_window_flag = 1;
            send_will_ttype();
            send_ttype_flag = 1;
          }
          break;
      }
      return;
    }
  }

send_will_window() {
  sprintf(f3,"%c%c%c",IAC,WILL,TELOPT_NAWS);
  write(fp2,&f3,strlen(f3));
  return;
}

 

現在の端末ウィンドサイズを取得してサーバへ送信

send_window_size() {
  int dummy = 0;
//  setupterm(MY_TTYPE, fileno(stdout), (int *) 0);
  setupterm(NULL, fileno(stdout), (int *) 0);
  my_height = tigetnum("lines");
  my_width = tigetnum("cols");
  sprintf(f3,"%c%c%c%c%c%c%c%c%c",IAC,SB,TELOPT_NAWS,dummy,my_width,dummy,my_height,IAC,SE);
  write(fp2,&f3,9);
  return;
}

pepo