From b10946c96d87e3de3a5a3ea166ef365d30a9bc9d Mon Sep 17 00:00:00 2001 From: Sean Middleditch Date: Sun, 22 Mar 2009 18:21:14 -0400 Subject: [PATCH] dont use a separate event for ZMP --- README | 26 +++++++++++++------- libtelnet.c | 66 ++++++++++++++++++++++++++++++-------------------- libtelnet.h | 1 - telnet-proxy.c | 34 +++++++++++++++++++------- 4 files changed, 82 insertions(+), 45 deletions(-) diff --git a/README b/README index a062b24..035fcc0 100644 --- a/README +++ b/README @@ -402,6 +402,14 @@ IId. Event Handling A subnegotiation should never be sent unless the specific option has been enabled through the use of the telnet negotiation feature. + + ZMP SUPPORT: + The event->argc field is the number of ZMP parameters, including + the command name, that have been received. The event->argv field + is an array of strings, one for each ZMP parameter. The command + name will be in event->argv[0]. If the ZMP command could not be + parsed because it was malformed, event->argc will be 0 (zero) and + event->argv will be NULL. TELNET_EV_COMPRESS The COMPRESS event notifies the app that COMPRESS2/MCCP2 @@ -411,13 +419,6 @@ IId. Event Handling The event->command value will be 1 if compression has started and will be 0 if compression has ended. - TELNET_EV_ZMP - The ZMP event is sent whenever a ZMP command has been received. - The event->argc field is the number of ZMP parameters, including - the command name, that have been received. The event->argv field - is an array of strings, one for each ZMP parameter. The command - name will be in event->argv[0]. - TELNET_EV_WARNING The WARNING event is sent whenever something has gone wrong inside of libtelnet (possibly due to malformed data sent by the other @@ -529,8 +530,15 @@ enables the client to send ZMP commands. The client must never attempt to negotiate ZMP directly using telnet_negotiate(). Once ZMP is enabled, any ZMP commands received will automatically be -sent to the event handler function with the TELNET_EV_ZMP event -code. +sent to the event handler function with the TELNET_EV_SUBNEGOTIATION +event code. The command will automatically be parsed and the ZMP +parameters will be placed in the event->argv array and the number of +parameters will be placed in the event->argc field. + +NOTE: if an error occured while parsing the ZMP command because it +was malformed, the event->argc field will be equal to 0 and the +event->argv field will be NULL. You should always check for this +before attempting to access the parameter array. To send ZMP commands to the remote end, use either telnet_send_zmp() or telnet_send_zmpv(). diff --git a/libtelnet.c b/libtelnet.c index 5eff06a..ba08c73 100644 --- a/libtelnet.c +++ b/libtelnet.c @@ -408,46 +408,53 @@ static void _negotiate(telnet_t *telnet, unsigned char telopt) { * must be aborted and reprocessed due to COMPRESS2 being activated */ static int _subnegotiate(telnet_t *telnet) { - /* invoke callback */ - _event(telnet, TELNET_EV_SUBNEGOTIATION, 0, telnet->sb_telopt, - telnet->buffer, telnet->buffer_pos, 0, 0); + const char **argv; + const char *c; + size_t i, argc; + switch (telnet->sb_telopt) { +#ifdef HAVE_ZLIB /* received COMPRESS2 begin marker, setup our zlib box and * start handling the compressed stream if it's not already. */ -#ifdef HAVE_ZLIB - if (telnet->sb_telopt == TELNET_TELOPT_COMPRESS2) { - if (_init_zlib(telnet, 0, 1) != TELNET_EOK) - return 0; + case TELNET_TELOPT_COMPRESS2: + if (telnet->sb_telopt == TELNET_TELOPT_COMPRESS2) { + if (_init_zlib(telnet, 0, 1) != TELNET_EOK) + return 0; - /* notify app that compression was enabled */ - _event(telnet, TELNET_EV_COMPRESS, 1, 0, 0, 0, 0, 0); - return 1; - } + /* standard SB notification */ + _event(telnet, TELNET_EV_SUBNEGOTIATION, 0, telnet->sb_telopt, + telnet->buffer, telnet->buffer_pos, 0, 0); + + /* notify app that compression was enabled */ + _event(telnet, TELNET_EV_COMPRESS, 1, 0, 0, 0, 0, 0); + return 1; + } + break; #endif /* HAVE_ZLIB */ - - /* parse ZMP args */ - if (telnet->sb_telopt == TELNET_TELOPT_ZMP) { - const char **argv; - const char *c = telnet->buffer; - size_t i, argc = 0; - + /* ZMP command */ + case TELNET_TELOPT_ZMP: /* make sure this is a valid ZMP buffer */ - if (telnet->buffer_pos == 0 || telnet->buffer[telnet->buffer_pos - 1] - != 0) + if (telnet->buffer_pos == 0 || + telnet->buffer[telnet->buffer_pos - 1] != 0) { + _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0, + "incomplete ZMP frame"); + _event(telnet, TELNET_EV_SUBNEGOTIATION, 0, telnet->sb_telopt, + telnet->buffer, telnet->buffer_pos, 0, 0); return 0; + } /* count arguments */ - while (c != telnet->buffer + telnet->buffer_pos) { - ++argc; + for (argc = 0, c = telnet->buffer; c != telnet->buffer + + telnet->buffer_pos; ++argc) c += strlen(c) + 1; - } /* allocate argument array, bail on error */ if ((argv = (const char **)malloc(sizeof(char *) * argc)) == 0) { _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0, "malloc() failed: %s", strerror(errno)); - return 0; + _event(telnet, TELNET_EV_SUBNEGOTIATION, 0, telnet->sb_telopt, + telnet->buffer, telnet->buffer_pos, 0, 0); } /* populate argument array */ @@ -456,11 +463,18 @@ static int _subnegotiate(telnet_t *telnet) { c += strlen(c) + 1; } - /* invoke ZMP event */ - _event(telnet, TELNET_EV_ZMP, 0, 0, 0, 0, argv, argc); + /* invoke event with our arguments */ + _event(telnet, TELNET_EV_SUBNEGOTIATION, 0, telnet->sb_telopt, + telnet->buffer, telnet->buffer_pos, argv, argc); /* free argument array */ free(argv); + break; + /* other generic subnegotiation */ + default: + _event(telnet, TELNET_EV_SUBNEGOTIATION, 0, telnet->sb_telopt, + telnet->buffer, telnet->buffer_pos, 0, 0); + break; } return 0; diff --git a/libtelnet.h b/libtelnet.h index 54289d9..48b400f 100644 --- a/libtelnet.h +++ b/libtelnet.h @@ -137,7 +137,6 @@ enum telnet_event_type_t { TELNET_EV_DONT, TELNET_EV_SUBNEGOTIATION, TELNET_EV_COMPRESS, - TELNET_EV_ZMP, TELNET_EV_WARNING, TELNET_EV_ERROR }; diff --git a/telnet-proxy.c b/telnet-proxy.c index 9600c3f..7d83b4a 100644 --- a/telnet-proxy.c +++ b/telnet-proxy.c @@ -224,14 +224,33 @@ static void _event_handler(telnet_t *telnet, telnet_event_t *ev, break; /* subnegotiation */ case TELNET_EV_SUBNEGOTIATION: - printf("%s SUB %d (%s)", conn->name, (int)ev->telopt, - get_opt(ev->telopt)); - if (ev->size > 0) { - printf(" [%zi]: ", ev->size); - print_buffer(ev->buffer, ev->size); + if (ev->telopt == TELNET_TELOPT_ZMP) { + if (ev->argc != 0) { + size_t i; + printf("%s ZMP [%zi params]", conn->name, ev->argc); + for (i = 0; i != ev->argc; ++i) { + printf(" \""); + print_buffer(ev->argv[i], strlen(ev->argv[i])); + printf("\""); + } + printf(COLOR_NORMAL "\n"); + } else { + printf("%s ZMP (malformed!) [%zi bytes]", + conn->name, ev->size); + print_buffer(ev->buffer, ev->size); + printf(COLOR_NORMAL "\n"); + } + } else { + printf("%s SUB %d (%s)", conn->name, (int)ev->telopt, + get_opt(ev->telopt)); + if (ev->size > 0) { + printf(" [%zi bytes]: ", ev->size); + print_buffer(ev->buffer, ev->size); + } + printf(COLOR_NORMAL "\n"); } - printf(COLOR_NORMAL "\n"); + /* forward */ telnet_subnegotiation(&conn->remote->telnet, ev->telopt, ev->buffer, ev->size); break; @@ -240,9 +259,6 @@ static void _event_handler(telnet_t *telnet, telnet_event_t *ev, printf("%s COMPRESSION %s" COLOR_NORMAL "\n", conn->name, ev->command ? "ON" : "OFF"); break; - /* ZMP command (ignored in PROXY mode) */ - case TELNET_EV_ZMP: - break; /* warning */ case TELNET_EV_WARNING: printf("%s WARNING: %s" COLOR_NORMAL "\n", conn->name, ev->buffer);