#!/bin/sh
# hamthings-node-websave — ponte ROOT per la pagina web HamThings sul Pi-Star (sudo www-data).
#   read  -> stato attuale in JSON (base dal live /etc/mmdvmhost; segreti mascherati).
#   save  -> valida lo staging, scrive il conf COMPLETO, delega ad apply (enforce delle
#            tecnologie ATTIVE) e gestisce le DISATTIVAZIONI (spegne le modalita' non nostre
#            + toglie le patch D-Star) restituendo il controllo a Pi-Star.
set -eu

CONF=/opt/hamthings-node/hamthings-node.conf
MM=/etc/mmdvmhost; YSFG=/etc/ysfgateway; DR=/etc/dstarrepeater
FN=/var/www/dashboard/mmdvmhost/functions.php
HOSTS=/root/YSFHosts.txt
STAGE=/tmp/hamthings-node.stage
APPLY=/opt/hamthings-node/hamthings-node-apply

cfg(){ sed -n "s/^[[:space:]]*$1[[:space:]]*=[[:space:]]*\([^#]*\).*/\1/p" "$CONF" 2>/dev/null | head -1 | sed 's/[[:space:]]*$//'; }
ini(){ awk -v s="[$2]" -v k="$3" 'BEGIN{FS="="} $0==s{inS=1;next} /^\[/&&$0!=s{inS=0} inS&&$1~"^[[:space:]]*"k"[[:space:]]*$"{sub(/^[^=]*=/,"");print;exit}' "$1" 2>/dev/null; }
jesc(){ printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'; }
active(){ systemctl is-active "$1" >/dev/null 2>&1 && echo true || echo false; }
set_ini(){ awk -v s="[$2]" -v k="$3" -v v="$4" '
    $0==s{inS=1;print;next} /^\[/&&$0!=s{ if(inS&&!d){print k"="v; d=1} inS=0 }
    inS&&$0~"^"k"="{print k"="v; d=1; next} {print} END{ if(inS&&!d) print k"="v }
  ' "$1" > "$1.hnw" && cat "$1.hnw" > "$1" && rm -f "$1.hnw"; }

# ---------- READ ----------
if [ "${1:-}" = "read" ]; then
  HOST=$(hostname 2>/dev/null)
  CALL=$(ini "$MM" General Callsign); DMRID=$(ini "$MM" General Id); DUP=$(ini "$MM" General Duplex)
  RXF=$(ini "$MM" Info RXFrequency); TXF=$(ini "$MM" Info TXFrequency)
  [ -n "$CALL" ] || CALL=$(cfg callsign)

  DS=$(cfg dstar); [ "$DS" = 1 ] && DSE=true || DSE=false
  MST=$(cfg master); PRT=$(cfg port); MOD=$(cfg module); [ -n "$PRT" ] || PRT=20010; [ -n "$MOD" ] || MOD=B
  PW=$(cfg password); case "$PW" in ''|INCOLLA-QUI|CHANGEME) HASPW=false;; *) HASPW=true;; esac
  # D-Star "connesso" = stato AUTH REALE scritto dall'agente (/run/hamthings-node.status), NON solo
  # "servizio attivo": l'agente resta attivo anche mentre ritenta con password errata (auth respinta),
  # e col vecchio check il pallino D-Star risultava verde a torto.
  DSC=false
  if [ "$(active hamthings-node)" = true ] && [ "$(cat /run/hamthings-node.status 2>/dev/null)" = connected ]; then DSC=true; fi

  YSS=$(ini "$YSFG" Network Startup); YT=$(ini "$YSFG" Network Options)
  case "$YSS" in HamThings-*) YM=${YSS##*-};; IT-YSF-HamThings) YM=2221;; *) YM="";; esac
  echo "$YM" | grep -qE '^[0-9]{3,6}$' || YM=""
  # "attivo" viene dal NOSTRO conf, come per il D-Star. Leggerlo da /etc/ysfgateway era sbagliato:
  # quel file NON viene toccato quando si disattiva (il vero interruttore e' [System Fusion] in
  # MMDVM.ini), quindi dopo il salvataggio l'interruttore in pagina tornava acceso pur avendo
  # spento la modalita'.
  YSCFG=$(cfg ysf); [ "$YSCFG" = 1 ] && YSFE=true || YSFE=false
  [ -n "$YT" ] && HASYT=true || HASYT=false
  YSFC=false
  if systemctl is-active ysfgateway >/dev/null 2>&1; then
    L=$(ls -t /var/log/pi-star/YSFGateway-*.log 2>/dev/null | head -1)
    # Case-insensitive: YSFGateway scrive il nome del reflector in MAIUSCOLO ("Linked to
    # HAMTHINGS-2221") mentre lo Startup e' "HamThings-2221". Col confronto esatto la spia
    # diceva "non connesso" anche a gateway collegato.
    [ -n "$L" ] && case "$(grep -aE 'Linked to|Unlinked' "$L" 2>/dev/null | tail -1 | tr 'A-Z' 'a-z')" in *"linked to hamthings-"*) YSFC=true;; esac
  fi

  # DMR: diretto verso un master HamThings? (Address del [DMR Network] risolve a un nostro id)
  DADDR=$(ini "$MM" "DMR Network" Address); DMEN=$(ini "$MM" DMR Enable)
  DMID=$(awk -F';' -v ip="$DADDR" '$4==ip{print $1; exit}' "$HOSTS" 2>/dev/null)
  [ "$DMEN" = 1 ] && [ -n "$DMID" ] && DMRE=true || DMRE=false
  [ -n "$(ini "$MM" "DMR Network" Password)" ] && HASDMPW=true || HASDMPW=false
  CC=$(ini "$MM" DMR ColorCode); ELC=$(ini "$MM" DMR EmbeddedLCOnly); DTA=$(ini "$MM" DMR DumpTAData)
  DMRC=false
  if [ "$DMRE" = true ] && systemctl is-active mmdvmhost >/dev/null 2>&1; then
    L=$(ls -t /var/log/pi-star/MMDVM-*.log 2>/dev/null | head -1)
    [ -n "$L" ] && case "$(grep -aE 'DMR, Logged into|DMR, Login to the master has failed|DMR, Closing|DMR, Connection to the master' "$L" 2>/dev/null | tail -1)" in *"Logged into"*) DMRC=true;; esac
  fi

  DMID_DS=$(awk -F';' -v ip="$MST" '$4==ip{print $1; exit}' "$HOSTS" 2>/dev/null)
  YIP=$(awk -F';' -v id="$YM" '$1==id{print $4; exit}' "$HOSTS" 2>/dev/null)
  printf '{"node":{"callsign":"%s","host":"%s","id":"%s","rxfreq":"%s","txfreq":"%s","duplex":"%s"},"dstar":{"enabled":%s,"connected":%s,"callsign":"%s","master":"%s","masterId":"%s","port":"%s","module":"%s","hasPassword":%s},"ysf":{"enabled":%s,"connected":%s,"master":"%s","ip":"%s","callsign":"%s","hasToken":%s},"dmr":{"enabled":%s,"connected":%s,"master":"%s","hasPassword":%s,"colorCode":"%s","embeddedLC":"%s","dumpTA":"%s"}}\n' \
    "$(jesc "$CALL")" "$(jesc "$HOST")" "$(jesc "$DMRID")" "$(jesc "$RXF")" "$(jesc "$TXF")" "$(jesc "$DUP")" \
    "$DSE" "$DSC" "$(jesc "$CALL")" "$(jesc "$MST")" "$(jesc "$DMID_DS")" "$(jesc "$PRT")" "$(jesc "$MOD")" "$HASPW" \
    "$YSFE" "$YSFC" "$(jesc "$YM")" "$(jesc "$YIP")" "$(jesc "$CALL")" "$HASYT" \
    "$DMRE" "$DMRC" "$(jesc "$DMID")" "$HASDMPW" "$(jesc "$CC")" "$(jesc "$ELC")" "$(jesc "$DTA")"
  exit 0
