use strict;
use vars qw($VERSION %IRSSI);

use Irssi;
use Data::Dumper;
$VERSION = '0.41';
%IRSSI = (
    authors     => 'Remco Lanting',
    contact     => 'remco.lanting+irssi@gmail.com',
    name        => 'Operscript',
    description => 'Do some magic to unrealircd server notices',
    license	=> 'Public domain',
);

#
# Todo:
#
# - add more notice formats
# - change the window title(s) for the notices to something nice if possible
# - if connect rate is just slightly over the limit for a longer period, 
#   auto-adjust the setting
# + Make sure alerts have a timeout between them
# - Logging of notices, with an on/off setting
#
# - = todo
# + = implemented but pretty much untested
#
my $wname;
my $window;
my $sname;
my $lastalert = 0;

# %servers{'servername'} 
# [0] = min array 
# [1] = sec array 
# [2] = chistory 
#   [0] = start time
#   [1] = total number of connects
# [3] = settings
#   [0] = enabled (0/1)
#   [1] = 10 second window
#   [2] = 60 second window
#   [3] = alltime window
#   [4] = alerts (0/1)
# [4] = kline queue
my %servers = ();

sub load_data {
	# load the settings into the hash
	# irc.server.com-BOOL-0.5-0.2-0.1-BOOL irc.server2.com- etc.
	my @d = split(/ /, Irssi::settings_get_str('operscript_servers'));
	%servers = ();
	return unless scalar @d >=1;
	foreach my $s(@d) {
		my @si = split(/\-/,$s);
		@servers{$si[0]} = [ [], [], [time()-1,0], [$si[1], $si[2], $si[3], $si[4], $si[5]] ];
	}
}
sub populate_servers {
	# initial adding of servers so they don't have to be created manually
	my @serverlist = Irssi::servers();
	my $count = 0;
	foreach my $s(@serverlist) {
		if ($s->{'server_operator'} || $s->{'usermode'} =~ /o/i ) {
			@servers{$s->{'real_address'}} = [[],[],[time()-1,0],["1", Irssi::settings_get_str('operscript_10sec'), Irssi::settings_get_str('operscript_60sec'), Irssi::settings_get_str('operscript_alltime'), "0"]];
			$count++;
		}
	}
	Irssi::print($count." servers were added and enabled automatically because you have an o-line on those servers");
	operscript_save(0);
}
sub alert {
	my ($message, $servername) = @_;
	if ($message && @{${$servers{$servername}}[3]}[4] && $lastalert + 120 < time()) {
		$window->printformat(MSGLEVEL_SNOTES+MSGLEVEL_HILIGHT, 'alert', $message);
		$lastalert = time();
	}
}
sub connect_check {	
	my ($servername) = @_;
	my $time = time();
	
	push(@{${$servers{$servername}}[0]}, $time);
	push(@{${$servers{$servername}}[1]}, $time);
	@{${$servers{$servername}}[2]}[1]++;
	
	while ( @{${$servers{$servername}}[0]}[0] + 60 < $time) {
		shift(@{@{$servers{$servername}}[0]});
	}
	while ( @{${$servers{$servername}}[1]}[0] + 10 < $time) {
		shift(@{@{$servers{$servername}}[1]});
	}

	my $at = @{${$servers{$servername}}[2]}[1]/(time()-@{${$servers{$servername}}[2]}[0]);
	my $sec = @{@{$servers{$servername}}[1]}/10;
	my $min = @{@{$servers{$servername}}[0]}/60;
        if (Irssi::settings_get_bool('operscript_debug')) {
		print "10sec: $sec /s, 60sec: $min /s, alltime: $at /s";
	}
	
	if ( ($sec > @{${$servers{$servername}}[3]}[1]) || ($min > @{${$servers{$servername}}[3]}[2]) || ($at > @{${$servers{$servername}}[3]}[3]) ) {
		return 1;
	}
	return 0;
}

