# -*- perl -*- vim:set ft=perl sw=4 sts=4:
use strict;
-use vars qw(%state @ssh $last $pipe $arg);
+use vars qw(%state @ssh $last $pipe $arg $slow);
@ssh=("ssh","-a","-x","-oBatchmode=yes","-oSetupTimeOut=20");
$pipe = "/tmp/.away-tpope";
daemon() if ($arg eq "-D");
-if($arg eq "activity" || $arg eq "away") {
+if($arg eq "activity" || $arg eq "away" || $arg eq "out" || $arg eq "check") {
if(exists($ARGV[0])) {
die "Daemon not running\n" unless (-p $pipe);
my $a = join(" ",@ARGV);
open FIFO, ">$pipe";
print FIFO "$arg $a";
} else {
- $arg =~ s/^away$/customaway/;
load();
print $state{$arg}."\n" if($state{$arg});
}
}
sub daemon {
+ die "Daemon already running?\n" if (-e "/tmp/.away-tpope.pid");
open TMP, ">/tmp/.away-tpope.pid";
print TMP "$$\n";
close TMP;
$SIG{'INT'} = \&quit_handler;
$SIG{'TERM'} = \&quit_handler;
$SIG{'QUIT'} = \&quit_handler;
- $SIG{'HUP'} = \&cycle;
+ $SIG{'HUP'} = \&hup_handler;
$SIG{'USR2'} = \&restart_handler;
die "Daemon already running\n" if (-r "/tmp/.tpope-away.pid");
unless (-p $pipe) {
unlink $pipe;
system("mkfifo", $pipe);
+ chmod 0600, $pipe;
}
+ $last=0;
+ $slow=1;
cycle();
- $last=time;
while(1) {
main_loop();
}
custom_activity($read);
} elsif($c eq "away") {
custom_away($read);
+ } elsif($c eq "out") {
+ custom_out($read);
+ } elsif($c eq "check") {
+ host_check($read);
} else {
print "Unknown command: $c\n";
}
}
- if(time-$last >=300) {
- local $SIG{'HUP'} = "IGNORE";
+ if(time-$last >= 240) {
cycle();
- $last=time;
}
}
sub cycle {
- do_phone();
- do_hosts();
+ local $SIG{'HUP'} = sub {$last = 1};
+ do_chat();
+ if((!$last) || $slow++ ) {
+ do_hosts();
+ do_power();
+ do_phone();
+ $slow=0;
+ }
do_schedule();
- process_away();
+ do_decision();
save();
do_custom();
+ if($last==1) {
+ $last=0;
+ } else {
+ $last=int(time/60)*60;
+ }
}
sub ping {
my ($begin, $end, $maxend);
next unless /(\d\d):(\d\d)-(\d\d):(\d\d) (.*)/;
my ($hs,$ms,$he,$me,$ev) = ($1, $2, $3, $4, $5);
+ $ev =~ s/ *\[.*$//;
$begin = $hs*60+$ms-25;
- $maxend = $he*60+$me+5;
- $end = ($begin+25)*3/4+($maxend-5)/4;
+ $maxend = $he*60+$me+10;
+ $end = ($begin+25)*3/4+($maxend-10)/4;
if($begin <= $now && $now < $end) {
$state{'class'} = $ev;
$familiar = 1;
my ($begin, $end, $maxend);
next unless /(\d\d):(\d\d)-(\d\d):(\d\d) (.*)/;
my ($hs,$ms,$he,$me,$ev) = ($1, $2, $3, $4, $5);
+ $ev =~ s/ *\[.*$//;
$begin = $hs*60+$ms;
$maxend = $he*60+$me;
$end = ($begin)*3/4+($maxend)/4;
$state{'schedule'} = $ev;
$familiar = 1;
last;
- } elsif ($state{'schedule'} eq $ev) {
+ } elsif (($state{'schedule'}||'') eq $ev) {
$familiar = 1;
undef $state{'schedule'}
if ($now > $maxend || $state{'phone'} eq "present");
undef $state{'schedule'} unless ($familiar);
}
+sub do_chat {
+ if(-r ($ENV{'HOME'} . "/.chat")) {
+ open TMP, $ENV{'HOME'} . "/.chat";
+ my $chat = join ("", <TMP>);
+ close TMP;
+ chomp $chat;
+ $state{'chat'} = $chat;
+ } else {
+ undef $state{'chat'};
+ }
+}
+
sub do_hosts {
- my @livehosts;
- foreach my $host ("sarah", "homer", "lisa", "mona") {
- push @livehosts, $host if(ping($host));
+ my (@check) = ("mona", "lisa", "homer", "sarah");
+ my (@uphosts, @livehosts, $host, $hostlist);
+ if(($_[0] || 0) == 1) {
+ $hostlist=$state{'hosts'};
+ $hostlist=~s/0\S* ?//g;
+ @livehosts = split / /, $hostlist;
+ } else {
+ $hostlist="";
+ foreach $host (@check) {
+ push @uphosts, $host if(ping($host));
+ }
+ foreach $host (@uphosts) {
+ if(is_alive($host)) {
+ push @livehosts,$host;
+ $hostlist="$host $hostlist";
+ } else {
+ $hostlist="0$host $hostlist";
+ }
+ }
+ $hostlist=~s/ $//;
+ $state{'hosts'}=$hostlist;
+ }
+ if(scalar @livehosts == 0) {
+ $state{'alive'} = '';
+ } elsif(scalar @livehosts > 1 && $state{'chat'}) {
+ foreach $host (@livehosts) {
+ if ($host eq $state{'chat'}) {
+ $state{'alive'} = $host;
+ return;
+ }
+ }
}
- my $alive = "";
- foreach my $host (@livehosts) {
- $alive=$host unless(system(@ssh,$host, 'if pidof xscreensaver >/dev/null && DISPLAY=:0.0 xscreensaver-command -version >/dev/null 2>&1; then if DISPLAY=:0.0 xscreensaver-command -time 2>&1 |egrep "non-blanked|no saver status" >/dev/null; then true; else pid=`ps ax|egrep "[0-9]:[0-9][0-9] ssh marge .*(screen.*RR irc|Chat)"|sed -e "s/^ *//"|cut -d" " -f 1`; [ -f "$HOME/.irc.lock" -o -z "$pid" ] || kill $pid; false; fi; else false; fi') >> 8);
+ $state{'alive'}=$livehosts[0];
+}
+
+sub is_alive {
+ my $ret;
+ eval {
+ local $SIG{ALRM} = sub { die "alarm\n" };
+ alarm(30);
+ $ret=!(system(@ssh,shift, 'if pidof xscreensaver >/dev/null && DISPLAY=:0.0 xscreensaver-command -version >/dev/null 2>&1; then if DISPLAY=:0.0 xscreensaver-command -time 2>&1 |egrep "non-blanked|no saver status" >/dev/null; then true; else pid=`ps ax|egrep "[0-9]:[0-9][0-9] ssh marge .*(screen.*RR irc|Chat)"|sed -e "s/^ *//"|cut -d" " -f 1`; [ -f "$HOME/.irc.lock" -o -z "$pid" ] || kill $pid; false; fi; else false; fi') >> 8);
+ alarm(0);
+ };
+ if($@) {
+ undef $ret;
+ die unless $@ eq "alarm\n";
}
- $state{'alive'} = $alive;
+ return $ret;
}
sub do_phone {
my $last_slh=`@ssh mona cat .blue/last_slh 2>/dev/null`;
if(!$last_slh) {
$phone="unknown";
- } elsif (time-$last_slh < 600) {
+ } elsif (time-$last_slh < 540) {
$phone="present";
} else {
$phone="absent";
}
}
- if($state{'phone'} eq 'absent' && $phone eq 'present') {
- custom_away("");
+ if($state{'phone'} ne 'present' && $phone eq 'present') {
+ custom_out("");
}
+ $state{'phone'} = $phone;
}
-sub process_away {
- if ($state{'customaway'}) {
+sub do_power {
+ open TMP, "upsc milhouse\@localhost|";
+ my $ups='';
+ while(<TMP>) {
+ chomp;
+ if(/status: (.*)/i) {
+ $ups=$1;
+ }
+ }
+ close TMP;
+ $state{'ups'}=$ups;
+}
+
+sub do_decision {
+ custom_away("")
+ if ($state{'customawayexp'} && $state{'customawayexp'}<time);
+ custom_out("")
+ if ($state{'customoutexp'} && $state{'customoutexp'}<time);
+ custom_activity("")
+ if ($state{'customactivityexp'} && $state{'customactivityexp'}<time);
+ if ($state{'customactivity'}) {
+ $state{'activity'}=$state{'customactivity'};
+ } elsif ($state{'ups'} eq 'OB' || $state{'ups'} eq 'LB') {
+ $state{'activity'}="Power outage";
+ } else {
+ undef $state{'activity'};
+ }
+ if ($state{'customout'} && $state{'phone'} eq 'absent') {
+ $state{'away'}=$state{'customout'};
+ } elsif ($state{'customaway'}) {
$state{'away'}=$state{'customaway'};
} elsif ($state{'schedule'}) {
$state{'away'}=$state{'schedule'};
$state{'away'}="Out";
} elsif ($state{'phone'} ne 'absent') {
my @now=localtime;
- if ($now[2] < 10) {
+ if (1 <= $now[2] && $now[2] < 9) {
$state{'away'}="Sleeping";
} else {
$state{'away'}="Away from keyboard";
}
}
+sub host_check {
+ return undef unless($_[0]);
+ my $host=$_[0];
+ if($host eq "phone") {
+ do_phone();
+ do_decision();
+ save();
+ do_custom();
+ } elsif($host eq "chat") {
+ do_chat();
+ do_hosts(1);
+ do_decision();
+ save();
+ } elsif($state{'hosts'} =~ /0$host/ && is_alive($_[0])) {
+ $state{'hosts'} =~ s/0$host/$host/;
+ do_hosts(1);
+ do_decision();
+ save();
+ do_custom();
+ } elsif($state{'hosts'} =~ /(?!0)$host/ && ! is_alive($_[0])) {
+ $state{'hosts'} =~ s/1?$host/0$host/;
+ do_hosts(1);
+ do_decision();
+ save();
+ }
+}
+
sub custom_away {
if($_[0]) {
$state{'customaway'} = $_[0];
+ $state{'customawayexp'} = time+48*60*60;
} else {
undef $state{'customaway'};
+ undef $state{'customawayexp'};
}
- process_away();
+ do_decision();
+ save();
+}
+
+sub custom_out {
+ if($_[0]) {
+ $state{'customout'} = $_[0];
+ $state{'customoutexp'} = time+14*24*60*60;
+ } else {
+ undef $state{'customout'};
+ undef $state{'customoutexp'};
+ }
+ do_decision();
save();
}
sub custom_activity {
if($_[0]) {
- $state{'activity'} = $_[0];
+ $state{'customactivity'} = $_[0];
+ $state{'customactivityexp'} = time+12*60*60;
} else {
- undef $state{'activity'};
+ undef $state{'customactivity'};
+ undef $state{'customactivityexp'};
}
+ do_decision();
save();
}
my $val=$state{$k};
next unless($val);
$val =~ s/\n/\\n/g;
- print CONF "$k=$val\n";
+ $val =~ s/"/\\"/g;
+ print CONF "$k=\"$val\"\n";
}
close CONF;
if(defined($state{'activity'})) {
open CONF, '<' . $ENV{'HOME'} . "/.away-tpope" or return;
while(my $line=<CONF>) {
$line =~ s/\\n/\n/g;
- $line =~ s/^([^=]*)=//;
+ $line =~ s/\\"/"/g;
+ $line =~ s/"$//;
+ $line =~ s/^([^=]*)="?//;
chomp $line;
$state{$1}=$line;
}
close CONF;
}
+sub hup_handler {
+ $last=1;
+}
+
sub restart_handler {
alarm 0;
unlink $pipe;