#!/usr/bin/perl
# Bittorrent checker
#
# Copyright (C) 2004-2005 Mandriva Daouda Lo <daouda At mandriva dOt com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
###############################################################################

use strict;
use lib qw(/usr/lib/libDrakX);
use standalone;
use common;
use any;

BEGIN { unshift @::textdomains, 'drakbt' };

use ugtk2 qw(:all);
use interactive;
use Gtk2::Pango;
use network::bittorrent;
use SOAP::Lite;

sub usage() {
    print STDERR N("drakbt 0.8.1
Copyright (C) 2004-2005 Mandriva.
This is free software and may be redistributed under the terms of the GNU GPL.

Usage: 
") . N(" --help                               - display this help     
") . N(" --url <http|ftp://link.torrent>      - preload the torrent web link
") . N(" --file <file://file.torrent>         - preload the torrent local file specified
");
    exit(0);
}

if ("@ARGV" =~ /(-h|--help)$/) { usage() }
my ($file_arg) = "@ARGV" =~ /--file (.*)/;
my ($url_arg) = "@ARGV" =~ /--url (.*)/; 

($file_arg) = "@ARGV" =~ m!([/.\w].*)! if (!$file_arg);
($url_arg) = "@ARGV" =~ /((http|ftp).*)/ if (!$url_arg);

#print "URL = $url_arg \nFILE = $file_arg \n";

my $server = 'qa.mandriva.com';
my $public_link = 'http://' . $server . '/torrent/';
my $club_link = 'https://club.mandriva.com/xwiki/bin/view/Downloads/';

my $in = interactive->vnew('');

sub get_in_outbound_IP() {
    my $link = "http://checkip.dyndns.org/";
    my $ip = network::bittorrent::get_URL($link);
    $ip->content =~ m!<body>Current IP Address:\s(.*)</body>! and return $1;
}


my $window = ugtk2->new(N("Mandriva Linux BitTorrent Checker"), center => 1);
gtkset_size_request($window->{rwindow}, 580, 420);
$window->{window}->signal_connect("delete_event", sub { ugtk2->exit(0) });

my ($menu, $_factory) = create_factory_menu($::isEmbedded ? $::Plug : $window->{window},
                                           ([ N("/_File"), undef, undef, undef, '<Branch>' ],
                                            [ N("/_File") . N("/_Quit"), N("<control>Q"), \&quit_global, undef, ],
					    [ N("/_Services") . N("/_Mandriva Linux products"), undef, sub { load_link("http://store.mandriva.com") }, undef ],
                                            [ N("/_Help"), undef, undef, undef, '<Branch>' ],
                                            [ N("/_Help") . N("/_Help"), undef, sub { help_system() }, undef ],
                                            [ N("/_Help") . N("/_Report Bug"), undef, sub { load_link("http://qa.mandriva.com") }, undef ],
                                            [ N("/_Help") . N("/_Club Subscription"), undef, sub { load_link("http://www.mandrivaclub.com") }, undef ]
                                           )
					   );
my ($file_or_url, $fake_rad, $public_rad, $club_rad, $club_list, $login, $password, $label_file, $get_info);
my $is_auth = 0;
$fake_rad = Gtk2::RadioButton->new_with_label(undef, "");
$public_rad = Gtk2::RadioButton->new_with_label($fake_rad, N("Public torrent files"));
$club_rad = Gtk2::RadioButton->new_with_label_from_widget($public_rad, N("Private torrent files (Mandriva Club)"));
$file_or_url = Gtk2::Combo->new;

my @public_torrent = get_mdk_torrent($public_link);
my @club_torrent;

my $textw =  Gtk2::TextView->new;
 
gtkadd($window->{window},
       gtkpack_(Gtk2::VBox->new(0, 0),
		0, $menu,
		0, Gtk2::HSeparator->new,
		0, gtkadd(Gtk2::Frame->new(N("Torrents Access Type")),
			  gtkpack(Gtk2::VBox->new(0, 0),
				  gtksignal_connect($public_rad, clicked => sub { set_pds($file_or_url, N("Choose your torrent..."), @public_torrent) }),
				  gtksignal_connect($club_rad, clicked => sub { $club_rad->get_active and authenticate_club_member() }),
				 ),
			 ),
		0, gtkadd(Gtk2::Frame->new(N("File or URL Selection")), 
			  gtkpack(Gtk2::VBox->new(0, 0),
				  create_packtable({ homogeneous => 0, col_spacings => 0, row_spacings =>0 },
						   [ "",
						     0, gtkpack_(Gtk2::HBox->new(0, 5),
								 1, $file_or_url,
								 0, gtksignal_connect(Gtk2::Button->new(N("Browse")), 
								      clicked => sub {  
									  my $dlg = Gtk2::FileChooserDialog->new(N("Torrent chooser"), $window->{real_window}, 'open', 'gtk-cancel' => 'cancel', 'gtk-ok' => 'ok');
									  if ($dlg->run eq 'ok') {
									      $file_or_url->entry->set_text($dlg->get_filename);
									  }
									  $dlg->destroy;
								      }
										     )) ],
						  ))),
		1, gtkadd(Gtk2::Frame->new(N("Status")),
			  gtkpack_(Gtk2::VBox->new(0, 0),
				   0, gtkpack_(Gtk2::HBox->new(0, 5),
					       0, gtksignal_connect($get_info = Gtk2::Button->new(N("Torrent information")), 
						    clicked => sub {
							my $w = $in->wait_message(N("Please Wait"), N("Checking %s", $file_or_url->entry->get_text));
							eval { display_torrent_status($file_or_url->entry->get_text) };
							undef $w;
							$@ and gtk_msg_(N("Error"), N("File or URL not found: %s", $@));
						    }),
					       1, $label_file = Gtk2::Label->new('')
					      ),
				   1, create_scrolled_window(gtktext_insert($textw, "", wrap_mode => 'none')),
				  )),
		0, Gtk2::HSeparator->new,
		0, gtkpack_(Gtk2::HBox->new(0,0),
			    0, gtksignal_connect(Gtk2::Button->new(N("Help")), clicked => sub { help_system() }),
			    1, Gtk2::Label->new(""),
			    0, gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => sub { quit_global() }),
			    0, gtksignal_connect(Gtk2::Button->new(N("Download")), clicked => sub {
						     launch_bt($file_or_url->entry->get_text);
						 }
						))));

