Index: perl/modules/jabber.pl
===================================================================
--- perl/modules/jabber.pl	(revision 6e9e50e02fd2d7673eb6b56ad78cf68162803e61)
+++ perl/modules/jabber.pl	(revision 84296f61eeceed9c114665d418936c3ab2a5bde9)
@@ -8,4 +8,6 @@
 use Net::DNS;
 use Getopt::Long;
+
+no warnings 'redefine';
 
 ################################################################################
@@ -20,5 +22,5 @@
 # Implementing formatting and logging callbacks for C
 # Appropriate callbacks for presence subscription messages.
-#  * Current behavior => auto-accept (default for Net::Jabber)
+#  * Current behavior is auto-accept (default for Net::Jabber)
 #
 ################################################################################
@@ -34,5 +36,4 @@
     }
     else {
-
         # Our owl doesn't support queue_message. Unfortunately, this
         # means it probably *also* doesn't support owl::error. So just
@@ -77,32 +78,48 @@
     }
     else {
-        $blistStr .= $jq{ask} ? " [pending]" : " [offline]";
-    }
-
+	if ($jq{ask}) {
+            $blistStr .= " [pending]";
+	}
+	elsif ($jq{subscription} eq 'none' || $jq{subscription} eq 'from') {
+	    $blistStr .= " [not subscribed]";
+	}
+	else {
+	    $blistStr .= " [offline]";
+	}
+    }
     return $blistStr . "\n";