sub event_notice {
	my ($server, $data, $nick, $address) = @_;

	my @d = split(/:/,$data);
	# only server notices (1) for servers that are defined (2) and enabled (3) sent to me (4)
	return unless $nick eq $server->{'real_address'} && defined $servers{$server->{'real_address'}} && @{${$servers{$server->{'real_address'}}}[3]}[0] && substr($d[0],0,-1) eq $server->{'nick'};	

	if ( Irssi::settings_get_bool('operscript_seperate_servers')) {
		$wname = $nick;
		$sname = "";
	} else {
		$wname = "snotice";
		$sname = $server->{'real_address'}." ";
	}

	$window = Irssi::window_find_name($wname);
	if(!defined $window) {
		$window = Irssi::Windowitem::window_create($wname, 1);
		$window->set_name($wname);
		# $window->change_server($server) if (Irssi::settings_get_bool('operscript_seperate_servers'));
	}
	$window->change_server($server) if (Irssi::settings_get_bool('operscript_seperate_servers'));
	# remove colours so hilighting lines works better
	$data =~ s/\x03\d?\d?(,\d?\d?)?|\x02|\x1f|\x16|\x06|\x07//g;
	if (index($data,"*** Notice") ne -1) {
		if ($data =~ /\*\*\* Notice \-\- Client connecting on port (\d+): ([^\s]+) \(([^\s]+)\) \[(.+)\] $/ ) {
			$window->printformat(MSGLEVEL_SNOTES, 'connect', $sname, $1, $2, $3, $4);
			alert("Connect flood detected", $sname) unless !connect_check($sname);
		}
		elsif($data =~ /\*\*\* Notice \-\- Client connecting on port (\d+): ([^\s]+) \(([^\s]+)\) \[([^\s]+)\] \[(.+)\]/ ) {
			$window->printformat(MSGLEVEL_SNOTES, 'connectssl', $sname, $1, $2, $3, $4, $5);
			alert("Connect flood detected", $sname) unless !connect_check($sname);
		}
		elsif($data =~ /\*\*\* Notice \-\- Client exiting: ([^\s]+) \(([^\s]+)\) \[(.+)\]/ ) {
			$window->printformat(MSGLEVEL_SNOTES, 'disconnect', $sname, $1, $2, $3);
		}
		elsif($data =~ /\*\*\* Notice \-\- Received KILL message for ([^\s]+) from ([^\s]+) Path: ([^\s]+) \((.+)\)/ ) {
			$window->printformat(MSGLEVEL_SNOTES, 'kill', $sname, $1, $2, $3, $4)
		}
		elsif($data =~ /\*\*\* Notice \-\- ([^\s]+) \(([^\s]+)\) has been forced to change his\/her nickname to ([^\s]+)/ ) {
                        $window->printformat(MSGLEVEL_SNOTES, 'nickchangeforce', $sname, $1, $2, $3)
                }
		elsif($data =~ /\*\*\* Notice \-\- ([^\s]+) \(([^\s]+)\) has changed his\/her nickname to ([^\s]+)/ ) {
                        $window->printformat(MSGLEVEL_SNOTES, 'nickchange', $sname, $1, $2, $3)
                }
		elsif($data =~ /\*\*\* Notice \-\- TS Control \- U:line set time to be ([\d]+) \(timediff: ([\d]+)\)/ ) {
                        $window->printformat(MSGLEVEL_SNOTES, 'tscontrol', $sname, $1, $2, $3)
                }
		elsif($data =~ /\*\*\* Notice \-\- ([^\s]+) used ([^\s]+) to make ([^\s]+) join ([^\s]+)/ ) {
                        $window->printformat(MSGLEVEL_SNOTES, 'saoverride', $sname, $1, $2, $3, $4)
                }
		elsif($data =~ /\*\*\* Notice \-\- ([^\s]+) used ([^\s]+) to make ([^\s]+) part ([^\s]+)/ ) {
                        $window->printformat(MSGLEVEL_SNOTES, 'saoverride', $sname, $1, $2, $3, $4)
                }
		elsif($data =~ /\*\*\* Notice \-\- ([^\s]+) is rehashing server config file/ ) {
			$window->printformat(MSGLEVEL_SNOTES, 'rehash', $sname, $1)
		}
                elsif($data =~ /\*\*\* Notice \-\- (Loading IRCd configuration \.\.)/ ) {
                        $window->printformat(MSGLEVEL_SNOTES, 'rehashmessage', $sname, $1)
                }
                elsif($data =~ /\*\*\* Notice \-\- (Configuration loaded without any problems \.\.)/ ) {
                        $window->printformat(MSGLEVEL_SNOTES, 'rehashmessage', $sname, $1)
                }
		elsif ( Irssi::settings_get_bool('operscript_unknown')) {
		# so anything I missed is logged too
			$window->printformat(MSGLEVEL_SNOTES, 'unknown', $sname, $data);
        	}

	}
	elsif (index($data,"*** OperOverride") ne -1) {
		#$window->print("[operoverride] $data");
		if ($data =~ /\*\*\* OperOverride \-\- ([^\s]+) \(([^\s]+)\) invited him\/herself into ([^\s]+) \(overriding ([^\s]+)\)/ ) {
			$window->printformat(MSGLEVEL_SNOTES, 'operinvite', $sname, $1, $2, $3, $4);
		}
		elsif ($data =~ /\*\*\* OperOverride \-\- ([^\s]+) \(([^\s]+)\) MODE ([^\s]+) ([^\s]+) ?(.+)?/ ) {
			$window->printformat(MSGLEVEL_SNOTES, 'opermode', $sname, $1, $2, $3, $4, $5);
		}
		elsif ($data =~ /\*\*\* OperOverride \-\- ([^\s]+) \(([^\s]+)\) TOPIC ([^\s]+) \'(.+)\'/ ) {
                        $window->printformat(MSGLEVEL_SNOTES, 'opertopic', $sname, $1, $2, $3, $4);
                }		
		elsif ($data =~ /\*\*\* OperOverride \-\- ([^\s]+) \(([^\s]+)\) KICK ([^\s]+) ([^\s]+) \((.+)\)/ ) {
                        $window->printformat(MSGLEVEL_SNOTES, 'operkick', $sname, $1, $2, $3, $4, $5);
                }
	}
	elsif (index($data,"[\2vhost\2]") ne -1) {
		#if you login yourself and fail, you get a notice too.
		#$window->print("[vhost notice] $data");
		if ($data =~ /Failed login for vhost ([^\s]+) by ([^\s]+) \- (.+)/) {
			$window->printformat(MSGLEVEL_SNOTES, 'vhosterror', $sname, $1, $2, $3);
		}
		elsif ($data =~ /([^\s]+) \(([^\s]+)\) is now using vhost ([^\s]+)/) {
			$window->printformat(MSGLEVEL_SNOTES, 'vhost', $sname, $1, $2, $3);
		}
		elsif ($data =~ /Login for ([^\s]+) failed - password incorrect/) {
			# this notice is because you failed to login using /vhost
			# yourself, return control back to the main loop
			return;
		} 
	}
	elsif (index($data,"Exiting ssl client") ne -1) {
		if ($data =~ /Exiting ssl client \[\@([\d]+\.[\d]+\.[\d]+\.[\d]+)\.([\d]+)\]: (.+)/) {
			$window->printformat(MSGLEVEL_SNOTES, 'ssl1', $sname, $1, $2, $3);
		}
		elsif ($data =~ /Exiting ssl client (.+)\[\@([\d]+\.[\d]+\.[\d]+\.[\d]+)\.([\d]+)\]: (.+)/) {
			$window->printformat(MSGLEVEL_SNOTES, 'ssl2', $sname, $1, $2, $3, $4);
		}
	}
	elsif ($data =~ /Failed OPER attempt by ([^\s]+) \(([^\s]+)\) \[(.+)\]/) {
		$window->printformat(MSGLEVEL_SNOTES, 'operunknown', $sname, $1, $2, $3);
	}
	elsif ($data =~ /Failed OPER attempt by ([^\s]+) \(([^\s]+)\) using UID ([^\s]+) \[(.+)\]/) {
		$window->printformat(MSGLEVEL_SNOTES, 'operfail', $sname, $1, $2, $3, $4);
	}
	elsif ($data =~ /Stats \'(.)\' requested by ([^\s]+) \(([^\s]+)\)/ ) {
		$window->printformat(MSGLEVEL_SNOTES, 'stats', $sname, $1, $2, $3);
	}
	elsif ($data =~ /\*\*\* Global \-\- from ([^\s]+): (.+)$/ ) {
		if ($1 eq $server->{'real_address'}) {
			# this should be a /samode, or anything else the server is stupid enough to send over Global
			if ($data =~ /\*\*\* Global \-\- from ([^\s]+): ([^\s]+) used ([^\s]+) ([^\s]+) \(([^\s]+)\)/) {
				$window->printformat(MSGLEVEL_SNOTES, 'saoverride', $sname, $2, $3, $4, $5);
			}
			else {
				$window->printformat(MSGLEVEL_SNOTES, 'unknown', $sname, $data);
			}
		}
		else {
			$window->printformat(MSGLEVEL_SNOTES+MSGLEVEL_PUBLIC, 'globops', $sname, $1, $2);
		}
	}
	elsif ($data =~ /\*\*\* LocOps \-\- from ([^\s]+): (.+)$/ ) {
		$window->printformat(MSGLEVEL_SNOTES+MSGLEVEL_PUBLIC, 'locops', $sname, $1, $2);
	}
	elsif ($data =~ /\*\*\* ChatOps \-\- from ([^\s]+): (.+)$/ ) {
                $window->printformat(MSGLEVEL_SNOTES+MSGLEVEL_PUBLIC, 'chatops', $sname, $1, $2);
        }
	elsif ($data =~ /\*\*\* AdminChat \-\- from ([^\s]+): (.+)$/ ) {
                $window->printformat(MSGLEVEL_SNOTES+MSGLEVEL_PUBLIC, 'adminchat', $sname, $1, $2);
        }
	elsif ($data =~ /\*\*\* NetAdmin\.Chat \-\- from ([^\s]+): (.+)$/ ) {
                $window->printformat(MSGLEVEL_SNOTES+MSGLEVEL_PUBLIC, 'netadminchat', $sname, $1, $2);
        }
        elsif ($data =~ /\*\*\* HelpOp \-\- from ([^\s]+) \(([^\s]+)\): (.+)$/ ) {
                $window->printformat(MSGLEVEL_SNOTES+MSGLEVEL_PUBLIC, 'helpop', $sname, $1, $2, $3);
        }
	elsif ($data =~ /\*\*\* (.*) added for (.*) on (.*) \(from (.*) to expire at (.*): (.*)\)$/ ) {
		$window->printformat(MSGLEVEL_SNOTES, 'line', $sname, $1, $2, $3, $4, $5, $6);
	}
	elsif ($data =~ /\*\*\* Expiring (.*) \(([^\s]+)\) made by ([^\s]+) \(Reason: (.*)\) set ([^\s]+) seconds ago/) {
		$window->printformat(MSGLEVEL_SNOTES, 'exline', $sname, $1, $2, $3, $4, $5);
	}
	elsif ($data =~ /([^\s]+) removed (.*) ([^\s]+) \(set at (.*) - reason: (.*)\)/ ) {
		$window->printformat(MSGLEVEL_SNOTES, 'unline', $sname, substr($1,1), $2, $3, $4, $5);
	}
	elsif ($data =~ /([^\s:]+) changed the (.*) of ([^\s]+) \(([^\s]+)\) to be (.*)/) {
		$window->printformat(MSGLEVEL_SNOTES, 'chinfo', $sname, $1, $2, $3, $4, $5);
	}
	elsif ($data =~ /\*\*\* ([^\s]+) \(([^\s]+)\) did a \/whois on you/ ) {
		$window->printformat(MSGLEVEL_SNOTES+MSGLEVEL_PUBLIC, 'whois', $sname, $1, $2);
	}
	elsif ($data =~ /([^\s]+) \(([^\s]+)\) \[([^\s]+)\] is now (.+) \(([^\s]+)\)/) {
		$window->printformat(MSGLEVEL_SNOTES, 'operup', $sname, substr($1,1), $2, $3, $4, $5);
	}
	elsif ($data =~ /\*\*\* Flood \-\- ([^\s]+) \(([^\s]+)\) exceeds ([\d]+) ([^\s]+)/) {
		$window->printformat(MSGLEVEL_SNOTES, 'sflood', $sname, substr($1,1), $2, $3, $4);
	}
	elsif ($data =~ /Forbidding Q-lined nick ([^\s]+) from \[([^\s]+)\]/) {
		if (Irssi::settings_get_bool('operscript_zline_on_qline')) {
			$server->command("quote zline +*\@$2 7d botnet");
		}
		$window->printformat(MSGLEVEL_SNOTES, 'qline', $sname, $1, $2);
	}
	elsif (index($data,"Spamfilter") ne -1) {
		if ($data =~ /\*\*\* Spamfilter added: \'(.*)\' \[target: ([^\s]+)\] \[action: ([^\s]+)\] \[reason: (.*)\] on (.*) \(from ([^\s]+)\)/) {
			$window->printformat(MSGLEVEL_SNOTES, 'spamadd', $sname, $1, $2, $3, $4, $5, $6);
		}
		elsif ($data =~ /([^\s]+) removed Spamfilter \'(.*)\' \(set at (.*)\)/) {
			$window->printformat(MSGLEVEL_SNOTES, 'spamdel', $sname, $1, $2, $3);
		}
		elsif ($data =~ /\[Spamfilter\] ([^\s]+) matches filter \'(.*)\': \[([^\s]+) ([^\s]+): \'(.*)\'\] \[(.*)\]/) {
			$window->printformat(MSGLEVEL_SNOTES, 'spammatch', $sname, $1, $2, $3, $4, $5, $6);
		}
	}
	elsif ( Irssi::settings_get_bool('operscript_unknown')) {
		# a lot of stuff can end up here, hence the setting
		$window->printformat(MSGLEVEL_SNOTES, 'unknown', $sname, $data);
	}
	else {
		# nothing matched and unknown lines are not captured so return before the signal is stopped
		return;
	}
	Irssi::signal_stop();
}

