filter out duplicate incoming calls
[auerswald-callnotifier.git] / src / callnotifier / CallMonitor.php
1 <?php
2 namespace callnotifier;
3
4 /**
5  * Watches EDSS1 messages for calls. Keeps an internal call state
6  * and notifies loggers of incoming and finished calls.
7  *
8  * Notifications:
9  * - incomingCall
10  * - finishedCall
11  */
12 class CallMonitor
13 {
14     protected $currentCalls = array();
15
16     public function __construct($config, $log)
17     {
18         $this->config = $config;
19         $this->log = $log;
20     }
21
22     public function handle(EDSS1_Message $msg)
23     {
24         $callId = $msg->callRef;
25         if (!array_key_exists($callId, $this->currentCalls)) {
26             $this->handleNew($callId, $msg);
27         } else {
28             $this->handleExisting($callId, $msg);
29         }
30     }
31
32     protected function handleNew($callId, EDSS1_Message $msg)
33     {
34         if ($msg->type != EDSS1_Message::SETUP) {
35             return;
36         }
37         $this->currentCalls[$callId] = new CallMonitor_Call();
38         $this->handleSetup($callId, $msg);
39     }
40
41
42     protected function handleSetup($callId, EDSS1_Message $msg)
43     {
44         $call = $this->currentCalls[$callId];
45         $call->start = time();
46         if ($msg->tei == 127) {
47             $call->type = CallMonitor_Call::INCOMING;
48         } else {
49             $call->type = CallMonitor_Call::OUTGOING;
50         }
51
52         $this->handleParams($msg, $call, $callId);
53     }
54
55
56     protected function handleExisting($callId, EDSS1_Message $msg)
57     {
58         $call = $this->currentCalls[$callId];
59
60         switch ($msg->type) {
61         case EDSS1_Message::INFORMATION:
62             $this->handleParams($msg, $call, $callId);
63             break;
64         case EDSS1_Message::ALERTING:
65             if ($call->type == CallMonitor_Call::OUTGOING) {
66                 /**
67                  * There may be two alerts: One from the telephone to the
68                  * switchboard, and one from the switchboard to the target.
69                  *
70                  * The alert from the switchboard to the target call is
71                  * sent first, so we can remove the call from the telephone
72                  * to the switchboard.
73                  */
74                 $bFound = false;
75                 foreach ($this->currentCalls as $otherCallId => $otherCall) {
76                     if ($otherCallId != $callId && $otherCall->to == $call->to) {
77                         $bFound = true;
78                         break;
79                     }
80                 }
81                 if ($bFound) {
82                     unset($this->currentCalls[$otherCallId]);
83                 }
84             }
85             $this->log->log('startingCall', array('call' => $call));
86             break;
87
88         case EDSS1_Message::RELEASE:
89         case EDSS1_Message::RELEASE_COMPLETE:
90             $call->end = time();
91             $this->log->log('finishedCall', array('call' => $call));
92             unset($this->currentCalls[$callId]);
93             break;
94         }
95     }
96
97     protected function handleParams($msg, $call, $callId)
98     {
99         foreach ($msg->parameters as $param) {
100             switch ($param->type) {
101             case EDSS1_Parameter::CALLING_PARTY_NUMBER:
102                 $call->from = $this->getFullNumber(
103                     $param->number, $param->numberType
104                 );
105                 break;
106             case EDSS1_Parameter::CALLED_PARTY_NUMBER:
107                 $call->to = $this->getFullNumber(
108                     $param->number, $param->numberType
109                 );
110                 if ($call->type == CallMonitor_Call::INCOMING
111                     && $param->numberType != EDSS1_Parameter_Names::NUMBER_SUBSCRIBER
112                 ) {
113                     //only keep incoming calls that arrive at the switchboard,
114                     // not the ones from the switchboard to the telephones
115                     unset($this->currentCalls[$callId]);
116                 }
117                 break;
118             case EDSS1_Parameter::KEYPAD:
119                 if ($call->to === null) {
120                     $call->to = $param->data;
121                 }
122             }
123         }
124     }
125
126
127     protected function getFullNumber($number, $type)
128     {
129         if ($type == EDSS1_Parameter_Names::NUMBER_NATIONAL) {
130             return '0' . $number;
131         }
132         return $number;
133     }
134 }
135
136 ?>