| 1 | use strict; |
|---|
| 2 | use warnings; |
|---|
| 3 | use utf8; |
|---|
| 4 | |
|---|
| 5 | use Irssi; |
|---|
| 6 | |
|---|
| 7 | use Glib; |
|---|
| 8 | use POE::Sugar::Args; |
|---|
| 9 | use POE qw/Session::Irssi Loop::Glib/; |
|---|
| 10 | |
|---|
| 11 | use Encode; |
|---|
| 12 | use Mobirc; |
|---|
| 13 | use Mobirc::Util; |
|---|
| 14 | use Mobirc::HTTPD; |
|---|
| 15 | use Module::Reload; |
|---|
| 16 | use YAML::Syck; |
|---|
| 17 | |
|---|
| 18 | our %IRSSI = ( name => 'mobirc' ); |
|---|
| 19 | |
|---|
| 20 | Irssi::settings_add_str('mobirc', 'mobirc_config_path', ''); |
|---|
| 21 | Irssi::settings_add_bool('mobirc', 'mobirc_auto_start', 0); |
|---|
| 22 | |
|---|
| 23 | POE::Session::Irssi->create( |
|---|
| 24 | inline_states => { |
|---|
| 25 | map { ( $_ => __PACKAGE__->can("poe_$_") ) } |
|---|
| 26 | qw/_start load initialize_mobirc unload/ |
|---|
| 27 | }, |
|---|
| 28 | |
|---|
| 29 | irssi_commands => { |
|---|
| 30 | mobirc => sub { |
|---|
| 31 | my $poe = sweet_args; |
|---|
| 32 | my ($data, $server, $witem) = @{ $poe->args->[1] }; |
|---|
| 33 | |
|---|
| 34 | if (($data || '') =~ /start/) { |
|---|
| 35 | if ($poe->kernel->alias_resolve('mobirc_httpd')) { |
|---|
| 36 | Irssi::print('mobirc is already started!'); |
|---|
| 37 | return; |
|---|
| 38 | } |
|---|
| 39 | $poe->kernel->yield('load'); |
|---|
| 40 | } |
|---|
| 41 | elsif (($data || '') =~ /stop/) { |
|---|
| 42 | $poe->kernel->yield('unload'); |
|---|
| 43 | } |
|---|
| 44 | }, |
|---|
| 45 | }, |
|---|
| 46 | |
|---|
| 47 | irssi_signals => { |
|---|
| 48 | map( { ( "message $_" => bind_signal("irssi_$_") ) } |
|---|
| 49 | qw/public private own_public own_private join part quit kick nick own_nick invite topic/ |
|---|
| 50 | ), |
|---|
| 51 | map( { ( "message irc $_" => bind_signal("irssi_irc_$_") ) } |
|---|
| 52 | qw/op_public own_wall own_action action own_notice notice own_ctcp ctcp/ |
|---|
| 53 | ), |
|---|
| 54 | 'server event' => bind_signal('irssi_irc_snotice'), |
|---|
| 55 | 'print text' => bind_signal('irssi_print_text'), |
|---|
| 56 | 'command script unload' => \&script_unload, |
|---|
| 57 | }, |
|---|
| 58 | ); |
|---|
| 59 | |
|---|
| 60 | sub nick_name { |
|---|
| 61 | my $server = Irssi::active_server() or return ''; |
|---|
| 62 | $server->{nick}; |
|---|
| 63 | } |
|---|
| 64 | |
|---|
| 65 | sub bind_signal { |
|---|
| 66 | my $sub = __PACKAGE__->can(shift) or return; |
|---|
| 67 | |
|---|
| 68 | return sub { |
|---|
| 69 | return unless $_[KERNEL]->alias_resolve('mobirc_httpd'); |
|---|
| 70 | $sub->(@_); |
|---|
| 71 | }; |
|---|
| 72 | } |
|---|
| 73 | |
|---|
| 74 | sub poe__start { |
|---|
| 75 | my $poe = sweet_args; |
|---|
| 76 | |
|---|
| 77 | if (Irssi::settings_get_bool('mobirc_auto_start')) { |
|---|
| 78 | $poe->kernel->yield('load'); |
|---|
| 79 | } |
|---|
| 80 | } |
|---|
| 81 | |
|---|
| 82 | sub poe_load { |
|---|
| 83 | my $poe = sweet_args; |
|---|
| 84 | Module::Reload->check; |
|---|
| 85 | |
|---|
| 86 | my $mobirc = $poe->kernel->call( $poe->session, 'initialize_mobirc') |
|---|
| 87 | or return; |
|---|
| 88 | |
|---|
| 89 | # dummy irc session to handle post message from httpd |
|---|
| 90 | POE::Session->create( |
|---|
| 91 | inline_states => { |
|---|
| 92 | _start => sub { |
|---|
| 93 | $_[KERNEL]->alias_set('irc_session'); |
|---|
| 94 | }, |
|---|
| 95 | }, |
|---|
| 96 | heap => { |
|---|
| 97 | irc => __PACKAGE__, |
|---|
| 98 | config => { incode => 'utf-8' }, |
|---|
| 99 | }, |
|---|
| 100 | ); |
|---|
| 101 | |
|---|
| 102 | POE::Session->create( |
|---|
| 103 | inline_states => { |
|---|
| 104 | _start => sub { |
|---|
| 105 | $_[KERNEL]->alias_set('mobirc_irc'); |
|---|
| 106 | }, |
|---|
| 107 | |
|---|
| 108 | privmsg => sub { |
|---|
| 109 | my ($channel, $message) = @_[ARG0, ARG1]; |
|---|
| 110 | |
|---|
| 111 | ($channel) = grep { $_->{name} eq $channel } Irssi::channels(); |
|---|
| 112 | if ($channel) { |
|---|
| 113 | $channel->{server}->command("MSG $channel->{name} $message"); |
|---|
| 114 | } |
|---|
| 115 | }, |
|---|
| 116 | }, |
|---|
| 117 | ); |
|---|
| 118 | |
|---|
| 119 | Mobirc::HTTPD->init($mobirc->config); |
|---|
| 120 | Irssi::print('started mobirc') if $poe->kernel->alias_resolve('mobirc_httpd'); |
|---|
| 121 | } |
|---|
| 122 | |
|---|
| 123 | sub irssi_print_text { |
|---|
| 124 | my $poe = sweet_args; |
|---|
| 125 | my ($dest, $text, $stripped) = @{ $poe->args->[1] }; |
|---|
| 126 | |
|---|
| 127 | if ($dest->{level} & MSGLEVEL_HILIGHT) { |
|---|
| 128 | Mobirc::Channel->update_keyword_buffer($poe->heap->{mobirc}, $poe->heap->{__last_row}); |
|---|
| 129 | } |
|---|
| 130 | } |
|---|
| 131 | |
|---|
| 132 | sub irssi_public { |
|---|
| 133 | my $poe = sweet_args; |
|---|
| 134 | my ($server, $msg, $nick, $address, $target) = @{ $poe->args->[1] }; |
|---|
| 135 | |
|---|
| 136 | add_message( $poe, $target, $nick, $msg, 'public' ); |
|---|
| 137 | } |
|---|
| 138 | |
|---|
| 139 | sub irssi_private {} |
|---|
| 140 | |
|---|
| 141 | sub irssi_own_public { |
|---|
| 142 | my $poe = sweet_args; |
|---|
| 143 | my ($server, $msg, $target) = @{ $poe->args->[1] }; |
|---|
| 144 | |
|---|
| 145 | add_message( $poe, $target, $server->{nick}, $msg, 'public' ); |
|---|
| 146 | } |
|---|
| 147 | sub irssi_own_private {} |
|---|
| 148 | |
|---|
| 149 | sub irssi_join { |
|---|
| 150 | my $poe = sweet_args; |
|---|
| 151 | my ($server, $channel, $nick, $address) = @{ $poe->args->[1] }; |
|---|
| 152 | |
|---|
| 153 | my $mobirc = $poe->heap->{mobirc}; |
|---|
| 154 | |
|---|
| 155 | $channel = decode('utf-8', $channel); |
|---|
| 156 | $channel = $mobirc->get_channel($channel) |
|---|
| 157 | || $mobirc->add_channel( Mobirc::Channel->new($poe->heap->{mobirc}, normalize_channel_name($channel) ) ); |
|---|
| 158 | |
|---|
| 159 | unless ($server->{nick} eq $nick) { |
|---|
| 160 | add_message( $poe, $channel, undef, "$nick joined", 'join'); |
|---|
| 161 | } |
|---|
| 162 | } |
|---|
| 163 | |
|---|
| 164 | sub irssi_part { |
|---|
| 165 | my $poe = sweet_args; |
|---|
| 166 | my ($server, $channel, $nick, $address, $reason) = @{ $poe->args->[1] }; |
|---|
| 167 | |
|---|
| 168 | my $mobirc = $poe->heap->{mobirc}; |
|---|
| 169 | |
|---|
| 170 | $channel = normalize_channel_name( decode('utf-8', $channel) ); |
|---|
| 171 | if ($server->{nick} eq $nick) { |
|---|
| 172 | delete $mobirc->{channels}->{$channel}; |
|---|
| 173 | } |
|---|
| 174 | else { |
|---|
| 175 | add_message($poe, $channel, undef, "$nick leaves", 'leave'); |
|---|
| 176 | } |
|---|
| 177 | } |
|---|
| 178 | |
|---|
| 179 | sub irssi_quit {} |
|---|
| 180 | sub irssi_kick {} |
|---|
| 181 | sub irssi_nick {} |
|---|
| 182 | sub irssi_own_nick {} |
|---|
| 183 | sub irssi_invite {} |
|---|
| 184 | |
|---|
| 185 | sub irssi_topic { |
|---|
| 186 | my $poe = sweet_args; |
|---|
| 187 | my ($server, $channel, $topic, $nick, $address) = @{ $poe->args->[1] }; |
|---|
| 188 | |
|---|
| 189 | my $mobirc = $poe->heap->{mobirc}; |
|---|
| 190 | |
|---|
| 191 | $channel = $mobirc->get_channel( normalize_channel_name(decode('utf-8', $channel)) ); |
|---|
| 192 | $channel->topic( decode('utf-8', $topic) ); |
|---|
| 193 | |
|---|
| 194 | add_message($poe, $channel, undef, "$nick set topic: $topic", 'topic'); |
|---|
| 195 | } |
|---|
| 196 | |
|---|
| 197 | sub irssi_irc_op_public {} |
|---|
| 198 | sub irssi_irc_own_wall {} |
|---|
| 199 | |
|---|
| 200 | sub irssi_irc_own_action { |
|---|
| 201 | my $poe = sweet_args; |
|---|
| 202 | my ($server, $msg, $target) = @{ $poe->args->[1] }; |
|---|
| 203 | |
|---|
| 204 | $msg = sprintf('* %s %s', $server->{nick}, decode('utf-8', $msg)); |
|---|
| 205 | add_message( $poe, $target, '', $msg, 'ctcp_action'); |
|---|
| 206 | } |
|---|
| 207 | |
|---|
| 208 | sub irssi_irc_action { |
|---|
| 209 | my $poe = sweet_args; |
|---|
| 210 | my ($server, $msg, $nick, $address, $target) = @{ $poe->args->[1] }; |
|---|
| 211 | |
|---|
| 212 | $msg = sprintf('* %s %s', $nick, decode('utf-8', $msg)); |
|---|
| 213 | add_message( $poe, $target, '', $msg, 'ctcp_action'); |
|---|
| 214 | } |
|---|
| 215 | |
|---|
| 216 | sub irssi_irc_own_notice { |
|---|
| 217 | my $poe = sweet_args; |
|---|
| 218 | my ($server, $msg, $target) = @{ $poe->args->[1] }; |
|---|
| 219 | |
|---|
| 220 | add_message($poe, $target, $server->{nick}, $msg, 'notice'); |
|---|
| 221 | } |
|---|
| 222 | |
|---|
| 223 | sub irssi_irc_notice { |
|---|
| 224 | my $poe = sweet_args; |
|---|
| 225 | my ($server, $msg, $nick, $address, $target) = @{ $poe->args->[1] }; |
|---|
| 226 | |
|---|
| 227 | add_message($poe, $target, $nick, $msg, 'notice'); |
|---|
| 228 | } |
|---|
| 229 | |
|---|
| 230 | sub irssi_irc_snotice { |
|---|
| 231 | my $poe = sweet_args; |
|---|
| 232 | my ($server, $msg, $nick, $address, $target) = @{ $poe->args->[1] }; |
|---|
| 233 | return unless $msg =~ /^\d/; # messages only |
|---|
| 234 | |
|---|
| 235 | add_message($poe, '*server*', undef, $msg, 'snotice'); |
|---|
| 236 | } |
|---|
| 237 | sub irssi_irc_own_ctcp {} |
|---|
| 238 | sub irssi_irc_ctcp {} |
|---|
| 239 | |
|---|
| 240 | sub poe_initialize_mobirc { |
|---|
| 241 | my $poe = sweet_args; |
|---|
| 242 | |
|---|
| 243 | delete $poe->heap->{mobirc} if $poe->heap->{mobirc}; |
|---|
| 244 | |
|---|
| 245 | my $conffname = Irssi::settings_get_str('mobirc_config_path'); |
|---|
| 246 | unless ($conffname) { |
|---|
| 247 | Irssi::print('mobirc_config_path is not defined, please do "/set mobirc_config_path your_yaml_path" first'); |
|---|
| 248 | return; |
|---|
| 249 | } |
|---|
| 250 | unless (-f $conffname && -r _) { |
|---|
| 251 | Irssi::print("file does not exist: $conffname"); |
|---|
| 252 | return; |
|---|
| 253 | } |
|---|
| 254 | |
|---|
| 255 | my $mobirc; |
|---|
| 256 | eval { $mobirc = Mobirc->new($conffname) }; |
|---|
| 257 | if ($@) { |
|---|
| 258 | Irssi::print("can't initialize mobirc: $@"); |
|---|
| 259 | return; |
|---|
| 260 | } |
|---|
| 261 | |
|---|
| 262 | # httpd echo mode is disable |
|---|
| 263 | $mobirc->config->{httpd}->{echo} = false; |
|---|
| 264 | $poe->heap->{mobirc} = $mobirc; |
|---|
| 265 | $poe->heap->{config} = $mobirc->config; |
|---|
| 266 | |
|---|
| 267 | $mobirc->add_channel( Mobirc::Channel->new($mobirc, '*server*') ); |
|---|
| 268 | for my $channel (Irssi::channels()) { |
|---|
| 269 | my $channel_name = normalize_channel_name(decode('utf-8', $channel)); |
|---|
| 270 | $mobirc->add_channel( Mobirc::Channel->new($mobirc, $channel_name) ); |
|---|
| 271 | } |
|---|
| 272 | |
|---|
| 273 | $mobirc; |
|---|
| 274 | } |
|---|
| 275 | |
|---|
| 276 | sub poe_unload { |
|---|
| 277 | my $kernel = $_[KERNEL]; |
|---|
| 278 | |
|---|
| 279 | if (my $httpd_session = $kernel->alias_resolve('mobirc_httpd')) { |
|---|
| 280 | $kernel->call( $httpd_session => 'shutdown' ); |
|---|
| 281 | delete $_[HEAP]->{mobirc}; |
|---|
| 282 | Irssi::print('stopped mobirc'); |
|---|
| 283 | } |
|---|
| 284 | } |
|---|
| 285 | |
|---|
| 286 | sub script_unload { |
|---|
| 287 | my ($kernel, $session, $args) = @_[KERNEL, SESSION, ARG1]; |
|---|
| 288 | my ($script) = @$args; |
|---|
| 289 | |
|---|
| 290 | if ($script =~ /mobirc/) { |
|---|
| 291 | $kernel->call($session, 'unload'); |
|---|
| 292 | } |
|---|
| 293 | } |
|---|
| 294 | |
|---|
| 295 | # XXX: to avoid weird warnings |
|---|
| 296 | { package Irssi::Nick } |
|---|
| 297 | |
|---|
| 298 | { |
|---|
| 299 | no warnings 'redefine'; |
|---|
| 300 | sub add_message { |
|---|
| 301 | my ($poe, @args) = @_; |
|---|
| 302 | for my $arg (@args) { |
|---|
| 303 | $arg = decode('utf-8', $arg) unless utf8::is_utf8($arg); |
|---|
| 304 | } |
|---|
| 305 | my ($channel, $who, $body, $class) = @args; |
|---|
| 306 | |
|---|
| 307 | $channel = $poe->heap->{mobirc}->get_channel(normalize_channel_name($channel)) |
|---|
| 308 | or return; |
|---|
| 309 | |
|---|
| 310 | my $message = Mobirc::Message->new( |
|---|
| 311 | who => $who, |
|---|
| 312 | body => $body, |
|---|
| 313 | class => $class, |
|---|
| 314 | ); |
|---|
| 315 | $channel->add_message($poe->heap->{__last_row} = $message); |
|---|
| 316 | } |
|---|
| 317 | } |
|---|
| 318 | |
|---|
| 319 | =pod |
|---|
| 320 | |
|---|
| 321 | =head1 NAME |
|---|
| 322 | |
|---|
| 323 | mobirc.pl - irssi plugin for Mobirc |
|---|
| 324 | |
|---|
| 325 | =head1 SYNOPSIS |
|---|
| 326 | |
|---|
| 327 | 1.. copy (or link) this script into irssi script directory |
|---|
| 328 | |
|---|
| 329 | 2. run irssi with Mobirc |
|---|
| 330 | |
|---|
| 331 | PERL5LIB=/path/to/mobirc/lib irssi |
|---|
| 332 | |
|---|
| 333 | 3. start script in irssi |
|---|
| 334 | |
|---|
| 335 | /run mobirc |
|---|
| 336 | |
|---|
| 337 | 4. set config.yaml path |
|---|
| 338 | |
|---|
| 339 | /set mobirc_config_path /path/to/your/config.yaml |
|---|
| 340 | |
|---|
| 341 | 5. start mobirc |
|---|
| 342 | |
|---|
| 343 | /mobirc start |
|---|
| 344 | |
|---|
| 345 | =head1 AUTHOR |
|---|
| 346 | |
|---|
| 347 | Daisuke Murase <typester@cpan.org> |
|---|
| 348 | |
|---|
| 349 | Kazuhiro Osawa |
|---|
| 350 | |
|---|
| 351 | =cut |
|---|
| 352 | |
|---|
| 353 | |
|---|