html/mg.pl


   1 # DCC MultiGet
   2 # by Kaveh Moini
   3 #
   4 # Description:
   5 #	* A small and rather resilient script for fetching a list of single packs 
   6 # 	  and ranges of packs from an XDCC bot
   7 #	* Can handle abrupt closing of DCC connection, check whether transfer 
   8 #	  started, and restart incomplete transfers
   9 #	* Avoids flooding bots and getting banned by using configurable delays 
  10 #	  (with sane defaults)
  11 #	* Configurable message prefix
  12 #
  13 # Requires:
  14 #	* Written on IRSSI 0.8.13 (20090331), can't be guaranteed to work on 
  15 #	  previous versions but testing won't hurt 
  16 #	  (don't forget to change 'use Irssi [version];' line)
  17 #	* dcc_autoget = on
  18 #	* dcc_autoresume = on
  19 #
  20 # Note:
  21 #	* For security reasons MultiGet does NOT automatically set dcc_autoget 
  22 #	   and dcc_autoresume you have to do so manually
  23 # 
  24 # Usage:
  25 # 	mg <bot name> <packs to transfer>
  26 #	Fetches specified packs from specified bot
  27 #	<packs to transfer> is a list of numbers, or ranges denoted by '-'
  28 # 	Example: mg BotX 38 1 12-14 82 23-43
  29 # 	Fetches, in order given, packs 38, 1, 12 to 14, 82, and 23 to 43
  30 #	When a range m-n is specified m and n will be fetched too
  31 #	----------------------------------------------------------------------
  32 #	mg_cancel
  33 #	Cancels mg fetching, will NOT close any running transfers
  34 #	----------------------------------------------------------------------
  35 #	mg_reset
  36 #	Resets all mg configuration to defaults
  37 #
  38 # Configuration:
  39 #	NOTE: all delays are in seconds
  40 #	* mg_next_delay: how much to wait before requesting next pack after 
  41 #	  successful transfer, default 5
  42 #	* mg_no_transfer_delay: how much to wait before re-requesting same pack
  43 #	  if transfer fails, default 60
  44 #	* mg_dcc_closed_retry_delay: how much to wait before re-requesting same
  45 #	  pack if DCC connection is closed for whatever reason, default 10
  46 #	* mg_transfer_confirmation_delay: how much to wait before checking if 
  47 #	  requested transfer started, will result in re-requesting the pack if no 
  48 #	  offer is received from the bot after set time, default 30
  49 #	* mg_message_prefix: what to tell the bot to request a pack, should 
  50 #	  include everything before the pack number including the last 
  51 #	  whitespace, default "xdcc send "
  52 
  53 use strict;
  54 
  55 use Irssi 20090331;
  56 
  57 use vars qw($VERSION %IRSSI);
  58 
  59 $VERSION = 20090813;
  60 %IRSSI = (
  61 	name => "mg", 
  62 	description => "DCC MultiGet, for fetching from XDCC bots",
  63 	license => "ccBSD, http://creativecommons.org/licenses/BSD/",
  64 	changed => "$VERSION",
  65 	authors => "Kaveh Moini",
  66 	contact => "campanastra\@gmail.com",
  67 );
  68 
  69 my ($server, $botname, $pncounter, $pact);
  70 my @totags = ();
  71 my @packs = ();
  72 
  73 my $nexdelay = 5; 
  74 my $dcrdelay = 10; 
  75 my $ntrdelay = 60;
  76 my $trcdelay = 30; 
  77 my $msgprefix = "xdcc send ";
  78 
  79 sub mg 
  80 {
  81 	@packs = ();
  82 	my @args = split(/ +/, @_[0]);
  83 	if ($#args < 1)
  84 	{
  85 		Irssi::print "MG | too few arguments";
  86 		Irssi::print "MG | usage: mg <bot name> <packs to transfer>";
  87 		return;
  88 	}
  89 	$server = @_[1];
  90 	my $witem = @_[2];
  91 	$botname = shift(@args);
  92 	my ($prh, $prl, $pn);
  93 	foreach my $ps (@args)
  94 	{
  95 		if ($ps =~ /^\d+-\d+$/)
  96 		{
  97 			($prl, $prh) = ($ps =~ /(\d+)-(\d+)/);
  98 			Irssi::print "MG | pack range: " . $prl . " through " . $prh;
  99 			for ($pn = $prl; $pn <= $prh; $pn += 1)
 100 			{
 101 				push(@packs, $pn);
 102 			}
 103 		}
 104 		elsif ($ps =~ /^\d+$/)
 105 		{
 106 			($pn) = ($ps =~ /(\d+)/);
 107 			Irssi::print "MG | pack number: " . $pn;
 108 			push(@packs, $pn);
 109 		}
 110 		else
 111 		{
 112 			Irssi::print "MG | invalid pack specification: " . $ps;
 113 		}
 114 	}
 115 	if ($#packs < 0)
 116 	{
 117 		Irssi::print "MG | no valid packs specifications";
 118 		return;
 119 	}
 120 	Irssi::print "MG | bot name: " . $botname;
 121 	Irssi::print "MG | message prefix: " . "\"" . $msgprefix . "\"";
 122 	$pncounter = 0;
 123 	$pact = 0;
 124 	Irssi::signal_add("dcc closed", "mghandler");
 125 	Irssi::signal_add("dcc get receive", "dcchandler");
 126 	Irssi::print "MG | beginning with: " . $packs[$pncounter];
 127 	&reqpack;
 128 }
 129 
 130 sub mghandler
 131 {
 132 	my ($dcc) = @_;
 133 	if ($dcc->{'nick'} eq $botname)
 134 	{
 135 		Irssi::print "MG | pack " . $packs[$pncounter] . " size was: " . $dcc->{'size'};
 136 		Irssi::print "MG | transferred: " . $dcc->{'transfd'};
 137 		Irssi::print "MG | skipped: " . $dcc->{'skipped'};
 138 		$pact = 0;
 139 		foreach my $to (@totags)
 140 		{
 141 			Irssi::timeout_remove($to);
 142 		}
 143 		@totags = ();
 144 		if ($dcc->{'transfd'} == $dcc->{'size'})
 145 		{
 146 			Irssi::print "MG | transfer successful";
 147 			if ($pncounter < $#packs)
 148 			{
 149 				Irssi::print "MG | waiting " . $nexdelay . " seconds";
 150 				Irssi::timeout_add_once($nexdelay * 1000, sub { $pncounter += 1; Irssi::print "MG | getting next: " . $packs[$pncounter]; &reqpack; } , []);
 151 			}
 152 			else
 153 			{
 154 				Irssi::print "MG | ending at: " . $packs[$pncounter];
 155 				Irssi::signal_remove("dcc closed", "mghandler");
 156 				Irssi::signal_remove("dcc get receive", "dcchandler");
 157 				@packs = ();
 158 			}
 159 		}
 160 		else
 161 		{
 162 			Irssi::print "MG | transfer failed";
 163 			Irssi::print "MG | waiting " . $dcrdelay . " seconds";
 164 			Irssi::timeout_add_once($dcrdelay * 1000, sub { Irssi::print "MG | retrying: " . $packs[$pncounter]; &reqpack; } , []);
 165 		}
 166 	}
 167 }
 168 
 169 sub dcchandler
 170 {
 171 	my ($gdcc) = @_;
 172 	if ($gdcc->{'nick'} eq $botname)
 173 	{
 174 		Irssi::print "MG | received connection for: " . $packs[$pncounter]; 
 175 		$pact = 1;
 176 	}
 177 }
 178 
 179 sub reqpack
 180 {
 181 	$server->command("msg $botname $msgprefix" . $packs[$pncounter]);
 182 	push(@totags, Irssi::timeout_add_once($trcdelay * 1000, sub { if ($pact == 0) { Irssi::print "MG | transfer status not confirmed for: " . $packs[$pncounter]; Irssi::print "MG | waiting " . $ntrdelay . " seconds"; push(@totags, Irssi::timeout_add_once($ntrdelay * 1000, sub { if ($pact == 0) { Irssi::print "MG | retrying: " . $packs[$pncounter]; &reqpack; } } , [])); } }, []));
 183 }
 184 
 185 sub setuphandler
 186 {
 187 	($nexdelay, $ntrdelay, $dcrdelay, $trcdelay, $msgprefix) = (Irssi::settings_get_int("mg_next_delay"), Irssi::settings_get_int("mg_no_transfer_delay"), Irssi::settings_get_int("mg_dcc_closed_retry_delay"), Irssi::settings_get_int("mg_transfer_confirmation_delay"), Irssi::settings_get_str("mg_message_prefix"));
 188 }
 189 
 190 sub mgreset
 191 {
 192 	$nexdelay = 5; 
 193 	$dcrdelay = 10; 
 194 	$ntrdelay = 60;
 195 	$trcdelay = 30; 
 196 	$msgprefix = "xdcc send ";
 197 	Irssi::settings_set_int("mg_next_delay", $nexdelay);
 198 	Irssi::settings_set_int("mg_no_transfer_delay", $ntrdelay);
 199 	Irssi::settings_set_int("mg_dcc_closed_retry_delay", $dcrdelay);
 200 	Irssi::settings_set_int("mg_transfer_confirmation_delay", $trcdelay);
 201 	Irssi::settings_set_str("mg_message_prefix", $msgprefix);
 202 	Irssi::print "MG | all settings reset to default values";
 203 }
 204 
 205 sub mgcancel
 206 {
 207 	Irssi::signal_remove("dcc closed", "mghandler");
 208 	Irssi::signal_remove("dcc get receive", "dcchandler");
 209 	foreach my $to (@totags)
 210 	{
 211 		Irssi::timeout_remove($to);
 212 	}
 213 	@totags = ();
 214 	Irssi::print "MG | cancelled";
 215 	Irssi::print "MG | last requested pack was: " . $packs[$pncounter];
 216 	Irssi::print "MG | remaining packs are: " . join(' ', splice(@packs, $pncounter));
 217 	@packs = ();
 218 }
 219 
 220 Irssi::settings_add_int("mg", "mg_next_delay", $nexdelay);
 221 Irssi::settings_add_int("mg", "mg_no_transfer_delay", $ntrdelay);
 222 Irssi::settings_add_int("mg", "mg_dcc_closed_retry_delay", $dcrdelay);
 223 Irssi::settings_add_int("mg", "mg_transfer_confirmation_delay", $trcdelay);
 224 Irssi::settings_add_str("mg", "mg_message_prefix", $msgprefix);
 225 Irssi::signal_add("setup changed", "setuphandler");
 226 Irssi::command_bind("mg", "mg");
 227 Irssi::command_bind("mg_reset", "mgreset");
 228 Irssi::command_bind("mg_cancel", "mgcancel");