Index: perl/lib/BarnOwl/Complete/Zephyr.pm
===================================================================
--- perl/lib/BarnOwl/Complete/Zephyr.pm	(revision 8f16dcda1df7627bc44d501b2a495055bf3bf654)
+++ perl/lib/BarnOwl/Complete/Zephyr.pm	(revision 84db778a610e15073885aa6d39fab196ab9e83cb)
@@ -30,13 +30,4 @@
 }
 
-sub complete_sub {
-    my $ctx = shift;
-    return complete_flags($ctx,
-        [],
-        {
-            "-r" => \&complete_realm,
-        });
-}
-
 sub on_message {
     my $m = shift;
@@ -50,8 +41,4 @@
 BarnOwl::Completion::register_completer(zcrypt    => \&complete_zwrite);
 
-# TODO: Handle aliases transparently in the core completion code?
-BarnOwl::Completion::register_completer(sub       => \&complete_sub);
-BarnOwl::Completion::register_completer(subscribe => \&complete_sub);
-
 $BarnOwl::Hooks::newMessage->add("BarnOwl::Complete::Zephyr::on_message");
 
Index: perl/lib/BarnOwl/Completion.pm
===================================================================
--- perl/lib/BarnOwl/Completion.pm	(revision f9875044fd71f0949f0ed37bb369246127f6b284)
+++ perl/lib/BarnOwl/Completion.pm	(revision c4efb4645adc5fd8c82354df981a846bd942866b)
@@ -18,5 +18,5 @@
                         point_move replace_region);
 
-use List::Util qw(max first);
+use List::Util qw(min first);
 
 our %completers = ();
