html/keepnick.pl
1 # keepnick - irssi 0.7.98.CVS
2 #
3 # $Id: keepnick.pl,v 1.17 2003/01/04 10:18:42 peder Exp $
4 #
5 # Copyright (C) 2001, 2002 by Peder Stray <peder@ninja.no>
6 #
7
8 use strict;
9 use Irssi 20011118.1727;
10 use Irssi::Irc;
11
12 # ======[ Script Header ]===============================================
13
14 use vars qw{$VERSION %IRSSI};
15 ($VERSION) = '$Revision: 1.17 $' =~ / (\d+\.\d+) /;
16 %IRSSI = (
17 name => 'keepnick',
18 authors => 'Peder Stray',
19 contact => 'peder@ninja.no',
20 url => 'http://ninja.no/irssi/keepnick.pl',
21 license => 'GPL',
22 description => 'Try to get your nick back when it becomes available.',
23 );
24
25 # ======[ Variables ]===================================================
26
27 my(%keepnick); # nicks we want to keep
28 my(%getnick); # nicks we are currently waiting for
29 my(%inactive); # inactive chatnets
30 my(%manual); # manual nickchanges
31
32 # ======[ Helper functions ]============================================
33
34 # --------[ change_nick ]-----------------------------------------------
35
36 sub change_nick {
37 my($server,$nick) = @_;
38 $server->redirect_event('keepnick nick', 1, ":$nick", -1, undef,
39 {
40 "event nick" => "redir keepnick nick",
41 "" => "event empty",
42 });
43 $server->send_raw("NICK :$nick");
44 }
45
46 # --------[ check_nick ]------------------------------------------------
47
48 sub check_nick {
49 my($server,$net,$nick);
50
51 %getnick = (); # clear out any old entries
52
53 for $net (keys %keepnick) {
54 next if $inactive{$net};
55 $server = Irssi::server_find_chatnet($net);
56 next unless $server;
57 next if lc $server->{nick} eq lc $keepnick{$net};
58
59 $getnick{$net} = $keepnick{$net};
60 }
61
62 for $net (keys %getnick) {
63 $server = Irssi::server_find_chatnet($net);
64 next unless $server;
65 $nick = $getnick{$net};
66 if (lc $server->{nick} eq lc $nick) {
67 delete $getnick{$net};
68 next;
69 }
70 $server->redirect_event('keepnick ison', 1, '', -1, undef,
71 { "event 303" => "redir keepnick ison" });
72 $server->send_raw("ISON :$nick");
73 }
74 }
75
76 # --------[ load_nicks ]------------------------------------------------
77
78 sub load_nicks {
79 my($file) = Irssi::get_irssi_dir."/keepnick";
80 my($count) = 0;
81 local(*CONF);
82
83 %keepnick = ();
84 open CONF, "< $file";
85 while (<CONF>) {
86 my($net,$nick) = split;
87 if ($net && $nick) {
88 $keepnick{lc $net} = $nick;
89 $count++;
90 }
91 }
92 close CONF;
93
94 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'keepnick_crap',
95 "Loaded $count nicks from $file");
96 }
97
98 # --------[ save_nicks ]------------------------------------------------
99
100 sub save_nicks {
101 my($auto) = @_;
102 my($file) = Irssi::get_irssi_dir."/keepnick";
103 my($count) = 0;
104 local(*CONF);
105
106 return if $auto && !Irssi::settings_get_bool('keepnick_autosave');
107
108 open CONF, "> $file";
109 for my $net (sort keys %keepnick) {
110 print CONF "$net\t$keepnick{$net}\n";
111 $count++;
112 }
113 close CONF;
114
115 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'keepnick_crap',
116 "Saved $count nicks to $file")
117 unless $auto;
118 }
119
120 # --------[ server_printformat ]----------------------------------------
121
122 sub server_printformat {
123 my($server,$level,$format,@params) = @_;
124 my($emitted) = 0;
125 for my $win (Irssi::windows) {
126 for my $item ($win->items) {
127 next unless ref $item;
128 if ($item->{server}{chatnet} eq $server->{chatnet}) {
129 $item->printformat($level,$format,@params);
130 $emitted++;
131 last;
132 }
133 }
134 }
135 $server->printformat(undef,$level,$format,@params)
136 unless $emitted;
137 }
138
139 # ======[ Signal Hooks ]================================================
140
141 # --------[ sig_message_nick ]------------------------------------------
142
143 # if anyone changes their nick, check if we want their old one.
144 sub sig_message_nick {
145 my($server,$newnick,$oldnick) = @_;
146 my($chatnet) = lc $server->{chatnet};
147 if (lc $oldnick eq lc $getnick{$chatnet}) {
148 change_nick($server, $getnick{$chatnet});
149 }
150 }
151
152 # --------[ sig_message_own_nick ]--------------------------------------
153
154 # if we change our nick, check it to see if we wanted it and if so
155 # remove it from the list.
156 sub sig_message_own_nick {
157 my($server,$newnick,$oldnick) = @_;
158 my($chatnet) = lc $server->{chatnet};
159 if (lc $newnick eq lc $keepnick{$chatnet}) {
160 delete $getnick{$chatnet};
161 if ($inactive{$chatnet}) {
162 delete $inactive{$chatnet};
163 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'keepnick_unhold',
164 $newnick, $chatnet);
165 }
166 } elsif (lc $oldnick eq lc $keepnick{$chatnet} &&
167 lc $newnick eq lc $manual{$chatnet}) {
168 $inactive{$chatnet} = 1;
169 delete $getnick{$chatnet};
170 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'keepnick_hold',
171 $oldnick, $chatnet);
172 }
173 }
174
175 # --------[ sig_message_own_nick_block ]--------------------------------
176
177 sub sig_message_own_nick_block {
178 my($server,$new,$old,$addr) = @_;
179 Irssi::signal_stop();
180 if (Irssi::settings_get_bool('keepnick_quiet')) {
181 Irssi::printformat(MSGLEVEL_NICKS | MSGLEVEL_NO_ACT,
182 'keepnick_got_nick', $new, $server->{chatnet});
183 } else {
184 server_printformat($server, MSGLEVEL_NICKS | MSGLEVEL_NO_ACT,
185 'keepnick_got_nick', $new, $server->{chatnet});
186 }
187 }
188
189 # --------[ sig_message_quit ]------------------------------------------
190
191 # if anyone quits, check if we want their nick.
192 sub sig_message_quit {
193 my($server,$nick) = @_;
194 my($chatnet) = lc $server->{chatnet};
195 if (lc $nick eq lc $getnick{$chatnet}) {
196 change_nick($server, $getnick{$chatnet});
197 }
198 }
199
200 # --------[ sig_redir_keepnick_ison ]-----------------------------------
201
202 sub sig_redir_keepnick_ison {
203 my($server,$text) = @_;
204 my $nick = $getnick{lc $server->{chatnet}};
205 change_nick($server, $nick)
206 unless $text =~ /:\Q$nick\E\s?$/i;
207 }
208
209 # --------[ sig_redir_keepnick_nick ]-----------------------------------
210
211 sub sig_redir_keepnick_nick {
212 my($server,$args,$nick,$addr) = @_;
213 Irssi::signal_add_first('message own_nick', 'sig_message_own_nick_block');
214 Irssi::signal_emit('event nick', @_);
215 Irssi::signal_remove('message own_nick', 'sig_message_own_nick_block');
216 }
217
218 # --------[ sig_setup_reread ]------------------------------------------
219
220 # main setup is reread, so let us do it too
221 sub sig_setup_reread {
222 load_nicks;
223 }
224
225 # --------[ sig_setup_save ]--------------------------------------------
226
227 # main config is saved, and so we should save too
228 sub sig_setup_save {
229 my($mainconf,$auto) = @_;
230 save_nicks($auto);
231 }
232
233 # ======[ Commands ]====================================================
234
235 # --------[ KEEPNICK ]--------------------------------------------------
236
237 # Usage: /KEEPNICK [-net <chatnet>] [<nick>]
238 sub cmd_keepnick {
239 my(@params) = split " ", shift;
240 my($server) = @_;
241 my($chatnet,$nick,@opts);
242
243 # parse named parameters from the parameterlist
244 while (@params) {
245 my($param) = shift @params;
246 if ($param =~ /^-(chat|irc)?net$/i) {
247 $chatnet = shift @params;
248 } elsif ($param =~ /^-/) {
249 Irssi::print("Unknown parameter $param");
250 } else {
251 push @opts, $param;
252 }
253 }
254 $nick = shift @opts;
255
256 # check if the ircnet specified (if any) is valid, and if so get the
257 # server for it
258 if ($chatnet) {
259 my($cn) = Irssi::chatnet_find($chatnet);
260 unless ($cn) {
261 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'keepnick_crap',
262 "Unknown chat network: $chatnet");
263 return;
264 }
265 $chatnet = $cn->{name};
266 $server = Irssi::server_find_chatnet($chatnet);
267 }
268
269 # if we need a server, check if the one we got is connected.
270 unless ($server || ($nick && $chatnet)) {
271 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'keepnick_crap',
272 "Not connected to server");
273 return;
274 }
275
276 # lets get the chatnet, and the nick we want
277 $chatnet ||= $server->{chatnet};
278 $nick ||= $server->{nick};
279
280 # check that we really have a chatnet
281 unless ($chatnet) {
282 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'keepnick_crap',
283 "Unable to find a chatnet");
284 return;
285 }
286
287 if ($inactive{lc $chatnet}) {
288 delete $inactive{lc $chatnet};
289 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'keepnick_unhold',
290 $nick, $chatnet);
291 }
292
293 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'keepnick_add', $nick,
294 $chatnet);
295
296 $keepnick{lc $chatnet} = $nick;
297
298 save_nicks(1);
299 check_nick();
300 }
301
302 # --------[ UNKEEPNICK ]------------------------------------------------
303
304 # Usage: /UNKEEPNICK [<chatnet>]
305 sub cmd_unkeepnick {
306 my($chatnet,$server) = @_;
307
308 # check if the ircnet specified (if any) is valid, and if so get the
309 # server for it
310 if ($chatnet) {
311 my($cn) = Irssi::chatnet_find($chatnet);
312 unless ($cn) {
313 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'keepnick_crap',
314 "Unknown chat network: $chatnet");
315 return;
316 }
317 $chatnet = $cn->{name};
318 } else {
319 $chatnet = $server->{chatnet};
320 }
321
322 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'keepnick_remove',
323 $keepnick{lc $chatnet}, $chatnet);
324
325 delete $keepnick{lc $chatnet};
326 delete $getnick{lc $chatnet};
327
328 save_nicks(1);
329 }
330
331 # --------[ LISTNICK ]--------------------------------------------------
332
333 # Usage: /LISTNICK
334 sub cmd_listnick {
335 my(@nets) = sort keys %keepnick;
336 my $net;
337 if (@nets) {
338 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'keepnick_list_header');
339 for (@nets) {
340 $net = Irssi::chatnet_find($_);
341 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'keepnick_list_line',
342 $keepnick{$_},
343 $net ? $net->{name} : ">$_<",
344 $inactive{$_}?'inactive':'active');
345 }
346 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'keepnick_list_footer');
347 } else {
348 Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'keepnick_list_empty');
349 }
350 }
351
352 # --------[ NICK ]------------------------------------------------------
353
354 sub cmd_nick {
355 my($data,$server) = @_;
356 my($nick) = split " ", $data;
357 return unless $server;
358 $manual{lc $server->{chatnet}} = $nick;
359 }
360
361 # ======[ Setup ]=======================================================
362
363 # --------[ Register settings ]-----------------------------------------
364
365 Irssi::settings_add_bool('keepnick', 'keepnick_autosave', 1);
366 Irssi::settings_add_bool('keepnick', 'keepnick_quiet', 0);
367
368 # --------[ Register formats ]------------------------------------------
369
370 Irssi::theme_register(
371 [
372 'keepnick_crap',
373 '{line_start}{hilight Keepnick:} $0',
374
375 'keepnick_add',
376 '{line_start}{hilight Keepnick:} Now keeping {nick $0} on [$1]',
377
378 'keepnick_remove',
379 '{line_start}{hilight Keepnick:} Stopped trying to keep {nick $0} on [$1]',
380
381 'keepnick_hold',
382 '{line_start}{hilight Keepnick:} Nickkeeping deactivated on [$1]',
383
384 'keepnick_unhold',
385 '{line_start}{hilight Keepnick:} Nickkeeping reactivated on [$1]',
386
387 'keepnick_list_empty',
388 '{line_start}{hilight Keepnick:} No nicks in keep list',
389
390 'keepnick_list_header',
391 '',
392
393 'keepnick_list_line',
394 '{line_start}{hilight Keepnick:} Keeping {nick $0} in [$1] ($2)',
395
396 'keepnick_list_footer',
397 '',
398
399 'keepnick_got_nick',
400 '{hilight Keepnick:} Nickstealer left [$1], got {nick $0} back',
401
402 ]);
403
404 # --------[ Register signals ]------------------------------------------
405
406 Irssi::signal_add('message quit', 'sig_message_quit');
407 Irssi::signal_add('message nick', 'sig_message_nick');
408 Irssi::signal_add('message own_nick', 'sig_message_own_nick');
409
410 Irssi::signal_add('redir keepnick ison', 'sig_redir_keepnick_ison');
411 Irssi::signal_add('redir keepnick nick', 'sig_redir_keepnick_nick');
412
413 Irssi::signal_add('setup saved', 'sig_setup_save');
414 Irssi::signal_add('setup reread', 'sig_setup_reread');
415
416 # --------[ Register commands ]-----------------------------------------
417
418 Irssi::command_bind("keepnick", "cmd_keepnick");
419 Irssi::command_bind("unkeepnick", "cmd_unkeepnick");
420 Irssi::command_bind("listnick", "cmd_listnick");
421 Irssi::command_bind("nick", "cmd_nick");
422
423 # --------[ Register timers ]-------------------------------------------
424
425 Irssi::timeout_add(12000, 'check_nick', '');
426
427 # --------[ Register redirects ]----------------------------------------
428
429 Irssi::Irc::Server::redirect_register('keepnick ison', 0, 0,
430 undef,
431 {
432 "event 303" => -1,
433 },
434 undef );
435
436 Irssi::Irc::Server::redirect_register('keepnick nick', 0, 0,
437 undef,
438 {
439 "event nick" => 0,
440 "event 432" => -1, # ERR_ERRONEUSNICKNAME
441 "event 433" => -1, # ERR_NICKNAMEINUSE
442 "event 437" => -1, # ERR_UNAVAILRESOURCE
443 "event 484" => -1, # ERR_RESTRICTED
444 },
445 undef );
446
447 # --------[ Load config ]-----------------------------------------------
448
449 load_nicks;
450
451 # ======[ END ]=========================================================
452
453 # Local Variables:
454 # header-initial-hide: t
455 # mode: header-minor
456 # end: