#!/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); } } }