2
* Copyright (C) 2010-2011 Daniel Richter <danielrichter2007@web.de>
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 3 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19
#ifndef GRUB_CUSTOMIZER_GrublistCfg_INCLUDED
20
#define GRUB_CUSTOMIZER_GrublistCfg_INCLUDED
33
#include "../config.hpp"
34
#include "../Controller/MainController.hpp"
35
#include "../Controller/Trait/ControllerAware.hpp"
37
#include "../lib/Mutex.hpp"
38
#include "../lib/Trait/LoggerAware.hpp"
40
#include "../lib/Exception.hpp"
41
#include "../lib/ArrayStructure.hpp"
42
#include "../lib/Helper.hpp"
46
#include "MountTable.hpp"
47
#include "Proxylist.hpp"
48
#include "ProxyScriptData.hpp"
49
#include "Repository.hpp"
50
#include "ScriptSourceMap.hpp"
51
#include "SettingsManagerData.hpp"
54
public Trait_LoggerAware,
55
public Trait_ControllerAware<MainController>,
56
public Mutex_Connection,
57
public Model_Env_Connection
60
std::string progress_name;
61
int progress_pos, progress_max;
62
std::string errorLogFile;
64
Model_ScriptSourceMap scriptSourceMap;
66
Model_ListCfg() : error_proxy_not_found(false),
68
cancelThreadsRequested(false), verbose(true),
69
errorLogFile(ERROR_LOG_FILE), ignoreLock(false), progress_pos(0), progress_max(0)
72
void setLogger(Logger& logger) {
73
this->Trait_LoggerAware::setLogger(logger);
74
this->proxies.setLogger(logger);
75
this->repository.setLogger(logger);
76
this->scriptSourceMap.setLogger(logger);
79
void setEnv(Model_Env& env) {
80
this->Model_Env_Connection::setEnv(env);
81
this->scriptSourceMap.setEnv(env);
85
Model_Proxylist proxies;
86
Model_Repository repository;
89
bool error_proxy_not_found;
93
if (this->mutex == NULL)
94
throw ConfigException("missing mutex", __FILE__, __LINE__);
101
if (this->mutex == NULL)
102
throw ConfigException("missing mutex", __FILE__, __LINE__);
103
return this->mutex->trylock();
107
if (this->ignoreLock)
109
if (this->mutex == NULL)
110
throw ConfigException("missing mutex", __FILE__, __LINE__);
111
this->mutex->unlock();
116
bool cancelThreadsRequested;
117
bool createScriptForwarder(std::string const& scriptName) const {
118
//replace: $cfg_dir/proxifiedScripts/ -> $cfg_dir/LS_
119
std::string scriptNameNoPath = scriptName.substr((this->env->cfg_dir+"/proxifiedScripts/").length());
120
std::string outputFilePath = this->env->cfg_dir+"/LS_"+scriptNameNoPath;
121
FILE* existingScript = fopen(outputFilePath.c_str(), "r");
122
if (existingScript == NULL){
123
Helper::assert_filepath_empty(outputFilePath, __FILE__, __LINE__);
124
FILE* fwdScript = fopen(outputFilePath.c_str(), "w");
126
fputs("#!/bin/sh\n", fwdScript);
127
fputs(("'"+scriptName.substr(env->cfg_dir_prefix.length())+"'").c_str(), fwdScript);
129
chmod(outputFilePath.c_str(), 0755);
136
fclose(existingScript);
141
bool removeScriptForwarder(std::string const& scriptName) const {
142
std::string scriptNameNoPath = scriptName.substr((this->env->cfg_dir+"/proxifiedScripts/").length());
143
std::string filePath = this->env->cfg_dir+"/LS_"+scriptNameNoPath;
144
return unlink(filePath.c_str()) == 0;
147
std::string readScriptForwarder(std::string const& scriptForwarderFilePath) const {
149
FILE* scriptForwarderFile = fopen(scriptForwarderFilePath.c_str(), "r");
150
if (scriptForwarderFile){
152
while ((c = fgetc(scriptForwarderFile)) != EOF && c != '\n'){} //skip first line
154
while ((c = fgetc(scriptForwarderFile)) != EOF && c != '\n'){result += char(c);} //read second line (=path)
155
fclose(scriptForwarderFile);
157
if (result.length() >= 3) {
158
return result.substr(1, result.length()-2);
164
void load(bool preserveConfig = false) {
165
if (!preserveConfig){
166
send_new_load_progress(0);
168
DIR* hGrubCfgDir = opendir(this->env->cfg_dir.c_str());
171
throw DirectoryNotFoundException("grub cfg dir not found", __FILE__, __LINE__);
175
this->log("loading scripts…", Logger::EVENT);
177
repository.load(this->env->cfg_dir, false);
178
repository.load(this->env->cfg_dir+"/proxifiedScripts", true);
180
send_new_load_progress(0.05);
184
this->log("loading proxies…", Logger::EVENT);
186
struct dirent *entry;
187
struct stat fileProperties;
188
while ((entry = readdir(hGrubCfgDir))){
189
stat((this->env->cfg_dir+"/"+entry->d_name).c_str(), &fileProperties);
190
if ((fileProperties.st_mode & S_IFMT) != S_IFDIR){ //ignore directories
191
if (entry->d_name[2] == '_'){ //check whether it's an script (they should be named XX_scriptname)…
192
this->proxies.push_back(Model_Proxy());
193
this->proxies.back().fileName = this->env->cfg_dir+"/"+entry->d_name;
194
this->proxies.back().index = (entry->d_name[0]-'0')*10 + (entry->d_name[1]-'0');
195
this->proxies.back().permissions = fileProperties.st_mode & ~S_IFMT;
197
FILE* proxyFile = fopen((this->env->cfg_dir+"/"+entry->d_name).c_str(), "r");
198
Model_ProxyScriptData data(proxyFile);
201
this->proxies.back().dataSource = repository.getScriptByFilename(this->env->cfg_dir_prefix+data.scriptCmd);
202
this->proxies.back().importRuleString(data.ruleString.c_str(), this->env->cfg_dir_prefix);
205
this->proxies.back().dataSource = repository.getScriptByFilename(this->env->cfg_dir+"/"+entry->d_name);
206
this->proxies.back().importRuleString("+*", this->env->cfg_dir_prefix); //it's no proxy, so accept all
212
closedir(hGrubCfgDir);
213
this->proxies.sort();
217
//clean up proxy configuration
218
this->log("cleaning up proxy configuration…", Logger::EVENT);
221
bool proxyRemoved = false;
223
for (std::list<Model_Proxy>::iterator pIter = this->proxies.begin(); pIter != this->proxies.end(); pIter++) {
224
if (!pIter->isExecutable() || !pIter->hasVisibleRules()) {
225
this->log(pIter->fileName + " has no visible entries and will be removed / disabled", Logger::INFO);
226
this->proxies.deleteProxy(&*pIter);
231
proxyRemoved = false;
232
} while (proxyRemoved);
238
proxies.unsync_all();
239
repository.deleteAllEntries();
243
//create proxifiedScript links & chmod other files
244
this->log("creating proxifiedScript links & chmodding other files…", Logger::EVENT);
247
for (Model_Repository::iterator iter = this->repository.begin(); iter != this->repository.end(); iter++){
248
if (iter->isInScriptDir(env->cfg_dir)){
249
//createScriptForwarder & disable proxies
250
createScriptForwarder(iter->fileName);
251
std::list<Model_Proxy*> relatedProxies = proxies.getProxiesByScript(*iter);
252
for (std::list<Model_Proxy*>::iterator piter = relatedProxies.begin(); piter != relatedProxies.end(); piter++){
253
int res = chmod((*piter)->fileName.c_str(), 0644);
256
//enable scripts (unproxified), in this case, Proxy::fileName == Script::fileName
257
chmod(iter->fileName.c_str(), 0755);
261
send_new_load_progress(0.1);
264
if (!preserveConfig){
266
this->scriptSourceMap.load();
267
if (!this->scriptSourceMap.fileExists() && this->getProxifiedScripts().size() > 0) {
268
this->generateScriptSourceMap();
270
this->populateScriptSourceMap();
274
this->log("running " + this->env->mkconfig_cmd, Logger::EVENT);
275
FILE* mkconfigProc = popen((this->env->mkconfig_cmd + " 2> " + this->errorLogFile).c_str(), "r");
276
readGeneratedFile(mkconfigProc);
278
int success = pclose(mkconfigProc);
279
if (success != 0 && !cancelThreadsRequested){
280
throw CmdExecException("failed running " + this->env->mkconfig_cmd, __FILE__, __LINE__);
282
remove(errorLogFile.c_str()); //remove file, if everything was ok
284
this->log("mkconfig successfull completed", Logger::INFO);
286
this->send_new_load_progress(0.9);
290
this->env->useDirectBackgroundProps = this->repository.getScriptByName("debian_theme") == NULL;
291
if (this->env->useDirectBackgroundProps) {
292
this->log("using simple background image settings", Logger::INFO);
294
this->log("using /usr/share/desktop-base/grub_background.sh to configure colors and the background image", Logger::INFO);
298
//restore old configuration
299
this->log("restoring grub configuration", Logger::EVENT);
301
for (Model_Repository::iterator iter = this->repository.begin(); iter != this->repository.end(); iter++){
302
if (iter->isInScriptDir(env->cfg_dir)){
303
//removeScriptForwarder & reset proxy permissions
304
bool result = removeScriptForwarder(iter->fileName);
306
this->log("removing of script forwarder not successful!", Logger::ERROR);
309
std::list<Model_Proxy*> relatedProxies = proxies.getProxiesByScript(*iter);
310
for (std::list<Model_Proxy*>::iterator piter = relatedProxies.begin(); piter != relatedProxies.end(); piter++){
311
chmod((*piter)->fileName.c_str(), (*piter)->permissions);
316
//remove invalid proxies from list (no file system action here)
317
this->log("removing invalid proxies from list", Logger::EVENT);
318
std::string invalidProxies = "";
319
bool foundInvalidScript = false;
321
foundInvalidScript = false;
322
for (std::list<Model_Proxy>::iterator pIter = this->proxies.begin(); pIter != this->proxies.end(); pIter++){
323
if (pIter->dataSource == NULL) {
324
this->proxies.trash.push_back(*pIter); // mark for deletion
325
this->proxies.erase(pIter);
326
foundInvalidScript = true;
327
invalidProxies += pIter->fileName + ",";
331
} while (foundInvalidScript);
333
if (invalidProxies != "") {
334
this->log("found invalid proxies: " + Helper::rtrim(invalidProxies, ","), Logger::INFO);
337
//fix conflicts (same number, same name but one script with "-proxy" the other without
338
if (this->proxies.hasConflicts()) {
339
this->log("found conflicts - renumerating", Logger::INFO);
343
this->log("loading completed", Logger::EVENT);
344
send_new_load_progress(1);
348
send_new_save_progress(0);
349
std::map<std::string, int> samename_counter;
350
proxies.deleteAllProxyscriptFiles(); //delete all proxies to get a clean file system
351
proxies.clearTrash(); //delete all files of removed proxies
352
repository.clearTrash();
354
std::map<Model_Script*, std::string> scriptFilenameMap; // stores original filenames
355
for (std::list<Model_Script>::iterator scriptIter = this->repository.begin(); scriptIter != this->repository.end(); scriptIter++) {
356
scriptFilenameMap[&*scriptIter] = scriptIter->fileName;
359
// create virtual custom scripts on file system
360
for (std::list<Model_Script>::iterator scriptIter = this->repository.begin(); scriptIter != this->repository.end(); scriptIter++) {
361
if (scriptIter->isCustomScript && scriptIter->fileName == "") {
362
scriptIter->fileName = this->env->cfg_dir + "/IN_" + scriptIter->name;
363
this->repository.createScript(*scriptIter, "");
367
for (Model_Repository::iterator script_iter = repository.begin(); script_iter != repository.end(); script_iter++)
368
script_iter->moveToBasedir(this->env->cfg_dir);
370
send_new_save_progress(0.1);
372
int mkdir_result = mkdir((this->env->cfg_dir+"/proxifiedScripts").c_str(), 0755); //create this directory if it doesn't already exist
374
// get new script locations
375
std::map<Model_Script const*, std::string> scriptTargetMap; // scripts and their target directories
376
for (Model_Repository::iterator script_iter = repository.begin(); script_iter != repository.end(); script_iter++) {
377
std::list<Model_Proxy*> relatedProxies = proxies.getProxiesByScript(*script_iter);
378
if (proxies.proxyRequired(*script_iter)){
379
scriptTargetMap[&*script_iter] = this->env->cfg_dir+"/proxifiedScripts/"+Model_PscriptnameTranslator::encode(script_iter->name, samename_counter[script_iter->name]++);
381
std::ostringstream nameStream;
382
nameStream << std::setw(2) << std::setfill('0') << relatedProxies.front()->index << "_" << script_iter->name;
383
std::list<Model_Proxy*> relatedProxies = proxies.getProxiesByScript(*script_iter);
384
scriptTargetMap[&*script_iter] = this->env->cfg_dir+"/"+nameStream.str();
388
// move scripts and create proxies
390
for (Model_Repository::iterator script_iter = repository.begin(); script_iter != repository.end(); script_iter++){
391
std::list<Model_Proxy*> relatedProxies = proxies.getProxiesByScript(*script_iter);
392
if (proxies.proxyRequired(*script_iter)){
393
script_iter->moveFile(scriptTargetMap[&*script_iter], 0755);
394
for (std::list<Model_Proxy*>::iterator proxy_iter = relatedProxies.begin(); proxy_iter != relatedProxies.end(); proxy_iter++){
395
std::map<Model_Entry const*, Model_Script const*> entrySourceMap = this->getEntrySources(**proxy_iter);
396
std::ostringstream nameStream;
397
nameStream << std::setw(2) << std::setfill('0') << (*proxy_iter)->index << "_" << script_iter->name << "_proxy";
398
(*proxy_iter)->generateFile(this->env->cfg_dir+"/"+nameStream.str(), this->env->cfg_dir_prefix.length(), this->env->cfg_dir_noprefix, entrySourceMap, scriptTargetMap);
403
if (relatedProxies.size() == 1){
404
script_iter->moveFile(scriptTargetMap[&*script_iter], relatedProxies.front()->permissions);
405
relatedProxies.front()->fileName = script_iter->fileName; // update filename
408
this->log("GrublistCfg::save: cannot move proxy… only one expected!", Logger::ERROR);
412
send_new_save_progress(0.2);
414
// register in script source map
415
for (std::map<Model_Script*, std::string>::iterator sMapIter = scriptFilenameMap.begin(); sMapIter != scriptFilenameMap.end(); sMapIter++) {
416
this->scriptSourceMap.registerMove(sMapIter->second, sMapIter->first->fileName);
418
this->scriptSourceMap.save();
420
//remove "proxifiedScripts" dir, if empty
423
int proxifiedScriptCount = 0;
424
struct dirent *entry;
425
struct stat fileProperties;
426
DIR* hScriptDir = opendir((this->env->cfg_dir+"/proxifiedScripts").c_str());
427
while ((entry = readdir(hScriptDir))) {
428
if (std::string(entry->d_name) != "." && std::string(entry->d_name) != ".."){
429
proxifiedScriptCount++;
432
closedir(hScriptDir);
434
if (proxifiedScriptCount == 0)
435
rmdir((this->env->cfg_dir+"/proxifiedScripts").c_str());
438
//add or remove proxy binary
440
FILE* proxyBin = fopen((this->env->cfg_dir+"/bin/grubcfg_proxy").c_str(), "r");
441
bool proxybin_exists = proxyBin != NULL;
445
std::string dummyproxy_code = "#!/bin/sh\ncat\n";
448
* copy the grub customizer proxy, if required
450
if (proxyCount != 0){
451
// create the bin subdirectory - may already exist
452
int bin_mk_success = mkdir((this->env->cfg_dir+"/bin").c_str(), 0755);
454
FILE* proxyBinSource = fopen((std::string(LIBDIR)+"/grubcfg-proxy").c_str(), "r");
457
FILE* proxyBinTarget = fopen((this->env->cfg_dir+"/bin/grubcfg_proxy").c_str(), "w");
460
while ((c = fgetc(proxyBinSource)) != EOF){
461
fputc(c, proxyBinTarget);
463
fclose(proxyBinTarget);
464
chmod((this->env->cfg_dir+"/bin/grubcfg_proxy").c_str(), 0755);
466
this->log("could not open proxy output file!", Logger::ERROR);
468
fclose(proxyBinSource);
470
this->log("proxy could not be copied, generating dummy!", Logger::ERROR);
471
FILE* proxyBinTarget = fopen((this->env->cfg_dir+"/bin/grubcfg_proxy").c_str(), "w");
473
fputs(dummyproxy_code.c_str(), proxyBinTarget);
474
error_proxy_not_found = true;
475
fclose(proxyBinTarget);
476
chmod((this->env->cfg_dir+"/bin/grubcfg_proxy").c_str(), 0755);
478
this->log("coundn't create proxy!", Logger::ERROR);
482
else if (proxyCount == 0 && proxybin_exists){
483
//the following commands are only cleanup… no problem, when they fail
484
unlink((this->env->cfg_dir+"/bin/grubcfg_proxy").c_str());
485
rmdir((this->env->cfg_dir+"/bin").c_str());
488
//update modified "custom" scripts
489
for (std::list<Model_Script>::iterator scriptIter = this->repository.begin(); scriptIter != this->repository.end(); scriptIter++) {
490
if (scriptIter->isCustomScript && scriptIter->isModified()) {
491
this->log("modifying script \"" + scriptIter->name + "\"", Logger::INFO);
492
assert(scriptIter->fileName != "");
493
Model_Proxy dummyProxy(*scriptIter);
494
std::ofstream scriptStream(scriptIter->fileName.c_str());
495
scriptStream << CUSTOM_SCRIPT_SHEBANG << "\n" << CUSTOM_SCRIPT_PREFIX << "\n";
496
for (std::list<Model_Rule>::iterator ruleIter = dummyProxy.rules.begin(); ruleIter != dummyProxy.rules.end(); ruleIter++) {
497
ruleIter->print(scriptStream);
498
if (ruleIter->dataSource) {
499
ruleIter->dataSource->isModified = false;
506
int saveProcSuccess = 0;
507
std::string saveProcOutput;
510
FILE* saveProc = popen((env->update_cmd + " 2>&1").c_str(), "r");
513
std::string row = "";
514
while ((c = fgetc(saveProc)) != EOF) {
515
saveProcOutput += char(c);
517
send_new_save_progress(0.5); //a gui should use pulse() instead of set_fraction
518
this->log(row, Logger::INFO);
524
saveProcSuccess = pclose(saveProc);
527
// correct pathes of foreign rules (to make sure re-syncing works)
528
std::list<Model_Rule*> foreignRules = this->proxies.getForeignRules();
529
for (std::list<Model_Rule*>::iterator foreignRuleIter = foreignRules.begin(); foreignRuleIter != foreignRules.end(); foreignRuleIter++) {
530
Model_Entry* entry = (*foreignRuleIter)->dataSource;
531
assert(entry != NULL);
532
Model_Script* script = this->repository.getScriptByEntry(*entry);
533
assert(script != NULL);
534
(*foreignRuleIter)->__sourceScriptPath = script->fileName;
537
send_new_save_progress(1);
539
if ((saveProcSuccess != 0 || saveProcOutput.find("Syntax errors are detected in generated GRUB config file") != -1)){
540
throw CmdExecException("failed running '" + env->update_cmd + "' output:\n" + saveProcOutput, __FILE__, __LINE__);
544
void readGeneratedFile(FILE* source, bool createScriptIfNotFound = false, bool createProxyIfNotFound = false) {
546
Model_Script* script;
548
bool inScript = false;
549
std::string plaintextBuffer = "";
551
double progressbarScriptSpace = 0.7 / this->repository.size();
552
while (!cancelThreadsRequested && (row = Model_Entry_Row(source))){
553
std::string rowText = Helper::ltrim(row.text);
554
if (!inScript && rowText.substr(0,10) == ("### BEGIN ") && rowText.substr(rowText.length()-4,4) == " ###"){
557
if (plaintextBuffer != "" && !script->isModified()) {
558
Model_Entry newEntry("#text", "", plaintextBuffer, Model_Entry::PLAINTEXT);
559
if (this->hasLogger()) {
560
newEntry.setLogger(this->getLogger());
562
script->entries().push_front(newEntry);
564
this->proxies.sync_all(true, true, script);
566
plaintextBuffer = "";
567
std::string scriptName = rowText.substr(10, rowText.length()-14);
568
std::string prefix = this->env->cfg_dir_prefix;
569
std::string realScriptName = prefix+scriptName;
570
if (realScriptName.substr(0, (this->env->cfg_dir+"/LS_").length()) == this->env->cfg_dir+"/LS_"){
571
realScriptName = prefix+readScriptForwarder(realScriptName);
573
script = repository.getScriptByFilename(realScriptName, createScriptIfNotFound);
574
if (createScriptIfNotFound && createProxyIfNotFound){ //for the compare-configuration
575
this->proxies.push_back(Model_Proxy(*script));
579
this->send_new_load_progress(0.1 + (progressbarScriptSpace * ++i + (progressbarScriptSpace/10*innerCount)), script->name, i, this->repository.size());
582
} else if (inScript && rowText.substr(0,8) == ("### END ") && rowText.substr(rowText.length()-4,4) == " ###") {
585
} else if (script != NULL && rowText.substr(0, 10) == "menuentry ") {
587
if (innerCount < 10) {
590
Model_Entry newEntry(source, row, this->getLoggerPtr());
591
if (!script->isModified()) {
592
script->entries().push_back(newEntry);
594
this->proxies.sync_all(false, false, script);
596
this->send_new_load_progress(0.1 + (progressbarScriptSpace * i + (progressbarScriptSpace/10*innerCount)), script->name, i, this->repository.size());
597
} else if (script != NULL && rowText.substr(0, 8) == "submenu ") {
599
Model_Entry newEntry(source, row, this->getLoggerPtr());
600
script->entries().push_back(newEntry);
601
this->proxies.sync_all(false, false, script);
603
this->send_new_load_progress(0.1 + (progressbarScriptSpace * i + (progressbarScriptSpace/10*innerCount)), script->name, i, this->repository.size());
604
} else if (inScript) { //Plaintext
605
plaintextBuffer += row.text + "\n";
610
if (plaintextBuffer != "" && !script->isModified()) {
611
Model_Entry newEntry("#text", "", plaintextBuffer, Model_Entry::PLAINTEXT);
612
if (this->hasLogger()) {
613
newEntry.setLogger(this->getLogger());
615
script->entries().push_front(newEntry);
617
this->proxies.sync_all(true, true, script);
620
// sync all (including foreign entries)
621
this->proxies.sync_all(true, true, NULL, this->repository.getScriptPathMap());
626
std::map<Model_Entry const*, Model_Script const*> getEntrySources(Model_Proxy const& proxy, Model_Rule const* parent = NULL) const {
627
std::list<Model_Rule> const& list = parent ? parent->subRules : proxy.rules;
628
std::map<Model_Entry const*, Model_Script const*> result;
629
assert(proxy.dataSource != NULL);
630
for (std::list<Model_Rule>::const_iterator iter = list.begin(); iter != list.end(); iter++) {
631
if (iter->dataSource && !proxy.ruleIsFromOwnScript(*iter)) {
632
Model_Script const* script = this->repository.getScriptByEntry(*iter->dataSource);
633
if (script != NULL) {
634
result[iter->dataSource] = script;
636
this->log("error finding the associated script! (" + iter->outputName + ")", Logger::WARNING);
638
} else if (iter->type == Model_Rule::SUBMENU) {
639
std::map<Model_Entry const*, Model_Script const*> subResult = this->getEntrySources(proxy, &*iter);
640
if (subResult.size()) {
641
result.insert(subResult.begin(), subResult.end());
648
bool loadStaticCfg() {
649
FILE* oldConfigFile = fopen(env->output_config_file.c_str(), "r");
651
this->readGeneratedFile(oldConfigFile, true, true);
652
fclose(oldConfigFile);
659
void send_new_load_progress(double newProgress, std::string scriptName = "", int current = 0, int max = 0) {
660
if (this->controller != NULL){
661
this->progress = newProgress;
662
this->progress_name = scriptName;
663
this->progress_pos = current;
664
this->progress_max = max;
665
this->controller->syncLoadStateThreadedAction();
667
else if (this->verbose) {
668
this->log("cannot show updated load progress - no UI connected!", Logger::ERROR);
672
void send_new_save_progress(double newProgress) {
673
if (this->controller != NULL){
674
this->progress = newProgress;
675
this->controller->syncSaveStateThreadedAction();
677
else if (this->verbose) {
678
this->log("cannot show updated save progress - no UI connected!", Logger::ERROR);
682
void cancelThreads() {
683
cancelThreadsRequested = true;
688
this->repository.clear();
689
this->repository.trash.clear();
690
this->proxies.clear();
691
this->proxies.trash.clear();
695
double getProgress() const {
699
std::string getProgress_name() const {
700
return progress_name;
703
int getProgress_pos() const {
707
int getProgress_max() const {
711
void renumerate(bool favorDefaultOrder = true) {
713
for (Model_Proxylist::iterator iter = this->proxies.begin(); iter != this->proxies.end(); iter++){
714
bool isDefaultNumber = false;
715
if (favorDefaultOrder && iter->dataSource) {
716
std::string sourceFileName = this->scriptSourceMap.getSourceName(iter->dataSource->fileName);
718
int prefixNum = Model_Script::extractIndexFromPath(sourceFileName, this->env->cfg_dir);
719
if (prefixNum >= i) {
721
isDefaultNumber = true;
723
} catch (InvalidStringFormatException const& e) {
724
this->log(e, Logger::ERROR);
734
if (!isDefaultNumber && iter->dataSource) {
735
// make sure that scripts never get a filePath that matches a script source (unless it's the source script)
736
std::ostringstream fullFileName;
737
fullFileName << this->env->cfg_dir << "/" << std::setw(2) << std::setfill('0') << i << "_" << iter->dataSource->name;
738
if (this->scriptSourceMap.has(fullFileName.str())) {
747
this->proxies.sort();
749
if (favorDefaultOrder && i > 100) { // if positions are out of range...
750
this->renumerate(false); // retry without favorDefaultOrder
754
Model_Rule& moveRule(Model_Rule* rule, int direction) {
756
return this->proxies.getProxyByRule(rule)->moveRule(rule, direction);
757
} catch (NoMoveTargetException const& e) {
758
Model_Proxy* proxy = this->proxies.getProxyByRule(rule);
759
Model_Rule* parent = NULL;
761
parent = proxy->getParentRule(rule);
762
} catch (ItemNotFoundException const& e) {/* do nothing */}
765
std::list<Model_Rule>::iterator nextRule = this->proxies.getNextVisibleRule(proxy->getListIterator(*rule, proxy->getRuleList(parent)), direction);
766
if (nextRule->type != Model_Rule::SUBMENU) { // create new proxy
767
std::list<Model_Rule>::iterator targetRule = proxy->rules.end();
768
bool targetRuleFound = false;
770
targetRule = this->proxies.getNextVisibleRule(nextRule, direction);
771
targetRuleFound = true;
772
} catch (NoMoveTargetException const& e) {
773
// ignore GrublistCfg::NO_MOVE_TARGET_FOUND - occurs when previousRule is not found. But this isn't a problem
776
if (targetRuleFound && this->proxies.getProxyByRule(&*targetRule)->dataSource == this->proxies.getProxyByRule(&*rule)->dataSource) {
777
Model_Proxy* targetProxy = this->proxies.getProxyByRule(&*targetRule);
778
targetProxy->removeEquivalentRules(*rule);
779
Model_Rule* newRule = NULL;
780
if (direction == -1) {
781
targetProxy->rules.push_back(*rule);
782
newRule = &targetProxy->rules.back();
784
targetProxy->rules.push_front(*rule);
785
newRule = &targetProxy->rules.front();
787
rule->setVisibility(false);
790
std::list<Model_Rule>::iterator previousRule = this->proxies.getNextVisibleRule(proxy->getListIterator(*rule, proxy->getRuleList(parent)), -direction);
791
if (this->proxies.getProxyByRule(&*nextRule)->dataSource == this->proxies.getProxyByRule(&*previousRule)->dataSource) {
792
this->proxies.getProxyByRule(&*previousRule)->removeEquivalentRules(*nextRule);
793
if (direction == 1) {
794
this->proxies.getProxyByRule(&*previousRule)->rules.push_back(*nextRule);
796
this->proxies.getProxyByRule(&*previousRule)->rules.push_front(*nextRule);
798
nextRule->setVisibility(false);
799
if (!this->proxies.getProxyByRule(&*nextRule)->hasVisibleRules()) {
800
this->proxies.deleteProxy(this->proxies.getProxyByRule(&*nextRule));
803
} catch (NoMoveTargetException const& e) {
804
// ignore NoMoveTargetException - occurs when previousRule is not found. But this isn't a problem
808
if (!proxy->hasVisibleRules()) {
809
this->proxies.deleteProxy(proxy);
814
std::list<Model_Rule>::iterator movedRule = this->proxies.moveRuleToNewProxy(*rule, direction);
816
Model_Proxy* currentProxy = this->proxies.getProxyByRule(&*movedRule);
818
std::list<Model_Rule>::iterator movedRule2 = this->proxies.moveRuleToNewProxy(*nextRule, -direction);
820
this->swapProxies(currentProxy, this->proxies.getProxyByRule(&*movedRule2));
823
std::list<Model_Rule>::iterator prevPrevRule = this->proxies.getNextVisibleRule(movedRule2, -direction);
825
if (this->proxies.getProxyByRule(&*prevPrevRule)->dataSource == this->proxies.getProxyByRule(&*movedRule2)->dataSource) {
826
Model_Proxy* prevprev = this->proxies.getProxyByRule(&*prevPrevRule);
827
prevprev->removeEquivalentRules(*movedRule2);
828
if (direction == 1) {
829
prevprev->rules.push_back(*movedRule2);
831
prevprev->rules.push_front(*movedRule2);
833
movedRule2->setVisibility(false);
834
if (!this->proxies.getProxyByRule(&*movedRule2)->hasVisibleRules()) {
835
this->proxies.deleteProxy(this->proxies.getProxyByRule(&*movedRule2));
838
} catch (NoMoveTargetException const& e) {
839
// ignore NoMoveTargetException - occurs when prevPrevRule is not found. But this isn't a problem
845
} else { // convert existing proxy to multiproxy
846
this->log("convert to multiproxy", Logger::INFO);
847
std::list<Model_Proxy>::iterator proxyIter = this->proxies.getIter(proxy);
849
Model_Rule* movedRule = NULL;
850
Model_Proxy* target = NULL;
851
if (direction == -1 && proxyIter != this->proxies.begin()) {
853
target = &*proxyIter;
854
target->removeEquivalentRules(*rule);
855
nextRule->subRules.push_back(*rule);
856
if (rule->type == Model_Rule::SUBMENU) {
857
proxy->removeForeignChildRules(*rule);
859
if ((rule->type == Model_Rule::SUBMENU && rule->subRules.size() != 0) || (rule->type != Model_Rule::SUBMENU && proxy->ruleIsFromOwnScript(*rule))) {
860
rule->setVisibility(false);
862
proxy->rules.pop_front();
864
movedRule = &nextRule->subRules.back();
866
proxyIter++; // go to the next proxy
867
} else if (direction == 1 && proxyIter != this->proxies.end() && &*proxyIter != &this->proxies.back()) {
869
target = &*proxyIter;
870
target->removeEquivalentRules(*rule);
871
nextRule->subRules.push_front(*rule);
872
if (rule->type == Model_Rule::SUBMENU) {
873
proxy->removeForeignChildRules(*rule);
875
if ((rule->type == Model_Rule::SUBMENU && rule->subRules.size() != 0) || (rule->type != Model_Rule::SUBMENU && proxy->ruleIsFromOwnScript(*rule))) {
876
rule->setVisibility(false);
878
proxy->rules.pop_back();
880
movedRule = &nextRule->subRules.front();
883
proxyIter--; // go to the previous proxy
885
throw NoMoveTargetException("cannot move this rule", __FILE__, __LINE__);
888
if (!proxy->hasVisibleRules()) {
889
if (proxyIter != this->proxies.end() && target->dataSource == proxyIter->dataSource) {
890
target->merge(*proxyIter, direction);
891
this->proxies.deleteProxy(&*proxyIter);
894
this->proxies.deleteProxy(proxy);
898
} catch (NoMoveTargetException const& e) {
901
} catch (MustBeProxyException const& e) {
902
Model_Proxy* proxy = this->proxies.getProxyByRule(rule);
903
Model_Rule* parent = NULL;
905
parent = proxy->getParentRule(rule);
906
} catch (ItemNotFoundException const& e) {/* do nothing */}
908
Model_Rule* parentSubmenu = parent;
910
std::list<Model_Rule>::iterator nextRule = this->proxies.getNextVisibleRule(proxy->getListIterator(*parent, proxy->rules), direction); // go forward
912
if (this->proxies.getProxyByRule(&*nextRule) == this->proxies.getProxyByRule(&*rule)) {
913
this->proxies.splitProxy(proxy, &*nextRule, direction);
915
} catch (NoMoveTargetException const& e) {
916
// there's no next rule… no split required
919
std::list<Model_Proxy>::iterator nextProxy = this->proxies.getIter(this->proxies.getProxyByRule(&*rule));
920
if (direction == 1) {
926
Model_Rule* movedRule = NULL;
927
if (nextProxy != this->proxies.end() && nextProxy->dataSource == this->repository.getScriptByEntry(*rule->dataSource)) {
928
nextProxy->removeEquivalentRules(*rule);
929
if (direction == 1) {
930
nextProxy->rules.push_front(*rule);
931
movedRule = &nextProxy->rules.front();
933
nextProxy->rules.push_back(*rule);
934
movedRule = &nextProxy->rules.back();
937
movedRule = &*this->proxies.moveRuleToNewProxy(*rule, direction, this->repository.getScriptByEntry(*rule->dataSource));
940
if (this->proxies.hasProxy(proxy)) { // check whether the proxy pointer is still valid
941
proxy->removeEquivalentRules(*rule);
945
throw NoMoveTargetException("no move target found", __FILE__, __LINE__);
948
void swapProxies(Model_Proxy* a, Model_Proxy* b) {
949
if (a->index == b->index) { // swapping has no effect if the indexes are identical
952
int index1 = a->index;
955
this->proxies.sort();
960
Model_Rule* createSubmenu(Model_Rule* position) {
961
return this->proxies.getProxyByRule(position)->createSubmenu(position);
964
Model_Rule* splitSubmenu(Model_Rule* child) {
965
return this->proxies.getProxyByRule(child)->splitSubmenu(child);
969
bool cfgDirIsClean() {
970
DIR* hGrubCfgDir = opendir(this->env->cfg_dir.c_str());
972
struct dirent *entry;
973
struct stat fileProperties;
974
while ((entry = readdir(hGrubCfgDir))){
975
std::string fname = entry->d_name;
976
if ((fname.length() >= 4 && fname.substr(0,3) == "LS_") || fname.substr(0,3) == "PS_" || fname.substr(0,3) == "DS_")
979
closedir(hGrubCfgDir);
984
void cleanupCfgDir() {
985
this->log("cleaning up cfg dir!", Logger::IMPORTANT_EVENT);
987
DIR* hGrubCfgDir = opendir(this->env->cfg_dir.c_str());
989
struct dirent *entry;
990
struct stat fileProperties;
991
std::list<std::string> lsfiles, dsfiles, psfiles;
992
std::list<std::string> proxyscripts;
993
while ((entry = readdir(hGrubCfgDir))){
994
std::string fname = entry->d_name;
995
if (fname.length() >= 4){
996
if (fname.substr(0,3) == "LS_")
997
lsfiles.push_back(fname);
998
else if (fname.substr(0,3) == "DS_")
999
dsfiles.push_back(fname);
1000
else if (fname.substr(0,3) == "PS_")
1001
psfiles.push_back(fname);
1003
else if (fname[0] >= '1' && fname[0] <= '9' && fname[1] >= '0' && fname[1] <= '9' && fname[2] == '_')
1004
proxyscripts.push_back(fname);
1007
closedir(hGrubCfgDir);
1009
for (std::list<std::string>::iterator iter = lsfiles.begin(); iter != lsfiles.end(); iter++){
1010
this->log("deleting " + *iter, Logger::EVENT);
1011
unlink((this->env->cfg_dir+"/"+(*iter)).c_str());
1013
//proxyscripts will be disabled before loading the config. While the provious mode will only be saved on the objects, every script should be made executable
1014
for (std::list<std::string>::iterator iter = proxyscripts.begin(); iter != proxyscripts.end(); iter++){
1015
this->log("re-activating " + *iter, Logger::EVENT);
1016
chmod((this->env->cfg_dir+"/"+(*iter)).c_str(), 0755);
1019
//remove the DS_ prefix (DS_10_foo -> 10_foo)
1020
for (std::list<std::string>::iterator iter = dsfiles.begin(); iter != dsfiles.end(); iter++) {
1021
this->log("renaming " + *iter, Logger::EVENT);
1022
std::string newPath = this->env->cfg_dir+"/"+iter->substr(3);
1023
Helper::assert_filepath_empty(newPath, __FILE__, __LINE__);
1024
rename((this->env->cfg_dir+"/"+(*iter)).c_str(), newPath.c_str());
1027
//remove the PS_ prefix and add index prefix (PS_foo -> 10_foo)
1028
int i = 20; //prefix
1029
for (std::list<std::string>::iterator iter = psfiles.begin(); iter != psfiles.end(); iter++) {
1030
this->log("renaming " + *iter, Logger::EVENT);
1031
std::string out = *iter;
1032
out.replace(0, 2, (std::string("") + char('0' + (i/10)%10) + char('0' + i%10)));
1033
std::string newPath = this->env->cfg_dir+"/"+out;
1034
Helper::assert_filepath_empty(newPath, __FILE__, __LINE__);
1035
rename((this->env->cfg_dir+"/"+(*iter)).c_str(), newPath.c_str());
1042
bool compare(Model_ListCfg const& other) const {
1043
std::list<const Model_Rule*> rlist[2];
1044
for (int i = 0; i < 2; i++){
1045
const Model_ListCfg* gc = i == 0 ? this : &other;
1046
for (Model_Proxylist::const_iterator piter = gc->proxies.begin(); piter != gc->proxies.end(); piter++){
1047
assert(piter->dataSource != NULL);
1048
if (piter->isExecutable() && piter->dataSource){
1049
if (piter->dataSource->fileName == "") { // if the associated file isn't found
1052
std::string fname = piter->dataSource->fileName.substr(other.env->cfg_dir.length()+1);
1053
if (i == 0 || (fname[0] >= '1' && fname[0] <= '9' && fname[1] >= '0' && fname[1] <= '9' && fname[2] == '_')) {
1054
std::list<Model_Rule const*> comparableRules = this->getComparableRules(piter->rules);
1055
rlist[i].splice(rlist[i].end(), comparableRules);
1060
return Model_ListCfg::compareLists(rlist[0], rlist[1]);
1063
static std::list<Model_Rule const*> getComparableRules(std::list<Model_Rule> const& list) {
1064
std::list<Model_Rule const*> result;
1065
for (std::list<Model_Rule>::const_iterator riter = list.begin(); riter != list.end(); riter++){
1066
if (((riter->type == Model_Rule::NORMAL && riter->dataSource) || (riter->type == Model_Rule::SUBMENU && riter->hasRealSubrules())) && riter->isVisible){
1067
result.push_back(&*riter);
1073
static bool compareLists(std::list<Model_Rule const*> a, std::list<Model_Rule const*> b) {
1074
if (a.size() != b.size()) {
1078
std::list<const Model_Rule*>::iterator self_iter = a.begin(), other_iter = b.begin();
1079
while (self_iter != a.end() && other_iter != b.end()){
1080
if ((*self_iter)->type != (*other_iter)->type) {
1083
assert((*self_iter)->type == (*other_iter)->type);
1085
if ((*self_iter)->outputName != (*other_iter)->outputName)
1087
if ((*self_iter)->dataSource) {
1088
if ((*self_iter)->dataSource->extension != (*other_iter)->dataSource->extension)
1090
if ((*self_iter)->dataSource->content != (*other_iter)->dataSource->content)
1092
if ((*self_iter)->dataSource->type != (*other_iter)->dataSource->type)
1095
//check rules inside the submenu
1096
if ((*self_iter)->type == Model_Rule::SUBMENU && !Model_ListCfg::compareLists(Model_ListCfg::getComparableRules((*self_iter)->subRules), Model_ListCfg::getComparableRules((*other_iter)->subRules))) {
1106
void renameRule(Model_Rule* rule, std::string const& newName) {
1107
rule->outputName = newName;
1110
std::string getRulePath(Model_Rule& rule) {
1111
Model_Proxy* proxy = this->proxies.getProxyByRule(&rule);
1112
std::stack<std::string> ruleNameStack;
1113
ruleNameStack.push(rule.outputName);
1115
Model_Rule* currentRule = &rule;
1116
while ((currentRule = proxy->getParentRule(currentRule))) {
1117
ruleNameStack.push(currentRule->outputName);
1120
std::string output = ruleNameStack.top();
1121
ruleNameStack.pop();
1122
while (ruleNameStack.size()) {
1123
output += ">" + ruleNameStack.top();
1124
ruleNameStack.pop();
1129
std::string getGrubErrorMessage() const {
1130
FILE* errorLogFile = fopen(this->errorLogFile.c_str(), "r");
1131
std::string errorMessage;
1133
while ((c = fgetc(errorLogFile)) != EOF) {
1134
errorMessage += char(c);
1136
fclose(errorLogFile);
1137
return errorMessage;
1141
void addColorHelper() {
1142
Model_Script* newScript = NULL;
1143
if (this->repository.getScriptByName("grub-customizer_menu_color_helper") == NULL) {
1144
Model_Script* newScript = this->repository.createScript("grub-customizer_menu_color_helper", this->env->cfg_dir + "06_grub-customizer_menu_color_helper", "#!/bin/sh\n\
1146
if [ \"x${GRUB_BACKGROUND}\" != \"x\" ] ; then\n\
1147
if [ \"x${GRUB_COLOR_NORMAL}\" != \"x\" ] ; then\n\
1148
echo \"set color_normal=${GRUB_COLOR_NORMAL}\"\n\
1151
if [ \"x${GRUB_COLOR_HIGHLIGHT}\" != \"x\" ] ; then\n\
1152
echo \"set color_highlight=${GRUB_COLOR_HIGHLIGHT}\"\n\
1156
assert(newScript != NULL);
1157
Model_Proxy newProxy(*newScript);
1159
this->proxies.push_back(newProxy);
1164
std::list<Model_Rule> getRemovedEntries(Model_Entry* parent = NULL, bool ignorePlaceholders = false) {
1165
std::list<Model_Rule> result;
1166
if (parent == NULL) {
1167
for (std::list<Model_Script>::iterator iter = this->repository.begin(); iter != this->repository.end(); iter++) {
1168
std::list<Model_Rule> subResult = this->getRemovedEntries(&iter->root, ignorePlaceholders);
1169
result.insert(result.end(), subResult.begin(), subResult.end());
1172
if (parent->type == Model_Entry::SUBMENU || parent->type == Model_Entry::SCRIPT_ROOT) {
1173
for (std::list<Model_Entry>::iterator entryIter = parent->subEntries.begin(); entryIter != parent->subEntries.end(); entryIter++) {
1174
std::list<Model_Rule> subResult = this->getRemovedEntries(&*entryIter, ignorePlaceholders);
1175
Model_Rule* currentSubmenu = NULL;
1176
if (subResult.size()) {
1177
Model_Rule submenu(Model_Rule::SUBMENU, std::list<std::string>(), entryIter->name, true);
1178
submenu.subRules = subResult;
1179
submenu.dataSource = &*entryIter;
1180
result.push_back(submenu);
1181
currentSubmenu = &result.back();
1184
if ((entryIter->type == Model_Entry::MENUENTRY || !ignorePlaceholders) && !this->proxies.getVisibleRuleForEntry(*entryIter)) {
1185
Model_Rule::RuleType ruleType = Model_Rule::NORMAL;
1186
switch (entryIter->type) {
1187
case Model_Entry::MENUENTRY:
1188
ruleType = Model_Rule::NORMAL;
1190
case Model_Entry::PLAINTEXT:
1191
ruleType = Model_Rule::PLAINTEXT;
1193
case Model_Entry::SUBMENU:
1194
ruleType = Model_Rule::OTHER_ENTRIES_PLACEHOLDER;
1197
Model_Rule newRule(ruleType, std::list<std::string>(), entryIter->name, true);
1198
newRule.dataSource = &*entryIter;
1199
if (currentSubmenu) {
1200
currentSubmenu->subRules.push_front(newRule);
1202
result.push_back(newRule);
1211
Model_Rule* addEntry(Model_Entry& entry, bool insertAsOtherEntriesPlaceholder = false) {
1212
Model_Script* sourceScript = this->repository.getScriptByEntry(entry);
1213
assert(sourceScript != NULL);
1215
Model_Proxy* targetProxy = NULL;
1216
if (this->proxies.size() && this->proxies.back().dataSource == sourceScript) {
1217
targetProxy = &this->proxies.back();
1218
targetProxy->set_isExecutable(true);
1220
this->proxies.push_back(Model_Proxy(*sourceScript, false));
1221
targetProxy = &this->proxies.back();
1226
if (insertAsOtherEntriesPlaceholder) {
1227
rule = Model_Rule(Model_Rule::OTHER_ENTRIES_PLACEHOLDER, sourceScript->buildPath(entry), true);
1228
rule.dataSource = &entry;
1230
rule = Model_Rule(entry, true, *sourceScript, std::list<std::list<std::string> >(), sourceScript->buildPath(entry));
1233
targetProxy->removeEquivalentRules(rule);
1234
targetProxy->rules.push_back(rule);
1235
return &targetProxy->rules.back();
1239
void deleteEntry(Model_Entry const& entry) {
1240
for (std::list<Model_Proxy>::iterator proxyIter = this->proxies.begin(); proxyIter != this->proxies.end(); proxyIter++) {
1241
Model_Rule* rule = proxyIter->getRuleByEntry(entry, proxyIter->rules, Model_Rule::NORMAL);
1243
proxyIter->removeRule(rule);
1246
this->repository.getScriptByEntry(entry)->deleteEntry(entry);
1250
std::list<Rule*> getNormalizedRuleOrder(std::list<Rule*> rules) {
1251
if (rules.size() == 0 || rules.size() == 1) {
1254
std::list<Rule*> result;
1256
Model_Rule* firstRuleOfList = &Model_Rule::fromPtr(rules.front());
1257
std::list<Model_Rule>::iterator currentRule;
1259
Model_Rule* parentRule = this->proxies.getProxyByRule(firstRuleOfList)->getParentRule(firstRuleOfList);
1261
currentRule = parentRule->subRules.begin();
1263
currentRule = this->proxies.front().rules.begin();
1268
for (std::list<Rule*>::iterator iter = rules.begin(); iter != rules.end(); iter++) {
1269
if (&*currentRule == *iter) {
1270
result.push_back(*iter);
1274
currentRule = this->proxies.getNextVisibleRule(currentRule, 1);
1276
} catch (NoMoveTargetException const& e) {
1284
std::list<Model_Script*> getProxifiedScripts() {
1285
std::list<Model_Script*> result;
1287
for (std::list<Model_Script>::iterator iter = this->repository.begin(); iter != this->repository.end(); iter++) {
1288
if (this->proxies.proxyRequired(*iter)) {
1289
result.push_back(&*iter);
1296
void generateScriptSourceMap() {
1297
std::map<std::string, int> defaultScripts; // only for non-static scripts - so 40_custom is ignored
1298
defaultScripts["header"] = 0;
1299
defaultScripts["debian_theme"] = 5;
1300
defaultScripts["grub-customizer_menu_color_helper"] = 6;
1301
defaultScripts["linux"] = 10;
1302
defaultScripts["linux_xen"] = 20;
1303
defaultScripts["memtest86+"] = 20;
1304
defaultScripts["os-prober"] = 30;
1305
defaultScripts["custom"] = 41;
1307
std::string proxyfiedScriptPath = this->env->cfg_dir + "/proxifiedScripts";
1309
for (std::list<Model_Script>::iterator scriptIter = this->repository.begin(); scriptIter != this->repository.end(); scriptIter++) {
1310
std::string currentPath = scriptIter->fileName;
1311
std::string defaultPath;
1314
if (scriptIter->isCustomScript) {
1315
defaultPath = this->env->cfg_dir + "/40_custom";
1316
} else if (defaultScripts.find(scriptIter->name) != defaultScripts.end()) {
1317
pos = defaultScripts[scriptIter->name];
1318
std::ostringstream str;
1319
str << this->env->cfg_dir << "/" << std::setw(2) << std::setfill('0') << pos << "_" << scriptIter->name;
1320
defaultPath = str.str();
1323
if (defaultPath != "" && defaultPath != currentPath) {
1324
this->scriptSourceMap[defaultPath] = currentPath;
1329
void populateScriptSourceMap() {
1330
std::string proxyfiedScriptPath = this->env->cfg_dir + "/proxifiedScripts";
1331
for (std::list<Model_Script>::iterator scriptIter = this->repository.begin(); scriptIter != this->repository.end(); scriptIter++) {
1332
if (scriptIter->fileName.substr(0, proxyfiedScriptPath.length()) != proxyfiedScriptPath
1333
&& this->scriptSourceMap.getSourceName(scriptIter->fileName) == "") {
1334
this->scriptSourceMap.addScript(scriptIter->fileName);
1339
bool hasScriptUpdates() const {
1340
return this->scriptSourceMap.getUpdates().size() > 0;
1343
void applyScriptUpdates() {
1344
std::list<std::string> newScriptPathes = this->scriptSourceMap.getUpdates();
1345
for (std::list<std::string>::iterator newScriptPathIter = newScriptPathes.begin(); newScriptPathIter != newScriptPathes.end(); newScriptPathIter++) {
1346
std::string oldScriptPath = this->scriptSourceMap[*newScriptPathIter];
1347
Model_Script* oldScript = this->repository.getScriptByFilename(oldScriptPath);
1348
Model_Script* newScript = this->repository.getScriptByFilename(*newScriptPathIter);
1349
if (!oldScript || !newScript) {
1350
this->log("applyScriptUpdates failed for " + oldScriptPath + " (" + *newScriptPathIter + ")", Logger::ERROR);
1354
// unsync proxies of newScript
1355
std::list<Model_Proxy*> newProxies = this->proxies.getProxiesByScript(*newScript);
1356
for (std::list<Model_Proxy*>::iterator newProxyIter = newProxies.begin(); newProxyIter != newProxies.end(); newProxyIter++) {
1357
(*newProxyIter)->unsync();
1358
this->proxies.deleteProxy(&**newProxyIter);
1361
// copy entries of custom scripts
1362
if (oldScript->isCustomScript && newScript->isCustomScript && oldScript->entries().size()) {
1363
for (std::list<Model_Entry>::iterator entryIter = oldScript->entries().begin(); entryIter != oldScript->entries().end(); entryIter++) {
1364
if (entryIter->type == Model_Entry::PLAINTEXT && newScript->getPlaintextEntry()) {
1365
newScript->getPlaintextEntry()->content = entryIter->content; // copy plaintext instead of adding another entry
1366
newScript->getPlaintextEntry()->isModified = true;
1368
newScript->entries().push_back(*entryIter);
1369
newScript->entries().back().isModified = true;
1374
// connect proxies of oldScript with newScript, resync
1375
std::list<Model_Proxy*> oldProxies = this->proxies.getProxiesByScript(*oldScript);
1376
for (std::list<Model_Proxy*>::iterator oldProxyIter = oldProxies.begin(); oldProxyIter != oldProxies.end(); oldProxyIter++) {
1377
// connect old proxy to new script
1378
(*oldProxyIter)->unsync();
1379
(*oldProxyIter)->dataSource = newScript;
1380
if ((*oldProxyIter)->fileName == oldScript->fileName) {
1381
(*oldProxyIter)->fileName = newScript->fileName; // set the new fileName
1385
std::list<Model_Rule*> foreignRules = this->proxies.getForeignRules();
1387
for (std::list<Model_Rule*>::iterator ruleIter = foreignRules.begin(); ruleIter != foreignRules.end(); ruleIter++) {
1388
if (this->repository.getScriptByEntry(*(*ruleIter)->dataSource) == oldScript) {
1389
(*ruleIter)->__sourceScriptPath = newScript->fileName;
1393
this->repository.removeScript(*oldScript);
1395
this->scriptSourceMap.deleteUpdates();
1397
this->proxies.unsync_all();
1398
this->proxies.sync_all(true, true, NULL, this->repository.getScriptPathMap());
1403
int remaining = this->proxies.size();
1405
this->proxies.deleteProxy(&this->proxies.front());
1406
assert(this->proxies.size() < remaining); // make sure that the proxy has really been deleted to prevent an endless loop
1407
remaining = this->proxies.size();
1409
std::list<std::string> usedIndices;
1410
int i = 50; // unknown scripts starting at position 50
1411
for (std::list<Model_Script>::iterator iter = this->repository.begin(); iter != this->repository.end(); iter++) {
1412
Model_Proxy newProxy(*iter);
1413
std::string sourceFileName = this->scriptSourceMap.getSourceName(iter->fileName);
1415
newProxy.index = Model_Script::extractIndexFromPath(sourceFileName, this->env->cfg_dir);
1416
} catch (InvalidStringFormatException const& e) {
1417
newProxy.index = i++;
1418
this->log(e, Logger::ERROR);
1422
std::ostringstream uniqueIndex;
1423
uniqueIndex << newProxy.index << iter->name;
1425
if (std::find(usedIndices.begin(), usedIndices.end(), uniqueIndex.str()) != usedIndices.end()) {
1426
newProxy.index = i++;
1429
usedIndices.push_back(uniqueIndex.str());
1431
this->proxies.push_back(newProxy);
1433
this->proxies.sort();
1437
operator ArrayStructure() const {
1438
ArrayStructure result;
1439
result["eventListener"] = this->controller;
1440
result["proxies"] = ArrayStructure(this->proxies);
1441
result["repository"] = ArrayStructure(this->repository);
1442
result["progress"] = this->progress;
1443
result["progress_name"] = this->progress_name;
1444
result["progress_pos"] = this->progress_pos;
1445
result["progress_max"] = this->progress_max;
1446
result["mutex"] = this->mutex;
1447
result["errorLogFile"] = this->errorLogFile;
1448
result["verbose"] = this->verbose;
1449
result["error_proxy_not_found"] = this->error_proxy_not_found;
1451
result["env"] = ArrayStructure(*this->env);
1453
result["env"] = ArrayStructureItem(NULL);
1455
result["ignoreLock"] = this->ignoreLock;
1456
result["cancelThreadsRequested"] = this->cancelThreadsRequested;
1461
class Model_ListCfg_Connection {
1463
Model_ListCfg* grublistCfg;
1465
Model_ListCfg_Connection() : grublistCfg(NULL) {}
1467
void setListCfg(Model_ListCfg& grublistCfg){
1468
this->grublistCfg = &grublistCfg;