1# Original version by Stefan "tommie" Tomanek <stefan@kann-nix.org> 2# Enhanced with max. download limits, retries, pausing, searching and other neat stuff by Obfuscoder (obfuscoder@obfusco.de) 3# You can find the script on GitHub: https://github.com/obfuscoder/irssi_scripts 4# Please report bugs to https://github.com/obfuscoder/irssi_scripts/issues 5 6use strict; 7use warnings; 8 9use vars qw($VERSION %IRSSI); 10$VERSION = "20141016"; 11%IRSSI = ( 12 authors => "Stefan 'tommie' Tomanek, Obfuscoder", 13 contact => "obfuscoder\@obfusco.de", 14 name => "xdccget", 15 description => "enhanced downloading, queing, searching from XDCC bots", 16 license => "GPLv2", 17 changed => "$VERSION", 18 commands => "xdccget" 19); 20 21use Irssi 20020324; 22 23use vars qw(@queue @completed %offers $timer $debug %lists); 24 25Irssi::settings_add_str($IRSSI{'name'}, 'xdccget_config_path', "$ENV{HOME}/.irssi"); 26Irssi::settings_add_int($IRSSI{'name'}, 'xdccget_max_downloads', 2); 27Irssi::settings_add_int($IRSSI{'name'}, 'xdccget_retry_time', 5); 28 29$debug=0; 30my $config_path = Irssi::settings_get_str('xdccget_config_path'); 31my $max_downloads = Irssi::settings_get_int('xdccget_max_downloads'); 32my $queue_file = "$config_path/xdccget.queue"; 33sub saveQueue { 34 if (!open (QUEUE, q{>}, $queue_file)) { 35 print CLIENTCRAP "XDCCGET - ERROR! Cannot open queue file for saving at $queue_file. $!"; 36 return; 37 } 38 foreach (@queue) { 39 print QUEUE $_->{net}."\t".$_->{nick}."\t".$_->{pack}."\t".$_->{filename}."\t".$_->{xdcc}."\n"; 40 } 41 if (!close QUEUE) { 42 print CLIENTCRAP "XDCCGET - ERROR! Could not close queue file after saving at $queue_file. $!"; 43 } 44} 45 46sub loadQueue { 47 @queue = (); 48 if (!open (QUEUE, q{<}, $queue_file)) { 49 print CLIENTCRAP "XDCCGET - Warning: Could open queue file for loading from $queue_file: $!"; 50 return; 51 } 52 while (<QUEUE>) { 53 chomp; 54 my ($net, $nick, $pack, $desc, $xdcc) = split (/\t/); 55 if ($xdcc eq "") { 56 $xdcc = "xdcc"; 57 } 58 my %transfer = ( 59 'nick' => $nick, 60 'pack' => $pack, 61 'status' => 'waiting', 62 'net' => $net, 63 'pos' => 0, 64 'try' => 0, 65 'etr' => 0, 66 'timer' => undef, 67 'xdcc' => $xdcc, 68 'filename' => $desc, 69 ); 70 push @queue, \%transfer; 71 } 72 if (!close QUEUE) { 73 print CLIENTCRAP "XDCCGET - ERROR! Could not close queue file after loading at $queue_file. $!"; 74 } 75} 76 77sub debugFunc { 78 return unless ($debug); 79 my $funcname = shift (@_); 80 print CLIENTCRAP "XDCC-DEBUG - $funcname (". join(",",@_).")\n"; 81} 82 83sub show_help() { 84 my $help="XDCCget $VERSION 85 Commands: 86 87 /xdccget queue <nickname> <number> [[-xdcc=<method>] <description>] 88 Queue the specified pack of the currently selected server and 'Nickname'. 89 The description will be shown in the queue. 90 With -xdcc=<method> it is possible to specify the method to be used in the request. 91 Default is 'xdcc' as in /msg <nickname> xdcc send <number> 92 93 /xdccget stat 94 /xdccget 95 /xdccget -l 96 List the download queue 97 98 /xdccget list <nickname> 99 Request the XDCC list of <nickname> 100 101 /xdccget cancel <number> 102 Cancel the download if currently downloading, request to being removed from queue 103 if queued by the XDCC offerer, or remove pack <number> from the download queue 104 105 /xdccget pause <number> 106 Pause pack <number> within the local queue. Resume with reset 107 108 /xdccget reset <number> 109 Reset pack <number> so that it is unpaused and -- 110 if download slots are still available -- triggers a download request 111 112 /xdccget offers [<options>] <description search pattern> 113 Display all the announced offers matching the given pattern or options. 114 The announcements are continuously monitored by this script throughout all joined channels. 115 116 Options: 117 One or more of the following options can be used. Each option must start with a '-': 118 119 -server=<server pattern> only show offers announced by bots on servers matching this pattern 120 -channel=<channel pattern> only show offers announced by bots on channels matching this pattern 121 -nick=<nick pattern> only show offers announced by bots with nicks matching this pattern 122 123 Examples: 124 /xdccget offers iron.*bluray 125 /xdccget offers -nick=bot iron.*bluray 126 /xdccget offers -channel=beast-xdcc iron.*bluray 127 128 Regular expressions are used to match each of the parameters. 129 130 /xdccget help 131 Display this help 132 133 You can also simply use /x instead of /xdccget ;-) 134 135 Configuration: 136 137 xdccget_config_path 138 Path where this script is storing its files (queue and finished downloads). 139 Default is '\$HOME/.irssi'. 140 141 xdccget_max_downloads 142 Maximum number of parallel downloads. Default is 2. A download request which is queued 143 by the XDCC offer bot does not count against the limit. The next item in the download queue 144 is being requested as long as download slots are available. Also other downloads not controlled 145 by this script do not count either. It is also possible to exceed this limit if a bot sends the 146 previously requested and queued file while there are downloads running already. 147 148 xdccget_retry_time 149 Time in minutes between retries. Default is 5. Retries are necessary for full 150 offer queues of bots, bots being/becoming offline, or not getting the requested download or any 151 understandable message regarding the request. Please DO NOT set this value to less than 300 152 (5 minutes) or risk being banned from the channels for spamming the bots. 153 154 Please report bugs to https://github.com/obfuscoder/irssi_scripts/issues 155"; 156 my $text = ''; 157 foreach (split(/\n/, $help)) { 158 $_ =~ s/^\/(.*)$/%9\/$1%9/; 159 $text .= $_."\n"; 160 } 161 print CLIENTCRAP &draw_box("XDCCget", $text, "help", 1); 162} 163 164sub draw_box ($$$$) { 165 my ($title, $text, $footer, $colour) = @_; 166 my $box = ''; 167 my $exp_flags = Irssi::EXPAND_FLAG_IGNORE_EMPTY | Irssi::EXPAND_FLAG_IGNORE_REPLACES; 168 $box .= '%R,--[%n%9%U'.$title.'%U%9%R]%n'."\n"; 169 if (defined($text)) { 170 foreach (split(/\n/, $text)) { 171 $box .= '%R|%n '.$_."\n"; 172 } 173 } 174 $box .= '%R`--<%n'.$footer.'%R>->%n'; 175 $box =~ s/%.//g unless $colour; 176 return $box; 177} 178 179sub contains { 180 my ($item, @list) = @_; 181 foreach (@list) { 182 ($item eq $_) && return 1; 183 } 184 return 0; 185} 186 187sub event_message_irc_notice { 188 debugFunc ("event_message_irc_notice", @_); 189 my ($server, $msg, $nick, $address, $target) = @_; 190 my $i; 191 $_ = $msg; 192 for ($i=0; $i<= $#queue; $i++) { 193 if ($queue[$i] && lc($nick) eq lc($queue[$i]->{'nick'})) { 194 if (/Closing Connection/) { 195 print CLIENTCRAP "%R>>%n XDCC-Transfer closed"; 196 # Is it a canceled transfer? 197 if ($queue[$i]->{'status'} eq 'canceling') { 198 $queue[$i]->{'status'} = 'cancelled'; 199 } elsif ($queue[$i]->{'status'} ne 'paused') { 200 # We should try again unless we paused the queue item 201 $queue[$i]->{'status'} = 'waiting'; 202 } 203 } elsif (/Transfer Completed/i) { 204 print CLIENTCRAP "%R>>%n XDCC-Transfer completed"; 205 # Mark the transfer as completed 206 $queue[$i]->{'status'} = 'completed'; 207 } elsif (/You already requested that pack/i) { 208 $queue[$i]->{'status'} = 'transferring'; 209 } elsif (/You already have that item queued/i) { 210 $queue[$i]->{'status'} = 'queued'; 211 } elsif (/Sending (?:You|u) (?:Your Queued )?Pack/i) { 212 $queue[$i]->{'status'} = 'transferring'; 213 print CLIENTCRAP "%R>>%n XDCC-Transfer starting"; 214 } elsif (/All Slots Full, Added (|you to the main )queue in position ([0-9]*)/i) { 215 $queue[$i]->{'pos'} = $2; 216 $queue[$i]->{'etr'} = 0; 217 $queue[$i]->{'status'} = 'queued'; 218 } 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) { 219 $queue[$i]->{'pos'} = $3; 220 $queue[$i]->{'etr'} = time() + (($5*60)+$6)*60; 221 $queue[$i]->{'status'} = 'queued'; 222 } elsif (/You have been queued for ([0-9]*?) hours ([0-9]*?) minutes, currently in main queue position ([0-9]*?) of ([0-9]*?)\./i) { 223 $queue[$i]->{'pos'} = $3; 224 $queue[$i]->{'status'} = 'queued'; 225 } elsif (/You have been queued for ([0-9]*?) minutes, currently in main queue position ([0-9]*?) of ([0-9]*?)\./i) { 226 $queue[$i]->{'status'} = 'queued'; 227 # FIXME unite somehow with regexp above 228 $queue[$i]->{'pos'} = $2; 229 } elsif (/It has been placed in queue slot #(\d+), it will send when sends are available/i) { 230 $queue[$i]->{'pos'} = $1; 231 $queue[$i]->{'status'} = 'queued'; 232 } elsif (/Invalid Pack Number/i) { 233 $queue[$i]->{'status'} = 'invalid'; 234 } elsif (/The Owner Has Requested That No New Connections Are Made/i || 235 /All Slots Full,( Main)? queue of size [0-9]* is Full, Try Again Later/i || 236 /You can only have 1 transfer at a time/i || 237 /you must be on a known channel/i) { 238 print CLIENTCRAP "Retrying ....\n"; 239 my $retry = Irssi::settings_get_int('xdccget_retry_time')*60000; 240 $queue[$i]->{'status'} = 'retrying'; 241 $queue[$i]->{'timer'} = Irssi::timeout_add($retry, 'retry_transfer', $i); 242 $queue[$i]->{'etr'} = time()+$retry/1000; 243 } elsif (/must be on a known channel/i) { 244 $server->command("WHOIS $nick"); 245 $queue[$i]->{'status'} = 'joining'; 246 } else { Irssi::print($_) if ($debug); } 247 process_queue(); 248 last; 249 } 250 } 251 if (/#(\d+).+?\d+x \[ *(<?\d+.*?)\] +(.*)$/) { 252 my ($pack, $size, $name) = ($1, $2, $3); 253 if (defined $lists{lc $server->{tag}}{lc $nick}) { 254 $lists{lc $server->{tag}}{lc $nick}{$pack} = $name; 255 } 256 foreach (@queue) { 257 next unless lc $nick eq lc $_->{nick}; 258 next unless lc $server->{tag} eq lc $_->{net}; 259 next unless $_->{pack} eq $pack; 260 $_->{filename} = $name; 261 } 262 } 263} 264 265sub process_queue { 266 debugFunc ("process_queue", @_); 267 my ($i, $j, $numdls); 268 $numdls = 0; 269 my $process; 270 unless (scalar(@queue) > 0) {return 0}; 271 for ($i=0; $i<= $#queue; $i++) { 272 debugFunc (" - Item: $i -> ".$queue[$i]{'status'}); 273 if ($queue[$i]{'status'} eq 'completed' || 274 $queue[$i]{'status'} eq 'cancelled') { 275 push (@completed, $queue[$i]); 276 my $done_file = "$config_path/xdccdone.txt"; 277 if (!open (DONEFILE, q{>>}, $done_file)) { 278 print CLIENTCRAP "XDCCGET - Warning: Could not open file for appending done queue entry at $done_file. $!"; 279 } else { 280 print DONEFILE $queue[$i]{net}."\t".$queue[$i]{nick}."\t".$queue[$i]{pack}."\t".$queue[$i]{filename}."\t".$queue[$i]{'status'}."\n"; 281 if (!close (DONEFILE)) { 282 print CLIENTCRAP "XDCCGET - Warning: Could not close file after appending done queue entry at $done_file. $!"; 283 } 284 } 285 splice (@queue, $i, 1); 286 } else { 287 if ($queue[$i]{'status'} eq 'waiting') { 288 $process = 1; 289 for ($j=0; $j<$i; $j++) { 290 if ($queue[$i]{'nick'} eq $queue[$j]{'nick'}) { 291 $process = 0; 292 } 293 } 294 if ($numdls >= $max_downloads) { 295 $process = 0; 296 } 297 if ($process) { 298 my $server = Irssi::server_find_tag($queue[$i]{'net'}); 299 if (defined($server)) { 300 $server->command('MSG '.$queue[$i]{'nick'}.' '.$queue[$i]{'xdcc'}.' send '.$queue[$i]{'pack'}); 301 print CLIENTCRAP "%R>>%n XDCC Requesting queue item ".($i+1); 302 $queue[$i]->{'try'}++; 303 $queue[$i]->{'status'} = 'requested'; 304 } 305 } 306 } 307 if ($queue[$i]{'status'} eq 'requested' || 308 $queue[$i]{'status'} eq 'transferring') { 309 $numdls ++; 310 } 311 } 312 } 313 saveQueue(); 314} 315 316sub retry_transfer { 317 my ($numdls,$i); 318 $numdls = 0; 319 for ($i=0; $i<= $#queue; $i++) { 320 if ($queue[$i]{'status'} eq 'requested' || 321 $queue[$i]{'status'} eq 'transferring') { 322 $numdls ++; 323 } 324 if (defined ($queue[$i]->{'timer'})) { 325 Irssi::timeout_remove($queue[$i]->{'timer'}); 326 undef ($queue[$i]->{'timer'}); 327 if ($queue[$i]->{'status'} eq 'retrying' && $numdls < $max_downloads) { 328 $queue[$i]->{'status'} = 'waiting'; 329 process_queue(); 330 } 331 } 332 } 333} 334 335sub queue_pack { 336 debugFunc ("queue_pack", @_); 337 my ($args, $server, $witem) = @_; 338 my @args = split(/ /, $args, 3); 339 my $xdcc = "xdcc"; 340 my ($nick, $pack, $desc); 341 if (ref $witem && $witem->{type} eq 'QUERY' && $args[0] =~ /^\d+$/) { 342 ($nick, $pack, $desc) = ($witem->{name}, $args[0], $args[1]); 343 } else { 344 ($nick, $pack, $desc) = @args; 345 } 346 if ($desc =~ /^-xdcc=(.+?) (.+)$/) { 347 $xdcc = $1; 348 $desc = $2; 349 } 350 my $status = 'waiting'; 351 my $chatnet = $server->{tag}; 352 my %transfer = ('nick' => $nick, 353 'pack' => $pack, 354 'status' => $status, 355 'net' => $chatnet, 356 'pos' => 0, 357 'try' => 0, 358 'etr' => 0, 359 'timer' => undef, 360 'xdcc' => $xdcc 361 ); 362 if (defined $server->{tag} && defined $lists{lc $server->{tag}} && defined $lists{lc $server->{tag}}{lc $nick}{$_}) { 363 $transfer{filename} = $lists{lc $server->{tag}}{lc $nick}{$_}; 364 } 365 if (defined ($desc)) { 366 $transfer{filename} = $desc; 367 } 368 push @queue, \%transfer; 369 process_queue(); 370} 371 372sub list_xdcc_queue { 373 my $text; 374 my $i = 1; 375 foreach (@queue) { 376 my $current = $_; 377 my $botname = $current->{'nick'}; 378 my $ircnet = $current->{'net'}; 379 my $pack = $current->{'pack'}; 380 my $status = $current->{'status'}; 381 my $info = ''; 382 my $etr = ''; 383 if ($current->{'status'} eq 'queued') { 384 my $time = $current->{'etr'}-time(); 385 my $hours = int($time / (60*60)); 386 my $minutes = int( ($time-($hours*60*60))/60 ); 387 my $seconds = int( ($time-($hours*60*60)-($minutes*60)) ); 388 389 $etr = '('.$hours.' hours, '.$minutes.' minutes and '.$seconds.' seconds remaining)' if ($current->{'etr'} > 0); 390 $info = "[".$current->{'pos'}."]".' '.$etr; 391 } elsif ($current->{'status'} eq 'retrying') { 392 my $time = $current->{'etr'}-time(); 393 my $hours = int($time / (60*60)); 394 my $minutes = int( ($time-($hours*60*60))/60 ); 395 my $seconds = int( ($time-($hours*60*60)-($minutes*60)) ); 396 397 $etr = '('.$hours.' hours, '.$minutes.' minutes and '.$seconds.' seconds remaining)' if ($current->{'etr'} > 0); 398 $info = '['.$current->{'try'}.']'.' '.$etr; 399 } 400 $text .= "%9".$i."%9 ".$botname."<".$ircnet.">: Pack ".$pack; 401 $text .= " (".$current->{filename}.")" if defined $current->{filename}; 402 $text .= " => ".$status.' '.$info; 403 $text .= "\n"; 404 $i++; 405 } 406 print CLIENTCRAP draw_box("XDCCget", $text, "queued packs", 1); 407} 408 409sub cancel_pack { 410 my (@numbers) = @_; 411 @numbers = sort {$b cmp $a} @numbers; 412 foreach (@numbers) { 413 my $item = $queue[$_-1]; 414 next if (!defined($item)); 415 416 if ($item->{'status'} eq 'queued') { 417 # Remove the request from the bots queue 418 my $server = Irssi::server_find_tag($item->{'net'}); 419 $server->command('MSG '.$item->{'nick'}.' xdcc remove'); 420 print CLIENTCRAP "%R>>>%n Removing pack ".$_." from server queue"; 421 $item->{'status'} = 'canceling'; 422 #splice(@queue, $_,$_+1); 423 } elsif ($item->{'status'} eq 'transferring') { 424 $item->{'status'} = 'cancelled'; 425 Irssi::command('dcc close get '.$item->{'nick'}); 426 print CLIENTCRAP "%R>>>%n Transfer aborted"; 427 428 } else { 429 debugFunc ("splice", $_); 430 splice(@queue, $_-1,1); 431 } 432 process_queue(); 433 } 434} 435 436sub reset_pack { 437 foreach (@_) { 438 next if ($#queue < $_ || $_ < 0); 439 $queue[$_-1]->{'status'} = 'waiting'; 440 } 441 process_queue(); 442} 443 444sub pause_pack { 445 my $server = shift; 446 foreach (@_) { 447 next if ($#queue < $_ || $_ < 0); 448 if ($queue[$_-1]->{'status'} eq 'queued') { 449 $server->command('msg '.$queue[$_-1]->{'nick'}.' xdcc remove'); 450 } elsif ($queue[$_-1]->{'status'} eq 'transferring') { 451 Irssi::command('dcc close get '.$queue[$_-1]->{'nick'}); 452 } 453 $queue[$_-1]->{'status'} = 'paused'; 454 } 455 process_queue(); 456} 457 458sub list_packs ($$) { 459 my ($server, $bot) = @_; 460 $server->command('MSG '.$bot.' xdcc list'); 461 $lists{lc $server->{tag}}{lc $bot} = {}; 462} 463 464sub cmd_xdccget { 465 my ($args, $server, $witem) = @_; 466 my @arg = split(/ /, $args); 467 468 if ((scalar(@arg) == 0) or ($arg[0] eq '-l') or ($arg[0] eq 'stat')) { 469 list_xdcc_queue(); 470 } elsif ($arg[0] eq 'queue') { 471 # queue files 472 shift @arg; 473 queue_pack("@arg", $server, $witem); 474 } elsif ($arg[0] eq 'list' && defined $arg[1]) { 475 list_packs($server, $arg[1]); 476 } elsif ($arg[0] eq 'cancel') { 477 shift @arg; 478 cancel_pack(@arg); 479 } elsif ($arg[0] eq 'reset') { 480 shift @arg; 481 reset_pack(@arg); 482 } elsif ($arg[0] eq 'pause') { 483 shift @arg; 484 pause_pack($server, @arg); 485 } elsif ($arg[0] eq 'help') { 486 show_help(); 487 } elsif ($arg[0] eq 'offers') { 488 shift @arg; 489 show_offers(@arg); 490 } 491} 492 493sub event_private_message { 494 debugFunc ("event_private_message", @_); 495 my ($server, $text, $nick, $address) = @_; 496 event_message_irc_notice($server, $text, $nick, $address, undef); 497} 498 499sub event_no_such_nick { 500 debugFunc ("event_private_message", @_); 501 my ($server, $args, $sender_nick, $sender_address) = @_; 502 my ($myself, $nick) = split(/ /, $args, 3); 503 504 my $i; 505 for ($i=0; $i<= $#queue; $i++) { 506 if ($nick eq $queue[$i]->{'nick'}) { 507 if ($queue[$i]->{'status'} eq 'requested' || $queue[$i]->{'status'} eq 'joining') { 508 my $retry = Irssi::settings_get_int('xdccget_retry_time')*60000; 509 $queue[$i]->{'status'} = 'retrying'; 510 $queue[$i]->{'timer'} = Irssi::timeout_add($retry, 'retry_transfer', $i); 511 $queue[$i]->{'etr'} = time()+$retry/1000; 512 } 513 } 514 process_queue(); 515 } 516} 517 518sub event_server_connected { 519 my ($server) = @_; 520 debugFunc ("SERVER CONNECTED: " . $server->{'tag'}); 521 522 my $i; 523 for ($i=0; $i<= $#queue; $i++) { 524 $queue[$i]->{'status'} = 'waiting' if (lc($queue[$i]->{'net'}) eq lc($server->{'tag'})); 525 } 526 process_queue(); 527} 528 529sub event_server_disconnected { 530 my ($server) = @_; 531 debugFunc ("SERVER DISCONNECTED: " . $server->{'tag'}); 532 533 my $i; 534 for ($i=0; $i<= $#queue; $i++) { 535 $queue[$i]->{'status'} = 'waiting' if (lc($queue[$i]->{'net'}) eq lc($server->{'tag'})); 536 } 537 process_queue(); 538} 539 540sub show_offers { 541 my $server; 542 my $channel; 543 my $nick; 544 my $desc; 545 foreach (@_) { 546 if (/^-server=(.*?)$/) { 547 $server = $1; 548 } elsif (/^-channel=(.*?)$/) { 549 $channel = $1; 550 } elsif (/^-nick=(.*?)$/) { 551 $nick = $1; 552 } else { 553 $desc = $_; 554 } 555 } 556 my $text; 557 $text = ""; 558 foreach my $s (keys %offers) { 559 next unless (!defined($server) || $s =~ /$server/i); 560 foreach my $c (keys %{$offers{$s}}) { 561 next unless (!defined($channel) || $c =~ /$channel/i); 562 foreach my $n (keys %{$offers{$s}{$c}}) { 563 next unless (defined($offers{$s}{$c}{$n}{'numpacks'})); 564 next unless (!defined($nick) || $n =~ /$nick/i); 565 my $text1 = ""; 566 $text1 .= "$s $c $n - #$offers{$s}{$c}{$n}{'numpacks'}, Slots: $offers{$s}{$c}{$n}{'freeslots'}/$offers{$s}{$c}{$n}{'numslots'}"; 567 $text1 .= ", Q: $offers{$s}{$c}{$n}{'posqueue'}/$offers{$s}{$c}{$n}{'numqueue'}" if (defined($offers{$s}{$c}{$n}{'posqueue'})); 568 $text1 .= ", Min: $offers{$s}{$c}{$n}{'minspeed'}" if (defined($offers{$s}{$c}{$n}{'minspeed'})); 569 $text1 .= ", Max: $offers{$s}{$c}{$n}{'maxspeed'}" if (defined($offers{$s}{$c}{$n}{'maxspeed'})); 570 $text1 .= ", Rec: $offers{$s}{$c}{$n}{'recspeed'}" if (defined($offers{$s}{$c}{$n}{'recspeed'})); 571 $text1 .= ", BW: $offers{$s}{$c}{$n}{'bwcurrent'}" if (defined($offers{$s}{$c}{$n}{'bwcurrent'})); 572 $text1 .= ", Rec: $offers{$s}{$c}{$n}{'bwrecord'}" if (defined($offers{$s}{$c}{$n}{'bwrecord'})); 573 $text1 .= ", Cap: $offers{$s}{$c}{$n}{'bwcapacity'}" if (defined($offers{$s}{$c}{$n}{'bwcapacity'})); 574 $text1 .= "\n"; 575 my $text2 = ""; 576 foreach my $p (sort {$a <=> $b} keys %{$offers{$s}{$c}{$n}{'packs'}}) { 577 next unless (!defined($desc) || $offers{$s}{$c}{$n}{'packs'}{$p}{'desc'} =~ /$desc/i); 578 $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"; 579 } 580 next if (length($text2) == 0); 581 $text .= $text1.$text2; 582 } 583 } 584 } 585 print CLIENTCRAP draw_box("XDCCget", $text, "offers", 1); 586} 587 588sub event_message_public { 589 my ($server, $msg, $nick, $address, $target) = @_; 590 591 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) { 592 $offers{$server->{'tag'}} = {} unless (defined($offers{$server->{'tag'}})); 593 $offers{$server->{'tag'}}{$target} = {} unless (defined($offers{$server->{'tag'}}{$target})); 594 $offers{$server->{'tag'}}{$target}{$nick} = {} unless (defined($offers{$server->{'tag'}}{$target}{$nick})); 595 $offers{$server->{'tag'}}{$target}{$nick}{'packs'} = {} unless (defined($offers{$server->{'tag'}}{$target}{$nick}{'packs'})); 596 $offers{$server->{'tag'}}{$target}{$nick}{'numpacks'} = $1 if (defined($1)); 597 $offers{$server->{'tag'}}{$target}{$nick}{'freeslots'} = $2 if (defined($2)); 598 $offers{$server->{'tag'}}{$target}{$nick}{'numslots'} = $3 if (defined($3)); 599 $offers{$server->{'tag'}}{$target}{$nick}{'posqueue'} = $4 if (defined($4)); 600 $offers{$server->{'tag'}}{$target}{$nick}{'numqueue'} = $5 if (defined($5)); 601 $offers{$server->{'tag'}}{$target}{$nick}{'minspeed'} = $6 if (defined($6)); 602 $offers{$server->{'tag'}}{$target}{$nick}{'maxspeed'} = $7 if (defined($7)); 603 $offers{$server->{'tag'}}{$target}{$nick}{'recspeed'} = $8 if (defined($8)); 604 } 605 if ($msg =~ /.*?\*\*.*? Bandwidth Usage .*?\*\*.*? Current: ((?:\d|\.)+KB\/s)(?:, Cap: ((?:\d|\.)+KB\/s))?(?:, Record: ((?:\d|\.)+KB\/s))?/) { 606 $offers{$server->{'tag'}} = {} unless (defined($offers{$server->{'tag'}})); 607 $offers{$server->{'tag'}}{$target} = {} unless (defined($offers{$server->{'tag'}}{$target})); 608 $offers{$server->{'tag'}}{$target}{$nick} = {} unless (defined($offers{$server->{'tag'}}{$target}{$nick})); 609 $offers{$server->{'tag'}}{$target}{$nick}{'packs'} = {} unless (defined($offers{$server->{'tag'}}{$target}{$nick}{'packs'})); 610 $offers{$server->{'tag'}}{$target}{$nick}{'bwcurrent'} = $1 if (defined($1)); 611 $offers{$server->{'tag'}}{$target}{$nick}{'bwcapacity'} = $2 if (defined($2)); 612 $offers{$server->{'tag'}}{$target}{$nick}{'bwrecord'} = $3 if (defined($3)); 613 } 614 615 if ($msg =~ /\.*?#(\d+).*?\s+(\d+)x\s+\[\s*?((?:\d|\.)*(?:M|K|G))\]\s+(.+)/) { 616 $offers{$server->{'tag'}} = {} unless (defined($offers{$server->{'tag'}})); 617 $offers{$server->{'tag'}}{$target} = {} unless (defined($offers{$server->{'tag'}}{$target})); 618 $offers{$server->{'tag'}}{$target}{$nick} = {} unless (defined($offers{$server->{'tag'}}{$target}{$nick})); 619 $offers{$server->{'tag'}}{$target}{$nick}{'packs'} = {} unless (defined($offers{$server->{'tag'}}{$target}{$nick}{'packs'})); 620 $offers{$server->{'tag'}}{$target}{$nick}{'packs'}{$1} = {} unless (defined($offers{$server->{'tag'}}{$target}{$nick}{'packs'}{$1})); 621 $offers{$server->{'tag'}}{$target}{$nick}{'packs'}{$1}{'numdl'} = $2; 622 $offers{$server->{'tag'}}{$target}{$nick}{'packs'}{$1}{'size'} = $3; 623 $offers{$server->{'tag'}}{$target}{$nick}{'packs'}{$1}{'desc'} = $4; 624 } 625} 626 627Irssi::command_bind('xdccget', \&cmd_xdccget); 628 629loadQueue(); 630 631foreach my $cmd ('queue', 'cancel', 'list', 'help', 'stat','reset','offers', 'pause') { 632 Irssi::command_bind('xdccget '.$cmd => sub { 633 cmd_xdccget("$cmd ".$_[0], $_[1], $_[2]); 634 }); 635} 636 637Irssi::signal_add('message public', 'event_message_public'); 638Irssi::signal_add('message irc notice', 'event_message_irc_notice'); 639Irssi::signal_add("message private", "event_private_message"); 640Irssi::signal_add("event 401", "event_no_such_nick"); 641Irssi::signal_add("event connected", "event_server_connected"); 642Irssi::signal_add("server disconnected", "event_server_disconnected"); 643 644print CLIENTCRAP '%B>>%n '.$IRSSI{name}.' '.$VERSION.' loaded: /xdccget help for help'; 645 646print "Configuration files are stored in $config_path"; 647 648if ($#queue >= 0) { 649 process_queue(); 650} 651