## Build list of sources for supertux binary
-FILE(GLOB SUPERTUX_SOURCES RELATIVE ${SUPERTUX_SOURCE_DIR} src/*.cpp src/audio/*.cpp src/badguy/*.cpp src/binreloc/*.cpp src/control/*.cpp src/gui/*.cpp src/lisp/*.cpp src/math/*.cpp src/object/*.cpp src/physfs/*.cpp src/sprite/*.cpp src/tinygettext/*.cpp src/trigger/*.cpp src/video/*.cpp src/worldmap/*.cpp src/scripting/*.cpp src/obstack/*.c)
+FILE(GLOB SUPERTUX_SOURCES RELATIVE ${SUPERTUX_SOURCE_DIR} src/*.cpp src/audio/*.cpp src/badguy/*.cpp src/binreloc/*.cpp src/control/*.cpp src/gui/*.cpp src/lisp/*.cpp src/math/*.cpp src/object/*.cpp src/physfs/*.cpp src/sprite/*.cpp src/tinygettext/*.cpp src/trigger/*.cpp src/video/*.cpp src/worldmap/*.cpp src/scripting/*.cpp src/addon/*.cpp src/obstack/*.c)
## Debug options
+++ /dev/null
-// $Id$
-//
-// SuperTux - Add-on
-// Copyright (C) 2007 Christoph Sommer <christoph.sommer@2007.expires.deltadevelopment.de>
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-// 02111-1307, USA.
-//
-
-#include <sstream>
-#include <stdexcept>
-#include "addon.hpp"
-#include "addon_manager.hpp"
-
-void
-Addon::install()
-{
- AddonManager& adm = AddonManager::get_instance();
- adm.install(*this);
-}
-
-void
-Addon::remove()
-{
- AddonManager& adm = AddonManager::get_instance();
- adm.remove(*this);
-}
-
-void
-Addon::parse(const lisp::Lisp& lisp)
-{
- try {
- lisp.get("kind", kind);
- lisp.get("title", title);
- lisp.get("author", author);
- lisp.get("license", license);
- lisp.get("http-url", http_url);
- lisp.get("file", file);
- lisp.get("md5", md5);
- } catch(std::exception& e) {
- std::stringstream msg;
- msg << "Problem when parsing addoninfo: " << e.what();
- throw std::runtime_error(msg.str());
- }
-}
-
-void
-Addon::parse(std::string fname)
-{
- try {
- lisp::Parser parser;
- const lisp::Lisp* root = parser.parse(fname);
- const lisp::Lisp* addon = root->get_lisp("supertux-addoninfo");
- if(!addon) throw std::runtime_error("file is not a supertux-addoninfo file.");
- parse(*addon);
- } catch(std::exception& e) {
- std::stringstream msg;
- msg << "Problem when reading addoninfo '" << fname << "': " << e.what();
- throw std::runtime_error(msg.str());
- }
-}
-
-void
-Addon::write(lisp::Writer& writer) const
-{
- writer.start_list("supertux-addoninfo");
- if (kind != "") writer.write_string("kind", kind);
- if (title != "") writer.write_string("title", title);
- if (author != "") writer.write_string("author", author);
- if (license != "") writer.write_string("license", license);
- if (http_url != "") writer.write_string("http-url", http_url);
- if (file != "") writer.write_string("file", file);
- if (md5 != "") writer.write_string("md5", md5);
- writer.end_list("supertux-addoninfo");
-}
-
-void
-Addon::write(std::string fname) const
-{
- lisp::Writer writer(fname);
- write(writer);
-}
-
-bool
-Addon::equals(const Addon& addon2) const
-{
- if ((this->md5 == "") || (addon2.md5 == "")) return (this->title == addon2.title);
- return (this->md5 == addon2.md5);
-}
-
+++ /dev/null
-// $Id$
-//
-// SuperTux - Add-on
-// Copyright (C) 2007 Christoph Sommer <christoph.sommer@2007.expires.deltadevelopment.de>
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-// 02111-1307, USA.
-//
-#ifndef ADDON_H
-#define ADDON_H
-
-#include <string>
-#include <vector>
-#include "lisp/parser.hpp"
-#include "lisp/lisp.hpp"
-#include "lisp/writer.hpp"
-
-/**
- * Represents an (available or installed) Add-on, e.g. a level set
- */
-class Addon
-{
-public:
- std::string kind;
- std::string title;
- std::string author;
- std::string license;
- std::string http_url;
- std::string file;
- std::string md5;
-
- bool isInstalled;
-
- /**
- * Download and install Add-on
- */
- void install();
-
- /**
- * Physically delete Add-on
- */
- void remove();
-
- /**
- * Read additional information from given contents of a (supertux-addoninfo ...) block
- */
- void parse(const lisp::Lisp& lisp);
-
- /**
- * Read additional information from given file
- */
- void parse(std::string fname);
-
- /**
- * Writes out Add-on metainformation to a Lisp Writer
- */
- void write(lisp::Writer& writer) const;
-
- /**
- * Writes out Add-on metainformation to a file
- */
- void write(std::string fname) const;
-
- /**
- * Checks if Add-on is the same as given one.
- * If available, checks MD5 sum, else relies on title alone.
- */
- bool equals(const Addon& addon2) const;
-
-};
-
-#endif
--- /dev/null
+// $Id$
+//
+// SuperTux - Add-on
+// Copyright (C) 2007 Christoph Sommer <christoph.sommer@2007.expires.deltadevelopment.de>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+
+#include <string>
+#include <sstream>
+#include <stdexcept>
+#include <physfs.h>
+#include "addon/addon.hpp"
+#include "addon/addon_manager.hpp"
+#include "log.hpp"
+#include "addon/md5.hpp"
+
+std::string
+Addon::get_md5() const
+{
+ if (!installed) {
+ if (stored_md5 == "") log_warning << "Add-on not installed and no stored MD5 available" << std::endl;
+ return stored_md5;
+ }
+
+ if (calculated_md5 != "") return calculated_md5;
+
+ if (installed_physfs_filename == "") throw std::runtime_error("Tried to calculate MD5 of Add-on with unknown filename");
+
+ // TODO: this does not work as expected for some files -- IFileStream seems to not always behave like an ifstream.
+ //IFileStream ifs(installed_physfs_filename);
+ //std::string md5 = MD5(ifs).hex_digest();
+
+ MD5 md5;
+ PHYSFS_file* file;
+ file = PHYSFS_openRead(installed_physfs_filename.c_str());
+ unsigned char buffer[1024];
+ while (true) {
+ PHYSFS_sint64 len = PHYSFS_read(file, buffer, 1, sizeof(buffer));
+ if (len <= 0) break;
+ md5.update(buffer, len);
+ }
+ PHYSFS_close(file);
+
+ calculated_md5 = md5.hex_digest();
+ log_debug << "MD5 of " << title << ": " << calculated_md5 << std::endl;
+
+ return calculated_md5;
+}
+
+void
+Addon::parse(const lisp::Lisp& lisp)
+{
+ try {
+ lisp.get("kind", kind);
+ lisp.get("title", title);
+ lisp.get("author", author);
+ lisp.get("license", license);
+ lisp.get("http-url", http_url);
+ lisp.get("file", suggested_filename);
+ lisp.get("md5", stored_md5);
+ } catch(std::exception& e) {
+ std::stringstream msg;
+ msg << "Problem when parsing addoninfo: " << e.what();
+ throw std::runtime_error(msg.str());
+ }
+}
+
+void
+Addon::parse(std::string fname)
+{
+ try {
+ lisp::Parser parser;
+ const lisp::Lisp* root = parser.parse(fname);
+ const lisp::Lisp* addon = root->get_lisp("supertux-addoninfo");
+ if(!addon) throw std::runtime_error("file is not a supertux-addoninfo file.");
+ parse(*addon);
+ } catch(std::exception& e) {
+ std::stringstream msg;
+ msg << "Problem when reading addoninfo '" << fname << "': " << e.what();
+ throw std::runtime_error(msg.str());
+ }
+}
+
+void
+Addon::write(lisp::Writer& writer) const
+{
+ writer.start_list("supertux-addoninfo");
+ if (kind != "") writer.write_string("kind", kind);
+ if (title != "") writer.write_string("title", title);
+ if (author != "") writer.write_string("author", author);
+ if (license != "") writer.write_string("license", license);
+ if (http_url != "") writer.write_string("http-url", http_url);
+ if (suggested_filename != "") writer.write_string("file", suggested_filename);
+ if (stored_md5 != "") writer.write_string("md5", stored_md5);
+ writer.end_list("supertux-addoninfo");
+}
+
+void
+Addon::write(std::string fname) const
+{
+ lisp::Writer writer(fname);
+ write(writer);
+}
+
+bool
+Addon::operator==(Addon addon2) const
+{
+ std::string s1 = this->get_md5();
+ std::string s2 = addon2.get_md5();
+
+ if ((s1 != "") && (s2 != "")) return (s1 == s2);
+
+ if (this->title != addon2.title) return false;
+ if (this->author != addon2.author) return false;
+ if (this->kind != addon2.kind) return false;
+ return true;
+}
+
--- /dev/null
+// $Id$
+//
+// SuperTux - Add-on
+// Copyright (C) 2007 Christoph Sommer <christoph.sommer@2007.expires.deltadevelopment.de>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+#ifndef ADDON_H
+#define ADDON_H
+
+#include <string>
+#include <vector>
+#include "lisp/parser.hpp"
+#include "lisp/lisp.hpp"
+#include "lisp/writer.hpp"
+
+class Addon;
+
+#include "addon/addon_manager.hpp"
+
+/**
+ * Represents an (available or installed) Add-on, e.g. a level set
+ */
+class Addon
+{
+public:
+ std::string kind;
+ std::string title;
+ std::string author;
+ std::string license;
+ std::string http_url;
+ std::string suggested_filename; /**< filename suggested by addon author, e.g. "pak0.zip" */
+ std::string installed_physfs_filename; /**< PhysFS filename on disk, e.g. "pak0.zip" */
+ std::string installed_absolute_filename; /**< complete path and filename on disk, e.g. "/home/sommer/.supertux2/pak0.zip" */
+ std::string stored_md5;
+ bool installed;
+ bool loaded;
+
+ /**
+ * Get MD5, based either on installed file's contents or stored value
+ */
+ std::string get_md5() const;
+
+ /**
+ * Read additional information from given contents of a (supertux-addoninfo ...) block
+ */
+ void parse(const lisp::Lisp& lisp);
+
+ /**
+ * Read additional information from given file
+ */
+ void parse(std::string fname);
+
+ /**
+ * Writes out Add-on metainformation to a Lisp Writer
+ */
+ void write(lisp::Writer& writer) const;
+
+ /**
+ * Writes out Add-on metainformation to a file
+ */
+ void write(std::string fname) const;
+
+ /**
+ * Checks if Add-on is the same as given one.
+ * If available, checks MD5 sum, else relies on kind, author and title alone.
+ */
+ bool operator==(Addon addon2) const;
+
+protected:
+ friend class AddonManager;
+
+ mutable std::string calculated_md5;
+
+ Addon() {};
+};
+
+#endif
--- /dev/null
+// $Id$
+//
+// SuperTux - Add-on Manager
+// Copyright (C) 2007 Christoph Sommer <christoph.sommer@2007.expires.deltadevelopment.de>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+
+#include <sstream>
+#include <stdexcept>
+#include <cstdlib>
+#include <list>
+#include <physfs.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include "addon/addon_manager.hpp"
+#include "config.h"
+#include "log.hpp"
+#include "lisp/parser.hpp"
+#include "lisp/lisp.hpp"
+#include "lisp/list_iterator.hpp"
+#include "physfs/physfs_stream.hpp"
+
+#ifdef HAVE_LIBCURL
+#include <curl/curl.h>
+#include <curl/types.h>
+#include <curl/easy.h>
+#endif
+
+#ifdef HAVE_LIBCURL
+namespace {
+
+ size_t my_curl_string_append(void *ptr, size_t size, size_t nmemb, void *string_ptr)
+ {
+ std::string& s = *static_cast<std::string*>(string_ptr);
+ std::string buf(static_cast<char*>(ptr), size * nmemb);
+ s += buf;
+ log_debug << "read " << size * nmemb << " bytes of data..." << std::endl;
+ return size * nmemb;
+ }
+
+ size_t my_curl_physfs_write(void *ptr, size_t size, size_t nmemb, void *f_p)
+ {
+ PHYSFS_file* f = static_cast<PHYSFS_file*>(f_p);
+ PHYSFS_sint64 written = PHYSFS_write(f, ptr, size, nmemb);
+ log_debug << "read " << size * nmemb << " bytes of data..." << std::endl;
+ return size * written;
+ }
+
+}
+#endif
+
+AddonManager&
+AddonManager::get_instance()
+{
+ static AddonManager instance;
+ return instance;
+}
+
+AddonManager::AddonManager()
+{
+#ifdef HAVE_LIBCURL
+ curl_global_init(CURL_GLOBAL_ALL);
+#endif
+}
+
+AddonManager::~AddonManager()
+{
+#ifdef HAVE_LIBCURL
+ curl_global_cleanup();
+#endif
+
+ for (std::vector<Addon*>::iterator i = addons.begin(); i != addons.end(); i++) delete *i;
+}
+
+std::vector<Addon*>
+AddonManager::get_addons()
+{
+/*
+ for (std::vector<Addon>::iterator it = installed_addons.begin(); it != installed_addons.end(); ++it) {
+ Addon& addon = *it;
+ if (addon.md5 == "") addon.md5 = calculate_md5(addon);
+ }
+*/
+ return addons;
+}
+
+void
+AddonManager::check_online()
+{
+#ifdef HAVE_LIBCURL
+ char error_buffer[CURL_ERROR_SIZE+1];
+
+ const char* baseUrl = "http://supertux.berlios.de/addons/index.nfo";
+ std::string addoninfos = "";
+
+ CURL *curl_handle;
+ curl_handle = curl_easy_init();
+ curl_easy_setopt(curl_handle, CURLOPT_URL, baseUrl);
+ curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "SuperTux/" PACKAGE_VERSION " libcURL");
+ curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, my_curl_string_append);
+ curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &addoninfos);
+ curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, error_buffer);
+ curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1);
+ curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
+ curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1);
+ curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);
+ CURLcode result = curl_easy_perform(curl_handle);
+ curl_easy_cleanup(curl_handle);
+
+ if (result != CURLE_OK) {
+ std::string why = error_buffer[0] ? error_buffer : "unhandled error";
+ throw std::runtime_error("Downloading Add-on list failed: " + why);
+ }
+
+ try {
+ lisp::Parser parser;
+ std::stringstream addoninfos_stream(addoninfos);
+ const lisp::Lisp* root = parser.parse(addoninfos_stream, "supertux-addons");
+
+ const lisp::Lisp* addons_lisp = root->get_lisp("supertux-addons");
+ if(!addons_lisp) throw std::runtime_error("Downloaded file is not an Add-on list");
+
+ lisp::ListIterator iter(addons_lisp);
+ while(iter.next()) {
+ const std::string& token = iter.item();
+ if(token != "supertux-addoninfo") {
+ log_warning << "Unknown token '" << token << "' in Add-on list" << std::endl;
+ continue;
+ }
+ Addon* addon_ptr = new Addon();
+ Addon& addon = *addon_ptr;
+ addon.parse(*(iter.lisp()));
+ addon.installed = false;
+ addon.loaded = false;
+
+ // make sure the list of known Add-ons does not already contain this one
+ bool exists = false;
+ for (std::vector<Addon*>::const_iterator i = addons.begin(); i != addons.end(); i++) {
+ if (**i == addon) {
+ exists = true;
+ break;
+ }
+ }
+ if (exists) {
+ delete addon_ptr;
+ continue;
+ }
+
+ // make sure the Add-on's file name does not contain weird characters
+ if (addon.suggested_filename.find_first_not_of("match.quiz-proxy_gwenblvdjfks0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != std::string::npos) {
+ log_warning << "Add-on \"" << addon.title << "\" contains unsafe file name. Skipping." << std::endl;
+ delete addon_ptr;
+ continue;
+ }
+
+ addons.push_back(addon_ptr);
+ }
+ } catch(std::exception& e) {
+ std::stringstream msg;
+ msg << "Problem when reading Add-on list: " << e.what();
+ throw std::runtime_error(msg.str());
+ }
+
+#endif
+}
+
+
+void
+AddonManager::install(Addon* addon)
+{
+#ifdef HAVE_LIBCURL
+
+ if (addon->installed) throw std::runtime_error("Tried installing installed Add-on");
+
+ // make sure the Add-on's file name does not contain weird characters
+ if (addon->suggested_filename.find_first_not_of("match.quiz-proxy_gwenblvdjfks0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != std::string::npos) {
+ throw std::runtime_error("Add-on has unsafe file name (\""+addon->suggested_filename+"\")");
+ }
+
+ std::string fileName = addon->suggested_filename;
+
+ // make sure its file doesn't already exist
+ if (PHYSFS_exists(fileName.c_str())) {
+ fileName = addon->stored_md5 + "_" + addon->suggested_filename;
+ if (PHYSFS_exists(fileName.c_str())) {
+ throw std::runtime_error("Add-on of suggested filename already exists (\""+addon->suggested_filename+"\", \""+fileName+"\")");
+ }
+ }
+
+ char error_buffer[CURL_ERROR_SIZE+1];
+
+ char* url = (char*)malloc(addon->http_url.length() + 1);
+ strncpy(url, addon->http_url.c_str(), addon->http_url.length() + 1);
+
+ PHYSFS_file* f = PHYSFS_openWrite(fileName.c_str());
+
+ log_debug << "Downloading \"" << url << "\"" << std::endl;
+
+ CURL *curl_handle;
+ curl_handle = curl_easy_init();
+ curl_easy_setopt(curl_handle, CURLOPT_URL, url);
+ curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "SuperTux/" PACKAGE_VERSION " libcURL");
+ curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, my_curl_physfs_write);
+ curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, f);
+ curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, error_buffer);
+ curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1);
+ curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
+ curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1);
+ CURLcode result = curl_easy_perform(curl_handle);
+ curl_easy_cleanup(curl_handle);
+
+ PHYSFS_close(f);
+
+ free(url);
+
+ if (result != CURLE_OK) {
+ PHYSFS_delete(fileName.c_str());
+ std::string why = error_buffer[0] ? error_buffer : "unhandled error";
+ throw std::runtime_error("Downloading Add-on failed: " + why);
+ }
+
+ addon->installed = true;
+ addon->installed_physfs_filename = fileName;
+ static const std::string writeDir = PHYSFS_getWriteDir();
+ static const std::string dirSep = PHYSFS_getDirSeparator();
+ addon->installed_absolute_filename = writeDir + dirSep + fileName;
+ addon->loaded = false;
+
+ if (addon->get_md5() != addon->stored_md5) {
+ addon->installed = false;
+ PHYSFS_delete(fileName.c_str());
+ std::string why = "MD5 checksums differ";
+ throw std::runtime_error("Downloading Add-on failed: " + why);
+ }
+
+ log_debug << "Finished downloading \"" << addon->installed_absolute_filename << "\". Enabling Add-on." << std::endl;
+
+ enable(addon);
+
+#else
+ (void) addon;
+#endif
+
+}
+
+void
+AddonManager::remove(Addon* addon)
+{
+ if (!addon->installed) throw std::runtime_error("Tried removing non-installed Add-on");
+
+ //FIXME: more checks
+
+ // make sure the Add-on's file name does not contain weird characters
+ if (addon->installed_physfs_filename.find_first_not_of("match.quiz-proxy_gwenblvdjfks0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != std::string::npos) {
+ throw std::runtime_error("Add-on has unsafe file name (\""+addon->installed_physfs_filename+"\")");
+ }
+
+ unload(addon);
+
+ log_debug << "deleting file \"" << addon->installed_absolute_filename << "\"" << std::endl;
+ PHYSFS_delete(addon->installed_absolute_filename.c_str());
+ addon->installed = false;
+
+ // FIXME: As we don't know anything more about it (e.g. where to get it), remove it from list of known Add-ons
+}
+
+void
+AddonManager::disable(Addon* addon)
+{
+ unload(addon);
+
+ std::string fileName = addon->installed_physfs_filename;
+ if (std::find(ignored_addon_filenames.begin(), ignored_addon_filenames.end(), fileName) == ignored_addon_filenames.end()) {
+ ignored_addon_filenames.push_back(fileName);
+ }
+}
+
+void
+AddonManager::enable(Addon* addon)
+{
+ load(addon);
+
+ std::string fileName = addon->installed_physfs_filename;
+ std::vector<std::string>::iterator i = std::find(ignored_addon_filenames.begin(), ignored_addon_filenames.end(), fileName);
+ if (i != ignored_addon_filenames.end()) {
+ ignored_addon_filenames.erase(i);
+ }
+}
+
+void
+AddonManager::unload(Addon* addon)
+{
+ if (!addon->installed) throw std::runtime_error("Tried unloading non-installed Add-on");
+ if (!addon->loaded) return;
+
+ log_debug << "Removing archive \"" << addon->installed_absolute_filename << "\" from search path" << std::endl;
+ if (PHYSFS_removeFromSearchPath(addon->installed_absolute_filename.c_str()) == 0) {
+ log_warning << "Could not remove " << addon->installed_absolute_filename << " from search path. Ignoring." << std::endl;
+ return;
+ }
+
+ addon->loaded = false;
+}
+
+void
+AddonManager::load(Addon* addon)
+{
+ if (!addon->installed) throw std::runtime_error("Tried loading non-installed Add-on");
+ if (addon->loaded) return;
+
+ log_debug << "Adding archive \"" << addon->installed_absolute_filename << "\" to search path" << std::endl;
+ if (PHYSFS_addToSearchPath(addon->installed_absolute_filename.c_str(), 0) == 0) {
+ log_warning << "Could not add " << addon->installed_absolute_filename << " to search path. Ignoring." << std::endl;
+ return;
+ }
+
+ addon->loaded = true;
+}
+
+void
+AddonManager::load_addons()
+{
+ // unload all Addons and forget about them
+ for (std::vector<Addon*>::iterator i = addons.begin(); i != addons.end(); i++) {
+ if ((*i)->installed && (*i)->loaded) unload(*i);
+ delete *i;
+ }
+ addons.clear();
+
+ // Search for archives and add them to the search path
+ char** rc = PHYSFS_enumerateFiles("/");
+
+ for(char** i = rc; *i != 0; ++i) {
+
+ // get filename of potential archive
+ std::string fileName = *i;
+
+ static const std::string archiveDir = PHYSFS_getRealDir(fileName.c_str());
+ static const std::string dirSep = PHYSFS_getDirSeparator();
+ std::string fullFilename = archiveDir + dirSep + fileName;
+
+ /*
+ // make sure it's in the writeDir
+ static const std::string writeDir = PHYSFS_getWriteDir();
+ if (fileName.compare(0, writeDir.length(), writeDir) != 0) continue;
+ */
+
+ // make sure it looks like an archive
+ static const std::string archiveExt = ".zip";
+ if (fullFilename.compare(fullFilename.length()-archiveExt.length(), archiveExt.length(), archiveExt) != 0) continue;
+
+ // make sure it exists
+ struct stat stats;
+ if (stat(fullFilename.c_str(), &stats) != 0) continue;
+
+ // make sure it's an actual file
+ if (!S_ISREG(stats.st_mode)) continue;
+
+ log_debug << "Found archive \"" << fullFilename << "\"" << std::endl;
+
+ // add archive to search path
+ PHYSFS_addToSearchPath(fullFilename.c_str(), 0);
+
+ // Search for infoFiles
+ std::string infoFileName = "";
+ char** rc2 = PHYSFS_enumerateFiles("/");
+ for(char** i = rc2; *i != 0; ++i) {
+
+ // get filename of potential infoFile
+ std::string potentialInfoFileName = *i;
+
+ // make sure it looks like an infoFile
+ static const std::string infoExt = ".nfo";
+ if (potentialInfoFileName.compare(potentialInfoFileName.length()-infoExt.length(), infoExt.length(), infoExt) != 0) continue;
+
+ // make sure it's in the current archive
+ std::string infoFileDir = PHYSFS_getRealDir(potentialInfoFileName.c_str());
+ if (infoFileDir != fullFilename) continue;
+
+ // found infoFileName
+ infoFileName = potentialInfoFileName;
+ break;
+ }
+ PHYSFS_freeList(rc2);
+
+ // if we have an infoFile, it's an Addon
+ if (infoFileName != "") {
+ try {
+ Addon* addon = new Addon();
+ addon->parse(infoFileName);
+ addon->installed = true;
+ addon->installed_physfs_filename = fileName;
+ addon->installed_absolute_filename = fullFilename;
+ addon->loaded = true;
+ addons.push_back(addon);
+
+ // check if the Addon is disabled
+ if (std::find(ignored_addon_filenames.begin(), ignored_addon_filenames.end(), fileName) != ignored_addon_filenames.end()) {
+ unload(addon);
+ }
+
+ } catch (const std::runtime_error& e) {
+ log_warning << "Could not load add-on info for " << fullFilename << ", loading as unmanaged:" << e.what() << std::endl;
+ }
+ }
+
+ }
+
+ PHYSFS_freeList(rc);
+}
+
+
+void
+AddonManager::read_config(const lisp::Lisp& lisp)
+{
+ lisp.get_vector("disabled-addons", ignored_addon_filenames);
+}
+
+void
+AddonManager::write_config(lisp::Writer& writer)
+{
+ writer.write_string_vector("disabled-addons", ignored_addon_filenames);
+}
+
--- /dev/null
+// $Id$
+//
+// SuperTux - Add-on Manager
+// Copyright (C) 2007 Christoph Sommer <christoph.sommer@2007.expires.deltadevelopment.de>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+#ifndef ADDON_MANAGER_H
+#define ADDON_MANAGER_H
+
+#include <string>
+#include <vector>
+#include "addon/addon.hpp"
+
+/**
+ * Checks for, installs and removes Add-ons
+ */
+class AddonManager
+{
+public:
+ /**
+ * returns a list of installed Add-ons
+ */
+ std::vector<Addon*> get_addons();
+
+ /**
+ * downloads list of available Add-ons
+ */
+ void check_online();
+
+ /**
+ * Download and install Add-on
+ */
+ void install(Addon* addon);
+
+ /**
+ * Physically delete Add-on
+ */
+ void remove(Addon* addon);
+
+ /**
+ * Unload Add-on and mark as not to be loaded automatically
+ */
+ void disable(Addon* addon);
+
+ /**
+ * Load Add-on and mark as to be loaded automatically
+ */
+ void enable(Addon* addon);
+
+ /**
+ * Remove Add-on from search path
+ */
+ void unload(Addon* addon);
+
+ /**
+ * Add Add-on to search path
+ */
+ void load(Addon* addon);
+
+ /**
+ * Loads all enabled Add-ons, i.e. adds them to the search path
+ */
+ void load_addons();
+
+ /**
+ * Returns the shared AddonManager instance
+ */
+ static AddonManager& get_instance();
+
+ /**
+ * Write AddonManager configuration to Lisp
+ */
+ void write_config(lisp::Writer& writer);
+
+ /**
+ * Read AddonManager configuration from Lisp
+ */
+ void read_config(const lisp::Lisp& lisp);
+
+protected:
+ std::vector<Addon*> addons;
+ std::vector<std::string> ignored_addon_filenames;
+
+ AddonManager();
+ ~AddonManager();
+};
+
+#endif
--- /dev/null
+//
+// MD5 message-digest algorithm
+// Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved.
+//
+// C++/object oriented translation and modification:
+// Copyright (C) 1995 Mordechai T. Abzug
+//
+// Further adaptations for SuperTux:
+// Copyright (C) 2008 Christoph Sommer <christoph.sommer@2008.expires.deltadevelopment.de>
+//
+// This translation/modification is provided "as is," without express or
+// implied warranty of any kind.
+//
+// The translators/modifiers do not claim:
+// (1) that MD5 will do what you think it does;
+// (2) that this translation/ modification is accurate; or
+// (3) that this software is "merchantible."
+//
+// based on:
+//
+// MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+// MDDRIVER.C - test driver for MD2, MD4 and MD5
+// Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved.
+//
+// License to copy and use this software is granted provided that it
+// is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+// Algorithm" in all material mentioning or referencing this software
+// or this function.
+//
+// License is also granted to make and use derivative works provided
+// that such works are identified as "derived from the RSA Data
+// Security, Inc. MD5 Message-Digest Algorithm" in all material
+// mentioning or referencing the derived work.
+//
+// RSA Data Security, Inc. makes no representations concerning either
+// the merchantability of this software or the suitability of this
+// software for any particular purpose. It is provided "as is"
+// without express or implied warranty of any kind.
+//
+// These notices must be retained in any copies of any part of this
+// documentation and/or software.
+//
+
+#include "md5.hpp"
+
+#include <assert.h>
+#include <strings.h>
+#include <iostream>
+#include <stdexcept>
+
+MD5::MD5() {
+ init();
+}
+
+void MD5::update (uint8_t* input, uint32_t input_length) {
+
+ uint32_t input_index, buffer_index;
+ uint32_t buffer_space; // how much space is left in buffer
+
+ if (finalized) throw std::runtime_error("MD5::update: Can't update a finalized digest!");
+
+ // Compute number of bytes mod 64
+ buffer_index = (unsigned int)((count[0] >> 3) & 0x3F);
+
+ // Update number of bits
+ if ( (count[0] += ((uint32_t) input_length << 3))<((uint32_t) input_length << 3) ) count[1]++;
+
+ count[1] += ((uint32_t)input_length >> 29);
+
+
+ buffer_space = 64 - buffer_index; // how much space is left in buffer
+
+ // Transform as many times as possible.
+ if (input_length >= buffer_space) { // ie. we have enough to fill the buffer
+ // fill the rest of the buffer and transform
+ memcpy (buffer + buffer_index, input, buffer_space);
+ transform (buffer);
+
+ // now, transform each 64-byte piece of the input, bypassing the buffer
+ for (input_index = buffer_space; input_index + 63 < input_length;
+ input_index += 64)
+ transform (input+input_index);
+
+ buffer_index = 0; // so we can buffer remaining
+ } else
+ input_index=0; // so we can buffer the whole input
+
+
+ // and here we do the buffering:
+ memcpy(buffer+buffer_index, input+input_index, input_length-input_index);
+}
+
+void MD5::update(FILE *file) {
+ uint8_t buffer[1024];
+ int len;
+
+ while ((len=fread(buffer, 1, 1024, file))) update(buffer, len);
+
+ fclose (file);
+}
+
+void MD5::update(std::istream& stream) {
+ uint8_t buffer[1024];
+ int len;
+
+ while (stream.good()) {
+ stream.read((char*)buffer, 1024); // note that return value of read is unusable.
+ len=stream.gcount();
+ update(buffer, len);
+ }
+}
+
+void MD5::update(std::ifstream& stream) {
+ uint8_t buffer[1024];
+ int len;
+
+ while (stream.good()) {
+ stream.read((char*)buffer, 1024); // note that return value of read is unusable.
+ len=stream.gcount();
+ update(buffer, len);
+ }
+}
+
+
+MD5::MD5(FILE *file) {
+ init(); // must be called be all constructors
+ update(file);
+ finalize ();
+}
+
+MD5::MD5(std::istream& stream) {
+ init(); // must called by all constructors
+ update (stream);
+ finalize();
+}
+
+MD5::MD5(std::ifstream& stream) {
+ init(); // must called by all constructors
+ update (stream);
+ finalize();
+}
+
+uint8_t* MD5::raw_digest() {
+ uint8_t* s = new uint8_t[16];
+
+ finalize();
+
+ memcpy(s, digest, 16);
+ return s;
+}
+
+std::string MD5::hex_digest() {
+ int i;
+ char* s= new char[33];
+
+ finalize();
+
+ for (i=0; i<16; i++) sprintf(s+i*2, "%02x", digest[i]);
+
+ s[32]='\0';
+
+ return s;
+}
+
+std::ostream& operator<<(std::ostream &stream, MD5 context) {
+ stream << context.hex_digest();
+ return stream;
+}
+
+
+// PRIVATE METHODS:
+
+void MD5::init() {
+ finalized=false;
+
+ // Nothing counted, so count=0
+ count[0] = 0;
+ count[1] = 0;
+
+ // Load magic initialization constants.
+ state[0] = 0x67452301;
+ state[1] = 0xefcdab89;
+ state[2] = 0x98badcfe;
+ state[3] = 0x10325476;
+}
+
+void MD5::finalize() {
+ if (finalized) return;
+
+ uint8_t bits[8];
+ unsigned int index, padLen;
+ static uint8_t PADDING[64]={
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ // Save number of bits
+ encode (bits, count, 8);
+
+ // Pad out to 56 mod 64.
+ index = (uint32_t) ((count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ update (PADDING, padLen);
+
+ // Append length (before padding)
+ update (bits, 8);
+
+ // Store state in digest
+ encode (digest, state, 16);
+
+ // Zeroize sensitive information
+ memset (buffer, 0, sizeof(*buffer));
+
+ finalized=true;
+}
+
+// Constants for MD5Transform routine.
+// Although we could use C++ style constants, defines are actually better,
+// since they let us easily evade scope clashes.
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+void MD5::transform (uint8_t block[64]) {
+ uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ decode (x, block, 64);
+
+ assert(!finalized); // not just a user error, since the method is private
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x02441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x04881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ // Zeroize sensitive information.
+ memset ( (uint8_t* ) x, 0, sizeof(x));
+}
+
+void MD5::encode (uint8_t* output, uint32_t* input, uint32_t len) {
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (uint8_t) (input[i] & 0xff);
+ output[j+1] = (uint8_t) ((input[i] >> 8) & 0xff);
+ output[j+2] = (uint8_t) ((input[i] >> 16) & 0xff);
+ output[j+3] = (uint8_t) ((input[i] >> 24) & 0xff);
+ }
+}
+
+void MD5::decode (uint32_t* output, uint8_t* input, uint32_t len) {
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) | (((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24);
+ }
+}
+
+// Note: Replace "for loop" with standard memcpy if possible.
+void MD5::memcpy (uint8_t* output, uint8_t* input, uint32_t len) {
+ unsigned int i;
+
+ for (i = 0; i < len; i++) output[i] = input[i];
+}
+
+// Note: Replace "for loop" with standard memset if possible.
+void MD5::memset (uint8_t* output, uint8_t value, uint32_t len) {
+ unsigned int i;
+
+ for (i = 0; i < len; i++) output[i] = value;
+}
+
+inline unsigned int MD5::rotate_left(uint32_t x, uint32_t n) {
+ return (x << n) | (x >> (32-n));
+}
+
+inline unsigned int MD5::F(uint32_t x, uint32_t y, uint32_t z) {
+ return (x & y) | (~x & z);
+}
+
+inline unsigned int MD5::G(uint32_t x, uint32_t y, uint32_t z) {
+ return (x & z) | (y & ~z);
+}
+
+inline unsigned int MD5::H(uint32_t x, uint32_t y, uint32_t z) {
+ return x ^ y ^ z;
+}
+
+inline unsigned int MD5::I(uint32_t x, uint32_t y, uint32_t z) {
+ return y ^ (x | ~z);
+}
+
+inline void MD5::FF(uint32_t& a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac) {
+ a += F(b, c, d) + x + ac;
+ a = rotate_left (a, s) +b;
+}
+
+inline void MD5::GG(uint32_t& a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac) {
+ a += G(b, c, d) + x + ac;
+ a = rotate_left (a, s) +b;
+}
+
+inline void MD5::HH(uint32_t& a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac) {
+ a += H(b, c, d) + x + ac;
+ a = rotate_left (a, s) +b;
+}
+
+inline void MD5::II(uint32_t& a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac) {
+ a += I(b, c, d) + x + ac;
+ a = rotate_left (a, s) +b;
+}
--- /dev/null
+//
+// MD5 message-digest algorithm
+// Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved.
+//
+// C++/object oriented translation and modification:
+// Copyright (C) 1995 Mordechai T. Abzug
+//
+// Further adaptations for SuperTux:
+// Copyright (C) 2008 Christoph Sommer <christoph.sommer@2008.expires.deltadevelopment.de>
+//
+// This translation/modification is provided "as is," without express or
+// implied warranty of any kind.
+//
+// The translators/modifiers do not claim:
+// (1) that MD5 will do what you think it does;
+// (2) that this translation/ modification is accurate; or
+// (3) that this software is "merchantible."
+//
+// based on:
+//
+// MD5.H - header file for MD5C.C
+// MDDRIVER.C - test driver for MD2, MD4 and MD5
+// Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved.
+//
+// License to copy and use this software is granted provided that it
+// is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+// Algorithm" in all material mentioning or referencing this software
+// or this function.
+//
+// License is also granted to make and use derivative works provided
+// that such works are identified as "derived from the RSA Data
+// Security, Inc. MD5 Message-Digest Algorithm" in all material
+// mentioning or referencing the derived work.
+//
+// RSA Data Security, Inc. makes no representations concerning either
+// the merchantability of this software or the suitability of this
+// software for any particular purpose. It is provided "as is"
+// without express or implied warranty of any kind.
+//
+// These notices must be retained in any copies of any part of this
+// documentation and/or software.
+//
+
+#include <stdio.h>
+#include <fstream>
+#include <iostream>
+#include <stdint.h>
+#include <string>
+
+class MD5 {
+
+ public:
+ MD5();
+ MD5(uint8_t* string); /**< digest string, finalize */
+ MD5(std::istream& stream); /**< digest stream, finalize */
+ MD5(FILE *file); /**< digest file, close, finalize */
+ MD5(std::ifstream& stream); /**< digest stream, close, finalize */
+
+ void update(uint8_t* input, unsigned int input_length); /**< MD5 block update operation. Continues an MD5 message-digest operation, processing another message block, and updating the context. */
+ void update(std::istream& stream);
+ void update(FILE *file);
+ void update(std::ifstream& stream);
+
+ uint8_t* raw_digest(); /**< digest as a 16-byte binary array */
+ std::string hex_digest(); /**< digest as a 33-byte ascii-hex string */
+ friend std::ostream& operator<<(std::ostream&, MD5 context);
+
+ private:
+ uint32_t state[4];
+ uint32_t count[2]; /**< number of _bits_, mod 2^64 */
+ uint8_t buffer[64]; /**< input buffer */
+ uint8_t digest[16];
+ bool finalized;
+
+ void init(); /**< called by all constructors */
+ void finalize(); /**< MD5 finalization. Ends an MD5 message-digest operation, writing the the message digest and zeroizing the context. */
+ void transform(uint8_t* buffer); /**< MD5 basic transformation. Transforms state based on block. Does the real update work. Note that length is implied to be 64. */
+
+ static void encode(uint8_t* dest, uint32_t* src, uint32_t length); /**< Encodes input (uint32_t) into output (uint8_t). Assumes len is a multiple of 4. */
+ static void decode(uint32_t* dest, uint8_t* src, uint32_t length); /**< Decodes input (uint8_t) into output (uint32_t). Assumes len is a multiple of 4. */
+ static void memcpy(uint8_t* dest, uint8_t* src, uint32_t length);
+ static void memset(uint8_t* start, uint8_t val, uint32_t length);
+
+ static inline uint32_t rotate_left(uint32_t x, uint32_t n);
+ static inline uint32_t F(uint32_t x, uint32_t y, uint32_t z); //*< F, G, H and I are basic MD5 functions. */
+ static inline uint32_t G(uint32_t x, uint32_t y, uint32_t z);
+ static inline uint32_t H(uint32_t x, uint32_t y, uint32_t z);
+ static inline uint32_t I(uint32_t x, uint32_t y, uint32_t z);
+ static inline void FF(uint32_t& a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac); /**< FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. Rotation is separate from addition to prevent recomputation. */
+ static inline void GG(uint32_t& a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac);
+ static inline void HH(uint32_t& a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac);
+ static inline void II(uint32_t& a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac);
+
+};
+++ /dev/null
-// $Id$
-//
-// SuperTux - Add-on Manager
-// Copyright (C) 2007 Christoph Sommer <christoph.sommer@2007.expires.deltadevelopment.de>
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-// 02111-1307, USA.
-//
-
-#include <sstream>
-#include <stdexcept>
-#include <cstdlib>
-#include <list>
-#include <physfs.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include "addon_manager.hpp"
-#include "config.h"
-#include "log.hpp"
-#include "lisp/parser.hpp"
-#include "lisp/lisp.hpp"
-#include "lisp/list_iterator.hpp"
-
-#ifdef HAVE_LIBCURL
-#include <curl/curl.h>
-#include <curl/types.h>
-#include <curl/easy.h>
-#endif
-
-#ifdef HAVE_LIBCURL
-namespace {
-
- size_t my_curl_string_append(void *ptr, size_t size, size_t nmemb, void *string_ptr)
- {
- std::string& s = *static_cast<std::string*>(string_ptr);
- std::string buf(static_cast<char*>(ptr), size * nmemb);
- s += buf;
- log_debug << "read " << size * nmemb << " bytes of data..." << std::endl;
- return size * nmemb;
- }
-
- size_t my_curl_physfs_write(void *ptr, size_t size, size_t nmemb, void *f_p)
- {
- PHYSFS_file* f = static_cast<PHYSFS_file*>(f_p);
- PHYSFS_sint64 written = PHYSFS_write(f, ptr, size, nmemb);
- log_debug << "read " << size * nmemb << " bytes of data..." << std::endl;
- return size * written;
- }
-
-}
-#endif
-
-AddonManager&
-AddonManager::get_instance()
-{
- static AddonManager instance;
- return instance;
-}
-
-AddonManager::AddonManager()
-{
-#ifdef HAVE_LIBCURL
- curl_global_init(CURL_GLOBAL_ALL);
-#endif
-}
-
-AddonManager::~AddonManager()
-{
-#ifdef HAVE_LIBCURL
- curl_global_cleanup();
-#endif
-}
-
-std::vector<Addon>
-AddonManager::get_installed_addons() const
-{
- std::vector<Addon> addons;
-
- // iterate over complete search path (i.e. directories and archives)
- char **i = PHYSFS_getSearchPath();
- if (!i) throw std::runtime_error("Could not query physfs search path");
- for (; *i != NULL; i++) {
-
- // get filename of potential archive
- std::string fileName = *i;
-
- // make sure it's in the writeDir
- static const std::string writeDir = PHYSFS_getWriteDir();
- if (fileName.compare(0, writeDir.length(), writeDir) != 0) continue;
-
- // make sure it looks like an archive
- static const std::string archiveExt = ".zip";
- if (fileName.compare(fileName.length()-archiveExt.length(), archiveExt.length(), archiveExt) != 0) continue;
-
- // make sure it exists
- struct stat stats;
- if (stat(fileName.c_str(), &stats) != 0) continue;
-
- // make sure it's an actual file
- if (!S_ISREG(stats.st_mode)) continue;
-
- Addon addon;
-
- // extract nice title as fallback for when the Add-on has no addoninfo file
- static const char* dirSep = PHYSFS_getDirSeparator();
- std::string::size_type n = fileName.rfind(dirSep) + 1;
- if (n == std::string::npos) n = 0;
- addon.title = fileName.substr(n, fileName.length() - n - archiveExt.length());
- std::string shortFileName = fileName.substr(n, fileName.length() - n);
- addon.file = shortFileName;
-
- // read an accompaining .nfo file, if it exists
- static const std::string infoExt = ".nfo";
- std::string infoFileName = fileName.substr(n, fileName.length() - n - archiveExt.length()) + infoExt;
- if (PHYSFS_exists(infoFileName.c_str())) {
- addon.parse(infoFileName);
- if (addon.file != shortFileName) {
- log_warning << "Add-on \"" << addon.title << "\", contained in file \"" << shortFileName << "\" is accompained by an addoninfo file that specifies \"" << addon.file << "\" as the Add-on's file name. Skipping." << std::endl;
- }
- }
-
- // make sure the Add-on's file name does not contain weird characters
- if (addon.file.find_first_not_of("match.quiz-proxy_gwenblvdjfks0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != std::string::npos) {
- log_warning << "Add-on \"" << addon.title << "\" contains unsafe file name. Skipping." << std::endl;
- continue;
- }
-
- addon.isInstalled = true;
- addons.push_back(addon);
- }
-
- return addons;
-}
-
-std::vector<Addon>
-AddonManager::get_available_addons() const
-{
- std::vector<Addon> addons;
-
-#ifdef HAVE_LIBCURL
-
- char error_buffer[CURL_ERROR_SIZE+1];
-
- const char* baseUrl = "http://supertux.berlios.de/addons/index.nfo";
- std::string addoninfos = "";
-
- CURL *curl_handle;
- curl_handle = curl_easy_init();
- curl_easy_setopt(curl_handle, CURLOPT_URL, baseUrl);
- curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "SuperTux/" PACKAGE_VERSION " libcURL");
- curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, my_curl_string_append);
- curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &addoninfos);
- curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, error_buffer);
- curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1);
- curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
- curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1);
- curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);
- CURLcode result = curl_easy_perform(curl_handle);
- curl_easy_cleanup(curl_handle);
-
- if (result != CURLE_OK) {
- std::string why = error_buffer[0] ? error_buffer : "unhandled error";
- throw std::runtime_error("Downloading Add-on list failed: " + why);
- }
-
- try {
- lisp::Parser parser;
- std::stringstream addoninfos_stream(addoninfos);
- const lisp::Lisp* root = parser.parse(addoninfos_stream, "supertux-addons");
-
- const lisp::Lisp* addons_lisp = root->get_lisp("supertux-addons");
- if(!addons_lisp) throw std::runtime_error("Downloaded file is not an Add-on list");
-
- lisp::ListIterator iter(addons_lisp);
- while(iter.next()) {
- const std::string& token = iter.item();
- if(token == "supertux-addoninfo") {
- Addon addon;
- addon.parse(*(iter.lisp()));
-
- // make sure the Add-on's file name does not contain weird characters
- if (addon.file.find_first_not_of("match.quiz-proxy_gwenblvdjfks0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != std::string::npos) {
- log_warning << "Add-on \"" << addon.title << "\" contains unsafe file name. Skipping." << std::endl;
- continue;
- }
-
- addon.isInstalled = false;
- addons.push_back(addon);
- } else {
- log_warning << "Unknown token '" << token << "' in Add-on list" << std::endl;
- }
- }
- } catch(std::exception& e) {
- std::stringstream msg;
- msg << "Problem when reading Add-on list: " << e.what();
- throw std::runtime_error(msg.str());
- }
-
-#endif
-
- return addons;
-}
-
-
-void
-AddonManager::install(const Addon& addon)
-{
- // make sure the Add-on's file name does not contain weird characters
- if (addon.file.find_first_not_of("match.quiz-proxy_gwenblvdjfks0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != std::string::npos) {
- throw std::runtime_error("Add-on has unsafe file name (\""+addon.file+"\")");
- }
-
-#ifdef HAVE_LIBCURL
-
- char error_buffer[CURL_ERROR_SIZE+1];
-
- char* url = (char*)malloc(addon.http_url.length() + 1);
- strncpy(url, addon.http_url.c_str(), addon.http_url.length() + 1);
-
- PHYSFS_file* f = PHYSFS_openWrite(addon.file.c_str());
-
- log_debug << "Downloading \"" << url << "\"" << std::endl;
-
- CURL *curl_handle;
- curl_handle = curl_easy_init();
- curl_easy_setopt(curl_handle, CURLOPT_URL, url);
- curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "SuperTux/" PACKAGE_VERSION " libcURL");
- curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, my_curl_physfs_write);
- curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, f);
- curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, error_buffer);
- curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1);
- curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
- curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1);
- CURLcode result = curl_easy_perform(curl_handle);
- curl_easy_cleanup(curl_handle);
-
- PHYSFS_close(f);
-
- free(url);
-
- if (result != CURLE_OK) {
- PHYSFS_delete(addon.file.c_str());
- std::string why = error_buffer[0] ? error_buffer : "unhandled error";
- throw std::runtime_error("Downloading Add-on failed: " + why);
- }
-
- // write an accompaining .nfo file
- static const std::string archiveExt = ".zip";
- static const std::string infoExt = ".nfo";
- std::string infoFileName = addon.file.substr(0, addon.file.length()-archiveExt.length()) + infoExt;
- addon.write(infoFileName);
-
- static const std::string writeDir = PHYSFS_getWriteDir();
- static const std::string dirSep = PHYSFS_getDirSeparator();
- std::string fullFilename = writeDir + dirSep + addon.file;
- log_debug << "Finished downloading \"" << fullFilename << "\"" << std::endl;
- PHYSFS_addToSearchPath(fullFilename.c_str(), 1);
-#else
- (void) addon;
-#endif
-
-}
-
-void
-AddonManager::remove(const Addon& addon)
-{
- // make sure the Add-on's file name does not contain weird characters
- if (addon.file.find_first_not_of("match.quiz-proxy_gwenblvdjfks0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != std::string::npos) {
- throw std::runtime_error("Add-on has unsafe file name (\""+addon.file+"\")");
- }
-
- log_debug << "deleting file \"" << addon.file << "\"" << std::endl;
- PHYSFS_removeFromSearchPath(addon.file.c_str());
- PHYSFS_delete(addon.file.c_str());
-
- // remove an accompaining .nfo file
- static const std::string archiveExt = ".zip";
- static const std::string infoExt = ".nfo";
- std::string infoFileName = addon.file.substr(0, addon.file.length()-archiveExt.length()) + infoExt;
- if (PHYSFS_exists(infoFileName.c_str())) {
- log_debug << "deleting file \"" << infoFileName << "\"" << std::endl;
- PHYSFS_delete(infoFileName.c_str());
- }
-}
-
+++ /dev/null
-// $Id$
-//
-// SuperTux - Add-on Manager
-// Copyright (C) 2007 Christoph Sommer <christoph.sommer@2007.expires.deltadevelopment.de>
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-// 02111-1307, USA.
-//
-#ifndef ADDON_MANAGER_H
-#define ADDON_MANAGER_H
-
-#include <string>
-#include <vector>
-#include "addon.hpp"
-
-/**
- * Checks for, installs and removes Add-ons
- */
-class AddonManager
-{
-public:
- /**
- * returns a list of installed Add-ons
- */
- std::vector<Addon> get_installed_addons() const;
-
- /**
- * returns a list of available Add-ons
- */
- std::vector<Addon> get_available_addons() const;
-
- /**
- * Download and install Add-on
- */
- void install(const Addon& addon);
-
- /**
- * Physically delete Add-on
- */
- void remove(const Addon& addon);
-
- static AddonManager& get_instance();
-
-protected:
- AddonManager();
- ~AddonManager();
-};
-
-#endif
#include "control/joystickkeyboardcontroller.hpp"
#include "resources.hpp"
#include "main.hpp"
+#include "addon/addon_manager.hpp"
Config* config = 0;
if(config_control_lisp && main_controller) {
main_controller->read(*config_control_lisp);
}
+
+ const lisp::Lisp* config_addons_lisp = config_lisp->get_lisp("addons");
+ if(config_addons_lisp) {
+ AddonManager::get_instance().read_config(*config_addons_lisp);
+ }
}
void
writer.end_list("control");
}
+ writer.start_list("addons");
+ AddonManager::get_instance().write_config(writer);
+ writer.end_list("addons");
+
writer.end_list("supertux-config");
}
return get_item_by_id(id).toggled;
}
+void
+Menu::set_toggled(int id, bool toggled)
+{
+ get_item_by_id(id).toggled = toggled;
+}
+
Menu*
Menu::get_parent() const
{
void event(const SDL_Event& event);
bool is_toggled(int id) const;
+ void set_toggled(int id, bool toggled);
Menu* get_parent() const;
}
void
+Writer::write_string_vector(const std::string& name,
+ const std::vector<std::string>& value)
+{
+ indent();
+ *out << '(' << name;
+ for(std::vector<std::string>::const_iterator i = value.begin(); i != value.end(); ++i) {
+ *out << " ";
+ write_escaped_string(*i);
+ }
+ *out << ")\n";
+}
+
+void
Writer::write_escaped_string(const std::string& str)
{
*out << '"';
void write_int_vector(const std::string& name, const std::vector<int>& value);
void write_int_vector(const std::string& name, const std::vector<unsigned int>& value);
void write_float_vector(const std::string& name, const std::vector<float>& value);
+ void write_string_vector(const std::string& name, const std::vector<std::string>& value);
// add more write-functions when needed...
void end_list(const std::string& listname);
#include "physfs/physfs_sdl.hpp"
#include "random_generator.hpp"
#include "worldmap/worldmap.hpp"
+#include "addon/addon_manager.hpp"
#include "binreloc/binreloc.h"
namespace { DrawingContext *context_pointer; }
throw std::runtime_error(msg.str());
}
+ // allow symbolic links
+ PHYSFS_permitSymbolicLinks(1);
+
// Initialize physfs (this is a slightly modified version of
// PHYSFS_setSaneConfig
const char* application = "supertux2"; //instead of PACKAGE_NAME so we can coexist with MS1
const char* userdir = PHYSFS_getUserDir();
- const char* dirsep = PHYSFS_getDirSeparator();
char* writedir = new char[strlen(userdir) + strlen(application) + 2];
// Set configuration directory
PHYSFS_addToSearchPath(writedir, 0);
delete[] writedir;
- // Search for archives and add them to the search path
- const char* archiveExt = "zip";
- char** rc = PHYSFS_enumerateFiles("/");
- size_t extlen = strlen(archiveExt);
-
- for(char** i = rc; *i != 0; ++i) {
- size_t l = strlen(*i);
- if((l > extlen) && ((*i)[l - extlen - 1] == '.')) {
- const char* ext = (*i) + (l - extlen);
- if(strcasecmp(ext, archiveExt) == 0) {
- const char* d = PHYSFS_getRealDir(*i);
- char* str = new char[strlen(d) + strlen(dirsep) + l + 1];
- sprintf(str, "%s%s%s", d, dirsep, *i);
- PHYSFS_addToSearchPath(str, 1);
- delete[] str;
- }
- }
- }
-
- PHYSFS_freeList(rc);
-
// when started from source dir...
std::string dir = PHYSFS_getBaseDir();
dir += "/data";
#endif
}
- // allow symbolic links
- PHYSFS_permitSymbolicLinks(1);
-
//show search Path
char** searchpath = PHYSFS_getSearchPath();
for(char** i = searchpath; *i != NULL; i++)
main_controller = new JoystickKeyboardController();
timelog("config");
init_config();
+ timelog("addons");
+ AddonManager::get_instance().load_addons();
timelog("tinygettext");
init_tinygettext();
timelog("commandline");
#include "options_menu.hpp"
#include "console.hpp"
#include "random_generator.hpp"
-#include "addon_manager.hpp"
+#include "addon/addon_manager.hpp"
enum MainMenuIDs {
MNID_STARTGAME,
}
namespace {
- bool generate_addons_menu_sorter(const Addon& a1, const Addon& a2)
+ bool generate_addons_menu_sorter(const Addon* a1, const Addon* a2)
{
- return a1.title < a2.title;
+ return a1->title < a2->title;
}
const int ADDON_LIST_START_ID = 10;
{
AddonManager& adm = AddonManager::get_instance();
- // refresh list of installed addons
- installed_addons = adm.get_installed_addons();
+ // refresh list of addons
+ addons = adm.get_addons();
- // build new Add-on list
- addons.clear();
-
- // add installed addons to list
- addons.insert(addons.end(), installed_addons.begin(), installed_addons.end());
-
- // add available addons to list
- addons.insert(addons.end(), available_addons.begin(), available_addons.end());
-
// sort list
std::sort(addons.begin(), addons.end(), generate_addons_menu_sorter);
- // remove available addons that are already installed
- std::vector<Addon>::iterator it2 = addons.begin();
- while (it2 != addons.end()) {
- Addon addon = *it2;
- if (addon.isInstalled) {
- bool restart = false;
- for (std::vector<Addon>::iterator it = addons.begin(); it != addons.end(); ++it) {
- Addon addon2 = *it;
- if ((addon2.equals(addon)) && (!addon2.isInstalled)) {
- addons.erase(it);
- restart = true;
- break;
- }
- }
- if (restart) {
- it2 = addons.begin();
- continue;
- }
- }
- it2++;
- }
-
// (re)generate menu
free_addons_menu();
addons_menu.reset(new Menu());
//addons_menu->add_hl();
for (unsigned int i = 0; i < addons.size(); i++) {
- Addon addon = addons[i];
+ const Addon& addon = *addons[i];
std::string text = "";
if (addon.kind != "") text += addon.kind + " ";
text += std::string("\"") + addon.title + "\"";
if (addon.author != "") text += " by \"" + addon.author + "\"";
- addons_menu->add_toggle(ADDON_LIST_START_ID + i, text, addon.isInstalled);
+ addons_menu->add_toggle(ADDON_LIST_START_ID + i, text, addon.loaded);
}
addons_menu->add_hl();
// check if "Check Online" was chosen
if (index == 0) {
try {
- available_addons = AddonManager::get_instance().get_available_addons();
+ AddonManager::get_instance().check_online();
generate_addons_menu();
Menu::set_current(addons_menu.get());
addons_menu->set_active_item(index);
// if one of the Addons listed was chosen, take appropriate action
if ((index >= ADDON_LIST_START_ID) && (index < ADDON_LIST_START_ID) + addons.size()) {
- Addon addon = addons[index - ADDON_LIST_START_ID];
- if (!addon.isInstalled) {
+ Addon& addon = *addons[index - ADDON_LIST_START_ID];
+ if (!addon.installed) {
try {
- addon.install();
- //generate_addons_menu();
- //Menu::set_current(addons_menu.get());
- //addons_menu->set_active_item(index);
- Menu::set_current(0);
+ AddonManager::get_instance().install(&addon);
}
catch (std::runtime_error e) {
- log_warning << "Installation of Add-on failed: " << e.what() << std::endl;
+ log_warning << "Installing Add-on failed: " << e.what() << std::endl;
}
+ addons_menu->set_toggled(index, addon.loaded);
+ } else if (!addon.loaded) {
+ try {
+ AddonManager::get_instance().enable(&addon);
+ }
+ catch (std::runtime_error e) {
+ log_warning << "Enabling Add-on failed: " << e.what() << std::endl;
+ }
+ addons_menu->set_toggled(index, addon.loaded);
} else {
try {
- addon.remove();
- //generate_addons_menu();
- //Menu::set_current(addons_menu.get());
- //addons_menu->set_active_item(index);
- Menu::set_current(0);
+ AddonManager::get_instance().disable(&addon);
}
catch (std::runtime_error e) {
- log_warning << "Removal of Add-on failed: " << e.what() << std::endl;
+ log_warning << "Disabling Add-on failed: " << e.what() << std::endl;
}
+ addons_menu->set_toggled(index, addon.loaded);
}
}
-
}
void
#include <vector>
#include "screen.hpp"
#include "game_session.hpp"
-#include "addon.hpp"
+#include "addon/addon.hpp"
class Menu;
class World;
std::auto_ptr<World> main_world;
std::vector<World*> contrib_worlds;
std::auto_ptr<Menu> addons_menu;
- std::vector<Addon> addons; /**< shown list of Add-ons */
- std::vector<Addon> available_addons; /**< list of downloadable Add-ons */
- std::vector<Addon> installed_addons; /**< list of currently installed Add-ons */
+ std::vector<Addon*> addons; /**< shown list of Add-ons */
World* current_world;
std::auto_ptr<Surface> frame;