<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -6,13 +6,12 @@ use HTML::Entities;
 use File::Temp;
 use LWP::Simple;
 use Data::Dumper;
-use Net::Twitter;
 $Data::Dumper::Indent = 1;
 
 use vars qw($VERSION %IRSSI);
 
-$VERSION = &quot;2.0.2&quot;;
-my ($REV) = '$Rev: 454 $' =~ /(\d+)/;
+$VERSION = &quot;2.2.0&quot;;
+my ($REV) = '$Rev: 559 $' =~ /(\d+)/;
 %IRSSI = (
     authors     =&gt; 'Dan Boger',
     contact     =&gt; 'zigdon@gmail.com',
@@ -21,19 +20,21 @@ my ($REV) = '$Rev: 454 $' =~ /(\d+)/;
       . 'Can optionally set your bitlbee /away message to same',
     license =&gt; 'GNU GPL v2',
     url     =&gt; 'http://twirssi.com',
-    changed =&gt; '$Date: 2009-02-04 13:35:29 -0800 (Wed, 04 Feb 2009) $',
+    changed =&gt; '$Date: 2009-03-16 15:34:12 -0700 (Mon, 16 Mar 2009) $',
 );
 
 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 $failwhale            = 0;
 my %irssi_to_mirc_colors = (
     '%k' =&gt; '01',
     '%r' =&gt; '05',
@@ -78,24 +79,29 @@ sub cmd_direct_as {
         return;
     }
 
-    return unless &amp;valid_username($username);
+    return unless $username = &amp;valid_username($username);
 
     eval {
-        unless ( $twits{$username}
+        if ( $twits{$username}
             -&gt;new_direct_message( { user =&gt; $target, text =&gt; $text } ) )
         {
+            &amp;notice(&quot;DM sent to $target&quot;);
+            $nicks{$target} = time;
+        } else {
+            my $error;
+            eval {
+                $error = JSON::Any-&gt;jsonToObj( $twits{$username}-&gt;get_error() );
+                $error = $error-&gt;{error};
+            };
+            die $error if $error;
             &amp;notice(&quot;DM to $target failed&quot;);
-            return;
         }
     };
 
     if ($@) {
-        &amp;notice(&quot;DM caused an error.  Aborted&quot;);
+        &amp;notice(&quot;DM caused an error: $@&quot;);
         return;
     }
-
-    &amp;notice(&quot;DM sent to $target&quot;);
-    $nicks{$target} = time;
 }
 
 sub cmd_tweet {
@@ -109,7 +115,7 @@ sub cmd_tweet {
         return;
     }
 
-    &amp;cmd_tweet_as( &quot;$user $data&quot;, $server, $win );
+    &amp;cmd_tweet_as( &quot;$user\@$defservice $data&quot;, $server, $win );
 }
 
 sub cmd_tweet_as {
@@ -118,6 +124,7 @@ sub cmd_tweet_as {
     return unless &amp;logged_in($twit);
 
     $data =~ s/^\s+|\s+$//;
+    $data =~ s/\s\s+/ /g;
     my ( $username, $data ) = split ' ', $data, 2;
 
     unless ( $username and $data ) {
@@ -125,31 +132,24 @@ sub cmd_tweet_as {
         return;
     }
 
-    return unless &amp;valid_username($username);
+    return unless $username = &amp;valid_username($username);
 
-    if ( &amp;too_long( $data, 1 )
-        and Irssi::settings_get_str(&quot;short_url_provider&quot;) )
-    {
-        foreach my $url ( $data =~ /(https?:\/\/\S+[\w\/])/g ) {
-            eval {
-                my $short = makeashorterlink($url);
-                $data =~ s/\Q$url/$short/g;
-            };
-        }
-    }
+    $data = &amp;shorten($data);
 
     return if &amp;too_long($data);
 
+    my $success = 1;
     eval {
         unless ( $twits{$username}-&gt;update($data) )
         {
             &amp;notice(&quot;Update failed&quot;);
-            return;
+            $success = 0;
         }
     };
+    return unless $success;
 
     if ($@) {
-        &amp;notice(&quot;Update caused an error.  Aborted.&quot;);
+        &amp;notice(&quot;Update caused an error: $@.  Aborted.&quot;);
         return;
     }
 
@@ -203,7 +203,7 @@ sub cmd_reply_as {
         return;
     }
 
-    return unless &amp;valid_username($username);
+    return unless $username = &amp;valid_username($username);
 
     my $nick;
     $id =~ s/[^\w\d\-:]+//g;
@@ -226,17 +226,11 @@ sub cmd_reply_as {
         $data = &quot;\@$nick &quot; . $data;
     }
 
-    if ( Irssi::settings_get_str(&quot;short_url_provider&quot;) ) {
-        foreach my $url ( $data =~ /(https?:\/\/\S+[\w\/])/g ) {
-            eval {
-                my $short = makeashorterlink($url);
-                $data =~ s/\Q$url/$short/g;
-            };
-        }
-    }
+    $data = &amp;shorten($data);
 
     return if &amp;too_long($data);
 
+    my $success = 1;
     eval {
         unless (
             $twits{$username}-&gt;update(
@@ -248,12 +242,13 @@ sub cmd_reply_as {
           )
         {
             &amp;notice(&quot;Update failed&quot;);
-            return;
+            $success = 0;
         }
     };
+    return unless $success;
 
     if ($@) {
-        &amp;notice(&quot;Update caused an error.  Aborted&quot;);
+        &amp;notice(&quot;Update caused an error: $@.  Aborted&quot;);
         return;
     }
 
@@ -280,13 +275,15 @@ sub gen_cmd {
             return;
         }
 
+        my $success = 1;
         eval {
             unless ( $twit-&gt;$api_name($data) )
             {
                 &amp;notice(&quot;$api_name failed&quot;);
-                return;
+                $success = 0;
             }
         };
+        return unless $success;
 
         if ($@) {
             &amp;notice(&quot;$api_name caused an error.  Aborted.&quot;);
@@ -301,10 +298,16 @@ sub cmd_switch {
     my ( $data, $server, $win ) = @_;
 
     $data =~ s/^\s+|\s+$//g;
+    $data = &amp;normalize_username($data);
     if ( exists $twits{$data} ) {
         &amp;notice(&quot;Switching to $data&quot;);
         $twit = $twits{$data};
-        $user = $data;
+        if ( $data =~ /(.*)\@(.*)/ ) {
+            $user       = $1;
+            $defservice = $2;
+        } else {
+            &amp;notice(&quot;Couldn't figure out what service '$data' is on&quot;);
+        }
     } else {
         &amp;notice(&quot;Unknown user $data&quot;);
     }
@@ -315,7 +318,7 @@ sub cmd_logout {
 
     $data =~ s/^\s+|\s+$//g;
     $data = $user unless $data;
-    return unless &amp;valid_username($data);
+    return unless $data = &amp;valid_username($data);
 
     &amp;notice(&quot;Logging out $data...&quot;);
     $twits{$data}-&gt;end_session();
@@ -339,14 +342,26 @@ sub cmd_login {
     {
         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 .= &quot;,&quot; . shift @pass;
+            }
+            push @unescaped, $p;
+        }
+
+        if ( @user != @unescaped ) {
             &amp;notice(&quot;Number of usernames doesn't match &quot;
                   . &quot;the number of passwords - auto-login failed&quot; );
         } else {
             my ( $u, $p );
-            while ( @user and @pass ) {
+            while ( @user and @unescaped ) {
                 $u = shift @user;
-                $p = shift @pass;
+                $p = shift @unescaped;
                 &amp;cmd_login(&quot;$u $p&quot;);
             }
             return;
@@ -359,14 +374,29 @@ sub cmd_login {
 
     %friends = %nicks = ();
 
-    $twit = Net::Twitter-&gt;new(
+    my $service;
+    if ( $user =~ /^(.*)@(twitter|identica)$/ ) {
+        ( $user, $service ) = ( $1, $2 );
+    } else {
+        $service = Irssi::settings_get_str(&quot;twirssi_default_service&quot;);
+    }
+    $defservice = $service = ucfirst lc $service;
+
+    eval &quot;use Net::$service&quot;;
+    if ($@) {
+        &amp;notice(
+            &quot;Failed to load Net::$service when trying to log in as $user: $@&quot;);
+        return;
+    }
+
+    $twit = &quot;Net::$service&quot;-&gt;new(
         username =&gt; $user,
         password =&gt; $pass,
         source   =&gt; &quot;twirssi&quot;
     );
 
     unless ( $twit-&gt;verify_credentials() ) {
-        &amp;notice(&quot;Login as $user failed&quot;);
+        &amp;notice(&quot;Login as $user\@$service failed&quot;);
         $twit = undef;
         if ( keys %twits ) {
             &amp;cmd_switch( ( keys %twits )[0], $server, $win );
@@ -384,10 +414,10 @@ sub cmd_login {
             return;
         }
 
-        $twits{$user} = $twit;
+        $twits{&quot;$user\@$service&quot;} = $twit;
         Irssi::timeout_remove($poll) if $poll;
         $poll = Irssi::timeout_add( &amp;get_poll_time * 1000, \&amp;get_updates, &quot;&quot; );
-        &amp;notice(&quot;Logged in as $user, loading friends list...&quot;);
+        &amp;notice(&quot;Logged in as $user\@$service, loading friends list...&quot;);
         &amp;load_friends();
         &amp;notice( &quot;loaded friends: &quot;, scalar keys %friends );
         if ( Irssi::settings_get_bool(&quot;twirssi_first_run&quot;) ) {
@@ -401,7 +431,7 @@ sub cmd_login {
         }
         %nicks = %friends;
         $nicks{$user} = 0;
-        &amp;get_updates;
+        return 1;
     } else {
         &amp;notice(&quot;Login failed&quot;);
     }
@@ -489,15 +519,8 @@ sub cmd_upgrade {
         return;
     }
 
-    if ( not -x &quot;/usr/bin/md5sum&quot; and not $data ) {
-        &amp;notice(
-&quot;/usr/bin/md5sum can't be found - try '/twirssi_upgrade nomd5' to skip MD5 verification&quot;
-        );
-        return;
-    }
-
     my $md5;
-    unless ($data) {
+    unless ( $data or Irssi::settings_get_bool(&quot;twirssi_upgrade_beta&quot;) ) {
         eval { use Digest::MD5; };
 
         if ($@) {
@@ -531,11 +554,14 @@ sub cmd_upgrade {
         }
     }
 
-    my $URL = &quot;http://twirssi.com/twirssi.pl&quot;;
+    my $URL =
+      Irssi::settings_get_bool(&quot;twirssi_upgrade_beta&quot;)
+      ? &quot;http://github.com/zigdon/twirssi/raw/master/twirssi.pl&quot;
+      : &quot;http://twirssi.com/twirssi.pl&quot;;
     &amp;notice(&quot;Downloading twirssi from $URL&quot;);
     LWP::Simple::getstore( $URL, &quot;$loc.upgrade&quot; );
 
-    unless ($data) {
+    unless ( $data or Irssi::settings_get_bool(&quot;twirssi_upgrade_beta&quot;) ) {
         unless ( open( NEW, &quot;$loc.upgrade&quot; ) ) {
             &amp;notice(
 &quot;Failed to read $loc.upgrade.  Check that /set twirssi_location is set to the correct location.&quot;
@@ -627,6 +653,7 @@ sub get_updates {
     return unless &amp;logged_in($twit);
 
     my ( $fh, $filename ) = File::Temp::tempfile();
+    binmode( $fh, &quot;:utf8&quot; );
     my $pid = fork();
 
     if ($pid) {    # parent
@@ -640,9 +667,7 @@ sub get_updates {
         my $new_poll = time;
 
         my $error = 0;
-        $error += &amp;do_updates( $fh, $user, $twit );
         foreach ( keys %twits ) {
-            next if $_ eq $user;
             $error += &amp;do_updates( $fh, $_, $twits{$_} );
         }
 
@@ -682,13 +707,11 @@ sub do_updates {
 
     print scalar localtime, &quot; - Polling for updates for $username&quot; if &amp;debug;
     my $tweets;
-    eval {
-        $tweets = $obj-&gt;friends_timeline(
-            { since =&gt; HTTP::Date::time2str($last_poll) } );
-    };
+    eval { $tweets = $obj-&gt;friends_timeline(); };
 
     if ($@) {
-        print $fh &quot;type:debug Error during friends_timeline call.  Aborted.\n&quot;;
+        print $fh
+          &quot;type:debug Error during friends_timeline call: $@.  Aborted.\n&quot;;
         return 1;
     }
 
@@ -727,6 +750,12 @@ sub do_updates {
                 printf $fh &quot;id:%d account:%s nick:%s type:tweet %s\n&quot;,
                   $context-&gt;{id}, $username,
                   $context-&gt;{user}{screen_name}, $ctext;
+                if ( $context-&gt;{truncated} and ref($obj) ne 'Net::Identica' ) {
+                    printf $fh &quot;id:%s account:%s nick:%s type:ellispis %s\n&quot;,
+                      $context-&gt;{id} . &quot;-url&quot;, $username,
+                      $context-&gt;{user}{screen_name},
+&quot;http://twitter.com/$context-&gt;{user}{screen_name}/status/$context-&gt;{id}&quot;;
+                }
                 $reply = &quot;reply&quot;;
             } elsif ($@) {
                 print $fh &quot;type:debug request to get context failed: $@&quot;;
@@ -741,6 +770,12 @@ sub do_updates {
               and not Irssi::settings_get_bool(&quot;show_own_tweets&quot;);
         printf $fh &quot;id:%d account:%s nick:%s type:%s %s\n&quot;,
           $t-&gt;{id}, $username, $t-&gt;{user}{screen_name}, $reply, $text;
+        if ( $t-&gt;{truncated} and ref($obj) ne 'Net::Identica' ) {
+            printf $fh &quot;id:%s account:%s nick:%s type:ellispis %s\n&quot;,
+              $t-&gt;{id} . &quot;-url&quot;, $username,
+              $t-&gt;{user}{screen_name},
+              &quot;http://twitter.com/$t-&gt;{user}{screen_name}/status/$t-&gt;{id}&quot;;
+        }
     }
 
     print scalar localtime, &quot; - Polling for replies&quot; if &amp;debug;
@@ -762,6 +797,12 @@ sub do_updates {
         $text = &amp;hilight($text);
         printf $fh &quot;id:%d account:%s nick:%s type:tweet %s\n&quot;,
           $t-&gt;{id}, $username, $t-&gt;{user}{screen_name}, $text;
+        if ( $t-&gt;{truncated} ) {
+            printf $fh &quot;id:%s account:%s nick:%s type:ellispis %s\n&quot;,
+              $t-&gt;{id} . &quot;-url&quot;, $username,
+              $t-&gt;{user}{screen_name},
+              &quot;http://twitter.com/$t-&gt;{user}{screen_name}/status/$t-&gt;{id}&quot;;
+        }
     }
 
     print scalar localtime, &quot; - Polling for DMs&quot; if &amp;debug;
@@ -837,8 +878,15 @@ sub monitor_child {
     print scalar localtime, &quot; - checking child log at $filename ($attempt)&quot;
       if &amp;debug;
     my $new_last_poll;
+
+    # first time we run we don't want to print out *everything*, so we just
+    # pretend
+    my $suppress = 0;
+    $suppress = 1 unless keys %tweet_cache;
+
     if ( open FILE, $filename ) {
         my @lines;
+        my %new_cache;
         while (&lt;FILE&gt;) {
             chomp;
             last if /^__friends__/;
@@ -850,14 +898,30 @@ sub monitor_child {
                 }
             }
 
-            if (not $meta{type} or $meta{type} ne 'searchid') {
-                next if exists $meta{id} and exists $tweet_cache{ $meta{id} };
-                $tweet_cache{ $meta{id} } = time;
+            if ( not $meta{type} or $meta{type} ne 'searchid' ) {
+                if ( exists $meta{id} and exists $new_cache{ $meta{id} } ) {
+                    next;
+                }
+
+                $new_cache{ $meta{id} } = time;
+
+                if ( exists $meta{id} and exists $tweet_cache{ $meta{id} } ) {
+                    next;
+                }
             }
 
             my $account = &quot;&quot;;
-            if ( $meta{account} ne $user ) {
-                $account = &quot;$meta{account}: &quot;;
+            if ( lc $meta{account} ne lc &quot;$user\@$defservice&quot; ) {
+                $meta{account} =~ s/\@(\w+)$//;
+                my $service = $1;
+                if (
+                    lc $service eq
+                    lc Irssi::settings_get_str(&quot;twirssi_default_service&quot;) )
+                {
+                    $account = &quot;$meta{account}: &quot;;
+                } else {
+                    $account = &quot;$meta{account}\@$service: &quot;;
+                }
             }
 
             my $marker = &quot;&quot;;
@@ -874,7 +938,11 @@ sub monitor_child {
 
             my $hilight_color =
               $irssi_to_mirc_colors{ Irssi::settings_get_str(&quot;hilight_color&quot;) };
-            if ( ($_ =~ /\@$meta{account}\W/i) &amp;&amp; Irssi::settings_get_bool(&quot;twirssi_hilights&quot;) ) {
+            my $nick =
+              '@' . substr( $meta{account}, 0, index( $meta{account}, &quot;@&quot; ) );
+            if ( $_ =~ /\Q$nick\E(?:\W|$)/i
+                and Irssi::settings_get_bool(&quot;twirssi_hilights&quot;) )
+            {
                 $meta{nick} = &quot;\cC$hilight_color$meta{nick}\cO&quot;;
                 $hilight = MSGLEVEL_HILIGHT;
             }
@@ -885,6 +953,9 @@ sub monitor_child {
                     ( MSGLEVEL_PUBLIC | $hilight ),
                     $meta{type}, $account, $meta{nick}, $marker, $_
                   ];
+            } elsif ( $meta{type} eq 'ellispis' ) {
+                push @lines,
+                  [ MSGLEVEL_PUBLIC, &quot;tweet&quot;, $account, $meta{nick}, &quot;&quot;, $_ ];
             } elsif ( $meta{type} eq 'search' ) {
                 push @lines,
                   [
@@ -892,7 +963,9 @@ sub monitor_child {
                     $meta{type}, $account, $meta{topic},
                     $meta{nick}, $marker,  $_
                   ];
-                if ( $meta{id} &gt;
+                if (
+                    exists $id_map{__searches}{ $meta{account} }{ $meta{topic} }
+                    and $meta{id} &gt;
                     $id_map{__searches}{ $meta{account} }{ $meta{topic} } )
                 {
                     $id_map{__searches}{ $meta{account} }{ $meta{topic} } =
@@ -906,7 +979,9 @@ sub monitor_child {
                   ];
             } elsif ( $meta{type} eq 'searchid' ) {
                 print &quot;Search '$meta{topic}' returned id $meta{id}&quot; if &amp;debug;
-                if ( $meta{id} &gt;=
+                if (
+                    exists $id_map{__searches}{ $meta{account} }{ $meta{topic} }
+                    and $meta{id} &gt;=
                     $id_map{__searches}{ $meta{account} }{ $meta{topic} } )
                 {
                     $id_map{__searches}{ $meta{account} }{ $meta{topic} } =
@@ -935,12 +1010,16 @@ sub monitor_child {
 
         if ($new_last_poll) {
             print &quot;new last_poll = $new_last_poll&quot; if &amp;debug;
-            for my $line (@lines) {
-                $window-&gt;printformat(
-                    $line-&gt;[0],
-                    &quot;twirssi_&quot; . $line-&gt;[1],
-                    @$line[ 2 .. $#$line ]
-                );
+            if ($suppress) {
+                print &quot;First call, not printing updates&quot; if &amp;debug;
+            } else {
+                foreach my $line (@lines) {
+                    $window-&gt;printformat(
+                        $line-&gt;[0],
+                        &quot;twirssi_&quot; . $line-&gt;[1],
+                        @$line[ 2 .. $#$line ]
+                    );
+                }
             }
 
             close FILE;
@@ -948,9 +1027,13 @@ sub monitor_child {
               or warn &quot;Failed to remove $filename: $!&quot;
               unless &amp;debug;
 
+            # commit the pending cache lines to the actual cache, now that
+            # we've printed our output
+            %tweet_cache = ( %tweet_cache, %new_cache );
+
             # keep enough cached tweets, to make sure we don't show duplicates.
             foreach ( keys %tweet_cache ) {
-                next if $tweet_cache{$_} &gt;= $last_poll;
+                next if $tweet_cache{$_} &gt;= $last_poll - 3600;
                 delete $tweet_cache{$_};
             }
             $last_poll = $new_last_poll;
@@ -964,21 +1047,50 @@ sub monitor_child {
                     print JSON JSON::Any-&gt;objToJson( \%id_map );
                     close JSON;
                 } else {
-                    &amp;notice(&quot;Failed to write replies to $file: $!&quot;);
+                    &amp;ccrap(&quot;Failed to write replies to $file: $!&quot;);
                 }
             }
+            $failwhale = 0;
             return;
         }
     }
 
     close FILE;
 
-    if ( $attempt &lt; 12 ) {
+    if ( $attempt &lt; 24 ) {
         Irssi::timeout_add_once( 5000, 'monitor_child',
             [ $filename, $attempt + 1 ] );
     } else {
-        &amp;notice(&quot;Giving up on polling $filename&quot;);
+        print &quot;Giving up on polling $filename&quot; if &amp;debug;
         unlink $filename unless &amp;debug;
+
+        return unless Irssi::settings_get_bool(&quot;twirssi_notify_timeouts&quot;);
+
+        my $since;
+        my @time = localtime($last_poll);
+        if ( time - $last_poll &lt; 24 * 60 * 60 ) {
+            $since = sprintf( &quot;%d:%02d&quot;, @time[ 2, 1 ] );
+        } else {
+            $since = scalar localtime($last_poll);
+        }
+
+        if ( not $failwhale and time - $last_poll &gt; 60 * 60 ) {
+            foreach my $whale (
+                q{     v  v        v},
+                q{     |  |  v     |  v},
+                q{     | .-, |     |  |},
+                q{  .--./ /  |  _.---.| },
+                q{   '-. (__..-&quot;       \\},
+                q{      \\          a    |},
+                q{       ',.__.   ,__.-'/},
+                q{         '--/_.'----'`}
+              )
+            {
+                &amp;ccrap($whale);
+            }
+            $failwhale = 1;
+        }
+        &amp;ccrap(&quot;Haven't been able to get updated tweets since $since&quot;);
     }
 }
 
@@ -990,6 +1102,10 @@ sub notice {
     $window-&gt;print( &quot;%R***%n @_&quot;, MSGLEVEL_PUBLIC );
 }
 
+sub ccrap {
+    $window-&gt;print( &quot;%R***%n @_&quot;, MSGLEVEL_CLIENTCRAP );
+}
+
 sub update_away {
     my $data = shift;
 
@@ -1003,7 +1119,7 @@ sub update_away {
             $server-&gt;send_raw(&quot;away :$data&quot;);
             return 1;
         } else {
-            &amp;notice( &quot;Can't find bitlbee server.&quot;,
+            &amp;ccrap( &quot;Can't find bitlbee server.&quot;,
                 &quot;Update bitlbee_server or disable tweet_to_away&quot; );
             return 0;
         }
@@ -1028,12 +1144,14 @@ sub too_long {
 sub valid_username {
     my $username = shift;
 
+    $username = &amp;normalize_username($username);
+
     unless ( exists $twits{$username} ) {
         &amp;notice(&quot;Unknown username $username&quot;);
-        return 0;
+        return undef;
     }
 
-    return 1;
+    return $username;
 }
 
 sub logged_in {
@@ -1056,8 +1174,10 @@ sub sig_complete {
       )
     {    # /twitter_reply gets a nick:num
         $word =~ s/^@//;
-        @$complist = map { &quot;$_:$id_map{__indexes}{$_}&quot; } grep /^\Q$word/i,
-          sort keys %{ $id_map{__indexes} };
+        @$complist = map { &quot;$_:$id_map{__indexes}{$_}&quot; }
+          sort { $nicks{$b} &lt;=&gt; $nicks{$a} }
+          grep /^\Q$word/i,
+          keys %{ $id_map{__indexes} };
     }
 
     # /tweet, /tweet_as, /dm, /dm_as - complete @nicks (and nicks as the first
@@ -1093,13 +1213,89 @@ sub get_poll_time {
 sub hilight {
     my $text = shift;
 
-    $text =~ s/(^|\W)\@([-\w]+)/$1\cC12\@$2\cO/g;
-    $text =~ s/(^|\W)\#([-\w]+)/$1\cC5\#$2\cO/g;
+    if ( Irssi::settings_get_str(&quot;twirssi_nick_color&quot;) ) {
+        my $c = Irssi::settings_get_str(&quot;twirssi_nick_color&quot;);
+        $c = $irssi_to_mirc_colors{$c};
+        $text =~ s/(^|\W)\@([-\w]+)/$1\cC$c\@$2\cO/g if $c;
+    }
+    if ( Irssi::settings_get_str(&quot;twirssi_topic_color&quot;) ) {
+        my $c = Irssi::settings_get_str(&quot;twirssi_topic_color&quot;);
+        $c = $irssi_to_mirc_colors{$c};
+        $text =~ s/(^|\W)\#([-\w]+)/$1\cC$c\#$2\cO/g if $c;
+    }
     $text =~ s/[\n\r]/ /g;
 
     return $text;
 }
 
+sub shorten {
+    my $data = shift;
+
+    my $provider = Irssi::settings_get_str(&quot;short_url_provider&quot;);
+    if (
+        (
+            Irssi::settings_get_bool(&quot;twirssi_always_shorten&quot;)
+            or &amp;too_long( $data, 1 )
+        )
+        and $provider
+      )
+    {
+        my @args;
+        if ( $provider eq 'Bitly' ) {
+            @args[ 1, 2 ] = split ',',
+              Irssi::settings_get_str(&quot;short_url_args&quot;), 2;
+            unless ( @args == 3 ) {
+                &amp;ccrap(
+                    &quot;WWW::Shorten::Bitly requires a username and API key.&quot;,
+                    &quot;Set short_url_args to username,API_key or change your&quot;,
+                    &quot;short_url_provider.&quot;
+                );
+                return $data;
+            }
+        }
+
+        foreach my $url ( $data =~ /(https?:\/\/\S+[\w\/])/g ) {
+            eval {
+                $args[0] = $url;
+                my $short = makeashorterlink(@args);
+                if ($short) {
+                    $data =~ s/\Q$url/$short/g;
+                } else {
+                    &amp;notice(&quot;Failed to shorten $url!&quot;);
+                }
+            };
+        }
+    }
+
+    return $data;
+}
+
+sub normalize_username {
+    my $user = shift;
+
+    my ( $username, $service ) = split /\@/, $user, 2;
+    if ($service) {
+        $service = ucfirst lc $service;
+    } else {
+        $service =
+          ucfirst lc Irssi::settings_get_str(&quot;twirssi_default_service&quot;);
+        unless ( exists $twits{&quot;$username\@$service&quot;} ) {
+            $service = undef;
+            foreach my $t ( sort keys %twits ) {
+                next unless $t =~ /^\Q$username\E\@(Twitter|Identica)/;
+                $service = $1;
+                last;
+            }
+
+            unless ($service) {
+                &amp;notice(&quot;Can't find a logged in user '$user'&quot;);
+            }
+        }
+    }
+
+    return &quot;$username\@$service&quot;;
+}
+
 Irssi::signal_add( &quot;send text&quot;, &quot;event_send_text&quot; );
 
 Irssi::theme_register(
@@ -1113,15 +1309,20 @@ Irssi::theme_register(
 );
 
 Irssi::settings_add_int( &quot;twirssi&quot;, &quot;twitter_poll_interval&quot;, 300 );
-Irssi::settings_add_str( &quot;twirssi&quot;, &quot;twitter_window&quot;,     &quot;twitter&quot; );
-Irssi::settings_add_str( &quot;twirssi&quot;, &quot;bitlbee_server&quot;,     &quot;bitlbee&quot; );
-Irssi::settings_add_str( &quot;twirssi&quot;, &quot;short_url_provider&quot;, &quot;TinyURL&quot; );
+Irssi::settings_add_str( &quot;twirssi&quot;, &quot;twitter_window&quot;,          &quot;twitter&quot; );
+Irssi::settings_add_str( &quot;twirssi&quot;, &quot;bitlbee_server&quot;,          &quot;bitlbee&quot; );
+Irssi::settings_add_str( &quot;twirssi&quot;, &quot;short_url_provider&quot;,      &quot;TinyURL&quot; );
+Irssi::settings_add_str( &quot;twirssi&quot;, &quot;short_url_args&quot;,          undef );
+Irssi::settings_add_str( &quot;twirssi&quot;, &quot;twitter_usernames&quot;,       undef );
+Irssi::settings_add_str( &quot;twirssi&quot;, &quot;twitter_passwords&quot;,       undef );
+Irssi::settings_add_str( &quot;twirssi&quot;, &quot;twirssi_default_service&quot;, &quot;Twitter&quot; );
+Irssi::settings_add_str( &quot;twirssi&quot;, &quot;twirssi_nick_color&quot;,      &quot;%B&quot; );
+Irssi::settings_add_str( &quot;twirssi&quot;, &quot;twirssi_topic_color&quot;,     &quot;%r&quot; );
 Irssi::settings_add_str( &quot;twirssi&quot;, &quot;twirssi_location&quot;,
     &quot;.irssi/scripts/twirssi.pl&quot; );
-Irssi::settings_add_str( &quot;twirssi&quot;, &quot;twitter_usernames&quot;, undef );
-Irssi::settings_add_str( &quot;twirssi&quot;, &quot;twitter_passwords&quot;, undef );
 Irssi::settings_add_str( &quot;twirssi&quot;, &quot;twirssi_replies_store&quot;,
     &quot;.irssi/scripts/twirssi.json&quot; );
+Irssi::settings_add_bool( &quot;twirssi&quot;, &quot;twirssi_upgrade_beta&quot;,      0 );
 Irssi::settings_add_bool( &quot;twirssi&quot;, &quot;tweet_to_away&quot;,             0 );
 Irssi::settings_add_bool( &quot;twirssi&quot;, &quot;show_reply_context&quot;,        0 );
 Irssi::settings_add_bool( &quot;twirssi&quot;, &quot;show_own_tweets&quot;,           1 );
@@ -1130,12 +1331,18 @@ Irssi::settings_add_bool( &quot;twirssi&quot;, &quot;twirssi_first_run&quot;,         1 );
 Irssi::settings_add_bool( &quot;twirssi&quot;, &quot;twirssi_track_replies&quot;,     1 );
 Irssi::settings_add_bool( &quot;twirssi&quot;, &quot;twirssi_replies_autonick&quot;,  1 );
 Irssi::settings_add_bool( &quot;twirssi&quot;, &quot;twirssi_use_reply_aliases&quot;, 0 );
+Irssi::settings_add_bool( &quot;twirssi&quot;, &quot;twirssi_notify_timeouts&quot;,   1 );
 Irssi::settings_add_bool( &quot;twirssi&quot;, &quot;twirssi_hilights&quot;,          1 );
+Irssi::settings_add_bool( &quot;twirssi&quot;, &quot;twirssi_always_shorten&quot;,    0 );
 Irssi::settings_add_bool( &quot;twirssi&quot;, &quot;tweet_window_input&quot;,        0 );
 
 $last_poll = time - &amp;get_poll_time;
 $window = Irssi::window_find_name( Irssi::settings_get_str('twitter_window') );
 if ( !$window ) {
+    Irssi::active_win()
+      -&gt;print( &quot;Couldn't find a window named '&quot;
+          . Irssi::settings_get_str('twitter_window')
+          . &quot;', trying to create it.&quot; );
     $window =
       Irssi::Windowitem::window_create(
         Irssi::settings_get_str('twitter_window'), 1 );
@@ -1156,6 +1363,7 @@ if ($window) {
     Irssi::command_bind( &quot;twitter_unsubscribe&quot;,        &quot;cmd_del_search&quot; );
     Irssi::command_bind( &quot;twitter_list_subscriptions&quot;, &quot;cmd_list_search&quot; );
     Irssi::command_bind( &quot;twirssi_upgrade&quot;,            &quot;cmd_upgrade&quot; );
+    Irssi::command_bind( &quot;twitter_updates&quot;,            &quot;get_updates&quot; );
     if ( Irssi::settings_get_bool(&quot;twirssi_use_reply_aliases&quot;) ) {
         Irssi::command_bind( &quot;reply&quot;,    &quot;cmd_reply&quot; );
         Irssi::command_bind( &quot;reply_as&quot;, &quot;cmd_reply_as&quot; );
@@ -1164,11 +1372,17 @@ if ($window) {
         &quot;twirssi_dump&quot;,
         sub {
             print &quot;twits: &quot;, join &quot;, &quot;,
-              map { &quot;u: $_-&gt;{username}&quot; } values %twits;
+              map { &quot;u: $_-&gt;{username}\@&quot; . ref($_) } values %twits;
+            print &quot;selected: $user\@$defservice&quot;;
             print &quot;friends: &quot;, join &quot;, &quot;, sort keys %friends;
             print &quot;nicks: &quot;,   join &quot;, &quot;, sort keys %nicks;
             print &quot;searches: &quot;, Dumper \%{ $id_map{__searches} };
             print &quot;last poll: $last_poll&quot;;
+            if ( open DUMP, &quot;&gt;/tmp/twirssi.cache.txt&quot; ) {
+                print DUMP Dumper \%tweet_cache;
+                close DUMP;
+                print &quot;cache written out to /tmp/twirssi.cache.txt&quot;;
+            }
         }
     );
     Irssi::command_bind(
@@ -1197,7 +1411,14 @@ if ($window) {
             sub { &amp;notice(&quot;Stopped following $_[0]&quot;); delete $nicks{ $_[0] }; }
         )
     );
-    Irssi::command_bind( &quot;twitter_updates&quot;, &quot;get_updates&quot; );
+    Irssi::command_bind(
+        &quot;twitter_device_updates&quot;,
+        &amp;gen_cmd(
+            &quot;/twitter_device_updates none|im|sms&quot;,
+            &quot;update_delivery_device&quot;,
+            sub { &amp;notice(&quot;Device updated to $_[0]&quot;); }
+        )
+    );
     Irssi::signal_add_last( 'complete word' =&gt; \&amp;sig_complete );
 
     &amp;notice(&quot;  %Y&lt;%C(%B^%C)%N                   TWIRSSI v%R$VERSION%N (r$REV)&quot;);
@@ -1217,6 +1438,7 @@ if ($window) {
                 my $num = keys %{ $id_map{__indexes} };
                 &amp;notice( sprintf &quot;Loaded old replies from %d contact%s.&quot;,
                     $num, ( $num == 1 ? &quot;&quot; : &quot;s&quot; ) );
+                &amp;cmd_list_search;
             };
         } else {
             &amp;notice(&quot;Failed to load old replies from $file: $!&quot;);
@@ -1224,11 +1446,13 @@ if ($window) {
     }
 
     if ( my $provider = Irssi::settings_get_str(&quot;short_url_provider&quot;) ) {
+        &amp;notice(&quot;Loading WWW::Shorten::$provider...&quot;);
         eval &quot;use WWW::Shorten::$provider;&quot;;
 
         if ($@) {
             &amp;notice(
-&quot;Failed to load WWW::Shorten::$provider - either clear short_url_provider or install the CPAN module&quot;
+                &quot;Failed to load WWW::Shorten::$provider - either clear&quot;,
+                &quot;short_url_provider or install the CPAN module&quot;
             );
         }
     }
@@ -1237,6 +1461,7 @@ if ($window) {
         and my $autopass = Irssi::settings_get_str(&quot;twitter_passwords&quot;) )
     {
         &amp;cmd_login();
+        &amp;get_updates;
     }
 
 } else {</diff>
      <filename>twirssi.pl</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>af8fafcbee68c42b6c85c68ca9c0fcaf418887c6</id>
    </parent>
    <parent>
      <id>6edd2e649ba18daadccc1727d775baa627a525c0</id>
    </parent>
  </parents>
  <author>
    <name>Brian S. Stephan</name>
    <login>bssteph</login>
    <email>bss@emptymatter.org</email>
  </author>
  <url>http://github.com/bssteph/twirssi/commit/605ec8cdb439c778acdcb79d9799973385338c7d</url>
  <id>605ec8cdb439c778acdcb79d9799973385338c7d</id>
  <committed-date>2009-03-17T16:24:09-07:00</committed-date>
  <authored-date>2009-03-17T16:24:09-07:00</authored-date>
  <message>merging upstream</message>
  <tree>c173c73ea727c581b43fcf299e5cf71f4a5ab0e9</tree>
  <committer>
    <name>Brian S. Stephan</name>
    <login>bssteph</login>
    <email>bss@emptymatter.org</email>
  </committer>
</commit>
