function setState($newstate) { global $ourcallid; global $partycallid; global $state; global $dir; // are we exiting? if ($state == "") { return; } Yate::Output("setState('" . $newstate . "') state: " . $state); // always obey a return to prompt if ($newstate == "prompt") { $state = $newstate; $m = new Yate("chan.attach"); $m->params["source"] = "wave/play/scripts/playrec_menu.au"; $m->Dispatch(); $m = new Yate("chan.attach"); $m->params["consumer"] = "wave/record/-"; $m->params["maxlen"] = 320000; $m->params["notify"] = $ourcallid; $m->Dispatch(); return; } if ($newstate == $state) { return; } switch ($newstate) { case "record": $m = new Yate("chan.attach"); $m->params["source"] = "wave/play/-"; $m->params["consumer"] = "wave/record/" . $dir . "/playrec.slin"; $m->params["maxlen"] = 80000; $m->params["notify"] = $ourcallid; $m->Dispatch(); break; case "play": $m = new Yate("chan.attach"); $m->params["source"] = "wave/play/" . $dir . "/playrec.slin"; $m->params["consumer"] = "wave/record/-"; $m->params["maxlen"] = 4800000; $m->params["notify"] = $ourcallid; $m->Dispatch(); break; case "goodbye": $m = new Yate("chan.attach"); $m->params["source"] = "tone/congestion"; $m->params["consumer"] = "wave/record/-"; $m->params["maxlen"] = 32000; $m->params["notify"] = $ourcallid; $m->Dispatch(); break; } $state = $newstate; }
function callInitiate($target, $ev) { Yate::Debug("Initiating dialout call to '{$target}'"); $m = new Yate("call.execute"); $m->id = ""; $m->SetParam("callto", "external/nodata/dialout-dialer.php"); $m->SetParam("direct", $target); $m->SetParam("caller", $ev->GetValue("caller")); $m->SetParam("callername", $ev->GetValue("callername")); $m->SetParam("called", $ev->GetValue("called")); $m->Dispatch(); }
function SendMsg($msg) { global $ourcallid; global $partycallid; $m = new Yate($msg); $m->id = ""; $m->params["id"] = $ourcallid; $m->params["peerid"] = $partycallid; $m->params["targetid"] = $partycallid; $m->params["reason"] = "queued"; $m->params["cdrcreate"] = "false"; $m->Dispatch(); }
function callInitiate($target, $ev) { Yate::Debug("Initiating dialout call to '{$target}'"); $m = new Yate("call.execute"); $m->params = $ev->params; $m->id = ""; $m->SetParam("callto", "external/nodata/ctc-dialer.php"); $m->SetParam("direct", $target); $m->SetParam("caller", $ev->GetValue("real_called")); $m->SetParam("call_from", $ev->GetValue("call_from")); $m->SetParam("called", $ev->GetValue("real_caller")); $m->SetParam("cdrtrack", "true"); $m->Dispatch(); }
function runCallTimer($when) { global $nextCallTime; global $numberCalled; global $sipGateway; if ($when < $nextCallTime) { return; } $nextCallTime = $when + rand(1, 10); $m = new Yate("call.execute"); $m->id = ""; $m->params["cdrtrack"] = "false"; $m->params["callto"] = "tone/noise"; $m->params["called"] = $numberCalled; $m->params["caller"] = rand(210000000, 799999999); $m->params["direct"] = "sip/sip:{$numberCalled}@{$sipGateway}"; $m->Dispatch(); }
function secondCall($route, $ev) { global $partycallid; global $real_called; global $billid; global $callFrom; // global $place; //$real_caller = '79297333104'; $m = new Yate("chan.masquerade"); $m->params = $ev->params; $m->SetParam("message", "call.execute"); $m->SetParam("callto", $route); //$m->SetParam("caller", $real_caller); $m->SetParam("called", $real_called); $m->SetParam("id", $partycallid); $m->SetParam("billid", $billid); $m->SetParam("call_from", $callFrom); $m->Dispatch(); }
function onDisconnect(&$ev, $reason) { global $ourcallid; Yate::Output("Channel {$ourcallid} was disconnected, reason: '{$reason}'"); // Sample action: redirect to info tone if user is busy if ($reason == "busy") { $m = new Yate("call.execute"); $m->id = $ev->id; $m->params["id"] = $ourcallid; $m->params["callto"] = "tone/info"; $m->Dispatch(); // Also send progressing so the tone goes through in early media $m = new Yate("call.progress"); $m->params["targetid"] = $ourcallid; $m->Dispatch(); return true; } return false; }
function sendTones($id, $text) { global $param; Yate::Debug($param . ": sendTones(" . $id . "," . $text . ")"); while (strlen($text) > 0) { $tone = substr($text, 0, 1); $text = substr($text, 1); if ($tone == "|") { if (!empty($text)) { setupCall($id, true, 1, $text); } break; } $m = new Yate("chan.masquerade"); $m->params["id"] = $id; $m->params["message"] = "chan.dtmf"; $m->params["text"] = $tone; $m->Dispatch(); } }
function Notify($state = false) { Yate::Debug("Notifying event " . $this->event . " for " . $this->match); if ($state !== false) { $this->state = $state; $this->pending = true; } if ($this->body == "") { Yate::Output("Empty body in event " . $this->event . " for " . $this->match); return; } $this->pending = false; $m = new Yate("xsip.generate"); $m->id = ""; $m->params["method"] = "NOTIFY"; $m->params["uri"] = $this->contact; $m->params["host"] = $this->host; $m->params["port"] = $this->port; $m->params["sip_Call-ID"] = $this->callid; $m->params["sip_From"] = $this->to; $m->params["sip_To"] = $this->from; $m->params["sip_Contact"] = "<" . $this->uri . ">"; $m->params["sip_Event"] = $this->event; $m->params["sip_Subscription-State"] = $this->state; $m->params["xsip_type"] = $this->media; $m->params["xsip_body"] = $this->body; $m->Dispatch(); }
if ($ev) { $ev->Acknowledge(); } break; case "answer": Yate::Debug("PHP Answered: " . $ev->name . " id: " . $ev->id); if (!$ev->handled) { if ($ev->name == "call.execute") { // call leg to operator didn't even start Yate::Output("Failed to start queue '{$queue}' call leg to: " . $ev->GetValue("callto")); $m = new Yate("chan.hangup"); $m->id = ""; $m->params["notify"] = $partycallid; $m->params["queue"] = $queue; $m->params["cdrtrack"] = "false"; $m->Dispatch(); } else { if ($ev->name == "chan.locate") { // caller hung up before we installed the hangup handler Yate::Output("Call {$partycallid} from '{$caller}' exited early from '{$queue}'"); Yate::SetLocal("reason", "nocall"); exit; } } } break; default: Yate::Debug("PHP Event: " . $ev->type); } } Yate::Debug("PHP: bye!");
function onFax($id) { Yate::Output("Fax call detected on {$id}"); $m = new Yate("chan.masquerade"); $m->id = ""; // don't notify about message result $m->params["message"] = "call.execute"; $m->params["id"] = $id; // FIXME: generate an unique name for each call $m->params["callto"] = "fax/receive/spool/fax-rx.tif"; $m->params["reason"] = "fax"; $m->Dispatch(); }
function setState($newstate) { global $ourcallid; global $state; global $vm_base; global $mailbox; global $user; global $file; // are we exiting? if ($state == "") { return; } debug("setState('{$newstate}') state: {$state}"); if ($newstate == $state) { return; } switch ($newstate) { case "novmail": $m = new Yate("chan.attach"); $m->params["source"] = "wave/play/{$vm_base}/novmail.au"; $m->params["notify"] = $ourcallid; $m->Dispatch(); break; case "greeting": $m = new Yate("chan.attach"); if (is_file("{$user}/greeting.au")) { $m->params["source"] = "wave/play/{$user}/greeting.au"; } else { $m->params["source"] = "wave/play/{$vm_base}/nogreeting.au"; } $m->params["notify"] = $ourcallid; $m->Dispatch(); break; case "beep": $m = new Yate("chan.attach"); $m->params["source"] = "wave/play/{$vm_base}/beep.au"; $m->params["notify"] = $ourcallid; $m->Dispatch(); break; case "record": $m = new Yate("chan.attach"); $m->params["source"] = "wave/play/-"; $m->params["consumer"] = "wave/record/{$user}/{$file}"; $m->params["maxlen"] = 160000; $m->params["notify"] = $ourcallid; $m->Dispatch(); $m = new Yate("user.update"); $m->id = ""; $m->params["user"] = $mailbox; $m->Dispatch(); break; case "goodbye": $m = new Yate("chan.attach"); $m->params["source"] = "tone/congestion"; $m->params["consumer"] = "wave/record/-"; $m->params["maxlen"] = 32000; $m->params["notify"] = $ourcallid; $m->Dispatch(); break; } $state = $newstate; }
/** * Play a standard tone * @param $file (optional) Name of the tone to play * @param $wait (optional) True to block until tones are received, false to continue */ static function PlayTone($tone = "dial", $wait = true) { global $chan_instance; if ($chan_instance->exiting) { return; } $m = new Yate("chan.attach"); $m->params["source"] = "tone/{$tone}"; $m->Dispatch(); if ($wait) { YateChan::RunEvents(); } }
function callAnswered() { global $ourcallid; global $prompt; global $done; Yate::Debug("callAnswered"); if ($prompt != "") { $m = new Yate("chan.attach"); $m->id = ""; $m->SetParam("id", $ourcallid); $m->SetParam("source", $prompt); $m->SetParam("single", true); $m->SetParam("notify", $ourcallid); $m->Dispatch(); } else { $done = true; } }
function setState($newstate) { global $ourcallid; global $partycallid; global $answer; global $state; global $vm_base; global $mailbox; global $user; global $file; // are we exiting? if ($state == "") { return; } Yate::Debug("setState('{$newstate}') state: {$state}"); if ($newstate == $state) { return; } switch ($newstate) { case "novmail": /* Play the prompt in early media, don't answer call */ $m = new Yate("chan.attach"); $m->params["source"] = "wave/play/{$vm_base}/novmail.slin"; $m->params["notify"] = $ourcallid; $m->params["action"] = "progress"; $m->Dispatch(); break; case "greeting": $m = new Yate("chan.attach"); if (is_file("{$user}/greeting.slin")) { $m->params["source"] = "wave/play/{$user}/greeting.slin"; } else { $m->params["source"] = "wave/play/{$vm_base}/greeting.slin"; } $m->params["notify"] = $ourcallid; $m->params["action"] = $answer ? "answer" : "progress"; $m->Dispatch(); break; case "beep": $m = new Yate("chan.attach"); $m->params["source"] = "wave/play/{$vm_base}/beep.slin"; $m->params["notify"] = $ourcallid; $m->params["action"] = "answer"; $m->Dispatch(); /* Answer the call at this point if not answered earlier */ sendAnswer(); break; case "record": $m = new Yate("chan.attach"); $m->params["source"] = "wave/play/-"; $m->params["consumer"] = "wave/record/{$user}/{$file}"; $m->params["maxlen"] = 160000; $m->params["notify"] = $ourcallid; $m->Dispatch(); $m = new Yate("user.update"); $m->id = ""; $m->params["user"] = $mailbox; $m->Dispatch(); break; case "goodbye": $m = new Yate("chan.attach"); $m->params["source"] = "tone/congestion"; $m->params["consumer"] = "wave/record/-"; $m->params["maxlen"] = 32000; $m->params["notify"] = $ourcallid; $m->Dispatch(); break; } $state = $newstate; }
/** * Emit a DTMF to the other end * @param $dtmf DTMF tones to play * @param $method Method to emit the DTMF, null to use technology default */ function PlayDTMF($dtmf, $method = null) { $m = new Yate("chan.dtmf"); $m->id = ""; $m->SetParam("id", IVR::ChannelID()); $m->SetParam("targetid", IVR::TargetID()); $m->SetParam("text", $dtmf); if ($method !== null) { $m->SetParam("method", $method); } $m->Dispatch(); }
function endRoute($callto, $ok, $err, $params) { global $partycallid; global $collect; global $final; global $queue; global $routeOnly; global $state; if ($ok && $callto != "-" && $callto != "error") { Yate::Output("Overlapped got route: '{$callto}' for '{$collect}'"); $m = new Yate("chan.masquerade"); $m->params = $params; $m->params["message"] = "call.execute"; $m->params["complete_minimal"] = true; $m->params["id"] = $partycallid; $m->params["callto"] = $callto; $m->Dispatch(); if (strlen($queue)) { // Masquerade the remaining digits // TODO: wait for call.execute to be processed to do that? $d = new Yate("chan.masquerade"); $d->params["message"] = "chan.dtmf"; $d->params["id"] = $partycallid; $d->params["tone"] = $queue; $d->Dispatch(); } return; } if ($final) { Yate::Output("Overlapped got final error '{$err}' for '{$collect}'"); Yate::SetLocal("reason", $err); setState(""); } else { if ($err != "incomplete") { Yate::Output("Overlapped got error '{$err}' for '{$collect}'"); Yate::SetLocal("reason", $err); setState(""); $final = true; } else { Yate::Debug("Overlapped still incomplete: '{$collect}'"); if ($routeOnly) { setState("noroute"); } else { // Don't use setState: we don't want to change the prompt $state = "prompt"; } // Check if got some other digits if ($queue != "") { gotDTMF(""); } } } }
function checkPass() { global $collect_user; global $collect_pass; if ($collect_pass == "") { setState("goodbye"); } else { setState("auth"); $m = new Yate("user.auth"); $m->params["username"] = $collect_user; $m->Dispatch(); } }
function endRoute($callto, $ok, $err) { global $partycallid; global $num; global $collect; if ($ok) { Yate::Output("Overlapped got route: '{$callto}' for '{$collect}'"); $m = new Yate("chan.masquerade"); $m->params["message"] = "call.execute"; $m->params["id"] = $partycallid; $m->params["callto"] = $callto; $m->params["caller"] = $num; $m->params["called"] = $collect; $m->Dispatch(); return; } if ($err != "incomplete") { setState("noroute"); } else { Yate::Output("Overlapped still incomplete: '{$collect}'"); } }
function setState($newstate) { global $ourcallid; global $partycallid; global $state; global $uploaded_prompts; global $keys; global $wait_time; global $caller; global $hold_keys; global $destination; global $called; global $ev; // are we exiting? if ($state == "") { return; } debug("setState('{$newstate}') state: {$state}"); $state = $newstate; // always obey a return to prompt switch ($newstate) { case "greeting": // check what prompt to use for this time of day //$query = "select prompts.prompt_id, prompts.file as prompt from time_frames, prompts /*where numeric_day=extract(dow from now()) and cast(start_hour as integer)<=extract(HOUR FROM now()) AND cast(end_hour as integer)>extract(HOUR FROM now()) and time_frames.prompt_id=prompts.prompt_id*/ UNION select prompt_id, file as prompt from prompts where status='online'"; $status = 'offline'; $query = "select prompt_id, day, start_hour, end_hour, numeric_day FROM time_frames"; $res = query_to_array($query); if (count($res)) { $day_week = date('w'); $hour = date('H') * 1; debug("Current week index '{$day_week}' : hour '{$hour}'"); //$day_week = 2; //$hour = 12; $status = 'offline'; foreach ($res as $row) { if ($row["numeric_day"] == $day_week && $row["start_hour"] <= $hour && $hour < $row["end_hour"]) { $hold_keys = ''; // Reset default key $status = 'online'; } } } $query = "select prompts.prompt_id, prompts.file as prompt from prompts where status='{$status}'"; $res = query_to_array($query); debug('greeting:' . format_array($res)); if (!count($res)) { debug("Auto-Attendant is not configured!!"); setState("goodbye"); return; } $prompt_id = $res[0]["prompt_id"]; $prompt = $res[0]["prompt"]; // here we must have ".au" //$prompt = str_ireplace(".mp3", ".slin", $prompt); $query = "SELECT keys.key, destination FROM `keys` WHERE prompt_id={$prompt_id}"; $keys = query_to_array($query); debug('keys:' . format_array($keys)); $m = new Yate("chan.attach"); // ------------------------ /* prompt based on called */ $prompt_file = "{$uploaded_prompts}/auto_attendant/{$prompt}"; //debug('source[called]:<' . $prompt_file.".".$called.">"); if (file_exists($prompt_file . "." . $called)) { $prompt_file = $prompt_file . "." . $called; } $m->params["source"] = "wave/play/{$prompt_file}"; debug('source:' . "wave/play/{$prompt_file}"); // ------------------------ /* $m->params["source"] = "wave/play/$uploaded_prompts/auto_attendant/$prompt"; debug('source:' . "wave/play/$uploaded_prompts/auto_attendant/$prompt"); */ $m->params["notify"] = $ourcallid; $m->Dispatch(); break; case "prolong_greeting": $m = new Yate("chan.attach"); $m->params["consumer"] = "wave/record/-"; $m->params["notify"] = $ourcallid; $m->params["maxlen"] = $wait_time * 10000; $m->Dispatch(); break; case "goodbye": $m = new Yate("chan.attach"); $m->params["source"] = "tone/congestion"; $m->params["consumer"] = "wave/record/-"; $m->params["maxlen"] = 32000; $m->params["notify"] = $ourcallid; $m->Dispatch(); break; case "call.route": $to_call = null; debug('$keys = ' . $keys); for ($i = 0; $i < count($keys); $i++) { if ($keys[$i]["key"] == $hold_keys) { $to_call = $keys[$i]["destination"]; //$hold_keys = null; break; } } if ($hold_keys == '') { debug('$called = ' . $called); $query = "SELECT (CASE WHEN extension_id IS NOT NULL THEN (SELECT extension FROM extensions WHERE extensions.extension_id=dids.extension_id) ELSE (SELECT extension FROM groups WHERE groups.group_id=dids.group_id) END) as called FROM dids WHERE number='{$called}'"; $res = query_to_array($query); if (!count($res) || !strlen($res[0]["called"])) { // this should never happen setState("goodbye"); return; } $to_call = $res[0]["called"]; } if (!$to_call) { $to_call = $hold_keys; } $m = new Yate("call.route"); $m->params["caller"] = $caller; $m->params["called"] = $to_call; $m->params["id"] = $ourcallid; $m->params["already-auth"] = "yes"; $m->params["call_type"] = "from outside"; $m->Dispatch(); break; case "send_call": $m = new Yate("chan.masquerade"); $m->params = $ev->params; $m->params["message"] = "call.execute"; $m->params["id"] = $partycallid; $m->params["callto"] = $destination; $m->Dispatch(); break; } }