/** This function checks if the information in the installed addons file is
 *  consistent with what is actually available. This avoids e.g. that an
 *  addon is installed, but not marked here (and therefore shows up as
 *  not installed in the addons GUI), see bug #455.
 */
void AddonsManager::checkInstalledAddons()
{
    bool something_was_changed = false;

    // Lock the whole addons list to make sure a consistent view is
    // written back to disk. The network thread might still be 
    // downloading icons and modify content
    m_addons_list.lock();

    // First karts
    // -----------
    for(unsigned int i=0; i<kart_properties_manager->getNumberOfKarts(); i++)
    {
        const KartProperties *kp = kart_properties_manager->getKartById(i);
        const std::string &dir=kp->getKartDir();
        if(dir.find(file_manager->getAddonsDir())==std::string::npos)
            continue;
        int n = getAddonIndex(kp->getIdent());
        if(n<0) continue;
        if(!m_addons_list.getData()[n].isInstalled())
        {
            printf("[addons] Marking '%s' as being installed.\n", 
                   kp->getIdent().c_str());
            m_addons_list.getData()[n].setInstalled(true);
            something_was_changed = true;
        }
    }

    // Then tracks
    // -----------
    for(unsigned int i=0; i<track_manager->getNumberOfTracks(); i++)
    {
        const Track *track = track_manager->getTrack(i);
        const std::string &dir=track->getFilename();
        if(dir.find(file_manager->getAddonsDir())==std::string::npos)
            continue;
        int n = getAddonIndex(track->getIdent());
        if(n<0) continue;
        if(!m_addons_list.getData()[n].isInstalled())
        {
            printf("[addons] Marking '%s' as being installed.\n", 
                   track->getIdent().c_str());
            m_addons_list.getData()[n].setInstalled(true);
            something_was_changed = true;
        }
    }
    if(something_was_changed)
        saveInstalled();
    m_addons_list.unlock();
}   // checkInstalledAddons
/** Removes all files froma login.
 *  \param addon The addon to be removed.
 *  \return True if uninstallation was successful.
 */
bool AddonsManager::uninstall(const Addon &addon)
{
    std::cout << "[addons] Uninstalling <" 
              << core::stringc(addon.getName()).c_str() << ">\n";

    // addon is a const reference, and to avoid removing the const, we
    // find the proper index again to modify the installed state
    int index = getAddonIndex(addon.getId());
    assert(index>=0 && index < (int)m_addons_list.getData().size());
    m_addons_list.getData()[index].setInstalled(false);

    //remove the addons directory
	bool error = false;
	// if the user deleted the data directory for an add-on with
	// filesystem tools, removeTrack/removeKart will trigger an assert
	// because the kart/track was never added in the first place
	if (file_manager->fileExists(addon.getDataDir()))
	{
		error = !file_manager->removeDirectory(addon.getDataDir());
		if(addon.getType()=="kart")
		{
			kart_properties_manager->removeKart(addon.getId());
		}
		else if(addon.getType()=="track" || addon.getType()=="arena")
		{
			track_manager->removeTrack(addon.getId());
		}
	}
    saveInstalled();
    return !error;
}   // uninstall
Beispiel #3
0
/** Installs or updates (i.e. = install on top of an existing installation) an 
 *  addon. It checks for the directories and then unzips the file (which must 
 *  already have been downloaded).
 *  \param addon Addon data for the addon to install.
 *  \return true if installation was successful.
 */
bool AddonsManager::install(const Addon &addon)
{
    bool success=true;
    const std::string &id = addon.getId();
    file_manager->checkAndCreateDirForAddons(id, addon.getTypeDirectory());

    //extract the zip in the addons folder called like the addons name    
    std::string base_name = StringUtils::getBasename(addon.getZipFileName());
    std::string from      = file_manager->getAddonsFile("tmp/"+base_name);
    std::string to        = addon.getDataDir();
    
    success = extract_zip(from, to);
    if (!success)
    {
        // TODO: show a message in the interface
        std::cerr << "[addons] Failed to unzip '" << from << "' to '" 
                  << to << "'\n";
        std::cerr << "[addons] Zip file will not be removed.\n";
        return false;
    }

    if(!file_manager->removeFile(from))
    {
        std::cerr << "[addons] Problems removing temporary file '"
                  << from << "'.\n";
    }

    int index = getAddonIndex(addon.getId());
    assert(index>=0 && index < (int)m_addons_list.getData().size());
    m_addons_list.getData()[index].setInstalled(true);
    
    if(addon.getType()=="kart")
    {
        // We have to remove the mesh of the kart since otherwise it remains
        // cashed (if a kart is updated), and will therefore be found again 
        // when reloading the karts. This is important on one hand since we 
        // reload all karts (this function is easily available) and existing
        // karts will not reload their meshes.
        const KartProperties *prop = 
            kart_properties_manager->getKart(addon.getId());
        // If the model already exist, first remove the old kart
        if(prop)
            kart_properties_manager->removeKart(addon.getId());
        kart_properties_manager->loadKart(addon.getDataDir());
    }
    else if (addon.getType()=="track" || addon.getType()=="arena")
    {
        Track *track = track_manager->getTrack(addon.getId());
        if(track)
            track_manager->removeTrack(addon.getId());
        track_manager->loadTrack(addon.getDataDir());
    }
    saveInstalled();
    return true;
}   // install
Beispiel #4
0
/** Removes all files froma login.
 *  \param addon The addon to be removed.
 *  \return True if uninstallation was successful.
 */
