[327] in BarnOwl Developers

home help back first fref pref prev next nref lref last post

[D-O-H] r471 - in trunk/owl: . perl/modules

daemon@ATHENA.MIT.EDU (asedeno@MIT.EDU)
Thu Oct 29 18:04:57 2009

Resent-From: nelhage@mit.edu
Resent-To: barnowl-dev-mtg@charon.mit.edu
To: dirty-owl-hackers@mit.edu
From: asedeno@MIT.EDU
Reply-to: dirty-owl-hackers@MIT.EDU
Date: Sun, 24 Dec 2006 14:15:05 -0500 (EST)

Author: asedeno
Date: 2006-12-24 14:15:05 -0500 (Sun, 24 Dec 2006)
New Revision: 471

Modified:
   trunk/owl/TODO
   trunk/owl/functions.c
   trunk/owl/owl.c
   trunk/owl/perl/modules/jabber.pl
Log:
Updates I've had pending for a while.

* First pass of Roster support
* Redesigning the connection storage as an object.
* Tweaking admin messages to allow reply actions. (Useful for Roster Management)
Possibly a few other things I'm forgetting.



Modified: trunk/owl/TODO
===================================================================
--- trunk/owl/TODO	2006-12-24 16:24:47 UTC (rev 470)
+++ trunk/owl/TODO	2006-12-24 19:15:05 UTC (rev 471)
@@ -14,3 +14,4 @@
 * Check for memory leaks
  * perl eval()s from owl seem problematic
 * Add sane default keybindings
+* Add jabber capabilities to one-line mode

Modified: trunk/owl/functions.c
===================================================================
--- trunk/owl/functions.c	2006-12-24 16:24:47 UTC (rev 470)
+++ trunk/owl/functions.c	2006-12-24 19:15:05 UTC (rev 471)
@@ -2086,12 +2086,6 @@
       }
     }
 
-    /* admin */
-    if (owl_message_is_type_admin(m)) {
-      owl_function_error("You cannot reply to an admin message");
-      return;
-    }
-
     /* loopback */
     if (owl_message_is_type_loopback(m)) {
       owl_function_loopwrite_setup();

Modified: trunk/owl/owl.c
===================================================================
--- trunk/owl/owl.c	2006-12-24 16:24:47 UTC (rev 470)
+++ trunk/owl/owl.c	2006-12-24 19:15:05 UTC (rev 471)
@@ -447,7 +447,6 @@
     }
 
     /* Hook perl into the loop */
-
     if (owl_perlconfig_is_function("owl::mainloop_hook")) {
 	 owl_perlconfig_mainloop();
     }

Modified: trunk/owl/perl/modules/jabber.pl
===================================================================
--- trunk/owl/perl/modules/jabber.pl	2006-12-24 16:24:47 UTC (rev 470)
+++ trunk/owl/perl/modules/jabber.pl	2006-12-24 19:15:05 UTC (rev 471)
@@ -25,7 +25,120 @@
 #
 ################################################################################
 
