I use irssi/screen on a remote server to maintain a constant IRC presence and I wanted a nice way to pop up a pretty, on-screen notification when my nick is hilighted or when I get a direct message. Irssi already has Perl 5 scripting support built-in, so the rest just took a little whipuptitude.

Here is part of a screen shot of the result:

There were three things I needed to make it work:

Run a simple web service locally on my desktop machine that translates remote notification requests to the local notification daemon

Use reverse port forwarding in the ssh connection for my IRC session to connect a remote port to my local web service

Script irssi to listen for hilights and HTTP POST the message to the remote port

I’ll explain each piece step-by-step.

The web service 🔗︎

I wrote a trivially-simple Plack application that reads the text content of a POST, splits it into a summary line and a message and calls the command line notification program with the message. I use ‘notify-send’ because I use Ubuntu 11.10, but you could swap in a comparable program for your own operating system.

use v5.10; use strict; use warnings; use Plack::Request; my $icon = "/usr/share/notify-osd/icons/gnome/scalable/status/notification-message-im.svg"; sub _notify { my $content = shift; my ($summary, $body) = split "

", $content, 2; $summary //= "IRC"; $body //= ""; system("/usr/bin/notify-send", "-i", $icon, $summary, $body); } my $app = sub { my $req = Plack::Request->new(shift); _notify($req->raw_body); my $res = $req->new_response(200); return $res->finalize; };

I saved that as app.psgi and fired it up to listen on port 7877:

plackup -l localhost:7877 app.psgi

(Making that start automatically as part of your own login session is left as an exercise for the reader.)

Reverse port forwarding 🔗︎

I already had an alias to ssh to the server with my irssi/screen session, so I just had to modify it to add the reverse forwarding.

alias irc="ssh xdg@example.com -R 7877:localhost:7877"

Irssi scripting 🔗︎

I already had an irssi script to email me on highlights, so I adapted that to make a web request instead. It has two configuration options: a cooldown delay between messages and a url for messages.

I savid it as ‘purr_notify.pl’, which you can also get from my irssi scripts repo.

use strict; use vars qw($VERSION %IRSSI); use Irssi; $VERSION = '0.0.1'; %IRSSI = ( authors => 'David Golden', contact => 'dagolden@cpan.org', name => 'purr_notify', description => 'Send a purr when someone is talking to you in some channel.', url => 'https://github.com/dagolden/irssi-scripts/blob/master/purr_notify.pl', license => 'Apache License 2.0', changed => 'Sun Feb 15 22:54:27 EST 2012' ); #-------------------------------------------------------------------- # In parts based on fnotify.pl 0.0.3 by Thorsten Leemhuis # http://www.leemhuis.info/files/fnotify/ # In parts based on knotify.pl 0.1.1 by Hugo Haas # http://larve.net/people/hugo/2005/01/knotify.pl # which is based on osd.pl 0.3.3 by Jeroen Coekaerts, Koenraad Heijlen # http://www.irssi.org/scripts/scripts/osd.pl # Other parts based on notify.pl from Luke Macken # http://fedora.feedjack.org/user/918/ #-------------------------------------------------------------------- #-------------------------------------------------------------------- # Configuration handling #-------------------------------------------------------------------- my %CONFIG; sub load_config { %CONFIG = ( url => Irssi::settings_get_str("$IRSSI{name}_url"), cooldown => Irssi::settings_get_int("$IRSSI{name}_cooldown"), ); if ( ! length $CONFIG{url} ) { $CONFIG{url} = "http://localhost:7877/"; Irssi::print("$IRSSI{name} setting '$IRSSI{name}_port' defaulting to $CONFIG{url}"); } if ( $CONFIG{cooldown} < 0 ) { $CONFIG{cooldown} = 120; Irssi::print("$IRSSI{name} setting '$IRSSI{name}_cooldown' defaulting to $CONFIG{cooldown}"); } } #-------------------------------------------------------------------- # Handle private messages #-------------------------------------------------------------------- my %last_priv_from; sub priv_msg { my ($server,$msg,$nick,$address,$target) = @_; if ( time - ($last_priv_from{$nick} || 0 ) > $CONFIG{cooldown} ) { $last_priv_from{$nick} = time; _send_purr($nick => $msg); } } #-------------------------------------------------------------------- # Handle public hilights #-------------------------------------------------------------------- my %last_hilight_from; sub hilight { my ($dest, $text, $stripped) = @_; my ($channel, $level) = ($dest->{target}, $dest->{level}); if ($level & MSGLEVEL_HILIGHT) { if ( time - ($last_hilight_from{$channel} || 0 ) > $CONFIG{cooldown} ) { $last_hilight_from{$channel} = time; _send_purr($channel => $stripped); } } } #-------------------------------------------------------------------- # Send notification message #-------------------------------------------------------------------- sub _send_purr { system("/usr/bin/curl", $CONFIG{url}, "-s", "-d", join("

",@_)); } #-------------------------------------------------------------------- # Hook into irssi settings and signals #-------------------------------------------------------------------- Irssi::settings_add_str($IRSSI{name}, "$IRSSI{name}_url", ''); Irssi::settings_add_int($IRSSI{name}, "$IRSSI{name}_cooldown", -1); load_config(); Irssi::signal_add_last("message private", \&priv_msg); Irssi::signal_add_last("print text", \&hilight); Irssi::signal_add_last("setup changed", \&load_config);

You might note that ‘curl’ is running silent with ‘-s’ so it won’t give errors trying to notify when the ssh connection is down.