Skip to content
 

Yet another way to get Irssi notifications on your Linux desktop

For a better solution, see this article – I am keeping this post online because it makes it possible to implement distributed notifications with Perl modules included in the Ubuntu repositories.

One of the things lacking (in my opinion at least) when using Irssi and GNU Screen is the lack of a way for Irssi to alert you when you are not looking at the terminal.

I have looked at many implementations for libnotify (default in Ubuntu), Mumbles (Growl for Linux) and Dzen.

Some of the things I have looked at

  • thl’s irssi notification script aka fnotify
    Most of this is actually quite good and has formed the basis for my implemenation. Uses libnotify.
  • Using irssi with libnotify over Secure Shell
    A different implementation of the above, using xterm’s print facility to send data to libnotify.
  • irssi-libnotify
    Uses notify-send on the same machine as irssi, requires X-forwarding (which is a bitch with screen). I liked this but as it uses X-Windows on the remote server the notifications might not match those of your desktop
  • Dzen notifications
    This is where I got the idea for using a named pipe
  • Mumbles
    I used this before libnotify became standard in Ubuntu. It was hard to make it work and required several (Python) daemon running to forward the notifications.

Since I have several machines I use to access my server where Irssi is running none of the other implementations I looked at really worked since I need to be sure that all machines get the notifications. In the end I decided to use MySQL as a “proxy” for the notifications.

Prepare the MySQL database

It’s a good idea to set up a separate database – just in case one of the scripts f*ck up and deletes everything.

$ sudo mysqladmin -u root -p create irssi
mysql> use irssi
Database changed
mysql> CREATE TABLE `notify` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `summary` varchar(64) CHARACTER SET utf8 NOT NULL,
  `message` varchar(255) CHARACTER SET utf8 NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM;
mysql> GRANT ALL ON irssi.* TO 'irssi'@'localhost' IDENTIFIED BY 'Password';

Installing the Irssi script

It is also possible to simply create a table inside an existing database; just adjust the configuration values in Irssi.

The Irssi script is based on Jared Quins work (which in turn is based on irssi-libnotify). The basic idea is the same as with fnotify but instead of writing to a temporary file I write to a MySQL database.

## Put me in ~/.irssi/scripts, and then execute the following in irssi:
##
##       /load perl
##       /script load notify
##

use strict;
use Irssi;
use vars qw($VERSION %IRSSI);
use HTML::Entities;
use DBI;
use utf8;

$VERSION = "0.01";
%IRSSI = (
    authors     => 'Allan Willems Joergensen',
    origauthors => 'Luke Macken, Paul W. Frields, Jared Quinn',
    contact     => 'allan@nowhere,dk',
    name        => 'notifier.pl',
    description => 'Use libnotify to alert the user of new messages or hilights (Using MySQL as "proxy")',
    license     => 'GNU General Public License',
    url         => 'http://www.nowhere.dk/articles/irssi-notification',
);

Irssi::settings_add_str('notifier','notifier_mysql_user', 'irssi');
Irssi::settings_add_str('notifier','notifier_mysql_password', 'changeme');
Irssi::settings_add_str('notifier','notifier_mysql_host', 'localhost');
Irssi::settings_add_str('notifier','notifier_mysql_db', 'irssi');

sub write2db {
        my $db_user = Irssi::settings_get_str('notifier_mysql_user');
        my $db_pass = Irssi::settings_get_str('notifier_mysql_password');
        my $db_host= Irssi::settings_get_str('notifier_mysql_host');
        my $db_name = Irssi::settings_get_str('notifier_mysql_db');
        my ($summary, $message) = @_;
        my $dsn = "dbi:mysql:dbname=$db_name;host=$db_host";
        my $dbh = DBI->connect($dsn, $db_user, $db_pass) || die "DB connect failed";

        my $sth = $dbh->prepare("INSERT INTO notify (summary, message) VALUES (?, ?)")
            or die "Can't prepare statement: $?";
        $sth->execute($summary, $message) or die "Couldn't execute INSERT: $?";

        $dbh->disconnect;
}


sub notify {
    my ($server, $summary, $message) = @_;
    my $safemsg = HTML::Entities::encode($message, '<>&"');
    my $utf8msg = utf8::encode($safemsg);

    write2db($summary, $safemsg);
}

sub print_text_notify {
    my ($dest, $text, $stripped) = @_;
    my $server = $dest->{server};
    return if (!$server || !($dest->{level} & MSGLEVEL_HILIGHT));
    my $sender = $stripped;
    $sender =~ s/^\<.([^\>]+)\>.+/\1/ ;
    $stripped =~ s/^\<.[^\>]+\>.// ;
    my $summary = "Hilite in " . $dest->{target};
    notify($server, $summary, $stripped);
}


sub message_private_notify {
    my ($server, $msg, $nick, $address) = @_;
    return if (!$server);
    notify($server, "Private message from ".$nick, $msg);
}

