Passed
Push — master ( db404c...6ceb7d )
by Chizhov
01:42
created

AGI_AsteriskManager::read_one_msg()   D

Complexity

Conditions 15
Paths 241

Size

Total Lines 71
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
eloc 47
nc 241
nop 1
dl 0
loc 71
rs 4.5708
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Inok\phpagi;
4
5
use Exception;
6
7
/**
8
 * phpagi-asmanager.php : PHP Asterisk Manager functions
9
 * @see https://github.com/welltime/phpagi
10
 * @filesource http://phpagi.sourceforge.net/
11
 *
12
 * $Id: phpagi-asmanager.php,v 1.10 2005/05/25 18:43:48 pinhole Exp $
13
 *
14
 * Copyright (c) 2004 - 2010 Matthew Asham <[email protected]>, David Eder <[email protected]> and others
15
 * All Rights Reserved.
16
 *
17
 * This software is released under the terms of the GNU Lesser General Public License v2.1
18
 *  A copy of which is available from http://www.gnu.org/copyleft/lesser.html
19
 *
20
 * We would be happy to list your phpagi based application on the phpagi
21
 * website.  Drop me an Email if you'd like us to list your program.
22
 *
23
 * @package phpAGI
24
 * @version 2.0
25
 */
26
27
28
/**
29
 * Written for PHP 4.3.4, should work with older PHP 4.x versions.
30
 * Please submit bug reports, patches, etc to https://github.com/welltime/phpagi
31
 *
32
 */
33
34
/**
35
 * Asterisk Manager class
36
 *
37
 * @link http://www.voip-info.org/wiki-Asterisk+config+manager.conf
38
 * @link http://www.voip-info.org/wiki-Asterisk+manager+API
39
 * @example examples/sip_show_peer.php Get information about a sip peer
40
 * @package phpAGI
41
 */
42
class AGI_AsteriskManager
43
{
44
  /**
45
   * Config variables
46
   *
47
   * @var array
48
   * @access public
49
   */
50
  public $config;
51
52
  /**
53
   * Socket
54
   *
55
   * @access public
56
   */
57
  public $socket = null;
58
59
  /**
60
   * Server we are connected to
61
   *
62
   * @access public
63
   * @var string
64
   */
65
  public $server;
66
67
  /**
68
   * Port on the server we are connected to
69
   *
70
   * @access public
71
   * @var integer
72
   */
73
  public $port;
74
75
  /**
76
   * Parent AGI
77
   *
78
   * @access private
79
   * @var AGI
80
   */
81
  private $pagi = false;
82
83
  /**
84
   * Event Handlers
85
   *
86
   * @access private
87
   * @var array
88
   */
89
  private $event_handlers;
90
91
  private $_buffer = null;
92
93
  /**
94
   * Whether we're successfully logged in
95
   *
96
   * @access private
97
   * @var boolean
98
   */
99
  private $_logged_in = false;
100
101
  private $defaultConfig = ["server" => 'localhost',
102
                            "port" => 5038,
103
                            "username" => "phpagi",
104
                            "secret" => "phpagi",
105
                            "write_log" => false];
106
107
  public function setPagi(&$agi) {
108
    $this->pagi = $agi;
109
  }
110
111
  /**
112
   * Constructor
113
   *
114
   * @param string $config is the name of the config file to parse or a parent agi from which to read the config
115
   * @param array $optconfig is an array of configuration vars and values, stuffed into $this->config['asmanager']
116
   */
117
  function __construct($config = null, array $optconfig = []) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
118
    // load config
119
    if (!is_null($config) && file_exists($config)) {
120
      $this->config = parse_ini_file($config, true);
121
    } elseif (file_exists(AGI_Others::DEFAULT_PHPAGI_CONFIG)) {
122
      $this->config = parse_ini_file(AGI_Others::DEFAULT_PHPAGI_CONFIG, true);
123
    }
124
125
    // If optconfig is specified, stuff values and vars into 'asmanager' config array.
126
    foreach ($optconfig as $var => $val) {
127
      $this->config['asmanager'][$var] = $val;
128
    }
129
130
    // add default values to config for uninitialized values
131
    foreach ($this->defaultConfig as $name => $value) {
132
      $this->config['asmanager'][$name] = $this->config['asmanager'][$name] ?? $value;
133
    }
134
  }
