#!/bin/bash

# push_firmware script
#
# Flashes firmware file to AVM devices or Speedport.
#
# Copyright (c) 2007 Michael Hampicke	 (mike@mhampicke.de)
#		2007 Alexander Kriegisch (kriegaex, ip-phone-forum.de)
#		2011 extended for ALICE 7570 by MaxMuster
#		2019 extended by ram-boot and dual-boot modes for freetz-ng
#		2020 extended by uimg support (uses fesc2000's uimg tool)
#
# Cygwin users note:
#   1. There is NO guarantee whatsoever that this will work on Cygwin, even
#      though it does on my box (kriegaex). Provided as is.
#   2. For FTP you need the 'ncftp' cygwin package (category 'net').
#   3. You need the 'ping' command from Windows (tested on XP), NOT from the
#      'ping' cygwin package (please uninstall or change path so Windows
#      version is found first), because the cygwin version has no timeout
#      parameter as of today (2007-07-11).
#   4. For 'hexdump' you need the 'util-linux' cygwin package (category
#      'utils').
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

UIMG_TOOL="${0%/*}/uimg"
TSUM_TOOL="${0%/*}/tichksum"

function wait_loader() {
	echo -en " * No reply from box, assuming switch-off or restart. Trying to re-detect box.\n   Waiting "
	[ -z "$SLEEP1" ] && SLEEP1=do || sleep 1
	while ! ping $ping_params $ip > /dev/null; do
		echo -n "."
		sleep 0.2
	done
	echo -e ". found!\n"
}

function read_enval() {
	ftp -v -n <<EOT | sed -rn "s/^$1[ \t]*//p"
open $ip
user adam2 adam2
quote GETENV $1
quote REBOOT
quit
EOT
}

