Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
581 lines (493 sloc) 16.2 KB
##############################################################################
#
# mh_sbsplitmode.pl v1.08 (20170424)
#
# Copyright (c) 2015-2017 Michael Hansen
#
# Permission to use, copy, modify, and distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice
# appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
# THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
##############################################################################
#
# provides a statusbar item showing if your server is in splitmode and /splitmode to show details
#
# will show an indicator if your active server is in splitmode, with
# optional details. there is also a command /splitmode that will list
# the status of all servers being watched. since /stats d is disabled
# for regular users on most irc networks, i have provided a setting to
# tell which networks we will check - currently only IRCnet is in the
# list. if you do not have the privileges it will tell you that splitmode
# is unavailable.
#
# settings:
#
# mh_sbsplitmode_delay (default 5): Aproximate delay (in minutes) between
# checking /stats d
#
# mh_sbsplitmode_networks (default IRCnet): a comma-seperated list of networks
# we will check for splitmode
#
# mh_sbsplitmode_show_details (default ON): show how many servers (s:) and/or
# users (u:) are missing before we go out of splitmode
#
# mh_sbsplitmode_show_detail_trend (default ON): show a + or - if s: or u:
# is increasing or decreasing
#
# mh_sbsplitmode_lag_limit (default 5): amount of lag (in seconds) where we skip
# checking the server for splitmode
#
# mh_sbsplitmode_print (default ON): enable/disable printing "* is in splitmode ..."
# or "* is no longer in splitmode" in all relevant (server/channel/query) windows
# of the server
#
# mh_sbsplitmode_print_details (default ON): enable/disable showing the server/user
# details in "* is in splitmode [servers:<current>/<min> users:<current>/<min>]"
#
# to configure irssi to show the new statusbar item in a default irssi
# installation type '/statusbar window add -after window_empty mh_sbsplitmode'.
# see '/help statusbar' for more details and do not forget to '/save'
#
# history:
#
# v1.08 (20170424)
# added 'sbitems' to irssi header for better scriptassist.pl support (github issue #1)
#
# v1.07 (20160213)
# added namespace to MSGLEVEL
# code cleanup
#
# v1.06 (20151227)
# added _print/_print_details and supporting code
# /splitmode now prints stats d unavailable in a bit nicer way
# now using individual redir numeric events for stats d
# now does a stats d on netsplit/join
# added changed field to irssi header
#
# v1.05 (20151217)
# added indents to /help
#
# v1.04 (20151210)
# added setting _show_details_trend and supporting code
# fixed warning about experimental feature (keys($var)) in perl v5.20.2
#
# v1.03 (20151208)
# cleaned up useless code.
#
# v1.02 (20151207)
# fixed bug where the timeout never got started
# added a few comments
#
# v1.01 (20151203)
# added _lag_limit and supporting code to skip /stats d on lag
# will now print server is in splitmode in all relevant windows
#
# v1.00 (20151201)
# initial release
#
use v5.14.2;
use strict;
##############################################################################
#
# irssi head
#
##############################################################################
use Irssi 20100403;
use Irssi::TextUI;
our $VERSION = '1.08';
our %IRSSI =
(
'name' => 'mh_sbsplitmode',
'description' => 'provides a statusbar item showing if your server is in splitmode and /splitmode to show details',
'license' => 'BSD',
'authors' => 'Michael Hansen',
'contact' => 'mh on IRCnet #help',
'url' => 'http://scripts.irssi.org / https://github.com/mh-source/irssi-scripts',
'changed' => 'Mon Apr 24 10:59:54 CEST 2017',
'sbitems' => 'mh_sbsplitmode',
);
##############################################################################
#
# global variables
#
##############################################################################
our $state;
##############################################################################
#
# common support functions
#
##############################################################################
sub trim_space
{
my ($string) = @_;
if (defined($string))
{
$string =~ s/^\s+//g;
$string =~ s/\s+$//g;
} else
{
$string = '';
}
return($string);
}
##############################################################################
#
# script functions
#
##############################################################################
sub request_stats_d
{
my ($server) = @_;
if (ref($server) eq 'Irssi::Irc::Server')
{
if ($server->{'connected'})
{
for my $networkname (split(',', Irssi::settings_get_str('mh_sbsplitmode_networks')))
{
if (lc($networkname) eq lc($server->{'chatnet'}))
{
#
# lag-protect stats d request
#
my $lag_limit = Irssi::settings_get_int('mh_sbsplitmode_lag_limit');
if ($lag_limit)
{
$lag_limit = $lag_limit * 1000; # seconds to milliseconds
}
if ((not $lag_limit) or ($lag_limit > $server->{'lag'}))
{
$server->redirect_event('mh_sbsplitmode stats d',
1, # count
'', # arg
-1, # remote
'', # failure signal
{ # signals
'event 248' => 'redir mh_sbsplitmode event 248', # RPL_STATSDEFINE
'event 481' => 'redir mh_sbsplitmode event 481', # ERR_NOPRIVILEGES
'' => 'event empty',
}
);
$server->send_raw('STATS d');
last;
}
}
}
}
}
}
sub request_stats_d_all
{
for my $server (Irssi::servers())
{
request_stats_d($server);
}
}
sub state_remove_server
{
my ($server) = @_;
if (exists($state->{lc($server->{'tag'})}))
{
delete($state->{lc($server->{'tag'})});
}
}
##############################################################################
#
# irssi timeouts
#
##############################################################################
sub timeout_request_stats_d
{
request_stats_d_all();
my $delay = Irssi::settings_get_int('mh_sbsplitmode_delay');
if ($delay > 60)
{
$delay = 60;
} elsif ($delay < 1)
{
$delay = 1;
}
$delay = ($delay * 60000); # in minutes
$delay = $delay + (int(rand(30000)) + 1);
Irssi::timeout_add_once($delay, 'timeout_request_stats_d', undef);
}
##############################################################################
#
# irssi signal handlers
#
##############################################################################
sub signal_redir_event_248
{
my ($server, $data, $sender) = @_;
if ($data =~ m/.* S:([0-9]*).* SS:[0-9]*\/([0-9]*)\/([0-9]*).* SU:[0-9]*\/([0-9]*)\/([0-9]*).*/)
{
my $servertag = lc($server->{'tag'});
my $old_s = 0;
my $old_ss = 0;
my $old_su = 0;
if (exists($state->{$servertag}))
{
$old_s = $state->{$servertag}->{'s'};
$old_ss = $state->{$servertag}->{'ss_cur'};
$old_su = $state->{$servertag}->{'su_cur'};
}
$state->{$servertag}->{'s'} = int($1);
$state->{$servertag}->{'ss_min'} = int($2);
$state->{$servertag}->{'ss_cur'} = int($3);
$state->{$servertag}->{'ss_old'} = $old_ss;
$state->{$servertag}->{'su_min'} = int($4);
$state->{$servertag}->{'su_cur'} = int($5);
$state->{$servertag}->{'su_old'} = $old_su;
Irssi::statusbar_items_redraw('mh_sbsplitmode');
#
# print to all relevant windows when server enters/leaves splitmode
#
if (Irssi::settings_get_bool('mh_sbsplitmode_print') and ($old_s != $state->{$servertag}->{'s'}))
{
my $format_server = $server->{'tag'} . '/' . $server->{'real_address'};
my $format_data = '';
my $details = Irssi::settings_get_bool('mh_sbsplitmode_print_details');
if ($state->{$servertag}->{'s'})
{
$format_data = 'is in';
} else
{
$details = 0;
$format_data = 'is no longer in';
}
for my $window (Irssi::windows())
{
if (exists($window->{'active_server'}))
{
if (lc($window->{'active_server'}->{'tag'}) eq $servertag)
{
if ($details)
{
my $format_details = 'servers:' . $state->{$servertag}->{'ss_cur'} . '/' . $state->{$servertag}->{'ss_min'} . ' users:' . $state->{$servertag}->{'su_cur'} . '/' . $state->{$servertag}->{'su_min'};
$window->printformat(Irssi::MSGLEVEL_CRAP | Irssi::MSGLEVEL_NO_ACT, 'mh_sbsplitmode_info_details', $format_server, $format_data, $format_details);
} else
{
$window->printformat(Irssi::MSGLEVEL_CRAP | Irssi::MSGLEVEL_NO_ACT, 'mh_sbsplitmode_info', $format_server, $format_data);
}
}
}
}
}
}
}
sub signal_redir_event_481
{
my ($server, $data, $sender) = @_;
if ($data =~ m/.*permission.*/i)
{
my $servertag = lc($server->{'tag'});
$state->{$servertag}->{'s'} = -1;
$state->{$servertag}->{'ss_min'} = 0;
$state->{$servertag}->{'ss_cur'} = 0;
$state->{$servertag}->{'su_min'} = 0;
$state->{$servertag}->{'su_cur'} = 0;
Irssi::statusbar_items_redraw('mh_sbsplitmode');
}
}
sub signal_netsplit_server_new
{
my ($server, $netsplitserver) = @_;
request_stats_d($server);
}
sub signal_setup_changed_last
{
Irssi::statusbar_items_redraw('mh_sbsplitmode');
}
##############################################################################
#
# irssi command functions
#
##############################################################################
sub command_splitmode
{
my ($data, $server, $windowitem) = @_;
if ($state)
{
for my $servertag (keys(%{$state}))
{
$server = Irssi::server_find_tag($servertag);
if ($server)
{
my $format_server = $server->{'tag'} . '/' . $server->{'real_address'};
my $format_data = '';
my $format_detail = '';
if ($state->{$servertag}->{'s'} < 0)
{
$format_data = 'Splitmode unavailable';
} else
{
if ($state->{$servertag}->{'s'})
{
$format_data = 'In splitmode';
if ($state->{$servertag}->{'s'} > 1)
{
$format_data = $format_data . ' since ' . localtime($state->{$servertag}->{'s'});
}
} else
{
$format_data = 'Not in splitmode';
}
$format_detail = 'servers:' . $state->{$servertag}->{'ss_cur'} . '/' . $state->{$servertag}->{'ss_min'} . ' users:' . $state->{$servertag}->{'su_cur'} . '/' . $state->{$servertag}->{'su_min'};
}
if ($format_detail ne '')
{
Irssi::active_win->printformat(Irssi::MSGLEVEL_CRAP, 'mh_sbsplitmode_line', $format_server, $format_data, $format_detail);
} else
{
Irssi::active_win->printformat(Irssi::MSGLEVEL_CRAP, 'mh_sbsplitmode_line_no_detail', $format_server, $format_data);
}
}
}
} else
{
Irssi::active_win->printformat(Irssi::MSGLEVEL_CRAP, 'mh_sbsplitmode_error', 'No servers');
}
}
sub command_help
{
my ($data, $server, $windowitem) = @_;
$data = lc(trim_space($data));
if ($data =~ m/^splitmode$/i)
{
Irssi::print('', Irssi::MSGLEVEL_CLIENTCRAP);
Irssi::print('SPLITMODE', Irssi::MSGLEVEL_CLIENTCRAP);
Irssi::print('', Irssi::MSGLEVEL_CLIENTCRAP);
Irssi::print('%|Shows the splitmode status of all watched servers.', Irssi::MSGLEVEL_CLIENTCRAP);
Irssi::print('', Irssi::MSGLEVEL_CLIENTCRAP);
Irssi::print('%|Splitmode occurs when a servers users or server links goes below a predefined value.', Irssi::MSGLEVEL_CLIENTCRAP);
Irssi::print('', Irssi::MSGLEVEL_CLIENTCRAP);
Irssi::print('See also: %|SET ' . uc('mh_sbsplitmode') .', STATS', Irssi::MSGLEVEL_CLIENTCRAP);
Irssi::print('', Irssi::MSGLEVEL_CLIENTCRAP);
Irssi::signal_stop();
}
}
##############################################################################
#
# statusbar item handlers
#
##############################################################################
sub statusbar_splitmode
{
my ($statusbaritem, $get_size_only) = @_;
my $server = Irssi::active_server();
my $format = '';
if ($server)
{
if ($state)
{
my $servertag = lc($server->{'tag'});
if (exists($state->{$servertag}))
{
if ($state->{$servertag}->{'s'} < 0)
{
$format = 'Splitmode unavailable';
} elsif ($state->{$servertag}->{'s'})
{
$format = 'Splitmode';
if (Irssi::settings_get_bool('mh_sbsplitmode_show_details'))
{
my $old_char = '';
if (Irssi::settings_get_bool('mh_sbsplitmode_show_detail_trend'))
{
if ($state->{$servertag}->{'ss_old'})
{
if ($state->{$servertag}->{'ss_old'} > $state->{$servertag}->{'ss_cur'})
{
$old_char = '+';
} elsif ($state->{$servertag}->{'ss_old'} < $state->{$servertag}->{'ss_cur'})
{
$old_char = '-';
}
}
}
if ($state->{$servertag}->{'ss_cur'} < $state->{$servertag}->{'ss_min'})
{
$format = $format . ' s:' . ($state->{$servertag}->{'ss_min'} - $state->{$servertag}->{'ss_cur'} . $old_char);
}
$old_char = '';
if (Irssi::settings_get_bool('mh_sbsplitmode_show_detail_trend'))
{
if ($state->{$servertag}->{'su_old'})
{
if ($state->{$servertag}->{'su_old'} > $state->{$servertag}->{'su_cur'})
{
$old_char = '+';
} elsif ($state->{$servertag}->{'su_old'} < $state->{$servertag}->{'su_cur'})
{
$old_char = '-';
}
}
}
if ($state->{$servertag}->{'su_cur'} < $state->{$servertag}->{'su_min'})
{
$format = $format . ' u:' . ($state->{$servertag}->{'su_min'} - $state->{$servertag}->{'su_cur'} . $old_char);
}
}
}
}
}
}
$statusbaritem->default_handler($get_size_only, '{sb ' . $format . '}', '', 0);
}
##############################################################################
#
# script on load
#
##############################################################################
Irssi::settings_add_int('mh_sbsplitmode', 'mh_sbsplitmode_delay', 5);
Irssi::settings_add_str('mh_sbsplitmode', 'mh_sbsplitmode_networks', 'IRCnet');
Irssi::settings_add_bool('mh_sbsplitmode', 'mh_sbsplitmode_show_details', 1);
Irssi::settings_add_bool('mh_sbsplitmode', 'mh_sbsplitmode_show_detail_trend', 1);
Irssi::settings_add_bool('mh_sbsplitmode', 'mh_sbsplitmode_print', 1);
Irssi::settings_add_bool('mh_sbsplitmode', 'mh_sbsplitmode_print_details', 1);
Irssi::settings_add_int('mh_sbsplitmode', 'mh_sbsplitmode_lag_limit', 5);
Irssi::theme_register([
'mh_sbsplitmode_line', '{server $0}: $1 {comment $2}',
'mh_sbsplitmode_line_no_detail', '{server $0}: {error $1}',
'mh_sbsplitmode_info', '{server $0} $1 {hilight splitmode}',
'mh_sbsplitmode_info_details', '{server $0} $1 {hilight splitmode} {comment $2}',
'mh_sbsplitmode_error', '{error $0}',
]);
Irssi::Irc::Server::redirect_register('mh_sbsplitmode stats d',
0, # remote
0, # timeout
{ # start signals
'event 248' => -1, # RPL_STATSDEFINE stats d line
'event 481' => -1, # ERR_NOPRIVILEGES error no privileges
},
{ # stop signals
'event 219' => -1, # RPL_ENDOFSTATS end of stats
},
undef # optional signals
);
Irssi::statusbar_item_register('mh_sbsplitmode', '', 'statusbar_splitmode');
Irssi::signal_add('redir mh_sbsplitmode event 248', 'signal_redir_event_248');
Irssi::signal_add('redir mh_sbsplitmode event 481', 'signal_redir_event_481');
Irssi::signal_add_last('event connected', 'request_stats_d');
Irssi::signal_add('server disconnected', 'state_remove_server');
Irssi::signal_add('netsplit server new', 'signal_netsplit_server_new');
Irssi::signal_add('netsplit server remove', 'signal_netsplit_server_new');
Irssi::signal_add_last('setup changed', 'signal_setup_changed_last');
Irssi::command_bind('splitmode', 'command_splitmode', 'mh_sbsplitmode');
Irssi::command_bind('help', 'command_help');
timeout_request_stats_d();
1;
##############################################################################
#
# eof mh_sbsplitmode.pl
#
##############################################################################