135
136
  /**
137
   * Send a request
138
   *
139
   * @param string $action
140
   * @param array $parameters
141
   * @return array of parameters
142
   * @throws Exception
143
   */
144
  function send_request(string $action, array $parameters = []): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
145
    $req = "Action: $action\r\n";
146
    $actionid = null;
147
    foreach ($parameters as $var => $val) {
148
      if (is_array($val)) {
149
        foreach ($val as $line) {
150
          $req .= "$var: $line\r\n";
151
        }
152
        continue;
153
      }
154
      $req .= "$var: $val\r\n";
155
      if (strtolower($var) == "actionid") {
156
        $actionid = $val;
157
      }
158
    }
159
    if (!$actionid) {
160
      $actionid = $this->ActionID();
161
      $req .= "ActionID: $actionid\r\n";
162
    }
163
    $req .= "\r\n";
164
165
    fwrite($this->socket, $req);
166
167
    return $this->wait_response(false, $actionid);
168
  }
169
170
  /**
171
   * @param bool $allow_timeout
172
   * @return array
173
   * @throws Exception
174
   */
175
  function read_one_msg(bool $allow_timeout = false): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Unused Code introduced by
The parameter $allow_timeout is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

175
  function read_one_msg(/** @scrutinizer ignore-unused */ bool $allow_timeout = false): array {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
176
    $type = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $type is dead and can be removed.
Loading history...
177
178
    do {
179
      $buf = fgets($this->socket, 4096);
180
      if (false === $buf) {
181
        throw new Exception("Error reading from AMI socket");
182
      }
183
      $this->_buffer .= $buf;
184
185
      $pos = strpos($this->_buffer, "\r\n\r\n");
186
      if (false !== $pos) {
187
        // there's a full message in the buffer
188
        break;
189
      }
190
    } while (!feof($this->socket));
191
192
    $msg = substr($this->_buffer, 0, $pos);
193
    $this->_buffer = substr($this->_buffer, $pos + 4);
194
195
    $msgarr = explode("\r\n", $msg);
196
197
    $parameters = [];
198
199
    $r = explode(': ', $msgarr[0]);
200
    $type = strtolower($r[0]);
201
202
    if (in_array($r[1], ['Success', 'Follows'])) {
203
      $str = array_pop($msgarr);
204
      $lastline = strpos($str, '--END COMMAND--');
205
      if (false !== $lastline) {
206
        $parameters['data'] = substr($str, 0, $lastline - 1); // cut '\n' too
207
      }
208
    }
209
210
    $haveData = array_key_exists("data", $parameters);
211
    $asteriskRawOutput = [];
212
213
    foreach ($msgarr as $num => $str) {
214
      $kv = explode(':', $str, 2);
215
      if (!isset($kv[1])) {
216
        $kv[1] = "";
217
      }
218
      $key = trim($kv[0]);
219
      $val = trim($kv[1]);
220
      if (!$haveData && mb_strtolower($key) == "output") {
221
        $asteriskRawOutput[] = $val;
222
        continue;
223
      }
224
      $parameters[$key] = $val;
225
    }
226
    if (!$haveData && count($asteriskRawOutput)) {
227
      $parameters["data"] = implode("\n", $asteriskRawOutput);
228
    }
229
230
    // process response
231
    switch ($type) {
232
      case '': // timeout occurred
233
        // $timeout = $allow_timeout;
234
        break;
235
      case 'event':
236
        $this->process_event($parameters);
237
        break;
238
      case 'response':
239
        break;
240
      default:
241
        $this->log('Unhandled response packet from Manager: ' . print_r($parameters, true));
0 ignored issues
show
Bug introduced by
Are you sure print_r($parameters, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

241
        $this->log('Unhandled response packet from Manager: ' . /** @scrutinizer ignore-type */ print_r($parameters, true));
Loading history...
242
        break;
243
    }
244
245
    return $parameters;
246
  }
247
248
  /**
249
   * Wait for a response
250
   *
251
   * If a request was just sent, this will return the response.
252
   * Otherwise, it will loop forever, handling events.
253
   *
254
   * XXX this code is slightly better then the original one
255
   * however it's still totally screwed up and needs to be rewritten,
256
   * for two reasons at least:
257
   * 1. it does not handle socket errors in any way
258
   * 2. it is terribly synchronous, esp. with eventlists,
259
   *    i.e. your code is blocked on waiting until full response is received
260
   *
261
   * @param boolean $allow_timeout if the socket times out, return an empty array
262
   * @param string $actionid
263
   * @return array of parameters, empty on timeout
264
   * @throws Exception
265
   */
266
  function wait_response(bool $allow_timeout = false, $actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
267
    if ($actionid) {
268
      do {
269
        $res = $this->read_one_msg($allow_timeout);
270
      } while (!(isset($res['ActionID']) && $res['ActionID'] == $actionid));
271
    } else {
272
      $res = $this->read_one_msg($allow_timeout);
273
      return $res;
274
    }
275
276
    if (isset($res['EventList']) && $res['EventList'] == 'start') {
277
      $evlist = [];
278
      do {
279
        $res = $this->wait_response(false, $actionid);
280
        if (isset($res['EventList']) && $res['EventList'] == 'Complete') {
281
          break;
282
        }
283
        $evlist[] = $res;
284
      } while (true);
285
      $res['events'] = $evlist;
286
    }
287
288
    return $res;
289
  }
290
291
292
  /**
293
   * Connect to Asterisk
294
   *
295
   * @param string $server
296
   * @param string $username
297
   * @param string $secret
298
   * @return boolean true on success
299
   * @throws Exception
300
   * @example examples/sip_show_peer.php Get information about a sip peer
301
   *
302
   */
303
  function connect($server = null, $username = null, $secret = null): bool {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
304
    // use config if not specified
305
    if (is_null($server)) {
306
      $server = $this->config['asmanager']['server'];
307
    }
308
    if (is_null($username)) {
309
      $username = $this->config['asmanager']['username'];
310
    }
311
    if (is_null($secret)) {
312
      $secret = $this->config['asmanager']['secret'];
313
    }
314
315
    // get port from server if specified
316
    if (strpos($server, ':') !== false) {
317
      $c = explode(':', $server);
318
      $this->server = $c[0];
319
      $this->port = $c[1];
0 ignored issues
show
Documentation Bug introduced by
The property $port was declared of type integer, but $c[1] is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
320
    } else {
321
      $this->server = $server;
322
      $this->port = $this->config['asmanager']['port'];
323
    }
324
325
    // connect the socket
326
    $errno = $errstr = null;
327
    $this->socket = fsockopen($this->server, $this->port, $errno, $errstr);
328
    if ($this->socket === false) {
329
      $this->log("Unable to connect to manager {$this->server}:{$this->port} ($errno): $errstr");
330
      return false;
331
    }
332
333
    // read the header
334
    $str = fgets($this->socket);
335
    if ($str === false) {
336
      // a problem.
337
      $this->log("Asterisk Manager header not received.");
338
      return false;
339
    }
340
341
    // login
342
    $res = $this->send_request('login', ['Username' => $username,
343
                                         'Secret' => $secret]);
344
    if ($res['Response'] != 'Success') {
345
      $this->_logged_in = false;
346
      $this->log("Failed to login.");
347
      $this->disconnect();
348
      return false;
349
    }
350
    $this->_logged_in = true;
351
    return true;
352
  }
353
354
  /**
355
   * Disconnect
356
   *
357
   * @throws Exception
358
   * @example examples/sip_show_peer.php Get information about a sip peer
359
   */
360
  function disconnect() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
361
    if ($this->_logged_in) {
362
      $this->logoff();
363
    }
364
    fclose($this->socket);
365
  }