function push_fw() {
	trap 'echo ; echo "aborted" ; exit 1' TERM INT

	echo
	echo    " * You should now reboot your box ($ip). Waiting for shut down."
	echo    "   Switch off, if reboot is not detected because it happens too quickly."
	echo    "   Some newer bootloader versions allow to flash on power-cycle only."
	echo -n "   "
	while ping $ping_params $ip > /dev/null; do
		echo -n "."
		sleep 0.2
	done
	echo

	if [ $ISRAM ]; then
		if [ "${FULLSIZE//0/}" == "x" ]; then
			wait_loader
			enval="$(read_enval memsize)"
			[ "$enval" != "${enval#0x}" ] && FULLSIZE="$enval"
			[ -z "$FULLSIZE" ] && echo "Invalid value for memsize." && exit 1
			echo " * Detected memsize: '$enval'"
			echo
		fi

		MAPSTART=0x80000000  # start mapped memory
		MAPLIMIT="0x$(printf '%.8x' $(( $MAPSTART + $FULLSIZE )))"
		FILESIZE="0x$(printf '%.8x' $(stat --printf='%s' "$mtdram1"))"
		FREESIZE="0x$(printf '%.8x' $(( $FULLSIZE - $FILESIZE )))"
		MTDSTART="0x$(printf '%.8x' $(( $MAPSTART + $FULLSIZE - $FILESIZE )))"

		echo -e " * MAPSTART=$MAPSTART"
		echo -e " * FULLSIZE=$FULLSIZE\t ($(($FULLSIZE/1024/1024)) MB)"
		echo -e " * MAPLIMIT=$MAPLIMIT"
		echo -e " * FILESIZE=$FILESIZE\t (~$(($FILESIZE/1024/1024)) MB)"
		echo -e " * FREESIZE=$FREESIZE\t (~$(($FREESIZE/1024/1024)) MB)"
		echo -e " * MTDSTART=$MTDSTART"
		echo -e
	fi

	if [ ! $ISSINGLE ]; then
		if [ ! $LFS ] || [ -n "$ISDUAL$ISUIMG" -a "$LFS" == "9" ]; then
			wait_loader
			enval="$(read_enval linux_fs_start)"
			[ "$enval" != "0" -a "$enval" != "1" -a "$enval" != "" ] && echo "Invalid value for linux_fs_start." && exit 1
			echo " * Detected linux_fs_start: '${enval:-<unset>}'"
			[ -z "$enval" ] && enval=0 #factory
			[ -z "$LFS" ]     && LFS="$(( ($enval + 1) % 2))" #other
			[ "$LFS" == "9" ] && LFS="$enval" #current
			echo " * Designated linux_fs_start: $LFS"
			echo
		fi
		if [ $ISRAM ]; then
			[ "$LFS" == "9" ] && LFS=
		elif [ $ISDUAL ]; then
			[ $LFS -ne 1 ] && ARMsysMTD='0'  && ARMkrnMTD='1'  && X86sysMTD='6'  && X86krnMTD='7'
			[ $LFS -eq 1 ] && ARMsysMTD='11' && ARMkrnMTD='12' && X86sysMTD='13' && X86krnMTD='14'
		elif [ $ISUIMG ]; then
			[ $LFS -ne 1 ] && ARMsysMTD='6'  && ARMkrnMTD='7'  && X86sysMTD='0'  && X86krnMTD='1'  && ALLgwtMTD='TODO'
			[ $LFS -eq 1 ] && ARMsysMTD='='  && ARMkrnMTD='>'  && X86sysMTD=';'  && X86krnMTD='<'  && ALLgwtMTD='TODO'
			[ -e $ALLgwt ] && echo " * GWFS (tar) mtd: $ALLgwtMTD"
		fi
		if [ -n "$ISDUAL$ISUIMG" ]; then
			echo " * Arm-System mtd: $ARMsysMTD"
			echo " * Arm-Kernel mtd: $ARMkrnMTD"
			echo " * x86-System mtd: $X86sysMTD"
			echo " * x86-Kernel mtd: $X86krnMTD"
			echo
		fi
	fi

	wait_loader
	echo " * Box is back up again, initiating transfer."
	echo

	if [ $ISSINGLE ]; then
		if [ $ISALICE ]; then
			basename=$(basename $0)
			echo "$basename: Trying to flash an image to an \"Alice\" 7570 FritzBox."
			[ $(which telnet) ] || { echo "$basename: Error finding required binary \"telnet\"." ; exit 1 ;}
			VALUES="$(telnet_hn | telnet 2>/dev/null| grep -e '^mtd[1\|5]\|^HWRevision')" || { echo "$basename: Error trying to get values from \"Alice\" FritzBox."; exit 1; }
			HWR=$(echo "$VALUES" | sed -n '/^HWRev/ s/HWRevision[^0-9]*//p')
			[ "153" = "$HWR" ] || { echo "$basename: Error veryfing HWRevision=153 as required for \"Alice\" FritzBox. Found: HWRevision=$HWR." ; exit 1 ;}
			MTD=$(echo "$VALUES" | sed -n '/^mtd/ s/mtd.[^0]*// p')
			$(echo $MTD | tr -d '\n' | grep '0x90040000,0x907E0000' | grep -q '0x907E0000,0x90F80000') || \
				{ echo -e "$basename: Error veryfing mtd values for \"Alice\" box. Found values:\n$MTD" ; exit 1 ;}

			size=$(stat -c %s $img)
			let max_size=7808*1024
			if [ $size -ge $max_size ]; then
				kernel_mtd1=$(mktemp -t freetz_mtd1_XXX) || { echo "$basename: Error creating temporary file for mtd1."; exit 1; }
				kernel_mtd5=$(mktemp -t freetz_mtd5_XXX) || { echo "$basename: Error creating temporary file for mtd5."; exit 1; }
				dd if=${file} of=${kernel_mtd1} bs=1k count=7808 >/dev/null 2>&1 || { echo "$basename: Error creating image part for mtd1."; exit 1; }
				dd if=${file} of=${kernel_mtd5} bs=1k skip=7808 >/dev/null 2>&1 || { echo "$basename: Error creating image part for mtd5."; exit 1; }
			else
				ISALICE=false
				kernel_mtd1=$img
			fi
		else
			kernel_mtd1=$img
		fi
	fi

	if [ $FOUND_NCFTP ]; then
		if [ $ISRAM ]; then
			ncftpput \
				-C -d stdout -u adam2 -p adam2 \
				-o doNotGetStartCWD=1,useFEAT=0,useHELP_SITE=0,useCLNT=0,useSIZE=0,useMDTM=0 \
				-W "quote MEDIA SDRAM" \
				-W "quote SETENV memsize ${FREESIZE}" \
				-W "quote SETENV kernel_args_tmp mtdram1=${MTDSTART},${MAPLIMIT}" \
				-X "$([ ! $LFS ] && echo "quote SYST" || echo "quote SETENV linux_fs_start $LFS")" \
				-Y "quote QUIT" \
				$ip ${mtdram1} "${MTDSTART} ${MAPLIMIT}" || exit $?
		elif [ -n "$ISDUAL$ISUIMG" ]; then
			[ -e $ALLgwt ] && ncftpput \
				-C -d stdout -u adam2 -p adam2 \
				-o doNotGetStartCWD=1,useFEAT=0,useHELP_SITE=0,useCLNT=0,useSIZE=0,useMDTM=0 \
				-W "quote MEDIA FLSH" \
				$ip $ALLgwt mtd$ALLgwtMTD || exit $?
			ncftpput \
				-C -d stdout -u adam2 -p adam2 \
				-o doNotGetStartCWD=1,useFEAT=0,useHELP_SITE=0,useCLNT=0,useSIZE=0,useMDTM=0 \
				-W "quote MEDIA FLSH" \
				$ip $ARMsys mtd$ARMsysMTD || exit $?
			ncftpput \
				-C -d stdout -u adam2 -p adam2 \
				-o doNotGetStartCWD=1,useFEAT=0,useHELP_SITE=0,useCLNT=0,useSIZE=0,useMDTM=0 \
				-W "quote MEDIA FLSH" \
				$ip $ARMkrn mtd$ARMkrnMTD || exit $?
			ncftpput \
				-C -d stdout -u adam2 -p adam2 \
				-o doNotGetStartCWD=1,useFEAT=0,useHELP_SITE=0,useCLNT=0,useSIZE=0,useMDTM=0 \
				-W "quote MEDIA FLSH" \
				$ip $X86sys mtd$X86sysMTD || exit $?
			ncftpput \
				-C -d stdout -u adam2 -p adam2 \
				-o doNotGetStartCWD=1,useFEAT=0,useHELP_SITE=0,useCLNT=0,useSIZE=0,useMDTM=0 \
				-W "quote MEDIA FLSH" \
				-X "quote SETENV linux_fs_start $LFS" \
				-Y "quote REBOOT" \
				$ip $X86krn mtd$X86krnMTD || exit $?
		elif [ $ISSINGLE ]; then
			[ $ISALICE ] && ( ncftpput \
				-C -d stdout -u adam2 -p adam2 \
				-o doNotGetStartCWD=1,useFEAT=0,useHELP_SITE=0,useCLNT=0,useSIZE=0,useMDTM=0 \
				-W "quote MEDIA FLSH" \
				$ip ${kernel_mtd5} mtd5 || exit $? )
			ncftpput \
				-C -d stdout -u adam2 -p adam2 \
				-o doNotGetStartCWD=1,useFEAT=0,useHELP_SITE=0,useCLNT=0,useSIZE=0,useMDTM=0 \
				-W "quote MEDIA FLSH" \
				-Y "quote REBOOT" \
				$ip ${kernel_mtd1} mtd1 || exit $?
		else
			echo "miserable failure" && exit 1
		fi
	elif [ $FOUND_FTP ]; then
		if [ $ISRAM ]; then
			ftp -n -p <<EOT
open $ip
user adam2 adam2
debug
bin
quote MEDIA SDRAM
quote SETENV memsize ${FREESIZE}
quote SETENV kernel_args_tmp mtdram1=${MTDSTART},${MAPLIMIT}
put ${mtdram1} "${MTDSTART} ${MAPLIMIT}"
$([ $LFS ] && echo quote SETENV linux_fs_start $LFS)
quit
EOT
		elif [ -n "$ISDUAL$ISUIMG" ]; then
			ftp -n -p <<EOT
open $ip
user adam2 adam2
debug
bin
quote MEDIA FLSH
put $ARMsys mtd$ARMsysMTD
put $ARMkrn mtd$ARMkrnMTD
put $X86sys mtd$X86sysMTD
put $X86krn mtd$X86krnMTD
$([ -e $ALLgwt ] && echo put $ALLgwt mtd$ALLgwtMTD)
quote SETENV linux_fs_start $LFS
quote REBOOT
quit
EOT
		elif [ $ISSINGLE ]; then
			ftp -n -p <<EOT
open $ip
user adam2 adam2
debug
bin
quote MEDIA FLSH
put ${kernel_mtd1} mtd1
$([ $ISALICE ] && echo put ${kernel_mtd5} mtd5 )
quote REBOOT
quit
EOT
		else
			echo "miserable failure" && exit 1
		fi
	fi
}

