# /MLOCK <channel> <mode>
#
# Locks the channel mode to <mode>, if someone else tries to change the mode
# Irssi will automatically change it back. +k and +l are a bit special since
# they require the parameter. If you omit the parameter, like setting the
# mode to "+ntlk", Irssi will allow all +k and +l (or -lk) mode changes.

use Irssi;
use Irssi::Irc;
use strict;

my %keep_channels;

sub cmd_mlock {
	my ($data, $server) = @_;
	my ($channel, $mode) = split(/ /, $data, 2);

	$keep_channels{$channel} = $mode;
	mlock_check_mode($server, $channel);
}

sub mlock_check_mode {
        my ($server, $channame) = @_;

	my $channel = $server->channel_find($channame);
	return if (!$channel || !$channel->{chanop});

        my $keep_mode = $keep_channels{$channame};
	return if (!$keep_mode);

	# old channel mode
	my ($oldmode, $oldkey, $oldlimit);
	$oldmode = $channel->{mode};
        $oldmode =~ s/^([^ ]*).*/\1/;
	$oldkey = $channel->{key};
	$oldlimit = $channel->{limit};

	# get the new channel key/limit
	my (@newmodes, $newkey, $limit);
	@newmodes = split(/ /, $keep_mode); $keep_mode = $newmodes[0];
	if ($keep_mode =~ /k/) {
		if ($keep_mode =~ /k.*l/) {
                        $newkey = $newmodes[1];
                        $limit = $newmodes[2];
		} elsif ($keep_mode =~ /l.*k/) {
			$limit = $newmodes[1];
                        $newkey = $newmodes[2];
		} else {
                        $newkey = $newmodes[1];
		}
	} elsif ($keep_mode =~ /l/) {
		$limit = $newmodes[1];
	}

	# check the differences
	my %allmodes;
	$keep_mode =~ s/^\+//;
	for (my $n = 0; $n < length($keep_mode); $n++) {
		my $modechar = substr($keep_mode, $n, 1);
		$allmodes{$modechar} = '+';
	}

	for (my $n = 0; $n < length($oldmode); $n++) {
		my $modechar = substr($oldmode, $n, 1);

		if ($allmodes{$modechar} eq '+') {
			next if (($modechar eq "k" && $newkey ne $oldkey) ||
				 ($modechar eq "l" && $limit != $oldlimit));
			delete $allmodes{$modechar};
		} else {
			$allmodes{$modechar} = '-';
		}
	}

	# create the mode change string
	my ($modecmd, $extracmd);
	foreach my $mode (keys %allmodes) {
		Irssi::print("key = '$mode':".$allmodes{$mode});
		if ($mode eq "k") {
			if ($allmodes{$mode} eq '+') {
				next if ($newkey eq "");
				if ($oldkey ne "") {
					# we need to get rid of old key too
					$modecmd .= "-k";
					$extracmd .= " $oldkey";
				}
				$extracmd .= " $newkey";
			} else {
				$extracmd .= " $oldkey";
			}
		}
		if ($mode eq "l" && $allmodes{$mode} eq '+') {
			next if ($limit <= 0);
                        $extracmd .= " $limit";
		}
		$modecmd .= $allmodes{$mode}.$mode;
	}

	if ($modecmd ne "") {
		$channel->{server}->command("/mode $channame $modecmd$extracmd");
	}
}

sub mlock_mode_changed {
	my ($server, $data) = @_;
	my ($channel, $mode) = split(/ /, $data, 2);

	mlock_check_mode($server, $channel);
}

sub mlock_synced {
	my $channel = $_[0];

	mlock_check_mode($channel->{server}, $channel->{name});
}

Irssi::command_bind('mlock', 'cmd_mlock');
Irssi::signal_add_last("event mode", "mlock_mode_changed");
Irssi::signal_add("channel synced", "mlock_synced");