366
367
  // *********************************************************************************************************
368
  // **                       COMMANDS                                                                      **
369
  // *********************************************************************************************************
370
371
  /**
372
   * Set Absolute Timeout
373
   *
374
   * Hangup a channel after a certain time.
375
   *
376
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+AbsoluteTimeout
377
   * @param string $channel Channel name to hangup
378
   * @param integer $timeout Maximum duration of the call (sec)
379
   * @return array
380
   * @throws Exception
381
   */
382
  function AbsoluteTimeout(string $channel, int $timeout): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
383
    return $this->send_request('AbsoluteTimeout', ['Channel' => $channel,
384
                                                   'Timeout' => $timeout]);
385
  }
386
387
  /**
388
   * Change monitoring filename of a channel
389
   *
390
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ChangeMonitor
391
   * @param string $channel the channel to record.
392
   * @param string $file the new name of the file created in the monitor spool directory.
393
   * @return array
394
   * @throws Exception
395
   */
396
  function ChangeMonitor(string $channel, string $file): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
397
    return $this->send_request('ChangeMonitor', ['Channel' => $channel,
398
                                                 'File' => $file]);
399
  }
400
401
  /**
402
   * Execute Command
403
   *
404
   * @param string $command
405
   * @param string $actionid message matching variable
406
   * @return array
407
   * @throws Exception
408
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Command
409
   * @link http://www.voip-info.org/wiki-Asterisk+CLI
410
   * @example examples/sip_show_peer.php Get information about a sip peer
411
   */
