+ return unless &logged_in($twit);
+
+ my ( $target, $text ) = split ' ', $data, 2;
+ unless ( $target and $text ) {
+ ¬ice("Usage: /dm <nick> <message>");
+ return;
+ }
+
+ &cmd_direct_as( "$user $data", $server, $win );
+}
+
+sub cmd_direct_as {
+ my ( $data, $server, $win ) = @_;
+
+ return unless &logged_in($twit);
+
+ my ( $username, $target, $text ) = split ' ', $data, 3;
+ unless ( $username and $target and $text ) {
+ ¬ice("Usage: /dm_as <username> <nick> <message>");
+ return;
+ }
+
+ return unless $username = &valid_username($username);
+
+ eval {
+ if ( $twits{$username}
+ ->new_direct_message( { user => $target, text => $text } ) )
+ {
+ ¬ice("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;
+ ¬ice("DM to $target failed");
+ }
+ };
+
+ if ($@) {
+ ¬ice("DM caused an error: $@");
+ return;
+ }
+}
+
+sub cmd_retweet {
+ my ( $data, $server, $win ) = @_;
+
+ return unless &logged_in($twit);
+
+ $data =~ s/^\s+|\s+$//;
+ unless ($data) {
+ ¬ice("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") ) {
+ ¬ice("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) {
+ ¬ice("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 } ) {
+ ¬ice("Can't find a tweet from $nick to retweet!");
+ return;
+ }
+
+ $id = $id_map{__indexes}{$nick} unless $id;
+ unless ( $id_map{ lc $nick }[$id] ) {
+ ¬ice("Can't find a tweet numbered $id from $nick to retweet!");
+ return;
+ }
+
+ unless ( $id_map{__tweets}{ lc $nick }[$id] ) {
+ ¬ice("The text of this tweet isn't saved, sorry!");
+ 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 {
+ $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]
+ }
+ )
+ )
+ {
+ ¬ice("Update failed");
+ $success = 0;
+ }
+ };
+ return unless $success;
+
+ if ($@) {
+ ¬ice("Update caused an error: $@. Aborted");
+ return;
+ }
+
+ foreach ( $data =~ /@([-\w]+)/ ) {
+ $nicks{$1} = time;
+ }
+
+ ¬ice("Retweet sent");
+}
+
+sub cmd_tweet {
+ my ( $data, $server, $win ) = @_;
+
+ return unless &logged_in($twit);
+
+ $data =~ s/^\s+|\s+$//;
+ unless ($data) {
+ ¬ice("Usage: /tweet <update>");
+ return;
+ }
+
+ &cmd_tweet_as( "$user\@$defservice $data", $server, $win );
+}
+
+sub cmd_tweet_as {
+ my ( $data, $server, $win ) = @_;
+
+ return unless &logged_in($twit);
+
+ $data =~ s/^\s+|\s+$//;
+ $data =~ s/\s\s+/ /g;
+ my ( $username, $data ) = split ' ', $data, 2;
+
+ unless ( $username and $data ) {
+ ¬ice("Usage: /tweet_as <username> <update>");
+ return;
+ }
+
+ return unless $username = &valid_username($username);
+
+ $data = &shorten($data);
+
+ return if &too_long($data);
+
+ my $success = 1;
+ eval {
+ unless ( $twits{$username}->update($data) )
+ {
+ ¬ice("Update failed");
+ $success = 0;
+ }
+ };
+ return unless $success;
+
+ if ($@) {
+ ¬ice("Update caused an error: $@. Aborted.");
+ return;
+ }
+
+ foreach ( $data =~ /@([-\w]+)/ ) {
+ $nicks{$1} = time;
+ }
+
+ my $away = &update_away($data);
+
+ ¬ice( "Update sent" . ( $away ? " (and away msg set)" : "" ) );
+}
+
+sub cmd_reply {
+ my ( $data, $server, $win ) = @_;
+
+ return unless &logged_in($twit);
+
+ $data =~ s/^\s+|\s+$//;
+ unless ($data) {
+ ¬ice("Usage: /reply <nick[:num]> <update>");
+ return;
+ }
+
+ my ( $id, $data ) = split ' ', $data, 2;
+ unless ( $id and $data ) {
+ ¬ice("Usage: /reply <nick[:num]> <update>");
+ return;
+ }
+
+ &cmd_reply_as( "$user $id $data", $server, $win );
+}
+
+sub cmd_reply_as {
+ my ( $data, $server, $win ) = @_;
+
+ unless ( Irssi::settings_get_bool("twirssi_track_replies") ) {
+ ¬ice("twirssi_track_replies is required in order to reply to "
+ . "specific tweets. Either enable it, or just use /tweet "
+ . "\@username <text>." );
+ return;
+ }
+
+ return unless &logged_in($twit);
+
+ $data =~ s/^\s+|\s+$//;
+ my ( $username, $id, $data ) = split ' ', $data, 3;
+
+ unless ( $username and $data ) {
+ ¬ice("Usage: /reply_as <username> <nick[:num]> <update>");
+ return;
+ }
+
+ return unless $username = &valid_username($username);
+
+ my $nick;
+ $id =~ s/[^\w\d\-:]+//g;
+ ( $nick, $id ) = split /:/, $id;
+ unless ( exists $id_map{ lc $nick } ) {
+ ¬ice("Can't find a tweet from $nick to reply to!");
+ return;
+ }
+
+ $id = $id_map{__indexes}{$nick} unless $id;
+ unless ( $id_map{ lc $nick }[$id] ) {
+ ¬ice("Can't find a tweet numbered $id from $nick to reply to!");
+ return;
+ }
+
+ if ( Irssi::settings_get_bool("twirssi_replies_autonick") ) {
+
+ # remove any @nick at the beginning of the reply, as we'll add it anyway
+ $data =~ s/^\s*\@?$nick\s*//;
+ $data = "\@$nick " . $data;
+ }
+
+ $data = &shorten($data);
+
+ 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]
+ }
+ )
+ )
+ {
+ ¬ice("Update failed");
+ $success = 0;
+ }
+ };
+ return unless $success;
+
+ if ($@) {
+ ¬ice("Update caused an error: $@. Aborted");
+ return;
+ }
+
+ foreach ( $data =~ /@([-\w]+)/ ) {
+ $nicks{$1} = time;
+ }
+
+ my $away = &update_away($data);
+
+ ¬ice( "Update sent" . ( $away ? " (and away msg set)" : "" ) );
+}
+
+sub gen_cmd {
+ my ( $usage_str, $api_name, $post_ref ) = @_;
+
+ return sub {
+ my ( $data, $server, $win ) = @_;
+
+ return unless &logged_in($twit);
+
+ $data =~ s/^\s+|\s+$//;
+ unless ($data) {
+ ¬ice("Usage: $usage_str");
+ return;
+ }
+
+ my $success = 1;
+ eval {
+ unless ( $twit->$api_name($data) )
+ {
+ ¬ice("$api_name failed");
+ $success = 0;
+ }
+ };
+ return unless $success;
+
+ if ($@) {
+ ¬ice("$api_name caused an error. Aborted.");
+ return;
+ }
+
+ &$post_ref($data) if $post_ref;
+ }
+}
+
+sub cmd_switch {
+ my ( $data, $server, $win ) = @_;
+
+ $data =~ s/^\s+|\s+$//g;
+ $data = &normalize_username($data);
+ if ( exists $twits{$data} ) {
+ ¬ice("Switching to $data");
+ $twit = $twits{$data};
+ if ( $data =~ /(.*)\@(.*)/ ) {
+ $user = $1;
+ $defservice = $2;
+ } else {
+ ¬ice("Couldn't figure out what service '$data' is on");
+ }
+ } else {
+ ¬ice("Unknown user $data");
+ }
+}
+
+sub cmd_logout {
+ my ( $data, $server, $win ) = @_;
+
+ $data =~ s/^\s+|\s+$//g;
+ $data = $user unless $data;
+ return unless $data = &valid_username($data);
+
+ ¬ice("Logging out $data...");
+ $twits{$data}->end_session();
+ delete $twits{$data};
+ undef $twit;
+ if ( keys %twits ) {
+ &cmd_switch( ( keys %twits )[0], $server, $win );
+ } else {
+ Irssi::timeout_remove($poll) if $poll;
+ undef $poll;
+ }
+}
+
+sub cmd_login {
+ my ( $data, $server, $win ) = @_;
+ my $pass;
+ if ($data) {
+ ( $user, $pass ) = split ' ', $data, 2;
+ } elsif ( my $autouser = Irssi::settings_get_str("twitter_usernames")
+ and my $autopass = Irssi::settings_get_str("twitter_passwords") )
+ {
+ my @user = split /\s*,\s*/, $autouser;
+ my @pass = split /\s*,\s*/, $autopass;
+
+ # 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 ) {
+ ¬ice("Number of usernames doesn't match "
+ . "the number of passwords - auto-login failed" );
+ } else {
+ my ( $u, $p );
+ while ( @user and @unescaped ) {
+ $u = shift @user;
+ $p = shift @unescaped;
+ &cmd_login("$u $p");
+ }
+ return;
+ }
+ } else {
+ ¬ice("/twitter_login requires either a username and password "
+ . "or twitter_usernames and twitter_passwords to be set." );
+ return;
+ }
+
+ %friends = %nicks = ();
+
+ 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 ($@) {
+ ¬ice(
+ "Failed to load Net::$service when trying to log in as $user: $@");
+ return;
+ }
+
+ $twit = "Net::$service"->new(
+ username => $user,
+ password => $pass,
+ source => "twirssi",
+ ssl => Irssi::settings_get_bool("twirssi_avoid_ssl") ? 0 : 1,
+ );
+