html/operit.pl
1 ### operit.pl (c) 2002, 2003 Petr Baudis <pasky@ucw.cz>
2 #
3 ## Perform certain action (invite/op/...) on request authenticated by the
4 ## IRC operator status.
5 #
6 ## See http://pasky.ji.cz/~pasky/dev/irssi/ for the latest version.
7 #
8 ## Thanks to:
9 ## mofo <mick@mofo.nl> (patches)
10 ## Garion <garion@dnsspam.nl> (ideas)
11 ## Borys <borys@irc.pl> (ideas)
12 ## devastor <devastor@idiosynkrasia.net>(bug reports)
13 ## babar <babar@magicnet.org> (delay patch)
14 #
15 ## $Id: operit.pl,v 1.14 2003/09/06 12:27:11 pasky Exp pasky $
16 #
17 # $Log: operit.pl,v $
18 # Revision 1.14 2003/09/06 12:27:11 pasky
19 # Okay, so while I'm at it updated other instance of my email addy, copyright, bunch of grammar fixes and documented the operit_public_delay variable.
20 #
21 # Revision 1.13 2003/09/06 12:25:09 pasky
22 # Updated my email addy.
23 #
24 # Revision 1.12 2003/09/06 12:23:50 pasky
25 # Added support for randomly delayed operit - if operit is public, the delay is zero to five seconds by default - this helps greatly if there is a lot of operit-enabled clients on a channel. Patch by Babar <babar@magicnet.org> and me.
26 #
27 # Revision 1.11 2003/03/20 08:58:18 pasky
28 # Match whole channel, not random part, when checking for deny_channels and deny_hosts. So you can deny operits at #iraq but still allow them at #iraqlive ;-). Thanks to viha for cooperation during testing.
29 #
30 # Revision 1.10 2002/11/29 16:51:46 pasky
31 # Don't play with channels we aren't on. Fixes occassional 'can't call method command on undefined value'; thanks to devastor for a report.
32 #
33 # Revision 1.9 2002/10/19 13:12:34 pasky
34 # Introduced operit_allow_public (by default on), which toggles accepting of public (on-channel) operit requests. Idea by Borys.
35 #
36 # Revision 1.8 2002/10/13 12:33:13 pasky
37 # We don't care about /^operit [^!#&]/ anymore. Thanks fly to Garion for suggestion.
38 #
39 # Revision 1.7 2002/10/07 14:16:58 pasky
40 # Added operit_show_requests bool setting (by default 1, that is same behaviour as now).
41 #
42 # Revision 1.6 2002/09/01 12:27:08 pasky
43 # Erm, compilation fixes.
44 #
45 # Revision 1.5 2002/09/01 12:24:24 pasky
46 # Allow specification of more channels separated by a comma in requests. Changed default value of operit_hosts_deny to something harmless. Patch by mofo <mick@mofo.nl>.
47 #
48 # Revision 1.4 2002/03/13 13:17:36 pasky
49 # remove one debug message accidentally left there
50 #
51 # Revision 1.3 2002/03/12 18:02:37 pasky
52 # invait actually works now
53 #
54 # Revision 1.2 2002/02/05 17:47:13 pasky
55 # fixed many things :^). now it basically works how it should...
56 #
57 # Revision 1.1 2002/02/05 16:47:09 pasky
58 # Initial revision
59 #
60 #
61 ###
62
63 ### Inspired by Operit-2.01b+enge script for ircII+ clients by
64 ## - Viha (Viha@Theblah.Org)
65 # - Karzan (Kari@Theblah.Org)
66 #
67 ## Credits also go to:
68 # - LuckyS (lucky@binet.lv) [bug reports]
69 # - Fusion (fusion@nuts.edu) [bug reports]
70 # - RA^v^EN (raven@sky.siol.org) [bug reports]
71 # - tumble (tumble@openface.ca) [beta testing]
72 # - koopal (andre@nl.uu.net) [script ideas]
73 # - pt (primetime@wnol.net) [script ideas]
74 # - delta (delta@rus.uni-stuttgart.de) [script ideas]
75 # - pht (svobodam@irc.vsp.cz) [bug reports]
76 # - enge (engerim@magicnet.org) [modifications]
77 #
78 ### The most recent version can always be found at
79 # http://www.vip.fi/~viha/irc/
80 ###
81
82 use strict;
83
84 use vars qw ($VERSION %IRSSI $rcsid);
85
86 $rcsid = '$Id: operit.pl,v 1.14 2003/09/06 12:27:11 pasky Exp pasky $';
87 ($VERSION) = '$Revision: 1.14 $' =~ / (\d+\.\d+) /;
88 %IRSSI = (
89 name => 'operit',
90 authors => 'Petr Baudis',
91 contact => 'pasky@ucw.cz',
92 url => 'http://pasky.ji.cz/~pasky/dev/irssi/',
93 license => 'BSD',
94 description => 'Perform certain action (invite/op/...) on request authenticated by the IRC operator status.'
95 );
96
97
98 use Irssi 20021117; # timeout_add_once
99 use Irssi::Irc;
100
101
102 my $queue = 0; # already queued an operit? (when?)
103 my $disp = 0; # already displayed kind notice about already queued operit?
104 my $cmd = ""; # command issued
105 my $target = ""; # who issued the command
106 my $chan = ""; # object of the command
107
108 my $coperit = 0;
109 my $cinvait = 0;
110 my $cdamode = 0;
111 my $mpublic = 0;
112
113
114 sub event_privmsg {
115 my ($server, $data, $nick, $address) = @_;
116 my ($msgtarget, $text) = split(/ :/, $data, 2);
117
118 return if (Irssi::settings_get_bool("operit_deny"));
119
120 if ($text =~ s/^(invait|operit|damode)( .*)?$/$2/i) {
121 if (uc($msgtarget) eq uc($server->{nick})) {
122 $mpublic = 0;
123 } else {
124 return unless (Irssi::settings_get_bool("operit_allow_public"));
125 $mpublic = 1;
126 }
127
128 if (time - $queue < 10) {
129 Irssi::print "Operit currently deactivated or queued. Request ignored."
130 if (time - $disp > 20);
131 $disp = time;
132 return;
133 }
134
135 $cmd = $1; $target = $nick; $queue = 0; $disp = 0;
136
137 # if ($msgtarget eq $N or $cmd eq 'invait') {
138 if (1) {
139 ($_, $chan) = split /\s+/, $text; # oh.. oh well :)
140 my $a = 0;
141
142 $chan = $msgtarget if (not $chan and $msgtarget ne $server->{nick});
143 return unless ($chan =~ /^[#!&]/);
144
145 foreach (split /\s+/, Irssi::settings_get_str("operit_chans")) {
146 s/\./\\./;
147 s/\*/.*/g;
148 if ($chan =~ /^$_$/i) {
149 $a++;
150 }
151 }
152
153 unless ($a) {
154 Irssi::print "Unauthorized $cmd $chan by $target (not in operit_chans)" if (Irssi::settings_get_bool("operit_show_requests"));
155 return;
156 }
157
158 foreach (split /\s+/, Irssi::settings_get_str("operit_chans_deny")) {
159 s/\./\\./;
160 s/\*/.*/g;
161 if ($chan =~ /^$_$/i) {
162 Irssi::print "Unauthorized $cmd $chan by $target (in operit_chans_deny)" if (Irssi::settings_get_bool("operit_show_requests"));
163 return;
164 }
165 }
166
167 foreach (split /^\s+$/, Irssi::settings_get_str("operit_hosts_deny")) {
168 s/\./\\./;
169 s/\*/.*/g;
170 if ($address =~ /$_/i) {
171 Irssi::print "Unauthorized $cmd $chan by $target <$address> (in operit_hosts_deny)" if (Irssi::settings_get_bool("operit_show_requests"));
172 return;
173 }
174 }
175
176 $queue = time;
177
178 $server->redirect_event("userhost", 1, $target, 0, 'redir userhost_operit_error',
179 {"event 302" => "redir userhost_operit"});
180
181 $server->command("USERHOST $target");
182 }
183 }
184 }
185
186 sub event_userhost_error {
187 Irssi::print "Operit userhost on $target failed, aborting the action...";
188
189 $queue = $disp = 0;
190 }
191
192
193 sub event_userhost_operit {
194 my ($server, $data) = @_;
195 my ($mynick, $reply) = split(/ +/, $data);
196 my ($nick, $user, $host) = $reply =~ /^:(.*)=.(.*)@(.*)/;
197
198 unless ($nick =~ s/\*$//) {
199 Irssi::print "$target requested UNAUTHORIZED $cmd on channel $chan" if (Irssi::settings_get_bool("operit_show_requests"));
200 return;
201 }
202
203 Irssi::print "$target requested $cmd on channel $chan" if (Irssi::settings_get_bool("operit_show_requests"));
204
205 foreach my $chansplit (split(/\,/, $chan)) {
206 my $channel = $server->channel_find($chansplit);
207
208 next unless ($channel);
209
210 if (lc($cmd) eq "operit") {
211 if ($mpublic) {
212 my $precision = 10; # Delay precision (10 = 1/10s)
213 my $rdelay = int(rand(Irssi::settings_get_str("operit_public_delay") * $precision)) * 1000 / $precision;
214
215 Irssi::print "Waiting " . ($rdelay / 1000) . " seconds before executing PUBLIC $cmd for $target on $chan";
216 Irssi::timeout_add_once($rdelay + 11, sub { # XXX why + 10 ? --pasky
217 my ($target, $channel) = @{$_[0]};
218 my ($tgrec) = $channel->nick_find($target);
219 $channel->command("op $target") unless ($tgrec and $tgrec->{'op'});
220 }, [ $target, $channel ]);
221 } else {
222 $channel->command("op $target");
223 }
224 $coperit++;
225
226 } elsif (lc($cmd) eq "invait") {
227 $server->command("invite $target $chansplit");
228 $cinvait++;
229
230 } elsif (lc($cmd) eq "damode") {
231 $server->command("notice $target mode for $chansplit is +$channel->{mode}");
232 $cdamode++;
233 }
234 }
235
236 $queue = $disp = 0;
237 }
238
239
240 sub event_ctcp {
241 my ($server, $data, $nick, $address, $target) = @_;
242
243 return if (Irssi::settings_get_bool("operit_deny"));
244
245 if ($data =~ /^operit/i) {
246 Irssi::print "$nick requested operit thru CTCP... no way!" if (Irssi::settings_get_bool("operit_show_requests"));
247 $server->command("NOTICE $nick ssshht!");
248 Irssi::signal_stop();
249 }
250 }
251
252
253 sub cmd_operit {
254 my ($data, $server, $channel) = @_;
255
256 if ($data =~ /^(usage|help)/i) {
257
258 foreach (split /\n/, <<USAGEE
259 Operit:
260
261 Local commands
262
263 operit usage - This help.
264 operit help - This help.
265 operit status - Display statistical information.
266
267 Remote commands
268
269 operit #chan - Op the person in question on #chan. (req. *)
270 invait #chan - Invait the person in question to #chan. (req. *)
271 damode #chan - Give the person in question the modes of #chan. (req. *)
272
273 Variables
274
275 operit_chans - The channelmask operit/invait is permitted on. (* is *)
276 operit_chans_deny - The channel(s) operit/invait is not permitted on. (* is *)
277 operit_hosts_deny - The user\@host(s) operit/invait is not permitted from. (* is *)
278 operit_deny - Toogle this ON if you don't actually want invait/operit to function.
279 operit_show_requests
280 - Toogle this OFF if you don't want to see messages about operit requests.
281 operit_allow_public
282 - Toogle this OFF if you don't want requests written on channels to be proceeded.
283 operit_public_delay
284 - Set this to 0 if you don't want random delay between request and action.
285 USAGEE
286 ) {
287 Irssi::print $_;
288 }
289
290 } elsif ($data =~ /^status/i) {
291 my $ctotal = $coperit + $cinvait + $cdamode;
292
293 Irssi::print "Operit $VERSION Status:";
294 Irssi::print "The last person to request $cmd was $target [$chan].";
295 Irssi::print "This session has served $coperit op-requests, $cinvait invite-requests and $cdamode mode-requests.";
296 Irssi::print "Making a total of $ctotal succesful requests.";
297
298 } else {
299 Irssi::print "Excuse moi, sir? I guess that you want /operit usage ..?";
300 }
301 }
302
303
304 Irssi::command_bind("operit", "cmd_operit");
305 Irssi::signal_add("redir userhost_operit", "event_userhost_operit");
306 Irssi::signal_add("redir userhost_operit_error", "event_userhost_error");
307 Irssi::signal_add("default ctcp msg", "event_ctcp");
308 Irssi::signal_add("event privmsg", "event_privmsg");
309
310
311 Irssi::settings_add_str("operit", "operit_chans", "#* !*");
312 Irssi::settings_add_str("operit", "operit_chans_deny", "#ircophackers");
313 Irssi::settings_add_str("operit", "operit_hosts_deny", "*!*@*.lamehost1 *lamehost2");
314 Irssi::settings_add_bool("operit", "operit_deny", 0);
315 Irssi::settings_add_bool("operit", "operit_show_requests", 1);
316 Irssi::settings_add_bool("operit", "operit_allow_public", 1);
317 Irssi::settings_add_str("operit", "operit_public_delay", 5);
318
319
320 Irssi::print("Operit $VERSION loaded... see command 'operit usage'");