sub dcc_request_notify {
    my ($dcc, $sendaddr) = @_;
    my $server = $dcc->{server};

    return if (!$dcc);
    notify($server, "DCC ".$dcc->{type}." request", $dcc->{nick});
}

Irssi::signal_add('print text', 'print_text_notify');
Irssi::signal_add('message private', 'message_private_notify');
Irssi::signal_add('dcc request', 'dcc_request_notify');

Download the script to ~/.irssi/scripts and rename it to notifier.pl.

If you want it to load automatically, symlink it to ~/.irssi/scripts/autorun
$ ln -sf ~/.irssi/scripts/notifier.pl ~/.irssi/scripts/autorun/notifier.pl

Load the script inside irssi
/script load notifier.

Once you have loaded the script, set these variables inside Irssi (adjust according to your setup)

/set notifier_mysql_db irssi
/set notifier_mysql_host localhost
/set notifier_mysql_user irssi
/set notifier_mysql_password Password

Setup MySQL port forwarding

It is possible to use autossh to automatically setup the tunnel but since I am always connected to my server (at least when I am in front of a computer) I chose to use normal ssh port forwarding.

In ~/.ssh/config I have

Host my.server.bogus
        LocalForward 13306 localhost:3306

The stuff running on your local machine

That is, the stuff that actually shows the notifications

I did not want to bother trying to make the MySQL-stuff error proof so I simply call the Perl script from a shell script like so

#!/bin/bash

wait=0
while true
 do
    $HOME/bin/irssi-notify-client.pl

    let wait=$wait+5
    if [ $wait -ge 30 ]
     then
        sleep 30
    else
        sleep $wait
    fi
done

Save the script as ~/bin/start-irssi-notify-client.sh

The Perl script requires DBI and Desktop::Notify – Both are available in Ubuntu

$ sudo install libdesktop-notify-perl libdbd-mysql-perl
#!/usr/bin/perl

use strict;
use warnings;
use DBI;
use Desktop::Notify;

my $last = 0;
my $loops = 0;
my $notify_timeout = 2000;
my $icon = "gnome-irc.png";

sub mysql_connect {
    my $db_user = "irssi";
    my $db_pass = "Password";
    my $db_host = "127.0.0.1:13306";
    my $db_name = "irssi";
    my $dsn = "dbi:mysql:dbname=$db_name;host=$db_host";
    my $dbh = DBI->connect($dsn, $db_user, $db_pass) or die "DB connect failed";

    return($dbh);
}

while (1) {
    my $dbh = mysql_connect();

    if ($last == 0) {
        my $sth_state = $dbh->prepare("SELECT MAX(id) FROM notify");
        $sth_state->execute() or die "Unable execute query: $dbh->err, $dbh->errstr\n";
        $last = ($sth_state->fetchrow_array)[0];
        $sth_state->finish();
    }

    my $sth = $dbh->prepare("SELECT id,time,summary,message FROM notify WHERE id > ? ORDER BY id ASC LIMIT 0,10");
    $sth->execute($last) or die "Unable execute query:$dbh->err, $dbh->errstr\n";

    if ($sth->rows > 0) {
        my $notify = Desktop::Notify->new();
        my $notification = $notify->create(timeout => $notify_timeout, app_icon => $icon);
        while (my $ref = $sth->fetchrow_hashref()) {
       
            my $id = $ref->{'id'};
            my $summary = $ref->{'summary'};
            my $message = $ref->{'message'};
           
            $notification->summary($summary);
            $notification->body($message);
            $notification->show();

            $last = $id;
            sleep 1;

        }
        $notification->close();
    }

    $sth->finish();
   
    # Clean up once in a while. This is not really essential so we simply
    # do it once every 1000 iterations
    $loops++;
    if ($loops > 1000) {
        my $sth_cleanup = $dbh->prepare("DELETE FROM notify WHERE id < ?");
        $sth_cleanup->execute($last);
        $sth_cleanup->finish();
    }

    $dbh->disconnect;

    sleep 5;
}

Save the script to ~/bin/irssi-notify-client.pl.

Remember to make both scripts executable.

The final thing to do is to add the notify client to your desktop environment’s autostart

In GNOME: System -> Preferences -> Startup Applications

Add Startup Program

Add Startup Program

Related posts:

  1. Irssi notifications using Desktop Notifications and Minivan I was pretty happy with solution to get notifications from...
  2. Irssi notifications in Windows using Growl and Minivan After completing my script to deliver Irssi notifications to the...
  3. Using ISO-8859-15 encoding with Twirssi Since I run irssi all the time, packing as many...
  4. Facebook Chat in bitlbee Facebook now supports XMPP. Yay. Using Facebook Chat in bitlbee...

Related posts brought to you by Yet Another Related Posts Plugin.

2 Comments

  1. Jared Quinn says:

    I like where you have taken my implementation. Nice work.

  2. [...] was pretty happy with solution to get notifications from Irssi though it had some [...]

Leave a Reply