my $ip = get_in_outbound_IP();
$get_info->set_sensitive(0);
$file_or_url->entry->signal_connect(changed => sub { my $input = $file_or_url->entry->get_text; 
						     $label_file->set_text($input);
						     $textw->get_buffer->set_text('');
						     if ($input eq '') { $get_info->set_sensitive(0) } else { $get_info->set_sensitive(1)  }
						 });
if (defined $url_arg || defined $file_arg) { 
    $file_or_url->entry->set_text($url_arg || $file_arg);
    eval { display_torrent_status($file_or_url->entry->get_text) };
    $@ and gtk_msg_(N("Error"), N("File or URL not found: %s", $@), scroll => 1);
}

$window->{rwindow}->show_all;

$window->main;
ugtk2->exit(0);

sub quit_global() {
    Gtk2->main_quit;
}

sub help_system() { my $help_array = build_help(); gtk_msg_(N("Help"), $help_array , scroll => 1) }

sub build_help() {
    my $color = { 'foreground' => 'royalblue3', 'weight' => Gtk2::Pango->PANGO_WEIGHT_BOLD };
    [ [ N("Drakbt Help") . "\n", $color ],
      [ "\n" . N("drakbt reports status information for a given torrent file or URL. It can connect automagically to Mandriva websites to grab and display available torrents. You should provide login and password if you want to connect to club member restricted torrents. After all checks are done, you can trigger the download process from drakbt.") ],
      [ "\n\n" . N(" Information displayed are:"), $color ],
      [ "\n- " . N("current number of complete copies (seeds)") ],
      [ "\n- " . N("incomplete copies (leeches) currently active") ],
      [ "\n- " . N("Bittorrent port reachability") ],
      [ "\n- " . N("Hash info ....") ]
    ];
}

