mirror of https://gerrit.osmocom.org/libtelnet
various telnet-client updates making it capable of real use for vim/nethack/etc. on a real telnet server
This commit is contained in:
parent
5cf66661e5
commit
a7896d1117
|
@ -19,6 +19,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#ifdef HAVE_ZLIB
|
#ifdef HAVE_ZLIB
|
||||||
|
@ -27,6 +28,13 @@
|
||||||
|
|
||||||
#include "libtelnet.h"
|
#include "libtelnet.h"
|
||||||
|
|
||||||
|
static struct termios orig_tios;
|
||||||
|
static int do_echo;
|
||||||
|
|
||||||
|
static void _cleanup(void) {
|
||||||
|
tcsetattr(STDOUT_FILENO, TCSADRAIN, &orig_tios);
|
||||||
|
}
|
||||||
|
|
||||||
static void _send(int sock, unsigned char *buffer, unsigned int size) {
|
static void _send(int sock, unsigned char *buffer, unsigned int size) {
|
||||||
int rs;
|
int rs;
|
||||||
|
|
||||||
|
@ -61,11 +69,68 @@ static void _event_handler(struct libtelnet_t *telnet,
|
||||||
break;
|
break;
|
||||||
/* accept any options we want */
|
/* accept any options we want */
|
||||||
case LIBTELNET_EV_NEGOTIATE:
|
case LIBTELNET_EV_NEGOTIATE:
|
||||||
/* enable COMPRESS2 */
|
switch (ev->command) {
|
||||||
if (ev->command == LIBTELNET_WILL &&
|
case LIBTELNET_WILL:
|
||||||
ev->telopt == LIBTELNET_TELOPT_COMPRESS2)
|
switch (ev->telopt) {
|
||||||
|
/* accept request to enable compression */
|
||||||
|
case LIBTELNET_TELOPT_COMPRESS2:
|
||||||
libtelnet_send_negotiate(telnet, LIBTELNET_DO, ev->telopt);
|
libtelnet_send_negotiate(telnet, LIBTELNET_DO, ev->telopt);
|
||||||
break;
|
break;
|
||||||
|
/* server "promises" to echo, so turn off local echo */
|
||||||
|
case LIBTELNET_TELOPT_ECHO:
|
||||||
|
do_echo = 0;
|
||||||
|
libtelnet_send_negotiate(telnet, LIBTELNET_DO, ev->telopt);
|
||||||
|
break;
|
||||||
|
/* unknown -- reject */
|
||||||
|
default:
|
||||||
|
libtelnet_send_negotiate(telnet, LIBTELNET_DONT, ev->telopt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LIBTELNET_WONT:
|
||||||
|
switch (ev->telopt) {
|
||||||
|
/* server wants us to do echoing, by telling us it won't */
|
||||||
|
case LIBTELNET_TELOPT_ECHO:
|
||||||
|
do_echo = 1;
|
||||||
|
libtelnet_send_negotiate(telnet, LIBTELNET_DONT, ev->telopt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LIBTELNET_DO:
|
||||||
|
switch (ev->telopt) {
|
||||||
|
/* accept request to enable terminal-type requests */
|
||||||
|
case LIBTELNET_TELOPT_TTYPE:
|
||||||
|
libtelnet_send_negotiate(telnet, LIBTELNET_WILL, ev->telopt);
|
||||||
|
break;
|
||||||
|
/* unknown - reject */
|
||||||
|
default:
|
||||||
|
libtelnet_send_negotiate(telnet, LIBTELNET_WONT, ev->telopt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LIBTELNET_DONT:
|
||||||
|
/* ignore for now */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
/* respond to particular subnegotiations */
|
||||||
|
case LIBTELNET_EV_SUBNEGOTIATION:
|
||||||
|
/* respond with our terminal type */
|
||||||
|
if (ev->telopt == LIBTELNET_TELOPT_TTYPE) {
|
||||||
|
/* NOTE: we just assume the server sent a legitimate
|
||||||
|
* sub-negotiation, as there really isn't anything else
|
||||||
|
* it's allowed to send
|
||||||
|
*/
|
||||||
|
char buffer[64];
|
||||||
|
buffer[0] = 0; /* IS code for RFC 1091 */
|
||||||
|
snprintf(buffer + 1, sizeof(buffer) - 1, "%s", getenv("TERM"));
|
||||||
|
libtelnet_send_subnegotiation(telnet, LIBTELNET_TELOPT_TTYPE,
|
||||||
|
(unsigned char *)buffer, 1 + strlen(buffer + 1));
|
||||||
|
}
|
||||||
|
break;
|
||||||
/* error */
|
/* error */
|
||||||
case LIBTELNET_EV_ERROR:
|
case LIBTELNET_EV_ERROR:
|
||||||
fprintf(stderr, "ERROR: %.*s\n", ev->size, ev->buffer);
|
fprintf(stderr, "ERROR: %.*s\n", ev->size, ev->buffer);
|
||||||
|
@ -85,6 +150,7 @@ int main(int argc, char **argv) {
|
||||||
struct libtelnet_t telnet;
|
struct libtelnet_t telnet;
|
||||||
struct addrinfo *ai;
|
struct addrinfo *ai;
|
||||||
struct addrinfo hints;
|
struct addrinfo hints;
|
||||||
|
struct termios tios;
|
||||||
|
|
||||||
/* check usage */
|
/* check usage */
|
||||||
if (argc != 3) {
|
if (argc != 3) {
|
||||||
|
@ -125,6 +191,18 @@ int main(int argc, char **argv) {
|
||||||
/* free address lookup info */
|
/* free address lookup info */
|
||||||
freeaddrinfo(ai);
|
freeaddrinfo(ai);
|
||||||
|
|
||||||
|
/* get current terminal settings, set raw mode, make sure we
|
||||||
|
* register atexit handler to restore terminal settings
|
||||||
|
*/
|
||||||
|
tcgetattr(STDOUT_FILENO, &orig_tios);
|
||||||
|
atexit(_cleanup);
|
||||||
|
tios = orig_tios;
|
||||||
|
cfmakeraw(&tios);
|
||||||
|
tcsetattr(STDOUT_FILENO, TCSADRAIN, &tios);
|
||||||
|
|
||||||
|
/* set input echoing on by default */
|
||||||
|
do_echo = 1;
|
||||||
|
|
||||||
/* initialize telnet box */
|
/* initialize telnet box */
|
||||||
libtelnet_init(&telnet, _event_handler, LIBTELNET_MODE_CLIENT, &sock);
|
libtelnet_init(&telnet, _event_handler, LIBTELNET_MODE_CLIENT, &sock);
|
||||||
|
|
||||||
|
@ -140,6 +218,11 @@ int main(int argc, char **argv) {
|
||||||
/* read from stdin */
|
/* read from stdin */
|
||||||
if (pfd[0].revents & POLLIN) {
|
if (pfd[0].revents & POLLIN) {
|
||||||
if ((rs = read(STDIN_FILENO, buffer, sizeof(buffer))) > 0) {
|
if ((rs = read(STDIN_FILENO, buffer, sizeof(buffer))) > 0) {
|
||||||
|
/* local echo */
|
||||||
|
if (do_echo)
|
||||||
|
write(STDOUT_FILENO, buffer, rs);
|
||||||
|
|
||||||
|
/* send over the wire */
|
||||||
libtelnet_send_data(&telnet, buffer, rs);
|
libtelnet_send_data(&telnet, buffer, rs);
|
||||||
} else if (rs == 0) {
|
} else if (rs == 0) {
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue