1
0
mirror of https://github.com/winscp/winscp.git synced 2026-10-24 02:28:55 +03:00
Files
winscp/source/putty/utils/format_connection_setup_command.c
Martin Prikryl fbc97830e9 PuTTY 0.84
Source commit: 74c128b1c46223d1ff41e055c5fadd44bf73dbe4
2026-05-30 01:01:18 +02:00

185 lines
5.8 KiB
C

/*
* Formats a command line using the formatting language common to
* Telnet proxies, local proxy commands, and pre-connection hooks.
*
* Returns the formatted command, dynamically allocated. Also,
* optionally, returns flags indicating whether %user or %pass were
* referred to but not provided in the Conf.
*/
#include "putty.h"
char *format_connection_setup_command(
const char *fmt, SockAddr *addr, int port, Conf *conf, unsigned *flags_out)
{
int so = 0, eo = 0;
strbuf *buf = strbuf_new();
unsigned flags = 0;
/* we need to escape \\, \%, \r, \n, \t, \x??, \0???,
* %%, %host, %port, %user, and %pass
*/
while (fmt[eo] != 0) {
/* scan forward until we hit end-of-line,
* or an escape character (\ or %) */
while (fmt[eo] != 0 && fmt[eo] != '%' && fmt[eo] != '\\')
eo++;
/* if we hit eol, break out of our escaping loop */
if (fmt[eo] == 0) break;
/* if there was any unescaped text before the escape
* character, send that now */
if (eo != so)
put_data(buf, fmt + so, eo - so);
so = eo++;
/* if the escape character was the last character of
* the line, we'll just stop and send it. */
if (fmt[eo] == 0) break;
if (fmt[so] == '\\') {
/* we recognize \\, \%, \r, \n, \t, \x??.
* anything else, we just send unescaped (including the \).
*/
switch (fmt[eo]) {
case '\\':
put_byte(buf, '\\');
eo++;
break;
case '%':
put_byte(buf, '%');
eo++;
break;
case 'r':
put_byte(buf, '\r');
eo++;
break;
case 'n':
put_byte(buf, '\n');
eo++;
break;
case 't':
put_byte(buf, '\t');
eo++;
break;
case 'x':
case 'X': {
/* escaped hexadecimal value (ie. \xff) */
unsigned char v = 0;
int i = 0;
for (;;) {
eo++;
if (fmt[eo] >= '0' && fmt[eo] <= '9')
v += fmt[eo] - '0';
else if (fmt[eo] >= 'a' && fmt[eo] <= 'f')
v += fmt[eo] - 'a' + 10;
else if (fmt[eo] >= 'A' && fmt[eo] <= 'F')
v += fmt[eo] - 'A' + 10;
else {
/* non hex character, so we abort and just
* send the whole thing unescaped (including \x)
*/
put_byte(buf, '\\');
eo = so + 1;
break;
}
/* we only extract two hex characters */
if (i == 1) {
put_byte(buf, v);
eo++;
break;
}
i++;
v <<= 4;
}
break;
}
default:
put_data(buf, fmt + so, 2);
eo++;
break;
}
} else {
/* % escape. we recognize %%, %host, %port, %user, %pass.
* %proxyhost, %proxyport. Anything else we just send
* unescaped (including the %).
*/
if (fmt[eo] == '%') {
put_byte(buf, '%');
eo++;
}
else if (strnicmp(fmt + eo, "host", 4) == 0) {
char dest[512];
sk_getaddr(addr, dest, lenof(dest));
put_data(buf, dest, strlen(dest));
eo += 4;
}
else if (strnicmp(fmt + eo, "port", 4) == 0) {
put_fmt(buf, "%d", port);
eo += 4;
}
else if (strnicmp(fmt + eo, "user", 4) == 0) {
const char *username = conf_get_str(conf, CONF_proxy_username);
put_data(buf, username, strlen(username));
eo += 4;
if (!*username)
flags |= TELNET_CMD_MISSING_USERNAME;
}
else if (strnicmp(fmt + eo, "pass", 4) == 0) {
const char *password = conf_get_str(conf, CONF_proxy_password);
put_data(buf, password, strlen(password));
eo += 4;
if (!*password)
flags |= TELNET_CMD_MISSING_PASSWORD;
}
else if (strnicmp(fmt + eo, "proxyhost", 9) == 0) {
const char *host = conf_get_str(conf, CONF_proxy_host);
put_data(buf, host, strlen(host));
eo += 9;
}
else if (strnicmp(fmt + eo, "proxyport", 9) == 0) {
int port = conf_get_int(conf, CONF_proxy_port);
put_fmt(buf, "%d", port);
eo += 9;
}
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.
*/
put_byte(buf, '%');
}
}
/* 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) {
put_data(buf, fmt + so, eo - so);
}
if (flags_out)
*flags_out = flags;
return strbuf_to_str(buf);
}