diff options
Diffstat (limited to 'scripts/poison.pl')
-rw-r--r-- | scripts/poison.pl | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/scripts/poison.pl b/scripts/poison.pl new file mode 100644 index 0000000..f04da33 --- /dev/null +++ b/scripts/poison.pl @@ -0,0 +1,341 @@ +# by Stefan 'tommie' Tomanek +# +use strict; + +use vars qw($VERSION %IRSSI); +$VERSION = "2003020801"; +%IRSSI = ( + authors => "Stefan 'tommie' Tomanek", + contact => "stefan\@pico.ruhr.de", + name => "Poison", + description => "equips Irssi with an interface to giFT", + license => "GPLv2", + changed => "$VERSION", + modules => "IO::Socket::INET Data::Dumper", + commands => "poison" +); + +use vars qw($forked %ids); +use IO::Socket::INET; +use Data::Dumper; +use Irssi; +use POSIX; + +sub show_help() { + my $help = $IRSSI{name}." $VERSION +/poison + List current downloads +/poison search <query> + Search for files on the network +"; + my $text = ''; + foreach (split(/\n/, $help)) { + $_ =~ s/^\/(.*)$/%9\/$1%9/; + $text .= $_."\n"; + } + print CLIENTCRAP &draw_box($IRSSI{name}, $text, "help", 1); +} + +sub giftconnect { + my $host = Irssi::settings_get_str('poison_host'); + my $port = Irssi::settings_get_int('poison_port'); + my $sock = IO::Socket::INET->new(PeerAddr => $host, + PeerPort => $port, + Proto => 'tcp'); + return $sock; +} + +sub draw_box ($$$$) { my ($title, $text, $footer, $colour) = @_; + my $box = ''; + $box .= '%R,--[%n%9%U'.$title.'%U%9%R]%n'."\n"; + foreach (split(/\n/, $text)) { + $box .= '%R|%n '.$_."\n"; + } + $box .= '%R`--<%n'.$footer.'%R>->%n'; + unless ($colour) { + $box =~ s/%(.)/$1 eq '%'?$1:''/eg; + } + return $box; +} + +sub round ($$) { + return $_[0] unless Irssi::settings_get_bool('poison_round_filesize'); + if ($_[1] > 100000) { + return sprintf "%.2fMB", $_[0]/1024/1024; + } else { + return sprintf "%.2fKB", $_[0]/1024; + } +} + +sub array2table { + my (@array) = @_; + my @width; + foreach my $line (@array) { + for (0..scalar(@$line)-1) { + my $l = $line->[$_]; + $l =~ s/%[^%]//g; + $l =~ s/%%/%/g; + $width[$_] = length($l) if $width[$_]<length($l); + } + } + my $text; + foreach my $line (@array) { + for (0..scalar(@$line)-1) { + my $l = $line->[$_]; + $text .= $line->[$_]; + $l =~ s/%[^%]//g; + $l =~ s/%%/%/g; + $text .= " "x($width[$_]-length($l)+1) unless ($_ == scalar(@$line)-1); + } + $text .= "\n"; + } + return $text; +} + +sub bg_do ($$) { + my ($id, $sub) = @_; + my ($rh, $wh); + pipe($rh, $wh); + return if $forked; + $forked = 1; + my $pid = fork(); + if ($pid > 0) { + close $wh; + Irssi::pidwait_add($pid); + my $pipetag; + my @args = ($rh, \$pipetag); $pipetag = Irssi::input_add(fileno($rh), INPUT_READ, \&pipe_input, \@args); + } else { + eval { + my $result; + $result->{$id} = &$sub(); + my $dumper = Data::Dumper->new([$result]); + $dumper->Purity(1)->Deepcopy(1); + my $data = $dumper->Dump; + print($wh $data); + close($wh); + }; + POSIX::_exit(1); + } +} + +sub pipe_input ($) { + my ($rh, $pipetag) = @{$_[0]}; + my $text; + $text .= $_ foreach (<$rh>); + close($rh); + Irssi::input_remove($$pipetag); + $forked = 0; + return unless($text); + no strict; + my $result = eval "$text"; + return unless ref $result; + print_results($result->{search}) if defined $result->{search}; + print CLIENTCRAP '%R>>%n Added '.$result->{sources}.' source(s) for download' if defined $result->{sources}; +} + +sub search_file ($) { + my ($query) = @_; + my $sock = giftconnect(); + return unless $sock; + $sock->print("SEARCH query(".$query.");\n"); + my %results; + my %item; + my $meta = 0; + while ($_ = $sock->getline()) { + if ((not $meta) && / *(.*?)\((.*?)\)[^;]/) { + my ($key, $value) = ($1, $2); + $value =~ s/\\(.)/$1/g; + $item{$key} = $value; + } elsif (/META/) { + $meta = 1; + } elsif (/ITEM;/) { + $sock->close(); + last; + } elsif (/;/) { + $meta = 0; + my %foo = %item; + %item = (); + $results{$foo{hash}} = \%foo; + } + } + return \%results; +} + +sub get_file ($) { + my ($id) = @_; + return unless $ids{$id}; + my $data = $ids{$id}; + add_source($data); + bg_do('sources', sub { retrieve_sources($data->{hash}) } ); +} + +sub retrieve_sources ($) { + my ($hash) = @_; + my %sources; + foreach (@{ find_sources($hash) }) { + add_source($_); + $sources{$_->{user}} = 1; + } + return scalar keys %sources; +} + +sub add_source (\%) { + my ($data) = @_; + my $sock = giftconnect(); + return unless $sock; + my @bar = split('/', $data->{url}); + my $file = $bar[-1]; + + my $line = "ADDSOURCE "; + $line .= "user(".$data->{user}.") "; + $line .= "hash(".$data->{hash}.") "; + $line .= "size(".$data->{size}.") "; + $line .= "url(".$data->{url}.") "; + $line .= "save(".$file.");"; + $sock->print($line."\n"); + $sock->close(); +} + +sub find_sources ($) { + my ($hash) = @_; + my $sock = giftconnect(); + return unless $sock; + $sock->print("LOCATE query(".$hash.");\n"); + my %item; + my @sources; + my $meta = 0; + while ($_ = $sock->getline()) { + if ((not $meta) && (/ *(.*?)\((.*?)\)[^;]/)) { + my ($key, $value) = ($1, $2); + #print $key." => ".$value; + $value =~ s/\\(.)/$1/g; + $item{$key} = $value; + } elsif (/META/) { + $meta = 1; + } elsif (/ITEM;/) { + $sock->close(); + last; + } elsif (/;/) { + $meta = 0; + my %foo = %item; + %item = (); + push @sources, \%foo; + } + } + return \@sources; +} + +sub get_downloads { + my %downloads; + my $sock = giftconnect(); + return unless $sock; + $sock->print("ATTACH client(".$IRSSI{name}.") version(".$VERSION."); DETACH;"); + my %downloads; + my ($add, $source) = (0,0); + my %item; + while ($_ = $sock->getline()) { + if (/^DOWNLOAD_ADD\((\d+)\)/) { + $add = 1; + $item{sessionid} = $1; + } elsif (/SOURCE/) { + $source = 1; + } elsif (/};/) { + $source = 0; + $add = 0; + my %foo = %item; + $downloads{$foo{file}} = \%foo; + } else { + if (($add && not $source) && /^ (.*?)\((.*?)\)$/) { + my ($key, $value) = ($1, $2); + $value =~ s/\\(.)/$1/g; + $item{$key} = $value; + } + } + } + return \%downloads; +} + +sub print_results ($) { + my ($results) = @_; + my @array; + %ids = (); + my $i = 1; + foreach (sort {uc($a) cmp uc($b)} keys %$results) { + my @bar = split('/', $results->{$_}{url}); + my $file = $bar[-1]; + $file =~ s/%20/ /g; + $file =~ s/%/%%/g; + my @line; + push @line, "%9".$i."%9"; + push @line, "%9".$file."%9"; + push @line, $results->{$_}{size}; + push @line, $results->{$_}{availability}; + push @array, \@line; + $ids{$i} = $results->{$_}; + $i++; + } + my $text = array2table(@array); + print CLIENTCRAP draw_box("Poison", $text, "Results", 1) if $text; +} + +sub print_downloads ($) { + my ($downloads) = @_; + my $text; + foreach (sort {uc($a) cmp uc($b)} keys %$downloads) { + if ($downloads->{$_}{state} eq 'Active') { + $text .= '%bo%n'; + } elsif ($downloads->{$_}{state} eq 'Paused') { + $text .= '%yo%n'; + } + my $percent = $downloads->{$_}{size} > 0 ? ($downloads->{$_}{transmit} / $downloads->{$_}{size}) * 100 : 0; + my $file = $_; + $file =~ s/%20/ /g; + $file =~ s/%/%%/g; + $text .= " %9".$file."%9"; + $text .= "\n"; + $text .= ' '; + $text .= round($downloads->{$_}{transmit}, $downloads->{$_}{size}).'/'; + $text .= round($downloads->{$_}{size}, $downloads->{$_}{size}); + $percent =~ s/(\..).*/$1/g; + $text .= " (".$percent."%%)"; + $text .= "\n" + } + print CLIENTCRAP draw_box("Poison", $text, "Downloads", 1); +} + + + +sub cmd_poison ($$$) { + my ($args, $server, $witem) = @_; + my @args = split(/ /, $args); + if (@args == 0) { + print_downloads(get_downloads()); + } elsif ($args[0] eq 'search') { + shift @args; + if ($forked) { + print CLIENTCRAP '%R>>%n Already searching...'; + } else { + print CLIENTCRAP '%R>>%n Search in progress...'; + } + bg_do 'search', sub { search_file(join(' ', @args)) }; + #print_results search_file(join(' ', @args)); + } elsif ($args[0] eq 'get' && $args[1]) { + get_file($args[1]); + } elsif ($args[0] eq 'help') { + show_help(); + } +} + +Irssi::settings_add_str('poison', 'poison_host', 'localhost'); +Irssi::settings_add_int('poison', 'poison_port', 1213); +Irssi::settings_add_bool('poison', 'poison_round_filesize', 1); + +Irssi::command_bind('poison', \&cmd_poison); + +foreach my $cmd ('help', 'search', 'get') { + Irssi::command_bind('poison '.$cmd => sub { + cmd_poison("$cmd ".$_[0], $_[1], $_[2]); }); +} + +print CLIENTCRAP '%B>>%n '.$IRSSI{name}.' '.$VERSION.' loaded, /poison help'; + |