#!/system/bin/sh
#
# Magisk init script service.sh for the Magisk Module to enable adb via WiFi using a fixed TCP port
#
#h# Usage:
#h#
#h#    service.sh  [ --reset_port | --reset-port | -r ]
#h#
#h# Parameter:
#h#
#h#   --reset_port - disable and enable adb via WiFi 
#h#
#
# This script enables adb via WiFi using the script enable_wireless_adb.sh and starts socat to forward connections to a fixed TCP port to the port
# used by adb via WiFI. After the start of socat, service.sh keeps running in the background to restart the socat binary if necessary (e.g. because the WiFi connection failed).
#
# To temporary disable the restart of socat, create the file 
#
#     /data/local/tmp/enable_wireless_adb/do_not_restart_socat
#
# To reenable the restart of socat, delete this file. If socat is not running, the script service.sh checks every n seconds wether this file exists.
# The default value for n is 4; to use a different value, write it it to the semaphore file, e.g. to wait 60 seconds between the checks use
#
#    echo 60 >/data/local/tmp/enable_wireless_adb/do_not_restart_socat
#
# 
# To disable the script complete, create the file
#
#    /data/local/tmp/enable_wireless_adb/do_not_start_socat
#
# If this file exists, the script service.sh is terminated immediately. To restart the script, the phone must be restarted.
#
#
# The script to enable adb via WiFi, enable_wireless_adb.sh, does not add the WLAN BSSID to the adbd keystore. This must be done manually once for each WLAN in the confirmation dialog in the Android GUI.
# To enable adding the WLAN BSSID to the adbd keystore in the script, create the file
#
#   /data/local/tmp/enable_wireless_adb/add_wlan_bssid
#
# and either disable and enable adb via WiFi in the GUI manual or just reboot the phone.
#
# The default fixed port for the adb WiFi connections is 9999. To use another port either set the environment variable SOCAT_PORT before executing this script or store the port to use in the 
# file /data/local/tmp/enable_wireless_adb/adb_wifi_port
#
#
# History
#   03.05.2025 /bs
#     initial release
#     
#


# -----------------------------------------------------------------------------

# -----------------------------------------------------------------------------
# define constants
#
__TRUE=0
__FALSE=1

# -----------------------------------------------------------------------------
#
# the environment variable MODPATH is only defined by Magisk for the script customize.sh
#
[ "${MODPATH}"x = ""x ] && MODPATH="${0%/*}"

MODULE_NAME="$( grep "^id=" ${MODPATH}/module.prop  | cut -f2 -d "=" )"
[ "${MODULE_NAME}"x = ""x ] && MODULE_NAME="unknown_magisk_module"


SCRIPT_NAME="${0##*/}"

SCRIPT_DIR="${0%/*}"

SOCAT="${SCRIPT_DIR}/system/bin/socat"

DEFAULT_SOCAT_PORT="9999"

SOCAT_OPTIONS=""

ENABLE_WIRELESS_ADB_SCRIPT="${SCRIPT_DIR}/system/bin/enable_wireless_adb.sh"

DATA_DIR="/data/local/tmp/enable_wireless_adb"

SOCAT_PORT_FILE="${DATA_DIR}/adb_wifi_port"

DEFAULT_SLEEP_INTERVALL=4

DISABLE_SOCAT_AUTOSTART_SEMFILE="${DATA_DIR}/do_not_start_socat"

DISABLE_SOCAT_RESTART_SEMFILE="${DATA_DIR}/do_not_restart_socat"

ADD_WLAN_BSSID_SEMAPHOR_FILE="${DATA_DIR}/add_wlan_bssid"

# -----------------------------------------------------------------------------
# change either "0 = 1" to "0 = 0" in this script or create the file /data/local/tmp/debug to enable the debug output to the log file
#
if [ 0 = 1 -o -r /data/local/tmp/debug ] ; then
  LOGFILE="${DATA_DIR}/${MODULE_NAME}_${SCRIPT_NAME}.log"

#  echo "Writing all messages to the log file ${LOGFILE}"

  exec 1>"${LOGFILE}" 2>&1

  if [ -r /data/local/tmp/trace ] ; then
    set -x
  fi
fi

# -----------------------------------------------------------------------------

function LogMsg {
  echo "$*"
}