sub prepare_link {
    my $ent = shift;
    my $status = {};
    #=> Get a torrent
    #https://www.mandrivaclub.com/club_RemoteAction.php?log=Ayo&pass=xxxxxx&action=get&torrent=gfdsgsdgs (deprecated)
    #https://club.mandriva.com/xwiki/bin/view/Downloads/GetTorrent?xpage=plain&login=foo.bar@mandriva.com&password=xxx&file=snafu.torrent 
    # my $basename = $ent;
    my $l; my $is_club_active = $club_rad->get_active;
    if (-e $ent) { $status->{rlink} = $ent; $status->{list} = [] } 
    elsif ($login && $is_club_active) {	
	$status->{list} = \@club_torrent; 
	$l = $club_link . 'GetTorrent?xpage=plain' . '&login=' . $login . '&password=' . $password . '&action=get' . '&file=' . $ent;
	#$res = network::bittorrent::get_URL($club_link . '?log='. $login . '&pass=' . $password . '&action=get' . '&torrent=' . $ent);
	#if ($res->is_success) { $l = $res->content ; } else { gtk_msg_('drakbt', "Unable to connect to club torrents") }
    } else { $status->{list} = \@public_torrent; $l = $public_link }
    $status->{rlink} or $status->{rlink} = $is_club_active ? $l : $l . "/$ent";
    $status;
}

sub display_torrent_status {
    my $ent = shift;
    my $torrent_properties;
    my $basename = $ent; 
    my $status = prepare_link($ent);
    $status->{rlink} or return "$ent cannot not be parsed, please check the link or file";
    eval { $torrent_properties = network::bittorrent::process_global_file_or_url($status->{rlink}) };
    $@ and gtk_msg_(N("Error"), N("Could not parse torrent file: %s", $@), scroll => 1);
    my $color = {};
    foreach my $l (['first', 'red'], ['second', 'royalblue3']) { 
	$color->{$l->[0]} = { 'foreground' => $l->[1], 'weight' => Gtk2::Pango->PANGO_WEIGHT_BOLD };
    }
    each_index { $status->{fs}[$::i] = [ $_->{name}, $_->{size} ] } @{$torrent_properties->{files}};
    my ($seeds, $leeches, $_error) = get_seeds_leeches($torrent_properties);
    my $port_access = nat_check();
    gtktext_insert($textw, [ [ N("Name: "), $color->{first} ], [ "$basename\n" ],
			     [ "\n" . N("Outbound IP: "), $color->{first} ], [ $ip . "\n" ], 
			     [ N("BitTorrent port access: "), $color->{first} ], [ $port_access . "\n" ],
 			     [ "\n" . N("Tracker information") . "\n\n", $color->{second} ],
			     if_(!$torrent_properties->{error},
				 [ N("Full copies: "), $color->{first} ], [ N("%s seeds", $seeds) . "\n" ],
				 [ N("Partial copies: "), $color->{first} ], [ N("%s leeches", $leeches) . "\n" ]),
			     [ "\n" . N("Torrent information") . "\n\n", $color->{second} ],
			     [ N("Announce: "), $color->{first} ], [ $torrent_properties->{announce} . "\n" ],
			     [ N("Hash: "), $color->{first} ], [ $torrent_properties->{hash} . "\n" ],
			     [ N("Total size: "), $color->{first} ], [ N("%s Bytes", $torrent_properties->{total_size}) . "\n" ],
			     [ sprintf("%15s   %s\n", "Bytes", N("Files")), $color->{first} ], 
		     map { [ sprintf("%15s   %s\n", commify($_->[1]), $_->[0]) ]  } @{$status->{fs}},
			   ],  wrap_mode => 'none');
}

