diff --git a/README.md b/README.md index 517d138..fc04a8e 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ sudo make install ## Usage ```sh -sbotc [-j] [-T] [-l] [-r] +sbotc [-j] [-T] [-l] [-r] [-e] [ -n | [-c ] [-k ] [-K ] ] [ [-s ] [-p ] [ -4 | -6 ] | [-u ] ] [ -a | [-t ] [...] ] diff --git a/sbotc.1 b/sbotc.1 index 1c12004..00e7178 100644 --- a/sbotc.1 +++ b/sbotc.1 @@ -11,6 +11,7 @@ .Op Fl l .Op Fl r .Op Fl T +.Op Fl e .Op Fl a . .Oo @@ -52,6 +53,8 @@ Don't output newlines after string or JSON packets. .It Fl r Raw mode. Disables stdin line buffering/editing and echoing. Implies .Fl l . +.It Fl e +Encode arguments as strings, rather than expecting them to be JSON-encoded. .It Fl T Test using shs1-testsuite protocol. Instead of connecting to a server and running a command, connect to stdio. On successful handshake, output concatenation of @@ -104,7 +107,9 @@ Default is to look up the method in .It Ar method Method name. .It Op Ar argument ... -Arguments to pass to the method call. Each argument must be JSON-encoded. +Arguments to pass to the method call. Each argument must be JSON-encoded, unless the +.Fl e +option is used, in which the arguments are treated as strings. .El .Sh ENVIRONMENT .Bl -tag diff --git a/sbotc.c b/sbotc.c index 5e5cc31..c364800 100644 --- a/sbotc.c +++ b/sbotc.c @@ -112,7 +112,7 @@ static void reset_termios() { } static void usage() { - fputs("usage: sbotc [-j] [-T] [-l] [-r]\n" + fputs("usage: sbotc [-j] [-T] [-l] [-r] [-e]\n" " [ -n | [-c ] [-k ] [-K ] ]\n" " [ [-s ] [-p ] [ -4 | -6 ] | [-u ] ]\n" " [ -a | [-t ] [...] ]\n", stderr); @@ -916,25 +916,54 @@ static int method_to_json(char *out, size_t outlen, const char *str) { return i; } -static int args_to_json_length(int argc, char *argv[]) { +static int args_to_json_length(int argc, char *argv[], bool encode_strings) { int i = 0; int len = 3; // "[]\0" - for (i = 0; i < argc; i++) - len += strlen(argv[i])+1; + for (i = 0; i < argc; i++) { + if (!encode_strings) { + len += strlen(argv[i])+1; + } else { + len += 3; // "\"\"," + char *arg = argv[i], c; + while ((c = *arg++)) switch (c) { + case '"': len += 2; break; + case '\\': len += 2; break; + default: len++; + } + } + } return len; } -static int args_to_json(char *out, size_t outlen, unsigned int argc, char *argv[]) { +static int args_to_json(char *out, size_t outlen, unsigned int argc, char *argv[], bool encode_strings) { size_t i = 0; size_t j; if (i+1 > outlen) return -1; out[i++] = '['; for (j = 0; j < argc; j++) { - size_t len = strlen(argv[j]); - if (j > 0) out[i++] = ','; - if (i+len > outlen) return -1; - strncpy(out+i, argv[j], len); - i += len; + if (!encode_strings) { + size_t len = strlen(argv[j]); + if (j > 0) out[i++] = ','; + if (i+len > outlen) return -1; + strncpy(out+i, argv[j], len); + i += len; + } else { + char *arg = argv[j]; + char c; + if (j > 0) { + if (i+1 > outlen) return -1; + out[i++] = ','; + } + if (i+1 > outlen) return -1; + out[i++] = '"'; + while ((c = *arg++)) { + if (i+2 > outlen) return -1; + if (c == '"' || c == '\\') out[i++] = '\\'; + out[i++] = c; + } + if (i+1 > outlen) return -1; + out[i++] = '"'; + } } if (i+2 > outlen) return -1; out[i++] = ']'; @@ -972,6 +1001,7 @@ int main(int argc, char *argv[]) { bool ipv4_arg = false; bool ipv6_arg = false; bool passthrough = false; + bool strings = false; enum ip_family ip_family; get_app_dir(app_dir, sizeof(app_dir)); @@ -1008,6 +1038,7 @@ int main(int argc, char *argv[]) { case 'a': passthrough = true; break; case 'l': no_newline = true; break; case 'r': raw = true; no_newline = true; break; + case 'e': strings = true; break; default: usage(); } } @@ -1027,7 +1058,7 @@ int main(int argc, char *argv[]) { memcpy(shs_cap_key, ssb_cap, 32); } - argument_len = test ? 0 : args_to_json_length(argc-i, argv+i); + argument_len = test ? 0 : args_to_json_length(argc-i, argv+i, strings); char argument[argument_len]; if (passthrough) { @@ -1037,7 +1068,7 @@ int main(int argc, char *argv[]) { if (test) errx(1, "-a option conflicts with -T test"); } else if (!test) { - rc = args_to_json(argument, sizeof(argument), argc-i, argv+i); + rc = args_to_json(argument, sizeof(argument), argc-i, argv+i, strings); if (rc < 0) errx(1, "unable to collect arguments"); char manifest_buf[8192];