dispatch.pl


use strict;
#use warnings;
use Irssi;
use Irssi::Irc;
use vars qw($VERSION %IRSSI %cmplist $active %static_list);

$VERSION = "0.0.3";
%IRSSI = (
	authors     => "Sebastian 'yath' Schmidt, Valentin Batz",
	contact     => "yathen\@web.de, senneth\@irssi.org",
	name        => "Command dispatcher, with tab completion",
	description => "This scripts sends only known commands to the server",
	license     => "GNU GPLv2",
	changed     => "Thu Jan 12 19:27:38 CET 2006",
	revision    => '$LastChangedRevision: 368 $',
	changed     => '$LastChangedDate: 2006-01-31 22:29:39 +0100 (Di, 31 Jan 2006) $',
	version     => $VERSION,
);

$active = 0;

%static_list = (
	euircd => [ 
		"cs", "chanserv",
		"ns", "nickserv",
		"ms", "memoserv", 
	],
	hybrid => [ 
		"locops", "lwallops", "ltrace",
		"close", "kline", "unkline",
		"dline", "htm",
		"gline", "testline",
	],
);

sub load_static_commands {
	my $server = shift;
	if ($server->{'version'} =~ /^euircd/i) {
		@{$cmplist{$server->{'tag'}}} = @{$static_list{euircd}};
	} elsif ($server->{'version'} =~ /^hybrid/i) {
		@{$cmplist{$server->{'tag'}}} = @{$static_list{hybrid}};
	}
}

sub event_help_notice {
	# "message irc notice", SERVER_REC, char *msg, char *nick, char *address, char *target
	my ($server, $msg, $nick, undef, $target) = @_;
	#assume that nicks can't contain dots or hyphens (so it works with irssi-proxy and psybnc)
	if ( defined $server && $nick =~ /[-\.]/ && $target eq $server->{'nick'} ) {
		@{$cmplist{$server->{'tag'}}} = ( @{$cmplist{$server->{'tag'}}}, lc $msg );
		Irssi::signal_stop();
	}
}

# ratbox specific stuff
sub event_help_reply {
	my ($server, $data) = @_;
	my (undef, $cmds) = split ':', $data, 2;
	if ($cmds ne '') {
		my @commands = split '\ +', lc $cmds;
		@{$cmplist{$server->{'tag'}}} = ( @{$cmplist{$server->{'tag'}}}, @commands );
	}
	Irssi::signal_stop();
}

Irssi::Irc::Server::redirect_register( "help reply", 0, 0,
					{
						"event 704" => -1,
					},
					{
						"event 706" => -1,
					},
					undef );
#end ratbox

sub add_sig {
	return if $active;
	Irssi::signal_add("message irc notice", "event_help_notice");
	$active = 1;
}

sub remove_sig {
	return if not $active;
	Irssi::signal_remove("message irc notice", "event_help_notice");
	$active = 0;
}

sub remove_sig_later {
	return if not $active;
	my $timeout = shift;
	$timeout = 1000 if $timeout < 1000;
	Irssi::timeout_add_once($timeout, "remove_sig", undef);
}

sub update_server_cmds {
	my $server = shift;
	return if not defined $server;
	@{$cmplist{$server->{'tag'}}} = ();
	# hybrid and euircd sends more than just commands :/
	if ($server->{'version'} =~ /(^Hybrid|^euIRCd)/) {
		load_static_commands($server);
		return;
	}
	if ( $server->{'version'} =~ /^ircd-ratbox/i ) {
		$server->redirect_event( "help reply", 0, '', -1, undef,
					{
						"event 705" => "redir help reply",
						""	=> "event empty",
					} );
	}
	$server->send_raw('HELP');
}

sub update_server_later {
	my $tag = shift;
	my $server = Irssi::server_find_tag($tag);
	return unless $server;
	add_sig();
	update_server_cmds($server);
	remove_sig_later();
}

sub event_connected {
	my $server = shift;
	#add_sig();
	#update_server_cmds($server);
	#remove_sig_later();
	if ($server->{'chat_type'} eq 'IRC') {
		Irssi::timeout_add_once(20000, "update_server_later", $server->{'tag'});
	}
}

sub get_ircd_commands {
	my $nservers = 0;
	if (defined Irssi::servers()) {
		add_sig();
		foreach my $server (Irssi::servers()) {
				next if $server->{'chat_type'} ne 'IRC';
				update_server_cmds($server);
				$nservers++;
		}
		remove_sig_later(1000 * $nservers);
	}
}

sub event_default_command {
	my ($command, $server) = @_;
	return if (Irssi::settings_get_bool("dispatch_unknown_commands") == 0
		|| !$server || $server->{'chat_type'} ne 'IRC');
	my $found = 0;
	foreach my $cmd ( @{$cmplist{$server->{'tag'}}} ) {
		my $quoted = quotemeta $cmd;
		if ($command =~ /^$quoted/) {
			$found = 1;
			last;
		}
	}
	if ($found || scalar @{$cmplist{$server->{'tag'}}} eq 0 ) {
		$server->send_raw($command);
		Irssi::signal_stop();
	}
}

sub sig_complete_word {
	my ($complist, $window, $word, $linestart, $want_space) = @_;
	my $cmdchars = quotemeta Irssi::settings_get_str("cmdchars");
	if ($word =~ /^[$cmdchars]/) {
		my $prefix = substr($word, 0, 1); #preserve cmdchar
		my $tag = $window->{'active_server'}->{'tag'};
		my $arr = $cmplist{ $tag };
		if (defined $arr) {
			@{$arr} = sort(@{$arr});
			my $cmd = quotemeta substr($word, 1);
			my @cmds;
			foreach my $c (@$arr) {
				if ($c =~ /^$cmd/) {
					@cmds = (@cmds, $prefix.$c);
				}
			}
			if (scalar @cmds gt 0) { push (@{$complist}, @cmds); }
		}
	}
	
}

Irssi::settings_add_bool("misc", "dispatch_unknown_commands", 1);
Irssi::signal_add_first("default command", "event_default_command");
Irssi::signal_add_first("redir help reply", "event_help_reply");
Irssi::signal_add_last("complete word", "sig_complete_word");
Irssi::signal_add_last("event connected", "event_connected");
get_ircd_commands();