# # $Id: growl-notify.pl 144 2006-08-09 03:12:28Z wu $ # # This is a little irssi script I cooked up to use Growl for Mac OS X # to provide pop-up notifications using Mac::Growl. # # http://www.geekfarm.org/twiki/bin/view/Main/GrowlNotify # use strict; # use warnings; # 'use warnings' was generating annoying errors about global variables # not shared in subroutines... wtf? use vars qw($VERSION %IRSSI $APP); use Mac::Growl ':all'; use Irssi; use YAML; $VERSION = do { my @r=(0, q$Revision: 144 $=~/\d+/g); sprintf "%d."."%03d"x$#r,@r }; %IRSSI = ( authors => 'VVu', contact => 'growl-notify--AT--geekfarm--DOT--org', name => 'growl notify', description => 'configurable Growl notifications on OS X for irssi.', license => 'Public Domain' ); # #_* To Do # # server connect and disconnect notifications # buddy connect/disconnect notifications # buddy icons - waiting on the next growl release # command to pause all notification # messages configurable by nick # if bbdb available, define nicks and images there # # #_* Config # my $configfile = "$ENV{HOME}/.irssi/growl.yaml"; my $config = { %{ YAML::LoadFile( $configfile ) || {} }, }; my $image_dir = $config->{'buddyicons'}; # #_* Global Data # # Store most recently received data to prevent duplicate paging events my ( $lastnick, $lasttext, $laststicky ); # #_* Growl registration # Mac::Growl::RegisterNotifications( 'irssi', [ 'irssi' ], [ 'irssi' ], "Irssix" ); # #_* Private Messages # sub sig_privmsg { return unless ( $config->{"private.enable"} ); my ($server, $data, $nick, $address) = @_; return undef unless ( $nick && $data ); unless ( _supress_duplicates( $nick, $data, 1 ) ) { notify ( "$nick (private)", "$data", $config->{"private.sticky"}, "$image_dir/$nick" ); } } Irssi::signal_add_last("message private","sig_privmsg"); # #_* Public Messages # sub sig_public { return unless $config->{"public.enable"}; my ( $server, $msg, $nick, $address, $target ) = @_; return unless ( $nick && $msg ); # If growl is true for this channel my $channel = lc( $target ); if ( $config->{"public.channels"}->{$channel} ) { my $sticky; if ( $config->{"public.channels"}->{$channel} eq "sticky" ) { $sticky = 1; } unless ( _supress_duplicates( $nick, $msg, $sticky ) ) { notify ( "$nick [$channel] (public)", $msg, $sticky, "$image_dir/$nick" ); } } } Irssi::signal_add_last('message public', 'sig_public'); # # Hilighted Words # sub sig_printtext { return unless ( $config->{"hilight.enable"} ); my ($dest, $text, $stripped) = @_; if (($dest->{level} & (MSGLEVEL_HILIGHT|MSGLEVEL_MSGS)) && ($dest->{level} & MSGLEVEL_NOHILIGHT) == 0) { # Pull nick and text from $stripped $stripped =~ m|^\<(.*?)\>\s+(.*)$|; my ( $nick, $text ) = ( $1, $2 ); return undef unless ( $nick && $text ); unless ( _supress_duplicates( $nick, $text, 1 ) ) { notify ( "$nick (hilite)", $text, $config->{"hilight.sticky"}, "$image_dir/$nick" ); } } } Irssi::signal_add_last('print text', 'sig_printtext'); Irssi::print('%G>>%n '.$IRSSI{name}.' '.$VERSION.' loaded (/growl for help)'); # # #_* Public Subroutines # # # #__* notify # # send a pop-up notification using growl sub notify { my ( $subject, $text, $sticky, $image ) = @_; Irssi::print( "Private message" ); return undef unless $subject; return undef unless $text; # legal characters $text =~ tr|a-zA-Z0-9\!\@\#\$\%\^\&\*\(\)\_\+\-\=\[\]\{\}\;\:\'\"\,\.\<\>\/\?\`\~\ \n||cd; $subject =~ tr|a-zA-Z0-9\!\@\#\$\%\^\&\*\(\)\_\+\-\=\[\]\{\}\;\:\'\"\,\.\<\>\/\?\`\~\ \n||cd; $sticky = $sticky ? 1 : 0; # priority is set high if sticky is set my $prio = $sticky ? 2 : 0; # include time my $timestamp = sprintf ( "%02d:%02d:%02d", ( localtime( time ) )[ 2,1,0 ] ); unless ( $image && -r $image ) { $image = undef; } # hmm, this doesn't seem to work... :( #my $image = '/Applications/Utilities/Installer.app/Contents/Resources/Caut.tiff'; Mac::Growl::PostNotification( 'irssi', 'irssi', $subject, "($timestamp) $text", $sticky, $prio, $image ); # Mac::Growl::PostNotification( # 'irssi', # 'irssi', # $subject, # $text, # $sticky, # 1, # "/Applications/Utilities/Installer.app/Contents/Resources/Caut.tiff" # ); } # #__* /growl # # set, query, save, and load params to config file sub growl { my ( $command, @args ) = split( '\s+', $_[0] ); if ( $command eq 'config' ) { my $param = shift @args; $param = "$param"; unless ( defined( $config->{"$param"} ) ) { Irssi::print( "ERROR: config param $param not defined" ); return undef; } my $ref = ref $config->{$param}; if ( $ref eq "HASH" ) { my ( $subparam, $value ) = @args; if ( $value eq 'delete' ) { Irssi::print( "Deleting param $param->$subparam" ); delete $config->{$param}->{$subparam}; } else { Irssi::print( "Setting value for $param->$subparam to $value" ); $config->{$param}->{$subparam} = $value; } } else { my $value = shift @args; Irssi::print "Setting param $param to value $value"; $config->{$param} = $value; } } elsif ( $command eq 'dump' ) { my $dump = Data::Dumper->new( [ $config ] ); Irssi::print( $dump->Dump ); } elsif ( $command eq 'save' ) { Irssi::print( "Saving config file" ); YAML::DumpFile( $configfile, $config ); } elsif ( $command eq 'load' ) { Irssi::print( "Loading config file" ); $config = { %{ YAML::LoadFile( $configfile ) || {} }, }; } else { Irssi::print( "Usage: growl " ); Irssi::print( "\nAvailable Commands:" ); Irssi::print( "config set simple values" ); Irssi::print( "dump display the current config" ); Irssi::print( "save save the config to the config file" ); Irssi::print( "load load config stored in file. loses changes made since last save." ); Irssi::print( "\nValid config params:" ); Irssi::print( " private.enable = enable alerts for private messages" ); Irssi::print( " private.sticky = sticky alerts for private messages" ); Irssi::print( " hilight.enable = enable alerts for hilighted text" ); Irssi::print( " hilight.sticky = sticky alerts for hilighted text" ); Irssi::print( " public.channels #channelname sticky|nosticky" ); Irssi::print( "\nExamples:" ); Irssi::print( "/growl dump" ); Irssi::print( "/growl save" ); Irssi::print( "/growl load" ); Irssi::print( "/growl config private.enable 0" ); Irssi::print( "/growl config hilight.enable 1" ); Irssi::print( "/growl config hilight.sticky 1" ); Irssi::print( "/growl config public.channels #mychan sticky" ); Irssi::print( " messages to #mychan are enabled sticky" ); Irssi::print( "/growl config public.channels #mychan delete" ); } } Irssi::command_bind("growl", "growl"); # # #_* Private Subroutines # # # #__* supress duplicates # # Store the last several messages. If we get a duplicate message, # then avoid sending multiple pages. Duplicates occur when a message # matches more than one message, e.g. a public message in a monitored # channel that contains a hilighted word. sub _supress_duplicates { my ( $nick, $text, $sticky ) = @_; #Irssi::print( "Last seen: .$lastnick.:.$lasttext." ); # already alerted for this one if ( $lastnick && $nick eq $lastnick && $lasttext && $text eq $lasttext ) { # Message was already alerted. If this one is sticky and the # last one wasn't, then allow the alert to run again in sticky # mode. unless ( $sticky && ! $laststicky ) { return 1; } } $lastnick = $nick; $lasttext = $text; $laststicky = $sticky; # no match return undef; }