sub nat_check() {
    my $ext_ip = get_in_outbound_IP();
    my $s = SOAP::Lite
      -> uri('http://qa.mandriva.com/Natcheck')
	-> proxy('http://qa.mandriva.com/cgi-bin/btserver.cgi')
	  -> check_btports($ext_ip);
    my $res = $s->result;
    $res;
}

sub launch_bt {
    my $torrent = shift;
    my $status = prepare_link($torrent);
    my $rl = $status->{rlink};
    my $raw_file = $rl;
    my $r = get_release();
    if ($rl =~ m!^(:?https?|ftp)://!) {
	print "\nrl(http) = $rl\n";
	($raw_file) = $rl =~ m!.*(?:=|/)(.*torrent)$!;
	$raw_file = $ENV{HOME} . '/' . $raw_file;
	my $cmd = $r <= 10.2 ? "/usr/bin/wget \'$rl\' -O $raw_file" : "/usr/bin/wget --no-check-certificate \'$rl\' -O $raw_file";
	system $cmd;
    }
    #    print "\nraw file = $raw_file\n";
    if ($r == 10.1) {
	system("/usr/bin/btdownloadgui.py $raw_file &");
    } elsif ($r == 10.2) {
	system("/usr/bin/btdownloadgui.py $raw_file --pause 0 &");
    } else { 
	system("/usr/bin/bittorrent $raw_file --no_pause &");
    }
}

sub get_seeds_leeches {
    my $result = shift;
    my ($tracker_status, $error_reason) = network::bittorrent::retrieve_tracker_info($result->{announce});
    if (!defined $tracker_status) {
	return undef, undef, $error_reason;
    }
    my $hash = $result->{hash};
    my %status = %$tracker_status;
    
    if (!exists $status{$hash}) {
	return undef, undef, N("The torrent may have been removed from the server.");      
    }
    my $seeds = $status{$hash}{complete};
    my $leeches = $status{$hash}{incomplete};
    return $seeds, $leeches, undef;
}

sub commify {
    my $input = shift;
    $input = reverse $input;
    $input =~ s|(\d\d\d)(?=\d)(?!\d*\.)|$1,|g;
    my $t = reverse $input;
    return $t;
}

sub authenticate_club_member() {
    my $w = ugtk2->new(N("Club Login Screen"), transient => $window->{real_window});
    #=> list les torrent
    #https://www.mandrivaclub.com/club_RemoteAction.php?log=Ayo&pass=mandrake&action=list
    my $login_wg = Gtk2::Entry->new; my $password_wg = Gtk2::Entry->new; $password_wg->set_visibility(0);
    my $remember_log_pass = Gtk2::CheckButton->new(N("Remember authentication for this session"));
    gtkadd($w->{window},
	   gtkpack(Gtk2::VBox->new(0, 0),
		   create_packtable({ homogeneous => 0, col_spacings => 0, row_spacings =>0 },
				    [ N("Login: "), $login_wg ],
				    [ N("Password: "), $password_wg ],
				    [ "", $remember_log_pass ]
				   ),
		   Gtk2::HSeparator->new,
		   gtkpack(
			   create_hbox(),
			   gtksignal_connect(
					     Gtk2::Button->new(N("Cancel")),
					     clicked => sub { 
						 set_pds($file_or_url, N("Choose your torrent..."), @public_torrent);
						 $public_rad->set_active(1);
						 Gtk2->main_quit;
					     }),
			   gtksignal_connect(
					     Gtk2::Button->new(N("Authenticate")),
					     clicked => sub {
						 ($login, $password) = ($login_wg->get_text, $password_wg->get_text);
						 my $ll = $club_link . 'ListTorrents?xpage=plain' . '&login=' . $login . '&password=' . $password;
						 my $result = network::bittorrent::get_URL($ll);
						 if ($result->is_success) {
						     my $ret = $result->content;
						     if ($ret =~ /torrent/) {
							 Gtk2->main_quit;
							 set_pds($file_or_url, N("Choose your torrent..."), split("\n", $ret));
							 $is_auth = $remember_log_pass->get_active;
						     } else {
							 gtk_msg_(N("Error"), N("Authentication failed"), transient => $w->{real_window});
							 $password_wg->set_text(''); 
						     } 
						 } else { Gtk2->main_quit; gtk_msg_(N("Error"), N("Connection failed")) }
					     }),
			  )));
    if ($is_auth) { $_->[0]->set_text($_->[1]) foreach ([$login_wg, $login], [$password_wg, $password]) }
    if ($is_auth && $login && $password) {
	$_->[0]->set_text($_->[1]) foreach ([$login_wg, $login], [$password_wg, $password]);
	$remember_log_pass->set_active(1);
    }
    $w->main;
}

