and Thralling Penguin, LLC * @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 "
".print_r($this->data,true)."
"; 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)."
date2=".date('Ymd',$date2)."
"; 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
"; #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 "
".print_r($r, true)."
"; 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!
'; 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\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 = ''; 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 = ''; 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 "
".print_r($areas,true)."
"; $areas_seen = array(); $js = ''; 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."
"; $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']."
"; #echo "esrc=".$src." edst=".$dst."

"; #$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."
"; $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 = explode(";", $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
"; # 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 "
";
						#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 "
"; } 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.

"; echo "Cough up $".number_format($total,4)."!
"; } /** 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.
\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."
"; $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.
'; return $num; } ?>