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");