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: