#!/bin/bash set -e set -f set -o pipefail shopt -s lastpipe PROGNAME=${0##*/} BOT_SIZE=8 BOT_TITLE=input BOT_CMD=sendstream if [ $# = 0 ] then TOP_CMD="$SHELL -i" else TOP_CMD=$* fi TOP_TITLE=$TOP_CMD TWOPANE=$(mktemp -d) export TWOPANE TOP_CMD BOT_CMD TOP_TITLE BOT_TITLE BOT_SIZE trap 'rm -r "$TWOPANE"' EXIT STY=twopane.${TWOPANE##*/} save_file() { cat > "$TWOPANE"/"${1:?$PROGNAME: Error: filename cannot be empty string}" } save_screenrc() { save_file screenrc"${1:+.$1}" } save_screenrc <<'.' # Disable keybindings. unbindall escape \0\0 # Disable messages. This is needed for screen -X/-Q to work reasonably. msgwait 0 msgminwait 0 caption string '%t' layout new split focus bottom resize $BOT_SIZE screen -ln -t "$BOT_TITLE" 0 bash --noprofile --rcfile "$TWOPANE"/bashrc -i source "$TWOPANE"/screenrc.startpane layout save 0 . save_screenrc 'startpane' <<. focus top screen -ln -t "\$TOP_TITLE" 1 $TOP_CMD exec .!. sh -c 'socat UNIX-LISTEN:"\$TWOPANE"/socket STDIN,rawer!!STDOUT' title 'output' focus top . restart() { while screen -p1 -Q info >/dev/null do screen -p1 -X kill done screen -X source "$TWOPANE"/screenrc.startpane } sendstream() { socat_stty_opts=( rawer echo=0 intr=0 quit=0 eof=0 start=0 stop=0 susp=0 lnext=0 opost=1 onlcr=1 onlret=1 ) stty=$(printf %s, "${socat_stty_opts[@]}") trap ': SIGUSR1; restart' USR1 exec 100<&0 101>&1 while true do coproc SOCAT \ { socat STDIN!!STDOUT UNIX-CONNECT:"$TWOPANE"/socket,forever kill -USR1 $$ } exec 200<&${SOCAT[0]} 201>&${SOCAT[1]} socat FD:100,${stty%,}!!STDOUT STDIN!!STDOUT <&200 | input_filter | tee >(output_filter | soft_cursor >&101) >&201 reset -I -Q -w exec 200<&- 201>&- wait -f "$SOCAT_PID" 2>/dev/null done } input_filter() { while read -N1 do case "$REPLY" in a ) echo -n "${REPLY@U}" ;; A ) echo -n "${REPLY@L}" ;; * ) echo -n "$REPLY" ;; esac done } output_filter() { cat -vt } soft_cursor() { printf $'\033[43m \b' while read -N1 do printf '%s' \ $'\033[00m \b' \ "$REPLY" \ $'\033[43m \b' done } save_file bashrc <<. set -f set -b set -o pipefail shopt -s lastpipe trap "screen -X quit" EXIT $(declare -f) export PS1="\$BOT_TITLE\$ " if [ "\$SHOW_SOCAT_ERRORS" ] then exec 20>&2 else exec 20>/dev/null fi \$BOT_CMD . main() { screen -c "$TWOPANE"/screenrc -m -S "$STY" -ln } main "$@"