#!/bin/bash -i
#
# ZigzagProxy (ZPROXY)
# 
# This program is free software: you can redistribute it and/or modify it 
# under the terms of the GNU General Public License as published 
# by the Free Software Foundation; either version 3 of the License, 
# or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, 
# but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License 
# along with this program. If not, see http://www.gnu.org/licenses/. 
# 
# Copyright (C) 2012
# Free Software Foundation, Inc.
# 
# For information or to collaborate on the project:
# https://savannah.nongnu.org/projects/zproxy
# 
# Gianluca Zoni
# http://inventati.org/zoninoz
# zoninoz@inventati.org
#


#### CONFIG
# NB: se si usa "source" oppure "." prima dello script, ovviamente "$prog" è "/bin/bash", quindi è meglio scegliere un nome al posto di basename:
#prog=`basename $0`

prog="zproxy"
proxy_list_sources=(
    https://ip-adress.com/proxy_list/
    http://proxy-list.org/en/index.php
)

PROG=$(tr a-z A-Z <<< "$prog")
path_prog="$HOME/$prog"
path_tmp="$HOME/$prog"
mkdir -p "$path_prog"
#proxy_types=( Transparent )
credentials="$HOME/${prog}/.credenziali_router.txt"
max_waiting=40
    
url_update="http://git.savannah.nongnu.org/cgit/zproxy.git/snapshot/zproxy-0.1.tar.gz"

ck_proxy_url="http://inventati.org/zoninoz/html/index.php"
#ck_proxy_url="https://savannah.nongnu.org"

update=false
help=false
disable_proxy=false
transparent=false
anonymous=false
elite=false
reconnect=false
ip=false

user_agent="Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0"
user_lang="$LANG"
user_language="$LANGUAGE"
prog_lang='en_US.UTF-8:en'

ip_server_url='http://indirizzo-ip.com/ip.php'


#### layout

function init_colors {
	# Reset
    Color_Off='\e[0m'       # Text Reset
    
	# Regular Colors
    Black='\e[0;30m'        # Nero
    Red='\e[0;31m'          # Rosso
    Green='\e[0;32m'        # Verde
    Yellow='\e[0;33m'       # Giallo
    Blue='\e[0;34m'         # Blu
    Purple='\e[0;35m'       # Viola
    Cyan='\e[0;36m'         # Ciano
    White='\e[0;37m'        # Bianco
    
	# Bold
    BBlack='\e[1;30m'       # Nero
    BRed='\e[1;31m'         # Rosso
    BGreen='\e[1;32m'       # Verde
    BYellow='\e[1;33m'      # Giallo
    BBlue='\e[1;34m'        # Blu
    BPurple='\e[1;35m'      # Viola
    BCyan='\e[1;36m'        # Ciano
    BWhite='\e[1;37m'       # Bianco
    
	# Underline
    UBlack='\e[4;30m'       # Nero
    URed='\e[4;31m'         # Rosso
    UGreen='\e[4;32m'       # Verde
    UYellow='\e[4;33m'      # Giallo
    UBlue='\e[4;34m'        # Blu
    UPurple='\e[4;35m'      # Viola
    UCyan='\e[4;36m'        # Ciano
    UWhite='\e[4;37m'       # Bianco
    
	# Background
    On_Black='\e[40m'       # Nero
    On_Red='\e[41m'         # Rosso
    On_Green='\e[42m'       # Verde
    On_Yellow='\e[43m'      # Giallo
    On_Blue='\e[44m'        # Blu
    On_Purple='\e[45m'      # Purple
    On_Cyan='\e[46m'        # Ciano
    On_White='\e[47m'       # Bianco
    
	# High Intensty
    IBlack='\e[0;90m'       # Nero
    IRed='\e[0;91m'         # Rosso
    IGreen='\e[0;92m'       # Verde
    IYellow='\e[0;93m'      # Giallo
    IBlue='\e[0;94m'        # Blu
    IPurple='\e[0;95m'      # Viola
    ICyan='\e[0;96m'        # Ciano
    IWhite='\e[0;97m'       # Bianco
    
	# Bold High Intensty
    BIBlack='\e[1;90m'      # Nero
    BIRed='\e[1;91m'        # Rosso
    BIGreen='\e[1;92m'      # Verde
    BIYellow='\e[1;93m'     # Giallo
    BIBlue='\e[1;94m'       # Blu
    BIPurple='\e[1;95m'     # Viola
    BICyan='\e[1;96m'       # Ciano
    BIWhite='\e[1;97m'      # Bianco
    
	# High Intensty backgrounds
    On_IBlack='\e[0;100m'   # Nero
    On_IRed='\e[0;101m'     # Rosso
    On_IGreen='\e[0;102m'   # Verde
    On_IYellow='\e[0;103m'  # Giallo
    On_IBlue='\e[0;104m'    # Blu
    On_IPurple='\e[10;95m'  # Viola
    On_ICyan='\e[0;106m'    # Ciano
    On_IWhite='\e[0;107m'   # Bianco
}


