#!/bin/bash
# Campaign 10 — blind console driver for VM 311 on demo-hp.
# snap <label>        : screendump the VM console -> PNG on DooPlex (for visual Read)
# key  <k> [k...]     : sendkey one or more keys (QEMU keynames), 0.25s apart
# type <string>       : type an ASCII string as sendkey events
set -uo pipefail
SCRATCH=/tmp/claude-1000/-mnt-5-hdd-felhom-eu-git/0d68ad3e-5c39-4852-8e38-9c029dff2562/scratchpad
VM=311
H=demo-hp

mon() { ssh -o ConnectTimeout=10 "$H" "LC_ALL=C qm monitor $VM" <<<"$1" 2>/dev/null | grep -v '^QEMU\|^(qemu)' ; }

snap() {
  local label="${1:-x}"
  ssh -o ConnectTimeout=10 "$H" "LC_ALL=C qm monitor $VM" <<<"screendump /tmp/c10.ppm" >/dev/null 2>&1
  scp -q "$H:/tmp/c10.ppm" "$SCRATCH/c10-$label.ppm" 2>/dev/null || { echo "snap: scp failed"; return 1; }
  convert "$SCRATCH/c10-$label.ppm" "$SCRATCH/c10-$label.png" 2>/dev/null || { echo "snap: convert failed"; return 1; }
  echo "$SCRATCH/c10-$label.png"
}

key() {
  local cmds=""
  for k in "$@"; do cmds+="sendkey $k
"; done
  ssh -o ConnectTimeout=10 "$H" "LC_ALL=C qm monitor $VM" <<<"$cmds" >/dev/null 2>&1
}

# type: map ASCII -> qemu keynames, including shifted chars
type_str() {
  local s="$1" cmds="" c
  local -A M=( [' ']='spc' ['-']='minus' ['.']='dot' ['/']='slash' ['=']='equal'
               [',']='comma' [';']='semicolon' ["'"]='apostrophe' ['\']='backslash'
               ['[']='bracket_left' [']']='bracket_right' ['`']='grave_accent' )
  local -A SH=( ['_']='minus' ['+']='equal' ['?']='slash' [':']='semicolon' ['"']='apostrophe'
                ['!']='1' ['@']='2' ['#']='3' ['$']='4' ['%']='5' ['^']='6' ['&']='7'
                ['*']='8' ['(']='9' [')']='0' ['{']='bracket_left' ['}']='bracket_right'
                ['|']='backslash' ['~']='grave_accent' ['<']='comma' ['>']='dot' )
  for (( i=0; i<${#s}; i++ )); do
    c="${s:$i:1}"
    if [[ -n "${SH[$c]:-}" ]]; then cmds+="sendkey shift-${SH[$c]}
"
    elif [[ -n "${M[$c]:-}" ]]; then cmds+="sendkey ${M[$c]}
"
    elif [[ "$c" =~ [A-Z] ]]; then cmds+="sendkey shift-$(tr '[:upper:]' '[:lower:]' <<<"$c")
"
    elif [[ "$c" =~ [a-z0-9] ]]; then cmds+="sendkey $c
"
    else echo "type_str: unmapped char '$c'" >&2; return 1
    fi
  done
  ssh -o ConnectTimeout=10 "$H" "LC_ALL=C qm monitor $VM" <<<"$cmds" >/dev/null 2>&1
}

case "${1:-}" in
  snap) shift; snap "$@" ;;
  key)  shift; key "$@" ;;
  type) shift; type_str "$@" ;;
  # typefile: read the string from a file so a secret never lands in argv/ps
  typefile) shift; type_str "$(cat "$1")" ;;
  mon)  shift; mon "$@" ;;
  *) echo "usage: vm.sh {snap <label>|key <k>...|type <str>|typefile <path>|mon <cmd>}"; exit 2 ;;
esac
