root/src/dps8/libtelnet.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _send
  2. _check_telopt
  3. _get_rfc1143
  4. _set_rfc1143
  5. _send_negotiate
  6. _negotiate
  7. _environ_telnet
  8. _ttype_telnet
  9. _subnegotiate
  10. telnet_init
  11. telnet_free
  12. _buffer_byte
  13. _process
  14. telnet_recv
  15. telnet_iac
  16. telnet_negotiate
  17. telnet_send
  18. telnet_send_text
  19. telnet_begin_sb
  20. telnet_vprintf
  21. telnet_printf
  22. telnet_raw_vprintf
  23. telnet_raw_printf

   1 /*
   2  * vim: filetype=c:tabstop=4:ai:expandtab
   3  * SPDX-License-Identifier: CC-PDDC
   4  * SPDX-FileCopyrightText: Public domain
   5  * scspell-id: 845a8edb-f62f-11ec-a0d8-80ee73e9b8e7
   6  *
   7  * ---------------------------------------------------------------------------
   8  *
   9  * libTELNET - TELNET protocol handling library
  10  *
  11  * Sean Middleditch <sean@sourcemud.org>
  12  *
  13  * The author or authors of this code dedicate any and all copyright
  14  * interest in this code to the public domain. We make this dedication
  15  * for the benefit of the public at large and to the detriment of our heirs
  16  * and successors. We intend this dedication to be an overt act of
  17  * relinquishment in perpetuity of all present and future rights to this
  18  * code under copyright law.
  19  *
  20  * ---------------------------------------------------------------------------
  21  */
  22 
  23 /*
  24  * The person or persons who have associated work with this document
  25  * (the "Dedicator" or "Certifier") hereby either (a) certifies that,
  26  * to the best of his knowledge, the work of authorship identified
  27  * is in the public domain of the country from which the work is
  28  * published, or (b) hereby dedicates whatever copyright the dedicators
  29  * holds in the work of authorship identified below (the "Work") to the
  30  * public domain. A certifier, moreover, dedicates any copyright
  31  * interest he may have in the associated work, and for these purposes,
  32  * is described as a "dedicator" below.
  33  *
  34  * A certifier has taken reasonable steps to verify the copyright
  35  * status of this work. Certifier recognizes that his good faith
  36  * efforts may not shield him from liability if in fact the work
  37  * certified is not in the public domain.
  38  *
  39  * Dedicator makes this dedication for the benefit of the public at
  40  * large and to the detriment of the Dedicator's heirs and successors.
  41  * Dedicator intends this dedication to be an overt act of
  42  * relinquishment in perpetuity of all present and future rights under
  43  * copyright law, whether vested or contingent, in the Work. Dedicator
  44  * understands that such relinquishment of all rights includes the
  45  * relinquishment of all rights to enforce (by lawsuit or otherwise)
  46  * those copyrights in the Work.
  47  *
  48  * Dedicator recognizes that, once placed in the public domain, the
  49  * Work may be freely reproduced, distributed, transmitted, used,
  50  * modified, built upon, or otherwise exploited by anyone for any
  51  * purpose, commercial or non-commercial, and in any way, including by
  52  * methods that have not yet been invented or conceived.
  53  */
  54 
  55 #include <stdlib.h>
  56 #include <string.h>
  57 #include <stdio.h>
  58 #include <errno.h>
  59 #include <string.h>
  60 #include <stdarg.h>
  61 
  62 #ifdef __GNUC__
  63 # define NO_RETURN   __attribute__ ((noreturn))
  64 # define UNUSED      __attribute__ ((unused))
  65 #else
  66 # define NO_RETURN
  67 # define UNUSED
  68 #endif
  69 
  70 /* Win32 compatibility */
  71 #if defined(_WIN32)
  72 # define __func__ __FUNCTION__
  73 # if defined(_MSC_VER)
  74 #  if _MSC_VER <= 1700
  75 #   define va_copy(dest, src) (dest = src)
  76 #  endif
  77 # endif
  78 #endif
  79 
  80 #include "libtelnet.h"
  81 
  82 #undef FREE
  83 #define FREE(p) do  \
  84   {                 \
  85     free((p));      \
  86     (p) = NULL;     \
  87   } while(0)
  88 
  89 #ifdef TESTING
  90 # undef realloc
  91 # undef FREE
  92 # define FREE(p) free(p)
  93 # define realloc trealloc
  94 #endif /* ifdef TESTING */
  95 
  96 /* helper for Q-method option tracking */
  97 #define Q_US(q)    ((q).state & 0x0F)
  98 #define Q_HIM(q)  (((q).state & 0xF0) >> 4)
  99 #define Q_MAKE(us,him) ((us) | ((him) << 4))
 100 
 101 /* helper for the negotiation routines */
 102 #define NEGOTIATE_EVENT(telnet,cmd,opt) \
 103         ev.type = (cmd);                \
 104         ev.neg.telopt = (opt);          \
 105         (telnet)->eh((telnet), &ev, (telnet)->ud);
 106 
 107 /* telnet state codes */
 108 enum telnet_state_t {
 109         TELNET_STATE_DATA = 0,
 110         TELNET_STATE_EOL,
 111         TELNET_STATE_IAC,
 112         TELNET_STATE_WILL,
 113         TELNET_STATE_WONT,
 114         TELNET_STATE_DO,
 115         TELNET_STATE_DONT,
 116         TELNET_STATE_SB,
 117         TELNET_STATE_SB_DATA,
 118         TELNET_STATE_SB_DATA_IAC
 119 };
 120 typedef enum telnet_state_t telnet_state_t;
 121 
 122 /* telnet state tracker */
 123 struct telnet_t {
 124         /* user data */
 125         void *ud;
 126         /* telopt support table */
 127         const telnet_telopt_t *telopts;
 128         /* event handler */
 129         telnet_event_handler_t eh;
 130         /* RFC-1143 option negotiation states */
 131         struct telnet_rfc1143_t *q;
 132         /* sub-request buffer */
 133         char *buffer;
 134         /* current size of the buffer */
 135         size_t buffer_size;
 136         /* current buffer write position (also length of buffer data) */
 137         size_t buffer_pos;
 138         /* current state */
 139         enum telnet_state_t state;
 140         /* option flags */
 141         unsigned char flags;
 142         /* current subnegotiation telopt */
 143         unsigned char sb_telopt;
 144         /* length of RFC-1143 queue */
 145         unsigned int q_size;
 146         /* number of entries in RFC-1143 queue */
 147         unsigned int q_cnt;
 148 };
 149 
 150 /* RFC-1143 option negotiation state */
 151 typedef struct telnet_rfc1143_t {
 152         unsigned char telopt;
 153         unsigned char state;
 154 } telnet_rfc1143_t;
 155 
 156 /* RFC-1143 state names */
 157 #define Q_NO         0
 158 #define Q_YES        1
 159 #define Q_WANTNO     2
 160 #define Q_WANTYES    3
 161 #define Q_WANTNO_OP  4
 162 #define Q_WANTYES_OP 5
 163 
 164 /* telnet NVT EOL sequences */
 165 static const char CRLF[]  = { '\r', '\n' };
 166 static const char CRNUL[] = { '\r', '\0' };
 167 
 168 /* buffer sizes */
 169 static const size_t _buffer_sizes[] = { 0, 512, 2048, 8192, 16384, };
 170 static const size_t _buffer_sizes_count = sizeof(_buffer_sizes) /
 171                                           sizeof(_buffer_sizes[0]);
 172 
 173 /* error generation function */
 174 static telnet_error_t _error(telnet_t *telnet, unsigned line,
 175                              const char* func, telnet_error_t err,
 176                              int fatal, const char *fmt, ...) {
 177         telnet_event_t ev;
 178         char buffer[512];
 179         va_list va;
 180 
 181         /* format informational text */
 182         va_start(va, fmt);
 183         vsnprintf(buffer, sizeof(buffer), fmt, va);
 184         va_end(va);
 185 
 186         /* send error event to the user */
 187         ev.type       = fatal ? TELNET_EV_ERROR : TELNET_EV_WARNING;
 188         ev.error.file = __FILE__;
 189         ev.error.func = func;
 190         ev.error.line = (int) line;
 191         ev.error.msg  = buffer;
 192         telnet->eh(telnet, &ev, telnet->ud);
 193 
 194         return err;
 195 }
 196 
 197 /* push bytes out */
 198 static void _send(telnet_t *telnet, const char *buffer,
     /* [previous][next][first][last][top][bottom][index][help] */
 199                   size_t size) {
 200         telnet_event_t ev;
 201 
 202         ev.type        = TELNET_EV_SEND;
 203         ev.data.buffer = buffer;
 204         ev.data.size   = size;
 205         telnet->eh(telnet, &ev, telnet->ud);
 206 }
 207 
 208 /* to send bags of unsigned chars */
 209 #define _sendu(t, d, s) _send((t), (const char*)(d), (s))
 210 
 211 /*
 212  * check if we support a particular telopt; if us is non-zero, we
 213  * check if we (local) supports it, otherwise we check if he (remote)
 214  * supports it.  return non-zero if supported, zero if not supported.
 215  */
 216 
 217 static __inline__ int _check_telopt(telnet_t *telnet, unsigned char telopt,
     /* [previous][next][first][last][top][bottom][index][help] */
 218                                     int us) {
 219         int i;
 220 
 221         /* if we have no telopts table, we obviously don't support it */
 222         if (telnet->telopts == 0)
 223                 return 0;
 224 
 225         /* loop until found or end marker (us and him both 0) */
 226         for (i = 0; telnet->telopts[i].telopt != -1; ++i) {
 227                 if (telnet->telopts[i].telopt == telopt) {
 228                         if (us && telnet->telopts[i].us == TELNET_WILL)
 229                                 return 1;
 230                         else if (!us && telnet->telopts[i].him == TELNET_DO)
 231                                 return 1;
 232                         else
 233                                 return 0;
 234                 }
 235         }
 236 
 237         /* not found, so not supported */
 238         return 0;
 239 }
 240 
 241 /* retrieve RFC-1143 option state */
 242 static __inline__ telnet_rfc1143_t _get_rfc1143(telnet_t *telnet,
     /* [previous][next][first][last][top][bottom][index][help] */
 243                                                 unsigned char telopt) {
 244         telnet_rfc1143_t empty;
 245         unsigned int i;
 246 
 247         /* search for entry */
 248         for (i = 0; i != telnet->q_cnt; ++i) {
 249                 if (telnet->q[i].telopt == telopt) {
 250                         return telnet->q[i];
 251                 }
 252         }
 253 
 254         /* not found, return empty value */
 255         empty.telopt = telopt;
 256         empty.state  = 0;
 257         return empty;
 258 }
 259 
 260 /* save RFC-1143 option state */
 261 static __inline__ void _set_rfc1143(telnet_t *telnet, unsigned char telopt,
     /* [previous][next][first][last][top][bottom][index][help] */
 262                                     unsigned char us, unsigned char him) {
 263         telnet_rfc1143_t *qtmp;
 264         unsigned int i;
 265 
 266         /* search for entry */
 267         for (i = 0; i != telnet->q_cnt; ++i) {
 268                 if (telnet->q[i].telopt == telopt) {
 269                         telnet->q[i].state = (unsigned char) Q_MAKE(us,him);
 270                         if (telopt != TELNET_TELOPT_BINARY)
 271                                 return;
 272                         telnet->flags &=
 273                             (unsigned char)~(TELNET_FLAG_TRANSMIT_BINARY |
 274                                              TELNET_FLAG_RECEIVE_BINARY);
 275                         if (us == Q_YES)
 276                                 telnet->flags |= TELNET_FLAG_TRANSMIT_BINARY;
 277                         if (him == Q_YES)
 278                                 telnet->flags |= TELNET_FLAG_RECEIVE_BINARY;
 279                         return;
 280                 }
 281         }
 282 
 283         /*
 284          * we're going to need to track state for it, so grow the queue
 285          * by 4 (four) elements and put the telopt into it; bail on allocation
 286          * error.  we go by four because it seems like a reasonable guess as
 287          * to the number of enabled options for most simple code, and it
 288          * allows for an acceptable number of reallocations for complex code.
 289          */
 290 
 291 #define QUANTUM 4
 292     /* Did we reach the end of the table? */
 293        if (i >= telnet->q_size) {
 294                /* Expand the size */
 295                if ((qtmp = (telnet_rfc1143_t *)realloc(telnet->q,
 296                        sizeof(telnet_rfc1143_t) * (telnet->q_size + QUANTUM))) == 0) {
 297                        _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
 298                                        "realloc() failed: %s", strerror(errno));
 299                        return;
 300                }
 301                memset(&qtmp[telnet->q_size], 0, sizeof(telnet_rfc1143_t) * QUANTUM);
 302                telnet->q       = qtmp;
 303                telnet->q_size += QUANTUM;
 304         }
 305        /* Add entry to end of table */
 306        telnet->q[telnet->q_cnt].telopt = telopt;
 307        telnet->q[telnet->q_cnt].state  = (unsigned char) Q_MAKE(us, him);
 308        telnet->q_cnt ++;
 309 }
 310 
 311 /* send negotiation bytes */
 312 static __inline__ void _send_negotiate(telnet_t *telnet, unsigned char cmd,
     /* [previous][next][first][last][top][bottom][index][help] */
 313                                        unsigned char telopt) {
 314         unsigned char bytes[3];
 315         bytes[0] = TELNET_IAC;
 316         bytes[1] = cmd;
 317         bytes[2] = telopt;
 318         _sendu(telnet, bytes, 3);
 319 }
 320 
 321 /* negotiation handling magic for RFC-1143 */
 322 static void _negotiate(telnet_t *telnet, unsigned char telopt) {
     /* [previous][next][first][last][top][bottom][index][help] */
 323         telnet_event_t ev;
 324         telnet_rfc1143_t q;
 325 
 326         /* in PROXY mode, just pass it thru and do nothing */
 327         if (telnet->flags & TELNET_FLAG_PROXY) {
 328                 switch ((int)telnet->state) {
 329                 case TELNET_STATE_WILL:
 330                         NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
 331                         break;
 332                 case TELNET_STATE_WONT:
 333                         NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
 334                         break;
 335                 case TELNET_STATE_DO:
 336                         NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
 337                         break;
 338                 case TELNET_STATE_DONT:
 339                         NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt);
 340                         break;
 341                 }
 342                 return;
 343         }
 344 
 345         /* lookup the current state of the option */
 346         q = _get_rfc1143(telnet, telopt);
 347 
 348         /* start processing... */
 349         switch ((int)telnet->state) {
 350         /* request to enable option on remote end or confirm DO */
 351         case TELNET_STATE_WILL:
 352                 switch (Q_HIM(q)) {
 353                 case Q_NO:
 354                         if (_check_telopt(telnet, telopt, 0)) {
 355                                 _set_rfc1143(telnet, telopt, Q_US(q), Q_YES);
 356                                 _send_negotiate(telnet, TELNET_DO, telopt);
 357                                 NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
 358                         } else
 359                                 _send_negotiate(telnet, TELNET_DONT, telopt);
 360                         break;
 361                 case Q_WANTNO:
 362                         _set_rfc1143(telnet, telopt, Q_US(q), Q_NO);
 363                         NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
 364                         _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 365                                         "DONT answered by WILL");
 366                         break;
 367                 case Q_WANTNO_OP:
 368                         _set_rfc1143(telnet, telopt, Q_US(q), Q_YES);
 369                         _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 370                                         "DONT answered by WILL");
 371                         break;
 372                 case Q_WANTYES:
 373                         _set_rfc1143(telnet, telopt, Q_US(q), Q_YES);
 374                         NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
 375                         break;
 376                 case Q_WANTYES_OP:
 377                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTNO);
 378                         _send_negotiate(telnet, TELNET_DONT, telopt);
 379                         NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
 380                         break;
 381                 }
 382                 break;
 383 
 384         /* request to disable option on remote end, confirm DONT, reject DO */
 385         case TELNET_STATE_WONT:
 386                 switch (Q_HIM(q)) {
 387                 case Q_YES:
 388                         _set_rfc1143(telnet, telopt, Q_US(q), Q_NO);
 389                         _send_negotiate(telnet, TELNET_DONT, telopt);
 390                         NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
 391                         break;
 392                 case Q_WANTNO:
 393                         _set_rfc1143(telnet, telopt, Q_US(q), Q_NO);
 394                         NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
 395                         break;
 396                 case Q_WANTNO_OP:
 397                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES);
 398                         _send_negotiate(telnet, TELNET_DO, telopt);
 399                         NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
 400                         break;
 401                 case Q_WANTYES:
 402                 case Q_WANTYES_OP:
 403                         _set_rfc1143(telnet, telopt, Q_US(q), Q_NO);
 404                         break;
 405                 }
 406                 break;
 407 
 408         /* request to enable option on local end or confirm WILL */
 409         case TELNET_STATE_DO:
 410                 switch (Q_US(q)) {
 411                 case Q_NO:
 412                         if (_check_telopt(telnet, telopt, 1)) {
 413                                 _set_rfc1143(telnet, telopt, Q_YES, Q_HIM(q));
 414                                 _send_negotiate(telnet, TELNET_WILL, telopt);
 415                                 NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
 416                         } else
 417                                 _send_negotiate(telnet, TELNET_WONT, telopt);
 418                         break;
 419                 case Q_WANTNO:
 420                         _set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q));
 421                         NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt);
 422                         _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 423                                         "WONT answered by DO");
 424                         break;
 425                 case Q_WANTNO_OP:
 426                         _set_rfc1143(telnet, telopt, Q_YES, Q_HIM(q));
 427                         _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 428                                         "WONT answered by DO");
 429                         break;
 430                 case Q_WANTYES:
 431                         _set_rfc1143(telnet, telopt, Q_YES, Q_HIM(q));
 432                         NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
 433                         break;
 434                 case Q_WANTYES_OP:
 435                         _set_rfc1143(telnet, telopt, Q_WANTNO, Q_HIM(q));
 436                         _send_negotiate(telnet, TELNET_WONT, telopt);
 437                         NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
 438                         break;
 439                 }
 440                 break;
 441 
 442         /* request to disable option on local end, confirm WONT, reject WILL */
 443         case TELNET_STATE_DONT:
 444                 switch (Q_US(q)) {
 445                 case Q_YES:
 446                         _set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q));
 447                         _send_negotiate(telnet, TELNET_WONT, telopt);
 448                         NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt);
 449                         break;
 450                 case Q_WANTNO:
 451                         _set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q));
 452                         NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt);
 453                         break;
 454                 case Q_WANTNO_OP:
 455                         _set_rfc1143(telnet, telopt, Q_WANTYES, Q_HIM(q));
 456                         _send_negotiate(telnet, TELNET_WILL, telopt);
 457                         NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt);
 458                         break;
 459                 case Q_WANTYES:
 460                 case Q_WANTYES_OP:
 461                         _set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q));
 462                         break;
 463                 }
 464                 break;
 465         }
 466 }
 467 
 468 /*
 469  * process an ENVIRON/NEW-ENVIRON subnegotiation buffer
 470  *
 471  * the algorithm and approach used here is kind of a hack,
 472  * but it reduces the number of memory allocations we have
 473  * to make.
 474  *
 475  * we copy the bytes back into the buffer, starting at the very
 476  * beginning, which makes it easy to handle the ENVIRON ESC
 477  * escape mechanism as well as ensure the variable name and
 478  * value strings are NUL-terminated, all while fitting inside
 479  * of the original buffer.
 480  */
 481 
 482 static int _environ_telnet(telnet_t *telnet, unsigned char type,
     /* [previous][next][first][last][top][bottom][index][help] */
 483                            char* buffer, size_t size) {
 484         telnet_event_t ev;
 485         struct telnet_environ_t *values = 0;
 486         char *c, *last, *out;
 487         size_t eindex, count;
 488 
 489         /* if we have no data, just pass it through */
 490         if (size == 0) {
 491                 return 0;
 492         }
 493 
 494         /* first byte must be a valid command */
 495         if ((unsigned)buffer[0] != TELNET_ENVIRON_SEND &&
 496                         (unsigned)buffer[0] != TELNET_ENVIRON_IS &&
 497                         (unsigned)buffer[0] != TELNET_ENVIRON_INFO) {
 498                 _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 499                                 "telopt %ld subneg has invalid command", (long) type);
 500                 return 0;
 501         }
 502 
 503         /* store ENVIRON command */
 504         ev.environ.cmd = (unsigned char) buffer[0];
 505 
 506         /* if we have no arguments, send an event with no data end return */
 507         if (size == 1) {
 508                 /* no list of variables given */
 509                 ev.environ.values = 0;
 510                 ev.environ.size   = 0;
 511 
 512                 /* invoke event with our arguments */
 513                 ev.type = TELNET_EV_ENVIRON;
 514                 telnet->eh(telnet, &ev, telnet->ud);
 515 
 516                 return 0;
 517         }
 518 
 519         /* very second byte must be VAR or USERVAR, if present */
 520         if ((unsigned)buffer[1] != TELNET_ENVIRON_VAR &&
 521                         (unsigned)buffer[1] != TELNET_ENVIRON_USERVAR) {
 522                 _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 523                                 "telopt %d subneg missing variable type", type);
 524                 return 0;
 525         }
 526 
 527         /* ensure last byte is not an escape byte (makes parsing later easier) */
 528         if ((unsigned)buffer[size - 1] == TELNET_ENVIRON_ESC) {
 529                 _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 530                                 "telopt %d subneg ends with ESC", type);
 531                 return 0;
 532         }
 533 
 534         /* count arguments; each valid entry starts with VAR or USERVAR */
 535         count = 0;
 536         for (c = buffer + 1; c < buffer + size; ++c) {
 537                 if (*c == TELNET_ENVIRON_VAR || *c == TELNET_ENVIRON_USERVAR) {
 538                         ++count;
 539                 } else if (*c == TELNET_ENVIRON_ESC) {
 540                         /* skip the next byte */
 541                         ++c;
 542                 }
 543         }
 544 
 545         /* allocate argument array, bail on error */
 546         if ((values = (struct telnet_environ_t *)calloc(count,
 547                         sizeof(struct telnet_environ_t))) == 0) {
 548                 _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
 549                                 "calloc() failed: %s", strerror(errno));
 550                 return 0;
 551         }
 552 
 553         /* parse argument array strings */
 554         out = buffer;
 555         c = buffer + 1;
 556         for (eindex = 0; eindex != count; ++eindex) {
 557                 /* remember the variable type (will be VAR or USERVAR) */
 558                 values[eindex].type = (unsigned char) (*c++);
 559 
 560                 /* scan until we find an end-marker, and buffer up unescaped
 561                  * bytes into our buffer */
 562                 last = out;
 563                 while (c < buffer + size) {
 564                         /* stop at the next variable or at the value */
 565                         if ((unsigned)*c == TELNET_ENVIRON_VAR ||
 566                                         (unsigned)*c == TELNET_ENVIRON_VALUE ||
 567                                         (unsigned)*c == TELNET_ENVIRON_USERVAR) {
 568                                 break;
 569                         }
 570 
 571                         /* buffer next byte (taking into account ESC) */
 572                         if (*c == TELNET_ENVIRON_ESC) {
 573                                 ++c;
 574                         }
 575 
 576                         *out++ = *c++;
 577                 }
 578                 *out++ = '\0';
 579 
 580                 /* store the variable name we have just received */
 581                 values[eindex].var   = last;
 582                 values[eindex].value = "";
 583 
 584                 /* if we got a value, find the next end marker and
 585                  * store the value; otherwise, store empty string */
 586                 if (c < buffer + size && *c == TELNET_ENVIRON_VALUE) {
 587                         ++c;
 588                         last = out;
 589                         while (c < buffer + size) {
 590                                 /* stop when we find the start of the next variable */
 591                                 if ((unsigned)*c == TELNET_ENVIRON_VAR ||
 592                                                 (unsigned)*c == TELNET_ENVIRON_USERVAR) {
 593                                         break;
 594                                 }
 595 
 596                                 /* buffer next byte (taking into account ESC) */
 597                                 if (*c == TELNET_ENVIRON_ESC) {
 598                                         ++c;
 599                                 }
 600 
 601                                 *out++ = *c++;
 602                         }
 603                         *out++ = '\0';
 604 
 605                         /* store the variable value */
 606                         values[eindex].value = last;
 607                 }
 608         }
 609 
 610         /* pass values array and count to event */
 611         ev.environ.values = values;
 612         ev.environ.size   = count;
 613 
 614         /* invoke event with our arguments */
 615         ev.type = TELNET_EV_ENVIRON;
 616         telnet->eh(telnet, &ev, telnet->ud);
 617 
 618         /* clean up */
 619         FREE(values);
 620         return 0;
 621 }
 622 
 623 /* parse TERMINAL-TYPE command subnegotiation buffers */
 624 static int _ttype_telnet(telnet_t *telnet, const char* buffer, size_t size) {
     /* [previous][next][first][last][top][bottom][index][help] */
 625         telnet_event_t ev;
 626 
 627         /* make sure request is not empty */
 628         if (size == 0) {
 629                 _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 630                                 "incomplete TERMINAL-TYPE request");
 631                 return 0;
 632         }
 633 
 634         /* make sure request has valid command type */
 635         if (buffer[0] != TELNET_TTYPE_IS &&
 636                         buffer[0] != TELNET_TTYPE_SEND) {
 637                 _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 638                                 "TERMINAL-TYPE request has invalid type");
 639                 return 0;
 640         }
 641 
 642         /* send proper event */
 643         if (buffer[0] == TELNET_TTYPE_IS) {
 644                 char *name;
 645 
 646                 /* allocate space for name */
 647                 if ((name = (char *)malloc(size)) == 0) {
 648                         _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
 649                                         "malloc() failed: %s", strerror(errno));
 650                         return 0;
 651                 }
 652                 memcpy(name, buffer + 1, size - 1);
 653                 name[size - 1] = '\0';
 654 
 655                 ev.type       = TELNET_EV_TTYPE;
 656                 ev.ttype.cmd  = TELNET_TTYPE_IS;
 657                 ev.ttype.name = name;
 658                 telnet->eh(telnet, &ev, telnet->ud);
 659 
 660                 /* clean up */
 661                 FREE(name);
 662         } else {
 663                 ev.type       = TELNET_EV_TTYPE;
 664                 ev.ttype.cmd  = TELNET_TTYPE_SEND;
 665                 ev.ttype.name = 0;
 666                 telnet->eh(telnet, &ev, telnet->ud);
 667         }
 668 
 669         return 0;
 670 }
 671 
 672 /*
 673  * process a subnegotiation buffer; return non-zero if the current buffer
 674  * must be aborted and reprocessed.
 675  */
 676 
 677 static int _subnegotiate(telnet_t *telnet) {
     /* [previous][next][first][last][top][bottom][index][help] */
 678         telnet_event_t ev;
 679 
 680         /* standard subnegotiation event */
 681         ev.type       = TELNET_EV_SUBNEGOTIATION;
 682         ev.sub.telopt = telnet->sb_telopt;
 683         ev.sub.buffer = telnet->buffer;
 684         ev.sub.size   = telnet->buffer_pos;
 685         telnet->eh(telnet, &ev, telnet->ud);
 686 
 687         switch (telnet->sb_telopt) {
 688 
 689         /* specially handled subnegotiation telopt types */
 690         case TELNET_TELOPT_TTYPE:
 691                 return _ttype_telnet(telnet, telnet->buffer, telnet->buffer_pos);
 692         case TELNET_TELOPT_ENVIRON:
 693         case TELNET_TELOPT_NEW_ENVIRON:
 694                 return _environ_telnet(telnet, telnet->sb_telopt, telnet->buffer,
 695                                 telnet->buffer_pos);
 696         default:
 697                 return 0;
 698         }
 699 }
 700 
 701 /* initialize a telnet state tracker */
 702 telnet_t *telnet_init(const telnet_telopt_t *telopts,
     /* [previous][next][first][last][top][bottom][index][help] */
 703                       telnet_event_handler_t eh, unsigned char flags, void *user_data) {
 704         /* allocate structure */
 705         struct telnet_t *telnet = (telnet_t*)calloc(1, sizeof(telnet_t));
 706         if (telnet == 0)
 707                 return 0;
 708 
 709         /* initialize data */
 710         telnet->ud      = user_data;
 711         telnet->telopts = telopts;
 712         telnet->eh      = eh;
 713         telnet->flags   = flags;
 714 
 715         return telnet;
 716 }
 717 
 718 /* free up any memory allocated by a state tracker */
 719 void telnet_free(telnet_t *telnet) {
     /* [previous][next][first][last][top][bottom][index][help] */
 720         /* free sub-request buffer */
 721         if (telnet->buffer != 0) {
 722                 FREE(telnet->buffer);
 723                 telnet->buffer      = 0; //-V1048
 724                 telnet->buffer_size = 0;
 725                 telnet->buffer_pos  = 0;
 726         }
 727 
 728         /* free RFC-1143 queue */
 729         if (telnet->q) {
 730                 FREE(telnet->q);
 731                 telnet->q      = NULL;
 732                 telnet->q_size = 0;
 733                 telnet->q_cnt  = 0;
 734         }
 735 
 736         /* free the telnet structure itself */
 737         free(telnet); /* X-LINTED: FREE */
 738 }
 739 
 740 /* push a byte into the telnet buffer */
 741 static telnet_error_t _buffer_byte(telnet_t *telnet,
     /* [previous][next][first][last][top][bottom][index][help] */
 742                                    unsigned char byte) {
 743         char *new_buffer;
 744 
 745         /* check if we're out of room */
 746         if (telnet->buffer_pos == telnet->buffer_size) {
 747                 size_t i;
 748                 /* find the next buffer size */
 749                 for (i = 0; i != _buffer_sizes_count; ++i) {
 750                         if (_buffer_sizes[i] == telnet->buffer_size) {
 751                                 break;
 752                         }
 753                 }
 754 
 755                 /* overflow -- can't grow any more */
 756                 if (i >= _buffer_sizes_count - 1) {
 757                         _error(telnet, __LINE__, __func__, TELNET_EOVERFLOW, 0,
 758                                         "subnegotiation buffer size limit reached");
 759                         return TELNET_EOVERFLOW;
 760                 }
 761 
 762                 /* (re)allocate buffer */
 763                 new_buffer = (char *)realloc(telnet->buffer, _buffer_sizes[i + 1]);
 764                 if (new_buffer == 0) {
 765                         _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
 766                                         "realloc() failed");
 767                         return TELNET_ENOMEM;
 768                 }
 769 
 770                 telnet->buffer = new_buffer;
 771                 telnet->buffer_size = _buffer_sizes[i + 1];
 772         }
 773 
 774         /* push the byte, all set */
 775         telnet->buffer[telnet->buffer_pos++] = (char) byte;
 776         return TELNET_EOK;
 777 }
 778 
 779 static void _process(telnet_t *telnet, const char *buffer, size_t size) {
     /* [previous][next][first][last][top][bottom][index][help] */
 780         telnet_event_t ev;
 781         unsigned char byte;
 782         size_t i, start;
 783         for (i = start = 0; i != size; ++i) {
 784                 byte = (unsigned char) buffer[i];
 785                 switch (telnet->state) {
 786                 /* regular data */
 787                 case TELNET_STATE_DATA:
 788                         /* on an IAC byte, pass through all pending bytes and
 789                          * switch states */
 790                         if (byte == TELNET_IAC) {
 791                                 if (i != start) {
 792                                         ev.type        = TELNET_EV_DATA;
 793                                         ev.data.buffer = buffer + start;
 794                                         ev.data.size   = i - start;
 795                                         telnet->eh(telnet, &ev, telnet->ud);
 796                                 }
 797                                 telnet->state = TELNET_STATE_IAC;
 798                         } else if (byte == '\r' &&
 799                                             (telnet->flags & TELNET_FLAG_NVT_EOL) &&
 800                                            !(telnet->flags & TELNET_FLAG_RECEIVE_BINARY)) {
 801                                 if (i != start) {
 802                                         ev.type        = TELNET_EV_DATA;
 803                                         ev.data.buffer = buffer + start;
 804                                         ev.data.size   = i - start;
 805                                         telnet->eh(telnet, &ev, telnet->ud);
 806                                 }
 807                                 telnet->state = TELNET_STATE_EOL;
 808                         }
 809                         break;
 810 
 811                 /* NVT EOL to be translated */
 812                 case TELNET_STATE_EOL:
 813                         if (byte != '\n') {
 814                                 byte           = '\r';
 815                                 ev.type        = TELNET_EV_DATA;
 816                                 ev.data.buffer = (char*)&byte;
 817                                 ev.data.size   = 1;
 818                                 telnet->eh(telnet, &ev, telnet->ud);
 819                                 byte           = (unsigned char) buffer[i];
 820                         }
 821                         /* any byte following '\r' other than '\n' or '\0' is invalid, */
 822                         /* so pass both \r and the byte */
 823                         start = i;
 824                         if (byte == '\0')
 825                                 ++start;
 826                         /* state update */
 827                         telnet->state = TELNET_STATE_DATA;
 828                         break;
 829 
 830                 /* IAC command */
 831                 case TELNET_STATE_IAC:
 832                         switch (byte) {
 833                         /* subnegotiation */
 834                         case TELNET_SB:
 835                                 telnet->state = TELNET_STATE_SB;
 836                                 break;
 837                         /* negotiation commands */
 838                         case TELNET_WILL:
 839                                 telnet->state = TELNET_STATE_WILL;
 840                                 break;
 841                         case TELNET_WONT:
 842                                 telnet->state = TELNET_STATE_WONT;
 843                                 break;
 844                         case TELNET_DO:
 845                                 telnet->state = TELNET_STATE_DO;
 846                                 break;
 847                         case TELNET_DONT:
 848                                 telnet->state = TELNET_STATE_DONT;
 849                                 break;
 850                         /* IAC escaping */
 851                         case TELNET_IAC:
 852                                 /* event */
 853                                 ev.type        = TELNET_EV_DATA;
 854                                 ev.data.buffer = (char*)&byte;
 855                                 ev.data.size   = 1;
 856                                 telnet->eh(telnet, &ev, telnet->ud);
 857 
 858                                 /* state update */
 859                                 start         = i + 1;
 860                                 telnet->state = TELNET_STATE_DATA;
 861                                 break;
 862                         /* some other command */
 863                         default:
 864                                 /* event */
 865                                 ev.type       = TELNET_EV_IAC;
 866                                 ev.iac.cmd    = byte;
 867                                 telnet->eh(telnet, &ev, telnet->ud);
 868 
 869                                 /* state update */
 870                                 start         = i + 1;
 871                                 telnet->state = TELNET_STATE_DATA;
 872                         }
 873                         break;
 874 
 875                 /* negotiation commands */
 876                 case TELNET_STATE_WILL:
 877                 case TELNET_STATE_WONT:
 878                 case TELNET_STATE_DO:
 879                 case TELNET_STATE_DONT:
 880                         _negotiate(telnet, byte);
 881                         start         = i + 1;
 882                         telnet->state = TELNET_STATE_DATA;
 883                         break;
 884 
 885                 /* subnegotiation -- determine subnegotiation telopt */
 886                 case TELNET_STATE_SB:
 887                         telnet->sb_telopt  = byte;
 888                         telnet->buffer_pos = 0;
 889                         telnet->state      = TELNET_STATE_SB_DATA;
 890                         break;
 891 
 892                 /* subnegotiation -- buffer bytes until end request */
 893                 case TELNET_STATE_SB_DATA:
 894                         /* IAC command in subnegotiation -- either IAC SE or IAC IAC */
 895                         if (byte == TELNET_IAC) {
 896                                 telnet->state = TELNET_STATE_SB_DATA_IAC;
 897                         } else if (_buffer_byte(telnet, byte) != TELNET_EOK) {
 898                                 start = i + 1;
 899                                 telnet->state = TELNET_STATE_DATA;
 900                         }
 901                         break;
 902 
 903                 /* IAC escaping inside a subnegotiation */
 904                 case TELNET_STATE_SB_DATA_IAC:
 905                         switch (byte) {
 906                         /* end subnegotiation */
 907                         case TELNET_SE:
 908                                 /* return to default state */
 909                                 start = i + 1;
 910                                 telnet->state = TELNET_STATE_DATA;
 911 
 912                                 /* process subnegotiation */
 913                                 if (_subnegotiate(telnet) != 0) {
 914                                         telnet_recv(telnet, &buffer[start], size - start);
 915                                         return;
 916                                 }
 917                                 break;
 918                         /* escaped IAC byte */
 919                         case TELNET_IAC:
 920                                 /* push IAC into buffer */
 921                                 if (_buffer_byte(telnet, TELNET_IAC) !=
 922                                                 TELNET_EOK) {
 923                                         start = i + 1;
 924                                         telnet->state = TELNET_STATE_DATA;
 925                                 } else {
 926                                         telnet->state = TELNET_STATE_SB_DATA;
 927                                 }
 928                                 break;
 929                         /*
 930                          * Something else -- protocol error.  attempt to process
 931                          * content in subnegotiation buffer, then evaluate the
 932                          * given command as an IAC code.
 933                          */
 934 
 935                         default:
 936                                 _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 937                                                 "unexpected byte after IAC inside SB: %d",
 938                                                 byte);
 939 
 940                                 /* enter IAC state */
 941                                 start = i + 1;
 942                                 telnet->state = TELNET_STATE_IAC;
 943 
 944                                 /*
 945                                  * Process subnegotiation; see comment in
 946                                  * TELNET_STATE_SB_DATA_IAC about invoking telnet_recv()
 947                                  */
 948 
 949                                 if (_subnegotiate(telnet) != 0) {
 950                                         telnet_recv(telnet, &buffer[start], size - start);
 951                                         return;
 952                                 } else {
 953 
 954                                         /*
 955                                          * Recursive call to get the current input byte processed
 956                                          * as a regular IAC command.  we could use a goto, but
 957                                          * that would be gross.
 958                                          */
 959 
 960                                         _process(telnet, (char *)&byte, 1);
 961                                 }
 962                                 break;
 963                         }
 964                         break;
 965                 }
 966         }
 967 
 968         /* pass through any remaining bytes */
 969         if (telnet->state == TELNET_STATE_DATA && i != start) {
 970                 ev.type        = TELNET_EV_DATA;
 971                 ev.data.buffer = buffer + start;
 972                 ev.data.size   = i - start;
 973                 telnet->eh(telnet, &ev, telnet->ud);
 974         }
 975 }
 976 
 977 /* push a bytes into the state tracker */
 978 void telnet_recv(telnet_t *telnet, const char *buffer,
     /* [previous][next][first][last][top][bottom][index][help] */
 979                  size_t size) {
 980         _process(telnet, buffer, size);
 981 }
 982 
 983 /* send an iac command */
 984 void telnet_iac(telnet_t *telnet, unsigned char cmd) {
     /* [previous][next][first][last][top][bottom][index][help] */
 985         unsigned char bytes[2];
 986         bytes[0] = TELNET_IAC;
 987         bytes[1] = cmd;
 988         _sendu(telnet, bytes, 2);
 989 }
 990 
 991 /* send negotiation */
 992 void telnet_negotiate(telnet_t *telnet, unsigned char cmd,
     /* [previous][next][first][last][top][bottom][index][help] */
 993                       unsigned char telopt) {
 994         telnet_rfc1143_t q;
 995 
 996         /* if we're in proxy mode, just send it now */
 997         if (telnet->flags & TELNET_FLAG_PROXY) {
 998                 unsigned char bytes[3];
 999                 bytes[0] = TELNET_IAC;
1000                 bytes[1] = cmd;
1001                 bytes[2] = telopt;
1002                 _sendu(telnet, bytes, 3);
1003                 return;
1004         }
1005 
1006         /* get current option states */
1007         q = _get_rfc1143(telnet, telopt);
1008 
1009         switch (cmd) {
1010         /* advertise willingness to support an option */
1011         case TELNET_WILL:
1012                 switch (Q_US(q)) {
1013                 case Q_NO:
1014                         _set_rfc1143(telnet, telopt, Q_WANTYES, Q_HIM(q));
1015                         _send_negotiate(telnet, TELNET_WILL, telopt);
1016                         break;
1017                 case Q_WANTNO:
1018                         _set_rfc1143(telnet, telopt, Q_WANTNO_OP, Q_HIM(q));
1019                         break;
1020                 case Q_WANTYES_OP:
1021                         _set_rfc1143(telnet, telopt, Q_WANTYES, Q_HIM(q));
1022                         break;
1023                 }
1024                 break;
1025 
1026         /* force turn-off of locally enabled option */
1027         case TELNET_WONT:
1028                 switch (Q_US(q)) {
1029                 case Q_YES:
1030                         _set_rfc1143(telnet, telopt, Q_WANTNO, Q_HIM(q));
1031                         _send_negotiate(telnet, TELNET_WONT, telopt);
1032                         break;
1033                 case Q_WANTYES:
1034                         _set_rfc1143(telnet, telopt, Q_WANTYES_OP, Q_HIM(q));
1035                         break;
1036                 case Q_WANTNO_OP:
1037                         _set_rfc1143(telnet, telopt, Q_WANTNO, Q_HIM(q));
1038                         break;
1039                 }
1040                 break;
1041 
1042         /* ask remote end to enable an option */
1043         case TELNET_DO:
1044                 switch (Q_HIM(q)) {
1045                 case Q_NO:
1046                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES);
1047                         _send_negotiate(telnet, TELNET_DO, telopt);
1048                         break;
1049                 case Q_WANTNO:
1050                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTNO_OP);
1051                         break;
1052                 case Q_WANTYES_OP:
1053                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES);
1054                         break;
1055                 }
1056                 break;
1057 
1058         /* demand remote end disable an option */
1059         case TELNET_DONT:
1060                 switch (Q_HIM(q)) {
1061                 case Q_YES:
1062                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTNO);
1063                         _send_negotiate(telnet, TELNET_DONT, telopt);
1064                         break;
1065                 case Q_WANTYES:
1066                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES_OP);
1067                         break;
1068                 case Q_WANTNO_OP:
1069                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTNO);
1070                         break;
1071                 }
1072                 break;
1073         }
1074 }
1075 
1076 /* send non-command data (escapes IAC bytes) */
1077 void telnet_send(telnet_t *telnet, const char *buffer,
     /* [previous][next][first][last][top][bottom][index][help] */
1078                  size_t size) {
1079         size_t i, l;
1080 
1081         for (l = i = 0; i != size; ++i) {
1082                 /* dump prior portion of text, send escaped bytes */
1083                 if (buffer[i] == (char)TELNET_IAC) {
1084                         /* dump prior text if any */
1085                         if (i != l) {
1086                                 _send(telnet, buffer + l, i - l);
1087                         }
1088                         l = i + 1;
1089 
1090                         /* send escape */
1091                         telnet_iac(telnet, TELNET_IAC);
1092                 }
1093         }
1094 
1095         /* send whatever portion of buffer is left */
1096         if (i != l) {
1097                 _send(telnet, buffer + l, i - l);
1098         }
1099 }
1100 
1101 /* send non-command text (escapes IAC bytes and does NVT translation) */
1102 void telnet_send_text(telnet_t *telnet, const char *buffer,
     /* [previous][next][first][last][top][bottom][index][help] */
1103                       size_t size) {
1104         size_t i, l;
1105 
1106         for (l = i = 0; i != size; ++i) {
1107                 /* dump prior portion of text, send escaped bytes */
1108                 if (buffer[i] == (char)TELNET_IAC) {
1109                         /* dump prior text if any */
1110                         if (i != l) {
1111                                 _send(telnet, buffer + l, i - l);
1112                         }
1113                         l = i + 1;
1114 
1115                         /* send escape */
1116                         telnet_iac(telnet, TELNET_IAC);
1117                 }
1118                 /* special characters if not in BINARY mode */
1119                 else if (!(telnet->flags & TELNET_FLAG_TRANSMIT_BINARY) &&
1120                                  (buffer[i] == '\r' || buffer[i] == '\n')) {
1121                         /* dump prior portion of text */
1122                         if (i != l) {
1123                                 _send(telnet, buffer + l, i - l);
1124                         }
1125                         l = i + 1;
1126 
1127                         /* automatic translation of \r -> CRNUL */
1128                         if (buffer[i] == '\r') {
1129                                 _send(telnet, CRNUL, 2);
1130                         }
1131                         /* automatic translation of \n -> CRLF */
1132                         else {
1133                                 _send(telnet, CRLF, 2);
1134                         }
1135                 }
1136         }
1137 
1138         /* send whatever portion of buffer is left */
1139         if (i != l) {
1140                 _send(telnet, buffer + l, i - l);
1141         }
1142 }
1143 
1144 /* send subnegotiation header */
1145 void telnet_begin_sb(telnet_t *telnet, unsigned char telopt) {
     /* [previous][next][first][last][top][bottom][index][help] */
1146         unsigned char sb[3];
1147         sb[0] = TELNET_IAC;
1148         sb[1] = TELNET_SB;
1149         sb[2] = telopt;
1150         _sendu(telnet, sb, 3);
1151 }
1152 
1153 /* send formatted data with \r and \n translation in addition to IAC IAC */
1154 int telnet_vprintf(telnet_t *telnet, const char *fmt, va_list va) {
     /* [previous][next][first][last][top][bottom][index][help] */
1155         char buffer[1024];
1156         char *output = buffer;
1157         int rs, i, l;
1158 
1159         /* format */
1160         va_list va2;
1161         va_copy(va2, va);
1162         rs = vsnprintf(buffer, sizeof(buffer), fmt, va);
1163         if ((unsigned long) rs >= sizeof(buffer)) {
1164                 output = (char*)malloc((unsigned long) ((unsigned long)rs + 1L));
1165                 if (output == 0) {
1166                         _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
1167                                         "malloc() failed: %s", strerror(errno));
1168                         va_end(va2);
1169                         return -1;
1170                 }
1171                 rs = vsnprintf(output, rs + 1, fmt, va2);
1172         }
1173         va_end(va2);
1174         va_end(va);
1175 
1176         /* send */
1177         for (l = i = 0; i != rs; ++i) {
1178                 /* special characters */
1179                 if (output[i] == (char)TELNET_IAC || output[i] == '\r' ||
1180                                 output[i] == '\n') {
1181                         /* dump prior portion of text */
1182                         if (i != l)
1183                                 _send(telnet, output + l, (size_t) (i - l));
1184                         l = i + 1;
1185 
1186                         /* IAC -> IAC IAC */
1187                         if (output[i] == (char)TELNET_IAC)
1188                                 telnet_iac(telnet, TELNET_IAC);
1189                         /* automatic translation of \r -> CRNUL */
1190                         else if (output[i] == '\r')
1191                                 _send(telnet, CRNUL, 2);
1192                         /* automatic translation of \n -> CRLF */
1193                         else if (output[i] == '\n')
1194                                 _send(telnet, CRLF, 2);
1195                 }
1196         }
1197 
1198         /* send whatever portion of output is left */
1199         if (i != l) {
1200                 _send(telnet, output + l, (size_t) (i - l));
1201         }
1202 
1203         /* free allocated memory, if any */
1204         if (output != buffer) {
1205                 FREE(output);
1206         }
1207 
1208         return rs;
1209 }
1210 
1211 /* see telnet_vprintf */
1212 int telnet_printf(telnet_t *telnet, const char *fmt, ...) {
     /* [previous][next][first][last][top][bottom][index][help] */
1213         va_list va;
1214         int rs;
1215 
1216         va_start(va, fmt);
1217         rs = telnet_vprintf(telnet, fmt, va);
1218         va_end(va);
1219 
1220         return rs;
1221 }
1222 
1223 /* send formatted data through telnet_send */
1224 int telnet_raw_vprintf(telnet_t *telnet, const char *fmt, va_list va) {
     /* [previous][next][first][last][top][bottom][index][help] */
1225         char buffer[1024];
1226         char *output = buffer;
1227         int rs;
1228 
1229         /* format; allocate more space if necessary */
1230         va_list va2;
1231         va_copy(va2, va);
1232         rs = vsnprintf(buffer, sizeof(buffer), fmt, va);
1233         if ((unsigned long) rs >= sizeof(buffer)) {
1234                 output = (char*)malloc((unsigned long) rs + 1);
1235                 if (output == 0) {
1236                         _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
1237                                         "malloc() failed: %s", strerror(errno));
1238                         va_end(va2);
1239                         return -1;
1240                 }
1241                 rs = vsnprintf(output, (int)((unsigned int) rs + 1), fmt, va2);
1242         }
1243         va_end(va2);
1244         va_end(va);
1245 
1246         /* send out the formatted data */
1247         telnet_send(telnet, output, (size_t) rs);
1248 
1249         /* release allocated memory, if any */
1250         if (output != buffer) {
1251                 FREE(output);
1252         }
1253 
1254         return rs;
1255 }
1256 
1257 /* see telnet_raw_vprintf */
1258 int telnet_raw_printf(telnet_t *telnet, const char *fmt, ...) {
     /* [previous][next][first][last][top][bottom][index][help] */
1259         va_list va;
1260         int rs;
1261 
1262         va_start(va, fmt);
1263         rs = telnet_raw_vprintf(telnet, fmt, va);
1264         va_end(va);
1265 
1266         return rs;
1267 }

/* [previous][next][first][last][top][bottom][index][help] */