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 /* check if we support a particular telopt; if us is non-zero, we
 212  * check if we (local) supports it, otherwise we check if he (remote)
 213  * supports it.  return non-zero if supported, zero if not supported.
 214  */
 215 static __inline__ int _check_telopt(telnet_t *telnet, unsigned char telopt,
     /* [previous][next][first][last][top][bottom][index][help] */
 216                                     int us) {
 217         int i;
 218 
 219         /* if we have no telopts table, we obviously don't support it */
 220         if (telnet->telopts == 0)
 221                 return 0;
 222 
 223         /* loop until found or end marker (us and him both 0) */
 224         for (i = 0; telnet->telopts[i].telopt != -1; ++i) {
 225                 if (telnet->telopts[i].telopt == telopt) {
 226                         if (us && telnet->telopts[i].us == TELNET_WILL)
 227                                 return 1;
 228                         else if (!us && telnet->telopts[i].him == TELNET_DO)
 229                                 return 1;
 230                         else
 231                                 return 0;
 232                 }
 233         }
 234 
 235         /* not found, so not supported */
 236         return 0;
 237 }
 238 
 239 /* retrieve RFC-1143 option state */
 240 static __inline__ telnet_rfc1143_t _get_rfc1143(telnet_t *telnet,
     /* [previous][next][first][last][top][bottom][index][help] */
 241                                                 unsigned char telopt) {
 242         telnet_rfc1143_t empty;
 243         unsigned int i;
 244 
 245         /* search for entry */
 246         for (i = 0; i != telnet->q_cnt; ++i) {
 247                 if (telnet->q[i].telopt == telopt) {
 248                         return telnet->q[i];
 249                 }
 250         }
 251 
 252         /* not found, return empty value */
 253         empty.telopt = telopt;
 254         empty.state  = 0;
 255         return empty;
 256 }
 257 
 258 /* save RFC-1143 option state */
 259 static __inline__ void _set_rfc1143(telnet_t *telnet, unsigned char telopt,
     /* [previous][next][first][last][top][bottom][index][help] */
 260                                     unsigned char us, unsigned char him) {
 261         telnet_rfc1143_t *qtmp;
 262         unsigned int i;
 263 
 264         /* search for entry */
 265         for (i = 0; i != telnet->q_cnt; ++i) {
 266                 if (telnet->q[i].telopt == telopt) {
 267                         telnet->q[i].state = (unsigned char) Q_MAKE(us,him);
 268                         if (telopt != TELNET_TELOPT_BINARY)
 269                                 return;
 270                         telnet->flags &=
 271                             (unsigned char)~(TELNET_FLAG_TRANSMIT_BINARY |
 272                                              TELNET_FLAG_RECEIVE_BINARY);
 273                         if (us == Q_YES)
 274                                 telnet->flags |= TELNET_FLAG_TRANSMIT_BINARY;
 275                         if (him == Q_YES)
 276                                 telnet->flags |= TELNET_FLAG_RECEIVE_BINARY;
 277                         return;
 278                 }
 279         }
 280 
 281         /* we're going to need to track state for it, so grow the queue
 282          * by 4 (four) elements and put the telopt into it; bail on allocation
 283          * error.  we go by four because it seems like a reasonable guess as
 284          * to the number of enabled options for most simple code, and it
 285          * allows for an acceptable number of reallocations for complex code.
 286          */
 287 #define QUANTUM 4
 288     /* Did we reach the end of the table? */
 289        if (i >= telnet->q_size) {
 290                /* Expand the size */
 291                if ((qtmp = (telnet_rfc1143_t *)realloc(telnet->q,
 292                        sizeof(telnet_rfc1143_t) * (telnet->q_size + QUANTUM))) == 0) {
 293                        _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
 294                                        "realloc() failed: %s", strerror(errno));
 295                        return;
 296                }
 297                memset(&qtmp[telnet->q_size], 0, sizeof(telnet_rfc1143_t) * QUANTUM);
 298                telnet->q       = qtmp;
 299                telnet->q_size += QUANTUM;
 300         }
 301        /* Add entry to end of table */
 302        telnet->q[telnet->q_cnt].telopt = telopt;
 303        telnet->q[telnet->q_cnt].state  = (unsigned char) Q_MAKE(us, him);
 304        telnet->q_cnt ++;
 305 }
 306 
 307 /* send negotiation bytes */
 308 static __inline__ void _send_negotiate(telnet_t *telnet, unsigned char cmd,
     /* [previous][next][first][last][top][bottom][index][help] */
 309                                        unsigned char telopt) {
 310         unsigned char bytes[3];
 311         bytes[0] = TELNET_IAC;
 312         bytes[1] = cmd;
 313         bytes[2] = telopt;
 314         _sendu(telnet, bytes, 3);
 315 }
 316 
 317 /* negotiation handling magic for RFC-1143 */
 318 static void _negotiate(telnet_t *telnet, unsigned char telopt) {
     /* [previous][next][first][last][top][bottom][index][help] */
 319         telnet_event_t ev;
 320         telnet_rfc1143_t q;
 321 
 322         /* in PROXY mode, just pass it thru and do nothing */
 323         if (telnet->flags & TELNET_FLAG_PROXY) {
 324                 switch ((int)telnet->state) {
 325                 case TELNET_STATE_WILL:
 326                         NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
 327                         break;
 328                 case TELNET_STATE_WONT:
 329                         NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
 330                         break;
 331                 case TELNET_STATE_DO:
 332                         NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
 333                         break;
 334                 case TELNET_STATE_DONT:
 335                         NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt);
 336                         break;
 337                 }
 338                 return;
 339         }
 340 
 341         /* lookup the current state of the option */
 342         q = _get_rfc1143(telnet, telopt);
 343 
 344         /* start processing... */
 345         switch ((int)telnet->state) {
 346         /* request to enable option on remote end or confirm DO */
 347         case TELNET_STATE_WILL:
 348                 switch (Q_HIM(q)) {
 349                 case Q_NO:
 350                         if (_check_telopt(telnet, telopt, 0)) {
 351                                 _set_rfc1143(telnet, telopt, Q_US(q), Q_YES);
 352                                 _send_negotiate(telnet, TELNET_DO, telopt);
 353                                 NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
 354                         } else
 355                                 _send_negotiate(telnet, TELNET_DONT, telopt);
 356                         break;
 357                 case Q_WANTNO:
 358                         _set_rfc1143(telnet, telopt, Q_US(q), Q_NO);
 359                         NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
 360                         _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 361                                         "DONT answered by WILL");
 362                         break;
 363                 case Q_WANTNO_OP:
 364                         _set_rfc1143(telnet, telopt, Q_US(q), Q_YES);
 365                         _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 366                                         "DONT answered by WILL");
 367                         break;
 368                 case Q_WANTYES:
 369                         _set_rfc1143(telnet, telopt, Q_US(q), Q_YES);
 370                         NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
 371                         break;
 372                 case Q_WANTYES_OP:
 373                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTNO);
 374                         _send_negotiate(telnet, TELNET_DONT, telopt);
 375                         NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt);
 376                         break;
 377                 }
 378                 break;
 379 
 380         /* request to disable option on remote end, confirm DONT, reject DO */
 381         case TELNET_STATE_WONT:
 382                 switch (Q_HIM(q)) {
 383                 case Q_YES:
 384                         _set_rfc1143(telnet, telopt, Q_US(q), Q_NO);
 385                         _send_negotiate(telnet, TELNET_DONT, telopt);
 386                         NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
 387                         break;
 388                 case Q_WANTNO:
 389                         _set_rfc1143(telnet, telopt, Q_US(q), Q_NO);
 390                         NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
 391                         break;
 392                 case Q_WANTNO_OP:
 393                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES);
 394                         _send_negotiate(telnet, TELNET_DO, telopt);
 395                         NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt);
 396                         break;
 397                 case Q_WANTYES:
 398                 case Q_WANTYES_OP:
 399                         _set_rfc1143(telnet, telopt, Q_US(q), Q_NO);
 400                         break;
 401                 }
 402                 break;
 403 
 404         /* request to enable option on local end or confirm WILL */
 405         case TELNET_STATE_DO:
 406                 switch (Q_US(q)) {
 407                 case Q_NO:
 408                         if (_check_telopt(telnet, telopt, 1)) {
 409                                 _set_rfc1143(telnet, telopt, Q_YES, Q_HIM(q));
 410                                 _send_negotiate(telnet, TELNET_WILL, telopt);
 411                                 NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
 412                         } else
 413                                 _send_negotiate(telnet, TELNET_WONT, telopt);
 414                         break;
 415                 case Q_WANTNO:
 416                         _set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q));
 417                         NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt);
 418                         _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 419                                         "WONT answered by DO");
 420                         break;
 421                 case Q_WANTNO_OP:
 422                         _set_rfc1143(telnet, telopt, Q_YES, Q_HIM(q));
 423                         _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 424                                         "WONT answered by DO");
 425                         break;
 426                 case Q_WANTYES:
 427                         _set_rfc1143(telnet, telopt, Q_YES, Q_HIM(q));
 428                         NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
 429                         break;
 430                 case Q_WANTYES_OP:
 431                         _set_rfc1143(telnet, telopt, Q_WANTNO, Q_HIM(q));
 432                         _send_negotiate(telnet, TELNET_WONT, telopt);
 433                         NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt);
 434                         break;
 435                 }
 436                 break;
 437 
 438         /* request to disable option on local end, confirm WONT, reject WILL */
 439         case TELNET_STATE_DONT:
 440                 switch (Q_US(q)) {
 441                 case Q_YES:
 442                         _set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q));
 443                         _send_negotiate(telnet, TELNET_WONT, telopt);
 444                         NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt);
 445                         break;
 446                 case Q_WANTNO:
 447                         _set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q));
 448                         NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt);
 449                         break;
 450                 case Q_WANTNO_OP:
 451                         _set_rfc1143(telnet, telopt, Q_WANTYES, Q_HIM(q));
 452                         _send_negotiate(telnet, TELNET_WILL, telopt);
 453                         NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt);
 454                         break;
 455                 case Q_WANTYES:
 456                 case Q_WANTYES_OP:
 457                         _set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q));
 458                         break;
 459                 }
 460                 break;
 461         }
 462 }
 463 
 464 /* process an ENVIRON/NEW-ENVIRON subnegotiation buffer
 465  *
 466  * the algorithm and approach used here is kind of a hack,
 467  * but it reduces the number of memory allocations we have
 468  * to make.
 469  *
 470  * we copy the bytes back into the buffer, starting at the very
 471  * beginning, which makes it easy to handle the ENVIRON ESC
 472  * escape mechanism as well as ensure the variable name and
 473  * value strings are NUL-terminated, all while fitting inside
 474  * of the original buffer.
 475  */
 476 static int _environ_telnet(telnet_t *telnet, unsigned char type,
     /* [previous][next][first][last][top][bottom][index][help] */
 477                            char* buffer, size_t size) {
 478         telnet_event_t ev;
 479         struct telnet_environ_t *values = 0;
 480         char *c, *last, *out;
 481         size_t eindex, count;
 482 
 483         /* if we have no data, just pass it through */
 484         if (size == 0) {
 485                 return 0;
 486         }
 487 
 488         /* first byte must be a valid command */
 489         if ((unsigned)buffer[0] != TELNET_ENVIRON_SEND &&
 490                         (unsigned)buffer[0] != TELNET_ENVIRON_IS &&
 491                         (unsigned)buffer[0] != TELNET_ENVIRON_INFO) {
 492                 _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 493                                 "telopt %ld subneg has invalid command", (long) type);
 494                 return 0;
 495         }
 496 
 497         /* store ENVIRON command */
 498         ev.environ.cmd = (unsigned char) buffer[0];
 499 
 500         /* if we have no arguments, send an event with no data end return */
 501         if (size == 1) {
 502                 /* no list of variables given */
 503                 ev.environ.values = 0;
 504                 ev.environ.size   = 0;
 505 
 506                 /* invoke event with our arguments */
 507                 ev.type = TELNET_EV_ENVIRON;
 508                 telnet->eh(telnet, &ev, telnet->ud);
 509 
 510                 return 0;
 511         }
 512 
 513         /* very second byte must be VAR or USERVAR, if present */
 514         if ((unsigned)buffer[1] != TELNET_ENVIRON_VAR &&
 515                         (unsigned)buffer[1] != TELNET_ENVIRON_USERVAR) {
 516                 _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 517                                 "telopt %d subneg missing variable type", type);
 518                 return 0;
 519         }
 520 
 521         /* ensure last byte is not an escape byte (makes parsing later easier) */
 522         if ((unsigned)buffer[size - 1] == TELNET_ENVIRON_ESC) {
 523                 _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 524                                 "telopt %d subneg ends with ESC", type);
 525                 return 0;
 526         }
 527 
 528         /* count arguments; each valid entry starts with VAR or USERVAR */
 529         count = 0;
 530         for (c = buffer + 1; c < buffer + size; ++c) {
 531                 if (*c == TELNET_ENVIRON_VAR || *c == TELNET_ENVIRON_USERVAR) {
 532                         ++count;
 533                 } else if (*c == TELNET_ENVIRON_ESC) {
 534                         /* skip the next byte */
 535                         ++c;
 536                 }
 537         }
 538 
 539         /* allocate argument array, bail on error */
 540         if ((values = (struct telnet_environ_t *)calloc(count,
 541                         sizeof(struct telnet_environ_t))) == 0) {
 542                 _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
 543                                 "calloc() failed: %s", strerror(errno));
 544                 return 0;
 545         }
 546 
 547         /* parse argument array strings */
 548         out = buffer;
 549         c = buffer + 1;
 550         for (eindex = 0; eindex != count; ++eindex) {
 551                 /* remember the variable type (will be VAR or USERVAR) */
 552                 values[eindex].type = (unsigned char) (*c++);
 553 
 554                 /* scan until we find an end-marker, and buffer up unescaped
 555                  * bytes into our buffer */
 556                 last = out;
 557                 while (c < buffer + size) {
 558                         /* stop at the next variable or at the value */
 559                         if ((unsigned)*c == TELNET_ENVIRON_VAR ||
 560                                         (unsigned)*c == TELNET_ENVIRON_VALUE ||
 561                                         (unsigned)*c == TELNET_ENVIRON_USERVAR) {
 562                                 break;
 563                         }
 564 
 565                         /* buffer next byte (taking into account ESC) */
 566                         if (*c == TELNET_ENVIRON_ESC) {
 567                                 ++c;
 568                         }
 569 
 570                         *out++ = *c++;
 571                 }
 572                 *out++ = '\0';
 573 
 574                 /* store the variable name we have just received */
 575                 values[eindex].var   = last;
 576                 values[eindex].value = "";
 577 
 578                 /* if we got a value, find the next end marker and
 579                  * store the value; otherwise, store empty string */
 580                 if (c < buffer + size && *c == TELNET_ENVIRON_VALUE) {
 581                         ++c;
 582                         last = out;
 583                         while (c < buffer + size) {
 584                                 /* stop when we find the start of the next variable */
 585                                 if ((unsigned)*c == TELNET_ENVIRON_VAR ||
 586                                                 (unsigned)*c == TELNET_ENVIRON_USERVAR) {
 587                                         break;
 588                                 }
 589 
 590                                 /* buffer next byte (taking into account ESC) */
 591                                 if (*c == TELNET_ENVIRON_ESC) {
 592                                         ++c;
 593                                 }
 594 
 595                                 *out++ = *c++;
 596                         }
 597                         *out++ = '\0';
 598 
 599                         /* store the variable value */
 600                         values[eindex].value = last;
 601                 }
 602         }
 603 
 604         /* pass values array and count to event */
 605         ev.environ.values = values;
 606         ev.environ.size   = count;
 607 
 608         /* invoke event with our arguments */
 609         ev.type = TELNET_EV_ENVIRON;
 610         telnet->eh(telnet, &ev, telnet->ud);
 611 
 612         /* clean up */
 613         FREE(values);
 614         return 0;
 615 }
 616 
 617 /* parse TERMINAL-TYPE command subnegotiation buffers */
 618 static int _ttype_telnet(telnet_t *telnet, const char* buffer, size_t size) {
     /* [previous][next][first][last][top][bottom][index][help] */
 619         telnet_event_t ev;
 620 
 621         /* make sure request is not empty */
 622         if (size == 0) {
 623                 _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 624                                 "incomplete TERMINAL-TYPE request");
 625                 return 0;
 626         }
 627 
 628         /* make sure request has valid command type */
 629         if (buffer[0] != TELNET_TTYPE_IS &&
 630                         buffer[0] != TELNET_TTYPE_SEND) {
 631                 _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 632                                 "TERMINAL-TYPE request has invalid type");
 633                 return 0;
 634         }
 635 
 636         /* send proper event */
 637         if (buffer[0] == TELNET_TTYPE_IS) {
 638                 char *name;
 639 
 640                 /* allocate space for name */
 641                 if ((name = (char *)malloc(size)) == 0) {
 642                         _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
 643                                         "malloc() failed: %s", strerror(errno));
 644                         return 0;
 645                 }
 646                 memcpy(name, buffer + 1, size - 1);
 647                 name[size - 1] = '\0';
 648 
 649                 ev.type       = TELNET_EV_TTYPE;
 650                 ev.ttype.cmd  = TELNET_TTYPE_IS;
 651                 ev.ttype.name = name;
 652                 telnet->eh(telnet, &ev, telnet->ud);
 653 
 654                 /* clean up */
 655                 FREE(name);
 656         } else {
 657                 ev.type       = TELNET_EV_TTYPE;
 658                 ev.ttype.cmd  = TELNET_TTYPE_SEND;
 659                 ev.ttype.name = 0;
 660                 telnet->eh(telnet, &ev, telnet->ud);
 661         }
 662 
 663         return 0;
 664 }
 665 
 666 /* process a subnegotiation buffer; return non-zero if the current buffer
 667  * must be aborted and reprocessed.
 668  */
 669 static int _subnegotiate(telnet_t *telnet) {
     /* [previous][next][first][last][top][bottom][index][help] */
 670         telnet_event_t ev;
 671 
 672         /* standard subnegotiation event */
 673         ev.type       = TELNET_EV_SUBNEGOTIATION;
 674         ev.sub.telopt = telnet->sb_telopt;
 675         ev.sub.buffer = telnet->buffer;
 676         ev.sub.size   = telnet->buffer_pos;
 677         telnet->eh(telnet, &ev, telnet->ud);
 678 
 679         switch (telnet->sb_telopt) {
 680 
 681         /* specially handled subnegotiation telopt types */
 682         case TELNET_TELOPT_TTYPE:
 683                 return _ttype_telnet(telnet, telnet->buffer, telnet->buffer_pos);
 684         case TELNET_TELOPT_ENVIRON:
 685         case TELNET_TELOPT_NEW_ENVIRON:
 686                 return _environ_telnet(telnet, telnet->sb_telopt, telnet->buffer,
 687                                 telnet->buffer_pos);
 688         default:
 689                 return 0;
 690         }
 691 }
 692 
 693 /* initialize a telnet state tracker */
 694 telnet_t *telnet_init(const telnet_telopt_t *telopts,
     /* [previous][next][first][last][top][bottom][index][help] */
 695                       telnet_event_handler_t eh, unsigned char flags, void *user_data) {
 696         /* allocate structure */
 697         struct telnet_t *telnet = (telnet_t*)calloc(1, sizeof(telnet_t));
 698         if (telnet == 0)
 699                 return 0;
 700 
 701         /* initialize data */
 702         telnet->ud      = user_data;
 703         telnet->telopts = telopts;
 704         telnet->eh      = eh;
 705         telnet->flags   = flags;
 706 
 707         return telnet;
 708 }
 709 
 710 /* free up any memory allocated by a state tracker */
 711 void telnet_free(telnet_t *telnet) {
     /* [previous][next][first][last][top][bottom][index][help] */
 712         /* free sub-request buffer */
 713         if (telnet->buffer != 0) {
 714                 FREE(telnet->buffer);
 715                 telnet->buffer      = 0; //-V1048
 716                 telnet->buffer_size = 0;
 717                 telnet->buffer_pos  = 0;
 718         }
 719 
 720         /* free RFC-1143 queue */
 721         if (telnet->q) {
 722                 FREE(telnet->q);
 723                 telnet->q      = NULL;
 724                 telnet->q_size = 0;
 725                 telnet->q_cnt  = 0;
 726         }
 727 
 728         /* free the telnet structure itself */
 729         free(telnet);
 730 }
 731 
 732 /* push a byte into the telnet buffer */
 733 static telnet_error_t _buffer_byte(telnet_t *telnet,
     /* [previous][next][first][last][top][bottom][index][help] */
 734                                    unsigned char byte) {
 735         char *new_buffer;
 736 
 737         /* check if we're out of room */
 738         if (telnet->buffer_pos == telnet->buffer_size) {
 739                 size_t i;
 740                 /* find the next buffer size */
 741                 for (i = 0; i != _buffer_sizes_count; ++i) {
 742                         if (_buffer_sizes[i] == telnet->buffer_size) {
 743                                 break;
 744                         }
 745                 }
 746 
 747                 /* overflow -- can't grow any more */
 748                 if (i >= _buffer_sizes_count - 1) {
 749                         _error(telnet, __LINE__, __func__, TELNET_EOVERFLOW, 0,
 750                                         "subnegotiation buffer size limit reached");
 751                         return TELNET_EOVERFLOW;
 752                 }
 753 
 754                 /* (re)allocate buffer */
 755                 new_buffer = (char *)realloc(telnet->buffer, _buffer_sizes[i + 1]);
 756                 if (new_buffer == 0) {
 757                         _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
 758                                         "realloc() failed");
 759                         return TELNET_ENOMEM;
 760                 }
 761 
 762                 telnet->buffer = new_buffer;
 763                 telnet->buffer_size = _buffer_sizes[i + 1];
 764         }
 765 
 766         /* push the byte, all set */
 767         telnet->buffer[telnet->buffer_pos++] = (char) byte;
 768         return TELNET_EOK;
 769 }
 770 
 771 static void _process(telnet_t *telnet, const char *buffer, size_t size) {
     /* [previous][next][first][last][top][bottom][index][help] */
 772         telnet_event_t ev;
 773         unsigned char byte;
 774         size_t i, start;
 775         for (i = start = 0; i != size; ++i) {
 776                 byte = (unsigned char) buffer[i];
 777                 switch (telnet->state) {
 778                 /* regular data */
 779                 case TELNET_STATE_DATA:
 780                         /* on an IAC byte, pass through all pending bytes and
 781                          * switch states */
 782                         if (byte == TELNET_IAC) {
 783                                 if (i != start) {
 784                                         ev.type        = TELNET_EV_DATA;
 785                                         ev.data.buffer = buffer + start;
 786                                         ev.data.size   = i - start;
 787                                         telnet->eh(telnet, &ev, telnet->ud);
 788                                 }
 789                                 telnet->state = TELNET_STATE_IAC;
 790                         } else if (byte == '\r' &&
 791                                             (telnet->flags & TELNET_FLAG_NVT_EOL) &&
 792                                            !(telnet->flags & TELNET_FLAG_RECEIVE_BINARY)) {
 793                                 if (i != start) {
 794                                         ev.type        = TELNET_EV_DATA;
 795                                         ev.data.buffer = buffer + start;
 796                                         ev.data.size   = i - start;
 797                                         telnet->eh(telnet, &ev, telnet->ud);
 798                                 }
 799                                 telnet->state = TELNET_STATE_EOL;
 800                         }
 801                         break;
 802 
 803                 /* NVT EOL to be translated */
 804                 case TELNET_STATE_EOL:
 805                         if (byte != '\n') {
 806                                 byte           = '\r';
 807                                 ev.type        = TELNET_EV_DATA;
 808                                 ev.data.buffer = (char*)&byte;
 809                                 ev.data.size   = 1;
 810                                 telnet->eh(telnet, &ev, telnet->ud);
 811                                 byte           = (unsigned char) buffer[i];
 812                         }
 813                         // any byte following '\r' other than '\n' or '\0' is invalid,
 814                         // so pass both \r and the byte
 815                         start = i;
 816                         if (byte == '\0')
 817                                 ++start;
 818                         /* state update */
 819                         telnet->state = TELNET_STATE_DATA;
 820                         break;
 821 
 822                 /* IAC command */
 823                 case TELNET_STATE_IAC:
 824                         switch (byte) {
 825                         /* subnegotiation */
 826                         case TELNET_SB:
 827                                 telnet->state = TELNET_STATE_SB;
 828                                 break;
 829                         /* negotiation commands */
 830                         case TELNET_WILL:
 831                                 telnet->state = TELNET_STATE_WILL;
 832                                 break;
 833                         case TELNET_WONT:
 834                                 telnet->state = TELNET_STATE_WONT;
 835                                 break;
 836                         case TELNET_DO:
 837                                 telnet->state = TELNET_STATE_DO;
 838                                 break;
 839                         case TELNET_DONT:
 840                                 telnet->state = TELNET_STATE_DONT;
 841                                 break;
 842                         /* IAC escaping */
 843                         case TELNET_IAC:
 844                                 /* event */
 845                                 ev.type        = TELNET_EV_DATA;
 846                                 ev.data.buffer = (char*)&byte;
 847                                 ev.data.size   = 1;
 848                                 telnet->eh(telnet, &ev, telnet->ud);
 849 
 850                                 /* state update */
 851                                 start         = i + 1;
 852                                 telnet->state = TELNET_STATE_DATA;
 853                                 break;
 854                         /* some other command */
 855                         default:
 856                                 /* event */
 857                                 ev.type       = TELNET_EV_IAC;
 858                                 ev.iac.cmd    = byte;
 859                                 telnet->eh(telnet, &ev, telnet->ud);
 860 
 861                                 /* state update */
 862                                 start         = i + 1;
 863                                 telnet->state = TELNET_STATE_DATA;
 864                         }
 865                         break;
 866 
 867                 /* negotiation commands */
 868                 case TELNET_STATE_WILL:
 869                 case TELNET_STATE_WONT:
 870                 case TELNET_STATE_DO:
 871                 case TELNET_STATE_DONT:
 872                         _negotiate(telnet, byte);
 873                         start         = i + 1;
 874                         telnet->state = TELNET_STATE_DATA;
 875                         break;
 876 
 877                 /* subnegotiation -- determine subnegotiation telopt */
 878                 case TELNET_STATE_SB:
 879                         telnet->sb_telopt  = byte;
 880                         telnet->buffer_pos = 0;
 881                         telnet->state      = TELNET_STATE_SB_DATA;
 882                         break;
 883 
 884                 /* subnegotiation -- buffer bytes until end request */
 885                 case TELNET_STATE_SB_DATA:
 886                         /* IAC command in subnegotiation -- either IAC SE or IAC IAC */
 887                         if (byte == TELNET_IAC) {
 888                                 telnet->state = TELNET_STATE_SB_DATA_IAC;
 889                         } else if (_buffer_byte(telnet, byte) != TELNET_EOK) {
 890                                 start = i + 1;
 891                                 telnet->state = TELNET_STATE_DATA;
 892                         }
 893                         break;
 894 
 895                 /* IAC escaping inside a subnegotiation */
 896                 case TELNET_STATE_SB_DATA_IAC:
 897                         switch (byte) {
 898                         /* end subnegotiation */
 899                         case TELNET_SE:
 900                                 /* return to default state */
 901                                 start = i + 1;
 902                                 telnet->state = TELNET_STATE_DATA;
 903 
 904                                 /* process subnegotiation */
 905                                 if (_subnegotiate(telnet) != 0) {
 906                                         telnet_recv(telnet, &buffer[start], size - start);
 907                                         return;
 908                                 }
 909                                 break;
 910                         /* escaped IAC byte */
 911                         case TELNET_IAC:
 912                                 /* push IAC into buffer */
 913                                 if (_buffer_byte(telnet, TELNET_IAC) !=
 914                                                 TELNET_EOK) {
 915                                         start = i + 1;
 916                                         telnet->state = TELNET_STATE_DATA;
 917                                 } else {
 918                                         telnet->state = TELNET_STATE_SB_DATA;
 919                                 }
 920                                 break;
 921                         /* something else -- protocol error.  attempt to process
 922                          * content in subnegotiation buffer, then evaluate the
 923                          * given command as an IAC code.
 924                          */
 925                         default:
 926                                 _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0,
 927                                                 "unexpected byte after IAC inside SB: %d",
 928                                                 byte);
 929 
 930                                 /* enter IAC state */
 931                                 start = i + 1;
 932                                 telnet->state = TELNET_STATE_IAC;
 933 
 934                                 /* process subnegotiation; see comment in
 935                                  * TELNET_STATE_SB_DATA_IAC about invoking telnet_recv()
 936                                  */
 937                                 if (_subnegotiate(telnet) != 0) {
 938                                         telnet_recv(telnet, &buffer[start], size - start);
 939                                         return;
 940                                 } else {
 941                                         /* recursive call to get the current input byte processed
 942                                          * as a regular IAC command.  we could use a goto, but
 943                                          * that would be gross.
 944                                          */
 945                                         _process(telnet, (char *)&byte, 1);
 946                                 }
 947                                 break;
 948                         }
 949                         break;
 950                 }
 951         }
 952 
 953         /* pass through any remaining bytes */
 954         if (telnet->state == TELNET_STATE_DATA && i != start) {
 955                 ev.type        = TELNET_EV_DATA;
 956                 ev.data.buffer = buffer + start;
 957                 ev.data.size   = i - start;
 958                 telnet->eh(telnet, &ev, telnet->ud);
 959         }
 960 }
 961 
 962 /* push a bytes into the state tracker */
 963 void telnet_recv(telnet_t *telnet, const char *buffer,
     /* [previous][next][first][last][top][bottom][index][help] */
 964                  size_t size) {
 965         _process(telnet, buffer, size);
 966 }
 967 
 968 /* send an iac command */
 969 void telnet_iac(telnet_t *telnet, unsigned char cmd) {
     /* [previous][next][first][last][top][bottom][index][help] */
 970         unsigned char bytes[2];
 971         bytes[0] = TELNET_IAC;
 972         bytes[1] = cmd;
 973         _sendu(telnet, bytes, 2);
 974 }
 975 
 976 /* send negotiation */
 977 void telnet_negotiate(telnet_t *telnet, unsigned char cmd,
     /* [previous][next][first][last][top][bottom][index][help] */
 978                       unsigned char telopt) {
 979         telnet_rfc1143_t q;
 980 
 981         /* if we're in proxy mode, just send it now */
 982         if (telnet->flags & TELNET_FLAG_PROXY) {
 983                 unsigned char bytes[3];
 984                 bytes[0] = TELNET_IAC;
 985                 bytes[1] = cmd;
 986                 bytes[2] = telopt;
 987                 _sendu(telnet, bytes, 3);
 988                 return;
 989         }
 990 
 991         /* get current option states */
 992         q = _get_rfc1143(telnet, telopt);
 993 
 994         switch (cmd) {
 995         /* advertise willingness to support an option */
 996         case TELNET_WILL:
 997                 switch (Q_US(q)) {
 998                 case Q_NO:
 999                         _set_rfc1143(telnet, telopt, Q_WANTYES, Q_HIM(q));
1000                         _send_negotiate(telnet, TELNET_WILL, telopt);
1001                         break;
1002                 case Q_WANTNO:
1003                         _set_rfc1143(telnet, telopt, Q_WANTNO_OP, Q_HIM(q));
1004                         break;
1005                 case Q_WANTYES_OP:
1006                         _set_rfc1143(telnet, telopt, Q_WANTYES, Q_HIM(q));
1007                         break;
1008                 }
1009                 break;
1010 
1011         /* force turn-off of locally enabled option */
1012         case TELNET_WONT:
1013                 switch (Q_US(q)) {
1014                 case Q_YES:
1015                         _set_rfc1143(telnet, telopt, Q_WANTNO, Q_HIM(q));
1016                         _send_negotiate(telnet, TELNET_WONT, telopt);
1017                         break;
1018                 case Q_WANTYES:
1019                         _set_rfc1143(telnet, telopt, Q_WANTYES_OP, Q_HIM(q));
1020                         break;
1021                 case Q_WANTNO_OP:
1022                         _set_rfc1143(telnet, telopt, Q_WANTNO, Q_HIM(q));
1023                         break;
1024                 }
1025                 break;
1026 
1027         /* ask remote end to enable an option */
1028         case TELNET_DO:
1029                 switch (Q_HIM(q)) {
1030                 case Q_NO:
1031                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES);
1032                         _send_negotiate(telnet, TELNET_DO, telopt);
1033                         break;
1034                 case Q_WANTNO:
1035                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTNO_OP);
1036                         break;
1037                 case Q_WANTYES_OP:
1038                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES);
1039                         break;
1040                 }
1041                 break;
1042 
1043         /* demand remote end disable an option */
1044         case TELNET_DONT:
1045                 switch (Q_HIM(q)) {
1046                 case Q_YES:
1047                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTNO);
1048                         _send_negotiate(telnet, TELNET_DONT, telopt);
1049                         break;
1050                 case Q_WANTYES:
1051                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES_OP);
1052                         break;
1053                 case Q_WANTNO_OP:
1054                         _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTNO);
1055                         break;
1056                 }
1057                 break;
1058         }
1059 }
1060 
1061 /* send non-command data (escapes IAC bytes) */
1062 void telnet_send(telnet_t *telnet, const char *buffer,
     /* [previous][next][first][last][top][bottom][index][help] */
1063                  size_t size) {
1064         size_t i, l;
1065 
1066         for (l = i = 0; i != size; ++i) {
1067                 /* dump prior portion of text, send escaped bytes */
1068                 if (buffer[i] == (char)TELNET_IAC) {
1069                         /* dump prior text if any */
1070                         if (i != l) {
1071                                 _send(telnet, buffer + l, i - l);
1072                         }
1073                         l = i + 1;
1074 
1075                         /* send escape */
1076                         telnet_iac(telnet, TELNET_IAC);
1077                 }
1078         }
1079 
1080         /* send whatever portion of buffer is left */
1081         if (i != l) {
1082                 _send(telnet, buffer + l, i - l);
1083         }
1084 }
1085 
1086 /* send non-command text (escapes IAC bytes and does NVT translation) */
1087 void telnet_send_text(telnet_t *telnet, const char *buffer,
     /* [previous][next][first][last][top][bottom][index][help] */
1088                       size_t size) {
1089         size_t i, l;
1090 
1091         for (l = i = 0; i != size; ++i) {
1092                 /* dump prior portion of text, send escaped bytes */
1093                 if (buffer[i] == (char)TELNET_IAC) {
1094                         /* dump prior text if any */
1095                         if (i != l) {
1096                                 _send(telnet, buffer + l, i - l);
1097                         }
1098                         l = i + 1;
1099 
1100                         /* send escape */
1101                         telnet_iac(telnet, TELNET_IAC);
1102                 }
1103                 /* special characters if not in BINARY mode */
1104                 else if (!(telnet->flags & TELNET_FLAG_TRANSMIT_BINARY) &&
1105                                  (buffer[i] == '\r' || buffer[i] == '\n')) {
1106                         /* dump prior portion of text */
1107                         if (i != l) {
1108                                 _send(telnet, buffer + l, i - l);
1109                         }
1110                         l = i + 1;
1111 
1112                         /* automatic translation of \r -> CRNUL */
1113                         if (buffer[i] == '\r') {
1114                                 _send(telnet, CRNUL, 2);
1115                         }
1116                         /* automatic translation of \n -> CRLF */
1117                         else {
1118                                 _send(telnet, CRLF, 2);
1119                         }
1120                 }
1121         }
1122 
1123         /* send whatever portion of buffer is left */
1124         if (i != l) {
1125                 _send(telnet, buffer + l, i - l);
1126         }
1127 }
1128 
1129 /* send subnegotiation header */
1130 void telnet_begin_sb(telnet_t *telnet, unsigned char telopt) {
     /* [previous][next][first][last][top][bottom][index][help] */
1131         unsigned char sb[3];
1132         sb[0] = TELNET_IAC;
1133         sb[1] = TELNET_SB;
1134         sb[2] = telopt;
1135         _sendu(telnet, sb, 3);
1136 }
1137 
1138 /* send formatted data with \r and \n translation in addition to IAC IAC */
1139 int telnet_vprintf(telnet_t *telnet, const char *fmt, va_list va) {
     /* [previous][next][first][last][top][bottom][index][help] */
1140         char buffer[1024];
1141         char *output = buffer;
1142         int rs, i, l;
1143 
1144         /* format */
1145         va_list va2;
1146         va_copy(va2, va);
1147         rs = vsnprintf(buffer, sizeof(buffer), fmt, va);
1148         if ((unsigned long) rs >= sizeof(buffer)) {
1149                 output = (char*)malloc((unsigned long) ((unsigned long)rs + 1L));
1150                 if (output == 0) {
1151                         _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
1152                                         "malloc() failed: %s", strerror(errno));
1153                         va_end(va2);
1154                         return -1;
1155                 }
1156                 rs = vsnprintf(output, rs + 1, fmt, va2);
1157         }
1158         va_end(va2);
1159         va_end(va);
1160 
1161         /* send */
1162         for (l = i = 0; i != rs; ++i) {
1163                 /* special characters */
1164                 if (output[i] == (char)TELNET_IAC || output[i] == '\r' ||
1165                                 output[i] == '\n') {
1166                         /* dump prior portion of text */
1167                         if (i != l)
1168                                 _send(telnet, output + l, (size_t) (i - l));
1169                         l = i + 1;
1170 
1171                         /* IAC -> IAC IAC */
1172                         if (output[i] == (char)TELNET_IAC)
1173                                 telnet_iac(telnet, TELNET_IAC);
1174                         /* automatic translation of \r -> CRNUL */
1175                         else if (output[i] == '\r')
1176                                 _send(telnet, CRNUL, 2);
1177                         /* automatic translation of \n -> CRLF */
1178                         else if (output[i] == '\n')
1179                                 _send(telnet, CRLF, 2);
1180                 }
1181         }
1182 
1183         /* send whatever portion of output is left */
1184         if (i != l) {
1185                 _send(telnet, output + l, (size_t) (i - l));
1186         }
1187 
1188         /* free allocated memory, if any */
1189         if (output != buffer) {
1190                 FREE(output);
1191         }
1192 
1193         return rs;
1194 }
1195 
1196 /* see telnet_vprintf */
1197 int telnet_printf(telnet_t *telnet, const char *fmt, ...) {
     /* [previous][next][first][last][top][bottom][index][help] */
1198         va_list va;
1199         int rs;
1200 
1201         va_start(va, fmt);
1202         rs = telnet_vprintf(telnet, fmt, va);
1203         va_end(va);
1204 
1205         return rs;
1206 }
1207 
1208 /* send formatted data through telnet_send */
1209 int telnet_raw_vprintf(telnet_t *telnet, const char *fmt, va_list va) {
     /* [previous][next][first][last][top][bottom][index][help] */
1210         char buffer[1024];
1211         char *output = buffer;
1212         int rs;
1213 
1214         /* format; allocate more space if necessary */
1215         va_list va2;
1216         va_copy(va2, va);
1217         rs = vsnprintf(buffer, sizeof(buffer), fmt, va);
1218         if ((unsigned long) rs >= sizeof(buffer)) {
1219                 output = (char*)malloc((unsigned long) rs + 1);
1220                 if (output == 0) {
1221                         _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0,
1222                                         "malloc() failed: %s", strerror(errno));
1223                         va_end(va2);
1224                         return -1;
1225                 }
1226                 rs = vsnprintf(output, (int)((unsigned int) rs + 1), fmt, va2);
1227         }
1228         va_end(va2);
1229         va_end(va);
1230 
1231         /* send out the formatted data */
1232         telnet_send(telnet, output, (size_t) rs);
1233 
1234         /* release allocated memory, if any */
1235         if (output != buffer) {
1236                 FREE(output);
1237         }
1238 
1239         return rs;
1240 }
1241 
1242 /* see telnet_raw_vprintf */
1243 int telnet_raw_printf(telnet_t *telnet, const char *fmt, ...) {
     /* [previous][next][first][last][top][bottom][index][help] */
1244         va_list va;
1245         int rs;
1246 
1247         va_start(va, fmt);
1248         rs = telnet_raw_vprintf(telnet, fmt, va);
1249         va_end(va);
1250 
1251         return rs;
1252 }

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