File Coverage

blib/lib/Circle/Net/IRC/Target.pm
Criterion Covered Total %
statement 30 175 17.1
branch 0 36 0.0
condition 0 9 0.0
subroutine 10 40 25.0
pod 1 26 3.8
total 41 286 14.3


line stmt bran cond sub pod time code
1             # You may distribute under the terms of the GNU General Public License
2             #
3             # (C) Paul Evans, 2008-2014 -- leonerd@leonerd.org.uk
4              
5             package Circle::Net::IRC::Target;
6              
7 4     4   26 use strict;
  4         8  
  4         87  
8 4     4   16 use warnings;
  4         6  
  4         87  
9 4     4   15 use base qw( Tangence::Object Circle::WindowItem );
  4         6  
  4         852  
10              
11             our $VERSION = '0.173320';
12              
13             sub new
14             {
15 0     0 0   my $class = shift;
16 0           my %args = @_;
17              
18 0           my $self = $class->SUPER::new( @_ );
19              
20 0           $self->{irc} = $args{irc};
21              
22 0           $self->set_prop_name( $args{name} );
23 0           $self->set_prop_tag( $args{name} );
24              
25 0           $self->{root} = $args{root};
26 0           $self->{net} = $args{net};
27              
28 0           return $self;
29             }
30              
31             # Convenience accessor
32             sub name
33             {
34 0     0 0   my $self = shift;
35 0           return $self->get_prop_name;
36             }
37              
38 4     4   31 use Scalar::Util qw( refaddr );
  4         7  
  4         320  
39             use overload
40             # '""' => "STRING",
41 0     0   0 '0+' => sub { refaddr $_[0] },
42 4     4   25 fallback => 1;
  4         8  
  4         36  
43              
44 4     4   440 use constant PREFIX_OVERHEAD => 3;
  4         5  
  4         209  
45 4     4   22 use constant PRIVMSG_OVERHEAD => length("PRIVMSG :");
  4         11  
  4         199  
46 4     4   20 use constant CTCP_ACTION_OVERHEAD => length("PRIVMSG :\x01CTCP ACTION \x01");
  4         7  
  4         5887  
