domenica 19 agosto 2012

Un semplice ed efficiente GMail notifier grazie a Perl e Cron :-)

Esistono vari programmi e applet per GNU/Linux che ci consentono di monitorare la nostra posta su Gmail; tutti però richiedono ovviamente di restare in esecuzione, andando quindi ad impegnare costantemente una parte delle risorse del nostro sistema ... e tutto questo solo per notificarci la presenza di eventuali nuove mail!

In questo articolo vi illustro un piccolo programma che ho scritto in perl  e progettato per essere eseguito tramite cron: il vantaggio rispetto alle implementazioni "classiche" è che il consumo di risorse è veramente minimo dal momento che, come dicevo, il programma viene lanciato all'intervallo prefissato da cron e terminato una volta completato il controllo della nostra posta su gmail. Non c'è quindi un impegno costante di risorse: terminato il controllo, il programma viene chiuso e la memoria completamente rilasciata.

Per chi fosse interessato a provare questa soluzione, riporto qui di seguito le istruzioni per l'installazione e la configurazione, facendo riferimento ad Arch Linux; lo script è comunque utilizzabile su qualunque distro.

Iniziamo con l'installare i moduli perl necessari:

# pacman -S perl-file-slurp perl-lwp-protocol-https
$ yaourt -S perl-gtk2-notify

Dando per scontato che abbiate cron (o una delle sue varianti) e dbus attivi, dovete verificare che il DE/WM che utilizzate fornisca una gestore di notifiche; i progetti maggiori come KDE, GNOME, XFCE, ecc. soddisfano questo requisito, mentre se utilizzate LXDE o WM tipo openbox, fluxbox ecc. molto probabilmente non avrete nessun gestore di notifiche installato.
Se rientrate in quest' ultima categoria potete risolvere il problema installando notification-daemon:

# pacman -S notification-daemon

e piazzarne l'eseguibile ( /usr/lib/notification-daemon-1.0/notification-daemon ) tra i programmi da lanciare all'avvio del vostro desktop.

Occupiamoci ora del programma vero e proprio: copiamo il seguente codice all'interno di un file di testo che chiameremo pgmail.pl e salviamo il file da qualche parte nella nostra home, per esempio in ~/bin :


#!/usr/bin/perl
# pgmail - gmail checker in perl

use strict;
use warnings;
use LWP;
use File::Slurp;
use Gtk2::Notify -init, $0;
use autodie;
use Env 'DBUS_SESSION_BUS_ADDRESS';

my $USER = 'user';
my $PASS = 'password';
my $ICON = 'checkgmail';

my $TMP_FILE = "/tmp/tmp_gmail_${USER}";

my $browser = LWP::UserAgent->new();
$browser->timeout(30);

my $req = HTTP::Request->new(GET => 'https://mail.google.com/mail/feed/atom');
$req->authorization_basic($USER, $PASS);
my $resp = $browser->request($req, $TMP_FILE);
die ':: oops, got error <', $resp->status_line, ">, exiting ...\n" unless $resp->is_success;

my @file = read_file( $TMP_FILE );
my ($MESSAGE, $TITLE);

for (@file)
{
        if($_ =~ /<fullcount>(?<mail_count>\d+)/)
        {
                if ($+{mail_count} == 0)
                {
                        unlink $TMP_FILE;
                        exit;
                }
                else{
                        $TITLE = "($+{mail_count}) Nuovi messaggi su GMail!";
                }
        }
        if ($_ =~ /<title>(?<subject>.*)<\/title>/)
        {
                $MESSAGE = $MESSAGE .  "\nOggetto: $+{subject}\n" unless
                ($+{subject} eq "Gmail - Inbox for ${USER}\@gmail.com");
        }
        if ($_ =~ /<email>(?<from>.*)<\/email>/)
        {
                $MESSAGE = $MESSAGE . "Da: $+{from}\n";
        }
}

$DBUS_SESSION_BUS_ADDRESS = get_dbus_address();
if (!$DBUS_SESSION_BUS_ADDRESS)
{
    die ":: Unable to set DBUS_SESSION_BUS_ADDRESS!\n";
}

my $notification = Gtk2::Notify->new($TITLE, $MESSAGE, $ICON) ;
$notification->show;

unlink $TMP_FILE;

sub get_dbus_address
{
    my $PROGRAM = 'kwin';
    my $PIDOF_PATH ='/bin/pidof';

    my $pid = qx[$PIDOF_PATH -s $PROGRAM];
    die qq{:: "${PROGRAM}" isn't running!\n} unless $pid;
    chomp $pid;
    my $environ = read_file("/proc/${pid}/environ");
    my @lines = split( chr(0), $environ );

    for (@lines)
    {
            if ($_ =~ /DBUS_SESSION_BUS_ADDRESS=(.+)/)
            {
                    return $1;
            last;
            }   
    }   
    return undef;
}


Come potete vedere, non sono che poche righe di codice; del resto le operazioni che il nostro script deve compiere sono in effetti solo quelle di verificare la presenza di nuovi messaggi e inviarci una notifica in caso positivo :-)

Una volta salvato il file, rendiamolo accessibile unicamente al nostro utente, dal momento che in esso sono conservate le nostre credenziali di accesso a gmail ( dati personali molto importanti che quindi devono restare riservati ) :

$ chmod 700 ~/bin/pgmail.pl

