This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
khosb/modules/voip/voip.inc.php

2142 lines
68 KiB
PHP
Raw Normal View History

<?php
/**
* AgileBill - Open Billing Software
*
* This body of work is free software; you can redistribute it and/or
* modify it under the terms of the Open AgileBill License
* License as published at http://www.agileco.com/agilebill/license1-4.txt
*
* For questions, help, comments, discussion, etc., please join the
* Agileco community forums at http://forum.agileco.com/
*
* @link http://www.agileco.com/
* @copyright 2004-2008 Agileco, LLC.
* @license http://www.agileco.com/agilebill/license1-4.txt
* @author Tony Landis <tony@agileco.com> and Thralling Penguin, LLC <http://www.thrallingpenguin.com>
* @package AgileBill
* @version 1.4.93
*/
class didArea
{
var $cc;
var $data;
function didArea($cc = 1, $data = false)
{
$this->cc = $cc;
$this->data = $data;
}
function determineArea($cc, $number)
{
$db =& DB();
switch($cc) {
case 1:
/* usa - return the npa,nxx */
return substr($number,0,6);
default:
$sql = "SELECT locName, npa FROM ".AGILE_DB_PREFIX."voip_npa_nxx
WHERE country_code=".$db->qstr($cc)." ORDER BY length(npa) desc";
$rs = $db->Execute($sql);
if($rs && $rs->RecordCount()) {
while(!$rs->EOF) {
if(strncmp($rs->fields['npa'],$number,strlen($rs->fields['npa']))==0) {
return $rs->fields['npa'];
}
$rs->MoveNext();
}
return false;
} else {
return false;
}
}
}
function getName()
{
return $this->data['locName'];
}
function getState()
{
return $this->data['locState'];
}
function getAreacode()
{
return $this->data['areacode'];
}
function getNpa()
{
return $this->data['npa'];
}
function getNxx()
{
return $this->data['nxx'];
}
function getStations($plugins)
{
// $data['areacode'] or $data['npa']+$data['nxx']
$p = AGILE_DB_PREFIX;
$db =& DB();
$pre = "";
if($this->data['country_code'] == 1) {
$sql = "select distinct A.country_code,A.npa,A.nxx,A.station
FROM {$p}voip_pool AS A
left join {$p}voip_npa_nxx AS B
on (A.npa=B.npa and A.nxx=B.nxx AND B.country_code='1')
WHERE (A.account_id IS NULL OR A.account_id = 0)
AND (A.date_reserved IS NULL OR A.date_reserved = 0)
AND A.npa = " . $db->qstr($this->data['npa']) . "
AND A.nxx = " . $db->qstr($this->data['nxx']) . "
AND A.voip_did_plugin_id in (".join(",",$plugins).")
AND A.site_id=".DEFAULT_SITE."
LIMIT 0,50";
} else {
$sql = "select distinct A.country_code,A.areacode as npa,A.nxx,A.station
FROM {$p}voip_pool AS A
left join {$p}voip_npa_nxx AS B
on (A.areacode=B.npa AND B.country_code=".$db->qstr($this->data['country_code']).")
WHERE (A.account_id IS NULL OR A.account_id = 0)
AND (A.date_reserved IS NULL OR A.date_reserved = 0)
AND A.areacode = " . $db->qstr($this->data['areacode']) . "
AND A.voip_did_plugin_id in (".join(",",$plugins).")
AND A.site_id=".DEFAULT_SITE."
LIMIT 0,50";
$pre = "011";
}
#echo "document.write('".str_replace("'","\\'",str_replace("\n","",$sql))."');"; return;
$rs = $db->Execute($sql);
if($rs && $rs->RecordCount()) {
$i = 0;
while(!$rs->EOF) {
if ($rs->fields['country_code'] == '1') {
$dids[$i][0] = $pre.$rs->fields['country_code'].$rs->fields['npa'].$rs->fields['nxx'].$rs->fields['station'];
$dids[$i++][1] = $rs->fields['country_code']." ".$rs->fields['npa'].$rs->fields['nxx'].$rs->fields['station'];
} else {
$dids[$i][0] = $pre.$rs->fields['country_code'].$rs->fields['station'];
$dids[$i++][1] = $rs->fields['country_code']." ".$rs->fields['station'];
}
$rs->MoveNext();
}
return $dids;
}
syslog(LOG_INFO,$db->ErrorMsg()." -> ".$sql);
return false;
}
}
class didAreas
{
var $data, $cc;
function didAreas($cc, $plugins = false)
{
$this->cc = $cc;
$p = AGILE_DB_PREFIX;
$db =& DB();
if($cc!=1) {
$sql = "select distinct A.areacode,B.locName
from {$p}voip_pool AS A
inner join {$p}voip_npa_nxx AS B
on (A.areacode=B.npa and A.country_code=".$db->qstr($cc)." AND
B.country_code=".$db->qstr($cc).")
WHERE (A.account_id IS NULL OR A.account_id = 0) AND
(A.date_reserved IS NULL OR A.date_reserved = 0) AND ";
if(is_array($plugins))
$sql .= "A.voip_did_plugin_id in (".join(",",$plugins).") AND ";
$sql .= "A.site_id=".DEFAULT_SITE." ORDER BY B.locName";
} else {
$sql = "select distinct A.npa,A.nxx,B.locName,B.locState from {$p}voip_pool AS A inner join {$p}voip_npa_nxx AS B on
(A.npa=B.npa and A.nxx=B.nxx and B.country_code='1')
WHERE (A.account_id IS NULL OR A.account_id = 0) AND
(A.date_reserved IS NULL OR A.date_reserved = 0) AND ";
if(is_array($plugins))
$sql .= "A.voip_did_plugin_id in (".join(",",$plugins).") AND ";
$sql .= "A.site_id=".DEFAULT_SITE." ORDER BY B.locName";
}
# echo "document.write('".str_replace("'","\\'",str_replace("\n","",$sql))."');";
$rs = $db->Execute($sql);
if($rs && $rs->RecordCount()) {
while(!$rs->EOF) {
$this->data[] = $rs->fields;
$rs->MoveNext();
}
}
}
function getArea()
{
if(!is_array($this->data)) return false;
$row = each($this->data);
if($row === false) { reset($this->data); return false; }
return new didArea($this->cc, $row[1]);
}
}
class didCountry
{
var $data;
function didCountry($row)
{
$this->data = $row;
}
function getAreas($plugin = false)
{
return new didAreas($this->data['country_code'],$plugin);
}
function getCode()
{
return $this->data['country_code'];
}
function getName()
{
return $this->data['name'];
}
}
class didCountries
{
var $data;
var $did_plugin_ids;
function didCountries($pluginArray)
{
$this->did_plugin_ids = $pluginArray;
$p = AGILE_DB_PREFIX;
$db =& DB();
$sql = "select distinct a.country_code,c.id,c.code,c.name from {$p}voip_pool as b
left join {$p}voip_iso_country_code_map as a on (a.country_code=b.country_code)
left join {$p}voip_iso_country_code as c on (a.iso_country_code=c.code)
where (account_id IS NULL or account_id=0)
and (b.date_reserved IS NULL or b.date_reserved = 0 )
and c.site_id=".DEFAULT_SITE." AND b.site_id=".DEFAULT_SITE." and a.site_id=".DEFAULT_SITE;
$rs = $db->Execute($sql);
if($rs && $rs->RecordCount()) {
while(!$rs->EOF) {
$this->data[] = $rs->fields;
$rs->MoveNext();
}
}
#echo "<pre>".print_r($this->data,true)."</pre>";
reset($this->data);
}
function getCountry()
{
$row = each($this->data);
if($row === false) { reset($this->data); return false; }
return new didCountry($row[1]);
}
}
class DateFunc {
function day_of_week( $m, $d, $y ) {
// Calculate the day of the week, with sat. starting it
$r = date('w',mktime(0,0,0,$m,$d,$y));
// As r stands above, sun=0 sat=6
$r = $r + 1;
if( $r > 6 )
$r = 0;
// now sun=6 sat=0
return $r;
}
function dow( $m, $d, $y ) {
$a = $this->day_of_week( $m, $d, $y );
switch( $a ) {
case 0:
return "SA";
case 1:
return "SU";
case 2:
return "MO";
case 3:
return "TU";
case 4:
return "WE";
case 5:
return "TH";
case 6:
return "FR";
}
}
function week_of_year( $m, $d, $y ) {
// Calculate the week of the year, using Saturdays...
$day = date('z',mktime(0,0,0,$m,$d,$y) ) + 1;
$wday= $this->day_of_week($m,$d,$y) + 1;
$week = 0;
while( $day > 0 ) {
$wday = $wday - 1;
$day = $day - 1;
if( $wday < 0 ) {
$wday = $wday + 7;
$week = $week + 1;
}
}
return $week;
}
function get_range_begin( $m, $d, $y ) {
// First valid date in the week (always a Sat)
return mktime(0,0,0,$m,($d+(6-$this->day_of_week($m,$d,$y)))-6,$y);
}
function get_range_end( $m, $d, $y ) {
// End valid date in a week (always a Fri)
return mktime(0,0,0,$m,($d+(6-$this->day_of_week($m,$d,$y))),$y);
}
function getWeekArray() {
$cwn = $this->week_of_year(date('m'),date('d'),date('Y'));
$ts = mktime(0,0,0,date('m'),date('d'),date('Y'));
$n = 0;
for( $i=$cwn; $n<16; $i-- ) {
$j = $i;
if( $j > 52 )
$j = abs(53 - $j) + 1;
else if( $j < 1 )
$j = 53 + $j;
$ret[$n]['text'] = "Week #$j " . date(UNIX_DATE_FORMAT,$this->get_range_begin(date('m',$ts),date('d',$ts),date('Y',$ts))) . " through " . date(UNIX_DATE_FORMAT,$this->get_range_end(date('m',$ts),date('d',$ts),date('Y',$ts)));
$ret[$n]['begin'] = $this->get_range_begin(date('m',$ts),date('d',$ts),date('Y',$ts));
$ret[$n]['end'] = $this->get_range_end(date('m',$ts),date('d',$ts),date('Y',$ts));
$ret[$n]['week'] = $j;
$n++;
$ts = $ts - (86400 * 7);
}
return $ret;
}
function getNumberOfDays($date1, $date2) {
# Correct parameters if needed.
if($date2<$date1) {
$tmp = $date1;
$date1 = $date2;
$date2 = $tmp;
}
# Get the year, month, day values of the two dates
#$d1[0] = date('Y',$date1); #substr($date1,0,4);
#$d1[1] = date('m',$date1); #substr($date1,4,2);
#$d1[2] = date('d',$date1); #substr($date1,6,2);
#$d2[0] = date('Y',$date2); #substr($date2,0,4);
#$d2[1] = date('m',$date2); #substr($date2,4,2);
#$d2[2] = date('d',$date2); #substr($date2,6,2);
# Construct UNIX timestamps based on the original dates
$date1 = mktime(0,0,0, date('m',$date1), date('d',$date1), date('Y',$date1));
$date2 = mktime(0,0,0, date('m',$date2), date('d',$date2), date('Y',$date2));
#print "date1=".date('Ymd',$date1)."<br>date2=".date('Ymd',$date2)."<br>"; exit;
$tmp = $date1;
$y = date('Y',$date1);
$m = date('m',$date1);
$d = date('d',$date1);
$days = 0;
# Increments $tmp one day at a time until it matches $date2
while ($tmp != $date2) {
$d++;
$tmp = mktime(0,0,0, date($m), date($d), date($y));
$days++;
#echo "tmp=$tmp date2=$date2 m=$m d=$d y=$y<br>";
#if($d>30) break;
} # while
# Returns the number of increments for the dates to match
return $days;
}
}
class voip
{
var $voip_intrastate;
var $voip_default_prefix;
var $perform_normalization;
var $normalization_min_len;
/**
* Handle the click to call feature. This is complex as apache/php runs as wwwadmin, so this may need an additional layer
* to allow asterisk to receive the call file as owner root.
*/
function place_call($VAR)
{
global $C_debug;
# gimmie temp file
$file = tempnam("/tmp","clicktocall-").".call";
$C_debug->alert("Placing Call, please answer your phone when it rings and the call will then be completed.");
$fp = fopen($file, "w");
fwrite($fp,"Channel: ".$VAR['voip_from']."\n");
fwrite($fp,"MaxRetries: 0\n");
fwrite($fp,"RetryTime: 60\n");
fwrite($fp,"WaitTime: 20\n");
fwrite($fp,"Callerid: \"Click to Crash\" <".$VAR['voip_callerid'].">\n");
fwrite($fp,"Context: international\n");
fwrite($fp,"Extension: ".$VAR['voip_to']."\n");
fwrite($fp,"Priority: 1\n");
fclose($fp);
chmod($file,0777);
system("mv -f ".escapeshellarg($file)." /var/spool/asterisk/outgoing/");
}
/**
* Given a country code and possible NPA/NXX, determine where in the world we're at.
*/
function where_is(&$db, $countrycode, $npa, $nxx)
{
if ($countrycode == 1) {
# We are in the USA, use npa/nxx lookup
if ($npa == "800" || $npa == "866" || $npa == "877" || $npa == "888")
return "Toll-free";
$rs =& $db->Execute("SELECT locName, locState FROM ".AGILE_DB_PREFIX."voip_npa_nxx WHERE country_code='1' and npa=".$db->qstr($npa)." and nxx=".$db->qstr($nxx));
if ($rs && $rs->RecordCount())
return $rs->fields[0].", ".$rs->fields[1];
else
return "Unknown";
} else {
/*
mysql> describe ab_voip_iso_country_code_map;
+------------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------+-------------+------+-----+---------+-------+
| id | int(11) | | PRI | 0 | |
| country_code | varchar(16) | | MUL | | |
| iso_country_code | char(3) | | | | |
| iso_sub_code | char(3) | | | | |
+------------------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
mysql> describe ab_voip_iso_country_code;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | | PRI | 0 | |
| code | char(3) | | UNI | | |
| name | varchar(64) | | | | |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
*/
$sql = "SELECT b.name FROM ".AGILE_DB_PREFIX."voip_iso_country_code_map a left join ".AGILE_DB_PREFIX."voip_iso_country_code b
on (a.iso_country_code=b.code)
WHERE a.country_code like ".$db->qstr($countrycode."%");
$rs =& $db->Execute($sql);
if ($rs && $rs->RecordCount())
return $rs->fields[0];
else return "Unknown";
}
return "Unknown";
}
/**
* Given a DID, returns the e.164 representation and the country code with possible npa/nxx if USA. If successful,
* a true is returned, otherwise false is returned.
*
* @param $number Input telephone number
* @param $e164 Output cleaned number in E.164 format
* @param $countrycode Output country code designator
* @param $npa Output NPA code if USA country
* @param $nxx Output NXX code if USA country
*/
function e164($number, &$e164, &$countrycode, &$npa, &$nxx)
{
if(function_exists('agileco_e164')) {
if(($r = agileco_e164($number,$this->voip_default_prefix)) === false)
return false;
$e164 = $r['e164'];
$countrycode = $r['country_code'];
$npa = $r['npa'];
$nxx = $r['nxx'];
#echo "<pre>".print_r($r, true)."</pre>";
return true;
}
$e164 = ""; $countrycode = ""; $npa = ""; $nxx = "";
if (preg_match("/[a-zA-Z]/",$number)) return false;
if (!strncmp($number, "+", 1)) {
# if the number has a leading plus, strip it.
$number = substr($number,1);
}
if (strlen($number) == 7) {
# USA local dialing, need to prefix the country code and local npa
$e164 = "+1".$this->voip_default_prefix.$number;
}
if (!strncmp($number, "0111", 4)) {
# Screwed up USA call, strip the international prefixing
$e164 = "+".substr($number, 3);
}
/* UK Specific hack */
if (!strncmp($number, "44", 2)) {
$e164 = "+011".$number;
}
if (!strncmp($number, "0", 1) && strlen($number) == 11) {
$e164 = "+01144".$number;
}
/* End UK Specific hack */
if (strlen($number) == 10 && strncmp($number,"011",3)) {
# USA Call without the country code selection
$e164 = "+1".$number;
}
if ($e164 == "") {
$e164 = "+".$number;
}
# ok, cleaned the number. Now, what's the country code?
if (!strncmp($e164, "+011", 4)) {
# international
$countrycode = $this->parse_country_code($e164);
} else {
# USA
$countrycode = "1";
$npa = substr($e164, 2, 3);
$nxx = substr($e164, 5, 3);
}
if (strlen($countrycode) && strlen($number))
return true;
return false;
}
/**
* Parses the E.164 number for a correct country code. NOTE: Doesn't handle the USA right. Returns the country code.
* Example: +011xxxxxxx
*/
function parse_country_code($e164)
{
if(function_exists('agileco_parse_country_code')) {
#echo 'calling agileco_parse_country_code!<br>';
return agileco_parse_country_code($e164);
}
$numdigs = 2;
$d1 = substr($e164, 4, 1);
$d2 = substr($e164, 5, 1);
switch ($d1) {
case '1':
case '7':
$numdigs = 1;
break;
case '2':
if ($d2 != '0' && $d2 != '7') {
$numdigs = 3;
}
break;
case '3':
if ($d2 == '5' || $d2 == '7' || $d2 == '8') {
$numdigs = 3;
}
break;
case '4':
if ($d2 == '2') {
$numdigs = 3;
}
break;
case '5':
if ($d2 == '0' || $d2 == '9') {
$numdigs = 3;
}
break;
case '6':
if ($d2 >= 7) {
$numdigs = 3;
}
break;
case '8':
if ($d2 == '0' || $d2 == '3' || $d2 == '5' || $d2 == '7') {
$numdigs = 3;
}
break;
case '9':
if ($d2 == '6' || $d2 == '7' || $d2 == '9') {
$numdigs = 3;
}
break;
default:
$numdigs = 0;
break;
}
if ($d2<0 || $d2>9) {
$numdigs = 0;
} else {
if (strlen($e164) < $numdigs) {
$numdigs = 0;
}
}
if ($numdigs) {
return substr($e164, 4, $numdigs);
}
return "";
}
/**
* Get the activity for the week needed
*/
function activity($VAR) {
global $smarty;
$fdids = $this->get_fax_dids(SESS_ACCOUNT);
$dt = new DateFunc;
if (empty($VAR['wnum']))
$wnum = $dt->week_of_year(date('m'),date('d'),date('Y'));
else
$wnum = $VAR['wnum'];
$smarty->assign('wnum',$wnum);
$weeks = $dt->getWeekArray();
$wtext[] = "-- Please Select --";
foreach ($weeks as $w) {
$wtext[$w['week']] = $w['text'];
if ($w['week'] == $wnum) {
$b = $w['begin'];
$e = $w['end']; $e+=86400;
}
}
$smarty->assign('weeks', $wtext);
$db=&DB();
$p=AGILE_DB_PREFIX;
// get dids
$sql_in='';
$sql_out='';
$dids = $this->get_all_dids(SESS_ACCOUNT);
$dids = $this->normalize_dids($dids);
if(count($dids)>0) {
foreach($dids as $did) {
if($sql_in!='') {
$sql_in .= ' OR ';
$sql_out .= ' OR ';
}
$sql_in .= " dst = $did ";
$sql_out .= " src = $did ";
if(strncmp($did,"1",1) && strncmp($did,"0",1)) {
$sql_in .= " OR dst = ".$db->qstr("1".$did)." ";
$sql_out .= " OR src = ".$db->qstr("1".$did)." ";
}
}
} else {
$rs =& $db->Execute(sqlSelect($db,"account","username","id=".SESS_ACCOUNT));
$sql_out = "accountcode=::".$rs->fields[0]."::";
}
# gather prepaid account pins
$pins = array();
$rs =& $db->Execute(sqlSelect($db,"voip_prepaid","pin","account_id=".SESS_ACCOUNT));
while ($rs && !$rs->EOF) {
$pins[] = $rs->fields[0];
$rs->MoveNext();
}
foreach ($pins as $pin) {
if ($sql_out!='') {
$sql_out .= ' OR ';
}
if ($sql_in!='') {
$sql_in .= ' OR ';
}
$sql_out .= " accountcode=::cc:".$pin.":: ";
$sql_in .= " dst = ::".$pin.":: ";
}
# Get currency
$rs =& $db->Execute($sql=sqlSelect($db,"currency","symbol","id=".DEFAULT_CURRENCY));
$smarty->assign('currency', $rs->fields[0]);
# Get last 25 incoming:
$rs =& $db->Execute(sqlSelect($db,"voip_cdr","date_orig, clid, src, dst, ceiling(duration/60) as duration, amount, lastapp"," ( $sql_in ) AND (lastapp='Dial' or lastapp='VoiceMail' or lastapp='MeetMe' or lastapp='Hangup') AND disposition='ANSWERED' AND account_id = ".SESS_ACCOUNT." AND date_orig>=$b AND date_orig<=$e","date_orig DESC"));
if($rs && $rs->RecordCount() > 0) {
$i = 0;
while(!$rs->EOF) {
$in[$i]=$rs->fields;
if (strcasecmp($rs->fields['lastapp'], 'VoiceMail') == 0)
$in[$i]['type'] = 'v';
else if (in_array($rs->fields['dst'], $fdids))
$in[$i]['type'] = 'f';
$cc = ""; $npa = ""; $nxx = ""; $e164 = "";
if ($this->e164($rs->fields['src'], $e164, $cc, $npa, $nxx)) {
$in[$i]['location'] = $this->where_is($db, $cc, $npa, $nxx);
}
$i++;
$rs->MoveNext();
}
}
# Get last 25 outgoing:
$rs =& $db->Execute($sql = sqlSelect($db,"voip_cdr","date_orig, clid, dst, ceiling(duration/60) as duration, amount, lastapp"," ( $sql_out ) AND (lastapp='Dial' or lastapp='VoiceMail' or lastapp='MeetMe' or lastapp='Hangup') AND disposition='ANSWERED' AND account_id = ".SESS_ACCOUNT." AND date_orig>=$b AND date_orig<=$e","date_orig DESC"));
if($rs && $rs->RecordCount() > 0) {
$i = 0;
while(!$rs->EOF) {
$out[$i]=$rs->fields;
if (strcasecmp($rs->fields['lastapp'], 'VoiceMail') == 0)
$out[$i]['type'] = 'v';
foreach ($pins as $pin) {
if (strcmp($rs->fields['accountcode'], "cc:".$pin)==0) {
$out[$i]['type'] = 'c';
}
}
$cc = ""; $npa = ""; $nxx = ""; $e164 = "";
if ($this->e164($rs->fields['dst'], $e164, $cc, $npa, $nxx)) {
$out[$i]['location'] = $this->where_is($db, $cc, $npa, $nxx);
}
$i++;
$rs->MoveNext();
}
}
$smarty->assign('in', $in);
$smarty->assign('out', $out);
}
function normalize_dids($dids)
{
foreach($dids as $did) {
$out[] = $did;
if(!strncmp($did,"011",3))
$out[] = substr($did,3);
if(!strncmp($did,"1",1))
$out[] = substr($did,1);
}
return $out;
}
/**
* Get the last 25 placed and received calls for the user
* @todo Get some call statistics daily/weekly/monthly for the user
*/
function overview($VAR) {
global $smarty;
// validate logged in
if(!SESS_LOGGED) return false;
$fdids = $this->get_fax_dids(SESS_ACCOUNT);
// get dids
$sql_in='';
$sql_out='';
$dids = $this->get_all_dids(SESS_ACCOUNT);
$dids = $this->normalize_dids($dids);
$db=&DB();
$p=AGILE_DB_PREFIX;
if(count($dids)>0) {
foreach($dids as $did) {
if($sql_in!='') {
$sql_in .= ' OR ';
$sql_out .= ' OR ';
}
$sql_in .= " dst = ".$db->qstr($did)." ";
$sql_out .= " src = ".$db->qstr($did)." ";
if(strncmp($did,"1",1) && strncmp($did,"0",1)) {
$sql_in .= " OR dst = ".$db->qstr("1".$did)." ";
$sql_out .= " OR src = ".$db->qstr("1".$did)." ";
}
}
} else {
$rs =& $db->Execute(sqlSelect($db,"account","username","id=".SESS_ACCOUNT));
$sql_out = "accountcode=::".$rs->fields[0]."::";
}
# gather prepaid account pins
$pins = array();
$rs =& $db->Execute(sqlSelect($db,"voip_prepaid","pin","account_id=".SESS_ACCOUNT));
while ($rs && !$rs->EOF) {
$pins[] = $rs->fields[0];
$rs->MoveNext();
}
foreach ($pins as $pin) {
if ($sql_out!='') {
$sql_out .= ' OR ';
}
if ($sql_in!='') {
$sql_in .= ' OR ';
}
$sql_out .= " accountcode=::cc:".$pin.":: ";
$sql_in .= " dst = ::".$pin.":: ";
}
# Get last 25 incoming:
$rs =& $db->Execute(sqlSelect($db,"voip_cdr","id, date_orig, clid, src, dst, ceiling(duration/60) as duration, lastapp"," ( $sql_in ) AND (lastapp='Dial' or lastapp='VoiceMail' or lastapp='MeetMe' or lastapp='Hangup') AND disposition='ANSWERED' AND account_id = ".SESS_ACCOUNT,"date_orig DESC LIMIT 25",25));
if($rs && $rs->RecordCount() > 0) {
$i = 0;
while(!$rs->EOF) {
$in[$i]=$rs->fields;
if (strcasecmp($rs->fields['lastapp'], 'VoiceMail') == 0)
$in[$i]['type'] = 'v';
else if (in_array($rs->fields['dst'], $fdids))
$in[$i]['type'] = 'f';
$cc = ""; $npa = ""; $nxx = ""; $e164 = "";
if ($this->e164($rs->fields['src'], $e164, $cc, $npa, $nxx)) {
$in[$i]['location'] = $this->where_is($db, $cc, $npa, $nxx);
}
$i++;
$rs->MoveNext();
}
}
#echo "\n\n<!-- $sql -->\n\n";
# Get last 25 outgoing:
$rs =& $db->Execute(sqlSelect($db,"voip_cdr","id, accountcode, date_orig, clid, dst, ceiling(duration/60) as duration, lastapp"," ( $sql_out ) AND (lastapp='Dial' or lastapp='VoiceMail' or lastapp='MeetMe' or lastapp='Hangup') AND disposition='ANSWERED' AND account_id = ".SESS_ACCOUNT,"date_orig DESC LIMIT 25",25));
if($rs && $rs->RecordCount() > 0) {
$i = 0;
while(!$rs->EOF) {
$out[$i]=$rs->fields;
if (strcasecmp($rs->fields['lastapp'], 'VoiceMail') == 0)
$out[$i]['type'] = 'v';
foreach ($pins as $pin) {
if (strcmp($rs->fields['accountcode'], "cc:".$pin)==0) {
$out[$i]['type'] = 'c';
}
}
$cc = ""; $npa = ""; $nxx = ""; $e164 = "";
if ($this->e164($rs->fields['dst'], $e164, $cc, $npa, $nxx)) {
$out[$i]['location'] = $this->where_is($db, $cc, $npa, $nxx);
}
$i++;
$rs->MoveNext();
}
}
echo $sql;
$smarty->assign('in', $in);
$smarty->assign('out', $out);
}
/**
* Get user features for selected did
*/
function features($VAR) {
// validate logged in
if(!SESS_LOGGED) return false;
global $smarty;
// get the selected did
if(!empty($VAR['voip_did_id']) && is_numeric($VAR['voip_did_id']))
{
$smart=$this->get_auth_did($VAR['voip_did_id']);
$smarty->assign('record',$smart);
}
else
{
$dids = $this->get_all_dids(SESS_ACCOUNT);
if(is_array($dids)) $dids = $dids[0];
if(!$dids) return false;
$smart=$this->get_auth_did($dids);
$smarty->assign('record',$smart);
}
}
/**
* verify that a specific did is validated for the current account
*/
function get_auth_did($did) {
$db=&DB();
if($did) $sql = "id = ::$did:: AND "; else $did ='';
$rs = & $db->Execute($sql=sqlSelect($db,"voip_did","*","$sql account_id = ".SESS_ACCOUNT));
if($rs && $rs->RecordCount()>0) {
// get the voicemail email setting
if(!empty($rs->fields['voicemailenabled'])) {
$vm = & $db->Execute($sql = sqlSelect($db,"voip_vm","email","mailbox = ::{$rs->fields['did']}:: AND account_id = ".SESS_ACCOUNT));
$rs->fields['vm_email'] = $vm->fields['email'];
}
// is callwaiting enabled or disabled
$callwaiting = 1;
$cw =& $db->Execute($sql=sqlSelect($db,"voip_sip","data","keyword=::incominglimit:: and sip=::".$rs->fields['did']."::"));
if(!empty($cw->fields['data'])) {
if($cw->fields['data'] == 1) {
$callwaiting = 0;
}
}
$rs->fields['sip_callwaiting'] = $callwaiting;
return $rs->fields;
} else {
return false;
}
}
/**
* Update user features for selected did
*/
function update_features($VAR) {
if(!SESS_LOGGED) return false;
// get the selected did
if(!empty($VAR['voip_did_id']) && is_numeric($VAR['voip_did_id']))
{
if($flds = $this->get_auth_did($VAR['voip_did_id']))
{
$fields['voicemailafter'] = @$VAR['voip_voicemailafter'];
$fields['callforwardingenabled'] = @$VAR['voip_callforwardingenabled'];
$fields['cfringfor'] = @$VAR['voip_cfringfor'];
$fields['cfnumber'] = @$VAR['voip_cfnumber'];
$fields['busycallforwardingenabled']= @$VAR['voip_busycallforwardingenabled'];
$fields['bcfnumber'] = @$VAR['voip_bcfnumber'];
$fields['faxemail'] = @$VAR['voip_faxemail'];
$fields['failovernumber'] = @$VAR['voip_failovernumber'];
$fields['remotecallforwardnumber'] = @$VAR['voip_remotecallforwardnumber'];
$db=&DB();
$rs = & $db->Execute($sql=sqlUpdate($db,"voip_did",$fields,"id = ::{$flds['id']}::"));
if(!empty($VAR['voip_vm_email']) && !empty($flds['voicemailenabled'])) {
$fields2['email'] = $VAR['voip_vm_email'];
$rs = & $db->Execute($sql = sqlUpdate($db,"voip_vm",$fields2,"mailbox = ::{$flds['did']}:: AND account_id = ".SESS_ACCOUNT));
}
# update the call waiting setting
if(!empty($VAR['sip_callwaiting'])) {
# delete the incominglimit
$sql = "DELETE FROM ".AGILE_DB_PREFIX."voip_sip WHERE sip=".$flds['did']." and keyword='incominglimit' and site_id=".DEFAULT_SITE;
$db->Execute($sql);
} else {
$f['data'] = "1";
$f['keyword'] = "incominglimit";
$f['sip'] = $flds['did'];
$sql = sqlInsert($db, "voip_sip", $f);
$db->Execute($sql);
}
}
}
}
// get available parent service ids
function menu_parent_service($VAR) {
if(!empty($VAR['account_id']))
$account_id = $VAR['account_id'];
else
$account_id = SESS_ACCOUNT;
$db=&DB();
$rs=&$db->Execute($sql=sqlSelect($db,array("voip_did","service"),"A.id,A.service_id,A.did","A.service_id = B.id AND (A.rxfax=0 or A.rxfax is null) AND (A.conf=0 or A.conf is null) AND (A.remotecallforward=0 or A.remotecallforward is null) AND B.active=1 AND B.account_id=".$account_id,false,false,"DISTINCT"));
if($rs && $rs->RecordCount() > 0) {
$return = '<select name="attr[parent_service_id]">';
$return .= '<option value="" selected></option>';
if($rs && $rs->RecordCount() > 0)
{
while(!$rs->EOF)
{
$return .= '<option value="' . $rs->fields['service_id'] . '">' . $rs->fields["did"] . '</option>';
$rs->MoveNext();
}
}
$return .= '</select>';
echo $return;
} else {
echo "No associated accounts found";
}
}
// function
function get_did_plugin_countries($id, &$plugins) {
$countries = false;
$db=&DB();
$rs = & $db->Execute($sql=sqlSelect($db,"product","prod_plugin_data","id = ::$id::"));
if($rs && $rs->RecordCount() > 0) {
@$plugin = unserialize($rs->fields['prod_plugin_data']);
@$plugins = $plugin['voip_did_plugins'];
if(is_array($plugins) && count($plugins > 0)) {
$sql = '';
foreach($plugins as $key=>$plgid) {
if($sql!='') $sql .= " OR ";
$sql .= " id = $plgid ";
}
$rs = & $db->Execute(sqlSelect($db,"voip_did_plugin","avail_countries","( $sql )"));
if($rs && $rs->RecordCount() > 0) {
while(!$rs->EOF) {
$carr = unserialize($rs->fields['avail_countries']);
foreach($carr as $cid) $countries["$cid"] = $cid;
$rs->MoveNext();
}
}
} else {
$plugins = array();
}
}
return $countries;
}
// get available countries
function menu_countries($VAR) {
header('Pragma: no-cache');
header('Cache-Control: no-cache, must-revalidate');
if(!$did_plugins = $this->get_did_plugin_countries($VAR['id'],$plugins)) {
echo '-- No Countries --';
return;
}
$countries = new didCountries($plugins);
$js = '<select id="voip_country" name="attr[country]" onChange="voipChangeCountry(this.value)">';
$js .= '<option value="" selected>--- Pick a Country ---</option>';
while($c = $countries->getCountry()) {
$js .= '<option value="' . $c->getCode() . '">' . $c->getName() . '</option>';
}
$js .= '</select>';
echo $js;
}
//
function menu_states($VAR)
{
header('Pragma: no-cache');
header('Cache-Control: no-cache, must-revalidate');
$did_plugins = $this->get_did_plugin_countries($VAR['id'],$plugins);
$areas = new didAreas(1,$plugins);
#echo "<pre>".print_r($areas,true)."</pre>";
$areas_seen = array();
$js = '<select id="voip_state" name="attr[state]" onChange="voipChangeState(this.value)">';
$js .= '<option value="" selected>--- Pick a State ---</option>';
while($area = $areas->getArea()) {
#echo print_r($area,true);
if(!isset($areas_seen[$area->getState()])) {
$js .= '<option value="' . $area->getState() . '">' . $area->getState() . '</option>';
$areas_seen[$area->getState()] = true;
}
}
$js .= '</select>';
echo $js;
}
// return location menu
function menu_location($VAR)
{
header('Pragma: no-cache');
header('Cache-Control: no-cache, must-revalidate');
$did_plugins = $this->get_did_plugin_countries($VAR['id'],$plugins);
$cc = 1;
if(!empty($VAR['country']))
$cc = $VAR['country'];
#echo "alert('$cc');"; exit;
$areas = new didAreas($cc,$plugins);
$js = 'menuClearOptions("voip_location");';
$js .= "menuAppendOption('voip_location', '', '-- Select A Location --');";
$count = 0;
while($area = $areas->getArea()) {
if($cc!=1) {
$js .= "menuAppendOption('voip_location', '{$cc}:".$area->getAreacode()."', '".$area->getName()." (".$area->getAreacode().")');";
} else if($area->data['locState']==$VAR['state']) {
$js .= "menuAppendOption('voip_location', '".$area->getNpa()."-".$area->getNxx()."', '".$area->getName()." (".$area->getNpa()."-".$area->getNxx().")');";
}
$count++;
}
if($count)
echo $js;
else
echo 'document.write("Sorry, none available at this time. Please check again later.");';
return;
}
// return location menu
function menu_station($VAR)
{
header('Pragma: no-cache');
header('Cache-Control: no-cache, must-revalidate');
$did_plugins = $this->get_did_plugin_countries($VAR['id'],$plugins);
#echo "alert(\"".str_replace("\n","\\\n",str_replace("\"","\\\"",print_r($VAR,true)))."\");";return;
#if(empty($VAR['location']) && empty($VAR['country'])) return false;
$l = $VAR['location'];
if (strchr($l,':')) {
$cn = explode(':', $l);
$data['country_code'] = $cn[0];
$data['areacode'] = $cn[1];
} else {
$cn = explode('-', $l);
$data['country_code'] = 1;
$data['npa'] = $cn[0];
$data['nxx'] = $cn[1];
}
$area = new didArea($data['country_code'], $data);
#echo "alert(\"".str_replace("\n","\\\n",str_replace("\"","\\\"",print_r($area,true)))."\");"; return;
$js = 'menuClearOptions("voip_station"); ';
$js .= "menuAppendOption('voip_station', '', '-- Select A Station --'); ";
$dids = $area->getStations($plugins);
#echo "alert(\"".str_replace("\n","\\\n",str_replace("\"","\\\"",print_r($dids,true)))."\");"; return;
foreach($dids as $did) {
#if($data['country_code'] == 1) {
$js .= "menuAppendOption('voip_station', '".$did[0]."', '{$did[1]}'); ";
#} else {
# ;
#}
}
echo $js;
return;
$db=&DB();
$p = AGILE_DB_PREFIX;
if(!empty($VAR['location']))
{
$l = $VAR['location'];
if(eregi(':', $l)) // passed country_code:region
{
$cn = explode(':', $l);
$ccode = $cn[0];
$npa = $cn[1];
$sql = "select distinct left(A.station,4) as npa,B.locName, station from {$p}voip_pool AS A
inner join {$p}voip_npa_nxx AS B on (left(A.station,4)=B.npa AND
A.country_code='{$ccode}' AND B.country_code='{$ccode}' AND B.npa='{$npa}')
WHERE (A.account_id IS NULL OR A.account_id = 0) AND
(A.date_reserved IS NULL OR A.date_reserved = 0) AND
A.voip_did_plugin_id in (".join(",",$plugins).") AND
A.site_id=".DEFAULT_SITE." ORDER BY B.locName LIMIT 0,50";
// loop through results
$rs = $db->Execute($sql);
if($rs && $rs->RecordCount() > 0) {
while(!$rs->EOF) {
if(!empty($rs->fields["station"]))
$js .= "menuAppendOption('voip_station', '011". $ccode . $rs->fields["station"]."', '{$ccode} {$rs->fields["station"]}'); ";
$rs->MoveNext();
}
} else {
$js = 'document.write("Sorry, none available at this time. Please check again later.");';
}
} else {
$np=explode('-',$l); // passed npa-nxx
$npa=$np[0];
$nxx=$np[1];
$sql = "select distinct A.country_code,A.npa,A.nxx,A.station
FROM {$p}voip_pool AS A
left join {$p}voip_npa_nxx AS B
on (A.npa=B.npa and A.nxx=B.nxx AND B.country_code='1')
WHERE (A.account_id IS NULL OR A.account_id = 0)
AND (A.date_reserved IS NULL OR A.date_reserved = 0)
AND A.npa = " . $db->qstr($npa) . "
AND A.nxx = " . $db->qstr($nxx) . "
AND A.voip_did_plugin_id in (".join(",",$plugins).")
AND A.site_id=".DEFAULT_SITE."
LIMIT 0,50";
// loop through results
$rs = $db->Execute($sql);
if($rs && $rs->RecordCount() > 0) {
while(!$rs->EOF) {
if(!empty($rs->fields["station"]))
$js .= "menuAppendOption('voip_station', '". $rs->fields["country_code"].$rs->fields["npa"].$rs->fields["nxx"].$rs->fields['station'] ."', '{$rs->fields["npa"]}-{$rs->fields["nxx"]}-{$rs->fields["station"]}'); ";
$rs->MoveNext();
}
} else {
$js = 'document.write("Sorry, none available at this time. Please check again later.");';
}
}
}
else
{
$country = $VAR['country'];
$sql = "SELECT DISTINCT B.country_code, B.station from {$p}voip_pool AS B
LEFT JOIN {$p}voip_iso_country_code_map AS A ON (B.country_code=A.country_code)
WHERE ( account_id IS NULL or account_id = 0)
AND ( B.date_reserved IS NULL or B.date_reserved = 0 )
AND A.iso_country_code=".$db->qstr($country)."
AND B.voip_did_plugin_id in (".join(",",$plugins).")
and A.site_id=".DEFAULT_SITE." AND B.site_id=".DEFAULT_SITE."
LIMIT 0,50";
$rs = $db->Execute($sql);
if($rs && $rs->RecordCount() > 0) {
while(!$rs->EOF) {
if(!empty($rs->fields["station"]))
$js .= " menuAppendOption('voip_station', '011". $rs->fields["country_code"] . $rs->fields["station"] ."', '{$rs->fields["country_code"]}{$rs->fields["station"]}'); ";
$rs->MoveNext();
}
} else {
$js = 'document.write("Sorry, none available at this time. Please check again later.");';
}
}
echo $js;
ob_end_flush();
return true;
}
/** Returns the fields from voip_pool for a given DID entry.
*/
function get_did_e164($did)
{
$db =& DB();
$cc = ""; $npa = ""; $nxx = ""; $e164 = "";
if ($this->e164($did, $e164, $cc, $npa, $nxx)) {
if ($cc == '1') {
$station = substr($e164, 8);
$where = "country_code=1 and npa=::$npa:: and nxx=::$nxx:: and station=::$station::";
} else {
$station = substr($e164, 4 + strlen($cc));
$where = "country_code=::$cc:: and station=::$station::";
}
$rs = $db->Execute(sqlSelect($db, "voip_pool", "*", $where));
if (!$rs) return false;
return $rs->fields;
}
return false;
}
/** Save the configuration.
*/
function config($VAR)
{
global $C_debug;
$db = & DB();
# define the validation class
include_once(PATH_CORE . 'validate.inc.php');
$validate = new CORE_validate;
$arr['min_len'] = 4;
$arr['max_len'] = 4;
if(is_numeric($VAR['voip_vm_passwd']) && !empty($VAR['voip_intrastate']))
{
$fields['voip_vm_passwd'] = $VAR['voip_vm_passwd'];
$fields['voip_intrastate'] = $VAR['voip_intrastate'];
$fields['voip_secret_gen'] = $VAR['voip_secret_gen'];
$fields['voip_default_prefix'] = $VAR['voip_default_prefix'];
$fields['prepaid_low_balance'] = $VAR['prepaid_low_balance'];
$fields['auth_domain'] = $VAR['auth_domain'];
$fields['perform_normalization'] = $VAR['perform_normalization'];
$fields['normalization_min_len'] = $VAR['normalization_min_len'];
$rs = $db->Execute( sqlSelect($db, "voip", "id", "site_id=::".DEFAULT_SITE."::") );
if ($rs && !$rs->EOF) {
$db->Execute( sqlUpdate($db, "voip", $fields, "site_id=::".DEFAULT_SITE."::") );
} else {
$db->Execute( sqlInsert($db, "voip", $fields) );
}
$C_debug->alert("Saved!");
} else {
$C_debug->alert("Problems while saving:".$db->ErrorMsg());
}
}
/** Load the configuration variables into smarty
*/
function config_get($VAR)
{
global $smarty;
$db = & DB();
$sql = sqlSelect($db, "voip", "*", "");
$rs = $db->Execute($sql);
$smarty->assign('config',$rs->fields);
}
/** Return all available DIDs the customer owns.
* @param $account_id: The account to return dids for
*/
function get_all_dids($account_id)
{
return $this->get_all_dids_internal($account_id, 0);
}
/** Return all DIDs with voice mail active.
* @param $account_id: The account to return dids for
*/
function get_voicemail_dids($account_id)
{
return $this->get_all_dids_internal($account_id, 1);
}
/** Return all DIDs with fax active.
* @param $account_id: The account to return dids for
*/
function get_fax_dids($account_id)
{
return $this->get_all_dids_internal($account_id, 2);
}
/** Internal function used to gather an accounts available DIDs.
* @param $VAR The AB passed array
* @param $filter A flag to specify the type of DIDs to return. 0=ALL, 1=VM, 2=FAX, 3=CONFERENCE
*/
function get_all_dids_internal($account_id, $filter)
{
$db = & DB();
$rs = & $db->Execute($sql=sqlSelect($db,"voip_did","did,voicemailenabled,rxfax,conf","active=1 AND account_id = ::$account_id::"));
#echo $sql;
$dids = array();
if ($rs && $rs->RecordCount() > 0) {
while (!$rs->EOF) {
$did = $rs->fields['did'];
switch ($filter) {
case 0: //ALL
array_push($dids, $did);
break;
case 1:
if ($rs->fields['voicemailenabled']) { //VM
array_push($dids, $did);
}
break;
case 2:
if ($rs->fields['rxfax']) { //FAX
array_push($dids, $did);
}
break;
case 3:
if ($rs->fields['conf']) { //CONF
array_push($dids, $did);
}
break;
default:
global $C_debug;
$C_debug->error('voip.inc.php','get_all_dids_internal','Invalid filter passed: '.$filter);
}
$rs->MoveNext();
}
}
return $dids;
}
function normalize(&$db)
{
$count = 0;
$sql = sqlSelect($db, "voip_cdr", "src, dst, id", "(rated is null or rated=0)");
#echo $sql."<BR>";
$rs = $db->Execute($sql);
while (!$rs->EOF) {
$src = $rs->fields['src'];
$dst = $rs->fields['dst'];
$e164 = ""; $cc = ""; $npa = ""; $nxx = "";
if (strlen($src)>=$this->normalization_min_len && $this->e164($src, $e164, $cc, $npa, $nxx)) {
$src = substr($e164,1);
}
$e164 = ""; $cc = ""; $npa = ""; $nxx = "";
if (strlen($dst)>=$this->normalization_min_len && $this->e164($dst, $e164, $cc, $npa, $nxx)) {
$dst = substr($e164,1);
}
#echo "src=".$rs->fields['src']." dst=".$rs->fields['dst']."<br>";
#echo "esrc=".$src." edst=".$dst."<br><br>";
#$f = array('src' => $src, 'dst' => $dst, 'rated' => '2');
#$sql = sqlUpdate($db,"voip_cdr",$f,"id=::".$rs->fields['id']);
$sql = "UPDATE ".AGILE_DB_PREFIX."voip_cdr SET
src=".$db->qstr($src).", dst=".$db->qstr($dst).", rated=2
WHERE id=".$db->qstr($rs->fields['id']);
#echo $sql."<br>";
$db->Execute($sql);
$count++;
$rs->MoveNext();
}
echo "Normalized $count records...\n";
}
// Call as task - voip:task
function task($VAR)
{
if(function_exists('agileco_parse_country_code')) {
$this->c_task($VAR);
return;
}
global $rate;
$rate = array();
$db = &DB();
$rs = & $db->Execute( sqlSelect($db, "product", "id,prod_plugin_data", "prod_plugin_file=::VOIP:: and prod_plugin=1"));
while (!$rs->EOF) {
$pdata = unserialize($rs->fields['prod_plugin_data']);
$id = $rs->fields['id'];
if ($pdata['rate_cdr'] == 1) {
$products[] = $id;
}
$rs->MoveNext();
}
// no products to rate
if(empty($products)) return false;
# Load configuration
$sql = sqlSelect($db, "voip", "voip_intrastate, voip_default_prefix, perform_normalization, normalization_min_len", "");
$rs = $db->Execute($sql);
$this->voip_intrastate = explode(",",ereg_replace("[[:space:]]","",$rs->fields['voip_intrastate']));
$this->voip_default_prefix = $rs->fields['voip_default_prefix'];
$this->normalization_min_len = $rs->fields['normalization_min_len'];
$this->perform_normalization = $rs->fields['perform_normalization'];
ob_start();
# normalize the CDR records
echo "Begin normalization...\n";
if($this->perform_normalization) {
$this->normalize($db);
}
echo "Finished normalization...\n";
# rate prepaid cards, non-SIP prepaid
$rs =& $db->Execute(sqlSelect($db,"voip_prepaid","pin, account_id, product_id, voip_did_id","(voip_did_id=0 or voip_did_id is null)"));
if ($rs && $rs->RecordCount() > 0) {
while (!$rs->EOF) {
$dp = 0;
unset($dids);
$dids[$dp]['start'] = 0;
$dids[$dp]['end'] = mktime(0,0,0,date('m')+1,1,date('Y'));
$dids[$dp]['accountcode'] = "cc:".$rs->fields['pin'];
echo "Rating calling card PIN: ".$rs->fields['pin']."\n";
# Load rating table configuration
$rate = $this->load_rating_table($db, $rs->fields['product_id']);
$this->rate_calls($db, $db, $dids, $rs->fields, false);
# Mark inbound calls
if ($rs->fields['voip_did_id'] > 0) {
$sql = "update ".AGILE_DB_PREFIX."voip_cdr SET amount=0, rated=1, account_id=".$db->qstr($rs->fields['account_id'])." where dst=".$db->qstr($rs->fields['pin'])." and rated=0 and site_id=".DEFAULT_SITE;
echo $sql."\n";
$db->Execute($sql);
}
$rs->MoveNext();
}
}
echo "Begin SIP Prepaid rating...\n";
$sql = "select account_id, username, prod_attr_cart, prod_plugin_data, date_last_invoice, date_next_invoice, b.product_id, b.id as service_id from ".AGILE_DB_PREFIX."account as a left join ".AGILE_DB_PREFIX."service as b on (a.id=b.account_id) where a.status=1 and prod_plugin_name='PREPAID' and b.active=1 and a.site_id=".DEFAULT_SITE." and b.site_id=".DEFAULT_SITE;
echo $sql."\n";
$rs =& $db->Execute($sql);
if ($rs && $rs->RecordCount() > 0) {
while (!$rs->EOF) {
$dp = 0;
unset($dids);
$cart = @unserialize($rs->fields['prod_attr_cart']);
$plugin = unserialize($rs->fields['prod_plugin_data']);
if (isset($cart['station']) && isset($plugin['type']) && $plugin['type'] == 'did') {
$dids[$dp]['start'] = $rs->fields['date_last_invoice'] - (MAX_INV_GEN_PERIOD*86400);
$dids[$dp]['end'] = $rs->fields['date_next_invoice'] + 86399;
$dids[$dp]['did'] = $cart['station'];
# Load rating table configuration
$rate = $this->load_rating_table($db, $rs->fields['product_id']);
if (is_array($rate)) {
$this->rate_calls($db, $db, $dids, $rs->fields);
}
}
$rs->MoveNext();
}
}
echo "Begin postpaid rating...\n";
# rate calls
$sql = "select account_id, username, prod_attr_cart, prod_plugin_data, date_last_invoice, date_next_invoice, b.product_id, b.id as service_id, b.sku from ".AGILE_DB_PREFIX."account as a left join ".AGILE_DB_PREFIX."service as b on (a.id=b.account_id) where a.status=1 and prod_plugin_name='VOIP' and b.active=1 and product_id IN (".join(",",$products).") and a.site_id=".DEFAULT_SITE." and b.site_id=".DEFAULT_SITE;
echo $sql."\n";
$rs = $db->Execute($sql);
$dp = 0;
while (!$rs->EOF) {
$dp = 0; unset($dids);
$cart = @unserialize($rs->fields['prod_attr_cart']);
$plugin = unserialize($rs->fields['prod_plugin_data']);
$dids[$dp]['start'] = $rs->fields['date_last_invoice'] - (MAX_INV_GEN_PERIOD*86400);
$dids[$dp]['end'] = $rs->fields['date_next_invoice'];
$dids[$dp]['did'] = @$cart['station'];
if (strlen(@$cart['ported']))
$dids[0]['did'] = $cart['ported'];
$cc = ""; $e164 = ""; $npa = ""; $nxx = "";
if ((!strlen($dids[0]['did']) && $plugin['rate_accountcode'] == 0)) {
echo "Skipping service_id = ".$rs->fields['service_id']." (sku: ".$rs->fields['sku'].")\n";
} else {
if ($this->e164($dids[0]['did'],$e164,$cc,$npa,$nxx)) {
$dids[0]['did'] = substr($e164,1);
if ($cc == '1') {
$dp++;
$dids[$dp]['start'] = $rs->fields['date_last_invoice'] - (MAX_INV_GEN_PERIOD*86400);
$dids[$dp]['end'] = $rs->fields['date_next_invoice'] + 86399;
$dids[$dp]['did'] = substr($e164,2);
$dp++;
$dids[$dp]['start'] = $rs->fields['date_last_invoice'] - (MAX_INV_GEN_PERIOD*86400);
$dids[$dp]['end'] = $rs->fields['date_next_invoice'] + 86399;
$dids[$dp]['did'] = substr($e164,1);
} else {
$dp++;
$dids[$dp]['start'] = $rs->fields['date_last_invoice'];
$dids[$dp]['end'] = $rs->fields['date_next_invoice'] + 86399;
$dids[$dp]['did'] = substr($e164,4);
}
}
if (@$cart['parent_service_id'] > 0) {
# echo "This is a virtual number, skipping record...";
;
} else {
# load virtual numbers on this parent service
$sql = "select * from ".AGILE_DB_PREFIX."service where account_id=".$db->qstr($rs->fields['account_id'])." and active=1 and prod_plugin_name='VOIP' and site_id=".DEFAULT_SITE;
echo $sql."\n";
$rs1 = $db->Execute($sql); $i = 1;
if ($rs1) {
while (!$rs1->EOF) {
$carttmp = @unserialize($rs1->fields['prod_attr_cart']);
if (@$carttmp['parent_service_id'] == $rs->fields['service_id']) {
# is this an actual virtual line?
$ppd = unserialize($rs1->fields['prod_plugin_data']);
if ($ppd['parent_enabled'] && $ppd['virtual_number']) {
$dp++;
$dids[$dp]['start'] = $rs1->fields['date_last_invoice'] - (MAX_INV_GEN_PERIOD*86400);
$dids[$dp]['end'] = $rs1->fields['date_next_invoice'] + 86399;
$dids[$dp]['did'] = @$carttmp['station'];
if (strlen($carttmp['ported']))
$dids[$dp]['did'] = $carttmp['ported'];
$cc = ""; $e164 = ""; $npa = ""; $nxx = "";
if ($this->e164($dids[$dp]['did'],$e164,$cc,$npa,$nxx)) {
$dids[$dp]['did'] = substr($e164,1);
if ($cc == '1') {
$dp++;
$dids[$dp]['start'] = $rs->fields['date_last_invoice'] - (MAX_INV_GEN_PERIOD*86400);
$dids[$dp]['end'] = $rs->fields['date_next_invoice'] + 86399;
$dids[$dp]['did'] = substr($e164,2);
$dp++;
$dids[$dp]['start'] = $rs->fields['date_last_invoice'] - (MAX_INV_GEN_PERIOD*86400);
$dids[$dp]['end'] = $rs->fields['date_next_invoice'] + 86399;
$dids[$dp]['did'] = substr($e164,1);
}
}
echo "Found virtual number: ".$dids[$dp]['did']."\n";
} # end test to see if truely virtual
}
$rs1->MoveNext();
}
}
# Load rating table configuration
$rate = $this->load_rating_table($db, $rs->fields['product_id']);
if (is_array($rate)) {
if ($plugin['rate_accountcode']) {
# rate accountcode based
# echo "Rate by account code: ".$rs->fields['username']."\n";
$dids[$dp]['accountcode'] = $rs->fields['username'];
$this->rate_calls($db, $db, $dids, $rs->fields);
} else {
# rate non-accountcode based
$this->rate_calls($db, $db, $dids, $rs->fields);
}
}
}
} # end did length check
$rs->MoveNext();
}
$debug = ob_get_contents();
echo $debug;
ob_end_clean();
if (defined('RATING_DEBUG')) {
mail("joe@thrallingpenguin.com","Rating Debug For ".URL,$debug);
}
return true;
}
/** Returns the call type of two DIDs. Returns: 1=INTRASTATE,2=INTERSTATE,3=TOLL-FREE
* @param $src Source telephone number
* @param $dst Destination telephone number
*/
function isIntrastateCall($src,$dst)
{
# This is OHIOs NPAs. We need to know the location of us and we can load these values from
# the beastly add-on table we have.
#
# Can we assume the business state is the location of this stuff?
#
$ohio = $this->voip_intrastate;
if (strncmp("1800",$dst,4)==0 || strncmp("1877",$dst,4)==0 || strncmp("1866",$dst,4)==0 || strncmp("1888",$dst,4)==0)
return 3;
$s = 0; $d = 0;
foreach ($ohio as $p) {
if (strncmp("1".$p,$src,4)==0)
$s = 1;
if (strncmp("1".$p,$dst,4)==0)
$d = 1;
}
if($s == 1 && $d == 1) return 1;
return 2;
}
/** Loads the rate table associated with a product.
* @param $db A database connection handle
* @param $product_id The ID of the product to load.
*/
function load_rating_table(&$db, $product_id)
{
global $rate;
$sql = "SELECT b.id, b.connect_fee, b.increment_seconds, b.amount, b.pattern, b.type, b.direction, b.min, b.max, b.combine, b.percall as perCall, b.seconds_included, b.name FROM ".AGILE_DB_PREFIX."voip_rate_prod a inner join ".AGILE_DB_PREFIX."voip_rate b on (a.voip_rate_id=b.id and a.site_id=".DEFAULT_SITE.") WHERE product_id=".$product_id." ORDER BY type, direction DESC, length(pattern) DESC";
echo $sql."\n";
$rs = $db->Execute($sql);
unset($rate);
$i = 0;
while (!$rs->EOF) {
$rate[$i] = $rs->fields;
$rate[$i]['pattern'] = str_replace("\r","",str_replace("\n","",ereg_replace("[^0-9;]","",$rs->fields['pattern'])));
$rate[$i]['perCall'] = intval($rs->fields['perCall']);
switch ($rs->fields['type']) {
case 0:
$rate[$i]['type'] = 'innetwork';
break;
case 1:
$rate[$i]['type'] = 'local';
break;
case 2:
$rate[$i]['type'] = 'regular';
break;
case 3:
$rate[$i]['type'] = 'default';
break;
default:
break;
}
switch ($rs->fields['direction']) {
case 0:
$rate[$i]['direction'] = 'inbound';
break;
case 1:
$rate[$i]['direction'] = 'outbound';
break;
case 2:
$rate[$i]['direction'] = 'both';
break;
default:
break;
}
$i++;
$rs->MoveNext();
}
if ($i == 0) {
#global $C_debug;
#$C_debug->error('voip.inc.php','load_rating_table','Rate table is empty for product_id = '.$product_id);
echo "Rating table is blank!\n\n";
}
return (isset($rate) ? $rate : false);
}
/** Returns boolean if the DID S is in the array of DIDs DIDS.
*/
function in_did_array($s, &$dids)
{
$ret = false;
foreach ($dids as $d) {
if (isset($d['did'])) {
if ($d['did'] == $s) {
$ret = true;
break;
}
}
}
return $ret;
}
function price_call(&$dbast, $r, $dur, $callSQL, &$unit, &$quan)
{
$billedDur = (($dur - $r['seconds_included']) / $r['increment_seconds']);
if ($billedDur < 0)
$billedDur = 0;
$billedDur = ceil($billedDur);
$billedDur = ($billedDur * $r['increment_seconds'])/60;
$cost = 0;
$quan = $billedDur;
# get count for min/max, honor the combine flag!
$count = 0;
if ($r['combine']) {
$sql = "select sum(adjbillinterval) from ".AGILE_DB_PREFIX."voip_cdr where voip_rate_id=".$r['id']." and $callSQL";
#echo $sql."\n";
$rst = $dbast->Execute($sql);
$count = intval($rst->fields[0]);
}
echo "count=$count, rmin=".$r['min'].", rmax=".$r['max']."\n";
if ($count >= $r['min'] &&
($count <= $r['max'] || $r['max'] == -1)) {
echo "perCall = ".$r['perCall']."\n";
if ($r['perCall']) {
$cost = $r['amount'];
$quan = 1;
$unit = $r['amount'];
} else {
$cost = ($r['amount'] * $billedDur);
$quan = $billedDur;
$unit = $r['amount'];
echo "billedDur=".$billedDur."\n";
}
}
print "cost=$cost, quan=$quan, unit=$unit\n";
return $cost;
}
/** Determines if DST is in SRC's local calling area.
*/
function is_local_calling_area(&$dbast, $src, $dst)
{
$cc1 = ""; $npa1 = ""; $nxx1 = "";
$cc2 = ""; $npa2 = ""; $nxx2 = "";
$e164 = "";
if ($this->e164($src,$e164,$cc1,$npa1,$nxx1)) {
if ($this->e164($dst,$e164,$cc2,$npa2,$nxx2)) {
$sql = "select t1.grouping as id1, t2.grouping from ".AGILE_DB_PREFIX."voip_local_lookup as t1 join ".AGILE_DB_PREFIX."voip_local_lookup as t2 on (t1.npa='$npa1' and t1.nxx='$nxx1' and t2.npa='$npa2' and t2.nxx='$nxx2') where t1.grouping=t2.grouping";
echo $sql."\n";
$rs = $dbast->Execute($sql);
if ($rs->fields[0] > 0) {
return true;
}
}
}
return false;
}
function rate_calls(&$db, &$dbast, $dids, $crow, $postCharges = true)
{
global $rate;
$quan = 0;
$bAccountcode = false;
# probably should have the e.164 values here too.
$sql = "(";
foreach($dids as $d) {
if (strlen(@$d['accountcode'])) {
$sql .= "(accountcode=".$db->qstr($d['accountcode'])." and date_orig>='".$d['start']."' and date_orig<='".$d['end']."') OR ";
$bAccountcode = true;
} else {
$sql .= "((src='".$d['did']."' or dst='".$d['did']."') and date_orig>='".$d['start']."' and date_orig<='".$d['end']."') OR ";
}
}
$sql = substr($sql,0,strlen($sql)-3).")";
$callSQL = $sql;
$sql = "select * from ".AGILE_DB_PREFIX."voip_cdr where $sql and
(lastapp='Dial' or lastapp='VoiceMail' or lastapp='MeetMe' or lastapp='Hangup')
AND disposition='ANSWERED' and (rated=2)";
echo $sql."\n";
$rs1 = $dbast->Execute($sql);
#print_r($rate);
while ($rs1 && !$rs1->EOF) {
$calltype = 0;
if(strlen($this->voip_intrastate))
$calltype = $this->isIntrastateCall($rs1->fields['src'], $rs1->fields['dst']);
$slotMatched = 0; $unit = 0; $quan = 0; $amount = 0;
$isInbound = $this->in_did_array($rs1->fields['dst'], $dids);
if ($isInbound)
$calltype = 4;
$slotMatched = 0; $unit = 0; $quan = 0;
foreach ($rate as $r) {
if ($r['type'] == 'innetwork') {
#echo "Is the call In Network?\n";
if ($r['direction'] == 'inbound') {
$search = $rs1->fields['src'];
} else if ($r['direction'] == 'outbound') {
$search = $rs1->fields['dst'];
} else {
$search = $rs1->fields['src']."','".$rs1->fields['dst'];
}
$sql = "select count(*) from ".AGILE_DB_PREFIX."voip_in_network where did in ('".$search."')";
echo $sql."\n";
$rs2 = $dbast->Execute($sql);
if ($rs2->fields[0] > 0) {
echo "Yes, call is in-network.\n";
$amount = 0;
$slotMatched = $r['id'];
#break;
}
} else if ($r['type'] == 'local') {
echo "Local calling area\n";
if ($this->is_local_calling_area($dbast, $rs1->fields['src'], $rs1->fields['dst'])) {
$amount = 0;
$slotMatched = $r['id'];
#break;
}
} else if ($r['type'] == 'regular' || $r['type'] == 'default') {
#echo "src=".$rs1->fields['src']."\n";
#echo "dst=".$rs1->fields['dst']."\n";
$pats = split(";", $r['pattern']);
$search = $rs1->fields['dst'];
foreach ($pats as $pattern) {
#echo "Matching against: $pattern\n";
#if (ereg("^".$pattern, $search) || $r['type'] == 'default') {
if ((strncmp($pattern, $search, strlen($pattern))==0 && strlen($pattern)) || $r['type'] == 'default') {
echo "src=".$rs1->fields['src']."\n";
echo "dst=".$rs1->fields['dst']."\n";
echo "pattern=".$pattern."\n";
echo "Billsec=".$rs1->fields['billsec']."\n";
$amount = $this->price_call($db, $r, $rs1->fields['billsec'], $callSQL, $unit, $quan);
$slotMatched = $r['id'];
echo "Matched slot ".$r['id']." (".$r['name'].") with quan=$quan and unit=$unit\n";
break;
}
}
}
# if the slot matched, and the call direction matches, then exit the rating table matching
if ($slotMatched && (
$r['direction'] == 'both' || # rate entry for both call directions
($r['direction'] == 'inbound' && $isInbound) || # inbound rate and inbound call direction
($r['direction'] == 'outbound' && !$isInbound) ) # outbound rate and outbound call direction
) {
echo "Found match: ".$slotMatched."\n";
break;
} else if ($slotMatched && $bAccountcode ) {
# matched via account codes
echo "Found match via accountcode: ".$slotMatched."\n";
break;
} else if ($slotMatched) {
# reset the variables and continue trying to find a match
$slotMatched = 0; $unit = 0; $quan = 0; $amount = 0;
echo "Incorrect direction, continuing to match...\n";
}
}
$sql = "update ".AGILE_DB_PREFIX."voip_cdr set account_id=".$db->qstr($crow['account_id']).", amount='".$amount."', calltype='$calltype', voip_rate_id='$slotMatched', rated=1, adjbillinterval=".$db->qstr($quan)." WHERE id=".$rs1->fields['id']." AND site_id=".DEFAULT_SITE;
echo $sql."\n";
if (!$db->Execute($sql)) {
echo $db->ErrorMsg()."\n";
}
if ($unit && $postCharges) {
$a = 'Source=='.$rs1->fields['src'].'\r\nDestination=='.$rs1->fields['dst'];
$a .= '\r\nvoip_cdr_id=='.$rs1->fields['id'].'\r\ndate_orig=='.$rs1->fields['date_orig'];
if ($r['connect_fee']) {
$b = $a.'\r\nConnection Charge';
unset($fields);
$fields['date_orig'] = $rs1->fields['date_orig'];
$fields['status'] = 0;
$fields['service_id'] = $crow['service_id'];
$fields['amount'] = $r['connect_fee'];
$fields['sweep_type'] = 6;
$fields['taxable'] = 0;
$fields['quantity'] = 1;
$fields['product_id'] = $crow['product_id'];
$fields['attributes'] = $b;
$db->Execute( sqlInsert($db,"charge",$fields) );
}
if ($quan > 0) {
unset($fields);
$fields['date_orig'] = $rs1->fields['date_orig'];
$fields['status'] = 0;
$fields['service_id'] = $crow['service_id'];
$fields['amount'] = $unit;
$fields['sweep_type'] = 6;
$fields['taxable'] = 0;
$fields['quantity'] = $quan;
$fields['product_id'] = $crow['product_id'];
$fields['attributes'] = $a;
$db->Execute( sqlInsert($db,"charge",$fields) );
}
}
$rs1->MoveNext();
}
}
function microtime_float()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
/**
* TODO: Accountcode based rating, Prepaid based rating
*/
function c_task($VAR)
{
# set the PHP timeout and the don't abort flag
set_time_limit(60 * 15);
# normalize the CDR records
if($this->perform_normalization) {
echo "Begin normalization...\n";
$this->normalize($db);
echo "Finished normalization...\n";
}
# Add in the prepaid rating pieces
# Begin the postpaid rating
$bDoCallType = false;
if(strlen($this->voip_intrastate))
$bDoCallType = true;
$db =& DB();
$sql = "select * from ".AGILE_DB_PREFIX."voip_cdr where
(lastapp='Dial' or lastapp='VoiceMail' or lastapp='MeetMe' or lastapp='Hangup')
AND disposition='ANSWERED' and rated=2 limit 1000";
$rs = $db->Execute($sql); $i = 0; $total = 0.0;
$st = $this->microtime_float();
while(!$rs->EOF) {
unset($match);
# who does the number belong to?
$account_id = 0; $service_id = 0; $product_id = 0; $callSQL = "";
find_owner($rs->fields['src'], $account_id, $service_id, $product_id, $callSQL);
$isInbound = 0;
$calltype = 0;
if($bDoCallType)
$calltype = $this->isIntrastateCall($rs->fields['src'], $rs->fields['dst']);
#echo "Account: {$account_id} on src\n";
if($account_id === false) {
find_owner($rs->fields['dst'], $account_id, $service_id, $product_id, $callSQL);
$isInbound = 1;
$calltype=4;
#echo "AccountL {$account_id} on dst\n";
}
if($account_id !== false) {
# echo "Account=$account_id Product=$product_id Service=$service_id<br />";
# Retrieve the correct rate table
$rt =& $this->c_load_rating_table($db, $product_id);
if(is_resource($rt)) {
# Rate the call
$src = $isInbound ? $rs->fields['dst'] : $rs->fields['src'];
$dst = $isInbound ? $rs->fields['src'] : $rs->fields['dst'];
if($match=agileco_search_rate_table($rt, strval($dst), intval($rs->fields['billsec']),
intval($isInbound), strval($callSQL))) {
#echo "<pre>";
#echo "SRC=".$src."\n";
#echo "DST=".strval($dst)."\n";
#echo "BILLSEC=".intval($rs->fields['billsec'])."\n";
#echo "In Bound?=".intval($isInbound)."\n";
#echo "Call Type=".$calltype."\n";
#echo "callSQL=".$callSQL."\n\n";
#echo print_r($match,true);
#echo "\n";
#echo "</pre>";
} else {
#echo "SRC=".$src."\n";
#echo "DST=".strval($dst)."\n";
#echo "BILLSEC=".intval($rs->fields['billsec'])."\n";
#echo "In Bound?=".intval($isInbound)."\n";
#echo "Call Type=".$calltype."\n";
#echo 'Returned false.'."\n\n";
$match['amount'] = 0;
$match['quantity'] = 0;
$match['unit'] = 0;
$match['voip_rate_id'] = 0;
}
$rated=1;
} else {
echo "Product $product_id does not have a rating table.\n";
}
} else {
$isInbound = 0; $account_id = 0; $calltype=0; $rated = 3;
}
if(isset($match)) {
$total += $match['amount'];
$sql = "update ".AGILE_DB_PREFIX."voip_cdr SET
account_id=".$db->qstr($account_id).",
amount=".$db->qstr($match['amount']).",
calltype=".$db->qstr($calltype).",
voip_rate_id=".$db->qstr($match['voip_rate_id']).",
rated={$rated},
adjbillinterval=".$db->qstr($match['quantity']).",
site_id=".DEFAULT_SITE."
WHERE id=".$rs->fields['id'];
#echo $sql."\n";
if (!$db->Execute($sql)) {
echo $sql."\n";
echo $db->ErrorMsg()."\n";
}
$a = 'Source=='.$rs->fields['src'].'\r\nDestination=='.$rs->fields['dst'];
$a .= '\r\nvoip_cdr_id=='.$rs->fields['id'].'\r\ndate_orig=='.$rs->fields['date_orig'];
if (isset($match['connect_fee']) && $match['connect_fee']) {
$b = $a.'\r\nConnection Charge';
$cid = sqlGenID($db, "charge");
$sql = "INSERT INTO ".AGILE_DB_PREFIX."charge SET
id=".$db->qstr($cid).",
side_id=".DEFAULT_SITE.",
date_orig=.".$db->qstr($rs->fields['date_orig']).",
status=0,
sweep_type=6,
product_id=".$db->qstr($product_id).",
service_id=".$db->qstr($service_id).",
amount=".$db->qstr($match['connect_fee']).",
quantity=1,
taxable=0,
attributes=".$db->qstr($b);
if (!$db->Execute($sql)) {
echo $sql."\n";
echo $db->ErrorMsg()."\n";
}
}
if ($match['quantity'] > 0) {
$cid = sqlGenID($db, "charge");
$sql = "INSERT INTO ".AGILE_DB_PREFIX."charge SET
id=".$db->qstr($cid).",
site_id=".DEFAULT_SITE.",
date_orig=".$db->qstr($rs->fields['date_orig']).",
status=0,
sweep_type=6,
product_id=".$db->qstr($product_id).",
service_id=".$db->qstr($service_id).",
amount=".$db->qstr($match['unit']).",
quantity=".$db->qstr($match['quantity']).",
taxable=0,
attributes=".$db->qstr($a);
if (!$db->Execute($sql)) {
echo $sql."\n";
echo $db->ErrorMsg()."\n";
}
}
}
$i++;
$rs->MoveNext();
}
$et = $this->microtime_float();
$tt = $et - $st;
echo "Rated {$i} entries in {$tt} seconds.<br><br>";
echo "Cough up $".number_format($total,4)."!<br>";
}
/** Loads the rate table associated with a product.
* @param $db A database connection handle
* @param $product_id The ID of the product to load.
*/
function & c_load_rating_table(&$db, $product_id)
{
static $rate_cache;
/* Is the rate already cached? */
if(isset($rate_cache[$product_id])) {
return $rate_cache[$product_id];
}
/* Cache Miss. Generate the entry. */
$db =& DB();
$rate_cache[$product_id] = agileco_new_rate_table();
$i = 0; $st = $this->microtime_float();
$sql = "SELECT b.id, b.connect_fee, b.increment_seconds, b.amount, b.pattern, b.type, b.direction, b.min, b.max, b.combine, b.percall, b.seconds_included FROM ".AGILE_DB_PREFIX."voip_rate_prod a left join ".AGILE_DB_PREFIX."voip_rate b on (a.voip_rate_id=b.id and a.site_id=".DEFAULT_SITE.") WHERE product_id=".$product_id." ORDER BY type ASC";
#echo $sql."\n";
$rs = $db->Execute($sql);
while (!$rs->EOF) {
$pattern = preg_replace("/[^0-9;]/","",$rs->fields['pattern']);
$pattern = str_replace("\r","",str_replace("\n","",$pattern));
$pats = explode(";",$pattern);
foreach($pats as $pat) {
agileco_rate_table_insert(
$rate_cache[$product_id],
$pat,
intval($rs->fields['id']),
floatval($rs->fields['connect_fee']),
intval($rs->fields['increment_seconds']),
intval($rs->fields['seconds_included']),
floatval($rs->fields['amount']),
intval($rs->fields['min']),
intval($rs->fields['max']),
intval($rs->fields['type']),
intval($rs->fields['direction']),
intval($rs->fields['combine']),
intval($rs->fields['percall'])
);
++$i;
}
$rs->MoveNext();
}
$et = $this->microtime_float(); $tt = $et - $st;
echo "Loaded {$i} patterns for product {$product_id} in {$tt} seconds.<br />\n";
return $rate_cache[$product_id];
}
}
#
# C MODULE FUNCTIONS FOLLOW BELOW
#
// NOTE: I didn't include this in the class because it is known to be faster to call
// a function, than a method of a class.
function find_owner($did, &$account_id, &$service_id, &$product_id, &$callSQL) {
static $owners;
if(isset($owners[$did])) {
$account_id = $owners[$did]['account_id'];
$service_id = $owners[$did]['service_id'];
$product_id = $owners[$did]['product_id'];
$callSQL = $owners[$did]['callSQL'];
return true;
}
$db =& DB();
#$sql = "SELECT id FROM ab_account WHERE username=".$db->qstr($did)." and site_id=".DEFAULT_SITE;
$sql = "select A.account_id, A.service_id, B.product_id, B.date_last_invoice, B.date_next_invoice
from ".AGILE_DB_PREFIX."voip_did A inner join ".AGILE_DB_PREFIX."service B on (B.id=A.service_id)
where did=".$db->qstr($did)." and A.site_id=".DEFAULT_SITE." and B.site_id=".DEFAULT_SITE;
#echo $sql."<br>";
$row = $db->GetRow($sql);
if($row === false || !isset($row[0])) {
$account_id = false;
$service_id = false;
$product_id = false;
$callSQL = "";
return false;
}
$account_id = $row[0];
$service_id = $row[1];
$product_id = $row[2];
$row[3] = $row[3] - (MAX_INV_GEN_PERIOD*86400);
$row[4] = $row[4] + 86399;
$callSQL = "((src=".$db->qstr($did)." or dst=".$db->qstr($did).") and ";
$callSQL .= "date_orig>=".$db->qstr($row[3])." and date_orig<=".$db->qstr($row[4]).")";
$owners[$did]['account_id'] = $row[0];
$owners[$did]['service_id'] = $row[1];
$owners[$did]['product_id'] = $row[2];
$owners[$did]['callSQL'] = $callSQL;
return true;
}
function agileco_php_in_network($did) {
$db =& DB();
$sql = "select count(*) from ".AGILE_DB_PREFIX."voip_in_network where did in ('".$did."')";
#echo $sql."\n";
$rs2 = $db->Execute($sql);
if ($rs2->fields[0] > 0) {
#echo "Yes, call is local.\n";
return 1;
}
return 0;
}
function agileco_php_local_call($dst) {
global $src;
$voip = new voip;
$cc1 = ""; $npa1 = ""; $nxx1 = "";
$cc2 = ""; $npa2 = ""; $nxx2 = "";
$e164 = "";
if ($voip->e164($src,$e164,$cc1,$npa1,$nxx1)) {
if ($voip->e164($dst,$e164,$cc2,$npa2,$nxx2)) {
$sql = "select t1.grouping as id1, t2.grouping from ".AGILE_DB_PREFIX."voip_local_lookup as t1 join ".AGILE_DB_PREFIX."voip_local_lookup as t2 on (t1.npa='$npa1' and t1.nxx='$nxx1' and t2.npa='$npa2' and t2.nxx='$nxx2') where t1.grouping=t2.grouping";
echo $sql."\n";
$rs = $db->Execute($sql);
if ($rs->fields[0] > 0) {
return 1;
}
}
}
return 0;
}
function agileco_php_minutes_used($voip_did_id, $callSQL) {
$db =& DB();
$sql = "select sum(adjbillinterval) from ".AGILE_DB_PREFIX."voip_cdr where voip_rate_id={$voip_did_id} and {$callSQL}";
$rst = $db->Execute($sql);
$num = intval($rst->fields[0]);
echo 'Customer has '.$num.' minutes used.<br>';
return $num;
}
?>