diff --git a/README.md b/README.md index 9643e61..517d138 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ sudo make install ## Usage ```sh -sbotc [-j] [-T] [-l] +sbotc [-j] [-T] [-l] [-r] [ -n | [-c ] [-k ] [-K ] ] [ [-s ] [-p ] [ -4 | -6 ] | [-u ] ] [ -a | [-t ] [...] ] diff --git a/sbotc.1 b/sbotc.1 index 4e62805..91003b3 100644 --- a/sbotc.1 +++ b/sbotc.1 @@ -48,6 +48,8 @@ standard I/O. Send stdin data as JSON. .It Fl l Don't output newlines after string or JSON packets. +.It Fl r +Raw mode. Disables stdin line buffering/editing and echoing. .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 diff --git a/sbotc.c b/sbotc.c index 3bae9ac..db3bdff 100644 --- a/sbotc.c +++ b/sbotc.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -104,7 +105,7 @@ static const unsigned char ssb_cap[] = { }; static void usage() { - fputs("usage: sbotc [-j] [-T] [-l]\n" + fputs("usage: sbotc [-j] [-T] [-l] [-r]\n" " [ -n | [-c ] [-k ] [-K ] ]\n" " [ [-s ] [-p ] [ -4 | -6 ] | [-u ] ]\n" " [ -a | [-t ] [...] ]\n", stderr); @@ -857,7 +858,7 @@ static int muxrpc_write_blob_add(struct boxs *bs, int infd, int outfd, int req_i in == stream_state_ended_error || out == stream_state_ended_error ? 2 : 1; } -static int muxrpc_duplex(struct boxs *bs, int infd, int outfd, enum pkt_type in_ptype, int req_id, bool no_newline) { +static int muxrpc_duplex(struct boxs *bs, int infd, int outfd, enum pkt_type in_ptype, int req_id, bool no_newline, bool raw) { int rc; fd_set rd; int sfd = bs->s; @@ -866,7 +867,7 @@ static int muxrpc_duplex(struct boxs *bs, int infd, int outfd, enum pkt_type in_ enum stream_state out = stream_state_open; while (out == stream_state_open - || (in == stream_state_open && out != stream_state_ended_error)) { + || (!raw && in == stream_state_open && out != stream_state_ended_error)) { FD_ZERO(&rd); if (in == stream_state_open) FD_SET(infd, &rd); if (out == stream_state_open) FD_SET(sfd, &rd); @@ -957,6 +958,7 @@ int main(int argc, char *argv[]) { bool test = false; bool noauth = false; bool no_newline = false; + bool raw = false; bool host_arg = false; bool port_arg = false; bool key_arg = false; @@ -999,6 +1001,7 @@ int main(int argc, char *argv[]) { case '6': ipv6_arg = true; break; case 'a': passthrough = true; break; case 'l': no_newline = true; break; + case 'r': raw = true; break; default: usage(); } } @@ -1134,6 +1137,17 @@ do_tcp_connect: muxrpc_call(&bs, method, argument, type, typestr, 1); + struct termios orig_tc; + if (raw) { + struct termios raw_tc; + rc = tcgetattr(STDIN_FILENO, &orig_tc); + if (rc < 0) warnx("tcgetattr"); + raw_tc = orig_tc; + raw_tc.c_lflag &= ~(ICANON | ECHO); + rc = tcsetattr(STDIN_FILENO, TCSANOW, &raw_tc); + if (rc < 0) warnx("tcgetattr"); + } + switch (type) { case muxrpc_type_async: rc = muxrpc_read_async(&bs, STDOUT_FILENO, 1, no_newline); @@ -1149,10 +1163,15 @@ do_tcp_connect: } break; case muxrpc_type_duplex: - rc = muxrpc_duplex(&bs, STDIN_FILENO, STDOUT_FILENO, ptype, 1, no_newline); + rc = muxrpc_duplex(&bs, STDIN_FILENO, STDOUT_FILENO, ptype, 1, no_newline, raw); break; } + if (raw) { + rc = tcsetattr(STDIN_FILENO, TCSANOW, &orig_tc); + if (rc < 0) warnx("tcsetattr"); + } + bs_end(&bs); close(s); return rc;