+}
+
+sub getSingleBuddyList {
+    my $jid = shift;
+    $jid = resolveJID($jid);
+    return "" unless $jid;
+    my $blist = "";
+    my $roster = \$connections->{$jid}->{roster};
+    if ($$roster) {
+        $blist .= "\n" . boldify("Jabber Roster for $jid\n");
+
+        foreach my $group ( $$roster->groups() ) {
+            $blist .= "  Group: $group\n";
+            foreach my $buddy ( $$roster->jids( 'group', $group ) ) {
+                $blist .= blist_listBuddy( $roster, $buddy );
+            }
+        }
+
+        my @unsorted = $$roster->jids('nogroup');
+        if (@unsorted) {
+            $blist .= "  [unsorted]\n";
+            foreach my $buddy (@unsorted) {
+                $blist .= blist_listBuddy( $roster, $buddy );
+            }
+        }
+    }
+    return $blist;
 }
 
 sub onGetBuddyList {
     my $blist = "";
-    foreach my $jid ( keys %{$connections} ) {
-        my $roster = \$connections->{$jid}->{roster};
-        if ($$roster) {
-            $blist .= "\n" . boldify("Jabber Roster for $jid\n");
-
-            foreach my $group ( $$roster->groups() ) {
-                $blist .= "  Group: $group\n";
-                foreach my $buddy ( $$roster->jids( 'group', $group ) ) {
-                    $blist .= blist_listBuddy( $roster, $buddy );
-                }
-            }
-
-            my @unsorted = $$roster->jids('nogroup');
-            if (@unsorted) {
-                $blist .= "  [unsorted]\n";
-                foreach my $buddy (@unsorted) {
-                    $blist .= blist_listBuddy( $roster, $buddy );
-                }
-            }
-        }
+    foreach my $jid (keys %{$connections}) {
+        $blist .= getSingleBuddyList($jid);
     }
     return $blist;
@@ -177,22 +194,6 @@
     my ( $server, $port ) = getServerFromJID($jid);
 
-    $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();
-
-    #XXX Todo: Add more callbacks.
-    # MUC presence handlers
-    $$client->SetMessageCallBacks(
-        chat      => sub { owl_jabber::process_incoming_chat_message(@_) },
-        error     => sub { owl_jabber::process_incoming_error_message(@_) },
-        groupchat => sub { owl_jabber::process_incoming_groupchat_message(@_) },
-        headline  => sub { owl_jabber::process_incoming_headline_message(@_) },
-        normal    => sub { owl_jabber::process_incoming_normal_message(@_) }
-    );
-
+    $vars{jlogin_jid} = $jidStr;
+    $vars{jlogin_havepass} = 0;
     $vars{jlogin_connhash} = {
         hostname      => $server,
@@ -201,82 +202,72 @@
         componentname => $componentname
     };
-
-    my $status = $$client->Connect( %{ $vars{jlogin_connhash} } );
-
-    if ( !$status ) {
-        delete $connections->{$jidStr};
-        delete $vars{jlogin_connhash};
-        owl::error("We failed to connect");
-        return "";
-    }
-
     $vars{jlogin_authhash} =
-      { username => $uid, resource => $resource, password => '' };
-    my @result = $$client->AuthSend( %{ $vars{jlogin_authhash} } );
-    if ( $result[0] ne 'ok' ) {
-        if ( $result[1] == 401 ) {
-            $vars{jlogin_jid} = $jidStr;
+      { username => $uid,
+        resource => $resource,
+    };
+
+    return do_login('');
+}
+
+sub do_login {
+    $vars{jlogin_password} = shift;
+    $vars{jlogin_authhash}->{password} = sub { return $vars{jlogin_password} || '' };
+    my $jidStr = $vars{jlogin_jid};
+    if ( !$jidStr && $vars{jlogin_havepass}) {
+        owl::error("Got password but have no jid!");
+    }
+    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();
+
+        #XXX Todo: Add more callbacks.
+        # * MUC presence handlers
+        $$client->SetMessageCallBacks(
+            chat      => sub { owl_jabber::process_incoming_chat_message(@_) },
+            error     => sub { owl_jabber::process_incoming_error_message(@_) },
+            groupchat => sub { owl_jabber::process_incoming_groupchat_message(@_) },
+            headline  => sub { owl_jabber::process_incoming_headline_message(@_) },
+            normal    => sub { owl_jabber::process_incoming_normal_message(@_) }
+        );
+        $$client->SetPresenceCallBacks(
+            subscribe   => sub { owl_jabber::process_presence_subscribe(@_) },
+            unsubscribe => sub { owl_jabber::process_presence_unsubscribe(@_) });
+
+        my $status = $$client->Connect( %{ $vars{jlogin_connhash} } );
+        if ( !$status ) {
             delete $connections->{$jidStr};
-            owl::start_password( "Password for $jidStr: ", \&do_login_with_pw );
-            return "";
-        }
-        owl::error(
-            "Error in connect: " . join( " ", $result[ 1 .. $#result ] ) );
-        do_logout($jidStr);
-        delete $vars{jlogin_connhash};
-        delete $vars{jlogin_authhash};
-        return "";
-    }
-    $connections->{$jidStr}->{roster}->fetch();
-    $$client->PresenceSend( priority => 1 );
-    queue_admin_msg("Connected to jabber as $jidStr");
-    delete $vars{jlogin_connhash};
-    delete $vars{jlogin_authhash};
-    return "";
-}
-
-sub do_login_with_pw {
-    $vars{jlogin_authhash}->{password} = shift;
-    my $jidStr = delete $vars{jlogin_jid};
-    if ( !$jidStr ) {
-        owl::error("Got password but have no jid!");
-    }
-
-    $connections->{$jidStr}->{client} = Net::Jabber::Client->new();
-    my $client = \$connections->{$jidStr}->{client};
-    $connections->{$jidStr}->{roster} =
-      $connections->{$jidStr}->{client}->Roster();
-
-    $$client->SetMessageCallBacks(
-        chat      => sub { owl_jabber::process_incoming_chat_message(@_) },
-        error     => sub { owl_jabber::process_incoming_error_message(@_) },
-        groupchat => sub { owl_jabber::process_incoming_groupchat_message(@_) },
-        headline  => sub { owl_jabber::process_incoming_headline_message(@_) },
-        normal    => sub { owl_jabber::process_incoming_normal_message(@_) }
-    );
-
-    my $status = $$client->Connect( %{ $vars{jlogin_connhash} } );
-    if ( !$status ) {
-        delete $connections->{$jidStr};
-        delete $vars{jlogin_connhash};
-        delete $vars{jlogin_authhash};
-        owl::error("We failed to connect");
-        return "";
-    }
-
-    my @result = $$client->AuthSend( %{ $vars{jlogin_authhash} } );
-
-    if ( $result[0] ne 'ok' ) {
-        owl::error(
-            "Error in connect: " . join( " ", $result[ 1 .. $#result ] ) );
-        do_logout($jidStr);
-        delete $vars{jlogin_connhash};
-        delete $vars{jlogin_authhash};
-        return "";
-    }
-
-    $connections->{$jidStr}->{roster}->fetch();
-    $$client->PresenceSend( priority => 1 );
-    queue_admin_msg("Connected to jabber as $jidStr");
+            owl::error("We failed to connect");
+        }
+        else {
+            my @result = $$client->AuthSend( %{ $vars{jlogin_authhash} } );
+
+            if ( $result[0] ne 'ok' ) {
+            if ( !$vars{jlogin_havepass} && $result[0] == 401 ) {
+                $vars{jlogin_havepass} = 1;
+                delete $connections->{$jidStr};
+                owl::start_password( "Password for $jidStr: ", \&do_login );
+                return "";
+            }
+            delete $connections->{$jidStr};
+            owl::error(
+                "Error in connect: " . join( " ", @result ) );
+        }
+            else {
+                $connections->{$jidStr}->{roster}->fetch();
+                $$client->PresenceSend( priority => 1 );
+                queue_admin_msg("Connected to jabber as $jidStr");
+            }
+        }
+    }
+    delete $vars{jlogin_jid};
+    $vars{jlogin_password} =~ tr/\0-\377/x/;
+    delete $vars{jlogin_password};
+    delete $vars{jlogin_havepass};
     delete $vars{jlogin_connhash};
     delete $vars{jlogin_authhash};
@@ -292,12 +283,10 @@
 
 sub cmd_logout {
-
     # Logged into multiple accounts
     if ( 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";
+              "You are logged into multiple accounts. Please specify an account to log out of.\n";
             foreach my $jid ( keys %$connections ) {
                 $errStr .= "\t$jid\n";
@@ -305,5 +294,4 @@
             queue_admin_msg($errStr);
         }
-
         # Logged into multiple accounts, account specified.
         else {
@@ -323,5 +311,4 @@
     else                            # Only one account logged in.
     {
-
         do_logout( ( keys %$connections )[0] );
     }
@@ -707,4 +694,11 @@
 }
 
+sub baseJID {
+    my $givenJidStr = shift;
+    my $givenJid    = new Net::XMPP::JID;
+    $givenJid->SetJID($givenJidStr);
+    return $givenJid->GetJID('base');
+}
+
 sub resolveJID {
     my $givenJidStr = shift;
@@ -752,5 +746,5 @@
         }
 
-        # Log out this one.
+        # It's this one.
         else {
             return $matchingJid;
@@ -759,2 +753,4 @@
     return "";
 }
+
+1;
