r599 - fix nick in retweet
[twirssi-net-twitter-lite.git] / twirssi.pl
index b4094ad..e6142cd 100644 (file)
@@ -6,13 +6,12 @@ use HTML::Entities;
 use File::Temp;
 use LWP::Simple;
 use Data::Dumper;
 use File::Temp;
 use LWP::Simple;
 use Data::Dumper;
-use Net::Twitter;
 $Data::Dumper::Indent = 1;
 
 use vars qw($VERSION %IRSSI);
 
 $Data::Dumper::Indent = 1;
 
 use vars qw($VERSION %IRSSI);
 
-$VERSION = "2.0.3";
-my ($REV) = '$Rev: 475 $' =~ /(\d+)/;
+$VERSION = "2.2.1beta";
+my ($REV) = '$Rev: 599 $' =~ /(\d+)/;
 %IRSSI = (
     authors     => 'Dan Boger',
     contact     => 'zigdon@gmail.com',
 %IRSSI = (
     authors     => 'Dan Boger',
     contact     => 'zigdon@gmail.com',
@@ -21,19 +20,21 @@ my ($REV) = '$Rev: 475 $' =~ /(\d+)/;
       . 'Can optionally set your bitlbee /away message to same',
     license => 'GNU GPL v2',
     url     => 'http://twirssi.com',
       . 'Can optionally set your bitlbee /away message to same',
     license => 'GNU GPL v2',
     url     => 'http://twirssi.com',
-    changed => '$Date: 2009-02-16 20:36:03 -0800 (Mon, 16 Feb 2009) $',
+    changed => '$Date: 2009-04-07 07:49:19 -0700 (Tue, 07 Apr 2009) $',
 );
 
 my $window;
 my $twit;
 my %twits;
 my $user;
 );
 
 my $window;
 my $twit;
 my %twits;
 my $user;
+my $defservice;
 my $poll;
 my $last_poll;
 my %nicks;
 my %friends;
 my %tweet_cache;
 my %id_map;
 my $poll;
 my $last_poll;
 my %nicks;
 my %friends;
 my %tweet_cache;
 my %id_map;
+my $failwhale            = 0;
 my %irssi_to_mirc_colors = (
     '%k' => '01',
     '%r' => '05',
 my %irssi_to_mirc_colors = (
     '%k' => '01',
     '%r' => '05',
@@ -78,24 +79,128 @@ sub cmd_direct_as {
         return;
     }
 
         return;
     }
 
-    return unless &valid_username($username);
+    return unless $username = &valid_username($username);
 
     eval {
 
     eval {
-        unless ( $twits{$username}
+        if ( $twits{$username}
             ->new_direct_message( { user => $target, text => $text } ) )
         {
             ->new_direct_message( { user => $target, text => $text } ) )
         {
+            &notice("DM sent to $target");
+            $nicks{$target} = time;
+        } else {
+            my $error;
+            eval {
+                $error = JSON::Any->jsonToObj( $twits{$username}->get_error() );
+                $error = $error->{error};
+            };
+            die $error if $error;
             &notice("DM to $target failed");
             &notice("DM to $target failed");
-            return;
         }
     };
 
     if ($@) {
         }
     };
 
     if ($@) {
-        &notice("DM caused an error: $@.  Aborted");
+        &notice("DM caused an error: $@");
+        return;
+    }
+}
+
+sub cmd_retweet {
+    my ( $data, $server, $win ) = @_;
+
+    return unless &logged_in($twit);
+
+    $data =~ s/^\s+|\s+$//;
+    unless ($data) {
+        &notice("Usage: /retweet <nick[:num]> [comment]");
+        return;
+    }
+
+    my ( $id, $data ) = split ' ', $data, 2;
+
+    &cmd_retweet_as( "$user $id $data", $server, $win );
+}
+
+sub cmd_retweet_as {
+    my ( $data, $server, $win ) = @_;
+
+    unless ( Irssi::settings_get_bool("twirssi_track_replies") ) {
+        &notice("twirssi_track_replies is required in order to reteet.");
+        return;
+    }
+
+    return unless &logged_in($twit);
+
+    $data =~ s/^\s+|\s+$//;
+    my ( $username, $id, $data ) = split ' ', $data, 3;
+
+    unless ( $username ) {
+        &notice("Usage: /retweet_as <username> <nick[:num]> [comment]");
+        return;
+    }
+
+    return unless $username = &valid_username($username);
+
+    my $nick;
+    $id =~ s/[^\w\d\-:]+//g;
+    ( $nick, $id ) = split /:/, $id;
+    unless ( exists $id_map{ lc $nick } ) {
+        &notice("Can't find a tweet from $nick to retweet!");
+        return;
+    }
+
+    $id = $id_map{__indexes}{$nick} unless $id;
+    unless ( $id_map{ lc $nick }[$id] ) {
+        &notice("Can't find a tweet numbered $id from $nick to retweet!");
+        return;
+    }
+
+    unless ( $id_map{__tweets}{ lc $nick }[$id] ) {
+        &notice("The text of this tweet isn't saved, sorry!");
         return;
         return;
+    }
+
+# Irssi::settings_add_str( "twirssi", "twirssi_retweet_format", 'RT $n: $t ${-- $c$}' );
+    my $text = Irssi::settings_get_str("twirssi_retweet_format");
+    $text =~ s/\$n/\@$nick/g;
+    if ($data) {
+        $text =~ s/\${|\$}//g;
+        $text =~ s/\$c/$data/;
     } else {
     } else {
-        &notice("DM sent to $target");
-        $nicks{$target} = time;
+        $text =~ s/\${.*?\$}//;
     }
     }
+    $text =~ s/\$t/$id_map{__tweets}{ lc $nick }[$id]/;
+
+    $data = &shorten($text);
+
+    return if &too_long($data);
+
+    my $success = 1;
+    eval {
+        unless (
+            $twits{$username}->update(
+                {
+                    status                => $data,
+                    in_reply_to_status_id => $id_map{ lc $nick }[$id]
+                }
+            )
+          )
+        {
+            &notice("Update failed");
+            $success = 0;
+        }
+    };
+    return unless $success;
+
+    if ($@) {
+        &notice("Update caused an error: $@.  Aborted");
+        return;
+    }
+
+    foreach ( $data =~ /@([-\w]+)/ ) {
+        $nicks{$1} = time;
+    }
+
+    &notice("Retweet sent");
 }
 
 sub cmd_tweet {
 }
 
 sub cmd_tweet {
@@ -109,7 +214,7 @@ sub cmd_tweet {
         return;
     }
 
         return;
     }
 
