params["name"]="value" */ var $params; /** * Static function to output a string to Yate's stderr or logfile * @param $str String to output */ function Output($str) { global $yate_stderr; fputs($yate_stderr, $str . "\n"); } /** * Static function to convert a Yate string representation to a boolean * @param $str String value to convert * @return True if $str is "true", false otherwise */ function Str2bool($str) { return ($str == "true") ? true : false; } /** * Static function to convert a boolean to a Yate string representation * @param $bool Boolean value to convert * @return The string "true" if $bool was true, "false" otherwise */ function Bool2str($bool) { return $bool ? "true" : "false"; } /** * Static function to convert a string to its Yate escaped format * @param $str String to escape * @param $extra (optional) Character to escape in addition to required ones * @return Yate escaped string */ function Escape($str, $extra = "") { $str = $str . ""; $s = ""; $n = strlen($str); for ($i=0; $i<$n; $i++) { $c = $str{$i}; if ((ord($c) < 32) || ($c == ':') || ($c == $extra)) { $c = chr(ord($c) + 64); $s .= '%'; } else if ($c == '%') $s .= $c; $s .= $c; } return $s; } /** * Static function to convert a Yate escaped string back to a plain string * @param $str Yate escaped string to unescape * @return Unescaped string */ function Unescape($str) { $s = ""; $n = strlen($str); for ($i=0; $i<$n; $i++) { $c = $str{$i}; if ($c == '%') { $i++; $c = $str{$i}; if ($c != '%') $c = chr(ord($c) - 64); } $s .= $c; } return $s; } /** * Install a Yate message handler * @param $name Name of the messages to handle * @param $priority (optional) Priority to insert in chain, default 100 */ function Install($name, $priority = 100) { $name=Yate::Escape($name); print "%%>install:$priority:$name\n"; } /** * Uninstall a Yate message handler * @param $name Name of the messages to stop handling */ function Uninstall($name) { $name=Yate::Escape($name); print "%%>uninstall:$name\n"; } /** * Changes a local module parameter * @param $name Name of the parameter to modify * @param $value New value to set in the parameter */ function SetLocal($name, $value) { $name=Yate::Escape($name); $value=Yate::Escape($value); print "%%>setlocal:$name:$value\n"; } /** * Constructor. Creates a new outgoing message * @param $name Name of the new message * @param $retval (optional) Default return * @param $id (optional) Identifier of the new message */ function Yate($name, $retval = "", $id = "") { if ($id == "") $id=uniqid(rand(),1); $this->type="outgoing"; $this->name=$name; $this->retval=$retval; $this->origin=time(); $this->handled=false; $this->id=$id; $this->params=array(); } /** * Retrive the value of a named parameter * @param $key Name of the parameter to retrive * @param $defvalue (optional) Default value to return if parameter is not set * @return Value of the $key parameter or $defvalue */ function GetValue($key, $defvalue = null) { if (isset($this->params[$key])) return $this->params[$key]; return $defvalue; } /** * Fill the parameter array from a text representation * @param $parts A numerically indexed array with the key=value parameters * @param $offs (optional) Offset in array to start processing from */ function FillParams(&$parts, $offs = 0) { $n = count($parts); for ($i=$offs; $i<$n; $i++) { $s=$parts[$i]; $q=strpos($s,'='); if ($q === false) $this->params[Yate::Unescape($s)]=NULL; else $this->params[Yate::Unescape(substr($s,0,$q))]=Yate::Unescape(substr($s,$q+1)); } } /** * Dispatch the message to Yate for handling * @param $message Message object to dispatch */ function Dispatch() { if ($this->type != "outgoing") { Yate::Output("PHP bug: attempt to dispatch message type: " . $this->type); return; } $i=Yate::Escape($this->id); $t=0+$this->origin; $n=Yate::Escape($this->name); $r=Yate::Escape($this->retval); $p=""; $pa = array(&$p); array_walk($this->params, "_yate_message_walk", $pa); print "%%>message:$i:$t:$n:$r$p\n"; $this->type="dispatched"; } /** * Acknowledge the processing of a message passed from Yate * @param $handled (optional) True if Yate should stop processing, default false */ function Acknowledge() { if ($this->type != "incoming") { Yate::Output("PHP bug: attempt to acknowledge message type: " . $this->type); return; } $i=Yate::Escape($this->id); $k=Yate::Bool2str($this->handled); $n=Yate::Escape($this->name); $r=Yate::Escape($this->retval); $p=""; $pa = array(&$p); array_walk($this->params, "_yate_message_walk", $pa); print "%%type="acknowledged"; } /** * This static function processes just one input line. * It must be called in a loop to keep messages running. Or else. * @return "EOF" if we should exit, "" if we should keep running, * or an Yate object instance */ function GetEvent() { global $yate_stdin; if (feof($yate_stdin)) return "EOF"; $line=fgets($yate_stdin,4096); if ($line == false) return ""; $line=str_replace("\n", "", $line); if ($line == "") return ""; $ev=""; $part=explode(":", $line); switch ($part[0]) { case "%%>message": /* incoming message str_id:int_time:str_name:str_retval[:key=value...] */ $ev=new Yate(Yate::Unescape($part[3]),Yate::Unescape($part[4]),Yate::Unescape($part[1])); $ev->type="incoming"; $ev->origin=0+$part[2]; $ev->FillParams($part,5); break; case "%%type="answer"; $ev->handled=Yate::Str2bool($part[2]); $ev->FillParams($part,5); break; case "%%type="installed"; $ev->handled=Yate::Str2bool($part[3]); break; case "%%type="uninstalled"; $ev->handled=Yate::Str2bool($part[3]); break; case "%%type="setlocal"; $ev->handled=Yate::Str2bool($part[3]); break; case "Error in": /* We are already in error so better stay quiet */ break; default: Yate::Output("PHP parse error: " . $line); } return $ev; } /** * This static function initializes globals in the PHP Yate External Module. * It should be called before any other method. * @param $async (optional) True if asynchronous, polled mode is desired */ function Init($async = false) { global $yate_stdin, $yate_stdout, $yate_stderr; $yate_stdin = fopen("php://stdin","r"); $yate_stdout = fopen("php://stdout","w"); $yate_stderr = fopen("php://stderr","w"); flush(); set_error_handler(_yate_error_handler); ob_implicit_flush(1); if ($async && function_exists("stream_set_blocking")) stream_set_blocking($yate_stdin,false); } } /* Internal error handler callback - output plain text to stderr */ function _yate_error_handler($errno, $errstr, $errfile, $errline) { $str = " [$errno] $errstr in $errfile line $errline\n"; switch ($errno) { case E_USER_ERROR: Yate::Output("PHP fatal:" . $str); exit(1); break; case E_WARNING: case E_USER_WARNING: Yate::Output("PHP error:" . $str); break; case E_NOTICE: case E_USER_NOTICE: Yate::Output("PHP warning:" . $str); break; default: Yate::Output("PHP unknown error:" . $str); } } /* Internal function */ function _yate_message_walk($item, $key, &$result) { // workaround to pass by reference the 3rd parameter to message_walk: // the reference is placed in an array and the array is passed by value // taken from: http://hellsgate.online.ee/~glen/array_walk2.php $result[0] .= ':' . Yate::Escape($key,'=') . '=' . Yate::Escape($item); } /* vi: set ts=8 sw=4 sts=4 noet: */ ?>