function LogInfo {
  LogMsg "INFO: $*"
}

function LogWarning {
  LogMsg "WARNING: $*"
}

function LogError {
  LogMsg "ERROR: $*"
}

# ----------------------------------------------------------------------
# die
#
# function: print a message and end the script
#
# usage: die [script_exit_code] [message]
#
# the parameter "message" is optional; the script will add a leading "ERROR: "
# to the message if the script_exit_code is not zero
#
# returns: n/a
#
function die  {
  THISRC=$1
  [ $# -ne 0 ] && shift
  THISMSG="$*"

  if [ "${THISMSG}"x != ""x ] ; then
    if [ ${THISRC} != 0 ] ; then
      LogError "${THISMSG} (RC=${THISRC})" >&2
    else
      LogMsg "${THISMSG}"
    fi
  fi

  exit ${THISRC}
}

# ----------------------------------------------------------------------
# isNumber
#
# check if a value is an integer
#
# usage: isNumber testValue
#
# returns: ${__TRUE} - testValue is a number else not
#
function isNumber {

# this code does not work in the sh in Android
#  [[ $1 == +([0-9]) ]] && THISRC=${__TRUE} || THISRC=${__FALSE}

# old code:
  if [ "$1"x != ""x ] ; then
    TESTVAR="$(echo "$1" | sed 's/[0-9]*//g' )"
    [ "${TESTVAR}"x = ""x ] && return ${__TRUE} || return ${__FALSE}
  fi
  
  return ${__FALSE}
}


# ---------------------------------------------------------------------


# ---------------------------------------------------------------------
#

PRINT_USAGE=${__FALSE}

# reset the port used by adb ?
#
RESET_ADB_VIA_WIFI=${__FALSE}

while [ $# -ne 0 ] ; do

  CUR_PARAMETER="$1"
  shift
  
  case ${CUR_PARAMETER} in

    --help | -h )
      PRINT_USAGE=${__TRUE}
      ;;

    --verbose | -v )
      VERBOSE=${__TRUE}
      ;;

    --reset_port | --reset-port | -r )
      RESET_ADB_VIA_WIFI=${__TRUE}
      ;;

    * )
      LogMsg "ERROR: Invalid parameter found: ${CUR_PARAMETER}"
      exit 10
      ;;
  esac
done  

if [ ${PRINT_USAGE} = ${__TRUE} ] ; then

  grep "^#h#" $0 | cut -c4-
  
  if [ ${VERBOSE} = ${__TRUE} ] ; then
    grep "^#H#" $0 | cut -c4-
  fi
  
  exit 0

fi

# ---------------------------------------------------------------------
#
# check if root access is working
#
ROOT_ACCESS_OKAY=${__TRUE}

# the user running this script
#
CUR_USER="$( id -un )"

SU_PREFIX=""

if [ "${CUR_USER}" != "root"x ] ; then
  LogMsg "Running as non-root user"
  CUR_OUTPUT="$( su - -c "id -un" 2>/dev/null )"
  if [ "${CUR_OUTPUT}"x != "root"x ] ; then
    ROOT_ACCESS_OKAY=${__FALSE}
  else
    SU_PREFIX="su - -c "      
  fi
fi

# -----------------------------------------------------------------------------
# get the fixed TCP port to be used for the adb WiFi connections
#
if [ "${SOCAT_PORT}"x = ""x ] ; then
  if [ -r "${SOCAT_PORT_FILE}" ] ; then
    LogMsg "Reading the port for the adb WiFi connections from the file \"${SOCAT_PORT_FILE}\" ..."
    SOCAT_PORT="$( grep -E -v "^#|^$" "${SOCAT_PORT_FILE}" | tail -1 | tr "\t" " " | cut -f1 -d " "  )"
    isNumber "${SOCAT_PORT}"
    if [ $? -eq ${__TRUE} ] ;then
      LogMsg "The port for the adb WiFi connections is now \"${SOCAT_PORT}\" "
    else
      LogMsg "ERROR: \"${SOCAT_PORT}\" is NOT a valid port number"
      SOCAT_PORT=""
    fi
  fi
fi

if [ "${SOCAT_PORT}"x = ""x ] ; then
  LogMsg "Using the default port \"${DEFAULT_SOCAT_PORT}\" for the adb WiFi connections"
  SOCAT_PORT="${DEFAULT_SOCAT_PORT}"
