archive- Random tools & helpful resources for IRC |
git clone git://git.acid.vegas/archive.git |
Log | Files | Refs | Archive |
parrot.pl (11976B)
1 use strict; 2 use warnings; 3 4 no strict 'subs'; 5 6 my $SCRIPT_NAME = 'parrot'; 7 my $SCRIPT_AUTHOR = 'The Krusty Krab <wowaname@volatile.ch>'; 8 my $SCRIPT_VERSION = '1.0'; 9 my $SCRIPT_LICENCE = 'Public domain'; 10 my $SCRIPT_DESC = 'Relay channel messages and modes'; 11 12 # %cbs{server}{hook_name} = $hook_ptr: 13 # stores hook pointers to unhook() on exit 14 # %chans{server}{channel} = @groups: 15 # stores groups associated with a channel 16 # %groups{groupname}{server}{channel} = $flags: 17 # stores channels associated with a group, as well as the channel's flags 18 # $READ, $STAT, $MODE: 19 # flags for -read, -stat, -mode switches 20 our (%cbs, %chans, %groups); 21 our ($READ, $STAT, $MODE) = (0x1, 0x2, 0x4); 22 our $confpath; 23 24 sub servchan 25 { 26 my $buffer = shift; 27 return (lc weechat::buffer_get_string($buffer, 'localvar_server'), 28 lc weechat::buffer_get_string($buffer, 'localvar_channel')); 29 } 30 31 sub ircbuf { weechat::buffer_search('irc', "(?i)".(join '.', @_)) } 32 33 sub getgroup 34 { 35 my ($server, $channel) = @_; 36 my @ret; 37 38 for my $group (@{ $chans{$server}{$channel} }) { 39 for my $to_serv (keys %{ $groups{$group} }) { 40 for my $to_chan (keys %{ $groups{$group}{$to_serv} }) { 41 # don't send to myself 42 next if $to_serv eq $server and $to_chan eq $channel; 43 push @ret, [$to_serv, $to_chan, $groups{$group}{$to_serv}{$to_chan}, $group] 44 } } } 45 46 return @ret; 47 } 48 49 sub sendto 50 { 51 my ($server, $command) = @_; 52 weechat::hook_signal_send('irc_input_send', 53 weechat::WEECHAT_HOOK_SIGNAL_STRING, 54 "$server;;1;;$command"); 55 } 56 57 sub add_relay 58 { 59 my ($groupname, $server, $channel, $flags) = @_; 60 return if exists $cbs{$server}; 61 push @{ $chans{$server}{$channel} }, $groupname; 62 $groups{$groupname}{$server}{$channel} = $flags; 63 $cbs{$server}{PRIVMSG} = 64 weechat::hook_signal("$server,irc_raw_in_privmsg", 'irc_privmsg_notice', ''); 65 $cbs{$server}{NOTICE} = 66 weechat::hook_signal("$server,irc_raw_in_notice", 'irc_privmsg_notice', ''); 67 $cbs{$server}{OUT_PRIVMSG} = 68 weechat::hook_signal("$server,irc_out1_privmsg", 'ircout_privmsg_notice', ''); 69 $cbs{$server}{OUT_NOTICE} = 70 weechat::hook_signal("$server,irc_out1_notice", 'ircout_privmsg_notice', ''); 71 if ($flags & $STAT) { 72 $cbs{$server}{JOIN} = 73 weechat::hook_signal("$server,irc_raw_in_join", 'irc_join', ''); 74 $cbs{$server}{PART} = 75 weechat::hook_signal("$server,irc_raw_in_part", 'irc_part', ''); 76 $cbs{$server}{KICK} = 77 weechat::hook_signal("$server,irc_raw_in_kick", 'irc_kick', ''); 78 $cbs{$server}{NICK} = 79 weechat::hook_signal("$server,irc_raw_in_nick", 'irc_nick', ''); 80 $cbs{$server}{QUIT} = 81 weechat::hook_signal("$server,irc_raw_in_quit", 'irc_quit', ''); 82 } 83 if ($flags & $MODE) { 84 # $cbs{$server}{MODE} = 85 # weechat::hook_signal("$server,irc_raw_in_mode", 'irc_mode', ''); 86 $cbs{$server}{TOPIC} = 87 weechat::hook_signal("$server,irc_raw_in_topic", 'irc_topic', ''); 88 } 89 } 90 91 sub read_conf 92 { 93 open FH, '<', $confpath or weechat::print('', weechat::prefix('error'). 94 "Error opening $confpath for reading: $!"), return; 95 while (<FH>) { 96 chomp; 97 add_relay(split ' '); 98 } 99 close FH; 100 } 101 102 sub write_conf 103 { 104 open FH, '>', $confpath or weechat::print('', weechat::prefix('error'). 105 "Error opening $confpath for writing: $!"), return; 106 for my $server (keys %chans) { 107 for my $channel (keys %{ $chans{$server} }) { 108 for my $group (@{ $chans{$server}{$channel} }) { 109 my $flags = $groups{$group}{$server}{$channel}; 110 print FH "$group $server $channel $flags\n"; 111 } } } 112 close FH; 113 } 114 115 sub irc_privmsg_notice 116 { 117 my (undef, $server, $cmd, $nick, $channel, $message) = (shift, 118 shift =~ /(.+),irc_raw_in_(privmsg|notice)/i, 119 shift =~ /:([^! ]*)[^ ]* [^ ]+ ([^ ]+) :?(.*)/i); 120 ($server, $channel) = (lc $server, lc $channel); 121 return weechat::WEECHAT_RC_OK unless exists $chans{$server}{$channel}; 122 123 for (getgroup($server, $channel)) { 124 my ($to_serv, $to_chan, $flags, undef) = @$_; 125 next if $flags & $READ; 126 next unless ircbuf("$to_serv.$to_chan"); 127 if ($message =~ /^\x01ACTION /i) { 128 $message =~ s/^\x01ACTION |\x01$//g; 129 sendto($to_serv, "/msg $to_chan * \x02$nick\x0f $message"); 130 next; 131 } 132 my $prefix = lc $cmd eq 'notice' ? "[\x02$nick\x0f]" : "<\x02$nick\x0f>"; 133 sendto($to_serv, "/msg $to_chan $prefix $message"); 134 } 135 136 return weechat::WEECHAT_RC_OK; 137 } 138 139 sub ircout_privmsg_notice 140 { 141 my (undef, $server, $cmd, $channel, $message) = (shift, 142 shift =~ /(.*),irc_out1_(privmsg|notice)/i, 143 shift =~ /[^ ]+ ([^ ]+) :?(.*)/i); 144 ($server, $channel) = (lc $server, lc $channel); 145 return weechat::WEECHAT_RC_OK unless exists $chans{$server}{$channel}; 146 147 for (getgroup($server, $channel)) { 148 my ($to_serv, $to_chan, $flags, undef) = @$_; 149 next if $flags & $READ; 150 next unless ircbuf("$to_serv.$to_chan"); 151 my $prefix = lc $cmd eq 'notice' ? 'notice' : 'msg'; 152 if ($message =~ /^\x01ACTION /i) { 153 $message =~ s/^\x01ACTION |\x01$//g; 154 sendto($to_serv, "/$prefix $to_chan \x01ACTION $message\x01"); 155 next; 156 } 157 sendto($to_serv, "/$prefix $to_chan $message"); 158 } 159 160 return weechat::WEECHAT_RC_OK; 161 } 162 163 sub irc_join 164 { 165 my (undef, $server, $nick, $host, $channel) = (shift, 166 shift =~ /(.+),irc_raw_in_join/i, 167 shift =~ /:([^! ]*)([^ ]*) join :?([^ ]+)/i); 168 ($server, $channel) = (lc $server, lc $channel); 169 return weechat::WEECHAT_RC_OK unless exists $chans{$server}{$channel}; 170 171 for (getgroup($server, $channel)) { 172 my ($to_serv, $to_chan, $flags, undef) = @$_; 173 next unless $flags & $STAT; 174 next if $flags & $READ; 175 next unless ircbuf("$to_serv.$to_chan"); 176 sendto($to_serv, "/notice $to_chan \x02$nick\x0f$host joined $server/$channel\x0f"); 177 } 178 179 return weechat::WEECHAT_RC_OK; 180 } 181 182 sub irc_part 183 { 184 my (undef, $server, $nick, $channel, $message) = (shift, 185 shift =~ /(.+),irc_raw_in_part/i, 186 shift =~ /:([^! ]*)[^ ]* part ([^ ]+) ?:?(.*)/i); 187 ($server, $channel) = (lc $server, lc $channel); 188 return weechat::WEECHAT_RC_OK unless exists $chans{$server}{$channel}; 189 190 for (getgroup($server, $channel)) { 191 my ($to_serv, $to_chan, $flags, undef) = @$_; 192 next unless $flags & $STAT; 193 next if $flags & $READ; 194 next unless ircbuf("$to_serv.$to_chan"); 195 sendto($to_serv, "/notice $to_chan \x02$nick\x0f left $server/$channel\x0f: $message"); 196 } 197 198 return weechat::WEECHAT_RC_OK; 199 } 200 201 sub irc_kick 202 { 203 my (undef, $server, $nick, $channel, $target, $message) = (shift, 204 shift =~ /(.+),irc_raw_in_kick/i, 205 shift =~ /:([^! ]*)[^ ]* kick ([^ ]+) ([^ ]+) :?(.*)/i); 206 ($server, $channel) = (lc $server, lc $channel); 207 return weechat::WEECHAT_RC_OK unless exists $chans{$server}{$channel}; 208 209 for (getgroup($server, $channel)) { 210 my ($to_serv, $to_chan, $flags, undef) = @$_; 211 next unless $flags & $STAT; 212 next if $flags & $READ; 213 next unless ircbuf("$to_serv.$to_chan"); 214 sendto($to_serv, "/notice $to_chan \x02$nick\x0f kicked $target\x0f from $server/$channel\x0f: $message"); 215 } 216 217 return weechat::WEECHAT_RC_OK; 218 } 219 220 sub irc_nick 221 { 222 my (undef, $server, $nick, $newnick) = (shift, 223 shift =~ /(.+),irc_raw_in_nick/i, 224 shift =~ /:([^! ]*)[^ ]* nick :?(.*)/i); 225 226 for my $channel (keys %{ $chans{$server} }) { 227 my $iptr = weechat::infolist_get('irc_nick', '', "$server,$channel,$nick"); 228 next unless $iptr; 229 weechat::infolist_free($iptr); 230 for (getgroup($server, $channel)) { 231 my ($to_serv, $to_chan, $flags, undef) = @$_; 232 next unless $flags & $STAT; 233 next if $flags & $READ; 234 next unless ircbuf("$to_serv.$to_chan"); 235 sendto($to_serv, "/notice $to_chan \x02$nick\x0f is now \x02$newnick\x0f"); 236 } } 237 238 return weechat::WEECHAT_RC_OK; 239 } 240 241 sub irc_quit 242 { 243 my (undef, $server, $nick, $message) = (shift, 244 shift =~ /(.+),irc_raw_in_quit/i, 245 shift =~ /:([^! ]*)[^ ]* quit :?(.*)/i); 246 247 for my $channel (keys %{ $chans{$server} }) { 248 my $iptr = weechat::infolist_get('irc_nick', '', "$server,$channel,$nick"); 249 next unless $iptr; 250 weechat::infolist_free($iptr); 251 for (getgroup($server, $channel)) { 252 my ($to_serv, $to_chan, $flags, undef) = @$_; 253 next unless $flags & $STAT; 254 next if $flags & $READ; 255 next unless ircbuf("$to_serv.$to_chan"); 256 sendto($to_serv, "/notice $to_chan \x02$nick\x0f left $server: $message"); 257 } } 258 259 return weechat::WEECHAT_RC_OK; 260 } 261 262 sub irc_mode 263 { 264 my (undef, $server, $nick, $channel, $modes) = (shift, 265 shift =~ /(.+),irc_raw_in_mode/i, 266 shift =~ /:([^! ]*)[^ ]* mode ([^ ]+) (.*)/i); 267 ($server, $channel) = (lc $server, lc $channel); 268 return weechat::WEECHAT_RC_OK unless exists $chans{$server}{$channel}; 269 270 return weechat::WEECHAT_RC_OK; 271 } 272 273 sub irc_topic 274 { 275 my (undef, $server, $nick, $channel, $message) = (shift, 276 shift =~ /(.+),irc_raw_in_topic/i, 277 shift =~ /:([^! ]*)[^ ]* topic ([^ ]+) :?([^ ]+)/i); 278 ($server, $channel) = (lc $server, lc $channel); 279 weechat::print('',"$server $channel"); 280 return weechat::WEECHAT_RC_OK unless exists $chans{$server}{$channel}; 281 return weechat::WEECHAT_RC_OK if lc $nick eq lc weechat::info_get('irc_nick', $server); 282 283 for (getgroup($server, $channel)) { 284 my ($to_serv, $to_chan, $flags, undef) = @$_; 285 next unless $flags & $MODE; 286 next if $flags & $READ; 287 next unless ircbuf("$to_serv.$to_chan"); 288 sendto($to_serv, "/topic $to_chan $message"); 289 } 290 291 return weechat::WEECHAT_RC_OK; 292 } 293 294 sub cmd_parrot 295 { 296 my (undef, $buffer, $command) = @_; 297 my ($server, $channel) = servchan($buffer); 298 my ($flags, $remove, $groupname) = 299 ( 0, 0, ''); 300 for (split / +/, $command) { 301 /^-read$/ and ($flags |= $READ), next; 302 /^-stat$/ and ($flags |= $STAT), next; 303 /^-mode$/ and ($flags |= $MODE), next; 304 /^-remove$/ and ($remove = 1), next; 305 $groupname = $_; last; 306 } 307 308 unless ($groupname) { 309 if ($chans{$server}{$channel}) { 310 for (getgroup($server, $channel)) { 311 my ($to_serv, $to_chan, $flags, $group) = @$_; 312 my $flag_str = $flags ? ':' : ''; 313 $flag_str .= ' readonly' if $flags & $READ; 314 $flag_str .= ' statusmsg' if $flags & $STAT; 315 $flag_str .= ' sendmodes' if $flags & $MODE; 316 weechat::print($buffer, weechat::prefix('server'). 317 "Relaying to $to_serv/$to_chan in group $group$flag_str"); 318 } 319 } else { 320 weechat::print($buffer, weechat::prefix('server'). 321 "This channel is not being relayed"); 322 } 323 return weechat::WEECHAT_RC_OK; 324 } 325 326 # clear hooks first (if they exist) 327 if (exists $cbs{$server}) { 328 weechat::unhook($cbs{$server}{$_}) for (keys %{ $cbs{$server} }); 329 delete $cbs{$server}; 330 } 331 @{ $chans{$server}{$channel} } = 332 grep { $_ ne $groupname } @{ $chans{$server}{$channel} }; 333 334 if ($remove) { 335 delete $groups{$groupname}{$server}{$channel}; 336 delete $groups{$groupname}{$server} unless $groups{$groupname}{$server}; 337 delete $groups{$groupname} unless $groups{$groupname}; 338 delete $chans{$server}{$channel} unless $chans{$server}{$channel}; 339 delete $chans{$server} unless $chans{$server}; 340 341 write_conf(); 342 weechat::print($buffer, weechat::prefix('server'). 343 "Removed relay from group $groupname"); 344 return weechat::WEECHAT_RC_OK; 345 } 346 347 add_relay($groupname, $server, $channel, $flags); 348 349 write_conf(); 350 weechat::print($buffer, weechat::prefix('server'). 351 "Added relay to group $groupname"); 352 return weechat::WEECHAT_RC_OK; 353 } 354 355 sub completion_groupnames 356 { 357 my $completion = pop; 358 weechat::hook_completion_list_add($completion, $_, 0, 359 weechat::WEECHAT_LIST_POS_SORT) for keys %groups; 360 } 361 362 if (weechat::register($SCRIPT_NAME, $SCRIPT_AUTHOR, $SCRIPT_VERSION, 363 $SCRIPT_LICENCE, $SCRIPT_DESC, '', '')) { 364 $confpath = weechat::info_get('weechat_dir', '') . '/parrot.db'; 365 weechat::hook_completion('perl_parrot_groupname', 'parrot.pl group names', 366 'completion_groupnames', ''); 367 weechat::hook_command('parrot', $SCRIPT_DESC, 368 "[-read] [-stat] [-mode] groupname\n". 369 "-remove", 370 "-read: relay from this channel to others, but do not relay to\n". 371 " this channel\n". 372 "-stat: show status messages (join/part) in this channel\n". 373 "-mode: transfer modes to this channel, even if you are op". 374 "groupname: all channels with the same group name are relayed together\n". 375 "-remove: remove this channel from the relay group", 376 '-remove %(perl_parrot_groupname) %-'. 377 '||-read|-stat|-mode|%(perl_parrot_groupname)|%*', 378 'cmd_parrot', ''); 379 read_conf(); 380 }