1# $Id: users.pl,v 1.22 2003/01/11 14:54:35 jylefort Exp $
2
3use strict;
4use Irssi 20020121.2020 ();
5use vars qw($VERSION %IRSSI);
6$VERSION = "2.3";
7%IRSSI = (
8	  authors     => 'Jean-Yves Lefort',
9	  contact     => 'jylefort\@brutele.be, decadix on IRCnet',
10	  name        => 'users',
11	  description => 'Implements /USERS',
12	  license     => 'BSD',
13	  changed     => '$Date: 2003/01/11 14:54:35 $ ',
14);
15
16# usage:
17#
18#	/USERS [<orderstring>]
19#
20#		<orderstring> is an optional string
21#		whose format is described below.
22#
23# /set's:
24#
25#	users_sort_order
26#
27#		A sort order string which will be used to complete
28#		the order string given as a parameter to /USERS.
29#
30#		Example: /set users_sort_order mnha
31#
32#			Command		Resulting order
33#
34#			/USERS		mnha
35#			/USERS an	anmh
36#
37# sort order string format:
38#
39#	An order string must be composed by one or more characters from
40#	the following set:
41#
42#		m	server and channel mode
43#		n	nickname
44#		h	user@hostname
45#		a	away state
46#
47# /format's:
48#
49#	users		list header
50#			$0	channel name
51#
52#	users_nick	nick
53#			$0	* if IRC operator
54#			$1	@ if channel operator
55#			$2	% if half channel operator
56#			$3	+ if voiced
57#			$4	a if marked away
58#			$5	nickname
59#			$6	user@hostname
60#
61#	endofusers	end of list
62#			$0	channel name
63#			$1	number of nicks
64#			$2	number of IRC operators
65#			$3	number of channel operators
66#			$4	number of half channel operators
67#			$5	number of voiced
68#			$6	number of marked away
69#
70# changes:
71#
72#	2003-01-11	release 2.3
73#			* nick count was wrong
74#
75#	2003-01-09	release 2.2
76#			* command char independed
77#
78#	2003-01-09	release 2.1
79#			* minor oblivion fix
80#
81#	2003-01-09	release 2.0
82#			* /USERS accepts a sort order argument
83#			* added /set users_sort_order
84#			* shows away state
85#
86#	2002-07-04	release 1.01
87#			* command_bind uses a reference instead of a string
88#
89#	2002-04-25	release 1.00
90#			* uses '*' instead of 'S' for IRC operators
91#
92#	2002-04-12	release 0.13
93#			* added support for ircops
94#			* changed theme
95#
96#	2002-01-28	release 0.12
97#			* added support for halfops
98#
99#	2002-01-28	release 0.11
100#
101#	2002-01-23	initial release
102
103### sort algorithms table #####################################################
104
105my %cmp = (
106	   m => sub { get_mode_weight($_[1]) cmp get_mode_weight($_[0]) },
107	   n => sub { lc $_[0]->{nick} cmp lc $_[1]->{nick} },
108	   h => sub { lc $_[0]->{host} cmp lc $_[1]->{host} },
109	   a => sub { $_[1]->{gone} cmp $_[0]->{gone} }
110	  );
111
112### support functions #########################################################
113
114sub get_mode_weight
115{
116  my ($nick) = @_;
117
118  return ($nick->{serverop} * 4) + ($nick->{op} * 3) + ($nick->{halfop} * 2) + $nick->{voice};
119}
120
121sub nick_cmp
122{
123  my ($this, $that, @order) = @_;
124  my $sort;
125
126  foreach (@order)
127    {
128      $sort = &{$cmp{$_}}($this, $that);
129
130      if ($sort)
131	{
132	  return $sort;
133	}
134    }
135
136  return $sort;
137}
138
139sub validate_order
140{
141  my @order = @_;
142
143  foreach (@order)
144    {
145      if (! exists($cmp{$_}))
146	{
147	  return "unknown character '$_'";
148	}
149    }
150
151  return undef;
152}
153
154sub get_order
155{
156  my ($string) = @_;
157  my @order;
158  my @default;
159  my $error;
160  my %has;
161
162  @order = split(//, $string);
163  @default = split(//, Irssi::settings_get_str("users_sort_order"));
164
165  $error = validate_order(@default);
166  if (defined $error)
167    {
168      return "unable to validate users_sort_order: $error";
169    }
170
171  $error = validate_order(@order);
172  if (defined $error)
173    {
174      return "unable to validate given order: $error";
175    }
176
177  foreach (@order)
178    {
179      $has{$_} = 1;
180    }
181
182  foreach (@default)
183    {
184      if (! exists($has{$_}))
185	{
186	  push(@order, $_);
187	}
188    }
189
190  return (undef, @order);
191}
192
193### /users ####################################################################
194
195sub users
196{
197  my ($args, $server, $item) = @_;
198
199  if ($item && $item->{type} eq "CHANNEL")
200    {
201      my $error;
202      my @order;
203      my $window;
204      my @nicks;
205
206      my $serverop_count = 0;
207      my $chanop_count = 0;
208      my $halfop_count = 0;
209      my $voice_count = 0;
210      my $away_count = 0;
211
212      ($error, @order) = get_order($args);
213
214      if (defined $error)
215	{
216	  Irssi::print("Unable to compute sort order: $error", MSGLEVEL_CLIENTERROR);
217	  return;
218	}
219
220      Irssi::command('WINDOW NEW HIDDEN');
221
222      $window = Irssi::active_win();
223      $window->set_name("U:$item->{name}");
224      $window->printformat(MSGLEVEL_CRAP, "users", $item->{name});
225
226      @nicks = $item->nicks();
227      @nicks = sort { nick_cmp($a, $b, @order) } @nicks;
228
229      foreach (@nicks)
230	{
231	  my $serverop;
232	  my $chanop;
233	  my $halfop;
234	  my $voice;
235	  my $away;
236
237	  $serverop = $_->{serverop} ? '*' : '.';
238	  $chanop = $_->{op} ? '@' : '.';
239	  $halfop = $_->{halfop} ? '%' : '.';
240	  $voice = $_->{voice} ? '+' : '.';
241	  $away = $_->{gone} ? 'a' : '.';
242
243	  $serverop_count++ if ($_->{serverop});
244	  $chanop_count++ if ($_->{op});
245	  $halfop_count++ if ($_->{halfop});
246	  $voice_count++ if ($_->{voice});
247	  $away_count++ if ($_->{gone});
248
249	  $window->printformat(MSGLEVEL_CRAP, "users_nick",
250			       $serverop, $chanop, $halfop, $voice, $away,
251			       $_->{nick}, $_->{host});
252	}
253
254      $window->printformat(MSGLEVEL_CRAP, "endofusers", $item->{name},
255			   scalar @nicks, $serverop_count, $chanop_count,
256			   $halfop_count, $voice_count, $away_count);
257    }
258}
259
260### initialization ############################################################
261
262Irssi::theme_register([
263		       "users", '{names_users Users {names_channel $0}}',
264		       "users_nick", '{hilight $0$1$3$4}  $[9]5  $[50]6',
265		       "endofusers", '{channel $0}: Total of {hilight $1} nicks, {hilight $2} IRC operators, {hilight $3} channel operators, {hilight $5} voiced, {hilight $6} marked away',
266		      ]);
267
268Irssi::settings_add_str("misc", "users_sort_order", "mnha");
269
270Irssi::command_bind("users", \&users);
271