1 <?php
3 class fonreport extends plugin
4 {
5 /* Definitions */
6 var $plHeadline= "Phone Reports";
7 var $plDescription= "View the phone report for incoming and outgoing calls";
8 var $plIcon = "plugins/gofon/images/phonereport.png";
10 var $ui = NULL;
12 /* For internal use */
13 var $start = 0;
14 var $search_for = "*";
15 var $search_base = "";
16 var $year = "";
17 var $month = "";
18 var $sort = 0;
19 var $sort_direction = "down";
20 var $range = 20;
21 var $selected_server= "";
23 /* attribute list for save action */
24 var $fields = array("calldate", "src", "dst", "channel", "lastapp", "disposition", "duration");
25 var $attributes_SO = array("start","search_for","search_base","range","month","sort_direction","sort","year");
26 var $objectclasses = array();
27 var $view_logged = FALSE;
29 var $telephoneNumberToDN = array();
31 /* Construct class */
32 function fonreport (&$config, $ui)
33 {
34 /* Include config object */
35 $this->config = $config;
36 $this->ui = $ui;
37 $this->search_base= $this->config->current['BASE'];
39 $this->month = date("m");
40 $this->year = date("Y");
42 /* Use filter settings if we have already searched */
43 if (!session::is_set("fonfilter")){
44 $fonfilter = array();
45 foreach($this->attributes_SO as $name){
46 $fonfilter[$name]=$this->$name;
47 }
48 session::set("fonfilter", $fonfilter);
49 }else{
50 $fonfilter = session::get("fonfilter");
51 foreach($this->attributes_SO as $name){
52 $this->$name = $fonfilter[$name];
53 }
54 }
56 // Get ALL valid FAX-Accounts and their dns, this allows us to perform correct
57 // permissions checks later.
58 $filter= "(&(objectClass=gosaAccount)(!(objectClass=gosaUserTemplate))".
59 "(objectClass=goFonAccount)(telephoneNumber=*))";
60 $tmp= get_list($filter, "users/viewFonEntries", $this->search_base,
61 array("telephoneNumber"), GL_SUBSEARCH | GL_NO_ACL_CHECK);
62 $this->telephoneNumberToDN = array();
63 foreach($tmp as $attrs){
64 for($i=0;$i<$attrs['telephoneNumber']['count']; $i++){
65 $this->telephoneNumberToDN[$attrs['telephoneNumber'][$i]] = $attrs['dn'];
66 }
67 }
68 }
71 /* Save ui interactions and store results in session,
72 to remember settings */
73 function save_object()
74 {
75 $fonfilter= session::get("fonfilter");
76 if(isset($_POST['EntryPerPage'])){
77 $this->range = $_POST['EntryPerPage'];
78 }
79 if (isset($_GET['start'])){
80 $this->start= (int)$_GET['start'];
81 }
82 foreach( array("year", "month", "search_for","selected_server") as $type){
83 if (isset($_POST[$type])){
84 $this->$type= get_post($type);
85 }
86 }
88 /* Adapt sorting */
89 if (isset($_GET['sort'])){
90 if ($this->sort == (int)$_GET['sort']){
91 if ($this->sort_direction == "down"){
92 $this->sort_direction= "up";
93 } else {
94 $this->sort_direction= "down";
95 }
96 }
97 $this->sort= (int)$_GET['sort'];
98 if ($this->sort < 0 || $this->sort > 6){
99 $this->sort= 0;
100 }
101 }
103 /* remove unwanted tags */
104 $this->search_for = stripslashes(preg_replace("/[^0-9a-z\*\+ \-\/]/i","",$this->search_for));
106 foreach($this->attributes_SO as $name){
107 $fonfilter[$name] = $this->$name;
108 }
109 session::set("fonfilter", $fonfilter);
110 }
113 /* Search & display results */
114 function execute()
115 {
116 /* Call parent execute */
117 plugin::execute();
119 // Use the configured global timezone settings
120 timezone::get_default_timezone();
122 /* GVet template engine */
123 $smarty= get_smarty();
125 /* Log view */
126 if(!$this->view_logged){
127 $this->view_logged = TRUE;
128 new log("view","fonreport/".get_class($this),$this->dn);
129 }
131 /*****************
132 Variable Init
133 *****************/
135 $fields_str = "";
137 $months= array();
138 for($i = 1 ; $i <= 12 ; $i ++ ){
139 $months[$i] = _(date("F",gmmktime(0,0,0,$i)));
140 }
142 /* Prepare template */
143 $current= date("Y");
144 $years= array();
145 for ($y= $current - 5; $y<=$current; $y++){
146 $years[$y]= $y;
147 }
149 /*****************
150 Smarty
151 *****************/
153 $smarty->assign("plug", "?plug=".validate($_GET['plug']));
154 $smarty->assign("search_for", htmlentities($this->search_for));
155 $smarty->assign("months", $months);
156 $smarty->assign("month_select", $this->month);
157 $smarty->assign("years", $years);
158 $smarty->assign("year_select", $this->year);
159 $smarty->assign("search_result", "");
162 /*****************
163 Check Database , Table , Connection
164 *****************/
166 // Collect servers and allow to select the server in the ui.
167 $servers = array();
168 foreach($this->config->data['SERVERS']['FON'] as $key => $server){
169 $servers[$server['SERVER']] = $server['SERVER'];
170 }
171 $smarty->assign("servers", $servers);
172 $smarty->assign("selected_server", $this->selected_server);
174 /* Connecting, selecting database */
175 if (!isset($this->config->data['SERVERS']['FON'][0])){
176 msg_dialog::display(_("Configuration error"), msgPool::noserver(
177 _("GOfon")), WARNING_DIALOG);
178 return($smarty->fetch(get_template_path('contents.tpl', TRUE)));
179 }elseif(!is_callable("mysql_connect")){
180 msg_dialog::display(_("Configuration error"), msgPool::missingext("php-mysql"), WARNING_DIALOG);
181 return($smarty->fetch(get_template_path('contents.tpl', TRUE)));
182 }else{
184 // Get CFG for the selected server, if empty use first.
185 if($this->selected_server == ""){
186 $cfg= $this->config->data['SERVERS']['FON'][0];
187 }else{
188 foreach($this->config->data['SERVERS']['FON'] as $server){
189 if($server['SERVER'] == $this->selected_server){
190 $cfg = $server;
191 }
192 }
193 }
195 $link = @mysql_pconnect($cfg['SERVER'], $cfg['LOGIN'], $cfg['PASSWORD']);
196 if ($link === FALSE){
197 msg_dialog::display(_("Error"), msgPool::dbconnect(
198 _("GOfon"),@mysql_error(),$cfg['SERVER']),ERROR_DIALOG);
199 return($smarty->fetch(get_template_path('contents.tpl', TRUE)));
200 }
201 if (! @mysql_select_db("gophone")){
202 msg_dialog::display(_("Error"), msgPool::dbselect(
203 _("GOfon"),@mysql_error(),$cfg['DB']),ERROR_DIALOG);
204 return($smarty->fetch(get_template_path('contents.tpl', TRUE)));
205 }
206 }
209 /*****************
210 Get Query String && Search
211 *****************/
213 // Get entries for the selected range only.
214 $link = @mysql_pconnect($cfg['SERVER'], $cfg['LOGIN'], $cfg['PASSWORD']);
215 @DEBUG (DEBUG_MYSQL, __LINE__, __FUNCTION__, __FILE__,$query, "Database query");
216 $query = $this->CreateQuerySyntax();
217 $result = @mysql_query($query);
218 if ($result === false){
219 msg_dialog::display(_("Error"), msgPool::dbquery(
220 _("GOfon"),@mysql_error(),$cfg['SERVER']),ERROR_DIALOG);
221 return($smarty->fetch(get_template_path('contents.tpl', TRUE)));
222 }
225 /*****************
226 Fetch results
227 *****************/
229 $report_list= array();
231 /* Restricted attributes will not be displayed, this will be displayed instead */
232 $no_acl = "<img class='center' src='images/lists/locked.png'
233 title='".msgPool::permView()."' alt='"._("Insufficient permissions")."'>";
235 $no_acl = " -";
237 while ($line = mysql_fetch_array($result, MYSQL_ASSOC)) {
239 // Get dn to check ACLs for
240 // Existing ldap-user -> use its dn
241 // Not existing user -> use ldap base dn
242 $dn = $this->search_base;
243 if(isset($this->telephoneNumberToDN[$line['src']])){
244 $dn = $this->telephoneNumberToDN[$line['src']];
245 }
246 // We do not have any ACLs for this entry, so continue.
247 $acls = $this->ui->get_permissions($dn,"users/viewFonEntries","");
248 if(!preg_match("/r/",$acls)){
249 continue;
250 }
252 // Check attribute permissions
253 foreach($line as $attr => $value){
254 if($attr == "duration") continue;
255 $acl = $this->ui->get_permissions($dn,"users/viewFonEntries",$attr);
256 if(!preg_match("/r/",$acl)){
257 $line[$attr] = $no_acl;
258 }
259 }
261 // Check date permissions
262 if($this->ui->get_permissions($dn,"users/viewFonEntries","calldate")){
263 $hour= substr($line["calldate"], 11, 2);
264 $minute=substr($line["calldate"], 14, 2);
265 $format= _("Y-M-D");
266 $date= preg_replace("/Y/", substr($line["calldate"], 0, 4), $format);
267 $date= preg_replace("/M/", substr($line["calldate"], 5, 2), $date);
268 $date= preg_replace("/D/", substr($line["calldate"], 8, 2), $date);
269 $date_str = $date." ".$hour.":".$minute;
270 }else{
271 $date_str = $no_acl;
272 }
274 $append_str = "<td class='list1'>".$date_str."</td>";
275 foreach(array("src","dst","channel","lastapp","disposition") as $atr){
276 if(isset($line[$atr])){
277 $append_str .= "<td class='list1'>".$line[$atr]."</td>";
278 }
279 }
280 if($this->ui->get_permissions($dn,"users/viewFonEntries","duration")){
281 $append_str .= "<td class='list1' style='border-right: 0pt none;'>".
282 $this->gen_duration($line["duration"])."</td>";
283 }else{
284 $append_str .= "<td class='list1' style='border-right: 0pt none;'>".
285 $no_acl."</td>";
286 }
287 $report_list[] = $append_str;
288 }
290 @mysql_close($link);
293 /*****************
294 Create list of results
295 *****************/
297 $res_count = count($report_list);
298 $report_list = array_slice($report_list, $this->start, $this->range);
299 if($res_count < $this->start) $this->start = 0;
301 /* Generate output */
302 $output ="";
303 foreach($report_list as $val){
304 $output.= "<tr>$val</tr>";
305 }
307 /*****************
308 Tell smarty what we have found
309 *****************/
311 $smarty->assign("search_result", $output);
312 $smarty->assign("range_selector", range_selector($res_count, $this->start,$this->range,"EntryPerPage"));
314 /* Show main page */
315 for($i= 0; $i<7; $i++){
316 $smarty->assign("mode$i", "");
317 }
318 $smarty->assign("mode".$this->sort, image("images/lists/sort-".$this->sort_direction.".png"));
320 return($smarty->fetch(get_template_path('contents.tpl', TRUE)));
321 }
324 /* Create duration string 12'11" */
325 function gen_duration($seconds)
326 {
327 if ($seconds / 60 > 1){
328 $minutes= (int)($seconds / 60);
329 $seconds= $seconds % 60;
330 return ("$minutes’$seconds”");
331 }
332 return ("$seconds”");
333 }
336 /* Create WHERE part for our mysql serach */
337 function GetUidMatchingFilter()
338 {
339 $ldap= $this->config->get_ldap_link();
340 $ldap->cd($this->search_base);
341 $s = $this->search_for;
343 $s = preg_replace("/\%/","",$s);
344 $s2 = preg_replace("/\*/","%",$s);
346 $filter = "(&(objectClass=gosaAccount)(!(objectClass=gosaUserTemplate))".
347 "(|(uid=$s)(l=$s)(homePhone=$s)(telephoneNumber=$s)(facsimileTelephoneNumber=$s)(mobile=$s)".
348 "(pager=$s)(cn=$s)(givenName=$s)(sn=$s)(personalTitle=$s)(title=$s)))";
350 $attrs = array("uid");
351 $res = get_list($filter,"users/viewFonEntries",$this->search_base,$attrs);
353 $str = " AND (";
354 $fields = array("dstchannel","channel");
355 if(count($res)){
356 foreach($res as $attrs){
357 $uid = $attrs["uid"][0];
358 foreach($fields as $name){
359 $str .= $name." like '%".$uid."%' OR ";
360 }
361 }
362 }
363 $str .= " channel like '%".$s."%' OR
364 dstchannel like '%".$s."%' OR
365 dst like '%".$s2."%' OR
366 src like '%".$s2."%' OR
367 lastapp like '%".$s2."%')";
368 return($str);
369 }
372 /* Create query string */
373 function CreateQuerySyntax()
374 {
375 /* Get extended search filter which contain uids and so on */
376 $uidstring = $this->GetUidMatchingFilter();
378 /* Create string with all fields seperated by ,*/
379 $fields_str ="";
380 foreach($this->fields as $field){
381 if($field == "calldate") {
382 continue;
383 }
384 $fields_str .= $field.", ";
385 }
386 $fields_str = preg_replace("/, $/","",$fields_str);
388 /* Create Sort tag */
389 if ($this->sort_direction == "down"){
390 $desc= "DESC";
391 } else {
392 $desc= "ASC";
393 }
394 /* Create times */
395 $start= date ("YmdHis", mktime(0,0,0,$this->month,1,$this->year));
396 $end= date ("YmdHis", mktime(23,59,59,($this->month +1),0,$this->year));
398 /* Create string with all fields seperated by ,*/
399 $fields_str ="";
400 foreach($this->fields as $field){
401 if($field == "calldate") continue;
402 $fields_str .= $field.", ";
403 }
404 $fields_str = preg_replace("/, $/","",$fields_str);
405 $fieldset = $fields_str.",calldate";
407 $query = "SELECT {$fieldset} FROM cdr ".
408 "WHERE
409 calldate <= $end
410 AND
411 calldate >= $start
412 ". $uidstring."
413 ORDER BY ".$this->fields[$this->sort]." $desc";
415 $query.=";";
416 return($query);
417 }
418 }
420 class viewFonEntries{
422 static function plInfo()
423 {
424 return (array(
425 "plShortName" => _("View phone reports"),
426 "plDescription" => _("View phone reports")." <i>"._("All entries are readonly")."</i>",
427 "plSelfModify" => TRUE,
428 "plDepends" => array(),
429 "plPriority" => 88,
430 "plSection" => array("administration"),
431 "plCategory" => array("users"),
433 "plProvidedAcls" => array(
434 "calldate" =>_("Date"),
435 "src" =>_("Source"),
436 "dst" =>_("Destination"),
437 "channel" =>_("Channel"),
438 "lastapp" =>_("Application called"),
439 "disposition" =>_("Disposition"),
440 "duration" =>_("Duration"))
441 ));
442 }
443 }
444 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
445 ?>