- Timestamp:
- Nov 23, 2012 10:30:55 AM (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/branches/projects/cli/pjlib-util/src/pjlib-util/cli_telnet.c
r3232 r4299 42 42 #endif 43 43 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 */ 49 enum 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 */ 57 59 }; 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 */ 65 typedef 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 */ 93 typedef 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 106 typedef 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 126 enum 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 181 enum 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 */ 202 typedef 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 219 typedef struct cmd_history 220 { 221 PJ_DECL_LIST_MEMBER(struct cmd_history); 222 pj_str_t command; 223 } cmd_history; 224 225 typedef 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; 58 242 59 243 struct cli_telnet_fe … … 71 255 }; 72 256 257 /* Forward Declaration */ 258 static pj_status_t telnet_sess_send2(cli_telnet_sess *sess, 259 const unsigned char *str, int len); 260 261 static 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 */ 268 static unsigned recv_buf_right_len(telnet_recv_buf *recv_buf) 269 { 270 return (recv_buf->len - recv_buf->cur_pos); 271 } 272 273 static 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 301 static 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 318 static 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 336 static 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 342 static 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 380 static 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 407 static 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 */ 429 static 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 */ 472 static 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 508 static 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 514 static 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 520 static 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 526 static 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 */ 537 static 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 */ 585 static 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 624 static pj_bool_t receive_do(cli_telnet_sess *sess, unsigned char option) 625 { 626 return receive_enable_option(sess, PJ_TRUE, option); 627 } 628 629 static pj_bool_t receive_dont(cli_telnet_sess *sess, unsigned char option) 630 { 631 return receive_disable_option(sess, PJ_TRUE, option); 632 } 633 634 static pj_bool_t receive_will(cli_telnet_sess *sess, unsigned char option) 635 { 636 return receive_enable_option(sess, PJ_FALSE, option); 637 } 638 639 static pj_bool_t receive_wont(cli_telnet_sess *sess, unsigned char option) 640 { 641 return receive_disable_option(sess, PJ_FALSE, option); 642 } 643 644 static 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 651 static 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 658 static 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 664 static 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 670 static void send_return_key(cli_telnet_sess *sess) 671 { 672 telnet_sess_send2(sess, (unsigned char*)"\r\n", 2); 673 } 674 675 static void send_bell(cli_telnet_sess *sess) { 676 unsigned char bell[1] = {0x07}; 677 telnet_sess_send2(sess, &bell[0], 1); 678 } 679 680 static 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 694 static 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 727 static 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 736 static 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 745 static 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 829 static 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 845 static 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 862 static 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 880 static 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 940 static 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 986 static 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 996 static 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 1007 static 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 1044 static 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 73 1085 PJ_DEF(void) pj_cli_telnet_cfg_default(pj_cli_telnet_cfg *param) 74 1086 { … … 80 1092 } 81 1093 82 83 1094 /* Send a message to a telnet session */ 84 static pj_status_t telnet_sess_send( structcli_telnet_sess *sess,1095 static pj_status_t telnet_sess_send(cli_telnet_sess *sess, 85 1096 const pj_str_t *str) 86 1097 { … … 110 1121 pj_memmove(sess->buf + sess->buf_len, str->ptr, clen); 111 1122 if (clen < sz) { 112 pj_ansi_snprintf( sess->buf + CLI_TELNET_BUF_SIZE,1123 pj_ansi_snprintf((char *)sess->buf + CLI_TELNET_BUF_SIZE, 113 1124 MAX_CUT_MSG_LEN, CUT_MSG); 114 1125 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); 116 1127 } else 117 1128 sess->buf_len += clen; … … 126 1137 } 127 1138 128 static pj_status_t telnet_sess_send2( structcli_telnet_sess *sess,129 const char *str, int len)1139 static pj_status_t telnet_sess_send2(cli_telnet_sess *sess, 1140 const unsigned char *str, int len) 130 1141 { 131 1142 pj_str_t s; … … 137 1148 static void cli_telnet_sess_destroy(pj_cli_sess *sess) 138 1149 { 139 struct cli_telnet_sess *tsess = (structcli_telnet_sess *)sess;1150 cli_telnet_sess *tsess = (cli_telnet_sess *)sess; 140 1151 pj_mutex_t *mutex = ((struct cli_telnet_fe *)sess->fe)->mutex; 141 1152 … … 161 1172 sess = tfe->sess_head.next; 162 1173 while (sess != &tfe->sess_head) { 163 struct cli_telnet_sess *tsess = (structcli_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); 168 1179 } 169 1180 … … 214 1225 pj_ssize_t sent) 215 1226 { 216 struct cli_telnet_sess *sess = (structcli_telnet_sess *)217 1227 cli_telnet_sess *sess = (cli_telnet_sess *) 1228 pj_activesock_get_user_data(asock); 218 1229 219 1230 PJ_UNUSED_ARG(op_key); 220 1231 221 1232 if (sent <= 0) { 222 pj_cli_ end_session(&sess->base);1233 pj_cli_sess_end_session(&sess->base); 223 1234 return PJ_FALSE; 224 1235 } … … 232 1243 if (telnet_sess_send2(sess, sess->buf, len) != PJ_SUCCESS) { 233 1244 pj_mutex_unlock(sess->smutex); 234 pj_cli_ end_session(&sess->base);1245 pj_cli_sess_end_session(&sess->base); 235 1246 return PJ_FALSE; 236 1247 } … … 248 1259 pj_size_t *remainder) 249 1260 { 250 struct cli_telnet_sess *sess = (structcli_telnet_sess *)251 1261 cli_telnet_sess *sess = (cli_telnet_sess *) 1262 pj_activesock_get_user_data(asock); 252 1263 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; 254 1266 255 1267 PJ_UNUSED_ARG(size); … … 257 1269 258 1270 if (status != PJ_SUCCESS && status != PJ_EPENDING) { 259 pj_cli_ end_session(&sess->base);1271 pj_cli_sess_end_session(&sess->base); 260 1272 return PJ_FALSE; 261 1273 } … … 266 1278 pj_mutex_lock(sess->smutex); 267 1279 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); 326 1363 } 327 1364 … … 329 1366 330 1367 return PJ_TRUE; 331 332 on_exit:333 pj_mutex_unlock(sess->smutex);334 pj_cli_end_session(&sess->base);335 return PJ_FALSE;336 1368 } 337 1369 … … 345 1377 pj_status_t sstatus; 346 1378 pj_pool_t *pool; 347 structcli_telnet_sess *sess;1379 cli_telnet_sess *sess; 348 1380 pj_activesock_cb asock_cb; 349 1381 … … 364 1396 } 365 1397 366 sess = PJ_POOL_ZALLOC_T(pool, structcli_telnet_sess);1398 sess = PJ_POOL_ZALLOC_T(pool, cli_telnet_sess); 367 1399 sess->pool = pool; 368 1400 sess->base.fe = &fe->base; … … 373 1405 asock_cb.on_data_read = &telnet_sess_on_data_read; 374 1406 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; 375 1411 376 1412 sstatus = pj_mutex_create_recursive(pool, "mutex_telnet_sess", … … 387 1423 } 388 1424 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); 406 1446 407 1447 /* Start reading for input from the new telnet session */ … … 462 1502 fe->base.type = PJ_CLI_TELNET_FRONT_END; 463 1503 fe->base.op->on_write_log = &cli_telnet_fe_write_log; 464 // fe->base.op->on_quit = &cli_telnet_fe_quit;465 1504 fe->base.op->on_destroy = &cli_telnet_fe_destroy; 466 1505 fe->pool = pool; … … 497 1536 PJ_LOG(3, (THIS_FILE, "CLI telnet daemon listening at port %d", 498 1537 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 } 499 1548 } else { 500 1549 PJ_LOG(3, (THIS_FILE, "Failed binding the socket"));
Note: See TracChangeset
for help on using the changeset viewer.