@@ -76,5 +76,5 @@
 sub common_prefix {
     my @words = @_;
-    my $len   = max(map {length($_)} @words);
+    my $len   = min(map {length($_)} @words);
     my $pfx = '';
     for my $i (1..$len) {
Index: perl/modules/IRC/lib/BarnOwl/Module/IRC.pm
===================================================================
--- perl/modules/IRC/lib/BarnOwl/Module/IRC.pm	(revision 96f7b07abe4fed9ababf9c2ac07b44c6c092d98e)
+++ perl/modules/IRC/lib/BarnOwl/Module/IRC.pm	(revision ab9cd8fb253006464aab9dfd1a01bb65b655f080)
@@ -18,4 +18,5 @@
 use BarnOwl::Message::IRC;
 use BarnOwl::Module::IRC::Connection qw(is_private);
+use BarnOwl::Module::IRC::Completion;
 
 use Net::IRC;
Index: perl/modules/IRC/lib/BarnOwl/Module/IRC/Completion.pm
===================================================================
--- perl/modules/IRC/lib/BarnOwl/Module/IRC/Completion.pm	(revision 216b1d0da99f45529967a1f7fc74efcba998bec7)
+++ perl/modules/IRC/lib/BarnOwl/Module/IRC/Completion.pm	(revision 216b1d0da99f45529967a1f7fc74efcba998bec7)
@@ -0,0 +1,97 @@
+use strict;
+use warnings;
+
+package BarnOwl::Module::IRC::Completion;
+
+use BarnOwl::Completion::Util qw(complete_flags);
+
+my %networks = ();
+my %dests = ();
+my %servers = ();
+
+sub complete_networks { keys %networks }
+sub complete_dests    { keys %dests }
+sub complete_channels { grep /^#/, keys %dests }
+sub complete_nicks    { grep /^[^#]/, keys %dests }
+sub complete_servers  { keys %servers }
+
+sub complete_irc_connect {
+    my $ctx = shift;
+    return complete_flags($ctx,
+        [qw(-s)],
+        {
+            "-a" => \&complete_networks,
+            "-p" => sub {},
+            "-n" => sub {},
+        },
+        \&complete_servers
+       );
+}
+
+sub complete_irc_network {
+    my $ctx = shift;
+    return complete_flags($ctx,
+        [],
+        {
+            "-a" => \&complete_networks,
+        },
+       );
+}
+
+sub complete_irc_dest {
+    my $ctx = shift;
+    return complete_flags($ctx,
+        [],
+        {
+            "-a" => \&complete_networks,
+        },
+        \&complete_dests
+       );
+}
+
+sub complete_irc_channel {
+    my $ctx = shift;
+    return complete_flags($ctx,
+        [],
+        {
+            "-a" => \&complete_networks,
+        },
+        \&complete_channels
+       );
+}
+
+sub complete_irc_nick {
+    my $ctx = shift;
+    return complete_flags($ctx,
+        [],
+        {
+            "-a" => \&complete_networks,
+        },
+        \&complete_nicks
+       );
+}
+
+sub on_message {
+    my $m = shift;
+    return unless $m->type eq 'IRC';
+    $networks{$m->network} = 1;
+    $dests{$m->recipient} = 1;
+    $dests{$m->sender} = 1;
+    $servers{$m->server} = 1;
+}
+
+BarnOwl::Completion::register_completer('irc-connect'    => \&complete_irc_connect);
+BarnOwl::Completion::register_completer('irc-disconnect' => \&complete_irc_network);
+BarnOwl::Completion::register_completer('irc-msg'        => \&complete_irc_dest);
+BarnOwl::Completion::register_completer('irc-mode'       => \&complete_irc_dest);
+BarnOwl::Completion::register_completer('irc-join'       => \&complete_irc_channel);
+BarnOwl::Completion::register_completer('irc-part'       => \&complete_irc_channel);
+BarnOwl::Completion::register_completer('irc-names'      => \&complete_irc_channel);
+BarnOwl::Completion::register_completer('irc-whois'      => \&complete_irc_nick);
+BarnOwl::Completion::register_completer('irc-motd'       => \&complete_irc_network);
+BarnOwl::Completion::register_completer('irc-topic'      => \&complete_irc_channel);
+BarnOwl::Completion::register_completer('irc-quote'      => \&complete_irc_network);
+
+$BarnOwl::Hooks::newMessage->add("BarnOwl::Module::IRC::Completion::on_message");
+
+1;
Index: perl/modules/Jabber/lib/BarnOwl/Module/Jabber.pm
===================================================================
--- perl/modules/Jabber/lib/BarnOwl/Module/Jabber.pm	(revision 004d68374da74406bb215031c1ec2d0c1b4f56e0)
+++ perl/modules/Jabber/lib/BarnOwl/Module/Jabber.pm	(revision 57ba9f1c9e6940e2becb6c4e748873c782b63acb)
@@ -19,4 +19,5 @@
 use BarnOwl::Module::Jabber::Connection;
 use BarnOwl::Module::Jabber::ConnectionManager;
+use BarnOwl::Completion::Util qw(complete_flags);
 
 use Authen::SASL qw(Perl);
@@ -62,4 +63,5 @@
 $conn ||= BarnOwl::Module::Jabber::ConnectionManager->new;
 our %vars;
+our %completion_jids;
 
 sub onStart {
@@ -164,4 +166,6 @@
 
     $blistStr .= sprintf '%-15s %s', $name, $buddy->GetJID();
+    $completion_jids{$name} = 1;
+    $completion_jids{$buddy->GetJID()} = 1;
 
     if ($res) {
@@ -427,5 +431,6 @@
                 BarnOwl::error( "Error in connect: " . join( " ", @result ) );
             } else {
-                $conn->getRosterFromJID($jidStr)->fetch();
+                my $roster = $conn->getRosterFromJID($jidStr);
+                $roster->fetch();
                 $client->PresenceSend( priority => 1 );
 		my $fullJid = $client->{SESSION}->{FULLJID} || $jidStr;
@@ -437,4 +442,12 @@
                 #queue_admin_msg("Connected to jabber as $fullJid ($client->{fileno})");
                 BarnOwl::add_dispatch($client->{fileno}, sub { $client->OwlProcess() });
+
+                # populate completion from roster.
+                for my $buddy ( $roster->jids('all') ) {
+                    my %jq  = $roster->query($buddy);
+                    my $name = $jq{name} || $buddy->GetUserID();
+                    $completion_jids{$name} = 1;
+                    $completion_jids{$buddy->GetJID()} = 1;
+                }
             }
         }
@@ -647,4 +660,5 @@
                                                    MaxChars => 0
                                                   });
+    $completion_jids{$muc} = 1;
     return;
 }
@@ -701,4 +715,5 @@
 
     my $presence = "JIDs present in " . $m->BaseJID;
+    $completion_jids{$m->BaseJID} = 1;
     if($m->Anonymous) {
         $presence .= " [anonymous MUC]";
@@ -875,4 +890,7 @@
     $name = "" unless (1 == scalar(@ARGV));
 
+    $completion_jids{$baseJID} = 1;
+    $completion_jids{$name} = 1 if $name;
+
     foreach my $to (@ARGV) {
         my %jq  = $roster->query($to);
@@ -1057,7 +1075,8 @@
 
 sub process_presence_available {
-    return unless (BarnOwl::getvar('jabber:show_logins') eq 'on');
     my ( $sid, $p ) = @_;
     my $from = $p->GetFrom('jid')->GetJID('base');
+    $completion_jids{$from} = 1;
+    return unless (BarnOwl::getvar('jabber:show_logins') eq 'on');
     my $to = $p->GetTo();
     my $type = $p->GetType();
@@ -1209,8 +1228,17 @@
               if ($connection->FindMUC(jid => $to));
         }
+
+        # Populate completion.
+        if ($dir eq 'in') {
+            $completion_jids{ $props{sender} }= 1;
+        }
+        else {
+            $completion_jids{ $props{recipient} } = 1;
+        }
     }
     elsif ( $jtype eq 'groupchat' ) {
         my $nick = $props{nick} = $from->GetResource();
         my $room = $props{room} = $from->GetJID('base');
+        $completion_jids{$room} = 1;
 
         $props{sender} = $nick || $room;
@@ -1384,3 +1412,22 @@
 }
 
+################################################################################
+### Completion
+
+sub complete_user_or_muc { return keys %completion_jids; }
+sub complete_account { return $conn->getJIDs(); }
+
+sub complete_jwrite {
+    my $ctx = shift;
+    return complete_flags($ctx,
+                          [qw(-t -i -s)],
+                          {
+                              "-a" => \&complete_account,
+                          },
+                          \&complete_user_or_muc
+        );
+}
+
+BarnOwl::Completion::register_completer(jwrite => sub { BarnOwl::Module::Jabber::complete_jwrite(@_) });
+
 1;
Index: perlglue.xs
===================================================================
--- perlglue.xs	(revision 6dc2d6b460d2b3cbeb2f8363c4dc6e65a7909663)
+++ perlglue.xs	(revision d77e909569f46d050c2125505e433957e2563f2d)
@@ -332,4 +332,26 @@
 	CODE:
 	owl_select_remove_perl_dispatch(fd);
+
+
+AV*
+all_filters()
+	PREINIT:
+		AV *filters;
+		owl_list *fl;
+		owl_filter *f;
+		int i;
+	CODE:
+	{
+		fl = owl_global_get_filterlist(&g);
+		filters = newAV();
+		for(i=0;i<owl_list_get_size(fl);i++) {
+			f = owl_list_get_element(fl, i);
+			av_push(filters, newSVpv(owl_filter_get_name(f), 0));
+		}
+		RETVAL = filters;
+		sv_2mortal((SV*)RETVAL);
+	}
+	OUTPUT:
+		RETVAL
 
 MODULE = BarnOwl		PACKAGE = BarnOwl::Internal
Index: t/completion.t
===================================================================
--- t/completion.t	(revision 7be5d8b6e180b287462defa361f336639cd5e84e)
+++ t/completion.t	(revision c4efb4645adc5fd8c82354df981a846bd942866b)
@@ -122,4 +122,6 @@
 is(BarnOwl::Completion::common_prefix(qw(abc abc)), 'abc');
 
+is(BarnOwl::Completion::common_prefix('a', ''), '');
+
 ## Test complete_flags
 