sub operscript_sub {
        my ($cstring, $server, $item) = @_;
	my @mywords = split(/ /, lc($cstring));
	
	if ($mywords[0] eq "view") {
		return unless operscript_checkserver($mywords[1]);
		my @d = @{${$servers{$mywords[1]}}[3]};
		Irssi::print("Settings for ".$mywords[1]);
		Irssi::print("Enabled: ".$d[0]);
		Irssi::print("10 second window: ".$d[1]);
		Irssi::print("60 second window: ".$d[2]);
		Irssi::print("Alltime window: ".$d[3]);
		Irssi::print("Alerts: ".$d[4]);		
	}
	elsif ($mywords[0] eq "stats") {
		return unless operscript_checkserver($mywords[1]);
		Irssi::print("Fancy stats will perhaps get to be here sometime");
	}
	elsif ($mywords[0] eq "add") {
		if (defined $servers{$mywords[1]}) {
			Irssi::print("Server is already defined");
		}
		else {
			@servers{$mywords[1]} = [[],[],[time()-1,0],["1", Irssi::settings_get_str('operscript_10sec'), Irssi::settings_get_str('operscript_60sec'), Irssi::settings_get_str('operscript_alltime'), "0"]];
			Irssi::print("Server added");
			operscript_save(0);
		}
	}
	elsif ($mywords[0] eq "del") {
		return unless operscript_checkserver($mywords[1]);
		delete $servers{$mywords[1]};
		Irssi::print("Server deleted");
		operscript_save(0);
	}
	elsif ($mywords[0] eq "set") {
		return unless operscript_checkserver($mywords[1]);
		if ($mywords[2] eq "enabled") {
			if ($mywords[3] eq "1" || $mywords[3] eq "0") {
				${${$servers{$mywords[1]}}[3]}[0] = $mywords[3];
				operscript_save(1);
			}
			else {
				Irssi::print("Unknown value '".$mywords[3]."'. Expected 0 or 1");
			}
		}
		elsif ($mywords[2] eq "10sec") {
			if ($mywords[3] > 0) {
				${${$servers{$mywords[1]}}[3]}[1] = $mywords[3];
				operscript_save(1);
			}
			else {
				Irssi::print("Unknown value '".$mywords[3]."'. Expected a (decimal) number greater than zero");
			}
		}
		elsif ($mywords[2] eq "60sec") {
			if ($mywords[3] > 0) {
				${${$servers{$mywords[1]}}[3]}[2] = $mywords[3];
				operscript_save(1);
			}
			else {
				Irssi::print("Unknown value '".$mywords[3]."'. Expected a (decimal) number greater than zero");
			}
		}
		elsif ($mywords[2] eq "alltime") {
			if ($mywords[3] > 0) {
				${${$servers{$mywords[1]}}[3]}[3] = $mywords[3];
				operscript_save(1);
			}
			else {
				Irssi::print("Unknown value '".$mywords[3]."'. Expected a (decimal) number greater than zero");
			}
		}
		elsif ($mywords[2] eq "alerts") {
			if ($mywords[3] eq "1" || $mywords[3] eq "0") {
				${${$servers{$mywords[1]}}[3]}[4] = $mywords[3]; 
				operscript_save(1);
			}
			else {
				Irssi::print("Unknown value '".$mywords[3]."'. Expected 0 or 1");
			}
		}
		else {
			Irssi::print("Unknown setting '".$mywords[2]."' Expected <enabled|10sec|60sec|alltime|alerts>");
		}
	}
	elsif ($mywords[0] eq "save") {
		operscript_save(1);
	}
	elsif ($mywords[0] eq "reload") {
		load_data();
	}
	else {
		Irssi::print("Operscript usage:");
		Irssi::print("/operscript help: display this help");
		Irssi::print("/operscript add <servername>: add a server");
		Irssi::print("/operscript del <servername>: delete a server");
		Irssi::print("/operscript view <servername>: view server settings");
		Irssi::print("/operscript set <servername> <enabled|10sec|60sec|alltime|alerts> <value>: alter a setting");
		Irssi::print("/operscript save: save all settings to the /set");
		Irssi::print("/operscript reload: reload the settings from the /set");
		Irssi::print("There are also a few global settings, do '/set operscript' to see them all");
	}
}
sub operscript_checkserver {
	my ($server) = @_;
	if (defined $servers{$server}) {
		return 1;
	}
	else {
		Irssi::print("The server named '".$server."' doesn't exist");
		return 0;
	}
}
sub operscript_save {
	my ($noisy) = @_;
	# save all settings to the /set
	my $savestring = "";
	while (my($key, $value) = each(%servers)){
		$savestring .= $key;
		foreach my $item (@{${$servers{$key}}[3]}) {
			$savestring .= "-".$item;
		}
		$savestring .= " ";
	}

	Irssi::settings_set_str("operscript_servers", $savestring);
	return unless $noisy;
	Irssi::print("Settings saved successfully");
}

