#!/bin/bash
#
# Lazy boring
# Ubuntu-MM
# Idea from Xaomi
# Ko Ko Ye <kokoye2007@gmail.com>
# Ubuntu Myanmar LoCo Team
# https://github.com/kokoye2007/wifi-qr

WIFIS=''
SSID=''
KEEY=''
PSK=''
QSSID=''
QKEES=''
QSSIDO=''

RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
BLUE=$(tput setaf 4)
RESET=$(tput sgr0)
BOLD=$(tput bold)
VERSION=0.3

#RAW DATA SAMPLE
#"WIFI:S:$SSID;P:$PASSWORD;T:$KEY_TYPE;H:$true;"
#qrencode -o - -t UTF8
#qrencode -l h -s 14 -o

#GUI Mainmenu
main_menu() {

  CHOICE=$(zenity --list \
    --title="WiFi and QR Code" \
    --text="Choose:" \
    --radiolist \
    --width=300 --height=320 \
    --column="Check" --column="Option" \
    TRUE "Scan and connect" \
    FALSE "Scan Image and connect" \
    FALSE "Share current WiFi" \
    FALSE "Share saved WiFi" \
    FALSE "See license" \
    FALSE "See version")

  #Menu Select
  if [[ "$CHOICE" =~ "Share saved WiFi" ]]; then
    call_wifi_gui

  elif [[ "$CHOICE" =~ "Share current WiFi" ]]; then
    call_current_wifi_gui

  elif [[ "$CHOICE" =~ "Scan and connect" ]]; then
    call_wifi_scan_gui "cam"

  elif [[ "$CHOICE" =~ "Scan Image and connect" ]]; then
    call_file_select_and_scan_gui

  elif [[ "$CHOICE" =~ "See license" ]]; then
    zenity --text-info --title="WiFi QR Copyright" --filename=/usr/share/doc/wifi-qr/copyright --width=528 --height=780
    main_menu

  elif [[ "$CHOICE" =~ "See version" ]]; then
    zenity --info --icon-name=wifi-qr --title="WiFi QR Version" --no-wrap --text=" This is wifi-qr version $VERSION"
    main_menu
  else
	exit 0
  fi
}


#GUI
call_wifi_gui() {
mapfile -t wifilist < <(nmcli  -g NAME,TYPE connection | grep 802-11-wireless | sed 's/:802-11-wireless//' |  sed 's/\\\([\\;,:"\]\)/\1/g' )

  WIFIS=$(zenity --list --column="SSID" \
	  --width=300 --height=600 \
	  --title="Select SSID" \
	  "${wifilist[@]}")

  if [ -z "$WIFIS" ]; then
    exit 0
  else
    call_qr_gui
  fi
}

call_qr_gui() {
  call_wifi_pass
  QR_FILE_NAME="wifi-qr-$(echo "$WIFIS" | tr -dc '[:alnum:]').png"
  SAVE_QR_DIR="${HOME}/Pictures/"
  QR_PNG="$(zenity --file-selection --save --confirm-overwrite --filename="$SAVE_QR_DIR"/"$QR_FILE_NAME")"
  if [[ -z "$QR_PNG" ]]; then
	  main_menu
  else
    qrencode -l h -s 14 -o "$QR_PNG" "WIFI:S:$SSID;P:$KEEY;$PSSK;$H;"

    xdg-open "$QR_PNG"
  fi
}

call_current_wifi_gui() {
  current_wifi_ssid
  call_qr_gui
}

#WiFi Command from terminal
call_wifi_terminal() {
mapfile -t wifilist < <(nmcli  -g NAME,TYPE connection | grep 802-11-wireless | sed 's/:802-11-wireless//' )
  OLD_IFS=$IFS
  IFS=$'\n'
  for l in "${wifilist[@]}"; do
    array[$i]=$l
    i=$((i + 1))
  done

  i=0
  for m in "${array[@]}"; do
    echo
    echo "$((i++))) $(basename "$m")"
  done
  IFS=$OLD_IFS
  echo ""
  echo -e "${BLUE}===============================================================${RESET}"
  echo -e "${BOLD}${WHITE}please choose WiFi ssid ${RESET}"
  echo -e "${BLUE}===============================================================${RESET}"
  read -e -r wifissid
  WIFIS="${array[$wifissid]}"
  echo -e "${BLUE}===============================================================${RESET}"
  echo -e "\nYou choose SSID File is: $WIFIS\n ${RESET}"
  echo -e "${BLUE}===============================================================${RESET}"
  terminal_qr
}

#WiFi Command from terminal with FZF
call_wifi_terminal_fzf() {
mapfile -t wifilist < <(nmcli  -g NAME,TYPE connection | grep 802-11-wireless | sed 's/:802-11-wireless//' | sed 's/\\\([\\;,:"\]\)/\1/g' )
  OLD_IFS=$IFS
  IFS=$'\n'
  for l in "${wifilist[@]}"; do
    array[$i]=$l
    i=$((i + 1))
  done
  IFS=$OLD_IFS

  wifissid=$(printf '%s\n' "${array[@]}" | fzf)

  WIFIS="$wifissid"

  echo -e "${BLUE}===============================================================${RESET}"
  echo -e "\nYou choose SSID File is: $WIFIS\n ${RESET}"
  echo -e "${BLUE}===============================================================${RESET}"
  terminal_qr
}


terminal_qr() {
  call_wifi_pass
  qrencode -o - -t UTF8 "WIFI:S:$SSID;P:$KEEY;$PSSK;$H;"
  echo
}

current_wifi_ssid() {
  WIFIS="$(nmcli -t -f active,ssid dev wifi | grep -E '^yes' | cut -d':' -f2- | tr -d '\r\n')"
  echo -e "${BLUE}===============================================================${RESET}"
  echo -e "\nYou current active SSID is:${BOLD}${RED} $WIFIS\n ${RESET}"
  echo -e "${BLUE}===============================================================${RESET}"
}


#Data Extractor nmcli version
call_wifi_pass() {
  WIFIS=$(echo "${WIFIS}" | sed 's/\\\([\\;,:"\]\)/\1/g' )
  SSID=$(nmcli -g 802-11-wireless.ssid connection show "${WIFIS}" | sed 's/[;,"]/\\&/g' )
  KEEY=$(nmcli -g 802-11-wireless-security.psk  -s connection show "${WIFIS}" | sed 's/[;,"]/\\&/g')
  PSK=$(nmcli -g 802-11-wireless-security.key-mgmt  connection show "${WIFIS}" )
  HIDN=$(nmcli -g 802-11-wireless.hidden connection show "${WIFIS}")

  if [[ "$PSK" == *"wpa"* ]]; then
    PSSK="T:WPA;"
  elif
    [[ "$PSK" == "wep" ]]
  then
    PSSK="T:WEP;"
  else
   PSSK=""
  fi
  if [[ "$HIDN" == *"yes"* ]]; then
      H="H:true;"
  fi
  echo -e "${GREEN}"
  echo ""
  # echo "SSID:    $SSID"
  echo "SSID:    $SSID" | sed 's/\\\([\\;,:"\]\)/\1/g'
  # echo "PASS:    $KEEY"
  echo "PASS:    $KEEY" | sed 's/\\\([\\;,:"\]\)/\1/g'
  echo "TYPE:    $PSSK"
  echo "HIDE:    $H"
  echo ""
  echo -e "${RESET}"
}