-    &cmd_tweet_as( "$user $data", $server, $win );
+    &cmd_tweet_as( "$user\@$defservice $data", $server, $win );
 }
 
 sub cmd_tweet_as {
 }
 
 sub cmd_tweet_as {
@@ -126,31 +231,24 @@ sub cmd_tweet_as {
         return;
     }
 
         return;
     }
 
-    return unless &valid_username($username);
+    return unless $username = &valid_username($username);
 
 
-    if ( &too_long( $data, 1 )
-        and Irssi::settings_get_str("short_url_provider") )
-    {
-        foreach my $url ( $data =~ /(https?:\/\/\S+[\w\/])/g ) {
-            eval {
-                my $short = makeashorterlink($url);
-                $data =~ s/\Q$url/$short/g;
-            };
-        }
-    }
+    $data = &shorten($data);
 
     return if &too_long($data);
 
 
     return if &too_long($data);
 
+    my $success = 1;
     eval {
         unless ( $twits{$username}->update($data) )
         {
             &notice("Update failed");
     eval {
         unless ( $twits{$username}->update($data) )
         {
             &notice("Update failed");
-            return;
+            $success = 0;
         }
     };
         }
     };
+    return unless $success;
 
     if ($@) {
 
     if ($@) {
-        &notice("Update caused an error.  Aborted.");
+        &notice("Update caused an error: $@.  Aborted.");
         return;
     }
 
         return;
     }
 
@@ -174,10 +272,9 @@ sub cmd_reply {
         return;
     }
 
         return;
     }
 
-    $data =~ s/^\s+|\s+$//;
     my ( $id, $data ) = split ' ', $data, 2;
     unless ( $id and $data ) {
     my ( $id, $data ) = split ' ', $data, 2;
     unless ( $id and $data ) {
-        &notice("Usage: /reply_as <nick[:num]> <update>");
+        &notice("Usage: /reply <nick[:num]> <update>");
         return;
     }
 
         return;
     }
 
@@ -204,7 +301,7 @@ sub cmd_reply_as {
         return;
     }
 
         return;
     }
 
-    return unless &valid_username($username);
+    return unless $username = &valid_username($username);
 
     my $nick;
     $id =~ s/[^\w\d\-:]+//g;
 
     my $nick;
     $id =~ s/[^\w\d\-:]+//g;
@@ -227,17 +324,11 @@ sub cmd_reply_as {
         $data = "\@$nick " . $data;
     }
 
         $data = "\@$nick " . $data;
     }
 
