root/lang/perl/mobirc/trunk/lib/App/Mobirc/Plugin/Component/IRCClient.pm @ 12148

Revision 12148, 11.6 kB (checked in by tokuhirom, 5 years ago)

mvoe models to Model:: namespace

Line 
1package App::Mobirc::Plugin::Component::IRCClient;
2use strict;
3use warnings;
4
5use POE;
6use POE::Sugar::Args;
7use POE::Component::IRC;
8
9use Encode;
10use Carp;
11
12use App::Mobirc::Model::Message;
13use App::Mobirc::Util;
14
15sub register {
16    my ($class, $global_context, $conf) = @_;
17
18    DEBUG "register ircclient component";
19    $conf->{ping_delay}       ||= 30;
20    $conf->{reconnect_delay}  ||= 10;
21
22    $global_context->register_hook(
23        'run_component' => sub { _init($conf, shift) },
24    );
25    $global_context->register_hook(
26        'process_command' => sub { my ($global_context, $command, $channel) = @_;  _process_command($conf, $global_context, $command, $channel) },
27    );
28}
29
30sub _process_command {
31    my ($conf, $global_context, $command, $channel) = @_;
32
33    my $irc_incode = $conf->{incode};
34    if ($command && $channel->name =~ /^[#*%]/) {
35        if ($command =~ m{^/}) {
36            DEBUG "SENDING COMMAND";
37            $command =~ s!^/!!g;
38
39            my @args =
40              map { encode( $irc_incode, $_ ) } split /\s+/,
41              $command;
42
43            $poe_kernel->post('mobirc_irc', @args);
44        } else {
45            DEBUG "NORMAL PRIVMSG";
46
47            $poe_kernel->post( 'mobirc_irc',
48                privmsg => encode( $irc_incode, $channel->name ) =>
49                encode( $irc_incode, $command ) );
50
51            DEBUG "Sending command $command";
52            # FIXME: httpd $B4X78$J$$7o(B
53            if ($global_context->config->{httpd}->{echo} eq true) {
54                $channel->add_message(
55                    App::Mobirc::Model::Message->new(
56                        who => decode(
57                            $irc_incode,
58                            $poe_kernel->alias_resolve('irc_session')->get_heap->{irc}->nick_name
59                        ),
60                        body  => $command,
61                        class => 'public',
62                    )
63                );
64            }
65        }
66        return true;
67    }
68    return false;
69}
70
71sub _init {
72    my ($config, $global_context) = @_;
73
74    DEBUG "initialize ircclient";
75    # irc component
76    my $irc = POE::Component::IRC->spawn(
77        Alias    => 'mobirc_irc',
78        Nick     => $config->{nick},
79        Username => $config->{username},
80        Ircname  => $config->{desc},
81        Server   => $config->{server},
82        Port     => $config->{port},
83        Password => $config->{password}
84    );
85
86    POE::Session->create(
87        heap => {
88            seen_traffic   => false,
89            disconnect_msg => true,
90            config         => $config,
91            irc            => $irc,
92            global_context => $global_context,
93        },
94        inline_states => {
95            _start           => \&on_irc_start,
96            _default         => \&on_irc_default,
97
98            irc_001          => \&on_irc_001,
99            irc_join         => \&on_irc_join,
100            irc_part         => \&on_irc_part,
101            irc_public       => \&on_irc_public,
102            irc_notice       => \&on_irc_notice,
103            irc_topic        => \&on_irc_topic,
104            irc_332          => \&on_irc_topicraw,
105            irc_ctcp_action  => \&on_irc_ctcp_action,
106            irc_kick         => \&on_irc_kick,
107            irc_snotice      => \&on_irc_snotice,
108
109            autoping         => \&do_autoping,
110            connect          => \&do_connect,
111
112            irc_disconnected => \&on_irc_reconnect,
113            irc_error        => \&on_irc_reconnect,
114            irc_socketerr    => \&on_irc_reconnect,
115        }
116    );
117
118    $global_context->add_channel(
119        App::Mobirc::Model::Channel->new($global_context, U('*server*'))
120    );
121}
122
123# -------------------------------------------------------------------------
124
125sub on_irc_default {
126    DEBUG "ignore unknown event: $_[ARG0]";
127}
128
129sub on_irc_start {
130    my $poe = sweet_args;
131    DEBUG "START";
132
133    $poe->kernel->alias_set('irc_session');
134
135    DEBUG "input charset is: " . $poe->heap->{config}->{incode};
136
137    $poe->heap->{irc}->yield( register => 'all' );
138    $poe->heap->{irc}->yield( connect  => {} );
139}
140
141sub on_irc_001 {
142    my $poe = sweet_args;
143
144    DEBUG "CONNECTED";
145
146    my $channel = $poe->heap->{global_context}->get_channel(decode( 'utf8', '*server*' ));
147    $channel->add_message(
148        App::Mobirc::Model::Message->new(
149            who   => undef,
150            body  => decode('utf8', 'Connected to irc server!'),
151            class => 'connect',
152        )
153    );
154
155    $poe->heap->{disconnect_msg} = true;
156    $poe->kernel->delay( autoping => $poe->heap->{config}->{ping_delay} );
157}
158
159sub on_irc_join {
160    my $poe = sweet_args;
161
162    DEBUG "JOIN";
163
164    my ($who, $channel_name) = _get_args($poe);
165
166    $who =~ s/!.*//;
167
168    # chop off after the gap (bug workaround of madoka)
169    $channel_name =~ s/ .*//;
170    $channel_name = normalize_channel_name($channel_name);
171
172    # create channel
173    my $channel = $poe->heap->{global_context}->get_channel($channel_name);
174    unless ($channel) {
175        $channel = App::Mobirc::Model::Channel->new(
176            $poe->heap->{global_context},
177            $channel_name,
178        );
179        $poe->heap->{global_context}->add_channel( $channel );
180    }
181
182    my $irc = $poe->heap->{irc};
183    unless ( $who eq $irc->nick_name ) {
184        $channel->add_message(
185            App::Mobirc::Model::Message->new(
186                who   => undef,
187                body  => $who . U(" joined"),
188                class => 'join',
189            )
190        );
191    }
192    $poe->heap->{seen_traffic}   = true;
193    $poe->heap->{disconnect_msg} = true;
194}
195
196sub on_irc_part {
197    my $poe = sweet_args;
198
199    my ($who, $channel_name, $msg) = _get_args($poe);
200
201    $who =~ s/!.*//;
202
203    # chop off after the gap (bug workaround of POE::Filter::IRC)
204    $channel_name =~ s/ .*//;
205    $channel_name = normalize_channel_name($channel_name);
206
207    my $irc = $poe->heap->{irc};
208    if ( $who eq $irc->nick_name ) {
209        $poe->heap->{global_context}->delete_channel($channel_name);
210    }
211    else {
212        my $message = "$who leaves";
213        if ($msg) {
214            $message .= "($msg)";
215        }
216
217        my $channel = $poe->heap->{global_context}->get_channel($channel_name);
218        $channel->add_message(
219            App::Mobirc::Model::Message->new(
220                who   => undef,
221                body  => $message,
222                class => 'leave',
223            )
224        );
225    }
226    $poe->heap->{seen_traffic}   = true;
227    $poe->heap->{disconnect_msg} = true;
228}
229
230sub on_irc_public {
231    my $poe = sweet_args;
232
233    DEBUG "IRC PUBLIC";
234
235    my ($who, $channel_name, $msg) = _get_args($poe);
236
237    $who =~ s/!.*//;
238
239    $channel_name = $channel_name->[0];
240    $channel_name = normalize_channel_name($channel_name);
241
242    my $channel = $poe->heap->{global_context}->get_channel($channel_name);
243    $channel->add_message(
244        App::Mobirc::Model::Message->new(
245            who   => $who,
246            body  => $msg,
247            class => 'public',
248        )
249    );
250    my $irc = $poe->heap->{irc};
251    if ( $who eq $irc->nick_name ) {
252        DEBUG "CLEAR UNREAD";
253        $channel->clear_unread;
254    }
255
256    $poe->heap->{seen_traffic}   = true;
257    $poe->heap->{disconnect_msg} = true;
258}
259
260sub on_irc_notice {
261    my $poe = sweet_args;
262
263    my ($who, $channel_name, $msg) = _get_args($poe);
264
265    DEBUG "IRC NOTICE $who $channel_name $msg";
266
267    for my $code (@{ $poe->heap->{global_context}->get_hook_codes('on_irc_notice') }) {
268        my $finished = $code->($poe, $who, $channel_name, $msg);
269        return if $finished;
270    }
271
272    $who =~ s/!.*//;
273    $channel_name = $channel_name->[0];
274    $channel_name = normalize_channel_name($channel_name);
275
276    my $channel = $poe->heap->{global_context}->get_channel($channel_name);
277    $channel->add_message(
278        App::Mobirc::Model::Message->new(
279            who   => $who,
280            body  => $msg,
281            class => 'notice',
282        )
283    );
284    $poe->heap->{seen_traffic}   = true;
285    $poe->heap->{disconnect_msg} = true;
286}
287
288sub on_irc_topic {
289    my $poe = sweet_args;
290
291    my ($who, $channel_name, $topic) = _get_args($poe);
292
293    $who =~ s/!.*//;
294
295    DEBUG "SET TOPIC";
296    $channel_name = normalize_channel_name($channel_name);
297
298    my $channel = $poe->heap->{global_context}->get_channel($channel_name);
299    $channel->topic($topic);
300    $channel->add_message(
301        App::Mobirc::Model::Message->new(
302            who   => undef,
303            body  => "$who set topic: $topic",
304            class => 'topic',
305        )
306    );
307
308    $poe->heap->{seen_traffic}                  = true;
309    $poe->heap->{disconnect_msg}                = true;
310}
311
312sub on_irc_topicraw {
313    my $poe = sweet_args;
314
315    my ($x, $y, $dat) = _get_args($poe);
316
317    my ( $channel, $topic ) = @{$dat};
318
319    DEBUG "SET TOPIC RAW: $channel => $topic";
320
321    $poe->heap->{global_context}->get_channel(normalize_channel_name($channel))->topic($topic);
322    $poe->heap->{seen_traffic}                  = true;
323    $poe->heap->{disconnect_msg}                = true;
324}
325
326sub on_irc_ctcp_action {
327    my $poe = sweet_args;
328
329    my ($who, $channel_name, $msg) = _get_args($poe);
330
331    $who =~ s/!.*//;
332    $channel_name = $channel_name->[0];
333
334    my $channel = $poe->heap->{global_context}->get_channel($channel_name);
335    my $body = sprintf(decode('utf8', "* %s %s"), $who, $msg);
336    $channel->add_message(
337        App::Mobirc::Model::Message->new(
338            who   => undef,
339            body  => $body,
340            class => 'ctcp_action',
341        )
342    );
343
344    $poe->heap->{seen_traffic}   = true;
345    $poe->heap->{disconnect_msg} = true;
346}
347
348sub on_irc_kick {
349    my $poe = sweet_args;
350
351    DEBUG "DNBKICK";
352
353    my ($kicker, $channel_name, $kickee, $msg) = _get_args($poe);
354    $msg ||= 'Flooder';
355
356    $kicker =~ s/!.*//;
357
358    $poe->heap->{global_context}->get_channel($channel_name)->add_message(
359        App::Mobirc::Model::Message->new(
360            who   => undef,
361            body  => "$kicker has kicked $kickee($msg)",
362            class => 'kick',
363        )
364    );
365
366    $poe->heap->{seen_traffic}   = true;
367    $poe->heap->{disconnect_msg} = true;
368}
369
370sub do_connect {
371    my $poe = sweet_args;
372
373    $poe->heap->{irc}->yield( connect => {} );
374}
375
376sub do_autoping {
377    my $poe = sweet_args;
378
379    $poe->kernel->post( mobirc_irc => time ) unless $poe->heap->{seen_traffic};
380    $poe->heap->{seen_traffic} = false;
381    $poe->kernel->delay( autoping => $poe->heap->{config}->{ping_delay} );
382}
383
384sub on_irc_snotice {
385    my $poe = sweet_args;
386
387    my ($message, ) = _get_args($poe);
388
389    DEBUG "getting snotice : $message";
390
391    my $channel = $poe->heap->{global_context}->get_channel(U('*server*' ));
392    $channel->add_message(
393        App::Mobirc::Model::Message->new(
394            who   => undef,
395            body  => $message,
396            class => 'snotice',
397        )
398    );
399}
400
401sub on_irc_reconnect {
402    my $poe = sweet_args;
403
404    DEBUG "!RECONNECT! " . $poe->heap->{disconnect_msg};
405    if ( $poe->heap->{disconnect_msg} ) {
406        my $channel = $poe->heap->{global_context}->get_channel(decode( 'utf8', '*server*' ));
407        $channel->add_message(
408            App::Mobirc::Model::Message->new(
409                who   => undef,
410                body  => decode( 'utf8', 'Disconnected from irc server, trying to reconnect...'),
411                class => 'reconnect',
412            )
413        );
414    }
415    $poe->heap->{disconnect_msg} = false;
416    $poe->kernel->delay( connect => $poe->heap->{config}->{reconnect_delay} );
417}
418
419# FIXME: I want more cool implement
420sub _get_args {
421    my $poe = shift;
422
423    my @ret;
424    for my $elem (@{$poe->args}) {
425        if ( ref $elem && ref $elem eq 'ARRAY') {
426            push @ret, [map { decode($poe->heap->{config}->{incode}, $_) } @$elem];
427        } else {
428            push @ret, decode($poe->heap->{config}->{incode}, $elem);
429        }
430    }
431    return @ret;
432}
433
4341;
Note: See TracBrowser for help on using the browser.