use strict; use warnings; use Irssi; use List::MoreUtils qw(any); no autovivification; use feature qw(fc); use Data::Dumper; my $noopenquery; our $VERSION = "0.2"; our %IRSSI = ( authors => 'Jari Matilainen, init[1]@irc.freenode.net', contact => 'vague@vague.se', name => 'fn', description => 'Various freenode op commands', license => 'Public Domain', url => 'https://vague.se', modified => 'Tue Apr 11 22:15:00 CEST 2017' ); my $commands = { op => sub { my ($item) = $_[0]; $item->command(($noopenquery ? '^' : '') . "msg chanserv op $item->{name}") }, deop => sub { my ($item) = $_[0]; $item->command(($noopenquery ? '^' : '') . "msg chanserv deop $item->{name}") }, voice => sub { my $item = shift; $item->command(($noopenquery ? '^' : '') . "msg chanserv voice $item->{name} " . join ',', @_) if @_ }, devoice => sub { my $item = shift; $item->command(($noopenquery ? '^' : '') . "msg chanserv devoice $item->{name} " . join ',', @_) if @_ }, forward => sub { my ($item, $mask, $fwchan) = @_; $fwchan = '##fix_your_connection' unless $fwchan; $item->command("mode $item->{name} +b " . ($mask =~ /@/ ? '' : '$a:') . $mask . '$' . $fwchan) if $mask }, unforward => sub { my ($item, $mask, $fwchan) = @_; $fwchan = '##fix_your_connection' unless $fwchan; $item->command("mode $item->{name} -b " . ($mask =~ /@/ ? '' : '$a:') . $mask . '$' . $fwchan) if $mask }, mode => sub { my ($item, @mode) = @_; $item->command("mode $item->{name} " . join(' ', @mode)) }, quiet => sub { my ($item, $mask) = @_; $item->command("mode $item->{name} +q " . ($mask =~ /@/ ? '' : '$a:') . $mask) if $mask }, unquiet => sub { my ($item, $mask) = @_; $item->command("mode $item->{name} -q " . ($mask =~ /@/ ? '' : '$a:') . $mask) if $mask }, ban => sub { my ($item, $mask) = @_; $item->command("mode $item->{name} +b " . ($mask =~ /@/ ? '' : '$a:') . $mask) if $mask }, unban => sub { my ($item, $mask) = @_; $item->command("mode $item->{name} -b " . ($mask =~ /@/ ? '' : '$a:') . $mask) if $mask }, kick => sub { my $item = shift; my $mask = shift; $item->command("kick $item->{name} $mask " . join ' ', @_) if $mask }, kickban => sub { my $item = shift; my $mask = shift; $item->command("kickban $item->{name} $mask " . join ' ', @_) if $mask }, }; sub cmd_help { my ($args, $server, $witem) = @_; if($args =~ /^fn\b/i) { Irssi::print ( < [ [|]] %_Description:%_ Commands to handle Freenode channels. means registered nick unless hostmask is specified or otherwise stated. %_Available settings:%_ fn_enabled_channels - comma separated list of channels and allowed commands: #chan1:op deop quiet,#chan2:all fn_services_wait - how long we should wait for services to accomplish a task %_The following commands can be used:%_ op - gain ops in channel, only possible to op yourself deop - lose ops in channel, only possible to deop yourself voice - give voice to :s, is channel nick devoice - remove voice from :s, is channel nick mode - set in quiet - put on quiet unquiet - remove quiet from forward - forward to unforward - remove forward of from ban - ban from channel, is channel nick or hostmask unban - unban from channel, is channel nick or hostmask kick - kick from channel with , is channel nick kickban - kickban from channel with , is channel nick %_Examples:%_ /fn op /fn deop /fn kick vague get out! /fn kick vague,jonas both of you get out! /fn quiet vague!*vague\@host.com /fn forward vague ##fix_your_connection /fn unforward vague SCRIPTHELP_EOF ,MSGLEVEL_CLIENTCRAP); Irssi::signal_stop; } } sub cmd_fn { my ($args, $server, $witem) = @_; unless($server->can('isupport') && fc($server->isupport('network')) eq fc("freenode")) { $witem->print("You are not on freenode", MSGLEVEL_CLIENTERROR); return; } my $pattern = qr/\s*,\s*/; my @chancmds = split /$pattern/, Irssi::settings_get_str('fn_enabled_channels'); my %cmds = map { my ($ch, $co) = split ':'; +"\F$ch" => [split ' ', $co] } @chancmds; my ($cmd, @rest) = split ' ', $args; unless(any {/\b($cmd|all)\b/i} $cmds{fc($witem->{name})}->@*) { $witem->print("Illegal command, only the following commands are allowed for $witem->{name}: " . join(', ', $cmds{fc($witem->{name})}->@*) . ". See /help fn for more info", MSGLEVEL_CLIENTERROR); return; } my $timeout = 20; my $has_op = $witem->{ownnick}->{op}; if($cmd =~ /\b(mode|ban|unban|kick|kickban|quiet|unquiet|forward)\b/i && !$has_op) { $timeout = Irssi::settings_get_time('fn_services_wait'); $commands->{op}($witem); } Irssi::timeout_add_once($timeout, sub { return unless $_[0]->[0] && $_[0]->[1]; my $s = Irssi::server_find_tag($_[0]->[0]) or return; my $wi = $s->window_item_find($_[0]->[1]) or return; if(exists $commands->{fc $cmd}) { $commands->{fc $cmd}($wi, @rest); } else { $wi->print("Invalid command, see /help fn", MSGLEVEL_CLIENTERROR); } if(!$has_op && $timeout > 20) { Irssi::timeout_add_once($timeout, sub { return unless $_[0]->[0] && $_[0]->[1]; my $s = Irssi::server_find_tag($_[0]->[0]) or return; my $wi = $s->window_item_find($_[0]->[1]) or return; $commands->{deop}($wi); }, [$wi->{server}{tag}, $wi->{name}]); } }, [$server->{tag}, $witem->{name}]); } sub init { $noopenquery = Irssi::settings_get_bool('fn_no_open_query'); } Irssi::settings_add_str('foc', 'fn_enabled_channels', ''); Irssi::settings_add_bool('foc', 'fn_no_open_query', 1); Irssi::settings_add_time('foc', 'fn_services_wait', '2000ms'); Irssi::command_bind("fn", 'cmd_fn'); Irssi::command_bind_first('help', 'cmd_help'); Irssi::signal_add('setup changed' => 'init'); init();