/**
  * Imports language packs from an xml file and updates the database and recaches the languages
  *
  * @param	integer	$lang_id		ID of the language pack to import
  * @param	bool	$in_dev			Set to 1 for developer language import
  * @param	bool	$no_return		If set to 1, this function will return a value, rather than outputting data
  * @param	string	$app_override	Overrides the application for which languages are being imported
  * @param	bool	$skip_charset	Skips charset conversion in the XML file (useful during upgrade routine as strings don't need to be converted)
  * @return	mixed
  */
 public function imprtFromXML($lang_id = 0, $in_dev = 0, $no_return = 0, $app_override = '', $skip_charset = false)
 {
     //-----------------------------------------
     // Set version..
     //-----------------------------------------
     $LATESTVERSION = IPSLib::fetchVersionNumber();
     //-----------------------------------------
     // INDEV?
     //-----------------------------------------
     if ($in_dev) {
         $_FILES['FILE_UPLOAD']['name'] = '';
     } else {
         if ($this->request['file_location']) {
             $this->request['file_location'] = IPS_ROOT_PATH . $this->request['file_location'];
         }
     }
     //-----------------------------------------
     // Not an upload?
     //-----------------------------------------
     if ($_FILES['FILE_UPLOAD']['name'] == "" or !$_FILES['FILE_UPLOAD']['name'] or $_FILES['FILE_UPLOAD']['name'] == "none") {
         //-----------------------------------------
         // Check and load from server
         //-----------------------------------------
         if (!$this->request['file_location']) {
             $this->registry->output->global_message = $this->lang->words['l_nofile'];
             $this->languagesList();
             return;
         }
         if (!is_file($this->request['file_location'])) {
             $this->registry->output->global_message = $this->lang->words['l_noopen'] . $this->request['file_location'];
             $this->languagesList();
             return;
         }
         if (preg_match('#\\.gz$#', $this->request['file_location'])) {
             if ($FH = @gzopen($this->request['file_location'], 'rb')) {
                 while (!@gzeof($FH)) {
                     $content .= @gzread($FH, 1024);
                 }
                 @gzclose($FH);
             }
         } else {
             $content = file_get_contents($this->request['file_location']);
         }
         $originalContent = $content;
         //-----------------------------------------
         // Extract archive
         //-----------------------------------------
         require_once IPS_KERNEL_PATH . 'classXMLArchive.php';
         /*noLibHook*/
         $xmlarchive = new classXMLArchive();
         //-----------------------------------------
         // Read the archive
         //-----------------------------------------
         $xmlarchive->readXML($content);
         //-----------------------------------------
         // Get the data
         //-----------------------------------------
         $content = '';
         foreach ($xmlarchive->asArray() as $k => $f) {
             if ($k == 'language_entries.xml') {
                 $content = $f['content'];
                 break;
             }
         }
         //-----------------------------------------
         // No content from de-archiving, must not
         // be archive, but rather raw XML file
         //-----------------------------------------
         if ($content == '' and strpos($originalContent, "<languageexport") !== false) {
             $content = $originalContent;
         }
     } else {
         //-----------------------------------------
         // Get uploaded schtuff
         //-----------------------------------------
         $tmp_name = $_FILES['FILE_UPLOAD']['name'];
         $tmp_name = preg_replace('#\\.gz$#', "", $tmp_name);
         if ($_FILES['FILE_UPLOAD']['error']) {
             switch ($_FILES['FILE_UPLOAD']['error']) {
                 case 1:
                     $this->registry->output->global_message = sprintf($this->lang->words['lang_upload_too_large'], ini_get('upload_max_filesize'));
                     $this->languagesList();
                     return;
                     break;
                 default:
                     $this->registry->output->global_message = $this->lang->words['lang_upload_other_error'];
                     $this->languagesList();
                     return;
                     break;
             }
         }
         //-----------------------------------------
         // Get content
         //-----------------------------------------
         try {
             $uploadedContent = $this->registry->adminFunctions->importXml($tmp_name);
         } catch (Exception $e) {
             $this->registry->output->showError($e->getMessage());
         }
         //-----------------------------------------
         // Extract archive
         //-----------------------------------------
         require_once IPS_KERNEL_PATH . 'classXMLArchive.php';
         /*noLibHook*/
         $xmlarchive = new classXMLArchive();
         //-----------------------------------------
         // Read the archive
         //-----------------------------------------
         $xmlarchive->readXML($uploadedContent);
         //-----------------------------------------
         // Get the data
         //-----------------------------------------
         $content = '';
         foreach ($xmlarchive->asArray() as $k => $f) {
             if ($k == 'language_entries.xml') {
                 $content = $f['content'];
                 break;
             }
         }
         //-----------------------------------------
         // No content from de-archiving, must not
         // be archive, but rather raw XML file
         //-----------------------------------------
         if ($content == '' and strpos($uploadedContent, "<languageexport") !== false) {
             $content = $uploadedContent;
         }
     }
     //-----------------------------------------
     // Make sure we have content
     //-----------------------------------------
     if (!$content) {
         if ($no_return) {
             return;
         }
         $this->registry->output->global_message = $this->lang->words['l_badfile'];
         $this->languagesList();
         return;
     }
     //-----------------------------------------
     // Get xml class
     //-----------------------------------------
     require_once IPS_KERNEL_PATH . 'classXML.php';
     /*noLibHook*/
     $xml = new classXML($skip_charset ? 'utf-8' : IPS_DOC_CHAR_SET);
     $xml->loadXML($content);
     //-----------------------------------------
     // Is this full language pack?...
     //-----------------------------------------
     foreach ($xml->fetchElements('langinfo') as $lang_data) {
         $lang_info = $xml->fetchElementsFromRecord($lang_data);
         $lang_data = array('lang_short' => $lang_info['lang_short'], 'lang_title' => $lang_info['lang_title']);
     }
     $lang_ids = array();
     $insertId = 0;
     //-----------------------------------------
     // Do we have language pack info?
     //-----------------------------------------
     if ($lang_data['lang_short']) {
         //-----------------------------------------
         // Does this pack already exist
         //-----------------------------------------
         $update_lang = $this->DB->buildAndFetch(array('select' => 'lang_id', 'from' => 'core_sys_lang', 'where' => "lang_short='{$lang_data['lang_short']}'"));
         //-----------------------------------------
         // If doesn't exist, then create new pack
         //-----------------------------------------
         if (!$update_lang['lang_id']) {
             $this->DB->insert('core_sys_lang', $lang_data);
             $insertId = $this->DB->getInsertId();
             if (@mkdir(IPS_CACHE_PATH . '/cache/lang_cache/' . $insertId)) {
                 @file_put_contents(IPS_CACHE_PATH . 'cache/lang_cache/' . $insertId . '/index.html', '');
                 @chmod(IPS_CACHE_PATH . '/cache/lang_cache/' . $insertId, IPS_FOLDER_PERMISSION);
             }
             //-----------------------------------------
             // Copy over language bits from default lang
             //-----------------------------------------
             $default = $this->DB->buildAndFetch(array('select' => 'lang_id', 'from' => 'core_sys_lang', 'where' => "lang_default=1"));
             $this->DB->build(array('select' => 'word_app,word_pack,word_key,word_default,word_js', 'from' => 'core_sys_lang_words', 'where' => "lang_id={$default['lang_id']}"));
             $q = $this->DB->execute();
             while ($r = $this->DB->fetch($q)) {
                 $r['lang_id'] = $insertId;
                 $r['word_custom'] = '';
                 $this->DB->insert('core_sys_lang_words', $r);
             }
             //-----------------------------------------
             // Rebuild IPB and disk caches
             //-----------------------------------------
             $this->registry->class_localization->rebuildLanguagesCache();
         } else {
             $insertId = $update_lang['lang_id'];
         }
     }
     //-----------------------------------------
     // We need to add language bits to every pack..
     //-----------------------------------------
     $this->DB->build(array('select' => 'lang_id', 'from' => 'core_sys_lang'));
     $this->DB->execute();
     while ($r = $this->DB->fetch()) {
         $lang_ids[] = $r['lang_id'];
     }
     //-----------------------------------------
     // Init counts array
     //-----------------------------------------
     $counts = array('updates' => 0, 'inserts' => 0);
     //-----------------------------------------
     // Init a cache array to save entries
     //-----------------------------------------
     $lang_entries = array();
     if ($app_override) {
         $this->DB->build(array('select' => "MD5( CONCAT( lang_id, '-', word_app, '-', word_pack, '-', word_key ) ) as word_lookup, word_id, md5(word_default) as word_default, word_default_version", 'from' => 'core_sys_lang_words', 'where' => "word_app='{$app_override}' AND lang_id IN(" . implode(",", $lang_ids) . ")"));
         $this->DB->execute();
         while ($r = $this->DB->fetch()) {
             $lang_entries[$r['word_lookup']] = $r;
         }
     }
     //-----------------------------------------
     // Start looping
     //-----------------------------------------
     $_lastLookup = '';
     foreach ($xml->fetchElements('lang') as $entry) {
         $lang = $xml->fetchElementsFromRecord($entry);
         foreach ($lang_ids as $_lang_id) {
             $lang_entry = array();
             //-----------------------------------------
             // Build db array
             //-----------------------------------------
             $db_array = array('lang_id' => $_lang_id, 'word_app' => $app_override ? $app_override : $lang['word_app'], 'word_pack' => $lang['word_pack'], 'word_key' => $lang['word_key'], 'word_default' => $lang['word_default'], 'word_custom' => $in_dev ? '' : $lang['word_custom'], 'word_js' => intval($lang['word_js']), 'word_default_version' => $lang['word_default_version'] ? $lang['word_default_version'] : $LATESTVERSION['long'], 'word_custom_version' => $lang['word_custom_version']);
             $dbKey = md5($db_array['lang_id'] . '-' . $db_array['word_app'] . '-' . $db_array['word_pack'] . '-' . $db_array['word_key']);
             $langIdKey = md5($_lang_id . '-' . $db_array['word_app'] . '-' . $db_array['word_pack'] . '-' . $db_array['word_key']);
             // If the default value hasn't changed, we don't need to update the word_default_version (see bug report 19172)
             if (md5($lang['word_default']) == $lang_entries[$dbKey]['word_default']) {
                 $db_array['word_default_version'] = $lang_entries[$dbKey]['word_default_version'];
             }
             //-----------------------------------------
             // If cached, get from cache
             //-----------------------------------------
             if ($lang_entries[$langIdKey]) {
                 $lang_entry = $lang_entries[$langIdKey];
             } else {
                 if (!$app_override) {
                     if ($_lastLookup != md5($db_array['word_app'] . '-' . $db_array['word_pack'])) {
                         unset($lang_entries);
                     }
                     $_lastLookup = md5($db_array['word_app'] . '-' . $db_array['word_pack']);
                     $this->DB->build(array('select' => '*', 'from' => 'core_sys_lang_words', 'where' => "lang_id={$_lang_id} AND word_app='{$db_array['word_app']}' AND word_pack='{$db_array['word_pack']}'"));
                     $this->DB->execute();
                     while ($r = $this->DB->fetch()) {
                         $lang_entries[md5($r['lang_id'] . '-' . $r['word_app'] . '-' . $r['word_pack'] . '-' . $r['word_key'])] = $r;
                     }
                     if ($lang_entries[$langIdKey]) {
                         $lang_entry = $lang_entries[$langIdKey];
                     }
                 }
             }
             //-----------------------------------------
             // Didn't find any match?  Must be importing
             // a new language pack, huh?
             //-----------------------------------------
             if (!isset($lang_entry['word_id'])) {
                 //continue 2;
             }
             //-----------------------------------------
             // If there is no new custom lang bit to insert
             // don't delete what is already there.
             //-----------------------------------------
             if (!$db_array['word_custom'] || $insertId > 0 && $insertId != $_lang_id) {
                 unset($db_array['word_custom']);
                 unset($db_array['word_custom_version']);
             }
             //-----------------------------------------
             // Lang bit already exists, update
             //-----------------------------------------
             if ($lang_entry['word_id'] and (!$insertId or $insertId == $_lang_id)) {
                 //-----------------------------------------
                 // Don't update default version
                 //-----------------------------------------
                 // This causes no languages to show "out of date" on upgrade
                 // @link	http://community.invisionpower.com/tracker/issue-31637-no-out-of-date-entries-for-language-string-updates
                 // This WAS added to fix a previously reported bug, however, so need to watch out for this
                 // unset( $db_array['word_default_version'] );
                 $counts['updates']++;
                 $this->DB->update('core_sys_lang_words', $db_array, "word_id={$lang_entry['word_id']}");
             } else {
                 if (!$lang_entry['word_id']) {
                     /* Ensure there is a value to avoid null */
                     if (!$db_array['word_custom']) {
                         $db_array['word_custom'] = '';
                     }
                     /* Ensure custom word but isn't added to other packs that simply had missing strings */
                     if ($insertId and $insertId != $_lang_id) {
                         $db_array['word_custom'] = '';
                     }
                     $counts['inserts']++;
                     $this->DB->insert('core_sys_lang_words', $db_array);
                 }
             }
             unset($lang_entry, $db_array);
         }
     }
     /* Save some memory */
     unset($lang_entries);
     //-----------------------------------------
     // Recache all our lang packs
     //-----------------------------------------
     foreach ($lang_ids as $_lang_id) {
         $this->cacheToDisk($_lang_id, $app_override);
     }
     //-----------------------------------------
     // Set output message
     //-----------------------------------------
     $this->registry->output->global_message = sprintf($this->lang->words['l_updatedcount'], $counts['updates'], $counts['inserts']);
     if (is_array($this->cache_errors) and count($this->cache_errors)) {
         $this->registry->output->global_message .= "<br />" . implode("<br />", $this->cache_errors);
     }
     //-----------------------------------------
     // Free a little memory
     //-----------------------------------------
     unset($xml);
     //-----------------------------------------
     // Update IPB cache
     //-----------------------------------------
     $this->registry->class_localization->rebuildLanguagesCache();
     //-----------------------------------------
     // Return! Now!
     //-----------------------------------------
     if (!$no_return) {
         $this->languagesList();
         return;
     }
 }
 /**
  * Import an emoticon pack
  *
  * @return	@e void
  */
 public function emoticonsPackImport()
 {
     /* Make sure all emoticon directories are writable */
     $this->DB->build(array('select' => $this->DB->buildDistinct('emo_set') . ' as folder', 'from' => 'emoticons'));
     $this->DB->execute();
     while ($r = $this->DB->fetch()) {
         $_folders[] = $r['folder'];
     }
     if (count($_folders)) {
         foreach ($_folders as $folder) {
             if (!IPSLib::isWritable(DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_emoticons/' . $folder)) {
                 $this->registry->output->global_error = sprintf($this->lang->words['emodir_not_write'], PUBLIC_DIRECTORY . '/style_emoticons/' . $folder);
                 return $this->emoticonsPackSplash();
             }
         }
     }
     /* Get the xml file */
     try {
         $content = $this->registry->adminFunctions->importXml('ipb_emoticons.xml');
     } catch (Exception $e) {
         $this->registry->output->showError($e->getMessage());
     }
     /* Check for content */
     if (!$content) {
         $this->registry->output->global_error = $this->lang->words['emo_fail'];
         return $this->emoticonsPackSplash();
     }
     /* Setup XML */
     require_once IPS_KERNEL_PATH . 'classXML.php';
     /*noLibHook*/
     $xml = new classXML(IPS_DOC_CHAR_SET);
     require_once IPS_KERNEL_PATH . 'classXMLArchive.php';
     /*noLibHook*/
     $xmlarchive = new classXMLArchive();
     /* Read the archive */
     $xmlarchive->readXML($content);
     /* Get the data file */
     $emoticons = array();
     $emoticon_data = array();
     foreach ($xmlarchive->asArray() as $k => $f) {
         if ($k == 'emoticon_data.xml') {
             $emoticon_data = $f;
         } else {
             $emoticons[$f['filename']] = $f['content'];
         }
     }
     /* Parse the XML Document */
     $xml->loadXML($emoticon_data['content']);
     /* Make sure we have a destination for these emoicons */
     if (!$this->request['emo_set'] and !$this->request['new_emo_set']) {
         $this->registry->output->global_error = $this->lang->words['emo_specify'];
     }
     /* Current emoticon set directory */
     $emo_set_dir = trim($this->request['emo_set']);
     /* New emoticon set directory */
     $this->request['new_emo_set'] = preg_replace('/[^a-zA-Z0-9\\-_]/', "", $this->request['new_emo_set']);
     /* Create the new set */
     if ($this->request['new_emo_set']) {
         $emo_set_dir = trim($this->request['new_emo_set']);
         /* Check to see if the directory already exists */
         if (file_exists(DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_emoticons/' . $emo_set_dir)) {
             $this->registry->output->global_error = sprintf($this->lang->words['emo_already'], $emo_set_dir);
             return $this->emoticonsPackSplash();
         }
         /* Create the directory */
         if (@mkdir(DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_emoticons/' . $emo_set_dir, IPS_FOLDER_PERMISSION)) {
             @chmod(DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_emoticons/' . $emo_set_dir, IPS_FOLDER_PERMISSION);
             @file_put_contents(DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_emoticons/' . $emo_set_dir . '/index.html', '');
         } else {
             $this->registry->output->global_error = $this->lang->words['emo_ftp'];
             return $this->emoticonsPackSplash();
         }
     }
     /* Get a list of current emoticons, if we are not overwriting */
     $emo_image = array();
     $emo_typed = array();
     if ($this->request['overwrite'] != 1) {
         $this->DB->build(array('select' => '*', 'from' => 'emoticons', 'where' => "emo_set='" . $emo_set_dir . "'"));
         $this->DB->execute();
         while ($r = $this->DB->fetch()) {
             $emo_image[$r['image']] = 1;
             $emo_typed[$r['typed']] = 1;
         }
     }
     /* Loop through the emoticons in the xml document */
     foreach ($xml->fetchElements('emoticon') as $emoticon) {
         $entry = $xml->fetchElementsFromRecord($emoticon);
         /* Emoticon Data */
         $image = $entry['image'];
         $typed = $entry['typed'];
         $click = $entry['clickable'];
         /* Skip if we're not overwriting */
         if ($emo_image[$image] or $emo_typed[$typed]) {
             continue;
         }
         /* Get the extension */
         $file_extension = preg_replace('#^.*\\.(.+?)$#si', "\\1", strtolower($image));
         /* Make sure it's allowed */
         if (!in_array($file_extension, $this->allowed_files)) {
             continue;
         }
         /* Remove any existing emoticon */
         @unlink(DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_emoticons/' . $emo_set_dir . '/' . $image);
         $this->DB->delete('emoticons', "typed='{$typed}' and image='{$image}' and emo_set='{$emo_set_dir}'");
         /* Create the image in the file system */
         if ($FH = fopen(DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_emoticons/' . $emo_set_dir . '/' . $image, 'wb')) {
             if (fwrite($FH, $emoticons[$image])) {
                 fclose($FH);
                 /* Insert the emoticon record */
                 $this->DB->insert('emoticons', array('typed' => $typed, 'image' => $image, 'clickable' => $click, 'emo_set' => $emo_set_dir));
             }
         }
         /* Add the emoticon to all the other directories */
         try {
             foreach (new DirectoryIterator(DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_emoticons/') as $file) {
                 if (!$file->isDot() && $file->isDir()) {
                     if (substr($file->getFilename(), 0, 1) == '.') {
                         continue;
                     }
                     if (!is_file(DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_emoticons/' . $file->getFilename() . '/' . $image)) {
                         $this->DB->delete('emoticons', "typed='{$typed}' and image='{$image}' and emo_set='{$file->getFilename()}'");
                         if ($FH = @fopen(DOC_IPS_ROOT_PATH . PUBLIC_DIRECTORY . '/style_emoticons/' . $file->getFilename() . '/' . $image, 'wb')) {
                             if (fwrite($FH, $emoticons[$image])) {
                                 fclose($FH);
                                 $this->DB->insert('emoticons', array('typed' => $typed, 'image' => $image, 'clickable' => $click, 'emo_set' => $file->getFilename()));
                             }
                         }
                     }
                 }
             }
         } catch (Exception $e) {
         }
     }
     /* Recache and bounce */
     $this->emoticonsRebuildCache();
     $this->registry->output->global_message = $this->lang->words['emo_xml_good'];
     $this->emoticonsOverview();
 }
 /**
  * Imports a set XMLArchive
  *
  * @access	public
  * @param	string		XMLArchive content to import
  * @param	int 		[ Skin set parent. If omitted, it will be made a root skin ]
  * @param	string		[ Images directory to use. If omitted, default skin's image dir is used ]
  * @param	string		[ Name of skin to create. If omitted, name from skin set is used ]
  * @return	mixed		bool, or number of items added
  */
 public function importSetXMLArchive($content, $parentID = 0, $imageDir = '', $setName = '')
 {
     //-----------------------------------------
     // INIT
     //-----------------------------------------
     $templates = array();
     $csss = array();
     $groups = array();
     $defaultSkin = array();
     $return = array('replacements' => 0, 'css' => 0, 'templates' => 0);
     //-----------------------------------------
     // Got anything?
     //-----------------------------------------
     if (!strstr($content, "<xmlarchive")) {
         $this->_addErrorMessage("The content was not a valid XMLArchive");
         return FALSE;
     }
     //-----------------------------------------
     // Make admin group list
     //-----------------------------------------
     foreach ($this->caches['group_cache'] as $id => $data) {
         if ($data['g_access_cp']) {
             $groups[] = $id;
         }
     }
     //-----------------------------------------
     // Grab the XMLArchive class
     //-----------------------------------------
     require_once IPS_KERNEL_PATH . 'classXMLArchive.php';
     $xmlArchive = new classXMLArchive();
     $xmlArchive->readXML($content);
     if (!$xmlArchive->countFileArray()) {
         $this->_addErrorMessage("The XMLArchive is empty");
         return FALSE;
     }
     //-----------------------------------------
     // Gather data
     //-----------------------------------------
     /* Info */
     $infoXml = $xmlArchive->getFile('info.xml');
     if (!$infoXml) {
         $this->_addErrorMessage("The info.xml file is empty or was not included");
         return FALSE;
     }
     $info = $this->parseInfoXML($infoXml);
     /* Replacements */
     $replacements = $this->parseReplacementsXML($xmlArchive->getFile('replacements.xml'));
     /* Templates */
     foreach ($xmlArchive->asArray() as $path => $fileData) {
         if ($fileData['path'] == 'templates' && $fileData['content']) {
             $templates[str_replace('.xml', '', $fileData['filename'])] = $this->parseTemplatesXML($fileData['content']);
         }
     }
     /* Templates */
     foreach ($xmlArchive->asArray() as $path => $fileData) {
         if ($fileData['path'] == 'css') {
             $csss[str_replace('.xml', '', $fileData['filename'])] = $this->parseCSSXML($fileData['content']);
         }
     }
     if (!is_array($info)) {
         $this->_addErrorMessage("The XMLArchive does not contain an info.xml file");
         return FALSE;
     }
     $info['set_output_format'] = $info['set_output_format'] ? $info['set_output_format'] : 'html';
     //-----------------------------------------
     // Find default skin
     //-----------------------------------------
     foreach ($this->registry->output->allSkins as $id => $data) {
         if ($data['set_is_default'] and $data['set_output_format'] == $info['set_output_format']) {
             $defaultSkin = $data;
             break;
         }
     }
     //-----------------------------------------
     // Build Set Array
     //-----------------------------------------
     $newSet = array('set_name' => $setName ? $setName : $info['set_name'] . ' (Import)', 'set_key' => '', 'set_parent_id' => $parentID, 'set_permissions' => implode(",", $groups), 'set_is_default' => 0, 'set_author_name' => $info['set_author_name'], 'set_author_url' => $info['set_author_url'], 'set_image_dir' => $imageDir ? $imageDir : $defaultSkin['set_image_dir'], 'set_emo_dir' => $defaultSkin['set_emo_dir'], 'set_css_inline' => 0, 'set_output_format' => $info['set_output_format'], 'set_css_groups' => '', 'set_hide_from_list' => 1, 'set_updated' => time());
     //-----------------------------------------
     // Insert...
     //-----------------------------------------
     $this->DB->insert('skin_collections', $newSet);
     $setID = $this->DB->getInsertId();
     /* Rebuild trees */
     $this->rebuildTreeInformation($setID);
     /* Now re-load to fetch the tree information */
     $newSet = $this->DB->buildAndFetch(array('select' => '*', 'from' => 'skin_collections', 'where' => 'set_id=' . $setID));
     /* Add to allSkins array for caching functions below */
     $newSet['_parentTree'] = unserialize($newSet['set_parent_array']);
     $newSet['_childTree'] = unserialize($newSet['set_child_array']);
     $newSet['_userAgents'] = unserialize($newSet['set_locked_uagent']);
     $newSet['_cssGroupsArray'] = unserialize($newSet['set_css_groups']);
     $this->registry->output->allSkins[$setID] = $newSet;
     //-----------------------------------------
     // Replacements...
     //-----------------------------------------
     if (is_array($replacements)) {
         foreach ($replacements as $replacement) {
             if ($replacement['replacement_key']) {
                 $return['replacements']++;
                 $this->DB->insert('skin_replacements', array('replacement_key' => $replacement['replacement_key'], 'replacement_content' => $replacement['replacement_content'], 'replacement_set_id' => $setID, 'replacement_added_to' => $setID));
             }
         }
     }
     //-----------------------------------------
     // CSS...
     //-----------------------------------------
     /* Fetch master CSS */
     $_MASTER = $this->fetchCSS(0);
     $apps = new IPSApplicationsIterator();
     if (is_array($csss)) {
         foreach ($apps as $app) {
             $appDir = $apps->fetchAppDir();
             if (isset($csss[$appDir]) && is_array($csss[$appDir])) {
                 foreach ($csss[$appDir] as $css) {
                     if ($css['css_group']) {
                         $return['css']++;
                         $this->DB->insert('skin_css', array('css_group' => $css['css_group'], 'css_content' => $css['css_content'], 'css_position' => $css['css_position'], 'css_attributes' => $css['css_attributes'], 'css_app' => $css['css_app'], 'css_app_hide' => $css['css_app_hide'], 'css_modules' => str_replace(' ', '', $css['css_modules']), 'css_updated' => time(), 'css_set_id' => $setID, 'css_added_to' => isset($_MASTER[$css['css_group']]) ? 0 : $setID));
                     }
                 }
             }
         }
     }
     //-----------------------------------------
     // Templates - only import apps we have...
     //-----------------------------------------
     /* Fetch all master items */
     $_MASTER = $this->fetchTemplates(0, 'allNoContent');
     $apps = new IPSApplicationsIterator();
     if (is_array($templates)) {
         foreach ($apps as $app) {
             $appDir = $apps->fetchAppDir();
             if (array_key_exists($appDir, $templates)) {
                 foreach ($templates[$appDir] as $template) {
                     if ($template['template_group'] and $template['template_name']) {
                         /* Figure out if this is added by a user or not */
                         $isAdded = (is_array($_MASTER[$template['template_group']][strtolower($template['template_name'])]) and !$_MASTER[$template['template_group']][strtolower($template['template_name'])]['template_user_added']) ? 0 : 1;
                         $return['templates']++;
                         $this->DB->insert('skin_templates', array('template_set_id' => $setID, 'template_group' => $template['template_group'], 'template_content' => $template['template_content'], 'template_name' => $template['template_name'], 'template_data' => $template['template_data'], 'template_updated' => $template['template_updated'], 'template_removable' => 1, 'template_user_edited' => 1, 'template_user_added' => $isAdded, 'template_added_to' => $setID));
                     }
                 }
             }
         }
     }
     //-----------------------------------------
     // Re-cache
     //-----------------------------------------
     $this->rebuildReplacementsCache($setID);
     $this->rebuildCSS($setID);
     $this->rebuildPHPTemplates($setID);
     $this->rebuildSkinSetsCache();
     //-----------------------------------------
     // Done....
     //-----------------------------------------
     return $return;
 }
 /**
  * Imports language packs from an xml file and updates the database and recaches the languages
  *
  * @access	public
  * @param	integer	$lang_id	ID of the language pack to import
  * @param	bool	$in_dev		Set to 1 for developer language import
  * @param	bool	$no_return	If set to 1, this function will return a value, rather than outputting data
  * @param	string	$app_override	Overrides the application for which languages are being imported
  * @return	mixed
  */
 public function imprtFromXML($lang_id = 0, $in_dev = 0, $no_return = 0, $app_override = '')
 {
     //-----------------------------------------
     // Set version..
     //-----------------------------------------
     $LATESTVERSION = IPSLib::fetchVersionNumber();
     //-----------------------------------------
     // INDEV?
     //-----------------------------------------
     if ($in_dev) {
         $_FILES['FILE_UPLOAD']['name'] = '';
     } else {
         if ($this->request['file_location']) {
             $this->request['file_location'] = IPS_ROOT_PATH . $this->request['file_location'];
         }
     }
     //-----------------------------------------
     // Not an upload?
     //-----------------------------------------
     if ($_FILES['FILE_UPLOAD']['name'] == "" or !$_FILES['FILE_UPLOAD']['name'] or $_FILES['FILE_UPLOAD']['name'] == "none") {
         //-----------------------------------------
         // Check and load from server
         //-----------------------------------------
         if (!$this->request['file_location']) {
             $this->registry->output->global_message = $this->lang->words['l_nofile'];
             $this->languagesList();
             return;
         }
         if (!file_exists($this->request['file_location'])) {
             $this->registry->output->global_message = $this->lang->words['l_noopen'] . $this->request['file_location'];
             $this->languagesList();
             return;
         }
         if (preg_match("#\\.gz\$#", $this->request['file_location'])) {
             if ($FH = @gzopen($this->request['file_location'], 'rb')) {
                 while (!@gzeof($FH)) {
                     $content .= @gzread($FH, 1024);
                 }
                 @gzclose($FH);
             }
         } else {
             $content = file_get_contents($this->request['file_location']);
         }
         $originalContent = $content;
         //-----------------------------------------
         // Extract archive
         //-----------------------------------------
         require_once IPS_KERNEL_PATH . 'classXMLArchive.php';
         $xmlarchive = new classXMLArchive();
         //-----------------------------------------
         // Read the archive
         //-----------------------------------------
         $xmlarchive->readXML($content);
         //-----------------------------------------
         // Get the data
         //-----------------------------------------
         $content = '';
         foreach ($xmlarchive->asArray() as $k => $f) {
             if ($k == 'language_entries.xml') {
                 $content = $f['content'];
                 break;
             }
         }
         //-----------------------------------------
         // No content from de-archiving, must not
         // be archive, but rather raw XML file
         //-----------------------------------------
         if ($content == '' and strpos($originalContent, "<languageexport") !== false) {
             $content = $originalContent;
         }
     } else {
         //-----------------------------------------
         // Get uploaded schtuff
         //-----------------------------------------
         $tmp_name = $_FILES['FILE_UPLOAD']['name'];
         $tmp_name = preg_replace("#\\.gz\$#", "", $tmp_name);
         if ($_FILES['FILE_UPLOAD']['error']) {
             switch ($_FILES['FILE_UPLOAD']['error']) {
                 case 1:
                     $this->registry->output->global_message = sprintf($this->lang->words['lang_upload_too_large'], ini_get('upload_max_filesize'));
                     $this->languagesList();
                     return;
                     break;
                 default:
                     $this->registry->output->global_message = $this->lang->words['lang_upload_other_error'];
                     $this->languagesList();
                     return;
                     break;
             }
         }
         //-----------------------------------------
         // Get content
         //-----------------------------------------
         $uploadedContent = $this->registry->adminFunctions->importXml($tmp_name);
         //-----------------------------------------
         // Extract archive
         //-----------------------------------------
         require_once IPS_KERNEL_PATH . 'classXMLArchive.php';
         $xmlarchive = new classXMLArchive();
         //-----------------------------------------
         // Read the archive
         //-----------------------------------------
         $xmlarchive->readXML($uploadedContent);
         //-----------------------------------------
         // Get the data
         //-----------------------------------------
         $content = '';
         foreach ($xmlarchive->asArray() as $k => $f) {
             if ($k == 'language_entries.xml') {
                 $content = $f['content'];
                 break;
             }
         }
         //-----------------------------------------
         // No content from de-archiving, must not
         // be archive, but rather raw XML file
         //-----------------------------------------
         if ($content == '' and strpos($uploadedContent, "<languageexport") !== false) {
             $content = $uploadedContent;
         }
     }
     //-----------------------------------------
     // Make sure we have content
     //-----------------------------------------
     if (!$content) {
         $this->registry->output->global_message = $this->lang->words['l_badfile'];
         $this->languagesList();
         return;
     }
     //-----------------------------------------
     // Get xml class
     //-----------------------------------------
     require_once IPS_KERNEL_PATH . 'classXML.php';
     $xml = new classXML(IPS_DOC_CHAR_SET);
     $xml->loadXML($content);
     //-----------------------------------------
     // Is this full language pack?...
     //-----------------------------------------
     foreach ($xml->fetchElements('langinfo') as $lang_data) {
         $lang_info = $xml->fetchElementsFromRecord($lang_data);
         $lang_data = array('lang_short' => $lang_info['lang_short'], 'lang_title' => $lang_info['lang_title']);
     }
     $lang_ids = array();
     $insertId = 0;
     //-----------------------------------------
     // Do we have language pack info?
     //-----------------------------------------
     if ($lang_data['lang_short']) {
         //-----------------------------------------
         // Does this pack already exist
         //-----------------------------------------
         $update_lang = $this->DB->buildAndFetch(array('select' => 'lang_id', 'from' => 'core_sys_lang', 'where' => "lang_short='{$lang_data['lang_short']}'"));
         //-----------------------------------------
         // If doesn't exist, then create new pack
         //-----------------------------------------
         if (!$update_lang['lang_id']) {
             $this->DB->insert('core_sys_lang', $lang_data);
             $insertId = $this->DB->getInsertId();
             if (@mkdir(IPS_CACHE_PATH . '/cache/lang_cache/' . $insertId)) {
                 @file_put_contents(IPS_CACHE_PATH . 'cache/lang_cache/' . $insertId . '/index.html', '');
                 @chmod(IPS_CACHE_PATH . '/cache/lang_cache/' . $insertId, 0777);
             }
             //-----------------------------------------
             // Copy over language bits from default lang
             //-----------------------------------------
             $default = $this->DB->buildAndFetch(array('select' => 'lang_id', 'from' => 'core_sys_lang', 'where' => "lang_default=1"));
             $this->DB->build(array('select' => 'word_app,word_pack,word_key,word_default', 'from' => 'core_sys_lang_words', 'where' => "lang_id={$default['lang_id']}"));
             $q = $this->DB->execute();
             while ($r = $this->DB->fetch($q)) {
                 $r['lang_id'] = $insertId;
                 $this->DB->insert('core_sys_lang_words', $r);
             }
             //-----------------------------------------
             // Rebuild IPB and disk caches
             //-----------------------------------------
             $this->registry->class_localization->rebuildLanguagesCache();
         }
     }
     //-----------------------------------------
     // We need to add language bits to every pack..
     //-----------------------------------------
     if (count($this->caches['lang_data'])) {
         foreach ($this->caches['lang_data'] as $langData) {
             $lang_ids[] = $langData['lang_id'];
         }
     } else {
         $this->DB->build(array('select' => 'lang_id', 'from' => 'core_sys_lang'));
         $this->DB->execute();
         while ($r = $this->DB->fetch()) {
             $lang_ids[] = $r['lang_id'];
         }
     }
     //-----------------------------------------
     // Init counts array
     //-----------------------------------------
     $counts = array('updates' => 0, 'inserts' => 0);
     //-----------------------------------------
     // Init a cache array to save entries
     //-----------------------------------------
     $lang_entries = array();
     if ($app_override) {
         $this->DB->build(array('select' => '*', 'from' => 'core_sys_lang_words', 'where' => "word_app='{$app_override}'"));
         $this->DB->execute();
         while ($r = $this->DB->fetch()) {
             $lang_entries[$r['lang_id']][$r['word_app']][$r['word_pack']][$r['word_key']] = $r;
         }
     }
     //-----------------------------------------
     // Start looping
     //-----------------------------------------
     foreach ($xml->fetchElements('lang') as $entry) {
         $lang = $xml->fetchElementsFromRecord($entry);
         foreach ($lang_ids as $_lang_id) {
             //-----------------------------------------
             // Build db array
             //-----------------------------------------
             $db_array = array('lang_id' => $_lang_id, 'word_app' => $app_override ? $app_override : $lang['word_app'], 'word_pack' => $lang['word_pack'], 'word_key' => $lang['word_key'], 'word_default' => stripslashes($lang['word_default']), 'word_custom' => $in_dev ? '' : stripslashes($lang['word_custom']), 'word_js' => $lang['word_js'], 'word_default_version' => $lang['word_default_version'] >= 30000 ? $lang['word_default_version'] : $LATESTVERSION['long'], 'word_custom_version' => $lang['word_custom_version']);
             //-----------------------------------------
             // If cached, get from cache
             //-----------------------------------------
             if ($lang_entries[$_lang_id][$db_array['word_app']][$db_array['word_pack']]) {
                 $lang_entry = $lang_entries[$_lang_id][$db_array['word_app']][$db_array['word_pack']][$db_array['word_key']];
             } else {
                 if (!$app_override) {
                     $this->DB->build(array('select' => '*', 'from' => 'core_sys_lang_words', 'where' => "lang_id={$_lang_id} AND word_app='{$db_array['word_app']}' AND word_pack='{$db_array['word_pack']}'"));
                     $this->DB->execute();
                     while ($r = $this->DB->fetch()) {
                         $lang_entries[$r['lang_id']][$r['word_app']][$r['word_pack']][$r['word_key']] = $r;
                     }
                     if ($lang_entries[$_lang_id][$db_array['word_app']][$db_array['word_pack']][$db_array['word_key']]) {
                         $lang_entry = $lang_entries[$_lang_id][$db_array['word_app']][$db_array['word_pack']][$db_array['word_key']];
                     }
                 }
             }
             //-----------------------------------------
             // If there is no new custom lang bit to insert
             // don't delete what is already there.
             //-----------------------------------------
             if (!$db_array['word_custom']) {
                 unset($db_array['word_custom']);
                 unset($db_array['word_custom_version']);
             }
             //-----------------------------------------
             // Lang bit already exists, update
             //-----------------------------------------
             if ($lang_entry['word_id'] and (!$insertId or $insertId == $_lang_id)) {
                 //-----------------------------------------
                 // Don't update default version
                 //-----------------------------------------
                 unset($db_array['word_default_version']);
                 $counts['updates']++;
                 $this->DB->update('core_sys_lang_words', $db_array, "word_id={$lang_entry['word_id']}");
             } else {
                 if (!$lang_entry['word_id']) {
                     $counts['inserts']++;
                     $this->DB->insert('core_sys_lang_words', $db_array);
                 }
             }
         }
     }
     //-----------------------------------------
     // Recache all our lang packs
     //-----------------------------------------
     foreach ($lang_ids as $_lang_id) {
         $this->cacheToDisk($_lang_id);
     }
     //-----------------------------------------
     // Set output message
     //-----------------------------------------
     $this->registry->output->global_message = sprintf($this->lang->words['l_updatedcount'], $counts['updates'], $counts['inserts']);
     if (is_array($this->cache_errors) and count($this->cache_errors)) {
         $this->registry->output->global_message .= "<br />" . implode("<br />", $this->cache_errors);
     }
     //-----------------------------------------
     // Free a little memory
     //-----------------------------------------
     unset($xml);
     //-----------------------------------------
     // Update IPB cache
     //-----------------------------------------
     $this->registry->class_localization->rebuildLanguagesCache();
     //-----------------------------------------
     // Return! Now!
     //-----------------------------------------
     if (!$no_return) {
         $this->languagesList();
         return;
     }
 }
 /**
  * Create new session
  *
  * @access	public
  * @param	string		Diff session title
  * @param	string		Compare HTML
  * @param	boolean		Ignore new bits
  * @return	int			New session ID
  */
 public function createSession($title, $content, $ignoreBits = FALSE)
 {
     //-----------------------------------------
     // INIT
     //-----------------------------------------
     $templateBits = array();
     //-----------------------------------------
     // Get number for missing template bits
     //-----------------------------------------
     $_bits = $this->DB->buildAndFetch(array('select' => 'COUNT(*) as count', 'from' => 'skin_templates', 'where' => 'template_set_id=0'));
     //-----------------------------------------
     // Create session
     //-----------------------------------------
     $this->DB->allow_sub_select = 1;
     $this->DB->insert('template_diff_session', array('diff_session_togo' => intval($_bits['count']), 'diff_session_done' => 0, 'diff_session_title' => $title, 'diff_session_updated' => time(), 'diff_session_ignore_missing' => $ignoreBits === TRUE ? 1 : 0));
     $diffSesssionID = $this->DB->getInsertId();
     //-----------------------------------------
     // XML
     //-----------------------------------------
     require_once IPS_KERNEL_PATH . 'classXML.php';
     $xml = new classXML(IPS_DOC_CHAR_SET);
     //-----------------------------------------
     // Check to see if its an archive...
     //-----------------------------------------
     if (strstr($content, "<xmlarchive")) {
         /* It's an archive... */
         require IPS_KERNEL_PATH . 'classXMLArchive.php';
         $xmlArchive = new classXMLArchive(IPS_KERNEL_PATH);
         $xmlArchive->readXML($content);
         /* We just want the templates.. */
         foreach ($xmlArchive->asArray() as $path => $fileData) {
             if ($fileData['path'] == 'templates') {
                 $xml->loadXML($fileData['content']);
                 foreach ($xml->fetchElements('template') as $xmlelement) {
                     $data = $xml->fetchElementsFromRecord($xmlelement);
                     if (is_array($data)) {
                         $templateBits[] = $data;
                     }
                 }
             }
         }
     } else {
         $xml->loadXML($content);
         foreach ($xml->fetchElements('template') as $xmlelement) {
             $data = $xml->fetchElementsFromRecord($xmlelement);
             if (is_array($data)) {
                 $templateBits[] = $data;
             }
         }
     }
     //-----------------------------------------
     // Got anything?
     //-----------------------------------------
     if (!count($templateBits)) {
         return FALSE;
     }
     //-----------------------------------------
     // Build session data
     //-----------------------------------------
     foreach ($templateBits as $bit) {
         $diffKey = $diffSesssionID . ':' . $bit['template_group'] . ':' . $bit['template_name'];
         if (!$seen[$diffKey]) {
             $this->DB->allow_sub_select = 1;
             $this->DB->insert('templates_diff_import', array('diff_key' => $diffKey, 'diff_func_group' => $bit['template_group'], 'diff_func_data' => $bit['template_data'], 'diff_func_name' => $bit['template_name'], 'diff_func_content' => $bit['template_content'], 'diff_session_id' => $diffSesssionID));
             $seen[$diffKey] = 1;
         }
     }
     return $diffSesssionID;
 }
 /**
  * Imports a set XMLArchive
  *
  * @access	public
  * @param	string		XMLArchive content to import
  * @param	int 		[ Skin set parent. If omitted, it will be made a root skin ]
  * @param	string		[ Images directory to use. If omitted, default skin's image dir is used ]
  * @param	string		[ Name of skin to create. If omitted, name from skin set is used ]
  * @param	bool		[ Whether or not we are attempting to upgrade an existing skin ]
  * @return	mixed		bool, or number of items added
  */
 public function importSetXMLArchive($content, $parentID = 0, $imageDir = '', $setName = '', $upgrading = FALSE)
 {
     //-----------------------------------------
     // INIT
     //-----------------------------------------
     $templates = array();
     $csss = array();
     $groups = array();
     $defaultSkin = array();
     $return = array('replacements' => 0, 'css' => 0, 'templates' => 0, 'upgrade' => FALSE);
     //-----------------------------------------
     // Got anything?
     //-----------------------------------------
     if (!strstr($content, "<xmlarchive")) {
         $this->_addErrorMessage($this->lang->words['invalidxmlarchivei']);
         return FALSE;
     }
     //-----------------------------------------
     // Make admin group list
     //-----------------------------------------
     foreach ($this->caches['group_cache'] as $id => $data) {
         if ($data['g_access_cp']) {
             $groups[] = $id;
         }
     }
     //-----------------------------------------
     // Grab the XMLArchive class
     //-----------------------------------------
     require_once IPS_KERNEL_PATH . 'classXMLArchive.php';
     /*noLibHook*/
     $xmlArchive = new classXMLArchive();
     $xmlArchive->readXML($content);
     if (!$xmlArchive->countFileArray()) {
         $this->_addErrorMessage($this->lang->words['emptyxmlarchivei']);
         return FALSE;
     }
     //-----------------------------------------
     // Gather data
     //-----------------------------------------
     /* Info */
     $infoXml = $xmlArchive->getFile('info.xml');
     if (!$infoXml) {
         $this->_addErrorMessage($this->lang->words['noinfoxml']);
         return FALSE;
     }
     $info = $this->parseInfoXML($infoXml);
     /* Are we attempting to upgrade? */
     $setID = 0;
     $doUpgrade = FALSE;
     $new_items = array('replacements' => array(), 'css' => array(), 'templates' => array());
     if ($info['set_key'] && $upgrading) {
         foreach ($this->caches['skinsets'] as $set_id => $set_data) {
             if ($set_data['set_key'] == $info['set_key']) {
                 $setID = $set_id;
                 $doUpgrade = TRUE;
                 $return['upgrade'] = TRUE;
                 break;
             }
         }
     }
     /* Replacements */
     $replacements = $this->parseReplacementsXML($xmlArchive->getFile('replacements.xml'));
     /* Templates */
     foreach ($xmlArchive->asArray() as $path => $fileData) {
         if ($fileData['path'] == 'templates' && $fileData['content']) {
             $templates[str_replace('.xml', '', $fileData['filename'])] = $this->parseTemplatesXML($fileData['content']);
         }
     }
     /* Templates */
     foreach ($xmlArchive->asArray() as $path => $fileData) {
         if ($fileData['path'] == 'css') {
             $csss[str_replace('.xml', '', $fileData['filename'])] = $this->parseCSSXML($fileData['content']);
         }
     }
     if (!is_array($info)) {
         $this->_addErrorMessage($this->lang->words['noinfoxml']);
         return FALSE;
     }
     $info['set_output_format'] = $info['set_output_format'] ? $info['set_output_format'] : 'html';
     //-----------------------------------------
     // Find default skin
     //-----------------------------------------
     foreach ($this->registry->output->allSkins as $id => $data) {
         if ($data['set_is_default'] and $data['set_output_format'] == $info['set_output_format']) {
             $defaultSkin = $data;
             break;
         }
     }
     /* Make sure key in unique */
     $test = $this->DB->buildAndFetch(array('select' => '*', 'from' => 'skin_collections', 'where' => 'set_key=\'' . $this->DB->addSlashes($info['set_key']) . '\' AND set_id != ' . intval($setID)));
     if ($test['set_id']) {
         $info['set_key'] .= '_' . time();
     }
     //-----------------------------------------
     // Build Set Array
     //-----------------------------------------
     $newSet = array('set_name' => $setName ? $setName : $info['set_name'] . ' (Import)', 'set_key' => $info['set_key'], 'set_parent_id' => $parentID, 'set_permissions' => implode(",", $groups), 'set_is_default' => 0, 'set_author_name' => $info['set_author_name'], 'set_author_url' => $info['set_author_url'], 'set_image_dir' => $imageDir ? $imageDir : $defaultSkin['set_image_dir'], 'set_emo_dir' => $defaultSkin['set_emo_dir'], 'set_css_inline' => 1, 'set_output_format' => $info['set_output_format'], 'set_css_groups' => '', 'set_hide_from_list' => 1, 'set_order' => intval($this->fetchHighestSetPosition()) + 1, 'set_master_key' => isset($info['set_master_key']) ? $info['set_master_key'] : 'root', 'set_updated' => time());
     if ($setID) {
         //-----------------------------------------
         // Update...
         //-----------------------------------------
         $this->DB->update('skin_collections', array('set_author_name' => $info['set_author_name'], 'set_author_url' => $info['set_author_url'], 'set_updated' => time()), 'set_id=' . $setID);
     } else {
         //-----------------------------------------
         // Insert...
         //-----------------------------------------
         $this->DB->insert('skin_collections', $newSet);
         $setID = $this->DB->getInsertId();
     }
     /* Rebuild trees */
     $this->rebuildTreeInformation($setID);
     /* Now re-load to fetch the tree information */
     $newSet = $this->DB->buildAndFetch(array('select' => '*', 'from' => 'skin_collections', 'where' => 'set_id=' . $setID));
     /* Add to allSkins array for caching functions below */
     $newSet['_parentTree'] = unserialize($newSet['set_parent_array']);
     $newSet['_childTree'] = unserialize($newSet['set_child_array']);
     $newSet['_userAgents'] = unserialize($newSet['set_locked_uagent']);
     $newSet['_cssGroupsArray'] = unserialize($newSet['set_css_groups']);
     $this->registry->output->allSkins[$setID] = $newSet;
     //-----------------------------------------
     // Replacements...
     //-----------------------------------------
     if (is_array($replacements)) {
         foreach ($replacements as $replacement) {
             if ($replacement['replacement_key']) {
                 $return['replacements']++;
                 $existing_id = 0;
                 /* Check if we need to update or insert */
                 if ($doUpgrade) {
                     $exists = $this->DB->buildAndFetch(array('select' => 'replacement_id', 'from' => 'skin_replacements', 'where' => "replacement_key='{$replacement['replacement_key']}' AND replacement_set_id={$setID} AND replacement_added_to={$setID}"));
                     $existing_id = $exists['replacement_id'];
                 }
                 if ($existing_id) {
                     $new_items['replacements'][] = $existing_id;
                     $this->DB->update('skin_replacements', array('replacement_content' => $replacement['replacement_content']), "replacement_id=" . $existing_id);
                 } else {
                     $this->DB->insert('skin_replacements', array('replacement_key' => $replacement['replacement_key'], 'replacement_content' => $replacement['replacement_content'], 'replacement_set_id' => $setID, 'replacement_added_to' => $setID));
                 }
             }
         }
     }
     //-----------------------------------------
     // CSS...
     //-----------------------------------------
     /* Fetch master CSS */
     $_MASTER = $this->fetchCSS(0);
     if (is_array($csss)) {
         foreach (ipsRegistry::$applications as $appDir => $data) {
             if (isset($csss[$appDir]) && is_array($csss[$appDir])) {
                 foreach ($csss[$appDir] as $css) {
                     if ($css['css_group']) {
                         $return['css']++;
                         $existing_id = 0;
                         /* Check if we need to update or insert */
                         if ($doUpgrade) {
                             $exists = $this->DB->buildAndFetch(array('select' => 'css_id', 'from' => 'skin_css', 'where' => "css_group='{$css['css_group']}' AND css_app='{$css['css_app']}' AND css_set_id={$setID}"));
                             $existing_id = $exists['css_id'];
                         }
                         if ($existing_id) {
                             $new_items['css'][] = $existing_id;
                             $this->DB->update('skin_css', array('css_content' => $css['css_content'], 'css_position' => $css['css_position'], 'css_attributes' => $css['css_attributes'], 'css_app_hide' => $css['css_app_hide'], 'css_modules' => str_replace(' ', '', $css['css_modules']), 'css_updated' => time(), 'css_added_to' => isset($_MASTER[$css['css_group']]) ? 0 : $setID), "css_id=" . $existing_id);
                         } else {
                             $this->DB->insert('skin_css', array('css_group' => $css['css_group'], 'css_content' => $css['css_content'], 'css_position' => $css['css_position'], 'css_attributes' => $css['css_attributes'], 'css_app' => $css['css_app'], 'css_app_hide' => $css['css_app_hide'], 'css_modules' => str_replace(' ', '', $css['css_modules']), 'css_updated' => time(), 'css_set_id' => $setID, 'css_added_to' => isset($_MASTER[$css['css_group']]) ? 0 : $setID));
                         }
                     }
                 }
             }
         }
     }
     //-----------------------------------------
     // Templates - only import apps we have...
     //-----------------------------------------
     /* Fetch all master items */
     $_MASTER = $this->fetchTemplates(0, 'allNoContent');
     if (is_array($templates)) {
         foreach (ipsRegistry::$applications as $appDir => $data) {
             if (array_key_exists($appDir, $templates)) {
                 foreach ($templates[$appDir] as $template) {
                     if ($template['template_group'] and $template['template_name']) {
                         /* Figure out if this is added by a user or not */
                         $isAdded = (is_array($_MASTER[$template['template_group']][strtolower($template['template_name'])]) and !$_MASTER[$template['template_group']][strtolower($template['template_name'])]['template_user_added']) ? 0 : 1;
                         $return['templates']++;
                         $existing_id = 0;
                         /* Check if we need to update or insert */
                         if ($doUpgrade) {
                             $exists = $this->DB->buildAndFetch(array('select' => 'template_id', 'from' => 'skin_templates', 'where' => "template_set_id={$setID} AND template_group='{$template['template_group']}' AND template_name='{$template['template_name']}'"));
                             $existing_id = $exists['template_id'];
                         }
                         if ($existing_id) {
                             $new_items['templates'][] = $existing_id;
                             $this->DB->update('skin_templates', array('template_content' => $template['template_content'], 'template_data' => $template['template_data'], 'template_updated' => $template['template_updated'] ? $template['template_updated'] : IPS_UNIX_TIME_NOW, 'template_removable' => 1, 'template_user_edited' => 1, 'template_user_added' => $isAdded, 'template_added_to' => $setID), "template_id=" . $existing_id);
                         } else {
                             $this->DB->insert('skin_templates', array('template_set_id' => $setID, 'template_group' => $template['template_group'], 'template_content' => $template['template_content'], 'template_name' => $template['template_name'], 'template_data' => $template['template_data'], 'template_updated' => $template['template_updated'] ? $template['template_updated'] : IPS_UNIX_TIME_NOW, 'template_removable' => 1, 'template_user_edited' => 1, 'template_user_added' => $isAdded, 'template_added_to' => $setID));
                         }
                     }
                 }
             }
         }
     }
     //-----------------------------------------
     // If upgrading, and there are items from an old
     // skin not in the new one, delete the old elements
     // This probably won't ever come up, but I'm anal retentive :P
     //-----------------------------------------
     if ($doUpgrade) {
         if (count($new_items['replacements'])) {
             $this->DB->delete('skin_replacements', "replacement_set_id={$setID} AND replacement_id NOT IN (" . implode(',', $new_items['replacements']) . ")");
         }
         if (count($new_items['css'])) {
             $this->DB->delete('skin_css', "css_set_id={$setID} AND css_id NOT IN (" . implode(',', $new_items['css']) . ")");
         }
         if (count($new_items['templates'])) {
             $this->DB->delete('skin_templates', "template_set_id={$setID} AND template_id NOT IN (" . implode(',', $new_items['templates']) . ")");
         }
     }
     //-----------------------------------------
     // Re-cache
     //-----------------------------------------
     $this->rebuildReplacementsCache($setID);
     $this->rebuildCSS($setID);
     $this->rebuildPHPTemplates($setID);
     $this->rebuildSkinSetsCache();
     //-----------------------------------------
     // Done....
     //-----------------------------------------
     return $return;
 }