#include <addon_manager.hpp>
Public Member Functions | |
std::vector< Addon * > | get_addons () |
returns a list of installed Add-ons | |
void | check_online () |
downloads list of available Add-ons | |
void | install (Addon *addon) |
Download and install Add-on. | |
void | remove (Addon *addon) |
Physically delete Add-on. | |
void | disable (Addon *addon) |
Unload Add-on and mark as not to be loaded automatically. | |
void | enable (Addon *addon) |
Load Add-on and mark as to be loaded automatically. | |
void | unload (Addon *addon) |
Remove Add-on from search path. | |
void | load (Addon *addon) |
Add Add-on to search path. | |
void | load_addons () |
Loads all enabled Add-ons, i.e. | |
void | write (Writer &writer) |
Write AddonManager configuration to Lisp. | |
void | read (const Reader &lisp) |
Read AddonManager configuration from Lisp. | |
Static Public Member Functions | |
static AddonManager & | get_instance () |
Returns the shared AddonManager instance. | |
Protected Member Functions | |
AddonManager () | |
~AddonManager () | |
Protected Attributes | |
std::vector< Addon * > | addons |
std::vector< std::string > | ignored_addon_filenames |
Definition at line 31 of file addon_manager.hpp.
AddonManager::AddonManager | ( | ) | [protected] |
Definition at line 71 of file addon_manager.cpp.
00071 : 00072 addons(), 00073 ignored_addon_filenames() 00074 { 00075 #ifdef HAVE_LIBCURL 00076 curl_global_init(CURL_GLOBAL_ALL); 00077 #endif 00078 }
AddonManager::~AddonManager | ( | ) | [protected] |
Definition at line 80 of file addon_manager.cpp.
References addons.
00081 { 00082 #ifdef HAVE_LIBCURL 00083 curl_global_cleanup(); 00084 #endif 00085 00086 for (std::vector<Addon*>::iterator i = addons.begin(); i != addons.end(); i++) delete *i; 00087 }
std::vector< Addon * > AddonManager::get_addons | ( | ) |
returns a list of installed Add-ons
Definition at line 90 of file addon_manager.cpp.
References addons.
Referenced by AddonMenu::refresh().
00091 { 00092 /* 00093 for (std::vector<Addon>::iterator it = installed_addons.begin(); it != installed_addons.end(); ++it) { 00094 Addon& addon = *it; 00095 if (addon.md5 == "") addon.md5 = calculate_md5(addon); 00096 } 00097 */ 00098 return addons; 00099 }
void AddonManager::check_online | ( | ) |
downloads list of available Add-ons
Definition at line 102 of file addon_manager.cpp.
References addons, lisp::Lisp::get_lisp(), lisp::ListIterator::item(), lisp::ListIterator::lisp(), log_warning, lisp::ListIterator::next(), and lisp::Parser::parse().
Referenced by AddonMenu::check_menu().
00103 { 00104 #ifdef HAVE_LIBCURL 00105 char error_buffer[CURL_ERROR_SIZE+1]; 00106 00107 const char* baseUrl = "http://supertux.lethargik.org/addons/index.nfo"; 00108 std::string addoninfos = ""; 00109 00110 CURL *curl_handle; 00111 curl_handle = curl_easy_init(); 00112 curl_easy_setopt(curl_handle, CURLOPT_URL, baseUrl); 00113 curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "SuperTux/" PACKAGE_VERSION " libcURL"); 00114 curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, my_curl_string_append); 00115 curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &addoninfos); 00116 curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, error_buffer); 00117 curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1); 00118 curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1); 00119 curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1); 00120 curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1); 00121 CURLcode result = curl_easy_perform(curl_handle); 00122 curl_easy_cleanup(curl_handle); 00123 00124 if (result != CURLE_OK) { 00125 std::string why = error_buffer[0] ? error_buffer : "unhandled error"; 00126 throw std::runtime_error("Downloading Add-on list failed: " + why); 00127 } 00128 00129 try { 00130 lisp::Parser parser; 00131 std::stringstream addoninfos_stream(addoninfos); 00132 const lisp::Lisp* root = parser.parse(addoninfos_stream, "supertux-addons"); 00133 00134 const lisp::Lisp* addons_lisp = root->get_lisp("supertux-addons"); 00135 if(!addons_lisp) throw std::runtime_error("Downloaded file is not an Add-on list"); 00136 00137 lisp::ListIterator iter(addons_lisp); 00138 while(iter.next()) 00139 { 00140 const std::string& token = iter.item(); 00141 if(token != "supertux-addoninfo") 00142 { 00143 log_warning << "Unknown token '" << token << "' in Add-on list" << std::endl; 00144 continue; 00145 } 00146 std::auto_ptr<Addon> addon(new Addon()); 00147 addon->parse(*(iter.lisp())); 00148 addon->installed = false; 00149 addon->loaded = false; 00150 00151 // make sure the list of known Add-ons does not already contain this one 00152 bool exists = false; 00153 for (std::vector<Addon*>::const_iterator i = addons.begin(); i != addons.end(); i++) { 00154 if (**i == *addon) { 00155 exists = true; 00156 break; 00157 } 00158 } 00159 00160 if (exists) 00161 { 00162 // do nothing 00163 } 00164 else if (addon->suggested_filename.find_first_not_of("match.quiz-proxy_gwenblvdjfks0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != std::string::npos) 00165 { 00166 // make sure the Add-on's file name does not contain weird characters 00167 log_warning << "Add-on \"" << addon->title << "\" contains unsafe file name. Skipping." << std::endl; 00168 } 00169 else 00170 { 00171 addons.push_back(addon.release()); 00172 } 00173 } 00174 } catch(std::exception& e) { 00175 std::stringstream msg; 00176 msg << "Problem when reading Add-on list: " << e.what(); 00177 throw std::runtime_error(msg.str()); 00178 } 00179 00180 #endif 00181 }
void AddonManager::install | ( | Addon * | addon | ) |
Download and install Add-on.
Definition at line 184 of file addon_manager.cpp.
References enable(), Addon::get_md5(), Addon::http_url, Addon::installed, Addon::installed_absolute_filename, Addon::installed_physfs_filename, Addon::loaded, log_debug, Addon::stored_md5, and Addon::suggested_filename.
Referenced by AddonMenu::check_menu().
00185 { 00186 #ifdef HAVE_LIBCURL 00187 00188 if (addon->installed) throw std::runtime_error("Tried installing installed Add-on"); 00189 00190 // make sure the Add-on's file name does not contain weird characters 00191 if (addon->suggested_filename.find_first_not_of("match.quiz-proxy_gwenblvdjfks0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != std::string::npos) { 00192 throw std::runtime_error("Add-on has unsafe file name (\""+addon->suggested_filename+"\")"); 00193 } 00194 00195 std::string fileName = addon->suggested_filename; 00196 00197 // make sure its file doesn't already exist 00198 if (PHYSFS_exists(fileName.c_str())) { 00199 fileName = addon->stored_md5 + "_" + addon->suggested_filename; 00200 if (PHYSFS_exists(fileName.c_str())) { 00201 throw std::runtime_error("Add-on of suggested filename already exists (\""+addon->suggested_filename+"\", \""+fileName+"\")"); 00202 } 00203 } 00204 00205 char error_buffer[CURL_ERROR_SIZE+1]; 00206 00207 char* url = (char*)malloc(addon->http_url.length() + 1); 00208 strncpy(url, addon->http_url.c_str(), addon->http_url.length() + 1); 00209 00210 PHYSFS_file* f = PHYSFS_openWrite(fileName.c_str()); 00211 00212 log_debug << "Downloading \"" << url << "\"" << std::endl; 00213 00214 CURL *curl_handle; 00215 curl_handle = curl_easy_init(); 00216 curl_easy_setopt(curl_handle, CURLOPT_URL, url); 00217 curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "SuperTux/" PACKAGE_VERSION " libcURL"); 00218 curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, my_curl_physfs_write); 00219 curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, f); 00220 curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, error_buffer); 00221 curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1); 00222 curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1); 00223 curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1); 00224 CURLcode result = curl_easy_perform(curl_handle); 00225 curl_easy_cleanup(curl_handle); 00226 00227 PHYSFS_close(f); 00228 00229 free(url); 00230 00231 if (result != CURLE_OK) { 00232 PHYSFS_delete(fileName.c_str()); 00233 std::string why = error_buffer[0] ? error_buffer : "unhandled error"; 00234 throw std::runtime_error("Downloading Add-on failed: " + why); 00235 } 00236 00237 addon->installed = true; 00238 addon->installed_physfs_filename = fileName; 00239 static const std::string writeDir = PHYSFS_getWriteDir(); 00240 static const std::string dirSep = PHYSFS_getDirSeparator(); 00241 addon->installed_absolute_filename = writeDir + dirSep + fileName; 00242 addon->loaded = false; 00243 00244 if (addon->get_md5() != addon->stored_md5) { 00245 addon->installed = false; 00246 PHYSFS_delete(fileName.c_str()); 00247 std::string why = "MD5 checksums differ"; 00248 throw std::runtime_error("Downloading Add-on failed: " + why); 00249 } 00250 00251 log_debug << "Finished downloading \"" << addon->installed_absolute_filename << "\". Enabling Add-on." << std::endl; 00252 00253 enable(addon); 00254 00255 #else 00256 (void) addon; 00257 #endif 00258 00259 }
void AddonManager::remove | ( | Addon * | addon | ) |
Physically delete Add-on.
Definition at line 262 of file addon_manager.cpp.
References Addon::installed, Addon::installed_absolute_filename, Addon::installed_physfs_filename, log_debug, and unload().
00263 { 00264 if (!addon->installed) throw std::runtime_error("Tried removing non-installed Add-on"); 00265 00266 //FIXME: more checks 00267 00268 // make sure the Add-on's file name does not contain weird characters 00269 if (addon->installed_physfs_filename.find_first_not_of("match.quiz-proxy_gwenblvdjfks0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != std::string::npos) { 00270 throw std::runtime_error("Add-on has unsafe file name (\""+addon->installed_physfs_filename+"\")"); 00271 } 00272 00273 unload(addon); 00274 00275 log_debug << "deleting file \"" << addon->installed_absolute_filename << "\"" << std::endl; 00276 PHYSFS_delete(addon->installed_absolute_filename.c_str()); 00277 addon->installed = false; 00278 00279 // FIXME: As we don't know anything more about it (e.g. where to get it), remove it from list of known Add-ons 00280 }
void AddonManager::disable | ( | Addon * | addon | ) |
Unload Add-on and mark as not to be loaded automatically.
Definition at line 283 of file addon_manager.cpp.
References ignored_addon_filenames, Addon::installed_physfs_filename, and unload().
Referenced by AddonMenu::check_menu().
00284 { 00285 unload(addon); 00286 00287 std::string fileName = addon->installed_physfs_filename; 00288 if (std::find(ignored_addon_filenames.begin(), ignored_addon_filenames.end(), fileName) == ignored_addon_filenames.end()) { 00289 ignored_addon_filenames.push_back(fileName); 00290 } 00291 }
void AddonManager::enable | ( | Addon * | addon | ) |
Load Add-on and mark as to be loaded automatically.
Definition at line 294 of file addon_manager.cpp.
References ignored_addon_filenames, Addon::installed_physfs_filename, and load().
Referenced by AddonMenu::check_menu(), and install().
00295 { 00296 load(addon); 00297 00298 std::string fileName = addon->installed_physfs_filename; 00299 std::vector<std::string>::iterator i = std::find(ignored_addon_filenames.begin(), ignored_addon_filenames.end(), fileName); 00300 if (i != ignored_addon_filenames.end()) { 00301 ignored_addon_filenames.erase(i); 00302 } 00303 }
void AddonManager::unload | ( | Addon * | addon | ) |
Remove Add-on from search path.
Definition at line 306 of file addon_manager.cpp.
References Addon::installed, Addon::installed_absolute_filename, Addon::loaded, log_debug, and log_warning.
Referenced by disable(), load_addons(), and remove().
00307 { 00308 if (!addon->installed) throw std::runtime_error("Tried unloading non-installed Add-on"); 00309 if (!addon->loaded) return; 00310 00311 log_debug << "Removing archive \"" << addon->installed_absolute_filename << "\" from search path" << std::endl; 00312 if (PHYSFS_removeFromSearchPath(addon->installed_absolute_filename.c_str()) == 0) { 00313 log_warning << "Could not remove " << addon->installed_absolute_filename << " from search path. Ignoring." << std::endl; 00314 return; 00315 } 00316 00317 addon->loaded = false; 00318 }
void AddonManager::load | ( | Addon * | addon | ) |
Add Add-on to search path.
Definition at line 321 of file addon_manager.cpp.
References Addon::installed, Addon::installed_absolute_filename, Addon::loaded, log_debug, and log_warning.
Referenced by enable().
00322 { 00323 if (!addon->installed) throw std::runtime_error("Tried loading non-installed Add-on"); 00324 if (addon->loaded) return; 00325 00326 log_debug << "Adding archive \"" << addon->installed_absolute_filename << "\" to search path" << std::endl; 00327 if (PHYSFS_addToSearchPath(addon->installed_absolute_filename.c_str(), 0) == 0) { 00328 log_warning << "Could not add " << addon->installed_absolute_filename << " to search path. Ignoring." << std::endl; 00329 return; 00330 } 00331 00332 addon->loaded = true; 00333 }
void AddonManager::load_addons | ( | ) |
Loads all enabled Add-ons, i.e.
adds them to the search path
Definition at line 336 of file addon_manager.cpp.
References addons, ignored_addon_filenames, Addon::installed, Addon::installed_absolute_filename, Addon::installed_physfs_filename, Addon::loaded, log_debug, log_warning, Addon::parse(), and unload().
Referenced by Main::run().
00337 { 00338 // unload all Addons and forget about them 00339 for (std::vector<Addon*>::iterator i = addons.begin(); i != addons.end(); i++) { 00340 if ((*i)->installed && (*i)->loaded) unload(*i); 00341 delete *i; 00342 } 00343 addons.clear(); 00344 00345 // Search for archives and add them to the search path 00346 char** rc = PHYSFS_enumerateFiles("/"); 00347 00348 for(char** i = rc; *i != 0; ++i) { 00349 00350 // get filename of potential archive 00351 std::string fileName = *i; 00352 00353 const std::string archiveDir = PHYSFS_getRealDir(fileName.c_str()); 00354 static const std::string dirSep = PHYSFS_getDirSeparator(); 00355 std::string fullFilename = archiveDir + dirSep + fileName; 00356 00357 /* 00358 // make sure it's in the writeDir 00359 static const std::string writeDir = PHYSFS_getWriteDir(); 00360 if (fileName.compare(0, writeDir.length(), writeDir) != 0) continue; 00361 */ 00362 00363 // make sure it looks like an archive 00364 static const std::string archiveExt = ".zip"; 00365 if (fullFilename.compare(fullFilename.length()-archiveExt.length(), archiveExt.length(), archiveExt) != 0) continue; 00366 00367 // make sure it exists 00368 struct stat stats; 00369 if (stat(fullFilename.c_str(), &stats) != 0) continue; 00370 00371 // make sure it's an actual file 00372 if (!S_ISREG(stats.st_mode)) continue; 00373 00374 log_debug << "Found archive \"" << fullFilename << "\"" << std::endl; 00375 00376 // add archive to search path 00377 PHYSFS_addToSearchPath(fullFilename.c_str(), 0); 00378 00379 // Search for infoFiles 00380 std::string infoFileName = ""; 00381 char** rc2 = PHYSFS_enumerateFiles("/"); 00382 for(char** i = rc2; *i != 0; ++i) { 00383 00384 // get filename of potential infoFile 00385 std::string potentialInfoFileName = *i; 00386 00387 // make sure it looks like an infoFile 00388 static const std::string infoExt = ".nfo"; 00389 if (potentialInfoFileName.length() <= infoExt.length()) 00390 continue; 00391 00392 if (potentialInfoFileName.compare(potentialInfoFileName.length()-infoExt.length(), infoExt.length(), infoExt) != 0) 00393 continue; 00394 00395 // make sure it's in the current archive 00396 std::string infoFileDir = PHYSFS_getRealDir(potentialInfoFileName.c_str()); 00397 if (infoFileDir != fullFilename) continue; 00398 00399 // found infoFileName 00400 infoFileName = potentialInfoFileName; 00401 break; 00402 } 00403 PHYSFS_freeList(rc2); 00404 00405 // if we have an infoFile, it's an Addon 00406 if (infoFileName != "") { 00407 try { 00408 Addon* addon = new Addon(); 00409 addon->parse(infoFileName); 00410 addon->installed = true; 00411 addon->installed_physfs_filename = fileName; 00412 addon->installed_absolute_filename = fullFilename; 00413 addon->loaded = true; 00414 addons.push_back(addon); 00415 00416 // check if the Addon is disabled 00417 if (std::find(ignored_addon_filenames.begin(), ignored_addon_filenames.end(), fileName) != ignored_addon_filenames.end()) { 00418 unload(addon); 00419 } 00420 00421 } catch (const std::runtime_error& e) { 00422 log_warning << "Could not load add-on info for " << fullFilename << ", loading as unmanaged:" << e.what() << std::endl; 00423 } 00424 } 00425 00426 } 00427 00428 PHYSFS_freeList(rc); 00429 }
AddonManager & AddonManager::get_instance | ( | ) | [static] |
Returns the shared AddonManager instance.
Definition at line 65 of file addon_manager.cpp.
Referenced by AddonMenu::check_menu(), Config::load(), AddonMenu::refresh(), Main::run(), and Config::save().
00066 { 00067 static AddonManager instance; 00068 return instance; 00069 }
void AddonManager::write | ( | Writer & | writer | ) |
Write AddonManager configuration to Lisp.
Definition at line 438 of file addon_manager.cpp.
References ignored_addon_filenames, and lisp::Writer::write().
Referenced by Config::save().
00439 { 00440 writer.write("disabled-addons", ignored_addon_filenames); 00441 }
void AddonManager::read | ( | const Reader & | lisp | ) |
Read AddonManager configuration from Lisp.
Definition at line 432 of file addon_manager.cpp.
References lisp::Lisp::get(), and ignored_addon_filenames.
Referenced by Config::load().
00433 { 00434 lisp.get("disabled-addons", ignored_addon_filenames); 00435 }
std::vector<Addon*> AddonManager::addons [protected] |
Definition at line 95 of file addon_manager.hpp.
Referenced by check_online(), get_addons(), load_addons(), and ~AddonManager().
std::vector<std::string> AddonManager::ignored_addon_filenames [protected] |
Definition at line 96 of file addon_manager.hpp.
Referenced by disable(), enable(), load_addons(), read(), and write().