# bitlbee_status_notice.pl
# Adds detailed information about status changed to bitlbee query windows
# Information about known offline, online, and away durations will be printed
# to open query windows of buddies. Away messages will also be asked for when
# using the Oscar network.

# To use:
# Set the correct values for $bitlbee_* below, and then:
#   /script load bitlbee_status_notice.pl

# Settings:
#   /set bitlbee_hide_joins ON|OFF
#       Prevents joins from showing up in #bitlbee control channel when buddies
#       sign on
#   /set bitlbee_hide_quits ON|OFF
#       Same for buddies signing off, except it also applies to query windows,
#       because Irssi shows quit notices in query windows automatically.
# Both settings are ON by default (joins and quits are hidden)

# Tip: to ignore root's mode changes (when away_devoice = true), use:
#   /ignore -channels &bitlbee root!*@* MODES


# TODO
# Make server tag and channel settings

use Data::Dumper;
use strict;
use Irssi::TextUI;
use Time::Duration;

use vars qw($VERSION %IRSSI);

$VERSION = '1.3';
%IRSSI = (
    authors     => 'Matt "f0rked" Sparks',
    contact     => 'root@f0rked.com',
    name        => 'bitlbee_status_notice',
    description => 'Adds detailed information about status changes to bitlbee query windows',
    license     => 'GPLv2',
    url         => 'http://f0rked.com',
    changed     => '2005-12-05',
);

my $bitlbee_channel="&bitlbee";
my $bitlbee_server_tag="IM";

my %away_watch;
my %away_times;
my %online_times;
my %offline_times;

my $hide_it;
my $requested_info;

Irssi::theme_register([
    'state_away', '{channick $0} {chanhost $1} has gone away',
    'state_back', '{channick_hilight $0} {chanhost_hilight $1} has come back$2',
    'away_msg', '{chanhost msg} $0',
    'join', '{channick_hilight $0} {chanhost_hilight $1} has signed on$2',
    'quit', '{channick $0} {chanhost $1} has signed off$2',
]);

Irssi::signal_add_last 'channel sync' => sub {
    my($channel)=@_;
    if ($channel->{topic} eq "Welcome to the control channel. Type \x02help\x02 for help information.") {
        $bitlbee_server_tag=$channel->{server}->{tag};
        $bitlbee_channel=$channel->{name};
    }
};

sub event_join {
    my($server,$channel,$nick,$address)=@_;
    if ($channel eq $bitlbee_channel && $server->{tag} eq $bitlbee_server_tag) {
        my $off_time; $off_time=time-$offline_times{$nick} if $offline_times{$nick};
        delete($offline_times{$nick}) if $offline_times{$nick};
        my $str; $str=" (last seen: ".ago_exact($off_time).")" if $off_time;
        $online_times{$nick}=time;
        my $window = $server->query_find($nick);
        if ($window) {
            $window->printformat(MSGLEVEL_JOINS,"join",$nick,$address,$str);
        }
        Irssi::signal_stop() # don't print the join announcement in &bitlbee
            if Irssi::settings_get_bool("bitlbee_hide_joins");
    }
}

sub event_quit {
    my($server,$nick,$address,$reason)=@_;
    if ($server->{tag} eq $bitlbee_server_tag) {
        my $on_time; $on_time=time-$online_times{$nick} if $online_times{$nick};
        delete($online_times{$nick}) if $online_times{$nick};
        my $str; $str=" (duration: ".duration($on_time).")" if $on_time;
        $offline_times{$nick}=time;
        my $window = $server->query_find($nick);
        if ($window) {
            $window->printformat(MSGLEVEL_QUITS,"quit",$nick,$address,$str);
        }
        Irssi::signal_stop() # don't print the quit announcement anywhere
            if Irssi::settings_get_bool("bitlbee_hide_quits");
    }
}

sub event_mode {
    my($channel,$nick,$setby,$mode,$type)=@_;
    #print Dumper $nick;
    #print Dumper $channel;
    if ($mode eq "+" && $channel->{name} eq $bitlbee_channel && $channel->{server}->{tag} eq $bitlbee_server_tag) {
        my $window=$channel->{server}->query_find($nick->{nick});
        my $gone_time;
        
        if ($type eq "-") {
            $away_times{$nick->{nick}}=time;
        }
        elsif ($type eq "+") {
            if (my $time=$away_times{$nick->{nick}}) {
                $gone_time=time-$time;
                delete($away_times{$nick->{nick}});
            }       
        }        
        
        if ($window) {
            if ($type eq "+") {
                my $gone_str; $gone_str=" (gone: ".duration($gone_time).")" if $gone_time;
                $window->printformat(MSGLEVEL_MODES,"state_back",$nick->{nick},$nick->{host},$gone_str)
                    if (time-$online_times{$nick->{nick}} > 2);
            }
            elsif ($type eq "-") {
                $window->printformat(MSGLEVEL_MODES,"state_away",$nick->{nick},$nick->{host});
                if ($nick->{host} =~ /login\.oscar\.aol\.com$/) {
                    $away_watch{nick}=$nick->{nick};
                    $channel->{server}->send_message($channel->{name},"info $nick->{nick}",0);
                    $requested_info=1;
                }
            }
        }
    }    
}

sub pub_msg {
    my($server,$msg,$nick,$address,$target)=@_;
    #print "$msg $nick $address $target";
    if ($nick eq "root" && $server->{tag} eq $bitlbee_server_tag && $target eq $bitlbee_channel) {
        my $window=$server->channel_find($target);
        if ($window) {
            my $qwin;
            $qwin = $server->query_find($away_watch{nick}) if $away_watch{nick};
            if ($msg =~ /TOC\(?.*\)? - Away Message/g) {
                $away_watch{watch}=1;
                $hide_it=1 if $requested_info;
                Irssi::timeout_add_once(400,sub{$hide_it=0;$requested_info=0;},"");
                #$qwin->print("Away message:",MSGLEVEL_CRAP) if $qwin;
            }
            elsif ($msg =~ /^TOC\(?.*\)? \- .+$/) {
                delete($away_watch{watch});
                delete($away_watch{nick});
            }
            elsif ($away_watch{watch} && $qwin) {
                $qwin->printformat(MSGLEVEL_CRAP,"away_msg",$msg) if $qwin;
            }
        }
        Irssi::signal_stop if $hide_it;
    }
}

Irssi::settings_add_bool("bitlbee","bitlbee_hide_joins",1);
Irssi::settings_add_bool("bitlbee","bitlbee_hide_quits",1);

Irssi::signal_add("message public","pub_msg");
Irssi::signal_add("nick mode changed","event_mode");
Irssi::signal_add("message join", "event_join");
Irssi::signal_add("message quit", "event_quit");
