Page MenuHomePhabricator

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/library/cdr_opensips.php b/library/cdr_opensips.php
index abfd021..3bdcae2 100644
--- a/library/cdr_opensips.php
+++ b/library/cdr_opensips.php
@@ -1,5577 +1,5595 @@
<?
class CDRS_opensips extends CDRS {
var $table = "radacct";
var $CDR_class = "CDR_opensips";
var $subscriber_table = "subscriber";
var $ENUMtld = '';
var $maxCDRsNormalizeWeb = 500;
var $sipTrace = 'sip_trace';
var $mediaTrace = 'media_trace';
var $missed_calls_group = 'missed-calls';
var $rate_on_net_group = 'rate-on-net';
var $callerid_cache = array();
var $CDRFields=array('id' => 'RadAcctId',
'callId' => 'AcctSessionId',
'duration' => 'AcctSessionTime',
'startTime' => 'AcctStartTime',
'stopTime' => 'AcctStopTime',
'inputTraffic' => 'AcctInputOctets',
'outputTraffic' => 'AcctOutputOctets',
'flow' => 'ServiceType',
'aNumber' => 'CallingStationId',
'username' => 'UserName',
'domain' => 'Realm',
'cNumber' => 'CalledStationId',
'timestamp' => 'timestamp',
'SipMethod' => 'SipMethod',
'disconnect' => 'SipResponseCode',
'SipFromTag' => 'SipFromTag',
'SipToTag' => 'SipToTag',
'RemoteAddress' => 'SipTranslatedRequestURI',
'SipCodec' => 'SipCodecs',
'SipUserAgents' => 'SipUserAgents',
'application' => 'SipApplicationType',
'BillingPartyId' => 'UserName',
'SipRPID' => 'SipRPID',
'SipProxyServer' => 'NASIPAddress',
'gateway' => 'SourceIP',
'SourceIP' => 'SourceIP',
'SourcePort' => 'SourcePort',
'CanonicalURI' => 'CanonicalURI',
'normalized' => 'Normalized',
'rate' => 'Rate',
'price' => 'Price',
'DestinationId' => 'DestinationId',
'ResellerId' => 'BillingId',
'MediaInfo' => 'MediaInfo',
'RTPStatistics' => 'RTPStatistics',
'ENUMtld' => 'ENUMtld',
'UserAgent' => 'UserAgent',
'FromHeader' => 'FromHeader'
);
var $CDRNormalizationFields=array('id' => 'RadAcctId',
'callId' => 'AcctSessionId',
'username' => 'UserName',
'domain' => 'Realm',
'gateway' => 'SourceIP',
'duration' => 'AcctSessionTime',
'startTime' => 'AcctStartTime',
'stopTime' => 'AcctStopTime',
'inputTraffic' => 'AcctInputOctets',
'outputTraffic' => 'AcctOutputOctets',
'aNumber' => 'CallingStationId',
'cNumber' => 'CalledStationId',
'timestamp' => 'timestamp',
'disconnect' => 'SipResponseCode',
'RemoteAddress' => 'SipTranslatedRequestURI',
'CanonicalURI' => 'CanonicalURI',
'SipRPID' => 'SipRPID',
'SipMethod' => 'SipMethod',
'application' => 'SipApplicationType',
'flow' => 'ServiceType',
'BillingPartyId' => 'UserName',
'ResellerId' => 'BillingId',
'price' => 'Price',
'DestinationId' => 'DestinationId',
'ENUMtld' => 'ENUMtld'
);
var $GROUPBY=array('UserName' => 'SIP Billing Party',
'CallingStationId' => 'SIP Caller Party',
'SipRPID' => 'SIP Remote Party Id',
'CanonicalURI' => 'SIP Canonical URI',
'DestinationId' => 'SIP Destination Id',
'NASIPAddress' => 'SIP Proxy',
'MediaInfo' => 'Media Information',
'SourceIP' => 'Source IP',
'Realm' => 'SIP Billing domain',
'UserAgent' => 'User Agent',
'SipCodecs' => 'Codec type',
'SipApplicationType' => 'Application',
'SipResponseCode' => 'SIP status code',
'BillingId' => 'Tech prefix',
'ServiceType' => 'Call Flow',
' ' => '-------------',
'hour' => 'Hour of day',
'DAYOFWEEK' => 'Day of Week',
'DAYOFMONTH' => 'Day of Month',
'DAYOFYEAR' => 'Day of Year',
'BYMONTH' => 'Month',
'BYYEAR' => 'Year'
);
var $FormElements=array(
"begin_hour","begin_min","begin_month","begin_day","begin_year","begin_datetime",
"end_hour","end_min","end_month","end_day","end_year","end_datetime",
"call_id","sip_proxy",
"a_number","a_number_comp","UserName","UserName_comp","BillingId",
"c_number","c_number_comp","DestinationId","ExcludeDestinations",
"NASPortId","Realm","Realms",
"SipMethod","SipCodec","SipRPID","UserAgent",
"application","sip_status","sip_status_class","gateway",
"duration","action","MONTHYEAR",
"order_by","order_type","group_by",
"cdr_source","trace",
"ReNormalize","media_info","cdr_table","maxrowsperpage", "flow"
);
function initCDRFields() {
// init names of CDR fields
foreach (array_keys($this->CDRFields) as $field) {
$mysqlField=$this->CDRFields[$field];
$_field=$field."Field";
$this->$_field=$mysqlField;
}
}
function LoadDisconnectCodes() {
$query="select * from sip_status order by code";
$this->disconnectCodesElements[]=array("label"=>"Any Status","value"=>"");
$this->disconnectCodesElements[]=array("label"=>"Undefined (0)","value"=>"0");
$this->disconnectCodesClassElements[]=array("label"=>"Any Status Class","value"=>"");
if ($this->cdrtool->query($query)) {
while($this->cdrtool->next_record()) {
$key = $this->cdrtool->f('code');
$value = $this->cdrtool->f('description');
$value_print = $this->cdrtool->f('description')." (".$this->cdrtool->f('code').")";
if (preg_match("/^[^2-6]/",$key)) {
continue;
}
$this->disconnectCodesElements[]=array("label"=>$value_print,"value"=>$key);
$this->disconnectCodesDescription[$key]=$value;
$class=substr($key,0,1);
$class_text=substr($key,0,1)."XX (".$this->cdrtool->f('code_type').")";
if (!$seen[$class]) {
$this->disconnectCodesClassElements[]=array("label"=>$class_text,"value"=>substr($key,0,1));
$this->disconnectCodesClassDescription[substr($key,0,1)]=$class_text;
$seen[$class]++;
}
$i++;
}
}
}
function showTableHeader() {
print "
<table class='table table-hover table-condensed'>
<thead>
<tr>
<th>Id</th>
<th>Start Time</th>
<th>Flow</th>
<th>SIP Caller</th>
<th>Caller Location</th>
<th>Sip Proxy</th>
<th>Media</th>
<th>SIP Destination</th>
<th>Dur</th>
<th>Price</th>
<th>KBIn</th>
<th>KBOut</th>
<th>Codecs</th>
<th class='pull-right'>Status</th>
</tr>
</thead>
";
}
function showExportHeader() {
print "id,StartTime,StopTime,BillingParty,BillingDomain,PSTNCallerId,CallerParty,CalledParty,DestinationId,DestinationName,RemoteAddress,CanonicalURI,Duration,Price,SIPProxy,Caller KBIn,Called KBIn,CallingUserAgent,CalledUserAgent,StatusCode,StatusName,Codec,Media\n";
}
function showTableHeaderSubscriber() {
if (!$this->export) {
print "
<table class='table table-striped table-condensed'>
<thead>
<tr>
<th>Id</th>
<th>Start Time</th>
<th>SIP Caller</th>
<th>Caller Location</th>
<th>Sip Proxy</th>
<th>SIP Destination</th>
<th>Duration</th>
<th>Price</th>
<th>KBIn</th>
<th>KBOut</th>
</tr>
</thead>
";
} else {
print "id,StartTime,StopTime,SIPBillingParty,SIPBillingDomain,RemotePartyId,CallerParty,CalledParty,DestinationId,DestinationName,RemoteAddress,CanonicalURI,Duration,Price,SIPProxy,Applications,Caller KBIn,Called KBIn,CallingUserAgent,CalledUserAgent,StatusCode,StatusName,Codec,Application\n";
}
}
function showTableHeaderStatistics() {
$group_byPrint=$this->GROUPBY[$this->group_byOrig];
if (!$this->export) {
print "
<table class='table table-striped table-condensed'>
<thead>
<tr>
<th></th>
<th>Calls</th>
<th>Seconds</th>
<th>Minutes</th>
<th>Hours</th>
<th>Price</th>
<th>TrafficIn(MB)</th>
<th>TrafficOut(MB)</th>
<th colspan=2>Success</th>
<th colspan=2>Failure</th>
<th>$group_byPrint</th>
<th>Description</th>
<th>Action</th>
</tr>
</thead>
";
} else {
print "id,Calls,Seconds,Minutes,Hours,Price,TrafficIn(MB),TrafficOut(MB),Success(%),Success(calls),Failure(%),Failure(calls),$group_byPrint,Description\n";
}
}
function initForm() {
// form els added below must have global vars
foreach ($this->FormElements as $_el) {
global ${$_el};
${$_el} = trim($_REQUEST[$_el]);
}
$action = "search";
if ($this->CDRTool['filter']['gateway']) {
$gateway=$this->CDRTool["filter"]["gateway"];
}
if ($this->CDRTool['filter']['aNumber']) {
$UserName=$this->CDRTool['filter']['aNumber'];
}
if ($this->CDRTool['filter']['domain']) {
$Realm = $this->CDRTool['filter']['domain'];
}
if (!$maxrowsperpage) $maxrowsperpage=15;
$this->f = new form;
if (isset($this->CDRTool['dataSourcesAllowed'])) {
while (list($k,$v)=each($this->CDRTool['dataSourcesAllowed'])) {
if ($this->DATASOURCES[$v]['invisible']) continue;
$cdr_source_els[]=array("label"=>$this->DATASOURCES[$v]['name'],"value"=>$v);
}
}
if (!$cdr_source) $cdr_source=$cdr_source_els[0]['value'];
$this->f->add_element(array("name"=>"cdr_source",
"type"=>"select",
"options"=>$cdr_source_els,
"size"=>"1",
"extrahtml"=>"class=span2 onChange=\"document.datasource.submit.disabled = true; location.href = 'callsearch.phtml?cdr_source=' + this.options[this.selectedIndex].value\"",
"value"=>"$cdr_source"
)
);
$cdr_table_els=array();
foreach ($this->tables as $_table) {
if (preg_match("/^.*(\d{6})$/",$_table,$m)) {
$cdr_table_els[]=array("label"=>$m[1],"value"=>$_table);
} else {
$cdr_table_els[]=array("label"=>$_table,"value"=>$_table);
}
}
$this->f->add_element(array( "name"=>"cdr_table",
"type"=>"select",
"options"=>$cdr_table_els,
"size"=>"1",
"class"=>"span2",
"value"=>$cdr_table,
"extrahtml"=>"class=span2"
));
if ($begin_datetime) {
preg_match("/^(\d\d\d\d)-(\d+)-(\d+)\s+(\d\d):(\d\d)/", "$begin_datetime", $parts);
$begin_year =date(Y,$begin_datetime);
$begin_month=date(m,$begin_datetime);
$begin_day =date(d,$begin_datetime);
$begin_hour =date(H,$begin_datetime);
$begin_min =date(i,$begin_datetime);
} else {
$begin_day = $_REQUEST["begin_day"];
$begin_month = $_REQUEST["begin_month"];
$begin_year = $_REQUEST["begin_year"];
$begin_hour = $_REQUEST["begin_hour"];
$begin_min = $_REQUEST["begin_min"];
}
if ($end_datetime) {
preg_match("/^(\d\d\d\d)-(\d+)-(\d+)\s+(\d\d):(\d\d)/", "$end_datetime", $parts);
$end_year =date(Y,$end_datetime);
$end_month =date(m,$end_datetime);
$end_day =date(d,$end_datetime);
$end_hour =date(H,$end_datetime);
$end_min =date(i,$end_datetime);
} else {
$end_day = $_REQUEST["end_day"];
$end_month = $_REQUEST["end_month"];
$end_year = $_REQUEST["end_year"];
$end_hour = $_REQUEST["end_hour"];
$end_min = $_REQUEST["end_min"];
}
// corect last day of the month to be valid day
$begin_day = validDay($begin_month,$begin_day,$begin_year);
$end_day = validDay($end_month,$end_day,$end_year);
$default_year = Date("Y");
$default_month = Date("m");
$default_day = Date("d");
$default_hour = Date(H,time());
if ($default_hour > 1) $default_hour=$default_hour-1;
$default_hour = preg_replace("/^(\d)$/","0$1",$default_hour);
$default_min = Date("i");
if ($default_min > 10) {
$default_min=$default_min-10;
$default_min=preg_replace("/^(\d)$/","0$1",$default_min);
}
if (!$begin_hour) $begin_hour = $default_hour;
if (!$begin_min) $begin_min = $default_min;
if (!$begin_day) $begin_day = $default_day;
if (!$begin_month) $begin_month = $default_month;
if (!$begin_year) $begin_year = $default_year;
if (!$end_hour) $end_hour = 23;
if (!$end_min) $end_min = 55;
if (!$end_day) $end_day = $default_day;
if (!$end_month) $end_month = $default_month;
if (!$end_year) $end_year = $default_year;
$m=0;
while ($m<24) {
if ($m<10) { $v="0".$m; } else { $v=$m; }
$hours_els[]=array("label"=>$v,"value"=>$v);
$m++;
}
$this->f->add_element(array(
"name"=>"begin_hour",
"type"=>"select",
"options"=>$hours_els,
"size"=>"1",
"extrahtml"=>"class=span1"
));
$this->f->add_element(array( "name"=>"end_hour",
"type"=>"select",
"options"=>$hours_els,
"size"=>"1",
"value"=>"23",
"extrahtml"=>"class=span1"
));
$m=0;
while ($m<60) {
if ($m<10) { $v="0".$m; } else { $v=$m; }
$min_els[]=array("label"=>$v,"value"=>$v);
$m++;
}
$this->f->add_element(array( "name"=>"begin_min",
"type"=>"select",
"options"=>$min_els,
"size"=>"1",
"extrahtml"=>"class=span1"
));
$this->f->add_element(array(
"name"=>"end_min",
"type"=>"select",
"options"=>$min_els,
"size"=>"1",
"extrahtml"=>"class=span1"
));
$m=1;
while ($m<32) {
if ($m<10) { $v="0".$m; } else { $v=$m; }
$days_els[]=array("label"=>$v,"value"=>$v);
$m++;
}
$this->f->add_element(array( "name"=>"begin_day",
"type"=>"select",
"options"=>$days_els,
"size"=>"1",
"extrahtml"=>"class=span1"
));
$this->f->add_element(array( "name"=>"end_day",
"type"=>"select",
"options"=>$days_els,
"size"=>"1",
"extrahtml"=>"class=span1"
));
$m=1;
while ($m<13) {
if ($m<10) { $v="0".$m; } else { $v=$m; }
$month_els[]=array("label"=>$v,"value"=>$v);
$m++;
}
$this->f->add_element(array( "name"=>"begin_month",
"type"=>"select",
"options"=>$month_els,
"size"=>"1",
"extrahtml"=>"class=span1"
));
$this->f->add_element(array( "name"=>"end_month",
"type"=>"select",
"options"=>$month_els,
"size"=>"1",
"extrahtml"=>"class=span1"
));
$thisYear=date("Y",time());
$y=$thisYear;
while ($y>$thisYear-6) {
$year_els[]=array("label"=>$y,"value"=>$y);
$y--;
}
$this->f->add_element(array( "name"=>"begin_year",
"type"=>"select",
"options"=>$year_els,
"size"=>"1",
"extrahtml"=>"class=span2"
));
$this->f->add_element(array( "name"=>"end_year",
"type"=>"select",
"options"=>$year_els,
"size"=>"1",
"extrahtml"=>"class=span2"
));
$this->f->add_element(array( "name"=>"call_id",
"type"=>"text",
"size"=>"50",
"maxlength"=>"100",
"extrahtml"=>"class=span4"
));
$this->f->add_element(array( "name"=>"UserName",
"type"=>"text",
"size"=>"25",
"maxlength"=>"255",
"extrahtml"=>"class=span2"
));
$this->f->add_element(array( "name"=>"a_number",
"type"=>"text",
"size"=>"25",
"maxlength"=>"255",
"extrahtml"=>"class=span2"
));
$this->f->add_element(array( "name"=>"BillingId",
"type"=>"text",
"size"=>"25",
"maxlength"=>"255",
"extra_html"=>"class=span2"
));
$this->f->add_element(array( "name"=>"c_number",
"type"=>"text",
"size"=>"25",
"maxlength"=>"255",
"extrahtml"=>"class=span2"
));
$this->f->add_element(array( "name"=>"sip_status",
"type"=>"select",
"options"=>$this->disconnectCodesElements,
"size"=>"1",
"value"=>$sip_status,
"extrahtml"=>"class=span3"
));
$this->f->add_element(array( "name"=>"sip_status_class",
"type"=>"select",
"options"=>$this->disconnectCodesClassElements,
"size"=>"1",
"extrahtml"=>"class=span3"
));
if (!$this->CDRTool['filter']['aNumber']) {
$durations_els = array(
array("label"=>"All calls","value"=>""),
array("label"=>"0 seconds","value"=>"zero"),
array("label"=>"non 0 seconds","value"=>"nonzero"),
array("label"=>"non 0 seconds without price","value"=>"zeroprice"),
array("label"=>"less than 5 seconds","value"=>"< 5"),
array("label"=>"more than 5 seconds","value"=>"> 5"),
array("label"=>"less than 60 seconds","value"=>"< 60"),
array("label"=>"greater than 1 hour","value"=>"> 3600"),
array("label"=>"one hour","value"=>"onehour"),
array("label"=>"greater than 5 hours","value"=>"> 18000"),
array("label"=>"Un-normalized calls","value"=>"unnormalized"),
array("label"=>"Un-normalized calls > 0s","value"=>"unnormalized_duration"),
array("label"=>"One way media","value"=>"onewaymedia"),
array("label"=>"No media","value"=>"nomedia")
);
} else {
$durations_els = array(
array("label"=>"All calls","value"=>""),
array("label"=>"0 seconds call","value"=>"zero"),
array("label"=>"Succesfull calls","value"=>"nonzero"),
array("label"=>"less than 60 seconds","value"=>"< 60"),
array("label"=>"greater than 1 hour","value"=>"> 3600")
);
$this->GROUPBY=array(
'UserName' => 'SIP Billing Party',
'CallingStationId' => 'SIP Caller Party',
'DestinationId' => 'SIP Destination Id',
'SipApplicationType' => 'Application',
' ' => '-------------',
'hour' => 'Hour of day',
'DAYOFWEEK' => 'Day of Week',
'DAYOFMONTH' => 'Day of Month',
'DAYOFYEAR' => 'Day of Year',
'BYMONTH' => 'Month',
'BYYEAR' => 'Year'
);
}
$flow_els = array(
array("label"=>"Any Call Flow","value"=>""),
array("label"=>"On Net","value"=>"on-net"),
array("label"=>"Incoming","value"=>"incoming"),
array("label"=>"Outgoing","value"=>"outgoing"),
array("label"=>"Transit","value"=>"transit"),
array("label"=>"Diverted On Net","value"=>"diverted-on-net"),
array("label"=>"Diverted Off Net","value"=>"diverted-off-net"),
array("label"=>"On Net Diverted On Net","value"=>"on-net-diverted-on-net"),
array("label"=>"On Net Diverted Off Net","value"=>"on-net-diverted-off-net"),
array("label"=>"Unknown Flow","value"=>"Sip-Session")
);
$this->f->add_element(array( "name"=>"flow",
"type"=>"select",
"options"=>$flow_els,
"value"=>"",
"size"=>"1",
"extrahtml"=>"class=span3"
));
$this->f->add_element(array( "name"=>"duration",
"type"=>"select",
"options"=>$durations_els,
"value"=>"All",
"size"=>"1",
"extrahtml"=>"class=span3"
));
$comp_ops_els = array(
array("label"=>"Begins with","value"=>"begin"),
array("label"=>"Contains","value"=>"contain"),
array("label"=>"Is empty","value"=>"empty"),
array("label"=>"Equal","value"=>"equal")
);
$this->f->add_element(array( "name"=>"a_number_comp",
"type"=>"select",
"options"=>$comp_ops_els,
"value"=>"begin",
"size"=>"1",
"extrahtml"=>"class=span2"
));
$this->f->add_element(array( "name"=>"c_number_comp",
"type"=>"select",
"options"=>$comp_ops_els,
"value"=>"begin",
"size"=>"1",
"extrahtml"=>"class=span2"
));
$this->f->add_element(array( "name"=>"UserName_comp",
"type"=>"select",
"options"=>$comp_ops_els,
"value"=>"begin",
"size"=>"1",
"extrahtml"=>"class=span2"
));
$this->f->add_element(array( "name"=>"Realm",
"type"=>"text",
"size"=>"25",
"maxlength"=>"25",
"extrahtml"=>"class=span2"
));
$media_info_els=array(
array("label"=>"","value"=>""),
array("label"=>"Timeout","value"=>"timeout"),
array("label"=>"ICE session","value"=>"ICE session")
);
$this->f->add_element(array( "name"=>"media_info",
"type"=>"select",
"options"=>$media_info_els,
"size"=>"1",
"value"=>"",
"extrahtml"=>"class=span2"
));
$this->f->add_element(array("type"=>"submit",
"name"=>"submit",
"value"=>"Search","extrahtml"=>"class=btn"
));
$max_els=array(
array("label"=>"5","value"=>"5"),
array("label"=>"10","value"=>"10"),
array("label"=>"15","value"=>"15"),
array("label"=>"25","value"=>"25"),
array("label"=>"50","value"=>"50"),
array("label"=>"100","value"=>"100"),
array("label"=>"500","value"=>"500")
);
$this->f->add_element(array( "name"=>"maxrowsperpage",
"type"=>"select",
"options"=>$max_els,
"size"=>"1",
"value"=>"25",
"extrahtml"=>"class=span2"
));
$order_type_els=array(
array("label"=>"Descending","value"=>"DESC"),
array("label"=>"Ascending","value"=>"ASC")
);
$this->f->add_element(array( "name"=>"order_type",
"type"=>"select",
"options"=>$order_type_els,
"size"=>"1",
"extrahtml"=>"class=span2"
));
$this->f->add_element(array("type"=>"hidden",
"name"=>"action",
"value"=>$action
));
$order_by_els=array(array("label"=>"Id","value"=>"RadAcctId"),
array("label"=>"Date","value"=>"AcctStopTime"),
array("label"=>"Billing Party","value"=>"UserName"),
array("label"=>"Remote Party Id","value"=>"SipRPID"),
array("label"=>"Caller Party","value"=>"CallingStationId"),
array("label"=>"Destination","value"=>"CalledStationId"),
array("label"=>"Duration","value"=>"AcctSessionTime"),
array("label"=>"Input traffic","value"=>"AcctInputOctets"),
array("label"=>"Output traffic","value"=>"AcctOutputOctets"),
array("label"=>"Price","value"=>"Price"),
array("label"=>"Failures(%)","value"=>"zeroP"),
array("label"=>"Success(%)","value"=>"nonzeroP"),
array("label"=>"Group by","value"=>"group_by")
);
$group_by_els[]=array("label"=>"","value"=>"");
while (list($k,$v)=each($this->GROUPBY)) {
$group_by_els[]=array("label"=>$v,"value"=>$k);
}
$this->f->add_element(array("name"=>"order_by",
"type"=>"select",
"options"=>$order_by_els,
"value"=>$order_by,
"size"=>"1",
"extrahtml"=>"class=span3"
));
$this->f->add_element(array("name"=>"group_by",
"type"=>"select",
"options"=>$group_by_els,
"value"=>$group_by,
"size"=>"1",
"extrahtml"=>"class=span3"
));
$application_els=array(
array("label"=>"Any Application", "value"=>""),
array("label"=>"Audio", "value"=>"audio"),
array("label"=>"Video", "value"=>"video"),
array("label"=>"Message" , "value"=>"message"),
array("label"=>"IM Chat" , "value"=>"chat"),
array("label"=>"Audio + Chat" , "value"=>"audio=2C chat"),
array("label"=>"File Transfer","value"=>"file-transfer")
);
$this->f->add_element(array("name"=>"application",
"type"=>"select",
"options"=>$application_els,
"value"=>$application,
"size"=>"1",
"extrahtml"=>"class=span2"
));
$this->f->add_element(array("name"=>"UserAgent",
"type"=>"text",
"size"=>"25",
"maxlength"=>"50",
"value"=>$UserAgent,
"extrahtml"=>"class=span2"
));
$this->f->add_element(array("name"=>"SipCodec",
"type"=>"text",
"size"=>"10",
"maxlength"=>"50",
"value"=>$SipCodec,
"extrahtml"=>"class=span2"
));
$this->f->add_element(array("name"=>"sip_proxy",
"type"=>"text",
"size"=>"25",
"maxlength"=>"255",
"value"=>$sip_proxy,
"extrahtml"=>"class=span2"
));
$this->f->add_element(array("name"=>"gateway",
"type"=>"text",
"size"=>"25",
"maxlength"=>"255",
"value"=>$gateway,
"extrahtml"=>"class=span2"
));
$this->f->add_element(array("name"=>"DestinationId",
"type"=>"text",
"size"=>"10",
"extrahtml"=>"class=span3"
));
$this->f->add_element(array( "name"=>"ExcludeDestinations",
"type"=>"text",
"size"=>"20",
"maxlength"=>"255",
"extrahtml"=>"class=span3"
));
$this->f->load_defaults();
}
function searchForm() {
global $perm;
$this->initForm();
$this->f->start("","POST","","","datasource");
print "<table id='search' class='table table-bordered table-condensed' cellpadding=5 width=100% align=center>";
$this->showDataSources ($this->f);
$this->showDateTimeElements ($this->f);
// freeze some form els
if ($this->CDRTool['filter']['aNumber']) {
$ff[]="a_number";
$ff[]="a_number_comp";
$ff[]="UserName";
$ff[]="UserName_comp";
}
if ($this->CDRTool['filter']['domain']) {
$Realm=$this->CDRTool['filter']['domain'];
$ff[]="Realm";
}
if ($this->CDRTool['filter']['gateway']) {
$gateway=$this->CDRTool['filter']['gateway'];
$ff[]="gateway";
}
if (count($ff)) {
$this->f->freeze($ff);
}
print "
<tr>
<td align=left>
<b>SIP Call Id / Source IP</b>
</td>
<td>
<div class=\"input-prepend\">
<div class=\"input-append\">";
$this->f->show_element("call_id","");
print "<span class=\"add-on\">/</span></div>";
$this->f->show_element("gateway","");
print "</div>
Sip Proxy ";
$this->f->show_element("sip_proxy","");
print "
</td>
</tr>
<tr>
</tr>
";
print "
<tr>
<td align=left>
<b>User Agent / Media Codecs</b>
</td>
<td >
";
$this->f->show_element("UserAgent","");
print " Codec: ";
$this->f->show_element("SipCodec","");
print "
</td>
</tr>
<tr>
</tr>
";
print "
<tr>
<td align=left>
<b>SIP Billing Party (Username)</b>
</td>
<td>
";
$this->f->show_element("UserName_comp","");
print "
<div class=\"input-prepend\">
<div class=\"input-append\">
";
$this->f->show_element("UserName","");
print "<span class=\"add-on\">@</span></div>";
$this->f->show_element("Realm","");
print "</div> Tech prefix: ";
$this->f->show_element("BillingId","");
print "</div>
</td>
</tr>
<tr>
</tr>
";
print "
<tr>
<td align=left>
<b>
SIP Caller Party (From URI)
</b>
</td>
<td valign=top>
";
$this->f->show_element("a_number_comp","");
print "&nbsp;";
$this->f->show_element("a_number");
print "
</td>
</tr>
<tr>
</tr>
";
print "
<tr>
<td align=left>
<b>SIP Destination (Canonical URI)
</b>
</td>
<td valign=top> ";
$this->f->show_element("c_number_comp","");
print "&nbsp;";
$this->f->show_element("c_number","");
print " Exclude: ";
$this->f->show_element("ExcludeDestinations_comp");
$this->f->show_element("ExcludeDestinations","");
print "
</td>
</tr>
<tr>
</tr>
";
print "
<tr>
<td align=left>
<b>Application / Call Flow</b>
</td>
<td valign=top> ";
$this->f->show_element("flow","");
print "&nbsp;";
$this->f->show_element("application","");
print " Media Info: ";
$this->f->show_element("media_info","");
print "
</td>
</tr>
";
print "
<tr>
<td align=left>
<b>Duration / Status</b>
</td>
<td valign=top> ";
$this->f->show_element("duration","");
print "&nbsp;";
$this->f->show_element("sip_status","");
print "&nbsp;";
$this->f->show_element("sip_status_class","");
print "
</td>
</tr>
";
print "
<tr>
<td align=left>
<b>Order by / Group by</b>
</td>
<td valign=top>
";
$this->f->show_element("order_by","");
print "&nbsp;";
$this->f->show_element("order_type","");
if ($perm->have_perm("statistics")) {
print " Group by ";
$this->f->show_element("group_by","");
}
print " Max results per page ";
$this->f->show_element("maxrowsperpage","");
print "</nobr>&nbsp";
if (!$perm->have_perm('readonly')) {
print ";&nbsp;&nbsp; <nobr>ReNormalize ";
print "<input type=checkbox name=ReNormalize value=1>
";
}
print "
</td>
</tr>
";
print "
</table>
<p>
<center>
";
$this->f->show_element("submit","");
$this->f->finish();
print "
</center>
";
}
function searchFormSubscriber() {
global $perm;
$this->initForm();
$this->f->start("","POST","","","datasource");
print "
<table id='search' class='table table-bordered table-condensed' cellpadding=5 width=100% align=center>
";
$this->showDataSources ($this->f);
$this->showDateTimeElements ($this->f);
// freeze some form els
if ($this->CDRTool['filter']['aNumber']) {
$ff[]="UserName";
}
if ($this->CDRTool['filter']['domain']) {
$ff[]="Realm";
}
if ($this->CDRTool["filter"]["gateway"]) {
$ff[]="gateway";
}
if (count($ff)) {
$this->f->freeze($ff);
}
print "
<tr>
<td align=left>
<b>
SIP Caller Party
</b>
</td>
<td valign=top>
";
$this->f->show_element("a_number","");
print "
</td>
</tr>
<tr>
</tr>
";
print "
<tr>
<td align=left>
<b>
SIP Billing Party
</b>
</td>
<td valign=top>
";
$this->f->show_element("UserName","");
print "
</td>
</tr>
<tr>
</tr>
";
print "
<tr>
<td align=left>
<b>
SIP Destination
</b>
</td>
<td valign=top> ";
$this->f->show_element("c_number_comp","");
$this->f->show_element("c_number","");
//$this->f->show_element("DestinationId","");
print "
</td>
</tr>
<tr>
</tr>
";
print "
<tr>
<td align=left>
<b>SIP Session duration</b>
</td>
<td valign=top> ";
$this->f->show_element("duration","");
print " Application ";
$this->f->show_element("application","");
print "
</td>
</tr>
";
print "
<tr>
<td align=left>
<b>Order by</b>
</td>
<td valign=top>
";
$this->f->show_element("order_by","");
$this->f->show_element("order_type","");
if ($perm->have_perm("statistics")) {
print " Group by ";
$this->f->show_element("group_by","");
}
print " Max results per page ";
$this->f->show_element("maxrowsperpage","");
print "
</td>
</tr>
";
print "
</table>
<p>
<center>
";
$this->f->show_element("submit","");
$this->f->finish();
print "
</center>
";
}
function show() {
global $perm;
if (!is_object($this->CDRdb)) {
$log=sprintf("Error: CDR database is not initalized");
print $log;
return false;
}
foreach ($this->FormElements as $_el) {
${$_el} = trim($_REQUEST[$_el]);
}
// overwrite some elements based on user rights
if ($this->CDRTool['filter']['gateway']) {
$gateway =$this->CDRTool['filter']['gateway'];
}
if (!$this->export) {
if (!$begin_datetime) {
$begin_datetime="$begin_year-$begin_month-$begin_day $begin_hour:$begin_min";
$begin_datetime_timestamp=mktime($begin_hour, $begin_min, 0, $begin_month,$begin_day,$begin_year);
} else {
$begin_datetime_timestamp=$begin_datetime;
$begin_datetime=Date("Y-m-d H:i",$begin_datetime);
}
if (!$end_datetime) {
$end_datetime_timestamp=mktime($end_hour, $end_min, 0, $end_month,$end_day,$end_year);
$end_datetime="$end_year-$end_month-$end_day $end_hour:$end_min";
} else {
$end_datetime_timestamp=$end_datetime;
$end_datetime=Date("Y-m-d H:i",$end_datetime);
}
} else {
$begin_datetime=Date("Y-m-d H:i",$begin_datetime);
$end_datetime=Date("Y-m-d H:i",$end_datetime);
}
if (!$order_by || (!$group_by && $order_by == "group_by")) {
$order_by=$this->idField;
}
if (!$cdr_table) $cdr_table=$this->table;
$this->url=sprintf("?cdr_source=%s&cdr_table=%s",$this->cdr_source,$cdr_table);
if ($this->CDRTool['filter']['domain']) {
$this->url .= sprintf("&Realms=%s",urlencode($this->CDRTool['filter']['domain']));
$Realms = explode(" ",$this->CDRTool['filter']['domain']);
} else if ($Realms) {
$this->url .= sprintf("&Realms=%s",urlencode($Realms));
$Realms = explode(" ",$Realms);
}
if ($this->CDRTool['filter']['aNumber']) {
$this->url .= sprintf("&UserName=%s",urlencode($this->CDRTool['filter']['aNumber']));
}
if ($this->CDRTool['filter']['after_date']) {
$where .= sprintf(" and %s >= '%s' ",addslashes($this->startTimeField),addslashes($this->CDRTool['filter']['after_date']));
}
if ($order_by) {
$this->url.=sprintf("&order_by=%s&order_type=%s",addslashes($order_by),addslashes($order_type));
}
$this->url.=sprintf("&begin_datetime=%s",urlencode($begin_datetime_timestamp));
$this->url.=sprintf("&end_datetime=%s",urlencode($end_datetime_timestamp));
if (!$call_id && $begin_datetime && $end_datetime) {
$where .= sprintf(" (%s >= '%s' and %s < '%s') ",addslashes($this->startTimeField),addslashes($begin_datetime),addslashes($this->startTimeField), addslashes($end_datetime));
} else {
$where .= sprintf(" (%s >= '1970-01-01' ) ",addslashes($this->startTimeField));
}
if ($MONTHYEAR) {
$where .= sprintf(" and %s like '%s%s' ", addslashes($this->startTimeField), addslashes($MONTHYEAR), '%');
$this->url.= sprintf("&MONTHYEAR=%s",urlencode($MONTHYEAR));
}
if ($flow) {
$this->url.=sprintf("&flow=%s",urlencode($flow));
$where .= sprintf(" and %s = '%s' ", addslashes($this->flowField), addslashes($flow));
}
if ($this->CDRTool['filter']['aNumber']) {
// force user to see only CDRS with his a_numbers
$where .= sprintf(" and ( %s = '%s' or %s = '%s') ",
addslashes($this->usernameField),
addslashes($this->CDRTool['filter']['aNumber']),
addslashes($this->CanonicalURIField),
addslashes($this->CDRTool['filter']['aNumber'])
);
$UserName_comp='equal';
$UserName=$this->CDRTool['filter']['aNumber'];
}
if ($UserName_comp == "empty") {
$where .= sprintf(" and %s = ''", addslashes($this->usernameField));
$this->url.=sprintf("&UserName_comp=%s",urlencode($UserName_comp));
} else if (strlen($UserName) && !$this->CDRTool['filter']['aNumber']) {
if (!$UserName_comp) $UserName_comp='begin';
if ($UserName_comp=="begin") {
$where .= sprintf(" and %s like '%s%s'", addslashes($this->usernameField), addslashes($UserName), '%');
} elseif ($UserName_comp=="contain") {
$where .= sprintf(" and %s like '%s%s%s'", addslashes($this->usernameField), '%', addslashes($UserName), '%');
} elseif ($UserName_comp=="equal") {
$where .= sprintf(" and %s = '%s'", addslashes($this->usernameField), addslashes($UserName));
} else {
$where .= sprintf(" and %s = ''", addslashes($this->usernameField));
}
$this->url.=sprintf("&UserName=%s&UserName_comp=%s",urlencode($UserName),$UserName_comp);
}
$a_number=trim($a_number);
if ($a_number_comp == "empty") {
$where .= sprintf(" and %s = ''", addslashes($this->aNumberField));
$this->url.=sprintf("&a_number_comp=%s",urlencode($a_number_comp));
} else if (strlen($a_number)) {
$a_number=urldecode($a_number);
if (!$a_number_comp) $a_number_comp="equal";
$this->url.=sprintf("&a_number=%s",urlencode($a_number));
if ($a_number_comp=="begin") {
$where .= sprintf(" and %s like '%s%s'", addslashes($this->aNumberField), addslashes($a_number), '%');
} elseif ($a_number_comp=="contain") {
$where .= sprintf(" and %s like '%s%s%s'", addslashes($this->aNumberField), '%', addslashes($a_number), '%');
} elseif ($a_number_comp=="equal") {
$where .= sprintf(" and %s = '%s'", addslashes($this->aNumberField), addslashes($a_number));
}
$this->url.=sprintf("&a_number_comp=%s",urlencode($a_number_comp));
}
$c_number=trim($c_number);
if ($c_number_comp == "empty") {
$where .= sprintf(" and %s = ''", addslashes($this->CanonicalURIField));
$this->url.=sprintf("&c_number_comp=%s",urlencode($c_number_comp));
} else if (strlen($c_number)) {
$c_number=urldecode($c_number);
if (!$c_number_comp) $c_number_comp="begin";
if (!$c_number_comp || $c_number_comp=="begin") {
$where .= sprintf(" and %s like '%s%s'", addslashes($this->CanonicalURIField), addslashes($c_number), '%');
} elseif ($c_number_comp=="contain") {
$where .= sprintf(" and %s like '%s%s%s'", addslashes($this->CanonicalURIField), '%', addslashes($c_number), '%');
} elseif ($c_number_comp=="equal") {
$where .= sprintf(" and %s = '%s'", addslashes($this->CanonicalURIField), addslashes($c_number));
}
$this->url.=sprintf("&c_number=%s&c_number_comp=%s",urlencode($c_number),urlencode($c_number_comp));
}
$Realm=trim($Realm);
if ($Realms) {
$where .= sprintf("and %s in (",$this->domainField);
foreach ($Realms as $realm) {
$where .= sprintf("'%s',",addslashes($realm));
}
$where=rtrim($where, ",");
$where .= ") ";
} else if ($Realm) {
$Realm=urldecode($Realm);
$where .= sprintf(" and %s like '%s' ", $this->domainField, addslashes($Realm));
$this->url.=sprintf("&Realm=%s",urlencode($Realm));
}
$BillingId=trim($BillingId);
if (preg_match("/^\d+$/",$BillingId) && $this->BillingIdField) {
$where .= " and $this->BillingIdField = '".addslashes($BillingId)."'";
$this->url.=sprintf("&BillingId=%s",urlencode($BillingId));
}
if ($application) {
$where .= " and $this->applicationField like '%".addslashes($application)."%'";
$this->url.=sprintf("&application=%s",urlencode($application));
}
if ($DestinationId) {
if ($DestinationId=="empty") {
$DestinationIdSQL="";
} else {
$DestinationIdSQL=$DestinationId;
}
$where .= " and $this->DestinationIdField = '".addslashes($DestinationIdSQL)."'";
$this->url.=sprintf("&DestinationId=%s",urlencode($DestinationId));
}
if (strlen(trim($ExcludeDestinations))) {
$ExcludeDestArray=explode(" ",trim($ExcludeDestinations));
foreach ($ExcludeDestArray as $exclDst) {
if (preg_match("/^0+(\d+)$/",$exclDst,$m)) {
$exclDest_id=$m[1];
} else {
$exclDest_id=$exclDst;
}
$where .= " and ".
$this->CanonicalURIField.
" not like '".
addslashes(trim($exclDst)).
"'";
}
$this->url.=sprintf("&ExcludeDestinations=%s",urlencode($ExcludeDestinations));
}
$call_id=trim($call_id);
if ($call_id) {
$call_id=urldecode($call_id);
$where .= " and $this->callIdField = '".addslashes($call_id)."'";
$this->url.=sprintf("&call_id=%s",urlencode($call_id));
}
if ($sip_proxy) {
$sip_proxy=urldecode($sip_proxy);
$where .= " and $this->SipProxyServerField = '".addslashes($sip_proxy)."'";
$this->url.=sprintf("&sip_proxy=%s",urlencode($sip_proxy));
}
if ($SipCodec) {
$this->url.=sprintf("&SipCodec=%s",urlencode($SipCodec));
if ($SipCodec != "empty") {
$where .= " and $this->SipCodecField = '".addslashes($SipCodec)."'";
} else {
$where .= " and $this->SipCodecField = ''";
}
}
if ($SipRPID) {
$this->url.=sprintf("&SipRPID=%s",urlencode($SipRPID));
if ($SipRPID != "empty") {
$where .= " and $this->SipRPIDField = '".addslashes($SipRPID)."'";
} else {
$where .= " and $this->SipRPIDField = ''";
}
}
if ($UserAgent) {
$where .= " and $this->UserAgentField like '%".addslashes($UserAgent)."%'";
$this->url.=sprintf("&UserAgent=%s",urlencode($UserAgent));
}
if (strlen($sip_status)) {
$where .= " and $this->disconnectField ='".addslashes($sip_status)."'";
$this->url.=sprintf("&sip_status=%s",urlencode($sip_status));
}
if ($sip_status_class) {
$where .= " and $this->disconnectField like '$sip_status_class%'";
$this->url.=sprintf("&sip_status_class=%s",urlencode($sip_status_class));
}
if ($this->CDRTool[filter]["gateway"]) {
$gatewayFilter=$this->CDRTool[filter]["gateway"];
$where .= " and $this->gatewayField = '".addslashes($gatewayFilter)."'";
} else if ($gateway) {
$gateway=urldecode($gateway);
$where .= " and $this->gatewayField = '".addslashes($gateway)."'";
$this->url.=sprintf("&gateway=%s",urlencode($gateway));
}
if ($duration) {
if (preg_match("/\d+/",$duration) ) {
$where .= " and ($this->durationField > 0 and $this->durationField $duration) ";
} elseif (preg_match("/onehour/",$duration) ) {
$where .= " and ($this->durationField < 3610 and $this->durationField > 3530) ";
} elseif ($duration == "zero") {
$where .= " and $this->durationField = 0";
} elseif ($duration == "zeroprice" && $this->priceField) {
$where .= " and $this->durationField > 0 and ($this->priceField = '' or $this->priceField is NULL)";
$mongo_where[$this->priceField] = '';
} elseif ($duration == "nonzero") {
$where .= " and $this->durationField > 0";
} elseif ($duration == "onewaymedia") {
$where .= " and (($this->inputTrafficField > 0 && $this->outputTrafficField = 0) || ($this->inputTrafficField = 0 && $this->outputTrafficField > 0)) " ;
} elseif ($duration == "nomedia") {
$where .= " and ($this->inputTrafficField = 0 && $this->outputTrafficField = 0) " ;
}
$this->url.=sprintf("&duration=%s",urlencode($duration));
}
if ($media_info) {
$this->url.=sprintf("&media_info=%s",urlencode($media_info));
$where .= sprintf(" and %s = '%s' ",addslashes($this->MediaInfoField), addslashes($media_info));
}
$this->url.=sprintf("&maxrowsperpage=%s",addslashes($this->maxrowsperpage));
$url_calls = $this->scriptFile.$this->url."&action=search";
if ($group_by) {
$this->url.=sprintf("&group_by=%s",urlencode($group_by));
}
$this->url_edit = $this->scriptFile.$this->url."&action=edit";
$this->url_run = $this->scriptFile.$this->url."&action=search";
$this->url_export = $_SERVER["PHP_SELF"].$this->url."&action=search&export=1";
if ($duration == "unnormalized") {
$where .= " and $this->normalizedField = '0' ";
}
if ($duration == "unnormalized_duration") {
$where .= " and $this->normalizedField = '0' and $this->durationField > 0 ";
}
if ($group_by) {
$this->group_byOrig=$group_by;
if ($group_by=="hour") {
$group_by="HOUR(AcctStartTime)";
} else if (preg_match("/^DAY/",$group_by)) {
$group_by="$group_by(AcctStartTime)";
} else if (preg_match("/BYMONTH/",$group_by)) {
$group_by="DATE_FORMAT(AcctStartTime,'%Y-%m')";
} else if (preg_match("/BYYEAR/",$group_by)) {
$group_by="DATE_FORMAT(AcctStartTime,'%Y')";
} else if ($group_by=="UserAgentType") {
$group_by="SUBSTRING_INDEX($this->SipUserAgentsField, ' ', '1')";
}
$this->group_by=$group_by;
if ($group_by==$this->callIdField) {
$having=sprintf(" having count(%s) > 1 ", addslashes($group_by));
}
$query= sprintf("select sum(%s) as duration, SEC_TO_TIME(sum(%s)) as duration_print, count(%s) as calls, %s from %s where %s group by %s %s ",
addslashes($this->durationField),
addslashes($this->durationField),
$group_by,
$group_by,
addslashes($cdr_table),
$where,
$group_by,
$having
);
} else {
$query = sprintf("select count(*) as records from %s where ", addslashes($cdr_table)). $where;
}
dprint($query);
if ($this->CDRdb->query($query)) {
$this->CDRdb->next_record();
if ($group_by) {
$rows = $this->CDRdb->num_rows();
} else {
$rows = $this->CDRdb->f('records');
}
} else {
printf ("%s",$this->CDRdb->Error);
$rows = 0;
}
$this->rows=$rows;
if ($this->CDRTool['filter']['aNumber']) {
$this->showResultsMenuSubscriber('0',$begin_datetime,$end_datetime);
} else {
$this->showResultsMenu('0',$begin_datetime,$end_datetime);
}
if (!$this->next) {
$i=0;
$this->next=0;
} else {
- $i=$this->next;
+ $i=intval($this->next);
}
$j=0;
$z=0;
if ($rows>0) {
if ($call_id && $ReNormalize) {
$query=sprintf("update %s
set %s = '0'
where %s = '%s'",
addslashes($cdr_table),
addslashes($this->normalizedField),
addslashes($this->callIdField),
addslashes($call_id)
);
$this->CDRdb->query($query);
}
if ($UnNormalizedCalls=$this->getUnNormalized($where,$cdr_table)) {
if (!$this->DATASOURCES[$this->cdr_source]['skipNormalizeOnPageLoad']) {
if ($UnNormalizedCalls < $this->maxCDRsNormalizeWeb) {
$this->NormalizeCDRS($where,$cdr_table);
if (!$this->export && $this->status['normalized'] ) {
print "<div class=\"alert alert-info\">";
print "<i class='icon-info-sign icon-large'></i>&nbsp;&nbsp;";
printf ("<b><span class=\"alert-heading\">%d</span></b> CDRs normalized. ",$this->status['normalized']);
if ($this->status['cached_keys']['saved_keys']) {
printf ("Quota usage updated for <b><span class=\"alert-heading\">%d</span></b> accounts. ",$this->status['cached_keys']['saved_keys']);
}
print "</div>";
}
}
}
}
if ($rows > $this->maxrowsperpage) {
$maxrows=$this->maxrowsperpage+$this->next;
if ($maxrows > $rows) {
$maxrows=$rows;
$prev_rows=$maxrows;
}
} else {
$maxrows=$rows;
}
if ($duration == "unnormalized") {
// if display un normalized calls we must substract
// the amount of calls normalized above
$maxrows=$maxrows-$this->status['normalized'];
}
if ($group_by) {
if ($order_by=="group_by") {
$order_by1=$group_by;
} else {
if ($order_by == $this->inputTrafficField ||
$order_by == $this->outputTrafficField ||
$order_by == $this->durationField ||
$order_by == $this->priceField ||
$order_by == "zeroP" ||
$order_by == "nonzeroP" ) {
$order_by1=$order_by;
} else {
$order_by1="calls";
}
}
$this->SipMethodField=$this->CDRFields['SipMethod'];
$query= "
select sum($this->durationField) as $this->durationField,
SEC_TO_TIME(sum($this->durationField)) as hours,
count($group_by) as calls,
$this->SipMethodField,
2*sum($this->inputTrafficField)/1024/1024 as $this->inputTrafficField,
2*sum($this->outputTrafficField)/1024/1024 as $this->outputTrafficField,
SUM($this->durationField = '0') as zero,
SUM($this->durationField > '0') as nonzero,
";
if ($order_by=="zeroP" || $order_by=="nonzeroP") {
$query.="
SUM($this->durationField = '0')/count($group_by)*100 as zeroP,
SUM($this->durationField > '0')/count($group_by)*100 as nonzeroP,
";
}
$query.="
sum($this->inputTrafficField)*8*2/1024/sum($this->durationField) as netrate_in,
sum($this->outputTrafficField)*8*2/1024/sum($this->durationField) as netrate_out
";
if ($this->priceField) {
$query.= ", sum($this->priceField) as $this->priceField ";
}
+ $_max_rows = intval($this->maxrowsperpage);
+ if (!$_max_rows) {
+ $_max_rows = 10;
+ }
+ /*
$query.= "
, $group_by as mygroup
from $cdr_table
where $where
group by $group_by
$having
order by $order_by1 $order_type
- limit $i,$this->maxrowsperpage
+ limit $i,$_max_rows
";
+ */
+
+ $query.= sprintf(", %s as mygroup from %s
+ where %s
+ group by %s
+ %s
+ order by %s %s
+ limit %d, %d
+ ", addslashes($group_by), addslashes($cdr_table), $where, addslashes($group_by), addslashes($having), addslashes($order_by1), addslashes($order_type), $i, $_max_rows);
dprint($query);
$this->CDRdb->query($query);
$this->showTableHeaderStatistics();
while ($i<$maxrows) {
$found=$i+1;
$this->CDRdb->next_record();
$calls = $this->CDRdb->f('calls');
$seconds = $this->CDRdb->f($this->durationField);
$seconds = $this->CDRdb->f($this->durationField);
$seconds_print = number_format($this->CDRdb->f($this->durationField),0);
$minutes = number_format($this->CDRdb->f($this->durationField)/60,0,"","");
$minutes_print = number_format($this->CDRdb->f($this->durationField)/60,0);
$hours = $this->CDRdb->f('hours');
$AcctInputOctets = number_format($this->CDRdb->f($this->inputTrafficField),2,".","");
$AcctOutputOctets = number_format($this->CDRdb->f($this->outputTrafficField),2,".","");
$NetRateIn = $this->CDRdb->f('netrate_in');
$NetRateOut = $this->CDRdb->f('netrate_out');
$SipMethod = $this->CDRdb->f($this->callTypeField);
$AcctTerminateCause = $this->CDRdb->f($this->disconnectField);
$mygroup = $this->CDRdb->f('mygroup');
$zero = $this->CDRdb->f('zero');
$nonzero = $this->CDRdb->f('nonzero');
$success = number_format($nonzero/$calls*100,2,".","");
$failure = number_format($zero/$calls*100,2,".","");
$NetworkRateIn = number_format($NetRateIn,2);
$NetworkRateOut = number_format($NetRateOut,2);
$NetworkRate = max($NetworkRateIn,$NetworkRateOut);
if ($this->priceField) {
$price = $this->CDRdb->f($this->priceField);
}
$rr=floor($found/2);
$mod=$found-$rr*2;
if ($mod ==0) {
$inout_color="lightgrey";
} else {
$inout_color="white";
}
$traceValue="";
$mygroup_print=quoted_printable_decode($mygroup);
if ($this->group_byOrig==$this->DestinationIdField) {
if ($this->CDRTool['filter']['domain'] && $this->destinations[$this->CDRTool['filter']['domain']]) {
list($_dst_id,$_dst_name)=$this->getPSTNDestinationId($mygroup,'',$this->CDRTool['filter']['domain']);
$description=$_dst_name;
} else {
$description=$this->destinations[0]["default"][$mygroup]["name"];
//list($_dst_id,$_dst_name)=$this->getPSTNDestinationId($mygroup);
//$description=$_dst_name;
}
if ($mygroup) {
$traceValue=$mygroup;
} else {
$traceValue="empty";
}
} else if ($this->group_byOrig==$this->aNumberField) {
# Normalize Called Station Id
$N=$this->NormalizeNumber($mygroup);
$mygroup_print=$N['username']."@".$N[domain];
$description="";
$traceField="a_number";
$traceValue=urlencode($mygroup);
} else if ($this->group_byOrig==$this->CanonicalURIField) {
$traceField="c_number";
$traceValue=urlencode($mygroup);
} else if ($this->group_byOrig==$this->SipProxyServerField) {
$traceField="sip_proxy";
$traceValue=urlencode($mygroup);
} else if ($this->group_byOrig==$this->SipCodecField) {
$traceField="SipCodec";
} else if (preg_match("/UserAgent/",$this->group_byOrig)) {
$traceField="UserAgent";
} else if (preg_match("/^BY/",$this->group_byOrig)) {
$traceField="MONTHYEAR";
} else if ($this->group_byOrig==$this->callIdField) {
$traceField="call_id";
} else if ($this->group_byOrig=="DAYOFWEEK") {
if ($mygroup == "1") {
$description="Sunday";
} else if ($mygroup == "2") {
$description="Monday";
} else if ($mygroup == "3") {
$description="Tuesday";
} else if ($mygroup == "4") {
$description="Wednesday";
} else if ($mygroup == "5") {
$description="Thursday";
} else if ($mygroup == "6") {
$description="Friday";
} else if ($mygroup == "7") {
$description="Saturday";
}
} else if ($this->group_byOrig=="DAYOFMONTH") {
$description =$this->CDRdb->f('day');
} else if ($this->group_byOrig=="DAYOFYEAR") {
$description =$this->CDRdb->f('day');
} else if ($this->group_byOrig=="SourceIP") {
$traceField="gateway";
} else if ($this->group_byOrig=="SipResponseCode") {
$description =$this->disconnectCodesDescription[$mygroup];
$traceField="sip_status";
} else if ($this->group_byOrig=="SipApplicationType") {
$traceField="application";
} else if ($this->group_byOrig=="ServiceType") {
$traceField="flow";
} else {
$description="";
}
if (!$traceField) {
$traceField = $group_by;
}
if (!$traceValue) {
$traceValue = $mygroup;
}
if (!$traceValue) {
$traceValue="";
$comp_type="empty";
} else {
$comp_type="begin";
}
$traceValue_enc=urlencode($traceValue);
if (!$this->export) {
print "
<tr>
<td><b>$found</b></td>
<td align=right>$calls</td>
<td align=right>$seconds_print</td>
<td align=right>$minutes_print</td>
<td align=right>$hours</td>
";
if ($perm->have_perm("showPrice")) {
$pricePrint=number_format($price,4,".","");
} else {
$pricePrint='x.xxx';
}
print "
<td align=right>$pricePrint</td>
<td align=right>$AcctInputOctets</td>
<td align=right>$AcctOutputOctets</td>
<td align=right>$success%</td>
<td align=right>($nonzero calls)</td>
<td align=right>$failure%</td>
<td align=right>($zero calls)</td>
<td>$mygroup_print</td>
<td>$description</td>
<td>";
printf("<a href=%s&%s=%s&%s_comp=%s target=_new>Display calls</a></td>",$url_calls,$traceField,$traceValue_enc,$traceField,$comp_type);
print "
</tr>
";
} else {
print "$found,";
print "$calls,";
print "$seconds,";
print "$minutes,";
print "$hours,";
if ($perm->have_perm("showPrice")) {
$pricePrint=$price;
} else {
$pricePrint='x.xxx';
}
print "$pricePrint,";
print "$AcctInputOctets,";
print "$AcctOutputOctets,";
print "$success,";
print "$nonzero,";
print "$failure,";
print "$zero,";
print "$mygroup_print,";
print "$description";
print "\n";
}
$i++;
}
if (!$this->export) {
print "
</table>
";
}
} else {
if (!$this->export) {
printf ("<div class='alert alert-info'><i style='font-size:13px' class='icon-info-sign'></i> For more information about each call click on its Id column.</div>");
}
if ($order_by=="zeroP" || $order_by=="nonzeroP") {
$order_by="timestamp";
}
+ $_max_rows = intval($this->maxrowsperpage);
+ if (!$_max_rows) {
+ $_max_rows = 10;
+ }
$query=sprintf("select *, UNIX_TIMESTAMP($this->startTimeField) as timestamp
from %s where %s order by %s %s limit %d, %d",
addslashes($cdr_table),
$where,
addslashes($order_by),
addslashes($order_type),
- $i,
- $this->maxrowsperpage
+ intval($i),
+ $_max_rows
);
$this->CDRdb->query($query);
if ($this->CDRTool['filter']['aNumber']) {
$this->showTableHeaderSubscriber();
} else {
if (!$this->export) {
$this->showTableHeader();
} else {
$this->showExportHeader();
}
}
while ($i<$maxrows) {
global $found;
$found=$i+1;
$this->CDRdb->next_record();
$Structure=$this->_readCDRFieldsFromDB();
//dprint_r($Structure);
$CDR = new $this->CDR_class($this, $Structure);
if ($this->CDRTool['filter']['aNumber']) {
$CDR->showSubscriber();
} else {
if (!$this->export) {
$CDR->show();
} else {
$CDR->export();
}
}
$i++;
}
if (!$this->export) {
print "
</table>
";
}
}
$this->showPagination($this->next,$maxrows);
}
}
function LoadDomains() {
if (!$this->db_subscribers) {
$log=printf("Error: Cannot load domains because db_subscribers is not defined in datasource %s",$this->cdr_source);
print $log;
syslog(LOG_NOTICE,$log);
return false;
}
if (!is_object($this->AccountsDB)) {
$log=printf("Error: AccountsDB is not a valid database object");
print $log;
syslog(LOG_NOTICE,$log);
return false;
}
if (strlen($this->DATASOURCES[$this->cdr_source]['enableThor'])) {
$this->domain_table = "sip_domains";
} else {
$this->domain_table = "domain";
}
$query=sprintf("select * from %s",$this->domain_table);
if ($this->CDRTool['filter']['aNumber']) {
$els=explode("@",$this->CDRTool['filter']['aNumber']);
$query.= sprintf(" where domain = '%s' ", addslashes($els[1]));
} else if ($this->CDRTool['filter']['domain']) {
$fdomain=$this->CDRTool['filter']['domain'];
$query.=sprintf(" where domain = '%s' ", addslashes($fdomain));
}
if (!$this->AccountsDB->query($query)) {
$log=sprintf ("Database %s error: %s (%d) %s\n",$this->db_subscribers,$this->AccountsDB->Error,$this->AccountsDB->Errno,$query);
print $log;
syslog(LOG_NOTICE,$log);
return false;
}
while($this->AccountsDB->next_record()) {
if ($this->AccountsDB->f('domain')) {
$this->localDomains[$this->AccountsDB->f('domain')]=array('name' => $this->AccountsDB->f('domain'),
'reseller' => intval($this->AccountsDB->f('reseller_id'))
);
}
}
return count($this->localDomains);
}
function LoadTrustedPeers() {
if (!$this->db_subscribers) {
$log=printf("Error: Cannot load trusted peers because db_subscribers is not defined in datasource %s",$this->cdr_source);
print $log;
syslog(LOG_NOTICE,$log);
return false;
}
if (!is_object($this->AccountsDB)) {
$log=printf("Error: AccountsDB is not a valid database object");
print $log;
syslog(LOG_NOTICE,$log);
return false;
}
if (strlen($this->DATASOURCES[$this->cdr_source]['enableThor'])) {
$this->trusted_table = "sip_trusted";
} else {
$this->trusted_table = "trusted_peers";
}
$query=sprintf("select * from %s",addslashes($this->trusted_table));
if (!$this->AccountsDB->query($query)) {
$log=sprintf ("Database %s error: %s (%d) %s\n",$this->db_subscribers,$this->AccountsDB->Error,$this->AccountsDB->Errno,$query);
print $log;
syslog(LOG_NOTICE,$log);
return false;
}
while($this->AccountsDB->next_record()) {
if ($this->AccountsDB->f('ip')) {
$this->trustedPeers[$this->AccountsDB->f('ip')]=array('ip' => $this->AccountsDB->f('ip'),
'reseller' => intval($this->AccountsDB->f('reseller_id'))
);
}
}
return count($this->trustedPeers);
}
function getQuota($account) {
if (!$this->quotaEnabled) return true;
if (!$account) return;
if (!is_object($this->AccountsDB)) {
$log=printf("Error: AccountsDB is not a valid database object");
print $log;
syslog(LOG_NOTICE,$log);
return false;
}
list($username,$domain) = explode("@",$account);
if ($this->enableThor) {
$query=sprintf("select * from sip_accounts where username = '%s' and domain = '%s'",addslashes($username),addslashes($domain));
if (!$this->AccountsDB->query($query)) {
$log=sprintf ("Database error for query 1 %s: %s (%s)",$query,$this->AccountsDB->Error,$this->AccountsDB->Errno);
syslog(LOG_NOTICE,$log);
return 0;
}
if ($this->AccountsDB->num_rows()) {
$this->AccountsDB->next_record();
$_profile=json_decode(trim($this->AccountsDB->f('profile')));
return $_profile->quota;
} else {
return 0;
}
} else {
$query=sprintf("select quota from subscriber where username = '%s' and domain = '%s'",addslashes($username),addslashes($domain));
if (!$this->AccountsDB->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->AccountsDB->Error,$this->AccountsDB->Errno);
syslog(LOG_NOTICE,$log);
return 0;
}
if ($this->AccountsDB->num_rows()) {
$this->AccountsDB->next_record();
return $this->AccountsDB->f('quota');
} else {
return 0;
}
}
}
function getBlockedByQuotaStatus($account) {
if (!$this->quotaEnabled) return true;
if (!$account) return 0;
if (!is_object($this->AccountsDB)) {
$log=printf("Error: AccountsDB is not a valid database object");
print $log;
syslog(LOG_NOTICE,$log);
return false;
}
list($username,$domain) = explode("@",$account);
if ($this->enableThor) {
$query=sprintf("select * from sip_accounts where username = '%s' and domain = '%s'",addslashes($username),addslashes($domain));
if (!$this->AccountsDB->query($query)) {
$log=sprintf ("Database error for query2 %s: %s (%s)",$query,$this->AccountsDB->Error,$this->AccountsDB->Errno);
syslog(LOG_NOTICE,$log);
return 0;
}
if ($this->AccountsDB->num_rows()) {
$this->AccountsDB->next_record();
$_profile=json_decode(trim($this->AccountsDB->f('profile')));
if (in_array('quota',$_profile->groups)) {
return 1;
} else {
return 0;
}
} else {
return 0;
}
} else {
$query=sprintf("select CONCAT(username,'@',domain) as account from grp where grp = 'quota' and username = '%s' and domain = '%s'",addslashes($username),addslashes($domain));
if (!$this->AccountsDB->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->AccountsDB->Error,$this->AccountsDB->Errno);
syslog(LOG_NOTICE,$log);
return 0;
}
if ($this->AccountsDB->num_rows()) {
return 1;
} else {
return 0;
}
}
return 0;
}
function notifyLastSessions($count='200',$account='') {
// send emails with last missed and received sessions to subscribers in group $this->missed_calls_group
$lockName=sprintf("%s:notifySessions",$this->cdr_source);
if (!$this->getNormalizeLock($lockName)) {
return true;
}
if (strlen($account)) {
list($username,$domain)=explode('@',$account);
if (!strlen($username) || !strlen($domain)) return false;
} else {
$query=sprintf("select * from memcache where `key` = '%s'",'notifySessionsLastRun');
$this->cdrtool->query($query);
if ($this->cdrtool->num_rows()) {
$this->cdrtool->next_record();
$lastRun=$this->cdrtool->f('value');
if (Date('Y-m-d') == $lastRun) {
$log=sprintf("Notify sessions script already run for date %s\n",$lastRun);
print $log;
syslog(LOG_NOTICE,$log);
return true;
}
}
}
$this->notifySubscribers=array();
require_once('Mail.php');
require_once('Mail/mime.php');
if ($this->enableThor) {
$query=sprintf("select * from sip_accounts");
if (strlen($account)) {
$query=sprintf("select * from sip_accounts where username = '%s' and domain = '%s'",addslashes($username),addslashes($domain));
}
if (!$this->AccountsDB->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->AccountsDB->Error,$this->AccountsDB->Errno);
syslog(LOG_NOTICE,$log);
return 0;
}
if ($this->AccountsDB->num_rows()) {
while ($this->AccountsDB->next_record()) {
$_profile=json_decode(trim($this->AccountsDB->f('profile')));
if (in_array($this->missed_calls_group,$_profile->groups)) {
$this->notifySubscribers[$this->AccountsDB->f('username').'@'.$this->AccountsDB->f('domain')]=array('email'=>$this->AccountsDB->f('email'),'timezone' => $_profile->timezone);
}
}
} else {
return 0;
}
} else {
$query=sprintf("select CONCAT(username,'@',domain) as account,email_address,timezone from grp join subscriber on grp.subscriber_id =subscriber.id where grp = '%s'",
addslashes($this->missed_calls_group));
if (strlen($account)) {
$query.= sprintf (" and username = '%s' and domain = '%s' ",$username,$domain);
}
if (!$this->AccountsDB->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->AccountsDB->Error,$this->AccountsDB->Errno);
syslog(LOG_NOTICE,$log);
return 0;
}
if ($this->AccountsDB->num_rows()) {
while ($this->AccountsDB->next_record()) {
$this->notifySubscribers[$this->AccountsDB->f('account')]=array('email'=>$this->AccountsDB->f('email_address'),'timezone' => $this->AccountsDB->f('timezone'));
}
} else {
return 0;
}
}
if (!count($this->notifySubscribers)) return 0;
$j=0;
foreach (array_keys($this->notifySubscribers) as $_subscriber) {
$j++;
$_last_sessions=array();
unset($textBody);
unset($htmlBody);
$query = sprintf("SELECT *, UNIX_TIMESTAMP(%s) as timestamp FROM %s where (%s = '%s' or %s = '%s') and %s > DATE_ADD(NOW(), INTERVAL -1 day) order by %s desc limit 200",
addslashes($this->startTimeField),
addslashes($this->table),
addslashes($this->usernameField),
addslashes($_subscriber),
addslashes($this->CanonicalURIField),
addslashes($_subscriber),
addslashes($this->startTimeField),
addslashes($this->startTimeField)
);
if (!$this->CDRdb->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->CDRdb->Error,$this->CDRdb->Errno);
syslog(LOG_NOTICE,$log);
print $log;
return 0;
}
if (Date('d')== 1) {
while ($this->CDRdb->next_record()) {
$_last_sessions[]=array('duration' => $this->CDRdb->f($this->durationField),
'from' => $this->CDRdb->f($this->aNumberField),
'to' => $this->CDRdb->f($this->cNumberField),
'username' => $this->CDRdb->f($this->usernameField),
'canonical' => $this->CDRdb->f($this->CanonicalURIField),
'date' => getlocaltime($this->notifySubscribers[$_subscriber]['timezone'],$this->CDRdb->f('timestamp'))
);
}
if (preg_match("/^(\w+)(\d{4})(\d{2})$/",$this->table,$m)) {
$previousTable=$m[1].date('Ym', mktime(0, 0, 0, $m[3]-1, "01", $m[2]));
$query = sprintf("SELECT *, UNIX_TIMESTAMP(%s) as timestamp FROM %s where %s = '%s' and %s > DATE_ADD(NOW(), INTERVAL -1 day) order by %s desc limit 200",
addslashes($this->startTimeField),
addslashes($previousTable),
addslashes($this->CanonicalURIField),
addslashes($_subscriber),
addslashes($this->startTimeField),
addslashes($this->startTimeField)
);
if (!$this->CDRdb->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->CDRdb->Error,$this->CDRdb->Errno);
syslog(LOG_NOTICE,$log);
print $log;
return 0;
}
while ($this->CDRdb->next_record()) {
$_last_sessions[]=array('duration' => $this->CDRdb->f($this->durationField),
'from' => $this->CDRdb->f($this->aNumberField),
'to' => $this->CDRdb->f($this->cNumberField),
'username' => $this->CDRdb->f($this->usernameField),
'canonical' => $this->CDRdb->f($this->CanonicalURIField),
'date' => getlocaltime($this->notifySubscribers[$_subscriber]['timezone'],$this->CDRdb->f('timestamp'))
);
}
}
} else {
while ($this->CDRdb->next_record()) {
$_last_sessions[]=array('duration' => $this->CDRdb->f($this->durationField),
'from' => $this->CDRdb->f($this->aNumberField),
'to' => $this->CDRdb->f($this->cNumberField),
'username' => $this->CDRdb->f($this->usernameField),
'canonical' => $this->CDRdb->f($this->CanonicalURIField),
'date' => getlocaltime($this->notifySubscribers[$_subscriber]['timezone'],$this->CDRdb->f('timestamp'))
);
}
}
if (!count($_last_sessions)) continue;
$sessions=array('missed' => array(),
'received' => array(),
'diverted' => array()
);
$have_sessions=0;
foreach ($_last_sessions as $_s) {
if ($_s['duration'] == 0 && $_s['canonical'] == $_subscriber) {
$sessions['missed'][]=$_s;
$have_sessions++;
continue;
}
if ($_s['duration'] > 0 && $_s['canonical'] == $_subscriber) {
$sessions['received'][]=$_s;
$have_sessions++;
continue;
}
if ($_s['from'] != $_subscriber && $_s['canonical'] != $_subscriber) {
$sessions['diverted'][]=$_s;
$have_sessions++;
continue;
}
}
if (!$have_sessions) continue;;
if (count($sessions['missed'])) {
// missed sessions
$textBody .= sprintf ("Missed sessions\n\n
Id,Date,From,Duration\n
");
$htmlBody .= sprintf ("<h2>Missed Calls</h2>
<p>
<table border=0>
<tr>
<th>
</th>
<th>Date and Time
</th>
<th>Caller
</th>
</tr>
");
$i=0;
foreach ($sessions['missed'] as $_session) {
$i++;
if ($i >= $count) break;
$htmlBody.=sprintf ("<tr><td>%s</td><td>%s</td><td><a href=sip:%s>sip:%s</a></td></tr>",
$i,
$_session['date'],
$_session['from'],
$_session['from']
);
$txtBody.=sprintf ("%s,%s,%s,%s,%s\n",
$i,
$_session['date'],
$_session['from'],
$_session['to']
);
}
$htmlBody.="</table>";
}
if (count($sessions['diverted'])) {
// diverted sessions
$textBody .= sprintf ("Diverted Calls\n\n
Id,Date,From,Diverted to\n
");
$htmlBody .= sprintf ("<h2>Diverted Calls</h2>
<p>
<table border=0>
<tr>
<th>
</th>
<th>Date and Time
</th>
<th>Caller
</th>
<th>Diverted to
</th>
</tr>
");
$i=0;
foreach ($sessions['diverted'] as $_session) {
$i++;
if ($i >= $count) break;
$htmlBody.=sprintf ("<tr><td>%s</td><td>%s</td><td><a href=sip:%s>sip:%s</a></td><td>%s</td></tr>",
$i,
$_session['date'],
$_session['from'],
$_session['from'],
$_session['canonical']
);
$txtBody.=sprintf ("%s,%s,%s,%s\n",
$i,
$_session['date'],
$_session['from'],
$_session['canonical']
);
}
$htmlBody.="</table>";
}
if (count($sessions['received'])) {
// received sessions
$textBody .= sprintf ("Received Calls\n\n
Id,Date,From,Duration\n");
$htmlBody .= sprintf ("<h2>Received Calls</h2>
<p>
<table border=0>
<tr>
<th>
</th>
<th>Date and Time
</th>
<th>Caller
</th>
<th>Duration
</th>
</tr>
");
$i=1;
foreach ($sessions['received'] as $_session) {
if ($i >= $count) break;
$htmlBody.=sprintf ("<tr><td>%s</td><td>%s</td><td><a href=sip:%s>sip:%s</a></td><td>%s</td></tr>",
$i,
$_session['date'],
$_session['from'],
$_session['from'],
$_session['duration']
);
$txtBody.=sprintf ("%s,%s,%s,%s\n",
$i,
$_session['date'],
$_session['from'],
$_session['duration']
);
$i++;
}
$htmlBody.="</table>";
}
$htmlBody.="<p>This is an automatically generated message, do not reply.";
$txtBody.="\nThis is an automatically generated message, do not reply.\n";
$crlf = "\n";
$hdrs = array(
'From'=> $this->CDRTool['provider']['fromEmail'],
'Subject' => sprintf("Incoming Calls for %s on %s",$_subscriber,date('Y-m-d'))
);
$mime = new Mail_mime($crlf);
$mime->setTXTBody($textBody);
$mime->setHTMLBody($htmlBody);
$body = $mime->get();
$hdrs = $mime->headers($hdrs);
$mail =& Mail::factory('mail');
$mail->send($this->notifySubscribers[$_subscriber]['email'], $hdrs, $body);
$log=sprintf("Notify %s at %s with last %d sessions\n",
$_subscriber,
$this->notifySubscribers[$_subscriber]['email'],
count($_last_sessions));
print $log;
syslog(LOG_NOTICE,$log);
}
$query=sprintf("update memcache set `value` = '%s' where `key` = '%s'",Date('Y-m-d'),'notifySessionsLastRun');
if (!$this->cdrtool->query($query)) {
$log=sprintf("Database error for query %s: %s (%s)",$query,$this->cdrtool->Error,$this->cdrtool->Errno);
print $log;
syslog(LOG_NOTICE,$log);
return false;
}
if (!$this->cdrtool->affected_rows()) {
$query=sprintf("insert into memcache (`value`,`key`) values ('%s','%s')",Date('Y-m-d'),'notifySessionsLastRun');
if (!$this->cdrtool->query($query)) {
if ($this->cdrtool->Errno != 1062) {
$log=sprintf("Database error for query %s: %s (%s)",$query,$this->cdrtool->Error,$this->cdrtool->Errno);
print $log;
syslog(LOG_NOTICE,$log);
return false;
}
}
}
}
function getCallerId($account) {
if (!$account) {
return NULL;
}
if ($this->callerid_cache[$account]) {
return $this->callerid_cache[$account];
}
list($username,$domain) = explode('@',$account);
if ($this->enableThor) {
$query=sprintf("select * from sip_accounts where username = '%s' and domain = '%s'",addslashes($username),addslashes($domain));
if (!$this->AccountsDB->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->AccountsDB->Error,$this->AccountsDB->Errno);
syslog(LOG_NOTICE,$log);
return NULL;
}
if ($this->AccountsDB->num_rows()) {
$this->AccountsDB->next_record();
$_profile=json_decode(trim($this->AccountsDB->f('profile')));
$this->callerid_cache[$account]=$_profile->rpid;
return $_profile->rpid;
}
} else {
$query=sprintf("select rpid from subscriber where username = '%s' and domain = '%s'",addslashes($username),addslashes($domain));
if (!$this->AccountsDB->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->AccountsDB->Error,$this->AccountsDB->Errno);
syslog(LOG_NOTICE,$log);
return NULL;
}
if ($this->AccountsDB->num_rows()) {
$this->AccountsDB->next_record();
$rpid = $this->AccountsDB->f('rpid');
$this->callerid_cache[$account]=$rpid;
return $rpid;
}
}
return NULL;
}
function rate_on_net_enabled($username, $domain) {
if ($this->enableThor) {
$query=sprintf("select * from sip_accounts where username = '%s' and domain = '%s'",addslashes($username),addslashes($domain));
if (!$this->AccountsDB->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->AccountsDB->Error,$this->AccountsDB->Errno);
syslog(LOG_NOTICE,$log);
return false;
}
if ($this->AccountsDB->num_rows()) {
while ($this->AccountsDB->next_record()) {
$_profile=json_decode(trim($this->AccountsDB->f('profile')));
if (in_array($this->rate_on_net_group,$_profile->groups)) {
return true;
}
}
}
}
return false;
}
}
class CDR_opensips extends CDR {
function CDR_opensips($parent, $CDRfields) {
$this->CDRS = $parent;
$this->cdr_source = $this->CDRS->cdr_source;
foreach (array_keys($this->CDRS->CDRFields) as $field) {
$this->$field = $CDRfields[$this->CDRS->CDRFields[$field]];
}
if ($this->CanonicalURI) {
$this->CanonicalURI = quoted_printable_decode($this->CanonicalURI);
}
if ($this->RemoteAddress) {
$this->RemoteAddress = quoted_printable_decode($this->RemoteAddress);
}
if ($this->BillingPartyId) {
$this->BillingPartyId = quoted_printable_decode($this->BillingPartyId);
}
if ($this->aNumber) {
$this->aNumber = quoted_printable_decode($this->aNumber);
}
if ($this->cNumber) {
$this->cNumber = quoted_printable_decode($this->cNumber);
}
if ($this->SipRPID) {
$this->SipRPID = quoted_printable_decode($this->SipRPID);
}
$this->buildMongoCDR();
if (!$this->application && $this->SipMethod) {
$_method=strtolower($this->SipMethod);
if ($_method == 'message') {
$this->application = 'message';
$this->stopTimeNormalized=$this->startTime;
} else {
$this->application = 'audio';
}
}
if ($this->application == 'message') {
$this->stopTimeNormalized=$this->startTime;
}
$this->application=strtolower($this->application);
$this->application_print=quoted_printable_decode($this->application);
$this->FromHeaderPrint = quoted_printable_decode($this->FromHeader);
if (strstr($this->FromHeaderPrint,';')) {
$_els=explode(";",$this->FromHeaderPrint);
$this->FromHeaderPrint=$_els[0];
}
$this->FromHeaderPrint = htmlentities($this->FromHeaderPrint);
$this->UserAgentPrint = quoted_printable_decode($this->UserAgent);
$app_prefix = preg_replace('/[.].*$/', '', $this->application);
if (!in_array($app_prefix, $this->supportedApplicationTypes)) {
$log=sprintf("Changing application from %s to %s\n", $this->application, $this->defaultApplicationType);
syslog(LOG_NOTICE,$log);
$this->application = $this->defaultApplicationType;
}
//$this->applicationNormalized=$this->application;
if ($this->aNumber) {
$NormalizedNumber = $this->CDRS->NormalizeNumber($this->aNumber,"source");
$this->aNumberPrint = $NormalizedNumber['NumberPrint'];
$this->aNumberNormalized = $NormalizedNumber['Normalized'];
$this->aNumberUsername = $NormalizedNumber['username'];
$this->aNumberDomain = $NormalizedNumber['domain'];
}
if (!$this->BillingPartyId || $this->BillingPartyId == 'n/a') {
$this->BillingPartyId=$this->aNumberPrint;
}
$this->ResellerId=0;
// calculate reseller
$_billing_party_els=explode("@",$this->BillingPartyId);
if ($this->isBillingPartyLocal()) {
$this->ResellerId = $this->CDRS->localDomains[$_billing_party_els[1]]['reseller'];
} else {
if (!strlen($_billing_party_els[0])) $this->BillingPartyId=$_billing_party_els[1];
if (count($_billing_party_els)==2) {
if (!$this->domain) $this->domain=$_billing_party_els[1];
if ($this->CDRS->localDomains[$_billing_party_els[1]]['reseller']) {
$this->ResellerId = $this->CDRS->localDomains[$_billing_party_els[1]]['reseller'];
} else if ($this->CDRS->trustedPeers[$_billing_party_els[1]]['reseller']) {
$this->ResellerId = $this->CDRS->trustedPeers[$_billing_party_els[1]]['reseller'];
}
} else if (count($_billing_party_els)==1) {
$this->ResellerId=$this->CDRS->trustedPeers[$_billing_party_els[0]]['reseller'];
}
}
if (!strlen($this->ResellerId)) {
$this->ResellerId = 0;
}
$this->BillingPartyId=strtolower($this->BillingPartyId);
$this->BillingPartyIdPrint=$this->BillingPartyId;
$this->domainNormalized = $this->domain;
if (is_array($this->CDRS->DATASOURCES[$this->cdr_source]['domainTranslation_SourceIP']) &&
isset($this->CDRS->DATASOURCES[$this->cdr_source]['domainTranslation_SourceIP'][$this->SourceIP]) &&
strlen($this->CDRS->DATASOURCES[$this->cdr_source]['domainTranslation_SourceIP'][$this->SourceIP])) {
$this->domainNormalized=$this->CDRS->DATASOURCES[$this->cdr_source]['domainTranslation_SourceIP'][$this->SourceIP];
} else if (is_array($this->CDRS->DATASOURCES[$this->cdr_source]['domainTranslation']) &&
isset($this->CDRS->DATASOURCES[$this->cdr_source]['domainTranslation'][$this->domain]) &&
strlen($this->CDRS->DATASOURCES[$this->cdr_source]['domainTranslation'][$this->domain])) {
$this->domainNormalized=$this->CDRS->DATASOURCES[$this->cdr_source]['domainTranslation'][$this->domain];
}
$this->domainNormalized=strtolower($this->domainNormalized);
$this->RemoteAddressPrint=quoted_printable_decode($this->RemoteAddress);
$_timestamp_stop=$this->timestamp+$this->duration;
$this->dayofweek = date("w",$this->timestamp);
$this->hourofday = date("G",$this->timestamp);
$this->dayofyear = date("Y-m-d",$this->timestamp);
// Called Station ID or cNumber should not be used for rating purposes because
// it is chosen by the subscriber but the Proxy rewrites it into a different
// final destination (the Canonical URI)
// Canonical URI is the final logical SIP destination after all
// lookups like aliases, usrloc , call forwarding, ENUM
// mappings or PSTN gateways but before the DNS lookup
// Canonical URI must be saved in the SIP Proxy and added as an extra
// Radius attribute in the Radius START packet
if (!$this->CanonicalURI) {
if ($this->RemoteAddress) {
$this->CanonicalURI=$this->RemoteAddress;
} else if ($this->cNumber) {
$this->CanonicalURI=$this->cNumber;
}
}
if ($this->CanonicalURI) {
$this->CanonicalURIPrint = $this->CanonicalURI;
$NormalizedNumber = $this->CDRS->NormalizeNumber($this->CanonicalURI,"destination",$this->BillingPartyId,$this->domain,$this->gateway,'',$this->ENUMtld,$this->ResellerId);
$this->CanonicalURINormalized = $NormalizedNumber['Normalized'];
$this->CanonicalURIUsername = $NormalizedNumber['username'];
$this->CanonicalURIDomain = $NormalizedNumber['domain'];
$this->CanonicalURIPrint = $NormalizedNumber['NumberPrint'];
$this->CanonicalURIDelimiter = $NormalizedNumber['delimiter'];
$this->CanonicalURIE164 = $NormalizedNumber['E164'];
// Destination Id is used for rating purposes
$this->DestinationId = $NormalizedNumber['DestinationId'];
$this->destinationName = $NormalizedNumber['destinationName'];
$this->region = $NormalizedNumber['region'];
}
if ($this->cNumber) {
$NormalizedNumber = $this->CDRS->NormalizeNumber($this->cNumber,"destination",$this->BillingPartyId,$this->domain,$this->gateway,'',$this->ENUMtld,$this->ResellerId);
$this->cNumberNormalized = $NormalizedNumber['Normalized'];
$this->cNumberUsername = $NormalizedNumber['username'];
$this->cNumberDomain = $NormalizedNumber['domain'];
$this->cNumberPrint = $NormalizedNumber['username'].$NormalizedNumber['delimiter'].$NormalizedNumber['domain'];
$this->cNumberDelimiter = $NormalizedNumber['delimiter'];
$this->cNumberE164 = $NormalizedNumber['E164'];
}
if ($this->RemoteAddress) {
// Next hop is the real destination after all lookups including DNS
$NormalizedNumber = $this->CDRS->NormalizeNumber($this->RemoteAddress,"destination",$this->BillingPartyId,$this->domain,$this->gateway,'',$this->ENUMtld,$this->ResellerId);
$this->RemoteAddressPrint = $NormalizedNumber['NumberPrint'];
$this->RemoteAddressNormalized = $NormalizedNumber['Normalized'];
$this->RemoteAddressDestinationId = $NormalizedNumber['DestinationId'];
$this->RemoteAddressDestinationName = $NormalizedNumber['destinationName'];
$this->RemoteAddressUsername = $NormalizedNumber['username'];
$this->RemoteAddressDelimiter = $NormalizedNumber['delimiter'];
$this->RemoteAddressE164 = $NormalizedNumber['E164'];
$this->remoteGateway = $NormalizedNumber['domain'];
$this->remoteUsername = $NormalizedNumber['username'];
}
$this->isCalleeLocal();
$this->isCallerLocal();
if ($this->CallerIsLocal) {
if ($this->aNumberPrint == $this->BillingPartyId) {
// call is not diverted
if ($this->CalleeIsLocal) {
$this->flow = 'on-net';
} else {
$this->flow = 'outgoing';
}
} else {
// call is diverted
if ($this->CalleeIsLocal) {
$this->flow = 'on-net-diverted-on-net';
} else {
$this->flow = 'on-net-diverted-off-net';
}
}
} else {
if ($this->isBillingPartyLocal()) {
// call is diverted by local user
if ($this->CalleeIsLocal) {
$this->flow = 'diverted-on-net';
} else {
$this->flow = 'diverted-off-net';
}
} else if ($this->CalleeIsLocal) {
$this->flow = 'incoming';
} else {
// transit from trusted peer
$this->flow = 'transit';
}
}
if (($this->flow == 'on-net' || $this->flow == 'diverted-on-net' || $this->flow == 'on-net-diverted-on-net') &&
$this->application == 'audio' &&
$this->CDRS->rating_settings['rate_on_net_calls'] &&
$this->CDRS->rate_on_net_enabled($_billing_party_els[0], $_billing_party_els[1]) &&
!$this->DestinationId &&
$this->CalleeCallerId) {
$_dest = preg_replace("/^\+(\d+)$/","00$1", $this->CalleeCallerId);
$NormalizedNumber = $this->CDRS->NormalizeNumber($_dest,"destination",$this->BillingPartyId,$this->domain,$this->gateway,'',$this->ENUMtld,$this->ResellerId);
$this->DestinationId = $NormalizedNumber['DestinationId'];
$this->destinationName = $NormalizedNumber['destinationName'];
}
if ($this->application == "presence") {
$this->destinationPrint = $this->cNumberUsername.$this->cNumberDelimiter.$this->cNumberDomain;
$this->DestinationForRating = $this->cNumberNormalized;
} else {
if (!$this->DestinationId) {
if ($this->CanonicalURIDomain) {
$this->destinationPrint = $this->CanonicalURIUsername.$this->CanonicalURIDelimiter.$this->CanonicalURIDomain;
} else {
$this->destinationPrint = $this->cNumberUsername.$this->cNumberDelimiter.$this->cNumberDomain;
}
if (strstr($this->CanonicalURINormalized,'@')) {
$this->DestinationForRating = $this->CanonicalURINormalized;
} else {
$this->DestinationForRating = $this->RemoteAddressNormalized;
}
} else {
$this->DestinationForRating = $this->CanonicalURINormalized;
$this->destinationPrint = $this->CanonicalURIPrint;
}
}
if ($this->inputTraffic) {
$this->inputTrafficPrint = number_format($this->inputTraffic/1024,2);
} else {
$this->inputTrafficPrint=0;
}
if ($this->outputTraffic) {
$this->outputTrafficPrint = number_format($this->outputTraffic/1024,2);
} else {
$this->outputTrafficPrint=0;
}
if (!$CDRfields['skip_fix_prepaid_duration']) {
if (!$this->normalized && $this->callId) {
// fix the duration of prepaid sessions if the prepaid duration is different than radius calculated duration
$query=sprintf("select duration from prepaid_history
where session = '%s'
and destination = '%s'
order by id desc limit 1",
addslashes($this->callId),
addslashes($this->destinationPrint) // must be synced with maxsession time
);
if ($this->CDRS->cdrtool->query($query)) {
if ($this->CDRS->cdrtool->num_rows()) {
$this->CDRS->cdrtool->next_record();
$this->durationNormalized = $this->CDRS->cdrtool->f('duration');
$this->durationPrint = sec2hms($this->durationNormalized);
} else {
$this->durationPrint = sec2hms($this->duration);
}
} else {
$log=sprintf("Database error for query %s: %s (%s)",$query,$this->CDRS->cdrtool->Error,$this->CDRS->cdrtool->Errno);
syslog(LOG_NOTICE,$log);
}
} else {
$this->durationPrint = sec2hms($this->duration);
}
} else {
$this->durationPrint = sec2hms($this->duration);
}
if ($this->disconnect) {
$this->disconnectPrint = $this->NormalizeDisconnect($this->disconnect);
}
$this->traceIn();
$this->traceOut();
$this->obfuscateCallerId();
if ($this->CDRS->rating) {
global $perm;
if (is_object($perm) && $perm->have_perm("showPrice")) {
$this->pricePrint=$this->price;
} else {
$this->pricePrint='x.xxx';
}
}
}
function buildMongoCDR() {
# TODO = remove me
$this->mongo_cdr = array();
$int_values = array('duration', 'inputTraffic', 'outputTraffic', 'timestamp', 'disconnect');
foreach (array_keys($this->CDRS->CDRFields) as $field) {
if (in_array($field, $int_values)) {
$this->mongo_cdr[$field] = intval($this->$field);
} else {
$this->mongo_cdr[$field] = $this->$field;
}
}
if ($this->CanonicalURI) {
$this->mongo_cdr['CanonicalURI'] = $this->CanonicalURI;
}
if ($this->RemoteAddress) {
$this->mongo_cdr['RemoteAddress'] = $this->RemoteAddress;
}
if ($this->BillingPartyId) {
$this->mongo_cdr['BillingPartyId'] = $this->BillingPartyId;
}
if ($this->aNumber) {
$this->mongo_cdr['aNumber'] = $this->aNumber;
}
if ($this->cNumber) {
$this->mongo_cdr['cNumber'] = $this->cNumber;
}
if ($this->SipRPID) {
$this->mongo_cdr['SipRPID'] = $this->SipRPID;
}
}
function buildCDRdetail() {
global $perm;
global $found;
if (!is_object($perm)) return;
$this->geo_location=$this->lookupGeoLocation($this->SourceIP);
$this->cdr_details="
<div class=\"alert alert-info\" style='color: black'>
<div class='row-fluid'>
<div class='span4'>
<h5>SIP Signalling</h5>
";
$this->cdr_details.= sprintf("
<a href=%s&call_id=%s><font color=orange>Click here to show only this call id</font></a>
",
$this->CDRS->url_run,
urlencode($this->callId)
);
if ($this->CDRS->sipTrace) {
$trace_datasource = $this->CDRS->sipTrace;
$callid_enc = urlencode(quoted_printable_decode($this->callId));
$fromtag_enc = urlencode(quoted_printable_decode($this->SipFromTag));
$totag_enc = urlencode(quoted_printable_decode($this->SipToTag));
$this->traceLink="<a href=\"javascript:void(null);\" onClick=\"return window.open('sip_trace.phtml?cdr_source=$trace_datasource&callid=$callid_enc&fromtag=$fromtag_enc&totag=$totag_enc&proxyIP=$this->SipProxyServer', 'Trace',
'toolbar=0,status=0,menubar=0,scrollbars=1,resizable=1,width=1300px,height=600')\"><font color=red>Click here for the SIP trace</font></a> &nbsp;";
$this->cdr_details.= "
<div class=\"row-fluid\">
<div class=\"span3\">Call id:</div>
<div class=\"span9\">$this->callId </div>
</div>
";
}
$this->cdr_details.= sprintf("
<div class=\"row-fluid\">
<div class=\"span12\">%s</div>
</div>
", $this->traceLink);
$this->cdr_details.= "
<div class=\"row-fluid\">
<div class=\"span3\">From tag: </div>
<div class=\"span9\">$this->SipFromTag</div>
</div>
<div class=\"row-fluid\">
<div class=\"span3\">To tag: </div>
<div class=\"span9\">$this->SipToTag</div>
</div>
<div class=\"row-fluid\">
<div class=\"span3\">Start Time:</div>
<div class=\"span9\">$this->startTime $providerTimezone</div>
</div>
<div class=\"row-fluid\">
<div class=\"span3\">Stop Time:</div>
<div class=\"span9\">$this->stopTime</div>
</div>
";
$this->cdr_details.= sprintf("
<div class=\"row-fluid\">
<div class=\"span3\">Country:</div>
<div class=\"span9\">%s</div>
</div>
",$this->geo_location);
$this->cdr_details.= "
<div class=\"row-fluid\">
<div class=\"span3\">Method:</div>
<div class=\"span9\">$this->SipMethod from <i>$this->SourceIP:$this->SourcePort</i></div>
</div>
<div class=\"row-fluid\">
<div class=\"span3\">From:</div>
<div class=\"span9\">$this->aNumberPrint</div>
</div>
<div class=\"row-fluid\">
<div class=\"span3\">From Header:</div>
<div class=\"span9\">$this->FromHeaderPrint</div>
</div>
<div class=\"row-fluid\">
<div class=\"span3\">User Agent:</div>
<div class=\"span9\">$this->UserAgentPrint</div>
</div>
<div class=\"row-fluid\">
<div class=\"span3\">Domain:</div>
<div class=\"span9\">$this->domain</div>
</div>
<div class=\"row-fluid\">
<div class=\"span3\">To (dialed URI):</div>
<div class=\"span9\">$this->cNumberPrint</div>
</div>
";
if ($this->CanonicalURI) {
$this->cdr_details.= sprintf("
<div class=\"row-fluid\">
<div class=\"span3\">Canonical URI: </div>
<div class=\"span9\">%s</div>
</div>
",htmlentities($this->CanonicalURI));
}
$this->cdr_details.= sprintf("
<div class=\"row-fluid\">
<div class=\"span3\">Next Hop URI:</div>
<div class=\"span9\">%s</div>
</div>
",htmlentities($this->RemoteAddress));
if ($this->DestinationId) {
$this->cdr_details.= "
<div class=\"row-fluid\">
<div class=\"span3\">Destination: </div>
<div class=\"span9\">$this->destinationName ($this->DestinationId)</div>
</div>
";
}
if ($this->ENUMtld && $this->ENUMtld != 'none' && $this->ENUMtld != 'N/A') {
$this->cdr_details.= "
<div class=\"row-fluid\">
<div class=\"span3\">ENUM TLD: </div>
<div class=\"span9\">$this->ENUMtld</div>
</div>
";
}
if ($this->SipRPID) {
$this->cdr_details .= "
<div class=\"row-fluid\">
<div class=\"span3\">Caller ID: </div>
<div class=\"span9\">$this->SipRPIDPrint</div>
</div>
";
}
if ($this->CalleeCallerId) {
$this->cdr_details .= "
<div class=\"row-fluid\">
<div class=\"span3\">Called ID: </div>
<div class=\"span9\">$this->CalleeCallerId</div>
</div>
";
}
$this->cdr_details.= "
<div class=\"row-fluid\">
<div class=\"span3\">Billing Party:</div>
<div class=\"span9\"><font color=brown>$this->BillingPartyIdPrint</font></div>
</div>
<div class=\"row-fluid\">
<div class=\"span3\">Reseller:</div>
<div class=\"span9\"><font color=brown>$this->ResellerId</font></div>
</div>
</div>
";
$this->cdr_details.= "
<div class='span3'>
";
if ($this->application != 'message') {
$this->cdr_details.= "
<h5>Media Streams</h5>
";
if ($this->CDRS->mediaTrace) {
$media_trace_datasource = $this->CDRS->mediaTrace;
$this->mediaTraceLink="<a href=\"javascript:void(null);\" onClick=\"return window.open('media_trace.phtml?cdr_source=$media_trace_datasource&callid=$callid_enc&fromtag=$fromtag_enc&totag=$totag_enc&proxyIP=$this->SipProxyServer', 'Trace',
'toolbar=0,status=0,menubar=0,scrollbars=1,resizable=1,width=800,height=730')\">Click here for media information</a> &nbsp;";
$this->cdr_details.= sprintf("
<div class=\"row-fluid\">
<div class='span12'>%s</div>
</div>
", $this->mediaTraceLink);
}
$this->SipCodec = quoted_printable_decode($this->SipCodec);
if ($this->SipCodec) {
$this->cdr_details.= "
<div class=\"row-fluid\">
<div class=\"span5\">Codecs: </div>
<div class=\"span7\">$this->SipCodec</div>
</div>
";
}
$this->cdr_details.= "
<div class=\"row-fluid\">
<div class=\"span5\">Caller RTP: </div>
<div class=\"span7\">$this->inputTrafficPrint KB</div>
</div>
<div class=\"row-fluid\">
<div class=\"span5\">Called RTP: </div>
<div class=\"span7\">$this->outputTrafficPrint KB</div>
</div>
";
if ($this->MediaInfo) {
$this->cdr_details.= "
<div class=\"row-fluid\">
<div class=\"span5\">Media Info:</div>
<div class=\"span7\"><font color=red>$this->MediaInfo</font></div>
</div>
";
}
$this->cdr_details.= "
<div class=\"row-fluid\">
<div class=\"span5\">Applications: </div>
<div class=\"span7\">$this->application_print</div>
</div>
";
}
if ($this->SipUserAgents) {
$this->SipUserAgents = quoted_printable_decode($this->SipUserAgents);
$callerAgents=explode("+",$this->SipUserAgents);
$callerUA=htmlentities($callerAgents[0]);
$calledUA=htmlentities($callerAgents[1]);
$this->cdr_details.= "
<div class=\"row-fluid\">
<div class=\"span5\">Caller SIP UA: </div>
<div class=\"span7\">$callerUA</div>
</div>
<div class=\"row-fluid\">
<div class=\"span5\">Called SIP UA: </div>
<div class=\"span7\">$calledUA</div>
</div>
";
}
$this->cdr_details.= "
</div>";
if ($perm->have_perm("showPrice") && $this->normalized) {
$this->cdr_details.= "
<div class=\"span3\">
<h5>Rating</h5>
";
if ($this->price > 0 || $this->rate) {
$this->ratePrint=nl2br($this->rate);
$this->cdr_details.= "
<div class=\"row-fluid\">
$this->ratePrint
</div>
";
} else {
$this->cdr_details.= "
<div class=\"row-fluid\">
Free call
</div>
";
}
$this->cdr_details.= "
</div>
";
}
$this->cdr_details.= "
</div>
</div>
";
}
function traceIn () {
$datasource=$this->CDRS->traceInURL[$this->SourceIP];
global $DATASOURCES;
if (!$datasource || !$DATASOURCES[$datasource]) {
return;
}
$tplus = $this->timestamp+$this->duration+300;
$tmin = $this->timestamp-300;
$c_number = $this->remoteUsername;
$cdr_table = Date('Ym',time($this->timestamp));
$this->traceIn=
"<a href=callsearch.phtml".
"?cdr_source=$datasource".
"&cdr_table=$cdr_table".
"&trace=1".
"&action=search".
"&c_number=$c_number".
"&c_number_comp=begins".
"&begin_datetime=$tmin".
"&end_datetime=$tplus".
" target=bottom>".
"In".
"</a>";
}
function traceOut () {
$datasource=$this->CDRS->traceOutURL[$this->remoteGateway];
global $DATASOURCES;
if (!$datasource || !$DATASOURCES[$datasource]) {
return;
}
$tplus = $this->timestamp+$this->duration+300;
$tmin = $this->timestamp-300;
$c_number = preg_replace("/^(0+)/","",$this->remoteUsername);
$cdr_table = Date('Ym',time($this->timestamp));
$this->traceOut=
"<a href=callsearch.phtml".
"?cdr_source=$datasource".
"&cdr_table=$cdr_table".
"&trace=1".
"&action=search".
"&c_number=$c_number".
"&c_number_comp=contain".
"&begin_datetime=$tmin".
"&end_datetime=$tplus".
" target=bottom>".
"Out".
"</a>";
}
function show() {
$this->buildCDRdetail();
global $found;
global $perm;
$rr=floor($found/2);
$mod=$found-$rr*2;
if ($mod ==0) {
$inout_color="#F9F9F9";
} else {
$inout_color="white";
}
$this->ratePrint=nl2br($this->rate);
if ($this->CDRS->Accounts[$this->BillingPartyId]['timezone']) {
$timezone_print=$this->CDRS->Accounts[$this->BillingPartyId]['timezone'];
} else {
$timezone_print=$this->CDRS->CDRTool['provider']['timezone'];
}
$found_print=$found;
if ($this->normalized) $found_print.='N';
$providerTimezone=$this->CDRS->CDRTool['provider']['timezone'];
print "
<tr bgcolor=$inout_color>
<td valign=top onClick=\"return toggleVisibility('row$found')\"><a href=#>$found_print</a></td>
<td valign=top onClick=\"return toggleVisibility('row$found')\"><nobr>$this->startTime</nobr></td>
<td valign=top onClick=\"return toggleVisibility('row$found')\"><nobr>$this->flow</nobr></td>
<td valign=top onClick=\"return toggleVisibility('row$found')\"><nobr>$this->aNumberPrint</td>
<td valign=top onClick=\"return toggleVisibility('row$found')\"><nobr>$this->geo_location</td>
<td valign=top onClick=\"return toggleVisibility('row$found')\">$this->SipProxyServer</td>
<td valign=top onClick=\"return toggleVisibility('row$found')\">$this->application</td>
<td valign=top><nobr>$this->destinationPrint</nobr>
";
if ($this->DestinationId) {
if ($this->DestinationId != $this->CanonicalURI) {
print " ($this->destinationName $this->DestinationId)";
} else {
print " ($this->destinationName)";
}
}
print "</td>";
if (!$this->normalized){
if ($this->duration > 0 ) {
print "<td valign=top align=left colspan=4><font color=red>$this->duration(s)</a></td>";
} else {
print "<td valign=top align=left colspan=4><font color=red>in progress</a></td>";
}
} else {
print "
<td valign=top align=right>$this->durationPrint</td>
<td valign=top align=right>$this->pricePrint</td>
<td valign=top align=right>$this->inputTrafficPrint </td>
<td valign=top align=right>$this->outputTrafficPrint</td>
";
}
$SIPclass=substr($this->disconnect,0,1);
if ($SIPclass=="6") {
$status_color="<span class=\"pull-right label label-important\">";
} else if ($SIPclass=="5" ) {
$status_color="<span class=\"pull-right label label-important\">";
} else if ($SIPclass=="4" ) {
$status_color="<span class=\"pull-right label label-info\">";
} else if ($SIPclass=="3" ) {
$status_color="<span class=\"pull-right label label-success\">";
} else if ($SIPclass=="2" ) {
$status_color="<span class=\"pull-right label label-success\">";
} else {
$status_color="<span class=\"pull-right label\">";
}
print "
<td valign=top align=right>$this->SipCodec</td>
<td valign=top align=right>$status_color $this->disconnectPrint</span></td>
</tr>
<tr class=extrainfo id='row$found'>
<td></td>
<td colspan=13>$this->cdr_details</td>
</tr>
";
}
function export() {
global $found;
$disconnectName = $this->CDRS->disconnectCodesDescription[$this->disconnect];
$UserAgents = explode("+",$this->SipUserAgents);
$CallingUserAgent = trim($UserAgents[0]);
$CalledUserAgent = trim($UserAgents[1]);
print "$found";
print ",$this->startTime";
print ",$this->stopTime";
print ",$this->BillingPartyIdPrint";
print ",$this->domain";
print ",$this->SipRPIDPrint";
print ",$this->aNumberPrint";
print ",$this->destinationPrint";
print ",$this->DestinationId";
print ",$this->destinationName";
print ",$this->RemoteAddressPrint";
print ",$this->CanonicalURIPrint";
print ",$this->duration";
print ",$this->price";
print ",$this->SipProxyServer";
print ",$this->inputTraffic";
print ",$this->outputTraffic";
printf(",%s",preg_replace("/,/","/",quoted_printable_decode($CallingUserAgent)));
printf(",%s",preg_replace("/,/","/",quoted_printable_decode($CalledUserAgent)));
print ",$this->disconnect";
print ",$disconnectName";
printf(",%s",preg_replace("/,/","/",quoted_printable_decode($this->SipCodec)));
print ",$this->application";
print "\n";
}
function showSubscriber() {
$this->buildCDRdetail();
global $found;
$rr=floor($found/2);
$mod=$found-$rr*2;
if ($mod ==0) {
$inout_color="lightgrey";
} else {
$inout_color="white";
}
if (!$this->CDRS->export) {
$timezone_print=$this->CDRS->CDRTool['provider']['timezone'];
$found_print=$found;
if ($this->normalized) $found_print.='N';
print "
<tr rel=tooltip data-placement='bottom' data-original-title='For more information about this call click the row.'>
<td valign=top onClick=\"return toggleVisibility('row$found')\"><a href=#>$found_print</a></td>
<td valign=top onClick=\"return toggleVisibility('row$found')\"><nobr>$this->startTime $timezone_print</nobr></td>
<td valign=top><nobr>$this->aNumberPrint</nobr></td>
<td valign=top onClick=\"return toggleVisibility('row$found')\"><nobr>$this->geo_location</td>
<td valign=top onClick=\"return toggleVisibility('row$found')\">$this->SipProxyServer</td>
<td valign=top><nobr>$this->destinationPrint $this->destinationName</td>
<td valign=top align=right>$this->durationPrint</td>
";
if ($this->CDRS->rating) {
print "<td valign=top align=right>$this->pricePrint</td>";
}
print "
<td valign=top align=right>$this->inputTrafficPrint </td>
<td valign=top align=right>$this->outputTrafficPrint</td>
</tr>
";
print "
<tr class=extrainfo id='row$found'>
<td></td>
<td colspan=11>$this->cdr_details</td>
</tr>
";
} else {
$disconnectName=$this->CDRS->disconnectCodesDescription[$this->disconnect];
$UserAgents=explode("+",$this->SipUserAgents);
$CallingUserAgent=trim($UserAgents[0]);
$CalledUserAgent=trim($UserAgents[1]);
print "$found,$this->startTime,$this->stopTime,$this->BillingPartyId,$this->domain,$this->aNumberPrint,$this->cNumberPrint,$this->DestinationId,$this->destinationName,$this->RemoteAddressPrint,$this->duration,$this->price,$this->SipProxyServer,$this->inputTraffic,$this->outputTraffic,$CallingUserAgent,$CalledUserAgent,$this->disconnect,$disconnectName,$this->SipCodec,$this->application\n";
}
}
function isBillingPartyLocal() {
$els=explode("@",$this->BillingPartyId);
if ($els[1] && isset($this->CDRS->localDomains[$els[1]])) {
return true;
}
return false;
}
function isCallerLocal() {
if (isset($this->CDRS->localDomains[$this->aNumberDomain])) {
$this->CallerIsLocal=true;
$this->SipRPID = $this->CDRS->getCallerId($this->BillingPartyId);
$this->SipRPIDPrint = $this->SipRPID;
#$this->SipRPIDPrint = quoted_printable_decode($this->SipRPID);
}
}
function isCalleeLocal() {
if (isset($this->CDRS->localDomains[$this->CanonicalURIDomain]) && !preg_match("/^0/",$this->CanonicalURIUsername)) {
$this->CalleeIsLocal=true;
$this->CalleeCallerId=$this->CDRS->getCallerId($this->CanonicalURI);
}
}
function obfuscateCallerId() {
global $obfuscateCallerId;
if ($obfuscateCallerId) {
//Caller party
$caller_els=explode("@",$this->aNumberPrint);
if (is_numeric($caller_els[0]) && strlen($caller_els[0]>3)) {
$_user=substr($caller_els[0],0,strlen($caller_els[0])-3).'xxx';
} else {
$_user='caller';
}
if (count($caller_els)== 2) {
$this->aNumberPrint=$_user.'@'.$caller_els[1];
} else {
$this->aNumberPrint=$_user;
}
//Billing party
$caller_els=explode("@",$this->BillingPartyIdPrint);
if (is_numeric($caller_els[0]) && strlen($caller_els[0]>3)) {
$_user=substr($caller_els[0],0,strlen($caller_els[0])-3).'xxx';
} else {
$_user='party';
}
$this->BillingPartyIdPrint=$_user.'@'.$caller_els[1];
// Destination
$caller_els=explode("@",$this->destinationPrint);
if (is_numeric($caller_els[0]) && strlen($caller_els[0]>3)) {
$_user=substr($caller_els[0],0,strlen($caller_els[0])-3).'xxx';
} else {
$_user='destination';
}
if (count($caller_els)== 2) {
$this->destinationPrint=$_user.'@'.$caller_els[1];
} else {
$this->destinationPrint=$_user;
}
$caller_els=explode("@",$this->cNumberPrint);
if (is_numeric($caller_els[0]) && strlen($caller_els[0]>3)) {
$_user=substr($caller_els[0],0,strlen($caller_els[0])-3).'xxx';
} else {
$_user='dialedNumber';
}
if (count($caller_els)== 2) {
$this->cNumberPrint=$_user.'@'.$caller_els[1];
} else {
$this->cNumberPrint=$_user;
}
$caller_els=explode("@",$this->RemoteAddressPrint);
if (is_numeric($caller_els[0]) && strlen($caller_els[0]>3)) {
$_user=substr($caller_els[0],0,strlen($caller_els[0])-3).'xxx';
} else {
$_user='remoteAddress';
}
if (count($caller_els)== 2) {
$this->RemoteAddressPrint=$_user.'@'.$caller_els[1];
} else {
$this->RemoteAddressPrint=$_user;
}
// Canonical URI
$caller_els=explode("@",$this->CanonicalURIPrint);
if (is_numeric($caller_els[0]) && strlen($caller_els[0]>3)) {
$_user=substr($caller_els[0],0,strlen($caller_els[0])-3).'xxx';
} else {
$_user='canonicalURI';
}
if (count($caller_els)== 2) {
$this->CanonicalURIPrint=$_user.'@'.$caller_els[1];
} else {
$this->CanonicalURIPrint=$_user;
}
if (is_numeric($this->SipRPIDPrint) && strlen($this->SipRPIDPrint) > 3) {
$this->SipRPIDPrint=substr($this->SipRPID,0,strlen($this->SipRPID)-3).'xxx';
} else {
$_user='callerId';
}
// IP address
$this->SourceIP='xxx.xxx.xxx.xxx';
}
}
}
class CDRS_opensips_mongo extends CDRS_opensips {
var $CDR_class = "CDR_opensips_mongo";
var $mongo_db_ro = NULL;
var $mongo_db_rw = NULL;
function getCDRtables() {
if (!is_object($this->mongo_db_rw) && !$this->initDatabaseConnection) {
return array();
}
$_tables=array();
try {
$_tables=$this->mongo_db_rw->listCollections();
} catch (Exception $e) {
printf("<p>Caught Mongo exception in getCDRtables(): %s", $e->getMessage());
}
$t=count($_tables);
if ($this->table) $this->tables[]=$this->table;
foreach ($_tables as $_table) {
$_table=strval($_table);
if (preg_match("/^.*\.(radacct\d{6})$/",$_table,$m)) {
if ($list_t > 24) break;
if (!in_array($m[1], $this->tables)) {
$this->tables[]=$m[1];
}
$list_t++;
}
$t--;
}
$this->tables=array_unique($this->tables);
}
function initDatabaseConnection() {
if ($this->DATASOURCES[$this->cdr_source]['mongo_db']) {
$mongo_db = $this->CDRTool['mongo_db'][$this->DATASOURCES[$this->cdr_source]['mongo_db']];
$mongo_uri = $mongo_db['uri'];
$mongo_replicaSet = $mongo_db['replicaSet'];
$mongo_database = $mongo_db['database'];
try {
$mongo_connection_ro = new Mongo("mongodb://$mongo_uri?readPreference=secondaryPreferred", array("replicaSet" => $mongo_replicaSet));
$this->mongo_db_ro = $mongo_connection_ro->selectDB($mongo_database);
$mongo_connection_rw = new Mongo("mongodb://$mongo_uri?readPreference=primaryPreferred", array("replicaSet" => $mongo_replicaSet));
$this->mongo_db_rw = $mongo_connection_rw->selectDB($mongo_database);
return true;
} catch (Exception $e) {
printf("<p>Caught exception in initDatabaseConnection(): %s", $e->getMessage());
return false;
}
}
return true;
}
function getMongoTable($table, $rw=false) {
try {
if ($rw) {
if (!$this->mongo_db_rw && !$this->initDatabaseConnection()) {
return NULL;
}
$table = $this->mongo_db_rw->selectCollection($table);
} else {
if (!$this->mongo_db_ro && !$this->initDatabaseConnection()) {
return NULL;
}
$table = $this->mongo_db_ro->selectCollection($table);
}
return $table;
} catch (Exception $e) {
printf("<p>Caught exception in getMongoTable(): %s", $e->getMessage());
}
return NULL;
}
function initCDRFields() {
// init names of CDR fields
foreach (array_keys($this->CDRFields) as $field) {
$mongo_field=$field;
$_field=$field."Field";
$this->$_field=$mongo_field;
}
}
function _readCDRFieldsFromDB($mongo_result) {
foreach (array_keys($this->CDRFields) as $field) {
$CDRStructure[$this->CDRFields[$field]] = $mongo_result[$field];
}
return $CDRStructure;
}
function getUnNormalized($where="",$table) {
# TODO
return 0;
}
function show() {
global $perm;
foreach ($this->FormElements as $_el) {
${$_el} = trim($_REQUEST[$_el]);
}
if ($begin_time) {
list($begin_hour,$begin_min)=explode(":",$begin_time);
}
if ($end_time) {
list($end_hour,$end_min)=explode(":",$end_time);
}
if ($begin_date) {
list($begin_year,$begin_month,$begin_day)=explode("-",$begin_date);
}
if ($end_date) {
list($end_year,$end_month,$end_day)=explode("-",$end_date);
}
// overwrite some elements based on user rights
if ($this->CDRTool['filter']['gateway']) {
$gateway =$this->CDRTool['filter']['gateway'];
}
if (!$this->export) {
if (!$begin_datetime) {
$begin_datetime="$begin_year-$begin_month-$begin_day $begin_hour:$begin_min";
$begin_datetime_timestamp=mktime($begin_hour, $begin_min, 0, $begin_month,$begin_day,$begin_year);
} else {
$begin_datetime_timestamp=$begin_datetime;
$begin_datetime=Date("Y-m-d H:i",$begin_datetime);
}
if (!$end_datetime) {
$end_datetime_timestamp=mktime($end_hour, $end_min, 0, $end_month,$end_day,$end_year);
$end_datetime="$end_year-$end_month-$end_day $end_hour:$end_min";
} else {
$end_datetime_timestamp=$end_datetime;
$end_datetime=Date("Y-m-d H:i",$end_datetime);
}
} else {
$begin_datetime=Date("Y-m-d H:i",$begin_datetime);
$end_datetime=Date("Y-m-d H:i",$end_datetime);
}
if (!$order_by || (!$group_by && $order_by == "group_by")) {
$order_by=$this->idField;
}
$mongo_where = array();
if (!$cdr_table) $cdr_table=$this->table;
$mongo_table_ro = $this->getMongoTable($cdr_table);
$mongo_table_rw = $this->getMongoTable($cdr_table, true);
$this->url=sprintf("?cdr_source=%s&cdr_table=%s",$this->cdr_source,$cdr_table);
if ($this->CDRTool['filter']['domain']) {
$this->url .= sprintf("&Realms=%s",urlencode($this->CDRTool['filter']['domain']));
$Realms = explode(" ",$this->CDRTool['filter']['domain']);
} else if ($Realms) {
$this->url .= sprintf("&Realms=%s",urlencode($Realms));
$Realms = explode(" ",$Realms);
}
if ($this->CDRTool['filter']['aNumber']) {
$this->url .= sprintf("&UserName=%s",urlencode($this->CDRTool['filter']['aNumber']));
}
if ($this->CDRTool['filter']['after_date']) {
$mongo_where[$this->startTimeField] = array('$gte' => $this->CDRTool['filter']['after_date']);
}
if ($order_by) {
$this->url.=sprintf("&order_by=%s&order_type=%s",addslashes($order_by),addslashes($order_type));
}
$this->url.=sprintf("&begin_datetime=%s",urlencode($begin_datetime_timestamp));
$this->url.=sprintf("&end_datetime=%s",urlencode($end_datetime_timestamp));
if (!$call_id && $begin_datetime && $end_datetime) {
$mongo_where[$this->startTimeField] = array('$gte' => $begin_datetime, '$lt' => $end_datetime);
} else {
$mongo_where[$this->startTimeField] = array('$gte' => '1970-01-01');
}
if ($MONTHYEAR) {
$mongo_where[$this->startTimeField] = new MongoRegex("/^$MONTHYEAR/");
$this->url.= sprintf("&MONTHYEAR=%s",urlencode($MONTHYEAR));
}
if ($flow) {
$this->url.=sprintf("&flow=%s",urlencode($flow));
$mongo_where[$this->flowField] = $flow;
}
if ($this->CDRTool['filter']['aNumber']) {
// force user to see only CDRS with his a_numbers
$mongo_where['$or'] = array(array($this->usernameField => $this->CDRTool['filter']['aNumber']), array($this->CanonicalURIField => $this->CDRTool['filter']['aNumber']));
$UserName_comp='equal';
$UserName=$this->CDRTool['filter']['aNumber'];
}
if ($UserName_comp == "empty") {
$mongo_where[$this->usernameField] = '';
$this->url.=sprintf("&UserName_comp=%s",urlencode($UserName_comp));
} else if (strlen($UserName) && !$this->CDRTool['filter']['aNumber']) {
if (!$UserName_comp) $UserName_comp='begin';
if ($UserName_comp=="begin") {
$mongo_where[$this->usernameField] = new MongoRegex("/^$UserName/");
} elseif ($UserName_comp=="contain") {
$mongo_where[$this->usernameField] = new MongoRegex("/$UserName/");
} elseif ($UserName_comp=="equal") {
$mongo_where[$this->usernameField] = $UserName;
} else {
$mongo_where[$this->usernameField] = '';
}
$this->url.=sprintf("&UserName=%s&UserName_comp=%s",urlencode($UserName),$UserName_comp);
}
$a_number=trim($a_number);
if ($a_number_comp == "empty") {
$mongo_where[$this->aNumberField] = '';
$this->url.=sprintf("&a_number_comp=%s",urlencode($a_number_comp));
} else if (strlen($a_number)) {
$a_number=urldecode($a_number);
if (!$a_number_comp) $a_number_comp="equal";
$this->url.=sprintf("&a_number=%s",urlencode($a_number));
if ($a_number_comp=="begin") {
$mongo_where[$this->aNumberField] = new MongoRegex("/^$a_number/");
} elseif ($a_number_comp=="contain") {
$mongo_where[$this->aNumberField] = new MongoRegex("/$a_number/");
} elseif ($a_number_comp=="equal") {
$mongo_where[$this->aNumberField] = $a_number;
}
$this->url.=sprintf("&a_number_comp=%s",urlencode($a_number_comp));
}
$c_number=trim($c_number);
if ($c_number_comp == "empty") {
$mongo_where[$this->CanonicalURIField] = '';
$this->url.=sprintf("&c_number_comp=%s",urlencode($c_number_comp));
} else if (strlen($c_number)) {
$c_number=urldecode($c_number);
if (!$c_number_comp) $c_number_comp="begin";
if (!$c_number_comp || $c_number_comp=="begin") {
$mongo_where[$this->CanonicalURIField] = new MongoRegex("/^$c_number/");
} elseif ($c_number_comp=="contain") {
$mongo_where[$this->CanonicalURIField] = new MongoRegex("/$c_number/");
} elseif ($c_number_comp=="equal") {
$mongo_where[$this->CanonicalURIField] = $c_number;
}
$this->url.=sprintf("&c_number=%s&c_number_comp=%s",urlencode($c_number),urlencode($c_number_comp));
}
$Realm=trim($Realm);
if ($Realms) {
$d_array=array();
foreach ($Realms as $realm) {
$d_array[] = array($this->domainField => $realm);
}
$mongo_where['$or'] = $d_array;
} else if ($Realm) {
$Realm=urldecode($Realm);
$mongo_where[$this->domainField] = $Realm;
$this->url.=sprintf("&Realm=%s",urlencode($Realm));
}
$BillingId=trim($BillingId);
if (preg_match("/^\d+$/",$BillingId) && $this->BillingIdField) {
$mongo_where[$this->BillingIdField] = $BillingId;
$this->url.=sprintf("&BillingId=%s",urlencode($BillingId));
}
if ($application) {
$mongo_where[$this->applicationField] = new MongoRegex("/$application/");
$this->url.=sprintf("&application=%s",urlencode($application));
}
if ($DestinationId) {
if ($DestinationId=="empty") {
$DestinationIdSQL="";
} else {
$DestinationIdSQL=$DestinationId;
}
$mongo_where[$this->DestinationIdField] = $DestinationIdSQL;
$this->url.=sprintf("&DestinationId=%s",urlencode($DestinationId));
}
if (strlen(trim($ExcludeDestinations))) {
# TODO: migrateb clause to mongo
$ExcludeDestArray=explode(" ",trim($ExcludeDestinations));
foreach ($ExcludeDestArray as $exclDst) {
if (preg_match("/^0+(\d+)$/",$exclDst,$m)) {
$exclDest_id=$m[1];
} else {
$exclDest_id=$exclDst;
}
$where .= " and ".
$this->CanonicalURIField.
" not like '".
addslashes(trim($exclDst)).
"'";
}
$this->url.=sprintf("&ExcludeDestinations=%s",urlencode($ExcludeDestinations));
}
$call_id=trim($call_id);
if ($call_id) {
$call_id=urldecode($call_id);
$mongo_where[$this->callIdField] = $call_id;
$this->url.=sprintf("&call_id=%s",urlencode($call_id));
}
if ($sip_proxy) {
$sip_proxy=urldecode($sip_proxy);
$mongo_where[$this->SipProxyServerField] = $sip_proxy;
$this->url.=sprintf("&sip_proxy=%s",urlencode($sip_proxy));
}
if ($SipCodec) {
$this->url.=sprintf("&SipCodec=%s",urlencode($SipCodec));
if ($SipCodec != "empty") {
$mongo_where[$this->SipCodecField] = $SipCodec;
} else {
$mongo_where[$this->SipCodecField] = '';
}
}
if ($SipRPID) {
$this->url.=sprintf("&SipRPID=%s",urlencode($SipRPID));
if ($SipRPID != "empty") {
$mongo_where[$this->SipRPIDField] = $SipRPID;
} else {
$mongo_where[$this->SipRPIDField] = '';
}
}
if ($UserAgent) {
$mongo_where[$this->UserAgentField] = $UserAgent;
$this->url.=sprintf("&UserAgent=%s",urlencode($UserAgent));
}
if (strlen($sip_status)) {
$mongo_where[$this->disconnectField] = $sip_status;
$this->url.=sprintf("&sip_status=%s",urlencode($sip_status));
}
if ($sip_status_class) {
$mongo_where[$this->disconnectField] = new MongoRegex("/^$sip_status_class/");
$this->url.=sprintf("&sip_status_class=%s",urlencode($sip_status_class));
}
if ($this->CDRTool[filter]["gateway"]) {
$mongo_where[$this->gatewayField] = $this->CDRTool[filter]["gateway"];
} else if ($gateway) {
$gateway=urldecode($gateway);
$mongo_where[$this->gatewayField] = $gateway;
$this->url.=sprintf("&gateway=%s",$gateway);
}
if ($duration) {
if (preg_match("/\d+/",$duration) ) {
$mongo_where[$this->durationField] = array('$gt' => 0);;
} elseif (preg_match("/onehour/",$duration) ) {
$mongo_where[$this->durationField] = array('$lt' => 3610, '$gt' => 3530);
} elseif ($duration == "zero") {
$mongo_where[$this->durationField] = 0;
} elseif ($duration == "zeroprice" && $this->priceField) {
$mongo_where[$this->durationField] = array('$gt' => 0);
$mongo_where[$this->priceField] = NULL;
} elseif ($duration == "nonzero") {
$mongo_where[$this->durationField] = array('$gt' => 0);
} elseif ($duration == "onewaymedia") {
$mongo_where['$or'] = array(array($this->outputTrafficField => 0), array($this->inputTrafficField => 0));
} elseif ($duration == "nomedia") {
$mongo_where[$this->inputTrafficField] = 0;
$mongo_where[$this->outputTrafficField] = 0;
}
$this->url.=sprintf("&duration=%s",urlencode($duration));
}
if ($media_info) {
$this->url.=sprintf("&media_info=%s",urlencode($media_info));
$mongo_where[$this->MediaInfoField] = $media_info;
}
$this->url.=sprintf("&maxrowsperpage=%s",addslashes($this->maxrowsperpage));
$url_calls = $this->scriptFile.$this->url."&action=search";
if ($group_by) {
$this->url.=sprintf("&group_by=%s",urlencode($group_by));
}
$this->url_edit = $this->scriptFile.$this->url."&action=edit";
$this->url_run = $this->scriptFile.$this->url."&action=search";
$this->url_export = $_SERVER["PHP_SELF"].$this->url."&action=search&export=1";
if ($duration == "unnormalized") {
$mongo_where[$this->normalizedField] = '0';
}
if ($duration == "unnormalized_duration") {
$mongo_where[$this->normalizedField] = '0';
$mongo_where[$this->durationField] = array('$gt' => 0);
}
if ($group_by) {
$this->group_byOrig=$group_by;
if ($group_by=="hour") {
$group_by="HOUR(AcctStartTime)";
} else if (preg_match("/^DAY/",$group_by)) {
$group_by="$group_by(AcctStartTime)";
} else if (preg_match("/BYMONTH/",$group_by)) {
$group_by="DATE_FORMAT(AcctStartTime,'%Y-%m')";
} else if (preg_match("/BYYEAR/",$group_by)) {
$group_by="DATE_FORMAT(AcctStartTime,'%Y')";
} else if ($group_by=="UserAgentType") {
$group_by="SUBSTRING_INDEX($this->SipUserAgentsField, ' ', '1')";
}
$this->group_by=$group_by;
if ($group_by==$this->callIdField) {
$having=sprintf(" having count(%s) > 1 ", addslashes($group_by));
}
$field = array_search($group_by, $this->CDRFields);
$pipeline=array(
array('$match' => $mongo_where),
array('$group' => array("_id" => sprintf('$%s', $field),
'calls' => array('$sum' => 1))),
array('$match' => array('calls' => array('$gte' => 0)))
);
$rows = 0;
if ($mongo_table_ro) {
try {
$group_results = $mongo_table_ro->aggregate($pipeline);
$rows = count($group_results);
} catch (Exception $e) {
printf("<p>Caught Mongo exception in show(): %s", $e->getMessage());
}
}
} else {
$rows = 0;
if ($mongo_table_ro) {
try {
$rows = $mongo_table_ro->find($mongo_where)->slaveOkay()->count();
} catch (Exception $e) {
printf("<p>Caught Mongo exception in show(): %s", $e->getMessage());
}
}
}
dprint_r($mongo_where);
$this->rows=$rows;
if ($this->CDRTool['filter']['aNumber']) {
$this->showResultsMenuSubscriber('0',$begin_datetime,$end_datetime);
} else {
$this->showResultsMenu('0',$begin_datetime,$end_datetime);
}
if (!$this->next) {
$i=0;
$this->next=0;
} else {
$i=$this->next;
}
$j=0;
$z=0;
if ($rows>0) {
if ($call_id && $ReNormalize) {
if ($mongo_table_rw) {
$mongo_table_rw->update(array($this->normalizedField=>0), array('$set' => array($this->callIdField => $call_id)));
}
}
if ($UnNormalizedCalls=$this->getUnNormalized($mongo_where,$cdr_table)) {
if (!$this->DATASOURCES[$this->cdr_source]['skipNormalizeOnPageLoad']) {
if ($UnNormalizedCalls < $this->maxCDRsNormalizeWeb) {
$this->NormalizeCDRS($mongo_where,$cdr_table);
if (!$this->export && $this->status['normalized'] ) {
print "<div class=\"alert alert-info\">";
printf ("<b><span class=\"alert-heading\">%d</span></b> CDRs normalized. ",$this->status['normalized']);
if ($this->status['cached_keys']['saved_keys']) {
printf ("Quota usage updated for <b><span class=\"alert-heading\">%d</span></b> accounts. ",$this->status['cached_keys']['saved_keys']);
}
print "</div>";
}
}
}
}
if ($rows > $this->maxrowsperpage) {
$maxrows=$this->maxrowsperpage+$this->next;
if ($maxrows > $rows) {
$maxrows=$rows;
$prev_rows=$maxrows;
}
} else {
$maxrows=$rows;
}
if ($duration == "unnormalized") {
// if display un normalized calls we must substract
// the amount of calls normalized above
$maxrows=$maxrows-$this->status['normalized'];
}
$mongo_order_by = '_id';
if ($order_type == DESC) {
$mongo_order_type = -1;
} else {
$mongo_order_type = 1;
}
if ($group_by) {
if ($order_by == "group_by") {
$mongo_order_by = '_id';
} else {
$_tmp = array_search($order_by, $this->CDRFields);
if (in_array($_tmp, array('price', 'duration','inputTraffic', 'outputTraffic'))) {
$mongo_order_by = $_tmp;
} else {
$mongo_order_by = 'calls';
}
}
$pipeline=array(
array('$match' => $mongo_where),
array('$group' => array('_id' => sprintf('$%s', $field),
'calls' => array( '$sum' => 1),
'duration' => array( '$sum' => '$duration'),
'inputTraffic' => array( '$sum' => '$inputTraffic'),
'outputTraffic' => array( '$sum' => '$outputTraffic'),
'price' => array( '$sum' => '$price'),
'zero' => array( '$sum' => array('$cond'=> array(array('$eq' => array('$duration', 0)), 1, 0 ))),
'nonzero' => array( '$sum' => array('$cond'=> array(array('$gt' => array('$duration', 0)), 1, 0 )))
)
),
array('$match' => array('calls' => array('$gte' => 0))),
array('$sort' => array($mongo_order_by => $mongo_order_type)),
array('$skip' => intval($i)),
array('$limit' => intval($this->maxrowsperpage))
);
//dprint_r($pipeline);
try {
$group_results = $mongo_table_ro->aggregate($pipeline);
} catch (Exception $e) {
printf("<p>Caught Mongo exception in show(): %s", $e->getMessage());
}
$this->showTableHeaderStatistics();
foreach ($group_results as $result) {
$found=$i+1;
$mygroup = $result['_id'];
$calls = $result['calls'];
$seconds = $result['duration'];
$price = $result['price'];
$zero = $result['zero'];
$zeroP = $calls/$zero * 100;
$nonzero = $result['nonzero'];
$nonzeroP = $calls/$nonzero * 100;
$seconds_print = number_format($seconds,0);
$minutes = number_format($seconds/60,0,"","");
$minutes_print = number_format($seconds/60,0);
$hours = sec2hms($seconds);
$AcctInputOctets = number_format($result['inputTraffic'] * 2/ 1024/1024,2,".","");
$AcctOutputOctets = number_format($result['outputTraffic'] * 2/ 1024/1024,2,".","");
$NetRateIn = $result['inputTraffic']*8*2/1024/$seconds;
$NetRateOut = $result['outputTraffic']*8*2/1024/$seconds;
$success = number_format($nonzero/$calls*100,2,".","");
$failure = number_format($zero/$calls*100,2,".","");
$NetworkRateIn = number_format($NetRateIn,2);
$NetworkRateOut = number_format($NetRateOut,2);
$NetworkRate = max($NetworkRateIn,$NetworkRateOut);
$rr=floor($found/2);
$mod=$found-$rr*2;
if ($mod ==0) {
$inout_color="lightgrey";
} else {
$inout_color="white";
}
$traceValue="";
$mygroup_print=quoted_printable_decode($mygroup);
if ($this->group_byOrig==$this->DestinationIdField) {
if ($this->CDRTool['filter']['domain'] && $this->destinations[$this->CDRTool['filter']['domain']]) {
list($_dst_id,$_dst_name)=$this->getPSTNDestinationId($mygroup,'',$this->CDRTool['filter']['domain']);
$description=$_dst_name;
} else {
$description=$this->destinations[0]["default"][$mygroup]["name"];
}
if ($mygroup) {
$traceValue=$mygroup;
} else {
$traceValue="empty";
}
} else if ($this->group_byOrig==$this->aNumberField) {
# Normalize Called Station Id
$N=$this->NormalizeNumber($mygroup);
$mygroup_print=$N['username']."@".$N[domain];
$description="";
$traceField="a_number";
$traceValue=urlencode($mygroup);
} else if ($this->group_byOrig==$this->CanonicalURIField) {
$traceField="c_number";
$traceValue=urlencode($mygroup);
} else if ($this->group_byOrig==$this->SipProxyServerField) {
$traceField="sip_proxy";
$traceValue=urlencode($mygroup);
} else if ($this->group_byOrig==$this->SipCodecField) {
$traceField="SipCodec";
} else if (preg_match("/UserAgent/",$this->group_byOrig)) {
$traceField="UserAgent";
} else if (preg_match("/^BY/",$this->group_byOrig)) {
$traceField="MONTHYEAR";
} else if ($this->group_byOrig==$this->callIdField) {
$traceField="call_id";
} else if ($this->group_byOrig=="SourceIP") {
$traceField = "gateway";
} else if ($this->group_byOrig=="SipResponseCode") {
$description = $this->disconnectCodesDescription[$mygroup];
$traceField="sip_status";
} else if ($this->group_byOrig=="SipApplicationType") {
$traceField="application";
} else if ($this->group_byOrig=="ServiceType") {
$traceField="flow";
} else {
$description="";
}
if (!$traceField) {
$traceField = $group_by;
}
if (!$traceValue) {
$traceValue = $mygroup;
}
if (!$traceValue) {
$traceValue="";
$comp_type="empty";
} else {
$comp_type="begin";
}
$traceValue_enc=urlencode($traceValue);
if (!$this->export) {
print "
<tr>
<td><b>$found</b></td>
<td align=right>$calls</td>
<td align=right>$seconds_print</td>
<td align=right>$minutes_print</td>
<td align=right>$hours</td>
";
if ($perm->have_perm("showPrice")) {
$pricePrint=number_format($price,4,".","");
} else {
$pricePrint='x.xxx';
}
print "
<td align=right>$pricePrint</td>
<td align=right>$AcctInputOctets</td>
<td align=right>$AcctOutputOctets</td>
<td align=right>$success%</td>
<td align=right>($nonzero calls)</td>
<td align=right>$failure%</td>
<td align=right>($zero calls)</td>
<td>$mygroup_print</td>
<td>$description</td>
<td>";
printf("<a href=%s&%s=%s&%s_comp=%s target=_new>Display calls</a></td>",$url_calls,$traceField,$traceValue_enc,$traceField,$comp_type);
print "
</tr>
";
} else {
print "$found,";
print "$calls,";
print "$seconds,";
print "$minutes,";
print "$hours,";
if ($perm->have_perm("showPrice")) {
$pricePrint=$price;
} else {
$pricePrint='x.xxx';
}
print "$pricePrint,";
print "$AcctInputOctets,";
print "$AcctOutputOctets,";
print "$success,";
print "$nonzero,";
print "$failure,";
print "$zero,";
print "$mygroup_print,";
print "$description";
print "\n";
}
$i++;
}
if (!$this->export) {
print "
</table>
";
}
} else {
if (!$this->export) {
// printf ("<div class='alert alert-info'><i style='font-size:13px' class='icon-info-sign'></i> For more information about each call click on its Id column.</div>");
}
if ($order_by=="zeroP" || $order_by=="nonzeroP") {
$order_by="timestamp";
}
if ($mongo_table_ro) {
$cursor = $mongo_table_ro->find($mongo_where)->sort(array($mongo_order_by=>$mongo_order_type))->skip($i)->limit($this->maxrowsperpage)->slaveOkay();
} else {
$cursor = array();
}
if ($this->CDRTool['filter']['aNumber']) {
$this->showTableHeaderSubscriber();
} else {
if (!$this->export) {
$this->showTableHeader();
} else {
$this->showExportHeader();
}
}
foreach ($cursor as $result) {
global $found;
$found=$i+1;
$Structure=$this->_readCDRFieldsFromDB($result);
$CDR = new $this->CDR_class($this, $Structure);
if ($this->CDRTool['filter']['aNumber']) {
$CDR->showSubscriber();
} else {
if (!$this->export) {
$CDR->show();
} else {
$CDR->export();
}
}
$i++;
}
if (!$this->export) {
print "
</table>
";
}
}
$this->showPagination($this->next,$maxrows);
}
}
}
class CDR_opensips_mongo extends CDR_opensips {
}
class SIP_trace {
var $enableThor = false;
var $trace_array = array();
var $traced_ip = array();
var $SIPProxies = array();
var $mediaTrace = false;
var $thor_nodes = array();
var $hostnames = array();
function SIP_trace ($cdr_source) {
global $DATASOURCES, $auth;
$this->cdr_source = $cdr_source;
$this->cdrtool = new DB_CDRTool();
if (!is_array($DATASOURCES[$this->cdr_source])) {
$log=sprintf("Error: datasource '%s' is not defined",$this->cdr_source);
print $log;
return 0;
}
if (strlen($DATASOURCES[$this->cdr_source]['enableThor'])) {
$this->enableThor = $DATASOURCES[$this->cdr_source]['enableThor'];
}
if (strlen($DATASOURCES[$this->cdr_source]['mediaTrace'])) {
$this->mediaTrace = $DATASOURCES[$this->cdr_source]['mediaTrace'];
}
if ($this->enableThor) {
require("/etc/cdrtool/ngnpro_engines.inc");
require_once("ngnpro_soap_library.php");
if ($DATASOURCES[$this->cdr_source]['soapEngineId'] && in_array($DATASOURCES[$this->cdr_source]['soapEngineId'],array_keys($soapEngines))) {
$this->soapEngineId=$DATASOURCES[$this->cdr_source]['soapEngineId'];
$this->SOAPlogin = array(
"username" => $soapEngines[$this->soapEngineId]['username'],
"password" => $soapEngines[$this->soapEngineId]['password'],
"admin" => true
);
$this->SOAPurl=$soapEngines[$this->soapEngineId]['url'];
$this->SoapAuth = array('auth', $this->SOAPlogin , 'urn:AGProjects:NGNPro', 0, '');
// Instantiate the SOAP client
$this->soapclient = new WebService_NGNPro_SipPort($this->SOAPurl);
$this->soapclient->setOpt('curl', CURLOPT_TIMEOUT, 5);
$this->soapclient->setOpt('curl', CURLOPT_SSL_VERIFYPEER, 0);
$this->soapclient->setOpt('curl', CURLOPT_SSL_VERIFYHOST, 0);
if (is_array($soapEngines[$this->soapEngineId]['hostnames'])) {
$this->hostnames=$soapEngines[$this->soapEngineId]['hostnames'];
}
} else {
printf ("<p><font color=red>Error: soapEngineID not defined in datasource %s</font>",$this->cdr_source);
return false;
}
} else {
$this->table = $DATASOURCES[$this->cdr_source]['table'];
$db_class = $DATASOURCES[$this->cdr_source]['db_class'];
$this->purgeRecordsAfter = $DATASOURCES[$this->cdr_source]['purgeRecordsAfter'];
if (class_exists($db_class)) {
$this->db = new $db_class;
} else {
printf("<p><font color=red>Error: database class '%s' is not defined</font>",$db_class);
return false;
}
}
if (is_object($auth)) $this->isAuthorized=1;
if (is_array($DATASOURCES[$this->cdr_source]['SIPProxies'])) {
$this->SIPProxies=$DATASOURCES[$this->cdr_source]['SIPProxies'];
}
}
function isProxy($ip,$sip_proxy='') {
if (!$ip) return false;
if (!$this->enableThor) {
if (!is_array($this->SIPProxies)) {
return false;
}
if (in_array($ip,array_keys($this->SIPProxies))) {
return true;
}
} else if ($sip_proxy) {
if ($this->thor_nodes[$ip]) {
return true;
} else {
if (isThorNode($ip,$sip_proxy)) {
$this->thor_nodes[$ip]=1;
return true;
} else {
return false;
}
}
}
return false;
}
function getTrace ($proxyIP,$callid,$fromtag,$totag) {
if ($this->enableThor) {
// get trace using soap request
if (!$proxyIP || !$callid || !$fromtag) return false;
if (!is_object($this->soapclient)) {
print "Error: soap client is not defined.";
return false;
}
$this->seen_ip=array();
$filter=array('nodeIp' => $proxyIP,
'callId' => $callid,
'fromTag' => $fromtag,
'toTag' => $totag
);
$this->soapclient->addHeader($this->SoapAuth);
$result = $this->soapclient->getSipTrace($filter);
if (PEAR::isError($result)) {
$error_msg = $result->getMessage();
$error_fault = $result->getFault();
$error_code = $result->getCode();
printf("<font color=red>Error from %s: %s (%s)</font>",$this->SOAPurl,
$error_fault->detail->exception->errorstring,
$error_fault->detail->exception->errorcode
);
return false;
}
$columns=0;
$traces=json_decode($result);
$trace_array=array();
foreach ($traces as $_trace) {
if (preg_match("/^(udp|tcp|tls):(.*):(.*)$/",$_trace->to_ip,$m)) {
$toip = $m[2];
$transport = $m[1];
$toport = $m[3];
} else if (preg_match("/^(.*):(.*)$/",$_trace->to_ip,$m)) {
$toip = $m[1];
$transport = 'udp';
$toport = $m[2];
} else {
$toip = $_trace->to_ip;
$transport = 'udp';
$toport = '5060';
}
if (preg_match("/^(udp|tcp|tls):(.*):(.*)$/",$_trace->from_ip,$m)) {
$fromip = $m[2];
$fromport = $m[3];
} else if (preg_match("/^(.*):(.*)$/",$_trace->from_ip,$m)) {
$fromip = $m[1];
$fromport = $m[2];
} else {
$fromip = $_trace->from_ip;
}
if (!$this->seen_ip[$toip] && $this->isProxy($toip)) {
$this->seen_ip[$toip]++;
}
if (!$this->seen_ip[$fromip] && $this->isProxy($fromip)) {
$this->seen_ip[$fromip]++;
}
if (!$this->column[$fromip]) {
$this->column[$fromip] = $columns+1;
$this->column_port[$fromip]=$fromport;
$columns++;
}
if (!$this->column[$toip]) {
$this->column[$toip] = $columns+1;
$this->column_port[$toip]=$toport;
$columns++;
}
preg_match("/^(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)$/",$_trace->time_stamp,$m);
$timestamp = mktime($m[4],$m[5],$m[6],$m[2],$m[3],$m[1]);
$idx=$proxyIP.'_'.$_trace->id;
$trace_array[$idx]=
array (
'id' => $idx,
'direction' => $_trace->direction,
'fromip' => $fromip,
'toip' => $toip,
'fromport' => $fromport,
'toport' => $toport,
'method' => $_trace->method,
'transport' => $transport,
'date' => $_trace->time_stamp,
'status' => $_trace->status,
'timestamp' => $timestamp,
'msg' => $_trace->message,
'md5' => md5($_trace->message)
);
}
$this->trace_array=$trace_array;
$this->rows = count($this->trace_array);
} else {
// get trace from SQL
if (!is_object($this->db)) {
print "<p><font color=red>Error: no database connection defined</font>";
return false;
}
$query=sprintf("select *,UNIX_TIMESTAMP(time_stamp) as timestamp
from %s where callid = '%s' order by id asc",
addslashes($this->table),
addslashes($callid));
if (!$this->db->query($query)) {
printf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
return false;
}
$this->rows = $this->db->num_rows();
$columns = 0;
while ($this->db->next_record()) {
if (preg_match("/^(udp|tcp|tls):(.*):(.*)$/",$this->db->f('toip'),$m)) {
$toip = $m[2];
$transport = $m[1];
$toport = $m[3];
} else if (preg_match("/^(.*):(.*)$/",$this->db->f('toip'),$m)) {
$toip = $m[1];
$transport = 'udp';
$toport = $m[2];
} else {
$toip = $this->db->f('toip');
$toport = '5060';
}
if (preg_match("/^(udp|tcp|tls):(.*):(.*)$/",$this->db->f('fromip'),$m)) {
$fromip = $m[2];
$fromport = $m[3];
} else if (preg_match("/^(.*):(.*)$/",$this->db->f('fromip'),$m)) {
$fromip = $m[1];
$fromport = $m[2];
} else {
$fromip = $this->db->f('fromip');
$transport = 'udp';
$fromport = '5060';
}
if (!$this->seen_ip[$toip] && $this->isProxy($toip)) {
$this->seen_ip[$toip]++;
}
if (!$this->seen_ip[$fromip] && $this->isProxy($fromip)) {
$this->seen_ip[$fromip]++;
}
if (!$this->column[$fromip]) {
$this->column[$fromip]=$columns+1;
$this->column_port[$fromip]=$fromport;
$columns++;
}
if (!$this->column[$toip]) {
$this->column[$toip]=$columns+1;
$this->column_port[$toip]=$toport;
$columns++;
}
$this->trace_array[$this->db->f('id')]=
array (
'id' => $this->db->f('id'),
'direction' => $this->db->f('direction'),
'fromip' => $fromip,
'toip' => $toip,
'method' => $this->db->f('method'),
'fromport' => $fromport,
'toport' => $toport,
'transport' => $transport,
'date' => $this->db->f('time_stamp'),
'status' => $this->db->f('status'),
'timestamp' => $this->db->f('timestamp'),
'msg' => $this->db->f('msg'),
'md5' => md5($this->db->f('msg'))
);
}
}
}
function show($proxyIP,$callid,$fromtag,$totag) {
$action = $_REQUEST['action'];
$toggleVisibility = $_REQUEST['toggleVisibility'];
if ($action=='toggleVisibility') {
$this->togglePublicVisibility($callid,$fromtag,$toggleVisibility);
}
if ($_SERVER['HTTPS'] == "on") {
$protocolURL = "https://";
} else {
$protocolURL = "http://";
}
$this->getTrace($proxyIP,$callid,$fromtag,$totag);
if (!count($this->trace_array)) {
print "<p>
SIP trace for session id $callid is not available.";
return;
}
print "<div class=container-fluid><div id=trace class=main>
<h1 class='page-header'>CDRTool SIP trace
<small>SIP session $callid $authorizei</small></h1>
<div class=row-fluid>
<div class=span9>
<form class=form-inline method=post name=visibility>
";
// if ($this->isAuthorized) {
// $key="callid-".trim($callid).trim($fromtag);
// $query=sprintf("select * from memcache where `key` = '%s'",addslashes($key));
// $this->cdrtool->query($query);
$basicURL = $protocolURL.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
// if ($this->cdrtool->num_rows()) {
// $selected_toggleVisibility['public']="selected";
// $fullURL=$basicURL."&public=1";
// $color2="lightblue";
// } else {
// $selected_toggleVisibility['private']="selected";
$fullURL=$basicURL;
// }
// print "
// This SIP trace is visible
// <select class=span3 name=toggleVisibility onChange=\"document.visibility.submit.disabled = true; location.href = '$basicURL&action=toggleVisibility&toggleVisibility=' + this.options[this.selectedIndex].value\">
// <option $selected_toggleVisibility[public] value=1>without authorization
// <option $selected_toggleVisibility[private] value=0>only to authorized users
// </select>
// <input type=hidden name=action value=toggleVisibility>
// ";
print "URLs for this trace: <a href=$fullURL>HTML</a> | <a href=$fullURL&format=text>TEXT</a></td>";
//} else {
// print "";
//}
if ($this->mediaTrace) {
$this->mediaTraceLink=sprintf("<p class=pull-right><a href=\"javascript:void(null);\" onClick=\"return window.open('media_trace.phtml?cdr_source=%s&callid=%s&fromtag=%s&totag=%s&proxyIP=%s', 'mediatrace',
'toolbar=0,status=0,menubar=0,scrollbars=1,resizable=1,width=800,height=730')\">Click here for RTP media information</a></p>",
$this->mediaTrace,
urlencode($callid),
urlencode($fromtag),
urlencode($totag),
$proxyIP
);
}
print "
</form>
</div>
<div class='span3'>
<p class='pull-right'>
Click on each packet to expand its body content</p>
$this->mediaTraceLink
</div>
</div>
";
foreach (array_keys($this->trace_array) as $key) {
if ($this->trace_array[$key]['direction'] == 'in') {
if (is_array($this->SIPProxies)) {
$thisIP=explode(":",$this->trace_array[$key]['fromip']);
if ($this->isProxy($thisIP[0],$proxyIP)) {
$this->trace_array[$key]['isProxy'] = 1;
}
}
if ($this->trace_array[$key]['fromip'] == $this->trace_array[$key]['toip']) {
$this->trace_array[$key]['arrow_align'] = "left";
$arrow_direction="loop";
} else if ($this->column[$this->trace_array[$key]['fromip']] < $this->column[$this->trace_array[$key]['toip']]) {
$arrow_direction="right";
$this->trace_array[$key]['arrow_align'] = "right";
} else {
$arrow_direction="left";
$this->trace_array[$key]['arrow_align'] = "left";
}
$this->trace_array[$key]['msg_possition'] = $this->column[$this->trace_array[$key]['toip']];
$this->trace_array[$key]['arrow_possition'] = $this->column[$this->trace_array[$key]['fromip']];
$this->trace_array[$key]['arrow_direction'] = $arrow_direction;
} else {
if ($this->trace_array[$key]['fromip'] == $this->trace_array[$key]['toip']) {
$this->trace_array[$key]['arrow_align'] = "left";
$arrow_direction="loop";
} else if ($this->column[$this->trace_array[$key]['fromip']] < $this->column[$this->trace_array[$key]['toip']]) {
$this->trace_array[$key]['arrow_align'] = "left";
$arrow_direction="right";
} else {
$this->trace_array[$key]['arrow_align'] = "right";
$arrow_direction="left";
}
$this->trace_array[$key]['msg_possition'] = $this->column[$this->trace_array[$key]['fromip']];
$this->trace_array[$key]['arrow_possition'] = $this->column[$this->trace_array[$key]['toip']];
$this->trace_array[$key]['arrow_direction'] = $arrow_direction;
}
}
//print_r($this->hostnames);
print "
<p>
<a name=#top>
<table class='table table-condensed table-hover' cellpadding=2 cellspacing=0 border=0 width=100%>
<thead>
<tr>
<th></th>
<th align=center><b>Packet</b></th>
<th align=center><b>Size</b></th>
<th align=center><b>Time</b></th>
";
foreach (array_keys($this->column) as $_key) {
$IPels=explode(":",$_key);
if ($this->hostnames[$IPels[0]]) {
$_hostname=$this->hostnames[$IPels[0]];
} else {
$_hostname=$_key;
}
print "<th align=center class=border>";
if ($proxyIP != $IPels[0] && $this->isProxy($IPels[0],$proxyIP)) {
$trace_link=sprintf("<a href=\"javascript:void(null);\" onClick=\"return window.open('sip_trace.phtml?cdr_source=%s&callid=%s&fromtag=%s&totag=%s&proxyIP=%s', 'Trace',
'toolbar=0,status=1,menubar=1,scrollbars=1,resizable=1,width=1000,height=600')\"><font color=red><b>%s:%s (Trace) </b></font></a>",
urlencode($this->cdr_source),
urlencode($callid),
urlencode($fromtag),
urlencode($totag),
$IPels[0],
$_hostname,
$this->column_port[$_key]
);
printf ("<b><font color=blue>%s</b>",$trace_link);
} else {
printf ("<b>%s</b>",$_hostname);
}
print "</th>";
}
print "</tr>
</thead>";
$i=0;
foreach (array_keys($this->trace_array) as $key) {
$i++;
$id = $this->trace_array[$key]['id'];
$msg = $this->trace_array[$key]['msg'];
$fromip = $this->trace_array[$key]['fromip'];
$toip = $this->trace_array[$key]['toip'];
$date = substr($this->trace_array[$key]['date'],11);
$status = $this->trace_array[$key]['status'];
$direction = $this->trace_array[$key]['direction'];
$timestamp = $this->trace_array[$key]['timestamp'];
$method = $this->trace_array[$key]['method'];
$isProxy = $this->trace_array[$key]['isProxy'];
$transport = $this->trace_array[$key]['transport'];
$msg_possition = $this->trace_array[$key]['msg_possition'];
$arrow_possition = $this->trace_array[$key]['arrow_possition'];
$arrow_direction = $this->trace_array[$key]['arrow_direction'];
$arrow_align = $this->trace_array[$key]['arrow_align'];
$md5 = $this->trace_array[$key]['md5'];
if ($i==1) $begin_timestamp = $timestamp;
$timeline=$timestamp-$begin_timestamp;
$sip_phone_img=getImageForUserAgent($msg);
if ($seen_msg[$md5]) continue;
$SIPclass=substr($status,0,1);
if ($SIPclass=="6") {
$status_color="<font color=red>";
} else if ($SIPclass=="5" ) {
$status_color="<font color=red>";
} else if ($SIPclass=="4" ) {
$status_color="<font color=blue>";
} else if ($SIPclass=="3" ) {
$status_color="<font color=green>";
} else if ($SIPclass=="2" ) {
$status_color="<font color=green>";
} else if ($SIPclass=="1" ) {
$status_color="<font color=\"#cc6600\">";
} else {
$status_color="<font color=black>";
}
$_lines=explode("\n",$msg);
if (preg_match("/^(.*) SIP/",$_lines[0],$m)) {
$_lines[0]=$m[1];
} else if (preg_match("/^SIP\/2\.0 (.*)/",$_lines[0],$m)) {
$_lines[0]=$m[1];
}
unset($media);
unset($diversions);
$j=0;
$media_index=0;
$search_ice=0;
$search_ip=0;
$contact_header='';
foreach ($_lines as $_line) {
if (preg_match("/^(Diversion: ).*;(.*)$/",$_line,$m)) {
$diversions[]=$m[1].$m[2];
}
if (preg_match("/^Cseq:\s*\d+\s*(.*)$/i",$_line,$m)) {
$status_for_method=$m[1];
}
if (preg_match("/^Contact:\s*.*@(.*:\d+).*$/i",$_line,$m)) {
$contact_header=$m[1];
}
if (preg_match("/^c=IN \w+ ([\d|\w\.]+)/i",$_line,$m)) {
$media['ip']=$m[1];
}
if (preg_match("/^m=(\w+) (\d+) /i",$_line,$m)) {
$media_index++;
$search_ice=1;
$search_ip=1;
$media['streams'][$media_index]=array('type' => $m[1],
'ip' => $media['ip'],
'port' => $m[2],
'ice' => ''
);
}
if ($search_ip && preg_match("/^c=IN \w+ ([\d|\w\.]+)/i",$_line,$m)) {
$media['streams'][$media_index]['ip']=$m[1];
$search_ip=0;
}
if ($search_ice && preg_match("/^a=ice/i",$_line,$m)) {
$media['streams'][$media_index]['ice']="ICE";
$search_ice=0;
}
$j++;
}
$_els=explode(";",$_lines[0]);
$cell_content = "<a name=\"packet$i\">
$status_color $_els[0]</font>
";
if ($status) $cell_content.=" <font color=black>for ".$status_for_method."</font>";
if ($contact_header) {
$cell_content.=sprintf("<br>Contact: %s",htmlspecialchars($contact_header));
}
if (is_array($diversions)) {
foreach ($diversions as $_diversion) {
$cell_content.="<br><b>$_diversion</b>";
}
}
if (is_array($media['streams'])) {
foreach (array_keys($media['streams']) as $_key) {
$_stream=sprintf("%s->%s:%s %s",$media['streams'][$_key]['type'],
$media['streams'][$_key]['ip'],
$media['streams'][$_key]['port'],
$media['streams'][$_key]['ice']
);
if ($media['streams'][$_key]['port']) {
$cell_content.="<br><b>$_stream</b>";
} else {
$cell_content.="<br><b><font color=red>$_stream</font></b>";
}
}
}
$cell_content.="
</font>
</a>
";
print "
<tr class=border onClick=\"return toggleVisibility('row$i')\">
<td>
";
if ($timeline && !$_seen_timeline[$timeline]) {
printf ("%s+%ds </font>",$status_color,$timeline);
$_seen_timeline[$timeline]++;
}
$len=strlen($msg);
print "
</td>
<td class=bbot>$status_color$i/$this->rows&nbsp;</font></td>
<td class=bbot>$len bytes</td>
<td class=bbot><nobr>$status_color$date</nobr></font>
";
$column_current=1;
while ($column_current <= count($this->column)) {
if ($arrow_possition==$column_current) {
if ($direction=='out') {
if ($arrow_direction == 'left') {
$arrow="green_arrow_left.png";
} else if ($arrow_direction == 'right') {
$arrow="green_arrow_right.png";
} else if ($arrow_direction == 'loop'){
$arrow="LoopArrow.png";
}
} else {
if ($arrow_direction == 'left') {
$arrow="blue_arrow_left.png";
} else if ($arrow_direction == 'right') {
$arrow="blue_arrow_right.png";
} else if ($arrow_direction == 'loop'){
$arrow="LoopArrow.png";
}
}
}
if ($arrow_possition==$column_current) {
print "<td class=bbot align=$arrow_align>";
if ($arrow_direction == 'left') {
print "<img src=images/$arrow border=0>";
if (!$isProxy && $direction=='in' && $sip_phone_img && $sip_phone_img!='unknown.png')
print "<img src=images/30/$sip_phone_img border=0>";
} else {
if (!$isProxy && $direction=='in' && $sip_phone_img && $sip_phone_img!='unknown.png')
print "<img src=images/30/$sip_phone_img border=0>";
print "<img src=images/$arrow border=0>";
}
print "<br>";
if ($transport == 'tls') print "<span style='font-size:16px'><i class='icon-lock'></i></span> ";
if ($direction == 'in') {
printf ("%s port %d",strtoupper($transport),$this->trace_array[$key]['fromport']);
} else {
printf ("%s port %d",strtoupper($transport),$this->trace_array[$key]['toport']);
}
} else {
print "<td class=bbot>";
}
if ($msg_possition == $column_current) {
print $cell_content;
print "<br>";
if ($direction == 'in') {
printf ("%s port %d",strtoupper($transport),$this->trace_array[$key]['toport']);
} else {
printf ("%s port %d",strtoupper($transport),$this->trace_array[$key]['fromport']);
}
} else {
print "&nbsp;";
}
print "
</td>
";
$column_current++;
if ($arrow_direction=='loop') $seen_msg[$md5]++;
}
print "</tr>";
if (is_array($this->SIPProxies)) {
$IPels=explode(":",$fromip);
$justIP=$IPels[0];
foreach (array_keys($this->SIPProxies) as $localProxy) {
if ($localProxy==$justIP) {
$direction="out";
break;
}
}
}
$trace_span=count($this->column)+2;
print "
<tr class=extrainfo id=row$i >
<td></td>
<td colspan=$trace_span>
";
print "<div class='alert alert-info'>
<div class=row-fluid><div class='span2'><div class='row-fluid'><div class='span12'>";
if ($direction == "out") {
print "
<nobr>
<h1>SIP Proxy</h1></nobr>
";
} else {
if ($sip_phone_img) print "<img style='max-width:none' src=images/$sip_phone_img>";
}
print "</div></div><div class=row-fluid><div class='span12'>";
if ($timeline > 0) {
printf ("<p>+%s s<br>(%s)",$timeline,sec2hms($timeline));
}
print "</div></div></div><div class=span10>";
$msg=nl2br(htmlentities($msg));
print "
$status_color $msg
</div></div></div>";
print "
</td>
<td></td>
</tr>
";
}
print "
</table>
";
}
function showText($proxyIP,$callid,$fromtag,$totag) {
$this->getTrace($proxyIP,$callid,$fromtag,$totag);
print "<pre>";
if (!count($this->trace_array)) {
print "SIP trace for session id $callid is not available.";
return false;
}
printf ("SIP trace on proxy %s for session %s\n--\n\n",$proxyIP,$callid);
foreach (array_keys($this->trace_array) as $key) {
$i++;
printf ("Packet %d at %s from %s to %s (%s)\n",
$i,
$this->trace_array[$key]['date'],
$this->trace_array[$key]['fromip'],
$this->trace_array[$key]['toip'],
$this->trace_array[$key]['direction']);
printf ("\n%s\n",htmlspecialchars($this->trace_array[$key]['msg']));
print "---\n";
}
print "</pre>";
}
function togglePublicVisibility($callid,$fromtag,$public='0') {
$key="callid-".trim($callid).trim($fromtag);
if (!$public) {
$query=sprintf("delete from memcache where `key` = '%s'",addslashes($key));
$this->cdrtool->query($query);
} else {
$query=sprintf("delete from memcache where `key` = '%s'",addslashes($key));
$this->cdrtool->query($query);
$query=sprintf("insert into memcache values ('%s','public')",addslashes($key));
$this->cdrtool->query($query);
}
}
function purgeRecords($days='') {
if ($this->enableThor) {
return true;
}
$b=time();
if ($days) {
$this->purgeRecordsAfter=$days;
} else if (!$this->purgeRecordsAfter) {
$this->purgeRecordsAfter=15;
}
$beforeDate=Date("Y-m-d", time()-$this->purgeRecordsAfter*3600*24);
$query=sprintf("select id as min, time_stamp from %s order by id ASC limit 1",
addslashes($this->table));
if ($this->db->query($query)) {
if ($this->db->num_rows()) {
$this->db->next_record();
$min=$this->db->f('min');
$begindate=$this->db->f('date');
} else {
$log=sprintf("No records found in %s\n",$this->table);
print $log;
syslog(LOG_NOTICE,$log);
return false;
}
} else {
$log=sprintf("Error: %s (%s)\n",$this->db->Error,$query);
print $log;
syslog(LOG_NOTICE,$log);
return false;
}
$query=sprintf("select id as max from %s where time_stamp < '%s' order by id DESC limit 1",
addslashes($this->table),addslashes($beforeDate));
if ($this->db->query($query) && $this->db->num_rows()) {
$this->db->next_record();
$max=$this->db->f('max');
} else {
$log=sprintf("No records found in %s before %s, records start after %s\n",
$this->table,$beforeDate,$begindate);
syslog(LOG_NOTICE,$log);
print $log;
return false;
}
$deleted=0;
$i=$min;
$interval=1000;
$rows2delete=$max-$min;
$found = 0;
print "$rows2delete traces to delete between $min and $max\n";
while ($i<=$max) {
$found=$found+$interval;
if ($i + $interval < $max) {
$top=$i;
} else {
$top=$max;
}
$query=sprintf("delete low_priority from %s
where id >= '%d' and id <='%d'",
addslashes($this->table),addslashes($min),addslashes($top));
if ($this->db->query($query)) {
$deleted=$deleted+$this->db->affected_rows();
} else {
$log=sprintf("Error: %s (%s)",$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE,$log);
return false;
}
if ($found > $progress*$rows2delete/100) {
$progress++;
if ($progress%10==0) {
print "$progress% ";
}
flush();
}
$i=$i+$interval;
}
print "\n";
$e =time();
$d =$e-$b;
$rps=0;
if ($deleted && $d) $rps=$deleted/$d;
$log=sprintf("%s records before %s from %s deleted in %d s @ %.0f rps\n",$deleted,$beforeDate,$this->table,$d,$rps);
syslog(LOG_NOTICE,$log);
print $log;
return true;
}
}
class Media_trace {
var $enableThor = false;
var $table = 'media_sessions';
function Media_trace ($cdr_source) {
global $DATASOURCES;
$this->cdr_source = $cdr_source;
$this->cdrtool = new DB_CDRTool();
if (!is_array($DATASOURCES[$this->cdr_source])) {
$log=sprintf("Error: datasource '%s' is not defined",$this->cdr_source);
print $log;
return 0;
}
if (strlen($DATASOURCES[$this->cdr_source]['enableThor'])) {
$this->enableThor = $DATASOURCES[$this->cdr_source]['enableThor'];
}
if ($this->enableThor) {
require("/etc/cdrtool/ngnpro_engines.inc");
require_once("ngnpro_soap_library.php");
if ($DATASOURCES[$this->cdr_source]['soapEngineId'] && in_array($DATASOURCES[$this->cdr_source]['soapEngineId'],array_keys($soapEngines))) {
$this->soapEngineId=$DATASOURCES[$this->cdr_source]['soapEngineId'];
$this->SOAPlogin = array(
"username" => $soapEngines[$this->soapEngineId]['username'],
"password" => $soapEngines[$this->soapEngineId]['password'],
"admin" => true
);
$this->SOAPurl=$soapEngines[$this->soapEngineId]['url'];
$this->SoapAuth = array('auth', $this->SOAPlogin , 'urn:AGProjects:NGNPro', 0, '');
// Instantiate the SOAP client
$this->soapclient = new WebService_NGNPro_SipPort($this->SOAPurl);
$this->soapclient->setOpt('curl', CURLOPT_TIMEOUT, 5);
$this->soapclient->setOpt('curl', CURLOPT_SSL_VERIFYPEER, 0);
$this->soapclient->setOpt('curl', CURLOPT_SSL_VERIFYHOST, 0);
} else {
print "Error: soapEngineID not defined in datasource $this->cdr_source";
return false;
}
} else {
if ($DATASOURCES[$this->cdr_source]['table']) {
$this->table = $DATASOURCES[$this->cdr_source]['table'];
}
$db_class = $DATASOURCES[$this->cdr_source]['db_class'];
if (class_exists($db_class)) {
$this->db = new $db_class;
} else {
printf("<p><font color=red>Error: database class %s is not defined in datasource %s</font>",$db_class,$this->cdr_source);
return false;
}
}
}
function getTrace ($proxyIP,$callid,$fromtag,$totag) {
if ($this->enableThor) {
// get trace using soap request
if (!$proxyIP || !$callid || !$fromtag) {
print "<p><font color=red>Error: proxyIP or callid or fromtag are not defined</font>";
return false;
}
if (!is_object($this->soapclient)) {
print "<p><font color=red>Error: soap client is not defined</font>";
return false;
}
$filter=array('nodeIp' => $proxyIP,
'callId' => $callid,
'fromTag' => $fromtag,
'toTag' => $totag
);
$this->soapclient->addHeader($this->SoapAuth);
$result = $this->soapclient->getMediaTrace($filter);
if (PEAR::isError($result)) {
$error_msg = $result->getMessage();
$error_fault = $result->getFault();
$error_code = $result->getCode();
if ($error_fault->detail->exception->errorcode != 1060) {
printf("<font color=red>Error from %s: %s (%s)</font>",
$this->SOAPurl,
$error_fault->detail->exception->errorstring,
$error_fault->detail->exception->errorcode
);
}
return false;
}
$this->info = json_decode($result);
} else {
if (!is_object($this->db)) {
print "<p><font color=red>Error: no database connection defined</font>";
return false;
}
// get trace from SQL
$query=sprintf("select info from %s where call_id = '%s' and from_tag = '%s' and to_tag= '%s'",
addslashes($this->table),
addslashes($callid),
addslashes($fromtag),
addslashes($totag)
);
if (!$this->db->query($query)) {
printf ("<p><font color=red>Database error for query %s: %s (%s)</font>",$query,$this->db->Error,$this->db->Errno);
return false;
}
if ($this->db->num_rows()) {
$this->db->next_record();
$this->info = json_decode($this->db->f('info'));
}
}
}
function show($proxyIP,$callid,$fromtag,$totag) {
if ($_SERVER['HTTPS'] == "on") {
$protocolURL = "https://";
} else {
$protocolURL = "http://";
}
$this->getTrace($proxyIP,$callid,$fromtag,$totag);
print "<div class=container-fluid'><div id=trace class='main'>";
if (!is_object($this->info)) {
print "<p>No information available.";
return false;
}
if (!count($this->info->streams)) {
print "<p>
No RTP media streams have been established";
return;
}
print "
<h1 class=page-header>CDRTool Media Trace
<small>Media Session $callid</small></h1>
";
foreach (array_values($this->info->streams) as $_val) {
$_diff=$_val->end_time-$_val->timeout_wait;
$seen_stamp[$_val->start_time]++;
$seen_stamp[$_val->end_time]++;
$seen_stamp[$_diff]++;
$media_types[]=$_val->media_type;
}
print "<h2>Media Information</h2>";
print "<table border=0>";
printf ("<tr><td class=border>Call duration</td><td class=border>%s</td></tr>",$this->info->duration);
list($relay_ip,$relay_port)=explode(":",$this->info->streams[0]->caller_local);
printf ("<tr><td class=border>Media relay</td><td class=border>%s</td></tr>",$relay_ip);
print "</table>";
print "<h2>Media Streams</h2>";
print "<table class='table table-condensed table-striped' style='width:300px' border=0>";
print "<thead><tr><th></th>";
foreach (array_values($media_types) as $_type) {
printf ("<th>%s</th>",ucfirst($_type));
}
print "</tr></thead>";
foreach ($this->info->streams[0] as $_val => $_value) {
printf ("<tr><td class=border>%s</td>",ucfirst(preg_replace("/_/"," ",$_val)));
$j=0;
while ($j < count($media_types)) {
printf ("<td class=border>%s</td>",$this->info->streams[$j]->$_val);
$j++;
}
printf ("</tr>\n");
}
print "</table>";
print "<br><h2>Stream Succession</h2>";
$w_legend_bar=500;
$w_text=30;
$stamps=array_keys($seen_stamp);
sort($stamps);
$w_table=$w_legend_bar+$w_text;
print "<table border=0 cellpadding=1 cellspacing=1 width=$w_table>";
$j=0;
$_index=0;
foreach (array_values($this->info->streams) as $_val) {
if ($_val->status == 'unselected ice candidate') continue;
$_index=$_index+$_val->start_time;
$_duration = $_val->end_time-$_val->start_time;
$_timeout = $_val->timeout_wait;
$duration_print= $_duration;
if ($_val->status == 'conntrack timeout') {
$w_duration = intval(($_duration-$_timeout)*$w_legend_bar/$this->info->duration);
$w_timeout = intval($_timeout*$w_legend_bar/$this->info->duration);
$duration_print = $_duration - $_timeout;
} else if ($_val->status == 'no-traffic timeout') {
$w_duration = intval($_duration*$w_legend_bar/$this->info->duration);
$w_timeout = intval($_timeout*$w_legend_bar/$this->info->duration);
} else if ($_val->status == 'closed' ) {
$w_duration = intval($_duration * $w_legend_bar / $this->info->duration);
$w_timeout = 0;
}
$w_start_time = intval($_index*$w_legend_bar/$this->info->duration);
$w_rest = $w_legend_bar-$w_duration-$w_timeout-$w_start_time;
$w_duration_p = ($w_legend_bar/$w_duration) * 100;
$w_timeout_p = ($w_legend_bar/$w_timeout)* 100;
$w_start_p = ($w_legend_bar/$w_start)* 100;
//printf ("%s, %s, %s, %s<br>\n",$w_start_p,$w_duration_p,$w_timeout_p,$w_rest);
if ($_val->caller_packets != '0' && $_val->callee_packets != '0'){
print "<tr><td width=$w_text class=border>$_val->media_type</td>";
print "<td width=$w_legend_bar>\n";
//print "<table width=100% border=0 cellpadding=0 cellspacing=0><tr>\n";
print "<div class='progress progress-striped'>";
print "<div class=bar style='width:$w_start_p%'></div>\n";
print "<div class='bar bar-success' style='width:$w_duration_p% ; text-align:center'><font color=white>$duration_print</font></div>\n";
if ($_val->timeout_wait) {
print "<div class='bar bar-danger' style='width:$w_timeout%; text-align:center'><font color=white>$_timeout</font></div>\n";
} else {
print "<div class='bar bar-warning' style='width:$w_timeout%; text-align:center'></div>\n";
}
//print "<td width=$w_rest bgcolor=white align=center></td>\n";
//print "</table>\n";
print "</td></tr>";
} elseif ( $_val->status == 'unselected ICE candidate') {
print "<tr><td>ICE session</td></tr>";
} else {
print "<tr><td>No stream data found</td></tr>";
}
}
print "</table>";
print "<br><strong>Legend</strong>";
print "<p><table border=0>
<tr><td width=50><div class='progress progress-striped progress-success'><div class='bar' style='width:100%'></div></div></td><td>Session data</td></tr>
<tr><td><div class='progress progress-striped progress-danger'><div class='bar' style='width:100%'></div></div></td><td>Timeout period</td></tr>
</table></p></div></div>
";
}
}
include_once("phone_images.php");
function getImageForUserAgent($msg) {
global $userAgentImages;
$msg_lines=explode("\n",$msg);
foreach($msg_lines as $line) {
$els=explode(":",$line);
if (strtolower($els[0]) == 'user-agent' || strtolower($els[0]) == 'server') {
foreach ($userAgentImages as $agentRegexp => $image) {
if (preg_match("/^(user-agent|server):.*$agentRegexp/i", $line)) {
return $image;
}
}
}
}
return "unknown.png";
}
function isThorNode($ip,$sip_proxy) {
if (!$ip || !$sip_proxy) return false;
$socket = fsockopen($sip_proxy, 9500, $errno, $errstr, 1);
if (!$socket) {
return false;
}
$request=sprintf("is_online %s as sip_proxy",$ip);
if (fputs($socket,"$request\r\n") !== false) {
$ret = trim(fgets($socket,4096));
fclose($socket);
} else {
fclose($socket);
return false;
}
if ($ret == 'Yes') {
return true;
} else {
return false;
}
}
?>
diff --git a/library/rating.php b/library/rating.php
index 5f9577b..9519cdc 100644
--- a/library/rating.php
+++ b/library/rating.php
@@ -1,9506 +1,9506 @@
<?
/*
Copyright (c) 2007-2012 AG Projects
http://ag-projects.com
This library contains classes and functions for rating functionality
*/
class Rate {
var $priceDenominator = 10000; // allow sub cents
var $priceDecimalDigits = 4; // web display
var $durationPeriodRated = 60; // how the prices are indicated in the billing_rates, default is per minute
var $trafficSizeRated = 1024; // in KBytes, default 1MByte
var $rate_longer_than = 0; // minimum duration considered to apply rates for a call, if call is shorter the price is zero
var $ENUMtld = '';
var $ENUMdiscount = 0; // how much percentage to substract from the final price
var $price = 0;
var $spans = 0; // number of spans we looped through
var $connectCost = 0;
var $increment = 0; // used to consider the duration of the call in increments (default 1 second)
var $min_duration = 0; // minimum duration considered for calculating the price
var $max_duration = 0; // maximum duration considered for calculating the price
var $max_price = 0; // maximum price for the call
var $discount_connect = 0;
var $discount_duration = 0;
var $rateValuesCache = array(); // used to speed up prepaid apoplication
var $broken_rate = false;
var $mongo_db = NULL;
var $db = NULL;
var $database_backend = "mysql";
function Rate($settings, $db) {
$this->db = $db;
$this->settings = $settings;
if ($this->database_backend == "mysql") {
$this->db->Halt_On_Error="no";
}
if ($this->settings['priceDenominator']) {
$this->priceDenominator=$this->settings['priceDenominator'];
}
if ($this->settings['priceDecimalDigits']) {
$this->priceDecimalDigits=$this->settings['priceDecimalDigits'];
}
if ($this->settings['durationPeriodRated']) {
$this->durationPeriodRated=$this->settings['durationPeriodRated'];
}
if ($this->settings['trafficSizeRated']) {
$this->trafficSizeRated=$this->settings['trafficSizeRated'];
}
if ($this->settings['rate_longer_than']) {
// if call is shorter than this, it has zero cost
$this->rate_longer_than=$this->settings['rate_longer_than'];
}
if ($this->settings['min_duration']) {
// if call is shorter than this, it has zero cost
$this->min_duration=$this->settings['min_duration'];
}
if ($this->settings['increment']) {
$this->increment=$this->settings['increment'];
}
if ($this->settings['database_backend']) {
$this->database_backend=$this->settings['database_backend'];
}
if ($this->database_backend == "mongo") {
if (is_array($this->settings['mongo_db'])) {
$mongo_uri = $this->settings['mongo_db']['uri'];
$mongo_replicaSet = $this->settings['mongo_db']['replicaSet'];
$mongo_database = $this->settings['mongo_db']['database'];
try {
$mongo_connection = new Mongo("mongodb://$mongo_uri?readPreference=secondaryPreferred", array("replicaSet" => $mongo_replicaSet));
$this->mongo_db = $mongo_connection->selectDB($mongo_database);
} catch (Exception $e) {
syslog(LOG_NOTICE, sprintf("Error: cannot connect to mongo database %s: %s",$mongo_uri, $e->getMessage()));
$this->mongo_db = NULL;
}
}
}
}
function calculateAudio($dictionary) {
// used for calculate rate for audio application
$this->RatingTables = $dictionary['RatingTables'];
$this->callId = $dictionary['callId'];
$this->timestamp = $dictionary['timestamp'];
$this->duration = $dictionary['duration'];
$this->traffic = 2 * ($dictionary['inputTraffic'] + $dictionary['outputTraffic']);
$this->DestinationId = $dictionary['DestinationId'];
$this->BillingPartyId = $dictionary['BillingPartyId'];
$this->domain = $dictionary['domain'];
$this->gateway = $dictionary['gateway'];
$this->ResellerId = $dictionary['ResellerId'];
$this->aNumber = $dictionary['aNumber'];
$this->cNumber = $dictionary['cNumber'];
$this->ENUMtld = $dictionary['ENUMtld'];
if ($this->rate_longer_than && $this->duration < $this->rate_longer_than) {
//syslog(LOG_NOTICE, "Duration less than minimum $this->rate_longer_than");
$this->rateInfo .= " Duration < $this->rate_longer_than s\n";
return true;
}
if ($this->ENUMtld && $this->ENUMtld != 'n/a' && $this->ENUMtld != 'none' && $this->RatingTables->ENUMtlds[$this->ENUMtld]) {
$this->ENUMdiscount = $this->RatingTables->ENUMtlds[$this->ENUMtld]['discount'];
if (!is_numeric($this->ENUMdiscount ) || $this->ENUMdiscount < 0 || $this->ENUMdiscount > 100) {
syslog(LOG_NOTICE, "Error: ENUM discount for tld $this->ENUMtld must be between 0 and 100");
}
}
if (!$this->gateway) {
$this->gateway="0.0.0.0";
}
if (!$this->duration) {
$this->duration = 0;
}
if (!$this->traffic) {
$this->traffic = 0;
}
$this->application=$dictionary['application'];
if (!$this->application) {
$this->application = 'audio';
}
$durationRate = 0;
$foundRates=array();
if (!$this->DestinationId) {
syslog(LOG_NOTICE, "Error: Cannot calculate rate without destination id for callid=$this->callId");
return false;
}
if (!$this->lookupDestinationDetails()) {
// get region, increment and other per destination details
syslog(LOG_NOTICE, "Error: Cannot find destination details for call_id=$this->callId, dest_id=$this->DestinationId)");
return false;
}
if (!$this->lookupProfiles()) {
// get profiles for the billing party
syslog(LOG_NOTICE, "Error: Cannot find any profiles for call_id=$this->callId, dest_id=$this->DestinationId)");
return false;
}
// lookup discounts if any
$this->lookupDiscounts();
$this->startTimeBilling = getLocalTime($this->billingTimezone,$this->timestamp);
list($dateText,$timeText) = explode(" ",trim($this->startTimeBilling));
$Bdate = explode("-",$dateText);
$Btime = explode(":",$timeText);
$this->timestampBilling = mktime($Btime[0], $Btime[1], $Btime[2], $Bdate[1], $Bdate[2], $Bdate[0]);
$this->startTimeBilling = Date("Y-m-d H:i:s",$this->timestampBilling);
$this->trafficKB=number_format($this->traffic/1024,0,"","");
// check min_duration and increment per destination
if ($this->increment >= 1) {
// increase the billed duration to the next increment
$this->duration = $this->increment * ceil($this->duration / $this->increment);
}
if ($this->max_duration && $this->duration > $this->max_duration) {
// limit the maximum duration for rating
$this->duration=$this->max_duration;
}
$this->rateSyslog="";
if ($this->duration) {
if ($this->increment >= 1) {
$this->rateInfo .=
" Increment: $this->increment s\n";
$this->rateSyslog .= sprintf("Increment=%s ",$this->increment);
}
if ($this->min_duration) {
$this->rateInfo .=
" Min duration: $this->min_duration s\n";
$this->rateSyslog .= sprintf("MinDuration=%s ",$this->min_duration);
}
if ($this->max_duration) {
$this->rateInfo .=
" Max duration: $this->max_duration s\n";
$this->rateSyslog .= sprintf("MaxDuration=%s ",$this->max_duration);
}
if ($this->max_price) {
$this->rateInfo .=
" Max price: $this->max_price\n";
$this->rateSyslog .= sprintf("MaxPrice=%s ",$this->max_price);
}
unset($IntervalsForPricing);
$this->rateInfo .=
" Duration: $this->duration s\n".
" App: $this->application\n".
" Destination: $this->DestinationId\n".
" Customer: $this->CustomerProfile\n";
if ($this->region) {
$this->rateInfo .=
" Region: $this->region\n";
}
if ($this->discount_duration || $this->discount_connect) {
$this->rateInfo .=
" Discount: ";
}
if ($this->discount_connect) {
$this->rateInfo .= " connect $this->discount_connect% ";
}
if ($this->discount_duration) {
$this->rateInfo .= " duration $this->discount_duration% ";
}
if ($this->discount_duration || $this->discount_connect) {
$this->rateInfo .= "\n";
}
if ($this->ENUMtld && $this->ENUMtld != 'none' && $this->ENUMtld != 'n/a') {
$this->rateInfo .=
" ENUM tld: $this->ENUMtld\n".
" ENUM discount: $this->ENUMdiscount%\n";
}
$i=0;
$durationRatedTotal=0;
// get recursively a set of arrays with rates
// until we billed the whole duration
while ($durationRatedTotal < $this->duration) {
if ($i == "0") {
$dayofweek = date("w",$this->timestampBilling);
$hourofday = date("G",$this->timestampBilling);
$dayofyear = date("Y-m-d",$this->timestampBilling);
} else {
$dayofweek = date("w",$this->timestampBilling+$durationRatedTotal);
$hourofday = $foundRate['nextHourOfDay'];
$dayofyear = date("Y-m-d",$this->timestampBilling+$durationRatedTotal);
}
$foundRate = $this->lookupRateAudio($dayofyear,$dayofweek,$hourofday,$durationRatedTotal);
$durationRatedTotal = $durationRatedTotal + $foundRate['duration'];
if (!$foundRate['rate']) {
$this->broken_rate=true;
return false;
}
$foundRates[] = $foundRate;
$i++;
if ($i > 10) {
// possible loop because of wrong coding make sure we end this loop somehow
$body="Rating of call $this->callId (DestId=$this->DestinationId) has more than 10 spans. It could be a serious bug.\n";
mail($this->toEmail, "CDRTool rating problem", $body , $this->extraHeaders);
syslog(LOG_NOTICE, "Error: Rating of call $this->callId (DestId=$this->DestinationId) has more than 10 spans.");
break;
}
}
}
$j=0;
$span=0;
foreach ($foundRates as $thisRate) {
$spanPrice=0;
$span++;
if ($j > 0) {
$payConnect=0;
$durationForRating=$thisRate['duration'];
} else {
$payConnect=1;
if ($this->min_duration && $this->duration < $this->min_duration) {
$durationForRating=$this->min_duration;
} else {
$durationForRating=$thisRate['duration'];
}
}
$connectCost = $thisRate['values']['connectCost'];
$durationRate = $thisRate['values']['durationRate'];
// apply discounts for connect
if ($this->discount_connect) {
$connectCost=$connectCost-$connectCost*$this->discount_connect/100;
}
// apply discounts for duration
if ($this->discount_duration) {
$durationRate=$durationRate-$durationRate*$this->discount_duration/100;
}
$connectCostIn = $thisRate['values']['connectCostIn'];
$durationRateIn = $thisRate['values']['durationRateIn'];
if ($span=="1") {
$connectCostSpan=$connectCost;
$this->connectCost=number_format($connectCost/$this->priceDenominator,$this->priceDecimalDigits);
$connectCostSpanIn=$connectCostIn;
$this->connectCostIn=number_format($connectCostIn/$this->priceDenominator,$this->priceDecimalDigits);
} else {
$connectCostSpan=0;
$connectCostSpanIn=0;
}
$connectCostPrint = number_format($connectCostSpan/$this->priceDenominator,$this->priceDecimalDigits);
$durationRatePrint = number_format($durationRate/$this->priceDenominator,$this->priceDecimalDigits);
$connectCostPrintIn = number_format($connectCostSpanIn/$this->priceDenominator,$this->priceDecimalDigits);
$durationRatePrintIn = number_format($durationRateIn/$this->priceDenominator,$this->priceDecimalDigits);
if (!$connectCostSpan) $connectCostSpan=0;
if (!$durationRate) $durationRate=0;
if (!$connectCostSpanIn) $connectCostSpanIn=0;
if (!$durationRateIn) $durationRateIn=0;
if (!$this->inputTraffic) $this->inputTraffic=0;
if (!$this->outputTraffic) $this->outputTraffic=0;
if ($span>1) $this->rateInfo .= "--\n";
/*
durationRate*durationForRating/durationPeriodRated/priceDenominator+
trafficRate/priceDenominator/trafficSizeRated*(inputTraffic+outputTraffic)/8");
$durationRate*$durationForRating/$this->durationPeriodRated/$this->priceDenominator+
$trafficRate/$this->priceDenominator/$this->trafficSizeRated*($this->inputTraffic+$this->outputTraffic)/8");
*/
$spanPrice = $durationRate*$durationForRating/$this->durationPeriodRated/$this->priceDenominator;
$this->price = $this->price+$spanPrice;
$spanPricePrint = number_format($spanPrice,$this->priceDecimalDigits);
$spanPriceIn = $durationRateIn*$durationForRating/$this->durationPeriodRated/$this->priceDenominator;
$this->priceIn = $this->priceIn+$spanPriceIn;
$spanPricePrintIn = number_format($spanPriceIn,$this->priceDecimalDigits);
if ($span=="1" && $thisRate['profile']) {
if ($connectCostIn) {
$this->rateInfo .=
" Connect in: $connectCostPrintIn\n";
}
$this->rateInfo .=
" Connect: $connectCostPrint\n".
" StartTime: $this->startTimeBilling\n".
"--\n";
$this->rateSyslog .= "ConnectFee=$connectCostPrint ";
$this->price = $this->price+$connectCostSpan/$this->priceDenominator*$payConnect;
$this->priceIn = $this->priceIn+$connectCostSpanIn/$this->priceDenominator*$payConnect;
}
$this->rateInfo .=
" Span: $span\n".
" Duration: $durationForRating s\n";
$this->rateSyslog .= sprintf("CallId=%s Span=%s Duration=%s DestId=%s %s",$this->callId,$span,$durationForRating,$this->DestinationId,$thisRate['customer']);
if ($thisRate['profile']) {
$this->rateInfo .=
" ProfileId: $thisRate[profile] / $thisRate[day]\n".
" RateId: $thisRate[rate] / $thisRate[interval]h\n".
" Rate: $durationRatePrint / $this->durationPeriodRated s\n".
" Price: $spanPricePrint\n";
if ($spanPriceIn) {
$this->rateInfo .=
" Price in: $spanPricePrintIn\n";
}
$this->rateSyslog .= sprintf(" Profile=%s Period=%s Rate=%s Interval=%s Cost=%s/%s",$thisRate['profile'],$thisRate['day'],$thisRate['rate'],$thisRate['interval'],$durationRatePrint,$this->durationPeriodRated);
} else {
$this->rateInfo .=
" ProfileId: none\n".
" RateId: none\n";
$this->rateSyslog .= " Profile=none, Rate=none";
}
$this->rateSyslog .= " Price=".sprintf("%.4f",$spanPrice);
$this->rateSyslog .= " PriceIn=".sprintf("%.4f",$spanPriceIn);
if ($this->discount_connect) {
$this->rateSyslog .= sprintf(" DisCon=%s",$this->discount_connect);
}
if ($this->discount_duration) {
$this->rateSyslog .= sprintf(" DisDur=%s",$this->discount_duration);
}
syslog(LOG_NOTICE, $this->rateSyslog);
$j++;
}
if ($this->priceIn) {
$this->rateInfo .= "--\n".
" Price out: ".sprintf("%.4f",$this->price)."\n".
" Price in: ".sprintf("%.4f",$this->priceIn)."\n".
" Margin: ".sprintf("%.4f",$this->price-$this->priceIn)."\n";
}
$this->rateInfo=trim($this->rateInfo);
if ($this->max_price && $this->price > $this->max_price) {
$this->price=$this->max_price;
}
if ($this->ENUMdiscount) {
$this->priceBeforeDiscount=sprintf("%.4f",$this->price);
$this->price = $this->price - $this->price*$this->ENUMdiscount/100;
$this->price=sprintf("%.4f",$this->price);
$this->rateInfo .=
"\n--\n".
" Total: $this->priceBeforeDiscount\n".
" Total after discount: $this->price\n";
}
$this->price=sprintf("%.4f",$this->price);
$this->pricePrint=number_format($this->price,$this->priceDecimalDigits);
return true;
}
function calculateMessage($dictionary) {
// used for calculate rate for SMS application
$this->RatingTables = $dictionary['RatingTables'];
$this->callId = $dictionary['callId'];
$this->timestamp = $dictionary['timestamp'];
$this->DestinationId = $dictionary['DestinationId'];
$this->BillingPartyId = $dictionary['BillingPartyId'];
$this->domain = $dictionary['domain'];
$this->gateway = $dictionary['gateway'];
$this->ResellerId = $dictionary['ResellerId'];
$this->aNumber = $dictionary['aNumber'];
$this->cNumber = $dictionary['cNumber'];
if (!$this->gateway) {
$this->gateway="0.0.0.0";
}
$this->application='sms';
$foundRates=array();
if (!$this->DestinationId) {
syslog(LOG_NOTICE, "Error calculateMessage(): Cannot calculate rate without destination id");
return false;
}
if (!$this->lookupProfiles()) {
// get profiles for the billing party
syslog(LOG_NOTICE, "Error: calculateMessage() Cannot find any profiles for call_id=$this->callId, dest_id=$this->DestinationId)");
return false;
}
// lookup discounts if any
$this->lookupDiscounts();
$this->startTimeBilling = getLocalTime($this->billingTimezone,$this->timestamp);
list($dateText,$timeText) = explode(" ",trim($this->startTimeBilling));
$Bdate = explode("-",$dateText);
$Btime = explode(":",$timeText);
$this->timestampBilling = mktime($Btime[0], $Btime[1], $Btime[2], $Bdate[1], $Bdate[2], $Bdate[0]);
$dayofweek = date("w",$this->timestampBilling);
$hourofday = date("G",$this->timestampBilling);
$dayofyear = date("Y-m-d",$this->timestampBilling);
$this->rateInfo .=
" App: sms\n".
" Destination: $this->DestinationId\n".
" Customer: $this->CustomerProfile\n";
if ($this->region) {
$this->rateInfo .=
" Region: $this->region\n";
}
if ($this->discount_duration || $this->discount_connect) {
$this->rateInfo .=
" Discount: ";
}
if ($this->discount_connect) {
$this->rateInfo .= " connect $this->discount_connect% ";
}
if ($this->discount_duration || $this->discount_connect) {
$this->rateInfo .= "\n";
}
$foundRate = $this->lookupRateMessage($dayofyear,$dayofweek,$hourofday);
if (is_array($foundRate)) {
$this->price=number_format($foundRate['values']['connectCost']/$this->priceDenominator,$this->priceDecimalDigits);
$this->price=sprintf("%.4f",$this->price);
$this->pricePrint=$this->price;
$this->rateInfo .=
" ProfileId: $foundRate[profile] / $foundRate[day]\n".
" RateId: $foundRate[rate]\n".
" Price: $this->price\n";
return true;
} else {
return false;
}
}
function lookupDiscounts() {
// get discounts for customer per region if set otherwise per destination id
if (!$this->CustomerProfile) {
return false;
}
if ($this->region) {
$_field='region';
$_value=$this->region;
} else {
$_field='destination';
$_value=$this->DestinationId;
}
if ($this->mongo_db != NULL) {
// mongo backend
if ($this->CustomerProfile == 'default') {
$mongo_where['subscriber'] = '';
$mongo_where['domain'] = '';
$mongo_where['domain'] = '';
$mongo_where['domain'] = '';
$mongo_where['application'] = $this->application;
$mongo_where[$_field] = $_value;
} else {
$els=explode("=",$this->CustomerProfile);
$mongo_where[$els[0]] = $els[1];
$mongo_where['application'] = $this->application;
$mongo_where[$_field] = $_value;
}
try {
$table = $this->mongo_db->selectCollection('billing_discounts');
$cursor = $table->find($mongo_where)->limit(1)->slaveOkay();
$result = $cursor->getNext();
} catch (Exception $e) {
$log = sprintf("<p>Caught exception in lookupDiscounts(): %s", $e->getMessage());
syslog(LOG_NOTICE, $log);
return false;
}
if($result) {
if ($result['connect'] > 0 && $result['connect'] <=100) {
$this->discount_connect = $result['connect'];
}
if ($result['duration'] > 0 && $result['duration'] <=100) {
$this->discount_duration = $result['duration'];
}
return true;
}
}
if ($this->CustomerProfile == 'default') {
$query=sprintf("select * from billing_discounts
where subscriber = ''
and domain = ''
and gateway = ''
and application = '%s'
and %s = '%s'
",
addslashes($this->application),
addslashes($_field),
addslashes($_value)
);
} else {
$els=explode("=",$this->CustomerProfile);
$query=sprintf("select * from billing_discounts
where %s = '%s'
and application = '%s'
and %s = '%s'
",
addslashes($els[0]),
addslashes($els[1]),
addslashes($this->application),
addslashes($_field),
addslashes($_value)
);
}
// mysql backend
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->num_rows()) {
$this->db->next_record();
if ($this->db->f('connect') > 0 && $this->db->f('connect') <=100) {
$this->discount_connect = $this->db->f('connect');
}
if ($this->db->f('duration') > 0 && $this->db->f('duration') <=100) {
$this->discount_duration = $this->db->f('duration');
}
}
return true;
}
function lookupDestinationDetails() {
// get rating related details for the destination id
if (!$this->DestinationId) {
syslog(LOG_NOTICE, "Error: Cannot lookup destination details without a destination id");
return false;
}
if ($this->mongo_db != NULL) {
// mongo backend
$mongo_where['dest_id'] = $this->DestinationId;
$mongo_where['$or'] = array(array('reseller_id' => intval($this->ResellerId)),
array('reseller_id' => 0)
);
try {
$table = $this->mongo_db->selectCollection('destinations');
$cursor = $table->find($mongo_where)->sort(array('reseller_id'=>-1))->limit(1)->slaveOkay();
$result = $cursor->getNext();
} catch (Exception $e) {
$log = sprintf("<p>Caught exception in lookupProfiles(): %s", $e->getMessage());
syslog(LOG_NOTICE, $log);
return false;
}
if(!$result) {
$log=sprintf ("Error: cannot find mongo destination details for dest id %s",$this->DestinationId);
syslog(LOG_NOTICE, $log);
//return false;
}
if($result) {
$this->region = $result['region'];
$this->max_duration = $result['max_duration'];
$this->max_price = $result['max_price'];
if ($result['increment']) {
$this->increment = $result['increment'];
}
if ($result['min_duration']) {
$this->min_duration = $result['min_duration'];
}
return true;
}
}
// mysql backend
$query=sprintf("select * from destinations
where dest_id = '%s'
and (reseller_id = %d or reseller_id = 0) order by reseller_id desc limit 1",
addslashes($this->DestinationId),
addslashes($this->ResellerId)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->num_rows()) {
$this->db->next_record();
$this->region = $this->db->Record['region'];
$this->max_duration = $this->db->Record['max_duration'];
$this->max_price = $this->db->Record['max_price'];
if ($this->db->Record['increment']) {
$this->increment = $this->db->Record['increment'];
}
if ($this->db->Record['min_duration']) {
$this->min_duration = $this->db->Record['min_duration'];
}
}
return true;
}
function lookupProfiles() {
unset($this->allProfiles);
/*
lookup the profile_name in billing_customers in the following order:
subscriber, domain, gateway (based on $dayofweek):
- profile_workday matches days [1-5] (Work-day)
- profile_weekend matches days [6-0] (Week-end)
- week starts with 0 Sunday and ends with 6 Saturday
Alternatively look for profile_workday_alt and profile_weekend_alt
If no rates are found for destination in the profileX,
than lookup rates in profileX_alt
*/
if ($this->mongo_db != NULL) {
// mongo backend
$mongo_where['$or'] = array(array('subscriber' => $this->BillingPartyId),
array('domain' => $this->domain),
array('gateway' => $this->gateway),
array('gateway' => '',
'domain' => '',
'subscriber' => ''
)
);
try {
$table = $this->mongo_db->selectCollection('billing_customers');
$cursor = $table->find($mongo_where)->sort(array('subscriber'=>-1, 'domain'=>-1, 'gateway'=>-1))->limit(1)->slaveOkay();
$result = $cursor->getNext();
} catch (Exception $e) {
$log = sprintf("<p>Caught exception in lookupProfiles(): %s", $e->getMessage());
syslog(LOG_NOTICE, $log);
return false;
}
if(!$result) {
$log=sprintf("Error: no customer found in mongo billing_customers table for billing party=%s, domain=%s, gateway=%s",$this->BillingPartyId,$this->domain,$this->gateway);
syslog(LOG_NOTICE, $log);
//return false;
}
if($result) {
if ($result['subscriber']) {
$this->CustomerProfile = sprintf("subscriber=%s",$result['subscriber']);
} else if ($result['domain']) {
$this->CustomerProfile = sprintf("domain=%s",$result['domain']);
} else if ($result['gateway']) {
$this->CustomerProfile = sprintf("gateway=%s",$result['gateway']);
} else {
$this->CustomerProfile = "default";
}
if (!$result['profile_name1']) {
$log=sprintf("Error: customer %s (id=%d) has no weekday profile assigned in profiles table",$this->CustomerProfile,$result['id']);
syslog(LOG_NOTICE, $log);
return false;
}
if (!$result['profile_name2']) {
$log=sprintf("Error: customer %s (id=%d) has no weekend profile assigned in profiles table",$this->CustomerProfile,$result['id']);
syslog(LOG_NOTICE, $log);
return false;
}
if (!$result['timezone']) {
$log = sprintf ("Error: missing timezone for customer %s",$this->CustomerProfile);
syslog(LOG_NOTICE, $log);
return false;
}
$this->billingTimezone = $result['timezone'];
$this->allProfiles = array (
"profile_workday" => $result['profile_name1'],
"profile_weekend" => $result['profile_name2'],
"profile_workday_alt" => $result['profile_name1_alt'],
"profile_weekend_alt" => $result['profile_name2_alt'],
"timezone" => $result['timezone']
);
if ($result['increment']) {
$this->increment = $result['increment'];
}
if ($result['min_duration']) {
$this->min_duration = $result['min_duration'];
}
return true;
}
}
// mysql backend
$query=sprintf("select * from billing_customers
where subscriber = '%s'
or domain = '%s'
or gateway = '%s'
or (subscriber = '' and domain = '' and gateway = '')
order by subscriber desc, domain desc, gateway desc limit 1 ",
addslashes($this->BillingPartyId),
addslashes($this->domain),
addslashes($this->gateway)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->num_rows()) {
$this->db->next_record();
if ($this->db->Record['subscriber']) {
$this->CustomerProfile = sprintf("subscriber=%s",$this->db->Record['subscriber']);
} else if ($this->db->Record['domain']) {
$this->CustomerProfile = sprintf("domain=%s",$this->db->Record['domain']);
} else if ($this->db->Record['gateway']) {
$this->CustomerProfile = sprintf("gateway=%s",$this->db->Record['gateway']);
} else {
$this->CustomerProfile = "default";
}
if (!$this->db->Record['profile_name1']) {
$log=sprintf("Error: customer %s (id=%d) has no weekday profile assigned in profiles table",$this->CustomerProfile,$this->db->Record['id']);
syslog(LOG_NOTICE, $log);
return false;
}
if (!$this->db->Record['profile_name2']) {
$log=sprintf("Error: customer %s (id=%d) has no weekend profile assigned in profiles table",$this->CustomerProfile,$this->db->Record['id']);
syslog(LOG_NOTICE, $log);
return false;
}
if (!$this->db->Record['timezone']) {
$log = sprintf ("Error: missing timezone for customer %s",$this->CustomerProfile);
syslog(LOG_NOTICE, $log);
return false;
}
$this->billingTimezone = $this->db->Record['timezone'];
$this->allProfiles = array (
"profile_workday" => $this->db->Record['profile_name1'],
"profile_weekend" => $this->db->Record['profile_name2'],
"profile_workday_alt" => $this->db->Record['profile_name1_alt'],
"profile_weekend_alt" => $this->db->Record['profile_name2_alt'],
"timezone" => $this->db->Record['timezone']
);
if ($this->db->Record['increment']) {
$this->increment = $this->db->Record['increment'];
}
if ($this->db->Record['min_duration']) {
$this->min_duration = $this->db->Record['min_duration'];
}
return true;
} else {
$log=sprintf("Error: no customer found in billing_customers table for billing party=%s, domain=%s, gateway=%s",$this->BillingPartyId,$this->domain,$this->gateway);
syslog(LOG_NOTICE, $log);
return false;
}
}
function lookupRateAudio($dayofyear,$dayofweek,$hourofday,$durationRatedAlready) {
/*
// Required information from CDR structure
$this->BillingPartyId # calling subscriber
$this->domain # multiple callers may belong to same domain
$this->gateway # multiple callers may belong to the same gateway
$this->cNumber # E164 destination prefixed with 00 (e.g. 0041 CH)
$this->DestinationId # longest matched DestinationId
$this->region # region the destination belongs to
// pertinent to the curent rating SPAN (a span = same profile like evening hours)
$hourofday # which hour of teh day started for peak/ofpeak rates
$dayofweek # which day of the week for matching profiles
$dayofyear # which day of the year for matching holidays
$durationRatedAlready= the full duration for which a profile is defined (e.g. 0800-1800)
// the call is called recursively until the $durationRatedAlready = $CDR->duration
// when a call spans multiple profiles. If we span multiple profiles we must call
// the function again to lookup the corect rates
Rating logic
------------
1. using the profile_name found, lookup the rate_name based
on $hourofday in billing_profiles
- the day may be split in maximum 4 periods
- each day starts with hour 0 and ends with hour 24
- rate_name1 defines the first interval after hour 0
- rate_name2 defines the first interval after rate_name1
- rate_name3 defines the first interval after rate_name2
- rate_name4 defines the first interval after rate_name3
When the hour matches an interval use the rate_nameX found
to lookup the rate in billing_rates
- if no record is found use the rate called 'default'
2. lookup in billing_rates the record having same name found above
and billing_rates.destination = $this->DestinationId
- return an array with all the values to
$this->calculateAudio() function that called us
*/
// get work-day or weekend profile
if ($this->RatingTables->holidays[$dayofyear]) {
$this->profileName = $this->allProfiles['profile_weekend'];
$this->profileNameAlt = $this->allProfiles['profile_weekend_alt'];
$this->PeriodOfProfile = "weekend";
} else {
if ($dayofweek >=1 && $dayofweek <=5 ) {
$this->profileName = $this->allProfiles['profile_workday'];
$this->profileNameAlt = $this->allProfiles['profile_workday_alt'];
$this->PeriodOfProfile = "weekday";
} else {
$this->profileName = $this->allProfiles['profile_weekend'];
$this->profileNameAlt = $this->allProfiles['profile_weekend_alt'];
$this->PeriodOfProfile = "weekend";
}
}
// get rate for the time of the day
$timestampNextProfile = $this->timestampBilling + $durationRatedAlready;
$profileValues = $this->RatingTables->profiles[$this->profileName];
if (is_array($profileValues)) {
$this->profileNameLog = $this->profileName;
if ($hourofday < $profileValues['hour1'] ) {
$this->rateName = $profileValues['rate_name1'];
$this->timeInterval = "0-".$profileValues['hour1'];
$foundProfile = $profileValues['hour1'];
$this->nextProfile = $profileValues['hour1'];
} else if ($hourofday < $profileValues['hour2']) {
$this->rateName = $profileValues['rate_name2'];
$this->timeInterval = $profileValues['hour1']."-".$profileValues['hour2'];
$foundProfile = $profileValues['hour2'];
$this->nextProfile = $profileValues['hour2'];
} else if ($hourofday < $profileValues['hour3']) {
$this->rateName = $profileValues['rate_name3'];
$this->timeInterval = $profileValues['hour2']."-".$profileValues['hour3'];
$foundProfile = $profileValues['hour3'];
$this->nextProfile = $profileValues['hour3'];
} else if ($hourofday < $profileValues['hour4']) {
$this->rateName = $profileValues['rate_name4'];
$this->timeInterval = $profileValues['hour3']."-".$profileValues['hour4'];
$foundProfile = $profileValues['hour4'];
$this->nextProfile = 0;
}
if ($this->rateName) {
$found_history=false;
//get historical rating if exists
if (is_array($this->RatingTables->ratesHistory[$this->rateName][$this->DestinationId][$this->application])) {
$h=0;
foreach (($this->RatingTables->ratesHistory[$this->rateName][$this->DestinationId][$this->application]) as $_idx) {
$h++;
if ($_idx['startDate'] <= $this->timestamp) {
if ($_idx['endDate'] > $this->timestamp) {
// found historical rate
$found_history=true;
$this->rateValues=$_idx;
break;
} else {
$_log=sprintf("Interval missmatch %s < %s",$_idx['endDate'],$this->timestamp);
continue;
}
} else {
$_log=sprintf("Interval missmatch %s > %s",$_idx['startDate'],$this->timestamp);
continue;
}
}
}
if (!$found_history) {
if ($this->region) {
$this->rateValues=$this->lookupRateValuesAudio($this->rateName,$this->region);
if (!$this->rateValues) {
// try the destination as last resort
$this->rateValues=$this->lookupRateValuesAudio($this->rateName,$this->DestinationId);
}
} else {
$this->rateValues=$this->lookupRateValuesAudio($this->rateName,$this->DestinationId);
}
}
}
}
$profileValuesAlt = $this->RatingTables->profiles[$this->profileNameAlt];
if (!$this->rateValues && is_array($profileValuesAlt)) {
$this->profileNameLog = $this->profileNameAlt;
if ($hourofday < $profileValuesAlt['hour1'] ) {
$this->rateName = $profileValuesAlt['rate_name1'];
$this->timeInterval = "0-".$profileValuesAlt['hour1'];
$foundProfile = $profileValuesAlt['hour1'];
$this->nextProfile = $profileValuesAlt['hour1'];
} else if ($hourofday < $profileValuesAlt['hour2']) {
$this->rateName = $profileValuesAlt['rate_name2'];
$this->timeInterval = $profileValuesAlt['hour1']."-".$profileValuesAlt['hour2'];
$foundProfile = $profileValuesAlt['hour2'];
$this->nextProfile = $profileValuesAlt['hour2'];
} else if ($hourofday < $profileValuesAlt['hour3']) {
$this->rateName = $profileValuesAlt['rate_name3'];
$this->timeInterval = $profileValuesAlt['hour2']."-".$profileValuesAlt['hour3'];
$foundProfile = $profileValuesAlt['hour3'];
$this->nextProfile = $profileValuesAlt['hour3'];
} else if ($hourofday < $profileValuesAlt['hour4']) {
$this->rateName = $profileValuesAlt['rate_name4'];
$this->timeInterval = $profileValuesAlt['hour3']."-".$profileValuesAlt['hour4'];
$foundProfile = $profileValuesAlt['hour4'];
$this->nextProfile = 0;
}
if ($this->rateName) {
$found_history=false;
//get historical rating if exists
if (is_array($this->RatingTables->ratesHistory[$this->rateName][$this->DestinationId][$this->application])) {
$h=0;
foreach (($this->RatingTables->ratesHistory[$this->rateName][$this->DestinationId][$this->application]) as $_idx) {
$h++;
if ($_idx['startDate'] <= $this->timestamp) {
if ($_idx['endDate'] > $this->timestamp) {
// found historical rate
$found_history=true;
$this->rateValues=$_idx;
break;
} else {
$_log=sprintf("Interval missmatch %s < %s",$_idx['endDate'],$this->timestamp);
continue;
}
} else {
$_log=sprintf("Interval missmatch %s > %s",$_idx['startDate'],$this->timestamp);
continue;
}
}
}
if (!$found_history) {
if ($this->region) {
$this->rateValues=$this->lookupRateValuesAudio($this->rateName,$this->region);
// try destination as last resort
if (!$this->rateValues) {
$this->rateValues=$this->lookupRateValuesAudio($this->rateName,$this->DestinationId);
}
} else {
$this->rateValues=$this->lookupRateValuesAudio($this->rateName,$this->DestinationId);
}
}
}
}
if (!$this->rateValues) {
$this->rateNotFound=true;
$log=sprintf("Error: Cannot find rates for callid=%s, billing party=%s, customer %s, gateway=%s, destination=%s, profile=%s, app=%s",
$this->callId,$this->BillingPartyId,$this->CustomerProfile,$this->gateway,$this->DestinationId,$this->profileName,$this->application);
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->nextProfile == "24") $this->nextProfile = 0;
$DST = Date("I",$timestampNextProfile);
if (!$this->nextProfile) {
// check it we change daylight saving time tomorrow
// yes this cann happen and we must apply a different rate
$timestampNextProfile =$timestampNextProfile+24*3600;
$DSTNext = Date("I",$timestampNextProfile);
if ($DST != $DSTNext) {
if ($DSTNext==0) {
$timestampNextProfile=$timestampNextProfile+3600;
} else if ($DSTNext==1) {
$timestampNextProfile=$timestampNextProfile-3600;
}
}
}
// see if we have minimum duration or increment
if ($this->rateValues['increment']) {
// increase the billed duration to the next increment
$this->duration = $this->rateValues['increment'] * ceil($this->duration / $this->rateValues['increment']);
}
$durationToRate=$this->duration-$durationRatedAlready;
$month = Date("m",$timestampNextProfile);
$day = Date("d",$timestampNextProfile);
$year = Date("Y",$timestampNextProfile);
$nextProfileTimestamp=mktime($this->nextProfile, 0, 0, $month,$day,$year);
$npdt=Date("Y-m-d H:i", $nextProfileTimestamp);
$timeTillNextProfile=$nextProfileTimestamp-$this->timestampBilling;
if ($durationToRate > $timeTillNextProfile) {
$diff=$durationToRate-$timeTillNextProfile;
$this->durationRated=$timeTillNextProfile;
} else {
$this->durationRated=$durationToRate;
}
$rate=array(
"customer" => $this->CustomerProfile,
"application" => $this->application,
"profile" => $this->profileNameLog,
"day" => $this->PeriodOfProfile,
"destinationId" => $this->DestinationId,
"duration" => $this->durationRated,
"rate" => $this->rateName,
"values" => $this->rateValues,
"interval" => $this->timeInterval,
"nextHourOfDay" => $this->nextProfile
);
return $rate;
}
function lookupRateMessage($dayofyear,$dayofweek,$hourofday) {
/*
// Required information from CDR structure
$this->BillingPartyId # calling subscriber
$this->domain # multiple callers may belong to same domain
$this->gateway # multiple callers may belong to the same gateway
$this->cNumber # E164 destination prefixed with 00 (e.g. 0041 CH)
$this->DestinationId # longest matched DestinationId
$this->region # region the destination belongs to
// pertinent to the curent rating SPAN (a span = same profile like evening hours)
$hourofday # which hour of teh day started for peak/ofpeak rates
$dayofweek # which day of the week for matching profiles
$dayofyear # which day of the year for matching holidays
$durationRatedAlready= the full duration for which a profile is defined (e.g. 0800-1800)
// the call is called recursively until the $durationRatedAlready = $CDR->duration
// when a call spans multiple profiles. If we span multiple profiles we must call
// the function again to lookup the corect rates
Rating logic
------------
1. using the profile_name found, lookup the rate_name based
on $hourofday in billing_profiles
- the day may be split in maximum 4 periods
- each day starts with hour 0 and ends with hour 24
- rate_name1 defines the first interval after hour 0
- rate_name2 defines the first interval after rate_name1
- rate_name3 defines the first interval after rate_name2
- rate_name4 defines the first interval after rate_name3
When the hour matches an interval use the rate_nameX found
to lookup the rate in billing_rates
- if no record is found use the rate called 'default'
2. lookup in billing_rates the record having same name found above
and billing_rates.destination = $this->DestinationId
- return an array with all the values to
$this->calculateAudio() function that called us
*/
// get work-day or weekend profile
if ($this->RatingTables->holidays[$dayofyear]) {
$this->profileName = $this->allProfiles['profile_weekend'];
$this->profileNameAlt = $this->allProfiles['profile_weekend_alt'];
$this->PeriodOfProfile = "weekend";
} else {
if ($dayofweek >=1 && $dayofweek <=5 ) {
$this->profileName = $this->allProfiles['profile_workday'];
$this->profileNameAlt = $this->allProfiles['profile_workday_alt'];
$this->PeriodOfProfile = "weekday";
} else {
$this->profileName = $this->allProfiles['profile_weekend'];
$this->profileNameAlt = $this->allProfiles['profile_weekend_alt'];
$this->PeriodOfProfile = "weekend";
}
}
// get rate for the time of the day
$timestampNextProfile = $this->timestampBilling + $durationRatedAlready;
$profileValues = $this->RatingTables->profiles[$this->profileName];
if (is_array($profileValues)) {
$this->profileNameLog = $this->profileName;
if ($hourofday < $profileValues['hour1'] ) {
$this->rateName = $profileValues['rate_name1'];
$this->timeInterval = "0-".$profileValues['hour1'];
$foundProfile = $profileValues['hour1'];
} else if ($hourofday < $profileValues['hour2']) {
$this->rateName = $profileValues['rate_name2'];
$this->timeInterval = $profileValues['hour1']."-".$profileValues['hour2'];
$foundProfile = $profileValues['hour2'];
} else if ($hourofday < $profileValues['hour3']) {
$this->rateName = $profileValues['rate_name3'];
$this->timeInterval = $profileValues['hour2']."-".$profileValues['hour3'];
$foundProfile = $profileValues['hour3'];
} else if ($hourofday < $profileValues['hour4']) {
$this->rateName = $profileValues['rate_name4'];
$this->timeInterval = $profileValues['hour3']."-".$profileValues['hour4'];
$foundProfile = $profileValues['hour4'];
}
if ($this->rateName) {
if ($this->region) {
$this->rateValues=$this->lookupRateValuesMessage($this->rateName,$this->region);
if (!$this->rateValues) {
// try the destination as last resort
$this->rateValues=$this->lookupRateValuesMessage($this->rateName,$this->DestinationId);
}
} else {
$this->rateValues=$this->lookupRateValuesMessage($this->rateName,$this->DestinationId);
}
}
}
$profileValuesAlt = $this->RatingTables->profiles[$this->profileNameAlt];
if (!$this->rateValues && is_array($profileValuesAlt)) {
$this->profileNameLog = $this->profileNameAlt;
if ($hourofday < $profileValuesAlt['hour1'] ) {
$this->rateName = $profileValuesAlt['rate_name1'];
$this->timeInterval = "0-".$profileValuesAlt['hour1'];
$foundProfile = $profileValuesAlt['hour1'];
} else if ($hourofday < $profileValuesAlt['hour2']) {
$this->rateName = $profileValuesAlt['rate_name2'];
$this->timeInterval = $profileValuesAlt['hour1']."-".$profileValuesAlt['hour2'];
$foundProfile = $profileValuesAlt['hour2'];
} else if ($hourofday < $profileValuesAlt['hour3']) {
$this->rateName = $profileValuesAlt['rate_name3'];
$this->timeInterval = $profileValuesAlt['hour2']."-".$profileValuesAlt['hour3'];
$foundProfile = $profileValuesAlt['hour3'];
} else if ($hourofday < $profileValuesAlt['hour4']) {
$this->rateName = $profileValuesAlt['rate_name4'];
$this->timeInterval = $profileValuesAlt['hour3']."-".$profileValuesAlt['hour4'];
$foundProfile = $profileValuesAlt['hour4'];
}
if ($this->rateName) {
if ($this->region) {
$this->rateValues=$this->lookupRateValuesMessage($this->rateName,$this->region);
// try destination as last resort
if (!$this->rateValues) {
$this->rateValues=$this->lookupRateValuesMessage($this->rateName,$this->DestinationId);
}
} else {
$this->rateValues=$this->lookupRateValuesMessage($this->rateName,$this->DestinationId);
}
}
}
if (!$this->rateValues) {
$this->rateNotFound=true;
$log=sprintf("Error: Cannot find rates for callid=%s, billing party=%s, customer %s, gateway=%s, destination=%s, profile=%s, app=sms",
$this->callId,$this->BillingPartyId,$this->CustomerProfile,$this->gateway,$this->DestinationId,$this->profileName);
syslog(LOG_NOTICE, $log);
return false;
}
$rate=array(
"customer" => $this->CustomerProfile,
"application" => $this->application,
"profile" => $this->profileNameLog,
"day" => $this->PeriodOfProfile,
"destinationId" => $this->DestinationId,
"rate" => $this->rateName,
"values" => $this->rateValues,
);
return $rate;
}
function MaxSessionTime($dictionary) {
// Used for prepaid application to return maximum session time based on a prepaid balance
$this->rateValuesCache=array();
$this->MaxSessionTimeSpans=0;
$durationRate = 0;
/////////////////////////////////////////////////////
// required fields passed from the CDR structure
//
$this->timestamp = time();
$this->callId = $dictionary['callId'];
$this->DestinationId = $dictionary['DestinationId'];
$this->BillingPartyId = $dictionary['BillingPartyId'];
$this->domain = $dictionary['domain'];
$this->duration = $dictionary['duration'];
$this->aNumber = $dictionary['aNumber'];
$this->cNumber = $dictionary['cNumber'];
$this->gateway = $dictionary['gateway'];
$this->RatingTables = $dictionary['RatingTables'];
$this->application = $dictionary['application'];
$this->ResellerId = $dictionary['ResellerId'];
$Balance = $dictionary['Balance'];
if (!$this->application) $this->application='audio';
if (!$this->DestinationId) {
$log=sprintf("Error: no DestinationId supplied in MaxSessionTime()");
syslog(LOG_NOTICE, $log);
return false;
}
if (!$this->lookupDestinationDetails()) {
return false;
}
if (!$this->lookupProfiles()) {
return false;
}
$this->startTimeBilling = getLocalTime($this->billingTimezone,$this->timestamp);
list($dateText,$timeText) = explode(" ",trim($this->startTimeBilling));
$Bdate = explode("-",$dateText);
$Btime = explode(":",$timeText);
$this->timestampBilling = mktime($Btime[0], $Btime[1], $Btime[2], $Bdate[1], $Bdate[2], $Bdate[0]);
$this->startTimeBilling = Date("Y-m-d H:i:s",$this->timestampBilling);
$i=0;
$durationRatedTotal=0;
while ($Balance > 0 ) {
$span++;
$this->MaxSessionTimeSpans++;
if ($i == "0") {
$dayofweek = date("w",$this->timestampBilling);
$hourofday = date("G",$this->timestampBilling);
$dayofyear = date("Y-m-d",$this->timestampBilling);
} else {
$dayofweek = date("w",$this->timestampBilling+$durationRatedTotal);
$hourofday = $foundRate['nextHourOfDay'];
$dayofyear = date("Y-m-d",$this->timestampBilling+$durationRatedTotal);
}
$foundRate = $this->lookupRateAudio($dayofyear,$dayofweek,$hourofday,$durationRatedTotal);
if ($this->rateNotFound) {
// break here to avoid loops
break;
}
$thisRate=$foundRate;
if ($j > 0) {
$payConnect=0;
$durationForRating = $thisRate['duration'];
} else {
$payConnect=1;
if ($this->min_duration && $this->duration < $this->min_duration) {
$durationForRating=$this->min_duration;
} else {
$durationForRating=$thisRate['duration'];
}
}
$j++;
$connectCost = $thisRate['values']['connectCost'];
$durationRate = $thisRate['values']['durationRate'];
if ($span=="1" && !$dictionary['skipConnectCost']) {
$this->connectCost=number_format($connectCost/$this->priceDenominator,$this->priceDecimalDigits);
$connectCostSpan=$connectCost;
$setupBalanceRequired=$connectCost/$this->priceDenominator;
if ($connectCost && $Balance <= $setupBalanceRequired) {
syslog(LOG_NOTICE,"Balance too small: $Balance <= $setupBalanceRequired");
return false;
}
$Balance = $Balance-$setupBalanceRequired;
} else {
$connectCostSpan=0;
$setupBalanceRequired=0;
}
$connectCostPrint = number_format($connectCostSpan/$this->priceDenominator,$this->priceDecimalDigits);
$durationRatePrint = number_format($durationRate/$this->priceDenominator,$this->priceDecimalDigits);
$spanPrice = $this->price+$setupBalanceRequired*$payConnect+
$durationRate*$durationForRating/$this->durationPeriodRated/$this->priceDenominator;
if ($Balance > $spanPrice) {
$Balance = $Balance-$spanPrice;
$durationRatedTotal = $durationRatedTotal+ $foundRate['duration'];
} else {
$durationAllowedinThisSpan = $Balance /
$durationRate * $this->durationPeriodRated * $this->priceDenominator;
$rateOfThisSpan=$durationRate/$this->priceDenominator;
$durationRatedTotal=$durationRatedTotal + $durationAllowedinThisSpan;
$Balance=$Balance-$spanPrice;
return $durationRatedTotal;
}
if ($durationRatedTotal >= $this->duration) {
return sprintf("%f",$durationRatedTotal);
}
$i++;
if ($i>10) {
return sprintf("%f",$durationRatedTotal);
break;
}
}
return false;
}
function lookupRateValuesAudio($rateName,$DestinationId) {
if (is_array($this->rateValuesCache[$rateName][$DestinationId][$this->application])) {
return $this->rateValuesCache[$rateName][$DestinationId][$this->application];
}
if ($this->mongo_db != NULL) {
// mongo backend
$mongo_where['destination'] = $DestinationId;
$mongo_where['application'] = $this->application;
$mongo_where['$or'] = array(array('reseller_id' => intval($this->ResellerId)),
array('reseller_id' => 0)
);
try {
$table = $this->mongo_db->selectCollection('billing_rates');
$cursor = $table->find($mongo_where)->sort(array('reseller_id'=>-1))->limit(1)->slaveOkay();
$result = $cursor->getNext();
} catch (Exception $e) {
$log = sprintf("<p>Caught exception in lookupRateValuesAudio(): %s", $e->getMessage());
syslog(LOG_NOTICE, $log);
return false;
}
if(!$result) {
$log=sprintf ("Error: cannot find mongo rate values for dest id %s",$DestinationId);
syslog(LOG_NOTICE, $log);
//return false;
}
if($result){
$values=array(
"connectCost" => $result['connectCost'],
"durationRate" => $result['durationRate'],
"connectCostIn" => $result['connectCostIn'],
"durationRateIn" => $result['durationRateIn']
);
// cache values
$this->rateValuesCache[$rateName][$DestinationId][$this->application]=$values;
return $values;
}
}
if ($this->settings['split_rating_table']) {
if ($rateName) {
$table="billing_rates_".$rateName;
} else {
$table="billing_rates_default";
}
$query=sprintf("select * from %s where destination = '%s' and application = '%s'",
$table,
addslashes($DestinationId),
addslashes($this->application)
);
} else {
$table="billing_rates";
$query=sprintf("select * from %s where name = '%s' and destination = '%s' and application = '%s'",
$table,
addslashes($rateName),
addslashes($DestinationId),
addslashes($this->application)
);
}
// mysql backend
if (!$this->db->query($query)) {
if ($this->db->Errno != 1146) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
return false;
}
// try the main table
$query=sprintf("select * from billing_rates where name = '%s' and destination = '%s' and application = '%s'",
addslashes($rateName),
addslashes($DestinationId),
addslashes($this->application)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
return false;
}
}
if ($this->db->num_rows()) {
$this->db->next_record();
$values=array(
"connectCost" => $this->db->Record['connectCost'],
"durationRate" => $this->db->Record['durationRate'],
"connectCostIn" => $this->db->Record['connectCostIn'],
"durationRateIn" => $this->db->Record['durationRateIn']
);
// cache values
$this->rateValuesCache[$rateName][$DestinationId][$this->application]=$values;
return $values;
} else {
return false;
}
}
function lookupRateValuesMessage($rateName,$DestinationId) {
if (is_array($this->rateValuesCache[$rateName][$DestinationId]['sms'])) {
return $this->rateValuesCache[$rateName][$DestinationId]['sms'];
}
if ($this->mongo_db != NULL) {
// mongo backend
$mongo_where['application'] = 'sms';
$mongo_where['$or'] = array(array('reseller_id' => intval($this->ResellerId)),
array('reseller_id' => 0)
);
$mongo_where['$or'] = array(array('destination' => $DestinationId),
array('destination' => '')
);
try {
$table = $this->mongo_db->selectCollection('billing_rates');
$cursor = $table->find($mongo_where)->sort(array('destination'=>-1))->limit(1)->slaveOkay();
$result = $cursor->getNext();
} catch (Exception $e) {
$log = sprintf("<p>Caught exception in lookupRateValuesMessage(): %s", $e->getMessage());
syslog(LOG_NOTICE, $log);
return false;
}
if(!$result) {
$log=sprintf ("Error: cannot find mongo rate sms values for dest id %s",$DestinationId);
syslog(LOG_NOTICE, $log);
//return false;
}
if($result){
$values=array(
"connectCost" => $result['connectCost']
);
// cache values
$this->rateValuesCache[$rateName][$DestinationId]['sms']=$values;
return $values;
}
}
if ($this->settings['split_rating_table']) {
if ($rateName) {
$table="billing_rates_".$rateName;
} else {
$table="billing_rates_default";
}
$query=sprintf("select * from %s where (destination = '%s' or destination = '') and application = 'sms' order by destination desc limit 1",
$table,
addslashes($DestinationId)
);
} else {
$table="billing_rates";
$query=sprintf("select * from %s where name = '%s' and (destination = '%s' or destination = '') and application = 'sms' order by destination desc limit 1",
$table,
addslashes($rateName),
addslashes($DestinationId)
);
}
// mysql backend
if (!$this->db->query($query)) {
if ($this->db->Errno != 1146) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
return false;
}
// try the main table
// lookup rate from MySQL
$query=sprintf("select * from billing_rates where name = '%s' and (destination = '%s' or destination = '') and application = 'sms' order by destination desc limit 1",
addslashes($rateName),
addslashes($DestinationId)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
return false;
}
}
if ($this->db->num_rows()) {
$this->db->next_record();
$values=array(
"connectCost" => $this->db->Record['connectCost']
);
// cache values
$this->rateValuesCache[$rateName][$DestinationId]['sms']=$values;
return $values;
} else {
return false;
}
}
}
class RatingTables {
var $database_backend = 'mysql'; // mongo or mysql
var $csv_export=array(
"destinations" => "destinations.csv",
"billing_customers" => "customers.csv",
"billing_profiles" => "profiles.csv",
"billing_rates" => "rates.csv",
"billing_rates_history" => "ratesHistory.csv",
"billing_discounts" => "discounts.csv",
"billing_enum_tlds" => "enumtld.csv",
"prepaid" => "prepaid.csv",
"quota_usage" => "quotausage.csv"
);
var $csv_import=array(
"destinations" => "destinations.csv",
"billing_customers" => "customers.csv",
"billing_profiles" => "profiles.csv",
"billing_rates" => "rates.csv",
"billing_rates_history" => "ratesHistory.csv",
"billing_discounts" => "discounts.csv"
);
var $previously_imported_files=0;
var $maxrowsperpage=15;
var $insertDomainOption=array();
var $delimiter=",";
var $filesToImport=array();
var $importFilesPatterns=array('ratesHistory',
'rates',
'profiles',
'destinations',
'discounts',
'customers'
);
var $mustReload = false;
var $web_elements=array('table',
'export',
'web_task',
'subweb_task',
'confirmDelete',
'confirmCopy',
'next',
'id',
'search_text',
'ReloadRatingTables',
'account',
'balance',
'fromRate',
'toRate',
'sessionId'
);
var $requireReload = array('destinations');
var $whereResellerFilter = " (1=1) ";
var $cvs_import_dir = "/var/spool/cdrtool";
var $tables=array(
"destinations"=>array("name"=>"Destinations",
"skip_math"=> true,
"keys"=>array("id"),
"exceptions" =>array(),
"order"=>"dest_id ASC",
"domainFilterColumn"=>"domain",
"fields"=>array(
"gateway"=>array("size"=>15,
"checkType"=>'ip',
"name"=>"Trusted peer"
),
"reseller_id"=>array("size"=>8,
"checkType"=>'numeric',
"name"=>"Reseller"
),
"domain"=>array("size"=>15,
"name"=>"Domain",
"checkType"=>'domain',
"class"=>"span2"
),
"subscriber"=>array("size"=>15,
"checkType"=>'sip_account',
"name"=>"Subscriber",
"class"=>"span2"
),
"dest_id"=>array("size"=>12,
"name"=>"Destination",
),
"region"=>array("size"=>10,
"name"=>"Region"
),
"dest_name"=>array("size"=>20,
"name"=>"Description",
"class"=>"span2"
),
"increment" =>array("size"=>3,
"checkType"=>'numeric',
"name"=>"Incr"
),
"min_duration" =>array("size"=>3,
"checkType"=>'numeric',
"name"=>"Min Dur"
),
"max_duration" =>array("size"=>5,
"checkType"=>'numeric',
"name"=>"Max Dur"
),
"max_price" =>array("size"=>8,
"checkType"=>'numeric',
"name"=>"Max Price"
)
)
),
"billing_customers"=>array("name"=>"Customers",
"skip_math"=> true,
"keys"=>array("id"),
"domainFilterColumn"=>"domain",
"fields"=>array("gateway"=>array("size"=>15,
"checkType"=>'ip',
"name"=>"Trusted Peer"
),
"reseller_id"=>array("size"=>8,
"checkType"=>'numeric',
"name"=>"Reseller"
),
"domain"=>array("size"=>15,
"checkType"=>'domain',
"name"=>"Domain",
"class"=>"span2"
),
"subscriber"=>array("size"=>25,
"checkType"=>'sip_account',
"name"=>"Subscriber",
"class"=>"span2"
),
"profile_name1"=>array("size"=>10,
"name"=>"Profile WD"
),
"profile_name1_alt"=>array("size"=>8,
"name"=>"Fallback"
),
"profile_name2"=>array("size"=>10,
"name"=>"Profile WE"
),
"profile_name2_alt"=>array("size"=>8,
"name"=>"Fallback"
),
"timezone" =>array("size"=>16,
"name"=>"Timezone",
"class"=>"span2"
),
"increment" =>array("size"=>3,
"checkType"=>'numeric',
"name"=>"Incr"
),
"min_duration" =>array("size"=>3,
"checkType"=>'numeric',
"name"=>"Min Dur"
)
)
),
"billing_discounts"=>array("name"=>"Discounts",
"keys"=>array("id"),
"domainFilterColumn"=>"domain",
"fields"=>array("gateway"=>array("size"=>15,
"checkType"=>'ip',
"name"=>"Trusted Peer"
),
"reseller_id"=>array("size"=>8,
"checkType"=>'numeric',
"name"=>"Reseller"
),
"domain"=>array("size"=>15,
"checkType"=>'domain',
"name"=>"Domain",
"class"=>"span2"
),
"subscriber"=>array("size"=>25,
"checkType"=>'sip_account',
"name"=>"Subscriber",
"class"=>"span2"
),
"application"=>array("size"=>6,
"name"=>"App"
),
"destination"=>array("size"=>10,
"name"=>"Destination"
),
"region"=>array("size"=>8,
"name"=>"Region"
),
"connect"=>array("size"=>5,
"name"=>"Connect"
),
"duration"=>array("size"=>5,
"name"=>"Duration"
)
)
),
"billing_profiles"=>array("name"=>"Profiles",
"skip_math"=> true,
"keys"=>array("id"),
"exceptions" =>array(),
"size"=>6,
"fields"=>array(
"reseller_id"=>array("size"=>8,
"checkType"=>'numeric',
"name"=>"Reseller"
),
"name"=>array("size"=>12,
"name"=>"Profile",
"class"=>"span2"
),
"rate_name1"=>array("size"=>12,
"name"=>"Rate 1"
),
"hour1"=>array("size"=>3,
"checkType"=>'numeric',
"name"=>"00-H1"
),
"rate_name2"=>array("size"=>12,
"name"=>"Rate 2"
),
"hour2"=>array("size"=>3,
"checkType"=>'numeric',
"name"=>"H1-H2"
),
"rate_name3"=>array("size"=>12,
"name"=>"Rate 3"
),
"hour3"=>array("size"=>3,
"checkType"=>'numeric',
"name"=>"H2-H3"
),
"rate_name4"=>array("size"=>12,
"name"=>"Rate 4"
),
"hour4"=>array("size"=>3,
"checkType"=>'numeric',
"name"=>"H3-24"
),
)
),
"billing_rates"=>array("name"=>"Rates",
"keys"=>array("id"),
"size"=>10,
"exceptions"=>array('maxPrice'),
"order"=>"durationRate desc",
"fields"=>array(
"reseller_id"=>array("size"=>8,
"checkType"=>'numeric',
"name"=>"Reseller"
),
"name"=>array("size"=>12,
"name"=>"Rate",
"class"=>"span2"
),
"destination"=>array("size"=>12,
"name"=>"Destination"
),
"application"=>array("size"=>6,
"name"=>"App"
),
"connectCost"=>array("size"=>8,
"checkType"=>'numeric',
"name"=>"Connect"
),
"durationRate"=>array("size"=>8,
"checkType"=>'numeric',
"name"=>"Duration"
),
"connectCostIn"=>array("size"=>8,
"checkType"=>'numeric',
"name"=>"Conn In"
),
"durationRateIn"=>array("size"=>8,
"checkType"=>'numeric',
"name"=>"Duration In"
)
)
),
"billing_rates_history"=>array("name"=>"Rates history",
"keys"=>array("id"),
"size"=>10,
"order"=>"destination ASC, name ASC",
"fields"=>array(
"reseller_id"=>array("size"=>8,
"checkType"=>'numeric',
"name"=>"Reseller"
),
"name"=>array("size"=>10,
"name"=>"Rate",
"class"=>"span2"
),
"destination"=>array("size"=>12,
"name"=>"Destination"
),
"application"=>array("size"=>6,
"name"=>"App"
),
"connectCost"=>array("size"=>8,
"checkType"=>'numeric',
"name"=>"Conn"
),
"durationRate"=>array("size"=>8,
"checkType"=>'numeric',
"name"=>"Price"
),
"connectCostIn"=>array("size"=>8,
"checkType"=>'numeric',
"name"=>"Conn In"
),
"durationRateIn"=>array("size"=>8,
"checkType"=>'numeric',
"name"=>"Price In"
),
"startDate"=>array("size"=>11,
"name"=>"Start Date",
"class"=>"span2"
),
"endDate"=>array("size"=>11,
"name"=>"End Date",
"class"=>"span2"
)
)
),
"billing_enum_tlds"=>array("name"=>"ENUM discounts",
"skip_math"=> true,
"keys"=>array("id"),
"exceptions" =>array(),
"size"=>6,
"fields"=>array(
"reseller_id"=>array("size"=>8,
"checkType"=>'numeric',
"name"=>"Reseller"
),
"enum_tld"=>array("size"=>35,
"mustExist"=>true,
"checkType"=>'domain',
"name"=>"ENUM TLD",
"class"=>"span2"
),
"e164_regexp"=>array("size"=>35,
"mustExist"=>true,
"name"=>"E164 Regexp",
"class"=>"span2"
),
"discount"=>array("size"=>10,
"mustExist"=>true,
"checkType"=>'numeric',
"name"=>"Discount"
)
)
),
"prepaid"=>array("name"=>"Prepaid accounts",
"keys"=>array("id"),
"size"=>15,
"exceptions" =>array('change_date','active_sessions','domain'),
"order"=>"change_date DESC",
"fields"=>array("account"=>array("size"=>35,
"name"=>"Subscriber",
"checkType"=>'sip_account',
"mustExist"=>true,
"class"=>"span2"
),
"reseller_id"=>array("size"=>8,
"checkType"=>'numeric',
"name"=>"Reseller"
),
"balance"=>array("size"=>10,
"name"=>"Balance"
),
"change_date"=>array("size"=>19,
"name"=>"Last Change",
"readonly"=>1
),
"session_counter"=>array("size"=>3,
"name"=>"Active Sessions",
"readonly"=>1
),
"max_sessions"=>array("size"=>3,
"name"=>"Max Sessions"
)
)
),
"prepaid_cards"=>array("name"=>"Prepaid cards",
"keys"=>array("id"),
"size"=>15,
"exceptions" =>array('service'),
"fields"=>array("batch"=>array("size"=>40,
"name"=>"Batch name",
"readonly"=>1,
"class"=>"span3"
),
"reseller_id"=>array("size"=>8,
"checkType"=>'numeric',
"name"=>"Reseller"
),
"date_batch"=>array("size"=>11,
"name"=>"Batch Date",
"class"=>"span2"
),
"number"=>array("size"=>20,
"checkType"=>'numeric',
"mustExist"=>true,
"name"=>"Card Number",
"class"=>"span2"
),
"id"=>array("size"=>20,
"checkType"=>'numeric',
"mustExist"=>true,
"name"=>"Card Id",
),
"value"=>array("size"=>8,
"checkType"=>'numeric',
"mustExist"=>true,
"name"=>"Card Value"
),
"blocked"=>array("size"=>1,
"name"=>"Lock"
),
"date_active"=>array("size"=>18,
"name"=>"Activation Date",
"class"=>"span2"
)
)
),
"prepaid_history"=>array("name"=>"Prepaid history",
"order"=>"id DESC",
"skip_math"=> true,
"keys"=>array("id"),
"size"=>15,
"exceptions" =>array('session','destination'),
"fields"=>array("username"=>array( "size"=>15,
"readonly"=>1,
"class"=>"span2"
),
"domain"=>array("size"=>15,
"readonly"=>1,
"class"=>"span2"
),
"reseller_id"=>array("size"=>8,
"checkType"=>'numeric',
"name"=>"Reseller",
"readonly"=>1
),
"action"=>array("size"=>15,
"readonly"=>1,
"class"=>"span2"
),
"duration"=>array("size"=>5
),
"destination"=>array("size"=>15
),
"session"=>array("size"=>30,
"readonly"=>1
),
"description"=>array("size"=>30,
"class"=>"span3"
),
"value"=>array("size"=>10
),
"balance"=>array("size"=>10
),
"date"=>array("size"=>18,
"class"=>"span2"
))
),
"quota_usage"=>array("name"=>"Quota usage",
"keys"=>array("id"),
"size"=>15,
"readonly"=>1,
"exceptions" =>array("change_date","traffic","duration","calls"),
"domainFilterColumn"=>"domain",
"fields"=>array("datasource"=>array("size"=>15,
"readonly"=>1
),
"reseller_id"=>array("size"=>8,
"checkType"=>'numeric',
"name"=>"Reseller",
"readonly" => true
),
"account"=>array("size"=>30,
"readonly"=>1,
"name" => "Subscriber",
"class"=>"span2"
),
"domain"=>array("size"=>15,
"readonly"=>1,
"class"=>"span2"
),
"blocked"=>array("size"=>2,
"readonly"=>1
),
"notified"=>array("size"=>20,
"readonly"=>1
),
"quota"=>array("size"=>5,
"readonly"=>1
),
"cost"=>array("size"=>10,
"readonly"=>1,
"name"=>"This Month"
),
"cost_today"=>array("size"=>10,
"readonly"=>1,
"name"=>"Today"
),
"duration"=>array("size"=>10,
"readonly"=>1
),
"calls"=>array("size"=>10,
"readonly"=>1
),
"traffic"=>array("size"=>20,
"readonly"=>1
)
)
)
);
function RatingTables($readonly=false) {
global $CDRTool;
global $RatingEngine;
$this->mongo_db_ro = NULL;
$this->mongo_db_rw = NULL;
$this->settings = $RatingEngine;
$this->CDRTool = $CDRTool;
$this->table = $_REQUEST['table'];
if (!$this->table || !in_array($this->table,array_keys($this->tables))) $this->table="destinations";
$this->readonly=$readonly;
if ($this->settings['csv_delimiter']) {
$this->delimiter=$this->settings['csv_delimiter'];
}
if (!strlen($this->CDRTool['filter']['customer'])) {
$this->whereResellerFilter = sprintf ("reseller_id = %d",'99999999');
} else {
if ($this->CDRTool['filter']['customer'] && $this->tables[$this->table]['fields']['reseller_id']) {
$this->whereResellerFilter = sprintf ("reseller_id = %d",addslashes($this->CDRTool['filter']['customer']));
$this->tables[$this->table]['fields']['reseller_id']['readonly']=true;
}
}
if ($this->settings['split_rating_table']) {
$this->tables['billing_rates']['fields']['name']['readonly']=1;
}
if (strlen($this->settings['socketIP'])) {
if ($this->settings['socketIP'] == '0.0.0.0' || $this->settings['socketIP'] == '0') {
$this->settings['socketIPforClients']='127.0.0.1';
} else {
$this->settings['socketIPforClients']=$this->settings['socketIP'];
}
}
if ($this->settings['database_backend']) {
$this->database_backend = $this->settings['database_backend'];
}
$this->db = new DB_cdrtool;
$this->db1 = new DB_cdrtool;
$this->db->Halt_On_Error="no";
$this->db1->Halt_On_Error="no";
if ($this->database_backend == "mysql") {
# TODO
} else if ($this->database_backend == "mongo") {
$this->mongo_safe = 1;
if (is_array($this->settings['mongo_db'])) {
$mongo_uri = $this->settings['mongo_db']['uri'];
$mongo_replicaSet = $this->settings['mongo_db']['replicaSet'];
$mongo_database = $this->settings['mongo_db']['database'];
if ($this->settings['mongo_db']['safe']) {
$this->mongo_safe = $this->settings['mongo_db']['safe'];
}
try {
$mongo_connection_rw = new Mongo("mongodb://$mongo_uri?readPreference=primaryPreferred", array("replicaSet" => $mongo_replicaSet));
$mongo_connection_ro = new Mongo("mongodb://$mongo_uri?readPreference=secondaryPreferred", array("replicaSet" => $mongo_replicaSet));
$this->mongo_db_rw = $mongo_connection_rw->selectDB($mongo_database);
$this->mongo_db_ro = $mongo_connection_ro->selectDB($mongo_database);
} catch (Exception $e) {
$log = sprintf("Error: mongo exception in RatingTables(): %s", $e->getMessage());
syslog(LOG_NOTICE, $log);
}
$existing_rating_tables=array();
try {
$_tables=$this->mongo_db_ro->listCollections();;
foreach ($_tables as $_table) {
list($collection, $table) = explode(".",strval($_table));
$existing_rating_tables[]=$table;
}
} catch (Exception $e) {
$log = sprintf("<p>Caught exception in RatingTables(): %s", $e->getMessage());
syslog(LOG_NOTICE, $log);
}
foreach (array_keys($this->csv_export) as $table) {
if (!in_array($table, $existing_rating_tables)) {
try {
$this->mongo_db_rw->command(array("create" => $table));
$log=sprintf("Created mongo collection %s", $table);
syslog(LOG_NOTICE, $log);
} catch (Exception $e) {
$log=sprintf("Error creating mongo collection %s: %s", $table, $e->getMessage());
syslog(LOG_NOTICE, $log);
}
}
}
}
}
}
function ImportCSVFiles($dir=false) {
$results=0;
if (!$dir) $dir="/var/spool/cdrtool";
$this->scanFilesForImport($dir);
if ($this->previously_imported_files) {
printf("Skipping %d previously imported files\n",$this->previously_imported_files);
}
$results=0;
foreach (array_keys($this->filesToImport) as $file) {
$importFunction="Import".ucfirst($this->filesToImport[$file]['type']);
printf("Reading file %s\n",$this->filesToImport[$file]['path']);
$results = $this->$importFunction($this->filesToImport[$file]['path'],$this->filesToImport[$file]['reseller']);
$this->logImport($dir,$this->filesToImport[$file]['path'],$this->filesToImport[$file]['watermark'],$results,$this->filesToImport[$file]['reseller']);
}
return $results;
}
function ImportRates($file,$reseller=0) {
if (!$file || !is_readable($file) || !$fp = fopen($file, "r")) return false;
$i=0;
$inserted = 0;
$updated = 0;
$deleted = 0;
printf ("Importing rates from %s for reseller %s:\n",$file,$reseller);
while ($buffer = fgets($fp,1024)) {
$buffer=trim($buffer);
$p = explode($this->delimiter, $buffer);
$ops = trim($p[0]);
$name = trim($p[2]);
$destination = trim($p[3]);
$application = trim($p[4]);
$connectCost = trim($p[5]);
$durationRate = trim($p[6]);
$connectCostIn = trim($p[7]);
$durationRateIn = trim($p[8]);
if ($reseller) {
$reseller_id = intval($reseller);
} else {
$reseller_id = intval($p[1]);
}
if (!is_numeric($destination) && !strstr($destination,'@')) {
// skip invalid destinations
$skipped++;
continue;
}
if (strlen($connectCost) && !is_numeric($connectCost)) {
$skipped++;
continue;
}
if (strlen($durationRate) && !is_numeric($durationRate)) {
$skipped++;
continue;
}
if (!$application) $application='audio';
if ($ops=="1") {
$query=sprintf("insert into billing_rates
(
reseller_id,
name,
destination,
application,
connectCost,
durationRate,
connectCostIn,
durationRateIn
) values (
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s'
)",
addslashes($reseller_id),
addslashes($name),
addslashes($destination),
addslashes($application),
addslashes($connectCost),
addslashes($durationRate),
addslashes($connectCostIn),
addslashes($durationRateIn)
);
// mysql backend
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
}
if ($this->db->affected_rows()) {
if ($this->settings['split_rating_table']) {
if ($name) {
$_table='billing_rates_'.$name;
} else {
$_table='billing_rates_default';
}
if (!$this->createRatingTable($name)) {
$query=sprintf("insert into %s
(
id,
reseller_id,
name,
destination,
application,
connectCost,
durationRate,
connectCostIn,
durationRateIn
) values (
LAST_INSERT_ID(),
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s'
)",
addslashes($_table),
addslashes($reseller_id),
addslashes($name),
addslashes($destination),
addslashes($application),
addslashes($connectCost),
addslashes($durationRate),
addslashes($connectCostIn),
addslashes($durationRateIn)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
}
$inserted++;
} else {
$failed++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
$mongo_data=array('reseller_id' => intval(reseller_id),
'name' => $name,
'destination' => $destination,
'application' => $application,
'connectCost' => intval($connectCost),
'durationRate' => intval($durationRate),
'connectCostIn' => intval($connectCostIn),
'durationRateIn' => intval($durationRateIn)
);
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_rates');
$mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe));
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when inserting in billing_rates: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
}
} else if ($ops=="3") {
$query=sprintf("delete from billing_rates
where
reseller_id = '%s'
and name = '%s'
and destination = '%s'
and application = '%s'",
addslashes($reseller_id),
addslashes($name),
addslashes($destination),
addslashes($application)
);
// mysql backend
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows()) {
if ($this->settings['split_rating_table']) {
if ($name) {
$_table='billing_rates_'.$name;
} else {
$_table='billing_rates_default';
}
$query=sprintf("delete from %s
where reseller_id = '%s'
and name = '%s'
and destination = '%s'
and application = '%s'",
addslashes($_table),
addslashes($reseller_id),
addslashes($name),
addslashes($destination),
addslashes($application)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
}
}
$deleted++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_rates');
$mongo_match = array('reseller_id' => intval(reseller_id),
'name' => $name,
'destination' => $destination,
'application' => $application
);
$mongo_table_rw->remove($mongo_match,
array("safe" => $self->mongo_safe)
);
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when deleting from billing_rates: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
}
} else if ($ops=="2") {
$query=sprintf("select * from billing_rates
where name = '%s'
and destination = '%s'
and reseller_id = '%s'
and application = '%s'
",
addslashes($name),
addslashes($destination),
addslashes($reseller_id),
addslashes($application)
);
// mysql backend
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->num_rows()) {
$query=sprintf("update billing_rates set
connectCost = '%s',
durationRate = '%s',
connectCostIn = '%s',
durationRateIn = '%s'
where name = '%s'
and destination = '%s'
and reseller_id = '%s'
and application = '%s'
",
addslashes($connectCost),
addslashes($durationRate),
addslashes($connectCostIn),
addslashes($durationRateIn),
addslashes($name),
addslashes($destination),
addslashes($reseller_id),
addslashes($application)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows()) {
if ($this->settings['split_rating_table']) {
if ($name) {
$_table = 'billing_rates_'.$name;
} else {
$_table = 'billing_rates_default';
}
$query=sprintf("update %s set
connectCost = '%s',
durationRate = '%s',
connectCostIn = '%s',
durationRateIn = '%s'
where name = '%s'
and destination = '%s'
and reseller_id = '%s'
and application = '%s'
",
addslashes($_table),
addslashes($connectCost),
addslashes($durationRate),
addslashes($connectCostIn),
addslashes($durationRateIn),
addslashes($name),
addslashes($destination),
addslashes($reseller_id),
addslashes($application)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
}
}
$updated++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
$mongo_match = array('reseller_id' => intval(reseller_id),
'name' => $name,
'destination' => $destination,
'application' => $application
);
$mongo_data=array('reseller_id' => intval(reseller_id),
'name' => $name,
'destination' => $destination,
'application' => $application,
'connectCost' => intval($connectCost),
'durationRate' => intval($durationRate),
'connectCostIn' => intval($connectCostIn),
'durationRateIn' => intval($durationRateIn)
);
$mongo_options = array("upsert" => true,
"safe" => $self->mongo_safe
);
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_rates');
$result = $mongo_table_rw->update($mongo_match, $mongo_data, $mongo_options);
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when updating billing_rates: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
}
} else {
$query=sprintf("insert into billing_rates
(
reseller_id,
name,
destination,
application,
connectCost,
durationRate,
connectCostIn,
durationRateIn
) values (
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s'
)",
addslashes($reseller_id),
addslashes($name),
addslashes($destination),
addslashes($application),
addslashes($connectCost),
addslashes($durationRate),
addslashes($connectCostIn),
addslashes($durationRateIn)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows()) {
if ($this->settings['split_rating_table']) {
if ($name) {
$_table='billing_rates_'.$name;
} else {
$_table='billing_rates_default';
}
if (!$this->createRatingTable($name)) {
$query=sprintf("insert into %s
(
id,
reseller_id,
name,
destination,
application
connectCost,
durationRate,
connectCostIn,
durationRateIn
) values (
LAST_INSERT_ID(),
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s'
)",
addslashes($_table),
addslashes($reseller_id),
addslashes($name),
addslashes($destination),
addslashes($application),
addslashes($connectCost),
addslashes($durationRate),
addslashes($connectCostIn),
addslashes($durationRateIn)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
}
$inserted++;
} else {
$failed++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
$mongo_data=array('reseller_id' => intval(reseller_id),
'name' => $name,
'destination' => $destination,
'application' => $application,
'connectCost' => intval($connectCost),
'durationRate' => intval($durationRate),
'connectCostIn' => intval($connectCostIn),
'durationRateIn' => intval($durationRateIn)
);
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_rates');
$mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe));
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when inserting in billing_rates: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
}
}
}
}
} else {
$skipped++;
}
$this->showImportProgress($file);
$i++;
}
if ($i) print "Read $i records\n";
if ($skipped) print "Skipped $skipped records\n";
if ($inserted) print "Inserted $inserted records\n";
if ($updated) print "Updated $updated records\n";
if ($deleted) print "Delete $deleted records\n";
$results=$inserted+$updated+$deleted;
return $results;
}
function ImportRatesHistory($file,$reseller=0) {
if (!$file || !is_readable($file) || !$fp = fopen($file, "r")) return false;
$this->mustReload=true;
$i=0;
$inserted = 0;
$updated = 0;
$deleted = 0;
printf ("Importing rates history from %s for reseller %s:\n",$file,$reseller);
while ($buffer = fgets($fp,1024)) {
$buffer=trim($buffer);
$p = explode($this->delimiter, $buffer);
$ops = trim($p[0]);
$name = trim($p[2]);
$destination = trim($p[3]);
$application = trim($p[4]);
$connectCost = trim($p[5]);
$durationRate = trim($p[6]);
$connectCostIn = trim($p[7]);
$durationRateIn = trim($p[8]);
$startDate = trim($p[9]);
$endDate = trim($p[10]);
if ($reseller) {
$reseller_id = intval($reseller);
} else {
$reseller_id = intval($p[1]);
}
if (!is_numeric($destination) && !strstr($destination,'@')) {
// skip invalid destinations
$skipped++;
continue;
}
if (strlen($connectCost) && !is_numeric($connectCost)) {
$skipped++;
continue;
}
if (strlen($durationRate) && !is_numeric($durationRate)) {
$skipped++;
continue;
}
if (preg_match("/^\d{4}\-{\d{2}\-\d{2}$/",$startDate)) {
$skipped++;
continue;
}
if (preg_match("/^\d{4}\-{\d{2}\-\d{2}$/",$endDate)) {
$skipped++;
continue;
}
if ($ops=="1") {
$query=sprintf("insert into billing_rates_history
(
reseller_id,
name,
destination,
application,
connectCost,
durationRate,
connectCostIn,
durationRateIn,
startDate,
endDate
) values (
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s'
)",
addslashes($reseller_id),
addslashes($name),
addslashes($destination),
addslashes($application),
addslashes($connectCost),
addslashes($durationRate),
addslashes($connectCostIn),
addslashes($durationRateIn),
addslashes($startDate),
addslashes($endDate)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows() >0) {
$inserted++;
} else {
$failed++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
$mongo_data=array('reseller_id' => intval(reseller_id),
'name' => $name,
'destination' => $destination,
'application' => $application,
'connectCost' => intval($connectCost),
'durationRate' => intval($durationRate),
'connectCostIn' => intval($connectCostIn),
'durationRateIn' => intval($durationRateIn),
'startDate' => $startDate,
'endDate' => $endDate
);
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_rates_history');
$mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe));
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when inserting in billing_rates_history: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
}
}
}
} else if ($ops=="3") {
$query=sprintf("delete from billing_rates_history
where reseller_id = '%s'
and name = '%s'
and destination = '%s'
and startDate = '%s'
and endDate = '%s'",
addslashes($reseller_id),
addslashes($name),
addslashes($destination),
addslashes($startDate),
addslashes($endDate)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows() >0) {
$deleted++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_rates_history');
$mongo_match = array('reseller_id' => intval(reseller_id),
'name' => $name,
'destination' => $destination,
'application' => $application,
'startDate' => $startDate,
'endDate' => $endDate
);
$mongo_table_rw->remove($mongo_match,
array("safe" => $self->mongo_safe)
);
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when deleting from billing_rates_history: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
}
} else if ($ops=="2") {
$query=sprintf("select * from billing_rates_history
where name = '%s'
and destination = '%s'
and reseller_id = '%s'
and startDate = '%s'
and endDate = '%s'
",
addslashes($name),
addslashes($destination),
addslashes($reseller_id),
addslashes($startDate),
addslashes($endDate)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->num_rows()) {
$query=sprintf("update billing_rates_history set
application = '%s',
connectCost = '%s',
durationRate = '%s',
connectCostIn = '%s',
connectCostIn = '%s'
where name = '%s'
and destination = '%s'
and reseller_id = '%s'
and startDate = '%s'
and endDate = '%s'
",
addslashes($application),
addslashes($connectCost),
addslashes($durationRate),
addslashes($connectCostIn),
addslashes($durationRateIn),
addslashes($name),
addslashes($destination),
addslashes($reseller_id),
addslashes($startDate),
addslashes($endDate)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows() >0) {
$updated++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
$mongo_match = array('reseller_id' => intval(reseller_id),
'name' => $name,
'destination' => $destination,
'application' => $application,
'startDate' => $startDate,
'endDate' => $endDate
);
$mongo_data=array('reseller_id' => intval(reseller_id),
'name' => $name,
'destination' => $destination,
'application' => $application,
'connectCost' => intval($connectCost),
'durationRate' => intval($durationRate),
'connectCostIn' => intval($connectCostIn),
'durationRateIn' => intval($durationRateIn),
'startDate' => $startDate,
'endDate' => $endDate
);
$mongo_options = array("upsert" => true,
"safe" => $self->mongo_safe
);
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_rates_history');
$result = $mongo_table_rw->update($mongo_match, $mongo_data, $mongo_options);
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when updating billing_rates_history: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
}
} else {
$query=sprintf("insert into billing_rates_history
(
reseller_id,
name,
destination,
application,
connectCost,
durationRate,
connectCostIn,
durationRateIn,
startDate,
endDate
) values (
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s'
)",
addslashes($reseller_id),
addslashes($name),
addslashes($destination),
addslashes($application),
addslashes($connectCost),
addslashes($durationRate),
addslashes($connectCostIn),
addslashes($durationRateIn),
addslashes($startDate),
addslashes($endDate)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows() >0) {
$inserted++;
} else {
$failed++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
$mongo_data=array('reseller_id' => intval(reseller_id),
'name' => $name,
'destination' => $destination,
'application' => $application,
'connectCost' => intval($connectCost),
'durationRate' => intval($durationRate),
'connectCostIn' => intval($connectCostIn),
'durationRateIn' => intval($durationRateIn),
'startDate' => $startDate,
'endDate' => $endDate
);
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_rates_history');
$mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe));
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when inserting in billing_rates_history: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
}
}
}
}
} else {
$skipped++;
}
$j++;
if ($j=="10000") {
flush();
$j=0;
}
$this->showImportProgress($file);
$i++;
}
if ($i) print "Read $i records\n";
if ($skipped) print "Skipped $skipped records\n";
if ($inserted) print "Inserted $inserted records\n";
if ($updated) print "Updated $updated records\n";
if ($deleted) print "Delete $deleted records\n";
$results=$inserted+$updated+$deleted;
return $results;
}
function ImportCustomers($file,$reseller=0) {
if (!$file || !is_readable($file) || !$fp = fopen($file, "r")) return false;
$this->mustReload=true;
$i=0;
$inserted = 0;
$updated = 0;
$deleted = 0;
printf ("Importing customers from %s for reseller %s:\n",$file,$reseller);
while ($buffer = fgets($fp,1024)) {
$buffer=trim($buffer);
$p = explode($this->delimiter, $buffer);
$ops = trim($p[0]);
$gateway = trim($p[2]);
$domain = trim($p[3]);
$subscriber = trim($p[4]);
$profile_name1 = trim($p[5]);
$profile_name1_alt = trim($p[6]);
$profile_name2 = trim($p[7]);
$profile_name2_alt = trim($p[8]);
$timezone = trim($p[9]);
if ($reseller) {
$reseller_id = intval($reseller);
} else {
$reseller_id = intval($p[1]);
}
if (strlen($reseller_id) && !is_integer($reseller_id)) {
$skipped++;
continue;
}
if ($ops=="1") {
$query=sprintf("insert into billing_customers
(
reseller_id,
gateway,
domain,
subscriber,
profile_name1,
profile_name2,
timezone,
profile_name1_alt,
profile_name2_alt
) values (
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s'
)",
addslashes($reseller_id),
addslashes($gateway),
addslashes($domain),
addslashes($subscriber),
addslashes($profile_name1),
addslashes($profile_name2),
addslashes($timezone),
addslashes($profile_name1_alt),
addslashes($profile_name2_alt)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows() >0) {
$inserted++;
} else {
$failed++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
$mongo_data=array('reseller_id' => intval(reseller_id),
'gateway' => $gateway,
'domain' => $domain,
'subscriber' => $subscriber,
'profile_name1' => $profile_name1,
'profile_name2' => $profile_name2,
'profile_name1_alt' => $profile_name1_alt,
'profile_name2_alt' => $profile_name2_alt,
'timezone' => $timezone
);
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_customers');
$mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe));
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when inserting in billing_customers: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
}
} else if ($ops=="3") {
$query=sprintf("delete from billing_customers
where gateway = '%s'
and reseller_id = '%s'
and domain = '%s'
and subscriber = '%s'
",
addslashes($gateway),
addslashes($reseller_id),
addslashes($domain),
addslashes($subscriber)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows() >0) {
$deleted++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_customers');
$mongo_match = array('gateway' => $gateway,
'reseller_id' => intval(reseller_id),
'domain' => $domain,
'subscriber' => $subscriber,
'dest_id' => $dest_id
);
$mongo_table_rw->remove($mongo_match,
array("safe" => $self->mongo_safe)
);
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when deleting from billing_customers: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
}
} else if ($ops=="2") {
$query=sprintf("select * from billing_customers
where gateway = '%s'
and reseller_id = '%s'
and domain = '%s'
and subscriber = '%s'
",
addslashes($gateway),
addslashes($reseller_id),
addslashes($domain),
addslashes($subscriber)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->num_rows()) {
$query=sprintf("update billing_customers set
profile_name1 = '%s',
profile_name2 = '%s',
profile_name1_alt = '%s',
profile_name2_alt = '%s',
timezone = '%s'
where gateway = '%s'
and domain = '%s'
and reseller_id = '%s'
and subscriber = '%s'\n",
addslashes($profile_name1),
addslashes($profile_name2),
addslashes($profile_name1_alt),
addslashes($profile_name2_alt),
addslashes($timezone),
addslashes($gateway),
addslashes($domain),
addslashes($reseller_id),
addslashes($subscriber)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows()) {
$updated++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
$mongo_match = array('gateway' => $gateway,
'reseller_id' => intval(reseller_id),
'domain' => $domain,
'subscriber' => $subscriber
);
$mongo_data=array('reseller_id' => intval(reseller_id),
'gateway' => $gateway,
'domain' => $domain,
'subscriber' => $subscriber,
'profile_name1' => $profile_name1,
'profile_name2' => $profile_name2,
'profile_name1_alt' => $profile_name1_alt,
'profile_name2_alt' => $profile_name2_alt,
'timezone' => $timezone
);
$mongo_options = array("upsert" => true,
"safe" => $self->mongo_safe
);
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_customers');
$result = $mongo_table_rw->update($mongo_match, $mongo_data, $mongo_options);
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when updating billing_customers: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
}
} else {
$query=sprintf("insert into billing_customers
(
reseller_id,
gateway,
domain,
subscriber,
profile_name1,
profile_name2,
timezone,
profile_name1_alt,
profile_name2_alt
) values (
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s'
)",
addslashes($reseller_id),
addslashes($gateway),
addslashes($domain),
addslashes($subscriber),
addslashes($profile_name1),
addslashes($profile_name2),
addslashes($timezone),
addslashes($profile_name1_alt),
addslashes($profile_name2_alt)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows()) {
$inserted++;
}
if ($this->mongo_db_rw) {
$mongo_data=array('reseller_id' => intval(reseller_id),
'gateway' => $gateway,
'domain' => $domain,
'subscriber' => $subscriber,
'profile_name1' => $profile_name1,
'profile_name2' => $profile_name2,
'profile_name1_alt' => $profile_name1_alt,
'profile_name2_alt' => $profile_name2_alt,
'timezone' => $timezone
);
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_customers');
$mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe));
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when inserting in billing_customers: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
}
} else {
$skipped++;
}
$this->showImportProgress($file);
$i++;
}
if ($i) print "Read $i records\n";
if ($skipped) print "Skipped $skipped records\n";
if ($inserted) print "Inserted $inserted records\n";
if ($updated) print "Updated $updated records\n";
if ($deleted) print "Delete $deleted records\n";
$results=$inserted+$updated+$deleted;
return $results;
}
function ImportDestinations($file,$reseller=0) {
if (!$file || !is_readable($file) || !$fp = fopen($file, "r")) return false;
$this->mustReload=true;
$i=0;
$inserted = 0;
$updated = 0;
$deleted = 0;
printf ("Importing destinations from %s for reseller %s:\n",$file,$reseller);
while ($buffer = fgets($fp,1024)) {
$buffer=trim($buffer);
$p = explode($this->delimiter, $buffer);
$ops = trim($p[0]);
$gateway = trim($p[2]);
$domain = trim($p[3]);
$subscriber = trim($p[4]);
$dest_id = trim($p[5]);
$region = trim($p[6]);
$dest_name = trim($p[7]);
$increment = intval($p[8]);
$min_duration = intval($p[9]);
$max_duration = intval($p[10]);
$max_price = trim($p[11]);
if ($reseller) {
$reseller_id = intval($reseller);
} else {
$reseller_id = intval($p[1]);
}
if (!is_numeric($dest_id) && !strstr($dest_id,'@')) {
// skip invalid destinations
$skipped++;
continue;
}
if ($ops=="1") {
$query=sprintf("insert into destinations
(
reseller_id,
gateway,
domain,
subscriber,
dest_id,
region,
dest_name,
increment,
min_duration,
max_duration,
max_price
) values (
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s'
)",
addslashes($reseller_id),
addslashes($gateway),
addslashes($domain),
addslashes($subscriber),
addslashes($dest_id),
addslashes($region),
addslashes($dest_name),
addslashes($increment),
addslashes($min_duration),
addslashes($max_duration),
addslashes($max_price)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows() >0) {
$inserted++;
} else {
$failed++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
$mongo_data=array('reseller_id' => intval(reseller_id),
'gateway' => $gateway,
'domain' => $domain,
'subscriber' => $subscriber,
'dest_id' => $dest_id,
'region' => $region,
'dest_name' => $dest_name,
'increment' => intval($increment),
'min_duration' => intval($min_duration),
'max_duration' => intval($max_duration),
'max_price' => floatval($max_price)
);
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('destinations');
$mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe));
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when inserting in destinations: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
}
} elseif ($ops=="3") {
$query=sprintf("delete from destinations
where gateway = '%s'
and reseller_id = '%s'
and domain = '%s'
and subscriber = '%s'
and dest_id = '%s'
",
addslashes($gateway),
addslashes($reseller_id),
addslashes($domain),
addslashes($subscriber),
addslashes($dest_id)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows() >0) {
$deleted++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('destinations');
$mongo_match = array('gateway' => $gateway,
'reseller_id' => intval(reseller_id),
'domain' => $domain,
'subscriber' => $subscriber,
'dest_id' => $dest_id
);
$mongo_table_rw->remove($mongo_match,
array("safe" => $self->mongo_safe)
);
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when deleting from destinations: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
}
} elseif ($ops=="2") {
$query=sprintf("select * from destinations
where gateway = '%s'
and reseller_id = '%s'
and domain = '%s'
and subscriber = '%s'
and dest_id = '%s'
",
addslashes($gateway),
addslashes($reseller_id),
addslashes($domain),
addslashes($subscriber),
addslashes($dest_id)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->num_rows()) {
$query=sprintf("update destinations set
region = '%s',
dest_name = '%s',
increment = '%s',
min_duration = '%s',
max_duration = '%s',
max_price = '%s'
where gateway = '%s'
and reseller_id = '%s'
and domain = '%s'
and subscriber = '%s'
and dest_id = '%s'
",
addslashes($region),
addslashes($dest_name),
addslashes($increment),
addslashes($min_duration),
addslashes($max_duration),
addslashes($max_price),
addslashes($gateway),
addslashes($reseller_id),
addslashes($domain),
addslashes($subscriber),
addslashes($dest_id)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows()) {
$updated++;
}
dprint($this->database_backend);
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
$mongo_match = array('gateway' => $gateway,
'reseller_id' => intval(reseller_id),
'domain' => $domain,
'subscriber' => $subscriber,
'dest_id' => $dest_id
);
$mongo_data = array('reseller_id' => intval(reseller_id),
'gateway' => $gateway,
'domain' => $domain,
'subscriber' => $subscriber,
'dest_id' => $dest_id,
'region' => $region,
'dest_name' => $dest_name,
'increment' => intval($increment),
'min_duration' => intval($min_duration),
'max_duration' => intval($max_duration),
'max_price' => floatval($max_price)
);
$mongo_options = array("upsert" => true,
"safe" => $self->mongo_safe
);
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('destinations');
$result = $mongo_table_rw->update($mongo_match, $mongo_data, $mongo_options);
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when updating destinations: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
}
} else {
$query=sprintf("insert into destinations
(
reseller_id,
gateway,
domain,
subscriber,
dest_id,
region,
dest_name,
increment,
min_duration,
max_duration,
max_price
) values (
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s'
)",
addslashes($reseller_id),
addslashes($gateway),
addslashes($domain),
addslashes($subscriber),
addslashes($dest_id),
addslashes($region),
addslashes($dest_name),
addslashes($increment),
addslashes($min_duration),
addslashes($max_duration),
addslashes($max_price)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows() >0) {
$inserted++;
} else {
$failed++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
$mongo_data=array('reseller_id' => intval(reseller_id),
'gateway' => $gateway,
'domain' => $domain,
'subscriber' => $subscriber,
'dest_id' => $dest_id,
'region' => $region,
'dest_name' => $dest_name,
'increment' => intval($increment),
'min_duration' => intval($min_duration),
'max_duration' => intval($max_duration),
'max_price' => floatval($max_price)
);
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('destinations');
$mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe));
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when inserting in destinations: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
}
}
}
}
} else {
$skipped++;
}
$this->showImportProgress($file);
$i++;
}
if ($i) print "Read $i records\n";
if ($skipped) print "Skipped $skipped records\n";
if ($inserted) print "Inserted $inserted records\n";
if ($updated) print "Updated $updated records\n";
if ($deleted) print "Delete $deleted records\n";
$results=$inserted+$updated+$deleted;
return $results;
}
function ImportDiscounts($file,$reseller=0) {
if (!$file || !is_readable($file) || !$fp = fopen($file, "r")) return false;
$this->mustReload=true;
$i=0;
$inserted = 0;
$updated = 0;
$deleted = 0;
printf ("Importing discounts from %s for reseller %s:\n",$file,$reseller);
while ($buffer = fgets($fp,1024)) {
$buffer=trim($buffer);
$p = explode($this->delimiter, $buffer);
$ops = trim($p[0]);
$gateway = trim($p[2]);
$domain = trim($p[3]);
$subscriber = trim($p[4]);
$application = trim($p[5]);
$destination = trim($p[6]);
$region = trim($p[7]);
$connect = intval($p[8]);
$duration = intval($p[9]);
if ($reseller) {
$reseller_id = intval($reseller);
} else {
$reseller_id = intval($p[1]);
}
if (!is_numeric($destination) && !strstr($destination,'@')) {
// skip invalid destinations
$skipped++;
continue;
}
if ($ops=="1") {
$query=sprintf("insert into billing_discounts
(
reseller_id,
gateway,
domain,
subscriber,
application,
destination,
region,
connect,
duration
) values (
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s'
)",
addslashes($reseller_id),
addslashes($gateway),
addslashes($domain),
addslashes($subscriber),
addslashes($application),
addslashes($destination),
addslashes($region),
addslashes($connect),
addslashes($duration)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows() >0) {
$inserted++;
} else {
$failed++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
$mongo_data=array('reseller_id' => intval(reseller_id),
'gateway' => $gateway,
'domain' => $domain,
'subscriber' => $subscriber,
'application' => $application,
'destination' => $destination,
'region' => $region,
'connect' => intval($connect),
'duration' => intval($min_duration)
);
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_discounts');
$mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe));
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when inserting in billing_discounts: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
}
} elseif ($ops=="3") {
$query=sprintf("delete from billing_discounts
where gateway = '%s'
and reseller_id = '%s'
and domain = '%s'
and subscriber = '%s'
and application = '%s'
and destination = '%s'
and region = '%s'
",
addslashes($gateway),
addslashes($reseller_id),
addslashes($domain),
addslashes($subscriber),
addslashes($application),
addslashes($destination),
addslashes($region)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows() >0) {
$deleted++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_discounts');
$mongo_match=array('reseller_id' => intval(reseller_id),
'gateway' => $gateway,
'domain' => $domain,
'subscriber' => $subscriber,
'application' => $application,
'destination' => $destination,
'region' => $region
);
$mongo_table_rw->remove($mongo_match,
array("safe" => $self->mongo_safe)
);
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when deleting from billing_discounts: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
}
} elseif ($ops=="2") {
$query=sprintf("select * from billing_discounts
where gateway = '%s'
and reseller_id = '%s'
and domain = '%s'
and subscriber = '%s'
and application = '%s'
and destination = '%s'
and region = '%s'
",
addslashes($gateway),
addslashes($reseller_id),
addslashes($domain),
addslashes($subscriber),
addslashes($application),
addslashes($destination),
addslashes($region)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->num_rows()) {
$query=sprintf("update billing_discounts set
connect = '%s',
duration = '%s',
where gateway = '%s'
and reseller_id = '%s'
and domain = '%s'
and subscriber = '%s'
and application = '%s'
and destination = '%s'
and region = '%s'
",
addslashes($connect),
addslashes($duration),
addslashes($gateway),
addslashes($reseller_id),
addslashes($domain),
addslashes($subscriber),
addslashes($application),
addslashes($destination),
addslashes($region)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows()) {
$updated++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
$mongo_match=array('reseller_id' => intval(reseller_id),
'gateway' => $gateway,
'domain' => $domain,
'subscriber' => $subscriber,
'application' => $application,
'destination' => $destination,
'region' => $region
);
$mongo_data=array('reseller_id' => intval(reseller_id),
'gateway' => $gateway,
'domain' => $domain,
'subscriber' => $subscriber,
'application' => $application,
'destination' => $destination,
'region' => $region,
'connect' => intval($connect),
'duration' => intval($min_duration)
);
$mongo_options = array("upsert" => true,
"safe" => $self->mongo_safe
);
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_discounts');
$result = $mongo_table_rw->update($mongo_match, $mongo_data, $mongo_options);
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when updating billing_discounts: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
}
} else {
$query=sprintf("insert into billing_discounts
(
reseller_id,
gateway,
domain,
subscriber,
application,
destination,
region,
connect,
duration
) values (
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s'
)",
addslashes($reseller_id),
addslashes($gateway),
addslashes($domain),
addslashes($subscriber),
addslashes($application),
addslashes($destination),
addslashes($region),
addslashes($connect),
addslashes($duration)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows() >0) {
$inserted++;
} else {
$failed++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
$mongo_data=array('reseller_id' => intval(reseller_id),
'gateway' => $gateway,
'domain' => $domain,
'subscriber' => $subscriber,
'application' => $application,
'destination' => $destination,
'region' => $region,
'connect' => intval($connect),
'duration' => intval($min_duration)
);
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_discounts');
$mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe));
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when inserting in billing_discounts: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
}
}
} else {
$skipped++;
}
$this->showImportProgress($file);
$i++;
}
if ($i) print "Read $i records\n";
if ($skipped) print "Skipped $skipped records\n";
if ($inserted) print "Inserted $inserted records\n";
if ($updated) print "Updated $updated records\n";
if ($deleted) print "Delete $deleted records\n";
$results=$inserted+$updated+$deleted;
return $results;
}
function ImportProfiles($file,$reseller=0) {
if (!$file || !is_readable($file) || !$fp = fopen($file, "r")) return false;
$this->mustReload=true;
$i=0;
$inserted = 0;
$updated = 0;
$deleted = 0;
print "Importing Profiles:\n";
while ($buffer = fgets($fp,1024)) {
$buffer=trim($buffer);
$p = explode($this->delimiter, $buffer);
$ops = trim($p[0]);
$profile = trim($p[2]);
$rate1 = trim($p[3]);
$hour1 = trim($p[4]);
$rate2 = trim($p[5]);
$hour2 = trim($p[6]);
$rate3 = trim($p[7]);
$hour3 = trim($p[8]);
$rate4 = trim($p[9]);
$hour4 = trim($p[10]);
if ($reseller) {
$reseller_id = intval($reseller);
} else {
$reseller_id = intval($p[1]);
}
if (!$hour1) $hour1=0;
if (!$hour2) $hour2=0;
if (!$hour3) $hour3=0;
if (!$hour4) $hour4=0;
if ($ops=="1") {
$query=sprintf("insert into billing_profiles
(
reseller_id,
name,
rate_name1,
hour1,
rate_name2,
hour2,
rate_name3,
hour3,
rate_name4,
hour4
) values (
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s'
)",
addslashes($reseller_id),
addslashes($profile),
addslashes($rate1),
addslashes($hour1),
addslashes($rate2),
addslashes($hour2),
addslashes($rate3),
addslashes($hour3),
addslashes($rate4),
addslashes($hour4)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows() >0) {
$inserted++;
} else {
$failed++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
$mongo_data=array('reseller_id' => intval(reseller_id),
'name' => $profile,
'rate_name1' => $rate1,
'hour1' => $hour1,
'rate_name2' => $rate2,
'hour2' => $hour2,
'rate_name3' => $rate3,
'hour3' => $hour3,
'rate_name4' => $rate4,
'hour4' => $hour4
);
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_profiles');
$mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe));
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when inserting in billing_profiles: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
}
}
}
} else if ($ops=="3") {
$query=sprintf("delete from billing_profiles
where name = '%s'
and reseller_id= '%s'
",
addslashes($profile),
addslashes($reseller_id)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows() >0) {
$deleted++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_profiles');
$mongo_match = array('reseller_id' => intval(reseller_id),
'name' => $name
);
$mongo_table_rw->remove($mongo_match,
array("safe" => $self->mongo_safe)
);
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when deleting from billing_profiles: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
}
} else if ($ops=="2") {
$query=sprintf("select * from billing_profiles
where name = '%s'
and reseller_id= '%s'
",
addslashes($profile),
addslashes($reseller_id)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->num_rows()) {
$query=sprintf("update billing_profiles set
rate_name1 = '%s',
rate_name2 = '%s',
rate_name3 = '%s',
rate_name4 = '%s',
hour1 = '%s',
hour2 = '%s',
hour3 = '%s',
hour4 = '%s'
where name = '%s'
and reseller_id= '%s'
\n",
addslashes($rate1),
addslashes($rate2),
addslashes($rate3),
addslashes($rate4),
addslashes($hour1),
addslashes($hour2),
addslashes($hour3),
addslashes($hour4),
addslashes($profile),
addslashes($reseller_id)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows()) {
$updated++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
$mongo_match = array('reseller_id' => intval(reseller_id),
'name' => $profile
);
$mongo_data=array('reseller_id' => intval(reseller_id),
'name' => $profile,
'rate_name1' => $rate1,
'hour1' => $hour1,
'rate_name2' => $rate2,
'hour2' => $hour2,
'rate_name3' => $rate3,
'hour3' => $hour3,
'rate_name4' => $rate4,
'hour4' => $hour4
);
$mongo_options = array("upsert" => true,
"safe" => $self->mongo_safe
);
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_profiles');
$result = $mongo_table_rw->update($mongo_match, $mongo_data, $mongo_options);
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when updating billing_profiles: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
}
} else {
$query=sprintf("insert into billing_profiles
(
reseller_id,
name,
rate_name1,
hour1,
rate_name2,
hour2,
rate_name3,
hour3,
rate_name4,
hour4
) values (
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s',
'%s'
)",
addslashes($reseller_id),
addslashes($profile),
addslashes($rate1),
addslashes($hour1),
addslashes($rate2),
addslashes($hour2),
addslashes($rate3),
addslashes($hour3),
addslashes($rate4),
addslashes($hour4)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows() >0) {
$inserted++;
} else {
$failed++;
}
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_rw) {
$mongo_data=array('reseller_id' => intval(reseller_id),
'name' => $profile,
'rate_name1' => $rate1,
'hour1' => $hour1,
'rate_name2' => $rate2,
'hour2' => $hour2,
'rate_name3' => $rate3,
'hour3' => $hour3,
'rate_name4' => $rate4,
'hour4' => $hour4
);
try {
$mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_profiles');
$mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe));
} catch (Exception $e) {
$log=sprintf("Error: Mongo exception when inserting in billing_profiles: %s", $e->getMessage());
print $log;
syslog(LOG_NOTICE, $log);
}
}
}
}
}
$this->showImportProgress($file);
$i++;
}
if ($i) print "Read $i records\n";
if ($inserted) print "Inserted $inserted records\n";
if ($updated) print "Updated $updated records\n";
if ($deleted) print "Delete $deleted records\n";
$results=$inserted+$updated+$deleted;
return $results;
}
function LoadRatingTables () {
$log=sprintf("Memory usage: %0.2fMB, memory limit: %sB",memory_get_usage()/1024/1024,ini_get('memory_limit'));
syslog(LOG_NOTICE, $log);
$loaded['profiles'] = $this->LoadProfilesTable();
$loaded['ratesHistory'] = $this->LoadRatesHistoryTable();
$loaded['holidays'] = $this->LoadHolidaysTable();
$loaded['enumTlds'] = $this->LoadENUMtldsTable();
foreach(array_keys($loaded) as $_load) {
syslog(LOG_NOTICE, "Loaded $loaded[$_load] $_load into memory");
}
$log=sprintf("Memory usage: %0.2fMB, memory limit: %sB",memory_get_usage()/1024/1024,ini_get('memory_limit'));
syslog(LOG_NOTICE, $log);
return $loaded;
}
function LoadENUMtldsTable() {
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_ro) {
// mongo backend
try {
$table = $this->mongo_db_ro->selectCollection('billing_enum_tlds');
$cursor = $table->find()->slaveOkay();
} catch (Exception $e) {
$log = sprintf("<p>Caught Mongo exception in LoadENUMtldsTable(): %s", $e->getMessage());
syslog(LOG_NOTICE, $log);
return 0;
}
$i=0;
foreach ($cursor as $result) {
if ($result['enum_tld']) {
$i++;
$_app=$result['application'];
if (!$_app) $_app='audio';
$_ENUMtlds[$result['enum_tld']]=
array(
"discount" => $result['discount'],
"e164_regexp" => $result['e164_regexp']
);
}
}
$this->ENUMtlds = $_ENUMtlds;
$this->ENUMtldsCount = $i;
return $i;
} else {
$log = sprintf("<p>Error: mongo db is not initialized in LoadENUMtldsTable()");
syslog(LOG_NOTICE, $log);
return 0;
}
}
$query="select * from billing_enum_tlds";
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
$i=0;
$rows=$this->db->num_rows();
while($this->db->next_record()) {
if ($this->db->Record['enum_tld']) {
$i++;
$_app=$this->db->Record['application'];
if (!$_app) $_app='audio';
$_ENUMtlds[$this->db->Record['enum_tld']]=
array(
"discount" => $this->db->Record['discount'],
"e164_regexp" => $this->db->Record['e164_regexp']
);
}
}
$this->ENUMtlds = $_ENUMtlds;
$this->ENUMtldsCount = $i;
return $i;
}
function LoadRatesHistoryTable() {
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_ro) {
// mongo backend
try {
$table = $this->mongo_db_ro->selectCollection('billing_rates_history');
$cursor = $table->find()->slaveOkay();
} catch (Exception $e) {
$log = sprintf("<p>Caught Mongo exception in LoadRatesHistoryTable(): %s", $e->getMessage());
syslog(LOG_NOTICE, $log);
return 0;
}
$i=0;
foreach ($cursor as $result) {
$i++;
if ($result['name'] && $result['destination']) {
$i++;
$_app=$result['application'];
if (!$_app) $_app='audio';
preg_match("/^(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)$/",$result['startDateTimestamp'],$m);
$startDate = mktime($m[4],$m[5],$m[6],$m[2],$m[3],$m[1]);
preg_match("/^(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)$/",$result['endDateTimestamp'],$m);
$endDate = mktime($m[4],$m[5],$m[6],$m[2],$m[3],$m[1]);
$_rates[$result['name']][$result['destination']][$_app][$result['id']]=
array(
"connectCost" => $result['connectCost'],
"durationRate" => $result['durationRate'],
"connectCostIn" => $result['connectCostIn'],
"durationRateIn" => $result['durationRateIn'],
"increment" => $result['increment'],
"min_duration" => $result['min_duration'],
"startDate" => $startDate,
"endDate" => $endDate
);
}
}
$this->ratesHistory=$_rates;
$this->ratesHistoryCount=$i;
return $i;
} else {
$log = sprintf("<p>Error: mongo db is not initialized in LoadRatesHistoryTable()");
syslog(LOG_NOTICE, $log);
return 0;
}
}
$query="select *,
UNIX_TIMESTAMP(startDate) as startDateTimestamp,
UNIX_TIMESTAMP(endDate) as endDateTimestamp
from billing_rates_history
order by name ASC,destination ASC,startDate DESC";
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
$i=0;
$rows=$this->db->num_rows();
while($this->db->next_record()) {
if ($this->db->Record['name'] && $this->db->Record['destination']) {
$i++;
$_app=$this->db->Record['application'];
if (!$_app) $_app='audio';
$_rates[$this->db->Record['name']][$this->db->Record['destination']][$_app][$this->db->Record['id']]=
array(
"connectCost" => $this->db->Record['connectCost'],
"durationRate" => $this->db->Record['durationRate'],
"connectCostIn" => $this->db->Record['connectCostIn'],
"durationRateIn" => $this->db->Record['durationRateIn'],
"increment" => $this->db->Record['increment'],
"min_duration" => $this->db->Record['min_duration'],
"startDate" => $this->db->Record['startDateTimestamp'],
"endDate" => $this->db->Record['endDateTimestamp']
);
}
}
$this->ratesHistory=$_rates;
$this->ratesHistoryCount=$i;
return $i;
}
function LoadProfilesTable() {
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_ro) {
// mongo backend
try {
$table = $this->mongo_db_ro->selectCollection('billing_profiles');
$cursor = $table->find()->slaveOkay();
} catch (Exception $e) {
$log = sprintf("<p>Caught Mongo exception in LoadProfilesTable(): %s", $e->getMessage());
syslog(LOG_NOTICE, $log);
return 0;
}
$i=0;
foreach ($cursor as $result) {
$i++;
if ($result['name'] && $result['hour1'] > 0 ) {
$_profiles[$result['name']]=
array(
"rate_name1" => $result['rate_name1'],
"hour1" => $result['hour1'],
"rate_name2" => $result['rate_name2'],
"hour2" => $result['hour2'],
"rate_name3" => $result['rate_name3'],
"hour3" => $result['hour3'],
"rate_name4" => $result['rate_name4'],
"hour4" => $result['hour4'],
);
}
}
$this->profiles=$_profiles;
return $i;
} else {
$log = sprintf("<p>Error: mongo db is not initialized in LoadProfilesTable()");
syslog(LOG_NOTICE, $log);
return 0;
}
}
$query="select * from billing_profiles order by name";
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
$i=0;
while($this->db->next_record()) {
$i++;
if ($this->db->Record['name'] && $this->db->Record['hour1'] > 0 ) {
$_profiles[$this->db->Record['name']]=
array(
"rate_name1" => $this->db->Record['rate_name1'],
"hour1" => $this->db->Record['hour1'],
"rate_name2" => $this->db->Record['rate_name2'],
"hour2" => $this->db->Record['hour2'],
"rate_name3" => $this->db->Record['rate_name3'],
"hour3" => $this->db->Record['hour3'],
"rate_name4" => $this->db->Record['rate_name4'],
"hour4" => $this->db->Record['hour4'],
);
}
}
$this->profiles=$_profiles;
return $i;
}
function LoadHolidaysTable() {
if ($this->database_backend == 'mongo') {
if ($this->mongo_db_ro) {
// mongo backend
try {
$table = $this->mongo_db_ro->selectCollection('billing_holidays');
$cursor = $table->find()->slaveOkay();
} catch (Exception $e) {
$log = sprintf("<p>Caught Mongo exception in LoadHolidaysTable(): %s", $e->getMessage());
syslog(LOG_NOTICE, $log);
return 0;
}
$i=0;
foreach ($cursor as $result) {
$i++;
if ($result['day']) {
$i++;
$_holidays[$result['day']]++;
}
}
$this->holidays=$_holidays;
return $i;
} else {
$log = sprintf("<p>Error: mongo db is not initialized in LoadHolidaysTable()");
syslog(LOG_NOTICE, $log);
return 0;
}
}
$query="select * from billing_holidays order by day";
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
$i=0;
while($this->db->next_record()) {
if ($this->db->Record['day']) {
$i++;
$_holidays[$this->db->Record['day']]++;
}
}
$this->holidays=$_holidays;
return $i;
}
function checkRatingEngineConnection () {
if ($this->settings['socketIPforClients'] && $this->settings['socketPort'] &&
$fp = fsockopen ($this->settings['socketIPforClients'], $this->settings['socketPort'], $errno, $errstr, 2)) {
fclose($fp);
return true;
}
return false;
}
function showCustomers($filter) {
return true;
foreach (array_keys($this->customers) as $key) {
if (strlen($filter)) {
if (preg_match("/$filter/",$key)) {
$customers=$customers.$key."\n";
}
} else {
$customers=$customers.$key."\n";
}
}
return $customers;
}
function showProfiles() {
foreach (array_keys($this->profiles) as $key) {
$profiles=$profiles.$key."\n";
}
return $profiles;
}
function showENUMtlds() {
foreach (array_keys($this->ENUMtlds) as $key) {
$ENUMtlds=$ENUMtlds.$key."\n";
}
return $ENUMtlds;
}
function scanFilesForImport($dir) {
$import_dirs[$this->cvs_import_dir]=array('path'=>$this->cvs_import_dir,
'reseller' => 0
);
if ($handle = opendir($this->cvs_import_dir)) {
while (false !== ($filename = readdir($handle))) {
$reseller=0;
if ($filename == "." || $filename == "..") continue;
$fullPath=$this->cvs_import_dir."/".$filename;
if (is_dir($fullPath) && is_numeric($filename)) {
$reseller=$filename;
$import_dirs[$fullPath]=array('path' => $fullPath,
'reseller'=> $reseller
);
}
}
}
foreach (array_keys($import_dirs) as $_dir) {
if ($handle = opendir($_dir)) {
while (false !== ($filename = readdir($handle))) {
if ($filename != "." && $filename != "..") {
foreach ($this->importFilesPatterns as $_pattern) {
if (strstr($filename,$_pattern) && preg_match("/\.csv$/",$filename)) {
$fullPath=$_dir."/".$filename;
if ($content=file_get_contents($fullPath)) {
$watermark=$filename."-".md5($content);
if ($this->hasFileBeenImported($filename,$watermark)) {
$this->previously_imported_files++;
break;
}
$this->filesToImport[$filename]=array( 'name' => $filename,
'watermark' => $watermark,
'type' => $_pattern,
'path' => $fullPath,
'reseller' => $import_dirs[$_dir]['reseller']
);
}
break;
}
}
}
}
}
}
}
function hasFileBeenImported($filename,$watermark) {
$query=sprintf("select * from log where url = '%s'\n",addslashes($watermark));
if ($this->db->query($query)) {
if ($this->db->num_rows()) {
$this->db->next_record();
/*
$log=sprintf ("File %s has already been imported at %s.\n",$filename,$this->db->f('date'));
syslog(LOG_NOTICE, $log);
print $log;
*/
return true;
} else {
return false;
}
} else {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
function logImport($dir,$filename,$watermark,$results=0,$reseller=0) {
$query=sprintf("insert into log (date,login,ip,url,results,description,datasource,reseller_id)
values (NOW(),'ImportScript','localhost','%s','%s','Imported %s','%s',%d)",
addslashes($watermark),addslashes($results),addslashes($filename),addslashes($dir),addslashes($reseller));
$log=sprintf ("Imported file %s, %d records have been affected\n",$filename,$results);
syslog(LOG_NOTICE, $log);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
function showImportProgress ($filename='unspecified',$increment=5000) {
$this->importIndex++;
if ($this->importIndex == $increment) {
printf ("Loaded %d records from %s\n",$this->importIndex,$filename);
flush();
$this->importIndex=0;
}
}
function createRatingTable($name) {
if ($name) {
$table='billing_rates_'.$name;
} else {
$table='billing_rates_default';
}
$query=sprintf("create table %s select * from billing_rates where name = '%s'\n",addslashes($table),addslashes($name));
if ($this->db->query($query)) {
$query=sprintf("alter table %s add index rate_idx (name)",addslashes($table));
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
}
$query=sprintf("alter table %s add index destination_idx (destination)",addslashes($table));
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
}
printf ("Created table %s\n",$table);
return true;
} else {
return false;
}
}
function splitRatingTable() {
$query="select count(*) as c from billing_rates";
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
$this->db->next_record();
$rows=$this->db->f('c');
$query="select distinct(name) from billing_rates order by name ASC";
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
while ($this->db->next_record()) {
$rate_names[]=$this->db->f('name');
}
foreach ($rate_names as $name) {
if (!$name) $name='default';
$table="billing_rates_".$name;
$query=sprintf("drop table if exists %s",addslashes($table));
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
$query=sprintf("create table %s select * from billing_rates where name = '%s'\n",addslashes($table),addslashes($name));
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
} else {
$query=sprintf("alter table %s add index rate_idx (name)",addslashes($table));
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
$query=sprintf("alter table %s add index destination_idx (destination)",addslashes($table));
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
$query=sprintf("select count(*) as c from %s",addslashes($table));
$this->db->query($query);
$this->db->next_record();
$records=$this->db->f('c');
$created_records=$created_records+$records;
$progress=100*$created_records/$rows;
printf ("Created table %s with %s records (%.1f %s)\n",$table,$records,$progress,'%');
}
}
return true;
}
function updateTable() {
global $auth;
$loginname=$auth->auth["uname"];
foreach ($this->web_elements as $_el) {
${$_el}= $_REQUEST[$_el];
}
if (!$table) return false;
if ($this->readonly) {
return true;
}
// Init table structure
if (!is_array($this->tables[$table]['exceptions'])) $this->tables[$table]['exceptions']=array();
if (!is_array($this->tables[$table]['keys'])) $this->tables[$table]['keys']=array();
if (!is_array($this->tables[$table]['fields'])) $this->tables[$table]['fields']=array();
$metadata = $this->db->metadata($table="$table");
$cc = count($metadata);
// end init table structure
if ($web_task =="update") {
$affected_rows=0;
if ($subweb_task == "Update") {
if ($this->checkValues($table,$_REQUEST)) {
$update_set='';
$k=0;
while ($k < $cc ) {
$k++;
$Fname=$metadata[$k]['name'];
if (!$Fname) continue;
$value=$_REQUEST[$Fname];
if ($this->tables[$table]['fields'][$Fname]['readonly']) {
continue;
}
if (in_array($Fname,$this->tables[$table]['exceptions'])) {
continue;
}
if (in_array($Fname,$this->tables[$table]['keys'])) {
continue;
}
if ($kkk > 0) {
$comma = ",";
} else {
$comma = "";
}
if (!$this->tables[$table]['skip_math'] && preg_match("/^([\+\-\*\/])(.*)$/",$value,$sign)) {
$update_set .= $comma.addslashes($Fname)."= ROUND(".addslashes($Fname). " ".$sign[1]. "'".$sign[2]."')";
} else {
$update_set .= $comma.addslashes($Fname)."='".addslashes($value)."'";
}
$kkk++;
}
$k=0;
while ($k < $cc ) {
if ($metadata[$k]['name'] == 'change_date') {
$update_set .= sprintf("%s %s = NOW() ",$comma,addslashes($metadata[$k]['name']));
break;
}
$k++;
}
$log_entity=" id = $id ";
$where = sprintf(" id = '%s' and %s", addslashes($id), $this->whereResellerFilter);
if ($table == "billing_rates") {
if ($this->settings['split_rating_table']) {
$rate_table_affected=array();
$query_r="select distinct (name) from billing_rates where". $where;
if ($this->db->query($query_r)) {
while($this->db->next_record()) {
$rate_tables_affected[]='billing_rates_'.$this->db->f('name');
}
} else {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
}
}
} else if ($table=="prepaid") {
register_shutdown_function("unLockTables",$this->db);
if ($this->db->query("lock table prepaid write")) {
$query_q=sprintf("select * from prepaid where account = '%s'",addslashes($account));
if ($this->db->query($query_q) && $this->db->num_rows()) {
$this->db->next_record();
$old_balance=$this->db->f('balance');
}
$this->db->query("unlock tables");
}
}
$query = sprintf("update %s set %s where %s " ,
addslashes($table),
$update_set,
$where
);
if ($this->db->query($query)) {
$affected_rows=$this->db->affected_rows();
if ($affected_rows) {
if ($table=="prepaid") {
list($username,$domain)=explode("@",$account);
$value=$balance-$old_balance;
if (floatval($balance) != floatval($old_balance)) {
$query=sprintf("insert into prepaid_history
(username,domain,action,description,value,balance,date,reseller_id)
values
('%s','%s','Set balance','Manual update','%s','%s',NOW(),%d)",
addslashes($username),
addslashes($domain),
addslashes($value),
addslashes($balance),
$this->CDRTool['filter']['reseller']
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
}
}
} else if ($table=='billing_rates') {
if ($this->settings['split_rating_table']) {
foreach ($rate_tables_affected as $extra_rate_table) {
$query_u = sprintf("update %s set %s where %s ",
addslashes($extra_rate_table),
$update_set,
$where
);
if (!$this->db->query($query_u)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query_u,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
}
}
}
}
if (in_array($table,$this->requireReload)) {
if (!$this->db->query("update settings set var_value= '1' where var_name = 'reloadRating'")){
printf ("<font color=red>Database error: %s (%s)</font>",$this->db->Error,$this->db->Errno);
}
}
}
} else {
printf ("<font color=red>Database error for query '%s': %s (%s)</font>",$query,$this->db->Error,$this->db->Errno);
}
} else {
print "<p>Correct the values and try again.";
}
} elseif ($subweb_task == "Update selection") {
$k=0;
$kkk=0;
$update_set='';
while ($k < $cc ) {
$k++;
$Fname=$metadata[$k]['name'];
$value=$_REQUEST[$Fname];
if (!strlen($value)) continue;
if ($this->tables[$table]['fields'][$Fname]['readonly']) {
continue;
}
if (in_array($Fname,$this->tables[$table]['exceptions'])) {
continue;
}
if (in_array($Fname,$this->tables[$table]['keys'])) {
continue;
}
if ($kkk > 0) {
$comma = ",";
} else {
$comma="";
}
if ($value == "NULL") {
$value="";
}
if (preg_match("/^([\+\-\*\/])(.*)$/",$value,$sign)) {
$update_set .= $comma.$Fname." = ROUND(".$Fname. " ".$sign[1]. "'".$sign[2]."')";
} else {
$update_set .= $comma.$Fname." = '".$value."'";
}
$kkk++;
}
$where = $this->whereResellerFilter;
if ($kkk) {
// reconstruct where clause to apply all changes to selection
// build where clause
// Search build for each field
$j=0;
while ($j < $cc ) {
$Fname=$metadata[$j]['name'];
$size=$metadata[$j]['len'];
if (!in_array($Fname,$this->tables[$table]['exceptions'])) {
$f_name="search_".$Fname;
$value=$_REQUEST[$f_name];
if (preg_match("/^([<|>]+)(.*)$/",$value,$likes)) {
$like=$likes[1];
$likewhat=$likes[2];
$quotes="";
} else {
$like="like";
$likewhat=$value;
$quotes="'";
}
if (strlen($value)) {
$where .= " and $Fname $like $quotes".$likewhat."$quotes";
$t++;
}
}
$j++;
}
if ($table == 'billing_rates') {
if ($this->settings['split_rating_table']) {
$rate_table_affected=array();
$query_r="select distinct (name) from billing_rates where". $where;
if ($this->db->query($query_r)) {
while($this->db->next_record()) {
$rate_tables_affected[]='billing_rates_'.$this->db->f('name');
}
} else {
printf ("<font color=red>Database error: %s (%s)</font>",$this->db->Error,$this->db->Errno);
}
}
}
$query = sprintf("update %s set %s where %s " ,
addslashes($table),
$update_set,
$where
);
if ($this->db->query($query)) {
$affected_rows=$this->db->affected_rows();
if ($affected_rows) {
if ($table == 'billing_rates') {
if ($this->settings['split_rating_table']) {
foreach ($rate_tables_affected as $extra_rate_table) {
$query_u = sprintf("update %s set %s where %s ",
$extra_rate_table,
$update_set,
$where
);
if (!$this->db->query($query_u)) {
printf ("<font color=red>Database error for %s: %s (%s)</font>",$query_u,$this->db->Error,$this->db->Errno);
}
}
}
}
if (in_array($table,$this->requireReload)) {
$this->db->query("update settings set var_value= '1' where var_name = 'reloadRating'");
}
}
} else {
printf ("<font color=red>Database error: %s</font>",$this->db->Error);
}
}
} elseif ($subweb_task == "Delete selection") {
if ($confirmDelete) {
// reconstruct where clause to apply all changes to selection
// build where clause
// Search build for each field
$where = $this->whereResellerFilter;
$j=0;
while ($j < $cc ) {
$Fname=$metadata[$j]['name'];
$size=$metadata[$j]['len'];
if (!in_array($Fname,$this->tables[$table]['exceptions'])) {
$f_name="search_".$Fname;
$value=$_REQUEST[$f_name];
if (preg_match("/^([<|>]+)(.*)$/",$value,$likes)) {
$like=$likes[1];
$likewhat=$likes[2];
$quotes="";
} else {
$like="like";
$likewhat=$value;
$quotes="'";
}
if (strlen($value)) {
$where .= " and $Fname $like $quotes".$likewhat."$quotes";
$t++;
}
}
$j++;
}
if ($table == 'billing_rates') {
if ($this->settings['split_rating_table']) {
$rate_table_affected=array();
$query_r="select distinct (name) from billing_rates where". $where;
if ($this->db->query($query_r)) {
while($this->db->next_record()) {
$rate_tables_affected[]='billing_rates_'.$this->db->f('name');
}
} else {
printf ("<font color=red>Database error: %s (%s)</font>",$this->db->Error,$this->db->Errno);
}
}
}
$query="delete from $table where $where";
if ($this->db->query($query)) {
$affected_rows=$this->db->affected_rows();
if ($affected_rows) {
if ($table == 'billing_rates') {
if ($this->settings['split_rating_table']) {
foreach ($rate_tables_affected as $extra_rate_table) {
$query_u = sprintf("delete from %s where %s ",
$extra_rate_table,
$where
);
if (!$this->db->query($query_u)) {
printf ("<font color=red>Database error for %s: %s (%s)</font>",$query_u,$this->db->Error,$this->db->Errno);
}
}
}
}
if (in_array($table,$this->requireReload)) {
$this->db->query("update settings set var_value= '1' where var_name = 'reloadRating'");
}
}
} else {
printf ("<font color=red>Database error: %s</font>",$this->db->Error);
}
unset($confirmDelete);
} else {
print "<p><font color=blue>";
print "Please confirm the deletion by pressing the Delete button again. ";
print "</font>";
print "<input type=hidden name=confirmDelete value=1>";
}
} elseif ($subweb_task == "Copy rate" && strlen($fromRate) && strlen($toRate)) {
$toRate=preg_replace("/%/","",$toRate);
if ($confirmCopy) {
if ($toRate == 'history') {
$values=sprintf("
(reseller_id,name,destination,application,connectCost,durationRate,connectCostIn,durationRateIn,startDate,endDate)
select
billing_rates.reseller_id,
'%s',
billing_rates.destination,
billing_rates.application,
billing_rates.connectCost,
billing_rates.durationRate,
billing_rates.connectCostIn,
billing_rates.durationRateIn,
NOW(),
NOW()
from billing_rates ",
addslashes($fromRate)
);
} else {
$values=sprintf("
(reseller_id,name,destination,application,connectCost,durationRate,connectCostIn,durationRateIn)
select
billing_rates.reseller_id,
'%s',
billing_rates.destination,
billing_rates.application,
billing_rates.connectCost,
billing_rates.durationRate,
billing_rates.connectCostIn,
billing_rates.durationRateIn
from billing_rates ",
addslashes($toRate)
);
}
$where = $this->whereResellerFilter;
$j=0;
while ($j < $cc ) {
$Fname=$metadata[$j]['name'];
$size=$metadata[$j]['len'];
if (!in_array($Fname,$this->tables[$table]['exceptions'])) {
$f_name="search_".$Fname;
$value=$_REQUEST[$f_name];
if (preg_match("/^([<|>]+)(.*)$/",$value,$likes)) {
$like=$likes[1];
$likewhat=$likes[2];
$quotes="";
} else {
$like="like";
$likewhat=$value;
$quotes="'";
}
if (strlen($value)) {
$where .= " and $Fname $like $quotes".$likewhat."$quotes";
$t++;
}
}
$j++;
}
if ($toRate == 'history') {
$query="insert into billing_rates_history $values where $where";
} else {
$query="insert into billing_rates $values where $where";
}
if ($this->db->query($query)) {
$affected_rows=$this->db->affected_rows();
if ($affected_rows) {
print "$affected_rows rates copied. ";
if ($table == 'billing_rates') {
if ($this->settings['split_rating_table']) {
$query=sprintf("create table billing_rates_%s select * from billing_rates where %s ",
$toRate,
$where
);
if (!$this->db->query($query)) {
printf ("<font color=red>Database error for %s: %s (%s)</font>",$query,$this->db->Error,$this->db->Errno);
}
}
}
if (in_array($table,$this->requireReload)) {
$this->db->query("update settings set var_value= '1' where var_name = 'reloadRating'");
}
}
if ($toRate == 'history') {
// Switch to history
$table = 'billing_rates_history';
// Init table structure
$this->tables[$table]['exceptions']= $this->tables[$table]['exceptions'];
$this->tables[$table]['keys'] = $this->tables[$table]['keys'];
$this->tables[$table]['fields'] = $this->tables[$table]['fields'];
$metadata = $this->db->metadata($table="$table");
$cc = count($metadata);
// end init table structure
}
unset($confirmCopy);
} else {
printf ("<font color=red>Database error: %s</font>",$this->db->Error);
}
$log_entity="rate=$toRate";
} else {
print "<p><font color=blue>";
print "Please confirm the copy of rate $fromRate to $toRate. ";
print "</font>";
}
} elseif ($subweb_task == "Insert") {
//print "<h3>Insert</h3>";
if ($this->checkValues($table,$_REQUEST)) {
$query=sprintf("insert into %s ( ",addslashes($table));
$k=1;
$kkk=0;
while ($k < $cc ) {
$Fname=$metadata[$k]['name'];
if (!in_array($Fname,$this->tables[$table]['exceptions']) ) {
if ($kkk > 0) {
$comma = ",";
} else {
$comma="";
}
$query .= $comma.addslashes($Fname);
$kkk++;
}
$k++;
}
$query .= ") values ( ";
$k=1;
$kkk=0;
while ($k < $cc ) {
$Fname=$metadata[$k]['name'];
$value=$_REQUEST[$Fname];
if (!in_array($Fname,$this->tables[$table]['exceptions']) ) {
if ($kkk > 0) {
$comma = ",";
} else {
$comma="";
}
if ($Fname == 'reseller_id' && $this->CDRTool['filter']['reseller']) {
$query .= $comma."'".addslashes($this->CDRTool['filter']['reseller'])."'";
} else {
$query .= $comma."'".addslashes($value)."'";
}
$kkk++;
}
$k++;
}
$query .= ") ";
$k=1;
while ($k < $cc ) {
$Fname=$metadata[$k]['name'];
$value=$_REQUEST[$Fname];
if (in_array($Fname,$this->tables[$table]['keys']) ) {
if ($value == "") {
$Fname_print_insert=substr($Fname,4);
print "$Fname_print_insert = ???? <br>";
$empty_insert=1;
}
}
$k++;
}
if (!$empty_insert) {
if ($this->db->query($query)) {
$affected_rows=$this->db->affected_rows();
if ($affected_rows) {
$this->db->query("select LAST_INSERT_ID() as lid");
$this->db->next_record();
$log_entity=sprintf("id=%s",$this->db->f('lid'));
if (in_array($table,$this->requireReload)) {
$this->db->query("update settings set var_value= '1' where var_name = 'reloadRating'");
}
}
} else {
printf ("<font color=red>Database error for query %s: %s (%s)</font>",$query,$this->db->Error,$this->db->Errno);
}
} else {
print "<font color=red>
Error: The insert statement contains an empty key!
</font>
";
}
} else {
print "<p>Correct the values and try again.";
}
} elseif ($subweb_task == "Delete") {
if ($confirmDelete) {
$query=sprintf("delete from %s where id = '%s' and %s ",addslashes($table), addslashes($id), $this->whereResellerFilter);
if ($this->db->query($query)) {
$affected_rows=$this->db->affected_rows();
if ($affected_rows && in_array($table,$this->requireReload)) {
$this->db->query("update settings set var_value= '1' where var_name = 'reloadRating'");
}
$log_entity=sprintf("id=%s",$id);
} else {
printf ("<font color=red>Database error: %s</font>",$this->db->Error);
}
unset($confirmDelete);
} else {
$idForDeletion=$id;
print "<p><font color=blue>";
print "Please confirm the deletion by pressing the Delete button again. ";
print "</font>";
print "<input type=hidden name=confirmDelete value=1>";
}
} elseif ($subweb_task == "Delete session" && $sessionId && $table=='prepaid') {
$query=sprintf("select active_sessions from %s where id = %d and %s",addslashes($table),addslashes($id),$this->whereResellerFilter);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
}
if (!$this->db->num_rows()) return;
$this->db->next_record();
if (strlen($this->db->f('active_sessions'))) {
// remove session
$active_sessions=array();
$old_active_sessions = json_decode($this->db->f('active_sessions'),true);
if (!count($old_active_sessions)) return;
foreach (array_keys($old_active_sessions) as $_key) {
if ($_key==$sessionId) continue;
$active_sessions[$_key]=$old_active_sessions[$_key];
}
} else {
$active_sessions=array();
}
$query=sprintf("update %s
set active_sessions = '%s',
session_counter = %d
where id = %d",
addslashes($table),
addslashes(json_encode($active_sessions)),
count($active_sessions),
addslashes($id)
);
if ($this->db->query($query)) {
return 1;
} else {
$log=sprintf ("Database error for %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
print $log;
return 0;
}
}
if ($affected_rows && $table!="prepaid") {
$log_query=sprintf("insert into log
(date,login,ip,datasource,results,description,reseller_id)
values (NOW(),'%s','%s','Rating','%d','%s in table %s %s',%d)",
addslashes($loginname),
addslashes($_SERVER['REMOTE_ADDR']),
addslashes($affected_rows),
addslashes($subweb_task),
addslashes($table),
addslashes($log_entity),
addslashes($this->CDRTool['filter']['reseller'])
);
$this->db->query($log_query);
}
}
}
function showTable() {
$PHP_SELF=$_SERVER['PHP_SELF'];
foreach ($this->web_elements as $_el) {
${$_el}= $_REQUEST[$_el];
}
if ($this->table == 'prepaid_cards') {
print "<p>
<a href=prepaid_cards.phtml>Prepaid card generator</a>";
}
// Init table structure
if (!is_array($this->tables[$this->table]['exceptions'])) $this->tables[$this->table]['exceptions']=array();
if (!is_array($this->tables[$this->table]['keys'])) $this->tables[$this->table]['keys']=array();
if (!is_array($this->tables[$this->table]['fields'])) $this->tables[$this->table]['fields']=array();
if ($this->table=='prepaid' && strlen($_REQUEST['search_session_counter'])) {
$this->readonly=true;
}
if ($this->readonly) {
$this->tables[$this->table]['readonly']=1;
}
$metadata = $this->db->metadata($this->table);
$cc = count($metadata);
// end init table structure
// delimiter for exporting records
if ($this->settings['csv_delimiter']) {
$delimiter=$this->settings['csv_delimiter'];
} else {
$delimiter=",";
}
$query=sprintf("select count(*) as c from %s where %s",
addslashes($this->table),
$this->whereResellerFilter);
$t=0;
$j=0;
while ($j < $cc ) {
$Fname=$metadata[$j]['name'];
$size=$metadata[$j]['len'];
$class=$metadata[$j]['class'];
if (!in_array($Fname,$this->tables[$this->table]['exceptions'])) {
$f_name="search_".$Fname;
$value=$_REQUEST[$f_name];
if (preg_match("/^([<|>]+)(.*)$/",$value,$likes)) {
$like=$likes[1];
$likewhat=$likes[2];
$quotes="";
} else {
$like="like";
$likewhat=$value;
$quotes="'";
}
if (strlen($value)) {
$where.=sprintf(" and %s %s %s%s%s ", addslashes($Fname),$like, $quotes, addslashes($likewhat),$quotes);
$t++;
}
}
$j++;
}
$query .= $where;
$this->db->query($query);
$this->db->next_record();
$rows=$this->db->Record['c'];
if (!$export) {
print "
<table border=0 align=center>
<tr><td colspan=\"2\">
";
if ($rows == 0) {
print "No records found. ";
} else {
print "$selectie $rows records found. ";
}
if ($this->settings['socketIPforClients'] && $this->settings['socketPort']) {
$engineAddress=$this->settings['socketIPforClients'].":".$this->settings['socketPort'];
if ($this->checkRatingEngineConnection()) {
print " | <span class=\"label label-success\">Rating engine running at $engineAddress</span>";
} else {
print " | <span class=\"label label-important\">Cannot connect to rating engine $engineAddress</span>";
}
}
print " | <a href=doc/RATING.txt target=rating_help>Rating documentation</a>";
print "
</td>
</tr> ";
if ($this->csv_import[$this->table]) {
print "<td style='text-align: center; padding-top:5px'>
<form class='form-inline' action=$PHP_SELF method='post' enctype='multipart/form-data'>
<input type=hidden name=import value=1>
";
printf ("
<input type='hidden' name=table value=%s>
<input type='hidden' name='MAX_FILE_SIZE' value=1024000>
<div class='fileupload fileupload-new' style='display: inline-block; margin-bottom:0px' data-provides='fileupload'>
<div class='input-append'>
<div class='uneditable-input input-small'>
<span class='fileupload-preview'></span>
</div>
<span class='btn btn-file'>
<span class='fileupload-new'>Select file</span>
<span class='fileupload-exists'>Change</span>
<input type='file' name='%s'/></span>
<a href='#' class='btn fileupload-exists' data-dismiss='fileupload'>Remove</a>
<button type='submit' class='btn fileupload-exists' value=\"Import\"><i class='icon-upload'></i> Import</button>
</div>
</div>
",$this->table,$this->table
);
print "</form><td style='padding-top:5px'>
";
} else {
print "<td style='padding-top:5px; text-align: center' colspan=\"2\">";
}
print "<form class='form-inline' action=$PHP_SELF method=post target=export>
<input type=hidden name=export value=1>
";
$j=0;
while ($j < $cc ) {
$Fname=$metadata[$j]['name'];
$size=$metadata[$j]['len'];
if (!in_array($Fname,$this->tables[$this->table]['exceptions'])) {
$SEARCH_NAME="search_".$Fname;
$value=$_REQUEST[$SEARCH_NAME];
print "<input type=hidden name=search_$Fname value=\"$value\">";
}
$j++;
}
if ($this->table!=='prepaid_cards' ) {
printf ("
<input type=hidden name=table value=%s>
<button class=btn type=submit value=\"Export %s\"><i class=icon-file></i> Export %s</button>
",$this->table,$this->csv_export[$this->table],$this->csv_export[$this->table]);
}
if ($this->settings['socketIPforClients'] && $this->settings['socketPort']) {
if ($ReloadRatingTables) {
reloadRatingEngineTables();
} else {
$this->db->query("select var_value from settings where var_name = 'reloadRating' and var_value='1'");
if ($this->db->num_rows()) {
print "<a class='btn btn-danger' href=rating_tables.phtml?ReloadRatingTables=1&table=$this->table>Reload rating tables</a>";
}
}
}
print "</form></td>
</tr>
</table>
";
} else {
$this->maxrowsperpage=10000000;
}
if (!$next) {
$i=0;
$next=0;
} else {
- $i=$next;
+ $i=intval($next);
}
$j=0;
$z=0;
if ($rows > $this->maxrowsperpage) {
$maxrows=$this->maxrowsperpage+$next;
if ($maxrows > $rows) {
$maxrows=$rows;
$prev_rows=$maxrows;
}
} else {
$maxrows=$rows;
}
if (!$order && $this->tables[$this->table]['order']) {
$order=sprintf(" order by %s ",addslashes($this->tables[$this->table]['order']));
}
$query=sprintf("select * from %s where (1=1) %s and %s %s limit %d, %d",
addslashes($this->table),
$where,
$this->whereResellerFilter,
$order,
- $i,
- $this->maxrowsperpage
+ intval($i),
+ intval($this->maxrowsperpage)
);
$this->db->query($query);
$num_fields=$this->db->num_fields();
$k=0;
if (!$export) {
if ($this->table=='prepaid') {
print "
<table class='table-hover table table-condensed' id='rates_table' align=center width=100%>
<thead>
<tr>
<th></th>";
} else {
print "
<table class='table-hover table table-condensed table-striped' id='rates_table' align=center width=100%>
<thead>
<tr>
<th></th>
";
}
}
while ($k < $cc) {
$th=$metadata[$k]['name'];
if (!in_array($th,$this->tables[$this->table]['exceptions']) ) {
if ($this->tables[$this->table]['fields'][$th]['name']) {
$th=$this->tables[$this->table]['fields'][$th]['name'];
} else {
$th=ucfirst($th);
}
if (!$export) {
print "<th>$th</th>";
} else {
if ($k) {
printf ("%s%s",$delimiter,$th);
} else {
print "Ops";
}
}
$t_columns++;
}
$k++;
}
if ($export) {
print "\n";
}
if (!$export) {
print "
<th>Action</th>
</tr>";
$t_columns=$t_columns+2;
// SEARCH FORM
print "
<tr>
<td colspan=$t_columns>
Use _ to match one character and % to match any. Use > or <
to find greater or smaller values.</td>
</tr>
";
// Search form
print "
<form class='form-inline' style='display:none' action=$PHP_SELF method=post name=rating>
<input type=hidden name=web_task value=Search>
<tr>
<td>&nbsp;</td>";
$j=0;
while ($j < $cc ) {
$Fname=$metadata[$j]['name'];
$size=$metadata[$j]['len'];
if (!in_array($Fname,$this->tables[$this->table]['exceptions'])) {
$SEARCH_NAME="search_".$Fname;
$value=$_REQUEST[$SEARCH_NAME];
if ($value != "") {
$selection_made=1;
}
$maxlength=$size;
if ($this->tables[$this->table]['fields'][$Fname]['size']) {
$field_size=$this->tables[$this->table]['fields'][$Fname]['size'];
} else {
$field_size=$el_size;
}
$class=$this->tables[$this->table]['fields'][$Fname]['class'];
if (!in_array($Fname,$this->tables[$this->table]['keys']) ) {
if (!$class) {
$class="span1";
}
print "<td><input class=$class type=text size=$field_size maxlength=$maxlength name=search_$Fname value=\"$value\"></td>";
} else {
print "<td></td>";
}
}
$j++;
}
printf("
<script type=\"text/JavaScript\">
function jumpMenu(){
location.href=\"%s?table=\" + document.rating.table.options[document.rating.table.selectedIndex].value;
}
</script>",
$PHP_SELF
);
print "
<td>
";
printf("<div class='input-append'><select class='span3' name='table' onChange=\"jumpMenu('this.form')\">\n");
$selected_table[$this->table]="selected";
foreach (array_keys($this->tables) as $tb) {
$sel_name=$this->tables[$tb]['name'];
print "<option value=$tb $selected_table[$tb]>$sel_name";
}
print "
</select><input class='btn btn-primary' type=submit name=subweb_task value=Search></div>
</form>";
print "
</td>
</tr></thead>
";
//print "
//<tr>
//<td colspan=$t_columns><hr noshade size=2></td>
//</tr>
//";
if ($selection_made && !$this->tables[$this->table]['readonly']) {
// Update all form
print "
<tr><td colspan=$t_columns>
Use + or - to add/substract from curent values.
Use * or / to multiply/divide curent values.</td>
</tr>";
$j=0;
print "
<form class='form-inline' action=$PHP_SELF method=post>
<input type=hidden name=web_task value=update>
<input type=hidden name=next value=$next>
<tr>
<td>&nbsp;</td>";
while ($j < $cc ) {
$Fname=$metadata[$j]['name'];
$size=$metadata[$j]['len'];
if ($this->tables[$this->table]['fields'][$Fname]['size']) {
$field_size=$this->tables[$this->table]['fields'][$Fname]['size'];
} else {
$field_size=$el_size;
}
$class=$this->tables[$this->table]['fields'][$Fname]['class'];
if (!in_array($Fname,$this->tables[$this->table]['exceptions'])) {
if (!in_array($Fname,$this->tables[$this->table]['keys']) ) {
if (!$class) {
$class="span1";
}
print "<td><input class='$class' type=text size=$field_size maxlength=$size name=$Fname></td>";
} else {
print "<td></td>";
}
}
$j++;
}
$j=0;
while ($j < $cc ) {
$Fname=$metadata[$j]['name'];
$size=$metadata[$j]['len'];
if (!in_array($Fname,$this->tables[$this->table]['exceptions'])) {
$SEARCH_NAME="search_".$Fname;
$value=$_REQUEST[$SEARCH_NAME];
print "<input type=hidden name=search_$Fname value=\"$value\">";
}
$j++;
}
if ($subweb_task=="Delete selection" && !$confirmDelete) {
print "<td>";
print "<input type=hidden name=confirmDelete value=1>";
print "<input class='btn btn-danger' type=submit name=subweb_task value=\"Delete selection\">";
print " ($rows records)";
} else if (!$this->tables[$this->table]['readonly']){
if ($this->table == "billing_rates" && strlen($_REQUEST['search_name'])) {
if ($subweb_task=="Copy rate" && !$confirmCopy) {
print "<td>";
print "<input type=hidden name=confirmCopy value=1>";
} else {
print "<td>";
print "<div class=\"btn-group\">
<input class='btn' type=submit name=subweb_task value=\"Update selection\">
<input class='btn btn-danger' type=submit name=subweb_task value=\"Delete selection\">
</div>
";
}
print "
<input type=submit name=subweb_task value=\"Copy rate\">";
printf (" id %s to",$_REQUEST['search_name']);
$query=sprintf("select distinct(name) as name
from billing_rates where
name like '%s'
order by name DESC
limit 1",addslashes($_REQUEST['search_name']));
$this->db1->query($query);
$this->db1->next_record();
$_rateName=$this->db1->f('name');
$_rateName=preg_replace("/%/","",$_rateName);
if (preg_match("/^(.*)_(\d+)$/",$_rateName,$m)) {
$_idx=$m[2]+1;
$newRateName=$m[1]."_".$_idx;
} else {
$newRateName=$_rateName."_1";
}
printf ("<input type=hidden name=fromRate value=\"%s\">",$_REQUEST['search_name']);
$selected_newtable[$toRate]='selected';
printf ("<select name=toRate>
<option value=\"%s\" %s>Rate id %s
<option value=history %s>Rate history table
</select>",
$newRateName,
$selected_newtable[$newRateName],
$newRateName,
$selected_newtable['history']
);
} else {
print "<td>";
print "<div class=\"btn-group\">
<input class='btn' type=submit name=subweb_task value=\"Update selection\">
<input class='btn btn-danger' type=submit name=subweb_task value=\"Delete selection\">
</div>";
}
}
print "
<td>
<input type=hidden name=table value=$this->table>
<input type=hidden name=search_text value=\"$search_text\">
</td>
</tr></thead>
</form>
";
} else if (!$this->tables[$this->table]['readonly']){
// Insert form
$j=0;
print "
<form style='display:none' action=$PHP_SELF method=post>
<input type=hidden name=web_task value=update>
<input type=hidden name=next value=$next>
<tr>
<td>&nbsp; </td>
";
while ($j < $cc ) {
$Fname=$metadata[$j]['name'];
$size=$metadata[$j]['len'];
if ($this->tables[$this->table]['fields'][$Fname]['size']) {
$field_size=$this->tables[$this->table]['fields'][$Fname]['size'];
} else {
$field_size=$el_size;
}
$class=$this->tables[$this->table]['fields'][$Fname]['class'];
if (!in_array($Fname,$this->tables[$this->table]['exceptions'])) {
if (!in_array($Fname,$this->tables[$this->table]['keys']) ) {
if (!$class){
$class='span1';
}
print "<td><input class='$class' type=text size=$field_size maxlength=$size name=$Fname></td>";
} else {
print "<td></td>";
}
}
$j++;
}
$j=0;
while ($j < $cc ) {
$Fname=$metadata[$j]['name'];
$size=$metadata[$j]['len'];
if (!in_array($Fname,$this->tables[$this->table]['exceptions'])) {
$SEARCH_NAME="search_".$Fname;
$value=$_REQUEST[$SEARCH_NAME];
print "<input type=hidden name=search_$Fname value=\"$value\">";
}
$j++;
}
print "
<td>
<input type=hidden name=table value=\"$this->table\">
<input type=hidden name=search_text value=\"$search_text\">
<input class='btn btn-warning' type=submit name=subweb_task value=Insert>
</td>
</tr></thead>
</form>
";
//print "
//<tr>
//<td colspan=$t_columns><hr noshade size=2></td>
//</tr>
//";
}
}
while ($i<$maxrows) {
$this->db->next_record();
$id = $this->db->f('id');
$status = $this->db->f('status');
$found = $i+1;
if (!$export) {
print "
<form style='display:none' action=$PHP_SELF method=post>
<input type=hidden name=web_task value=update>
<input type=hidden name=next value=$next>
<input type=hidden name=id value=$id>
<tr>
";
if ($this->table == 'prepaid') {
$active_sessions = json_decode($this->db->f('active_sessions'),true);
$account=$this->db->f('account');
$extraInfo="
<table border=0 bgcolor=#CCDDFF cellpadding=0 cellspacing=0>
<form action=$PHP_SELF method=post>
<input type=hidden name=web_task value=update>
<input type=hidden name=next value=$next>
<input type=hidden name=id value=$id>
<tr>
<td valign=top>
<table border=0>
";
$t=0;
foreach (array_keys($active_sessions) as $_session) {
$t++;
$maxsessiontime=$active_sessions[$_session]['MaxSessionTime'];
$extraInfo.=sprintf ("<tr bgcolor=lightgrey><td class=border>%d. Session id</td><td>%s</td></tr>",$t,$_session);
$duration=time()-$active_sessions[$_session]['timestamp'];
foreach (array_keys($active_sessions[$_session]) as $key) {
if ($key=='timestamp') {
$extraInfo.= sprintf ("<tr><td class=border><b>StartTime</b></td><td>%s</td></tr>",Date("Y-m-d H:i",$active_sessions[$_session]['timestamp']));
$extraInfo.= sprintf ("<tr><td class=border><b>Progress</b></td><td>%s (%s s)</td></tr>",sec2hms($duration),$duration);
} else {
$extraInfo.= sprintf ("<tr><td class=border><b>%s</b></td><td>%s</td></tr>",ucfirst($key),$active_sessions[$_session][$key]);
}
}
if ($maxsessiontime < $duration ) {
$extraInfo.= sprintf ("<tr><td class=border colspan=2><font color=red><b>Session expired since %d s</b></font></td></tr>",$duration-$maxsessiontime);
$extraInfo.= sprintf("<tr><td colspan=2><input type=submit name=subweb_task value='Delete session'></td></tr>");
}
//if (!$this->readonly) {
//}
}
$extraInfo.=sprintf("
<input type=hidden name=table value='%s'>
<input type=hidden name=next value='%s'>
<input type=hidden name=sessionId value='%s'>
<input type=hidden name=search_text value='%s'>
</form>
</table>
</td>
</tr>
</table>",
$this->table,$next,$_session,$search_text
);
}
print "
<td>$found. </td>
";
}
$j=0;
while ($j < $this->db->num_fields()) {
$value=$this->db->Record[$metadata[$j]['name']];
$Fname=$metadata[$j]['name'];
$size=$metadata[$j]['len'];
$class=$metadata[$j]['class'];
if ($this->tables[$this->table]['fields'][$Fname]['size']) {
$field_size=$this->tables[$this->table]['fields'][$Fname]['size'];
} else {
$field_size=$el_size;
}
$class=$this->tables[$this->table]['fields'][$Fname]['class'];
if ($this->tables[$this->table]['fields'][$Fname]['readonly']=="1") {
$extra_form_els="disabled=true";
} else {
$extra_form_els="";
}
$class=$this->tables[$this->table]['fields'][$Fname]['class'];
if (!in_array($Fname,$this->tables[$this->table]['exceptions'])) {
if (!$export) {
if (!in_array($Fname,$this->tables[$this->table]['keys']) && !$this->readonly) {
if ($this->table == 'prepaid' && $Fname == 'session_counter' && $value) {
if (count($active_sessions) > 1) {
$session_counter_txt=sprintf("%d sessions",$value);
} else {
$session_counter_txt=sprintf("%d session",$value);
}
printf("<td onClick=\"return toggleVisibility('row%s')\"><a href=#>%s</td>",$found,$session_counter_txt);
} else {
if (!$class) {
$class="span1";
}
print "<td>
<input class='$class' type=text bgcolor=grey size=$field_size maxlength=$size name=$Fname value=\"$value\" $extra_form_els>
</td>";
}
} else {
if ($this->table == 'prepaid' && $Fname == 'session_counter' && $value) {
if (count($active_sessions) > 1) {
$session_counter_txt=sprintf("%d sessions",$value);
} else {
$session_counter_txt=sprintf("%d session",$value);
}
printf("<td onClick=\"return toggleVisibility('row%s')\"><a href=#>%s</td>",$found,$session_counter_txt);
} else {
print "<td>$value</td>";
}
}
} else {
if ($j) {
printf ("%s%s",$delimiter,$value);
} else {
print "2";
}
}
}
$j++;
}
$j=0;
while ($j < $cc ) {
$Fname=$metadata[$j]['name'];
$size=$metadata[$j]['len'];
if (!in_array($Fname,$this->tables[$this->table]['exceptions'])) {
$SEARCH_NAME="search_".$Fname;
$value=$_REQUEST[$SEARCH_NAME];
if (!$export) {
print "<input type=hidden name=search_$Fname value=\"$value\">";
}
}
$j++;
}
if ($export) {
print "\n";
}
if (!$export) {
if (!$this->tables[$this->table]['readonly']) {
if ($subweb_task=="Delete" && $idForDeletion == $id && !$confirmDelete) {
print "<td class=border bgcolor=lightgrey>";
print "<input type=hidden name=confirmDelete value=1>";
print "<input type=submit name=subweb_task value=Delete>";
} else {
print "
<td class=border>
<div class=\"btn-group\">
<input class='btn' type=submit name=subweb_task value=Update>
<input class='btn btn-danger' type=submit name=subweb_task value=Delete></div>
";
print "<input type=hidden name=confirmDelete value=1>";
}
print "
<input type=hidden name=table value=$this->table>
<input type=hidden name=next value=$next>
<input type=hidden name=search_text value=\"$search_text\">
</td>
</tr>
</form>";
if ($extraInfo!='') {
print "
<tr style='display:none' id='row$found'>
<td></td>
<td colspan=$t_columns>$extraInfo</td>
</tr>
";
}
} else {
if ($this->table=='prepaid') {
print "
<tr style='display:none' id='row$found'>
<td></td>
<td colspan=$t_columns>$extraInfo</td>
</tr>
";
}
}
}
$i++;
}
if (!$export) {
print "</form>
</table>
";
print "
<form class=form-inline id=prev method=post>
";
if ($next!= 0 ) {
$show_next=$this->maxrowsperpage-$next;
if ($show_next<0) {
$mod_show_next = $show_next-2*$show_next;
}
print "
<input style=\"display:none\" type=hidden name=maxrowsperpage value=$this->maxrowsperpage>
<input type=hidden name=next value=$mod_show_next>
<input type=hidden name=web_task value=Search>
<input type=hidden name=table value=$this->table>
<input type=hidden name=search_text value=\"$search_text\">
";
$j=0;
while ($j < $cc ) {
$Fname=$metadata[$j]['name'];
$size=$metadata[$j]['len'];
if (!in_array($Fname,$this->tables[$this->table]['exceptions'])) {
$SEARCH_NAME="search_".$Fname;
$value=$_REQUEST[$SEARCH_NAME];
print "<input type=hidden name=search_$Fname value=\"$value\">
";
}
$j++;
}
}
print "
</form>
<form class=form-inline id=next method=post>
";
if ($rows>$this->maxrowsperpage && $rows!=$maxrows) {
$show_next=$this->maxrowsperpage+$next;
print "
<input type=hidden name=maxrowsperpage value=$this->maxrowsperpage>
<input type=hidden name=next value=$show_next>
<input type=hidden name=table value=$this->table>
<input type=hidden name=web_task value=Search>
";
$j=0;
while ($j < $cc ) {
$Fname=$metadata[$j]['name'];
$size=$metadata[$j]['len'];
if (!in_array($Fname,$this->tables[$this->table]['exceptions'])) {
$SEARCH_NAME="search_".$Fname;
$value=$_REQUEST[$SEARCH_NAME];
print "<input type=hidden name=search_$Fname value=\"$value\">";
}
$j++;
}
print "
<input type=hidden name=search_text value=\"$search_text\">
";
}
print "
</form>
<ul class=\"pager\">";
if ($next!= 0 ) {
print "
<li><a href=\"javascript:document.forms['prev'].submit()\">&larr; Previous</a></li>";
}
if ($rows>$this->maxrowsperpage && $rows!=$maxrows) {
print "
<li><a href=\"javascript:document.forms['next'].submit()\">Next &rarr;</a></li>";
}
print "</ul>";
print "
</body>
</html>
";
}
}
function checkValues($table,$values=array()) {
if (!$table) return false;
$metadata = $this->db->metadata($table);
if (!is_array($metadata)) return false;
$k=1;
while ($k < count($metadata)) {
$db_name = $metadata[$k]['name'];
$k++;
$web_name = $this->tables[$table]['fields'][$db_name]['name'];
$value = $values[$db_name];
$checkType = $this->tables[$table]['fields'][$db_name]['checkType'];
$mustExist = $this->tables[$table]['fields'][$db_name]['mustExist'];
if ($web_name) {
$name_print=$web_name;
} else {
$name_print=$db_name;
}
if ($mustExist) {
if (!strlen($value)) {
printf ("Error: field '%s' must be filled in\n",$name_print);
return false;
}
}
if ($checkType) {
if (!strlen($value)) {
if (!$mustExist) continue;
}
if ($checkType == 'sip_account') {
if (!checkEmail($value)) {
printf ("Error: value '%s' for field '%s' must be of format 'user@domain'\n",$value,$name_print);
return false;
}
}
if ($checkType == 'domain') {
if (stristr($value,"-.") || !preg_match("/^([a-zA-Z0-9][a-zA-Z0-9-]*\.)+[a-zA-Z]{2,}$/i",$value)) {
printf ("Error: value '%s' for field '%s' must be of format 'example.com'\n",$value,$name_print);
return false;
}
}
if ($checkType == 'ip') {
if (!preg_match("/^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i",$value,$m)) {
printf ("Error: value '%s' for field '%s' must be of format 'X.X.X.X'\n",$value,$name_print);
return false;
} else {
$i=1;
while ($i<=4) {
if ($m[$i] < 0 || $m[$i] > 255) {
printf ("Error: value '%s' for field '%s' must be of a valid IP address\n",$value,$name_print);
return false;
}
$i++;
}
}
}
if ($checkType == 'numeric') {
if (!is_numeric($value)) {
printf ("Error: value '%s' for field '%s' must be of type '%s'\n",$value,$name_print,$checkType);
return false;
}
}
}
}
return true;
}
function importTable($table='') {
// import a table from web
if (!is_array($_FILES[$table]) || $_FILES[$table]['size'] == 0) return false;
foreach ($this->importFilesPatterns as $_pattern) {
if (strstr($_FILES[$table]['name'],$_pattern) && preg_match("/\.csv$/",$_FILES[$table]['name'])) {
if ($this->CDRTool['filters']['reseller']) {
$dir=$this->cvs_import_dir.'/'.$this->CDRTool['filters']['reseller'];
if (!is_dir($dir)) {
if (!mkdir($dir)) {
printf ("<font color=red>Error: cannot create directory %s</font>",$dir);
return false;
}
}
$fullPath=$this->cvs_import_dir.'/'.$this->CDRTool['filters']['reseller'].'/'.$_FILES[$table]['name'];
} else {
$fullPath=$this->cvs_import_dir.'/'.$_FILES[$table]['name'];
}
if (!is_file($fullPath)) {
if ($fp = fopen($fullPath, "w")) {
} else {
printf ("<font color=red>Error: cannot open file %s for writing</font>",$fullPath);
return false;
}
} else {
list($basename,$extension)=explode('.',$_FILES[$table]['name']);
$j=0;
while (1) {
$j++;
if ($this->CDRTool['filters']['reseller']) {
$fullPath=$this->cvs_import_dir.'/'.$this->CDRTool['filters']['reseller'].'/'.$basename.'-'.$j.'.'.$extension;
} else {
$fullPath=$this->cvs_import_dir.'/'.$basename.'-'.$j.'.'.$extension;
}
if (is_file($fullPath)) continue;
if ($fp = fopen($fullPath, "w")) {
break;
} else {
printf ("<font color=red>Error: cannot open file %s for writing</font>",$fullPath);
return false;
}
}
}
$content=fread(fopen($_FILES[$table]['tmp_name'], "r"), $_FILES[$table]['size']);
fwrite($fp,$content);
fclose($fp);
printf ("<p><font color=green>Imported %s bytes into %s</font>",$_FILES[$table]['size'],$fullPath);
break;
}
}
}
}
class OpenSIPSQuota {
var $localDomains = array();
var $quotaGroup = 'quota'; // group set if subscriber was blocked by quota
var $timeout = 5; // soap connection timeout
var $daily_quota = 0; // by default do not check daily quota
function OpenSIPSQuota($parent) {
global $DATASOURCES;
$this->CDRdb = $parent->CDRdb;
$this->table = $parent->table;
$this->CDRTool = $parent->CDRTool;
$this->cdr_source = $parent->cdr_source;
$this->path=$this->CDRTool['Path'];
$this->db_subscribers = $parent->db_subscribers;
if (!class_exists($this->db_subscribers)) {
printf("Info: No database defined for SIP accounts for source '%s'.\n", $this->cdr_source);
return false;
}
$this->AccountsDB = new $this->db_subscribers;
$this->enableThor = $parent->enableThor;
$parent->LoadDomains();
$this->localDomains = $parent->localDomains;
$this->cdr_source = $parent->cdr_source;
$this->BillingPartyIdField = $parent->CDRFields['BillingPartyId'];
$this->parent = $parent;
$this->db = new DB_cdrtool;
$this->db->Halt_On_Error="no";
$this->db1 = new DB_cdrtool;
$this->db1->Halt_On_Error="no";
$this->db1 = new DB_cdrtool;
$this->db1->Halt_On_Error="no";
$this->CDRS = $parent;
$this->quota_init_flag = $parent->quota_init_flag;
$this->quota_reset_flag = $parent->quota_reset_flag;
if ($parent->daily_quota && is_numeric($parent->daily_quota) && $parent->daily_quota > 1 && $parent->daily_quota < 100) {
$this->daily_quota = $parent->daily_quota;
}
// load e-mail addresses for quota notifications
$query="select * from settings where var_module = 'notifications'";
if ($this->db->query($query) && $this->db->num_rows()) {
while ($this->db->next_record()) {
$_bp =$this->db->f('billing_party');
$_name =$this->db->f('var_name');
$_value =$this->db->f('var_value');
if ($_bp && $_name && $_value) {
$this->notificationAddresses[$_bp][$_name]=$_value;
}
}
}
if ($DATASOURCES[$this->cdr_source]['soapEngineId']) {
require("/etc/cdrtool/ngnpro_engines.inc");
require_once("ngnpro_soap_library.php");
if (in_array($DATASOURCES[$this->cdr_source]['soapEngineId'],array_keys($soapEngines))) {
$this->SOAPurl = $soapEngines[$DATASOURCES[$this->cdr_source]['soapEngineId']]['url'];
$log=sprintf("Using SOAP engine %s to block accounts at %s\n",$DATASOURCES[$this->cdr_source]['soapEngineId'],$this->SOAPurl);
syslog(LOG_NOTICE, $log);
$this->SOAPlogin = array(
"username" => $soapEngines[$DATASOURCES[$this->cdr_source]['soapEngineId']]['username'],
"password" => $soapEngines[$DATASOURCES[$this->cdr_source]['soapEngineId']]['password'],
"admin" => true
);
$this->SoapAuth=array('auth', $this->SOAPlogin , 'urn:AGProjects:NGNPro', 0, '');
$this->soapclient = new WebService_NGNPro_SipPort($this->SOAPurl);
$this->soapclient->setOpt('curl', CURLOPT_SSL_VERIFYPEER, 0);
$this->soapclient->setOpt('curl', CURLOPT_SSL_VERIFYHOST, 0);
$this->soapclient->_options['timeout'] = $this->timeout;
} else {
$e=$DATASOURCES[$this->cdr_source]['soapEngineId'];
$log=sprintf("Error: soap engine id $e not found in /etc/cdrtool/ngnpro_engines.inc\n");
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
} else {
$log=sprintf("Using database queries to block accounts\n");
syslog(LOG_NOTICE, $log);
}
}
function ShowAccountsWithQuota($treshhold='') {
$query=sprintf("select * from quota_usage where datasource = '%s' and quota > 0 and cost > 0",addslashes($this->CDRS->cdr_source));
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
while ($this->db->next_record()) {
if ($this->db->f('blocked')) {
$blockedStatus="blocked";
} else {
$blockedStatus='';;
}
$usageRatio=$this->db->f('cost')*100/$this->db->f('quota');
if ($treshhold && $treshhold > $usageRatio) continue;
$usageStatus=sprintf("usage=%-10s",$this->db->f('cost'));
printf ("%-35s quota=%-6s %s %.2f%s %s\n",
$this->db->f('account'),
$this->db->f('quota'),
$usageStatus,
$usageRatio,
'%',
$blockedStatus
);
}
}
function deblockAccounts($reset_quota_for=array()) {
// deblock users blocked by quota
if (!$this->db_subscribers) {
print("Info: No database defined for SIP accounts.\n");
return false;
}
if (!count($reset_quota_for)) {
printf("Deblocking all SIP accounts blocked by quota\n");
} else {
printf("Deblocking %d SIP accounts blocked by quota\n",count($reset_quota_for));
}
if ($this->enableThor) {
$query=sprintf("select username, domain, profile from sip_accounts where (1=1) ");
if (count($reset_quota_for)) {
$k=0;
foreach ($reset_quota_for as $_account) {
if ($k) $usage_keys.= ", ";
$usage_keys.="'".addslashes($_account)."'";
$k++;
}
$query.= "and CONCAT(username,'@',domain) in (".$usage_keys.")";
}
if (!$this->AccountsDB->query($query)) {
$log=sprintf("Error: %s (%s)",$this->AccountsDB->Error,$this->AccountsDB->Errno);
syslog(LOG_NOTICE,$log);
return false;
}
while ($this->AccountsDB->next_record()) {
$i++;
$_account=$this->AccountsDB->f('username')."@".$this->AccountsDB->f('domain');
$_profile=json_decode(trim($this->AccountsDB->f('profile')));
if (in_array('quota',$_profile->groups)) {
$blockedAccounts[]=$_account;
}
if ($i%5000 == 0) {
print "$i accounts checked for deblocking\n";
flush();
}
}
if ($i) {
print "$i accounts checked for deblocking\n";
flush();
}
} else {
$query=sprintf("select CONCAT(username,'@',domain) as account from grp where grp = '%s'",$this->quotaGroup);
if (count($reset_quota_for)) {
$k=0;
foreach ($reset_quota_for as $_account) {
if ($k) $usage_keys.= ", ";
$usage_keys.="'".addslashes($_account)."'";
$k++;
}
$query.= "and CONCAT(username,'@',domain) in (".$usage_keys.")";
}
if (!$this->AccountsDB->query($query)) {
$log=sprintf ("Database error: %s (%s)",$this->AccountsDB->Error,$this->AccountsDB->Errno);
print $log;
syslog(LOG_NOTICE,$log);
return false;
}
$blockedAccounts=array();
while ($this->AccountsDB->next_record()) {
$i++;
$blockedAccounts[]=$this->AccountsDB->f('account');
if ($i%10000 == 0) {
print "$i accounts checked for deblocking\n";
flush();
}
}
}
if (count($reset_quota_for)) {
$blockedAccounts=array_intersect($blockedAccounts,$reset_quota_for);
}
if (count($blockedAccounts) >0 ) {
$this->unBlockRemoteAccounts($blockedAccounts);
if (!$this->enableThor) {
$query=sprintf("delete from grp where grp = '%s'",$this->quotaGroup);
if (count($reset_quota_for)) {
$k=0;
foreach ($reset_quota_for as $_account) {
if ($k) $usage_keys.= ", ";
$usage_keys.="'".addslashes($_account)."'";
$k++;
}
$query.= "and CONCAT(username,'@',domain) in (".$usage_keys.")";
}
if (!$this->AccountsDB->query($query)) {
$log=sprintf ("Database error: %s (%s)",$this->AccountsDB->Error,$this->AccountsDB->Errno);
print $log;
syslog(LOG_NOTICE,$log);
return false;
}
}
}
if (count($blockedAccounts)) {
$log=sprintf ("Reset %d users blocked by quota\n",count($blockedAccounts));
print $log;
syslog(LOG_NOTICE, $log);
}
}
function initQuotaUsageFromDatabase($month="",$reset_quota_for=array()) {
if (!$month) {
$this->startTime=Date("Y-m-01 00:00",time());
} else {
$this->startTime=$month."-01 00:00";
}
$j=0;
$usage_keys='';
if (count($reset_quota_for)) {
$log=sprintf ("Init quota of data source %s for %d accounts\n",addslashes($this->CDRS->cdr_source),count($reset_quota_for));
print $log;
syslog(LOG_NOTICE, $log);
$k=0;
foreach ($reset_quota_for as $_account) {
if ($k) $usage_keys.= ", ";
$usage_keys.="'".addslashes($_account)."'";
$k++;
}
$usage_keys="and ".addslashes($this->BillingPartyIdField). " in (".$usage_keys.")";
} else {
if (count($this->localDomains)) {
$domain_filter="and Realm in (";
$t=0;
foreach (array_keys($this->localDomains) as $_domain) {
if (!$_domain) continue;
if ($t) $domain_filter .= ",";
$domain_filter .= sprintf("'%s'",addslashes($_domain));
$t++;
}
$domain_filter .= ") ";
}
$log=sprintf ("Init quota of data source %s for all accounts\n",$this->CDRS->cdr_source);
print $log;
syslog(LOG_NOTICE, $log);
}
$query=sprintf("select %s,
count(*) as calls,
sum(AcctSessionTime) as duration,
sum(Price) as cost,
sum(AcctInputOctets + AcctOutputOctets)/2 as traffic
from %s
where AcctStartTime >= '%s'
and Normalized = '1'
%s
%s
group by %s\n",
addslashes($this->BillingPartyIdField),
addslashes($this->table),
addslashes($this->startTime),
$domain_filter,
$usage_keys,
addslashes($this->BillingPartyIdField)
);
if (!$this->CDRdb->query($query)) {
if ($this->CDRdb->Errno != 1146) {
$log=sprintf ("Database error: %s (%s)",$this->CDRdb->Error,$this->CDRdb->Errno);
print $log;
syslog(LOG_NOTICE,$log);
return false;
}
}
$rows=$this->CDRdb->num_rows();
$log=sprintf ("%d callers generated traffic in %s for data source %s\n",$rows,Date("Y-m",time()),$this->CDRS->cdr_source);
print $log;
flush();
syslog(LOG_NOTICE, $log);
$j=0;
$progress=0;
while($this->CDRdb->next_record()) {
if ($rows > 1000) {
if ($j > $progress*$rows/100) {
$progress++;
if ($progress%10 == 0) {
print "$progress% ";
flush();
}
}
}
unset($accounts);
$accounts[$this->CDRdb->f($this->BillingPartyIdField)]['usage']['calls'] = $this->CDRdb->f('calls');
$accounts[$this->CDRdb->f($this->BillingPartyIdField)]['usage']['duration'] = $this->CDRdb->f('duration');
$accounts[$this->CDRdb->f($this->BillingPartyIdField)]['usage']['cost'] = $this->CDRdb->f('cost');
$accounts[$this->CDRdb->f($this->BillingPartyIdField)]['usage']['traffic'] = $this->CDRdb->f('traffic');
$accounts[$this->CDRdb->f($this->BillingPartyIdField)]['usage']['cost_today'] = 0;
$this->CDRS->cacheQuotaUsage($accounts);
$j++;
}
}
function checkQuota($notify) {
global $UserQuota;
$this->initQuotaUsage();
$query=sprintf("select * from quota_usage where datasource = '%s' and quota > 0 and (cost > quota or cost_today >= quota * $this->daily_quota/100)",addslashes($this->CDRS->cdr_source));
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
$toNotify=array();
$_checks=0;
while ($this->db->next_record()) {
$account=$this->db->f('account');
list($username,$domain)=explode("@",$account);
if ($this->db->f('cost') >= $this->db->f('quota')) {
$quota_exceeded=true;
$exceeded_period='monthly';
} else if ($this->daily_quota && ($this->db->f('cost_today') >= $this->db->f('quota') * $this->daily_quota/100)) {
$quota_exceeded=true;
$exceeded_period='daily';
} else {
$quota_exceeded= false;
}
if ($quota_exceeded) {
$exceeding_accounts++;
if (!$this->db->f('blocked')) {
$reason='Cost exceeded';
if (!$seen_title) {
$line=sprintf ("%40s %6s %8s %8s %13s %s\n","User","Calls","Price","Minutes","Traffic","Reason");
print $line;
$email_body=$line;
$seen_title++;
}
$line = sprintf ("%40s %6s %8s %8s %10s MB %s\n",
$account,
$this->db->f('calls'),
$this->db->f('cost'),
number_format($this->db->f('duration')/60,0,"",""),
number_format($this->db->f('traffic')/1024/1024,2),
$reason
);
$email_body = $email_body.$line;
print $line;
if ($this->enableThor) {
$this->domain_table = "sip_domains";
} else {
$this->domain_table = "domain";
}
$query=sprintf("select * from %s where domain = '%s'",addslashes($this->domain_table),addslashes($domain));
if (!$this->AccountsDB->query($query)) {
$log=sprintf ("Database error: %s (%d) %s\n",$this->AccountsDB->Error,$this->AccountsDB->Errno,$query);
syslog(LOG_NOTICE,$log);
}
if ($this->AccountsDB->num_rows()){
$this->AccountsDB->next_record();
$_reseller=$this->AccountsDB->f('reseller_id');
} else {
$_reseller=0;
}
$log=sprintf("%s quota exceeded for %s (%s > %s)",ucfirst($exceeded_period),$account,$this->db->f('cost'), $this->db->f('quota'));
syslog(LOG_NOTICE, $log);
$log_query=sprintf("insert into log
(date,login,ip,datasource,results,description,reseller_id)
values (NOW(),'quotacheck','localhost','QuotaCheck','1','%s',%d)",
addslashes($log),
$_reseller
);
if (!$this->db1->query($log_query)) {
$log=sprintf ("Database error: %s (%s)",$this->db1->Error,$this->db1->Errno);
print $log;
syslog(LOG_NOTICE,$log);
}
if ($this->blockAccount($account)) {
if ($notify) {
$toNotify[]=$account;
}
$blocked_now++;
$blockedAccountsNow=$blockedAccountsNow.$account."\n";
}
} else {
$blockedAccountsPrevious=$blockedAccountsPrevious.$account."\n";
$blocked_previous++;
}
}
$_checks++;
}
if ($exceeding_accounts) {
$line=sprintf("%6d accounts have exceeded their traffic limits\n",$exceeding_accounts);
print $line;
$email_body=$email_body.$line;
} else {
$log=sprintf("No quota has been exceeded\n");
syslog(LOG_NOTICE, $log);
}
if ($blocked_now) {
$line=sprintf("%6d accounts have been blocked now\n",$blocked_now);
$email_body=$email_body.$line;
}
if ($blockedAccountsNow) {
$line="Blocked accounts now:\n".$blockedAccountsNow;
print $line;
$email_body=$email_body.$line.$batch_block;
}
if ($blockedAccountsPrevious) {
$line="Blocked acccounts previously:\n".$blockedAccountsPrevious;
print $line;
$email_body=$email_body.$line.$batch_unblock;
}
// send notification to the provider
if ($this->CDRTool['provider']['toEmail'] && $blockedAccountsNow) {
$from = $this->CDRTool['provider']['fromEmail'];
$to = $this->CDRTool['provider']['toEmail'];
$bcc = $this->CDRTool['provider']['bccEmail'];
$service = $this->CDRTool['provider']['service'];
if (!$service) $service = "SIP";
if ($from) $extraHeaders="From: $from\r\nBCC: $from";
if ($bcc) $extraHeaders=$extraHeaders.",".$bcc;
print("Notify CDRTool provider at $to\n");
mail($to, "$service platform - CDRTool quota check", $email_body, $extraHeaders);
}
if ($notify && is_array($toNotify) && count($toNotify) >0) {
// send notification to accounts
foreach($toNotify as $rcpt) {
$this->notify($rcpt);
}
}
}
function notify($account) {
global $DATASOURCES;
list($username,$domain)=explode("@",$account);
if (!$DATASOURCES[$this->cdr_source]['UserQuotaNotify']) {
return false;
}
// get account information
if ($this->enableThor) {
$query=sprintf("select first_name,last_name,email,profile from sip_accounts where username = '%s' and domain = '%s'",addslashes($username),addslashes($domain));
} else {
$query=sprintf("select first_name,last_name,email_address as email,profile from subscriber where username = '%s' and domain = '%s'",addslashes($username),addslashes($domain));
}
if (!$this->AccountsDB->query($query)) {
$log=sprintf("Database error: %s (%s)",$this->AccountsDB->Error,$this->AccountsDB->Errno);
syslog(LOG_NOTICE,$log);
return false;
}
if (!$this->AccountsDB->num_rows()) return false;
$this->AccountsDB->next_record();
$fullname = $this->AccountsDB->f('first_name')." ".$this->AccountsDB->f('last_name');
$toEmail = $this->AccountsDB->f('email');
$profile = json_decode($this->AccountsDB->f('profile'),true);
$providerName=$this->notificationAddresses[$domain]['providerName'];
if (!$providerName) $providerName="your SIP service provider";
$body=sprintf("Dear __NAME__,\n\n".
"Your SIP account %s has been temporarily blocked\n".
"because your monthly quota has been exceeded.\n\n".
"To unblock your account you may contact %s.\n\n".
"N.B. This is an automatically generated message. Do not reply to it.\n",
$account,
$providerName);
$fromEmail = $this->CDRTool['provider']['fromEmail'];
$bccEmail = $this->CDRTool['provider']['bccEmail'];
$seen_bcc[$bccEmail]++;
if ($this->notificationAddresses[$domain]['fromEmail']) {
$fromEmail=$this->notificationAddresses[$domain]['fromEmail'];
}
if ($this->notificationAddresses[$domain]['quotaBody']) {
$body=$this->notificationAddresses[$domain]['quotaBody'];
}
if ($this->notificationAddresses[$domain]['quotaSubject']) {
$subject=$this->notificationAddresses[$domain]['quotaSubject'];
}
$body=preg_replace("/__NAME__/",$fullname,$body);
$body=preg_replace("/__ACCOUNT__/",$account,$body);
$body=preg_replace("/__CALLERID__/","$profile[rpid]",$body);
if (!$subject) {
$subject=sprintf("Monthly quota exceeded for account %s",$account);
} else {
$subject=preg_replace("/__ACCOUNT__/",$account,$subject);
$subject=preg_replace("/__CALLERID__/","$profile[rpid]",$subject);
}
if (!$toEmail || !$fromEmail) {
return false;
}
$seen_bcc[$toEmail]++;
$extraHeaders="From: $fromEmail";
if ($this->notificationAddresses[$domain][bccEmail]) {
if ($bccEmail) $bccEmail.= ",";
$bccEmail.=$this->notificationAddresses[$domain][bccEmail];
}
if ($bccEmail) $extraHeaders = $extraHeaders."\r\nBCC: ".$bccEmail;
mail($toEmail,$subject,$body, $extraHeaders);
$log_msg=sprintf("Monthly quota exceeded for %s. Notified To:%s From:%s\n",$account, $toEmail,$fromEmail);
syslog(LOG_NOTICE, $log_msg);
print $log_msg;
}
function blockAccount($account) {
list($username,$domain)=explode("@",$account);
if (is_object($this->soapclient)) {
return $this->blockAccountRemote($account);
} else {
$query=sprintf("insert into grp
(username,domain,grp,last_modified)
values
('%s','%s','%s',NOW())",
addslashes($username),
addslashes($domain),
addslashes($this->quotaGroup)
);
if (!$this->AccountsDB->query($query)) {
if ($this->AccountsDB->Errno != 1062) {
$log=sprintf ("Database error: %s (%s)",$this->AccountsDB->Error,$this->AccountsDB->Errno);
print $log;
syslog(LOG_NOTICE,$log);
return false;
} else {
return true;
}
} else {
$this->markBlocked($account);
return true;
}
}
}
function blockAccountRemote($account) {
list($username,$domain)=explode("@",$account);
if (!$username || !$domain) {
$log=sprintf("Error: misssing username/domain in blockAccountRemote()");
syslog(LOG_NOTICE, $log);
return false;
}
$this->soapclient->addHeader($this->SoapAuth);
$result = $this->soapclient->addToGroup(array("username" => $username,"domain"=> $domain), "quota");
if (PEAR::isError($result)) {
$error_msg = $result->getMessage();
$error_fault = $result->getFault();
$error_code = $result->getCode();
$log=sprintf("Error from %s: %s (%s)",$this->SOAPurl,$error_fault->faultstring,$error_fault->faultcode);
syslog(LOG_NOTICE, $log);
print $log;
if ($error_fault->detail->exception->errorcode != "1030") {
$from = $this->CDRTool['provider']['fromEmail'];
$to = $this->CDRTool['provider']['toEmail'];
$extraHeaders = "From: $from";
$email_body = "Remote SOAP request failure when calling blockAccountRemote(): \n\n".
$log;
mail($to, "CDRTool SOAP client failure", $email_body, $extraHeaders);
}
return false;
} else {
$log=sprintf ("Block account %s at %s",$account,$this->SOAPurl );
syslog(LOG_NOTICE, $log);
$this->markBlocked($account);
return true;
}
}
function unBlockRemoteAccounts($accounts) {
if (!is_object($this->soapclient)) {
return;
}
foreach ($accounts as $account) {
list($username,$domain)=explode("@",$account);
if (!$username || !$domain) return true;
$this->soapclient->addHeader($this->SoapAuth);
$result = $this->soapclient->removeFromGroup(array("username" => $username,"domain"=> $domain), "quota");
if (PEAR::isError($result)) {
$error_msg = $result->getMessage();
$error_fault = $result->getFault();
$error_code = $result->getCode();
if ($error_fault->detail->exception->errorcode &&
$error_fault->detail->exception->errorcode != "1030" &&
$error_fault->detail->exception->errorcode != "1031"
) {
$from = $this->CDRTool[provider][fromEmail];
$to = $this->CDRTool[provider][toEmail];
$extraHeaders="From: $from";
$email_body="SOAP request failure: \n\n".
$log=sprintf ("SOAP client error: %s %s\n",$error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring);
syslog(LOG_NOTICE, $log);
mail($to, "CDRTool SOAP failure", $email_body, $extraHeaders);
}
} else {
$log=sprintf ("Unblock remote account %s at %s",$account,$this->SOAPurl);
syslog(LOG_NOTICE, $log);
}
}
}
function saveQuotaInitFlag() {
$query=sprintf("insert into memcache (`key`,`value`) values ('%s','1')",addslashes($this->quota_init_flag));
if (!$this->db->query($query)) {
if ($this->db->Errno != '1062') {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
return true;
}
function deleteQuotaInitFlag() {
$query=sprintf("delete from memcache where `key` in ('%s','%s')",addslashes($this->quota_init_flag),addslashes($this->quota_reset_flag));
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
return true;
}
function deleteQuotaUsageFromCache ($reset_quota_for=array()) {
$query=sprintf("delete from quota_usage where datasource = '%s' ",addslashes($this->CDRS->cdr_source));
if (count($reset_quota_for)) {
$query.= " and account in (";
$t=0;
foreach($reset_quota_for as $_account) {
if ($t) $query.=",";
$query.= sprintf("'%s'",$_account);
$t++;
}
$query.=")";
}
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->affected_rows()) {
$log=sprintf("Deleted %d keys from cache\n",$this->db->affected_rows());
print $log;
syslog(LOG_NOTICE, $log);
}
return true;
}
function initQuotaUsage() {
$query=sprintf("select value from memcache where `key` = '%s'",addslashes($this->quota_init_flag));
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
if ($this->db->num_rows()) return true;
$lockName=sprintf("%s:%s",$this->CDRS->cdr_source,$this->CDRS->table);
if (!$this->CDRS->getNormalizeLock($lockName)) {
$log=sprintf("Error: cannot initialize now the quota because a normalization process in progress\n");
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
$query=sprintf("select value from memcache where `key` = '%s'",addslashes($this->quota_reset_flag));
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
$reset_quota_for= array();
if ($this->db->num_rows()) {
$this->db->next_record();
$reset_quota_for = json_decode($this->db->f('value'));
}
$this->deblockAccounts($reset_quota_for);
$this->deleteQuotaUsageFromCache($reset_quota_for);
$this->initQuotaUsageFromDatabase('',$reset_quota_for);
if ($this->CDRS->status['cached_keys']['saved_keys']) {
$log=sprintf("Saved %d accounts in quota cache\n",$this->CDRS->status['cached_keys']['saved_keys']);
print $log;
syslog(LOG_NOTICE, $log);
}
if ($this->CDRS->status['cached_keys']['failed_keys']) {
$log=sprintf("Error: failed to save %d account\n",$this->CDRS->status['cached_keys']['failed_keys']);
print $log;
syslog(LOG_NOTICE, $log);
}
if ($this->saveQuotaInitFlag()) {
$query=sprintf("delete from memcache where `key` = '%s'",addslashes($this->quota_reset_flag));
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
return true;
} else {
$log=sprintf ("Error: failed to save key quotaCheckInit");
syslog(LOG_NOTICE, $log);
return false;
}
}
function markBlocked($account) {
$query=sprintf("update quota_usage set blocked = '1', notified = NOW() where account = '%s' and datasource = '%s'",addslashes($account),addslashes($this->CDRS->cdr_source));
if (!$this->db1->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db1->Error,$this->db1->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
}
function resetDailyQuota () {
$query=sprintf("update quota_usage set cost_today = 0 where datasource = '%s'",addslashes($this->CDRS->cdr_source));
if (!$this->db1->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->db1->Error,$this->db1->Errno);
print $log;
syslog(LOG_NOTICE, $log);
return false;
}
return true;
}
}
class RatingEngine {
var $method = '';
var $log_runtime = false;
var $prepaid_table = "prepaid";
var $init_ok = false;
function RatingEngine () {
global $RatingEngine; // set in global.inc
global $DATASOURCES; // set in global.inc
if (!strlen($RatingEngine['socketIP']) || !$RatingEngine['socketPort'] || !$RatingEngine['cdr_source']) {
$log=sprintf("Please define \$RatingEngine['socketIP'], \$RatingEngine['socketPort'] and \$RatingEngine['cdr_source'] in /etc/cdrtool/global.inc\n");
syslog(LOG_NOTICE,$log);
return false;
}
if (preg_match("/^\d{1-3}\.\d{1-3}\.\d{1-3}\.\d{1-3}$/",$RatingEngine['socketIP'])) {
$log=sprintf("Invalid \$RatingEngine['socketIP'] in /etc/cdrtool/global.inc\n");
syslog(LOG_NOTICE,$log);
return false;
}
if (intval($RatingEngine['socketPort']) < 1 || intval($RatingEngine['socketPort']) > 65535) {
$log=sprintf("Invalid \$RatingEngine['socketPort'] in /etc/cdrtool/global.inc\n");
syslog(LOG_NOTICE,$log);
return false;
}
if (!is_array($DATASOURCES[$RatingEngine['cdr_source']])) {
$log=sprintf("Datasource '%s' does not exist in /etc/cdrtool/global.inc\n",$RatingEngine['cdr_source']);
syslog(LOG_NOTICE,$log);
return false;
}
$this->settings = $RatingEngine;
if ($this->settings['log_runtime']) {
$this->log_runtime=true;
}
// init database
$this->db = new DB_CDRTool;
$query=sprintf("delete from memcache where `key` = 'destinations_sip' or `key` = 'destinations'");
if (!$this->db->query($query)) {
$log=sprintf ("Database error: %s (%s) for query %s",$db->Error,$db->Errno,$query);
syslog(LOG_NOTICE,$log);
}
// init CDR datasource
$CDR_class = $DATASOURCES[$RatingEngine['cdr_source']]['class'];
$this->CDRS = new $CDR_class($RatingEngine['cdr_source']);
// load Rating Tables
$this->CDRS->RatingTables = new RatingTables();
$this->CDRS->RatingTables->LoadRatingTables();
// init subscribers database
$this->db_subscribers_class = $this->CDRS->db_subscribers;
if (!class_exists($this->db_subscribers_class)) {
syslog(LOG_NOTICE,"Error: No database defined for SIP accounts");
return false;
}
$this->AccountsDB = new $this->db_subscribers_class;
$this->enableThor = $this->CDRS->enableThor;
$this->init_ok = true;
}
function reloadRatingTables () {
$b=time();
//$query="delete from memcache where `key` in ('destinations','destinations_sip','ENUMtlds')";
$query="delete from memcache where `key` in ('ENUMtlds')";
if (!$this->db->query($query)) {
$log=sprintf ("Database error: %s (%s)",$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE,$log);
}
$this->CDRS->RatingTables->LoadRatingTables();
$e=time();
$d=$e-$b;
if ($d > 0 ) syslog(LOG_NOTICE, "Reloaded rating tables in $d seconds");
$b=time();
$this->CDRS->LoadDestinations();
$e=time();
$d=$e-$b;
if ($d > 0 ) syslog(LOG_NOTICE, "Reloaded destinations in $d seconds");
$this->db->query("update settings set var_value = '' where var_name = 'reloadRating'");
return 1;
}
function reloadCustomers ($customerFilter) {
return 1;
}
function reloadDomains () {
return 1;
}
function reloadQuota($account) {
if (!$account) return false;
$quota = $this->getQuota($account);
$blocked = $this->getBlockedByQuotaStatus($account);
$query=sprintf("update quota_usage set quota = '%s', blocked = '%s' where datasource = '%s' and account = '%s'",
$quota,
intval($blocked),
$this->CDRS->cdr_source,
addslashes($account)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query '%s': %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
return 0;
}
return 1;
}
function getBalanceHistory($account,$limit=50) {
list($username,$domain)=explode("@",$account);
if (!$username || !$domain) return 0;
$query=sprintf("select * from prepaid_history where username = '%s' and domain = '%s' order by id desc",
addslashes($username),
addslashes($domain)
);
if ($limit) $query.= sprintf (" limit %d",$limit);
if (!$this->db->query($query)) {
$log=sprintf ("getBalanceHistory error: %s (%s)",$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
return 0;
}
while ($this->db->next_record()) {
$history[]=array('account' => $account,
'action' => $this->db->f('action'),
'description' => $this->db->f('description'),
'value' => $this->db->f('value'),
'balance' => $this->db->f('balance')
);
}
$line=json_encode($history);
return $line;
}
function DebitBalanceAudio($account,$balance,$session_id,$duration,$force=false) {
$this->old_session_count = 0;
$this->new_session_count = 0;
$els=explode(":",$account);
if (count($els) == 2) {
$account=$els[1];
}
if (!$account) {
syslog(LOG_NOTICE, "DebitBalanceAudio() error: missing account");
return 0;
}
if (!is_numeric($balance)) {
syslog(LOG_NOTICE, "DebitBalanceAudio() error: balance must be numeric");
return 0;
}
if (!$session_id) {
syslog(LOG_NOTICE, "DebitBalanceAudio() error: missing call id");
return 0;
}
$query=sprintf("select * from %s where account = '%s'",
addslashes($this->prepaid_table),
addslashes($account)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE,$log);
$this->logRuntime();
return 0;
}
if (!$this->db->num_rows()) {
$log=sprintf ("DebitBalanceAudio() error: account $account does not exist");
syslog(LOG_NOTICE, $log);
$this->logRuntime();
return 0;
}
$this->db->next_record();
if (strlen($this->db->f('active_sessions'))) {
// remove active session
$active_sessions=array();
$old_active_sessions = json_decode($this->db->f('active_sessions'),true);
$destination=$old_active_sessions[$session_id]['Destination'];
if (!$force) {
if (!in_array($session_id,array_keys($old_active_sessions))) {
$this->sessionDoesNotExist=true;
$log=sprintf("Error: session %s of %s does not exist",$session_id,$account);
syslog(LOG_NOTICE, $log);
return 0;
}
}
foreach (array_keys($old_active_sessions) as $_key) {
if ($_key==$session_id) continue;
$active_sessions[$_key]=$old_active_sessions[$_key];
}
} else {
if (!$force) {
$this->sessionDoesNotExist=true;
$log=sprintf ("Error: session %s for %s does not exist",$session_id,$account);
syslog(LOG_NOTICE, $log);
return 0;
}
}
$next_balance=$this->db->f('balance')-$balance;
//get parallel calls and remaining_balance
$this->getActivePrepaidSessions($active_sessions, $next_balance, $account);
// calculate the updated maxsessiontime
$maxsessiontime=$this->getAggregatedMaxSessiontime($this->parallel_calls,$this->remaining_balance,$account);
$this->old_session_count = count($old_active_sessions);
$this->new_session_count = count($active_sessions);
$query=sprintf("update %s
set balance = balance - '%s',
change_date = NOW(),
active_sessions = '%s',
session_counter = '%s'
where account = '%s'",
addslashes($this->prepaid_table),
addslashes($balance),
addslashes(json_encode($active_sessions)),
count($active_sessions),
addslashes($account)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
return 0;
}
if ($balance > 0) {
list($prepaidUser,$prepaidDomain)=explode("@",$account);
if ($this->enableThor) {
$this->domain_table = "sip_domains";
} else {
$this->domain_table = "domain";
}
$query=sprintf("select * from %s where domain = '%s'",addslashes($this->domain_table),addslashes($prepaidDomain));
if (!$this->AccountsDB->query($query)) {
$log=sprintf ("Database error: %s (%d) %s\n",$this->AccountsDB->Error,$this->AccountsDB->Errno,$query);
syslog(LOG_NOTICE,$log);
}
if ($this->AccountsDB->num_rows()){
$this->AccountsDB->next_record();
$_reseller=$this->AccountsDB->f('reseller_id');
} else {
$_reseller=0;
}
$query=sprintf("insert into prepaid_history
(username,domain,action,description,value,balance,date,session,duration,destination,reseller_id)
values
('%s','%s','Debit balance','Session to %s for %ds','-%s','%s',NOW(),'%s','%d','%s',%d)",
addslashes($prepaidUser),
addslashes($prepaidDomain),
addslashes($destination),
addslashes($duration),
addslashes($balance),
addslashes($next_balance),
addslashes($session_id),
addslashes($duration),
addslashes($destination),
addslashes($_reseller)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
}
}
return $maxsessiontime;
}
function DebitBalanceMessage($account,$destination,$balance,$session_id) {
$els=explode(":",$account);
if (count($els) == 2) {
$account=$els[1];
}
if (!$account) {
syslog(LOG_NOTICE, "DebitBalanceMessage() error: missing account");
return 0;
}
if (!is_numeric($balance)) {
syslog(LOG_NOTICE, "DebitBalanceMessage() error: balance must be numeric");
return 0;
}
if (!$session_id) {
syslog(LOG_NOTICE, "DebitBalanceMessage() error: missing call id");
return 0;
}
$query=sprintf("select * from %s where account = '%s'",
addslashes($this->prepaid_table),
addslashes($account)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE,$log);
$this->logRuntime();
return 0;
}
if (!$this->db->num_rows()) {
$log=sprintf ("DebitBalanceMessage() error: account $account does not exist");
syslog(LOG_NOTICE, $log);
$this->logRuntime();
return 0;
}
$this->db->next_record();
if (strlen($this->db->f('active_sessions'))) {
$active_sessions = json_decode($this->db->f('active_sessions'),true);
}
$next_balance=$this->db->f('balance')-$balance;
//get parallel calls and remaining_balance
$this->getActivePrepaidSessions($active_sessions,$next_balance,$account);
// calculate the updated maxsessiontime
$maxsessiontime=$this->getAggregatedMaxSessiontime($this->parallel_calls,$this->remaining_balance,$account);
$query=sprintf("update %s
set balance = balance - '%s',
change_date = NOW()
where account = '%s'",
addslashes($this->prepaid_table),
addslashes($balance),
addslashes($account)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
return 0;
}
if ($balance > 0) {
list($prepaidUser,$prepaidDomain)=explode("@",$account);
if ($this->enableThor) {
$this->domain_table = "sip_domains";
} else {
$this->domain_table = "domain";
}
$query=sprintf("select * from %s where domain = '%s'",addslashes($this->domain_table),addslashes($prepaidDomain));
if (!$this->AccountsDB->query($query)) {
$log=sprintf ("Database error: %s (%d) %s\n",$this->AccountsDB->Error,$this->AccountsDB->Errno,$query);
syslog(LOG_NOTICE,$log);
}
if ($this->AccountsDB->num_rows()){
$this->AccountsDB->next_record();
$_reseller=$this->AccountsDB->f('reseller_id');
} else {
$_reseller=0;
}
$query=sprintf("insert into prepaid_history
(username,domain,action,description,value,balance,date,session,destination,reseller_id)
values
('%s','%s','Debit balance','Message to %s','-%s','%s',NOW(),'%s','%s',%d)",
addslashes($prepaidUser),
addslashes($prepaidDomain),
addslashes($destination),
addslashes($balance),
addslashes($next_balance),
addslashes($session_id),
addslashes($destination),
addslashes($_reseller)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
}
}
return true;
}
function CreditBalance($account,$balance) {
if (!is_numeric($balance)) {
syslog(LOG_NOTICE, "CreditBalance() error: balance \"$balance\"is invalid");
return 0;
}
$els=explode(":",$account);
if (count($els) == 2) {
$account=$els[1];
}
if (!$account) {
syslog(LOG_NOTICE, "CreditBalance() error: missing account");
return 0;
}
list($prepaidUser,$prepaidDomain)=explode("@",$account);
$query=sprintf("select * from %s where account = '%s'",
addslashes($this->prepaid_table),
addslashes($account)
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE,$log);
$this->logRuntime();
return 0;
}
if ($this->db->num_rows()) {
$this->db->next_record();
$current_balance = $this->db->f('balance');
$query=sprintf("update %s
set balance = balance + '%s',
change_date = NOW()
where account = '%s'",
addslashes($this->prepaid_table),
addslashes($balance),
addslashes($account)
);
$this->db->query($query);
if ($this->db->affected_rows()) {
$new_balance = $current_balance + $balance;
$log=sprintf ("Prepaid account $account credited with $balance");
syslog(LOG_NOTICE, $log);
// log to prepaid_history
$query=sprintf("insert into prepaid_history
(username,domain,action,description,value,balance,date)
values
('%s','%s','Set balance','Manual update','%s','%s',NOW())",
addslashes($prepaidUser),
addslashes($prepaidDomain),
addslashes($balance),
addslashes($new_balance)
);
if (!$this->db->query($query)) {
$log=sprintf("Error: %s (%s)",$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
}
return 1;
} else {
$log=sprintf ("CreditBalance() error: failed to credit balance: %s (%s)",$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
return 0;
}
} else {
$query=sprintf("insert into %s (balance, account, change_date) values ('%s','%s',NOW())",
addslashes($this->prepaid_table),
addslashes($balance),
addslashes($account)
);
$this->db->query($query);
if ($this->db->affected_rows()) {
$log=sprintf ("Added prepaid account $account with balance=$balance");
syslog(LOG_NOTICE, $log);
// log to prepaid_history
$query=sprintf("insert into prepaid_history
(username,domain,action,description,value,balance,date)
values
('%s','%s','Set balance','Manual update','%s','%s',NOW())",
addslashes($prepaidUser),
addslashes($prepaidDomain),
addslashes($balance),
addslashes($balance)
);
if (!$this->db->query($query)) {
$log=sprintf("Error: %s (%s)",$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
}
return 1;
} else {
$log=sprintf ("CreditBalance() error: failed to credit balance: %s (%s)",$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
return 0;
}
}
}
function DeleteBalance($account) {
$els=explode(":",$account);
if (count($els) == 2) {
$account=$els[1];
}
if (!$account) {
syslog(LOG_NOTICE, "DeleteBalance() error: missing account");
return 0;
}
$query=sprintf("delete from %s where account = '%s'",
addslashes($this->prepaid_table),
addslashes($account)
);
if (!$this->db->query($query)) {
$log=sprintf("DeleteBalance error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
return 0;
}
$log=sprintf ("Prepaid account %s has been deleted",$account);
syslog(LOG_NOTICE, $log);
return 1;
}
function DeleteBalanceHistory($account) {
$account=trim($account);
$els=explode(":",$account);
if (count($els) == 2) {
$account=$els[1];
}
if (!$account) {
syslog(LOG_NOTICE, "DeleteBalanceHistory() error: missing account");
return 0;
}
list($username,$domain)=explode('@',$account);
$query=sprintf("delete from prepaid_history where username = '%s' and domain = '%s'",
addslashes($username),
addslashes($domain)
);
if (!$this->db->query($query)) {
$log=sprintf("DeleteBalanceHistory error for query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
return 0;
}
$log=sprintf ("History of prepaid account %s has been deleted",$account);
syslog(LOG_NOTICE, $log);
return 1;
}
function GetEntityProfiles($entity) {
if (!$entity) {
syslog(LOG_NOTICE, "GetEntityProfiles");
return 0;
}
$query=sprintf("select * from billing_customers where
subscriber = '%s' or domain = '%s' or gateway = '%s'",
addslashes($entity),
addslashes($entity),
addslashes($entity)
);
if (!$this->db->query($query)) {
$log=sprintf ("GetEntityProfiles error: %s (%s)",$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
return 0;
}
if ($this->db->num_rows() ==1 ) {
$this->db->next_record();
$entity = array('entity' => $entity,
'profileWeekday' => $this->db->f('profile_name1'),
'profileWeekdayAlt' => $this->db->f('profile_name1_alt'),
'profileWeekend' => $this->db->f('profile_name2'),
'profileWeekendAlt' => $this->db->f('profile_name2_alt'),
'timezone' => $this->db->f('timezone'),
'increment' => $this->db->f('increment'),
'min_duration' => $this->db->f('min_duration')
);
}
$line=json_encode($entity);
return $line;
}
function SetEntityProfiles($entity,$profiles) {
if (!$entity) {
syslog(LOG_NOTICE, "SetEntityProfiles");
return 0;
}
}
function showHelp() {
$help=
"Version\n".
"Help\n".
"ShowClients\n".
"MaxSessionTime CallId=6432622xvv@1 From=sip:123@example.com To=sip:0031650222333@example.com Duration=7200 Gateway=10.0.0.1 Lock=1\n".
"ShowPrice From=sip:123@example.com To=sip:0031650222333@example.com Gateway=10.0.0.1 Duration=59\n".
"DebitBalance CallId=6432622xvv@1 From=sip:123@example.com To=sip:0031650222333@example.com Gateway=10.0.0.1 Duration=59\n".
"AddBalance From=123@example.com Value=10.00\n".
"GetBalance From=123@example.com\n".
"GetBalanceHistory From=123@example.com\n".
"DeleteBalance From=123@example.com\n".
"DeleteBalanceHistory From=123@example.com\n".
"ReloadQuota Account=abc@example.com\n".
"GetEntityProfiles Entity=abc@example.com\n".
"DumpPrepaidSessions Account=123@example.com\n".
"ReloadRatingTables\n".
"ReloadDomains\n".
"ShowProfiles\n".
"ShowENUMtlds\n"
;
return $help;
}
function logRuntime() {
if (!$this->log_runtime) return;
$t=0;
$log='';
foreach (array_keys($this->runtime) as $_key) {
$stamp=$this->runtime[$_key];
if ($prev_stamp) {
$_exec_time=$stamp-$prev_stamp;
$log .= sprintf("%s=%1.7f ",$_key,$_exec_time);
}
$prev_stamp=$stamp;
$t++;
}
syslog(LOG_NOTICE, $log);
}
function processNetworkInput($tinput) {
// Read key=value pairs from input
// Strip any unnecessary spaces
$this->runtime=array();
$tinput=preg_replace("/\s+/"," ",$tinput);
if ($tinput == "/" and strlen($this->last_input)) {
$tinput = $this->last_input;
} else {
$this->last_input = $tinput;
}
$_els=explode(" ",trim($tinput));
$this->runtime['start']=microtime_float();
syslog(LOG_NOTICE, $tinput);
if (!$_els[0]) return 0;
// read fields from input
unset($NetFields);
unset($seenField);
$i=0;
while ($i < count($_els)) {
$i++;
$_dict = explode("=",$_els[$i]);
$_key = strtolower(trim($_dict[0]));
if ($_key == 'callid') {
$_value = trim($_dict[1]);
} else {
$_value = strtolower(trim($_dict[1]));
}
if ($_key && $seenField[$_key]) {
$log=sprintf ("Error: '$_key' attribute is present more than once in $tinput");
syslog(LOG_NOTICE, $log);
return 0;
} else {
if ($_key) {
$NetFields[$_key]=$_value;
$seenField[$_key]++;
}
}
}
$NetFields['action']=strtolower($_els[0]);
$this->method = $NetFields['action'];
// begin processing
if ($NetFields['action']=="maxsessiontime") {
if (!$NetFields['from']) {
$log=sprintf ("error: missing From parameter");
syslog(LOG_NOTICE, $log);
return $log;
}
if (!$NetFields['to']) {
$log=sprintf ("error: missing To parameter");
syslog(LOG_NOTICE, $log);
return $log;
}
if (!$NetFields['gateway']) {
$log=sprintf ("error: missing gateway parameter");
syslog(LOG_NOTICE, $log);
return $log;
}
if (!$NetFields['callid']) {
$log=sprintf ("error: missing Call Id parameter");
syslog(LOG_NOTICE, $log);
return $log;
}
if (!$NetFields['duration'] && $this->settings['MaxSessionTime']) {
$NetFields['duration']=$this->settings['MaxSessionTime'];
}
$app_prefix = preg_replace('/[.].*$/', '', $NetFields['application']);
if (strlen($app_prefix)) {
if ($app_prefix == 'audio' || $app_prefix == 'sms' ) {
$application=$NetFields['application'];
} else {
$log=sprintf ("error: unsupported application %s",$NetFields['application']);
syslog(LOG_NOTICE, $log);
return $log;
}
} else {
$application='audio';
}
list($username_t,$domain_t)=explode("@",$NetFields['from']);
$CDRStructure=array (
$this->CDRS->CDRFields['callId'] => $NetFields['callid'],
$this->CDRS->CDRFields['aNumber'] => $NetFields['from'],
$this->CDRS->CDRFields['CanonicalURI'] => $NetFields['to'],
$this->CDRS->CDRFields['gateway'] => $NetFields['gateway'],
$this->CDRS->CDRFields['duration'] => floor($NetFields['duration']),
$this->CDRS->CDRFields['timestamp'] => time(),
$this->CDRS->CDRFields['domain'] => $domain_t,
$this->CDRS->CDRFields['application'] => $application,
'skip_fix_prepaid_duration' => true
);
$CDR = new $this->CDRS->CDR_class($this->CDRS, $CDRStructure);
$CDR->normalize();
$this->runtime['normalize_cdr']=microtime_float();
$query=sprintf("select * from %s where account = '%s'",addslashes($this->prepaid_table),addslashes($CDR->BillingPartyId));
if (!$this->db->query($query)) {
$log=sprintf ("Database error for query '%s': %s (%s), link_id =%s, query_id =%s",$query,$this->db->Error,$this->db->Errno,$this->db->Link_ID,$this->db->Query_ID);
syslog(LOG_NOTICE,$log);
$this->logRuntime();
$ret=sprintf("error: database error for query '%s': %s (%s)",$query,$this->db->Error,$this->db->Errno)."\n"."type=prepaid";
return $ret;
}
if (!$this->db->num_rows()) {
$log=sprintf ("MaxSessionTime=unlimited Type=postpaid CallId=%s BillingParty=%s",$NetFields['callid'],$CDR->BillingPartyId);
syslog(LOG_NOTICE, $log);
$ret="none"."\n"."type=postpaid";
return $ret;
}
$this->db->next_record();
$current_balance = $this->db->f('balance');
$old_session_counter = $this->db->f('session_counter');
$max_sessions = $this->db->f('max_sessions');
if (strlen($this->db->f('active_sessions'))) {
// load active sessions
$active_sessions = json_decode($this->db->f('active_sessions'),true);
if (count($active_sessions)) {
// purge stale sessions
$active_sessions_new=array();
$expired=0;
foreach (array_keys($active_sessions) as $_session) {
$expired_since=time() - $active_sessions[$_session]['timestamp'] - $active_sessions[$_session]['MaxSessionTime'];
if ($expired_since > 120) {
// this session has passed its maxsessiontime plus its reasonable setup time of 2 minutes,
// it could be stale
// because the call control module did not call debitbalance, so we purge it
$log = sprintf ("Session %s for %s has expired since %d seconds",
$_session,
$active_sessions[$_session]['BillingPartyId'],
$expired_since);
syslog(LOG_NOTICE, $log);
$expired++;
} else {
$active_sessions_new[$_session]=$active_sessions[$_session];
}
}
if ($expired) {
$active_sessions=$active_sessions_new;
}
}
} else {
$active_sessions=array();
}
if (!$current_balance) {
$log=sprintf ("No balance found");
syslog(LOG_NOTICE,$log);
$this->logRuntime();
$ret="0"."\n"."type=prepaid";
return $ret;
}
if (preg_match("/^0[0-9]{1,}@/",$CDR->CanonicalURINormalized)) {
if (!$CDR->DestinationId) {
$log = sprintf ("error: cannot figure out the destination id for %s",$CDR->CanonicalURI);
$this->logRuntime();
syslog(LOG_NOTICE, $log);
$ret=$log."\n"."type=prepaid";
return $ret;
}
} else {
$log=sprintf ("MaxSessionTime=unlimited Type=prepaid CallId=%s BillingParty=%s DestId=None",$NetFields['callid'],$CDR->BillingPartyId);
syslog(LOG_NOTICE, $log);
$this->logRuntime();
$ret="none"."\n"."type=prepaid";
return $ret;
}
$session_counter=count($active_sessions);
if ($max_sessions && $session_counter >= $max_sessions) {
$log = sprintf ("Locked: maximum number of concurrent calls %s reached, $max_sessions allowed");
syslog(LOG_NOTICE, $log);
$ret="Locked"."\n"."type=prepaid";
return $ret;
}
$maxduration=0;
// Build Rate dictionary containing normalized CDR fields plus customer Balance
if (count($active_sessions)) {
// set $this->remaining_balance and $this->parallel_calls for ongoing calls:
if (!$this->getActivePrepaidSessions($active_sessions, $current_balance, $CDR->BillingPartyId, array($CDR->callId))) {
$ret="0"."\n"."type=prepaid";
return $ret;
}
$this->runtime['get_parallel_calls']=microtime_float();
// add this new call to the list of parallel calls
$RateDictionary=array(
'duration' => $CDR->duration,
'callId' => $CDR->callId,
'Balance' => $this->remaining_balance,
'timestamp' => $CDR->timestamp,
'DestinationId' => $CDR->DestinationId,
'region' => $CDR->region,
'domain' => $CDR->domain,
'gateway' => $CDR->gateway,
'BillingPartyId' => $CDR->BillingPartyId,
'ENUMtld' => $CDR->ENUMtld,
'RatingTables' => $this->CDRS->RatingTables,
'application' => $application
);
$Rate = new Rate($this->settings, $this->db);
$_maxduration = round($Rate->MaxSessionTime($RateDictionary));
$log = sprintf ("Maximum duration for new session %s of %s to destination %s having balance=%s is %s",
$CDR->callId,
$CDR->BillingPartyId,
$CDR->DestinationId,
$this->remaining_balance,
$_maxduration);
syslog(LOG_NOTICE, $log);
if ($_maxduration > 0) {
$this->parallel_calls[$CDR->callId]=array('remainingBalancePerSecond' => $this->remaining_balance/$_maxduration);
} else {
$log = sprintf ("Maximum duration for new session %s of %s <=0",$CDR->callId,$CDR->BillingPartyId);
syslog(LOG_NOTICE, $log);
$ret="0"."\n"."type=prepaid";
return $ret;
}
$this->parallel_calls[$CDR->callId]=array('remainingBalancePerSecond' => $this->remaining_balance/$_maxduration);
$maxduration=$this->getAggregatedMaxSessiontime($this->parallel_calls, $this->remaining_balance, $CDR->BillingPartyId);
} else {
$RateDictionary=array(
'duration' => $CDR->duration,
'callId' => $CDR->callId,
'Balance' => $current_balance,
'timestamp' => $CDR->timestamp,
'DestinationId' => $CDR->DestinationId,
'region' => $CDR->region,
'domain' => $CDR->domain,
'gateway' => $CDR->gateway,
'BillingPartyId' => $CDR->BillingPartyId,
'ENUMtld' => $CDR->ENUMtld,
'RatingTables' => $this->CDRS->RatingTables,
'application' => $application
);
$Rate = new Rate($this->settings, $this->db);
$this->runtime['instantiate_rate']=microtime_float();
$maxduration = round($Rate->MaxSessionTime($RateDictionary));
}
// add new active session
$active_sessions[$CDR->callId]= array('timestamp' => $CDR->timestamp,
'duration' => $CDR->duration,
'BillingPartyId' => $CDR->BillingPartyId,
'MaxSessionTime' => $maxduration,
'domain' => $CDR->domain,
'gateway' => $CDR->gateway,
'Destination' => $CDR->destinationPrint,
'DestinationId' => $CDR->DestinationId,
'region' => $CDR->region,
'connectCost' => $Rate->connectCost
);
if ($CDR->ENUMtld) {
$active_sessions[$CDR->callId]['ENUMtld']=$CDR->ENUMtld;
}
$this->runtime['calculate_maxduration']=microtime_float();
if ($maxduration < 0) {
$log = sprintf ("error: maxduration %s is negative",$maxduration);
syslog(LOG_NOTICE, $log);
$ret=$log."\n"."type=prepaid";
return $ret;
}
if ($Rate->min_duration && $maxduration < $Rate->min_duration) {
$log = sprintf ("Notice: maxduration of %s is less then min_duration (%s)",$maxduration,$Rate->min_duration);
syslog(LOG_NOTICE, $log);
$ret="0"."\n"."type=prepaid";
return $ret;
}
if (!$Rate->billingTimezone) {
$log = sprintf ("error: cannot figure out the billing timezone")."\n"."type=prepaid";
syslog(LOG_NOTICE, $log);
$ret=$log."\n"."type=prepaid";
return $ret;
}
if (!$Rate->startTimeBilling) {
$log = sprintf ("error: cannot figure out the billing start time")."\n"."type=prepaid";
syslog(LOG_NOTICE, $log);
$ret=$log."\n"."type=prepaid";
return $ret;
}
$log=sprintf("MaxSessionTime=%s Type=prepaid CallId=%s BillingParty=%s DestId=%s Balance=%s Spans=%d Counter=%d->%d",
$maxduration,
$NetFields['callid'],
$CDR->BillingPartyId,
$CDR->DestinationId,
$RateDictionary['Balance'],
$Rate->MaxSessionTimeSpans,
$old_session_counter,
count($active_sessions)
);
syslog(LOG_NOTICE, $log);
if ($maxduration > 0) {
$query=sprintf("update %s
set
active_sessions = '%s',
session_counter = '%s'
where account = '%s'",
addslashes($this->prepaid_table),
addslashes(json_encode($active_sessions)),
count($active_sessions),
addslashes($CDR->BillingPartyId));
if (!$this->db->query($query)) {
$log=sprintf ("Database error for %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE,$log);
$log=sprintf ("error: database error %s (%s)",$this->db->Error,$this->db->Errno);
return $log;
}
}
$this->runtime['update_prepaid']=microtime_float();
$this->logRuntime();
$ret=$maxduration."\n"."type=prepaid";
return $ret;
} else if ($NetFields['action'] == "dumpprepaidsessions") {
if (!$NetFields['account']) {
$log=sprintf ("error: missing account parameter");
syslog(LOG_NOTICE, $log);
return $log;
}
$query=sprintf("select * from %s where account = '%s'",
addslashes($this->prepaid_table),
addslashes($NetFields['account'])
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE,$log);
$this->logRuntime();
return 0;
}
if (!$this->db->num_rows()) {
$log=sprintf ("DebitBalanceAudio() error: account $account does not exist");
syslog(LOG_NOTICE, $log);
$this->logRuntime();
return 0;
}
$this->db->next_record();
return var_export(json_decode($this->db->f('active_sessions'),true), true);
} else if ($NetFields['action'] == "debitbalance") {
if (!$NetFields['from']) {
$log=sprintf ("error: missing From parameter");
syslog(LOG_NOTICE, $log);
return $log;
}
if (!$NetFields['to']) {
$log=sprintf ("error: missing To parameter");
syslog(LOG_NOTICE, $log);
return $log;
}
$app_prefix = preg_replace('/[.].*$/', '', $NetFields['application']);
if (!strlen($app_prefix) || (strlen($app_prefix) && $app_prefix == 'audio')) {
if (!strlen($NetFields['duration'])) {
$log=sprintf ("error: missing Duration parameter");
syslog(LOG_NOTICE, $log);
return $log;
}
}
if (strlen($app_prefix)) {
if ($app_prefix == 'audio' || $app_prefix == 'sms' ) {
$application=$NetFields['application'];
} else {
$log=sprintf ("error: unsupported application %s",$NetFields['application']);
syslog(LOG_NOTICE, $log);
return $log;
}
} else {
$application='audio';
$app_prefix='audio';
}
if (!$NetFields['gateway']) {
$log=sprintf ("error: missing gateway parameter");
syslog(LOG_NOTICE, $log);
return $log;
}
if (!$NetFields['callid']) {
$log=sprintf ("error: missing Call Id parameter");
syslog(LOG_NOTICE, $log);
return $log;
}
if ($NetFields['force']) {
$force=true;
} else {
$force=false;
}
$timestamp=time();
list($username_t,$domain_t)=explode("@",$NetFields['from']);
$CDRStructure=array (
$this->CDRS->CDRFields['callId'] => $NetFields['callid'],
$this->CDRS->CDRFields['aNumber'] => $NetFields['from'],
$this->CDRS->CDRFields['CanonicalURI'] => $NetFields['to'],
$this->CDRS->CDRFields['gateway'] => $NetFields['gateway'],
$this->CDRS->CDRFields['ENUMtld'] => $NetFields['enumtld'],
$this->CDRS->CDRFields['duration'] => floor($NetFields['duration']),
$this->CDRS->CDRFields['timestamp'] => time(),
$this->CDRS->CDRFields['domain'] => $domain_t,
$this->CDRS->CDRFields['application'] => $application,
'skip_fix_prepaid_duration' => true
);
// Init CDR
$CDR = new $this->CDRS->CDR_class($this->CDRS, $CDRStructure);
$CDR->normalize();
$this->runtime['normalize_cdr']=microtime_float();
// Build Rate dictionary containing normalized CDR fields plus customer Balance
$RateDictionary=array(
'callId' => $NetFields['callid'],
'timestamp' => $CDR->timestamp,
'duration' => $CDR->duration,
'DestinationId' => $CDR->DestinationId,
'region' => $CDR->region,
'domain' => $CDR->domain,
'gateway' => $CDR->gateway,
'BillingPartyId' => $CDR->BillingPartyId,
'ENUMtld' => $CDR->ENUMtld,
'RatingTables' => $this->CDRS->RatingTables,
'application' => $application
);
$Rate = new Rate($this->settings, $this->db);
$this->runtime['instantiate_rate']=microtime_float();
if ($app_prefix == 'audio') {
if ($Rate->calculateAudio($RateDictionary)) {
$this->runtime['calculate_rate']=microtime_float();
$this->sessionDoesNotExist=false;
$result = $this->DebitBalanceAudio($CDR->BillingPartyId,$Rate->price,$NetFields['callid'],$CDR->duration,$force);
if ($this->sessionDoesNotExist) {
return "Failed";
}
$this->runtime['debit_balance']=microtime_float();
$log = sprintf ("DebitBalance=%s Duration=%s CallId=%s BillingParty=%s DestId=%s MaxSessionTime=%d Counter=%d->%d",
$Rate->price,
$CDR->duration,
$NetFields['callid'],
$CDR->BillingPartyId,
$CDR->DestinationId,
$result,
$this->old_session_count,
$this->new_session_count
);
syslog(LOG_NOTICE, $log);
$RateReturn = "Ok";
$RateReturn.= sprintf("\nMaxSessionTime=%d",$result);
if (strlen($Rate->price)) {
$RateReturn.="\n".$Rate->price;
if ($Rate->rateInfo) {
$RateReturn.="\n".trim($Rate->rateInfo);
}
}
return $RateReturn;
} else {
syslog(LOG_NOTICE, 'Failed to calculate rate in DebitBalance()');
return "Failed\n";
}
} else if ($app_prefix == 'sms') {
// return Ok, No credit, Error
if ($Rate->calculateMessage($RateDictionary)) {
if ($this->DebitBalanceMessage($CDR->BillingPartyId,$CDR->destinationPrint,$Rate->price,$NetFields['callid'])) {
$log = sprintf ("Price=%s CallId=%s BillingParty=%s DestId=%s Application=%s",
$Rate->price,
$NetFields['callid'],
$CDR->BillingPartyId,
$CDR->DestinationId,
$application
);
syslog(LOG_NOTICE, $log);
$RateReturn = "Ok";
if (strlen($Rate->price)) {
$RateReturn.="\n".$Rate->price;
if ($Rate->rateInfo) {
$RateReturn.="\n".trim($Rate->rateInfo);
}
}
return $RateReturn;
} else {
return "Failed";
}
} else {
return "Failed";
}
} else {
return false;
}
} else if ($NetFields['action'] == "addbalance") {
if (!$NetFields['from']) {
$log=sprintf ("Error: Missing From parameter");
syslog(LOG_NOTICE, $log);
return 0;
}
if (!is_numeric($NetFields['value'])) {
$log=sprintf ("Error: Missing Value parameter, it must be numeric");
syslog(LOG_NOTICE, $log);
return 0;
}
return $this->CreditBalance($NetFields['from'],$NetFields['value']);
} else if ($NetFields['action'] == "deletebalance") {
if (!$NetFields['from']) {
$log=sprintf ("Error: Missing From parameter");
syslog(LOG_NOTICE, $log);
return 0;
}
return $this->DeleteBalance($NetFields['from']);
} else if ($NetFields['action'] == "deletebalancehistory") {
if (!$NetFields['from']) {
$log=sprintf ("Error: Missing From parameter");
syslog(LOG_NOTICE, $log);
return 0;
}
return $this->DeleteBalanceHistory($NetFields['from']);
} else if ($NetFields['action'] == "showprice") {
if (!$NetFields['from']) {
$log=sprintf ("Error: Missing From parameter");
syslog(LOG_NOTICE, $log);
return 0;
}
if (!$NetFields['to']) {
$log=sprintf ("Error: Missing To parameter");
syslog(LOG_NOTICE, $log);
return 0;
}
if (!strlen($NetFields['duration'])) {
$log=sprintf ("Error: Missing Duration parameter");
syslog(LOG_NOTICE, $log);
return 0;
}
if ($NetFields['timestamp']) {
$timestamp=$NetFields['timestamp'];
} else {
$timestamp=time();
}
if (!$NetFields['gateway']) {
$log=sprintf ("error: missing gateway parameter");
syslog(LOG_NOTICE, $log);
return $log;
}
$app_prefix = preg_replace('/[.].*$/', '', $NetFields['application']);
if (strlen($app_prefix)) {
if ($app_prefix == 'audio' || $app_prefix == 'sms' ) {
$application=$NetFields['application'];
} else {
$log=sprintf ("error: unsupported application %s",$NetFields['application']);
syslog(LOG_NOTICE, $log);
return $log;
}
} else {
$application='audio';
}
list($username_t,$domain_t)=explode("@",$NetFields['from']);
$CDRStructure=array (
$this->CDRS->CDRFields['callId'] => $NetFields['callid'],
$this->CDRS->CDRFields['aNumber'] => $NetFields['from'],
$this->CDRS->CDRFields['CanonicalURI'] => $NetFields['to'],
$this->CDRS->CDRFields['gateway'] => $NetFields['gateway'],
$this->CDRS->CDRFields['ENUMtld'] => $NetFields['enumtld'],
$this->CDRS->CDRFields['duration'] => floor($NetFields['duration']),
$this->CDRS->CDRFields['timestamp'] => time(),
$this->CDRS->CDRFields['domain'] => $domain_t,
$this->CDRS->CDRFields['application'] => $application,
'skip_fix_prepaid_duration' => true
);
$CDR = new $this->CDRS->CDR_class($this->CDRS, $CDRStructure);
$CDR->normalize();
$Rate = new Rate($this->settings, $this->db);
$RateDictionary=array(
'callId' => $CDR->callId,
'timestamp' => $CDR->timestamp,
'duration' => $CDR->duration,
'DestinationId' => $CDR->DestinationId,
'region' => $CDR->region,
'domain' => $CDR->domain,
'gateway' => $CDR->gateway,
'BillingPartyId' => $CDR->BillingPartyId,
'ENUMtld' => $CDR->ENUMtld,
'RatingTables' => $this->CDRS->RatingTables,
'application' => $application
);
$Rate->calculateAudio($RateDictionary);
$this->runtime['calculate_rate']=microtime_float();
if (strlen($Rate->price)) {
$RateReturn=$Rate->price;
if ($Rate->rateInfo) {
$RateReturn.="\n".trim($Rate->rateInfo);
}
} else {
$RateReturn="0";
}
return $RateReturn;
} else if ($NetFields['action'] == "getbalance") {
if (!$NetFields['from']) {
$log=sprintf ("Error: Missing From parameter");
syslog(LOG_NOTICE, $log);
return 0;
}
$query=sprintf("select * from %s where account = '%s'",
addslashes($this->prepaid_table),
addslashes($NetFields['from'])
);
if (!$this->db->query($query)) {
$log=sprintf ("Database error for %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE,$log);
$this->logRuntime();
return 0;
}
if ($this->db->num_rows()) {
$this->db->next_record();
return number_format($this->db->f('balance'),4,".","");
} else {
return sprintf("%0.4f",0);
}
} else if ($NetFields['action'] == "getbalancehistory") {
if (!$NetFields['from']) {
$log=sprintf ("Error: Missing From parameter");
syslog(LOG_NOTICE, $log);
return 0;
}
$history=$this->getBalanceHistory($NetFields['from']);
return trim($history);
} else if ($NetFields['action'] == "getentityprofiles") {
if (!$NetFields['entity']) {
$log=sprintf ("Error: Missing Entity parameter");
syslog(LOG_NOTICE, $log);
return 0;
}
$entity=$this->GetEntityProfiles($NetFields['entity']);
return trim($entity);
} else if ($NetFields['action'] == "showprofiles") {
return trim($this->CDRS->RatingTables->showProfiles());
} else if ($NetFields['action'] == "showenumtlds") {
return trim($this->CDRS->RatingTables->showENUMtlds());
} else if ($NetFields['action'] == "version") {
$version_file=$this->CDRS->CDRTool['Path']."/version";
$version="CDRTool version ".trim(file_get_contents($version_file));
return $version;
} else if ($NetFields['action'] == "help") {
return $this->showHelp();
} else if ($NetFields['action'] == "reloadratingtables") {
return $this->reloadRatingTables();
} else if ($NetFields['action'] == "keepalive") {
return $this->keepAlive();
} else if ($NetFields['action'] == "reloadquota") {
if (!$NetFields['account']) {
$log=sprintf ("Error: Missing Account parameter");
syslog(LOG_NOTICE, $log);
return 0;
}
return $this->reloadQuota($NetFields['account']);
} else if ($NetFields['action'] == "reloaddomains") {
return $this->CDRS->LoadDomains();
} else if ($NetFields['action'] == "reloadcustomers") {
if ($NetFields['customer'] && $NetFields['type']) {
$_customerFilter=array('customer'=>$NetFields['customer'],
'type'=>$NetFields['type']);
}
return $this->reloadCustomers($_customerFilter);
} else {
$log=sprintf ("Error: Invalid request");
syslog(LOG_NOTICE, $log);
return 0;
}
}
function getQuota($account) {
if (!$account) return;
list($username,$domain) = explode("@",$account);
if ($this->enableThor) {
$query=sprintf("select * from sip_accounts where username = '%s' and domain = '%s'",addslashes($username),addslashes($domain));
if (!$this->AccountsDB->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->AccountsDB->Error,$this->AccountsDB->Errno);
syslog(LOG_NOTICE,$log);
return 0;
}
if ($this->AccountsDB->num_rows()) {
$this->AccountsDB->next_record();
$_profile=json_decode(trim($this->AccountsDB->f('profile')));
return $_profile->quota;
} else {
return 0;
}
} else {
$query=sprintf("select quota from subscriber where username = '%s' and domain = '%s'",addslashes($username),addslashes($domain));
if (!$this->AccountsDB->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->AccountsDB->Error,$this->AccountsDB->Errno);
syslog(LOG_NOTICE,$log);
return 0;
}
if ($this->AccountsDB->num_rows()) {
$this->AccountsDB->next_record();
return $this->AccountsDB->f('quota');
} else {
return 0;
}
}
}
function getBlockedByQuotaStatus($account) {
if (!$account) return 0;
list($username,$domain) = explode("@",$account);
if ($this->enableThor) {
$query=sprintf("select * from sip_accounts where username = '%s' and domain = '%s'",addslashes($username),addslashes($domain));
if (!$this->AccountsDB->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->AccountsDB->Error,$this->AccountsDB->Errno);
syslog(LOG_NOTICE,$log);
return 0;
}
if ($this->AccountsDB->num_rows()) {
$this->AccountsDB->next_record();
$_profile=json_decode(trim($this->AccountsDB->f('profile')));
if (in_array('quota',$_profile->groups)) {
return 1;
} else {
return 0;
}
} else {
return 0;
}
} else {
$query=sprintf("select CONCAT(username,'@',domain) as account from grp where grp = 'quota' and username = '%s' and domain = '%s'",addslashes($username),addslashes($domain));
if (!$this->AccountsDB->query($query)) {
$log=sprintf ("Database error for query %s: %s (%s)",$query,$this->AccountsDB->Error,$this->AccountsDB->Errno);
syslog(LOG_NOTICE,$log);
return 0;
}
if ($this->AccountsDB->num_rows()) {
return 1;
} else {
return 0;
}
}
return 0;
}
function getActivePrepaidSessions($active_sessions, $current_balance, $BillingPartyId, $exceptSessions=array()) {
$this->parallel_calls=array();
$this->remaining_balance=$current_balance;
$ongoing_rates=array();
foreach (array_keys($active_sessions) as $_session) {
if (in_array($_session,$exceptSessions)) {
/*
$log = sprintf ("Ongoing prepaid session %s for %s updated",
$_session,
$BillingPartyId
);
syslog(LOG_NOTICE, $log);
*/
continue;
}
$Rate_session = new Rate($this->settings, $this->db);
$passed_time=time()-$active_sessions[$_session]['timestamp'];
$active_sessions[$_session]['passed_time']=$passed_time;
$RateDictionary_session=array(
'duration' => $passed_time,
'callId' => $_session,
'timestamp' => $active_sessions[$_session]['timestamp'],
'DestinationId' => $active_sessions[$_session]['DestinationId'],
'region' => $active_sessions[$_session]['region'],
'domain' => $active_sessions[$_session]['domain'],
'BillingPartyId' => $active_sessions[$_session]['BillingPartyId'],
'ENUMtld' => $active_sessions[$_session]['ENUMtld'],
'RatingTables' => $this->CDRS->RatingTables
);
$Rate_session->calculateAudio($RateDictionary_session);
$log = sprintf ("Active sessions %s for %s to %s: duration=%s, price=%s ",
$_session,
$BillingPartyId,
$active_sessions[$_session]['Destination'],
$passed_time,
$Rate_session->price
);
syslog(LOG_NOTICE, $log);
$ongoing_rates[$_session] = array(
'duration' => $passed_time,
'price' => $Rate_session->price
);
}
if (count($ongoing_rates)) {
// calculate the virtual balance of the user at this moment in time
$due_balance=0;
foreach (array_keys($ongoing_rates) as $_o) {
$due_balance = $due_balance + $ongoing_rates[$_o]['price'];
}
$this->remaining_balance = $this->remaining_balance-$due_balance;
$log = sprintf ("Balance for %s having %d active sessions: database=%s, due=%s, real=%s",$BillingPartyId,count($ongoing_rates),sprintf("%0.4f",$current_balance),sprintf("%0.4f",$due_balance),sprintf("%0.4f",$this->remaining_balance));
syslog(LOG_NOTICE, $log);
}
foreach (array_keys($active_sessions) as $_session) {
if (in_array($_session,$exceptSessions)) {
continue;
}
$RateDictionary_session=array(
'callId' => $_session,
'timestamp' => time(),
'Balance' => $this->remaining_balance,
'DestinationId' => $active_sessions[$_session]['DestinationId'],
'region' => $active_sessions[$_session]['region'],
'domain' => $active_sessions[$_session]['domain'],
'BillingPartyId' => $active_sessions[$_session]['BillingPartyId'],
'ENUMtld' => $active_sessions[$_session]['ENUMtld'],
'RatingTables' => $this->CDRS->RatingTables,
'skipConnectCost' => true
);
if ($active_sessions[$_session]['duration']) {
$RateDictionary_session['duration'] = $active_sessions[$_session]['duration']-$active_sessions[$_session]['passed_time'];
}
$Rate = new Rate($this->settings, $this->db);
$_maxduration = round($Rate->MaxSessionTime($RateDictionary_session));
$log = sprintf("Remaining duration for active session %s of %s to destination %s having balance=%s is %s",
$_session,
$BillingPartyId,
$active_sessions[$_session]['DestinationId'],
$this->remaining_balance,
$_maxduration);
syslog(LOG_NOTICE, $log);
if ($_maxduration > 0) {
$this->parallel_calls[$_session]=array('remainingBalancePerSecond' => $this->remaining_balance/$_maxduration);
} else {
/*
$log = sprintf ("Maxduration for session %s of %s will be negative",$_session,$active_sessions[$_session]['BillingPartyId']);
syslog(LOG_NOTICE, $log);
*/
}
}
return 1;
}
function getAggregatedMaxSessiontime($parallel_calls=array(), $balance, $BillingPartyId) {
$maxduration=0;
$sum_remaining_balance_per_second=0;
foreach (array_keys($parallel_calls) as $_call) {
$sum_remaining_balance_per_second = $sum_remaining_balance_per_second + $parallel_calls[$_call]['remainingBalancePerSecond'];
}
if ($sum_remaining_balance_per_second > 0 ) {
$maxduration =intval($balance/$sum_remaining_balance_per_second);
if (count($parallel_calls) > 1) {
$log = sprintf ("Maximum agregated duration for %s is %s", $BillingPartyId,$maxduration);
syslog(LOG_NOTICE, $log);
}
} else {
/*
$log = sprintf ("Error: sum_remaining_balance_per_second for %s is negative",$BillingPartyId);
syslog(LOG_NOTICE, $log);
*/
$maxduration = 0;
}
return round($maxduration);
}
function keepAlive() {
$query=sprintf("select * from auth_user");
if (!$this->db->query($query) || !$this->db->num_rows()) {
$log=sprintf ("Database error for keepalive query %s: %s (%s)",$query,$this->db->Error,$this->db->Errno);
syslog(LOG_NOTICE, $log);
return false;
}
$log=sprintf("Keepalive successful");
syslog(LOG_NOTICE, $log);
return true;
}
}
function reloadRatingEngineTables () {
global $RatingEngine;
global $DATASOURCES;
if (strlen($RatingEngine['socketIP']) && $RatingEngine['socketPort']) {
if ($RatingEngine['socketIP']=='0.0.0.0' || $RatingEngine['socketIP'] == '0') {
$RatingEngine['socketIPforClients']= '127.0.0.1';
} else {
$RatingEngine['socketIPforClients']=$RatingEngine['socketIP'];
}
// init CDR datasource
$CDR_class = $DATASOURCES[$RatingEngine['cdr_source']]['class'];
$CDRS = new $CDR_class($RatingEngine['cdr_source']);
$CDRS->CacheDestinations();
if ($fp = fsockopen ($RatingEngine['socketIPforClients'], $RatingEngine['socketPort'], $errno, $errstr, 2)) {
fputs($fp, "ReloadRatingTables\n");
fclose($fp);
return true;
}
}
return false;
}
function keepAliveRatingEngine() {
global $RatingEngine;
if (strlen($RatingEngine['socketIP']) && $RatingEngine['socketPort']) {
if ($RatingEngine['socketIP']=='0.0.0.0' || $RatingEngine['socketIP'] == '0') {
$RatingEngine['socketIPforClients']= '127.0.0.1';
} else {
$RatingEngine['socketIPforClients']=$RatingEngine['socketIP'];
}
if ($fp = fsockopen ($RatingEngine['socketIPforClients'], $RatingEngine['socketPort'], $errno, $errstr, 2)) {
fputs($fp, "KeepAlive\n");
fclose($fp);
return true;
}
}
return false;
}
function testRatingTables () {
global $RatingEngine;
if (!strlen($RatingEngine['socketIP']) || !$RatingEngine['socketPort']) {
return false;
}
if ($RatingEngine['socketIP']=='0.0.0.0' || $RatingEngine['socketIP'] == '0') {
$RatingEngine['socketIPforClients']= '127.0.0.1';
} else {
$RatingEngine['socketIPforClients']=$RatingEngine['socketIP'];
}
$i=0;
$b=time();
while ($i < 1000) {
if (!$fp = fsockopen ($RatingEngine['socketIPforClients'], $RatingEngine['socketPort'], $errno, $errstr, 2)) {
print "Error connecting to rating engine\n";
break;
}
$i++;
$number='00'.RandomNumber(1,true).RandomNumber(12).'@example.com';
$duration=RandomNumber(3,true);
$command=sprintf("ShowPrice From=sip:123@example.com To=sip:%s Gateway=10.0.0.1 Duration=%d\n",$number,$duration);
fputs($fp, $command,strlen($command));
$response = fgets($fp, 8192);
fclose($fp);
}
$e=time();
$d=$e-$b;
if ($d) printf("Commands=%d, Time=%s seconds, Speed=%s cps\n",$i,$d,number_format($i/$d,1));
}
?>
diff --git a/log.phtml b/log.phtml
index 00230ae..2125abb 100644
--- a/log.phtml
+++ b/log.phtml
@@ -1,338 +1,342 @@
<?
require("/etc/cdrtool/global.inc");
page_open(
array("sess" => "CDRTool_Session",
"auth" => "CDRTool_Auth",
"perm" => "CDRTool_Perm"));
$loginname=$auth->auth["uname"];
$title = "Logs";
$search_text = $_REQUEST['search_text'];
$task = $_REQUEST['task'];
$current_log = $_REQUEST['current_log'];
$log_description = $_REQUEST['log_description'];
-$next = $_REQUEST['next'];
+$next = intval($_REQUEST['next']);
$maxrowsperpage = 20;
$PHP_SELF = $_SERVER['PHP_SELF'];
$thisMonth = $_REQUEST['thisMonth'];
$db = new DB_CDRTool;
if (is_readable("/etc/cdrtool/local/header.phtml")) {
include("/etc/cdrtool/local/header.phtml");
} else {
include("header.phtml");
}
if ($search_text) {
$search_text=preg_replace("/[^\d|\w| -\.@_]/s","",$search_text);
}
$layout = new pageLayoutLocal();
$layout->showTopMenu($title);
if ($thisMonth) {
$checked_thisMonth='checked';
} else {
$checked_thisMonth='';
}
$where = " (1=1) ";
if ($CDRTool['filter']['reseller']) {
$where .= sprintf (' and reseller_id = %s',addslashes($CDRTool['filter']['reseller']));
} else if (!$perm->have_perm("admin")) {
$where.=sprintf(" and login = '%s'",addslashes($auth->auth["uname"]));
}
if ($perm->have_perm(admin)) {
$query="select * from auth_user where perms like '%admin%'";
$db->query($query);
while ($db->next_record()) {
$Collegues[$db->f('email')] =$db->f('name');
if ($loginname == $db->f('username')) {
$myEmailAddress=$db->f('email');
$myName=$db->f('name');
}
}
} else {
$Collegues[$CDRTool['provider']['toEmail']] = $CDRTool['provider']['name'];
$myName =$CDRTool["loginName"];
$myEmailAddress=$CDRTool["loginEmail"];
}
if ($current_log ) {
if ($task == "edit") {
$query=sprintf("update log set description = '%s' where %s and id = %d",
addslashes($log_description),
$where,
addslashes($current_log));
$db->query($query);
} else if ($task == "mailLog" && $recipient) {
$query=sprintf("select * from log where %s and id = %d",$where,addslashes($current_log));
$db->query($query);
$db->next_record();
$rerun =$db->f('rerun');
$description =$db->f('description');
if ($_SERVER['HTTPS']=="on") {
$protocolURL="https://";
} else {
$protocolURL="http://";
}
$subject="CDRTool";
$fullURL=$protocolURL.$_SERVER['HTTP_HOST'].$CDRTool['tld']."/".$rerun;
$body="CDRTool query to analize:\n\n$fullURL\n\n";
if ($description) {
$body=$body."The query id $current_log is saved with name \"$description\"\n\n";
$subject=$subject.": ".$description;
}
$body=$body."This notification has been sent to you from CDRTool log interface by $myName";
mail($recipient,$subject,$body,"From: $myEmailAddress");
print "<p>Notified $recipient.";
}
}
if ($search_text) {
$where.= sprintf(" and (description like '%s%s%s' or url like '%s' or id = '%s')",
"%",addslashes($search_text),"%",
addslashes($search_text),
addslashes($search_text));
$search_text_enc=urlencode($search_text);
$url_log .="&search_text=$search_text_enc";
}
if ($thisMonth) {
$where.= sprintf(" and date like '%s'",date ('Y-m').'%');
$url_log .= "&thisMonth=1";
}
$query = sprintf("select count(*) as records from log where %s ",$where);
if ($db->query($query)) {
$db->next_record();
$rows = $db->f('records');
} else {
$rows = 0;
}
if (!$next) {
$i=0;
$next=0;
} else {
$i=$next;
}
$j=0;
$z=0;
print "
<form method=post action=$PHP_SELF>
<table border=0 align=center>
<tr>
<td>
Found $rows records.
</td>
<td>
<div class='input-append'>
<input class=span2 type=text size=30 name=search_text value=\"$search_text\"><button class='btn btn-primary' type=submit value=Search>Search</button></div>
</td>
<td>
<input type=checkbox name=thisMonth value=1 $checked_thisMonth>
Only this month?
</td>
</tr>
</table>
</form>
";
if ($rows>0) {
if ($rows > $maxrowsperpage) {
$maxrows=$maxrowsperpage+$next;
if ($maxrows > $rows) {
$maxrows=$rows;
$prev_rows=$maxrows;
}
} else {
$maxrows=$rows;
}
- $query = sprintf("select * from log where %s order by id desc limit %d, %d",$where,$i,$maxrowsperpage);
+ $_max_rows= intval($maxrowsperpage);
+ if (!$_max_rows) {
+ $_max_rows = 10;
+ }
+ $query = sprintf("select * from log where %s order by id desc limit %d, %d",addslashes($where),intval($i),$_max_rows);
$db->query($query);
print "<br/>
<table id='log' class='table table-striped table-condensed' width=100% align=center>
<thead>
<tr>
<th> </th>
<th> <b>Log id</th>
<th> <b>Reseller</th>
<th> <b>Date and time</th>
<th> <b>Account</th>
<th> <b>IP address</th>
<th> <b>Data source</th>
<th> <b>Rows</th>
<th> <b>Description </th>
<th> <b>Actions</th>
</tr>
</thead>
";
while ($i<$maxrows) {
$found=$i+1;
$db->next_record();
$current_log =$db->f('id');
$reseller_id =$db->f('reseller_id');
$log_date =$db->f('date');
$login =$db->f('login');
$ip =$db->f('ip');
$url =$db->f('url');
$reedit =$db->f('reedit');
$rerun =$db->f('rerun');
$results =$db->f('results');
$description =$db->f('description');
$datasource =$db->f('datasource');
if ($rerun && $DATASOURCES[$datasource]['name']) {
$datasource_print=$DATASOURCES[$datasource]['name'];
} else {
$datasource_print=$datasource;
}
if (!$reedit || !$rerun) {
if (preg_match("/do_search/", $url)) {
$url_run="<a href=\"../search_call/$url"."&history_id=$current_log"."\">Run</a>";
$url_edit=preg_replace("/do_/","",$url);
$url_edit="<a href=\"../search_call/$url_edit\">Edit</a>";
$display_form=1;
} elseif (preg_match("/do_statistics/", $url)) {
$url_run="<a href=\"../statistics/$url"."&history_id=$current_log"."\">Run</a>";
$url_edit=preg_replace("/do_/","",$url);
$url_edit="<a href=\"../statistics/$url_edit\">Edit stat</a>";
$display_form=1;
} else {
$url_edit="";
$url_run="";
$display_form=0;
}
} else {
$display_form=1;
$url_run="<a class='btn' href=\"$rerun\">Run</a>";
$url_edit="<a class='btn btn-info' href=\"$reedit\">Edit</a>";
}
$rr=floor($found/2);
$mod=$found-$rr*2;
if ($mod ==0) {
//$bgcolor="lightgrey";
} else {
//$bgcolor="white";
}
print "
<tr>
<td class=cdr><b>$found.</b></td>
<td class=cdr>$current_log</td>
<td class=cdr>$reseller_id</td>
<td class=cdr>$log_date</td>
<td class=cdr>$login</td>
<td class=cdr>$ip</td>
<td class=cdr>$datasource_print</td>
<td class=cdr>$results</td>
<td class=cdr><form class='cform form-inline' method=post>";
if ($display_form == 1) {
print "
<input type=hidden name=current_log value=\"$current_log\">
<input type=hidden name=task value=edit>
<input type=hidden name=next value=$next>
<input type=hidden name=search_text value=\"$search_text\">
<div class='input-append'>
<input type=text class=span2 size=25 name=log_description value=\"$description\"><button class=btn type=submit value=Save>Save</button>
</div>
";
} else {
print "$description";
}
print "</form>
</td> <td class=cdr>
<form class='cform form-inline' method=post>
<div class='btn-group'>
$url_run $url_edit
";
if (strlen($description) && $rerun) {
print "
<button class='btn' type=submit value=Notify>Notify</button>
<select class=span3 name=recipient>
";
foreach(array_keys($Collegues) as $col) {
print "<option value=\"$col\">$Collegues[$col]";
}
print "
</select>
<input type=hidden name=current_log value=\"$current_log\">
<input type=hidden name=task value=mailLog>
<input type=hidden name=next value=$next>
<input type=hidden name=search_text value=\"$search_text\">
";
}
print "</div></form>
</td>
</tr>
";
$i++;
}
print "</table>
";
}
print "
<ul class=\"pager\">
";
if ($next!=0 ) {
$show_next=$maxrowsperpage-$next;
if ($show_next < 0) {
$mod_show_next = $show_next-2*$show_next;
}
$url_prev =$PHP_SELF."?".$url_log."&action=search&next=$mod_show_next";
print "<li><a href=\"$url_prev\">&larr; Previous</a></li>";
}
if ($rows>$maxrowsperpage && $rows!=$maxrows) {
$show_next =$maxrowsperpage+$next;
$url_next =$PHP_SELF."?".$url_log."&action=search&next=$show_next";
print "<li><a href=\"$url_next\">Next &rarr;</a></li>";
}
print "
</div>
";
$layout->showFooter();
print "
</body>
</html>
";
page_close();
?>
diff --git a/phplib/ct_sql.inc b/phplib/ct_sql.inc
index 4fb349c..8df6224 100644
--- a/phplib/ct_sql.inc
+++ b/phplib/ct_sql.inc
@@ -1,153 +1,155 @@
<?php
##
## Copyright (c) 1998,1999 SH Online Dienst GmbH
## Boris Erdmann, Kristian Koehntopp
##
## Copyright (c) 1998,1999 Sascha Schumann <sascha@schumann.cx>
##
## $Id: ct_sql.inc,v 1.2 2004-07-06 11:46:04 adigeo Exp $
##
## PHPLIB Data Storage Container using a SQL database
##
class CT_Sql {
##
## Define these parameters by overwriting or by
## deriving your own class from it (recommened)
##
var $database_table = "active_sessions";
var $database_class = "DB_Sql";
var $database_lock_semaphore = "";
var $encoding_mode = "base64";
## end of configuration
var $db;
function ac_start() {
$name = $this->database_class;
$this->db = new $name;
}
function ac_get_lock() {
if ( "" != $this->database_lock_semaphore ) {
$query = sprintf("SELECT get_lock('%s')", $this->database_lock_semaphore);
while ( ! $this->db->query($query)) {
$t = 1 + time(); while ( $t > time() ) { ; }
}
}
}
function ac_release_lock() {
if ( "" != $this->database_lock_semaphore ) {
$query = sprintf("SELECT release_lock('%s')", $this->database_lock_semaphore);
$this->db->query($query);
}
}
function ac_gc($gc_time, $name) {
$timeout = time();
$sqldate = date("YmdHis", $timeout - ($gc_time * 60));
$this->db->query(sprintf("DELETE FROM %s WHERE changed < '%s' AND name = '%s'",
$this->database_table,
$sqldate,
addslashes($name)));
}
function ac_store($id, $name, $str) {
$ret = true;
+ if (strstr($id, " ")) {
+ return false;
+ }
switch ( $this->encoding_mode ) {
case "slashes":
$str = addslashes($name . ":" . $str);
break;
case "base64":
default:
$str = base64_encode($name . ":" . $str);
};
$name = addslashes($name);
## update duration of visit
global $HTTP_REFERER, $HTTP_USER_AGENT, $REMOTE_ADDR;
$now = date("YmdHis", time());
$uquery = sprintf("update %s set val='%s', changed='%s', count=count+1 where sid='%s' and name='%s'",
$this->database_table,
- $str,
+ addslashes($str),
$now,
addslashes($id),
- $name);
- $iquery = sprintf("insert
- into %s ( sid, name, val, changed ) values ('%s', '%s', '%s', '%s')",
+ addslashes($name));
+ $iquery = sprintf("insert into %s ( sid, name, val, changed ) values ('%s', '%s', '%s', '%s')",
$this->database_table,
addslashes($id),
$name,
- $str,
+ addslashes($str),
$now);
$this->db->query($uquery);
if ($this->db->affected_rows()==0 &&
!$this->db->query($iquery)) {
$ret = false;
}
return $ret;
}
function ac_delete($id, $name) {
$this->db->query(sprintf("delete from %s where name = '%s' and sid = '%s'",
$this->database_table,
addslashes($name),
addslashes($id)));
}
function ac_get_value($id, $name) {
$this->db->query(sprintf("select val from %s where sid = '%s' and name = '%s'",
$this->database_table,
addslashes($id),
addslashes($name)));
if ($this->db->next_record()) {
$str = $this->db->f("val");
$str2 = base64_decode( $str );
if ( preg_match("/^$name:.*/", $str2) ) {
$str = preg_replace("/^$name:/", "", $str2 );
} else {
$str3 = stripslashes( $str );
if ( preg_match("/^$name:.*/", $str3) ) {
$str = preg_replace("/^$name:/", "", $str3 );
} else {
switch ( $this->encoding_mode ) {
case "slashes":
$str = stripslashes($str);
break;
case "base64":
default:
$str = base64_decode($str);
}
}
};
return $str;
};
return "";
}
function ac_newid($str, $name) {
return $str;
}
function ac_halt($s) {
$this->db->halt($s);
}
}
?>

File Metadata

Mime Type
text/x-diff
Expires
Sat, Feb 1, 10:36 AM (22 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3489209
Default Alt Text
(642 KB)

Event Timeline