3 # -*- perl -*- vim:set ft=perl sw=4 sts=4:
6 use vars qw(%state @ssh $last $pipe $arg $slow);
7 @ssh=("ssh","-a","-x","-oBatchmode=yes","-oSetupTimeOut=20","-qq");
8 $pipe = "/tmp/.away-tpope";
11 daemonize() if ($arg eq "-d");
12 daemon() if ($arg eq "-D");
15 if($arg eq "activity" || $arg eq "away" || $arg eq "out" || $arg eq "check") {
16 if(exists($ARGV[0])) {
17 die "Daemon not running\n" unless (-p $pipe);
18 my $a = join(" ",@ARGV);
24 print $state{$arg}."\n" if($state{$arg});
31 die "Daemon already running?\n" if (-e "/tmp/.away-tpope.pid");
32 open TMP, ">/tmp/.away-tpope.pid";
36 $SIG{'INT'} = \&quit_handler;
37 $SIG{'TERM'} = \&quit_handler;
38 $SIG{'QUIT'} = \&quit_handler;
39 $SIG{'HUP'} = \&hup_handler;
40 $SIG{'USR2'} = \&restart_handler;
41 die "Daemon already running\n" if (-r "/tmp/.tpope-away.pid");
44 system("mkfifo", $pipe);
61 elsif(defined($pid)) {
69 local $SIG{ALRM} = sub { die "alarm\n" };
71 open FIFO, "<$pipe" and
77 die unless $@ eq "alarm\n";
82 $read =~ s/^([a-z]*)( |$)//;
84 if($c eq "activity") {
85 custom_activity($read);
86 } elsif($c eq "away") {
88 } elsif($c eq "out") {
90 } elsif($c eq "check") {
93 print "Unknown command: $c\n";
96 if(time-$last >= 240) {
102 local $SIG{'HUP'} = sub {$last = 1};
104 if((!$last) || $slow++ ) {
118 $last=int(time/60)*60;
123 open(SOUT, ">&STDOUT");
125 my $ret=!(system('ping','-q','-c','1',shift)>>8);
126 open(STDOUT, ">&SOUT");
133 my $now=$now[2]*60+$now[1];
136 open(SCHEDULE, "today --category=school|");
138 my ($begin, $end, $maxend);
139 next unless /(\d\d):(\d\d)-(\d\d):(\d\d) (.*)/;
140 my ($hs,$ms,$he,$me,$ev) = ($1, $2, $3, $4, $5);
142 $begin = $hs*60+$ms-10;
143 $maxend = $he*60+$me+10;
144 $end = ($begin+10)*3/4+($maxend-10)/4;
145 if($begin <= $now && $now < $end) {
146 $state{'class'} = $ev;
147 internal_out("School");
150 } elsif($begin-35<=$now && $now<$end && $state{'phone'} eq "absent") {
151 internal_out("School");
152 } elsif (($state{'class'}||'') eq $ev) {
154 undef $state{'class'}
155 if ($now > $maxend || $state{'phone'} eq "present");
159 undef $state{'class'} unless ($familiar);
161 open(SCHEDULE, "today --category='!school !private'|");
164 my ($begin, $end, $maxend);
165 next unless /(\d\d):(\d\d)-(\d\d):(\d\d) (.*)/;
166 my ($hs,$ms,$he,$me,$ev) = ($1, $2, $3, $4, $5);
169 $maxend = $he*60+$me;
170 $end = ($begin)*3/4+($maxend)/4;
171 if($begin <= $now && $now < $end) {
172 $state{'schedule'} = $ev;
175 } elsif (($state{'schedule'}||'') eq $ev) {
177 undef $state{'schedule'}
178 if ($now > $maxend || $state{'phone'} eq "present");
182 undef $state{'schedule'} unless ($familiar);
186 if(-r ($ENV{'HOME'} . "/.chat")) {
187 open TMP, $ENV{'HOME'} . "/.chat";
188 my $chat = join ("", <TMP>);
191 $state{'chat'} = $chat;
193 undef $state{'chat'};
198 if(($state{'chat'}||'') =~ /^(tpope-\d+|jmwaller|arwen|george)$/) {
199 internal_out("Work",3*60*60);
200 } elsif(($state{'chat'}||'') eq "accd") {
201 #internal_out("School",30*60);
206 my (@check) = ("tobias", "lucille", "lindsay", "buster");
207 my (@uphosts, @livehosts, $host, $hostlist);
208 if(($_[0] || 0) == 1) {
209 $hostlist=$state{'hosts'};
210 $hostlist=~s/0\S* ?//g;
211 @livehosts = split / /, $hostlist;
214 foreach $host (@check) {
215 push @uphosts, $host if(ping($host));
217 foreach $host (@uphosts) {
218 if(is_alive($host)) {
219 push @livehosts,$host;
220 $hostlist="$host $hostlist";
222 $hostlist="0$host $hostlist";
226 $state{'hosts'}=$hostlist;
228 if(scalar @livehosts == 0) {
229 $state{'alive'} = '';
230 } elsif(scalar @livehosts > 1 && $state{'chat'}) {
231 foreach $host (@livehosts) {
232 if ($host eq $state{'chat'}) {
233 $state{'alive'} = $host;
238 $state{'alive'}=$livehosts[0];
244 local $SIG{ALRM} = sub { die "alarm\n" };
246 $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 gob .*(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);
251 die unless $@ eq "alarm\n";
258 if(!ping('tobias')) {
261 my $last_slh=`@ssh tobias cat .blue/last_slh 2>/dev/null`;
264 } elsif (time-$last_slh < 540) {
270 if(($state{'phone'}||"") ne 'present' && $phone eq 'present') {
274 $state{'phone'} = $phone;
278 open TMP, "upsc milhouse\@localhost 2>/dev/null|";
282 if(/status: (.*)/i) {
292 if ($state{'customawayexp'} && $state{'customawayexp'}<time);
294 if ($state{'customoutexp'} && $state{'customoutexp'}<time);
296 if ($state{'internaloutexp'} && $state{'internaloutexp'}<time);
298 if ($state{'customactivityexp'} && $state{'customactivityexp'}<time);
299 if (exists($state{'customactivity'})) {
300 $state{'activity'}=$state{'customactivity'};
301 } elsif ($state{'ups'} eq 'OB' || $state{'ups'} eq 'LB') {
302 $state{'activity'}="Power outage";
304 undef $state{'activity'};
306 if ($state{'customout'} && $state{'phone'} eq 'absent') {
307 $state{'away'}=$state{'customout'};
308 } elsif ($state{'customaway'}) {
309 $state{'away'}=$state{'customaway'};
310 } elsif ($state{'schedule'}) {
311 $state{'away'}=$state{'schedule'};
312 } elsif ($state{'phone'} ne 'present' && $state{'class'}) {
313 $state{'away'}="Class: ".$state{'class'};
314 } elsif ($state{'internalout'} && $state{'phone'} eq 'absent') {
315 $state{'away'}=$state{'internalout'};
316 } elsif ($state{'alive'}) {
317 undef($state{'away'});
318 } elsif ($state{'phone'} eq 'absent') {
319 $state{'away'}="Out";
320 } elsif ($state{'phone'} ne 'absent') {
322 if (0 <= $now[2] && $now[2] < 7) {
323 $state{'away'}="Sleeping";
325 $state{'away'}="Away from keyboard";
331 return undef unless($_[0]);
333 if($host eq "phone") {
338 } elsif($host eq "chat") {
343 } elsif($state{'hosts'} =~ /0$host/ && is_alive($_[0])) {
344 $state{'hosts'} =~ s/0$host/$host/;
349 } elsif($state{'hosts'} =~ /(?!0)$host/ && ! is_alive($_[0])) {
350 $state{'hosts'} =~ s/1?$host/0$host/;
359 $state{'customaway'} = $_[0];
360 $state{'customawayexp'} = time+48*60*60;
362 undef $state{'customaway'};
363 undef $state{'customawayexp'};
371 $state{'customout'} = $_[0];
372 $state{'customoutexp'} = time+14*24*60*60;
374 undef $state{'customout'};
375 undef $state{'customoutexp'};
383 $state{'internalout'} = $_[0];
384 $state{'internaloutexp'} = time+($_[1]||150*60);
386 undef $state{'internalout'};
387 undef $state{'internaloutexp'};
393 sub custom_activity {
395 $state{'customactivity'} = $_[0];
396 $state{'customactivityexp'} = time+12*60*60;
398 undef $state{'customactivity'};
399 undef $state{'customactivityexp'};
406 if (defined($state{'activity'})) {
407 $state{'status'}=$state{'activity'};
408 } elsif (defined($state{'away'})) {
409 $state{'status'}=$state{'away'};
410 } elsif ($state{'alive'} eq "tobias" || $state{'alive'} eq "lucille") {
411 $state{'status'}="On desktop";
412 } elsif ($state{'alive'} eq "lindsay") {
413 $state{'status'}="On laptop";
414 } elsif ($state{'alive'} eq "buster") {
415 $state{'status'}="In bed";
417 open CONF, '>' . $ENV{'HOME'} . "/.away-tpope" || die $!;
418 foreach my $k (keys %state) {
423 print CONF "$k=\"$val\"\n";
426 if(defined($state{'activity'})) {
427 open TMP, '>' . $ENV{'HOME'} . "/.activity";
428 print TMP $state{'activity'}."\n";
431 unlink($ENV{'HOME'} . "/.activity");
433 if(defined($state{'away'})) {
434 open TMP, '>' . $ENV{'HOME'} . "/.away";
435 print TMP $state{'away'}."\n";
438 unlink($ENV{'HOME'} . "/.away");
440 open TMP, '>' . $ENV{'HOME'} . "/.status";
441 print TMP $state{'status'}."\n";
446 open CONF, '<' . $ENV{'HOME'} . "/.away-tpope" or return;
447 undef $state{'customactivity'};
448 undef $state{'customaway'};
449 undef $state{'customout'};
450 undef $state{'internalout'};
451 while(my $line=<CONF>) {
455 $line =~ s/^([^=]*)="?//;
466 sub restart_handler {
469 unlink "/tmp/.away-tpope.pid";
471 exec($0,$arg) || die $!;
472 print "Restarting $0 $arg...\n";
477 unlink "/tmp/.away-tpope.pid";
483 system("away-actions &");