From eb49bde71f3b10efd1df21a47c7ecc3164b1832c Mon Sep 17 00:00:00 2001 From: "marcos.alconada" <marcos.alconada@artica.es> Date: Tue, 19 Feb 2019 15:50:14 +0100 Subject: [PATCH 01/50] Ticekt resolved Former-commit-id: b93b1c5cb39239f3b038d55b39e8102de1628742 --- pandora_console/extensions/dbmanager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandora_console/extensions/dbmanager.php b/pandora_console/extensions/dbmanager.php index 2aface6996..c924bd3ea9 100644 --- a/pandora_console/extensions/dbmanager.php +++ b/pandora_console/extensions/dbmanager.php @@ -106,7 +106,7 @@ function dbmgr_extension_main() echo '<br /><br />'; echo "<form method='post' action=''>"; - html_print_textarea('sql', 5, 50, html_entity_decode($sql, ENT_QUOTES)); + html_print_textarea('sql', 5, 50, $sql); echo '<br />'; echo '<div class="action-buttons" style="width: 100%">'; echo '<br />'; From 6ef1c3951af5cc8e82279531fc7b19b23b580f6f Mon Sep 17 00:00:00 2001 From: "marcos.alconada" <marcos.alconada@artica.es> Date: Thu, 21 Feb 2019 14:04:00 +0100 Subject: [PATCH 02/50] Ticket Changed Former-commit-id: e258f0932398d9fc58a8d097098c83b7bed084c5 --- pandora_console/operation/agentes/status_monitor.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandora_console/operation/agentes/status_monitor.php b/pandora_console/operation/agentes/status_monitor.php index ada6cd6ec6..953996678a 100644 --- a/pandora_console/operation/agentes/status_monitor.php +++ b/pandora_console/operation/agentes/status_monitor.php @@ -945,7 +945,7 @@ $sql = 'SELECT LIMIT '.$offset.','.$limit_sql; // When you enter for the first time you have less than 4 query params in the url -$first_interaction = count($_GET) > 4; +$first_interaction = count($_GET); // We do not show the modules until the user searches with the filter if ($first_interaction) { if (! defined('METACONSOLE')) { @@ -1032,6 +1032,7 @@ if (($config['dbtype'] == 'oracle') && ($result !== false)) { } } + // Start Build List Result // if (!empty($result)) { From 35ad2f4bb5d7d537bc69804643feedc4f0644ff2 Mon Sep 17 00:00:00 2001 From: "marcos.alconada" <marcos.alconada@artica.es> Date: Fri, 22 Feb 2019 11:21:38 +0100 Subject: [PATCH 03/50] Validations for default values Former-commit-id: a33139b817ece206a611d5f2678b62c876a8e41f --- .../operation/agentes/status_monitor.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pandora_console/operation/agentes/status_monitor.php b/pandora_console/operation/agentes/status_monitor.php index 953996678a..6e3c26b470 100644 --- a/pandora_console/operation/agentes/status_monitor.php +++ b/pandora_console/operation/agentes/status_monitor.php @@ -63,6 +63,17 @@ $sort = get_parameter('sort', 'none'); $id_module = (int) get_parameter('id_module', 0); $ag_custom_fields = (array) get_parameter('ag_custom_fields', []); $module_option = (int) get_parameter('module_option', 1); +$autosearch = false; + +// It is validated if it receives parameters different from those it has by default +if ($ag_freestring != '' || $moduletype != '' || $datatype != '' + || $ag_modulename != '' || $refr != 0 || $offset != 0 || $status != 4 + || $modulegroup != -1 || $tag_filter != 0 || $sortField != '' + || $sort != '' || $id_module != 0 || $ag_custom_fields != null + || $module_option != 1 +) { + $autosearch = true; +} if (!is_metaconsole()) { $ag_group = (int) get_parameter('ag_group', 0); @@ -947,7 +958,7 @@ $sql = 'SELECT // When you enter for the first time you have less than 4 query params in the url $first_interaction = count($_GET); // We do not show the modules until the user searches with the filter -if ($first_interaction) { +if ($first_interaction || $autosearch) { if (! defined('METACONSOLE')) { $result = db_get_all_rows_sql($sql); From 504a8e9d1a3c0ccb92090d4131b7f39acfa839d1 Mon Sep 17 00:00:00 2001 From: daniel <daniel.barbero@artica.es> Date: Mon, 25 Feb 2019 13:02:39 +0100 Subject: [PATCH 04/50] fixed warnings php Former-commit-id: d21cb02113c65a7f50a5e29f7f536e85ba5cb945 --- pandora_console/extras/pandora_diag.php | 4 +- .../godmode/groups/modu_group_list.php | 179 ++++--- .../godmode/massive/massive_add_alerts.php | 88 ++-- .../godmode/servers/manage_recontask.php | 109 ++-- .../godmode/servers/manage_recontask_form.php | 479 ++++++++++++++---- pandora_console/include/functions_events.php | 46 +- .../include/functions_pandora_networkmap.php | 293 ++++++----- .../agentes/pandora_networkmap.editor.php | 46 +- .../agentes/pandora_networkmap.view.php | 157 +++--- 9 files changed, 913 insertions(+), 488 deletions(-) diff --git a/pandora_console/extras/pandora_diag.php b/pandora_console/extras/pandora_diag.php index 519b4b32a5..d6cd017087 100644 --- a/pandora_console/extras/pandora_diag.php +++ b/pandora_console/extras/pandora_diag.php @@ -106,7 +106,9 @@ function get_value_sum($arr) { foreach ($arr as $clave) { foreach ($clave as $valor) { - $result += $valor; + if (is_numeric($valor) === true) { + $result += $valor; + } } } diff --git a/pandora_console/godmode/groups/modu_group_list.php b/pandora_console/godmode/groups/modu_group_list.php index f75d46cfd8..9dbc9311a6 100644 --- a/pandora_console/godmode/groups/modu_group_list.php +++ b/pandora_console/godmode/groups/modu_group_list.php @@ -1,17 +1,32 @@ <?php +/** + * Extension to manage a list of gateways and the node address where they should + * point to. + * + * @category Extensions + * @package Pandora FMS + * @subpackage Community + * @version 1.0.0 + * @license See below + * + * ______ ___ _______ _______ ________ + * | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __| + * | __/| _ | | _ || _ | _| _ | | ___| |__ | + * |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| + * + * ============================================================================ + * Copyright (c) 2005-2019 Artica Soluciones Tecnologicas + * Please see http://pandorafms.org for full contribution list + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation for version 2. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ============================================================================ + */ -// Pandora FMS - http://pandorafms.com -// ================================================== -// Copyright (c) 2005-2010 Artica Soluciones Tecnologicas -// Please see http://pandorafms.org for full contribution list -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation for version 2. -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// Load global vars global $config; check_login(); @@ -51,15 +66,22 @@ if (is_ajax()) { } if (!is_metaconsole()) { - // Header - ui_print_page_header(__('Module groups defined in %s', get_product_name()), 'images/module_group.png', false, '', true, ''); + // Header. + ui_print_page_header( + __('Module groups defined in %s', get_product_name()), + 'images/module_group.png', + false, + '', + true, + '' + ); } $create_group = (bool) get_parameter('create_group'); $update_group = (bool) get_parameter('update_group'); $delete_group = (bool) get_parameter('delete_group'); -// Create group +// Create group. if ($create_group) { $name = (string) get_parameter('name'); $icon = (string) get_parameter('icon'); @@ -70,22 +92,29 @@ if ($create_group) { if ($name) { if (!$check) { - $result = db_process_sql_insert('tmodule_group', ['name' => $name]); + $result = db_process_sql_insert( + 'tmodule_group', + ['name' => $name] + ); if ($result) { ui_print_success_message(__('Group successfully created')); } else { - ui_print_error_message(__('There was a problem creating group')); + ui_print_error_message( + __('There was a problem creating group') + ); } } else { - ui_print_error_message(__('Each module group must have a different name')); + ui_print_error_message( + __('Each module group must have a different name') + ); } } else { ui_print_error_message(__('Module group must have a name')); } } -// Update group +// Update group. if ($update_group) { $id_group = (int) get_parameter('id_group'); $name = (string) get_parameter('name'); @@ -98,38 +127,79 @@ if ($update_group) { if ($name) { if (!$check || $subcheck == $name) { - $result = db_process_sql_update('tmodule_group', ['name' => $name], ['id_mg' => $id_group]); + $result = db_process_sql_update( + 'tmodule_group', + ['name' => $name], + ['id_mg' => $id_group] + ); if ($result !== false) { ui_print_success_message(__('Group successfully updated')); } else { - ui_print_error_message(__('There was a problem modifying group')); + ui_print_error_message( + __('There was a problem modifying group') + ); } } else { - ui_print_error_message(__('Each module group must have a different name')); + ui_print_error_message( + __('Each module group must have a different name') + ); } } else { ui_print_error_message(__('Module group must have a name')); } } -// Delete group +// Delete group. if ($delete_group) { $id_group = (int) get_parameter('id_group'); $result = db_process_sql_delete('tmodule_group', ['id_mg' => $id_group]); if ($result) { - $result = db_process_sql_update('tagente_modulo', ['id_module_group' => 0], ['id_module_group' => $id_group]); - db_process_sql_update('tpolicy_modules', ['id_module_group' => 0], ['id_module_group' => $id_group]); - db_process_sql_update('tcontainer_item', ['id_module_group' => 0], ['id_module_group' => $id_group]); - db_process_sql_update('tnetwork_component', ['id_module_group' => 0], ['id_module_group' => $id_group]); - db_process_sql_update('treport_content', ['id_module_group' => 0], ['id_module_group' => $id_group]); - db_process_sql_update('tnetwork_map', ['id_module_group' => 0], ['id_module_group' => $id_group]); - db_process_sql_update('tlocal_component', ['id_module_group' => 0], ['id_module_group' => $id_group]); - db_process_sql_update('treport_content_template', ['id_module_group' => 0], ['id_module_group' => $id_group]); + $result = db_process_sql_update( + 'tagente_modulo', + ['id_module_group' => 0], + ['id_module_group' => $id_group] + ); + db_process_sql_update( + 'tpolicy_modules', + ['id_module_group' => 0], + ['id_module_group' => $id_group] + ); + db_process_sql_update( + 'tcontainer_item', + ['id_module_group' => 0], + ['id_module_group' => $id_group] + ); + db_process_sql_update( + 'tnetwork_component', + ['id_module_group' => 0], + ['id_module_group' => $id_group] + ); + db_process_sql_update( + 'treport_content', + ['id_module_group' => 0], + ['id_module_group' => $id_group] + ); + db_process_sql_update( + 'tnetwork_map', + ['id_module_group' => 0], + ['id_module_group' => $id_group] + ); + db_process_sql_update( + 'tlocal_component', + ['id_module_group' => 0], + ['id_module_group' => $id_group] + ); + db_process_sql_update( + 'treport_content_template', + ['id_module_group' => 0], + ['id_module_group' => $id_group] + ); - // A group with no modules can be deleted, to avoid a message error then do the follwing + // A group with no modules can be deleted, + // to avoid a message error then do the follwing. if ($result !== false) { $result = true; } @@ -150,36 +220,15 @@ $offset = (int) get_parameter('offset', 0); ui_pagination($total_groups, $url, $offset); -switch ($config['dbtype']) { - case 'mysql': - $sql = 'SELECT * - FROM tmodule_group - ORDER BY name ASC - LIMIT '.$offset.', '.$config['block_size']; - break; - case 'postgresql': - $sql = 'SELECT * - FROM tmodule_group - ORDER BY name ASC - LIMIT '.$config['block_size'].' OFFSET '.$offset; - break; - - case 'oracle': - $set = []; - $set['limit'] = $config['block_size']; - $set['offset'] = $offset; - - $sql = 'SELECT * - FROM tmodule_group - ORDER BY name ASC'; - - $sql = oracle_recode_query($sql, $set); - break; -} +$sql = 'SELECT * + FROM tmodule_group + ORDER BY name ASC + LIMIT '.$offset.', '.$config['block_size']; $groups = db_get_all_rows_sql($sql); +$table = new stdClass(); $table->width = '100%'; $table->class = 'databox data'; @@ -210,11 +259,21 @@ if (!empty($groups)) { html_print_table($table); } else { - ui_print_info_message(['no_close' => true, 'message' => __('There are no defined module groups') ]); + ui_print_info_message( + [ + 'no_close' => true, + 'message' => __('There are no defined module groups'), + ] + ); } echo '<form method="post" action="index.php?sec=gmodules&sec2=godmode/groups/configure_modu_group">'; echo '<div class="action-buttons" style="width: '.$table->width.'">'; -html_print_submit_button(__('Create module group'), 'crt', false, 'class="sub next"'); +html_print_submit_button( + __('Create module group'), + 'crt', + false, + 'class="sub next"' +); echo '</div>'; echo '</form>'; diff --git a/pandora_console/godmode/massive/massive_add_alerts.php b/pandora_console/godmode/massive/massive_add_alerts.php index 989a8cd3a8..bf52fd0459 100755 --- a/pandora_console/godmode/massive/massive_add_alerts.php +++ b/pandora_console/godmode/massive/massive_add_alerts.php @@ -1,17 +1,32 @@ <?php +/** + * Extension to manage a list of gateways and the node address where they should + * point to. + * + * @category Extensions + * @package Pandora FMS + * @subpackage Community + * @version 1.0.0 + * @license See below + * + * ______ ___ _______ _______ ________ + * | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __| + * | __/| _ | | _ || _ | _| _ | | ___| |__ | + * |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| + * + * ============================================================================ + * Copyright (c) 2005-2019 Artica Soluciones Tecnologicas + * Please see http://pandorafms.org for full contribution list + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation for version 2. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ============================================================================ + */ -// Pandora FMS - http://pandorafms.com -// ================================================== -// Copyright (c) 2005-2009 Artica Soluciones Tecnologicas -// Please see http://pandorafms.org for full contribution list -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation for version 2. -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// Load global vars check_login(); if (! check_acl($config['id_user'], 0, 'AW')) { @@ -34,7 +49,8 @@ if (is_ajax()) { if ($get_agents) { $id_group = (int) get_parameter('id_group', 0); - // Is is possible add keys prefix to avoid auto sorting in js object conversion + // Is is possible add keys prefix to avoid auto + // sorting in js object conversion. $keys_prefix = (string) get_parameter('keys_prefix', ''); if ($id_group == 0) { @@ -62,7 +78,7 @@ if (is_ajax()) { ); } - // Add keys prefix + // Add keys prefix. if ($keys_prefix !== '') { foreach ($agents as $k => $v) { $agents[$keys_prefix.$k] = $v; @@ -92,8 +108,8 @@ function process_manage_add($id_alert_template, $id_agents, $module_names) foreach ($module_names as $module) { foreach ($id_agents as $id_agent) { - $module_id = modules_get_agentmodule_id($module, $id_agent); - $modules_id[] = $module_id['id_agente_modulo']; + $module_id = modules_get_agentmodule_id($module, $id_agent); + $modules_id[] = $module_id['id_agente_modulo']; } } @@ -148,6 +164,7 @@ if (!$own_info['is_admin'] && !check_acl($config['id_user'], 0, 'AW')) { $return_all_group = true; } +$table = new stdClass(); $table->id = 'add_table'; $table->class = 'databox filters'; $table->width = '100%'; @@ -251,10 +268,10 @@ html_print_submit_button(__('Add'), 'go', false, 'class="sub add"'); echo '</div>'; echo '</form>'; -// TODO: Change to iu_print_error system +// TODO: Change to iu_print_error system. echo '<h3 class="error invisible" id="message"> </h3>'; -// Hack to translate text "none" in PHP to javascript +// Hack to translate text "none" in PHP to javascript. echo '<span id ="none_text" style="display: none;">'.__('None').'</span>'; ui_require_jquery_file('form'); @@ -270,42 +287,40 @@ $(document).ready (function () { var get_parameters_count = window.location.href.slice( window.location.href.indexOf('?') + 1).split('&').length; var post_parameters_count = $("#form_alerts").serializeArray().length; - + var count_parameters = get_parameters_count + post_parameters_count; - + if (count_parameters > limit_parameters_massive) { alert("<?php echo __('Unsucessful sending the data, please contact with your administrator or make with less elements.'); ?>"); return false; } }); - - + $("#checkbox-recursion").click(function () { $("#id_group").trigger("change"); }); - + $("#id_agents").change(agent_changed_by_multiple_agents); - + $("#id_group").change (function () { var $select = $("#id_agents").enable (); $("#agent_loading").show (); $("option", $select).remove (); - + jQuery.post ("ajax.php", {"page" : "godmode/massive/massive_add_alerts", "get_agents" : 1, "id_group" : this.value, "recursion" : $("#checkbox-recursion").is(":checked") ? 1 : 0, - // Add a key prefix to avoid auto sorting in js object conversion + // Add a key prefix to avoid auto sorting in js object conversion. "keys_prefix" : "_" }, function (data, status) { options = ""; jQuery.each (data, function (id, value) { - // Remove keys_prefix from the index + // Remove keys_prefix from the index. id = id.substring(1); - options += "<option value=\""+id+"\">"+value+"</option>"; }); $("#id_agents").append (options); @@ -315,40 +330,39 @@ $(document).ready (function () { "json" ); }); - + $("#id_group").value = "0"; - + $("#id_group").click ( function () { $(this).css ("width", "auto"); }); - + $("#id_group").blur (function () { $(this).css ("width", "180px"); }); - + $("#id_agents").click ( function () { $(this).css ("width", "auto"); }); - + $("#id_agents").blur (function () { $(this).css ("width", "180px"); }); - + $("#module").click ( function () { $(this).css ("width", "auto"); }); - + $("#module").blur (function () { $(this).css ("width", "180px"); }); - + $("#modules_selection_mode").change (function() { $("#id_agents").trigger('change'); }); - }); /* ]]> */ </script> diff --git a/pandora_console/godmode/servers/manage_recontask.php b/pandora_console/godmode/servers/manage_recontask.php index a76571d54a..00ac75d1da 100644 --- a/pandora_console/godmode/servers/manage_recontask.php +++ b/pandora_console/godmode/servers/manage_recontask.php @@ -1,17 +1,32 @@ <?php +/** + * Extension to manage a list of gateways and the node address where they should + * point to. + * + * @category Extensions + * @package Pandora FMS + * @subpackage Community + * @version 1.0.0 + * @license See below + * + * ______ ___ _______ _______ ________ + * | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __| + * | __/| _ | | _ || _ | _| _ | | ___| |__ | + * |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| + * + * ============================================================================ + * Copyright (c) 2005-2019 Artica Soluciones Tecnologicas + * Please see http://pandorafms.org for full contribution list + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation for version 2. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ============================================================================ + */ -// Pandora FMS - http://pandorafms.com -// ================================================== -// Copyright (c) 2005-2012 Artica Soluciones Tecnologicas -// Please see http://pandorafms.org for full contribution list -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation for version 2. -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// Load global vars global $config; check_login(); @@ -37,13 +52,19 @@ $user_groups_w = array_keys($user_groups_w); $user_groups_r = users_get_groups(false, 'AW', true, false, null, 'id_grupo'); $user_groups_r = array_keys($user_groups_r); -// Headers -// ui_print_page_header (__('Manage recontask'), "images/gm_servers.png", false, "", true); -ui_print_page_header(__('Manage recontask'), 'images/gm_servers.png', false, '', true, $options); +// Headers. +ui_print_page_header( + __('Manage recontask'), + 'images/gm_servers.png', + false, + '', + true, + $options +); // -------------------------------- -// DELETE A RECON TASKs +// DELETE A RECON TASKs. // -------------------------------- if (isset($_GET['delete'])) { $id = get_parameter_get('delete'); @@ -59,11 +80,15 @@ if (isset($_GET['delete'])) { $id = get_parameter_get('id'); $disabled = get_parameter_get('disabled'); - $result = db_process_sql_update('trecon_task', ['disabled' => $disabled], ['id_rt' => $id]); + $result = db_process_sql_update( + 'trecon_task', + ['disabled' => $disabled], + ['id_rt' => $id] + ); if ($result !== false) { ui_print_success_message(__('Successfully updated recon task')); - // If the action is enabled, we force recon_task to be queued asap + // If the action is enabled, we force recon_task to be queued asap. if ($disabled == 0) { servers_force_recon_task($id); } @@ -73,9 +98,9 @@ if (isset($_GET['delete'])) { } // -------------------------------- -// GET PARAMETERS IF UPDATE OR CREATE +// GET PARAMETERS IF UPDATE OR CREATE. // -------------------------------- -if ((isset($_GET['update'])) or ((isset($_GET['create'])))) { +if ((isset($_GET['update'])) || ((isset($_GET['create'])))) { $name = get_parameter_post('name'); $network = get_parameter_post('network'); $description = get_parameter_post('description'); @@ -115,14 +140,16 @@ if ((isset($_GET['update'])) or ((isset($_GET['create'])))) { $alias_as_name = (int) get_parameter('alias_as_name', 0); $snmp_enabled = (int) get_parameter('snmp_enabled', 0); $vlan_enabled = (int) get_parameter('vlan_enabled', 0); - // Get macros + // Get macros. $macros = (string) get_parameter('macros'); if (!empty($macros)) { $macros = json_decode(base64_decode($macros), true); - foreach ($macros as $k => $m) { - $macros[$k]['value'] = get_parameter($m['macro'], ''); + if (isset($macros) === true && is_array($macros) === true) { + foreach ($macros as $k => $m) { + $macros[$k]['value'] = get_parameter($m['macro'], ''); + } } } @@ -130,7 +157,7 @@ if ((isset($_GET['update'])) or ((isset($_GET['create'])))) { } // -------------------------------- -// UPDATE A RECON TASK +// UPDATE A RECON TASK. // -------------------------------- if (isset($_GET['update'])) { $id = get_parameter_get('update'); @@ -193,10 +220,18 @@ if (isset($_GET['update'])) { $reason = __('Wrong format in Subnet field'); $result = false; } else { - $result = db_process_sql_update('trecon_task', $values, $where); + $result = db_process_sql_update( + 'trecon_task', + $values, + $where + ); } } else { - $result = db_process_sql_update('trecon_task', $values, $where); + $result = db_process_sql_update( + 'trecon_task', + $values, + $where + ); } } else { $result = false; @@ -314,9 +349,9 @@ if (isset($_GET['create'])) { } // -------------------------------- -// SHOW TABLE WITH ALL RECON TASKs +// SHOW TABLE WITH ALL RECON TASKs. // -------------------------------- -// Pandora Admin must see all columns +// Pandora Admin must see all columns. if (! check_acl($config['id_user'], 0, 'PM')) { $sql = sprintf( 'SELECT * @@ -377,26 +412,26 @@ if ($result !== false) { if ($row['id_recon_script'] == 0) { - // Network recon task + // Network recon task. $data[2] = html_print_image('images/network.png', true, ['title' => __('Network recon task')]).' '; $data[2] .= network_profiles_get_name($row['id_network_profile']); $mode_name = ''; } else { - // APP recon task + // APP recon task. $data[2] = html_print_image('images/plugin.png', true).' '; $mode_name = db_get_sql(sprintf('SELECT name FROM trecon_script WHERE id_recon_script = %d', $row['id_recon_script'])); $data[2] .= $mode_name; } - // GROUP + // GROUP. if ($row['id_recon_script'] == 0) { $data[3] = ui_print_group_icon($row['id_group'], true); } else { $data[3] = '-'; } - // SNMP VERSION + // SNMP VERSION. if ($row['snmp_version'] == '1') { $data[4] = 'v. 1'; } else if ($row['snmp_version'] == '2') { @@ -409,31 +444,31 @@ if ($result !== false) { - // INCIDENT + // INCIDENT. $data[5] = (($row['create_incident'] == 1) ? __('Yes') : __('No')); - // OS + // OS. if ($row['id_recon_script'] == 0) { $data[6] = (($row['id_os'] > 0) ? ui_print_os_icon($row['id_os'], false, true) : __('Any')); } else { $data[6] = '-'; } - // INTERVAL + // INTERVAL. if ($row['interval_sweep'] == 0) { $data[7] = __('Manual'); } else { $data[7] = human_time_description_raw($row['interval_sweep']); } - // PORTS + // PORTS. if ($row['id_recon_script'] == 0) { $data[8] = substr($row['recon_ports'], 0, 15); } else { $data[8] = '-'; } - // ACTION + // ACTION. $task_group = $row['id_group']; if (in_array($task_group, $user_groups_w)) { diff --git a/pandora_console/godmode/servers/manage_recontask_form.php b/pandora_console/godmode/servers/manage_recontask_form.php index c47416afd7..37947900b4 100644 --- a/pandora_console/godmode/servers/manage_recontask_form.php +++ b/pandora_console/godmode/servers/manage_recontask_form.php @@ -1,17 +1,32 @@ <?php +/** + * Extension to manage a list of gateways and the node address where they should + * point to. + * + * @category Extensions + * @package Pandora FMS + * @subpackage Community + * @version 1.0.0 + * @license See below + * + * ______ ___ _______ _______ ________ + * | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __| + * | __/| _ | | _ || _ | _| _ | | ___| |__ | + * |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| + * + * ============================================================================ + * Copyright (c) 2005-2019 Artica Soluciones Tecnologicas + * Please see http://pandorafms.org for full contribution list + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation for version 2. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ============================================================================ + */ -// Pandora FMS - http://pandorafms.com -// ================================================== -// Copyright (c) 2005-2010 Artica Soluciones Tecnologicas -// Please see http://pandorafms.org for full contribution list -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation for version 2. -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// Load global vars global $config; check_login(); @@ -36,7 +51,12 @@ if (is_ajax()) { if ($get_explanation) { $id = (int) get_parameter('id', 0); - $explanation = db_get_value('description', 'trecon_script', 'id_recon_script', $id); + $explanation = db_get_value( + 'description', + 'trecon_script', + 'id_recon_script', + $id + ); echo io_safe_output($explanation); @@ -49,17 +69,42 @@ if (is_ajax()) { $id_recon_task = (int) get_parameter('id_rt'); if (!empty($id_recon_task) && empty($id_recon_script)) { - $recon_script_macros = db_get_value('macros', 'trecon_task', 'id_rt', $id_recon_task); + $recon_script_macros = db_get_value( + 'macros', + 'trecon_task', + 'id_rt', + $id_recon_task + ); } else if (!empty($id_recon_task)) { - $recon_task_id_rs = (int) db_get_value('id_recon_script', 'trecon_task', 'id_rt', $id_recon_task); + $recon_task_id_rs = (int) db_get_value( + 'id_recon_script', + 'trecon_task', + 'id_rt', + $id_recon_task + ); if ($id_recon_script == $recon_task_id_rs) { - $recon_script_macros = db_get_value('macros', 'trecon_task', 'id_rt', $id_recon_task); + $recon_script_macros = db_get_value( + 'macros', + 'trecon_task', + 'id_rt', + $id_recon_task + ); } else { - $recon_script_macros = db_get_value('macros', 'trecon_script', 'id_recon_script', $id_recon_script); + $recon_script_macros = db_get_value( + 'macros', + 'trecon_script', + 'id_recon_script', + $id_recon_script + ); } } else if (!empty($id_recon_script)) { - $recon_script_macros = db_get_value('macros', 'trecon_script', 'id_recon_script', $id_recon_script); + $recon_script_macros = db_get_value( + 'macros', + 'trecon_script', + 'id_recon_script', + $id_recon_script + ); } else { $recon_script_macros = []; } @@ -75,7 +120,7 @@ if (is_ajax()) { return; } -// Edit mode +// Edit mode. if (isset($_GET['update']) || (isset($_GET['upd']))) { $update_recon = true; if (isset($_GET['upd'])) { @@ -174,9 +219,7 @@ if (isset($_GET['update']) || (isset($_GET['upd']))) { $snmp3_security_level = ''; $id_network_profile = 0; $id_os = -1; - // Any $recon_ports = ''; - // Any $field1 = ''; $field2 = ''; $field3 = ''; @@ -200,7 +243,7 @@ if (isset($_GET['update']) || (isset($_GET['upd']))) { } if (!$modify) { - // Headers + // Headers. ui_print_page_header(__('Manage recontask'), '', false, 'recontask', true); } @@ -244,11 +287,11 @@ $table->rowclass[14] = 'recon_script'; $table->rowclass[15] = 'recon_script'; $table->rowclass[16] = 'recon_script'; $table->rowclass[17] = 'recon_script'; -// Name +// Name. $table->data[0][0] = '<b>'.__('Task name').'</b>'; $table->data[0][1] = html_print_input_text('name', $name, '', 25, 0, true); -// Recon server +// Recon server. $table->data[1][0] = '<b>'.__('Recon server').ui_print_help_tip( __('You must select a Recon Server for the Task, otherwise the Recon Task will never run'), true @@ -258,7 +301,15 @@ $sql = 'SELECT id_server, name FROM tserver WHERE server_type = 3 ORDER BY name'; -$table->data[1][1] = html_print_select_from_sql($sql, 'id_recon_server', $id_recon_server, '', '', '', true); +$table->data[1][1] = html_print_select_from_sql( + $sql, + 'id_recon_server', + $id_recon_server, + '', + '', + '', + true +); $fields['network_sweep'] = __('Network sweep'); if (!$is_windows) { @@ -267,44 +318,94 @@ if (!$is_windows) { $table->data[2][0] = '<b>'.__('Mode').'</b>'; -$table->data[2][1] = html_print_select($fields, 'mode', $mode, '', '', 0, true); +$table->data[2][1] = html_print_select( + $fields, + 'mode', + $mode, + '', + '', + 0, + true +); -// Network +// Network. $table->data[3][0] = '<b>'.__('Network').'</b>'; -$table->data[3][0] .= ui_print_help_tip(__('You can specify several networks, separated by commas, for example: 192.168.50.0/24,192.168.60.0/24'), true); -$table->data[3][1] = html_print_input_text('network', $network, '', 25, 0, true); +$table->data[3][0] .= ui_print_help_tip( + __('You can specify several networks, separated by commas, for example: 192.168.50.0/24,192.168.60.0/24'), + true +); +$table->data[3][1] = html_print_input_text( + 'network', + $network, + '', + 25, + 0, + true +); -// Interval +// Interval. $interv_manual = 0; if ((int) $interval == 0) { $interv_manual = 1; } $table->data[4][0] = '<b>'.__('Interval'); -$table->data[4][0] .= ui_print_help_tip(__('Manual interval means that it will be executed only On-demand'), true); +$table->data[4][0] .= ui_print_help_tip( + __('Manual interval means that it will be executed only On-demand'), + true +); $values = [ 0 => __('Defined'), 1 => __('Manual'), ]; -$table->data[4][1] = html_print_select($values, 'interval_manual_defined', $interv_manual, '', '', '', true); +$table->data[4][1] = html_print_select( + $values, + 'interval_manual_defined', + $interv_manual, + '', + '', + '', + true +); $table->data[4][1] .= '<span id="interval_manual_container">'; -$table->data[4][1] .= html_print_extended_select_for_time('interval', $interval, '', '', '0', false, true, false, false); -$table->data[4][1] .= ui_print_help_tip(__('The minimum recomended interval for Recon Task is 5 minutes'), true); +$table->data[4][1] .= html_print_extended_select_for_time( + 'interval', + $interval, + '', + '', + '0', + false, + true, + false, + false +); +$table->data[4][1] .= ui_print_help_tip( + __('The minimum recomended interval for Recon Task is 5 minutes'), + true +); $table->data[4][1] .= '</span>'; -// Module template +// Module template. $table->data[5][0] = '<b>'.__('Module template').'</b>'; $sql = 'SELECT id_np, name FROM tnetwork_profile ORDER BY name'; -$table->data[5][1] = html_print_select_from_sql($sql, 'id_network_profile', $id_network_profile, '', __('None'), 0, true); +$table->data[5][1] = html_print_select_from_sql( + $sql, + 'id_network_profile', + $id_network_profile, + '', + __('None'), + 0, + true +); -// Recon script +// Recon script. $data[1] = ''; $table->data[6][0] = '<b>'.__('Recon script').'</b>'; @@ -314,35 +415,72 @@ $sql = "SELECT id_recon_script, name WHERE name <> 'IPAM Recon' ORDER BY name"; if ($name_script != 'IPAM Recon') { - $table->data[6][1] = html_print_select_from_sql($sql, 'id_recon_script', $id_recon_script, '', '', '', true); + $table->data[6][1] = html_print_select_from_sql( + $sql, + 'id_recon_script', + $id_recon_script, + '', + '', + '', + true + ); $table->data[6][1] .= "<span id='spinner_recon_script' style='display: none;'>".html_print_image('images/spinner.gif', true).'</span>'; - $table->data[6][1] .= $data[1] .= html_print_input_hidden('macros', base64_encode($macros), true); + $table->data[6][1] .= $data[1] .= html_print_input_hidden( + 'macros', + base64_encode($macros), + true + ); } else { $table->data[6][1] = 'IPAM Recon'; } -// OS +// OS. $table->data[7][0] = '<b>'.__('OS').'</b>'; $sql = 'SELECT id_os, name FROM tconfig_os ORDER BY name'; -$table->data[7][1] = html_print_select_from_sql($sql, 'id_os', $id_os, '', __('Any'), -1, true); +$table->data[7][1] = html_print_select_from_sql( + $sql, + 'id_os', + $id_os, + '', + __('Any'), + -1, + true +); -// Recon ports +// Recon ports. $table->data[8][0] = '<b>'.__('Ports').'</b>'; -$table->data[8][1] = html_print_input_text('recon_ports', $recon_ports, '', 25, 0, true); +$table->data[8][1] = html_print_input_text( + 'recon_ports', + $recon_ports, + '', + 25, + 0, + true +); $table->data[8][1] .= ui_print_help_tip( __('Ports defined like: 80 or 80,443,512 or even 0-1024 (Like Nmap command line format). If dont want to do a sweep using portscan, left it in blank'), true ); -// Group +// Group. $table->data[9][0] = '<b>'.__('Group'); $groups = users_get_groups(false, 'PM', false); -$table->data[9][1] = html_print_select_groups(false, 'PM', false, 'id_group', $id_group, '', '', 0, true); +$table->data[9][1] = html_print_select_groups( + false, + 'PM', + false, + 'id_group', + $id_group, + '', + '', + 0, + true +); -// Incident +// Incident. $values = [ 0 => __('No'), 1 => __('Yes'), @@ -356,24 +494,50 @@ $table->data[10][1] = html_print_select( '', '', true -).' '.ui_print_help_tip(__('Choose if the discovery of a new system creates an incident or not.'), true); +).' '.ui_print_help_tip( + __('Choose if the discovery of a new system creates an incident or not.'), + true +); -// snmp_enabled +// Snmp_enabled. $table->data[11][0] = '<b>'.__('SNMP enabled'); -$table->data[11][1] = html_print_checkbox('snmp_enabled', 1, $snmp_enabled, true); +$table->data[11][1] = html_print_checkbox( + 'snmp_enabled', + 1, + $snmp_enabled, + true +); -// SNMP default community +// SNMP default community. $table->data[12][0] = '<b>'.__('SNMP Default community'); -$table->data[12][0] .= ui_print_help_tip(__('You can specify several values, separated by commas, for example: public,mysecret,1234'), true); -$table->data[12][1] = html_print_input_text('snmp_community', $snmp_community, '', 35, 0, true); +$table->data[12][0] .= ui_print_help_tip( + __('You can specify several values, separated by commas, for example: public,mysecret,1234'), + true +); +$table->data[12][1] = html_print_input_text( + 'snmp_community', + $snmp_community, + '', + 35, + 0, + true +); -// SNMP version +// SNMP version. $snmp_versions['1'] = 'v. 1'; $snmp_versions['2'] = 'v. 2'; $snmp_versions['2c'] = 'v. 2c'; $snmp_versions['3'] = 'v. 3'; $table->data[24][0] = '<b>'._('SNMP version'); -$table->data[24][1] = html_print_select($snmp_versions, 'snmp_version', $snmp_version, '', '', 0, true); +$table->data[24][1] = html_print_select( + $snmp_versions, + 'snmp_version', + $snmp_version, + '', + '', + 0, + true +); $table->data[25][0] = '<b>'.__('Auth user'); $table->data[25][1] = html_print_input_text( @@ -400,10 +564,30 @@ $table->data[26][1] = html_print_input_password( false, '' ); -$table->data[26][1] .= html_print_input_hidden_extended('active_snmp_v3', 0, 'active_snmp_v3_mmen', true); +$table->data[26][1] .= html_print_input_hidden_extended( + 'active_snmp_v3', + 0, + 'active_snmp_v3_mmen', + true +); $table->data[27][0] = '<b>'.__('Privacy method'); -$table->data[27][1] = html_print_select(['DES' => __('DES'), 'AES' => __('AES')], 'snmp_privacy_method', $snmp3_privacy_method, '', '', '', true, false, false, '', ''); +$table->data[27][1] = html_print_select( + [ + 'DES' => __('DES'), + 'AES' => __('AES'), + ], + 'snmp_privacy_method', + $snmp3_privacy_method, + '', + '', + '', + true, + false, + false, + '', + '' +); $table->data[28][0] = '<b>'.__('Privacy pass').ui_print_help_tip(__('The pass length must be eight character minimum.'), true); $table->data[28][1] = html_print_input_password( 'snmp_privacy_pass', @@ -417,7 +601,22 @@ $table->data[28][1] = html_print_input_password( '' ); $table->data[29][0] = '<b>'.__('Auth method'); -$table->data[29][1] = html_print_select(['MD5' => __('MD5'), 'SHA' => __('SHA')], 'snmp_auth_method', $snmp3_auth_method, '', '', '', true, false, false, '', ''); +$table->data[29][1] = html_print_select( + [ + 'MD5' => __('MD5'), + 'SHA' => __('SHA'), + ], + 'snmp_auth_method', + $snmp3_auth_method, + '', + '', + '', + true, + false, + false, + '', + '' +); $table->data[30][0] = '<b>'.__('Security level'); $table->data[30][1] = html_print_select( [ @@ -437,75 +636,139 @@ $table->data[30][1] = html_print_select( '' ); -// Explanation -$explanation = db_get_value('description', 'trecon_script', 'id_recon_script', $id_recon_script); +// Explanation. +$explanation = db_get_value( + 'description', + 'trecon_script', + 'id_recon_script', + $id_recon_script +); $table->data[13][0] = '<b>'.__('Explanation').'</b>'; $table->data[13][1] = "<span id='spinner_layout' style='display: none;'>".html_print_image('images/spinner.gif', true).'</span>'.html_print_textarea('explanation', 4, 60, $explanation, 'style="width: 388px;"', true); -// A hidden "model row" to clone it from javascript to add fields dynamicaly +// A hidden "model row" to clone it from javascript to add fields dynamicaly. $data = []; $data[0] = 'macro_desc'; $data[0] .= ui_print_help_tip('macro_help', true); -$data[1] = html_print_input_text('macro_name', 'macro_value', '', 100, 255, true); +$data[1] = html_print_input_text( + 'macro_name', + 'macro_value', + '', + 100, + 255, + true +); $table->colspan['macro_field'][1] = 3; $table->rowstyle['macro_field'] = 'display:none'; $table->data['macro_field'] = $data; -// If there are $macros, we create the form fields +// If there are $macros, we create the form fields. if (!empty($macros)) { $macros = json_decode($macros, true); - foreach ($macros as $k => $m) { - $data = []; - $data[0] = '<b>'.$m['desc'].'</b>'; - if (!empty($m['help'])) { - $data[0] .= ui_print_help_tip($m['help'], true); + if (isset($macros) === true + && is_array($macros) === true + ) { + foreach ($macros as $k => $m) { + $data = []; + $data[0] = '<b>'.$m['desc'].'</b>'; + if (!empty($m['help'])) { + $data[0] .= ui_print_help_tip($m['help'], true); + } + + if ($m['hide']) { + $data[1] = html_print_input_password( + $m['macro'], + $m['value'], + '', + 100, + 255, + true + ); + } else { + $data[1] = html_print_input_text( + $m['macro'], + $m['value'], + '', + 100, + 255, + true + ); + } + + $table->colspan['macro'.$m['macro']][1] = 3; + $table->rowclass['macro'.$m['macro']] = 'macro_field'; + + $table->data['macro'.$m['macro']] = $data; } - - if ($m['hide']) { - $data[1] = html_print_input_password($m['macro'], $m['value'], '', 100, 255, true); - } else { - $data[1] = html_print_input_text($m['macro'], $m['value'], '', 100, 255, true); - } - - $table->colspan['macro'.$m['macro']][1] = 3; - $table->rowclass['macro'.$m['macro']] = 'macro_field'; - - $table->data['macro'.$m['macro']] = $data; } } -// Comments +// Comments. $table->data[18][0] = '<b>'.__('Comments'); -$table->data[18][1] = html_print_input_text('description', $description, '', 45, 0, true); +$table->data[18][1] = html_print_input_text( + 'description', + $description, + '', + 45, + 0, + true +); -// OS detection +// OS detection. $table->data[19][0] = '<b>'.__('OS detection'); -$table->data[19][1] = html_print_checkbox('os_detect', 1, $os_detect, true); +$table->data[19][1] = html_print_checkbox( + 'os_detect', + 1, + $os_detect, + true +); -// Name resolution +// Name resolution. $table->data[20][0] = '<b>'.__('Name resolution'); -$table->data[20][1] = html_print_checkbox('resolve_names', 1, $resolve_names, true); +$table->data[20][1] = html_print_checkbox( + 'resolve_names', + 1, + $resolve_names, + true +); -// Parent detection +// Parent detection. $table->data[21][0] = '<b>'.__('Parent detection'); -$table->data[21][1] = html_print_checkbox('parent_detection', 1, $parent_detection, true); +$table->data[21][1] = html_print_checkbox( + 'parent_detection', + 1, + $parent_detection, + true +); -// Parent recursion +// Parent recursion. $table->data[22][0] = '<b>'.__('Parent recursion'); -$table->data[22][1] = html_print_input_text('parent_recursion', $parent_recursion, '', 5, 0, true).ui_print_help_tip(__('Maximum number of parent hosts that will be created if parent detection is enabled.'), true); +$table->data[22][1] = html_print_input_text( + 'parent_recursion', + $parent_recursion, + '', + 5, + 0, + true +).ui_print_help_tip( + __('Maximum number of parent hosts that will be created if parent detection is enabled.'), + true +); -// vlan_enabled +// Vlan_enabled. $table->data[23][0] = '<b>'.__('Vlan enabled'); -$table->data[23][1] = html_print_checkbox('vlan_enabled', 1, $vlan_enabled, true); +$table->data[23][1] = html_print_checkbox( + 'vlan_enabled', + 1, + $vlan_enabled, + true +); -// Alias as name // NOTE: The 7.0NG Recon Server will not generate random names, since IP // address collisions could have other consequences. -// $table->data[22][0] = "<b>".__('Alias as Name'); -// $table->data[22][1] = html_print_checkbox ('alias_as_name', 1, $alias_as_name, true); -// Different Form url if it's a create or if it's a update form +// Different Form url if it's a create or if it's a update form. echo '<form name="modulo" method="post" action="index.php?sec=gservers&sec2=godmode/servers/manage_recontask&'.(($id_rt != -1) ? 'update='.$id_rt : 'create=1').'">'; html_print_table($table); echo '<div class="action-buttons" style="width: '.$table->width.'">'; @@ -529,23 +792,23 @@ ui_require_javascript_file('pandora_modules'); <script type="text/javascript"> /* <![CDATA[ */ $(document).ready (function () { - + }); var xhrManager = function () { var manager = {}; - + manager.tasks = []; - + manager.addTask = function (xhr) { manager.tasks.push(xhr); } - + manager.stopTasks = function () { while (manager.tasks.length > 0) manager.tasks.pop().abort(); } - + return manager; }; @@ -591,7 +854,7 @@ $('select#mode').change(function() { if (type == 'recon_script') { $(".recon_script").show(); $(".network_sweep").hide(); - + get_explanation_recon_script($("#id_recon_script").val()); } else if (type == 'network_sweep') { @@ -603,13 +866,13 @@ $('select#mode').change(function() { }).change(); function get_explanation_recon_script (id) { - // Stop old ajax tasks + // Stop old ajax tasks. taskManager.stopTasks(); - - // Show the spinners + + // Show the spinners. $("#textarea_explanation").hide(); $("#spinner_layout").show(); - + var xhr = jQuery.ajax ({ data: { 'page': 'godmode/servers/manage_recontask_form', @@ -632,11 +895,11 @@ function get_explanation_recon_script (id) { } }); taskManager.addTask(xhr); - - // Delete all the macro fields + + // Delete all the macro fields. $('.macro_field').remove(); $("#spinner_recon_script").show(); - + var xhr = jQuery.ajax ({ data: { 'page': 'godmode/servers/manage_recontask_form', @@ -654,7 +917,7 @@ function get_explanation_recon_script (id) { success: function (data, textStatus, xhr) { if (data.array !== null) { $('#hidden-macros').val(data.base64); - + jQuery.each (data.array, function (i, macro) { if (macro.desc != '') { add_macro_field(macro, 'table_recon-macro'); diff --git a/pandora_console/include/functions_events.php b/pandora_console/include/functions_events.php index 476f0f158a..bbce5ea942 100644 --- a/pandora_console/include/functions_events.php +++ b/pandora_console/include/functions_events.php @@ -2316,9 +2316,8 @@ function events_page_custom_fields($event) { global $config; - // - // Custom fields - // + // Custom fields. + $table = new stdClass; $table->cellspacing = 2; $table->cellpadding = 2; $table->width = '100%'; @@ -2402,9 +2401,8 @@ function events_page_details($event, $server='') $serverstring = ''; } - // - // Details - // + // Details. + $table_details = new stdClass; $table_details->width = '100%'; $table_details->data = []; $table_details->head = []; @@ -2773,9 +2771,8 @@ function events_page_general($event) // $group_rep = $event['similar_ids'] == -1 ? 1 : count(explode(',',$event['similar_ids'])); global $group_rep; - // - // General - // + // General. + $table_general = new stdClass; $table_general->cellspacing = 2; $table_general->cellpadding = 2; $table_general->width = '100%'; @@ -2926,11 +2923,10 @@ function events_page_general($event) function events_page_comments($event, $childrens_ids=[]) { - // - // Comments - // + // Comments. global $config; + $table_comments = new stdClass; $table_comments->width = '100%'; $table_comments->data = []; $table_comments->head = []; @@ -2941,13 +2937,15 @@ function events_page_comments($event, $childrens_ids=[]) $event_comments = $event['user_comment']; $event_comments = str_replace(["\n", '
'], '<br>', $event_comments); - // If comments are not stored in json, the format is old + // If comments are not stored in json, the format is old. $event_comments_array = json_decode($event_comments, true); - // Show the comments more recent first - $event_comments_array = array_reverse($event_comments_array); + // Show the comments more recent first. + if (is_array($event_comments_array)) { + $event_comments_array = array_reverse($event_comments_array); + } - if (is_null($event_comments_array)) { + if ($event_comments_array === true) { $comments_format = 'old'; } else { $comments_format = 'new'; @@ -2963,18 +2961,22 @@ function events_page_comments($event, $childrens_ids=[]) $table_comments->data[] = $data; } - foreach ($event_comments_array as $c) { - $data[0] = '<b>'.$c['action'].' by '.$c['id_user'].'</b>'; - $data[0] .= '<br><br><i>'.date($config['date_format'], $c['utimestamp']).'</i>'; - $data[1] = $c['comment']; - $table_comments->data[] = $data; + if (isset($event_comments_array) === true + && is_array($event_comments_array) === true + ) { + foreach ($event_comments_array as $c) { + $data[0] = '<b>'.$c['action'].' by '.$c['id_user'].'</b>'; + $data[0] .= '<br><br><i>'.date($config['date_format'], $c['utimestamp']).'</i>'; + $data[1] = $c['comment']; + $table_comments->data[] = $data; + } } break; case 'old': $comments_array = explode('<br>', $event_comments); - // Split comments and put in table + // Split comments and put in table. $col = 0; $data = []; diff --git a/pandora_console/include/functions_pandora_networkmap.php b/pandora_console/include/functions_pandora_networkmap.php index c1eb630d52..9870172de4 100644 --- a/pandora_console/include/functions_pandora_networkmap.php +++ b/pandora_console/include/functions_pandora_networkmap.php @@ -1365,117 +1365,137 @@ function clean_duplicate_links($relations) } $final_links = []; - /* - ---------------------------------------------------------------- */ - /* - --------------------- Clean duplicate links -------------------- */ + + // ---------------------------------------------------------------- + // --------------------- Clean duplicate links -------------------- // ---------------------------------------------------------------- $duplicated = false; $index_to_del = 0; $index = 0; - foreach ($segregation_links['aa'] as $link) { - foreach ($segregation_links['aa'] as $link2) { - if ($link['id_parent'] == $link2['id_child'] && $link['id_child'] == $link2['id_parent']) { - if (enterprise_installed()) { - delete_link($segregation_links['aa'][$index_to_del]); + if (isset($segregation_links['aa']) === true + && is_array($segregation_links['aa']) === true + ) { + foreach ($segregation_links['aa'] as $link) { + foreach ($segregation_links['aa'] as $link2) { + if ($link['id_parent'] == $link2['id_child'] + && $link['id_child'] == $link2['id_parent'] + ) { + if (enterprise_installed()) { + delete_link($segregation_links['aa'][$index_to_del]); + } + + unset($segregation_links['aa'][$index_to_del]); } - unset($segregation_links['aa'][$index_to_del]); + $index_to_del++; } - $index_to_del++; + $final_links['aa'][$index] = $link; + $index++; + + $duplicated = false; + $index_to_del = 0; } - - $final_links['aa'][$index] = $link; - $index++; - - $duplicated = false; - $index_to_del = 0; } $duplicated = false; $index_to_del = 0; $index2 = 0; - foreach ($segregation_links['mm'] as $link) { - foreach ($segregation_links['mm'] as $link2) { - if ($link['id_parent'] == $link2['id_child'] && $link['id_child'] == $link2['id_parent']) { - if (enterprise_installed()) { - delete_link($segregation_links['mm'][$index_to_del]); + if (isset($segregation_links['mm']) === true + && is_array($segregation_links['mm']) === true + ) { + foreach ($segregation_links['mm'] as $link) { + foreach ($segregation_links['mm'] as $link2) { + if ($link['id_parent'] == $link2['id_child'] + && $link['id_child'] == $link2['id_parent'] + ) { + if (enterprise_installed()) { + delete_link($segregation_links['mm'][$index_to_del]); + } } - // unset($segregation_links['mm'][$index_to_del]); + $index_to_del++; } - $index_to_del++; + $final_links['mm'][$index2] = $link; + $index2++; + + $duplicated = false; + $index_to_del = 0; } - - $final_links['mm'][$index2] = $link; - $index2++; - - $duplicated = false; - $index_to_del = 0; } $duplicated = false; $index_to_del = 0; $index3 = 0; - foreach ($segregation_links['ff'] as $link) { - foreach ($segregation_links['ff'] as $link2) { - if ($link['id_parent'] == $link2['id_child'] && $link['id_child'] == $link2['id_parent']) { - if (enterprise_installed()) { - delete_link($segregation_links['ff'][$index_to_del]); + + if (isset($segregation_links['ff']) === true + && is_array($segregation_links['ff']) === true + ) { + foreach ($segregation_links['ff'] as $link) { + foreach ($segregation_links['ff'] as $link2) { + if ($link['id_parent'] == $link2['id_child'] + && $link['id_child'] == $link2['id_parent'] + ) { + if (enterprise_installed()) { + delete_link($segregation_links['ff'][$index_to_del]); + } + + unset($segregation_links['ff'][$index_to_del]); } - unset($segregation_links['ff'][$index_to_del]); + $index_to_del++; } - $index_to_del++; + $final_links['ff'][$index3] = $link; + $index3++; + + $duplicated = false; + $index_to_del = 0; } - - $final_links['ff'][$index3] = $link; - $index3++; - - $duplicated = false; - $index_to_del = 0; } $final_links['am'] = $segregation_links['am']; /* - ---------------------------------------------------------------- */ - /* - ----------------- AA, AM and MM links management --------------- */ - /* - ------------------ Priority: ----------------------------------- */ - /* - -------------------- 1 -> MM (module - module) ----------------- */ - /* - -------------------- 2 -> AM (agent - module) ------------------ */ - /* - -------------------- 3 -> AA (agent - agent) ------------------- */ - // ---------------------------------------------------------------- + ---------------------------------------------------------------- + ----------------- AA, AM and MM links management --------------- + ------------------ Priority: ----------------------------------- + -------------------- 1 -> MM (module - module) ----------------- + -------------------- 2 -> AM (agent - module) ------------------ + -------------------- 3 -> AA (agent - agent) ------------------- + ---------------------------------------------------------------- + */ + $final_links2 = []; $index = 0; $l3_link = []; $agent1 = 0; $agent2 = 0; - foreach ($final_links['mm'] as $rel_mm) { - $module_parent = $rel_mm['id_parent_source_data']; - $module_children = $rel_mm['id_child_source_data']; - $agent1 = (int) agents_get_agent_id_by_module_id($module_parent); - $agent2 = (int) agents_get_agent_id_by_module_id($module_children); - foreach ($final_links['aa'] as $key => $rel_aa) { - $l3_link = $rel_aa; - $id_p_source_data = (int) $rel_aa['id_parent_source_data']; - $id_c_source_data = (int) $rel_aa['id_child_source_data']; - if ((($id_p_source_data == $agent1) && ($id_c_source_data == $agent2)) - || (($id_p_source_data == $agent2) && ($id_c_source_data == $agent1)) - ) { - if (enterprise_installed()) { - delete_link($final_links['aa'][$key]); - } - unset($final_links['aa'][$key]); + if (isset($final_links['mm']) === true + && is_array($final_links['mm']) === true + ) { + foreach ($final_links['mm'] as $rel_mm) { + $module_parent = $rel_mm['id_parent_source_data']; + $module_children = $rel_mm['id_child_source_data']; + $agent1 = (int) agents_get_agent_id_by_module_id($module_parent); + $agent2 = (int) agents_get_agent_id_by_module_id($module_children); + foreach ($final_links['aa'] as $key => $rel_aa) { + $l3_link = $rel_aa; + $id_p_source_data = (int) $rel_aa['id_parent_source_data']; + $id_c_source_data = (int) $rel_aa['id_child_source_data']; + if ((($id_p_source_data == $agent1) + && ($id_c_source_data == $agent2)) + || (($id_p_source_data == $agent2) + && ($id_c_source_data == $agent1)) + ) { + if (enterprise_installed()) { + delete_link($final_links['aa'][$key]); + } + + unset($final_links['aa'][$key]); + } } } } @@ -1487,14 +1507,18 @@ function clean_duplicate_links($relations) $same_m = []; $index = 0; - foreach ($final_links2['am'] as $rel_am) { - foreach ($final_links2['am'] as $rel_am2) { - if (($rel_am['id_child_source_data'] == $rel_am2['id_child_source_data']) - && ($rel_am['id_parent_source_data'] != $rel_am2['id_parent_source_data']) - ) { - $same_m[$index]['rel'] = $rel_am2; - $same_m[$index]['agent_parent'] = $rel_am['id_parent_source_data']; - $index++; + if (isset($final_links2['am']) === true + && is_array($final_links2['am']) === true + ) { + foreach ($final_links2['am'] as $rel_am) { + foreach ($final_links2['am'] as $rel_am2) { + if (($rel_am['id_child_source_data'] == $rel_am2['id_child_source_data']) + && ($rel_am['id_parent_source_data'] != $rel_am2['id_parent_source_data']) + ) { + $same_m[$index]['rel'] = $rel_am2; + $same_m[$index]['agent_parent'] = $rel_am['id_parent_source_data']; + $index++; + } } } } @@ -1503,19 +1527,23 @@ function clean_duplicate_links($relations) $index = 0; $l3_link = []; $have_l3 = false; - foreach ($final_links2['aa'] as $key => $rel_aa) { - $l3_link = $rel_aa; - foreach ($same_m as $rel_am) { - if ((($rel_aa['id_parent_source_data'] == $rel_am['parent']['id_parent_source_data']) - && ($rel_aa['id_child_source_data'] == $rel_am['rel']['id_parent_source_data'])) - || (($rel_aa['id_child_source_data'] == $rel_am['parent']['id_parent_source_data']) - && ($rel_aa['id_parent_source_data'] == $rel_am['rel']['id_parent_source_data'])) - ) { - if (enterprise_installed()) { - delete_link($final_links2['aa'][$key]); - } + if (isset($final_links2['aa']) === true + && is_array($final_links2['aa']) === true + ) { + foreach ($final_links2['aa'] as $key => $rel_aa) { + $l3_link = $rel_aa; + foreach ($same_m as $rel_am) { + if ((($rel_aa['id_parent_source_data'] == $rel_am['parent']['id_parent_source_data']) + && ($rel_aa['id_child_source_data'] == $rel_am['rel']['id_parent_source_data'])) + || (($rel_aa['id_child_source_data'] == $rel_am['parent']['id_parent_source_data']) + && ($rel_aa['id_parent_source_data'] == $rel_am['rel']['id_parent_source_data'])) + ) { + if (enterprise_installed()) { + delete_link($final_links2['aa'][$key]); + } - unset($final_links2['aa'][$key]); + unset($final_links2['aa'][$key]); + } } } } @@ -1526,20 +1554,36 @@ function clean_duplicate_links($relations) $final_links3['ff'] = $final_links2['ff']; $cleaned_links = []; - foreach ($final_links3['aa'] as $link) { - $cleaned_links[] = $link; + if (isset($final_links3['aa']) === true + && is_array($final_links3['aa']) === true + ) { + foreach ($final_links3['aa'] as $link) { + $cleaned_links[] = $link; + } } - foreach ($final_links3['am'] as $link) { - $cleaned_links[] = $link; + if (isset($final_links3['am']) === true + && is_array($final_links3['am']) === true + ) { + foreach ($final_links3['am'] as $link) { + $cleaned_links[] = $link; + } } - foreach ($final_links3['mm'] as $link) { - $cleaned_links[] = $link; + if (isset($final_links3['mm']) === true + && is_array($final_links3['mm']) === true + ) { + foreach ($final_links3['mm'] as $link) { + $cleaned_links[] = $link; + } } - foreach ($final_links3['ff'] as $link) { - $cleaned_links[] = $link; + if (isset($final_links3['ff']) === true + && is_array($final_links3['ff']) === true + ) { + foreach ($final_links3['ff'] as $link) { + $cleaned_links[] = $link; + } } return $cleaned_links; @@ -1677,34 +1721,34 @@ function show_networkmap($id=0, $user_readonly=false, $nodes_and_relations=[], $ stroke: #fff; stroke-width: 1px; } - + .node_over { stroke: #999; } - + .node_selected { stroke:#343434; stroke-width:5; } - + .node_children { stroke: #00f; } - + .link { stroke-opacity: .6; } - + .link_over { stroke: #000; stroke-opacity: .6; } - + .holding_area { stroke: #0f0; stroke-dasharray: 12,3; } - + .holding_area_link { stroke-dasharray: 12,3; } @@ -1730,7 +1774,7 @@ function show_networkmap($id=0, $user_readonly=false, $nodes_and_relations=[], $ init_drag_and_drop(); init_minimap(); function_open_minimap(); - + $(document.body).on("mouseleave", ".context-menu-list", function(e) { @@ -1757,7 +1801,7 @@ function show_networkmap($id=0, $user_readonly=false, $nodes_and_relations=[], $ <div id="dialog_node_edit" style="display: none;" title="<?php echo __('Edit node'); ?>"> <div style="text-align: left; width: 100%;"> <?php - $table = null; + $table = new stdClass(); $table->id = 'node_details'; $table->width = '100%'; @@ -1778,7 +1822,7 @@ function show_networkmap($id=0, $user_readonly=false, $nodes_and_relations=[], $ false ); - $table = null; + $table = new stdClass(); $table->id = 'interface_information'; $table->width = '100%'; @@ -1802,7 +1846,7 @@ function show_networkmap($id=0, $user_readonly=false, $nodes_and_relations=[], $ true ); - $table = null; + $table = new stdClass(); $table->id = 'node_options'; $table->width = '100%'; @@ -1820,7 +1864,24 @@ function show_networkmap($id=0, $user_readonly=false, $nodes_and_relations=[], $ '', 0, true - ).' '.'<span id="shape_icon_in_progress" style="display: none;">'.html_print_image('images/spinner.gif', true).'</span>'.'<span id="shape_icon_correct" style="display: none;">'.html_print_image('images/dot_green.png', true).'</span>'.'<span id="shape_icon_fail" style="display: none;">'.html_print_image('images/dot_red.png', true).'</span>'; + ); + $table->data[0][1] .= ' <span id="shape_icon_in_progress" style="display: none;">'; + $table->data[0][1] .= html_print_image( + 'images/spinner.gif', + true + ); + $table->data[0][1] .= '</span><span id="shape_icon_correct" style="display: none;">'; + $table->data[0][1] .= html_print_image( + 'images/dot_green.png', + true + ); + $table->data[0][1] .= '</span><span id="shape_icon_fail" style="display: none;">'; + $table->data[0][1] .= html_print_image( + 'images/dot_red.png', + true + ); + $table->data[0][1] .= '</span>'; + $table->data['node_name'][0] = __('Name'); $table->data['node_name'][1] = html_print_input_text( 'edit_name_node', @@ -1875,7 +1936,7 @@ function show_networkmap($id=0, $user_readonly=false, $nodes_and_relations=[], $ true ); - $table = null; + $table = new stdClass(); $table->id = 'relations_table'; $table->width = '100%'; @@ -1990,7 +2051,7 @@ function show_networkmap($id=0, $user_readonly=false, $nodes_and_relations=[], $ <div id="dialog_node_add" style="display: none;" title="<?php echo __('Add node'); ?>"> <div style="text-align: left; width: 100%;"> <?php - $table = null; + $table = new stdClass(); $table->width = '100%'; $table->data = []; @@ -2033,7 +2094,7 @@ function show_networkmap($id=0, $user_readonly=false, $nodes_and_relations=[], $ false ); - $table = null; + $table = new stdClass(); $table->width = '100%'; $table->data = []; $table->data[0][0] = __('Group'); @@ -2083,7 +2144,7 @@ function show_networkmap($id=0, $user_readonly=false, $nodes_and_relations=[], $ true ); - $table = null; + $table = new stdClass(); $table->width = '100%'; $table->data = []; $table->data[0][0] = __('Name'); @@ -2126,5 +2187,3 @@ function show_networkmap($id=0, $user_readonly=false, $nodes_and_relations=[], $ </div> <?php } - - diff --git a/pandora_console/operation/agentes/pandora_networkmap.editor.php b/pandora_console/operation/agentes/pandora_networkmap.editor.php index ebdb0bbb90..e43f26c6eb 100644 --- a/pandora_console/operation/agentes/pandora_networkmap.editor.php +++ b/pandora_console/operation/agentes/pandora_networkmap.editor.php @@ -1,18 +1,35 @@ <?php -// ______ __ _______ _______ _______ -// | __ \.---.-.-----.--| |.-----.----.---.-. | ___| | | __| -// | __/| _ | | _ || _ | _| _ | | ___| |__ | -// |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| -// -// ============================================================================ -// Copyright (c) 2007-2010 Artica Soluciones Tecnologicas, http://www.artica.es -// This code is NOT free software. This code is NOT licenced under GPL2 licence -// You cannnot redistribute it without written permission of copyright holder. -// ============================================================================ -// Load global variables +/** + * Extension to manage a list of gateways and the node address where they should + * point to. + * + * @category Extensions + * @package Pandora FMS + * @subpackage Community + * @version 1.0.0 + * @license See below + * + * ______ ___ _______ _______ ________ + * | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __| + * | __/| _ | | _ || _ | _| _ | | ___| |__ | + * |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| + * + * ============================================================================ + * Copyright (c) 2005-2019 Artica Soluciones Tecnologicas + * Please see http://pandorafms.org for full contribution list + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation for version 2. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ============================================================================ + */ + global $config; -// Check user credentials +// Check user credentials. check_login(); $id = (int) get_parameter('id_networkmap', 0); @@ -63,8 +80,7 @@ if ($edit_networkmap) { } else { $id_group = $values['id_group']; - // ACL for the network map - // $networkmap_read = check_acl ($config['id_user'], $id_group, "MR"); + // ACL for the network map. $networkmap_write = check_acl($config['id_user'], $id_group, 'MW'); $networkmap_manage = check_acl($config['id_user'], $id_group, 'MM'); @@ -221,7 +237,7 @@ if (!empty($result)) { if ($not_found) { ui_print_error_message(__('Not found networkmap.')); } else { - $table = null; + $table = new stdClass(); $table->id = 'form_editor'; $table->width = '98%'; diff --git a/pandora_console/operation/agentes/pandora_networkmap.view.php b/pandora_console/operation/agentes/pandora_networkmap.view.php index a9d570eed1..df97e7742b 100644 --- a/pandora_console/operation/agentes/pandora_networkmap.view.php +++ b/pandora_console/operation/agentes/pandora_networkmap.view.php @@ -1,15 +1,32 @@ <?php -// ______ __ _______ _______ _______ -// | __ \.---.-.-----.--| |.-----.----.---.-. | ___| | | __| -// | __/| _ | | _ || _ | _| _ | | ___| |__ | -// |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| -// -// ============================================================================ -// Copyright (c) 2007-2010 Artica Soluciones Tecnologicas, http://www.artica.es -// This code is NOT free software. This code is NOT licenced under GPL2 licence -// You cannnot redistribute it without written permission of copyright holder. -// ============================================================================ -// Load global variables +/** + * Extension to manage a list of gateways and the node address where they should + * point to. + * + * @category Extensions + * @package Pandora FMS + * @subpackage Community + * @version 1.0.0 + * @license See below + * + * ______ ___ _______ _______ ________ + * | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __| + * | __/| _ | | _ || _ | _| _ | | ___| |__ | + * |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| + * + * ============================================================================ + * Copyright (c) 2005-2019 Artica Soluciones Tecnologicas + * Please see http://pandorafms.org for full contribution list + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation for version 2. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ============================================================================ + */ + global $config; require_once 'include/functions_pandora_networkmap.php'; @@ -19,9 +36,9 @@ require_once 'include/functions_modules.php'; $public_hash = get_parameter('hash', false); -// Try to authenticate by hash on public dashboards +// Try to authenticate by hash on public dashboards. if ($public_hash === false) { - // Login check + // Login check. check_login(); } else { $validate_hash = enterprise_hook( @@ -33,7 +50,10 @@ if ($public_hash === false) { ] ); if ($validate_hash === false || $validate_hash === ENTERPRISE_NOT_HOOK) { - db_pandora_audit('Invalid public hash', 'Trying to access report builder'); + db_pandora_audit( + 'Invalid public hash', + 'Trying to access report builder' + ); include 'general/noaccess.php'; exit; } @@ -117,7 +137,7 @@ if (is_ajax()) { ); $row['style'] = json_decode($row['style'], true); $row['style']['shape'] = $shape; - // WORK AROUND FOR THE JSON ENCODE WITH FOR EXAMPLE Ñ OR Á + // WORK AROUND FOR THE JSON ENCODE WITH FOR EXAMPLE Ñ OR Á. $row['style']['label'] = 'json_encode_crash_with_ut8_chars'; $row['style']['color'] = $color; $row['style']['networkmap'] = $networkmap; @@ -215,52 +235,17 @@ if (is_ajax()) { if ($get_tooltip_content) { $id = (int) get_parameter('id', 0); - // Get all module from agent - switch ($config['dbtype']) { - case 'mysql': - case 'postgresql': - $sql = sprintf( - ' - SELECT * - FROM tagente_estado, tagente_modulo - LEFT JOIN tmodule_group - ON tmodule_group.id_mg = tagente_modulo.id_module_group - WHERE tagente_modulo.id_agente_modulo = '.$id.' - AND tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo - AND tagente_modulo.disabled = 0 - AND tagente_modulo.delete_pending = 0 - AND tagente_estado.utimestamp != 0' - ); - break; - - // If Dbms is Oracle then field_list in sql statement has to be recoded. See oracle_list_all_field_table() - case 'oracle': - $fields_tagente_estado = oracle_list_all_field_table( - 'tagente_estado', - 'string' - ); - $fields_tagente_modulo = oracle_list_all_field_table( - 'tagente_modulo', - 'string' - ); - $fields_tmodule_group = oracle_list_all_field_table( - 'tmodule_group', - 'string' - ); - - $sql = sprintf( - ' - SELECT '.$fields_tagente_estado.', '.$fields_tagente_modulo.', '.$fields_tmodule_group.' FROM tagente_estado, tagente_modulo - LEFT JOIN tmodule_group - ON tmodule_group.id_mg = tagente_modulo.id_module_group - WHERE tagente_modulo.id_agente_modulo = '.$id.' - AND tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo - AND tagente_modulo.disabled = 0 - AND tagente_modulo.delete_pending = 0 - AND tagente_estado.utimestamp != 0' - ); - break; - } + $sql = sprintf( + 'SELECT * + FROM tagente_estado, tagente_modulo + LEFT JOIN tmodule_group + ON tmodule_group.id_mg = tagente_modulo.id_module_group + WHERE tagente_modulo.id_agente_modulo = '.$id.' + AND tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo + AND tagente_modulo.disabled = 0 + AND tagente_modulo.delete_pending = 0 + AND tagente_estado.utimestamp != 0' + ); $modules = db_get_all_rows_sql($sql); if (empty($modules)) { @@ -377,7 +362,7 @@ if (is_ajax()) { $return['content'] .= '<b>'.__('Status: ').'</b>'.ui_print_status_image($status, $title, true).'<br />'; if ($module['id_tipo_modulo'] == 24) { - // log4x + // Log4x. switch ($module['datos']) { case 10: $salida = 'TRACE'; @@ -410,7 +395,7 @@ if (is_ajax()) { break; } - $salida = "<span style='$style'>$salida</span>"; + $salida = "<span style='".$style."'>".$salida.'</span>'; } else { if (is_numeric($module['datos'])) { $salida = format_numeric($module['datos']); @@ -513,7 +498,7 @@ if (is_ajax()) { include_once 'include/functions_agents.php'; $id = (int) get_parameter('id', 0); - // q is what autocomplete plugin gives + // Q is what autocomplete plugin gives. $string = (string) get_parameter('q'); $agents = db_get_all_rows_filter( @@ -586,8 +571,7 @@ if (is_ajax()) { $filter = json_encode($array_filter); - // ACL for the network map - // $networkmap_read = check_acl ($config['id_user'], $networkmap['id_group'], "MR"); + // ACL for the network map. $networkmap_write = check_acl($config['id_user'], $networkmap['id_group'], 'MW'); $networkmap_manage = check_acl($config['id_user'], $networkmap['id_group'], 'MM'); @@ -641,7 +625,7 @@ if (is_ajax()) { return; } - // Popup + // Popup. $get_status_node = (bool) get_parameter('get_status_node', false); $get_status_module = (bool) get_parameter( 'get_status_module', @@ -763,13 +747,9 @@ if (is_ajax()) { } // --------------END AJAX------------------------------------------------ -if (_id_ != '_id_') { - $id = _id_; -} else { - $id = (int) get_parameter('id_networkmap', 0); -} +$id = (int) get_parameter('id_networkmap', 0); -// Print some params to handle it in js +// Print some params to handle it in js. html_print_input_hidden('product_name', get_product_name()); html_print_input_hidden('center_logo', ui_get_full_url(ui_get_logo_to_center_networkmap())); @@ -823,7 +803,7 @@ if ($networkmap === false) { return; } else { - // ACL for the network map + // ACL for the network map. $networkmap_read = check_acl($config['id_user'], $networkmap['id_group'], 'MR'); $networkmap_write = check_acl($config['id_user'], $networkmap['id_group'], 'MW'); $networkmap_manage = check_acl($config['id_user'], $networkmap['id_group'], 'MM'); @@ -841,11 +821,11 @@ if ($networkmap === false) { $pure = (int) get_parameter('pure', 0); - // Main code + // Main code. if ($pure == 1) { $buttons['screen'] = [ 'active' => false, - 'text' => '<a href="index.php?sec=networkmapconsole&'.'sec2=operation/agentes/pandora_networkmap&'.'tab=view&id_networkmap='.$id.'">'.html_print_image( + 'text' => '<a href="index.php?sec=networkmapconsole&sec2=operation/agentes/pandora_networkmap&tab=view&id_networkmap='.$id.'">'.html_print_image( 'images/normal_screen.png', true, ['title' => __('Normal screen')] @@ -855,7 +835,7 @@ if ($networkmap === false) { if (!$dash_mode) { $buttons['screen'] = [ 'active' => false, - 'text' => '<a href="index.php?sec=networkmapconsole&'.'sec2=operation/agentes/pandora_networkmap&'.'pure=1&tab=view&id_networkmap='.$id.'">'.html_print_image( + 'text' => '<a href="index.php?sec=networkmapconsole&sec2=operation/agentes/pandora_networkmap&pure=1&tab=view&id_networkmap='.$id.'">'.html_print_image( 'images/full_screen.png', true, ['title' => __('Full screen')] @@ -863,7 +843,7 @@ if ($networkmap === false) { ]; $buttons['list'] = [ 'active' => false, - 'text' => '<a href="index.php?sec=networkmapconsole&'.'sec2=operation/agentes/pandora_networkmap">'.html_print_image( + 'text' => '<a href="index.php?sec=networkmapconsole&sec2=operation/agentes/pandora_networkmap">'.html_print_image( 'images/list.png', true, ['title' => __('List of networkmap')] @@ -895,23 +875,18 @@ if ($networkmap === false) { <script> $(document).ready(function() { $("*").on("click", function(){ - if($("[aria-describedby=dialog_node_edit]").css('display') == 'block'){ - $('#foot').css({'top':parseInt($("[aria-describedby=dialog_node_edit]").css('height')+$("[aria-describedby=dialog_node_edit]").css('top')),'position':'relative'}); - - } - else{ - $('#foot').css({'position':'','top':'0'}); - } - - + if($("[aria-describedby=dialog_node_edit]").css('display') == 'block'){ + $('#foot').css({'top':parseInt($("[aria-describedby=dialog_node_edit]").css('height')+$("[aria-describedby=dialog_node_edit]").css('top')),'position':'relative'}); + } + else{ + $('#foot').css({'position':'','top':'0'}); + } }); $("[aria-describedby=dialog_node_edit]").on('dialogclose', function(event) { - - $('#foot').css({'position':'','top':'0'}); - + $('#foot').css({'position':'','top':'0'}); }); }); -</script> \ No newline at end of file +</script> From de7c1ce978f508e071aad2923b6dbe7358dfd98b Mon Sep 17 00:00:00 2001 From: Luis Calvo <luis.calvo@artica.es> Date: Tue, 26 Feb 2019 09:40:04 +0100 Subject: [PATCH 05/50] Fixed ACL selection menu wrong sec for visual console Former-commit-id: dd9f4a212f43774c2602932baa0c1a83e3ba6e56 --- pandora_console/include/functions_menu.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pandora_console/include/functions_menu.php b/pandora_console/include/functions_menu.php index 39e5adf455..7012094570 100644 --- a/pandora_console/include/functions_menu.php +++ b/pandora_console/include/functions_menu.php @@ -510,8 +510,6 @@ function menu_add_extras(&$menu) $menu_extra['workspace']['sub']['operation/incidents/incident_detail']['text'] = __('Manage incident'); - $menu_extra['reporting']['sub']['godmode/reporting/visual_console_builder']['text'] = __('Manage visual console'); - // Duplicate extensions as sec=extension to check it from url foreach ($menu as $k => $m) { if (!isset($m['sub'])) { @@ -649,6 +647,7 @@ function menu_get_sec_pages($sec, $menu_hash=false) /** * Get the pages in a section2 + * $menu * * @param string sec code * @param string menu hash. All the menu structure (For example From 95b5c4ad0172e75dd9376a71b9e0e37a80b8b66c Mon Sep 17 00:00:00 2001 From: daniel <daniel.barbero@artica.es> Date: Thu, 28 Feb 2019 12:30:01 +0100 Subject: [PATCH 06/50] add new macro for alert events Former-commit-id: 08c5bf0168bcd5d9c23a23443187870269d61a40 --- pandora_console/include/help/en/help_alert_config.php | 1 + pandora_console/include/help/en/help_alert_macros.php | 1 + pandora_console/include/help/es/help_alert_config.php | 1 + pandora_console/include/help/es/help_alert_macros.php | 1 + pandora_console/include/help/ja/help_alert_config.php | 1 + pandora_console/include/help/ja/help_alert_macros.php | 1 + 6 files changed, 6 insertions(+) diff --git a/pandora_console/include/help/en/help_alert_config.php b/pandora_console/include/help/en/help_alert_config.php index c210a3164e..a78e468107 100644 --- a/pandora_console/include/help/en/help_alert_config.php +++ b/pandora_console/include/help/en/help_alert_config.php @@ -52,6 +52,7 @@ Apart from the defined module macros, the following macros are also available: <li>_event_extra_id_ : (Only event alerts) Extra id.</li> <li>_event_id_: (Only event alerts) ID of the event that triggered the alert.</li> <li>_event_text_severity_: (Only event alerts) Event text severity (Maintenance, Informational, Normal Minor, Warning, Major, Critical).</li> + <li>_eventTimestamp_: Timestamp in which the event was created.</li> <li>_field1_: User defined field 1.</li> <li>_field2_: User defined field 2.</li> <li>_field3_: User defined field 3.</li> diff --git a/pandora_console/include/help/en/help_alert_macros.php b/pandora_console/include/help/en/help_alert_macros.php index 16ee3a91dd..9d730cfcc9 100644 --- a/pandora_console/include/help/en/help_alert_macros.php +++ b/pandora_console/include/help/en/help_alert_macros.php @@ -37,6 +37,7 @@ Besides the defined module macros, the following macros are available: <li>_event_extra_id_: (Only event alerts) Extra id.</li> <li>_event_id_: (Only event alerts) ID of the event that triggered the alert.</li> <li>_event_text_severity_: (Only event alerts) Event text severity (Maintenance, Informational, Normal Minor, Warning, Major, Critical).</li> +<li>_eventTimestamp_: Timestamp in which the event was created.</li> <li>_field1_: User defined field 1.</li> <li>_field2_: User defined field 2.</li> <li>_field3_: User defined field 3.</li> diff --git a/pandora_console/include/help/es/help_alert_config.php b/pandora_console/include/help/es/help_alert_config.php index 3c6d0b8e53..ec219d87ca 100644 --- a/pandora_console/include/help/es/help_alert_config.php +++ b/pandora_console/include/help/es/help_alert_config.php @@ -54,6 +54,7 @@ Además de las macros de módulo definidas, las siguientes macros están disponi <li>_event_extra_id_ : (Solo alertas de evento) Id extra.</li> <li>_event_id_: (Solo alertas de evento) Id del evento que disparó la alerta.</li> <li>_event_text_severity_: (Solo alertas de evento) Prioridad en texto de el evento que dispara la alerta (Maintenance, Informational, Normal Minor, Warning, Major, Critical).</li> + <li>_eventTimestamp_: Timestamp en el que se creo el evento.</li> <li>_field1_: Campo 1 definido por el usuario.</li> <li>_field2_: Campo 2 definido por el usuario.</li> <li>_field3_: Campo 3 definido por el usuario.</li> diff --git a/pandora_console/include/help/es/help_alert_macros.php b/pandora_console/include/help/es/help_alert_macros.php index de420b31c7..75e627f19a 100644 --- a/pandora_console/include/help/es/help_alert_macros.php +++ b/pandora_console/include/help/es/help_alert_macros.php @@ -37,6 +37,7 @@ Además de las macros de módulo definidas, las siguientes macros están disponi <li>_event_extra_id_ : (Solo alertas de evento) Id extra.</li> <li>_event_id_: (Solo alertas de evento) Id del evento que disparó la alerta.</li> <li>_event_text_severity_:(Solo alertas de evento) Prioridad en texto de el evento que dispara la alerta (Maintenance, Informational, Normal Minor, Warning, Major, Critical).</li> + <li>_eventTimestamp_: Timestamp en el que se creo el evento.</li> <li>_field1_: Campo 1 definido por el usuario.</li> <li>_field2_: Campo 2 definido por el usuario.</li> <li>_field3_: Campo 3 definido por el usuario.</li> diff --git a/pandora_console/include/help/ja/help_alert_config.php b/pandora_console/include/help/ja/help_alert_config.php index 21e12b1baf..b606b1571f 100644 --- a/pandora_console/include/help/ja/help_alert_config.php +++ b/pandora_console/include/help/ja/help_alert_config.php @@ -53,6 +53,7 @@ email アクションを設定するには、_field1_ (送信先アドレス)、 <li>_event_extra_id_: (イベントアラートのみ) 拡張 ID</li> <li>_event_id_ : (イベントアラートのみ) アラート発生元のイベントID</li> <li>_event_text_severity_ : (イベントアラートのみ) イベント(アラートの発生元)のテキストでの重要度 (Maintenance, Informational, Normal Minor, Warning, Major, Critical)</li> + <li>_eventTimestamp_: Timestamp in which the event was created.</li> <li>_field1_ : ユーザ定義フィールド1</li> <li>_field2_ : ユーザ定義フィールド2</li> <li>_field3_ : ユーザ定義フィールド3</li> diff --git a/pandora_console/include/help/ja/help_alert_macros.php b/pandora_console/include/help/ja/help_alert_macros.php index 73ca00126e..36ff609741 100644 --- a/pandora_console/include/help/ja/help_alert_macros.php +++ b/pandora_console/include/help/ja/help_alert_macros.php @@ -37,6 +37,7 @@ <li>_event_extra_id_: (Only event alerts) Extra id.</li> <li>_event_id_ : (イベントアラートのみ) アラート発生元のイベントID</li> <li>_event_text_severity_ : (イベントアラートのみ) イベント(アラートの発生元)のテキストでの重要度 (Maintenance, Informational, Normal Minor, Warning, Major, Critical)</li> + <li>_eventTimestamp_: Timestamp in which the event was created.</li> <li>_field1_ : ユーザ定義フィールド1</li> <li>_field2_ : ユーザ定義フィールド2</li> <li>_field3_ : ユーザ定義フィールド3</li> From fb40ef7ce4190814f473222cd39d17e6445d675a Mon Sep 17 00:00:00 2001 From: Daniel Maya <daniel.maya@artica.es> Date: Thu, 28 Feb 2019 17:12:31 +0100 Subject: [PATCH 07/50] Changed Maintainer in pandorafms-agent-unix Former-commit-id: c0bff759d2926ec1459e66205b3918ec3d02d3f4 --- pandora_agents/pc/DEBIAN/control | 6 +++--- pandora_agents/shellscript/linux/DEBIAN/control | 4 ++-- pandora_agents/unix/DEBIAN/control | 2 +- pandora_console/DEBIAN/make_deb_package.sh | 2 +- pandora_server/DEBIAN/control | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pandora_agents/pc/DEBIAN/control b/pandora_agents/pc/DEBIAN/control index af1e09fc24..cdbcc99cfe 100644 --- a/pandora_agents/pc/DEBIAN/control +++ b/pandora_agents/pc/DEBIAN/control @@ -1,10 +1,10 @@ package: pandorafms-agent-unix -Version: 4.0.1 +Version: 7.0 Architecture: all Priority: optional Section: admin Installed-Size: 260 -Maintainer: Miguel de Dios <miguel.dedios@artica.es> -Homepage: http://pandorafms.org/ +Maintainer: ÁRTICA ST <info@artica.es> +Homepage: https://pandorafms.org/ Depends: coreutils, perl, unzip Description: Pandora FMS agents are based on native languages in every platform: scripts that can be written in any language. It’s possible to reproduce any agent in any programming language and can be extended without difficulty the existing ones in order to cover aspects not taken into account up to the moment. These scripts are formed by modules that each one gathers a "chunk" of information. Thus, every agent gathers several "chunks" of information; this one is organized in a data set and stored in a single file, called data file. diff --git a/pandora_agents/shellscript/linux/DEBIAN/control b/pandora_agents/shellscript/linux/DEBIAN/control index d17817f5b8..55a5168f93 100755 --- a/pandora_agents/shellscript/linux/DEBIAN/control +++ b/pandora_agents/shellscript/linux/DEBIAN/control @@ -1,10 +1,10 @@ package: pandorafms-agent -Version: 4.0 +Version: 7.0 Architecture: all Priority: optional Section: admin Installed-Size: 260 -Maintainer: Miguel de Dios <miguel.dedios@artica.es> +Maintainer: ÁRTICA ST <info@artica.es> Homepage: http://pandorafms.org/ Depends: coreutils, perl Description: Pandora FMS agents are based on native languages in every platform: scripts that can be written in any language. It’s possible to reproduce any agent in any programming language and can be extended without difficulty the existing ones in order to cover aspects not taken into account up to the moment. These scripts are formed by modules that each one gathers a "chunk" of information. Thus, every agent gathers several "chunks" of information; this one is organized in a data set and stored in a single file, called data file. diff --git a/pandora_agents/unix/DEBIAN/control b/pandora_agents/unix/DEBIAN/control index 13323ebd9e..7f6ab99071 100644 --- a/pandora_agents/unix/DEBIAN/control +++ b/pandora_agents/unix/DEBIAN/control @@ -4,7 +4,7 @@ Architecture: all Priority: optional Section: admin Installed-Size: 260 -Maintainer: Miguel de Dios <miguel.dedios@artica.es> +Maintainer: ÁRTICA ST <info@artica.es> Homepage: http://pandorafms.org/ Depends: coreutils, perl, unzip Description: Pandora FMS agents are based on native languages in every platform: scripts that can be written in any language. It’s possible to reproduce any agent in any programming language and can be extended without difficulty the existing ones in order to cover aspects not taken into account up to the moment. These scripts are formed by modules that each one gathers a "chunk" of information. Thus, every agent gathers several "chunks" of information; this one is organized in a data set and stored in a single file, called data file. diff --git a/pandora_console/DEBIAN/make_deb_package.sh b/pandora_console/DEBIAN/make_deb_package.sh index 9902501164..c62e0945f2 100644 --- a/pandora_console/DEBIAN/make_deb_package.sh +++ b/pandora_console/DEBIAN/make_deb_package.sh @@ -149,7 +149,7 @@ if [ $package_pear -eq 1 ] then echo "Make the package \"php-xml-rpc\"." cd temp_package - dh-make-pear --maintainer "Miguel de Dios <miguel.dedios@artica.es>" XML_RPC + dh-make-pear --maintainer "ÁRTICA ST <info@artica.es>" XML_RPC cd php-xml-rpc-* dpkg-buildpackage -rfakeroot cd .. diff --git a/pandora_server/DEBIAN/control b/pandora_server/DEBIAN/control index 4f78a1c055..c8259b54b9 100644 --- a/pandora_server/DEBIAN/control +++ b/pandora_server/DEBIAN/control @@ -4,7 +4,7 @@ Architecture: all Priority: optional Section: admin Installed-Size: 640 -Maintainer: Miguel de Dios <miguel.dedios@artica.es> +Maintainer: ÁRTICA ST <info@artica.es> Homepage: http://pandorafms.org/ Depends: perl (>= 5.8), libdbi-perl, libdbd-mysql-perl, libtime-format-perl, libnetaddr-ip-perl, libtime-format-perl, libxml-simple-perl, libxml-twig-perl, libhtml-parser-perl, snmp, snmpd, traceroute, xprobe2, nmap, sudo, libwww-perl, libsocket6-perl, libio-socket-inet6-perl, snmp-mibs-downloader, libjson-perl, libnet-telnet-perl, libencode-locale-perl, libgeo-ip-perl Description: Pandora FMS is a monitoring system for big IT environments. It uses remote tests, or local agents to grab information. Pandora supports all standard OS (Linux, AIX, HP-UX, Solaris and Windows XP,2000/2003), and support multiple setups in HA enviroments. This is the server package. Server makes the remote checks and process information transfer by Pandora FMS agents to the server. From 488be0d602a858eff96dbe6382fcbe7510fd12af Mon Sep 17 00:00:00 2001 From: manuel <manuel.montes@artica.es> Date: Mon, 4 Mar 2019 13:12:01 +0100 Subject: [PATCH 08/50] Changed radio buttons by checkbox switch Former-commit-id: f0c64cecbf9e1197be08a9a95248d3b4ea8bd949 --- pandora_console/godmode/setup/setup_auth.php | 1 - .../godmode/setup/setup_ehorus.php | 36 ++++++++++-------- .../godmode/setup/setup_general.php | 36 ++++++++++-------- .../godmode/setup/setup_netflow.php | 37 +++++++++++-------- .../godmode/setup/setup_visuals.php | 8 ++-- 5 files changed, 65 insertions(+), 53 deletions(-) diff --git a/pandora_console/godmode/setup/setup_auth.php b/pandora_console/godmode/setup/setup_auth.php index cdb75816cc..ac9f706e41 100644 --- a/pandora_console/godmode/setup/setup_auth.php +++ b/pandora_console/godmode/setup/setup_auth.php @@ -134,7 +134,6 @@ if (is_ajax()) { set_unless_defined($config['double_auth_enabled'], false); $row = []; $row['name'] = __('Double authentication').ui_print_help_tip(__('If this option is enabled, the users can use double authentication with their accounts'), true); - $row['control'] = html_print_input_hidden('double_auth_enabled', 0); $row['control'] .= html_print_checkbox_switch('double_auth_enabled', 1, $config['double_auth_enabled'], true); $table->data['double_auth_enabled'] = $row; diff --git a/pandora_console/godmode/setup/setup_ehorus.php b/pandora_console/godmode/setup/setup_ehorus.php index f51854a63c..0274767cff 100644 --- a/pandora_console/godmode/setup/setup_ehorus.php +++ b/pandora_console/godmode/setup/setup_ehorus.php @@ -1,18 +1,23 @@ <?php +/** + * ______ ___ _______ _______ ________ + * | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __| + * | __/| _ | | _ || _ | _| _ | | ___| |__ | + * |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| + * + * ============================================================================ + * Copyright (c) 2005-2019 Artica Soluciones Tecnologicas + * Please see http://pandorafms.org for full contribution list + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation for version 2. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ============================================================================ + */ -// Pandora FMS - http://pandorafms.com -// ================================================== -// Copyright (c) 2005-2010 Artica Soluciones Tecnologicas -// Please see http://pandorafms.org for full contribution list -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation for version 2. -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// Warning: This file may be required into the metaconsole's setup -// Load global vars global $config; check_login(); @@ -48,8 +53,7 @@ $table_enable->style['name'] = 'font-weight: bold'; // Enable eHorus $row = []; $row['name'] = __('Enable eHorus'); -$row['control'] = __('Enabled').' '.html_print_radio_button('ehorus_enabled', 1, '', $config['ehorus_enabled'], true).' '; -$row['control'] .= __('Disabled').' '.html_print_radio_button('ehorus_enabled', 0, '', $config['ehorus_enabled'], true); +$row['control'] = html_print_checkbox_switch('ehorus_enabled', false, $config['ehorus_enabled'], true); $row['button'] = html_print_submit_button(__('Update'), 'update_button', false, 'class="sub upd"', true); $table_enable->data['ehorus_enabled'] = $row; @@ -169,7 +173,7 @@ if ($config['ehorus_enabled']) { if (event.target.value == '1') showFields(); else hideFields(); } - $('input:radio[name="ehorus_enabled"]').change(handleEnable); + $('input:checkbox[name="ehorus_enabled"]').change(handleEnable); var handleTest = function (event) { var user = $('input#text-ehorus_user').val(); diff --git a/pandora_console/godmode/setup/setup_general.php b/pandora_console/godmode/setup/setup_general.php index 8f07d3d88d..370df5d808 100644 --- a/pandora_console/godmode/setup/setup_general.php +++ b/pandora_console/godmode/setup/setup_general.php @@ -1,17 +1,23 @@ <?php +/** + * ______ ___ _______ _______ ________ + * | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __| + * | __/| _ | | _ || _ | _| _ | | ___| |__ | + * |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| + * + * ============================================================================ + * Copyright (c) 2005-2019 Artica Soluciones Tecnologicas + * Please see http://pandorafms.org for full contribution list + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation for version 2. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ============================================================================ + */ -// Pandora FMS - http://pandorafms.com -// ================================================== -// Copyright (c) 2005-2011 Artica Soluciones Tecnologicas -// Please see http://pandorafms.org for full contribution list -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation for version 2. -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// Load global vars global $config; check_login(); @@ -269,12 +275,10 @@ $table->data[37][0] = __('Audit log directory').ui_print_help_tip(__('Directory $table->data[37][1] = html_print_input_text('auditdir', io_safe_output($config['auditdir']), '', 30, 100, true); $table->data[38][0] = __('Set alias as name by default in agent creation'); -$table->data[38][1] = __('Yes').' '.html_print_radio_button('alias_as_name', 1, '', $config['alias_as_name'], true).' '; -$table->data[38][1] .= __('No').' '.html_print_radio_button('alias_as_name', 0, '', $config['alias_as_name'], true); +$table->data[38][1] = html_print_checkbox_switch('alias_as_name', 1, $config['alias_as_name'], true); $table->data[39][0] = __('Unique IP').ui_print_help_tip(__('Set the primary IP address as the unique IP, preventing the same primary IP address from being used in more than one agent'), true); -$table->data[39][1] = __('Yes').' '.html_print_radio_button('unique_ip', 1, '', $config['unique_ip'], true).' '; -$table->data[39][1] .= __('No').' '.html_print_radio_button('unique_ip', 0, '', $config['unique_ip'], true); +$table->data[39][1] = html_print_checkbox_switch('unique_ip', 1, $config['unique_ip'], true); echo '<form id="form_setup" method="post" action="index.php?sec=gsetup&sec2=godmode/setup/setup&section=general&pure='.$config['pure'].'">'; diff --git a/pandora_console/godmode/setup/setup_netflow.php b/pandora_console/godmode/setup/setup_netflow.php index 1b62a23810..0b2cddbc25 100644 --- a/pandora_console/godmode/setup/setup_netflow.php +++ b/pandora_console/godmode/setup/setup_netflow.php @@ -1,16 +1,23 @@ <?php +/** + * ______ ___ _______ _______ ________ + * | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __| + * | __/| _ | | _ || _ | _| _ | | ___| |__ | + * |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| + * + * ============================================================================ + * Copyright (c) 2005-2019 Artica Soluciones Tecnologicas + * Please see http://pandorafms.org for full contribution list + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation for version 2. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ============================================================================ + */ -// Pandora FMS - http://pandorafms.com -// ================================================== -// Copyright (c) 2005-2011 Artica Soluciones Tecnologicas -// Please see http://pandorafms.org for full contribution list -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; version 2 -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. global $config; require_once 'include/functions_ui.php'; @@ -55,21 +62,19 @@ $table->data[5][0] = '<b>'.__('Maximum chart resolution').'</b>'.ui_print_help_t $table->data[5][1] = html_print_input_text('netflow_max_resolution', $config['netflow_max_resolution'], false, 50, 200, true); $table->data[6][0] = '<b>'.__('Disable custom live view filters').'</b>'.ui_print_help_tip(__('Disable the definition of custom filters in the live view. Only existing filters can be used.'), true); -$table->data[6][1] = __('Yes').' '.html_print_radio_button('netflow_disable_custom_lvfilters', 1, '', $config['netflow_disable_custom_lvfilters'], true).' '; -$table->data[6][1] .= __('No').' '.html_print_radio_button('netflow_disable_custom_lvfilters', 0, '', $config['netflow_disable_custom_lvfilters'], true); +$table->data[6][1] = html_print_checkbox_switch('netflow_disable_custom_lvfilters', 1, $config['netflow_disable_custom_lvfilters'], true); $table->data[7][0] = '<b>'.__('Netflow max lifetime').'</b>'.ui_print_help_tip(__('Sets the maximum lifetime for netflow data in days.'), true); $table->data[7][1] = html_print_input_text('netflow_max_lifetime', $config['netflow_max_lifetime'], false, 50, 200, true); $table->data[8][0] = '<b>'.__('Name resolution for IP address').'</b>'.ui_print_help_tip(__('Resolve the IP addresses to get their hostnames.'), true); $onclick = "if (!confirm('".__('Warning').'. '.__('IP address resolution can take a lot of time')."')) return false;"; -$table->data[8][1] = __('Yes').' '.html_print_radio_button_extended('netflow_get_ip_hostname', 1, '', $config['netflow_get_ip_hostname'], false, $onclick, '', true).' '; -$table->data[8][1] .= __('No').' '.html_print_radio_button('netflow_get_ip_hostname', 0, '', $config['netflow_get_ip_hostname'], true); +$table->data[8][1] = html_print_checkbox_switch_extended('netflow_get_ip_hostname', 1, $config['netflow_get_ip_hostname'], false, $onclick, '', true); echo '<form id="netflow_setup" method="post">'; html_print_table($table); -// Update button +// Update button. echo '<div class="action-buttons" style="width:100%;">'; html_print_input_hidden('update_config', 1); html_print_submit_button(__('Update'), 'upd_button', false, 'class="sub upd"'); diff --git a/pandora_console/godmode/setup/setup_visuals.php b/pandora_console/godmode/setup/setup_visuals.php index 85047cd488..2a8cf22d8d 100755 --- a/pandora_console/godmode/setup/setup_visuals.php +++ b/pandora_console/godmode/setup/setup_visuals.php @@ -961,7 +961,7 @@ $table_other->data[$row][0] = __('Custom report front page').ui_print_help_tip( __('Custom report front page. It will be applied to all reports and templates by default.'), true ); -$table_other->data[$row][1] = html_print_checkbox( +$table_other->data[$row][1] = html_print_checkbox_switch( 'custom_report_front', 1, $config['custom_report_front'], @@ -1435,12 +1435,12 @@ $(document).ready (function () { // Juanma (06/05/2014) New feature: Custom front page for reports var custom_report = $('#checkbox-custom_report_front') .prop('checked'); - display_custom_report_front(custom_report,$('#checkbox-custom_report_front').parent().parent().parent().parent().attr('id')); + display_custom_report_front(custom_report,$('#checkbox-custom_report_front').parent().parent().parent().parent().parent().attr('id')); - $("#checkbox-custom_report_front").click( function() { + $("#checkbox-custom_report_front").change( function() { var custom_report = $('#checkbox-custom_report_front') .prop('checked'); - display_custom_report_front(custom_report,$(this).parent().parent().parent().parent().attr('id')); + display_custom_report_front(custom_report,$(this).parent().parent().parent().parent().parent().attr('id')); }); $(".databox.filters").css('margin-bottom','-10px'); }); From 9d7c6854a8ab4bf04842c9a5837ba7b3546bfd1c Mon Sep 17 00:00:00 2001 From: daniel <daniel.barbero@artica.es> Date: Mon, 4 Mar 2019 15:33:36 +0100 Subject: [PATCH 09/50] fixed error in snmp browser change server Former-commit-id: 0545012dd8526bdf4cc836af2d263af7b5ca5328 --- .../include/functions_snmp_browser.php | 167 ++++++++++++++---- .../javascript/pandora_snmp_browser.js | 2 + .../operation/snmpconsole/snmp_browser.php | 93 +++++++--- 3 files changed, 198 insertions(+), 64 deletions(-) diff --git a/pandora_console/include/functions_snmp_browser.php b/pandora_console/include/functions_snmp_browser.php index 4920816c89..fd68b77e54 100644 --- a/pandora_console/include/functions_snmp_browser.php +++ b/pandora_console/include/functions_snmp_browser.php @@ -1,21 +1,41 @@ <?php +/** + * Extension to manage a list of gateways and the node address where they should + * point to. + * + * @category Extensions + * @package Pandora FMS + * @subpackage Community + * @version 1.0.0 + * @license See below + * + * ______ ___ _______ _______ ________ + * | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __| + * | __/| _ | | _ || _ | _| _ | | ___| |__ | + * |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| + * + * ============================================================================ + * Copyright (c) 2005-2019 Artica Soluciones Tecnologicas + * Please see http://pandorafms.org for full contribution list + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation for version 2. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ============================================================================ + */ -// Pandora FMS - http://pandorafms.com -// ================================================== -// Copyright (c) 2013 Artica Soluciones Tecnologicas -// Please see http://pandorafms.org for full contribution list -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public License -// as published by the Free Software Foundation; version 2 -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. require_once $config['homedir'].'/include/functions_config.php'; -enterprise_include_once($config['homedir'].'/enterprise/include/pdf_translator.php'); -enterprise_include_once($config['homedir'].'/enterprise/include/functions_metaconsole.php'); +enterprise_include_once( + $config['homedir'].'/enterprise/include/pdf_translator.php' +); +enterprise_include_once( + $config['homedir'].'/enterprise/include/functions_metaconsole.php' +); -// Date format for nfdump +// Date format for nfdump. global $nfdump_date_format; $nfdump_date_format = 'Y/m/d.H:i:s'; @@ -27,16 +47,23 @@ $nfdump_date_format = 'Y/m/d.H:i:s'; * @param id string Level ID. Do not set, used for recursion. * @param depth string Branch depth. Do not set, used for recursion. */ -function snmp_browser_print_tree($tree, $id=0, $depth=0, $last=0, $last_array=[], $sufix=false, $checked=[]) -{ +function snmp_browser_print_tree( + $tree, + $id=0, + $depth=0, + $last=0, + $last_array=[], + $sufix=false, + $checked=[] +) { static $url = false; - // Get the base URL for images + // Get the base URL for images. if ($url === false) { $url = ui_get_full_url('operation/tree', false, false, false); } - // Leaf + // Leaf. if (empty($tree['__LEAVES__'])) { return; } @@ -134,8 +161,19 @@ function snmp_browser_print_tree($tree, $id=0, $depth=0, $last=0, $last_array=[] * * @return array The SNMP tree. */ -function snmp_browser_get_tree($target_ip, $community, $starting_oid='.', $version='2c', $snmp3_auth_user='', $snmp3_security_level='', $snmp3_auth_method='', $snmp3_auth_pass='', $snmp3_privacy_method='', $snmp3_privacy_pass='', $server_to_exec=0) -{ +function snmp_browser_get_tree( + $target_ip, + $community, + $starting_oid='.', + $version='2c', + $snmp3_auth_user='', + $snmp3_security_level='', + $snmp3_auth_method='', + $snmp3_auth_pass='', + $snmp3_privacy_method='', + $snmp3_privacy_pass='', + $server_to_exec=0 +) { global $config; if ($target_ip == '') { @@ -303,14 +341,33 @@ function snmp_browser_get_tree($target_ip, $community, $starting_oid='.', $versi /** * Retrieve data for the specified OID. * - * @param target_ip string IP of the SNMP agent. - * @param community string SNMP community to use. - * @param target_oid SNMP OID to query. + * @param string $target_ip IP of the SNMP agent. + * @param string $community SNMP community to use. + * @param string $target_oid SNMP OID to query. + * @param string $version Version SNMP. + * @param string $snmp3_auth_user User snmp3. + * @param string $snmp3_security_level Security level snmp3. + * @param string $snmp3_auth_method Method snmp3. + * @param string $snmp3_auth_pass Pass snmp3. + * @param string $snmp3_privacy_method Privicy method snmp3. + * @param string $snmp3_privacy_pass Pass Method snmp3. + * @param integer $server_to_exec Execute with other server. * - * @return array OID data. + * @return mixed OID data. */ -function snmp_browser_get_oid($target_ip, $community, $target_oid, $version='2c', $snmp3_auth_user='', $snmp3_security_level='', $snmp3_auth_method='', $snmp3_auth_pass='', $snmp3_privacy_method='', $snmp3_privacy_pass='') -{ +function snmp_browser_get_oid( + $target_ip, + $community, + $target_oid, + $version='2c', + $snmp3_auth_user='', + $snmp3_security_level='', + $snmp3_auth_method='', + $snmp3_auth_pass='', + $snmp3_privacy_method='', + $snmp3_privacy_pass='', + $server_to_exec=0 +) { global $config; if ($target_oid == '') { @@ -348,10 +405,38 @@ function snmp_browser_get_oid($target_ip, $community, $target_oid, $version='2c' break; } - if ($version == '3') { - exec($snmpget_bin.' -m ALL -v 3 -u '.escapeshellarg($snmp3_auth_user).' -A '.escapeshellarg($snmp3_auth_pass).' -l '.escapeshellarg($snmp3_security_level).' -a '.escapeshellarg($snmp3_auth_method).' -x '.escapeshellarg($snmp3_privacy_method).' -X '.escapeshellarg($snmp3_privacy_pass).' '.escapeshellarg($target_ip).' '.escapeshellarg($target_oid).' 2> '.$error_redir_dir, $output, $rc); + if ($server_to_exec != 0) { + $sql = sprintf( + 'SELECT ip_address FROM tserver WHERE id_server = %d', + $server_to_exec + ); + $server_data = db_get_row_sql($sql); + + if ($version == '3') { + $command = $snmpget_bin.' -m ALL -v 3 -u '.escapeshellarg($snmp3_auth_user).' -A '.escapeshellarg($snmp3_auth_pass).' -l '.escapeshellarg($snmp3_security_level).' -a '.escapeshellarg($snmp3_auth_method).' -x '.escapeshellarg($snmp3_privacy_method).' -X '.escapeshellarg($snmp3_privacy_pass).' '.escapeshellarg($target_ip).' '.escapeshellarg($target_oid).' 2> '.$error_redir_dir; + } else { + $command = $snmpget_bin.' -m ALL -M +'.escapeshellarg($config['homedir'].'/attachment/mibs').' -On -c '.escapeshellarg(io_safe_output($community)).' -v '.escapeshellarg($version).' '.escapeshellarg($target_ip).' '.escapeshellarg($target_oid).' 2> '.$error_redir_dir; + } + + exec( + 'ssh pandora_exec_proxy@'.$server_data['ip_address'].' "'.$command.'"', + $output, + $rc + ); } else { - exec($snmpget_bin.' -m ALL -M +'.escapeshellarg($config['homedir'].'/attachment/mibs').' -On -c '.escapeshellarg(io_safe_output($community)).' -v '.escapeshellarg($version).' '.escapeshellarg($target_ip).' '.escapeshellarg($target_oid).' 2> '.$error_redir_dir, $output, $rc); + if ($version == '3') { + exec( + $snmpget_bin.' -m ALL -v 3 -u '.escapeshellarg($snmp3_auth_user).' -A '.escapeshellarg($snmp3_auth_pass).' -l '.escapeshellarg($snmp3_security_level).' -a '.escapeshellarg($snmp3_auth_method).' -x '.escapeshellarg($snmp3_privacy_method).' -X '.escapeshellarg($snmp3_privacy_pass).' '.escapeshellarg($target_ip).' '.escapeshellarg($target_oid).' 2> '.$error_redir_dir, + $output, + $rc + ); + } else { + exec( + $snmpget_bin.' -m ALL -M +'.escapeshellarg($config['homedir'].'/attachment/mibs').' -On -c '.escapeshellarg(io_safe_output($community)).' -v '.escapeshellarg($version).' '.escapeshellarg($target_ip).' '.escapeshellarg($target_oid).' 2> '.$error_redir_dir, + $output, + $rc + ); + } } if ($rc != 0) { @@ -359,7 +444,7 @@ function snmp_browser_get_oid($target_ip, $community, $target_oid, $version='2c' } foreach ($output as $line) { - // Separate the OID from the value + // Separate the OID from the value. $full_oid = explode('=', $line); if (! isset($full_oid[1])) { break; @@ -368,7 +453,7 @@ function snmp_browser_get_oid($target_ip, $community, $target_oid, $version='2c' $oid = trim($full_oid[0]); $oid_data['numeric_oid'] = $oid; - // Translate the OID + // Translate the OID. if (empty($config['snmptranslate'])) { switch (PHP_OS) { case 'FreeBSD': @@ -387,10 +472,20 @@ function snmp_browser_get_oid($target_ip, $community, $target_oid, $version='2c' $snmptranslate_bin = $config['snmptranslate']; } - exec( - $snmptranslate_bin.' -m ALL -M +'.escapeshellarg($config['homedir'].'/attachment/mibs').' -Td '.escapeshellarg($oid), - $translate_output - ); + if ($server_to_exec != 0) { + $command_output = $snmptranslate_bin.' -m ALL -M +'.escapeshellarg($config['homedir'].'/attachment/mibs').' -Td '.escapeshellarg($oid); + exec( + 'ssh pandora_exec_proxy@'.$server_data['ip_address'].' "'.$command_output.'"', + $translate_output, + $rc + ); + } else { + exec( + $snmptranslate_bin.' -m ALL -M +'.escapeshellarg($config['homedir'].'/attachment/mibs').' -Td '.escapeshellarg($oid), + $translate_output + ); + } + foreach ($translate_output as $line) { if (preg_match('/SYNTAX\s+(.*)/', $line, $matches) == 1) { $oid_data['syntax'] = $matches[1]; @@ -403,7 +498,7 @@ function snmp_browser_get_oid($target_ip, $community, $target_oid, $version='2c' } } - // Parse the description. First search for it in custom values + // Parse the description. First search for it in custom values. $custom_data = db_get_row('ttrap_custom_values', 'oid', $oid); if ($custom_data === false) { $translate_output = implode('', $translate_output); diff --git a/pandora_console/include/javascript/pandora_snmp_browser.js b/pandora_console/include/javascript/pandora_snmp_browser.js index eb4cc80f2e..ee75eac71f 100644 --- a/pandora_console/include/javascript/pandora_snmp_browser.js +++ b/pandora_console/include/javascript/pandora_snmp_browser.js @@ -164,6 +164,7 @@ function snmpGet(oid) { var snmp3_privacy_method = $("#snmp3_browser_privacy_method").val(); var snmp3_privacy_pass = $("#password-snmp3_browser_privacy_pass").val(); var ajax_url = $("#hidden-ajax_url").val(); + var server_to_exec = $("#server_to_exec").val(); // Check for a custom action var custom_action = $("#hidden-custom_action").val(); @@ -183,6 +184,7 @@ function snmpGet(oid) { "snmp3_browser_auth_pass=" + snmp3_auth_pass, "snmp3_browser_privacy_method=" + snmp3_privacy_method, "snmp3_browser_privacy_pass=" + snmp3_privacy_pass, + "server_to_exec=" + server_to_exec, "action=" + "snmpget", "custom_action=" + custom_action, "page=operation/snmpconsole/snmp_browser" diff --git a/pandora_console/operation/snmpconsole/snmp_browser.php b/pandora_console/operation/snmpconsole/snmp_browser.php index 9cc50e1fc3..bae4f9e06f 100644 --- a/pandora_console/operation/snmpconsole/snmp_browser.php +++ b/pandora_console/operation/snmpconsole/snmp_browser.php @@ -1,24 +1,39 @@ <?php +/** + * Extension to manage a list of gateways and the node address where they should + * point to. + * + * @category Extensions + * @package Pandora FMS + * @subpackage Community + * @version 1.0.0 + * @license See below + * + * ______ ___ _______ _______ ________ + * | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __| + * | __/| _ | | _ || _ | _| _ | | ___| |__ | + * |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| + * + * ============================================================================ + * Copyright (c) 2005-2019 Artica Soluciones Tecnologicas + * Please see http://pandorafms.org for full contribution list + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation for version 2. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ============================================================================ + */ -// Pandora FMS - http://pandorafms.com -// ================================================== -// Copyright (c) 2005-2010 Artica Soluciones Tecnologicas -// Please see http://pandorafms.org for full contribution list -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation for version 2. -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// Load global vars global $config; require_once $config['homedir'].'/include/functions_snmp_browser.php'; ui_require_javascript_file('pandora_snmp_browser'); -// AJAX call +// AJAX call. if (is_ajax()) { - // Read the action to perform + // Read the action to perform. $action = (string) get_parameter('action', ''); $target_ip = (string) get_parameter('target_ip', ''); $community = (string) get_parameter('community', ''); @@ -29,9 +44,11 @@ if (is_ajax()) { $snmp3_auth_method = get_parameter('snmp3_browser_auth_method'); $snmp3_auth_pass = io_safe_output(get_parameter('snmp3_browser_auth_pass')); $snmp3_privacy_method = get_parameter('snmp3_browser_privacy_method'); - $snmp3_privacy_pass = io_safe_output(get_parameter('snmp3_browser_privacy_pass')); + $snmp3_privacy_pass = io_safe_output( + get_parameter('snmp3_browser_privacy_pass') + ); - // SNMP browser + // SNMP browser. if ($action == 'snmptree') { $starting_oid = (string) get_parameter('starting_oid', '.'); @@ -83,9 +100,8 @@ if (is_ajax()) { } return; - } - // SNMP get - else if ($action == 'snmpget') { + } else if ($action == 'snmpget') { + // SNMP get. $target_oid = htmlspecialchars_decode(get_parameter('oid', '')); $custom_action = get_parameter('custom_action', ''); if ($custom_action != '') { @@ -102,8 +118,10 @@ if (is_ajax()) { $snmp3_auth_method, $snmp3_auth_pass, $snmp3_privacy_method, - $snmp3_privacy_pass + $snmp3_privacy_pass, + $server_to_exec ); + snmp_browser_print_oid( $oid, $custom_action, @@ -117,7 +135,7 @@ if (is_ajax()) { return; } -// Check login and ACLs +// Check login and ACLs. check_login(); if (! check_acl($config['id_user'], 0, 'AR')) { db_pandora_audit( @@ -128,17 +146,36 @@ if (! check_acl($config['id_user'], 0, 'AR')) { exit; } -// Header +// Header. $url = 'index.php?sec=snmpconsole&sec2=operation/snmpconsole/snmp_browser&pure='.$config['pure']; if ($config['pure']) { - // Windowed - $link['text'] = '<a target="_top" href="'.$url.'&pure=0&refr=30">'.html_print_image('images/normal_screen.png', true, ['title' => __('Normal screen')]).'</a>'; + // Windowed. + $link['text'] = '<a target="_top" href="'.$url.'&pure=0&refr=30">'; + $link['text'] .= html_print_image( + 'images/normal_screen.png', + true, + ['title' => __('Normal screen')] + ); + $link['text'] .= '</a>'; } else { - // Fullscreen - $link['text'] = '<a target="_top" href="'.$url.'&pure=1&refr=0">'.html_print_image('images/full_screen.png', true, ['title' => __('Full screen')]).'</a>'; + // Fullscreen. + $link['text'] = '<a target="_top" href="'.$url.'&pure=1&refr=0">'; + $link['text'] .= html_print_image( + 'images/full_screen.png', + true, + ['title' => __('Full screen')] + ); + $link['text'] .= '</a>'; } -ui_print_page_header(__('SNMP Browser'), 'images/op_snmp.png', false, '', false, [$link]); +ui_print_page_header( + __('SNMP Browser'), + 'images/op_snmp.png', + false, + '', + false, + [$link] +); -// SNMP tree container +// SNMP tree container. snmp_browser_print_container(); From 18ca3a191bce2ae991dd9018ff4a8a007505c6b7 Mon Sep 17 00:00:00 2001 From: "marcos.alconada" <marcos.alconada@artica.es> Date: Wed, 6 Mar 2019 16:47:56 +0100 Subject: [PATCH 10/50] ticket changed Former-commit-id: 532d461aa9ff0c956dbbe0dd931dc6f03d56498b --- .../operation/agentes/status_monitor.php | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/pandora_console/operation/agentes/status_monitor.php b/pandora_console/operation/agentes/status_monitor.php index 6e3c26b470..f32c10d890 100644 --- a/pandora_console/operation/agentes/status_monitor.php +++ b/pandora_console/operation/agentes/status_monitor.php @@ -63,17 +63,6 @@ $sort = get_parameter('sort', 'none'); $id_module = (int) get_parameter('id_module', 0); $ag_custom_fields = (array) get_parameter('ag_custom_fields', []); $module_option = (int) get_parameter('module_option', 1); -$autosearch = false; - -// It is validated if it receives parameters different from those it has by default -if ($ag_freestring != '' || $moduletype != '' || $datatype != '' - || $ag_modulename != '' || $refr != 0 || $offset != 0 || $status != 4 - || $modulegroup != -1 || $tag_filter != 0 || $sortField != '' - || $sort != '' || $id_module != 0 || $ag_custom_fields != null - || $module_option != 1 -) { - $autosearch = true; -} if (!is_metaconsole()) { $ag_group = (int) get_parameter('ag_group', 0); @@ -955,10 +944,23 @@ $sql = 'SELECT ORDER BY '.$order['field'].' '.$order['order'].' LIMIT '.$offset.','.$limit_sql; -// When you enter for the first time you have less than 4 query params in the url -$first_interaction = count($_GET); -// We do not show the modules until the user searches with the filter -if ($first_interaction || $autosearch) { + $automonitordetail = false; + $autovisualconsole = false; + + // It is validated if it receives parameters different from those it has by default + $defaulturl = ui_get_full_url(); +if ($defaulturl !== 'http://localhost/pandora_console/index.php?sec=view&sec2=operation/agentes/status_monitor') { + $automonitordetail = true; +} + + $urlvisual = 'http://localhost/pandora_console/index.php?sec=view&sec2=operation/agentes/status_monitor&id_module='.$id_module; + +if ($urlvisual !== $defaulturl) { + $autovisualconsole = true; +} + + // We do not show the modules until the user searches with the filter +if ($automonitordetail && $autovisualconsole) { if (! defined('METACONSOLE')) { $result = db_get_all_rows_sql($sql); From d760c7d7017e2bb6a879fd769e06d44d7a3b4ea3 Mon Sep 17 00:00:00 2001 From: alejandro-campos <alejandro.campos@artica.es> Date: Wed, 6 Mar 2019 17:07:37 +0100 Subject: [PATCH 11/50] fix bug in functions_filemanager Former-commit-id: 93507790a70eb673a5660357acfcdf9c68279047 --- pandora_console/include/functions_filemanager.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandora_console/include/functions_filemanager.php b/pandora_console/include/functions_filemanager.php index fa51e3ad12..0f7e125852 100644 --- a/pandora_console/include/functions_filemanager.php +++ b/pandora_console/include/functions_filemanager.php @@ -121,9 +121,9 @@ if (!function_exists('mime_content_type')) { global $config; if (isset($config['homedir_filemanager'])) { - $homedir_filemanager = io_safe_output($config['homedir_filemanager']); + $homedir_filemanager = trim(io_safe_output($config['homedir_filemanager'])); } else { - $homedir_filemanager = $config['homedir']; + $homedir_filemanager = trim($config['homedir']); } $sec2 = get_parameter('sec2'); From e79e2a4fbc6cfca0dfdd79c060c52c10c15efb6e Mon Sep 17 00:00:00 2001 From: "marcos.alconada" <marcos.alconada@artica.es> Date: Wed, 6 Mar 2019 17:25:36 +0100 Subject: [PATCH 12/50] Finished Former-commit-id: 529f6297404b74dc41af77ae672a034530f18727 --- .../operation/agentes/status_monitor.php | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/pandora_console/operation/agentes/status_monitor.php b/pandora_console/operation/agentes/status_monitor.php index f32c10d890..4a4114b6f8 100644 --- a/pandora_console/operation/agentes/status_monitor.php +++ b/pandora_console/operation/agentes/status_monitor.php @@ -63,6 +63,16 @@ $sort = get_parameter('sort', 'none'); $id_module = (int) get_parameter('id_module', 0); $ag_custom_fields = (array) get_parameter('ag_custom_fields', []); $module_option = (int) get_parameter('module_option', 1); +$autosearch = false; + +// It is validated if it receives parameters different from those it has by default +if ($ag_freestring !== '' || $moduletype !== '' || $datatype !== '' + || $ag_modulename !== '' || $refr !== 0 || $offset !== 0 || $status !== 4 + || $modulegroup !== -1 || $tag_filter !== 0 || $sortField !== '' + || $sort !== 'none' || $id_module !== 0 || $module_option !== 1 +) { + $autosearch = true; +} if (!is_metaconsole()) { $ag_group = (int) get_parameter('ag_group', 0); @@ -84,6 +94,7 @@ if ($id_module) { $status = -1; $ag_modulename = modules_get_agentmodule_name($id_module); $ag_freestring = modules_get_agentmodule_agent_alias($id_module); + $autosearch = false; } enterprise_hook('open_meta_frame'); @@ -944,23 +955,8 @@ $sql = 'SELECT ORDER BY '.$order['field'].' '.$order['order'].' LIMIT '.$offset.','.$limit_sql; - $automonitordetail = false; - $autovisualconsole = false; - - // It is validated if it receives parameters different from those it has by default - $defaulturl = ui_get_full_url(); -if ($defaulturl !== 'http://localhost/pandora_console/index.php?sec=view&sec2=operation/agentes/status_monitor') { - $automonitordetail = true; -} - - $urlvisual = 'http://localhost/pandora_console/index.php?sec=view&sec2=operation/agentes/status_monitor&id_module='.$id_module; - -if ($urlvisual !== $defaulturl) { - $autovisualconsole = true; -} - - // We do not show the modules until the user searches with the filter -if ($automonitordetail && $autovisualconsole) { +// We do not show the modules until the user searches with the filter +if ($autosearch) { if (! defined('METACONSOLE')) { $result = db_get_all_rows_sql($sql); From 2d6636bb51f7d2004c4f3f53aa486b81637eabeb Mon Sep 17 00:00:00 2001 From: "marcos.alconada" <marcos.alconada@artica.es> Date: Thu, 7 Mar 2019 10:36:06 +0100 Subject: [PATCH 13/50] Revert changes on dbmanager.php Former-commit-id: 3c9eaec695b923ea81f60d8dcfb5716af6515e37 --- pandora_console/extensions/dbmanager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandora_console/extensions/dbmanager.php b/pandora_console/extensions/dbmanager.php index c924bd3ea9..2aface6996 100644 --- a/pandora_console/extensions/dbmanager.php +++ b/pandora_console/extensions/dbmanager.php @@ -106,7 +106,7 @@ function dbmgr_extension_main() echo '<br /><br />'; echo "<form method='post' action=''>"; - html_print_textarea('sql', 5, 50, $sql); + html_print_textarea('sql', 5, 50, html_entity_decode($sql, ENT_QUOTES)); echo '<br />'; echo '<div class="action-buttons" style="width: 100%">'; echo '<br />'; From ccb669a204967d6cd72607c998eaebfe4d609bc5 Mon Sep 17 00:00:00 2001 From: manuel <manuel.montes@artica.es> Date: Mon, 11 Mar 2019 09:37:08 +0100 Subject: [PATCH 14/50] Fixed minor errors in setup_ehorus Former-commit-id: ed0ba17641714a87446b4db88d933d7b176e531e --- .../godmode/setup/setup_ehorus.php | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/pandora_console/godmode/setup/setup_ehorus.php b/pandora_console/godmode/setup/setup_ehorus.php index 0274767cff..fc2ebd3d3a 100644 --- a/pandora_console/godmode/setup/setup_ehorus.php +++ b/pandora_console/godmode/setup/setup_ehorus.php @@ -28,7 +28,7 @@ if (! check_acl($config['id_user'], 0, 'PM') && ! is_user_admin($config['id_user return; } -// Check custom field +// Check custom field. $custom_field = db_get_value('name', 'tagent_custom_fields', 'name', $config['ehorus_custom_field']); $custom_field_exists = !empty($custom_field); $custom_field_created = null; @@ -41,7 +41,7 @@ if ($config['ehorus_enabled'] && !$custom_field_exists) { $custom_field_exists = $custom_field_created = $result; } -// Enable table +// Enable table. $table_enable = new StdClass(); $table_enable->data = []; $table_enable->width = '100%'; @@ -50,14 +50,13 @@ $table_enable->class = 'databox filters'; $table_enable->size['name'] = '30%'; $table_enable->style['name'] = 'font-weight: bold'; -// Enable eHorus +// Enable eHorus. $row = []; $row['name'] = __('Enable eHorus'); -$row['control'] = html_print_checkbox_switch('ehorus_enabled', false, $config['ehorus_enabled'], true); -$row['button'] = html_print_submit_button(__('Update'), 'update_button', false, 'class="sub upd"', true); +$row['control'] = html_print_checkbox_switch('ehorus_enabled', 1, $config['ehorus_enabled'], true); $table_enable->data['ehorus_enabled'] = $row; -// Remote config table +// Remote config table. $table_remote = new StdClass(); $table_remote->data = []; $table_remote->width = '100%'; @@ -67,40 +66,40 @@ $table_remote->class = 'databox filters'; $table_remote->size['name'] = '30%'; $table_remote->style['name'] = 'font-weight: bold'; -// User +// User. $row = []; $row['name'] = __('User'); $row['control'] = html_print_input_text('ehorus_user', $config['ehorus_user'], '', 30, 100, true); $table_remote->data['ehorus_user'] = $row; -// Pass +// Pass. $row = []; $row['name'] = __('Password'); $row['control'] = html_print_input_password('ehorus_pass', io_output_password($config['ehorus_pass']), '', 30, 100, true); $table_remote->data['ehorus_pass'] = $row; -// Directory hostname +// Directory hostname. $row = []; $row['name'] = __('API Hostname'); $row['control'] = html_print_input_text('ehorus_hostname', $config['ehorus_hostname'], '', 30, 100, true); $row['control'] .= ui_print_help_tip(__('Hostname of the eHorus API').'. '.__('Without protocol and port').'. '.__('e.g., portal.ehorus.com'), true); $table_remote->data['ehorus_hostname'] = $row; -// Directory port +// Directory port. $row = []; $row['name'] = __('API Port'); $row['control'] = html_print_input_text('ehorus_port', $config['ehorus_port'], '', 6, 100, true); $row['control'] .= ui_print_help_tip(__('e.g., 18080'), true); $table_remote->data['ehorus_port'] = $row; -// Request timeout +// Request timeout. $row = []; $row['name'] = __('Request timeout'); $row['control'] = html_print_input_text('ehorus_req_timeout', $config['ehorus_req_timeout'], '', 3, 10, true); $row['control'] .= ui_print_help_tip(__('Time in seconds to set the maximum time of the requests to the eHorus API').'. '.__('0 to disable'), true); $table_remote->data['ehorus_req_timeout'] = $row; -// Test +// Test. $row = []; $row['name'] = __('Test'); $row['control'] = html_print_button(__('Start'), 'test-ehorus', false, '', 'class="sub next"', true); @@ -110,7 +109,7 @@ $row['control'] .= '<span id="test-ehorus-failure" style="display:none;"> ' $row['control'] .= ' <span id="test-ehorus-message" style="display:none;"></span>'; $table_remote->data['ehorus_test'] = $row; -// Print +// Print. echo '<div style="text-align: center; padding-bottom: 20px;">'; echo '<a target="_blank" rel="noopener noreferrer" href="http://ehorus.com">'; html_print_image('include/ehorus/images/ehorus-logo-grey.png'); @@ -140,13 +139,13 @@ if ($config['ehorus_enabled'] && !$custom_field_exists) { ui_print_error_message($error_message); } -// Form enable +// Form enable. echo '<form id="form_enable" method="post">'; html_print_input_hidden('update_config', 1); html_print_table($table_enable); echo '</form>'; -// Form remote +// Form remote. if ($config['ehorus_enabled']) { echo '<form id="form_remote" method="post">'; echo '<fieldset>'; @@ -163,6 +162,9 @@ if ($config['ehorus_enabled']) { ?> <script type="text/javascript"> + $('input:checkbox[name="ehorus_enabled"]').attr('checked', false); + $('form#form_remote').hide(); + $('form#form_enable').css('margin-bottom','20px'); var showFields = function () { $('form#form_remote').show(); } @@ -170,8 +172,15 @@ if ($config['ehorus_enabled']) { $('form#form_remote').hide(); } var handleEnable = function (event) { - if (event.target.value == '1') showFields(); - else hideFields(); + var is_checked = $('input:checkbox[name="ehorus_enabled"]').is(':checked'); + if (event.target.value == '1' && is_checked) { + showFields(); + $('input:checkbox[name="ehorus_enabled"]').attr('checked', false); + } + else { + hideFields(); + $('input:checkbox[name="ehorus_enabled"]').attr('checked', true); + }; } $('input:checkbox[name="ehorus_enabled"]').change(handleEnable); From 71afb7a741aad88ee40df90692901d7c615bc640 Mon Sep 17 00:00:00 2001 From: Tatiana Llorente <tatiana.llorente@artica.es> Date: Mon, 11 Mar 2019 10:07:22 +0100 Subject: [PATCH 15/50] New login page Former-commit-id: 69408bda61a30561372a5ebaecc08fd04b434611 --- pandora_console/general/login_page.php | 103 ++++------ pandora_console/images/back_login.png | Bin 0 -> 213 bytes pandora_console/images/back_login_hover.png | Bin 0 -> 286 bytes .../background_pandora_console_keys.jpg | Bin 44092 -> 176549 bytes .../background_pandora_console_keys_2.jpg | Bin 0 -> 44092 bytes pandora_console/images/candado_login.png | Bin 690 -> 476 bytes pandora_console/images/saml_login.png | Bin 0 -> 305 bytes pandora_console/images/saml_login_hover.png | Bin 0 -> 276 bytes pandora_console/images/user_login.png | Bin 0 -> 459 bytes pandora_console/images/user_login_hover.png | Bin 0 -> 561 bytes pandora_console/images/usuario_login.png | Bin 669 -> 454 bytes pandora_console/include/functions_config.php | 4 +- pandora_console/include/styles/login.css | 187 ++++++++++-------- 13 files changed, 144 insertions(+), 150 deletions(-) create mode 100644 pandora_console/images/back_login.png create mode 100644 pandora_console/images/back_login_hover.png create mode 100644 pandora_console/images/backgrounds/background_pandora_console_keys_2.jpg create mode 100644 pandora_console/images/saml_login.png create mode 100644 pandora_console/images/saml_login_hover.png create mode 100644 pandora_console/images/user_login.png create mode 100644 pandora_console/images/user_login_hover.png diff --git a/pandora_console/general/login_page.php b/pandora_console/general/login_page.php index 198b5c3fc9..ea73318e2a 100755 --- a/pandora_console/general/login_page.php +++ b/pandora_console/general/login_page.php @@ -82,42 +82,30 @@ if (!empty($page) && !empty($sec)) { } $login_body_style = ''; -// Overrides the default background with the defined by the user +// Overrides the default background with the defined by the user. if (!empty($config['login_background'])) { $background_url = 'images/backgrounds/'.$config['login_background']; - $login_body_style = "style=\"background-image: url('$background_url');\""; + $login_body_style = "style=\"background:linear-gradient(74deg, #02020255 36%, transparent 36%), url('".$background_url."');\""; } -// Get the custom icons +// Get the custom icons. $docs_logo = ui_get_docs_logo(); $support_logo = ui_get_support_logo(); echo '<div id="login_body" '.$login_body_style.'>'; echo '<div id="header_login">'; - echo '<div id="icon_custom_pandora">'; -if (file_exists(ENTERPRISE_DIR.'/load_enterprise.php')) { - if (isset($config['custom_logo'])) { - echo '<img src="enterprise/images/custom_logo/'.$config['custom_logo'].'" alt="monitoring_console">'; - } else { - echo '<img src="images/custom_logo/pandora_logo_head_4.png" alt="monitoring_console">'; - } -} else { - echo '<img src="images/custom_logo/pandora_logo_head_3.png" alt="monitoring_console">'; -} - - echo '</div>'; - echo '<div id="list_icon_docs_support"><ul style="line-height: 36px;">'; + echo '<div id="list_icon_docs_support"><ul>'; if ($docs_logo !== false) { echo '<li><a href="'.$config['custom_docs_url'].'" target="_blank"><img src="'.$docs_logo.'" alt="docs"></a></li>'; } - echo '<li><a style="color: white; font-size:inherit;" href="'.$config['custom_docs_url'].'" target="_blank">'.__('Docs').'</li>'; + echo '<li><a href="'.$config['custom_docs_url'].'" target="_blank">'.__('Docs').'</li>'; if (file_exists(ENTERPRISE_DIR.'/load_enterprise.php')) { if ($support_logo !== false) { echo '<li id="li_margin_left"><a href="'.$config['custom_support_url'].'" target="_blank"><img src="'.$support_logo.'" alt="support"></a></li>'; } - echo '<li><a style="color: white; font-size:inherit;" href="'.$config['custom_support_url'].'" target="_blank">'.__('Support').'</li>'; + echo '<li><a href="'.$config['custom_support_url'].'" target="_blank">'.__('Support').'</li>'; } else { echo '<li id="li_margin_left"><a href="https://pandorafms.com/monitoring-services/support/" target="_blank"><img src="'.$support_logo.'" alt="support"></a></li>'; echo '<li>'.__('Support').'</li>'; @@ -151,7 +139,8 @@ if (defined('METACONSOLE')) { html_print_image('images/custom_logo_login/'.$config['custom_logo_login'], false, ['class' => 'login_logo', 'alt' => 'logo', 'border' => 0, 'title' => $logo_title], false, true); } - echo "<br><span style='font-size:120%;color:white;top:10px;position:relative;'>Community edition</span>"; + // I comment this in case in the future we put a logo without text. + // echo "<br><span style='font-size:120%;color:white;top:10px;position:relative;'>Community edition</span>";. } echo '</a></div>'; @@ -167,9 +156,6 @@ switch ($login_screen) { if ($config['auth'] == 'saml') { echo '<div id="log_nick" class="login_nick" style="display: none;">'; - echo '<div>'; - html_print_image('/images/usuario_login.png', false); - echo '</div>'; html_print_input_text_extended( 'nick', '', @@ -184,9 +170,6 @@ switch ($login_screen) { echo '</div>'; echo '<div id="log_pass" class="login_pass" style="display: none;">'; - echo '<div>'; - html_print_image('/images/candado_login.png', false); - echo '</div>'; html_print_input_text_extended( 'pass', '', @@ -202,54 +185,48 @@ switch ($login_screen) { ); echo '</div>'; - echo '<div id="log_button" class="login_button" style="display: none; margin-bottom: 20px;">'; + echo '<div id="log_button" class="login_button" style="display: none;">'; html_print_submit_button(__('Login as admin'), 'login_button', false, 'class="sub next_login"'); echo '</div>'; - echo '<div class="login_button" id="remove_button" style="margin-bottom: 20px;">'; + echo '<div class="login_button" id="remove_button">'; echo '<input type="button" id="input_saml" value="Login as admin" onclick="show_normal_menu()">'; echo '</div>'; - echo '<div class="login_button">'; + echo '<div class="login_button login_button_saml">'; html_print_submit_button(__('Login with SAML'), 'login_button_saml', false, ''); echo '</div>'; } else { echo '<div class="login_nick">'; - echo '<div>'; - html_print_image('/images/usuario_login.png', false); - echo '</div>'; - html_print_input_text_extended( - 'nick', - '', - 'nick', - '', - '', - '', - false, - '', - 'autocomplete="off" placeholder="'.__('User').'"' - ); + html_print_input_text_extended( + 'nick', + '', + 'nick', + '', + '', + '', + false, + '', + 'autocomplete="off" placeholder="'.__('User').'"' + ); echo '</div>'; echo '<div class="login_pass">'; - echo '<div>'; - html_print_image('/images/candado_login.png', false); - echo '</div>'; - html_print_input_text_extended( - 'pass', - '', - 'pass', - '', - '', - '', - false, - '', - 'autocomplete="off" placeholder="'.__('Password').'"', - false, - true - ); + html_print_input_text_extended( + 'pass', + '', + 'pass', + '', + '', + '', + false, + '', + 'autocomplete="off" placeholder="'.__('Password').'"', + false, + true + ); echo '</div>'; echo '<div class="login_button">'; - html_print_submit_button(__('Login'), 'login_button', false, 'class="sub next_login"'); + html_print_submit_button(__('Login'), 'login_button', false, 'class="sub next_login"'); echo '</div>'; } break; @@ -289,9 +266,9 @@ switch ($login_screen) { if ($config['enterprise_installed']) { if ($config['reset_pass_option']) { $reset_pass_link = 'reset_pass.php'; - // Reset password link - echo '<div style="width:70%; height:40px; margin-right:auto; margin-left:auto; margin-top:20px; text-align:center;">'; - echo '<a style="color: white !important;" href="index.php?reset=true&first=true">'.__('Forgot your password?'); + // Reset password link. + echo '<div class="reset_password">'; + echo '<a href="index.php?reset=true&first=true">'.__('Forgot your password?'); echo '</a>'; echo '</div>'; } @@ -544,7 +521,7 @@ ui_require_jquery_file('jquery-ui.min'); ?> <?php -// Hidden div to forced title +// Hidden div to forced title. html_print_div(['id' => 'forced_title_layer', 'class' => 'forced_title_layer', 'hidden' => true]); // html_print_div(array('id' => 'modal_alert', 'hidden' => true)); diff --git a/pandora_console/images/back_login.png b/pandora_console/images/back_login.png new file mode 100644 index 0000000000000000000000000000000000000000..870226192ec5b3dee732c181c25182a1d2e5e9ed GIT binary patch literal 213 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5X$~|2iLn>}1B`Glf`Tswjp+maCqM`8?L)MR<|2ZZ&cpr95 zu(z}ISt7x=#Gy@cfv4`0si#*8+bnMDm-5@h${WF>zu<_^m!2}l?pYNXYKx-^Co~)t zf9|d;xiuvtdeb~DQz;GuBO^VApiZ7GY#w$C^8_X`GcfTmxY|FPqx``50niByp00i_ I>zopr00U`9VgLXD literal 0 HcmV?d00001 diff --git a/pandora_console/images/back_login_hover.png b/pandora_console/images/back_login_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..d518b9cfe6a055be88a1bc7aef3839b23c9d3a57 GIT binary patch literal 286 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5X4tTmahE&{2N>N}od3!~eA&AwXX5qQNm)L5uBu|>u*b7KI zv<fv&(>btoUZ>MxM+Le0a%x<>?2WA=?1FNKKeF)$iUlNDIC5*4%B*L-Vj#1e^@@?q zYSt?zGKZP6r2BN`MG_46Oo%zWF|vTMdsfAY^Cy^YJW^ovID0&4qw)oHd5vuix28Qf z%^tF`CBSdl4WXn{N?kgN+e}n%3oXhvDbiKkb*M3In~O;zv(B_h@u`nCv@~XkC2V}c hv{EccmVrfrA?Q-h^0nudJ_7oM!PC{xWt~$(697NQWaa<> literal 0 HcmV?d00001 diff --git a/pandora_console/images/backgrounds/background_pandora_console_keys.jpg b/pandora_console/images/backgrounds/background_pandora_console_keys.jpg index b919de4ed88d645717287f90111f51cde3d44de3..d1775d40f25c08d402a82d924f9bc64fe795ec3a 100644 GIT binary patch literal 176549 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%0Ds6(7FOIO9V#tT`m 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 KYL%WckN??j3m&`x literal 44092 zcmb?^2|!dwwrJg6k)?wxieT<D8hIHNkszyZd!oMhG=kAAxByWEA_|5EWfLy+oBth` zNHn9OEO(NO(YRnlWl)69`%zJWW}<?K5k}dxK@bE%wtuQ_chf+l$$N8@y0x6Dd+)iY zPMtb+s=EJf|3A^hh0&h}A+&h$JIDkLKz}0|y&!6RXbhr|2(n!e>i?(ki;&33EpGPq zVT#$G1%|KNFnfLYX8Y*Rw%9w&o@0+ZyrQ>!wmx)2B)x7!@aJLkr#4?Im`Z;hIDhIV zP9MzqV9R?OLOy>#He$ny*kvo%$A+$V4V>!bNqa=QMQ`4+c|+u9boAy;VG6hC`BO>b zZV<=W_ETws5*a#wsvO^y{`3PM`n~Xo4Ybp2$64#=I5^Pr=FN6^*J<87hne);ISzB} z=fMAYvmD-abDHNi*O}JBRJdD2V36B~3l?eb1*!Q{wJ)`8+qT);9A}3|1lv2fy1L>v z=FXi37_$^HVUeFj&k9q#rE6iq2F3b_&$mQ=9v(*H7C&1T9u+x%Dm*Fw3Y)il@PWQz zqtx2G8NV07Rz!ZdVc;>0Vk=h0Y}sJ{;RZ!`RK)rXfc}=QGSKeTH^PYUG;ZDzpTkG_ zY}119^--HQghei1Fn=nP%ntlK(9LzhyH1XC92P8mcka6m4htP!-&-)xb%Be^AK!DG z=k%`YA9ZaQt1EYrzc+W0v%{kI9Gsx;Jh{WWjtimoJZC2thd;h2*VSDdrilD3Z2bn^ zeLsi$YU|E<WnH)TA~t*$86L4RJbaUm1AIclBf}LT;alkUR?MUAKKN|?=V3VG-|+|H z-*>@=h|jlf2wW5qzL_QzcKh7O6U>?C0{r9r?i}a25Or{HnLAhh#|4hgjxO?r^XC51 zb*i>*;Qxeb_V6(Fm^}>GMVAFUh@*PuhlIZSYzTus69Jv0|0$9YmPdgq=!8^%CHgNU z6=Q%<YATgTP0dG1rK8McW@hGQX0p-d1V+m&M~@zDDH}iD%4+=hDHx{efs&e-$Sh>m zW5!t9T8*=^)ffEMNWTh=HW6v0r9x^n5{#yVqpAL%(dURFFd#z^B@l|FIMW~xzlOk) zWC{R;PzV9!jdl?J+Zg%s&!&DcckCZOOnU1p$M-~|ht-8!-9zS3K`>f48hN2kW^miO zlz>Hu<ya2VB!KIXr+}P)B~W=)fBHE5>jnIMe3(zsn<*o=Z#fPjA^&*D#FRX$QDgxN zLYWgl8Ga!F0@OhuWd<dGb3$Bg!?7b_3w>K9+{qmX(HMinfpMVi5E^&_28r=VF%-sG z;v9;BK!o76If(pgz+!Qi_~OIk&Yj;_tLub7C{t-!a^VlYRp<si{0<iV=-fx2k%t*x zXfy|ZBxH#w`LNP)gqeI8A1Gmbyl^?o;qYGp4?Kg%1*yNbv~}(M=+gxZb+SacV(0PA zUz>Ha%Tymsojd#<X7<#k=Aw@_y#D2cHTv54?cjU)F!~%4(dAMM`C1}zAI=smk!PK1 z{T9CWzXAj|Z&;LkzVKz?zrRo?jnz1{QM+7{apuN^b$<>In2~5=Ym__TJx{o|jsJAP z>mEX;M_@T0)Bqm`ccB3w-H1klWXRI?LWo%`U1hP<`^K(k)a)9m8%xjyKA)27{~~bO zOMkw|XUzkj@I<e7PKU7e2`<2^M&WFW)!D9(JPWvGD_{GL+6F{oU_m4nB$JoHnWiS> z9~Kt~K9~s(FjykrBk@ATo$lqwQ_;ngiI;kX6YjC32m(r_i~SF;_yv7|3)lZ;bfEao zD|?#XU9%1m@ZRe|$bl5HBVWo?M>IPmAkrP)4htY1D7gFWPn3!~GyY=T$(CH+7cHG1 zH%p#Tsw@9JSMk2mjrER&b9J{IRQL8Bwjk!E=wh#6n^7(uglsf1g&CI3_-KbGN)9~_ zzNt3pgGd6z=Y*gtbiX~}cI2TV!4qb^U)3+NZ69}GDq;*IEF9M6D>5vC=Zmu)dy;nD zRIT16KjLD}z5@AwTQmh;3Aj%SVu-?9@hSY|2zekWbzF1K*73>y8+%%rpl(M>?N=F3 zU%Al5qy5g%_lP`flep+WA|2HBFsc1utN2=-aC?r2)a&#qL7gh_cQ!XNI?RfO0Ly8I zO_ER8Qzv?e(3yEa8PmSH_CFTyR;><{I5q88x&HcuBi{~J{ar9KUErM(rqMj3-fph3 zx>nR8X{$P9-WzEV^y#RMT+V+(k8oaPjh^totL@*0tYuOj*@vM5Acngu$AUa!5xRW^ zI_34+MKvjAc`8Nug(?J}bYM6gPCmXR%2=lr@6Ta>ZI9n7bj;<dJU58$_ox)orTysG z+fj8s-sdyWB|=6g#}NCT2FDF7+#Z!FN<%fNwI8Ji@7Rsg|1z+_EomuhMQ#OYqM|_n z?+?8=Cd7IE)~@Bbf2K|sn)?T4P`fVq1hKdtfGrvrqWGNGgtFW_x%~)bejcxkQ3q4I z5(>tReVKG>S%i>Ow0O9!c41l9Gb%GbCCoRs=U9F4J0|e{@yhs@RsZ}bEUr~t+u7jy zB;p$*>ceYp{hDHyl-ujcK~z18C{0x0xygrmkKNx#ZKEBwA8aw-dRy06gDx`c8aXUS zn_=brwe|gsfN6KstW(w*?R&`n-j6=AX|EMYdJ`MX8Z+N<<pgTFD(ItChmWN7BzXo? znSX1R&wC4q@vj7$G-jrP3qzs^VNoVX0>L(6nNs1fuyg11`#p5=ony4NoGSHXs<rXo zaWSi`#(Xv*KKZ_{n>mY6_Q%nJo@8M{ZmXpE#%>zPGOaUj?AqNMzR)@Fa<XGT`cLJ* zxYx^)`R5h1Sh1$bC~`oefU*c65+7u9{Qoxg0(5(p<RB@3F%k;37=}e>BV}6#8bwIb ztElHR700jGM7jD9X&v=*UF^3Rc^r#C2TZspVGOJPZ{z%}#R4X5-OdOmsC3y5*04zq z5_l>p!0HrMJ>I0Z7?!^#PRUQ~DoNT)A8y58PY?IYXHbqO?B%ysG`Wvo^A$XUn0=h! z*z&{A#mDv(Ev{YU)ZYBxgKFrjzBYm%)hN(7SI{zHU1?-S!Cj}Knu%ro=#ROT|1hLJ z=pF%xfv+keZTP@M_4g=;Aoy&moiz28HIqBmB~T?BRgqV-6AN9Ndy`T~gW7;9FVE^J z4UVamKt`xdbD>*hhTWBpgp_ra@yUjWzcp?Og4a0konNS!pgg)=(Q47NaANscZxdI| z$I7AjXCMP6Mhw=%h|zN>0!bSmpK8S=aS8Gh$B$g6(nFg%g<jU|uZNrEVbjxll$j+V zPM2mjxUvK7%`E18Rg7;;tgK-2jW0ir;MnX!rxQm!$9*<{^E+aAzGfUKl09xhP-$ez zwAODEEhm+qWfYgrOWX$G&n(WT-Rl1lp5h&T;_)MuE15j-%6C$!%g7yiP$SwzREff| zgDc7D+|R}~7ry<y-CT>MRXb%z${k%~D?S!z`~w09s`<Lf_K%6bW7b&I$<~L5gBo$G z`~i%04}Q#aTI8g7C_FrXJ0#{76r{4xdj3Ok@vFvnd!4p9q&7|x#^1P18FQ^^Q9eDr zBO$5e>Fu!`Yk+Fg;GFsKIa$T?#eFJ`V_GM>dPd3@9o>$>v_~~D$l#9RV^HDs(eR1g z!cQJ&?tOP`YWZFohOoM%ll7=RTpi$Ck=v6rKe2G~*=5YSO1WWER9py+gue9&@=J~T zd*vlhs%X}*d{Er%fuQ(_;MWdbJs4D^P2_?7$yh$**}@+#oGD!#xN~|{!=#JH2B{4e zOE-41n#_gy@^a6UHIqBptCv&NH8$s)3)qNDWqGB6P#+HsGJ&84F2+E}8OgO+T3Kz? zw~Z}MYc<=mJ;bR|-N!lDgN*chJ84rtIvVGZ?7b$lNxo-$T(8`H5OMUaf$o1?Q)=IH zZd5;-FLa(ak|@+yfC)3A2U48D@HUW(W5gbUKr$k$L6n<$pi|QJxGbsCbGMp)>^NhG z_-qW!J=;9um0w=ISL(2t$2RL6+}z-lF?G<QXq6<}u}ix2!J|iouJz3w;*KuqoTw|^ z!5VpHmxjBPm-(rA@tRK2#hhZ%;O6)gb+WF(R-xH{V^`E}rE{eh%IuIQHuVUKA9nft zy(G`H{^X}SRK_X}<k<<5X?@Bbb&kw5h{cu%7+&<~d_-6|KSo_`Es1I@i7)-4ydOPJ zY?ZBgaK28-Hw>ENh~OqIB%1bM1el$Nd!9%L|5?<RTYjz3`O>C?o|O9W3CuK+AY{tx zn4sQmeeyj)HDmnzR2#dU<m})Uv?(fYeUrTM<wLtiSsU^#10dJ>aJI@VxWeh#N+(To z(fAuBQ)w-(vCAOAV#UTYZv03y92XQLtsQ2VH8HmRX-Pa`m3*p1KlA|`TCv01898TW zdW-l#jO1uv_Cuj>)jeOidc{HZ@ssktkhk08)GCMR`P8km^@m$!0jtAP7~}1Ti<+wE zzd7;7m)3Xg$WsW8?e>I{c%QY8vVZ*O`e@^|AXi+C*+kbX1TAmukQ(oufQ!dgITgSg zoTx!fYBdflJcwy^P~oc*)`!lGnpSS-bo}|{3~HO_ttP5)f}fxAXnmzuh%BP@xozAo zclnXV3`c4&&5qPi(-U>=f(}iKl7DlAnlx33rzG1`>kCh>8=;cfPjbtFB0uUGYM=+w zgJQgypHlfnPFRdC2x*-WON#{NJFSIF@EjXRjDw6dmM{GNgr+K!4qw&m!K^=6=vLR; zcC%)z)qy&tb@A749L+6V)2wkZPc~LnoA<o_k*UYa%lgU6S)f@zs(Q!8_vX(AFF4Qw zEFg?)*r89GO1%OuXR^yix(98~fLcj0)%K|Rd$}78{e*+cEd23CScrh75*sghb0vc_ zej8vFs<$M&Luwn!1@(r@vw~+hQHdJYN1)xdbAhjDWI~Men|}1o-ubQi=XQ_Hx<>5{ zBueSfn&Rp=EmwR)lZV7*Fdxc1<Ni|AJR+~#VKj;co5YFh)GSFX4W?PBry_a>=5~s~ zWZ~;i09>OGiC5o;f!*vGQ8y$thifDZLXqv7e&l>bvduM%4J0crlhs)(tzSO!j8|ry z%pp_AVJ*O|gHvKX{`paT{&L+%rf%J-v8tpBhau}<9=;C?rGhptZ-3#0zQIcUuxg-n zhQ&75e4Kw)=yn@yAPbg(VTgQaK;^Gka9oBICWjn>d61|MLs~Mfa<^L4-w98#FZUW- zm*kWl@6U!#tZkIe??>k`QFz$ee!b*aN$-IN-v2cbZebjx-<HQ^*geWErgd))eX7vu zsZ>W7T{SBD-=UB1z@}%K<e5#!bg=S&C8L3aJao=h@wj*A{gMcCO~nj0qO3`>fPob= zG0`Zr3rd(Td~hx%1?CMh8zJ`@2#hg<z1{4<oUbRmu&Oriwoix`bb}q>_(SC(=RNnU zs;w$A{M6%YRHO;tSuNtURukkFd;X@%J1B;8+{O8K`QM%1{zN!%k3lh6#;J%F>yG-? zKj<gMO;0jymuGJ7k{1oagn{5hMW@I>Fqk>Yvv!P%G-n6n8K$<tgg;wzQM%^kcdfF0 z?*n;g7fnToLk*%ZHxN{y5&<9&9x`C%jSLW8y04`z2C^AiS<G%4T0bL86f-KB#9N)6 zlBnb10nUl}?p<t+?C%AedP7_*ZmO7#Pw)5YhP}%l25n7hQYW61T2dQo8{DruPygX` zT$ShC9qLN|GvQOzSJ{sBnfHV#`a2Jb<Wp7FN7Qz%;cu=o*A`gRZ*ydeFJB(SgG7u9 zXnkEL$8K@onMoJV4dpu>2G}8R)FOC-^7Qr(h2KvTmDNaX<2JX*w%#N1)Lw;+6@a3} zlrosXFdZ>RVRi!;VRZG0d|5wc+l@U-(n}WDY^trM2{M=wzv$@d5&HM#wupbOk1z|~ zo>*;@6xdYlobhN)K?*QYT(<;>WL*$i%J5Y}9dls%AKH)RShs7MGEYfo)obJ_)bUF* zs1ziPY14F#G@+DapExZ0HKXWQ?a4KqO8WqYmpm>nWn}}+>hes@fM$&u)R7Y-ieVl# z)CIaAD8qZMPaSotP`0Y$h03+EipCaeB8oU1qX*Pc%zYr7LvZnk;O09!j@n)FK=`*@ z^))xMqNiJ9d~SDp*9krID&l<nHyy0gvWS@?IE9HSm;zHI$+Oe`)srs-wRUpF*Af)f z<`30P@^sC`hUpi`dJcaxNp{w$2DfIfO}!lSc&F#(Zsy5FmGbgW9)D@~kR9QH%Aynr zRHb`K{X4rgce-}C-oHDn=b6#=KaXpeOY2$?Tn}+-uTSy(C0eq1M7HCR#i^Kry~nDi ziSn<*63xwcx;{Lfg+k0_q+{}nQ3M^vH8Qf{B`lG+73)6+@FuNKoLwD5<!UmIv`P|B z)jnhT(OQ`OA1Q7Qu+Pfw5p3<vqOwju+0*NuK|ea#8x9PFtV_bOR8H+z6YupX-Og6A z;l0nQillVpl>=)^gMH5?rB%weAI!<*f;OthnVpE&aV5E<?e<mus2J3`m!$zHQk}j3 zYwPaVCx70)FYzSIsWpWI&!vArK4Q;?dsccVzkA?RW48Mvo1D}mEy_VCg5HJxJ4S`< z&}YKfP+sOuuLT>%yn814Y@-pgj8(EW&D7m^a8Tsm^a<t&8ccscZGs+)13h3JnyE&4 z5=JcIIDIxmbe1|QK50XSoI3fiDpTe3ytwmV%^3gh17@ndE*x_@9X@}jW8#IxL*~VI zm1`g5Ppgq+KdCR4JZ(E9i+!=W+NLR|4iqA%FSqB*Pxo%?p-!%j^ALnOI;smNmfOQB z)6HjHqC<DO#N8Fo5}5p(CEjd+;WHp2G5z~dkb9TZ^~oJ!OzJZ^I|yTF!s<c-b77D@ z!_=&OTqB$Q4XsCorL#5r3#XSiSdJtd^{C?RRa$Zn;W|AA+G53WLQv(5%b`%`!|dY| zvuc;CeSefZi#w8{NH3PWaDV%oUH6|XyZuI9QJp+>PiUufv8E(GX?v=gRg`D1oFo$0 zip0gW4bBQD_mp6;|K+PYpc`LEC`eJ%HaPVo_Zi`;nH`H=gXK<*Ii0L(;BiRIEx5d* z@)?zt|Anikd{3NH;t;wHK_8S9SKE87OW&`W0a}F)HU^dY1$)Y8U#gy@%X-a~Mba8A z%5XI!Ph5>mg#v`kT8%XW>n@K^zW91YZhhG?wP#NDfB#$lw(QnXvvb?ovh5#tN$S2} zKZpz7txSKAl@f^j{OJddN8Fiw_0MeBlFW0`IcuKODZhWaFF3_}Q$4l23WT43V5Y`X zz6&~V;LsaV3FT=GG|uJK$)V*#(|PBt_Qj05kU+Uj)fWj@%uDV^Yx)s=@M9&d&mJk_ zGg1NMV_C<*C%^*FXA#8^R9f#HMFnkcF*|v`OTrgWx3=~MxGGmP9WS(~ztvUhd_Q0! zUL398oDa>^s|($H(-PmESk@%Inkzr?XZu7Hw#@^0te&Daob3>3w)tt*6mpwE0nz;j z<rqnb_a(Q=mt>XFtW8g{uH4C?Tl_Sb4SF(2TIxziy0W-nXdj}G<U4USES5l7Ax6NU zMcN2!4~M?`=y;2H^ZXqyT3LDj>iIqx0!k7>W_1L6jsB1MaZWw~h{~%|Tu>&K1;14O z<w8|TWYH0|*PJoEif467^w_@21{Q!1=Sof={l2J6!r#M4h;`}L!p6WA52;9#e`}Gl zc9tLVTCSPOKdaHIX$BiK*bF<oF}%#F&gvMI*QS~?xKt;N4RdKH%pUL`#062uIKK4k zDhuzmJ<9Kjc77iyY@!nEP;H~ye)&Ww74NG;5BM(hr?Fbc4-oy3o4fCU&l1;Y6N`tf zZSVlCN!V<fR~hF;d;5DvMVr6SBp#z_{su-uj@4z_(Yn}>tEt)CcY2s5KM>-8+D(eB z(#0>^3g7(PL$Er89#UaQ5~TKuH-B8+mn#X+e*V^k*A0WX_DnH92{inuWFFa%0`Bj7 z=a|4%QxN8ls-`6$4Vh=&>=m-38kR-pfi!;7t6Y1P+5_saIks|9xx2thDCl+ciX7|w zwbcqu92JF)Lq#aE^FiVvS-|~{jmz{t5|QnXnrbFJNH}LySb`pipACc7PQxb*LVGGG zaa~rRWb-#P_-s}QfV#K`5YZ!SdMODHF+esJ&7P-Jly{F$JS{&`P`bNv;En_1`k-pn zGud(^*(4H)S&rkdL1_+%Z=x>%9`v-Zbqhb{1P+xaTFl=5o8(Hc;>;q&uQ8Ioyq0%v zOx=n3E4X%a+Cx|k%u~N(Rgu=SU}AnT^gLJsnBE<nnG&o?qz`PFoLTA7qgv{pc}m=m z(wkdG9Z&W23~_vbUrx{^xapBBxL&D>D$C#ZzS;2?*W@b5e+7VX&q%4bR{XN>3TUCC z3$PmLhfK^$u|f&FU+TBG#w@FJu8~THS<VhWSg2QKEL`1Q=&IS?V*UcY!mA;hE~nvR z9;}%J3)iX;JgY<!ib`NeHQ!m1?@#y1b5qB!oK#j|xuAPvd}(OY?2wbeYtlw%H6<)u zqj?s;qxAH)m!X~CICWfX`NM}>7K$z;$agjFe@I`slh4a&Np?aGSAMoHc&98NH}A6e zPI{w2^9flC7F-W!!(#i9Tb{T(*b7FwJsY3&DCx4O_RFF>-G0i1QxU!4J4ZFD?S_bz zp|52Iqs~yE0=e>Ot?z6vU^3r*k456naRpNmi?PgR$P?)4cY5&Wdj;U912cO(%rj%y z3q?C?v%(udGc44KY*N#QHqt;geS4oE8MJ-YF@UD+pf`gECQJoiGZlM;C_h~M&yVD( z$HPS-6EmO6(i(t>n$BapE7~vj2v459^07zrKS$sBXy(Dfo#wxS^9&g04HkthikD=7 za*0&@z1?1(tZy~n_y8ye8TnLYKWe<zDswh!^U|q>fN7)`-!A4N@VE#%l>ZzPJp049 zfMNY-QPY5^#CgL3%bztbH@C`iuSST^3J+Ya;vz2Q6w<>n2j$!@oS6p0fCwzUB4!D= zy9e08xXBWu0rp2NdjE%V6%vHzNoL2mcP)r4Zd|^n#Q&V6?RbD=qvX2-5j!*6`sBw` zskome=3lp5_Y@{ILx4INs*!Ksf3V<;<Ci^EJ1n+4c8l^0?nq{4KTJjzFWcMmdVKuD zV&Xt74hOBk#{~va9uL$@{~hnFO-K?kNX(vF+4^rh&HV%&%(CaNQPQnbb5w5ix4NZ^ zQ#}N~F0Qf3dD_E7l%38apK<tu=yQZC=1aay!OPu*Xw*!J97#AkC<h4vgXq%LHIq}n zS~%Y6w9w;@Wx*z;Z+XDGqk<Q%_bOkrApBvEo%&XW*mrO7=pR3<5UuO>dfy=`WQc6J zeI=WB$!pFC_3~mB5AtI?gs3bk!a{RIjcq={f24L?vvXAYdGwS*Y5Bt~!^aFNfYv?p zP*&rzy?*@UtYGbOzLp=~70uLl?E_oPAC&5<8NX7;k7OZDrgx)lP#`#hMwDNAF8kz@ zku^eXD^Lxy2_wR$MhaF~C={e(m`_ciqY7y}^1ON8dY>tWWO4l{<gM=nJ<3Ua7az)Y z{;f0FwIV96dU9&D-SqoA9Ja%9=d59jZI)W8+Il#(POh%VAbowp#_NS92x*=?lb3WM zTld}Sy@$cHccO<0F!Ekn6Zp^)(5$RsRB)#qqYS3i$Vq*7Mk13*4@DoG78F%h+bW*) zlt%4iW`8H06<5I2M}@=G<JACMy)g(z0@5id#DExJEGL}-%cBnr4@akc6k0uwS=lHS zJdsZ<??`9=UVhEaX%l-jA*wWToKUs9DsYGEulLMZ<m6bD;-2Dpwq&rw>EtW>R>v#n zbv(CCaNb)dJjgQeJfWJH(!dEz;)PlLsC;jo(oo16KCVTuSEy=jY<o(8VJ;t^06zLz z9y_;x*J562KrJ&BjGtqwO6lP>2IcSqtRO%$jXfB{)@DT+E=LZ+G)!15y=Sqs5O@fH z#WJ4;ErcEw06ppq@YtP|qQ+)w&&C(Y_P?}!lbX{TvS(?+6+gk6|CIKCHg`L%W$J3$ zaeL->HcwB1=iCx`%#4&JB|XAVdIRQ|9l2q4{00!x06<*b>;dcc%~A#AO4=H0Y9;x1 z^8>6ZX1r7>23rses)0^<!B4eSeZhZ^pvo_*jVgJ0p2|G>{m^+a%+n;fGroc$z!58P zI)HWW45qo^H4+U`1%5$Uh3<>zj>-yT>$5iJQ@b{UrTx_aYeP<sw4HW%F|h+vqyXqB zK*cP}a%aX-s}E-X_?}zC+x0bL`qAfA{pjmOKgPLyvoWGWs8HDn{&qXrwQ2)+8e-ew zgrKAdvm>3Nv(L?3EWA@yK_$XZ_f;J-Yh>#NKSk4#7i#-MvX3KLEKzv*^aA?GzR;n> z7+k~p$n6#jbySbizrC1!6mF=Sf~g3cZl{gA*ejg(e1X0iUNMqYsc3!1NRio_iyOt4 z?ns!C5VZN$spqUyQ^xs_Bzz1a#VjcXS&Af^kmUqHveLINN3(KCZ&cM4Nz(z-s~&C7 zmRpy&#{O{EHra6-4gC^E7qj->Bu~59r-XBp!CfmZLrF(~DJ$WpuzobQdQy{U@Kc0Z zzbp-}$mmfm*5rq)9F9+~8G<kveQ0W9(9ZJqLdU3=qlqp-im7Pn&%)Q3T8Fk{JdI^l zFw61X52KhM;Gi9d111uHBNcTFITtwYbh;i~IHTvM<I})SE-&f!Vy+OkREs6gp4E)4 zV=aPix-y3|sM(2g%=?bnx2s!64I2`X+4P*0$r-txQS$J!i;I+2uOD#?9~qSCqh9N> z6e&SZ{$VgwTCrQ1Ww37XzXv>k%@s0O1nGcAG^{P-oE_-+f<W}CsVv*3_1iyYN71{% zH(uLgh{&0l)+mv0sFj?*UOg#?TXIA4ea)y%!r{uB;AU`<fcMc5`d%q#L;X$%gKbZD z$5&oKxE;^Dd!oWa==|}HwB983mnueA0k0#^V7*6nbkiZ?>lDL;k+`HSvsluDg~$L9 zz7Sy9JQegLSYvlzTlj7Iuh^}t!2hmQCcEZ=z*l}+L95X1uFRs5yP|YyY*SZ0^^3+O zbBg@h>Wd>|4%{5U*Uty*+eNTWZXWF--6?K0%Pc(}Y^NRNK=HBd6~q`+FdE$$q)|Ed zBl|D=<b_5N24{*h<iGg%$QgrNUh!c-WQZ6v9&SHPjCfPV^!n-vJtfHz$-?bV<!@)z z$d<fH8itqeJ>S(LJ959MMmkw9;)iN^1~<lg%V3<mUbFHN(4cs<i%2BNQ!Ps>wWBc> zr}$073m6e)sqN~*)B96Lr^f|$f*1~$54wwygw@v|DJ5<4V;~d=u;dC10X7Phj2XfX zO&<*kwYXts!RI&3m7f-{OA_Q@!|xIpEJyK`4MJb{Xjwm+Sm?64vXs&0zrxrC!W&y) zVbj^XdsBrg$HYj^yT<-uo{2Z@Pj98jd-!<Lzy}7mFdBui2JGZBzFLLd4%1r9*RFbt z<`JoCqZJ?%j~s_mtVLyU;MqV0tDGqYE5KN_!=nj^W|&J*m@ja|asjed!z#lBKcBVU zg>zx!=xTR4SSHvEOl>N9gdyE6_WN+ALz6Qw))LniqtA5vO1?Zx^Of%<;Cst6;3xT_ z!|Xw{@G`qExq}IWD%hKBS(3_V<$+8|o2D%3mgjMgop<VB!63NW=Jcsn=;2!6M@n5v zf0Z2FEU62Gm#6lq3+KS{Za9_CV#Nb{H4v-;aX|x{(0>w%v%j9u12b&Fi$^SrQOrPX zX)o$W8!dwBZcbZXVz8@+w4e>Bs&dy1<$<it19D;nRo^et`cQB33)k^SPQ;rWEJ$Je zd^~zg&-w|cqHOj;NraGwCi8?31zSspuS^);65@|DKR#doP<VQ~Z{aCFxlKFXWfl4x z1}s9DX_6$&#&39`+F<CO!U!b;q7;m4{8ADgRrpRL0OJw#9<w^?h=)JAPzUR$4frAP zt|Na<W?k~ys%xsbvW$X4hxlZiKMaKViKRA%-grLDFdRe$=BU6nKRzs*j2wltga=BJ zP?NArob&wOA9RgQfhwR;1d5uCR36kEo?jf@?uNZ~^J=Uc+4_RW4C>nIve!<ziS#OZ z-vS|;V-YfcvQ>Bp32s>2FeO5Tc(OqmunOoMAWnAR2<tPwn#T7Ru9#4wq%T9wSJT4l zwX^^u@WvqTsaf~D(Um*j&@;gmpbK=}QS#s`qU@aN2_+1}zzu!eMz!JVtAMA)yq?mn z>MU2usT43j>{q#HV#{AUKg1Jh*wn>=YYy&T3{u>$ZGdsKEW{aR)jF_5I%$H38-x~Z z=1ZjEIc4vEn^A9{I9>wTk?no*U4~97y83Xnz5K}|wm!F*a6X@psXqu{2}|kk>#_4- zA{SJ-fI(>T!Rn9W7WnTR6+&Y~F1;6DUI}McSKB%~&M9;co}}Jkv3ly4t6waBR15QE zCobTX6@l;cv;Y|jFAw4~y8zW2^c%hbmY*9!NXDHR#0w0h4T3epvYwU+iJRKmu=z>q z?O!u7pMUgWw|3T)mors4^D{$a^sqv02Jo8Fe@%Vi@og_hAJLA?z$Sj%c*~T}vOadC zs=9n|kdhsGUfITNEpg05cfgl>R@`?jGPeikYYa439roZW=;LAQyy?57n-D<(6S?H0 z^)>%72Z@U%wPL~`*g$WIjaO(iFe{iCC^xCx4Ld%T1&6q8T;e%?&2mJYj1l@V#kJ!5 zwT*c7{FS6Z&3irw{@UjJk;CTf;3v|hoE#Eqn1~$TmMCyET+b4>jH)WtA&qo3!_LD~ zj>Ic3e38~EzTi#QXZ<e8vAD(>%&6dkgh5VTe&X#~;D764u-uV_3mQuJ$uE#WfYL=E zN?8seXHBc9yraI_qQp;$gwfAJ9OILPr-Lg!esB!jF$cWZ3h1kOdi?_$F#t*d9yIRD z;v9RF2Y!q&N*Q}Mi=_!aC7xaw^rT8KEnTFqEryXM(wI}e9s@`0-K!_7f2g9H(t<t5 ztv>F-0bw#NZO&f~Eylh3l>j=)<U{)l=b>YG&=u@R#$yBxf)k<X>1>?|8l!}v2f8qe zo59l<7OQJ$_dUP>Ogr=-!Exhm?r~qmM~apm?BmqlmBE^B;n`^B$l2uX8S3Dj=E!VT z1}HbiA=E9mMV9S*zg80Uq^HKFF}si+iimxK9J;v6CGn=kcfN5-Tekh2v}%fLi+RTf z@zKH+ZP*uwfbbzz$y93-BVXoE$<5d*-1cG2@|%9meLla%K#nDx0<=ZdcwMvjg+TO* zV3m2B7p+2qI^`Cf;AJqEfxz`JIiRHBWEB{*fl!YV=Ewrd?Cq&jk6OQ-@P+vB*)3zi z4{vg}cUGBF*Q}B2%sfe3Q+A=-2kV)G<wvR~R%L12WC4Q^u^!|wBL%*_X>m8$b8Vgb z&e;4U5AH|rYNdsci+{bw0&SLUQ&f-9`~MHR$)E)2zs_lkYbLj#W00@gyFw$(9C!$J zt++82`i&i|BLE11f$*S=rgJ*(7P269AN0I${=V6>@oV4CuNZw}1nmtspab6%UUbgZ z9-ly62EO7|*&uLmYEwCY>q6F=%z1q%|7K^4#r@*?CJ*Hfx4L53tFr5e-E7CWD%IP~ z9gU(K!q3=E)3BlcX&el8(xnf*>2h{C2vRZZ9N>iv3`Z2C7~qo+mi=U-LKFN`HVWaE zwDwF4<QOuYxMH$!Yw!gU2-G_*G!Z}iczc25#~Asx83`0F`R#yBF^lm){MSiM+~c>u za8C%CRu&Z#Oa(vB%eR}}-qYjHhP#y{o|Mii39+=!xY^Yu=$_S?iBxb8yBW-Hztbx) z#rwI(X^J|fKc)hVGGt5^j|NI05#MP*`i|ZMlN#8Y&)w!AAH*$)oKYc;`l%%N=mX_& z(eDB3_)ZIj>-gEQpY&}-q($OlFfDyr(;cjuU2tJ~uketYx(Te^W1A9ar!>EgPRX`7 zt;ck8!|%Dx$hZ`&R62t4jxj(SPzwkz!24=>VF3)aX6{r;33LW0yLS->c&vau(6VSV z(1rl8!A=tv%6}Kw&D2fi3X(to%#W{SuM{6-n>1<acg=6M-zjb}*G!0Ru?SjIcTW~k zQ9YsglSlmW((4Bp1j^ZjN51Ji{%arWY^(Al$3d@W;k&{g#CS6hOM?`EF@!dMvaJSO zN<OuKi7#G=pH=Oscg_aSP{K8m1-RyK20!77H_!OhPtA@B`BU-!b5<_h!Dq(QsTR*_ zF;gg7&HB-jm!bn2AFGN!)&5v^?b;X#18obr*WLi$os6!UwCmMlw|Ue`(_UM}y2L39 zJ?=+u?xkxLiWoU4#8~ZudgIVIid2UMFaV0zLx2R9po#zk_{xs~sZ3Y@H0h#9%MSu3 zlm)T@HDMBp!R#jA1WCLiz{kg|OOPl05<NcS*XYsI<<`Yi+RdylmC@zD^oGpHx!gyk zUYbFJyRWz;SDy89vDZn-tR}7H`L(lKeqp}guG`Y<)hjQhV9zmu!-M2kJP#>y&h$Gc z%Wa2|<5@LYU$OUGbIp`32sWJ`hIt)~Bc^z)0Ki%p^bE`}z&x~xI9)miEGS=t3K!I% z-x>S9#rs%tV5Q^_ggC;4ybfi;&1uyxEY5xnz&h>rz}A0{!roO2m{99lNnd7FwrWPU z^JU3&aG=bsaH2LGQQM~kJ<_;`!2K~u`O7Ope8ADs?f$*O@AgHHPY+`h<!7q|+S(&m z6Z&3-?Y)>XE!c+lsOg%0fGY@zBdW-+$00GrfB+RE2FX`KKqfh0Ji^mE3XM<qF5Jzc znUag6B1aiWPzuW(0KoW)T&u=vGLAhuaW9!<zcL`EmHmZ(EB7$jxAuW>&D8|^Vo_O) zJ1jw$m$h+^HC64|t>)ev4%S$~?%|!H0$+uEZ;Mnf#a`JsEH%26<uOs}quw2on*A!r zQ}uK$?0)p5*w@qpr)wu}tNI6TFS?5Lfzbqg;C-&z<6h=!6@#QpOT)0(;h+^e0sRAz z5kPNb#P+1OCPWy#yqOACQ?+18G$kv?3&O0kZ63?7=<-LrVmnRlG!YojwnqggqC)3g zGh)rFXjmHqPmsFn3CyLO9zjs+bF27fybuWxIbvJ-f>6)Pp+8GEy$oz?m8C(i%60|E z&_`Ke=X->DoRK0<X`xJ0=F&`O@L=U}C`w)VWr=DF2$mSILx+$t2?9$f#&Va;|3p|_ zg^A#zt>&z*>9c|s;5pc9Y>Ckj0$~k8ti2zdacYv%IPppdZ34TYUym~GYET?C<7`o{ z{D^&x<%Ias@We5JlU|0V_Xugy0N&&M8UUxpRX`AhN00LRpW&>clElL@w+@Z}&sZS5 z8m#%Mfo*N_TWKviTtSR9vm*0!0UH3mouy%z1K__7z<7X-ve0uZg{;tdO^f*|T@g<d zZOU>StoJdHz(>AV#KkL9bZ8@9o%U=Gmv29OxWIC(>!rMgS(zUQx}BX$7=`3VbxxsM zX!ODCI%P&qR3AT~X&A8~eZhn6tIAtIXasvEgt$c$;-q|0p0lctc4hTQBSgx+I2A43 z6dTwDmN<S$V+iKNj^HM$K06cClAAYV`;?H22XY?x$sY;nQBkx*lpI7af%h%&^aqb> zz%l>~B7K=U=@()<KRcUyNU&ZRxWzt=i8X(5_^CYM;_Yr9fB*8FMsrPiXUhOzzOp_7 zsk^HD8CB_dvc5|KG|*J0b#`&2_b>sku8Mbm?Fm)6ufH{;Sh{#x3$L(19TxtC|2M~` zAVkI>iy-B990xhtViSaDNYZ$;T21d>yUP4I|MoB`VL|{8GZwfdK`7F8BG~O2>Unqh zPmnbNP$wU)68h%m>9j33&7{=ER&(`+{j7>qdHo1P-SRvYs>X7pEhY4<(E3GCG^Rt) zIr9<jIgrh>#mhk01h=@Fd`Z5Hfy)QWN`%Gy<`*~)K>1-Zi_5@rl8mo7#UeIOP(ke~ zC>_w`5iE&Ak)EP}$~r&*w#DtMdOjKp`vUtcM_j#x#f3ZI($+REv`6S!)cbv+gH8d{ zPO_>=Q?Cl#g72J)=_JJ1SOFV`9^*3+a!$qQ2t0CKi(u<=b}Nih^y6t66k~vhRWKr4 z)pQ$-ym`{aa?YR_W_;Mt6x96Oe2{PQ8PH#_<RyH810+&l?m&2>__^$uhbInXw;$Wh z;;f+{=#sQO0XY#o>BgRT>aMAYY)VmYR1d8hK-@AA9UcQ7g^z_jxI5XVOuq;VI6)+$ z{GxZebXNGPwh?{#^$iiNwrTIuOt(QDgfADsMOfUZhLe1d3JGJl`=p=nh4}L$6QOg2 z(CTBtDv-n$uY@yWN`&AF0q%x8d(dEK5)fn+P!A}45_V%`wRbGEY2TGOWS<i*2hpVW z5B<XNp9=*&%amW|Y<q68rZ*wL***ZNv%NNP@PP<O8U8wA2z?jtMRweM{VpbsqWn@n zN{P6rJxgT7YPdjhGz$FT2yuK3q=&u^i;!bpFXvH)eO*4axM2also&sIyi$ST;D;tx z?&vwPOcCPjNSh+xQbqP(Ky-X+L1xI<&cb1A6J)Mk@0fWZTDqotdMD?<rods5eb#bG zOmH<J9>&uGzs}%)CNg#ZfA0#Xb~W}2ear8Tvx&MNddB)`&Lh>#r}4_|$Yy(LZSzB} zj?{|ORUYwb3J*r*Hl5uv={LBT!dhKawQcs}o(9{%{VIVS$2SWvZ=$^c4Of@$AK@%L zu&jfmjYwv3sa9?X*1rFim41T^vB%8?qb+SGbW2Z{vq<2xQGoF=Md6PHO3lGt5QFt$ z>@^hLXbq>g*#E^QXG4JruaNP@;FndLPnCOS5y}78D0=LN$|*OWseIdu1mSe4V<UK5 zdR|sMRIVydpl7z2!k!T|RnI`>23-TMxJubq6zYob2RgmoD_wYUU$j`KkMPnLh>QW# zdS)YNy6UnP&{V^G!nBM7WrQ|sB@D&`6F2OSe0$n*2BLDbe9y9#lh7OJ%mg3_2SXJv zh=G5g*cdpat&Ns0g-y`k!t4c&{bWCPRngJKg}&*ZmUN<{@NM_3U7hkve^&o#QhVhC zf0dgsy}jr8<kbBtJBKXrIn-4A04>`JSz~Pv&BH?UH6VGm>qL(*U*TAdB`1&ufCyr+ zv+-XS(?{wRmT)V(2u22KL$$NktOEHH3g5Cy<bpXC;sDq^XKd@Y@zp%jnIr`V^Ol&I z5*CJPOk&vi1YCpX0yM5M1RiXUEyc_Jf0<nGAy7^!j);#DwKwO>Pc2ik>&p{SgKSM* zZYQ_qzMm?zc~ea${rBR`cdcPSRQpwU(DmCw-~_6B;(aiAF?OQNkel(z7Nfa_nZz42 zR*{-oh`WlmyJ#;gkufmf!uxpi6>SesL?E3%#C?lsbv%KBbn|xYr2gI>t;n2;`_a|< zIw4pcU^1y!2Y^yABOs%g;gf)e2b`Z8oaMSa3uSIfzG=@=v*Y6Ad%RCy@(_M^nXNyr z$T}xETAN9$yF&}uNMXvD3J;}qhx)%|+wj6TSTFrGUSEAU$UAG$4F(b*a1)}<;k|wf z2tO?^Un@Q8R|2n1-kTU4`I=f1(ZCb1i|2DyOk-^|jThXvKsmLnWf2$?nc@q{Jhq-f z*JrRkWQ+$S%W*K#S}`D}2`Y#o6a0J(Ur`rYr4NkaNEVy(i3SdxO_Mmywhv|_OY(1V z+~M>ziDN<5l^&tOKVZr3Qr~F;pi;)=0_>jJYGSdp@2A9*;GnQzNXxoA7+mo-H}z?6 zy6Wf5sV<@Eo#RtTp_Vxe5DlVmkQDU)&EOZiHa6Ikx^dGUR!D_8Clb53Cr}YMLeFHl zlkf~i;~wSGt-!*YL1uQi4<ey+BBwt+3=E^b?UgmQZwC^|1XP1|Fy)T8W95$myBEiD zkVnP?U^u*FVgTfPt0x61Q80w<L@0q$do{<(*u&}UwG*&)ND|fYjGA%U`$(Jo%#!2O zP1v7CHeZF3wW#s4&Mh!#%XpM%noD2S;C1-+re0w>Y@RWWX^@NkB47hSSE*Z3QKuN$ zT!v%RZi9j@K6sFOUhn^TX^2*8>HChBBe1Z6b?R)kP2;s1e6y+J@?3c=-e|IRm5KHS z&S|R+2nLy$W(<-zd*Qt}I+2b$H}vpA2rO}o2fW!6{In8&`X$KQ)DCTB7H<$YIBuK4 zuKy5@pqG4q*2gJV&CZ8|2wAwPEViTapAz>Fl<kFm0GIp*GY+tESrYhg)b}VqzFq?q zgN+lvMGrtcgN4IbSEOcvJcJ10UTcLkxMrMcZB>>I<uc#}{89q=1NV&tm<0qMf>lvd zv(hE{;}#@GXTciGLOe?70H_7$P0Vao!D3W0c+$i6G`<MC(U`M3G<*fI48-z=QyFl# z7BvT}Tsxk$SgfnB6V&xqgKPA==J$hkE`9$kKMD+b5n#|WajcOEdIMXfl^K-#2ur_) zcZgJ<Sk=}7rq6mBujbE>`@Y&H>~vnTA&${FmN;N2t4bH1hEb5P5w$lcp`tIqLxs?M z&&%7hdz1mZ+_%%Uz;Y%e%HrO{3jc4mM=5ZO7O)p!{TREuILRSo!*e80t@LF-+o+I< z1?lEc4%JNyS%~OZODj^|aa&9ye^j6DpJV5As%1jFYMuY-+{CFz3r=5@WdwYw$OXd$ zN2f1OkDEr0Kxh3{nO%o{0R?{?ta?Gy!@#U&vif^WtqMXd;ep;?;sb5YpU9#Mhv5#* zAlwzZxvLaAlCUA#$DWcH<{IbW1A->JJPS-evBA(17J~+&kj6~`kHK}+rVRQ2tH`>L z#Ns>vtW!Du+2dHL9Zqq$8dw=ILy`*Y)$c8#3kTTC8C*`bYfQqo7KuqZ-1CzBmS^s` zO^~wb-G8uA+}G9I@P=Q(xHrPD70&GI5*M9~PfmIuwC;Fcwrwj{I5S;bld;gV>aWBo zN!l1G5Z8mXdA?hDCQMYZ6Vd)c*YICwTm`q--{4XOdzHZN#_@4Z9r3D=uy7ZUOt3BZ zLBcJz&G+UF6NH|}ZmYN<W3{y6a4`TB0I--|Lgx=-q_$5rdK)FI*gK~s+zwkt##vLH zrb_eZ0%S5OIKUynlCiTKhxJn27+lOvIEVrtBA-ytOYzF1UrgP@WsF<jms!a+py{{S zC8bX8F0zDzT>-OyjJqrSrK)3m?zGP22`#Yc%md{0vAJf`#huCDFJPdJR|EF1NqzpL zOJ^4FP+}%yz9?%S!ej<=d!R+U>G|>A4+`G3&E8$Ff}xH84dK89CfI*<Y3$z`8?-z| z7zYqo_#-@Kf<R$rADvpOU(617X-)}S3_A-j(}=-LzyrhgOz47>Zuf91*jdX#fe(YR zmhE6!oPt1hcYpfwGb_PJbLA8Fy<aLny_`1sgeR4{H=}g*%uIA`TlL4;8S($H7J=u? z)yrhBOREV!hUGU6j{F-h%NpRaFXLV;e&)Gw3s6kwWB?B`5*Vi#;Ua-=g(@Z|^Yq`% zS>ztOO|6mN<yCy`JV?a12^Z=JjO+<21;2U^+4=IkIuQ9VZD#=4M|X2e1W6o-nB^rU zD`5}_Amlei|5h5PLjrTQ=HO0u;OcQU1?B##)0x=g>mYFQ{5aT-2c87jpK%=C2mCs) zO2^JxT4wsn8oMSHL}rey`NSg5={FN6^MibOrAvvNGrSwDX?TTs-YPish6@thyjdFi zMb?E_SSizT6TZ*{-vprpEfdR<ZmyE(>QDH{b~@%FAPWh!`8+#;PPfDK?eEvg0-!NF z=zNHsA;%a(4u=ReAG!N2gT#4K_t{rAu9I7fE~eNtpY0=CU<EC*!gscP!y_6EVN4+a zKc-NY*CV{JJ*LnZWU4yhvFD6Jm(YseVtmso3b2{A;%WrE^B`c+8_wBYYZJ%8JS4I` zTocpDJqHAC5E8u9D)W1?*t@R3t}<syQ62|Z=Xds~NG}6-bA1I7Ru(YZED)phD_WH_ zCJcw2!1O2(k@UvaKKxPzvEuu%y9)LM2VWM6>l;_(wTybO!w}PW9JGwJF<QGU<}~9z zeQri7gOk{!J5g=&D(p5pv>YBiy}l_!SR8B*?=U6v<Gx!5!KsVa)(4R3aW?I_)Xmj7 z+9M(aMfWU<3Qf&7D(Zw_hdV6$Y7s~3aF`=_0BMb-mI<Q4I3_PCp<y5}MLe?@{C<Ei z-|6lTr7YgxRJGyQ98;-ljjZoaa$PGUU#Yy8Pq7|ZGa2_A@LYR>&t-kRmm^pi9G+YR z<^Uams4{R1PCF_=Q~<I#?#G)QYz;UyIklI|pB&8Q2nqx`U~zZ1?T*8T4e@?wc;q4* z;ikZ=`hc$8wlYk>!f;OlZ9Pm2XrBa*$CQw3uYFN+0t=4?=WF?d`&}Q0&$yOHOJ~%q zDERB^MG4q4y#3u<Wfuy~Ltzhjq3hb!LmhJ)bWd+^#Va46@sy`21NdA43lE4m_;eWH zayS#Fwo#rrENIXV(&4OU<r!SU;edbun}e$^dhb^5xl^9P;5_gk2n%9hzGjIg-EM4{ z1KL8X^1J06f?lIrTLv_k#~=j47SKSwX{?p&)E?Z19>_+#z9fCxNTizN;VvmYn1Nog zk8+@{Fs5Ati=JT3#vcg)UL5l-{74y%llUtM4_>lOXRGnkKc8}P<Hkrbvf?2FgHVO_ zrJuW`w&AN<%~_m9P765`s^U9=`NoJHg<#Sy_|s&T^a~PTJm?oJ&jy&z%E=N2E*Rj) z7e0L7oR5>xK9OM!lE$JyLnF{&Bo8)y!MDDX*44#9G5?Tu+Uc_Xz2S)t)>lv2T(1ES zC#w8TzMs!FZCm8^*C*VEncM%le7L+*Lh|v>u)TMks`1Cgu*6*i>avGV6m0hAFtG-N z<-qs~xx2D{F=qiE7Ll#kJaNi6q=4~;@qsLmrsQ5EIxG;@3}o32L`lr(x-gu`zW01{ zwQbG*hxnyAf~l`55bPisP~rd<+eEqzlFwhZcVuEg$O9*I>j<X*SrB&q(L>lg03d*K zVa|jt_P}16h}%irPRySsEC_(LhX;Ok8h%MrKYlU{9w8_kEIDqu?tzl#ppgXl^Ti#) z<|iospM#JyS~oW{R27^3b})_Km49EJ*9kUFLK9$Qb<?%7j%aMY2Z2{Qf9{JKE%nDu zDr?K69~DFujD0A~jN=6g97_`qT&iu!1QY@e3DeWQf&OwjeBB=YPWTiEUiuRu!otjm zt&h4rwvgNu(N45IVGTff4d{ooJT0Sh1{I8cZYYOCb>CPP)sZe?G5g^P2K;0>j^sdd zc<gg|!zm3ny{$bwTO%*!@h+ye$*(1766VT2*8T($*((4C5a71(Mk^3pVkElVIJyX* z7bo>y=|jr2eE_$OzxAwYhf{qi>o2gl8UXFYJGRaN=~6(GtPz7Pd<owCm720~);^VD z5;G$5KmqSVHh*lJe9z0LiFmw*vtZZcaZkxugz<PzAT?+^7GHr01j2(kZ@y$7A_T|0 zNWXV$1eYP7H|W)la4`PUo<N&Z+HsCwKoRUD)k#1T7c=WL{M$Sa?Em>64D@IWKo3iN zWq=TqVB?^}=3_H(ng_6{a0pgfUI|i0TMR__^mbA5710F-mPV%sLOusYK;sbsuZDxZ z^j%x4MH|Z<-oN7ODQmq?RnxFH$~(&+&f~{}KhMORK_gI(2La&S14~@x^<@b;EXZ&| z!DiI(=Ti3>U#)4!1Uap<!OSe??*E)2|0{!QY5{gdh>@V=CmT>VtvHSSx;;9o@CfkW zlfd`w;&}-}GAQbJiXR-H0u}^0=L3V`PdLAelo<(hzrBfnqN-;Xu*XN3FdCjPz-30N z3}ji<m!HC$%Q6z=1(=GiaX(gc;89MPaCv)FkFXSo0@*s^;22L4(y$3~?N(G&VV`h2 zxB7~iwWG7nwUq|LGKFbvRFqaifNj&+K~0x(q%HzmZ!$}wJAn5}>T4Fk(pquta<Ew& zawClnfbz1nQ$pAVzHU&g#bO#ZY~3A&M6lDs4hhi~(#$IZpN;GOv0gDo@PG-b5U<k{ zg|7q683ip-K8)#-dJ}|E!3k8|g9NfeIClQ3#@aTjbhs!%SP&34hoLRzyz39plX$?^ zw~gyNfcN<RCV)2wz?;nYt!A*zXb0@|OOINlB7Fr4u?gi3bT#LtWY&4oFwh+a*9;*8 z3^_er!idCQTeBQlf{P*eh~+N>p_Jj{<W~kR$$yEh8K1SoJTyX>{_9^q)e?39dw7g^ zO_8&V)9P8inA#hrvl@aYQdDW|hQ<b7zH9prk4CUZF}PPsoO4rqlz$pHEqEO4j#Ngx z&-2tbJU$SE&;)O{JDi>jjz`!VVr2+lN}M#HkHFG}T#H|icc6owfeB6>fxa>U&NQJ| zNbAlFgXjS0I|*+$J_TnRwHN-u-*O^3a(I?x0W*LLF(ErB$tSdIF*gQ#F6hhO@XC2} zb=4K@M`qjW4#%-ddDDy5?m+P1@c=NvEp1*j*8kipn^zg9dlRrZw_04s!!o9TPT}M| zVThwMayWkDEm+L1J9d}Q2)6}pQ~U`KIDv#Kyv}S~%*$Bdm31l#vEVu(e9b4uKf}nM zzB6t7UniE;$*;jL6$)(|Xwv8_1H6Xm9(-#Cn3_BUEJ4Mg&|O{WAw68;2Ru4E++O~q zxO-W$R;T6&77kbvqoFhZ`o3&+M*{6iGGKXdI(NT_7}z<;;fEtqMB_B(4JtU`%LEDu zRc=eLWq}vjtAQ4MNg3_hZlc{2Oj20Q65$h&D7$w}4RvYK?4STI-&cBO-gPT_-_%?a zQ|O}kHJlxG4hv;e4#V`boj8=z_sP;b-!T5{)c^bS%S7z;h1_0lyV=e?)yY#6{@L+x z3xNA{p2UfZDC>SkxES)N05?#&8T_BDQbR9*jUl)|41eIX3tKUx_+3LSw$ovP1z@ED z9V2PiW-W8!LtyFxB`n~BjK=q3h4TckKAkI<L*{VMs@mAlrr8VUGG(VyT(DnJeX-P{ z`xG3^J?u9a8-}-mh!gVN_Qh@T@_mNIEEZg8(t|5B(eNaA9+ei_G##Ff*R$ZQ0LUBS zizF;by&89U2}24X2!D4nj`~p4N=B>25p+4E@ctMP<)I|5xlV__4d4LtAa)jluTKCb zWQsS>gkEF$Btt|8D&PW4P0Xlc=Gtt&kc7J5sD|l0tk+jfy;wg+xXv*vC_?7;V)ZkF zUpO(SGb{?;UwluA+~<wBLB&9X+NNv4_pr2qMXTN@^%W^#@N^&-Ek}zQrgK+wXjeQQ z@-2YnSzJu^@cY7wA5`)odMxG%03Zt4lWEB%voOGnI(`>ee{A*SzbvZ8ZXU2WsH6!Z z+A_Js3l5@$1jphWfeD9bBoO%GV@R#P9wtC2Dq1^71h@AhGg!``3U=UQ?p;GG!;>cd zw%Im5Zp5fR96SI#`j`@M5X|ch0Tohs>q*r;yt)X_2Ze^fTV3Mf488-%c36JxDUIyR zKy5WP+cF930MoEgok$Z-+X7IYhB$V)6hN17O9LL8;1l+dRTJ&F?WG*>F=*9%jwJAt z!5@4P3dWlh%zk!!fiBecXnby4-<3Uue^{HcC_J0J@++rebtvQty2Egg91Y78o}TYm zEH&!+B>>f|ThXCToC6yju+dq=#cpVTW(Ge4Z+^M-EaeN`A}aj0#e?mMXMp*@?Mn~} zzac}j+NE^?`wcXpmEJ%M5Dp-dSRf2+uc3k$z{H)3<&yblB}TsMU^CRuokZ1GpkQYC z)LeU@0FSB-Sq>svVwhsC`*k_Ly<!m7u!L}hvmdxoWez3;v_<Ps;p4S+EAaV>hoIl| zrFTRqkKr;-hXBK4watsC`yaxOGz~1p!0;WOf_>L^Vm#MwM>tcS#e3b|{u2p~K}<&q z93?s`9&qqZqqp3EJ+$CUcG;dmVqFF=MPP7efGv#Z9<XmyS_3}f{z+f_^}{F3$zNBI z8OuO*<JyMy#J67M$zi@+M3I2{Ft)*zH6`XGaW(NRFMB>EHO`G6RybYz4h3O~K^7W> zml1zi7ihhlpqRm0*o25@z}DEG5ZUqi2Vn}JGkjs(LqLk)(O2Mbq6$HjfW^}1llNf* z4KM^Dh9zW^;TF>(NCm2lZiplJ5P(fhngYI6v+jITwm_Guz2f0%DDb)(td9i+wqVme zM-X%z4_yKSi%qnOn|JXL3kyH}=&(!$*#H~~iM*a{;OcK(G8-(#xzu^su0UaKhK2Ar zH|%+D@t@eGQrjVLSHKL8liI^&&~Z3!2^=eU66142oTm|Eo>l?Ii1^P0O~;g&DFJZ| z9tMMe_=e#eLsl`SZVK>^E7#Z_4U#XwLp$kq6r-!f@Lx|fn&G#uTqI@-V(D<=Egj^p zu%?wB?%FDIf3dL>evwc+BRg5AfnNqIpOLb8Az+E1b)bXPwqAo55hb+})i|PWkQN}2 z0|FyU22sP(6AJ%ewY_C3rQ!>5Z|M7p!wkT40?7vaF)X5KOhCtgxmt4ZHApBBsB|x) z%N<H5KEFwG?OKQ%KWif2ozvkHQbU3@SS=+#1fy2DV|K-0Iw~p+EVA9FItyKOzZ51W zXLa5I#dTRUuQI{gi$p$XY)tn8yx_E^H1ca}ks$@}E<3WJ1BpC@;0XwaXv2raKm|59 z&%kl*IuOYm5C~8(1`e9h<{Dh!IJ5Y{B6EvD=|I%V@!XWuXD&cM%!M2j;6EMEID$Fu zz}79;L>q0+;$`;s4puu)5NCUW;i~zn{Dy8Xw!TMA(~3dd1PuCUD(f2Oc=Pr|c&EJ5 zO_Y|sa3OX=2jvRha`chY(UMsWw7vt@k<IGl+d}|MV2SZzki-&zfp8L}hXN?E23f{G zI~dRNxaK`ug#lQ@$M3Gy^!b|jo%!(qn;-7NswT2n@4xDerI*F{hYguo`(X#n<*Gqz z5ct$_|HHDgi~qThZ-fs;jL0WDdk6eBn2JH-uP4LSKp(u{76W;6viTa8Ef>u`CDL|N zTVivDU4$%$ABzMy!s2IwX9K<m8DL@pYl=V+Oql_|qX80fe1`F#l-vljvd3^Hs+Ax7 z7Q+{3@q>|7X11Bw&I#)cYE*<<!=xXhR5z;285N9*4^C}`QBfdB7oLq74Vx7_=l<cq z`6%sr7;NkS$B6HW)PKTDfbh96kgqZtjb1cAwdZFW7B<(tYdc*_3_=OO!8@8}VNysK zNCALFBKOM}Nm9CZkpxEF1fq+=!|D4214s<d5LkDb1kY;t`EeWAr;1$R2aixS9~%^w zeE~k-ipOyHDRvOXdm8KTmoSxemIus3JAoZJz$aXyt4BBlJ^(mR#yNJd*bx<5GQV}s zKC`f4Mq)t8<+IV_Z@@34fQ|_O>p%Boxj)|kdo?sf?3vIfh;AjIcf#RtzAtYBFY_ZL zSg>dgBLXTCP|rM+;Gr0Z=?@@VWl;}H0n1<vfLXgai)M$w0bN5VqU$1<E)#)aT?S68 z;#<*&CT1#qTpxj7LIL^x=$03)aU}kuI)!--yh+042<1P}=!N<bLthO(1jO;zrjYcF zF!-gp0N5CsejiT3EZ~BkHt?Ml8ppr0`PHH%j1AjFc@Qy#??#K3r`P`|g_ninPP9kB z00M3ltT6c?9?oeA@rEb<!4{Yf!*`*PFCLzyY#3}F^ubSt8zYBjVG_V|;Z;8dE7f3U z_8dAi@N-fIDh>r~)&>8r=kO~NMc1qOO@@k&`fRQZFoplnln0On1L&KB6lKC4@Ko@T z(6yXQpBNQJz(D*RbK9@iE>gia)6x(}kjN5ej28L8&p#b3_%AFdbLD?W94><y5e>|+ z7QC(ucBZV7?Vn5bGzkRC$(bnuh*CsbsPM`F|Nf*VW(5(9mhdDj0Deq%5GMl`%YhA; zU=I%XO{}o3NHdN71}Z@tR6>BqgQ8aDA&`iVKq4-<jGtQfr>jmr7nT?zWELoWBdD)x ztO~2b1o$BW9Cxc+I9Q^G_cG=95*(V)kY&P}e6w+@aPNP?({BKMfrSFt;|UE?v%ixJ zNCz_3E+r@Cz^$OA66IggI2J5f&&fOjo=f{tF$Z8dLBfn=z#a6#NE!&!!bb*$;hvX6 zY=3;bztC+l=?tV$B$=Pu2zDqR23zG;HCBTTF>D;62`W$xnOD*-%@tKUaF4)XIBCLu z3J9^^u(*H+LIgC`gaa?qKH~i11is34+EQ2nUk5w3_?OUbEh@O{ToTQf!z)thB_;5Q zD0@3MhUW+JiAV><{Q&m~ike-(6l$B~v{!t2v)UkG5H(5%xEEF5@#r8|1O4IC@-pQu z;#^4jGUf^%;E@0rFcEOYr7q3e2Y$_`Oc4oOY{zl%IpF<RLsmerZ3e3Cn95Gry2ZxH zH5%S{rsQuD6=cGF;b$KlHghaV;60UFyYyyLoC$xfPa@zHK3EcGH(`N*HC&#H@atn% z_)lyTiwmKl0K?FJ!RH!=#3~7!FH?ruTCTQru&qz<wkae{{P>cKjDvdkZ=g{YQV67i zV3jPk^vl?)1o|Y&0kb5`N5}CW$_I>ZTAt+#iD0DOG2!rfaj;JWy!i&{Vg_64e1e`b z>-0ZCL*;>kc}b9*(bfY*Z0b-!4G$l@IUhHxZ5nVe3DB4d>d0wW9cKADXP}Rfc>td@ z5`y^ye!O`~s>cr4YB=~okx2T+RxkP?FoJI$_xxr>ss4sqP5_Dnz-=d8tac5pcqw(? z%xB@;TTVnI`sgbWWE{xxQ~zf&@PbRT7cne39kyWY(4TIzR|fW?-7bdXTzFBSt!ar5 zO%rM*V<G~b6@LrCb6m`52`~xHVfL!QNiFy=pX#E<uFiP#`rf5*T&mtIJ%EPK`n$=W z!rk<w{Gp-i3Ou}t4v{?o%H!F1@IybR)nB`C5jesru+tnq3w$UOP$J-8!UQIcxgB`j z6rU()Ay`d2Y^y?r+LnovESRUlud$>95?Yhb%p$8Ao0GLL3fel7dvMw+xSzmm5-52A zh6p^$@Bp?Pc;pd)cy{1k5H-x=h-=WUabI-d?XURfz2>`KW=kP+SZnxq(7^;=5oylf z<t#qaQn`jL$@WkMK$flJ%1D-%3WEj+JUYO41holKJ_~JLWcYC^JhPVG#m7_;fRlZ+ zCMi(j_$(k8MDV-9ieLbYMPtB42(x8_Jwq@kJdlqHhhIi~h#3NyR0n`HGEZ0pTlrCy zQ!-+tzVOowtgep1)$#b<H|Djq<A;>xpNem>g@{%f>#^`0T51s&mKTjzc>t`~+t(Vc zYgjO^Uj5!~H;c8)AKbuvLZsvnV(x&nzyt(@$<#l?R<Ro;el%3jf-vR^_ZVEo3@Cw# zz`M&q+jG%4(6o{m9=(BF%zsTt+7+km6)@w$01O2ZgCX&uf!4I>btWn`1uOi+KqRJa zR%Vnai{Qq@J@m9H1S1V<?}Jd+p>7bcUlkjV@voNsFclPn6sY62uKho}RY;)n0rg@$ zgPYO8XlM_XEkI4<cB1;mR;8{0pSkW93<smJyaeQ3Dqvn<2{M`mt^h}G*nI)>smUNG z2cBw4Al5gr;sHN*;{rbpAk?<VvD^Tb{w@$9`rY53_x*G)2#oQZVbMSw?>S)QgX5 zA#458E$}V?deJMo5Df0|Rh@+{zv}$zbm!3i|Gut1Hj3kl&))fNO@Z?P77mV~D=_T| z0s&HFFkgEWv=QPDyO1h~)S$Xx3)&Je4#l8!IsfB+AgqR#eDJYNQVENsc1hBP)|jhA z6^91fYCr^;I;X^7Tc+SzV3`Jz{(f(Ek28Th>27!DV|V7gH*aR%ym=EXS&^ll8n=%w z{<s7dD?a<0Eyz&Or{pdAPj?&96=2@1()kSs3f}yTV-*6A;G$B#8=Nh*z?I@qetMuR zUau^OS+cZ?7)O~7mi)&!lna<vMuOkFXHOBsJTzT)B-YR?LzC+E<3pJFIM|ZltF`<D z{xwo|c_`QhraUn)Wq(;qhpz&bVkrfC%PX)`o|IwvrXcLk>vcR7$8lkrz5O)G2<AA} zhsMRijNpystSXf-YSs&9ahmD#*4(YO_x(rP7Ijn6NK}vxnilL5^e6%UXWP(biemo0 z36=HN9tXP-xqM@(797+qR#i!4CPwcmFeE_#MPa!1p_~x3ZQisWQi44MMpeYG4)q+Q zeUzSSEw%kJp<2ODf=BLNYTplMD`__g+%GyW;LNB)LPDs#YH%8^P;vCn*oVP|jfeC^ z3ndg{Emtex(|C8`K<(iR9p6L>g61->nc#Cko8EAWI9tWx6$;XzV)bb&sf^fs&$x2J z33zEwh*}dPXj<1HwH9O$9(fL)?t>kps3C}VLP`4jT<9F_`{M6C7TlF#b^swa`Y%=( z9lq=|>~ImBtiVdU^Ua`6&*e8vh#WkTDNrDTo!&S+Z_OKc?RD4Hk%?nEJ>?*PJ;}?L zTe0@#wtEo@?k`r!vT_sXDd-0>P<3<*WC|7KglcX>(zZ+1#^bi*;(W{^9&0UA%LUl4 zpzBnS1TWeul=5GUtC_yvdT~*_?}d7mRr*yZP%B{pu=tc|VNQ%A4to!Be4q!jbi4!g zBlh%zTL4%`#G%MxM_P`@$Eu?0tyeku;xYBpOW)N!h~FIqEaf6&b^v>c*2so293`Cw zE{BRd^jQHIK=bz&@k;EKVE=<~k(QI3VgL=j1%WP{YC*qOP(x*peG(G$S*22}v+#o; z<xcwb>6>8V@zzBSH7&7p*q3jxqVkbvK4)}ZXiRd-#s0lb1`?gssYgH|fTuGKQG>0? zAi-7Vuh9Q<{<%A`erQY_S3)PN$li`(Zy`2d(E7jZ<1^;WpPcrKvL_)Y-k)^)$nUy) z@GLMiFMuILYN~KGGz_U|ekgbXXpqR<=tO(7UFMH}prlZOaQXJgzevmRvyoJ`OYdS2 zg#dhQd(4nmbYRM_yV#Ki-M|)_6LfBM%DpjA$>xfovD;DHaW>vXhS5M9!dBc)uG)=l zUS0$CBhkjo%VdjEi@)0^lIWRO`#Qw;!W+w8<VdZH>ZY&40@l?Z1Kw-QI8xgf${Y^W z<M>#=QV~0l@ZE!>ks^%-&8@7{p)F0{NkZ)C5I;Wi3Nlyhx@P`P&%T$`+zGy|BF?m; zs;MV4abPqYq2*}IicNJizeBI)N#4lr_Q!F|1>EWET2n23ekk(`;cD(bcqi<I@g%mk zLaY*Jhi)G-XW|S=HYYgQIq%5^vRQ_p6n3D>VSMc}upA(&)Zl2)%3~aa6zsLBOTJ$h zC8>i0Fy?q?*xZI)Rv8>DaT$Mjsd=>XNLgJscopUO^UlY{)r{I{{jp|fU24(|5&%GF zn_?cXxPlK>U^hr<h6{}b5oml^e693duw9x=NI=^eyy(Biet%j30lVwg=YMZ`lKG!# z9@<ghK(yw1V<s&l80E=GPA420X#Qgm-x#KuwOz&@!qx2orFLF@7BUh_IdMqJygsAI zy^L^{JbfzhEu?k5pf6vt(FPW^Z&<7ssf^vp^=VT_u}=vRi)abNrL4%|6{2!}<no=m zB<9~xlw3X5fzX)$mB6|rjw!wggOn>;s;E%-t$z5mS=Gu;A8<uxdXrPdR5oeCdbBbS zOX@=c;5G_Zfa4K@PC{uG@R$Z+#u=Uzhjk4-?`Fr$=7AUwgbiGFdJkk2reg8TS1v7$ zV|48SjpXYwlTNpOO>&8i+n{<|@VAGWGdf1ZxJE~@Y4_spiN+rtG0tA6LRuidZI-$A z7gD#Bg-KGwM-g1+za05Z!U4iqTvq`=1^g_f*C*Ace&-xE9i>pZdevJH3e`*B4X#5i z0cKP#Bns<|?*mslN+O==DyjJsCkh@`b?TA-ctyCV;l-RKr*4OBFDlQ$?(oWz70AbG zGdCIE1CkxCkf%zIIDkoJrT<AI{z?O!>0r<F951bRdPaSvJR5vlRoBn0BxZ6ioeJZk zTXTri#)n91Av?7y$K&-#4uFOolLwX}-S(yCSfWG4*$7G66fSCyjG=fJX*vA70a`q) z>V|=Q;p)aWdKY*8`$D?v`7dE(0}OSL4O1I=wO>2DG;YHh*}_2$b!aYYn@j&ymH+_> z2F&FfH{J<O^ex<EALP;X@X%K%6=NdJH~VBA7_`w+Q&^d?WJ3=FIA-MYy+<vC?Z7Xm zUV0f6COxw<&XC=anipH-Cd+D<6yskYaCNZu0+#3O`=o&%&npagv7vuSOZ#8Wn3j&f za_Rgw&5w{hvR_bPUYrKl8bGdHe{RQj=ip|?xzZ*yEHt@G7zi)3aiTODqX32wJr_T= z`t<S#iw07$isid*w32nYVnrQk>LUv(BeYjG+&cV<YAqXvOaKe&oDpLNGQK|6gC`n; zO30eW!73#La}c~{|1k1{z$+n}KNvPA@1DKaku2bc6srdxRjjfLFX>*mT*S9+cJK&i z{FsC%QF#}Y&zXXwPzrf4Os%DpW2p-MFE$ktF$8o{HaXk)=jsEH2-C6qKr~1!um+=p zT(2-$p8X#<!82_HXN3l{+OJLQxe0-QO$Zj{s`M|C<rAF|rNl6u;g0<Am3#05z^~lR zPuEwDrGR-51OhI^6i5GCoedz3hVUOkC^oQ0W3`aC%IZhb)j1+3tZrhrWxR1=@<v={ zcbkj;=8tyZ@AGY}O^r}u2xVahBe}NZ4MghMr1D(+5wd|zWjf{S?gqc!jb|Xr#(*cO zoTtYm98eh42cB6d!Z!Jrw&1b9QOO{0Sc00E>%V_;AjcN5>Lt#+jOky^HTQnlwE7kY z5^cmA;;1*IUK}nl+5ATU;yCXsxV5lmjH6W3qu_mTYTNY=AVC1`$*aW)%L4uE^>W;^ zk%-}-%l60PjtailTD)lp7UB-7jUV}&zjIU|CitxAAiOz*&M$Wokg*wr1qDH3oqT~K zX#xXiA2ygqS_0%F$b}|T!btigxmErHr{lpWn0^9>Oni1aO1Bg~&z^71vs#(=MC}GO zqYixaOJ<(xFieAmAj?%e!6^ju?_qv>W9d(i&2w}-4*G5W9~Pzh3LT{KKOMj=riY+1 z?Mi1Z9LN^d?891x)+0-1?7V?H13AZ%&qi`HDyN_~8V?l#JrbdAq`y>8cY8n(>drvc zozdw4JXPQ9Kj_><c&_3YaRkgt$wt7zNPc?zsqwSXXkf6rWx}z^QW#eV2Vn5HJe?P3 zj)-$}*(|~ya85c3;%r-`3~XWu!_UF8qIPkNS6V7K<^9{{9O(B~b^I6!eBKWjpSI53 zIqbC804s#i*8KP7W`d(eZLpMc-j!BQ(&J~TZpOx-P6OG26B`()w2*HY=Z69#xjC(r zfo4iQv&(E;3hbcnnL`5PR@;ZZP`6EQ2~RcUJ4(6J2c}tw3a;hU7cX5y{Acv~+KsiM z3t2Ux%=iG29^}7Q|D2=L3>41=nZL&Kcw!#aars7bunrP>yKeNPk`#L%iV)@-Fq460 a?^qf7V6<g?8|zI_#z}Y2A^?mpF8v?7>nITb diff --git a/pandora_console/images/backgrounds/background_pandora_console_keys_2.jpg b/pandora_console/images/backgrounds/background_pandora_console_keys_2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b919de4ed88d645717287f90111f51cde3d44de3 GIT binary patch literal 44092 zcmb?^2|!dwwrJg6k)?wxieT<D8hIHNkszyZd!oMhG=kAAxByWEA_|5EWfLy+oBth` zNHn9OEO(NO(YRnlWl)69`%zJWW}<?K5k}dxK@bE%wtuQ_chf+l$$N8@y0x6Dd+)iY zPMtb+s=EJf|3A^hh0&h}A+&h$JIDkLKz}0|y&!6RXbhr|2(n!e>i?(ki;&33EpGPq zVT#$G1%|KNFnfLYX8Y*Rw%9w&o@0+ZyrQ>!wmx)2B)x7!@aJLkr#4?Im`Z;hIDhIV zP9MzqV9R?OLOy>#He$ny*kvo%$A+$V4V>!bNqa=QMQ`4+c|+u9boAy;VG6hC`BO>b zZV<=W_ETws5*a#wsvO^y{`3PM`n~Xo4Ybp2$64#=I5^Pr=FN6^*J<87hne);ISzB} z=fMAYvmD-abDHNi*O}JBRJdD2V36B~3l?eb1*!Q{wJ)`8+qT);9A}3|1lv2fy1L>v z=FXi37_$^HVUeFj&k9q#rE6iq2F3b_&$mQ=9v(*H7C&1T9u+x%Dm*Fw3Y)il@PWQz zqtx2G8NV07Rz!ZdVc;>0Vk=h0Y}sJ{;RZ!`RK)rXfc}=QGSKeTH^PYUG;ZDzpTkG_ zY}119^--HQghei1Fn=nP%ntlK(9LzhyH1XC92P8mcka6m4htP!-&-)xb%Be^AK!DG z=k%`YA9ZaQt1EYrzc+W0v%{kI9Gsx;Jh{WWjtimoJZC2thd;h2*VSDdrilD3Z2bn^ zeLsi$YU|E<WnH)TA~t*$86L4RJbaUm1AIclBf}LT;alkUR?MUAKKN|?=V3VG-|+|H z-*>@=h|jlf2wW5qzL_QzcKh7O6U>?C0{r9r?i}a25Or{HnLAhh#|4hgjxO?r^XC51 zb*i>*;Qxeb_V6(Fm^}>GMVAFUh@*PuhlIZSYzTus69Jv0|0$9YmPdgq=!8^%CHgNU z6=Q%<YATgTP0dG1rK8McW@hGQX0p-d1V+m&M~@zDDH}iD%4+=hDHx{efs&e-$Sh>m zW5!t9T8*=^)ffEMNWTh=HW6v0r9x^n5{#yVqpAL%(dURFFd#z^B@l|FIMW~xzlOk) zWC{R;PzV9!jdl?J+Zg%s&!&DcckCZOOnU1p$M-~|ht-8!-9zS3K`>f48hN2kW^miO zlz>Hu<ya2VB!KIXr+}P)B~W=)fBHE5>jnIMe3(zsn<*o=Z#fPjA^&*D#FRX$QDgxN zLYWgl8Ga!F0@OhuWd<dGb3$Bg!?7b_3w>K9+{qmX(HMinfpMVi5E^&_28r=VF%-sG z;v9;BK!o76If(pgz+!Qi_~OIk&Yj;_tLub7C{t-!a^VlYRp<si{0<iV=-fx2k%t*x zXfy|ZBxH#w`LNP)gqeI8A1Gmbyl^?o;qYGp4?Kg%1*yNbv~}(M=+gxZb+SacV(0PA zUz>Ha%Tymsojd#<X7<#k=Aw@_y#D2cHTv54?cjU)F!~%4(dAMM`C1}zAI=smk!PK1 z{T9CWzXAj|Z&;LkzVKz?zrRo?jnz1{QM+7{apuN^b$<>In2~5=Ym__TJx{o|jsJAP z>mEX;M_@T0)Bqm`ccB3w-H1klWXRI?LWo%`U1hP<`^K(k)a)9m8%xjyKA)27{~~bO zOMkw|XUzkj@I<e7PKU7e2`<2^M&WFW)!D9(JPWvGD_{GL+6F{oU_m4nB$JoHnWiS> z9~Kt~K9~s(FjykrBk@ATo$lqwQ_;ngiI;kX6YjC32m(r_i~SF;_yv7|3)lZ;bfEao zD|?#XU9%1m@ZRe|$bl5HBVWo?M>IPmAkrP)4htY1D7gFWPn3!~GyY=T$(CH+7cHG1 zH%p#Tsw@9JSMk2mjrER&b9J{IRQL8Bwjk!E=wh#6n^7(uglsf1g&CI3_-KbGN)9~_ zzNt3pgGd6z=Y*gtbiX~}cI2TV!4qb^U)3+NZ69}GDq;*IEF9M6D>5vC=Zmu)dy;nD zRIT16KjLD}z5@AwTQmh;3Aj%SVu-?9@hSY|2zekWbzF1K*73>y8+%%rpl(M>?N=F3 zU%Al5qy5g%_lP`flep+WA|2HBFsc1utN2=-aC?r2)a&#qL7gh_cQ!XNI?RfO0Ly8I zO_ER8Qzv?e(3yEa8PmSH_CFTyR;><{I5q88x&HcuBi{~J{ar9KUErM(rqMj3-fph3 zx>nR8X{$P9-WzEV^y#RMT+V+(k8oaPjh^totL@*0tYuOj*@vM5Acngu$AUa!5xRW^ zI_34+MKvjAc`8Nug(?J}bYM6gPCmXR%2=lr@6Ta>ZI9n7bj;<dJU58$_ox)orTysG z+fj8s-sdyWB|=6g#}NCT2FDF7+#Z!FN<%fNwI8Ji@7Rsg|1z+_EomuhMQ#OYqM|_n z?+?8=Cd7IE)~@Bbf2K|sn)?T4P`fVq1hKdtfGrvrqWGNGgtFW_x%~)bejcxkQ3q4I z5(>tReVKG>S%i>Ow0O9!c41l9Gb%GbCCoRs=U9F4J0|e{@yhs@RsZ}bEUr~t+u7jy zB;p$*>ceYp{hDHyl-ujcK~z18C{0x0xygrmkKNx#ZKEBwA8aw-dRy06gDx`c8aXUS zn_=brwe|gsfN6KstW(w*?R&`n-j6=AX|EMYdJ`MX8Z+N<<pgTFD(ItChmWN7BzXo? znSX1R&wC4q@vj7$G-jrP3qzs^VNoVX0>L(6nNs1fuyg11`#p5=ony4NoGSHXs<rXo zaWSi`#(Xv*KKZ_{n>mY6_Q%nJo@8M{ZmXpE#%>zPGOaUj?AqNMzR)@Fa<XGT`cLJ* zxYx^)`R5h1Sh1$bC~`oefU*c65+7u9{Qoxg0(5(p<RB@3F%k;37=}e>BV}6#8bwIb ztElHR700jGM7jD9X&v=*UF^3Rc^r#C2TZspVGOJPZ{z%}#R4X5-OdOmsC3y5*04zq z5_l>p!0HrMJ>I0Z7?!^#PRUQ~DoNT)A8y58PY?IYXHbqO?B%ysG`Wvo^A$XUn0=h! z*z&{A#mDv(Ev{YU)ZYBxgKFrjzBYm%)hN(7SI{zHU1?-S!Cj}Knu%ro=#ROT|1hLJ z=pF%xfv+keZTP@M_4g=;Aoy&moiz28HIqBmB~T?BRgqV-6AN9Ndy`T~gW7;9FVE^J z4UVamKt`xdbD>*hhTWBpgp_ra@yUjWzcp?Og4a0konNS!pgg)=(Q47NaANscZxdI| z$I7AjXCMP6Mhw=%h|zN>0!bSmpK8S=aS8Gh$B$g6(nFg%g<jU|uZNrEVbjxll$j+V zPM2mjxUvK7%`E18Rg7;;tgK-2jW0ir;MnX!rxQm!$9*<{^E+aAzGfUKl09xhP-$ez zwAODEEhm+qWfYgrOWX$G&n(WT-Rl1lp5h&T;_)MuE15j-%6C$!%g7yiP$SwzREff| zgDc7D+|R}~7ry<y-CT>MRXb%z${k%~D?S!z`~w09s`<Lf_K%6bW7b&I$<~L5gBo$G z`~i%04}Q#aTI8g7C_FrXJ0#{76r{4xdj3Ok@vFvnd!4p9q&7|x#^1P18FQ^^Q9eDr zBO$5e>Fu!`Yk+Fg;GFsKIa$T?#eFJ`V_GM>dPd3@9o>$>v_~~D$l#9RV^HDs(eR1g z!cQJ&?tOP`YWZFohOoM%ll7=RTpi$Ck=v6rKe2G~*=5YSO1WWER9py+gue9&@=J~T zd*vlhs%X}*d{Er%fuQ(_;MWdbJs4D^P2_?7$yh$**}@+#oGD!#xN~|{!=#JH2B{4e zOE-41n#_gy@^a6UHIqBptCv&NH8$s)3)qNDWqGB6P#+HsGJ&84F2+E}8OgO+T3Kz? zw~Z}MYc<=mJ;bR|-N!lDgN*chJ84rtIvVGZ?7b$lNxo-$T(8`H5OMUaf$o1?Q)=IH zZd5;-FLa(ak|@+yfC)3A2U48D@HUW(W5gbUKr$k$L6n<$pi|QJxGbsCbGMp)>^NhG z_-qW!J=;9um0w=ISL(2t$2RL6+}z-lF?G<QXq6<}u}ix2!J|iouJz3w;*KuqoTw|^ z!5VpHmxjBPm-(rA@tRK2#hhZ%;O6)gb+WF(R-xH{V^`E}rE{eh%IuIQHuVUKA9nft zy(G`H{^X}SRK_X}<k<<5X?@Bbb&kw5h{cu%7+&<~d_-6|KSo_`Es1I@i7)-4ydOPJ zY?ZBgaK28-Hw>ENh~OqIB%1bM1el$Nd!9%L|5?<RTYjz3`O>C?o|O9W3CuK+AY{tx zn4sQmeeyj)HDmnzR2#dU<m})Uv?(fYeUrTM<wLtiSsU^#10dJ>aJI@VxWeh#N+(To z(fAuBQ)w-(vCAOAV#UTYZv03y92XQLtsQ2VH8HmRX-Pa`m3*p1KlA|`TCv01898TW zdW-l#jO1uv_Cuj>)jeOidc{HZ@ssktkhk08)GCMR`P8km^@m$!0jtAP7~}1Ti<+wE zzd7;7m)3Xg$WsW8?e>I{c%QY8vVZ*O`e@^|AXi+C*+kbX1TAmukQ(oufQ!dgITgSg zoTx!fYBdflJcwy^P~oc*)`!lGnpSS-bo}|{3~HO_ttP5)f}fxAXnmzuh%BP@xozAo zclnXV3`c4&&5qPi(-U>=f(}iKl7DlAnlx33rzG1`>kCh>8=;cfPjbtFB0uUGYM=+w zgJQgypHlfnPFRdC2x*-WON#{NJFSIF@EjXRjDw6dmM{GNgr+K!4qw&m!K^=6=vLR; zcC%)z)qy&tb@A749L+6V)2wkZPc~LnoA<o_k*UYa%lgU6S)f@zs(Q!8_vX(AFF4Qw zEFg?)*r89GO1%OuXR^yix(98~fLcj0)%K|Rd$}78{e*+cEd23CScrh75*sghb0vc_ zej8vFs<$M&Luwn!1@(r@vw~+hQHdJYN1)xdbAhjDWI~Men|}1o-ubQi=XQ_Hx<>5{ zBueSfn&Rp=EmwR)lZV7*Fdxc1<Ni|AJR+~#VKj;co5YFh)GSFX4W?PBry_a>=5~s~ zWZ~;i09>OGiC5o;f!*vGQ8y$thifDZLXqv7e&l>bvduM%4J0crlhs)(tzSO!j8|ry z%pp_AVJ*O|gHvKX{`paT{&L+%rf%J-v8tpBhau}<9=;C?rGhptZ-3#0zQIcUuxg-n zhQ&75e4Kw)=yn@yAPbg(VTgQaK;^Gka9oBICWjn>d61|MLs~Mfa<^L4-w98#FZUW- zm*kWl@6U!#tZkIe??>k`QFz$ee!b*aN$-IN-v2cbZebjx-<HQ^*geWErgd))eX7vu zsZ>W7T{SBD-=UB1z@}%K<e5#!bg=S&C8L3aJao=h@wj*A{gMcCO~nj0qO3`>fPob= zG0`Zr3rd(Td~hx%1?CMh8zJ`@2#hg<z1{4<oUbRmu&Oriwoix`bb}q>_(SC(=RNnU zs;w$A{M6%YRHO;tSuNtURukkFd;X@%J1B;8+{O8K`QM%1{zN!%k3lh6#;J%F>yG-? zKj<gMO;0jymuGJ7k{1oagn{5hMW@I>Fqk>Yvv!P%G-n6n8K$<tgg;wzQM%^kcdfF0 z?*n;g7fnToLk*%ZHxN{y5&<9&9x`C%jSLW8y04`z2C^AiS<G%4T0bL86f-KB#9N)6 zlBnb10nUl}?p<t+?C%AedP7_*ZmO7#Pw)5YhP}%l25n7hQYW61T2dQo8{DruPygX` zT$ShC9qLN|GvQOzSJ{sBnfHV#`a2Jb<Wp7FN7Qz%;cu=o*A`gRZ*ydeFJB(SgG7u9 zXnkEL$8K@onMoJV4dpu>2G}8R)FOC-^7Qr(h2KvTmDNaX<2JX*w%#N1)Lw;+6@a3} zlrosXFdZ>RVRi!;VRZG0d|5wc+l@U-(n}WDY^trM2{M=wzv$@d5&HM#wupbOk1z|~ zo>*;@6xdYlobhN)K?*QYT(<;>WL*$i%J5Y}9dls%AKH)RShs7MGEYfo)obJ_)bUF* zs1ziPY14F#G@+DapExZ0HKXWQ?a4KqO8WqYmpm>nWn}}+>hes@fM$&u)R7Y-ieVl# z)CIaAD8qZMPaSotP`0Y$h03+EipCaeB8oU1qX*Pc%zYr7LvZnk;O09!j@n)FK=`*@ z^))xMqNiJ9d~SDp*9krID&l<nHyy0gvWS@?IE9HSm;zHI$+Oe`)srs-wRUpF*Af)f z<`30P@^sC`hUpi`dJcaxNp{w$2DfIfO}!lSc&F#(Zsy5FmGbgW9)D@~kR9QH%Aynr zRHb`K{X4rgce-}C-oHDn=b6#=KaXpeOY2$?Tn}+-uTSy(C0eq1M7HCR#i^Kry~nDi ziSn<*63xwcx;{Lfg+k0_q+{}nQ3M^vH8Qf{B`lG+73)6+@FuNKoLwD5<!UmIv`P|B z)jnhT(OQ`OA1Q7Qu+Pfw5p3<vqOwju+0*NuK|ea#8x9PFtV_bOR8H+z6YupX-Og6A z;l0nQillVpl>=)^gMH5?rB%weAI!<*f;OthnVpE&aV5E<?e<mus2J3`m!$zHQk}j3 zYwPaVCx70)FYzSIsWpWI&!vArK4Q;?dsccVzkA?RW48Mvo1D}mEy_VCg5HJxJ4S`< z&}YKfP+sOuuLT>%yn814Y@-pgj8(EW&D7m^a8Tsm^a<t&8ccscZGs+)13h3JnyE&4 z5=JcIIDIxmbe1|QK50XSoI3fiDpTe3ytwmV%^3gh17@ndE*x_@9X@}jW8#IxL*~VI zm1`g5Ppgq+KdCR4JZ(E9i+!=W+NLR|4iqA%FSqB*Pxo%?p-!%j^ALnOI;smNmfOQB z)6HjHqC<DO#N8Fo5}5p(CEjd+;WHp2G5z~dkb9TZ^~oJ!OzJZ^I|yTF!s<c-b77D@ z!_=&OTqB$Q4XsCorL#5r3#XSiSdJtd^{C?RRa$Zn;W|AA+G53WLQv(5%b`%`!|dY| zvuc;CeSefZi#w8{NH3PWaDV%oUH6|XyZuI9QJp+>PiUufv8E(GX?v=gRg`D1oFo$0 zip0gW4bBQD_mp6;|K+PYpc`LEC`eJ%HaPVo_Zi`;nH`H=gXK<*Ii0L(;BiRIEx5d* z@)?zt|Anikd{3NH;t;wHK_8S9SKE87OW&`W0a}F)HU^dY1$)Y8U#gy@%X-a~Mba8A z%5XI!Ph5>mg#v`kT8%XW>n@K^zW91YZhhG?wP#NDfB#$lw(QnXvvb?ovh5#tN$S2} zKZpz7txSKAl@f^j{OJddN8Fiw_0MeBlFW0`IcuKODZhWaFF3_}Q$4l23WT43V5Y`X zz6&~V;LsaV3FT=GG|uJK$)V*#(|PBt_Qj05kU+Uj)fWj@%uDV^Yx)s=@M9&d&mJk_ zGg1NMV_C<*C%^*FXA#8^R9f#HMFnkcF*|v`OTrgWx3=~MxGGmP9WS(~ztvUhd_Q0! zUL398oDa>^s|($H(-PmESk@%Inkzr?XZu7Hw#@^0te&Daob3>3w)tt*6mpwE0nz;j z<rqnb_a(Q=mt>XFtW8g{uH4C?Tl_Sb4SF(2TIxziy0W-nXdj}G<U4USES5l7Ax6NU zMcN2!4~M?`=y;2H^ZXqyT3LDj>iIqx0!k7>W_1L6jsB1MaZWw~h{~%|Tu>&K1;14O z<w8|TWYH0|*PJoEif467^w_@21{Q!1=Sof={l2J6!r#M4h;`}L!p6WA52;9#e`}Gl zc9tLVTCSPOKdaHIX$BiK*bF<oF}%#F&gvMI*QS~?xKt;N4RdKH%pUL`#062uIKK4k zDhuzmJ<9Kjc77iyY@!nEP;H~ye)&Ww74NG;5BM(hr?Fbc4-oy3o4fCU&l1;Y6N`tf zZSVlCN!V<fR~hF;d;5DvMVr6SBp#z_{su-uj@4z_(Yn}>tEt)CcY2s5KM>-8+D(eB z(#0>^3g7(PL$Er89#UaQ5~TKuH-B8+mn#X+e*V^k*A0WX_DnH92{inuWFFa%0`Bj7 z=a|4%QxN8ls-`6$4Vh=&>=m-38kR-pfi!;7t6Y1P+5_saIks|9xx2thDCl+ciX7|w zwbcqu92JF)Lq#aE^FiVvS-|~{jmz{t5|QnXnrbFJNH}LySb`pipACc7PQxb*LVGGG zaa~rRWb-#P_-s}QfV#K`5YZ!SdMODHF+esJ&7P-Jly{F$JS{&`P`bNv;En_1`k-pn zGud(^*(4H)S&rkdL1_+%Z=x>%9`v-Zbqhb{1P+xaTFl=5o8(Hc;>;q&uQ8Ioyq0%v zOx=n3E4X%a+Cx|k%u~N(Rgu=SU}AnT^gLJsnBE<nnG&o?qz`PFoLTA7qgv{pc}m=m z(wkdG9Z&W23~_vbUrx{^xapBBxL&D>D$C#ZzS;2?*W@b5e+7VX&q%4bR{XN>3TUCC z3$PmLhfK^$u|f&FU+TBG#w@FJu8~THS<VhWSg2QKEL`1Q=&IS?V*UcY!mA;hE~nvR z9;}%J3)iX;JgY<!ib`NeHQ!m1?@#y1b5qB!oK#j|xuAPvd}(OY?2wbeYtlw%H6<)u zqj?s;qxAH)m!X~CICWfX`NM}>7K$z;$agjFe@I`slh4a&Np?aGSAMoHc&98NH}A6e zPI{w2^9flC7F-W!!(#i9Tb{T(*b7FwJsY3&DCx4O_RFF>-G0i1QxU!4J4ZFD?S_bz zp|52Iqs~yE0=e>Ot?z6vU^3r*k456naRpNmi?PgR$P?)4cY5&Wdj;U912cO(%rj%y z3q?C?v%(udGc44KY*N#QHqt;geS4oE8MJ-YF@UD+pf`gECQJoiGZlM;C_h~M&yVD( z$HPS-6EmO6(i(t>n$BapE7~vj2v459^07zrKS$sBXy(Dfo#wxS^9&g04HkthikD=7 za*0&@z1?1(tZy~n_y8ye8TnLYKWe<zDswh!^U|q>fN7)`-!A4N@VE#%l>ZzPJp049 zfMNY-QPY5^#CgL3%bztbH@C`iuSST^3J+Ya;vz2Q6w<>n2j$!@oS6p0fCwzUB4!D= zy9e08xXBWu0rp2NdjE%V6%vHzNoL2mcP)r4Zd|^n#Q&V6?RbD=qvX2-5j!*6`sBw` zskome=3lp5_Y@{ILx4INs*!Ksf3V<;<Ci^EJ1n+4c8l^0?nq{4KTJjzFWcMmdVKuD zV&Xt74hOBk#{~va9uL$@{~hnFO-K?kNX(vF+4^rh&HV%&%(CaNQPQnbb5w5ix4NZ^ zQ#}N~F0Qf3dD_E7l%38apK<tu=yQZC=1aay!OPu*Xw*!J97#AkC<h4vgXq%LHIq}n zS~%Y6w9w;@Wx*z;Z+XDGqk<Q%_bOkrApBvEo%&XW*mrO7=pR3<5UuO>dfy=`WQc6J zeI=WB$!pFC_3~mB5AtI?gs3bk!a{RIjcq={f24L?vvXAYdGwS*Y5Bt~!^aFNfYv?p zP*&rzy?*@UtYGbOzLp=~70uLl?E_oPAC&5<8NX7;k7OZDrgx)lP#`#hMwDNAF8kz@ zku^eXD^Lxy2_wR$MhaF~C={e(m`_ciqY7y}^1ON8dY>tWWO4l{<gM=nJ<3Ua7az)Y z{;f0FwIV96dU9&D-SqoA9Ja%9=d59jZI)W8+Il#(POh%VAbowp#_NS92x*=?lb3WM zTld}Sy@$cHccO<0F!Ekn6Zp^)(5$RsRB)#qqYS3i$Vq*7Mk13*4@DoG78F%h+bW*) zlt%4iW`8H06<5I2M}@=G<JACMy)g(z0@5id#DExJEGL}-%cBnr4@akc6k0uwS=lHS zJdsZ<??`9=UVhEaX%l-jA*wWToKUs9DsYGEulLMZ<m6bD;-2Dpwq&rw>EtW>R>v#n zbv(CCaNb)dJjgQeJfWJH(!dEz;)PlLsC;jo(oo16KCVTuSEy=jY<o(8VJ;t^06zLz z9y_;x*J562KrJ&BjGtqwO6lP>2IcSqtRO%$jXfB{)@DT+E=LZ+G)!15y=Sqs5O@fH z#WJ4;ErcEw06ppq@YtP|qQ+)w&&C(Y_P?}!lbX{TvS(?+6+gk6|CIKCHg`L%W$J3$ zaeL->HcwB1=iCx`%#4&JB|XAVdIRQ|9l2q4{00!x06<*b>;dcc%~A#AO4=H0Y9;x1 z^8>6ZX1r7>23rses)0^<!B4eSeZhZ^pvo_*jVgJ0p2|G>{m^+a%+n;fGroc$z!58P zI)HWW45qo^H4+U`1%5$Uh3<>zj>-yT>$5iJQ@b{UrTx_aYeP<sw4HW%F|h+vqyXqB zK*cP}a%aX-s}E-X_?}zC+x0bL`qAfA{pjmOKgPLyvoWGWs8HDn{&qXrwQ2)+8e-ew zgrKAdvm>3Nv(L?3EWA@yK_$XZ_f;J-Yh>#NKSk4#7i#-MvX3KLEKzv*^aA?GzR;n> z7+k~p$n6#jbySbizrC1!6mF=Sf~g3cZl{gA*ejg(e1X0iUNMqYsc3!1NRio_iyOt4 z?ns!C5VZN$spqUyQ^xs_Bzz1a#VjcXS&Af^kmUqHveLINN3(KCZ&cM4Nz(z-s~&C7 zmRpy&#{O{EHra6-4gC^E7qj->Bu~59r-XBp!CfmZLrF(~DJ$WpuzobQdQy{U@Kc0Z zzbp-}$mmfm*5rq)9F9+~8G<kveQ0W9(9ZJqLdU3=qlqp-im7Pn&%)Q3T8Fk{JdI^l zFw61X52KhM;Gi9d111uHBNcTFITtwYbh;i~IHTvM<I})SE-&f!Vy+OkREs6gp4E)4 zV=aPix-y3|sM(2g%=?bnx2s!64I2`X+4P*0$r-txQS$J!i;I+2uOD#?9~qSCqh9N> z6e&SZ{$VgwTCrQ1Ww37XzXv>k%@s0O1nGcAG^{P-oE_-+f<W}CsVv*3_1iyYN71{% zH(uLgh{&0l)+mv0sFj?*UOg#?TXIA4ea)y%!r{uB;AU`<fcMc5`d%q#L;X$%gKbZD z$5&oKxE;^Dd!oWa==|}HwB983mnueA0k0#^V7*6nbkiZ?>lDL;k+`HSvsluDg~$L9 zz7Sy9JQegLSYvlzTlj7Iuh^}t!2hmQCcEZ=z*l}+L95X1uFRs5yP|YyY*SZ0^^3+O zbBg@h>Wd>|4%{5U*Uty*+eNTWZXWF--6?K0%Pc(}Y^NRNK=HBd6~q`+FdE$$q)|Ed zBl|D=<b_5N24{*h<iGg%$QgrNUh!c-WQZ6v9&SHPjCfPV^!n-vJtfHz$-?bV<!@)z z$d<fH8itqeJ>S(LJ959MMmkw9;)iN^1~<lg%V3<mUbFHN(4cs<i%2BNQ!Ps>wWBc> zr}$073m6e)sqN~*)B96Lr^f|$f*1~$54wwygw@v|DJ5<4V;~d=u;dC10X7Phj2XfX zO&<*kwYXts!RI&3m7f-{OA_Q@!|xIpEJyK`4MJb{Xjwm+Sm?64vXs&0zrxrC!W&y) zVbj^XdsBrg$HYj^yT<-uo{2Z@Pj98jd-!<Lzy}7mFdBui2JGZBzFLLd4%1r9*RFbt z<`JoCqZJ?%j~s_mtVLyU;MqV0tDGqYE5KN_!=nj^W|&J*m@ja|asjed!z#lBKcBVU zg>zx!=xTR4SSHvEOl>N9gdyE6_WN+ALz6Qw))LniqtA5vO1?Zx^Of%<;Cst6;3xT_ z!|Xw{@G`qExq}IWD%hKBS(3_V<$+8|o2D%3mgjMgop<VB!63NW=Jcsn=;2!6M@n5v zf0Z2FEU62Gm#6lq3+KS{Za9_CV#Nb{H4v-;aX|x{(0>w%v%j9u12b&Fi$^SrQOrPX zX)o$W8!dwBZcbZXVz8@+w4e>Bs&dy1<$<it19D;nRo^et`cQB33)k^SPQ;rWEJ$Je zd^~zg&-w|cqHOj;NraGwCi8?31zSspuS^);65@|DKR#doP<VQ~Z{aCFxlKFXWfl4x z1}s9DX_6$&#&39`+F<CO!U!b;q7;m4{8ADgRrpRL0OJw#9<w^?h=)JAPzUR$4frAP zt|Na<W?k~ys%xsbvW$X4hxlZiKMaKViKRA%-grLDFdRe$=BU6nKRzs*j2wltga=BJ zP?NArob&wOA9RgQfhwR;1d5uCR36kEo?jf@?uNZ~^J=Uc+4_RW4C>nIve!<ziS#OZ z-vS|;V-YfcvQ>Bp32s>2FeO5Tc(OqmunOoMAWnAR2<tPwn#T7Ru9#4wq%T9wSJT4l zwX^^u@WvqTsaf~D(Um*j&@;gmpbK=}QS#s`qU@aN2_+1}zzu!eMz!JVtAMA)yq?mn z>MU2usT43j>{q#HV#{AUKg1Jh*wn>=YYy&T3{u>$ZGdsKEW{aR)jF_5I%$H38-x~Z z=1ZjEIc4vEn^A9{I9>wTk?no*U4~97y83Xnz5K}|wm!F*a6X@psXqu{2}|kk>#_4- zA{SJ-fI(>T!Rn9W7WnTR6+&Y~F1;6DUI}McSKB%~&M9;co}}Jkv3ly4t6waBR15QE zCobTX6@l;cv;Y|jFAw4~y8zW2^c%hbmY*9!NXDHR#0w0h4T3epvYwU+iJRKmu=z>q z?O!u7pMUgWw|3T)mors4^D{$a^sqv02Jo8Fe@%Vi@og_hAJLA?z$Sj%c*~T}vOadC zs=9n|kdhsGUfITNEpg05cfgl>R@`?jGPeikYYa439roZW=;LAQyy?57n-D<(6S?H0 z^)>%72Z@U%wPL~`*g$WIjaO(iFe{iCC^xCx4Ld%T1&6q8T;e%?&2mJYj1l@V#kJ!5 zwT*c7{FS6Z&3irw{@UjJk;CTf;3v|hoE#Eqn1~$TmMCyET+b4>jH)WtA&qo3!_LD~ zj>Ic3e38~EzTi#QXZ<e8vAD(>%&6dkgh5VTe&X#~;D764u-uV_3mQuJ$uE#WfYL=E zN?8seXHBc9yraI_qQp;$gwfAJ9OILPr-Lg!esB!jF$cWZ3h1kOdi?_$F#t*d9yIRD z;v9RF2Y!q&N*Q}Mi=_!aC7xaw^rT8KEnTFqEryXM(wI}e9s@`0-K!_7f2g9H(t<t5 ztv>F-0bw#NZO&f~Eylh3l>j=)<U{)l=b>YG&=u@R#$yBxf)k<X>1>?|8l!}v2f8qe zo59l<7OQJ$_dUP>Ogr=-!Exhm?r~qmM~apm?BmqlmBE^B;n`^B$l2uX8S3Dj=E!VT z1}HbiA=E9mMV9S*zg80Uq^HKFF}si+iimxK9J;v6CGn=kcfN5-Tekh2v}%fLi+RTf z@zKH+ZP*uwfbbzz$y93-BVXoE$<5d*-1cG2@|%9meLla%K#nDx0<=ZdcwMvjg+TO* zV3m2B7p+2qI^`Cf;AJqEfxz`JIiRHBWEB{*fl!YV=Ewrd?Cq&jk6OQ-@P+vB*)3zi z4{vg}cUGBF*Q}B2%sfe3Q+A=-2kV)G<wvR~R%L12WC4Q^u^!|wBL%*_X>m8$b8Vgb z&e;4U5AH|rYNdsci+{bw0&SLUQ&f-9`~MHR$)E)2zs_lkYbLj#W00@gyFw$(9C!$J zt++82`i&i|BLE11f$*S=rgJ*(7P269AN0I${=V6>@oV4CuNZw}1nmtspab6%UUbgZ z9-ly62EO7|*&uLmYEwCY>q6F=%z1q%|7K^4#r@*?CJ*Hfx4L53tFr5e-E7CWD%IP~ z9gU(K!q3=E)3BlcX&el8(xnf*>2h{C2vRZZ9N>iv3`Z2C7~qo+mi=U-LKFN`HVWaE zwDwF4<QOuYxMH$!Yw!gU2-G_*G!Z}iczc25#~Asx83`0F`R#yBF^lm){MSiM+~c>u za8C%CRu&Z#Oa(vB%eR}}-qYjHhP#y{o|Mii39+=!xY^Yu=$_S?iBxb8yBW-Hztbx) z#rwI(X^J|fKc)hVGGt5^j|NI05#MP*`i|ZMlN#8Y&)w!AAH*$)oKYc;`l%%N=mX_& z(eDB3_)ZIj>-gEQpY&}-q($OlFfDyr(;cjuU2tJ~uketYx(Te^W1A9ar!>EgPRX`7 zt;ck8!|%Dx$hZ`&R62t4jxj(SPzwkz!24=>VF3)aX6{r;33LW0yLS->c&vau(6VSV z(1rl8!A=tv%6}Kw&D2fi3X(to%#W{SuM{6-n>1<acg=6M-zjb}*G!0Ru?SjIcTW~k zQ9YsglSlmW((4Bp1j^ZjN51Ji{%arWY^(Al$3d@W;k&{g#CS6hOM?`EF@!dMvaJSO zN<OuKi7#G=pH=Oscg_aSP{K8m1-RyK20!77H_!OhPtA@B`BU-!b5<_h!Dq(QsTR*_ zF;gg7&HB-jm!bn2AFGN!)&5v^?b;X#18obr*WLi$os6!UwCmMlw|Ue`(_UM}y2L39 zJ?=+u?xkxLiWoU4#8~ZudgIVIid2UMFaV0zLx2R9po#zk_{xs~sZ3Y@H0h#9%MSu3 zlm)T@HDMBp!R#jA1WCLiz{kg|OOPl05<NcS*XYsI<<`Yi+RdylmC@zD^oGpHx!gyk zUYbFJyRWz;SDy89vDZn-tR}7H`L(lKeqp}guG`Y<)hjQhV9zmu!-M2kJP#>y&h$Gc z%Wa2|<5@LYU$OUGbIp`32sWJ`hIt)~Bc^z)0Ki%p^bE`}z&x~xI9)miEGS=t3K!I% z-x>S9#rs%tV5Q^_ggC;4ybfi;&1uyxEY5xnz&h>rz}A0{!roO2m{99lNnd7FwrWPU z^JU3&aG=bsaH2LGQQM~kJ<_;`!2K~u`O7Ope8ADs?f$*O@AgHHPY+`h<!7q|+S(&m z6Z&3-?Y)>XE!c+lsOg%0fGY@zBdW-+$00GrfB+RE2FX`KKqfh0Ji^mE3XM<qF5Jzc znUag6B1aiWPzuW(0KoW)T&u=vGLAhuaW9!<zcL`EmHmZ(EB7$jxAuW>&D8|^Vo_O) zJ1jw$m$h+^HC64|t>)ev4%S$~?%|!H0$+uEZ;Mnf#a`JsEH%26<uOs}quw2on*A!r zQ}uK$?0)p5*w@qpr)wu}tNI6TFS?5Lfzbqg;C-&z<6h=!6@#QpOT)0(;h+^e0sRAz z5kPNb#P+1OCPWy#yqOACQ?+18G$kv?3&O0kZ63?7=<-LrVmnRlG!YojwnqggqC)3g zGh)rFXjmHqPmsFn3CyLO9zjs+bF27fybuWxIbvJ-f>6)Pp+8GEy$oz?m8C(i%60|E z&_`Ke=X->DoRK0<X`xJ0=F&`O@L=U}C`w)VWr=DF2$mSILx+$t2?9$f#&Va;|3p|_ zg^A#zt>&z*>9c|s;5pc9Y>Ckj0$~k8ti2zdacYv%IPppdZ34TYUym~GYET?C<7`o{ z{D^&x<%Ias@We5JlU|0V_Xugy0N&&M8UUxpRX`AhN00LRpW&>clElL@w+@Z}&sZS5 z8m#%Mfo*N_TWKviTtSR9vm*0!0UH3mouy%z1K__7z<7X-ve0uZg{;tdO^f*|T@g<d zZOU>StoJdHz(>AV#KkL9bZ8@9o%U=Gmv29OxWIC(>!rMgS(zUQx}BX$7=`3VbxxsM zX!ODCI%P&qR3AT~X&A8~eZhn6tIAtIXasvEgt$c$;-q|0p0lctc4hTQBSgx+I2A43 z6dTwDmN<S$V+iKNj^HM$K06cClAAYV`;?H22XY?x$sY;nQBkx*lpI7af%h%&^aqb> zz%l>~B7K=U=@()<KRcUyNU&ZRxWzt=i8X(5_^CYM;_Yr9fB*8FMsrPiXUhOzzOp_7 zsk^HD8CB_dvc5|KG|*J0b#`&2_b>sku8Mbm?Fm)6ufH{;Sh{#x3$L(19TxtC|2M~` zAVkI>iy-B990xhtViSaDNYZ$;T21d>yUP4I|MoB`VL|{8GZwfdK`7F8BG~O2>Unqh zPmnbNP$wU)68h%m>9j33&7{=ER&(`+{j7>qdHo1P-SRvYs>X7pEhY4<(E3GCG^Rt) zIr9<jIgrh>#mhk01h=@Fd`Z5Hfy)QWN`%Gy<`*~)K>1-Zi_5@rl8mo7#UeIOP(ke~ zC>_w`5iE&Ak)EP}$~r&*w#DtMdOjKp`vUtcM_j#x#f3ZI($+REv`6S!)cbv+gH8d{ zPO_>=Q?Cl#g72J)=_JJ1SOFV`9^*3+a!$qQ2t0CKi(u<=b}Nih^y6t66k~vhRWKr4 z)pQ$-ym`{aa?YR_W_;Mt6x96Oe2{PQ8PH#_<RyH810+&l?m&2>__^$uhbInXw;$Wh z;;f+{=#sQO0XY#o>BgRT>aMAYY)VmYR1d8hK-@AA9UcQ7g^z_jxI5XVOuq;VI6)+$ z{GxZebXNGPwh?{#^$iiNwrTIuOt(QDgfADsMOfUZhLe1d3JGJl`=p=nh4}L$6QOg2 z(CTBtDv-n$uY@yWN`&AF0q%x8d(dEK5)fn+P!A}45_V%`wRbGEY2TGOWS<i*2hpVW z5B<XNp9=*&%amW|Y<q68rZ*wL***ZNv%NNP@PP<O8U8wA2z?jtMRweM{VpbsqWn@n zN{P6rJxgT7YPdjhGz$FT2yuK3q=&u^i;!bpFXvH)eO*4axM2also&sIyi$ST;D;tx z?&vwPOcCPjNSh+xQbqP(Ky-X+L1xI<&cb1A6J)Mk@0fWZTDqotdMD?<rods5eb#bG zOmH<J9>&uGzs}%)CNg#ZfA0#Xb~W}2ear8Tvx&MNddB)`&Lh>#r}4_|$Yy(LZSzB} zj?{|ORUYwb3J*r*Hl5uv={LBT!dhKawQcs}o(9{%{VIVS$2SWvZ=$^c4Of@$AK@%L zu&jfmjYwv3sa9?X*1rFim41T^vB%8?qb+SGbW2Z{vq<2xQGoF=Md6PHO3lGt5QFt$ z>@^hLXbq>g*#E^QXG4JruaNP@;FndLPnCOS5y}78D0=LN$|*OWseIdu1mSe4V<UK5 zdR|sMRIVydpl7z2!k!T|RnI`>23-TMxJubq6zYob2RgmoD_wYUU$j`KkMPnLh>QW# zdS)YNy6UnP&{V^G!nBM7WrQ|sB@D&`6F2OSe0$n*2BLDbe9y9#lh7OJ%mg3_2SXJv zh=G5g*cdpat&Ns0g-y`k!t4c&{bWCPRngJKg}&*ZmUN<{@NM_3U7hkve^&o#QhVhC zf0dgsy}jr8<kbBtJBKXrIn-4A04>`JSz~Pv&BH?UH6VGm>qL(*U*TAdB`1&ufCyr+ zv+-XS(?{wRmT)V(2u22KL$$NktOEHH3g5Cy<bpXC;sDq^XKd@Y@zp%jnIr`V^Ol&I z5*CJPOk&vi1YCpX0yM5M1RiXUEyc_Jf0<nGAy7^!j);#DwKwO>Pc2ik>&p{SgKSM* zZYQ_qzMm?zc~ea${rBR`cdcPSRQpwU(DmCw-~_6B;(aiAF?OQNkel(z7Nfa_nZz42 zR*{-oh`WlmyJ#;gkufmf!uxpi6>SesL?E3%#C?lsbv%KBbn|xYr2gI>t;n2;`_a|< zIw4pcU^1y!2Y^yABOs%g;gf)e2b`Z8oaMSa3uSIfzG=@=v*Y6Ad%RCy@(_M^nXNyr z$T}xETAN9$yF&}uNMXvD3J;}qhx)%|+wj6TSTFrGUSEAU$UAG$4F(b*a1)}<;k|wf z2tO?^Un@Q8R|2n1-kTU4`I=f1(ZCb1i|2DyOk-^|jThXvKsmLnWf2$?nc@q{Jhq-f z*JrRkWQ+$S%W*K#S}`D}2`Y#o6a0J(Ur`rYr4NkaNEVy(i3SdxO_Mmywhv|_OY(1V z+~M>ziDN<5l^&tOKVZr3Qr~F;pi;)=0_>jJYGSdp@2A9*;GnQzNXxoA7+mo-H}z?6 zy6Wf5sV<@Eo#RtTp_Vxe5DlVmkQDU)&EOZiHa6Ikx^dGUR!D_8Clb53Cr}YMLeFHl zlkf~i;~wSGt-!*YL1uQi4<ey+BBwt+3=E^b?UgmQZwC^|1XP1|Fy)T8W95$myBEiD zkVnP?U^u*FVgTfPt0x61Q80w<L@0q$do{<(*u&}UwG*&)ND|fYjGA%U`$(Jo%#!2O zP1v7CHeZF3wW#s4&Mh!#%XpM%noD2S;C1-+re0w>Y@RWWX^@NkB47hSSE*Z3QKuN$ zT!v%RZi9j@K6sFOUhn^TX^2*8>HChBBe1Z6b?R)kP2;s1e6y+J@?3c=-e|IRm5KHS z&S|R+2nLy$W(<-zd*Qt}I+2b$H}vpA2rO}o2fW!6{In8&`X$KQ)DCTB7H<$YIBuK4 zuKy5@pqG4q*2gJV&CZ8|2wAwPEViTapAz>Fl<kFm0GIp*GY+tESrYhg)b}VqzFq?q zgN+lvMGrtcgN4IbSEOcvJcJ10UTcLkxMrMcZB>>I<uc#}{89q=1NV&tm<0qMf>lvd zv(hE{;}#@GXTciGLOe?70H_7$P0Vao!D3W0c+$i6G`<MC(U`M3G<*fI48-z=QyFl# z7BvT}Tsxk$SgfnB6V&xqgKPA==J$hkE`9$kKMD+b5n#|WajcOEdIMXfl^K-#2ur_) zcZgJ<Sk=}7rq6mBujbE>`@Y&H>~vnTA&${FmN;N2t4bH1hEb5P5w$lcp`tIqLxs?M z&&%7hdz1mZ+_%%Uz;Y%e%HrO{3jc4mM=5ZO7O)p!{TREuILRSo!*e80t@LF-+o+I< z1?lEc4%JNyS%~OZODj^|aa&9ye^j6DpJV5As%1jFYMuY-+{CFz3r=5@WdwYw$OXd$ zN2f1OkDEr0Kxh3{nO%o{0R?{?ta?Gy!@#U&vif^WtqMXd;ep;?;sb5YpU9#Mhv5#* zAlwzZxvLaAlCUA#$DWcH<{IbW1A->JJPS-evBA(17J~+&kj6~`kHK}+rVRQ2tH`>L z#Ns>vtW!Du+2dHL9Zqq$8dw=ILy`*Y)$c8#3kTTC8C*`bYfQqo7KuqZ-1CzBmS^s` zO^~wb-G8uA+}G9I@P=Q(xHrPD70&GI5*M9~PfmIuwC;Fcwrwj{I5S;bld;gV>aWBo zN!l1G5Z8mXdA?hDCQMYZ6Vd)c*YICwTm`q--{4XOdzHZN#_@4Z9r3D=uy7ZUOt3BZ zLBcJz&G+UF6NH|}ZmYN<W3{y6a4`TB0I--|Lgx=-q_$5rdK)FI*gK~s+zwkt##vLH zrb_eZ0%S5OIKUynlCiTKhxJn27+lOvIEVrtBA-ytOYzF1UrgP@WsF<jms!a+py{{S zC8bX8F0zDzT>-OyjJqrSrK)3m?zGP22`#Yc%md{0vAJf`#huCDFJPdJR|EF1NqzpL zOJ^4FP+}%yz9?%S!ej<=d!R+U>G|>A4+`G3&E8$Ff}xH84dK89CfI*<Y3$z`8?-z| z7zYqo_#-@Kf<R$rADvpOU(617X-)}S3_A-j(}=-LzyrhgOz47>Zuf91*jdX#fe(YR zmhE6!oPt1hcYpfwGb_PJbLA8Fy<aLny_`1sgeR4{H=}g*%uIA`TlL4;8S($H7J=u? z)yrhBOREV!hUGU6j{F-h%NpRaFXLV;e&)Gw3s6kwWB?B`5*Vi#;Ua-=g(@Z|^Yq`% zS>ztOO|6mN<yCy`JV?a12^Z=JjO+<21;2U^+4=IkIuQ9VZD#=4M|X2e1W6o-nB^rU zD`5}_Amlei|5h5PLjrTQ=HO0u;OcQU1?B##)0x=g>mYFQ{5aT-2c87jpK%=C2mCs) zO2^JxT4wsn8oMSHL}rey`NSg5={FN6^MibOrAvvNGrSwDX?TTs-YPish6@thyjdFi zMb?E_SSizT6TZ*{-vprpEfdR<ZmyE(>QDH{b~@%FAPWh!`8+#;PPfDK?eEvg0-!NF z=zNHsA;%a(4u=ReAG!N2gT#4K_t{rAu9I7fE~eNtpY0=CU<EC*!gscP!y_6EVN4+a zKc-NY*CV{JJ*LnZWU4yhvFD6Jm(YseVtmso3b2{A;%WrE^B`c+8_wBYYZJ%8JS4I` zTocpDJqHAC5E8u9D)W1?*t@R3t}<syQ62|Z=Xds~NG}6-bA1I7Ru(YZED)phD_WH_ zCJcw2!1O2(k@UvaKKxPzvEuu%y9)LM2VWM6>l;_(wTybO!w}PW9JGwJF<QGU<}~9z zeQri7gOk{!J5g=&D(p5pv>YBiy}l_!SR8B*?=U6v<Gx!5!KsVa)(4R3aW?I_)Xmj7 z+9M(aMfWU<3Qf&7D(Zw_hdV6$Y7s~3aF`=_0BMb-mI<Q4I3_PCp<y5}MLe?@{C<Ei z-|6lTr7YgxRJGyQ98;-ljjZoaa$PGUU#Yy8Pq7|ZGa2_A@LYR>&t-kRmm^pi9G+YR z<^Uams4{R1PCF_=Q~<I#?#G)QYz;UyIklI|pB&8Q2nqx`U~zZ1?T*8T4e@?wc;q4* z;ikZ=`hc$8wlYk>!f;OlZ9Pm2XrBa*$CQw3uYFN+0t=4?=WF?d`&}Q0&$yOHOJ~%q zDERB^MG4q4y#3u<Wfuy~Ltzhjq3hb!LmhJ)bWd+^#Va46@sy`21NdA43lE4m_;eWH zayS#Fwo#rrENIXV(&4OU<r!SU;edbun}e$^dhb^5xl^9P;5_gk2n%9hzGjIg-EM4{ z1KL8X^1J06f?lIrTLv_k#~=j47SKSwX{?p&)E?Z19>_+#z9fCxNTizN;VvmYn1Nog zk8+@{Fs5Ati=JT3#vcg)UL5l-{74y%llUtM4_>lOXRGnkKc8}P<Hkrbvf?2FgHVO_ zrJuW`w&AN<%~_m9P765`s^U9=`NoJHg<#Sy_|s&T^a~PTJm?oJ&jy&z%E=N2E*Rj) z7e0L7oR5>xK9OM!lE$JyLnF{&Bo8)y!MDDX*44#9G5?Tu+Uc_Xz2S)t)>lv2T(1ES zC#w8TzMs!FZCm8^*C*VEncM%le7L+*Lh|v>u)TMks`1Cgu*6*i>avGV6m0hAFtG-N z<-qs~xx2D{F=qiE7Ll#kJaNi6q=4~;@qsLmrsQ5EIxG;@3}o32L`lr(x-gu`zW01{ zwQbG*hxnyAf~l`55bPisP~rd<+eEqzlFwhZcVuEg$O9*I>j<X*SrB&q(L>lg03d*K zVa|jt_P}16h}%irPRySsEC_(LhX;Ok8h%MrKYlU{9w8_kEIDqu?tzl#ppgXl^Ti#) z<|iospM#JyS~oW{R27^3b})_Km49EJ*9kUFLK9$Qb<?%7j%aMY2Z2{Qf9{JKE%nDu zDr?K69~DFujD0A~jN=6g97_`qT&iu!1QY@e3DeWQf&OwjeBB=YPWTiEUiuRu!otjm zt&h4rwvgNu(N45IVGTff4d{ooJT0Sh1{I8cZYYOCb>CPP)sZe?G5g^P2K;0>j^sdd zc<gg|!zm3ny{$bwTO%*!@h+ye$*(1766VT2*8T($*((4C5a71(Mk^3pVkElVIJyX* z7bo>y=|jr2eE_$OzxAwYhf{qi>o2gl8UXFYJGRaN=~6(GtPz7Pd<owCm720~);^VD z5;G$5KmqSVHh*lJe9z0LiFmw*vtZZcaZkxugz<PzAT?+^7GHr01j2(kZ@y$7A_T|0 zNWXV$1eYP7H|W)la4`PUo<N&Z+HsCwKoRUD)k#1T7c=WL{M$Sa?Em>64D@IWKo3iN zWq=TqVB?^}=3_H(ng_6{a0pgfUI|i0TMR__^mbA5710F-mPV%sLOusYK;sbsuZDxZ z^j%x4MH|Z<-oN7ODQmq?RnxFH$~(&+&f~{}KhMORK_gI(2La&S14~@x^<@b;EXZ&| z!DiI(=Ti3>U#)4!1Uap<!OSe??*E)2|0{!QY5{gdh>@V=CmT>VtvHSSx;;9o@CfkW zlfd`w;&}-}GAQbJiXR-H0u}^0=L3V`PdLAelo<(hzrBfnqN-;Xu*XN3FdCjPz-30N z3}ji<m!HC$%Q6z=1(=GiaX(gc;89MPaCv)FkFXSo0@*s^;22L4(y$3~?N(G&VV`h2 zxB7~iwWG7nwUq|LGKFbvRFqaifNj&+K~0x(q%HzmZ!$}wJAn5}>T4Fk(pquta<Ew& zawClnfbz1nQ$pAVzHU&g#bO#ZY~3A&M6lDs4hhi~(#$IZpN;GOv0gDo@PG-b5U<k{ zg|7q683ip-K8)#-dJ}|E!3k8|g9NfeIClQ3#@aTjbhs!%SP&34hoLRzyz39plX$?^ zw~gyNfcN<RCV)2wz?;nYt!A*zXb0@|OOINlB7Fr4u?gi3bT#LtWY&4oFwh+a*9;*8 z3^_er!idCQTeBQlf{P*eh~+N>p_Jj{<W~kR$$yEh8K1SoJTyX>{_9^q)e?39dw7g^ zO_8&V)9P8inA#hrvl@aYQdDW|hQ<b7zH9prk4CUZF}PPsoO4rqlz$pHEqEO4j#Ngx z&-2tbJU$SE&;)O{JDi>jjz`!VVr2+lN}M#HkHFG}T#H|icc6owfeB6>fxa>U&NQJ| zNbAlFgXjS0I|*+$J_TnRwHN-u-*O^3a(I?x0W*LLF(ErB$tSdIF*gQ#F6hhO@XC2} zb=4K@M`qjW4#%-ddDDy5?m+P1@c=NvEp1*j*8kipn^zg9dlRrZw_04s!!o9TPT}M| zVThwMayWkDEm+L1J9d}Q2)6}pQ~U`KIDv#Kyv}S~%*$Bdm31l#vEVu(e9b4uKf}nM zzB6t7UniE;$*;jL6$)(|Xwv8_1H6Xm9(-#Cn3_BUEJ4Mg&|O{WAw68;2Ru4E++O~q zxO-W$R;T6&77kbvqoFhZ`o3&+M*{6iGGKXdI(NT_7}z<;;fEtqMB_B(4JtU`%LEDu zRc=eLWq}vjtAQ4MNg3_hZlc{2Oj20Q65$h&D7$w}4RvYK?4STI-&cBO-gPT_-_%?a zQ|O}kHJlxG4hv;e4#V`boj8=z_sP;b-!T5{)c^bS%S7z;h1_0lyV=e?)yY#6{@L+x z3xNA{p2UfZDC>SkxES)N05?#&8T_BDQbR9*jUl)|41eIX3tKUx_+3LSw$ovP1z@ED z9V2PiW-W8!LtyFxB`n~BjK=q3h4TckKAkI<L*{VMs@mAlrr8VUGG(VyT(DnJeX-P{ z`xG3^J?u9a8-}-mh!gVN_Qh@T@_mNIEEZg8(t|5B(eNaA9+ei_G##Ff*R$ZQ0LUBS zizF;by&89U2}24X2!D4nj`~p4N=B>25p+4E@ctMP<)I|5xlV__4d4LtAa)jluTKCb zWQsS>gkEF$Btt|8D&PW4P0Xlc=Gtt&kc7J5sD|l0tk+jfy;wg+xXv*vC_?7;V)ZkF zUpO(SGb{?;UwluA+~<wBLB&9X+NNv4_pr2qMXTN@^%W^#@N^&-Ek}zQrgK+wXjeQQ z@-2YnSzJu^@cY7wA5`)odMxG%03Zt4lWEB%voOGnI(`>ee{A*SzbvZ8ZXU2WsH6!Z z+A_Js3l5@$1jphWfeD9bBoO%GV@R#P9wtC2Dq1^71h@AhGg!``3U=UQ?p;GG!;>cd zw%Im5Zp5fR96SI#`j`@M5X|ch0Tohs>q*r;yt)X_2Ze^fTV3Mf488-%c36JxDUIyR zKy5WP+cF930MoEgok$Z-+X7IYhB$V)6hN17O9LL8;1l+dRTJ&F?WG*>F=*9%jwJAt z!5@4P3dWlh%zk!!fiBecXnby4-<3Uue^{HcC_J0J@++rebtvQty2Egg91Y78o}TYm zEH&!+B>>f|ThXCToC6yju+dq=#cpVTW(Ge4Z+^M-EaeN`A}aj0#e?mMXMp*@?Mn~} zzac}j+NE^?`wcXpmEJ%M5Dp-dSRf2+uc3k$z{H)3<&yblB}TsMU^CRuokZ1GpkQYC z)LeU@0FSB-Sq>svVwhsC`*k_Ly<!m7u!L}hvmdxoWez3;v_<Ps;p4S+EAaV>hoIl| zrFTRqkKr;-hXBK4watsC`yaxOGz~1p!0;WOf_>L^Vm#MwM>tcS#e3b|{u2p~K}<&q z93?s`9&qqZqqp3EJ+$CUcG;dmVqFF=MPP7efGv#Z9<XmyS_3}f{z+f_^}{F3$zNBI z8OuO*<JyMy#J67M$zi@+M3I2{Ft)*zH6`XGaW(NRFMB>EHO`G6RybYz4h3O~K^7W> zml1zi7ihhlpqRm0*o25@z}DEG5ZUqi2Vn}JGkjs(LqLk)(O2Mbq6$HjfW^}1llNf* z4KM^Dh9zW^;TF>(NCm2lZiplJ5P(fhngYI6v+jITwm_Guz2f0%DDb)(td9i+wqVme zM-X%z4_yKSi%qnOn|JXL3kyH}=&(!$*#H~~iM*a{;OcK(G8-(#xzu^su0UaKhK2Ar zH|%+D@t@eGQrjVLSHKL8liI^&&~Z3!2^=eU66142oTm|Eo>l?Ii1^P0O~;g&DFJZ| z9tMMe_=e#eLsl`SZVK>^E7#Z_4U#XwLp$kq6r-!f@Lx|fn&G#uTqI@-V(D<=Egj^p zu%?wB?%FDIf3dL>evwc+BRg5AfnNqIpOLb8Az+E1b)bXPwqAo55hb+})i|PWkQN}2 z0|FyU22sP(6AJ%ewY_C3rQ!>5Z|M7p!wkT40?7vaF)X5KOhCtgxmt4ZHApBBsB|x) z%N<H5KEFwG?OKQ%KWif2ozvkHQbU3@SS=+#1fy2DV|K-0Iw~p+EVA9FItyKOzZ51W zXLa5I#dTRUuQI{gi$p$XY)tn8yx_E^H1ca}ks$@}E<3WJ1BpC@;0XwaXv2raKm|59 z&%kl*IuOYm5C~8(1`e9h<{Dh!IJ5Y{B6EvD=|I%V@!XWuXD&cM%!M2j;6EMEID$Fu zz}79;L>q0+;$`;s4puu)5NCUW;i~zn{Dy8Xw!TMA(~3dd1PuCUD(f2Oc=Pr|c&EJ5 zO_Y|sa3OX=2jvRha`chY(UMsWw7vt@k<IGl+d}|MV2SZzki-&zfp8L}hXN?E23f{G zI~dRNxaK`ug#lQ@$M3Gy^!b|jo%!(qn;-7NswT2n@4xDerI*F{hYguo`(X#n<*Gqz z5ct$_|HHDgi~qThZ-fs;jL0WDdk6eBn2JH-uP4LSKp(u{76W;6viTa8Ef>u`CDL|N zTVivDU4$%$ABzMy!s2IwX9K<m8DL@pYl=V+Oql_|qX80fe1`F#l-vljvd3^Hs+Ax7 z7Q+{3@q>|7X11Bw&I#)cYE*<<!=xXhR5z;285N9*4^C}`QBfdB7oLq74Vx7_=l<cq z`6%sr7;NkS$B6HW)PKTDfbh96kgqZtjb1cAwdZFW7B<(tYdc*_3_=OO!8@8}VNysK zNCALFBKOM}Nm9CZkpxEF1fq+=!|D4214s<d5LkDb1kY;t`EeWAr;1$R2aixS9~%^w zeE~k-ipOyHDRvOXdm8KTmoSxemIus3JAoZJz$aXyt4BBlJ^(mR#yNJd*bx<5GQV}s zKC`f4Mq)t8<+IV_Z@@34fQ|_O>p%Boxj)|kdo?sf?3vIfh;AjIcf#RtzAtYBFY_ZL zSg>dgBLXTCP|rM+;Gr0Z=?@@VWl;}H0n1<vfLXgai)M$w0bN5VqU$1<E)#)aT?S68 z;#<*&CT1#qTpxj7LIL^x=$03)aU}kuI)!--yh+042<1P}=!N<bLthO(1jO;zrjYcF zF!-gp0N5CsejiT3EZ~BkHt?Ml8ppr0`PHH%j1AjFc@Qy#??#K3r`P`|g_ninPP9kB z00M3ltT6c?9?oeA@rEb<!4{Yf!*`*PFCLzyY#3}F^ubSt8zYBjVG_V|;Z;8dE7f3U z_8dAi@N-fIDh>r~)&>8r=kO~NMc1qOO@@k&`fRQZFoplnln0On1L&KB6lKC4@Ko@T z(6yXQpBNQJz(D*RbK9@iE>gia)6x(}kjN5ej28L8&p#b3_%AFdbLD?W94><y5e>|+ z7QC(ucBZV7?Vn5bGzkRC$(bnuh*CsbsPM`F|Nf*VW(5(9mhdDj0Deq%5GMl`%YhA; zU=I%XO{}o3NHdN71}Z@tR6>BqgQ8aDA&`iVKq4-<jGtQfr>jmr7nT?zWELoWBdD)x ztO~2b1o$BW9Cxc+I9Q^G_cG=95*(V)kY&P}e6w+@aPNP?({BKMfrSFt;|UE?v%ixJ zNCz_3E+r@Cz^$OA66IggI2J5f&&fOjo=f{tF$Z8dLBfn=z#a6#NE!&!!bb*$;hvX6 zY=3;bztC+l=?tV$B$=Pu2zDqR23zG;HCBTTF>D;62`W$xnOD*-%@tKUaF4)XIBCLu z3J9^^u(*H+LIgC`gaa?qKH~i11is34+EQ2nUk5w3_?OUbEh@O{ToTQf!z)thB_;5Q zD0@3MhUW+JiAV><{Q&m~ike-(6l$B~v{!t2v)UkG5H(5%xEEF5@#r8|1O4IC@-pQu z;#^4jGUf^%;E@0rFcEOYr7q3e2Y$_`Oc4oOY{zl%IpF<RLsmerZ3e3Cn95Gry2ZxH zH5%S{rsQuD6=cGF;b$KlHghaV;60UFyYyyLoC$xfPa@zHK3EcGH(`N*HC&#H@atn% z_)lyTiwmKl0K?FJ!RH!=#3~7!FH?ruTCTQru&qz<wkae{{P>cKjDvdkZ=g{YQV67i zV3jPk^vl?)1o|Y&0kb5`N5}CW$_I>ZTAt+#iD0DOG2!rfaj;JWy!i&{Vg_64e1e`b z>-0ZCL*;>kc}b9*(bfY*Z0b-!4G$l@IUhHxZ5nVe3DB4d>d0wW9cKADXP}Rfc>td@ z5`y^ye!O`~s>cr4YB=~okx2T+RxkP?FoJI$_xxr>ss4sqP5_Dnz-=d8tac5pcqw(? z%xB@;TTVnI`sgbWWE{xxQ~zf&@PbRT7cne39kyWY(4TIzR|fW?-7bdXTzFBSt!ar5 zO%rM*V<G~b6@LrCb6m`52`~xHVfL!QNiFy=pX#E<uFiP#`rf5*T&mtIJ%EPK`n$=W z!rk<w{Gp-i3Ou}t4v{?o%H!F1@IybR)nB`C5jesru+tnq3w$UOP$J-8!UQIcxgB`j z6rU()Ay`d2Y^y?r+LnovESRUlud$>95?Yhb%p$8Ao0GLL3fel7dvMw+xSzmm5-52A zh6p^$@Bp?Pc;pd)cy{1k5H-x=h-=WUabI-d?XURfz2>`KW=kP+SZnxq(7^;=5oylf z<t#qaQn`jL$@WkMK$flJ%1D-%3WEj+JUYO41holKJ_~JLWcYC^JhPVG#m7_;fRlZ+ zCMi(j_$(k8MDV-9ieLbYMPtB42(x8_Jwq@kJdlqHhhIi~h#3NyR0n`HGEZ0pTlrCy zQ!-+tzVOowtgep1)$#b<H|Djq<A;>xpNem>g@{%f>#^`0T51s&mKTjzc>t`~+t(Vc zYgjO^Uj5!~H;c8)AKbuvLZsvnV(x&nzyt(@$<#l?R<Ro;el%3jf-vR^_ZVEo3@Cw# zz`M&q+jG%4(6o{m9=(BF%zsTt+7+km6)@w$01O2ZgCX&uf!4I>btWn`1uOi+KqRJa zR%Vnai{Qq@J@m9H1S1V<?}Jd+p>7bcUlkjV@voNsFclPn6sY62uKho}RY;)n0rg@$ zgPYO8XlM_XEkI4<cB1;mR;8{0pSkW93<smJyaeQ3Dqvn<2{M`mt^h}G*nI)>smUNG z2cBw4Al5gr;sHN*;{rbpAk?<VvD^Tb{w@$9`rY53_x*G)2#oQZVbMSw?>S)QgX5 zA#458E$}V?deJMo5Df0|Rh@+{zv}$zbm!3i|Gut1Hj3kl&))fNO@Z?P77mV~D=_T| z0s&HFFkgEWv=QPDyO1h~)S$Xx3)&Je4#l8!IsfB+AgqR#eDJYNQVENsc1hBP)|jhA z6^91fYCr^;I;X^7Tc+SzV3`Jz{(f(Ek28Th>27!DV|V7gH*aR%ym=EXS&^ll8n=%w z{<s7dD?a<0Eyz&Or{pdAPj?&96=2@1()kSs3f}yTV-*6A;G$B#8=Nh*z?I@qetMuR zUau^OS+cZ?7)O~7mi)&!lna<vMuOkFXHOBsJTzT)B-YR?LzC+E<3pJFIM|ZltF`<D z{xwo|c_`QhraUn)Wq(;qhpz&bVkrfC%PX)`o|IwvrXcLk>vcR7$8lkrz5O)G2<AA} zhsMRijNpystSXf-YSs&9ahmD#*4(YO_x(rP7Ijn6NK}vxnilL5^e6%UXWP(biemo0 z36=HN9tXP-xqM@(797+qR#i!4CPwcmFeE_#MPa!1p_~x3ZQisWQi44MMpeYG4)q+Q zeUzSSEw%kJp<2ODf=BLNYTplMD`__g+%GyW;LNB)LPDs#YH%8^P;vCn*oVP|jfeC^ z3ndg{Emtex(|C8`K<(iR9p6L>g61->nc#Cko8EAWI9tWx6$;XzV)bb&sf^fs&$x2J z33zEwh*}dPXj<1HwH9O$9(fL)?t>kps3C}VLP`4jT<9F_`{M6C7TlF#b^swa`Y%=( z9lq=|>~ImBtiVdU^Ua`6&*e8vh#WkTDNrDTo!&S+Z_OKc?RD4Hk%?nEJ>?*PJ;}?L zTe0@#wtEo@?k`r!vT_sXDd-0>P<3<*WC|7KglcX>(zZ+1#^bi*;(W{^9&0UA%LUl4 zpzBnS1TWeul=5GUtC_yvdT~*_?}d7mRr*yZP%B{pu=tc|VNQ%A4to!Be4q!jbi4!g zBlh%zTL4%`#G%MxM_P`@$Eu?0tyeku;xYBpOW)N!h~FIqEaf6&b^v>c*2so293`Cw zE{BRd^jQHIK=bz&@k;EKVE=<~k(QI3VgL=j1%WP{YC*qOP(x*peG(G$S*22}v+#o; z<xcwb>6>8V@zzBSH7&7p*q3jxqVkbvK4)}ZXiRd-#s0lb1`?gssYgH|fTuGKQG>0? zAi-7Vuh9Q<{<%A`erQY_S3)PN$li`(Zy`2d(E7jZ<1^;WpPcrKvL_)Y-k)^)$nUy) z@GLMiFMuILYN~KGGz_U|ekgbXXpqR<=tO(7UFMH}prlZOaQXJgzevmRvyoJ`OYdS2 zg#dhQd(4nmbYRM_yV#Ki-M|)_6LfBM%DpjA$>xfovD;DHaW>vXhS5M9!dBc)uG)=l zUS0$CBhkjo%VdjEi@)0^lIWRO`#Qw;!W+w8<VdZH>ZY&40@l?Z1Kw-QI8xgf${Y^W z<M>#=QV~0l@ZE!>ks^%-&8@7{p)F0{NkZ)C5I;Wi3Nlyhx@P`P&%T$`+zGy|BF?m; zs;MV4abPqYq2*}IicNJizeBI)N#4lr_Q!F|1>EWET2n23ekk(`;cD(bcqi<I@g%mk zLaY*Jhi)G-XW|S=HYYgQIq%5^vRQ_p6n3D>VSMc}upA(&)Zl2)%3~aa6zsLBOTJ$h zC8>i0Fy?q?*xZI)Rv8>DaT$Mjsd=>XNLgJscopUO^UlY{)r{I{{jp|fU24(|5&%GF zn_?cXxPlK>U^hr<h6{}b5oml^e693duw9x=NI=^eyy(Biet%j30lVwg=YMZ`lKG!# z9@<ghK(yw1V<s&l80E=GPA420X#Qgm-x#KuwOz&@!qx2orFLF@7BUh_IdMqJygsAI zy^L^{JbfzhEu?k5pf6vt(FPW^Z&<7ssf^vp^=VT_u}=vRi)abNrL4%|6{2!}<no=m zB<9~xlw3X5fzX)$mB6|rjw!wggOn>;s;E%-t$z5mS=Gu;A8<uxdXrPdR5oeCdbBbS zOX@=c;5G_Zfa4K@PC{uG@R$Z+#u=Uzhjk4-?`Fr$=7AUwgbiGFdJkk2reg8TS1v7$ zV|48SjpXYwlTNpOO>&8i+n{<|@VAGWGdf1ZxJE~@Y4_spiN+rtG0tA6LRuidZI-$A z7gD#Bg-KGwM-g1+za05Z!U4iqTvq`=1^g_f*C*Ace&-xE9i>pZdevJH3e`*B4X#5i z0cKP#Bns<|?*mslN+O==DyjJsCkh@`b?TA-ctyCV;l-RKr*4OBFDlQ$?(oWz70AbG zGdCIE1CkxCkf%zIIDkoJrT<AI{z?O!>0r<F951bRdPaSvJR5vlRoBn0BxZ6ioeJZk zTXTri#)n91Av?7y$K&-#4uFOolLwX}-S(yCSfWG4*$7G66fSCyjG=fJX*vA70a`q) z>V|=Q;p)aWdKY*8`$D?v`7dE(0}OSL4O1I=wO>2DG;YHh*}_2$b!aYYn@j&ymH+_> z2F&FfH{J<O^ex<EALP;X@X%K%6=NdJH~VBA7_`w+Q&^d?WJ3=FIA-MYy+<vC?Z7Xm zUV0f6COxw<&XC=anipH-Cd+D<6yskYaCNZu0+#3O`=o&%&npagv7vuSOZ#8Wn3j&f za_Rgw&5w{hvR_bPUYrKl8bGdHe{RQj=ip|?xzZ*yEHt@G7zi)3aiTODqX32wJr_T= z`t<S#iw07$isid*w32nYVnrQk>LUv(BeYjG+&cV<YAqXvOaKe&oDpLNGQK|6gC`n; zO30eW!73#La}c~{|1k1{z$+n}KNvPA@1DKaku2bc6srdxRjjfLFX>*mT*S9+cJK&i z{FsC%QF#}Y&zXXwPzrf4Os%DpW2p-MFE$ktF$8o{HaXk)=jsEH2-C6qKr~1!um+=p zT(2-$p8X#<!82_HXN3l{+OJLQxe0-QO$Zj{s`M|C<rAF|rNl6u;g0<Am3#05z^~lR zPuEwDrGR-51OhI^6i5GCoedz3hVUOkC^oQ0W3`aC%IZhb)j1+3tZrhrWxR1=@<v={ zcbkj;=8tyZ@AGY}O^r}u2xVahBe}NZ4MghMr1D(+5wd|zWjf{S?gqc!jb|Xr#(*cO zoTtYm98eh42cB6d!Z!Jrw&1b9QOO{0Sc00E>%V_;AjcN5>Lt#+jOky^HTQnlwE7kY z5^cmA;;1*IUK}nl+5ATU;yCXsxV5lmjH6W3qu_mTYTNY=AVC1`$*aW)%L4uE^>W;^ zk%-}-%l60PjtailTD)lp7UB-7jUV}&zjIU|CitxAAiOz*&M$Wokg*wr1qDH3oqT~K zX#xXiA2ygqS_0%F$b}|T!btigxmErHr{lpWn0^9>Oni1aO1Bg~&z^71vs#(=MC}GO zqYixaOJ<(xFieAmAj?%e!6^ju?_qv>W9d(i&2w}-4*G5W9~Pzh3LT{KKOMj=riY+1 z?Mi1Z9LN^d?891x)+0-1?7V?H13AZ%&qi`HDyN_~8V?l#JrbdAq`y>8cY8n(>drvc zozdw4JXPQ9Kj_><c&_3YaRkgt$wt7zNPc?zsqwSXXkf6rWx}z^QW#eV2Vn5HJe?P3 zj)-$}*(|~ya85c3;%r-`3~XWu!_UF8qIPkNS6V7K<^9{{9O(B~b^I6!eBKWjpSI53 zIqbC804s#i*8KP7W`d(eZLpMc-j!BQ(&J~TZpOx-P6OG26B`()w2*HY=Z69#xjC(r zfo4iQv&(E;3hbcnnL`5PR@;ZZP`6EQ2~RcUJ4(6J2c}tw3a;hU7cX5y{Acv~+KsiM z3t2Ux%=iG29^}7Q|D2=L3>41=nZL&Kcw!#aars7bunrP>yKeNPk`#L%iV)@-Fq460 a?^qf7V6<g?8|zI_#z}Y2A^?mpF8v?7>nITb literal 0 HcmV?d00001 diff --git a/pandora_console/images/candado_login.png b/pandora_console/images/candado_login.png index 149f2ef12cd24d4dbb7ff15459302a8e06d70610..3c51ef775e4627daf91c99231521ee0477bfb639 100644 GIT binary patch delta 449 zcmV;y0Y3h+1>6H6iBL{Q4GJ0x0000DNk~Le0000R0000R2nGNE0FBi2Rgoble*u0; zL_t(|+O(ECZo@DPhV8~f$K0SUe1N7WsJnP}#!gMgjy*wogES{-)^3`;#5qBH0i((d z(i5~K@EZ_ZKPXutAkY>>eI_Z&3<C?vvMeT*(ugrt(x{4}I7{q9A!I>n15jHSv?bvC zWEi|T(wJka!r=FX;U&*K4tW^~e;oV7#=OarHY-~n!yc^xX8q>m8NzqOD}z+ex(3K{ zOY3ykx~mbda%kNLf_%Vp)5aQh2R#G|kSEo$v4%B=;zy9%6Ljnf3ygZ2EaAwJ-{VUe zb{N^~0d=TR0$K#aDcl=jw3Rb}l_ZRt37{s|YiZ6>4=KuB4~Q3WfpOwre{d~n8^g!} zbl+UIbdYwWzNPuK^-P(!I-Ylz3S%ss^8(8$bStACS3?)Cj|1}D^L!DQvqTOyDTVLX zXPqezjwmT?>jCy}k6G8Mx~_GSBq!XF*A6%SYgZdF>$4zWMZhnkWs?XO_*1(Bvu#r6 r@RFf7Mj>mo1N`4A$2#Lb7XbzUyRUX+BfzA~00000NkvXXu0mjfk-5T7 delta 664 zcmV;J0%!f)1F{7niBL{Q4GJ0x0000DNk~Le0000Z0000Z2nGNE0cqZY&ygV~e*#oV zL_t(|+G1cJ1f-;-{)1>1C}%&Aa)3!PAt^k7O)Fd_Kmg%49K|e{AQL`q3LqLFfEdvP z4S>{n5c}D)XN=g~$N*K~2*S85-w!nb<RJlMoh(S~LXb(wCcpqd01<^4aRkBzptXiL zy$fY0;Br#}P!bjk53pK?&B3s+e`3NVfee_4@f{PsXvP<*7^wvyfQZsWmPTZ!0dWH% zF+zqE;PN9baYif(K`}d@kY(u6f-Oqo(fAjDIFXRSEJWCB2z9AHkP0B%AY$_kwj}8Y z&Azz618m8bY5*XBsDhY@N!7f(ybPZ|fBryJ5rU@qJ$lIn1cJbD`9M@me?gPJ0CGSA z#Xt%3JwA)E<*Ni7;s!()EI?N*z#{wsTLNSuv21xjY{n!ewKf7>+CWk{i3QY?TG%FH zt$9f>q!1Lq(0oO<A^v3LW;Eb{l=v8ETDFiIJAs4>Cq`U}3T6OM%?6@!G1M!dTx@{U z9-$oo2(Uqg$ST00%_LA3e@eiS*%t!w1Z)K%)f@wjGf*QF)@IuPEgUXD<w3<(K2j?h zB<@J8qeykkeW*h~)uJK+wdbLU?E_G)AT@F{dikq>Eg#_ku<}R%)VQLmV~{&AuxKIB z?D>FH$_h{|nxJJ}J%yPCRC*^;<QSks*5hl?kqGdnHDaPkfQm(lZUQYT0^~9U)UaZN zVM4VrEgjQ{r3`5tD96kPrm249{t=McKTwWgfYqYZNM9^OrVG5~4+$d&6t(Ucpk+fM y6+)0;E0N?{8(JB{I+M7f1y=fQ#L*WR`~U!`hRDD9b$<8&0000<MNUMnLSTZ*E)97A diff --git a/pandora_console/images/saml_login.png b/pandora_console/images/saml_login.png new file mode 100644 index 0000000000000000000000000000000000000000..414b590d84710b509462bbf63b63b6c2d8458766 GIT binary patch literal 305 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5XE_=E-hE&{2N|0b(+z@o2L+`<}XJQOXcoy8@-d*<gmV+qw z0=Dz)NsK0@{0$a@85bEh={891o7WKKUZj)ABE?tqu~tVf{lGKfBp%l?juTBR85e38 zk^(B&1rj9{3mB!=h(|Q=u&z+>NMOEjsMX<Hos5*Do^{9ZggOPi2DM3l9X9hsdX&s$ z77=DXu<!uOS3Zt2?6)lDcbsTr447c%bd!6*GllL(rzec66M0T4%d^?cG;*9Qs_~V@ zX>Z5br;Q@1CQI(<F!Z{t5*1yXAQHgGz{JDAX6m!8Bj~#>(0dG?u6{1-oD!M<^T=mW literal 0 HcmV?d00001 diff --git a/pandora_console/images/saml_login_hover.png b/pandora_console/images/saml_login_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..7f76c0e5ad739c74f4de9cfc71d92ba5f672e281 GIT binary patch literal 276 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xwt2cZhE&{2N|0b(+z@o2L+``?|Nj{jQW>7cC8VU>aS)yD zz{dRX_x~9W>;$X>4i`8z=y*#sO0hP4sZ|hDSn!QeKwT(RL-{dd%5`;zSPrgvKP{R% zLki?N4t_krbc8Elw~(VC*OUm3l=sIUT1+_2_o&duUO?PI_+;IJ$Tl4nww25x!ptle zlxJK~U|N~ou<5yTGi#(y<0TKarxW>^=lOJ=&0q}C)LL-xsl((&Ng_Q=n;0D$7#Uth W#}%mCziJ2ifWgz%&t;ucLK6VA%VDbk literal 0 HcmV?d00001 diff --git a/pandora_console/images/user_login.png b/pandora_console/images/user_login.png new file mode 100644 index 0000000000000000000000000000000000000000..4821ba6d52c1e2b8b3256ed08473ebef74d63beb GIT binary patch literal 459 zcmV;+0W|)JP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzZAnByRCwB~Rf}=MAPfahzy|RKWrHw6 zx<R`^Hz=LJ*9mYZ$OuU%a5hLbz#C90RdSf{QJcIwoewPONgyOC7ziO4_?TpSFQweK zY`con9>jroSUQlW==U1;!Y}aK3obxefeewcuIOsgK@42y6N%1bWJpwo=ty>o<6I@i zQ@F(<h}gbFFl3x#)IOBq<MSsH%*5s{G-Qs&hBj<kakSsZRrC%rLfIX}ouJYk$>)_| z1M(>zhcEIeI(kHNA^H`=*{YDm`M59xJoi(<_=Q1G(!qc=5@6MQi^l_lRvkl0+@pg8 zGxe4nJ{Sbgh5i0aPIc=m?W6Y4T*FSs3sX>htGr@Wu-PnvrjF<;Jt~J?CHmdMU(_m0 zM%i-uP^nd<j*geKNpWKIqU*q+Y<=9HWJ0o~+n+NdvW1Zz?Ezl$Yi%ZM!~fy9W7Gc8 zvA>xC43eIPP;1}}wV^MWWSZ_qM~&>nnIAs_3;?8`)ftzJv>5;Z002ovPDHLkV1n2e B%hLb= literal 0 HcmV?d00001 diff --git a/pandora_console/images/user_login_hover.png b/pandora_console/images/user_login_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..14705007e54cce5d1136f318602f7909ca077262 GIT binary patch literal 561 zcmV-10?z%3P)<h;3K|Lk000e1NJLTq0015U0015c1^@s6J20-I0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUz(@8`@RCwC#R?AVtFc7s}flF`&#Hk>@ zafDPrQbFPd0Mmd&1-OGaM@~2u1gO9zxCC}*UKpWStz^RIk~g#C8Eds~wc3xO=!`!? zJVyE9`Qn;BGm_j|>Phw_?d|3J@FT=TmeOZUvLa!lEy)|m7#Ycggq>pDN0N=tf!IS@ z(B}z+6&Y&-^zRUnrKTS%MiwAt?@KEJg%R$K<kdVO>2QQ<kT=1^@chNz2xn@9)CNc7 zUT}Oaoji8j=>dsS3eIS-9bF^zQ~KYViixn9l_QfBxCuzsFFIsn!`A@v$VbfCTMGZP zZ<cIDvOpwdV$|v2%ib{{TOCfl&`vx<ok~apcwAB0!M2k)M{|&nhY(ZLB)!hwFWqr} zVsz7xXe7VT|AQP)M%+^slEHSpx*SS`#ff8M<2$L@xrF>siT9W?Qd#iEjY3>1Ygfo@ zCvl6+ER?d4;H-VJm0_r~PGU@$Mrv`Mj7{y%WS~ah_x5TIS&jz(IXFo8{<cau512^y zXf32`h?OS}lPr<ttH926OwbB#lBZcI&E$}Wz$tJ(1QMmW^M*N|J!3Iwq~6YjOq~YQ zuw5BbjdaxW7G-gK-eyMA?;$%Wd(ZfHd<ZZAom;fh+xvWB00000NkvXXu0mjfeFXsN literal 0 HcmV?d00001 diff --git a/pandora_console/images/usuario_login.png b/pandora_console/images/usuario_login.png index cd333a1f46db0c0d52af88c20eb1b3adfb45c196..78e65a607d076b184140e06371e908989648b258 100644 GIT binary patch delta 427 zcmV;c0aX5-1;zs*iBL{Q4GJ0x0000DNk~Le0000R0000R2nGNE0FBi2Rgoble*tJo zL_t(|+RT<QPJ}=dhFSCg9AOOya6Ez95UpHqAf=V=2{wBIy@Birc5P`KJ4@_rNGL7w z2L5CI0?7{Z7$(M-yui->@bM<^{SZZ-k!9K0*lT7Z0Sg>fNYz=^$aPtkIv5O~2ORDP zBsqY^WEi*X#UX2vCjd4!K`bone@>uDTskRiA=If5upl9YH9}n*0=5zAo<qPM1=VR+ z>x*ExiP@fOWMu>KfB&Jzd?lPO#TlyTBBxw?Wks6nTV#RXxesjHX?s)MxdB>i?1{7X zv+d9=#jwtk_M>1$4Xe9C?la}1zMC8l6t=Rg-!NTauFstff~w{&H}G+tf7r)%gpuH( z)nCD)PQ&~kZ`6VA-$-Cp2vEQE;{kixO@wX6c;k8ksHJ)TiUXUvuItY<O}}t@;Q_nE z?tF-01ik?{v)GZXqFaD=Q@^f^(awk7XUOF~qxStsRkWdF4y@_6cfMwv9sDi80800B VvV)3sTL1t607*qoM6N<$0fI8H#99CV delta 643 zcmV-}0(||(1DypSiBL{Q4GJ0x0000DNk~Le0000Z0000Z2nGNE0cqZY&ygV~e*!;A zL_t(|+G1e92c)E={sZxQ5Ss}}yb*{6;DSIE4nV3Nn|1*h8z6viTF?Np1la<RIf)<! zBg_d<i3!Ns6hJgU0O4}*e`GNx1|k3xHWwk8xF7ByWC>*cvuDr1@&Exu6vAl|vMHoF z911Q#=?}Pk2eQflYK;K0)lAp|f0K}P1l<&fCbs}zT5v!Y0|+33Aqq{Muw*6(^w<Yt zf(hAx1gJ-m)9QOzoRbm&2XKgQB-Nn%Ag@3%D6bhp<EtO&Dg%OH1kHBuiHNC0pur39 zxu}516kSg+*07}}bby|RnD8ia#9>AwNg0t;01!a5N3a42isutmgrFJFe~%^RE&#*D zkQ77y6B9#3mkFenV^lXp5Q~^0(S|@{Vn5XXpi-?6$_{|lkc2WNDCeF>DxMvoG{|5F zq}1Dh&yfGbgagU7$biQVMTRsIq3;331r#ZT(*t7j4l%`n1Gbux>Hr|X7^zfv86ef9 z7jRX_G;<6zpC;f@0?v9se}`S5nPZ^M)B7Z7L8*wTorw}iR9{ca98GF^ctET|W>Q`9 z`Sa%!yu7@is4^hZ;g&!>KWGv%&^+D<t*Iv9X<~v}gCI2qIJ-gQCSXw811<h9Ky%9n z9O^;MjDBL(6YUtF!RtX)D;0_)kV6zn?iL_9B!Ef|VSpBl^C?L)Sq2Q$1pzdztVsk1 z$aW00)%1aij+sbl$S6|DL4iQeZJ<is1nTSJOMrO50-z%jX<2K79F~tGfq#IG8%zW` d;sL`@1OVcHzaRo-pkn|4002ovPDHLkV1mtc19t!b diff --git a/pandora_console/include/functions_config.php b/pandora_console/include/functions_config.php index 3152430931..9ba9ace3ff 100644 --- a/pandora_console/include/functions_config.php +++ b/pandora_console/include/functions_config.php @@ -1828,11 +1828,11 @@ function config_process_config() } if (!isset($config['custom_title1_login'])) { - config_update_value('custom_title1_login', __('WELCOME TO PANDORA FMS')); + config_update_value('custom_title1_login', __('PANDORA FMS')); } if (!isset($config['custom_title2_login'])) { - config_update_value('custom_title2_login', __('NEXT GENERATION')); + config_update_value('custom_title2_login', __('ONE TOOL TO MONITOR THEM ALL')); } if (!isset($config['custom_docs_url'])) { diff --git a/pandora_console/include/styles/login.css b/pandora_console/include/styles/login.css index f7066ba92c..3836dbdfb8 100644 --- a/pandora_console/include/styles/login.css +++ b/pandora_console/include/styles/login.css @@ -29,41 +29,11 @@ div#error_buttons a { width: 100%; z-index: -9999; position: absolute; - background-image: url("../../images/backgrounds/background_pandora_console_keys.jpg"); + background: linear-gradient(74deg, #02020255 36%, transparent 36%), + url("../../images/backgrounds/background_pandora_console_keys.jpg"); background-repeat: repeat; } -/*@media screen and (max-width: 1024px) { /* Specific to this particular image */ -/* #login_body { - left: 50%; - margin-left: -512px; /* 50% */ -/* } -} -@media screen and (max-width: 1100px) { /* Specific to this particular image */ -/* #login_body { - background-image: url("../../images/backgrounds/background_pandora_console_keys.jpg"); - background-repeat: repeat; - } -} -@media screen and (max-width: 1400px) { /* Specific to this particular image */ -/* #login_body { - background-image: url("../../images/backgrounds/background_pandora_console_keys.jpg"); - background-repeat: repeat; - } -} -@media screen and (max-width: 2000px) { /* Specific to this particular image */ -/* #login_body { - background-image: url("../../images/backgrounds/background_pandora_console_keys.jpg"); - background-repeat: repeat; - } -} -@media screen and (min-width: 2000px) { /* Specific to this particular image */ -/* #login_body { - background-image: url("../../images/backgrounds/background_pandora_console_keys.jpg"); - background-repeat: repeat; - } -}*/ - p.log_in { color: #fff !important; padding: 0px 10px; @@ -77,7 +47,6 @@ h1#log_f { } div#error_login { - text-align: center; margin-top: 5px; margin-left: 5px; width: 75%; @@ -104,8 +73,11 @@ div#login_f { width: 100%; position: absolute; bottom: 10px; - color: #fff; + color: #878787; text-align: center; + font-family: "Open Sans", sans-serif; + font-weight: 700; + font-size: 8.5pt; } /* @@ -118,23 +90,17 @@ div#login_f { div#header_login { width: 100%; height: 65px; - background-color: rgba(255, 255, 255, 0.06); -} - -div#icon_custom_pandora { - float: left; - margin-top: 5px; - margin-left: 4%; } div#list_icon_docs_support { - float: right; - margin-top: 8px; - margin-right: 4%; + float: left; + margin-top: 25px; + margin-left: 5%; } div#list_icon_docs_support ul { margin-top: 5px; + line-height: 36px; } div#list_icon_docs_support ul li { @@ -145,6 +111,11 @@ div#list_icon_docs_support ul li { font-size: 10pt; } +div#list_icon_docs_support ul li a { + color: #979797; + font-size: 10pt; +} + li#li_margin_left { margin-left: 30px; } @@ -162,14 +133,6 @@ div.login_page { float: left; } -div.login_page form { - border-right: 1px solid #868686; - padding-top: 30px; - padding-bottom: 50px; - min-width: 400px; - max-height: 600px; -} - div.login_logo_icon { margin-bottom: 40px; text-align: center; @@ -177,7 +140,7 @@ div.login_logo_icon { div.login_logo_icon img { margin: 0 auto; - width: 150px; + max-width: 70%; } div.login_double_auth_code, @@ -186,27 +149,36 @@ div.login_pass { margin: 0 auto; width: 70%; height: 40px; - background-color: rgba(255, 255, 255, 0.2) !important; margin-bottom: 25px; min-width: 260px; + background-color: #fff; + opacity: 0.77; + box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1); + border-radius: 3px; } -div.login_nick img, -div.login_pass img { - vertical-align: middle; - margin: 3px; +div.login_nick input { + background-image: url("../../images/usuario_login.png"); +} + +div.login_pass input { + background-image: url("../../images/candado_login.png"); } div.login_nick input, div.login_pass input { - background-color: rgba(255, 255, 255, 0) !important; border: 0px !important; - color: white !important; - border-radius: 0px; - width: 89%; + color: #343434; + border-radius: 3px; + width: 100%; height: 40px; - font-size: 9pt; + font-size: 10pt; padding: 0px !important; + background-repeat: no-repeat; + background-size: 27px; + background-position: left center; + text-indent: 35px; + font-family: "Open Sans", sans-serif; } div.login_nick input:focus, @@ -224,46 +196,76 @@ div.login_pass input:-webkit-autofill:focus, div.login_pass input:-webkit-autofill:active { transition: background-color 10000s ease-in-out 0s; -webkit-box-shadow: 0 0 0px 0px transparent inset !important; - -webkit-text-fill-color: white !important; + -webkit-text-fill-color: #343434 !important; border: 0px; width: 89%; } div.login_nick input::-webkit-input-placeholder, div.login_pass input::-webkit-input-placeholder { - color: white; + color: #343434; } -div.login_pass img, -div.login_nick img { - width: 30px; -} - -div.login_pass div, -div.login_nick div { - float: left; - width: 11%; -} - -div.login_button { +div.login_button, +div.login_button_saml { margin: 0 auto; - width: 70%; + width: 40%; height: 40px; - background-color: rgb(25, 25, 25); - border: 1px solid white; min-width: 260px; + margin-bottom: 20px; } div.login_button input { width: 100%; - background-color: rgb(25, 25, 25) !important; + background-color: #82b92e !important; text-align: center; - border: 0px; - border-radius: 0px; height: 40px; padding: 0px; - font-size: 9pt; - color: white; + font-size: 11pt; + color: #fff !important; + border: 1px solid #82b92e; + border-radius: 3px; +} + +div.login_button_saml input { + border: 1px solid #fff; + background-color: #fff !important; + color: #000 !important; + background-image: url("../../images/saml_login.png"); + background-repeat: no-repeat; + background-position: right 5% center; +} + +div.login_button input:hover { + background-color: #fff !important; + color: #000 !important; + border: 1px solid #fff !important; +} + +div.login_button_saml input:hover { + background-image: url("../../images/saml_login_hover.png"); + background-color: transparent !important; + color: #fff !important; + border: 1px solid #fff !important; +} + +#remove_button input { + background-image: url("../../images/user_login.png") !important; + background-repeat: no-repeat; + background-position: right 5% center; +} + +#remove_button input:hover { + background-image: url("../../images/user_login_hover.png") !important; +} + +.login_back input { + background-image: url("../../images/back_login.png") !important; + background-position: left 5% center !important; +} + +.login_back input:hover { + background-image: url("../../images/back_login_hover.png") !important; } div.login_data { @@ -307,6 +309,21 @@ div.img_banner_login img { min-height: 50%; } +.reset_password { + width: 70%; + height: 40px; + margin-right: auto; + margin-left: auto; + margin-top: 20px; + text-align: center; +} + +.reset_password a { + color: #ddd !important; + font-family: "Open Sans", sans-serif; + font-size: 8.5pt; +} + @media all and (max-width: 1200px) { span.span1 { font-size: 30pt; From bf0e8633ff9d4a39ffa81b4051c12455cfc58277 Mon Sep 17 00:00:00 2001 From: manuel <manuel.montes@artica.es> Date: Mon, 11 Mar 2019 12:36:52 +0100 Subject: [PATCH 16/50] Added button servers list in header Former-commit-id: 96d9f7a49d617b0a9f04df601c41bbce71009e38 --- pandora_console/general/header.php | 37 ++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/pandora_console/general/header.php b/pandora_console/general/header.php index cfbf070a6a..427aca7cdf 100644 --- a/pandora_console/general/header.php +++ b/pandora_console/general/header.php @@ -30,6 +30,33 @@ require_once 'include/functions_notifications.php'; $notifications_numbers['last_id'] ).'</div>'; + // ======= Servers List =============================================== + $servers_list = '<div id="servers_list">'; + $servers = []; + $servers['all'] = (int) db_get_value('COUNT(id_server)', 'tserver'); + if ($servers['all'] != 0) { + $servers['up'] = (int) servers_check_status(); + $servers['down'] = ($servers['all'] - $servers['up']); + if ($servers['up'] == 0) { + // All Servers down or no servers at all. + $servers_check_img = html_print_image('images/header_down_gray.png', true, ['alt' => 'cross', 'class' => 'bot', 'title' => __('All systems').': '.__('Down')]); + } else if ($servers['down'] != 0) { + // Some servers down. + $servers_check_img = html_print_image('images/header_warning_gray.png', true, ['alt' => 'error', 'class' => 'bot', 'title' => $servers['down'].' '.__('servers down')]); + } else { + // All servers up. + $servers_check_img = html_print_image('images/header_ready_gray.png', true, ['alt' => 'ok', 'class' => 'bot', 'title' => __('All systems').': '.__('Ready')]); + } + + unset($servers); + // Since this is the header, we don't like to trickle down variables. + $servers_check_img_link = '<a class="white" href="index.php?sec=advanced&sec2=advanced/servers&refr=60">'; + $servers_check_img_link .= $servers_check_img; + $servers_check_img_link .= '</a>'; + }; + $servers_list .= $servers_check_img_link.'</div>'; + + // ======= Alerts =============================================== $check_minor_release_available = false; @@ -48,7 +75,7 @@ require_once 'include/functions_notifications.php'; } - // Chat messages + // Chat messages. $header_chat = "<div id='header_chat'><span id='icon_new_messages_chat' style='display: none;'>"; $header_chat .= "<a href='index.php?sec=workspace&sec2=operation/users/webchat'>"; $header_chat .= html_print_image('images/header_chat_gray.png', true, ['title' => __('New chat message')]); @@ -180,7 +207,7 @@ require_once 'include/functions_notifications.php'; $header_autorefresh_counter = '<div id="header_autorefresh_counter" style="'.$display_counter.'">'.$autorefresh_link_open_txt.$autorefresh_txt.$autorefresh_link_close.$autorefresh_additional.'</div>'; - // qr + // Qr. if ($config['show_qr_code_header'] == 0) { $show_qr_code_header = 'display: none;'; } else { @@ -209,7 +236,7 @@ require_once 'include/functions_notifications.php'; }); </script> <?php - // User + // User. if (is_user_admin($config['id_user']) == 1) { $header_user = html_print_image('images/header_user_admin_green.png', true, ['title' => __('Edit my user'), 'class' => 'bot', 'alt' => 'user']); } else { @@ -218,13 +245,13 @@ require_once 'include/functions_notifications.php'; $header_user = '<div id="header_user"><a href="index.php?sec=workspace&sec2=operation/users/user_edit">'.$header_user.'<span> ('.$config['id_user'].')</span></a></div>'; - // Logout + // Logout. $header_logout = '<div id="header_logout"><a class="white" href="'.ui_get_full_url('index.php?bye=bye').'">'; $header_logout .= html_print_image('images/header_logout_gray.png', true, ['alt' => __('Logout'), 'class' => 'bot', 'title' => __('Logout')]); $header_logout .= '</a></div>'; echo '<div class="header_left">'.$header_autorefresh, $header_autorefresh_counter, $header_qr, $header_chat.'</div> - <div class="header_center">'.$header_searchbar, $header_discovery.'</div> + <div class="header_center">'.$header_searchbar, $header_discovery, $servers_list.'</div> <div class="header_right">'.$header_user, $header_logout.'</div>'; ?> </div> <!-- Closes #table_header_inner --> From 8f9beccf769474bacc54afe0ee7583dcb1027448 Mon Sep 17 00:00:00 2001 From: manuel <manuel.montes@artica.es> Date: Mon, 11 Mar 2019 12:47:27 +0100 Subject: [PATCH 17/50] Fixed url Former-commit-id: 7bed92d53f59a0b01034d3630dcddce8a7bc5cfa --- pandora_console/general/header.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandora_console/general/header.php b/pandora_console/general/header.php index 427aca7cdf..7addef057f 100644 --- a/pandora_console/general/header.php +++ b/pandora_console/general/header.php @@ -50,7 +50,7 @@ require_once 'include/functions_notifications.php'; unset($servers); // Since this is the header, we don't like to trickle down variables. - $servers_check_img_link = '<a class="white" href="index.php?sec=advanced&sec2=advanced/servers&refr=60">'; + $servers_check_img_link = '<a class="white" href="index.php?sec=gservers&sec2=godmode/servers/modificar_server&refr=60">'; $servers_check_img_link .= $servers_check_img; $servers_check_img_link .= '</a>'; }; From f4208a35f22112d83b42b67a65fe859aaf76bc49 Mon Sep 17 00:00:00 2001 From: Luis Calvo <luis.calvo@artica.es> Date: Mon, 11 Mar 2019 13:25:28 +0100 Subject: [PATCH 18/50] Changede sec=reporting to sec=network on visual console link to another console Former-commit-id: 5cbbae6f99993a7b250feea354eb197fe6355969 --- pandora_console/include/functions_visual_map.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pandora_console/include/functions_visual_map.php b/pandora_console/include/functions_visual_map.php index 3506c46220..5344eb15ee 100755 --- a/pandora_console/include/functions_visual_map.php +++ b/pandora_console/include/functions_visual_map.php @@ -476,7 +476,7 @@ function visual_map_print_item( } } else if ($is_a_link_to_other_visualconsole) { if (!is_metaconsole()) { - $url = $config['homeurl'].'index.php?sec=reporting&sec2=operation/visual_console/render_view&pure='.$config['pure'].'&id='.$layoutData['id_layout_linked']; + $url = $config['homeurl'].'index.php?sec=network&sec2=operation/visual_console/render_view&pure='.$config['pure'].'&id='.$layoutData['id_layout_linked']; } else { $url = 'index.php?sec=screen&sec2=screens/screens&action=visualmap&pure=0&id_visualmap='.$layoutData['id_layout_linked'].'&refr=0'; } @@ -567,7 +567,7 @@ function visual_map_print_item( if (METACONSOLE == 1) { $url = $config['homeurl'].'index.php?sec=screen&sec2=screens/screens&action=visualmap&pure=0&id_visualmap='.$layoutData['id_layout_linked'].'&refr=300'; } else { - $url = $config['homeurl'].'index.php?sec=reporting&sec2=operation/visual_console/render_view&pure='.$config['pure'].'&id='.$layoutData['id_layout_linked']; + $url = $config['homeurl'].'index.php?sec=network&sec2=operation/visual_console/render_view&pure='.$config['pure'].'&id='.$layoutData['id_layout_linked']; } } else { if (METACONSOLE == 1) { @@ -581,7 +581,7 @@ function visual_map_print_item( case LABEL: if ($layoutData['id_layout_linked'] != 0) { // Link to a map - $url = $config['homeurl'].'index.php?sec=reporting&sec2=operation/visual_console/render_view&pure='.$config['pure'].'&id='.$layoutData['id_layout_linked']; + $url = $config['homeurl'].'index.php?sec=network&sec2=operation/visual_console/render_view&pure='.$config['pure'].'&id='.$layoutData['id_layout_linked']; } break; @@ -590,7 +590,7 @@ function visual_map_print_item( if ($layoutData['id_layout_linked'] != 0) { // Link to a map if (empty($layoutData['id_metaconsole'])) { - $url = 'index.php?sec=reporting&sec2=operation/visual_console/render_view&pure='.$config['pure'].'&id='.$layoutData['id_layout_linked']; + $url = 'index.php?sec=network&sec2=operation/visual_console/render_view&pure='.$config['pure'].'&id='.$layoutData['id_layout_linked']; } else { $pure = get_parameter('pure', 0); $url = 'index.php?sec=screen&sec2=screens/screens&action=visualmap&pure='.$pure.'&id_visualmap='.$layoutData['id_layout_linked'].'&refr=0'; @@ -638,7 +638,7 @@ function visual_map_print_item( } else if ($layoutData['id_layout_linked'] > 0) { // Link to a map if (empty($layoutData['id_metaconsole'])) { - $url = 'index.php?sec=reporting&sec2=operation/visual_console/render_view&pure='.$config['pure'].'&id='.$layoutData['id_layout_linked']; + $url = 'index.php?sec=network&sec2=operation/visual_console/render_view&pure='.$config['pure'].'&id='.$layoutData['id_layout_linked']; } else { $pure = get_parameter('pure', 0); $url = 'index.php?sec=screen&sec2=screens/screens&action=visualmap&pure='.$pure.'&id_visualmap='.$layoutData['id_layout_linked'].'&refr=0'; From fcab1ae6128517026bd016a9302fa5ccbb8a261e Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Mon, 11 Mar 2019 15:09:31 +0100 Subject: [PATCH 19/50] WIP NetworkMap class Former-commit-id: da5ce8681313cdf5c5a7ec7a005c3ebd273fea43 --- .../include/class/NetworkMap.class.php | 899 +++++++++++++++++- 1 file changed, 876 insertions(+), 23 deletions(-) diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php index a626fca23c..ead73b1254 100644 --- a/pandora_console/include/class/NetworkMap.class.php +++ b/pandora_console/include/class/NetworkMap.class.php @@ -46,6 +46,34 @@ class NetworkMap */ public $idMap; + /** + * Content of tmap. + * + * @var array + */ + public $map; + + /** + * Data origin, network. + * + * @var string + */ + public $network; + + /** + * Data origin, group id. + * + * @var integer + */ + public $idGroup; + + /** + * Data origin, Discovery task. + * + * @var integer + */ + public $idTask; + /** * Graph definition * @@ -87,23 +115,22 @@ class NetworkMap /** * Base constructor. * - * @param array $options Could define: - * id_map => target map to be painted. - * graph => target graph (already built) + * @param mixed $options Could define in array as: + * id_map => target discovery task id. + * id_group => target group. + * network => target CIDR. + * graph => target graph (already built). * nodes => target agents or nodes. * relations => target array of relationships. - * mode => simple (0) or advanced (1) - * map_options => ? + * mode => simple (0) or advanced (1). + * map_options => Map options. * * @return object New networkmap manager. */ - public function __construct($options=[]) + public function __construct($options=false) { + $recreate = true; if (is_array($options)) { - if (isset($options['id_map'])) { - $this->idMap = $options['id_map']; - } - if (isset($options['graph'])) { $this->graph = $options['graph']; } @@ -123,6 +150,33 @@ class NetworkMap if (isset($options['map_options'])) { $this->mapOptions = $options['map_options']; } + + // Load from Discovery task. + if ($options['id_map']) { + $this->idMap = $options['id_map']; + // Update nodes and relations. + $this->loadMap(); + + if (empty($this->nodes) + || empty($this->relations) + ) { + $this->createMap(); + } + } else { + if ($options['id_group']) { + $this->idGroup = $options['id_group']; + } + + if ($options['id_task']) { + $this->idTask = $options['id_task']; + } + + if ($options['network']) { + $this->network = $options['network']; + } + + $this->createMap(); + } } return $this; @@ -130,6 +184,814 @@ class NetworkMap } + /** + * Creates a new map based on a target. + * + * Target is specified from constructor arguments. + * options: + * - id_task => create a map from task. + * - id_group => create a map from group. + * - network => create a map from network. + * + * @return void + */ + public function createMap() + { + if ($this->idMap) { + $this->loadMap(); + + return; + } + + if ($this->network) { + $this->nodes = networkmap_get_new_nodes_from_ip_mask( + $this->network + ); + } + } + + + /** + * Loads a map from a target map ID. + * + * @return void. + */ + public function loadMap() + { + if ($this->idMap) { + $this->map = db_get_row('tmap', 'id', $this->idMap); + + // Retrieve or update nodes and relations. + $this->getNodes(); + $this->getRelations(); + + // Nodes and relations. + $this->graph = networkmap_process_networkmap($this->idMap); + } + } + + + /** + * Return nodes of current map. + * + * @return array Nodes. + */ + public function getNodes() + { + if ($this->nodes) { + return $this->nodes; + } + + if ($this->idMap !== false) { + if (enterprise_installed()) { + // Enterprise environment: LOAD. + $this->nodes = enterprise_hook( + 'get_nodes_from_db', + [$this->idMap] + ); + } + } + + return $this->nodes; + + } + + + /** + * Return relations of current map. + * + * @return array Relations. + */ + public function getRelations() + { + if ($this->relations) { + return $this->relations; + } + + if ($this->idMap !== false) { + if (enterprise_installed()) { + $this->relations = enterprise_hook( + 'get_relations_from_db', + [$this->idMap] + ); + } + } + + return $this->relations; + + } + + + /** + * Transform node information into JS data. + * + * @return string HTML code with JS data. + */ + public function loadMapData() + { + $networkmap = $this->map; + $networkmap['filter'] = json_decode( + $networkmap['filter'], + true + ); + + // Hardcoded. + $networkmap['filter']['holding_area'] = [ + 500, + 500, + ]; + /* + $this->graph['relations'] = clean_duplicate_links( + $this->graph['relations'] + ); + */ + $output .= '<script type="text/javascript"> + //////////////////////////////////////////////////////////////////// + // VARS FROM THE DB + //////////////////////////////////////////////////////////////////// + var url_background_grid = "'.ui_get_full_url('images/background_grid.png').'"; + var networkmap_id = '.$this->idMap.";\n"; + + if (!empty($map_dash_details)) { + $output .= 'var x_offs = '.$map_dash_details['x_offs'].";\n"; + $output .= 'var y_offs = '.$map_dash_details['y_offs'].";\n"; + $output .= 'var z_dash = '.$map_dash_details['z_dash'].";\n"; + } else { + $output .= "var x_offs = null;\n"; + $output .= "var y_offs = null;\n"; + $output .= "var z_dash = null;\n"; + } + + $output .= 'var networkmap_refresh_time = 1000 * '.$networkmap['source_period'].";\n"; + $output .= 'var networkmap_center = [ '.$networkmap['center_x'].', '.$networkmap['center_y']."];\n"; + $output .= 'var networkmap_dimensions = [ '.$networkmap['width'].', '.$networkmap['height']."];\n"; + $output .= 'var enterprise_installed = '.((int) enterprise_installed()).";\n"; + $output .= 'var node_radius = '.$networkmap['filter']['node_radius'].";\n"; + $output .= 'var networkmap_holding_area_dimensions = '.json_encode($networkmap['filter']['holding_area']).";\n"; + $output .= "var networkmap = {'nodes': [], 'links': []};\n"; + $nodes = $this->graph['nodes']; + + if (empty($nodes)) { + $nodes = []; + } + + $count_item_holding_area = 0; + $count = 0; + $nodes_graph = []; + + foreach ($nodes as $key => $node) { + $style = json_decode($node['style'], true); + $node['style'] = json_decode($node['style'], true); + + // Only agents can be show. + if (isset($node['type'])) { + if ($node['type'] == 1) { + continue; + } + } else { + $node['type'] = ''; + } + + $item = networkmap_db_node_to_js_node( + $node, + $count, + $count_item_holding_area + ); + if ($item['deleted']) { + continue; + } + + $output .= 'networkmap.nodes.push('.json_encode($item).");\n"; + $nodes_graph[$item['id']] = $item; + } + + $relations = $this->graph['relations']; + + if ($relations === false) { + $relations = []; + } + + // Clean the relations and transform the module relations into + // interfaces. + networkmap_clean_relations_for_js($relations); + + $links_js = networkmap_links_to_js_links($relations, $nodes_graph); + + $array_aux = []; + foreach ($links_js as $link_js) { + if ($link_js['deleted']) { + unset($links_js[$link_js['id']]); + } + + if ($link_js['target'] == -1) { + unset($links_js[$link_js['id']]); + } + + if ($link_js['source'] == -1) { + unset($links_js[$link_js['id']]); + } + + if ($link_js['target'] == $link_js['source']) { + unset($links_js[$link_js['id']]); + } + + if ($link_js['arrow_start'] == 'module' && $link_js['arrow_end'] == 'module') { + $output .= 'networkmap.links.push('.json_encode($link_js).");\n"; + $array_aux[$link_js['id_agent_start']] = 1; + unset($links_js[$link_js['id']]); + } + } + + foreach ($links_js as $link_js) { + if (($link_js['id_agent_end'] === 0) && $array_aux[$link_js['id_agent_start']] === 1) { + continue; + } else { + $output .= 'networkmap.links.push('.json_encode($link_js).");\n"; + } + } + + $output .= ' + //////////////////////////////////////////////////////////////////// + // INTERFACE STATUS COLORS + //////////////////////////////////////////////////////////////////// + '; + + $module_color_status = []; + $module_color_status[] = [ + 'status_code' => AGENT_MODULE_STATUS_NORMAL, + 'color' => COL_NORMAL, + ]; + $module_color_status[] = [ + 'status_code' => AGENT_MODULE_STATUS_CRITICAL_BAD, + 'color' => COL_CRITICAL, + ]; + $module_color_status[] = [ + 'status_code' => AGENT_MODULE_STATUS_WARNING, + 'color' => COL_WARNING, + ]; + $module_color_status[] = [ + 'status_code' => AGENT_STATUS_ALERT_FIRED, + 'color' => COL_ALERTFIRED, + ]; + $module_color_status_unknown = COL_UNKNOWN; + + $output .= 'var module_color_status = '.json_encode($module_color_status).";\n"; + $output .= "var module_color_status_unknown = '".$module_color_status_unknown."';\n"; + + $output .= ' + //////////////////////////////////////////////////////////////////// + // Other vars + //////////////////////////////////////////////////////////////////// + '; + + $output .= "var translation_none = '".__('None')."';\n"; + $output .= "var dialog_node_edit_title = '".__('Edit node %s')."';\n"; + $output .= "var holding_area_title = '".__('Holding Area')."';\n"; + $output .= "var edit_menu = '".__('Show details and options')."';\n"; + $output .= "var interface_link_add = '".__('Add a interface link')."';\n"; + $output .= "var set_parent_link = '".__('Set parent interface')."';\n"; + $output .= "var set_as_children_menu = '".__('Set as children')."';\n"; + $output .= "var set_parent_menu = '".__('Set parent')."';\n"; + $output .= "var abort_relationship_menu = '".__('Abort the action of set relationship')."';\n"; + $output .= "var delete_menu = '".__('Delete')."';\n"; + $output .= "var add_node_menu = '".__('Add node')."';\n"; + $output .= "var set_center_menu = '".__('Set center')."';\n"; + $output .= "var refresh_menu = '".__('Refresh')."';\n"; + $output .= "var refresh_holding_area_menu = '".__('Refresh Holding area')."';\n"; + $output .= "var ok_button = '".__('Proceed')."';\n"; + $output .= "var message_to_confirm = '".__('Resetting the map will delete all customizations you have done, including manual relationships between elements, new items, etc.')."';\n"; + $output .= "var warning_message = '".__('WARNING')."';\n"; + $output .= "var ok_button = '".__('Proceed')."';\n"; + $output .= "var cancel_button = '".__('Cancel')."';\n"; + $output .= "var restart_map_menu = '".__('Restart map')."';\n"; + $output .= "var abort_relationship_interface = '".__('Abort the interface relationship')."';\n"; + $output .= "var abort_relationship_menu = '".__('Abort the action of set relationship')."';\n"; + + $output .= '</script>'; + + return $output; + } + + + /** + * Show an advanced interface to manage dialogs. + * + * @return string HTML code with dialogs. + */ + public function loadAdvanceInterface() + { + $list_networkmaps = get_networkmaps($this->idMap); + if (empty($list_networkmaps)) { + $list_networkmaps = []; + } + + $output .= '<div id="open_version_dialog" style="display: none;">'; + $output .= __( + 'In the Open version of %s can not be edited nodes or map', + get_product_name() + ); + $output .= '</div>'; + + $output .= '<div id="dialog_node_edit" style="display: none;" title="'; + $output .= __('Edit node').'">'; + $output .= '<div style="text-align: left; width: 100%;">'; + + $table = null; + $table->id = 'node_details'; + $table->width = '100%'; + + $table->data = []; + $table->data[0][0] = '<strong>'.__('Agent').'</strong>'; + $table->data[0][1] = ''; + $table->data[1][0] = '<strong>'.__('Adresses').'</strong>'; + $table->data[1][1] = ''; + $table->data[2][0] = '<strong>'.__('OS type').'</strong>'; + $table->data[2][1] = ''; + $table->data[3][0] = '<strong>'.__('Group').'</strong>'; + $table->data[3][1] = ''; + + $output .= ui_toggle( + html_print_table($table, true), + __('Node Details'), + __('Node Details'), + false, + true + ); + + $table = null; + $table->id = 'interface_information'; + $table->width = '100%'; + + $table->head['interface_name'] = __('Name'); + $table->head['interface_status'] = __('Status'); + $table->head['interface_graph'] = __('Graph'); + $table->head['interface_ip'] = __('Ip'); + $table->head['interface_mac'] = __('MAC'); + $table->data = []; + $table->rowstyle['template_row'] = 'display: none;'; + $table->data['template_row']['interface_name'] = ''; + $table->data['template_row']['interface_status'] = ''; + $table->data['template_row']['interface_graph'] = ''; + $table->data['template_row']['interface_ip'] = ''; + $table->data['template_row']['interface_mac'] = ''; + + $output .= ui_toggle( + html_print_table($table, true), + __('Interface Information (SNMP)'), + __('Interface Information (SNMP)'), + true, + true + ); + + $table = null; + $table->id = 'node_options'; + $table->width = '100%'; + + $table->data = []; + $table->data[0][0] = __('Shape'); + $table->data[0][1] = html_print_select( + [ + 'circle' => __('Circle'), + 'square' => __('Square'), + 'rhombus' => __('Rhombus'), + ], + 'shape', + '', + 'javascript:', + '', + 0, + true + ).' <span id="shape_icon_in_progress" style="display: none;">'.html_print_image('images/spinner.gif', true).'</span><span id="shape_icon_correct" style="display: none;">'.html_print_image('images/dot_green.png', true).'</span><span id="shape_icon_fail" style="display: none;">'.html_print_image('images/dot_red.png', true).'</span>'; + $table->data['node_name'][0] = __('Name'); + $table->data['node_name'][1] = html_print_input_text( + 'edit_name_node', + '', + __('name node'), + '20', + '50', + true + ); + $table->data['node_name'][2] = html_print_button( + __('Update node'), + '', + false, + '', + 'class="sub"', + true + ); + + $table->data['fictional_node_name'][0] = __('Name'); + $table->data['fictional_node_name'][1] = html_print_input_text( + 'edit_name_fictional_node', + '', + __('name fictional node'), + '20', + '50', + true + ); + $table->data['fictional_node_networkmap_link'][0] = __('Networkmap to link'); + $table->data['fictional_node_networkmap_link'][1] = html_print_select( + $list_networkmaps, + 'edit_networkmap_to_link', + '', + '', + '', + 0, + true + ); + $table->data['fictional_node_update_button'][0] = ''; + $table->data['fictional_node_update_button'][1] = html_print_button( + __('Update fictional node'), + '', + false, + 'add_fictional_node();', + 'class="sub"', + true + ); + + $output .= ui_toggle( + html_print_table($table, true), + __('Node options'), + __('Node options'), + true, + true + ); + + $table = null; + $table->id = 'relations_table'; + $table->width = '100%'; + + $table->head = []; + $table->head['node_source'] = __('Node source'); + $table->head['interface_source'] = __('Interface source'); + $table->head['interface_target'] = __('Interface Target'); + + $table->head['node_target'] = __('Node target'); + $table->head['edit'] = '<span title="'.__('Edit').'">'.__('E.').'</span>'; + + $table->data = []; + $table->rowstyle['template_row'] = 'display: none;'; + $table->data['template_row']['node_source'] = ''; + $table->data['template_row']['interface_source'] = html_print_select( + [], + 'interface_source', + '', + '', + __('None'), + 0, + true + ); + $table->data['template_row']['interface_target'] = html_print_select( + [], + 'interface_target', + '', + '', + __('None'), + 0, + true + ); + + $table->data['template_row']['node_target'] = ''; + $table->data['template_row']['edit'] = ''; + + $table->data['template_row']['edit'] .= '<span class="edit_icon_correct" style="display: none;">'.html_print_image('images/dot_green.png', true).'</span><span class="edit_icon_fail" style="display: none;">'.html_print_image('images/dot_red.png', true).'</span><span class="edit_icon_progress" style="display: none;">'.html_print_image('images/spinner.gif', true).'</span><span class="edit_icon"><a class="edit_icon_link" title="'.__('Update').'" href="#">'.html_print_image('images/config.png', true).'</a></span>'; + + $table->data['template_row']['edit'] .= '<a class="delete_icon" href="#">'.html_print_image('images/delete.png', true).'</a>'; + + $table->colspan['no_relations']['0'] = 5; + $table->cellstyle['no_relations']['0'] = 'text-align: center;'; + $table->data['no_relations']['0'] = __('There are not relations'); + + $table->colspan['loading']['0'] = 5; + $table->cellstyle['loading']['0'] = 'text-align: center;'; + $table->data['loading']['0'] = html_print_image( + 'images/wait.gif', + true + ); + + $output .= ui_toggle( + html_print_table($table, true), + __('Relations'), + __('Relations'), + true, + true + ); + + $output .= '</div></div>'; + + $output .= '<div id="dialog_interface_link" style="display: none;" title="Interface link">'; + $output .= '<div style="text-align: left; width: 100%;">'; + + $table = new stdClass(); + $table->id = 'interface_link_table'; + $table->width = '100%'; + $table->head['node_source_interface'] = __('Node source'); + $table->head['interface_source_select'] = __('Interface source'); + $table->head['interface_target_select'] = __('Interface Target'); + $table->head['node_target_interface'] = __('Node target'); + + $table->data = []; + + $table->data['interface_row']['node_source_interface'] = html_print_label('', 'node_source_interface'); + + $table->data['interface_row']['interface_source_select'] = html_print_select( + [], + 'interface_source_select', + '', + '', + __('None'), + 0, + true + ); + + $table->data['interface_row']['interface_target_select'] = html_print_select( + [], + 'interface_target_select', + '', + '', + __('None'), + 0, + true + ); + + $table->data['interface_row']['node_target_interface'] = html_print_label( + '', + 'node_target_interface' + ); + + $output .= 'br><br>'; + + $table->data['interface_row']['interface_link_button'] = html_print_button( + __('Add interface link'), + '', + false, + 'add_interface_link_js();', + 'class="sub"', + true + ); + + $output .= html_print_table($table, true); + $output .= '</div></div>'; + + $output .= '<div id="dialog_node_add" style="display: none;" title="'; + $output .= __('Add node').'">'; + $output .= '<div style="text-align: left; width: 100%;">'; + + $table = null; + $table->width = '100%'; + $table->data = []; + + $table->data[0][0] = __('Agent'); + $params = []; + $params['return'] = true; + $params['show_helptip'] = true; + $params['input_name'] = 'agent_name'; + $params['input_id'] = 'agent_name'; + $params['print_hidden_input_idagent'] = true; + $params['hidden_input_idagent_name'] = 'id_agent'; + $params['disabled_javascript_on_blur_function'] = true; + $table->data[0][1] = ui_print_agent_autocomplete_input($params); + $table->data[1][0] = ''; + $table->data[1][1] = html_print_button( + __('Add agent node'), + '', + false, + 'add_agent_node();', + 'class="sub"', + true + ).html_print_image( + 'images/error_red.png', + true, + [ + 'id' => 'error_red', + 'style' => 'vertical-align: bottom;display: none;', + 'class' => 'forced_title', + 'alt' => 'Esto es una prueba', + 'data-title' => 'data-use_title_for_force_title:1', + ], + false + ); + + $add_agent_node_html = html_print_table($table, true); + $output .= ui_toggle( + $add_agent_node_html, + __('Add agent node'), + __('Add agent node'), + false, + true + ); + + $table = null; + $table->width = '100%'; + $table->data = []; + $table->data[0][0] = __('Group'); + $table->data[0][1] = html_print_select_groups( + false, + 'IW', + false, + 'group_for_show_agents', + -1, + 'choose_group_for_show_agents()', + __('None'), + -1, + true + ); + $table->data[1][0] = __('Agents'); + $table->data[1][1] = html_print_select( + [-1 => __('None')], + 'agents_filter_group', + -1, + '', + '', + 0, + true, + true, + true, + '', + false, + 'width: 170px;', + false, + 5 + ); + $table->data[2][0] = ''; + $table->data[2][1] = html_print_button( + __('Add agent node'), + '', + false, + 'add_agent_node_from_the_filter_group();', + 'class="sub"', + true + ); + + $add_agent_node_html = html_print_table($table, true); + $output .= ui_toggle( + $add_agent_node_html, + __('Add agent node (filter by group)'), + __('Add agent node'), + true, + true + ); + + $table = null; + $table->width = '100%'; + $table->data = []; + $table->data[0][0] = __('Name'); + $table->data[0][1] = html_print_input_text( + 'name_fictional_node', + '', + __('name fictional node'), + '20', + '50', + true + ); + $table->data[1][0] = __('Networkmap to link'); + $table->data[1][1] = html_print_select( + $list_networkmaps, + 'networkmap_to_link', + '', + '', + '', + 0, + true + ); + $table->data[2][0] = ''; + $table->data[2][1] = html_print_button( + __('Add fictional node'), + '', + false, + 'add_fictional_node();', + 'class="sub"', + true + ); + $add_agent_node_html = html_print_table($table, true); + $output .= ui_toggle( + $add_agent_node_html, + __('Add fictional point'), + __('Add agent node'), + true, + true + ); + + $output .= '</div></div>'; + + return $output; + } + + + /** + * Loads advanced map controller (JS). + * + * @return string HTML code for advanced controller. + */ + public function loadController() + { + $output = ''; + + // Generate JS for advanced controller. + $output .= ' + +<script type="text/javascript"> + //////////////////////////////////////////////////////////////////////// + // document ready + //////////////////////////////////////////////////////////////////////// + + $(document).ready(function() { + init_graph({ + graph: networkmap, + networkmap_center: networkmap_center, + networkmap_dimensions: networkmap_dimensions, + enterprise_installed: enterprise_installed, + node_radius: node_radius, + holding_area_dimensions: networkmap_holding_area_dimensions, + url_background_grid: url_background_grid + }); + init_drag_and_drop(); + init_minimap(); + function_open_minimap(); + + $(document.body).on("mouseleave", + ".context-menu-list", + function(e) { + try { + $("#networkconsole_'.$this->idMap.'").contextMenu("hide"); + } + catch(err) { + } + } + ); + }); +</script>'; + + if ($return === false) { + echo $output; + } + + return $output; + + } + + + /** + * Load networkmap HTML skel and JS requires. + * + * @return string HTML code for skel. + */ + public function loadMapSkel() + { + global $config; + + ui_require_css_file('networkmap'); + ui_require_css_file('jquery.contextMenu', 'include/styles/js/'); + + $output = ''; + $hide_minimap = ''; + if ($dashboard_mode) { + $hide_minimap = 'none'; + } + + $networkmap = $this->map; + $networkmap['filter'] = json_decode($networkmap['filter'], true); + + $networkmap['filter']['l2_network_interfaces'] = 1; + + $output .= '<script type="text/javascript" src="'.$config['homeurl'].'include/javascript/d3.3.5.14.js" charset="utf-8"></script>'; + $output .= '<script type="text/javascript" src="'.$config['homeurl'].'include/javascript/jquery.contextMenu.js"></script>'; + $output .= '<script type="text/javascript" src="'.$config['homeurl'].'include/javascript/functions_pandora_networkmap.js"></script>'; + + // Open networkconsole_id div. + $output .= '<div id="networkconsole_'.$networkmap['id'].'"'; + $output .= ' style="position: relative; overflow: hidden; background: #FAFAFA">'; + + $output .= '<div style="display: '.$hide_minimap.';">'; + $output .= '<canvas id="minimap_'.$networkmap['id'].'"'; + $output .= ' style="position: absolute; left: 0px; top: 0px; border: 1px solid #bbbbbb;">'; + $output .= '</canvas>'; + + $output .= '<div id="arrow_minimap_'.$networkmap['id'].'"'; + $output .= ' style="position: absolute; left: 0px; top: 0px;">'; + $output .= '<a title="'.__('Open Minimap').'" href="javascript: toggle_minimap();">'; + $output .= '<img id="image_arrow_minimap_'.$networkmap['id'].'"'; + $output .= ' src="images/minimap_open_arrow.png" />'; + $output .= '</a><div></div></div>'; + + $output .= '<div id="hide_labels_'.$networkmap['id'].'"'; + $output .= ' style="position: absolute; right: 10px; top: 10px;">'; + $output .= '<a title="'.__('Hide Labels').'" href="javascript: hide_labels();">'; + $output .= '<img id="image_hide_show_labels" src="images/icono_borrar.png" />'; + $output .= '</a></div>'; + + $output .= '<div id="holding_spinner_'.$networkmap['id'].'" '; + $output .= ' style="display: none; position: absolute; right: 50px; top: 20px;">'; + $output .= '<img id="image_hide_show_labels" src="images/spinner.gif" />'; + $output .= '</div>'; + + // Close networkconsole_id div. + $output .= "</div>\n"; + + return $output; + } + + /** * Print all components required to visualizate a network map. * @@ -173,19 +1035,10 @@ class NetworkMap $user_readonly = !$networkmap_write && !$networkmap_manage; if (isset($this->idMap)) { - $graph = networkmap_process_networkmap($this->idMap); - - ob_start(); - - ui_require_css_file('networkmap'); - show_networkmap( - $this->idMap, - $user_readonly, - $graph, - get_parameter('pure', 0) - ); - - $output = ob_get_clean(); + $output .= $this->loadMapSkel(); + $output .= $this->loadMapData(); + $output .= $this->loadController(); + $output .= $this->loadAdvanceInterface(); } else if (isset($this->graph)) { // Build graph based on direct graph definition. } From c8bad2b68a9fe4c5244eeca1ceda652acbd03d23 Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Mon, 11 Mar 2019 15:10:22 +0100 Subject: [PATCH 20/50] WIP NetworkMap class Former-commit-id: e6918056fa9d71d33cc3b06e3c265dc3856e45af --- pandora_console/include/class/NetworkMap.class.php | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php index ead73b1254..c912bd0173 100644 --- a/pandora_console/include/class/NetworkMap.class.php +++ b/pandora_console/include/class/NetworkMap.class.php @@ -1,6 +1,4 @@ <?php - - /** * Class to manage networkmaps in Pandora FMS * @@ -300,11 +298,11 @@ class NetworkMap 500, 500, ]; - /* - $this->graph['relations'] = clean_duplicate_links( + + $this->graph['relations'] = clean_duplicate_links( $this->graph['relations'] - ); - */ + ); + $output .= '<script type="text/javascript"> //////////////////////////////////////////////////////////////////// // VARS FROM THE DB @@ -1039,8 +1037,6 @@ class NetworkMap $output .= $this->loadMapData(); $output .= $this->loadController(); $output .= $this->loadAdvanceInterface(); - } else if (isset($this->graph)) { - // Build graph based on direct graph definition. } if ($return === false) { From 9db8078e72418a85f26db989fbef72e32271ed25 Mon Sep 17 00:00:00 2001 From: Daniel Maya <daniel.maya@artica.es> Date: Mon, 11 Mar 2019 15:18:09 +0100 Subject: [PATCH 21/50] Fixed first painted map Former-commit-id: 8f1098e312b4524568501a25642a533615e899f9 --- .../include/functions_pandora_networkmap.php | 52 +++++++++++++------ 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/pandora_console/include/functions_pandora_networkmap.php b/pandora_console/include/functions_pandora_networkmap.php index 550a63f40e..7c7c96191c 100644 --- a/pandora_console/include/functions_pandora_networkmap.php +++ b/pandora_console/include/functions_pandora_networkmap.php @@ -769,14 +769,13 @@ function networkmap_links_to_js_links($relations, $nodes_graph) $agent = 0; $agent2 = 0; + $control1 = false; + $control2 = false; if (($relation['parent_type'] == 1) && ($relation['child_type'] == 1)) { - $mod1_status = db_get_value_filter('estado', 'tagente_estado', ['id_agente_modulo' => $relation['id_parent_source_data']]); - $mod2_status = db_get_value_filter('estado', 'tagente_estado', ['id_agente_modulo' => $relation['id_child_source_data']]); - - if (($mod1_status == AGENT_MODULE_STATUS_CRITICAL_BAD) || ($mod2_status == AGENT_MODULE_STATUS_CRITICAL_BAD)) { + if (($item['status_start'] == AGENT_MODULE_STATUS_CRITICAL_BAD) || ($item['status_end'] == AGENT_MODULE_STATUS_CRITICAL_BAD)) { $item['link_color'] = '#FC4444'; - } else if (($mod1_status == AGENT_MODULE_STATUS_WARNING) || ($mod2_status == AGENT_MODULE_STATUS_WARNING)) { + } else if (($item['status_start'] == AGENT_MODULE_STATUS_WARNING) || ($item['status_end'] == AGENT_MODULE_STATUS_WARNING)) { $item['link_color'] = '#FAD403'; } @@ -786,17 +785,23 @@ function networkmap_links_to_js_links($relations, $nodes_graph) if (isset($node['id_agent'])) { if ($node['id_agent'] == $agent) { $agent = $node['id_db']; - } else if ($node['id_agent'] == $agent2) { + $control1 = true; + } + + if ($node['id_agent'] == $agent2) { $agent2 = $node['id_db']; + $control2 = true; + } + + if ($control1 && $control2) { + break; } } } } else if ($relation['child_type'] == 1) { - $mod1_status = db_get_value_filter('estado', 'tagente_estado', ['id_agente_modulo' => $relation['id_child_source_data']]); - - if ($mod1_status == AGENT_MODULE_STATUS_CRITICAL_BAD) { + if ($item['status_start'] == AGENT_MODULE_STATUS_CRITICAL_BAD) { $item['link_color'] = '#FC4444'; - } else if ($mod1_status == AGENT_MODULE_STATUS_WARNING) { + } else if ($item['status_start'] == AGENT_MODULE_STATUS_WARNING) { $item['link_color'] = '#FAD403'; } @@ -805,28 +810,41 @@ function networkmap_links_to_js_links($relations, $nodes_graph) if (isset($node['id_agent'])) { if ($node['id_agent'] == $relation['id_parent_source_data']) { $agent = $node['id_db']; - } else if ($node['id_agent'] == $agent2) { + $control1 = true; + } + + if ($node['id_agent'] == $agent2) { $agent2 = $node['id_db']; + $control2 = true; + } + + if ($control1 && $control2) { + break; } } } } else if ($relation['parent_type'] == 1) { - $mod1_status = db_get_value_filter('estado', 'tagente_estado', ['id_agente_modulo' => $relation['id_parent_source_data']]); - - if ($mod1_status == AGENT_MODULE_STATUS_CRITICAL_BAD) { + if ($item['status_end'] == AGENT_MODULE_STATUS_CRITICAL_BAD) { $item['link_color'] = '#FC4444'; - } else if ($mod1_status == AGENT_MODULE_STATUS_WARNING) { + } else if ($item['status_end'] == AGENT_MODULE_STATUS_WARNING) { $item['link_color'] = '#FAD403'; } $agent = agents_get_agent_id_by_module_id($relation['id_parent_source_data']); - foreach ($nodes_graph as $key2 => $node) { if (isset($node['id_agent'])) { if ($node['id_agent'] == $agent) { $agent = $node['id_db']; - } else if ($node['id_agent'] == $relation['id_child_source_data']) { + $control1 = true; + } + + if ($node['id_agent'] == $relation['id_child_source_data']) { $agent2 = $node['id_db']; + $control2 = true; + } + + if ($control1 && $control2) { + break; } } } From 2188caaec2857dda054e409bf1aa1b71fddb790a Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Mon, 11 Mar 2019 15:37:08 +0100 Subject: [PATCH 22/50] WIP NetworkMap class Former-commit-id: 5af817aef635798f1ebdfcf596f30939b327e2a7 --- .../include/class/NetworkMap.class.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php index c912bd0173..4da984489b 100644 --- a/pandora_console/include/class/NetworkMap.class.php +++ b/pandora_console/include/class/NetworkMap.class.php @@ -476,7 +476,7 @@ class NetworkMap * * @return string HTML code with dialogs. */ - public function loadAdvanceInterface() + public function loadAdvancedInterface() { $list_networkmaps = get_networkmaps($this->idMap); if (empty($list_networkmaps)) { @@ -494,7 +494,7 @@ class NetworkMap $output .= __('Edit node').'">'; $output .= '<div style="text-align: left; width: 100%;">'; - $table = null; + $table = new StdClass(); $table->id = 'node_details'; $table->width = '100%'; @@ -516,7 +516,7 @@ class NetworkMap true ); - $table = null; + $table = new StdClass(); $table->id = 'interface_information'; $table->width = '100%'; @@ -541,7 +541,7 @@ class NetworkMap true ); - $table = null; + $table = new StdClass(); $table->id = 'node_options'; $table->width = '100%'; @@ -615,7 +615,7 @@ class NetworkMap true ); - $table = null; + $table = new StdClass(); $table->id = 'relations_table'; $table->width = '100%'; @@ -735,7 +735,7 @@ class NetworkMap $output .= __('Add node').'">'; $output .= '<div style="text-align: left; width: 100%;">'; - $table = null; + $table = new StdClass(); $table->width = '100%'; $table->data = []; @@ -779,7 +779,7 @@ class NetworkMap true ); - $table = null; + $table = new StdClass(); $table->width = '100%'; $table->data = []; $table->data[0][0] = __('Group'); @@ -830,7 +830,7 @@ class NetworkMap true ); - $table = null; + $table = new StdClass(); $table->width = '100%'; $table->data = []; $table->data[0][0] = __('Name'); @@ -1036,7 +1036,7 @@ class NetworkMap $output .= $this->loadMapSkel(); $output .= $this->loadMapData(); $output .= $this->loadController(); - $output .= $this->loadAdvanceInterface(); + $output .= $this->loadAdvancedInterface(); } if ($return === false) { From 5f7680f4ee7b0ba87f29adb938694ae2d9b9ede6 Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Mon, 11 Mar 2019 15:40:44 +0100 Subject: [PATCH 23/50] WIP NetworkMap class Former-commit-id: 0380bec0023a1c6a5eb3f902ed66738c1d297754 --- .../include/functions_pandora_networkmap.php | 186 ++++++++++-------- 1 file changed, 103 insertions(+), 83 deletions(-) diff --git a/pandora_console/include/functions_pandora_networkmap.php b/pandora_console/include/functions_pandora_networkmap.php index 7c7c96191c..d92b1b5213 100644 --- a/pandora_console/include/functions_pandora_networkmap.php +++ b/pandora_console/include/functions_pandora_networkmap.php @@ -1393,70 +1393,76 @@ function clean_duplicate_links($relations) $duplicated = false; $index_to_del = 0; $index = 0; - foreach ($segregation_links['aa'] as $link) { - foreach ($segregation_links['aa'] as $link2) { - if ($link['id_parent'] == $link2['id_child'] && $link['id_child'] == $link2['id_parent']) { - if (enterprise_installed()) { - delete_link($segregation_links['aa'][$index_to_del]); + if (is_array($segregation_links['aa'])) { + foreach ($segregation_links['aa'] as $link) { + foreach ($segregation_links['aa'] as $link2) { + if ($link['id_parent'] == $link2['id_child'] && $link['id_child'] == $link2['id_parent']) { + if (enterprise_installed()) { + delete_link($segregation_links['aa'][$index_to_del]); + } + + unset($segregation_links['aa'][$index_to_del]); } - unset($segregation_links['aa'][$index_to_del]); + $index_to_del++; } - $index_to_del++; + $final_links['aa'][$index] = $link; + $index++; + + $duplicated = false; + $index_to_del = 0; } - - $final_links['aa'][$index] = $link; - $index++; - - $duplicated = false; - $index_to_del = 0; } $duplicated = false; $index_to_del = 0; $index2 = 0; - foreach ($segregation_links['mm'] as $link) { - foreach ($segregation_links['mm'] as $link2) { - if ($link['id_parent'] == $link2['id_child'] && $link['id_child'] == $link2['id_parent']) { - if (enterprise_installed()) { - delete_link($segregation_links['mm'][$index_to_del]); + if (is_array($segregation_links['mm'])) { + foreach ($segregation_links['mm'] as $link) { + foreach ($segregation_links['mm'] as $link2) { + if ($link['id_parent'] == $link2['id_child'] && $link['id_child'] == $link2['id_parent']) { + if (enterprise_installed()) { + delete_link($segregation_links['mm'][$index_to_del]); + } + + // unset($segregation_links['mm'][$index_to_del]); } - // unset($segregation_links['mm'][$index_to_del]); + $index_to_del++; } - $index_to_del++; + $final_links['mm'][$index2] = $link; + $index2++; + + $duplicated = false; + $index_to_del = 0; } - - $final_links['mm'][$index2] = $link; - $index2++; - - $duplicated = false; - $index_to_del = 0; } $duplicated = false; $index_to_del = 0; $index3 = 0; - foreach ($segregation_links['ff'] as $link) { - foreach ($segregation_links['ff'] as $link2) { - if ($link['id_parent'] == $link2['id_child'] && $link['id_child'] == $link2['id_parent']) { - if (enterprise_installed()) { - delete_link($segregation_links['ff'][$index_to_del]); + if (is_array($segregation_links['ff'])) { + foreach ($segregation_links['ff'] as $link) { + foreach ($segregation_links['ff'] as $link2) { + if ($link['id_parent'] == $link2['id_child'] && $link['id_child'] == $link2['id_parent']) { + if (enterprise_installed()) { + delete_link($segregation_links['ff'][$index_to_del]); + } + + unset($segregation_links['ff'][$index_to_del]); } - unset($segregation_links['ff'][$index_to_del]); + $index_to_del++; } - $index_to_del++; + $final_links['ff'][$index3] = $link; + $index3++; + + $duplicated = false; + $index_to_del = 0; } - - $final_links['ff'][$index3] = $link; - $index3++; - - $duplicated = false; - $index_to_del = 0; } $final_links['am'] = $segregation_links['am']; @@ -1479,23 +1485,25 @@ function clean_duplicate_links($relations) $l3_link = []; $agent1 = 0; $agent2 = 0; - foreach ($final_links['mm'] as $rel_mm) { - $module_parent = $rel_mm['id_parent_source_data']; - $module_children = $rel_mm['id_child_source_data']; - $agent1 = (int) agents_get_agent_id_by_module_id($module_parent); - $agent2 = (int) agents_get_agent_id_by_module_id($module_children); - foreach ($final_links['aa'] as $key => $rel_aa) { - $l3_link = $rel_aa; - $id_p_source_data = (int) $rel_aa['id_parent_source_data']; - $id_c_source_data = (int) $rel_aa['id_child_source_data']; - if ((($id_p_source_data == $agent1) && ($id_c_source_data == $agent2)) - || (($id_p_source_data == $agent2) && ($id_c_source_data == $agent1)) - ) { - if (enterprise_installed()) { - delete_link($final_links['aa'][$key]); - } + if (is_array($segregation_links['mm'])) { + foreach ($final_links['mm'] as $rel_mm) { + $module_parent = $rel_mm['id_parent_source_data']; + $module_children = $rel_mm['id_child_source_data']; + $agent1 = (int) agents_get_agent_id_by_module_id($module_parent); + $agent2 = (int) agents_get_agent_id_by_module_id($module_children); + foreach ($final_links['aa'] as $key => $rel_aa) { + $l3_link = $rel_aa; + $id_p_source_data = (int) $rel_aa['id_parent_source_data']; + $id_c_source_data = (int) $rel_aa['id_child_source_data']; + if ((($id_p_source_data == $agent1) && ($id_c_source_data == $agent2)) + || (($id_p_source_data == $agent2) && ($id_c_source_data == $agent1)) + ) { + if (enterprise_installed()) { + delete_link($final_links['aa'][$key]); + } - unset($final_links['aa'][$key]); + unset($final_links['aa'][$key]); + } } } } @@ -1507,14 +1515,16 @@ function clean_duplicate_links($relations) $same_m = []; $index = 0; - foreach ($final_links2['am'] as $rel_am) { - foreach ($final_links2['am'] as $rel_am2) { - if (($rel_am['id_child_source_data'] == $rel_am2['id_child_source_data']) - && ($rel_am['id_parent_source_data'] != $rel_am2['id_parent_source_data']) - ) { - $same_m[$index]['rel'] = $rel_am2; - $same_m[$index]['agent_parent'] = $rel_am['id_parent_source_data']; - $index++; + if (is_array($final_links2['am'])) { + foreach ($final_links2['am'] as $rel_am) { + foreach ($final_links2['am'] as $rel_am2) { + if (($rel_am['id_child_source_data'] == $rel_am2['id_child_source_data']) + && ($rel_am['id_parent_source_data'] != $rel_am2['id_parent_source_data']) + ) { + $same_m[$index]['rel'] = $rel_am2; + $same_m[$index]['agent_parent'] = $rel_am['id_parent_source_data']; + $index++; + } } } } @@ -1523,19 +1533,21 @@ function clean_duplicate_links($relations) $index = 0; $l3_link = []; $have_l3 = false; - foreach ($final_links2['aa'] as $key => $rel_aa) { - $l3_link = $rel_aa; - foreach ($same_m as $rel_am) { - if ((($rel_aa['id_parent_source_data'] == $rel_am['parent']['id_parent_source_data']) - && ($rel_aa['id_child_source_data'] == $rel_am['rel']['id_parent_source_data'])) - || (($rel_aa['id_child_source_data'] == $rel_am['parent']['id_parent_source_data']) - && ($rel_aa['id_parent_source_data'] == $rel_am['rel']['id_parent_source_data'])) - ) { - if (enterprise_installed()) { - delete_link($final_links2['aa'][$key]); - } + if (is_array($final_links2['aa'])) { + foreach ($final_links2['aa'] as $key => $rel_aa) { + $l3_link = $rel_aa; + foreach ($same_m as $rel_am) { + if ((($rel_aa['id_parent_source_data'] == $rel_am['parent']['id_parent_source_data']) + && ($rel_aa['id_child_source_data'] == $rel_am['rel']['id_parent_source_data'])) + || (($rel_aa['id_child_source_data'] == $rel_am['parent']['id_parent_source_data']) + && ($rel_aa['id_parent_source_data'] == $rel_am['rel']['id_parent_source_data'])) + ) { + if (enterprise_installed()) { + delete_link($final_links2['aa'][$key]); + } - unset($final_links2['aa'][$key]); + unset($final_links2['aa'][$key]); + } } } } @@ -1546,20 +1558,28 @@ function clean_duplicate_links($relations) $final_links3['ff'] = $final_links2['ff']; $cleaned_links = []; - foreach ($final_links3['aa'] as $link) { - $cleaned_links[] = $link; + if (is_array($final_links3['aa'])) { + foreach ($final_links3['aa'] as $link) { + $cleaned_links[] = $link; + } } - foreach ($final_links3['am'] as $link) { - $cleaned_links[] = $link; + if (is_array($final_links3['am'])) { + foreach ($final_links3['am'] as $link) { + $cleaned_links[] = $link; + } } - foreach ($final_links3['mm'] as $link) { - $cleaned_links[] = $link; + if (is_array($final_links3['mm'])) { + foreach ($final_links3['mm'] as $link) { + $cleaned_links[] = $link; + } } - foreach ($final_links3['ff'] as $link) { - $cleaned_links[] = $link; + if (is_array($final_links3['ff'])) { + foreach ($final_links3['ff'] as $link) { + $cleaned_links[] = $link; + } } return $cleaned_links; From ccb41f1b6886b3580cf5121574d69ace2230f218 Mon Sep 17 00:00:00 2001 From: Daniel Maya <daniel.maya@artica.es> Date: Mon, 11 Mar 2019 16:57:54 +0100 Subject: [PATCH 24/50] Fixed z_dash(zoom) in networkmap Former-commit-id: 2d19cd9234717cd5066d2ddd7094d367262ed1c4 --- .../include/class/NetworkMap.class.php | 17 +++++++++++++---- .../operation/agentes/pandora_networkmap.php | 8 ++++---- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php index 4da984489b..4c8f5cdbee 100644 --- a/pandora_console/include/class/NetworkMap.class.php +++ b/pandora_console/include/class/NetworkMap.class.php @@ -309,11 +309,20 @@ class NetworkMap //////////////////////////////////////////////////////////////////// var url_background_grid = "'.ui_get_full_url('images/background_grid.png').'"; var networkmap_id = '.$this->idMap.";\n"; + if (!empty($networkmap['filter'])) { + if (empty($networkmap['filter']['x_offs'])) { + $output .= "var x_offs =null;\n"; + } else { + $output .= 'var x_offs ='.$networkmap['filter']['x_offs'].";\n"; + } - if (!empty($map_dash_details)) { - $output .= 'var x_offs = '.$map_dash_details['x_offs'].";\n"; - $output .= 'var y_offs = '.$map_dash_details['y_offs'].";\n"; - $output .= 'var z_dash = '.$map_dash_details['z_dash'].";\n"; + if (empty($networkmap['filter']['y_offs'])) { + $output .= "var y_offs =null;\n"; + } else { + $output .= 'var y_offs ='.$networkmap['filter']['y_offs'].";\n"; + } + + $output .= 'var z_dash = '.$networkmap['filter']['z_dash'].";\n"; } else { $output .= "var x_offs = null;\n"; $output .= "var y_offs = null;\n"; diff --git a/pandora_console/operation/agentes/pandora_networkmap.php b/pandora_console/operation/agentes/pandora_networkmap.php index 48a91f9976..2050b37910 100644 --- a/pandora_console/operation/agentes/pandora_networkmap.php +++ b/pandora_console/operation/agentes/pandora_networkmap.php @@ -244,8 +244,8 @@ if ($new_networkmap || $save_networkmap) { $node_radius = (int) get_parameter('node_radius', 40); $description = get_parameter('description', ''); - $offset_x = get_parameter('pos_x'); - $offset_y = get_parameter('pos_y'); + $offset_x = get_parameter('pos_x', 0); + $offset_y = get_parameter('pos_y', 0); $scale_z = get_parameter('scale_z', 0.5); $node_sep = get_parameter('node_sep', '0.25'); @@ -421,8 +421,8 @@ else if ($update_networkmap || $copy_networkmap || $delete) { $source = (string) get_parameter('source', 'group'); - $offset_x = get_parameter('pos_x'); - $offset_y = get_parameter('pos_y'); + $offset_x = get_parameter('pos_x', 0); + $offset_y = get_parameter('pos_y', 0); $scale_z = get_parameter('scale_z', 0.5); $values = []; From 5b3dd6121b9e5e54f0195acb58ae885f12baf489 Mon Sep 17 00:00:00 2001 From: samucarc <samuel.carcases> Date: Mon, 11 Mar 2019 17:14:26 +0100 Subject: [PATCH 25/50] Fixed error in event filters when is only new events Former-commit-id: a1e0529b58e4a1c62c8c35cba7b133c218f59a93 --- pandora_console/operation/events/events.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/pandora_console/operation/events/events.php b/pandora_console/operation/events/events.php index 9fb78b084c..de7a02074a 100644 --- a/pandora_console/operation/events/events.php +++ b/pandora_console/operation/events/events.php @@ -1068,9 +1068,6 @@ function validate_event_advanced(id, new_status) { next_row_id = row_id_name + '-' + row_id_number_next; $("#"+previous_row_id).css('display', 'none'); - $("#"+current_row_id).css('display', 'none'); - $("#"+selected_row_id).css('display', 'none'); - $("#"+next_row_id).css('display', 'none'); } }); From e67245699814cb1c0c4580d03812f34d8126091f Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Mon, 11 Mar 2019 18:04:23 +0100 Subject: [PATCH 26/50] fixes satellite contact interval detector Former-commit-id: b3536e29fd7ae1330667eee7bf98a55ef3f65e4b --- pandora_console/include/class/ConsoleSupervisor.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pandora_console/include/class/ConsoleSupervisor.php b/pandora_console/include/class/ConsoleSupervisor.php index 63e2c46fca..66d0fd828e 100644 --- a/pandora_console/include/class/ConsoleSupervisor.php +++ b/pandora_console/include/class/ConsoleSupervisor.php @@ -1065,6 +1065,7 @@ class ConsoleSupervisor id_server, name, server_type, + server_keepalive, status, unix_timestamp() - unix_timestamp(keepalive) as downtime FROM tserver @@ -1100,8 +1101,8 @@ class ConsoleSupervisor } foreach ($servers as $server) { - if ($server['type'] == SERVER_TYPE_ENTERPRISE_SATELLITE) { - if ($server['downtime'] < ($server['keepalive'] * 2)) { + if ($server['server_type'] == SERVER_TYPE_ENTERPRISE_SATELLITE) { + if ($server['downtime'] < ($server['server_keepalive'] * 2)) { // Satellite uses different keepalive mode. continue; } From 1d660d259fcae4265b6cd84a9b0a81ea5eba2f0c Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Mon, 11 Mar 2019 20:10:08 +0100 Subject: [PATCH 27/50] WIP NetworkMap class Former-commit-id: 6694ee84fe5e9dc783010a3092753b4041370993 --- .../include/class/NetworkMap.class.php | 361 +++++++++++++++++- 1 file changed, 356 insertions(+), 5 deletions(-) diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php index 4c8f5cdbee..8695b682a0 100644 --- a/pandora_console/include/class/NetworkMap.class.php +++ b/pandora_console/include/class/NetworkMap.class.php @@ -29,8 +29,11 @@ // Begin. global $config; +require_once $config['homedir'].'/include/functions_networkmap.php'; require_once $config['homedir'].'/include/functions_pandora_networkmap.php'; +enterprise_include_once('include/functions_pandora_networkmap.php'); + /** * Manage networkmaps in Pandora FMS */ @@ -79,6 +82,13 @@ class NetworkMap */ public $graph; + /** + * Dot string with graph definition. + * + * @var string + */ + public $dotGraph; + /** * Node list. * @@ -127,7 +137,37 @@ class NetworkMap */ public function __construct($options=false) { - $recreate = true; + // Default mapOptions values. + // Default neato. + $this->mapOptions['generation_method'] = 3; + $this->mapOptions['simple'] = 0; + $this->mapOptions['font_size'] = 12; + $this->mapOptions['layout'] = 'spring1'; + $this->mapOptions['nooverlap'] = 1; + $this->mapOptions['zoom'] = 1; + $this->mapOptions['ranksep'] = 0.5; + $this->mapOptions['center'] = 0; + $this->mapOptions['regen'] = 0; + $this->mapOptions['pure'] = 0; + $this->mapOptions['show_snmp_modules'] = false; + $this->mapOptions['cut_names'] = false; + $this->mapOptions['relative'] = true; + $this->mapOptions['text_filter'] = ''; + $this->mapOptions['dont_show_subgroups'] = false; + $this->mapOptions['strict_user'] = false; + $this->mapOptions['size_canvas'] = null; + $this->mapOptions['old_mode'] = false; + $this->mapOptions['map_filter'] = [ + 'node_radius' => 40, + 'x_offs' => '', + 'y_offs' => '', + 'z_dash' => 0.31, + 'node_sep' => 0.1, + 'rank_sep' => 1, + 'mindist' => 1, + 'kval' => 0.1, + ]; + if (is_array($options)) { if (isset($options['graph'])) { $this->graph = $options['graph']; @@ -145,8 +185,10 @@ class NetworkMap $this->mode = $options['mode']; } - if (isset($options['map_options'])) { - $this->mapOptions = $options['map_options']; + if (is_array($options['map_options'])) { + foreach ($options['map_options'] as $k => $v) { + $this->mapOptions[$k] = $v; + } } // Load from Discovery task. @@ -206,6 +248,11 @@ class NetworkMap $this->network ); } + + if ($this->idTask) { + // Retrieve data from target task. + $this->loadMap(); + } } @@ -225,6 +272,22 @@ class NetworkMap // Nodes and relations. $this->graph = networkmap_process_networkmap($this->idMap); + } else { + // Simulated map. + $this->idMap = '0'; + // No tmap definition. Paint data. + if ($this->idTask) { + $recon_task = db_get_row_filter( + 'trecon_task', + ['id_rt' => $networkmap['source_data']] + ); + $this->network = $recon_task['subnet']; + } + + $this->graph = $this->generateNetworkMap(); + + // Simulate map entry. + $this->map = ['id' => '0']; } } @@ -255,6 +318,275 @@ class NetworkMap } + /** + * Generates a nodes - relationships array using graphviz dot + * schema. + * + * @return array Node - relationship calculated. + */ + public function generateNetworkMap() + { + /* + * Let graphviz place the nodes. + */ + + switch ($this->mapOptions['generation_method']) { + case 0: + $filter = 'circo'; + $layout = 'circular'; + break; + + case 1: + $filter = 'dot'; + $layout = 'flat'; + break; + + case 2: + $filter = 'twopi'; + $layout = 'radial'; + break; + + case 3: + default: + $filter = 'neato'; + $layout = 'spring1'; + break; + + case 4: + $filter = 'fdp'; + $layout = 'spring2'; + break; + } + + $nodes_and_relations = []; + // Generate dot file. + $graph = networkmap_generate_dot( + get_product_name(), + $this->idGroup, + $this->mapOptions['simple'], + $this->mapOptions['font_size'], + $this->mapOptions['layout'], + $this->mapOptions['nooverlap'], + $this->mapOptions['zoom'], + $this->mapOptions['ranksep'], + $this->mapOptions['center'], + $this->mapOptions['regen'], + $this->mapOptions['pure'], + $this->mapOptions['id'], + $this->mapOptions['show_snmp_modules'], + $this->mapOptions['cut_names'], + $this->mapOptions['relative'], + $this->mapOptions['text_filter'], + $this->network, + $this->mapOptions['dont_show_subgroups'], + // Strict user (strict_user). + false, + // Canvas size (size_canvas). + null, + $this->mapOptions['old_mode'], + $this->mapOptions['map_filter'] + ); + + switch (PHP_OS) { + case 'WIN32': + case 'WINNT': + case 'Windows': + $filename_dot = sys_get_temp_dir()."\\networkmap_".$filter; + break; + + default: + $filename_dot = sys_get_temp_dir().'/networkmap_'.$filter; + break; + } + + if ($simple) { + $filename_dot .= '_simple'; + } + + if ($nooverlap) { + $filename_dot .= '_nooverlap'; + } + + $filename_dot .= '_'.$this->idMap.'.dot'; + + file_put_contents($filename_dot, $graph); + + switch (PHP_OS) { + case 'WIN32': + case 'WINNT': + case 'Windows': + $filename_plain = sys_get_temp_dir().'\\plain.txt'; + + $cmd = io_safe_output( + $config['graphviz_bin_dir'].'\\'.$filter.'.exe -Tplain -o '.$filename_plain.' '.$filename_dot + ); + break; + + default: + $filename_plain = sys_get_temp_dir().'/plain.txt'; + + $cmd = $filter.' -Tplain -o '.$filename_plain.' '.$filename_dot; + break; + } + + $r = system($cmd); + + unlink($filename_dot); + + $nodes = networkmap_loadfile( + $this->idMap, + $filename_plain, + $relation_nodes, + $graph + ); + + unlink($filename_plain); + + $id = $this->idMap; + + /* + * Graphviz section ends here. + */ + + /* + * Calculate references. + */ + + // Set the position of modules. + foreach ($nodes as $key => $node) { + if ($node['type'] == 'module') { + // Search the agent of this module for to get the + // position. + foreach ($nodes as $key2 => $node2) { + if ($node2['id_agent'] != 0 && $node2['type'] == 'agent') { + if ($node2['id_agent'] == $node['id_agent']) { + $nodes[$key]['coords'][0] = ($nodes[$key2]['coords'][0] + $node['height'] / 2); + $nodes[$key]['coords'][1] = ($nodes[$key2]['coords'][1] + $node['width'] / 2); + } + } + } + } + } + + $nodes_and_relations['nodes'] = []; + $index = 0; + $node_center = []; + foreach ($nodes as $key => $node) { + $nodes_and_relations['nodes'][$index]['id'] = $node['id']; + $nodes_and_relations['nodes'][$index]['id_map'] = $id; + + $children_count = 0; + foreach ($relation_nodes as $relation) { + if (($relation['parent_type'] == 'agent') || ($relation['parent_type'] == '')) { + if ($nodes[$relation['id_parent']]['id_agent'] == $node['id_agent']) { + $children_count++; + } + } else if ($relation['parent_type'] == 'module') { + if ($nodes[$relation['id_parent']]['id_module'] == $node['id_module']) { + $children_count++; + } + } + } + + if (empty($node_center) || $node_center['counter'] < $children_count) { + $node_center['x'] = (int) $node['coords'][0]; + $node_center['y'] = (int) $node['coords'][1]; + $node_center['counter'] = $children_count; + } + + $nodes_and_relations['nodes'][$index]['x'] = (int) $node['coords'][0]; + $nodes_and_relations['nodes'][$index]['y'] = (int) $node['coords'][1]; + + if (($node['type'] == 'agent') || ($node['type'] == '')) { + $nodes_and_relations['nodes'][$index]['source_data'] = $node['id_agent']; + $nodes_and_relations['nodes'][$index]['type'] = 0; + } else { + $nodes_and_relations['nodes'][$index]['source_data'] = $node['id_module']; + $nodes_and_relations['nodes'][$index]['id_agent'] = $node['id_agent']; + $nodes_and_relations['nodes'][$index]['type'] = 1; + } + + $style = []; + $style['shape'] = 'circle'; + $style['image'] = $node['image']; + $style['width'] = $node['width']; + $style['height'] = $node['height']; + $style['label'] = $node['text']; + $nodes_and_relations['nodes'][$index]['style'] = json_encode($style); + + $index++; + } + + $nodes_and_relations['relations'] = []; + $index = 0; + foreach ($relation_nodes as $relation) { + $nodes_and_relations['relations'][$index]['id_map'] = $id; + + if (($relation['parent_type'] == 'agent') || ($relation['parent_type'] == '')) { + $nodes_and_relations['relations'][$index]['id_parent'] = $relation['id_parent']; + $nodes_and_relations['relations'][$index]['id_parent_source_data'] = $nodes[$relation['id_parent']]['id_agent']; + $nodes_and_relations['relations'][$index]['parent_type'] = 0; + } else if ($relation['parent_type'] == 'module') { + $nodes_and_relations['relations'][$index]['id_parent'] = $relation['id_parent']; + $nodes_and_relations['relations'][$index]['id_parent_source_data'] = $nodes[$relation['id_parent']]['id_module']; + $nodes_and_relations['relations'][$index]['parent_type'] = 1; + } else { + $nodes_and_relations['relations'][$index]['id_parent'] = $relation['id_parent']; + $nodes_and_relations['relations'][$index]['id_child_source_data'] = -2; + $nodes_and_relations['relations'][$index]['parent_type'] = 3; + } + + if (($relation['child_type'] == 'agent') || ($relation['child_type'] == '')) { + $nodes_and_relations['relations'][$index]['id_child'] = $relation['id_child']; + $nodes_and_relations['relations'][$index]['id_child_source_data'] = $nodes[$relation['id_child']]['id_agent']; + $nodes_and_relations['relations'][$index]['child_type'] = 0; + } else if ($relation['child_type'] == 'module') { + $nodes_and_relations['relations'][$index]['id_child'] = $relation['id_child']; + $nodes_and_relations['relations'][$index]['id_child_source_data'] = $nodes[$relation['id_child']]['id_module']; + $nodes_and_relations['relations'][$index]['child_type'] = 1; + } else { + $nodes_and_relations['relations'][$index]['id_child'] = $relation['id_child']; + $nodes_and_relations['relations'][$index]['id_child_source_data'] = -2; + $nodes_and_relations['relations'][$index]['child_type'] = 3; + } + + $index++; + } + + if ($this->idMap > 0) { + enterprise_hook( + 'save_generate_nodes', + [ + $id, + $nodes_and_relations, + ] + ); + + $pandorafms_node = $nodes_and_relations['nodes'][0]; + $center = [ + 'x' => $node_center['x'], + 'y' => $node_center['y'], + ]; + + $networkmap['center_x'] = $center['x']; + $networkmap['center_y'] = $center['y']; + db_process_sql_update( + 'tmap', + [ + 'center_x' => $networkmap['center_x'], + 'center_y' => $networkmap['center_y'], + ], + ['id' => $id] + ); + } else { + $this->map['center_x'] = $center['x']; + $this->map['center_y'] = $center['y']; + } + + return $nodes_and_relations; + } + + /** * Return relations of current map. * @@ -293,6 +625,13 @@ class NetworkMap true ); + if (empty($networkmap['filter'])) { + // Direct print. Avoid extra options. + $networkmap['source_period'] = 60; + $networkmap['filter']['node_radius'] = 40; + $networkmap['filter'] = $this->mapOptions['map_filter']; + } + // Hardcoded. $networkmap['filter']['holding_area'] = [ 500, @@ -308,7 +647,9 @@ class NetworkMap // VARS FROM THE DB //////////////////////////////////////////////////////////////////// var url_background_grid = "'.ui_get_full_url('images/background_grid.png').'"; - var networkmap_id = '.$this->idMap.";\n"; + '; + $output .= 'var networkmap_id = '.$this->idMap.";\n"; + if (!empty($networkmap['filter'])) { if (empty($networkmap['filter']['x_offs'])) { $output .= "var x_offs =null;\n"; @@ -322,7 +663,11 @@ class NetworkMap $output .= 'var y_offs ='.$networkmap['filter']['y_offs'].";\n"; } - $output .= 'var z_dash = '.$networkmap['filter']['z_dash'].";\n"; + if (empty($networkmap['filter']['y_offs'])) { + $output .= "var z_dash =null;\n"; + } else { + $output .= 'var z_dash = '.$networkmap['filter']['z_dash'].";\n"; + } } else { $output .= "var x_offs = null;\n"; $output .= "var y_offs = null;\n"; @@ -1046,6 +1391,12 @@ class NetworkMap $output .= $this->loadMapData(); $output .= $this->loadController(); $output .= $this->loadAdvancedInterface(); + } else { + // Simple mode, no tmap entries. + $this->idMap = '0'; + $output .= $this->loadMapSkel(); + $output .= $this->loadMapData(); + $output .= $this->loadController(); } if ($return === false) { From 67080c72d9883fc1c4f6ff22d3bdebd065939177 Mon Sep 17 00:00:00 2001 From: artica <artica.devel@gmail.com> Date: Tue, 12 Mar 2019 00:01:23 +0100 Subject: [PATCH 28/50] Auto-updated build strings. Former-commit-id: d5c1d195e9648fa5b091c533b57a6e234275787c --- pandora_agents/unix/DEBIAN/control | 2 +- pandora_agents/unix/DEBIAN/make_deb_package.sh | 2 +- pandora_agents/unix/pandora_agent | 2 +- pandora_agents/unix/pandora_agent.redhat.spec | 2 +- pandora_agents/unix/pandora_agent.spec | 2 +- pandora_agents/unix/pandora_agent_installer | 2 +- pandora_agents/win32/installer/pandora.mpi | 2 +- pandora_agents/win32/pandora.cc | 2 +- pandora_agents/win32/versioninfo.rc | 2 +- pandora_console/DEBIAN/control | 2 +- pandora_console/DEBIAN/make_deb_package.sh | 2 +- pandora_console/include/config_process.php | 2 +- pandora_console/install.php | 4 ++-- pandora_console/pandora_console.redhat.spec | 2 +- pandora_console/pandora_console.spec | 2 +- pandora_server/DEBIAN/control | 2 +- pandora_server/DEBIAN/make_deb_package.sh | 2 +- pandora_server/lib/PandoraFMS/Config.pm | 2 +- pandora_server/lib/PandoraFMS/PluginTools.pm | 2 +- pandora_server/pandora_server.redhat.spec | 2 +- pandora_server/pandora_server.spec | 2 +- pandora_server/pandora_server_installer | 2 +- pandora_server/util/pandora_db.pl | 2 +- pandora_server/util/pandora_manage.pl | 2 +- 24 files changed, 25 insertions(+), 25 deletions(-) diff --git a/pandora_agents/unix/DEBIAN/control b/pandora_agents/unix/DEBIAN/control index e2c07b411d..4b20131ada 100644 --- a/pandora_agents/unix/DEBIAN/control +++ b/pandora_agents/unix/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-agent-unix -Version: 7.0NG.732-190311 +Version: 7.0NG.732-190312 Architecture: all Priority: optional Section: admin diff --git a/pandora_agents/unix/DEBIAN/make_deb_package.sh b/pandora_agents/unix/DEBIAN/make_deb_package.sh index 4f7a02a497..4c38106b0f 100644 --- a/pandora_agents/unix/DEBIAN/make_deb_package.sh +++ b/pandora_agents/unix/DEBIAN/make_deb_package.sh @@ -14,7 +14,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -pandora_version="7.0NG.732-190311" +pandora_version="7.0NG.732-190312" echo "Test if you has the tools for to make the packages." whereis dpkg-deb | cut -d":" -f2 | grep dpkg-deb > /dev/null diff --git a/pandora_agents/unix/pandora_agent b/pandora_agents/unix/pandora_agent index e0a754adad..7bf1e25c3a 100755 --- a/pandora_agents/unix/pandora_agent +++ b/pandora_agents/unix/pandora_agent @@ -42,7 +42,7 @@ my $Sem = undef; my $ThreadSem = undef; use constant AGENT_VERSION => '7.0NG.732'; -use constant AGENT_BUILD => '190311'; +use constant AGENT_BUILD => '190312'; # Agent log default file size maximum and instances use constant DEFAULT_MAX_LOG_SIZE => 600000; diff --git a/pandora_agents/unix/pandora_agent.redhat.spec b/pandora_agents/unix/pandora_agent.redhat.spec index fb0952ad20..5bb4145674 100644 --- a/pandora_agents/unix/pandora_agent.redhat.spec +++ b/pandora_agents/unix/pandora_agent.redhat.spec @@ -3,7 +3,7 @@ # %define name pandorafms_agent_unix %define version 7.0NG.732 -%define release 190311 +%define release 190312 Summary: Pandora FMS Linux agent, PERL version Name: %{name} diff --git a/pandora_agents/unix/pandora_agent.spec b/pandora_agents/unix/pandora_agent.spec index c4cca3a53b..f98ff3cd9d 100644 --- a/pandora_agents/unix/pandora_agent.spec +++ b/pandora_agents/unix/pandora_agent.spec @@ -3,7 +3,7 @@ # %define name pandorafms_agent_unix %define version 7.0NG.732 -%define release 190311 +%define release 190312 Summary: Pandora FMS Linux agent, PERL version Name: %{name} diff --git a/pandora_agents/unix/pandora_agent_installer b/pandora_agents/unix/pandora_agent_installer index 26aaea4fa7..fb27a8e252 100755 --- a/pandora_agents/unix/pandora_agent_installer +++ b/pandora_agents/unix/pandora_agent_installer @@ -10,7 +10,7 @@ # ********************************************************************** PI_VERSION="7.0NG.732" -PI_BUILD="190311" +PI_BUILD="190312" OS_NAME=`uname -s` FORCE=0 diff --git a/pandora_agents/win32/installer/pandora.mpi b/pandora_agents/win32/installer/pandora.mpi index 23cad4a284..20957929d2 100644 --- a/pandora_agents/win32/installer/pandora.mpi +++ b/pandora_agents/win32/installer/pandora.mpi @@ -186,7 +186,7 @@ UpgradeApplicationID {} Version -{190311} +{190312} ViewReadme {Yes} diff --git a/pandora_agents/win32/pandora.cc b/pandora_agents/win32/pandora.cc index 0d2b48f5d0..5ea340e78e 100644 --- a/pandora_agents/win32/pandora.cc +++ b/pandora_agents/win32/pandora.cc @@ -30,7 +30,7 @@ using namespace Pandora; using namespace Pandora_Strutils; #define PATH_SIZE _MAX_PATH+1 -#define PANDORA_VERSION ("7.0NG.732(Build 190311)") +#define PANDORA_VERSION ("7.0NG.732(Build 190312)") string pandora_path; string pandora_dir; diff --git a/pandora_agents/win32/versioninfo.rc b/pandora_agents/win32/versioninfo.rc index a9ecca4a92..9f62b65035 100644 --- a/pandora_agents/win32/versioninfo.rc +++ b/pandora_agents/win32/versioninfo.rc @@ -11,7 +11,7 @@ BEGIN VALUE "LegalCopyright", "Artica ST" VALUE "OriginalFilename", "PandoraAgent.exe" VALUE "ProductName", "Pandora FMS Windows Agent" - VALUE "ProductVersion", "(7.0NG.732(Build 190311))" + VALUE "ProductVersion", "(7.0NG.732(Build 190312))" VALUE "FileVersion", "1.0.0.0" END END diff --git a/pandora_console/DEBIAN/control b/pandora_console/DEBIAN/control index ac8156d640..0f08432214 100644 --- a/pandora_console/DEBIAN/control +++ b/pandora_console/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-console -Version: 7.0NG.732-190311 +Version: 7.0NG.732-190312 Architecture: all Priority: optional Section: admin diff --git a/pandora_console/DEBIAN/make_deb_package.sh b/pandora_console/DEBIAN/make_deb_package.sh index a2b5f1c9c6..a15849cec1 100644 --- a/pandora_console/DEBIAN/make_deb_package.sh +++ b/pandora_console/DEBIAN/make_deb_package.sh @@ -14,7 +14,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -pandora_version="7.0NG.732-190311" +pandora_version="7.0NG.732-190312" package_pear=0 package_pandora=1 diff --git a/pandora_console/include/config_process.php b/pandora_console/include/config_process.php index c71487946d..6cadc13ccd 100644 --- a/pandora_console/include/config_process.php +++ b/pandora_console/include/config_process.php @@ -20,7 +20,7 @@ /** * Pandora build version and version */ -$build_version = 'PC190311'; +$build_version = 'PC190312'; $pandora_version = 'v7.0NG.732'; // Do not overwrite default timezone set if defined. diff --git a/pandora_console/install.php b/pandora_console/install.php index 250d334d6d..8ba50b3c71 100644 --- a/pandora_console/install.php +++ b/pandora_console/install.php @@ -128,8 +128,8 @@ </div> <div style='height: 10px'> <?php - $version = '7.0NG.732'; - $build = '190311'; +$version = '7.0NG.732'; +$build = '190312'; $banner = "v$version Build $build"; error_reporting(0); diff --git a/pandora_console/pandora_console.redhat.spec b/pandora_console/pandora_console.redhat.spec index f7d85b5a17..82b3c55204 100644 --- a/pandora_console/pandora_console.redhat.spec +++ b/pandora_console/pandora_console.redhat.spec @@ -3,7 +3,7 @@ # %define name pandorafms_console %define version 7.0NG.732 -%define release 190311 +%define release 190312 # User and Group under which Apache is running %define httpd_name httpd diff --git a/pandora_console/pandora_console.spec b/pandora_console/pandora_console.spec index 68c69f5eec..1a28b1fdd0 100644 --- a/pandora_console/pandora_console.spec +++ b/pandora_console/pandora_console.spec @@ -3,7 +3,7 @@ # %define name pandorafms_console %define version 7.0NG.732 -%define release 190311 +%define release 190312 %define httpd_name httpd # User and Group under which Apache is running %define httpd_name apache2 diff --git a/pandora_server/DEBIAN/control b/pandora_server/DEBIAN/control index 35ebe7ba72..9ec614259c 100644 --- a/pandora_server/DEBIAN/control +++ b/pandora_server/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-server -Version: 7.0NG.732-190311 +Version: 7.0NG.732-190312 Architecture: all Priority: optional Section: admin diff --git a/pandora_server/DEBIAN/make_deb_package.sh b/pandora_server/DEBIAN/make_deb_package.sh index e8587ab115..15aed91cda 100644 --- a/pandora_server/DEBIAN/make_deb_package.sh +++ b/pandora_server/DEBIAN/make_deb_package.sh @@ -14,7 +14,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -pandora_version="7.0NG.732-190311" +pandora_version="7.0NG.732-190312" package_cpan=0 package_pandora=1 diff --git a/pandora_server/lib/PandoraFMS/Config.pm b/pandora_server/lib/PandoraFMS/Config.pm index a1fa8d2e6b..ba427f8bb0 100644 --- a/pandora_server/lib/PandoraFMS/Config.pm +++ b/pandora_server/lib/PandoraFMS/Config.pm @@ -45,7 +45,7 @@ our @EXPORT = qw( # version: Defines actual version of Pandora Server for this module only my $pandora_version = "7.0NG.732"; -my $pandora_build = "190311"; +my $pandora_build = "190312"; our $VERSION = $pandora_version." ".$pandora_build; # Setup hash diff --git a/pandora_server/lib/PandoraFMS/PluginTools.pm b/pandora_server/lib/PandoraFMS/PluginTools.pm index 0d13ebc02e..85cf1f9219 100644 --- a/pandora_server/lib/PandoraFMS/PluginTools.pm +++ b/pandora_server/lib/PandoraFMS/PluginTools.pm @@ -32,7 +32,7 @@ our @ISA = qw(Exporter); # version: Defines actual version of Pandora Server for this module only my $pandora_version = "7.0NG.732"; -my $pandora_build = "190311"; +my $pandora_build = "190312"; our $VERSION = $pandora_version." ".$pandora_build; our %EXPORT_TAGS = ( 'all' => [ qw() ] ); diff --git a/pandora_server/pandora_server.redhat.spec b/pandora_server/pandora_server.redhat.spec index 8be92339c6..5c6662ad47 100644 --- a/pandora_server/pandora_server.redhat.spec +++ b/pandora_server/pandora_server.redhat.spec @@ -3,7 +3,7 @@ # %define name pandorafms_server %define version 7.0NG.732 -%define release 190311 +%define release 190312 Summary: Pandora FMS Server Name: %{name} diff --git a/pandora_server/pandora_server.spec b/pandora_server/pandora_server.spec index 8107520b9f..239b8b4a98 100644 --- a/pandora_server/pandora_server.spec +++ b/pandora_server/pandora_server.spec @@ -3,7 +3,7 @@ # %define name pandorafms_server %define version 7.0NG.732 -%define release 190311 +%define release 190312 Summary: Pandora FMS Server Name: %{name} diff --git a/pandora_server/pandora_server_installer b/pandora_server/pandora_server_installer index bcdeb6a35a..8bfb991f42 100755 --- a/pandora_server/pandora_server_installer +++ b/pandora_server/pandora_server_installer @@ -9,7 +9,7 @@ # ********************************************************************** PI_VERSION="7.0NG.732" -PI_BUILD="190311" +PI_BUILD="190312" MODE=$1 if [ $# -gt 1 ]; then diff --git a/pandora_server/util/pandora_db.pl b/pandora_server/util/pandora_db.pl index c8256d9739..8602f0d24d 100644 --- a/pandora_server/util/pandora_db.pl +++ b/pandora_server/util/pandora_db.pl @@ -34,7 +34,7 @@ use PandoraFMS::Config; use PandoraFMS::DB; # version: define current version -my $version = "7.0NG.732 PS190311"; +my $version = "7.0NG.732 PS190312"; # Pandora server configuration my %conf; diff --git a/pandora_server/util/pandora_manage.pl b/pandora_server/util/pandora_manage.pl index ea0e6f48e5..1b00ef349a 100644 --- a/pandora_server/util/pandora_manage.pl +++ b/pandora_server/util/pandora_manage.pl @@ -36,7 +36,7 @@ use Encode::Locale; Encode::Locale::decode_argv; # version: define current version -my $version = "7.0NG.732 PS190311"; +my $version = "7.0NG.732 PS190312"; # save program name for logging my $progname = basename($0); From 0ad8a0383f140fb8243d86d5b8063b3f5d20bc7a Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Tue, 12 Mar 2019 10:29:19 +0100 Subject: [PATCH 29/50] WIP NetworkMap class Former-commit-id: f2594c8388e4cb235e39f08945ad064e999cfbcb --- .../include/class/NetworkMap.class.php | 64 ++++++++++++------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php index 8695b682a0..b223f14862 100644 --- a/pandora_console/include/class/NetworkMap.class.php +++ b/pandora_console/include/class/NetworkMap.class.php @@ -144,11 +144,11 @@ class NetworkMap $this->mapOptions['font_size'] = 12; $this->mapOptions['layout'] = 'spring1'; $this->mapOptions['nooverlap'] = 1; - $this->mapOptions['zoom'] = 1; + $this->mapOptions['zoom'] = 0.5; $this->mapOptions['ranksep'] = 0.5; $this->mapOptions['center'] = 0; $this->mapOptions['regen'] = 0; - $this->mapOptions['pure'] = 0; + $this->mapOptions['pure'] = 1; $this->mapOptions['show_snmp_modules'] = false; $this->mapOptions['cut_names'] = false; $this->mapOptions['relative'] = true; @@ -158,14 +158,15 @@ class NetworkMap $this->mapOptions['size_canvas'] = null; $this->mapOptions['old_mode'] = false; $this->mapOptions['map_filter'] = [ - 'node_radius' => 40, - 'x_offs' => '', - 'y_offs' => '', - 'z_dash' => 0.31, - 'node_sep' => 0.1, - 'rank_sep' => 1, - 'mindist' => 1, - 'kval' => 0.1, + 'dont_show_subgroups' => 0, + 'node_radius' => 40, + 'x_offs' => 0, + 'y_offs' => 0, + 'z_dash' => 0.5, + 'node_sep' => 0.1, + 'rank_sep' => 1, + 'mindist' => 1, + 'kval' => 0.1, ]; if (is_array($options)) { @@ -274,7 +275,7 @@ class NetworkMap $this->graph = networkmap_process_networkmap($this->idMap); } else { // Simulated map. - $this->idMap = '0'; + $this->idMap = uniqid(); // No tmap definition. Paint data. if ($this->idTask) { $recon_task = db_get_row_filter( @@ -284,10 +285,27 @@ class NetworkMap $this->network = $recon_task['subnet']; } + // Simulate map entry. + $this->map = [ + 'id' => $this->idMap, + '__simulated' => 1, + 'background' => '', + 'background_options' => 0, + 'source_period' => 60, + 'filter' => $this->mapOptions['map_filter'], + 'width' => 900, + 'height' => 400, + 'center_x' => 450, + 'center_y' => 200, + ]; + $this->graph = $this->generateNetworkMap(); - // Simulate map entry. - $this->map = ['id' => '0']; + // Direct print. Avoid extra options. + // $networkmap['source_period'] = 60; + // $networkmap['filter'] = $this->mapOptions['map_filter']; + // $networkmap['width'] = 1400; + // $networkmap['height'] = 800; } } @@ -620,16 +638,12 @@ class NetworkMap public function loadMapData() { $networkmap = $this->map; - $networkmap['filter'] = json_decode( - $networkmap['filter'], - true - ); - if (empty($networkmap['filter'])) { - // Direct print. Avoid extra options. - $networkmap['source_period'] = 60; - $networkmap['filter']['node_radius'] = 40; - $networkmap['filter'] = $this->mapOptions['map_filter']; + if (!isset($networkmap['__simulated'])) { + $networkmap['filter'] = json_decode( + $networkmap['filter'], + true + ); } // Hardcoded. @@ -642,13 +656,17 @@ class NetworkMap $this->graph['relations'] ); + // Print some params to handle it in js. + html_print_input_hidden('product_name', get_product_name()); + html_print_input_hidden('center_logo', ui_get_full_url(ui_get_logo_to_center_networkmap())); + $output .= '<script type="text/javascript"> //////////////////////////////////////////////////////////////////// // VARS FROM THE DB //////////////////////////////////////////////////////////////////// var url_background_grid = "'.ui_get_full_url('images/background_grid.png').'"; '; - $output .= 'var networkmap_id = '.$this->idMap.";\n"; + $output .= 'var networkmap_id = "'.$this->idMap."\";\n"; if (!empty($networkmap['filter'])) { if (empty($networkmap['filter']['x_offs'])) { From e5190a91eeb4116351b6a1740618e93011219863 Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Tue, 12 Mar 2019 10:29:35 +0100 Subject: [PATCH 30/50] WIP NetworkMap class Former-commit-id: 90763db5291c638e89216da48e1fc4fdba92bc82 --- pandora_console/include/class/NetworkMap.class.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php index b223f14862..7c927858d7 100644 --- a/pandora_console/include/class/NetworkMap.class.php +++ b/pandora_console/include/class/NetworkMap.class.php @@ -300,12 +300,6 @@ class NetworkMap ]; $this->graph = $this->generateNetworkMap(); - - // Direct print. Avoid extra options. - // $networkmap['source_period'] = 60; - // $networkmap['filter'] = $this->mapOptions['map_filter']; - // $networkmap['width'] = 1400; - // $networkmap['height'] = 800; } } From c6fa365b904b017d234830bb1a93e237b170d999 Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Tue, 12 Mar 2019 10:47:28 +0100 Subject: [PATCH 31/50] minor fix force discovery console task Former-commit-id: be2a85079f51fca0222ac25f2f93ad5a14f3542d --- .../godmode/wizards/DiscoveryTaskList.class.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php index 3372f8ce63..0d3fcc9b5a 100644 --- a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php +++ b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php @@ -240,7 +240,7 @@ class DiscoveryTaskList extends Wizard $id_console_task = (int) get_parameter('id_console_task'); if ($id_console_task !== null) { - enterprise_hook('cron_task_run', $id_console_task, true); + enterprise_hook('cron_task_run', [$id_console_task, true]); // Trick to avoid double execution. header('Location: '.$this->url); } @@ -511,6 +511,15 @@ class DiscoveryTaskList extends Wizard $data[9] .= '</a>'; } + if ($task['disabled'] != 2) { + $data[9] .= '<a href="#" onclick="show_map('.$task['id_rt'].',\''.$task['name'].'\',\''.$url_ajax.'\')">'; + $data[9] .= html_print_image( + 'images/dynamic_network_icon.png', + true + ); + $data[9] .= '</a>'; + } + if (check_acl( $config['id_user'], $task['id_group'], From 29f00dd1dac4199b7670590252c287d1ffa487d7 Mon Sep 17 00:00:00 2001 From: Tatiana Llorente <tatiana.llorente@artica.es> Date: Tue, 12 Mar 2019 11:09:12 +0100 Subject: [PATCH 32/50] New login page Former-commit-id: ae1cc9368536c6a9fbcea12ec2aa1d6b7584268a --- .../images/custom_logo_login/pandora_logo.png | Bin 4542 -> 8929 bytes .../custom_logo_login/pandora_logo_2.png | Bin 0 -> 4542 bytes pandora_console/include/styles/login.css | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 pandora_console/images/custom_logo_login/pandora_logo_2.png diff --git a/pandora_console/images/custom_logo_login/pandora_logo.png b/pandora_console/images/custom_logo_login/pandora_logo.png index 67aeb1bf842857f742c1b755858df7e44a353a7c..c84a02fb6a4283f810cf1655c3ac4bc60f1ed31a 100644 GIT binary patch literal 8929 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 literal 4542 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 diff --git a/pandora_console/images/custom_logo_login/pandora_logo_2.png b/pandora_console/images/custom_logo_login/pandora_logo_2.png new file mode 100644 index 0000000000000000000000000000000000000000..67aeb1bf842857f742c1b755858df7e44a353a7c GIT binary patch literal 4542 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 literal 0 HcmV?d00001 diff --git a/pandora_console/include/styles/login.css b/pandora_console/include/styles/login.css index 3836dbdfb8..bffcda19d5 100644 --- a/pandora_console/include/styles/login.css +++ b/pandora_console/include/styles/login.css @@ -173,12 +173,12 @@ div.login_pass input { width: 100%; height: 40px; font-size: 10pt; - padding: 0px !important; + padding: 0px 0px 0px 35px !important; background-repeat: no-repeat; background-size: 27px; background-position: left center; - text-indent: 35px; font-family: "Open Sans", sans-serif; + box-sizing: border-box; } div.login_nick input:focus, From d7983bec4ef87bbd17c2f56e54c8608005ac6ab4 Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Tue, 12 Mar 2019 12:05:54 +0100 Subject: [PATCH 33/50] WIP NetworkMap class Former-commit-id: ae987e5f6f3ec0997746093d20f7dbd5758c9ff1 --- .../include/ajax/task_list.ajax.php | 11 + .../include/class/NetworkMap.class.php | 207 ++++++++++-------- .../include/functions_pandora_networkmap.php | 100 +++++++-- .../include/javascript/pandora_taskList.js | 33 +++ 4 files changed, 237 insertions(+), 114 deletions(-) diff --git a/pandora_console/include/ajax/task_list.ajax.php b/pandora_console/include/ajax/task_list.ajax.php index 83968cb2e1..dd4221a05d 100644 --- a/pandora_console/include/ajax/task_list.ajax.php +++ b/pandora_console/include/ajax/task_list.ajax.php @@ -29,6 +29,7 @@ require_once $config['homedir'].'/include/graphs/functions_d3.php'; $progress_task_discovery = (bool) get_parameter('progress_task_discovery', 0); +$showmap = (bool) get_parameter('showmap', 0); if ($progress_task_discovery) { $id_task = get_parameter('id', 0); @@ -72,3 +73,13 @@ if ($progress_task_discovery) { return; } + +if ($showmap) { + include_once $config['homedir'].'/include/class/NetworkMap.class.php'; + $id_task = get_parameter('id', 0); + + $map = new NetworkMap( + ['id_task' => $id_task] + ); + $map->printMap(); +} diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php index 7c927858d7..5cb7eba99a 100644 --- a/pandora_console/include/class/NetworkMap.class.php +++ b/pandora_console/include/class/NetworkMap.class.php @@ -170,29 +170,41 @@ class NetworkMap ]; if (is_array($options)) { + // Previously nodes_and_relations. if (isset($options['graph'])) { $this->graph = $options['graph']; } + // String dotmap. + if (isset($options['dot_graph'])) { + $this->dotGraph = $options['dot_graph']; + } + + // Array of nodes, agents, virtual, etc. if (isset($options['nodes'])) { $this->nodes = $options['nodes']; } + // Array of relations. if (isset($options['relations'])) { $this->relations = $options['relations']; } + // User interface type. Simple or advanced. if (isset($options['mode'])) { $this->mode = $options['mode']; } + // Map options, check default values above. + // This is only used while generating new maps using + // (generateDotGraph). if (is_array($options['map_options'])) { foreach ($options['map_options'] as $k => $v) { $this->mapOptions[$k] = $v; } } - // Load from Discovery task. + // Load from tmap. if ($options['id_map']) { $this->idMap = $options['id_map']; // Update nodes and relations. @@ -204,6 +216,7 @@ class NetworkMap $this->createMap(); } } else { + // Generate from group, task or network. if ($options['id_group']) { $this->idGroup = $options['id_group']; } @@ -238,22 +251,40 @@ class NetworkMap */ public function createMap() { + // If exists, load from DB. if ($this->idMap) { $this->loadMap(); return; } - if ($this->network) { - $this->nodes = networkmap_get_new_nodes_from_ip_mask( - $this->network + // Simulated map. + $this->idMap = uniqid(); + // No tmap definition. Paint data. + if ($this->idTask) { + $recon_task = db_get_row_filter( + 'trecon_task', + ['id_rt' => $networkmap['source_data']] ); + $this->network = $recon_task['subnet']; } - if ($this->idTask) { - // Retrieve data from target task. - $this->loadMap(); - } + // Simulate map entry. + $this->map = [ + 'id' => $this->idMap, + '__simulated' => 1, + 'background' => '', + 'background_options' => 0, + 'source_period' => 60, + 'filter' => $this->mapOptions['map_filter'], + 'width' => 900, + 'height' => 400, + 'center_x' => 450, + 'center_y' => 200, + ]; + + $this->graph = $this->generateNetworkMap(); + } @@ -273,33 +304,6 @@ class NetworkMap // Nodes and relations. $this->graph = networkmap_process_networkmap($this->idMap); - } else { - // Simulated map. - $this->idMap = uniqid(); - // No tmap definition. Paint data. - if ($this->idTask) { - $recon_task = db_get_row_filter( - 'trecon_task', - ['id_rt' => $networkmap['source_data']] - ); - $this->network = $recon_task['subnet']; - } - - // Simulate map entry. - $this->map = [ - 'id' => $this->idMap, - '__simulated' => 1, - 'background' => '', - 'background_options' => 0, - 'source_period' => 60, - 'filter' => $this->mapOptions['map_filter'], - 'width' => 900, - 'height' => 400, - 'center_x' => 450, - 'center_y' => 200, - ]; - - $this->graph = $this->generateNetworkMap(); } } @@ -330,6 +334,46 @@ class NetworkMap } + /** + * Generate a graphviz string structure to be used later. + * + * @return void + */ + public function generateDotGraph() + { + if (!isset($this->dotGraph)) { + // Generate dot file. + $this->dotGraph = networkmap_generate_dot( + get_product_name(), + $this->idGroup, + $this->mapOptions['simple'], + $this->mapOptions['font_size'], + $this->mapOptions['layout'], + $this->mapOptions['nooverlap'], + $this->mapOptions['zoom'], + $this->mapOptions['ranksep'], + $this->mapOptions['center'], + $this->mapOptions['regen'], + $this->mapOptions['pure'], + $this->mapOptions['id'], + $this->mapOptions['show_snmp_modules'], + $this->mapOptions['cut_names'], + $this->mapOptions['relative'], + $this->mapOptions['text_filter'], + $this->network, + $this->mapOptions['dont_show_subgroups'], + // Strict user (strict_user). + false, + // Canvas size (size_canvas). + null, + $this->mapOptions['old_mode'], + $this->mapOptions['map_filter'] + ); + } + + } + + /** * Generates a nodes - relationships array using graphviz dot * schema. @@ -338,6 +382,10 @@ class NetworkMap */ public function generateNetworkMap() { + if (!isset($this->dotGraph)) { + $this->generateDotGraph(); + } + /* * Let graphviz place the nodes. */ @@ -349,56 +397,27 @@ class NetworkMap break; case 1: - $filter = 'dot'; - $layout = 'flat'; + $filter = 'dot'; + $layout = 'flat'; break; case 2: - $filter = 'twopi'; - $layout = 'radial'; + $filter = 'twopi'; + $layout = 'radial'; break; case 3: default: - $filter = 'neato'; - $layout = 'spring1'; + $filter = 'neato'; + $layout = 'spring1'; break; case 4: - $filter = 'fdp'; - $layout = 'spring2'; + $filter = 'fdp'; + $layout = 'spring2'; break; } - $nodes_and_relations = []; - // Generate dot file. - $graph = networkmap_generate_dot( - get_product_name(), - $this->idGroup, - $this->mapOptions['simple'], - $this->mapOptions['font_size'], - $this->mapOptions['layout'], - $this->mapOptions['nooverlap'], - $this->mapOptions['zoom'], - $this->mapOptions['ranksep'], - $this->mapOptions['center'], - $this->mapOptions['regen'], - $this->mapOptions['pure'], - $this->mapOptions['id'], - $this->mapOptions['show_snmp_modules'], - $this->mapOptions['cut_names'], - $this->mapOptions['relative'], - $this->mapOptions['text_filter'], - $this->network, - $this->mapOptions['dont_show_subgroups'], - // Strict user (strict_user). - false, - // Canvas size (size_canvas). - null, - $this->mapOptions['old_mode'], - $this->mapOptions['map_filter'] - ); - switch (PHP_OS) { case 'WIN32': case 'WINNT': @@ -421,7 +440,7 @@ class NetworkMap $filename_dot .= '_'.$this->idMap.'.dot'; - file_put_contents($filename_dot, $graph); + file_put_contents($filename_dot, $this->dotGraph); switch (PHP_OS) { case 'WIN32': @@ -449,13 +468,11 @@ class NetworkMap $this->idMap, $filename_plain, $relation_nodes, - $graph + $this->dotGraph ); unlink($filename_plain); - $id = $this->idMap; - /* * Graphviz section ends here. */ @@ -485,7 +502,7 @@ class NetworkMap $node_center = []; foreach ($nodes as $key => $node) { $nodes_and_relations['nodes'][$index]['id'] = $node['id']; - $nodes_and_relations['nodes'][$index]['id_map'] = $id; + $nodes_and_relations['nodes'][$index]['id_map'] = $this->idMap; $children_count = 0; foreach ($relation_nodes as $relation) { @@ -532,7 +549,7 @@ class NetworkMap $nodes_and_relations['relations'] = []; $index = 0; foreach ($relation_nodes as $relation) { - $nodes_and_relations['relations'][$index]['id_map'] = $id; + $nodes_and_relations['relations'][$index]['id_map'] = $this->idMap; if (($relation['parent_type'] == 'agent') || ($relation['parent_type'] == '')) { $nodes_and_relations['relations'][$index]['id_parent'] = $relation['id_parent']; @@ -565,34 +582,33 @@ class NetworkMap $index++; } - if ($this->idMap > 0) { + if ($this->idMap > 0 && (!isset($this->map['__simulated']))) { enterprise_hook( 'save_generate_nodes', [ - $id, + $this->idMap, $nodes_and_relations, ] ); - $pandorafms_node = $nodes_and_relations['nodes'][0]; $center = [ 'x' => $node_center['x'], 'y' => $node_center['y'], ]; - $networkmap['center_x'] = $center['x']; - $networkmap['center_y'] = $center['y']; + $this->map['center_x'] = $center['x']; + $this->map['center_y'] = $center['y']; db_process_sql_update( 'tmap', [ - 'center_x' => $networkmap['center_x'], - 'center_y' => $networkmap['center_y'], + 'center_x' => $this->map['center_x'], + 'center_y' => $this->map['center_y'], ], - ['id' => $id] + ['id' => $this->idMap] ); } else { - $this->map['center_x'] = $center['x']; - $this->map['center_y'] = $center['y']; + $this->map['center_x'] = $node_center['x']; + $this->map['center_y'] = $node_center['y']; } return $nodes_and_relations; @@ -633,11 +649,14 @@ class NetworkMap { $networkmap = $this->map; + $simulate = false; if (!isset($networkmap['__simulated'])) { $networkmap['filter'] = json_decode( $networkmap['filter'], true ); + } else { + $simulate = true; } // Hardcoded. @@ -719,7 +738,8 @@ class NetworkMap $item = networkmap_db_node_to_js_node( $node, $count, - $count_item_holding_area + $count_item_holding_area, + $simulate ); if ($item['deleted']) { continue; @@ -739,7 +759,11 @@ class NetworkMap // interfaces. networkmap_clean_relations_for_js($relations); - $links_js = networkmap_links_to_js_links($relations, $nodes_graph); + $links_js = networkmap_links_to_js_links( + $relations, + $nodes_graph, + $simulate + ); $array_aux = []; foreach ($links_js as $link_js) { @@ -1404,8 +1428,7 @@ class NetworkMap $output .= $this->loadController(); $output .= $this->loadAdvancedInterface(); } else { - // Simple mode, no tmap entries. - $this->idMap = '0'; + // Simulated, no tmap entries. $output .= $this->loadMapSkel(); $output .= $this->loadMapData(); $output .= $this->loadController(); diff --git a/pandora_console/include/functions_pandora_networkmap.php b/pandora_console/include/functions_pandora_networkmap.php index d92b1b5213..100d7625ee 100644 --- a/pandora_console/include/functions_pandora_networkmap.php +++ b/pandora_console/include/functions_pandora_networkmap.php @@ -471,8 +471,22 @@ function get_networkmaps($id) } -function networkmap_db_node_to_js_node($node, &$count, &$count_item_holding_area) -{ +/** + * Translates node (nodes_and_relations) into JS node. + * + * @param array $node Node. + * @param integer $count Count. + * @param integer $count_item_holding_area Count_item_holding_area. + * @param boolean $simulated Simulated. + * + * @return array JS nodes. + */ +function networkmap_db_node_to_js_node( + $node, + &$count, + &$count_item_holding_area, + $simulated=false +) { global $config; $networkmap = db_get_row('tmap', 'id', $node['id_map']); @@ -492,7 +506,7 @@ function networkmap_db_node_to_js_node($node, &$count, &$count_item_holding_area $item = []; $item['id'] = $count; - if (enterprise_installed()) { + if (enterprise_installed() && $simulated === false) { enterprise_include_once('include/functions_pandora_networkmap.php'); $item['id_db'] = $node['id_in_db']; } else { @@ -670,29 +684,53 @@ function networkmap_clean_relations_for_js(&$relations) } -function networkmap_links_to_js_links($relations, $nodes_graph) -{ +/** + * Transform networkmap relations into js links. + * + * @param array $relations Relations. + * @param array $nodes_graph Nodes_graph. + * @param boolean $simulated Simulated. + * + * @return array JS relations. + */ +function networkmap_links_to_js_links( + $relations, + $nodes_graph, + $simulated=false +) { $return = []; - if (enterprise_installed()) { + if (enterprise_installed() && $simulated === false) { enterprise_include_once('include/functions_pandora_networkmap.php'); } $count = 0; foreach ($relations as $key => $relation) { if (($relation['parent_type'] == 1) && ($relation['child_type'] == 1)) { - $id_target_agent = agents_get_agent_id_by_module_id($relation['id_parent_source_data']); - $id_source_agent = agents_get_agent_id_by_module_id($relation['id_child_source_data']); + $id_target_agent = agents_get_agent_id_by_module_id( + $relation['id_parent_source_data'] + ); + $id_source_agent = agents_get_agent_id_by_module_id( + $relation['id_child_source_data'] + ); $id_target_module = $relation['id_parent_source_data']; $id_source_module = $relation['id_child_source_data']; - } else if (($relation['parent_type'] == 1) && ($relation['child_type'] == 0)) { - $id_target_agent = agents_get_agent_id_by_module_id($relation['id_parent_source_data']); + } else if (($relation['parent_type'] == 1) + && ($relation['child_type'] == 0) + ) { + $id_target_agent = agents_get_agent_id_by_module_id( + $relation['id_parent_source_data'] + ); $id_target_module = $relation['id_parent_source_data']; $id_source_agent = $relation['id_child_source_data']; - } else if (($relation['parent_type'] == 0) && ($relation['child_type'] == 1)) { + } else if (($relation['parent_type'] == 0) + && ($relation['child_type'] == 1) + ) { $id_target_agent = $relation['id_parent_source_data']; $id_source_module = $relation['id_child_source_data']; - $id_source_agent = agents_get_agent_id_by_module_id($relation['id_child_source_data']); + $id_source_agent = agents_get_agent_id_by_module_id( + $relation['id_child_source_data'] + ); } else { $id_target_agent = $relation['id_parent_source_data']; $id_source_agent = $relation['id_child_source_data']; @@ -701,7 +739,7 @@ function networkmap_links_to_js_links($relations, $nodes_graph) $item = []; $item['id'] = $count; $count++; - if (enterprise_installed()) { + if (enterprise_installed() && $simulated === false) { $item['id_db'] = get_relation_id($relation); } else { $item['id_db'] = $key; @@ -720,7 +758,7 @@ function networkmap_links_to_js_links($relations, $nodes_graph) $item['source'] = -1; $item['deleted'] = $relation['deleted']; - if (enterprise_installed()) { + if (enterprise_installed() && $simulated === false) { $target_and_source = []; $target_and_source = get_id_target_and_source_in_db($relation); $item['target_id_db'] = (int) $target_and_source['target']; @@ -779,8 +817,12 @@ function networkmap_links_to_js_links($relations, $nodes_graph) $item['link_color'] = '#FAD403'; } - $agent = agents_get_agent_id_by_module_id($relation['id_parent_source_data']); - $agent2 = agents_get_agent_id_by_module_id($relation['id_child_source_data']); + $agent = agents_get_agent_id_by_module_id( + $relation['id_parent_source_data'] + ); + $agent2 = agents_get_agent_id_by_module_id( + $relation['id_child_source_data'] + ); foreach ($nodes_graph as $key2 => $node) { if (isset($node['id_agent'])) { if ($node['id_agent'] == $agent) { @@ -805,7 +847,9 @@ function networkmap_links_to_js_links($relations, $nodes_graph) $item['link_color'] = '#FAD403'; } - $agent2 = agents_get_agent_id_by_module_id($relation['id_child_source_data']); + $agent2 = agents_get_agent_id_by_module_id( + $relation['id_child_source_data'] + ); foreach ($nodes_graph as $key2 => $node) { if (isset($node['id_agent'])) { if ($node['id_agent'] == $relation['id_parent_source_data']) { @@ -830,7 +874,9 @@ function networkmap_links_to_js_links($relations, $nodes_graph) $item['link_color'] = '#FAD403'; } - $agent = agents_get_agent_id_by_module_id($relation['id_parent_source_data']); + $agent = agents_get_agent_id_by_module_id( + $relation['id_parent_source_data'] + ); foreach ($nodes_graph as $key2 => $node) { if (isset($node['id_agent'])) { if ($node['id_agent'] == $agent) { @@ -848,7 +894,9 @@ function networkmap_links_to_js_links($relations, $nodes_graph) } } } - } else if (($relation['parent_type'] == 3) && ($relation['child_type'] == 3)) { + } else if (($relation['parent_type'] == 3) + && ($relation['child_type'] == 3) + ) { foreach ($nodes_graph as $key2 => $node) { if ($relation['id_parent'] == $node['id_db']) { $agent = $node['id_db']; @@ -860,7 +908,9 @@ function networkmap_links_to_js_links($relations, $nodes_graph) $agent2 = $node['id_db']; } } - } else if (($relation['parent_type'] == 3) || ($relation['child_type'] == 3)) { + } else if (($relation['parent_type'] == 3) + || ($relation['child_type'] == 3) + ) { if ($relation['parent_type'] == 3) { foreach ($nodes_graph as $key2 => $node) { if ($relation['id_parent'] == $node['id_db']) { @@ -898,7 +948,10 @@ function networkmap_links_to_js_links($relations, $nodes_graph) } } - if ((($item['target'] == -1) || ($item['source'] == -1)) && $relation['parent_type'] == 1 && $relation['child_type'] == 1) { + if ((($item['target'] == -1) || ($item['source'] == -1)) + && $relation['parent_type'] == 1 + && $relation['child_type'] == 1 + ) { continue; } @@ -1112,7 +1165,10 @@ function networkmap_loadfile( ) { global $config; - $height_map = db_get_value('height', 'tmap', 'id', $id); + $height_map = 200; + if ((int) $id > 0) { + $height_map = db_get_value('height', 'tmap', 'id', $id); + } $networkmap_nodes = []; diff --git a/pandora_console/include/javascript/pandora_taskList.js b/pandora_console/include/javascript/pandora_taskList.js index f8fe84e8c2..dc6fd13208 100644 --- a/pandora_console/include/javascript/pandora_taskList.js +++ b/pandora_console/include/javascript/pandora_taskList.js @@ -31,3 +31,36 @@ function progress_task_list(id, name, url) { } }); } + +function show_map(id, name, url) { + var params = []; + params.push("page=include/ajax/task_list.ajax"); + params.push("showmap=1"); + params.push("id=" + id); + + $("#progress_task") + .empty() + .hide() + .append("<p>Loading map</p>") + .dialog({ + title: "Task: " + name, + resizable: true, + draggable: true, + modal: false, + width: 1280, + height: 700 + }) + .show(); + + jQuery.ajax({ + data: params.join("&"), + type: "POST", + url: (action = url), + dataType: "html", + success: function(data) { + $("#progress_task") + .empty() + .append(data); + } + }); +} From 5227390c87eb25f09fcde3be5c53017c527423b4 Mon Sep 17 00:00:00 2001 From: "marcos.alconada" <marcos.alconada@artica.es> Date: Tue, 12 Mar 2019 13:06:27 +0100 Subject: [PATCH 34/50] se elimina linea de autosearch = false Former-commit-id: aab03c4e38d41b098a8af818b45036f6524580de --- pandora_console/operation/agentes/status_monitor.php | 1 - 1 file changed, 1 deletion(-) diff --git a/pandora_console/operation/agentes/status_monitor.php b/pandora_console/operation/agentes/status_monitor.php index 4a4114b6f8..31e7cb2f2a 100644 --- a/pandora_console/operation/agentes/status_monitor.php +++ b/pandora_console/operation/agentes/status_monitor.php @@ -94,7 +94,6 @@ if ($id_module) { $status = -1; $ag_modulename = modules_get_agentmodule_name($id_module); $ag_freestring = modules_get_agentmodule_agent_alias($id_module); - $autosearch = false; } enterprise_hook('open_meta_frame'); From 06f8aae91a7e199029df8f56115b88b4b6564233 Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Tue, 12 Mar 2019 16:22:28 +0100 Subject: [PATCH 35/50] WIP NetworkMap class Former-commit-id: 575e0b5d078d01ac82ce313eda57084441fb4301 --- .../wizards/DiscoveryTaskList.class.php | 2 +- .../include/class/NetworkMap.class.php | 316 ++++++++++++++---- .../operation/agentes/pandora_networkmap.php | 21 +- .../agentes/pandora_networkmap.view.php | 2 +- 4 files changed, 257 insertions(+), 84 deletions(-) diff --git a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php index 0d3fcc9b5a..2cedd211d4 100644 --- a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php +++ b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php @@ -511,7 +511,7 @@ class DiscoveryTaskList extends Wizard $data[9] .= '</a>'; } - if ($task['disabled'] != 2) { + if ($task['disabled'] != 2 && $task['utimestamp'] > 0) { $data[9] .= '<a href="#" onclick="show_map('.$task['id_rt'].',\''.$task['name'].'\',\''.$url_ajax.'\')">'; $data[9] .= html_print_image( 'images/dynamic_network_icon.png', diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php index 5cb7eba99a..ffbc9435a4 100644 --- a/pandora_console/include/class/NetworkMap.class.php +++ b/pandora_console/include/class/NetworkMap.class.php @@ -34,6 +34,17 @@ require_once $config['homedir'].'/include/functions_pandora_networkmap.php'; enterprise_include_once('include/functions_pandora_networkmap.php'); +define('SOURCE_GROUP', 0); +define('SOURCE_TASK', 1); +define('SOURCE_NETWORK', 2); + +define('LAYOUT_CIRCULAR', 0); +define('LAYOUT_FLAT', 1); +define('LAYOUT_RADIAL', 2); +define('LAYOUT_SPRING1', 3); +define('LAYOUT_SPRING2', 4); + + /** * Manage networkmaps in Pandora FMS */ @@ -138,13 +149,12 @@ class NetworkMap public function __construct($options=false) { // Default mapOptions values. - // Default neato. - $this->mapOptions['generation_method'] = 3; + // Defines the command to generate positions. + $this->mapOptions['generation_method'] = LAYOUT_SPRING1; $this->mapOptions['simple'] = 0; $this->mapOptions['font_size'] = 12; - $this->mapOptions['layout'] = 'spring1'; $this->mapOptions['nooverlap'] = 1; - $this->mapOptions['zoom'] = 0.5; + $this->mapOptions['z_dash'] = 0.5; $this->mapOptions['ranksep'] = 0.5; $this->mapOptions['center'] = 0; $this->mapOptions['regen'] = 0; @@ -164,7 +174,7 @@ class NetworkMap 'y_offs' => 0, 'z_dash' => 0.5, 'node_sep' => 0.1, - 'rank_sep' => 1, + 'rank_sep' => 0.1, 'mindist' => 1, 'kval' => 0.1, ]; @@ -264,7 +274,7 @@ class NetworkMap if ($this->idTask) { $recon_task = db_get_row_filter( 'trecon_task', - ['id_rt' => $networkmap['source_data']] + ['id_rt' => $this->idTask] ); $this->network = $recon_task['subnet']; } @@ -277,13 +287,14 @@ class NetworkMap 'background_options' => 0, 'source_period' => 60, 'filter' => $this->mapOptions['map_filter'], - 'width' => 900, - 'height' => 400, - 'center_x' => 450, - 'center_y' => 200, + 'width' => 0, + 'height' => 0, + 'center_x' => 0, + 'center_y' => 0, ]; - $this->graph = $this->generateNetworkMap(); + // Will be stored in $this->graph. + $this->generateNetworkMap(); } @@ -295,15 +306,60 @@ class NetworkMap */ public function loadMap() { + if ($this->map) { + // Already loaded. + return; + } + if ($this->idMap) { $this->map = db_get_row('tmap', 'id', $this->idMap); + $this->mapOptions['map_filter'] = json_decode( + $this->map['filter'], + true + ); + + foreach ($this->map as $k => $v) { + $this->mapOptions[$k] = $v; + } + + // Retrieve data origin. + $this->network = null; + $this->idTask = null; + $this->idGroup = $this->map['id_group']; + + switch ($this->map['source']) { + case SOURCE_GROUP: + $this->idGroup = $this->map['source_data']; + break; + + case SOURCE_TASK: + $this->idTask = $this->map['source_data']; + break; + + case SOURCE_NETWORK: + $this->network = $this->map['source_data']; + break; + + default: + // Ignore. + break; + } + + if ($this->idTask) { + $recon_task = db_get_row_filter( + 'trecon_task', + ['id_rt' => $networkmap['source_data']] + ); + $this->network = $recon_task['subnet']; + } + // Retrieve or update nodes and relations. $this->getNodes(); $this->getRelations(); - // Nodes and relations. - $this->graph = networkmap_process_networkmap($this->idMap); + // Nodes and relations will be stored in $this->graph. + $this->loadGraph(); } } @@ -334,6 +390,98 @@ class NetworkMap } + /** + * Return relations of current map. + * + * @return array Relations. + */ + public function getRelations() + { + if ($this->relations) { + return $this->relations; + } + + if ($this->idMap !== false) { + if (enterprise_installed()) { + $this->relations = enterprise_hook( + 'get_relations_from_db', + [$this->idMap] + ); + } + } + + return $this->relations; + + } + + + /** + * Generates or loads nodes&relations array from data load + * and stores it in $this->graph. + * + * @return void + */ + public function loadGraph() + { + $nodes = $this->nodes; + $relations = $this->relations; + + // Generate if there's no data in DB about nodes or relations. + if (empty($nodes) || empty($relations)) { + $this->generateNetworkMap(); + return; + } + + $nodes_and_relations = []; + $nodes_and_relations['nodes'] = []; + $index_nodes = 0; + foreach ($nodes as $node) { + if (!$node['deleted']) { + $nodes_and_relations['nodes'][$index_nodes]['id_map'] = $node['id_map']; + $nodes_and_relations['nodes'][$index_nodes]['x'] = $node['x']; + $nodes_and_relations['nodes'][$index_nodes]['y'] = $node['y']; + $nodes_and_relations['nodes'][$index_nodes]['source_data'] = $node['source_data']; + $nodes_and_relations['nodes'][$index_nodes]['type'] = $node['type']; + + $style_node = json_decode($node['style'], true); + $style = []; + $style['shape'] = $style_node['shape']; + $style['image'] = $style_node['image']; + $style['width'] = $style_node['width']; + $style['height'] = $style_node['height']; + $style['label'] = $style_node['label']; + $style['id_networkmap'] = $style_node['networkmap']; + $nodes_and_relations['nodes'][$index_nodes]['style'] = json_encode($style); + + if ($node['type'] == 1) { + $nodes_and_relations['nodes'][$index_nodes]['id_agent'] = $style_node['id_agent']; + } + + $nodes_and_relations['nodes'][$index_nodes]['id_in_db'] = $node['id']; + + $index_nodes++; + } + } + + $nodes_and_relations['relations'] = []; + $index_relations = 0; + foreach ($relations as $relation) { + $nodes_and_relations['relations'][$index_relations]['id_map'] = $relation['id_map']; + $nodes_and_relations['relations'][$index_relations]['id_parent'] = $relation['id_parent']; + $nodes_and_relations['relations'][$index_relations]['id_child'] = $relation['id_child']; + $nodes_and_relations['relations'][$index_relations]['parent_type'] = $relation['parent_type']; + $nodes_and_relations['relations'][$index_relations]['child_type'] = $relation['child_type']; + $nodes_and_relations['relations'][$index_relations]['id_parent_source_data'] = $relation['id_parent_source_data']; + $nodes_and_relations['relations'][$index_relations]['id_child_source_data'] = $relation['id_child_source_data']; + + $index_relations++; + } + + $this->graph = $nodes_and_relations; + + } + + /** * Generate a graphviz string structure to be used later. * @@ -350,7 +498,7 @@ class NetworkMap $this->mapOptions['font_size'], $this->mapOptions['layout'], $this->mapOptions['nooverlap'], - $this->mapOptions['zoom'], + $this->mapOptions['z_dash'], $this->mapOptions['ranksep'], $this->mapOptions['center'], $this->mapOptions['regen'], @@ -375,49 +523,88 @@ class NetworkMap /** - * Generates a nodes - relationships array using graphviz dot - * schema. + * Creates an empty dot graph (with only base node) * - * @return array Node - relationship calculated. + * @return void + */ + public function generateEmptyDotGraph() + { + // Create an empty map dot structure. + $graph = networkmap_open_graph( + $this->mapOptions['layout'], + $this->mapOptions['nooverlap'], + $this->mapOptions['pure'], + $this->mapOptions['z_dash'], + $this->mapOptions['ranksep'], + $this->mapOptions['font_size'], + null + ); + $graph .= networkmap_create_pandora_node( + get_product_name(), + $this->mapOptions['font_size'], + $this->mapOptions['simple'] + ); + $graph .= networkmap_close_graph(); + + $this->dotGraph = $graph; + } + + + /** + * Generates a nodes - relationships array using graphviz dot + * schema and stores nodes&relations into $this->graph. + * + * @return void */ public function generateNetworkMap() { - if (!isset($this->dotGraph)) { - $this->generateDotGraph(); - } + global $config; + + include_once 'include/functions_os.php'; + + $map_filter = json_decode( + $this->map['filter'], + true + ); /* * Let graphviz place the nodes. */ switch ($this->mapOptions['generation_method']) { - case 0: + case LAYOUT_CIRCULAR: $filter = 'circo'; - $layout = 'circular'; + $this->mapOptions['layout'] = 'circular'; break; - case 1: + case LAYOUT_FLAT: $filter = 'dot'; - $layout = 'flat'; + $this->mapOptions['layout'] = 'flat'; break; - case 2: + case LAYOUT_RADIAL: $filter = 'twopi'; - $layout = 'radial'; + $this->mapOptions['layout'] = 'radial'; break; - case 3: + case LAYOUT_SPRING1: default: $filter = 'neato'; - $layout = 'spring1'; + $this->mapOptions['layout'] = 'spring1'; break; - case 4: + case LAYOUT_SPRING2: $filter = 'fdp'; - $layout = 'spring2'; + $this->mapOptions['layout'] = 'spring2'; break; } + if ($map_filter['empty_map']) { + $this->generateEmptyDotGraph(); + } else if (!isset($this->dotGraph)) { + $this->generateDotGraph(); + } + switch (PHP_OS) { case 'WIN32': case 'WINNT': @@ -548,6 +735,7 @@ class NetworkMap $nodes_and_relations['relations'] = []; $index = 0; + foreach ($relation_nodes as $relation) { $nodes_and_relations['relations'][$index]['id_map'] = $this->idMap; @@ -583,13 +771,15 @@ class NetworkMap } if ($this->idMap > 0 && (!isset($this->map['__simulated']))) { - enterprise_hook( - 'save_generate_nodes', - [ - $this->idMap, - $nodes_and_relations, - ] - ); + if (enterprise_installed()) { + $nodes_and_relations = enterprise_hook( + 'save_generate_nodes', + [ + $this->idMap, + $nodes_and_relations, + ] + ); + } $center = [ 'x' => $node_center['x'], @@ -611,31 +801,7 @@ class NetworkMap $this->map['center_y'] = $node_center['y']; } - return $nodes_and_relations; - } - - - /** - * Return relations of current map. - * - * @return array Relations. - */ - public function getRelations() - { - if ($this->relations) { - return $this->relations; - } - - if ($this->idMap !== false) { - if (enterprise_installed()) { - $this->relations = enterprise_hook( - 'get_relations_from_db', - [$this->idMap] - ); - } - } - - return $this->relations; + $this->graph = $nodes_and_relations; } @@ -655,16 +821,20 @@ class NetworkMap $networkmap['filter'], true ); + $networkmap['filter']['holding_area'] = [ + 500, + 500, + ]; + $holding_area_title = __('Holding Area'); } else { $simulate = true; + $holding_area_title = ''; + $networkmap['filter']['holding_area'] = [ + 0, + 0, + ]; } - // Hardcoded. - $networkmap['filter']['holding_area'] = [ - 500, - 500, - ]; - $this->graph['relations'] = clean_duplicate_links( $this->graph['relations'] ); @@ -834,7 +1004,7 @@ class NetworkMap $output .= "var translation_none = '".__('None')."';\n"; $output .= "var dialog_node_edit_title = '".__('Edit node %s')."';\n"; - $output .= "var holding_area_title = '".__('Holding Area')."';\n"; + $output .= "var holding_area_title = '".$holding_area_title."';\n"; $output .= "var edit_menu = '".__('Show details and options')."';\n"; $output .= "var interface_link_add = '".__('Add a interface link')."';\n"; $output .= "var set_parent_link = '".__('Set parent interface')."';\n"; @@ -1332,9 +1502,9 @@ class NetworkMap ui_require_css_file('jquery.contextMenu', 'include/styles/js/'); $output = ''; - $hide_minimap = ''; - if ($dashboard_mode) { - $hide_minimap = 'none'; + $minimap_display = ''; + if ($this->mapOptions['pure']) { + $minimap_display = 'none'; } $networkmap = $this->map; @@ -1350,7 +1520,7 @@ class NetworkMap $output .= '<div id="networkconsole_'.$networkmap['id'].'"'; $output .= ' style="position: relative; overflow: hidden; background: #FAFAFA">'; - $output .= '<div style="display: '.$hide_minimap.';">'; + $output .= '<div style="display: '.$minimap_display.';">'; $output .= '<canvas id="minimap_'.$networkmap['id'].'"'; $output .= ' style="position: absolute; left: 0px; top: 0px; border: 1px solid #bbbbbb;">'; $output .= '</canvas>'; diff --git a/pandora_console/operation/agentes/pandora_networkmap.php b/pandora_console/operation/agentes/pandora_networkmap.php index 2050b37910..431cf305d6 100644 --- a/pandora_console/operation/agentes/pandora_networkmap.php +++ b/pandora_console/operation/agentes/pandora_networkmap.php @@ -126,7 +126,10 @@ if (enterprise_installed()) { $id = $result; define('_id_', $id); - $tab = 'view'; + if ($result !== false) { + $tab = 'view'; + header('Location: '.$_SERVER['HTTP_REFERER'].'&tab='.$tab.'&id_networkmap='.$id); + } } else if ($update_empty_networkmap) { $id_group = (int) get_parameter('id_group', 0); @@ -189,9 +192,9 @@ if (enterprise_installed()) { } } -$result_txt = ''; // The networkmap doesn't exist yet if ($new_networkmap || $save_networkmap) { + $result_txt = ''; if ($new_networkmap) { if ($networkmaps_write || $networkmaps_manage) { include 'pandora_networkmap.editor.php'; @@ -349,14 +352,15 @@ if ($new_networkmap || $save_networkmap) { $id = $result; define('_id_', $id); - $tab = 'view'; + if ($result !== false) { + if ($values['generation_method'] == 6) { + $tab = 'r_dinamic'; + define('_activeTab_', 'radial_dynamic'); + } - if ($values['generation_method'] == 6) { - $tab = 'r_dinamic'; - define('_activeTab_', 'radial_dynamic'); + $tab = 'view'; + header('Location: '.$_SERVER['HTTP_REFERER'].'&tab='.$tab.'&id_networkmap='.$id); } - - header('Location: '.$_SERVER['HTTP_REFERER'].'&tab=view&id_networkmap='.$id); } } // The networkmap exists @@ -758,4 +762,3 @@ switch ($tab) { } break; } - diff --git a/pandora_console/operation/agentes/pandora_networkmap.view.php b/pandora_console/operation/agentes/pandora_networkmap.view.php index 2e7e6014c0..2cc4e23dcd 100644 --- a/pandora_console/operation/agentes/pandora_networkmap.view.php +++ b/pandora_console/operation/agentes/pandora_networkmap.view.php @@ -772,6 +772,7 @@ html_print_input_hidden('center_logo', ui_get_full_url(ui_get_logo_to_center_net $dash_mode = 0; $map_dash_details = []; $networkmap = db_get_row('tmap', 'id', $id); + if (enterprise_installed()) { include_once 'enterprise/dashboard/widgets/network_map.php'; if ($id_networkmap) { @@ -783,7 +784,6 @@ if (enterprise_installed()) { $map_dash_details['x_offs'] = $x_offs; $map_dash_details['y_offs'] = $y_offs; $map_dash_details['z_dash'] = $z_dash; - $networkmap = db_get_row('tmap', 'id', $id); } else { $networkmap_filter = json_decode($networkmap['filter'], true); From c91c79a735d49adc64de7b89ddbca079b77edbda Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Tue, 12 Mar 2019 16:52:42 +0100 Subject: [PATCH 36/50] WIP experiments with graphviz Former-commit-id: cee005851cd7ed05aa43fd3037c5c7d743d06fa7 --- pandora_console/include/functions_networkmap.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pandora_console/include/functions_networkmap.php b/pandora_console/include/functions_networkmap.php index 3d6ee59531..34eadefa65 100644 --- a/pandora_console/include/functions_networkmap.php +++ b/pandora_console/include/functions_networkmap.php @@ -689,7 +689,7 @@ function networkmap_create_edge($head, $tail, $layout, $nooverlap, $pure, $zoom, } // edgeURL allows node navigation - $edge = "\n".$head.' -- '.$tail.'[color="#BDBDBD", headclip=false, tailclip=false, edgeURL=""];'."\n"; + $edge = "\n".$head.' -- '.$tail.'[len=3, color="#BDBDBD", headclip=false, tailclip=false, edgeURL=""];'."\n"; return $edge; } @@ -1188,7 +1188,7 @@ function networkmap_open_graph( $nooverlap, $pure, $zoom, - $ranksep, + $rank_sep, $font_size, $size_canvas, $map_filter=[] @@ -1250,7 +1250,7 @@ function networkmap_open_graph( $head = 'graph networkmap { dpi=100; bgcolor="transparent"; labeljust=l; margin=0; pad="0.75,0.75";'; if ($nooverlap != '') { $head .= 'overlap="false";'; - $head .= 'outputorder=edgesfirst;'; + $head .= 'outputorder=first;'; } if ($layout == 'flat' || $layout == 'spring1' || $layout == 'spring2') { @@ -1275,12 +1275,13 @@ function networkmap_open_graph( $head .= "mindist=\"$mindist\";"; } - $head .= 'ratio=fill;'; + $head .= 'ratio="fill";'; $head .= 'root=0;'; $head .= "nodesep=\"$node_sep\";"; $head .= "size=\"$size\";"; $head .= "\n"; + return $head; } From 1bc326c00cba6a43d071eec2e6ece07bc5911946 Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Tue, 12 Mar 2019 18:17:18 +0100 Subject: [PATCH 37/50] WIP: NetworkMap class Former-commit-id: 888621c19262397298ac934e26e55a0b0ab218ec --- .../include/class/NetworkMap.class.php | 25 +++++++++++-------- pandora_console/include/constants.php | 14 +++++++++++ .../include/functions_networkmap.php | 2 +- .../include/functions_pandora_networkmap.php | 10 ++++---- .../operation/agentes/pandora_networkmap.php | 16 ++++++------ .../agentes/pandora_networkmap.view.php | 2 +- 6 files changed, 43 insertions(+), 26 deletions(-) diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php index ffbc9435a4..2abca6dc75 100644 --- a/pandora_console/include/class/NetworkMap.class.php +++ b/pandora_console/include/class/NetworkMap.class.php @@ -38,13 +38,6 @@ define('SOURCE_GROUP', 0); define('SOURCE_TASK', 1); define('SOURCE_NETWORK', 2); -define('LAYOUT_CIRCULAR', 0); -define('LAYOUT_FLAT', 1); -define('LAYOUT_RADIAL', 2); -define('LAYOUT_SPRING1', 3); -define('LAYOUT_SPRING2', 4); - - /** * Manage networkmaps in Pandora FMS */ @@ -625,15 +618,16 @@ class NetworkMap $filename_dot .= '_nooverlap'; } - $filename_dot .= '_'.$this->idMap.'.dot'; + $filename_dot .= uniqid().'_'.$this->idMap.'.dot'; file_put_contents($filename_dot, $this->dotGraph); + $plain_file = 'plain'.uniqid().'.txt'; switch (PHP_OS) { case 'WIN32': case 'WINNT': case 'Windows': - $filename_plain = sys_get_temp_dir().'\\plain.txt'; + $filename_plain = sys_get_temp_dir().'\\'.$plain_file; $cmd = io_safe_output( $config['graphviz_bin_dir'].'\\'.$filter.'.exe -Tplain -o '.$filename_plain.' '.$filename_dot @@ -641,13 +635,22 @@ class NetworkMap break; default: - $filename_plain = sys_get_temp_dir().'/plain.txt'; + $filename_plain = sys_get_temp_dir().'/'.$plain_file; $cmd = $filter.' -Tplain -o '.$filename_plain.' '.$filename_dot; break; } - $r = system($cmd); + $retval = 0; + $r = system($cmd, $retval); + + if ($retval != 0) { + ui_print_error_message( + __('Failed to generate dotmap, please select different layout schema') + ); + $this->graph = networkmap_process_networkmap($this->idMap); + return; + } unlink($filename_dot); diff --git a/pandora_console/include/constants.php b/pandora_console/include/constants.php index b472f98ad8..699264b17a 100644 --- a/pandora_console/include/constants.php +++ b/pandora_console/include/constants.php @@ -535,6 +535,20 @@ define('MAP_GENERATION_RADIAL', 2); define('MAP_GENERATION_SPRING1', 3); define('MAP_GENERATION_SPRING2', 4); +// Algorithm: Circo. +define('LAYOUT_CIRCULAR', 0); +// Algorithm: Dot. +define('LAYOUT_FLAT', 1); +// Algorithm: Twopi. +define('LAYOUT_RADIAL', 2); +// Algorithm: Neato. +define('LAYOUT_SPRING1', 3); +// Algorithm: Fdp. +define('LAYOUT_SPRING2', 4); +// Extra: radial dynamic. +define('LAYOUT_RADIAL_DYNAMIC', 6); + + define('MAP_SOURCE_GROUP', 0); define('MAP_SOURCE_IP_MASK', 1); diff --git a/pandora_console/include/functions_networkmap.php b/pandora_console/include/functions_networkmap.php index 34eadefa65..b5443ae8b6 100644 --- a/pandora_console/include/functions_networkmap.php +++ b/pandora_console/include/functions_networkmap.php @@ -329,7 +329,7 @@ function networkmap_generate_dot( $filter[] = '(nombre COLLATE utf8_general_ci LIKE "%'.$text_filter.'%")'; } - if ($group >= 1) { + if ($group >= 0 && empty($ip_mask)) { if ($dont_show_subgroups) { $filter['id_grupo'] = $group; } else { diff --git a/pandora_console/include/functions_pandora_networkmap.php b/pandora_console/include/functions_pandora_networkmap.php index 100d7625ee..a74dfca8cc 100644 --- a/pandora_console/include/functions_pandora_networkmap.php +++ b/pandora_console/include/functions_pandora_networkmap.php @@ -57,27 +57,27 @@ function networkmap_process_networkmap($id=0) $pure = (int) get_parameter('pure', 0); switch ($networkmap['generation_method']) { - case 0: + case LAYOUT_CIRCULAR: $filter = 'circo'; $layout = 'circular'; break; - case 1: + case LAYOUT_FLAT: $filter = 'dot'; $layout = 'flat'; break; - case 2: + case LAYOUT_RADIAL: $filter = 'twopi'; $layout = 'radial'; break; - case 3: + case LAYOUT_SPRING1: $filter = 'neato'; $layout = 'spring1'; break; - case 4: + case LAYOUT_SPRING2: $filter = 'fdp'; $layout = 'spring2'; break; diff --git a/pandora_console/operation/agentes/pandora_networkmap.php b/pandora_console/operation/agentes/pandora_networkmap.php index 431cf305d6..13100799cb 100644 --- a/pandora_console/operation/agentes/pandora_networkmap.php +++ b/pandora_console/operation/agentes/pandora_networkmap.php @@ -272,31 +272,31 @@ if ($new_networkmap || $save_networkmap) { switch ($method) { case 'twopi': - $values['generation_method'] = 2; + $values['generation_method'] = LAYOUT_RADIAL; break; case 'dot': - $values['generation_method'] = 1; + $values['generation_method'] = LAYOUT_FLAT; break; case 'circo': - $values['generation_method'] = 0; + $values['generation_method'] = LAYOUT_CIRCULAR; break; case 'neato': - $values['generation_method'] = 3; + $values['generation_method'] = LAYOUT_SPRING1; break; case 'fdp': - $values['generation_method'] = 4; + $values['generation_method'] = LAYOUT_SPRING2; break; case 'radial_dinamic': - $values['generation_method'] = 6; + $values['generation_method'] = LAYOUT_RADIAL_DYNAMIC; break; default: - $values['generation_method'] = 2; + $values['generation_method'] = LAYOUT_RADIAL; break; } @@ -353,12 +353,12 @@ if ($new_networkmap || $save_networkmap) { define('_id_', $id); if ($result !== false) { + $tab = 'view'; if ($values['generation_method'] == 6) { $tab = 'r_dinamic'; define('_activeTab_', 'radial_dynamic'); } - $tab = 'view'; header('Location: '.$_SERVER['HTTP_REFERER'].'&tab='.$tab.'&id_networkmap='.$id); } } diff --git a/pandora_console/operation/agentes/pandora_networkmap.view.php b/pandora_console/operation/agentes/pandora_networkmap.view.php index 2cc4e23dcd..56ffe8fac0 100644 --- a/pandora_console/operation/agentes/pandora_networkmap.view.php +++ b/pandora_console/operation/agentes/pandora_networkmap.view.php @@ -890,7 +890,7 @@ if ($networkmap === false) { include_once $config['homedir'].'/include/class/NetworkMap.class.php'; - echo 'generado por clase'; + $map_manager = new NetworkMap( [ 'id_map' => $networkmap['id']] ); From 663c1e0841c4c28647845a8cca2c3b70c099f1f7 Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Tue, 12 Mar 2019 18:32:55 +0100 Subject: [PATCH 38/50] NetworkMap class rc1 Former-commit-id: 871da4e80cd5909f6bb1da567e3fbe55709690a5 --- .../include/ajax/task_list.ajax.php | 5 +- .../include/class/NetworkMap.class.php | 9 +++- .../include/functions_networkmap.php | 52 ++++++++++++++++--- 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/pandora_console/include/ajax/task_list.ajax.php b/pandora_console/include/ajax/task_list.ajax.php index dd4221a05d..ec5066c7f8 100644 --- a/pandora_console/include/ajax/task_list.ajax.php +++ b/pandora_console/include/ajax/task_list.ajax.php @@ -79,7 +79,10 @@ if ($showmap) { $id_task = get_parameter('id', 0); $map = new NetworkMap( - ['id_task' => $id_task] + [ + 'id_task' => $id_task, + 'pure' => 1, + ] ); $map->printMap(); } diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php index 2abca6dc75..f88e797fc9 100644 --- a/pandora_console/include/class/NetworkMap.class.php +++ b/pandora_console/include/class/NetworkMap.class.php @@ -148,10 +148,10 @@ class NetworkMap $this->mapOptions['font_size'] = 12; $this->mapOptions['nooverlap'] = 1; $this->mapOptions['z_dash'] = 0.5; - $this->mapOptions['ranksep'] = 0.5; + $this->mapOptions['ranksep'] = 3; $this->mapOptions['center'] = 0; $this->mapOptions['regen'] = 0; - $this->mapOptions['pure'] = 1; + $this->mapOptions['pure'] = 0; $this->mapOptions['show_snmp_modules'] = false; $this->mapOptions['cut_names'] = false; $this->mapOptions['relative'] = true; @@ -198,6 +198,11 @@ class NetworkMap $this->mode = $options['mode']; } + // Show interface elements or dashboard style. + if (isset($options['pure'])) { + $this->mapOptions['pure'] = $options['pure']; + } + // Map options, check default values above. // This is only used while generating new maps using // (generateDotGraph). diff --git a/pandora_console/include/functions_networkmap.php b/pandora_console/include/functions_networkmap.php index b5443ae8b6..c35d865a15 100644 --- a/pandora_console/include/functions_networkmap.php +++ b/pandora_console/include/functions_networkmap.php @@ -679,17 +679,57 @@ function networkmap_generate_dot( } -// Returns an edge definition -function networkmap_create_edge($head, $tail, $layout, $nooverlap, $pure, $zoom, $ranksep, $simple, $regen, $font_size, $group, $sec2='operation/agentes/networkmap', $tab='topology', $id_networkmap=0) -{ +/** + * Returns an edge definition. + * + * @param mixed $head Head. + * @param mixed $tail Tail. + * @param string $layout Layout. + * @param string $nooverlap Nooverlap. + * @param integer $pure Pure. + * @param float $zoom Zoom. + * @param float $ranksep Ranksep. + * @param integer $simple Simple. + * @param integer $regen Regen. + * @param integer $font_size Font_size. + * @param integer $group Group. + * @param string $sec2 Sec2. + * @param string $tab Tab. + * @param integer $id_networkmap Id_networkmap. + * + * @return string Dot string. + */ +function networkmap_create_edge( + $head, + $tail, + $layout, + $nooverlap, + $pure, + $zoom, + $ranksep, + $simple, + $regen, + $font_size, + $group, + $sec2='operation/agentes/networkmap', + $tab='topology', + $id_networkmap=0 +) { if (defined('METACONSOLE')) { $url = ''; } else { - $url = 'index.php?sec=estado&'.'sec2='.$sec2.'&'.'tab='.$tab.'&'.'recenter_networkmap=1&'.'center='.$head.'&'.'layout='.$layout.'&'.'nooverlap='.$nooverlap.'&'.'pure='.$pure.'&'.'zoom='.$zoom.'&'.'ranksep='.$ranksep.'&'.'simple='.$simple.'&'.'regen=1'.'&'.'font_size='.$font_size.'&'.'group='.$group.'&'.'id_networkmap='.$id_networkmap; + $url = 'index.php?sec=estado&sec2='.$sec2.'&tab='.$tab.'&'; + $url .= 'recenter_networkmap=1¢er='.$head.'&'; + $url .= 'layout='.$layout.'&nooverlap='.$nooverlap.'&'; + $url .= 'pure='.$pure.'&zoom='.$zoom.'&ranksep='.$ranksep.'&'; + $url .= 'simple='.$simple.'®en=1&font_size='.$font_size.'&'; + $url .= 'group='.$group.'&id_networkmap='.$id_networkmap; } - // edgeURL allows node navigation - $edge = "\n".$head.' -- '.$tail.'[len=3, color="#BDBDBD", headclip=false, tailclip=false, edgeURL=""];'."\n"; + // Option edgeURL allows node navigation. + $edge = "\n".$head.' -- '.$tail.'[len='.$ranksep; + $edge .= ', color="#BDBDBD", headclip=false, tailclip=false, edgeURL=""];'; + $edge .= "\n"; return $edge; } From bf9b84f26653adfd53b91160ffd161ce434f840e Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Tue, 12 Mar 2019 18:38:58 +0100 Subject: [PATCH 39/50] discarded ranksep var as recommended edge len Former-commit-id: 24fe2b0f7ff49b9bdf4e4ef6463ddf5f66de04d8 --- pandora_console/include/functions_networkmap.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandora_console/include/functions_networkmap.php b/pandora_console/include/functions_networkmap.php index c35d865a15..b1e1c3fedc 100644 --- a/pandora_console/include/functions_networkmap.php +++ b/pandora_console/include/functions_networkmap.php @@ -727,8 +727,8 @@ function networkmap_create_edge( } // Option edgeURL allows node navigation. - $edge = "\n".$head.' -- '.$tail.'[len='.$ranksep; - $edge .= ', color="#BDBDBD", headclip=false, tailclip=false, edgeURL=""];'; + $edge = "\n".$head.' -- '.$tail; + $edge .= '[color="#BDBDBD", headclip=false, tailclip=false, edgeURL=""];'; $edge .= "\n"; return $edge; From e61d409acc858ecaf87319c41b3e40d94d92ea78 Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Tue, 12 Mar 2019 19:23:40 +0100 Subject: [PATCH 40/50] fix in redirection after map creation Former-commit-id: dbe1a326942df79f77d8973e8a83781778fa59b0 --- .../include/class/NetworkMap.class.php | 2 +- .../operation/agentes/pandora_networkmap.php | 21 ++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php index f88e797fc9..e80e0d89eb 100644 --- a/pandora_console/include/class/NetworkMap.class.php +++ b/pandora_console/include/class/NetworkMap.class.php @@ -1332,7 +1332,7 @@ class NetworkMap 'id' => 'error_red', 'style' => 'vertical-align: bottom;display: none;', 'class' => 'forced_title', - 'alt' => 'Esto es una prueba', + 'alt' => '', 'data-title' => 'data-use_title_for_force_title:1', ], false diff --git a/pandora_console/operation/agentes/pandora_networkmap.php b/pandora_console/operation/agentes/pandora_networkmap.php index 13100799cb..43c4c907b0 100644 --- a/pandora_console/operation/agentes/pandora_networkmap.php +++ b/pandora_console/operation/agentes/pandora_networkmap.php @@ -128,7 +128,11 @@ if (enterprise_installed()) { if ($result !== false) { $tab = 'view'; - header('Location: '.$_SERVER['HTTP_REFERER'].'&tab='.$tab.'&id_networkmap='.$id); + header( + 'Location: '.ui_get_full_url( + 'index.php?sec=network&sec2=operation/agentes/pandora_networkmap&tab='.$tab.'&id_networkmap='.$id + ) + ); } } else if ($update_empty_networkmap) { $id_group = (int) get_parameter('id_group', 0); @@ -357,9 +361,20 @@ if ($new_networkmap || $save_networkmap) { if ($values['generation_method'] == 6) { $tab = 'r_dinamic'; define('_activeTab_', 'radial_dynamic'); + $url = 'index.php?sec=network&sec2=operation/agentes/networkmap.dinamic&activeTab=radial_dynamic'; + header( + 'Location'.ui_get_full_url( + $url.'&id_networkmap='.$id + ) + ); + } else { + $url = 'index.php?sec=network&sec2=operation/agentes/pandora_networkmap'; + header( + 'Location: '.ui_get_full_url( + $url.'&tab='.$tab.'&id_networkmap='.$id + ) + ); } - - header('Location: '.$_SERVER['HTTP_REFERER'].'&tab='.$tab.'&id_networkmap='.$id); } } } From 99afea22cb2d3a62e32b5b42e3215618006b56fa Mon Sep 17 00:00:00 2001 From: artica <artica.devel@gmail.com> Date: Wed, 13 Mar 2019 00:01:24 +0100 Subject: [PATCH 41/50] Auto-updated build strings. Former-commit-id: 9d92b8845f144366f2d7ed521fefbea0ce7e8eac --- pandora_agents/unix/DEBIAN/control | 2 +- pandora_agents/unix/DEBIAN/make_deb_package.sh | 2 +- pandora_agents/unix/pandora_agent | 2 +- pandora_agents/unix/pandora_agent.redhat.spec | 2 +- pandora_agents/unix/pandora_agent.spec | 2 +- pandora_agents/unix/pandora_agent_installer | 2 +- pandora_agents/win32/installer/pandora.mpi | 2 +- pandora_agents/win32/pandora.cc | 2 +- pandora_agents/win32/versioninfo.rc | 2 +- pandora_console/DEBIAN/control | 2 +- pandora_console/DEBIAN/make_deb_package.sh | 2 +- pandora_console/include/config_process.php | 2 +- pandora_console/install.php | 4 ++-- pandora_console/pandora_console.redhat.spec | 2 +- pandora_console/pandora_console.spec | 2 +- pandora_server/DEBIAN/control | 2 +- pandora_server/DEBIAN/make_deb_package.sh | 2 +- pandora_server/lib/PandoraFMS/Config.pm | 2 +- pandora_server/lib/PandoraFMS/PluginTools.pm | 2 +- pandora_server/pandora_server.redhat.spec | 2 +- pandora_server/pandora_server.spec | 2 +- pandora_server/pandora_server_installer | 2 +- pandora_server/util/pandora_db.pl | 2 +- pandora_server/util/pandora_manage.pl | 2 +- 24 files changed, 25 insertions(+), 25 deletions(-) diff --git a/pandora_agents/unix/DEBIAN/control b/pandora_agents/unix/DEBIAN/control index 4b20131ada..b4a1487f25 100644 --- a/pandora_agents/unix/DEBIAN/control +++ b/pandora_agents/unix/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-agent-unix -Version: 7.0NG.732-190312 +Version: 7.0NG.732-190313 Architecture: all Priority: optional Section: admin diff --git a/pandora_agents/unix/DEBIAN/make_deb_package.sh b/pandora_agents/unix/DEBIAN/make_deb_package.sh index 4c38106b0f..0481649acd 100644 --- a/pandora_agents/unix/DEBIAN/make_deb_package.sh +++ b/pandora_agents/unix/DEBIAN/make_deb_package.sh @@ -14,7 +14,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -pandora_version="7.0NG.732-190312" +pandora_version="7.0NG.732-190313" echo "Test if you has the tools for to make the packages." whereis dpkg-deb | cut -d":" -f2 | grep dpkg-deb > /dev/null diff --git a/pandora_agents/unix/pandora_agent b/pandora_agents/unix/pandora_agent index 7bf1e25c3a..025c7ff0ef 100755 --- a/pandora_agents/unix/pandora_agent +++ b/pandora_agents/unix/pandora_agent @@ -42,7 +42,7 @@ my $Sem = undef; my $ThreadSem = undef; use constant AGENT_VERSION => '7.0NG.732'; -use constant AGENT_BUILD => '190312'; +use constant AGENT_BUILD => '190313'; # Agent log default file size maximum and instances use constant DEFAULT_MAX_LOG_SIZE => 600000; diff --git a/pandora_agents/unix/pandora_agent.redhat.spec b/pandora_agents/unix/pandora_agent.redhat.spec index 5bb4145674..e066d9b3b6 100644 --- a/pandora_agents/unix/pandora_agent.redhat.spec +++ b/pandora_agents/unix/pandora_agent.redhat.spec @@ -3,7 +3,7 @@ # %define name pandorafms_agent_unix %define version 7.0NG.732 -%define release 190312 +%define release 190313 Summary: Pandora FMS Linux agent, PERL version Name: %{name} diff --git a/pandora_agents/unix/pandora_agent.spec b/pandora_agents/unix/pandora_agent.spec index f98ff3cd9d..b9017687a1 100644 --- a/pandora_agents/unix/pandora_agent.spec +++ b/pandora_agents/unix/pandora_agent.spec @@ -3,7 +3,7 @@ # %define name pandorafms_agent_unix %define version 7.0NG.732 -%define release 190312 +%define release 190313 Summary: Pandora FMS Linux agent, PERL version Name: %{name} diff --git a/pandora_agents/unix/pandora_agent_installer b/pandora_agents/unix/pandora_agent_installer index fb27a8e252..4f0011c733 100755 --- a/pandora_agents/unix/pandora_agent_installer +++ b/pandora_agents/unix/pandora_agent_installer @@ -10,7 +10,7 @@ # ********************************************************************** PI_VERSION="7.0NG.732" -PI_BUILD="190312" +PI_BUILD="190313" OS_NAME=`uname -s` FORCE=0 diff --git a/pandora_agents/win32/installer/pandora.mpi b/pandora_agents/win32/installer/pandora.mpi index 20957929d2..09defbca4a 100644 --- a/pandora_agents/win32/installer/pandora.mpi +++ b/pandora_agents/win32/installer/pandora.mpi @@ -186,7 +186,7 @@ UpgradeApplicationID {} Version -{190312} +{190313} ViewReadme {Yes} diff --git a/pandora_agents/win32/pandora.cc b/pandora_agents/win32/pandora.cc index 5ea340e78e..f566961adb 100644 --- a/pandora_agents/win32/pandora.cc +++ b/pandora_agents/win32/pandora.cc @@ -30,7 +30,7 @@ using namespace Pandora; using namespace Pandora_Strutils; #define PATH_SIZE _MAX_PATH+1 -#define PANDORA_VERSION ("7.0NG.732(Build 190312)") +#define PANDORA_VERSION ("7.0NG.732(Build 190313)") string pandora_path; string pandora_dir; diff --git a/pandora_agents/win32/versioninfo.rc b/pandora_agents/win32/versioninfo.rc index 9f62b65035..472d9723ce 100644 --- a/pandora_agents/win32/versioninfo.rc +++ b/pandora_agents/win32/versioninfo.rc @@ -11,7 +11,7 @@ BEGIN VALUE "LegalCopyright", "Artica ST" VALUE "OriginalFilename", "PandoraAgent.exe" VALUE "ProductName", "Pandora FMS Windows Agent" - VALUE "ProductVersion", "(7.0NG.732(Build 190312))" + VALUE "ProductVersion", "(7.0NG.732(Build 190313))" VALUE "FileVersion", "1.0.0.0" END END diff --git a/pandora_console/DEBIAN/control b/pandora_console/DEBIAN/control index 0f08432214..b28bde0506 100644 --- a/pandora_console/DEBIAN/control +++ b/pandora_console/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-console -Version: 7.0NG.732-190312 +Version: 7.0NG.732-190313 Architecture: all Priority: optional Section: admin diff --git a/pandora_console/DEBIAN/make_deb_package.sh b/pandora_console/DEBIAN/make_deb_package.sh index a15849cec1..a000b443a0 100644 --- a/pandora_console/DEBIAN/make_deb_package.sh +++ b/pandora_console/DEBIAN/make_deb_package.sh @@ -14,7 +14,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -pandora_version="7.0NG.732-190312" +pandora_version="7.0NG.732-190313" package_pear=0 package_pandora=1 diff --git a/pandora_console/include/config_process.php b/pandora_console/include/config_process.php index 6cadc13ccd..a3a2f4662e 100644 --- a/pandora_console/include/config_process.php +++ b/pandora_console/include/config_process.php @@ -20,7 +20,7 @@ /** * Pandora build version and version */ -$build_version = 'PC190312'; +$build_version = 'PC190313'; $pandora_version = 'v7.0NG.732'; // Do not overwrite default timezone set if defined. diff --git a/pandora_console/install.php b/pandora_console/install.php index e4b6fb5827..c83ac86528 100644 --- a/pandora_console/install.php +++ b/pandora_console/install.php @@ -128,8 +128,8 @@ </div> <div style='height: 10px'> <?php - $version = '7.0NG.732'; - $build = '190312'; +$version = '7.0NG.732'; +$build = '190313'; $banner = "v$version Build $build"; error_reporting(0); diff --git a/pandora_console/pandora_console.redhat.spec b/pandora_console/pandora_console.redhat.spec index 82b3c55204..16fc050ffb 100644 --- a/pandora_console/pandora_console.redhat.spec +++ b/pandora_console/pandora_console.redhat.spec @@ -3,7 +3,7 @@ # %define name pandorafms_console %define version 7.0NG.732 -%define release 190312 +%define release 190313 # User and Group under which Apache is running %define httpd_name httpd diff --git a/pandora_console/pandora_console.spec b/pandora_console/pandora_console.spec index 1a28b1fdd0..d10585e6e4 100644 --- a/pandora_console/pandora_console.spec +++ b/pandora_console/pandora_console.spec @@ -3,7 +3,7 @@ # %define name pandorafms_console %define version 7.0NG.732 -%define release 190312 +%define release 190313 %define httpd_name httpd # User and Group under which Apache is running %define httpd_name apache2 diff --git a/pandora_server/DEBIAN/control b/pandora_server/DEBIAN/control index 9ec614259c..9548932fb6 100644 --- a/pandora_server/DEBIAN/control +++ b/pandora_server/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-server -Version: 7.0NG.732-190312 +Version: 7.0NG.732-190313 Architecture: all Priority: optional Section: admin diff --git a/pandora_server/DEBIAN/make_deb_package.sh b/pandora_server/DEBIAN/make_deb_package.sh index 15aed91cda..108621d2e0 100644 --- a/pandora_server/DEBIAN/make_deb_package.sh +++ b/pandora_server/DEBIAN/make_deb_package.sh @@ -14,7 +14,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -pandora_version="7.0NG.732-190312" +pandora_version="7.0NG.732-190313" package_cpan=0 package_pandora=1 diff --git a/pandora_server/lib/PandoraFMS/Config.pm b/pandora_server/lib/PandoraFMS/Config.pm index ba427f8bb0..b185ecc9ca 100644 --- a/pandora_server/lib/PandoraFMS/Config.pm +++ b/pandora_server/lib/PandoraFMS/Config.pm @@ -45,7 +45,7 @@ our @EXPORT = qw( # version: Defines actual version of Pandora Server for this module only my $pandora_version = "7.0NG.732"; -my $pandora_build = "190312"; +my $pandora_build = "190313"; our $VERSION = $pandora_version." ".$pandora_build; # Setup hash diff --git a/pandora_server/lib/PandoraFMS/PluginTools.pm b/pandora_server/lib/PandoraFMS/PluginTools.pm index 85cf1f9219..d162fe14a3 100644 --- a/pandora_server/lib/PandoraFMS/PluginTools.pm +++ b/pandora_server/lib/PandoraFMS/PluginTools.pm @@ -32,7 +32,7 @@ our @ISA = qw(Exporter); # version: Defines actual version of Pandora Server for this module only my $pandora_version = "7.0NG.732"; -my $pandora_build = "190312"; +my $pandora_build = "190313"; our $VERSION = $pandora_version." ".$pandora_build; our %EXPORT_TAGS = ( 'all' => [ qw() ] ); diff --git a/pandora_server/pandora_server.redhat.spec b/pandora_server/pandora_server.redhat.spec index 5c6662ad47..b72c6fba9c 100644 --- a/pandora_server/pandora_server.redhat.spec +++ b/pandora_server/pandora_server.redhat.spec @@ -3,7 +3,7 @@ # %define name pandorafms_server %define version 7.0NG.732 -%define release 190312 +%define release 190313 Summary: Pandora FMS Server Name: %{name} diff --git a/pandora_server/pandora_server.spec b/pandora_server/pandora_server.spec index 239b8b4a98..ef34f29d11 100644 --- a/pandora_server/pandora_server.spec +++ b/pandora_server/pandora_server.spec @@ -3,7 +3,7 @@ # %define name pandorafms_server %define version 7.0NG.732 -%define release 190312 +%define release 190313 Summary: Pandora FMS Server Name: %{name} diff --git a/pandora_server/pandora_server_installer b/pandora_server/pandora_server_installer index 8bfb991f42..85d5e4023c 100755 --- a/pandora_server/pandora_server_installer +++ b/pandora_server/pandora_server_installer @@ -9,7 +9,7 @@ # ********************************************************************** PI_VERSION="7.0NG.732" -PI_BUILD="190312" +PI_BUILD="190313" MODE=$1 if [ $# -gt 1 ]; then diff --git a/pandora_server/util/pandora_db.pl b/pandora_server/util/pandora_db.pl index 8602f0d24d..3db44fae7b 100644 --- a/pandora_server/util/pandora_db.pl +++ b/pandora_server/util/pandora_db.pl @@ -34,7 +34,7 @@ use PandoraFMS::Config; use PandoraFMS::DB; # version: define current version -my $version = "7.0NG.732 PS190312"; +my $version = "7.0NG.732 PS190313"; # Pandora server configuration my %conf; diff --git a/pandora_server/util/pandora_manage.pl b/pandora_server/util/pandora_manage.pl index 1b00ef349a..61817bc6e9 100644 --- a/pandora_server/util/pandora_manage.pl +++ b/pandora_server/util/pandora_manage.pl @@ -36,7 +36,7 @@ use Encode::Locale; Encode::Locale::decode_argv; # version: define current version -my $version = "7.0NG.732 PS190312"; +my $version = "7.0NG.732 PS190313"; # save program name for logging my $progname = basename($0); From 95c61024f7ce2afef3234de59ae9962903f5302d Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Wed, 13 Mar 2019 11:38:03 +0100 Subject: [PATCH 42/50] Cleanup Networkmaps Former-commit-id: 68893c73092e80bf4a67a0aa82c51ec242aab01f --- .../include/class/NetworkMap.class.php | 5 +- pandora_console/include/functions_agents.php | 2 +- .../include/functions_networkmap.php | 1718 ++++++++++--- .../include/functions_networkmaps.php | 42 +- .../include/functions_pandora_networkmap.php | 2244 +---------------- .../operation/agentes/pandora_networkmap.php | 1 - .../agentes/pandora_networkmap.view.php | 9 +- 7 files changed, 1381 insertions(+), 2640 deletions(-) diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php index e80e0d89eb..3adf1b44b5 100644 --- a/pandora_console/include/class/NetworkMap.class.php +++ b/pandora_console/include/class/NetworkMap.class.php @@ -30,9 +30,7 @@ global $config; require_once $config['homedir'].'/include/functions_networkmap.php'; -require_once $config['homedir'].'/include/functions_pandora_networkmap.php'; - -enterprise_include_once('include/functions_pandora_networkmap.php'); +enterprise_include_once('include/functions_networkmap.php'); define('SOURCE_GROUP', 0); define('SOURCE_TASK', 1); @@ -653,7 +651,6 @@ class NetworkMap ui_print_error_message( __('Failed to generate dotmap, please select different layout schema') ); - $this->graph = networkmap_process_networkmap($this->idMap); return; } diff --git a/pandora_console/include/functions_agents.php b/pandora_console/include/functions_agents.php index 0ac9bb876f..93eeec9e20 100644 --- a/pandora_console/include/functions_agents.php +++ b/pandora_console/include/functions_agents.php @@ -2202,7 +2202,7 @@ function agents_delete_agent($id_agents, $disableACL=false) // Delete agent in networkmap enterprise if (enterprise_installed()) { - enterprise_include_once('include/functions_pandora_networkmap.php'); + enterprise_include_once('include/functions_networkmap.php'); networkmap_delete_nodes_by_agent([$id_agent]); } diff --git a/pandora_console/include/functions_networkmap.php b/pandora_console/include/functions_networkmap.php index b1e1c3fedc..28fa630f0a 100644 --- a/pandora_console/include/functions_networkmap.php +++ b/pandora_console/include/functions_networkmap.php @@ -1,32 +1,36 @@ <?php - -// Pandora FMS - http://pandorafms.com -// ================================================== -// Copyright (c) 2005-2011 Artica Soluciones Tecnologicas -// Please see http://pandorafms.org for full contribution list -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public License -// as published by the Free Software Foundation; version 2 -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - - - /** - * @package Include - * @subpackage Network_Map + * Library for networkmaps in Pandora FMS + * + * @category Library + * @package Pandora FMS + * @subpackage NetworkMap + * @version 1.0.0 + * @license See below + * + * ______ ___ _______ _______ ________ + * | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __| + * | __/| _ | | _ || _ | _| _ | | ___| |__ | + * |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| + * + * ============================================================================ + * Copyright (c) 2005-2019 Artica Soluciones Tecnologicas + * Please see http://pandorafms.org for full contribution list + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation for version 2. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ============================================================================ */ -/** - * Include agents function - */ +// Begin. require_once 'functions_agents.php'; require_once $config['homedir'].'/include/functions_modules.php'; require_once $config['homedir'].'/include/functions_groups.php'; -ui_require_css_file('cluetip', 'include/styles/js/'); - +enterprise_include_once('include/functions_networkmap.php'); // Check if a node descends from a given node function networkmap_is_descendant($node, $ascendant, $parents) @@ -264,34 +268,6 @@ function networkmap_generate_hash( } -function networkmap_check_exists_edge_between_nodes($edges, $node_a, $node_b) -{ - $relation = false; - - if (is_array($edges[$node_a])) { - if (array_search($node_b, $edges[$node_a]) !== false) { - $relation = true; - } - } else { - if ($edges[$node_a] == $node_b) { - $relation = true; - } - } - - if (is_array($edges[$node_b])) { - if (array_search($node_a, $edges[$node_b]) !== false) { - $relation = true; - } - } else { - if ($edges[$node_b] == $node_a) { - $relation = true; - } - } - - return $relation; -} - - function networkmap_generate_dot( $pandora_name, $group=0, @@ -744,96 +720,6 @@ function networkmap_create_transparent_edge($head, $tail) } -// Returns a group node definition -function networkmap_create_group_node($group, $simple=0, $font_size=10, $metaconsole=false, $id_server=null, $strict_user=false) -{ - global $config; - global $hack_networkmap_mobile; - - $status = groups_get_status($group['id_grupo'], $strict_user); - - // Set node status - switch ($status) { - case 0: - $status_color = COL_NORMAL; - // Normal monitor - break; - - case 1: - $status_color = COL_CRITICAL; - // Critical monitor - break; - - case 2: - $status_color = COL_WARNING; - // Warning monitor - break; - - case 4: - $status_color = COL_ALERTFIRED; - // Alert fired - break; - - default: - $status_color = COL_UNKNOWN; - // Unknown monitor - break; - } - - $icon = groups_get_icon($group['id_grupo']); - - if ($simple == 0) { - // Set node icon - if ($hack_networkmap_mobile) { - $img_node = $config['homedir'].'/images/groups_small/'.$icon.'.png'; - - if (!file_exists($img_node)) { - $img_node = '-'; - } - - $img_node = '<img src="'.$img_node.'" />'; - } else if (file_exists(html_print_image('images/groups_small/'.$icon.'.png', true, false, true, true))) { - $img_node = html_print_image('images/groups_small/'.$icon.'.png', true, false, false, true); - } else { - $img_node = '-'; - } - - if (strlen(groups_get_name($group['id_grupo'])) > 40) { - $name = substr(groups_get_name($group['id_grupo']), 0, 40).'...'; - } else { - $name = groups_get_name($group['id_grupo']); - } - - if (defined('METACONSOLE')) { - $url = ''; - $url_tooltip = ''; - } else { - $url = 'index.php?sec=estado&sec2=operation/agentes/estado_agente&refr=60&group_id='.$group['id_grupo']; - $url_tooltip = 'ajax.php?page=operation/agentes/ver_agente&get_group_status_tooltip=1&id_group='.$group['id_grupo']; - } - - $node = "\n".$group['id_node'].' [ color="'.$status_color.'", fontsize='.$font_size.', style="filled", fixedsize=true, width=0.30, height=0.30, '.'label=<<TABLE CELLPADDING="0" data-status="'.$status.'" CELLSPACING="0" BORDER="0"><TR><TD>'.$img_node.'</TD></TR> - <TR><TD>'.io_safe_output($name).'</TD></TR></TABLE>>, - shape="invtrapezium", URL="'.$url.'", - tooltip="'.$url_tooltip.'"];'."\n"; - } else { - if (defined('METACONSOLE')) { - $url = ''; - $url_tooltip = ''; - } else { - $url = 'index.php?sec=estado&sec2=operation/agentes/estado_agente&refr=60&group_id='.$group['id_grupo']; - $url_tooltip = 'ajax.php?page=operation/agentes/ver_agente&get_group_status_tooltip=1&id_group='.$group['id_grupo']; - } - - $node = "\n".$group['id_node'].' [ color="'.$status_color.'", fontsize='.$font_size.', shape="invtrapezium", - URL="'.$url.'", style="filled", fixedsize=true, width=0.20, height=0.20, label="", - tooltip="'.$url_tooltip.'"];'."\n"; - } - - return $node; -} - - // Returns a node definition function networkmap_create_agent_node($agent, $simple=0, $font_size=10, $cut_names=true, $relative=false, $metaconsole=false, $id_server=null, $strict_user=false) { @@ -977,76 +863,6 @@ function networkmap_create_agent_node($agent, $simple=0, $font_size=10, $cut_nam } -function networkmap_create_module_group_node($module_group, $simple=0, $font_size=10, $metaconsole=false, $id_server=null) -{ - global $config; - global $hack_networkmap_mobile; - - // Set node status - switch ($module_group['status']) { - case 0: - $status_color = COL_NORMAL; - // Normal monitor - break; - - case 1: - $status_color = COL_CRITICAL; - // Critical monitor - break; - - case 2: - $status_color = COL_WARNING; - // Warning monitor - break; - - case 4: - $status_color = COL_ALERTFIRED; - // Alert fired - break; - - default: - $status_color = COL_UNKNOWN; - // Unknown monitor - break; - } - - if ($simple == 0) { - if (defined('METACONSOLE')) { - $url = ''; - $url_tooltip = ''; - } else { - $url = ''; - $url_tooltip = ''; - } - - $node = $module_group['id_node'].' [ color="'.$status_color.'", fontsize='.$font_size.', style="filled", '.'fixedsize=true, width=0.30, height=0.30, '.'label=<<TABLE data-id_agent="'.$module_group['id_agent'].'" data-status="'.$module_group['status'].'" CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR><TD>'.io_safe_output($module_group['name']).'</TD></TR></TABLE>>, - shape="square", URL="'.$url.'", - tooltip="'.$url_tooltip.'"];'; - } else { - if ($hack_networkmap_mobile) { - $img_node = ui_print_moduletype_icon($module['id_tipo_modulo'], true, true, false, true); - - $img_node = $config['homedir'].'/'.$img_node; - $img_node = '<img src="'.$img_node.'" />'; - } else { - $img_node = ui_print_moduletype_icon($module['id_tipo_modulo'], true, true, false); - } - - if (defined('METACONSOLE')) { - $url = ''; - $url_tooltip = ''; - } else { - $url = ''; - $url_tooltip = ''; - } - - $node = $module_group['id_node'].' [ color="'.$status_color.'", fontsize='.$font_size.', shape="square", URL="'.$url.'", '.'style="filled", fixedsize=true, width=0.20, '.'height=0.20, label="", tooltip="'.$url_tooltip.'"];'; - } - - return $node; -} - - // Returns a module node definition function networkmap_create_module_node($module, $simple=0, $font_size=10, $metaconsole=false, $id_server=null) { @@ -1200,28 +1016,6 @@ function networkmap_create_transparent_node($count=0) } -// Opens a group definition -function networkmap_open_group($id) -{ - $img = 'images/'.groups_get_icon($id).'.png'; - $name = groups_get_name($id); - - $group = 'subgraph cluster_'.$id.' { style=filled; color=darkolivegreen3; label=<<TABLE BORDER=\'0\'> - <TR><TD>'.html_print_image($img, true).'</TD><TD>'.$name.'</TD></TR> - </TABLE>>; tooltip="'.$name.'"; - URL="index.php?sec=estado&sec2=operation/agentes/estado_agente&group_id='.$id.'";'; - - return $group; -} - - -// Closes a group definition -function networkmap_close_group() -{ - return '}'; -} - - // Opens a graph definition function networkmap_open_graph( $layout, @@ -1364,67 +1158,6 @@ function networkmap_get_filter($layout) } -/** - * Creates a networkmap. - * - * @param string Network map name. - * @param string Network map type (topology, groups or policies). - * @param layout Network map layout (circular, flat, radial, spring1 or spring2). - * @param bool overlapping activate flag. - * @param bool simple view activate flag. - * @param bool regenerate file activate flag. - * @param int font size. - * @param int group id filter (0 for all). - * @param int module group id filter (0 for all). - * @param int policy id filter (0 for all). - * @param string depth level. - * @param bool only modules with alerts flag. - * @param bool hide policy modules flag - * @param float zoom factor - * - * @return mixed New networkmap id if created. False if it could not be created. - */ -function networkmap_create_networkmap($values) -{ - global $config; - - // The name is required - if (! isset($values['name'])) { - return false; - } - - // Set defaults for the empty values - set_unless_defined($values['type'], 'topology'); - set_unless_defined($values['layout'], 'radial'); - set_unless_defined($values['nooverlap'], true); - set_unless_defined($values['simple'], false); - set_unless_defined($values['regenerate'], true); - set_unless_defined($values['font_size'], 12); - set_unless_defined($values['store_group'], 0); - set_unless_defined($values['id_group'], 0); - set_unless_defined($values['regenerate'], true); - set_unless_defined($values['id_module_group'], 0); - set_unless_defined($values['depth'], 'all'); - set_unless_defined($values['only_modules_with_alerts'], false); - set_unless_defined($values['hide_policy_modules'], false); - set_unless_defined($values['zoom'], 1); - set_unless_defined($values['distance_nodes'], 2.5); - set_unless_defined($values['center'], 0); - set_unless_defined($values['id_user'], $config['id_user']); - set_unless_defined($values['text_filter'], ''); - set_unless_defined($values['regenerate'], true); - set_unless_defined($values['dont_show_subgroups'], 0); - set_unless_defined($values['show_groups'], false); - set_unless_defined($values['pandoras_children'], false); - set_unless_defined($values['show_modules'], false); - set_unless_defined($values['show_snmp_modules'], 0); - set_unless_defined($values['l2_network'], 0); - set_unless_defined($values['server_name'], ''); - - return @db_process_sql_insert('tnetwork_map', $values); -} - - /** * Get a network map report. * @@ -1543,57 +1276,6 @@ function networkmap_type_to_str_type($type) } -/** - * Deletes a network map if the property is that user. - * - * @param string User id that call this funtion. - * @param int Map id to be deleted. - * - * @return boolean True if the map was deleted, false the map is not yours. - */ -function networkmap_delete_user_networkmap($id_user='', $id_networkmap) -{ - if ($id_user == '') { - $id_user = $config['id_user']; - } - - $id_networkmap = safe_int($id_networkmap); - if (empty($id_networkmap)) { - return false; - } - - $networkmap = networkmap_get_networkmap($id_networkmap); - if ($networkmap === false) { - return false; - } - - return @db_process_sql_delete('tnetwork_map', ['id_networkmap' => $id_networkmap, 'id_user' => $id_user]); -} - - -/** - * Updates a network map. - * - * @param int Map id. - * @param array Extra values to be set. - * - * @return boolean True if the map was updated. False otherwise. - */ -function networkmap_update_networkmap($id_networkmap, $values) -{ - $networkmap = networkmap_get_networkmap($id_networkmap); - if ($networkmap === false) { - return false; - } - - return (db_process_sql_update( - 'tnetwork_map', - $values, - ['id_networkmap' => $id_networkmap] - )) !== false; -} - - /** * Get different networkmaps types for creation. * @@ -1622,51 +1304,6 @@ function networkmap_get_types($strict_user=false) } -/** - * Get networkmaps types. - * - * @return array Networkmap diferent types. - */ -function networkmap_get_filter_types($strict_user=false) -{ - $networkmap_types = []; - - $is_enterprise = enterprise_include_once('include/functions_policies.php'); - - $networkmap_types['topology'] = __('Topology'); - $networkmap_types['groups'] = __('Group'); - $networkmap_types['dynamic'] = __('Dynamic'); - if (!$strict_user) { - $networkmap_types['radial_dynamic'] = __('Radial dynamic'); - } - - if (($is_enterprise !== ENTERPRISE_NOT_HOOK) && (!$strict_user)) { - $enterprise_types = enterprise_hook('policies_get_networkmap_filter_types'); - - $networkmap_types = array_merge($networkmap_types, $enterprise_types); - } - - return $networkmap_types; -} - - -function networkmap_cidr_match($ip, $cidr_mask) -{ - // copy from open source code - // https://gist.github.com/linickx/1309388 - $chunks = explode('/', $cidr_mask); - $subnet = $chunks[0]; - $bits = $chunks[1]; - - $ip = ip2long($ip); - $subnet = ip2long($subnet); - $mask = (-1 << (32 - $bits)); - $subnet &= $mask; - // nb: in case the supplied subnet wasn't correctly aligned - return ($ip & $mask) == $subnet; -} - - /** * Retrieve agent list matching desired network. * @@ -1762,7 +1399,1306 @@ function modules_get_all_interfaces($id_agent) } -?> +function networkmap_delete_networkmap($id=0) +{ + if (enterprise_installed()) { + // Relations + $result = delete_relations($id); + + // Nodes + $result = delete_nodes($id); + } + + // Map + $result = db_process_sql_delete('tmap', ['id' => $id]); + + return $result; +} + + +function networkmap_delete_nodes($id_map) +{ + return db_process_sql_delete('titem', ['id_map' => $id_map]); +} + + +function get_networkmaps($id) +{ + $groups = array_keys(users_get_groups(null, 'IW')); + + $filter = []; + $filter['id_group'] = $groups; + $filter['id'] = '<>'.$id; + $networkmaps = db_get_all_rows_filter('tmap', $filter); + if ($networkmaps === false) { + $networkmaps = []; + } + + $return = []; + $return[0] = __('None'); + foreach ($networkmaps as $networkmap) { + $return[$networkmap['id']] = $networkmap['name']; + } + + return $return; +} + + +/** + * Translates node (nodes_and_relations) into JS node. + * + * @param array $node Node. + * @param integer $count Count. + * @param integer $count_item_holding_area Count_item_holding_area. + * @param boolean $simulated Simulated. + * + * @return array JS nodes. + */ +function networkmap_db_node_to_js_node( + $node, + &$count, + &$count_item_holding_area, + $simulated=false +) { + global $config; + + $networkmap = db_get_row('tmap', 'id', $node['id_map']); + + $networkmap['filter'] = json_decode($networkmap['filter'], true); + + // Hardcoded + $networkmap['filter']['holding_area'] = [ + 500, + 500, + ]; + + // 40 = DEFAULT NODE RADIUS + // 30 = for to align + $holding_area_max_y = ($networkmap['height'] + 30 + 40 * 2 - $networkmap['filter']['holding_area'][1] + 10 * 40); + + $item = []; + $item['id'] = $count; + + if (enterprise_installed() && $simulated === false) { + enterprise_include_once('include/functions_networkmap.php'); + $item['id_db'] = $node['id_in_db']; + } else { + $item['id_db'] = (int) $node['id']; + } + + if ((int) $node['type'] == 0) { + $item['type'] = 0; + $item['id_agent'] = (int) $node['source_data']; + $item['id_module'] = ''; + } else if ((int) $node['type'] == 1) { + $item['type'] = 1; + $item['id_agent'] = (int) $node['style']['id_agent']; + $item['id_module'] = (int) $node['source_data']; + } else { + $item['type'] = 3; + } + + $item['fixed'] = true; + $item['x'] = (int) $node['x']; + $item['y'] = (int) $node['y']; + $item['px'] = (int) $node['x']; + $item['py'] = (int) $node['y']; + $item['z'] = (int) $node['z']; + $item['state'] = $node['state']; + $item['deleted'] = $node['deleted']; + if ($item['state'] == 'holding_area') { + // 40 = DEFAULT NODE RADIUS + // 30 = for to align + $holding_area_x = ($networkmap['width'] + 30 + 40 * 2 - $networkmap['filter']['holding_area'][0] + ($count_item_holding_area % 11) * 40); + $holding_area_y = ($networkmap['height'] + 30 + 40 * 2 - $networkmap['filter']['holding_area'][1] + (int) (($count_item_holding_area / 11)) * 40); + + if ($holding_area_max_y <= $holding_area_y) { + $holding_area_y = $holding_area_max_y; + } + + $item['x'] = $holding_area_x; + $item['y'] = $holding_area_y; + + // Increment for the next node in holding area + $count_item_holding_area++; + } + + $item['image_url'] = ''; + $item['image_width'] = 0; + $item['image_height'] = 0; + if (!empty($node['style']['image'])) { + $item['image_url'] = html_print_image( + $node['style']['image'], + true, + false, + true + ); + $image_size = getimagesize( + $config['homedir'].'/'.$node['style']['image'] + ); + $item['image_width'] = (int) $image_size[0]; + $item['image_height'] = (int) $image_size[1]; + } + + $item['raw_text'] = $node['style']['label']; + $item['text'] = io_safe_output($node['style']['label']); + $item['shape'] = $node['style']['shape']; + switch ($node['type']) { + case 0: + $color = get_status_color_networkmap($node['source_data']); + break; + + default: + // Old code + if ($node['source_data'] == -1) { + $color = '#364D1F'; + } else if ($node['source_data'] == -2) { + $color = '#364D1F'; + } else { + $color = get_status_color_networkmap($node['source_data']); + } + break; + } + + $item['color'] = $color; + $item['map_id'] = 0; + if (isset($node['id_map'])) { + $item['map_id'] = $node['id_map']; + } + + if (!isset($node['style']['id_networkmap']) || $node['style']['id_networkmap'] == '' || $node['style']['id_networkmap'] == 0) { + $item['networkmap_id'] = 0; + } else { + $item['networkmap_id'] = $node['style']['id_networkmap']; + } + + $count++; + + return $item; +} + + +function get_status_color_networkmap($id, $color=true) +{ + // $status = agents_get_status($id); + $agent_data = db_get_row_sql('SELECT * FROM tagente WHERE id_agente = '.$id); + + if ($agent_data === false) { + return COL_UNKNOWN; + } + + $status = agents_get_status_from_counts($agent_data); + + if (!$color) { + return $status; + } + + if ($agent_data['fired_count'] > 0) { + return COL_ALERTFIRED; + } + + // Select node color by checking status. + switch ($status) { + case AGENT_MODULE_STATUS_NORMAL: + return COL_NORMAL; + + case AGENT_MODULE_STATUS_NOT_INIT: + return COL_NOTINIT; + + case AGENT_MODULE_STATUS_CRITICAL_BAD: + return COL_CRITICAL; + + case AGENT_MODULE_STATUS_WARNING: + return COL_WARNING; + + case AGENT_MODULE_STATUS_UNKNOWN: + default: + return COL_UNKNOWN; + } + + return COL_UNKNOWN; +} + + +function networkmap_clean_relations_for_js(&$relations) +{ + do { + $cleaned = true; + + foreach ($relations as $key => $relation) { + if ($relation['id_parent_source_data'] == $relation['id_child_source_data']) { + if (($relation['child_type'] != 3) && $relation['parent_type'] != 3) { + $cleaned = false; + + if ($relation['parent_type'] == 1) { + $to_find = $relation['id_parent_source_data']; + $to_replace = $relation['id_child_source_data']; + } else if ($relation['child_type'] == 1) { + $to_find = $relation['id_child_source_data']; + $to_replace = $relation['id_parent_source_data']; + } + + // Replace and erase the links + foreach ($relations as $key2 => $relation2) { + if ($relation2['id_parent_source_data'] == $to_find) { + $relations[$key2]['id_parent_source_data'] = $to_replace; + } else if ($relation2['id_child_source_data'] == $to_find) { + $relations[$key2]['id_child_source_data'] = $to_replace; + } + } + + unset($relations[$key]); + + break; + } + } + } + } while (!$cleaned); +} + + +/** + * Transform networkmap relations into js links. + * + * @param array $relations Relations. + * @param array $nodes_graph Nodes_graph. + * @param boolean $simulated Simulated. + * + * @return array JS relations. + */ +function networkmap_links_to_js_links( + $relations, + $nodes_graph, + $simulated=false +) { + $return = []; + + if (enterprise_installed() && $simulated === false) { + enterprise_include_once('include/functions_networkmap.php'); + } + + $count = 0; + foreach ($relations as $key => $relation) { + if (($relation['parent_type'] == 1) && ($relation['child_type'] == 1)) { + $id_target_agent = agents_get_agent_id_by_module_id( + $relation['id_parent_source_data'] + ); + $id_source_agent = agents_get_agent_id_by_module_id( + $relation['id_child_source_data'] + ); + $id_target_module = $relation['id_parent_source_data']; + $id_source_module = $relation['id_child_source_data']; + } else if (($relation['parent_type'] == 1) + && ($relation['child_type'] == 0) + ) { + $id_target_agent = agents_get_agent_id_by_module_id( + $relation['id_parent_source_data'] + ); + $id_target_module = $relation['id_parent_source_data']; + $id_source_agent = $relation['id_child_source_data']; + } else if (($relation['parent_type'] == 0) + && ($relation['child_type'] == 1) + ) { + $id_target_agent = $relation['id_parent_source_data']; + $id_source_module = $relation['id_child_source_data']; + $id_source_agent = agents_get_agent_id_by_module_id( + $relation['id_child_source_data'] + ); + } else { + $id_target_agent = $relation['id_parent_source_data']; + $id_source_agent = $relation['id_child_source_data']; + } + + $item = []; + $item['id'] = $count; + $count++; + if (enterprise_installed() && $simulated === false) { + $item['id_db'] = get_relation_id($relation); + } else { + $item['id_db'] = $key; + } + + $item['arrow_start'] = ''; + $item['arrow_end'] = ''; + $item['status_start'] = ''; + $item['status_end'] = ''; + $item['id_module_start'] = 0; + $item['id_agent_start'] = (int) $id_source_agent; + $item['id_module_end'] = 0; + $item['id_agent_end'] = (int) $id_target_agent; + $item['link_color'] = '#999'; + $item['target'] = -1; + $item['source'] = -1; + $item['deleted'] = $relation['deleted']; + + if (enterprise_installed() && $simulated === false) { + $target_and_source = []; + $target_and_source = get_id_target_and_source_in_db($relation); + $item['target_id_db'] = (int) $target_and_source['target']; + $item['source_id_db'] = (int) $target_and_source['source']; + } else { + if (($relation['parent_type'] == 1) && ($relation['child_type'] == 1)) { + $item['target_id_db'] = $id_target_agent; + $item['source_id_db'] = $id_source_agent; + } else if (($relation['parent_type'] == 0) && ($relation['child_type'] == 0)) { + $item['target_id_db'] = (int) $relation['id_parent_source_data']; + $item['source_id_db'] = $id_source_agent; + } else { + $item['target_id_db'] = (int) $relation['id_parent_source_data']; + $item['source_id_db'] = (int) $relation['id_child_source_data']; + } + } + + $item['text_end'] = ''; + $item['text_start'] = ''; + + if ($relation['parent_type'] == 1) { + $item['arrow_end'] = 'module'; + $item['status_end'] = modules_get_agentmodule_status((int) $id_target_module, false, false, null); + $item['id_module_end'] = (int) $id_target_module; + $text_end = modules_get_agentmodule_name((int) $id_target_module); + if (preg_match('/(.+)_ifOperStatus$/', (string) $text_end, $matches)) { + if ($matches[1]) { + // It's ok to safe_output as it inlo goint to be user into the map line + $item['text_end'] = io_safe_output($matches[1]); + } + } + } + + if ($relation['child_type'] == 1) { + $item['arrow_start'] = 'module'; + $item['status_start'] = modules_get_agentmodule_status((int) $id_source_module, false, false, null); + $item['id_module_start'] = (int) $id_source_module; + $text_start = modules_get_agentmodule_name((int) $id_source_module); + if (preg_match('/(.+)_ifOperStatus$/', (string) $text_start, $matches)) { + if ($matches[1]) { + // It's ok to safe_output as it inlo goint to be user into the map line + $item['text_start'] = io_safe_output($matches[1]); + } + } + } + + $agent = 0; + $agent2 = 0; + $control1 = false; + $control2 = false; + + if (($relation['parent_type'] == 1) && ($relation['child_type'] == 1)) { + if (($item['status_start'] == AGENT_MODULE_STATUS_CRITICAL_BAD) || ($item['status_end'] == AGENT_MODULE_STATUS_CRITICAL_BAD)) { + $item['link_color'] = '#FC4444'; + } else if (($item['status_start'] == AGENT_MODULE_STATUS_WARNING) || ($item['status_end'] == AGENT_MODULE_STATUS_WARNING)) { + $item['link_color'] = '#FAD403'; + } + + $agent = agents_get_agent_id_by_module_id( + $relation['id_parent_source_data'] + ); + $agent2 = agents_get_agent_id_by_module_id( + $relation['id_child_source_data'] + ); + foreach ($nodes_graph as $key2 => $node) { + if (isset($node['id_agent'])) { + if ($node['id_agent'] == $agent) { + $agent = $node['id_db']; + $control1 = true; + } + + if ($node['id_agent'] == $agent2) { + $agent2 = $node['id_db']; + $control2 = true; + } + + if ($control1 && $control2) { + break; + } + } + } + } else if ($relation['child_type'] == 1) { + if ($item['status_start'] == AGENT_MODULE_STATUS_CRITICAL_BAD) { + $item['link_color'] = '#FC4444'; + } else if ($item['status_start'] == AGENT_MODULE_STATUS_WARNING) { + $item['link_color'] = '#FAD403'; + } + + $agent2 = agents_get_agent_id_by_module_id( + $relation['id_child_source_data'] + ); + foreach ($nodes_graph as $key2 => $node) { + if (isset($node['id_agent'])) { + if ($node['id_agent'] == $relation['id_parent_source_data']) { + $agent = $node['id_db']; + $control1 = true; + } + + if ($node['id_agent'] == $agent2) { + $agent2 = $node['id_db']; + $control2 = true; + } + + if ($control1 && $control2) { + break; + } + } + } + } else if ($relation['parent_type'] == 1) { + if ($item['status_end'] == AGENT_MODULE_STATUS_CRITICAL_BAD) { + $item['link_color'] = '#FC4444'; + } else if ($item['status_end'] == AGENT_MODULE_STATUS_WARNING) { + $item['link_color'] = '#FAD403'; + } + + $agent = agents_get_agent_id_by_module_id( + $relation['id_parent_source_data'] + ); + foreach ($nodes_graph as $key2 => $node) { + if (isset($node['id_agent'])) { + if ($node['id_agent'] == $agent) { + $agent = $node['id_db']; + $control1 = true; + } + + if ($node['id_agent'] == $relation['id_child_source_data']) { + $agent2 = $node['id_db']; + $control2 = true; + } + + if ($control1 && $control2) { + break; + } + } + } + } else if (($relation['parent_type'] == 3) + && ($relation['child_type'] == 3) + ) { + foreach ($nodes_graph as $key2 => $node) { + if ($relation['id_parent'] == $node['id_db']) { + $agent = $node['id_db']; + } + } + + foreach ($nodes_graph as $key2 => $node) { + if ($relation['id_child'] == $node['id_db']) { + $agent2 = $node['id_db']; + } + } + } else if (($relation['parent_type'] == 3) + || ($relation['child_type'] == 3) + ) { + if ($relation['parent_type'] == 3) { + foreach ($nodes_graph as $key2 => $node) { + if ($relation['id_parent'] == $node['id_db']) { + $agent = $node['id_db']; + } else if ($node['id_agent'] == $relation['id_child_source_data']) { + $agent2 = $node['id_db']; + } + } + } else if ($relation['child_type'] == 3) { + foreach ($nodes_graph as $key2 => $node) { + if ($relation['id_child'] == $node['id_db']) { + $agent2 = $node['id_db']; + } else if ($node['id_agent'] == $relation['id_parent_source_data']) { + $agent = $node['id_db']; + } + } + } + } else { + foreach ($nodes_graph as $key2 => $node) { + if (isset($node['id_agent'])) { + if ($node['id_agent'] == $relation['id_parent_source_data']) { + $agent = $node['id_db']; + } else if ($node['id_agent'] == $relation['id_child_source_data']) { + $agent2 = $node['id_db']; + } + } + } + } + + foreach ($nodes_graph as $node) { + if ($node['id_db'] == $agent) { + $item['target'] = $node['id']; + } else if ($node['id_db'] == $agent2) { + $item['source'] = $node['id']; + } + } + + if ((($item['target'] == -1) || ($item['source'] == -1)) + && $relation['parent_type'] == 1 + && $relation['child_type'] == 1 + ) { + continue; + } + + $return[] = $item; + } + + return $return; +} + + +function networkmap_write_js_array($id, $nodes_and_relations=[], $map_dash_details=[]) +{ + global $config; + + db_clean_cache(); + + $ent_installed = (int) enterprise_installed(); + + $networkmap = db_get_row('tmap', 'id', $id); + + $networkmap['filter'] = json_decode($networkmap['filter'], true); + + // Hardcoded + $networkmap['filter']['holding_area'] = [ + 500, + 500, + ]; + + echo "\n"; + echo "////////////////////////////////////////////////////////////////////\n"; + echo "// VARS FROM THE DB\n"; + echo "////////////////////////////////////////////////////////////////////\n"; + echo "\n"; + echo "var url_background_grid = '".ui_get_full_url( + 'images/background_grid.png' + )."'\n"; + echo 'var networkmap_id = '.$id.";\n"; + + if (!empty($map_dash_details)) { + echo 'var x_offs = '.$map_dash_details['x_offs'].";\n"; + echo 'var y_offs = '.$map_dash_details['y_offs'].";\n"; + echo 'var z_dash = '.$map_dash_details['z_dash'].";\n"; + } else { + echo "var x_offs = null;\n"; + echo "var y_offs = null;\n"; + echo "var z_dash = null;\n"; + } + + echo 'var networkmap_refresh_time = 1000 * '.$networkmap['source_period'].";\n"; + echo 'var networkmap_center = [ '.$networkmap['center_x'].', '.$networkmap['center_y']."];\n"; + echo 'var networkmap_dimensions = [ '.$networkmap['width'].', '.$networkmap['height']."];\n"; + + echo 'var enterprise_installed = '.$ent_installed.";\n"; + + echo 'var node_radius = '.$networkmap['filter']['node_radius'].";\n"; + + echo 'var networkmap_holding_area_dimensions = '.json_encode($networkmap['filter']['holding_area']).";\n"; + + echo "var networkmap = {'nodes': [], 'links': []};\n"; + + $nodes = $nodes_and_relations['nodes']; + + if (empty($nodes)) { + $nodes = []; + } + + $count_item_holding_area = 0; + $count = 0; + $nodes_graph = []; + + foreach ($nodes as $key => $node) { + $style = json_decode($node['style'], true); + $node['style'] = json_decode($node['style'], true); + + // Only agents can be show + if (isset($node['type'])) { + if ($node['type'] == 1) { + continue; + } + } else { + $node['type'] = ''; + } + + $item = networkmap_db_node_to_js_node( + $node, + $count, + $count_item_holding_area + ); + if ($item['deleted']) { + continue; + } + + echo 'networkmap.nodes.push('.json_encode($item).");\n"; + $nodes_graph[$item['id']] = $item; + } + + $relations = $nodes_and_relations['relations']; + + if ($relations === false) { + $relations = []; + } + + // Clean the relations and transform the module relations into + // interfaces + networkmap_clean_relations_for_js($relations); + + $links_js = networkmap_links_to_js_links($relations, $nodes_graph); + + $array_aux = []; + foreach ($links_js as $link_js) { + if ($link_js['deleted']) { + unset($links_js[$link_js['id']]); + } + + if ($link_js['target'] == -1) { + unset($links_js[$link_js['id']]); + } + + if ($link_js['source'] == -1) { + unset($links_js[$link_js['id']]); + } + + if ($link_js['target'] == $link_js['source']) { + unset($links_js[$link_js['id']]); + } + + if ($link_js['arrow_start'] == 'module' && $link_js['arrow_end'] == 'module') { + echo 'networkmap.links.push('.json_encode($link_js).");\n"; + $array_aux[$link_js['id_agent_start']] = 1; + unset($links_js[$link_js['id']]); + } + } + + foreach ($links_js as $link_js) { + if (($link_js['id_agent_end'] === 0) && $array_aux[$link_js['id_agent_start']] === 1) { + continue; + } else { + echo 'networkmap.links.push('.json_encode($link_js).");\n"; + } + } + + echo "\n"; + echo "\n"; + + echo "////////////////////////////////////////////////////////////////////\n"; + echo "// INTERFACE STATUS COLORS\n"; + echo "////////////////////////////////////////////////////////////////////\n"; + + $module_color_status = []; + $module_color_status[] = [ + 'status_code' => AGENT_MODULE_STATUS_NORMAL, + 'color' => COL_NORMAL, + ]; + $module_color_status[] = [ + 'status_code' => AGENT_MODULE_STATUS_CRITICAL_BAD, + 'color' => COL_CRITICAL, + ]; + $module_color_status[] = [ + 'status_code' => AGENT_MODULE_STATUS_WARNING, + 'color' => COL_WARNING, + ]; + $module_color_status[] = [ + 'status_code' => AGENT_STATUS_ALERT_FIRED, + 'color' => COL_ALERTFIRED, + ]; + $module_color_status_unknown = COL_UNKNOWN; + + echo 'var module_color_status = '.json_encode($module_color_status).";\n"; + echo "var module_color_status_unknown = '".$module_color_status_unknown."';\n"; + + echo "\n"; + echo "\n"; + + echo "////////////////////////////////////////////////////////////////////\n"; + echo "// Other vars\n"; + echo "////////////////////////////////////////////////////////////////////\n"; + + echo "var translation_none = '".__('None')."';\n"; + echo "var dialog_node_edit_title = '".__('Edit node %s')."';\n"; + echo "var holding_area_title = '".__('Holding Area')."';\n"; + echo "var edit_menu = '".__('Show details and options')."';\n"; + echo "var interface_link_add = '".__('Add a interface link')."';\n"; + echo "var set_parent_link = '".__('Set parent interface')."';\n"; + echo "var set_as_children_menu = '".__('Set as children')."';\n"; + echo "var set_parent_menu = '".__('Set parent')."';\n"; + echo "var abort_relationship_menu = '".__('Abort the action of set relationship')."';\n"; + echo "var delete_menu = '".__('Delete')."';\n"; + echo "var add_node_menu = '".__('Add node')."';\n"; + echo "var set_center_menu = '".__('Set center')."';\n"; + echo "var refresh_menu = '".__('Refresh')."';\n"; + echo "var refresh_holding_area_menu = '".__('Refresh Holding area')."';\n"; + echo "var ok_button = '".__('Proceed')."';\n"; + echo "var message_to_confirm = '".__('Resetting the map will delete all customizations you have done, including manual relationships between elements, new items, etc.')."';\n"; + echo "var warning_message = '".__('WARNING')."';\n"; + echo "var ok_button = '".__('Proceed')."';\n"; + echo "var cancel_button = '".__('Cancel')."';\n"; + echo "var restart_map_menu = '".__('Restart map')."';\n"; + echo "var abort_relationship_interface = '".__('Abort the interface relationship')."';\n"; + echo "var abort_relationship_menu = '".__('Abort the action of set relationship')."';\n"; + + echo "\n"; + echo "\n"; +} + + +function networkmap_loadfile( + $id=0, + $file='', + &$relations_param, + $graph +) { + global $config; + + $height_map = 200; + if ((int) $id > 0) { + $height_map = db_get_value('height', 'tmap', 'id', $id); + } + + $networkmap_nodes = []; + + $relations = []; + + $other_file = file($file); + + // Remove the graph head + $graph = preg_replace('/^graph .*/', '', $graph); + // Cut in nodes the graph + $graph = explode(']', $graph); + + $ids = []; + foreach ($graph as $node) { + $line = str_replace("\n", ' ', $node); + + if (preg_match('/([0-9]+) \[.*tooltip.*id_module=([0-9]+)/', $line, $match) != 0) { + $ids[$match[1]] = [ + 'type' => 'module', + 'id_module' => $match[2], + ]; + } else if (preg_match('/([0-9]+) \[.*tooltip.*id_agent=([0-9]+)/', $line, $match) != 0) { + $ids[$match[1]] = [ + 'type' => 'agent', + 'id_agent' => $match[2], + ]; + } + } + + foreach ($other_file as $key => $line) { + // clean line a long spaces for one space caracter + $line = preg_replace('/[ ]+/', ' ', $line); + + $data = []; + + if (preg_match('/^node.*$/', $line) != 0) { + $items = explode(' ', $line); + $node_id = $items[1]; + $node_x = ($items[2] * 100); + // 200 is for show more big + $node_y = ($height_map - $items[3] * 100); + // 200 is for show more big + $data['id'] = $node_id; + $data['text'] = ''; + $data['image'] = ''; + $data['width'] = 10; + $data['height'] = 10; + $data['id_agent'] = 0; + + if (preg_match('/<img src=\"([^\"]*)\"/', $line, $match) == 1) { + $image = $match[1]; + + $data['shape'] = 'image'; + $data['image'] = $image; + $size = getimagesize($config['homedir'].'/'.$image); + $data['width'] = $size[0]; + $data['height'] = $size[1]; + + $data['id_agent'] = 0; + $data['id_module'] = 0; + $data['type'] = ''; + $product_name = get_product_name(); + if (preg_match("/$product_name/", $line) != 0) { + $data['text'] = $product_name; + $data['id_agent'] = 0; + } else { + $data['type'] = $ids[$node_id]['type']; + + switch ($ids[$node_id]['type']) { + case 'module': + $data['id_module'] = $ids[$node_id]['id_module']; + $data['id_agent'] = modules_get_agentmodule_agent($ids[$node_id]['id_module']); + + $text = modules_get_agentmodule_name($data['id_module']); + $text = ui_print_truncate_text( + $text, + 'agent_medium', + false, + true, + false, + '...', + false + ); + $data['text'] = $text; + $data['id_agent'] = db_get_value('id_agente', 'tagente_modulo', 'id_agente_modulo', $data['id_module']); + break; + + case 'agent': + $data['id_agent'] = $ids[$node_id]['id_agent']; + + $text = agents_get_alias($ids[$node_id]['id_agent']); + $text = ui_print_truncate_text( + $text, + 'agent_medium', + false, + true, + false, + '...', + false + ); + $data['text'] = $text; + $data['parent'] = db_get_value('id_parent', 'tagente', 'id_agente', $data['id_agent']); + break; + } + } + } else { + $data['shape'] = 'wtf'; + } + + $data['coords'] = [ + $node_x, + $node_y, + ]; + + if (strpos($node_id, 'transp_') !== false) { + // removed the transparent nodes + } else { + $networkmap_nodes[$node_id] = $data; + } + } else if (preg_match('/^edge.*$/', $line) != 0) { + $items = explode(' ', $line); + $line_orig = $items[2]; + $line_dest = $items[1]; + + // $relations[$line_dest] = $line_orig; + $relations[] = [ + 'orig' => $line_orig, + 'dest' => $line_dest, + ]; + } + } + + $relations_param = []; + + foreach ($relations as $rel) { + if (strpos($rel['orig'], 'transp_') !== false) { + // removed the transparent nodes + continue; + } + + if (strpos($rel['dest'], 'transp_') !== false) { + // removed the transparent nodes + continue; + } + + $row = [ + 'id_child' => $rel['orig'], + 'child_type' => $networkmap_nodes[$rel['orig']]['type'], + 'id_parent' => $rel['dest'], + 'parent_type' => $networkmap_nodes[$rel['dest']]['type'], + ]; + $relations_param[] = $row; + } + + return $networkmap_nodes; +} + + +function get_status_color_module_networkmap($id_agente_modulo) +{ + $status = modules_get_agentmodule_status($id_agente_modulo); + + // Set node status + switch ($status) { + case 0: + // At the moment the networkmap enterprise does not show the + // alerts. + case AGENT_MODULE_STATUS_NORMAL_ALERT: + $status_color = COL_NORMAL; + // Normal monitor + break; + + case 1: + $status_color = COL_CRITICAL; + // Critical monitor + break; + + case 2: + $status_color = COL_WARNING; + // Warning monitor + break; + + case 4: + $status_color = COL_ALERTFIRED; + // Alert fired + break; + + default: + $status_color = COL_UNKNOWN; + // Unknown monitor + break; + } + + return $status_color; +} + + +function duplicate_networkmap($id) +{ + $return = true; + + $values = db_get_row('tmap', 'id', $id); + unset($values['id']); + $free_name = false; + $values['name'] = io_safe_input(__('Copy of ')).$values['name']; + $count = 1; + while (!$free_name) { + $exist = db_get_row_filter('tmap', ['name' => $values['name']]); + if ($exist === false) { + $free_name = true; + } else { + $values['name'] = $values['name'].io_safe_input(' '.$count); + } + } + + $correct_or_id = db_process_sql_insert('tmap', $values); + if ($correct_or_id === false) { + $return = false; + } else { + if (enterprise_installed()) { + $new_id = $correct_or_id; + duplicate_map_insert_nodes_and_relations($id, $new_id); + } + } + + if ($return) { + return true; + } else { + // Clean DB. + if (enterprise_installed()) { + // Relations + delete_relations($new_id); + + // Nodes + delete_nodes($new_id); + } + + db_process_sql_delete('tmap', ['id' => $new_id]); + + return false; + } +} + + +function clean_duplicate_links($relations) +{ + if (enterprise_installed()) { + enterprise_include_once('include/functions_networkmap.php'); + } + + $segregation_links = []; + $index = 0; + $index2 = 0; + $index3 = 0; + $index4 = 0; + foreach ($relations as $rel) { + if (($rel['parent_type'] == 0) && ($rel['child_type'] == 0)) { + $segregation_links['aa'][$index] = $rel; + $index++; + } else if (($rel['parent_type'] == 1) && ($rel['child_type'] == 1)) { + $segregation_links['mm'][$index2] = $rel; + $index2++; + } else if (($rel['parent_type'] == 3) && ($rel['child_type'] == 3)) { + $segregation_links['ff'][$index4] = $rel; + $index4++; + } else { + $segregation_links['am'][$index3] = $rel; + $index3++; + } + } + + $final_links = []; + + // ---------------------------------------------------------------- + // --------------------- Clean duplicate links -------------------- + // ---------------------------------------------------------------- + $duplicated = false; + $index_to_del = 0; + $index = 0; + if (isset($segregation_links['aa']) === true + && is_array($segregation_links['aa']) === true + ) { + foreach ($segregation_links['aa'] as $link) { + foreach ($segregation_links['aa'] as $link2) { + if ($link['id_parent'] == $link2['id_child'] + && $link['id_child'] == $link2['id_parent'] + ) { + if (enterprise_installed()) { + delete_link($segregation_links['aa'][$index_to_del]); + } + + unset($segregation_links['aa'][$index_to_del]); + } + + $index_to_del++; + } + + $final_links['aa'][$index] = $link; + $index++; + + $duplicated = false; + $index_to_del = 0; + } + } + + $duplicated = false; + $index_to_del = 0; + $index2 = 0; + if (isset($segregation_links['mm']) === true + && is_array($segregation_links['mm']) === true + ) { + foreach ($segregation_links['mm'] as $link) { + foreach ($segregation_links['mm'] as $link2) { + if ($link['id_parent'] == $link2['id_child'] + && $link['id_child'] == $link2['id_parent'] + ) { + if (enterprise_installed()) { + delete_link($segregation_links['mm'][$index_to_del]); + } + } + + $index_to_del++; + } + + $final_links['mm'][$index2] = $link; + $index2++; + + $duplicated = false; + $index_to_del = 0; + } + } + + $duplicated = false; + $index_to_del = 0; + $index3 = 0; + + if (isset($segregation_links['ff']) === true + && is_array($segregation_links['ff']) === true + ) { + foreach ($segregation_links['ff'] as $link) { + foreach ($segregation_links['ff'] as $link2) { + if ($link['id_parent'] == $link2['id_child'] + && $link['id_child'] == $link2['id_parent'] + ) { + if (enterprise_installed()) { + delete_link($segregation_links['ff'][$index_to_del]); + } + + unset($segregation_links['ff'][$index_to_del]); + } + + $index_to_del++; + } + + $final_links['ff'][$index3] = $link; + $index3++; + + $duplicated = false; + $index_to_del = 0; + } + } + + $final_links['am'] = $segregation_links['am']; + + /* + ---------------------------------------------------------------- + ----------------- AA, AM and MM links management --------------- + ------------------ Priority: ----------------------------------- + -------------------- 1 -> MM (module - module) ----------------- + -------------------- 2 -> AM (agent - module) ------------------ + -------------------- 3 -> AA (agent - agent) ------------------- + ---------------------------------------------------------------- + */ + + $final_links2 = []; + $index = 0; + $l3_link = []; + $agent1 = 0; + $agent2 = 0; + + if (isset($final_links['mm']) === true + && is_array($final_links['mm']) === true + ) { + foreach ($final_links['mm'] as $rel_mm) { + $module_parent = $rel_mm['id_parent_source_data']; + $module_children = $rel_mm['id_child_source_data']; + $agent1 = (int) agents_get_agent_id_by_module_id($module_parent); + $agent2 = (int) agents_get_agent_id_by_module_id($module_children); + foreach ($final_links['aa'] as $key => $rel_aa) { + $l3_link = $rel_aa; + $id_p_source_data = (int) $rel_aa['id_parent_source_data']; + $id_c_source_data = (int) $rel_aa['id_child_source_data']; + if ((($id_p_source_data == $agent1) + && ($id_c_source_data == $agent2)) + || (($id_p_source_data == $agent2) + && ($id_c_source_data == $agent1)) + ) { + if (enterprise_installed()) { + delete_link($final_links['aa'][$key]); + } + + unset($final_links['aa'][$key]); + } + } + } + } + + $final_links2['aa'] = $final_links['aa']; + $final_links2['mm'] = $final_links['mm']; + $final_links2['am'] = $final_links['am']; + $final_links2['ff'] = $final_links['ff']; + + $same_m = []; + $index = 0; + if (isset($final_links2['am']) === true + && is_array($final_links2['am']) === true + ) { + foreach ($final_links2['am'] as $rel_am) { + foreach ($final_links2['am'] as $rel_am2) { + if (($rel_am['id_child_source_data'] == $rel_am2['id_child_source_data']) + && ($rel_am['id_parent_source_data'] != $rel_am2['id_parent_source_data']) + ) { + $same_m[$index]['rel'] = $rel_am2; + $same_m[$index]['agent_parent'] = $rel_am['id_parent_source_data']; + $index++; + } + } + } + } + + $final_links3 = []; + $index = 0; + $l3_link = []; + $have_l3 = false; + if (isset($final_links2['aa']) === true + && is_array($final_links2['aa']) === true + ) { + foreach ($final_links2['aa'] as $key => $rel_aa) { + $l3_link = $rel_aa; + foreach ($same_m as $rel_am) { + if ((($rel_aa['id_parent_source_data'] == $rel_am['parent']['id_parent_source_data']) + && ($rel_aa['id_child_source_data'] == $rel_am['rel']['id_parent_source_data'])) + || (($rel_aa['id_child_source_data'] == $rel_am['parent']['id_parent_source_data']) + && ($rel_aa['id_parent_source_data'] == $rel_am['rel']['id_parent_source_data'])) + ) { + if (enterprise_installed()) { + delete_link($final_links2['aa'][$key]); + } + + unset($final_links2['aa'][$key]); + } + } + } + } + + $final_links3['aa'] = $final_links2['aa']; + $final_links3['mm'] = $segregation_links['mm']; + $final_links3['am'] = $segregation_links['am']; + $final_links3['ff'] = $final_links2['ff']; + + $cleaned_links = []; + if (isset($final_links3['aa']) === true + && is_array($final_links3['aa']) === true + ) { + foreach ($final_links3['aa'] as $link) { + $cleaned_links[] = $link; + } + } + + if (isset($final_links3['am']) === true + && is_array($final_links3['am']) === true + ) { + foreach ($final_links3['am'] as $link) { + $cleaned_links[] = $link; + } + } + + if (isset($final_links3['mm']) === true + && is_array($final_links3['mm']) === true + ) { + foreach ($final_links3['mm'] as $link) { + $cleaned_links[] = $link; + } + } + + if (isset($final_links3['ff']) === true + && is_array($final_links3['ff']) === true + ) { + foreach ($final_links3['ff'] as $link) { + $cleaned_links[] = $link; + } + } + + return $cleaned_links; +} + + +function migrate_older_open_maps($id) +{ + global $config; + + $old_networkmap = db_get_row_filter( + 'tnetwork_map', + ['id_networkmap' => $id] + ); + + $map_values = []; + $map_values['id_group'] = $old_networkmap['id_group']; + $map_values['id_user'] = $old_networkmap['id_user']; + $map_values['type'] = 0; + $map_values['subtype'] = 0; + $map_values['name'] = $old_networkmap['name']; + + $new_map_filter = []; + $new_map_filter['dont_show_subgroups'] = $old_networkmap['dont_show_subgroups']; + $new_map_filter['node_radius'] = 40; + $new_map_filter['id_migrate_map'] = $id; + $map_values['filter'] = json_encode($new_map_filter); + + $map_values['description'] = 'Mapa open migrado'; + $map_values['width'] = 4000; + $map_values['height'] = 4000; + $map_values['center_x'] = 2000; + $map_values['center_y'] = 2000; + $map_values['background'] = ''; + $map_values['background_options'] = 0; + $map_values['source_period'] = 60; + $map_values['source'] = 0; + $map_values['source_data'] = $old_networkmap['id_group']; + if ($old_networkmap['type'] == 'radial_dinamic') { + $map_values['generation_method'] = 6; + } else { + $map_values['generation_method'] = 4; + } + + $map_values['generated'] = 0; + + $id_new_map = db_process_sql_insert('tmap', $map_values); + + if (!$id_new_map) { + return false; + } + + return true; +} + + +/** + * Load cluetip required files and JS. + * + * @return void + */ +function networkmap_load_cluetip() +{ + ui_require_css_file('cluetip', 'include/styles/js/'); + + ?> <script language="javascript" type="text/javascript"> $(document).ready (function () { // TODO: Implement the jquery tooltip functionality everywhere @@ -1802,3 +2738,5 @@ function modules_get_all_interfaces($id_agent) }); }); </script> + <?php +} \ No newline at end of file diff --git a/pandora_console/include/functions_networkmaps.php b/pandora_console/include/functions_networkmaps.php index 289b5f8f57..cad7fc7edf 100644 --- a/pandora_console/include/functions_networkmaps.php +++ b/pandora_console/include/functions_networkmaps.php @@ -1,17 +1,29 @@ <?php -; -// Pandora FMS - http://pandorafms.com -// ================================================== -// Copyright (c) 2005-2011 Artica Soluciones Tecnologicas -// Please see http://pandorafms.org for full contribution list -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public License -// as published by the Free Software Foundation; version 2 -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -/* - * @package Include - * @subpackage Networkmaps +/** + * Library for networkmaps in Pandora FMS + * + * @category Deprecated + * @package Pandora FMS + * @subpackage NetworkMap + * @version 1.0.0 + * @license See below + * + * ______ ___ _______ _______ ________ + * | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __| + * | __/| _ | | _ || _ | _| _ | | ___| |__ | + * |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| + * + * ============================================================================ + * Copyright (c) 2005-2019 Artica Soluciones Tecnologicas + * Please see http://pandorafms.org for full contribution list + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation for version 2. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ============================================================================ */ + +// Deprecated. diff --git a/pandora_console/include/functions_pandora_networkmap.php b/pandora_console/include/functions_pandora_networkmap.php index 785a67190d..cad7fc7edf 100644 --- a/pandora_console/include/functions_pandora_networkmap.php +++ b/pandora_console/include/functions_pandora_networkmap.php @@ -1,2227 +1,29 @@ <?php -// ______ __ _______ _______ _______ -// | __ \.---.-.-----.--| |.-----.----.---.-. | ___| | | __| -// | __/| _ | | _ || _ | _| _ | | ___| |__ | -// |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| -// -// ============================================================================ -// Copyright (c) 2007-2010 Artica Soluciones Tecnologicas, http://www.artica.es -// This code is NOT free software. This code is NOT licenced under GPL2 licence -// You cannnot redistribute it without written permission of copyright holder. -// ============================================================================ -enterprise_include_once('include/functions_pandora_networkmap.php'); - - -function networkmap_delete_networkmap($id=0) -{ - if (enterprise_installed()) { - // Relations - $result = delete_relations($id); - - // Nodes - $result = delete_nodes($id); - } - - // Map - $result = db_process_sql_delete('tmap', ['id' => $id]); - - return $result; -} - - -function networkmap_delete_nodes($id_map) -{ - return db_process_sql_delete('titem', ['id_map' => $id_map]); -} - - -function networkmap_process_networkmap($id=0) -{ - global $config; - - include_once 'include/functions_os.php'; - - $numNodes = (int) db_get_num_rows( - ' - SELECT * - FROM titem - WHERE id_map = '.$id.' and deleted = 0' - ); - - $networkmap = db_get_row_filter( - 'tmap', - ['id' => $id] - ); - $map_filter = json_decode($networkmap['filter'], true); - - $pure = (int) get_parameter('pure', 0); - - switch ($networkmap['generation_method']) { - case LAYOUT_CIRCULAR: - $filter = 'circo'; - $layout = 'circular'; - break; - - case LAYOUT_FLAT: - $filter = 'dot'; - $layout = 'flat'; - break; - - case LAYOUT_RADIAL: - $filter = 'twopi'; - $layout = 'radial'; - break; - - case LAYOUT_SPRING1: - $filter = 'neato'; - $layout = 'spring1'; - break; - - case LAYOUT_SPRING2: - $filter = 'fdp'; - $layout = 'spring2'; - break; - } - - $simple = 0; - $font_size = 12; - $nooverlap = false; - $zoom = 1; - $ranksep = 0.5; - $center = 0; - $regen = 1; - $show_snmp_modules = false; - $dont_show_subgroups = false; - - $id_group = $networkmap['id_group']; - $ip_mask = ''; - switch ($networkmap['source']) { - case 1: - $recon_task = db_get_row_filter( - 'trecon_task', - ['id_rt' => $networkmap['source_data']] - ); - - $ip_mask = $recon_task['subnet']; - break; - - case 2: - $ip_mask = $networkmap['source_data']; - break; - } - - $nodes_and_relations = []; - - if (enterprise_installed() && ($numNodes > 0)) { - $nodes_and_relations = get_structure_nodes($id); - } else { - if ($map_filter['empty_map']) { - // Open Graph - $graph = networkmap_open_graph( - $layout, - $nooverlap, - $pure, - $zoom, - $ranksep, - $font_size, - null - ); - $graph .= networkmap_create_pandora_node(get_product_name(), $font_size, $simple); - $graph .= networkmap_close_graph(); - - switch (PHP_OS) { - case 'WIN32': - case 'WINNT': - case 'Windows': - $filename_dot = sys_get_temp_dir()."\\networkmap_".$filter; - break; - - default: - $filename_dot = sys_get_temp_dir().'/networkmap_'.$filter; - break; - } - - if ($simple) { - $filename_dot .= '_simple'; - } - - if ($nooverlap) { - $filename_dot .= '_nooverlap'; - } - - $filename_dot .= '_'.$id.'.dot'; - - file_put_contents($filename_dot, $graph); - - switch (PHP_OS) { - case 'WIN32': - case 'WINNT': - case 'Windows': - $filename_plain = sys_get_temp_dir().'\\plain.txt'; - - $cmd = io_safe_output( - $config['graphviz_bin_dir']."\\$filter.exe -Tplain -o ".$filename_plain.' '.$filename_dot - ); - break; - - default: - $filename_plain = sys_get_temp_dir().'/plain.txt'; - - $cmd = "$filter -Tplain -o ".$filename_plain.' '.$filename_dot; - break; - } - - system($cmd); - - unlink($filename_dot); - - $nodes = networkmap_loadfile( - $id, - $filename_plain, - $relation_nodes, - $graph - ); - - unlink($filename_plain); - - // Set the position of modules - foreach ($nodes as $key => $node) { - if ($node['type'] == 'module') { - // Search the agent of this module for to get the - // position - foreach ($nodes as $key2 => $node2) { - if ($node2['id_agent'] != 0 && $node2['type'] == 'agent') { - if ($node2['id_agent'] == $node['id_agent']) { - $nodes[$key]['coords'][0] = ($nodes[$key2]['coords'][0] + $node['height'] / 2); - $nodes[$key]['coords'][1] = ($nodes[$key2]['coords'][1] + $node['width'] / 2); - } - } - } - } - } - - $nodes_and_relations['nodes'] = []; - $index = 0; - foreach ($nodes as $key => $node) { - $nodes_and_relations['nodes'][$index]['id'] = $node['id']; - $nodes_and_relations['nodes'][$index]['id_map'] = $id; - - $nodes_and_relations['nodes'][$index]['x'] = (int) $node['coords'][0]; - $nodes_and_relations['nodes'][$index]['y'] = (int) $node['coords'][1]; - - if (($node['type'] == 'agent') || ($node['type'] == '')) { - $nodes_and_relations['nodes'][$index]['source_data'] = $node['id_agent']; - $nodes_and_relations['nodes'][$index]['type'] = 0; - } else { - $nodes_and_relations['nodes'][$index]['source_data'] = $node['id_module']; - $nodes_and_relations['nodes'][$index]['id_agent'] = $node['id_agent']; - $nodes_and_relations['nodes'][$index]['type'] = 1; - } - - $style = []; - $style['shape'] = 'circle'; - $style['image'] = $node['image']; - $style['width'] = $node['width']; - $style['height'] = $node['height']; - $style['label'] = $node['text']; - $style['id_networkmap'] = $node['networkmap']; - $nodes_and_relations['nodes'][$index]['style'] = json_encode($style); - - $index++; - } - - $nodes_and_relations['relations'] = []; - - if (enterprise_installed()) { - enterprise_include_once('include/functions_pandora_networkmap.php'); - save_generate_nodes($id, $nodes_and_relations); - } - } else { - // Generate dot file - $graph = networkmap_generate_dot( - get_product_name(), - $id_group, - $simple, - $font_size, - $layout, - $nooverlap, - $zoom, - $ranksep, - $center, - $regen, - $pure, - $id, - $show_snmp_modules, - false, - // cut_names - true, - // relative - '', - $ip_mask, - $dont_show_subgroups, - false, - null, - $old_mode, - $map_filter - ); - - switch (PHP_OS) { - case 'WIN32': - case 'WINNT': - case 'Windows': - $filename_dot = sys_get_temp_dir()."\\networkmap_".$filter; - break; - - default: - $filename_dot = sys_get_temp_dir().'/networkmap_'.$filter; - break; - } - - if ($simple) { - $filename_dot .= '_simple'; - } - - if ($nooverlap) { - $filename_dot .= '_nooverlap'; - } - - $filename_dot .= '_'.$id.'.dot'; - - file_put_contents($filename_dot, $graph); - - switch (PHP_OS) { - case 'WIN32': - case 'WINNT': - case 'Windows': - $filename_plain = sys_get_temp_dir().'\\plain.txt'; - - $cmd = io_safe_output( - $config['graphviz_bin_dir']."\\$filter.exe -Tplain -o ".$filename_plain.' '.$filename_dot - ); - break; - - default: - $filename_plain = sys_get_temp_dir().'/plain.txt'; - - $cmd = "$filter -Tplain -o ".$filename_plain.' '.$filename_dot; - break; - } - - system($cmd); - - unlink($filename_dot); - - $nodes = networkmap_loadfile( - $id, - $filename_plain, - $relation_nodes, - $graph - ); - - unlink($filename_plain); - - // Set the position of modules - foreach ($nodes as $key => $node) { - if ($node['type'] == 'module') { - // Search the agent of this module for to get the - // position - foreach ($nodes as $key2 => $node2) { - if ($node2['id_agent'] != 0 && $node2['type'] == 'agent') { - if ($node2['id_agent'] == $node['id_agent']) { - $nodes[$key]['coords'][0] = ($nodes[$key2]['coords'][0] + $node['height'] / 2); - $nodes[$key]['coords'][1] = ($nodes[$key2]['coords'][1] + $node['width'] / 2); - } - } - } - } - } - - $nodes_and_relations['nodes'] = []; - $index = 0; - $node_center = []; - foreach ($nodes as $key => $node) { - $nodes_and_relations['nodes'][$index]['id'] = $node['id']; - $nodes_and_relations['nodes'][$index]['id_map'] = $id; - - $children_count = 0; - foreach ($relation_nodes as $relation) { - if (($relation['parent_type'] == 'agent') || ($relation['parent_type'] == '')) { - if ($nodes[$relation['id_parent']]['id_agent'] == $node['id_agent']) { - $children_count++; - } - } else if ($relation['parent_type'] == 'module') { - if ($nodes[$relation['id_parent']]['id_module'] == $node['id_module']) { - $children_count++; - } - } - } - - if (empty($node_center) || $node_center['counter'] < $children_count) { - $node_center['x'] = (int) $node['coords'][0]; - $node_center['y'] = (int) $node['coords'][1]; - $node_center['counter'] = $children_count; - } - - $nodes_and_relations['nodes'][$index]['x'] = (int) $node['coords'][0]; - $nodes_and_relations['nodes'][$index]['y'] = (int) $node['coords'][1]; - - if (($node['type'] == 'agent') || ($node['type'] == '')) { - $nodes_and_relations['nodes'][$index]['source_data'] = $node['id_agent']; - $nodes_and_relations['nodes'][$index]['type'] = 0; - } else { - $nodes_and_relations['nodes'][$index]['source_data'] = $node['id_module']; - $nodes_and_relations['nodes'][$index]['id_agent'] = $node['id_agent']; - $nodes_and_relations['nodes'][$index]['type'] = 1; - } - - $style = []; - $style['shape'] = 'circle'; - $style['image'] = $node['image']; - $style['width'] = $node['width']; - $style['height'] = $node['height']; - $style['label'] = $node['text']; - $nodes_and_relations['nodes'][$index]['style'] = json_encode($style); - - $index++; - } - - $nodes_and_relations['relations'] = []; - $index = 0; - foreach ($relation_nodes as $relation) { - $nodes_and_relations['relations'][$index]['id_map'] = $id; - - if (($relation['parent_type'] == 'agent') || ($relation['parent_type'] == '')) { - $nodes_and_relations['relations'][$index]['id_parent'] = $relation['id_parent']; - $nodes_and_relations['relations'][$index]['id_parent_source_data'] = $nodes[$relation['id_parent']]['id_agent']; - $nodes_and_relations['relations'][$index]['parent_type'] = 0; - } else if ($relation['parent_type'] == 'module') { - $nodes_and_relations['relations'][$index]['id_parent'] = $relation['id_parent']; - $nodes_and_relations['relations'][$index]['id_parent_source_data'] = $nodes[$relation['id_parent']]['id_module']; - $nodes_and_relations['relations'][$index]['parent_type'] = 1; - } else { - $nodes_and_relations['relations'][$index]['id_parent'] = $relation['id_parent']; - $nodes_and_relations['relations'][$index]['id_child_source_data'] = -2; - $nodes_and_relations['relations'][$index]['parent_type'] = 3; - } - - if (($relation['child_type'] == 'agent') || ($relation['child_type'] == '')) { - $nodes_and_relations['relations'][$index]['id_child'] = $relation['id_child']; - $nodes_and_relations['relations'][$index]['id_child_source_data'] = $nodes[$relation['id_child']]['id_agent']; - $nodes_and_relations['relations'][$index]['child_type'] = 0; - } else if ($relation['child_type'] == 'module') { - $nodes_and_relations['relations'][$index]['id_child'] = $relation['id_child']; - $nodes_and_relations['relations'][$index]['id_child_source_data'] = $nodes[$relation['id_child']]['id_module']; - $nodes_and_relations['relations'][$index]['child_type'] = 1; - } else { - $nodes_and_relations['relations'][$index]['id_child'] = $relation['id_child']; - $nodes_and_relations['relations'][$index]['id_child_source_data'] = -2; - $nodes_and_relations['relations'][$index]['child_type'] = 3; - } - - $index++; - } - - if (enterprise_installed()) { - enterprise_include_once('include/functions_pandora_networkmap.php'); - save_generate_nodes($id, $nodes_and_relations); - } - - $pandorafms_node = $nodes_and_relations['nodes'][0]; - $center = [ - 'x' => $node_center['x'], - 'y' => $node_center['y'], - ]; - - $networkmap['center_x'] = $center['x']; - $networkmap['center_y'] = $center['y']; - db_process_sql_update( - 'tmap', - [ - 'center_x' => $networkmap['center_x'], - 'center_y' => $networkmap['center_y'], - ], - ['id' => $id] - ); - } - } - - return $nodes_and_relations; -} - - -function get_networkmaps($id) -{ - $groups = array_keys(users_get_groups(null, 'IW')); - - $filter = []; - $filter['id_group'] = $groups; - $filter['id'] = '<>'.$id; - $networkmaps = db_get_all_rows_filter('tmap', $filter); - if ($networkmaps === false) { - $networkmaps = []; - } - - $return = []; - $return[0] = __('None'); - foreach ($networkmaps as $networkmap) { - $return[$networkmap['id']] = $networkmap['name']; - } - - return $return; -} - - /** - * Translates node (nodes_and_relations) into JS node. + * Library for networkmaps in Pandora FMS * - * @param array $node Node. - * @param integer $count Count. - * @param integer $count_item_holding_area Count_item_holding_area. - * @param boolean $simulated Simulated. + * @category Deprecated + * @package Pandora FMS + * @subpackage NetworkMap + * @version 1.0.0 + * @license See below * - * @return array JS nodes. + * ______ ___ _______ _______ ________ + * | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __| + * | __/| _ | | _ || _ | _| _ | | ___| |__ | + * |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| + * + * ============================================================================ + * Copyright (c) 2005-2019 Artica Soluciones Tecnologicas + * Please see http://pandorafms.org for full contribution list + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation for version 2. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ============================================================================ */ -function networkmap_db_node_to_js_node( - $node, - &$count, - &$count_item_holding_area, - $simulated=false -) { - global $config; - $networkmap = db_get_row('tmap', 'id', $node['id_map']); - - $networkmap['filter'] = json_decode($networkmap['filter'], true); - - // Hardcoded - $networkmap['filter']['holding_area'] = [ - 500, - 500, - ]; - - // 40 = DEFAULT NODE RADIUS - // 30 = for to align - $holding_area_max_y = ($networkmap['height'] + 30 + 40 * 2 - $networkmap['filter']['holding_area'][1] + 10 * 40); - - $item = []; - $item['id'] = $count; - - if (enterprise_installed() && $simulated === false) { - enterprise_include_once('include/functions_pandora_networkmap.php'); - $item['id_db'] = $node['id_in_db']; - } else { - $item['id_db'] = (int) $node['id']; - } - - if ((int) $node['type'] == 0) { - $item['type'] = 0; - $item['id_agent'] = (int) $node['source_data']; - $item['id_module'] = ''; - } else if ((int) $node['type'] == 1) { - $item['type'] = 1; - $item['id_agent'] = (int) $node['style']['id_agent']; - $item['id_module'] = (int) $node['source_data']; - } else { - $item['type'] = 3; - } - - $item['fixed'] = true; - $item['x'] = (int) $node['x']; - $item['y'] = (int) $node['y']; - $item['px'] = (int) $node['x']; - $item['py'] = (int) $node['y']; - $item['z'] = (int) $node['z']; - $item['state'] = $node['state']; - $item['deleted'] = $node['deleted']; - if ($item['state'] == 'holding_area') { - // 40 = DEFAULT NODE RADIUS - // 30 = for to align - $holding_area_x = ($networkmap['width'] + 30 + 40 * 2 - $networkmap['filter']['holding_area'][0] + ($count_item_holding_area % 11) * 40); - $holding_area_y = ($networkmap['height'] + 30 + 40 * 2 - $networkmap['filter']['holding_area'][1] + (int) (($count_item_holding_area / 11)) * 40); - - if ($holding_area_max_y <= $holding_area_y) { - $holding_area_y = $holding_area_max_y; - } - - $item['x'] = $holding_area_x; - $item['y'] = $holding_area_y; - - // Increment for the next node in holding area - $count_item_holding_area++; - } - - $item['image_url'] = ''; - $item['image_width'] = 0; - $item['image_height'] = 0; - if (!empty($node['style']['image'])) { - $item['image_url'] = html_print_image( - $node['style']['image'], - true, - false, - true - ); - $image_size = getimagesize( - $config['homedir'].'/'.$node['style']['image'] - ); - $item['image_width'] = (int) $image_size[0]; - $item['image_height'] = (int) $image_size[1]; - } - - $item['raw_text'] = $node['style']['label']; - $item['text'] = io_safe_output($node['style']['label']); - $item['shape'] = $node['style']['shape']; - switch ($node['type']) { - case 0: - $color = get_status_color_networkmap($node['source_data']); - break; - - default: - // Old code - if ($node['source_data'] == -1) { - $color = '#364D1F'; - } else if ($node['source_data'] == -2) { - $color = '#364D1F'; - } else { - $color = get_status_color_networkmap($node['source_data']); - } - break; - } - - $item['color'] = $color; - $item['map_id'] = 0; - if (isset($node['id_map'])) { - $item['map_id'] = $node['id_map']; - } - - if (!isset($node['style']['id_networkmap']) || $node['style']['id_networkmap'] == '' || $node['style']['id_networkmap'] == 0) { - $item['networkmap_id'] = 0; - } else { - $item['networkmap_id'] = $node['style']['id_networkmap']; - } - - $count++; - - return $item; -} - - -function get_status_color_networkmap($id, $color=true) -{ - // $status = agents_get_status($id); - $agent_data = db_get_row_sql('SELECT * FROM tagente WHERE id_agente = '.$id); - - if ($agent_data === false) { - return COL_UNKNOWN; - } - - $status = agents_get_status_from_counts($agent_data); - - if (!$color) { - return $status; - } - - if ($agent_data['fired_count'] > 0) { - return COL_ALERTFIRED; - } - - // Select node color by checking status. - switch ($status) { - case AGENT_MODULE_STATUS_NORMAL: - return COL_NORMAL; - - case AGENT_MODULE_STATUS_NOT_INIT: - return COL_NOTINIT; - - case AGENT_MODULE_STATUS_CRITICAL_BAD: - return COL_CRITICAL; - - case AGENT_MODULE_STATUS_WARNING: - return COL_WARNING; - - case AGENT_MODULE_STATUS_UNKNOWN: - default: - return COL_UNKNOWN; - } - - return COL_UNKNOWN; -} - - -function networkmap_clean_relations_for_js(&$relations) -{ - do { - $cleaned = true; - - foreach ($relations as $key => $relation) { - if ($relation['id_parent_source_data'] == $relation['id_child_source_data']) { - if (($relation['child_type'] != 3) && $relation['parent_type'] != 3) { - $cleaned = false; - - if ($relation['parent_type'] == 1) { - $to_find = $relation['id_parent_source_data']; - $to_replace = $relation['id_child_source_data']; - } else if ($relation['child_type'] == 1) { - $to_find = $relation['id_child_source_data']; - $to_replace = $relation['id_parent_source_data']; - } - - // Replace and erase the links - foreach ($relations as $key2 => $relation2) { - if ($relation2['id_parent_source_data'] == $to_find) { - $relations[$key2]['id_parent_source_data'] = $to_replace; - } else if ($relation2['id_child_source_data'] == $to_find) { - $relations[$key2]['id_child_source_data'] = $to_replace; - } - } - - unset($relations[$key]); - - break; - } - } - } - } while (!$cleaned); -} - - -/** - * Transform networkmap relations into js links. - * - * @param array $relations Relations. - * @param array $nodes_graph Nodes_graph. - * @param boolean $simulated Simulated. - * - * @return array JS relations. - */ -function networkmap_links_to_js_links( - $relations, - $nodes_graph, - $simulated=false -) { - $return = []; - - if (enterprise_installed() && $simulated === false) { - enterprise_include_once('include/functions_pandora_networkmap.php'); - } - - $count = 0; - foreach ($relations as $key => $relation) { - if (($relation['parent_type'] == 1) && ($relation['child_type'] == 1)) { - $id_target_agent = agents_get_agent_id_by_module_id( - $relation['id_parent_source_data'] - ); - $id_source_agent = agents_get_agent_id_by_module_id( - $relation['id_child_source_data'] - ); - $id_target_module = $relation['id_parent_source_data']; - $id_source_module = $relation['id_child_source_data']; - } else if (($relation['parent_type'] == 1) - && ($relation['child_type'] == 0) - ) { - $id_target_agent = agents_get_agent_id_by_module_id( - $relation['id_parent_source_data'] - ); - $id_target_module = $relation['id_parent_source_data']; - $id_source_agent = $relation['id_child_source_data']; - } else if (($relation['parent_type'] == 0) - && ($relation['child_type'] == 1) - ) { - $id_target_agent = $relation['id_parent_source_data']; - $id_source_module = $relation['id_child_source_data']; - $id_source_agent = agents_get_agent_id_by_module_id( - $relation['id_child_source_data'] - ); - } else { - $id_target_agent = $relation['id_parent_source_data']; - $id_source_agent = $relation['id_child_source_data']; - } - - $item = []; - $item['id'] = $count; - $count++; - if (enterprise_installed() && $simulated === false) { - $item['id_db'] = get_relation_id($relation); - } else { - $item['id_db'] = $key; - } - - $item['arrow_start'] = ''; - $item['arrow_end'] = ''; - $item['status_start'] = ''; - $item['status_end'] = ''; - $item['id_module_start'] = 0; - $item['id_agent_start'] = (int) $id_source_agent; - $item['id_module_end'] = 0; - $item['id_agent_end'] = (int) $id_target_agent; - $item['link_color'] = '#999'; - $item['target'] = -1; - $item['source'] = -1; - $item['deleted'] = $relation['deleted']; - - if (enterprise_installed() && $simulated === false) { - $target_and_source = []; - $target_and_source = get_id_target_and_source_in_db($relation); - $item['target_id_db'] = (int) $target_and_source['target']; - $item['source_id_db'] = (int) $target_and_source['source']; - } else { - if (($relation['parent_type'] == 1) && ($relation['child_type'] == 1)) { - $item['target_id_db'] = $id_target_agent; - $item['source_id_db'] = $id_source_agent; - } else if (($relation['parent_type'] == 0) && ($relation['child_type'] == 0)) { - $item['target_id_db'] = (int) $relation['id_parent_source_data']; - $item['source_id_db'] = $id_source_agent; - } else { - $item['target_id_db'] = (int) $relation['id_parent_source_data']; - $item['source_id_db'] = (int) $relation['id_child_source_data']; - } - } - - $item['text_end'] = ''; - $item['text_start'] = ''; - - if ($relation['parent_type'] == 1) { - $item['arrow_end'] = 'module'; - $item['status_end'] = modules_get_agentmodule_status((int) $id_target_module, false, false, null); - $item['id_module_end'] = (int) $id_target_module; - $text_end = modules_get_agentmodule_name((int) $id_target_module); - if (preg_match('/(.+)_ifOperStatus$/', (string) $text_end, $matches)) { - if ($matches[1]) { - // It's ok to safe_output as it inlo goint to be user into the map line - $item['text_end'] = io_safe_output($matches[1]); - } - } - } - - if ($relation['child_type'] == 1) { - $item['arrow_start'] = 'module'; - $item['status_start'] = modules_get_agentmodule_status((int) $id_source_module, false, false, null); - $item['id_module_start'] = (int) $id_source_module; - $text_start = modules_get_agentmodule_name((int) $id_source_module); - if (preg_match('/(.+)_ifOperStatus$/', (string) $text_start, $matches)) { - if ($matches[1]) { - // It's ok to safe_output as it inlo goint to be user into the map line - $item['text_start'] = io_safe_output($matches[1]); - } - } - } - - $agent = 0; - $agent2 = 0; - $control1 = false; - $control2 = false; - - if (($relation['parent_type'] == 1) && ($relation['child_type'] == 1)) { - if (($item['status_start'] == AGENT_MODULE_STATUS_CRITICAL_BAD) || ($item['status_end'] == AGENT_MODULE_STATUS_CRITICAL_BAD)) { - $item['link_color'] = '#FC4444'; - } else if (($item['status_start'] == AGENT_MODULE_STATUS_WARNING) || ($item['status_end'] == AGENT_MODULE_STATUS_WARNING)) { - $item['link_color'] = '#FAD403'; - } - - $agent = agents_get_agent_id_by_module_id( - $relation['id_parent_source_data'] - ); - $agent2 = agents_get_agent_id_by_module_id( - $relation['id_child_source_data'] - ); - foreach ($nodes_graph as $key2 => $node) { - if (isset($node['id_agent'])) { - if ($node['id_agent'] == $agent) { - $agent = $node['id_db']; - $control1 = true; - } - - if ($node['id_agent'] == $agent2) { - $agent2 = $node['id_db']; - $control2 = true; - } - - if ($control1 && $control2) { - break; - } - } - } - } else if ($relation['child_type'] == 1) { - if ($item['status_start'] == AGENT_MODULE_STATUS_CRITICAL_BAD) { - $item['link_color'] = '#FC4444'; - } else if ($item['status_start'] == AGENT_MODULE_STATUS_WARNING) { - $item['link_color'] = '#FAD403'; - } - - $agent2 = agents_get_agent_id_by_module_id( - $relation['id_child_source_data'] - ); - foreach ($nodes_graph as $key2 => $node) { - if (isset($node['id_agent'])) { - if ($node['id_agent'] == $relation['id_parent_source_data']) { - $agent = $node['id_db']; - $control1 = true; - } - - if ($node['id_agent'] == $agent2) { - $agent2 = $node['id_db']; - $control2 = true; - } - - if ($control1 && $control2) { - break; - } - } - } - } else if ($relation['parent_type'] == 1) { - if ($item['status_end'] == AGENT_MODULE_STATUS_CRITICAL_BAD) { - $item['link_color'] = '#FC4444'; - } else if ($item['status_end'] == AGENT_MODULE_STATUS_WARNING) { - $item['link_color'] = '#FAD403'; - } - - $agent = agents_get_agent_id_by_module_id( - $relation['id_parent_source_data'] - ); - foreach ($nodes_graph as $key2 => $node) { - if (isset($node['id_agent'])) { - if ($node['id_agent'] == $agent) { - $agent = $node['id_db']; - $control1 = true; - } - - if ($node['id_agent'] == $relation['id_child_source_data']) { - $agent2 = $node['id_db']; - $control2 = true; - } - - if ($control1 && $control2) { - break; - } - } - } - } else if (($relation['parent_type'] == 3) - && ($relation['child_type'] == 3) - ) { - foreach ($nodes_graph as $key2 => $node) { - if ($relation['id_parent'] == $node['id_db']) { - $agent = $node['id_db']; - } - } - - foreach ($nodes_graph as $key2 => $node) { - if ($relation['id_child'] == $node['id_db']) { - $agent2 = $node['id_db']; - } - } - } else if (($relation['parent_type'] == 3) - || ($relation['child_type'] == 3) - ) { - if ($relation['parent_type'] == 3) { - foreach ($nodes_graph as $key2 => $node) { - if ($relation['id_parent'] == $node['id_db']) { - $agent = $node['id_db']; - } else if ($node['id_agent'] == $relation['id_child_source_data']) { - $agent2 = $node['id_db']; - } - } - } else if ($relation['child_type'] == 3) { - foreach ($nodes_graph as $key2 => $node) { - if ($relation['id_child'] == $node['id_db']) { - $agent2 = $node['id_db']; - } else if ($node['id_agent'] == $relation['id_parent_source_data']) { - $agent = $node['id_db']; - } - } - } - } else { - foreach ($nodes_graph as $key2 => $node) { - if (isset($node['id_agent'])) { - if ($node['id_agent'] == $relation['id_parent_source_data']) { - $agent = $node['id_db']; - } else if ($node['id_agent'] == $relation['id_child_source_data']) { - $agent2 = $node['id_db']; - } - } - } - } - - foreach ($nodes_graph as $node) { - if ($node['id_db'] == $agent) { - $item['target'] = $node['id']; - } else if ($node['id_db'] == $agent2) { - $item['source'] = $node['id']; - } - } - - if ((($item['target'] == -1) || ($item['source'] == -1)) - && $relation['parent_type'] == 1 - && $relation['child_type'] == 1 - ) { - continue; - } - - $return[] = $item; - } - - return $return; -} - - -function networkmap_write_js_array($id, $nodes_and_relations=[], $map_dash_details=[]) -{ - global $config; - - db_clean_cache(); - - $ent_installed = (int) enterprise_installed(); - - $networkmap = db_get_row('tmap', 'id', $id); - - $networkmap['filter'] = json_decode($networkmap['filter'], true); - - // Hardcoded - $networkmap['filter']['holding_area'] = [ - 500, - 500, - ]; - - echo "\n"; - echo "////////////////////////////////////////////////////////////////////\n"; - echo "// VARS FROM THE DB\n"; - echo "////////////////////////////////////////////////////////////////////\n"; - echo "\n"; - echo "var url_background_grid = '".ui_get_full_url( - 'images/background_grid.png' - )."'\n"; - echo 'var networkmap_id = '.$id.";\n"; - - if (!empty($map_dash_details)) { - echo 'var x_offs = '.$map_dash_details['x_offs'].";\n"; - echo 'var y_offs = '.$map_dash_details['y_offs'].";\n"; - echo 'var z_dash = '.$map_dash_details['z_dash'].";\n"; - } else { - echo "var x_offs = null;\n"; - echo "var y_offs = null;\n"; - echo "var z_dash = null;\n"; - } - - echo 'var networkmap_refresh_time = 1000 * '.$networkmap['source_period'].";\n"; - echo 'var networkmap_center = [ '.$networkmap['center_x'].', '.$networkmap['center_y']."];\n"; - echo 'var networkmap_dimensions = [ '.$networkmap['width'].', '.$networkmap['height']."];\n"; - - echo 'var enterprise_installed = '.$ent_installed.";\n"; - - echo 'var node_radius = '.$networkmap['filter']['node_radius'].";\n"; - - echo 'var networkmap_holding_area_dimensions = '.json_encode($networkmap['filter']['holding_area']).";\n"; - - echo "var networkmap = {'nodes': [], 'links': []};\n"; - - $nodes = $nodes_and_relations['nodes']; - - if (empty($nodes)) { - $nodes = []; - } - - $count_item_holding_area = 0; - $count = 0; - $nodes_graph = []; - - foreach ($nodes as $key => $node) { - $style = json_decode($node['style'], true); - $node['style'] = json_decode($node['style'], true); - - // Only agents can be show - if (isset($node['type'])) { - if ($node['type'] == 1) { - continue; - } - } else { - $node['type'] = ''; - } - - $item = networkmap_db_node_to_js_node( - $node, - $count, - $count_item_holding_area - ); - if ($item['deleted']) { - continue; - } - - echo 'networkmap.nodes.push('.json_encode($item).");\n"; - $nodes_graph[$item['id']] = $item; - } - - $relations = $nodes_and_relations['relations']; - - if ($relations === false) { - $relations = []; - } - - // Clean the relations and transform the module relations into - // interfaces - networkmap_clean_relations_for_js($relations); - - $links_js = networkmap_links_to_js_links($relations, $nodes_graph); - - $array_aux = []; - foreach ($links_js as $link_js) { - if ($link_js['deleted']) { - unset($links_js[$link_js['id']]); - } - - if ($link_js['target'] == -1) { - unset($links_js[$link_js['id']]); - } - - if ($link_js['source'] == -1) { - unset($links_js[$link_js['id']]); - } - - if ($link_js['target'] == $link_js['source']) { - unset($links_js[$link_js['id']]); - } - - if ($link_js['arrow_start'] == 'module' && $link_js['arrow_end'] == 'module') { - echo 'networkmap.links.push('.json_encode($link_js).");\n"; - $array_aux[$link_js['id_agent_start']] = 1; - unset($links_js[$link_js['id']]); - } - } - - foreach ($links_js as $link_js) { - if (($link_js['id_agent_end'] === 0) && $array_aux[$link_js['id_agent_start']] === 1) { - continue; - } else { - echo 'networkmap.links.push('.json_encode($link_js).");\n"; - } - } - - echo "\n"; - echo "\n"; - - echo "////////////////////////////////////////////////////////////////////\n"; - echo "// INTERFACE STATUS COLORS\n"; - echo "////////////////////////////////////////////////////////////////////\n"; - - $module_color_status = []; - $module_color_status[] = [ - 'status_code' => AGENT_MODULE_STATUS_NORMAL, - 'color' => COL_NORMAL, - ]; - $module_color_status[] = [ - 'status_code' => AGENT_MODULE_STATUS_CRITICAL_BAD, - 'color' => COL_CRITICAL, - ]; - $module_color_status[] = [ - 'status_code' => AGENT_MODULE_STATUS_WARNING, - 'color' => COL_WARNING, - ]; - $module_color_status[] = [ - 'status_code' => AGENT_STATUS_ALERT_FIRED, - 'color' => COL_ALERTFIRED, - ]; - $module_color_status_unknown = COL_UNKNOWN; - - echo 'var module_color_status = '.json_encode($module_color_status).";\n"; - echo "var module_color_status_unknown = '".$module_color_status_unknown."';\n"; - - echo "\n"; - echo "\n"; - - echo "////////////////////////////////////////////////////////////////////\n"; - echo "// Other vars\n"; - echo "////////////////////////////////////////////////////////////////////\n"; - - echo "var translation_none = '".__('None')."';\n"; - echo "var dialog_node_edit_title = '".__('Edit node %s')."';\n"; - echo "var holding_area_title = '".__('Holding Area')."';\n"; - echo "var edit_menu = '".__('Show details and options')."';\n"; - echo "var interface_link_add = '".__('Add a interface link')."';\n"; - echo "var set_parent_link = '".__('Set parent interface')."';\n"; - echo "var set_as_children_menu = '".__('Set as children')."';\n"; - echo "var set_parent_menu = '".__('Set parent')."';\n"; - echo "var abort_relationship_menu = '".__('Abort the action of set relationship')."';\n"; - echo "var delete_menu = '".__('Delete')."';\n"; - echo "var add_node_menu = '".__('Add node')."';\n"; - echo "var set_center_menu = '".__('Set center')."';\n"; - echo "var refresh_menu = '".__('Refresh')."';\n"; - echo "var refresh_holding_area_menu = '".__('Refresh Holding area')."';\n"; - echo "var ok_button = '".__('Proceed')."';\n"; - echo "var message_to_confirm = '".__('Resetting the map will delete all customizations you have done, including manual relationships between elements, new items, etc.')."';\n"; - echo "var warning_message = '".__('WARNING')."';\n"; - echo "var ok_button = '".__('Proceed')."';\n"; - echo "var cancel_button = '".__('Cancel')."';\n"; - echo "var restart_map_menu = '".__('Restart map')."';\n"; - echo "var abort_relationship_interface = '".__('Abort the interface relationship')."';\n"; - echo "var abort_relationship_menu = '".__('Abort the action of set relationship')."';\n"; - - echo "\n"; - echo "\n"; -} - - -function networkmap_loadfile( - $id=0, - $file='', - &$relations_param, - $graph -) { - global $config; - - $height_map = 200; - if ((int) $id > 0) { - $height_map = db_get_value('height', 'tmap', 'id', $id); - } - - $networkmap_nodes = []; - - $relations = []; - - $other_file = file($file); - - // Remove the graph head - $graph = preg_replace('/^graph .*/', '', $graph); - // Cut in nodes the graph - $graph = explode(']', $graph); - - $ids = []; - foreach ($graph as $node) { - $line = str_replace("\n", ' ', $node); - - if (preg_match('/([0-9]+) \[.*tooltip.*id_module=([0-9]+)/', $line, $match) != 0) { - $ids[$match[1]] = [ - 'type' => 'module', - 'id_module' => $match[2], - ]; - } else if (preg_match('/([0-9]+) \[.*tooltip.*id_agent=([0-9]+)/', $line, $match) != 0) { - $ids[$match[1]] = [ - 'type' => 'agent', - 'id_agent' => $match[2], - ]; - } - } - - foreach ($other_file as $key => $line) { - // clean line a long spaces for one space caracter - $line = preg_replace('/[ ]+/', ' ', $line); - - $data = []; - - if (preg_match('/^node.*$/', $line) != 0) { - $items = explode(' ', $line); - $node_id = $items[1]; - $node_x = ($items[2] * 100); - // 200 is for show more big - $node_y = ($height_map - $items[3] * 100); - // 200 is for show more big - $data['id'] = $node_id; - $data['text'] = ''; - $data['image'] = ''; - $data['width'] = 10; - $data['height'] = 10; - $data['id_agent'] = 0; - - if (preg_match('/<img src=\"([^\"]*)\"/', $line, $match) == 1) { - $image = $match[1]; - - $data['shape'] = 'image'; - $data['image'] = $image; - $size = getimagesize($config['homedir'].'/'.$image); - $data['width'] = $size[0]; - $data['height'] = $size[1]; - - $data['id_agent'] = 0; - $data['id_module'] = 0; - $data['type'] = ''; - $product_name = get_product_name(); - if (preg_match("/$product_name/", $line) != 0) { - $data['text'] = $product_name; - $data['id_agent'] = 0; - } else { - $data['type'] = $ids[$node_id]['type']; - - switch ($ids[$node_id]['type']) { - case 'module': - $data['id_module'] = $ids[$node_id]['id_module']; - $data['id_agent'] = modules_get_agentmodule_agent($ids[$node_id]['id_module']); - - $text = modules_get_agentmodule_name($data['id_module']); - $text = ui_print_truncate_text( - $text, - 'agent_medium', - false, - true, - false, - '...', - false - ); - $data['text'] = $text; - $data['id_agent'] = db_get_value('id_agente', 'tagente_modulo', 'id_agente_modulo', $data['id_module']); - break; - - case 'agent': - $data['id_agent'] = $ids[$node_id]['id_agent']; - - $text = agents_get_alias($ids[$node_id]['id_agent']); - $text = ui_print_truncate_text( - $text, - 'agent_medium', - false, - true, - false, - '...', - false - ); - $data['text'] = $text; - $data['parent'] = db_get_value('id_parent', 'tagente', 'id_agente', $data['id_agent']); - break; - } - } - } else { - $data['shape'] = 'wtf'; - } - - $data['coords'] = [ - $node_x, - $node_y, - ]; - - if (strpos($node_id, 'transp_') !== false) { - // removed the transparent nodes - } else { - $networkmap_nodes[$node_id] = $data; - } - } else if (preg_match('/^edge.*$/', $line) != 0) { - $items = explode(' ', $line); - $line_orig = $items[2]; - $line_dest = $items[1]; - - // $relations[$line_dest] = $line_orig; - $relations[] = [ - 'orig' => $line_orig, - 'dest' => $line_dest, - ]; - } - } - - $relations_param = []; - - foreach ($relations as $rel) { - if (strpos($rel['orig'], 'transp_') !== false) { - // removed the transparent nodes - continue; - } - - if (strpos($rel['dest'], 'transp_') !== false) { - // removed the transparent nodes - continue; - } - - $row = [ - 'id_child' => $rel['orig'], - 'child_type' => $networkmap_nodes[$rel['orig']]['type'], - 'id_parent' => $rel['dest'], - 'parent_type' => $networkmap_nodes[$rel['dest']]['type'], - ]; - $relations_param[] = $row; - } - - return $networkmap_nodes; -} - - -function get_status_color_module_networkmap($id_agente_modulo) -{ - $status = modules_get_agentmodule_status($id_agente_modulo); - - // Set node status - switch ($status) { - case 0: - // At the moment the networkmap enterprise does not show the - // alerts. - case AGENT_MODULE_STATUS_NORMAL_ALERT: - $status_color = COL_NORMAL; - // Normal monitor - break; - - case 1: - $status_color = COL_CRITICAL; - // Critical monitor - break; - - case 2: - $status_color = COL_WARNING; - // Warning monitor - break; - - case 4: - $status_color = COL_ALERTFIRED; - // Alert fired - break; - - default: - $status_color = COL_UNKNOWN; - // Unknown monitor - break; - } - - return $status_color; -} - - -function duplicate_networkmap($id) -{ - $return = true; - - $values = db_get_row('tmap', 'id', $id); - unset($values['id']); - $free_name = false; - $values['name'] = io_safe_input(__('Copy of ')).$values['name']; - $count = 1; - while (!$free_name) { - $exist = db_get_row_filter('tmap', ['name' => $values['name']]); - if ($exist === false) { - $free_name = true; - } else { - $values['name'] = $values['name'].io_safe_input(' '.$count); - } - } - - $correct_or_id = db_process_sql_insert('tmap', $values); - if ($correct_or_id === false) { - $return = false; - } else { - if (enterprise_installed()) { - $new_id = $correct_or_id; - duplicate_map_insert_nodes_and_relations($id, $new_id); - } - } - - if ($return) { - return true; - } else { - // Clean DB. - if (enterprise_installed()) { - // Relations - delete_relations($new_id); - - // Nodes - delete_nodes($new_id); - } - - db_process_sql_delete('tmap', ['id' => $new_id]); - - return false; - } -} - - -function clean_duplicate_links($relations) -{ - if (enterprise_installed()) { - enterprise_include_once('include/functions_pandora_networkmap.php'); - } - - $segregation_links = []; - $index = 0; - $index2 = 0; - $index3 = 0; - $index4 = 0; - foreach ($relations as $rel) { - if (($rel['parent_type'] == 0) && ($rel['child_type'] == 0)) { - $segregation_links['aa'][$index] = $rel; - $index++; - } else if (($rel['parent_type'] == 1) && ($rel['child_type'] == 1)) { - $segregation_links['mm'][$index2] = $rel; - $index2++; - } else if (($rel['parent_type'] == 3) && ($rel['child_type'] == 3)) { - $segregation_links['ff'][$index4] = $rel; - $index4++; - } else { - $segregation_links['am'][$index3] = $rel; - $index3++; - } - } - - $final_links = []; - - // ---------------------------------------------------------------- - // --------------------- Clean duplicate links -------------------- - // ---------------------------------------------------------------- - $duplicated = false; - $index_to_del = 0; - $index = 0; - if (isset($segregation_links['aa']) === true - && is_array($segregation_links['aa']) === true - ) { - foreach ($segregation_links['aa'] as $link) { - foreach ($segregation_links['aa'] as $link2) { - if ($link['id_parent'] == $link2['id_child'] - && $link['id_child'] == $link2['id_parent'] - ) { - if (enterprise_installed()) { - delete_link($segregation_links['aa'][$index_to_del]); - } - - unset($segregation_links['aa'][$index_to_del]); - } - - $index_to_del++; - } - - $final_links['aa'][$index] = $link; - $index++; - - $duplicated = false; - $index_to_del = 0; - } - } - - $duplicated = false; - $index_to_del = 0; - $index2 = 0; - if (isset($segregation_links['mm']) === true - && is_array($segregation_links['mm']) === true - ) { - foreach ($segregation_links['mm'] as $link) { - foreach ($segregation_links['mm'] as $link2) { - if ($link['id_parent'] == $link2['id_child'] - && $link['id_child'] == $link2['id_parent'] - ) { - if (enterprise_installed()) { - delete_link($segregation_links['mm'][$index_to_del]); - } - } - - $index_to_del++; - } - - $final_links['mm'][$index2] = $link; - $index2++; - - $duplicated = false; - $index_to_del = 0; - } - } - - $duplicated = false; - $index_to_del = 0; - $index3 = 0; - - if (isset($segregation_links['ff']) === true - && is_array($segregation_links['ff']) === true - ) { - foreach ($segregation_links['ff'] as $link) { - foreach ($segregation_links['ff'] as $link2) { - if ($link['id_parent'] == $link2['id_child'] - && $link['id_child'] == $link2['id_parent'] - ) { - if (enterprise_installed()) { - delete_link($segregation_links['ff'][$index_to_del]); - } - - unset($segregation_links['ff'][$index_to_del]); - } - - $index_to_del++; - } - - $final_links['ff'][$index3] = $link; - $index3++; - - $duplicated = false; - $index_to_del = 0; - } - } - - $final_links['am'] = $segregation_links['am']; - - /* - ---------------------------------------------------------------- - ----------------- AA, AM and MM links management --------------- - ------------------ Priority: ----------------------------------- - -------------------- 1 -> MM (module - module) ----------------- - -------------------- 2 -> AM (agent - module) ------------------ - -------------------- 3 -> AA (agent - agent) ------------------- - ---------------------------------------------------------------- - */ - - $final_links2 = []; - $index = 0; - $l3_link = []; - $agent1 = 0; - $agent2 = 0; - - if (isset($final_links['mm']) === true - && is_array($final_links['mm']) === true - ) { - foreach ($final_links['mm'] as $rel_mm) { - $module_parent = $rel_mm['id_parent_source_data']; - $module_children = $rel_mm['id_child_source_data']; - $agent1 = (int) agents_get_agent_id_by_module_id($module_parent); - $agent2 = (int) agents_get_agent_id_by_module_id($module_children); - foreach ($final_links['aa'] as $key => $rel_aa) { - $l3_link = $rel_aa; - $id_p_source_data = (int) $rel_aa['id_parent_source_data']; - $id_c_source_data = (int) $rel_aa['id_child_source_data']; - if ((($id_p_source_data == $agent1) - && ($id_c_source_data == $agent2)) - || (($id_p_source_data == $agent2) - && ($id_c_source_data == $agent1)) - ) { - if (enterprise_installed()) { - delete_link($final_links['aa'][$key]); - } - - unset($final_links['aa'][$key]); - } - } - } - } - - $final_links2['aa'] = $final_links['aa']; - $final_links2['mm'] = $final_links['mm']; - $final_links2['am'] = $final_links['am']; - $final_links2['ff'] = $final_links['ff']; - - $same_m = []; - $index = 0; - if (isset($final_links2['am']) === true - && is_array($final_links2['am']) === true - ) { - foreach ($final_links2['am'] as $rel_am) { - foreach ($final_links2['am'] as $rel_am2) { - if (($rel_am['id_child_source_data'] == $rel_am2['id_child_source_data']) - && ($rel_am['id_parent_source_data'] != $rel_am2['id_parent_source_data']) - ) { - $same_m[$index]['rel'] = $rel_am2; - $same_m[$index]['agent_parent'] = $rel_am['id_parent_source_data']; - $index++; - } - } - } - } - - $final_links3 = []; - $index = 0; - $l3_link = []; - $have_l3 = false; - if (isset($final_links2['aa']) === true - && is_array($final_links2['aa']) === true - ) { - foreach ($final_links2['aa'] as $key => $rel_aa) { - $l3_link = $rel_aa; - foreach ($same_m as $rel_am) { - if ((($rel_aa['id_parent_source_data'] == $rel_am['parent']['id_parent_source_data']) - && ($rel_aa['id_child_source_data'] == $rel_am['rel']['id_parent_source_data'])) - || (($rel_aa['id_child_source_data'] == $rel_am['parent']['id_parent_source_data']) - && ($rel_aa['id_parent_source_data'] == $rel_am['rel']['id_parent_source_data'])) - ) { - if (enterprise_installed()) { - delete_link($final_links2['aa'][$key]); - } - - unset($final_links2['aa'][$key]); - } - } - } - } - - $final_links3['aa'] = $final_links2['aa']; - $final_links3['mm'] = $segregation_links['mm']; - $final_links3['am'] = $segregation_links['am']; - $final_links3['ff'] = $final_links2['ff']; - - $cleaned_links = []; - if (isset($final_links3['aa']) === true - && is_array($final_links3['aa']) === true - ) { - foreach ($final_links3['aa'] as $link) { - $cleaned_links[] = $link; - } - } - - if (isset($final_links3['am']) === true - && is_array($final_links3['am']) === true - ) { - foreach ($final_links3['am'] as $link) { - $cleaned_links[] = $link; - } - } - - if (isset($final_links3['mm']) === true - && is_array($final_links3['mm']) === true - ) { - foreach ($final_links3['mm'] as $link) { - $cleaned_links[] = $link; - } - } - - if (isset($final_links3['ff']) === true - && is_array($final_links3['ff']) === true - ) { - foreach ($final_links3['ff'] as $link) { - $cleaned_links[] = $link; - } - } - - return $cleaned_links; -} - - -function is_in_rel_array($relations, $relation) -{ - $is_in_array = false; - foreach ($relations as $rel) { - if ($rel['id_parent_source_data'] == $relation['id_parent_source_data'] - && $rel['id_child_source_data'] == $relation['id_child_source_data'] - ) { - $is_in_array = true; - } - } - - return $is_in_array; -} - - -function map_migrated($id) -{ - $new_maps = db_get_all_rows_sql('SELECT filter FROM tmap'); - $new_map_filter = json_decode($new_maps, true); - - foreach ($new_map_filter as $filter) { - if ((isset($filter['id_migrate_map'])) && ($filter['id_migrate_map'] == $id)) { - return true; - } - } - - return false; -} - - -function migrate_older_open_maps($id) -{ - global $config; - - $old_networkmap = db_get_row_filter( - 'tnetwork_map', - ['id_networkmap' => $id] - ); - - $map_values = []; - $map_values['id_group'] = $old_networkmap['id_group']; - $map_values['id_user'] = $old_networkmap['id_user']; - $map_values['type'] = 0; - $map_values['subtype'] = 0; - $map_values['name'] = $old_networkmap['name']; - - $new_map_filter = []; - $new_map_filter['dont_show_subgroups'] = $old_networkmap['dont_show_subgroups']; - $new_map_filter['node_radius'] = 40; - $new_map_filter['id_migrate_map'] = $id; - $map_values['filter'] = json_encode($new_map_filter); - - $map_values['description'] = 'Mapa open migrado'; - $map_values['width'] = 4000; - $map_values['height'] = 4000; - $map_values['center_x'] = 2000; - $map_values['center_y'] = 2000; - $map_values['background'] = ''; - $map_values['background_options'] = 0; - $map_values['source_period'] = 60; - $map_values['source'] = 0; - $map_values['source_data'] = $old_networkmap['id_group']; - if ($old_networkmap['type'] == 'radial_dinamic') { - $map_values['generation_method'] = 6; - } else { - $map_values['generation_method'] = 4; - } - - $map_values['generated'] = 0; - - $id_new_map = db_process_sql_insert('tmap', $map_values); - - if (!$id_new_map) { - return false; - } - - return true; -} - - -function show_networkmap($id=0, $user_readonly=false, $nodes_and_relations=[], $dashboard_mode=false, $map_dash_details=[]) -{ - global $config; - $clean_relations = clean_duplicate_links($nodes_and_relations['relations']); - - $hide_minimap = ''; - - $nodes_and_relations['relations'] = $clean_relations; - - $networkmap = db_get_row('tmap', 'id', $id); - $networkmap['filter'] = json_decode($networkmap['filter'], true); - - $networkmap['filter']['l2_network_interfaces'] = 1; - - echo '<script type="text/javascript" src="'.$config['homeurl'].'include/javascript/d3.3.5.14.js" charset="utf-8"></script>'; - ui_require_css_file('jquery.contextMenu', 'include/styles/js/'); - echo '<script type="text/javascript" src="'.$config['homeurl'].'include/javascript/jquery.contextMenu.js"></script>'; - echo '<script type="text/javascript" src="'.$config['homeurl'].'include/javascript/functions_pandora_networkmap.js"></script>'; - echo '<div id="networkconsole_'.$networkmap['id'].'" style="position: relative; overflow: hidden; background: #FAFAFA">'; - if ($dashboard_mode) { - $hide_minimap = 'none'; - } - - echo '<div style="display: '.$hide_minimap.';">'; - echo '<canvas id="minimap_'.$networkmap['id'].'" style="position: absolute; left: 0px; top: 0px; border: 1px solid #bbbbbb;"> - </canvas>'; - - echo '<div id="arrow_minimap_'.$networkmap['id'].'" style="position: absolute; left: 0px; top: 0px;"> - <a title="'.__('Open Minimap').'" href="javascript: toggle_minimap();"> - <img id="image_arrow_minimap_'.$networkmap['id'].'" src="images/minimap_open_arrow.png" /> - </a> - </div>'; - echo '</div>'; - - echo '<div id="hide_labels_'.$networkmap['id'].'" style="position: absolute; right: 10px; top: 10px;"> - <a title="'.__('Hide Labels').'" href="javascript: hide_labels();"> - <img id="image_hide_show_labels" src="images/icono_borrar.png" /> - </a> - </div>'; - echo '<div id="holding_spinner_'.$networkmap['id'].'" style="display: none; position: absolute; right: 50px; top: 20px;"> - <img id="image_hide_show_labels" src="images/spinner.gif" /> - </div>'; - - echo '</div>'; - - ?> -<script type="text/javascript"> - <?php - networkmap_write_js_array($id, $nodes_and_relations, $map_dash_details); - ?> - //////////////////////////////////////////////////////////////////////// - // document ready - //////////////////////////////////////////////////////////////////////// - $(document).ready(function() { - init_graph({ - graph: networkmap, - networkmap_center: networkmap_center, - networkmap_dimensions: networkmap_dimensions, - enterprise_installed: enterprise_installed, - node_radius: node_radius, - holding_area_dimensions: networkmap_holding_area_dimensions, - url_background_grid: url_background_grid - }); - init_drag_and_drop(); - init_minimap(); - function_open_minimap(); - - $(document.body).on("mouseleave", - ".context-menu-list", - function(e) { - try { - $("#networkconsole_" + "<?php echo $id; ?>").contextMenu("hide"); - } - catch(err) { - } - } - ); - }); -</script> - <?php - $list_networkmaps = get_networkmaps($id); - if (empty($list_networkmaps)) { - $list_networkmaps = []; - } - ?> - -<div id="open_version_dialog" style="display: none;"> - <?php echo __('In the Open version of %s can not be edited nodes or map', get_product_name()); ?> -</div> - -<div id="dialog_node_edit" style="display: none;" title="<?php echo __('Edit node'); ?>"> - <div style="text-align: left; width: 100%;"> - <?php - $table = new stdClass(); - $table->id = 'node_details'; - $table->width = '100%'; - - $table->data = []; - $table->data[0][0] = '<strong>'.__('Agent').'</strong>'; - $table->data[0][1] = ''; - $table->data[1][0] = '<strong>'.__('Adresses').'</strong>'; - $table->data[1][1] = ''; - $table->data[2][0] = '<strong>'.__('OS type').'</strong>'; - $table->data[2][1] = ''; - $table->data[3][0] = '<strong>'.__('Group').'</strong>'; - $table->data[3][1] = ''; - - ui_toggle( - html_print_table($table, true), - __('Node Details'), - __('Node Details'), - false - ); - - $table = new stdClass(); - $table->id = 'interface_information'; - $table->width = '100%'; - - $table->head['interface_name'] = __('Name'); - $table->head['interface_status'] = __('Status'); - $table->head['interface_graph'] = __('Graph'); - $table->head['interface_ip'] = __('Ip'); - $table->head['interface_mac'] = __('MAC'); - $table->data = []; - $table->rowstyle['template_row'] = 'display: none;'; - $table->data['template_row']['interface_name'] = ''; - $table->data['template_row']['interface_status'] = ''; - $table->data['template_row']['interface_graph'] = ''; - $table->data['template_row']['interface_ip'] = ''; - $table->data['template_row']['interface_mac'] = ''; - - ui_toggle( - html_print_table($table, true), - __('Interface Information (SNMP)'), - __('Interface Information (SNMP)'), - true - ); - - $table = new stdClass(); - $table->id = 'node_options'; - $table->width = '100%'; - - $table->data = []; - $table->data[0][0] = __('Shape'); - $table->data[0][1] = html_print_select( - [ - 'circle' => __('Circle'), - 'square' => __('Square'), - 'rhombus' => __('Rhombus'), - ], - 'shape', - '', - 'javascript:', - '', - 0, - true - ); - $table->data[0][1] .= ' <span id="shape_icon_in_progress" style="display: none;">'; - $table->data[0][1] .= html_print_image( - 'images/spinner.gif', - true - ); - $table->data[0][1] .= '</span><span id="shape_icon_correct" style="display: none;">'; - $table->data[0][1] .= html_print_image( - 'images/dot_green.png', - true - ); - $table->data[0][1] .= '</span><span id="shape_icon_fail" style="display: none;">'; - $table->data[0][1] .= html_print_image( - 'images/dot_red.png', - true - ); - $table->data[0][1] .= '</span>'; - - $table->data['node_name'][0] = __('Name'); - $table->data['node_name'][1] = html_print_input_text( - 'edit_name_node', - '', - __('name node'), - '20', - '50', - true - ); - $table->data['node_name'][2] = html_print_button( - __('Update node'), - '', - false, - '', - 'class="sub"', - true - ); - - $table->data['fictional_node_name'][0] = __('Name'); - $table->data['fictional_node_name'][1] = html_print_input_text( - 'edit_name_fictional_node', - '', - __('name fictional node'), - '20', - '50', - true - ); - $table->data['fictional_node_networkmap_link'][0] = __('Networkmap to link'); - $table->data['fictional_node_networkmap_link'][1] = html_print_select( - $list_networkmaps, - 'edit_networkmap_to_link', - '', - '', - '', - 0, - true - ); - $table->data['fictional_node_update_button'][0] = ''; - $table->data['fictional_node_update_button'][1] = html_print_button( - __('Update fictional node'), - '', - false, - 'add_fictional_node();', - 'class="sub"', - true - ); - - ui_toggle( - html_print_table($table, true), - __('Node options'), - __('Node options'), - true - ); - - $table = new stdClass(); - $table->id = 'relations_table'; - $table->width = '100%'; - - $table->head = []; - $table->head['node_source'] = __('Node source'); - $table->head['interface_source'] = __('Interface source'); - $table->head['interface_target'] = __('Interface Target'); - - $table->head['node_target'] = __('Node target'); - $table->head['edit'] = '<span title="'.__('Edit').'">'.__('E.').'</span>'; - - $table->data = []; - $table->rowstyle['template_row'] = 'display: none;'; - $table->data['template_row']['node_source'] = ''; - $table->data['template_row']['interface_source'] = html_print_select( - [], - 'interface_source', - '', - '', - __('None'), - 0, - true - ); - $table->data['template_row']['interface_target'] = html_print_select( - [], - 'interface_target', - '', - '', - __('None'), - 0, - true - ); - - $table->data['template_row']['node_target'] = ''; - $table->data['template_row']['edit'] = ''; - - $table->data['template_row']['edit'] .= '<span class="edit_icon_correct" style="display: none;">'.html_print_image('images/dot_green.png', true).'</span>'.'<span class="edit_icon_fail" style="display: none;">'.html_print_image('images/dot_red.png', true).'</span>'.'<span class="edit_icon_progress" style="display: none;">'.html_print_image('images/spinner.gif', true).'</span>'.'<span class="edit_icon"><a class="edit_icon_link" title="'.__('Update').'" href="#">'.html_print_image('images/config.png', true).'</a></span>'; - - $table->data['template_row']['edit'] .= '<a class="delete_icon" href="#">'.html_print_image('images/delete.png', true).'</a>'; - - $table->colspan['no_relations']['0'] = 5; - $table->cellstyle['no_relations']['0'] = 'text-align: center;'; - $table->data['no_relations']['0'] = __('There are not relations'); - - $table->colspan['loading']['0'] = 5; - $table->cellstyle['loading']['0'] = 'text-align: center;'; - $table->data['loading']['0'] = html_print_image( - 'images/wait.gif', - true - ); - - ui_toggle( - html_print_table($table, true), - __('Relations'), - __('Relations'), - true - ); - ?> - </div> -</div> - -<div id="dialog_interface_link" style="display: none;" title="Interface link"> - <div style="text-align: left; width: 100%;"> - <?php - $table = new stdClass(); - $table->id = 'interface_link_table'; - $table->width = '100%'; - $table->head['node_source_interface'] = __('Node source'); - $table->head['interface_source_select'] = __('Interface source'); - $table->head['interface_target_select'] = __('Interface Target'); - $table->head['node_target_interface'] = __('Node target'); - - $table->data = []; - - $table->data['interface_row']['node_source_interface'] = html_print_label('', 'node_source_interface'); - - $table->data['interface_row']['interface_source_select'] = html_print_select( - [], - 'interface_source_select', - '', - '', - __('None'), - 0 - ); - - $table->data['interface_row']['interface_target_select'] = html_print_select( - [], - 'interface_target_select', - '', - '', - __('None'), - 0 - ); - - $table->data['interface_row']['node_target_interface'] = html_print_label('', 'node_target_interface'); - ?> - <br><br> - <?php - $table->data['interface_row']['interface_link_button'] = html_print_button( - __('Add interface link'), - '', - false, - 'add_interface_link_js();', - 'class="sub"' - ); - - html_print_table($table, true) - ?> - </div> -</div> - -<div id="dialog_node_add" style="display: none;" title="<?php echo __('Add node'); ?>"> - <div style="text-align: left; width: 100%;"> - <?php - $table = new stdClass(); - $table->width = '100%'; - $table->data = []; - - $table->data[0][0] = __('Agent'); - $params = []; - $params['return'] = true; - $params['show_helptip'] = true; - $params['input_name'] = 'agent_name'; - $params['input_id'] = 'agent_name'; - $params['print_hidden_input_idagent'] = true; - $params['hidden_input_idagent_name'] = 'id_agent'; - $params['disabled_javascript_on_blur_function'] = true; - $table->data[0][1] = ui_print_agent_autocomplete_input($params); - $table->data[1][0] = ''; - $table->data[1][1] = html_print_button( - __('Add agent node'), - '', - false, - 'add_agent_node();', - 'class="sub"', - true - ).html_print_image( - 'images/error_red.png', - true, - [ - 'id' => 'error_red', - 'style' => 'vertical-align: bottom;display: none;', - 'class' => 'forced_title', - 'alt' => 'Esto es una prueba', - 'data-title' => 'data-use_title_for_force_title:1', - ], - false - ); - - $add_agent_node_html = html_print_table($table, true); - ui_toggle( - $add_agent_node_html, - __('Add agent node'), - __('Add agent node'), - false - ); - - $table = new stdClass(); - $table->width = '100%'; - $table->data = []; - $table->data[0][0] = __('Group'); - $table->data[0][1] = html_print_select_groups( - false, - 'IW', - false, - 'group_for_show_agents', - -1, - 'choose_group_for_show_agents()', - __('None'), - -1, - true - ); - $table->data[1][0] = __('Agents'); - $table->data[1][1] = html_print_select( - [-1 => __('None')], - 'agents_filter_group', - -1, - '', - '', - 0, - true, - true, - true, - '', - false, - 'width: 170px;', - false, - 5 - ); - $table->data[2][0] = ''; - $table->data[2][1] = html_print_button( - __('Add agent node'), - '', - false, - 'add_agent_node_from_the_filter_group();', - 'class="sub"', - true - ); - - $add_agent_node_html = html_print_table($table, true); - ui_toggle( - $add_agent_node_html, - __('Add agent node (filter by group)'), - __('Add agent node'), - true - ); - - $table = new stdClass(); - $table->width = '100%'; - $table->data = []; - $table->data[0][0] = __('Name'); - $table->data[0][1] = html_print_input_text( - 'name_fictional_node', - '', - __('name fictional node'), - '20', - '50', - true - ); - $table->data[1][0] = __('Networkmap to link'); - $table->data[1][1] = html_print_select( - $list_networkmaps, - 'networkmap_to_link', - '', - '', - '', - 0, - true - ); - $table->data[2][0] = ''; - $table->data[2][1] = html_print_button( - __('Add fictional node'), - '', - false, - 'add_fictional_node();', - 'class="sub"', - true - ); - $add_agent_node_html = html_print_table($table, true); - ui_toggle( - $add_agent_node_html, - __('Add fictional point'), - __('Add agent node'), - true - ); - ?> - </div> -</div> - <?php -} +// Deprecated. diff --git a/pandora_console/operation/agentes/pandora_networkmap.php b/pandora_console/operation/agentes/pandora_networkmap.php index 43c4c907b0..a18475030c 100644 --- a/pandora_console/operation/agentes/pandora_networkmap.php +++ b/pandora_console/operation/agentes/pandora_networkmap.php @@ -30,7 +30,6 @@ if (!$networkmaps_read && !$networkmaps_write && !$networkmaps_manage) { } require_once 'include/functions_networkmap.php'; -require_once 'include/functions_pandora_networkmap.php'; $new_networkmap = (bool) get_parameter('new_networkmap', false); $save_networkmap = (bool) get_parameter('save_networkmap', false); diff --git a/pandora_console/operation/agentes/pandora_networkmap.view.php b/pandora_console/operation/agentes/pandora_networkmap.view.php index 7a6cbccb14..a2786713ff 100644 --- a/pandora_console/operation/agentes/pandora_networkmap.view.php +++ b/pandora_console/operation/agentes/pandora_networkmap.view.php @@ -29,7 +29,7 @@ global $config; -require_once 'include/functions_pandora_networkmap.php'; +require_once 'include/functions_networkmap.php'; enterprise_include_once('include/functions_policies.php'); enterprise_include_once('include/functions_dashboard.php'); require_once 'include/functions_modules.php'; @@ -866,13 +866,6 @@ if ($networkmap === false) { ); } - /* - $nodes_and_relations = networkmap_process_networkmap($id); - - show_networkmap($id, $user_readonly, $nodes_and_relations, $dash_mode, $map_dash_details); - */ - - include_once $config['homedir'].'/include/class/NetworkMap.class.php'; $map_manager = new NetworkMap( From f5b0e6b1a4708000a4d7f6efbe44e34d325317fc Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Wed, 13 Mar 2019 12:55:24 +0100 Subject: [PATCH 43/50] minor fix radial redirection Former-commit-id: 0676ff2eb51a7ea281eb1410b1e5c4082c39d074 --- pandora_console/operation/agentes/networkmap.dinamic.php | 6 +++--- pandora_console/operation/agentes/pandora_networkmap.php | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pandora_console/operation/agentes/networkmap.dinamic.php b/pandora_console/operation/agentes/networkmap.dinamic.php index ae4b696aba..dd075647bb 100644 --- a/pandora_console/operation/agentes/networkmap.dinamic.php +++ b/pandora_console/operation/agentes/networkmap.dinamic.php @@ -504,9 +504,9 @@ function create_loading_tooltip(d, x, y) { } function show_tooltip(d) { - x = d3.event.clientX + 10; - y = d3.event.clientY + 10; - + x = d3.event.clientX 100; + y = d3.event.clientY 100; + if (d.default_tooltip) { create_loading_tooltip(d, x, y); diff --git a/pandora_console/operation/agentes/pandora_networkmap.php b/pandora_console/operation/agentes/pandora_networkmap.php index a18475030c..b9f67e5bb0 100644 --- a/pandora_console/operation/agentes/pandora_networkmap.php +++ b/pandora_console/operation/agentes/pandora_networkmap.php @@ -357,12 +357,12 @@ if ($new_networkmap || $save_networkmap) { if ($result !== false) { $tab = 'view'; - if ($values['generation_method'] == 6) { + if ($values['generation_method'] == LAYOUT_RADIAL_DYNAMIC) { $tab = 'r_dinamic'; define('_activeTab_', 'radial_dynamic'); $url = 'index.php?sec=network&sec2=operation/agentes/networkmap.dinamic&activeTab=radial_dynamic'; header( - 'Location'.ui_get_full_url( + 'Location: '.ui_get_full_url( $url.'&id_networkmap='.$id ) ); From f4290e52feff67250f57f09d05ddcf17c7cf2b0d Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Wed, 13 Mar 2019 15:55:24 +0100 Subject: [PATCH 44/50] Minor fix notif. ball margins Former-commit-id: 36705558ac7b2ef94115068acb0bce01662b8ecc --- pandora_console/include/styles/pandora.css | 1 + 1 file changed, 1 insertion(+) diff --git a/pandora_console/include/styles/pandora.css b/pandora_console/include/styles/pandora.css index 1e4aeda96f..a5e6adc603 100644 --- a/pandora_console/include/styles/pandora.css +++ b/pandora_console/include/styles/pandora.css @@ -4415,6 +4415,7 @@ div#header_discovery { width: 9px; font-weight: bold; color: #fff; + margin-right: 15px; } div#header_discovery:hover { From 99b1aadacb2871349483ff8c73dc684725d95ac8 Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Thu, 14 Mar 2019 17:21:16 +0100 Subject: [PATCH 45/50] discovery icon set Former-commit-id: d88ba9c57d7a4c590e7a6965b2a4a9f7fd473790 --- pandora_console/images/gm_discovery.menu.png | Bin 342 -> 339 bytes .../images/gm_discovery.menu_white.png | Bin 272 -> 263 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/pandora_console/images/gm_discovery.menu.png b/pandora_console/images/gm_discovery.menu.png index b33975dcec719f434f446a95a1419e1f2975effd..5c0296b562ef41406521a93cde11a57d101d4d2a 100644 GIT binary patch delta 275 zcmV+u0qp+P0@DJJNq_Z8L_t(|+G1cJ0Ol-NCIG|%gw!!H5C-#scs<ZC1F{VQYIXop zFxT``;-Y#awgc2)(hP!Xa=>FS(Jsn|(v3hI2*e+tu2LY{AW%#ph0TJLn5Ydv`T?2+ zM7bydiM=0a@O~f-i?sk!4Dv@}E1-py0=A^Ugu`171Y*;H7=ITz5Rpjji808Y2!lv= z5h%74fw9I2qJj7TR9pZ(oLI0J1XGX*G++Tt5Xc5aza!9q`OsJesk?yHMMzm-0<s}! zpb(m-6!3WsBzXa7NFlDk0m^|=cp`dOVl$|aP)Gv}JAjnZv4+tGprQ*5#DR&(9Do1= Z0HU2lvnE7yjSK()002ovPDHLkV1knOZB+mO delta 278 zcmV+x0qOqJ0@ebMNq_iBL_t(|+G1cJ0?b*mOo5OZCL#^l52Ot!G6)Fzff!`ida?}y zy21fS1wgq9Kz;(bE~<ypAJF*38w3p-2Pk&~Ay+XG;TjN_h{X0M)gV~dd`O9jx&Wjv zz{Ig72PPce0vRFz<sN`~=Kzut2Xs9wI9%h8rYQg^z+v(Wh=1`KvW)_0G*%Ze;fO6l zSwaAs#_+lb-L?l%ZyZ1qHy{*7_DJkTV2m{&xz+%hRTQA=Cg5`s%%((SLqGtU3>={W zuRzFaAcGbFH7&pvI6!fbR|C<##)KBo2GB4m#23;)!$9G+0Xe|YT_gYvmk&e~FNMfS c0wBNuiIhm4j1RG7>;M1&07*qoM6N<$f^J=Eb^rhX diff --git a/pandora_console/images/gm_discovery.menu_white.png b/pandora_console/images/gm_discovery.menu_white.png index d05d5e761672650352fc998ca20b209ae449391b..80d0913c905b2e474ea9d96de156272828456e41 100644 GIT binary patch delta 198 zcmV;%06G7V0*3;SNq?zHL_t(|+G1cJ0RI2~F95^=43q+(A?yD`fB_|jIQ&O|{gfEA z|34~lpwu<wy9z068bE;!#P6Ye1yT$VKyrlwRO~#I-%pA`1xN<nM+>X_lms$5Fd)@i zxIh6h1_cmd(0XDF>L<dW_rw@<9@%E3SW`d?I|D)n!9W5I`9Jyi<k3@eKY_>qC5Z-n z1|@*JMr8Kck554Zu^AKOMSPM5BqUlCwEzJI0OW9??za%lssI2007*qoM6N<$f~|y3 A^8f$< delta 207 zcmV;=05JcD0+0fbNq@3QL_t(|+G1cJ0{s8~Ux9&A05SxK?*p*`r3S744*~ZnF~s3N zDo7yLp#4w--jnSrXxPBOe6n4Irr7|Ay`EHqVBUET<)23~3?n%(;V>isNC`l>2cX_L zfTYBM9B;ixqlxz(Gy&oR?@5g<e87QF7@_<B0T3@h3nLIPAV?*A8qnknki5N~kU{71 zB|NCtK>>fBkU`*-OiUicrvT=30U}EU2YfaqkdPMxV0?f80|05UYOOWYCt3gi002ov JPDHLkV1k{iRcHVJ From 8c8f368993afab467f216dd592ed9c0658834ce7 Mon Sep 17 00:00:00 2001 From: fbsanchez <fborja.sanchez@artica.es> Date: Thu, 14 Mar 2019 18:51:48 +0100 Subject: [PATCH 46/50] WIP: NetworkMaps rebuild Former-commit-id: d3ca9d0de1b718a35bbc4aae80982b2c4705a454 --- pandora_console/godmode/wizards/Wizard.main.php | 15 ++++++++------- .../include/class/NetworkMap.class.php | 8 ++------ pandora_console/include/constants.php | 15 +++++++++++++++ pandora_console/include/functions_networkmap.php | 10 ++++++++++ pandora_console/include/functions_servers.php | 3 +++ .../operation/agentes/pandora_networkmap.php | 2 ++ 6 files changed, 40 insertions(+), 13 deletions(-) diff --git a/pandora_console/godmode/wizards/Wizard.main.php b/pandora_console/godmode/wizards/Wizard.main.php index 5fc95e7a01..7a1a5916aa 100644 --- a/pandora_console/godmode/wizards/Wizard.main.php +++ b/pandora_console/godmode/wizards/Wizard.main.php @@ -26,14 +26,15 @@ * ============================================================================ */ -define('CLOUDWIZARD_AWS_DESCRIPTION', 'Discovery.Cloud.AWS.EC2'); +// Begin. -/** - * Global Wizard generic class. Needs to be inherited. - * - * Used in Hostdevices class, Applications class and others, is the core of - * Discovery proyect. - */ + + /** + * Global Wizard generic class. Needs to be inherited. + * + * Used in Hostdevices class, Applications class and others, is the core of + * Discovery proyect. + */ class Wizard { diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php index 3adf1b44b5..8f153eb415 100644 --- a/pandora_console/include/class/NetworkMap.class.php +++ b/pandora_console/include/class/NetworkMap.class.php @@ -32,10 +32,6 @@ global $config; require_once $config['homedir'].'/include/functions_networkmap.php'; enterprise_include_once('include/functions_networkmap.php'); -define('SOURCE_GROUP', 0); -define('SOURCE_TASK', 1); -define('SOURCE_NETWORK', 2); - /** * Manage networkmaps in Pandora FMS */ @@ -217,7 +213,7 @@ class NetworkMap $this->loadMap(); if (empty($this->nodes) - || empty($this->relations) + && empty($this->relations) ) { $this->createMap(); } @@ -423,7 +419,7 @@ class NetworkMap $relations = $this->relations; // Generate if there's no data in DB about nodes or relations. - if (empty($nodes) || empty($relations)) { + if (empty($nodes) && empty($relations)) { $this->generateNetworkMap(); return; } diff --git a/pandora_console/include/constants.php b/pandora_console/include/constants.php index 699264b17a..a82d36c1d0 100644 --- a/pandora_console/include/constants.php +++ b/pandora_console/include/constants.php @@ -548,13 +548,28 @@ define('LAYOUT_SPRING2', 4); // Extra: radial dynamic. define('LAYOUT_RADIAL_DYNAMIC', 6); +// Map sources. +define('SOURCE_GROUP', 0); +define('SOURCE_TASK', 1); +define('SOURCE_NETWORK', 2); +// Backward compatibility ~ Migration. define('MAP_SOURCE_GROUP', 0); define('MAP_SOURCE_IP_MASK', 1); define('NETWORKMAP_DEFAULT_WIDTH', 800); define('NETWORKMAP_DEFAULT_HEIGHT', 800); +// Discovery task types. +define('DISCOVERY_HOSTDEVICES', 0); +define('DISCOVERY_HOSTDEVICES_CUSTOM', 1); +define('DISCOVERY_CLOUD_AWS', 10); +define('DISCOVERY_APP_VMWARE', 100); + +// Discovery task descriptions. +define('CLOUDWIZARD_AWS_DESCRIPTION', 'Discovery.Cloud.AWS.EC2'); +define('CLOUDWIZARD_VMWARE_DESCRIPTION', 'Discovery.App.VMware'); + // Background options. define('CENTER', 0); define('MOSAIC', 1); diff --git a/pandora_console/include/functions_networkmap.php b/pandora_console/include/functions_networkmap.php index 28fa630f0a..fba71431bd 100644 --- a/pandora_console/include/functions_networkmap.php +++ b/pandora_console/include/functions_networkmap.php @@ -305,6 +305,16 @@ function networkmap_generate_dot( $filter[] = '(nombre COLLATE utf8_general_ci LIKE "%'.$text_filter.'%")'; } + /* + * Select data origin. + * group + * discovery task + * - Cloud + * - Application + * - Standar or custom + * network/mask + */ + if ($group >= 0 && empty($ip_mask)) { if ($dont_show_subgroups) { $filter['id_grupo'] = $group; diff --git a/pandora_console/include/functions_servers.php b/pandora_console/include/functions_servers.php index 0d8b581f5a..0850dcbfac 100644 --- a/pandora_console/include/functions_servers.php +++ b/pandora_console/include/functions_servers.php @@ -1041,6 +1041,9 @@ function servers_get_server_string_name(int $server) case SERVER_TYPE_WUX: return __('WUX server'); + case SERVER_TYPE_ENTERPRISE_SATELLITE: + return __('Satellite'); + default: return __('N/A'); } diff --git a/pandora_console/operation/agentes/pandora_networkmap.php b/pandora_console/operation/agentes/pandora_networkmap.php index b9f67e5bb0..cca936a396 100644 --- a/pandora_console/operation/agentes/pandora_networkmap.php +++ b/pandora_console/operation/agentes/pandora_networkmap.php @@ -732,6 +732,8 @@ switch ($tab) { if (($count == 0) && ($network_map['source'] != 'empty')) { if ($network_map['generated']) { $data['nodes'] = __('Empty map'); + } else if ($network_map['generation_method'] == LAYOUT_RADIAL_DYNAMIC) { + $data['nodes'] = __('Dynamic'); } else { $data['nodes'] = __('Pending to generate'); } From 0593e72f3e214429013433c2169a2d9d31b50a6e Mon Sep 17 00:00:00 2001 From: Daniel Barbero <daniel.barbero@artica.es> Date: Fri, 15 Mar 2019 09:11:18 +0100 Subject: [PATCH 47/50] move custom net scan and script to OPEN Former-commit-id: ad30ba98670d23ff895b95beb9f58d1105473e3d --- .../godmode/wizards/HostDevices.class.php | 57 +- .../images/wizard/customnetscan.png | Bin 0 -> 2477 bytes .../images/wizard/managenetscanscripts.png | Bin 0 -> 2174 bytes .../include/class/CustomNetScan.class.php | 758 +++++++++++++++++ .../class/ManageNetScanScripts.class.php | 759 ++++++++++++++++++ 5 files changed, 1546 insertions(+), 28 deletions(-) create mode 100644 pandora_console/images/wizard/customnetscan.png create mode 100644 pandora_console/images/wizard/managenetscanscripts.png create mode 100644 pandora_console/include/class/CustomNetScan.class.php create mode 100644 pandora_console/include/class/ManageNetScanScripts.class.php diff --git a/pandora_console/godmode/wizards/HostDevices.class.php b/pandora_console/godmode/wizards/HostDevices.class.php index ef383e8233..f0e8325459 100755 --- a/pandora_console/godmode/wizards/HostDevices.class.php +++ b/pandora_console/godmode/wizards/HostDevices.class.php @@ -28,9 +28,10 @@ require_once __DIR__.'/Wizard.main.php'; require_once $config['homedir'].'/include/functions_users.php'; +require_once $config['homedir'].'/include/class/CustomNetScan.class.php'; +require_once $config['homedir'].'/include/class/ManageNetScanScripts.class.php'; + enterprise_include_once('include/class/CSVImportAgents.class.php'); -enterprise_include_once('include/class/CustomNetScan.class.php'); -enterprise_include_once('include/class/ManageNetScanScripts.class.php'); enterprise_include_once('include/functions_hostdevices.php'); /** @@ -126,20 +127,20 @@ class HostDevices extends Wizard 'icon' => ENTERPRISE_DIR.'/images/wizard/csv.png', 'label' => __('Import CSV'), ]; - - $buttons[] = [ - 'url' => $this->url.'&mode=customnetscan', - 'icon' => ENTERPRISE_DIR.'/images/wizard/customnetscan.png', - 'label' => __('Custom NetScan'), - ]; - - $buttons[] = [ - 'url' => $this->url.'&mode=managenetscanscripts', - 'icon' => ENTERPRISE_DIR.'/images/wizard/managenetscanscripts.png', - 'label' => __('Manage NetScan scripts'), - ]; } + $buttons[] = [ + 'url' => $this->url.'&mode=customnetscan', + 'icon' => '/images/wizard/customnetscan.png', + 'label' => __('Custom NetScan'), + ]; + + $buttons[] = [ + 'url' => $this->url.'&mode=managenetscanscripts', + 'icon' => '/images/wizard/managenetscanscripts.png', + 'label' => __('Manage NetScan scripts'), + ]; + $this->prepareBreadcrum( [ [ @@ -165,22 +166,22 @@ class HostDevices extends Wizard ); return $csv_importer->runCSV(); } + } - if ($mode === 'customnetscan') { - $customnetscan_importer = new CustomNetScan( - $this->page, - $this->breadcrum - ); - return $customnetscan_importer->runCustomNetScan(); - } + if ($mode === 'customnetscan') { + $customnetscan_importer = new CustomNetScan( + $this->page, + $this->breadcrum + ); + return $customnetscan_importer->runCustomNetScan(); + } - if ($mode === 'managenetscanscripts') { - $managenetscanscript_importer = new ManageNetScanScripts( - $this->page, - $this->breadcrum - ); - return $managenetscanscript_importer->runManageNetScanScript(); - } + if ($mode === 'managenetscanscripts') { + $managenetscanscript_importer = new ManageNetScanScripts( + $this->page, + $this->breadcrum + ); + return $managenetscanscript_importer->runManageNetScanScript(); } if ($mode == 'netscan') { diff --git a/pandora_console/images/wizard/customnetscan.png b/pandora_console/images/wizard/customnetscan.png new file mode 100644 index 0000000000000000000000000000000000000000..edc036fa39248eb7aecd2b9d10fbc3aa9f5bc938 GIT binary patch literal 2477 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 literal 0 HcmV?d00001 diff --git a/pandora_console/images/wizard/managenetscanscripts.png b/pandora_console/images/wizard/managenetscanscripts.png new file mode 100644 index 0000000000000000000000000000000000000000..4694ec1e7ada5a4abcedeae45027b289328b5914 GIT binary patch literal 2174 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 AH2?qr literal 0 HcmV?d00001 diff --git a/pandora_console/include/class/CustomNetScan.class.php b/pandora_console/include/class/CustomNetScan.class.php new file mode 100644 index 0000000000..a0f8af019d --- /dev/null +++ b/pandora_console/include/class/CustomNetScan.class.php @@ -0,0 +1,758 @@ +<?php +/** + * Extension to schedule tasks on Pandora FMS Console + * + * @category Wizard + * @package Pandora FMS + * @subpackage Host&Devices + * @version 1.0.0 + * @license See below + * + * ______ ___ _______ _______ ________ + * | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __| + * | __/| _ | | _ || _ | _| _ | | ___| |__ | + * |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| + * + * ============================================================================ + * Copyright (c) 2005-2019 Artica Soluciones Tecnologicas + * Please see http://pandorafms.org for full contribution list + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation for version 2. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ============================================================================ + */ + +require_once $config['homedir'].'/godmode/wizards/Wizard.main.php'; + +/** + * CustomNetScan. Host and devices child class. + */ +class CustomNetScan extends Wizard +{ + + /** + * Number of pages to control breadcrum. + * + * @var integer + */ + public $MAXPAGES = 2; + + /** + * Labels for breadcrum. + * + * @var array + */ + public $pageLabels = [ + 'Netscan Custom definition', + 'Netscan Custom script', + ]; + + + /** + * Constructor. + * + * @param integer $page Page. + * @param array $breadcrum Breadcrum. + * + * @return void + */ + public function __construct(int $page, array $breadcrum) + { + $this->url = ui_get_full_url( + 'index.php?sec=gservers&sec2=godmode/servers/discovery&wiz=hd' + ); + $this->page = $page; + $this->breadcrum = $breadcrum; + } + + + /** + * Retrieves and validates information given by user in NetScan wizard. + * + * @return boolean Data OK or not. + */ + public function parseNetScan() + { + if (isset($this->page) === true && $this->page === 0) { + // Check if we're updating a task. + $task_id = get_parameter('task', null); + + if (isset($task_id) === true) { + // We're updating this task. + $task = db_get_row( + 'trecon_task', + 'id_rt', + $task_id + ); + + if ($task !== false) { + $this->task = $task; + } + } + + return true; + } + + // Validate response from page 0. No, not a bug, we're always 1 page + // from 'validation' page. + if (isset($this->page) === true && $this->page === 1) { + $task_id = get_parameter('task', null); + $taskname = get_parameter('taskname', ''); + $comment = get_parameter('comment', ''); + $server_id = get_parameter('id_recon_server', ''); + $id_group = get_parameter('id_group', ''); + $interval = get_parameter('interval', 0); + + if (isset($task_id) === true) { + // We're updating this task. + $task = db_get_row( + 'trecon_task', + 'id_rt', + $task_id + ); + + if ($task !== false) { + $this->task = $task; + } + } else if (isset($taskname) === true) { + // Avoid double creation. + $task = db_get_row_filter( + 'trecon_task', + ['name' => $taskname] + ); + + if ($task !== false) { + $this->task = $task; + $this->msg = __('This task has been already defined. Please edit it or create a new one.'); + return false; + } + } + + if ($task_id !== null + && $taskname == null + && $server_id == null + && $id_group == null + && $server == null + && $datacenter == '' + && $user == '' + && $pass == '' + && $encrypt == null + && $interval == 0 + ) { + // Default values, no data received. + // User is accesing directly to this page. + if (users_is_admin() !== true && check_acl( + $config['id_usuario'], + $this->task['id_group'], + 'PM' + ) !== true + ) { + $this->msg = __('You have no access to edit this task.'); + return false; + } + } else { + if (isset($this->task['id_rt']) === false) { + // Disabled 2 Implies wizard non finished. + $this->task['disabled'] = 2; + } + + if ($taskname == '') { + $this->msg = __('You must provide a task name.'); + return false; + } + + if ($server_id == '') { + $this->msg = __('You must select a Discovery Server.'); + return false; + } + + if ($id_group == '') { + $this->msg = __('You must select a valid group.'); + return false; + } + + // Assign fields. + $this->task['name'] = $taskname; + $this->task['description'] = $comment; + $this->task['id_recon_server'] = $server_id; + $this->task['id_group'] = $id_group; + $this->task['interval_sweep'] = $interval; + + if (isset($this->task['id_rt']) === false) { + // Create. + $this->task['id_rt'] = db_process_sql_insert( + 'trecon_task', + $this->task + ); + } else { + // Update. + db_process_sql_update( + 'trecon_task', + $this->task, + ['id_rt' => $this->task['id_rt']] + ); + } + } + + return true; + } + + // Validate response from page 1. + if ($this->page == 2) { + $id_rt = get_parameter('task', -1); + + $task = db_get_row( + 'trecon_task', + 'id_rt', + $id_rt + ); + + if ($task !== false) { + $this->task = $task; + } else { + $this->msg = __('Failed to find network scan task.'); + return false; + } + + $id_recon_script = get_parameter('id_recon_script', null); + $field1 = get_parameter('_field1_', ''); + $field2 = get_parameter('_field2_', ''); + $field3 = get_parameter('_field3_', ''); + $field4 = get_parameter('_field4_', ''); + + // Get macros. + $macros = get_parameter('macros', null); + + if (empty($macros) === false) { + $macros = json_decode( + base64_decode($macros), + true + ); + + foreach ($macros as $k => $m) { + $macros[$k]['value'] = get_parameter($m['macro'], ''); + } + } + + $this->task['id_recon_script'] = $id_recon_script; + $this->task['macros'] = io_json_mb_encode($macros); + $this->task['field1'] = $field1; + $this->task['field2'] = $field2; + $this->task['field3'] = $field3; + $this->task['field4'] = $field4; + + if ($this->task['disabled'] == 2) { + // Wizard finished. + $this->task['disabled'] = 0; + } + + // Update. + $res = db_process_sql_update( + 'trecon_task', + $this->task, + ['id_rt' => $this->task['id_rt']] + ); + + return true; + } + + return false; + } + + + /** + * Run function. It will be call into HostsDevices class. + * Page 0: Upload form. + * Page 1: Task resume. + * + * @return void + */ + public function runCustomNetScan() + { + global $config; + + if (!check_acl($config['id_user'], 0, 'PM')) { + db_pandora_audit( + 'ACL Violation', + 'Trying to access Custom Net Scan.' + ); + include 'general/noaccess.php'; + return; + } + + if ($this->parseNetScan() === false) { + // Error. + ui_print_error_message( + $this->msg + ); + + $form = [ + 'form' => [ + 'method' => 'POST', + 'action' => $this->url.'&mode=customnetscan&page='.($this->page - 1).'&task='.$this->task['id_rt'], + ], + 'inputs' => [ + [ + 'arguments' => [ + 'type' => 'hidden', + 'name' => 'task', + 'value' => $this->task['id_rt'], + ], + ], + [ + 'arguments' => [ + 'name' => 'submit', + 'label' => __('Go back'), + 'type' => 'submit', + 'attributes' => 'class="sub cancel"', + 'return' => true, + ], + ], + ], + ]; + + // Check ACL. If user is not able to manage target task, + // redirect him to main page. + if (users_is_admin() !== true && check_acl( + $config['id_usuario'], + $this->task['id_group'], + 'PM' + ) !== true + ) { + $form['form']['action'] = $this->url.'&mode=customnetscan&page='.($this->page - 1); + } + + $this->printForm($form); + return null; + } + + $run_url = 'index.php?sec=gservers&sec2=godmode/servers/discovery'; + + $task_url = ''; + if (isset($this->task['id_rt']) === true) { + $task_url = '&task='.$this->task['id_rt']; + } + + $breadcrum[] = [ + 'link' => $run_url.'&wiz=hd', + 'label' => __('Host & Devices'), + ]; + + for ($i = 0; $i < $this->MAXPAGES; $i++) { + $breadcrum[] = [ + 'link' => $run_url.'&wiz=hd&mode=customnetscan&page='.$i.$task_url, + 'label' => __($this->pageLabels[$i]), + 'selected' => (($i == $this->page) ? 1 : 0), + ]; + } + + if ($this->page < $this->MAXPAGES) { + // Avoid to print header out of wizard. + $this->prepareBreadcrum($breadcrum); + $this->printHeader(); + } + + $task_url = ''; + if (isset($this->task['id_rt'])) { + $task_url = '&task='.$this->task['id_rt']; + } + + $breadcrum[] = [ + 'link' => $run_url.'&wiz=hd', + 'label' => __($this->label), + ]; + for ($i = 0; $i < $this->maxPagesNetScan; $i++) { + $breadcrum[] = [ + 'link' => $run_url.'&wiz=hd&mode=customnetscan&page='.$i.$task_url, + 'label' => $this->pageLabelsNetScan[$i], + 'selected' => (($i == $this->page) ? 1 : 0), + ]; + } + + if ($this->page < $this->maxPagesNetScan) { + // Avoid to print header out of wizard. + $this->prepareBreadcrum($breadcrum); + $this->printHeader(); + } + + if (isset($this->page) === true + && $this->page !== 0 + && isset($this->task['id_rt']) === false + ) { + // Error. + ui_print_error_message( + __('Internal error, please re-run this wizard.') + ); + + $form = [ + 'form' => [ + 'method' => 'POST', + 'action' => $this->url.'&mode=customnetscan&page=0', + ], + 'inputs' => [ + [ + 'arguments' => [ + 'type' => 'hidden', + 'name' => 'page', + 'value' => 0, + ], + ], + [ + 'arguments' => [ + 'name' => 'submit', + 'label' => __('Go back'), + 'type' => 'submit', + 'attributes' => 'class="sub cancel"', + 'return' => true, + ], + ], + ], + ]; + + $this->printForm($form); + return null; + } + + // -------------------------------. + // Page 0. wizard starts HERE. + // -------------------------------. + if (isset($this->page) === true || $this->page == 0) { + if (isset($this->page) === false + || $this->page == 0 + ) { + $form = []; + + // Input task name. + $form['inputs'][] = [ + 'label' => '<b>'.__('Task name').'</b>', + 'arguments' => [ + 'name' => 'taskname', + 'value' => $this->task['name'], + 'type' => 'text', + 'size' => 25, + ], + ]; + + if (isset($this->task['id_rt']) === true) { + // Propagate id. + $form['inputs'][] = [ + 'arguments' => [ + 'name' => 'task', + 'value' => $this->task['id_rt'], + 'type' => 'hidden', + ], + ]; + } + + // Input task description. + $form['inputs'][] = [ + 'label' => '<b>'.__('Comment').'</b>', + 'arguments' => [ + 'name' => 'comment', + 'value' => $this->task['description'], + 'type' => 'text', + 'size' => 25, + ], + ]; + + // Input Discovery Server. + $form['inputs'][] = [ + 'label' => '<b>'.__('Discovery server').'</b>'.ui_print_help_tip( + __('You must select a Discovery Server to run the Task, otherwise the Recon Task will never run'), + true + ), + 'arguments' => [ + 'type' => 'select_from_sql', + 'sql' => sprintf( + 'SELECT id_server, name + FROM tserver + WHERE server_type = %d + ORDER BY name', + SERVER_TYPE_DISCOVERY + ), + 'name' => 'id_recon_server', + 'selected' => $this->task['id_recon_server'], + 'return' => true, + ], + ]; + + // Input Group. + $form['inputs'][] = [ + 'label' => '<b>'.__('Group').'</b>', + 'arguments' => [ + 'name' => 'id_group', + 'returnAllGroup' => false, + 'privilege' => 'PM', + 'type' => 'select_groups', + 'selected' => $this->task['id_group'], + 'return' => true, + ], + ]; + + // Interval and schedules. + $interv_manual = 0; + if ((int) $this->task['interval_sweep'] == 0) { + $interv_manual = 1; + } + + // Schedule. + $form['inputs'][] = [ + 'label' => '<b>'.__('Interval').'</b>'.ui_print_help_tip( + __('Manual interval means that it will be executed only On-demand'), + true + ), + 'arguments' => [ + 'type' => 'select', + 'selected' => $interv_manual, + 'fields' => [ + 0 => __('Defined'), + 1 => __('Manual'), + ], + 'name' => 'interval_manual_defined', + 'return' => true, + ], + 'extra' => '<span id="interval_manual_container">'.html_print_extended_select_for_time( + 'interval', + $this->task['interval_sweep'], + '', + '', + '0', + false, + true, + false, + false + ).ui_print_help_tip( + __('The minimum recomended interval for Recon Task is 5 minutes'), + true + ).'</span>', + ]; + + $str = __('Next'); + + if (isset($this->task['id_rt']) === true) { + $str = __('Update and continue'); + } + + // Submit button. + $form['inputs'][] = [ + 'arguments' => [ + 'name' => 'submit', + 'label' => $str, + 'type' => 'submit', + 'attributes' => 'class="sub next"', + 'return' => true, + ], + ]; + + $task_url = ''; + if (isset($this->task['id_rt'])) { + $task_url = '&task='.$this->task['id_rt']; + } + + $form['form'] = [ + 'method' => 'POST', + 'action' => $this->url.'&mode=customnetscan&page='.($this->page + 1).$task_url, + ]; + + // Default. + $interval = 600; + $unit = 60; + if (isset($this->task['interval_sweep']) === true) { + $interval = $this->task['interval_sweep']; + $unit = $this->getTimeUnit($interval); + } + + $form['js'] = ' + $("select#interval_manual_defined").change(function() { + if ($("#interval_manual_defined").val() == 1) { + $("#interval_manual_container").hide(); + $("#text-interval_text").val(0); + $("#hidden-interval").val(0); + } + else { + $("#interval_manual_container").show(); + $("#text-interval_text").val(10); + $("#hidden-interval").val('.$interval.'); + $("#interval_units").val('.$unit.'); + } + }).change(); + '; + + // XXX: Could be improved validating inputs before continue (JS) + // Print NetScan page 0. + $this->printForm($form); + } + } + + if (isset($this->page) === true && $this->page === 1) { + $name_ipam = 'IPAM Recon'; + // Recon script. + $form['inputs'][] = [ + 'label' => '<b>'.__('Recon script').'</b>', + 'arguments' => [ + 'type' => 'select_from_sql', + 'sql' => sprintf( + 'SELECT id_recon_script, name FROM trecon_script WHERE name <> "%s" ORDER BY name', + $name_ipam + ), + 'name' => 'id_recon_script', + 'selected' => $this->task['id_recon_script'], + 'return' => true, + ], + ]; + + $form['inputs'][] = [ + 'hidden' => 1, + 'arguments' => [ + 'type' => 'hidden', + 'name' => 'task', + 'value' => $this->task['id_rt'], + ], + ]; + + $form['inputs'][] = [ + 'hidden' => 1, + 'arguments' => [ + 'type' => 'hidden_extended', + 'name' => 'macros', + 'value' => base64_encode($this->task['macros']), + 'return' => true, + ], + ]; + + // Explanation. + $explanation = db_get_value( + 'description', + 'trecon_script', + 'id_recon_script', + $this->task['id_recon_script'] + ); + + $form['inputs'][] = [ + 'label' => '<b>'.__('Explanation').'</b><span id="spinner_recon_script" style="display: none;">'.html_print_image('images/spinner.gif', true).'</span>', + 'arguments' => [ + 'type' => 'textarea', + 'rows' => 4, + 'columns' => 60, + 'name' => 'explanation', + 'value' => $explanation, + 'return' => true, + 'attributes' => 'style="width: 388px;"', + ], + ]; + + $form['inputs'][] = [ + 'hidden' => 1, + 'id' => 'table_recon-macro_field', + 'label' => '<b>'.__('macro_desc').'</b>'.ui_print_help_tip('macro_help', true), + 'arguments' => [ + 'name' => 'macro_name', + 'value' => 'macro_value', + 'type' => 'text', + 'size' => 100, + 'return' => true, + ], + ]; + + if (empty($this->task['macros']) === false) { + $macros = json_decode($this->task['macros'], true); + foreach ($macros as $k => $m) { + $label_macro = ''; + $label_macro .= '<b>'.$m['desc'].'</b>'; + if (!empty($m['help'])) { + $label_macro .= ui_print_help_tip( + $m['help'], + true + ); + } + + if ($m['hide']) { + $form['inputs'][] = [ + 'label' => $label_macro, + 'id' => 'table_recon-macro'.$m['macro'], + 'class' => 'macro_field', + 'arguments' => [ + 'name' => $m['macro'], + 'value' => $m['value'], + 'type' => 'password', + 'size' => 100, + 'return' => true, + ], + ]; + } else { + $form['inputs'][] = [ + 'label' => $label_macro, + 'id' => 'table_recon-macro'.$m['macro'], + 'class' => 'macro_field', + 'arguments' => [ + 'name' => $m['macro'], + 'value' => $m['value'], + 'type' => 'text', + 'size' => 100, + 'return' => true, + ], + ]; + } + } + } + + // Submit button. + $form['inputs'][] = [ + 'arguments' => [ + 'name' => 'submit', + 'label' => __('Finish'), + 'type' => 'submit', + 'attributes' => 'class="sub next"', + 'return' => true, + ], + ]; + + $form['form'] = [ + 'method' => 'POST', + 'action' => $this->url.'&mode=customnetscan&page='.($this->page + 1).'&task='.$this->task['id_rt'], + ]; + + $id_task = (isset($this->task['id_rt']) === true) ? $this->task['id_rt'] : 0; + + $url_ajax = $config['homeurl'].'ajax.php'; + + $change = ''; + if (empty($this->task['macros']) !== false) { + $change = '.change();'; + } + + $form['js'] = ' + $("select#id_recon_script").change(function() { + get_explanation_recon_script($(this).val(), "'.$id_task.'", "'.$url_ajax.'"); + })'.$change; + + $this->printForm($form); + } + + if (isset($this->page) === true && $this->page === 2) { + if ($this->task['id_rt']) { + // 0 - Is OK. + $this->result = 0; + $this->msg = __('Task configured.'); + } else { + // 1 - Is NOT OK. + $this->result = 1; + $this->msg = __('Wizard failed. Cannot configure task.'); + } + + return [ + 'result' => $this->result, + 'id' => $this->task['id_rt'], + 'msg' => $this->msg, + ]; + } + + ui_require_javascript_file('pandora_modules'); + } + + +} diff --git a/pandora_console/include/class/ManageNetScanScripts.class.php b/pandora_console/include/class/ManageNetScanScripts.class.php new file mode 100644 index 0000000000..377259478a --- /dev/null +++ b/pandora_console/include/class/ManageNetScanScripts.class.php @@ -0,0 +1,759 @@ +<?php +/** + * Extension to schedule tasks on Pandora FMS Console + * + * @category Wizard + * @package Pandora FMS + * @subpackage Host&Devices + * @version 1.0.0 + * @license See below + * + * ______ ___ _______ _______ ________ + * | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __| + * | __/| _ | | _ || _ | _| _ | | ___| |__ | + * |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______| + * + * ============================================================================ + * Copyright (c) 2005-2019 Artica Soluciones Tecnologicas + * Please see http://pandorafms.org for full contribution list + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation for version 2. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ============================================================================ + */ + +require_once $config['homedir'].'/godmode/wizards/Wizard.main.php'; + +/** + * ManageNetScanScripts. Host and devices child class. + */ +class ManageNetScanScripts extends Wizard +{ + + /** + * Number of pages to control breadcrum. + * + * @var integer + */ + public $MAXPAGES = 2; + + /** + * Labels for breadcrum. + * + * @var array + */ + public $pageLabels = [ + 'List net scan scripts', + 'Operation net scan cripts', + ]; + + + /** + * Constructor. + * + * @param integer $page Page. + * @param array $breadcrum Breadcrum. + * + * @return void + */ + public function __construct(int $page, array $breadcrum) + { + $this->url = ui_get_full_url( + 'index.php?sec=gservers&sec2=godmode/servers/discovery&wiz=hd' + ); + $this->page = $page; + $this->breadcrum = $breadcrum; + } + + + /** + * Run function. It will be call into HostsDevices class. + * Page 0: Upload form. + * Page 1: Task resume. + * + * @return void + */ + public function runManageNetScanScript() + { + global $config; + + if (check_acl($config['id_user'], 0, 'AW') === 0) { + db_pandora_audit( + 'ACL Violation', + 'Trying to access Net Scan Script.' + ); + include 'general/noaccess.php'; + return; + } + + $run_url = 'index.php?sec=gservers&sec2=godmode/servers/discovery'; + + $breadcrum[] = [ + 'link' => $run_url.'&wiz=hd', + 'label' => __('Host & Devices'), + ]; + + for ($i = 0; $i < $this->MAXPAGES; $i++) { + $breadcrum[] = [ + 'link' => $run_url.'&wiz=hd&mode=managenetscanscripts&page='.$i, + 'label' => __($this->pageLabels[$i]), + 'selected' => (($i == $this->page) ? 1 : 0), + ]; + } + + if ($this->page < $this->MAXPAGES) { + // Avoid to print header out of wizard. + $this->prepareBreadcrum($breadcrum); + $this->printHeader(); + } + + $id_script = get_parameter('id_script', 0); + + // Initialize msg. + $msg = []; + + // Operations. + $operation_scp = get_parameter('operation_scp', ''); + if ($operation_scp !== '') { + switch ($operation_scp) { + case 'update_scp': + $msg = $this->updateScanScripts($id_script); + break; + + case 'delete_scp': + $msg = $this->deleteScanScripts($id_script); + break; + + case 'create_scp': + $msg = $this->createScanScripts($id_script); + break; + + default: + // Nothing for doing. Never exist other operation. + break; + } + } + + if (!isset($this->page) || $this->page === 0) { + $this->printListNetScanScripts($msg); + } + + if (!isset($this->page) || $this->page === 1) { + $this->printFormScanScripts($id_script); + } + } + + + /** + * Create net scan script. + * + * @return array Check msg successfully or problem + */ + private function createScanScripts() + { + $result = []; + + $reconscript_name = get_parameter('form_name', ''); + $reconscript_description = get_parameter('form_description', ''); + $reconscript_script = get_parameter('form_script', ''); + + // Get macros. + $i = 1; + $macros = []; + while (1) { + $macro = (string) get_parameter('field'.$i.'_macro'); + if ($macro == '') { + break; + } + + $desc = (string) get_parameter('field'.$i.'_desc'); + $help = (string) get_parameter('field'.$i.'_help'); + $value = (string) get_parameter('field'.$i.'_value'); + $hide = get_parameter('field'.$i.'_hide'); + + $macros[$i]['macro'] = $macro; + $macros[$i]['desc'] = $desc; + $macros[$i]['help'] = $help; + $macros[$i]['value'] = $value; + $macros[$i]['hide'] = $hide; + $i++; + } + + $macros = io_json_mb_encode($macros); + + $values = [ + 'name' => $reconscript_name, + 'description' => $reconscript_description, + 'script' => $reconscript_script, + 'macros' => $macros, + ]; + + $result_crt = false; + if ($values['name'] !== '' && $values['script'] !== '') { + $result_crt = db_process_sql_insert('trecon_script', $values); + if (!$result_crt) { + $result = [ + 'error' => 1, + 'msg' => __('Problem creating'), + ]; + } else { + $result = [ + 'error' => 0, + 'msg' => __('Created successfully'), + ]; + } + } else { + $result = [ + 'error' => 1, + 'msg' => __('Name or Script fullpath they can not be empty'), + ]; + } + + return $result; + } + + + /** + * Update net scan script. + * + * @param integer $id_script Id script. + * + * @return array Check msg successfully or problem + */ + private function updateScanScripts(int $id_script) + { + $result = []; + if (isset($id_script) === false || $id_script === 0) { + $result = [ + 'error' => 1, + 'msg' => __('Problem deleting Net scan Scripts, Not selected script'), + ]; + + return $result; + } + + // If modified any parameter. + $reconscript_name = get_parameter('form_name', ''); + $reconscript_description = get_parameter('form_description', ''); + $reconscript_script = get_parameter('form_script', ''); + + // Get macros. + $i = 1; + $macros = []; + while (1) { + $macro = (string) get_parameter('field'.$i.'_macro'); + if ($macro == '') { + break; + } + + $desc = (string) get_parameter('field'.$i.'_desc'); + $help = (string) get_parameter('field'.$i.'_help'); + $value = (string) get_parameter('field'.$i.'_value'); + $hide = get_parameter('field'.$i.'_hide'); + + $macros[$i]['macro'] = $macro; + $macros[$i]['desc'] = $desc; + $macros[$i]['help'] = $help; + $macros[$i]['value'] = $value; + $macros[$i]['hide'] = $hide; + $i++; + } + + $macros = io_json_mb_encode($macros); + + $sql_update = sprintf( + "UPDATE trecon_script SET + name = '%s', + description = '%s', + script = '%s', + macros = '%s' + WHERE id_recon_script = %d", + $reconscript_name, + $reconscript_description, + $reconscript_script, + $macros, + $id_script + ); + + $result_upd = false; + if ($reconscript_name !== '' && $reconscript_script !== '') { + $result_upd = db_process_sql($sql_update); + if (!$result_upd) { + $result = [ + 'error' => 1, + 'msg' => __('Problem updating'), + ]; + } else { + $result = [ + 'error' => 0, + 'msg' => __('Updated successfully'), + ]; + } + } else { + $result = [ + 'error' => 1, + 'msg' => __('Name or Script fullpath they can not be empty'), + ]; + } + + return $result; + } + + + /** + * Delete net scan script. + * + * @param integer $id_script Id script. + * + * @return array Check msg successfully or problem + */ + private function deleteScanScripts(int $id_script) + { + $result = []; + if (isset($id_script) === false || $id_script === 0) { + $result = [ + 'error' => 1, + 'msg' => __('Problem deleting Net scan Scripts, Not selected script'), + ]; + + return $result; + } + + $result_dlt = db_process_sql_delete( + 'trecon_script', + ['id_recon_script' => $id_script] + ); + + if (!$result_dlt) { + $result = [ + 'error' => 1, + 'msg' => __('Problem deleting Net scan Scripts'), + ]; + } else { + $result_dlt2 = db_process_sql_delete( + 'trecon_task', + ['id_recon_script' => $id_script] + ); + + if (!$result_dlt2) { + $result = [ + 'error' => 1, + 'msg' => __('Problem deleting Net scan Scripts'), + ]; + } else { + $result = [ + 'error' => 0, + 'msg' => __('Deleted successfully'), + ]; + } + } + + return $result; + + } + + + /** + * Print list Net scan scripts and messages operations. + * + * @param array $msg Print msg if necessary. + * + * @return void + */ + private function printListNetScanScripts(array $msg) + { + if (count($msg) > 0) { + if ($msg['error'] === 1) { + ui_print_error_message($msg['msg']); + } else { + ui_print_success_message($msg['msg']); + } + } + + $url = 'index.php?sec=gservers&sec2=godmode/servers/discovery'; + $url .= '&wiz=hd&mode=managenetscanscripts'; + + // List available Net scan scripts. + $rows = db_get_all_rows_in_table('trecon_script'); + + if ($rows !== false) { + echo '<table width="100%" cellspacing="4" cellpadding="4" class="databox data">'; + echo '<th>'.__('Name').'</th>'; + echo '<th>'.__('Description').'</th>'; + echo '<th>'.__('Delete').'</th>'; + $color = 0; + foreach ($rows as $row) { + if ($color == 1) { + $tdcolor = 'datos'; + $color = 0; + } else { + $tdcolor = 'datos2'; + $color = 1; + } + + echo '<tr>'; + echo "<td class='".$tdcolor."' style='min-width: 100px;'>"; + echo '<b><a href="'.$url.'&page=1&id_script='.$row['id_recon_script'].'">'; + echo $row['name']; + echo '</a></b></td>'; + echo "</td><td class='".$tdcolor."'>"; + $desc = io_safe_output( + $row['description'] + ); + + $desc = str_replace( + "\n", + '<br>', + $desc + ); + + echo $desc.'<br><br>'; + echo '<b>'.__('Command').': </b><i>'.$row['script'].'</i>'; + echo "</td><td align='center' class='".$tdcolor."'>"; + // Delete. + echo '<form + method="post" + onsubmit="if (! confirm (\''.__('Are you sure delete script?').'\')) return false" + style="display: inline;">'; + echo html_print_input_hidden('page', 0, true); + echo html_print_input_hidden( + 'operation_scp', + 'delete_scp', + true + ); + echo html_print_input_hidden( + 'id_script', + $row['id_recon_script'], + true + ); + echo html_print_input_image( + 'delete', + 'images/cross.png', + 1, + '', + true, + [ + 'title' => __('Delete Script'), + ] + ); + echo '</form>'; + echo '</td></tr>'; + } + + echo '</table>'; + + echo "<form name=reconscript method='post' action='".$url."'>"; + echo html_print_input_hidden('page', 1, true); + echo "<input name='crtbutton' style='float:right;' type='submit' class='sub next' value='".__('Add')."'>"; + echo '</form>'; + } else { + ui_print_info_message( + [ + 'no_close' => true, + 'message' => __( + 'There are no net scan scripts in the system' + ), + ] + ); + } + } + + + /** + * Print form net scan scripts. + * + * @param integer $id_script Id script. + * + * @return void + */ + private function printFormScanScripts(int $id_script) + { + // Initialize vars. + if ($id_script !== 0) { + $form_id = $id_script; + $reconscript = db_get_row( + 'trecon_script', + 'id_recon_script', + $form_id + ); + $form_name = $reconscript['name']; + $form_description = $reconscript['description']; + $form_script = $reconscript['script']; + $macros = $reconscript['macros']; + } else { + $form_name = ''; + $form_description = ''; + $form_script = ''; + $macros = ''; + } + + $url = 'index.php?sec=gservers&sec2=godmode/servers/discovery'; + $url .= '&wiz=hd&mode=managenetscanscripts'; + + if ($id_script !== 0) { + echo '<form name=reconscript method="post" action="'.$url.'&id_script='.$id_script.'">'; + echo html_print_input_hidden('page', 0, true); + echo html_print_input_hidden( + 'operation_scp', + 'update_scp', + true + ); + } else { + echo '<form name=reconscript method="post" action="'.$url.'">'; + echo html_print_input_hidden('page', 0, true); + echo html_print_input_hidden( + 'operation_scp', + 'create_scp', + true + ); + } + + $table = new stdClass(); + $table->width = '100%'; + $table->id = 'table-form'; + $table->class = 'databox filters'; + $table->style = []; + $table->style[0] = 'font-weight: bold'; + $table->style[2] = 'font-weight: bold'; + $table->data = []; + + $data = []; + $data[0] = __('Name'); + $data[0] .= ui_print_help_icon( + 'reconscript_definition', + true, + '', + 'images/help_w.png' + ); + + $data[1] = '<input type="text" name="form_name" size=30 value="'.$form_name.'">'; + $table->data['recon_name'] = $data; + $table->colspan['recon_name'][1] = 3; + + $data = []; + $data[0] = __('Script fullpath'); + $data[1] = '<input type="text" name="form_script" size=70 value="'.$form_script.'">'; + $table->data['recon_fullpath'] = $data; + $table->colspan['recon_fullpath'][1] = 3; + + $data = []; + $data[0] = __('Description'); + $data[1] = '<textarea name="form_description" cols="50" rows="4">'; + $data[1] .= $form_description; + $data[1] .= '</textarea>'; + $table->data['recon_description'] = $data; + $table->colspan['recon_description'][1] = 3; + + $macros = json_decode($macros, true); + + // This code is ready to add locked feature as plugins. + $locked = false; + + // The next row number is recon_3. + $next_name_number = 3; + $i = 1; + while (1) { + // Always print at least one macro. + if ((!isset($macros[$i]) || $macros[$i]['desc'] == '') && $i > 1) { + break; + } + + $macro_desc_name = 'field'.$i.'_desc'; + $macro_desc_value = ''; + $macro_help_name = 'field'.$i.'_help'; + $macro_help_value = ''; + $macro_value_name = 'field'.$i.'_value'; + $macro_value_value = ''; + $macro_name_name = 'field'.$i.'_macro'; + $macro_name = '_field'.$i.'_'; + $macro_hide_value_name = 'field'.$i.'_hide'; + $macro_hide_value_value = 0; + + if (isset($macros[$i]['desc'])) { + $macro_desc_value = $macros[$i]['desc']; + } + + if (isset($macros[$i]['help'])) { + $macro_help_value = $macros[$i]['help']; + } + + if (isset($macros[$i]['value'])) { + $macro_value_value = $macros[$i]['value']; + } + + if (isset($macros[$i]['hide'])) { + $macro_hide_value_value = $macros[$i]['hide']; + } + + $datam = []; + $datam[0] = __('Description'); + $datam[0] .= "<span style='font-weight: normal'> ( "; + $datam[0] .= $macro_name; + $datam[0] .= ' )</span>'; + $datam[0] .= html_print_input_hidden( + $macro_name_name, + $macro_name, + true + ); + $datam[1] = html_print_input_text_extended( + $macro_desc_name, + $macro_desc_value, + 'text-'.$macro_desc_name, + '', + 30, + 255, + $locked, + '', + "class='command_advanced_conf'", + true + ); + if ($locked) { + $datam[1] .= html_print_image( + 'images/lock.png', + true, + ['class' => 'command_advanced_conf'] + ); + } + + $datam[2] = __('Default value'); + $datam[2] .= "<span style='font-weight: normal'> ( "; + $datam[2] .= $macro_name; + $datam[2] .= ' ) </span>'; + $datam[3] = html_print_input_text_extended( + $macro_value_name, + $macro_value_value, + 'text-'.$macro_value_name, + '', + 30, + 255, + $locked, + '', + "class='command_component command_advanced_conf'", + true + ); + if ($locked) { + $datam[3] .= html_print_image( + 'images/lock.png', + true, + ['class' => 'command_advanced_conf'] + ); + } + + $table->data['recon_'.$next_name_number] = $datam; + + $next_name_number++; + + $table->colspan['recon_'.$next_name_number][1] = 3; + + $datam = []; + $datam[0] = __('Hide value'); + $datam[0] .= ui_print_help_tip( + __('This field will show up as dots like a password'), + true + ); + + $datam[1] = html_print_checkbox_extended( + $macro_hide_value_name, + 1, + $macro_hide_value_value, + 0, + '', + ['class' => 'command_advanced_conf'], + true, + 'checkbox-'.$macro_hide_value_name + ); + + $table->data['recon_'.$next_name_number] = $datam; + $next_name_number++; + + $table->colspan['recon_'.$next_name_number][1] = 3; + + $datam = []; + $datam[0] = __('Help'); + $datam[0] .= "<span style='font-weight: normal'> ( "; + $datam[0] .= $macro_name; + $datam[0] .= ' )</span><br><br><br>'; + + $tadisabled = ($locked === true) ? ' disabled' : ''; + + $datam[1] = html_print_textarea( + $macro_help_name, + 6, + 100, + $macro_help_value, + 'class="command_advanced_conf" style="width: 97%;"'.$tadisabled, + true + ); + + if ($locked) { + $datam[1] .= html_print_image( + 'images/lock.png', + true, + ['class' => 'command_advanced_conf'] + ); + } + + $datam[1] .= '<br><br><br>'; + + $table->data['recon_'.$next_name_number] = $datam; + $next_name_number++; + $i++; + } + + if (!$locked) { + $datam = []; + $datam[0] = '<span style="font-weight: bold">'; + $datam[0] .= __('Add macro').'</span>'; + $datam[0] .= '<a href="javascript:new_macro(\'table-form-recon_\');update_preview();">'; + $datam[0] .= html_print_image( + 'images/add.png', + true + ); + $datam[0] .= '</a>'; + $datam[0] .= '<div id="next_macro" style="display:none">'; + $datam[0] .= $i.'</div>'; + $datam[0] .= '<div id="next_row" style="display:none">'; + $datam[0] .= $next_name_number.'</div>'; + + $delete_macro_style = ''; + if ($i <= 2) { + $delete_macro_style = 'display:none;'; + } + + $datam[2] = '<div id="delete_macro_button" style="'.$delete_macro_style.'">'; + $datam[2] .= __('Delete macro'); + $datam[2] .= '<a href="javascript:delete_macro_form(\'table-form-recon_\');update_preview();">'; + $datam[2] .= html_print_image( + 'images/delete.png', + true + ); + $datam[2] .= '</a></div>'; + + $table->colspan['recon_action'][0] = 2; + $table->rowstyle['recon_action'] = 'text-align:center'; + $table->colspan['recon_action'][2] = 2; + $table->data['recon_action'] = $datam; + } + + html_print_table($table); + + echo '<table width=100%>'; + echo '<tr><td align="right">'; + + if ($id_script === 0) { + echo "<input name='crtbutton' type='submit' class='sub wand' value='".__('Create')."'>"; + } else { + echo "<input name='uptbutton' type='submit' class='sub upd' value='".__('Update')."'>"; + } + + echo '</form></table>'; + + ui_require_javascript_file('pandora_modules'); + } + + +} From 7e345035e1baa0f860856a02018f30c0db355785 Mon Sep 17 00:00:00 2001 From: Daniel Barbero <daniel.barbero@artica.es> Date: Fri, 15 Mar 2019 10:22:55 +0100 Subject: [PATCH 48/50] add height and round border in d3 graph progress Former-commit-id: 8eacfe068c1ae744fd04a752f65ed44f747d6158 --- .../include/ajax/task_list.ajax.php | 20 ++++++++++--- .../include/graphs/functions_d3.php | 29 ++++++++++++++++--- pandora_console/include/graphs/pandora.d3.js | 18 +++++++----- 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/pandora_console/include/ajax/task_list.ajax.php b/pandora_console/include/ajax/task_list.ajax.php index ec5066c7f8..d6bf652d21 100644 --- a/pandora_console/include/ajax/task_list.ajax.php +++ b/pandora_console/include/ajax/task_list.ajax.php @@ -43,9 +43,15 @@ if ($progress_task_discovery) { $id_task, 90, 460, - 50, - '#EA5434' + 30, + '#EA5434', + '%', + '', + '#FFFFFF', + 0, + 0 ); + $result .= '</li>'; $result .= '<li><h1>'.__('Searching devices in').' red a scanear</h1></li>'; $result .= '<li>'; @@ -53,9 +59,15 @@ if ($progress_task_discovery) { $id_task.'_2', 30, 460, - 50, - '#2751E1' + 30, + '#2751E1', + '%', + '', + '#FFFFFF', + 0, + 0 ); + $result .= '</li>'; $result .= '<li><h1>'.__('Summary').'</h1></li>'; $result .= '<li><span><b>'.__('Estimated').'</b>: total de host</span></li>'; diff --git a/pandora_console/include/graphs/functions_d3.php b/pandora_console/include/graphs/functions_d3.php index 3bd3224445..cc8ffea667 100644 --- a/pandora_console/include/graphs/functions_d3.php +++ b/pandora_console/include/graphs/functions_d3.php @@ -354,8 +354,18 @@ function ux_console_phases_donut($phases, $id, $return=false) } -function d3_progress_bar($id, $percentile, $width, $height, $color, $unit='%', $text='', $fill_color='#FFFFFF') -{ +function d3_progress_bar( + $id, + $percentile, + $width, + $height, + $color, + $unit='%', + $text='', + $fill_color='#FFFFFF', + $radiusx=10, + $radiusy=10 +) { global $config; $recipient_name = 'progress_bar_'.$id; @@ -366,8 +376,19 @@ function d3_progress_bar($id, $percentile, $width, $height, $color, $unit='%', $ $output .= '<div id='.$recipient_name." style='overflow: hidden;'></div>"; $output .= include_javascript_d3(true); $output .= "<script language=\"javascript\" type=\"text/javascript\"> - progress_bar_d3('".$recipient_name_to_js."', ".(int) $percentile.', '.(int) $width.', '.(int) $height.", '".$color."', '".$unit."', '".$text."', '".$fill_color."'); - </script>"; + progress_bar_d3( + '".$recipient_name_to_js."', + ".(int) $percentile.', + '.(int) $width.', + '.(int) $height.", + '".$color."', + '".$unit."', + '".$text."', + '".$fill_color."', + ".(int) $radiusx.', + '.(int) $radiusy.', + ); + </script>'; return $output; } diff --git a/pandora_console/include/graphs/pandora.d3.js b/pandora_console/include/graphs/pandora.d3.js index 40dcd34ac1..5501d92f6f 100644 --- a/pandora_console/include/graphs/pandora.d3.js +++ b/pandora_console/include/graphs/pandora.d3.js @@ -1782,7 +1782,9 @@ function progress_bar_d3( color, unit, label, - label_color + label_color, + radiusx, + radiusy ) { var startPercent = 0; var endPercent = parseInt(percentile) / 100; @@ -1799,20 +1801,20 @@ function progress_bar_d3( .append("rect") .attr("fill", "#000000") .attr("fill-opacity", 0.5) - .attr("height", 20) + .attr("height", height) .attr("width", width) - .attr("rx", 10) - .attr("ry", 10) + .attr("rx", radiusx) + .attr("ry", radiusy) .attr("x", 0); var progress_front = circle .append("rect") .attr("fill", color) .attr("fill-opacity", 1) - .attr("height", 20) + .attr("height", height) .attr("width", 0) - .attr("rx", 10) - .attr("ry", 10) + .attr("rx", radiusx) + .attr("ry", radiusy) .attr("x", 0); var labelText = circle @@ -1834,7 +1836,7 @@ function progress_bar_d3( .style("font-weight", "bold") .style("font-size", 14) .attr("text-anchor", "middle") - .attr("dy", "-10"); + .attr("dy", (height - height / 2) / 4); function updateProgress(bar_progress) { var percent_value = Number(bar_progress * 100); From 8a7702e054933170b28b75f4aec8c20e914d4f0d Mon Sep 17 00:00:00 2001 From: Daniel Maya <daniel.maya@artica.es> Date: Mon, 18 Mar 2019 09:01:53 +0100 Subject: [PATCH 49/50] Update networkmap class with simple map Former-commit-id: cb6bd489ba973cf0f9c6eda8dee062518f33f382 --- .../include/class/NetworkMap.class.php | 991 ++++++++++-------- 1 file changed, 550 insertions(+), 441 deletions(-) diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php index 8f153eb415..ffc8450aca 100644 --- a/pandora_console/include/class/NetworkMap.class.php +++ b/pandora_console/include/class/NetworkMap.class.php @@ -117,6 +117,16 @@ class NetworkMap */ public $mapOptions; + /** + * loadfile function array + * file path + * function name + * extra parameter(cluster) + * + * @var array + */ + public $loadfile; + /** * Base constructor. @@ -154,6 +164,15 @@ class NetworkMap $this->mapOptions['strict_user'] = false; $this->mapOptions['size_canvas'] = null; $this->mapOptions['old_mode'] = false; + $this->mapOptions['baseurl'] = ui_get_full_url(false, false, false, false); + $this->mapOptions['width'] = '100%'; + $this->mapOptions['height'] = 600; + $this->mapOptions['node_radius'] = 40; + $this->mapOptions['id_cluster'] = null; + $this->mapOptions['tooltip'] = false; + $this->mapOptions['size_image'] = 40; + $this->mapOptions['page_tooltip'] = null; + $this->mapOptions['map_filter'] = [ 'dont_show_subgroups' => 0, 'node_radius' => 40, @@ -206,6 +225,14 @@ class NetworkMap } } + // loadfile options + // This is only used while generating simple maps + if (is_array($options['loadfile'])) { + foreach ($options['loadfile'] as $k => $v) { + $this->loadfile[$k] = $v; + } + } + // Load from tmap. if ($options['id_map']) { $this->idMap = $options['id_map']; @@ -482,35 +509,51 @@ class NetworkMap public function generateDotGraph() { if (!isset($this->dotGraph)) { - // Generate dot file. - $this->dotGraph = networkmap_generate_dot( - get_product_name(), - $this->idGroup, - $this->mapOptions['simple'], - $this->mapOptions['font_size'], - $this->mapOptions['layout'], - $this->mapOptions['nooverlap'], - $this->mapOptions['z_dash'], - $this->mapOptions['ranksep'], - $this->mapOptions['center'], - $this->mapOptions['regen'], - $this->mapOptions['pure'], - $this->mapOptions['id'], - $this->mapOptions['show_snmp_modules'], - $this->mapOptions['cut_names'], - $this->mapOptions['relative'], - $this->mapOptions['text_filter'], - $this->network, - $this->mapOptions['dont_show_subgroups'], - // Strict user (strict_user). - false, - // Canvas size (size_canvas). - null, - $this->mapOptions['old_mode'], - $this->mapOptions['map_filter'] - ); - } + if (isset($this->mode) && $this->mode === 'simple') { + include_once $config['homedir'].'/include/functions_maps.php'; + $graph .= open_graph(); + foreach ($this->nodes as $key => $value) { + $graph .= create_node($value, $this->mapOptions['font_size']); + } + + foreach ($this->relations as $key => $relation) { + $graph .= create_edge($key, $relation); + } + + $graph .= close_graph(); + + $this->dotGraph = $graph; + } else { + // Generate dot file. + $this->dotGraph = networkmap_generate_dot( + get_product_name(), + $this->idGroup, + $this->mapOptions['simple'], + $this->mapOptions['font_size'], + $this->mapOptions['layout'], + $this->mapOptions['nooverlap'], + $this->mapOptions['z_dash'], + $this->mapOptions['ranksep'], + $this->mapOptions['center'], + $this->mapOptions['regen'], + $this->mapOptions['pure'], + $this->mapOptions['id'], + $this->mapOptions['show_snmp_modules'], + $this->mapOptions['cut_names'], + $this->mapOptions['relative'], + $this->mapOptions['text_filter'], + $this->network, + $this->mapOptions['dont_show_subgroups'], + // Strict user (strict_user). + false, + // Canvas size (size_canvas). + null, + $this->mapOptions['old_mode'], + $this->mapOptions['map_filter'] + ); + } + } } @@ -652,158 +695,171 @@ class NetworkMap unlink($filename_dot); - $nodes = networkmap_loadfile( - $this->idMap, - $filename_plain, - $relation_nodes, - $this->dotGraph - ); + if (isset($this->mode) && $this->mode === 'simple') { + if (isset($this->loadfile)) { + include_once $this->loadfile[0]; + $func = $this->loadfile[1]; + // Extra parameter. Used in clustermap. + if (isset($this->mapOptions['id_cluster'])) { + $this->graph = $func($filename_plain, $this->dotGraph, $this->mapOptions['id_cluster']); + } else { + $this->graph = $func($filename_plain, $this->dotGraph); + } + } else { + } + } else { + $nodes = networkmap_loadfile( + $this->idMap, + $filename_plain, + $relation_nodes, + $this->dotGraph + ); - unlink($filename_plain); + unlink($filename_plain); - /* - * Graphviz section ends here. - */ + /* + * Graphviz section ends here. + */ - /* - * Calculate references. - */ + /* + * Calculate references. + */ - // Set the position of modules. - foreach ($nodes as $key => $node) { - if ($node['type'] == 'module') { - // Search the agent of this module for to get the - // position. - foreach ($nodes as $key2 => $node2) { - if ($node2['id_agent'] != 0 && $node2['type'] == 'agent') { - if ($node2['id_agent'] == $node['id_agent']) { - $nodes[$key]['coords'][0] = ($nodes[$key2]['coords'][0] + $node['height'] / 2); - $nodes[$key]['coords'][1] = ($nodes[$key2]['coords'][1] + $node['width'] / 2); + // Set the position of modules. + foreach ($nodes as $key => $node) { + if ($node['type'] == 'module') { + // Search the agent of this module for to get the + // position. + foreach ($nodes as $key2 => $node2) { + if ($node2['id_agent'] != 0 && $node2['type'] == 'agent') { + if ($node2['id_agent'] == $node['id_agent']) { + $nodes[$key]['coords'][0] = ($nodes[$key2]['coords'][0] + $node['height'] / 2); + $nodes[$key]['coords'][1] = ($nodes[$key2]['coords'][1] + $node['width'] / 2); + } } } } } - } - $nodes_and_relations['nodes'] = []; - $index = 0; - $node_center = []; - foreach ($nodes as $key => $node) { - $nodes_and_relations['nodes'][$index]['id'] = $node['id']; - $nodes_and_relations['nodes'][$index]['id_map'] = $this->idMap; + $nodes_and_relations['nodes'] = []; + $index = 0; + $node_center = []; + foreach ($nodes as $key => $node) { + $nodes_and_relations['nodes'][$index]['id'] = $node['id']; + $nodes_and_relations['nodes'][$index]['id_map'] = $this->idMap; - $children_count = 0; - foreach ($relation_nodes as $relation) { - if (($relation['parent_type'] == 'agent') || ($relation['parent_type'] == '')) { - if ($nodes[$relation['id_parent']]['id_agent'] == $node['id_agent']) { - $children_count++; - } - } else if ($relation['parent_type'] == 'module') { - if ($nodes[$relation['id_parent']]['id_module'] == $node['id_module']) { - $children_count++; + $children_count = 0; + foreach ($relation_nodes as $relation) { + if (($relation['parent_type'] == 'agent') || ($relation['parent_type'] == '')) { + if ($nodes[$relation['id_parent']]['id_agent'] == $node['id_agent']) { + $children_count++; + } + } else if ($relation['parent_type'] == 'module') { + if ($nodes[$relation['id_parent']]['id_module'] == $node['id_module']) { + $children_count++; + } } } + + if (empty($node_center) || $node_center['counter'] < $children_count) { + $node_center['x'] = (int) $node['coords'][0]; + $node_center['y'] = (int) $node['coords'][1]; + $node_center['counter'] = $children_count; + } + + $nodes_and_relations['nodes'][$index]['x'] = (int) $node['coords'][0]; + $nodes_and_relations['nodes'][$index]['y'] = (int) $node['coords'][1]; + + if (($node['type'] == 'agent') || ($node['type'] == '')) { + $nodes_and_relations['nodes'][$index]['source_data'] = $node['id_agent']; + $nodes_and_relations['nodes'][$index]['type'] = 0; + } else { + $nodes_and_relations['nodes'][$index]['source_data'] = $node['id_module']; + $nodes_and_relations['nodes'][$index]['id_agent'] = $node['id_agent']; + $nodes_and_relations['nodes'][$index]['type'] = 1; + } + + $style = []; + $style['shape'] = 'circle'; + $style['image'] = $node['image']; + $style['width'] = $node['width']; + $style['height'] = $node['height']; + $style['label'] = $node['text']; + $nodes_and_relations['nodes'][$index]['style'] = json_encode($style); + + $index++; } - if (empty($node_center) || $node_center['counter'] < $children_count) { - $node_center['x'] = (int) $node['coords'][0]; - $node_center['y'] = (int) $node['coords'][1]; - $node_center['counter'] = $children_count; + $nodes_and_relations['relations'] = []; + $index = 0; + + foreach ($relation_nodes as $relation) { + $nodes_and_relations['relations'][$index]['id_map'] = $this->idMap; + + if (($relation['parent_type'] == 'agent') || ($relation['parent_type'] == '')) { + $nodes_and_relations['relations'][$index]['id_parent'] = $relation['id_parent']; + $nodes_and_relations['relations'][$index]['id_parent_source_data'] = $nodes[$relation['id_parent']]['id_agent']; + $nodes_and_relations['relations'][$index]['parent_type'] = 0; + } else if ($relation['parent_type'] == 'module') { + $nodes_and_relations['relations'][$index]['id_parent'] = $relation['id_parent']; + $nodes_and_relations['relations'][$index]['id_parent_source_data'] = $nodes[$relation['id_parent']]['id_module']; + $nodes_and_relations['relations'][$index]['parent_type'] = 1; + } else { + $nodes_and_relations['relations'][$index]['id_parent'] = $relation['id_parent']; + $nodes_and_relations['relations'][$index]['id_child_source_data'] = -2; + $nodes_and_relations['relations'][$index]['parent_type'] = 3; + } + + if (($relation['child_type'] == 'agent') || ($relation['child_type'] == '')) { + $nodes_and_relations['relations'][$index]['id_child'] = $relation['id_child']; + $nodes_and_relations['relations'][$index]['id_child_source_data'] = $nodes[$relation['id_child']]['id_agent']; + $nodes_and_relations['relations'][$index]['child_type'] = 0; + } else if ($relation['child_type'] == 'module') { + $nodes_and_relations['relations'][$index]['id_child'] = $relation['id_child']; + $nodes_and_relations['relations'][$index]['id_child_source_data'] = $nodes[$relation['id_child']]['id_module']; + $nodes_and_relations['relations'][$index]['child_type'] = 1; + } else { + $nodes_and_relations['relations'][$index]['id_child'] = $relation['id_child']; + $nodes_and_relations['relations'][$index]['id_child_source_data'] = -2; + $nodes_and_relations['relations'][$index]['child_type'] = 3; + } + + $index++; } - $nodes_and_relations['nodes'][$index]['x'] = (int) $node['coords'][0]; - $nodes_and_relations['nodes'][$index]['y'] = (int) $node['coords'][1]; + if ($this->idMap > 0 && (!isset($this->map['__simulated']))) { + if (enterprise_installed()) { + $nodes_and_relations = enterprise_hook( + 'save_generate_nodes', + [ + $this->idMap, + $nodes_and_relations, + ] + ); + } - if (($node['type'] == 'agent') || ($node['type'] == '')) { - $nodes_and_relations['nodes'][$index]['source_data'] = $node['id_agent']; - $nodes_and_relations['nodes'][$index]['type'] = 0; - } else { - $nodes_and_relations['nodes'][$index]['source_data'] = $node['id_module']; - $nodes_and_relations['nodes'][$index]['id_agent'] = $node['id_agent']; - $nodes_and_relations['nodes'][$index]['type'] = 1; - } + $center = [ + 'x' => $node_center['x'], + 'y' => $node_center['y'], + ]; - $style = []; - $style['shape'] = 'circle'; - $style['image'] = $node['image']; - $style['width'] = $node['width']; - $style['height'] = $node['height']; - $style['label'] = $node['text']; - $nodes_and_relations['nodes'][$index]['style'] = json_encode($style); - - $index++; - } - - $nodes_and_relations['relations'] = []; - $index = 0; - - foreach ($relation_nodes as $relation) { - $nodes_and_relations['relations'][$index]['id_map'] = $this->idMap; - - if (($relation['parent_type'] == 'agent') || ($relation['parent_type'] == '')) { - $nodes_and_relations['relations'][$index]['id_parent'] = $relation['id_parent']; - $nodes_and_relations['relations'][$index]['id_parent_source_data'] = $nodes[$relation['id_parent']]['id_agent']; - $nodes_and_relations['relations'][$index]['parent_type'] = 0; - } else if ($relation['parent_type'] == 'module') { - $nodes_and_relations['relations'][$index]['id_parent'] = $relation['id_parent']; - $nodes_and_relations['relations'][$index]['id_parent_source_data'] = $nodes[$relation['id_parent']]['id_module']; - $nodes_and_relations['relations'][$index]['parent_type'] = 1; - } else { - $nodes_and_relations['relations'][$index]['id_parent'] = $relation['id_parent']; - $nodes_and_relations['relations'][$index]['id_child_source_data'] = -2; - $nodes_and_relations['relations'][$index]['parent_type'] = 3; - } - - if (($relation['child_type'] == 'agent') || ($relation['child_type'] == '')) { - $nodes_and_relations['relations'][$index]['id_child'] = $relation['id_child']; - $nodes_and_relations['relations'][$index]['id_child_source_data'] = $nodes[$relation['id_child']]['id_agent']; - $nodes_and_relations['relations'][$index]['child_type'] = 0; - } else if ($relation['child_type'] == 'module') { - $nodes_and_relations['relations'][$index]['id_child'] = $relation['id_child']; - $nodes_and_relations['relations'][$index]['id_child_source_data'] = $nodes[$relation['id_child']]['id_module']; - $nodes_and_relations['relations'][$index]['child_type'] = 1; - } else { - $nodes_and_relations['relations'][$index]['id_child'] = $relation['id_child']; - $nodes_and_relations['relations'][$index]['id_child_source_data'] = -2; - $nodes_and_relations['relations'][$index]['child_type'] = 3; - } - - $index++; - } - - if ($this->idMap > 0 && (!isset($this->map['__simulated']))) { - if (enterprise_installed()) { - $nodes_and_relations = enterprise_hook( - 'save_generate_nodes', + $this->map['center_x'] = $center['x']; + $this->map['center_y'] = $center['y']; + db_process_sql_update( + 'tmap', [ - $this->idMap, - $nodes_and_relations, - ] + 'center_x' => $this->map['center_x'], + 'center_y' => $this->map['center_y'], + ], + ['id' => $this->idMap] ); + } else { + $this->map['center_x'] = $node_center['x']; + $this->map['center_y'] = $node_center['y']; } - $center = [ - 'x' => $node_center['x'], - 'y' => $node_center['y'], - ]; - - $this->map['center_x'] = $center['x']; - $this->map['center_y'] = $center['y']; - db_process_sql_update( - 'tmap', - [ - 'center_x' => $this->map['center_x'], - 'center_y' => $this->map['center_y'], - ], - ['id' => $this->idMap] - ); - } else { - $this->map['center_x'] = $node_center['x']; - $this->map['center_y'] = $node_center['y']; + $this->graph = $nodes_and_relations; } - - $this->graph = $nodes_and_relations; - } @@ -814,221 +870,245 @@ class NetworkMap */ public function loadMapData() { - $networkmap = $this->map; + if (isset($this->mode) && $this->mode === 'simple') { + $output .= '<script type="text/javascript">'; + $output .= "var controller_map = null;\n"; + $output .= 'var size_image ='.json_encode($this->mapOptions['size_image']).";\n"; + $output .= 'var tooltipster ='.json_encode($this->mapOptions['tootltip']).";\n"; + $output .= 'var nodes = '.json_encode($this->graph['nodes']).";\n"; + $output .= 'var arrows = '.json_encode($this->graph['arrows']).";\n"; + $output .= 'var height = '.json_encode($this->mapOptions['height']).";\n"; + $output .= 'var node_radius ='.json_encode($this->mapOptions['node_radius']).";\n"; + $output .= 'var font_size ='.json_encode($this->mapOptions['font_size']).";\n"; + $output .= 'var homedir ='.json_encode($this->mapOptions['baseurl']).";\n"; + $output .= "var custom_params = {};\n"; + $output .= "custom_params['get_tooltip_info'] = 1;\n"; + if ($this->mapOptions['id_cluster'] != null) { + $output .= "custom_params['id_cluster'] = ".$this->mapOptions['id_cluster'].";\n"; + $output .= 'var id_cluster ='.json_encode($this->mapOptions['id_cluster']).";\n"; + } - $simulate = false; - if (!isset($networkmap['__simulated'])) { - $networkmap['filter'] = json_decode( - $networkmap['filter'], - true + $output .= "custom_params['page'] = 'enterprise/include/ajax/clustermap';\n"; + $output .= '</script>'; + + return $output; + } else { + $networkmap = $this->map; + + $simulate = false; + if (!isset($networkmap['__simulated'])) { + $networkmap['filter'] = json_decode( + $networkmap['filter'], + true + ); + $networkmap['filter']['holding_area'] = [ + 500, + 500, + ]; + $holding_area_title = __('Holding Area'); + } else { + $simulate = true; + $holding_area_title = ''; + $networkmap['filter']['holding_area'] = [ + 0, + 0, + ]; + } + + $this->graph['relations'] = clean_duplicate_links( + $this->graph['relations'] ); - $networkmap['filter']['holding_area'] = [ - 500, - 500, - ]; - $holding_area_title = __('Holding Area'); - } else { - $simulate = true; - $holding_area_title = ''; - $networkmap['filter']['holding_area'] = [ - 0, - 0, - ]; - } - $this->graph['relations'] = clean_duplicate_links( - $this->graph['relations'] - ); + // Print some params to handle it in js. + html_print_input_hidden('product_name', get_product_name()); + html_print_input_hidden('center_logo', ui_get_full_url(ui_get_logo_to_center_networkmap())); - // Print some params to handle it in js. - html_print_input_hidden('product_name', get_product_name()); - html_print_input_hidden('center_logo', ui_get_full_url(ui_get_logo_to_center_networkmap())); + $output .= '<script type="text/javascript"> + //////////////////////////////////////////////////////////////////// + // VARS FROM THE DB + //////////////////////////////////////////////////////////////////// + var url_background_grid = "'.ui_get_full_url('images/background_grid.png').'"; + '; + $output .= 'var networkmap_id = "'.$this->idMap."\";\n"; - $output .= '<script type="text/javascript"> - //////////////////////////////////////////////////////////////////// - // VARS FROM THE DB - //////////////////////////////////////////////////////////////////// - var url_background_grid = "'.ui_get_full_url('images/background_grid.png').'"; - '; - $output .= 'var networkmap_id = "'.$this->idMap."\";\n"; + if (!empty($networkmap['filter'])) { + if (empty($networkmap['filter']['x_offs'])) { + $output .= "var x_offs =null;\n"; + } else { + $output .= 'var x_offs ='.$networkmap['filter']['x_offs'].";\n"; + } - if (!empty($networkmap['filter'])) { - if (empty($networkmap['filter']['x_offs'])) { - $output .= "var x_offs =null;\n"; - } else { - $output .= 'var x_offs ='.$networkmap['filter']['x_offs'].";\n"; - } + if (empty($networkmap['filter']['y_offs'])) { + $output .= "var y_offs =null;\n"; + } else { + $output .= 'var y_offs ='.$networkmap['filter']['y_offs'].";\n"; + } - if (empty($networkmap['filter']['y_offs'])) { - $output .= "var y_offs =null;\n"; - } else { - $output .= 'var y_offs ='.$networkmap['filter']['y_offs'].";\n"; - } - - if (empty($networkmap['filter']['y_offs'])) { - $output .= "var z_dash =null;\n"; - } else { - $output .= 'var z_dash = '.$networkmap['filter']['z_dash'].";\n"; - } - } else { - $output .= "var x_offs = null;\n"; - $output .= "var y_offs = null;\n"; - $output .= "var z_dash = null;\n"; - } - - $output .= 'var networkmap_refresh_time = 1000 * '.$networkmap['source_period'].";\n"; - $output .= 'var networkmap_center = [ '.$networkmap['center_x'].', '.$networkmap['center_y']."];\n"; - $output .= 'var networkmap_dimensions = [ '.$networkmap['width'].', '.$networkmap['height']."];\n"; - $output .= 'var enterprise_installed = '.((int) enterprise_installed()).";\n"; - $output .= 'var node_radius = '.$networkmap['filter']['node_radius'].";\n"; - $output .= 'var networkmap_holding_area_dimensions = '.json_encode($networkmap['filter']['holding_area']).";\n"; - $output .= "var networkmap = {'nodes': [], 'links': []};\n"; - $nodes = $this->graph['nodes']; - - if (empty($nodes)) { - $nodes = []; - } - - $count_item_holding_area = 0; - $count = 0; - $nodes_graph = []; - - foreach ($nodes as $key => $node) { - $style = json_decode($node['style'], true); - $node['style'] = json_decode($node['style'], true); - - // Only agents can be show. - if (isset($node['type'])) { - if ($node['type'] == 1) { - continue; + if (empty($networkmap['filter']['y_offs'])) { + $output .= "var z_dash =null;\n"; + } else { + $output .= 'var z_dash = '.$networkmap['filter']['z_dash'].";\n"; } } else { - $node['type'] = ''; + $output .= "var x_offs = null;\n"; + $output .= "var y_offs = null;\n"; + $output .= "var z_dash = null;\n"; } - $item = networkmap_db_node_to_js_node( - $node, - $count, - $count_item_holding_area, + $output .= 'var networkmap_refresh_time = 1000 * '.$networkmap['source_period'].";\n"; + $output .= 'var networkmap_center = [ '.$networkmap['center_x'].', '.$networkmap['center_y']."];\n"; + $output .= 'var networkmap_dimensions = [ '.$networkmap['width'].', '.$networkmap['height']."];\n"; + $output .= 'var enterprise_installed = '.((int) enterprise_installed()).";\n"; + $output .= 'var node_radius = '.$networkmap['filter']['node_radius'].";\n"; + $output .= 'var networkmap_holding_area_dimensions = '.json_encode($networkmap['filter']['holding_area']).";\n"; + $output .= "var networkmap = {'nodes': [], 'links': []};\n"; + $nodes = $this->graph['nodes']; + + if (empty($nodes)) { + $nodes = []; + } + + $count_item_holding_area = 0; + $count = 0; + $nodes_graph = []; + + foreach ($nodes as $key => $node) { + $style = json_decode($node['style'], true); + $node['style'] = json_decode($node['style'], true); + + // Only agents can be show. + if (isset($node['type'])) { + if ($node['type'] == 1) { + continue; + } + } else { + $node['type'] = ''; + } + + $item = networkmap_db_node_to_js_node( + $node, + $count, + $count_item_holding_area, + $simulate + ); + if ($item['deleted']) { + continue; + } + + $output .= 'networkmap.nodes.push('.json_encode($item).");\n"; + $nodes_graph[$item['id']] = $item; + } + + $relations = $this->graph['relations']; + + if ($relations === false) { + $relations = []; + } + + // Clean the relations and transform the module relations into + // interfaces. + networkmap_clean_relations_for_js($relations); + + $links_js = networkmap_links_to_js_links( + $relations, + $nodes_graph, $simulate ); - if ($item['deleted']) { - continue; + + $array_aux = []; + foreach ($links_js as $link_js) { + if ($link_js['deleted']) { + unset($links_js[$link_js['id']]); + } + + if ($link_js['target'] == -1) { + unset($links_js[$link_js['id']]); + } + + if ($link_js['source'] == -1) { + unset($links_js[$link_js['id']]); + } + + if ($link_js['target'] == $link_js['source']) { + unset($links_js[$link_js['id']]); + } + + if ($link_js['arrow_start'] == 'module' && $link_js['arrow_end'] == 'module') { + $output .= 'networkmap.links.push('.json_encode($link_js).");\n"; + $array_aux[$link_js['id_agent_start']] = 1; + unset($links_js[$link_js['id']]); + } } - $output .= 'networkmap.nodes.push('.json_encode($item).");\n"; - $nodes_graph[$item['id']] = $item; + foreach ($links_js as $link_js) { + if (($link_js['id_agent_end'] === 0) && $array_aux[$link_js['id_agent_start']] === 1) { + continue; + } else { + $output .= 'networkmap.links.push('.json_encode($link_js).");\n"; + } + } + + $output .= ' + //////////////////////////////////////////////////////////////////// + // INTERFACE STATUS COLORS + //////////////////////////////////////////////////////////////////// + '; + + $module_color_status = []; + $module_color_status[] = [ + 'status_code' => AGENT_MODULE_STATUS_NORMAL, + 'color' => COL_NORMAL, + ]; + $module_color_status[] = [ + 'status_code' => AGENT_MODULE_STATUS_CRITICAL_BAD, + 'color' => COL_CRITICAL, + ]; + $module_color_status[] = [ + 'status_code' => AGENT_MODULE_STATUS_WARNING, + 'color' => COL_WARNING, + ]; + $module_color_status[] = [ + 'status_code' => AGENT_STATUS_ALERT_FIRED, + 'color' => COL_ALERTFIRED, + ]; + $module_color_status_unknown = COL_UNKNOWN; + + $output .= 'var module_color_status = '.json_encode($module_color_status).";\n"; + $output .= "var module_color_status_unknown = '".$module_color_status_unknown."';\n"; + + $output .= ' + //////////////////////////////////////////////////////////////////// + // Other vars + //////////////////////////////////////////////////////////////////// + '; + + $output .= "var translation_none = '".__('None')."';\n"; + $output .= "var dialog_node_edit_title = '".__('Edit node %s')."';\n"; + $output .= "var holding_area_title = '".$holding_area_title."';\n"; + $output .= "var edit_menu = '".__('Show details and options')."';\n"; + $output .= "var interface_link_add = '".__('Add a interface link')."';\n"; + $output .= "var set_parent_link = '".__('Set parent interface')."';\n"; + $output .= "var set_as_children_menu = '".__('Set as children')."';\n"; + $output .= "var set_parent_menu = '".__('Set parent')."';\n"; + $output .= "var abort_relationship_menu = '".__('Abort the action of set relationship')."';\n"; + $output .= "var delete_menu = '".__('Delete')."';\n"; + $output .= "var add_node_menu = '".__('Add node')."';\n"; + $output .= "var set_center_menu = '".__('Set center')."';\n"; + $output .= "var refresh_menu = '".__('Refresh')."';\n"; + $output .= "var refresh_holding_area_menu = '".__('Refresh Holding area')."';\n"; + $output .= "var ok_button = '".__('Proceed')."';\n"; + $output .= "var message_to_confirm = '".__('Resetting the map will delete all customizations you have done, including manual relationships between elements, new items, etc.')."';\n"; + $output .= "var warning_message = '".__('WARNING')."';\n"; + $output .= "var ok_button = '".__('Proceed')."';\n"; + $output .= "var cancel_button = '".__('Cancel')."';\n"; + $output .= "var restart_map_menu = '".__('Restart map')."';\n"; + $output .= "var abort_relationship_interface = '".__('Abort the interface relationship')."';\n"; + $output .= "var abort_relationship_menu = '".__('Abort the action of set relationship')."';\n"; + + $output .= '</script>'; + + return $output; } - - $relations = $this->graph['relations']; - - if ($relations === false) { - $relations = []; - } - - // Clean the relations and transform the module relations into - // interfaces. - networkmap_clean_relations_for_js($relations); - - $links_js = networkmap_links_to_js_links( - $relations, - $nodes_graph, - $simulate - ); - - $array_aux = []; - foreach ($links_js as $link_js) { - if ($link_js['deleted']) { - unset($links_js[$link_js['id']]); - } - - if ($link_js['target'] == -1) { - unset($links_js[$link_js['id']]); - } - - if ($link_js['source'] == -1) { - unset($links_js[$link_js['id']]); - } - - if ($link_js['target'] == $link_js['source']) { - unset($links_js[$link_js['id']]); - } - - if ($link_js['arrow_start'] == 'module' && $link_js['arrow_end'] == 'module') { - $output .= 'networkmap.links.push('.json_encode($link_js).");\n"; - $array_aux[$link_js['id_agent_start']] = 1; - unset($links_js[$link_js['id']]); - } - } - - foreach ($links_js as $link_js) { - if (($link_js['id_agent_end'] === 0) && $array_aux[$link_js['id_agent_start']] === 1) { - continue; - } else { - $output .= 'networkmap.links.push('.json_encode($link_js).");\n"; - } - } - - $output .= ' - //////////////////////////////////////////////////////////////////// - // INTERFACE STATUS COLORS - //////////////////////////////////////////////////////////////////// - '; - - $module_color_status = []; - $module_color_status[] = [ - 'status_code' => AGENT_MODULE_STATUS_NORMAL, - 'color' => COL_NORMAL, - ]; - $module_color_status[] = [ - 'status_code' => AGENT_MODULE_STATUS_CRITICAL_BAD, - 'color' => COL_CRITICAL, - ]; - $module_color_status[] = [ - 'status_code' => AGENT_MODULE_STATUS_WARNING, - 'color' => COL_WARNING, - ]; - $module_color_status[] = [ - 'status_code' => AGENT_STATUS_ALERT_FIRED, - 'color' => COL_ALERTFIRED, - ]; - $module_color_status_unknown = COL_UNKNOWN; - - $output .= 'var module_color_status = '.json_encode($module_color_status).";\n"; - $output .= "var module_color_status_unknown = '".$module_color_status_unknown."';\n"; - - $output .= ' - //////////////////////////////////////////////////////////////////// - // Other vars - //////////////////////////////////////////////////////////////////// - '; - - $output .= "var translation_none = '".__('None')."';\n"; - $output .= "var dialog_node_edit_title = '".__('Edit node %s')."';\n"; - $output .= "var holding_area_title = '".$holding_area_title."';\n"; - $output .= "var edit_menu = '".__('Show details and options')."';\n"; - $output .= "var interface_link_add = '".__('Add a interface link')."';\n"; - $output .= "var set_parent_link = '".__('Set parent interface')."';\n"; - $output .= "var set_as_children_menu = '".__('Set as children')."';\n"; - $output .= "var set_parent_menu = '".__('Set parent')."';\n"; - $output .= "var abort_relationship_menu = '".__('Abort the action of set relationship')."';\n"; - $output .= "var delete_menu = '".__('Delete')."';\n"; - $output .= "var add_node_menu = '".__('Add node')."';\n"; - $output .= "var set_center_menu = '".__('Set center')."';\n"; - $output .= "var refresh_menu = '".__('Refresh')."';\n"; - $output .= "var refresh_holding_area_menu = '".__('Refresh Holding area')."';\n"; - $output .= "var ok_button = '".__('Proceed')."';\n"; - $output .= "var message_to_confirm = '".__('Resetting the map will delete all customizations you have done, including manual relationships between elements, new items, etc.')."';\n"; - $output .= "var warning_message = '".__('WARNING')."';\n"; - $output .= "var ok_button = '".__('Proceed')."';\n"; - $output .= "var cancel_button = '".__('Cancel')."';\n"; - $output .= "var restart_map_menu = '".__('Restart map')."';\n"; - $output .= "var abort_relationship_interface = '".__('Abort the interface relationship')."';\n"; - $output .= "var abort_relationship_menu = '".__('Abort the action of set relationship')."';\n"; - - $output .= '</script>'; - - return $output; } @@ -1446,46 +1526,57 @@ class NetworkMap { $output = ''; - // Generate JS for advanced controller. - $output .= ' - -<script type="text/javascript"> - //////////////////////////////////////////////////////////////////////// - // document ready - //////////////////////////////////////////////////////////////////////// - - $(document).ready(function() { - init_graph({ - graph: networkmap, - networkmap_center: networkmap_center, - networkmap_dimensions: networkmap_dimensions, - enterprise_installed: enterprise_installed, - node_radius: node_radius, - holding_area_dimensions: networkmap_holding_area_dimensions, - url_background_grid: url_background_grid - }); - init_drag_and_drop(); - init_minimap(); - function_open_minimap(); - - $(document.body).on("mouseleave", - ".context-menu-list", - function(e) { - try { - $("#networkconsole_'.$this->idMap.'").contextMenu("hide"); - } - catch(err) { - } - } - ); - }); -</script>'; - - if ($return === false) { + if (isset($this->mode) && $this->mode === 'simple') { + $output .= '<script type="text/javascript"> + var controller = null + $(function() { + controller = new SimpleMapController("#simple_map"); + controller.init_map(); + }); + </script>'; echo $output; - } + } else { + // Generate JS for advanced controller. + $output .= ' - return $output; + <script type="text/javascript"> + //////////////////////////////////////////////////////////////////////// + // document ready + //////////////////////////////////////////////////////////////////////// + + $(document).ready(function() { + init_graph({ + graph: networkmap, + networkmap_center: networkmap_center, + networkmap_dimensions: networkmap_dimensions, + enterprise_installed: enterprise_installed, + node_radius: node_radius, + holding_area_dimensions: networkmap_holding_area_dimensions, + url_background_grid: url_background_grid + }); + init_drag_and_drop(); + init_minimap(); + function_open_minimap(); + + $(document.body).on("mouseleave", + ".context-menu-list", + function(e) { + try { + $("#networkconsole_'.$this->idMap.'").contextMenu("hide"); + } + catch(err) { + } + } + ); + }); + </script>'; + + if ($return === false) { + echo $output; + } + + return $output; + } } @@ -1499,55 +1590,73 @@ class NetworkMap { global $config; - ui_require_css_file('networkmap'); - ui_require_css_file('jquery.contextMenu', 'include/styles/js/'); - $output = ''; - $minimap_display = ''; - if ($this->mapOptions['pure']) { - $minimap_display = 'none'; + + if (isset($this->mode) && $this->mode === 'simple') { + $output .= '<script type="text/javascript" src="'.$config['homeurl'].'include/javascript/d3.3.5.14.js" charset="utf-8"></script>'; + $output .= '<script type="text/javascript" src="'.$config['homeurl'].'enterprise/include/javascript/SimpleMapController.js"></script>'; + $output .= '<script type="text/javascript" src="'.$config['homeurl'].'enterprise/include/javascript/tooltipster.bundle.min.js"></script>'; + $output .= '<script type="text/javascript" src="'.$config['homeurl'].'include/javascript/jquery.svg.js"></script>'; + $output .= '<script type="text/javascript" src="'.$config['homeurl'].'include/javascript/jquery.svgdom.js"></script>'; + $output .= '<link rel="stylesheet" type="text/css" href="'.$this->mapOptions['baseurl'].'/enterprise/include/styles/tooltipster.bundle.min.css" />'."\n"; + + $output .= '<div id="simple_map" data-id="<?php echo $this->name;?>" style="border: 1px #dddddd solid;">'; + $output .= '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" pointer-events="all" width="'.$this->mapOptions['width'].'" height="'.$this->mapOptions['height'].'px">'; + + $output .= '</svg>'; + $output .= '</div>'; + + return $output; + } else { + ui_require_css_file('networkmap'); + ui_require_css_file('jquery.contextMenu', 'include/styles/js/'); + + $minimap_display = ''; + if ($this->mapOptions['pure']) { + $minimap_display = 'none'; + } + + $networkmap = $this->map; + $networkmap['filter'] = json_decode($networkmap['filter'], true); + + $networkmap['filter']['l2_network_interfaces'] = 1; + + $output .= '<script type="text/javascript" src="'.$config['homeurl'].'include/javascript/d3.3.5.14.js" charset="utf-8"></script>'; + $output .= '<script type="text/javascript" src="'.$config['homeurl'].'include/javascript/jquery.contextMenu.js"></script>'; + $output .= '<script type="text/javascript" src="'.$config['homeurl'].'include/javascript/functions_pandora_networkmap.js"></script>'; + + // Open networkconsole_id div. + $output .= '<div id="networkconsole_'.$networkmap['id'].'"'; + $output .= ' style="position: relative; overflow: hidden; background: #FAFAFA">'; + + $output .= '<div style="display: '.$minimap_display.';">'; + $output .= '<canvas id="minimap_'.$networkmap['id'].'"'; + $output .= ' style="position: absolute; left: 0px; top: 0px; border: 1px solid #bbbbbb;">'; + $output .= '</canvas>'; + + $output .= '<div id="arrow_minimap_'.$networkmap['id'].'"'; + $output .= ' style="position: absolute; left: 0px; top: 0px;">'; + $output .= '<a title="'.__('Open Minimap').'" href="javascript: toggle_minimap();">'; + $output .= '<img id="image_arrow_minimap_'.$networkmap['id'].'"'; + $output .= ' src="images/minimap_open_arrow.png" />'; + $output .= '</a><div></div></div>'; + + $output .= '<div id="hide_labels_'.$networkmap['id'].'"'; + $output .= ' style="position: absolute; right: 10px; top: 10px;">'; + $output .= '<a title="'.__('Hide Labels').'" href="javascript: hide_labels();">'; + $output .= '<img id="image_hide_show_labels" src="images/icono_borrar.png" />'; + $output .= '</a></div>'; + + $output .= '<div id="holding_spinner_'.$networkmap['id'].'" '; + $output .= ' style="display: none; position: absolute; right: 50px; top: 20px;">'; + $output .= '<img id="image_hide_show_labels" src="images/spinner.gif" />'; + $output .= '</div>'; + + // Close networkconsole_id div. + $output .= "</div>\n"; + + return $output; } - - $networkmap = $this->map; - $networkmap['filter'] = json_decode($networkmap['filter'], true); - - $networkmap['filter']['l2_network_interfaces'] = 1; - - $output .= '<script type="text/javascript" src="'.$config['homeurl'].'include/javascript/d3.3.5.14.js" charset="utf-8"></script>'; - $output .= '<script type="text/javascript" src="'.$config['homeurl'].'include/javascript/jquery.contextMenu.js"></script>'; - $output .= '<script type="text/javascript" src="'.$config['homeurl'].'include/javascript/functions_pandora_networkmap.js"></script>'; - - // Open networkconsole_id div. - $output .= '<div id="networkconsole_'.$networkmap['id'].'"'; - $output .= ' style="position: relative; overflow: hidden; background: #FAFAFA">'; - - $output .= '<div style="display: '.$minimap_display.';">'; - $output .= '<canvas id="minimap_'.$networkmap['id'].'"'; - $output .= ' style="position: absolute; left: 0px; top: 0px; border: 1px solid #bbbbbb;">'; - $output .= '</canvas>'; - - $output .= '<div id="arrow_minimap_'.$networkmap['id'].'"'; - $output .= ' style="position: absolute; left: 0px; top: 0px;">'; - $output .= '<a title="'.__('Open Minimap').'" href="javascript: toggle_minimap();">'; - $output .= '<img id="image_arrow_minimap_'.$networkmap['id'].'"'; - $output .= ' src="images/minimap_open_arrow.png" />'; - $output .= '</a><div></div></div>'; - - $output .= '<div id="hide_labels_'.$networkmap['id'].'"'; - $output .= ' style="position: absolute; right: 10px; top: 10px;">'; - $output .= '<a title="'.__('Hide Labels').'" href="javascript: hide_labels();">'; - $output .= '<img id="image_hide_show_labels" src="images/icono_borrar.png" />'; - $output .= '</a></div>'; - - $output .= '<div id="holding_spinner_'.$networkmap['id'].'" '; - $output .= ' style="display: none; position: absolute; right: 50px; top: 20px;">'; - $output .= '<img id="image_hide_show_labels" src="images/spinner.gif" />'; - $output .= '</div>'; - - // Close networkconsole_id div. - $output .= "</div>\n"; - - return $output; } From d13e7bbf44d7db6917684bb1a5f1a8be67b38c14 Mon Sep 17 00:00:00 2001 From: Daniel Maya <daniel.maya@artica.es> Date: Mon, 18 Mar 2019 09:05:47 +0100 Subject: [PATCH 50/50] new generic functions Former-commit-id: 09352ca97ea73505acdb44d14cde79b0d916d286 --- pandora_console/include/functions_maps.php | 216 ++++++++++++++++++ .../include/styles/cluster_view.css | 2 +- 2 files changed, 217 insertions(+), 1 deletion(-) diff --git a/pandora_console/include/functions_maps.php b/pandora_console/include/functions_maps.php index 2de8dc4b57..ed9b1bab06 100644 --- a/pandora_console/include/functions_maps.php +++ b/pandora_console/include/functions_maps.php @@ -221,3 +221,219 @@ function run_graphviz($filename_map, $filename_dot, $layout, $graph) return $filename_plain; } + + +function open_graph($size_x=50, $size_y=25) +{ + $size = ''; + + $size = $size_x.','.$size_y; + + // BEWARE: graphwiz DONT use single ('), you need double ("). + $head = 'graph vmwaremap { labeljust=l; margin=0; '; + $head .= 'ratio=fill;'; + $head .= 'root=0;'; + $head .= 'rankdir=LR;'; + $head .= 'size="'.$size.'";'; + + return $head; +} + + +function create_node($node, $font_size=10) +{ + // Set node status. + if (isset($node['status'])) { + switch ($node['status']) { + case AGENT_MODULE_STATUS_NORMAL: + $status_color = COL_NORMAL; + // Normal monitor. + break; + + case AGENT_MODULE_STATUS_CRITICAL_BAD: + $status_color = COL_CRITICAL; + // Critical monitor. + break; + + case AGENT_MODULE_STATUS_WARNING: + $status_color = COL_WARNING; + // Warning monitor. + break; + + case AGENT_STATUS_ALERT_FIRED: + case AGENT_MODULE_STATUS_CRITICAL_ALERT: + case AGENT_MODULE_STATUS_WARNING_ALERT: + $status_color = COL_ALERTFIRED; + // Alert fired. + break; + + case AGENT_MODULE_STATUS_NOT_INIT: + $status_color = COL_NOTINIT; + // Not init. + break; + + default: + $status_color = COL_UNKNOWN; + // Unknown monitor. + break; + } + + $status_color = 'color="'.$status_color.'",'; + } else { + $status_color = ''; + } + + // Short name. + if (isset($node['nombre'])) { + $name = io_safe_output(strtolower($node['nombre'])); + if (strlen($name) > 16) { + $name = substr($name, 0, 16).'...'; + } + } + + // Set node icon. + if (isset($node['image'])) { + if (file_exists($node['image'])) { + $img_node = $node['image']; + } else { + $img_node = null; + } + } else { + $img_node = null; + } + + $result = $node['id_node'].' [ '.$status_color.' fontsize='.$font_size.', style="filled", fixedsize=true, width=0.40, height=0.40, label=<<TABLE CELLPADDING="0" CELLSPACING="0" BORDER="0"><TR><TD>'.html_print_image($img_node, true, false, false, true).'</TD></TR> + <TR><TD>'.$name.'</TD></TR></TABLE>>, + shape="doublecircle", + tooltip="ajax.php?page=operation/agentes/ver_agente&get_agent_status_tooltip=1&id_agent='.$node['id'].'"];'; + + return $result; +} + + +/** + * Returns an edge definition. + * + * @param string $head Origin. + * @param string $tail Target. + * + * @return string Edge str. + */ +function create_edge($head, $tail) +{ + // Token edgeURL allows node navigation. + $edge = $head.' -- '.$tail.'[color="#BDBDBD", headclip=false, tailclip=false];'."\n"; + + return $edge; +} + + +// Closes a graph definition +function close_graph() +{ + return '}'; +} + + +function loadfile_map($file='', $graph) +{ + global $config; + + $networkmap_nodes = []; + + $relations = []; + + $other_file = file($file); + $graph = explode(']', $graph); + + $ids = []; + foreach ($graph as $node) { + $line = str_replace("\n", ' ', $node); + if (preg_match('/([0-9]+) \[.*tooltip.*id_agent=([0-9]+)/', $line, $match) != 0) { + $ids[$match[1]] = ['id_agent' => $match[2]]; + } + } + + foreach ($other_file as $key => $line) { + $line = preg_replace('/[ ]+/', ' ', $line); + + $data = []; + + if (preg_match('/^node.*$/', $line) != 0) { + $items = explode(' ', $line); + $node_id = $items[1]; + $node_x = ($items[2] * 100); + // 200 is for show more big + $node_y = ($height_map - $items[3] * 100); + // 200 is for show more big + $data['id'] = $node_id; + $data['image'] = ''; + $data['width'] = 10; + $data['height'] = 10; + $data['id_agent'] = 0; + + if (preg_match('/<img src=\"([^\"]*)\"/', $line, $match) == 1) { + $image = $match[1]; + $data['image'] = $config['homeurl'].'/'.$image; + $size = getimagesize($config['homeurl'].'/'.$image); + $data['image_width'] = $size[0]; + $data['image_height'] = $size[1]; + if ($ids[$node_id]['id_agent'] == '') { + $data['id_agent'] = 0; + $data['label'] = get_product_name(); + $data['color'] = COL_UNKNOWN; + } else { + $data['id_agent'] = $ids[$node_id]['id_agent']; + $data['label'] = io_safe_output(agents_get_alias($data['id_agent'])); + + $status = agents_get_status($data['id_agent']); + + switch ($status) { + case 0: + $status_color = COL_NORMAL; + // Normal monitor + break; + + case 1: + $status_color = COL_CRITICAL; + // Critical monitor + break; + + case 2: + $status_color = COL_WARNING; + // Warning monitor + break; + + case 4: + $status_color = COL_ALERTFIRED; + // Alert fired + break; + + default: + $status_color = COL_UNKNOWN; + // Unknown monitor + break; + } + + $data['color'] = $status_color; + } + } + + $data['x'] = $node_x; + $data['y'] = $node_y; + + $networkmap_nodes['nodes'][] = $data; + } else if (preg_match('/^edge.*$/', $line) != 0) { + $items = explode(' ', $line); + $line_orig = $items[2]; + $line_dest = $items[1]; + + $networkmap_nodes['arrows'][] = [ + 'orig' => $line_orig, + 'dest' => $line_dest, + ]; + } + } + + return $networkmap_nodes; +} diff --git a/pandora_console/include/styles/cluster_view.css b/pandora_console/include/styles/cluster_view.css index 74e30f1a8c..4d8f02ccb9 100644 --- a/pandora_console/include/styles/cluster_view.css +++ b/pandora_console/include/styles/cluster_view.css @@ -58,7 +58,7 @@ overflow-y: scroll; } -#cluster_map { +#simple_map { border: 1px solid lightgray; width: 900px; height: 500px;