bool AddonsManager::uninstall(const Addon &addon)
{
    std::cout << "[addons] Uninstalling <" 
              << core::stringc(addon.getName()).c_str() << ">\n";

    // addon is a const reference, and to avoid removing the const, we
    // find the proper index again to modify the installed state
    int index = getAddonIndex(addon.getId());
    assert(index>=0 && index < (int)m_addons_list.getData().size());
    m_addons_list.getData()[index].setInstalled(false);

    //remove the addons directory
    bool error = !file_manager->removeDirectory(addon.getDataDir());
    if(addon.getType()=="kart")
    {
        kart_properties_manager->removeKart(addon.getId());
    }
    else if(addon.getType()=="track" || addon.getType()=="arena")
    {
        track_manager->removeTrack(addon.getId());
    }
    saveInstalled();
    return !error;
}   // uninstall
/** This initialises the online portion of the addons manager. It uses the
 *  downloaded list of available addons. This is called by network_http before
 *  it goes into command-receiving mode, so we can't use any asynchronous calls
 *  here (though this is being called from a separate thread , so the
 *  main GUI is not blocked anyway). This function will update the state 
 *  variable
 */
void AddonsManager::initOnline(const XMLNode *xml)
{
    m_addons_list.lock();
    // Clear the list in case that a reinit is being done.
    m_addons_list.getData().clear();
    loadInstalledAddons();
    m_addons_list.unlock();

    for(unsigned int i=0; i<xml->getNumNodes(); i++)
    {
        const XMLNode *node = xml->getNode(i);
        const std::string &name = node->getName();
        // Ignore news/redirect, which is handled by network_http
        if(name=="include" || name=="message") continue;
        if(node->getName()=="track" || node->getName()=="kart" ||
            node->getName()=="arena"                                 )
        {
            Addon addon(*node);
            int index = getAddonIndex(addon.getId());

            int stk_version=0;
            node->get("format", &stk_version);
            int   testing=-1;
            node->get("testing", &testing);

            bool wrong_version=false;

            if(addon.getType()=="kart")
                wrong_version = stk_version <stk_config->m_min_kart_version ||
                                stk_version >stk_config->m_max_kart_version   ;
            else
                wrong_version = stk_version <stk_config->m_min_track_version ||
                                stk_version >stk_config->m_max_track_version   ;
            // If the add-on is included, behave like it is a wrong version
            if (addon.testIncluded(addon.getMinIncludeVer(), addon.getMaxIncludeVer()))
                wrong_version = true;

            // Check which version to use: only for this stk version,
            // and not addons that are marked as hidden (testing=0)
            if(wrong_version|| testing==0)
            {
                // If the version is too old (e.g. after an update of stk)
                // remove a cached icon.
                std::string full_path = 
                    file_manager->getAddonsFile("icons/"
                                                +addon.getIconBasename());
                if(file_manager->fileExists(full_path))
                {
                    if(UserConfigParams::logAddons())
                        printf("[addons] Removing cached icon '%s'.\n", 
                               addon.getIconBasename().c_str());
                    file_manager->removeFile(full_path);
                }
                continue;
            }

            m_addons_list.lock();
            if(index>=0)
            {
                Addon& tmplist_addon = m_addons_list.getData()[index];
                
                // Only copy the data if a newer revision is found (ignore unapproved
                // revisions unless player is in the mode to see them)
                if (tmplist_addon.getRevision() < addon.getRevision() &&
                    (addon.testStatus(Addon::AS_APPROVED) || UserConfigParams::m_artist_debug_mode))
                {
                    m_addons_list.getData()[index].copyInstallData(addon);
                }
            }
            else
            {
                m_addons_list.getData().push_back(addon);
                index = m_addons_list.getData().size()-1;
            }
            // Mark that this addon still exists on the server
            m_addons_list.getData()[index].setStillExists();
            m_addons_list.unlock();
        }
        else
        {
            fprintf(stderr, 
                    "[addons] Found invalid node '%s' while downloading addons.\n",
                    node->getName().c_str());
            fprintf(stderr, "[addons] Ignored.\n");
        }
    }   // for i<xml->getNumNodes
    delete xml;

    // Now remove all items from the addons-installed list, that are not
    // on the server anymore (i.e. not in the addons.xml file), and not
    // installed. If found, remove the icon cached for this addon.
    // Note that if (due to a bug) an icon is shared (i.e. same icon on
    // an addon that's still on the server and an invalid entry in the
    // addons installed file), it will be re-downloaded later.
    m_addons_list.lock();
    unsigned int count = m_addons_list.getData().size();

    for(unsigned int i=0; i<count;)
    {
        if(m_addons_list.getData()[i].getStillExists() ||
            m_addons_list.getData()[i].isInstalled())
        {
            i++;
            continue;
        }
        // This addon is not on the server anymore, and not installed. Remove
        // it from the list. 
        if(UserConfigParams::logAddons())
            printf(
                "[addons] Removing '%s' which is not on the server anymore.\n",
                m_addons_list.getData()[i].getId().c_str() );
        std::string icon = m_addons_list.getData()[i].getIconBasename();
        std::string icon_file =file_manager->getAddonsFile("icons/"+icon);
        if(file_manager->fileExists(icon_file))
        {
            file_manager->removeFile(icon_file);
            // Ignore errors silently.
        }
        m_addons_list.getData()[i] = m_addons_list.getData()[count-1];
        m_addons_list.getData().pop_back();
        count--;
    }
    m_addons_list.unlock();

    m_state.setAtomic(STATE_READY);

    if (UserConfigParams::m_internet_status == INetworkHttp::IPERM_ALLOWED)
        downloadIcons();
}   // initOnline
/** Returns an addon with a given id. Raises an assertion if the id is not 
 *  found!
 *  \param id The id to search for.
 */
const Addon* AddonsManager::getAddon(const std::string &id) const
{
    int i = getAddonIndex(id);
    return (i<0) ? NULL : &(m_addons_list.getData()[i]);
}   // getAddon