Index: perl/modules/Facebook/README
===================================================================
--- perl/modules/Facebook/README	(revision 4b2300941dbf2e57524f7730fe82255ec11b3e39)
+++ perl/modules/Facebook/README	(revision 8b6208883c04d551ae374ef4fca9dec22b98964e)
@@ -32,10 +32,7 @@
     and blocks the entire BarnOwl interface.  We need to confront
     Perl's threading demon.
-  * Need to detect if you have two friends with the same name and
-    disambiguate if so.
-  * No messaging support.
-  * No auto-completion support.
-  * No posting to an arbitrary user's wall.
-  * See code comments for more work items!
+  * No messaging support. (We'll add it when Facebook makes the new endpoint.)
+  * Smarter name de-duplication (see code comments for details.)
+  * Grep for XXX and TODO for more work items.
 
 TECHNICAL NOTES
Index: perl/modules/Facebook/lib/BarnOwl/Module/Facebook.pm
===================================================================
--- perl/modules/Facebook/lib/BarnOwl/Module/Facebook.pm	(revision eb497a96f6a7cdfd6a3d386d075faa0c4412ff50)
+++ perl/modules/Facebook/lib/BarnOwl/Module/Facebook.pm	(revision 8b6208883c04d551ae374ef4fca9dec22b98964e)
@@ -123,7 +123,10 @@
 sub cmd_facebook {
     my $cmd = shift;
-    BarnOwl::start_edit_win("What's on your mind?", sub{ facebook(shift) });
-    # User prompt for other person's wall is "Write something..." which
-    # we will ostensibly check for soon.
+    my $user = shift;
+
+    BarnOwl::start_edit_win(
+        defined $user ? "Write something to $user..." : "What's on your mind?",
+        sub{ facebook($user, shift) }
+    );
 }
 
@@ -156,3 +159,8 @@
 BarnOwl::filter(qw{facebook type ^facebook$});
 
+# Autocompletion support
+
+sub complete_user { return keys %{$facebook_handle->{friends}}; }
+BarnOwl::Completion::register_completer(facebook => sub { complete_user(@_) });
+
 1;
Index: perl/modules/Facebook/lib/BarnOwl/Module/Facebook/Handle.pm
===================================================================
--- perl/modules/Facebook/lib/BarnOwl/Module/Facebook/Handle.pm	(revision eb207319e7d62245abef127a0eebbfe7084e779d)
+++ perl/modules/Facebook/lib/BarnOwl/Module/Facebook/Handle.pm	(revision 8b6208883c04d551ae374ef4fca9dec22b98964e)
@@ -80,6 +80,13 @@
         'facebook' => undef,
 
+        # Ideally this should be done using Facebook realtime updates,
+        # but we can't assume that the BarnOwl lives on a publically
+        # addressable server (XXX maybe we can setup an option for this.)
+        'last_friend_poll' => 0,
+        'friend_timer' => undef,
+
         # Initialized with our 'time', but will be synced to Facebook
-        # soon enough.
+        # soon enough. (Subtractive amount is just to preseed with some
+        # values.)
         'last_poll' => time - 60 * 60 * 24 * 2,
         'timer' => undef,
@@ -100,4 +107,7 @@
         # would need another hash for topic de-dup
         'topics' => {},
+
+        # deduplicated map of names to user ids
+        'friends' => {},
     };
 
@@ -125,4 +135,8 @@
 
     # Stop any existing timers.
+    if (defined $self->{friend_timer}) {
+        $self->{friend_timer}->stop;
+        $self->{friend_timer} = undef;
+    }
     if (defined $self->{timer}) {
         $self->{timer}->stop;
@@ -135,4 +149,10 @@
     }
 
+    $self->{friend_timer} = BarnOwl::Timer->new({
+        name     => "Facebook friend poll",
+        after    => $delay,
+        interval => 60 * 60 * 24,
+        cb       => sub { $weak->poll_friends if $weak }
+       });
     $self->{timer} = BarnOwl::Timer->new({
         name     => "Facebook poll",
@@ -142,4 +162,56 @@
        });
     # XXX implement message polling
+}
+
+sub poll_friends {
+    my $self = shift;
+
+    return unless BarnOwl::getvar('facebook:poll') eq 'on';
+    return unless $self->{logged_in};
+
+    my $friends = eval { $self->{facebook}->fetch('me/friends'); };
+    if ($@) {
+        warn "Poll failed $@";
+        return;
+    }
+
+    $self->{last_friend_poll} = time;
+    $self->{friends} = {};
+
+    for my $friend ( @{$friends->{data}} ) {
+        if (defined $self->{friends}{$friend->{name}}) {
+            # XXX We should try a little harder here, rather than just
+            # tacking on a number.  Ideally, we should be able to
+            # calculate some extra piece of information that the user
+            # needs to disambiguate between the two users.  An old
+            # version of Facebook used to disambiguate with your primary
+            # network (so you might have Edward Yang (MIT) and Edward
+            # Yang (Cambridge), the idea being that users in the same
+            # network would probably have already disambiguated
+            # themselves with middle names or nicknames.  We no longer
+            # get network information, since Facebook axed that
+            # information, but the Education/Work fields may still be
+            # a reasonable approximation (but which one do you pick?!
+            # The most recent one.)  Since getting this information
+            # involves extra queries, there are also caching and
+            # efficiency concerns.
+            #   We may want a facility for users to specify custom
+            # aliases for Facebook users, which are added into this
+            # hash.  See also username support.
+            warn "Duplicate friend name " . $friend->{name};
+            my $name = $friend->{name};
+            my $i = 2;
+            while (defined $self->{friends}{$friend->{name} . ' ' . $i}) { $i++; }
+            $self->{friends}{$friend->{name} . ' ' . $i} = $friend->{id};
+        } else {
+            $self->{friends}{$friend->{name}} = $friend->{id};
+        }
+    }
+
+    # XXX We should also have support for usernames, and not just real
+    # names. However, since this data is not returned by the friends
+    # query, it would require a rather expensive set of queries. We
+    # might try to preserve old data, but all-in-all it's a bit
+    # complicated, so we don't bother.
 }
 
@@ -283,6 +355,6 @@
     my $self = shift;
 
+    my $user = shift;
     my $msg = shift;
-    my $reply_to = shift;
 
     if (!defined $self->{facebook} || !$self->{logged_in}) {
@@ -290,5 +362,10 @@
         return;
     }
-    $self->{facebook}->add_post->set_message( $msg )->publish;
+    if (defined $user) {
+        $user = $self->{friends}{$user} || $user;
+        $self->{facebook}->add_post( $user )->set_message( $msg )->publish;
+    } else {
+        $self->{facebook}->add_post->set_message( $msg )->publish;
+    }
     $self->sleep(0);
 }