sub event_send_text {
	my ($data, $server, $witem) = @_;
	my $active_window = Irssi::active_win();
	if ( $active_window->{'name'} ne "snotice" && $active_window->{'name'} ne $server->{'real_address'} ) {
		return;
	}
	if ($server eq '0') {
		$active_window->printformat(MSGLEVEL_SNOTES, 'message', "", "No active server, change with ^X");
		return;
	}
	if (!operscript_checkoper()) {
		$active_window->printformat(MSGLEVEL_SNOTES, 'message', "", "You're not an oper on ".$server->{'real_address'}.", change server with ^X");
		return;
	}
	if ($data =~ /^kline queue$/i) {
		operscript_process_queue($server, "kline", "+");
	} elsif ($data =~ /^clear queue$/i) {
		%{${$servers{$server->{'real_address'}}}[4]} = ();
		$active_window->printformat(MSGLEVEL_CLIENTCRAP, 'message', "", "Queue cleared");
	} elsif ($data =~ /^gline queue$/i) {
		operscript_process_queue($server, "gline", "+");
	} elsif ($data =~ /^ungline queue$/i) {
		operscript_process_queue($server, "gline", "-");
	} elsif ($data =~ /^shun queue$/i) {
		operscript_process_queue($server, "shun", "+");
	} elsif ($data =~ /^unshun queue$/i) {
		operscript_process_queue($server, "shun", "-");
	} elsif ($data =~ /^unkline queue$/i) {
		operscript_process_queue($server, "kline", "-");
	}
	operscript_queue($server,$data,$active_window);
	Irssi::signal_stop();
}
sub operscript_queue {
	my ($server, $line,$window) = @_;
	#filter out *.opera.com here
	if ($line =~ /\b~?([a-zA-Z0-9._-]{1,10})@([a-zA-Z0-9_.-]+)\b/) {
		my ($user, $host) = ($1, $2);
		if ($host =~ /.*\.opera\.com/) {
			return;
		}
		@{${$servers{$server->{'real_address'}}}[4]}{"$host"} = $user;
		if (Irssi::settings_get_bool('operscript_kline_queue')) {
			my $prefix = "";
			if ( !Irssi::settings_get_bool('operscript_seperate_servers')) {
				$prefix = $server->{'real_address'}." ";
			}
			$window->printformat(MSGLEVEL_CLIENTCRAP, 'message', $prefix, "host added to queue");
		} else {
			operscript_process_queue($server, "kline", "+");
		}		
        }

}