call_zbar_cam_scan() {
  qr_data=$1
  zbarcam --raw --prescale=320x240 /dev/video0 >"$qr_data" &

  # Last job running in background eg. zbarcam
  pid=$!
  # Sleep loop until $qr_data file has content
  local i=0
  local chars="/-\|"
  echo -en "  Scanning QR Code" "\r"
  while [[ ! -s $qr_data ]]; do
    sleep 0.5
    pgrep -x zbarcam >/dev/null && echo -en "${chars:$i:1}" "\r" || exit 0
    i=$(((i+1)%${#chars}))
    # cleanup - add a trap that will remove $qr_data and kill zbarcam
    # if any of the signals - SIGHUP SIGINT SIGTERM it received.
    trap 'rm -f "$qr_data" ; kill -s 9 "$pid"; exit' SIGHUP SIGINT SIGTERM
  done

  kill -s 9 $pid
  # to supress the kill message
  # https://stackoverflow.com/a/5722874/11910267
  wait $pid 2>/dev/null
}

call_zbar_img_scan() {
  qr_data=$1
  img_path=$2
  zbarimg --raw "$img_path" >"$qr_data" 2>/dev/null
}

call_wifi_scan() {
  mode=$1
  wifiqrdata=''
  # tmp data-matrix holder
  cwd="/tmp/"
  qr_data="$cwd/wifi-qr-scan"

  if [[ $mode == "cam" ]]; then
    call_zbar_cam_scan "$qr_data"
  else
    call_zbar_img_scan "$qr_data" "$mode" # mode stores the image path
  fi

  wifiqrdata=$(cat $qr_data)
  rm -f $qr_data

  # Check if the QR contains WiFi data or not
  if echo "$wifiqrdata" | grep --quiet ^WIFI; then
    ## Go Go GUI and CLI Mod
    # ssid & key are not always in the same sequence - fix by using a dict and cut identifier for first key
    if echo "$wifiqrdata" | grep --quiet "H:true;"; then
    	QHIDE=true
    fi

	WIFIQRDATA="${wifiqrdata}"

	# Extract the SSID
	QSSID=$(echo "$WIFIQRDATA" | sed -n 's/.*S:\([^;]*\)\(;[PHT]\).*$/\1/p' |  sed 's/\\\([\\;,:"\]\)/\1/g' )

	# Extract the security type
	QTYPE=$(echo "$WIFIQRDATA" | sed -n 's/.*T:\([^;]*\)\(;[PHS]\).*$/\1/p' |  sed 's/\\\([\\;,:"\]\)/\1/g' )

	# Extract the password
	if [[ $WIFIQRDATA == *';H:'* ]]; then
	  QKEES=$(echo "$WIFIQRDATA" | sed -n 's/.*P:\([^;]*\)\(;[TSH]\).*$/\1/p' |  sed 's/\\\([\\;,:"\]\)/\1/g' )
	else
	  QKEES=$(echo "$WIFIQRDATA" | sed -n 's/.*P:\([^;]*\)\(;[TS]\).*$/\1/p' |  sed 's/\\\([\\;,:"\]\)/\1/g' )
	fi

	# Check if the Wi-Fi network is hidden
	if [[ $WIFIQRDATA == *';H:true'* ]]; then
	  QHIDE="true"
	else
	  QHIDE="false"
	fi


	# Print the SSID, security type, password, and hidden attribute
      echo -e "${GREEN}============================${RESET}"
      echo -e "${BOLD}${BLUE} SSID: ${RESET} ${WHITE} $QSSID ${RESET}"
      echo -e "${BOLD}${BLUE} TYPE: ${RESET} ${WHITE} $QTYPE ${RESET}"
      echo -e "${BOLD}${BLUE} PASS: ${RESET} ${WHITE} $QKEES ${RESET}"
      echo -e "${BOLD}${BLUE} HIDE: ${RESET} ${WHITE} $QHIDE ${RESET}"
      echo -e "${GREEN}============================${RESET}"


    if [[ "$QHIDE" == "true" ]]; then
      echo -e "${GREEN}============================${RESET}"
      echo -e "${BOLD}${WHITE}It's is HIDDEN ${RESET}"
      echo -e "${GREEN}============================${RESET}"

    elif nmcli device wifi list | grep -w "$QSSID"; then
      echo -e "${GREEN}============================${RESET}"
      echo -e "${BOLD}${WHITE}$QSSID is Online ${RESET}"
      echo -e "${GREEN}============================${RESET}"
      QSSIDO=ON

    else
      echo -e "${RED}============================${RESET}"
      echo -e "${BOLD}${WHITE}Can't find $QSSID ${RESET}"
      echo -e "${RED}============================${RESET}"
      QSSIDO=OFF
    fi

  else
    echo -e "${RED}============================${RESET}"
    echo -e "${BOLD}${WHITE}It's not WiFi QR ${RESET}"
    echo -e "${RED}============================${RESET}"
    echo -e "${BLUE}============================${RESET}"
    echo -e "${BOLD}${BLUE} $wifiqrdata ${RESET}"
    echo -e "${BLUE}============================${RESET}"
    QSSIDO=NOWIFI
  fi

# key-mgmt type convert

  if [[ -z "$QTYPE" ]] ; then
    NTYPE="none"
  elif [[ "$QTYPE" == "WEP" ]] ; then
    NTYPE="ieee8021x"
  elif [[ "$QTYPE" == "WPA" ]] ; then
    NTYPE="wpa-psk"
  else
    echo "unknow or need to add key-mgmt type"
  fi

}


call_wifi_scan_terminal() {
  call_wifi_scan "$1"
     if [[ "$QSSIDO" == "NOWIFI" ]]; then
	exit 0
     elif [[ "$QHIDE" == "true" ]]; then
	scan_connect_hidden
     elif [[ "$QSSIDO" == "ON" ]]; then
	scan_connect
     else
	echo "Can't find Network and Can't Connect"
	exit 0
     fi
}

call_wifi_scan_gui() {
  call_wifi_scan "$1"
  # Function with QR data
  if [[ "$QSSIDO" =~ "ON" ]]; then
    zenity --question --title="Connect to WiFi" --text="Connect to '$QSSID'?" --width=200 --height=120 --icon-name=network-wireless 2>/dev/null
    connectn=$?
    if [ $connectn == 0 ]; then \
      scan_connect
    else
      exit
    fi
  elif [[ "$QSSIDO" =~ "OFF" ]]; then
    CHOICE=$(zenity --list \
      --title="Can't find WiFi" \
      --text="Choose:" \
      --radiolist \
      --width=400 --height=180 \
      --column="Check" --column="Option" \
      --icon-name=network-wireless-offline \
      TRUE "Retry scanning internally" \
      FALSE "Retry submitting another QR Code" )
    if [[ "$CHOICE" =~ "Retry scanning internally" ]]; then
      echo e "${BOLD}Scanning in progess ... ${RESET}"
      nmcli radio wifi off
      sleep 5
      scan_connect
      if [[ $connectn != 0 ]]; then
        echo -e "${RED}============================${RESET}"
        echo -e "${BOLD}${WHITE}Can't find $QSSID ${RESET}"
        echo -e "${RED}============================${RESET}"
        exit
      fi
    elif [[ "$CHOICE" =~ "Retry submitting another QR Code" ]]; then
      if [[ $1 == "cam" ]]; then
        call_wifi_gui "cam"
      else
        call_file_select_and_scan_gui
      fi
    else
      exit
    fi
  elif [[ "$QHIDE" =~ "true" ]]; then
    zenity --question --title="Connect to Hidden WiFi" --text="Connect to '$QSSID'?" --width=200 --height=120 --icon-name=network-wireless 2>/dev/null
    if [ $connectn = 0 ]; then
      scan_connect_hidden
    else
      exit
    fi
  fi
}

call_file_select_and_scan_gui () {
  img_path=$(zenity --file-selection)
  if [ -z "$img_path" ]; then
    echo "No file selected"
    exit
  fi
  call_wifi_scan_gui "$img_path"
}

scan_connect() {
  nmcli radio wifi on
  nmcli dev wifi rescan >/dev/null 2>&1
  nmcli dev wifi connect "$QSSID" password "$QKEES" >/dev/null 2>&1
}

scan_connect_hidden() {
  nmcli radio wifi on
  nmcli con delete "$QSSID" >/dev/null 2>&1
  nmcli con add type wifi con-name "$QSSID" ssid "$QSSID" >/dev/null 2>&1
  nmcli con modify "$QSSID" wifi-sec.key-mgmt "$NTYPE" >/dev/null 2>&1
  nmcli con modify "$QSSID" wifi-sec.psk "$QKEES" >/dev/null 2>&1
  nmcli con modify "$QSSID" wifi.hidden yes  >/dev/null 2>&1
  nmcli con up "$QSSID" >/dev/null 2>&1
}

usage() {
  echo ""
  echo " Usage: $0 [-g] [-c] [-t] [-s] [-z] [-f file] [-p] [-q] [-v] [-h]"
  echo ""
  echo " -g	 Launch GUI Main Menu"
  echo " -c	 Launch WiFi QR Create GUI"
  echo " -t	 Launch WiFi QR Create Terminal"
  echo " -z	 Launch WiFi QR Create Terminal Fuzzy Finder"
  echo " -s	 Launch QR Scan and Auto Connect WiFi"
  echo " -f file Terminal [file] QR Scan and Auto Connect WiFi from file"
  echo " -p 	 Launch GUI [file] QR Scan and Auto Connect WiFi from file"
  echo " -q	 Launch QR Scan and Connect WiFi GUI"
  echo " -v	 Show WiFi-QR Version $VERSION"
  echo " -h	 Show this help message"
  echo ""
}

check_file() {
  if [ ! -f "$1" ]; then
    echo "Error: $1 is not a file."
    exit 1
  fi

  file_type=$(file -b --mime-type "$1")
  if [ "$file_type" != "image/png" ] && [ "$file_type" != "image/jpeg" ]; then
    echo "Error: $1 is not an image file."
    exit 1
  fi
}

if [[ $# -eq 0 ]] || [[ $1 != -* ]]; then
  usage
  exit 0
fi

while getopts ":gctszf:pqvh" opt; do
  case $opt in
    g)
      echo "Launching GUI Main Menu..."
      main_menu
      ;;
    c)
      echo "Launching WiFi QR Create GUI..."
      call_wifi_gui
      ;;
    t)
      echo "Launching WiFi QR Create Terminal..."
      call_wifi_terminal
      ;;
    s)
      echo "Launching QR Scan and Auto Connect WiFi..."
      call_wifi_scan_terminal "cam"
      ;;
    z)
      echo "Launching WiFi QR Create Terminal Fuzzy Finder..."
      call_wifi_terminal_fzf
      ;;
    f)
      check_file "$OPTARG"
      echo "Launching Terminal [file] QR Scan and Auto Connect WiFi from file: $OPTARG"
      call_wifi_scan_terminal "$2"
      ;;
    p)
      echo "Launching GUI [file] QR Scan and Auto Connect WiFi from file"
      call_file_select_and_scan_gui
      ;;
    q)
      echo "Launching QR Scan and Connect WiFi GUI..."
      call_wifi_scan_gui "cam"
      ;;
    v)
      echo -e "${GREEN}============================${RESET}"
      echo -e "${BOLD}${WHITE}	WiFI-QR $VERSION ${RESET}"
      echo -e "${GREEN}============================${RESET}"
      ;;
    h)
      usage
      nmcli device wifi show-password
      exit 0
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      exit 1
      ;;
    :)
      echo "Option -$OPTARG requires an argument." >&2
      exit 1
      ;;
    *)
      usage
      exit 0
  esac
done
