File Coverage

blib/lib/Bot/Cobalt/Plugin/Extras/Relay.pm
Criterion Covered Total %
statement 10 246 4.0
branch 0 64 0.0
condition 0 44 0.0
subroutine 4 19 21.0
pod 0 15 0.0
total 14 388 3.6


line stmt bran cond sub pod time code
1             package Bot::Cobalt::Plugin::Extras::Relay;
2             $Bot::Cobalt::Plugin::Extras::Relay::VERSION = '0.021002';
3             ## Simplistic relaybot plugin
4 1     1   931 use Scalar::Util 'reftype';
  1         1  
  1         47  
5              
6 1     1   5 use Bot::Cobalt;
  1         1  
  1         5  
7 1     1   616 use Bot::Cobalt::Common;
  1         1  
  1         8  
8              
9 1     1 0 357 sub new { bless +{}, shift }
10              
11             sub get_relays {
12 0     0 0   my ($self, $context, $channel) = @_;
13 0 0 0       return unless $context and $channel;
14              
15             ## array of arrays mapping relay relationships
16             ## $channel = [
17             ## [
18             ## $target_context,
19             ## $target_channel
20             ## ],
21             ## ]
22 0 0         return unless exists $self->{Relays}->{$context};
23 0   0       my $relays = $self->{Relays}->{$context}->{$channel} // return;
24 0 0         return unless @$relays;
25 0 0         wantarray ? return @$relays : return $relays ;
26             }
27              
28             sub add_relay {
29 0     0 0   my ($self, $ref) = @_;
30             ## take a hash mapping From and To
31 0 0 0       return unless $ref and ref $ref eq 'HASH';
32              
33 0   0       my $from = $ref->{From} // return;
34 0   0       my $to = $ref->{To} // return;
35              
36 0   0       my $context0 = $from->{Context} // return;
37 0   0       my $chan0 = $from->{Channel} // return;
38              
39 0   0       my $context1 = $to->{Context} // return;
40 0   0       my $chan1 = $to->{Channel} // return;
41              
42             ## context0:chan0 is relayed to *1:
43 0           push( @{ $self->{Relays}->{$context0}->{$chan0} },
  0            
44             [ $context1, $chan1 ],
45             );
46             ## and vice-versa:
47 0           push( @{ $self->{Relays}->{$context1}->{$chan1} },
  0            
48             [ $context0, $chan0 ],
49             );
50              
51 0           logger->debug(
52             "relaying: $context0 $chan0 -> $context1 $chan1"
53             );
54 0           return 1
55             }
56              
57             sub Cobalt_register {
58 0     0 0   my ($self, $core) = splice @_, 0, 2;
59              
60 0           my $pcfg = $core->get_plugin_cfg($self);
61 0           my $relays = $pcfg->{Relays};
62 0 0 0       unless (ref $relays and reftype $relays eq 'ARRAY') {
63 0           $core->log->warn("'Relays' conf directive not valid, should be a list");
64             } else {
65 0           for my $ref (@$relays) {
66 0           $self->add_relay($ref);
67             }
68             }
69              
70 0           register( $self, 'SERVER',
71             [
72             'public_msg',
73             'ctcp_action',
74              
75             'user_joined',
76             'user_kicked',
77             'user_left',
78             'user_quit',
79             'nick_changed',
80              
81             'public_cmd_relay',
82             'public_cmd_rwhois',
83              
84             'relay_push_join_queue',
85             ],
86             );
87              
88 0           $core->log->info("Loaded relay system");
89              
90 0           $core->timer_set( 3,
91             {
92             Event => 'relay_push_join_queue',
93             Alias => $core->get_plugin_alias($self),
94             },
95             'RELAYBOT_JOINQUEUE'
96             );
97              
98 0           return PLUGIN_EAT_NONE
99             }
100              
101             sub Cobalt_unregister {
102 0     0 0   my ($self, $core) = splice @_, 0, 2;
103 0           $core->log->info("Unloaded");
104 0           return PLUGIN_EAT_NONE
105             }
106              
107             sub Bot_relay_push_join_queue {
108 0     0 0   my ($self, $core) = splice @_, 0, 2;
109              
110 0           $self->_push_left_queue;
111              
112 0   0       my $queue = $self->{JoinQueue}//{};
113              
114 0           SERV: for my $context (keys %$queue) {
115 0 0         next SERV unless scalar keys %{ $self->{Relays}->{$context} };
  0            
116              
117 0           CHAN: for my $channel (keys %{ $queue->{$context} }) {
  0            
118 0           my @relays = $self->get_relays($context, $channel);
119 0 0         next CHAN unless @relays;
120              
121 0           my @pending = @{ $queue->{$context}->{$channel} };
  0            
122 0           my $str = "[joined: ${context}:${channel}] ";
123              
124 0 0         if (@pending > 5) {
125 0           $str .= join ', ', splice @pending, 0, 5;
126              
127 0           my $remaining = scalar @pending;
128 0           $str .= " ($remaining more, truncated)";
129             } else {
130 0           $str .= join ', ', @pending;
131             }
132              
133             ## clear queue
134 0           $queue->{$context}->{$channel} = [];
135              
136 0           RELAY: for my $relay (@relays) {
137 0           my ($to_context, $to_channel) = @$relay;
138 0           broadcast( 'message',
139             $to_context,
140             $to_channel,
141             $str
142             );
143             } # RELAY
144              
145             } # CHAN
146              
147             } # SERV
148              
149 0           $self->{JoinQueue} = {};
150              
151 0           broadcast('relay_push_left_queue');
152              
153 0           $core->timer_set( 3,
154             {
155             Event => 'relay_push_join_queue',
156             Alias => $core->get_plugin_alias($self),
157             },
158             'RELAYBOT_JOINQUEUE'
159             );
160              
161 0           return PLUGIN_EAT_ALL
162             }
163              
164             sub _push_left_queue {
165 0     0     my ($self) = @_;
166              
167 0   0       my $queue = $self->{LeftQueue}//{};
168              
169 0           SERV: for my $context (keys %$queue) {
170 0 0         next SERV unless scalar keys %{ $self->{Relays}->{$context} };
  0            
171 0           CHAN: for my $channel (keys %{ $queue->{$context} }) {
  0            
172 0           my @relays = $self->get_relays($context, $channel);
173 0 0         next CHAN unless @relays;
174              
175 0           my @pending = @{ $queue->{$context}->{$channel} };
  0            
176 0           my $str = "[left: ${context}:${channel}] ";
177              
178 0 0         if (@pending > 5) {
179 0           $str .= join ', ', splice @pending, 0, 5;
180              
181 0           my $remaining = scalar @pending;
182 0           $str .= " ($remaining more, truncated)";
183             } else {
184 0           $str .= join ', ', @pending;
185             }
186              
187 0           RELAY: for my $relay (@relays) {
188 0           my ($to_context, $to_channel) = @$relay;
189              
190 0           broadcast( 'message',
191             $to_context,
192             $to_channel,
193             $str
194             );
195             } # RELAY
196              
197             } # CHAN
198              
199             } # SERV
200              
201 0           $self->{LeftQueue} = {};
202              
203 0           return PLUGIN_EAT_ALL
204             }
205              
206              
207             sub Bot_public_msg {
208 0     0 0   my ($self, $core) = splice @_, 0, 2;
209 0           my $msg = ${ $_[0] };
  0            
210 0           my $context = $msg->context;
211              
212 0           my $channel = $msg->target;
213              
214 0           my @relays = $self->get_relays($context, $channel);
215 0 0         return PLUGIN_EAT_NONE unless @relays;
216              
217             ## don't relay our handled commands
218 0           my @handled = qw/ relay rwhois /;
219 0 0         if ($msg->cmd) {
220             return PLUGIN_EAT_NONE if $msg->cmd
221 0 0 0       and grep { $_ eq $msg->cmd } @handled;
  0            
222             }
223              
224 0           my $src_nick = $msg->src_nick;
225 0           my $text = $msg->message;
226 0           my $str = "<${src_nick}:${channel}> $text";
227              
228 0           for my $relay (@relays) {
229 0           my $to_context = $relay->[0];
230 0           my $to_channel = $relay->[1];
231              
232             ## should be good to relay away ...
233 0           broadcast( 'message',
234             $to_context,
235             $to_channel,
236             $str
237             );
238             }
239              
240 0           return PLUGIN_EAT_NONE
241             }
242              
243             sub Bot_ctcp_action {
244 0     0 0   my ($self, $core) = splice @_, 0, 2;
245 0           my $action = ${ $_[0] };
  0            
246 0           my $context = $action->context;
247              
248 0   0       my $channel = $action->channel || return PLUGIN_EAT_NONE;
249              
250 0           my @relays = $self->get_relays($context, $channel);
251 0 0         return PLUGIN_EAT_NONE unless @relays;
252              
253 0           my $src_nick = $action->src_nick;
254 0           my $text = $action->message;
255 0           my $str = "[action:${channel}] * $src_nick $text";
256              
257 0           for my $relay (@relays) {
258 0           my $to_context = $relay->[0];
259 0           my $to_channel = $relay->[1];
260              
261 0           broadcast( 'message',
262             $to_context,
263             $to_channel,
264             $str
265             );
266             }
267              
268 0           return PLUGIN_EAT_NONE
269             }
270              
271             sub Bot_user_joined {
272 0     0 0   my ($self, $core) = splice @_, 0, 2;
273 0           my $join = ${ $_[0] };
  0            
274              
275 0           my $context = $join->context;
276 0           my $channel = $join->channel;
277              
278 0 0         return PLUGIN_EAT_NONE unless $self->get_relays($context, $channel);
279              
280 0           my $src_nick = $join->src_nick;
281              
282 0           push( @{ $self->{JoinQueue}->{$context}->{$channel} }, $src_nick )
283 0           unless grep { $_ eq $src_nick }
284 0 0 0       @{ $self->{JoinQueue}->{$context}->{$channel}//[] };
  0            
285              
286 0           return PLUGIN_EAT_NONE
287             }
288              
289             sub Bot_user_left {
290 0     0 0   my ($self, $core) = splice @_, 0, 2;
291 0           my $part = ${ $_[0] };
  0            
292              
293 0           my $context = $part->context;
294 0           my $channel = $part->channel;
295              
296 0 0         return PLUGIN_EAT_NONE unless $self->get_relays($context, $channel);
297              
298 0           my $src_nick = $part->src_nick;
299              
300 0           push( @{ $self->{LeftQueue}->{$context}->{$channel} }, $src_nick )
301 0           unless grep { $_ eq $src_nick }
302 0 0 0       @{ $self->{LeftQueue}->{$context}->{$channel}//[] };
  0            
303              
304 0           return PLUGIN_EAT_NONE
305             }
306              
307             sub Bot_user_kicked {
308 0     0 0   my ($self, $core) = splice @_, 0, 2;
309 0           my $kick = ${ $_[0] };
  0            
310 0           my $context = $kick->context;
311              
312 0           my $channel = $kick->channel;
313              
314 0           my @relays = $self->get_relays($context, $channel);
315 0 0         return PLUGIN_EAT_NONE unless @relays;
316              
317 0           my $src_nick = $kick->src_nick;
318 0           my $kicked_u = $kick->kicked;
319 0           my $reason = $kick->reason;
320              
321 0           for my $relay (@relays) {
322 0           my $to_context = $relay->[0];
323 0           my $to_channel = $relay->[1];
324              
325 0           my $str =
326             " $kicked_u was kicked by $src_nick ($reason)";
327 0           broadcast( 'message',
328             $to_context,
329             $to_channel,
330             $str
331             );
332             }
333              
334 0           return PLUGIN_EAT_NONE
335             }
336              
337             sub Bot_user_quit {
338 0     0 0   my ($self, $core) = splice @_, 0, 2;
339 0           my $quit = ${ $_[0] };
  0            
340 0           my $context = $quit->context;
341              
342             return PLUGIN_EAT_NONE
343 0 0         unless $self->{Relays}->{$context};
344              
345 0           my $src_nick = $quit->src_nick;
346 0           my $common = $quit->common;
347              
348             ## see if we have any applicable relays for this quit
349             ## send the quit to all of them
350 0           for my $channel (@$common) {
351 0           my @relays = $self->get_relays($context, $channel);
352 0 0         next unless @relays;
353              
354 0           RELAY: for my $relay (@relays) {
355 0           my ($to_context, $to_channel) = @$relay;
356              
357 0           push(@{ $self->{LeftQueue}->{$context}->{$channel} }, $src_nick )
358 0           unless grep { $_ eq $src_nick }
359 0 0 0       @{ $self->{LeftQueue}->{$context}->{$channel}//[] };
  0            
360             }
361             }
362              
363 0           return PLUGIN_EAT_NONE
364             }
365              
366             sub Bot_nick_changed {
367 0     0 0   my ($self, $core) = splice @_, 0, 2;
368 0           my $nchg = ${ $_[0] };
  0            
369 0           my $context = $nchg->context;
370              
371             ## disregard case changes to cut back noise
372 0 0         return PLUGIN_EAT_NONE if $nchg->equal;
373              
374             return PLUGIN_EAT_NONE
375 0 0         unless $self->{Relays}->{$context};
376              
377 0           my $src_nick = $nchg->new_nick;
378 0           my $old_nick = $nchg->old_nick;
379 0           my $common = $nchg->channels;
380              
381 0           for my $channel (@$common) {
382 0           my @relays = $self->get_relays($context, $channel);
383 0 0         next unless @relays;
384              
385 0           RELAY: for my $relay (@relays) {
386 0           my ($to_context, $to_channel) = @$relay;
387 0           my $str =
388             "[relay: $channel] $old_nick changed nickname to $src_nick";
389              
390 0           broadcast( 'message', $to_context, $to_channel, $str );
391             }
392             }
393              
394 0           return PLUGIN_EAT_NONE
395             }
396              
397             sub Bot_public_cmd_relay {
398 0     0 0   my ($self, $core) = splice @_, 0, 2;
399 0           my $msg = ${ $_[0] };
  0            
400 0           my $context = $msg->context;
401             ## Show relay info
402              
403 0           my $channel = $msg->target;
404              
405 0           my @relays = $self->get_relays($context, $channel);
406              
407 0 0         unless (@relays) {
408 0           broadcast( 'message',
409             $context,
410             $channel,
411             "There are no relays for $channel on context $context"
412             );
413 0           return PLUGIN_EAT_ALL
414             }
415              
416 0           my $str = "Currently relaying to: ";
417              
418 0           my $idx = 0;
419 0           for my $relay (@relays) {
420 0           my ($to_context, $to_channel) = @$relay;
421 0           $str .= "${to_context}:${to_channel} ";
422             }
423              
424 0           broadcast( 'message', $context, $channel, $str );
425 0           return PLUGIN_EAT_ALL
426             }
427              
428             sub Bot_public_cmd_rwhois {
429 0     0 0   my ($self, $core) = splice @_, 0, 2;
430 0           my $msg = ${ $_[0] };
  0            
431 0           my $context = $msg->context;
432              
433 0           my $channel = $msg->target;
434              
435 0           my ($remotenet, $remoteuser) = @{ $msg->message_array };
  0            
436 0 0 0       unless ($remotenet && $remoteuser) {
437 0           my $src_nick = $msg->src_nick;
438 0           broadcast( 'message',
439             $context,
440             $channel,
441             "${src_nick}: Usage: rwhois "
442             );
443 0           return PLUGIN_EAT_ALL
444             }
445              
446 0 0         unless ( $self->get_relays($context, $channel) ) {
447 0           broadcast( 'message',
448             $context,
449             $channel,
450             "There are no active relays for $channel on context $context"
451             );
452 0           return PLUGIN_EAT_ALL
453             }
454              
455 0           my $irc_obj = $core->get_irc_obj($remotenet);
456 0 0 0       unless ( $self->{Relays}->{$remotenet} and ref $irc_obj ) {
457 0           broadcast( 'message',
458             $context,
459             $channel,
460             "We don't seem to have a relay for $remotenet"
461             );
462 0           return PLUGIN_EAT_ALL
463             }
464              
465 0           my $nickinfo = $irc_obj->nick_info($remoteuser);
466 0           my $resp;
467 0 0         unless ($nickinfo) {
468 0           $resp = "No such user: $remoteuser";
469             } else {
470 0           my $nick = $nickinfo->{Nick};
471 0           my $user = $nickinfo->{User};
472 0           my $host = $nickinfo->{Host};
473 0           my $real = $nickinfo->{Real};
474 0           my $userhost = "${nick}!${user}\@${host}";
475 0           $resp = "$remoteuser ($userhost) [$real]"
476             }
477 0           broadcast( 'message', $context, $channel, $resp );
478              
479 0           return PLUGIN_EAT_ALL
480             }
481              
482             1;
483             __END__