412
  function Command(string $command, $actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
413
    $parameters = ['Command' => $command];
414
    if ($actionid) {
415
      $parameters['ActionID'] = $actionid;
416
    }
417
    return $this->send_request('Command', $parameters);
418
  }
419
420
  /**
421
   * Enable/Disable sending of events to this manager
422
   *
423
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Events
424
   * @param string $eventmask is either 'on', 'off', or 'system,call,log'
425
   * @return array
426
   * @throws Exception
427
   */
428
  function Events(string $eventmask): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
429
    return $this->send_request('Events', ['EventMask' => $eventmask]);
430
  }
431
432
  /**
433
   *  Generate random ActionID
434
   **/
435
  function ActionID(): string {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
436
    return "A" . sprintf(rand(), "%6d");
437
  }
438
439
  /**
440
   *
441
   *  DBGet
442
   *  http://www.voip-info.org/wiki/index.php?page=Asterisk+Manager+API+Action+DBGet
443
   * @param string $family key family
444
   * @param string $key key name
445
   * @param string $actionid
446
   * @return string
447
   *
448
   * @throws Exception
449
   */
450
  function DBGet(string $family, string $key, $actionid = null): string {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
451
    $parameters = ['Family' => $family,
452
                   'Key' => $key];
453
    if ($actionid == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $actionid of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
454
      $actionid = $this->ActionID();
455
    }
456
    $parameters['ActionID'] = $actionid;
457
    $response = $this->send_request("DBGet", $parameters);
458
    if ($response['Response'] == "Success") {
459
      $response = $this->wait_response(false, $actionid);
460
      return $response['Val'];
461
    }
462
    return "";
463
  }
464
465
  /**
466
   * Check Extension Status
467
   *
468
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ExtensionState
469
   * @param string $exten Extension to check state on
470
   * @param string $context Context for extension
471
   * @param string $actionid message matching variable
472
   * @return array
473
   * @throws Exception
474
   */
475
  function ExtensionState(string $exten, string $context, $actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
476
    $parameters = ['Exten' => $exten,
477
                   'Context' => $context];
478
    if ($actionid) {
479
      $parameters['ActionID'] = $actionid;
480
    }
481
    return $this->send_request('ExtensionState', $parameters);
482
  }
483
484
  /**
485
   * Gets a Channel Variable
486
   *
487
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+GetVar
488
   * @link http://www.voip-info.org/wiki-Asterisk+variables
489
   * @param string $channel Channel to read variable from
490
   * @param string $variable
491
   * @param string $actionid message matching variable
492
   * @return array
493
   * @throws Exception
494
   */
495
  function GetVar(string $channel, string $variable, $actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
496
    $parameters = ['Channel' => $channel,
497
                   'Variable' => $variable];
498
    if ($actionid) {
499
      $parameters['ActionID'] = $actionid;
500
    }
501
    return $this->send_request('GetVar', $parameters);
502
  }
503
504
  /**
505
   * Hangup Channel
506
   *
507
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Hangup
508
   * @param string $channel The channel name to be hangup
509
   * @return array
510
   * @throws Exception
511
   */
512
  function Hangup(string $channel): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
513
    return $this->send_request('Hangup', ['Channel' => $channel]);
514
  }
