Rename $command_list to $filter_commands and $scriptHelp to $filter_help
[softsnow_xchat2_filter.git] / SoftSnow_filter.pl
blob1a42c3271b79c3168d3496a8957045c2b3af708e
1 #!/usr/bin/perl
3 use strict;
4 use warnings;
6 use File::Temp qw(tempfile);
7 use File::Copy qw(move);
10 my $scriptName = "SoftSnow XChat2 Filter";
11 my $scriptVersion = "2.1.0";
12 my $scriptDescr = "Filter out file server announcements and IRC SPAM";
14 my $B = "\cB"; # bold
15 my $U = "\cU"; # underline
16 my $C = "\cC"; # start of color sequence
18 ### config ###
19 my $filter_file = Xchat::get_info("xchatdir") . "/SoftSnow_filter.conf";
21 my $filter_turned_on = 0; # is filter is turned on
22 my $limit_to_server = ''; # if true limit to given server (host)
23 my $use_filter_allow = 0; # use overrides (ALLOW before DENY)
25 my $filtered_to_window = 0;
26 my $filter_window = "(filtered)";
27 ### end config ###
29 my $filter_commands = 'ON|OFF|STATUS|SERVER|SERVERON|ALL|HELP|DEBUG|PRINT|ALLOW|ADD|DELETE|SAVE|LOAD';
31 my $filter_help = <<"EOF";
32 ${B}/FILTER $filter_commands${B}
33 /FILTER ON|OFF - turns filtering on/off
34 /FILTER HELP - prints this help message
35 /FILTER STATUS - prints if filter is turned on, and with what limits
36 /FILTER DEBUG - shows some info; used in debuggin the filter
37 /FILTER PRINT - prints all the rules
38 /FILTER ALLOW - toggle use of ALLOW rules (before DENY).
39 /FILTER SERVER - limits filtering to current server (host)
40 /FILTER SERVERON - limits to server and turns filter on
41 /FILTER ALL - resumes filtering everywhere i.e. removes limits
42 /FILTER SAVE - saves the rules to the file $filter_file
43 /FILTER LOAD - loads the rules from the file, replacing existing rules
44 /FILTER ADD <rule> - add rule at the end of the DENY rules
45 /FILTER DELETE [<num>] - delete rule number <num>, or last rule
46 /FILTER SHOW [<num>] - show rule number <num>, or last rule
47 /FILTER VERSION - prints the name and version of this script
48 /FILTER without parameter is equivalent to /FILTER STATUS
49 EOF
51 Xchat::register($scriptName, $scriptVersion, $scriptDescr);
53 Xchat::hook_command("FILTER", \&filter_command_handler,
54 { help_text => $filter_help });
55 Xchat::hook_server("PRIVMSG", \&privmsg_handler);
57 Xchat::print("Loading ${B}$scriptName $scriptVersion${B}\n".
58 " For help: ${B}/FILTER HELP${B}\n");
60 # GUI, windows, etc.
61 if ($filtered_to_window) {
62 Xchat::command("QUERY $filter_window");
65 # information about (default) options used
66 if ($filter_turned_on) {
67 Xchat::print("Filter turned ${B}ON${B}\n");
68 } else {
69 Xchat::print("Filter turned ${B}OFF${B}\n");
71 if ($limit_to_server) {
72 Xchat::print("Filter limited to server $limit_to_server\n")
74 if ($use_filter_allow) {
75 Xchat::print("Filter uses ALLOW rules\n");
78 # ------------------------------------------------------------
80 my @filter_allow = (
81 q/^\@search\s/,
84 my @filter_deny = (
85 q/\@/,
86 q/^\s*\!/,
87 q/slot\(s\)/,
88 #q/~&~&~/,
90 #xdcc
91 q/^\#\d+/,
93 #fserves
94 q/(?i)fserve.*trigger/,
95 q/(?i)trigger.*\!/,
96 q/(?i)trigger.*\/ctcp/,
97 q/(?i)type\:\s*\!/,
98 q/(?i)file server online/,
100 #ftps
101 q/(?i)ftp.*l\/p/,
103 #CTCPs
104 q/SLOTS/,
105 q/MP3 /,
107 #messages for when a file is received/failed to receive
108 q/(?i)DEFINITELY had the right stuff to get/,
109 q/(?i)has just received/,
110 q/(?i)I have just received/,
112 #mp3 play messages
113 q/is listening to/,
114 q/\]\-MP3INFO\-\[/,
116 #spammy scripts
117 q/\]\-SpR\-\[/,
118 q/We are BORG/,
120 #general messages
121 q/brave soldier in the war/,
124 # return 1 (true) if text given as argument is to be filtered out
125 sub isFiltered {
126 my $text = shift;
127 my $regexp = '';
129 #strip colour, underline, bold codes, etc.
130 $text = Xchat::strip_code($text);
132 if ($use_filter_allow) {
133 foreach $regexp (@filter_allow) {
134 return 0 if ($text =~ /$regexp/);
138 foreach $regexp (@filter_deny) {
139 return 1 if ($text =~ /$regexp/);
142 return 0;
145 #called when someone says something in the channel
146 #1: address of speaker
147 #2: PRIVMSG constant
148 #3: channel
149 #4: text said (prefixed with :)
150 sub privmsg_handler {
151 # $_[0] - array reference containing the IRC message or command
152 # and arguments broken into words
153 # $_[1] - array reference containing the Nth word to the last word
154 my ($address, $msgtype, $channel) = @{$_[0]};
155 my ($nick, $user, $host) = ($address =~ /^:(.*?)!(.*?)@(.*)$/);
157 my $text = $_[1][3]; # Get server message
159 my $server = Xchat::get_info("host");
161 return Xchat::EAT_NONE unless $filter_turned_on;
162 if ($limit_to_server) {
163 return Xchat::EAT_NONE unless $server eq $limit_to_server;
166 $text =~ s/^://;
168 if (isFiltered($text)) {
169 if (defined $nick && $filtered_to_window) {
170 #Xchat::print($text, $filter_window)
172 my $ctx = Xchat::get_context();
173 Xchat::set_context($filter_window);
174 Xchat::emit_print('Channel Message', $nick, $text);
175 Xchat::set_context($ctx);
177 #return Xchat::EAT_XCHAT;
178 return Xchat::EAT_ALL;
180 return Xchat::EAT_NONE;
184 # ------------------------------------------------------------
186 sub save_filter {
187 my ($fh, $tmpfile) = tempfile($filter_file.'.XXXXXX', UNLINK=>1);
189 unless ($fh) {
190 Xchat::print("${B}FILTER:${B} ".
191 "Couldn't open temporary file $tmpfile to save filter: $!\n");
192 return;
195 Xchat::print("${B}FILTER SAVE >$filter_file${B}\n");
196 foreach my $regexp (@filter_deny) {
197 Xchat::print("/".$regexp."/ saved\n");
198 print $fh $regexp."\n";
201 unless (close $fh) {
202 Xchat::print("${B}FILTER:${B} Couldn't close file to save filter: $!\n");
203 return;
205 #move($tmpfile, $filter_file);
206 rename($tmpfile, $filter_file);
207 Xchat::print("${B}FILTER SAVED ----------${B}\n");
209 return 1;
212 sub load_filter {
213 my $fh;
215 Xchat::print("${B}FILTER:${B} ...loading filter patterns\n");
216 unless (open $fh, '<', $filter_file) {
217 Xchat::print("${B}FILTER:${B} Couldn't open file to load filter: $!\n");
218 return;
221 @filter_deny = <$fh>;
222 map (chomp, @filter_deny);
224 unless (close $fh) {
225 Xchat::print("${B}FILTER:${B} Couldn't close file to load filter: $!\n");
226 return;
229 Xchat::print("${B}FILTER DENY ----------${B}\n");
230 for (my $i = 0; $i <= $#filter_deny; $i++) {
231 Xchat::print(" [$i]: /".$filter_deny[$i]."/\n");
233 Xchat::print("${B}FILTER DENY ----------${B}\n");
236 sub add_rule ( $ ) {
237 my $rule = shift;
239 # always ading rules at the end
240 push @filter_deny, $rule;
243 sub delete_rule ( $ ) {
244 my $num = shift || $#filter_deny;
246 splice @filter_deny, $num, 1;
249 # ============================================================
250 # ------------------------------------------------------------
251 # ............................................................
253 sub cmd_version {
254 Xchat::print("${B}$scriptName $scriptVersion${B}\n");
255 Xchat::print(" * URL: http://github.com/jnareb/softsnow-xchat2-filter\n");
256 Xchat::print(" * URL: http://gitorious.org/projects/softsnow-xchat2-filter\n");
257 Xchat::print(" * URL: http://repo.or.cz/w/softsnow_xchat2_filter.git\n");
260 sub cmd_status {
261 my $server = shift;
263 if ($filter_turned_on) {
264 Xchat::print("Filter is turned ${B}ON${B}\n");
265 } else {
266 Xchat::print("Filter is turned ${B}OFF${B}\n");
268 if ($limit_to_server) {
269 if ($server eq $limit_to_server) {
270 Xchat::print("Filter is limited to ${B}current${B} ".
271 "server $limit_to_server\n");
272 } else {
273 Xchat::print("Filter is limited to server ".
274 "$limit_to_server != $server\n");
277 if ($use_filter_allow) {
278 Xchat::print("Filter is using ALLOW rules (before DENY)\n");
282 sub cmd_debug {
283 Xchat::print("${B}FILTER DEBUG ----------${B}\n");
284 Xchat::print("Channel: ".Xchat::get_info("channel")."\n");
285 Xchat::print("Host: ".Xchat::get_info("host")."\n");
286 Xchat::print("Server: ".Xchat::get_info("server")."\n");
287 Xchat::print("Server Id: ".Xchat::get_info("id")."\n");
288 Xchat::print("Network: ".Xchat::get_info("network")."\n");
289 Xchat::print("\n");
290 Xchat::printf("%3u %s rules\n", scalar(@filter_allow), "allow");
291 Xchat::printf("%3u %s rules\n", scalar(@filter_deny), "deny");
292 Xchat::print("${B}FILTER DEBUG ----------${B}\n");
295 sub cmd_server_limit {
296 my $server = shift;
298 if ($server) {
299 # adding limiting to given (single) server
300 if ($limit_to_server) {
301 Xchat::print("${B}FILTER:${B} Changing server from $limit_to_server to $server\n");
302 } else {
303 Xchat::print("${B}FILTER:${B} Limiting filtering to server $server\n");
305 $limit_to_server = $server;
307 } else {
308 # removing limiting to server
309 if ($limit_to_server) {
310 Xchat::print("Filter: Removing limit to server $limit_to_server\n");
312 $limit_to_server = '';
317 sub cmd_print_rules {
318 Xchat::print("${B}FILTER PRINT ----------${B}\n");
319 Xchat::print("${B}ALLOW${B}".($use_filter_allow ? ' (on)' : ' (off)')."\n");
321 for (my $i = 0; $i <= $#filter_allow; $i++) {
322 Xchat::print("[$i]: /".$filter_allow[$i]."/\n");
324 Xchat::print("${B}DENY${B}\n");
325 for (my $i = 0; $i <= $#filter_deny; $i++) {
326 Xchat::print("[$i]: /".$filter_deny[$i]."/\n");
328 Xchat::print("${B}FILTER PRINT ----------${B}\n");
331 sub cmd_add_rule {
332 my $rule = shift;
334 if ($rule) {
335 add_rule($rule);
336 Xchat::print("${B}FILTER RULE [$#filter_deny]:${B} /$rule/\n");
337 } else {
338 Xchat::print("Syntax: ${B}/FILTER ADD ${U}rule${U}${B} to add\n")
342 sub cmd_delete_rule {
343 my $num = shift;
345 # strip whitespace
346 $num =~ s/^\s*(.*?)\s*$/$1/g if $num;
347 SWITCH: {
348 unless ($num) {
349 Xchat::print("${B}FILTER:${B} deleting /".$filter_deny[-1]."/\n");
350 $#filter_deny--;
351 Xchat::print("${B}FILTER:${B} deleted successfully last rule\n");
352 last SWITCH;
354 if ($num !~ /^\d+$/) {
355 Xchat::print("${B}FILTER:${B} $num is not a number\n");
356 last SWITCH;
358 if ($num < 0 || $num > $#filter_deny) {
359 Xchat::print("${B}FILTER:${B} $num outside range [0,$#filter_deny]\n");
360 last SWITCH;
362 # default
364 Xchat::print("${B}FILTER:${B} deleting /".$filter_deny[$num]."/\n");
365 delete_rule($num);
366 Xchat::print("${B}FILTER:${B} deleted successfully rule $num\n");
371 sub cmd_show_rule {
372 my $num = shift;
374 $num =~ s/^\s*(.*?)\s*$/$1/g if $num;
376 if (defined $num && $num !~ /^\d+$/) {
377 Xchat::print("${B}FILTER:${B} $num is not a number\n");
378 } elsif (defined $num && !defined $filter_deny[$num]) {
379 Xchat::print("${B}FILTER:${B} rule $num does not exist\n");
380 } else {
381 Xchat::print("${B}FILTER:${B} ".(defined $num ? "[$num]" : "last").
382 " rule /".$filter_deny[defined $num ? $num : -1]."/\n");
386 # ============================================================
387 # ============================================================
388 # ============================================================
390 sub filter_command_handler {
391 my $cmd = $_[0][1]; # 1st parameter (after FILTER)
392 my $arg = $_[1][2]; # 2nd word to the last word
393 my $server = Xchat::get_info("host");
396 if (!$cmd || $cmd =~ /^STATUS$/i) {
397 cmd_status($server);
399 } elsif ($cmd =~ /^ON$/i) {
400 $filter_turned_on = 1;
401 Xchat::print("Filter turned ${B}ON${B}\n");
403 } elsif ($cmd =~ /^OFF$/i) {
404 $filter_turned_on = 0;
405 Xchat::print("Filter turned ${B}OFF${B}\n");
407 } elsif ($cmd =~ /^SERVER$/i) {
408 cmd_server_limit($server);
410 } elsif ($cmd =~ /^SERVERON$/i) {
411 cmd_server_limit($server);
413 $filter_turned_on = 1;
414 Xchat::print("Filter turned ${B}ON${B}\n");
416 } elsif ($cmd =~ /^ALL$/i) {
417 cmd_server_limit(undef);
419 } elsif ($cmd =~ /^HELP$/i) {
420 Xchat::print($filter_help);
422 } elsif ($cmd =~ /^VERSION$/i) {
423 cmd_version();
425 } elsif ($cmd =~ /^DEBUG$/i || $cmd =~ /^INFO$/i) {
426 cmd_debug();
428 } elsif ($cmd =~ /^(?:PRINT|LIST)$/i) {
429 cmd_print_rules();
431 } elsif ($cmd =~ /^ALLOW$/i) {
432 $use_filter_allow = !$use_filter_allow;
433 Xchat::print("${B}FILTER:${B} ALLOW rules ".
434 ($use_filter_allow ? "enabled" : "disabled")."\n");
436 } elsif ($cmd =~ /^ADD$/i) {
437 cmd_add_rule($arg);
439 } elsif ($cmd =~ /^DEL(?:ETE)$/i) {
440 cmd_delete_rule($arg);
442 } elsif ($cmd =~ /^SHOW$/i) {
443 cmd_show_rule($arg);
445 } elsif ($cmd =~ /^SAVE$/i) {
446 save_filter();
447 Xchat::print("${B}FILTER:${B} saved DENY rules to $filter_file\n");
449 } elsif ($cmd =~ /^(RE)?LOAD$/i) {
450 load_filter();
451 Xchat::print("${B}FILTER:${B} loaded DENY rules from $filter_file\n");
453 } else {
454 Xchat::print("Unknown command ${B}/FILTER $_[1][1]${B}\n") if $cmd;
456 return 1;
459 Xchat::print("${B}$scriptName $scriptVersion${B} loaded\n");