" . _("Call History") . "


"; return $ret; } /* * Acts on the selected call monitor recordings in the method indicated by the action and updates page * * @param $args * Common arguments */ function recAction($args) { // args $m = getArgument($args,'m'); $a = getArgument($args,'a'); $q = getArgument($args,'q'); $start = getArgument($args,'start'); $span = getArgument($args,'span'); $order = getArgument($args,'order'); $sort = getArgument($args,'sort'); $duration_filter = getArgument($args,'duration_filter'); // get files $files = array(); foreach($_REQUEST as $key => $value) { if (preg_match('/selected/',$key)) { array_push($files, $value); } } if ($a=='delete') { $this->deleteRecData($files); } if ($a=='ignore') { $start = 0; setcookie("ari_duration_filter", $duration_filter, time()+365*24*60*60); } // redirect to see updated page $ret .= " "; return $ret; } /* * Displays stats page * * @param $args * Common arguments */ function display($args) { global $ASTERISK_CALLMONITOR_PATH; global $CALLMONITOR_ALLOW_DELETE; global $AJAX_PAGE_REFRESH_ENABLE; $display = new DisplaySearch(); // get the search string $m = getArgument($args,'m'); $f = getArgument($args,'f'); $q = getArgument($args,'q'); $start = getArgument($args,'start'); $span = getArgument($args,'span'); $order = getArgument($args,'order'); $sort = getArgument($args,'sort'); $duration_filter = getArgument($args,'duration_filter'); $start = $start=='' ? 0 : $start; $span = $span=='' ? 15 : $span; $order = $order=='' ? 'calldate' : $order; $sort = $sort=='' ? 'desc' : $sort; $displayname = $_SESSION['ari_user']['displayname']; $extension = $_SESSION['ari_user']['extension']; // get data $record_count = $this->getCdrCount($q,$duration_filter); $data = $this->getCdrData($q,$duration_filter,$start,$span,$order,$sort); // get the call monitor recording files $paths = split(';',$ASTERISK_CALLMONITOR_PATH); foreach($paths as $key => $path) { if (!is_dir($path)) { $_SESSION['ari_error'] .= sprintf(_("Path is not a directory: %s"),$path) . "
"; } } $recordings = $this->getRecordings($ASTERISK_CALLMONITOR_PATH,$data); // build controls if ($CALLMONITOR_ALLOW_DELETE) { $controls .= "  "; } $controls .= " " . _("duration") . " "; // table header if ($CALLMONITOR_ALLOW_DELETE) { $recording_delete_header = ""; } $fields[0]['field'] = "calldate"; $fields[0]['text'] = _("Date"); $fields[1]['field'] = "calldate"; $fields[1]['text'] = _("Time"); $fields[2]['field'] = "clid"; $fields[2]['text'] = _("Caller ID"); $fields[3]['field'] = "src"; $fields[3]['text'] = _("Source"); $fields[4]['field'] = "dst"; $fields[4]['text'] = _("Destination"); $fields[5]['field'] = "dcontext"; $fields[5]['text'] = _("Context"); $fields[6]['field'] = "duration"; $fields[6]['text'] = _("Duration"); $i = 0; while ($fields[$i]) { $field = $fields[$i]['field']; $text = $fields[$i]['text']; if ($order==$field) { if ($sort=='asc') { $currentSort = 'desc'; $arrowImg = "sort"; } else { $currentSort = 'asc'; $arrowImg = "sort"; } if ($i==1) { $arrowImg = ''; } } else { $arrowImg = ''; $currentSort = 'desc'; } $unicode_q = urlencode($q); $recording_header .= "" . $text . $arrowImg . ""; $i++; } $recording_header .= "" . _("Monitor") . ""; // table body foreach($data as $key=>$value) { // recording file $recording = $recordings[$value['uniqueid'] . $value['calldate']]; // date and time $buf = split(' ', $value[calldate]); $date = $buf[0]; $time = $buf[1]; // recording delete checkbox if ($CALLMONITOR_ALLOW_DELETE) { $recording_delete_checkbox = ""; } $recordingLink = ''; if (is_file($recordings[$value['uniqueid'] . $value['calldate']])) { $recordingLink = "" . _("play") . ""; } $recording_body .= " " . $recording_delete_checkbox . " " . $date . " " . $time . " " . $value[clid] . " " . $value[src] . " " . $value[dst] . " " . $value[dcontext] . " " . $value[duration] . " sec " . $recordingLink . " "; } if (!count($data)) { $recording_body .= ""; } // options $url_opts = array(); $url_opts['sort'] = $sort; $url_opts['order'] = $order; $url_opts['duration_filter'] = $duration_filter; // build page content $ret .= checkErrorMessage(); // ajax page refresh script if ($AJAX_PAGE_REFRESH_ENABLE) { // $ret .= ajaxRefreshScript($args); } // header if ($_SESSION['ari_user']['admin_callmonitor']) { $header_text = _("Call History"); } else { $header_text = sprintf(_("Call History for %s (%s)"),$displayname,$extension); } $ret .= $display->displayHeaderText($header_text); $ret .= $display->displaySearchBlock('left',$m,$q,$url_opts,true); // start form if ($CALLMONITOR_ALLOW_DELETE) { $ret .= "
"; } $ret .= $display->displayInfoBarBlock($controls,$q,$start,$span,$record_count); // javascript for popup and message actions $ret .= " "; // call monitor delete recording controls if ($CALLMONITOR_ALLOW_DELETE) { $ret .= "
" . _("select") . ": " . _("all") . " " . _("none") . "
"; } else { $ret .= "
"; } // table $ret .= " " . $recording_delete_header . " " . $recording_header . " " . $recording_body . "
"; $start = getArgument($args,'start'); $span = getArgument($args,'span'); $order = getArgument($args,'order'); $sort = getArgument($args,'sort'); // end form if ($CALLMONITOR_ALLOW_DELETE) { $ret .= "
"; } $ret .= $display->displaySearchBlock('center',$m,$q,$url_opts,false); $ret .= $display->displayNavigationBlock($m,$q,$url_opts,$start,$span,$record_count); return $ret; } /* * Checks for a recording file * * @param $asterisk_callmonitor_path * path call monitor recording directory on the asterisk server * @param $data * current call monitor recordings on the asterisk server * @return $recording * returns an array of $recording file names if found */ function getRecordings($asterisk_callmonitor_path,$data) { global $CALLMONITOR_ONLY_EXACT_MATCHING; global $CALLMONITOR_AGGRESSIVE_MATCHING; $recordings = array(); $extension = $_SESSION['ari_user']['extension']; $paths = split(';',$asterisk_callmonitor_path); foreach($paths as $key => $path) { $paths[$key] = fixPathSlash($paths[$key]); } $files = array(); if (!$CALLMONITOR_ONLY_EXACT_MATCHING) { $filter = ''; $recursiveMax = 6; $recursiveCount = 0; foreach($paths as $key => $path) { $path_files = getFiles($path,$filter,$recursiveMax,$recursiveCount); if ($path_files) { $files = array_merge($files,$path_files); } } rsort($files); } foreach($data as $data_key => $data_value) { $recording=''; $calldate = $data_value['calldate']; $duration = $data_value['duration']; $lastdata = $data_value['lastdata']; $uniqueid = $data_value['uniqueid']; $userfield = $data_value['userfield']; // timestamps $st = trim(strtotime($calldate)); $et = trim(strtotime($calldate) + $duration); // for on-demand call recordings // unique file key if ($uniqueid) { $buf = preg_replace('/\-|\:/', '', $calldate); $calldate_key = preg_replace('/\s+/', '-', $buf); $unique_file_key = $calldate_key . "-" . $uniqueid; } if ($unique_file_key=='') { $buf = preg_split("/\|/", $lastdata); $unique_file_key = $buf[1]; } $recordingLink = ''; foreach($paths as $callmonitor_key => $path) { // try to find an exact match using the uniqueid if (isset($uniqueid)) { $check_files = array(); array_push($check_files,$path . $uniqueid . ".WAV"); array_push($check_files,$path . $uniqueid . ".wav"); array_push($check_files,$path . $uniqueid . ".gsm"); array_push($check_files,$path . $unique_file_key . ".WAV"); array_push($check_files,$path . $unique_file_key . ".wav"); array_push($check_files,$path . $unique_file_key . ".gsm"); array_push($check_files,$path . "g" . $extension . "-" . $unique_file_key . ".WAV"); array_push($check_files,$path . "g" . $extension . "-" . $unique_file_key . ".wav"); array_push($check_files,$path . "g" . $extension . "-" . $unique_file_key . ".gsm"); array_push($check_files,$path . "q" . $extension . "-" . $unique_file_key . ".WAV"); array_push($check_files,$path . "q" . $extension . "-" . $unique_file_key . ".wav"); array_push($check_files,$path . "q" . $extension . "-" . $unique_file_key . ".gsm"); array_push($check_files,$path . "OUT" . $extension . "-" . $unique_file_key . ".WAV"); array_push($check_files,$path . "OUT" . $extension . "-" . $unique_file_key . ".wav"); array_push($check_files,$path . "OUT" . $extension . "-" . $unique_file_key . ".gsm"); array_push($check_files,$path . $userfield); // try to match foreach($check_files as $check_file) { if (is_file($check_file)) { $recording = $check_file; break; } } } // if found do not need to check the rest of the paths if ($recording!='') { break; } } // get all the callmonitor recordings on server and try to find a non-exact match for this log entry if (!$CALLMONITOR_ONLY_EXACT_MATCHING) { // try to find a file using the uniqueid if (!$recording) { // try and match the unique id if (!$recording) { foreach($files as $key => $path) { if (strlen($uniqueid)>1 && strpos($path,$uniqueid)!==FALSE) { $recording = $path; $files[$key] = ''; // remove it from the recording files so it will not be matched twice break; } } } } // try and match a file using the calldate (if no unique number from database) if (!$recording) { foreach($files as $key => $path) { $parts = split("-", $path); if (strlen($st)>1 && (strpos($path,$st)!==FALSE) || (strpos($path,"auto")!==FALSE && $parts[1] >= $st && $parts[1] <= $et)) { $recording = $path; $files[$key] = ''; // remove it from the recording files so it will not be matched twice break; } } } if ($CALLMONITOR_AGGRESSIVE_MATCHING) { // one last stab at finding a recording by adding one or two seconds to the call time if (!$recording) { $st_1 = trim($st+1); $st_2 = trim($st+2); $et_1 = trim($et+1); $et_2 = trim($et+2); foreach($files as $key => $path) { $split = explode("-", $path); if (strlen($st)>1 && ((strpos($path,$st_1)!==FALSE) || (strpos($path,$st_2)!==FALSE) || (strpos($path,"auto")!==FALSE && $parts[1] >= $st_1 && $parts[1] <= $et_1) || (strpos($path,"auto")!==FALSE && $parts[1] >= $st_2 && $parts[1] <= $et_2))) { $recording = $path; $files[$key] = ''; // remove it from the recording files so it will not be matched twice break; } } } } } // add to array to be returned if ($recording) { $recordings[$uniqueid . $calldate] = $recording; } } return $recordings; } /* * Deletes selected call monitor recordings * * @param $files * Array of files to delete */ function deleteRecData($files) { foreach($files as $key => $file) { if (is_writable($file)) { unlink($file); } else { $_SESSION['ari_error'] = _("Only deletes recording files, not cdr log"); } } } /* * Gets cdr record count * * @param $q * query text */ function getSearchText($q,$duration_filter) { // search text if ($q!='*' && $q!=NULL) { $searchText .= "WHERE "; $tok = strtok($q," \n\t"); while ($tok) { $searchText .= " (calldate regexp '" . $tok . "' OR clid regexp '" . $tok . "' OR src regexp '" . $tok . "' OR dst regexp '" . $tok . "' OR dstchannel regexp '" . $tok . "' OR dcontext regexp '" . $tok . "' OR duration regexp '" . $tok . "' OR disposition regexp '" . $tok . "' OR uniqueid regexp '" . $tok . "' OR userfield regexp '" . $tok . "' )"; $tok = strtok(" \n\t"); if ($tok) { $searchText .= " AND"; } } } // duration_filter if ($duration_filter) { if (!$searchText) { $searchText .= "WHERE "; } else { $searchText .= "AND "; } $searchText .= "duration>" . $duration_filter . " "; } // admin if (!$_SESSION['ari_user']['admin_callmonitor']) { if (!$searchText) { $searchText .= "WHERE "; } else { $searchText .= "AND "; } // allow entries to be viewed with users extension $searchText .= "(src = '" . $_SESSION['ari_user']['extension'] . "' OR dst = '" . $_SESSION['ari_user']['extension'] . "' OR channel LIKE 'IAX2/" . $_SESSION['ari_user']['extension'] ."-%' OR dstchannel LIKE 'IAX2/" . $_SESSION['ari_user']['extension'] ."-%' OR channel LIKE 'SIP/" . $_SESSION['ari_user']['extension'] ."-%' OR dstchannel LIKE 'SIP/" . $_SESSION['ari_user']['extension'] ."-%')"; // allow entries to be viewed with users outbound CID if (isset($_SESSION['ari_user']['outboundCID']) && trim($_SESSION['ari_user']['outboundCID']) != '') { $searchText .= "OR (src = '" . $_SESSION['ari_user']['outboundCID'] . "' OR dst = '" . $_SESSION['ari_user']['outboundCID'] . "')"; } } return $searchText; } /* * Gets cdr record count * * @param $q * query text * @return $count * Number of cdr records counted */ function getCdrCount($q,$duration_filter) { global $ASTERISKCDR_DBTABLE; $searchText = $this->getSearchText($q,$duration_filter); $dbh = $_SESSION['dbh_cdr']; $sql = "SELECT count(*) FROM " . $ASTERISKCDR_DBTABLE . " " . $searchText; $result = $dbh->getAll($sql); if (DB::isError($result)) { $_SESSION['ari_error'] = $result->getMessage(); return; } $count = $result[0][0]; return $count; } /* * Gets cdr data * * @param $q * query text * @param $start * start record * @param $span * number of records to return * @return $data * cdr data to be returned */ function getCdrData($q,$duration_filter,$start,$span,$order,$sort) { global $ASTERISKCDR_DBTABLE; $data = array(); $searchText = $this->getSearchText($q,$duration_filter); $dbh = $_SESSION['dbh_cdr']; $sql = "SELECT * FROM " . $ASTERISKCDR_DBTABLE . " " . $searchText . " ORDER BY " . $order . " " . $sort . " LIMIT " . $start . "," . $span; $result = $dbh->getAll($sql,DB_FETCHMODE_ASSOC); if (DB::isError($result)) { $_SESSION['ari_error'] = $result->getMessage(); return; } $data = $result; return $data; } } ?>