fi

# aggiorna ORA le host-list (DMR+YSF) dai master, senza aspettare il cron giornaliero
if [ "${1:-}" = "hosts" ]; then
  /opt/hamthings-node/hamthings-dmrhosts 2>&1
  exit 0
fi

if [ "${1:-}" != "save" ]; then echo "uso: hamthings-node-websave read|save|hosts" >&2; exit 2; fi

# ---------- SAVE ----------
[ -r "$STAGE" ] || { echo "ERR staging assente"; exit 1; }
get(){ b=$(sed -n "s/^$1=//p" "$STAGE" | head -1); [ -n "$b" ] && printf '%s' "$b" | base64 -d 2>/dev/null || true; }

CALL=$(get callsign); DMRID=$(get dmrid); RXF=$(get rxfreq); TXF=$(get txfreq); DUP=$(get duplex)
DS=$(get dstar); MST=$(get master); PRT=$(get port); PW=$(get password); MOD=$(get module)
YS=$(get ysf); YT=$(get ysf_token); YM=$(get ysf_master)
DMR=$(get dmr); DM=$(get dmr_master); DMPW=$(get dmr_password)
CC=$(get colorcode); ELC=$(get embedded_lc); DTA=$(get dump_ta)
[ -n "$PRT" ] || PRT=20010; [ -n "$MOD" ] || MOD=B; [ -n "$DUP" ] || DUP=0

