1 /*
2  * reply.c
3  * (C)1998-2011 by Marc Huber <Marc.Huber@web.de>
4  * All rights reserved.
5  *
6  * $Id: reply.c,v 1.16 2015/03/14 06:11:27 marc Exp marc $
7  *
8  */
9 
10 #include "headers.h"
11 #include <stdarg.h>
12 #include <arpa/telnet.h>
13 
14 static const char rcsid[] __attribute__ ((used)) = "$Id: reply.c,v 1.16 2015/03/14 06:11:27 marc Exp marc $";
15 
16 /*
17  * For data written to the command channel we need to follow
18  * Telnet NVT conventions.
19  */
20 
buffer_reply(struct buffer * b,char * s,size_t len)21 struct buffer *buffer_reply(struct buffer *b, char *s, size_t len)
22 {
23     size_t j = 2 * len;
24     char *a = alloca(j);
25     char *t = a, *se = s + len;
26     DebugIn(DEBUG_PROC);
27 
28     for (; s < se; s++) {
29 	*t++ = *s;
30 	if (*s == '\r')
31 	    /* <CR> => <CR><NUL> */
32 	    *t++ = 0, len++;
33 	else if ((u_char) * s == IAC)
34 	    *t++ = IAC, len++;
35     }
36     b = buffer_write(b, a, len);
37     DebugOut(DEBUG_PROC);
38     return b;
39 }
40 
replyf(struct context * ctx,char * format,...)41 void replyf(struct context *ctx, char *format, ...)
42 {
43     ssize_t len = 1024, nlen;
44     size_t j = 2 * len;
45     char *tmpbuf;
46 
47     DebugIn(DEBUG_PROC);
48 
49   again:
50     tmpbuf = alloca(j);
51 
52     if (ctx && ctx->cfn > -1) {
53 	va_list ap;
54 	va_start(ap, format);
55 	nlen = vsnprintf(tmpbuf, len, format, ap);
56 	va_end(ap);
57 	if (len <= nlen) {
58 	    j = 2 * ++nlen;
59 	    goto again;
60 	}
61 	len = nlen;
62 
63 	if (len > -1) {
64 	    char *t = tmpbuf + len - 1;
65 	    char *u = tmpbuf + 2 * len - 1;
66 	    ssize_t f;
67 
68 	    /* <CR><NL> at the end of the format string is ok */
69 	    if (len > 1 && ((f = strlen(format)) > 1)
70 		&& format[f - 2] == '\r' && format[f - 1] == '\n') {
71 		*u-- = *t--;
72 		*u-- = *t--;
73 	    }
74 
75 	    for (; t >= tmpbuf; *u-- = *t--)
76 		if (*t == '\r')
77 		    /* <CR> => <CR><NUL> */
78 		    *u-- = 0, len++;
79 		else if ((u_char) * t == IAC)
80 		    /* <IAC> => <IAC><IAC> */
81 		    *u-- = IAC, len++;
82 	    ctx->cbufo = buffer_write(ctx->cbufo, u + 1, len);
83 
84 	    io_set_o(ctx->io, ctx->cfn);
85 	}
86     }
87     DebugOut(DEBUG_PROC);
88 }
89 
reply(struct context * ctx,char * s)90 void reply(struct context *ctx, char *s)
91 {
92     DebugIn(DEBUG_PROC);
93 
94     if (ctx && ctx->cfn > -1) {
95 	size_t len = strlen(s);
96 	if (len > 1 && s[len - 2] == '\r' && s[len - 1] == '\n') {
97 	    /* Don't escape <CR><LF> at end of string */
98 	    ctx->cbufo = buffer_reply(ctx->cbufo, s, len - 2);
99 	    ctx->cbufo = buffer_write(ctx->cbufo, "\r\n", 2);
100 	} else
101 	    ctx->cbufo = buffer_reply(ctx->cbufo, s, len);
102 
103 	io_set_o(ctx->io, ctx->cfn);
104     }
105     DebugOut(DEBUG_PROC);
106 }
107