Index: lib/BarnOwl/Module/Twitter/Handle.pm
===================================================================
--- lib/BarnOwl/Module/Twitter/Handle.pm	(revision e4951ea0e778794ad7b7e603fbbb22615f4432e6)
+++ lib/BarnOwl/Module/Twitter/Handle.pm	(revision e4951ea0e778794ad7b7e603fbbb22615f4432e6)
@@ -15,4 +15,12 @@
 
 use Net::Twitter::Lite;
+BEGIN {
+    # Backwards compatibility with version of Net::Twitter::Lite that
+    # lack home_timeline.
+    if(!defined(*Net::Twitter::Lite::home_timeline{CODE})) {
+        *Net::Twitter::Lite::home_timeline =
+          \&Net::Twitter::Lite::friends_timeline;
+    }
+}
 use HTML::Entities;
 
@@ -71,6 +79,6 @@
     $self->{twitter}  = Net::Twitter::Lite->new(%twitter_args);
 
-    my $timeline = eval { $self->{twitter}->friends_timeline({count => 1}) };
-    warn "$@" if $@;
+    my $timeline = eval { $self->{twitter}->home_timeline({count => 1}) };
+    warn "$@\n" if $@;
 
     if(!defined($timeline)) {
@@ -86,5 +94,5 @@
         $self->{last_direct} = $self->{twitter}->direct_messages()->[0]{id};
     };
-    warn "$@" if $@;
+    warn "$@\n" if $@;
     $self->{last_direct} = 1 unless defined($self->{last_direct});
 
@@ -92,5 +100,5 @@
         $self->{twitter}->{ua}->timeout(1);
     };
-    warn "$@" if $@;
+    warn "$@\n" if $@;
 
     $self->sleep(0);
@@ -129,9 +137,37 @@
 }
 
+=head2 twitter_command COMMAND ARGS...
+
+Call the specified method on $self->{twitter} with an extended
+timeout. This is intended for interactive commands, with the theory
+that if the user explicitly requested an action, it is slightly more
+acceptable to hang the UI for a second or two than to fail just
+because Twitter is being slightly slow. Polling commands should be
+called normally, with the default (short) timeout, to prevent
+background Twitter suckage from hosing the UI normally.
+
+=cut
+
+sub twitter_command {
+    my $self = shift;
+    my $cmd = shift;
+
+    eval { $self->{twitter}->{ua}->timeout(5); };
+    my $result = eval {
+        $self->{twitter}->$cmd(@_);
+    };
+    my $error = $@;
+    eval { $self->{twitter}->{ua}->timeout(1); };
+    if ($error) {
+        die($error);
+    }
+    return $result;
+}
+
 sub twitter_error {
     my $self = shift;
 
     my $ratelimit = eval { $self->{twitter}->rate_limit_status };
-    warn "$@" if $@;
+    warn "$@\n" if $@;
     unless(defined($ratelimit) && ref($ratelimit) eq 'HASH') {
         # Twitter's probably just sucking, try again later.
@@ -157,6 +193,6 @@
     BarnOwl::debug("Polling " . $self->{cfg}->{account_nickname});
 
-    my $timeline = eval { $self->{twitter}->friends_timeline( { since_id => $self->{last_id} } ) };
-    warn "$@" if $@;
+    my $timeline = eval { $self->{twitter}->home_timeline( { since_id => $self->{last_id} } ) };
+    warn "$@\n" if $@;
     unless(defined($timeline) && ref($timeline) eq 'ARRAY') {
         $self->twitter_error();
@@ -166,5 +202,5 @@
     if ($self->{cfg}->{show_mentions}) {
         my $mentions = eval { $self->{twitter}->mentions( { since_id => $self->{last_id} } ) };
-        warn "$@" if $@;
+        warn "$@\n" if $@;
         unless (defined($mentions) && ref($mentions) eq 'ARRAY') {
             $self->twitter_error();
@@ -211,5 +247,5 @@
 
     my $direct = eval { $self->{twitter}->direct_messages( { since_id => $self->{last_direct} } ) };
-    warn "$@" if $@;
+    warn "$@\n" if $@;
     unless(defined($direct) && ref($direct) eq 'ARRAY') {
         $self->twitter_error();
@@ -228,5 +264,5 @@
                 location  => decode_entities($tweet->{sender}{location}||""),
                 body      => decode_entities($tweet->{text}),
-                isprivate => 'true',
+                private => 'true',
                 service   => $self->{cfg}->{service},
                 account   => $self->{cfg}->{account_nickname},
@@ -249,12 +285,11 @@
         $self->twitter_direct($1, $2);
     } elsif(defined $self->{twitter}) {
-        if(defined($reply_to)) {
-            $self->{twitter}->update({
-                status => $msg,
-                in_reply_to_status_id => $reply_to
-               });
-        } else {
-            $self->{twitter}->update($msg);
+        if(length($msg) > 140) {
+            die("Twitter: Message over 140 characters long.\n");
         }
+        $self->twitter_command('update', {
+            status => $msg,
+            defined($reply_to) ? (in_reply_to_status_id => $reply_to) : ()
+           });
     }
 }
@@ -266,5 +301,5 @@
     my $msg = shift;
     if(defined $self->{twitter}) {
-        $self->{twitter}->new_direct_message({
+        $self->twitter_command('new_direct_message', {
             user => $who,
             text => $msg
@@ -277,5 +312,5 @@
                 direction => 'out',
                 body      => $msg,
-                isprivate => 'true',
+                private => 'true',
                 service   => $self->{cfg}->{service},
                );
@@ -298,4 +333,14 @@
 }
 
+sub twitter_retweet {
+    my $self = shift;
+    my $msg = shift;
+
+    if($msg->service ne $self->{cfg}->{service}) {
+        die("Cannot retweet a message from a different service.\n");
+    }
+    $self->twitter_command(retweet => $msg->{status_id});
+}
+
 sub twitter_follow {
     my $self = shift;
@@ -303,5 +348,5 @@
     my $who = shift;
 
-    my $user = $self->{twitter}->create_friend($who);
+    my $user = $self->twitter_command('create_friend', $who);
     # returns a string on error
     if (defined $user && !ref $user) {
@@ -317,5 +362,5 @@
     my $who = shift;
 
-    my $user = $self->{twitter}->destroy_friend($who);
+    my $user = $self->twitter_command('destroy_friend', $who);
     # returns a string on error
     if (defined $user && !ref $user) {