err=""
[ -n "$CALL" ] && { echo "$CALL" | grep -qiE '^[A-Z0-9]{3,8}$' || err="$err callsign;"; }
[ -n "$DMRID" ] && { echo "$DMRID" | grep -qE '^[0-9]{5,9}$' || err="$err dmrid;"; }   # 5-9: base + eventuale ESSID (2 cifre)
[ -n "$CC" ]  && { echo "$CC"  | grep -qE '^([0-9]|1[0-5])$' || err="$err colorcode;"; }
[ -n "$ELC" ] && { echo "$ELC" | grep -qE '^[01]$' || err="$err embedded_lc;"; }
[ -n "$DTA" ] && { echo "$DTA" | grep -qE '^[01]$' || err="$err dump_ta;"; }
[ -n "$RXF" ] && { echo "$RXF" | grep -qE '^[0-9]{6,9}$' || err="$err rxfreq;"; }
[ -n "$TXF" ] && { echo "$TXF" | grep -qE '^[0-9]{6,9}$' || err="$err txfreq;"; }
echo "$DUP" | grep -qE '^[01]$' || err="$err duplex;"
if [ "$DS" = 1 ]; then
  echo "$CALL" | grep -qiE '^[A-Z0-9]{3,8}$' || err="$err callsign_dstar;"
  echo "$MST"  | grep -qE  '^[A-Za-z0-9.-]{3,64}$' || err="$err master;"
  echo "$PRT"  | grep -qE  '^[0-9]{2,5}$' || err="$err port;"
  echo "$MOD"  | grep -qiE '^[A-D]$' || err="$err module;"
  case "$PW" in ''|INCOLLA-QUI|CHANGEME) case "$(cfg password)" in ''|INCOLLA-QUI|CHANGEME) err="$err password_mancante;";; esac ;;
    *) printf '%s' "$PW" | grep -qE '^[[:print:]]{4,200}$' || err="$err password;";; esac
fi
if [ "$YS" = 1 ]; then
  echo "$YM" | grep -qE '^[0-9]{3,6}$' || err="$err ysf_master;"
  if [ -n "$YT" ]; then echo "$YT" | grep -qE '^[A-Za-z0-9_-]{4,64}$' || err="$err ysf_token;"
  else [ -n "$(ini "$YSFG" Network Options)" ] || err="$err ysf_token_mancante;"; fi
fi
if [ "$DMR" = 1 ]; then
  echo "$DM" | grep -qE '^[0-9]{3,6}$' || err="$err dmr_master;"
  case "$DMPW" in ''|INCOLLA-QUI|CHANGEME) [ -n "$(cfg dmr_password)" ] || [ -n "$(ini "$MM" "DMR Network" Password)" ] || err="$err dmr_password_mancante;";;
    *) printf '%s' "$DMPW" | grep -qE '^[[:print:]]{4,200}$' || err="$err dmr_password;";; esac
fi
[ -z "$err" ] || { echo "ERR validazione:$err"; exit 1; }

# segreti VUOTI = tieni gli esistenti (conf; per il DMR anche il live)
case "$PW" in ''|INCOLLA-QUI|CHANGEME) PW=$(cfg password);; esac
[ -n "$YT" ] || YT=$(cfg ysf_token)
case "$DMPW" in ''|INCOLLA-QUI|CHANGEME) DMPW=$(cfg dmr_password); [ -n "$DMPW" ] || DMPW=$(ini "$MM" "DMR Network" Password);; esac

RW=0; if ! touch "$CONF" 2>/dev/null; then mount -o remount,rw / 2>/dev/null && RW=1; fi

cat > "$CONF" <<EOF
# hamthings-node — scritto dalla pagina web ($(date -u '+%Y-%m-%dT%H:%M:%SZ'))
# --- base nodo ---
callsign = $CALL
dmrid    = $DMRID
rxfreq   = $RXF
txfreq   = $TXF
duplex   = $DUP
# --- D-Star ---
dstar    = ${DS:-0}
module   = $MOD
master   = $MST
port     = $PRT
password = $PW
# --- YSF ---
ysf        = ${YS:-0}
ysf_master = $YM
ysf_token  = $YT
# --- DMR ---
dmr          = ${DMR:-0}
dmr_master   = $DM
dmr_password = $DMPW
colorcode    = $CC
embedded_lc  = $ELC
dump_ta      = $DTA
verbose  = 0
EOF
chmod 600 "$CONF"

# DISATTIVAZIONI (al salvataggio): spegni le modalita' non attive e restituisci a Pi-Star.
# NB: apply NON tocca le modalita' spente al boot -> il sysop puo' gestirle dal cruscotto Pi-Star.
if [ -f "$MM" ]; then
  if [ "$DS" != 1 ]; then
    set_ini "$MM" "D-Star" "Enable" "0"; set_ini "$MM" "D-Star Network" "Enable" "0"
    [ -f "$FN" ] && sed -i 's/(isProcessRunning("ircddbgatewayd") || isProcessRunning("hamthings-node"))/isProcessRunning("ircddbgatewayd")/' "$FN" 2>/dev/null
    [ -f "$DR.ht-orig" ] && { cp -a "$DR.ht-orig" "$DR" 2>/dev/null; chmod 644 "$DR" 2>/dev/null; }
  fi
  if [ "$YS" != 1 ]; then
    set_ini "$MM" "System Fusion" "Enable" "0"; set_ini "$MM" "System Fusion Network" "Enable" "0"
    # Chiusura simmetrica dell'accensione (apply fa enable+restart di ysfgateway): senza questo il
    # gateway restava agganciato al NOSTRO reflector e il nodo risultava collegato sul master anche
    # a C4FM spento. Solo se punta a noi: il servizio e' di Pi-Star e qualcuno lo usa verso altre reti.
    case "$(ini "$YSFG" Network Startup)" in
      HamThings-*|IT-YSF-HamThings) systemctl disable --now ysfgateway >/dev/null 2>&1 || true ;;
    esac
  fi
  [ "$DMR" != 1 ] && { set_ini "$MM" "DMR" "Enable" "0"; set_ini "$MM" "DMR Network" "Enable" "0"; }
fi

# applica le tecnologie ATTIVE (+ base) e riavvia mmdvmhost
"$APPLY" >/dev/null 2>&1 || true

# agente d'identita' D-Star
if [ "$DS" = 1 ]; then systemctl enable hamthings-node >/dev/null 2>&1 || true; systemctl restart hamthings-node >/dev/null 2>&1 || true
else systemctl disable --now hamthings-node >/dev/null 2>&1 || true; fi

[ "$RW" = 1 ] && mount -o remount,ro / 2>/dev/null || true
rm -f "$STAGE" 2>/dev/null || true
echo "OK base;D-Star:$([ "$DS" = 1 ] && echo on || echo off);YSF:$([ "$YS" = 1 ] && echo on || echo off);DMR:$([ "$DMR" = 1 ] && echo on || echo off)"
exit 0