-    if ( Irssi::settings_get_str("short_url_provider") ) {
-        foreach my $url ( $data =~ /(https?:\/\/\S+[\w\/])/g ) {
-            eval {
-                my $short = makeashorterlink($url);
-                $data =~ s/\Q$url/$short/g;
-            };
-        }
-    }
+    $data = &shorten($data);
 
     return if &too_long($data);
 
 
     return if &too_long($data);
 
+    my $success = 1;
     eval {
         unless (
             $twits{$username}->update(
     eval {
         unless (
             $twits{$username}->update(
@@ -249,12 +340,13 @@ sub cmd_reply_as {
           )
         {
             &notice("Update failed");
           )
         {
             &notice("Update failed");
-            return;
+            $success = 0;
         }
     };
         }
     };
+    return unless $success;
 
     if ($@) {
 
     if ($@) {
-        &notice("Update caused an error.  Aborted");
+        &notice("Update caused an error: $@.  Aborted");
         return;
     }
 
         return;
     }
 
@@ -281,13 +373,15 @@ sub gen_cmd {
             return;
         }
 
             return;
         }
 
+        my $success = 1;
         eval {
             unless ( $twit->$api_name($data) )
             {
                 &notice("$api_name failed");
         eval {
             unless ( $twit->$api_name($data) )
             {
                 &notice("$api_name failed");
-                return;
+                $success = 0;
             }
         };
             }
         };
+        return unless $success;
 
         if ($@) {
             &notice("$api_name caused an error.  Aborted.");
 
         if ($@) {
             &notice("$api_name caused an error.  Aborted.");
@@ -302,10 +396,16 @@ sub cmd_switch {
     my ( $data, $server, $win ) = @_;
 
     $data =~ s/^\s+|\s+$//g;
     my ( $data, $server, $win ) = @_;
 
     $data =~ s/^\s+|\s+$//g;
+    $data = &normalize_username($data);
     if ( exists $twits{$data} ) {
         &notice("Switching to $data");
         $twit = $twits{$data};
     if ( exists $twits{$data} ) {
         &notice("Switching to $data");
         $twit = $twits{$data};
-        $user = $data;
+        if ( $data =~ /(.*)\@(.*)/ ) {
+            $user       = $1;
+            $defservice = $2;
+        } else {
+            &notice("Couldn't figure out what service '$data' is on");
+        }
     } else {
         &notice("Unknown user $data");
     }
     } else {
         &notice("Unknown user $data");
     }
@@ -316,7 +416,7 @@ sub cmd_logout {
 
     $data =~ s/^\s+|\s+$//g;
     $data = $user unless $data;
 
     $data =~ s/^\s+|\s+$//g;
     $data = $user unless $data;
-    return unless &valid_username($data);
+    return unless $data = &valid_username($data);
 
     &notice("Logging out $data...");
     $twits{$data}->end_session();
 
     &notice("Logging out $data...");
     $twits{$data}->end_session();
@@ -340,14 +440,26 @@ sub cmd_login {
     {
         my @user = split /\s*,\s*/, $autouser;
         my @pass = split /\s*,\s*/, $autopass;
     {
         my @user = split /\s*,\s*/, $autouser;
         my @pass = split /\s*,\s*/, $autopass;
-        if ( @user != @pass ) {
+
+        # if a password ends with a '\', it was meant to escape the comma, and
+        # it should be concatinated with the next one
+        my @unescaped;
+        while (@pass) {
+            my $p = shift @pass;
+            while ( $p =~ /\\$/ and @pass ) {
+                $p .= "," . shift @pass;
+            }
+            push @unescaped, $p;
+        }
+
+        if ( @user != @unescaped ) {
             &notice("Number of usernames doesn't match "
                   . "the number of passwords - auto-login failed" );
         } else {
             my ( $u, $p );
             &notice("Number of usernames doesn't match "
                   . "the number of passwords - auto-login failed" );
         } else {
             my ( $u, $p );
-            while ( @user and @pass ) {
+            while ( @user and @unescaped ) {
                 $u = shift @user;
                 $u = shift @user;
-                $p = shift @pass;
+                $p = shift @unescaped;
                 &cmd_login("$u $p");
             }
             return;
                 &cmd_login("$u $p");
             }
             return;
@@ -360,14 +472,29 @@ sub cmd_login {
 
     %friends = %nicks = ();
 
 
     %friends = %nicks = ();
 
-    $twit = Net::Twitter->new(
+    my $service;
+    if ( $user =~ /^(.*)@(twitter|identica)$/ ) {
+        ( $user, $service ) = ( $1, $2 );
+    } else {
+        $service = Irssi::settings_get_str("twirssi_default_service");
+    }
+    $defservice = $service = ucfirst lc $service;
+
+    eval "use Net::$service";
+    if ($@) {
+        &notice(
+            "Failed to load Net::$service when trying to log in as $user: $@");
+        return;
+    }
+
+    $twit = "Net::$service"->new(
         username => $user,
         password => $pass,
         source   => "twirssi"
     );
 
     unless ( $twit->verify_credentials() ) {
         username => $user,
         password => $pass,
         source   => "twirssi"
     );
 
     unless ( $twit->verify_credentials() ) {
-        &notice("Login as $user failed");
+        &notice("Login as $user\@$service failed");
         $twit = undef;
         if ( keys %twits ) {
             &cmd_switch( ( keys %twits )[0], $server, $win );
         $twit = undef;
         if ( keys %twits ) {
             &cmd_switch( ( keys %twits )[0], $server, $win );
@@ -385,10 +512,10 @@ sub cmd_login {
             return;
         }
 
             return;
         }
 
-        $twits{$user} = $twit;
+        $twits{"$user\@$service"} = $twit;
         Irssi::timeout_remove($poll) if $poll;
         $poll = Irssi::timeout_add( &get_poll_time * 1000, \&get_updates, "" );
         Irssi::timeout_remove($poll) if $poll;
         $poll = Irssi::timeout_add( &get_poll_time * 1000, \&get_updates, "" );
-        &notice("Logged in as $user, loading friends list...");
+        &notice("Logged in as $user\@$service, loading friends list...");
         &load_friends();
         &notice( "loaded friends: ", scalar keys %friends );
         if ( Irssi::settings_get_bool("twirssi_first_run") ) {
         &load_friends();
         &notice( "loaded friends: ", scalar keys %friends );
         if ( Irssi::settings_get_bool("twirssi_first_run") ) {
@@ -402,7 +529,7 @@ sub cmd_login {
         }
         %nicks = %friends;
         $nicks{$user} = 0;
         }
         %nicks = %friends;
         $nicks{$user} = 0;
-        &get_updates;
+        return 1;
     } else {
         &notice("Login failed");
     }
     } else {
         &notice("Login failed");
     }
@@ -490,15 +617,8 @@ sub cmd_upgrade {
         return;
     }
 
         return;
     }
 
-    if ( not -x "/usr/bin/md5sum" and not $data ) {
-        &notice(
-"/usr/bin/md5sum can't be found - try '/twirssi_upgrade nomd5' to skip MD5 verification"
-        );
-        return;
-    }
-
     my $md5;
     my $md5;
-    unless ($data) {
+    unless ( $data or Irssi::settings_get_bool("twirssi_upgrade_beta") ) {
         eval { use Digest::MD5; };
 
         if ($@) {
         eval { use Digest::MD5; };
 
         if ($@) {
@@ -532,11 +652,14 @@ sub cmd_upgrade {
         }
     }
 
         }
     }
 
-    my $URL = "http://twirssi.com/twirssi.pl";
+    my $URL =
+      Irssi::settings_get_bool("twirssi_upgrade_beta")
+      ? "http://github.com/zigdon/twirssi/raw/master/twirssi.pl"
+      : "http://twirssi.com/twirssi.pl";
     &notice("Downloading twirssi from $URL");
     LWP::Simple::getstore( $URL, "$loc.upgrade" );
 
     &notice("Downloading twirssi from $URL");
     LWP::Simple::getstore( $URL, "$loc.upgrade" );
 
-    unless ($data) {
+    unless ( $data or Irssi::settings_get_bool("twirssi_upgrade_beta") ) {
         unless ( open( NEW, "$loc.upgrade" ) ) {
             &notice(
 "Failed to read $loc.upgrade.  Check that /set twirssi_location is set to the correct location."
         unless ( open( NEW, "$loc.upgrade" ) ) {
             &notice(
 "Failed to read $loc.upgrade.  Check that /set twirssi_location is set to the correct location."
@@ -628,6 +751,7 @@ sub get_updates {
     return unless &logged_in($twit);
 
     my ( $fh, $filename ) = File::Temp::tempfile();
     return unless &logged_in($twit);
 
     my ( $fh, $filename ) = File::Temp::tempfile();
+    binmode( $fh, ":utf8" );
     my $pid = fork();
 
     if ($pid) {    # parent
     my $pid = fork();
 
     if ($pid) {    # parent
@@ -641,9 +765,7 @@ sub get_updates {
         my $new_poll = time;
 
         my $error = 0;
         my $new_poll&