root/contributed_modules/modules/endpointman/includes/functions.inc

Revision 10261, 89.9 kB (checked in by tm1000, 3 years ago)

-Change epm_version to $this->global_cfgversion?;

  • Property svn:eol-style set to native
Line 
1 <?php
2 /**
3  * Endpoint Manager Functions File
4  *
5  * @author Andrew Nagy
6  * @license MPL / GPLv2 / LGPL
7  * @package Provisioner
8  */
9 class endpointmanager {
10     //Load this class upon construction of the class
11
12     public $db;
13     public $amp_conf;
14     public $global_cfg;
15     public $error;
16
17     /**
18      *
19      * @global array $amp_conf Data taken about FreePBX from FreePBX as a global, we move this into a public variable
20      * @global object $db Pear DB information, we move this into a public variable
21      */
22     function __construct() {
23         global $amp_conf, $db, $global_cfg;
24
25         date_default_timezone_set('America/Los_Angeles');
26
27         $this->db = $db;
28         $this->amp_conf = $amp_conf;
29         $this->error = array();
30
31
32         //Define the location of phone modules, keeping it outside of the module directory so that when the user updates endpointmanager they don't lose all of their phones
33         define("PHONE_MODULES_PATH", dirname($_SERVER["SCRIPT_FILENAME"])."/modules/_ep_phone_modules/");
34
35         //Get local path information
36         define("WEB_PATH", dirname($_SERVER['SCRIPT_NAME'])."/modules/endpointman/");
37         define("LOCAL_PATH", dirname($_SERVER["SCRIPT_FILENAME"])."/modules/endpointman/");
38
39
40         $this->global_cfg =& $this->db->getAssoc("SELECT var_name, value FROM endpointman_global_vars");
41
42         define("UPDATE_PATH", $this->global_cfg['update_server']);
43         define("VER", $this->global_cfg['version']);
44        
45         //Define error reporting
46         if($this->global_cfg['debug']) {
47             error_reporting(E_ALL);
48             ini_set('display_errors', 1);
49         } else {
50             ini_set('display_errors', 0);
51         }     
52
53         //include the local template class
54         include LOCAL_PATH."includes/rain.tpl.class.php";
55     }
56
57     /**
58      * Displays the message box on any page if triggered.
59      * @param string $message The text of the message
60      * @param string $tpl Not used at this time
61      * @param int $fatal_error Either 0 or 1, 1 would be red, 0 would be black
62      */
63     function display_message_box($message, $tpl, $fatal_error=0) {
64         $tpl->assign("show_error_box", 1);
65         $tpl->assign("advanced_debug", $this->global_cfg['debug']);
66         $tpl->assign("fatal_error", $fatal_error);
67         $tpl->assign("error_message", $message);
68     }
69
70     /**
71      * A hacky way to add notifications into freepbx
72      * @deprecated Supposed to remove
73      * @param <type> $id
74      * @param <type> $type
75      * @param <type> $display_text
76      * @param <type> $text
77      * @param <type> $link
78      */
79     function add_freepbx_notification($id, $type, $display_text, $text, $link) {
80         $sql = "INSERT INTO notifications (module, id, level, display_text, link, candelete, timestamp, extended_text) VALUES ('endpointman', '".$id."', '500', '".$display_text."', '".$link."', '1', '".time()."', '".$text."')";
81         mysql_query($sql);
82     }
83
84     /**
85      * Taken from PHP.net. A list of errors returned when uploading files.
86      * @param <type> $error_code
87      * @return string
88      */
89     function file_upload_error_message($error_code) {
90         switch ($error_code) {
91             case UPLOAD_ERR_INI_SIZE:
92                 return 'The uploaded file exceeds the upload_max_filesize directive in php.ini';
93             case UPLOAD_ERR_FORM_SIZE:
94                 return 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form';
95             case UPLOAD_ERR_PARTIAL:
96                 return 'The uploaded file was only partially uploaded';
97             case UPLOAD_ERR_NO_FILE:
98                 return 'No file was uploaded';
99             case UPLOAD_ERR_NO_TMP_DIR:
100                 return 'Missing a temporary folder';
101             case UPLOAD_ERR_CANT_WRITE:
102                 return 'Failed to write file to disk';
103             case UPLOAD_ERR_EXTENSION:
104                 return 'File upload stopped by extension';
105             default:
106                 return 'Unknown upload error';
107         }
108     }
109
110     /**
111      * Get the brand from any mac sent
112      * @param string $mac
113      * @return array
114      */
115     function get_brand_from_mac($mac){
116         //Check for valid mac address first
117         if(!preg_match("/[0-9a-f][0-9a-f][:-][0-9a-f][0-9a-f][:-][0-9a-f][0-9a-f][:-][0-9a-f][0-9a-f][:-][0-9a-f][0-9a-f][:-][0-9a-f][0-9a-f]/i",$mac)) {
118             return(FALSE);
119         }
120
121         //Get the OUI only
122         $oui = substr($mac,0,6);
123         //Find the matching brand model to the oui
124         $oui_sql = "SELECT endpointman_brand_list.name, endpointman_brand_list.id FROM endpointman_oui_list, endpointman_brand_list WHERE oui LIKE '%". $oui ."%' AND endpointman_brand_list.id = endpointman_oui_list.brand AND endpointman_brand_list.installed = 1 LIMIT 1";
125         $brand =& $this->db->getRow($oui_sql, array(), DB_FETCHMODE_ASSOC);
126
127         $res =& $this->db->query($oui_sql);
128         $brand_count = $res->numRows();
129
130         if (!$brand_count) {
131             //oui doesn't have a matching mysql reference, probably a PC/router/wap/printer of some sort.
132            $phone_info['id'] = 0;
133            $phone_info['name'] = _("Unknown");
134         } else {
135            $phone_info['id'] = $brand['id'];
136            $phone_info['name'] = $brand['name'];
137         }
138
139         return($phone_info);
140     }
141
142     /**
143      * Setup provisioner class from Provisioner.net
144      *
145      * Not used yet
146      *
147      * @param <type> $mac_id
148      */
149     function setup_provisioner($mac_id=NULL) {
150         if(!class_exists('ProvisionerConfig')) {
151             require(PHONE_MODULES_PATH.'setup.php');
152         }
153         $phone_info = $endpoint->get_phone_info($mac_id);
154
155         if(is_array($phone_info['template_data'])) {
156             $template_data = unserialize($phone_info['template_data']['custom_cfg_data']);
157         } else {
158             $template_data = unserialize($phone_info['custom_cfg_data']);
159         }
160
161         $new_template_data = array();
162         if(is_array($template_data)) {
163             foreach($template_data as $key => $data) {
164                 $new_template_data = array_merge($new_template_data, array($key => $data['value']));
165             }
166         }
167
168         $class = "endpoint_" . $phone_info['directory'] . "_" . $phone_info['cfg_dir'] . '_phone';
169
170         $provisioner_lib = new $class();
171
172         $provisioner_lib->root_dir = PHONE_MODULES_PATH;
173
174         $provisioner_lib->engine = 'asterisk';
175         $provisioner_lib->system = 'unix';
176
177         $provisioner_lib->options = $new_template_data;
178
179         //have to because of versions less than php5.3
180         $provisioner_lib->brand_name = $phone_info['directory'];
181         $provisioner_lib->family_line = $phone_info['cfg_dir'];
182     }
183
184     /**
185      * Send this function an ID from the mac devices list table and you'll get all the information we have on that particular phone
186      * @param integer $mac_id ID number reference from the MySQL database referencing the table endpointman_mac_list
187      * @return <type>
188      */
189     function get_phone_info($mac_id=NULL) {
190         //You could screw up a phone if the mac_id is blank
191         if (!isset($mac_id)) {
192             $this->error['get_phone_info'] = "Mac ID is not set";
193             return(FALSE);
194         }
195         $sql = "SELECT id,mac,model FROM  endpointman_mac_list WHERE model > 0 AND id =".$mac_id;
196
197         $res =& $this->db->query($sql);
198         if($res->numRows()) {
199             //Returns Brand Name, Brand Directory, Model Name, Mac Address, Extension (FreePBX), Custom Configuration Template, Custom Configuration Data, Product Name, Product ID, Product Configuration Directory, Product Configuration Version, Product XML name,
200             $sql = "SELECT endpointman_mac_list.config_files_override, endpointman_mac_list.global_user_cfg_data, endpointman_model_list.id as model_id, endpointman_brand_list.id as brand_id, endpointman_brand_list.name, endpointman_brand_list.directory, endpointman_model_list.model, endpointman_mac_list.mac, endpointman_line_list.ext, endpointman_mac_list.template_id, endpointman_mac_list.global_custom_cfg_data, endpointman_product_list.long_name, endpointman_product_list.id as product_id, endpointman_product_list.cfg_dir, endpointman_product_list.cfg_ver, endpointman_model_list.template_data, endpointman_model_list.enabled, devices.description, sip.data as secret FROM endpointman_line_list, endpointman_mac_list, endpointman_model_list, endpointman_brand_list, endpointman_product_list, sip, devices WHERE endpointman_mac_list.model = endpointman_model_list.id AND endpointman_brand_list.id = endpointman_model_list.brand AND endpointman_product_list.id = endpointman_model_list.product_id AND endpointman_line_list.ext = sip.id AND sip.keyword = 'secret' AND endpointman_line_list.ext = devices.id AND endpointman_mac_list.id = endpointman_line_list.mac_id AND endpointman_mac_list.id = ". $mac_id;
201
202             $phone_info =& $this->db->getRow($sql, array(), DB_FETCHMODE_ASSOC);
203
204             if(!$phone_info) {
205                 $this->error['get_phone_info'] = "Error with SQL Statement";
206             }
207
208             //If there is a template associated with this phone then pull that information and put it into the array
209             if ($phone_info['template_id'] > 0) {
210                 $sql = "SELECT name, global_custom_cfg_data, config_files_override FROM endpointman_template_list WHERE id = ".$phone_info['template_id'];
211
212                 $phone_info['template_data'] =& $this->db->getRow($sql, array(), DB_FETCHMODE_ASSOC);
213
214             }
215         } else {
216             $sql = "SELECT id, mac, ext FROM endpointman_mac_list WHERE id =".$mac_id;
217             //Phone is unknown, we need to display this to the end user so that they can make corrections
218             $row =& $this->db->getRow($sql, array(), DB_FETCHMODE_ASSOC);
219
220             $brand = $this->get_brand_from_mac($row['mac']);
221             if($brand) {
222                 $phone_info['brand_id'] = $brand['id'];
223                 $phone_info['name'] = $brand['name'];
224             } else {
225                 $phone_info['brand_id'] = 0;
226                 $phone_info['name'] = 'Unknown';
227             }
228
229             $phone_info['id'] = $mac_id;
230             $phone_info['model_id'] = 0;
231             $phone_info['product_id'] = 0;
232             $phone_info['custom_cfg_template'] = 0;
233             $phone_info['ext'] = $row['ext'];
234             $phone_info['mac'] = $row['mac'];
235         }
236
237         //Final Output needs to look like this:
238         //$this['mac_id']
239         //$this['model_id']
240         //$this['brand_id']
241         //$this['template_id']
242         //$this['product_id']
243         //$this['mac']
244         //$this['cfg_dir']
245         //$this['cfg_ver']
246         //$this['model_name']
247         //$this['brand_name']
248         //$this['long_name']
249         //$this['config_files_override']
250         //$this['global_custom_cfg_data']
251         //$this['global_user_cfg_data']
252         //$this['template_data']
253         //$this['enabled']
254         //$this['line'][1]['ext']
255         //$this['line'][1]['description']
256         //$this['line'][1]['secret']
257         //$this['line'][1]['custom_cfg_data']
258         //$this['line'][1]['user_cfg_data']
259         //
260         return $phone_info;
261     }
262
263     /**
264      * Custom Means specific to that MAC
265      * id is either the mac ID (not address) or the template ID
266      * @param integer $id
267      * @param integer $custom
268      */
269     function edit_template_display($id, $custom) {
270         $alt_configs = NULL;
271
272         if($custom == 0) {
273             $sql = "SELECT model_id FROM endpointman_template_list WHERE id=".$id;
274         } else {
275             $sql = "SELECT model FROM endpointman_mac_list WHERE id=".$id;
276         }
277
278         $model_id = $this->db->getOne($sql);
279
280         //Make sure the model data from the local confg files are stored in the database and vice-versa. Serious errors will occur if the database is not in sync with the local file
281         if(!$this->sync_model($model_id)) {
282             die("unable to sync local template files - TYPE:". $custom);
283         }
284
285
286         //Determine if we are dealing with a general template or a specific [for that phone only] template (custom =0 means general)
287         if($custom == 0) {
288             $sql = "SELECT endpointman_model_list.model as model_name, endpointman_template_list.global_custom_cfg_data,  endpointman_product_list.config_files, endpointman_product_list.short_name, endpointman_product_list.id as product_id, endpointman_model_list.template_data, endpointman_model_list.id as model_id, endpointman_template_list.* FROM endpointman_product_list, endpointman_model_list, endpointman_template_list WHERE endpointman_product_list.id = endpointman_template_list.product_id AND endpointman_template_list.model_id = endpointman_model_list.id AND endpointman_template_list.id = ".$id;
289         } else {
290             $sql = "SELECT endpointman_model_list.model as model_name, endpointman_mac_list.global_custom_cfg_data, endpointman_product_list.config_files, endpointman_mac_list.*, endpointman_line_list.*, endpointman_model_list.id as model_id, endpointman_model_list.template_data, endpointman_product_list.id as product_id, endpointman_product_list.short_name, endpointman_product_list.cfg_dir, endpointman_brand_list.directory FROM endpointman_brand_list, endpointman_mac_list, endpointman_model_list, endpointman_product_list, endpointman_line_list WHERE endpointman_mac_list.id=".$id." AND endpointman_mac_list.id = endpointman_line_list.mac_id AND endpointman_mac_list.model = endpointman_model_list.id AND endpointman_model_list.brand = endpointman_brand_list.id AND endpointman_model_list.product_id = endpointman_product_list.id";
291         }
292
293         $row =& $this->db->getRow($sql, array(), DB_FETCHMODE_ASSOC);
294
295         $tpl = new RainTPL( LOCAL_PATH.'templates' );
296         $tpl->assign("template_editor_display", 1);
297
298         echo $tpl->draw( 'global_header' );
299         //Let the template system know if we are working with a general template or a specific [for that phone only] template
300         $tpl->assign("custom", $custom);
301         if($custom) {
302             $tpl->assign("ext", $row['ext']);
303         } else {
304             $tpl->assign("template_name", $row['name']);
305         }
306         $tpl->assign("product", $row['short_name']);
307         $tpl->assign("model", $row['model_name']);
308
309         if($ma = $this->modelsAvailable($row['model_id'], NULL, NULL, $row['product_id'])) {
310             $tpl->assign("models_ava", $ma);
311         }
312
313         $tpl->assign("area_ava", $this->areaAvailable($row['model_id']));
314         //Start the display of the html file in the product folder
315         if($row['config_files_override'] == "") {
316             $config_files_saved = "";
317         } else {
318             $config_files_saved = unserialize($row['config_files_override']);
319         }
320         $config_files_list = explode(",",$row['config_files']);
321         $i = 0;
322         $alt = 0;
323         //TODO: Perhaps fix this alternative files list
324         foreach($config_files_list as $files) {
325             $sql = "SELECT * FROM  endpointman_custom_configs WHERE product_id = '".$row['product_id']."' AND original_name = '".$files."'";
326             $alt_configs_list_count =& $this->db->query($sql);
327             if($alt_configs_list_count->numRows() > 0) {
328                 $alt_configs_list =& $this->db->getAll($sql, array(), DB_FETCHMODE_ASSOC);
329                 $alt_configs .= $files;
330                 $alt_configs .= '<select name="'.$files.'">';
331                 $alt_configs .= '<option value="0">'.$files.' (Original)</option>';
332                 $files = str_replace(".","_",$files);
333                 foreach($alt_configs_list as $ccf) {
334                     $alt_configs .= '<option value="'.$ccf['id'].'" ';
335                     $cf_key = $files;
336                     if((is_array($config_files_saved)) AND ($config_files_saved[$cf_key] == $ccf['id'])) {
337                         $alt_configs .= 'selected';
338                     }
339                     $alt_configs .= '>'.$ccf['name'].'</option>';
340                 }
341                 $alt_configs .= "</select>";
342                 $alt = 1;
343             }
344             $i++;
345         }
346
347         $tpl->assign("alt_configs", $alt_configs);
348         $tpl->assign("alt", $alt);
349
350         if($row['template_data'] != "") {
351             $out = $this->generate_gui_html($row['template_data'],$row['global_custom_cfg_data'],TRUE);
352         } else {
353             echo "No Template Data has been defined for this Product<br />";
354         }
355
356         $tpl->assign("template_editor", $out);
357         $tpl->assign("hidden_id", $row['id']);
358         $tpl->assign("hidden_custom", $custom);
359         echo $tpl->draw( 'template_editor' );
360
361         $tpl->assign("debug", "");
362
363     }
364
365     /**
366      * Generates the Visual Display for the end user
367      * @param <type> $cfg_data
368      * @param <type> $custom_cfg_data
369      * @param <type> $admin
370      * @param <type> $user_cfg_data
371      * @return <type>
372      */
373     function generate_gui_html($cfg_data,$custom_cfg_data=NULL, $admin=FALSE, $user_cfg_data=NULL) {
374         //take the data out of the database and turn it back into an array for use
375         $cfg_data = unserialize($cfg_data);
376
377         $count = count($cfg_data);
378
379         //Check to see if there is a custom template for this phone already listed in the endpointman_mac_list database
380         if (isset($custom_cfg_data)) {
381             $custom_cfg_data = unserialize($custom_cfg_data);
382         } else {
383             //No custom template so let's pull the default values for this model into the custom_cfg_data array and populate it from there so that we won't have to make two completely different functions below
384             foreach($cfg_data as $key => $data) {
385                 if(($data['type'] != 'group') && ($data['type'] != 'break') && ($data['type'] != 'loop')) {
386                     $key_default = str_replace('$','',$data['variable']);
387                     if(!is_array($data['default_value'])) {
388                         $custom_cfg_data[$key_default]['value'] = $data['default_value'];
389                     } else {
390                         $custom_cfg_data[$key_default]['value'] = "";
391                     }
392                 }
393             }
394         }
395         if(isset($user_cfg_data)) {
396             $user_cfg_data = unserialize($user_cfg_data);
397         }
398
399         $template_variables_array = array();
400
401         $group_count = 0;
402         //Fill the html form data with values from either the database or the default values to display to the end user
403         for($i=0;$i<$count;$i++) {
404             if(array_key_exists('variable',$cfg_data[$i])) {
405                 $key = str_replace('$','',$cfg_data[$i]['variable']);
406             } else {
407                 $key = "";
408             }
409             if(($admin) OR (isset($custom_cfg_data[$key]['ari']))) {
410                 //Checks to see if values are defined in the database, if not then we assume this is a new option and we need a default value here!
411                 if(!isset($custom_cfg_data[$key]['value'])) {
412                     //xml2array will take values that have no data and turn them into arrays, we want to avoid the word 'array' as a default value, so we blank it out here if we are an array
413                     if((array_key_exists('default_value',$cfg_data[$i])) AND (is_array($cfg_data[$i]['default_value']))) {
414                         $custom_cfg_data[$key]['value'] = "";
415                     } elseif((array_key_exists('default_value',$cfg_data[$i])) AND (!is_array($cfg_data[$i]['default_value']))) {
416                         $custom_cfg_data[$key]['value'] = $cfg_data[$i]['default_value'];
417                     }
418                 }
419                 if ($cfg_data[$i]['type'] == "group") {
420                     $group_count++;
421                     $template_variables_array[$group_count]['title'] = $cfg_data[$i]['description'];
422                     $variables_count = 0;
423                 } elseif ($cfg_data[$i]['type'] == "loop") {
424                     $group_count++;
425                     $template_variables_array[$group_count]['title'] = $cfg_data[$i]['description'];
426                     $loop_start = $cfg_data[$i]['loop_start'];
427                     $loop_end = $cfg_data[$i]['loop_end'];
428                     $variables_count = 0;
429                     for($a=$loop_start;$a<=$loop_end;$a++) {
430                         foreach($cfg_data[$i]['data']['item'] as $items) {
431                             if(isset($items['description'])) {
432                                 $items['description'] = str_replace('{$count}',$a,$items['description']);
433                                 $key = str_replace('$','',$items['variable'])."_".$a;
434                                 if(array_key_exists($key,$custom_cfg_data)) {
435                                     $custom_cfg_data[$key]['value'] = $custom_cfg_data[$key][$a];
436                                 } else {
437                                     $custom_cfg_data[$key]['value'] = '';
438                                 }
439                             }
440                             $items[$i] = $items;
441                             $template_variables_array[$group_count]['data'][$variables_count] = $this->generate_form_data($i,$items,$key,$custom_cfg_data);
442                             $template_variables_array[$group_count]['data'][$variables_count]['looping'] = TRUE;
443                             $variables_count++;
444                         }
445                     }
446                 } else {
447                     $template_variables_array[$group_count]['data'][$variables_count] = $this->generate_form_data($i,$cfg_data,$key,$custom_cfg_data);
448                     $variables_count++;
449                 }
450             }
451         }
452         return($template_variables_array);
453     }
454
455     /**
456      * Generate an array that will get parsed as HTML from an array of values from XML
457      * @param int $i
458      * @param array $cfg_data
459      * @param string $key
460      * @param array $custom_cfg_data
461      * @return array
462      */
463     function generate_form_data ($i,$cfg_data,$key,$custom_cfg_data) {
464         $admin = TRUE;
465         if ($cfg_data[$i]['type'] == "input") {
466             if((!$admin) && (isset($user_cfg_data[$key]['value']))) {
467                 $custom_cfg_data[$key]['value'] = $user_cfg_data[$key]['value'];
468             }
469             $template_variables_array['type'] = "input";
470             $template_variables_array['key'] = $key;
471             $template_variables_array['value'] = $custom_cfg_data[$key]['value'];
472             $template_variables_array['description'] = $cfg_data[$i]['description'];
473         } elseif ($cfg_data[$i]['type'] == "radio") {
474             if((!$admin) && (isset($user_cfg_data[$key]['value']))) {
475                 $custom_cfg_data[$key]['value'] = $user_cfg_data[$key]['value'];
476             }
477             $num = $custom_cfg_data[$key]['value'];
478             $template_variables_array['type'] = "radio";
479             $template_variables_array['key'] = $key;
480             $template_variables_array['description'] = $cfg_data[$i]['description'];
481             $z = 0;
482             while($z < count($cfg_data[$i]['data'])) {
483                 $template_variables_array['data'][$z]['key'] = $key;
484                 $template_variables_array['data'][$z]['value'] = $cfg_data[$i]['data'][$z]['value'];
485                 $template_variables_array['data'][$z]['description'] = $cfg_data[$i]['data'][$z]['text'];
486                 if ($cfg_data[$i]['data'][$z]['value'] == $num) {
487                     $template_variables_array['data'][$z]['checked'] = 'checked';
488                 }
489                 $z++;
490             }
491         } elseif ($cfg_data[$i]['type'] == "list") {
492             if((!$admin) && (isset($user_cfg_data[$key]['value']))) {
493                 $custom_cfg_data[$key]['value'] = $user_cfg_data[$key]['value'];
494             }
495             $num = $custom_cfg_data[$key]['value'];
496             $template_variables_array['type'] = "list";
497             $template_variables_array['key'] = $key;
498             $template_variables_array['description'] = $cfg_data[$i]['description'];
499             $z = 0;
500             while($z < count($cfg_data[$i]['data'])) {
501                 $template_variables_array['data'][$z]['value'] = $cfg_data[$i]['data'][$z]['value'];
502                 $template_variables_array['data'][$z]['description'] = $cfg_data[$i]['data'][$z]['text'];
503                 if ($cfg_data[$i]['data'][$z]['value'] == $num) {
504                     $template_variables_array['data'][$z]['selected'] = 'selected';
505                 }
506                 $z++;
507             }
508         } elseif ($cfg_data[$i]['type'] == "break") {
509             $template_variables_array['type'] = "break";
510         }
511         if(($this->global_cfg['enable_ari']) AND ($admin) AND ($cfg_data[$i]['type'] != "break") AND ($cfg_data[$i]['type'] != "group")) {
512             $template_variables_array['aried'] = 1;
513             $template_variables_array['ari']['key'] = $key;
514             if(isset($custom_cfg_data[$key]['ari'])) {
515                 $template_variables_array['ari']['checked'] = "checked";
516             }
517         }
518         return($template_variables_array);
519     }
520
521     /**
522      * Save template from the template view pain
523      * @param int $id Either the MAC ID or Template ID
524      * @param int $custom Either 0 or 1, it determines if $id is MAC ID or Template ID
525      * @param array $variables The variables sent from the form. usually everything in $_REQUEST[]
526      * @return string Location of area to return to in Endpoint Manager
527      */
528     function save_template($id, $custom, $variables) {
529         //Custom Means specific to that MAC
530         //This function is reversed. Not sure why
531         if($custom != "0") {
532             $sql = "SELECT endpointman_product_list.config_files, endpointman_mac_list.*, endpointman_product_list.id as product_id, endpointman_product_list.long_name, endpointman_model_list.template_data, endpointman_product_list.cfg_dir, endpointman_brand_list.directory FROM endpointman_brand_list, endpointman_mac_list, endpointman_model_list, endpointman_product_list WHERE endpointman_mac_list.id=".$id." AND endpointman_mac_list.model = endpointman_model_list.id AND endpointman_model_list.brand = endpointman_brand_list.id AND endpointman_model_list.product_id = endpointman_product_list.id";
533         } else {
534             $sql = "SELECT endpointman_brand_list.directory, endpointman_product_list.cfg_dir, endpointman_product_list.config_files, endpointman_product_list.long_name, endpointman_model_list.template_data, endpointman_model_list.id as model_id, endpointman_template_list.* FROM endpointman_brand_list, endpointman_product_list, endpointman_model_list, endpointman_template_list WHERE endpointman_product_list.id = endpointman_template_list.product_id AND endpointman_brand_list.id = endpointman_product_list.brand AND endpointman_template_list.model_id = endpointman_model_list.id AND endpointman_template_list.id = ".$id;
535         }
536
537         //Load template data
538         $row =& $this->db->getRow($sql, array(), DB_FETCHMODE_ASSOC);
539
540         $cfg_data = unserialize($row['template_data']);
541         $count = count($cfg_data);
542         for($i=0;$i<$count;$i++) {
543             if(array_key_exists('variable',$cfg_data[$i])) {
544                 $temping = str_replace('$','',$cfg_data[$i]['variable']);
545                 $temping_ari = "ari_" . $temping;
546                 if(array_key_exists($temping, $_REQUEST)) {
547                     $custom_cfg_data[$temping]['value'] = $_REQUEST[$temping];
548                     if(array_key_exists($temping_ari, $_REQUEST)) {
549                         if($_REQUEST[$temping_ari] == "on") {
550                             $custom_cfg_data[$temping]['ari'] = 1;
551                         }
552                     }
553                 }
554             } elseif ($cfg_data[$i]['type'] == 'loop') {
555                 $loop_start = $cfg_data[$i]['loop_start'];
556                 $loop_end = $cfg_data[$i]['loop_end'];
557                 $variables_count = 0;
558                 for($a=$loop_start;$a<=$loop_end;$a++) {
559                     foreach($cfg_data[$i]['data']['item'] as $items) {
560                         if(isset($items['description'])) {
561                             $items['description'] = str_replace('{$count}',$a,$items['description']);
562                             $temping = str_replace('$','',$items['variable'])."_".$a;
563                             $temping_ari = "ari_" . $temping;
564                             if(array_key_exists($temping, $_REQUEST)) {
565                                 $custom_cfg_data[$temping][$a] = $_REQUEST[$temping];
566                                 if(array_key_exists($temping_ari, $_REQUEST)) {
567                                     if($_REQUEST[$temping_ari] == "on") {
568                                         $custom_cfg_data[$temping]['ari'] = 1;
569                                     }
570                                 }
571                             }
572                         }
573                     }
574                 }
575             }
576         }
577
578         $config_files = explode(",",$row['config_files']);
579         $i = 0;
580         while($i < count($config_files)) {
581             $config_files[$i] = str_replace(".","_",$config_files[$i]);
582             if(isset($_REQUEST[$config_files[$i]])) {
583                 if($_REQUEST[$config_files[$i]] > 0) {
584                     $config_files_selected[$config_files[$i]] = $_REQUEST[$config_files[$i]];
585                 }
586             }
587             $i++;
588         }
589         if(!isset($config_files_selected)) {
590             $config_files_selected = "";
591         } else {
592             $config_files_selected = serialize($config_files_selected);
593         }
594         $save = serialize($custom_cfg_data);
595
596         if($custom == "0") {
597             $sql = 'UPDATE endpointman_template_list SET config_files_override = \''.addslashes($config_files_selected).'\', global_custom_cfg_data = \''.addslashes($save).'\' WHERE id ='.$id;
598             $location = "template_manager";
599         } else {
600             $sql = 'UPDATE endpointman_mac_list SET config_files_override = \''.addslashes($config_files_selected).'\', template_id = 0, global_custom_cfg_data = \''.addslashes($save).'\' WHERE id ='.$id;
601             $location = "devices_manager";
602         }
603  
604         $this->db->query($sql);
605
606         $phone_info = "";
607
608         if($custom != 0) {
609             $phone_info = $this->get_phone_info($id);
610             $this->prepare_configs($phone_info);
611
612         } else {
613             $sql = 'SELECT id FROM endpointman_mac_list WHERE template_id = '.$id;
614             $phones = $this->db->getAll($sql, array(), DB_FETCHMODE_ASSOC);
615             foreach($phones as $data) {
616                 $phone_info = $this->get_phone_info($data['id']);
617                 $this->prepare_configs($phone_info);
618             }
619         }
620
621         return($location);
622
623     }
624
625     /**
626      * Prepare and then send the data that Provisioner expects, then take what provisioner gives us and do what it says
627      * @param array $phone_info
628      */
629     function prepare_configs($phone_info) {
630         if(!class_exists('ProvisionerConfig')) {
631             require(PHONE_MODULES_PATH.'setup.php');
632         }
633
634         //Load Provisioner
635         $class = "endpoint_" . $phone_info['directory'] . "_" . $phone_info['cfg_dir'] . '_phone';
636         $provisioner_lib = new $class();
637
638         //Tell the system who we are and were to find the data.
639         $provisioner_lib->root_dir = PHONE_MODULES_PATH;
640         $provisioner_lib->engine = 'asterisk';
641         $provisioner_lib->system = 'unix';
642
643         //have to because of versions less than php5.3
644         $provisioner_lib->brand_name = $phone_info['directory'];
645         $provisioner_lib->family_line = $phone_info['cfg_dir'];
646
647         //Mac Address
648         $provisioner_lib->mac = $phone_info['mac'];
649
650         //Phone Model (Please reference family_data.xml in the family directory for a list of recognized models)
651         //This has to match word for word. I really need to fix this....
652         $provisioner_lib->model = $phone_info['model'];
653
654         //Timezone
655         $provisioner_lib->timezone = $this->global_cfg['tz'];
656
657         //Server IP
658         $provisioner_lib->server[1]['ip'] = $this->global_cfg['srvip'];
659         $provisioner_lib->server[1]['port'] = 5060;
660
661         //Provide alternate Configuration file instead of the one from the hard drive
662         $temp = "";
663         if(!empty($phone_info['config_files_override'])) {
664             $temp = unserialize($phone_info['config_files_override']);
665             foreach($temp as $list) {
666                 $sql = "SELECT original_name,data FROM endpointman_custom_configs WHERE id = ".$list;
667                 $res =& $this->db->query($sql);
668                 if($res->numRows()) {
669                     $data = $this->db->getRow($sql, array(),DB_FETCHMODE_ASSOC);
670                     $provisioner_lib->config_files_override[$data['original_name']] = $data['data'];
671                 }
672             }
673         }
674
675         //Pretend we have three lines, we could just have one line or 20...whatever the phone supports
676         $provisioner_lib->lines[1] = array('ext' => $phone_info['ext'], 'secret' => $phone_info['secret'], 'displayname' => $phone_info['description']);
677
678         if(is_array($phone_info['template_data'])) {
679             $template_data = unserialize($phone_info['template_data']['global_custom_cfg_data']);
680         } else {
681             $template_data = unserialize($phone_info['global_custom_cfg_data']);
682         }
683         $new_template_data = array();
684         if(is_array($template_data)) {
685             foreach($template_data as $key => $data) {
686                 if(array_key_exists('value', $data)) {
687                     $new_template_data[$key] = $data['value'];
688                 } else {
689                     $key = explode('_',$key);
690                     $new_template_data[$key[0]][$key[2]][$key[1]] = $data[$key[2]];
691                 }
692             }
693         }
694
695         //Set Variables according to the template_data files included. We can include different template.xml files within family_data.xml also one can create
696         //template_data_custom.xml which will get included or template_data_<model_name>_custom.xml which will also get included
697         //line 'global' will set variables that aren't line dependant
698         $provisioner_lib->options = $new_template_data;
699         //Setting a line variable here...these aren't defined in the template_data.xml file yet. however they will still be parsed
700         //and if they have defaults assigned in a future template_data.xml or in the config file using pipes (|) those will be used, pipes take precedence
701
702         // Because every brand is an extension (eventually) of endpoint, you know this function will exist regardless of who it is
703         $returned_data = $provisioner_lib->generate_config();
704
705         //Create Directory Structure (If needed)
706         if(isset($provisioner_lib->directory_structure)) {
707             foreach($provisioner_lib->directory_structure as $data) {
708                 $dir = $this->global_cfg['config_location'] . $data;
709                 if(!file_exists($dir)) {
710                     mkdir($dir, 0777);
711                 }
712             }
713         }
714
715         //Copy Files/Directories (If needed)
716         if(isset($provisioner_lib->copy_files)) {
717             foreach($provisioner_lib->copy_files as $data) {
718                 if(((file_exists($this->global_cfg['config_location'].$data)) AND (!in_array($data,$provisioner_lib->protected_files))) OR (!file_exists($this->global_cfg['config_location'].$data))) {
719                     if(is_dir(PHONE_MODULES_PATH."endpoint/".$phone_info['directory']."/".$phone_info['cfg_dir']."/".$data)) {
720                         if(!file_exists($this->global_cfg['config_location'].$data)) {
721                             mkdir($this->global_cfg['config_location'].$data, 0777);
722                         }
723                         $dir_iterator = new RecursiveDirectoryIterator(PHONE_MODULES_PATH."endpoint/".$phone_info['directory']."/".$phone_info['cfg_dir']."/".$data."/");
724                         $iterator = new RecursiveIteratorIterator($dir_iterator, RecursiveIteratorIterator::SELF_FIRST);
725                         // could use CHILD_FIRST if you so wish
726                         foreach ($iterator as $file) {
727                             if(is_dir($file)) {
728                                 $dir = str_replace(PHONE_MODULES_PATH."endpoint/".$phone_info['directory']."/".$phone_info['cfg_dir']."/".$data."/", "", $file);
729                                 if(!file_exists($this->global_cfg['config_location'].$data."/".$dir)) {
730                                     mkdir($this->global_cfg['config_location'].$data."/".$dir, 0777);
731                                 }
732                             } else {
733                                 $dir = str_replace(PHONE_MODULES_PATH."endpoint/".$phone_info['directory']."/".$phone_info['cfg_dir']."/".$data."/", "", $file);
734                                 copy($file, $this->global_cfg['config_location'].$data."/".$dir);
735                                 chmod($this->global_cfg['config_location'].$data."/".$dir, 0777);
736                             }
737                         }
738                     } else {
739                         copy(PHONE_MODULES_PATH."endpoint/".$phone_info['directory']."/".$phone_info['cfg_dir']."/".$data,$this->global_cfg['config_location'].$data);
740                         chmod($this->global_cfg['config_location'].$data, 0777);
741                     }
742                 }
743             }
744         }
745
746         $provisioner_lib->processor_info = "EndPoint Manager Version ".$this->global_cfg['version'];
747
748         //Generate Files
749         foreach($returned_data as $key => $data) {
750             if(((file_exists($this->global_cfg['config_location'].$key)) AND (!in_array($key,$provisioner_lib->protected_files))) OR (!file_exists($this->global_cfg['config_location'].$key))) {
751                 $fp = fopen($this->global_cfg['config_location'].$key, 'w');
752                 fwrite($fp, $data);
753                 fclose($fp);
754                 if(!file_exists($this->global_cfg['config_location'].$key)) {
755                     $this->error['parse_configs'] = "File not written to hard drive!";
756                 }
757             }
758         }
759         $provisioner_lib->reboot();
760     }
761
762     /**
763      * Check for new firmware on the servers
764      * @param int $id Product ID
765      * @return bool True on yes False on no
766      */
767     function firmware_update_check($id=NULL) {
768         $sql = "SELECT * FROM  endpointman_product_list WHERE  id ='". $id."'";
769         $row =& $this->db->getRow($sql,array(),DB_FETCHMODE_ASSOC);
770
771         $sql = "SELECT directory FROM  endpointman_brand_list WHERE id =". $row['brand'];
772         $brand_directory =& $this->db->getOne($sql);
773
774         //config drive unknown!
775         if ($row['cfg_dir'] == "") {
776             return FALSE;
777         } else {
778             $temp = $this->xml2array(PHONE_MODULES_PATH."endpoint/".$brand_directory."/".$row['cfg_dir']."/family_data.xml");
779             if((array_key_exists('data',$temp)) AND (!is_array($temp['data']['firmware_ver']))) {
780                 if($row['firmware_vers'] < $temp['data']['firmware_ver']) {
781                     return $temp;
782                 } else {
783                     return FALSE;
784                 }
785             } else {
786                 return FALSE;
787             }
788         }
789
790     }
791
792     /**
793      * Check to see the status of the firmware locally (installed or not)
794      * @param int $id
795      * @return string
796      */
797     function firmware_local_check($id=NULL) {
798         $sql = "SELECT * FROM  endpointman_product_list WHERE hidden = 0 AND id ='". $id ."'";
799         $res =& $this->db->query($sql);
800
801         if($res->numRows()) {
802             $row =& $this->db->getRow($sql,array(),DB_FETCHMODE_ASSOC);
803
804             $sql = "SELECT directory FROM  endpointman_brand_list WHERE hidden = 0 AND id =". $row['brand'];
805             $brand_directory =& $this->db->getOne($sql);
806
807             //config drive unknown!
808             if ($row['cfg_dir'] == "") {
809                 return("nothing");
810             } else {
811                 $temp = $this->xml2array(PHONE_MODULES_PATH."endpoint/".$brand_directory."/".$row['cfg_dir']."/family_data.xml");
812
813                 if((isset ($temp['data']['firmware_ver'])) AND (!is_array($temp['data']['firmware_ver']))) {
814                     if($row['firmware_vers'] == "") {
815                         return("install");
816                     } else {
817                         return("remove");
818                     }
819                 } else {
820                     return("nothing");
821                 }
822             }
823         } else {
824             return("nothing");
825         }
826     }
827
828     /**
829      * Remove firmware from the Hard Drive
830      * @param int $id Procut ID
831      */
832     function remove_firmware($id=NULL) {
833         $sql = "SELECT firmware_files FROM  endpointman_product_list WHERE  id =". $id;
834         $files = $this->db->getOne($sql);
835
836         $file_list = explode(",",$files);
837         $i = 0;
838         while($i < count($file_list)) {
839             unlink($this->global_cfg['config_location'].$file_list[$i]);
840             $i++;
841         }
842         $sql = 'UPDATE endpointman_product_list SET firmware_files = "", firmware_vers = "" WHERE id = '.$id;
843         $this->db->query($sql);
844     }
845
846     /**
847      * Install Firmware for the specified Product Line
848      * @param <type> $product_id
849      */
850     function install_firmware($product_id) {
851         $sql = 'SELECT endpointman_product_list.*, endpointman_brand_list.directory FROM endpointman_product_list, endpointman_brand_list WHERE endpointman_product_list.brand = endpointman_brand_list.id AND endpointman_product_list.id = '.$product_id;
852         $row =& $this->db->getRow($sql, array(), DB_FETCHMODE_ASSOC);
853         $temp = $this->xml2array(PHONE_MODULES_PATH."endpoint/".$row['directory']."/".$row['cfg_dir']."/family_data.xml");
854         if($temp['data']['firmware_ver'] > $row['firmware_vers']) {
855             echo "<div style='float: left'>Downloading firmware...</div><div style='float: left' id=\"DivExample\">.</div>";
856             $this->download_file_with_progress_bar(UPDATE_PATH.$row['directory']."/". $temp['data']['firmware_pkg'], PHONE_MODULES_PATH."temp/".$temp['data']['firmware_pkg']);
857             echo "<script type='text/javascript'>document.getElementById('DivExample').innerHTML='Done!';</script><br />";
858             if(!file_exists(PHONE_MODULES_PATH."endpoint/".$row['directory']."/".$row['cfg_dir']."/firmware")) {
859                 mkdir(PHONE_MODULES_PATH."endpoint/".$row['directory']."/".$row['cfg_dir']."/firmware");
860             }
861             echo "Installing Firmware...";
862             exec("rm -Rf ".PHONE_MODULES_PATH."endpoint/".$row['directory']."/".$row['cfg_dir']."/firmware");
863             mkdir(PHONE_MODULES_PATH."endpoint/".$row['directory']."/".$row['cfg_dir']."/firmware");
864             exec("tar -xvf ".PHONE_MODULES_PATH.'temp/'. $temp['data']['firmware_pkg'] ." -C ".PHONE_MODULES_PATH."endpoint/".$row['directory']."/".$row['cfg_dir']);
865             $i = 0;
866             foreach (glob(PHONE_MODULES_PATH."endpoint/".$row['directory']."/".$row['cfg_dir']."/firmware/*.*") as $filename) {
867                 $file = basename($filename);
868                 $list[$i] = $file;
869                 copy($filename, $this->global_cfg['config_location'].$file);
870                 $i++;
871             }
872             $list = implode(",", $list);
873             $sql = "UPDATE endpointman_product_list SET firmware_vers = '".$temp['data']['firmware_ver']."', firmware_files = '".$list."' WHERE id = ". $row['id'];
874             $this->db->query($sql);
875             echo "Done!";
876         } else {
877             echo "Your Firmware is already up to date";
878
879         }
880     }
881
882     /**
883      * Fix arrays so that they don't return an empty array if the array is empty
884      * Instead we will return an empty string
885      * Also we fix the problem of wanting to get single arrays with keys but not getting them
886      * @param array $array
887      * @return array
888      */
889     function fix_single_array_keys($array) {
890         if((empty($array[0])) AND (!empty($array))) {
891             $array_n[0] = $array;
892             return($array_n);
893         } elseif(!empty($array)) {
894             return($array);
895         } else {
896             return("");
897         }
898     }
899
900     /**
901      * Download the requested XML configuration files from the web
902      * @param string $location full URL of the XML file
903      * @param string $directory Directory to place the XML file in relation to provisioner.net
904      * @return bool True if downloaded, false if failed.
905      */
906     function download_xml($location,$directory=NULL) {
907         //If directory is not set then assume we are working with the master.xml file
908         if(!isset($directory)) {
909             $destination_file = PHONE_MODULES_PATH.'master.xml';
910       $directory = "master";
911         } else {
912             if(!file_exists(PHONE_MODULES_PATH.'/'.$directory)) {
913                 mkdir(PHONE_MODULES_PATH.'/'.$directory,0764);
914             }
915             $destination_file = PHONE_MODULES_PATH.'/'.$directory.'/brand_data.xml';
916         }
917         $temp_file = PHONE_MODULES_PATH.'temp/'.$directory.'.xml';
918         if($this->download_xml_file($location, $temp_file)) {
919             $handle = fopen($temp_file, "rb");
920             $contents = fread($handle, filesize($temp_file));
921             fclose($handle);
922             @$a = simplexml_load_string($contents);
923             if($a===FALSE) {
924                 //Error with the internet....ABORRRTTTT THEEEEE DOWNLOAAAAADDDDDDDD! SCOTTYYYY!;
925                 unlink($temp_file);
926                 return(FALSE);
927             } else {
928                 rename($temp_file, $destination_file);
929                 chmod($destination_file,0764);
930                 return(TRUE);
931             }
932         } else {
933             return(FALSE);
934         }
935     }
936
937     /**
938      * Check for new packges for brands. These packages will include phone models and such which the user can remove if they want
939      * This function will alos auto-update the provisioner.net library incase anything has changed
940      * @return array An array of all the brands/products/models and information about what's  enabled, installed or otherwise
941      */
942     function brand_update_check() {
943         $master_result = $this->download_xml(UPDATE_PATH . "master.xml");
944
945
946         if(!$master_result) {
947             $this->error['brand_update_check_master'] = "Not able to connect to repository. Using local master file instead.";
948         }
949
950         $temp = $this->xml2array(PHONE_MODULES_PATH.'master.xml');
951
952         $endpoint_package = $temp['data']['package'];
953         $endpoint_last_mod = $temp['data']['last_modified'];
954
955         $sql = "SELECT value FROM endpointman_global_vars WHERE var_name LIKE 'endpoint_vers'";
956         $data =& $this->db->getOne($sql);
957
958         if(($data == "") OR ($data <= $endpoint_last_mod)) {
959             if((!$master_result) OR (!$this->download_file_no_progress_bar(UPDATE_PATH.'/'.$endpoint_package, PHONE_MODULES_PATH."temp/".$endpoint_package))) {
960                 $this->error['brand_update_check_xml'] = "<br/>Not able to connect to repository. Using local Provisioner.net Package";
961             } else {
962                 exec("tar -xvf ".PHONE_MODULES_PATH.'temp/'. $endpoint_package ." -C ".PHONE_MODULES_PATH."temp/");
963
964                 if(!file_exists(PHONE_MODULES_PATH."endpoint")) {
965                     mkdir(PHONE_MODULES_PATH."endpoint");
966                 }
967
968                 unlink(PHONE_MODULES_PATH."temp/setup.php");
969                 rename(PHONE_MODULES_PATH."temp/endpoint/base.php", PHONE_MODULES_PATH."endpoint/base.php");
970
971                 $sql = "UPDATE endpointman_global_vars SET value = '".$endpoint_last_mod."' WHERE var_name = 'endpoint_vers'";
972                 $this->db->query($sql);
973             }
974         }
975
976
977         $out = $temp['data']['brands'];
978
979         //Assume that if we can't connect and find the master.xml file then why should we try to find every other file.
980         if($master_result) {
981             $row =& $this->db->getAll('SELECT * FROM  endpointman_brand_list WHERE id > 0', array(), DB_FETCHMODE_ASSOC);
982
983             foreach($out as $data) {
984                 //TODO: Make this pull from the local directory
985                 $result = $this->download_xml(UPDATE_PATH .$data['directory']."/".$data['directory'].".xml","endpoint/".$data['directory']);
986                 if(!$result) {
987                     $this->error['brand_update_check'] = "<br/>Not able to connect to repository. Using local brand [".$data['name']."] file instead.";
988                 }
989
990                 if(file_exists(PHONE_MODULES_PATH."endpoint/".$data['directory']."/brand_data.xml")) {
991                     $temp = $this->xml2array(PHONE_MODULES_PATH."endpoint/".$data['directory']."/brand_data.xml");
992
993                     $temp = $temp['data']['brands'];
994
995                     $temp['oui_list']['oui'] = $this->fix_single_array_keys($temp['oui_list']['oui']);
996
997                     foreach($temp['oui_list']['oui'] as $oui) {
998                         $sql = "INSERT INTO endpointman_oui_list (`oui`, `brand`, `custom`) VALUES ('".$oui."', '".$temp['brand_id']."', '0')";
999                         $this->db->query($sql);
1000
1001                     }
1002
1003                     $brand_name = $temp['directory'];
1004                     $version[$brand_name] = $temp['last_modified'];
1005
1006                     $last_mod = "";
1007
1008                     $temp['family_list']['family'] = $this->fix_single_array_keys($temp['family_list']['family']);
1009
1010                     foreach($temp['family_list']['family'] as $list) {
1011                         $last_mod = max($last_mod, $list['last_modified']);
1012                     }
1013                     $last_mod = max($last_mod, $version[$brand_name]);
1014
1015                     $version[$brand_name] = $last_mod;
1016
1017                     if(!($this->arraysearchrecursive($brand_name, $row, 'directory'))) {
1018                         //insert row
1019                         $sql = "INSERT INTO endpointman_brand_list (id, name, directory, cfg_ver) VALUES ('".$temp['brand_id']."', '".$temp['name']."', '".$temp['directory']."', '".$version[$brand_name]."')";
1020                         $this->db->query($sql);
1021                     } else {
1022                         //in database already!
1023                     }
1024                 } else {
1025                     $this->error['brand_update_check_local_file'] = "<br/>Error: No Local File for ".$data['name']."!";
1026                 }
1027             }
1028
1029             foreach($row as $ava_brands) {
1030                 $key = $this->arraysearchrecursive($ava_brands['directory'], $out, 'directory');
1031                 if($key === FALSE) {
1032                     $this->remove_brand($ava_brands['id']);
1033                 } else {
1034                     $key = $key[0];
1035
1036                     $brand_name = $ava_brands['directory'];
1037
1038                     if($ava_brands['cfg_ver'] < $version[$brand_name]) {
1039                         $out[$key]['update'] = 1;
1040                         $out[$key]['update_vers'] = $version[$brand_name];
1041                     } else {
1042                         $out[$key]['update'] = NULL;
1043                     }
1044                 }
1045             }
1046         } else {
1047             $this->error['brand_update_check_master_file'] = "<br/>Aborting Brand Downloads. Can't Get Master File, Assuming Timeout Issues!";
1048         }
1049
1050         return $out;
1051     }
1052
1053     /**
1054      * This will install or updated a brand package (which is the same thing to this)
1055      * Still needs way to determine when models move...perhaps another function?
1056      * @param <type> $id
1057      */
1058     function update_brand($id = NULL) {
1059         $row =& $this->db->getAll('SELECT * FROM  endpointman_brand_list WHERE id ='.$id, array(), DB_FETCHMODE_ASSOC);
1060
1061         echo "Downloading Brand XML.....";
1062         $result = $this->download_xml(UPDATE_PATH .$row[0]['directory']. "/".$row[0]['directory'].".xml","endpoint/".$row[0]['directory']);
1063         if($result) {
1064             echo "Done!<br/>";
1065
1066             $temp = $this->xml2array(PHONE_MODULES_PATH.'/endpoint/'.$row[0]['directory'].'/brand_data.xml');
1067
1068             $brand_name = $temp['data']['brands']['name'];
1069             $brand_id = $temp['data']['brands']['brand_id'];
1070             $brand_version = $temp['data']['brands']['version'];
1071             $brand_last_mod = $temp['data']['brands']['last_modified'];
1072             $package = $temp['data']['brands']['package'];
1073
1074             echo "<div style='float: left'>Downloading Brand Package...</div><div style='float: left' id=\"DivExample\">.</div>";
1075             $this->download_file_with_progress_bar(UPDATE_PATH.$row[0]['directory'].'/'.$package, PHONE_MODULES_PATH."temp/".$package);
1076             echo "<script type='text/javascript'>document.getElementById('DivExample').innerHTML='Done!';</script><br />";
1077            
1078             echo "Extracting Tarball........";
1079             exec("tar -xvf ".PHONE_MODULES_PATH.'temp/'. $package ." -C ".PHONE_MODULES_PATH."temp/");
1080             echo "Done!<br />";
1081
1082             echo "Creating Directory Structure/Moving Files...............";
1083             $dir_iterator = new RecursiveDirectoryIterator(PHONE_MODULES_PATH."temp/".$row[0]['directory']."/");
1084             $iterator = new RecursiveIteratorIterator($dir_iterator, RecursiveIteratorIterator::SELF_FIRST);
1085             // could use CHILD_FIRST if you so wish
1086
1087             foreach ($iterator as $file) {
1088                 if(is_dir($file)) {
1089                     $dir = str_replace(PHONE_MODULES_PATH."temp/".$row[0]['directory']."/", "", $file);
1090                     if(!file_exists(PHONE_MODULES_PATH."endpoint/".$row[0]['directory']."/".$dir)) {
1091                         mkdir(PHONE_MODULES_PATH."endpoint/".$row[0]['directory']."/".$dir,0764);
1092                     }
1093                 } else {
1094                     if(basename($file) != "brand_data.xml") {
1095                         $dir = str_replace(PHONE_MODULES_PATH."temp/".$row[0]['directory']."/", "", $file);
1096                         rename($file, PHONE_MODULES_PATH."endpoint/".$row[0]['directory']."/".$dir);
1097                         chmod(PHONE_MODULES_PATH."endpoint/".$row[0]['directory']."/".$dir,0764);
1098                     }
1099                 }
1100             }
1101             echo "Done!<br />";
1102
1103             echo "Removing Temporary Files..............";
1104             $this->deltree(PHONE_MODULES_PATH."temp/" .$row[0]['directory']);
1105             unlink(PHONE_MODULES_PATH.'temp/'. $package);
1106             echo "Done!<br />";
1107
1108             $last_mod = "";
1109             $temp['data']['brands']['family_list']['family'] = $this->fix_single_array_keys($temp['data']['brands']['family_list']['family']);
1110             foreach($temp['data']['brands']['family_list']['family'] as $family_list) {
1111                 echo "Updating Family Lines.................<br/>";
1112                 $last_mod = max($last_mod, $family_list['last_modified']);
1113
1114                 $family_line_xml = $this->xml2array(PHONE_MODULES_PATH.'/endpoint/'.$row[0]['directory'].'/'.$family_list['directory'].'/family_data.xml');
1115                 $data =& $this->db->getOne("SELECT id FROM endpointman_product_list WHERE id='".$brand_id.$family_line_xml['data']['id']."'", array(), DB_FETCHMODE_ASSOC);
1116                 $short_name = preg_replace("/\[(.*?)\]/si", "", $family_line_xml['data']['name']);
1117                 if($data) {
1118                     $sql = "UPDATE endpointman_product_list SET short_name = '".$short_name."', long_name = '".$family_line_xml['data']['name']."', cfg_ver = '".$family_line_xml['data']['version']."', config_files='".$family_line_xml['data']['configuration_files']."' WHERE id = '".$brand_id.$family_line_xml['data']['id']."'";
1119                 } else {
1120                     $sql = "INSERT INTO endpointman_product_list (`id`, `brand`, `short_name`, `long_name`, `cfg_dir`, `cfg_ver`, `config_files`, `hidden`) VALUES ('".$brand_id.$family_line_xml['data']['id']."', '".$brand_id."', '".$short_name."', '".$family_line_xml['data']['name']."', '".$family_line_xml['data']['directory']."', '".$family_line_xml['data']['version']."','".$family_line_xml['data']['configuration_files']."', '0')";
1121                 }
1122
1123                 $this->db->query($sql);
1124                 $family_line_xml['data']['model_list'] = $this->fix_single_array_keys($family_line_xml['data']['model_list']);
1125                 echo "--Updating Model Lines................<br/>";
1126                 foreach($family_line_xml['data']['model_list'] as $model_list) {
1127                     if(is_array($model_list['template_data']['files'])) {
1128                         $template_list = implode(",",$model_list['template_data']['files']);
1129                     } else {
1130                         $template_list = $model_list['template_data']['files'];
1131                     }
1132                     $m_data =& $this->db->getOne("SELECT id FROM endpointman_model_list WHERE id='".$brand_id.$family_line_xml['data']['id'].$model_list['id']."'", array(), DB_FETCHMODE_ASSOC);
1133                     if($m_data) {
1134                         $sql = "UPDATE endpointman_model_list SET max_lines = '".$model_list['lines']."', model = '".$model_list['model']."', template_list = '".$template_list."' WHERE id = '".$brand_id.$family_line_xml['data']['id'].$model_list['id']."'";
1135                     } else {
1136                         $sql = "INSERT INTO endpointman_model_list (`id`, `brand`, `model`, `max_lines`, `product_id`, `template_list`, `enabled`, `hidden`) VALUES ('".$brand_id.$family_line_xml['data']['id'].$model_list['id']."', '".$brand_id."', '".$model_list['model']."', '".$model_list['lines']."', '".$brand_id.$family_line_xml['data']['id']."', '".$template_list."', '0', '0')";
1137                     }
1138                     $this->db->query($sql);
1139                 }
1140             }
1141
1142             $brand_version = max($last_mod, $brand_last_mod);
1143             echo "Updating data..........";
1144             $sql = "UPDATE endpointman_brand_list SET name = '".$brand_name."', cfg_ver = '".$brand_version."', installed = 1, hidden = 0 WHERE id = ".$id;
1145             $this->db->query($sql);
1146             echo "Done!<br/>";
1147            
1148         } else {
1149             echo "<br/>Error Connecting to the Package Repository. Module not installed. Please Try again later.<br/>You Can Also Manually Update The Repository By Downloading Files here: <a href='http://www.provisioner.net/release.html' target='_blank'>Release Repo</a><br />Then Use Manual Upload in Advanced Settings";
1150         }
1151     }
1152
1153     /**
1154      * Remove the brand
1155      * @param int $id Brand ID
1156      */
1157     function remove_brand($id=NULL) {
1158         $brand_dir =& $this->db->getOne("SELECT directory FROM endpointman_brand_list WHERE id=".$id);
1159
1160         $sql = "DELETE FROM endpointman_model_list WHERE brand = '". $id."'";
1161         $this->db->query($sql);
1162
1163         $sql = "DELETE FROM endpointman_product_list WHERE brand = '". $id . "'";
1164         $this->db->query($sql);
1165
1166         $sql = "DELETE FROM endpointman_oui_list WHERE brand = '". $id . "'";
1167         $this->db->query($sql);
1168
1169         $this->deltree(PHONE_MODULES_PATH .$brand_dir);
1170         $sql = "DELETE FROM endpointman_brand_list WHERE id = ". $id;
1171
1172         $this->db->query($sql);
1173     }
1174
1175     /**
1176      * Sync the XML files (incuding all template files) from the hard drive with the database
1177      * @param int $model Model ID
1178      * @return boolean True on sync completed. False on sync failed
1179      */
1180     function sync_model($model=NULL) {
1181
1182         //TODO: combine these queries
1183
1184         $sql = "SELECT * FROM  endpointman_model_list WHERE id='".$model."'";
1185
1186         $model_row =& $this->db->getRow($sql, array(),DB_FETCHMODE_ASSOC);
1187
1188         $sql = "SELECT * FROM  endpointman_product_list WHERE id='".$model_row['product_id']."'";
1189
1190         $product_row =& $this->db->getRow($sql, array(),DB_FETCHMODE_ASSOC);
1191
1192         $sql = "SELECT * FROM  endpointman_brand_list WHERE id=".$model_row['brand'];
1193
1194
1195         $brand_row =& $this->db->getRow($sql, array(),DB_FETCHMODE_ASSOC);
1196
1197         $family_line_xml = $this->xml2array(PHONE_MODULES_PATH.'/endpoint/'.$brand_row['directory'].'/'.$product_row['cfg_dir'].'/family_data.xml');
1198
1199         if($product_row['cfg_ver'] <= $family_line_xml['data']['version']) {
1200             $key = $this->arraysearchrecursive($model_row['model'], $family_line_xml['data']['model_list'], 'model');
1201
1202             if($key === FALSE) {
1203                 $this->error['sync_model'] = "Can't locate model in family XML file";
1204                 return(FALSE);
1205             } else {
1206                 if(is_array($family_line_xml['data']['model_list'][$key[0]]['template_data']['files'])) {
1207                     $template_list = implode(",",$family_line_xml['data']['model_list'][$key[0]]['template_data']['files']);
1208                     $template_list_array = $family_line_xml['data']['model_list'][$key[0]]['template_data']['files'];
1209                 } else {
1210                     $template_list = $family_line_xml['data']['model_list'][$key[0]]['template_data']['files'];
1211                     $template_list_array[0] = $family_line_xml['data']['model_list'][$key[0]]['template_data']['files'];
1212                 }
1213             }
1214
1215             $sql = "UPDATE endpointman_model_list SET template_list = '".$template_list."' WHERE id = '".$model."'";
1216             $this->db->query($sql);
1217
1218             $version = $family_line_xml['data']['version'];
1219             $long_name = $family_line_xml['data']['name'];
1220             $short_name = preg_replace("/\[(.*?)\]/si", "", $family_line_xml['data']['name']);
1221             $configuration_files = $family_line_xml['data']['configuration_files'];
1222
1223             $sql = "UPDATE endpointman_product_list SET long_name = '".$template_list."', short_name = '".$short_name."' , cfg_ver = '".$version."', WHERE id = '".$product_row['id']."'";
1224             $this->db->query($sql);
1225
1226             $template_data_array = array();
1227             foreach($template_list_array as $data) {
1228                 if(file_exists(PHONE_MODULES_PATH.'/endpoint/'.$brand_row['directory'].'/'.$product_row['cfg_dir'].'/'.$data)) {
1229                     $template_data_xml = $this->xml2array(PHONE_MODULES_PATH.'/endpoint/'.$brand_row['directory'].'/'.$product_row['cfg_dir'].'/'.$data);
1230                     $template_data_xml = $this->fix_single_array_keys($template_data_xml['template_data']['item']);
1231                     $template_data_array = array_merge($template_data_array, $template_data_xml);
1232                 }
1233             }
1234
1235             if (file_exists(PHONE_MODULES_PATH.'/endpoint/'.$brand_row['directory'].'/'.$product_row['cfg_dir'].'/template_data_custom.xml')) {
1236                 $template_data_multi = $this->xml2array(PHONE_MODULES_PATH.'/endpoint/'.$brand_row['directory'].'/'.$product_row['cfg_dir'].'/template_data_custom.xml');
1237                 if($template_data_multi) {
1238                     $template_data_multi = $this->fix_single_array_keys($template_data_multi['template_data']['item']);
1239                     $template_data_array = array_merge($template_data_array, $template_data_multi);
1240                 }
1241             }
1242
1243             if (file_exists(PHONE_MODULES_PATH.'/endpoint/'.$brand_row['directory'].'/'.$product_row['cfg_dir'].'/template_data_' . $model_row['model'] . '_custom.xml')) {
1244                 $template_data_multi = $this->xml2array(self::$modules_path . $this->brand_name . "/" . $this->family_line . "/template_data_" . $this->model . "_custom.xml");
1245                 if($template_data_multi) {
1246                     $template_data_multi = $this->fix_single_array_keys($template_data_multi['template_data']['item']);
1247                     $template_data_array = array_merge($template_data_array, $template_data_multi);
1248                 }
1249             }
1250
1251             if(empty($template_data_array)) {
1252                 $this->error['sync_model'] = "No Template Data Found";
1253                 return(FALSE);
1254             }
1255
1256             $sql = "UPDATE endpointman_model_list SET template_data = '".serialize($template_data_array)."' WHERE id = '".$model."'";
1257             $this->db->query($sql);
1258         }
1259
1260         return(TRUE);
1261     }
1262
1263     /**
1264      * Taken from http://www.php.net/manual/en/function.array-search.php#69232
1265      * search haystack for needle and return an array of the key path, FALSE otherwise.
1266      * if NeedleKey is given, return only for this key mixed ArraySearchRecursive(mixed Needle,array Haystack[,NeedleKey[,bool Strict[,array Path]]])
1267      * @author ob (at) babcom (dot) biz
1268      * @param mixed $Needle
1269      * @param array $Haystack
1270      * @param mixed $NeedleKey
1271      * @param bool $Strict
1272      * @param array $Path
1273      * @return array
1274      */
1275     function arraysearchrecursive($Needle,$Haystack,$NeedleKey="",$Strict=false,$Path=array()) {
1276         if(!is_array($Haystack))
1277             return false;
1278         foreach($Haystack as $Key => $Val) {
1279             if(is_array($Val)&&
1280                     $SubPath=$this->arraysearchrecursive($Needle,$Val,$NeedleKey,$Strict,$Path)) {
1281                 $Path=array_merge($Path,Array($Key),$SubPath);
1282                 return $Path;
1283             }
1284             elseif((!$Strict&&$Val==$Needle&&
1285                             $Key==(strlen($NeedleKey)>0?$NeedleKey:$Key))||
1286                     ($Strict&&$Val===$Needle&&
1287                             $Key==(strlen($NeedleKey)>0?$NeedleKey:$Key))) {
1288                 $Path[]=$Key;
1289                 return $Path;
1290             }
1291         }
1292         return false;
1293     }
1294
1295     /**
1296      * cURL function to download files with a progress bar and echo output while downloading to the screen
1297      * @global <type> $ch
1298      * @global <type> $fout
1299      * @global <type> $file_size
1300      * @global <type> $downloaded
1301      * @global <type> $pkg_interface
1302      * @global <type> $progress_bar
1303      * @param <type> $url_file
1304      * @param <type> $destination_file
1305      * @return <type>
1306      */
1307     function download_file_with_progress_bar($url_file, $destination_file) {
1308         global $ch, $fout, $file_size, $downloaded, $pkg_interface, $progress_bar;
1309         set_time_limit(0);
1310         $progress_bar = 1;
1311         $file_size  = 1;
1312         $downloaded = 1;
1313         echo "&nbsp;";
1314         /* open destination file */
1315         $fout = fopen($destination_file, "wb");
1316
1317         /*
1318      *  Originally by Author: Keyvan Minoukadeh
1319      *  Modified by Scott Ullrich to return Content-Length size
1320         */
1321
1322         $ch = curl_init();
1323         curl_setopt($ch, CURLOPT_URL, $url_file);
1324         curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'endpointmanager_read_header');
1325         curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'endpointmanager_read_body');
1326         curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
1327         curl_setopt($ch, CURLOPT_TIMEOUT, 120);
1328
1329         curl_exec($ch);
1330         $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1331         if($fout)
1332             fclose($fout);
1333         curl_close($ch);
1334         return ($http_code == 200) ? true : $http_code;
1335     }
1336
1337     function download_file_no_progress_bar($url_file, $destination_file) {
1338         global $ch, $fout, $file_size, $downloaded, $pkg_interface, $progress_bar;
1339         set_time_limit(0);
1340         $progress_bar = 0;
1341         $file_size  = 1;
1342         $downloaded = 1;
1343         /* open destination file */
1344         $fout = fopen($destination_file, "wb");
1345
1346         /*
1347      *  Originally by Author: Keyvan Minoukadeh
1348      *  Modified by Scott Ullrich to return Content-Length size
1349         */
1350
1351         $ch = curl_init();
1352         curl_setopt($ch, CURLOPT_URL, $url_file);
1353         curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'endpointmanager_read_header');
1354         curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'endpointmanager_read_body');
1355         curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
1356         curl_setopt($ch, CURLOPT_TIMEOUT, 120);
1357
1358         curl_exec($ch);
1359         $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1360         if($fout)
1361             fclose($fout);
1362         curl_close($ch);
1363         return ($http_code == 200) ? true : $http_code;
1364     }
1365
1366     function download_xml_file($url_file, $destination_file) {
1367         global $ch, $fout, $file_size, $downloaded, $pkg_interface, $progress_bar;
1368         set_time_limit(0);
1369         $progress_bar = 0;
1370         $file_size  = 1;
1371         $downloaded = 1;
1372         /* open destination file */
1373         $fout = fopen($destination_file, "wb");
1374
1375         /*
1376      *  Originally by Author: Keyvan Minoukadeh
1377      *  Modified by Scott Ullrich to return Content-Length size
1378         */
1379
1380         $ch = curl_init();
1381         curl_setopt($ch, CURLOPT_URL, $url_file);
1382         curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'endpointmanager_read_header');
1383         curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'endpointmanager_read_body');
1384         curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
1385         curl_setopt($ch, CURLOPT_TIMEOUT, 20);
1386
1387         curl_exec($ch);
1388         $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1389         if($fout)
1390             fclose($fout);
1391         curl_close($ch);
1392         return ($http_code == 200) ? true : $http_code;
1393     }
1394
1395     //This function looks in common linux directories for system executable files. Like ARP & NMAP
1396     function find_exec($exec) {
1397         $usr_bin = glob("/usr/bin/".$exec);
1398         $usr_sbin = glob("/usr/sbin/".$exec);
1399         $sbin = glob("/sbin/".$exec);
1400         $bin = glob("/bin/".$exec);
1401         $etc = glob("/etc/".$exec);
1402         if(isset($usr_bin[0])) {
1403             return("/usr/bin/".$exec);
1404         } elseif(isset($usr_sbin[0])) {
1405             return("/usr/sbin/".$exec);
1406         } elseif(isset($sbin[0])) {
1407             return("/sbin/".$exec);
1408         } elseif(isset($bin[0])) {
1409             return("/bin/".$exec);
1410         } elseif(isset($etc[0])) {
1411             return("/etc/".$exec);
1412         } else {
1413             return($exec);
1414         }
1415     }
1416
1417     /**
1418      * Delete Directory Tree.
1419      * @deprecated In favor of rmrf
1420      * @param string $dir Full Directory path to delete
1421      */
1422     function deltree($dir) {
1423         $this->rmrf($dir);
1424     }
1425
1426     /**
1427      * A function to quickly remove a directory (works in seconds for a hundred thousand files)
1428      * @author http://www.php.net/manual/en/function.glob.php#93669
1429      * @param string $dir Full Directory path to delete
1430      */
1431     function rmrf($dir) {
1432         foreach (glob($dir) as $file) {
1433             if (is_dir($file)) {
1434                 $this->rmrf("$file/*");
1435                 rmdir($file);
1436             } else {
1437                 unlink($file);
1438             }
1439         }
1440     }
1441
1442     /**
1443      * Only used once in all of Endpoint Manager to determine if a table exists
1444      * @param <type> $table
1445      * @return <type>
1446      */
1447     function table_exists($table) {
1448         $sql = "SHOW TABLES FROM asterisk";
1449         $result = $this->db->getAll($sql);
1450
1451         foreach($result as $row) {
1452             if ($row[0] == $table) {
1453                 return TRUE;
1454             }
1455         }
1456         return FALSE;
1457     }
1458
1459     /**
1460      * xml2array() will convert the given XML text to an array in the XML structure.
1461      * @author http://www.php.net/manual/en/function.xml-parse.php#87920
1462      * @param sting $url the XML url (usually a local file)
1463      * @param boolean $get_attributes 1 or 0. If this is 1 the function will get the attributes as well as the tag values - this results in a different array structure in the return value.
1464      * @param string $priority Can be 'tag' or 'attribute'. This will change the way the resulting array sturcture. For 'tag', the tags are given more importance.
1465      * @return array The parsed XML in an array form.
1466      */
1467     function xml2array($url, $get_attributes = 1, $priority = 'tag') {
1468         $contents = "";
1469         if (!function_exists('xml_parser_create')) {
1470             return array ();
1471         }
1472         $parser = xml_parser_create('');
1473         if(!($fp = @ fopen($url, 'rb'))) {
1474             return array ();
1475         }
1476         while(!feof($fp)) {
1477             $contents .= fread($fp, 8192);
1478         }
1479         fclose($fp);
1480         xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8");
1481         xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
1482         xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
1483         xml_parse_into_struct($parser, trim($contents), $xml_values);
1484         xml_parser_free($parser);
1485         if(!$xml_values) {
1486             return; //Hmm...
1487         }
1488         $xml_array = array ();
1489         $parents = array ();
1490         $opened_tags = array ();
1491         $arr = array ();
1492         $current = & $xml_array;
1493         $repeated_tag_index = array ();
1494         foreach ($xml_values as $data) {
1495             unset ($attributes, $value);
1496             extract($data);
1497             $result = array ();
1498             $attributes_data = array ();
1499             if (isset ($value)) {
1500                 if($priority == 'tag') {
1501                     $result = $value;
1502                 }
1503                 else {
1504                     $result['value'] = $value;
1505                 }
1506             }
1507             if(isset($attributes) and $get_attributes) {
1508                 foreach($attributes as $attr => $val) {
1509                     if($priority == 'tag') {
1510                         $attributes_data[$attr] = $val;
1511                     }
1512                     else {
1513                         $result['attr'][$attr] = $val; //Set all the attributes in a array called 'attr'
1514                     }
1515                 }
1516             }
1517             if ($type == "open") {
1518                 $parent[$level -1] = & $current;
1519                 if(!is_array($current) or (!in_array($tag, array_keys($current)))) {
1520                     $current[$tag] = $result;
1521                     if($attributes_data) {
1522                         $current[$tag . '_attr'] = $attributes_data;
1523                     }
1524                     $repeated_tag_index[$tag . '_' . $level] = 1;
1525                     $current = & $current[$tag];
1526                 }
1527                 else {
1528                     if (isset ($current[$tag][0])) {
1529                         $current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
1530                         $repeated_tag_index[$tag . '_' . $level]++;
1531                     }
1532                     else {
1533                         $current[$tag] = array($current[$tag],$result);
1534                         $repeated_tag_index[$tag . '_' . $level] = 2;
1535                         if(isset($current[$tag . '_attr'])) {
1536                             $current[$tag]['0_attr'] = $current[$tag . '_attr'];
1537                             unset ($current[$tag . '_attr']);
1538                         }
1539                     }
1540                     $last_item_index = $repeated_tag_index[$tag . '_' . $level] - 1;
1541                     $current = & $current[$tag][$last_item_index];
1542                 }
1543             }
1544             else if($type == "complete") {
1545                 if(!isset ($current[$tag])) {
1546                     $current[$tag] = $result;
1547                     $repeated_tag_index[$tag . '_' . $level] = 1;
1548                     if($priority == 'tag' and $attributes_data) {
1549                         $current[$tag . '_attr'] = $attributes_data;
1550                     }
1551                 }
1552                 else {
1553                     if (isset ($current[$tag][0]) and is_array($current[$tag])) {
1554                         $current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
1555                         if ($priority == 'tag' and $get_attributes and $attributes_data) {
1556                             $current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
1557                         }
1558                         $repeated_tag_index[$tag . '_' . $level]++;
1559                     }
1560                     else {
1561                         $current[$tag] = array($current[$tag],$result);
1562                         $repeated_tag_index[$tag . '_' . $level] = 1;
1563                         if ($priority == 'tag' and $get_attributes) {
1564                             if (isset ($current[$tag . '_attr'])) {
1565                                 $current[$tag]['0_attr'] = $current[$tag . '_attr'];
1566                                 unset ($current[$tag . '_attr']);
1567                             }
1568                             if ($attributes_data) {
1569                                 $current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
1570                             }
1571                         }
1572                         $repeated_tag_index[$tag . '_' . $level]++; //0 and 1 index is already taken
1573                     }
1574                 }
1575             }
1576             else if($type == 'close') {
1577                 $current = & $parent[$level -1];
1578             }
1579         }
1580         return ($xml_array);
1581     }
1582
1583     /**
1584      * This function takes a string and tries to determine if it's a valid mac addess, return FALSE if invalid
1585      * @param string $mac The full mac address
1586      * @return mixed The cleaned up MAC is it was a MAC or False if not a mac
1587      */
1588     function mac_check_clean($mac) {
1589         if ((strlen($mac) == "17") OR (strlen($mac) == "12")) {
1590             //It might be better to use switch here instead of these IF statements...
1591
1592             //Is the mac separated by colons(:)?
1593             if (preg_match("/[0-9a-f][0-9a-f][:-]".
1594             "[0-9a-f][0-9a-f][:-]".
1595             "[0-9a-f][0-9a-f][:-]".
1596             "[0-9a-f][0-9a-f][:-]".
1597             "[0-9a-f][0-9a-f][:-]".
1598             "[0-9a-f][0-9a-f]/i", $mac)) {
1599                 return(strtoupper(str_replace(":", "", $mac)));
1600                 //Is the string exactly 12 characters?
1601             } elseif(strlen($mac) == "12") {
1602                 //Now is the string a valid HEX mac address?
1603                 if (preg_match("/[0-9a-f][0-9a-f]".
1604                 "[0-9a-f][0-9a-f]".
1605                 "[0-9a-f][0-9a-f]".
1606                 "[0-9a-f][0-9a-f]".
1607                 "[0-9a-f][0-9a-f]".
1608                 "[0-9a-f][0-9a-f]/i", $mac)) {
1609                     return(strtoupper($mac));
1610                 } else {
1611                     return(FALSE);
1612                 }
1613                 //Is the mac separated by whitespaces?
1614             } elseif(preg_match("/[0-9a-f][0-9a-f][\s]".
1615             "[0-9a-f][0-9a-f][\s]".
1616             "[0-9a-f][0-9a-f][\s]".
1617             "[0-9a-f][0-9a-f][\s]".
1618             "[0-9a-f][0-9a-f][\s]".
1619             "[0-9a-f][0-9a-f]/i", $mac)) {
1620                 return(strtoupper(str_replace(" ", "", $mac)));
1621             } else {
1622                 return(FALSE);
1623             }
1624         } else {
1625             return(FALSE);
1626         }
1627     }
1628
1629     /**
1630      * Check for valid netmast to avoid security issues
1631      * @param string $mask the complete netmask, eg [1.1.1.1/24]
1632      * @return boolean True if valid, False if not
1633      */
1634     function validate_netmask($mask) {
1635         if (preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\/(\d{1,2})$/", $mask)) {
1636             return(TRUE);
1637         } else {
1638             return(FALSE);
1639         }
1640     }
1641
1642     /**
1643      * Discover New Device/Hardware
1644      * nmap will actually discover 'unseen' devices that the VoIP server hasn't heard from
1645      * If the user just wishes to use the local arp cache they can tell the function to not use nmap
1646      * This results in a speed increase from 60 seconds to less than one second.
1647      * @author tm1000
1648      * @version 1.5
1649      * @param mixed $netmask The netmask, eg [1.1.1.1/24]
1650      * @param boolean $use_nmap True use nmap, false don't use it
1651      * @return array List of devices found on the network
1652      */
1653     function discover_new($netmask, $use_nmap=TRUE) {
1654
1655         if (($use_nmap) AND (file_exists($this->global_cfg['nmap_location'])) AND ($this->validate_netmask($netmask))) {
1656             shell_exec($this->global_cfg['nmap_location'].' -v -sP '. $netmask);
1657         } elseif(!$this->validate_netmask($netmask)) {
1658             $this->error['discover_new'] = "Invalid Netmask";
1659             return(FALSE);
1660         } elseif(!file_exists($this->global_cfg['nmap_location'])) {
1661             $this->error['discover_new'] = "Could Not Find NMAP, Using ARP Only";
1662             //return(FALSE);
1663         }
1664         //Get arp list
1665         $arp_list = shell_exec($this->global_cfg['arp_location'] . " -an");
1666
1667         //Throw arp list into an array, break by new lines
1668         $arp_array = explode("\n", $arp_list);
1669
1670
1671         //Find all references to active computers by searching out mac addresses.
1672         $temp = array_values(array_unique(preg_grep("/[0-9a-f][0-9a-f][:-]".
1673                 "[0-9a-f][0-9a-f][:-]".
1674                 "[0-9a-f][0-9a-f][:-]".
1675                 "[0-9a-f][0-9a-f][:-]".
1676                 "[0-9a-f][0-9a-f][:-]".
1677                 "[0-9a-f][0-9a-f]/i", $arp_array)));
1678
1679         //Go through each row of valid arp entries and pull out the information and add it into a nice array!
1680         foreach ($temp as $key => &$value) {
1681
1682             //Pull out the IP address from row. It's always the first entry in the row and it can only be a max of 15 characters with the delimiters
1683             preg_match_all("/\((.*?)\)/",$value,$matches);
1684             $ip = $matches[1];
1685             $ip = $ip[0];
1686
1687             //Pull out the mac address by looking for the delimiter
1688             $mac = substr($value, (strpos($value, ":") -2), 17);
1689
1690             //Get rid of the delimiter
1691             $mac_strip = strtoupper(str_replace(":", "", $mac));
1692
1693             //arp -n will return a MAC address of 000000000000 if no hardware was found, so we need to ignore it
1694             if($mac_strip != "000000000000") {
1695                 //only use the first 6 characters for the oui: http://en.wikipedia.org/wiki/Organizationally_Unique_Identifier
1696                 $oui = substr($mac_strip,0,6);
1697
1698                 //Find the matching brand model to the oui
1699                 $oui_sql = "SELECT endpointman_brand_list.name, endpointman_brand_list.id FROM endpointman_oui_list, endpointman_brand_list WHERE oui LIKE '%". $oui ."%' AND endpointman_brand_list.id = endpointman_oui_list.brand AND endpointman_brand_list.installed = 1 LIMIT 1";
1700
1701                 $brand =& $this->db->getRow($oui_sql, array(), DB_FETCHMODE_ASSOC);
1702                
1703                 $res =& $this->db->query($oui_sql);
1704                 $brand_count = $res->numRows();
1705                
1706                 if (!$brand_count) {
1707                     //oui doesn't have a matching mysql reference, probably a PC/router/wap/printer of some sort.
1708                     $brand['name'] = FALSE;
1709                     $brand['id'] = NULL;
1710                 }
1711
1712                 //Find out if endpoint has already been configured for this mac address
1713                 $epm_sql = "SELECT * FROM endpointman_mac_list WHERE mac LIKE  '%". $mac_strip ."%'";
1714                 $epm_row =& $this->db->getRow($epm_sql, array(), DB_FETCHMODE_ASSOC);
1715
1716                 $res =& $this->db->query($epm_sql);
1717                 $epm_count = $res->numRows();
1718
1719                 if ($epm_count) {
1720                     $epm = TRUE;
1721                 } else {
1722                     $epm = FALSE;
1723                 }
1724
1725                 //Add into a final array
1726                 $final[$key] = array("ip" => $ip, "mac" => $mac, "mac_strip" => $mac_strip, "oui" => $oui, "brand" => $brand['name'], "brand_id" => $brand['id'], "endpoint_managed" => $epm);
1727             }
1728         }
1729
1730         $final = array_values($final);
1731
1732         if(!is_array($final)) {
1733             return(FALSE);
1734         } else {
1735             return ($final);
1736         }
1737     }
1738
1739     function areaAvailable($model,$area=NULL) {
1740
1741         $temp[0]['value'] = 'GLOBAL';
1742         $temp[0]['text'] = 'GLOBAL';
1743         $temp[0]['selected'] = 0;
1744
1745         $temp[1]['value'] = 'ALL';
1746         $temp[1]['text'] = 'ALL LINES';
1747         $temp[1]['selected'] = 0;
1748
1749         $sql = "SELECT max_lines FROM endpointman_model_list WHERE id = '". $model."'";
1750
1751         $count = $this->db->getOne($sql);
1752         for($z=0;$z<$count;$z++) {
1753             $result[$z]['id'] = $z + 1;
1754             $result[$z]['model'] = $z + 1;
1755         }
1756
1757         $i = 2;
1758         foreach($result as $row) {
1759             if ($row['id'] == $model) {
1760                 $temp[$i]['value'] = $row['id'];
1761                 $temp[$i]['text'] = 'Line '.$row['model'];
1762                 $temp[$i]['selected'] = 'selected';
1763             }else {
1764                 $temp[$i]['value'] = $row['id'];
1765                 $temp[$i]['text'] = 'Line '.$row['model'];
1766                 $temp[$i]['selected'] = 0;
1767             }
1768             $i++;
1769         }
1770
1771         return($temp);
1772     }
1773
1774     function modelsAvailable($model=NULL, $macAdd=NULL, $brand=NULL, $product=NULL) {
1775         if (isset($macAdd)) {
1776             $oui=substr($macAdd,0,6);
1777         }
1778         if ((!isset($oui)) && (!isset($brand)) && (!isset($model))) {
1779             $sql="SELECT endpointman_model_list.* FROM endpointman_model_list, endpointman_product_list WHERE endpointman_model_list.product_id = endpointman_product_list.id AND endpointman_model_list.enabled = 1 AND endpointman_product_list.hidden = 0";
1780         }elseif((isset($brand)) && ($brand !=0)) {
1781             $sql="SELECT endpointman_model_list.* FROM endpointman_model_list, endpointman_product_list WHERE endpointman_model_list.product_id = endpointman_product_list.id AND endpointman_model_list.enabled = 1 AND endpointman_product_list.hidden = 0 AND endpointman_model_list.brand = " . $brand;
1782         }elseif((isset($product)) && ($product !=0)) {
1783             $sql="SELECT * FROM endpointman_model_list WHERE product_id = ".$product;
1784         } else {
1785             $sql="SELECT endpointman_model_list.* FROM endpointman_model_list, endpointman_product_list WHERE endpointman_model_list.product_id = endpointman_product_list.id AND endpointman_model_list.enabled = 1 AND endpointman_product_list.hidden = 0";
1786         }
1787
1788
1789         $result1 =& $this->db->getAll($sql, array(),DB_FETCHMODE_ASSOC);
1790
1791         $i = 1;
1792         foreach($result1 as $row) {
1793             if ($row['id'] == $model) {
1794                 $temp[$i]['value'] = $row['id'];
1795                 $temp[$i]['text'] = $row['model'];
1796                 $temp[$i]['selected'] = 'selected';
1797             }else {
1798                 $temp[$i]['value'] = $row['id'];
1799                 $temp[$i]['text'] = $row['model'];
1800                 $temp[$i]['selected'] = 0;
1801             }
1802             $i++;
1803         }
1804
1805         if(!isset($temp)) {
1806             $this->error['modelsAvailable'] = "You need to enable at least ONE model";
1807             return(FALSE);
1808         } else {
1809             return($temp);
1810         }
1811     }
1812
1813     function linesAvailable($model=NULL, $macid=NULL) {
1814
1815         if(isset($model)) {
1816             $sql="SELECT  `max_lines` FROM  `endpointman_model_list` WHERE  `id` LIKE";
1817         }
1818
1819
1820         $result1 =& $this->db->getAll($sql, array(),DB_FETCHMODE_ASSOC);
1821
1822         $i = 1;
1823         foreach($result1 as $row) {
1824             if ($row['id'] == $model) {
1825                 $temp[$i]['value'] = $row['id'];
1826                 $temp[$i]['text'] = $row['model'];
1827                 $temp[$i]['selected'] = 'selected';
1828             }else {
1829                 $temp[$i]['value'] = $row['id'];
1830                 $temp[$i]['text'] = $row['model'];
1831                 $temp[$i]['selected'] = 0;
1832             }
1833             $i++;
1834         }
1835
1836         if(!isset($temp)) {
1837             $this->error['modelsAvailable'] = "You need to enable at least ONE model";
1838             return(FALSE);
1839         } else {
1840             return($temp);
1841         }
1842     }
1843
1844     function displayExtension($ext = NULL) {
1845         if(!isset($ext)) {
1846             $not_added="SELECT devices.id, devices.description FROM devices WHERE tech='sip' AND devices.id not in (SELECT devices.id FROM devices, endpointman_line_list WHERE tech='sip' AND devices.id = endpointman_line_list.ext ) ORDER BY devices.id";
1847         } else {
1848             $not_added="SELECT devices.id, devices.description FROM devices WHERE tech='sip' AND devices.id not in (SELECT devices.id FROM devices, endpointman_line_list WHERE tech='sip' AND devices.id = endpointman_line_list.ext AND endpointman_line_list.ext !=".$ext." ) ORDER BY devices.id";
1849         }
1850         $result =& $this->db->getAll($not_added,array(), DB_FETCHMODE_ASSOC);
1851
1852
1853         $i = 1;
1854         $temp = array();
1855         foreach($result as $row) {
1856             $temp[$i]['value'] = $row['id'];
1857             $temp[$i]['text'] = $row['id'] . " --- " . $row['description'];
1858             if ($row['id'] == $ext) {
1859                 $temp[$i]['selected'] = "selected";
1860             }
1861             $i++;
1862         }
1863
1864         return($temp);
1865
1866     }
1867     /**
1868      * Returns list of Brands that are installed and not hidden and that have at least one model enabled under them
1869      * @param integer $selected ID Number of the brand that is supposed to be selected in a drop-down list box
1870      * @return array Number array used to generate a select box
1871      */
1872     function brandAvailable ($selected = NULL) {
1873         $sql="SELECT DISTINCT endpointman_brand_list.name, endpointman_brand_list.id FROM  endpointman_brand_list,endpointman_model_list WHERE endpointman_model_list.brand = endpointman_brand_list.id AND endpointman_model_list.enabled = 1 AND endpointman_model_list.hidden = 0 AND endpointman_brand_list.installed = 1 AND endpointman_brand_list.hidden = 0";
1874        
1875         $data =& $this->db->getAll($sql,array(), DB_FETCHMODE_ASSOC);
1876         $temp[0]['value'] = "";
1877         $temp[0]['text'] = "";
1878         $i = 1;
1879         foreach($data as $row) {
1880             $temp[$i]['value'] = $row['id'];
1881             $temp[$i]['text'] = $row['name'];
1882             if ($row['id'] == $selected) {
1883                 $temp[$i]['selected'] = TRUE;
1884             } else {
1885                 $temp[$i]['selected'] = NULL;
1886             }
1887             $i++;
1888         }
1889         return($temp);
1890     }
1891
1892     function display_templates($product_id,$temp_select = NULL) {
1893         $i = 0;
1894         $sql="SELECT id FROM  endpointman_product_list WHERE endpointman_product_list.id ='".$product_id."'";
1895
1896         $id =& $this->db->getOne($sql);
1897
1898         $sql="SELECT * FROM  endpointman_template_list WHERE  product_id = '".$id."'";
1899
1900         $data =& $this->db->getAll($sql,array(), DB_FETCHMODE_ASSOC);
1901         foreach($data as $row) {
1902             $temp[$i]['value'] = $row['id'];
1903             $temp[$i]['text'] = $row['name'];
1904             if ($row['id'] == $temp_select) {
1905                 $temp[$i]['selected'] = "selected";
1906             }
1907             $i++;
1908         }
1909         $temp[$i]['value'] = 0;
1910         if ($temp_select == 0) {
1911             $temp[$i]['text'] = "Custom...";
1912             $temp[$i]['selected'] = "selected";
1913         } else {
1914             $temp[$i]['text'] = "Custom...";
1915         }
1916
1917         return($temp);
1918     }
1919
1920     function listTZ($selected) {
1921         $sql="SELECT tz FROM endpointman_time_zones";
1922         $data =& $this->db->getAll($sql,array(), DB_FETCHMODE_ASSOC);
1923         $i = 0;
1924         foreach($data as $row) {
1925             if ($row['tz'] == $selected) {
1926                 $temp[$i]['value'] = $row['tz'];
1927                 $temp[$i]['text'] = $row['tz'];
1928                 $temp[$i]['selected'] = 1;
1929             }else {
1930                 $temp[$i]['value'] = $row['tz'];
1931                 $temp[$i]['text'] = $row['tz'];
1932                 $temp[$i]['selected'] = 0;
1933             }
1934             $i++;
1935         }
1936         return($temp);
1937     }
1938
1939 }
1940
1941 function endpointman_flush_buffers(){
1942     ob_end_flush();
1943     //ob_flush();
1944     flush();
1945     ob_start();
1946 }
1947
1948 function endpointman_update_progress_bar($out) {
1949     echo '<script type="text/javascript">document.getElementById(\'DivExample\').innerHTML="%'.$out.'";</script>';
1950 }
1951
1952 function endpointmanager_read_header($ch, $string) {
1953     global $file_size, $fout;
1954     $length = strlen($string);
1955     $regs = "";
1956     preg_match("/(Content-Length:) (.*)/i", $string, $regs);
1957     if((isset($regs[2])) AND ($regs[2] <> "")) {
1958         $file_size = intval($regs[2]);
1959     }
1960     //ob_flush();
1961     endpointman_flush_buffers();
1962     return $length;
1963 }
1964
1965 function endpointmanager_read_body($ch, $string) {
1966     global $fout, $file_size, $downloaded, $lastseen, $progress_bar;
1967     $length = strlen($string);
1968     $downloaded += intval($length);
1969     $downloadProgress = round(100 * (1 - $downloaded / $file_size), 0);
1970     $downloadProgress = 100 - $downloadProgress;
1971     if($lastseen <> $downloadProgress and $downloadProgress < 101) {
1972         if($progress_bar) {
1973             endpointman_update_progress_bar($downloadProgress);
1974         }
1975         $lastseen = $downloadProgress;
1976     }
1977     if($fout)
1978         fwrite($fout, $string);
1979     //ob_flush();
1980     endpointman_flush_buffers();
1981     return $length;
1982 }
Note: See TracBrowser for help on using the browser.