| Total Complexity | 237 |
| Total Lines | 1745 |
| Duplicated Lines | 0 % |
| Changes | 1 | ||
| Bugs | 0 | Features | 0 |
Complex classes like AGI often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use AGI, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 40 | class AGI |
||
| 41 | { |
||
| 42 | /** |
||
| 43 | * Request variables read in on initialization. |
||
| 44 | * |
||
| 45 | * Often contains any/all of the following: |
||
| 46 | * agi_request - name of agi script |
||
| 47 | * agi_channel - current channel |
||
| 48 | * agi_language - current language |
||
| 49 | * agi_type - channel type (SIP, ZAP, IAX, ...) |
||
| 50 | * agi_uniqueid - unique id based on unix time |
||
| 51 | * agi_callerid - callerID string |
||
| 52 | * agi_dnid - dialed number id |
||
| 53 | * agi_rdnis - referring DNIS number |
||
| 54 | * agi_context - current context |
||
| 55 | * agi_extension - extension dialed |
||
| 56 | * agi_priority - current priority |
||
| 57 | * agi_enhanced - value is 1.0 if started as an EAGI script |
||
| 58 | * agi_accountcode - set by SetAccount in the dialplan |
||
| 59 | * agi_network - value is yes if this is a fastagi |
||
| 60 | * agi_network_script - name of the script to execute |
||
| 61 | * |
||
| 62 | * NOTE: program arguments are still in $_SERVER['argv']. |
||
| 63 | * |
||
| 64 | * @var array |
||
| 65 | * @access public |
||
| 66 | */ |
||
| 67 | public $request; |
||
| 68 | |||
| 69 | /** |
||
| 70 | * Config variables |
||
| 71 | * |
||
| 72 | * @var array |
||
| 73 | * @access public |
||
| 74 | */ |
||
| 75 | public $config; |
||
| 76 | |||
| 77 | /** |
||
| 78 | * Asterisk Manager |
||
| 79 | * |
||
| 80 | * @var AGI_AsteriskManager |
||
| 81 | * @access public |
||
| 82 | */ |
||
| 83 | public $asm; |
||
| 84 | |||
| 85 | /** |
||
| 86 | * Input Stream |
||
| 87 | * |
||
| 88 | * @access private |
||
| 89 | */ |
||
| 90 | private $in; |
||
| 91 | |||
| 92 | /** |
||
| 93 | * Output Stream |
||
| 94 | * |
||
| 95 | * @access private |
||
| 96 | */ |
||
| 97 | private $out; |
||
| 98 | |||
| 99 | /** |
||
| 100 | * Audio Stream |
||
| 101 | * |
||
| 102 | * @access public |
||
| 103 | */ |
||
| 104 | public $audio = null; |
||
| 105 | |||
| 106 | |||
| 107 | /** |
||
| 108 | * Application option delimiter |
||
| 109 | * |
||
| 110 | * @access public |
||
| 111 | */ |
||
| 112 | public $option_delim = ","; |
||
| 113 | |||
| 114 | private $defaultConfig = ["error_handler" => true, |
||
| 115 | "debug" => false, |
||
| 116 | "admin" => null, |
||
| 117 | "tempdir" => AGI_Others::AST_TMP_DIR]; |
||
| 118 | |||
| 119 | /** |
||
| 120 | * Constructor |
||
| 121 | * |
||
| 122 | * @param string $config is the name of the config file to parse |
||
| 123 | * @param array $optconfig is an array of configuration vars and values, stuffed into $this->config['phpagi'] |
||
| 124 | */ |
||
| 125 | function __construct($config = null, array $optconfig = []) { |
||
| 126 | // load config |
||
| 127 | if (!is_null($config) && file_exists($config)) { |
||
| 128 | $this->config = parse_ini_file($config, true); |
||
| 129 | } elseif (file_exists(AGI_Others::DEFAULT_PHPAGI_CONFIG)) { |
||
| 130 | $this->config = parse_ini_file(AGI_Others::DEFAULT_PHPAGI_CONFIG, true); |
||
| 131 | } |
||
| 132 | |||
| 133 | // If optconfig is specified, stuff values and vars into 'phpagi' config array. |
||
| 134 | foreach ($optconfig as $var => $val) { |
||
| 135 | $this->config['phpagi'][$var] = $val; |
||
| 136 | } |
||
| 137 | |||
| 138 | // add default values to config for uninitialized values |
||
| 139 | foreach ($this->defaultConfig as $name => $value) { |
||
| 140 | $this->config["phpagi"][$name] = $this->config["phpagi"][$name] ?? $value; |
||
| 141 | } |
||
| 142 | |||
| 143 | // festival TTS config |
||
| 144 | $this->config['festival']['text2wave'] = $this->config['festival']['text2wave'] ?? $this->which('text2wave'); |
||
| 145 | |||
| 146 | // swift TTS config |
||
| 147 | $this->config['cepstral']['swift'] = $this->config['cepstral']['swift'] ?? $this->which('swift'); |
||
| 148 | |||
| 149 | ob_implicit_flush(); |
||
| 150 | |||
| 151 | // open stdin & stdout |
||
| 152 | $this->in = defined('STDIN') ? STDIN : fopen('php://stdin', 'r'); |
||
| 153 | $this->out = defined('STDOUT') ? STDOUT : fopen('php://stdout', 'w'); |
||
| 154 | |||
| 155 | // initialize error handler |
||
| 156 | if ($this->config['phpagi']['error_handler']) { |
||
| 157 | set_error_handler('\\Inok\\phpagi\\AGI_Others::phpagi_error_handler'); |
||
| 158 | AGI_Others::$phpagi_error_handler_email = $this->config['phpagi']['admin']; |
||
| 159 | error_reporting(E_ALL); |
||
| 160 | } |
||
| 161 | |||
| 162 | // make sure temp folder exists |
||
| 163 | $this->make_folder($this->config['phpagi']['tempdir']); |
||
| 164 | |||
| 165 | // read the request |
||
| 166 | $str = fgets($this->in); |
||
| 167 | while ($str != "\n") { |
||
| 168 | $this->request[substr($str, 0, strpos($str, ':'))] = trim(substr($str, strpos($str, ':') + 1)); |
||
| 169 | $str = fgets($this->in); |
||
| 170 | } |
||
| 171 | |||
| 172 | // open audio if agi detected |
||
| 173 | if ($this->request['agi_enhanced'] == '1.0') { |
||
| 174 | if (file_exists('/proc/' . getmypid() . '/fd/3')) { |
||
| 175 | $this->audio = fopen('/proc/' . getmypid() . '/fd/3', 'r'); |
||
| 176 | } elseif (file_exists('/dev/fd/3')) { |
||
| 177 | // may need to mount fdescfs |
||
| 178 | $this->audio = fopen('/dev/fd/3', 'r'); |
||
| 179 | } else { |
||
| 180 | $this->conlog('Unable to open audio stream'); |
||
| 181 | } |
||
| 182 | |||
| 183 | if ($this->audio) { |
||
| 184 | stream_set_blocking($this->audio, 0); |
||
| 185 | } |
||
| 186 | } |
||
| 187 | |||
| 188 | $this->conlog('AGI Request:'); |
||
| 189 | $this->conlog(print_r($this->request, true)); |
||
|
|
|||
| 190 | $this->conlog('PHPAGI internal configuration:'); |
||
| 191 | $this->conlog(print_r($this->config, true)); |
||
| 192 | } |
||
| 193 | |||
| 194 | // ********************************************************************************************************* |
||
| 195 | // ** COMMANDS ** |
||
| 196 | // ********************************************************************************************************* |
||
| 197 | |||
| 198 | /** |
||
| 199 | * Answer channel if not already in answer state. |
||
| 200 | * |
||
| 201 | * @link http://www.voip-info.org/wiki-answer |
||
| 202 | * @example examples/dtmf.php Get DTMF tones from the user and say the digits |
||
| 203 | * @example examples/input.php Get text input from the user and say it back |
||
| 204 | * @example examples/ping.php Ping an IP address |
||
| 205 | * |
||
| 206 | * @return array, see evaluate for return information. ['result'] is 0 on success, -1 on failure. |
||
| 207 | */ |
||
| 208 | function answer(): array { |
||
| 209 | return $this->evaluate('ANSWER'); |
||
| 210 | } |
||
| 211 | |||
| 212 | /** |
||
| 213 | * Get the status of the specified channel. If no channel name is specified, return the status of the current channel. |
||
| 214 | * |
||
| 215 | * @link http://www.voip-info.org/wiki-channel+status |
||
| 216 | * @param string $channel |
||
| 217 | * @return array, see evaluate for return information. ['data'] contains description. |
||
| 218 | */ |
||
| 219 | function channel_status(string $channel = ''): array { |
||
| 220 | $ret = $this->evaluate("CHANNEL STATUS $channel"); |
||
| 221 | switch ($ret['result']) { |
||
| 222 | case -1: |
||
| 223 | $ret['data'] = trim("There is no channel that matches $channel"); |
||
| 224 | break; |
||
| 225 | case AGI_Others::AST_STATE_DOWN: |
||
| 226 | $ret['data'] = 'Channel is down and available'; |
||
| 227 | break; |
||
| 228 | case AGI_Others::AST_STATE_RESERVED: |
||
| 229 | $ret['data'] = 'Channel is down, but reserved'; |
||
| 230 | break; |
||
| 231 | case AGI_Others::AST_STATE_OFFHOOK: |
||
| 232 | $ret['data'] = 'Channel is off hook'; |
||
| 233 | break; |
||
| 234 | case AGI_Others::AST_STATE_DIALING: |
||
| 235 | $ret['data'] = 'Digits (or equivalent) have been dialed'; |
||
| 236 | break; |
||
| 237 | case AGI_Others::AST_STATE_RING: |
||
| 238 | $ret['data'] = 'Line is ringing'; |
||
| 239 | break; |
||
| 240 | case AGI_Others::AST_STATE_RINGING: |
||
| 241 | $ret['data'] = 'Remote end is ringing'; |
||
| 242 | break; |
||
| 243 | case AGI_Others::AST_STATE_UP: |
||
| 244 | $ret['data'] = 'Line is up'; |
||
| 245 | break; |
||
| 246 | case AGI_Others::AST_STATE_BUSY: |
||
| 247 | $ret['data'] = 'Line is busy'; |
||
| 248 | break; |
||
| 249 | case AGI_Others::AST_STATE_DIALING_OFFHOOK: |
||
| 250 | $ret['data'] = 'Digits (or equivalent) have been dialed while offhook'; |
||
| 251 | break; |
||
| 252 | case AGI_Others::AST_STATE_PRERING: |
||
| 253 | $ret['data'] = 'Channel has detected an incoming call and is waiting for ring'; |
||
| 254 | break; |
||
| 255 | default: |
||
| 256 | $ret['data'] = "Unknown ({$ret['result']})"; |
||
| 257 | break; |
||
| 258 | } |
||
| 259 | return $ret; |
||
| 260 | } |
||
| 261 | |||
| 262 | /** |
||
| 263 | * Deletes an entry in the Asterisk database for a given family and key. |
||
| 264 | * |
||
| 265 | * @link http://www.voip-info.org/wiki-database+del |
||
| 266 | * @param string $family |
||
| 267 | * @param string $key |
||
| 268 | * @return array, see evaluate for return information. ['result'] is 1 on success, 0 otherwise. |
||
| 269 | */ |
||
| 270 | function database_del(string $family, string $key): array { |
||
| 271 | return $this->evaluate("DATABASE DEL \"$family\" \"$key\""); |
||
| 272 | } |
||
| 273 | |||
| 274 | /** |
||
| 275 | * Deletes a family or specific keytree within a family in the Asterisk database. |
||
| 276 | * |
||
| 277 | * @link http://www.voip-info.org/wiki-database+deltree |
||
| 278 | * @param string $family |
||
| 279 | * @param string $keytree |
||
| 280 | * @return array, see evaluate for return information. ['result'] is 1 on success, 0 otherwise. |
||
| 281 | */ |
||
| 282 | function database_deltree(string $family, string $keytree = ''): array { |
||
| 283 | $cmd = "DATABASE DELTREE \"$family\""; |
||
| 284 | if ($keytree != '') { |
||
| 285 | $cmd .= " \"$keytree\""; |
||
| 286 | } |
||
| 287 | return $this->evaluate($cmd); |
||
| 288 | } |
||
| 289 | |||
| 290 | /** |
||
| 291 | * Retrieves an entry in the Asterisk database for a given family and key. |
||
| 292 | * |
||
| 293 | * @link http://www.voip-info.org/wiki-database+get |
||
| 294 | * @param string $family |
||
| 295 | * @param string $key |
||
| 296 | * @return array, see evaluate for return information. ['result'] is 1 on success, 0 failure. ['data'] holds the value |
||
| 297 | */ |
||
| 298 | function database_get(string $family, string $key): array { |
||
| 299 | return $this->evaluate("DATABASE GET \"$family\" \"$key\""); |
||
| 300 | } |
||
| 301 | |||
| 302 | /** |
||
| 303 | * Adds or updates an entry in the Asterisk database for a given family, key, and value. |
||
| 304 | * |
||
| 305 | * @param string $family |
||
| 306 | * @param string $key |
||
| 307 | * @param string $value |
||
| 308 | * @return array, see evaluate for return information. ['result'] is 1 on success, 0 otherwise |
||
| 309 | */ |
||
| 310 | function database_put(string $family, string $key, string $value): array { |
||
| 311 | $value = str_replace("\n", '\n', addslashes($value)); |
||
| 312 | return $this->evaluate("DATABASE PUT \"$family\" \"$key\" \"$value\""); |
||
| 313 | } |
||
| 314 | |||
| 315 | |||
| 316 | /** |
||
| 317 | * Sets a global variable, using Asterisk 1.6 syntax. |
||
| 318 | * |
||
| 319 | * @link http://www.voip-info.org/wiki/view/Asterisk+cmd+Set |
||
| 320 | * |
||
| 321 | * @param string $pVariable |
||
| 322 | * @param string|int|float $pValue |
||
| 323 | * @return array, see evaluate for return information. ['result'] is 1 on success, 0 otherwise |
||
| 324 | */ |
||
| 325 | function set_global_var(string $pVariable, $pValue): array { |
||
| 326 | if (is_numeric($pValue)) { |
||
| 327 | return $this->evaluate("Set({$pVariable}={$pValue},g);"); |
||
| 328 | } |
||
| 329 | return $this->evaluate("Set({$pVariable}=\"{$pValue}\",g);"); |
||
| 330 | } |
||
| 331 | |||
| 332 | |||
| 333 | /** |
||
| 334 | * Sets a variable, using Asterisk 1.6 syntax. |
||
| 335 | * |
||
| 336 | * @link http://www.voip-info.org/wiki/view/Asterisk+cmd+Set |
||
| 337 | * |
||
| 338 | * @param string $pVariable |
||
| 339 | * @param string|int|float $pValue |
||
| 340 | * @return array, see evaluate for return information. ['result'] is 1 on success, 0 otherwise |
||
| 341 | */ |
||
| 342 | function set_var(string $pVariable, $pValue): array { |
||
| 343 | if (is_numeric($pValue)) { |
||
| 344 | return $this->evaluate("Set({$pVariable}={$pValue});"); |
||
| 345 | } |
||
| 346 | return $this->evaluate("Set({$pVariable}=\"{$pValue}\");"); |
||
| 347 | } |
||
| 348 | |||
| 349 | |||
| 350 | /** |
||
| 351 | * Executes the specified Asterisk application with given options. |
||
| 352 | * |
||
| 353 | * @link http://www.voip-info.org/wiki-exec |
||
| 354 | * @link http://www.voip-info.org/wiki-Asterisk+-+documentation+of+application+commands |
||
| 355 | * @param string $application |
||
| 356 | * @param mixed $options |
||
| 357 | * @return array, see evaluate for return information. ['result'] is whatever the application returns, or -2 on failure to find application |
||
| 358 | */ |
||
| 359 | function exec(string $application, $options): array { |
||
| 360 | if (is_array($options)) { |
||
| 361 | $options = join('|', $options); |
||
| 362 | } |
||
| 363 | return $this->evaluate("EXEC $application $options"); |
||
| 364 | } |
||
| 365 | |||
| 366 | /** |
||
| 367 | * Plays the given file and receives DTMF data. |
||
| 368 | * |
||
| 369 | * This is similar to STREAM FILE, but this command can accept and return many DTMF digits, |
||
| 370 | * while STREAM FILE returns immediately after the first DTMF digit is detected. |
||
| 371 | * |
||
| 372 | * Asterisk looks for the file to play in /var/lib/asterisk/sounds by default. |
||
| 373 | * |
||
| 374 | * If the user doesn't press any keys when the message plays, there is $timeout milliseconds |
||
| 375 | * of silence then the command ends. |
||
| 376 | * |
||
| 377 | * The user has the opportunity to press a key at any time during the message or the |
||
| 378 | * post-message silence. If the user presses a key while the message is playing, the |
||
| 379 | * message stops playing. When the first key is pressed a timer starts counting for |
||
| 380 | * $timeout milliseconds. Every time the user presses another key the timer is restarted. |
||
| 381 | * The command ends when the counter goes to zero or the maximum number of digits is entered, |
||
| 382 | * whichever happens first. |
||
| 383 | * |
||
| 384 | * If you don't specify a time out then a default timeout of 2000 is used following a pressed |
||
| 385 | * digit. If no digits are pressed then 6 seconds of silence follow the message. |
||
| 386 | * |
||
| 387 | * If you don't specify $max_digits then the user can enter as many digits as they want. |
||
| 388 | * |
||
| 389 | * Pressing the # key has the same effect as the timer running out: the command ends and |
||
| 390 | * any previously keyed digits are returned. A side effect of this is that there is no |
||
| 391 | * way to read a # key using this command. |
||
| 392 | * |
||
| 393 | * @param string $filename file to play. Do not include file extension. |
||
| 394 | * @param integer $timeout milliseconds |
||
| 395 | * @param integer $max_digits |
||
| 396 | * @return array, see evaluate for return information. ['result'] holds the digits and ['data'] holds the timeout if present. |
||
| 397 | * |
||
| 398 | * This differs from other commands with return DTMF as numbers representing ASCII characters. |
||
| 399 | * @example examples/ping.php Ping an IP address |
||
| 400 | * |
||
| 401 | * @link http://www.voip-info.org/wiki-get+data |
||
| 402 | */ |
||
| 403 | function get_data(string $filename, $timeout = null, $max_digits = null): array { |
||
| 404 | return $this->evaluate(rtrim("GET DATA $filename $timeout $max_digits")); |
||
| 405 | } |
||
| 406 | |||
| 407 | /** |
||
| 408 | * Fetch the value of a variable. |
||
| 409 | * |
||
| 410 | * Does not work with global variables. Does not work with some variables that are generated by modules. |
||
| 411 | * |
||
| 412 | * @link http://www.voip-info.org/wiki-get+variable |
||
| 413 | * @link http://www.voip-info.org/wiki-Asterisk+variables |
||
| 414 | * @param string $variable name |
||
| 415 | * @param boolean $getvalue return the value only |
||
| 416 | * @return mixed, see evaluate for return information. ['result'] is 0 if variable hasn't been set, 1 if it has. ['data'] holds the value. returns value if $getvalue is TRUE |
||
| 417 | */ |
||
| 418 | function get_variable(string $variable, bool $getvalue = false) { |
||
| 419 | $res = $this->evaluate("GET VARIABLE $variable"); |
||
| 420 | return $getvalue ? $res['data'] : $res; |
||
| 421 | } |
||
| 422 | |||
| 423 | |||
| 424 | /** |
||
| 425 | * Fetch the value of a full variable. |
||
| 426 | * |
||
| 427 | * |
||
| 428 | * @link http://www.voip-info.org/wiki/view/get+full+variable |
||
| 429 | * @link http://www.voip-info.org/wiki-Asterisk+variables |
||
| 430 | * @param string $variable name |
||
| 431 | * @param string $channel channel |
||
| 432 | * @param boolean $getvalue return the value only |
||
| 433 | * @return mixed, see evaluate for return information. ['result'] is 0 if variable hasn't been set, 1 if it has. ['data'] holds the value. returns value if $getvalue is TRUE |
||
| 434 | */ |
||
| 435 | function get_fullvariable(string $variable, $channel = false, bool $getvalue = false) { |
||
| 436 | $req = ($channel == false) ? $variable : $variable . ' ' . $channel; |
||
| 437 | $res = $this->evaluate('GET FULL VARIABLE ' . $req); |
||
| 438 | return $getvalue ? $res['data'] : $res; |
||
| 439 | |||
| 440 | } |
||
| 441 | |||
| 442 | /** |
||
| 443 | * Hangup the specified channel. If no channel name is given, hang up the current channel. |
||
| 444 | * |
||
| 445 | * With power comes responsibility. Hanging up channels other than your own isn't something |
||
| 446 | * that is done routinely. If you are not sure why you are doing so, then don't. |
||
| 447 | * |
||
| 448 | * @link http://www.voip-info.org/wiki-hangup |
||
| 449 | * @example examples/dtmf.php Get DTMF tones from the user and say the digits |
||
| 450 | * @example examples/input.php Get text input from the user and say it back |
||
| 451 | * @example examples/ping.php Ping an IP address |
||
| 452 | * |
||
| 453 | * @param string $channel |
||
| 454 | * @return array, see evaluate for return information. ['result'] is 1 on success, -1 on failure. |
||
| 455 | */ |
||
| 456 | function hangup(string $channel = ''): array { |
||
| 457 | return $this->evaluate("HANGUP $channel"); |
||
| 458 | } |
||
| 459 | |||
| 460 | /** |
||
| 461 | * Does nothing. |
||
| 462 | * |
||
| 463 | * @link http://www.voip-info.org/wiki-noop |
||
| 464 | * @param string $string |
||
| 465 | * @return array, see evaluate for return information. |
||
| 466 | */ |
||
| 467 | function noop(string $string = ""): array { |
||
| 468 | return $this->evaluate("NOOP \"$string\""); |
||
| 469 | } |
||
| 470 | |||
| 471 | /** |
||
| 472 | * Receive a character of text from a connected channel. Waits up to $timeout milliseconds for |
||
| 473 | * a character to arrive, or infinitely if $timeout is zero. |
||
| 474 | * |
||
| 475 | * @link http://www.voip-info.org/wiki-receive+char |
||
| 476 | * @param integer $timeout milliseconds |
||
| 477 | * @return array, see evaluate for return information. ['result'] is 0 on timeout or not supported, -1 on failure. Otherwise |
||
| 478 | * it is the decimal value of the DTMF tone. Use chr() to convert to ASCII. |
||
| 479 | */ |
||
| 480 | function receive_char(int $timeout = -1): array { |
||
| 481 | return $this->evaluate("RECEIVE CHAR $timeout"); |
||
| 482 | } |
||
| 483 | |||
| 484 | /** |
||
| 485 | * Record sound to a file until an acceptable DTMF digit is received or a specified amount of |
||
| 486 | * time has passed. Optionally the file BEEP is played before recording begins. |
||
| 487 | * |
||
| 488 | * @link http://www.voip-info.org/wiki-record+file |
||
| 489 | * @param string $file to record, without extension, often created in /var/lib/asterisk/sounds |
||
| 490 | * @param string $format of the file. GSM and WAV are commonly used formats. MP3 is read-only and thus cannot be used. |
||
| 491 | * @param string $escape_digits |
||
| 492 | * @param integer $timeout is the maximum record time in milliseconds, or -1 for no timeout. |
||
| 493 | * @param integer $offset to seek to without exceeding the end of the file. |
||
| 494 | * @param boolean $beep |
||
| 495 | * @param integer $silence number of seconds of silence allowed before the function returns despite the |
||
| 496 | * lack of dtmf digits or reaching timeout. |
||
| 497 | * @return array, see evaluate for return information. ['result'] is -1 on error, 0 on hangup, otherwise a decimal value of the |
||
| 498 | * DTMF tone. Use chr() to convert to ASCII. |
||
| 499 | */ |
||
| 500 | function record_file(string $file, string $format, string $escape_digits = '', int $timeout = -1, |
||
| 501 | $offset = null, bool $beep = false, $silence = null): array { |
||
| 502 | $cmd = trim("RECORD FILE $file $format \"$escape_digits\" $timeout $offset"); |
||
| 503 | if ($beep) { |
||
| 504 | $cmd .= ' BEEP'; |
||
| 505 | } |
||
| 506 | if (!is_null($silence)) { |
||
| 507 | $cmd .= " s=$silence"; |
||
| 508 | } |
||
| 509 | return $this->evaluate($cmd); |
||
| 510 | } |
||
| 511 | |||
| 512 | /** |
||
| 513 | * Say a given character string, returning early if any of the given DTMF digits are received on the channel. |
||
| 514 | * |
||
| 515 | * @link https://www.voip-info.org/say-alpha |
||
| 516 | * @param string $text |
||
| 517 | * @param string $escape_digits |
||
| 518 | * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no |
||
| 519 | * digit received, otherwise a decimal value of the DTMF tone. Use chr() to convert to ASCII. |
||
| 520 | */ |
||
| 521 | function say_alpha(string $text, string $escape_digits = ''): array { |
||
| 522 | return $this->evaluate("SAY ALPHA $text \"$escape_digits\""); |
||
| 523 | } |
||
| 524 | |||
| 525 | /** |
||
| 526 | * Say the given digit string, returning early if any of the given DTMF escape digits are received on the channel. |
||
| 527 | * |
||
| 528 | * @link http://www.voip-info.org/wiki-say+digits |
||
| 529 | * @param integer $digits |
||
| 530 | * @param string $escape_digits |
||
| 531 | * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no |
||
| 532 | * digit received, otherwise a decimal value of the DTMF tone. Use chr() to convert to ASCII. |
||
| 533 | */ |
||
| 534 | function say_digits(int $digits, string $escape_digits = ''): array { |
||
| 535 | return $this->evaluate("SAY DIGITS $digits \"$escape_digits\""); |
||
| 536 | } |
||
| 537 | |||
| 538 | /** |
||
| 539 | * Say the given number, returning early if any of the given DTMF escape digits are received on the channel. |
||
| 540 | * |
||
| 541 | * @link http://www.voip-info.org/wiki-say+number |
||
| 542 | * @param integer $number |
||
| 543 | * @param string $escape_digits |
||
| 544 | * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no |
||
| 545 | * digit received, otherwise a decimal value of the DTMF tone. Use chr() to convert to ASCII. |
||
| 546 | */ |
||
| 547 | function say_number(int $number, string $escape_digits = ''): array { |
||
| 548 | return $this->evaluate("SAY NUMBER $number \"$escape_digits\""); |
||
| 549 | } |
||
| 550 | |||
| 551 | /** |
||
| 552 | * Say the given character string, returning early if any of the given DTMF escape digits are received on the channel. |
||
| 553 | * |
||
| 554 | * @link http://www.voip-info.org/wiki-say+phonetic |
||
| 555 | * @param string $text |
||
| 556 | * @param string $escape_digits |
||
| 557 | * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no |
||
| 558 | * digit received, otherwise a decimal value of the DTMF tone. Use chr() to convert to ASCII. |
||
| 559 | */ |
||
| 560 | function say_phonetic(string $text, string $escape_digits = ''): array { |
||
| 561 | return $this->evaluate("SAY PHONETIC $text \"$escape_digits\""); |
||
| 562 | } |
||
| 563 | |||
| 564 | /** |
||
| 565 | * Say a given time, returning early if any of the given DTMF escape digits are received on the channel. |
||
| 566 | * |
||
| 567 | * @link http://www.voip-info.org/wiki-say+time |
||
| 568 | * @param integer $time number of seconds elapsed since 00:00:00 on January 1, 1970, Coordinated Universal Time (UTC). |
||
| 569 | * @param string $escape_digits |
||
| 570 | * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no |
||
| 571 | * digit received, otherwise a decimal value of the DTMF tone. Use chr() to convert to ASCII. |
||
| 572 | */ |
||
| 573 | function say_time($time = null, string $escape_digits = ''): array { |
||
| 574 | if (is_null($time)) { |
||
| 575 | $time = time(); |
||
| 576 | } |
||
| 577 | return $this->evaluate("SAY TIME $time \"$escape_digits\""); |
||
| 578 | } |
||
| 579 | |||
| 580 | /** |
||
| 581 | * Send the specified image on a channel. |
||
| 582 | * |
||
| 583 | * Most channels do not support the transmission of images. |
||
| 584 | * |
||
| 585 | * @link http://www.voip-info.org/wiki-send+image |
||
| 586 | * @param string $image without extension, often in /var/lib/asterisk/images |
||
| 587 | * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if the image is sent or |
||
| 588 | * channel does not support image transmission. |
||
| 589 | */ |
||
| 590 | function send_image(string $image): array { |
||
| 591 | return $this->evaluate("SEND IMAGE $image"); |
||
| 592 | } |
||
| 593 | |||
| 594 | /** |
||
| 595 | * Send the given text to the connected channel. |
||
| 596 | * |
||
| 597 | * Most channels do not support transmission of text. |
||
| 598 | * |
||
| 599 | * @link http://www.voip-info.org/wiki-send+text |
||
| 600 | * @param $text |
||
| 601 | * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if the text is sent or |
||
| 602 | * channel does not support text transmission. |
||
| 603 | */ |
||
| 604 | function send_text($text): array { |
||
| 605 | return $this->evaluate("SEND TEXT \"$text\""); |
||
| 606 | } |
||
| 607 | |||
| 608 | /** |
||
| 609 | * Cause the channel to automatically hangup at $time seconds in the future. |
||
| 610 | * If $time is 0 then the auto hangup feature is disabled on this channel. |
||
| 611 | * |
||
| 612 | * If the channel is hangup prior to $time seconds, this setting has no effect. |
||
| 613 | * |
||
| 614 | * @link http://www.voip-info.org/wiki-set+autohangup |
||
| 615 | * @param integer $time until automatic hangup |
||
| 616 | * @return array, see evaluate for return information. |
||
| 617 | */ |
||
| 618 | function set_autohangup(int $time = 0): array { |
||
| 619 | return $this->evaluate("SET AUTOHANGUP $time"); |
||
| 620 | } |
||
| 621 | |||
| 622 | /** |
||
| 623 | * Changes the caller ID of the current channel. |
||
| 624 | * |
||
| 625 | * @link http://www.voip-info.org/wiki-set+callerid |
||
| 626 | * @param string $cid example: "John Smith"<1234567> |
||
| 627 | * This command will let you take liberties with the <caller ID specification> but the format shown in the example above works |
||
| 628 | * well: the name enclosed in double quotes followed immediately by the number inside angle brackets. If there is no name then |
||
| 629 | * you can omit it. If the name contains no spaces you can omit the double quotes around it. The number must follow the name |
||
| 630 | * immediately; don't put a space between them. The angle brackets around the number are necessary; if you omit them the |
||
| 631 | * number will be considered to be part of the name. |
||
| 632 | * @return array, see evaluate for return information. |
||
| 633 | */ |
||
| 634 | function set_callerid(string $cid): array { |
||
| 636 | } |
||
| 637 | |||
| 638 | /** |
||
| 639 | * Sets the context for continuation upon exiting the application. |
||
| 640 | * |
||
| 641 | * Setting the context does NOT automatically reset the extension and the priority; if you want to start at the top of the new |
||
| 642 | * context you should set extension and priority yourself. |
||
| 643 | * |
||
| 644 | * If you specify a non-existent context you receive no error indication (['result'] is still 0) but you do get a |
||
| 645 | * warning message on the Asterisk console. |
||
| 646 | * |
||
| 647 | * @link http://www.voip-info.org/wiki-set+context |
||
| 648 | * @param string $context |
||
| 649 | * @return array, see evaluate for return information. |
||
| 650 | */ |
||
| 651 | function set_context(string $context): array { |
||
| 652 | return $this->evaluate("SET CONTEXT $context"); |
||
| 653 | } |
||
| 654 | |||
| 655 | /** |
||
| 656 | * Set the extension to be used for continuation upon exiting the application. |
||
| 657 | * |
||
| 658 | * Setting the extension does NOT automatically reset the priority. If you want to start with the first priority of the |
||
| 659 | * extension you should set the priority yourself. |
||
| 660 | * |
||
| 661 | * If you specify a non-existent extension you receive no error indication (['result'] is still 0) but you do |
||
| 662 | * get a warning message on the Asterisk console. |
||
| 663 | * |
||
| 664 | * @link http://www.voip-info.org/wiki-set+extension |
||
| 665 | * @param string $extension |
||
| 666 | * @return array, see evaluate for return information. |
||
| 667 | */ |
||
| 668 | function set_extension(string $extension): array { |
||
| 670 | } |
||
| 671 | |||
| 672 | /** |
||
| 673 | * Enable/Disable Music on hold generator. |
||
| 674 | * |
||
| 675 | * @link http://www.voip-info.org/wiki-set+music |
||
| 676 | * @param boolean $enabled |
||
| 677 | * @param string $class |
||
| 678 | * @return array, see evaluate for return information. |
||
| 679 | */ |
||
| 680 | function set_music(bool $enabled = true, string $class = ''): array { |
||
| 681 | $enabled = ($enabled) ? 'ON' : 'OFF'; |
||
| 682 | return $this->evaluate("SET MUSIC $enabled $class"); |
||
| 683 | } |
||
| 684 | |||
| 685 | /** |
||
| 686 | * Set the priority to be used for continuation upon exiting the application. |
||
| 687 | * |
||
| 688 | * If you specify a non-existent priority you receive no error indication (['result'] is still 0) |
||
| 689 | * and no warning is issued on the Asterisk console. |
||
| 690 | * |
||
| 691 | * @link http://www.voip-info.org/wiki-set+priority |
||
| 692 | * @param integer $priority |
||
| 693 | * @return array, see evaluate for return information. |
||
| 694 | */ |
||
| 695 | function set_priority(int $priority): array { |
||
| 696 | return $this->evaluate("SET PRIORITY $priority"); |
||
| 697 | } |
||
| 698 | |||
| 699 | /** |
||
| 700 | * Sets a variable to the specified value. The variables so created can later be used by later using ${<variablename>} |
||
| 701 | * in the dialplan. |
||
| 702 | * |
||
| 703 | * These variables live in the channel Asterisk creates when you pickup a phone and as such they are both local and temporary. |
||
| 704 | * Variables created in one channel can not be accessed by another channel. When you hang up the phone, the channel is deleted |
||
| 705 | * and any variables in that channel are deleted as well. |
||
| 706 | * |
||
| 707 | * @link http://www.voip-info.org/wiki-set+variable |
||
| 708 | * @param string $variable is case sensitive |
||
| 709 | * @param string $value |
||
| 710 | * @return array, see evaluate for return information. |
||
| 711 | */ |
||
| 712 | function set_variable(string $variable, string $value): array { |
||
| 713 | $value = str_replace("\n", '\n', addslashes($value)); |
||
| 714 | return $this->evaluate("SET VARIABLE $variable \"$value\""); |
||
| 715 | } |
||
| 716 | |||
| 717 | /** |
||
| 718 | * Play the given audio file, allowing playback to be interrupted by a DTMF digit. This command is similar to the GET DATA |
||
| 719 | * command but this command returns after the first DTMF digit has been pressed while GET DATA can accumulated any number of |
||
| 720 | * digits before returning. |
||
| 721 | * |
||
| 722 | * @param string $filename without extension, often in /var/lib/asterisk/sounds |
||
| 723 | * @param string $escape_digits |
||
| 724 | * @param integer $offset |
||
| 725 | * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no |
||
| 726 | * digit received, otherwise a decimal value of the DTMF tone. Use chr() to convert to ASCII. |
||
| 727 | * @example examples/ping.php Ping an IP address |
||
| 728 | * |
||
| 729 | * @link http://www.voip-info.org/wiki-stream+file |
||
| 730 | */ |
||
| 731 | function stream_file(string $filename, string $escape_digits = '', int $offset = 0): array { |
||
| 732 | return $this->evaluate("STREAM FILE $filename \"$escape_digits\" $offset"); |
||
| 733 | } |
||
| 734 | |||
| 735 | /** |
||
| 736 | * Enable or disable TDD transmission/reception on the current channel. |
||
| 737 | * |
||
| 738 | * @link http://www.voip-info.org/wiki-tdd+mode |
||
| 739 | * @param string $setting can be on, off or mate |
||
| 740 | * @return array, see evaluate for return information. ['result'] is 1 on success, 0 if the channel is not TDD capable. |
||
| 741 | */ |
||
| 742 | function tdd_mode(string $setting): array { |
||
| 743 | return $this->evaluate("TDD MODE $setting"); |
||
| 744 | } |
||
| 745 | |||
| 746 | /** |
||
| 747 | * Sends $message to the Asterisk console via the 'verbose' message system. |
||
| 748 | * |
||
| 749 | * If the Asterisk verbosity level is $level or greater, send $message to the console. |
||
| 750 | * |
||
| 751 | * The Asterisk verbosity system works as follows. The Asterisk user gets to set the desired verbosity at startup time or later |
||
| 752 | * using the console 'set verbose' command. Messages are displayed on the console if their verbose level is less than or equal |
||
| 753 | * to desired verbosity set by the user. More important messages should have a low verbose level; less important messages |
||
| 754 | * should have a high verbose level. |
||
| 755 | * |
||
| 756 | * @link http://www.voip-info.org/wiki-verbose |
||
| 757 | * @param string $message |
||
| 758 | * @param integer $level from 1 to 4 |
||
| 759 | * @return array, see evaluate for return information. |
||
| 760 | */ |
||
| 761 | function verbose(string $message, int $level = 1): array { |
||
| 768 | } |
||
| 769 | |||
| 770 | /** |
||
| 771 | * Waits up to $timeout milliseconds for channel to receive a DTMF digit. |
||
| 772 | * |
||
| 773 | * @link http://www.voip-info.org/wiki-wait+for+digit |
||
| 774 | * @param integer $timeout in milliseconds. Use -1 for the timeout value if you want the call to wait indefinitely. |
||
| 775 | * @return array, see evaluate for return information. ['result'] is 0 if wait completes with no |
||
| 776 | * digit received, otherwise a decimal value of the DTMF tone. Use chr() to convert to ASCII. |
||
| 777 | */ |
||
| 778 | function wait_for_digit(int $timeout = -1): array { |
||
| 779 | return $this->evaluate("WAIT FOR DIGIT $timeout"); |
||
| 780 | } |
||
| 781 | |||
| 782 | |||
| 783 | // ********************************************************************************************************* |
||
| 784 | // ** APPLICATIONS ** |
||
| 785 | // ********************************************************************************************************* |
||
| 786 | |||
| 787 | /** |
||
| 788 | * Set absolute maximum time of call. |
||
| 789 | * |
||
| 790 | * Note that the timeout is set from the current time forward, not counting the number of seconds the call has already been up. |
||
| 791 | * Each time you call AbsoluteTimeout(), all previous absolute timeouts are cancelled. |
||
| 792 | * Will return the call to the T extension so that you can playback an explanatory note to the calling party (the called party |
||
| 793 | * will not hear that) |
||
| 794 | * |
||
| 795 | * @link http://www.voip-info.org/wiki-Asterisk+-+documentation+of+application+commands |
||
| 796 | * @link http://www.dynx.net/ASTERISK/AGI/ccard/agi-ccard.agi |
||
| 797 | * @param integer $seconds allowed, 0 disables timeout |
||
| 798 | * @return array, see evaluate for return information. |
||
| 799 | */ |
||
| 800 | function exec_absolutetimeout(int $seconds = 0): array { |
||
| 801 | return $this->exec('AbsoluteTimeout', $seconds); |
||
| 802 | } |
||
| 803 | |||
| 804 | /** |
||
| 805 | * Executes an AGI compliant application. |
||
| 806 | * |
||
| 807 | * @param string $command |
||
| 808 | * @param string $args |
||
| 809 | * @return array, see evaluate for return information. ['result'] is -1 on hangup or if application requested hangup, or 0 on non-hangup exit. |
||
| 810 | */ |
||
| 811 | function exec_agi(string $command, string $args): array { |
||
| 812 | return $this->exec("AGI $command", $args); |
||
| 813 | } |
||
| 814 | |||
| 815 | /** |
||
| 816 | * Set Language. |
||
| 817 | * |
||
| 818 | * @param string $language code |
||
| 819 | * @return array, see evaluate for return information. |
||
| 820 | */ |
||
| 821 | function exec_setlanguage(string $language = 'en'): array { |
||
| 822 | return $this->exec('Set', 'CHANNEL(language)=' . $language); |
||
| 823 | } |
||
| 824 | |||
| 825 | /** |
||
| 826 | * Do ENUM Lookup. |
||
| 827 | * |
||
| 828 | * Note: to retrieve the result, use |
||
| 829 | * get_variable('ENUM'); |
||
| 830 | * |
||
| 831 | * @param $exten |
||
| 832 | * @return array, see evaluate for return information. |
||
| 833 | */ |
||
| 834 | function exec_enumlookup($exten): array { |
||
| 835 | return $this->exec('EnumLookup', $exten); |
||
| 836 | } |
||
| 837 | |||
| 838 | /** |
||
| 839 | * Dial. |
||
| 840 | * |
||
| 841 | * Dial takes input from ${VXML_URL} to send XML Url to Cisco 7960 |
||
| 842 | * Dial takes input from ${ALERT_INFO} to set ring cadence for Cisco phones |
||
| 843 | * Dial returns ${CAUSECODE}: If the dial failed, this is the errormessage. |
||
| 844 | * Dial returns ${DIALSTATUS}: Text code returning status of last dial attempt. |
||
| 845 | * |
||
| 846 | * @link http://www.voip-info.org/wiki-Asterisk+cmd+Dial |
||
| 847 | * @param string $type |
||
| 848 | * @param string $identifier |
||
| 849 | * @param integer $timeout |
||
| 850 | * @param string $options |
||
| 851 | * @param string $url |
||
| 852 | * @return array, see evaluate for return information. |
||
| 853 | */ |
||
| 854 | function exec_dial(string $type, string $identifier, $timeout = null, $options = null, $url = null): array { |
||
| 855 | return $this->exec( |
||
| 856 | 'Dial', trim("$type/$identifier" . $this->option_delim . $timeout . $this->option_delim . $options . $this->option_delim . $url, $this->option_delim)); |
||
| 857 | } |
||
| 858 | |||
| 859 | /** |
||
| 860 | * Goto. |
||
| 861 | * |
||
| 862 | * This function takes three arguments: context,extension, and priority, but the leading arguments |
||
| 863 | * are optional, not the trailing arguments. Those goto($z) sets the priority to $z. |
||
| 864 | * |
||
| 865 | * @param string $a |
||
| 866 | * @param string $b ; |
||
| 867 | * @param string $c ; |
||
| 868 | * @return array, see evaluate for return information. |
||
| 869 | */ |
||
| 870 | function exec_goto(string $a, $b = null, $c = null): array { |
||
| 872 | } |
||
| 873 | |||
| 874 | |||
| 875 | // ********************************************************************************************************* |
||
| 876 | // ** FAST PASSING ** |
||
| 877 | // ********************************************************************************************************* |
||
| 878 | |||
| 879 | /** |
||
| 880 | * Say the given digit string, returning early if any of the given DTMF escape digits are received on the channel. |
||
| 881 | * Return early if $buffer is adequate for request. |
||
| 882 | * |
||
| 883 | * @link http://www.voip-info.org/wiki-say+digits |
||
| 884 | * @param string $buffer |
||
| 885 | * @param integer $digits |
||
| 886 | * @param string $escape_digits |
||
| 887 | * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no |
||
| 888 | * digit received, otherwise a decimal value of the DTMF tone. Use chr() to convert to ASCII. |
||
| 889 | */ |
||
| 890 | function fastpass_say_digits(string &$buffer, int $digits, string $escape_digits = ''): array { |
||
| 891 | if ($buffer == '' || $this->proceedDigits($buffer, $escape_digits)) { |
||
| 892 | $res = $this->say_digits($digits, $escape_digits); |
||
| 893 | $this->appendBuffer($buffer, $res); |
||
| 894 | return $res; |
||
| 895 | } |
||
| 896 | return ['code' => AGI_Others::AGIRES_OK, |
||
| 897 | 'result' => $this->ordBuffer($buffer)]; |
||
| 898 | } |
||
| 899 | |||
| 900 | /** |
||
| 901 | * Say the given number, returning early if any of the given DTMF escape digits are received on the channel. |
||
| 902 | * Return early if $buffer is adequate for request. |
||
| 903 | * |
||
| 904 | * @link http://www.voip-info.org/wiki-say+number |
||
| 905 | * @param string $buffer |
||
| 906 | * @param integer $number |
||
| 907 | * @param string $escape_digits |
||
| 908 | * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no |
||
| 909 | * digit received, otherwise a decimal value of the DTMF tone. Use chr() to convert to ASCII. |
||
| 910 | */ |
||
| 911 | function fastpass_say_number(string &$buffer, int $number, string $escape_digits = ''): array { |
||
| 912 | if ($buffer == '' || $this->proceedDigits($buffer, $escape_digits)) { |
||
| 913 | $res = $this->say_number($number, $escape_digits); |
||
| 914 | $this->appendBuffer($buffer, $res); |
||
| 915 | return $res; |
||
| 916 | } |
||
| 917 | return ['code' => AGI_Others::AGIRES_OK, |
||
| 918 | 'result' => $this->ordBuffer($buffer)]; |
||
| 919 | } |
||
| 920 | |||
| 921 | /** |
||
| 922 | * Say the given character string, returning early if any of the given DTMF escape digits are received on the channel. |
||
| 923 | * Return early if $buffer is adequate for request. |
||
| 924 | * |
||
| 925 | * @link http://www.voip-info.org/wiki-say+phonetic |
||
| 926 | * @param string $buffer |
||
| 927 | * @param string $text |
||
| 928 | * @param string $escape_digits |
||
| 929 | * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no |
||
| 930 | * digit received, otherwise a decimal value of the DTMF tone. Use chr() to convert to ASCII. |
||
| 931 | */ |
||
| 932 | function fastpass_say_phonetic(string &$buffer, string $text, string $escape_digits = ''): array { |
||
| 933 | if ($buffer == '' || $this->proceedDigits($buffer, $escape_digits)) { |
||
| 934 | $res = $this->say_phonetic($text, $escape_digits); |
||
| 935 | $this->appendBuffer($buffer, $res); |
||
| 936 | return $res; |
||
| 937 | } |
||
| 938 | return ['code' => AGI_Others::AGIRES_OK, |
||
| 939 | 'result' => $this->ordBuffer($buffer)]; |
||
| 940 | } |
||
| 941 | |||
| 942 | /** |
||
| 943 | * Say a given time, returning early if any of the given DTMF escape digits are received on the channel. |
||
| 944 | * Return early if $buffer is adequate for request. |
||
| 945 | * |
||
| 946 | * @link http://www.voip-info.org/wiki-say+time |
||
| 947 | * @param string $buffer |
||
| 948 | * @param integer $time number of seconds elapsed since 00:00:00 on January 1, 1970, Coordinated Universal Time (UTC). |
||
| 949 | * @param string $escape_digits |
||
| 950 | * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no |
||
| 951 | * digit received, otherwise a decimal value of the DTMF tone. Use chr() to convert to ASCII. |
||
| 952 | */ |
||
| 953 | function fastpass_say_time(string &$buffer, $time = null, string $escape_digits = ''): array { |
||
| 954 | if ($buffer == '' || $this->proceedDigits($buffer, $escape_digits)) { |
||
| 955 | $res = $this->say_time($time, $escape_digits); |
||
| 956 | $this->appendBuffer($buffer, $res); |
||
| 957 | return $res; |
||
| 958 | } |
||
| 959 | return ['code' => AGI_Others::AGIRES_OK, |
||
| 960 | 'result' => $this->ordBuffer($buffer)]; |
||
| 961 | } |
||
| 962 | |||
| 963 | /** |
||
| 964 | * Play the given audio file, allowing playback to be interrupted by a DTMF digit. This command is similar to the GET DATA |
||
| 965 | * command but this command returns after the first DTMF digit has been pressed while GET DATA can accumulated any number of |
||
| 966 | * digits before returning. |
||
| 967 | * Return early if $buffer is adequate for request. |
||
| 968 | * |
||
| 969 | * @link http://www.voip-info.org/wiki-stream+file |
||
| 970 | * @param string $buffer |
||
| 971 | * @param string $filename without extension, often in /var/lib/asterisk/sounds |
||
| 972 | * @param string $escape_digits |
||
| 973 | * @param integer $offset |
||
| 974 | * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no |
||
| 975 | * digit received, otherwise a decimal value of the DTMF tone. Use chr() to convert to ASCII. |
||
| 976 | */ |
||
| 977 | function fastpass_stream_file(string &$buffer, string $filename, string $escape_digits = '', int $offset = 0): array { |
||
| 978 | if ($buffer == '' || $this->proceedDigits($buffer, $escape_digits)) { |
||
| 979 | $res = $this->stream_file($filename, $escape_digits, $offset); |
||
| 980 | $this->appendBuffer($buffer, $res); |
||
| 981 | return $res; |
||
| 982 | } |
||
| 983 | return ['code' => AGI_Others::AGIRES_OK, |
||
| 984 | 'result' => $this->ordBuffer($buffer), |
||
| 985 | 'endpos' => 0]; |
||
| 986 | } |
||
| 987 | |||
| 988 | /** |
||
| 989 | * Use festival to read text. |
||
| 990 | * Return early if $buffer is adequate for request. |
||
| 991 | * |
||
| 992 | * @link http://www.cstr.ed.ac.uk/projects/festival/ |
||
| 993 | * @param string $buffer |
||
| 994 | * @param string $text |
||
| 995 | * @param string $escape_digits |
||
| 996 | * @param integer $frequency |
||
| 997 | * @return array, see evaluate for return information. |
||
| 998 | */ |
||
| 999 | function fastpass_text2wav(string &$buffer, string $text, string $escape_digits = '', int $frequency = 8000): array { |
||
| 1000 | if ($buffer == '' || $this->proceedDigits($buffer, $escape_digits)) { |
||
| 1001 | $res = $this->text2wav($text, $escape_digits, $frequency); |
||
| 1002 | $this->appendBuffer($buffer, $res); |
||
| 1003 | return $res; |
||
| 1004 | } |
||
| 1005 | return ['code' => AGI_Others::AGIRES_OK, |
||
| 1006 | 'result' => $this->ordBuffer($buffer), |
||
| 1007 | 'endpos' => 0]; |
||
| 1008 | } |
||
| 1009 | |||
| 1010 | /** |
||
| 1011 | * Use Cepstral Swift to read text. |
||
| 1012 | * Return early if $buffer is adequate for request. |
||
| 1013 | * |
||
| 1014 | * @link http://www.cepstral.com/ |
||
| 1015 | * @param string $buffer |
||
| 1016 | * @param string $text |
||
| 1017 | * @param string $escape_digits |
||
| 1018 | * @param integer $frequency |
||
| 1019 | * @param $voice |
||
| 1020 | * @return array, see evaluate for return information. |
||
| 1021 | */ |
||
| 1022 | function fastpass_swift(string &$buffer, string $text, string $escape_digits = '', int $frequency = 8000, $voice = null): array { |
||
| 1031 | } |
||
| 1032 | |||
| 1033 | /** |
||
| 1034 | * Say Punctuation in a string. |
||
| 1035 | * Return early if $buffer is adequate for request. |
||
| 1036 | * |
||
| 1037 | * @param string $buffer |
||
| 1038 | * @param string $text |
||
| 1039 | * @param string $escape_digits |
||
| 1040 | * @param integer $frequency |
||
| 1041 | * @return array, see evaluate for return information. |
||
| 1042 | */ |
||
| 1043 | function fastpass_say_punctuation(string &$buffer, string $text, string $escape_digits = '', int $frequency = 8000): array { |
||
| 1044 | if ($buffer == '' || $this->proceedDigits($buffer, $escape_digits)) { |
||
| 1045 | $res = $this->say_punctuation($text, $escape_digits, $frequency); |
||
| 1046 | $this->appendBuffer($buffer, $res); |
||
| 1047 | return $res; |
||
| 1048 | } |
||
| 1049 | return ['code' => AGI_Others::AGIRES_OK, |
||
| 1050 | 'result' => $this->ordBuffer($buffer)]; |
||
| 1051 | } |
||
| 1052 | |||
| 1053 | /** |
||
| 1054 | * Plays the given file and receives DTMF data. |
||
| 1055 | * Return early if $buffer is adequate for request. |
||
| 1056 | * |
||
| 1057 | * This is similar to STREAM FILE, but this command can accept and return many DTMF digits, |
||
| 1058 | * while STREAM FILE returns immediately after the first DTMF digit is detected. |
||
| 1059 | * |
||
| 1060 | * Asterisk looks for the file to play in /var/lib/asterisk/sounds by default. |
||
| 1061 | * |
||
| 1062 | * If the user doesn't press any keys when the message plays, there is $timeout milliseconds |
||
| 1063 | * of silence then the command ends. |
||
| 1064 | * |
||
| 1065 | * The user has the opportunity to press a key at any time during the message or the |
||
| 1066 | * post-message silence. If the user presses a key while the message is playing, the |
||
| 1067 | * message stops playing. When the first key is pressed a timer starts counting for |
||
| 1068 | * $timeout milliseconds. Every time the user presses another key the timer is restarted. |
||
| 1069 | * The command ends when the counter goes to zero or the maximum number of digits is entered, |
||
| 1070 | * whichever happens first. |
||
| 1071 | * |
||
| 1072 | * If you don't specify a time out then a default timeout of 2000 is used following a pressed |
||
| 1073 | * digit. If no digits are pressed then 6 seconds of silence follow the message. |
||
| 1074 | * |
||
| 1075 | * If you don't specify $max_digits then the user can enter as many digits as they want. |
||
| 1076 | * |
||
| 1077 | * Pressing the # key has the same effect as the timer running out: the command ends and |
||
| 1078 | * any previously keyed digits are returned. A side effect of this is that there is no |
||
| 1079 | * way to read a # key using this command. |
||
| 1080 | * |
||
| 1081 | * @link http://www.voip-info.org/wiki-get+data |
||
| 1082 | * @param string $buffer |
||
| 1083 | * @param string $filename file to play. Do not include file extension. |
||
| 1084 | * @param integer $timeout milliseconds |
||
| 1085 | * @param integer $max_digits |
||
| 1086 | * @return array, see evaluate for return information. ['result'] holds the digits and ['data'] holds the timeout if present. |
||
| 1087 | * |
||
| 1088 | * This differs from other commands with return DTMF as numbers representing ASCII characters. |
||
| 1089 | */ |
||
| 1090 | function fastpass_get_data(string &$buffer, string $filename, $timeout = null, $max_digits = null): array { |
||
| 1091 | if (is_null($max_digits) || strlen($buffer) < $max_digits) { |
||
| 1092 | if ($buffer == '') { |
||
| 1093 | $res = $this->get_data($filename, $timeout, $max_digits); |
||
| 1094 | if ($res['code'] == AGI_Others::AGIRES_OK) { |
||
| 1095 | $buffer .= $res['result']; |
||
| 1096 | } |
||
| 1097 | return $res; |
||
| 1098 | } |
||
| 1099 | while (is_null($max_digits) || strlen($buffer) < $max_digits) { |
||
| 1100 | $res = $this->wait_for_digit(); |
||
| 1101 | if ($res['code'] != AGI_Others::AGIRES_OK) { |
||
| 1102 | return $res; |
||
| 1103 | } |
||
| 1104 | if ($res['result'] == ord('#')) { |
||
| 1105 | break; |
||
| 1106 | } |
||
| 1107 | $buffer .= chr($res['result']); |
||
| 1108 | } |
||
| 1109 | } |
||
| 1110 | return ['code' => AGI_Others::AGIRES_OK, |
||
| 1111 | 'result' => $buffer]; |
||
| 1112 | } |
||
| 1113 | |||
| 1114 | // ********************************************************************************************************* |
||
| 1115 | // ** DERIVED ** |
||
| 1116 | // ********************************************************************************************************* |
||
| 1117 | |||
| 1118 | /** |
||
| 1119 | * Menu. |
||
| 1120 | * |
||
| 1121 | * This function presents the user with a menu and reads the response |
||
| 1122 | * |
||
| 1123 | * @param array $choices has the following structure: |
||
| 1124 | * array('1'=>'*Press 1 for this', // festival reads if prompt starts with * |
||
| 1125 | * '2'=>'some-gsm-without-extension', |
||
| 1126 | * '*'=>'*Press star for help'); |
||
| 1127 | * @param int $timeout |
||
| 1128 | * @return mixed key pressed on success, -1 on failure |
||
| 1129 | */ |
||
| 1130 | function menu(array $choices, int $timeout = 2000) { |
||
| 1131 | $keys = join('', array_keys($choices)); |
||
| 1132 | $choice = null; |
||
| 1133 | while (is_null($choice)) { |
||
| 1134 | foreach ($choices as $prompt) { |
||
| 1135 | if ($prompt[0] == '*') { |
||
| 1136 | $ret = $this->text2wav(substr($prompt, 1), $keys); |
||
| 1137 | } else { |
||
| 1138 | $ret = $this->stream_file($prompt, $keys); |
||
| 1139 | } |
||
| 1140 | |||
| 1141 | if ($ret['code'] != AGI_Others::AGIRES_OK || $ret['result'] == -1) { |
||
| 1142 | $choice = -1; |
||
| 1143 | break; |
||
| 1144 | } |
||
| 1145 | |||
| 1146 | if ($ret['result'] != 0) { |
||
| 1147 | $choice = chr($ret['result']); |
||
| 1148 | break; |
||
| 1149 | } |
||
| 1150 | } |
||
| 1151 | |||
| 1152 | if (is_null($choice)) { |
||
| 1153 | $ret = $this->get_data('beep', $timeout, 1); |
||
| 1154 | if ($ret['code'] != AGI_Others::AGIRES_OK || $ret['result'] == -1) { |
||
| 1155 | $choice = -1; |
||
| 1156 | } elseif ($ret['result'] != '' && strpos(' ' . $keys, $ret['result'])) { |
||
| 1157 | $choice = $ret['result']; |
||
| 1158 | } |
||
| 1159 | } |
||
| 1160 | } |
||
| 1161 | return $choice; |
||
| 1162 | } |
||
| 1163 | |||
| 1164 | /** |
||
| 1165 | * setContext - Set context, extension and priority. |
||
| 1166 | * |
||
| 1167 | * @param string $context |
||
| 1168 | * @param string $extension |
||
| 1169 | * @param string $priority |
||
| 1170 | */ |
||
| 1171 | function setContext(string $context, string $extension = 's', $priority = 1) { |
||
| 1172 | $this->set_context($context); |
||
| 1173 | $this->set_extension($extension); |
||
| 1174 | $this->set_priority($priority); |
||
| 1175 | } |
||
| 1176 | |||
| 1177 | /** |
||
| 1178 | * Parse caller id. |
||
| 1179 | * |
||
| 1180 | * @param string $callerid |
||
| 1181 | * @return array('Name'=>$name, 'Number'=>$number) |
||
| 1182 | * @example examples/dtmf.php Get DTMF tones from the user and say the digits |
||
| 1183 | * @example examples/input.php Get text input from the user and say it back |
||
| 1184 | * |
||
| 1185 | * "name" <proto:user@server:port> |
||
| 1186 | * |
||
| 1187 | */ |
||
| 1188 | function parse_callerid($callerid = null): array { |
||
| 1189 | if (is_null($callerid)) { |
||
| 1190 | $callerid = $this->request['agi_callerid']; |
||
| 1191 | } |
||
| 1192 | |||
| 1193 | $ret = ['name' => '', |
||
| 1194 | 'protocol' => '', |
||
| 1195 | 'username' => '', |
||
| 1196 | 'host' => '', |
||
| 1197 | 'port' => '']; |
||
| 1198 | $callerid = trim($callerid); |
||
| 1199 | |||
| 1200 | if ($callerid[0] == '"' || $callerid[0] == "'") { |
||
| 1201 | $d = $callerid[0]; |
||
| 1202 | $callerid = explode($d, substr($callerid, 1)); |
||
| 1203 | $ret['name'] = array_shift($callerid); |
||
| 1204 | $callerid = join($d, $callerid); |
||
| 1205 | } |
||
| 1206 | |||
| 1207 | $callerid = explode('@', trim($callerid, '<> ')); |
||
| 1208 | $username = explode(':', array_shift($callerid)); |
||
| 1209 | if (count($username) == 1) { |
||
| 1210 | $ret['username'] = $username[0]; |
||
| 1211 | } else { |
||
| 1212 | $ret['protocol'] = array_shift($username); |
||
| 1213 | $ret['username'] = join(':', $username); |
||
| 1214 | } |
||
| 1215 | |||
| 1216 | $callerid = join('@', $callerid); |
||
| 1217 | $host = explode(':', $callerid); |
||
| 1218 | if (count($host) == 1) { |
||
| 1219 | $ret['host'] = $host[0]; |
||
| 1220 | } else { |
||
| 1221 | $ret['host'] = array_shift($host); |
||
| 1222 | $ret['port'] = join(':', $host); |
||
| 1223 | } |
||
| 1224 | |||
| 1225 | return $ret; |
||
| 1226 | } |
||
| 1227 | |||
| 1228 | /** |
||
| 1229 | * Use festival to read text. |
||
| 1230 | * |
||
| 1231 | * @param string $text |
||
| 1232 | * @param string $escape_digits |
||
| 1233 | * @param integer $frequency |
||
| 1234 | * @return array | bool, see evaluate for return information. |
||
| 1235 | * @example examples/dtmf.php Get DTMF tones from the user and say the digits |
||
| 1236 | * @example examples/input.php Get text input from the user and say it back |
||
| 1237 | * @example examples/ping.php Ping an IP address |
||
| 1238 | * |
||
| 1239 | * @link http://www.cstr.ed.ac.uk/projects/festival/ |
||
| 1240 | */ |
||
| 1241 | function text2wav(string $text, string $escape_digits = '', int $frequency = 8000) { |
||
| 1242 | $text = trim($text); |
||
| 1243 | if ($text == '') { |
||
| 1244 | return true; |
||
| 1245 | } |
||
| 1246 | |||
| 1247 | $hash = md5($text); |
||
| 1248 | $fname = $this->config['phpagi']['tempdir'] . DIRECTORY_SEPARATOR; |
||
| 1249 | $fname .= 'text2wav_' . $hash; |
||
| 1250 | |||
| 1251 | // create wave file |
||
| 1252 | if (!file_exists("$fname.wav")) { |
||
| 1253 | // write text file |
||
| 1254 | if (!file_exists("$fname.txt")) { |
||
| 1255 | $fp = fopen("$fname.txt", 'w'); |
||
| 1256 | fputs($fp, $text); |
||
| 1257 | fclose($fp); |
||
| 1258 | } |
||
| 1259 | |||
| 1260 | shell_exec("{$this->config['festival']['text2wave']} -F $frequency -o $fname.wav $fname.txt"); |
||
| 1261 | } else { |
||
| 1262 | touch("$fname.txt"); |
||
| 1263 | touch("$fname.wav"); |
||
| 1264 | } |
||
| 1265 | |||
| 1266 | // stream it |
||
| 1267 | $ret = $this->stream_file($fname, $escape_digits); |
||
| 1268 | |||
| 1269 | // clean up old files |
||
| 1270 | $delete = time() - 2592000; // 1 month |
||
| 1271 | foreach (glob($this->config['phpagi']['tempdir'] . DIRECTORY_SEPARATOR . 'text2wav_*') as $file) { |
||
| 1272 | if (filemtime($file) < $delete) { |
||
| 1273 | unlink($file); |
||
| 1274 | } |
||
| 1275 | } |
||
| 1276 | |||
| 1277 | return $ret; |
||
| 1278 | } |
||
| 1279 | |||
| 1280 | /** |
||
| 1281 | * Use Cepstral Swift to read text. |
||
| 1282 | * |
||
| 1283 | * @link http://www.cepstral.com/ |
||
| 1284 | * @param string $text |
||
| 1285 | * @param string $escape_digits |
||
| 1286 | * @param integer $frequency |
||
| 1287 | * @param $voice |
||
| 1288 | * @return array | bool, see evaluate for return information. |
||
| 1289 | */ |
||
| 1290 | function swift(string $text, string $escape_digits = '', int $frequency = 8000, $voice = null) { |
||
| 1291 | if (!is_null($voice)) { |
||
| 1292 | $voice = "-n $voice"; |
||
| 1293 | } elseif (isset($this->config['cepstral']['voice'])) { |
||
| 1294 | $voice = "-n {$this->config['cepstral']['voice']}"; |
||
| 1295 | } |
||
| 1296 | |||
| 1297 | $text = trim($text); |
||
| 1298 | if ($text == '') { |
||
| 1299 | return true; |
||
| 1300 | } |
||
| 1301 | |||
| 1302 | $hash = md5($text); |
||
| 1303 | $fname = $this->config['phpagi']['tempdir'] . DIRECTORY_SEPARATOR; |
||
| 1304 | $fname .= 'swift_' . $hash; |
||
| 1305 | |||
| 1306 | // create wave file |
||
| 1307 | if (!file_exists("$fname.wav")) { |
||
| 1308 | // write text file |
||
| 1309 | if (!file_exists("$fname.txt")) { |
||
| 1310 | $fp = fopen("$fname.txt", 'w'); |
||
| 1311 | fputs($fp, $text); |
||
| 1312 | fclose($fp); |
||
| 1313 | } |
||
| 1314 | |||
| 1315 | shell_exec("{$this->config['cepstral']['swift']} -p audio/channels=1,audio/sampling-rate=$frequency $voice -o $fname.wav -f $fname.txt"); |
||
| 1316 | } |
||
| 1317 | |||
| 1318 | // stream it |
||
| 1319 | $ret = $this->stream_file($fname, $escape_digits); |
||
| 1320 | |||
| 1321 | // clean up old files |
||
| 1322 | $delete = time() - 2592000; // 1 month |
||
| 1323 | foreach (glob($this->config['phpagi']['tempdir'] . DIRECTORY_SEPARATOR . 'swift_*') as $file) { |
||
| 1324 | if (filemtime($file) < $delete) { |
||
| 1325 | unlink($file); |
||
| 1326 | } |
||
| 1327 | } |
||
| 1328 | |||
| 1329 | return $ret; |
||
| 1330 | } |
||
| 1331 | |||
| 1332 | /** |
||
| 1333 | * Text Input. |
||
| 1334 | * |
||
| 1335 | * Based on ideas found at http://www.voip-info.org/wiki-Asterisk+cmd+DTMFToText |
||
| 1336 | * |
||
| 1337 | * Example: |
||
| 1338 | * UC H LC i , SP h o w SP a r e SP y o u ? |
||
| 1339 | * $string = '*8'.'44*'.'*5'.'444*'.'00*'.'0*'.'44*'.'666*'.'9*'.'0*'.'2*'.'777*'.'33*'.'0*'.'999*'.'666*'.'88*'.'0000*'; |
||
| 1340 | * |
||
| 1341 | * @link http://www.voip-info.org/wiki-Asterisk+cmd+DTMFToText |
||
| 1342 | * @example examples/input.php Get text input from the user and say it back |
||
| 1343 | * |
||
| 1344 | * @param string $mode |
||
| 1345 | * @return string |
||
| 1346 | */ |
||
| 1347 | function text_input(string $mode = 'NUMERIC'): string { |
||
| 1348 | $alpha = ['k0' => ' ', |
||
| 1349 | 'k00' => ',', |
||
| 1350 | 'k000' => '.', |
||
| 1351 | 'k0000' => '?', |
||
| 1352 | 'k00000' => '0', |
||
| 1353 | 'k1' => '!', |
||
| 1354 | 'k11' => ':', |
||
| 1355 | 'k111' => ';', |
||
| 1356 | 'k1111' => '#', |
||
| 1357 | 'k11111' => '1', |
||
| 1358 | 'k2' => 'A', |
||
| 1359 | 'k22' => 'B', |
||
| 1360 | 'k222' => 'C', |
||
| 1361 | 'k2222' => '2', |
||
| 1362 | 'k3' => 'D', |
||
| 1363 | 'k33' => 'E', |
||
| 1364 | 'k333' => 'F', |
||
| 1365 | 'k3333' => '3', |
||
| 1366 | 'k4' => 'G', |
||
| 1367 | 'k44' => 'H', |
||
| 1368 | 'k444' => 'I', |
||
| 1369 | 'k4444' => '4', |
||
| 1370 | 'k5' => 'J', |
||
| 1371 | 'k55' => 'K', |
||
| 1372 | 'k555' => 'L', |
||
| 1373 | 'k5555' => '5', |
||
| 1374 | 'k6' => 'M', |
||
| 1375 | 'k66' => 'N', |
||
| 1376 | 'k666' => 'O', |
||
| 1377 | 'k6666' => '6', |
||
| 1378 | 'k7' => 'P', |
||
| 1379 | 'k77' => 'Q', |
||
| 1380 | 'k777' => 'R', |
||
| 1381 | 'k7777' => 'S', |
||
| 1382 | 'k77777' => '7', |
||
| 1383 | 'k8' => 'T', |
||
| 1384 | 'k88' => 'U', |
||
| 1385 | 'k888' => 'V', |
||
| 1386 | 'k8888' => '8', |
||
| 1387 | 'k9' => 'W', |
||
| 1388 | 'k99' => 'X', |
||
| 1389 | 'k999' => 'Y', |
||
| 1390 | 'k9999' => 'Z', |
||
| 1391 | 'k99999' => '9']; |
||
| 1392 | $symbol = ['k0' => '=', |
||
| 1393 | 'k1' => '<', |
||
| 1394 | 'k11' => '(', |
||
| 1395 | 'k111' => '[', |
||
| 1396 | 'k1111' => '{', |
||
| 1397 | 'k11111' => '1', |
||
| 1398 | 'k2' => '@', |
||
| 1399 | 'k22' => '$', |
||
| 1400 | 'k222' => '&', |
||
| 1401 | 'k2222' => '%', |
||
| 1402 | 'k22222' => '2', |
||
| 1403 | 'k3' => '>', |
||
| 1404 | 'k33' => ')', |
||
| 1405 | 'k333' => ']', |
||
| 1406 | 'k3333' => '}', |
||
| 1407 | 'k33333' => '3', |
||
| 1408 | 'k4' => '+', |
||
| 1409 | 'k44' => '-', |
||
| 1410 | 'k444' => '*', |
||
| 1411 | 'k4444' => '/', |
||
| 1412 | 'k44444' => '4', |
||
| 1413 | 'k5' => "'", |
||
| 1414 | 'k55' => '`', |
||
| 1415 | 'k555' => '5', |
||
| 1416 | 'k6' => '"', |
||
| 1417 | 'k66' => '6', |
||
| 1418 | 'k7' => '^', |
||
| 1419 | 'k77' => '7', |
||
| 1420 | 'k8' => "\\", |
||
| 1421 | 'k88' => '|', |
||
| 1422 | 'k888' => '8', |
||
| 1423 | 'k9' => '_', |
||
| 1424 | 'k99' => '~', |
||
| 1425 | 'k999' => '9']; |
||
| 1426 | $text = ''; |
||
| 1427 | do { |
||
| 1428 | $command = false; |
||
| 1429 | $result = $this->get_data('beep'); |
||
| 1430 | foreach (explode('*', $result['result']) as $code) { |
||
| 1431 | if ($command) { |
||
| 1432 | switch ($code[0]) { |
||
| 1433 | case '2': |
||
| 1434 | $text = substr($text, 0, strlen($text) - 1); |
||
| 1435 | break; // backspace |
||
| 1436 | case '5': |
||
| 1437 | $mode = 'LOWERCASE'; |
||
| 1438 | break; |
||
| 1439 | case '6': |
||
| 1440 | $mode = 'NUMERIC'; |
||
| 1441 | break; |
||
| 1442 | case '7': |
||
| 1443 | $mode = 'SYMBOL'; |
||
| 1444 | break; |
||
| 1445 | case '8': |
||
| 1446 | $mode = 'UPPERCASE'; |
||
| 1447 | break; |
||
| 1448 | case '9': |
||
| 1449 | $text = explode(' ', $text); |
||
| 1450 | unset($text[count($text) - 1]); |
||
| 1451 | $text = join(' ', $text); |
||
| 1452 | break; // backspace a word |
||
| 1453 | } |
||
| 1454 | $code = substr($code, 1); |
||
| 1455 | $command = false; |
||
| 1456 | } |
||
| 1457 | if ($code == '') { |
||
| 1458 | $command = true; |
||
| 1459 | } elseif ($mode == 'NUMERIC') { |
||
| 1460 | $text .= $code; |
||
| 1461 | } elseif ($mode == 'UPPERCASE' && isset($alpha['k' . $code])) { |
||
| 1462 | $text .= $alpha['k' . $code]; |
||
| 1463 | } elseif ($mode == 'LOWERCASE' && isset($alpha['k' . $code])) { |
||
| 1464 | $text .= strtolower($alpha['k' . $code]); |
||
| 1465 | } elseif ($mode == 'SYMBOL' && isset($symbol['k' . $code])) { |
||
| 1466 | $text .= $symbol['k' . $code]; |
||
| 1467 | } |
||
| 1468 | } |
||
| 1469 | $this->say_punctuation($text); |
||
| 1470 | } while (substr($result['result'], -2) == '**'); |
||
| 1471 | return $text; |
||
| 1472 | } |
||
| 1473 | |||
| 1474 | /** |
||
| 1475 | * Say Punctuation in a string. |
||
| 1476 | * |
||
| 1477 | * @param string $text |
||
| 1478 | * @param string $escape_digits |
||
| 1479 | * @param integer $frequency |
||
| 1480 | * @return array, see evaluate for return information. |
||
| 1481 | */ |
||
| 1482 | function say_punctuation(string $text, string $escape_digits = '', int $frequency = 8000): array { |
||
| 1483 | $ret = ""; |
||
| 1484 | for ($i = 0; $i < strlen($text); $i++) { |
||
| 1485 | switch ($text[$i]) { |
||
| 1486 | case ' ': |
||
| 1487 | $ret .= 'SPACE '; |
||
| 1488 | break; |
||
| 1489 | case ',': |
||
| 1490 | $ret .= 'COMMA '; |
||
| 1491 | break; |
||
| 1492 | case '.': |
||
| 1493 | $ret .= 'PERIOD '; |
||
| 1494 | break; |
||
| 1495 | case '?': |
||
| 1496 | $ret .= 'QUESTION MARK '; |
||
| 1497 | break; |
||
| 1498 | case '!': |
||
| 1499 | $ret .= 'EXPLANATION POINT '; |
||
| 1500 | break; |
||
| 1501 | case ':': |
||
| 1502 | $ret .= 'COLON '; |
||
| 1503 | break; |
||
| 1504 | case ';': |
||
| 1505 | $ret .= 'SEMICOLON '; |
||
| 1506 | break; |
||
| 1507 | case '#': |
||
| 1508 | $ret .= 'POUND '; |
||
| 1509 | break; |
||
| 1510 | case '=': |
||
| 1511 | $ret .= 'EQUALS '; |
||
| 1512 | break; |
||
| 1513 | case '<': |
||
| 1514 | $ret .= 'LESS THAN '; |
||
| 1515 | break; |
||
| 1516 | case '(': |
||
| 1517 | $ret .= 'LEFT PARENTHESIS '; |
||
| 1518 | break; |
||
| 1519 | case '[': |
||
| 1520 | $ret .= 'LEFT BRACKET '; |
||
| 1521 | break; |
||
| 1522 | case '{': |
||
| 1523 | $ret .= 'LEFT BRACE '; |
||
| 1524 | break; |
||
| 1525 | case '@': |
||
| 1526 | $ret .= 'AT '; |
||
| 1527 | break; |
||
| 1528 | case '$': |
||
| 1529 | $ret .= 'DOLLAR SIGN '; |
||
| 1530 | break; |
||
| 1531 | case '&': |
||
| 1532 | $ret .= 'AMPERSAND '; |
||
| 1533 | break; |
||
| 1534 | case '%': |
||
| 1535 | $ret .= 'PERCENT '; |
||
| 1536 | break; |
||
| 1537 | case '>': |
||
| 1538 | $ret .= 'GREATER THAN '; |
||
| 1539 | break; |
||
| 1540 | case ')': |
||
| 1541 | $ret .= 'RIGHT PARENTHESIS '; |
||
| 1542 | break; |
||
| 1543 | case ']': |
||
| 1544 | $ret .= 'RIGHT BRACKET '; |
||
| 1545 | break; |
||
| 1546 | case '}': |
||
| 1547 | $ret .= 'RIGHT BRACE '; |
||
| 1548 | break; |
||
| 1549 | case '+': |
||
| 1550 | $ret .= 'PLUS '; |
||
| 1551 | break; |
||
| 1552 | case '-': |
||
| 1553 | $ret .= 'MINUS '; |
||
| 1554 | break; |
||
| 1555 | case '*': |
||
| 1556 | $ret .= 'ASTERISK '; |
||
| 1557 | break; |
||
| 1558 | case '/': |
||
| 1559 | $ret .= 'SLASH '; |
||
| 1560 | break; |
||
| 1561 | case "'": |
||
| 1562 | $ret .= 'SINGLE QUOTE '; |
||
| 1563 | break; |
||
| 1564 | case '`': |
||
| 1565 | $ret .= 'BACK TICK '; |
||
| 1566 | break; |
||
| 1567 | case '"': |
||
| 1568 | $ret .= 'QUOTE '; |
||
| 1569 | break; |
||
| 1570 | case '^': |
||
| 1571 | $ret .= 'CAROT '; |
||
| 1572 | break; |
||
| 1573 | case "\\": |
||
| 1574 | $ret .= 'BACK SLASH '; |
||
| 1575 | break; |
||
| 1576 | case '|': |
||
| 1577 | $ret .= 'BAR '; |
||
| 1578 | break; |
||
| 1579 | case '_': |
||
| 1580 | $ret .= 'UNDERSCORE '; |
||
| 1581 | break; |
||
| 1582 | case '~': |
||
| 1583 | $ret .= 'TILDE '; |
||
| 1584 | break; |
||
| 1585 | default: |
||
| 1586 | $ret .= $text[$i] . ' '; |
||
| 1587 | break; |
||
| 1588 | } |
||
| 1589 | } |
||
| 1590 | return $this->text2wav($ret, $escape_digits, $frequency); |
||
| 1591 | } |
||
| 1592 | |||
| 1593 | /** |
||
| 1594 | * Create a new AGI_AsteriskManager. |
||
| 1595 | */ |
||
| 1596 | function &new_AsteriskManager(): AGI_AsteriskManager { |
||
| 1597 | $this->asm = new AGI_AsteriskManager(null, $this->config['asmanager']); |
||
| 1598 | $this->asm->setPagi($this); |
||
| 1599 | $this->config['asmanager'] = &$this->asm->config['asmanager']; |
||
| 1600 | return $this->asm; |
||
| 1601 | } |
||
| 1602 | |||
| 1603 | |||
| 1604 | // ********************************************************************************************************* |
||
| 1605 | // ** PRIVATE ** |
||
| 1606 | // ********************************************************************************************************* |
||
| 1607 | |||
| 1608 | |||
| 1609 | /** |
||
| 1610 | * Evaluate an AGI command. |
||
| 1611 | * |
||
| 1612 | * @access private |
||
| 1613 | * @param string $command |
||
| 1614 | * @return array ('code'=>$code, 'result'=>$result, 'data'=>$data) |
||
| 1615 | */ |
||
| 1616 | private function evaluate(string $command): array { |
||
| 1617 | $broken = ['code' => 500, |
||
| 1618 | 'result' => -1, |
||
| 1619 | 'data' => '']; |
||
| 1620 | |||
| 1621 | // write command |
||
| 1622 | if (!@fwrite($this->out, trim($command) . "\n")) { |
||
| 1623 | return $broken; |
||
| 1624 | } |
||
| 1625 | fflush($this->out); |
||
| 1626 | |||
| 1627 | // Read result. Occasionally, a command return a string followed by an extra new line. |
||
| 1628 | // When this happens, our script will ignore the new line, but it will still be in the |
||
| 1629 | // buffer. So, if we get a blank line, it is probably the result of a previous |
||
| 1630 | // command. We read until we get a valid result or asterisk hangs up. One offending |
||
| 1631 | // command is SEND TEXT. |
||
| 1632 | $count = 0; |
||
| 1633 | do { |
||
| 1634 | $str = trim(fgets($this->in, 4096)); |
||
| 1635 | } while ($str == '' && $count++ < 5); |
||
| 1636 | |||
| 1637 | if ($count >= 5) { |
||
| 1638 | // $this->conlog("evaluate error on read for $command"); |
||
| 1639 | return $broken; |
||
| 1640 | } |
||
| 1641 | |||
| 1642 | // parse result |
||
| 1643 | $ret['code'] = substr($str, 0, 3); |
||
| 1644 | $str = trim(substr($str, 3)); |
||
| 1645 | |||
| 1646 | if ($str[0] == '-') { // we have a multiline response! |
||
| 1647 | $count = 0; |
||
| 1648 | $str = substr($str, 1) . "\n"; |
||
| 1649 | $line = fgets($this->in, 4096); |
||
| 1650 | while (substr($line, 0, 3) != $ret['code'] && $count < 5) { |
||
| 1651 | $str .= $line; |
||
| 1652 | $line = fgets($this->in, 4096); |
||
| 1653 | $count = (trim($line) == '') ? $count + 1 : 0; |
||
| 1654 | } |
||
| 1655 | if ($count >= 5) { |
||
| 1656 | // $this->conlog("evaluate error on multiline read for $command"); |
||
| 1657 | return $broken; |
||
| 1658 | } |
||
| 1659 | } |
||
| 1660 | |||
| 1661 | $ret['result'] = null; |
||
| 1662 | $ret['data'] = ''; |
||
| 1663 | if ($ret['code'] != AGI_Others::AGIRES_OK) { // some sort of error |
||
| 1664 | $ret['data'] = $str; |
||
| 1665 | $this->conlog(print_r($ret, true)); |
||
| 1666 | } else { // normal AGIRES_OK response |
||
| 1667 | $parse = explode(' ', trim($str)); |
||
| 1668 | $in_token = false; |
||
| 1669 | foreach ($parse as $token) { |
||
| 1670 | if ($in_token) { // we previously hit a token starting with ')' but not ending in ')' |
||
| 1671 | $ret['data'] .= ' ' . trim($token, '() '); |
||
| 1672 | if ($token[strlen($token) - 1] == ')') { |
||
| 1673 | $in_token = false; |
||
| 1674 | } |
||
| 1675 | } elseif ($token[0] == '(') { |
||
| 1676 | if ($token[strlen($token) - 1] != ')') { |
||
| 1677 | $in_token = true; |
||
| 1678 | } |
||
| 1679 | $ret['data'] .= ' ' . trim($token, '() '); |
||
| 1680 | } elseif (strpos($token, '=')) { |
||
| 1681 | $token = explode('=', $token); |
||
| 1682 | $ret[$token[0]] = $token[1]; |
||
| 1683 | } elseif ($token != '') { |
||
| 1684 | $ret['data'] .= ' ' . $token; |
||
| 1685 | } |
||
| 1686 | } |
||
| 1687 | $ret['data'] = trim($ret['data']); |
||
| 1688 | } |
||
| 1689 | |||
| 1690 | // log some errors |
||
| 1691 | if ($ret['result'] < 0) { |
||
| 1692 | $this->conlog("$command returned {$ret['result']}"); |
||
| 1693 | } |
||
| 1694 | |||
| 1695 | return $ret; |
||
| 1696 | } |
||
| 1697 | |||
| 1698 | /** |
||
| 1699 | * Log to console if debug mode. |
||
| 1700 | * |
||
| 1701 | * @param string $str |
||
| 1702 | * @param integer $vbl verbose level |
||
| 1703 | * @example examples/ping.php Ping an IP address |
||
| 1704 | * |
||
| 1705 | */ |
||
| 1706 | function conlog(string $str, int $vbl = 1) { |
||
| 1714 | } |
||
| 1715 | } |
||
| 1716 | } |
||
| 1717 | |||
| 1718 | /** |
||
| 1719 | * Find an executable in the path. |
||
| 1720 | * |
||
| 1721 | * @access private |
||
| 1722 | * @param string $cmd command to find |
||
| 1723 | * @param string $checkpath path to check |
||
| 1724 | * @return string the path to the command |
||
| 1725 | */ |
||
| 1726 | private function which(string $cmd, $checkpath = null) { |
||
| 1727 | if (is_null($checkpath)) { |
||
| 1728 | $chpath = getenv('PATH'); |
||
| 1729 | if ($chpath === false) { |
||
| 1730 | $chpath = '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:' . |
||
| 1731 | '/usr/X11R6/bin:/usr/local/apache/bin:/usr/local/mysql/bin'; |
||
| 1732 | } |
||
| 1733 | } else { |
||
| 1734 | $chpath = $checkpath; |
||
| 1735 | } |
||
| 1736 | |||
| 1737 | foreach (explode(':', $chpath) as $path) { |
||
| 1738 | if (is_executable("$path/$cmd")) { |
||
| 1739 | return "$path/$cmd"; |
||
| 1740 | } |
||
| 1741 | } |
||
| 1742 | |||
| 1743 | return false; |
||
| 1744 | } |
||
| 1745 | |||
| 1746 | /** |
||
| 1747 | * Make a folder recursively. |
||
| 1748 | * |
||
| 1749 | * @access private |
||
| 1750 | * @param string $folder |
||
| 1751 | * @param integer $perms |
||
| 1752 | * @return boolean |
||
| 1753 | */ |
||
| 1754 | private function make_folder(string $folder, int $perms = 0755): bool { |
||
| 1755 | $f = explode(DIRECTORY_SEPARATOR, $folder); |
||
| 1756 | $base = ''; |
||
| 1757 | for ($i = 0; $i < count($f); $i++) { |
||
| 1758 | $base .= $f[$i]; |
||
| 1759 | if ($f[$i] != '' && !file_exists($base)) { |
||
| 1760 | if (mkdir($base, $perms) == false) { |
||
| 1761 | return (false); |
||
| 1762 | } |
||
| 1763 | } |
||
| 1764 | $base .= DIRECTORY_SEPARATOR; |
||
| 1765 | } |
||
| 1766 | return (true); |
||
| 1767 | } |
||
| 1768 | |||
| 1769 | private function proceedDigits(string $buffer, string $escapeDigits): bool { |
||
| 1776 | } |
||
| 1777 | |||
| 1778 | private function ordBuffer(string $buffer): int { |
||
| 1780 | } |
||
| 1781 | |||
| 1782 | private function appendBuffer(string &$buffer, array $res) { |
||
| 1783 | if ($res['code'] == AGI_Others::AGIRES_OK && $res['result'] > 0) { |
||
| 1784 | $buffer .= chr($res['result']); |
||
| 1785 | } |
||
| 1786 | } |
||
| 1787 | } |
||
| 1788 | |||
| 1789 |