515
516
  /**
517
   * List IAX Peers
518
   *
519
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+IAXpeers
520
   * @throws Exception
521
   */
522
  function IAXPeers(): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
523
    return $this->send_request('IAXPeers');
524
  }
525
526
  /**
527
   * List available manager commands
528
   *
529
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ListCommands
530
   * @param string $actionid message matching variable
531
   * @return array
532
   * @throws Exception
533
   */
534
  function ListCommands($actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
535
    return $this->send_request('ListCommands', $actionid ? ['ActionID' => $actionid] : []);
536
  }
537
538
  /**
539
   * Logoff Manager
540
   *
541
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Logoff
542
   * @throws Exception
543
   */
544
  function Logoff(): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
545
    return $this->send_request('Logoff');
546
  }
547
548
  /**
549
   * Check Mailbox Message Count
550
   *
551
   * Returns number of new and old messages.
552
   *   Message: Mailbox Message Count
553
   *   Mailbox: <mailboxid>
554
   *   NewMessages: <count>
555
   *   OldMessages: <count>
556
   *
557
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+MailboxCount
558
   * @param string $mailbox Full mailbox ID <mailbox>@<vm-context>
559
   * @param string $actionid message matching variable
560
   * @return array
561
   * @throws Exception
562
   */
563
  function MailboxCount(string $mailbox, $actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
564
    $parameters = ['Mailbox' => $mailbox];
565
    if ($actionid) {
566
      $parameters['ActionID'] = $actionid;
567
    }
568
    return $this->send_request('MailboxCount', $parameters);
569
  }
570
571
  /**
572
   * Check Mailbox
573
   *
574
   * Returns number of messages.
575
   *   Message: Mailbox Status
576
   *   Mailbox: <mailboxid>
577
   *   Waiting: <count>
578
   *
579
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+MailboxStatus
580
   * @param string $mailbox Full mailbox ID <mailbox>@<vm-context>
581
   * @param string $actionid message matching variable
582
   * @return array
583
   * @throws Exception
584
   */
585
  function MailboxStatus(string $mailbox, $actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
586
    $parameters = ['Mailbox' => $mailbox];
587
    if ($actionid) {
588
      $parameters['ActionID'] = $actionid;
589
    }
590
    return $this->send_request('MailboxStatus', $parameters);
591
  }
592
593
  /**
594
   * Monitor a channel
595
   *
596
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Monitor
597
   * @param string $channel
598
   * @param string $file
599
   * @param string $format
600
   * @param boolean $mix
601
   * @return array
602
   * @throws Exception
603
   */
604
  function Monitor(string $channel, $file = null, $format = null, $mix = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
605
    $parameters = ['Channel' => $channel];
606
    if ($file) {
607
      $parameters['File'] = $file;
608
    }
609
    if ($format) {
610
      $parameters['Format'] = $format;
611
    }
612
    if (!is_null($file)) {
613
      $parameters['Mix'] = ($mix) ? 'true' : 'false';
614
    }
615
    return $this->send_request('Monitor', $parameters);
616
  }
617
618
  /**
619
   * Originate Call
620
   *
621
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Originate
622
   * @param string $channel Channel name to call
623
   * @param string $exten Extension to use (requires 'Context' and 'Priority')
624
   * @param string $context Context to use (requires 'Exten' and 'Priority')
625
   * @param string $priority Priority to use (requires 'Exten' and 'Context')
626
   * @param string $application Application to use
627
   * @param string $data Data to use (requires 'Application')
628
   * @param integer $timeout How long to wait for call to be answered (in ms)
629
   * @param string $callerid Caller ID to be set on the outgoing channel
630
   * @param string $variable Channel variable to set (VAR1=value1|VAR2=value2)
631
   * @param string $account Account code
632
   * @param boolean $async true fast origination
633
   * @param string $actionid message matching variable
634
   * @return array
635
   * @throws Exception
636
   */
