diff options
| author | obfuscoder | 2014-10-16 14:47:21 +0200 | 
|---|---|---|
| committer | Obfuscoder | 2015-05-03 21:32:51 +0200 | 
| commit | 4c4175129851b1dc0a7857cac2bec935388c3140 (patch) | |
| tree | 885f7671d307a21c7db698d94624ca59fbac1fa3 /scripts/xdccget.pl | |
| parent | 0a0ba125acd8e929dfcd4809f900ce251b5ddc50 (diff) | |
| download | scripts.irssi.org-4c4175129851b1dc0a7857cac2bec935388c3140.tar.bz2 | |
Update xdccget.pl with queue management and search
Update xdccget.pl with some queue management and search capabilities. (pausing, retries, max parallel downloads).
Rework of help output.
Diffstat (limited to 'scripts/xdccget.pl')
| -rw-r--r-- | scripts/xdccget.pl | 752 | 
1 files changed, 526 insertions, 226 deletions
| diff --git a/scripts/xdccget.pl b/scripts/xdccget.pl index 9f16bda..b6d396c 100644 --- a/scripts/xdccget.pl +++ b/scripts/xdccget.pl @@ -1,70 +1,157 @@ -# -# by Stefan "tommie" Tomanek <stefan@kann-nix.org> -# -# History: -# -# 26.02.2002 -# *first release, report bugs :) -# -# 01.03.2002 -# *CHanged to GPL -# -# 08.03.200 -# *some bugfixes -# -# 13.04.2002 -# *major improvements -# *cosmetic changes -#  -# 14.04.2002 -# *internal redesign -# *feature enhancements -# -# 17.04.2002 -# * improved queuing code -# * changed to $server->{tag} -# * improved communication with server -# -# 21.04.2002 -# *improved ETA listing -# -# 27.04.2002 -# *handling of gone bots added -# -# 28.04.2002 -# *fixed handling of servers that are not in an ircnet +# Original version by Stefan "tommie" Tomanek <stefan@kann-nix.org> +# Enhanced with max. download limits, retries, pausing, searching and other neat stuff by Obfuscoder (obfuscoder@obfusco.de) +# You can find the script on GitHub: https://github.com/obfuscoder/irssi_scripts +# Please report bugs to https://github.com/obfuscoder/irssi_scripts/issues  use strict; -#use warnings; +use warnings;  use vars qw($VERSION %IRSSI); -$VERSION = "20040509"; +$VERSION = "20141016";  %IRSSI = ( -    authors     => "Stefan 'tommie' Tomanek", -    contact     => "stefan\@pico.ruhr.de", -    name        => "XDCCget", -    description => "advances downloading from XDCC bots", +    authors     => "Stefan 'tommie' Tomanek, Obfuscoder", +    contact     => "obfuscoder\@obfusco.de", +    name        => "xdccget", +    description => "enhanced downloading, queing, searching from XDCC bots",      license     => "GPLv2",      changed     => "$VERSION", -    commands	=> "xdccget" +    commands    => "xdccget"  );  use Irssi 20020324; -use vars qw(@queue $timer $debug %lists); +use vars qw(@queue @completed %offers $timer $debug %lists); + +Irssi::settings_add_str($IRSSI{'name'}, 'xdccget_config_path', "$ENV{HOME}/.irssi"); +Irssi::settings_add_int($IRSSI{'name'}, 'xdccget_max_downloads', 2); +Irssi::settings_add_int($IRSSI{'name'}, 'xdccget_retry_time', 5);  $debug=0; +my $config_path = Irssi::settings_get_str('xdccget_config_path'); +my $max_downloads = Irssi::settings_get_int('xdccget_max_downloads'); +my $queue_file = "$config_path/xdccget.queue"; +sub saveQueue { +    if (!open (QUEUE, q{>}, $queue_file)) { +        print CLIENTCRAP "XDCCGET - ERROR! Cannot open queue file for saving at $queue_file. $!"; +        return; +    } +    foreach (@queue) { +        print QUEUE $_->{net}."\t".$_->{nick}."\t".$_->{pack}."\t".$_->{filename}."\t".$_->{xdcc}."\n"; +    } +    if (!close QUEUE) { +        print CLIENTCRAP "XDCCGET - ERROR! Could not close queue file after saving at $queue_file. $!"; +    } +} + +sub loadQueue { +    @queue = (); +    if (!open (QUEUE, q{<}, $queue_file)) { +        print CLIENTCRAP "XDCCGET - Warning: Could open queue file for loading from $queue_file: $!"; +        return; +    } +    while (<QUEUE>) { +        chomp; +        my ($net, $nick, $pack, $desc, $xdcc) = split (/\t/); +        if ($xdcc eq "") { +            $xdcc = "xdcc"; +        } +        my %transfer = ( +            'nick'     => $nick, +            'pack'     => $pack, +            'status'   => 'waiting', +            'net'      => $net, +            'pos'      => 0, +            'try'      => 0, +            'etr'      => 0, +            'timer'    => undef, +            'xdcc'     => $xdcc, +            'filename' => $desc, +        ); +        push @queue, \%transfer; +    } +    if (!close QUEUE) { +        print CLIENTCRAP "XDCCGET - ERROR! Could not close queue file after loading at $queue_file. $!"; +    } +} + +sub debugFunc { +    return unless ($debug); +    my $funcname = shift (@_); +    print CLIENTCRAP "XDCC-DEBUG - $funcname (". join(",",@_).")\n"; +}  sub show_help() {      my $help="XDCCget $VERSION -/xdccget queue Nickname <number> <number>... -    Queue the specified packs of the server 'Nickname' -/xdccget list -    List the download queue -/xdccget cancel <number> -    Remove pack <number> from the local queue -/xdccget help -    Display this help +  Commands: + +  /xdccget queue <nickname> <number> [[-xdcc=<method>] <description>] +      Queue the specified pack of the currently selected server and 'Nickname'. +      The description will be shown in the queue. +      With -xdcc=<method> it is possible to specify the method to be used in the request. +      Default is 'xdcc' as in /msg <nickname> xdcc send <number> + +  /xdccget stat +  /xdccget +  /xdccget -l +      List the download queue + +  /xdccget list <nickname> +      Request the XDCC list of <nickname> + +  /xdccget cancel <number> +      Cancel the download if currently downloading, request to being removed from queue +      if queued by the XDCC offerer, or remove pack <number> from the download queue + +  /xdccget pause <number> +      Pause pack <number> within the local queue. Resume with reset + +  /xdccget reset <number> +      Reset pack <number> so that it is unpaused and -- +      if download slots are still available -- triggers a download request + +  /xdccget offers [<options>] <description search pattern> +      Display all the announced offers matching the given pattern or options. +      The announcements are continuously monitored by this script throughout all joined channels. + +      Options: +      One or more of the following options can be used. Each option must start with a '-': + +      -server=<server pattern>     only show offers announced by bots on servers matching this pattern +      -channel=<channel pattern>   only show offers announced by bots on channels matching this pattern +      -nick=<nick pattern>         only show offers announced by bots with nicks matching this pattern + +      Examples: +         /xdccget offers iron.*bluray +         /xdccget offers -nick=bot iron.*bluray +         /xdccget offers -channel=beast-xdcc iron.*bluray + +      Regular expressions are used to match each of the parameters. + +  /xdccget help +      Display this help + +  You can also simply use /x instead of /xdccget ;-) + +  Configuration: + +  xdccget_config_path +      Path where this script is storing its files (queue and finished downloads). +      Default is '\$HOME/.irssi'. + +  xdccget_max_downloads +      Maximum number of parallel downloads. Default is 2. A download request which is queued +      by the XDCC offer bot does not count against the limit. The next item in the download queue +      is being requested as long as download slots are available. Also other downloads not controlled +      by this script do not count either. It is also possible to exceed this limit if a bot sends the +      previously requested and queued file while there are downloads running already.  + +  xdccget_retry_time +      Time in minutes between retries. Default is 5. Retries are necessary for full +      offer queues of bots, bots being/becoming offline, or not getting the requested download or any +      understandable message regarding the request. Please DO NOT set this value to less than 300 +      (5 minutes) or risk being banned from the channels for spamming the bots. + +  Please report bugs to https://github.com/obfuscoder/irssi_scripts/issues  ";      my $text = '';      foreach (split(/\n/, $help)) { @@ -79,8 +166,12 @@ sub draw_box ($$$$) {      my $box = '';      my $exp_flags = Irssi::EXPAND_FLAG_IGNORE_EMPTY | Irssi::EXPAND_FLAG_IGNORE_REPLACES;      $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'; +    if (defined($text)) { +        foreach (split(/\n/, $text)) { +            $box .= '%R|%n '.$_."\n"; +        } +    } +    $box .= '%R`--<%n'.$footer.'%R>->%n';      $box =~ s/%.//g unless $colour;      return $box;  } @@ -88,178 +179,229 @@ sub draw_box ($$$$) {  sub contains {      my ($item, @list) = @_;      foreach (@list) { -	    ($item eq $_) && return 1; +        ($item eq $_) && return 1;      }      return 0;  }  sub event_message_irc_notice { +    debugFunc ("event_message_irc_notice", @_);      my ($server, $msg, $nick, $address, $target) = @_; +    my $i;      $_ = $msg; -    if ($queue[0] &&  $nick eq $queue[0]->{'nick'}) { -	if (/\*\*\* Closing Connection:/) { -	    print CLIENTCRAP "%R>>%n XDCC-Transfer closed"; -	    # Is it a canceled transger? -	    if ($queue[0]->{'status'} == 5) { -		$queue[0]->{'status'} = 4; -	    } else { -		# We should try again -		$queue[0]->{'status'} = 0; -	    } -	} elsif (/\*\*\* Transfer Completed/i) { -    	    print CLIENTCRAP "%R>>%n XDCC-Transfer completed"; -	    # Mark the transfer as completed -	    $queue[0]->{'status'} = 4; -	} elsif (/\*\*\* You already requested that pack/i) { -	    $queue[0]->{'status'} = 4; -	} elsif (/\*\*\* Sending You Pack/i || /\*\*\* Sending You Your Queued Pack|DCC Send .*? \(.*?\)/i) { -	    $queue[0]->{'status'} = 3; -	    print CLIENTCRAP "%R>>%n XDCC-Transfer starting"; -	} elsif (/\*\*\* All Slots Full, Added (|you to the main )queue in position ([0-9]*)/i) { -	    $queue[0]->{'pos'} = $2; -	    $queue[0]->{'etr'} = 0; -	    $queue[0]->{'status'} = 2; -	} elsif (/You have been queued for ([0-9]*?) hr ([0-9]*?) min, currently in main queue position ([0-9]*?) of ([0-9]*?)\.  Estimated remaining time is ([0-9]*?) hr ([0-9]*?) min or (less|more)\./i) { -	    $queue[0]->{'pos'} = $3; -	    $queue[0]->{'etr'} = time() + (($5*60)+$6)*60; -	    $queue[0]->{'status'} = 2; -	} elsif (/You have been queued for ([0-9]*?) hours ([0-9]*?) minutes, currently in main queue position ([0-9]*?) of ([0-9]*?)\./i) { -	    $queue[0]->{'pos'} = $3; -	    $queue[0]->{'status'} = 2; -	} elsif (/You have been queued for ([0-9]*?) minutes, currently in main queue position ([0-9]*?) of ([0-9]*?)\./) { -	    $queue[0]->{'status'} = 2; -	    # FIXME unite somehow with regexp above -	    $queue[0]->{'pos'} = $2; -	} elsif (/It has been placed in queue slot #(\d+), it will send when sends are available/) { -	    $queue[0]->{'pos'} = $1; -	    $queue[0]->{'status'} = 2; -	} elsif (/\*\*\* Invalid Pack Number/) { -	    $queue[0]->{'status'} = 4; -	} elsif (/\*\*\* The Owner Has Requested That No New Connections Are Made/) { -	    $queue[0]->{'status'} = 4; -	} elsif (/\*\*\* All Slots Full,(| Main) queue of size [0-9]* is Full, Try Again Later/i || /\*\*\* You can only have 1 transfer at a time/i) { -	    if (Irssi::settings_get_int('xdccget_retry_time') > 0) { -		my $retry = Irssi::settings_get_int('xdccget_retry_time')*1000; -		$queue[0]->{'status'} = 6; -		$queue[0]->{'timer'} = Irssi::timeout_add($retry, 'retry_transfer', undef); -		$queue[0]->{'etr'} = time()+$retry/1000; -	    } else { -		$queue[0]->{'status'} = 4; -	    } -	} elsif (/Removed you from the queue/) { -	    $queue[0]->{'status'} = 4; -	} else { Irssi::print($_) if ($debug); } -	 -	process_queue(); +    for ($i=0; $i<= $#queue; $i++) { +        if ($queue[$i] && lc($nick) eq lc($queue[$i]->{'nick'})) { +            if (/Closing Connection/) { +                print CLIENTCRAP "%R>>%n XDCC-Transfer closed"; +                # Is it a canceled transfer? +                if ($queue[$i]->{'status'} eq 'canceling') { +                    $queue[$i]->{'status'} = 'cancelled'; +                } elsif ($queue[$i]->{'status'} ne 'paused') { +                    # We should try again unless we paused the queue item +                    $queue[$i]->{'status'} = 'waiting'; +                } +            } elsif (/Transfer Completed/i) { +                print CLIENTCRAP "%R>>%n XDCC-Transfer completed"; +                # Mark the transfer as completed +                $queue[$i]->{'status'} = 'completed'; +            } elsif (/You already requested that pack/i) { +                $queue[$i]->{'status'} = 'transferring'; +            } elsif (/You already have that item queued/i) { +                $queue[$i]->{'status'} = 'queued'; +            } elsif (/Sending (?:You|u) (?:Your Queued )?Pack/i) { +                $queue[$i]->{'status'} = 'transferring'; +                print CLIENTCRAP "%R>>%n XDCC-Transfer starting"; +            } elsif (/All Slots Full, Added (|you to the main )queue in position ([0-9]*)/i) { +                $queue[$i]->{'pos'} = $2; +                $queue[$i]->{'etr'} = 0; +                $queue[$i]->{'status'} = 'queued'; +            } elsif (/You have been queued for ([0-9]*?) hr ([0-9]*?) min, currently in main queue position ([0-9]*?) of ([0-9]*?)\.  Estimated remaining time is ([0-9]*?) hr ([0-9]*?) min or (less|more)\./i) { +                $queue[$i]->{'pos'} = $3; +                $queue[$i]->{'etr'} = time() + (($5*60)+$6)*60; +                $queue[$i]->{'status'} = 'queued'; +            } elsif (/You have been queued for ([0-9]*?) hours ([0-9]*?) minutes, currently in main queue position ([0-9]*?) of ([0-9]*?)\./i) { +                $queue[$i]->{'pos'} = $3; +                $queue[$i]->{'status'} = 'queued'; +            } elsif (/You have been queued for ([0-9]*?) minutes, currently in main queue position ([0-9]*?) of ([0-9]*?)\./i) { +                $queue[$i]->{'status'} = 'queued'; +                # FIXME unite somehow with regexp above +                $queue[$i]->{'pos'} = $2; +            } elsif (/It has been placed in queue slot #(\d+), it will send when sends are available/i) { +                $queue[$i]->{'pos'} = $1; +                $queue[$i]->{'status'} = 'queued'; +            } elsif (/Invalid Pack Number/i) { +                $queue[$i]->{'status'} = 'invalid'; +            } elsif (/The Owner Has Requested That No New Connections Are Made/i || +                /All Slots Full,( Main)? queue of size [0-9]* is Full, Try Again Later/i || +                /You can only have 1 transfer at a time/i || +                /you must be on a known channel/i) { +                print CLIENTCRAP "Retrying ....\n"; +                my $retry = Irssi::settings_get_int('xdccget_retry_time')*60000; +                $queue[$i]->{'status'} = 'retrying'; +                $queue[$i]->{'timer'} = Irssi::timeout_add($retry, 'retry_transfer', $i); +                $queue[$i]->{'etr'} = time()+$retry/1000; +            } elsif (/must be on a known channel/i) { +                $server->command("WHOIS $nick"); +                $queue[$i]->{'status'} = 'joining'; +            } else { Irssi::print($_) if ($debug); } +            process_queue(); +            last; +        }      }      if (/#(\d+).+?\d+x \[ *(<?\d+.*?)\] +(.*)$/) { -	my ($pack, $size, $name) = ($1, $2, $3); -    	if (defined $lists{lc $server->{tag}}{lc $nick}) { -	    $lists{lc $server->{tag}}{lc $nick}{$pack} = $name; -	} -	foreach (@queue) { -	    next unless lc $nick eq lc $_->{nick}; -	    next unless lc $server->{tag} eq lc $_->{net}; -	    next unless $_->{pack} eq $pack; -	    $_->{filename} = $name; -	} +        my ($pack, $size, $name) = ($1, $2, $3); +        if (defined $lists{lc $server->{tag}}{lc $nick}) { +            $lists{lc $server->{tag}}{lc $nick}{$pack} = $name; +        } +        foreach (@queue) { +            next unless lc $nick eq lc $_->{nick}; +            next unless lc $server->{tag} eq lc $_->{net}; +            next unless $_->{pack} eq $pack; +            $_->{filename} = $name; +        }      }  }  sub process_queue { +    debugFunc ("process_queue", @_); +    my ($i, $j, $numdls); +    $numdls = 0; +    my $process;      unless (scalar(@queue) > 0) {return 0}; -    my %current = %{$queue[0]}; -    shift @queue if ( $current{'status'} == 4 ); -    unless (scalar(@queue) > 0) {return 0}; -    %current = %{$queue[0]}; -    if ( $current{'status'} == 0 ) { -	my $server = Irssi::server_find_tag($current{'net'}); -    	$server->command('MSG '.$current{'nick'}.' xdcc send '.$current{'pack'}); -	$queue[0]->{'try'}++; -	$queue[0]->{'status'} = 1; +    for ($i=0; $i<= $#queue; $i++) { +        debugFunc (" - Item: $i -> ".$queue[$i]{'status'}); +        if ($queue[$i]{'status'} eq 'completed' || +            $queue[$i]{'status'} eq 'cancelled') { +            push (@completed, $queue[$i]); +            my $done_file = "$config_path/xdccdone.txt"; +            if (!open (DONEFILE, q{>>}, $done_file)) { +                print CLIENTCRAP "XDCCGET - Warning: Could not open file for appending done queue entry at $done_file. $!"; +            } else { +                print DONEFILE $queue[$i]{net}."\t".$queue[$i]{nick}."\t".$queue[$i]{pack}."\t".$queue[$i]{filename}."\t".$queue[$i]{'status'}."\n"; +                if (!close (DONEFILE)) { +                    print CLIENTCRAP "XDCCGET - Warning: Could not close file after appending done queue entry at $done_file. $!"; +                } +            } +            splice (@queue, $i, 1); +        } else { +            if ($queue[$i]{'status'} eq 'waiting') { +                $process = 1; +                for ($j=0; $j<$i; $j++) { +                    if ($queue[$i]{'nick'} eq $queue[$j]{'nick'}) { +                        $process = 0; +                    } +                } +                if ($numdls >= $max_downloads) { +                    $process = 0; +                } +                if ($process) { +                    my $server = Irssi::server_find_tag($queue[$i]{'net'}); +                    if (defined($server)) { +                        $server->command('MSG '.$queue[$i]{'nick'}.' '.$queue[$i]{'xdcc'}.' send '.$queue[$i]{'pack'}); +                        print CLIENTCRAP "%R>>%n XDCC Requesting queue item ".($i+1); +                        $queue[$i]->{'try'}++; +                        $queue[$i]->{'status'} = 'requested'; +                    } +                } +            } +            if ($queue[$i]{'status'} eq 'requested' || +                $queue[$i]{'status'} eq 'transferring') { +                $numdls ++; +            } +        }      } +    saveQueue();  }  sub retry_transfer { -    if (defined $queue[0] && $queue[0]->{'status'} == 6) { -	Irssi::timeout_remove($queue[0]->{'timer'}); -	#print CLIENTCRAP "%R>>%n Retrying XDCC-transfer..."; -	$queue[0]->{'status'} = 0; -	process_queue(); +    my ($numdls,$i); +    $numdls = 0; +    for ($i=0; $i<= $#queue; $i++) { +        if ($queue[$i]{'status'} eq 'requested' || +            $queue[$i]{'status'} eq 'transferring') { +            $numdls ++; +        } +        if (defined ($queue[$i]->{'timer'})) { +            Irssi::timeout_remove($queue[$i]->{'timer'}); +            undef ($queue[$i]->{'timer'}); +            if ($queue[$i]->{'status'} eq 'retrying' && $numdls < $max_downloads) { +                $queue[$i]->{'status'} = 'waiting'; +                process_queue(); +            } +        }      }  }  sub queue_pack { +    debugFunc ("queue_pack", @_);      my ($args, $server, $witem) = @_; -    my @args = split(/ /, $args, 2); -    my ($nick, $packs); +    my @args = split(/ /, $args, 3); +    my $xdcc = "xdcc"; +    my ($nick, $pack, $desc);      if (ref $witem && $witem->{type} eq 'QUERY' && $args[0] =~ /^\d+$/) { -	($nick, $packs) = ($witem->{name}, $args[0]); +        ($nick, $pack, $desc) = ($witem->{name}, $args[0], $args[1]);      } else { -	($nick, $packs) = @args; +        ($nick, $pack, $desc) = @args; +    } +    if ($desc =~ /^-xdcc=(.+?) (.+)$/) { +        $xdcc = $1; +        $desc = $2;      } -    my @packs = split(/ /, $packs); -    foreach (@packs) { -	# 0: Waiting, 1: Processing, 2: Doenloading -	my $status = 0; -	my $chatnet = $server->{tag}; -	my %transfer = ('nick'    => $nick, -			'pack'    => $_, -			'status'  => $status, -			'net'     => $chatnet, -			'pos'     => 0, -			'try'     => 0, -			'etr'     => 0, -			'timer'   => undef, -			); -	if (defined $lists{lc $server->{tag}}{lc $nick}{$_}) { -	    $transfer{filename} = $lists{lc $server->{tag}}{lc $nick}{$_}; -	} -	push @queue, \%transfer; +    my $status = 'waiting'; +    my $chatnet = $server->{tag}; +    my %transfer = ('nick'    => $nick, +        'pack'    => $pack, +        'status'  => $status, +        'net'     => $chatnet, +        'pos'     => 0, +        'try'     => 0, +        'etr'     => 0, +        'timer'   => undef, +        'xdcc'    => $xdcc +    ); +    if (defined $server->{tag} && defined $lists{lc $server->{tag}} && defined $lists{lc $server->{tag}}{lc $nick}{$_}) { +        $transfer{filename} = $lists{lc $server->{tag}}{lc $nick}{$_};      } -    process_queue() +    if (defined ($desc)) { +        $transfer{filename} = $desc; +    } +    push @queue, \%transfer; +    process_queue();  }  sub list_xdcc_queue {      my $text; -    my %progress = (0=>'waiting', -		    1=>'requesting', -		    2=>'queued', -		    3=>'transferring', -		    4=>'completed', -		    5=>'canceling', -		    6=>'retrying');      my $i = 1;      foreach (@queue) { -	my $current = $_; -	my $botname = $current->{'nick'}; -	my $ircnet = $current->{'net'}; -	my $pack = $current->{'pack'}; -	my $status = $progress{$current->{'status'}}; -	my $info = ''; -	my $etr = ''; -	if ($current->{'status'}==2) { -	    my $time = $current->{'etr'}-time(); +        my $current = $_; +        my $botname = $current->{'nick'}; +        my $ircnet = $current->{'net'}; +        my $pack = $current->{'pack'}; +        my $status = $current->{'status'}; +        my $info = ''; +        my $etr = ''; +        if ($current->{'status'} eq 'queued') { +            my $time = $current->{'etr'}-time(); +            my $hours = int($time / (60*60)); +            my $minutes = int( ($time-($hours*60*60))/60 ); +            my $seconds = int( ($time-($hours*60*60)-($minutes*60))  ); + +            $etr = '('.$hours.' hours, '.$minutes.' minutes and '.$seconds.' seconds remaining)' if ($current->{'etr'} > 0); +            $info = "[".$current->{'pos'}."]".' '.$etr; +        } elsif ($current->{'status'} eq 'retrying') { +            my $time = $current->{'etr'}-time();              my $hours = int($time / (60*60));              my $minutes = int( ($time-($hours*60*60))/60 );              my $seconds = int( ($time-($hours*60*60)-($minutes*60))  );              $etr = '('.$hours.' hours, '.$minutes.' minutes and '.$seconds.' seconds remaining)' if ($current->{'etr'} > 0); -	    $info = "[".$current->{'pos'}."]".' '.$etr; -	} elsif ($current->{'status'}==6) { -	    my $time = $current->{'etr'}-time(); -	    my $hours = int($time / (60*60)); -	    my $minutes = int( ($time-($hours*60*60))/60 ); -	    my $seconds = int( ($time-($hours*60*60)-($minutes*60))  ); -	     -	    $etr = '('.$hours.' hours, '.$minutes.' minutes and '.$seconds.' seconds remaining)' if ($current->{'etr'} > 0); -	    $info = '['.$current->{'try'}.']'.' '.$etr; -	} -	$text .= "%9".$i."%9 ".$botname."<".$ircnet.">: Pack ".$pack; -	$text .= " (".$current->{filename}.")" if defined $current->{filename}; -	$text .= " => ".$status.' '.$info; -	$text .= "\n"; -	$i++; +            $info = '['.$current->{'try'}.']'.' '.$etr; +        } +        $text .= "%9".$i."%9 ".$botname."<".$ircnet.">: Pack ".$pack; +        $text .= " (".$current->{filename}.")" if defined $current->{filename}; +        $text .= " => ".$status.' '.$info; +        $text .= "\n"; +        $i++;      }      print CLIENTCRAP draw_box("XDCCget", $text, "queued packs", 1);  } @@ -268,24 +410,49 @@ sub cancel_pack {      my (@numbers) = @_;      @numbers = sort {$b cmp $a} @numbers;      foreach (@numbers) { -	my $item = @queue->[$_-1]; - -	if ($item->{'status'} == 2) { -	    # Remove the order from the bots queue -	    my $server = Irssi::server_find_tag($item->{'net'}); -	    $server->command('MSG '.$item->{'nick'}.' xdcc remove'); -	    print CLIENTCRAP "%R>>>%n Removing pack ".$_." from server queue"; -	    $item->{'status'} = 5; -	    #splice(@queue, $_,$_+1); -	} elsif ($item->{'status'} == 3) { -	    $item->{'status'} = 5; -	    Irssi::command('DCC close get '.$item->{'nick'}); -	    print CLIENTCRAP "%R>>>%n Transfer aborted, waiting for acknowledgement"; -	} else { -	    splice(@queue, $_-1, $_); -	} -	process_queue(); +        my $item = $queue[$_-1]; +        next if (!defined($item)); + +        if ($item->{'status'} eq 'queued') { +            # Remove the request from the bots queue +            my $server = Irssi::server_find_tag($item->{'net'}); +            $server->command('MSG '.$item->{'nick'}.' xdcc remove'); +            print CLIENTCRAP "%R>>>%n Removing pack ".$_." from server queue"; +            $item->{'status'} = 'canceling'; +            #splice(@queue, $_,$_+1); +        } elsif ($item->{'status'} eq 'transferring') { +            $item->{'status'} = 'cancelled'; +            Irssi::command('dcc close get '.$item->{'nick'}); +            print CLIENTCRAP "%R>>>%n Transfer aborted"; + +        } else { +            debugFunc ("splice", $_); +            splice(@queue, $_-1,1); +        } +        process_queue(); +    } +} + +sub reset_pack { +    foreach (@_) { +        next if ($#queue < $_ || $_ < 0); +        $queue[$_-1]->{'status'} = 'waiting'; +    } +    process_queue(); +} + +sub pause_pack { +    my $server = shift; +    foreach (@_) { +        next if ($#queue < $_ || $_ < 0); +        if ($queue[$_-1]->{'status'} eq 'queued') { +            $server->command('msg '.$queue[$_-1]->{'nick'}.' xdcc remove'); +        } elsif ($queue[$_-1]->{'status'} eq 'transferring') { +            Irssi::command('dcc close get '.$queue[$_-1]->{'nick'}); +        } +        $queue[$_-1]->{'status'} = 'paused';      } +    process_queue();  }  sub list_packs ($$) { @@ -298,53 +465,186 @@ sub cmd_xdccget {      my ($args, $server, $witem) = @_;      my @arg = split(/ /, $args); -    if ((scalar(@arg) == 0) or ($arg[0] eq '-l')) { -	list_xdcc_queue(); +    if ((scalar(@arg) == 0) or ($arg[0] eq '-l') or ($arg[0] eq 'stat')) { +        list_xdcc_queue();      } elsif ($arg[0] eq 'queue') { -	# queue files -	shift @arg; -	queue_pack("@arg", $server, $witem); +        # queue files +        shift @arg; +        queue_pack("@arg", $server, $witem);      } elsif ($arg[0] eq 'list' && defined $arg[1]) { -	list_packs($server, $arg[1]); +        list_packs($server, $arg[1]);      } elsif ($arg[0] eq 'cancel') { -	shift @arg; -	cancel_pack(@arg); +        shift @arg; +        cancel_pack(@arg); +    } elsif ($arg[0] eq 'reset') { +        shift @arg; +        reset_pack(@arg); +    } elsif ($arg[0] eq 'pause') { +        shift @arg; +        pause_pack($server, @arg);      } elsif ($arg[0] eq 'help') { -	show_help(); +        show_help(); +    } elsif ($arg[0] eq 'offers') { +        shift @arg; +        show_offers(@arg);      }  }  sub event_private_message { +    debugFunc ("event_private_message", @_);      my ($server, $text, $nick, $address) = @_;      event_message_irc_notice($server, $text, $nick, $address, undef);  }  sub event_no_such_nick { +    debugFunc ("event_private_message", @_);      my ($server, $args, $sender_nick, $sender_address) = @_;      my ($myself, $nick) = split(/ /, $args, 3); -     -    unless (scalar(@queue) == 0) { -	if ($nick eq $queue[0]->{'nick'}) { -	    if ($queue[0]->{'status'} == 1 || $queue[0]->{'status'} == 5) { -		$queue[0]->{'status'} = 4; -	    } -	} -	process_queue(); + +    my $i; +    for ($i=0; $i<= $#queue; $i++) { +        if ($nick eq $queue[$i]->{'nick'}) { +            if ($queue[$i]->{'status'} eq 'requested' || $queue[$i]->{'status'} eq 'joining') { +                my $retry = Irssi::settings_get_int('xdccget_retry_time')*60000; +                $queue[$i]->{'status'} = 'retrying'; +                $queue[$i]->{'timer'} = Irssi::timeout_add($retry, 'retry_transfer', $i); +                $queue[$i]->{'etr'} = time()+$retry/1000; +            } +        } +        process_queue(); +    } +} + +sub event_server_connected { +    my ($server) = @_; +    debugFunc ("SERVER CONNECTED: " . $server->{'tag'}); + +    my $i; +    for ($i=0; $i<= $#queue; $i++) { +        $queue[$i]->{'status'} = 'waiting' if (lc($queue[$i]->{'net'}) eq lc($server->{'tag'})); +    } +    process_queue(); +} + +sub event_server_disconnected { +    my ($server) = @_; +    debugFunc ("SERVER DISCONNECTED: " . $server->{'tag'}); + +    my $i; +    for ($i=0; $i<= $#queue; $i++) { +        $queue[$i]->{'status'} = 'waiting' if (lc($queue[$i]->{'net'}) eq lc($server->{'tag'}));      } +    process_queue();  } +sub show_offers { +    my $server; +    my $channel; +    my $nick; +    my $desc; +    foreach (@_) { +        if (/^-server=(.*?)$/) { +            $server = $1; +        } elsif (/^-channel=(.*?)$/) { +            $channel = $1; +        } elsif (/^-nick=(.*?)$/) { +            $nick = $1; +        } else { +            $desc = $_; +        } +    } +    my $text; +    $text = ""; +    foreach my $s (keys %offers) { +        next unless (!defined($server) || $s =~ /$server/i); +        foreach my $c (keys %{$offers{$s}}) { +            next unless (!defined($channel) || $c =~ /$channel/i); +            foreach my $n (keys %{$offers{$s}{$c}}) { +                next unless (defined($offers{$s}{$c}{$n}{'numpacks'})); +                next unless (!defined($nick) || $n =~ /$nick/i); +                my $text1 = ""; +                $text1 .= "$s $c $n - #$offers{$s}{$c}{$n}{'numpacks'}, Slots: $offers{$s}{$c}{$n}{'freeslots'}/$offers{$s}{$c}{$n}{'numslots'}"; +                $text1 .= ", Q: $offers{$s}{$c}{$n}{'posqueue'}/$offers{$s}{$c}{$n}{'numqueue'}" if (defined($offers{$s}{$c}{$n}{'posqueue'})); +                $text1 .= ", Min: $offers{$s}{$c}{$n}{'minspeed'}" if (defined($offers{$s}{$c}{$n}{'minspeed'})); +                $text1 .= ", Max: $offers{$s}{$c}{$n}{'maxspeed'}" if (defined($offers{$s}{$c}{$n}{'maxspeed'})); +                $text1 .= ", Rec: $offers{$s}{$c}{$n}{'recspeed'}" if (defined($offers{$s}{$c}{$n}{'recspeed'})); +                $text1 .= ", BW: $offers{$s}{$c}{$n}{'bwcurrent'}" if (defined($offers{$s}{$c}{$n}{'bwcurrent'})); +                $text1 .= ", Rec: $offers{$s}{$c}{$n}{'bwrecord'}" if (defined($offers{$s}{$c}{$n}{'bwrecord'})); +                $text1 .= ", Cap: $offers{$s}{$c}{$n}{'bwcapacity'}" if (defined($offers{$s}{$c}{$n}{'bwcapacity'})); +                $text1 .= "\n"; +                my $text2 = ""; +                foreach my $p (sort {$a <=> $b} keys %{$offers{$s}{$c}{$n}{'packs'}}) { +                    next unless (!defined($desc) || $offers{$s}{$c}{$n}{'packs'}{$p}{'desc'} =~ /$desc/i); +                    $text2 .= "    #$p x$offers{$s}{$c}{$n}{'packs'}{$p}{'numdl'} [$offers{$s}{$c}{$n}{'packs'}{$p}{'size'}] $offers{$s}{$c}{$n}{'packs'}{$p}{'desc'}\n"; +                } +                next if (length($text2) == 0); +                $text .= $text1.$text2; +            } +        } +    } +    print CLIENTCRAP draw_box("XDCCget", $text, "offers", 1); +} + +sub event_message_public { +    my ($server, $msg, $nick, $address, $target) = @_; + +    if ($msg =~ /.*?\*\*.*? (\d+) packs? .*?\*\*.*?  (\d+) of (\d+) slots? open(?:, Queue: (\d+)\/(\d+))?(?:, Min: ((?:\d+|\.)+KB\/s))?(?:, Max: ((?:\d+|\.)+KB\/s))?(?:, Record: ((?:\d|\.)+KB\/s))?/i) { +        $offers{$server->{'tag'}} = {} unless (defined($offers{$server->{'tag'}})); +        $offers{$server->{'tag'}}{$target} = {} unless (defined($offers{$server->{'tag'}}{$target})); +        $offers{$server->{'tag'}}{$target}{$nick} = {} unless (defined($offers{$server->{'tag'}}{$target}{$nick})); +        $offers{$server->{'tag'}}{$target}{$nick}{'packs'} = {} unless (defined($offers{$server->{'tag'}}{$target}{$nick}{'packs'})); +        $offers{$server->{'tag'}}{$target}{$nick}{'numpacks'} = $1 if (defined($1)); +        $offers{$server->{'tag'}}{$target}{$nick}{'freeslots'} = $2 if (defined($2)); +        $offers{$server->{'tag'}}{$target}{$nick}{'numslots'} = $3 if (defined($3)); +        $offers{$server->{'tag'}}{$target}{$nick}{'posqueue'} = $4 if (defined($4)); +        $offers{$server->{'tag'}}{$target}{$nick}{'numqueue'} = $5 if (defined($5)); +        $offers{$server->{'tag'}}{$target}{$nick}{'minspeed'} = $6 if (defined($6)); +        $offers{$server->{'tag'}}{$target}{$nick}{'maxspeed'} = $7 if (defined($7)); +        $offers{$server->{'tag'}}{$target}{$nick}{'recspeed'} = $8 if (defined($8)); +    } +    if ($msg =~ /.*?\*\*.*? Bandwidth Usage .*?\*\*.*? Current: ((?:\d|\.)+KB\/s)(?:, Cap: ((?:\d|\.)+KB\/s))?(?:, Record: ((?:\d|\.)+KB\/s))?/) { +        $offers{$server->{'tag'}} = {} unless (defined($offers{$server->{'tag'}})); +        $offers{$server->{'tag'}}{$target} = {} unless (defined($offers{$server->{'tag'}}{$target})); +        $offers{$server->{'tag'}}{$target}{$nick} = {} unless (defined($offers{$server->{'tag'}}{$target}{$nick})); +        $offers{$server->{'tag'}}{$target}{$nick}{'packs'} = {} unless (defined($offers{$server->{'tag'}}{$target}{$nick}{'packs'})); +        $offers{$server->{'tag'}}{$target}{$nick}{'bwcurrent'} = $1 if (defined($1)); +        $offers{$server->{'tag'}}{$target}{$nick}{'bwcapacity'} = $2 if (defined($2)); +        $offers{$server->{'tag'}}{$target}{$nick}{'bwrecord'} = $3 if (defined($3)); +    } + +    if ($msg =~ /\.*?#(\d+).*?\s+(\d+)x\s+\[\s*?((?:\d|\.)*(?:M|K|G))\]\s+(.+)/) { +        $offers{$server->{'tag'}} = {} unless (defined($offers{$server->{'tag'}})); +        $offers{$server->{'tag'}}{$target} = {} unless (defined($offers{$server->{'tag'}}{$target})); +        $offers{$server->{'tag'}}{$target}{$nick} = {} unless (defined($offers{$server->{'tag'}}{$target}{$nick})); +        $offers{$server->{'tag'}}{$target}{$nick}{'packs'} = {} unless (defined($offers{$server->{'tag'}}{$target}{$nick}{'packs'})); +        $offers{$server->{'tag'}}{$target}{$nick}{'packs'}{$1} = {} unless (defined($offers{$server->{'tag'}}{$target}{$nick}{'packs'}{$1})); +        $offers{$server->{'tag'}}{$target}{$nick}{'packs'}{$1}{'numdl'} = $2; +        $offers{$server->{'tag'}}{$target}{$nick}{'packs'}{$1}{'size'} = $3; +        $offers{$server->{'tag'}}{$target}{$nick}{'packs'}{$1}{'desc'} = $4; +    } +}  Irssi::command_bind('xdccget', \&cmd_xdccget); -foreach my $cmd ('queue', 'cancel', 'list', 'help', 'list') { + +loadQueue(); + +foreach my $cmd ('queue', 'cancel', 'list', 'help', 'stat','reset','offers', 'pause') {      Irssi::command_bind('xdccget '.$cmd => sub { -                        cmd_xdccget("$cmd ".$_[0], $_[1], $_[2]); }); +        cmd_xdccget("$cmd ".$_[0], $_[1], $_[2]); +    });  } - +Irssi::signal_add('message public', 'event_message_public');  Irssi::signal_add('message irc notice', 'event_message_irc_notice');  Irssi::signal_add("message private", "event_private_message");  Irssi::signal_add("event 401", "event_no_such_nick"); - -Irssi::settings_add_int($IRSSI{'name'}, 'xdccget_retry_time', 30); +Irssi::signal_add("event connected", "event_server_connected"); +Irssi::signal_add("server disconnected", "event_server_disconnected");  print CLIENTCRAP '%B>>%n '.$IRSSI{name}.' '.$VERSION.' loaded: /xdccget help for help'; + +print "Configuration files are stored in $config_path"; + +if ($#queue >= 0) { +    process_queue(); +} | 
