1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
<?php
namespace callnotifier;
/**
* Watches EDSS1 messages for calls. Keeps an internal call state
* and notifies loggers of incoming and finished calls.
*
* Notifications:
* - startingCall
* - finishedCall
*/
class CallMonitor
{
protected $currentCalls = array();
/**
* Array of objects that are able to load details for a call
*
* @var array
*/
protected $detaillers = array();
public function __construct($config, $log)
{
$this->config = $config;
$this->log = $log;
}
public function addDetailler(CallMonitor_Detailler $detailler)
{
$this->detaillers[] = $detailler;
}
public function handle(EDSS1_Message $msg)
{
$callId = $msg->callRef;
if (!array_key_exists($callId, $this->currentCalls)) {
$this->handleNew($callId, $msg);
} else {
$this->handleExisting($callId, $msg);
}
}
protected function handleNew($callId, EDSS1_Message $msg)
{
if ($msg->type != EDSS1_Message::SETUP) {
return;
}
$this->currentCalls[$callId] = new CallMonitor_Call();
$this->handleSetup($callId, $msg);
}
protected function handleSetup($callId, EDSS1_Message $msg)
{
$call = $this->currentCalls[$callId];
$call->start = time();
if ($msg->tei == 127) {
$call->type = CallMonitor_Call::INCOMING;
} else {
$call->type = CallMonitor_Call::OUTGOING;
}
$this->handleParams($msg, $call, $callId);
}
protected function handleExisting($callId, EDSS1_Message $msg)
{
$call = $this->currentCalls[$callId];
switch ($msg->type) {
case EDSS1_Message::INFORMATION:
$this->handleParams($msg, $call, $callId);
break;
case EDSS1_Message::ALERTING:
if ($call->type == CallMonitor_Call::OUTGOING) {
/**
* There may be two alerts: One from the telephone to the
* switchboard, and one from the switchboard to the target.
*
* The alert from the switchboard to the target call is
* sent first, so we can remove the call from the telephone
* to the switchboard.
*/
$bFound = false;
foreach ($this->currentCalls as $otherCallId => $otherCall) {
if ($otherCallId != $callId && $otherCall->to == $call->to) {
$bFound = true;
break;
}
}
if ($bFound) {
unset($this->currentCalls[$otherCallId]);
}
}
$this->loadCallDetails($call);
$this->log->log('startingCall', array('call' => $call));
break;
case EDSS1_Message::RELEASE:
case EDSS1_Message::RELEASE_COMPLETE:
$call->end = time();
//we need to load details here because they might not have been
//loaded yet, e.g. for calls to MSNs that have no phones.
$this->loadCallDetails($call);
$this->log->log('finishedCall', array('call' => $call));
unset($this->currentCalls[$callId]);
break;
}
}
protected function handleParams($msg, $call, $callId)
{
foreach ($msg->parameters as $param) {
switch ($param->type) {
case EDSS1_Parameter::CALLING_PARTY_NUMBER:
$call->from = $this->getFullNumber(
$param->number, $param->numberType
);
break;
case EDSS1_Parameter::CALLED_PARTY_NUMBER:
$call->to = $this->getFullNumber(
$param->number, $param->numberType
);
if ($call->type == CallMonitor_Call::INCOMING
&& $param->numberType != EDSS1_Parameter_Names::NUMBER_SUBSCRIBER
) {
//only keep incoming calls that arrive at the switchboard,
// not the ones from the switchboard to the telephones
unset($this->currentCalls[$callId]);
}
break;
case EDSS1_Parameter::KEYPAD:
if ($call->to === null) {
$call->to = $param->data;
}
}
}
}
protected function getFullNumber($number, $type)
{
if ($type == EDSS1_Parameter_Names::NUMBER_NATIONAL) {
return '0' . $number;
} else if ($type == EDSS1_Parameter_Names::NUMBER_INTERNATIONAL) {
return '+' . $number;
}
return $number;
}
/**
* Load details for a call, e.g. the name of the calling person
* or the area
*
* @return void
*/
protected function loadCallDetails($call)
{
foreach ($this->detaillers as $detailler) {
$detailler->loadCallDetails($call);
}
}
}
?>
|