# /AUTOAWAY <n> - Mark user away after <n> seconds of inactivity
# /AWAY - play nice with autoaway
# New, brighter, whiter version of my autoaway script. Actually works :)
# (c) 2000 Larry Daffner (vizzie@airmail.net)
#     You may freely use, modify and distribute this script, as long as
#      1) you leave this notice intact
#      2) you don't pretend my code is yours
#      3) you don't pretend your code is mine
#
# share and enjoy!
    
# A simple script. /autoaway <n> will mark you as away automatically if
# you have not typed any commands in <n> seconds. (<n>=0 disables the feature)
# It will also automatically unmark you away the next time you type a command.
# Note that using the /away command will disable the autoaway mechanism, as
# well as the autoreturn. (when you unmark yourself, the auutoaway wil
# restart again)

# Modified to use X11's idle time. Requires X11::Protocol::Ext::ScreenSaver,
# and expects to find the value of the actual $DISPLAY in
# $HOME/.screen/DISPLAY (set by screen when running screen -r)

use Irssi;
#use Irssi::Irc;

use X11::Protocol;
use vars qw($VERSION %IRSSI);
$version = "0.1";
%IRSSI = (
    authors => 'Matthieu Weber, Larry "Vizzie" Daffner',
    contact => 'mweber@mit.jyu.fi, vizzie@airmail.net',
    name => 'X11 Autoaway',
    description => 'Automatically goes away after defined X11 inactivity',
    licence => 'BSD',
    url => '',
    changed => 'Thu Sep  4 09:36:54 EEST 2008',
    changes => ''
);

my ($autoaway_sec, $autoaway_to_tag, $autoaway_state);
my ($autoaway_x, $autoaway_last_screen_display_check);
$autoaway_state = 0;
$autoaway_screen_display = "$ENV{HOME}/.screen/DISPLAY";
$autoaway_last_screen_display_check = 0;

sub sigpipe {
  ${$autoaway_x->{'connection'}}->close;
  undef $autoaway_x;
}

$SIG{PIPE} = \&sigpipe;

sub get_X_display {
  if (-e $autoaway_screen_display) {
    my @s = stat($autoaway_screen_display);
    if ($s[10] > $autoaway_last_screen_display_check) {
      $autoaway_last_screen_display_check = $s[10];
      open (D, $autoaway_screen_display);
      my $display = <D>;
      close(D);
      &init_X($display)
    }
  }
  else {
    &init_X($ENV{DISPLAY})
  }
}

sub init_X {
  my $display = shift;
  $autoaway_x = eval {
    undef *X11::Protocol::ScreenSaverQueryInfo;
    $x = X11::Protocol->new($display);
    $x->init_extension('MIT-SCREEN-SAVER');
    return $x;
  }
}

sub get_X_idle_time {
  if ($autoaway_x) {
    my $ret = eval {
      @tmp = $autoaway_x->ScreenSaverQueryInfo($autoaway_x->root);
      return $tmp[2]/1000;
    };
    if ($ret) {
      return $ret;
    } 
    else {
      $autoaway_last_screen_display_check = 0;
      return 0;
    } 
  }
  else {
    return 0;
  }
}

sub check_X_idle_time {
  &get_X_display();
  return &get_X_idle_time();
}

#
# /AUTOAWAY - set the autoaway timeout
#
sub cmd_autoaway {
  my ($data, $server, $channel) = @_;
  
  if ($data =~ /^[0-9]+m$/) {
    $autoaway_sec = $data * 60;
  }
  elsif ($data =~ /^([0-9]+)s?$/) {
    $autoaway_sec = $1;
  }
  else {
    Irssi::print("autoaway: usage: /autoaway [<secs>[s] | <mins>m]");
    return;
  }

  if ($autoaway_sec) {
    Irssi::print("autoaway timeout set to $autoaway_sec seconds");
  } else {
    Irssi::print("autoway disabled");
  }
  
  if (defined($autoaway_to_tag)) {
    Irssi::timeout_remove($autoaway_to_tag);
    $autoaway_to_tag = undef;
  }

  if ($autoaway_sec) {
    $autoaway_to_tag = Irssi::timeout_add(1000, "auto_timeout", "");
  }
}

# state:
#   0: not away, timer running
#   1: auto away
#   2: manual away
#   3: going auto away
#
# away = Set us away or back, within the autoaway system
sub cmd_away {
  my ($data, $server, $channel) = @_;
  
  if ($data eq "") {
    # If $autoaway_state is 2, we went away by typing /away, and need
    # to restart autoaway ourselves. Otherwise, we were autoaway, and
    # we'll let the autoaway return take care of business.

    if ($autoaway_state eq 2) {
      if ($autoaway_sec) {
        $autoaway_to_tag = Irssi::timeout_add(1000, "auto_timeout", "");
      }
    }
    $autoaway_state = 0;
  } else {
    if ($autoaway_state eq 0) {
      Irssi::timeout_remove($autoaway_to_tag);
      $autoaway_to_tag = undef;
      $autoaway_state = 2;
    }
  }
}

sub auto_timeout {
  my ($data, $server) = @_;
  my (@servers) = Irssi::servers();

  if ($autoaway_state eq 0 && $autoaway_sec) {
    if (&check_X_idle_time() > $autoaway_sec) {
      # we're in the process.. don't touch anything.
      $autoaway_state = 3;
      $server = $servers[0];
      $server->command("/AWAY autoaway after $autoaway_sec seconds");

      $autoaway_state = 1;
    }
  }
  elsif ($autoaway_state eq 1 && $autoaway_sec) {
    if (&check_X_idle_time() < $autoaway_sec) {
      &auto_unaway();
    }
  }
}

sub auto_unaway {
  if ($autoaway_state eq 1) {
    my (@servers) = Irssi::servers();
    
    $autoaway_state = 3;
    $server = $servers[0];
    $server->command("/AWAY");
    
    $autoaway_state = 0;
  } 
}

Irssi::settings_add_int("misc", "autoaway_timeout", 0);

$autoaway_default = Irssi::settings_get_int("autoaway_timeout");
if ($autoaway_default) {
  $autoaway_sec = $autoaway_default;
  $autoaway_to_tag = Irssi::timeout_add(1000, "auto_timeout", "");
}
Irssi::command_bind('autoaway', 'cmd_autoaway');
Irssi::command_bind('away', 'cmd_away');
Irssi::signal_add('send command', 'auto_unaway');
