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 8use strict; 9use Irssi 20011118.1727; 10use Irssi::Irc; 11 12# ======[ Script Header ]=============================================== 13 14use 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 27my(%keepnick); # nicks we want to keep 28my(%getnick); # nicks we are currently waiting for 29my(%inactive); # inactive chatnets 30my(%manual); # manual nickchanges 31 32# ======[ Helper functions ]============================================ 33 34# --------[ change_nick ]----------------------------------------------- 35 36sub 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 48sub 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 78sub 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 100sub 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 122sub 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. 144sub 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. 156sub 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 177sub 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. 192sub 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 202sub 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 211sub 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 221sub sig_setup_reread { 222 load_nicks; 223} 224 225# --------[ sig_setup_save ]-------------------------------------------- 226 227# main config is saved, and so we should save too 228sub 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>] 238sub 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>] 305sub 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 334sub 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 354sub 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 365Irssi::settings_add_bool('keepnick', 'keepnick_autosave', 1); 366Irssi::settings_add_bool('keepnick', 'keepnick_quiet', 0); 367 368# --------[ Register formats ]------------------------------------------ 369 370Irssi::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 406Irssi::signal_add('message quit', 'sig_message_quit'); 407Irssi::signal_add('message nick', 'sig_message_nick'); 408Irssi::signal_add('message own_nick', 'sig_message_own_nick'); 409 410Irssi::signal_add('redir keepnick ison', 'sig_redir_keepnick_ison'); 411Irssi::signal_add('redir keepnick nick', 'sig_redir_keepnick_nick'); 412 413Irssi::signal_add('setup saved', 'sig_setup_save'); 414Irssi::signal_add('setup reread', 'sig_setup_reread'); 415 416# --------[ Register commands ]----------------------------------------- 417 418Irssi::command_bind("keepnick", "cmd_keepnick"); 419Irssi::command_bind("unkeepnick", "cmd_unkeepnick"); 420Irssi::command_bind("listnick", "cmd_listnick"); 421Irssi::command_bind("nick", "cmd_nick"); 422 423# --------[ Register timers ]------------------------------------------- 424 425Irssi::timeout_add(12000, 'check_nick', ''); 426 427# --------[ Register redirects ]---------------------------------------- 428 429Irssi::Irc::Server::redirect_register('keepnick ison', 0, 0, 430 undef, 431 { 432 "event 303" => -1, 433 }, 434 undef ); 435 436Irssi::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 449load_nicks; 450 451# ======[ END ]========================================================= 452 453# Local Variables: 454# header-initial-hide: t 455# mode: header-minor 456# end: 457