637
  function Originate(string $channel,
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
638
                     $exten = null, $context = null, $priority = null,
639
                     $application = null, $data = null,
640
                     $timeout = null, $callerid = null, $variable = null, $account = null, $async = null, $actionid = null): array {
641
    $parameters = ['Channel' => $channel];
642
643
    if ($exten) {
644
      $parameters['Exten'] = $exten;
645
    }
646
    if ($context) {
647
      $parameters['Context'] = $context;
648
    }
649
    if ($priority) {
650
      $parameters['Priority'] = $priority;
651
    }
652
653
    if ($application) {
654
      $parameters['Application'] = $application;
655
    }
656
    if ($data) {
657
      $parameters['Data'] = $data;
658
    }
659
660
    if ($timeout) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $timeout of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
661
      $parameters['Timeout'] = $timeout;
662
    }
663
    if ($callerid) {
664
      $parameters['CallerID'] = $callerid;
665
    }
666
    if ($variable) {
667
      $parameters['Variable'] = $variable;
668
    }
669
    if ($account) {
670
      $parameters['Account'] = $account;
671
    }
672
    if (!is_null($async)) {
673
      $parameters['Async'] = ($async) ? 'true' : 'false';
674
    }
675
    if ($actionid) {
676
      $parameters['ActionID'] = $actionid;
677
    }
678
679
    return $this->send_request('Originate', $parameters);
680
  }
681
682
  /**
683
   * List parked calls
684
   *
685
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ParkedCalls
686
   * @param string $actionid message matching variable
687
   * @return array
688
   * @throws Exception
689
   */
690
  function ParkedCalls($actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
691
    return $this->send_request('ParkedCalls', $actionid ? ['ActionID' => $actionid] : []);
692
  }
693
694
  /**
695
   * Ping
696
   *
697
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Ping
698
   * @throws Exception
699
   */
700
  function Ping(): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
701
    return $this->send_request('Ping');
702
  }
703
704
  /**
705
   * Queue Add
706
   *
707
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+QueueAdd
708
   * @param string $queue
709
   * @param string $interface
710
   * @param integer $penalty
711
   * @param string $memberName
712
   * @return array
713
   * @throws Exception
714
   */
715
  function QueueAdd(string $queue, string $interface, int $penalty = 0, $memberName = false): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
716
    $parameters = ['Queue' => $queue,
717
                   'Interface' => $interface];
718
    if ($penalty) {
719
      $parameters['Penalty'] = $penalty;
720
    }
721
    if ($memberName) {
722
      $parameters["MemberName"] = $memberName;
723
    }
724
    return $this->send_request('QueueAdd', $parameters);
725
  }
726
727
  /**
728
   * Queue Remove
729
   *
730
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+QueueRemove
731
   * @param string $queue
732
   * @param string $interface
733
   * @return array
734
   * @throws Exception
735
   */
736
  function QueueRemove(string $queue, string $interface): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
737
    return $this->send_request('QueueRemove', ['Queue' => $queue,
738
                                               'Interface' => $interface]);
739
  }
740
741
  /**
742
   * @return array
743
   * @throws Exception
744
   */
745
  function QueueReload(): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
746
    return $this->send_request('QueueReload');
747
  }
748
749
  /**
750
   * Queues
751
   *
752
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Queues
753
   * @throws Exception
754
   */
755
  function Queues(): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
756
    return $this->send_request('Queues');
757
  }
758
759
  /**
760
   * Queue Status
761
   *
762
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+QueueStatus
763
   * @param string $actionid message matching variable
764
   * @return array
765
   * @throws Exception
766
   */
767
  function QueueStatus($actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
768
    return $this->send_request('QueueStatus', $actionid ? ['ActionID' => $actionid] : []);
769
  }
770
771
  /**
772
   * Redirect
773
   *
774
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Redirect
775
   * @param string $channel
776
   * @param string $extrachannel
777
   * @param string $exten
778
   * @param string $context
779
   * @param string $priority
780
   * @return array
781
   * @throws Exception
782
   */
783
  function Redirect(string $channel, string $extrachannel, string $exten, string $context, string $priority): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
784
    return $this->send_request('Redirect', ['Channel' => $channel,
785
                                            'ExtraChannel' => $extrachannel,
786
                                            'Exten' => $exten,
787
                                            'Context' => $context,
788
                                            'Priority' => $priority]);
789
  }
790
791
  /**
792
   * @param string $channel
793
   * @param string $exten
794
   * @param string $context
795
   * @param string $priority
796
   * @return array
797
   * @throws Exception
798
   */
799
  function Atxfer(string $channel, string $exten, string $context, string $priority): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
