summaryrefslogtreecommitdiff
path: root/scripts/mlock.pl
blob: 35ad785670176ad16876064c586d1182b6e51884 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# /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");