Assorted away-tpope updates
[tpope-extra.git] / perl / mobile-phone-monitor
1 #!/usr/bin/perl
2 # $Id$
3 # -*- perl -*- vim:set ft=perl sw=4 sts=4:
4
5 # Monitors a bluetooth mobile phone for calls.  You'll need to bind rfcomm1 to
6 # your mobile phone's SP service.  You'll also need my Device::Nokia module
7 # (the name is misleading, it's not Nokia specific).
8
9 use strict;
10 use Device::Nokia;
11 my $number;
12 my %status;
13 my $quiton;
14 my $daemonize;
15 my $last=0;
16 my $gsm = new Device::Nokia( port => '/dev/rfcomm1', log => 'file,/dev/null');
17
18 $SIG{INT}  = 'death';
19 $SIG{TERM} = 'death';
20 $SIG{QUIT} = 'death';
21
22 sub initialize {
23     my $gsm=shift;
24     $gsm->connect() || return 0;
25     $gsm->atsend( 'AT+CLIP=1' . Device::Modem::CR );
26     $gsm->answer();
27     return 1;
28 }
29
30 initialize($gsm) || die "Could not initialize modem: $!";
31
32 while($_=shift) {
33     $daemonize=1 if ($_ eq "-d");
34     $quiton=1 if ($_ eq "-b");
35 }
36
37 daemonize() if $daemonize;
38
39 $|=1;
40 while(1) {
41 %status=("is_active"=>1);
42 while($status{"is_active"} ne 0) {
43     for(my $i=0;$i<3;$i++) {
44         sleep 1;
45         $number = wait_for_ring();
46         if($number) {
47             $status{"number"} = $number;
48             output_status(%status);
49             ring($number);
50             last;
51         } elsif(!defined($number)) { $status{"is_active"}=0; last; };
52     }
53     my %newstatus=gather_data($gsm);
54     ring() if($newstatus{"call"}!=0 && $status{"call"}==0 && !$status{"number"});
55     foreach (keys %newstatus) {
56         $status{$_} = $newstatus{$_} if(defined ($newstatus{$_}));
57     }
58     undef $status{"number"} if (!$number && $status{"callsetup"}==0 && $status{"call"}==0);
59     output_status(%status);
60     if ($status{"source"}==0 && $status{"callsetup"}==0 && $status{"call"}==0 && $quiton) {
61         death() if(time-$last>600);
62     } elsif ($quiton) {
63         $last=time;
64     }
65 }
66 $gsm->disconnect();
67 output_status(is_active => 0);
68 do {sleep (60-30*$quiton);}
69 until(initialize($gsm));
70 }
71
72 sub wait_for_ring {
73     local $_;
74     eval {
75         local $SIG{ALRM} = sub { die "alarm\n" };
76         alarm 5;
77         $_ = $gsm->answer("\\+CLIP: \"[0-9]+\",[0-9]+\$", 30);
78         alarm 0
79     };
80     if($@) {
81         die unless $@ eq "alarm\n";
82         return undef;
83     } else {
84         m/CLIP: "([0-9]+)",/;
85         return "$1";
86     }
87 }
88
89 sub ring {
90     system($ENV{"HOME"} . "/bin/phone-call " . $_[0]);
91 }
92
93 sub gather_data {
94   my %data;
95   my $gsm=shift;
96   eval {
97   local $SIG{ALRM} = sub { die "alarm\n" };
98   alarm 15;
99   %data=$gsm->indicators();
100   my ($first, $second) = $gsm->battery_strength();
101   $data{"source"}=$first;
102   #$data{"battery"}=$second;
103   ($first, $second) = $gsm->signal_quality();
104   $data{"signal"}=$first;
105   alarm 0;
106   };
107     if($@) {
108         die unless $@ eq "alarm\n";
109         return (is_active => 0);
110     } else {
111         $data{"is_active"}=$gsm->is_active() && $data{"signal"} && 1 || 0;
112         return %data;
113     }
114 }
115
116 sub output_status {
117     my %status = @_;
118     open STATUS, ">/tmp/.phone-status.new" || die $!;
119     foreach my $indicator (sort keys %status) {
120         print STATUS "$indicator=" . $status{$indicator} . "\n";
121     };
122     close STATUS;
123     rename "/tmp/.phone-status.new", "/tmp/.phone-status" || die $!;
124 }
125
126 sub daemonize {
127     chdir "/";
128     my $pid=fork();
129     if($pid) {
130         exit(0)
131     }
132     elsif(defined($pid))
133     {
134         close STDIN;
135         close STDOUT;
136         close STDERR;
137     }
138     else { exit(1); }
139 }
140
141 sub death {
142     $gsm->disconnect() if($gsm);
143     unlink "/tmp/.phone-status.new", "/tmp/.phone-status";
144     exit(0);
145 }