diff --git a/pandora_console/extensions/update_manager/lang/language_en.php b/pandora_console/extensions/update_manager/lang/language_en.php
new file mode 100644
index 0000000000..a171281bf0
--- /dev/null
+++ b/pandora_console/extensions/update_manager/lang/language_en.php
@@ -0,0 +1,7 @@
+
diff --git a/pandora_console/extensions/update_manager/lib/libupdate_manager.php b/pandora_console/extensions/update_manager/lib/libupdate_manager.php
new file mode 100644
index 0000000000..b120f5bb99
--- /dev/null
+++ b/pandora_console/extensions/update_manager/lib/libupdate_manager.php
@@ -0,0 +1,521 @@
+PEAR::DB not found. Please install it with:
pear install DB
');
+error_reporting ($prev_level);
+unset ($prev_level);
+
+require_once ('libupdate_manager_utils.php');
+require_once ('libupdate_manager_updates.php');
+require_once ('libupdate_manager_components.php');
+require_once ('libupdate_manager_client.php');
+
+function um_db_load_settings () {
+ global $db;
+
+ $result =& $db->query ('SELECT * FROM tupdate_settings');
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return NULL;
+ }
+ $settings = new stdClass ();
+ while ($result->fetchInto ($setting)) {
+ $key = $setting->key;
+ $settings->$key = $setting->value;
+ }
+
+ return $settings;
+}
+
+function um_db_update_setting ($key, $value = '') {
+ global $db;
+
+ $values = array ($value, $key);
+
+ $sql =& $db->prepare ('UPDATE tupdate_settings SET value = ? WHERE `key` = ?');
+ $result =& $db->execute ($sql, $values);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return false;
+ }
+
+ return true;
+}
+
+function um_db_get_latest_public_package ($id_package = '0') {
+ global $db;
+
+ $values = array ('public', $id_package);
+ $sql =& $db->prepare ('SELECT * FROM tupdate_package WHERE status = ? AND id > ? ORDER BY id DESC LIMIT 1');
+ $result =& $db->execute ($sql, $values);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return false;
+ }
+
+ $result->fetchInto ($package);
+
+ return $package;
+}
+
+function um_db_get_latest_development_package ($id_package = '0') {
+ global $db;
+
+ $values = array ('development', $id_package);
+ $sql =& $db->prepare ('SELECT * FROM tupdate_package WHERE status = ? AND id > ? ORDER BY id DESC LIMIT 1');
+ $result =& $db->execute ($sql, $values);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return false;
+ }
+
+ $result->fetchInto ($package);
+
+ return $package;
+}
+
+function um_db_get_next_package ($id_package = '0', $development = false) {
+ global $db;
+
+ $values = array ('public', $id_package);
+ $sql =& $db->prepare ('SELECT * FROM tupdate_package WHERE status = ? AND id > ? ORDER BY id ASC LIMIT 1');
+ $result =& $db->execute ($sql, $values);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return false;
+ }
+
+ $result->fetchInto ($package);
+
+ if (! $package && $development) {
+ $values = array ('development', $id_package);
+ $sql =& $db->prepare ('SELECT * FROM tupdate_package WHERE status = ? AND id > ? ORDER BY id ASC LIMIT 1');
+ $result =& $db->execute ($sql, $values);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return false;
+ }
+ $result->fetchInto ($package);
+ }
+
+ return $package;
+}
+
+function um_db_create_package ($description = '') {
+ global $db;
+
+ $sql =& $db->prepare ('INSERT INTO tupdate_package (description) VALUES (?)');
+ $result =& $db->execute ($sql, $description);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return false;
+ }
+
+ return true;
+}
+
+function um_db_update_package ($id_package, $description = '', $status = 'disabled') {
+ global $db;
+
+ $values = array ($description, $status, $id_package);
+
+ $sql =& $db->prepare ('UPDATE tupdate_package SET description = ?, status = ? WHERE id = ?');
+ $result =& $db->execute ($sql, $values);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return false;
+ }
+
+ return true;
+}
+
+function um_db_delete_package ($id_package) {
+ global $db;
+
+ $package = um_db_get_package ($id_package);
+ if ($package->status != 'development') {
+ echo 'Error: '.'Only packages in development state can be deleted';
+ return false;
+ }
+
+ $sql =& $db->prepare ('DELETE FROM tupdate_package WHERE id = ?');
+ $result =& $db->execute ($sql, $id_package);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return false;
+ }
+
+ return true;
+}
+
+function um_db_get_package ($id_package) {
+ global $db;
+
+ $sql =& $db->prepare ('SELECT * FROM tupdate_package WHERE id = ? LIMIT 1');
+ $result =& $db->execute ($sql, $id_package);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return NULL;
+ }
+ $result->fetchInto ($package);
+
+ return $package;
+}
+
+function um_db_get_all_packages () {
+ global $db;
+
+ $result =& $db->query ('SELECT * FROM tupdate_package');
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return array ();
+ }
+ $packages = array ();
+ while ($result->fetchInto ($package)) {
+ $packages[$package->id] = $package;
+ }
+
+ return $packages;
+}
+
+function um_db_get_package_updates ($id_package) {
+ global $db;
+
+ $sql =& $db->prepare ('SELECT * FROM tupdate WHERE id_update_package = ?');
+ $result =& $db->execute ($sql, $id_package);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return NULL;
+ }
+ $updates = array ();
+ while ($result->fetchInto ($update)) {
+ $updates[$update->id] = $update;
+ }
+
+ return $updates;
+}
+
+function um_db_create_package_log ($id_package, $id_auth, $ip_address = '') {
+ global $db;
+
+ $values = array ($id_package, $id_auth, $ip_address);
+ $sql =& $db->prepare ('INSERT INTO tupdate_package_log (id_update_package, id_auth, ip_address) VALUES (?, ?, ?)');
+ $result =& $db->execute ($sql, $values);
+ if (PEAR::isError ($result)) {
+ return false;
+ }
+ return true;
+}
+
+function um_db_create_component ($type, $name, $path = '') {
+ global $db;
+
+ $values = array ($type, $name, $path);
+ $sql =& $db->prepare ('INSERT INTO tupdate_component (type, name, path) VALUES (?, ?, ?)');
+ $result =& $db->execute ($sql, $values);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return false;
+ }
+ return true;
+}
+
+function um_db_update_component ($name, $path = '') {
+ global $db;
+
+ $values = array ($path, $name);
+
+ $sql =& $db->prepare ('UPDATE tupdate_component SET path = ? WHERE name = ?');
+ $result =& $db->execute ($sql, $values);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return false;
+ }
+
+ return true;
+}
+
+function um_db_delete_component ($name) {
+ global $db;
+
+ $sql =& $db->prepare ('DELETE FROM tupdate_component WHERE name = ?');
+ $result =& $db->execute ($sql, $name);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return false;
+ }
+
+ return true;
+}
+
+function um_db_get_component ($name) {
+ global $db;
+
+ $sql =& $db->prepare ('SELECT * FROM tupdate_component WHERE name = ? LIMIT 1');
+ $result =& $db->execute ($sql, $name);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return NULL;
+ }
+ $result->fetchInto ($component);
+
+ return $component;
+}
+
+function um_db_get_all_components ($type = '') {
+ global $db;
+
+ if ($type != '') {
+ $sql =& $db->prepare ('SELECT * FROM tupdate_component WHERE type = ?');
+ $result =& $db->execute ($sql, $type);
+ } else {
+ $result =& $db->query ('SELECT * FROM tupdate_component');
+ }
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return array ();
+ }
+ $components = array ();
+ while ($result->fetchInto ($component)) {
+ $components[$component->name] = $component;
+ }
+
+ return $components;
+}
+
+function um_db_create_component_db ($table_name, $field_name, $order, $component_name) {
+ global $db;
+
+ $values = array ($table_name, $field_name, $order, $component_name);
+ $sql =& $db->prepare ('INSERT INTO tupdate_component_db (table_name, field_name, `order`, component) VALUES (?, ?, ?, ?)');
+ $result =& $db->execute ($sql, $values);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return false;
+ }
+
+ return true;
+}
+
+function um_db_update_component_db ($id, $table_name = '', $field_name = '', $order = '') {
+ global $db;
+
+ $values = array ($table_name, $field_name, $order, $id);
+ $sql =& $db->prepare ('UPDATE tupdate_component_db SET table_name = ?, field_name = ?, `order` = ? WHERE id = ?');
+ $result =& $db->execute ($sql, $values);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return false;
+ }
+
+ return true;
+}
+
+function um_db_delete_component_db ($id) {
+ global $db;
+
+ $sql =& $db->prepare ('DELETE FROM tupdate_component_db WHERE id = ?');
+ $result =& $db->execute ($sql, $id);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return false;
+ }
+
+ return true;
+}
+
+function um_db_get_component_db ($id_component_db) {
+ global $db;
+
+ $sql =& $db->prepare ('SELECT * FROM tupdate_component_db WHERE id = ? LIMIT 1');
+ $result =& $db->execute ($sql, $id_component_db);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return NULL;
+ }
+ $result->fetchInto ($component);
+
+ return $component;
+}
+
+function um_db_get_database_components ($component_name) {
+ global $db;
+
+ $sql =& $db->prepare ('SELECT * FROM tupdate_component_db WHERE component = ? ORDER BY `order` ASC');
+ $result =& $db->execute ($sql, $component_name);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return NULL;
+ }
+ $components = array ();
+ while ($result->fetchInto ($component)) {
+ $components[$component->id] = $component;
+ }
+
+ return $components;
+}
+
+function um_db_create_auth ($client_key, $subscription_limit, $description = '', $developer = false) {
+ global $db;
+
+ if (! is_numeric ($subscription_limit)) {
+ echo 'Error: Subscription must be numeric
';
+ return false;
+ }
+ $values = array ($client_key, $subscription_limit, $description, $developer);
+ $sql =& $db->prepare ('INSERT INTO tupdate_auth (client_key, subscription_limit, description, developer) VALUES (?, ?, ?, ?)');
+ $result =& $db->execute ($sql, $values);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return false;
+ }
+ return true;
+}
+
+function um_db_update_auth ($id_auth, $client_key, $subscription_limit, $description = '', $developer = false) {
+ global $db;
+
+ if (! is_numeric ($subscription_limit)) {
+ echo 'Error: Subscription must be numeric
';
+ return false;
+ }
+ $values = array ($client_key, $subscription_limit, $description,
+ $developer, $id_auth);
+ $sql =& $db->prepare ('UPDATE tupdate_auth SET client_key = ?, subscription_limit = ?, description = ?, developer = ? WHERE id = ?');
+ $result =& $db->execute ($sql, $values);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return false;
+ }
+
+ return true;
+}
+
+function um_db_delete_auth ($id_auth) {
+ global $db;
+
+ $sql =& $db->prepare ('DELETE FROM tupdate_auth WHERE id = ?');
+ $result =& $db->execute ($sql, $id_auth);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return false;
+ }
+
+ return true;
+}
+
+function um_db_get_auth ($id_auth) {
+ global $db;
+
+ $sql =& $db->prepare ('SELECT * FROM tupdate_auth WHERE id = ? LIMIT 1');
+ $result =& $db->execute ($sql, $id_auth);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return NULL;
+ }
+ $result->fetchInto ($auth);
+
+ return $auth;
+}
+
+function um_db_get_all_auths () {
+ global $db;
+
+ $result =& $db->query ('SELECT * FROM tupdate_auth');
+
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return array ();
+ }
+ $auths = array ();
+ while ($result->fetchInto ($auth)) {
+ $auths[$auth->id] = $auth;
+ }
+
+ return $auths;
+}
+
+function um_db_check_auth ($client_key, $subscription_limit) {
+ global $db;
+
+ $sql =& $db->prepare ('SELECT * FROM tupdate_auth WHERE client_key = ? LIMIT 1');
+ $result =& $db->execute ($sql, $client_key);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return false;
+ }
+ $result->fetchInto ($auth);
+ if (! $auth)
+ return false;
+
+ if ($auth->developer == 1)
+ return $auth->id;
+
+ if ($auth->subscription_limit >= $subscription_limit)
+ return $auth->id;
+ return false;
+}
+
+function um_db_is_auth_developer ($id_auth) {
+ global $db;
+
+ $developer =& $db->getOne ('SELECT developer FROM tupdate_auth WHERE id = ? LIMIT 1', $id_auth);
+ if (PEAR::isError ($developer)) {
+ echo 'Error: '.$developer->getMessage ().'
';
+ return false;
+ }
+ return (bool) $developer;
+}
+
+function um_db_connect ($backend = 'mysql', $host = '', $user = '', $password = '', $db_name = '') {
+ static $db = NULL;
+
+ if ($db)
+ return $db;
+
+ $dsn = $backend.'://'.$user.':'.$password.'@'.$host.'/'.$db_name;
+ $db =& DB::Connect ($dsn, array ());
+ if (PEAR::isError ($db)) {
+ echo 'Error: '.$db->getMessage ().'
';
+ die;
+ }
+ $db->setFetchMode (DB_FETCHMODE_OBJECT);
+
+ return $db;
+}
+
+function um_component_db_connect () {
+ $settings = um_db_load_settings ();
+
+ $dsn = 'mysql://'.$settings->dbuser.':'.$settings->dbpass.'@'.$settings->dbhost.'/'.$settings->dbname;
+ $db =& DB::Connect ($dsn, array ());
+ if (PEAR::isError ($db)) {
+ return false;
+ }
+ $db->setFetchMode (DB_FETCHMODE_ORDERED);
+
+ return $db;
+}
+
+function um_get_package_status () {
+ $status = array ();
+
+ $status['development'] = 'Development';
+ $status['testing'] = 'Testing';
+ $status['public'] = 'Public';
+ $status['disabled'] = 'Disabled';
+
+ return $status;
+}
+
+function um_get_component_types () {
+ $types = array ();
+
+ $types['database'] = 'Database';
+ $types['directory'] = 'Code / binary directory';
+
+ return $types;
+}
+?>
diff --git a/pandora_console/extensions/update_manager/lib/libupdate_manager_client.php b/pandora_console/extensions/update_manager/lib/libupdate_manager_client.php
new file mode 100644
index 0000000000..68ecd32e81
--- /dev/null
+++ b/pandora_console/extensions/update_manager/lib/libupdate_manager_client.php
@@ -0,0 +1,333 @@
+PEAR::XML_RPC not found. Please install it with: pear install XML_RPC
');
+error_reporting ($prev_level);
+unset ($prev_level);
+
+define ('XMLRPC_DEBUG', 0);
+
+function um_xml_rpc_client_call ($server_host, $server_path, $server_port, $function, $parameters) {
+ $msg = new XML_RPC_Message ($function, $parameters);
+ $client = new XML_RPC_Client ($server_path, $server_host, $server_port);
+ if (defined ('XMLRPC_DEBUG'))
+ $client->setDebug (XMLRPC_DEBUG);
+ $result = $client->send ($msg);
+
+ if (! $result) {
+ trigger_error ('Open Update Manager Server comunication error. '.$client->errstr);
+ return false;
+ }
+ if ($result->faultCode ()) {
+ trigger_error ('Open Update Manager XML-RPC error. '.$result->faultString ());
+ return false;
+ }
+
+ return $result;
+}
+
+function um_xml_rpc_unpack_update ($update_xml_rpc) {
+ if ($update_xml_rpc->kindOf () != 'struct') {
+ return false;
+ }
+
+ $update = new stdClass ();
+ $value = $update_xml_rpc->structeach ();
+ while ($value) {
+ $update->$value['key'] = $value[1]->scalarval ();
+ $value = $update_xml_rpc->structeach ();
+ }
+
+ return $update;
+}
+
+function um_xml_rpc_unpack_package ($package_xml_rpc) {
+ if ($package_xml_rpc->kindOf () != 'struct') {
+ return false;
+ }
+
+ $package = new stdClass ();
+ $value = $package_xml_rpc->structeach ();
+ while ($value) {
+ $package->$value['key'] = $value[1]->scalarval ();
+ $value = $package_xml_rpc->structeach ();
+ }
+
+ if (! isset ($package->updates))
+ return $package;
+
+ $package->updates = array ();
+ $updates = $package_xml_rpc->structmem ('updates');
+ $size = $updates->arraysize ();
+ for ($i = 0; $i < $size; $i++) {
+ $update = um_xml_rpc_unpack_update ($updates->arraymem ($i));
+ $update->id_update_package = $package->id;
+ array_push ($package->updates, $update);
+ }
+
+ return $package;
+}
+
+function um_client_check_latest_update ($settings, $user_key) {
+ $params = array (new XML_RPC_Value ($settings->customer_key, 'string'),
+ new XML_RPC_Value ($user_key, 'string'),
+ new XML_RPC_Value ($settings->current_update, 'int'));
+ $result = um_xml_rpc_client_call ($settings->update_server_host,
+ $settings->update_server_path,
+ $settings->update_server_port,
+ 'get_latest_package', $params);
+
+ if ($result === false) {
+ return false;
+ }
+
+ $value = $result->value ();
+ if ($value->kindOf () == 'scalar') {
+ /* No new updates */
+ return $value->scalarval ();
+ }
+
+ $package = um_xml_rpc_unpack_package ($value);
+
+ return $package;
+}
+
+function um_client_get_package ($settings, $user_key) {
+ $params = array (new XML_RPC_Value ($settings->customer_key, 'string'),
+ new XML_RPC_Value ($user_key, 'string'),
+ new XML_RPC_Value ($settings->current_update, 'int'));
+ $result = um_xml_rpc_client_call ($settings->update_server_host,
+ $settings->update_server_path,
+ $settings->update_server_port,
+ 'get_next_package', $params);
+
+ if ($result === false)
+ return false;
+
+ $value = $result->value ();
+ if ($value->kindOf () == 'scalar') {
+ /* No new updates */
+ return (bool) $value->scalarval ();
+ }
+
+ $package = um_xml_rpc_unpack_package ($value);
+
+ return $package;
+}
+
+function um_client_db_save_package ($package) {
+ global $db;
+
+ $fields = array ('id' => $package->id,
+ 'description' => $package->description);
+ $replace = array ();
+ for ($i = 0; $i < sizeof ($fields); $i++) {
+ $replace[] = '?';
+ }
+
+ $sql =& $db->prepare ('INSERT INTO tupdate_package ('.implode(',', array_keys (&$fields)).') VALUES ('.implode(',', &$replace).')');
+ $result =& $db->execute ($sql, $fields);
+ if (PEAR::isError ($result)) {
+ return false;
+ }
+ return true;
+}
+
+function um_client_db_save_update ($update) {
+ global $db;
+
+ $fields = array_keys (get_object_vars (&$update));
+ $values = array_values (get_object_vars (&$update));
+ $replace = array ();
+ for ($i = 0; $i < sizeof ($values); $i++) {
+ $replace[] = '?';
+ }
+
+ $sql =& $db->prepare ('INSERT INTO tupdate ('.implode(',', &$fields).') VALUES ('.implode(',', &$replace).')');
+ $result =& $db->execute ($sql, $values);
+ if (PEAR::isError ($result)) {
+ return false;
+ }
+ return true;
+}
+
+function um_client_apply_update_file ($update, $destiny_filename, $force = false) {
+ if (! is_writable ($destiny_filename)) {
+ return false;
+ }
+
+ if (file_exists ($destiny_filename)) {
+ $checksum = md5_file ($destiny_filename);
+ if (! $force &&$update->previous_checksum != '') {
+ if ($update->previous_checksum != $checksum)
+ /* Local changes in the file. Don't update */
+ return false;
+ }
+ $content = file_get_contents ($destiny_filename);
+ $update->data_rollback = convert_uuencode ($content);
+ $update->previous_checksum = $checksum;
+ }
+ $result = file_put_contents ($destiny_filename, convert_uudecode ($update->data));
+
+ if ($result === false) {
+ return false;
+ }
+ return true;
+}
+
+function um_client_apply_update_database ($update, $db) {
+ if ($update->type == 'db_data') {
+ $values = array ($update->db_table,
+ $update->db_field,
+ $update->db_field_value);
+ $exists =& $db->getOne ('SELECT COUNT(*) FROM `!` WHERE ? = ?', $values);
+ if (PEAR::isError ($exists)) {
+ return false;
+ }
+ /* If it exists, it failed. */
+ if ($exists)
+ return false;
+ }
+
+ $result =& $db->query ($update->data);
+ if (PEAR::isError ($result)) {
+ echo $result->getMessage ();
+ return false;
+ }
+ return true;
+}
+
+function um_client_apply_update ($update, $settings, $db, $force = false) {
+ if ($update->type == 'code') {
+ $filename = realpath ($settings->updating_code_path.'/'.$update->filename);
+ $success = um_client_apply_update_file (&$update, &$filename, $force);
+ } else if ($update->type == 'binary') {
+ $filename = realpath ($settings->updating_binary_path.'/'.$update->filename);
+ $success = um_client_apply_update_file (&$update, &$filename);
+ } else if ($update->type == 'db_data' || $update->type == 'db_schema') {
+ $success = um_client_apply_update_database (&$update, &$db);
+ } else {
+ return false;
+ }
+
+ if (! $success)
+ return false;
+ return true;
+}
+
+function um_client_rollback_update_file ($update, $destiny_filename) {
+ /* If there's no data rollback, we suppose it's a new file, so it should
+ not be a problem. In any case, it's better than deleting the file. */
+ if (! isset ($update->data_rollback))
+ return true;
+
+ $result = file_put_contents ($destiny_filename, convert_uudecode ($update->data_rollback));
+
+ if ($result === false)
+ return false;
+ return true;
+}
+
+function um_client_rollback_update ($update, $settings, $db) {
+ if ($update->type == 'code') {
+ $filename = realpath ($settings->updating_code_path.'/'.$update->filename);
+ $success = um_client_rollback_update_file (&$update, &$filename);
+ } else if ($update->type == 'binary') {
+ $filename = realpath ($settings->updating_binary_path.'/'.$update->filename);
+ $success = um_client_rollback_update_file (&$update, &$filename);
+ } else if ($update->type == 'db_data' || $update->type == 'db_schema') {
+ $db->rollback ();
+ $success = true;
+ } else {
+ return false;
+ }
+
+ return $success;
+}
+
+function um_client_print_update ($update, $settings) {
+ echo 'Update #'.$update->id;
+ echo '';
+ echo '- Type: '.$update->type.'
';
+ if ($update->type == 'code' || $update->type == 'binary') {
+ $realpath = realpath ($settings->updating_code_path.'/'.$update->filename);
+ echo '- Filename: '.$update->filename.'
';
+ echo '- Realpath: '.$realpath.'
';
+ echo '- Checksum: '.$update->checksum.'
';
+ echo '- Writable: '.(is_writable ($realpath) ? 'yes' : 'no').'
';
+ } else {
+ echo '- Table: '.$update->db_table.'
';
+ echo '- Field: '.$update->db_field.'
';
+ echo '- Value: '.$update->db_field_value.'
';
+ echo '- Data: '.$update->data.'
';
+ }
+ echo '
';
+}
+
+function um_client_upgrade_to_package ($package, $settings, $force = false) {
+ $applied_updates = array ();
+ $rollback = false;
+
+ $db = um_client_db_connect (&$settings);
+ if ($db === false)
+ return false;
+ foreach ($package->updates as $update) {
+ $success = um_client_apply_update (&$update, &$settings, &$db, $force);
+ if (! $success) {
+ echo 'Failed on:
';
+ um_client_print_update ($update, $settings);
+ $rollback = true;
+ break;
+ }
+ array_push ($applied_updates, $update);
+ }
+
+ if ($rollback) {
+ foreach ($applied_updates as $update) {
+ $success = um_client_rollback_update (&$update, &$settings, &$db);
+ }
+ return false;
+ }
+ $db->commit ();
+ um_client_db_save_package ($package);
+ foreach ($package->updates as $update) {
+ um_client_db_save_update ($update);
+ }
+
+ um_db_update_setting ('current_update', $package->id);
+ return true;
+}
+
+function um_client_upgrade_to_latest ($user_key, $force) {
+ $settings = um_db_load_settings ();
+ do {
+ $package = um_client_get_package ($settings, $user_key);
+ if ($package === false || $package === true)
+ break;
+ $success = um_client_upgrade_to_package ($package, $settings, $force);
+ if (! $success)
+ break;
+
+
+ $settings->current_update = $package->id;
+ } while (1);
+ /* Break on error, when there are no more packages on the server (server return true)
+ or on auth failure (server return false) */
+}
+
+function um_client_db_connect ($settings = NULL) {
+ if (! $settings)
+ $settings = um_db_load_settings ();
+
+ $dsn = 'mysql://'.$settings->dbuser.':'.$settings->dbpass.'@'.$settings->dbhost.'/'.$settings->dbname;
+ $db =& DB::Connect ($dsn, array ());
+ if (PEAR::isError ($db)) {
+ return false;
+ }
+ $db->setFetchMode (DB_FETCHMODE_ASSOC);
+ $db->autoCommit (false);
+
+ return $db;
+}
+?>
diff --git a/pandora_console/extensions/update_manager/lib/libupdate_manager_components.php b/pandora_console/extensions/update_manager/lib/libupdate_manager_components.php
new file mode 100644
index 0000000000..a4e587fd55
--- /dev/null
+++ b/pandora_console/extensions/update_manager/lib/libupdate_manager_components.php
@@ -0,0 +1,119 @@
+setFetchMode (DB_FETCHMODE_OBJECT);
+
+ $fields = um_component_database_get_table_fields ($component_db->table_name);
+ $sql =& $db->prepare ('SELECT '.implode (',', $fields).' FROM !');
+ $result =& $db->execute ($sql, $component_db->table_name);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return NULL;
+ }
+ $resultdata = array ();
+ $field = $component_db->field_name;
+ while ($result->fetchInto ($data)) {
+ $update = um_update_get_last_from_table_field_value ($component_db->component,
+ $component_db->id,
+ $data->$field);
+ if ($update && $update->db_field_value == $data->$field)
+ continue;
+ array_push ($resultdata, $data);
+ }
+
+ return $resultdata;
+}
+
+function um_component_database_get_all_tables () {
+ $db = um_component_db_connect ();
+
+ if ($db === false) {
+ return array ();
+ }
+
+ $result =& $db->query ('SHOW TABLES');
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return array ();
+ }
+ $tables = array ();
+ while ($result->fetchInto ($table)) {
+ array_push ($tables, $table[0]);
+ }
+
+ return $tables;
+}
+
+function um_component_database_get_available_tables ($component_name) {
+ $all_tables = um_component_database_get_all_tables ();
+ $components_db = um_db_get_database_components ($component_name);
+ $defined_tables = array ();
+ foreach ($components_db as $component_db) {
+ array_push ($defined_tables, $component_db->table_name);
+ }
+
+ return array_diff ($all_tables, $defined_tables);
+}
+
+function um_component_database_get_table_fields ($table_name) {
+ $db = um_component_db_connect ();
+
+ if ($db === false) {
+ return array ();
+ }
+
+ $sql =& $db->prepare ('SHOW COLUMNS FROM ! WHERE `Key` \!= "PRI"');
+ $result =& $db->execute ($sql, $table_name);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return array ();
+ }
+
+ $fields = array ();
+ while ($result->fetchInto ($field)) {
+ array_push ($fields, $field[0]);
+ }
+ return $fields;
+}
+
+function um_component_directory_get_all_files ($component, $binary = false) {
+ if (! $component || ! isset ($component->path)) {
+ return array ();
+ }
+
+ if (! is_dir ($component->path)) {
+ return array ();
+ }
+
+ $path = $component->path;
+ if (substr ($path, -1) != '/')
+ $path .= "/";
+ $files = directory_to_array ($path,
+ array ('.svn', '.cvs', '.git', '.', '..' ), $binary);
+
+ return $files;
+}
+
+function um_component_directory_get_modified_files ($component, $binary = false) {
+ $all_files = um_component_directory_get_all_files ($component, $binary);
+
+ $files = array ();
+ foreach ($all_files as $file) {
+ $last_update = um_update_get_last_from_filename ($component->name, $file);
+ if ($last_update) {
+ $checksum = md5_file (realpath ($component->path.'/'.$file));
+ if ($last_update->checksum == $checksum)
+ continue;
+ }
+
+ array_push ($files, $file);
+ }
+
+ return $files;
+}
+?>
diff --git a/pandora_console/extensions/update_manager/lib/libupdate_manager_updates.php b/pandora_console/extensions/update_manager/lib/libupdate_manager_updates.php
new file mode 100644
index 0000000000..fd91ed55fd
--- /dev/null
+++ b/pandora_console/extensions/update_manager/lib/libupdate_manager_updates.php
@@ -0,0 +1,154 @@
+prepare ('SELECT * FROM tupdate WHERE component = ? AND filename = ? ORDER BY id DESC LIMIT 1');
+ $result =& $db->execute ($sql, $values);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return NULL;
+ }
+ $result->fetchInto ($update);
+ return $update;
+}
+
+function um_update_get_last_from_table_field_value ($component_name, $id_component_db, $field_value) {
+ global $db;
+
+ $values = array ($component_name, $id_component_db, $field_value);
+ $sql =& $db->prepare ('SELECT * FROM tupdate WHERE component = ? AND id_component_db = ? AND db_field_value = ? ORDER BY id DESC LIMIT 1');
+ $result =& $db->execute ($sql, $values);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return NULL;
+ }
+ $result->fetchInto ($update);
+ return $update;
+}
+
+function um_db_get_orphan_updates () {
+ global $db;
+
+ $result =& $db->query ('SELECT * FROM tupdate WHERE id_update_package IS NULL');
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return NULL;
+ }
+ $updates = array ();
+ while ($result->fetchInto ($update)) {
+ $updates[$update['id']] = $update;
+ }
+ return $updates;
+}
+
+function um_db_get_update ($id_update) {
+ global $db;
+
+ $sql =& $db->prepare ('SELECT * FROM tupdate WHERE id = ? LIMIT 1');
+ $result =& $db->execute ($sql, $id_update);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return NULL;
+ }
+ $result->fetchInto ($update);
+
+ return $update;
+}
+
+function um_db_delete_update ($id_update) {
+ global $db;
+
+ $update = um_db_get_update ($id_update);
+ $package = um_db_get_package ($update->id_update_package);
+ if ($package->status != 'development') {
+ echo 'Error: '.'Only packages in development state can be deleted';
+ return false;
+ }
+
+ $sql =& $db->prepare ('DELETE FROM tupdate WHERE id = ?');
+ $result =& $db->execute ($sql, $id_update);
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return false;
+ }
+ return true;
+}
+
+function um_db_create_update ($type, $component_name, $id_package, $update, $db_data = NULL) {
+ global $db;
+
+ if ($id_package == 0)
+ return false;
+ $component = um_db_get_component ($component_name);
+ $values = array ('type' => $type,
+ 'component' => $component_name,
+ 'id_update_package' => $id_package);
+ switch ($type) {
+ case 'code':
+ $filepath = realpath ($component->path.'/'.$update->filename);
+ $values['svn_version'] = um_file_get_svn_revision ($filepath);
+ case 'binary':
+ $last_update = um_update_get_last_from_filename ($component_name, $update->filename);
+ $filepath = realpath ($component->path.'/'.$update->filename);
+ $values['checksum'] = md5_file ($filepath);
+ if ($last_update && $last_update->checksum == $values['checksum']) {
+ return false;
+ }
+ $values['filename'] = $update->filename;
+ $values['data'] = um_file_uuencode ($filepath);
+ if ($last_update && $last_update->checksum != '')
+ $values['previous_checksum'] = $last_update->checksum;
+
+ break;
+ case 'db_data':
+ if ($db_data === NULL)
+ return false;
+ $component_db = um_db_get_component_db ($update->id_component_db);
+ $field = $component_db->field_name;
+ $values['db_field_value'] = $db_data->$field;
+ $values['id_component_db'] = $update->id_component_db;
+ $values['data'] = 'INSERT INTO `'.$component_db->table_name.'` (`'.implode('`,`', array_keys (get_object_vars ($db_data))).'`) VALUES (\''.implode('\',\'', get_object_vars ($db_data)).'\')';
+
+ break;
+ case 'db_schema':
+ $values['data'] = $update->data;
+
+ break;
+ default:
+ return false;
+ }
+ $replace = array ();
+ for ($i = 0; $i < sizeof ($values); $i++) {
+ $replace[] = '?';
+ }
+ $sql =& $db->prepare ('INSERT INTO tupdate ('.implode(',', array_keys ($values)).') VALUES ('.implode(',', $replace).')');
+ $result =& $db->execute ($sql, array_values ($values));
+ if (PEAR::isError ($result)) {
+ echo 'Error: '.$result->getMessage ().'
';
+ return false;
+ }
+ return true;
+}
+
+function um_get_update_types () {
+ $types = array ();
+
+ $types['code'] = 'Code';
+ $types['db_data'] = 'Database data';
+ $types['db_schema'] = 'Database schema';
+ $types['binary'] = 'Binary file';
+
+ return $types;
+}
+
+function um_file_get_svn_revision ($file) {
+ return (int) exec ('svn info '.$file.'| grep "Revis" | head -1 | cut -f2 -d":"');
+}
+
+function um_file_uuencode ($file) {
+ $content = file_get_contents ($file);
+ return convert_uuencode ($content);
+}
+?>
diff --git a/pandora_console/extensions/update_manager/lib/libupdate_manager_utils.php b/pandora_console/extensions/update_manager/lib/libupdate_manager_utils.php
new file mode 100644
index 0000000000..a3836bc4e9
--- /dev/null
+++ b/pandora_console/extensions/update_manager/lib/libupdate_manager_utils.php
@@ -0,0 +1,62 @@
+
diff --git a/pandora_console/extensions/update_manager/lib/load_updatemanager.php b/pandora_console/extensions/update_manager/lib/load_updatemanager.php
new file mode 100644
index 0000000000..41494cb595
--- /dev/null
+++ b/pandora_console/extensions/update_manager/lib/load_updatemanager.php
@@ -0,0 +1,18 @@
+
diff --git a/pandora_console/extensions/update_manager/load_updatemanager.php b/pandora_console/extensions/update_manager/load_updatemanager.php
new file mode 100644
index 0000000000..1d3546be4a
--- /dev/null
+++ b/pandora_console/extensions/update_manager/load_updatemanager.php
@@ -0,0 +1,17 @@
+
diff --git a/pandora_console/extensions/update_manager/main.php b/pandora_console/extensions/update_manager/main.php
new file mode 100644
index 0000000000..61ce0bd461
--- /dev/null
+++ b/pandora_console/extensions/update_manager/main.php
@@ -0,0 +1,97 @@
+'.__('Update manager').'';
+
+if (! file_exists ($settings->keygen_path)) {
+ echo ''.__('Keygen file does not exists')."
";
+ return;
+}
+
+if (! is_executable ($settings->keygen_path)) {
+ echo ''.__('Keygen is not executable')."
";
+ return;
+}
+
+$user_key = exec ($settings->keygen_path);
+
+$update_package = (bool) get_parameter_post ('update_package');
+
+if ($update_package) {
+ echo 'Updating...';
+ flush ();
+ $force = (bool) get_parameter_post ('force_update');
+ um_client_upgrade_to_latest ($user_key, $force);
+ /* TODO: Meter una noticia en tnews*/
+}
+
+$settings = um_db_load_settings ();
+$package = um_client_check_latest_update ($settings, $user_key);
+
+if (is_int ($package) && $package == 1) {
+ echo ''.__('Your system is up-to-date').'.
';
+} elseif ($package === false) {
+ echo ''.__('Server connection failed')."
";
+} elseif (is_int ($package) && $package == 0) {
+ echo ''.__('Server authorization rejected')."
";
+} else {
+ echo ''.__('There\'s a new update for Pandora')."
";
+
+ $table->width = '50%';
+ $table->data = array ();
+
+ $table->data[0][0] = ''.__('Id').'';
+ $table->data[0][1] = $package->id;
+
+ $table->data[1][0] = ''.__('Timestamp').'';
+ $table->data[1][1] = $package->timestamp;
+
+ $table->data[2][0] = ''.__('Description').'';
+ $table->data[2][1] = html_entity_decode ($package->description);
+
+ print_table ($table);
+ echo '';
+}
+
+echo ''.__('Your system version number is').': '.$settings->current_update.'
';
+
+?>
diff --git a/pandora_console/extensions/update_manager/settings.php b/pandora_console/extensions/update_manager/settings.php
new file mode 100644
index 0000000000..3fa27e4c58
--- /dev/null
+++ b/pandora_console/extensions/update_manager/settings.php
@@ -0,0 +1,74 @@
+ $value) {
+ um_db_update_setting ($key, $value);
+ }
+ echo "".__('Update manager settings updated')."
";
+}
+
+$settings = um_db_load_settings ();
+
+echo ''.__('Settings').'
';
+echo '';
+
+?>
diff --git a/pandora_console/extensions/update_manager/sql/update_manager.sql b/pandora_console/extensions/update_manager/sql/update_manager.sql
new file mode 100644
index 0000000000..57eb6f1588
--- /dev/null
+++ b/pandora_console/extensions/update_manager/sql/update_manager.sql
@@ -0,0 +1,5 @@
+CREATE TABLE `tupdate_settings` ( `key` varchar(255) default '', `value` varchar(255) default '', PRIMARY KEY (`key`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+INSERT INTO `tupdate_settings` VALUES ('current_update', '0'), ('customer_key', 'Insert your customer key here'), ('keygen_path', ''), ('update_server_host', ''), ('update_server_port', '80'), ('update_server_path', ''), ('updating_binary_path', 'Path where the updated binary files will be stored'), ('updating_code_path', 'Path where the updated code is stored'), ('dbname', ''), ('dbhost', ''), ('dbpass', ''), ('dbuser', '');
+CREATE TABLE `tupdate_package` ( id int(11) unsigned NOT NULL auto_increment, timestamp datetime NOT NULL, description mediumtext NOT NULL default '', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+CREATE TABLE `tupdate` ( id int(11) unsigned NOT NULL auto_increment, type enum('code', 'db_data', 'db_schema', 'binary'), id_update_package int(11) unsigned NOT NULL default 0, filename varchar(250) default '', checksum varchar(250) default '', previous_checksum varchar(250) default '', svn_version int(4) unsigned NOT NULL default 0, data LONGTEXT default '', data_rollback LONGTEXT default '', description TEXT default '', db_table_name varchar(140) default '', db_field_name varchar(140) default '', db_field_value varchar(1024) default '', PRIMARY KEY (`id`), FOREIGN KEY (`id_update_package`) REFERENCES tupdate_package(`id`) ON UPDATE CASCADE ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+CREATE TABLE `tupdate_journal` ( id int(11) unsigned NOT NULL auto_increment, id_update int(11) unsigned NOT NULL default 0, PRIMARY KEY (`id`), FOREIGN KEY (`id_update`) REFERENCES tupdate(`id`) ON UPDATE CASCADE ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8;