function print_c {
    case "$1" in
	1)
	    echo -n -e '\e[1;32m' #verde
	    ;;
	2)
	    echo -n -e '\e[1;33m' #giallo
	    ;;	
	3)
	    echo -n -e '\e[1;31m' #rosso
	    ;;	
	4)
	    echo -n -e "$BBlue"
    esac
    echo -n -e "$2\n"
    echo -n -e "${Color_Off}"
}

function separator {
	#COLUMNS=$( tput cols ) 2>/dev/null
    if [ -z "$COLUMNS" ]
    then 
	COLUMNS=50
    fi

    echo -ne "${BBlue}"
    for column in $(seq 1 $COLUMNS)
    do
	echo -n -e "$1"
    done
    #\e[1;34m

    echo -ne "${Color_Off}"
}


function separator- {
    separator "─"
}

function fclear {
    #echo -n -e "\e[0;37m\e[40m\ec"
    #echo -n -e "\ec\e[37m\e[40m\e[J"
    echo -n -e "\ec${White}${On_Black}\e[J"
}

function cursor {
    local stato=$1
    case $stato in
	off)
	    echo -e -n "\033[?30;30;30c"
	    ;;
	on)
	    echo -e -n "\033[?0;0;0c"
	    ;;
    esac
}

function header {
    ## $1=label ; $2=colors ; $3=header pattern

    # echo -n -e "\e[1;34m $1 ${Color_Off}\n"
    local text="$1"
    local length_text=$(( ${#text}+2 ))
    local hpattern="$3"
    
    [ -z "$hpattern" ] && hpattern=" "
    echo -ne "$2"

    for column in `seq 1 $COLUMNS`
    do
	echo -ne "$hpattern" 
    done 

    if [ -n "$length_text" ] &&
	   [ -n "$COLUMNS" ]
    then
	if (( $length_text<=$COLUMNS ))
	then
	    echo -ne "\r$text${Color_Off}\n"

	else
	    echo -ne "\r${text:0:$COLUMNS}${Color_Off}${text:$COLUMNS}\n"
	fi
    fi
}


function header_z {
    fclear
    zclock
    header " ZigzagProxy ($prog) $zclock" "$On_Blue" " "
}

function header_box {
    header " $1 " "$Black${On_White}" "─" #"-" 
}

function header_dl {
    header " $1 " "$White${On_Blue}" " "
}

function pause {
    echo
    header ">>>>>>>> Digita un tasto per continuare " "$On_Blue$BWhite" "<"
    cursor off
    read -n 1
    cursor on
}

function xterm_stop {
    echo
    header ">>>>>>>> Digita < Enter > per chiudere Xterm " "$On_Blue$BWhite" "<"
    cursor off
    read -n 1
    cursor on
}
function zclock {
    week=( "dom" "lun" "mar" "mer" "gio" "ven" "sab" )
    zclock="\033[1;$((COLUMNS-22))f$(date +%R) │ ${week[$( date +%w )]} $(date +%d·%m·%Y)"
}





function my_ip {
    # myip=$(wget -qO- \
    # 		checkip.dyndns.org |
    # 		  sed -e 's/.*Current IP Address: //' -e 's/<.*$//')

    
    print_c 4 "Indirizzo IP:"
    wget -qO- "$ip_server_url"
    echo
}


function new_ip_router {
    if [ -s $credentials ]
    then
	USER=$(awk '{print $1}' "$credentials")
	PASSWD=$(awk '{print $2}' "$credentials")

	print_c 1 "Cambio indirizzo IP..."
	wget --http-passwd=$PASSWD    \
	     --http-user=$USER        \
	     192.168.0.1/stanet.stm   \
	     -O- &>/dev/null

	wget --http-passwd=$PASSWD       \
	     --http-user=$USER           \
	     --post-data="disconnect=1"  \
	     192.168.0.1/cgi-bin/statusprocess.exe \
	     -O- &>/dev/null
	echo
    else
	print_c 3 "Funzione di cambio indirizzo IP (riconnessione del router) disattivata: non esiste il file di configurazione $credentials"
    fi

}

function unset_proxy {
    unset http_proxy https_proxy
    export http_proxy https_proxy
}

function set_proxy {
    export http_proxy="$1"
    export https_proxy=$http_proxy
}

## servizi proxy:
function _ip_adress {
    local proxy_regex
    ## ip-adress.com

    for proxy_type in ${proxy_types[*]}
    do
	case "$proxy_type" in
	    Transparent)
		proxy_regex='<td>transparent'
		;;
	    Anonymous)
		proxy_regex='<td>anonymous'
		;;
	    Elite)
		proxy_regex='<td>highly-anonymous'
		;;
	esac
	
	grep "${proxy_regex}" "$path_tmp/proxy_page.html" -B1  |
	    grep href |
	    sed -r "s|.+>([^>]+)</a>([^<]+)<.+|\1\2:$proxy_type|g"  >> "$path_tmp/proxy_list.txt"	
    done
}


function _proxy_list {
    #### attualmente non ancora integrata nel più recente sistema
    ## proxy-list.org
    
    for proxy_type in ${proxy_types[*]}
    do
	html=$(grep -B 4 "${proxy_type}" "$path_tmp/proxy_page.html" |grep class)
    done
    ## da fare:
    ## sostituire $html con "$path_tmp"/proxy_list.txt: accodare in modo uniforme questi proxy con quelli dell'altro servizio
    

    ## get_proxy proxy:
    ##
    # n=$(( $(wc -l <<< "$html")/4 ))
    # proxy_type=$(sed -n $(( ${line}*4 ))p <<< "$html")
    # proxy_type="${proxy_type%%'</'*}"
    # proxy_type="${proxy_type##*>}"

    # proxy=$(sed -n $(( ${line}*4-3 ))p <<< "$html")
    # proxy="${proxy#*proxy\">}"
    # proxy="${proxy%<*}"
}

function get_proxy_list {
    wget -q -t 1 -T 20                              \
	 --user-agent="$user_agent"                 \
	 ${proxy_list_sources[0]}                   \
	 -O "$path_tmp/proxy_page.html"             \
	 -o /dev/null

    print_c 4 "Ricerca lista proxy $proxy_server: ${list_proxy_url[$proxy_server]}"


    if [ -s "$path_tmp/proxy_page.html" ]
    then
	_ip_adress
    else
	print_c 3 "Proxy non disponibili, riprovo più tardi"
	break
    fi
}

function get_proxy {
    declare -n ref_address="$1"
    declare -n ref_type="$2"
    local regex=$(tr ' ' '|' <<< "${proxy_types[*]}")
    echo "$regex"
    
    local max=$(wc -l < "$path_tmp/proxy_list.txt")
    local proxy_line=$(grep -P "($regex)" "$path_tmp/proxy_list.txt" |head -n1)

    
    [[ "$proxy_line" =~ Anonymous ]] && ref_type="Anonymous"
    [[ "$proxy_line" =~ Transparent ]] && ref_type="Transparent"
    [[ "$proxy_line" =~ Elite ]] && ref_type="Elite"
    
    ref_address="${proxy_line%:${ref_type}*}"
}