telnet_hn() {
	echo open $ip 21
	sleep 0.2
	echo USER adam2
	sleep 0.2
	echo PASS adam2
	sleep 0.2
	echo GETENV mtd1
	sleep 0.2
	echo GETENV mtd5
	sleep 0.2
	echo GETENV HWRevision
	sleep 0.2
	echo QUIT
	sleep 0.2
}

prepare_image() {
	if [ $ISRAM ]; then
		tmpdir=$(mktemp -td freetz_XXX) || { echo "Error creating temporary directory."; exit 1; }
		mtdram1="$tmpdir/ramboot.flash"
		if [ $INMEM ]; then
			cp -p $file $mtdram1
		elif tar -C $tmpdir/ -xf $file --wildcards '*.image' >/dev/null 2>&1; then
			if [ -s "$tmpdir/var/tmp/kernel.image" -a -s "$tmpdir/var/tmp/filesystem.image" ]; then
				for f in "$tmpdir/var/tmp/kernel.image" "$tmpdir/var/tmp/filesystem.image"; do
					$TSUM_TOOL -r "$f" >/dev/null
					dd if="$f" bs=256 conv=sync 2>/dev/null
				done  > "$mtdram1"
			fi
		fi
		if [ ! -s "$mtdram1" ]; then
			echo -e "\nError: file is not a valid ram-boot image to be written to the device.\n" >&2
			exit 1
		fi
	elif [ $ISDUAL ]; then
		tmpdir=$(mktemp -td freetz_XXX) || { echo "Error creating temporary directory."; exit 1; }
		ARMsys="$tmpdir/ARM-system.image"
		ARMkrn="$tmpdir/ARM-kernel.image"
		X86sys="$tmpdir/X86-system.image"
		X86krn="$tmpdir/X86-kernel.image"
		if tar -C $tmpdir/ -xf $file --wildcards '*.image' >/dev/null 2>&1; then
			mv "$tmpdir/var/remote/var/tmp/filesystem.image"     "$ARMsys" 2>/dev/null
			mv "$tmpdir/var/remote/var/tmp/kernel.image"         "$ARMkrn" 2>/dev/null
			mv "$tmpdir/var/remote/var/tmp/x86/filesystem.image" "$X86sys" 2>/dev/null
			mv "$tmpdir/var/remote/var/tmp/x86/kernel.image"     "$X86krn" 2>/dev/null
		fi
		if [ ! -s "$ARMsys" -o ! -s "$ARMkrn" -o ! -s "$X86sys" -o ! -s "$X86krn" ]; then
			echo -e "\nError: file is not a valid dual-boot image to be written to the device.\n" >&2
			exit 1
		fi
	elif [ $ISUIMG ]; then
		tmpdir=$(mktemp -td freetz_XXX) || { echo "Error creating temporary directory."; exit 1; }
		ARMsys="$tmpdir/ARM-system.image"
		ARMkrn="$tmpdir/ARM-kernel.image"
		X86sys="$tmpdir/X86-system.image"
		X86krn="$tmpdir/X86-kernel.image"
		ALLgwt="$tmpdir/ALL-gw_fs.image"
		if tar -C $tmpdir/ -xf $file ./var/firmware-update.uimg >/dev/null 2>&1; then
			$UIMG_TOOL -u "$tmpdir/var/firmware-update.uimg" >/dev/null
			chmod +w $tmpdir/var/*.bin
			mv $tmpdir/var/*_ARM_ROOTFS.bin  "$ARMsys" 2>/dev/null
			mv $tmpdir/var/*_ARM_KERNEL.bin  "$ARMkrn" 2>/dev/null
			mv $tmpdir/var/*_ATOM_ROOTFS.bin "$X86sys" 2>/dev/null
			mv $tmpdir/var/*_ATOM_KERNEL.bin "$X86krn" 2>/dev/null
#			mv $tmpdir/var/*_GWFS.bin        "$ALLgwt" 2>/dev/null  # TODO
		fi
		if [ ! -s "$ARMsys" -o ! -s "$ARMkrn" -o ! -s "$X86sys" -o ! -s "$X86krn" ]; then
			echo -e "\nError: file is not a valid uimg-boot image to be written to the device.\n" >&2
			exit 1
		fi
	elif [ $ISSINGLE ]; then
		work=$file
		img=""
		while [ -z "$img" ]; do
			[ "$(uname -s)" == "Darwin" ] && CHECK="81 12 ed fe" || CHECK="1281 feed"
			hexdump -n4 "$work" | grep -iq "$CHECK" && img="$work"
			if [ -z "$img" ]; then
				if tar tf "$work" ./var/tmp/kernel.image >/dev/null 2>&1; then
					tmpimg=$(mktemp -t freetz_XXX) || { echo "Error creating temporary file."; exit 1; }
					tar -Oxf "$work" ./var/tmp/kernel.image > $tmpimg
					work=$tmpimg
				else
					echo -e "\nError: file is not a valid single-boot image to be written to the device.\n" >&2
					exit 1
				fi
			fi
		done
	else
		echo "miserable failure" && exit 1
	fi
}

function cleanup() {
	local val=$?
	[ -n "$tmpdir"        -a -d "$tmpdir"        ] && rm -rf "$tmpdir";
	[ -n "$tmpimg"        -a -f "$tmpimg"        ] && rm -rf "$tmpimg";
	[ -n "${kernel_mtd1}" -a -f "${kernel_mtd1}" ] && rm -rf "${kernel_mtd1}";
	[ -n "${kernel_mtd5}" -a -f "${kernel_mtd5}" ] && rm -rf "${kernel_mtd5}";
	exit $val
}
trap cleanup EXIT SIGTERM SIGINT

usage()
{
	echo
	echo "Usage: $0 [image] [ -m<s|r|d|u|f> ] [ -f ] [ -ip <ip> ] [ -ram <mb> ] [ -lfs <0|1|9> ] [ -cmd <ftp|ncftp> ] [ -hn ]"
	echo
	echo "[image]           When no 'image' file is given, images/latest.image will be tried."
	echo "-ms               Force mode single-boot (classic devices, like 7270 & 7390)"
	echo "-mr               Force mode ram-boot (newer devices, like 7490 & 7590)"
	echo "-md               Force mode dual-boot (classic docsis devices, like 6490 & 6590)"
	echo "-mu               Force mode uimg-boot (newer docsis devices, like 6591 & 6660)"
	echo "                    See https://bitbucket.org/fesc2000/ffritz/src/6591/README-6591.md"
	echo "-mf               Force mode fit-boot (newer AX devices, like 7530 AX)"
	echo "                    Not supported yet!"
	echo "-f                Disable safety prompt."
	echo "-ip <ip>          Bootloader IP address or hostname, default 192.168.178.1"
	echo "-ram <mb>         Only ram-boot mode: Usable ram size in MB of your device."
	echo "                    Without this parameter, the default of 128 MB will be used."
	echo "                    Some devices like Repeater 3000 need 256 MB to flash."
	echo "                    Use '0' to detect and use all available ram."
	echo "-lfs <0|1|9>      Not single-boot mode: Set linux_fs_start to 0 or 1 and flash into this."
	echo "                    Without this parameter, the inactive linux_fs_start will be used."
	echo "                    Use '9' for the currently active linux_fs_start."
	echo "-cmd <ftp|ncftp>  Force the prefered usage of ftp or ncftp command for upload."
	echo "-hn               Only single-boot mode: Flash to an 'Alice/HanseNet' version of 7570."
	echo
	exit 1
}

while [ $# -ge 1 ]; do
	case "$1" in
		(-ms|-msingle)
			ISSINGLE=true
			;;
		(-mr|-mram)
			ISRAM=true
			;;
		(-md|-mdual)
			ISDUAL=true
			;;
		(-mu|-muimg)
			ISUIMG=true
			;;
		(-mf|-mfit)
			ISFIT=true
			;;
		(-f|-force)
			ISFORCE=true
			;;
		(-ip)
			[ -z "$2" -o "$2" != "${2#\-}" ] && usage
			ip=$2
			shift
			;;
		(-ram)
			[ -z "$2" -o "$2" != "${2#\-}" ] && usage
			[ "$2" -ge 0 2>/dev/null ] && FULLSIZE="0x$(printf '%.8x' "$(( $2 * 1048576 ))")"
			[ -z "$FULLSIZE" ] && echo "Invalid value for ram size" && usage
			shift
			;;
		(-lfs)
			[ "$2" != "0" -a "$2" != "1" -a "$2" != "9" ] && echo "Invalid linux_fs_start value" && usage
			LFS=$2
			shift
			;;
		(-cmd)
			[ "$2" != "ftp" -a "$2" != "ncftp" ] && echo "Invalid command value" && usage
			CMD=$2
			shift
			;;
		(-hn)
			ISALICE=true
			;;
		(-h|--help)
			usage
			;;
		(*)
			if [ -z "$file" -a "$1" == "${1#\-}" ]; then
				file="$1"
			else
				echo "Unknown parameter: $1" && usage
			fi
			;;
	esac
	shift
done

# environment
[ "$FREETZ_FORCEPF" == "true" ] && ISFORCE=true

# file checks
[ -z "$file" ] && [ -e images/latest.image ] && file="images/latest.image"
[ -L "$file" ] && file="$(realpath "$file")" && file=${file#$PWD/}
[ -z "$file" ] && usage
[ -n "$file" ] || { echo "An image file is mandatory."      ; exit 1; }
[ -e "$file" ] || { echo "No such file or directory: $file" ; exit 1; }
[ -f "$file" ] || { echo "Not a file: $file"                ; exit 1; }
[ -r "$file" ] || { echo "Access denied: $file"             ; exit 1; }

# img detect
if [ -z "$ISSINGLE$ISDUAL$ISRAM$ISUIMG$ISFIT" ]; then
	echo -e "\n * Analyzing '$file' ... "
	if tar tf "$file" --wildcards '*/fit-image' &>/dev/null; then
		ISFIT=true
	elif tar tf "$file" --wildcards '*/firmware-update.uimg' &>/dev/null; then
		ISUIMG=true
	elif dd if="$file" bs=1 skip=2 count=2 2>/dev/null | base64 | grep -q '^7f4=$'; then
		INMEM=true
		ISRAM=true
	else
		N="$(tar tf "$file" --wildcards '*/kernel.image' 2>/dev/null | wc -l)"
		S="$(tar -Oxf "$file" ./var/tmp/filesystem.image 2>/dev/null | wc -c)"
		[ "$N" == "1" -a "$S" != "0" ] && ISRAM=true
		[ "$N" == "2" -a "$S" == "0" ] && ISDUAL=true
		[ "$N" == "1" -a "$S" == "0" ] && ISSINGLE=true
	fi
fi
[ -z "$ISSINGLE$ISDUAL$ISRAM$ISUIMG$ISFIT" ] && echo "Can not recognize image, please use '-m<s|r|d|u|f>'."  && exit 1
# arg check
[ ! $ISSINGLE ] && [ $ISALICE ]        && echo "Parameter '-hn' is only allowed for single-boot mode."       && exit 1
[ $ISSINGLE ]   && [ $LFS ]            && echo "Parameter '-lfs' is not allowed for single-boot mode."       && exit 1
[ $ISDUAL ]     && [ ! $LFS ]          && LFS="1"
[ $ISUIMG ]     && [ ! $LFS ]          && LFS="1"
[ $ISUIMG ]     && [ ! -x $UIMG_TOOL ] && echo "File $UIMG_TOOL missing. Run 'make uimg' first."             && exit 1
[ $ISRAM ]      && [ ! -x $TSUM_TOOL ] && echo "File $TSUM_TOOL missing. Run 'make tichksum-host' first."    && exit 1
[ ! $ISRAM ]    && [ $FULLSIZE ]       && echo "Parameter '-ram' is only allowed for ram-boot mode."         && exit 1
[ $ISFIT ]                             && echo "FIT is not supported yet!"                                   && exit 1

prepare_image

# IPs
[ ! $ip ] && ip=192.168.178.1
oa="unknown"
for horst in $(hostname -I); do
	[ ${horst%.*} == ${ip%.*} ] && oa=$horst
done
if [ "$oa" == "unknown" ]; then
	echo -ne "\n * Warning: It seems your network is not able to reach\n   $ip directly."
	case $(ls /sys/class/net/ | grep -v "^lo$" | wc -w) in
		0)	echo ;;
		1)	echo " This command could help to fix:" ;;
		*)	echo " One(!) of these commands could help to fix:" ;;
	esac
	for x in $(ls /sys/class/net/ | grep -v "^lo$" ); do
		echo -e  "   $ \033[4msudo ifconfig $x:0 ${ip%.*}.$(ifconfig $x | sed -rn 's/.*inet [0-9\.]*\.([0-9]*) .*/\1/p') up\033[0m"
	done
	echo -n  "   Proceed anyway? ([y]/n) "
	read -n 1 -s PROCEED_NETCFG
	[ "$PROCEED_NETCFG" != "y" -a -n "$PROCEED_NETCFG" ] && echo -e "n\n\naborted\n" && exit
	echo     "$PROCEED_NETCFG"
