/** * agi_call - place a call on asterisk server. * * It executes Dial($callStr...) and add support for prepay system * * PRE : * if the destination is a local destinatin, this destination exist * * $extension: only use for logging purpose * * $callStr, destination for Dial application of asterisk * * $callOptions << !!!!!!!!!! USE THIS WITH CARE !!!!!!!! * * $priceConn connection price >= 0 * * $price the price/minutes of the call >= 0 * * $callerId a the callerId (only the number) * * $callerIdFull : full callerId * * logIfFailed : if the function have to log a call even if it failed. * * * POST : * call is logged * * prepay card of the callerId is updated if the call succeed * ^ if the call is not free * * if the callerId is not a person, it checks for a owner * of the callerId in the database and use his prepaid card * * return the price of the call * * $call->set_lastTryStatus with the return status of Application Dial * in case of 'not enough of money' : "MONEY' */ function agi_call(&$call, $callStr, $callOptions, $priceConn, $price, $logIfFailed = true) { global $db; $extension = $call->get_extension(); $callerId = $call->get_cid(); $callerIdFull = $call->get_cidFull(); $account = $call->get_responsable(); agi_log(DEBUG_DEBUG, "agi_call : {$callStr}, {$priceConn}, " . "{$price}, {$callerId}, {$callerIdFull}"); // first I check if the callerId is a valid person in the database $query = "select P.Credit, P.Announce, P.AskHigherCost, " . "\tP.AllowOtherCID " . " from People_PrePay_Settings as P " . " where People_Extension = {$account}"; $query = $db->query($query); check_db($query); if (!($row = $query->fetchRow(DB_FETCHMODE_ORDERED)) or $account != $callerId and !$row[3]) { // introuvable ou le responsable qui ne prend pas en charge $found = false; $credit = 0; $announce = false; $ask = false; } else { $found = true; $credit = $row[0]; $announce = $row[1]; $ask = $row[2]; } if ($price + $priceConn > $credit) { agi_log(DEBUG_INFO, "agi_call(): not enough money"); agi_play_soundSet(SOUNDSET_NOT_ENOUGH_MONEY, ""); $call->set_lastTryStatus("MONEY"); if ($logIfFailed) { agi_logCall($call, $price, 0, "MONEY"); } return -1; } // bon on a assez de soux que pour faire l'appel.... on dial if ($price == 0) { agi_write("EXEC DIAL {$callStr}||{$callOptions}", true); } else { $maxSec = ($credit - $priceConn) / $price * 60 * 1000; agi_write("EXEC DIAL {$callStr}||{$callOptions}L({$maxSec})", true); } $answeredTime = agi_getVar("ANSWEREDTIME"); $dialStatus = agi_getVar("DIALSTATUS"); $call->set_lastTryStatus($dialStatus); agi_log(DEBUG_INFO, "agi_dial : {$extension} -> {$callStr} " . ": {$dialStatus} : {$answeredTime}"); $total = $priceConn + ceil($answeredTime / 60) * $price; if ($dialStatus == "ANSWER") { agi_logCall($call, $price, $answeredTime, $dialStatus); agi_credit($account, -$total); } else { if ($logIfFailed) { agi_logCall($call, $price, $answeredTime, $dialStatus); } } return $total; }
function outside_dial(&$call) { global $db; // 1°) trouver à quel réseau appartient l'extension $net = outside_getNetworkId($call); agi_log(DEBUG_DEBUG, 'outside_dial() : ' . $call->get_extension() . " -> {$net}"); if ($net < 0) { return agi_notFound($call); } // 2°) faut-il annoncer le prix à l'utilisateur ? // faut-il continuer plus cher ? $query = "select P.Announce, P.AskHigherCost " . " from People_PrePay_Settings as P " . " where People_Extension = " . $call->get_responsable(); $query = $db->query($query); check_db($query); if (!($row = $query->fetchRow(DB_FETCHMODE_ORDERED))) { // not found : paramètre par défaut : $askHigher = false; $announce = true; agi_log(DEBUG_INFO, "outside_dial() : account not found"); } else { $askHigher = $row[1]; $announce = $row[0]; } agi_log(DEBUG_DEBUG, "outside_dial() : {$announce} - {$askHigher}"); // 3°) récupérer la liste des providers et leur prix $query = "select N.Name, N.channel, P.ConnectionPrice, P.Price, " . " P.RmDigits, P.AddDigits, N.DialOpts " . " from NetworkProvider as N, Price as P, " . "\t NetworkTimeZone_details as T " . " where P.Network_ID = {$net} " . " and P.NetworkProvider_ID = N.ID " . " and P.NetworkTimeZone_ID = T.NetworkTimeZone_ID " . " and (" . date("i") . " between start_min and end_min )" . " and (" . date("G") . " between start_hour and end_hour )" . " and (" . date("n") . " between start_month and end_month )" . " and (" . date("j") . " between start_dom and end_dom )" . " and (" . date("w") . " between start_dow and end_dow )" . " order by P.Price, P.ConnectionPrice "; $query = $db->query($query); check_db($query); /* 0 : name * 1 : channel * 2 : priceConn * 3 : price/min * 4 : RmDigits * 5 : AddDigits * 6 : DialOpts */ if ($query->numRows() == 0) { return agi_notFound($call); } $provider = $query->fetchRow(DB_FETCHMODE_ORDERED); // 4°) on tente d'appeler $isFirst = true; // première tentative au prix le plus bas while (($isFirst || $askHigher) && $provider != NULL) { $price = $provider[3]; // 5°) on annonce au besoin : if ($announce) { agi_play_soundSet(SOUNDSET_PRICE_ANNOUNCE, ""); agi_sayNumber(ceil($price * 100)); agi_play_soundSet(SOUNDSET_CURRENCY, ""); } // on teste l'un à la suite de l'autre tout les providers // qui ont le même prix d'appel while ($provider[3] == $price && $provider != NULL) { $callStr = $provider[1] . $provider[5] . substr($call->get_extension(), $provider[4]); agi_log(DEBUG_DEBUG, "outside_dial() : trying : {$callStr}"); $result = agi_call($call, $callStr, $provider[6], $provider[2], $provider[3], false); if ($result >= 0 || $call->get_lastTryStatus() != "CHANUNAVIL") { // succeed return $result; } $provider = $query->fetchRow(DB_FETCHMODE_ORDERED); } // annonce qu'il est impossible d'effectuer l'appel au prix // annoncé précédement agi_play_soundSet(SOUNDSET_UNAVAIL_AT_PRICE, ""); $first = false; // téléchargement du provider suivant $provider = $query->fetchRow(DB_FETCHMODE_ORDERED); } agi_logCall($call, 0, 0, "NOT ROUTABLE"); return -1; }