sub operscript_process_queue {
	my ($server, $action, $mod) = @_;
	my $time = Irssi::settings_get_int('operscript_kline_time');
	my $reason = Irssi::settings_get_str('operscript_kline_reason');
	my $count = 0;
	while (my($key, $value) = each(%{${$servers{$server->{'real_address'}}}[4]})){
		$server->command("quote $action $mod*\@$key $time $reason");
		$count++;
	}
	%{${$servers{$server->{'real_address'}}}[4]} = ();
	my $prefix = "";
	if ( !Irssi::settings_get_bool('operscript_seperate_servers')) {
		$prefix = $server->{'real_address'}." ";
	}
	$mod = ($mod eq "+")? "added":"removed";
	Irssi::active_win()->printformat(MSGLEVEL_CLIENTCRAP, 'message', $prefix, $action." ".$mod." for ".$count." hosts");
}

sub operscript_checkoper {
	return 0 unless Irssi::active_server();
	return 1 if Irssi::active_server()->{server_operator}
		 or Irssi::active_server()->{'usermode'} =~ /o/i;
	return 0;
}
# Using {servernotice $0} would be nice but it doesn't collapse if there is no content
Irssi::theme_register([
	'connect', '{server $0}[%BConnect%n] {nick $2} {nickhost $3} on port $1, type $4',
	'connectssl', '{server $0}[%BConnect%n] {nick $2} {nickhost $3} on port $1, type $4 [$5]',
	'disconnect', '{server $0}[%bDisconnect%n] {nick $1} {nickhost $2} {reason $3}',
	'kill', '{server $0}[%mKill%n] {nickhost $1} was killed by {nickhost $2} Path: $3 {reason $4}',
	'stats', '{server $0}[%YStats%n] /stats $1 reguested by {nick $2} {nickhost $3}',
	'operinvite', '{server $0}[%gOperOverride%n] {nick $1} {nickhost $2} invited him/herself into $3 overriding $4',
	'opermode', '{server $0}[%gOperOverride%n] {nick $1} {nickhost $2} did a /mode $3 $4 $5',
	'opertopic', '{server $0}[%gOperOverride%n] {nick $1} {nickhost $2} changed the topic on $3 to \'$4\'',
	'operkick', '{server $0}[%gOperOverride%n] {nick $1} {nickhost $2} kicked $4 from $3 with reason {reason $5}',
	'operunknown', '{server $0}[%rFailed OPER%n] {nick $1} {nickhost $2} tried to oper up but got {reason $3}',
	'operfail', '{server $0}[%rFailed OPER%n] {nick $1} {nickhost $2} tried to oper up using {nick $3} but got {reason $4}',
	'nickchange', '{server $0}[%cNickChange%n] {nick $1} {nickhost $2} has changed his/her nick to {nick $3}',
	'nickchangeforce', '{server $0}[%KNickChange%n] An oper forced {nick $1} {nickhost $2} to change his/her nick to {nick $3}',
	'tscontrol', '{server $0}[%yTScontrol%n] U:line set time to be $1 (difference: $2)',
	'vhosterror', '{server $0}[Vhost] {nickhost $2} failed login for $1 {reason $3}',
	'vhost', '{server $0}[Vhost] {nick $1} {nickhost $2} is now using vhost $3',
	'globops', '{server $0}[GlobOps] {msgnick $1}$2',
	'locops', '{server $0}[LocOps] {msgnick $1}$2',
	'chatops', '{server $0}[ChatOps] {msgnick $1}$2',
	'adminchat', '{server $0}[AdminChat] {msgnick $1}$2',
	'netadminchat', '{server $0}[NetAdminChat] {msgnick $1}$2',
	'helpop', '{server $0}[HelpOp] ($2) {msgnick $1}$3',
	'saoverride', '{server $0}[%GSAoverride%n] {nick $1} used $2 on $3 ($4)',
	'line', '{server $0}[%MServerBan%n] $1 for {nickhost $2} set on $3 by {nickhost $4} expiring on $5 {reason $6}',
	'exline', '{server $0}[%MServerBan%n] Expiring $1 for {nickhost $2} set by {nickhost $3} {reason $4} (was set $5 seconds ago)',
	'unline', '{server $0}[%MServerBan%n] $1 removed $2 set on {nickhost $3} (set at $4 {reason $5})',
	'chinfo', '{server $0}[Info] {nick $1} changed the $2 of {nick $3} {nickhost $4} to be $5',
	'alert', '[%RALERT%n] $0',
	'whois', '{server $0}[%CWhois%n] $1 {nickhost $2} did a /whois on you',
	'message', '{server $0}[Message] $1',
	'operup', '{server $0}[OperUP] $1 {nickhost $2} opered up using login [$3], making him/her $4 ($5)',
	'sflood', '{server $0}[Flood] {nickhost $1} $4 $2>$3',
	'ssl1', '{server $0}[%KSSLError%n] Client connecting from {nickhost $1}, port $2 had a problem: $3',
	'ssl2', '{server $0}[%KSSLError%n] {nick $1} connecting from {nickhost $2}, port $3 had a problem: $4',
	'qline', '{server $0}[Q:line] Forbidding Q-lined nick $1 from $2',
	'spamadd', '{server $0}[Spamfilter] Added: \'$1\' [target: $2] [action: $3] [reason: $4] on $5 by {nickhost $6}',
	'spamdel', '{server $0}[Spamfilter] Removed: \'$2\' on $3 by {nickhost $1}',
	'spammatch', '{server $0}[Spamfilter] Match: \'$2\' by {nickhost $1} [target: $3 $4] [message: $5] [reason: $6]',
	'rehash', '{server $0}[Rehash] Config file is being rehashed by $1',
	'rehashmessage', '{server $0}[Rehash] $1',
	'unknown', '{server $0}[Unknown] $1'
]);
# global settings
Irssi::settings_add_bool('operscript', 'operscript_seperate_servers', 0);
Irssi::settings_add_bool('operscript', 'operscript_debug', 0);
Irssi::settings_add_bool('operscript', 'operscript_unknown', 0);
Irssi::settings_add_bool('operscript', 'operscript_zline_on_qline', 0);
# Initial values for the per server settings
Irssi::settings_add_str('operscript', 'operscript_10sec', "0.5");
Irssi::settings_add_str('operscript', 'operscript_60sec', "0.2");
Irssi::settings_add_str('operscript', 'operscript_alltime', "0.1");
# used to store all server specific settings
Irssi::settings_add_str('operscript', 'operscript_servers', "");
# easy kline settings
Irssi::settings_add_int('operscript', 'operscript_kline_time', 259200); # 259200 = 3 days
Irssi::settings_add_bool('operscript', 'operscript_kline_queue', 1);
Irssi::settings_add_str('operscript', 'operscript_kline_reason', 'botnet');

Irssi::command_bind("operscript", "operscript_sub");

Irssi::signal_add("event notice", "event_notice");
Irssi::signal_add('send text', 'event_send_text');

if (Irssi::settings_get_str('operscript_servers') eq "") {
	populate_servers();
} else {
	load_data();
}
print CLIENTCRAP '%B>>%n '.$IRSSI{name}.' '.$VERSION.' loaded successfully.';