-our $connections;
+
+################################################################################
+################################################################################
+package owl_jabber::ConnectionManager;
+sub new {
+    my $class = shift;
+    return bless { }, $class;
+}
+
+sub addConnection {
+    my $self = shift;
+    my $jidStr = shift;
+
+    $self->{Client}->{$jidStr} = 
+      Net::Jabber::Client->new(
+          debuglevel => owl::getvar('debug') eq 'on' ? 1 : 0,
+          debugfile => 'jabber.log'
+      );
+    my $refConn = \$self->{Client}->{$jidStr};
+    $self->{Roster}->{$jidStr} = $$refConn->Roster();
+    return $refConn;
+}
+
+sub removeConnection {
+    my $self = shift;
+    my $jidStr = shift;
+    my $ret = 0;
+    foreach my $j ( keys %{ $self->{Client} } ) {
+        if ($j eq $jidStr) {
+            $self->{Client}->{$j}->Disconnect();
+            delete $self->{Roster}->{$j};
+            delete $self->{Client}->{$j};
+            $ret = 1;
+        }
+    }
+    return $ret;
+}
+
+sub connected {
+    my $self = shift;
+    return scalar keys %{ $self->{Client} };
+}
+
+sub getJids {
+    my $self = shift;
+    return keys %{ $self->{Client} };
+}
+
+sub jidExists {
+    my $self = shift;
+    my $jidStr = shift;
+    foreach my $j ( keys %{ $self->{Client} } ) {
+        return 1 if ($j eq $jidStr);
+    }
+    return 0;
+}
+
+sub sidExists {
+    my $self = shift;
+    my $sid = shift || "";
+    foreach my $j ( keys %{ $self->{Client} } ) {
+        return 1 if ($self->{Client}->{$j}->{SESSION}->{id} eq $sid);
+    }
+    return 0;
+}
+
+sub getConnRefFromSid {
+    my $self = shift;
+    my $sid = shift;
+    foreach my $j ( keys %{ $self->{Client} } ) {
+        if ($self->{Client}->{$j}->{SESSION}->{id} eq $sid) {
+            return \$self->{Client}->{$j};
+        }
+    }
+    return undef;
+}
+
+sub getConnRefFromJidStr {
+    my $self = shift;
+    my $jidStr = shift;
+    foreach my $j ( keys %{ $self->{Client} } ) {
+        if ($jidStr eq $j) {
+            return \$self->{Client}->{$j};
+        }
+    }
+    return undef;
+}
+
+sub getRosterRefFromSid {
+    my $self = shift;
+    my $sid = shift;
+    foreach my $j ( keys %{ $self->{Client} } ) {
+        if ($self->{Client}->{$j}->{SESSION}->{id} eq $sid) {
+            return \$self->{Roster}->{$j};
+        }
+    }
+    return undef;
+}
+
+sub getRosterRefFromJidStr {
+    my $self = shift;
+    my $jidStr = shift;
+    foreach my $j ( keys %{ $self->{Client} } ) {
+        if ($jidStr eq $j) {
+            return \$self->{Roster}->{$j};
+        }
+    }
+    return undef;
+}
+################################################################################
+
+package owl_jabber;
+
+our $conn = new owl_jabber::ConnectionManager unless $conn;;
 our %vars;
 
 sub onStart {
@@ -44,10 +157,10 @@
 push @::onStartSubs, sub { owl_jabber::onStart(@_) };
 
 sub onMainLoop {
-    return if ( !connected() );
+    return if ( !$conn->connected() );
 
-    foreach my $jid ( keys %$connections ) {
-        my $client = \$connections->{$jid}->{client};
+    foreach my $jid ( $conn->getJids() ) {
+        my $client = $conn->getConnRefFromJidStr($jid);
 
         my $status = $$client->Process(0);
         if ( !defined($status) ) {
@@ -68,7 +181,7 @@
     my %jq  = $$roster->query($buddy);
     my $res = $$roster->resource($buddy);
 
-    $blistStr .= $jq{name} ? $jq{name} : $buddy->GetJID();
+    $blistStr .= $jq{name} ? $jq{name} . "\t(" .$buddy->GetJID() . ')' : $buddy->GetJID();
 
     if ($res) {
         my %rq = $$roster->resourceQuery( $buddy, $res );
@@ -95,7 +208,7 @@
     $jid = resolveJID($jid);
     return "" unless $jid;
     my $blist = "";
-    my $roster = \$connections->{$jid}->{roster};
+    my $roster = $conn->getRosterRefFromJidStr($jid);
     if ($$roster) {
         $blist .= "\n" . boldify("Jabber Roster for $jid\n");
 
@@ -119,7 +232,7 @@
 
 sub onGetBuddyList {
     my $blist = "";
-    foreach my $jid (keys %{$connections}) {
+    foreach my $jid ($conn->getJids()) {
         $blist .= getSingleBuddyList($jid);
     }
     return $blist;
@@ -168,6 +281,14 @@
             usage => "jmuc {command} {args}"
         }
     );
+    owl::new_command(
+        jroster => \&cmd_jroster,
+        {
+            summary     => "Jabber Roster related commands.",
+	    description => "jroster sends jabber commands related to rosters.\n\n",
+            usage       => "jroster {command} {args}"
+        }
+    );
 }
 
 sub cmd_login {
@@ -186,7 +307,7 @@
         return;
     }
 
-    if ( $connections->{$jidStr} ) {
+    if ( $conn->jidExists($jidStr) ) {
         owl::error("Already logged in as $jidStr.");
         return;
     }
@@ -218,13 +339,7 @@
     }
     else
     {
-        $connections->{$jidStr}->{client} = Net::Jabber::Client->new(
-            debuglevel => owl::getvar('debug') eq 'on' ? 1 : 0,
-            debugfile => 'jabber.log'
-        );
-        my $client = \$connections->{$jidStr}->{client};
-        $connections->{$jidStr}->{roster} =
-          $connections->{$jidStr}->{client}->Roster();
+        my $client = $conn->addConnection($jidStr);
 
         #XXX Todo: Add more callbacks.
         # * MUC presence handlers
@@ -236,12 +351,16 @@
             normal    => sub { owl_jabber::process_incoming_normal_message(@_) }
         );
         $$client->SetPresenceCallBacks(
-            subscribe   => sub { owl_jabber::process_presence_subscribe(@_) },
-            unsubscribe => sub { owl_jabber::process_presence_unsubscribe(@_) });
+#            available    => sub { owl_jabber::process_presence_available(@_) },
+#            unavailable  => sub { owl_jabber::process_presence_available(@_) },
+            subscribe    => sub { owl_jabber::process_presence_subscribe(@_) },
+            subscribed   => sub { owl_jabber::process_presence_subscribed(@_) },
+            unsubscribe  => sub { owl_jabber::process_presence_unsubscribe(@_) },
+            unsubscribed => sub { owl_jabber::process_presence_unsubscribed(@_) });
 
         my $status = $$client->Connect( %{ $vars{jlogin_connhash} } );
         if ( !$status ) {
-            delete $connections->{$jidStr};
+            $conn->removeConnection($jidStr);
             owl::error("We failed to connect");
         }
         else {
@@ -250,16 +369,16 @@
             if ( $result[0] ne 'ok' ) {
             if ( !$vars{jlogin_havepass} && $result[0] == 401 ) {
                 $vars{jlogin_havepass} = 1;
-                delete $connections->{$jidStr};
+                $conn->removeConnection($jidStr);
                 owl::start_password( "Password for $jidStr: ", \&do_login );
                 return "";
             }
-            delete $connections->{$jidStr};
+            $conn->removeConnection($jidStr);
             owl::error(
                 "Error in connect: " . join( " ", @result ) );
         }
             else {
-                $connections->{$jidStr}->{roster}->fetch();
+                ${ $conn->getRosterRefFromJidStr($jidStr) }->fetch();
                 $$client->PresenceSend( priority => 1 );
                 queue_admin_msg("Connected to jabber as $jidStr");
             }
@@ -276,19 +395,18 @@
 
 sub do_logout {
     my $jid = shift;
-    $connections->{$jid}->{client}->Disconnect();
-    delete $connections->{$jid};
-    queue_admin_msg("Jabber disconnected ($jid).");
+    my $disconnected = $conn->removeConnection($jid);
+    queue_admin_msg("Jabber disconnected ($jid).") if $disconnected;
 }
 
 sub cmd_logout {
     # Logged into multiple accounts
-    if ( connected() > 1 ) {
+    if ( $conn->connected() > 1 ) {
         # Logged into multiple accounts, no accout specified.
         if ( !$_[1] ) {
             my $errStr =
               "You are logged into multiple accounts. Please specify an account to log out of.\n";
-            foreach my $jid ( keys %$connections ) {
+            foreach my $jid ( $conn->getJids() ) {
                 $errStr .= "\t$jid\n";
             }
             queue_admin_msg($errStr);
@@ -297,7 +415,7 @@
         else {
             if ( $_[1] eq '-a' )    #All accounts.
             {
-                foreach my $jid ( keys %$connections ) {
+                foreach my $jid ( $conn->getJids() ) {
                     do_logout($jid);
                 }
             }
@@ -310,13 +428,13 @@
     }
     else                            # Only one account logged in.
     {
-        do_logout( ( keys %$connections )[0] );
+        do_logout( ( $conn->getJids() )[0] );
     }
     return "";
 }
 
 sub cmd_jlist {
-    if ( !( scalar keys %$connections ) ) {
+    if ( !( scalar $conn->getJids() ) ) {
         owl::error("You are not logged in to Jabber.");
         return;
     }
@@ -324,13 +442,14 @@
 }
 
 sub cmd_jwrite {
-    if ( !connected() ) {
+    if ( !$conn->connected() ) {
         owl::error("You are not logged in to Jabber.");
         return;
     }
 
     my $jwrite_to      = "";
     my $jwrite_from    = "";
+    my $jwrite_sid     = "";
     my $jwrite_thread  = "";
     my $jwrite_subject = "";
     my $jwrite_type    = "chat";
@@ -343,6 +462,7 @@
         'thread=s'  => \$jwrite_thread,
         'subject=s' => \$jwrite_subject,
         'account=s' => \$jwrite_from,
+        'id=s'     =>  \$jwrite_sid,
         'groupchat' => \$gc
     );
     $jwrite_type = 'groupchat' if $gc;
@@ -357,8 +477,8 @@
     }
 
     if ( !$jwrite_from ) {
-        if ( connected() == 1 ) {
-            $jwrite_from = ( keys %$connections )[0];
+        if ( $conn->connected() == 1 ) {
+            $jwrite_from = ( $conn->getJids() )[0];
         }
         else {
             owl::error("Please specify an account with -a {jid}");
@@ -373,19 +493,20 @@
     $vars{jwrite} = {
         to      => $jwrite_to,
         from    => $jwrite_from,
+        sid     => $jwrite_sid,
         subject => $jwrite_subject,
         thread  => $jwrite_thread,
         type    => $jwrite_type
     };
 
     owl::message(
-        "Type your message below.  End with a dot on a line by itself.  ^C will quit."
-       );
+"Type your message below.  End with a dot on a line by itself.  ^C will quit."
+    );
     owl::start_edit_win( join( ' ', @args ), \&process_owl_jwrite );
 }
 
 sub cmd_jmuc {
-    die "You are not logged in to Jabber" unless connected();
+    die "You are not logged in to Jabber" unless $conn->connected();
     my $ocmd = shift;
     my $cmd  = shift;
     if ( !$cmd ) {
@@ -448,7 +569,7 @@
         $x->SetPassword($password);
     }
 
-    $connections->{$jid}->{client}->Send($presence);
+    ${ $conn->getConnRefFromJidStr($jid) }->Send($presence);
 }
 
 sub jmuc_part {
@@ -457,7 +578,7 @@
     $muc = shift @args if scalar @args;
     die("Usage: jmuc part {muc} [-a account]") unless $muc;
 
-    $connections->{$jid}->{client}
+    ${ $conn->getConnRefFromJidStr($jid) }
       ->PresenceSend( to => $muc, type => 'unavailable' );
     queue_admin_msg("$jid has left $muc.");
 }
@@ -476,7 +597,7 @@
     my $x = $message->NewChild('http://jabber.org/protocol/muc#user');
     $x->AddInvite();
     $x->GetInvite()->SetTo($invite_jid);
-    $connections->{$jid}->{client}->Send($message);
+    ${ $conn->getConnRefFromJidStr($jid) }->Send($message);
     queue_admin_msg("$jid has invited $invite_jid to $muc.");
 }
 
@@ -491,10 +612,201 @@
     my $x     = $query->NewChild("jabber:x:data");
     $x->SetType('submit');
 
-    $connections->{$jid}->{client}->Send($iq);
+    ${ $conn->getConnRefFromJidStr($jid) }->Send($iq);
     queue_admin_msg("Accepted default instant configuration for $muc");
 }
 
+
+#XXX TODO: Consider merging this with jmuc and selecting off the first two args.
+sub cmd_jroster {
+    die "You are not logged in to Jabber" unless $conn->connected();
+    my $ocmd = shift;
+    my $cmd  = shift;
+    if ( !$cmd ) {
+
+        #XXX TODO: Write general usage for jroster command.
+        return;
+    }
+
+    my %jroster_commands = (
+        sub      => \&jroster_sub,
+        unsub    => \&jroster_unsub,
+        add      => \&jroster_add,
+        remove   => \&jroster_remove,
+        auth     => \&jroster_auth,
+        deauth   => \&jroster_deauth
+    );
+
+    my $func = $jroster_commands{$cmd};
+    if ( !$func ) {
+        owl::error("jroster: Unknown command: $cmd");
+        return;
+    }
+
+    {
+        local @ARGV = @_;
+        my $jid;
+        my $name;
+        my @groups;
+        my $purgeGroups;
+        my $getopt = Getopt::Long::Parser->new;
+        $getopt->configure('pass_through');
+        $getopt->getoptions(
+            'account=s' => \$jid,
+            'group=s' => \@groups,
+            'purgegroups' => \$purgeGroups,
+            'name=s' => \$name
+        );
+        $jid ||= defaultJID();
+        if ($jid) {
+            $jid = resolveJID($jid);
+            return unless $jid;
+        }
+        else {
+            owl::error('You must specify an account with -a {jid}');
+        }
+        return $func->( $jid, $name, \@groups, $purgeGroups,  @ARGV );
+    }
+}
+
+sub jroster_sub {
+    my $jid = shift;
+    my $name = shift;
+    my @groups = @{ shift() };
+    my $purgeGroups = shift;
+    my $baseJid = baseJID($jid);
+
+    my $roster = $conn->getRosterRefFromJidStr($jid);
+
+    # Adding lots of users with the same name is a bad idea.
+    $name = "" unless (1 == scalar(@ARGV));
+
+    my $p = new Net::XMPP::Presence;
+    $p->SetType('subscribe');
+
+    foreach my $to (@ARGV) {
+        jroster_add($jid, $name, \@groups, $purgeGroups, ($to)) unless ($$roster->exists($to));
+
+        $p->SetTo($to);
+        ${ $conn->getConnRefFromJidStr($jid) }->Send($p);
+        queue_admin_msg("You ($baseJid) have requested a subscription to ($to)'s presence.");
+    }
+}
+
+sub jroster_unsub {
+    my $jid = shift;
+    my $name = shift;
+    my @groups = @{ shift() };
+    my $purgeGroups = shift;
+    my $baseJid = baseJID($jid);
+
+    my $p = new Net::XMPP::Presence;
+    $p->SetType('unsubscribe');
+    foreach my $to (@ARGV) {
+        $p->SetTo($to);
+        ${ $conn->getConnRefFromJidStr($jid) }->Send($p);
+        queue_admin_msg("You ($baseJid) have unsubscribed from ($to)'s presence.");
+    }
+}
+
+sub jroster_add {
+    my $jid = shift;
+    my $name = shift;
+    my @groups = @{ shift() };
+    my $purgeGroups = shift;
+    my $baseJid = baseJID($jid);
+
+    my $roster = $conn->getRosterRefFromJidStr($jid);
+
+    # Adding lots of users with the same name is a bad idea.
+    $name = "" unless (1 == scalar(@ARGV));
+
+    foreach my $to (@ARGV) {
+        my %jq  = $$roster->query($to);
+        my $iq = new Net::XMPP::IQ;
+        $iq->SetType('set');
+        my $item = new XML::Stream::Node('item');
+        $iq->NewChild('jabber:iq:roster')->AddChild($item);
+
+        my %allGroups = ();
+
+        foreach my $g (@groups) {
+            $allGroups{$g} = $g;
+        }
+
+        unless ($purgeGroups) {
+            foreach my $g (@{$jq{groups}}) {
+                $allGroups{$g} = $g;
+            }
+        }
+
+        foreach my $g (keys %allGroups) {
+            $item->add_child('group')->add_cdata($g);
+        }
+
+        $item->put_attrib(jid => $to);
+        $item->put_attrib(name => $name) if $name;
+        ${ $conn->getConnRefFromJidStr($jid) }->Send($iq);
+        my $msg = "$baseJid: "
+          . ($name ? "$name ($to)" : "($to)")
+          . " is on your roster in the following groups: { "
+          . join(" , ", keys %allGroups)
+          . " }";
+        queue_admin_msg($msg);
+    }
+}
+
+sub jroster_remove {
+    my $jid = shift;
+    my $name = shift;
+    my @groups = @{ shift() };
+    my $purgeGroups = shift;
+    my $baseJid = baseJID($jid);
+
+    my $iq = new Net::XMPP::IQ;
+    $iq->SetType('set');
+    my $item = new XML::Stream::Node('item');
+    $iq->NewChild('jabber:iq:roster')->AddChild($item);
+    $item->put_attrib(subscription=> 'remove');
+    foreach my $to (@ARGV) {
+        $item->put_attrib(jid => $to);
+        ${ $conn->getConnRefFromJidStr($jid) }->Send($iq);
+        queue_admin_msg("You ($baseJid) have removed ($to) from your roster.");
+    }
+}
+
+sub jroster_auth {
+    my $jid = shift;
+    my $name = shift;
+    my @groups = @{ shift() };
+    my $purgeGroups = shift;
+    my $baseJid = baseJID($jid);
+
+    my $p = new Net::XMPP::Presence;
+    $p->SetType('subscribed');
+    foreach my $to (@ARGV) {
+        $p->SetTo($to);
+        ${ $conn->getConnRefFromJidStr($jid) }->Send($p);
+        queue_admin_msg("($to) has been subscribed to your ($baseJid) presence.");
+    }
+}
+
+sub jroster_deauth {
+    my $jid = shift;
+    my $name = shift;
+    my @groups = @{ shift() };
+    my $purgeGroups = shift;
+    my $baseJid = baseJID($jid);
+
+    my $p = new Net::XMPP::Presence;
+    $p->SetType('unsubscribed');
+    foreach my $to (@ARGV) {
+        $p->SetTo($to);
+        ${ $conn->getConnRefFromJidStr($jid) }->Send($p);
+        queue_admin_msg("($to) has been unsubscribed from your ($baseJid) presence.");
+    }
+}
+
 ################################################################################
 ### Owl Callbacks
 sub process_owl_jwrite {
@@ -508,16 +820,24 @@
         type => $vars{jwrite}{type},
         body => $body
     );
+
     $j->SetThread( $vars{jwrite}{thread} )   if ( $vars{jwrite}{thread} );
     $j->SetSubject( $vars{jwrite}{subject} ) if ( $vars{jwrite}{subject} );
 
-    my $m = j2o( $j, 'out' );
+    my $m = j2o( $j, { direction => 'out' } );
     if ( $vars{jwrite}{type} ne 'groupchat' ) {
 
         #XXX TODO: Check for displayoutgoing.
         owl::queue_message($m);
     }
-    $connections->{ $vars{jwrite}{from} }->{client}->Send($j);
+
+    if ($vars{jwrite}{sid} && $conn->sidExists( $vars{jwrite}{sid} )) {
+        ${ $conn->getConnRefFromSid($vars{jwrite}{sid}) }->Send($j);
+    }
+    else {
+        ${ $conn->getConnRefFromJidStr($vars{jwrite}{from}) }->Send($j);
+    }
+
     delete $vars{jwrite};
     owl::message("");   # Kludge to make the ``type your message...'' message go away
 }
@@ -525,33 +845,38 @@
 ### XMPP Callbacks
 
 sub process_incoming_chat_message {
-    my ( $session, $j ) = @_;
-    owl::queue_message( j2o( $j, 'in' ) );
+    my ( $sid, $j ) = @_;
+    owl::queue_message( j2o( $j, { direction => 'in',
+                                   sid => $sid } ) );
 }
 
 sub process_incoming_error_message {
-    my ( $session, $j ) = @_;
-    my %jhash = j2hash( $j, 'in' );
+    my ( $sid, $j ) = @_;
+    my %jhash = j2hash( $j, { direction => 'in',
+                              sid => $sid } );
     $jhash{type} = 'admin';
     owl::queue_message( owl::Message->new(%jhash) );
 }
 
 sub process_incoming_groupchat_message {
-    my ( $session, $j ) = @_;
+    my ( $sid, $j ) = @_;
 
     # HACK IN PROGRESS (ignoring delayed messages)
     return if ( $j->DefinedX('jabber:x:delay') && $j->GetX('jabber:x:delay') );
-    owl::queue_message( j2o( $j, 'in' ) );
+    owl::queue_message( j2o( $j, { direction => 'in',
+                                   sid => $sid } ) );
 }
 
 sub process_incoming_headline_message {
-    my ( $session, $j ) = @_;
-    owl::queue_message( j2o( $j, 'in' ) );
+    my ( $sid, $j ) = @_;
+    owl::queue_message( j2o( $j, { direction => 'in',
+                                   sid => $sid } ) );
 }
 
 sub process_incoming_normal_message {
-    my ( $session, $j ) = @_;
-    my %props = j2hash( $j, 'in' );
+    my ( $sid, $j ) = @_;
+    my %jhash = j2hash( $j, { direction => 'in',
+                              sid => $sid } );
 
     # XXX TODO: handle things such as MUC invites here.
 
@@ -564,26 +889,125 @@
     #	}
     #    }
     #
-    owl::queue_message( owl::Message->new(%props) );
+    owl::queue_message( owl::Message->new(%jhash) );
 }
 
 sub process_muc_presence {
-    my ( $session, $p ) = @_;
+    my ( $sid, $p ) = @_;
     return unless ( $p->HasX('http://jabber.org/protocol/muc#user') );
+}
 
+
+sub process_presence_available {
+    my ( $sid, $p ) = @_;
+    my $from = $p->GetFrom();
+    my $to = $p->GetTo();
+    my $type = $p->GetType();
+    my %props = (
+        to => $to,
+        from => $from,
+        recipient => $to,
+        sender => $from,
+        type => 'jabber',
+        jtype => $p->GetType(),
+        status => $p->GetStatus(),
+        show => $p->GetShow(),
+        xml => $p->GetXML(),
+        direction => 'in');
+
+    if ($type eq '' || $type eq 'available') {
+        $props{body} = "$from is now online. ";
+        $props{loginout} = 'login';
+    }
+    else {
+        $props{body} = "$from is now offline. ";
+        $props{loginout} = 'logout';
+    }
+    $props{replysendercmd} = $props{replycmd} = "jwrite $from -i $sid";
+    owl::queue_message(owl::Message->new(%props));
 }
 
+sub process_presence_subscribe {
+    my ( $sid, $p ) = @_;
+    my $from = $p->GetFrom();
+    my $to = $p->GetTo();
+    my %props = (
+        to => $to,
+        from => $from,
+        xml => $p->GetXML(),
+        type => 'admin',
+        adminheader => 'Jabber presence: subscribe',
+        direction => 'in');
+
+    $props{body} = "The user ($from) wants to subscribe to your ($to) presence.\nReply (r) will authorize, reply-sender (R) will deny.";
+    $props{replycmd} = "jroster auth $from -a $to";
+    $props{replysendercmd} = "jroster deauth $from -a $to";
+    owl::queue_message(owl::Message->new(%props));
+}
+
+sub process_presence_unsubscribe {
+    my ( $sid, $p ) = @_;
+    my $from = $p->GetFrom();
+    my $to = $p->GetTo();
+    my %props = (
+        to => $to,
+        from => $from,
+        xml => $p->GetXML(),
+        type => 'admin',
+        adminheader => 'Jabber presence: unsubscribe',
+        direction => 'in');
+
+    $props{body} = "The user ($from) has been unsubscribed from your ($to) presence.\n";
+    owl::queue_message(owl::Message->new(%props));
+
+    # Find a connection to reply with.
+    foreach my $jid ($conn->getJids()) {
+	my $cJid = new Net::XMPP::JID;
+	$cJid->SetJID($jid);
+	if ($to eq $cJid->GetJID('base') ||
+            $to eq $cJid->GetJID('full')) {
+	    my $reply = $p->Reply(type=>"unsubscribed");
+	    ${ $conn->getConnRefFromJidStr($jid) }->Send($reply);
+	    return;
+	}
+    }
+}
+
+sub process_presence_subscribed {
+    my ( $sid, $p ) = @_;
+    queue_admin_msg("ignoring:".$p->GetXML());
+    # RFC 3921 says we should respond to this with a "subscribe"
+    # but this causes a flood of sub/sub'd presence packets with
+    # some servers, so we won't. We may want to detect this condition
+    # later, and have per-server settings.
+    return;
+}
+
+sub process_presence_unsubscribed {
+    my ( $sid, $p ) = @_;
+    queue_admin_msg("ignoring:".$p->GetXML());
+    # RFC 3921 says we should respond to this with a "subscribe"
+    # but this causes a flood of unsub/unsub'd presence packets with
+    # some servers, so we won't. We may want to detect this condition
+    # later, and have per-server settings.
+    return;
+}
+
+
 ### Helper functions
 
 sub j2hash {
     my $j   = shift;
-    my $dir = shift;
+    my %initProps = %{ shift() };
 
-    my %props = (
-        type      => 'jabber',
-        direction => $dir
-    );
+    my $dir = 'none';
+    my %props = ( type => 'jabber' );
 
+    foreach my $k (keys %initProps) {
+        $dir = $initProps{$k} if ($k eq 'direction');
+        $props{$k} = $initProps{$k};
+    }
+
     my $jtype = $props{jtype} = $j->GetType();
     my $from = $j->GetFrom('jid');
     my $to   = $j->GetTo('jid');
@@ -591,8 +1015,6 @@
     $props{from} = $from->GetJID('full');
     $props{to}   = $to->GetJID('full');
 
-    my $account = ( $dir eq 'out' ) ? $props{from} : $props{to};
-
     $props{recipient}  = $to->GetJID('base');
     $props{sender}     = $from->GetJID('base');
     $props{subject}    = $j->GetSubject() if ( $j->DefinedSubject() );
@@ -604,17 +1026,18 @@
 
     if ( $jtype eq 'chat' ) {
         $props{replycmd} =
-          "jwrite " . ( ( $dir eq 'in' ) ? $props{from} : $props{to} ) . " -a $account";
+          "jwrite " . ( ( $dir eq 'in' ) ? $props{from} : $props{to} );
+        $props{replycmd} .=
+          " -a " . ( ( $dir eq 'out' ) ? $props{from} : $props{to} );
         $props{isprivate} = 1;
-        $props{replysendercmd} = $props{replycmd};
     }
     elsif ( $jtype eq 'groupchat' ) {
         my $nick = $props{nick} = $from->GetResource();
         my $room = $props{room} = $from->GetJID('base');
-        $props{replycmd} = "jwrite -g $room -a $account";
+        $props{replycmd} = "jwrite -g $room";
+        $props{replycmd} .=
+          " -a " . ( ( $dir eq 'out' ) ? $props{from} : $props{to} );
 
-        $props{replysendercmd} = "jwrite " . $from->GetJID('full') . " -a $account";
-
         $props{sender} = $nick || $room;
         $props{recipient} = $room;
 
@@ -639,6 +1062,7 @@
           . $props{error};
     }
 
+    $props{replysendercmd} = $props{replycmd};
     return %props;
 }
 
@@ -684,12 +1108,8 @@
     return $jid->GetServer(), 5222;
 }
 
-sub connected {
-    return scalar keys %$connections;
-}
-
 sub defaultJID {
-    return ( keys %$connections )[0] if ( connected() == 1 );
+    return ( $conn->getJids() )[0] if ( $conn->connected() == 1 );
     return;
 }
 
@@ -707,15 +1127,9 @@
 
     # Account fully specified.
     if ( $givenJid->GetResource() ) {
-
         # Specified account exists
-        if ( defined $connections->{$givenJidStr} ) {
-            return $givenJidStr;
-        }
-        else    #Specified account doesn't exist
-        {
-            owl::error("Invalid account: $givenJidStr");
-        }
+        return $givenJidStr if ($conn->jidExists($givenJidStr) );
+        owl::error("Invalid account: $givenJidStr");
     }
 
     # Disambiguate.
@@ -725,7 +1139,7 @@
           "Ambiguous account reference. Please specify a resource.\n";
         my $ambiguous = 0;
 
-        foreach my $jid ( keys %$connections ) {
+        foreach my $jid ( $conn->getJids() ) {
             my $cJid = new Net::XMPP::JID;
             $cJid->SetJID($jid);
             if ( $givenJidStr eq $cJid->GetJID('base') ) {


home help back first fref pref prev next nref lref last post