Ignore:
Timestamp:
Nov 23, 2012 10:30:55 AM (11 years ago)
Author:
riza
Message:

Re #1098: Additional implementation to command parsing, telnet front end, console front end

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/branches/projects/cli/pjlib-util/src/pjlib-util/cli_telnet.c

    r3232 r4299  
    4242#endif 
    4343 
    44 struct cli_telnet_sess 
    45 { 
    46     pj_cli_sess         base; 
    47     pj_pool_t          *pool; 
    48     pj_activesock_t    *asock; 
    49     pj_bool_t           authorized; 
    50     pj_ioqueue_op_key_t op_key; 
    51     pj_mutex_t         *smutex; 
    52  
    53     char                rcmd[PJ_CLI_MAX_CMDBUF]; 
    54     int                 len; 
    55     char                buf[CLI_TELNET_BUF_SIZE + MAX_CUT_MSG_LEN]; 
    56     unsigned            buf_len; 
     44#define MAX_CLI_TELNET_OPTIONS 256 
     45 
     46/** 
     47 * This specify the state for the telnet option negotiation. 
     48 */ 
     49enum cli_telnet_option_states  
     50{     
     51    OPT_DISABLE,                /* Option disable */ 
     52    OPT_ENABLE,                 /* Option enable */ 
     53    OPT_EXPECT_DISABLE,         /* Already send disable req, expecting resp */ 
     54    OPT_EXPECT_ENABLE,          /* Already send enable req, expecting resp */ 
     55    OPT_EXPECT_DISABLE_REV,     /* Already send disable req, expecting resp,  
     56                                 * need to send enable req */ 
     57    OPT_EXPECT_ENABLE_REV       /* Already send enable req, expecting resp, 
     58                                 * need to send disable req */ 
    5759}; 
     60 
     61/** 
     62 * This structure contains information for telnet session option negotiation. 
     63 * It contains the local/peer option config and the option negotiation state. 
     64 */ 
     65typedef struct cli_telnet_sess_option 
     66{ 
     67    /** 
     68     * Local setting for the option. 
     69     * Default: FALSE; 
     70     */ 
     71    pj_bool_t local_is_enable; 
     72 
     73    /** 
     74     * Remote setting for the option. 
     75     * Default: FALSE; 
     76     */ 
     77    pj_bool_t peer_is_enable; 
     78 
     79    /** 
     80     * Local state of the option negotiation. 
     81     */ 
     82    enum cli_telnet_option_states local_state; 
     83 
     84    /** 
     85     * Remote state of the option negotiation. 
     86     */ 
     87    enum cli_telnet_option_states peer_state; 
     88} cli_telnet_sess_option; 
     89 
     90/** 
     91 * This specify the state of input character parsing. 
     92 */ 
     93typedef enum cmd_parse_state 
     94{ 
     95    ST_NORMAL, 
     96    ST_CR, 
     97    ST_ESC, 
     98    ST_VT100, 
     99    ST_IAC, 
     100    ST_DO, 
     101    ST_DONT, 
     102    ST_WILL, 
     103    ST_WONT 
     104} cmd_parse_state; 
     105 
     106typedef enum cli_telnet_command 
     107{ 
     108    SUBNEGO_END     = 240,      /* End of subnegotiation parameters. */ 
     109    NOP             = 241,      /* No operation. */ 
     110    DATA_MARK       = 242,      /* Marker for NVT cleaning. */ 
     111    BREAK           = 243,      /* Indicates that the "break" key was hit. */ 
     112    INT_PROCESS     = 244,      /* Suspend, interrupt or abort the process. */ 
     113    ABORT_OUTPUT    = 245,      /* Abort output, abort output stream. */ 
     114    ARE_YOU_THERE   = 246,      /* Are you there. */ 
     115    ERASE_CHAR      = 247,      /* Erase character, erase the current char. */ 
     116    ERASE_LINE      = 248,      /* Erase line, erase the current line. */ 
     117    GO_AHEAD        = 249,      /* Go ahead, other end can transmit. */ 
     118    SUBNEGO_BEGIN   = 250,      /* Subnegotiation begin. */ 
     119    WILL            = 251,      /* Accept the use of option. */ 
     120    WONT            = 252,      /* Refuse the use of option. */ 
     121    DO              = 253,      /* Request to use option. */ 
     122    DONT            = 254,      /* Request to not use option. */ 
     123    IAC             = 255       /* Interpret as command */ 
     124} cli_telnet_command; 
     125 
     126enum cli_telnet_options 
     127{ 
     128    TRANSMIT_BINARY     = 0,    /* Transmit Binary. */ 
     129    ECHO                = 1,    /* Echo. */ 
     130    RECONNECT           = 2,    /* Reconnection. */ 
     131    SUPPRESS_GA         = 3,    /* Suppress Go Aheah. */ 
     132    MESSAGE_SIZE_NEGO   = 4,    /* Approx Message Size Negotiation. */ 
     133    STATUS              = 5,    /* Status. */ 
     134    TIMING_MARK         = 6,    /* Timing Mark. */ 
     135    RTCE_OPTION         = 7,    /* Remote Controlled Trans and Echo. */ 
     136    OUTPUT_LINE_WIDTH   = 8,    /* Output Line Width. */ 
     137    OUTPUT_PAGE_SIZE    = 9,    /* Output Page Size. */ 
     138    CR_DISPOSITION      = 10,   /* Carriage-Return Disposition. */ 
     139    HORI_TABSTOPS       = 11,   /* Horizontal Tabstops. */ 
     140    HORI_TAB_DISPO      = 12,   /* Horizontal Tab Disposition. */ 
     141    FF_DISP0            = 13,   /* Formfeed Disposition. */ 
     142    VERT_TABSTOPS       = 14,   /* Vertical Tabstops. */ 
     143    VERT_TAB_DISPO      = 15,   /* Vertical Tab Disposition. */ 
     144    LF_DISP0            = 16,   /* Linefeed Disposition. */ 
     145    EXT_ASCII           = 17,   /* Extended ASCII. */ 
     146    LOGOUT              = 18,   /* Logout. */ 
     147    BYTE_MACRO          = 19,   /* Byte Macro. */ 
     148    DE_TERMINAL         = 20,   /* Data Entry Terminal. */ 
     149    SUPDUP_PROTO        = 21,   /* SUPDUP Protocol. */ 
     150    SUPDUP_OUTPUT       = 22,   /* SUPDUP Output. */ 
     151    SEND_LOC            = 23,   /* Send Location. */ 
     152    TERM_TYPE           = 24,   /* Terminal Type. */ 
     153    EOR                 = 25,   /* End of Record. */ 
     154    TACACS_UID          = 26,   /* TACACS User Identification. */ 
     155    OUTPUT_MARKING      = 27,   /* Output Marking. */ 
     156    TTYLOC              = 28,   /* Terminal Location Number. */ 
     157    USE_3270_REGIME     = 29,   /* Telnet 3270 Regime. */ 
     158    USE_X3_PAD          = 30,   /* X.3 PAD. */ 
     159    WINDOW_SIZE         = 31,   /* Window Size. */ 
     160    TERM_SPEED          = 32,   /* Terminal Speed. */ 
     161    REM_FLOW_CONTROL    = 33,   /* Remote Flow Control. */ 
     162    LINE_MODE           = 34,   /* Linemode. */ 
     163    X_DISP_LOC          = 35,   /* X Display Location. */ 
     164    ENVIRONMENT         = 36,   /* Environment. */ 
     165    AUTH                = 37,   /* Authentication. */ 
     166    ENCRYPTION          = 38,   /* Encryption Option. */ 
     167    NEW_ENVIRONMENT     = 39,   /* New Environment. */ 
     168    TN_3270E            = 40,   /* TN3270E. */ 
     169    XAUTH               = 41,   /* XAUTH. */ 
     170    CHARSET             = 42,   /* CHARSET. */ 
     171    REM_SERIAL_PORT     = 43,   /* Telnet Remote Serial Port. */ 
     172    COM_PORT_CONTROL    = 44,   /* Com Port Control. */ 
     173    SUPP_LOCAL_ECHO     = 45,   /* Telnet Suppress Local Echo. */ 
     174    START_TLS           = 46,   /* Telnet Start TLS. */ 
     175    KERMIT              = 47,   /* KERMIT. */ 
     176    SEND_URL            = 48,   /* SEND-URL. */ 
     177    FWD_X               = 49,   /* FORWARD_X. */ 
     178    EXT_OPTIONS         = 255   /* Extended-Options-List */ 
     179}; 
     180 
     181enum terminal_cmd  
     182{ 
     183    TC_ESC              = 27, 
     184    TC_UP               = 65, 
     185    TC_DOWN             = 66, 
     186    TC_RIGHT            = 67, 
     187    TC_LEFT             = 68, 
     188    TC_END              = 70, 
     189    TC_HOME             = 72,     
     190    TC_CTRL_C           = 3, 
     191    TC_CR               = 13, 
     192    TC_BS               = 8, 
     193    TC_TAB              = 9, 
     194    TC_QM               = 63, 
     195    TC_BELL             = 7, 
     196    TC_DEL              = 127 
     197}; 
     198 
     199/** 
     200 * This structure contains the command line shown to the user.   
     201 */ 
     202typedef struct telnet_recv_buf { 
     203    /** 
     204     * Buffer containing the characters, NULL terminated. 
     205     */ 
     206    unsigned char           rbuf[PJ_CLI_MAX_CMDBUF]; 
     207 
     208    /** 
     209     * Current length of the command line. 
     210     */ 
     211    unsigned                len; 
     212 
     213    /** 
     214     * Current cursor position. 
     215     */ 
     216    unsigned                cur_pos; 
     217} telnet_recv_buf; 
     218 
     219typedef struct cmd_history 
     220{ 
     221    PJ_DECL_LIST_MEMBER(struct cmd_history); 
     222    pj_str_t command; 
     223} cmd_history; 
     224 
     225typedef struct cli_telnet_sess 
     226{ 
     227    pj_cli_sess             base; 
     228    pj_pool_t               *pool; 
     229    pj_activesock_t         *asock; 
     230    pj_bool_t               authorized; 
     231    pj_ioqueue_op_key_t     op_key; 
     232    pj_mutex_t              *smutex; 
     233    cmd_parse_state         parse_state; 
     234    cli_telnet_sess_option  telnet_option[MAX_CLI_TELNET_OPTIONS]; 
     235    cmd_history             *history; 
     236    cmd_history             *active_history; 
     237 
     238    telnet_recv_buf         *rcmd; 
     239    unsigned char           buf[CLI_TELNET_BUF_SIZE + MAX_CUT_MSG_LEN]; 
     240    unsigned                buf_len; 
     241} cli_telnet_sess; 
    58242 
    59243struct cli_telnet_fe 
     
    71255}; 
    72256 
     257/* Forward Declaration */ 
     258static pj_status_t telnet_sess_send2(cli_telnet_sess *sess, 
     259                                     const unsigned char *str, int len); 
     260 
     261static pj_status_t telnet_sess_send(cli_telnet_sess *sess, 
     262                                    const pj_str_t *str); 
     263 
     264/** 
     265 * Return the number of characters between the current cursor position  
     266 * to the end of line. 
     267 */ 
     268static unsigned recv_buf_right_len(telnet_recv_buf *recv_buf) 
     269{ 
     270    return (recv_buf->len - recv_buf->cur_pos); 
     271} 
     272 
     273static pj_bool_t recv_buf_insert(telnet_recv_buf *recv_buf,  
     274                                 unsigned char *data)  
     275{     
     276    if (recv_buf->len+1 >= PJ_CLI_MAX_CMDBUF) { 
     277        return PJ_FALSE; 
     278    } else {     
     279        if (*data == '\t' || *data == '?' || *data == '\r') { 
     280            /* Always insert to the end of line */ 
     281            recv_buf->rbuf[recv_buf->len] = *data; 
     282        } else { 
     283            /* Insert based on the current cursor pos */ 
     284            unsigned cur_pos = recv_buf->cur_pos; 
     285            unsigned rlen = recv_buf_right_len(recv_buf);            
     286            if (rlen > 0) {                  
     287                /* Shift right characters */ 
     288                pj_memmove(&recv_buf->rbuf[cur_pos+1],  
     289                           &recv_buf->rbuf[cur_pos],  
     290                           rlen+1); 
     291            }  
     292            recv_buf->rbuf[cur_pos] = *data; 
     293        } 
     294        ++recv_buf->cur_pos; 
     295        ++recv_buf->len; 
     296        recv_buf->rbuf[recv_buf->len] = 0; 
     297    } 
     298    return PJ_TRUE; 
     299} 
     300 
     301static pj_bool_t recv_buf_delete(telnet_recv_buf *recv_buf) 
     302{ 
     303    if ((recv_buf->len == 0) || (recv_buf_right_len(recv_buf) == 0)) { 
     304        return PJ_FALSE; 
     305    } else { 
     306        unsigned rlen; 
     307        unsigned cur_pos = recv_buf->cur_pos; 
     308        rlen = recv_buf_right_len(recv_buf)-1; 
     309        pj_memmove(&recv_buf->rbuf[cur_pos], &recv_buf->rbuf[cur_pos+1],  
     310                   rlen); 
     311        --recv_buf->cur_pos; 
     312        --recv_buf->len; 
     313        recv_buf->rbuf[recv_buf->len] = 0; 
     314    } 
     315    return PJ_TRUE; 
     316} 
     317 
     318static pj_bool_t recv_buf_backspace(telnet_recv_buf *recv_buf) 
     319{ 
     320    if ((recv_buf->cur_pos == 0) || (recv_buf->len == 0)) { 
     321        return PJ_FALSE; 
     322    } else { 
     323        unsigned rlen = recv_buf_right_len(recv_buf); 
     324        if (rlen) { 
     325            unsigned cur_pos = recv_buf->cur_pos; 
     326            pj_memmove(&recv_buf->rbuf[cur_pos-1], &recv_buf->rbuf[cur_pos],  
     327                       rlen); 
     328        } 
     329        --recv_buf->cur_pos; 
     330        --recv_buf->len; 
     331        recv_buf->rbuf[recv_buf->len] = 0; 
     332    }     
     333    return PJ_TRUE; 
     334} 
     335 
     336static int compare_str(void *value, const pj_list_type *nd) 
     337{ 
     338    cmd_history *node = (cmd_history*)nd; 
     339    return (pj_strcmp((pj_str_t *)value, &node->command)); 
     340} 
     341 
     342static pj_status_t insert_history(cli_telnet_sess *sess,                                  
     343                                  char *cmd_val) 
     344{ 
     345    cmd_history *in_history; 
     346    pj_str_t cmd; 
     347    cmd.ptr = cmd_val; 
     348    cmd.slen = pj_ansi_strlen(cmd_val)-1; 
     349 
     350    if (cmd.slen == 0) 
     351        return PJ_SUCCESS; 
     352 
     353    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
     354 
     355    /* Find matching history */ 
     356    in_history = pj_list_search(sess->history, (void*)&cmd, compare_str); 
     357    if (!in_history) { 
     358        if (pj_list_size(sess->history) < PJ_CLI_MAX_CMD_HISTORY) {          
     359            char *data_history; 
     360            in_history = PJ_POOL_ZALLOC_T(sess->pool, cmd_history); 
     361            pj_list_init(in_history); 
     362            data_history = (char *)pj_pool_calloc(sess->pool,  
     363                           sizeof(char), PJ_CLI_MAX_CMDBUF); 
     364            in_history->command.ptr = data_history; 
     365            in_history->command.slen = 0; 
     366        } else { 
     367            /* Get the oldest history */ 
     368            in_history = sess->history->prev; 
     369        }            
     370    } else { 
     371        pj_list_insert_nodes_after(in_history->prev, in_history->next); 
     372    } 
     373    pj_strcpy(&in_history->command, pj_strtrim(&cmd)); 
     374    pj_list_push_front(sess->history, in_history); 
     375    sess->active_history = sess->history; 
     376 
     377    return PJ_SUCCESS; 
     378} 
     379 
     380static pj_str_t* get_prev_history(cli_telnet_sess *sess, pj_bool_t is_forward) 
     381{ 
     382    pj_str_t *retval; 
     383    pj_size_t history_size; 
     384    cmd_history *node; 
     385    cmd_history *root; 
     386 
     387    PJ_ASSERT_RETURN(sess, NULL); 
     388 
     389    node = sess->active_history; 
     390    root = sess->history; 
     391    history_size = pj_list_size(sess->history); 
     392 
     393    if (history_size == 0) { 
     394        return NULL; 
     395    } else { 
     396        if (is_forward) {            
     397            node = (node->next==root)?node->next->next:node->next;           
     398        } else { 
     399            node = (node->prev==root)?node->prev->prev:node->prev;           
     400        } 
     401        retval = &node->command; 
     402        sess->active_history = node; 
     403    } 
     404    return retval; 
     405} 
     406 
     407static pj_bool_t send_telnet_cmd(cli_telnet_sess *sess,  
     408                                 cli_telnet_command cmd,  
     409                                 unsigned char option) 
     410{        
     411    unsigned char buf[3]; 
     412    PJ_ASSERT_RETURN(sess, PJ_FALSE); 
     413 
     414    buf[0] = IAC; 
     415    buf[1] = cmd; 
     416    buf[2] = option; 
     417    telnet_sess_send2(sess, buf, 3); 
     418 
     419    return PJ_TRUE; 
     420} 
     421 
     422/** 
     423 * This method will handle sending telnet's ENABLE option negotiation. 
     424 * For local option: send WILL. 
     425 * For remote option: send DO. 
     426 * This method also handle the state transition of the ENABLE  
     427 * negotiation process. 
     428 */ 
     429static pj_bool_t send_enable_option(cli_telnet_sess *sess,  
     430                                    pj_bool_t is_local,  
     431                                    unsigned char option) 
     432{ 
     433    cli_telnet_sess_option *sess_option; 
     434    enum cli_telnet_option_states *state; 
     435    PJ_ASSERT_RETURN(sess, PJ_FALSE); 
     436 
     437    sess_option = &sess->telnet_option[option]; 
     438    state = is_local?(&sess_option->local_state):(&sess_option->peer_state); 
     439    switch (*state) { 
     440        case OPT_ENABLE: 
     441            /* Ignore if already enabled */ 
     442            break; 
     443        case OPT_DISABLE: 
     444            *state = OPT_EXPECT_ENABLE; 
     445            send_telnet_cmd(sess, (is_local?WILL:DO), option); 
     446            break; 
     447        case OPT_EXPECT_ENABLE: 
     448            *state = OPT_DISABLE; 
     449            break; 
     450        case OPT_EXPECT_DISABLE: 
     451            *state = OPT_EXPECT_DISABLE_REV; 
     452            break; 
     453        case OPT_EXPECT_ENABLE_REV: 
     454            *state = OPT_EXPECT_ENABLE; 
     455            break; 
     456        case OPT_EXPECT_DISABLE_REV:         
     457            *state = OPT_DISABLE; 
     458            break; 
     459        default: 
     460            return PJ_FALSE; 
     461    } 
     462    return PJ_TRUE; 
     463} 
     464 
     465/** 
     466 * This method will handle sending telnet's DISABLE option negotiation. 
     467 * For local option: send WON'T. 
     468 * For remote option: send DON'T. 
     469 * This method also handle the state transition of the DISABLE  
     470 * negotiation process.  
     471 */ 
     472static pj_bool_t send_disable_option(cli_telnet_sess *sess,  
     473                                     pj_bool_t is_local,  
     474                                     unsigned char option) 
     475{ 
     476    cli_telnet_sess_option *sess_option; 
     477    enum cli_telnet_option_states *state; 
     478    PJ_ASSERT_RETURN(sess, PJ_FALSE); 
     479 
     480    sess_option = &sess->telnet_option[option]; 
     481    state = is_local?(&sess_option->local_state):(&sess_option->peer_state); 
     482    switch (*state) { 
     483        case OPT_ENABLE: 
     484            *state = OPT_EXPECT_DISABLE; 
     485            send_telnet_cmd(sess, (is_local?WONT:DONT), option); 
     486            break; 
     487        case OPT_DISABLE: 
     488            /* Ignore if already disabled */ 
     489            break; 
     490        case OPT_EXPECT_ENABLE: 
     491            *state = OPT_EXPECT_ENABLE_REV; 
     492            break; 
     493        case OPT_EXPECT_DISABLE: 
     494            *state = OPT_ENABLE; 
     495            break; 
     496        case OPT_EXPECT_ENABLE_REV:          
     497            *state = OPT_ENABLE; 
     498            break; 
     499        case OPT_EXPECT_DISABLE_REV: 
     500            *state = OPT_EXPECT_DISABLE; 
     501            break; 
     502        default: 
     503            return PJ_FALSE; 
     504    } 
     505    return PJ_TRUE; 
     506} 
     507 
     508static pj_bool_t send_cmd_do(cli_telnet_sess *sess,  
     509                             unsigned char option) 
     510{ 
     511    return send_enable_option(sess, PJ_FALSE, option); 
     512} 
     513 
     514static pj_bool_t send_cmd_dont(cli_telnet_sess *sess,  
     515                               unsigned char option) 
     516{ 
     517    return send_disable_option(sess, PJ_FALSE, option); 
     518} 
     519 
     520static pj_bool_t send_cmd_will(cli_telnet_sess *sess,  
     521                               unsigned char option) 
     522{ 
     523    return send_enable_option(sess, PJ_TRUE, option); 
     524} 
     525 
     526static pj_bool_t send_cmd_wont(cli_telnet_sess *sess,  
     527                               unsigned char option) 
     528{ 
     529    return send_disable_option(sess, PJ_TRUE, option); 
     530} 
     531 
     532/** 
     533 * This method will handle receiving telnet's ENABLE option negotiation. 
     534 * This method also handle the state transition of the ENABLE  
     535 * negotiation process.  
     536 */ 
     537static pj_bool_t receive_enable_option(cli_telnet_sess *sess,  
     538                                       pj_bool_t is_local,  
     539                                       unsigned char option) 
     540{ 
     541    cli_telnet_sess_option *sess_opt; 
     542    enum cli_telnet_option_states *state; 
     543    pj_bool_t opt_ena; 
     544    PJ_ASSERT_RETURN(sess, PJ_FALSE); 
     545 
     546    sess_opt = &sess->telnet_option[option]; 
     547    state = is_local?(&sess_opt->local_state):(&sess_opt->peer_state); 
     548    opt_ena = is_local?sess_opt->local_is_enable:sess_opt->peer_is_enable; 
     549    switch (*state) { 
     550        case OPT_ENABLE: 
     551            /* Ignore if already enabled */ 
     552            break; 
     553        case OPT_DISABLE: 
     554            if (opt_ena) { 
     555                *state = OPT_ENABLE; 
     556                send_telnet_cmd(sess, is_local?WILL:DO, option); 
     557            } else { 
     558                send_telnet_cmd(sess, is_local?WONT:DONT, option); 
     559            } 
     560            break; 
     561        case OPT_EXPECT_ENABLE:      
     562            *state = OPT_ENABLE; 
     563            break; 
     564        case OPT_EXPECT_DISABLE:             
     565            *state = OPT_DISABLE; 
     566            break; 
     567        case OPT_EXPECT_ENABLE_REV: 
     568            *state = OPT_EXPECT_DISABLE; 
     569            send_telnet_cmd(sess, is_local?WONT:DONT, option);       
     570            break; 
     571        case OPT_EXPECT_DISABLE_REV: 
     572            *state = OPT_EXPECT_DISABLE; 
     573            break; 
     574        default: 
     575            return PJ_FALSE; 
     576    } 
     577    return PJ_TRUE;         
     578} 
     579 
     580/** 
     581 * This method will handle receiving telnet's DISABLE option negotiation. 
     582 * This method also handle the state transition of the DISABLE  
     583 * negotiation process.  
     584 */ 
     585static pj_bool_t receive_disable_option(cli_telnet_sess *sess,  
     586                                        pj_bool_t is_local,  
     587                                        unsigned char option) 
     588{ 
     589    cli_telnet_sess_option *sess_opt; 
     590    enum cli_telnet_option_states *state; 
     591    pj_bool_t opt_ena; 
     592    PJ_ASSERT_RETURN(sess, PJ_FALSE); 
     593 
     594    sess_opt = &sess->telnet_option[option]; 
     595    state = is_local?(&sess_opt->local_state):(&sess_opt->peer_state); 
     596    opt_ena = is_local?sess_opt->local_is_enable:sess_opt->peer_is_enable; 
     597    switch (*state) { 
     598        case OPT_ENABLE: 
     599            /* Disabling option always need to be accepted */ 
     600            *state = OPT_DISABLE; 
     601            send_telnet_cmd(sess, is_local?WONT:DONT, option); 
     602            break; 
     603        case OPT_DISABLE: 
     604            /* Ignore if already enabled */ 
     605            break; 
     606        case OPT_EXPECT_ENABLE:      
     607        case OPT_EXPECT_DISABLE: 
     608            *state = OPT_DISABLE; 
     609            break; 
     610        case OPT_EXPECT_ENABLE_REV: 
     611            *state = OPT_DISABLE; 
     612            send_telnet_cmd(sess, is_local?WONT:DONT, option);       
     613            break; 
     614        case OPT_EXPECT_DISABLE_REV: 
     615            *state = OPT_EXPECT_ENABLE; 
     616            send_telnet_cmd(sess, is_local?WILL:DO, option); 
     617            break; 
     618        default: 
     619            return PJ_FALSE; 
     620    } 
     621    return PJ_TRUE;        
     622} 
     623 
     624static pj_bool_t receive_do(cli_telnet_sess *sess, unsigned char option) 
     625{ 
     626    return receive_enable_option(sess, PJ_TRUE, option); 
     627} 
     628 
     629static pj_bool_t receive_dont(cli_telnet_sess *sess, unsigned char option) 
     630{ 
     631    return receive_disable_option(sess, PJ_TRUE, option); 
     632} 
     633 
     634static pj_bool_t receive_will(cli_telnet_sess *sess, unsigned char option) 
     635{ 
     636    return receive_enable_option(sess, PJ_FALSE, option); 
     637} 
     638 
     639static pj_bool_t receive_wont(cli_telnet_sess *sess, unsigned char option) 
     640{ 
     641    return receive_disable_option(sess, PJ_FALSE, option); 
     642} 
     643 
     644static void set_local_option(cli_telnet_sess *sess,  
     645                             unsigned char option,  
     646                             pj_bool_t enable)  
     647{ 
     648    sess->telnet_option[option].local_is_enable = enable; 
     649} 
     650 
     651static void set_peer_option(cli_telnet_sess *sess,  
     652                            unsigned char option,  
     653                            pj_bool_t enable)  
     654{ 
     655    sess->telnet_option[option].peer_is_enable = enable; 
     656} 
     657 
     658static pj_bool_t is_local_option_state_ena(cli_telnet_sess *sess,  
     659                                           unsigned char option) 
     660{     
     661    return (sess->telnet_option[option].local_state == OPT_ENABLE); 
     662} 
     663 
     664static pj_bool_t is_peer_option_state_ena(cli_telnet_sess *sess,  
     665                                          unsigned char option) 
     666{     
     667    return (sess->telnet_option[option].peer_state == OPT_ENABLE); 
     668} 
     669 
     670static void send_return_key(cli_telnet_sess *sess)  
     671{     
     672    telnet_sess_send2(sess, (unsigned char*)"\r\n", 2); 
     673} 
     674 
     675static void send_bell(cli_telnet_sess *sess) { 
     676    unsigned char bell[1] = {0x07}; 
     677    telnet_sess_send2(sess, &bell[0], 1); 
     678} 
     679 
     680static void send_prompt_str(cli_telnet_sess *sess) 
     681{ 
     682    pj_str_t send_data; 
     683    char data_str[128]; 
     684    struct cli_telnet_fe *fe = (struct cli_telnet_fe *)sess->base.fe; 
     685 
     686    send_data.ptr = &data_str[0]; 
     687    send_data.slen = 0; 
     688     
     689    pj_strcat(&send_data, &fe->cfg.prompt_str); 
     690 
     691    telnet_sess_send(sess, &send_data); 
     692} 
     693 
     694static void send_err_arg(cli_telnet_sess *sess,  
     695                         const pj_cli_exec_info *info,  
     696                         const pj_str_t *msg, 
     697                         pj_bool_t with_return, 
     698                         pj_bool_t with_last_cmd) 
     699{ 
     700    pj_str_t send_data; 
     701    char data_str[256]; 
     702    unsigned len; 
     703    unsigned i; 
     704    struct cli_telnet_fe *fe = (struct cli_telnet_fe *)sess->base.fe; 
     705 
     706    send_data.ptr = &data_str[0]; 
     707    send_data.slen = 0; 
     708 
     709    if (with_return) 
     710        pj_strcat2(&send_data, "\r\n"); 
     711 
     712    len = fe->cfg.prompt_str.slen + info->err_pos; 
     713 
     714    for (i=0;i<len;++i) { 
     715        pj_strcat2(&send_data, " "); 
     716    } 
     717    pj_strcat2(&send_data, "^"); 
     718    pj_strcat2(&send_data, "\r\n"); 
     719    pj_strcat(&send_data, msg); 
     720    pj_strcat(&send_data, &fe->cfg.prompt_str); 
     721    if (with_last_cmd) 
     722        pj_strcat2(&send_data, (char *)&sess->rcmd->rbuf[0]); 
     723 
     724    telnet_sess_send(sess, &send_data); 
     725} 
     726 
     727static void send_inv_arg(cli_telnet_sess *sess,  
     728                         const pj_cli_exec_info *info, 
     729                         pj_bool_t with_return, 
     730                         pj_bool_t with_last_cmd) 
     731{ 
     732    static const pj_str_t ERR_MSG = {"%Error : Invalid Arguments\r\n", 28}; 
     733    send_err_arg(sess, info, &ERR_MSG, with_return, with_last_cmd); 
     734} 
     735 
     736static void send_too_many_arg(cli_telnet_sess *sess,  
     737                              const pj_cli_exec_info *info, 
     738                              pj_bool_t with_return, 
     739                              pj_bool_t with_last_cmd) 
     740{ 
     741    static const pj_str_t ERR_MSG = {"%Error : Too Many Arguments\r\n", 29}; 
     742    send_err_arg(sess, info, &ERR_MSG, with_return, with_last_cmd); 
     743} 
     744 
     745static void send_ambi_arg(cli_telnet_sess *sess,  
     746                          const pj_cli_exec_info *info, 
     747                          pj_bool_t with_return, 
     748                          pj_bool_t with_last_cmd) 
     749{ 
     750    unsigned i; 
     751    pj_ssize_t j; 
     752    unsigned len; 
     753    pj_str_t send_data; 
     754    char data[1028]; 
     755    struct cli_telnet_fe *fe = (struct cli_telnet_fe *)sess->base.fe; 
     756    const pj_cli_hint_info *hint = info->hint; 
     757    pj_bool_t is_process_sc = PJ_FALSE; 
     758    pj_bool_t valid_type = PJ_FALSE; 
     759    pj_ssize_t max_length = 0; 
     760    const pj_str_t sc_type = pj_str("SC");     
     761    send_data.ptr = &data[0]; 
     762    send_data.slen = 0; 
     763     
     764    if (with_return) 
     765        pj_strcat2(&send_data, "\r\n"); 
     766 
     767    len = fe->cfg.prompt_str.slen + info->err_pos; 
     768 
     769    for (i=0;i<len;++i) { 
     770        pj_strcat2(&send_data, " "); 
     771    } 
     772    pj_strcat2(&send_data, "^"); 
     773    /* Get the max length of the command name */ 
     774    for (i=0;i<info->hint_cnt;++i) { 
     775        if (hint[i].name.slen > max_length) { 
     776            max_length = hint[i].name.slen; 
     777        } 
     778    } 
     779 
     780    for (i=0;i<info->hint_cnt;++i) {     
     781        if ((&hint[i].type) && (hint[i].type.slen > 0)) { 
     782            valid_type = PJ_TRUE; 
     783            if (pj_stricmp(&hint[i].type, &sc_type) == 0) { 
     784                if (is_process_sc) { 
     785                    pj_strcat2(&send_data, ", "); 
     786                } else { 
     787                    pj_strcat2(&send_data, "\r\n\t Shorcut: "); 
     788                    is_process_sc = PJ_TRUE; 
     789                } 
     790                pj_strcat(&send_data, &hint[i].name); 
     791            } else { 
     792                is_process_sc = PJ_FALSE; 
     793            } 
     794        } else {             
     795            valid_type = PJ_FALSE; 
     796            is_process_sc = PJ_FALSE; 
     797        } 
     798 
     799        if (!is_process_sc) { 
     800            pj_strcat2(&send_data, "\r\n\t"); 
     801 
     802            if (valid_type) { 
     803                pj_strcat2(&send_data, "<"); 
     804                pj_strcat(&send_data, &hint[i].type); 
     805                pj_strcat2(&send_data, ">");     
     806            } else { 
     807                pj_strcat(&send_data, &hint[i].name);        
     808            } 
     809         
     810            if ((&hint[i].desc) && (hint[i].desc.slen > 0)) { 
     811                if (!valid_type) { 
     812                    for (j=0;j<(max_length-hint[i].name.slen);++j) { 
     813                        pj_strcat2(&send_data, " "); 
     814                    } 
     815                } 
     816                pj_strcat2(&send_data, "\t"); 
     817                pj_strcat(&send_data, &hint[i].desc);        
     818            } 
     819        } 
     820    }    
     821    pj_strcat2(&send_data, "\r\n");        
     822    pj_strcat(&send_data, &fe->cfg.prompt_str); 
     823    if (with_last_cmd) 
     824        pj_strcat2(&send_data, (char *)&sess->rcmd->rbuf[0]); 
     825 
     826    telnet_sess_send(sess, &send_data);     
     827} 
     828 
     829static void send_comp_arg(cli_telnet_sess *sess,  
     830                          pj_cli_exec_info *info) 
     831{ 
     832    pj_str_t send_data; 
     833    char data[128]; 
     834 
     835    pj_strcat2(&info->hint[0].name, " "); 
     836 
     837    send_data.ptr = &data[0]; 
     838    send_data.slen = 0; 
     839 
     840    pj_strcat(&send_data, &info->hint[0].name);         
     841 
     842    telnet_sess_send(sess, &send_data); 
     843} 
     844 
     845static pj_bool_t handle_alfa_num(cli_telnet_sess *sess, unsigned char *data) 
     846{         
     847    if (is_local_option_state_ena(sess, ECHO)) { 
     848        if (recv_buf_right_len(sess->rcmd) > 0) { 
     849            /* Insert character */           
     850            unsigned char echo[5] = {0x1b, 0x5b, 0x31, 0x40, 0x00}; 
     851            echo[4] = *data; 
     852            telnet_sess_send2(sess, &echo[0], 5); 
     853        } else { 
     854            /* Append character */ 
     855            telnet_sess_send2(sess, data, 1); 
     856        } 
     857        return PJ_TRUE; 
     858    }  
     859    return PJ_FALSE; 
     860} 
     861 
     862static pj_bool_t handle_backspace(cli_telnet_sess *sess, unsigned char *data) 
     863{ 
     864    unsigned rlen = recv_buf_right_len(sess->rcmd); 
     865    if (recv_buf_backspace(sess->rcmd)) { 
     866        if (rlen) { 
     867            /* Cursor is not at the end of line */ 
     868            unsigned char echo[5] = {0x00, 0x1b, 0x5b, 0x31, 0x50}; 
     869            echo[0] = *data; 
     870            telnet_sess_send2(sess, &echo[0], 5); 
     871        } else { 
     872            const static unsigned char echo[3] = {0x08, 0x20, 0x08};         
     873            telnet_sess_send2(sess, &echo[0], 3); 
     874        } 
     875        return PJ_TRUE; 
     876    } 
     877    return PJ_FALSE; 
     878} 
     879 
     880static pj_bool_t handle_tab(cli_telnet_sess *sess) 
     881{ 
     882    pj_status_t status; 
     883    pj_bool_t retval = PJ_TRUE; 
     884    unsigned len; 
     885     
     886    pj_pool_t *pool; 
     887    pj_cli_cmd_val *cmd_val; 
     888    pj_cli_exec_info info; 
     889    pool = pj_pool_create(sess->pool->factory, "handle_tab", 
     890                          PJ_CLI_TELNET_POOL_SIZE, PJ_CLI_TELNET_POOL_INC, 
     891                          NULL); 
     892 
     893    cmd_val = PJ_POOL_ZALLOC_T(pool, pj_cli_cmd_val); 
     894     
     895    status = pj_cli_sess_parse(&sess->base, (char *)&sess->rcmd->rbuf, cmd_val,  
     896                               pool, &info);     
     897 
     898    len = pj_ansi_strlen((char *)&sess->rcmd->rbuf[0]); 
     899 
     900    switch (status) { 
     901    case PJ_CLI_EINVARG: 
     902        send_inv_arg(sess, &info, PJ_TRUE, PJ_TRUE);             
     903        break; 
     904    case PJ_CLI_ETOOMANYARGS: 
     905        send_too_many_arg(sess, &info, PJ_TRUE, PJ_TRUE); 
     906        break; 
     907    case PJ_CLI_EMISSINGARG: 
     908    case PJ_CLI_EAMBIGUOUS: 
     909        send_ambi_arg(sess, &info, PJ_TRUE, PJ_TRUE); 
     910        break; 
     911    case PJ_SUCCESS: 
     912        if (len > sess->rcmd->cur_pos) 
     913        { 
     914            /* Send the cursor to EOL */ 
     915            unsigned rlen = len - sess->rcmd->cur_pos+1; 
     916            unsigned char *data_sent = &sess->rcmd->rbuf[sess->rcmd->cur_pos-1]; 
     917            telnet_sess_send2(sess, data_sent, rlen); 
     918        } 
     919        if (info.hint_cnt > 0) {         
     920            /* Complete command */ 
     921            send_comp_arg(sess, &info); 
     922 
     923            pj_memcpy(&sess->rcmd->rbuf[len],  
     924                      &info.hint[0].name.ptr[0], info.hint[0].name.slen); 
     925 
     926            len += info.hint[0].name.slen; 
     927            sess->rcmd->rbuf[len] = 0;               
     928        } else { 
     929            retval = PJ_FALSE; 
     930        } 
     931        break; 
     932    } 
     933    sess->rcmd->len = len; 
     934    sess->rcmd->cur_pos = sess->rcmd->len; 
     935 
     936    pj_pool_release(pool);       
     937    return retval;  
     938} 
     939 
     940static pj_bool_t handle_return(cli_telnet_sess *sess) 
     941{ 
     942    pj_status_t status; 
     943    pj_bool_t retval = PJ_TRUE; 
     944     
     945    pj_pool_t *pool;     
     946    pj_cli_exec_info info;     
     947     
     948    send_return_key(sess); 
     949    insert_history(sess, (char *)&sess->rcmd->rbuf); 
     950 
     951    pool = pj_pool_create(sess->pool->factory, "handle_return", 
     952                          PJ_CLI_TELNET_POOL_SIZE, PJ_CLI_TELNET_POOL_INC, 
     953                          NULL);     
     954     
     955    status = pj_cli_sess_exec(&sess->base, (char *)&sess->rcmd->rbuf,  
     956                              pool, &info);     
     957 
     958    switch (status) { 
     959    case PJ_CLI_EINVARG: 
     960        send_inv_arg(sess, &info, PJ_FALSE, PJ_FALSE);   
     961        break; 
     962    case PJ_CLI_ETOOMANYARGS: 
     963        send_too_many_arg(sess, &info, PJ_FALSE, PJ_FALSE); 
     964        break; 
     965    case PJ_CLI_EAMBIGUOUS: 
     966    case PJ_CLI_EMISSINGARG: 
     967        send_ambi_arg(sess, &info, PJ_FALSE, PJ_FALSE); 
     968        break; 
     969    case PJ_CLI_EEXIT: 
     970        retval = PJ_FALSE; 
     971        break; 
     972    case PJ_SUCCESS: 
     973        send_prompt_str(sess); 
     974        break; 
     975    }     
     976    if (retval) { 
     977        sess->rcmd->rbuf[0] = 0; 
     978        sess->rcmd->len = 0; 
     979        sess->rcmd->cur_pos = sess->rcmd->len; 
     980    } 
     981 
     982    pj_pool_release(pool);       
     983    return retval;  
     984} 
     985 
     986static pj_bool_t handle_right_key(cli_telnet_sess *sess) 
     987{ 
     988    if (recv_buf_right_len(sess->rcmd)) { 
     989        unsigned char *data = &sess->rcmd->rbuf[sess->rcmd->cur_pos++]; 
     990        telnet_sess_send2(sess, data, 1);                
     991        return PJ_TRUE; 
     992    } 
     993    return PJ_FALSE; 
     994} 
     995 
     996static pj_bool_t handle_left_key(cli_telnet_sess *sess) 
     997{ 
     998    const static unsigned char BACK_SPACE = 0x08; 
     999    if (sess->rcmd->cur_pos) { 
     1000        telnet_sess_send2(sess, &BACK_SPACE, 1); 
     1001        --sess->rcmd->cur_pos; 
     1002        return PJ_TRUE; 
     1003    } 
     1004    return PJ_FALSE; 
     1005} 
     1006 
     1007static pj_bool_t handle_up_down(cli_telnet_sess *sess, pj_bool_t is_up) 
     1008{ 
     1009    pj_str_t *history; 
     1010 
     1011    PJ_ASSERT_RETURN(sess, PJ_FALSE); 
     1012 
     1013    history = get_prev_history(sess, is_up); 
     1014    if (history) { 
     1015        pj_str_t send_data; 
     1016        char str[PJ_CLI_MAX_CMDBUF]; 
     1017        send_data.ptr = &str[0]; 
     1018        send_data.slen = 0; 
     1019 
     1020        if (sess->rcmd->cur_pos > 0) { 
     1021            pj_memset(send_data.ptr, 0x08, sess->rcmd->cur_pos); 
     1022            send_data.slen = sess->rcmd->cur_pos; 
     1023        } 
     1024 
     1025        if (sess->rcmd->len > (unsigned)history->slen) { 
     1026            unsigned buf_len = sess->rcmd->len; 
     1027            pj_memset(&send_data.ptr[send_data.slen], 0x20, buf_len); 
     1028            send_data.slen += buf_len; 
     1029            pj_memset(&send_data.ptr[send_data.slen], 0x08, buf_len); 
     1030            send_data.slen += buf_len; 
     1031        }  
     1032        /* Send data */ 
     1033        pj_strcat(&send_data, history); 
     1034        telnet_sess_send(sess, &send_data); 
     1035        pj_ansi_strncpy((char*)&sess->rcmd->rbuf, history->ptr, history->slen); 
     1036        sess->rcmd->rbuf[history->slen] = 0; 
     1037        sess->rcmd->len = history->slen; 
     1038        sess->rcmd->cur_pos = sess->rcmd->len; 
     1039        return PJ_TRUE; 
     1040    } 
     1041    return PJ_FALSE; 
     1042} 
     1043 
     1044static pj_status_t process_vt100_cmd(cli_telnet_sess *sess,  
     1045                                     unsigned char *cmd) 
     1046{     
     1047    pj_status_t status = PJ_TRUE; 
     1048    switch (*cmd) { 
     1049        case TC_ESC: 
     1050            break; 
     1051        case TC_UP: 
     1052            status = handle_up_down(sess, PJ_TRUE); 
     1053            break; 
     1054        case TC_DOWN: 
     1055            status = handle_up_down(sess, PJ_FALSE); 
     1056            break; 
     1057        case TC_RIGHT: 
     1058            status = handle_right_key(sess); 
     1059            break; 
     1060        case TC_LEFT: 
     1061            status = handle_left_key(sess); 
     1062            break; 
     1063        case TC_END: 
     1064            break; 
     1065        case TC_HOME: 
     1066            break; 
     1067        case TC_CTRL_C: 
     1068            break; 
     1069        case TC_CR: 
     1070            break; 
     1071        case TC_BS: 
     1072            break; 
     1073        case TC_TAB: 
     1074            break; 
     1075        case TC_QM: 
     1076            break; 
     1077        case TC_BELL: 
     1078            break; 
     1079        case TC_DEL: 
     1080            break; 
     1081    }; 
     1082    return status; 
     1083} 
     1084 
    731085PJ_DEF(void) pj_cli_telnet_cfg_default(pj_cli_telnet_cfg *param) 
    741086{ 
     
    801092} 
    811093 
    82  
    831094/* Send a message to a telnet session */ 
    84 static pj_status_t telnet_sess_send(struct cli_telnet_sess *sess, 
     1095static pj_status_t telnet_sess_send(cli_telnet_sess *sess, 
    851096                                    const pj_str_t *str) 
    861097{ 
     
    1101121            pj_memmove(sess->buf + sess->buf_len, str->ptr, clen); 
    1111122        if (clen < sz) { 
    112             pj_ansi_snprintf(sess->buf + CLI_TELNET_BUF_SIZE, 
     1123            pj_ansi_snprintf((char *)sess->buf + CLI_TELNET_BUF_SIZE, 
    1131124                             MAX_CUT_MSG_LEN, CUT_MSG); 
    1141125            sess->buf_len = CLI_TELNET_BUF_SIZE + 
    115                             pj_ansi_strlen(sess->buf + CLI_TELNET_BUF_SIZE); 
     1126                            pj_ansi_strlen((char *)sess->buf+CLI_TELNET_BUF_SIZE); 
    1161127        } else 
    1171128            sess->buf_len += clen; 
     
    1261137} 
    1271138 
    128 static pj_status_t telnet_sess_send2(struct cli_telnet_sess *sess, 
    129                                      const char *str, int len) 
     1139static pj_status_t telnet_sess_send2(cli_telnet_sess *sess, 
     1140                                     const unsigned char *str, int len) 
    1301141{ 
    1311142    pj_str_t s; 
     
    1371148static void cli_telnet_sess_destroy(pj_cli_sess *sess) 
    1381149{ 
    139     struct cli_telnet_sess *tsess = (struct cli_telnet_sess *)sess; 
     1150    cli_telnet_sess *tsess = (cli_telnet_sess *)sess; 
    1401151    pj_mutex_t *mutex = ((struct cli_telnet_fe *)sess->fe)->mutex; 
    1411152 
     
    1611172    sess = tfe->sess_head.next; 
    1621173    while (sess != &tfe->sess_head) { 
    163         struct cli_telnet_sess *tsess = (struct cli_telnet_sess *)sess; 
    164  
    165         sess = sess->next; 
    166         if (tsess->base.log_level > level && tsess->authorized) 
    167             telnet_sess_send2(tsess, data, len); 
     1174        cli_telnet_sess *tsess = (cli_telnet_sess *)sess; 
     1175 
     1176        sess = sess->next;         
     1177        if (tsess->base.log_level > level) 
     1178            telnet_sess_send2(tsess, (unsigned char *)data, len); 
    1681179    } 
    1691180     
     
    2141225                                          pj_ssize_t sent) 
    2151226{ 
    216     struct cli_telnet_sess *sess = (struct cli_telnet_sess *) 
    217                                     pj_activesock_get_user_data(asock); 
     1227    cli_telnet_sess *sess = (cli_telnet_sess *) 
     1228                            pj_activesock_get_user_data(asock); 
    2181229 
    2191230    PJ_UNUSED_ARG(op_key); 
    2201231 
    2211232    if (sent <= 0) { 
    222         pj_cli_end_session(&sess->base); 
     1233        pj_cli_sess_end_session(&sess->base); 
    2231234        return PJ_FALSE; 
    2241235    } 
     
    2321243        if (telnet_sess_send2(sess, sess->buf, len) != PJ_SUCCESS) { 
    2331244            pj_mutex_unlock(sess->smutex); 
    234             pj_cli_end_session(&sess->base); 
     1245            pj_cli_sess_end_session(&sess->base); 
    2351246            return PJ_FALSE; 
    2361247        } 
     
    2481259                                          pj_size_t *remainder) 
    2491260{ 
    250     struct cli_telnet_sess *sess = (struct cli_telnet_sess *) 
    251                                     pj_activesock_get_user_data(asock); 
     1261    cli_telnet_sess *sess = (cli_telnet_sess *) 
     1262                            pj_activesock_get_user_data(asock); 
    2521263    struct cli_telnet_fe *tfe = (struct cli_telnet_fe *)sess->base.fe; 
    253     char *cdata = (char*)data; 
     1264    unsigned char *cdata = (unsigned char*)data;     
     1265    pj_status_t is_valid = PJ_TRUE; 
    2541266 
    2551267    PJ_UNUSED_ARG(size); 
     
    2571269 
    2581270    if (status != PJ_SUCCESS && status != PJ_EPENDING) { 
    259         pj_cli_end_session(&sess->base); 
     1271        pj_cli_sess_end_session(&sess->base); 
    2601272        return PJ_FALSE; 
    2611273    } 
     
    2661278    pj_mutex_lock(sess->smutex); 
    2671279 
    268     if (*cdata == 8) {                          // Backspace 
    269         if (sess->len > 0) 
    270             sess->len--; 
    271         if (telnet_sess_send2(sess, " \b", 2) != PJ_SUCCESS) 
    272             goto on_exit; 
    273     } else { 
    274         if (sess->len < PJ_CLI_MAX_CMDBUF - 1) 
    275             sess->rcmd[sess->len++] = *cdata; 
    276         if (*cdata == '\n') { 
    277             /* Trim trailing newlines */ 
    278             for (; sess->len > 0;) { 
    279                 if (sess->rcmd[sess->len - 1] == '\n' || 
    280                     sess->rcmd[sess->len - 1] == '\r') 
    281                     sess->rcmd[--sess->len] = 0; 
    282                 else 
    283                     break; 
    284             } 
    285             if (sess->len > 0 && sess->rcmd[sess->len - 1] != 0) 
    286                 sess->rcmd[sess->len++] = 0; 
    287  
    288             /* If a password is necessary, check whether the supplied password 
    289              * is correct. 
    290              */ 
    291             if (!sess->authorized &&  
    292                 ((struct cli_telnet_fe *)sess->base.fe)->cfg.passwd.slen > 0) 
    293             { 
    294                 if (pj_strcmp2(&tfe->cfg.passwd, sess->rcmd)) { 
    295                     pj_str_t str = pj_str("Wrong password!\r\n"); 
    296  
    297                     telnet_sess_send(sess, &str); 
    298                     goto on_exit; 
    299                 } else { 
    300                     /* Password is correct, send welcome message */ 
    301                     if (telnet_sess_send(sess, &tfe->cfg.welcome_msg) 
    302                         != PJ_SUCCESS) 
    303                     { 
    304                         goto on_exit; 
    305                     } 
    306                     sess->authorized = PJ_TRUE; 
    307                 } 
    308             } else { 
    309                 pj_status_t status; 
    310                  
    311                 pj_mutex_unlock(sess->smutex); 
    312                 status = pj_cli_exec(&sess->base, sess->rcmd, NULL); 
    313                 if (status == PJ_CLI_EEXIT) 
    314                     return PJ_FALSE; 
    315                 pj_mutex_lock(sess->smutex); 
    316             } 
    317             sess->len = 0; 
    318         } else if (!sess->authorized &&  
    319             ((struct cli_telnet_fe *)sess->base.fe)->cfg.passwd.slen > 0 && 
    320             *cdata != '\r') 
    321         { 
    322             if (telnet_sess_send2(sess, "\b ", 2) != PJ_SUCCESS) 
    323                 goto on_exit; 
    324         } 
    325  
     1280    switch (sess->parse_state) { 
     1281        case ST_CR: 
     1282            sess->parse_state = ST_NORMAL; 
     1283            if (*cdata == 0 || *cdata == '\n')                           
     1284                pj_mutex_unlock(sess->smutex); 
     1285                is_valid = handle_return(sess); 
     1286                if (!is_valid)               
     1287                    return PJ_FALSE; 
     1288                pj_mutex_lock(sess->smutex);     
     1289                break; 
     1290        case ST_NORMAL: 
     1291            if (*cdata == IAC) { 
     1292                sess->parse_state = ST_IAC; 
     1293            } else if (*cdata == '\b') { 
     1294                is_valid = handle_backspace(sess, cdata); 
     1295            } else if (*cdata == 27) {               
     1296                sess->parse_state = ST_ESC; 
     1297            } else {  
     1298                if (recv_buf_insert(sess->rcmd, cdata)) { 
     1299                    if (*cdata == '\r') { 
     1300                        sess->parse_state = ST_CR; 
     1301                    } else if ((*cdata == '\t') || (*cdata == '?')) { 
     1302                        is_valid = handle_tab(sess); 
     1303                    } else if (*cdata > 31 && *cdata < 127) { 
     1304                        is_valid = handle_alfa_num(sess, cdata); 
     1305                    } 
     1306                } else { 
     1307                    is_valid = PJ_FALSE; 
     1308                } 
     1309            } 
     1310            break; 
     1311        case ST_ESC: 
     1312            if (*cdata == 91) {          
     1313                sess->parse_state = ST_VT100; 
     1314            } else { 
     1315                sess->parse_state = ST_NORMAL; 
     1316            } 
     1317            break; 
     1318        case ST_VT100: 
     1319            sess->parse_state = ST_NORMAL; 
     1320            is_valid = process_vt100_cmd(sess, cdata); 
     1321            break; 
     1322        case ST_IAC: 
     1323            switch ((unsigned) *cdata) { 
     1324                case DO: 
     1325                    sess->parse_state = ST_DO; 
     1326                    break; 
     1327                case DONT: 
     1328                    sess->parse_state = ST_DONT; 
     1329                    break; 
     1330                case WILL: 
     1331                    sess->parse_state = ST_WILL; 
     1332                    break; 
     1333                case WONT: 
     1334                    sess->parse_state = ST_WONT; 
     1335                    break; 
     1336                default: 
     1337                    sess->parse_state = ST_NORMAL; 
     1338                    break; 
     1339            } 
     1340            break; 
     1341        case ST_DO: 
     1342            receive_do(sess, *cdata); 
     1343            sess->parse_state = ST_NORMAL; 
     1344            break; 
     1345        case ST_DONT: 
     1346            receive_dont(sess, *cdata); 
     1347            sess->parse_state = ST_NORMAL; 
     1348            break; 
     1349        case ST_WILL: 
     1350            receive_will(sess, *cdata); 
     1351            sess->parse_state = ST_NORMAL; 
     1352            break; 
     1353        case ST_WONT: 
     1354            receive_wont(sess, *cdata); 
     1355            sess->parse_state = ST_NORMAL; 
     1356            break; 
     1357        default: 
     1358            sess->parse_state = ST_NORMAL; 
     1359            break; 
     1360    } 
     1361    if (!is_valid) { 
     1362        send_bell(sess); 
    3261363    } 
    3271364 
     
    3291366 
    3301367    return PJ_TRUE; 
    331  
    332 on_exit: 
    333     pj_mutex_unlock(sess->smutex); 
    334     pj_cli_end_session(&sess->base); 
    335     return PJ_FALSE; 
    3361368} 
    3371369 
     
    3451377    pj_status_t sstatus; 
    3461378    pj_pool_t *pool; 
    347     struct cli_telnet_sess *sess; 
     1379    cli_telnet_sess *sess; 
    3481380    pj_activesock_cb asock_cb; 
    3491381 
     
    3641396    } 
    3651397 
    366     sess = PJ_POOL_ZALLOC_T(pool, struct cli_telnet_sess); 
     1398    sess = PJ_POOL_ZALLOC_T(pool, cli_telnet_sess); 
    3671399    sess->pool = pool; 
    3681400    sess->base.fe = &fe->base; 
     
    3731405    asock_cb.on_data_read = &telnet_sess_on_data_read; 
    3741406    asock_cb.on_data_sent = &telnet_sess_on_data_sent; 
     1407    sess->rcmd = PJ_POOL_ZALLOC_T(pool, telnet_recv_buf); 
     1408    sess->history = PJ_POOL_ZALLOC_T(pool, struct cmd_history); 
     1409    pj_list_init(sess->history); 
     1410    sess->active_history = sess->history; 
    3751411 
    3761412    sstatus = pj_mutex_create_recursive(pool, "mutex_telnet_sess", 
     
    3871423    } 
    3881424 
    389     /* Prompt for password if required, otherwise directly send 
    390      * a welcome message. 
    391      */ 
    392     if (fe->cfg.passwd.slen) { 
    393         pj_str_t pwd = pj_str("Password: "); 
    394         if (telnet_sess_send(sess, &pwd) != PJ_SUCCESS) 
    395             goto on_exit; 
    396     } else { 
    397         if (pj_strlen(&fe->cfg.welcome_msg)) { 
    398             if (telnet_sess_send(sess, &fe->cfg.welcome_msg) != PJ_SUCCESS) 
    399                 goto on_exit; 
    400         } else { 
    401             if (telnet_sess_send2(sess, " \b", 2) != PJ_SUCCESS) 
    402                 goto on_exit; 
    403         } 
    404         sess->authorized = PJ_TRUE; 
    405     } 
     1425    pj_memset(sess->telnet_option, 0, sizeof(sess->telnet_option)); 
     1426    set_local_option(sess, TRANSMIT_BINARY, PJ_TRUE); 
     1427    set_local_option(sess, STATUS, PJ_TRUE); 
     1428    set_local_option(sess, SUPPRESS_GA, PJ_TRUE); 
     1429    set_local_option(sess, TIMING_MARK, PJ_TRUE); 
     1430    set_local_option(sess, TERM_SPEED, PJ_TRUE); 
     1431    set_local_option(sess, TERM_TYPE, PJ_TRUE); 
     1432 
     1433    set_peer_option(sess, TRANSMIT_BINARY, PJ_TRUE); 
     1434    set_peer_option(sess, SUPPRESS_GA, PJ_TRUE); 
     1435    set_peer_option(sess, STATUS, PJ_TRUE); 
     1436    set_peer_option(sess, TIMING_MARK, PJ_TRUE); 
     1437    set_peer_option(sess, ECHO, PJ_TRUE);     
     1438 
     1439    send_cmd_do(sess, SUPPRESS_GA); 
     1440    send_cmd_will(sess, ECHO); 
     1441    send_cmd_will(sess, STATUS);    
     1442    send_cmd_will(sess, SUPPRESS_GA); 
     1443 
     1444    /* Send prompt string */ 
     1445    telnet_sess_send(sess, &fe->cfg.prompt_str); 
    4061446 
    4071447    /* Start reading for input from the new telnet session */ 
     
    4621502    fe->base.type = PJ_CLI_TELNET_FRONT_END; 
    4631503    fe->base.op->on_write_log = &cli_telnet_fe_write_log; 
    464 //    fe->base.op->on_quit = &cli_telnet_fe_quit; 
    4651504    fe->base.op->on_destroy = &cli_telnet_fe_destroy; 
    4661505    fe->pool = pool; 
     
    4971536        PJ_LOG(3, (THIS_FILE, "CLI telnet daemon listening at port %d", 
    4981537               fe->cfg.port)); 
     1538         
     1539        if (fe->cfg.prompt_str.slen == 0) { 
     1540            pj_str_t prompt_sign = {"> ", 2}; 
     1541            char *prompt_data = pj_pool_alloc(fe->pool,  
     1542                                              pj_gethostname()->slen+2); 
     1543            fe->cfg.prompt_str.ptr = prompt_data; 
     1544 
     1545            pj_strcpy(&fe->cfg.prompt_str, pj_gethostname()); 
     1546            pj_strcat(&fe->cfg.prompt_str, &prompt_sign); 
     1547        }        
    4991548    } else { 
    5001549        PJ_LOG(3, (THIS_FILE, "Failed binding the socket")); 
Note: See TracChangeset for help on using the changeset viewer.