#!/bin/bash
#
# putty_reg2conf.sh
#
# written 2021-01-31 by Christian Wulsch
# version 1.0.1 2021-01-31ss
#
# Extracts putty sessions from a Windows registry export and creates
# session config files suitable for the Linux version of putty.
#
# Usage:
#
# First export your Windows putty sessions like this:
# regedit /s /e c:\putty.reg "HKEY_CURRENT_USER\SOFTWARE\SimonTatham"
#
# Now copy the created putty.reg file to your linux installation and use 
# the script like this:
#
# putty_reg2conf.sh putty.reg
#
# It will create a putty session file for each session found in putty.reg
# and write these files to ~/.putty/sessions/from_win_reg
# You may then copy all session files you want to the proper place where 
# putty expects them - usually ~/.putty/sessions
#

#
# config
# 
putty_reg_file="$1"
putty_sessions_path=~/.putty/sessions
putty_sessions_dest=~/.putty/sessions/from_win_reg

#
# functions
#
function urldecode() {
  text=$1
  echo $(text=${text//+/ }; printf "${text//%/\\x}")
}

function correct_value() {
  var="$1"
  val="$2"

  case "$var" in
    # Necessary corrections for linux putty to work
    "Beep" ) val=1;;
    "Font" ) var="FontName"; val="client:Hack 11";;

    # Optional changes
    "GSSLibs"       ) val="libgssapi,libgssapi_krb5,libgss,custom";;
    "PublicKeyFile" ) val="${val//\\\\/\/}"; [ ! -z "$val" ] && val="$(echo ~)/.ssh/$(basename "$val")";;
    "BellOverloadT" ) val=$((val * 1000));;
    "BellOverloadS" ) val=$((val * 1000));;
    #"TerminalType"  ) val="putty-256color";;
  esac

  echo "${var}=${val}"
}

function write_session_line() {
  filename="$1"
  session="$2"
  line="$3"
  line="$(echo $line | tr -d "\r")"
  [[ $line =~ ^\"([[:alnum:]]+)\"=([[:alnum:]]+\:)?(.*)$ ]] && { #    "Present"=dword:00000001
    var="${BASH_REMATCH[1]}"
    typ="${BASH_REMATCH[2]}"
    val="${BASH_REMATCH[3]}"
    val="${val#\"}"
    val="${val%\"}"
    [ "$typ" == "dword:" ] && val="$((16#$val))"
    echo "$(correct_value "$var" "$val")" >> "$filename"
    line=
  }
  [ ! -z $line ] && {
    echo
    echo "Could not recognize content of line: $line"
  }
}

#
# main
#

echo

command -v iconv >/dev/null 2>&1 || {
  echo "This script needs iconv to work. Please install it first!"
  echo "Memory hook:"
  echo "  apt-get install libc-bin"
  echo "  pacman -S plan9port"
  echo "  yum install glibc-common"
  echo "  dnf install glibc-common"
  echo "  brew install plan9port"
  exit 4
}

[ "$#" == "0"  ] && {
  echo "This script converts PuTTY sessions found in a Windows registry editor file into unix session files"
  echo "(usually placed in ${putty_sessions_path})."
  echo
  echo "Usage: $(basename $0) putty.reg"
  echo
  echo "putty.reg has to be an registry export of [HKEY_CURRENT_USER\SOFTWARE\SimonTatham\PuTTY]"
  echo
  exit 1
}

[ ! -r "$putty_reg_file" ] && {
  echo "$putty_reg_file does not exist or is not readable. Please check you parameters."
  echo
  exit 2
}

reg_version=$(head -n 1 "$putty_reg_file" | iconv -f utf-16le -t utf-8 - 2>/dev/null)
[[ $reg_version =~ Windows[[:space:]]Registry[[:space:]]Editor[[:space:]]Version ]] || {
  echo "$putty_reg_file is not recognized as an Windows registry editor file"
  echo
  exit 3
}

echo "Found $reg_version"

mkdir -p "${putty_sessions_dest}"
echo "Exporting to ${putty_sessions_dest}..."-

session=
session_count=0
line_count=0
while read -r line; do
  echo "$line" | grep -oP '^\[' >/dev/null 2>&1
  if [[ $? -eq 0 ]]; then
    found_session=
    newsession=$(echo "$line" | grep -ioP '\[HKEY_CURRENT_USER\\SOFTWARE\\SimonTatham\\PuTTY\\Sessions\\[^\]]+' | grep -oP '[^\\]+$') && found_session="putty"
    [ -z $newsession ] && newsession=$(echo "$line" | grep -ioP '\[HKEY_CURRENT_USER\\Software\\9bis.com\\KiTTY\\Sessions\\[^\]]+' | grep -oP '[^\\]+$') && found_session="kitty"
    if [ ! -z $found_session ]; then
      session=$(urldecode "$newsession")
      session_file="${putty_sessions_dest}/${session}"
      session_file="${session_file// /%20}"
      > "$session_file"
      echo
      echo -n "Writing $found_session session '$session' to '$session_file' "
      line_count=0
      (( session_count++ ))
    else
      session=
    fi
  else
    [ -z "$session" ] || {
      write_session_line "$session_file" "$session" "$line"
      ((line_count++))
      ! (( line_count % 10 )) && echo -n "."
    }
  fi
done < <(iconv -f utf-16le -t utf-8 < "$putty_reg_file")

echo
echo
echo "Wrote $session_count session files found in $putty_reg_file to ${putty_sessions_dest}"
echo "You may now manually copy the ones you want into ${putty_sessions_path}"
echo