fi

ping_params="-c1 -w1"
if [ "$(uname -s)" == "Darwin" ]; then
	ping_params="-c1 -t1"
elif [ "$(uname -o)" == "Cygwin" ]; then
	CYGWIN=1
	ping_params="-n 1 -w 500"
fi
[ -x "$(which ncftpput 2>/dev/null)" ] && FOUND_NCFTP=true
[ "$(uname -s)" == "Linux" -a -x "$(which ftp 2>/dev/null)" ] && FOUND_FTP=true
if [ -z "$FOUND_NCFTP" -a -z "$FOUND_FTP" ]; then
	echo "You have to install 'ncftp' or 'ftp' in order to use this script."
	exit 1
fi
if [ -z "$FOUND_FTP" ]; then
	[ $ISRAM ]       && [ "${FULLSIZE//0/}" == "x" ] && echo "Parameter '-ram' has to be bigger than 0 if you have no 'ftp' installed."  && exit 1
	[ ! $ISSINGLE ]  && [ -z "$LFS" ]                && echo "Parameter '-lfs' is mandatory if you have no 'ftp' installed."             && exit 1
	[ $ISDUAL ]      && [ "$LFS" == "9" ]            && echo "Parameter '-lfs' with 0 or 1 is mandatory if you have no 'ftp' installed." && exit 1
	[ $ISUIMG ]      && [ "$LFS" == "9" ]            && echo "Parameter '-lfs' with 0 or 1 is mandatory if you have no 'ftp' installed." && exit 1
