#!/bin/bash
MYVERSION="0.2.0e"

# Transform debug to DEBUG, in order to declare debug method.
if [ -n "${debug}" ]; then
	echo "Warning: debug variable is obsolete. Use DEBUG instead." >> /dev/stderr
	export DEBUG="${debug}"
	unset debug
fi

# Display formatted debug output if DEBUG variable is set.
# This method should have as less dependencies as possible.
debug() {
	if [ "a$1" != "arun_command" -a "a$1" != "ashow_file" -a -z "${DEBUG}" ]; then
		return 0
	elif [ "a$1" = "arun_command" -a -z "${DEBUG}" ]; then
		shift
		sh -c "$*" > /dev/null 2> /dev/null
		return $?
	elif [ "a$1" = "arun_command" -a -n "${DEBUG}" ]; then
		shift
		printf "/-------------------------------------------------------------------------------\n" >> "/dev/stderr"
		printf "[%.5d] [%s] Will now run command: \'%s\'\n" "$$" "`date "+%H:%M:%S"`" "${*}" >> "/dev/stderr"
		printf "/-------------------------------------------------------------------------------\n" >> "/dev/stderr"
		sh -c "$*" >> "/dev/stderr" 2>&1
		rdebug=$?
		printf "\-------------------------------------------------------------------------------\n" >> "/dev/stderr"
		printf "[%.5d] [%s] Command returned %d.\n" "$$" "`date "+%H:%M:%S"`" "${rdebug}" >> "/dev/stderr"
		printf "\-------------------------------------------------------------------------------\n" >> "/dev/stderr"
		return ${rdebug}
	elif [ -z "${DEBUG}" ]; then
		return 0
	elif [ "a$1" = "ashow_file" ]; then
		if [ -f "$2" ]; then
			printf "/-------------------------------------------------------------------------------\n" >> "/dev/stderr"
			printf "[%.5d] [%s] Will now display contents of: \'%s\'\n" "$$" "`date "+%H:%M:%S"`" "$2" >> "/dev/stderr"
			printf "/-------------------------------------------------------------------------------\n" >> "/dev/stderr"
			cat "$2" >> "/dev/stderr"
			printf "\-------------------------------------------------------------------------------\n" >> "/dev/stderr"
			ls -ld "$2" >> "/dev/stderr"
			printf "\-------------------------------------------------------------------------------\n" >> "/dev/stderr"
		else
			printf "/-------------------------------------------------------------------------------\n" >> "/dev/stderr"
			printf "[%.5d] [%s] File does not exist: \'%s\'\n" "$$" "`date "+%H:%M:%S"`" "$2" >> "/dev/stderr"
			printf "\-------------------------------------------------------------------------------\n" >> "/dev/stderr"
		fi
		return 0
	else
		rfmt="$1"
		shift
		if [ "a${YESFUNCNAME}" = "a" ]; then
			if [ "$#" -ge "1" ]; then
				printf "[%.5d] [%s] ${rfmt}" "$$" "`date "+%H:%M:%S"`" "${@}" >> "/dev/stderr"
			else
				printf "[%.5d] [%s] ${rfmt}" "$$" "`date "+%H:%M:%S"`" >> "/dev/stderr"
			fi
		else
			if [ "$#" -ge "1" ]; then
				printf "[%.5d] [%s] [%-20s] ${rfmt}" "$$" "`date "+%H:%M:%S"`" "${FUNCNAME[1]}" "${@}" >> "/dev/stderr"
			else
				printf "[%.5d] [%s] [%-20s] ${rfmt}" "$$" "`date "+%H:%M:%S"`" "${FUNCNAME[1]}" >> "/dev/stderr"
			fi
		fi
		unset rfmt
	fi
	return 0
}

# Print debug header
debug_header() {
	if [ -n "${DEBUG}" ]; then
		echo >> "/dev/stderr"
		echo "-------------------------------------------" >> "/dev/stderr"
		echo "Sakis3G ${MYVERSION} running on DEBUG mode." >> "/dev/stderr"
		echo "-------------------------------------------" >> "/dev/stderr"
		date >> "/dev/stderr"
		echo "-------------------------------------------" >> "/dev/stderr"
		if [ "a${allargs}" = "a" ]; then
			echo "Command line was: $0 $@" >> "/dev/stderr"
		else
			echo "Command line was: $0 ${allargs}" >> "/dev/stderr"
		fi
		echo "Running with PID: $$" >> "/dev/stderr"
		echo "-------------------------------------------" >> "/dev/stderr"
		echo "Environment is:" >> "/dev/stderr"
		set >> "/dev/stderr"
		echo "-------------------------------------------" >> "/dev/stderr"
		echo "Will now proceed with Sakis3G execution." >> "/dev/stderr"
		echo "-------------------------------------------" >> "/dev/stderr"
	fi
}

need_arg() {
	[ "a`eval echo \\\$$1 2> /dev/null`" != "a" ] && return 0
	case "$1" in
		foldwrapping)
			export foldwrapping=60
			;;
		pppint)
			export pppint="ppp0"
			;;
  		CHAT_ABORT_STRINGS)
			# Abort strings that chat program may encounter
			export CHAT_ABORT_STRINGS="ABORT BUSY ABORT ERROR ABORT BLOCKED ABORT NOCARRIER"
			;;
		BAUD)
			export BAUD="460800"
			;;
		PPPD_OPTIONS)
			# Options passed to pppd when called directly
			export PPPD_OPTIONS="modem crtscts -detach defaultroute dump noipdefault usepeerdns usehostname ktune logfd 2 noauth name sakis3g lock maxfail 3"
			;;
		PPPD_PEERS)
			# Directory where pppd keeps its peers
			export PPPD_PEERS=/etc/ppp/peers
			;;
		SERIALDRIVERS)
			export SERIALDRIVERS="ftdi_sio ipaq safe_serial usbserial visor"
			;;
		LOGPOSITION)
			export LOGPOSITION="/var/log/sakis3g.log"
			;;
		XOSDFONT)
			export XOSDFONT='-*-freesans-bold-r-*-*-36-*-*-*-*-*-*-*'
			;;
		AOSDFONT)
			export AOSDFONT='DejaVuSans 36'
			;;
		MENUFONT)
			export MENUFONT="-monotype-arial-medium-r-normal-*-18-*-*-*-*-*-*-*"
			;;
		*)
			debug "No default value for %s was found.\n" "$1"
			;;
	esac
	debug "Loaded default value for %s: %s\n" "$1" "`eval echo \\\$$1 2> /dev/null`"
}

sanitize() {
	echo "$@" 2> /dev/null | ${trbin} "\\" " " 2> /dev/null | ${trbin} "\"" " " | ${trbin} "'" " " | ${trbin} "\`" " "
}

release_X_cookie() {
	debug "Disposing stolen X session cookie for %s.\n" "${XCOOKIE}"
	if [ -n "${XCOOKIE}" ] && find_binary "xauth"; then
		# If having an authority file that does not belong to us, unset it.
		if [ "a${XAUTHORITY}" = "a${runhome}/.Xauthority" -a "a$HOME" != "a${runhome}" ]; then
			unset XAUTHORITY
		fi
		found=`${xauthbin} nlist ${XCOOKIE} | ${wcbin} -l`
		found=`echo ${found}`
		if [ "a${found}" = "a0" ]; then
			debug "Cookie already disposed.\n"
		else
			${xauthbin} remove ${XCOOKIE}
			found=`xauth nlist ${XCOOKIE} | ${wcbin} -l`
			found=`echo ${found}`
			if [ "a${found}" = "a0" ]; then
				debug "Cookie disposed as it should.\n"
				unset XCOOKIE
			else
				debug "Failed to dispose cookie.\n"
			fi
		fi
		unset found
	fi
}

# Callback function called on EXIT to execute traps.
exittrap() {
	if [ -n "${TRAPS}" ]; then
		debug "Now executing traps.\n"
		for tr in ${TRAPS}
		do
			debug "Executing trap \"%s\".\n" "${tr}"
			${tr}
		done
	else
		debug "No exit traps defined.\n"
	fi
	if ppp_fast_status; then
		debug "\n>>>>>>>>> If program is paused, you may freely press Ctrl+C. <<<<<<<<<\n>>> This happens due to DEBUG being set. Connection will NOT drop. <<<\n"
	fi
}

# Adds trap to be executed on EXIT
addexittrap() {
	[ "a$1" = "a" ] && return 0;
	if [ "a${TRAPS}" = "a" ]; then
		trap exittrap EXIT
		debug "Established trap handler.\n"
	fi
	if ! strinstr "$1" "${TRAPS}" " "; then
		TRAPS="$1 ${TRAPS}"
		debug "Traps are now: %s\n" "${TRAPS}"
	else
		debug "Trap %s already registered.\n" "${1}"
	fi
}

translate_load() {
	unset translatebase
	! find_binary "printf" && return 1
	! find_binary "grep" && return 1
	! find_binary "head" && return 1
	! find_binary "tail" && return 1
	! find_binary "sed" && return 1
	! find_binary "cat" && return 1
	! find_binary "cut" && return 1
	! find_binary "tr" && return 1
	if [ "a${notranslate}" != "a" ]; then
		export notranslate=yes; unset foldwrapping; need_arg "foldwrapping"
		return 1
	fi
	if [ "a${TRANSLATION}" != "a" ] && [ -f "${TRANSLATION}" ]; then
		debug "Requested to use file %s for translations.\n" "${TRANSLATION}"
		translatebase=`${catbin} "${TRANSLATION}" 2> /dev/null`
	elif [ "a${PROVIDER}" != "a" ] && [ -x "${PROVIDER}" ]; then
		translatelocale="${LC_MESSAGES}"
		[ "a${translatelocale}" = "a" ] && translatelocale="${LC_ALL}"
		[ "a${translatelocale}" = "a" ] && translatelocale="${LOCALE}"
		[ "a${translatelocale}" = "a" ] && translatelocale="${LANG}"
		if [ "a${translatelocale}" = "a" ]; then
			debug "No locale reported by system. Will not be using translations.\n"
			export notranslate=yes; unset foldwrapping; need_arg "foldwrapping"
			return 1
		fi
		debug "Locale %s found in environment.\n" "${translatelocale}"
		translatelocale=`echo ${translatelocale} | ${grepbin} -i "UTF\(.*\)8"`
		if [ "a${translatelocale}" = "a" ]; then
			debug "Reported locale is not UTF-8. Will not be using translations.\n"
			export notranslate=yes; unset foldwrapping; need_arg "foldwrapping"
			return 1
		fi
		translatelocale=`echo ${translatelocale} | ${cutbin} -d. -f1 | ${sedbin} -e "s/$/.UTF-8/g"`
		debug "Will attempt to get translation file from package: %s.\n" "messages/${translatelocale}"
		translatebase=`${PROVIDER} getfile "messages/${translatelocale}" 2> /dev/null`
	else
		debug "Unable to retrieve any translation file. Will not be using translations.\n"
		export notranslate=yes; unset foldwrapping; need_arg "foldwrapping"
		return 1
	fi
	helperfactor=`echo "${translatebase}" 2> /dev/null | ${headbin} -1 | ${grepbin} "^##\([0-9]\)$" | ${sedbin} -e "s/^##//g"`
	[ "a${helperfactor}" = "a" ] && helperfactor=1
	unset foldwrapping; need_arg "foldwrapping";
	foldwrapping=`expr ${foldwrapping} \* ${helperfactor} 2> /dev/null`; foldwrapping=`echo ${foldwrapping}`
	[ "a${foldwrapping}" = "a" ] && unset foldwrapping
	need_arg "foldwrapping"; unset helperfactor
	translatebase=`${printfbin} "%s" "${translatebase}" | ${grepbin} -v "^#"`
	if [ "a${translatebase}" = "a" ]; then
		debug "No translations retrieved from file. Will not be using translations.\n"
		export notranslate=yes; unset foldwrapping; need_arg "foldwrapping"
		return 1
	fi
	export foldwrapping
	debug "Translations loaded. Wrapping at %d bytes.\n" "${foldwrapping}"
	return 0
}

# Translates argument to locale
translate_text() {
	if [ "a${notranslate}" != "a" ]; then
		${printfbin} "%s" "$1"
		return 0
	fi
	[ "a${translatebase}" = "a" ] && translate_load
	if [ "a${notranslate}" != "a" -o "a${translatebase}" = "a" ]; then
		${printfbin} "%s" "$1"
		return 0
	fi
	# Safer, still slower way to translate
	#texttomatch=`${printfbin} "%s" "$1" | ${trbin} "\\n" ".." | ${trbin} "\n" "." | ${trbin} "\t" "." | ${trbin} "\\\\\\\" "." | ${sedbin} -e "s/\\\\\\/\./g" | ${sedbin} -e "s/\"/\./g"`
	texttomatch=`${printfbin} "%s" "$1" | ${trbin} "\\\\\\\" "." | ${trbin} "\\\\\"" "." | ${trbin} "\n" "."`
# Comment below is to help gedit in colouring text
# `"`
	if [ -n "${showtext}" ]; then
		debug "Text to check: %s\n" "${1}"
		debug "Text to match: %s\n" "${texttomatch}"
	fi
	texttranslated=`${printfbin} "%s" "${translatebase}" | ${grepbin} -A 1 -G "^.${texttomatch}.$" | ${headbin} -2 | ${tailbin} -1 | ${sedbin} -e "s/^\"\(.*\)\"$/\1/g"`
	unset texttomatch
	if [ "a${texttranslated}" != "a" -a "a${texttranslated}" != "a\"" ]; then
		[ -n "${showtext}" ] && debug "Text returned: %s\n" "${texttranslated}"
		${printfbin} "%s" "${texttranslated}"
	else
		[ -n "${showtext}" ] && debug "No translation found, returning original text: %s\n" "$1"
		${printfbin} "%s" "$1"
	fi
	unset texttranslated
	return 0
}

# Safety helper
safe_invoke() {
	if [ "a${NOFUNCNAME}" != "a" ]; then
		debug "FIXME: Called %s without FUNCNAME variables available.\n" "$0"
		return 99
	fi
	if [ "a${FUNCNAME[1]}" = "a" ]; then
		debug "FIXME: %s called without FUNCNAME[1] being available.\n"
		return 99
	fi
	debug "Function %s requested to call it in a safe manner.\n" "${FUNCNAME[1]}"
	callertimeout="$1"; callertimeout=`expr ${callertimeout} + 1 - 1 2> /dev/null`
	if [ "a${callertimeout}" = "a$1" ]; then
		debug "Timeout set by %s to %d seconds.\n" "${FUNCNAME[1]}" "${callertimeout}"
		shift
	else
		callertimeout=5
		debug "Caller did not provide timeout. Using default (%d seconds).\n" "${callertimeout}"
	fi
	if [ "a${safetimeout}" != "a" ]; then
		unset callertimeout
		debug "FIXME: However, we are already within a safe session.\n"
		${FUNCNAME[1]} "safe" "$@"
		ret=$?
		debug "FIXME: Function %s returned from within a nested safe session.\n" "${FUNCNAME[1]}"
		return ${ret}
	elif [ "a${nosafety}" != "a" ]; then
		unset callertimeout
		debug "However, config instructs not to use safety-checks.\n"
		${FUNCNAME[1]} "safe" "$@"
		ret=$?
		unset TIMEOUTOCCURED
		debug "Unsafe function %s returned.\n" "${FUNCNAME[1]}"
		return ${ret}
	fi
	safetimeout="${callertimeout}"
	callermethod="${FUNCNAME[1]}"
	unset TIMEOUTOCCURED; unset callertimeout
	if find_binary "mktemp"; then
		debug "Using %s to store standard output and error of %s.\n" "${mktempbin}" "${callermethod}"
		outputholder=`${mktempbin} -p /tmp -q sakis3g.safe.output.$$.XXXXXXXX`
		errorholder=`${mktempbin} -p /tmp -q sakis3g.safe.error.$$.XXXXXXXX`
	fi
	if [ "a${outputholder}" = "a" ]; then
		debug "Using backup method for creating temporary output holder.\n"
		outputholder="/tmp/sakis3g.unsafe.output.$$"
	fi
	if [ "a${errorholder}" = "a" ]; then
		debug "Using backup method for creating temporary output holder.\n"
		errorholder="/tmp/sakis3g.unsafe.error.$$"
	fi
	debug "Will store output at: %s\n" "${outputholder}"
	debug "Will store error at: %s\n" "${errorholder}"
	debug "Initiating safe session for %s (%d seconds timeout).\n" "${callermethod}" "${safetimeout}"
	"${callermethod}" "safe" "$@" > "${outputholder}" 2> "${errorholder}" &
	safecallerpid=$!; eval "disown -a" > /dev/null 2> /dev/null
	debug "Method spawned with PID %d.\n" "${safecallerpid}"
	while ! notrunning "${safecallerpid}"
	do
		debug "%s still runs. %d seconds before killing.\n" "${callermethod}" "${safetimeout}"
		if [ "a${safetimeout}" = "a0" ]; then
			debug "Time expired with no results.\n"
			if find_binary "kill"; then
				debug "Will attempt to kill process with PID %d.\n" "${safecallerpid}"
				! notrunning "${safecallerpid}" && debug run_command "${killbin} -1 ${safecallerpid}"
				! notrunning "${safecallerpid}" && debug run_command "${killbin} -9 ${safecallerpid}"
				! notrunning "${safecallerpid}" && debug "Failed to kill it.\n"
			fi
			if find_binary "rm"; then
				debug "Will attempt to unlink temporary holders.\n"
				debug run_command "${rmbin} -f \"${outputholder}\" \"${errorholder}\""
			fi
			export TIMEOUTOCCURED="${callermethod}"
			unset callermethod; unset safecallerpid; unset outputholder; unset errorholder
			debug "Method %s failed to respond within timeout.\n"
			unset safetimeout
			return 99
		fi
		safetimeout=`expr ${safetimeout} - 1`; safetimeout=`echo ${safetimeout}`
		sleep 1
	done
	debug "Method returned while %d seconds were remaining.\n" "${safetimeout}"
	debug show_file "${outputholder}"
	debug show_file "${errorholder}"
	if find_binary "cat"; then
		debug "Will now route output and error to mine.\n"
		[ -f "${outputholder}" ] && ${catbin} "${outputholder}" 2> /dev/null
		[ -f "${errorholder}" ] && ${catbin} "${errorholder}" >> /dev/stderr 2> /dev/null
	fi
	if find_binary "rm"; then
		debug "Will attempt to unlink temporary holders.\n"
		debug run_command "${rmbin} -f \"${outputholder}\" \"${errorholder}\""
	fi
	debug "Method %s responded within timeout specified.\n" "${FUNCNAME[1]}"
	unset callermethod; unset safecallerpid; unset outputholder; unset errorholder
	unset safetimeout
	debug "Left safe mode.\n"
	return 0
}

safe_lsusb() {
	if [ "a$1" != "asafe" -a "a${NOFUNCNAME}" = "a" ]; then
		safe_invoke "5" "$@"
		return $?
	elif [ "a${NOFUNCNAME}" = "a" ]; then
		shift
	fi
	[ "a${lsusbbin}" != "a" ] && ${lsusbbin} "$@"
}

safe_chat() {
	if [ "a$1" != "asafe" -a "a${NOFUNCNAME}" = "a" ]; then
		safe_invoke "10" "$@"
		return $?
	elif [ "a${NOFUNCNAME}" = "a" ]; then
		shift
	fi
	[ "a${chatbin}" != "a" ] && ${chatbin} "$@"
}

safe_cat() {
	if [ "a$1" != "asafe" -a "a${NOFUNCNAME}" = "a" ]; then
		safe_invoke "5" "$@"
		return $?
	elif [ "a${NOFUNCNAME}" = "a" ]; then
		shift
	fi
	[ "a${catbin}" != "a" ] && ${catbin} "$@"
}

# Formats text
format_text() {
	if find_binary "printf"; then
		rfmt="$1"
		[ "$#" -gt "0" ] && shift
		rfmt=`translate_text "${rfmt}"`
		if [ "$#" -ge "1" ]; then
			${printfbin} "${rfmt}" "${@}"
		else
			${printfbin} "${rfmt}"
		fi
		unset rfmt
	else
		echo "${@}"
	fi
}

# Clears terminal line if required
term_clearline() {
	[ "a${COLUMNS}" != "a" ] && find_binary "printf" && [ -n "${interactive}" ] && ${printfbin} "\r%.-${COLUMNS}s\r" "" && return 0
	[ "a${COLUMNS}" = "a" ] && find_binary "printf" && [ -n "${interactive}" ] && ${printfbin} "\r%s\r" "                                          " && return 0
}

# Prints argument to terminal
term_print() {
	term_clearline
	echo "${@}"
}

# Sends error to terminal, colored if possible.
term_error() {
	if find_binary "grep" && [ -n "${interactive}" ]; then
		term_print "$@" | ${grepbin} --color "."
	else
		term_print "$@"
	fi
}

term_verbose() {
	if [ -n "${interactive}" ]; then
		if find_binary "grep" && find_binary "tr"; then
			currentlyverbosing=yes
			term_print "$@" | GREP_COLOR=2 ${grepbin} --color=always "." | ${trbin} "\n" " "
			unset currentlyverbosing; lastlineverbose=yes
		else
			term_print "$@"
		fi
	fi
}

term_notify() {
	if find_binary "grep" && [ -n "${interactive}" ]; then
		term_print "$@" | GREP_COLOR=1 ${grepbin} --color "."
	else
		term_print "$@"
	fi
}

select_example() {
	examplevariable=`selection_argument variable "$@"`
	exampleoptions=`selection_argument options "$@"`
	[ "a${exampleoptions}" != "a" ] && format_text "\nAvailable options are:\n" && format_text "%s\n" "${exampleoptions}"
	[ "a${exampleoptions}" = "a" ] && exampleoptions="foo"
	format_text "\nExample:\n"
	format_text "\t$ %s [...] %s=\"%s\"\n\r\n" "${ME}" "${examplevariable}" "`echo ${exampleoptions} | ${cutbin} -d\  -f1`"
	unset exampletitle; unset examplevariable; unset exampleoptions
}

term_select_example() {
	examplevariable=`selection_argument variable "$@"`
	exampleoptions=`selection_argument options "$@"`
	[ "a${exampleoptions}" != "a" ] && notify "\nAvailable options are:\n" && notify "%s\n" "${exampleoptions}"
	[ "a${exampleoptions}" = "a" ] && exampleoptions="foo"
	notify "\nExample:\n"
	notify "\t$ %s %s=\"%s\"\n\r\n" "${ME}" "${examplevariable}" "`echo ${exampleoptions} | ${cutbin} -d\  -f1`"
	unset exampletitle; unset examplevariable; unset exampleoptions
}

term_select() {
	options=`selection_argument options "$@" | ${wcbin} -l`; options=`echo ${options}`
	variable=`selection_argument variable "$@"`
	if [ "a${options}" != "a1" ]; then
		exampletitle=`selection_argument title "$@"`
		notify "%s by using %s variable, or by enabling interactive mode.\n" "${exampletitle}" "${variable}"
		notify "\t$ %s --interactive %s\n" "${ME}" "${allargs}"
		unset exampletitle
		term_select_example "$@"
	else
		eval export ${variable}="`selection_argument option 1 "$@"`"
		debug "Returning sole available option \"%s\" on behalf of user.\n" "`eval echo \\\${${variable}}`"
		unset variable
		return 1
	fi
	unset variable; unset options
	stop_with 98
	return 98
}

term_confirm() {
	options=`selection_argument options "$@" | ${wcbin} -l`; options=`echo ${options}`
	variable=`selection_argument variable "$@"`
	exampletitle=`selection_argument title "$@"`
	notify "%s by using --%syes or --%sno switches, or by enabling interactive mode.\n" "${exampletitle}" "${variable}" "${variable}"
	notify "\t$ %s --interactive %s\n" "${ME}" "${allargs}"
	unset exampletitle
	stop_with 98
	return 98
}

term_prompt() {
	variable=`selection_argument variable "$@"`
	exampletitle=`selection_argument title "$@"`
	notify "%s by using %s variable, or by enabling interactive mode.\n" "${exampletitle}" "${variable}"
	notify "\t$ %s --interactive %s\n" "${ME}" "${allargs}"
	unset exampletitle
	term_select_example "$@"
	return 98
}

interactive_term_select() {
	variable=`selection_argument variable "$@"`
	title=`selection_argument title "$@"`
	text=`selection_argument text "$@"`
	options=`selection_argument options "$@" | ${wcbin} -l` ; options=`echo ${options}`
	debug "Prompting user to select variable %s.\n" "${variable}"
	[ "a${title}" != "a" ] && notify "%s\n\r\n" "${title}"
	[ "a${text}" != "a" ] && ${printfbin} "%s\n\r\n" "${text}"
	notify "Available options are:\n"
	selection_argument options "$@" | ${grepbin} -n "." | ${sedbin} -e "s/^\([0-9]*\):\(.*\)	\(.*\)/\1. \3/g" | GREP_COLOR=1 ${grepbin} --color=AUTO "\([0-9]*\)\."
	selection_argument button2 "$@" | ${grepbin} -n "." | ${sedbin} -e "s/^\([0-9]*\):\(.*\)/0. \2/g" | GREP_COLOR=1 ${grepbin} --color=AUTO "\([0-9]*\)\."
	format_text "You can automate this selection by setting %s variable.\nEnter \"*\" to discover how.\n" "${variable}" | GREP_COLOR=2 ${grepbin} --color=ALWAYS "."
	notify "\r\n"
	echo -n "`format_text "Please use numbers %d-%d to perform your selection: " "0" "${options}"`"
	read termselection
	debug "User typed: \"%s\"\n" "${termselection}"
	if [ "a${termselection}" = "a*" ]; then
		debug "Showing select example through variable %s.\n" "${variable}"
		term_select_example "$@"
		interactive_term_select "$@"
		selection=$?
	else
		selection=`${printfbin} "%d\n" "${termselection}" 2> /dev/null`
		[ "${selection}" -gt "${options}" ] && selection=0
		[ "${selection}" -eq "0" ] && selection=98
		[ "${selection}" -gt "0" -a "${selection}" -le "${options}" ] && eval export ${variable}="`selection_argument option ${selection} "$@"`"
	fi
	debug "Considering selection: %d\n" "${selection}"
	unset variable; unset title; unset text; unset options; unset termselection
	[ "a${DEBUG}" = "a" ] && find_binary "clear" && ${clearbin}
	return "${selection}"
}

interactive_term_confirm() {
	variable=`selection_argument variable "$@"`
	title=`selection_argument title "$@"`
	text=`selection_argument text "$@"`
	debug "Prompting user to select variable %s.\n" "${variable}"
	[ "a${title}" != "a" ] && notify "%s\n\r\n" "${title}"
	[ "a${text}" != "a" ] && ${printfbin} "%s\n\r\n" "${text}"
	notify "Available options are:\n"
	selection_argument button1 "$@" | ${sedbin} -e "s/^\(.*\)$/1. \1/g" | GREP_COLOR=1 ${grepbin} --color=AUTO "^\([0-9]*\)\."
	selection_argument button2 "$@" | ${sedbin} -e "s/^\(.*\)$/2. \1/g" | GREP_COLOR=1 ${grepbin} --color=AUTO "^\([0-9]*\)\."
	[ "a$6" != "areset" ] && format_text "You can automate this selection by setting --%syes or --%sno switches.\n" "${variable}" "${variable}" | GREP_COLOR=2 ${grepbin} --color=ALWAYS "."
	notify "\r\n"
	echo -n "`format_text "Please use numbers %d-%d to perform your selection: " "1" "2"`"
	read termselection
	debug "User typed: \"%s\"\n" "${termselection}"
	if [ "a${termselection}" = "a1" ]; then
		debug "User selected \"yes\".\n"
		selection=0
	elif [ "a${termselection}" = "a2" ]; then
		debug "User selected \"no\".\n"
		selection=1
	else
		interactive_term_confirm "$@"
		selection=$?
		return ${selection}
	fi
	unset variable; unset title; unset text; unset options; unset termselection
	[ "a${DEBUG}" = "a" ] && find_binary "clear" && ${clearbin}
	return "${selection}"
}

interactive_term_prompt() {
	variable=`selection_argument variable "$@"`
	title=`selection_argument title "$@"`
	text=`selection_argument text "$@"`
	debug "Prompting user to type variable %s.\n" "${variable}"
	[ "a${title}" != "a" ] && notify "%s\n" "${title}"
	format_text "You can automate this selection by setting %s variable.\nEnter \"*\" to discover how.\n" "${variable}" | GREP_COLOR=2 ${grepbin} --color=ALWAYS "."
	notify "\r\n"
	[ "a${text}" != "a" ] && ${printfbin} "%s: " "${text}"
	read termselection
	termselection=`sanitize "${termselection}"`
	termselection=`echo "${termselection}" | ${sedbin} -e "s/^ *//g" | ${sedbin} -e "s/ *$//g"`
	debug "User typed: \"%s\"\n" "${termselection}"
	if [ "a${termselection}" = "a*" ]; then
		debug "Showing select example through variable %s.\n" "${variable}"
		term_select_example "$@"
		interactive_term_prompt "$@"
		selection=$?
	elif [ "a${termselection}" = "a" ]; then
		debug "User pressed enter which indicates to abort.\n"
		selection=98
	else
		eval "export ${variable}=\"${termselection}\""
		selection=0
	fi
	debug "Considering selection: %d\n" "${selection}"
	unset variable; unset title; unset text; unset termselection
	[ "a${DEBUG}" = "a" ] && find_binary "clear" && ${clearbin}
	return "${selection}"
}

nine_verbose() {
	term_verbose "$@"
}

nine_fixcolors() {
	status_connected
	[ "a${NINEISP}" != "a${ISPID}" -o "a${ISPID}" = "a" ] && unset NINEBGCOLOR && unset NINEFGCOLOR
	[ "a${NINEFGCOLOR}" = "a" ] && NINEFGCOLOR=`echo ${ISP_FGCOLOR} | ${sedbin} -e "s/^\(..\)\(..\)\(..\)$/rgb:\1\/\2\/\3/g"`
	[ "a${NINEBGCOLOR}" = "a" ] && NINEBGCOLOR=`echo ${ISP_BGCOLOR} | ${sedbin} -e "s/^\(..\)\(..\)\(..\)$/rgb:\1\/\2\/\3/g"`
	[ "a${ISPID}" = "a" ] && unset NINEBGCOLOR && unset NINEFGCOLOR
	[ "a${NINEFGCOLOR}" = "a" ] && NINEFGCOLOR="rgb:00/00/00"
	[ "a${NINEBGCOLOR}" = "a" ] && NINEBGCOLOR="rgb:ec/ec/ec"
	[ "a${NINEISP}" = "a" ] && NINEISP="${ISPID}"
	export NINEISP; export NINEFGCOLOR; export NINEBGCOLOR
}

nine_notify() {
	unset nineerrormode
	! find_binary "9menu" && return 1
	if [ "a${1}" = "aerror" ]; then
		nineerrormode=1
		shift
		debug "Going into error mode.\n"
	else
		debug "Normal notification.\n"
	fi
	ninetext=`echo "$@" | ${sedbin} -e "s/:/;/g"`
	need_arg "MENUFONT"
	need_arg "foldwrapping"
	if find_binary "fold"; then
		ninetext=`echo "${ninetext}" | ${foldbin} -s -w ${foldwrapping}`
	else
		ninetext=`echo "${ninetext}" | ${sedbin} -e "s/^\(............................................................\)\(.*\)$/\1\\n\2/g"`
	fi
	ninetext=`echo "${ninetext}" | ${sedbin} -e "s/^\(.*\)$/\"\1:\"/g" | ${trbin} "	" " " | ${trbin} "\n" " "`
	debug "Displaying text to user through 9menu:%s\n" " $@ "
	debug "Displaying text to user through 9menu:%s\n" " ${ninetext} "
	if [ "a${nineerrormode}" = "a1" ]; then
		result=`eval "${ninemenubin} -font \"${MENUFONT}\" -bg \"rgb:ff/80/80\" -fg white -display \"${DISPLAY}\" -label \"\`translate_text "Error"\`\" ${ninetext} \":\" \"OK:exec echo OK-\"" 2> /dev/null | ${grepbin} "^OK-" | ${cutbin} -d- -f1`
	else
		nine_fixcolors
		result=`eval "${ninemenubin} -font \"${MENUFONT}\" -bg ${NINEBGCOLOR} -fg ${NINEFGCOLOR} -display \"${DISPLAY}\" -label \"\`translate_text "Notification"\`\" ${ninetext} \":\" \"OK:exec echo OK-\"" 2> /dev/null | ${grepbin} "^OK-" | ${cutbin} -d- -f1`
	fi
	if [ "a${result}" = "aOK" ]; then
		debug "User saw message.\n"
	else
		debug "9menu died or user closed it.\n"
	fi
	unset ninetext; unset result; unset nineerrormode
}

nine_error() {
	nine_notify "error" "$@"
}

nine_select() {
	! find_binary "9menu" && return 1
	nine_fixcolors
	need_arg "MENUFONT"
	need_arg "foldwrapping"
	debug "Prompting user to select variable %s with 9menu.\n" "${variable}"
	variable=`selection_argument variable "$@"`
	title=`selection_argument title "$@"`
	text=`selection_argument text "$@"`
	options=`selection_argument options "$@" | ${wcbin} -l` ; options=`echo ${options}`
	helptext=`format_text "You can automate this selection by setting %s variable on command line, click here to discover how.\n" "${variable}" | ${sedbin} -e "s/:/;/g"`
	localbutton2=`selection_argument button2 "$@"`; [ "a${localbutton2}" = "a" ] && localbutton2="Cancel"
	ninetext=`echo "${text}" | ${sedbin} -e "s/:/;/g"`
	if find_binary "fold"; then
		ninetext=`echo "${ninetext}" | ${foldbin} -s -w ${foldwrapping}`
		helptext=`echo "${helptext}" | ${foldbin} -s -w ${foldwrapping}`
	else
		ninetext=`echo "${ninetext}" | ${sedbin} -e "s/^\(............................................................\)\(.*\)$/\1\\n\2/g"`
		helptext=`echo "${helptext}" | ${sedbin} -e "s/^\(............................................................\)\(.*\)$/\1\\n\2/g"`
	fi
	ninetext=`echo "${ninetext}" | ${sedbin} -e "s/^\(.*\)$/\"\1:\"/g" | ${trbin} "	" " " | ${trbin} "\n" " "`
	helptext=`echo "${helptext}" | ${sedbin} -e "s/^\(.*\)$/\"\1:exec echo OPTION-AUTOMATE\"/g" | ${trbin} "	" " " | ${trbin} "\n" " "`
	localarguments=`selection_argument options "$@" | ${sedbin} -e "s/:/;/g" | ${grepbin} -n "." | ${sedbin} -e "s/^\([0-9]*\):\(.*\)	\(.*\)$/\"\1. \3:exec echo OPTION-\1\"/g" | ${trbin} "\n" " "`
	termselection=`eval "${ninemenubin} -font \"${MENUFONT}\" -bg ${NINEBGCOLOR} -fg ${NINEFGCOLOR} -display \"${DISPLAY}\" -label \"${title}\" ${ninetext} \":\" ${localarguments} \":\" ${helptext} \":\" \"${localbutton2}:exec echo OPTION-9menuexit\"" 2> /dev/null | ${grepbin} "^OPTION-" | ${cutbin} -d- -f2-`
	debug "User selected: \"%s\"\n" "${termselection}"
	if [ "a${termselection}" = "aAUTOMATE" ]; then
		localtext=`format_text "You can automate this selection by setting %s variable on command line.\n" "${variable}"`
		notify "${localtext}\n`select_example "$@"`"
		nine_select "$@"
		selection=$?
		return ${selection}
	elif [ "a${termselection}" = "a9menuexit" -o "a${termselection}" = "a" ]; then
		debug "User selected button: %s\n" "${localbutton2}"
		selection=98
	else
		termselection=`echo "${termselection}" | ${trbin} -t "." ""`
		selection=`${printfbin} "%d\n" "${termselection}" 2> /dev/null`
		[ "${selection}" -gt "${options}" ] && selection=0
		[ "${selection}" -eq "0" ] && selection=98
		[ "${selection}" -gt "0" -a "${selection}" -le "${options}" ] && eval export ${variable}="`selection_argument option ${selection} "$@"`"
	fi
	debug "Considering selection: %d\n" "${selection}"
	unset variable; unset title; unset text; unset ninetext; unset helptext; unset options; unset termselection; unset buttonselection; unset localtext; unset localarguments; unset localbutton2
	return "${selection}"
}

nine_confirm() {
	! find_binary "9menu" && return 1
	nine_fixcolors
	need_arg "MENUFONT"
	need_arg "foldwrapping"
	variable=`selection_argument variable "$@"`
	title=`selection_argument title "$@"`
	ninetext=`selection_argument text "$@" | ${sedbin} -e "s/:/;/g"`
	localbutton1=`selection_argument button1 "$@"`; [ "a${localbutton1}" = "a" ] && localbutton1="OK"
	localbutton2=`selection_argument button2 "$@"`; [ "a${localbutton2}" = "a" ] && localbutton2="Cancel"
	debug "Prompting user to confirm variable %s with 9menu.\n" "${variable}"
	helptext=""
	[ "a$6" != "areset" ] && helptext=`format_text "You can automate this selection by setting --%syes or --%sno switches.\n" "${variable}" "${variable}" | ${sedbin} -e "s/:/;/g"`
	if find_binary "fold"; then
		ninetext=`echo "${ninetext}" | ${foldbin} -s -w ${foldwrapping}`
		helptext=`echo "${helptext}" | ${foldbin} -s -w ${foldwrapping}`
	else
		ninetext=`echo "${ninetext}" | ${sedbin} -e "s/^\(............................................................\)\(.*\)$/\1\\n\2/g"`
		helptext=`echo "${helptext}" | ${sedbin} -e "s/^\(............................................................\)\(.*\)$/\1\\n\2/g"`
	fi
	ninetext=`echo "${ninetext}" | ${sedbin} -e "s/^\(.*\)$/\"\1:\"/g" | ${trbin} "	" " " | ${trbin} "\n" " "`
	helptext=`echo "${helptext}" | ${sedbin} -e "s/^\(.*\)$/\"\1:\"/g" | ${trbin} "	" " " | ${trbin} "\n" " "`
	localarguments="\"${localbutton1}:exec echo Answer-Yes\" \"${localbutton2}:exec echo Answer-No\""
	termselection=`eval "${ninemenubin} -font \"${MENUFONT}\" -bg ${NINEBGCOLOR} -fg ${NINEFGCOLOR} -display \"${DISPLAY}\" -label \"${title}\" ${ninetext} \":\" ${localarguments} \":\" ${helptext} \":\"" 2> /dev/null | ${grepbin} "^Answer-" | ${cutbin} -d- -f2-`
	debug "User selected: \"%s\"\n" "${termselection}"
	if [ "a${termselection}" = "aYes" ]; then
		selection=0
	else
		selection=1
	fi
	debug "Considering selection: %d\n" "${selection}"
	unset variable; unset title; unset text; unset ninetext; unset helptext; unset options; unset termselection; unset buttonselection; unset localtext; unset localarguments; unset localbutton2; unset localbutton1
	return "${selection}"
}

nine_prompt() {
	! find_binary "xterm" && return 1
	variable=`selection_argument variable "$@"`
	title=`selection_argument title "$@"`
	text=`selection_argument text "$@"`
	debug "Prompting user to type variable %s through xterm.\n" "${variable}"
	localtext=`format_text "You can automate this selection by setting %s variable.\n" "${variable}"` 
	[ "a${text}" != "a" ] && localtext=`${printfbin} "%s\n\n%s: " "${localtext}" "${text}"`
	locallines=`echo "${localtext}" | ${wcbin} -l`; locallines=`echo ${locallines}`; locallines=`expr ${locallines} + 10`; locallines=`echo ${locallines}`;
	${printfbin} "%s\n" "${localtext}" > "/tmp/sakis3g.xterm.pipe.$$"
	${xtermbin} -T "${title}" +cm +dc -e sh -c "${catbin} /tmp/sakis3g.xterm.pipe.$$; read XTERMANSWER; set >> /tmp/sakis3g.xterm.pipe.$$;" 2> /dev/null
	debug show_file "/tmp/sakis3g.xterm.pipe.$$"
	termselection=`${grepbin} "^XTERMANSWER=" "/tmp/sakis3g.xterm.pipe.$$" 2> /dev/null | ${cutbin} -d= -f2- | ${sedbin} -e "s/^\"\(.*\)\"$/\1/g" | ${sedbin} -e "s/^\'\(.*\)\'$/\1/g"`; ${rmbin} -f "/tmp/sakis3g.xterm.pipe.$$"
	termselection=`sanitize "${termselection}"`
	debug "User typed: \"%s\"\n" "${termselection}"
	# TODO: Implement example
	if [ "a${termselection}" != "a" ]; then
		debug "User typed: %s\n" "${termselection}"
		eval "export ${variable}=\"${termselection}\""
		selection=0
	elif [ "a${termselection}" = "a" ]; then
		debug "User requested to cancel.\n"
		selection=98
	else
		debug "Unknown error.\n"
		selection=99
	fi
	debug "Considering selection: %d\n" "${selection}"
	unset variable; unset title; unset text; unset termselection; unset buttonselection; unset localtext
	return "${selection}"
}

dialog_error() {
	dialog_cleanscreen
	if [ "a${SGUI}" = "adialog" ]; then
		! find_binary "dialog" && return 1
		${dialogbin} --backtitle "Sakis3G ${MYVERSION}" --colors --title "\Z1\Zb`translate_text "Error occured"`" --ok-label `translate_text "OK"` --clear --colors --aspect 30 --msgbox "\Z1\ZB$@" 0 0
	elif [ "a${SGUI}" = "aXdialog" ]; then
		! find_binary "Xdialog" && return 1
		${Xdialogbin} --backtitle `translate_text "Error occured"` --title "Sakis3G ${MYVERSION}" --ok-label `translate_text "OK"` --msgbox "$@ " 0 0
	elif [ "a${SGUI}" = "azenity" ]; then
		! find_binary "zenity" && return 1
		${zenitybin} --title "`translate_text "Error occured"`" --error --text "$@ "
	elif [ "a${SGUI}" = "akdialog" ]; then
		! find_binary "kdialog" && return 1
		${kdialogbin} --title "`translate_text "Error occured"`" --error "$@ " > /dev/null 2> /dev/null
	elif [ "a${SGUI}" = "awhiptail" ]; then
		! find_binary "whiptail" && return 1
		${whiptailbin} --backtitle "Sakis3G ${MYVERSION}" --title "`translate_text "Error occured"`" --clear --msgbox "$@ " 0 0
	fi
}

dialog_notify() {
	dialog_cleanscreen
	if [ "a${SGUI}" = "adialog" ]; then
		! find_binary "dialog" && return 1
		${dialogbin} --backtitle "Sakis3G ${MYVERSION}" --title `translate_text "Notification"` --ok-label `translate_text "OK"` --clear --aspect 30 --msgbox "$@" 0 0
	elif [ "a${SGUI}" = "aXdialog" ]; then
		! find_binary "Xdialog" && return 1
		${Xdialogbin} --title "Sakis3G ${MYVERSION}" --ok-label `translate_text "OK"` --msgbox "$@" 0 0
	elif [ "a${SGUI}" = "azenity" ]; then
		! find_binary "zenity" && return 1
		${zenitybin} --title "Sakis3G ${MYVERSION}" --info --text "$@ "
	elif [ "a${SGUI}" = "akdialog" ]; then
		! find_binary "kdialog" && return 1
		${kdialogbin} --title "Sakis3G ${MYVERSION}" --msgbox "$@ " > /dev/null 2> /dev/null
	elif [ "a${SGUI}" = "awhiptail" ]; then
		! find_binary "whiptail" && return 1
		${whiptailbin} --backtitle "Sakis3G ${MYVERSION}" --title `translate_text "Notification"` --clear --msgbox "$@" 0 0
	fi
}

dialog_cleanscreen() {
	if [ "a${SGUI}" = "aXdialog" ]; then
		if [ "a${XdialogVerbose}" != "a" -a "a${XdialogVerbose}" != "a0" ]; then
			! notrunning "${XdialogVerbose}" && find_binary "kill" && ${killbin} -1 "${XdialogVerbose}" 2> /dev/null
			unset XdialogVerbose
		fi
		unset currentlyverbosing
	elif [ "a${SGUI}" = "azenity" ]; then
		[ -f "/tmp/sakis3g.zenity.pipe" ] && ${printfbin} "\n100\n" >> "/tmp/sakis3g.zenity.pipe"
		[ -f "/tmp/sakis3g.zenity.pipe" ] && debug run_command "${rmbin} -f /tmp/sakis3g.zenity.pipe"
		[ "a${zenityverbosepid}" != "a" ] && ! notrunning "${zenityverbosepid}"	&& ${killbin} -1 "${zenityverbosepid}" 2> /dev/null
		[ "a${zenityverbosepid}" != "a" ] && ! notrunning "${zenityverbosepid}"	&& ${killbin} -9 "${zenityverbosepid}" 2> /dev/null
		unset zenityverbosepid
	elif [ "a${SGUI}" = "akdialog" ]; then
		! find_binary "kdialog" && return 1
		if [ "a${kdialogaddress}" != "a" ]; then
			dcopbased=`echo ${kdialogaddress} | ${grepbin} -i "dcop"`
			if [ "a${dcopbased}" != "a" ]; then
				if find_binary "dcop"; then
					debug run_command "${dcopbin} \"${kdialogaddress}\" close"
				fi
			else
				! find_binary "dbus-send" && find_binary "qdbus"
				if [ "a${dbus_sendbin}" != "a" ]; then
					debug run_command "${dbus_sendbin} --print-reply --dest=${kdialogaddress} \"org.kde.kdialog.ProgressDialog.close\""
				elif [ "a${qdbusbin}" != "a" ]; then
					debug run_command "${qdbusbin} ${kdialogaddress} \"org.kde.kdialog.ProgressDialog.close\""
				fi
			fi
		else
			term_clearline
		fi
		unset kdialogaddress
	fi
}

dialog_verbose() {
	if [ "a${SGUI}" = "adialog" ]; then
		! find_binary "dialog" && return 1
		verbwidth=`echo "${COLUMNS}"`; verbwidth=`expr ${verbwidth} + 1 - 1`; verbwidth=`echo ${verbwidth}`
		verbheight=0; [ "${verbwidth}" -gt "40" ] && verbheight=3
		currentlyverbosing=yes
		${dialogbin} --backtitle "Sakis3G ${MYVERSION}" --title "Working" --aspect 40 --infobox "$@..." ${verbheight} ${verbwidth}
		unset currentlyverbosing; lastlineverbose=yes; unset verbwidth; unset verbheight
	elif [ "a${SGUI}" = "aXdialog" ]; then
#		! find_binary "Xdialog" && return 1
#		${Xdialogbin} --title "Sakis3G is working" --infobox "$@..." 0 0 30000 &
#		XdialogVerbose=$!; currentlyverbosing=yes
		term_verbose "$@"
	elif [ "a${SGUI}" = "akdialog" ]; then
		! find_binary "kdialog" && return 1
		if ! find_binary "dbus-send" && ! find_binary "qdbus"; then
			term_verbose "$@"; return 0
		fi
		if [ "a${kdialogaddress}" = "a" ]; then
			temptext=`translate_text Working...`
			kdialogaddress=`${kdialogbin} --title "Sakis3G ${MYVERSION}" --progressbar "${temptext}" 100`
#			kdialogaddress=`${kdialogbin} --title "Sakis3G ${MYVERSION}" --progressbar "${temptext}" 100 2> /dev/null`
			debug "Returned 1\n"
			unset temptext
			[ "a${kdialogaddress}" != "a" ] && export kdialogaddress
		fi
			debug "Returned 2\n"
		if [ "a${kdialogaddress}" != "a" ]; then
			dcopbased=`echo ${kdialogaddress} | ${grepbin} -i "dcop"`
			if [ "a${dcopbased}" != "a" ]; then
				if find_binary "dcop"; then
					debug run_command "${dcopbin} --user \"${runner}\" --all-sessions \"${kdialogaddress}\" setProgress ${verbosecurrentcount}"
					debug run_command "${dcopbin} --user \"${runner}\" --all-sessions \"${kdialogaddress}\" setLabel \"$@\""
				fi
			else
				if [ "a${kdialogaddress}" != "a" ] && [ "a${dbus_sendbin}" != "a" ]; then
					debug run_command "${dbus_sendbin} --print-reply --dest=${kdialogaddress} \"org.freedesktop.DBus.Properties.Set\" string:'org.kde.kdialog.ProgressDialog' string:'value' variant:int32:${verbosecurrentcount}"
					debug run_command "${dbus_sendbin} --print-reply --dest=${kdialogaddress} \"org.kde.kdialog.ProgressDialog.setLabelText\" \"string:$@\""
				elif [ "a${kdialogaddress}" != "a" ] && [ "a${qdbusbin}" != "a" ]; then
					debug run_command "qdbus ${kdialogaddress} \"org.kde.kdialog.ProgressDialog.setLabelText\" \"$@\""
					debug run_command "qdbus ${kdialogaddress} \"org.freedesktop.DBus.Properties.Set\" \"\" \"value\" \"${verbosecurrentcount}\""
				fi
			fi
		else
			term_verbose "$@"
		fi
	elif [ "a${SGUI}" = "azenity" ]; then
		! find_binary "zenity" && return 1
		[ "a${zenityverbosepid}" != "a" ] && notrunning "${zenityverbosepid}" && unset zenityverbosepid
		[ ! -f "/tmp/sakis3g.zenity.pipe" ] && unset zenityverbosepid
		if [ "a${zenityverbosepid}" = "a" ] && find_binary "rm" && find_binary "tail" && find_binary "kill" && find_binary "printf" && find_binary "touch" && find_binary "chmod" && find_binary "setsid"; then
			debug "Establishing zenity verbose helper.\n"
			[ -f "/tmp/sakis3g.zenity.pipe" ] && ${printfbin} "\n100\n" >> "/tmp/sakis3g.zenity.pipe"
			[ -f "/tmp/sakis3g.zenity.pipe" ] && debug run_command "${rmbin} -f /tmp/sakis3g.zenity.pipe"
			debug run_command "${touchbin} /tmp/sakis3g.zenity.pipe"
			debug run_command "${chmodbin} 666 /tmp/sakis3g.zenity.pipe"
			if [ -f "/tmp/sakis3g.zenity.pipe" ]; then
				eval ${tailbin} -f "/tmp/sakis3g.zenity.pipe" "2> /dev/null" | ${zenitybin} --title="Sakis3G ${MYVERSION}" --text="`translate_text Working...`" --progress --percentage=0 --auto-close --auto-kill "> /dev/null 2> /dev/null" &
				zenityverbosepid=$!
				eval "disown -a" > /dev/null 2> /dev/null
				export zenityverbosepid
			fi
		fi
		[ "a${zenityverbosepid}" != "a" ] && notrunning "${zenityverbosepid}" && unset zenityverbosepid 
		[ "a${zenityverbosepid}" = "a" ] && term_verbose "$@" && return 1
		${printfbin} "\n%d\n# $@...\n\n" "${verbosecurrentcount}" >> "/tmp/sakis3g.zenity.pipe"
	elif [ "a${SGUI}" = "awhiptail" ]; then
		term_verbose "$@"
	fi
}

dialog_confirm() {
	dialog_cleanscreen
	if [ "a${SGUI}" = "adialog" ]; then
		! find_binary "dialog" && return 1
	elif [ "a${SGUI}" = "aXdialog" ]; then
		! find_binary "Xdialog" && return 1
	elif [ "a${SGUI}" = "azenity" ]; then
		! find_binary "zenity" && return 1
	elif [ "a${SGUI}" = "akdialog" ]; then
		! find_binary "kdialog" && return 1
	elif [ "a${SGUI}" = "awhiptail" ]; then
		! find_binary "whiptail" && return 1
	fi
	variable=`selection_argument variable "$@"`
	title=`selection_argument title "$@"`
	text=`selection_argument text "$@"`
	debug "Prompting user to select yes%s or no%s.\n" "${variable}" "${variable}"
	localtext=""
	[ "a$6" != "areset" ] && localtext=`format_text "You can automate this selection by setting --%syes or --%sno switches.\n" "${variable}" "${variable}"`
	if [ "a${SGUI}" = "adialog" ]; then
		[ "a${text}" != "a" ] && localtext=`${printfbin} "%s\\\\\\n\\\\\\n%s\n" "${text}" "${localtext}"`
		${dialogbin} --backtitle "Sakis3G ${MYVERSION}" --title " ${title} " --clear --cr-wrap --yesno "${localtext}" 0 0 2> /dev/null
		buttonselection=$?
	elif [ "a${SGUI}" = "aXdialog" ]; then
		[ "a${text}" != "a" ] && localtext=`${printfbin} "%s\\\\\\n\\\\\\n%s\n" "${text}" "${localtext}"`
		${Xdialogbin} --backtitle " ${title} " --title "Sakis3G ${MYVERSION}" --wrap --fill --yesno "${localtext}" 0 0 2> /dev/null
		buttonselection=$?
	elif [ "a${SGUI}" = "akdialog" ]; then
		[ "a${text}" != "a" ] && localtext=`${printfbin} "%s\\\\\\n\\\\\\n%s\n" "${text}" "${localtext}"`
		${kdialogbin} --title " ${title} " --yesno "${text}" 2> /dev/null
		buttonselection=$?
	elif [ "a${SGUI}" = "azenity" ]; then
		need_arg "foldwrapping"
		text=`echo "${text}" | ${sedbin} -e "s/_/__/g"`
		localtext=`echo "${localtext}" | ${sedbin} -e "s/_/__/g"`
#		if find_binary "fold"; then
#			localtext=`echo "${localtext}" | ${foldbin} -s -w ${foldwrapping}`
#			text=`echo "${text}" | ${foldbin} -s -w ${foldwrapping}`
#		fi
		[ "a${text}" != "a" ] && localtext=`${printfbin} "%s\\\\\\n\\\\\\n%s\n" "${text}" "${localtext}"`
		${zenitybin} --title " ${title} " --question --text "${localtext}" 2> /dev/null
		buttonselection=$?
	elif [ "a${SGUI}" = "awhiptail" ]; then
		[ "a${text}" != "a" ] && localtext=`${printfbin} "%s\\\\\\n\\\\\\n%s\n" "${text}" "${localtext}"`
		${whiptailbin} --backtitle "Sakis3G ${MYVERSION}" --title " ${title} " --clear --yesno "${localtext}" 0 0 2> /dev/null
		buttonselection=$?;
	fi
	if [ "a${buttonselection}" = "a0" ]; then
		debug "User selected \"yes\" (%d).\n" "${buttonselection}"
		return 0
	else
		debug "User selected \"no\" (%d).\n" "${buttonselection}"
		return 1
	fi
}

dialog_select() {
	dialog_cleanscreen
	if [ "a${SGUI}" = "adialog" ]; then
		! find_binary "dialog" && return 1
	elif [ "a${SGUI}" = "aXdialog" ]; then
		! find_binary "Xdialog" && return 1
	elif [ "a${SGUI}" = "azenity" ]; then
		! find_binary "zenity" && return 1
	elif [ "a${SGUI}" = "akdialog" ]; then
		! find_binary "kdialog" && return 1
	elif [ "a${SGUI}" = "awhiptail" ]; then
		! find_binary "whiptail" && return 1
	fi
	variable=`selection_argument variable "$@"`
	title=`selection_argument title "$@"`
	text=`selection_argument text "$@"`
	options=`selection_argument options "$@" | ${wcbin} -l` ; options=`echo ${options}`
	debug "Prompting user to select variable %s.\n" "${variable}"
	localtext=`format_text "You can automate this selection by setting %s variable on command line.\n" "${variable}"`
	[ "a${text}" != "a" ] && localtext=`${printfbin} "%s\\\\\\n\\\\\\n%s\n" "${localtext}" "${text}"`
	localbutton2=`selection_argument button2 "$@"`; [ "a${localbutton2}" = "a" ] && localbutton2="Cancel"
	if [ "a${SGUI}" = "adialog" ]; then
		localarguments=`selection_argument options "$@" | ${grepbin} -n "." | ${sedbin} -e "s/^\([0-9]*\):\(.*\)	\(.*\)$/\"\1.\" \"\3\" \"${variable}=\\\\\"\2\\\\\"\"/g"`
		eval ${dialogbin} --backtitle \"Sakis3G ${MYVERSION}\" --title \" ${title} \" --ok-label \"`translate_text "OK"`\" --cancel-label \"${localbutton2}\" --item-help --clear --cr-wrap --menu \"${localtext}\" 0 0 0 ${localarguments} 2> "/tmp/sakis3g.dialog.$$"
		buttonselection=$?
	elif [ "a${SGUI}" = "aXdialog" ]; then
		localarguments=`selection_argument options "$@" | ${grepbin} -n "." | ${sedbin} -e "s/^\([0-9]*\):\(.*\)	\(.*\)$/\"\1.\" \"\3\" \"${variable}=\\\\\"\2\\\\\"\"/g"`
		eval ${Xdialogbin} --backtitle \" ${title} \" --title \"Sakis3G ${MYVERSION}\" --ok-label \"`translate_text "OK"`\" --cancel-label \"${localbutton2}\" --item-help --wrap --fill --menubox \""${localtext}"\" 0 0 0 ${localarguments} 2> "/tmp/sakis3g.dialog.$$"
		buttonselection=$?
	elif [ "a${SGUI}" = "akdialog" ]; then
		localarguments=`selection_argument options "$@" | ${grepbin} -n "." | ${sedbin} -e "s/^\([0-9]*\):\(.*\)	\(.*\)$/\"\1.\" \"\3\"/g"`
		eval ${kdialogbin} --title \" ${title} \" --menu \""${text}"\" ${localarguments} \"AUTOMATE\" \"`translate_text "Help with this question"`\" > "/tmp/sakis3g.dialog.$$" 2> /dev/null
		buttonselection=$?
	elif [ "a${SGUI}" = "azenity" ]; then
		need_arg "foldwrapping"
		localarguments=`selection_argument options "$@" | ${grepbin} -n "." | ${sedbin} -e "s/^\([0-9]*\):\(.*\)	\(.*\)$/\"\1.\" \"\3\"/g"`
		localtext=`echo "${text}" | ${sedbin} -e "s/_/__/g"`
		find_binary "fold" && localtext=`echo "${localtext}" | ${foldbin} -s -w ${foldwrapping}`
		eval ${zenitybin} --title \" ${title} \" --list --text \""${localtext}"\" --hide-column 1 --column Index --column `translate_text "Option"` ${localarguments} \"AUTOMATE\" \"`translate_text "Help with this question"`\" > "/tmp/sakis3g.dialog.$$"
		buttonselection=$?
	elif [ "a${SGUI}" = "awhiptail" ]; then
		localarguments=`selection_argument options "$@" | ${grepbin} -n "." | ${sedbin} -e "s/^\([0-9]*\):\(.*\)	\(.*\)$/\"\1. \3\" \"\2\"/g"`
		eval ${whiptailbin} --backtitle \"Sakis3G ${MYVERSION}\" --title \" ${title} \" --noitem --clear --menu \"${localtext}\" 0 0 0 ${localarguments} 2> "/tmp/sakis3g.dialog.$$"
		buttonselection=$?;
	fi
	termselection=`${catbin} "/tmp/sakis3g.dialog.$$" 2> /dev/null`; ${rmbin} -f "/tmp/sakis3g.dialog.$$"
	debug "User selected: \"%s\"\n" "${termselection}"
	if [ "a${termselection}" = "aAUTOMATE" ]; then
		variable=`selection_argument variable "$@"`
		localtext=`format_text "You can automate this selection by setting %s variable on command line.\n" "${variable}"`
		notify "${localtext}\n`select_example "$@" | ${sedbin} -e "s/	/\\\n	/g"`"
		dialog_select "$@"
		selection=$?
		return ${selection}
	elif [ "a${buttonselection}" != "a0" ]; then
		debug "User selected button: %d\n" "${buttonselection}"
		selection=98
	else
		termselection=`echo "${termselection}" | ${trbin} -t "." ""`
		selection=`${printfbin} "%d\n" "${termselection}" 2> /dev/null`
		[ "${selection}" -gt "${options}" ] && selection=0
		[ "${selection}" -eq "0" ] && selection=98
		[ "${selection}" -gt "0" -a "${selection}" -le "${options}" ] && eval export ${variable}="`selection_argument option ${selection} "$@"`"
	fi
	debug "Considering selection: %d\n" "${selection}"
	unset variable; unset title; unset text; unset options; unset termselection; unset buttonselection; unset localtext; unset localarguments; unset localbutton2
	return "${selection}"
}

dialog_prompt() {
	dialog_cleanscreen
	if [ "a${SGUI}" = "adialog" ]; then
		! find_binary "dialog" && return 1
	elif [ "a${SGUI}" = "aXdialog" ]; then
		! find_binary "Xdialog" && return 1
	elif [ "a${SGUI}" = "azenity" ]; then
		! find_binary "zenity" && return 1
	elif [ "a${SGUI}" = "akdialog" ]; then
		! find_binary "kdialog" && return 1
	elif [ "a${SGUI}" = "awhiptail" ]; then
		! find_binary "whiptail" && return 1
	fi
	variable=`selection_argument variable "$@"`
	title=`selection_argument title "$@"`
	text=`selection_argument text "$@"`
	debug "Prompting user to type variable %s.\n" "${variable}"
	localtext=`format_text "You can automate this selection by setting %s variable.\n" "${variable}"` 
	[ "a${text}" != "a" ] && localtext=`${printfbin} "%s\n\n%s: " "${localtext}" "${text}"`
	locallines=`echo "${localtext}" | ${wcbin} -l`; locallines=`echo ${locallines}`; locallines=`expr ${locallines} + 10`; locallines=`echo ${locallines}`;
	if [ "a${SGUI}" = "adialog" ]; then
		${dialogbin} --backtitle "Sakis3G ${MYVERSION}" --title " ${title} " --ok-label `translate_text "OK"` --cancel-label `translate_text "Cancel"` --clear --inputbox "${localtext}" ${locallines} 0 2> "/tmp/sakis3g.dialog.$$"
		buttonselection=$?
	elif [ "a${SGUI}" = "aXdialog" ]; then
		${Xdialogbin} --backtitle " ${title} " --title "Sakis3G ${MYVERSION}" --ok-label `translate_text "OK"` --cancel-label `translate_text "Cancel"` --wrap --fill --clear --inputbox "${localtext}" ${locallines} 0 2> "/tmp/sakis3g.dialog.$$"
		buttonselection=$?
	elif [ "a${SGUI}" = "akdialog" ]; then
		${kdialogbin} --title " ${title} " --inputbox "${localtext}" "" > "/tmp/sakis3g.dialog.$$" 2> /dev/null
		buttonselection=$?
	elif [ "a${SGUI}" = "azenity" ]; then
		need_arg "foldwrapping"
		localtext=`echo "${localtext}" | ${sedbin} -e "s/_/__/g"`
		find_binary "fold" && localtext=`echo "${localtext}" | ${foldbin} -s -w ${foldwrapping}`
		${zenitybin} --title " ${title} " --entry --text "${localtext}" > "/tmp/sakis3g.dialog.$$"
		buttonselection=$?
	elif [ "a${SGUI}" = "awhiptail" ]; then
		${whiptailbin} --backtitle "Sakis3G ${MYVERSION}" --title " ${title} " --clear --inputbox "${localtext}" 0 0 2> "/tmp/sakis3g.dialog.$$"
		buttonselection=$?
	fi
	termselection=`${catbin} "/tmp/sakis3g.dialog.$$" 2> /dev/null`; ${rmbin} -f "/tmp/sakis3g.dialog.$$"
	termselection=`sanitize "${termselection}"`
	debug "User pressed button %d while typed: \"%s\"\n" "${buttonselection}" "${termselection}"
	# TODO: Implement example
	if [ "a${buttonselection}" = "a0" ]; then
		debug "User pressed OK.\n"
		if [ "a${termselection}" != "a" ]; then
			debug "User typed: %s\n" "${termselection}"
			eval "export ${variable}=\"${termselection}\""
			selection=0
		else
			debug "User entered no text.\n" "${variable}"
			selection=98
		fi
	elif [ "a${termselection}" = "a" -o "a${buttonselection}" != "a0" ]; then
		debug "User requested to cancel.\n"
		selection=98
	else
		debug "Unknown error.\n"
		selection=99
	fi
	debug "Considering selection: %d\n" "${selection}"
	unset variable; unset title; unset text; unset termselection; unset buttonselection; unset localtext
	return "${selection}"
}

dialog_clearscreen() {
	[ "a${DEBUG}" = "a" ] && find_binary "clear" && ${clearbin}
	return 0
}

selection_argument() {
	selectarg="$1"
	[ "$#" -gt "0" ] && shift
	case "${selectarg}" in
		variable)
			echo "$1"
			;;
		title)
			echo "$2"
			;;
		text)
			echo "$3"
			;;
		button1)
			echo "$4"
			;;
		button2)
			echo "$5"
			;;
		options)
			for selectind in `${seqbin} 6 2 $#`
			do
				eval selcode=\${${selectind}}
				selectinc=`expr ${selectind} + 1`; selectinc=`echo ${selectinc}`
				eval seloption=\${${selectinc}}
				echo "${selcode}	${seloption}"
				unset selcode; unset seloption; unset selectinc
			done
			unset selectind
			;;
		option)
			selectind=$1
			[ "$#" -gt "0" ] && shift
			selectind=`expr ${selectind} \* 2`; selectind=`echo ${selectind}`
			selectind=`expr ${selectind} + 4`; selectind=`echo ${selectind}`
			eval selcode=\${${selectind}}
			echo "${selcode}"
			unset selcode; unset selectind
			;;
		invalid)
			for selectind in `${seqbin} 7 2 $#`
			do
				eval selcode=\${${selectind}}
				if [ "a${selcode}" = "a$1" ]; then
					debug "%s==%s.\n" "$1" "${selcode}"
					unset selcode; unset selectarg
					selectind=`expr ${selectind} - 5`; selectind=`echo ${selectind}`
					selectind=`expr ${selectind} / 2`; selectind=`echo ${selectind}`
					return ${selectind}
				fi
				debug "%s!=%s\n" "${selcode}" "${1}"
				unset selcode
			done
			debug "Not a valid option \"%s\".\n" "$1"
			unset selectind
			return 0
			;;
		*)
			debug "Unknown selection id %s.\n" "${selectarg}"
			;;
	esac
	unset selectarg
}

# Returns true if $1 is found within $2.
strinstr() {
	[ "a$1" = "a" -o "a$2" = "a" ] && return 1
	if [ "a$3" = "a" ]; then
		strinstrsep=":"
	else
		strinstrsep="$3"
	fi
	strinstrfound=`echo "${strinstrsep}${2}${strinstrsep}" | grep "${strinstrsep}${1}${strinstrsep}"`
	strinstrfound=`echo "${strinstrfound}"`
	unset strinstrsep
	if [ "a${strinstrfound}" != "a" ]; then
		unset strinstrfound
		return 0
	fi
	unset strinstrfound
	return 1
}

# Checks if running with root priviledges
we_are_root_already() {
	if [ "a${UID}" = "a0" -o "a${USER}" = "aroot" -o "a${EUID}" = "a0" ]; then
		return 0
	fi
	debug "Not currently running with root privileges.\n"
	return 1
}

# Makes sure we are root
we_are_root() {
	if we_are_root_already; then
		debug "We are root already. Proceeding.\n"
		return 0
	fi
	state_variables
	verbose "Acquiring root privileges"
	[ -z "${SUMETHOD}" ] && check_su_software
	[ -z "${ME}" ] && have_me
	cleanscreen
	debug "This instance will call %s and abort.\n" "${SUMETHOD}"
	case "${SUMETHOD}" in
		"sudo")
			[ "a${DEBUG}" = "a" ] && find_binary "clear" && ${clearbin}
			eval ${sudobin} ${ME} ${allargs} ${statevariables}
			ret=$?
			if [ "$ret" -eq "1" ]; then
				echo
				echo If it didn\'t worked, you need to add yourself
				echo to sudo file: as root, type visudo and add the
				echo following line at the end of file:
				echo ${runner} ALL=\(root\) NOPASSWD: ${ME}
				stop_fmt_error 1 "Failed to become root."
			fi
			;;
		"gksu")
			# Nusty workaround because gksu does not properly handle arguments containing whitespaces
			${touchbin} "/tmp/sakis3g.gksu.wrapper.$$"
			${chmodbin} +x "/tmp/sakis3g.gksu.wrapper.$$"
			${printfbin} "#!/bin/bash\nexport PROVIDER=\"%s\"\n%s %s %s\nexit \$?\n\n" "${PROVIDER}" "${ME}" "${allargs}" "${statevariables}" > "/tmp/sakis3g.gksu.wrapper.$$"
			[ ! -f "/tmp/sakis3g.gksu.wrapper.$$" ] && stop_fmt_error 3 "No method for acquiring root privileges found."
			debug show_file "/tmp/sakis3g.gksu.wrapper.$$"
			${gksubin} /tmp/sakis3g.gksu.wrapper.$$
			ret=$?
			${rmbin} -f "/tmp/sakis3g.gksu.wrapper.$$"
			;;
		"kdesu")
			${kdesubin} "${ME} ${allargs} ${statevariables}"
			ret=$?
			;;
		"su")
			if [ -n "${stick_to_console}" -a -z "${interactive}" ]; then
				notify "\nUtility \"%s\" found but cannot be used since we are not interactive.\n" "su"
				notify "Either enable interactive mode:\n"
				notify "\t%s --interactive %s\n" "${ME}" "${allargs}"
				notify "or, force using %s instead:\n" "sudo"
				notify "\t%s --sudo %s\n\r\n" "${ME}" "${allargs}"
				stop_fmt_error 3 "No method for acquiring root privileges found."
			fi
			[ "a${DEBUG}" = "a" ] && find_binary "clear" && ${clearbin}
			term_print "Please supply root password, or press enter to abort."
			${subin} -c "${ME} ${allargs} ${statevariables}"
			ret=$?
			;;
	esac
	stop_with ${ret}
}

# Shows error
show_fmt_error() {
	errortext=`format_text "$@"`
	debug "Error: %s\n" "${errortext}"
	if [ "a${noerror}" != "a" ]; then
		debug "Skipping error notification due to configuration.\n"
		unset errortext
		return 0
	fi
	guruplug_error
	case "${SGUI}" in
		whiptail|dialog|Xdialog|zenity|kdialog)
			dialog_error "${errortext}"
			;;
		"9menu")
			nine_error "${errortext}"
			;;
		"interactive terminal")
			term_error "${errortext}"
			;;
		"terminal")
			term_error "${errortext}"
			;;
		*)
			term_error "${errortext}"
			;;
	esac
	unset errortext
}

cleanscreen() {
	osd_cleanscreen
	case "${SGUI}" in
		whiptail|dialog|Xdialog|zenity|kdialog)
			dialog_cleanscreen
			term_clearline
			;;
		"9menu")
			term_clearline
			;;
		"interactive terminal")
			term_clearline
			;;
		"terminal")
			term_clearline
			;;
		*)
			term_clearline
			;;
	esac
}

osd_cleanscreen() {
	if [ "a${OSDPID}" != "a" ]; then
		if find_binary "kill"; then
			! notrunning "${OSDPID}" && ${killbin} -1 "${OSDPID}" 2> /dev/null
			! notrunning "${OSDPID}" && ${killbin} -9 "${OSDPID}" 2> /dev/null
		fi
		unset OSDPID
	fi
	return 0
}

osd_verbose() {
	[ "a${OSDOUTPUT}" = "a" ] && return 1
	osd_cleanscreen
	case "${OSDOUTPUT}" in
		osd_cat)
			need_arg "XOSDFONT"
			if [ "a${OSDISP}" != "a${ISPID}" ]; then
				unset OSDFGCOLOR; unset OSDBGCOLOR;
			fi
			[ "a${OSDFGCOLOR}" = "a" ] && OSDFGCOLOR=`echo ${ISP_FG_COLOR} | ${sedbin} -e "s/^\(..\)\(..\)\(..\)$/rgb:\1\/\2\/\3/g"`
			[ "a${OSDBGCOLOR}" = "a" ] && OSDBGCOLOR=`echo ${ISP_BG_COLOR} | ${sedbin} -e "s/^\(..\)\(..\)\(..\)$/rgb:\1\/\2\/\3/g"`
			[ "a${OSDFGCOLOR}" = "a" ] && OSDFGCOLOR="rgb:80/ff/80"
			[ "a${OSDBGCOLOR}" = "a" ] && OSDBGCOLOR="rgb:00/40/00"
			OSDISP="${ISPID}"
			export OSDISP; export OSDFGCOLOR; export OSDBGCOLOR;
			${OSDOUTPUT} -T "Sakis3G: $1" -P ${verbosecurrentcount} -b percentage -O 2 -c ${OSDFGCOLOR} -u ${OSDBGCOLOR} -f "${XOSDFONT}" -p bottom -a 0 -d 10 -A center &
			OSDPID=$!
			eval "disown -a" > /dev/null 2> /dev/null
			export OSDPID
			[ "a${verbosecurrentcount}" = "a100" ] && sleep 3
			;;
		aosd_cat)
			need_arg "AOSDFONT"
			${OSDOUTPUT} -n "${AOSDFONT}" -f 100 -t 2 --input=- -u 10000 -o 3000 <<endl &
$1
endl
			OSDPID=$!
			eval "disown -a" > /dev/null 2> /dev/null
			export OSDPID
			[ "a${verbosecurrentcount}" = "a100" ] && sleep 3
			;;
	esac
}

verbose() {
	need_binary "printf"
	if [ "a$1" = "a100" ]; then 
		verbosecurrentcount=93
		shift
	fi
	verbosetext=`format_text "$@"`
	[ "${verbosecurrentcount}" = "a" ] && verbosecurrentcount=0
	if [ "a${verbosetext}" = "a${lastverbosetext}" ]; then
		verbosecurrentcount=`expr ${verbosecurrentcount} + 1`; 
		guruplug_verbose_same
	else
		verbosecurrentcount=`expr ${verbosecurrentcount} + 7`;
		guruplug_verbose
	fi
	lastverbosetext="${verbosetext}"
	verbosecurrentcount=`echo ${verbosecurrentcount}`
	export lastverbosetext
	export verbosecurrentcount
	debug "Verbosing: %d%% %s\n" "${verbosecurrentcount}" "${verbosetext}"
	if [ "a${noverbose}" != "a" ]; then
		debug "Skipping verbose due to configuration.\n" 
		unset verbosetext
		return 0
	fi
	if [ "a${OSDOUTPUT}" != "a" ]; then
		osdtext=`${printfbin} "$@"`
		osd_verbose "${osdtext}"
		unset osdtext
	else
		case "${SGUI}" in
			whiptail|dialog|Xdialog|zenity|kdialog)
				dialog_verbose "${verbosetext}"
				;;
			"9menu")
				nine_verbose "${verbosetext}"
				;;
			"interactive terminal")
				term_verbose "${verbosetext}"
				;;
			"terminal")
				term_verbose "${verbosetext}"
				;;
			*)
				term_verbose "${verbosetext}"
				;;
		esac
	fi
	unset verbosetext
}

notify() {
	notificationtext=`format_text "$@"`
	debug "Notify: %s\n" "${notificationtext}"
	if [ "a${nonotify}" != "a" ]; then
		debug "Skipping notification due to configuration.\n"
		unset notificationtext
		return 0
	fi
	case "${SGUI}" in
		whiptail|dialog|Xdialog|zenity|kdialog)
			dialog_notify "${notificationtext}"
			;;
		"9menu")
			nine_notify "${notificationtext}"
			;;
		"interactive terminal")
			term_notify "${notificationtext}"
			;;
		"terminal")
			term_notify "${notificationtext}"
			;;
		*)
			term_notify "${notificationtext}"
			;;
	esac
	unset notificationtext
}

balloon_notify() {
	notificationtext=`format_text "$@"`
	if [ "a${nonotify}" != "a" ]; then
		debug "Skipping balloon notification due to configuration: %s\n" "${notificationtext}"
		unset notificationtext
		return 0
	fi
	# File is deleted during release_X_cookie
	[ "a${PROVIDER}" != "a" ] && [ -x "${PROVIDER}" ] && ${PROVIDER} getfile "files/sakis3g.png" 2> /dev/null > "/tmp/sakis3g.notification.icon.$$.png"
	debug "Will display final message using libnotify.\n"
	if [ ! -f "/tmp/sakis3g.notification.icon.$$.png" ]; then
		debug "Notifying user without icon.\n"
		debug run_command "${notify_sendbin} \"Sakis3G\" \"${notificationtext}\""
	else
		debug "Notifying user with icon.\n"
		debug run_command "${notify_sendbin} --icon=\"/tmp/sakis3g.notification.icon.$$.png\" \"Sakis3G\" \"${notificationtext}\""
		debug run_command "${rmbin} -f \"/tmp/sakis3g.notification.icon.$$.png\""
	fi
	unset notificationtext
}

finalnotify() {
	guruplug_notify
	if [ "a${prefer_osd}" != "a" -a "a${OSDOUTPUT}" != "a" ]; then
		verbose "100" "$@"
	elif [ "a${prefer_osd}" = "a" -a "a${balloons}" != "a" -a "a${stick_to_console}" = "a" ] && find_binary "notify-send" && [ "a${DBUS_SESSION_BUS_ADDRESS}" != "a" -a "a${SESSION_MANAGER}" != "a" ]; then
		balloon_notify "$@"
	else
		notify "$@"
	fi
}

translate_selection() {
	unset translatedarguments
	localcounter=0
	for localargument in "$@"
	do
		localcounter=`expr ${localcounter} + 1`; localcounter=`echo ${localcounter}`
		if [ "${localcounter}" -eq "1" ]; then
			translatedarguments="\"${localargument}\""
		elif [ "${localcounter}" -le "5" ]; then
			translatedtext=`translate_text "${localargument}"`
			translatedarguments=`${printfbin} "%s \"%s\"" "${translatedarguments}" "${translatedtext}"`
			unset translatedtext
		elif [ "${localcounter}" -gt "5" ]; then
			verification=`expr \( ${localcounter} / 2 \) \* 2`; verification=`echo ${verification}`
			if [ "a${verification}" = "a${localcounter}" ]; then
				translatedarguments=`${printfbin} "%s \"%s\"" "${translatedarguments}" "${localargument}"`
			else
				translatedtext=`translate_text "${localargument}"`
				translatedarguments=`${printfbin} "%s \"%s\"" "${translatedarguments}" "${translatedtext}"`
				unset translatedtext
			fi
			unset verification
		fi
	done
	unset localcounter; unset 
	eval "user_select \"translated\" ${translatedarguments}"
	translatedselection=$?
	unset translatedarguments
	return ${translatedselection}
}

translate_confirm() {
	unset translatedarguments
	localcounter=0
	for localargument in "$@"
	do
		localcounter=`expr ${localcounter} + 1`; localcounter=`echo ${localcounter}`
		if [ "${localcounter}" -eq "1" ]; then
			translatedarguments="\"${localargument}\""
		elif [ "${localcounter}" -le "5" ]; then
			translatedtext=`translate_text "${localargument}"`
			translatedarguments=`${printfbin} "%s \"%s\"" "${translatedarguments}" "${translatedtext}"`
			unset translatedtext
		elif [ "${localcounter}" -gt "5" ]; then
			translatedarguments=`${printfbin} "%s \"%s\"" "${translatedarguments}" "${localargument}"`
		fi
	done
	unset localcounter; unset 
	eval "user_confirm \"translated\" ${translatedarguments}"
	translatedselection=$?
	unset translatedarguments
	return ${translatedselection}
}

translate_prompt() {
	unset translatedarguments
	localcounter=0
	for localargument in "$@"
	do
		localcounter=`expr ${localcounter} + 1`; localcounter=`echo ${localcounter}`
		if [ "${localcounter}" -eq "1" ]; then
			translatedarguments="\"${localargument}\""
		elif [ "${localcounter}" -le "5" ]; then
			translatedtext=`translate_text "${localargument}"`
			translatedarguments=`${printfbin} "%s \"%s\"" "${translatedarguments}" "${translatedtext}"`
			unset translatedtext
		elif [ "${localcounter}" -gt "5" ]; then
			verification=`expr \( ${localcounter} / 2 \) \* 2`; verification=`echo ${verification}`
			if [ "a${verification}" = "a${localcounter}" ]; then
				translatedarguments=`${printfbin} "%s \"%s\"" "${translatedarguments}" "${localargument}"`
			else
				translatedtext=`translate_text "${localargument}"`
				translatedarguments=`${printfbin} "%s \"%s\"" "${translatedarguments}" "${translatedtext}"`
				unset translatedtext
			fi
			unset verification
		fi
	done
	unset localcounter; unset 
	eval "user_prompt \"translated\" ${translatedarguments}"
	translatedselection=$?
	unset translatedarguments
	return ${translatedselection}
}

user_confirm() {
	unset selection
	if [ "a$1" != "atranslated" ]; then
		debug "Asking user to confirm: %s\n" "`echo "$@"`"
		translate_confirm "$@"
		return $?
	else
		shift
		debug "Asking user to confirm: %s\n" "`echo "$@"`"
	fi
	if [ "$#" -lt 3 ]; then
		debug "FIXME: Wrong number of arguments (%d). Returning 99.\n" "$#"
		return 99
	fi
	variable=`selection_argument variable "$@"`
	if [ "a$6" = "areset" -a "a${interactive}" != "a" ]; then
		eval unset ${variable}yes
		eval unset ${variable}no
	else
		eval alreadyset=\${${variable}yes}
		if [ "a${alreadyset}" != "a" ]; then
			debug "Switch %syes is already set.\n" "${variable}"
			return 0
		fi
		eval alreadyset=\${${variable}no}
		if [ "a${alreadyset}" != "a" ]; then
			debug "Switch %sno is already set.\n" "${variable}"
			return 1
		fi
	fi
	if voodoo_mode; then
		debug "Voodoo-mode is enabled. Will consider it a yes.\n"
		eval unset ${variable}no
		eval ${variable}yes=1
		eval export ${variable}yes
		selection=0
		return 0
	fi
	case "${SGUI}" in
		whiptail|dialog|Xdialog|zenity|kdialog)
			dialog_confirm "$@"
			selection=$?
			;;
		"9menu")
			nine_confirm "$@"
			selection=$?
			;;
		"interactive terminal")
			interactive_term_confirm "$@"
			selection=$?
			;;
		"terminal")
			term_confirm "$@"
			selection=$?
			;;
		*)
			term_confirm "$@"
			selection=$?
			;;
	esac
	variable=`selection_argument variable "$@"`
	if [ "a${selection}" = "a0" ]; then
		debug "User answered \"yes\".\n"
		eval unset ${variable}no
		eval ${variable}yes=1
		eval export ${variable}yes
		selection=0
	else
		debug "User answered \"no\".\n"
		eval unset ${variable}yes
		eval ${variable}no=1
		eval export ${variable}no
		selection=1
	fi
	unset variable
	return ${selection}
}

user_select() {
	unset selection
	if [ "a$1" != "atranslated" ]; then
		debug "Asking user to select: %s\n" "`echo "$@"`"
		translate_selection "$@"
		return $?
	else
		shift
		debug "Asking user to select: %s\n" "`echo "$@"`"
	fi
	if [ "$#" -lt 3 ]; then
		debug "FIXME: Wrong number of arguments (%d). Returning 99.\n" "$#"
		return 99
	fi
	variable=`selection_argument variable "$@"`
	eval alreadyset=\${${variable}}
	if [ "a${alreadyset}" != "a" ]; then
		debug "%s=%s\n" "${variable}" "${alreadyset}"
		# Check tokens first
		for selectioniterator in ${alreadyset}
		do
			selection_argument invalid "${selectioniterator}" "$@"
			selection=$?
			if [ "a${selection}" != "a0" -a "a${selection}" != "a" ]; then
				debug "User has already selected %s=\"%s\". Returning %d.\n" "${variable}" "${selectioniterator}" "${selection}"
				eval export ${variable}="${selectioniterator}"
				unset variable; unset alreadyset; unset selectioniterator
				return ${selection}
			fi
			unset selection;
		done
		unset selectioniterator
		# Check whole value then
		selection_argument invalid "${alreadyset}" "$@"
		selection=$?
		if [ "a${selection}" != "a0" -a "a${selection}" != "a" ]; then
			debug "User has already selected %s=\"%s\". Returning %d.\n" "${variable}" "${alreadyset}" "${selection}"
			eval export ${variable}="${alreadyset}"
			unset variable; unset alreadyset
			return ${selection}
		fi
		# Else warn
		show_fmt_error "Already selected value %s=\"%s\". Is not valid.\n" "${variable}" "${alreadyset}"
		eval unset ${variable}
		unset variable; unset alreadyset;
	else
		debug "Variable %s is not set already.\n" "${variable}"
		unset alreadyset; unset variable
	fi
	if voodoo_mode; then
		variable=`selection_argument variable "$@"`
		selectioncount=`selection_argument options "$@" | ${wcbin} -l`; selectioncount=`echo ${selectioncount}`
		if [ "a${selectioncount}" = "a1" ]; then
			selection=1
			eval export ${variable}="`selection_argument option 1 "$@"`"
			debug "Employed voodoo-mode in selecting %s from unique option: %s\n" "${variable}" "`eval echo \\${${variable}}`"
			unset selectioncount; unset variable
			return ${selection}
		elif [ "a${selectioncount}" = "a2" ]; then
			for selection in 1 2
			do
				voodoovalue=`selection_argument option ${selection} "$@" | ${grepbin} -i "custom" | ${wcbin} -l`; voodoovalue=`echo ${voodoovalue}`
				[ "a${voodoovalue}" = "a0" ] && voodoovalue=`selection_argument option ${selection} "$@" | ${grepbin} -i "other" | ${wcbin} -l`; voodoovalue=`echo ${voodoovalue}`
				if [ "a${voodoovalue}" = "a1" ]; then
					debug "Voodoo determined that selection %d leads to custom/other.\n" "${selection}"
					if [ "${selection}" -eq "1" ]; then
						selection=2
					else
						selection=1
					fi
					eval export ${variable}="`selection_argument option 1 "$@"`"
					debug "Employed voodoo-mode in selecting %s from option %d: %s\n" "${variable}" "${selection}" "`eval echo \\${${variable}}`"
					unset selectioncount; unset voodoovalue; unset variable
					return ${selection}
				fi
				unset voodoovalue
			done
			unset selection
		fi
		unset selectioncount; unset variable
	fi
	case "${SGUI}" in
		whiptail|dialog|Xdialog|zenity|kdialog)
			dialog_select "$@"
			selection=$?
			;;
		"9menu")
			nine_select "$@"
			selection=$?
			;;
		"interactive terminal")
			interactive_term_select "$@"
			selection=$?
			;;
		"terminal")
			term_select "$@"
			selection=$?
			;;
		*)
			term_select "$@"
			selection=$?
			;;
	esac
	debug "User selection was %d.\n" "${selection}"
	return ${selection}
}

# Prompts user to enter text
user_prompt() {
	if [ "a$1" != "atranslated" ]; then
		debug "Asking user to enter: %s\n" "`echo "$@"`"
		translate_prompt "$@"
		return $?
	else
		shift
		debug "Asking user to enter: %s\n" "`echo "$@"`"
	fi
	if [ "$#" -lt 3 ]; then
		debug "FIXME: Wrong number of arguments (%d). Returning 99.\n" "$#"
		return 99
	fi
	promptvariable=`selection_argument variable "$@"`
	eval alreadyset=\${${promptvariable}}
	if [ "a${alreadyset}" != "a" ]; then
		selection=0
		debug "%s=%s\n" "${promptvariable}" "${alreadyset}"
		debug "User has already entered %s=\"%s\". Returning %d.\n" "${promptvariable}" "${alreadyset}" "${selection}"
		unset alreadyset; unset promptvariable
		return ${selection}
	else
		debug "Variable %s is not set already.\n" "${promptvariable}"
		unset alreadyset; unset promptvariable
	fi
	case "${SGUI}" in
		whiptail|dialog|Xdialog|zenity|kdialog)
			dialog_prompt "$@"
			selection=$?
			;;
		"9menu")
			nine_prompt "$@"
			selection=$?
			;;
		"interactive terminal")
			interactive_term_prompt "$@"
			selection=$?
			;;
		"terminal")
			term_prompt "$@"
			selection=$?
			;;
		*)
			term_prompt "$@"
			selection=$?
			;;
	esac
	promptvariable=`selection_argument variable "$@"`
	eval "alreadyset=\"\${${promptvariable}}\""
	debug "New value is %s=\"%s\". Returning %d.\n" "${promptvariable}" "${alreadyset}" "${selection}"
	unset alreadyset; unset promptvariable
	return ${selection}
}

# Stops execution with return status $1
stop_with() {
	verbose "Cleaning"
	if [ "a$1" = "a" ]; then
		debug "Stopping operation with return status: %d\n" "99"
		exit 99
	else
		debug "Stopping operation with return status: %d\n" "$1"
		exit $1
	fi
}

# Shows error and aborts execution
stop_fmt_error() {
	errorcode="$1"
	[ "$#" -gt "0" ] && shift
	show_fmt_error "$@"
	stop_with ${errorcode}
}


# Make sure usual binary containing directories exist in PATH, even
# if not running as root. Some distributions do not include those
# folders in PATH (although they contain some useful user oriented
# utilities) if not running as root, or if not running from an
# interactive shell.
fix_path() {
	[ -n "${PATHFIXXED}" ] && return 0
	for fixpathi in "/bin" "/usr/bin" "/sbin" "/usr/sbin"
	do
		if strinstr "${fixpathi}" "${PATH}"; then
			debug "Dir \"%s\" exists in PATH.\n" "${fixpathi}"
		else
			export PATH="${fixpathi}:${PATH}"
			debug "Added \"%s\" to PATH.\n" "${fixpathi}"
		fi
	done
	unset fixpathi
	PATHFIXXED=YES
	debug "Done setting up PATH.\n"
}


# Locates full path of binary specified in argument
find_binary() {
	[ "a$1" = "a" ] && return 1
	binaryvariable=`echo "$1" | sed -e "s/-/_/g"`
	binaryvariable=`echo "${binaryvariable}" | sed -e "s/9/nine/g"`
	[ "a${binaryvariable}" = "a" ] && binaryvariable="$1"
	findbinaryfound=`eval echo \\\${${binaryvariable}bin}`
	if [ "a${findbinaryfound}" = "a" ]; then
		if [ "a${whichbin}" = "a" ]; then
			findbinaryfound=`which which 2> /dev/null`
		elif [ ! -x "${whichbin}" ]; then
			findbinaryfound=`which which 2> /dev/null`
		else
			findbinaryfound="${whichbin}"
		fi
		if [ "a${findbinaryfound}" = "a" ]; then
			debug "Unable to locate \"%s\" within PATH, because \"%s\" utility is not available.\n" "$1" "which"
			unset findbinaryfound
			return 1
		else
			if [ -z "${whichbin}" ]; then
				export whichbin="${findbinaryfound}"
				debug "Can search through PATH, \"%s\" binary found.\n" "which"
			fi
			findbinaryfound=`${findbinaryfound} "${1}" 2> /dev/null`
			if [ "a${findbinaryfound}" = "a" ]; then
				debug "Unable to locate \"%s\" within PATH.\n" "$1"
				unset findbinaryfound
				return 1
			elif [ -x "${findbinaryfound}" ]; then
				debug "Located \"%s\" within PATH (%s).\n" "$1" "${findbinaryfound}"
				eval export ${binaryvariable}bin="${findbinaryfound}"
			fi
		fi
	fi
	if [ -x "${findbinaryfound}" ]; then
		unset findbinaryfound
		return 0
	else
		debug "Unable to execute \"%s\" from \"%s\".\n" "$1" "${findbinaryfound}"
		unset findbinaryfound
		eval unset ${binaryvariable}bin
		return 1
	fi
}

# Aborts execution if "$1" binary is not found.
need_binary() {
	[ "a$1" = "a" ] && term_error "FIXME: Executed need_binary with no argument."
	! find_binary "$1" && stop_fmt_error 4 "Unable to locate dependency \"%s\". Script will now abort." "$1"
}

# Check dependencies. Only really required staff should be placed here.
# We cannot yet search in PATH.
check_level_one_deps() {
	for checkdependency in which echo grep 
	do
		need_binary "${checkdependency}"
	done
	unset checkdependency
	debug "Level 1 dependencies met.\n"
}

# Checks if communication software is available and aborts if not
check_com_software() {
	! find_binary "wvdial" && direct_pppd=yes
	if [ -n "${direct_pppd}" ]; then
		need_binary "pppd"
		need_arg "PPPD_PEERS"
		if [ ! -d "${PPPD_PEERS}" ]; then
			debug "Unable to locate pppd peers directory (%s)." "${pppdpeerdir}"
		fi
	fi
	for checkdependency in chat
	do
		need_binary "${checkdependency}"
	done
	unset checkdependency
	return 0
}

# Checks if method for becoming root, exists.
check_su_software() {
	unset SUMETHOD
	if [ -z "${alwayssudo}" ]; then
		if [ -z "${stick_to_console}" ]; then
			if find_binary "gksu"; then
				debug "Running on a GNOME system.\n"
				SUMETHOD="gksu"
			elif find_binary "kdesu"; then
				debug "Running on a KDE system.\n"
				SUMETHOD="kdesu"
			elif [ -x "/usr/lib/kde4/libexec/kdesu" ]; then
				export kdesubin="/usr/lib/kde4/libexec/kdesu"
				debug "Running on a KDE4 system.\n"
				SUMETHOD="kdesu"
			fi
		fi
		if [ -z "${SUMETHOD}" ]; then
			if find_binary "su"; then
				debug "Using plain text mode su.\n"
				SUMETHOD="su"
			else
				debug "No su method found. Will check if sudo available.\n"
				export alwayssudo=yes
			fi
		fi
	fi
	if [ -n "${alwayssudo}" ]; then
		! find_binary "sudo" && stop_fmt_error 3 "No method for acquiring root privileges found."
		debug "Running with sudo configuration.\n"
		SUMETHOD="sudo"
	fi
	return 0
}

# Forces use of text mode utilities for getting root privileges
console_su_software() {
	if [ "${SUMETHOD}" = "kdesu" -o "${SUMETHOD}" = "gksu" ]; then
		if find_binary "su"; then
			debug "Reverting to plain text mode su.\n"
			SUMETHOD="su"
		else
			debug "No text mode su found. Will check if sudo available.\n"
			export alwayssudo=yes
			check_su_software
		fi
	fi
}


# Check dependencies. Only really required staff should be placed here.
# We can now search within path.
check_level_two_deps() {
	for checkdependency in printf wc cut cat tail head sort uniq ls sed setsid getent ps chmod chown touch expr tr seq cp rm who mv expr basename dirname 
	do
		need_binary "${checkdependency}"
	done
	unset checkdependency
	debug "Level 2 dependencies met.\n"
	if [ "a${PROVIDER}" != "a" ] && [ ! -x "${PROVIDER}" ]; then
		debug run_command "${chmodbin} +x \"${PROVIDER}\""
		if [ ! -x "${PROVIDER}" ]; then
			stop_fmt_error 5 "Unable to determine my path.\n"
		fi
		debug "Successfully turned myself an executable.\n"
	fi
}

# If running as root, checks dependencies that should be met
# once running as root. If not running as root, checks if
# software for becoming root, is available.
check_root_deps() {
	if ! we_are_root_already; then
		check_su_software
	else
		for checkdependency in ifconfig
		do
			need_binary "${checkdependency}"
		done
		unset checkdependency
	fi
	debug "Root level dependencies met.\n"
}

# Locate required utilities within PATH
resolv_binaries() {
	check_level_one_deps
	fix_path
	get_me ${1}
	check_level_two_deps
	debug "Basic binaries are resolved.\n"
}

# Provides a writable log position
need_log() {
	need_arg "LOGPOSITION"
	for logcandidate in "${LOGPOSITION}" "/var/log/sakis3g.log" "sakis3g.log.$$" "/tmp/sakis3g.log.$$"
	do
		if [ "a${logcandidate}" != "a" ]; then
			${touchbin} "${logcandidate}" 2> /dev/null
			if [ -w "${logcandidate}" ]; then
				export LOGPOSITION="${logcandidate}"
				debug "Log file is set to \"%s\".\n" "${LOGPOSITION}"
				return 0
			else
				unset logposition
			fi
		fi
	done
	debug "Failed to find a place to store log.\n"
	export LOGPOSITION="/dev/null"
	debug "Log file is set to \"%s\".\n" "${logposition}"
	return 1
}

# Returns true(0) if process with PID given as 
# argument, is not running any more.
notrunning() {
	if [ -n "$1" ]; then
		pidrunning=`${psbin} -p $1 -o pid= 2> /dev/null | wc -l`
		pidrunning=`echo ${pidrunning}`
	else
		pidrunning=1
	fi
	if [ "${pidrunning}" -ne "0" ]; then
		debug "PID %s is still running.\n" "$1"
	else
		debug "PID %s is not running any more.\n" "$1"
	fi
	return ${pidrunning}
}

# Sets PPROCESS variable
get_parent_process() {
	pidtocheck=$1
	[ "a${pidtocheck}" = "a" ] && pidtocheck="${PPID}"
	PPROCESS=`${psbin} -p ${pidtocheck} -o comm= 2> /dev/null`
	export PPROCESS
	if [ "a${PPROCESS}" = "a" ]; then
		debug "Unable to get parent process name.\n"
		unset PPROCESS; unset pidtocheck
		return 1
	fi
	unset pidtocheck
	return 0
}

# Check if called by udevd. If yes, spawn in background
# and exit this instance.
check_udevd() {
	if [ "a${PROVIDER}" = "a" ]; then
		get_parent_process
	else
		pppid=`${psbin} -p ${PPID} -o ppid= 2> /dev/null`
		pppid=`echo ${pppid}`
		get_parent_process "${pppid}"
		unset pppid
	fi
	debug "Parent process is: %s\n" "${PPROCESS}"
	if [ "a${PPROCESS}" = "audevd" ]; then
		debug "Running by a udevd event.\n"
		need_log
		if have_me; then
			debug "Unconditionally setting DISPLAY to :0.\n"
			export DISPLAY=:0
			debug "Will now spawn child process in background.\n"
			${ME} "$@" > "${LOGPOSITION}" 2>&1 &
			stop_with 0
		fi
	else
		debug "Running by user request.\n"
	fi
}

# Get my location if possible
get_me() {
	unset metarget
	[ -x "${PROVIDER}" ] && metarget="${PROVIDER}"
	[ -z "${metarget}" ] && metarget="$1"
	find_binary "readlink" && ME=`${readlinkbin} -e ${metarget} 2> /dev/null`
	[ -z "${ME}" ] && find_binary "which" && ME="`${whichbin} ${metarget} 2> /dev/null`"
	unset metarget
	[ -n "${ME}" ] && [ ! -x "${ME}" ] && unset ME
	if [ -z "${ME}" ]; then
		unset ME
		debug "Unable to determine my own location.\n"
	else
		debug "My location is \"%s\".\n" "${ME}"
	fi

}

# Makes sure we know our own executable
have_me() {
	[ -n "${ME}" ] && [ -x "${ME}" ] && return 0;
	stop_fmt_error 5 "Unable to determine my path.\n"
}

# If we are root, attempts to determine real user
# behind it, by looking back the process tree. Goes
# back 15 processes before giving up.
resolv_root() {
	[ -z "$1" ] && pid=$$
	[ -z "${pid}" ] && pid=$1
	puser=`${psbin} -p ${pid} -o user= 2> /dev/null`
	if [ -z "${puser}" ]; then
		unset pid; unset puser
		return
	elif [ "${puser}" != "root" ]; then
		runner="${puser}"
		unset pid; unset puser
		return
	fi
	unset puser
	ppid=`${psbin} -p ${pid} -o ppid= 2> /dev/null`; unset pid
	if [ -z "${ppid}" ]; then
		unset ppid
		return
	elif [ "a${ppid}" = "a1" ]; then
		unset ppid
		return
	fi
	[ -z "$2" ] && count=0
	count=`expr $2 + 1`
	count=`echo ${count}`
	[ "$count" -lt 15 ] && resolv_root ${ppid} ${count}
	unset ppid; unset count
}

# Locates really running user. If root, attempts to resolv
# it to real user.
find_user() {
	unset runner; unset runhome
	[ -n "${USER}" ] && runner="${USER}"
	[ -n "${LOGNAME}" ] && runner="${LOGNAME}"
	[ -n "${USERNAME}" ] && runner="${USERNAME}"
	[ -z "${runner}" ] && find_binary "who" && runner=`${whobin} -m | ${cutbin} -d\  -f1`
	[ -z "${runner}" ] && we_are_root_already && runner="root"
	[ -n "${runner}" ] && [ "${runner}" = "root" ] && resolv_root $$ 0
	if [ -n "${runner}" ]; then
		runhome=`${getentbin} passwd ${runner} 2> /dev/null | ${cutbin} -d: -f6`
		[ -n "${runhome}" ] && [ ! -d "${runhome}" ] && unset runhome
		[ -z "${runhome}" ] && unset runner
		[ -n "${runner}" ] && debug "Person behind screen is %s.\n" "${runner}"
	fi
	[ -z "${runner}" ] && debug "Unable to find our username.\n"
}

# Determines if display $1 is unique local display.
unique_local_display() {
	debug "Will check if display %s belongs to unique user logged in.\n" "$1"
	[ "a$1" = "a" ] && return 1
	! find_binary "who" && return 1
	loggedusers=`${whobin} | ${grepbin} -v root | ${cutbin} -d\  -f1 | ${sortbin} | ${uniqbin} | ${wcbin} -l`
	loggedusers=`echo ${loggedusers}`
	if [ "a${loggedusers}" != "a1" ]; then
		debug "Found %d logged users. Cannot make sure who will really see message.\n" "${loggedusers}"
		unset loggedusers
		return 1
	fi
	unset loggedusers
	loggeduser=`${whobin} | ${grepbin} -v root | ${cutbin} -d\  -f1 | ${sortbin} | ${uniqbin}`
	confirm=`${whobin} | ${grepbin} ${1} | ${cutbin} -d\  -f1 | ${sortbin} | ${uniqbin} | ${grepbin} "^${loggeduser}$"`
	if [ "a${loggeduser}" = "a${confirm}" ]; then
		debug "Unique display %s belongs to user %s.\n" "$1" "${loggeduser}"
		unset confirm; unset loggeduser;
		return 0
	fi
	debug "Display %s does not belongs to user %s.\n" "$1" "${loggeduser}"
	unset confirm; unset loggeduser;
	return 1
}

# Attemtps to get access to display $1
access_display() {
	debug "Will attempt to get access to display %s.\n" "$1"
	[ "a$1" = "a" ] && return 1
	! find_binary "xauth" && return 1
	[ "a${XAUTHORITY}" = "a" ] && unset XAUTHORITY
	gotaccess=`${xauthbin} nlist $1 2> /dev/null | ${wcbin} -l`
	gotaccess=`echo ${gotaccess}`
	if [ "a${gotaccess}" = "a0" ]; then
		xuser=`${whobin} -u | ${grepbin} -v "^root" | ${grepbin} ${1} | ${cutbin} -d\  -f1 | ${sortbin} | ${uniqbin}`
		xhome=$(${getentbin} passwd ${xuser} | ${cutbin} -d: -f6)
		debug "Not currently trusted to display %s belonging to %s.\n" "${1}" "${xuser}"
		if [ "a${LOCALAUTHORITY}" != "a" ] && [ -r "${LOCALAUTHORITY}" ]; then
			xholder="${LOCALAUTHORITY}"
		elif [ -d "${xhome}" ] && [ -r "${xhome}/.Xauthority" ]; then
			xholder="${xhome}/.Xauthority"
		else
			unset xholder
		fi
		if [ "a${xholder}" = "a" ]; then
			debug "Unable to locate Xauthority file of %s.\n" "${xuser}"
		else
			debug "Will attempt to steal cookie from %s.\n" "${xholder}"
			if [ "a${HOME}" = "a" ]; then
				rruser="${runner}"
				we_are_root_already && rruser="root"
				rrhome=$(${getentbin} passwd ${rruser} | ${cutbin} -d: -f6)
				if [ -d "${rrhome}" -a "a${xhome}" != "a${rrhome}" ]; then
					debug "HOME variable not set already. Setting HOME for %s: %s\n" "${rruser}" "${rrhome}"
					export HOME="${rrhome}"
				fi
				unset rruser; unset rrhome;
			else
				debug "HOME directory set already (%s).\n" "${HOME}"
			fi
			${xauthbin} -f "${xholder}" nextract - $1 2> /dev/null | ${xauthbin} nmerge - 2> /dev/null
			gotaccess=`${xauthbin} nlist ${1} 2> /dev/null | ${wcbin} -l`
			gotaccess=`echo ${gotaccess}`
			if [ "a${gotaccess}" = "a0" ]; then
				debug "Failed to steal cookie.\n"
			else
				debug "Cookie stolen from %s(%s) to %s.\n" "${xuser}" "${1}" "${HOME}/.Xauthority"
				export XCOOKIE="$1"
				addexittrap "release_X_cookie" EXIT
				unset xuser; unset xhome; unset gotaccess; unset xholder
				return 0
			fi
		fi
		unset xuser; unset xhome; unset gotaccess; unset xholder
	else
		debug "Already granted access to display %s.\n" "${1}"
		[ "a${XAUTHORITY}" != "a" ] && export LOCALAUTHORITY="${XAUTHORITY}"
		unset gotaccess
		return 0
	fi
	return 1
}

# Find DISPLAY
find_display() {
	if [ -n "${stick_to_console}" ]; then
		unset DISPLAY; unset display;
		debug "Not using an X display due to stick-to-console variable.\n"
	else
		display="${DISPLAY}"
		# If display is not set, or is remote, attempt to find a local display of runner user.
		[ -z "${DISPLAY}" -o "`echo ${DISPLAY} | ${cutbin} -b1`" != ":" ] \
		&& display="" \
		&& [ -n "${runner}" -a "a${runner}" != "aroot" ] \
		&& find_binary "who" \
		&& display=`${whobin} -m | ${grepbin} "^${runner}" | ${grepbin} "(\:.*)" | ${cutbin} -d\( -f2 | ${cutbin} -d\) -f1 | ${sortbin} | ${headbin} -1`
		# If DISPLAY is set to a local display, but we are run
		# from root himself, and that X display is the unique
                # local X display available, use it no matter what.
		[ -n "${display}" -a -n "${DISPLAY}" -a "a${runner}" = "aroot" ] \
		&& ! unique_local_display "${DISPLAY}" && unset display
		# Get number of display (if any)
		displaynum=`echo ${display} | ${cutbin} -b2- | ${cutbin} -d. -f1`
		display=":${displaynum}"
		# Validate that determined xsession exists.
		[ ! -S "/tmp/.X11-unix/X${displaynum}" ] && unset display
		unset displaynum
		[ -n "${display}" ] && ! access_display "${display}" && unset display
		if [ -z "${display}" ]; then
			debug "Unable to find a local X display, will stick to terminal.\n"
			unset DISPLAY; unset display;
			export stick_to_console=yes
			find_gui
		else
			export display
			export DISPLAY="${display}"
		fi
	fi
	if [ -z "${display}" ]; then
		unset DISPLAY; unset display;
		export stick_to_console=yes
		console_su_software
	else
		debug "Will be using display %s.\n" "${display}"
	fi
}

# Selects GUI to be used if not already set by SGUI variable.
find_gui() {
	debug "Selecting GUI.\n"
	if [ -n "${stick_to_console}" -a -n "$SGUI" ]; then
		debug "Validating pre-selected GUI: %s\n" "${SGUI}"
		[ "a$SGUI" = "azenity" ] && unset SGUI
		[ "a$SGUI" = "agdialog" ] && unset SGUI
		[ "a$SGUI" = "akdialog" ] && unset SGUI
		[ "a$SGUI" = "aXdialog" ] && unset SGUI
		[ "a$SGUI" = "a9menu" ] && unset SGUI
		[ "a$SGUI" = "agnome-terminal" ] && unset SGUI
		[ "a$SGUI" = "akonsole" ] && unset SGUI
		[ "a$SGUI" = "axterm" ] && unset SGUI
		[ -z "${SGUI}" ] && debug "Could not be used from console. Will seek an alternative.\n"
	fi
	if [ "a${SGUI}" != "a" -a "a${SGUI}" != "ainteractive terminal" -a "a${SGUI}" != "aterminal" ] && ! find_binary "${SGUI}"; then
		debug "%s not found. Will search for another GUI provider.\n" "${SGUI}"
		unset SGUI
	fi
	if [ "a${stick_to_console}" = "a" ]; then
		[ "a${SGUI}" = "a9menu" ] && ! find_binary "9menu" && unset SGUI
		[ "a${SGUI}" = "a9menu" ] && ! find_binary "xterm" && unset SGUI
		[ -z "${SGUI}" ] && find_binary "kdialog" && SGUI="kdialog"
		[ -z "${SGUI}" ] && find_binary "zenity" && SGUI="zenity"
		[ -z "${SGUI}" ] && find_binary "Xdialog" && SGUI="Xdialog"
		[ -z "${SGUI}" ] && find_binary "gnome-terminal" && SGUI="gnome-terminal"
		[ -z "${SGUI}" ] && find_binary "konsole" && SGUI="konsole"
		[ -z "${SGUI}" ] && find_binary "xterm" && SGUI="xterm"
		if [ -z "${SGUI}" ]; then
			debug "No graphical GUI found. Forced to stick to terminal.\n"
			export stick_to_console=yes
		fi
	fi
	if [ "a${interactive}" != "a" ]; then
		[ -z "${SGUI}" ] && find_binary "dialog" && SGUI="dialog"
		[ -z "${SGUI}" ] && find_binary "whiptail" && SGUI="whiptail"
		[ -z "${SGUI}" ] && SGUI="interactive terminal"
	fi
	[ -z "${SGUI}" ] && SGUI="terminal"
	# Custom setup per GUI
	[ "a${SGUI}" = "adialog" ] && addexittrap "dialog_clearscreen"
	[ "a${SGUI}" = "aXdialog" -o "a${SGUI}" = "a9menu" ] && export notranslate=yes && unset foldwrapping && need_arg "foldwrapping"
	[ "a${SGUI}" = "adialog" -o "a${SGUI}" = "awhiptail" -o "a${SGUI}" = "aterminal" -o "a${SGUI}" = "ainteractive terminal" ] && export stick_to_console=yes
	[ "a${SGUI}" = "adialog" -o "a${SGUI}" = "awhiptail" -o "a${SGUI}" = "ainteractive terminal" -o "a${SGUI}" = "aXdialog" -o "a${SGUI}" = "azenity" -o "a${SGUI}" = "akdialog" -o "a${SGUI}" = "a9menu" ] && export interactive=yes
	debug "%s selected as GUI.\n" "${SGUI}"
	# Forward to terminal if have to do so
	case "${SGUI}" in
		xterm)
			debug "Will spawn xterm window.\n"
			unset SGUI; export stick_to_console=yes; export interactive=yes;
			state_variables
			eval ${xtermbin} -T "Sakis3G" +cm +dc -e ${ME} ${allargs} ${statevariables}
			stop_with $?
			;;
		gnome-terminal)
			debug "Will spawn gnome-terminal window.\n"
			unset SGUI; export stick_to_console=yes; export interactive=yes;
			state_variables
			eval ${gnome_terminalbin} -t "Sakis3G" -x ${ME} ${allargs} ${statevariables}
			stop_with $?
			;;
		konsole)
			debug "Will spawn konsole window.\n"
			unset SGUI; export stick_to_console=yes; export interactive=yes;
			state_variables
			eval ${konsolebin} --title "Sakis3G" -e "${ME} ${allargs} ${statevariables}"
			stop_with $?
			;;
	esac
	# Check for OSD
	unset OSDOUTPUT
	if [ "a${stick_to_console}" = "a" -a "a${prefer_osd}" != "a" ]; then
		if find_binary "osd_cat"; then
			export OSDOUTPUT="osd_cat"
		elif find_binary "aosd_cat"; then
			export OSDOUTPUT="aosd_cat"
		fi
		[ "a${OSDOUTPUT}" != "a" ] && debug "Will be using \"%s\" for displaying OSD messages.\n" "${OSDOUTPUT}"
	fi
	[ "a${prefer_osd}" != "a" -a "a${OSDOUTPUT}" = "a" ] && unset prefer_osd && debug "OSD will not appear.\n"
	return 0
}

# Checks if module $1 is loaded
module_loaded() {
	[ "a$1" = "a" ] && return 99
	unset moduleloaded
	debug "Checking if module \"%s\" is currently loaded.\n" "$1"
	if [ -r "/proc/modules" ]; then
		moduleloaded=`${grepbin} "^$1 " "/proc/modules" 2> /dev/null | ${sedbin} -e "s/^$1 \([0-9][0-9]*\) \([0-9][0-9]*\) \(.*\)$/\1 \3/g"`
		if [ "a${moduleloaded}" = "a" ]; then
			debug "Module \"%s\" is not currently loaded.\n" "$1"
			unset moduleloaded
			return 1
		elif [ "a${moduleloaded}" = "a$1 0" ]; then
			debug "Module \"%s\" is currently loaded having no users.\n" "$1"
			unset moduleloaded
			return 0
		else
			debug "Module \"%s\" is currently loaded and occupied.\n" "$1"
			unset moduleloaded
			return 0
		fi
	elif find_binary "lsmod"; then
		moduleloaded=`${lsmodbin} | ${grepbin} "^$1 " | ${wcbin} -l`; moduleloaded=`echo ${moduleloaded}`
		if [ "a${moduleloaded}" = "a" -o "a${moduleloaded}" = "a0" ]; then
			debug "Module \"%s\" is not currently loaded.\n" "$1"
			unset moduleloaded
			return 1
		else
			debug "Module \"%s\" is currently loaded.\n" "$1"
			unset moduleloaded
			return 0
		fi
	else
		show_fmt_error "Unable to check if module is currently loaded or if it has users.\n"
		return 1
	fi
}

# Unloads module from system if possible
module_unload() {
	[ "a$1" = "a" ] && return 99
	! module_loaded "$1" && return 0
	! find_binary "modprobe" && return 1
	debug "Attempting to unload module \"%s\".\n" "$1"
	debug run_command "${modprobebin} -r -v $1"
	debug "Waiting for module to vanish.\n"
	if module_loaded "$1"; then
		show_fmt_error "Failed to unload module \"%s\".\n" "$1"
		return 1
	else
		debug "Module \"%s\" succesfully unloaded.\n" "$1"
		return 0
	fi
}

# Loads module $1 if possible, providing arguments for device $2 if applicable
module_load() {
	[ "a$1" = "a" ] && return 99
	module_loaded "$1" && return 0
	! find_binary "modprobe" && return 1
	debug "Attempting to load module \"%s\".\n" "$1"
	need_arg "SERIALDRIVERS"
	needsarg=`echo " ${SERIALDRIVERS} " | ${grepbin} " $1 " | ${wcbin} -l`; needsarg=`echo ${needsarg}`
	if [ "a${needsarg}" = "a1" -a "a$2" != "a" ]; then
		if usb_device_connected "$2"; then
			modulevend=`echo "$2" | ${cutbin} -d: -f1`
			moduleprod=`echo "$2" | ${cutbin} -d: -f2`
			modargs="vendor=0x${modulevend} product=0x${moduleprod}"
			unset modulevend; unset moduleprod
			debug "Will provide arguments to \"%s\": %s\n" "$1" "${modargs}"
		else
			debug "Warning: Module \"%s\" needs arguments, but \"%s\" does not refer to a connected device.\n" "$1" "$2"
			unset modargs
		fi
	elif [ "a${needsarg}" = "a1" ]; then
		debug "Warning: Module \"%s\" needs arguments but device was not specified.\n" "$1"
		unset modargs
	fi
	debug run_command "${modprobebin} $1 ${modargs}"
	debug "Waiting for module to get loaded.\n"
	unset modargs; unset needsarg
	counter=0
	while [ "${counter}" -lt "6" ]
	do
		if ! module_loaded "$1"; then
			debug "Module \"%s\" still not live. Waiting a second.\n" "$1"
			sleep 1
		fi
		if module_loaded "$1"; then
			debug "Module \"%s\" succesfully loaded.\n" "$1"
			unset counter
			return 0
		fi
		counter=`expr ${counter} + 1`; counter=`echo ${counter}`
	done
	unset counter
	show_fmt_error "Failed to load module \"%s\".\n" "$1"
	return 1
}

# Attempts to detach driver $1 from device $2 interface $3
# If failed to detach, attempts to completely unload $1 before failing.
module_unbind() {
	[ "a$1" = "a" ] && return 99
	verbose "Unloading driver %s" "$1"
	if [ "a$2" = "a" -a "a$3" = "a" ]; then
		debug "Requested to unbind module \"%s\" without device specified. Will try to unload it.\n" "$1"
		module_unload "$1"
		return $?
	fi
	moduleattached=`usb_loaded_driver "$2" "$3" | ${tailbin} -1 | ${grepbin} "$1" | ${wcbin} -l`
	if [ "a${TIMEOUTOCCURED}" != "a" ]; then
		show_fmt_error "Seems like an electrical/USB bus error occured. You may need to replug your modem for it to properly work.\n"
		unset TIMEOUTOCCURED
	fi
	moduleattached=`echo ${moduleattached}`
	if [ "a${moduleattached}" = "a" -o "a${moduleattached}" = "a0" ]; then
		debug "Module \"%s\" does not appear to be attached to device \"%s\".\n" "$1" "$2"
		unset moduleattached
		return 0
	fi
	debug "Module \"%s\" is currently attached to \"%s\".\n" "$1" "$2"
	[ "a$3" != "a" ] && usb_sysfsdir_int "$2" "$3" && unbindvalue=`${basenamebin} ${sysfsintloc}`
	[ "a$3" = "a" ] && usb_sysfsdir && unbindvalue=`cd "${sysfsloc}"; ${lsbin} -1d \`${basenamebin} ${sysfsloc}\`*`
	[ "a${unbindvalue}" = "a" ] && unbindvalue=`echo "$2" | ${sedbin} -e "s/:/ /g"`
	sent=0
	[ "a$1" = "ausb_storage" ] && localdrivername="usb-storage"
	for endpoint in /sys/bus/usb/drivers/${localdrivername}/unbind /sys/bus/usb/drivers/$1/unbind
	do
		for destination in ${unbindvalue}
		do
			if [ -w "${endpoint}" ]; then
				echo -n "${destination}" > "${endpoint}" 2> /dev/null
				debug "Sent \"%s\" to \"%s\".\n" "${destination}" "${endpoint}"
				sent=1
			fi
		done
		unset destination
	done
	unset unbindvalue; unset endpoint; unset localdrivername
	if [ "${sent}" -eq "1" ]; then
		debug "Expecting module to detach from device.\n"
		while [ "${sent}" -lt "6" ]
		do
			unset moduleattached
			moduleattached=`usb_loaded_driver "$2" "$3" | ${tailbin} -1 | ${grepbin} "$1" | ${wcbin} -l`
			if [ "a${TIMEOUTOCCURED}" != "a" ]; then
				show_fmt_error "Seems like an electrical/USB bus error occured. You may need to replug your modem for it to properly work.\n"
				unset TIMEOUTOCCURED
				break
			fi
			moduleattached=`echo ${moduleattached}`
			if [ "a${moduleattached}" = "a" -o "a${moduleattached}" = "a0" ]; then
				debug "Module \"%s\" has detached from device \"%s\".\n" "$1" "$2"
				unset moduleattached; unset sent
				if find_binary "modprobe"; then
					if [ "a$1" != "ausb_storage" -a "a$1" != "ausb-storage" ]; then
						debug "Will attempt to also remove it.\n"
						debug run_command "${modprobebin} -r -v $1"
						module_loaded "$1"
					fi
				fi
				return 0
			fi
			debug "Module still attached. Waiting for %d second(s).\n" "${sent}"
			sent=`expr ${sent} + 1`; sent=`echo ${sent}`
			sleep 1
		done
		debug "Module \"%s\" did not detach from device \"%s\". Will try to unload it.\n" "$1" "$2"
	fi
	module_unload "$1"
	return $?
}

# Attempts to bind module $1 to device $2, interface $3 (optional)
module_bind() {
	[ "a$1" = "a" -o "a$2" = "a" ] && return 99
	verbose "Loading driver %s" "$1"
	module_load "$1" "$2"
	ret=$?; [ "${ret}" -ne "0" ] && return ${ret}
	unset moduleattached
	modulename="$1"
	[ "a${modulename}" = "ausb-storage" ] && modulename="usb_storage"
	[ "a${modulename}" = "acdc-acm" ] && modulename="cdc_acm"
	moduleattached=`usb_loaded_driver "$2" "$3" | ${tailbin} -1 | ${grepbin} "${modulename}" | ${wcbin} -l`
	if [ "a${TIMEOUTOCCURED}" != "a" ]; then
		show_fmt_error "Seems like an electrical/USB bus error occured. You may need to replug your modem for it to properly work.\n"
		unset TIMEOUTOCCURED
	fi
	moduleattached=`echo ${moduleattached}`
	if [ "a${moduleattached}" != "a" -a "a${moduleattached}" != "a0" ]; then
		debug "Module \"%s\" attached to device \"%s\".\n" "$1" "$2"
		unset moduleattached; unset sent; unset modulename
		return 0
	fi
	unset moduleattached
	debug "Module \"%s\" not yet attached to \"%s\".\n" "$1" "$2"
	bindvalue=`echo "$2" | ${sedbin} -e "s/:/ /g"`
	sent=0
	for endpoint in /sys/module/${modulename}/drivers/usb-serial:*/new_id
	do
		if [ -w "${endpoint}" ]; then
			echo -n "${bindvalue}" > "${endpoint}" 2> /dev/null
			if [ "$?" -eq "0" ]; then
				debug "Sent \"%s\" to \"%s\".\n" "${bindvalue}" "${endpoint}"
				sent=1
			fi
		fi
	done
	if [ "a${sent}" != "a1" ]; then
		for endpoint in /sys/module/${modulename}/drivers/usb:*/new_id
		do
			echo -n "${bindvalue}" > "${endpoint}" 2> /dev/null
			if [ "$?" -eq "0" ]; then
				debug "Sent \"%s\" to \"%s\".\n" "${bindvalue}" "${endpoint}"
				sent=1
			fi
		done
	fi
	unset bindvalue; unset endpoint
	if [ "a${sent}" = "a1" ]; then
		counter=0
		while [ "${counter}" -lt "10" ]
		do
			moduleattached=`usb_loaded_driver "$2" "$3" | ${tailbin} -1 | ${grepbin} "${modulename}" | ${wcbin} -l`
			if [ "a${TIMEOUTOCCURED}" != "a" ]; then
				show_fmt_error "Seems like an electrical/USB bus error occured. You may need to replug your modem for it to properly work.\n"
				unset TIMEOUTOCCURED
				break;
			fi
			moduleattached=`echo ${moduleattached}`
			if [ "a${moduleattached}" != "a1" ]; then
				debug "Waiting one second.\n"
				sleep 1
			fi
			moduleattached=`usb_loaded_driver "$2" "$3" | ${tailbin} -1 | ${grepbin} "${modulename}" | ${wcbin} -l`
			if [ "a${TIMEOUTOCCURED}" != "a" ]; then
				show_fmt_error "Seems like an electrical/USB bus error occured. You may need to replug your modem for it to properly work.\n"
				unset TIMEOUTOCCURED
				break;
			fi
			moduleattached=`echo ${moduleattached}`
			if [ "a${moduleattached}" != "a" -a "a${moduleattached}" != "a0" ]; then
				debug "Module \"%s\" attached to device \"%s\".\n" "$1" "$2"
				unset moduleattached; unset sent; unset counter; unset modulename
				return 0
			fi
			unset moduleattached
			counter=`expr ${counter} + 1`; counter=`echo ${counter}`
		done
		unset counter
	fi
	debug "Module \"%s\" did not bind to device \"%s\".\n" "$1" "$2"
	if [ "a$4" != "anoreload" ]; then
		debug "Will attempt to do a reload cycle.\n"
		if module_unload "$1" "$2" "$3"; then
			if module_bind "$1" "$2" "$3" "noreload"; then
				unset counter; unset sent; unset moduleattached; unset modulename
				debug "Reload cycle did the trick.\n"
				debug "Module \"%s\" attached to device \"%s\".\n" "$1" "$2"
				return 0
			else
				return $?
			fi
		fi
	fi
	unset moduleattached; unset modulename
	if [ "${sent}" -eq "0" ]; then
		show_fmt_error "Module \"%s\" loaded but did not bind to device \"%s\".\n" "$1" "$2"
	else
		show_fmt_error "Module \"%s\" loaded but refused to bind to device \"%s\".\n" "$1" "$2"
	fi
	unset sent; unset counter
	return 1
	return 99
}

# Unlocks a previously acquired lock to hal
hal_unlock() {
	[ "a${nohal}" != "a" ] && return 0
	[ "a${HAL_LOCK}" = "a" ] && return 0
	debug "Releasing HAL lock %d.\n" "${HAL_LOCK}"
	if notrunning "${HAL_LOCK}"; then
		debug "Already unlocked.\n"
	else
		if [ -f "/tmp/sakis3g.hal.lock.$$" ]; then
			${rmbin} -f "/tmp/sakis3g.hal.lock.$$"
			sleep 2
		fi
		if ! notrunning "${HAL_LOCK}"; then
			debug "Failed to unlock by unlinking mutex file. Will try to kill.\n"
			term_clearline
			${killbin} -1 ${HAL_LOCK} 2> /dev/null
			if ! notrunning "${HAL_LOCK}"; then
				debug "Failed to kill PID %d.\n" "${HAL_LOCK}"
				return 1
			fi
		fi
		debug "Unlocked.\n"
	fi
	unset HAL_LOCK
	return 0
}

# Attempts to establish lock of interface $1 (i.e. org.freedesktop.Hal.Device.Storage)
hal_acquire_lock() {
	[ "a${nohal}" != "a" ] && return 0
	[ "a${HAL_LOCK}" != "a" ] && ! hal_unlock && return 1
	! find_binary "hal-lock" && return 1
	! find_binary "kill" && return 1
	! find_binary "touch" && return 1
	! we_are_root && return 1
	debug "Acquiring lock in HAL for \"%s\".\n" "$1"
	${touchbin} "/tmp/sakis3g.hal.lock.$$"
	hal-lock --interface "$1" --exclusive --run "${ME} holdlock /tmp/sakis3g.hal.lock.$$" &
	halpid=$!; unset informed
	while ! notrunning ${halpid}
	do
		hallocksuccess=`${catbin} "/tmp/sakis3g.hal.lock.$$" 2> /dev/null`; hallocksuccess=`echo ${hallocksuccess} | ${sedbin} -e "s/ //g"`
		if [ "a${hallocksuccess}" = "a" ]; then
			unset hallocksuccess
			[ "a${informed}" = "a" ] && verbose "Acquiring exclusive lock to HAL"
			informed=`expr ${informed} + 1`; informed=`echo ${informed}`
			if [ "${informed}" -le "20" ]; then
				debug "Waiting for spawned process to acquire lock (%d secs will have passed).\n" "${informed}"
				sleep 1
			else
				debug "Giving up waiting for lock to occur. Will try to terminate current lock attempt.\n"
				export HAL_LOCK=${halpid}
				hal_unlock; unset HAL_LOCK
				break
			fi
		else
			debug "Exclusive lock granted to PID %d.\n" "${hallocksuccess}"
			break;
		fi
	done
	if [ "a${hallocksuccess}" != "a" ]; then
		export HAL_LOCK=${halpid}
		addexittrap hal_unlock
		debug "Succesfully locked HAL interface \"%s\" (hal-lock itself running with PID %d).\n" "$1" "${HAL_LOCK}"
		unset halpid; unset informed; unset hallocksuccess
		return 0
	fi
	unset halpid; unset informed; unset hallocksuccess
	debug "Failed to acquire exclusive lock to %s.\n" "$1"
	return 1
}

# Makes sure that only one instance of $3 is contained within 
# list $2 of hal udi $1.
hal_add_to_list() {
	! find_binary "hal-get-property" && return 1
	! find_binary "hal-set-property" && return 1
	[ "$#" -ne "3" ] && return 1
	halfound=0
	while [ "${halfound}" -ne "1" ];
	do
		contents=`hal-get-property --udi "$1" --key "$2" 2> /dev/null`
		halfound=0
		for op in ${contents}
		do
			if [ "a${op}" = "a$3" ]; then
				halfound=`expr ${halfound} + 1`
				halfound=`echo ${halfound}`
			fi
		done
		if [ "${halfound}" -eq "0" ]; then
			debug "Will attempt to add \"%s\" inside \"%s\".\n" "$3" "$2"
			hal-set-property --udi "$1" --key "$2" --strlist-post "$3" 2> /dev/null
		elif [ "${halfound}" -gt "1" ]; then
			debug "Will attempt to remove multiple instance of \"%s\" inside \"%s\".\n" "$3" "$2"
			hal-set-property --udi "$1" --key "$2" --strlist-rem "$3" 2> /dev/null
		fi
		hala=$?
		if [ "a${hala}" != "a0" ]; then
			debug "Unable to properly modify HAL.\n"
			break
		fi
	done
	[ "${halfound}" -eq "1" ] && debug "HAL is updated.\n"
	unset contents; unset op; unset hala
	if [ "a${halfound}" = "a1" ]; then
		unset halfound
		return 0
	fi
	unset halfound
	return 1
}

# Makes sure modem $1 capabilities are loaded on hal
hal_tty_update() {
	[ "a${nohal}" != "a" ] && return 0
	[ "a${nohalinform}" != "a" ] && return 0
	! find_binary "hal-get-property" && return 1
	! find_binary "hal-set-property" && return 1
	! find_binary "hal-find-by-property" && return 1
	unset halcapabilities
	case "a${TTY_CAPABILITIES}" in
		aGSM)
			halcapabilities="GSM-07.07 GSM-07.05"
			;;
		a)
			debug "No capabilities found. Don't know what to tell to HAL.\n"
			;;
		*)
			debug "FIX ME: Unknown capabilities %s. Don't know what to tell to HAL.\n" "${TTY_CAPABILITIES}"
			;;
	esac
	[ "a${halcapabilities}" = "a" ] && unset halcapabilities && return 1
	debug "Capabilities of %s are: %s\n" "$1" "${halcapabilities}"
	haludi=`hal-find-by-property --key "linux.device_file" --string "$1" 2> /dev/null | ${tailbin} -1`
	if [ "a${haludi}" = "a" ]; then
		unset haludi; unset halcapabilities
		debug "No HAL device referring to %s was found.\n" "$1"
		return 1
	fi
	debug "Found device in HAL: %s\n" "${haludi}"
	verbose "Updating HAL"
	hal_add_to_list "${haludi}" info.capabilities "modem"
	for cap in ${halcapabilities}
	do
		hal_add_to_list "${haludi}" modem.command_sets "${cap}"
	done
	debug "HAL was updated that %s is a modem.\n" "$1"
	find_binary "hal-device" && debug run_command "hal-device \"${haludi}\""
	unset cap; unset halcapabilities; unset haludi
	return 0
}

# If $1 node does not exist, creates it with major $2 and minor $3
dev_create_node() {
	[ "a$1" = "a" -o "a$2" = "a" -o "a$3" = "a" ] && return 99
	if [ ! -c "$1" ]; then
		debug "Device node \"%s\" does not exist.\n" "$1"
		if ! find_binary "mknod"; then
			show_fmt_error "Unable to create device node \"%s\"." "$1"
			return 1
		fi
		debug run_command "${mknodbin} \"$1\" c $2 $3"
		if [ ! -c "$1" ]; then
			show_fmt_error "Failed to create device node \"%s\"." "$1"
			return 1
		fi
		debug "Made node \"%s (%d,%d)\" ourselves.\n" "$1" "$2" "$3"
		return 0
	else
		debug "Device node \"%s\" already exists.\n" "$1"
		return 0
	fi
}

pin_valid() {
	[ "a$1" = "a" ] && return 1
	need_binary "expr"
	givenpin=`echo $1`
	mathpin=`${exprbin} 1${givenpin} + 1 - 1 2> /dev/null`; mathpin=`echo ${mathpin}`
	if [ "a${mathpin}" = "a1${givenpin}" ]; then
		if [ "1${givenpin}" -ge "10000" -a "1${givenpin}" -le "19999" ]; then
			debug "Valid PIN %s.\n" "$1"
			return 0
		fi
	fi
	debug "Invalid PIN %s.\n" "$1"
	return 1
}

pin_prompt() {
	user_prompt "SIM_PIN" "Modem needs PIN" "Please enter PIN number, or leave empty to abort" "OK" "Cancel"
	case "a${SIM_PIN}" in
		a)
			debug "User did not provide PIN.\n"
			unset SIM_PIN
			return 98
			;;
		*)
			if ! pin_valid "${SIM_PIN}"; then
				debug "PIN supplied by user was not a valid PIN number (%s).\n" "${SIM_PIN}"
				unset SIM_PIN
				pin_prompt
				ret=$?
			fi
			export SIM_PIN
			return 0
			;;
	esac
}


# Makes sure tty $1 is not busy
tty_not_busy() {
	[ "a$1" = "a" ] && return 1
	[ ! -c "$1" ] && return 1
	if we_are_root; then
		ttyusers=`${lsbin} -l /proc/*/fd/* 2> /dev/null | ${grepbin} "${1}$" | ${sedbin} -e "s/\(.*\)\/proc\/\([0-9][0-9]*\)\/fd\/\(.*\)/\2/g" | ${sortbin} | ${uniqbin} | ${wcbin} -l` ; ttyusers=`echo ${ttyusers}`
		if [ "a${ttyusers}" = "a0" ]; then
			unset ttyusers
			debug "Device %s is not busy.\n" "$1"
			[ "a$2" != "a" ] && verbose "Resuming"
			return 0
		fi
		debug "Device %s is currently occupied by %d process(es).\n" "$1" "${users}"
		ttyusers=`${lsbin} -l /proc/*/fd/* 2> /dev/null | ${grepbin} "${1}$" | ${sedbin} -e "s/\(.*\)\/proc\/\([0-9][0-9]*\)\/fd\/\(.*\)/\2/g" | ${sortbin} | ${uniqbin}` ; ttyusers=`echo ${ttyusers}`
		debug "PID(s) are: %s\n" "${ttyusers}"
		for ttyp in ${ttyusers}
		do
			debug run_command "${psbin} -p ${ttyp} -o pid,comm= | ${tailbin} -1"
			ttyusers="${ttyusers} `${psbin} -p ${ttyp} -o comm= 2> /dev/null`"
		done
		unset ttyp
		if [ "a$2" = "a" ]; then
			debug "Will wait for 10 seconds in case port is freed.\n"
			verbose "Waiting %s to be released by PID %s." "$1" "${ttyusers}"
			ttycount=11
		else
			ttycount=$2
		fi
		ttycount=`expr ${ttycount} - 1`
		if [ "a${ttycount}" = "a0" ]; then
			show_fmt_error "Port %s is currently occupied by %s." "$1" "${ttyusers}"
			unset ttyusers; unset ttycount;
			return 1
		else
			debug "Wait for another %d seconds in case port %s is freed.\n" "${ttycount}" "$1"
			sleep 1
			if tty_not_busy $1 $ttycount; then
				unset ttyusers; unset ttycount;
				return 0
			else
				unset ttyusers; unset ttycount;
				return 1
			fi
		fi
		unset ttyusers; unset ttycount;
	else
		show_fmt_error "Unable to check if %s is occupied. Not root." "$1"
	fi
	return 1
}

at_default_commands() {
	unset ttycommands
	[ "a$1" = "a" ] && return 1
	case "a$1" in
		aPROBEGSM)
			ttycommands="ATI OK 'AT+GCAP' OK 'AT+CGSN' OK"
			;;
		aIDENTIFY)
			ttycommands="AT+CGMM OK"
			;;
		aSTAGE0)
			if [ "a${INIT_STAGE0}" != "a" ]; then
				ttycommands="${INIT_STAGE0}"
			fi
			;;
		aSTAGE1)
			if [ "a${INIT_STAGE1}" != "a" ]; then
				ttycommands="${INIT_STAGE1}"
			fi
			;;
		aPINCHECK)
			if [ "a${INIT_STAGE2}" != "a" ]; then
				ttycommands="${INIT_STAGE2}"
				debug "Using instructed PINCHECK.\n"
			else
				ttycommands="'AT+CPIN?' OK"
				debug "Using default PINCHECK.\n"
			fi
			;;
		aPINSUPPLY)
			if pin_valid "${2}"; then
				if [ "a${INIT_STAGE3}" != "a" ]; then
					ttycommands=`${printfbin} "${INIT_STAGE3}\n" "${2}"`
					debug "Using instructed PINSUPPLY.\n"
				else
					ttycommands=`${printfbin} "'AT+CPIN=\"%s\"' OK\n" "${2}"`
					debug "Using default PINSUPPLY.\n"
				fi
			fi
			;;
		aSTAGE4)
			if [ "a${INIT_STAGE4}" != "a" ]; then
				ttycommands="${INIT_STAGE4}"
			fi
			;;
		aOPERATOR)
			ttycommands="AT+COPS=3,2 OK 'AT+COPS?' OK"
			;;
		aOPERATORS)
			ttycommands="AT+COPS=3,2 OK 'AT+COPS=?' TIMEOUT 120 OK"
			;;
		aOPERATORNAME)
			ttycommands="AT+COPS=3,0 OK 'AT+COPS?' OK"
			;;
		aSIMOPERATORNAME)
			ttycommands="'AT+CRSM=176,28486,0,0,17' OK"
			;;
		aSETOPERATOR)
			ttycommands=`${printfbin} "'AT+COPS=1,2,\"%s\"' OK\n" "${2}"`
			;;
		aSTAGE5)
			if [ "a${INIT_STAGE5}" != "a" ]; then
				ttycommands="${INIT_STAGE5}"
			fi
			;;
		aDETECTAPN)
			ttycommands="AT+CGDCONT? OK"
			;;
		aINITIALIZE)
			if [ "a${APN}" != "a" ]; then
				apnpart=`echo "${APN}" | ${cutbin} -d: -f1`
				[ "a${apnpart}" = "aCUSTOM_APN" ] && apnpart="${CUSTOM_APN}"
				if [ "a${INIT_STAGE6}" != "a" ]; then
					ttycommands=`${printfbin} "${INIT_STAGE6}\n" "${apnpart}"`
					debug "Using instructed INITIALIZE.\n"
				else
					ttycommands=`${printfbin} "ATZ OK 'AT&F' OK 'ATQ0 V1 E1' OK 'AT&D2 &C1' OK AT+FCLASS=0 OK ATS0=0 OK 'AT+CGDCONT=1,\"IP\",\"%s\"' OK\n" "${apnpart}"`
					debug "Using default INITIALIZE.\n"
				fi
				unset apnpart
			fi
			;;
		aSTAGE7)
			if [ "a${INIT_STAGE7}" != "a" ]; then
				ttycommands="${INIT_STAGE7}"
			fi
			;;
		aSTAGE8)
			if [ "a${INIT_STAGE8}" != "a" ]; then
				ttycommands="${INIT_STAGE8}"
			fi
			;;
		aDIAL)
			dialphone="${ISP_DIAL}"
			[ "a${dialphone}" = "a" ] && dialphone="*99#"
			ttycommands=`${printfbin} "ATD%s\n" "${dialphone}"`
			unset dialphone
			;;
	esac
	[ "a${ttycommands}" != "a" ] && debug "Command \"%s\" refers to AT commands: %s\n" "$1" "${ttycommands}" && return 0
	debug "Unknown command \"%s\".\n" "$1"
	return 1
}

# Send command $2 to tty $1
tty_send_command() {
	unset LASTTTYLOG
	[ "a$1" = "a" -o "a$2" = "a" ] && return 99
	if [ ! -c "$1" ]; then
		debug "Device node %s did not exist while trying \"%s\" command.\n" "$1" "$2"
		if [ "a${informedspurious}" != "a1" ] && [ "a${usbdevice}" != "a" ] && usb_device_connected "${usbdevice}" && usb_has_storage "$1" && [ "a${killstorage}" = "a" ]; then
			show_fmt_error "Spurious changes in tty %s. Consider using \"killstorage\" switch in case it improves stability." "$1"
			export informedspurious=1
		fi
		if [ "a${informedspurious}" != "a1" ]; then
			show_fmt_error "Spurious changes in tty %s. Problem may be solved by upgrading your kernel or by choosing another driver." "$1"
			export informedspurious=1
		fi
		[ ! -c "$1" ] && debug "Waiting one second in case it appears.\n" && sleep 1
		[ ! -c "$1" ] && debug "Device still missing. Aborting.\n" && return 1
		debug "Device %s appeared. Will proceed sending %s commands.\n" "$1" "$2"
	fi
	! find_binary "chat" && return 4
	need_arg "CHAT_ABORT_STRINGS"
	! at_default_commands "$2" "$3" && return 1
	ttycommands="\"\" '\pAT' OK ${ttycommands} '\pAT' OK"
	debug "Will send %s commands to tty %s: %s\n" "$2" "$1" "${ttycommands}"
	! tty_not_busy "$1" && return 1
	timestamp_before=`${lsbin} --full-time -G1 $1 2> /dev/null`; timestamp_before=`echo ${timestamp_before}`
	sh -c "${chatbin} -t 2 -e ${CHAT_ABORT_STRINGS} ${ttycommands} >> ${1} < ${1} 2> /tmp/sakis3g.chat.$$.log"
	timestamp_after=`${lsbin} --full-time -G1 $1 2> /dev/null`; timestamp_before=`echo ${timestamp_after}`
	if [ "a${timestamp_before}" != "a${timestamp_after}" ]; then
		debug "Spurious changes in tty %s.\n" "$1"
		if [ "a${usbdevice}" != "a" ] && usb_device_connected "${usbdevice}" && usb_has_storage "$1" && [ "a${killstorage}" = "a" ] && [ "a${informedspurious}" != "a1" ]; then
			show_fmt_error "Spurious changes in tty %s. Consider using \"killstorage\" switch in case it improves stability." "$1"
			export informedspurious=1
		fi
		if [ "a${informedspurious}" != "a1" ]; then
			show_fmt_error "Spurious changes in tty %s. Problem may be solved by upgrading your kernel or by choosing another driver." "$1"
			export informedspurious=1
		fi
	fi
	unset ttycommands
	if [ -f "/tmp/sakis3g.chat.$$.log" ]; then
		LASTTTYLOG=`${catbin} "/tmp/sakis3g.chat.$$.log"`
		debug "Got response from tty:\n%s\n" "${LASTTTYLOG}"
		rm -f "/tmp/sakis3g.chat.$$.log"
		return 0
	else
		debug "No response from tty %s.\n" "$1"
		return 1
	fi
}

# Finds capabilities of tty $1 and sets TTY_CAPABILITIES variable
tty_get_caps() {
	unset TTY_CAPABILITIES
	[ "a$1" = "a" ] && return 1
	! tty_send_command "$1" "PROBEGSM" && return 1
	gsmfound=`echo "${LASTTTYLOG}" | ${grepbin} "+CGSM" | wc -l`; gsmfound=`echo ${gsmfound}`
	if [ "a${gsmfound}" = "a0" ]; then
		debug "No GSM capabilities were advertised.\n"
		gsmfound=`echo "${LASTTTYLOG}" | ${grepbin} "^\([0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]\)$" | wc -l` ; gsmfound=`echo ${gsmfound}`
		if [ "a${gsmfound}" = "a1" ]; then
			debug "However, IMEI information was provided. Will consider it GSM capable.\n"
		fi
	fi
	[ "a${gsmfound}" = "a0" -o "a${gsmfound}" = "a" ] && [ "a${NOPROBEGSM}" != "a" ] && debug "Forced by user to consider tty %s GSM capable.\n" "$1" && gsmfound=1
	if [ "a${gsmfound}" != "a0" ]; then
		export TTY_CAPABILITIES="GSM"
		debug "Found GSM capabilities on tty %s.\n" "$1"
		return 0
	fi
	# TODO: Implement support for non GSM devices.
	debug "Device did not report GSM capabilities.\n"
	if [ "a$2" != "anoretry" ]; then
		debug "Will check one more time.\n"
		tty_get_caps "$1" "noretry"
		return $?
	fi
	show_fmt_error "Device did not report GSM capabilities. You can skip this by adding --noprobe command line switch.\n"
	return 1
}

# Sets MODEM_VARIANT, if possible, for tty $1
tty_identify() {
	unset MODEM_VARIANT
	[ "a$1" = "a" ] && return 1
	! tty_send_command "$1" "IDENTIFY" && return 1
	MODEM_VARIANT=`echo "${LASTTTYLOG}" | ${grepbin} -v "^AT" | ${sedbin} -e "s/AT//g" | ${sedbin} -e "s/OK//g" | ${sedbin} -e "s/ERROR//g" | ${trbin} "\n" " " | ${trbin} "\t" " " | ${sedbin} -e "s/  */ /g" | ${sedbin} -e "s/^ *//g" | ${sedbin} -e "s/ *$//g"`
	MODEM_VARIANT=`echo ${MODEM_VARIANT}`
	if [ "a${MODEM_VARIANT}" = "a" ]; then
		debug "Modem did not report a name.\n"
		unset MODEM_VARIANT
	else
		debug "Modem on tty identified itself as: %s\n" "${MODEM_VARIANT}"
		base_modem "${usbdevice}" "${MODEM_VARIANT}"
	fi
	return 0
}

# Checks if tty $1 needs PIN.
tty_needspin() {
	unset pinrequirement
	[ "a$1" = "a" ] && return 1
	! tty_send_command "$1" "PINCHECK" && return 1
	pinrequirement=`echo "${LASTTTYLOG}" | ${grepbin} "ERROR"`
	[ "a${pinrequirement}" != "a" ] && pinrequirement="ERROR"
	[ "a${pinrequirement}" = "a" ] && pinrequirement=`echo "${LASTTTYLOG}" | ${grepbin} "^.CPIN: " | ${cutbin} -d\  -f2-`
	[ "a${pinrequirement}" = "a" ] && pinrequirement="ERROR"
	[ "a${pinrequirement}" = "aREADY" ] && debug "Modem on %s does not need PIN.\n" "$1" && return 1
	[ "a${pinrequirement}" = "aSIM PIN" ] && debug "Modem on %s needs PIN.\n" "$1" && return 0
	debug "Got \"%s\" while checking modem on %s for PIN requirement.\n" "${pinrequirement}" "$1"
	return 0
}

# Unlocks tty $1 from PIN.
tty_pin_unlock() {
	[ "a$1" = "a" ] && return 1
	! tty_needspin "$1" && unset pinrequirement && return 0
	if [ "a${pinrequirement}" = "a" ]; then 
		show_fmt_error "Failed to get valid response from modem while checking for PIN."
		unset pinrequirement
		return 1
	elif [ "a${pinrequirement}" != "aSIM PIN" ]; then
		show_fmt_error "Modem responded \"%s\" while checking for PIN." "${pinrequirement}"
		unset pinrequirement
		return 1
	fi
	unset pinrequirement
	if ! pin_valid "${SIM_PIN}"; then
		unset SIM_PIN
		! pin_prompt && return 98
		! pin_valid "${SIM_PIN}" && return 1
	fi
	verbose "Sending PIN"
	! tty_send_command "$1" "PINSUPPLY" "${SIM_PIN}" && return 1
	debug "PIN sent to %s. Waiting 3 seconds before checking success.\n" "$1"
	sleep 3
	if ! tty_needspin "$1"; then
		unset pinrequirement
		debug "SIM is now READY.\n"
		return 0
	fi
	unset SIM_PIN
	stop_fmt_error 12 "WRONG PIN. Aborting to prevent you from locking your SIM card."
	return 1
}

tty_detect_apn() {
	unset MODEM_APN
	[ "a${MODEM_TTY}" = "a" ] && return 1
	! tty_send_command "${MODEM_TTY}" "DETECTAPN" && return 1
	MODEM_APN=`echo "${LASTTTYLOG}" | ${grepbin} "^+CGDCONT" | ${sedbin} -e "s/^\(.*\)IP\",\"\(.*\)\",\"\(.*\)$/\2/g" | ${grepbin} -v "^+CGDCONT"`
	export MODEM_APN
	debug "APN stored in modem was: %s\n" "${MODEM_APN}"
	[ "a${MODEM_APN}" = "a" ] && unset MODEM_APN && return 1
	return 0
}

tty_sim_provider_name() {
	unset ISPSIMNAME
	[ "a$1" = "a" ] && return 1
	if tty_send_command "$1" "SIMOPERATORNAME"; then
		ISPSIMNAME=`echo "${LASTTTYLOG}" | ${grepbin} "^+CRSM:\( *\)144," | ${sedbin} -e "s/^.CRSM:\( *\)144,\(.*\),\"\(.*\)\"\(.*\)$/ISPSIMNAME=\3/g" | ${grepbin} "^ISPSIMNAME=" | ${cutbin} -d= -f2-`
		[ "a${ISPSIMNAME}" = "a" ] && unset ISPSIMNAME && return 1
		ISPSIMNAME=`${printfbin} "\`echo "${ISPSIMNAME}" | ${sedbin} -e "s/\([0-9A-Fa-f][0-9A-Fa-f]\)/\\\\\\\\\\x\1/g" | ${sedbin} -e "s/\\\\\\\\\\xFF//g" | ${sedbin} -e "s/\\\\\\\\\\x01//g" | ${sedbin} -e "s/\\\\\\\\\\x02//g"\`\n"`
		ISPSIMNAME=`echo ${ISPSIMNAME}`
		[ "a${ISPSIMNAME}" = "a" ] && unset ISPSIMNAME && return 1
		debug "SIM contains \"service provider\" name: %s\n" "${ISPSIMNAME}"
		export ISPSIMNAME
		return 0
	fi
	return 1
}

tty_select_network() {
	unset FORCE_ISP
	verbose "Scanning networks"
	! tty_send_command "$1" "OPERATORS" && return 1
	networks=`echo "${LASTTTYLOG}" | ${grepbin} "^+COPS:" | ${cutbin} -d: -f2- -s | ${sedbin} -e "s/(/\\\n(/g" | ${sedbin} -e "s/)/)\\\n/g" | ${grepbin} "^([1-3],\"\(.*\)\",\"\(.*\)\",\"\([0-9][0-9]*\)\",0)$" | ${sedbin} -e "s/^(1,/(Allowed,/g" | ${sedbin} -e "s/^(2,/(Current,/g" | ${sedbin} -e "s/^(3,/(Forbidden,/g" | ${sedbin} -e "s/^(\(.*\),\"\(.*\)\",\"\(.*\)\",\"\([0-9][0-9]*\)\",0)$/\"\4\" \"\2 (\1\)\" /g"`
	eval user_select \"FORCE_ISP\" \"Please select a network\" \"Select network for modem to register.\" \"Select\" \"Cancel\" ${networks}
# in
	case "$?" in
		0)
			unset FORCE_ISP; unset networks
			return 98
			;;
		98)
			unset FORCE_ISP; unset networks
			return 98
			;;
		99)
			unset FORCE_ISP; unset networks
			return 99
			;;
		*)
			case "a${FORCE_ISP}" in
				a)
					unset FORCE_ISP; unset networks
					return 98
					;;
				*)
					debug "User selected %s.\n" "${FORCE_ISP}"
					return 0
				;;
			esac
			;;
	esac
	return 1
}

tty_registered_network() {
	unset ISPID; unset ISPNAME; unset ISPTEXT
	[ "a$1" = "a" ] && return 1
	! tty_send_command "$1" "OPERATOR" && return 1
	ISPID=`echo "${LASTTTYLOG}" | ${grepbin} "^+COPS:" | ${cutbin} -d\" -f2`; ISPID=`echo ${ISPID}`
	if [ "a${ISPID}" = "a+COPS: 0" -o "a${ISPID}" = "a" ]; then
		debug "Modem not registered to a network yet.\n"
		unset ISPID
		return 1
	fi
	debug "Modem registered to network ID \"%s\".\n" "${ISPID}"
	if [ -n "${FORCE_ISP}" ]; then
		if [ "a${ISPID}" != "a${FORCE_ISP}" ]; then
			debug "FORCE_ISP variable instructs to use \"%s\" instead.\n" "${FORCE_ISP}"
		fi
		debug "Will attempt to manually set %s and prevent roaming.\n" "${FORCE_ISP}"
		! tty_send_command "$1" "SETOPERATOR" "${FORCE_ISP}"
		if [ "a$2" != "aFORCE_ISP" ]; then
			tty_registered_network "$1" "FORCE_ISP"
		else
			if [ "a${ISPID}" != "a" ]; then
				show_fmt_error "Modem refused to register operator \"%s\" (currently registered to \"%s\").\n" "${FORCE_ISP}" "${ISPID}"
			else
				show_fmt_error "Modem refused to register operator \"%s\".\n" "${FORCE_ISP}"
			fi
			unset ISPID
			return 1
		fi
		unset ISPID
		return $?
	fi
	export ISPID
	if tty_send_command "$1" "OPERATORNAME"; then
		ISPNAME=`echo "${LASTTTYLOG}" | ${grepbin} "^+COPS:" | ${sedbin} -e "s/^.COPS: 0,0,\"\(.*\)\"\(.*\)$/ISPNAME=\1/g" | ${grepbin} "^ISPNAME=" | ${cutbin} -d= -f2-`
		if tty_sim_provider_name "$1" && [ "a${ISPSIMNAME}" != "a" -a "a${ISPSIMNAME}" != "a${ISPNAME}" ]; then
			debug "SIM card instructs to use \"%s\" as service provider name, instead of \"%s\".\n" "${ISPSIMNAME}" "${ISPNAME}"
			ISPNAME="${ISPSIMNAME}"
		fi
		# Some modems return numeric ID, even if instructed to display name.
		[ "a${ISPNAME}" = "a${ISPID}" ] && unset ISPNAME
		# Some SIMs incorrectly confuse modem to display FFs as service provider name.
		[ "a`echo ${ISPNAME} | ${cutbin} -b1-8`" = "aFFFFFFFF" ] && unset ISPNAME
		# Huawei E160 does not correctly report operator name.
		# This is not true. Was a SIM issue. This is not true.
		#[ "a${MODEM_VARIANT}" = "aE160" ] && unset ISPNAME
		export ISPNAME
		[ "a${ISPNAME}" = "a" ] && net_info "${ISPID}"
		[ "a${ISPNAME}" = "a" ] && unset ISPNAME
	fi
	export ISPTEXT="${ISPID}"
	[ "a${ISPNAME}" != "a" ] && export ISPTEXT="${ISPNAME}"
	return 0
}

tty_register_network() {
	[ "a$1" = "a" ] && return 1
	wat=0
	if [ -n "${FORCE_ISP}" ]; then
		debug "FORCE_ISP variable instructs to enter network \"%s\".\n" "${FORCE_ISP}"
		debug "Will attempt to manually set %s and prevent roaming.\n" "${FORCE_ISP}"
		! tty_send_command "$1" "SETOPERATOR" "${FORCE_ISP}"
	fi
	while ! tty_registered_network $1;
	do
		if [ "${wat}" -gt "20" ]; then
			debug "Giving up after %d seconds have passed.\n" "${wat}"
			break
		else
			wat=`expr ${wat} + 4`
			wat=`echo ${wat}`
		fi
		debug "Waiting modem to register network (%d seconds).\n" "${wat}"
		verbose "Registering network"
		sleep 4
	done
	unset wat
	if [ "a${ISPID}" = "a" ]; then
		show_fmt_error "Modem unable to register a network."
		unset ISPID
		if user_confirm "scan" "Scan for network" "Modem was unable to register a network. Would you like to manually select a network?" "Yes" "No" "reset"; then
			if tty_select_network "$@"; then
				tty_register_network "$@"
				return $?
			fi
		fi
		return 13
	else
		debug "Modem on %s has registered %s.\n" "$1" "${ISPID}"
		return 0
	fi
}

# Makes sure tty $1 is ready for connection to be established.
tty_prepare() {
	check_com_software
	ret=$?; [ "${ret}" -ne "0" ] && return ${ret}
	[ "a$1" = "a" ] && return 1
	verbose "Preparing modem"
	tty_send_command "$1" "STAGE0"
	! tty_get_caps "$@" && return 1
	! tty_identify "$@" && return 1
	tty_send_command "$1" "STAGE1"
	! tty_pin_unlock "$@" && return 1
	tty_send_command "$1" "STAGE4"
	tty_register_network "$@"; ret=$?; [ "${ret}" -ne "0" ] && return ${ret}
	tty_send_command "$1" "STAGE5"
	hal_tty_update "$@"
	debug "Modem on device node %s is now ready for connection.\n" "$1"
	return 0
}

# Attempts to get connected USB devices, exiting if it fails.
usb_connected_devices() {
	unset usb_devices
	need_binary "sort"; need_binary "uniq"; need_binary "sed"
	if [ -r "/proc/bus/usb/devices" ]; then
		debug "Fetching connected USB devices by using \"%s\".\n" "/proc/bus/usb/devices"
		usb_devices=`safe_cat "/proc/bus/usb/devices" | ${grepbin} -A 4 "^P:" | ${sedbin} -e "s/^\(.*\)Ven\(.*\)=\(....\) Pro\(.*\)=\(....\) \(.*\)$/\3:\5:/g" | ${sedbin} -e "s/^S:\(.*\)Pro\(.*\)=\(.*\)$/\3/g" | ${sedbin} -e "s/^.:\(.*\)$//g" | ${grepbin} -v "^$"`
		usb_devices=`echo ${usb_devices} | ${sedbin} -e "s/: */:/g" | ${sedbin} -e "s/ -- /\\\n/g" | ${sortbin} | ${uniqbin} | ${grepbin} -v "HCI Host Controller"`
	elif [ -d "/sys/bus/usb/devices" ]; then
		debug "Fetching connected USB devices by using \"%s\".\n" "/sys/bus/usb/devices"
		usb_devices=`cd /sys/bus/usb/devices/; ${grepbin} . */idProduct */idVendor */product */uevent | ${sortbin} | ${sedbin} -e "s/idProduct:\(.*\)$/idProduct:\1:/g" | ${sedbin} -e "s/idVendor:\(.*\)$/idVendor:\1:/g" | ${grepbin} -A 2 "idProduct" | ${sedbin} -e "s/^\(.*\):\(..*\):*$/\2/g"`
		usb_devices=`echo ${usb_devices} | ${sedbin} -e "s/: */:/g" | ${sedbin} -e "s/ -- /\\\n/g" | ${sortbin} | ${uniqbin} | ${sedbin} -e "s/^\(....\):\(....\):/\2:\1:/g" | ${sortbin} | ${uniqbin} | ${grepbin} -v "HCI Host Controller"`
	elif find_binary "lsusb"; then
		debug "Fetching connected USB devices by using \"%s\".\n" "${lsusbbin}"
		usb_devices=`safe_lsusb | ${sedbin} -e "s/\(.*\)ID \(....\):\(....\) \(.*\)$/\2:\3:\4/g" | ${sortbin} | ${uniqbin} | ${grepbin} -v "root hub"`
	else
		stop_fmt_error 7 "Unable to discover connected USB devices. Script will now abort."
	fi
	if [ "a${TIMEOUTOCCURED}" != "a" ]; then
		show_fmt_error "Seems like an electrical/USB bus error occured. You may need to replug your modem for it to properly work.\n"
		unset TIMEOUTOCCURED
	fi
	debug "Connected USB devices are:\n%s\n" "${usb_devices}"
	return 0
}

# Helper method. Prints equivalent of usb_devices only for those devices in $1
usb_device_list() {
	for condevice in $@
	do
		echo "${usb_devices}" | ${grepbin} "^${condevice}:"
	done
}

# Does scoring things to determine if which usb device looks like a sure candidate for being a modem.
# On success, returns 0 and sets usb_modems.
# On failure, returns 1
voodoo_connected_modems() {
	unset usb_modems
	need_binary "uname"
	debug "Voodoo mode employed to discover a possible modem.\n"
	debug "Attempting to enumerate interfaces.\n"
	uevents=`cd /sys/bus/usb/devices; ${grepbin} . [0-9]*/uevent 2> /dev/null`
	interfaces=`echo "${uevents}" | ${cutbin} -d/ -f1 -s | ${grepbin} ":" | ${sortbin} | ${uniqbin}` ; interfaces=`echo ${interfaces}`
	debug "uevent contents are:\n%s\n" "${uevents}"
	debug "Interfaces are:\n%s\n" "${interfaces}"
	unset orphaninterfaces; unset storageinterfaces; unset communicationdevices; unset suspectdevices; unset serialinterfaces; unset interruptinterfaces
	for intstr in ${interfaces}
	do
		intclass=`echo "${uevents}" | ${grepbin} "^${intstr}\/" | ${grepbin} "uevent:INTERFACE=" | ${cutbin} -d= -f2 -s | ${cutbin} -d/ -f1`
		[ "a${intclass}" = "a9" ] && continue
		intdriver=`echo "${uevents}" | ${grepbin} "^${intstr}\/" | ${grepbin} "uevent:DRIVER=" | ${cutbin} -d= -f2 -s | ${sedbin} -e "s/-/_/g"`
		intserial=0; [ "a${intdriver}" != "a" ] && intserial=`usb_serial_drivers ${intdriver} 2> /dev/null | ${wcbin} -w`; intserial=`echo ${intserial}`
		intpoint=`cd /sys/bus/usb/devices; ${grepbin} . ${intstr}/ep_*/type 2> /dev/null | ${grepbin} -i "interrupt$" | ${wcbin} -l`; intpoint=`echo ${intpoint}`
		intdevice=`echo "${intstr}" | ${cutbin} -d: -f1 -s`
		intvendor=`${catbin} /sys/bus/usb/devices/${intdevice}/idVendor 2> /dev/null`
		intmodemmaker=`${grepbin} -i "usb:v${intvendor}" /lib/modules/\`${unamebin} -r\`/modules.alias 2> /dev/null | ${cutbin} -d\  -f3 -s | ${sortbin} | ${uniqbin}`
		intmodemmaker=`usb_serial_drivers ${intmodemmaker} 2> /dev/null`
		intbrothers=`echo "${interfaces}" | ${trbin} " " "\n" | ${sedbin} -e "s/^\( *\)//g" | ${grepbin} "^${intdevice}:" | ${wcbin} -l`; intbrothers=`echo ${intbrothers}`
		if [ "a${intdriver}" = "a" ]; then
			orphaninterfaces="${orphaninterfaces} ${intstr} ${intstr} ${intstr}"
			debug "Added interface %s to orphan interfaces.\n" "${intstr}"
		fi
		if [ "a${intpoint}" = "a1" ]; then
			interruptinterfaces="${interruptinterfaces} ${intstr} ${intstr} ${intstr}"
			debug "Added interface %s to interrupt interfaces.\n" "${intstr}"
		fi
		if [ "a${intdriver}" = "ausb-storage" -o "a${intdriver}" = "ausb_storage" -o "a${intclass}" = "a8" ]; then
			storageinterfaces="${storageinterfaces} ${intstr} ${intstr} ${intstr} ${intstr}"
			debug "Added interface %s to storage interfaces.\n" "${intstr}"
			if [ "a${intbrothers}" = "a1" ]; then
				storageinterfaces="${storageinterfaces} ${intstr} ${intstr}"
				debug "+2 for being unique interface of device %s.\n" "${intdevice}"
			fi
			if [ "a${intbrothers}" = "a1" ] && [ "a${intmodemmaker}" != "a" ]; then
				storageinterfaces="${storageinterfaces} ${intstr} ${intstr} ${intstr}"
				debug "+3 for vendor %s being a modem maker.\n" "${intvendor}"
			fi
		fi
		if [ "a${intclass}" = "a2" ]; then
			communicationdevices="${communicationdevices} ${intstr} ${intstr}"
			debug "Added interface %s to communication interfaces.\n" "${intstr}"
		fi
		if [ "a${intclass}" = "a255" -o "a${intclass}" = "a224" ]; then
			suspectdevices="${suspectdevices} ${intstr}"
			debug "Added interface %s to suspect interfaces.\n" "${intstr}"
		fi
		if [ "a${intserial}" = "a1" ]; then
			serialinterfaces="${serialinterfaces} ${intstr} ${intstr} ${intstr} ${intstr} ${intstr}"
			debug "Added interface %s to serial interfaces.\n" "${intstr}"
		fi
	done
	unset interfaces; unset uevents
	unset intstr; unset intclass; unset intdriver; unset intserial; unset intpoint; unset intdevice; unset intvendor; unset intmodemmaker; unset intbrothers
	devicescore=`echo ${serialinterfaces} ${suspectdevices} ${communicationdevices} ${storageinterfaces} ${orphaninterfaces} ${interruptinterfaces} | ${trbin} " " "\n" | ${sedbin} -e "s/ //g" | ${grepbin} -v "^$" | ${cutbin} -d: -f1 -s | ${sortbin} | ${uniqbin} -c | ${sedbin} -e "s/^\( *\)//g" | ${sedbin} -e "s/\(  *\)/ /g" | ${sedbin} -e "s/^\([0-9]\) /0\1 /g" | ${sedbin} -e "s/^\([0-9][0-9]\) /0\1 /g" | ${sedbin} -e "s/^\([0-9][0-9][0-9]\) /0\1 /g" | ${sortbin} -r`
	interfacescore=`echo ${serialinterfaces} ${suspectdevices} ${communicationdevices} ${storageinterfaces} ${orphaninterfaces} ${interruptinterfaces} | ${trbin} " " "\n" | ${sedbin} -e "s/ //g" | ${grepbin} -v "^$" | ${sortbin} | ${uniqbin} -c | ${sedbin} -e "s/^\( *\)//g" | ${sedbin} -e "s/\(  *\)/ /g" | ${sedbin} -e "s/^\([0-9]\) /0\1 /g" | ${sedbin} -e "s/^\([0-9][0-9]\) /0\1 /g" | ${sedbin} -e "s/^\([0-9][0-9][0-9]\) /0\1 /g" | ${sortbin} -r`
	unset serialinterfaces; unset suspectdevices; unset communicationdevices; unset storageinterfaces; unset orphaninterfaces; unset interruptinterfaces;
	debug "Device score is:\n%s\n" "${devicescore}"
	debug "Interface score is:\n%s\n" "${interfacescore}"
	besttwo=`echo "${interfacescore}" | ${headbin} -2 | ${cutbin} -d\  -f2 -s | ${cutbin} -d: -f1 -s | ${uniqbin}`
	besttwocount=`echo "${besttwo}" | ${wcbin} -w`; besttwocount=`echo ${besttwocount}`
	if [ "a${besttwocount}" != "a" ] && [ "${besttwocount}" -eq "1" ]; then
		intvendor=`${catbin} /sys/bus/usb/devices/${besttwo}/idVendor 2> /dev/null`
		intproduct=`${catbin} /sys/bus/usb/devices/${besttwo}/idProduct 2> /dev/null`
		if usb_device_connected "${intvendor}:${intproduct}"; then
			export usb_modems="${intvendor}:${intproduct}"
			unset intvendor; unset intproduct
			debug "Voodoo operations determined device %s (%s) is a modem.\n" "${usb_modems}" "${besttwo}"
			unset besttwocount; unset besttwo; unset interfacescore; unset devicescore
			return 0
		fi
		unset intvendor; unset intproduct
	fi
	debug "No device is the absolute winner. Will check for dominating score.\n"
	firstscore=`echo "${interfacescore}" | ${headbin} -1 | ${cutbin} -d\  -f1 -s | ${sedbin} -e "s/^\(0*\)//g" | ${sedbin} -e "s/^$/0/g"`
	firstscore=`${printfbin} "%d\n" "${firstscore}" 2> /dev/null`; [ "a${firstscore}" = "a" ] && firstscore=0
	secondscore=`echo "${interfacescore}" | ${headbin} -2 | ${tailbin} -1 | ${cutbin} -d\  -f1 -s | ${sedbin} -e "s/^\(0*\)//g" | ${sedbin} -e "s/^$/0/g"`
	secondscore=`${printfbin} "%d\n" "${secondscore}" 2> /dev/null`; [ "a${secondscore}" = "a" ] && secondscore=0
	if [ "a${firstscore}" != "a" -a "a${secondscore}" != "a" ] && [ "a${firstscore}" != "a${secondscore}" ] && [ "${firstscore}" -gt "0" -a "${firstscore}" -gt "${secondscore}" ]; then
		secondscore=`expr ${secondscore} + ${secondscore}`; secondscore=`echo ${secondscore}`
		if [ "${firstscore}" -gt "${secondscore}" ]; then
			besttwo=`echo "${interfacescore}" | ${headbin} -1 | ${cutbin} -d\  -f2 -s | ${cutbin} -d: -f1 -s | ${uniqbin}`
			intvendor=`${catbin} /sys/bus/usb/devices/${besttwo}/idVendor 2> /dev/null`
			intproduct=`${catbin} /sys/bus/usb/devices/${besttwo}/idProduct 2> /dev/null`
			if usb_device_connected "${intvendor}:${intproduct}"; then
				export usb_modems="${intvendor}:${intproduct}"
				unset intvendor; unset intproduct
				debug "Device %s (%s) out-numbered second candidate and will be considered a modem.\n" "${usb_modems}" "${besttwo}"
				unset firstscore; unset secondscore
				unset besttwocount; unset besttwo; unset interfacescore; unset devicescore
				return 0
			fi
		fi
	fi
	unset firstscore; unset secondscore
	debug "No device dominates the other in score. Cannot decide.\n"
	unset besttwo; unset besttwocount; unset interfacescore; unset devicescore
	return 1
}

# Attempts to get connected modems, and sets usb_modems and usb_modem_devices variables
usb_connected_modems() {
	unset usb_modems; unset usb_modem_devices
	[ "a${KNOWN_devices}" = "a" ] && ! modeswitch_load && return 1
	! usb_connected_devices && return 1
	connectedevices=`echo "${usb_devices}" | ${cutbin} -d: -f1,2`
	for condevice in ${connectedevices}
	do
		devfound=`${printfbin} "%s\n%s\n%s\n" "${KNOWN_devices}" "${MODEM}" "${USBMODEM}" | ${grepbin} "${condevice}"`
		[ "a${devfound}" != "a" ] && usb_modems="${usb_modems} ${condevice}"
		unset devfound
	done
	unset condevice; unset connectedevices
	usb_modems=`echo ${usb_modems}`
	export usb_modems
	if [ "a${usb_modems}" = "a" ] && unset usb_modems; then
		debug "No plugged modems found.\n"
		! voodoo_mode && return 1
		! voodoo_connected_modems && return 1
	fi
	usb_modem_devices=`usb_device_list ${usb_modems}`
	export usb_modem_devices
	debug "Connected USB modems are:\n%s\n" "${usb_modem_devices}"
	return 0
}

# Returns true if device $1 is currently connected
usb_device_connected() {
	[ "a$1" = "a" ] && return 99
	usb_connected_devices
	usbconnected=`echo "${usb_devices}" | ${cutbin} -d: -f1,2 | ${grepbin} "^$1"`
	[ "a${usbconnected}" = "a$1" ] && unset usbconnected && return 0
	unset usbconnected
	debug "Device \"%s\" is not connected.\n" "$1"
	return 1
}

# Parses /proc/bus/usb/devices and only returns block referring to $1.
usb_device_block() {
	unset usbdeviceblock
	[ "a$1" = "a" ] && return 1
	if [ -r "/proc/bus/usb/devices" ]; then
		usbvend=`echo "$1" | ${cutbin} -d: -f1`
		usbprod=`echo "$1" | ${cutbin} -d: -f2`
		usbdevcat=`safe_cat /proc/bus/usb/devices`
		usblines=`${printfbin} "%s\n\n" "${usbdevcat}" | ${grepbin} -A 60 "=${usbvend} \(.*\)=${usbprod}" | ${grepbin} -n "^$" | ${headbin} -1 | ${sedbin} -e "s/:$//g"`; usblines=`echo ${usblines}`
		[ "a${usblines}" = "a" ] && usblines=0
		[ "${usblines}" -gt "0" ] && usbdeviceblock=`echo "${usbdevcat}" | ${grepbin} -A 60 "Vendor=${usbvend} ProdID=${usbprod}" | ${headbin} -${usblines}`
		unset usblines; unset usbvend; unset usbprod; unset usbdevcat
		echo "${usbdeviceblock}" | ${grepbin} -v "^$"
		return 0
	fi
	return 1
}

# Filters arguments and returns back only those that usb serial drivers
usb_serial_drivers() {
	[ "a${kernel}" = "a" ] && find_binary "uname" && kernel=`${unamebin} -r`
	[ "a${kernel}" = "a" ] && return 1
	export kernel
	for driver in $@
	do
		[ -f "/lib/modules/${kernel}/kernel/drivers/usb/serial/${driver}.ko" ] && echo "${driver}" && continue
		[ "a${driver}" = "acdc_acm" ] && [ -f "/lib/modules/${kernel}/kernel/drivers/usb/class/cdc-acm.ko" ] && echo "${driver}"
	done
}

# Attempts to find appropriate driver for USB device $1, and sets USBDRIVER
usb_serial_detect_driver() {
	unset USBDRIVER
	[ "a$1" = "a" ] && return 99
	serialvend=`echo "$1" | ${cutbin} -d: -f1`
	serialprod=`echo "$1" | ${cutbin} -d: -f2`
	if ! find_binary "uname"; then
		debug "Failed to locate running kernel's modules. Uname missing.\n"
	else
		kernel=`${unamebin} -r`
		if [ -f "/lib/modules/${kernel}/modules.alias" ]; then
			drivercandidates=`${grepbin} -i "usb:v${serialvend}p${serialprod}" "/lib/modules/${kernel}/modules.alias" | ${cutbin} -d\  -f3 | ${sortbin} | ${uniqbin}`;
			drivercandidates=`usb_serial_drivers ${drivercandidates}`
			if [ "a${drivercandidates}" = "a" ]; then
				debug "No perfect match found for device \"%s\".\n" "$1"
				debug "Will seek if exists a driver for other devices from vendor \"%s\".\n" "${serialvend}"
				drivercandidates=`${grepbin} -i "usb:v${serialvend}p" "/lib/modules/${kernel}/modules.alias" | ${cutbin} -d\  -f3 | ${sortbin} | ${uniqbin}`;
				drivercandidates=`usb_serial_drivers ${drivercandidates}`
				if [ "a${drivercandidates}" = "a" ]; then
					debug "No candidates were found.\n"
				else
					debug "Found driver(s) for other devices of same vendor: %s\n" "${drivercandidates}"
				fi
				drivercandidates=`echo "${drivercandidates}" | ${trbin} " " "\n" | ${sedbin} -e "s/ //g" | ${sortbin} | ${uniqbin}`
			else
				debug "Found driver(s) available for \"%s\": %s\n" "$1" "${drivercandidates}"
			fi
		fi
		unset kernel
	fi
	if base_drivers "${serialvend}" "${serialprod}"; then
		drivercandidates=`echo ${drivercandidates} ${basedrivercandidates}`
		unset basedrivercandidates
	fi
	drivercandidates=`echo ${drivercandidates} | ${trbin} " " "\n" | ${sedbin} -e "s/ //g" | ${sortbin} | ${uniqbin}`
	candidatenum=`echo ${drivercandidates} | ${wcbin} -w`; candidatenum=`echo ${candidatenum}`
	if [ "a${candidatenum}" = "a1" ]; then
		USBDRIVER=`echo ${drivercandidates}`
		export USBDRIVER
		debug "Only one candidate, will use it unconditionally: %s\n" "${USBDRIVER}"
		unset candidatenum; unset drivercandidates; unset serialvend; unset serialprod
		return 0
	elif [ "a${candidatenum}" = "a0" ]; then
		drivercandidates="option"
		debug "No driver found, will propose \"%s\" driver.\n" "${drivercandidates}"
		if usb_usable_interfaces "$1" && [ "a${usableinterfacecount}" != "a" ] && [ "${usableinterfacecount}" -gt "1" ]; then
			debug "Device has %d usable interfaces. Will propose cdc_acm also.\n"
			drivercandidates="cdc_acm option"
		fi
	fi
	debug "Driver candidates are: %s\n" "${drivercandidates}"
	if voodoo_mode; then
		for safetoprobe in cdc_acm
		do
			debug "Will try safe to probe driver %s.\n" "${safetoprobe}"
			if module_bind "${safetoprobe}" "$1"; then
				debug "Appropriate driver %s determined.\n" "${safetoprobe}"
				export USBDRIVER="${safetoprobe}"
				unset candidatenum; unset drivercandidates; unset serialvend; unset serialprod
				return 0
			else
				debug "Determined %s is not a valid candidate. Will make sure is not within list of candidates either.\n" "${safetoprobe}"
				drivercandidates=`echo ${drivercandidates} | ${sedbin} -e "s/\( *\)${safetoprobe}\( *\)/ /g" | ${sedbin} -e "s/  / /g"`
				drivercandidates=`echo ${drivercandidates}`
				debug "Driver candidates are: %s\n" "${drivercandidates}"
			fi
		done
	fi
	drivers=`echo ${drivercandidates} | ${trbin} " " "\n" | ${sedbin} -e "s/^\( *\)\(.*\)\( *\)$/\2/g" | ${sortbin} | ${uniqbin} | ${sedbin} -e "s/^\(.*\)$/\"\1\" \"\1 kernel module\"/g"`
	eval user_select \"USBDRIVER\" \"Please select appropriate driver\" \"Select kernel module that should be used.\" \"Select\" \"Cancel\" ${drivers} \"OTHER\" \"Other driver...\"
	case "$?" in
		0)
			unset drivers
			unset candidatenum; unset drivercandidates; unset serialvend; unset serialprod
			return 98
			;;
		98)
			unset drivers
			unset candidatenum; unset drivercandidates; unset serialvend; unset serialprod
			return 98
			;;
		99)
			unset drivers
			unset candidatenum; unset drivercandidates; unset serialvend; unset serialprod
			return 99
			;;
		*)
			case "a${USBDRIVER}" in
				aOTHER)
					unset USBDRIVER
					user_prompt "USBDRIVER" "Please enter name of driver" "Enter name of appropriate kernel module that should be used, or leave empty to abort" "OK" "Cancel"
					if [ "a${USBDRIVER}" != "a" ]; then
						unset drivers
						unset candidatenum; unset drivercandidates; unset serialvend; unset serialprod
						return 0
					fi
					usb_serial_detect_driver "$@"
					return $?
					;;
				*)
					unset drivers
					unset candidatenum; unset drivercandidates; unset serialvend; unset serialprod
					return 0
					;;
			esac
			;;
	esac
	return 99
}

# Returns driver attached to interface $2 of device $1
usb_loaded_driver() {
	[ "a$1" = "a" ] && return 99
	if [ -r "/proc/bus/usb/devices" ]; then
		usbblock=`usb_device_block "$1"`; [ "a${usbblock}" = "a" ] && return 7
		if [ "a$2" != "a" ]; then
			usbdriver=`echo "${usbblock}" | ${grepbin} "^I:\(.*\)If.=\( *\)$2 " | ${sedbin}  -e "s/^I:\(.*\)If.=\( *\)$2 \(.*\) Driver=\(.*\)/\4/g"`
		else
			usbdriver=`echo "${usbblock}" | ${grepbin} "^I:\(.*\)If.=" | ${sedbin}  -e "s/^I:\(.*\)If.=\( *\) \(.*\) Driver=\(.*\)/\4/g"`
		fi
		case "a${usbdriver}" in
			a)
				usbdriver="FAIL"
				echo ${usbdriver}
				unset usbdriver
				return 1
				;;
			"a(none)")
				usbdriver="NONE"
				echo ${usbdriver}
				unset usbdriver
				return 0
				;;
			*)
				usbdriver=`echo ${usbdriver} | ${trbin} "-" "_"`
				usbdriver=`echo ${usbdriver} | ${sedbin} -e "s/usbserial_generic/usbserial/g"`
				echo ${usbdriver}
				unset usbdriver
				return 1
		esac
	elif usb_sysfsdir "$1"; then
		if [ "a$2" != "a" ]; then
			usbdriver=`${grepbin} . ${sysfsloc}/*-*\:*.$2/uevent | ${grepbin} -i DRIVER= | ${cutbin} -d= -f2 -s`
		else
			usbdriver=`${grepbin} . ${sysfsloc}/*-*\:*.*/uevent | ${grepbin} -i DRIVER= | ${cutbin} -d= -f2 -s`; usbdriver=`echo ${usbdriver}`
		fi
		usbdriver=`echo ${usbdriver} | ${trbin} "-" "_"`
		usbdriver=`echo ${usbdriver} | ${sedbin} -e "s/usbserial_generic/usbserial/g"`
		[ "a${usbdriver}" = "a" ] && usbdriver="NONE"
		echo ${usbdriver}
		unset usbdriver
		return 0
	else
		debug "Unable to determine driver attached to interface %s of device %s.\n" "$2" "$1"
		usbdriver="FAIL"
		echo ${usbdriver}
		unset usbdriver
		return 1
	fi
}

usb_usable_interfaces() {
	unset usableinterfaces; usableinterfacecount=0
	[ "a$1" = "a" ] && return 99
	if [ -r "/proc/bus/usb/devices" ]; then
		debug "Using information of %s to determine usable interfaces.\n" "/proc/bus/usb/devices"
		usbblock=`usb_device_block "$1"`
		usbinter=`echo "${usbblock}" | ${grepbin} "^I:" | ${wcbin} -l`; usbinter=`echo ${usbinter}`
		debug "USB Device %s provides %d interface(s).\n" "$1" "${usbinter}"
		usbinter=`echo "${usbblock}" | ${grepbin} "(I)\(.*\)Atr=...Int\.. " | ${wcbin} -l`; usbinter=`echo ${usbinter}`
		debug "USB Device %s provides %d interruptable endpoint(s).\n" "$1" "${usbinter}"
		if [ "a${usbinter}" = "a0" -o "a${usbinter}" = "a" ]; then
			debug "USB device block output was:\n%s\n" "${usbblock}"
			debug "No modem lines on USB device \"%s\". Device may need switching.\n" "$1"
		else
			usbinter=`echo "${usbblock}" | ${grepbin} "(I)\(.*\)Atr=...Int\.. " | ${sedbin} -e "s/^E:\(.*\)Ad=\(.*\)(I)\(.*\)Atr=...Int\..\(.*\)$/\2/g"`; usbinter=`echo ${usbinter}`
			debug "Interruptable endpoint(s) are: %s\n" "${usbinter}"
			unset USB_INTERFACE
			for endpoint in ${usbinter}
			do
				localinter=`echo "${usbblock}" | ${grepbin} -B 10 "^E\(.*\)Ad=${endpoint}(I)" | ${grepbin} "^I" | ${tailbin} -1 | ${sedbin} -e "s/^\(.*\)If.=\( *\)\([0-9][0-9]*\) \(.*\)$/\3/g"`
				if [ "a${localinter}" != "a" ]; then
					localinter=`${printfbin} "%d\n" ${localinter} 2> /dev/null`
					if [ "a${localinter}" != "a" ]; then
						debug "Added interface %s, containing endpoint %s.\n" "${localinter}" "${endpoint}"
						usableinterfaces="${usableinterfaces} ${localinter}"
					fi
				fi
				unset localinter
			done
			unset localinter; unset endpoint
		fi
		unset usbinter; unset usbblock
		usableinterfaces=`echo ${usableinterfaces}`
		export usableinterfaces
		debug "Interfaces collected from %s are: %s\n" "/proc/bus/usb/devices" "${usableinterfaces}"
	fi
	if find_binary "lsusb"; then
		debug "Using information of %s to determine usable interfaces.\n" "lsusb"
		usbvend=`echo "$1" | ${cutbin} -d: -f1`; usbprod=`echo "$1" | ${cutbin} -d: -f2`
		usbblock=`safe_lsusb -v -d ${usbvend}:${usbprod}`
		usbinter=`echo "${usbblock}" | ${sedbin} -e "s/  */ /g" | ${grepbin} -i "transfer type interrupt" | ${wcbin} -l`; usbinter=`echo ${usbinter}`
		debug "USB Device %s provides %d interruptable endpoint(s).\n" "$1" "${usbinter}"
		if [ "a${usbinter}" = "a0" -o "a${usbinter}" = "a" ]; then
			debug "lsusb output was:\n%s\n" "${usbblock}"
			debug "No modem lines on USB device \"%s\". Device may need switching.\n" "$1"
			unset usbinter
		else
			# Enter character after "interrupt" word on following line IS NOT a mistake
			usbinter=`echo "${usbblock}" | ${sedbin} -e "s/  */ /g" | ${grepbin} -F -i "transfer type interrupt
binterfacenumber" | ${grepbin} -B 1 -i interrupt | ${grepbin} -i "binterfacenumber" | ${cutbin} -d\  -f3 -s`; usbinter=`echo ${usbinter}`
		fi
		debug "Interfaces collected from %s are: %s\n" "lsusb" "${usbinter}"
		[ "a${usbinter}" != "a" ] && usableinterfaces=`echo "${usableinterfaces} ${usbinter}"`
		export usableinterfaces
		unset usbvend; unset usbprod; unset usbblock; unset usbinter;
	elif [ ! -r "/proc/bus/usb/devices" ]; then
		debug "Failed to read USB information.\n"
		show_fmt_error "Both \"%s\" and \"%s\" are missing." "lsusb" "/proc/bus/usb/devices"
		return 7
	fi
	if [ "a${TIMEOUTOCCURED}" != "a" ]; then
		show_fmt_error "Seems like an electrical/USB bus error occured. You may need to replug your modem for it to properly work.\n"
		unset TIMEOUTOCCURED
	fi
	usableinterfaces=`echo ${usableinterfaces} | ${trbin} " " "\n" | ${sedbin} -e "s/ //g" | ${sortbin} | ${uniqbin}`
	usableinterfaces=`echo ${usableinterfaces}`
	usableinterfacecount=`echo ${usableinterfaces} | ${wcbin} -w`; usableinterfacecount=`echo ${usableinterfacecount}`
	return 0
}

usb_get_interface() {
	unset USB_INTERFACE
	[ "a$1" = "a" ] && return 99
	usb_usable_interfaces "$1"
	ret=$?; [ "a${ret}" != "a0" ] && return ${ret}
	USB_INTERFACE=`echo ${usableinterfaces}`
	export USB_INTERFACE
	if [ "a${USB_INTERFACE}" = "a" -o "a${usableinterfacecount}" = "a0" ]; then
		debug "Failed to locate any usable interface for device %s.\n" "$1"
		unset USB_INTERFACE
		return 8
	fi
	debug "Collected %d interface(s): %s\n" "${usableinterfacecount}" "${USB_INTERFACE}"
	if [ "a${usableinterfacecount}" = "a1" ]; then
		debug "Only one interface available. Will use that one unconditionally.\n"
		return 0
	fi
	usbvend=`echo "$1" | ${cutbin} -d: -f1 -s`
	usbprod=`echo "$1" | ${cutbin} -d: -f2 -s`
	if base_drivers "${usbvend}" "${usbprod}"; then
		if [ "a${baseintercandidates}" != "a" ]; then
			ifvalid=`echo ${USB_INTERFACE} | ${trbin} " " "\n" | ${grepbin} "^${baseintercandidates}$"`
			if [ "a${ifvalid}" = "a${baseintercandidates}" ]; then
				if [ "a${USBINTERFACE}" = "a" ]; then
					export USB_INTERFACE="${baseintercandidates}"
					debug "Will use interface #%d derived by config.\n" "${USB_INTERFACE}"
					unset ifvalid; unset usbvend; unset usbprod; unset baseintercandidates
					return 0
				else
					debug "However, will not use it in favor of already selected USBINTERFACE: %s\n" "${USBINTERFACE}"
				fi
			else
				debug "However, this interface is not available from device.\n"
			fi
			unset ifvalid
		else
			debug "Config does not specify interface for device %s.\n" "$1"
		fi
		unset baseintercandidates
	else
		debug "No configuration for device %s.\n" "$1"
	fi
	unset usbvend; unset usbprod
	if flow_select_interface "$1" "${USB_INTERFACE}"; then
		[ "a${USBINTERFACE}" = "a" ] && return 98
		export USB_INTERFACE="${USBINTERFACE}"
		debug "Will use interface #%d of USB device \"%s\".\n" "${USB_INTERFACE}" "$1"
		return 0
	else
		unset USB_INTERFACE
		debug "User did not provide an interface.\n"
		return 98
	fi
	return 99
}

usb_sysfsdir() {
	unset sysfsloc
	[ "a$1" = "a" ] && return 1
	! find_binary "dirname" && return 1
	usbven=`echo "$1" | ${cutbin} -d: -f1`; usbpro=`echo "$1" | ${cutbin} -d: -f2`
	venentry=`${grepbin} -H . /sys/bus/usb/devices/*/*/idVendor 2> /dev/null | ${grepbin} ":${usbven}$"`
	if [ "a${venentry}" != "a" ]; then
		for ff in ${venentry}
		do
			unset dirloc
			dirloc=`${dirnamebin} \`echo ${ff} | ${sedbin} -e "s/:${usbven}$//g"\` 2> /dev/null`
			if [ "a${dirloc}" != "a" ]; then
				if [ -d "${dirloc}" ]; then
					dirpro=`${catbin} ${dirloc}/idProduct`
					if [ "a${dirpro}" = "a${usbpro}" ]; then
						export sysfsloc="${dirloc}"
						debug "Device %s sysfs dir found: %s\n" "$1" "${sysfsloc}"
						unset dirpro; unset dirloc; unset venentry; unset usbven; unset usbpro
						return 0
					fi
					unset dirpro
				fi
			fi
			unset dirloc
		done
	fi
	debug "No device %s located in sysfs.\n" "$1"
	unset venentry;	unset usbven; unset usbpro
	return 1
}

usb_sysfsdir_int() {
	unset sysfsintloc
	[ "a$1" = "a" -o "a$2" = "a" ] && return 99
	! usb_sysfsdir "$1" && return 1
	intnum="$2"; [ "${intnum}" -lt "10" ] && intnum="0$2"
	intdir=`${grepbin} "." ${sysfsloc}/*/bInterfaceNumber | ${grepbin} "bInterfaceNumber:${intnum}$" | ${sedbin} -e "s/bInterfaceNumber:${intnum}$/bInterfaceNumber/g"`; intdir=`${dirnamebin} "${intdir}" 2> /dev/null`; unset intnum
	if [ "a${intdir}" = "a" ]; then
		unset intdir; debug "Failed to retrieve sysfs directory of interface #%d.\n" "$2"
		return 1
	elif [ ! -d "${intdir}" ]; then
		unset intdir; debug "Unable to retrieve sysfs directory of interface #%d.\n" "$2"
		return 1
	fi
	debug "Interface #%d sysfs dir is: %s\n" "$2" "${intdir}"
	export sysfsintloc="${intdir}"
	unset intdir
	return 0
}

# Finds tty which resides on interface $2 of usb device $1 and sets USBTTY
usb_sysfs_locate_tty() {
	unset USBTTY
	[ "a$1" = "a" -o "a$2" = "a" ] && return 99
	! usb_sysfsdir_int "$1" "$2" && return 1
	intstr=`cd ${sysfsintloc} ; ${grepbin} -H "." tty*/dev tty*/tty*/dev tty*/tty*/tty*/dev 2> /dev/null | ${sortbin} | ${uniqbin}`; unset intdir
	if [ "a${intstr}" = "a" ]; then
		unset intstr; debug "Failed to retrieve sysfs tty for interface #%d.\n" "$2"
		return 1
	fi
	debug "Interface #%d tty string is: %s\n" "$2" "${intstr}"
	unset ttynode
	[ "a${ttynode}" = "a" ] && ttynode=`echo "${intstr}" | ${sedbin} -e "s/^\(.*\)ttyUSB\([0-9][0-9]*\)\(.*\)$/ttyUSB\2/g" | ${grepbin} "^ttyUSB"`
	[ "a${ttynode}" = "a" ] && ttynode=`echo "${intstr}" | ${sedbin} -e "s/^\(.*\)ttyACM\([0-9][0-9]*\)\(.*\)$/ttyACM\2/g" | ${grepbin} "^ttyACM"`
	[ "a${ttynode}" = "a" ] && ttynode=`echo "${intstr}" | ${sedbin} -e "s/^\(.*\)ttyHS\([0-9][0-9]*\)\(.*\)$/ttyHS\2/g" | ${grepbin} "^ttyHS"`
	devicenode=`echo "${intstr}" | ${sedbin} -e "s/^\(.*\)dev:\([0-9][0-9]*\):\([0-9][0-9]*\)$/\2:\3/g"`
	ttymajor=`echo "${devicenode}" | ${cutbin} -d: -f1`
	ttyminor=`echo "${devicenode}" | ${cutbin} -d: -f2`
	unset intstr; unset devicenode
	debug "Will check if \"%s\" exists, or will create it with major %d and minor %d.\n" "/dev/${ttynode}" "${ttymajor}" "${ttyminor}"
	if dev_create_node "/dev/${ttynode}" "${ttymajor}" "${ttyminor}"; then
		export USBTTY="/dev/${ttynode}"
		unset ttynode; unset ttymajor; unset ttyminor
		debug "Found tty device node of interface #%d from device \"%s\": %s\n" "$2" "$1" "${USBTTY}"
		return 0
	else
		debug "Failed to create tty device of interface #%d from device \"%s\".\n" "$2" "$1"
		unset ttynode; unset ttymajor; unset ttyminor
		return 8
	fi
	unset ttynode; unset ttymajor; unset ttyminor
	return 99
}

usb_sysfsattr() {
	unset SYSFS_USB_Manufacturer
	unset SYSFS_USB_Product
	unset SYSFS_USB_Serial
	[ "a$1" = "a" ] && return 1
	! usb_sysfsdir "$1" && return 1
	[ "a${sysfsloc}" = "a" ] && return 1
	[ ! -d "${sysfsloc}" ] && return 1
	SYSFS_USB_Manufacturer=`${sedbin} -e "s/ /_/g" "${sysfsloc}/manufacturer" 2> /dev/null`
	SYSFS_USB_Product=`${sedbin} -e "s/ /_/g" "${sysfsloc}/product" 2> /dev/null`
	SYSFS_USB_Serial=`${sedbin} -e "s/ /_/g" "${sysfsloc}/serial" 2> /dev/null`
	debug "Information from sysfs:\nUSB Manufacturer: %s\nUSB Product:      %s\nUSB Serial:       %s\n" "${SYSFS_USB_Manufacturer}" "${SYSFS_USB_Product}" "${SYSFS_USB_Serial}"
	return 0
}

usb_scsisysfsattr() {
	unset scsidir
	unset SYSFS_SCSI_Vendor
	unset SYSFS_SCSI_Model
	unset SYSFS_SCSI_Revision
	[ "a$1" = "a" ] && return 1
	! usb_sysfsattr "$1" && return 1
	! find_binary "dirname" && return 1
	# How many seconds to wait for SCSI device to settle
	counter=30
	while [ "a${scsidir}" = "a" ];
	do
		if [ "a$2" = "a" ]; then
			debug "Checking interface #%d of device %s.\n" "0" "$1"
			target=`${lsbin} -1d ${sysfsloc}/*.0/host*/target*/*/vendor 2> /dev/null`
		else
			debug "Checking interface #%d of device %s.\n" "$2" "$1"
			target=`${lsbin} -1d ${sysfsloc}/*.$2/host*/target*/*/vendor 2> /dev/null | ${tailbin} -1`
		fi
		[ "a${target}" != "a" ] && scsidir=`${dirnamebin} "${target}" 2> /dev/null`
		[ "a${scsidir}" = "a" ] && unset scsidir
		[ "a${scsidir}" != "a" ] && [ ! -d "${scsidir}" ] && unset scsidir
		unset target
		if [ "a${scsidir}" = "a" ]; then
			if [ "${counter}" -gt "0" ]; then
				debug "Device not yet settled. Will be waiting for another %d second(s).\n" "${counter}"
				[ "${counter}" -eq "30" ] && verbose "Waiting device to settle"
				sleep 1
			else
				debug "Giving up. SCSI device did not settle, or is switched already.\n"
				break
			fi
			counter=`expr ${counter} - 1`; counter=`echo ${counter}`
		fi
	done
	unset counter
	[ "a${scsidir}" = "a" ] && unset scsidir && return 1
	SYSFS_SCSI_Vendor=`${sedbin} -e "s/ /_/g" "${scsidir}/vendor" 2> /dev/null`
	SYSFS_SCSI_Model=`${sedbin} -e "s/ /_/g" "${scsidir}/model" 2> /dev/null`
	SYSFS_SCSI_Revision=`${sedbin} -e "s/ /_/g" "${scsidir}/rev" 2> /dev/null`
	debug "SCSI device is settled:\nSCSI Vendor:      %s\nSCSI Model:       %s\nSCSI Revision:    %s\n" "${SYSFS_SCSI_Vendor}" "${SYSFS_SCSI_Model}" "${SYSFS_SCSI_Revision}"
	return 0
}

# Returns true if device $1 has a storage interface
usb_has_storage() {
	unset STORAGEIF
	[ "a$1" = "a" ] && return 99
	if [ -r "/proc/bus/usb/devices" ]; then
		usbblock=`usb_device_block "$1"`
		if [ "a${usbblock}" = "a" ]; then
			if [ "a${TIMEOUTOCCURED}" != "a" ]; then
				show_fmt_error "Seems like an electrical/USB bus error occured. You may need to replug your modem for it to properly work.\n"
				unset TIMEOUTOCCURED
			fi
			debug "No information for device was available. Is device really connected?\n"
			debug "Will consider storage part does not exist.\n"
			debug "However, this may lead into problems later.\n"
			unset usbblock
			return 1
		fi
		storageclass=`echo "${usbblock}" | ${grepbin} "Cls=08.stor."`
		[ "a${storageclass}" = "a" ] && storageclass=`echo "${usbblock}" | ${grepbin} "river=usb_storage"`
		[ "a${storageclass}" = "a" ] && storageclass=`echo "${usbblock}" | ${grepbin} "river=usb-storage"`
		if [ "a${storageclass}" = "a" ]; then
			debug "Device \"%s\" has no storage part.\n" "$1"
			unset usbblock; unset storageclass
			return 1
		fi
		storageclass=`echo "${storageclass}" | ${sedbin} -e "s/^I:\(.*\)If.=\( *\)\([0-9][0-9]*\) \(.*\)$/\3/g"`
		debug "Device has storage part on interface #%s.\n" "${storageclass}"
		STORAGEIF=`echo "${storageclass}" | ${headbin} -1 | ${cutbin} "-d "  -f1`
		export STORAGEIF
		unset usbblock; unset storageclass
		return 0
	elif find_binary "lsusb"; then
		storageclass=`safe_lsusb -d "$1" -v | ${grepbin} -B 10 -A 10 -i storage | ${grepbin} -i "bInterfaceNumber" | ${tailbin} -1 | ${sedbin} -e "s/  */ /g" | ${sedbin} -e "s/^ //g" | ${cutbin} -d\  -f2`
		if [ "a${storageclass}" = "a" ]; then
			if [ "a${TIMEOUTOCCURED}" != "a" ]; then
				show_fmt_error "Seems like an electrical/USB bus error occured. You may need to replug your modem for it to properly work.\n"
				unset TIMEOUTOCCURED
			fi
			debug "Device \"%s\" has no storage part.\n" "$1"
			unset storageclass
			return 1
		fi
		debug "Device has storage part on interface #%s.\n" "${storageclass}"
		# TODO: What happens when more storage interfaces exist?
		STORAGEIF=`echo "${storageclass}" | ${headbin} -1 | ${cutbin} -d\  -f1`
		export STORAGEIF
		unset storageclass
		return 0
	else
		debug "Both %s and %s are not available.\n" "/proc/bus/usb/devices" "lsusb"
		debug "Failed to determine if device %s has a storage interface.\n" "$1"
		debug "Will consider storage part does not exist.\n"
		debug "However, this may lead into problems later.\n"
		return 1
	fi
}

# Newer kernels provide this feature
usb_stabilize() {
	[ "a$1" = "a" ] && return 1
	! usb_sysfsdir "$1" && return 1
	[ "a${sysfsloc}" = "a" ] && return 1
	[ ! -d "${sysfsloc}" ] && return 1
	[ ! -w "${sysfsloc}/avoid_reset_quirk" ] && return 1
	debug "Kernel provides AVOID_RESET_QUIRK for device %s.\n" "$1"
	echo "1" > "${sysfsloc}/avoid_reset_quirk" 2> /dev/null
	ret=$?
	[ "a${ret}" = "a0" ] && debug "Succesfully enabled AVOID_RESET_QUIRK for device %s.\n" "$1"
	[ "a${ret}" = "a0" ] && debug "Failed to enable AVOID_RESET_QUIRK for device %s.\n" "$1"
	return ${ret}
}

# Makes sure that if device $1 has a storage part, this part
# is settled.
usb_storage_settled() {
	if ! usb_has_storage "$1"; then
		hal_unlock
		return 0
	fi
	debug "Device %s, provides storage interface #%s.\n" "$1" "${STORAGEIF}"
	storageloaded=`usb_loaded_driver "$1" "${STORAGEIF}" | ${tailbin} -1`
	if [ "a${TIMEOUTOCCURED}" != "a" ]; then
		show_fmt_error "Seems like an electrical/USB bus error occured. You may need to replug your modem for it to properly work.\n"
		unset TIMEOUTOCCURED
	fi
	if [ "a${storageloaded}" != "ausb-storage" -a "a${storageloaded}" != "ausb_storage" ]; then
		debug "Interface %s of device %s is bound to driver: %s\n" "${STORAGEIF}" "$1" "${storageloaded}"
		debug "No need to wait for storage interface to settle.\n"
		unset storageloaded
		hal_unlock
		return 0
	fi
	debug "Storage interface #%s is binded by %s driver.\n" "${STORAGEIF}" "${storageloaded}"
	if [ "a${killstorage}" != "a" ]; then
		debug "User has set \"%s\" switch. Will try to unbind %s driver from interface #%d.\n" "killstorage" "${storageloaded}" "${STORAGEIF}"
		if module_unbind "${storageloaded}" "$1" "${STORAGEIF}"; then
			debug "Storage interface has been freed as instructed.\n"
			debug "No need to wait for storage interface to settle.\n"
			unset storageloaded
			hal_unlock
			return 0
		else
			debug "Failed to unbind it. Too bad.\n"
			show_fmt_error "Failed to unbind driver %s. I am sorry." "${storageloaded}"
		fi
	fi
	unset storageloaded
	if ! usb_scsisysfsattr "$1" "${STORAGEIF}"; then
		debug "Will consider storage part is settled.\n"
		debug "However, this may lead into problems later.\n"
	fi
	storagedevices=`${grepbin} . ${sysfsloc}/*.${STORAGEIF}/host*/target*/*/block*/size 2> /dev/null | ${grepbin} -v ":0$" | ${sedbin} -e "s/^\(.*\)\/block:\(.*\)\/size:\(.*\)$/\2/g" | ${trbin} "\n" " "`; storagedevices=`echo ${storagedevices}`
	if [ "a${storagedevices}" = "a" ]; then
		debug "No storage device(s) with inserted media exist. Safe to unlock HAL.\n"
		hal_unlock
		unset storagedevices; unset STORAGEIF
		return 0
	fi
	debug "Media found on following device(s) provided by interface #%s of device %s: %s\n" "${STORAGEIF}" "$1" "${storagedevices}"
	if [ "a${HAL_LOCK}" != "a" ]; then
		hal_unlock
		debug "HAL is unlocked. Checking if HAL will kick in.\n"
		pausecounter=21
		while [ "${pausecounter}" -gt "0" ]
		do
			blocking=""
			for blockdevice in ${storagedevices}
			do
				poller=`${psbin} -Af | ${grepbin} "hald" | ${grepbin} "storage"	| ${grepbin} "polling \(.*\)${blockdevice}" | ${grepbin} -v "${grepbin}"`
				if [ "a${poller}" = "a" ]; then
					debug "No polling process exists for %s.\n" "${blockdevice}"
					continue
				fi
				debug "Polling process exists for %s: %s\n" "${blockdevice}" "${poller}"
				poller=`${grepbin} "\/${blockdevice} " "/proc/mounts" 2> /dev/null`
				if [ "a${poller}" != "a" ]; then
					debug "Device %s mounted: %s\n" "${blockdevice}" "${poller}"
				else
					debug "Device %s still not mounted.\n" "${blockdevice}"
					blocking="${blocking} ${blockdevice}"
				fi
			done
			unset blockdevice; unset poller; blocking=`echo ${blocking}`
			if [ "a${blocking}" = "a" ]; then
				debug "HAL has finished mounting media on device(s): %s\n" "${storagedevices}"
				break
			fi
			pausecounter=`expr ${pausecounter} - 1`; pausecounter=`echo ${pausecounter}`
			if [ "${pausecounter}" -eq "0" ]; then
				debug "Giving up waiting for HAL to mount devices.\n"
				debug "This may lead into problems later on.\n"
			else 
				[ "${pausecounter}" -eq "20" ] && verbose "Waiting HAL to mount device(s)"
				debug "Waiting for HAL to mount all devices. %d second(s) to abort.\n" "${pausecounter}"
				sleep 1
			fi
		done
		unset poller; unset blockdevice
		unset pausecounter; unset blocking
	else
		debug "HAL was not locked. Will skip waiting for device mount.\n"
	fi
	unset storagedevices; unset STORAGEIF
	return 0
}


# Scans for bluetooth devices
bluetooth_scan_devices() {
	! find_binary "hcitool" && return 1
	verbose "Scanning bluetooth devices"
	bluetooth_devices=`${hcitoolbin} scan 2> /dev/null | ${grepbin} "^	" | ${sedbin} -e "s/^	\(.*\)	\(.*\)/\1	\2/g"`
	debug "Found bluetooth devices:\n%s\n" "${bluetooth_devices}"
	return 0
}

# Returns rfcomm channel for service $2 for device $1
bluetooth_rfcomm_channel() {
	! find_binary "sdptool" && return 0
	rfchannel=`${sdptoolbin} search --raw --bdaddr "$1" "$2" 2> /dev/null | ${grepbin} -A 1 --binary-files=text "RFCOMM" | ${grepbin} "UINT8" | ${sedbin} -e "s/^\(.*\)UINT8 \(.*\)/\2/g"`
	rfchannel=`echo ${rfchannel}`
	debug "Found RFCOMM channel \"%s\" of service \"%s\" on device \"%s\".\n" "${rfchannel}" "$2" "$1"
	[ "a${rfchannel}" != "a" ] && rfchannel=`${printfbin} "%d\n" ${rfchannel} 2> /dev/null`
	[ "a${rfchannel}" = "a" ] && rfchannel="0"
	debug "Returning RFCOMM channels \"%s\".\n" "`echo ${rfchannel}`"
	return `echo ${rfchannel} | ${cutbin} -d\  -f1`
}

# Returns true if device $1, channel $2 is on tty $3
# NOTE: Does not depend on bluetooth_rfcomm_dev because
#       bluetooth_rfcomm_dev only returns 1st valid
#       channel
bluetooth_rfcomm_match() {
	! find_binary "rfcomm" && return 1
	[ "a${3}" != "a" ] && [ ! -c "${3}" ] && return 1
	bluematch=`${rfcommbin} -a --raw | ${grepbin} --binary-files=text " $1 " | ${grepbin} --binary-files=text " channel $2 " | ${grepbin} "^\`${basenamebin} $3\`:" | ${wcbin} -l`; bluematch=`echo ${bluematch}`
	if [ "a${bluematch}" = "a1" ]; then
		debug "%s refers to RFCOMM channel %d of device %s.\n" "$3" "$2" "$1"
		unset bluematch
		return 0
	fi
	debug "%s does not refer to RFCOMM channel %d of device %s.\n" "$3" "$2" "$1"
	unset bluematch
	return 1
}

# Returns tty where device $1, channel $2 resides (if any)
bluetooth_rfcomm_dev() {
	! find_binary "rfcomm" > /dev/null && return 1
	bluematch=`${rfcommbin} -a --raw 2> /dev/null | ${grepbin} --binary-files=text " $1 " | ${grepbin} --binary-files=text " channel $2 " | ${headbin} -1 | ${cutbin} -d: -f1`
	if [ "a${bluematch}" = "a" ]; then
		unset bluematch
		return 1
	fi
	echo "${bluematch}"
	unset bluematch
	return 0
}

# Creates rfcomm device for device $1, channel $2 and sets RFCOMM_TTY
bluetooth_create_dev() {
	! we_are_root_already && debug "Need root privileges to create rfcomm nodes.\n"
	! we_are_root && return 1
	need_binary "rfcomm"
	for devindex in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
	do
		unset occupied
		occupied=`${rfcommbin} show ${devindex} 2> /dev/null`
		[ "a${occupied}" = "a" ] && break
	done
	if [ "a${occupied}" != "a" ]; then
		unset occupied
		unset devindex
		show_fmt_error "Unable to find available rfcomm device index. Minors occupied."
		return 1
	fi
	unset occupied
	debug "Found available rfcomm device node %d.\n" "${devindex}"
	debug run_command "${rfcommbin} bind ${devindex} \"$1\" \"$2\""
	if ! bluetooth_rfcomm_match "$1" "$2" "/dev/rfcomm${devindex}"; then
		show_fmt_error "Unable to create rfcomm node %s." "rfcomm${devindex}"
		unset devindex
		return 1
	fi
	if [ ! -c "/dev/rfcomm${devindex}" ]; then
		debug "Device node \"%s\" was not automatically created.\n" "/dev/rfcomm${devindex}"
		if ! dev_create_node "/dev/rfcomm${devindex}" "216" "${devindex}"; then
			show_fmt_error "Unable to create rfcomm device node \"%s\"." "/dev/rfcomm${devindex}"
			unset devindex
			return 1
		fi
		debug "Made node \"%s\" ourselves.\n" "/dev/rfcomm${devindex}"
	fi
	export RFCOMM_TTY="/dev/rfcomm${devindex}"
	unset devindex
}

# Setups rfcomm device for device $1, channel $2 and sets RFCOMM_TTY
bluetooth_setup_rfcomm() {
	if [ "a${RFCOMM_TTY}" != "a" ]; then
		if bluetooth_rfcomm_match "$1" "$2" "${RFCOMM_TTY}"; then
			debug "Will use already set RFCOMM_TTY (%s).\n" "${RFCOMM_TTY}"
			return 0
		else
			debug "Already set RFCOMM_TTY does not refer to a tty of \"%s\": \"%s\"\n" "$1" "${RFCOMM_TTY}"
			unset RFCOMM_TTY
		fi
	fi
	RFCOMM_TTY=`bluetooth_rfcomm_dev "$1" "$2"`
	if [ "a${RFCOMM_TTY}" != "a" ]; then
		export RFCOMM_TTY="/dev/${RFCOMM_TTY}"
		if [ -c "${RFCOMM_TTY}" ]; then
			debug "Found already binded rfcomm tty %s.\n" "${RFCOMM_TTY}"
			return 0
		fi
		unset RFCOMM_TTY
	fi
	unset RFCOMM_TTY
	if bluetooth_create_dev "$1" "$2"; then
		debug "Succesfully binded to rfcomm tty %s.\n" "${RFCOMM_TTY}"
		return 0
	fi
	debug "Failed to setup rfcomm tty for device \"%s\".\n" "$1"
	return 1
}

# Method invoked when "status" action was requested.
ppp_fast_status() {
	need_binary "grep"
	need_arg "pppint"
	unset status
	[ -f "/proc/net/dev" ] && [ -r "/proc/net/dev" ] && status=`${grepbin} "${pppint}:" /proc/net/dev`
	[ -z "${status}" ] && find_binary "ifconfig" && status=`${ifconfigbin} ${pppint} 2> /dev/null | ${grepbin} " UP "`
	if [ "a${status}" = "a" ]; then
		unset status
		return 1
	else
		unset status
		return 0
	fi
}

# Called by ispconnect to determine if connection is established
ppp_slow_status() {
	need_arg "pppint"
	need_binary "netstat"
	[ "a${pppint}" = "a" ] && pppint="ppp0"
	pppcon=`${catbin} /proc/net/dev | ${grepbin} "^\( *\)${pppint}:" | ${wcbin} -l`; pppcon=`echo ${pppcon}`
	[ "a${pppcon}" = "a0" ] && unset pppcon && return 1
	debug "Interface %s is up.\n" "${pppint}"
	pppcon=`${netstatbin} -rn | ${grepbin} " ${pppint}$" | ${grepbin} -v "^0.0.0.0" | ${wcbin} -l`; pppcon=`echo ${pppcon}`
	[ "a${pppcon}" = "a0" ] && unset pppcon && return 1
	debug "Default route through %s is established.\n" "${pppint}"
	debug "Really connected.\n"
	return 0
}

# Shows version
show_version() {
	if find_binary "printf"; then
		format_text "Sakis 3G All-in-one script - Version %s\n" "${MYVERSION}"
		format_text "(c) Sakis Dimopoulos 2009, 2010 under GNU GPL v2\n\n"
	else
		need_binary "echo"
		echo "Sakis 3G All-in-one script - Version ${MYVERSION}"
		echo "(c) Sakis Dimopoulos 2009, 2010 under GNU GPL v2"
		echo
	fi
}

# Shows usage help
show_help() {
	helptext=`raw_help`
	notify "%s\n" "${helptext}"
	return 0
}

raw_help() {
	[ "a${PROVIDER}" = "a" ] && return 1
	[ ! -x "${PROVIDER}" ] && return 1
	show_version
	echo
	"${PROVIDER}" getfile "files/help.txt" 2> /dev/null
}

modeswitch_load_realtime() {
	debug "Loading system supplied device database.\n"
	for dep in sed rm grep tr sort uniq cut printf basename
	do
		! find_binary "${dep}" && return 1
	done
	unset dep; unset realtime_switchable; unset realtime_switched;
	unset CheckSuccess; unset Configuration; 
	unset GCTMode; unset HuaweiMode; unset SierraMode; unset SonyMode; 
	unset Interface; unset MessageContent; unset ResponseNeeded
	unset DefaultProduct; unset DefaultVendor; 
	unset TargetClass; unset TargetProduct; unset TargetProductList; unset TargetVendor
	for filename in /etc/usb_modeswitch.d/* /etc/usb_modeswitch.d/*
	do
		current_device=`${basenamebin} ${filename} | ${cutbin} -d: -f1,2 -s`
		[ "a${current_device}" = "a" ] && unset current_device && continue
		realtime_switchable="${realtime_switchable} ${current_device}" 
		${sedbin} -e "s/ //g" "${filename}" > "/tmp/$$.tmp" 2> /dev/null
		. "/tmp/$$.tmp" > /dev/null 2> /dev/null
		${rmbin} -f "/tmp/$$.tmp" > /dev/null 2> /dev/null
		for ven in ${TargetVendor}
		do
			if [ -n "${TargetProductList}" ]; then
				list=`echo ${TargetProductList} | ${sedbin} -e "s/,/ /g"`
				for pro in $list
				do
					realtime_switched="${realtime_switched} ${ven}:${pro}"
				done
				unset list
			elif [ -n "${TargetProduct}" ]; then
				realtime_switched="${realtime_switched} ${ven}:${TargetProduct}"
			fi
		done
		unset current_device
		unset CheckSuccess; unset Configuration; 
		unset GCTMode; unset HuaweiMode; unset SierraMode; unset SonyMode; 
		unset Interface; unset MessageContent; unset ResponseNeeded
		unset DefaultProduct; unset DefaultVendor; 
		unset TargetClass; unset TargetProduct; unset TargetProductList; unset TargetVendor
	done
	realtime_switched=`echo ${realtime_switched} | ${sedbin} -e "s/0x//g" | ${trbin} " " "\n" | ${sortbin} | ${uniqbin}`
	realtime_switched=`echo ${realtime_switched}`
	realtime_switchable=`echo ${realtime_switchable} | ${sedbin} -e "s/0x//g" | ${trbin} " " "\n" | ${sortbin} | ${uniqbin}`
	realtime_switchable=`echo ${realtime_switchable}`
	debug "Switchable devices within system device database:\n%s\n" "${realtime_switchable}"
	debug "Switched devices within system device database:\n%s\n" "${realtime_switched}"
	${printfbin} "%s\n%s\n" "${realtime_switchable}" "${realtime_switched}"
	unset realtime_switched; unset realtime_switchable
	return 0
}

# Loads Usb-ModeSwitch device database, both embedded and system supplied
modeswitch_load() {
	unset SWITCHABLE_devices; unset SWITCHED_devices; unset KNOWN_devices
	debug "Loading Usb-ModeSwitch device database.\n"
	# Check if possible to include embedded database
	if [ "a${PROVIDER}" = "a" ]; then
		debug "Unable to locate package provider.\n"
	elif [ ! -x "${PROVIDER}" ]; then
		debug "Unable to execute package provider.\n"
	else
		"${PROVIDER}" getfile "build/switchconfig" > "/tmp/sakis3g.$$.sw"
		if [ ! -f "/tmp/sakis3g.$$.sw" ]; then
			debug "Unable to find device database.\n"
		elif [ ! -s "/tmp/sakis3g.$$.sw" ]; then
			rm -f "/tmp/sakis3g.$$.sw"
			debug "Embedded device database contains 0 entries.\n"
		else
			. "/tmp/sakis3g.$$.sw"
			rm -f "/tmp/sakis3g.$$.sw"
			getswitchabledevices 2> /dev/null
			# TODO: Comment following line to render embedded device database unusable.
			#unset usbswitchabledevices && unset usbswitcheddevices && debug "DELETED DATABASE TO EMULATE VOODOO MODE.\n"
			ret=$?; 
			if [ "${ret}" -ne "0" ]; then
				debug "Failed to load embedded Usb-ModeSwitch device database.\n"
			else
				debug "Embedded device database loaded.\n"
				export SWITCHABLE_devices="${usbswitchabledevices}"
				export SWITCHED_devices="${usbswitcheddevices}"
				debug "Switchable devices within embedded device database:\n%s\n" "${SWITCHABLE_devices}"
				debug "Switched devices within embedded device database:\n%s\n" "${SWITCHED_devices}"
				KNOWN_devices=`echo "${SWITCHABLE_devices} ${SWITCHED_devices}" | ${trbin} " " "\n" | ${sortbin} | ${uniqbin}`
				KNOWN_devices=`echo "${KNOWN_devices}"`
				export KNOWN_devices
				devicecount=`echo "${KNOWN_devices}" | ${wcbin} -w`; devicecount=`echo ${devicecount}`; [ "a${devicecount}" = "a" ] && devicecount=0
				debug "Embedded Usb-ModeSwitch device database contains %d entries.\n" "${devicecount}"
				unset devicecount
			fi
		fi
	fi
	# Check if system supplied Usb-ModeSwitch database exists
	if [ -d "/etc/usb_modeswitch.d" ]; then
		debug "Folder \"%s\" exists. Will check if it contains configuration files.\n" "/etc/usb_modeswitch.d"
		realtime_devices=`modeswitch_load_realtime`
		if [ "a${realtime_devices}" != "a" ]; then
			usbswitchabledevices=`echo "${realtime_devices}" | ${tailbin} -2 | ${headbin} -1`
			usbswitcheddevices=`echo "${realtime_devices}" | ${tailbin} -1`
			SWITCHABLE_devices="${SWITCHABLE_devices} ${usbswitchabledevices}"
			SWITCHED_devices="${SWITCHED_devices} ${usbswitcheddevices}"
			SWITCHABLE_devices=`echo "${SWITCHABLE_devices}" | ${trbin} " " "\n" | ${sortbin} | ${uniqbin}`
			SWITCHED_devices=`echo "${SWITCHED_devices}" | ${trbin} " " "\n" | ${sortbin} | ${uniqbin}`
			SWITCHABLE_devices=`echo ${SWITCHABLE_devices}`
			SWITCHED_devices=`echo ${SWITCHED_devices}`
			KNOWN_devices=`echo "${SWITCHABLE_devices} ${SWITCHED_devices}" | ${trbin} " " "\n" | ${sortbin} | ${uniqbin}`
			KNOWN_devices=`echo "${KNOWN_devices}"`
			export SWITCHABLE_devices
			export SWITCHED_devices
			export KNOWN_devices
			devicecount=`echo "${KNOWN_devices}" | ${wcbin} -w`; devicecount=`echo ${devicecount}`; [ "a${devicecount}" = "a" ] && devicecount=0
			debug "Device database now contains %d entries.\n" "${devicecount}"
			unset devicecount
		fi
		unset realtime_devices
	fi
	unset usbswitchabledevices; unset usbswitcheddevices
	return 0
}

# Returns 0 if device $1 is switchable
modeswitch_is_switchable() {
	[ "a${KNOWN_devices}" = "a" ] && ! modeswitch_load && return 1
	isswitchable=`echo "${SWITCHABLE_devices}" | ${grepbin} "$1" | ${wcbin} -l`; isswitchable=`echo ${isswitchable}`
	[ "a${isswitchable}" = "a" ] && isswitchable="0"
	if [ "a${isswitchable}" = "a0" ]; then
		if [ -f "/etc/usb_modeswitch.d/$1" ]; then
			debug "Since file \"%s\" exists, will consider device \"%s\" switchable.\n" "/etc/usb_modeswitch.d/$1" "$1"
			unset isswitchable
			return 0
		fi
		debug "Device \"%s\" is not switchable.\n" "$1"
		unset isswitchable
		return 1
	else
		unset isswitchable
		return 0
	fi
}

modeswitch_switchable_devices() {
	! usb_connected_modems && return 1
	for condevice in ${usb_modems}
	do
		if modeswitch_is_switchable "${condevice}"; then
			debug "There is at least one (%s) switchable device plugged.\n" "${condevice}"
			unset condevice
			return 0
		fi
	done
	unset condevice
	debug "No switchable device plugged.\n" "${condevice}"
	return 1
}

modeswitch_conf_realtime() {
	unset modeswitch_config
	debug "Seeking a system supplied configuration file for switching device %s.\n" "$1"
	[ ! -d "/etc/usb_modeswitch.d" -a ! -d "/etc/usb-modeswitch.d" ] && return 1
	# Check if exists a candidate which needs SCSI information
	needscsi=`${lsbin} -1r /etc/usb_modeswitch.d/$1:s* /etc/usb-modeswitch.d/$1:s* 2> /dev/null | ${wcbin} -l`
        needscsi=`echo ${needscsi}`
	if [ "a${needscsi}" != "a0" -a "a${needscsi}" != "a" ]; then
		debug "Will need SCSI information for finding appropriate file.\n"
		usb_scsisysfsattr "$1"
	fi
	unset needscsi
	# Iterate through files
	files=`${lsbin} -1r /etc/usb_modeswitch.d/$1* /etc/usb-modeswitch.d/$1* 2> /dev/null`
	for filename in ${files}
	do
		debug "Checking if file \"%s\" matches.\n" "${filename}"
		bn=`${basenamebin} "${filename}"`
		crit=`echo "${bn}" | ${cutbin} -d: -f3-`; crit=`echo ${crit}`
		if [ "a${crit}" != "a" ]; then
			field=`echo "${crit}" | ${cutbin} -d= -f1 -s`
			value=`echo "${crit}" | ${cutbin} -d= -f2 -s`
			if [ "a${field}" = "a" ]; then
				debug "File %s does not specify criteria to match. Skipping it." "${bn}"
				unset bn; unset crit; unset field; unset value
				continue
			fi
			if [ "a${value}" = "a" ]; then
				debug "File %s does not specify value for attribute %s. Skipping it." "${bn}" "${field}"
				unset bn; unset crit; unset field; unset value
				continue
			fi
			len=`echo "${value}" | ${wcbin} -c`; len=`echo ${len}`; len=`expr ${len} - 1 2> /dev/null`; len=`echo ${len}`
			if [ "a${len}" = "a" ] || [ "${len}" -eq "0" ]; then
				debug "Value \"%s\" to be checked is not valid. Skipping file %s." "${value}" "${bn}"
				unset bn; unset crit; unset field; unset value
				continue
			fi
			unset attribute
			case "${field}" in
				sVe)
					attribute=`echo ${SYSFS_SCSI_Vendor}`
					;;
				sMo)
					attribute=`echo ${SYSFS_SCSI_Model}`
					;;
				sRe)
					attribute=`echo ${SYSFS_SCSI_Revision}`
					;;
				uMa)
					attribute=`echo ${SYSFS_USB_Manufacturer}`
					;;
				uPr)
					attribute=`echo ${SYSFS_USB_Product}`
					;;
				uSe)
					attribute=`echo ${SYSFS_USB_Serial}`
					;;
				*)
					debug "FIXME: Unknown field \"%s\". Try downloading a newer Sakis3G version.\n" "${field}"
					;;
			esac
			if [ "a${attribute}" = "a" ]; then
				debug "No value for field %s exists for device %s.\n" "${field}" "$1"
				unset attribute; unset len; unset field; unset value; unset bn; unset crit
				continue
			fi
			debug "Found %s.%s=\"%s\".\n" "$1" "${field}" "${attribute}"
			attribute=`echo ${attribute} | ${cutbin} -b1-${len} 2> /dev/null`
			if [ "a${attribute}" != "a" -a "a${attribute}" = "a${value}" ]; then
				debug "File %s matches information derived from device.\n" "${bn}"
				modeswitch_config="${filename}"
				unset attribute; unset len; unset field; unset value; unset bn; unset crit
				break;
			fi
			debug "File %s does not match.\n" "${bn}"
			unset attribute; unset len; unset field; unset value;
		else
			debug "Found an exact match file: %s\n" "${filename}"
			modeswitch_config="${filename}"
		fi
		unset crit; unset bn
	done
	filename="${modeswitch_config}"
	unset modeswitch_config
	if [ "a${filename}" != "a" ] && [ -f "${filename}" ]; then
		${catbin} "${filename}" > "/tmp/sakis3g.sw.dev.$$" 2> /dev/null
		if [ -s "/tmp/sakis3g.sw.dev.$$" ]; then
			export modeswitch_config="/tmp/sakis3g.sw.dev.$$"
			unset filename
			return 0
		else
			${rmbin} -f "/tmp/sakis3g.sw.dev.$$"
		fi
	fi
	unset filename
	debug "No system supplied configuration file found for switching device \"%s\".\n" "$1"
	return 1
}

# Returns location of extracted configuration file that should be used to switch device $1 within modeswitch_config variable
modeswitch_conf_embedded() {
	unset modeswitch_config
	debug "Seeking embedded configuration file for switching device %s.\n" "$1"
	switchfunc="usbswitchconf_`echo "$1" | ${sedbin} -e "s/:/_/g"`"
	unset modeswitchconf
	eval ${switchfunc} 2> /dev/null
	ret=$?; unset switchfunc
	if [ "${ret}" -ne "0" ]; then
		debug "Failed to retrieve configuration for switching device \"%s\".\n" "$1"
		return 1
	fi
	[ "a${modeswitchconf}" = "a" ] && debug "No configuration file found for switching device \"%s\".\n" "$1" && return 1
	[ "a${PROVIDER}" = "a" ] && debug "Unable to locate package provider.\n" && unset modeswitchconf && return 1
	[ ! -x "${PROVIDER}" ] && debug "Unable to execute package provider.\n" && unset modeswitchconf && return 1
	eval "${PROVIDER}" getfile "${modeswitchconf}" > "/tmp/sakis3g.sw.dev.$$"
	[ ! -f "/tmp/sakis3g.sw.dev.$$" ] && debug "Configuration file \"%s\" for switching device \"%s\" not found within package.\n" "${modeswitchconf}" "$1" && unset modeswitchconf && return 1
	if [ ! -s "/tmp/sakis3g.sw.dev.$$" ]; then
		${rmbin} -f "/tmp/sakis3g.sw.dev.$$"
		debug "Configuration file \"%s\" for switching device \"%s\" not found within package.\n" "${modeswitchconf}" "$1"
		unset modeswitchconf
		return 1
	fi
	unset modeswitchconf
	export modeswitch_config="/tmp/sakis3g.sw.dev.$$"
	return 0
}

modeswitch_conf() {
	unset modeswitch_config
	debug "Seeking configuration file for switching device %s.\n" "$1"
	[ "a${KNOWN_devices}" = "a" ] && ! modeswitch_load && return 1
	! modeswitch_conf_embedded "$1" && modeswitch_conf_realtime "$1"
	if [ "a${modeswitch_config}" = "a" ] || [ ! -f "${modeswitch_config}" ] || [ ! -s "${modeswitch_config}" ]; then
		unset modeswitch_config
		show_fmt_error "Unable to locate a configuration file for switching device %s.\n" "$1"
		return 1
	fi
	debug run_command "${catbin} \"${modeswitch_config}\""
	debug "Configuration file for switching device \"%s\" at: %s\n" "$1" "${modeswitch_config}"
	return 0
}

# Executed when binary Usb-ModeSwitch is binary incompatible on running platform.
modeswitch_emergency() {
	! usb_has_storage "$1" && return 1
	debug "Will attempt to switch device by detaching usb-storage driver.\n"
	storageloaded=`usb_loaded_driver "$1" "${STORAGEIF}" | ${tailbin} -1`
	if [ "a${TIMEOUTOCCURED}" != "a" ]; then
		show_fmt_error "Seems like an electrical/USB bus error occured. You may need to replug your modem for it to properly work.\n"
		unset TIMEOUTOCCURED
	fi
	[ "a${storageloaded}" = "aNONE" ] && ! module_bind "usb_storage" "$1" "${STORAGEIF}"
	! module_unbind "usb_storage" "$1" "${STORAGEIF}"
	unset STORAGEIF
	return 0
}

# Switches device $1. Caller should check NEWIDS variable, because device most likely will change its ID.
modeswitch_switch() {
	[ "a$1" = "a" ] && return 1
	! modeswitch_is_switchable "$1" && return 1
	! modeswitch_conf "$1" && return 1
	[ ! -f "${modeswitch_config}" ] && debug "Configuration file \"%s\" disappeared.\n" "${modeswitch_config}"
	# Block hal from messing with us
	hal_acquire_lock "org.freedesktop.Hal.Device.Storage"
	verbose "Switching modem"
	debug "Connected devices before switching.\n"
	usb_connected_devices
	previously=`echo "${usb_devices}" | ${grepbin} -v "^$1:" | ${cutbin} -d: -f1,2`
	if [ "a${binaryfree}" = "a" ]; then
		debug run_command "${PROVIDER} usb_modeswitch -W -I -c \"${modeswitch_config}\""
		ret=$?
	else
		ret=95
	fi
	if [ "${ret}" -eq "95" ]; then
		[ "a${binaryfree}" = "a" ] && debug "Binary incompatibility of package provided usb-modeswitch.\n"
		if find_binary "usb_modeswitch"; then
			debug "Will try system provided binary, hoping it is a recent one: %s\n" "${usb_modeswitchbin}"
			verbose "Switching modem (using %s)" "${usb_modeswitchbin}"
			debug run_command "${usb_modeswitchbin} --version"
			debug run_command "${usb_modeswitchbin} -W -I -c \"${modeswitch_config}\""
			ret=$?
		elif [ "a${binaryfree}" = "a" ]; then
			show_fmt_error "Embedded Usb-ModeSwitch binary is not valid for your architect. You need to recompile for devices to switch properly. Start by issueing: %s recompile" "${PROVIDER}"
			debug "Will try emergency mode.\n"
			verbose "Trying emergency switch"
			modeswitch_emergency "$1"
			ret=$?
		else
			show_fmt_error "%s is not installed on your system.\n" "Usb-ModeSwitch"
			return 4
		fi
	fi
	rm -f "${modeswitch_config}"; unset modeswitch_config
	counter=0
	while [ "${counter}" -lt "20" ]
	do
		usb_connected_devices
		after=`echo "${usb_devices}" | ${grepbin} "^$1:"`
		if [ "a${after}" != "a" -a "${counter}" -eq "0" ]; then
			debug "Device \"%s\" still there. Lets hope it has switched.\n" "$1"
			unset after; unset previously
			export NEWIDS="$1"
			return 0
		fi
		after="`echo "${usb_devices}" | ${cutbin} -d: -f1,2`"
		for device in ${after}
		do
			newdevice=`echo "${previously}" | ${grepbin} "^${device}"`
			if [ "a${newdevice}" = "a" ]; then
				export NEWIDS="${device}"
				debug "New device \"%s\" appeared.\n" "${NEWIDS}"
				unset device; unset after; unset previously
				return 0
			fi
		done
		unset device
		counter=`expr ${counter} + 1`; counter=`echo ${counter}`
		[ "${counter}" -lt "20" ] && debug "Waiting a second for device to appear.\n" && sleep 1
	done
	debug "Giving up waiting for new device to appear after %d seconds.\n" "${counter}"
	unset after; unset previously; unset counter
	return 1
}

# Detects usable interface of device $1 and sets USB_INTERFACE variable. Device will get switched if required.
# Callers should check NEWIDS variable
modem_usb_detect_int() {
	[ "a$1" = "a" ] && return 99
	usb_get_interface "$1"; ret=$?
	case "${ret}" in
		7)
			debug "Failed to get USB interface.\n"
			return 7
			;;
		98)
			debug "Failed to get USB interface, by user request.\n"
			return 98
			;;
		8)
			debug "Failed to get an interface for device.\n"
			if modeswitch_is_switchable "$1"; then
				if [ "a$2" != "aNOSWITCH" ]; then
					debug "This is normal, device \"%s\" is switchable.\n" "$1"
					modeswitch_switch "$1"
					ret=$?
					if [ "${ret}" -eq "0" -a "a${NEWIDS}" != "a" -a "a$2" != "aNOSWITCH" ]; then
						debug "Device \"%s\" is now switched to \"%s\". Will attempt to setup this one instead.\n" "$1" "${NEWIDS}"
						modem_usb_detect_int "${NEWIDS}" "NOSWITCH"
						ret=$?
						return ${ret}
					else
						debug "Failed to switch device \"%s\".\n" "$1"
						return ${ret}
					fi
				else
					debug "However, device \"%s\" is already switched.\n" "$1"
					return 8
				fi
			fi
			debug "Failed setting up USB modem \"%s\".\n" "$1"
			return 8
			;;
		0)
			debug "Got valid USB interface %d of USB modem \"%s\".\n" "${USB_INTERFACE}" "$1"
			return 0
			;;
		*)
			debug "Unknown error %d while retrieving interface number of USB Device.\n" "${ret}"
			return ${ret}
			;;
	esac
}

# Sets USBTTY one way or another
modem_usb_locate_tty() {
	verbose "Locating tty"
	lcounter=0
	while ! usb_sysfs_locate_tty "$1" "$2" "$3"
	do
		lcounter=`expr ${lcounter} + 1`; lcounter=`echo ${lcounter}`
		if [ "${lcounter}" -le "20" ]; then
			if [ "a$3" != "a" ]; then
				debug "Waiting for driver %s to create tty of device %s (interface #%d). [%d second(s) will have pass]\n" "$3" "$1" "$2" "${lcounter}"
			else
				debug "Waiting for tty of device %s (interface #%d). [%d second(s) will have pass]\n" "$1" "$2" "${lcounter}"
			fi
			sleep 1
		else
			if [ "a$3" != "a" ]; then
				debug "Driver %s failed to create a tty node for interface #%d of device %s.\n" "$3" "$2" "$1"
			else
				debug "No tty node created for interface #%d of device %s.\n" "$2" "$1"
			fi
			debug "Failed to locate tty device of interface #%d from device \"%s\".\n" "$2" "$1"
			unset lcounter
			return 8
		fi
	done
	return 0
}

modem_usb_fix_driver() {
	[ "a$1" = "a" -o "a$2" = "a" ] && return 99
	usb_stabilize "$1"
	# Make sure storage part (if exists), is settled before
	# we start playing with drivers. This should eliminate
	# cases that appeared on 2.6.31+ kernels.
	usb_storage_settled "$1"
	# Retrieve loaded driver
	usbdriver=`usb_loaded_driver "$1" "$2" | ${tailbin} -1`
	if [ "a${TIMEOUTOCCURED}" != "a" ]; then
		show_fmt_error "Seems like an electrical/USB bus error occured. You may need to replug your modem for it to properly work.\n"
		unset TIMEOUTOCCURED
	fi
	# Check value
	if [ "a${usbdriver}" = "a" -o "a${usbdriver}" = "aFAIL" ]; then
		show_fmt_error "Failed to detect driver of interface %d.\n" "$2"
		unset usbdriver
		return 7
	elif [ "a${usbdriver}" = "aNONE" ]; then
		debug "No driver attached to interface #%d of \"%s\".\n" "$2" "$1"
	else
		debug "Found already loaded driver \"%s\".\n" "${usbdriver}"
	fi
	# If driver mismatch, unload wrong driver
	if [ "a${USBDRIVER}" != "a" -a "a${usbdriver}" != "a" -a "a${usbdriver}" != "a${USBDRIVER}" -a "a${usbdriver}" != "aNONE" ]; then
		debug "USBDRIVER variable instructs to use \"%s\" instead.\n" "${USBDRIVER}"
		if ! module_unbind "${usbdriver}" "$1" "$2"; then
			show_fmt_error "Failed to detach wrong driver \"%s\". Please do it yourself and retry.\n" "${usbdriver}"
			unset usbdriver
			return 9
		fi
		usbdriver="NONE"
	fi
	# If no driver, attempt to detect one
	[ "a${USBDRIVER}" = "a" -a "a${usbdriver}" != "aNONE" ] && USBDRIVER="${usbdriver}"
	if [ "a${USBDRIVER}" = "a" -a "a${usbdriver}" = "aNONE" ]; then
		if [ "a${USB_INTERFACE}" != "a" ]; then
			usb_serial_detect_driver "$1" "$2"
			if [ "a${USB_INTERFACE}" = "a" ]; then
				# "usb_serial_detect_driver" call above, called "usb_usable_interfaces" which reset USB_INTERFACE
				USB_INTERFACE="$2" ; export USB_INTERFACE
				debug "Interface of device \"%s\" is still #%d.\n" "$1" "${USB_INTERFACE}"
			fi
		else
			usb_serial_detect_driver "$1" "$2"
		fi
	fi
	# We should know a driver now
	if [ "a${USBDRIVER}" = "a" ]; then
		unset usbdriver
		show_fmt_error "Unable to locate driver to use for device \"%s\"" "$1"
		return 10
	fi
	# Load driver (if required)
	if [ "${USBDRIVER}" = "${usbdriver}" ]; then
		debug "Driver \"%s\" already attached to interface #%d of device \"%s\".\n" "${USBDRIVER}" "$2" "$1"
		unset usbdriver
		return 0
	elif module_bind "${USBDRIVER}" "$1" "$2"; then
		debug "Driver \"%s\" loaded for interface #%d of device \"%s\".\n" "${USBDRIVER}" "$2" "$1"
		unset usbdriver
		return 0
	else
		show_fmt_error "Unable to load driver \"%s\" for device \"%s\"" "${USBDRIVER}" "$1"
		unset usbdriver
		return 11
	fi
}

modem_usb() {
	unset MODEM_TTY
	[ "a$1" = "a" ] && return 99
	! usb_device_connected "$1" && debug "Device \"%s\" not found.\n" "$1" && return 7
	export usbdevice="$1"

	# Find appropriate interface, switching if required
	modem_usb_detect_int "${usbdevice}"
	ret=$?; [ "${ret}" -ne "0" ] &&	unset usbdevice && return ${ret}
	# Check if device is switched
	[ "a${NEWIDS}" != "a" ] && export usbdevice="${NEWIDS}"
	# Load driver
	modem_usb_fix_driver "${usbdevice}" "${USB_INTERFACE}"
	ret=$?; [ "${ret}" -ne "0" ] && unset usbdevice && return ${ret}
	# Locate tty
	modem_usb_locate_tty "${usbdevice}" "${USB_INTERFACE}" "${USBDRIVER}"
	ret=$?; [ "${ret}" -ne "0" ] && unset usbdevice && return ${ret}
	if [ "a${USBTTY}" != "a" ]; then
		if [ -c "${USBTTY}" ]; then
			debug "Nothing more to do for setting it up device \"%s\".\n" "$1"
			export MODEM_TTY="${USBTTY}"
			return 0
		fi
	fi
	unset USB_INTERFACE
	unset USBTTY
	unset MODEM_TTY
	unset usbdevice
	return 99
}

modem_bluetooth() {
	unset MODEM_TTY
	[ "a$1" = "a" -o "a$2" = "a" ] && return 99
	debug "Attempting to setup bluetooth modem \"%s\" on channel \"%s\".\n" "$1" "$2"
	bluetooth_setup_rfcomm "$1" "$2"
	ret=$?
	if [ "a${ret}" = "a0" ]; then
		if [ "a${RFCOMM_TTY}" = "a" ]; then
			debug "No RFCOMM tty returned.\n"
		elif [ ! -c "${RFCOMM_TTY}" ]; then
			debug "RFCOMM tty returned (%s), does exist.\n" "${RFCOMM_TTY}"
		else
			debug "Nothing more to do for setting it up %s(channel #%d).\n" "$1" "$2"
			export MODEM_TTY="${RFCOMM_TTY}"
			return 0
		fi
	fi
	return 8
}

modem_custom() {
	[ "a$1" = "a" ] && return 99
	debug "Attempting to setup custom tty modem on \"%s\".\n" "$1"
	if [ -c "$1" ]; then
		debug "Custom tty \"%s\" exists. Nothing more to do for setting it up.\n" "$1"
		export MODEM_TTY="$1"
		return 0
	else
		debug "Custom tty \"%s\" does not exist. Unable to proceed.\n" "$1"
		show_fmt_error "Device node \"%s\" does not exist. Setup failed." "$1"
		unset MODEM_TTY
		return 8
	fi
}

modem_setup() {
	unset MODEM_TTY
	debug "Setting up modem.\n"
	! we_are_root && return 3
	[ "a${MODEM}" = "a" ] && ! flow_select_modem "$@" && return 98
	if [ "a${MODEM}" = "aOTHER" ]; then
		[ "a${OTHER}" = "a" ] && ! flow_other_modem "$@" && return 98
		if [ "a${OTHER}" = "aUSBMODEM" ]; then
			[ "a${USBMODEM}" = "a" ] && ! flow_usb_modem "$@" && return 98
			if [ "a${USBMODEM}" != "a" ]; then
				debug "Setting up USB modem %s.\n" "${USBMODEM}"
				modem_usb "${USBMODEM}" "$@"
				ret=$?
				[ "a${usbdevice}" != "a" -a "a${usbdevice}" = "a${NEWIDS}" ] && export USBMODEM="${USBMODEM} ${usbdevice}"
				return ${ret}
			fi
		elif [ "a${OTHER}" = "aBLUETOOTH" ]; then
			[ "a${BLUETOOTH}" = "a" ] && ! flow_blue_modem "$@" && return 98
			if [ "a${BLUETOOTH}" = "aUNDISCOVERABLE" ]; then
				[ "a${UNDISCOVERABLE}" = "a" ] && ! flow_undiscoverable "$@" && return 98
				if [ "a${UNDISCOVERABLE}" != "a" ]; then
					[ "a${RFSERVICE}" = "a" ] && ! flow_rfchannel "$@" && return 98
					if [ "a${RFSERVICE}" = "aRFCHANNEL" ]; then
						[ "a${RFCHANNEL}" = "a" ] && ! flow_manual_rfcomm "$@" && return 98
						if [ "a${RFCHANNEL}" != "a" ]; then
							debug "Setting up Bluetooth modem %s on channel %s.\n" "${UNDISCOVERABLE}" "${RFCHANNEL}"
							modem_bluetooth "${UNDISCOVERABLE}" "${RFCHANNEL}" "$@"
							return $?
						fi
					elif [ "a${RFSERVICE}" != "a" ]; then
						debug "Setting up Bluetooth modem %s on channel %s.\n" "${UNDISCOVERABLE}" "${RFSERVICE}"
						modem_bluetooth "${UNDISCOVERABLE}" "${RFSERVICE}" "$@"
						return $?
					fi
				fi
			elif [ "a${BLUETOOTH}" != "a" ]; then
				[ "a${RFSERVICE}" = "a" ] && ! flow_rfchannel "$@" && return 98
				if [ "a${RFSERVICE}" = "aRFCHANNEL" ]; then
					[ "a${RFCHANNEL}" = "a" ] && ! flow_manual_rfcomm "$@" && return 98
					if [ "a${RFCHANNEL}" != "a" ]; then
						debug "Setting up Bluetooth modem %s on channel %s.\n" "${BLUETOOTH}" "${RFCHANNEL}"
						modem_bluetooth "${BLUETOOTH}" "${RFCHANNEL}" "$@"
						return $?
					fi
				elif [ "a${RFSERVICE}" != "a" ]; then
					debug "Setting up Bluetooth modem %s on channel %s.\n" "${BLUETOOTH}" "${RFSERVICE}"
					modem_bluetooth "${BLUETOOTH}" "${RFSERVICE}" "$@"
					return $?
				fi
			fi
		elif [ "a${OTHER}" = "aCUSTOM_TTY" ]; then
			[ "a${CUSTOM_TTY}" = "a" ] && ! flow_custom_tty "$@" && return 98
			if [ "a${CUSTOM_TTY}" != "a" ]; then
				debug "Setting up custom modem on %s.\n" "${CUSTOM_TTY}"
				modem_custom "${CUSTOM_TTY}" "$@"
				return $?
			fi
		fi
	elif [ "a${MODEM}" != "a" ]; then
		debug "Setting up USB modem %s.\n" "${MODEM}"
		modem_usb "${MODEM}" "$@"
		ret=$?
		[ "a${usbdevice}" != "a" -a "a${usbdevice}" = "a${NEWIDS}" ] && export MODEM="${MODEM} ${usbdevice}"
		return ${ret}
	fi
	debug "Failed to setup any modem.\n"
	return 99
}

# Gets entries from file $1 that start with $2:$3
base_fetch() {
	unset BASERESULT
	[ "a$1" = "a" ] && return 1
	[ "a${PROVIDER}" = "a" ] && debug "Unable to locate package provider.\n" && return 1
	[ ! -x "${PROVIDER}" ] && debug "Unable to execute package provider.\n" && return 1
	baseentries=`"${PROVIDER}" getfile "$1" | ${grepbin} -v "^#" | ${grepbin} -i "^$2:"`
	if [ "a${baseentries}" = "a" ]; then
		unset baseentries
		debug "No information found for %s within %s database.\n" "$2" "$1"
		return 1
	fi
	[ "a$3" != "a" ] && BASERESULT=`echo "${baseentries}" | ${grepbin} -i "^$2:$3:"`
	[ "a${BASERESULT}" = "a" ] && BASERESULT=`echo "${baseentries}" | ${grepbin} -i "^$2::"`
	export BASERESULT
	unset baseentries
	if [ "a${BASERESULT}" = "a" ]; then
		unset BASERESULT
		[ "a$3" != "a" ] && debug "No information found for \"%s:%s:\" within %s.\n" "$2" "$3" "$1"
		[ "a$3" = "a" ] && debug "No default entry \"%s::\" found within %s.\n" "$2" "$1"
		return 1
	fi
	debug "Loaded entries from %s:\n%s\n" "$1" "${BASERESULT}"
	return 0
}

base_drivers() {
	unset basedrivercandidates; unset baseintercandidates
	[ "a$1" = "a" ] && return 1
	! base_fetch "files/usb_devices.db" "$1" "$2" && return 1
	[ "a${BASERESULT}" = "a" ] && return 1
	BASERESULT=`echo "${BASERESULT}" | ${headbin} -1`
	basedrivercandidates=`echo "${BASERESULT}" | ${cutbin} -f2 -s`
	baseintercandidates=`echo "${BASERESULT}" | ${cutbin} -f3 -s`
	[ "a${basedrivercandidates}" != "a" ] && debug "Device database indicates to use \"%s\" driver(s) for device %s.\n" "${basedrivercandidates}" "$1"
	[ "a${baseintercandidates}" != "a" ] && debug "Device database indicates to use interface #%d for device %s.\n" "${baseintercandidates}" "$1"
	unset BASERESULT
	return 0
}

# Sets INIT_STAGES of modem $1 with optional name $2.
# Parses files/modem_init.db.
base_modem() {
	unset INIT_STAGE0; unset INIT_STAGE1; unset INIT_STAGE2; unset INIT_STAGE3; unset INIT_STAGE4; unset INIT_STAGE5; unset INIT_STAGE6; unset INIT_STAGE7; unset INIT_STAGE8;
	[ "a$1" = "a" -a "a$2" = "a" ] && return 1
	! base_fetch "files/modem_init.db" "$1" "$2" && return 1
	[ "a${BASERESULT}" = "a" ] && return 1
	BASERESULT=`echo "${BASERESULT}" | ${headbin} -1`
	for item in 0 1 2 3 4 5 6 7 8
	do
		plusone=`expr ${item} + 1`; plusone=`echo ${plusone}`
		if [ "${item}" -le "7" -a "${item}" -ge "1" ]; then
			contents=`${printfbin} "%s\n" "${BASERESULT}" | ${cutbin} -f${plusone}`
		elif [ "${item}" -eq "8" ]; then
			contents=`${printfbin} "%s\n" "${MODEM_INIT}"`
		elif [ "${item}" -eq "0" ]; then
			contents=`${printfbin} "%s\n" "${MODEM_PREPARE}"`
		fi
		if [ "a${contents}" != "a" ]; then
			replacement=`${printfbin} "%s\n" "${contents}" | ${sedbin} -e "s/AT/\\nAT/g" | ${sedbin} -e "s/  *$//g" | ${grepbin} -v "^$" | ${grepbin} "^AT" | ${sedbin} -e "s/^\(.*\)$/\\\'\1\\\' OK/g" | ${trbin} "\n" " "`
			eval "INIT_STAGE${item}=\${replacement}"
			eval export INIT_STAGE${item}
			unset replacement
			if [ "a$1" != "a" ]; then
				if [ "a$2" != "a" ]; then
					debug "Loaded INIT Stage #%d for %s(%s): %s\n" "${item}" "$1" "$2" "`eval echo \\"\\${INIT_STAGE${item}}\\"`"
				else
					debug "Loaded INIT Stage #%d for %s: %s\n" "${item}" "$1" "`eval echo \\"\\${INIT_STAGE${item}}\\"`"
				fi
			else
				debug "Loaded INIT Stage #%d for %s: %s\n" "${item}" "$2" "`eval echo \\"\\${INIT_STAGE${item}}\\"`"
			fi
		else
			eval unset INIT_STAGE${item}
		fi
		unset contents; unset plusone
	done
	debug run_command "set | ${grepbin} \"^INIT_STAGE\""
	unset item
	return 0
}

# Sets NETINFO of ISP $1 with optional name $2. If $1==$ISPID sets ISP_ fields also
# Parses files/operators.db.
base_net() {
	unset NETINFO
	[ "a$1" = "a" ] && return 1
	! base_fetch "files/operators.db" "$1" "$2" && return 1
	[ "a${BASERESULT}" = "a" ] && return 1
	BASERESULT=`echo "${BASERESULT}" | ${headbin} -1`
	ISP_NAME=`echo "${BASERESULT}" | ${cutbin} -f2`
	ISP_PRODUCT=`echo "${BASERESULT}" | ${cutbin} -f3`
	ISP_FGCOLOR=`echo "${BASERESULT}" | ${cutbin} -f4`
	ISP_BGCOLOR=`echo "${BASERESULT}" | ${cutbin} -f5`
	ISP_DIAL=`echo "${BASERESULT}" | ${cutbin} -f6`
	ISP_APNS=`echo "${BASERESULT}" | ${cutbin} -f7 | ${trbin} " " "\n"`
	ISP_ICON=`echo "${BASERESULT}" | ${cutbin} -f8`
	export ISP_NAME
	export ISP_PRODUCT
	export ISP_FGCOLOR
	export ISP_BGCOLOR
	export ISP_DIAL
	export ISP_APNS
	export ISP_ICON
	return 0
}

# Gathers information about ISP $1 with optional name $2
net_info() {
	[ "a$1" != "a" ] && base_net "$@"
	[ "a$1" != "a${ISPID}" -a "a$1" != "a" ] && return 0
	[ "a${ISP_NAME}" = "a" ] && export ISP_NAME="${ISPNAME}"
	[ "a${ISP_NAME}" = "a" ] && export ISP_NAME="Unknown operator ${ISPID}"
	[ "a${ISPNAME}" = "a${ISPID}" -o "a${ISPNAME}" = "a" ] && export ISPNAME="${ISP_NAME}"
	[ "a${ISPNAME}" = "a${ISPID}" -o "a${ISPNAME}" = "a" ] && export ISPNAME="${ISP_NAME}"
	export ISPTEXT="${ISPNAME}"
	[ "a${ISP_PRODUCT}" = "a" ] && export ISP_PRODUCT="${ISP_NAME} Internet"
	[ "a${ISP_FGCOLOR}" = "a" ] && export ISP_FGCOLOR="ffffff"
	[ "a${ISP_BGCOLOR}" = "a" ] && export ISP_BGCOLOR="000000"
	[ "a${ISP_DIAL}" = "a" ] && export ISP_DIAL="*99#"
	[ "a${ISP_ICON}" = "a" ] && export ISP_ICON="files/sakis3g.png"
	if [ "a${CUSTOM_DIAL}" != "a" -a "a${CUSTOM_DIAL}" != "a${ISP_DIAL}" ]; then
		debug "Will dial \"%s\" specified by user instead of \"%s\" found in database.\n" "${CUSTOM_DIAL}" "${ISP_DIAL}"
		export ISP_DIAL="${CUSTOM_DIAL}"
	fi
	debug "ISPID: %s / ISPNAME: %s / ISPTEXT: %s\n" "${ISPID}" "${ISPNAME}" "${ISPTEXT}"
	return 0
}


# Select a device interface
flow_select_interface() {
	usbinterfaces=`echo "$2" | ${trbin} " " "\n" | ${sedbin} -e "s/^\(.*\)$/\"\1\" \"Interface #\1\"/g" | ${trbin} "\n" " "`
	eval user_select \"USBINTERFACE\" \"Please appropriate interface\" \"Select modem interface of USB device that provides modem capabilities.\" \"Select\" \"Cancel\" ${usbinterfaces}
	case "$?" in
		0)
			unset usbinterfaces
			return 98
			;;
		98)
			unset usbinterfaces
			return 98
			;;
		99)
			unset usbinterfaces
			return 99
			;;
		*)
			unset usbinterfaces
			return 0
			;;
	esac
	return 99
}


# Makes sure one USB modem exists
flow_usb_modem() {
	usb_connected_devices
	usbmodems=`echo "${usb_devices}" | ${sedbin} -e "s/^\(....\):\(....\):\(.*\)$/\"\1:\2\" \"\3\"/g"`
	eval user_select \"USBMODEM\" \"Please select USB modem\" \"Select USB device that provides modem capabilities.\" \"Select\" \"Cancel\" ${usbmodems}
	case "$?" in
		0)
			unset usbmodems
			return 98
			;;
		98)
			unset usbmodems
			return 98
			;;
		99)
			unset usbmodems
			return 99
			;;
		*)
			unset usbmodems
			usb_connected_devices
			usbmodems=`echo "${usb_devices}" | ${sedbin} -e "s/^\(....\):\(....\):\(.*\)$/ \1:\2 /g" | ${grepbin} " ${USBMODEM} "`; usbmodems=`echo ${usbmodems}`
			if [ "a${usbmodems}" = "a${USBMODEM}" ]; then
				debug "User selected USB modem \"%s\".\n" "${USBMODEM}"
				unset usbmodems
				return 0
			else
				debug "USB modem \"%s\" is not currently plugged.\n" "${USBMODEM}"
				unset usbmodems; unset USBMODEM
				flow_usb_modem "$@"
				return "$?"
			fi
			;;
	esac
	return 99
}

flow_manual_rfcomm() {
	user_prompt "RFCHANNEL" "Please enter RFCOMM channel" "Enter RFCOMM channel that should be used, or leave empty to abort [1-255]" "OK" "Cancel"
	case "a${RFCHANNEL}" in
		a)
			return 98
			;;
		*)
			RFCHANNEL=`${printfbin} "%d\n" "${RFCHANNEL}" 2> /dev/null`
			[ "a$RFCHANNEL" = "a" ] && RFCHANNEL=0
			[ "$RFCHANNEL" -gt "255" ] && RFCHANNEL=0
			export RFCHANNEL
			if [ "$RFCHANNEL" -eq "0" ]; then
				unset RFCHANNEL
				return 98
			fi
			return 0
			;;
	esac
}

flow_custom_tty() {
	user_prompt "CUSTOM_TTY" "Please enter tty" "Enter tty node where your 3G modem resides, or leave empty to abort" "OK" "Cancel"
	case "a${CUSTOM_TTY}" in
		a)
			unset CUSTOM_TTY
			return 98
			;;
		*)
			[ ! -c "${CUSTOM_TTY}" ] && [ -c "/dev/${CUSTOM_TTY}" ] && CUSTOM_TTY="/dev/${CUSTOM_TTY}"
			[ ! -c "${CUSTOM_TTY}" ] && [ -c "/dev${CUSTOM_TTY}" ] && CUSTOM_TTY="/dev${CUSTOM_TTY}"
			if [ ! -c "${CUSTOM_TTY}" ]; then
				show_fmt_error "Device node \"%s\" does not exist.\n" "${CUSTOM_TTY}"
				unset CUSTOM_TTY
				flow_custom_tty "$@"
				return $?
			else
				debug "Using device node \"%s\".\n" "${CUSTOM_TTY}"
				export CUSTOM_TTY
				return 0
			fi
			;;
	esac
}

flow_rfchannel() {
	[ "a${BLUETOOTH}" = "a" ] && ! flow_blue_modem "$@" && return $?
	if [ "a${RFSERVICE}" = "aRFCHANNEL" ]; then
		if ! flow_manual_rfcomm; then
			unset RFSERVICE
			flow_rfchannel "$@"
			return "$?"
		fi
		return 0
	fi
	verbose "Seeking %s" "${BLUETOOTH}"
	if bluetooth_rfcomm_channel "${BLUETOOTH}" "DUN"; then
		debug "No DUN rfcomm channels returned from \"%s\".\n" "${BLUETOOTH}"
		bluetooth_rfcomm_channel "${BLUETOOTH}" "SP"
		rfchannels=`echo "${rfchannel}" | ${sedbin} -e "s/^\([0-9][0-9]*\)$/\"\1\" \"Serial Port from RFCOMM channel #\1\"/g"`
	else
		rfchannels=`echo "${rfchannel}" | ${sedbin} -e "s/^\([0-9][0-9]*\)$/\"\1\" \"Dialup Networking from RFCOMM channel #\1\"/g"`
		bluetooth_rfcomm_channel "${BLUETOOTH}" "SP"
		rfchannels="${rfchannels} `echo \"${rfchannel}\" | ${sedbin} -e \"s/^\\\([0-9][0-9]*\\\)$/\\\"\\\1\\\" \\\"Serial Port from RFCOMM channel #\\\1\\\"/g\"`"
	fi
	eval user_select \"RFSERVICE\" \"Please select RFCOMM service\" \"Select RFCOMM service of Bluetooth device that provides 3G modem capabilities.\" \"Select\" \"Cancel\" \"RESCAN\" \"Scan device again\" ${rfchannels} \"RFCHANNEL\" \"Manually enter non-discovered channel...\"
	case "$?" in
		0)
			unset rfchannels
			return 98
			;;
		98)
			unset rfchannels
			return 98
			;;
		99)
			unset rfchannels
			return 99
			;;
		*)
			unset rfchannels
			case "a${RFSERVICE}" in
				aRESCAN)
					unset RFSERVICE
					flow_rfchannel "$@"
					return "$?"
					;;
				aRFCHANNEL)
					if ! flow_manual_rfcomm; then
						unset RFSERVICE
						flow_rfchannel "$@"
						return "$?"
					fi
					return 0
					;;
				*)
					export RFCHANNEL="${RFSERVICE}"
					return 0
					;;
			esac
			;;
	esac
	return 99


}

# Makes sure one UNDISCOVERABLE BLUETOOTH modem exists
flow_undiscoverable() {
	user_prompt "UNDISCOVERABLE" "Enter Bluetooth address" "Enter Bluetooth address of undiscoverable device, or leave empty to abort" "OK" "Cancel"
	case "a${UNDISCOVERABLE}" in
		a)
			return 98
			;;
		*)
			export BLUETOOTH="${UNDISCOVERABLE}"
			if ! flow_rfchannel; then
				unset UNDISCOVERABLE; unset BLUETOOTH
				return 98
			fi
			export BLUETOOTH="UNDISCOVERABLE"
			return 0
			;;
	esac
}


# Makes sure one BLUETOOTH modem exists
flow_blue_modem() {
	if [ "a${BLUETOOTH}" = "aUNDISCOVERABLE" ]; then
		if ! flow_undiscoverable; then
			unset BLUETOOTH
			flow_blue_modem "$@"
			return "$?"
		fi
		return 0
	fi
	bluetooth_scan_devices
	bluemodems=`echo "${bluetooth_devices}" | ${sedbin} -e "s/^\(.*\)	\(.*\)$/\"\1\" \"\2 (\1)\"/g"`
	eval user_select \"BLUETOOTH\" \"Please select Bluetooth device\" \"Select Bluetooth device that provides 3G modem capabilities.\" \"Select\" \"Cancel\" \"RESCAN\" \"Scan devices again\" ${bluemodems} \"UNDISCOVERABLE\" \"Manually enter undiscoverable device...\"
	case "$?" in
		0)
			unset bluemodems
			return 98
			;;
		98)
			unset bluemodems
			return 98
			;;
		99)
			unset bluemodems
			return 99
			;;
		*)
			unset bluemodems
			case "a${BLUETOOTH}" in
				aRESCAN)
					unset BLUETOOTH
					flow_blue_modem "$@"
					return "$?"
					;;
				aUNDISCOVERABLE)
					if ! flow_undiscoverable; then
						unset BLUETOOTH
						flow_blue_modem "$@"
						return "$?"
					fi
					return 0
					;;
				*)
					if ! flow_rfchannel; then
						unset BLUETOOTH
						flow_blue_modem "$@"
						return "$?"
					fi
					return 0
					;;
			esac
			;;
	esac
	return 99
}

# Makes sure one other modem is selected
flow_other_modem() {
	user_select "OTHER" "Please select modem type" "Select modem category that best fits your 3G modem." "Select" "Cancel" "USBMODEM" "USB device" "BLUETOOTH" "Bluetooth modem" "CUSTOM_TTY" "Custom tty..."
	case "$?" in
		0)
			return 98
			;;
		98)
			return 98
			;;
		99)
			return 99
			;;
		*)
			case "a${OTHER}" in
				aUSBMODEM)
					if ! flow_usb_modem; then
						unset OTHER
						flow_other_modem "$@"
						return "$?"
					fi
					return 0
					;;
				aBLUETOOTH)
					if ! flow_blue_modem; then
						unset OTHER
						flow_other_modem "$@"
						return "$?"
					fi
					return 0
					;;
				aCUSTOM_TTY)
					if ! flow_custom_tty; then
						unset OTHER
						flow_other_modem "$@"
						return "$?"
					fi
					return 0
					;;
				*)
					return 99
					;;
			esac
			;;
	esac
	return 99
}


# Makes sure one selected modem exists
flow_select_modem() {
	verbose "Locating device"
	usb_connected_modems
	modems=`echo "${usb_modem_devices}" | ${sedbin} -e "s/^\(....\):\(....\):\(.*\)$/\"\1:\2\" \"\3\"/g"`
	if [ "a${modems}" != "a" ]; then
		modemscount=`echo "${usb_modem_devices}" | ${wcbin} -l`; modemscount=`echo ${modemscount}`
		if [ "a${modemscount}" = "a1" -a "a${MODEM}" = "a" ]; then
			MODEM=`echo "${usb_modem_devices}" | ${headbin} -1 | ${sedbin} -e "s/^\(....\):\(....\):\(.*\)$/\1:\2/g"`
			export MODEM
			debug "Autoselecting unique USB modem plugged: %s\n" "${MODEM}"
			ret=1
		else
			eval user_select \"MODEM\" \"Please select modem\" \"Select modem that will be used for establishing 3G connection.\" \"Select\" \"Cancel\" ${modems} \"OTHER\" \"Other...\"
# in
			ret=$?
		fi
		unset modemscount
	else
		export MODEM="OTHER"
		ret=97
	fi
	case "${ret}" in
		0)
			return 98
			;;
		98)
			return 98
			;;
		99)
			return 99
			;;
		*)
			case "a${MODEM}" in
				aOTHER)
					if [ "${ret}" -eq "97" ]; then
						flow_other_modem "$@"
						ret=$?
						[ "${ret}" -ne "0" ] && unset MODEM
						return ${ret}
					else
						if ! flow_other_modem "$@"; then
							unset MODEM
							flow_select_modem "$@"
							return "$?"
						fi
					fi
					return 0
					;;
				a)
					return 98
					;;
				*)
					return 0
					;; 
			esac
			return 99
			;;
	esac
	return 0
}

flow_custom_apn() {
	user_prompt "CUSTOM_APN" "Please enter APN" "Enter correct APN, or leave empty to abort. Contact your operator if unsure" "OK" "Cancel"
	case "a${CUSTOM_APN}" in
		a)
			unset CUSTOM_APN
			return 98
			;;
		*)
			export CUSTOM_APN
			return 0
			;;
	esac
}


# Makes selected APN exists
flow_select_apn() {
	net_info "${ISPID}" "${ISPNAME}"
	[ "a${FORCE_APN}" != "a" ] && export ISP_APNS="${FORCE_APN}"
	[ "a${ISP_APNS}" = "a" ] && tty_detect_apn && export ISP_APNS="${MODEM_APN}"
	if [ "a${ISP_APNS}" != "a" -a "a${FORCE_APN}" = "a" ]; then
		apnoptions=""
		for apnoption in ${ISP_APNS}
		do
			apnname=`echo "${apnoption}" | ${cutbin} -d: -f1 -s`
			if [ "a${apnname}" = "a" ]; then
				apnname="${apnoption}"
				apndesc="${apnoption}"
				apnuser="" ; apnpass=""
			else
				apndesc=`echo "${apnoption}" | ${cutbin} -d: -f2 | ${sedbin} -e "s/_/ /g"`
				apndesc="${apndesc} (${apnname})"
				apnuser=`echo "${apnoption}" | ${cutbin} -d: -f3`
				apnpass=`echo "${apnoption}" | ${cutbin} -d: -f4`
			fi
			if [ "a${apnname}" = "a${MODEM_APN}" -a "a${MODEM_APN}" != "a" ]; then
				apndesc=`format_text "Reported by your modem (%s)" "${apnname}"`
			fi
			apnoptions="${apnoptions} \"${apnname}\" \"${apndesc}\""
			unset apnname; unset apndesc; unset apnuser; unset apnpass
		done
		unset apnoption
		eval user_select \"APN\" \"Please select APN\" \"Select APN that best describes your connection. Contact your operator if unsure. This information, along with APN username and password, is usually easily retrieved through a fast call to customer support\" \"Select\" \"Cancel\" ${apnoptions} \"CUSTOM_APN\" \"Custom APN...\"
		ret=$?
		unset apnoptions
	elif [ "a${FORCE_APN}" != "a" ]; then
		debug "Selected APN by FORCE_APN: %s\n" "${FORCE_APN}"
		APN=`echo "${FORCE_APN}" | ${cutbin} -d: -f1`
		export APN
		ret=1
	else
		export APN="CUSTOM_APN"
		ret=97
	fi
	case "${ret}" in
		0)
			return 98
			;;
		98)
			return 98
			;;
		99)
			return 99
			;;
		*)
			case "a${APN}" in
				aCUSTOM_APN)
					if [ "${ret}" -eq "97" ]; then
						if ! flow_custom_apn "$@"; then
							unset APN
							return 98
						fi
					else
						if ! flow_custom_apn "$@"; then
							unset APN
							flow_select_apn "$@"
							return "$?"
						fi
					fi
					return 0
					;;
				a)
					return 98
					;;
				*)
					APN=`echo "${ISP_APNS}" | ${grepbin} "^${APN}\(:*\)" | ${cutbin} -d: -f1`
					export APN
					if [ "a${APN}" = "a" ]; then
							unset APN
							flow_select_apn "$@"
							return "$?"
					else
						apnuser=`echo "${ISP_APNS}" | ${grepbin} "^${APN}\(:*\)" | ${cutbin} -d: -f3 -s`
						[ "a${apnuser}" != "a" -a "a${APN_USER}" = "a" ] && export APN_USER="${apnuser}"
						apnpass=`echo "${ISP_APNS}" | ${grepbin} "^${APN}\(:*\)" | ${cutbin} -d: -f4 -s`
						[ "a${apnuser}" != "a" -a "a${APN_PASS}" = "a" ] && export APN_PASS="${apnpass}"
						unset apnuser; unset apnpass
					fi
					return 0
					;; 
			esac
			return 99
			;;
	esac
	return 0
}

flow_apn_user() {
	[ "a${APN}" = "a" ] && return 98
	if [ "a${APN_USER}" = "a" ]; then
		if [ "a${APN}" != "a" ]; then
			if [ "a${APN}" = "aCUSTOM_APN" -a "a${CUSTOM_APN}" != "a" ]; then
				APN_USER=`echo "${CUSTOM_APN}" | ${cutbin} -d: -s -f3`
			else
				APN_USER=`echo "${APN}" | ${cutbin} -d: -s -f3`
			fi
		fi
	fi
	[ "a${APN_USER}" = "a" ] && unset APN_USER
	if [ "a${APN}" = "aCUSTOM_APN" -a "a${CUSTOM_APN}" != "a" ]; then
		apntitle=`echo "${CUSTOM_APN}" | ${cutbin} -d: -f1`
	elif [ "a${APN}" != "a" ]; then
		apntitle=`echo "${APN}" | ${cutbin} -d: -f1`
	fi
	user_prompt "APN_USER" "APN: ${apntitle}" "Enter username required by APN, or leave empty to abort. Contact your operator if unsure. This information, along with APN password, is usually easily retrieved through a fast call to customer support" "OK" "Cancel"
	case "a${APN_USER}" in
		a)
			unset APN_USER
			return 98
			;;
		*)
			export APN_USER
			return 0
			;;
	esac
}

flow_apn_pass() {
	[ "a${APN}" = "a" ] && return 98
	if [ "a${APN_PASS}" = "a" ]; then
		if [ "a${APN}" != "a" ]; then
			if [ "a${APN}" = "aCUSTOM_APN" -a "a${CUSTOM_APN}" != "a" ]; then
				APN_PASS=`echo "${CUSTOM_APN}" | ${cutbin} -d: -s -f4`
			else
				APN_PASS=`echo "${APN}" | ${cutbin} -d: -s -f4`
			fi
		fi
	fi
	[ "a${APN_PASS}" = "a" ] && unset APN_PASS
	if [ "a${APN}" = "aCUSTOM_APN" -a "a${CUSTOM_APN}" != "a" ]; then
		apntitle=`echo "${CUSTOM_APN}" | ${cutbin} -d: -f1`
	elif [ "a${APN}" != "a" ]; then
		apntitle=`echo "${APN}" | ${cutbin} -d: -f1`
	fi
	user_prompt "APN_PASS" "APN: ${apntitle}" "Enter password required by APN, or leave empty to abort. Contact your operator if unsure. This information is usually easily retrieved through a fast call to customer support" "OK" "Cancel"
	case "a${APN_PASS}" in
		a)
			unset APN_PASS
			return 98
			;;
		*)
			export APN_PASS
			return 0
			;;
	esac
}

flow_switch() {
	flow_select_modem "$@"
	ret=$?; [ "${ret}" -ne "0" ] && return ${ret}
	unset NEWIDS
	if modeswitch_is_switchable "${MODEM}" && usb_device_connected "${MODEM}"; then
		modeswitch_switch "${MODEM}"
		ret=$?
		if [ "a${NEWIDS}" != "a" -a "a${NEWIDS}" != "a${MODEM}" ]; then
			debug "Device changed ID. From \"%s\" to \"%s\".\n" "${MODEM}" "${NEWIDS}"
			export MODEM="${NEWIDS}"
		fi
		localdev="${MODEM}"
	elif modeswitch_is_switchable "${USBMODEM}" && usb_device_connected "${USBMODEM}"; then
		modeswitch_switch "${USBMODEM}"
		ret=$?
		if [ "a${NEWIDS}" != "a" -a "a${NEWIDS}" != "a${USBMODEM}" ]; then
			debug "Device changed ID. From \"%s\" to \"%s\".\n" "${USBMODEM}" "${NEWIDS}"
			export USBMODEM="${NEWIDS}"
		fi
		localdev="${USBMODEM}"
	else
		debug "Currently selected modem cannot be switched. No need to switch anything.\n"
		return 0
	fi
	# Should normally unlock HAL here. But we don't.
	# If we will stay within program, it will get unlocked during driver setup.
	# If stand-alone action, exit trap will unlock it.
	# So, line below should be commented out.
	#hal_unlock
	return ${ret}
}

flow_setup() {
	flow_select_modem "$@"
	ret=$?; [ "${ret}" -ne "0" ] && return ${ret}
	if modem_setup "$@"; then
		debug "Modem is now setup and resides on %s.\n" "${MODEM_TTY}"
		return 0
	else
		return $?
	fi
}

flow_prepare() {
	flow_setup "$@"
	ret=$?; [ "${ret}" -ne "0" ] && return ${ret}
	if tty_prepare "${MODEM_TTY}" "$@"; then
		debug "Device %s is now prepared and registered to %s.\n" "${MODEM_TTY}" "${ISPTEXT}"
	else
		return $?
	fi
}

pppd_config() {
	need_binary "pppd"
	need_arg "PPPD_OPTIONS"; need_arg "BAUD"
	unset CONNECTION_CONF; unset CONNECTION_COMMAND
	${touchbin} "/tmp/pppd.tmp.$$"
	if [ ! -w "/tmp/pppd.tmp.$$" ]; then
		show_fmt_error "Unable to create temporary pppd config file within %s directory.\n" "/tmp"
		return 99
	fi
	CONNECTION_CONF="/tmp/pppd.tmp.$$"
	find_binary "chmod" && ${chmodbin} 600 "${CONNECTION_CONF}"
	${catbin} > "${CONNECTION_CONF}" <<endl
ABORT "NO CARRIER"
ABORT "NO DIALTONE"
ABORT "BUSY"
ABORT "ERROR"
ABORT "NO ANSWER"
"" ATZ
endl
	#initstrings=`echo "${INIT_COMMANDS}" "ATDT${ISP_DIAL}" | ${sedbin} -e "s/AT/\\nAT/g" | ${grepbin} "^AT" | ${sedbin} -e "s/  *$//g" | ${grepbin} -v "^$" | ${sedbin} -e "s/^\(.*\)$/OK '\1'/g"`
	initstrings=`echo "${DIAL_COMMANDS}" | ${sedbin} -e "s/AT/\\nAT/g" | ${grepbin} "^AT" | ${sedbin} -e "s/  *$//g" | ${grepbin} -v "^$" | ${sedbin} -e "s/^\(.*\)$/OK '\1'/g"`
	debug "Init strings are:\n%s\n" "${initstrings}"
	echo "${initstrings}" >> "${CONNECTION_CONF}"
	unset initstrings
	if [ ! -s "${CONNECTION_CONF}" ]; then
		${rmbin} -f "${CONNECTION_CONF}"
		show_fmt_error "Failure to write on %s.\n" "${CONNECTION_CONF}"
		unset CONNECTION_CONF
		return 99
	fi
	debug "Config file that will be used is: \"%s\".\n" "${CONNECTION_CONF}"
	debug show_file "${CONNECTION_CONF}"
	pppdoptions="${PPPD_OPTIONS}"
	[ "a${pppdoptions}" = "a" ] && pppdoptions="modem crtscts -detach defaultroute dump noipdefault usepeerdns usehostname ktune logfd 2 noauth name sakis3g lock maxfail 3"
	if [ "a${PPPD_PEERS}" != "a" ]; then
		if [ -d "${PPPD_PEERS}" ]; then
			if [ -f "${PPPD_PEERS}/sakis3g" ]; then
				debug "Found peers file %s.\n" "${PPPD_PEERS}/sakis3g"
				pppdoptions="-detach dump logfd 2 name sakis3gpeer maxfail 3 call sakis3g"
			fi
		fi
	fi
	export CONNECTION_COMMAND="${setsidbin} ${pppdbin} ${MODEM_TTY} ${BAUD} ${pppdoptions} connect \"${chatbin} -v -f ${CONNECTION_CONF}\" user \"${APN_USER}\" password \"${APN_PASS}\""
	unset pppdoptions
	debug "Connection command that will be used is: %s\n" "${CONNECTION_COMMAND}"
	return 0
}

wvdial_config() {
	need_binary "wvdial"
	need_arg "BAUD"
	unset CONNECTION_CONF; unset CONNECTION_COMMAND
	${touchbin} "/tmp/wvdial.tmp.$$"
	if [ ! -w "/tmp/wvdial.tmp.$$" ]; then
		show_fmt_error "Unable to create temporary wvdial config file within %s directory.\n" "/tmp"
		return 99
	fi
	CONNECTION_CONF="/tmp/wvdial.tmp.$$"
	find_binary "chmod" && ${chmodbin} 600 "${CONNECTION_CONF}"
	${catbin} > "${CONNECTION_CONF}" <<endl
[Dialer Defaults]
Modem = ${MODEM_TTY}
Modem Type = Analog Modem
ISDN = 0
Baud = ${BAUD}
Dial Attempts = 3
Username = ${APN_USER}
Password = ${APN_PASS}
Phone = ${ISP_DIAL}
Auto Reconnect = off
Stupid Mode = 1
endl
	echo "Init1 = ATZ" >> "${CONNECTION_CONF}"
	if [ ! -s "${CONNECTION_CONF}" ]; then
		${rmbin} -f "${CONNECTION_CONF}"
		show_fmt_error "Failure to write on %s.\n" "${CONNECTION_CONF}"
		unset CONNECTION_CONF
		return 99
	fi
	debug "Config file that will be used is: \"%s\".\n" "${CONNECTION_CONF}"
	debug show_file "${CONNECTION_CONF}"
	export CONNECTION_COMMAND="${setsidbin} ${wvdialbin} --config \"${CONNECTION_CONF}\""
	debug "Connection command that will be used is: %s\n" "${CONNECTION_COMMAND}"
	return 0
}

ispconnect() {
	[ "a${CONNECTION_COMMAND}" = "a" ] && return 95
	if ppp_fast_status; then
		debug "Already connected.\n"
		return 0
	fi
	! we_are_root && return 1
	debug run_command "${rmbin} -f \"/tmp/sakis3g.3gnet\""
	! tty_not_busy "${MODEM_TTY}" && return 1
	if [ "a$1" = "anoretry" ]; then
		verbose "Connecting (second attempt)"
	else
		verbose "Connecting"
	fi
	logpid=0
	if [ -n "${DEBUG}" ]; then
		eval "${CONNECTION_COMMAND} &"
		logpid=$!
	else
		eval "${CONNECTION_COMMAND} <&- >&- 2>&- &"
		logpid=$!
	fi
	passed=0
	while ! notrunning "${logpid}"
	do
		ppp_slow_status && break
		debug "Waiting for interface to go up (%d seconds passed).\n" "${passed}"
		passed=`expr ${passed} + 1`; passed=`echo ${passed}`
		if [ "a${passed}" = "a21" ]; then
			debug "Giving up waiting for connection to occur.\n"
			if find_binary "kill"; then
				${killbin} -1 ${logpid} 2> /dev/null
				! notrunning "${logpid}" && sleep 1
				! notrunning "${logpid}" && sleep 1
			fi
			break
		fi
		sleep 1
	done
	if notrunning "${logpid}" && [ "a$1" != "anoretry" ]; then
		unset logpid
		ispconnect "noretry"
		return $?
	fi
	unset passed
	if ! ppp_slow_status; then
		debug "Failed to connect.\n"
		unset logpid
		return 95
	fi
	debug "Connection is established.\n"
	${printfbin} "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n" "${ISPID}" "${ISPTEXT}" "${MODEM_VARIANT}" "${USBDRIVER}" "${MODEM_TTY}" "${MODEM}" "${OTHER}" "${APN}" "${CUSTOM_APN}" "${APN_USER}" "${APN_PASS}" "${logpid}" > "/tmp/sakis3g.3gnet"
	[ -f "/tmp/sakis3g.3gnet" ] && ${chmodbin} 644 "/tmp/sakis3g.3gnet"
	unset logpid
	return 0
}

# Deletes all currently existing default gateways.
routing_delete_gateways() {
	! we_are_root && return 1
	! find_binary "netstat" && return 1
	! find_binary "route" && return 1
	while [ "1" = "1" ];
	do
		gatehost=`${netstatbin} -rn | ${grepbin} "^0.0.0.0 " | ${tailbin} -1 | ${sedbin} -e "s/  */ /g" | ${cutbin} -d\  -f2`
		if [ "a${gatehost}" != "a" ]; then
			debug "Deleting default gateway %s.\n" "${gatehost}"
			debug run_command "${routebin} del default gw ${gatehost}"
		else
			debug "Deleted all default gateways.\n"
			break
		fi
	done
	unset gatehost
	return 0
}

# Makes sure only our pppint(ppp0) peer is used as default gateway.
routing_fix() {
	! find_binary "netstat" && return 1
	! find_binary "route" && return 1
	need_arg "pppint"
	hostpeer=`${netstatbin} -rn | ${grepbin} " ${pppint}$" | ${grepbin} -v "^0.0.0.0 " | ${cutbin} -d\  -f1`
	if [ "a${hostpeer}" != "a" ]; then
		routing_delete_gateways
		debug run_command "${routebin} add default gw ${hostpeer}"
		debug "Added correct default gateway: %s.\n" "${hostpeer}"
		debug run_command "${netstatbin} -rn"
	fi
	unset hostpeer
	return 0
}

dns_fix() {
	debug "Checking if required to fix DNS settings.\n"
	unset needdnsfix
	if [ ! -f "/etc/resolv.conf" ]; then
		needdnsfix=1
		debug "No %s exists. Will make it ourselves.\n" "/etc/resolv.conf"
	else
		debug show_file "/etc/resolv.conf"
		baddns=`${grepbin} "10.11.12.13" "/etc/resolv.conf" | ${wcbin} -l`; baddns=`echo ${baddns}`
		[ "a${baddns}" = "a0" ] && baddns=`${grepbin} "10.11.12.14" "/etc/resolv.conf" | ${wcbin} -l`
		baddns=`echo ${baddns}`
		if [ "a${baddns}" != "a0" ]; then
			needdnsfix=1
			debug "File %s contains bad DNS servers. Will fix it.\n" "/etc/resolv.conf"
		fi
		unset baddns
	fi
	if [ "a${DNS}" != "a" ]; then
		needdnsfix=1
		debug "Will fix DNS due to DNS servers being set: %s\n" "${DNS}"
	fi
	if [ "a${needdnsfix}" != "a1" ]; then
		debug "No need to fix DNS servers. Skipping it.\n"
		unset needdnsfix
		return 0
	fi
	if [ "a${DNS}" = "a" ]; then
		debug "No DNS servers where set. Will use Google DNS.\n"
		export DNS="8.8.8.8 8.8.4.4"
	fi
	${rmbin} -f "/etc/resolv.conf"
	${touchbin} "/etc/resolv.conf"
	${chmodbin} 644 "/etc/resolv.conf"
	for dnsserver in ${DNS}
	do
		${printfbin} "nameserver %s\n" "${dnsserver}" >> "/etc/resolv.conf"
		debug "Added name server %s to %s.\n" "${dnsserver}" "/etc/resolv.conf"
	done
	unset dnsserver
	${printfbin} "\n# This file was autogenerated by %s.\n\n" "Sakis3G script" >> "/etc/resolv.conf"
	debug "Done setting up custom DNS server(s).\n"
	return 0
}


flow_post_connection() {
	if [ "a${NOSMART}" != "a" ]; then
		debug "Requested not to smart-fix connection.\n"
		return 0
	fi
	verbose "Fixing connection"
	debug "Running post-connection setup.\n"
	routing_fix
	dns_fix
}

flow_connect() {
	ppp_fast_status && return 0
	flow_prepare "$@"
	ret=$?; [ "${ret}" -ne "0" ] && return ${ret}
	verbose "Resolving connection details"
	flow_select_apn "$@"
	ret=$?; [ "${ret}" -ne "0" ] && return ${ret}
	flow_apn_user "$@"
	ret=$?; [ "${ret}" -ne "0" ] && return ${ret}
	flow_apn_pass "$@"
	ret=$?; [ "${ret}" -ne "0" ] && return ${ret}
	[ "a${MODEM_TTY}" = "a" ] && return 99
	[ ! -c "${MODEM_TTY}" ] && return 99
	[ "a${APN}" = "a" -o "a${APN_USER}" = "a" -o "a${APN_PASS}" = "a" -o "a${ISP_DIAL}" = "a" ] && return 99
	! at_default_commands "DIAL" && return 99
	[ "a${ttycommands}" = "a" ] && return 99
	export DIAL_COMMANDS="${ttycommands}"
	if [ "a${direct_pppd}" != "a" ]; then
		pppd_config "$@"
		ret=$?
	else
		wvdial_config "$@"
		ret=$?
	fi
	unset DIAL_COMMANDS
	[ "${ret}" -ne "0" ] && return ${ret}
	verbose "Initializing modem"
	tty_send_command "${MODEM_TTY}" "INITIALIZE"
	ret=$?; [ "${ret}" -ne "0" ] && return ${ret}
	tty_send_command "${MODEM_TTY}" "STAGE7"
	tty_send_command "${MODEM_TTY}" "STAGE8"
	ispconnect "$@"
	ret=$?
	[ "a${CONNECTION_CONF}" != "a" ] && [ -f "${CONNECTION_CONF}" ] && ${rmbin} -f "${CONNECTION_CONF}"
	unset CONNECTION_CONF; unset CONNECTION_COMMAND
	[ "${ret}" -ne "0" ] && return ${ret}
	flow_post_connection "$@"
	if [ "a${CONNECTION_HOOK}" != "a" ]; then
		debug "Will now execute CONNECTION_HOOK: %s.\n" "${CONNECTION_HOOK}"
		term_clearline
		debug run_command "${CONNECTION_HOOK}"
		debug "Connection hook returned.\n"
	fi
	! ppp_slow_status && return 99
	return ${ret}
}

flow_disconnect() {
	! ppp_fast_status && return 0
	! we_are_root && return 1
	verbose "Disconnecting"
	if find_binary "killall"; then
		${killallbin} -q -1 pppd
		sleep 1
		ppp_fast_status && ${killallbin} -q -9 pppd
	elif find_binary "ps" && find_binary "kill"; then
		ppppid=`${psbin} -C "pppd" -o pid= 2> /dev/null | ${grepbin} -i "PID"`; ppppid=`echo ${ppppid}`
		for propid in ${ppppid}
		do
			debug run_command "kill -1 ${propid}"
		done
		ppppid=`${psbin} -C "pppd" -o pid= 2> /dev/null | ${grepbin} -i "PID"`; ppppid=`echo ${ppppid}`
		for propid in ${ppppid}
		do
			debug run_command "kill -9 ${propid}"
		done
		unset ppppid; unset propid
	else
		show_fmt_error "Unable to stop running pppd session. Both %s and % were not found.\n" "kill" "killall"
		return 1
	fi
	sleep 1
	if ppp_fast_status; then
		debug "Failed to disconnect.\n"
		return 1
	fi
	debug "Disconnected.\n"
	return 0
}

compile_check_local_requirements() {
	if [ "a${PROVIDER}" = "a" ]; then
		show_fmt_error "Not running from within package.\n"
		return 1
	fi
	if [ ! -x "${PROVIDER}" ]; then
		show_fmt_error "Reported package location is not executable: %s\n" "${PROVIDER}"
		return 1
	fi
	if [ ! -w "${PROVIDER}" ] && we_are_root; then
		show_fmt_error "Unable to overwrite existing package %s. Check if on read-only filesystem.\n" "${PROVIDER}"
		return 1
	fi
	return 0
}

compile_check_dependencies() {
	unset missing
	for localdependency in bzip2 bunzip2 pwd basename dirname gcc tar dd stat cp chmod rm mkdir mv find rmdir printf grep expr ls sort uniq cut sed tr cat touch
	do
		! find_binary "${localdependency}" && missing="${missing} ${localdependency}"
	done
	missing=`echo ${missing}`
	if [ "a${missing}" != "a" ]; then
		show_fmt_error "Following dependencies not found within path: %s\n" "${missing}"
		unset missing
		return 1
	fi
	unset missing
	return 0
}

compile_compilation_dependencies() {
	[ "a${PROVIDER}" = "a" ] && return 1
	[ ! -x "${PROVIDER}" ] && return 1
	${rmbin} -f "/tmp/sakis3g.source.$$.combined.c" > /dev/null 2> /dev/null
	${touchbin} "/tmp/sakis3g.source.$$.combined.c" > /dev/null 2> /dev/null
	if [ ! -f "/tmp/sakis3g.source.$$.combined.c" ]; then
		show_fmt_error "Unable to create file %s.\n" "/tmp/sakis3g.source.$$.combined.c"
		return 1
	fi
	${PROVIDER} getfile usb_modeswitch.c 2> /dev/null > "/tmp/sakis3g.source.$$.c"
	${PROVIDER} getfile usb_modeswitch.h 2> /dev/null > "/tmp/sakis3g.source.$$.h"
	${catbin} "/tmp/sakis3g.source.$$.c" "/tmp/sakis3g.source.$$.h" > "/tmp/sakis3g.source.$$.combined.c"
	if [ ! -s "/tmp/sakis3g.source.$$.combined.c" ]; then
		${rmbin} -f "/tmp/sakis3g.source.$$.combined.c" "/tmp/sakis3g.source.$$.c" "/tmp/sakis3g.source.$$.h" > /dev/null 2> /dev/null
		show_fmt_error "Unable to extract %s source from package.\n" "Usb-ModeSwitch"
		return 1
	fi
	headerfiles=`${grepbin} "^#include <" "/tmp/sakis3g.source.$$.combined.c" | ${sedbin} -e "s/\(  *\)/ /g" | ${cutbin} -d\  -f2 -s | ${sedbin} -e "s/^<\(.*\)>$/INCLUDE:\1/g" | ${grepbin} "^INCLUDE:" | ${cutbin} -d: -f2- -s`
	if [ "a${headerfiles}" = "a" ]; then
		unset headerfiles
		${rmbin} -f "/tmp/sakis3g.source.$$.combined.c" "/tmp/sakis3g.source.$$.c" "/tmp/sakis3g.source.$$.h" > /dev/null 2> /dev/null
		show_fmt_error "Problem while parsing %s sources.\n" "Usb-ModeSwitch"
		return 1
	fi
	debug "Header files are:\n%s\n" "${headerfiles}"
	accumulative=""
	for header in ${headerfiles}
	do
		debug "Probing: %s\n" "${header}"
		accumulative=`${printfbin} "%s\n%s\n" "${accumulative}" "${header}" | ${grepbin} -v "^$"`
		echo "${accumulative}" | ${sedbin} -e "s/^\(.*\)$/#include <\1\>/g" > "/tmp/sakis3g.source.$$.combined.c"
		${printfbin} "int main(int argc, char **argv) {\nreturn 22;\n}\n\n" >> "/tmp/sakis3g.source.$$.combined.c"
		${rmbin} -f "/tmp/sakis3g.object.$$" > /dev/null 2> /dev/null
		if [ -f "/tmp/sakis3g.object.$$" ]; then
			unset headerfiles; unset header; unset accumulative;
			${rmbin} -f "/tmp/sakis3g.source.$$.combined.c" "/tmp/sakis3g.source.$$.c" "/tmp/sakis3g.source.$$.h" > /dev/null 2> /dev/null
			show_fmt_error "Unable to delete \"%s\".\n" "/tmp/sakis3g.object.$$"
			return 1
		fi
		debug run_command "${gccbin} -Wall -l usb-1.0 -o \"/tmp/sakis3g.object.$$\" \"/tmp/sakis3g.source.$$.combined.c\" -lusb-1.0 "
		if [ ! -x "/tmp/sakis3g.object.$$" ]; then
			if [ "a${header}" != "ausb.h" ]; then
				show_fmt_error "Header file %s missing from your system.\n" "${header}"
			else
				show_fmt_error "Header file %s missing from your system. This usually indicates libusb (or libusb-compat) development kit missing.\n" "${header}"
			fi
			unset headerfiles; unset header; unset accumulative;
			${rmbin} -f "/tmp/sakis3g.source.$$.combined.c" "/tmp/sakis3g.source.$$.c" "/tmp/sakis3g.source.$$.h" > /dev/null 2> /dev/null
			${rmbin} -f "/tmp/sakis3g.object.$$" > /dev/null 2> /dev/null
			return 1
		fi
		debug run_command "/tmp/sakis3g.object.$$"
		ret=$?
		if [ "${ret}" -ne "22" ]; then
			show_fmt_error "Unusable binary after including \"%s\".\n" "${header}"
			unset headerfiles; unset header; unset accumulative;
			${rmbin} -f "/tmp/sakis3g.source.$$.combined.c" "/tmp/sakis3g.source.$$.c" "/tmp/sakis3g.source.$$.h" > /dev/null 2> /dev/null
			${rmbin} -f "/tmp/sakis3g.object.$$" > /dev/null 2> /dev/null
			return 1
		fi
		debug "No problem encountered when including \"%s\".\n" "${header}"
		${rmbin} -f "/tmp/sakis3g.object.$$" > /dev/null 2> /dev/null
	done
	${rmbin} -f "/tmp/sakis3g.source.$$.combined.c" > /dev/null 2> /dev/null
	unset header; unset headerfiles;
	debug "Will now attempt linking.\n"
	echo "${accumulative}" | ${sedbin} -e "s/^\(.*\)$/#include <\1\>/g" > "/tmp/sakis3g.source.$$.combined.c"
	${catbin} "/tmp/sakis3g.source.$$.h" "/tmp/sakis3g.source.$$.c" | ${grepbin} -v "^#include" >> "/tmp/sakis3g.source.$$.combined.c"
	debug show_file "/tmp/sakis3g.source.$$.combined.c"
	debug run_command "${gccbin} -Wall -l usb-1.0 -o \"/tmp/sakis3g.object.$$\" \"/tmp/sakis3g.source.$$.combined.c\" -lusb-1.0"
	unset accumulative;
	${rmbin} -f "/tmp/sakis3g.source.$$.combined.c" "/tmp/sakis3g.source.$$.c" "/tmp/sakis3g.source.$$.h" > /dev/null 2> /dev/null
	if [ ! -x "/tmp/sakis3g.object.$$" ]; then
		${rmbin} -f "/tmp/sakis3g.object.$$" > /dev/null 2> /dev/null
		show_fmt_error "Failed to link %s. This usually indicates libusb (or libusb-compat) development kit missing.\n" "Usb-ModeSwitch"
		return 1
	fi
	${rmbin} -f "/tmp/sakis3g.object.$$" > /dev/null 2> /dev/null
	debug "Linking test was successful.\n"
	return 0
}

compile_perform() {
	[ "a${PROVIDER}" = "a" ] && return 1
	[ ! -x "${PROVIDER}" ] && return 1
	tempdestination="/tmp/sakis3g.recompile.$$"
	debug run_command "${rmbin} -rf \"${tempdestination}\""
	debug run_command "${mkdirbin} \"${tempdestination}\""
	if [ ! -d "${tempdestination}" ]; then
		show_fmt_error "Unable to create temporary folder \"%s\".\n" "${tempdestination}"
		unset tempdestination
		return 1
	fi
	debug run_command "${touchbin} \"${tempdestination}/test.$$\""
	if [ ! -w "${tempdestination}/test.$$" ]; then
		debug run_command "${rmbin} -rf \"${tempdestination}\""
		show_fmt_error "No write access to temporary folder \"%s\".\n" "${tempdestination}"
		unset tempdestination
		return 1
	fi
	debug run_command "${rmbin} -rf \"${tempdestination}/\"*"
	if [ ! -d "${tempdestination}" ]; then
		show_fmt_error "Oops. Weird \"%s\" version. Deleted temporary folder \"%s\".\n" "${rmbin}" "${tempdestination}"
		unset tempdestination
		return 1
	fi
	debug run_command "${PROVIDER} disassemble \"${tempdestination}/.\""
	if [ ! -x "${tempdestination}/sakis3g-${MYVERSION}/compile" ]; then
		debug run_command "${rmbin} -rf \"${tempdestination}\""
		show_fmt_error "Failed to disassemble Sakis3G package.\n" "${tempdestination}"
		unset tempdestination
		return 1
	fi
	debug run_command "${rmbin} -f \"${tempdestination}/sakis3g-${MYVERSION}/build/sakis3gz\""
	compilation_error=`cd "${tempdestination}/sakis3g-${MYVERSION}"; ./compile 2>&1`
	debug "Compilation output:\n%s\n" "${compilation_error}"
	if [ ! -x "${tempdestination}/sakis3g-${MYVERSION}/build/sakis3gz" -o ! -s "${tempdestination}/sakis3g-${MYVERSION}/build/sakis3gz" ]; then
		debug run_command "${rmbin} -rf \"${tempdestination}\""
		show_fmt_error "Failed to compile. Compilation output:\n%s\n" "${compilation_error}"
		unset compilation_error; unset tempdestination
		return 1
	fi
	unset compilation_error
	verification=`"${tempdestination}/sakis3g-${MYVERSION}/build/sakis3gz" usb_modeswitch --version 2> /dev/null | ${grepbin} -i "josua" | ${wcbin} -l`; verification=`echo ${verification}`
	if [ "a${verification}" = "a" -o "a${verification}" = "a0" ]; then
		unset verification
		debug run_command "${rmbin} -rf \"${tempdestination}\""
		show_fmt_error "Failed to verify result of compilation.\n"
		unset tempdestination
		return 1
	fi
	unset verification
	debug run_command "${rmbin} -f \"${PROVIDER}.backup\""
	if [ -f "${PROVIDER}.backup" ]; then
		debug run_command "${rmbin} -rf \"${tempdestination}\""
		show_fmt_error "Unable to delete previously existing \"%s\".\n" "${PROVIDER}.backup"
		unset tempdestination
		return 1
	fi
	debug run_command "${cpbin} \"${PROVIDER}\" \"${PROVIDER}.backup\""
	if [ ! -f "${PROVIDER}.backup" ]; then
		debug run_command "${rmbin} -rf \"${tempdestination}\""
		show_fmt_error "Unable to create a safe backup to \"%s\".\n" "${PROVIDER}.backup"
		unset tempdestination
		return 1
	fi
	debug run_command "${lsbin} -l \"${PROVIDER}\""
	# No rm, or we loose owner and rights information
	#debug run_command "${rmbin} -f \"${PROVIDER}\""
	#debug run_command "${lsbin} -l \"${PROVIDER}\""
	debug run_command "${cpbin} \"${tempdestination}/sakis3g-${MYVERSION}/build/sakis3gz\" \"${PROVIDER}\""
	debug run_command "${lsbin} -l \"${PROVIDER}\""
	debug run_command "${rmbin} -rf \"${tempdestination}\""
	unset tempdestination
	verification=`"${PROVIDER}" usb_modeswitch --version 2> /dev/null | ${grepbin} -i "josua" | ${wcbin} -l`; verification=`echo ${verification}`
	if [ "a${verification}" = "a" -o "a${verification}" = "a0" ]; then
		debug "Verification failed. Restoring previous version.\n"
		debug run_command "${cpbin} \"${PROVIDER}.backup\" \"${PROVIDER}\""
		unset verification
		if [ -x "${PROVIDER}" ]; then
			show_fmt_error "Failed to succesfully place new version. You are still using old version.\n"
		elif [ -x "${PROVIDER}.backup" ]; then
			show_fmt_error "Failed to succesfully create new version. Old version is still available at \"%s\".\n" "${PROVIDER}.backup"
		else
			show_fmt_error "Something really bad happened. I am really sorry. You may need to re-download Sakis3G.\n"
		fi
		return 1
	fi
	unset verification
	debug run_command "${rmbin} -f \"${PROVIDER}.backup\""
	debug run_command "${lsbin} -l \"${PROVIDER}.backup\""
	debug "Succesfully recompiled.\n"
	return 0
}

flow_compile() {
	if [ "a${binaryfree}" != "a" ]; then
		show_fmt_error "You are running a binary free version of Sakis3G. Unable to recompile %s.\n" "Usb-ModeSwitch"
		return 99
	fi
	verbose "Checking tools availability"
	compile_check_local_requirements
	ret=$?; [ "${ret}" -ne "0" ] && return ${ret}
	verbose "Checking dependencies"
	compile_check_dependencies
	ret=$?; [ "${ret}" -ne "0" ] && return ${ret}
	verbose "Testing compiler"
	compile_compilation_dependencies
	ret=$?; [ "${ret}" -ne "0" ] && return ${ret}
	verbose "Compiling"
	compile_perform
	ret=$?; [ "${ret}" -ne "0" ] && return ${ret}
	return 0
}

flow_report() {
	if ! status_connected; then
		show_fmt_error "You need to be connected for generating report.\n"
		return 6
	fi
	unset report_text
	old_translation=${notranslate}
	export notranslate=1
	report_text="Sakis3G version: ${MYVERSION}"
	if [ "a${PROVIDER}" = "a" ]; then
		report_text=`${printfbin} "%s\nNot running from within package.\n" "${report_text}"`
	elif [ ! -x "${PROVIDER}" ]; then
		report_text=`${printfbin} "%s\nPackage is not executable.\n" "${report_text}"`
	else
		if [ "a${binaryfree}" != "a" ]; then
			if [ "a${stripped}" != "a" ]; then
				report_text=`${printfbin} "%s\nRunning a binary free version.\n" "${report_text}"`
			else
				report_text=`${printfbin} "%s\nRunning a stripped version.\n" "${report_text}"`
			fi
			switchversion="95"
		else
			switchversion=`${PROVIDER} usb_modeswitch --version 2> /dev/null || echo $?`
		fi
		if [ "a${switchversion}" = "a95" ]; then
			if find_binary "usb_modeswitch"; then
				switchversion=`${usb_modeswitchbin} --version 2> /dev/null`
				report_text=`${printfbin} "%s\nSystem provided Usb-ModeSwitch:\n%s\n" "${report_text}" "${switchversion}"`
			else
				report_text=`${printfbin} "%s\nUsb-ModeSwitch is not available.\n" "${report_text}"`
			fi 
		else
			switchversion=`${printfbin} "%s\n" "${switchversion}" | ${grepbin} -i version`
			report_text=`${printfbin} "%s\nUsing embedded Usb-ModeSwitch version:\n%s\n" "${report_text}" "${switchversion}"` 
		fi
	fi
	if find_binary "uname"; then
		report_text=`${printfbin} "%s\nKernel version: %s\nArchitect: %s\n" "${report_text}" "\`${unamebin} -r\`" "\`${unamebin} -m\`"`
	else
		report_text=`${printfbin} "%s\nUtility uname is not available.\n" "${report_text}"`
	fi
	report_text=`${printfbin} "%s\nSelected UI is: %s\n" "${report_text}" "${SGUI}"`
	info_text=`action_info report | ${grepbin} -v "^$" | ${grepbin} -v "^ $"`
	report_text=`${printfbin} "%s\n%s\n" "${report_text}" "${info_text}"`
	state_variables "APN_USER APN_PASS SIM_PIN SGUI UNDISCOVERABLE BLUETOOTH MENU MOREMENU BALOONIZER"
	report_text=`${printfbin} "%s\nVariables: %s\n" "${report_text}" "${statevariables}"`
	unset info_text
	export notranslate="${old_translation}"
	[ "a${notranslate}" = "a" ] && unset notranslate
	unset old_translation
	trtext=`format_text "Please report following text:\n"`
	notify "%s\n\n%s\n" "${trtext}" "${report_text}"
	unset trtext; unset switchversion; unset report_text
	return 0
}


# Returns 0 if connected, 1 if not connected.
# Sets as much of the following information:
# - statusnet containing numeric ID of ISP
# - statusname containing text of ISP or nothing
# - statusicon if statusnet exists within operator database and contains icon.
# Sets ISPID only if not set already.
# It is possible that it returns 0 and not set variables. This happens
# if ppp interface was initiated by another application.
status_connected() {
	unset statusnet; unset statusname; unset statusicon; unset localpid
	! ppp_fast_status && return 1
	if [ -r "/tmp/sakis3g.3gnet" ]; then
		statusnet=`${headbin} -1 "/tmp/sakis3g.3gnet"`
		statusname=`${headbin} -2 "/tmp/sakis3g.3gnet" | ${tailbin} -1`
		debug "Retrieved from %s: \"%s\" - \"%s\"\n" "/tmp/sakis3g.3gnet" "${statusnet}" "${statusname}"
		statusnet=`echo "${statusnet}" | ${grepbin} "^[0-9][0-9][0-9][0-9][0-9]"`
		if [ "a${statusnet}" != "a" ]; then
			[ "a${statusname}" = "a${statusnet}" ] && unset statusname
			debug "Retrieved ISP ID from %s: %s\n" "/tmp/sakis3g.3gnet" "${statusnet}"
			[ "a${statusname}" != "a" ] && debug "Also retrieved ISP name: %s\n" "${statusname}"
		else
			unset statusname; unset statusnet
			debug "Invalid or not existing %s within %s.\n" "ISPID" "/tmp/sakis3g.3gnet"
		fi
		if [ "a${statusnet}" != "a" ] && [ "a${ISPID}" = "a" -o "a${ISPID}" = "a${statusnet}" ]; then
			if [ "a${MODEM_VARIANT}" = "a" ]; then
				MODEM_VARIANT=`${headbin} -3 "/tmp/sakis3g.3gnet" | ${tailbin} -1`
				[ "a${MODEM_VARIANT}" != "a" ] && export MODEM_VARIANT && debug "Also read: %s\n" "${MODEM_VARIANT}"
			fi
			if [ "a${USBDRIVER}" = "a" ]; then
				USBDRIVER=`${headbin} -4 "/tmp/sakis3g.3gnet" | ${tailbin} -1`
				[ "a${USBDRIVER}" != "a" ] && export USBDRIVER && debug "Also read: %s\n" "${USBDRIVER}"
			fi
			if [ "a${MODEM_TTY}" = "a" ]; then
				MODEM_TTY=`${headbin} -5 "/tmp/sakis3g.3gnet" | ${tailbin} -1`
				[ "a${MODEM_TTY}" != "a" ] && export MODEM_TTY && debug "Also read: %s\n" "${MODEM_TTY}"
			fi
			if [ "a${MODEM}" = "a" ]; then
				MODEM=`${headbin} -6 "/tmp/sakis3g.3gnet" | ${tailbin} -1`
				[ "a${MODEM}" != "a" ] && export MODEM && debug "Also read: %s\n" "${MODEM}"
			fi
			if [ "a${OTHER}" = "a" ]; then
				OTHER=`${headbin} -7 "/tmp/sakis3g.3gnet" | ${tailbin} -1`
				[ "a${OTHER}" != "a" ] && export OTHER && debug "Also read: %s\n" "${OTHER}"
			fi
			if [ "a${APN}" = "a" ]; then
				APN=`${headbin} -8 "/tmp/sakis3g.3gnet" | ${tailbin} -1`
				[ "a${APN}" != "a" ] && export APN && debug "Also read: %s\n" "${APN}"
			fi
			if [ "a${CUSTOM_APN}" = "a" -a "a${APN}" = "aCUSTOM_APN" ]; then
				CUSTOM_APN=`${headbin} -9 "/tmp/sakis3g.3gnet" | ${tailbin} -1`
				[ "a${CUSTOM_APN}" != "a" ] && export CUSTOM_APN && debug "Also read: %s\n" "${CUSTOM_APN}"
			fi
			if [ "a${APN_USER}" = "a" ]; then
				APN_USER=`${headbin} -10 "/tmp/sakis3g.3gnet" | ${tailbin} -1`
				[ "a${APN_USER}" != "a" ] && export APN_USER && debug "Also read: %s\n" "${APN_USER}"
			fi
			if [ "a${APN_PASS}" = "a" ]; then
				APN_PASS=`${headbin} -11 "/tmp/sakis3g.3gnet" | ${tailbin} -1`
				[ "a${APN_PASS}" != "a" ] && export APN_PASS && debug "Also read: %s\n" "${APN_PASS}"
			fi
			localpid=`${headbin} -12 "/tmp/sakis3g.3gnet" | ${tailbin} -1`
			if [ "a${localpid}" != "a" ]; then
				localprocess=`${psbin} -p ${localpid} -o comm= 2> /dev/null`
				if [ "a${localprocess}" != "a" ]; then
					debug "Process ID %s is: %s\n" "${localpid}" "${localprocess}"
					[ "${localprocess}" != "pppd" -a "${localprocess}" != "wvdial" ] && unset localprocess
				elif notrunning "${localpid}"; then
					debug "Process ID %s is not running.\n" "${localpid}"
				elif [ "a${localprocess}" = "a" ]; then
					debug "Process ID %s is not valid.\n" "${localpid}"
				fi
				if [ "a${localprocess}" = "a" -a "a${ISPID}" = "a" ]; then
					debug "Status file %s is stalled. Will discard information read from it.\n" "/tmp/sakis3g.3gnet"
					unset statusnet; unset statusname
				fi
			fi
			unset localpid; unset localprocess
		fi
	else
		debug "Invalid or not existing %s.\n" "/tmp/sakis3g.3gnet"
	fi
	if [ "a${ISPID}" != "a" ]; then
		debug "%s is set to: %s\n" "ISPID" "${ISPID}"
		if [ "a${statusnet}" = "a" ]; then
			statusnet="${ISPID}"
			debug "Was adapted since file not available.\n" "statusnet"
			if [ "a${ISPTEXT}" != "a" -a "a${ISPTEXT}" != "a${ISPID}" ]; then
				statusname="${ISPTEXT}"
				debug "Also adapted %s: %s\n" "ISPTEXT" "${ISPTEXT}"
			fi
		elif [ "a${statusnet}" = "a${ISPID}" ]; then
			debug "It matches value retrieved from file.\n"
			if [ "a${ISPTEXT}" != "a" -a "a${ISPTEXT}" != "a${ISPID}" -a "a${statusname}" = "a" ]; then
				statusname="${ISPTEXT}"
				debug "Also adapted %s since networks match: %s\n" "ISPTEXT" "${ISPTEXT}"
			fi
		else
			debug "Does not match value retrieved from file.\n"
			debug "Will trust file.\n"
		fi
	else
		debug "%s is not set.\n" "ISPID"
		if [ "a${statusnet}" = "a" ]; then
			debug "Unable to determine on which network we are connected.\n"
		else
			export ISPID="${statusnet}"
			debug "All information derived from file.\n"
			debug "Also set %s from file contents.\n" "ISPID"
		fi
	fi
	if net_info "${statusnet}" "${statusname}" && [ "a${BASERESULT}" != "a" ]; then
		statusproduct=`echo "${BASERESULT}" | ${cutbin} -f3 -s`
		[ "a${statusproduct}" != "a" ] && export statusproduct
		statusicon=`echo "${BASERESULT}" | ${cutbin} -f8 -s`
		[ "a${statusicon}" != "a" ] && export statusicon
		if [ "a${statusname}" = "a" ]; then
			statusname=`echo "${BASERESULT}" | ${cutbin} -d: -f2 -s`
			[ "a${statusname}" != "a" ] && debug "Retrieved %s name from database: %s\n" "${statusnet}" "${statusname}"
		fi
	fi
	if [ "a${statusnet}" = "a" ]; then
		unset statusnet; unset statusname
	else
		export statusnet
		if [ "a${statusname}" = "a" ]; then
			unset statusname
		else
			export statusname
		fi
	fi
	return 0
}

# Method invoked when "status" action was requested.
action_status() {
	unset verbosecurrentcount
	if ! ppp_fast_status; then
		show_fmt_error "Not connected.\n"
		return 6
	fi
	status_connected
	if [ "a${statusnet}" != "a" ]; then
		if [ "a${statusnet}" != "a${statusname}" -a "a${statusname}" != "a" ]; then
			if [ "a${MODEM_VARIANT}" != "a" ]; then
				finalnotify "%s connected to %s (%s)." "${MODEM_VARIANT}" "${statusname}" "${statusnet}"
			else
				finalnotify "Connected to %s (%s)." "${statusname}" "${statusnet}"
			fi
		else
			if [ "a${MODEM_VARIANT}" != "a" ]; then
				finalnotify "%s connected to %s." "${MODEM_VARIANT}" "${statusnet}"
			else
				finalnotify "Connected to %s." "${statusnet}"
			fi
		fi
	else
		finalnotify "Connected."
	fi
	return 0
}

action_info() {
	unset verbosecurrentcount
	if ! ppp_fast_status; then
		notify "Not connected.\n"
		return 0
	fi
	status_connected
	if [ "a${statusnet}" = "a" ]; then
		notify "Unable to gather connection information.\n"
		return 0
	fi
	if [ "a$1" != "areport" ]; then
		infotext=`translate_text "Connection Information"`
		infotext=`${printfbin} "%s\n \n" "${infotext}"`
	fi
	[ "a${pppint}" != "a" ] && localtext=`format_text "Interface:\t\t\tP-t-P (%s)\n" "${pppint}"`
	[ "a${localtext}" != "a" ] && infotext=`${printfbin} "%s\n%s\n" "${infotext}" "${localtext}"`; unset localtext
	infotext=`${printfbin} "%s\n \n" "${infotext}"`
	if [ "a$1" != "areport" ]; then
		if find_binary "stat"; then
			upsince=`${statbin} --printf="%z" "/tmp/sakis3g.3gnet" | ${cutbin} -d: -f1,2 -s`
			if [ "a${upsince}" != "a" ]; then
				localtext=`format_text "Connected since:\t%s\n" "${upsince}"`
				infotext=`${printfbin} "%s\n%s\n" "${infotext}" "${localtext}"`; unset localtext
			fi
			unset upsince
		fi
		if [ -r "/proc/net/dev" -a "a${pppint}" != "a" ]; then
			traffic=`${sedbin} -e "s/  */ /g" "/proc/net/dev" | ${grepbin} "^\( *\)${pppint}:" | ${headbin} -1 | ${cutbin} -d: -f2- | ${sedbin} -e "s/^  *//g" | ${cutbin} -d\  -f1,9`
			debug "Traffic details are: %s\n" "${traffic}"
			bytesreceived=`echo ${traffic} | ${cutbin} -d\  -f1 -s`
			[ "a${bytesreceived}" != "a" ] && bytesreceived=`expr \( ${bytesreceived} + 512 \) / 1024 2> /dev/null`
			[ "a${bytesreceived}" != "a" ] && localtext=`format_text "Kilobytes received:\t%d\n" ${bytesreceived}`
			[ "a${localtext}" != "a" ] && infotext=`${printfbin} "%s\n%s\n" "${infotext}" "${localtext}"`; unset localtext
			bytessent=`echo ${traffic} | ${cutbin} -d\  -f2 -s`
			[ "a${bytessent}" != "a" ] && bytessent=`expr \( ${bytessent} + 512 \) / 1024 2> /dev/null`
			[ "a${bytessent}" != "a" ] && localtext=`format_text "Kilobytes sent:\t%d\n" ${bytessent}`
			[ "a${localtext}" != "a" ] && infotext=`${printfbin} "%s\n%s\n" "${infotext}" "${localtext}"`; unset localtext
			unset traffic; unset bytesreceived; unset bytessent
		fi
	fi
	localtext=`format_text "Network ID:\t\t%s" "${statusnet}"`
	[ "a${localtext}" != "a" ] && infotext=`${printfbin} "%s\n\n%s\n" "${infotext}" "${localtext}"`; unset localtext
	[ "a${statusname}" != "a" ] && localtext=`format_text "Operator name:\t%s" "${statusname}"`
	[ "a${localtext}" != "a" ] && infotext=`${printfbin} "%s\n%s\n" "${infotext}" "${localtext}"`; unset localtext
	if [ "a${APN}" != "a" ]; then
		if [ "a${APN}" = "aCUSTOM_APN" -a "a${CUSTOM_APN}" != "a" ]; then
			localtext=`format_text "APN:\t\t\t%s" "${CUSTOM_APN}"`
		elif [ "a${APN}" != "aCUSTOM_APN" ]; then
			localtext=`format_text "APN:\t\t\t%s" "${APN}"`
		fi
	fi
	[ "a${localtext}" != "a" ] && infotext=`${printfbin} "%s\n%s\n" "${infotext}" "${localtext}"`; unset localtext
	infotext=`${printfbin} "%s\n \n" "${infotext}"`
	[ "a${MODEM_VARIANT}" != "a" ] && localtext=`format_text "Modem:\t\t\t%s\n" "${MODEM_VARIANT}"`
	[ "a${localtext}" != "a" ] && infotext=`${printfbin} "%s\n%s\n" "${infotext}" "${localtext}"`; unset localtext
	if [ "a${MODEM}" != "a" ]; then
		if [ "a${MODEM}" != "a" -a "a${MODEM}" != "aOTHER" ]; then
			localtext=`format_text "Modem type:\t\tUSB\n"`
		elif [ "a${MODEM}" = "aOTHER" ]; then
			if [ "a${OTHER}" = "aUSBMODEM" ]; then
				localtext=`format_text "Modem type:\t\tUSB\n"`
			elif [ "a${OTHER}" = "aBLUETOOTH" ]; then
				localtext=`format_text "Modem type:\t\tBluetooth\n"`
			else
				localtext=`format_text "Modem type:\t\tCustom\n"`
			fi
		else
			localtext=`format_text "Modem type:\t\tUnknown\n"`
		fi
	else
		localtext=`format_text "Modem type:\t\tUnspecified\n"`
	fi
	[ "a${localtext}" != "a" ] && infotext=`${printfbin} "%s\n%s\n" "${infotext}" "${localtext}"`; unset localtext
	[ "a${USBDRIVER}" != "a" ] && localtext=`format_text "Kernel driver:\t\t%s\n" "${USBDRIVER}"`
	[ "a${localtext}" != "a" ] && infotext=`${printfbin} "%s\n%s\n" "${infotext}" "${localtext}"`; unset localtext
	[ "a${MODEM_TTY}" != "a" ] && localtext=`format_text "Device:\t\t\t%s\n" "${MODEM_TTY}"`
	[ "a${localtext}" != "a" ] && infotext=`${printfbin} "%s\n%s\n" "${infotext}" "${localtext}"`; unset localtext
	infotext=`${printfbin} "%s\n \n" "${infotext}"`
	if [ "a$1" != "areport" ]; then
		if find_binary "ifconfig" && [ "a${pppint}" != "a" ]; then
			ipaddress=`${ifconfigbin} ${pppint} | ${sedbin} -e "s/^.*:\([0-9][0-9]*\)\.\([0-9][0-9]*\)\.\([0-9][0-9]*\)\.\([0-9][0-9]*\) .*:\([0-9][0-9]*\)\.\([0-9][0-9]*\)\.\([0-9][0-9]*\)\.\([0-9][0-9]*\) \(.*\):\([0-9][0-9]*\)\.\([0-9][0-9]*\)\.\([0-9][0-9]*\)\.\([0-9][0-9]*\)$/IPADDRESSES: \1.\2.\3.\4 \5.\6.\7.\8/g" | ${grepbin} "^IPADDRESSES:" | ${cutbin} -d: -f2- -s`
			if [ "a${ipaddress}" != "a" ]; then
				localip=`echo ${ipaddress} | ${cutbin} -d\  -f1 -s`
				localpeer=`echo ${ipaddress} | ${cutbin} -d\  -f2 -s`
				localmask="255.255.255.255"
				[ "a${localip}" != "a" ] && localtext=`format_text "IP Address:\t\t%s\n" "${localip}"`
				[ "a${localtext}" != "a" ] && infotext=`${printfbin} "%s\n%s\n" "${infotext}" "${localtext}"`; unset localtext
				[ "a${localip}" != "a" ] && localtext=`format_text "Subnet Mask:\t\t%s\n" "${localmask}"`
				[ "a${localtext}" != "a" ] && infotext=`${printfbin} "%s\n%s\n" "${infotext}" "${localtext}"`; unset localtext
				[ "a${localpeer}" != "a" ] && localtext=`format_text "Peer IP Address:\t%s\n" "${localpeer}"`
				[ "a${localtext}" != "a" ] && infotext=`${printfbin} "%s\n%s\n" "${infotext}" "${localtext}"`; unset localtext
				unset localip; unset localpeer; unset localmask
			fi
			unset ipaddress
		fi
		if find_binary "netstat" && [ "a${pppint}" != "a" ]; then
			localpeer=`${netstatbin} -rn | ${grepbin} "^0.0.0.0 " | ${sedbin} -e "s/  */ /g" | ${cutbin} -d\  -f2 -s`; localpeer=`echo ${localpeer}`
			[ "a${localpeer}" != "a" ] && localtext=`format_text "Default route(s):\t%s\n" "${localpeer}"`
			[ "a${localtext}" != "a" ] && infotext=`${printfbin} "%s\n%s\n" "${infotext}" "${localtext}"`; unset localtext
			unset localpeer
		fi
		[ "a${SGUI}" != "azenity" ] && infotext=`echo "${infotext}" | ${sedbin} -e "s/\(		*\)/ /g"`
		notify "%s\n" "${infotext}"
	else
		infotext=`echo "${infotext}" | ${sedbin} -e "s/\(		*\)/ /g"`
		${printfbin} "%s\n" "${infotext}"
	fi
	unset localtext; unset infotext
	return 0
}

action_desktop() {
	# Retrieve icon information if possible
	[ "a${runner}" = "a" ] && return 1
	[ "a${runhome}" = "a" ] && return 1
	[ ! -d "${runhome}" ] && return 1
	need_binary "touch"; need_binary "mkdir"; need_binary "chown"; need_binary "chmod"; need_binary "cat"
	unset desktopdestination
	if [ "a${DESKTOP}" = "a" ] && find_binary "xdg-user-dir"; then
		DESKTOP=`${xdg_user_dirbin} DESKTOP`
		[ "a${DESKTOP}" = "a" ] && DESKTOP=`${xdg_user_dirbin} desktop`
		if [ "a${DESKTOP}" != "a" ]; then
			DESKTOP=`echo "${DESKTOP}" | ${sedbin} -e "s/\/$//g"`
			DESKTOP=`${basenamebin} "${DESKTOP}"`
		fi
	fi
	if [ "a${DESKTOP}" != "a" ] && [ -d "${DESKTOP}" ]; then
		desktopdestination="${DESKTOP}"
	elif [ -d "${runhome}/Desktop" ]; then
		desktopdestination="${runhome}/Desktop"
	elif [ -d "${runhome}/desktop" ]; then
		desktopdestination="${runhome}/desktop"
	elif [ "a${HOME}" != "a" -a "a${DESKTOP}" != "a" ] && [ -d "${HOME}/${DESKTOP}" ]; then
		desktopdestination="${HOME}/${DESKTOP}"
	elif find_binary "pwd"; then
		desktopdestination="`${pwdbin} 2> /dev/null`"
	else
		desktopdestination="."
	fi
	[ "a${desktopdestination}" = "a" ] && desktopdestination="."
	debug "Destination of shortcut is: %s\n" "${desktopdestination}"
	if status_connected && [ "a${statusicon}" != "a" -a "a${statusname}" != "a" ] && find_binary "wget" && find_binary "basename"; then
		user_select "DESKTOPICON" "Desktop icon" "Select icon to use for shortcut" "OK" "Cancel" "SAKIS3G" "Sakis3G tux icon" "OPERATOR" "${statusname} icon"
		selection=$?
		case "${selection}" in
			1)
				DESKTOPICON="SAKIS3G"
				;;
			2)
				DESKTOPICON="OPERATOR"


		;;
			98)
				return 98
				;;
			*)
				return 99
				;;
		esac
	else
		debug "${statusicon} ${statusname}\n"
		debug "Automatically selecting %s icon.\n" "Sakis3G"
		DESKTOPICON="SAKIS3G"
	fi
	if [ "a${DESKTOPICON}" = "aOPERATOR" ]; then
		extension=`${basenamebin} "${statusicon}" | ${cutbin} -d. -f2-`
		verbose "Retrieving operator icon"
		debug run_command "${rmbin} -f \"/tmp/sakis3g.$$.${ISPID}_logo.${extension}\""
		debug run_command "${wgetbin} -O \"/tmp/sakis3g.$$.${ISPID}_logo.${extension}\" \"${statusicon}\""
		if [ ! -s "/tmp/sakis3g.$$.${ISPID}_logo.${extension}" ]; then
			debug run_command "${rmbin} -f \"/tmp/sakis3g.$$.${ISPID}_logo.${extension}\""
			show_fmt_error "Unable to get %s icon, unknown reason." "${statusname}"
			DESKTOPICON="SAKIS3G"
		else
			debug "Successfully retrieved %s icon.\n" "operator"
		fi
	fi
	if [ "a${DESKTOPICON}" = "aSAKIS3G" ] && [ "a${PROVIDER}" != "a" ] && [ -x "${PROVIDER}" ]; then
		extension="png"
		"${PROVIDER}" getfile "files/sakis3g.png" > "/tmp/sakis3g.$$.${ISPID}_logo.${extension}" 2> /dev/null
		if [ ! -s "/tmp/sakis3g.$$.${ISPID}_logo.${extension}" ]; then
			debug run_command "${rmbin} -f \"/tmp/sakis3g.$$.${ISPID}_logo.${extension}\""
			show_fmt_error "Unable to get %s icon, unknown reason." "Sakis3G"
			DESKTOPICON=""
		else
			debug "Successfully retrieved %s icon.\n" "Sakis3G"
		fi
	fi
	if [ -s "/tmp/sakis3g.$$.${ISPID}_logo.${extension}" ]; then
		debug run_command "${mkdirbin} -p \"${runhome}/.local\""
		debug run_command "${chownbin} ${runner} \"${runhome}/.local\"" 
		debug run_command "${mkdirbin} -p \"${runhome}/.local/share\""
		debug run_command "${chownbin} ${runner} \"${runhome}/.local/share\""
		debug run_command "${mkdirbin} -p \"${runhome}/.local/share/icons\""
		debug run_command "${chownbin} ${runner} \"${runhome}/.local/share/icons\""
		if [ "a${extension}" = "agif" -o "a${extension}" = "aGIF" -o "a${extension}" = "aGif" ]; then
			debug run_command "${mvbin} \"/tmp/sakis3g.$$.${ISPID}_logo.${extension}\" \"${runhome}/.local/share/icons/sakis3g.png\""
			debug run_command "${rmbin} -f \"/tmp/sakis3g.$$.${ISPID}_logo.${extension}\""
			extension="png"
		else
			debug run_command "${mvbin} \"/tmp/sakis3g.$$.${ISPID}_logo.${extension}\" \"${runhome}/.local/share/icons/sakis3g.${extension}\""
			debug run_command "${rmbin} -f \"/tmp/sakis3g.$$.${ISPID}_logo.${extension}\""
		fi
		if [ -s "${runhome}/.local/share/icons/sakis3g.${extension}" ]; then
			debug run_command "${chownbin} ${runner} \"${runhome}/.local/share/icons/sakis3g.${extension}\""
			debug run_command "${chmodbin} 644 \"${runhome}/.local/share/icons/sakis3g.${extension}\""
			icon="${runhome}/.local/share/icons/sakis3g.${extension}"
			debug "Successfully installed icon to \"%s\".\n" "${runhome}/.local/share/icons/sakis3g.${extension}"
		fi
	else
		debug "File %s does not exist or is empty.\n" "/tmp/sakis3g.$$.${ISPID}_logo.${extension}"
		[ -f "/tmp/sakis3g.$$.${ISPID}_logo.${extension}" ] && debug run_command "${rmbin} -f \"/tmp/sakis3g.$$.${ISPID}_logo.${extension}\""
		if [ -f "/usr/share/icons/gnome/scalable/status/nm-device-wireless.svg" ]; then
			debug "Selecting default GNOME icon.\n"
			icon="/usr/share/icons/gnome/scalable/status/nm-device-wireless.svg"
		else
			debug "Unable to locate any icon.\n"
			icon=""
		fi
	fi
	debug "Icon selected is: %s\n" "${icon}"
	shortcuttitle="Sakis3G"
	[ "a${DESKTOPICON}" = "aOPERATOR" ] && shortcuttitle="${statusproduct}" && [ "a${shortcuttitle}" = "a" ] && shortcuttitle="${statusname} Internet"
	[ "a${shortcuttitle}" = "a" ] && shortcuttitle="Sakis3G"
	commenttext=`format_text "Manages 3G internet connection and 3G USB modems"`
	${catbin} > "${desktopdestination}/sakis3g.desktop" <<endl
[Desktop Entry]
Version=1.0
Encoding=UTF-8
Type=Application
Terminal=false
Name=${shortcuttitle}
Name[en_US]=${shortcuttitle}
Exec=${ME} clicked
Comment=${commenttext}
Comment[en_US]=${commenttext}
Icon=${icon}
Icon[en_US]=${icon}
GenericName=
GenericName[en_US]=
endl
	debug run_command "${catbin} \"${desktopdestination}/sakis3g.desktop\""
	unset commenttext; unset shortcuttitle
	if [ -s "${desktopdestination}/sakis3g.desktop" ]; then
		debug run_command "${chownbin} ${runner} \"${desktopdestination}/sakis3g.desktop\""
		debug run_command "${chmodbin} 750 \"${desktopdestination}/sakis3g.desktop\""
		debug run_command "${lsbin} \"${desktopdestination}/sakis3g.desktop\""
		finalnotify "Desktop shortcut created at %s." "${desktopdestination}/sakis3g.desktop"
		unset desktopdestination
		return 0
	else
		debug run_command "${rmbin} -f \"${desktopdestination}/sakis3g.desktop\""
		unset desktopdestination
		return 1
	fi
}

action_modem() {
	unset verbosecurrentcount
	flow_select_modem "$@"
	ret=$?
	if [ "a${ret}" = "a0" ]; then
		finalnotify "Modem selected.\n"
		return 0
	else
		show_fmt_error "No modem selected.\n"
		return ${ret}
	fi
}

action_switch() {
	unset verbosecurrentcount
	flow_switch "$@"
	ret=$?
	if [ "a${ret}" = "a0" ]; then
		if [ "a${NEWIDS}" = "a" ]; then
			finalnotify "Modem switched.\n"
		else
			finalnotify "Modem switched to %s.\n" "${NEWIDS}"
		fi
		return 0
	else
		show_fmt_error "Failed to switch.\n"
		return ${ret}
	fi
}

action_setup() {
	unset verbosecurrentcount
	flow_setup "$@"
	ret=$?
	if [ "a${ret}" = "a0" ]; then
		finalnotify "Modem setup residing on %s.\n" "${MODEM_TTY}"
		return 0
	else
		show_fmt_error "Failed to setup modem.\n"
		return ${ret}
	fi
}

action_prepare() {
	unset verbosecurrentcount
	flow_prepare "$@"
	ret=$?
	if [ "a${ret}" = "a0" ]; then
		finalnotify "Modem on %s is registered to %s.\n" "${MODEM_TTY}" "${ISPTEXT}"
		return 0
	else
		show_fmt_error "Failed to prepare modem.\n"
		return ${ret}
	fi
}

action_connect() {
	unset verbosecurrentcount
	flow_connect "$@"
	ret=$?
	if [ "a${ret}" = "a0" ]; then
		action_status "$@"
		return 0
	else
		show_fmt_error "Failed to connect.\n"
		return ${ret}
	fi
}

action_compile() {
	unset verbosecurrentcount
	flow_compile "$@"
	ret=$?
	if [ "a${ret}" = "a0" ]; then
		finalnotify "Succesfully recompiled.\n"
		return 0
	else
		return ${ret}
	fi
}

action_disconnect() {
	unset verbosecurrentcount
	if ! ppp_fast_status; then
		finalnotify "Not connected.\n"
		return 0
	fi
	flow_disconnect "$@"
	ret=$?
	if [ "a${ret}" = "a0" ]; then
		finalnotify "Disconnected.\n"
		return 0
	else
		show_fmt_error "Failed to disconnect.\n"
		return ${ret}
	fi
}

action_reconnect() {
	unset verbosecurrentcount
	unset disconnectedbefore
	if ppp_fast_status; then
		status_connected
		flow_disconnect "$@"
		ret=$?
		if [ "${ret}" -ne "0" ]; then
			show_fmt_error "Failed to disconnect.\n"
			return ${ret}
		fi
		disconnectedbefore=1
	fi
	flow_connect "$@"
	ret=$?
	if [ "a${ret}" = "a0" -a "a${disconnectedbefore}" = "a1" ]; then
		unset disconnectedbefore
		finalnotify "Reconnected to %s.\n" "${ISPTEXT}"
		return 0
	elif [ "a${ret}" = "a0" ]; then
		action_status "$@"
		return 0
	else
		unset disconnectedbefore
		show_fmt_error "Failed to connect.\n"
		return ${ret}
	fi
}

action_toggle() {
	unset verbosecurrentcount
	unset disconnectedbefore
	if ppp_fast_status; then
		action_disconnect "$@"
		ret=$?
	else
		action_connect "$@"
		ret=$?
	fi
	return ${ret}
}

action_clicked() {
	unset verbosecurrentcount
	unset ret; unset tester
	tester="${SGUI}"; [ "a${tester}" = "a" ] && tester="terminal"
	case "${SGUI}" in
		zenity|dialog|Xdialog|whiptail|kdialog)
			action_menu "$@"
			ret=$?
			;;
		"9menu")
			action_menu "$@"
			ret=$?
			;;
		terminal|"interactive terminal")
			if [ "a${interactive}" = "a" ]; then
				action_toggle "$@"
				ret=$?
			else
				unset interactive
				action_toggle "$@"
				ret=$?
				export interactive=yes
			fi
			;;
	esac
	return ${ret}
}

# Method invoked when "more" action was requested.
action_more() {
	unset verbosecurrentcount
	unset usboptions; [ "a${binaryfree}" = "a" ] &&	usboptions="\"COMPILE\" \"Compile embedded Usb-ModeSwitch\""
	alwaysoptions="\"DESKTOP\" \"Create desktop shortcut\" \"ABOUT\" \"About Sakis3G\" \"HELP\" \"Show help\" \"EXIT\" \"Exit\""
	if ppp_fast_status; then
		stateoptions="\"DISCONNECT\" \"Disconnect\" \"RECONNECT\" \"Disconnect and then connect again\" \"INFO\" \"Connection information\" \"REPORT\" \"Generate success report\""
	else
		stateoptions="\"CONNECT\" \"Connect with 3G\" \"PREPARE\" \"Only prepare modem (Setup + PIN unlock + Register Network + Update HAL)\" \"SETUP\" \"Only setup modem (Switch + Load module + Setup tty)\" \"SWITCH\" \"Only switch modem (if applicable)\""
	fi
	eval user_select \"MOREMENU\" \"Please select an action\" \"Choose action for Sakis3G script to follow.\" \"OK\" \"Cancel\" ${stateoptions} ${usboptions} ${alwaysoptions}
# in
	ret=$?
	unset usboptions; unset alwaysoptions; unset stateoptions
	case "${ret}" in
		99)
			return 99
			;;
		98)
			debug "No action selected.\n"
			# Instead of returning 98, returns 0 to allow chaining of actors
			# EXIT menu item is used from breaking chain
			unset MOREMENU
			return 0
			;;
		*)
			case "a${MOREMENU}" in
				aCONNECT)
					action_connect "$@"
					;;
				aDISCONNECT)
					action_disconnect "$@"
					;;
				aRECONNECT)
					action_reconnect "$@"
					;;
				aPREPARE)
					action_prepare "$@"
					;;
				aSETUP)
					action_setup "$@"
					;;
				aSWITCH)
					action_switch "$@"
					;;
				aCOMPILE)
					action_compile "$@"
					;;
				aDESKTOP)
					action_desktop "$@"
					;;
				aINFO)
					action_info "$@"
					;;
				aREPORT)
					action_report "$@"
					;;
				aHELP)
					show_help
					;;
				aABOUT)
					action_about "$@"
					;;
				aEXIT)
					unset MOREMENU
					return 98
					;;
				a)
					unset MOREMENU
					return 98
					;;
				*)
					show_fmt_error "Option %s not implemented.\n" "${MOREMENU}"
					;;
			esac
			;;
	esac
	unset MOREMENU
	action_more "$@"
	return $?
}

# Method invoked when "menu" action was requested.
action_menu() {
	unset verbosecurrentcount
	if ppp_fast_status; then
		menuoptions="\"DISCONNECT\" \"Disconnect\" \"INFO\" \"Connection information\" \"DESKTOP\" \"Create shortcut\""
	else
		menuoptions="\"CONNECT\" \"Connect with 3G\""
	fi
	menuoptions="${menuoptions} \"MOREMENU\" \"More options...\" \"ABOUT\" \"About Sakis3G\""
	menuoptions="${menuoptions} \"EXIT\" \"Exit\""
	eval user_select \"MENU\" \"Please select an action\" \"Choose action for Sakis3G script to follow.\" \"OK\" \"Cancel\" ${menuoptions}
# in
	ret=$?; unset menuoptions
	case "${ret}" in
		99)
			return 99
			;;
		98)
			debug "No action selected.\n"
			# Instead of returning 98, returns 0 to allow chaining of actors
			# EXIT menu item is used from breaking chain
			return 0
			;;
		*)
			case "a${MENU}" in
				aCONNECT)
					action_connect "$@"
					;;
				aDISCONNECT)
					action_disconnect "$@"
					;;
				aMOREMENU)
					action_more "$@"
					ret=$?; [ "a${ret}" = "a98" ] && unset MENU && return 98
					;;
				aINFO)
					action_info "$@"
					;;
				aDESKTOP)
					action_desktop "$@"
					;;
				aHELP)
					show_help
					;;
				aABOUT)
					action_about "$@"
					;;
				aEXIT)
					debug "Breaking chain.\n"
					unset MENU
					return 98
					;;
				a)
					unset MENU
					return 98
					;;
				*)
					show_fmt_error "Option %s not implemented.\n" "${MENU}"
					;;
			esac
			;;
	esac
	unset MENU
	action_menu "$@"
	return $?
}

helper_cleaner() {
	[ -f "/tmp/sakis3g.helper.icon.green.$$.png" ] && ${rmbin} -f "/tmp/sakis3g.helper.icon.green.$$.png"
	[ -f "/tmp/sakis3g.helper.icon.red.$$.png" ] && ${rmbin} -f "/tmp/sakis3g.helper.icon.red.$$.png"
	[ -f "/tmp/sakis3g.helper.icon.yellow.$$.png" ] && ${rmbin} -f "/tmp/sakis3g.helper.icon.yellow.$$.png"
	[ "a${helperpid}" != "a" ] && ! notrunning "${helperpid}" && ${killbin} -1 ${helperpid} 2> /dev/null > /dev/null
	[ "a${helperpid}" != "a" ] && ! notrunning "${helperpid}" && ${killbin} -9 ${helperpid} 2> /dev/null > /dev/null
	if [ "a${balloons}" != "a" ] && [ "a${BALOONIZERPID}" != "a" -o "a${BALOONIZER}" != "a" ]; then
		[ "a${BALOONIZER}" != "a" ] && [ -f "${BALOONIZER}" ] && debug run_command "${rmbin} -f \"${BALOONIZER}\""
		[ "a${BALOONIZERPID}" != "a" ] && ! notrunning "${BALOONIZERPID}" && debug run_command "${killbin} -1 ${BALOONIZERPID}"
		[ "a${BALOONIZERPID}" != "a" ] && ! notrunning "${BALOONIZERPID}" && debug run_command "${killbin} -9 ${BALOONIZERPID}"
		find_binary "ps" && tailpid=`${psbin} -A -o pid,command | ${grepbin} "${tailbin} -f ${BALOONIZER}" | ${grepbin} -v "${grepbin}" | ${cutbin} -d\  -f1`
		[ "a${tailpid}" != "a" ] && ! notrunning "${tailpid}" && debug run_command "${killbin} -1 ${tailpid}"
		[ "a${tailpid}" != "a" ] && ! notrunning "${tailpid}" && debug run_command "${killbin} -9 ${tailpid}"
		unset BALOONIZERPID; unset BALOONIZER
	fi
}

action_helper() {
	if ! find_binary "zenity"; then
		show_fmt_error "Unable to install tray icon to system notification area. You need to install %s.\n" "zenity"
		return 0
	fi
	need_binary "kill"
	[ "a${PROVIDER}" = "a" ] && return 1
	[ ! -x "${PROVIDER}" ] && return 1
	if we_are_root_already && [ "a${MENU}" != "a" ]; then
		debug "Calling menu since state variable MENU is set.\n"
		action_menu "$@"
		unset MENU
		debug "MENU actor returned. Will now run as helper.\n"
	fi
	debug run_command "${rmbin} -f /tmp/sakis3g.helper.icon.red.$$.png /tmp/sakis3g.helper.icon.green.$$.png /tmp/sakis3g.helper.icon.yellow.$$.png"
	addexittrap helper_cleaner
	${PROVIDER} getfile files/sakis3g.red.png > "/tmp/sakis3g.helper.icon.red.$$.png" 2> /dev/null
	${PROVIDER} getfile files/sakis3g.green.png > "/tmp/sakis3g.helper.icon.green.$$.png" 2> /dev/null
	${PROVIDER} getfile files/sakis3g.yellow.png > "/tmp/sakis3g.helper.icon.yellow.$$.png" 2> /dev/null
	if [ ! -s "/tmp/sakis3g.helper.icon.green.$$.png" ]; then
		debug "Failed to retrieve green/connected state icon.\n"
		return 1
	elif [ ! -s "/tmp/sakis3g.helper.icon.red.$$.png" ]; then
		debug "Failed to retrieve red/no hardware state icon.\n"
		return 1
	elif [ ! -s "/tmp/sakis3g.helper.icon.yellow.$$.png" ]; then
		debug "Failed to retrieve yellow/not connected state icon.\n"
		return 1
	fi
	debug run_command "${chmodbin} 644 \"/tmp/sakis3g.helper.icon.red.$$.png\"" 
	debug run_command "${chmodbin} 644 \"/tmp/sakis3g.helper.icon.green.$$.png\""
	debug run_command "${chmodbin} 644 \"/tmp/sakis3g.helper.icon.yellow.$$.png\""
	if [ "a${balloons}" != "a" ]; then
		# Establish balloon helper now that will be accessible from root session later
		if [ "a${BALOONIZER}" = "a" ]; then
			BALOONIZER="/tmp/sakis3g.baloon.pipe.$$"
			debug run_command "${rmbin} -f \"${BALOONIZER}\""
			debug run_command "${touchbin} -f \"${BALOONIZER}\""
			if [ -w "${BALOONIZER}" ]; then
				${printfbin} "\n\n\n\n\nvisible:false\n" >> "${BALOONIZER}"
				export BALOONIZER
				eval ${tailbin} -f "${BALOONIZER}" "2> /dev/null" | ${zenitybin} --notification --listen > /dev/null 2> /dev/null &
				BALOONIZERPID=$!; eval "disown -a" > /dev/null 2> /dev/null
				export BALOONIZERPID
				${printfbin} "visible:false\n" >> "${BALOONIZER}"
				${printfbin} "visible:false\nvisible:false\n" >> "${BALOONIZER}"
				debug "Balloon pipe created. Location is \"%s\" and runs with PID %d.\n" "${BALOONIZER}" "${BALOONIZERPID}"
			else
				debug "Error while creating pipe for balloons.\n"
				debug run_command "${rmbin} -f \"${BALOONIZER}\""
				unset BALOONIZER

			fi
		elif [ -w "${BALOONIZER}" ]; then
			debug "Will be using already existing balloon pipe: %s\n" "${BALOONIZER}"
		elif [ ! -w "${BALOONIZER}" ]; then
			debug "Balloons pipe \"%s\" exists but no write access granted.\n" "${BALOONIZER}"
		fi
		[ "a${BALOONIZER}" = "a" ] && debug "No balloons will be appearing.\n"
	fi
	debug "All set. Going into helper mode.\n"
	while [ "1" = "1" ]
	do
		if ppp_slow_status && status_connected; then
			helpertext="`translate_text "Connected"`"
			[ "a${statusname}" != "a" ] && helpertext="${statusname}"
			helperconnected=2
		else
			usb_connected_modems
			if [ "a${usb_modem_devices}" != "a" ]; then
				helpertext="`translate_text "Not connected"`"
				helperconnected=1
				helpermodems=`echo "${usb_modem_devices}" | ${cutbin} -d: -f3- | ${trbin} "\n" " "`
			else
				helpertext="`translate_text "No USB modem"`"
				helperconnected=0
			fi
		fi
		# Check if something was changed not by us. Then balloon user.
		if [ "a${balloons}" != "a" ]; then
			if [ "a${BALOONIZER}" != "a" ] && [ "a${previousstatus}" != "a" -a "a${previousstatus}" != "a${helperconnected}" ]; then
				debug "Status changed. Not by us.\n"
				notificationtext=`translate_text "Notification"`
				if [ "a${helperconnected}" = "a2" ]; then
					iconpath="/tmp/sakis3g.helper.icon.green.$$.png"
				elif [ "a${helperconnected}" = "a1" ]; then
					iconpath="/tmp/sakis3g.helper.icon.yellow.$$.png"
				elif [ "a${helperconnected}" = "a0" ]; then
					iconpath="/tmp/sakis3g.helper.icon.red.$$.png"
				else
					iconpath="/tmp/sakis3g.helper.icon.yellow.$$.png"
				fi
				unset largetext; unset smalltext
				if [ "a${previousstatus}" = "a0" -a "a${helperconnected}" = "a1" ]; then
					largetext=`translate_text "USB Modem plugged"`
					smalltext=`format_text "USB Modem %s is now plugged on computer." "${helpermodems}"`
				elif [ "a${helperconnected}" = "a2" ]; then
					largetext=`translate_text "Connected"`
					if [ "a${MODEM_VARIANT}" != "a" -a "a${statusname}" != "a" ]; then
						smalltext=`format_text "Modem %s is now connected to %s." "${MODEM_VARIANT}" "${statusname}"`
					elif [ "a${MODEM_VARIANT}" != "a" ]; then
						smalltext=`format_text "Modem %s is now connected." "${MODEM_VARIANT}"`
					elif [ "a${statusname}" != "a" ]; then
						smalltext=`format_text "You are now connected to %s." "${statusname}"`
					else
						smalltext=`translate_text "Computer is now connected.\n"`
					fi
				elif [ "a${previousstatus}" = "a1" -a "a${helperconnected}" = "a0" ]; then
					largetext=`translate_text "USB Modem Unplugged"`
					smalltext=`translate_text "No USB modem is anymore plugged on computer."`
				elif [ "a${previousstatus}" = "a2" ]; then
					largetext=`translate_text "Disconnected"`
					if [ "a${helperconnected}" = "a0" ]; then
						smalltext=`translate_text "You were disconnected due to modem being unplugged."`
					elif [ "a${helperconnected}" = "a1" ]; then
						smalltext=`translate_text "You are now disconnected from operator."`
					fi
				fi
				debug "Will display baloon:\nIcon: %s\nTitle: %s\nMessage: %s\n" "${iconpath}" "${largetext}" "${smalltext}"
				if [ "a${smalltext}" != "a" -a "a${largetext}" != "a" ]; then
					${printfbin} "icon:%s\n" "${iconpath}" >> "${BALOONIZER}" 2> /dev/null
					${printfbin} "tooltip:%s\n" "${notificationtext}" >> "${BALOONIZER}" 2> /dev/null
					${printfbin} "visible:true\n" >> "${BALOONIZER}" 2> /dev/null
					${printfbin} "message:%s\\\n<small>%s</small>\n" "${largetext}" "${smalltext}" >> "${BALOONIZER}" 2> /dev/null
					${printfbin} "visible:false\n" >> "${BALOONIZER}" 2> /dev/null
				fi
				unset iconpath; unset smalltext; unset largetext; unset notificationtext
			fi
			previousstatus="${helperconnected}"
		fi
		if [ "a${helpertext}" != "a${announcedtext}" -a "a${helperpid}" != "a" ] && ! notrunning "${helperpid}"; then
			[ "a${helperpid}" != "a" ] && ! notrunning "${helperpid}" && ${killbin} -1 ${helperpid} 2> /dev/null > /dev/null
			[ "a${helperpid}" != "a" ] && ! notrunning "${helperpid}" && ${killbin} -9 ${helperpid} 2> /dev/null > /dev/null
			notrunning "${helperpid}" && unset helperpid
		fi
		if [ "a${helperpid}" = "a" ]; then
			if [ "a${helperconnected}" = "a2" ]; then
				${zenitybin} --notification --window-icon=/tmp/sakis3g.helper.icon.green.$$.png --text="${helpertext}" > /dev/null 2> /dev/null &
			elif [ "a${helperconnected}" = "a1" ]; then
				${zenitybin} --notification --window-icon=/tmp/sakis3g.helper.icon.yellow.$$.png --text="${helpertext}" > /dev/null 2> /dev/null &
			elif [ "a${helperconnected}" = "a0" ]; then
				${zenitybin} --notification --window-icon=/tmp/sakis3g.helper.icon.red.$$.png --text="${helpertext}" > /dev/null 2> /dev/null &
			else
				${zenitybin} --notification --text="${helpertext}" > /dev/null 2> /dev/null &
			fi
			helperpid=$!; 
			eval "disown -a" > /dev/null 2> /dev/null
			announcedtext="${helpertext}"
			export helperpid
		elif notrunning "${helperpid}"; then
			unset helperpid; unset previousstatus
			debug "User clicked on icon.\n"
			action_menu "$@"; ret=$?
			if [ "${ret}" -eq "98" ]; then
				if [ "a${forever}" != "a" ]; then
					debug "User selected exit on MENU. However, \"forever\" is set.\n"
					unset MENU; unset MOREMENU;
				else
					debug "User selected exit on MENU. Will ask for confirmation to exit.\n"
					#${zenitybin} --question --title="`translate_text "Confirm exit"`" --text="`translate_text "Exiting will also remove tray icon. Are you sure you want to exit Sakis3G?"`"
					#ret=$?
					#if [ "a${ret}" = "a0" ]; then
					if user_confirm "helperexit" "Confirm exit" "Exiting will also remove tray icon. Are you sure you want to exit Sakis3G?" "Yes" "No" "reset"; then
						debug "User confirmed he wants to exit. Helper will die.\n"
						break
					else
						debug "User did not confirm.\n"
						unset MENU; unset MOREMENU
					fi
				fi
			fi
			debug "Resuming helper operation.\n"
		else
			debug "Helper is sleeping for a second.\n"
			sleep 1
		fi
	done
	helper_cleaner
	return 98
}

# Method called when called as a helper to hold HAL lock
action_holdlock() {
	unset verbosecurrentcount
	[ "a$2" != "a" ] && [ -f "$2" ] && checkfile="$2" && echo "$$" > "${checkfile}"
	unset TRAPS
	while [ "1" = "1" ]
	do
		if [ "a${PROVIDER}" = "a" ]; then
			ppppp=`ps -p $$ -o ppid=`
		else
			ppppp=`ps -p $$ -o ppid=`
			ppppp=`ps -p ${ppppp} -o ppid=`
		fi
		ppppp=`echo $ppppp`
		[ "a${ppppp}" = "a1" ] && exit 0
		[ "a${ppppp}" = "a${PPID}" ] && exit 0
		[ "a${checkfile}" != "a" ] && [ ! -f "${checkfile}" ] && exit 0 
		#echo $ppppp
		sleep 1
	done
}

action_state() {
	unset verbosecurrentcount
	state_variables "SGUI interactive stick_to_console DEBUG LOCALAUTHORITY BALOONIZER"
	notify "To automatically repeat result of last action, use following command line:\n%s\n" "${ME} ${actors} ${statevariables}"
	return 0
}

action_udevrule() {
	unset verbosecurrentcount
	state_variables "SGUI MODEM interactive stick_to_console USBMODEM OTHER DEBUG LOCALAUTHORITY BALOONIZER"
#	statevariables=`echo "${statevariables}" | ${sedbin} -e "s/\"/\\\\\\\\\"/g"`
	statevariables=`echo "${statevariables}" | ${sedbin} -e "s/\"//g"`
	unset content
	candidates="${MODEM}"
	[ "a${candidates}" = "aOTHER" ] && unset candidates
	[ "a${candidates}" = "aOTHER" -a "a${OTHER}" = "aUSBMODEM" -a "a${USBMODEM}" != "a" ] && candidates="${USBMODEM}"
	localactors=`echo ${actors}`
	for candidate in ${candidates}
	do
		modemvendor=`echo ${candidate} | ${cutbin} -d: -f1 -s`
		modemproduct=`echo ${candidate} | ${cutbin} -d: -f2 -s`
		if [ "a${modemvendor}" != "a" -a "a${modemproduct}" != "a" ]; then
			content=`${printfbin} "%s\nACTION==\"add\", SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%s\", ATTRS{idProduct}==\"%s\", ATTRS{bInterfaceNumber}==\"00\", RUN+=\"%s %s %s MODEM=OTHER OTHER=USBMODEM USBMODEM=%s:%s\"\n\n" "${content}" "${modemvendor}" "${modemproduct}" "${ME}" "${localactors}" "${statevariables}" "${modemvendor}" "${modemproduct}"`
			break;
		fi
	done
	unset localactors; unset modemvendor; unset modemproduct; unset candidate; unset candidates; unset statevariables
	term_clearline
	if [ "a${content}" != "a" ]; then
		format_text "To automatically repeat result of last action, immediately upon device connection, include following line within a %s file within \"%s\" directory:\n%s\n" ".rules" "/etc/udev/rules.d/" "${content}"
	else
		format_text "No USB modem was selected. No need for a udev example.\n"
	fi
	unset content
	return 0
}

action_about() {
	unset verbosecurrentcount
	notify "%s\n" "`show_version`"
	return 0
}

show_man() {
	destination="$1"
	case "a${destination}" in
		ausb_modeswitch|ausb-modeswitch)
			destination="dependencies/usb-modeswitch/usb_modeswitch.1"
			;;
		asakis3g.conf)
			destination="man/sakis3g.conf.5"
			;;
		*)
			destination="man/sakis3g.1"
			;;
	esac
	debug "Destination man page is: %s\n" "${destination}"
	[ "a${PROVIDER}" = "a" ] && return 1
	[ ! -x "${PROVIDER}" ] && return 1
	need_binary "man"
	need_binary "rm"
	"${PROVIDER}" getfile "${destination}" > "/tmp/sakis3g.man.$$"
	debug "Will now display man page %s.\n" "${destination}"
	[ -s "/tmp/sakis3g.man.$$" ] && ${manbin} -l "/tmp/sakis3g.man.$$"
	${rmbin} -f "/tmp/sakis3g.man.$$"
	return 0
}

action_report() {
	unset verbosecurrentcount
	flow_report "$@"
	ret=$?
	if [ "a${ret}" = "a0" ]; then
		return 0
	else
		return ${ret}
	fi
}

# Executes actor $1 with the arguments
run_action() {
	actioncandidate=$1
	[ "$#" -gt "0" ] && shift
	unset verbosecurrentcount
	newactors="${actors} ${actioncandidate}"
	case "${actioncandidate}" in
		about)
			action_about "$@"
			actionresult=$?
			;;
		desktop)
			action_desktop "$@"
			actionresult=$?
			;;
		helper)
			action_helper "$@"
			actionresult=$?
			;;
		status)
			action_status "$@"
			actionresult=$?
			;;
		connected)
			ppp_fast_status
			actionresult=$?
			;;
		disconnected)
			if ppp_fast_status; then
				actionresult=99
			else
				actionresult=0
			fi
			;;
		plugged)
			if usb_connected_modems; then
				actionresult=0
			else
				actionresult=99
			fi
			;;
		unplugged)
			if usb_connected_modems; then
				actionresult=99
			else
				actionresult=0
			fi
			;;
		switched)
			if usb_connected_modems; then
				if modeswitch_switchable_devices; then
					actionresult=99
				else
					actionresult=0
				fi
			else
				actionresult=0
			fi
			;;
		switchable)
			if modeswitch_switchable_devices; then
				actionresult=0
			else
				actionresult=99
			fi
			;;
		wait|sleep)
			debug "Sleeping for 1 second.\n"
			sleep 1
			actionresult=0
			;;
		info)
			action_info "$@"
			actionresult=$?
			;;
		clicked)
			action_clicked "$@"
			actionresult=$?
			;;
		modem|select)
			action_modem "$@"
			actionresult=$?
			;;
		switchonly)
			action_switch "$@"
			actionresult=$?
			;;
		setup)
			action_setup "$@"
			actionresult=$?
			;;
		prepare|init)
			action_prepare "$@"
			actionresult=$?
			;;
		connect|start)
			action_connect "$@"
			actionresult=$?
			;;
		toggle)
			action_toggle "$@"
			actionresult=$?
			;;
		reconnect|restart)
			action_reconnect "$@"
			actionresult=$?
			;;
		disconnect|stop)
			action_disconnect "$@"
			actionresult=$?
			;;
		more|moremenu|menumore)
			action_more "$@"
			actionresult=$?
			;;
		menu)
			action_menu "$@"
			actionresult=$?
			;;
		state)
			action_state "$@"
			actionresult=$?
			;;
		udevrule)
			action_udevrule "$@"
			actionresult=$?
			;;
		compile|recompile)
			action_compile "$@"
			actionresult=$?
			;;
		report)
			action_report "$@"
			actionresult=$?
			;;
		*)
			newactors="${actors}"
			unset actioncandidate
			actionresult=0
			;;
	esac
	actors="${newactors}"
	unset actioncandidate; unset newactors
	[ "a${actionresult}" = "a" ] && actionresult=99
	return ${actionresult}
}

# Executes actors in the order defined
action_command() {
	unset actors
	while [ "$#" -gt "0" ]
	do
		if [ "a${1}" = "anot" -o "a${1}" = "aNot" -o "a${1}" = "a!" ]; then
			[ "$#" -gt "0" ] && shift
			actors="${actors} not"
			run_action "$@"
			actionresult=$?
			if [ "${actionresult}" -eq "0" ]; then
				actionresult=99
				debug "Actor \"%s\" returned %d, \"not\" operator instructs to abort.\n" "${1}" "${actionresult}"
				break
			else
				debug "Actor \"%s\" returned %d, but was inverted by \"not\" operator.\n" "${1}" "${actionresult}"
				actionresult=0
			fi
		elif [ "a${1}" = "aignore" -o "a${1}" = "aIgnore" -o "a${1}" = "aignoring" -o "a${1}" = "aIgnoring" -o "a${1}" = "a|" ]; then
			[ "$#" -gt "0" ] && shift
			actors="${actors} ignore"
			run_action "$@"
			actionresult=$?
			if [ "${actionresult}" -ne "0" ]; then
				debug "Actor \"%s\" returned %d, \"ignore\" operator instructs to continue.\n" "${1}" "${actionresult}"
				actionresult=0
			fi
		elif [ "a${1}" != "a" ] && ! run_action "$@"; then
			debug "Aborting execution chain due to actor \"%s\" returning %d.\n" "${1}" "${actionresult}"
			break
		fi
		[ "$#" -gt "0" ] && shift
	done
	unset arg
	actors=`echo ${actors}`
	if [ "a${actors}" = "a" ]; then
		debug "No actors defined.\n"
		unset actors
		return 1
	else
		debug "Following actors executed: %s\n" "${actors}"
		unset actors
		return 0
	fi
}

# Checks if arguments defined a dummy action and aborts if it does
no_action_command() {
	for arg in $@
	do
		case "$arg" in
			--help|help)
				unset arg
				if find_binary "fold"; then
					if [ "a${COLUMNS}" != "a" ]; then
						raw_help | ${foldbin} -s -w "${COLUMNS}"
					else
						raw_help | ${foldbin} -s -w "80"
					fi
				else
					raw_help
				fi
				return 0
				;;
			--version|version)
				unset arg
				show_version
				return 0
				;;
			--holdlock|holdlock)
				unset arg
				action_holdlock "$@"
				return 0
				;;
			usb_modeswitch)
				if [ "a${binaryfree}" != "a" ]; then
					show_fmt_error "You are running a binary free version of Sakis3G. This action is not available.\n"
				fi
				return 0
				;;
			man)
				if [ "a${stripped}" != "a" ]; then
					show_fmt_error "You are running a stripped version of Sakis3G. This action is not available.\n"
				else
					shift
					show_man "$@"
				fi
				unset arg
				return 0
				;;
		esac
	done
	unset arg
	return 1
}

# When no actor defined, executes default actor of GUI selected.
default_actor() {
	debug "Executing default actor for \"%s\".\n" "${SGUI}"
	if voodoo_mode; then
		debug "Voodoo actions will happen.\n"
		if action_connect "$@"; then
			actors="connect"
			action_state "$@"
			return $?
		else
			return $?
		fi
	fi
	case "${SGUI}" in
		whiptail|dialog|Xdialog|zenity|kdialog)
			action_menu "$@"
			return $?
			;;
		"9menu")
			action_menu "$@"
			return $?
			;;
		"interactive terminal")
			action_menu "$@"
			return $?
			;;
		"terminal")
			show_help
			return $?
			;;
		*)
			debug "No default actor for this GUI. Showing help.\n"
			show_help
			return $?
			;;
	esac
}

voodoo_mode() {
	[ "a${voodoo}" != "a" ] && return 0
	return 1
}

guruplug_led() {
	if [ "a$1" = "anoexecute" ]; then
		noexecute=1
		shift
	elif [ "a$1" = "aall" ]; then
		shift
		guruplug_leds "$@"
		return 0
	else
		noexecute=0
	fi
	ledcolor=""; ledname=""; othercolor=""; otherled=""; ledblink=""; ledon=""; ledoff=""
	for ledarg in "$@"
	do
		case "a${ledarg}" in
			ared|aRED|aRed|aR|ar|"a${redcolor}")
				ledcolor="${redcolor}"
				othercolor="${othercolor} ${greencolor}"
				;;
			agreen|aGREEN|aGreen|aG|ag|"a${greencolor}")
				ledcolor="${greencolor}"
				othercolor="${othercolor} ${redcolor}"
				;;
			ablack|aBLACK|aBlack|aB|ab|anone|aNONE|aNone|aN|an|aNO|aNo|ano|aReset|aRESET|areset)
				ledcolor=""
				othercolor="${othercolor} ${redcolor} ${greencolor}"
				;;
			aorange|aOrange|aORANGE|aO|ao|ayellow|aYellow|aYellow|aY|ay|aBOTH|aBoth|aboth)
				ledcolor="${ledcolors}"
				othercolor=""
				;;
			aleft|aLEFT|aLeft|aL|al|"a${leftled}")
				ledname="${leftled}"
				otherled="${otherled}"
				;;
			aright|aRIGHT|aRight|"a${rightled}")
				ledname="${rightled}"
				otherled="${otherled}"
				;;
			ablink|aBlink|aBLINK)
				ledblink=1;
				;;
			anand|aNAND|assd|aSSD|adisk|aDISK|aDisk|aNand|aSsd|anand-disk|ananddisk|assddisk|assd-disk)
				ledblink=2;
				;;
			ammc|ammc0|aMMC|aMmc|aMMC0|acard|aCard|aCARD)
				ledblink=3;
				;;
			*)
				ledcheck=`expr ${ledarg} + 1 - 1 2> /dev/null`
				if [ "a${ledcheck}" = "a${ledarg}" ]; then
					if [ "a${ledon}" = "a" ]; then
						ledon="${ledarg}"
					elif [ "a${ledoff}" = "a" ]; then
						ledoff="${ledarg}"
					fi
				fi
				;;
		esac
	done
	if [ "a${ledcolor}${othercolor}" = "a" -o "a${ledname}" = "a" ]; then
		unset noexecute; unset ledarg; unset ledcolor; unset ledname; unset othercolor; unset otherled;
		unset color; unset oled; unset ledcommand; unset ledblink; unset ledmode; unset ledon; unset ledoff;
		return 1
	fi
	ledcommand=""
	for oled in ${otherled}
	do
		for color in ${ledcolors}
		do
			ledcommand="${ledcommand} echo \"none\" > \"${ledpath}/${color}:${oled}/trigger\";"
			ledcommand="${ledcommand} echo \"0\" > \"${ledpath}/${color}:${oled}/brightness\";"
		done
	done
	if [ "a${ledblink}" = "a1" ]; then
		unset othercolor
		ledmode="timer"
		[ "a${ledon}" = "a" ] && ledon=500
		[ "a${ledoff}" = "a" ] && ledoff=500
		if [ "a${ledcolor}" = "a" ]; then
			ttt="${ledon}"; ledon="${ledoff}"; ledoff="${ttt}"; unset ttt
			ledcheck=`guruplug_led_getstate "${ledname}" | ${grepbin} "_brightness=1" | ${sedbin} -e "s/^${ledname}_\(.*\)_brightness=1$/\1/g" | tr "\n" " "`
			ledcheck=`echo ${ledcheck}`
			for color in ${ledcolors}
			do
				colorname=`echo "${color}" | ${sedbin} -e "s/:/_/g"`
				if strinstr "${colorname}" "${ledcheck}" " "; then
					ledcolor="${ledcolor} ${color}"
				else
					othercolor="${othercolor} ${color}"
				fi
			done
			unset color; unset colorname; unset ledcheck
		fi
		[ "a${ledcolor}" = "a" ] && unset othercolor
	elif [ "a${ledblink}" = "a2" ]; then
		ledmode="nand-disk"
	elif [ "a${ledblink}" = "a3" ]; then
		ledmode="mmc0"
	else
		ledmode="none"
	fi
	for color in ${othercolor}
	do
		ledcommand="${ledcommand} echo \"none\" > \"${ledpath}/${color}:${ledname}/trigger\";"
		ledcommand="${ledcommand} echo \"0\" > \"${ledpath}/${color}:${ledname}/brightness\";"
	done
	if [ "a${ledcolor}" != "a" ]; then
		for color in ${ledcolor}
		do
			ledcommand="${ledcommand} echo \"${ledmode}\" > \"${ledpath}/${color}:${ledname}/trigger\";"
			[ "a${ledmode}" = "anone" ] && ledcommand="${ledcommand} echo \"1\" > \"${ledpath}/${color}:${ledname}/brightness\";"
			if [ "a${ledblink}" = "a1" ]; then
				ledcommand="${ledcommand} echo \"${ledon}\" > \"${ledpath}/${color}:${ledname}/delay_on\";"
				ledcommand="${ledcommand} echo \"${ledoff}\" > \"${ledpath}/${color}:${ledname}/delay_off\";"
			fi
		done
		unset color
	fi
	if [ "a${noexecute}" = "a1" ]; then
		echo "${ledcommand}"
	else
		unset LEDSCLEAN
		eval ${ledcommand}
	fi
	unset noexecute; unset ledarg; unset ledcolor; unset ledname; unset othercolor; unset otherled;
	unset color; unset oled; unset ledcommand; unset ledblink; unset ledmode; unset ledon; unset ledoff;
	return 0
}

guruplug_leds() {
	ledscommands=""
	for ledi in ${allleds}
	do
		ledscommands="${ledscommands} `guruplug_led noexecute "${ledi}" "$@"`"
	done
	unset LEDSCLEAN
	eval ${ledscommands}
	unset ledscommands; unset ledi
	return 0
}

guruplug_verbose() {
	[ "a${guruplug}" = "a" ] && return 0
	if [ "a${gurucycle}" = "a" -o "a${gurucycle}" = "a0" ]; then
		gurucycle="1"
		led1="left"
		led2="right"
	elif [ "a${gurucycle}" = "a1" ]; then
		gurucycle="0"
		led1="right"
		led2="left"
	fi
	export gurucycle
	ledscommands=""
	ledscommands="${ledscommands} `guruplug_led noexecute ${led1} reset`"
	ledscommands="${ledscommands} `guruplug_led noexecute ${led2} reset`"
	ledscommands="${ledscommands} `guruplug_led noexecute ${led1} green`"
	ledscommands="${ledscommands} `guruplug_led noexecute ${led2} blink green`"
	eval ${ledscommands}
	unset led1; unset led2; unset ledscommands
	return 0
}

guruplug_verbose_same() {
	[ "a${guruplug}" = "a" ] && return 0
	if [ "a${gurucycle}" = "a" -o "a${gurucycle}" = "a0" ]; then
		led1="left"
		led2="right"
	elif [ "a${gurucycle}" = "a1" ]; then
		led1="right"
		led2="left"
	fi
	export gurucycle
	ledscommands=""
	ledscommands="${ledscommands} `guruplug_led noexecute ${led1} reset`"
	ledscommands="${ledscommands} `guruplug_led noexecute ${led2} reset`"
	ledscommands="${ledscommands} `guruplug_led noexecute ${led1} green`"
	ledscommands="${ledscommands} `guruplug_led noexecute ${led2} green`"
	ledscommands="${ledscommands} `guruplug_led noexecute ${led2} blink red`"
	eval ${ledscommands}
	unset led1; unset led2; unset ledscommands
	return 0
}

guruplug_notify() {
	[ "a${guruplug}" = "a" ] && return 0
	guruplug_leds black
	guruplug_leds blink green
	[ "a${interactive}" = "a" ] && sleep 5
}

guruplug_error() {
	[ "a${guruplug}" = "a" ] && return 0
	guruplug_leds black
	guruplug_leds blink red
	[ "a${interactive}" = "a" ] && sleep 5
}

guruplug_led_exists() {
	[ "a${guruplug}" = "a" ] && return 1
	[ "a$1" = "a" ] && return 1
	for color in ${ledcolors}
	do
		[ ! -d "${ledpath}/${color}:$1" ] && return 1
	done
	unset color
	return 0
}

guruplug_led_getstate() {
	[ "a${guruplug}" = "a" ] && return 0
	! guruplug_led_exists "$@" && return 1
	for color in ${ledcolors}
	do
		colorname=`echo ${color} | ${sedbin} -e "s/:/_/g"`
		for file in ${ledvariables}
		do
			if [ -r "${ledpath}/${color}:${1}/${file}" ]; then
				value=`${catbin} "${ledpath}/${color}:$1/${file}"`
				eval "$1_${colorname}_${file}=\"${value}\""
				eval "export $1_${colorname}_${file}"
			else
				eval "unset $1_${colorname}_${file}"
			fi
		done
                value=`${catbin} "${ledpath}/${color}:$1/trigger" | ${sedbin} -e "s/^\(.*\)\[\(.*\)\]\(.*\)$/\2/g"`
                eval "$1_${colorname}_trigger=\"${value}\""
		eval "export $1_${colorname}_trigger"
		[ "a${value}" != "anone" ] && eval "unset $1_${colorname}_brightness"
	done
	unset colorname; unset color; unset value; unset file;
	debug "Led $1 saved.\n"
	set | ${grepbin} "^$1_"
	return 0
}

guruplug_state() {
	[ "a${guruplug}" = "a" ] && return 0
	for ledi in ${allleds}
	do
		! guruplug_led_getstate ${ledi} && return 1
	done
	unset ledi
	debug "All leds are saved.\n"
	return 0
}

guruplug_restore() {
	[ "a${guruplug}" = "a" ] && return 0
	command=""
	for ledi in ${allleds}
	do
		for color in ${ledcolors}
		do
			colorname=`echo ${color} | ${sedbin} -e "s/:/_/g"`
			for file in trigger ${ledvariables}
			do
				value=`echo "$1" | ${grepbin} "^${ledi}_${colorname}_${file}=" | ${cutbin} -d= -f2- -s`
				if [ "a${value}" != "a" ]; then
					debug "echo \"${value}\" > \"${ledpath}/${color}:${ledi}/${file}\"\n"
					command="${command} echo \"${value}\" > \"${ledpath}/${color}:${ledi}/${file}\";"
				fi
			done
		done
	done
	unset LEDSCLEAN
	eval ${command}
	unset command
	unset value; unset file; unset colorname; unset color; unset ledi;
	return 0
}

guruplug_restore_state() {
	[ "a${guruplug}" = "a" ] && return 0
	[ "a${guruplug_original_state}" != "a" ] && guruplug_restore "${guruplug_original_state}" && debug "Original state of GuruPlug leds is now restored.\n" && return 0
	debug "Failed to restore GuruPlug leds into original state.\n"
	return 1
}

guruplug_save_state() {
	[ "a${guruplug}" = "a" ] && return 0
	! guruplug_state > /dev/null && return 1
	guruplug_original_state=`guruplug_state`
	export guruplug_original_state
	addexittrap guruplug_restore_state
	debug "Original state of GuruPlug leds is saved.\n"
	return 0
}

guruplug_probe() {
	[ "a${guruplug}" = "a" ] && return 1
	[ ! -w "/sys/class/leds/guruplug:green:health/trigger" ] && unset guruplug
	[ ! -w "/sys/class/leds/guruplug:green:health/brightness" ] && unset guruplug
	[ ! -w "/sys/class/leds/guruplug:red:health/trigger" ] && unset guruplug
	[ ! -w "/sys/class/leds/guruplug:red:health/brightness" ] && unset guruplug
	[ ! -w "/sys/class/leds/guruplug:green:wmode/trigger" ] && unset guruplug
	[ ! -w "/sys/class/leds/guruplug:green:wmode/brightness" ] && unset guruplug
	[ ! -w "/sys/class/leds/guruplug:red:wmode/trigger" ] && unset guruplug
	[ ! -w "/sys/class/leds/guruplug:red:wmode/brightness" ] && unset guruplug
	if [ "a${guruplug}" = "a" ]; then
		debug "GuruPlug leds not found, or not accessible.\n"
		return 1
	else
		##############################################
		export ledpath="/sys/class/leds"
		##############################################
		export redcolor="guruplug:red"
		export greencolor="guruplug:green"
		export ledcolors="${redcolor} ${greencolor}"
		##############################################
		export leftled="health"
		export rightled="wmode"
		export allleds="${leftled} ${rightled}"
		##############################################
		export ledvariables="brightness delay_off delay_on"
		##############################################
		debug "GuruPlug leds found.\n"
	fi
	if ! guruplug_save_state; then
		unset guruplug
		debug "Failed to retrieve state of leds.\n"
		return 1
	fi
}

config_args_read() {
	for arg in "$@"
	do
		debug "Parsing configuration value: %s.\n" "${arg}"
		parse_eval "readconfig" "${arg}" && continue
		parse_switches "${arg}"
	done
	unset arg
}

config_load() {
	# If no PIN supplied from command line and $HOME/.3gnet exists, use PIN from there.
	[ "a${SIM_PIN}" = "a" -a "a${runhome}" != "a" ] && [ -d "${runhome}" ] && [ -r "${runhome}/.3gpin" ] && SIM_PIN=`${headbin} -1 "${runhome}/.3gpin" 2> /dev/null | ${cutbin} -b1-4` && [ "a${SIM_PIN}" != "a" ] && export SIM_PIN && debug "Loaded PIN value from %s.\n" "${runhome}/.3gpin" && ! pin_valid "${SIM_PIN}" && unset SIM_PIN && debug "PIN supplied was not valid.\n"
	# Load PIN from system-wide PIN suppliers
	for pinsupplier in  "/etc/default/3gpin" "/etc/sysconfig/3gpin" "/etc/3gpin" "/etc/default/sakis3g.3gpin" "/etc/sysconfig/sakis3g.3gpin" "/etc/sakis3g.3gpin"
	do
		[ -r "${pinsupplier}" ] && unset SIM_PIN && SIM_PIN=`${headbin} -1 "${pinsupplier}" 2> /dev/null | ${cutbin} -b1-4` && [ "a${SIM_PIN}" != "a" ] && export SIM_PIN && debug "Loaded PIN value from %s.\n" "${pinsupplier}" &&! pin_valid "${SIM_PIN}" && unset SIM_PIN && debug "PIN supplied was not valid.\n"
	done
	unset pinsupplier
	# If system-wide configuration exists, load it overriding anything (user configuration/arguments/everything)
	for configfile in "/etc/default/sakis3g" "/etc/sysconfig/sakis3g" "/etc/sakis3g.conf"
	do
		if [ -r "${configfile}" ]; then
			debug "Loading system-wide configuration file %s.\n" "${configfile}"
			debug show_file "${configfile}"
			configargs=`${grepbin} -v "^#" "${configfile}" | ${grepbin} -v "^$" | ${sedbin} -e "s/^\(.*\)$/\"\1\"/g" | ${sedbin} -e "s/^\"\([A-Za-z_]*\)=\"\(.*\)\"\"$/\"\1=\2\"/g" | ${trbin} "\n" " "`
			debug "Configuration arguments are: %s\n" "${configargs}"
			eval config_args_read ${configargs}
			unset configargs
			debug "Finished loading file %s.\n" "${configfile}"
		else
			debug "Configuration file %s does not exist or is not readable.\n" "${configfile}"
		fi
	done
	unset configfile
	debug "Configuration file(s) loaded.\n"
}

# Parses command line switch arguments
parse_switch() {
	if [ "a$1" = "a$2" -o "a$1" = "a--$2" -o "a$1" = "a-$2" ]; then
		debug "Command line switch defined: %s\n" "$1"
		return 0
	fi
	return 1
}

# Parses command line variable settings
parse_eval() {
	! find_binary "cut" && return 1
	! find_binary "grep" && return 1
	if [ "a$1" = "areadconfig" ]; then
		readconfig=1
		shift
		[ "a$1" = "a" ] && unset readconfig && return 1
	else
		readconfig=0
	fi
	[ "a`echo "$1" | ${grepbin} "="`" = "a" ] && unset readconfig && return 1
	variable=`echo "${1}" | ${cutbin} -d= -f1`
	[ "a${variable}" = "a" ] && unset variable && unset readconfig && return 1
	value=`echo "${1}" | ${cutbin} -d= -f2-`
	[ "a${value}" = "a" ] && unset variable && unset value && unset readconfig && return 1
	case "${variable}" in
		pppint|PPPINT)
			export pppint="${value}"
			;;
  		CHAT_ABORT_STRINGS)
			# Abort strings that chat program may encounter
			export CHAT_ABORT_STRINGS="${value}"
			;;
		BAUD)
			# Baud rate
			if [ "a${value}" = "aMAX" -o "a${value}" = "amax" ]; then
				export BAUD="4000000"
			elif [ "a${value}" = "aMIN" -o "a${value}" = "amin" ]; then
				export BAUD="115200"
			elif [ "a${value}" = "aDEFAULT" -o "a${value}" = "adefault" -o "a${value}" = "aNORMAL" -o "a${value}" = "anormal" ]; then
				export BAUD="460800"
			else
				export BAUD="${value}"
			fi
			;;
		PPPD_OPTIONS)
			# Options passed to pppd when called directly
			export PPPD_OPTIONS="${value}"
			;;
		PPPD_PEERS)
			# Directory where pppd keeps its peers
			export PPPD_PEERS="${value}"
			;;
		XOSDFONT)
			# Font that will be used when displaying messages through XOSD (osd_cat)
			export XOSDFONT="${value}"
			;;
		AOSDFONT)
			# Font that will be used when displaying messages through XOSD (osd_cat)
			export AOSDFONT="${value}"
			;;
		MENUFONT|menufont)
			# Font that will be used when using 9menu
			export MENUFONT="${value}"
			;;
		OSDFONT)
			# Font that will be used when displaying messages through XOSD (osd_cat)
			export AOSDFONT="${value}"
			export XOSDFONT="${value}"
			;;
		LOGPOSITION|logposition)
			# Directory where pppd keeps its peers
			export LOGPOSITION="${value}"
			;;
		DESKTOPICON)
			# Directory where pppd keeps its peers
			export DESKTOPICON="${value}"
			;;
		DCOPSERVER)
			# Directory where pppd keeps its peers
			export DCOPSERVER="${value}"
			;;
		connection_hook|CONNECTION_HOOK|HOOK)
			# Enabling this is a security issue.
			# Users can pass argument to do whatever they want.
			if [ "a${readconfig}" = "a1" ]; then
				export CONNECTION_HOOK="${value}"
			else
				echo "Ignoring ${variable} variable for security reasons." > /dev/stderr
				echo "This variable is only usable through global configuration." > /dev/stderr
				echo "Consult documentation." > /dev/stderr
			fi
			;;
		DNS)
			export DNS="${value}"
			;;
		MODEM_PREPARE|PREPARE)
			export MODEM_PREPARE="${value}"
			INIT_STAGE0=`${printfbin} "%s\n" "${value}" | ${sedbin} -e "s/AT/\\nAT/g" | ${sedbin} -e "s/  *$//g" | ${grepbin} -v "^$" | ${grepbin} "^AT" | ${sedbin} -e "s/^\(.*\)$/\\\'\1\\\' OK/g" | ${trbin} "\n" " "`
			export INIT_STAGE0
			;;
		MODEM_INIT|INIT)
			export MODEM_INIT="${value}"
			;;
		DIAL|CUSTOM_DIAL)
			export CUSTOM_DIAL="${value}"
			;;
		FORCE_APN)
			export FORCE_APN="${value}"
			;;
		CUSTOM_APN)
			export CUSTOM_APN="${value}"
			;;
		APN)
			export APN="${value}"
			;;
		APN_USER)
			export APN_USER="${value}"
			;;
		APN_PASS)
			export APN_PASS="${value}"
			;;
		FORCE_ISP)
			export FORCE_ISP="${value}"
			;;
		SIM_PIN)
			export SIM_PIN="${value}"
			;;
		RFCOMM_TTY)
			export RFCOMM_TTY="${value}"
			;;
		CUSTOM_TTY)
			export CUSTOM_TTY="${value}"
			;;
		RFSERVICE)
			export RFSERVICE="${value}"
			;;
		RFCHANNEL)
			export RFCHANNEL="${value}"
			;;
		UNDISCOVERABLE)
			export UNDISCOVERABLE="${value}"
			;;
		BLUETOOTH)
			export BLUETOOTH="${value}"
			;;
		USBINTERFACE)
			export USBINTERFACE="${value}"
			;;
		USBDRIVER)
			export USBDRIVER="${value}"
			;;
		USBMODEM)
			export USBMODEM="${value}"
			;;
		OTHER)
			export OTHER="${value}"
			;;
		MODEM)
			export MODEM="${value}"
			;;
		MOREMENU)
			export MOREMENU="${value}"
			;;
		MENU)
			export MENU="${value}"
			;;
		DISPLAY)
			export DISPLAY="${value}"
			;;
		XAUTHORITY|LOCALAUTHORITY)
			export LOCALAUTHORITY="${value}"
			;;
		BALOONIZER|BALLOONIZER)
			export BALOONIZER="${value}"
			;;
		DESKTOP)
			export DESKTOP="${value}"
			;;
		SGUI)
			export SGUI="${value}"
			;;
		TRANSLATION)
			export TRANSLATION="${value}"
			;;
		*)
			debug "Unknown variable %s specified in command line.\n" "${variable}"
			unset variable
			;;
	esac
	unset readconfig
	if [ "a${variable}" != "a" ]; then
		debug "Command line set variable %s to \"%s\".\n" "${variable}" "`eval echo \\\${${variable}}`"
		unset variable; unset value;
		return 0
	fi
	unset variable; unset value
	return 1
}

parse_switches() {
	parse_switch "${1}" "balloons" && export balloons=yes
	parse_switch "${1}" "balloon" && export balloons=yes
	parse_switch "${1}" "baloons" && export balloons=yes
	parse_switch "${1}" "baloon" && export balloons=yes
	parse_switch "${1}" "ballons" && export balloons=yes
	parse_switch "${1}" "ballon" && export balloons=yes
	parse_switch "${1}" "balons" && export balloons=yes
	parse_switch "${1}" "balon" && export balloons=yes
	parse_switch "${1}" "b" && export balloons=yes

	parse_switch "${1}" "console" && export stick_to_console=yes
	parse_switch "${1}" "stick_to_console" && export stick_to_console=yes
	parse_switch "${1}" "c" && export stick_to_console=yes

	parse_switch "${1}" "debug" && export DEBUG=on
	parse_switch "${1}" "DEBUG" && export DEBUG=on
	parse_switch "${1}" "d" && export DEBUG=on

	parse_switch "${1}" "NOSMART" && export NOSMART=yes
	parse_switch "${1}" "NOFIX" && export NOSMART=yes
	parse_switch "${1}" "nosmart" && export NOSMART=yes
	parse_switch "${1}" "nofix" && export NOSMART=yes
	parse_switch "${1}" "smart" && export NOSMART=yes
	parse_switch "${1}" "fix" && export NOSMART=yes
	parse_switch "${1}" "f" && export NOSMART=yes

	parse_switch "${1}" "GOOGLEDNS" && export DNS="8.8.8.8 8.8.4.4"
	parse_switch "${1}" "GOOGLE" && export DNS="8.8.8.8 8.8.4.4"
	parse_switch "${1}" "googledns" && export DNS="8.8.8.8 8.8.4.4"
	parse_switch "${1}" "google" && export DNS="8.8.8.8 8.8.4.4"
	parse_switch "${1}" "g" && export DNS="8.8.8.8 8.8.4.4"

	parse_switch "${1}" "GURUPLUG" && export guruplug=yes
	parse_switch "${1}" "guruplug" && export guruplug=yes
	parse_switch "${1}" "GURU" && export guruplug=yes
	parse_switch "${1}" "guru" && export guruplug=yes
	parse_switch "${1}" "G" && export guruplug=yes

	parse_switch "${1}" "nohal" && export nohal=yes
	parse_switch "${1}" "hal" && export nohal=yes
	parse_switch "${1}" "h" && export nohal=yes

	parse_switch "${1}" "interactive" && export interactive=yes
	parse_switch "${1}" "i" && export interactive=yes

	parse_switch "${1}" "killstorage" && export killstorage=yes
	parse_switch "${1}" "nostorage" && export killstorage=yes
	parse_switch "${1}" "storage" && export killstorage=yes
	parse_switch "${1}" "k" && export killstorage=yes

	parse_switch "${1}" "nohalinform" && export nohalinform=yes
	parse_switch "${1}" "noinform" && export nohalinform=yes
	parse_switch "${1}" "l" && export nohalinform=yes

	parse_switch "${1}" "NOPROBE" && export NOPROBEGSM=yes
	parse_switch "${1}" "NOPROBEGSM" && export NOPROBEGSM=yes
	parse_switch "${1}" "noprobe" && export NOPROBEGSM=yes
	parse_switch "${1}" "noprobegsm" && export NOPROBEGSM=yes
	parse_switch "${1}" "GSM" && export NOPROBEGSM=yes
	parse_switch "${1}" "gsm" && export NOPROBEGSM=yes
	parse_switch "${1}" "n" && export NOPROBEGSM=yes

	parse_switch "${1}" "prefer_osd" && export prefer_osd=yes
	parse_switch "${1}" "preferosd" && export prefer_osd=yes
	parse_switch "${1}" "osd" && export prefer_osd=yes
	parse_switch "${1}" "OSD" && export prefer_osd=yes
	parse_switch "${1}" "o" && export prefer_osd=yes

	parse_switch "${1}" "forever" && export forever=yes
	parse_switch "${1}" "persist" && export forever=yes
	parse_switch "${1}" "P" && export forever=yes

	parse_switch "${1}" "directpppd" && export direct_pppd=yes
	parse_switch "${1}" "direct_pppd" && export direct_pppd=yes
	parse_switch "${1}" "ppp" && export direct_pppd=yes
	parse_switch "${1}" "pppd" && export direct_pppd=yes
	parse_switch "${1}" "p" && export direct_pppd=yes

	parse_switch "${1}" "noverbose" && export noverbose=yes
	parse_switch "${1}" "noinformation" && export nonotify=yes
	parse_switch "${1}" "nonotifications" && export nonotify=yes
	parse_switch "${1}" "nonotify" && export nonotify=yes
	parse_switch "${1}" "noerrors" && export noerror=yes
	parse_switch "${1}" "noerror" && export noerror=yes
	if parse_switch "${1}" "silent" || parse_switch "${1}" "quiet" || parse_switch "${1}" "q"; then
		export noerror=yes
		export nonotify=yes
		export noverbose=yes
	fi

	parse_switch "${1}" "sudo" && export alwayssudo=yes
	parse_switch "${1}" "alwayssudo" && export alwayssudo=yes
	parse_switch "${1}" "always_sudo" && export alwayssudo=yes
	parse_switch "${1}" "s" && export alwayssudo=yes

	parse_switch "${1}" "showtext" && export showtext=yes
	parse_switch "${1}" "T" && export showtext=yes

	parse_switch "${1}" "notranslate" && export notranslate=yes
	parse_switch "${1}" "t" && export notranslate=yes

	parse_switch "${1}" "nosafety" && export nosafety=yes
	parse_switch "${1}" "unsafe" && export nosafety=yes
	parse_switch "${1}" "u" && export nosafety=yes

	parse_switch "${1}" "voodoo" && export voodoo=yes
	parse_switch "${1}" "please" && export voodoo=yes
	parse_switch "${1}" "magic" && export voodoo=yes
	parse_switch "${1}" "Voodoo" && export voodoo=yes
	parse_switch "${1}" "Please" && export voodoo=yes
	parse_switch "${1}" "Magic" && export voodoo=yes
	parse_switch "${1}" "v" && export voodoo=yes

	parse_switch "${1}" "whiptail" && export SGUI="whiptail"
	parse_switch "${1}" "dialog" && export SGUI="dialog"
	parse_switch "${1}" "Xdialog" && export SGUI="Xdialog"
	parse_switch "${1}" "xdialog" && export SGUI="Xdialog"
	parse_switch "${1}" "zenity" && export SGUI="zenity"
	parse_switch "${1}" "kdialog" && export SGUI="kdialog"
	parse_switch "${1}" "9menu" && export SGUI="9menu"
	parse_switch "${1}" "xterm" && export SGUI="xterm"
	parse_switch "${1}" "gnome-terminal" && export SGUI="gnome-terminal"
	parse_switch "${1}" "konsole" && export SGUI="konsole"
	parse_switch "${1}" "interactiveterminal" && export SGUI="interactive terminal"
	parse_switch "${1}" "iterm" && export SGUI="interactive terminal"
	parse_switch "${1}" "terminal" && export SGUI="terminal"
	parse_switch "${1}" "term" && export SGUI="terminal"
	if parse_switch "${1}" "legacy"; then
		export SGUI="9menu"
		export prefer_osd="yes"
	fi

	parse_switch "${1}" "scanyes" && export scanyes="1"
	parse_switch "${1}" "scanno" && export scanno="1"
}

state_variables() {
	unset statevariables
	for flagvariable in stick_to_console:console interactive:interactive DEBUG:debug NOSMART:nofix killstorage:nostorage NOPROBEGSM:noprobegsm prefer_osd:osd direct_pppd:pppd alwayssudo:sudo forever:forever balloons:balloons
	do
		variablename=`echo "${flagvariable}" | cut -d: -f1`
		strinstr "${variablename}" "${1}" " " && debug "Variable %s excluded from state variables.\n" "${variablename}" && continue
		variablearg=`echo "${flagvariable}" | cut -d: -f2`
		variablevalue=`eval echo \\\${${variablename}}`
		[ "a${variablevalue}" != "a" ] && statevariables="${statevariables} --${variablearg}"
	done
	unset flagvariable; unset variablename; unset variablearg; unset variablevalue
	[ "a${DNS}" = "a8.8.8.8 8.8.4.4" ] && statevariables="${statevariables} --googledns"
	[ "a${DNS}" != "a8.8.8.8 8.8.4.4" -a "a${DNS}" != "a" ] && statevariables="${statevariables} DNS=\"${DNS}\""
	for valuevariable in MODEM_INIT FORCE_APN APN APN_USER APN_PASS FORCE_ISP SIM_PIN SGUI RFCOMM_TTY CUSTOM_TTY RFSERVICE RFCHANNEL UNDISCOVERABLE BLUETOOTH USBINTERFACE USBDRIVER USBMODEM OTHER MODEM MENU MOREMENU DISPLAY DESKTOP DCOPSERVER LOCALAUTHORITY BALOONIZER
	do
		strinstr "${valuevariable}" "${1}" " " && debug "Variable %s excluded from state variables.\n" "${valuevariable}" && continue
		variablevalue=`eval echo \\\${${valuevariable}}`
		[ "a${variablevalue}" != "a" ] && statevariables="${statevariables} ${valuevariable}=\"${variablevalue}\""
	done
	unset valuevariable; unset variablevalue
	statevariables=`echo ${statevariables}`
	export statevariables
	debug "State variables are: %s\n" "${statevariables}"
	return 0
}

# Parses command line arguments
parse_arguments() {
	need_binary "tr"
	unset allargs
	for arg in "$@"
	do
		varg=`sanitize "${arg}"`
		allargs="${allargs} \"${varg}\""
		parse_eval "${varg}" && continue
		parse_switches "${varg}"
		unset varg
	done
	unset arg
	allargs=`echo ${allargs}`
	export allargs
}

# Unsets binary variables if running as root. This eliminates the chance
# that a malicious user has succeed into setting a "trojan" binary helper
# that will be executed with root privileges.
secure_path() {
	PATH="/bin:/sbin:/usr/bin:/usr/sbin"
	export PATH
	unset whichbin
	unset grepbin
	unset cutbin
	need_binary "grep"
	need_binary "cut"
	for variable in `set | ${grepbin} "bin=" | ${cutbin} -d= -f1`
	do
		value=`eval echo \\${${variable}} 2> /dev/null`
		if [ "a${value}" != "a" ] && [ -x "${value}" ]; then
			eval "unset ${variable}"
			debug "Unset variable %s for security reasons.\n" "${variable}"
		fi
	done
	unset variable; unset value
	return 0
}

# Removes \, ", ', ` from variables' contents
secure_variables() {
	need_binary "sed"
	need_binary "tr"
	for variable in DISPLAY XAUTHORITY USERNAME HOME USER DESKTOP
	do
		debug "Sanitizing %s: %s\n" "${variable}" "`eval echo \"\\${${variable}}\"`"
		value=`eval "echo \"\\${${variable}}\"" 2> /dev/null | ${trbin} "\\\\" " " 2> /dev/null | ${trbin} "\"" " " | ${trbin} "'" " " | ${trbin} "\\\`" " "`
		debug "Sanitized value: %s\n" "${value}"
		eval "${variable}=\"""${value}""\""
		eval "${variable}=\"`eval echo \"\\${${variable}}\"`\""
		eval "export ${variable}"
		debug "Sanitized %s: %s\n" "${variable}" "`eval echo \"\\${${variable}}\"`"
	done
	unset value; unset variable
	return 0
}

secure_capabilities() {
	debug "Will check shell capabilities.\n"
	set +o monitor > /dev/null 2> /dev/null
	set +m > /dev/null 2> /dev/null
	funcname=`set | grep "^FUNCNAME="`
	if [ "a${funcname}" = "a" ]; then
		debug "Shell does not provide FUNCNAME environment variable.\n"
		debug "USB Safety will be disabled.\n"
		export NOFUNCNAME="1"
		unset YESFUNCNAME=""
	else
		debug "Shell provides FUNCNAME environment variable.\n"
		unset NOFUNCNAME
		export YESFUNCNAME="1"
	fi
	unset funcname
	return 0
}

# Makes sure no danger exists when run as root
secure_environment() {
	secure_capabilities
	! we_are_root_already && return 0
	secure_path
	secure_variables
	return 0
}

# Preparation or death
startup() {
	# try to set shell as helpful as possible with background jobs
	secure_environment
	addexittrap cleanscreen
	me=$1; [ "$#" -gt "0" ] && shift
	# Draftly set allargs. Will better do it during parse_arguments
	allargs="$@"; export allargs
	no_action_command "$@" && stop_with 0
	verbose "Starting up"
	parse_arguments "$@"
	debug_header "$@"
	resolv_binaries "${me}"; unset me
	check_udevd "$@"
	find_user
	config_load
	find_display
	find_gui
	translate_load
	check_root_deps
	modeswitch_load
	guruplug_probe
	debug "Finished starting up.\n"
}

# Main program
sakis3g_main() {
	# Initialization
	startup "$@"
	# Get action
	action_command "$@" && stop_with ${actionresult}
	default_actor
	ret=$?
	stop_with ${ret}
}

# Execute main method
sakis3g_main $0 "$@"

# In case all actors performed well
debug "Reached end of program.\n"
stop_with 0

