#!/usr/bin/env bash # SPDX-License-Identifier: GPL-3.0-or-later # Copyright (c) 2025 LUXIM d.o.o., Slovenia # Author: Matjaž Mozetič # # Name: backtunnel-share-gui # Summary: KDE/GUI wrapper to start a BackTunnel share with dialogs and logging. # Description: # GUI front-end that prompts for remote, duration, ports, and invite options using kdialog, # then launches backtunnel-share in a terminal (Konsole/xterm) to create the reverse-SSH share. # Prefills fields from BackTunnel profiles.ini when available (read-only, best-effort). # All output is logged to /tmp/backtunnel-share-gui..log for troubleshooting. # # Usage: # backtunnel-share-gui # # Examples: # backtunnel-share-gui ~/projects # # Dependencies: # - bash # - kdialog (for GUI prompts) # - konsole or xterm (preferred terminals; falls back to background run if missing) # - awk (for simple INI parsing), tee # - backtunnel-share (invoked to perform the actual sharing) # # Exit codes: # 0 command launched (terminal or background) # 1 invalid usage or no folder selected # # Notes: # - Profiles are used only to prefill fields; @profile is not used directly by this GUI. # - If no terminal emulator is available, runs in background and shows a message with the log path. # GUI wrapper for BackTunnel "Share" action (Dolphin service menu) # Prompts for parameters via kdialog and launches backtunnel-share in a terminal. set -euo pipefail LOG="/tmp/backtunnel-share-gui.$UID.log" exec > >(tee -a "$LOG") 2>&1 export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PATH:-}" FOLDER="${1:-}" if [[ -z "$FOLDER" ]]; then kdialog --error "No folder selected." || true echo "No folder argument passed from service menu." >>"$LOG" exit 1 fi # Defaults REMOTE_DEFAULT="user@vps.example.com" DURATION_DEFAULT="2h" TPORT_DEFAULT="2222" LPORT_DEFAULT="22" INVITE_MOUNT_DEFAULT="$HOME/remote-rssh" # Profiles (search order: user -> system -> packaged fallback) PROFILES_USER="${XDG_CONFIG_HOME:-$HOME/.config}/backtunnel/profiles.ini" PROFILES_SYS="/etc/backtunnel/profiles.ini" PROFILES_PKG="/usr/share/backtunnel/profiles.ini" if [[ -f "$PROFILES_USER" ]]; then PROFILES_FILE="$PROFILES_USER" elif [[ -f "$PROFILES_SYS" ]]; then PROFILES_FILE="$PROFILES_SYS" else PROFILES_FILE="$PROFILES_PKG" fi # If profiles exist, offer a profile picker and prefill dialogs if [[ -f "$PROFILES_FILE" ]]; then mapfile -t profs < <(awk '/^\[/{gsub(/^\[|\]$/,"",$1); if ($1!="default") print $1}' "$PROFILES_FILE") if (( ${#profs[@]} )); then choice="$(kdialog --combobox "Choose profile (or Cancel for manual)" "${profs[@]}")" || choice="" if [[ -n "$choice" ]]; then getval() { awk -v s="[""$choice""]" -v k="$1" ' $0==s{ok=1; next} /^\[/{ok=0} ok && $0 ~ /^[[:alnum:]_.-]+[[:space:]]*=/ { line=$0; sub(/[[:space:]]*=[[:space:]]*/, "=", line) split(line,a,"="); if(a[1]==k){val=substr(line,index(line,"=")+1); gsub(/^[[:space:]]+|[[:space:]]+$/,"",val); print val; exit} }' "$PROFILES_FILE" 2>/dev/null; } u="$(getval user)"; h="$(getval host)" if [[ -n "$u" && -n "$h" ]]; then REMOTE_DEFAULT="$u@$h" fi v="$(getval tunnel_port)"; [[ -n "$v" ]] && TPORT_DEFAULT="$v" v="$(getval local_ssh_port)"; [[ -n "$v" ]] && LPORT_DEFAULT="$v" v="$(getval invite_mount)"; [[ -n "$v" ]] && INVITE_MOUNT_DEFAULT="$v" # optional: default duration from [default] vd="$(awk -v s="[default]" -v k="duration" ' $0==s{ok=1; next} /^\[/{ok=0} ok && $0 ~ /^[[:alnum:]_.-]+[[:space:]]*=/ { line=$0; sub(/[[:space:]]*=[[:space:]]*/, "=", line) split(line,a,"="); if(a[1]==k){val=substr(line,index(line,"=")+1); gsub(/^[[:space:]]+|[[:space:]]+$/,"",val); print val; exit} }' "$PROFILES_FILE" 2>/dev/null)" [[ -n "$vd" ]] && DURATION_DEFAULT="$vd" fi fi fi # Dialogs (Cancel returns 1; treat as benign exit) REMOTE="$(kdialog --inputbox "Remote (user@host or user:host):" "$REMOTE_DEFAULT")" || exit 0 DUR="$(kdialog --combobox "Share duration" 30m 2h 6h 1d 2d --editable "$DURATION_DEFAULT")" || exit 0 TPORT="$(kdialog --inputbox "Tunnel port on remote:" "$TPORT_DEFAULT")" || exit 0 LPORT="$(kdialog --inputbox "Local SSH port to expose:" "$LPORT_DEFAULT")" || exit 0 INV="" # set to "-i" if chosen if kdialog --yesno "Print invite line for chat?"; then INV="-i" fi QR="" # set to "--qr" if chosen if kdialog --yesno "Show QR code for the invite?"; then QR="--qr" fi MP="$(kdialog --inputbox "Suggested mount point in invite:" "$INVITE_MOUNT_DEFAULT")" || exit 0 # Build command safely as an array; append optional flags conditionally (SC2206-safe) cmd=( backtunnel-share "$FOLDER" with "$REMOTE" for "$DUR" -p "$TPORT" -l "$LPORT" --invite-mount "$MP" ) if [[ -n "$INV" ]]; then cmd+=("$INV"); fi if [[ -n "$QR" ]]; then cmd+=("$QR"); fi if command -v konsole >/dev/null 2>&1; then exec konsole --noclose -e "${cmd[@]}" elif command -v xterm >/dev/null 2>&1; then exec xterm -hold -e "${cmd[@]}" else nohup "${cmd[@]}" >>"$LOG" 2>&1 & kdialog --msgbox "Sharing started in background.\nSee log: $LOG" exit 0 fi