#!/usr/bin/perl -w

use lib qw(/usr/lib/libDrakX);

# i18n: IMPORTANT: to get correct namespace (drakfon instead of libDrakX)
BEGIN { unshift @::textdomains, 'drakfon' }

use standalone;
use interactive;
use common;
use modules;
use log;
use network::network;
use Net::Telnet;
use TFTP;
use services;

my %router;
my @network_ips;
my $prefix = "/usr/share/drakfon/firmwares/";
my $in = interactive->vnew('su');
$::isStandalone = 0;

my $license_agreement = "Refuse";

my $is_2006 = eval { require network::ethernet };

my $discover_network = sub {
	my @addrs;
	my $_w = $in->wait_message('', N("Getting network information..."), 1);
	my $broadcast;
	my @inet_info;
	my @ifconfig = `ifconfig $router{intf}`;
	foreach(@ifconfig){
	    @inet_info = split(" ",$_) and last if ($_ =~ /inet .*/);
	}
	foreach(@inet_info){
	    $broadcast = (split(":",$_))[1] and last if ($_ =~ /Bcast:.*/);
	}
	system("ping -b $broadcast -w 5 &> /dev/null");
	$router{intf} = (split(":",$router{intf}))[0];
	my @arp_output = `arp -v -i $router{intf}`;
	foreach(@arp_output){
	   	$addrs[++$#addrs] = (split(" ",$_))[0] if ($_ =~ /.*$router{intf}.*/);
	}
	# Test default router IP 192.168.1.1 #
	# Router doesn't answer broadcast always #

	my $default_ip = get_router_address($router);
	my @found = grep { /$default_ip/ } @addrs;
	if (!@found){
		$addrs[++$#addrs] = "$default_ip" if(!system("ping -c 3 $default_ip &> /dev/null"));
	}	
	return(@addrs);
};

my $set_router_info = sub {
	if($router{model} eq "wrt54g"){
		$router{need_auth} = 0;
		$router{need_config} = 0;
		$router{firmware} = $prefix."FONbasic-WRT54GL-0.6.6.bin";
	}
	elsif($router{model} eq "wrt54gl"){
		$router{need_auth} = 0;
		$router{need_config} = 0;
		$router{firmware} = $prefix."FONbasic-WRT54GL-0.6.6.bin";
	}
	elsif($router{model} eq "wrt54gs"){
		$router{need_auth} = 0;
		$router{need_config} = 0;
		$router{firmware} = $prefix."FONbasic-WRT54GS-0.6.6.bin";
	}
	elsif($router{model} eq "wrt54gs4"){
		$router{need_auth} = 0;
		$router{need_config} = 0;
		$router{firmware} = $prefix."FONbasic-WRT54GS_v4-0.6.6.bin";
	}
	elsif($router{model} eq "wzrrsg54"){
		$router{need_auth} = 0;
  		$router{need_config} = 0;
		$router{firmware} = $prefix."FONbasic-BUFFALO-0.6.6.trx";		
	}
	elsif($router{model} eq "whrg54s"){
		$router{need_auth} = 0;
		$router{need_config} = 0;
		$router{address} = "192.168.11.1";
		$router{firmware} = $prefix."FONbasic-BUFFALO-0.6.6.trx";
	}
	elsif($router{model} eq "whrhpg54"){
		$router{need_auth} = 0;
		$router{need_config} = 0;
		$router{firmware} = $prefix."FONbasic-BUFFALO-0.6.6.trx";
	}
	else{
		$router{need_auth} = 0;
		$router{need_config} = 0;
		$router{firmware} = $prefix."FONbasic-WRT54GL-0.6.6.bin";
	}
};

sub get_router_address {
	my ($router) = @_;
	$router{address} || "192.168.1.1";
}

my $configure_router = sub {
	my $_w = $in->wait_message('', N("Configuring your router (%s)...", $router{model}), 1);
	$telnet = Net::Telnet->new(Timeout => 30);
	$telnet->errmode("return");
	$telnet->open($router{ip});
	$telnet->login($router{login}, $router{passwd}) if $router{need_auth};
	
	# Exec necessary cmds #	
	@lines = $telnet->cmd("uname -a");
	print @lines;
	
	my $return = $telnet->errmsg;
	my $success;
	if($return eq ""){
		$success = 1;
	}
	else{
		$router{errstr} = "Impossible to establish telnet connection";
		$success = 0;
	}
	return($success);
};

sub ping_router {
    my ($address, $timeout) = @_;
    require Net::Ping;
    my $ping = Net::Ping->new("icmp");
    while ($timeout-- > 0) {
        $ping->ping($address, 1) and return 1;
    }
    $router{errstr} = N("The router is still turned OFF");
    return 0;
}

my $upload_firmware = sub {
    my $_w = $in->wait_message('', N("Waiting for your router to be turned ON."), 1);
    ping_router(get_router_address($router), 30) or return;
    $_w = $in->wait_message('', N("Uploading firmware..."), 1);
    $tftp = new TFTP($router{ip},Timeout => 2, Retries =>15);
    $tftp->binary;
	my $return = $tftp->put($router{firmware});
	if($return eq $router{firmware}){
		$success = 1
	}
	else{
		$router{errstr}=$tftp->{'errstr'};
		$success = 0;
	}
    $tftp->quit;
	return($success);
};

my $test_router = sub{
    my $_w = $in->wait_message('', N("Installing firmware...") . "\n" .N("This can take a few minutes.") . "\n\n" . N("WARNING: do NOT unplug your router while firmware is being uploaded"), 1);
    my $dhclient_conf = "/tmp/dhclient-drakfon.conf";
    output_p($dhclient_conf, "timeout 4;\n");
    my $tries = 10;
    while ($tries-- > 0) {
        run_program::run("dhclient -cf $dhclient_conf $router{intf}");
        require network::tools;
        my (undef, $gw) = network::tools::get_interface_status($router{intf});
        $gw and return 1;
    }
    return 0;
};

$wiz = {
	defaultimage => "FON_logo.png",
	name => ($is_2006 ? " " x 20 : "") . N("DrakFON"),
	pages => {
		welcome => {
			name => sub {
                               N("This wizard allows you to easily install the FON firmware on any compatible WiFi router."). "\n\n" .
                               N("Make sure that your router's Ethernet port 1 is connected to your computer's Ethernet port.") . "\n\n" .
                               N("Press \"Next\"");
			},
			no_back => 1, 
			next => "license_agreement",
		},

		license_agreement => {
		    name => N("User License of the FON Software

This firmware that FON Wireless Limited is providing for your use, is a set of programs [see below] developed under the GPL license, and is now distributed for installation in certain WIFI Linksys router models (i.e. WRT54G and WRT54GS) and Buffalo (WZR-RS-G54/WHR-G54S/HP-G54).

Firmware for the creation and administration of WIFI Access Points for the FON Community.

This firmware is free software. You may redistribute and/or change it according to the terms of the GNU General Public License as published by the Free Software Foundation, in its current version 2.

This program is distributed in the hope that it will be useful, but WITHOUT ANY GUARANTEE: neither the implicit COMMERCIAL guarantee or without guaranteeing the CONVENIENCE FOR PRIVATE USE. Please refer to the GNU General Public License for more details.

You should have received a copy of the General Public License along with this program. If this is not the case you should write to the Free Software Foundation, Inc., in 675 Mass Ave, Cambridge, MA 02139, USA.

FONbasic Source code

This firmware contains various 3rd party software. All FON or OpenWrt specific additions are licensed under the terms of the GNU General Public License (version 2). You can find the exact licensing terms of other parts in the unmodified software archives included in our source release in the 'dl' directory.

The FONbasic source code for the Linksys router, based on OpenWrt is available to download at http://download.fon.com/firmware/0.6.6/FONbasic-0.6.6.tar.bz2

The FONbasic source code for La Fonera, based on OpenWrt is available to download at http://download.fon.com/firmware/fonera/latest/fonera.tar.bz2"),
		    data => [ {
			list => [ N_("Accept"), N_("Refuse") ], val => \$license_agreement,
			type => 'list', format => sub { translate($_[0]) },
		    } ],
		    complete => sub { $license_agreement eq "Refuse" },
		    next => "router_list",
		},

		router_list => {
			pre =>sub {
				my @supported = (
					[ N("Linksys WRT54G (version 1-4)"),	"wrt54g"	],
					[ N("Linksys WRT54GL"),					"wrt54gl"	],
					[ N("Linksys WRT54GS (version 1-3)"),	"wrt54gs"	],
					[ N("Linksys WRT54GS (version 4)"),		"wrt54gs4"	],
					[ N("Buffalo WZR-RS-G54"),				"wzrrsg54"	],
					[ N("Buffalo WHR-G54S"),				"whrg54s"	],
					[ N("Buffalo WHR-HP-G54"),				"whrhpg54"	],
				);
				foreach (@supported) {
					my ($string, $model) = @$_;
					$supported{$string} = $model;
				}
				@supported_list = {
					label => N("Router model"),
					val => \$router_model,
					list => [ map { $_->[0] } @supported ],
				 };
			},
			name => sub {
                               N("Choose one of the supported routers from the list:");
			},
			data => \@supported_list,
			post => sub {
				$router{model} = $supported{$router_model};
				$set_router_info->();
				return("restore_default");
			},
		},

		restore_default => {
			name => sub {
                               N("Please reset your router to the manufacturer default settings (see your product User Manual).") . "\n\n" .
                               N("To continue, press 'Next'.");
			},
			post => sub {
				return("get_intf");
			}, 
		},

		get_intf => {
			pre => sub {
				my @interfaces_names;
				my $modules_conf = modules::any_conf->read;
				modules::load_category($modules_conf, list_modules::ethernet_categories());
				my %names;
				if ($is_2006) {
				    require network::ethernet;
				    my @all_cards = network::ethernet::get_eth_cards($modules_conf);
				    %names = network::ethernet::get_eth_cards_names(@all_cards);
				} else {
				    require network::connection::ethernet;
				    my @all_cards = network::connection::ethernet::get_eth_cards($modules_conf);
				    %names = network::connection::ethernet::get_eth_cards_names(@all_cards);
				}

				foreach (keys %names) {
					$interfaces_names[++$#interfaces_names] = $names{$_};
					$interfaces{$names{$_}} = $_;
				}
				@intf_list = {
					val => \$intf_choosed,
                    type => 'list',
                    list => [sort(@interfaces_names)],
                 };
			},
			ignore => 1,
			name => sub{
				N("Choose the interface where the router (%s) is connected:", $router{model});
			},
			data =>\@intf_list,
			post => sub {
				$router{intf} = $interfaces{$intf_choosed};

				my $_w = $in->wait_message('', N("Resetting network configuration"));

				#- save shorewall state and stop it
				$shorewall_enabled = services::starts_on_boot("shorewall");
				run_program::run("shorewall", "clear");
				#- turn down ifplugd so that the interface does not disconnect when router is turned off
				run_program::run("ifdown", $router{intf}, "daemon");
				run_program::run("dhclient", $router{intf});

				undef $_w;
				@network_ips = $discover_network->();
				return("manual_ip") if (!@network_ips);
				return("router_ip");
			},
		},
	
		router_ip => {
			pre =>sub {
				my @addrs = @network_ips;
				$other_ip = "Other IP";
				foreach(@addrs){
				    $possibleIp{$_} = $_;
				}
				$possibleIp{$other_ip} = "other";
				
                @ip_list = {
                    val => \$ip_choosed,
                    type => 'list',
					list => [$other_ip, sort(@addrs)],
                 };
            },
			name =>sub {
				N("Choose your router IP address from the list above or choose \"%s\" and enter the IP address manually:", $other_ip);
			},
			data =>\@ip_list,
            post => sub {
				if($possibleIp{$ip_choosed} eq "other") {
					return("manual_ip");
				}
				else{
					$router{ip} = $possibleIp{$ip_choosed};
					my $success = 1;
					if ($router{need_config}){
						return("get_auth_info") if $router{need_auth};
						$success = $configure_router->();
					}
					$success ? return("turnoff") : return("error_config");
				}
			},
		},

		manual_ip => {
                       name => N("Enter the router IP address below:"),
			data => [{ label => N("Router IP address: "), val => \$ip_entered }],
			complete => sub {
				if (!is_ip($ip_entered)) {
					$in->ask_warn(N("Error"), N("IP address should be in the format 1.2.3.4"));
					return 1;
				}
			},
			post => sub {
				$router{ip} = $ip_entered;
				my $success = 1;
				if ($router{need_config}){
					return("get_auth_info") if $router{need_auth};
					my $success = $configure_router->();
				}
				$success ? return("turnoff") : return("error_config");
			}
		},

		error_config => {
			name => sub {
                               N("Error during network configuration of the router.") . "\n" .
                               N("This wizard was not able to configure the router.") . "\n\n" .
				N("Reason: %s", $router{errstr});
			},
			end => 1,
		},

		get_auth_info => {
			name => sub {
				N("Please enter the login and password to access the router:");
			},
			data => sub {
				[ { label => N("Login: "), val => \$router{login} },
				{ label => N("Password: "),  val => \$router{passwd}, hidden => 1 }, ],
			},
			post => sub {
				my $success = $configure_router->();
				$success ? return("turnoff") : return("error_config");
			},
		},

		turnoff => {
			name => sub {
                               N("Please turn your router OFF by unplugging your router's power chord.") . "\n\n" .
                               if_(0, N("This is necessary to upload the firmware.") . "\n\n") .
                               N("Once your router is turned OFF, click on \"Next\".");
			},
			post => sub {
				return("turnon");
			}
		},

		turnon => {
			name => sub {
				N("Please press \"Next\" to begin the firmware upload procedure.") . "\n\n" .
				N("You will be asked to turn your router back on by plugging its power chord.")
			},
			post => sub {
				my $upload = $upload_firmware->();
				my $test = $upload && $test_router->();

				#- restore shorewall to previous state
				services::restart("shorewall") if $shorewall_enabled;
				#- restart interface in classical mode
				run_program::run("dhclient", "-r", $router{intf});
				run_program::run("ifup", $router{intf}, "daemon");

				return("error_upload") if(!$upload);
				return("error_testing") if(!$test);

				return("end");
			},
		},

		error_upload => {
			name => sub {
                               N("Error during firmware uploading process.") . "\n" .
                               N("This wizard was not able to upload the new firmware to the router.") . "\n\n" .
				N("Reason: %s", $router{errstr});
			},
			end => 1,
		},

		error_testing => {
			name => sub {
                               N("Error during the firmware installation process.") . "\n" .
                               N("This wizard received a time out during the firmware installation.") . "\n" .
                               N("The new firmware may still be in the process of being upgraded. Please wait.") . "\n" .
                               N("If that is NOT the case, please try launching the DrakFON application again.");
			},
			end => 1,
		},

		end => {
			name => sub {
                               N("Firmware installation is complete.") . "\n\n" .
                               N("Congratulations! You have successfully installed the FON firmware on your wireless router. You can now join the FON Community and connect for free to any FON WiFi Access Point in the world. Go to http://www.fon.com to sign up and become a FONero!");
			},
			no_back => 1,
			end => 1,
		},
	}
};

if ($in->isa('interactive::gtk')) {
    use Gtk2;
    Gtk2::Rc->parse_string(<<END);
style "FON-default" {
  bg[NORMAL] = "#ffffff"
}
style "FON-button" {
  bg[NORMAL] = "#f49b10"
  bg[PRELIGHT] = "#fcb43b"
  bg[ACTIVE] = "#fbae50"
  fg[NORMAL] = "#000000"
}
class "GtkWidget" style "FON-default"
class "GtkButton" style "FON-button"
END
}

require wizards;
if ($is_2006) {
    wizards->new->process($wiz, $in);
} else {
    my $wizard = wizards->new($wiz);
    $wizard->process($in);
}
$in->exit;

