# -*- perl -*- vim:set ft=perl sw=4 sts=4:
use strict;
-use vars qw(%state @ssh $last $pipe $arg);
-@ssh=("ssh","-a","-x","-oBatchmode=yes","-oSetupTimeOut=20");
+use vars qw(%state @ssh $last $pipe $arg $slow);
+@ssh=("ssh","-a","-x","-oBatchmode=yes","-oSetupTimeOut=20","-qq");
$pipe = "/tmp/.away-tpope";
$arg=shift || "";
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;
+ }
+ eval_chat();
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);
- $begin = $hs*60+$ms-25;
- $maxend = $he*60+$me+5;
- $end = ($begin+25)*3/4+($maxend-5)/4;
+ $ev =~ s/ *\[.*$//;
+ $begin = $hs*60+$ms-10;
+ $maxend = $he*60+$me+10;
+ $end = ($begin+10)*3/4+($maxend-10)/4;
if($begin <= $now && $now < $end) {
$state{'class'} = $ev;
+ internal_out("School");
$familiar = 1;
last;
+ } elsif($begin-35<=$now && $now<$end && $state{'phone'} eq "absent") {
+ internal_out("School");
} elsif (($state{'class'}||'') eq $ev) {
$familiar = 1;
undef $state{'class'}
close(SCHEDULE);
undef $state{'class'} unless ($familiar);
-
open(SCHEDULE, "today --category='!school !private'|");
$familiar = 0;
while(<SCHEDULE>) {
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 eval_chat {
+ if(($state{'chat'}||'') eq "jmwaller" || ($state{'chat'}||'') eq "arwen") {
+ internal_out("Work",3*60*60);
+ } elsif(($state{'chat'}||'') =~ /^tpope-\d+$/) {
+ internal_out("Work",3*60*60);
+ } elsif(($state{'chat'}||'') eq "accd") {
+ #internal_out("School",30*60);
+ }
+}
+
sub do_hosts {
- my @livehosts;
- foreach my $host ("sarah", "homer", "lisa", "mona") {
- push @livehosts, $host if(ping($host));
+ my (@check) = ("tobias", "lucille", "lindsay", "buster");
+ 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;
}
- 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);
+ if(scalar @livehosts == 0) {
+ $state{'alive'} = '';
+ } elsif(scalar @livehosts > 1 && $state{'chat'}) {
+ foreach $host (@livehosts) {
+ if ($host eq $state{'chat'}) {
+ $state{'alive'} = $host;
+ return;
+ }
+ }
+ }
+ $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 michael .*(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 $phone;
- if(!ping('mona')) {
+ if(!ping('tobias')) {
$phone="unknown";
} else {
- my $last_slh=`@ssh mona cat .blue/last_slh 2>/dev/null`;
+ my $last_slh=`@ssh tobias 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("");
+ internal_out("");
}
+ $state{'phone'} = $phone;
}
-sub process_away {
- if ($state{'customaway'}) {
+sub do_power {
+ open TMP, "upsc milhouse\@localhost 2>/dev/null|";
+ 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);
+ internal_out("")
+ if ($state{'internaloutexp'} && $state{'internaloutexp'}<time);
+ custom_activity("")
+ if ($state{'customactivityexp'} && $state{'customactivityexp'}<time);
+ if (exists($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'};
} elsif ($state{'phone'} ne 'present' && $state{'class'}) {
$state{'away'}="Class: ".$state{'class'};
+ } elsif ($state{'internalout'} && $state{'phone'} eq 'absent') {
+ $state{'away'}=$state{'internalout'};
} elsif ($state{'alive'}) {
undef($state{'away'});
} elsif ($state{'phone'} eq 'absent') {
$state{'away'}="Out";
} elsif ($state{'phone'} ne 'absent') {
my @now=localtime;
- if ($now[2] < 10) {
+ if (0 <= $now[2] && $now[2] < 7) {
$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 internal_out {
+ if($_[0]) {
+ $state{'internalout'} = $_[0];
+ $state{'internaloutexp'} = time+($_[1]||150*60);
+ } else {
+ undef $state{'internalout'};
+ undef $state{'internaloutexp'};
+ }
+ 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();
}
$state{'status'}=$state{'activity'};
} elsif (defined($state{'away'})) {
$state{'status'}=$state{'away'};
- } elsif ($state{'alive'} eq "mona" || $state{'alive'} eq "homer") {
+ } elsif ($state{'alive'} eq "tobias" || $state{'alive'} eq "lucille") {
$state{'status'}="On desktop";
- } elsif ($state{'alive'} eq "lisa") {
+ } elsif ($state{'alive'} eq "lindsay") {
$state{'status'}="On laptop";
- } elsif ($state{'alive'} eq "sarah") {
+ } elsif ($state{'alive'} eq "buster") {
$state{'status'}="In bed";
}
open CONF, '>' . $ENV{'HOME'} . "/.away-tpope" || die $!;
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'})) {
sub load {
open CONF, '<' . $ENV{'HOME'} . "/.away-tpope" or return;
+ undef $state{'customactivity'};
+ undef $state{'customaway'};
+ undef $state{'customout'};
+ undef $state{'internalout'};
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;