# $Id: users.pl,v 1.22 2003/01/11 14:54:35 jylefort Exp $
use strict;
use Irssi 20020121.2020 ();
use vars qw($VERSION %IRSSI);
$VERSION = "2.3";
%IRSSI = (
authors => 'Jean-Yves Lefort',
contact => 'jylefort\@brutele.be, decadix on IRCnet',
name => 'users',
description => 'Implements /USERS',
license => 'BSD',
changed => '$Date: 2003/01/11 14:54:35 $ ',
);
# usage:
#
# /USERS []
#
# is an optional string
# whose format is described below.
#
# /set's:
#
# users_sort_order
#
# A sort order string which will be used to complete
# the order string given as a parameter to /USERS.
#
# Example: /set users_sort_order mnha
#
# Command Resulting order
#
# /USERS mnha
# /USERS an anmh
#
# sort order string format:
#
# An order string must be composed by one or more characters from
# the following set:
#
# m server and channel mode
# n nickname
# h user@hostname
# a away state
#
# /format's:
#
# users list header
# $0 channel name
#
# users_nick nick
# $0 * if IRC operator
# $1 @ if channel operator
# $2 % if half channel operator
# $3 + if voiced
# $4 a if marked away
# $5 nickname
# $6 user@hostname
#
# endofusers end of list
# $0 channel name
# $1 number of nicks
# $2 number of IRC operators
# $3 number of channel operators
# $4 number of half channel operators
# $5 number of voiced
# $6 number of marked away
#
# changes:
#
# 2003-01-11 release 2.3
# * nick count was wrong
#
# 2003-01-09 release 2.2
# * command char independed
#
# 2003-01-09 release 2.1
# * minor oblivion fix
#
# 2003-01-09 release 2.0
# * /USERS accepts a sort order argument
# * added /set users_sort_order
# * shows away state
#
# 2002-07-04 release 1.01
# * command_bind uses a reference instead of a string
#
# 2002-04-25 release 1.00
# * uses '*' instead of 'S' for IRC operators
#
# 2002-04-12 release 0.13
# * added support for ircops
# * changed theme
#
# 2002-01-28 release 0.12
# * added support for halfops
#
# 2002-01-28 release 0.11
#
# 2002-01-23 initial release
### sort algorithms table #####################################################
my %cmp = (
m => sub { get_mode_weight($_[1]) cmp get_mode_weight($_[0]) },
n => sub { lc $_[0]->{nick} cmp lc $_[1]->{nick} },
h => sub { lc $_[0]->{host} cmp lc $_[1]->{host} },
a => sub { $_[1]->{gone} cmp $_[0]->{gone} }
);
### support functions #########################################################
sub get_mode_weight
{
my ($nick) = @_;
return ($nick->{serverop} * 4) + ($nick->{op} * 3) + ($nick->{halfop} * 2) + $nick->{voice};
}
sub nick_cmp
{
my ($this, $that, @order) = @_;
my $sort;
foreach (@order)
{
$sort = &{$cmp{$_}}($this, $that);
if ($sort)
{
return $sort;
}
}
return $sort;
}
sub validate_order
{
my @order = @_;
foreach (@order)
{
if (! exists($cmp{$_}))
{
return "unknown character '$_'";
}
}
return undef;
}
sub get_order
{
my ($string) = @_;
my @order;
my @default;
my $error;
my %has;
@order = split(//, $string);
@default = split(//, Irssi::settings_get_str("users_sort_order"));
$error = validate_order(@default);
if (defined $error)
{
return "unable to validate users_sort_order: $error";
}
$error = validate_order(@order);
if (defined $error)
{
return "unable to validate given order: $error";
}
foreach (@order)
{
$has{$_} = 1;
}
foreach (@default)
{
if (! exists($has{$_}))
{
push(@order, $_);
}
}
return (undef, @order);
}
### /users ####################################################################
sub users
{
my ($args, $server, $item) = @_;
if ($item && $item->{type} eq "CHANNEL")
{
my $error;
my @order;
my $window;
my @nicks;
my $serverop_count = 0;
my $chanop_count = 0;
my $halfop_count = 0;
my $voice_count = 0;
my $away_count = 0;
($error, @order) = get_order($args);
if (defined $error)
{
Irssi::print("Unable to compute sort order: $error", MSGLEVEL_CLIENTERROR);
return;
}
Irssi::command('WINDOW NEW HIDDEN');
$window = Irssi::active_win();
$window->set_name("U:$item->{name}");
$window->printformat(MSGLEVEL_CRAP, "users", $item->{name});
@nicks = $item->nicks();
@nicks = sort { nick_cmp($a, $b, @order) } @nicks;
foreach (@nicks)
{
my $serverop;
my $chanop;
my $halfop;
my $voice;
my $away;
$serverop = $_->{serverop} ? '*' : '.';
$chanop = $_->{op} ? '@' : '.';
$halfop = $_->{halfop} ? '%' : '.';
$voice = $_->{voice} ? '+' : '.';
$away = $_->{gone} ? 'a' : '.';
$serverop_count++ if ($_->{serverop});
$chanop_count++ if ($_->{op});
$halfop_count++ if ($_->{halfop});
$voice_count++ if ($_->{voice});
$away_count++ if ($_->{gone});
$window->printformat(MSGLEVEL_CRAP, "users_nick",
$serverop, $chanop, $halfop, $voice, $away,
$_->{nick}, $_->{host});
}
$window->printformat(MSGLEVEL_CRAP, "endofusers", $item->{name},
scalar @nicks, $serverop_count, $chanop_count,
$halfop_count, $voice_count, $away_count);
}
}
### initialization ############################################################
Irssi::theme_register([
"users", '{names_users Users {names_channel $0}}',
"users_nick", '{hilight $0$1$3$4} $[9]5 $[50]6',
"endofusers", '{channel $0}: Total of {hilight $1} nicks, {hilight $2} IRC operators, {hilight $3} channel operators, {hilight $5} voiced, {hilight $6} marked away',
]);
Irssi::settings_add_str("misc", "users_sort_order", "mnha");
Irssi::command_bind("users", \&users);