800
    return $this->send_request('Atxfer', ['Channel' => $channel,
801
                                          'Exten' => $exten,
802
                                          'Context' => $context,
803
                                          'Priority' => $priority]);
804
  }
805
806
  /**
807
   * Set the CDR UserField
808
   *
809
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+SetCDRUserField
810
   * @param string $userfield
811
   * @param string $channel
812
   * @param string $append
813
   * @return array
814
   * @throws Exception
815
   */
816
  function SetCDRUserField(string $userfield, string $channel, $append = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
817
    $parameters = ['UserField' => $userfield,
818
                   'Channel' => $channel];
819
    if ($append) {
820
      $parameters['Append'] = $append;
821
    }
822
    return $this->send_request('SetCDRUserField', $parameters);
823
  }
824
825
  /**
826
   * Set Channel Variable
827
   *
828
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+SetVar
829
   * @param string $channel Channel to set variable for
830
   * @param string $variable name
831
   * @param string $value
832
   * @return array
833
   * @throws Exception
834
   */
835
  function SetVar(string $channel, string $variable, string $value): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
836
    return $this->send_request('SetVar', ['Channel' => $channel,
837
                                          'Variable' => $variable,
838
                                          'Value' => $value]);
839
  }
840
841
  /**
842
   * Channel Status
843
   *
844
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Status
845
   * @param string $channel
846
   * @param string $actionid message matching variable
847
   * @return array
848
   * @throws Exception
849
   */
850
  function Status(string $channel, $actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
851
    $parameters = ['Channel' => $channel];
852
    if ($actionid) {
853
      $parameters['ActionID'] = $actionid;
854
    }
855
    return $this->send_request('Status', $parameters);
856
  }
857
858
  /**
859
   * Stop monitoring a channel
860
   *
861
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+StopMonitor
862
   * @param string $channel
863
   * @return array
864
   * @throws Exception
865
   */
866
  function StopMonitor(string $channel): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
867
    return $this->send_request('StopMonitor', ['Channel' => $channel]);
868
  }
869
870
  /**
871
   * Dial over Zap channel while offhook
872
   *
873
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ZapDialOffhook
874
   * @param string $zapchannel
875
   * @param string $number
876
   * @return array
877
   * @throws Exception
878
   */
879
  function ZapDialOffhook(string $zapchannel, string $number): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
880
    return $this->send_request('ZapDialOffhook', ['ZapChannel' => $zapchannel,
881
                                                  'Number' => $number]);
882
  }
883
884
  /**
885
   * Toggle Zap channel Do Not Disturb status OFF
886
   *
887
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ZapDNDoff
888
   * @param string $zapchannel
889
   * @return array
890
   * @throws Exception
891
   */
892
  function ZapDNDoff(string $zapchannel): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
893
    return $this->send_request('ZapDNDoff', ['ZapChannel' => $zapchannel]);
894
  }
895
896
  /**
897
   * Toggle Zap channel Do Not Disturb status ON
898
   *
899
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ZapDNDon
900
   * @param string $zapchannel
901
   * @return array
902
   * @throws Exception
903
   */
904
  function ZapDNDon(string $zapchannel): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
905
    return $this->send_request('ZapDNDon', ['ZapChannel' => $zapchannel]);
906
  }
907
908
  /**
909
   * Hangup Zap Channel
910
   *
911
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ZapHangup
912
   * @param string $zapchannel
913
   * @return array
914
   * @throws Exception
915
   */
916
  function ZapHangup(string $zapchannel): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
917
    return $this->send_request('ZapHangup', ['ZapChannel' => $zapchannel]);
918
  }
919
920
  /**
921
   * Transfer Zap Channel
922
   *
923
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ZapTransfer
924
   * @param string $zapchannel
925
   * @return array
926
   * @throws Exception
927
   */
928
  function ZapTransfer(string $zapchannel): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
929
    return $this->send_request('ZapTransfer', ['ZapChannel' => $zapchannel]);
930
  }
931
932
  /**
933
   * Zap Show Channels
934
   *
935
   * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ZapShowChannels
936
   * @param string $actionid message matching variable
937
   * @return array
938
   * @throws Exception
939
   */
