SSH_CLIPBOARD_DIR="${SSH_CLIPBOARD_DIR:-$HOME/.cache}" SSH_CLIPBOARD_COPY_SOCKET="${SSH_CLIPBOARD_COPY_SOCKET:-$SSH_CLIPBOARD_DIR/ssh-clipboard-copy.sock}" SSH_CLIPBOARD_PASTE_SOCKET="${SSH_CLIPBOARD_PASTE_SOCKET:-$SSH_CLIPBOARD_DIR/ssh-clipboard-paste.sock}" SSH_CLIPBOARD_PIDFILE="${SSH_CLIPBOARD_PIDFILE:-$SSH_CLIPBOARD_DIR/ssh-clipboard.pid}" SSH_CLIPBOARD_PASTE_PIDFILE="${SSH_CLIPBOARD_PASTE_PIDFILE:-$SSH_CLIPBOARD_DIR/ssh-clipboard-paste.pid}" SSH_CLIPBOARD_LOG="${SSH_CLIPBOARD_LOG:-$SSH_CLIPBOARD_DIR/ssh-clipboard.log}" # These paths are created on the remote host. SSH_CLIPBOARD_REMOTE_COPY_SOCKET="/tmp/ssh-clipboard-copy-client.sock" SSH_CLIPBOARD_REMOTE_PASTE_SOCKET="/tmp/ssh-clipboard-paste-client.sock" function clipboard_server_running { local pid if [ -n "${SSH_CLIPBOARD_REMOTE_COPY_SOCKET:-}" ] && [ -S "$SSH_CLIPBOARD_REMOTE_COPY_SOCKET" ]; then return 0 fi [[ -f "$SSH_CLIPBOARD_PIDFILE" ]] || return 1 read -r pid < "$SSH_CLIPBOARD_PIDFILE" [[ "$pid" =~ ^[0-9]+$ ]] || return 1 kill -0 "$pid" 2>/dev/null } function init_clipboard_server { if clipboard_server_running; then return 0 fi command -v socat >/dev/null 2>&1 || { echo "clipboard server: socat is not installed" >&2 return 1 } case "$OSTYPE" in darwin*) [[ -x /usr/bin/pbcopy ]] || { echo "clipboard server: /usr/bin/pbcopy was not found" >&2 return 1 } [[ -x /usr/bin/pbpaste ]] || { echo "clipboard server: /usr/bin/pbpaste was not found" >&2 return 1 } mkdir -p "$SSH_CLIPBOARD_DIR" chmod 700 "$SSH_CLIPBOARD_DIR" rm -f \ "$SSH_CLIPBOARD_COPY_SOCKET" \ "$SSH_CLIPBOARD_PASTE_SOCKET" \ "$SSH_CLIPBOARD_PIDFILE" \ "$SSH_CLIPBOARD_PASTE_PIDFILE" ( umask 077 # Remote -> local clipboard socat \ "UNIX-LISTEN:$SSH_CLIPBOARD_COPY_SOCKET,fork,mode=600" \ EXEC:/usr/bin/pbcopy \ >>"$SSH_CLIPBOARD_LOG" 2>&1 & echo "$!" > "$SSH_CLIPBOARD_PIDFILE" # Local clipboard -> remote socat \ "UNIX-LISTEN:$SSH_CLIPBOARD_PASTE_SOCKET,fork,mode=600" \ EXEC:/usr/bin/pbpaste \ >>"$SSH_CLIPBOARD_LOG" 2>&1 & echo "$!" > "$SSH_CLIPBOARD_PASTE_PIDFILE" ) ;; cygwin*) # Eventually: # copy -> cat > /dev/clipboard # paste -> cat /dev/clipboard echo "clipboard server: Cygwin support is not implemented" >&2 return 1 ;; *) echo "clipboard server: $OSTYPE is not supported" >&2 return 1 ;; esac } function stop_clipboard_server { local pid if [[ -f "$SSH_CLIPBOARD_PIDFILE" ]]; then read -r pid < "$SSH_CLIPBOARD_PIDFILE" [[ "$pid" =~ ^[0-9]+$ ]] && kill "$pid" 2>/dev/null || true fi if [[ -f "$SSH_CLIPBOARD_PASTE_PIDFILE" ]]; then read -r pid < "$SSH_CLIPBOARD_PASTE_PIDFILE" [[ "$pid" =~ ^[0-9]+$ ]] && kill "$pid" 2>/dev/null || true fi rm -f \ "$SSH_CLIPBOARD_COPY_SOCKET" \ "$SSH_CLIPBOARD_PASTE_SOCKET" \ "$SSH_CLIPBOARD_PIDFILE" \ "$SSH_CLIPBOARD_PASTE_PIDFILE" } function clipboard_server_config { cat </dev/null 2>&1 || { echo "pbcopy: socat is required for the remote clipboard" >&2 return 1 } socat - "UNIX-CONNECT:$SSH_CLIPBOARD_REMOTE_COPY_SOCKET" return $? fi case "$OSTYPE" in darwin*) if [ -x /usr/bin/pbcopy ]; then /usr/bin/pbcopy else echo "pbcopy: /usr/bin/pbcopy was not found" >&2 return 1 fi ;; cygwin*) cat > /dev/clipboard ;; *) echo "pbcopy: no remote clipboard socket is available" >&2 return 1 ;; esac } function pbpaste { if [ -n "${SSH_CLIPBOARD_REMOTE_PASTE_SOCKET:-}" ] && [ -S "$SSH_CLIPBOARD_REMOTE_PASTE_SOCKET" ]; then command -v socat >/dev/null 2>&1 || { echo "pbpaste: socat is required for the remote clipboard" >&2 return 1 } socat - "UNIX-CONNECT:$SSH_CLIPBOARD_REMOTE_PASTE_SOCKET" return $? fi case "$OSTYPE" in darwin*) if [ -x /usr/bin/pbpaste ]; then /usr/bin/pbpaste else echo "pbpaste: /usr/bin/pbpaste was not found" >&2 return 1 fi ;; cygwin*) cat /dev/clipboard ;; *) echo "pbpaste: no remote clipboard socket is available" >&2 return 1 ;; esac } function cleanup_ssh_clipboard { [ -n "${SSH_CONNECTION:-}" ] || return [ -S "$SSH_CLIPBOARD_REMOTE_COPY_SOCKET" ] && rm -f -- "$SSH_CLIPBOARD_REMOTE_COPY_SOCKET" [ -S "$SSH_CLIPBOARD_REMOTE_PASTE_SOCKET" ] && rm -f -- "$SSH_CLIPBOARD_REMOTE_PASTE_SOCKET" } if [ -z "${SSH_CONNECTION:-}" ] && init_clipboard_server; then alias ssh='sshc' fi if [ -n "${SSH_CONNECTION:-}" ]; then trap cleanup_ssh_clipboard EXIT HUP TERM fi