#!/usr/bin/perl -w # # clifutil.pl: client-side filtering utilities for xchat-2.x # # # PURPOSE: # # To make the user capable of filtering data coming from the chat server, in # order to control what's being shown on screen an what's not. # # # USAGE: # # Just place a file called `filters' on your xchat directory (usually # ~/.xchat2), specifying those hooks you don't want to hear about any longer, # one by line, and that's all. a hook can be a word, a couple of them, a # sentence, etc... # # For example by placing the string `mujer canaria' on the above mentioned # file (~/.xchat2/filters), whenever someone says it, either in upper or # lower-case, or despite of where in the sentence it is actually present, # that sentence won't be shown as if it would have never been written. # # # HOW DOES IT WORK: # # The script basically parses raw data coming from the chat server, and by # post-processing it against a given configuration, decides whether it's ok to # display that line or not, independently of who wrote it. # # Even though the script has to process every single line coming from the # server, it does all the work at memory level--uses perl's linked lists--no # overhead is noticeable, or at least not on my laptop. # # I've been testing with quite large lists on kind of heavy channels an can't # still see any overhead. This doesn't mean it's not there; do your own # testing. # # The script makes also available the whole ignore list to the known hooks, # which means that every single sentence in which any of those nicks appear # won't be shown either. In this case pattern matching policy is a bit more # restrictive so words that can also be nicks doesn't get off the way as long # as aren't written exactly the same. # # In any case feel free to modify it upon your needs or what not... # # # PROVIDED COMMANDS: # # /clifutil reads/re-reads ignore and filters file. New filtering # policy applies straight away. This is just in case you # add new hooks to be filtered or add people to the ignore # list and want to keep things tidy. Otherwise isn't # needed. The script is loaded automatically at xchat's # startup (see bellow). # # /clifdump dump memory contents in regards of those hooks # (including nicks) that are being filtered. # # # have a nice chatting without having to read doughnuts! :) # # my $short_name = "clifutil"; my $long_name = "(client-side filtering utilities)"; my $version = "0.1"; # whether we're loading it by first time or not $loaded = 0; # this is the path for the rules-file. Change as you will but be aware, # though, scripts outside XCHAT_HOME aren't loaded automatically $rules = "$ENV{'HOME'}/.xchat2/rules"; # path for xchat's native ignore configuration (you shouldn't need to change # this) $ignore_conf = "$ENV{'HOME'}/.xchat2/ignore.conf"; # the rules' buffer @rules = (); # the nicks buffer, we need to keep them separate because of different # matching policies @nicks = (); # we start here, read in the rules' file, and parse the ignore config as well &read_rules_and_ignore; # set up handlers and the like IRC::register ($short_name, $version, "", ""); IRC::add_message_handler('PRIVMSG', 'parse_line'); IRC::add_message_handler('NOTICE', 'parse_line'); IRC::add_command_handler('clifutil', 'read_rules_and_ignore'); IRC::add_command_handler('clifdump', 'clif_dump'); IRC::print("$short_name v$version loaded"); # read (or re-read) the rules file, and the ingore config file. sub read_rules_and_ignore { if ($loaded) { IRC::print("$short_name: re-reading input files..."); } @rules = (); @nicks = (); open(RULES, "<$rules") || IRC::print("FAILED TO READ $rules - $!"); while (chomp($rule = )) { next unless $rule; push @rules, $rule; } close RULES; open(NICKS, "<$ignore_conf") || IRC::print("FAILED TO READ $ignore_conf - $!"); while (chomp($nick = )) { next unless $nick; if ($nick =~ /^mask = /) { next unless $nick; # get rid of everyting but the mask $nick =~ s/mask = //; # get rid of the mask and leave us just a nick $nick =~ s/\*|[!@]*//g; # push it onto the nicks' list push @nicks, $nick; } } close NICKS; if ($loaded) { IRC::print("$short_name: Ok"); }else{ $loaded++; } return 1; } # read_rules_and_ignore # dump memory contents in regards of hooks beign filtered sub clif_dump { my $value = shift; IRC::print("== RULES BEING FILTERED =="); foreach $value (@rules) { Xchat::print("$value"); } IRC::print("== NICKS BEING FILTERED =="); foreach $value (@nicks) { IRC::print("\"$value\""); } IRC::print("=========================="); return 1; } # clif_fump # check a sentence against our rules' matching policy sub check_filter { my $line = shift; foreach $rule (@rules) { return 1 if ($line =~ /$rule/i); } return 0; } # check_filter # check a sentence against our nicks' matching policy sub check_nick_filter { @words = (); my $line = shift; @words = split(/ /,$line); foreach $wordl (@words) { foreach $rule (@nicks) { return 1 if ($wordl =~ /\Q$rule\E/); } } return 0; } # check_nick_filter # parse a line coming from the server sub parse_line { my $line = shift; # get rid of the bloody colors $line =~ s/\cc[0-9]{2}//g; if ($line =~ /:(.+)!(.+)@(.+)\s([A-Z]+)\s(.+)\s?:(.+)/) { ($nick, $user, $host, $msgtype, $to, $msgtxt) = ($1, $2, $3, $4, $5, $6); } # check for nicks first $var = &check_nick_filter($line); if (!$var) { # and if not look for any matching rule return &check_filter($line); }else { return $var; } } # parse_line