sub set_pds {
    my $widget = shift;
    $widget->set_popdown_strings(@_);
}
sub get_mdk_torrent {
    my $link = shift;
    my @torrent;
    is_network() and @torrent = network::bittorrent::get_torrent($link);
    @torrent;
}

sub is_network() {
    my $is_network = gethostbyname($server) ? 1 : 0;
    $is_network;
}

sub load_link {
    my $link = shift;
    system "/usr/bin/www-browser $link &";
}

sub get_release() {
    my $release_file = find { -f $_ } '/etc/mandriva-release', '/etc/mandrakelinux-release', '/etc/mandrake-release', '/etc/redhat-release';
    my ($release) = cat_($release_file) =~ /release\s+(\S+)/;
    ($release)
}

sub gtk_msg_ { gtk_msg(@_, if_(exists $window->{rwindow}, transient => $window->{real_window})) }

#copied from rpmdrake
sub gtk_msg {
    my ($title, $contents, %options) = @_;
    my $d = ugtk2->new($title, if_(exists $options{transient}, transient => $options{transient}));
    $d->{rwindow}->set_position($options{transient} ? 'center_on_parent' : 'center_always') if !$::isEmbedded;
    $contents = formatAlaTeX($contents) unless $options{scroll};
    gtkadd(
      $d->{window},
	 gtkpack_(Gtk2::VBox->new,
		   1, ($options{scroll} ? gtkadd(
		       gtkset_shadow_type(Gtk2::Frame->new, 'in'),
		       gtkset_size_request(
		       create_scrolled_window(gtktext_insert(Gtk2::TextView->new, $contents)),
		       420, 260
	 	  )
                ) : gtkpack(create_hbox(), Gtk2::WrappedLabel->new($contents))
            ),      
            0, gtkpack(create_hbox(),
                (ref($options{yesno}) eq 'ARRAY' ? map {
                        my $label = $_;
                        gtksignal_connect(
                            Gtk2::Button->new($label),
                            clicked => sub { $d->{retval} = $label; Gtk2->main_quit }
			);
		    } @{$options{yesno}}
                    : (
                        $options{yesno} ? (
                            gtksignal_connect(
                                Gtk2::Button->new($options{text}{no} || N("No")),
                                clicked => sub { $d->{retval} = 0; Gtk2->main_quit }
                            ),                         
                            gtksignal_connect(Gtk2::Button->new($options{text}{yes} || N("Yes")),
                                clicked => sub { $d->{retval} = 1; Gtk2->main_quit }),
                        )                          
                        : gtksignal_connect(
                            Gtk2::Button->new(N("Ok")),
				clicked => sub { Gtk2->main_quit }
		       )
                    )
                )
            )
          )
	  );
    $d->main;
}
