#!/usr/bin/perl # What this script does : # ----------------------- # 1/ check nagios.log # 2/ setup an array of alerts # 3/ ability to remove-change alerts on new notification for same host/[service] # 4/ dialog with livestatus to replay full alerts on load/setup : irssi command /nagrefresh # 5/ define !recheck to nagios # 6/ ability to define chan/server on irssi configuration instead of bot config. # # What it should do : # ------------------- # TODO # define !ack irc command # use %ACK_INDEX by alert type HOST / SERVICE # use %ACK_INDEX_LEVEL by alert type CRIT/UP/DOWN/WARN/UNK… use strict; use vars qw($VERSION %IRSSI); use Irssi; use POSIX "sys_wait_h"; use POSIX qw(strftime); use Term::ANSIColor qw/ :constants /; use Fcntl; # provides `O_NONBLOCK' and `O_RDONLY' constants ########################################################################## # Part A : script configuration / Prototypes # Put signals to irssi ################################################### our ( $FIFO, # fifo absolute filename (expanded from Irssi config) $FIFO_HANDLE, # fifo filehandle for `open' et al. $FIFO_TAG ); # fifo signal tag for `input_add' $VERSION = "0.4.1"; %IRSSI = ( authors => 'asr', contact => 'root@lautre.net', name => 'nagios-ack', description => 'ack nagios alerts in irc / follow nagios log', license => 'GPLv2', url => 'http://www.lautre.net/', changed => '20141006', modules => '' ); my $PRINTF = "/usr/bin/printf"; # Put signals to irssi ################################################### Irssi::settings_add_str($IRSSI{name}, # default fifo_remote_file 'fifo_remote_file', '/home/tc-14/var/nagios-fifo'); # Irssi::settings_add_str("nagios_ack", "nagios_ack_channel", "#main_channel"); # see also etc/config.template Irssi::settings_add_str("nagios_ack", "nagios_ack_nick", ""); # any user (none by default) Irssi::settings_add_str("nagios_ack", "nagios_live", "/var/lib/nagios3/rw/live"); Irssi::settings_add_str("nagios_ack", "nagios_command", "/var/lib/nagios3/rw/nagios.cmd"); #Irssi::command_bind( 'ack', \&nagios_ack ); #Irssi::command_bind( 'nagstat', \&nagios_status ); Irssi::command_bind( 'nagrefresh', \&nagios_query_status ); # CONFIG: point this where your Nagios configuration files live #my $nagioslog = "/var/log/nagios3/nagios.log"; # To be used to check immediately / hosts-stats my $nagioscmd = Irssi::settings_get_str("nagios_command"); my $nagioslive = Irssi::settings_get_str("nagios_live"); my $nagios_ack_channel= Irssi::settings_get_str("nagios_ack_channel"); my $nagios_ack_nick= Irssi::settings_get_str("nagios_ack_nick"); my %renot; # { "host" or "host:service" => time_last_notification } my @cmdqueue = (); my %ignore = (); my @ACKS; # [ hostname, service, state, plugin_output, last_state_change, ACKnowledged ] ); my %ACK_Ind; my %C = ( K => "\x0301", # 00. White B => "\x0302", # 01. Black G => "\x0303", # 02. Blue (Navy) R => "\x0304", # 03. Green # 04. Red V => "\x0306", # 05. Brown (Maroon) O => "\x0307", # 06. Purple Y => "\x0308", # 07. Orange Gg => "\x0309", # 08. Yellow # 09. Light Green (Lime) C => "\x0311", # 10. Teal (Green/Blue Cyan) Bb => "\x0312", # 11. Light Cyan (Cyan) (Aqua) Ma => "\x0313", # 12. Light Blue (Royal) Gr => "\x0314", # 13. Pink (Light Purple) (Fuchsia) W => "\x0315", # 14. Grey # 15. Light Grey (Silver) Z => "\x03", ); # Numeric to string conversion of nagios status # 0..4 : hosts # 10..14 : services my @NagStates = qw/UP DOWN WARNING UNKNOWN .. .. .. .. .. .. OK WARNING CRITICAL UNKNOWN/; # Bold: U+0002 ("0x02") — Example: ^Bold Text^ whereas ^ represents the control character. # Italics: U+001D ("0x1D") — Example: ^Italicized Text^ whereas ^ represents the control character. # Underline: U+001F ("0x1F") — Example: ^Underlined Text^ whereas ^ represents the control character. # The control character used for color is U+0003 ("0x03"). my $state_to_color = { OK => $C{G}, UP => $C{G}, WARNING => $C{Y}, CRITICAL => $C{R}, DOWN => $C{V}, UNKNOWN => $C{Gr}, }; # Global use to limit memory use. Probably a bad idea : better to check # where is the memory leak. my ($status_line); my @match; my $msg; my $i; my $stat; my $message; my ($type,$data); my ($d,$type,$host,$service,$state,$output); my ( $host, $svc, $state, $id ); my ($server, $nick, $addr, $target); my ( $param, $server, $window ); my (@issue, $issue); #my $state_to_color = { OK => '', UP => '', WARNING => '', CRITICAL => '', DOWN => '', UNKNOWN => '' }; # Alert Acknowledment #################################################### my $last_alert; my $DEBUG=Irssi::settings_get_str("nagios_ack_nick"); # Simple subs ############################################################ sub TRUE() { 1 } # some constants [perlsyn(1) sub FALSE() { "" } # "Constant Functions"] sub DEBUG(@) { print "%B", join(":", @_),"%n" }# DEBUG thingy sub time2date($) { ($d)=@_; return strftime("%d/%m/%y %H:%M", localtime($d)); } ########################################################################## # Part B : user Actions ################################################## # Acknowledge alerts ##################################################### # Global use to limit memory use. Probably a bad idea : better to check # where is the memory leak. # Four unused subs. Still there to be implemented later sub parse_status(); sub nagios_ack($$$); sub nagios_check($$$); sub nagios_inject; #sub nagios_status(); # Return alert ID "[FF01]" # F : caracter to display (! : ; C : change ; + : new alert ; - : green flag ; ? : green but not found) # I : numeric ID # state : state string, from @NagStates or %state_to_color sub format_alert_id($$$$); # ($Flag,$I,$state,$acked) # Add alert to array / index # returns array (ID,char) : ID of new alert (-1 if not inserted) ; char in !,c,?,+,-. sub insert_alert($$$$$$); #( $host, $svc, $state, $msg, $d ) ########################################################################## # Part C : Logfile management ############################################ # disable fifo and erase fifo file sub destroy_fifo($); # [2004-08-14] # Open logfile/fifo sub open_fifo($); # [2004-08-14] # read from fifo # (called by fifo input signal) sub read_fifo(); # [2004-08-14] # Read logfile ########################################################### # create named fifo and open it for input # (called on script load and fifo name changes) sub create_fifo($); # [2004-08-14] # Query nagios ########################################################### sub nagios_query_status($); ########################################################################## # Part D : Alert processing ############################################## # display a line resuming the alert # ($server,$chan,$alert_id,$prefix) -> alert_id from @ACKS sub display_alert($$$$); # Search for services/host informations, and post them to IRC ############ # Delimiter : ; for logs; @ for direct nagios custom notification command # one parameter : the logline to parse. sub parse_nagios_log($); # Use alert fields to print and insert it # timestamp, alert-type, hostname, state, plugin output, service_name sub handle_alert($$$$$$$$); # $d,$type,$host,$state,$output,$service,$acked ########################################################################## # IRSSI Events ########################################################### # create new fifo (erase any old) and get command prefix # (called on script loading and on user /set) sub setup(); # [2004-08-13] # Interact with IRC chan users sub event_privmsg ($$$$); ########################################################################## # References ############################################################# ########################################################################## # REFERENCES # ---------- # # This script is mainly adapted from 3 other scripts related to nagios : # # https://github.com/zorkian/nagios-irc-bot/blob/master/nagiosirc.pl # http://www.update.uu.se/~zrajm/programs/irssi-scripts/fifo_remote.pl-0.5 # https://github.com/mikegrb/irssi-scripts/blob/master/nagios-ack.pl ########################################################################## # CODE ################################################################### ########################################################################## ########################################################################## # Part B : user Actions ################################################## sub parse_status() { return $1 if $last_alert =~ /^PROBLEM - (\S+) is DOWN/; return ($1, $2) if $last_alert =~ /^PROBLEM - (\S+) on (\S+) is/; return; } sub nagios_ack($$$) { ( $param, $server, $window ) = @_; $msg=''; @issue = parse_status(); if (!@issue) { #$window->print("Failed to parse last status: $last_alert"); } # $host / sticky / notif / persistant / user ($id,$message)=split " ",$param; if (($id =~ /^#(\d+)/) && ($id <= scalar @ACKS)) { $id=$1; $i=time; if ($ACKS[$id]->[5] == 1) { # Already ACKed, print an error. $msg = " ACK : impossible, c'est dejà fait" ; display_alert($server,$nagios_ack_channel,$id,' ' # format_alert_id(' ', $id, $ACKS[$id]->[2], $ACKS[$id]->[5]) ); } elsif ($ACKS[$id]->[1] ne "") { $msg = " ACK ".$id." \"ACKNOWLEDGE_SVC_PROBLEM;$ACKS[$id]->[0];$ACKS[$id]->[1];2;0;1;nagiosadmin;$message\" $i > $nagioscmd"; Irssi::active_server->command('MSG ' . $DEBUG . " ". `$PRINTF "[\%lu] ACKNOWLEDGE_SVC_PROBLEM;$ACKS[$id]->[0];$ACKS[$id]->[1];2;0;1;nagiosadmin;$message" $i> $nagioscmd` ); } else { $msg = " ACK ".$id." \"ACKNOWLEDGE_HOST_PROBLEM;$ACKS[$id]->[0];2;0;1;nagiosadmin;$message\" $i > $nagioscmd"; Irssi::active_server->command('MSG ' . $DEBUG . " ". `$PRINTF "[\%lu] ACKNOWLEDGE_HOST_PROBLEM;$ACKS[$id]->[0];2;0;1;nagiosadmin;$message" $i > $nagioscmd` ); } $ACKS[$id]->[5] = 1; Irssi::active_server->command('MSG ' . $nagios_ack_channel . $msg); } else { $server->command ( "msg ".$nagios_ack_channel. " Usage : !nagios ACK # . Please validate first, with a !nagios list #"); display_alert($server,$nagios_ack_channel,$id,' ' # format_alert_id(' ', $id, $ACKS[$id]->[2], $ACKS[$id]->[5]) ) if $id =~ /^(\d+)/ ; } } sub nagios_check($$$) { #1412375470;filer2;DISK_all;2;W=10% C=5% ( $param, $server, $window ) = @_; @issue = parse_status(); if (!@issue) { #$window->print("Failed to parse last status: $last_alert"); } $message = " CHECK ".$param . join ' ', reverse @issue; Irssi::active_server->command('MSG ' . $DEBUG . $message); # handle_alert($$$$$$$) { # $d,$type,$host,$state,$output,$service } } sub nagios_inject { $last_alert = shift; } #sub nagios_status { # (undef, undef, $window) = @_; # $issue = join ',', map { "'" . $_ . "'" } reverse parse_status(); # $window->print("Last issue: '$last_alert' ($issue)"); # #} # Return alert ID sub format_alert_id($$$$) { my ($Flag,$I,$state,$acked)=@_; my $M=sprintf('%02d', scalar @ACKS % 100); my $N=sprintf('%02d', $I % 100); if (($I == 0) && (scalar @ACKS == 0)) { return "[".($acked==0?'!':' ').$Flag." ]/$M "; } else { return "[".($acked==0?'!':' ').$Flag.$state_to_color->{$state}.$N.$C{Z}."]/$M "; } } # Add alert to array / index sub insert_alert($$$$$$) { # returns ID of new alert ; -1 if not inserted. #Irssi::print(">> On vire $host/$svc"); my $i; my $acked; ( $host, $svc, $state, $msg, $d, $acked ) = @_; # ALERT if ( $state eq 'WARNING' || $state eq 'CRITICAL' || $state eq 'UNKNOWN' || $state eq 'DOWN' ) { while ($i <= $#ACKS) { # Update, or insert ? if (($ACKS[$i]->[0] eq $host) && ($ACKS[$i]->[1] eq $svc)) { $ACKS[$i]->[4]=$d; Irssi::print(">> found $i"); if ($ACKS[$i]->[2] ne $state) { # Same alert, but different level $ACKS[$i]->[2]=$state; return ($i+1,'c'); } else { # Same alert return ($i+1, '!'); # No need to display... } } $i++; } # New alert, insert. push (@ACKS, [ $host, $svc, $state, $msg, $d, $acked ] ); return (scalar @ACKS,'+'); # Clear alert } else { # Irssi::print(">> On vire $host/$svc"); $i=0; # Find alert (need to be used by service/host index) while ($i <= $#ACKS) { if (($ACKS[$i]->[0] eq $host) && ($ACKS[$i]->[1] eq $svc)) { $ACKS[$i] = pop @ACKS; $i=$#ACKS; Irssi::print(">> found $i"); return (-1,'-'); } $i++; } return (-1,'?'); } } ########################################################################## # Part C : Logfile management ############################################ # disable fifo and erase fifo file sub destroy_fifo($) { # [2004-08-14] my ($fifo) = @_; # get args if (defined $FIFO_TAG) { # if fifo signal is active Irssi::input_remove($FIFO_TAG); # disable fifo signal undef $FIFO_TAG; # and forget its tag } # if (defined $FIFO_HANDLE) { # if fifo is open close $FIFO_HANDLE; # close it undef $FIFO_HANDLE; # and forget handle } # if (-p $fifo) { # if named fifo exists unlink $fifo; # erase fifo file undef $FIFO; # and forget filename } # return 1; # return } # # Open logfile/fifo sub open_fifo($) { # [2004-08-14] my ($fifo) = @_; # get args if (not sysopen $FIFO_HANDLE, $fifo, # open fifo for non-blocking O_NONBLOCK | O_RDONLY) { # reading print CLIENTERROR "could not open nagios logfile for reading"; return ""; # } # Irssi::input_remove($FIFO_TAG) # disable fifo reading signal if defined $FIFO_TAG; # if there is one $FIFO_TAG = Irssi::input_add # set up signal called when fileno($FIFO_HANDLE), INPUT_READ, # there's input in the pipe \&read_fifo, ''; # return 1; # } # read from fifo # (called by fifo input signal) sub read_fifo() { # [2004-08-14] # Read logfile ########################################################### foreach (<$FIFO_HANDLE>) { # for each input line chomp; # strip trailing newline parse_nagios_log($_); #if (/ALERT/ && /HARD;/); #Irssi::active_win->print( # show incoming commands (debug) # "\u$IRSSI{name} received command: \"$_\"", # # MSGLEVEL_CLIENTNOTICE); # # Irssi::active_win->command($_); # run incoming commands } # open_fifo($FIFO); # re-open fifo # TODO: Is the above re-opening of fifo really necessary? -- If not # invoked here `read_fifo' is called repeatedly, even though no input # is to be found on the fifo. (This seems a waste of resources to me.) } # create named fifo and open it for input # (called on script load and fifo name changes) sub create_fifo($) { # [2004-08-14] my ($new_fifo) = @_; # get args if (not -p $new_fifo) { # create fifo if non-existant if (system "mkfifo '$new_fifo' &>/dev/null" and system "chmod 777 '$new_fifo' &>/dev/null" and system "mknod '$new_fifo' &>/dev/null"){ print CLIENTERROR "`mkfifo' failed -- could not create named pipe"; # TODO: capture `mkfifo's stderr and show that here return ""; # } # } # $FIFO = $new_fifo; # remember fifo name open_fifo($new_fifo); # open fifo for reading } # # Query nagios ########################################################### sub nagios_query_status($){ # 1412478149;hyppocampe;apt;2;CRITICAL : unknown: qemu-utils, qemu-kvm, qemu-keymaps my ($option)=@_; my @unixcat; my $unixline; my $acked; $nagioslive = Irssi::settings_get_str("nagios_live"); foreach $acked (0,1) { foreach $unixline ( `echo "GET services Columns: last_state_change host_name display_name state plugin_output Filter: state > 0 Filter: acknowledged = $acked And: 2" | unixcat $nagioslive` ) { chomp $unixline; ($d,$host,$service,$state,$output)=split /;/,$unixline; handle_alert($option,$d,'SERVICE',$host,$NagStates[$state+10],$output,$service,$acked); Irssi::print("%B>>%n $unixline", MSGLEVEL_CLIENTCRAP); } } return; foreach $acked (0,1) { foreach $unixline ( `echo "GET hosts Columns: last_state_change host_name state plugin_output Filter: state > 0 Filter: acknowledged = 0 And: 2" | unixcat $nagioslive` ) { chomp $unixline; ($d,$host,$state,$output)=split /;/,$unixline; handle_alert($option,$d,'HOST',$host,$NagStates[$state],$output,"",$acked); Irssi::print("%B>>%n $unixline", MSGLEVEL_CLIENTCRAP); } } } ########################################################################## # Part D : Alert processing ############################################## sub display_alert($$$$){ my ($server,$chan,$alert_id,$prefix) = @_; #Irssi::print("... $alert_id"); return unless defined $ACKS[$alert_id]; # @ACKS; # [ hostname, service, state, plugin_output, last_state_change, ACKnowledged ] ); # my ($server,$chan,$date,$prefix,$state,$acked,$hostname,$service,$output) = @_; $prefix=format_alert_id($prefix,$alert_id,$ACKS[$alert_id]->[2],$ACKS[$alert_id]->[5]) ; #format_alert_id(' ', $i, $K->[2], $K->[5]), $server->command ( 'msg ' . $chan . " NAGIOS ". time2date ($ACKS[$alert_id]->[4])." ". $prefix. " ". $state_to_color->{$ACKS[$alert_id]->[2]}.$ACKS[$alert_id]->[0]."/".$ACKS[$alert_id]->[1].$C{Z}. " / $ACKS[$alert_id]->[2]".($ACKS[$alert_id]->[5]?" Acked":"")." : $ACKS[$alert_id]->[3]" ); } # Search for services/host informations, and post them to IRC ############ # Delimiter : ; for logs; @ for direct nagios custom notification command sub parse_nagios_log($){ my $option=""; $d=0; $status_line=""; $host="";$output="";$service=""; $status_line=shift; ### log : # [1412330770] SERVICE ALERT: ella;IMAPs_LOGIN;OK;SOFT;2;OK - CO1N OK LOGIN Ok. # /\[\d+\] (\w+) ALERT: (\w+);(\w+);(\w+);HARD;(\d+);(.+)/ # [1410969598] HOST ALERT: filou;DOWN;SOFT;1;PING CRITICAL - Paquets perdus = 100% # [TIMESTAMP] PROCESS type ALERT: host;service;STATE1;HARD;num;commentaire if (@match=$status_line =~ /\[?(\d+)\]? HOST ALERT: ([^@;]+)[@;]([^;@]+)[@;]HARD[@;][^;@]*[@;](.+)/) { # HOST ######################## ($d,$host,$state,$output)=@match; handle_alert($option,$d,"HOST",$host,$state,$output,$service,0); # SERVICE ##################### } elsif (@match=$status_line =~ /\[?(\d+)\]? (\w+) ALERT: ([^;@]+)[@;]([^;@]+)[@;]([^;@]+)[@;]HARD[@;][^;@]*[@;](.+)/) { ($d,$type,$host,$service,$state,$output)=@match; $service=~s/[^\w\d_-]/_/g; handle_alert($option,$d,$type,$host,$state,$output,$service,0); # OTHER ####################### } elsif (@match=$status_line =~ /\[\d+\] (\w+) ALERT: (.*)/) { ($type,$data)=@match; Irssi::print( "%B>>%n $IRSSI{name} $type - $data", MSGLEVEL_CLIENTCRAP) unless ($status_line =~ /[;@]SOFT[@;]/); # FALLBACK #################### } else { Irssi::print( # "%B>>%n $IRSSI{name} received message: \"$_\"", MSGLEVEL_CLIENTCRAP); # next } } # Use alert fields to print and insert it sub handle_alert($$$$$$$$) { # $d,$type,$host,$state,$output,$service,acked my $option; my $acked; # Temporisation ($option,$d,$type,$host,$state,$output,$service,$acked)=@_; next if exists $renot{"$host:$service"} && $renot{"$host:$service"} >= time() - 5; $renot{"$host:$service"} = time(); # HOST or SERVICE ? ($id,$stat) = insert_alert($host,$service,$state,$output,$d,$acked); # Silently ignore previously sent/acked alerts Irssi::print(">> $nagios_ack_channel,$d,$id,$state,$acked,$host,$service,$output"); return if $id == -1; $nagios_ack_channel= Irssi::settings_get_str("nagios_ack_channel"); display_alert(Irssi::active_server,$nagios_ack_channel,$id,$stat), unless ($option eq "silent"); } ########################################################################## # IRSSI Events ########################################################### # create new fifo (erase any old) and get command prefix # (called on script loading and on user /set) sub setup() { # [2004-08-13] my $new_fifo = Irssi::settings_get_str # setting from Irssi 'fifo_remote_file'; # (and add path to it) return if $new_fifo eq $FIFO and -p $FIFO; # do nada if already exists destroy_fifo($FIFO) if -p $FIFO; # destroy old fifo create_fifo($new_fifo) # create new fifo and $FIFO = $new_fifo; # and remember that fifo # To ADD : # request to livestatus to fetch stored alerts } # Interact with IRC chan users sub event_privmsg($$$$) { # Commamd channel my $K; my ($server, $data, $nick, $mask) =@_; my ($target, $text, $arg) = $data =~ /^(\S*)\s:(.*)/; #print ( "C:$target X:$text A:$admin D:$warndate L:$last W:$warn N:$nick D:$data" ); if ( $text =~ /^!nagios ?(.*)/i ) { $arg=$1; # If we are not in command channel : NoOP $nagios_ack_channel=Irssi::settings_get_str("nagios_ack_channel"); Irssi::print(">> $arg - $nagios_ack_channel - $target"); return if $target ne $nagios_ack_channel ; if ($arg =~ /^refresh ?(.*)/i) { $arg=$1; Irssi::print(">> $arg"); if ($arg =~ /\bclear\b/) { $server->command ( "msg ".$nagios_ack_channel." Local alerts cleared" ); @ACKS=(); } if ($arg =~ /\bclear\b/) { nagios_query_status("silent"); } else { nagios_query_status(""); $server->command ( "msg ".$nagios_ack_channel. 'Refresh nagios. Use "silent" keyword to disable display.'); } $server->command ( "msg ".$nagios_ack_channel. " ".scalar @ACKS." alertes"); } elsif ($arg =~ /^list ?(.*)/i) { my $i=0; # Do you search on pattern (whole database), or a list (reduced database) ? my $grepto; my $motif=$1; my $search_unack=0; $server->command ( "msg ".$nagios_ack_channel. " ".scalar @ACKS." alertes"); $motif="" unless defined($motif) ; $motif="0\$" if $motif =~ /^ack$/i; $motif="1\$" if $motif =~ /^unack$/i; $search_unack="1" if $motif eq ""; Irssi::print(">> List : $motif"); foreach $K (@ACKS) { my $grepto="#$i @$K"; # just display alert fields, with colors. # See ACKS fields organization # Field 5 is "Alert has been previously acknowledged" # display_alert($server,$chan,$date,$prefix,$state,$acked,$hostname,$service,$output) display_alert($server,$nagios_ack_channel,$i,' ' #format_alert_id(' ', $i, $K->[2], $K->[5]), #$K->[2],$K->[5],$K->[0],$K->[1],$K->[3] ) if ( ($grepto =~ /$motif/i) || ($search_unack && ($K->[5]==0)) ); # Display only if : $motif is found, or $motif is empty, and alert is unack $i++; } } elsif ($arg =~ /^help/i) { $server->command ( "msg ".$nagios_ack_channel. " !nagios list [pattern] [ack/unack] : liste des alertes nagios reçues ici"); $server->command ( "msg ".$nagios_ack_channel. " !nagios help : l'aide"); $server->command ( "msg ".$nagios_ack_channel. " !nagios ack <#ALERTE> TODO : aquitte l'alerte"); $server->command ( "msg ".$nagios_ack_channel. " !nagios check <#ALERTE> TODO : recheck une alerte donnée (service/host)"); $server->command ( "msg ".$nagios_ack_channel. " !nagios refresh [silent] [clear] : interroge le nagios pour avoir la liste de toutes les alertes"); $server->command ( "msg ".$nagios_ack_channel. " si le mot clef 'clear' est ajouté, il purge les alertes locales"); } elsif ( $arg =~ /^check ?(.*)/i ){ nagios_check($1,$server,undef); } elsif ( $arg =~ /^ack ?(.*)/i ){ nagios_ack($1,$server,undef); $server->command ( "msg ".$nagios_ack_channel. " ".scalar @ACKS." alertes"); } else { $server->command ( "msg ".$nagios_ack_channel. " ".scalar @ACKS." alertes"); } } return 1; } ########################################################################## # Main ################################################################### ########################################################################## print "starting...\n"; # clean up fifo on unload # (called on /script unload) Irssi::signal_add_first # 'command script unload', sub { # [2004-08-13] my ($script) = @_; # get args return unless $script =~ # only do cleanup when /(?:^|\s) $IRSSI{name} # unloading *this* script (?:\.[^. ]*)? (?:\s|$) /x; # destroy_fifo($FIFO) if -p $FIFO; # destroy old fifo Irssi::print("%B>>%n $IRSSI{name} $VERSION unloaded", MSGLEVEL_CLIENTCRAP); }; # setup(); # initialize setup values Irssi::signal_add('event privmsg', 'event_privmsg'); Irssi::signal_add("message public", "event_privmsg"); Irssi::signal_add('setup changed', \&setup); # re-read setup when it changes print CLIENTCRAP "%B>>%n $IRSSI{name} $VERSION (by $IRSSI{authors}) loaded"; 1;