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";
15 my $U = chr 31; # underline
16 my $C = chr 3; # start of color sequence
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)";
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
51 my $filterwindow_commands = 'ON|OFF';
53 my $filterwindow_help = <<"EOF";
54 ${B}/FILTERWINDOW $filterwindow_commands${B}
55 /FILTERWINDOW ON|OFF - turns saving filtered content to ${U}$filter_window${U}
58 Xchat
::register
($scriptName, $scriptVersion, $scriptDescr);
60 Xchat
::hook_command
("FILTER", \
&filter_command_handler
,
61 { help_text
=> $filter_help });
62 Xchat
::hook_command
("FILTERWINDOW", \
&filterwindow_command_handler
,
63 { help_text
=> $filterwindow_help });
64 Xchat
::hook_server
("PRIVMSG", \
&privmsg_handler
);
66 Xchat
::print("Loading ${B}$scriptName $scriptVersion${B}\n".
67 " For help: ${B}/FILTER HELP${B}\n");
70 if ($filtered_to_window) {
71 Xchat
::command
("QUERY $filter_window");
74 # information about (default) options used
75 if ($filter_turned_on) {
76 Xchat
::print("Filter turned ${B}ON${B}\n");
78 Xchat
::print("Filter turned ${B}OFF${B}\n");
80 if ($limit_to_server) {
81 Xchat
::print("Filter limited to server $limit_to_server\n")
83 if ($use_filter_allow) {
84 Xchat
::print("Filter uses ALLOW rules\n");
87 # ------------------------------------------------------------
103 q
/(?i)fserve.*trigger/,
105 q
/(?i)trigger.*\/ctcp
/,
107 q
/(?i)file server online/,
116 #messages for when a file is received/failed to receive
117 q
/(?i)DEFINITELY had the right stuff to get/,
118 q
/(?i)has just received/,
119 q
/(?i)I have just received/,
130 q
/brave soldier in the war/,
133 # return 1 (true) if text given as argument is to be filtered out
138 #strip colour, underline, bold codes, etc.
139 $text = Xchat
::strip_code
($text);
141 if ($use_filter_allow) {
142 foreach $regexp (@filter_allow) {
143 return 0 if ($text =~ /$regexp/);
147 foreach $regexp (@filter_deny) {
148 return 1 if ($text =~ /$regexp/);
154 #called when someone says something in the channel
155 #1: address of speaker
158 #4: text said (prefixed with :)
159 sub privmsg_handler
{
160 # $_[0] - array reference containing the IRC message or command
161 # and arguments broken into words
162 # $_[1] - array reference containing the Nth word to the last word
163 my ($address, $msgtype, $channel) = @
{$_[0]};
164 my ($nick, $user, $host) = ($address =~ /^:(.*?)!(.*?)@(.*)$/);
166 my $text = $_[1][3]; # Get server message
168 my $server = Xchat
::get_info
("host");
170 return Xchat
::EAT_NONE
unless $filter_turned_on;
171 if ($limit_to_server) {
172 return Xchat
::EAT_NONE
unless $server eq $limit_to_server;
177 if (isFiltered
($text)) {
178 if (defined $nick && $filtered_to_window) {
179 #Xchat::print($text, $filter_window)
181 my $ctx = Xchat
::get_context
();
182 Xchat
::set_context
($filter_window);
183 Xchat
::emit_print
('Channel Message', $nick, $text);
184 Xchat
::set_context
($ctx);
186 #return Xchat::EAT_XCHAT;
187 return Xchat
::EAT_ALL
;
189 return Xchat
::EAT_NONE
;
193 # ------------------------------------------------------------
196 my ($fh, $tmpfile) = tempfile
($filter_file.'.XXXXXX', UNLINK
=>1);
199 Xchat
::print("${B}FILTER:${B} ".
200 "Couldn't open temporary file $tmpfile to save filter: $!\n");
204 Xchat
::print("${B}FILTER SAVE >$filter_file${B}\n");
205 foreach my $regexp (@filter_deny) {
206 Xchat
::print("/".$regexp."/ saved\n");
207 print $fh $regexp."\n";
211 Xchat
::print("${B}FILTER:${B} Couldn't close file to save filter: $!\n");
214 #move($tmpfile, $filter_file);
215 rename($tmpfile, $filter_file);
216 Xchat
::print("${B}FILTER SAVED ----------${B}\n");
224 Xchat
::print("${B}FILTER:${B} ...loading filter patterns\n");
225 unless (open $fh, '<', $filter_file) {
226 Xchat
::print("${B}FILTER:${B} Couldn't open file to load filter: $!\n");
230 @filter_deny = <$fh>;
231 map (chomp, @filter_deny);
234 Xchat
::print("${B}FILTER:${B} Couldn't close file to load filter: $!\n");
238 Xchat
::print("${B}FILTER DENY ----------${B}\n");
239 for (my $i = 0; $i <= $#filter_deny; $i++) {
240 Xchat
::print(" [$i]: /".$filter_deny[$i]."/\n");
242 Xchat
::print("${B}FILTER DENY ----------${B}\n");
248 # always ading rules at the end
249 push @filter_deny, $rule;
252 sub delete_rule
( $ ) {
253 my $num = shift || $#filter_deny;
255 splice @filter_deny, $num, 1;
258 # ============================================================
259 # ------------------------------------------------------------
260 # ............................................................
263 Xchat
::print("${B}$scriptName $scriptVersion${B}\n");
264 Xchat
::print(" * URL: http://github.com/jnareb/softsnow-xchat2-filter\n");
265 Xchat
::print(" * URL: http://gitorious.org/projects/softsnow-xchat2-filter\n");
266 Xchat
::print(" * URL: http://repo.or.cz/w/softsnow_xchat2_filter.git\n");
272 if ($filter_turned_on) {
273 Xchat
::print("Filter is turned ${B}ON${B}\n");
275 Xchat
::print("Filter is turned ${B}OFF${B}\n");
277 if ($limit_to_server) {
278 if ($server eq $limit_to_server) {
279 Xchat
::print("Filter is limited to ${B}current${B} ".
280 "server $limit_to_server\n");
282 Xchat
::print("Filter is limited to server ".
283 "$limit_to_server != $server\n");
286 if ($use_filter_allow) {
287 Xchat
::print("Filter is using ALLOW rules (before DENY)\n");
292 Xchat
::print("${B}FILTER DEBUG ----------${B}\n");
293 Xchat
::print("Channel: ".Xchat
::get_info
("channel")."\n");
294 Xchat
::print("Host: ".Xchat
::get_info
("host")."\n");
295 Xchat
::print("Server: ".Xchat
::get_info
("server")."\n");
296 Xchat
::print("Server Id: ".Xchat
::get_info
("id")."\n");
297 Xchat
::print("Network: ".Xchat
::get_info
("network")."\n");
299 Xchat
::printf("%3u %s rules\n", scalar(@filter_allow), "allow");
300 Xchat
::printf("%3u %s rules\n", scalar(@filter_deny), "deny");
301 Xchat
::print("${B}FILTER DEBUG ----------${B}\n");
304 sub cmd_server_limit
{
308 # adding limiting to given (single) server
309 if ($limit_to_server) {
310 Xchat
::print("${B}FILTER:${B} Changing server from $limit_to_server to $server\n");
312 Xchat
::print("${B}FILTER:${B} Limiting filtering to server $server\n");
314 $limit_to_server = $server;
317 # removing limiting to server
318 if ($limit_to_server) {
319 Xchat
::print("Filter: Removing limit to server $limit_to_server\n");
321 $limit_to_server = '';
326 sub cmd_print_rules
{
327 Xchat
::print("${B}FILTER PRINT ----------${B}\n");
328 Xchat
::print("${B}ALLOW${B}".($use_filter_allow ?
' (on)' : ' (off)')."\n");
330 for (my $i = 0; $i <= $#filter_allow; $i++) {
331 Xchat
::print("[$i]: /".$filter_allow[$i]."/\n");
333 Xchat
::print("${B}DENY${B}\n");
334 for (my $i = 0; $i <= $#filter_deny; $i++) {
335 Xchat
::print("[$i]: /".$filter_deny[$i]."/\n");
337 Xchat
::print("${B}FILTER PRINT ----------${B}\n");
345 Xchat
::print("${B}FILTER RULE [$#filter_deny]:${B} /$rule/\n");
347 Xchat
::print("Syntax: ${B}/FILTER ADD ${U}rule${U}${B} to add\n")
351 sub cmd_delete_rule
{
355 $num =~ s/^\s*(.*?)\s*$/$1/g if $num;
358 Xchat
::print("${B}FILTER:${B} deleting /".$filter_deny[-1]."/\n");
360 Xchat
::print("${B}FILTER:${B} deleted successfully last rule\n");
363 if ($num !~ /^\d+$/) {
364 Xchat
::print("${B}FILTER:${B} $num is not a number\n");
367 if ($num < 0 || $num > $#filter_deny) {
368 Xchat
::print("${B}FILTER:${B} $num outside range [0,$#filter_deny]\n");
373 Xchat
::print("${B}FILTER:${B} deleting /".$filter_deny[$num]."/\n");
375 Xchat
::print("${B}FILTER:${B} deleted successfully rule $num\n");
383 $num =~ s/^\s*(.*?)\s*$/$1/g if $num;
385 if (defined $num && $num !~ /^\d+$/) {
386 Xchat
::print("${B}FILTER:${B} $num is not a number\n");
387 } elsif (defined $num && !defined $filter_deny[$num]) {
388 Xchat
::print("${B}FILTER:${B} rule $num does not exist\n");
390 Xchat
::print("${B}FILTER:${B} ".(defined $num ?
"[$num]" : "last").
391 " rule /".$filter_deny[defined $num ?
$num : -1]."/\n");
395 # ============================================================
396 # ============================================================
397 # ============================================================
399 sub filter_command_handler
{
400 my $cmd = $_[0][1]; # 1st parameter (after FILTER)
401 my $arg = $_[1][2]; # 2nd word to the last word
402 my $server = Xchat
::get_info
("host");
405 if (!$cmd || $cmd =~ /^STATUS$/i) {
408 } elsif ($cmd =~ /^ON$/i) {
409 $filter_turned_on = 1;
410 Xchat
::print("Filter turned ${B}ON${B}\n");
412 } elsif ($cmd =~ /^OFF$/i) {
413 $filter_turned_on = 0;
414 Xchat
::print("Filter turned ${B}OFF${B}\n");
416 } elsif ($cmd =~ /^SERVER$/i) {
417 cmd_server_limit
($server);
419 } elsif ($cmd =~ /^SERVERON$/i) {
420 cmd_server_limit
($server);
422 $filter_turned_on = 1;
423 Xchat
::print("Filter turned ${B}ON${B}\n");
425 } elsif ($cmd =~ /^ALL$/i) {
426 cmd_server_limit
(undef);
428 } elsif ($cmd =~ /^HELP$/i) {
429 Xchat
::print($filter_help);
430 Xchat
::print($filterwindow_help);
432 } elsif ($cmd =~ /^VERSION$/i) {
435 } elsif ($cmd =~ /^DEBUG$/i || $cmd =~ /^INFO$/i) {
438 } elsif ($cmd =~ /^(?:PRINT|LIST)$/i) {
441 } elsif ($cmd =~ /^ALLOW$/i) {
442 $use_filter_allow = !$use_filter_allow;
443 Xchat
::print("${B}FILTER:${B} ALLOW rules ".
444 ($use_filter_allow ?
"enabled" : "disabled")."\n");
446 } elsif ($cmd =~ /^ADD$/i) {
449 } elsif ($cmd =~ /^DEL(?:ETE)$/i) {
450 cmd_delete_rule
($arg);
452 } elsif ($cmd =~ /^SHOW$/i) {
455 } elsif ($cmd =~ /^SAVE$/i) {
457 Xchat
::print("${B}FILTER:${B} saved DENY rules to $filter_file\n");
459 } elsif ($cmd =~ /^(RE)?LOAD$/i) {
461 Xchat
::print("${B}FILTER:${B} loaded DENY rules from $filter_file\n");
464 Xchat
::print("Unknown command ${B}/FILTER $_[1][1]${B}\n") if $cmd;
469 sub filterwindow_command_handler
{
470 my $cmd = $_[0][1]; # 1st parameter (after FILTER)
471 #my $arg = $_[1][2]; # 2nd word to the last word
474 Xchat
::print("${B}${U}USAGE:${U} /FILTERWINDOW ON|OFF${B}\n");
476 } elsif ($cmd =~ /^ON$/i) {
477 Xchat
::command
("QUERY $filter_window");
478 Xchat
::print("${B}----- START LOGGING FILTERED CONTENTS -----${B}\n",
480 if !$filtered_to_window;
482 $filtered_to_window = 1;
483 Xchat
::print("Show filtered content in ${B}$filter_window${B}\n");
485 } elsif ($cmd =~ /^OFF$/i) {
486 Xchat
::print("${B}----- STOP LOGGING FILTERED CONTENTS -----${B}\n",
488 if $filtered_to_window;
489 #Xchat::command("CLOSE", $FilterWindow);
491 $filtered_to_window = 1;
492 Xchat
::print("Don't show filtered content in ${B}$filter_window${B}\n");
494 } elsif ($cmd =~ /^HELP$/i) {
495 Xchat
::print($filterwindow_help);
498 Xchat
::print("Unknown command ${B}/FILTERWINDOW $_[1][1]${B}\n") if $cmd;
499 Xchat
::print("${B}${U}USAGE:${U} /FILTERWINDOW ON|OFF${B}\n");
505 # ======================================================================
506 # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
507 # ----------------------------------------------------------------------
509 Xchat
::print("${B}$scriptName $scriptVersion${B} loaded\n");