/**
  * Installs new themes, either from a gzip or copy of the default.
  *
  * What it does:
  * - Puts themes in $boardurl/themes.
  * - Assumes the gzip has a root directory in it. (ie default.)
  * - Requires admin_forum.
  * - Accessed with ?action=admin;area=theme;sa=install.
  *
  * @uses ManageThemes template
  */
 public function action_install()
 {
     global $boardurl, $txt, $context, $settings, $modSettings;
     checkSession('request');
     require_once SUBSDIR . '/Themes.subs.php';
     require_once SUBSDIR . '/Package.subs.php';
     loadTemplate('ManageThemes');
     // Passed an ID, then the install is complete, lets redirect and show them
     if (isset($_GET['theme_id'])) {
         $_GET['theme_id'] = (int) $_GET['theme_id'];
         $context['sub_template'] = 'installed';
         $context['page_title'] = $txt['theme_installed'];
         $context['installed_theme'] = array('id' => $_GET['theme_id'], 'name' => getThemeName($_GET['theme_id']));
         return;
     }
     // How are we going to install this theme, from a dir, zip, copy of default?
     if (!empty($_FILES['theme_gz']) && (!isset($_FILES['theme_gz']['error']) || $_FILES['theme_gz']['error'] != 4) || !empty($_REQUEST['theme_gz'])) {
         $method = 'upload';
     } elseif (isset($_REQUEST['theme_dir']) && rtrim(realpath($_REQUEST['theme_dir']), '/\\') != realpath(BOARDDIR . '/themes') && file_exists($_REQUEST['theme_dir'])) {
         $method = 'path';
     } else {
         $method = 'copy';
     }
     // Copy the default theme?
     if (!empty($_REQUEST['copy']) && $method == 'copy') {
         // Hopefully the themes directory is writable, or we might have a problem.
         if (!is_writable(BOARDDIR . '/themes')) {
             fatal_lang_error('theme_install_write_error', 'critical');
         }
         // Make the new directory, standard characters only
         $theme_dir = BOARDDIR . '/themes/' . preg_replace('~[^A-Za-z0-9_\\- ]~', '', $_REQUEST['copy']);
         umask(0);
         mkdir($theme_dir, 0777);
         // Get some more time if we can
         @set_time_limit(600);
         if (function_exists('apache_reset_timeout')) {
             @apache_reset_timeout();
         }
         // Create the subdirectories for css, javascript and font files.
         mkdir($theme_dir . '/css', 0777);
         mkdir($theme_dir . '/scripts', 0777);
         mkdir($theme_dir . '/webfonts', 0777);
         // Copy over the default non-theme files.
         $to_copy = array('/index.php', '/index.template.php', '/scripts/theme.js');
         foreach ($to_copy as $file) {
             copy($settings['default_theme_dir'] . $file, $theme_dir . $file);
             @chmod($theme_dir . $file, 0777);
         }
         // And now the entire css, images and webfonts directories!
         copytree($settings['default_theme_dir'] . '/css', $theme_dir . '/css');
         copytree($settings['default_theme_dir'] . '/images', $theme_dir . '/images');
         copytree($settings['default_theme_dir'] . '/webfonts', $theme_dir . '/webfonts');
         package_flush_cache();
         $theme_name = $_REQUEST['copy'];
         $images_url = $boardurl . '/themes/' . basename($theme_dir) . '/images';
         $theme_dir = realpath($theme_dir);
         // Lets get some data for the new theme (default theme (1), default settings (0)).
         $theme_values = loadThemeOptionsInto(1, 0, array(), array('theme_templates', 'theme_layers'));
         // Lets add a theme_info.xml to this theme.
         write_theme_info($_REQUEST['copy'], $modSettings['elkVersion'], $theme_dir, $theme_values);
     } elseif (isset($_REQUEST['theme_dir']) && $method == 'path') {
         if (!is_dir($_REQUEST['theme_dir']) || !file_exists($_REQUEST['theme_dir'] . '/theme_info.xml')) {
             fatal_lang_error('theme_install_error', false);
         }
         $theme_name = basename($_REQUEST['theme_dir']);
         $theme_dir = $_REQUEST['theme_dir'];
     } elseif ($method == 'upload') {
         // Hopefully the themes directory is writable, or we might have a problem.
         if (!is_writable(BOARDDIR . '/themes')) {
             fatal_lang_error('theme_install_write_error', 'critical');
         }
         // This happens when the admin session is gone and the user has to login again
         if (empty($_FILES['theme_gz']) && empty($_REQUEST['theme_gz'])) {
             redirectexit('action=admin;area=theme;sa=admin;' . $context['session_var'] . '=' . $context['session_id']);
         }
         // Set the default settings...
         $theme_name = strtok(basename(isset($_FILES['theme_gz']) ? $_FILES['theme_gz']['name'] : $_REQUEST['theme_gz']), '.');
         $theme_name = preg_replace(array('/\\s/', '/\\.[\\.]+/', '/[^\\w_\\.\\-]/'), array('_', '.', ''), $theme_name);
         $theme_dir = BOARDDIR . '/themes/' . $theme_name;
         if (isset($_FILES['theme_gz']) && is_uploaded_file($_FILES['theme_gz']['tmp_name']) && (ini_get('open_basedir') != '' || file_exists($_FILES['theme_gz']['tmp_name']))) {
             read_tgz_file($_FILES['theme_gz']['tmp_name'], BOARDDIR . '/themes/' . $theme_name, false, true);
         } elseif (isset($_REQUEST['theme_gz'])) {
             if (!isAuthorizedServer($_REQUEST['theme_gz'])) {
                 fatal_lang_error('not_valid_server');
             }
             read_tgz_file($_REQUEST['theme_gz'], BOARDDIR . '/themes/' . $theme_name, false, true);
         } else {
             redirectexit('action=admin;area=theme;sa=admin;' . $context['session_var'] . '=' . $context['session_id']);
         }
     } else {
         fatal_lang_error('theme_install_general', false);
     }
     // Something go wrong?
     if ($theme_dir != '' && basename($theme_dir) != 'themes') {
         // Defaults.
         $install_info = array('theme_url' => $boardurl . '/themes/' . basename($theme_dir), 'images_url' => isset($images_url) ? $images_url : $boardurl . '/themes/' . basename($theme_dir) . '/images', 'theme_dir' => $theme_dir, 'name' => $theme_name);
         $explicit_images = false;
         if (file_exists($theme_dir . '/theme_info.xml')) {
             $theme_info = file_get_contents($theme_dir . '/theme_info.xml');
             // Parse theme-info.xml into an Xml_Array.
             require_once SUBSDIR . '/XmlArray.class.php';
             $theme_info_xml = new Xml_Array($theme_info);
             // @todo Error message of some sort?
             if (!$theme_info_xml->exists('theme-info[0]')) {
                 return 'package_get_error_packageinfo_corrupt';
             }
             $theme_info_xml = $theme_info_xml->path('theme-info[0]');
             $theme_info_xml = $theme_info_xml->to_array();
             $xml_elements = array('name' => 'name', 'theme_layers' => 'layers', 'theme_templates' => 'templates', 'based_on' => 'based-on');
             foreach ($xml_elements as $var => $name) {
                 if (!empty($theme_info_xml[$name])) {
                     $install_info[$var] = $theme_info_xml[$name];
                 }
             }
             if (!empty($theme_info_xml['images'])) {
                 $install_info['images_url'] = $install_info['theme_url'] . '/' . $theme_info_xml['images'];
                 $explicit_images = true;
             }
             if (!empty($theme_info_xml['extra'])) {
                 $install_info += unserialize($theme_info_xml['extra']);
             }
         }
         if (isset($install_info['based_on'])) {
             if ($install_info['based_on'] == 'default') {
                 $install_info['theme_url'] = $settings['default_theme_url'];
                 $install_info['images_url'] = $settings['default_images_url'];
             } elseif ($install_info['based_on'] != '') {
                 $install_info['based_on'] = preg_replace('~[^A-Za-z0-9\\-_ ]~', '', $install_info['based_on']);
                 $temp = loadBasedOnTheme($install_info['based_on'], $explicit_images);
                 // @todo An error otherwise?
                 if (is_array($temp)) {
                     $install_info = $temp + $install_info;
                     if (empty($explicit_images) && !empty($install_info['base_theme_url'])) {
                         $install_info['theme_url'] = $install_info['base_theme_url'];
                     }
                 }
             }
             unset($install_info['based_on']);
         }
         // Find the newest id_theme.
         $id_theme = nextTheme();
         $inserts = array();
         foreach ($install_info as $var => $val) {
             $inserts[] = array($id_theme, $var, $val);
         }
         if (!empty($inserts)) {
             addTheme($inserts);
         }
         updateSettings(array('knownThemes' => strtr($modSettings['knownThemes'] . ',' . $id_theme, array(',,' => ','))));
     }
     redirectexit('action=admin;area=theme;sa=install;theme_id=' . $id_theme . ';' . $context['session_var'] . '=' . $context['session_id']);
 }
 /**
  * Install a smiley set.
  */
 public function action_install()
 {
     global $modSettings, $scripturl, $context, $txt, $user_info;
     isAllowedTo('manage_smileys');
     checkSession('request');
     // One of these two may be necessary
     loadLanguage('Errors');
     loadLanguage('Packages');
     require_once SUBSDIR . '/Smileys.subs.php';
     require_once SUBSDIR . '/Package.subs.php';
     // Installing unless proven otherwise
     $testing = false;
     $destination = '';
     $name = '';
     if (isset($_REQUEST['set_gz'])) {
         $base_name = strtr(basename($_REQUEST['set_gz']), ':/', '-_');
         $name = Util::htmlspecialchars(strtok(basename($_REQUEST['set_gz']), '.'));
         $name_pr = preg_replace(array('/\\s/', '/\\.[\\.]+/', '/[^\\w_\\.\\-]/'), array('_', '.', ''), $name);
         $context['filename'] = $base_name;
         // Check that the smiley is from simplemachines.org, for now... maybe add mirroring later.
         if (!isAuthorizedServer($_REQUEST['set_gz']) == 0) {
             fatal_lang_error('not_valid_server');
         }
         $destination = BOARDDIR . '/packages/' . $base_name;
         if (file_exists($destination)) {
             fatal_lang_error('package_upload_error_exists');
         }
         // Let's copy it to the packages directory
         file_put_contents($destination, fetch_web_data($_REQUEST['set_gz']));
         $testing = true;
     } elseif (isset($_REQUEST['package'])) {
         $base_name = basename($_REQUEST['package']);
         $name = Util::htmlspecialchars(strtok(basename($_REQUEST['package']), '.'));
         $name_pr = preg_replace(array('/\\s/', '/\\.[\\.]+/', '/[^\\w_\\.\\-]/'), array('_', '.', ''), $name);
         $context['filename'] = $base_name;
         $destination = BOARDDIR . '/packages/' . basename($_REQUEST['package']);
     }
     if (!file_exists($destination)) {
         fatal_lang_error('package_no_file', false);
     }
     // Make sure temp directory exists and is empty.
     if (file_exists(BOARDDIR . '/packages/temp')) {
         deltree(BOARDDIR . '/packages/temp', false);
     }
     if (!mktree(BOARDDIR . '/packages/temp', 0755)) {
         deltree(BOARDDIR . '/packages/temp', false);
         if (!mktree(BOARDDIR . '/packages/temp', 0777)) {
             deltree(BOARDDIR . '/packages/temp', false);
             // @todo not sure about url in destination_url
             create_chmod_control(array(BOARDDIR . '/packages/temp/delme.tmp'), array('destination_url' => $scripturl . '?action=admin;area=smileys;sa=install;set_gz=' . $_REQUEST['set_gz'], 'crash_on_error' => true));
             deltree(BOARDDIR . '/packages/temp', false);
             if (!mktree(BOARDDIR . '/packages/temp', 0777)) {
                 fatal_lang_error('package_cant_download', false);
             }
         }
     }
     $extracted = read_tgz_file($destination, BOARDDIR . '/packages/temp');
     // @todo needs to change the URL in the next line ;)
     if (!$extracted) {
         fatal_lang_error('packageget_unable', false, array('http://custom.elkarte.net/index.php?action=search;type=12;basic_search=' . $name));
     }
     if ($extracted && !file_exists(BOARDDIR . '/packages/temp/package-info.xml')) {
         foreach ($extracted as $file) {
             if (basename($file['filename']) == 'package-info.xml') {
                 $base_path = dirname($file['filename']) . '/';
                 break;
             }
         }
     }
     if (!isset($base_path)) {
         $base_path = '';
     }
     if (!file_exists(BOARDDIR . '/packages/temp/' . $base_path . 'package-info.xml')) {
         fatal_lang_error('package_get_error_missing_xml', false);
     }
     $smileyInfo = getPackageInfo($context['filename']);
     if (!is_array($smileyInfo)) {
         fatal_lang_error($smileyInfo);
     }
     // See if it is installed?
     if (isSmileySetInstalled($smileyInfo['id'])) {
         fata_lang_error('package_installed_warning1');
     }
     // Everything is fine, now it's time to do something, first we test
     $actions = parsePackageInfo($smileyInfo['xml'], true, 'install');
     $context['post_url'] = $scripturl . '?action=admin;area=smileys;sa=install;package=' . $base_name;
     $context['has_failure'] = false;
     $context['actions'] = array();
     $context['ftp_needed'] = false;
     foreach ($actions as $action) {
         if ($action['type'] == 'readme' || $action['type'] == 'license') {
             $type = 'package_' . $action['type'];
             if (file_exists(BOARDDIR . '/packages/temp/' . $base_path . $action['filename'])) {
                 $context[$type] = htmlspecialchars(trim(file_get_contents(BOARDDIR . '/packages/temp/' . $base_path . $action['filename']), "\n\r"), ENT_COMPAT, 'UTF-8');
             } elseif (file_exists($action['filename'])) {
                 $context[$type] = htmlspecialchars(trim(file_get_contents($action['filename']), "\n\r"), ENT_COMPAT, 'UTF-8');
             }
             if (!empty($action['parse_bbc'])) {
                 require_once SUBSDIR . '/Post.subs.php';
                 preparsecode($context[$type]);
                 $context[$type] = parse_bbc($context[$type]);
             } else {
                 $context[$type] = nl2br($context[$type]);
             }
             continue;
         } elseif ($action['type'] == 'require-dir') {
             // Do this one...
             $thisAction = array('type' => $txt['package_extract'] . ' ' . ($action['type'] == 'require-dir' ? $txt['package_tree'] : $txt['package_file']), 'action' => Util::htmlspecialchars(strtr($action['destination'], array(BOARDDIR => '.'))));
             $file = BOARDDIR . '/packages/temp/' . $base_path . $action['filename'];
             if (isset($action['filename']) && (!file_exists($file) || !is_writable(dirname($action['destination'])))) {
                 $context['has_failure'] = true;
                 $thisAction += array('description' => $txt['package_action_error'], 'failed' => true);
             }
             // Show a description for the action if one is provided
             if (empty($thisAction['description'])) {
                 $thisAction['description'] = isset($action['description']) ? $action['description'] : '';
             }
             $context['actions'][] = $thisAction;
         } elseif ($action['type'] == 'credits') {
             // Time to build the billboard
             $credits_tag = array('url' => $action['url'], 'license' => $action['license'], 'copyright' => $action['copyright'], 'title' => $action['title']);
         }
     }
     if ($testing) {
         $context['sub_template'] = 'view_package';
         $context['uninstalling'] = false;
         $context['is_installed'] = false;
         $context['package_name'] = $smileyInfo['name'];
         loadTemplate('Packages');
     } else {
         $actions = parsePackageInfo($smileyInfo['xml'], false, 'install');
         foreach ($context['actions'] as $action) {
             updateSettings(array('smiley_sets_known' => $modSettings['smiley_sets_known'] . ',' . basename($action['action']), 'smiley_sets_names' => $modSettings['smiley_sets_names'] . "\n" . $smileyInfo['name'] . (count($context['actions']) > 1 ? ' ' . (!empty($action['description']) ? Util::htmlspecialchars($action['description']) : basename($action['action'])) : '')));
         }
         package_flush_cache();
         // Time to tell pacman we have a new package installed!
         package_put_contents(BOARDDIR . '/packages/installed.list', time());
         // Credits tag?
         $credits_tag = empty($credits_tag) ? '' : serialize($credits_tag);
         $installed = array('filename' => $smileyInfo['filename'], 'name' => $smileyInfo['name'], 'package_id' => $smileyInfo['id'], 'version' => $smileyInfo['filename'], 'id_member' => $user_info['id'], 'member_name' => $user_info['name'], 'credits_tag' => $credits_tag);
         logPackageInstall($installed);
         logAction('install_package', array('package' => Util::htmlspecialchars($smileyInfo['name']), 'version' => Util::htmlspecialchars($smileyInfo['version'])), 'admin');
         cache_put_data('parsing_smileys', null, 480);
         cache_put_data('posting_smileys', null, 480);
     }
     if (file_exists(BOARDDIR . '/packages/temp')) {
         deltree(BOARDDIR . '/packages/temp');
     }
     if (!$testing) {
         redirectexit('action=admin;area=smileys');
     }
 }