+ if (p->state == PROXY_CHANGE_NEW) {
+
+ int so = 0, eo = 0;
+
+ /* we need to escape \\, \%, \r, \n, \t, \x??, \0???,
+ * %%, %host, and %port
+ */
+
+ while (cfg.proxy_telnet_command[eo] != 0) {
+
+ /* scan forward until we hit end-of-line,
+ * or an escape character (\ or %) */
+ while (cfg.proxy_telnet_command[eo] != 0 &&
+ cfg.proxy_telnet_command[eo] != '%' &&
+ cfg.proxy_telnet_command[eo] != '\\') eo++;
+
+ /* if we hit eol, break out of our escaping loop */
+ if (cfg.proxy_telnet_command[eo] == 0) break;
+
+ /* if there was any unescaped text before the escape
+ * character, send that now */
+ if (eo != so) {
+ sk_write(p->sub_socket,
+ cfg.proxy_telnet_command + so, eo - so);
+ }
+
+ so = eo++;
+
+ /* if the escape character was the last character of
+ * the line, we'll just stop and send it. */
+ if (cfg.proxy_telnet_command[eo] == 0) break;
+
+ if (cfg.proxy_telnet_command[so] == '\\') {
+
+ /* we recognize \\, \%, \r, \n, \t, \x??.
+ * anything else, we just send unescaped (including the \).
+ */
+
+ switch (cfg.proxy_telnet_command[eo]) {
+
+ case '\\':
+ sk_write(p->sub_socket, "\\", 1);
+ eo++;
+ break;
+
+ case '%':
+ sk_write(p->sub_socket, "%%", 1);
+ eo++;
+ break;
+
+ case 'r':
+ sk_write(p->sub_socket, "\r", 1);
+ eo++;
+ break;
+
+ case 'n':
+ sk_write(p->sub_socket, "\n", 1);
+ eo++;
+ break;
+
+ case 't':
+ sk_write(p->sub_socket, "\t", 1);
+ eo++;
+ break;
+
+ case 'x':
+ case 'X':
+ {
+ /* escaped hexadecimal value (ie. \xff) */
+ unsigned char v = 0;
+ int i = 0;
+
+ for (;;) {
+ eo++;
+ if (cfg.proxy_telnet_command[eo] >= '0' &&
+ cfg.proxy_telnet_command[eo] <= '9')
+ v += cfg.proxy_telnet_command[eo] - '0';
+ else if (cfg.proxy_telnet_command[eo] >= 'a' &&
+ cfg.proxy_telnet_command[eo] <= 'f')
+ v += cfg.proxy_telnet_command[eo] - 'a' + 10;
+ else if (cfg.proxy_telnet_command[eo] >= 'A' &&
+ cfg.proxy_telnet_command[eo] <= 'F')
+ v += cfg.proxy_telnet_command[eo] - 'A' + 10;
+ else {
+ /* non hex character, so we abort and just
+ * send the whole thing unescaped (including \x)
+ */
+ sk_write(p->sub_socket, "\\", 1);
+ eo = so + 1;
+ break;
+ }
+
+ /* we only extract two hex characters */
+ if (i == 1) {
+ sk_write(p->sub_socket, &v, 1);
+ eo++;
+ break;
+ }
+
+ i++;
+ v <<= 4;
+ }
+ }
+ break;
+
+ default:
+ sk_write(p->sub_socket,
+ cfg.proxy_telnet_command + so, 2);
+ eo++;
+ break;
+ }
+ } else {
+
+ /* % escape. we recognize %%, %host, %port. anything else,
+ * we just send unescaped (including the %). */
+
+ if (cfg.proxy_telnet_command[eo] == '%') {
+ sk_write(p->sub_socket, "%", 1);
+ eo++;
+ }
+ else if (strnicmp(cfg.proxy_telnet_command + eo,
+ "host", 4) == 0) {
+ char dest[64];
+ sk_getaddr(p->remote_addr, dest, 64);
+ sk_write(p->sub_socket, dest, strlen(dest));
+ eo += 4;
+ }
+ else if (strnicmp(cfg.proxy_telnet_command + eo,
+ "port", 4) == 0) {
+ char port[8];
+ sprintf(port, "%i", p->remote_port);
+ sk_write(p->sub_socket, port, strlen(port));
+ eo += 4;
+ }
+ else {
+ /* we don't escape this, so send the % now, and
+ * don't advance eo, so that we'll consider the
+ * text immediately following the % as unescaped.
+ */
+ sk_write(p->sub_socket, "%", 1);
+ }
+ }
+
+ /* resume scanning for additional escapes after this one. */
+ so = eo;
+ }
+
+ /* if there is any unescaped text at the end of the line, send it */
+ if (eo != so) {
+ sk_write(p->sub_socket, cfg.proxy_telnet_command + so, eo - so);
+ }
+
+ p->state = 1;
+
+ return 0;
+ }
+
+ if (change == PROXY_CHANGE_CLOSING) {
+ /* if our proxy negotiation process involves closing and opening
+ * new sockets, then we would want to intercept this closing
+ * callback when we were expecting it. if we aren't anticipating
+ * a socket close, then some error must have occurred. we'll
+ * just pass those errors up to the backend.
+ */
+ return plug_closing(p->plug, p->closing_error_msg,
+ p->closing_error_code,
+ p->closing_calling_back);
+ }
+
+ if (change == PROXY_CHANGE_SENT) {
+ /* some (or all) of what we wrote to the proxy was sent.
+ * we don't do anything new, however, until we receive the
+ * proxy's response. we might want to set a timer so we can
+ * timeout the proxy negotiation after a while...
+ */
+ return 0;
+ }
+
+ if (change == PROXY_CHANGE_ACCEPTING) {
+ /* we should _never_ see this, as we are using our socket to
+ * connect to a proxy, not accepting inbound connections.
+ * what should we do? close the socket with an appropriate
+ * error message?
+ */
+ return plug_accepting(p->plug, p->accepting_sock);
+ }
+
+ if (change == PROXY_CHANGE_RECEIVE) {
+ /* we have received data from the underlying socket, which
+ * we'll need to parse, process, and respond to appropriately.
+ */
+
+ /* we're done */
+ proxy_activate(p);
+ /* proxy activate will have dealt with
+ * whatever is left of the buffer */
+ return 1;
+ }
+
+ plug_closing(p->plug, "Network error: Unexpected proxy error",
+ PROXY_ERROR_UNEXPECTED, 0);