Thanks, comments inline.
> diff --git a/usr.bin/cu/command.c b/usr.bin/cu/command.c
> index c07fe73aeca..e225fb544be 100644
> --- a/usr.bin/cu/command.c
> +++ b/usr.bin/cu/command.c
> @@ -30,6 +30,7 @@
> #include <stdio.h>
> #include <string.h>
> #include <unistd.h>
> +#include <vis.h>
>
> #include "cu.h"
>
> @@ -223,6 +224,8 @@ start_record(void)
> void
> do_command(char c)
> {
> + char esc[4 + 1];
> +
> if (restricted && strchr("CRX$>", c) != NULL) {
> cu_warnx("~%c command is not allowed in restricted mode", c);
> return;
> @@ -266,20 +269,26 @@ do_command(char c)
> sleep(1);
> ioctl(line_fd, TIOCCBRK, NULL);
> break;
> - case '~':
> - bufferevent_write(line_ev, "~", 1);
> + default:
> + if (c != escape_char)
> + break;
> + esc[0] = escape_char;
> + esc[1] = '\0';
No need for \0 since you are only writing one byte, but...
> + bufferevent_write(line_ev, esc, 1);
...why not do this instead:
bufferevent_write(line_ev, &c, 1);
> break;
> case '?':
> + vis(esc, escape_char, VIS_WHITE | VIS_NOSLASH, 0);
> printf("\r\n"
> - "~# send break\r\n"
> - "~$ pipe local command to remote host\r\n"
> - "~> send file to remote host\r\n"
> - "~C connect program to remote host\r\n"
> - "~D de-assert DTR line briefly\r\n"
> - "~R start recording to file\r\n"
> - "~S set speed\r\n"
> - "~X send file with XMODEM\r\n"
> - "~? get this summary\r\n"
> + "%s# send break\r\n"
> + "%s$ pipe local command to remote host\r\n"
> + "%s> send file to remote host\r\n"
> + "%sC connect program to remote host\r\n"
> + "%sD de-assert DTR line briefly\r\n"
> + "%sR start recording to file\r\n"
> + "%sS set speed\r\n"
> + "%sX send file with XMODEM\r\n"
> + "%s? get this summary\r\n",
> + esc, esc, esc, esc, esc, esc, esc, esc, esc
> );
> break;
> }
> diff --git a/usr.bin/cu/cu.1 b/usr.bin/cu/cu.1
> index 104a6ea7893..d52e0b94e5f 100644
> --- a/usr.bin/cu/cu.1
> +++ b/usr.bin/cu/cu.1
> @@ -38,6 +38,7 @@
> .Op Fl dr
> .Op Fl l Ar line
> .Op Fl s Ar speed | Fl Ar speed
> +.Op Fl E Ar escape_char
E comes before l and s.
> .Nm
> .Op Ar host
> .Sh DESCRIPTION
> @@ -92,6 +93,8 @@ and
> .It Fl s Ar speed | Fl Ar speed
> Set the speed of the connection.
> The default is 9600.
> +.It Fl E Ar escape_char
> +Specify a escape character to use instead of the default tilde.
"an escape character".
> .El
> .Pp
> If
> diff --git a/usr.bin/cu/cu.c b/usr.bin/cu/cu.c
> index 03a2df4181f..f269f4a74f3 100644
> --- a/usr.bin/cu/cu.c
> +++ b/usr.bin/cu/cu.c
> @@ -41,6 +41,7 @@ FILE *record_file;
> struct termios saved_tio;
> struct bufferevent *input_ev;
> struct bufferevent *output_ev;
> +int escape_char = -1;
Why not just initialize it to '~'?
> int is_direct = -1;
> int restricted = 0;
> const char *line_path = NULL;
> @@ -53,7 +54,7 @@ struct event sighup_ev;
> enum {
> STATE_NONE,
> STATE_NEWLINE,
> - STATE_TILDE
> + STATE_ESCAPE
> } last_state = STATE_NEWLINE;
>
> __dead void usage(void);
> @@ -67,8 +68,8 @@ void try_remote(const char *, const char *,
> const char *);
> __dead void
> usage(void)
> {
> - fprintf(stderr, "usage: %s [-dr] [-l line] [-s speed | -speed]\n",
> - __progname);
> + fprintf(stderr, "usage: %s [-dr] [-l line] [-s speed | -speed]"
> + " [-E escape_char]\n", __progname);
-E comes before -l and -s.
> fprintf(stderr, " %s [host]\n", __progname);
> exit(1);
> }
> @@ -101,7 +102,7 @@ main(int argc, char **argv)
> errx(1, "speed asprintf");
> }
>
> - while ((opt = getopt(argc, argv, "drl:s:")) != -1) {
> + while ((opt = getopt(argc, argv, "drl:s:E:")) != -1) {
> switch (opt) {
> case 'd':
> is_direct = 1;
> @@ -119,6 +120,17 @@ main(int argc, char **argv)
> if (errstr != NULL)
> errx(1, "speed is %s: %s", errstr, optarg);
> break;
> + case 'E':
> + if (optarg[0] == '^' && optarg[2] == 0 &&
> + (unsigned char)optarg[1] >= 64 &&
> + (unsigned char)optarg[1] < 128)
> + escape_char = (unsigned char)optarg[1] & 31;
> + else if (strlen(optarg) == 1)
> + escape_char = (unsigned char)optarg[0];
> + else
I know you copied this from ssh, but please use u_char rather than
unsigned char like cu does elsewhere.
> + errx(1, "invalid escape character: %s",
> + optarg);
> + break;
> default:
> usage();
> }
> @@ -155,6 +167,8 @@ main(int argc, char **argv)
> line_speed = 9600;
> if (is_direct == -1)
> is_direct = 0;
> + if (escape_char == -1)
> + escape_char = '~';
>
> if (strchr(line_path, '/') == NULL) {
> if (asprintf(&tmp, "%s%s", _PATH_DEV, line_path) == -1)
> @@ -308,14 +322,14 @@ stream_read(struct bufferevent *bufev, void *data)
> last_state = STATE_NEWLINE;
> break;
> case STATE_NEWLINE:
> - if (state_change && *ptr == '~') {
> - last_state = STATE_TILDE;
> + if (state_change && *ptr == escape_char) {
> + last_state = STATE_ESCAPE;
> continue;
> }
> if (*ptr != '\r')
> last_state = STATE_NONE;
> break;
> - case STATE_TILDE:
> + case STATE_ESCAPE:
> do_command(*ptr);
> last_state = STATE_NEWLINE;
> continue;
> diff --git a/usr.bin/cu/cu.h b/usr.bin/cu/cu.h
> index 2a7ca45d414..abcedc6d77a 100644
> --- a/usr.bin/cu/cu.h
> +++ b/usr.bin/cu/cu.h
> @@ -23,6 +23,7 @@
> void do_command(char);
>
> /* cu.c */
> +extern int escape_char;
> extern int restricted;
> extern FILE *record_file;
> extern struct termios saved_tio;
>