From 0666dd02983c5a7ad580a29d7d6deec1cbcd80b5 Mon Sep 17 00:00:00 2001 From: in2 Date: Fri, 8 Apr 2005 02:27:19 +0000 Subject: handle telnet protocol and enable NAWS (resize terminal) capability. SKIP_TELNET_CONTROL_SIGNAL can be disabled now. by piaip git-svn-id: http://opensvn.csie.org/pttbbs/trunk/pttbbs@2690 63ad8ddf-47c3-0310-b6dd-a9e9d9715204 --- include/proto.h | 1 + mbbsd/io.c | 112 ++++++++++++++++++++++++++++++++++++++++++++--------- mbbsd/mbbsd.c | 16 ++------ mbbsd/term.c | 28 ++++++++------ mbbsd/var.c | 1 + sample/pttbbs.conf | 3 +- 6 files changed, 119 insertions(+), 42 deletions(-) diff --git a/include/proto.h b/include/proto.h index 0671dd96..d0544240 100644 --- a/include/proto.h +++ b/include/proto.h @@ -671,6 +671,7 @@ int j_ticket_main(void); /* term */ void init_tty(void); int term_init(void); +void term_resize(int w, int h); void save_cursor(void); void restore_cursor(void); void do_move(int destcol, int destline); diff --git a/mbbsd/io.c b/mbbsd/io.c index fde21d3b..acbbe6f8 100644 --- a/mbbsd/io.c +++ b/mbbsd/io.c @@ -4,7 +4,7 @@ #define OBUFSIZE 2048 #define IBUFSIZE 128 -static char outbuf[OBUFSIZE], inbuf[IBUFSIZE]; +static unsigned char outbuf[OBUFSIZE], inbuf[IBUFSIZE]; static int obufsize = 0, ibufsize = 0; static int icurrchar = 0; @@ -187,7 +187,7 @@ dogetch(void) } #ifdef SKIP_TELNET_CONTROL_SIGNAL - } while( inbuf[0] == -1 ); + } while( inbuf[0] == IAC ); #endif ibufsize = len; icurrchar = 0; @@ -204,38 +204,114 @@ dogetch(void) currutmp->lastact = now; lastact = now; } - return inbuf[icurrchar++]; + return (unsigned char)inbuf[icurrchar++]; } +enum IAC_STATE { + IAC_NONE, + IAC_WAIT1, + IAC_WAIT_NAWS, + IAC_WAIT_NAWS_IAC, + IAC_WAIT_IAC_SE_1, + IAC_WAIT_IAC_SE_2, + IAC_ERROR +}; + static int water_which_flag = 0; int igetch(void) { - register int ch, mode = 0, last = 0; - while ((ch = dogetch())) { + register int ch, mode = 0, last = 0; + static int iac_state = IAC_NONE; + static unsigned char nawsbuf[4], inaws = 0; + while ((ch = dogetch()) >= 0) { + if(raw_connection) /* only process IAC in raw connection mode */ + switch (iac_state) { + case IAC_NONE: + if(ch == IAC) { + iac_state = IAC_WAIT1; + continue; + } + break; + case IAC_WAIT1: + if(ch == SB) + iac_state = IAC_WAIT_IAC_SE_1; + else + iac_state = IAC_NONE; + if(ch == AYT) { + redoscr(); + outmsg("我還活著喔"); + } + continue; + case IAC_WAIT_IAC_SE_1: + if(ch == IAC) + iac_state = IAC_WAIT_IAC_SE_2; + if(ch == TELOPT_NAWS) { + iac_state = IAC_WAIT_NAWS; + inaws = 0; + } + continue; + case IAC_WAIT_IAC_SE_2: + if(ch == SE) { + iac_state = IAC_NONE; + continue; + } + else + iac_state = IAC_WAIT_IAC_SE_1; + continue; + case IAC_WAIT_NAWS_IAC: + // when we're waiting for NAWS and an IAC comes, orz + iac_state = IAC_WAIT_NAWS; + if (ch == IAC) + nawsbuf[inaws-1] = IAC; + // else? i don't know how to handle sich situation + // there shall not be any other cases + continue; + case IAC_WAIT_NAWS: + nawsbuf[inaws++] = (unsigned char)ch; + if(ch == IAC) { + iac_state = IAC_WAIT_NAWS_IAC; + continue; + } + if(inaws == 4) { + int w = (nawsbuf[0] << 8) + nawsbuf[1]; + int h = (nawsbuf[2] << 8) + nawsbuf[3]; + iac_state = IAC_WAIT_IAC_SE_1; + term_resize(w, h); /* term_resize is safe */ + /* redoscr(); */ /* will not work as we want */ +#ifdef DEBUG + { + char buf[256]; + sprintf(buf, "[%dx%d]", w, h); + outmsg(buf); + } +#endif + iac_state = IAC_WAIT_IAC_SE_1; + } + continue; + } else if (ch == 0) /* in non-raw connection mode, ignore zero. */ + return 0; + if (mode == 0 && ch == KEY_ESC) // here is state machine for 2 bytes key - mode = 1; + mode = 1; else if (mode == 1) { /* Escape sequence */ if (ch == '[' || ch == 'O') mode = 2; else if (ch == '1' || ch == '4') - { mode = 3; last = ch; } - else - { + { mode = 3; last = ch; } + else { KEY_ESC_arg = ch; return KEY_ESC; - } + } } else if (mode == 2 && ch >= 'A' && ch <= 'D') /* Cursor key */ - return KEY_UP + (ch - 'A'); - else if (mode == 2 && ch >= '1' && ch <= '6') - { mode = 3; last = ch; } - else if (mode == 3 && ch == '~') { /* Ins Del Home End PgUp PgDn */ - return KEY_HOME + (last - '1'); + return KEY_UP + (ch - 'A'); + else if (mode == 2 && ch >= '1' && ch <= '6') + { mode = 3; last = ch; } + else if (mode == 3 && ch == '~') { /* Ins Del Home End PgUp PgDn */ + return KEY_HOME + (last - '1'); } else // here is switch for default keys - switch (ch) { - case IAC: - continue; + switch (ch) { // XXX: indent error #ifdef DEBUG case Ctrl('Q'):{ struct rusage ru; diff --git a/mbbsd/mbbsd.c b/mbbsd/mbbsd.c index 41b77e43..e54c0139 100644 --- a/mbbsd/mbbsd.c +++ b/mbbsd/mbbsd.c @@ -1139,6 +1139,8 @@ telnet_init(void) struct timeval to; unsigned char buf[64]; fd_set ReadSet, r; + + raw_connection = 1; FD_ZERO(&ReadSet); FD_SET(0, &ReadSet); @@ -1168,18 +1170,8 @@ telnet_init(void) bi += 3; w = GETB() << 8; w |= GETB(); h = GETB() << 8; h |= GETB(); - /* safer - // suggested by kcwu, a pity that we can't handle < 24. */ - h = MAX(24, MIN(100, h)); - w = MAX(80, MIN(200, w)); - if(buf[bi++] == IAC && buf[bi++] == SE) { - /* copied from term.c */ - t_lines = h; - t_columns = w; - scr_lns = t_lines; - b_lines = t_lines - 1; - p_lines = t_lines - 4; - } + if(buf[bi++] == IAC && buf[bi++] == SE) + term_resize(w, h); } } } diff --git a/mbbsd/term.c b/mbbsd/term.c index 94067e99..782d07b8 100644 --- a/mbbsd/term.c +++ b/mbbsd/term.c @@ -30,21 +30,27 @@ init_tty(void) #define TERMCOMSIZE (40) static void -term_resize(int sig) +sig_term_resize(int sig) { struct winsize newsize; + Signal(SIGWINCH, SIG_IGN); /* Don't bother me! */ + ioctl(0, TIOCGWINSZ, &newsize); + term_resize(newsize.ws_col, newsize.ws_row); +} + +void term_resize(int w, int h) +{ screenline_t *new_picture; Signal(SIGWINCH, SIG_IGN); /* Don't bother me! */ - ioctl(0, TIOCGWINSZ, &newsize); /* make sure reasonable size */ - newsize.ws_row = MAX(24, MIN(100, newsize.ws_row)); - newsize.ws_col = MAX(80, MIN(200, newsize.ws_col)); + h = MAX(24, MIN(100, h)); + w = MAX(80, MIN(200, w)); - if (newsize.ws_row > t_lines) { - new_picture = (screenline_t *) calloc(newsize.ws_row, - sizeof(screenline_t)); + if (h > t_lines && big_picture) { + new_picture = (screenline_t *) + calloc(h, sizeof(screenline_t)); if (new_picture == NULL) { syslog(LOG_ERR, "calloc(): %m"); return; @@ -53,19 +59,19 @@ term_resize(int sig) free(big_picture); big_picture = new_picture; } - t_lines = newsize.ws_row; - t_columns = newsize.ws_col; + t_lines = h; + t_columns = w; scr_lns = t_lines; /* XXX: scr_lns 跟 t_lines 有什麼不同, 為何分成兩個 */ b_lines = t_lines - 1; p_lines = t_lines - 4; - Signal(SIGWINCH, term_resize); + Signal(SIGWINCH, sig_term_resize); } int term_init(void) { - Signal(SIGWINCH, term_resize); + Signal(SIGWINCH, sig_term_resize); return YEA; } diff --git a/mbbsd/var.c b/mbbsd/var.c index 2d256aac..ee290bd3 100644 --- a/mbbsd/var.c +++ b/mbbsd/var.c @@ -375,6 +375,7 @@ char real_name[IDLEN + 1]; char local_article; /* mbbsd.c */ +int raw_connection = 0; char fromhost[STRLEN] = "\0"; char water_usies = 0; FILE *fp_writelog = NULL; diff --git a/sample/pttbbs.conf b/sample/pttbbs.conf index 8abc066b..410c13d8 100644 --- a/sample/pttbbs.conf +++ b/sample/pttbbs.conf @@ -115,7 +115,8 @@ //#define COLORDATE /* 若定義, 則會在 read socket的時候, 則會跳過讀入時第一個 byte 是 -1 - (即 telnet 的 control packet), 可避免循環錯誤 */ + (即 telnet 的 control packet), 可避免循環錯誤. + 但是就沒有辦法處理 term resize的情況. 不確定這個現在還會不會用到 */ //#define SKIP_TELNET_CONTROL_SIGNAL /* 若定義, 在使用者註冊之前, 會先顯示出該檔案, 經使用者確認後才能註冊 */ -- cgit v1.2.3