47              
48             sub STRING
49             {
50 0     0 0   my $self = shift;
51 0           return ref($self)."[name=".$self->name."]";
52             }
53              
54             sub describe
55             {
56 0     0 1   my $self = shift;
57 0           return ref($self) . "[" . $self->name . "]";
58             }
59              
60             sub get_prop_tag
61             {
62 0     0 0   my $self = shift;
63 0           return $self->name;
64             }
65              
66             sub get_prop_network
67             {
68 0     0 0   my $self = shift;
69 0           return $self->{net};
70             }
71              
72             sub reify
73             {
74 0     0 0   my $self = shift;
75              
76 0 0         return if $self->get_prop_real;
77              
78 0           $self->set_prop_real( 1 );
79              
80 0           my $root = $self->{root};
81 0           $root->broadcast_sessions( "new_item", $self );
82             }
83              
84             sub on_message
85             {
86 0     0 0   my $self = shift;
87 0           my ( $command, $message, $hints ) = @_;
88              
89             # $command might contain spaces from synthesized events - e.g. "ctcp ACTION"
90 0           ( my $method = "on_message_$command" ) =~ s/ /_/g;
91              
92 0 0 0       return 1 if $self->can( $method ) and $self->$method( $message, $hints );
93              
94 0 0 0       if( not $hints->{handled} and not $hints->{synthesized} ) {
95             $self->push_displayevent( "irc.irc", {
96             command => $command,
97             prefix => $message->prefix,
98 0           args => join( " ", map { "'$_'" } $message->args ),
  0            
99             } );
100 0           $self->bump_level( 1 );
101             }
102              
103 0           return 1;
104             }
105              
106             sub pick_display_target
107             {
108 0     0 0   my $self = shift;
109 0           my ( $display ) = @_;
110              
111 0 0         return $self if $display eq "self";
112 0 0         return $self->{net} if $display eq "server";
113             }
114              
115             sub default_message_level
116             {
117 0     0 0   my $self = shift;
118 0           my ( $hints ) = @_;
119              
120 0 0         return $hints->{is_notice} ? 1 : 2;
121             }
122              
123             sub on_message_text
124             {
125 0     0 0   my $self = shift;
126 0           my ( $message, $hints ) = @_;
127              
128 0           my $srcnick = $hints->{prefix_name};
129 0           my $text = $hints->{text};
130              
131 0           my $is_notice = $hints->{is_notice};
132              
133 0           my $net = $self->{net};
134              
135             my $event = {
136             %$hints,
137             text => $net->format_text_tagged( $text ),
138             is_action => 0,
139             level => $self->default_message_level( $hints ),
140 0 0 0       display => ( !defined $hints->{prefix_nick} or $is_notice && !$self->get_prop_real ) ? "server" : "self",
141             };
142              
143 0           $net->run_rulechain( "input", $event );
144              
145 0 0         my $eventname = $is_notice ? "notice" : "msg";
146              
147 0           $self->fire_event( $eventname, $srcnick, $text );
148              
149 0 0         if( my $target = $self->pick_display_target( $event->{display} ) ) {
150 0           $target->push_displayevent( "irc.$eventname", { target => $self->name, nick => $srcnick, text => $event->{text} } );
151 0 0         $target->bump_level( $event->{level} ) if defined $event->{level};
152              
153 0           $target->reify;
154             }
155              
156 0           return 1;
157             }
158              
159             sub on_message_ctcp_ACTION
160             {
161 0     0 0   my $self = shift;
162 0           my ( $message, $hints ) = @_;
163              
164 0           my $srcnick = $hints->{prefix_name};
165 0           my $text = $hints->{ctcp_args};
166              
167 0           my $net = $self->{net};
168              
169 0           my $event = {
170             %$hints,
171             text => $net->format_text_tagged( $text ),
172             is_action => 1,
173             level => $self->default_message_level( $hints ),
174             display => "self",
175             };
176              
177 0           $net->run_rulechain( "input", $event );
178              
179 0           $self->fire_event( "act", $srcnick, $text );
180              
181 0 0         if( my $target = $self->pick_display_target( $event->{display} ) ) {
182 0           $target->push_displayevent( "irc.act", { target => $self->name, nick => $srcnick, text => $event->{text} } );
183 0 0         $target->bump_level( $event->{level} ) if defined $event->{level};
184              
185 0           $target->reify;
186             }
187              
188 0           return 1;
189             }
190              
191             sub on_connected
192             {
193 0     0 0   my $self = shift;
194              
195 0           $self->push_displayevent( "status", { text => "Server is connected" } );
196             }
197              
198             sub on_disconnected
199             {
200 0     0 0   my $self = shift;
201 0           my ( $message ) = @_;
202              
203 0           $self->push_displayevent( "status", { text => $message } );
204             }
205              
206             sub _split_text_chunks
207             {
208 0     0     my ( $text, $maxlen, $on_chunk ) = @_;
209              
210 0           my $head = "<< ";
211 0           my $tail = " >>";
212              
213 0           while( length $text ) {
214 0 0         if( $maxlen >= length $text ) {
215 0           $on_chunk->( $text );
216 0           return;
217             }
218              
219 0           my $prefix = substr $text, 0, $maxlen - length( $tail );
220 0 0         if( $prefix =~ m/\s+\S+$/ ) {
221 0           substr( $prefix, $-[0] ) = "";
222             }
223              
224 0           $on_chunk->( $prefix . $tail );
225              
226 0           substr( $text, 0, length $prefix ) = "";
227 0           $text =~ s/^\s+//;
228 0           substr( $text, 0, 0 ) = $head;
229             }
230             }
231              
232             sub msg
233             {
234 0     0 0   my $self = shift;
235 0           my ( $text, %hints ) = @_;
236              
237 0           my $irc = $self->{irc};
238 0           my $net = $self->{net};
239              
240             my $event = {
241             text => Circle::TaggedString->new( $text ),
242             is_action => $hints{action},
243 0           };
244              
245 0           $net->run_rulechain( "output", $event );
246              
247 0           my $is_action = $event->{is_action};
248              
249             my $maxlen = 510 -
250             # To work out the maximum message length size we'd need to know our own
251             # prefix that the server will send. We can't know the host, but we know
252             # everything else. Just pretend it's maximal length, 64
253 0           ( length( $irc->{nick} ) + length( $irc->{user} ) + 64 + PREFIX_OVERHEAD );
254 0           my $target = $self->name;
255              
256 0           foreach my $line ( split m/\n/, $event->{text}->str ) {
257 0 0         if( $is_action ) {
258             _split_text_chunks( $line, $maxlen - length($target) - CTCP_ACTION_OVERHEAD, sub {
259 0     0     $irc->send_ctcp( undef, $target, "ACTION", $_[0] );
260 0           });
261             }
262             else {
263             _split_text_chunks( $line, $maxlen - length($target) - PRIVMSG_OVERHEAD, sub {
264 0     0     $irc->send_message( "PRIVMSG", undef, $target, $_[0] );
265 0           });
266             }
267              
268 0           my $line_formatted = $net->format_text( $line );
269              
270 0 0         $self->fire_event( $is_action ? "act" : "msg", $irc->nick, $line );
271 0 0         $self->push_displayevent( $is_action ? "irc.act" : "irc.msg", { target => $self->name, nick => $irc->nick, text => $line_formatted } );
272             }
273             }
274              
275             sub method_msg
276             {
277 0     0 0   my $self = shift; my $ctx = shift;
  0            
278 0           $self->msg( $_[0], action => 0 );
279             }
280              
281             sub notice
282             {
283 0     0 0   my $self = shift;
284 0           my ( $text ) = @_;
285              
286 0           my $irc = $self->{irc};
287 0           $irc->send_message( "NOTICE", undef, $self->name, $text );
288              
289 0           my $net = $self->{net};
290 0           my $text_formatted = $net->format_text( $text );
291              
292 0           $self->fire_event( "notice", $irc->nick, $text );
293 0           $self->push_displayevent( "irc.notice", { target => $self->name, nick => $irc->nick, text => $text_formatted } );
294             }
295              
296             sub method_notice
297             {
298 0     0 0   my $self = shift; my $ctx = shift;
  0            
299 0           $self->notice( @_ );
300             }
301              
302             sub method_act
303             {
304 0     0 0   my $self = shift; my $ctx = shift;
  0            
305 0           $self->msg( $_[0], action => 1 );
306             }
307              
308             sub command_say
309             : Command_description("Quote text directly as a PRIVMSG")
310             : Command_arg('text', eatall => 1)
311             {
312 0     0 0 0 my $self = shift;
313 0         0 my ( $text ) = @_;
314              
315 0         0 $self->msg( $text, action => 0 );
316              
317 0         0 return;
318 4     4   27 }
  4         8  
  4         18  
319              
320             sub command_me
321             : Command_description("Send a CTCP ACTION")
322             : Command_arg('text', eatall => 1)
323             {
324 0     0 0   my $self = shift;
325 0           my ( $text ) = @_;
326              
327 0           $self->msg( $text, action => 1 );
328              
329 0           return;
330 4     4   653 }
  4         8  
  4         13  
331              
332             sub commandable_parent
333             {
334 0     0 0   my $self = shift;
335 0           return $self->{net};
336             }
337              
338             sub enumerable_name
339             {
340 0     0 0   my $self = shift;
341 0           return $self->get_prop_tag;
342             }
343              
344             sub parent
345             {
346 0     0 0   my $self = shift;
347 0           return $self->{net};
348             }
349              
350             sub enter_text
351             {
352 0     0 0   my $self = shift;
353 0           my ( $text ) = @_;
354              
355 0 0         return unless length $text;
356              
357 0           $self->msg( $text );
358             }
359              
360             sub get_widget_commandentry
361             {
362 0     0 0   my $self = shift;
363 0           my $widget = $self->SUPER::get_widget_commandentry;
364              
365 0           $self->{net}->add_entry_widget_completegroups( $widget );
366              
367 0           return $widget;
368             }
369              
370             0x55AA;