fi
if [ -n "$CMD" ]; then
	[ "$CMD" == "ftp" ] && FOUND_NCFTP=""
	[ "$CMD" == "ncftp" ] && FOUND_FTP=""
fi
if [ -n "$FOUND_NCFTP" -a -n "$FOUND_FTP" ]; then
	[ $ISRAM ]    && FOUND_NCFTP=""
	[ $ISDUAL ]   && FOUND_NCFTP=""
	[ $ISUIMG ]   && FOUND_NCFTP=""
	[ $ISSINGLE ] && FOUND_FTP=""
	[ $ISALICE ]  && FOUND_NCFTP=""
fi
[ -n "$FOUND_NCFTP" ] && UCMD="ncftpput" || UCMD="ftp"

# logging
echo
echo " * Using command: $UCMD"
echo " * Target host: $ip"
echo " * Outgoing IP: $oa"

if [ $ISUIMG ]; then
	OUTVAL="uimg"
elif [ $ISDUAL ]; then
	OUTVAL="dual"
elif [ $INMEM ]; then
	OUTVAL="inmemory"
elif [ $ISRAM ]; then
	OUTVAL="ram"
else
	OUTVAL="single"
fi
echo " * Flash mode: $OUTVAL-boot"

if [ $ISRAM ]; then
	[ -z "$FULLSIZE" ] && FULLSIZE="0x08000000"
	[ "${FULLSIZE//0/}" == "x" ] && OUTVAL="<detect>" || OUTVAL="$(( $FULLSIZE /1024/1024 )) MB"
	echo " * Allowed memory size: $OUTVAL"
fi

if [ ! $ISSINGLE ]; then
	[ -n "$LFS" ]     && OUTVAL="$LFS"
	[ -z "$LFS" ]     && OUTVAL="<other>"
	[ "$LFS" == "9" ] && OUTVAL="<current>"
	echo " * Designated linux_fs_start: $OUTVAL"
fi

#
if [ $ISFORCE ]; then
	echo -e " * File: \033[4m$file\033[0m"
	push_fw
else
	echo
	echo    " !!! WARNING !!! WARNING !!! WARNING !!! WARNING !!! WARNING !!!"
	echo    " !!!  THERE IS NO WARRANTY AT ALL !!! USE AT YOUR OWN RISK   !!!"
	echo
	echo    " * Are you sure, that you want to flash this file to the device?"
	echo -e "   \033[4m$file\033[0m"
	echo -n "   Proceed? (y/[n]) "
	read -n 1 -s PROCEED
	[ "$PROCEED" != "y" ] && echo -e "n\n\naborted\n" && exit
	echo    "$PROCEED"
	push_fw
fi

echo
echo done
exit 0