940
  function ZapShowChannels($actionid = null): array {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
941
    return $this->send_request('ZapShowChannels', $actionid ? ['ActionID' => $actionid] : []);
942
  }
943
944
  // *********************************************************************************************************
945
  // **                       MISC                                                                          **
946
  // *********************************************************************************************************
947
948
  /*
949
   * Log a message
950
   *
951
   * @param string $message
952
   * @param integer $level from 1 to 4
953
   */
954
  function log(string $message, int $level = 1) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
955
    if ($this->pagi != false) {
0 ignored issues
show
introduced by
The condition $this->pagi != false is always true.
Loading history...
956
      $this->pagi->conlog($message, $level);
957
    } elseif ($this->config['asmanager']['write_log']) {
958
      error_log(date('r') . ' - ' . $message);
959
    }
960
  }
961
962
  /**
963
   * Add event handler
964
   *
965
   * Known Events include ( http://www.voip-info.org/wiki-asterisk+manager+events )
966
   *   Link - Fired when two voice channels are linked together and voice data exchange commences.
967
   *   Unlink - Fired when a link between two voice channels is discontinued, for example, just before call completion.
968
   *   Newexten -
969
   *   Hangup -
970
   *   Newchannel -
971
   *   Newstate -
972
   *   Reload - Fired when the "RELOAD" console command is executed.
973
   *   Shutdown -
974
   *   ExtensionStatus -
975
   *   Rename -
976
   *   Newcallerid -
977
   *   Alarm -
978
   *   AlarmClear -
979
   *   Agentcallbacklogoff -
980
   *   Agentcallbacklogin -
981
   *   Agentlogoff -
982
   *   MeetmeJoin -
983
   *   MessageWaiting -
984
   *   join -
985
   *   leave -
986
   *   AgentCalled -
987
   *   ParkedCall - Fired after ParkedCalls
988
   *   Cdr -
989
   *   ParkedCallsComplete -
990
   *   QueueParams -
991
   *   QueueMember -
992
   *   QueueStatusEnd -
993
   *   Status -
994
   *   StatusComplete -
995
   *   ZapShowChannels - Fired after ZapShowChannels
996
   *   ZapShowChannelsComplete -
997
   *
998
   * @param string $event type or * for default handler
999
   * @param string $callback function
1000
   * @return boolean success
1001
   */
1002
  function add_event_handler(string $event, string $callback): bool {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1003
    $event = strtolower($event);
1004
    if (isset($this->event_handlers[$event])) {
1005
      $this->log("$event handler is already defined, not over-writing.");
1006
      return false;
1007
    }
1008
    $this->event_handlers[$event] = $callback;
1009
    return true;
1010
  }
1011
1012
  /**
1013
   *
1014
   *   Remove event handler
1015
   *
1016
   * @param string $event type or * for default handler
1017
   * @return boolean success
1018
   **/
1019
  function remove_event_handler(string $event): bool {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1020
    $event = strtolower($event);
1021
    if (isset($this->event_handlers[$event])) {
1022
      unset($this->event_handlers[$event]);
1023
      return true;
1024
    }
1025
    $this->log("$event handler is not defined.");
1026
    return false;
1027
  }
1028
1029
  /**
1030
   * Process event
1031
   *
1032
   * @access private
1033
   * @param array $parameters
1034
   * @return mixed result of event handler or false if no handler was found
1035
   */
1036
  private function process_event(array $parameters) {
1037
    $ret = false;
1038
    $e = strtolower($parameters['Event']);
1039
    $this->log("Got event.. $e");
1040
1041
    $handler = '';
1042
    if (isset($this->event_handlers[$e])) {
1043
      $handler = $this->event_handlers[$e];
1044
    } elseif (isset($this->event_handlers['*'])) {
1045
      $handler = $this->event_handlers['*'];
1046
    }
1047
1048
    if (function_exists($handler)) {
1049
      $this->log("Execute handler $handler");
1050
      $ret = $handler($e, $parameters, $this->server, $this->port);
1051
    } elseif (is_array($handler)) {
1052
      $ret = call_user_func($handler, $e, $parameters, $this->server, $this->port);
1053
    } else {
1054
      $this->log("No event handler for event '$e'");
1055
    }
1056
    return $ret;
1057
  }
1058
}
1059