Skip to content

Commit

Permalink
Merge pull request #3 from Sketch/widechar
Browse files Browse the repository at this point in the history
Add Telnet character set negotiation
  • Loading branch information
kruton committed Jul 15, 2012
2 parents 9157f81 + 66ee214 commit fe8fa32
Showing 1 changed file with 69 additions and 2 deletions.
71 changes: 69 additions & 2 deletions src/socket.c
Expand Up @@ -310,6 +310,7 @@ typedef struct Sock { /* an open connection to a server */
conString *prompt; /* prompt from server */
struct timeval prompt_timeout; /* when does unterm'd line become a prompt */
int ttype; /* index into enum_ttype[] */
int charset; /* index into enum_charset[] */
attr_t attrs; /* current text attributes */
attr_t prepromptattrs; /* text attributes before implicit prompt */
unsigned long alert_id; /* id of last alert on this socket */
Expand Down Expand Up @@ -397,6 +398,12 @@ STATIC_BUFFER(telbuf);

#define MAXQUIET 25 /* max # of lines to suppress during login */

static const char *enum_charset[] = {
"UTF-8",
"ISO-8859-1", /* No real support; code passes all chars */
"US-ASCII",
"" /* Null-terminated list, so we can loop */
};
/* Note: many telnet servers send DO ECHO and DO SGA together to mean
* character-at-a-time mode.
*/
Expand Down Expand Up @@ -436,7 +443,7 @@ STATIC_BUFFER(telbuf);
#define TN_ENVIRON ((char)36) /* 1408 - (not used) */
#define TN_AUTH ((char)37) /* 1416 - (not used) */
#define TN_NEW_ENVIRON ((char)39) /* 1572 - (not used) */
#define TN_CHARSET ((char)42) /* 2066 - (not used) */
#define TN_CHARSET ((char)42) /* 2066 - Charset negotiation */
/* 85 & 86 are not standard. See http://www.randomly.org/projects/MCCP/ */
#define TN_COMPRESS ((char)85) /* MCCP v1 */
#define TN_COMPRESS2 ((char)86) /* MCCP v2 */
Expand Down Expand Up @@ -1239,6 +1246,7 @@ static int opensock(World *world, int flags)
xsock->host = NULL;
xsock->port = NULL;
xsock->ttype = -1;
xsock->charset = 2; /* Default to US-ASCII, not that we act on it */
xsock->fd = -1;
xsock->pid = -1;
xsock->fsastate = '\0';
Expand Down Expand Up @@ -2792,8 +2800,15 @@ static void test_prompt(void)

static void telnet_subnegotiation(void)
{
unsigned int i;
char *p;
const char *end;
char temp_buff[255]; /* Same length as whole subnegotiation line. */
char *temp_ptr;
int ttype;
char charset_sep = '\0';
int chosen_charset = -1;

static conString enum_ttype[] = {
STRING_LITERAL("TINYFUGUE"),
STRING_LITERAL("ANSI-ATTR"),
Expand All @@ -2804,6 +2819,7 @@ static void telnet_subnegotiation(void)
telnet_debug("recv", xsock->subbuffer->data, xsock->subbuffer->len);
Stringtrunc(xsock->subbuffer, xsock->subbuffer->len - 2);
p = xsock->subbuffer->data + 2;
end = p + xsock->subbuffer->len;
switch (*p) {
case TN_TTYPE:
if (!TELOPT(xsock, us, *p)) {
Expand All @@ -2829,6 +2845,41 @@ static void telnet_subnegotiation(void)
}
xsock->flags |= SOCKCOMPRESS;
break;
case TN_CHARSET:
if (!TELOPT(xsock, them, *p)) {
no_reply("option was not agreed upon");
break;
}
if (*++p == '\01') { /* REQUEST <sep> <character set>... */
charset_sep = *++p;
while (p != end) {
temp_ptr = ++p;
while (p != end && *p != charset_sep) {
temp_buff[p - temp_ptr] = (*p & ~0x80);
++p;
}
temp_buff[p - temp_ptr] = '\0';
for (i = 0; enum_charset[i][0]; ++i) {
if (strcasecmp(enum_charset[i], temp_buff) == 0) {
if (chosen_charset == -1 || i < chosen_charset ) {
chosen_charset = i;
break;
}
}
}
}
if (chosen_charset > -1) {
Sprintf(telbuf, "%c%c%c%c%s%c%c", TN_IAC, TN_SB, TN_CHARSET, '\02', enum_charset[chosen_charset], TN_IAC, TN_SE);
xsock->charset = chosen_charset;
} else {
Sprintf(telbuf, "%c%c%c%c%c%c", TN_IAC, TN_SB, TN_CHARSET, '\03', TN_IAC, TN_SE);
}
} else {
no_reply("option not implemented");
break;
}
telnet_send(telbuf);
break;
default:
no_reply("unknown option");
break;
Expand Down Expand Up @@ -3141,7 +3192,8 @@ static int handle_socket_input(const char *simbuffer, int simlen)
#endif
rawchar == TN_ECHO ||
rawchar == TN_SEND_EOR ||
rawchar == TN_BINARY) /* accept any of these */
rawchar == TN_BINARY ||
rawchar == TN_CHARSET) /* accept any of these */
{
SET_TELOPT(xsock, them, rawchar); /* set state */
if (TELOPT(xsock, them_tog, rawchar)) {/* we requested it */
Expand Down Expand Up @@ -3420,6 +3472,21 @@ static void telnet_debug(const char *dir, const char *str, int len)
Stringcat(buffer, " SEND");
}
state = 0;
} else if (state == TN_CHARSET) {
if (*str == (char)1) {
Stringcat(buffer, " REQUEST ");
while (len--, str++, is_print(*str) && !(*str & 0x80))
Stringadd(buffer, *str);
len++, str--;
} else if (*str == (char)2) {
Stringcat(buffer, " ACCEPTED ");
while (len--, str++, is_print(*str) && !(*str & 0x80))
Stringadd(buffer, *str);
len++, str--;
} else if (*str == (char)3) {
Stringcat(buffer, " REJECTED");
}
state = 0;
} else {
Sappendf(buffer, " %u", (unsigned char)*str);
state = 0;
Expand Down

0 comments on commit fe8fa32

Please sign in to comment.