package Jabber::PubSub::JEAI; use 5.008003; use strict; use warnings; require Exporter; use AutoLoader qw(AUTOLOAD); our @ISA = qw(Exporter); # Items to export into callers namespace by default. Note: do not export # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. # This allows declaration use Jabber::PubSub::JEAI ':all'; # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK # will save memory. our %EXPORT_TAGS = ( 'all' => [ qw( ) ] ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); our @EXPORT = qw( ); our $VERSION = '0.03'; # Preloaded methods go here. # Autoload methods go after =cut, and are processed by the autosplit program. use Net::Jabber qw(Client); sub create_channel{ my $p = shift; my ($uid,$pwd,$host,$port,$resource) = &conn_info($p); my $timestamp = time; my ($channel,$to,$iq_id,$payload); unless (defined $p->{'to'}){ warn "Missing service name: using pubsub.localhost instead."; $to = 'pubsub.localhost'; }else{ $to = $p->{'to'}||'pubsub.localhost'; } unless (defined $p->{'iq_id'}){ warn "Missing IQ ID: using default."; $iq_id = 'creating_on_'.$timestamp; }else{ $iq_id = $p->{'iq_id'}||'creating_on_'.$timestamp; } unless (defined $p->{'channel'}){ die "Missing channel name."; }else{ $channel = $p->{'channel'}; } my ($Jabber,$vCard,@connect); eval{ $Jabber = Net::XMPP::Client->new(); $Jabber->Connect( hostname => $host, port => $port, ); @connect = $Jabber->AuthSend( username => $uid, password => $pwd, resource => $resource, ); }; die $! if($@); if ($connect[0] ne "ok") { die "Ident/Auth with server failed: $connect[0] - $connect[1]\n"; }else{ print "User $uid is connected to Jabber server $host on port $port...\n"; } my $xml = qq| |; eval{ $vCard = new Net::Jabber::IQ(); $vCard->SetIQ(type=>'set', to=>$to, id=> $iq_id); $vCard->InsertRawXML($xml); $Jabber->Send($vCard); }; die $! if($@); print "User $uid has ordered to create pub/sub channel $channel.\n"; 1; } sub delete_channel{ my $p = shift; my ($uid,$pwd,$host,$port,$resource) = &conn_info($p); my $timestamp = time; my ($channel,$to,$iq_id,$payload); unless (defined $p->{'to'}){ warn "Missing service name: using pubsub.localhost instead."; $to = 'pubsub.localhost'; }else{ $to = $p->{'to'}||'pubsub.localhost'; } unless (defined $p->{'iq_id'}){ warn "Missing IQ ID: using default."; $iq_id = 'deleting_on_'.$timestamp; }else{ $iq_id = $p->{'iq_id'}||'deleting_on_'.$timestamp; } unless (defined $p->{'channel'}){ die "Missing channel name."; }else{ $channel = $p->{'channel'}; } my ($Jabber,$vCard,@connect); eval{ $Jabber = Net::XMPP::Client->new(); $Jabber->Connect( hostname => $host, port => $port, ); @connect = $Jabber->AuthSend( username => $uid, password => $pwd, resource => $resource, ); }; die $! if($@); if ($connect[0] ne "ok") { die "Ident/Auth with server failed: $connect[0] - $connect[1]\n"; }else{ print "User $uid is connected to Jabber server $host on port $port...\n"; } my $xml = qq| |; eval{ $vCard = new Net::Jabber::IQ(); $vCard->SetIQ(type=>'set', to=>$to, id=> $iq_id); $vCard->InsertRawXML($xml); $Jabber->Send($vCard); }; die $! if($@); print "User $uid has ordered to delete pub/sub channel $channel.\n"; 1; } sub subscribe { my $p = shift; my ($uid,$pwd,$host,$port,$resource) = &conn_info($p); my $timestamp = time; my ($channel,$to,$iq_id,$payload); unless (defined $p->{'to'}){ warn "Missing service name: using pubsub.localhost instead."; $to = 'pubsub.localhost'; }else{ $to = $p->{'to'}||'pubsub.localhost'; } unless (defined $p->{'iq_id'}){ warn "Missing IQ ID: using default."; $iq_id = 'subscribing_on_'.$timestamp; }else{ $iq_id = $p->{'iq_id'}||'subscribing_on_'.$timestamp; } unless (defined $p->{'channel'}){ die "Missing channel name."; }else{ $channel = $p->{'channel'}; } my ($Jabber,$vCard,@connect); eval{ $Jabber = Net::XMPP::Client->new(); $Jabber->Connect( hostname => $host, port => $port, ); @connect = $Jabber->AuthSend( username => $uid, password => $pwd, resource => $resource, ); }; die $! if($@); if ($connect[0] ne "ok") { die "Ident/Auth with server failed: $connect[0] - $connect[1]\n"; }else{ print "User $uid is connected to Jabber server $host on port $port...\n"; } eval{ my $xml = qq| |; $vCard = new Net::Jabber::IQ(); $vCard->SetIQ(type=>'set', to=>$to, id=> $iq_id); $vCard->InsertRawXML($xml); $Jabber->Send($vCard); }; die $! if($@); print "User $uid has ordered to subscribe to channel $channel.\n"; 1; } sub publish { my $p = shift; my ($uid,$pwd,$host,$port,$resource) = &conn_info($p); my $timestamp = time; my ($channel,$to,$iq_id,$payload); unless (defined $p->{'to'}){ warn "Missing service name: using pubsub.localhost instead."; $to = 'pubsub.localhost'; }else{ $to = $p->{'to'}||'pubsub.localhost'; } unless (defined $p->{'iq_id'}){ warn "Missing IQ ID: using default."; $iq_id = 'publishing_on_'.$timestamp; }else{ $iq_id = $p->{'iq_id'}||'publishing_on_'.$timestamp; } unless (defined $p->{'channel'}){ die "Missing channel name."; }else{ $channel = $p->{'channel'}; } unless (defined $p->{'payload'}){ die "Missing payload." }else{ $payload = $p->{'payload'}; } my ($Jabber,$vCard,@connect); eval{ $Jabber = Net::XMPP::Client->new(); $Jabber->Connect( hostname => $host, port => $port, ); @connect = $Jabber->AuthSend( username => $uid, password => $pwd, resource => $resource, ); }; die $! if($@); if ($connect[0] ne "ok") { die "Ident/Auth with server failed: $connect[0] - $connect[1]\n"; }else{ print "User $uid is connected to Jabber server $host on port $port...\n"; } eval{ my $xml = qq| $payload |; $vCard = new Net::Jabber::IQ(); $vCard->SetIQ(type=>'set', to=>$to, id=> $iq_id); $vCard->InsertRawXML($xml); my $res = $Jabber->Send($vCard); }; die $! if($@); print "User $uid has sent a message to channel $channel.\n"; 1; } sub listen { my $p = shift; my ($uid,$pwd,$host,$port,$resource) = &conn_info($p); my $timestamp = time; my ($channel,$to,$iq_id,$payload); my ($Jabber,$Presence, @connect); eval{ $Jabber = Net::XMPP::Client->new(); $Presence = Net::XMPP::Presence->new(); $Jabber->Connect( hostname => $host, port => $port, ); @connect = $Jabber->AuthSend( username => $uid, password => $pwd, resource => $resource, ); }; die $! if($@); if ($connect[0] ne "ok") { die "Ident/Auth with server failed: $connect[0] - $connect[1]\n"; }else{ print "User $uid is connected to Jabber server $host on port $port...\n"; } $Presence->SetType("available"); $Presence->SetStatus("Ask me! Ask me, now!"); $Jabber->Send($Presence); $Jabber->SetCallBacks(message=>\&handle_message, presence=>\&handle_presence, iq=>\&handle_iq,); my $lookups = 0; my $max_lookups = 10; while (defined($Jabber->Process())) { my $current_type = $Presence->GetType(); if (($lookups >= $max_lookups) && ($current_type ne "unavailable")) { $Presence->SetType("unavailable"); $Presence->SetStatus("I am helping someone else right now."); $Jabber->Send($Presence); } if ( ($lookups < $max_lookups) && ($current_type ne "available")) { $Presence->SetType("available"); $Presence->SetStatus("Ask me! Ask me, now!"); $Jabber->Send($Presence); } } 1; } sub handle_message { shift; my $msg = shift->GetX(); my $item = $msg->{TREE}->{CHILDREN}->[0]->{CHILDREN}->[0]->{CHILDREN}->[0]->{CHILDREN}->[0]; print $item,"\n"; return $item; } sub handle_presence { print Dumper(\@_); return \@_; } sub handle_iq { print Dumper(\@_); return \@_; } sub conn_info { my $p = shift; die "Missing input param." unless(defined $p); my ($uid,$pwd,$host,$port,$resource,$channel,$to,$iq_id,$payload); my $timestamp = time; unless (defined $p->{'uid'}){ die "Missing ID of the channel owner."; }else{ $uid = $p->{'uid'}; } unless (defined $p->{'pwd'}){ die "Missing password of the channel owner."; }else{ $pwd = $p->{'pwd'}; } unless (defined $p->{'host'}){ warn "Missing host name: using localhost instead."; $host = 'localhost'; }else{ $host = $p->{'host'}||'localhost'; } unless (defined $p->{'port'}){ warn "Missing port number: using 5222 instead."; $port = 5222; }else{ $port = $p->{'port'}||5222; } unless (defined $p->{'resource'}){ warn "Missing resource name: using PerlScript instead."; $resource = 'PerlScript'; }else{ $resource = $p->{'resource'}||'PerlScript'; } return ($uid,$pwd,$host,$port,$resource); } 1; __END__ # Below is stub documentation for your module. You'd better edit it! =head1 NAME Jabber::PubSub::JEAI - Perl extension for Erlang's J-EAI server =head1 SYNOPSIS use Jabber::PubSub::JEAI; It is important that you put Jabber connection and pub/sub parameters in a hash reference and pass it to the subroutines. Although not all of the pamameters are necessary for each subroutine. Example for channel creation: my $param = { 'uid' => 'admin', 'pwd' => 'nimda', 'host' => 'localhost', # default is 'localhost' 'port' => 5222, # default is 5222 'resource' => '', # use default 'channel' => 'home/localhost/admin/sport', 'to' => 'pubsub.localhost', 'iq_id' => '', # use default 'payload' => '', # N/A for channel creation }; Jabber::PubSub::JEAI::create_channel($param); Example for channel deletion: my $param = { 'uid' => 'admin', 'pwd' => 'nimda', 'host' => 'localhost', # default is 'localhost' 'port' => 5222, # default is 5222 'resource' => '', # use default 'channel' => 'home/localhost/admin/sport', 'to' => 'pubsub.localhost', 'iq_id' => '', # use default 'payload' => '', # N/A for channel creation }; Jabber::PubSub::JEAI::delete_channel($param); Example for subscription to the channel: $param = { 'uid' => 'app2', 'pwd' => 'app2', 'host' => 'localhost', # default is 'localhost' 'port' => 5222, # default is 5222 'resource' => '', # used default 'channel' => 'home/localhost/admin/sport', 'to' => 'pubsub.localhost', 'iq_id' => '', # use default 'payload' => '', # N/A for channel subscription }; Jabber::PubSub::JEAI::subscribe($param); To receive the publised messages you can use any Jabber client. All subscribers to the same channel will get the same messages simultaneously if they are all listening, or get the messages later but in correct sequence. Here is an example for polling a Jabber box and show the payloads in the published messages with Jabber::PubSub::JEAI: $param = { 'uid' => 'app2', 'pwd' => 'app2', 'host' => 'localhost', # default is 'localhost' 'port' => 5222, # default is 5222 'resoirce' => 'Test', 'channel' => '', # N/A for this purpose 'to' => '', # N/A for this purpose 'iq_id' => '', # N/A for this purpose 'payload' => '', # N/A for this purpose }; Jabber::PubSub::JEAI::listen($param); Example for publication to the channel: $param = { 'uid' => 'admin', 'pwd' => 'nimda', 'host' => 'localhost', # default is 'localhost' 'port' => 5222, # default is 5222 'resource' => 'Test', 'channel' => 'home/localhost/admin/sport', 'to' => 'pubsub.localhost', 'iq_id' => '', # use default 'payload' => 'Breaking news! ...', }; Jabber::PubSub::JEAI::publish($param); =head1 DESCRIPTION This package offers some utilities for interfacing with Erlang's J-EAI server 1.0. =head2 EXPORT None by default. =head1 ACKNOWLEDGMENT The author wishes to thank to "Thierry Mallard" and "Mickael Remond" , leaders of J-EAI development team, for their support. =head1 AUTHOR Kai Li, Ekaili@cpan.orgE =head1 COPYRIGHT AND LICENSE Copyright (C) 2005 by Kai Li This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.3 or, at your option, any later version of Perl 5 you may have available. =cut