#!/usr/bin/perl -w
# $Id: presence_monitor.pl 360 2003-12-26 09:28:09Z ralphm $
use strict;
use open ':utf8';
use Jabber::Connection;
use Jabber::NodeFactory;
use Jabber::NS qw(:all);
use DBI;
use XML::Simple;
use Getopt::Long;
use Data::Dumper;
my %optctl = ();
$optctl{config} = "";
&GetOptions(\%optctl, "config=s");
$optctl{config} = undef unless ($optctl{config} ne "");
my $config = XMLin($optctl{config});
my $nf = new Jabber::NodeFactory;
# Create a new db connection
my ($dbh, $sth);
&db_connect;
# Reset all presence entries
$dbh->do(
"UPDATE ".$config->{database}->{table}." set ".
"type='unavailable', show='', status='', priority=0, ".
"music_title='', music_state='' where type='available'");
# Update process list entry
$dbh->do("DELETE FROM process_list WHERE name='".$config->{process}->{name}."'");
$dbh->do("INSERT INTO process_list (name, pid) VALUES ('".$config->{process}->{name}."', $$)");
# Open connection to Jabber server
my $c = new Jabber::Connection(
server => $config->{jabber}->{server},
log => 1,
debug => 1,
);
$c->connect or die "oops: ".$c->lastError;
# Register various handlers
$c->register_handler('presence', \&presence);
# Identify and authenticate with the server
$c->auth($config->{jabber}->{username},
$config->{jabber}->{password},
$config->{jabber}->{resource});
# Request roster
$c->send('');
# Send presence
$c->send('');
# Start processing loop
$c->start();
#
# db_connect - connect to the database
#
sub db_connect {
$dbh = DBI->connect("dbi:Pg:dbname=".$config->{database}->{name})
or die "Cannot connect to database ($!)\n";
}
#
# getdata - return the data inside the element with name $name or empty
#
sub getdata {
my $node = shift;
my $name = shift;
my $tag;
return ($tag = $node->getTag($name)) ? $tag->data : "";
}
#
# presence - store incoming presence information in the database
#
sub presence {
my ($fulljid, $jid, $resource, $status, $type, $priority, $show, $music, $title, $state);
my $node = shift;
my $sth;
my $row;
my $exists;
# extract information from the presence packet
$fulljid = $node->attr('from');
$fulljid =~ /^([^\/]+)(\/(.*))?$/;
$jid = $1;
$jid = lc($jid);
$resource = $3? $3 : "";
$type = $node->attr('type') ? $node->attr('type') : "available";
# auto subscribe/unsubscribe
my $new_node;
if ($type eq 'subscribe') {
print "Received subscription request from $jid\n";
$new_node = $nf->newNode('presence');
$new_node->attr('to', $jid);
$new_node->attr('type', 'subscribed');
$c->send($new_node);
# return the favour
$new_node->attr('type', 'subscribe');
$c->send($new_node);
return;
} elsif ($type eq 'unsubscribe') {
print "Received unsubscription request from $jid\n";
$new_node = $nf->newNode('presence');
$new_node->attr('to', $jid);
$new_node->attr('type', 'unsubscribed');
$c->send($new_node);
# return the favour
$new_node->attr('type', 'unsubscribe');
$c->send($new_node);
return;
} elsif ($type ne 'available' and $type ne 'unavailable') {
return;
}
$status = getdata($node, 'status');
$priority = getdata($node, 'priority');
if (!$priority) {
$priority = 0;
}
$show = getdata($node, 'show');
$music = $node->getTag('x', 'gabber:x:music:info');
print STDERR "Received presence: \n";
print STDERR " JID --> ", $jid, "\n";
print STDERR " Resource --> ", $resource, "\n";
print STDERR " Status --> ", $status, "\n";
print STDERR " Type --> ", $type, "\n";
print STDERR " Priority --> ", $priority, "\n";
print STDERR " Show --> ", $show, "\n";
if ($music) {
$title = getdata($music, 'title');
$state = getdata($music, 'state');
print STDERR " Music --> ",
ucfirst($state), ": ", $title, "\n";
}
print STDERR "\n";
# check if we still have a valid database connection
$dbh->ping or &db_connect;
# check if there already is an entry with the same jid/resource combination
$sth = $dbh->prepare("SELECT jid, resource, type FROM ".
$config->{database}->{table}." ".
"WHERE jid=? AND resource=?");
$sth->execute($jid, $resource );
$exists = 0;
if ( $row = $sth->fetchrow_hashref ) {
$exists = 1;
}
# PRESENCE TABLE UPDATE
# prepare database query
if ( $exists ) {
my $id = ' ';
if ( $row->{type} eq 'unavailable' ) {
$id = '"id" = nextval(\'presences_test_id_seq\'), ';
}
# update the presence information and assign a fresh id
$sth = $dbh->prepare(
'UPDATE '.
$config->{database}->{table}." ".
'SET "type"=?, "status"=?, "priority"=?, "show"=?, '.
'"music_title"=?, "music_state"=?, '.
$id.
'"last_updated"=CURRENT_TIMESTAMP '.
'WHERE jid=? AND resource=?'
);
} else {
# insert a new record with the presence information
$sth = $dbh->prepare(
'INSERT INTO '.
$config->{database}->{table}." ".
'("type", "status", "priority", "show", "music_title", '.
'"music_state", "jid", "resource") '.
'VALUES (?, ?, ?, ?, ?, ?, ?, ?)'
);
}
# execute the actual query
$sth->execute($type, $status, $priority, $show, $title, $state, $jid, $resource);
# ROSTER TABLE UPDATE
$sth = $dbh->prepare("SELECT jid, id from ".
$config->{database}->{table}." ".
"where jid=? ".
"order by type, priority desc, ".
"(case when type='available' then id else 0 end), ".
"last_updated desc");
$sth->execute($jid);
if ( $row = $sth->fetchrow_hashref) {
$jid = $row->{jid};
my $id = $row->{id};
$sth = $dbh->prepare("UPDATE roster_test set id=? where jid=?");
my $affected_rows = $sth->execute($id, $jid);
if ($affected_rows < 1) {
$sth = $dbh->prepare("INSERT INTO roster_test (jid, id) VALUES (?, ?)");
$sth->execute($jid, $id);
}
}
}