# nicks and hosts must go in ~/.irssi/sos.oplist in the current format
# nickname host1 host2
# username .*\!ident\@.*\.isp\.com

use strict;
use Irssi;

use vars qw($VERSION %IRSSI);
$VERSION = "0.5";
%IRSSI = (
	authors		=> "David O\'Rourke",
	contact		=> "EFNet\://phyber\@\#irssi",
	name		=> "sos",
	description	=> "Simple Op Script",
	licence		=> "GPL General Public Licence",
	changed		=> "10.7.2003 20:02"
);

# might make this more configurable later. ie. a /set setting
my $passwd = "somepass";
my $chan = "\#somechan";
my %ops;

# host to regexp, borrowed from 'friends_shasta.pl'
my %htr = ();
# fill the hash
foreach my $i (0..255) {
	my $ch = chr($i);
	$htr{$ch} = "\Q$ch\E";
}
# wildcards to regexp
$htr{'?'} = '.';
$htr{'*'} = '.*';

sub uhost_to_regexp($) {
	my ($mask) = @_;
	$mask = lcase_hostpart($mask);
	$mask =~ s/(.)/$htr{$1}/g;
	return $mask;
}

sub lcase_hostpart($) {
	my ($host) = @_;
	$host =~ s/(.+)\@(.+)/sprintf("%s@%s", $1, lc($2));/eg;
	return $host;
}

# read the sos.oplist file.
# entryname .*\!ident\@.*some\.host\.com
sub cmd_load_ops {
	my ($file) = Irssi::get_irssi_dir."/sos.oplist";
	my ($count) = 0;
	my ($nick, @hostmasks);
	local(*FILE);

	%ops = ( );
	open FILE, "< $file";
	while (<FILE>) {
		($nick, @hostmasks) = split;
		$ops{$nick} = "@hostmasks";
	}
	close FILE;
	$count = keys %ops;
	
	Irssi::print "Loaded $count channel ops from $file";
}

sub check_host {
	my ($hostmask) = @_;
	my @checkhost;
	my $key;
	my $valid = 0;
	foreach $key (sort keys %ops) {
		@checkhost = $ops{$key};
		for my $validhost (split(/ /, "@checkhost")) {
			#Irssi::print "Comparing $hostmask => $validhost";
			if ($hostmask =~ /$validhost/) {
				Irssi::print "Authenticated: $hostmask";
				$valid = 1;
			}
		}
		# if we found a matching host, stop the loop
		last if ($valid == 1);
	}
	return $valid;
}

sub valid_op {
	my ($servtag, $nick) = @_;
	my $server = Irssi::server_find_tag($servtag);
	
	# let's not try to send the MODE if we arn't opped.
	my $channel = $server->channel_find($chan);
	return if (!$channel->{chanop});
	
	Irssi::print "Giving ops to $nick on $chan";
	$server->send_raw("MODE $chan +o $nick") if ($server);
}

sub event_check_op {
	my ($server, @data) = @_;
	# split the host and nick from the msg
	my $hostmask = pop(@data);
	my $nick = pop(@data);
	my $msg = "@data";

	# stop right now if $msg isn't the passwd
	return if ("$msg" ne "$passwd");
	
	# if it was the passwd, let's check out the hostmask
	$hostmask = "$nick!$hostmask";
	$hostmask = lcase_hostpart($hostmask);
	
	# check if the host is valid
	my $valid = check_host($hostmask);
	
	# stop if the host wasn't valid
	#Irssi::print "UnAuthorised: $hostmask" if ($valid == 0);
	return if ($valid == 0);
	
	# stop the signal if everything checks out.
	# we don't need a new query everytime someone msgs us the passwd
	Irssi::signal_stop();

	# ok, so if we're here, it MUST be a valid op, right?
	my $servtag = $server->{tag};
	valid_op($servtag, $nick);
}

Irssi::signal_add_first('message private', 'event_check_op');
Irssi::command_bind('oplist_reload', 'cmd_load_ops');
# load op list on script start
cmd_load_ops;