+ my $rate_limit = $twit->rate_limit_status();
+ if ( $rate_limit and $rate_limit->{remaining_hits} < 1 ) {
+ ¬ice(
+ "Rate limit exceeded, try again after $rate_limit->{reset_time}");
+ $twit = undef;
+ return;
+ }
+
+ print "saving object for $user\@$service" if &debug;
+ $twits{"$user\@$service"} = $twit;
+ Irssi::timeout_remove($poll) if $poll;
+ $poll = Irssi::timeout_add( &get_poll_time * 1000, \&get_updates, "" );
+ ¬ice("Logged in as $user\@$service, loading friends list...");
+ &load_friends();
+ ¬ice( "loaded friends: " . scalar keys %friends );
+ if ( Irssi::settings_get_bool("twirssi_first_run") ) {
+ Irssi::settings_set_bool( "twirssi_first_run", 0 );
+ }
+ %nicks = %friends;
+ $nicks{$user} = 0;
+ return 1;
+}
+
+sub cmd_add_follow {
+ my ( $data, $server, $win ) = @_;
+
+ unless ($data) {
+ ¬ice("Usage: /twitter_add_follow_extra <username>");
+ return;
+ }
+
+ $data =~ s/^\s+|\s+$//;
+ $data =~ s/^\@//;
+ $data = lc $data;
+
+ if ( exists $id_map{__fixreplies}{"$user\@$defservice"}{$data} ) {
+ ¬ice("Already following all replies by \@$data");
+ return;
+ }
+
+ $id_map{__fixreplies}{"$user\@$defservice"}{$data} = 1;
+ ¬ice("Will now follow all replies by \@$data");
+}
+
+sub cmd_del_follow {
+ my ( $data, $server, $win ) = @_;
+
+ unless ($data) {
+ ¬ice("Usage: /twitter_del_follow_extra <username>");
+ return;
+ }
+
+ $data =~ s/^\s+|\s+$//;
+ $data =~ s/^\@//;
+ $data = lc $data;
+
+ unless ( exists $id_map{__fixreplies}{"$user\@$defservice"}{$data} ) {
+ ¬ice("Wasn't following all replies by \@$data");
+ return;
+ }
+
+ delete $id_map{__fixreplies}{"$user\@$defservice"}{$data};
+ ¬ice("Will no longer follow all replies by \@$data");
+}
+
+sub cmd_list_follow {
+ my ( $data, $server, $win ) = @_;
+
+ my $found = 0;
+ foreach my $suser ( sort keys %{ $id_map{__fixreplies} } ) {
+ my $frusers;
+ foreach my $fruser ( sort keys %{ $id_map{__fixreplies}{$suser} } ) {
+ $frusers = $frusers ? "$frusers, $fruser" : $fruser;
+ }
+ if ($frusers) {
+ $found = 1;
+ ¬ice("Following all replies as \@$suser: $frusers");
+ }
+ }
+
+ unless ($found) {
+ ¬ice("Not following all replies by anyone");
+ }
+}
+
+sub cmd_add_search {
+ my ( $data, $server, $win ) = @_;
+
+ unless ( $twit and $twit->can('search') ) {
+ ¬ice("ERROR: Your version of Net::Twitter ($Net::Twitter::VERSION) "
+ . "doesn't support searches." );
+ return;
+ }
+
+ $data =~ s/^\s+|\s+$//;
+ $data = lc $data;
+
+ unless ($data) {
+ ¬ice("Usage: /twitter_subscribe <topic>");
+ return;
+ }
+
+ if ( exists $id_map{__searches}{"$user\@$defservice"}{$data} ) {
+ ¬ice("Already had a subscription for '$data'");
+ return;
+ }
+
+ $id_map{__searches}{"$user\@$defservice"}{$data} = 1;
+ ¬ice("Added subscription for '$data'");
+}
+
+sub cmd_del_search {
+ my ( $data, $server, $win ) = @_;
+
+ unless ( $twit and $twit->can('search') ) {
+ ¬ice("ERROR: Your version of Net::Twitter ($Net::Twitter::VERSION) "
+ . "doesn't support searches." );
+ return;
+ }
+ $data =~ s/^\s+|\s+$//;
+ $data = lc $data;
+
+ unless ($data) {
+ ¬ice("Usage: /twitter_unsubscribe <topic>");
+ return;
+ }
+
+ unless ( exists $id_map{__searches}{"$user\@$defservice"}{$data} ) {
+ ¬ice("No subscription found for '$data'");
+ return;
+ }
+
+ delete $id_map{__searches}{"$user\@$defservice"}{$data};
+ ¬ice("Removed subscription for '$data'");
+}
+
+sub cmd_list_search {
+ my ( $data, $server, $win ) = @_;
+
+ my $found = 0;
+ foreach my $suser ( sort keys %{ $id_map{__searches} } ) {
+ my $topics;
+ foreach my $topic ( sort keys %{ $id_map{__searches}{$suser} } ) {
+ $topics = $topics ? "$topics, $topic" : $topic;
+ }
+ if ($topics) {
+ $found = 1;
+ ¬ice("Search subscriptions for \@$suser: $topics");
+ }
+ }
+
+ unless ($found) {
+ ¬ice("No search subscriptions set up");
+ }
+}
+
+sub cmd_upgrade {
+ my ( $data, $server, $win ) = @_;
+
+ my $loc = Irssi::settings_get_str("twirssi_location");
+ unless ( -w $loc ) {
+ ¬ice("$loc isn't writable, can't upgrade."
+ . " Perhaps you need to /set twirssi_location?" );
+ return;
+ }
+
+ my $md5;
+ unless ( $data or Irssi::settings_get_bool("twirssi_upgrade_beta") ) {
+ eval { use Digest::MD5; };
+
+ if ($@) {
+ ¬ice("Failed to load Digest::MD5."
+ . " Try '/twirssi_upgrade nomd5' to skip MD5 verification" );
+ return;
+ }
+
+ $md5 = get("http://twirssi.com/md5sum");
+ chomp $md5;
+ $md5 =~ s/ .*//;
+ unless ($md5) {
+ ¬ice("Failed to download md5sum from peeron! Aborting.");
+ return;
+ }
+
+ unless ( open( CUR, $loc ) ) {
+ ¬ice("Failed to read $loc."
+ . " Check that /set twirssi_location is set to the correct location."
+ );
+ return;
+ }
+
+ my $cur_md5 = Digest::MD5::md5_hex(<CUR>);
+ close CUR;
+
+ if ( $cur_md5 eq $md5 ) {
+ ¬ice("Current twirssi seems to be up to date.");
+ return;
+ }
+ }
+
+ my $URL =
+ Irssi::settings_get_bool("twirssi_upgrade_beta")
+ ? "http://github.com/zigdon/twirssi/raw/master/twirssi.pl"
+ : "http://twirssi.com/twirssi.pl";
+ ¬ice("Downloading twirssi from $URL");
+ LWP::Simple::getstore( $URL, "$loc.upgrade" );
+
+ unless ( -s "$loc.upgrade" ) {
+ ¬ice("Failed to save $loc.upgrade."
+ . " Check that /set twirssi_location is set to the correct location."
+ );
+ return;
+ }
+
+ unless ( $data or Irssi::settings_get_bool("twirssi_upgrade_beta") ) {
+ unless ( open( NEW, "$loc.upgrade" ) ) {
+ ¬ice("Failed to read $loc.upgrade."
+ . " Check that /set twirssi_location is set to the correct location."
+ );
+ return;
+ }
+
+ my $new_md5 = Digest::MD5::md5_hex(<NEW>);
+ close NEW;
+
+ if ( $new_md5 ne $md5 ) {
+ ¬ice("MD5 verification failed. expected $md5, got $new_md5");
+ return;
+ }
+ }
+
+ rename $loc, "$loc.backup"
+ or ¬ice("Failed to back up $loc: $!. Aborting")
+ and return;
+ rename "$loc.upgrade", $loc
+ or ¬ice("Failed to rename $loc.upgrade: $!. Aborting")
+ and return;