use Irssi 20020300; use strict; use vars qw($VERSION %IRSSI %HELP); $HELP{getop} = " GETOP [channel] Gets op on current channel or 'channel' from random opped bot added by ADDGETOP. "; $HELP{addgetop} = " ADDGETOP [channel] Adds entry to 'channel' or current channel getop list. The \$0 in command specifies nick of random found mask in channel. "; $HELP{delgetop} = " DELGETOP [channel] Deletes entry from getoplist on current channel or 'channel'. "; $HELP{listgetop} = " LISTGETOP [channel] Lists all entries in getop list or just 'channel's getop list. "; $VERSION = "0.9b"; %IRSSI = ( authors => "Maciek \'fahren\' Freudenheim", contact => "fahren\@bochnia.pl", name => "GetOP", description => "Automatically request op from random opped person with specifed command from list after joining channel", license => "GNU GPLv2 or later", changed => "Fri Jan 10 03:54:07 CET 2003" ); Irssi::theme_register([ 'getop_listline', '[%W$[!-2]0%n]%| $[40]1%_: %_$2', 'getop_add', 'Added \'%_$2%_\' to getop list on channel %_$1%_ /$0/', 'getop_del', 'Deleted \'%_$2%_\' from getop list on channel %_$1%_ /$0/', 'getop_changed', 'Changed command for mask \'%_$2%_\' on channel %_$1%_ /$0/', 'getop_noone', '"%Y>>%n No one to get op from on $1 /$0/', 'getop_get', '%Y>>%n Getting op from %_$2%_ on $1 /$0/' ]); my %getop = (); my @userhosts; my $getopfile = Irssi::get_irssi_dir . "/getoplist"; sub sub_getop { my ($args, $server, $winit) = @_; my $chan; my ($channel) = $args =~ /^([^\s]+)/; if ($server->ischannel($channel)) { unless ($chan = $server->channel_find($channel)) { Irssi::print("%R>>%n You are not on $channel."); return; } $args =~ s/^[^\s]+\s?//; } else { unless ($winit && $winit->{type} eq "CHANNEL") { Irssi::print("%R>>%n You don't have active channel in that window."); return; } $channel = $winit->{name}; $chan = $winit; } if ($chan->{chanop}) { Irssi::print("%R>>%n You are already opped on $channel."); return; } $channel = lc($channel); my $tag = lc($server->{tag}); unless ($getop{$tag}{$channel}) { Irssi::print("%R>>%n Your getop list on channel $channel is empty. Use /ADDGETOP first."); return; }; unless ($getop{$tag}{$channel}) { Irssi::print("%R>>%n Your getop list on channel $channel is empty."); return; } getop_proc($tag, $chan); } sub sub_addgetop { my ($args, $server, $winit) = @_; my ($channel) = $args =~ /^([^\s]+)/; if ($server->ischannel($channel)) { $args =~ s/^[^\s]+\s?//; } else { unless ($winit && $winit->{type} eq "CHANNEL") { Irssi::print("%R>>%n You don't have active channel in that window."); return; } $channel = $winit->{name}; } my ($mask, $command) = split(/ +/, $args, 2); unless ($command) { Irssi::print("Usage: /ADDGETOP [channel] . If you type '\$0' in command then it will be changed automatically into mask's nick."); return; } my $cmdchar = Irssi::settings_get_str('cmdchars'); $command =~ s/^($cmdchar*)\^?/\1^/g; if (index($mask, "@") == -1) { my ($c, $n); if (($c = $server->channel_find($channel)) && ($n = $c->nick_find($mask))) { $mask = $n->{host}; $mask =~ s/^[~+\-=^]/*/; } else { $server->redirect_event('userhost', 1, $mask, 0, undef, { 'event 302' => 'redir getop userhost', '' => 'event empty' } ); $server->send_raw("USERHOST $mask"); my $uh = lc($mask) . " " . lc($channel) . " $command"; push @userhosts, $uh; return; } } $mask = "*!" . $mask if (index($mask, "!") == -1); my $tag = lc($server->{tag}); my $channel = lc($channel); for my $entry (@{$getop{$tag}{$channel}}) { if ($entry->{mask} eq $mask) { $entry->{command} = $command; Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'getop_changed', $tag, $channel, $mask, $command); &savegetop; return; } } my $gh = { mask => $mask, command => $command }; push @{$getop{$tag}{$channel}}, $gh; Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'getop_add', $tag, $channel, $mask, $command); &savegetop; } sub sub_delgetop { my ($args, $server, $winit) = @_; my ($channel) = $args =~ /^([^\s]+)/; if ($server->ischannel($channel)) { $args =~ s/^[^\s]+\s?//; } else { unless ($winit && $winit->{type} eq "CHANNEL") { Irssi::print("%R>>%n You don't have active channel in that window."); return; } $channel = $winit->{name}; } my $tag = lc($server->{tag}); my $channel = lc($channel); unless ($getop{$tag}{$channel}) { Irssi::print("%R>>%n Your getop list on channel $channel is empty."); return; } unless ($args) { Irssi::print("%W>>%n Usage: /DELGETOP [channel] "); return; } my $num; if ($args =~ /^[0-9]+$/) { if ($args > scalar(@{$getop{$tag}{$channel}})) { Irssi::print("%R>>%n No such entry in $channel getop list."); return; } $num = $args - 1; } else { my $i = 0; for my $entry (@{$getop{$tag}{$channel}}) { $args eq $entry->{mask} and $num = $i, last; $i++; } } if (my($gh) = splice(@{$getop{$tag}{$channel}}, $num, 1)) { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'getop_del', $tag, $channel, $gh->{mask}, $gh->{command}); unless (scalar(@{$getop{$tag}{$channel}})) { Irssi::print("%R>>%n No more entries in $channel getop list left."); delete $getop{$tag}{$channel}; } unless (keys %{$getop{$tag}}) { Irssi::print("%R>>%n No more entries in getop list on $tag left."); delete $getop{$tag}; } } &savegetop; } sub sub_listgetop { my ($args, $server, $winit) = @_; my ($channel) = $args =~ /^([^\s]+)/; if ($server->ischannel($channel)) { my $tag = lc($server->{tag}); $channel = lc($channel); unless ($getop{$tag}{$channel}) { Irssi::print("%R>>%n Your getop list on channel $channel is empty."); return; } my $i = 0; Irssi::print("Getop list on $channel /$tag/:"); for my $entry (@{$getop{$tag}{$channel}}) { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'getop_listline', $i++, $entry->{mask}, $entry->{command}); } } else { unless (keys %getop) { Irssi::print("%R>>%n Your getop list is empty. /ADDGETOP first."); return; } for my $ircnet (keys %getop) { for my $chan (keys %{$getop{$ircnet}}) { Irssi::print("Channel: $chan /$ircnet/"); my $i = 1; for my $entry (@{$getop{$ircnet}{$chan}}) { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'getop_listline', $i++, $entry->{mask}, $entry->{command}); } } } } } sub userhost_red { my ($server, $data) = @_; $data =~ s/^[^ ]* :?//; my $uh = shift @userhosts; my ($nick, $chan, $command) = split(/ /, $uh, 3); unless ($data && $data =~ /^([^=\*]*)\*?=.(.*)@(.*)/ && lc($1) eq $nick) { Irssi::print("%R>>%n No such nickname: $nick"); return; } my ($user, $host) = ($2, $3); $user =~ s/^[~+\-=^]/*/; my $mask = "*!" . $user . "@" . $host; my $tag = lc($server->{tag}); for my $entry (@{$getop{$tag}{$chan}}) { if ($entry->{mask} eq $mask) { $entry->{command} = $command; Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'getop_changed', $tag, $chan, $mask, $command); &savegetop; return; } } my $gh = { mask => $mask, command => $command }; push @{$getop{$tag}{$chan}}, $gh; Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'getop_add', $tag, $chan, $mask, $command); &savegetop; } sub getop_proc ($$) { my ($tag, $chan) = @_; my $channel = lc($chan->{name}); return unless ($getop{$tag}{$channel}); my (@list, $mask); for my $nick ($chan->nicks()) { next unless ($nick->{op}); $mask = $nick->{nick} . "!" . $nick->{host}; for my $entry (@{$getop{$tag}{$channel}}) { if (mask_match($mask, $entry->{mask})) { my $lh = { nick => $nick->{nick}, command => $entry->{command} }; push @list, $lh; } } } unless (@list) { Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'getop_noone', $tag, $channel); } else { my $get = $list[int(rand(@list))]; $get->{command} =~ s/\$0/$get->{nick}/g; Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'getop_get', $tag, $channel, $get->{nick}, $get->{command}); $chan->command($get->{command}); } } sub mask_match ($$) { my ($what, $match) = @_; $match =~ s/\\/\\\\/g; $match =~ s/\./\\\./g; $match =~ s/\*/\.\*/g; $match =~ s/\!/\\\!/g; $match =~ s/\?/\./g; $match =~ s/\+/\\\+/g; $match =~ s/\^/\\\^/g; return ($what =~ /^$match$/i); } sub got_notopped { my ($server, $data) = @_; my ($chan) = $data =~ /^[^\s]+\s([^\s]+)\s:/; getop_proc(lc($server->{tag}), $server->channel_find($chan)); } sub channel_sync { my $chan = shift; getop_proc(lc($chan->{server}->{tag}), $chan) unless ($chan->{chanop}); } sub savegetop { local *fp; open (fp, ">", $getopfile) or die "Couldn't open $getopfile for writing"; for my $ircnet (keys %getop) { for my $chan (keys %{$getop{$ircnet}}) { for my $entry (@{$getop{$ircnet}{$chan}}) { print(fp "$ircnet $chan $entry->{mask} $entry->{command}\n"); } } } close fp; } sub loadgetop { %getop = (); return unless (-e $getopfile); local *fp; open (fp, "<", $getopfile) or die "Couldn't open $getopfile for reading"; local $/ = "\n"; while () { chop; my $gh = {}; my ($tag, $chan); ($tag, $chan, $gh->{mask}, $gh->{command}) = split(/ /, $_, 4); push @{$getop{$tag}{$chan}}, $gh; } close fp; } &loadgetop; Irssi::command_bind( { 'getop' => \&sub_getop, 'addgetop' => \&sub_addgetop, 'delgetop' => \&sub_delgetop, 'listgetop' => \&sub_listgetop } ); Irssi::signal_add({ 'redir getop userhost' => \&userhost_red, 'event 482' => \&got_notopped, 'channel sync' => \&channel_sync});