fi

# -----------------------------------------------------------------------------

if [ ! -x "${ENABLE_WIRELESS_ADB_SCRIPT}" ] ; then
  die 100 "The script \"${ENABLE_WIRELESS_ADB_SCRIPT}\" does not exist or is not executable"
fi


if [ ! -x "${SOCAT}" ] ; then
  die 105 "The binary \"${SOCAT}\" does not exist or is not executable"
fi

# -----------------------------------------------------------------------------

export ENABLE_WIRELESS_ADB_LOGFILE="${DATA_DIR}/enable_wireless_adb.log"


while true ; do

  LogMsg ""
  LogMsg " ---------------------------------------------------------------------------- "
  LogMsg ""

  if [ -r "${DISABLE_SOCAT_AUTOSTART_SEMFILE}" ] ; then
    die 0 "The socat autostart is disabled"
  fi

  if [ -r "${DISABLE_SOCAT_RESTART_SEMFILE}" ] ; then
    LogMsg "The restart of socat is disabled"
    SLEEP_INTERVALL="$( grep -E -v "^#|^$" "${DISABLE_SOCAT_RESTART_SEMFILE}" | tail -1 | tr "\t" " " | cut -f1 -d " " )"
    if ! isNumber ${SLEEP_INTERVALL} ; then
      SLEEP_INTERVALL=${DEFAULT_SLEEP_INTERVALL}
    fi
    LogMsg "Sleeping for ${SLEEP_INTERVALL} seconds now ..."
    sleep ${SLEEP_INTERVALL}
  else


#
# check if we already know the port used for adb via WiFi
#

    ADB_VIA_WIFI_ALREADY_ENABLED=${__FALSE}

    LogMsg "Checking for an existing adb via WiFi configuration ..."
    ADB_WLAN_PORT="$( ${ENABLE_WIRELESS_ADB_SCRIPT} --print_port )"
    if [ "${ADB_WLAN_PORT}"x != ""x ] ; then
      netstat -tnlp 2>/dev/null | tr "\t" " " | grep ":${ADB_WLAN_PORT} " 
      if [ $? -eq 0 ] ; then
        LogMsg "Found a configured adb via WiFi configuration."
        if [ ${RESET_ADB_VIA_WIFI} != ${__TRUE} ] ; then
          ADB_VIA_WIFI_ALREADY_ENABLED=${__TRUE}
          LogMsg "Using the already configured port for adb via WiFi "
        fi
      fi
    fi
    
#
# enable adb via wireless
#
    if [ ${ADB_VIA_WIFI_ALREADY_ENABLED} != ${__TRUE} ] ; then

      SCRIPT_PARAMETER="--nostatus"

      if [ ${RESET_ADB_VIA_WIFI} = ${__TRUE} ] ; then
        LogMsg "Resetting the port used for adb via WiFi requested via parameter"
        SCRIPT_PARAMETER="${SCRIPT_PARAMETER} --reset_port"
      fi
      
      [ ! -r "${ADD_WLAN_BSSID_SEMAPHOR_FILE}" ] && SCRIPT_PARAMETER="${SCRIPT_PARAMETER} --ignore_BSSID"
    
      ${ENABLE_WIRELESS_ADB_SCRIPT} ${SCRIPT_PARAMETER}
    
#        
# read the port used for adb via wireless
#
      LogMsg "Retrieving the port used for adb via WiFi ...."

      ADB_WLAN_PORT="$( ${ENABLE_WIRELESS_ADB_SCRIPT} --print_port )"
    fi
    
    if   [ "${ADB_WLAN_PORT}"x = ""x ] ; then
      LogError "Can not get the port used for adb via wireless"
    else
      LogMsg "The port used for adb via WiFi is \"${ADB_WLAN_PORT}\" "

      LogMsg "Starting socat at $( date ) ...."
      START_SOCAT_CMD="${SOCAT} ${SOCAT_OPTIONS} TCP-LISTEN:${SOCAT_PORT},reuseaddr TCP:127.0.0.1:${ADB_WLAN_PORT},retry=0"
      set -x
      ${START_SOCAT_CMD}
      THISRC=$?
      set +x
      LogMsg "socat ended with RC=${THISRC}"
    fi
  fi
done

exit 0