function del_proxy {
    local proxy_address="$1"
    local proxy_type="$2"
    if [ -s "$path_tmp/proxy_list.txt" ]
    then
	grep -v "${proxy_address}:${proxy_type}" "$path_tmp/proxy_list.txt" >"$path_tmp/proxy_list.temp"
	mv "$path_tmp/proxy_list.temp" "$path_tmp/proxy_list.txt"
    fi
}

function check_speed {
    ## $1 == url to test
    local maxspeed=0
    local minspeed=25
    local num_speed type_speed speed

    print_c 2 "\nTest velocità di download:"

    i=0
    while ((i<3))
    do
	i=${#speed[*]}
	#speed[$i]=$(wget -t 1 -T 60 -O /dev/null "http://indirizzo-ip.com/ip.php" 2>&1 | grep '\([0-9.]\+ [KM]B/s\)' )
	#speed[$i]=$(wget -t 1 -T $max_waiting -O /dev/null "$url_in" 2>&1 | grep '\([0-9.]\+ [KM]B/s\)' )

	wget -t 1 -T $max_waiting              \
	     --user-agent="$user_agent"        \
	     -O /dev/null                      \
	     "$1"                              \
	     -o "$path_tmp"/speed-test-proxy

	speed[$i]=$(grep '\([0-9.]\+ [KM]B/s\)' "$path_tmp"/speed-test-proxy)
	
	if [ -n "${speed[$i]}" ]
	then
	    speed[$i]="${speed[$i]#*'('}"
	    speed[$i]="${speed[$i]%%)*}"
	    
	    type_speed[$i]="${speed[$i]//[0-9. ]}"
	    num_speed[$i]="${speed[$i]//${type_speed[$i]}}"
	    num_speed[$i]="${num_speed[$i]//[ ]*}"
	    num_speed[$i]="${num_speed[$i]//[.,]*}"

	    if [ "${type_speed[$i]}" == 'B/s' ]
	    then
		num_speed[$i]="0"

	    elif [ "${type_speed[$i]}" == 'MB/s' ]
	    then
		num_speed[$i]=$(( ${num_speed[$i]}*1024 ))
	    fi
	else
	    speed[$i]="0 KB/s"
	    num_speed[$i]="0"
	    type_speed[$i]='KB/s'
	fi
	print_c 0 "${speed[i]}"

	if (( "${num_speed[0]}" == 0 ))
	then
	    break

	elif (( "${num_speed[i]}" >= 25 ))
	then
	    print_c 1 "Velocità di download sufficiente usando il proxy $http_proxy: ${num_speed[i]} KB/s"
	    echo "$http_proxy" > "$path_tmp"/proxy-active
	    return 0
	fi
    done 2>/dev/null
    
    for k in ${num_speed[*]}
    do
    	(( $maxspeed<$k )) && maxspeed=$k 
    done
    
    if (( $maxspeed<$minspeed ))
    then
    	print_c 3 "La massima velocità di download raggiunta usando il proxy è inferiore a quella minima richiesta ($minspeed KB/s)"
	rm -f "$path_tmp"/proxy-active
	return 1

    else
    	print_c 1 "Massima velocità di download raggiunta usando il proxy $http_proxy: $maxspeed KB/s"
    	return 0
    fi 
}

function new_ip_proxy {
    export LANG="$prog_lang"
    export LANGUAGE="$prog_lang"
    
    rm -f "$path_tmp/proxy.tmp" "$path_tmp/cookies.zdl"

    ##########################################
    ## tipi di proxy: Anonymous Transparent Elite
    ## da impostare nelle estensioni in cui si fa uso di check_ip:
    ## proxy_types=( ELENCO TIPI DI PROXY )
    ##
    ## predefinito:
    if [ -z "${proxy_types[*]}" ]
    then
	proxy_types=( "Transparent" )
    fi
    ##########################################
    
    while true
    do
	unset_proxy
	unset proxy_address proxy_type
	print_c 1 "\nAggiorna proxy (${proxy_types[*]// /, }):"
	
	if [ ! -s "$path_tmp/proxy_list.txt" ]
	then
	    get_proxy_list
	fi
	get_proxy proxy_address proxy_type
	
	set_proxy "$proxy_address"

	print_c 0 "Proxy: $http_proxy ($proxy_type)\n"
	
	del_proxy "$proxy_address" "$proxy_type"

	if check_speed "$ip_server_url"
	then
	    break

	elif [ ! -s "$path_tmp/proxy_list.txt" ]
	then
	    print_c 3 "Proxy attualmente non disponibile: proxy disattivato"
	    break
	fi
    done
    
    [ ! -s "$path_tmp/proxy_list.txt" ] && rm -f "$path_tmp/proxy_list.txt"

    export LANG="$user_lang"
    export LANGUAGE="$user_language"
    print_c 4 "\nProxy attivato: $http_proxy"
}

function update_prog {
    local pwd_old="$PWD"
    print_c 1 "Aggiornamento di $PROG ..."
    
    cd /tmp

    wget -T $max_waiting "$url_update"

    print_c 1 "Installazione di $PROG in /usr/local/bin/"
    archive="${url_update##*\/}"
    tar -xzf "$archive"

    cd "${archive%.tar.gz}"
    chmod +x $prog

    mv $prog /usr/local/bin/ && print_c 1 "Aggiornamento completato." ||
	   ( sudo mv $prog /usr/local/bin/ && print_c 1 "Aggiornamento completato." ) ||
		    ( echo -n "(Root)" && su -c "mv $prog /usr/local/bin/" && print_c 1 "Aggiornamento completato." ) ||
			    print_c 3 "Aggiornamento automatico non riuscito"
    echo
    cd "$pwd_old"
}

function usage {
    echo -e -n '\e[0m\e[J'
    echo -e -n "\e[0m\e[J
\e[1mUso (l'ordine degli argomenti non è importante): \e[0m"
	echo -e "$prog [OPZIONI]

\e[1mOpzioni:\e[0m
-h,	--help		      Manuale di ZigzagProxy

        --ip                  Indirizzo IP attuale

-u      --update              Aggiorna ZigzagProxy
	
-d      --disable             Disabilita il proxy
	
-t      --transparent
-a      --anonymous
-e      --elite               Seleziona il tipo di proxy: Transparent, Anonymous, Elite
	
-r      --reconnect           Forza la riconnessione del modem (funziona solo per pochi modelli)
	

" #|less --RAW-CONTROL-CHARS	
}


init_colors
#header_z

#separator z

proxy_types=()

if (( $#>0 ))
then
    args=( $@ )
    i=0
    while (( i<$# ))
    do
	case "${args[i]}" in
	    -u | --update) 
		update=true
		;;
	    -h | --help)
		help=true
		;;
	    -d | --disable)
		disable_proxy=true
		;;
	    -t | --transparent)
		transparent=true
		[[ "${proxy_types[*]}" =~ Transparent ]] ||
		    proxy_types+=( Transparent )
		;;
	    -a | --anonymous)
		anonymous=true
		[[ "${proxy_types[*]}" =~ Anonymous ]] ||
		    proxy_types+=( Anonymous )
		;;
	    -e | --elite)
		elite=true
		[[ "${proxy_types[*]}" =~ Elite ]] ||
		    proxy_types+=( Elite )
		;;
	    -r | --reconnect)
		reconnect=true
		;;
	    --ip)
		ip=true
		;;
	    *)
		usage
		;;
	esac
	(( i++ ))
	
    done
    
    if [ -z "${proxy_types[*]}" ]
    then
	proxy_types=( "Transparent" )
    fi
    
    "$help" && usage	
    
    $update && update_prog
    $reconnect && new_ip_router
    $disable_proxy && unset_proxy

    if $transparent ||
	    $anonymous ||
	    $elite
    then
	new_ip_proxy
    fi

    $ip && my_ip

else
    usage
fi
