Return undef on error in save_filter and load_filter
[softsnow_xchat2_filter.git] / SoftSnow_filter.pl
blob73debb73953c704ced8b629ec6a5a74b36b4f3d8
1 #!/usr/bin/perl
3 use strict;
4 use warnings;
7 my $scriptName = "SoftSnow XChat2 Filter";
8 my $scriptVersion = "2.0.4";
9 my $scriptDescr = "Filter out file server announcements and IRC SPAM";
11 my $B = "\cB"; # bold
12 my $U = "\cU"; # underline
13 my $C = "\cC"; # start of color sequence
15 ### config ###
16 my $filter_file = Xchat::get_info("xchatdir") . "/SoftSnow_filter.conf";
18 my $filter_turned_on = 0; # was default turned ON
19 my $limit_to_server = ''; # don't limit to server (host)
20 my $use_filter_allow = 0; # use overrides
21 ### end config ###
23 my $command_list = 'ON|OFF|STATUS|SERVER|SERVERON|ALL|HELP|DEBUG|PRINT|ALLOW|ADD|DELETE|SAVE|LOAD';
25 my $scriptHelp = <<"EOF";
26 ${B}/FILTER $command_list${B}
27 /FILTER ON|OFF - turns filtering on/off
28 /FILTER HELP - prints this help message
29 /FILTER STATUS - prints if filter is turned on, and with what limits
30 /FILTER DEBUG - shows some info; used in debuggin the filter
31 /FILTER PRINT - prints all the rules
32 /FILTER ALLOW - toggle use of ALLOW rules (before DENY).
33 /FILTER SERVER - limits filtering to current server (host)
34 /FILTER SERVERON - limits to server and turns filter on
35 /FILTER ALL - resumes filtering everywhere i.e. removes limits
36 /FILTER SAVE - saves the rules to the file $filter_file
37 /FILTER LOAD - loads the rules from the file, replacing existing rules
38 /FILTER ADD <rule> - add rule at the end of the DENY rules
39 /FILTER DELETE [<num>] - delete rule number <num>, or last rule
40 /FILTER SHOW [<num>] - show rule number <num>, or last rule
41 /FILTER VERSION - prints the name and version of this script
42 /FILTER without parameter is equivalent to /FILTER STATUS
43 EOF
45 Xchat::register($scriptName, $scriptVersion, $scriptDescr);
47 Xchat::hook_command("FILTER", \&filter_command_handler,
48 { help_text => $scriptHelp });
49 Xchat::hook_server("PRIVMSG", \&privmsg_handler);
51 Xchat::print("Loading ${B}$scriptName $scriptVersion${B}\n".
52 " For help: ${B}/FILTER HELP${B}\n");
55 # information about (default) options used
56 if ($filter_turned_on) {
57 Xchat::print("Filter turned ${B}ON${B}\n");
58 } else {
59 Xchat::print("Filter turned ${B}OFF${B}\n");
61 if ($limit_to_server) {
62 Xchat::print("Filter limited to server $limit_to_server\n")
64 if ($use_filter_allow) {
65 Xchat::print("Filter uses ALLOW rules\n");
68 # ------------------------------------------------------------
70 my @filter_allow = (
71 q/^\@search\s/,
74 my @filter_deny = (
75 q/\@/,
76 q/^\s*\!/,
77 q/slot\(s\)/,
78 #q/~&~&~/,
80 #xdcc
81 q/^\#\d+/,
83 #fserves
84 q/(?i)fserve.*trigger/,
85 q/(?i)trigger.*\!/,
86 q/(?i)trigger.*\/ctcp/,
87 q/(?i)type\:\s*\!/,
88 q/(?i)file server online/,
90 #ftps
91 q/(?i)ftp.*l\/p/,
93 #CTCPs
94 q/SLOTS/,
95 q/MP3 /,
97 #messages for when a file is received/failed to receive
98 q/(?i)DEFINITELY had the right stuff to get/,
99 q/(?i)has just received/,
100 q/(?i)I have just received/,
102 #mp3 play messages
103 q/is listening to/,
104 q/\]\-MP3INFO\-\[/,
106 #spammy scripts
107 q/\]\-SpR\-\[/,
108 q/We are BORG/,
110 #general messages
111 q/brave soldier in the war/,
114 # return 1 (true) if text given as argument is to be filtered out
115 sub isFiltered {
116 my $text = shift;
117 my $regexp = '';
119 #strip colour, underline, bold codes, etc.
120 $text = Xchat::strip_code($text);
122 if ($use_filter_allow) {
123 foreach $regexp (@filter_allow) {
124 return 0 if ($text =~ /$regexp/);
128 foreach $regexp (@filter_deny) {
129 return 1 if ($text =~ /$regexp/);
132 return 0;
135 #called when someone says something in the channel
136 #1: address of speaker
137 #2: PRIVMSG constant
138 #3: channel
139 #4: text said (prefixed with :)
140 sub privmsg_handler {
141 # $_[0] - array reference containing the IRC message or command
142 # and arguments broken into words
143 # $_[1] - array reference containing the Nth word to the last word
144 #my ($address, $constant, $chan) = @{$_[0]};
145 my $text = $_[1][3]; # Get server message
147 my $server = Xchat::get_info("host");
150 return Xchat::EAT_NONE unless $filter_turned_on;
151 if ($limit_to_server) {
152 return Xchat::EAT_NONE unless $server eq $limit_to_server;
155 $text =~ s/^://;
157 return isFiltered($text) ? Xchat::EAT_ALL : Xchat::EAT_NONE;
160 # ------------------------------------------------------------
162 sub save_filter {
163 open F, ">$filter_file"
164 or do {
165 Xchat::print("${B}FILTER:${B} Couldn't open file to save filter: $!\n");
166 return;
169 Xchat::print("${B}FILTER SAVE >$filter_file${B}\n");
170 foreach my $regexp (@filter_deny) {
171 Xchat::print("/".$regexp."/ saved\n");
172 print F $regexp."\n";
174 Xchat::print("${B}FILTER SAVED ----------${B}\n");
175 close F
176 or do {
177 Xchat::print("${B}FILTER:${B} Couldn't close file to save filter: $!\n");
178 return;
180 return 1;
183 sub load_filter {
184 Xchat::print("${B}FILTER:${B} ...loading filter patterns\n");
185 open F, "<$filter_file"
186 or do {
187 Xchat::print("${B}FILTER:${B} Couldn't open file to load filter: $!\n");
188 return;
190 @filter_deny = <F>;
191 map (chomp, @filter_deny);
192 close F
193 or do {
194 Xchat::print("${B}FILTER:${B} Couldn't close file to load filter: $!\n");
195 return;
198 Xchat::print("${B}FILTER DENY ----------${B}\n");
199 for (my $i = 0; $i <= $#filter_deny; $i++) {
200 Xchat::print(" [$i]: /".$filter_deny[$i]."/\n");
202 Xchat::print("${B}FILTER DENY ----------${B}\n");
205 sub add_rule ( $ ) {
206 my $rule = shift;
208 # always ading rules at the end
209 push @filter_deny, $rule;
212 sub delete_rule ( $ ) {
213 my $num = shift || $#filter_deny;
215 splice @filter_deny, $num, 1;
218 # ============================================================
219 # ------------------------------------------------------------
220 # ............................................................
222 sub cmd_version {
223 Xchat::print("${B}$scriptName $scriptVersion${B}\n");
224 Xchat::print(" * URL: http://github.com/jnareb/softsnow-xchat2-filter\n");
225 Xchat::print(" * URL: http://gitorious.org/projects/softsnow-xchat2-filter\n");
226 Xchat::print(" * URL: http://repo.or.cz/w/softsnow_xchat2_filter.git\n");
229 sub cmd_status {
230 my $server = shift;
232 if ($filter_turned_on) {
233 Xchat::print("Filter is turned ${B}ON${B}\n");
234 } else {
235 Xchat::print("Filter is turned ${B}OFF${B}\n");
237 if ($limit_to_server) {
238 if ($server eq $limit_to_server) {
239 Xchat::print("Filter is limited to ${B}current${B} ".
240 "server $limit_to_server\n");
241 } else {
242 Xchat::print("Filter is limited to server ".
243 "$limit_to_server != $server\n");
246 if ($use_filter_allow) {
247 Xchat::print("Filter is using ALLOW rules (before DENY)\n");
251 sub cmd_debug {
252 Xchat::print("${B}FILTER DEBUG ----------${B}\n");
253 Xchat::print("Channel: ".Xchat::get_info("channel")."\n");
254 Xchat::print("Host: ".Xchat::get_info("host")."\n");
255 Xchat::print("Server: ".Xchat::get_info("server")."\n");
256 Xchat::print("Server Id: ".Xchat::get_info("id")."\n");
257 Xchat::print("Network: ".Xchat::get_info("network")."\n");
258 Xchat::print("\n");
259 Xchat::printf("%3u %s rules\n", scalar(@filter_allow), "allow");
260 Xchat::printf("%3u %s rules\n", scalar(@filter_deny), "deny");
261 Xchat::print("${B}FILTER DEBUG ----------${B}\n");
264 sub cmd_server_limit {
265 my $server = shift;
267 if ($server) {
268 # adding limiting to given (single) server
269 if ($limit_to_server) {
270 Xchat::print("${B}FILTER:${B} Changing server from $limit_to_server to $server\n");
271 } else {
272 Xchat::print("${B}FILTER:${B} Limiting filtering to server $server\n");
274 $limit_to_server = $server;
276 } else {
277 # removing limiting to server
278 if ($limit_to_server) {
279 Xchat::print("Filter: Removing limit to server $limit_to_server\n");
281 $limit_to_server = '';
286 sub cmd_print_rules {
287 Xchat::print("${B}FILTER PRINT ----------${B}\n");
288 Xchat::print("${B}ALLOW${B}".($use_filter_allow ? ' (on)' : ' (off)')."\n");
290 for (my $i = 0; $i <= $#filter_allow; $i++) {
291 Xchat::print("[$i]: /".$filter_allow[$i]."/\n");
293 Xchat::print("${B}DENY${B}\n");
294 for (my $i = 0; $i <= $#filter_deny; $i++) {
295 Xchat::print("[$i]: /".$filter_deny[$i]."/\n");
297 Xchat::print("${B}FILTER PRINT ----------${B}\n");
300 sub cmd_add_rule {
301 my $rule = shift;
303 if ($rule) {
304 add_rule($rule);
305 Xchat::print("${B}FILTER RULE [$#filter_deny]:${B} /$rule/\n");
306 } else {
307 Xchat::print("Syntax: ${B}/FILTER ADD ${U}rule${U}${B} to add\n")
311 sub cmd_delete_rule {
312 my $num = shift;
314 # strip whitespace
315 $num =~ s/^\s*(.*?)\s*$/$1/g if $num;
316 SWITCH: {
317 unless ($num) {
318 Xchat::print("${B}FILTER:${B} deleting /".$filter_deny[-1]."/\n");
319 $#filter_deny--;
320 Xchat::print("${B}FILTER:${B} deleted successfully last rule\n");
321 last SWITCH;
323 if ($num !~ /^\d+$/) {
324 Xchat::print("${B}FILTER:${B} $num is not a number\n");
325 last SWITCH;
327 if ($num < 0 || $num > $#filter_deny) {
328 Xchat::print("${B}FILTER:${B} $num outside range [0,$#filter_deny]\n");
329 last SWITCH;
331 # default
333 Xchat::print("${B}FILTER:${B} deleting /".$filter_deny[$num]."/\n");
334 delete_rule($num);
335 Xchat::print("${B}FILTER:${B} deleted successfully rule $num\n");
340 sub cmd_show_rule {
341 my $num = shift;
343 $num =~ s/^\s*(.*?)\s*$/$1/g if $num;
345 if (defined $num && $num !~ /^\d+$/) {
346 Xchat::print("${B}FILTER:${B} $num is not a number\n");
347 } elsif (defined $num && !defined $filter_deny[$num]) {
348 Xchat::print("${B}FILTER:${B} rule $num does not exist\n");
349 } else {
350 Xchat::print("${B}FILTER:${B} ".(defined $num ? "[$num]" : "last").
351 " rule /".$filter_deny[defined $num ? $num : -1]."/\n");
355 # ============================================================
356 # ============================================================
357 # ============================================================
359 sub filter_command_handler {
360 my $cmd = $_[0][1]; # 1st parameter (after FILTER)
361 my $arg = $_[1][2]; # 2nd word to the last word
362 my $server = Xchat::get_info("host");
365 if (!$cmd || $cmd =~ /^STATUS$/i) {
366 cmd_status($server);
368 } elsif ($cmd =~ /^ON$/i) {
369 $filter_turned_on = 1;
370 Xchat::print("Filter turned ${B}ON${B}\n");
372 } elsif ($cmd =~ /^OFF$/i) {
373 $filter_turned_on = 0;
374 Xchat::print("Filter turned ${B}OFF${B}\n");
376 } elsif ($cmd =~ /^SERVER$/i) {
377 cmd_server_limit($server);
379 } elsif ($cmd =~ /^SERVERON$/i) {
380 cmd_server_limit($server);
382 $filter_turned_on = 1;
383 Xchat::print("Filter turned ${B}ON${B}\n");
385 } elsif ($cmd =~ /^ALL$/i) {
386 cmd_server_limit(undef);
388 } elsif ($cmd =~ /^HELP$/i) {
389 Xchat::print($scriptHelp);
391 } elsif ($cmd =~ /^VERSION$/i) {
392 cmd_version();
394 } elsif ($cmd =~ /^DEBUG$/i || $cmd =~ /^INFO$/i) {
395 cmd_debug();
397 } elsif ($cmd =~ /^(?:PRINT|LIST)$/i) {
398 cmd_print_rules();
400 } elsif ($cmd =~ /^ALLOW$/i) {
401 $use_filter_allow = !$use_filter_allow;
402 Xchat::print("${B}FILTER:${B} ALLOW rules ".
403 ($use_filter_allow ? "enabled" : "disabled")."\n");
405 } elsif ($cmd =~ /^ADD$/i) {
406 cmd_add_rule($arg);
408 } elsif ($cmd =~ /^DEL(?:ETE)$/i) {
409 cmd_delete_rule($arg);
411 } elsif ($cmd =~ /^SHOW$/i) {
412 cmd_show_rule($arg);
414 } elsif ($cmd =~ /^SAVE$/i) {
415 save_filter();
416 Xchat::print("${B}FILTER:${B} saved DENY rules to $filter_file\n");
418 } elsif ($cmd =~ /^(RE)?LOAD$/i) {
419 load_filter();
420 Xchat::print("${B}FILTER:${B} loaded DENY rules from $filter_file\n");
422 } else {
423 Xchat::print("Unknown command ${B}/FILTER $_[1][1]${B}\n") if $cmd;
425 return 1;
428 Xchat::print("${B}$scriptName $scriptVersion${B} loaded\n");