In grassetto blu ho evidenziato le variabili che dovrete andare obbligatoriamente a cambiare per far girare lo script correttamente:

my $USER = 'user';
sostituite 'user' con il vostro "Nome utente" gmail senza '@gmail.com'. Non dimenticatevi gli apici e il punto e virgola finale! 

my $PASS = 'password';
sostituite 'password' con la reale password del vostro account gmail, sempre tra apici; il punto e virgola chiude la riga.

my $ICON = 'checkgmail';
l'icona che verrà mostrata nella notifica; potete utilizzare qualunque file .png, .xpm o .svg presente nelle cartelle ( e relative sottocartelle ) /usr/share/icons e /usr/share/pixmaps.  Nel caso inseriate un nome sbagliato o di un file inesistente, semplicemente la notifica non visualizzerà alcuna immagine. Potete anche specificare l'immagine da utilizzare, scrivendone il percorso completo, ad es:
my $ICON = '/usr/share/icons/hicolor/48x48/apps/firefox.png';

my $PROGRAM = 'kwin'; 
arriviamo alla variabile più problematica; per inviare correttamente la notifica il programma deve conoscere  l'indirizzo della sessione dbus attiva. Il modo più "semplice" per ottenere tale informazione è quella di accedere, tramite il filesystem speciale /proc, al file environ relativo ad un'applicazione grafica in esecuzione. Semplificando ulteriormente, la variabile $PROGRAM deve contenere il nome di un processo grafico che viene lanciato automaticamente ogni qualvolta avviate il vostro DE/WM.
Se siete su KDE potere lasciare tranquillamente impostato 'kwin'; gli utenti LXDE potranno invece utilizzare, ad esempio, 'lxpanel'; 'xfce4-panel' è perfetto per gli utenti XFCE. Se avete dei (comprensibilissimi :-) ) dubbi sul processo da impostare, fate così:

Avviate il vostro desktop, quindi da un terminale lanciate:

$ ps -u <vostro user> 

per ottenere un elenco dei processi in esecuzione. Purtroppo, non tutto quello che vi viene mostrato qui può andare bene per i nostri scopi; dopo aver esaminato l'ultima variabile che ci resta, vi illustrerò come verificare l'idoneità del processo scelto. 
        
my $PIDOF_PATH ='/bin/pidof'; 
Il percorso dell'eseguibile pidof. Se state utilizzando Arch Linux non avete bisogno di modificare niente. In caso contrario dovete verificare l'esatto percorso di pidof che può cambiare da distro a distro; per esempio su Fedora il path è /usr/sbin/pidof. Date semplicemente:

$ which pidof

per localizzare il percorso corretto sulla vostra distro.
Ok, a questo punto abbiamo completato la configurazione, non ci resta che testare il corretto funzionamento del programma.
Assicuriamoci di avere almeno un messaggio non letto nella nostra casella di posta gmail e simuliamo l'avvio dello script tramite cron in questo modo:

$ env -i DISPLAY=:0 /home/<vostro user>/bin/pgmail.pl

Se non sono stati commessi errori nella precedente fase, verrà visualizzata una notifica con il numero di messaggi non letti, mostrando per ciascuno di essi l'oggetto e la mail del destinatario.
Se la notifica non compare e il terminale riporta l'errore:

Unable to set DBUS_SESSION_BUS_ADDRESS!

significa che avete immesso una voce sbagliata in corrispondenza della variabile $PROGRAM.
Se invece il messaggio di errore è il seguente:

Gtk-WARNING **: cannot open display: :0 at /usr/lib/perl5/vendor_perl/Gtk2/Notify.pm line 23.

modificate e ripetete il comando precedente così:

$ env -i DISPLAY=:0 XAUTHORITY=/home/<vostro user>/.Xauthority /home/<vostro user>/bin/pgmail.pl

Una volta corretti eventuali errori, l'ultimo passo è quello di creare un cronjob per automatizzare l'esecuzione del nostro script; digitiamo in un terminale:

$ crontab -e

se è la prima volta che inserite un cronjob vi apparirà  un file del tutto vuoto.
Di default viene utilizzato Vi come editor ma se non lo conoscete potete specificare un programma alternativo settando la variabile EDITOR prima di lanciare il comando 'crontab -e'. Per esempio:

$ export EDITOR="/usr/bin/nano"

Aperto il nostro crontab, inseriamo la seguente regola:

*/15 * * * * export DISPLAY=:0; /home/<vostro user>/bin/pgmail.pl

Salvate e chiudete il file: l'operazione inserita sarà attiva da subito.
"*/15" significa che la posta verrà controllata ogni 15 minuti; siete ovviamente liberi di cambiare questo parametro a vostro piacimento.
Se invece volete, ad esempio, che il controllo venga fatto solo una volta ogni ora potete modificare il cronjob in questo modo:

01 * * * * export DISPLAY=:0; /home/<vostro user>/bin/pgmail.pl

Il programma verrà così avviato al primo minuto di ogni ora: 12:01, 13:01 e così via.

È tutto: se siete riusciti a seguire tutte le istruzioni senza perdervi  avrete ora attivo sul vostro sistema uno strumento super-efficiente per monitorare la vostra casella di posta gmail :-)

Aggiornamento del 17/07/14
Ho riscritto parte del codice utilizzando il modulo XML::Simple, potete prelevare la versione aggiornata da qui 

Nessun commento:

Posta un commento