00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <sys/types.h>
00022 #include <sys/stat.h>
00023 #include <unistd.h>
00024 #include <stdlib.h>
00025 #include <kde_file.h>
00026
00027 #include <QtCore/QDate>
00028 #include <QtCore/QFile>
00029 #include <QtCore/QTextStream>
00030 #include <QtCore/QTextCodec>
00031
00032 #include <kconfig.h>
00033 #include <kconfiggroup.h>
00034 #include <klocale.h>
00035 #include <kcmdlineargs.h>
00036 #include <kglobal.h>
00037 #include <kstandarddirs.h>
00038 #include <kaboutdata.h>
00039 #include <kcomponentdata.h>
00040 #include <ktemporaryfile.h>
00041 #include <kurl.h>
00042
00043 class KonfUpdate
00044 {
00045 public:
00046 KonfUpdate();
00047 ~KonfUpdate();
00048 QStringList findUpdateFiles(bool dirtyOnly);
00049
00050 QTextStream &log();
00051
00052 bool checkFile(const QString &filename);
00053 void checkGotFile(const QString &_file, const QString &id);
00054
00055 bool updateFile(const QString &filename);
00056
00057 void gotId(const QString &_id);
00058 void gotFile(const QString &_file);
00059 void gotGroup(const QString &_group);
00060 void gotRemoveGroup(const QString &_group);
00061 void gotKey(const QString &_key);
00062 void gotRemoveKey(const QString &_key);
00063 void gotAllKeys();
00064 void gotAllGroups();
00065 void gotOptions(const QString &_options);
00066 void gotScript(const QString &_script);
00067 void gotScriptArguments(const QString &_arguments);
00068 void resetOptions();
00069
00070 void copyGroup(KConfig *cfg1, const QString &group1,
00071 KConfig *cfg2, const QString &group2);
00072
00073 protected:
00074 KConfig *config;
00075 QString currentFilename;
00076 bool skip;
00077 bool skipFile;
00078 bool debug;
00079 QString id;
00080
00081 QString oldFile;
00082 QString newFile;
00083 QString newFileName;
00084 KConfig *oldConfig1;
00085 KConfig *oldConfig2;
00086 KConfig *newConfig;
00087
00088 QString oldGroup;
00089 QString newGroup;
00090 QString oldKey;
00091 QString newKey;
00092
00093 bool m_bCopy;
00094 bool m_bOverwrite;
00095 bool m_bUseConfigInfo;
00096 QString m_arguments;
00097 QTextStream *m_textStream;
00098 QFile *m_file;
00099 QString m_line;
00100 int m_lineCount;
00101 };
00102
00103 KonfUpdate::KonfUpdate()
00104 : m_textStream(0), m_file(0)
00105 {
00106 bool updateAll = false;
00107 oldConfig1 = 0;
00108 oldConfig2 = 0;
00109 newConfig = 0;
00110
00111 config = new KConfig("kconf_updaterc");
00112 KConfigGroup cg(config, QString());
00113
00114 QStringList updateFiles;
00115 KCmdLineArgs *args=KCmdLineArgs::parsedArgs();
00116
00117 debug = args->isSet("debug");
00118
00119 m_bUseConfigInfo = false;
00120 if (args->isSet("check"))
00121 {
00122 m_bUseConfigInfo = true;
00123 QString file = KStandardDirs::locate("data", "kconf_update/"+args->getOption("check"));
00124 if (file.isEmpty())
00125 {
00126 qWarning("File '%s' not found.", args->getOption("check").toLocal8Bit().data());
00127 log() << "File '" << args->getOption("check") << "' passed on command line not found" << endl;
00128 return;
00129 }
00130 updateFiles.append(file);
00131 }
00132 else if (args->count())
00133 {
00134 for(int i = 0; i < args->count(); i++)
00135 {
00136 KUrl url = args->url(i);
00137 if (!url.isLocalFile())
00138 KCmdLineArgs::usageError(i18n("Only local files are supported."));
00139 updateFiles.append(url.path());
00140 }
00141 }
00142 else
00143 {
00144 if (cg.readEntry("autoUpdateDisabled", false))
00145 return;
00146 updateFiles = findUpdateFiles(true);
00147 updateAll = true;
00148 }
00149
00150 for(QStringList::ConstIterator it = updateFiles.begin();
00151 it != updateFiles.end();
00152 ++it)
00153 {
00154 QString file = *it;
00155 updateFile(file);
00156 }
00157
00158 if (updateAll && !cg.readEntry("updateInfoAdded", false))
00159 {
00160 cg.writeEntry("updateInfoAdded", true);
00161 updateFiles = findUpdateFiles(false);
00162
00163 for(QStringList::ConstIterator it = updateFiles.begin();
00164 it != updateFiles.end();
00165 ++it)
00166 {
00167 QString file = *it;
00168 checkFile(file);
00169 }
00170 updateFiles.clear();
00171 }
00172 }
00173
00174 KonfUpdate::~KonfUpdate()
00175 {
00176 delete config;
00177 delete m_file;
00178 delete m_textStream;
00179 }
00180
00181 QTextStream &
00182 KonfUpdate::log()
00183 {
00184 if (!m_textStream)
00185 {
00186 QString file = KStandardDirs::locateLocal("data", "kconf_update/log/update.log");
00187 m_file = new QFile(file);
00188 if (m_file->open(QIODevice::WriteOnly | QIODevice::Append))
00189 {
00190 m_textStream = new QTextStream(m_file);
00191 }
00192 else
00193 {
00194
00195 m_textStream = new QTextStream(stderr, QIODevice::WriteOnly);
00196 }
00197 }
00198
00199 (*m_textStream) << QDateTime::currentDateTime().toString( Qt::ISODate ) << " ";
00200
00201 return *m_textStream;
00202 }
00203
00204 QStringList KonfUpdate::findUpdateFiles(bool dirtyOnly)
00205 {
00206 QStringList result;
00207 QStringList list = KGlobal::dirs()->findAllResources("data", "kconf_update/*.upd",
00208 KStandardDirs::NoDuplicates);
00209 for(QStringList::ConstIterator it = list.begin();
00210 it != list.end();
00211 ++it)
00212 {
00213 QString file = *it;
00214 KDE_struct_stat buff;
00215 if (KDE_stat( QFile::encodeName(file), &buff) == 0)
00216 {
00217 int i = file.lastIndexOf('/');
00218 if (i != -1)
00219 file = file.mid(i+1);
00220 KConfigGroup cg(config, file);
00221 time_t ctime = cg.readEntry("ctime", 0);
00222 time_t mtime = cg.readEntry("mtime", 0);
00223 if (!dirtyOnly ||
00224 (ctime != buff.st_ctime) || (mtime != buff.st_mtime))
00225 {
00226 result.append(*it);
00227 }
00228 }
00229 }
00230 return result;
00231 }
00232
00233 bool KonfUpdate::checkFile(const QString &filename)
00234 {
00235 currentFilename = filename;
00236 int i = currentFilename.lastIndexOf('/');
00237 if (i != -1)
00238 currentFilename = currentFilename.mid(i+1);
00239 skip = true;
00240 QFile file(filename);
00241 if (!file.open(QIODevice::ReadOnly))
00242 return false;
00243
00244 QTextStream ts(&file);
00245 ts.setCodec(QTextCodec::codecForName("ISO-8859-1"));
00246 int lineCount = 0;
00247 resetOptions();
00248 QString id;
00249 while(!ts.atEnd())
00250 {
00251 QString line = ts.readLine().trimmed();
00252 lineCount++;
00253 if (line.isEmpty() || (line[0] == '#'))
00254 continue;
00255 if (line.startsWith("Id="))
00256 id = currentFilename+':'+line.mid(3);
00257 else if (line.startsWith("File="))
00258 checkGotFile(line.mid(5), id);
00259 }
00260
00261 return true;
00262 }
00263
00264 void KonfUpdate::checkGotFile(const QString &_file, const QString &id)
00265 {
00266 QString file;
00267 int i = _file.indexOf(',');
00268 if (i == -1)
00269 {
00270 file = _file.trimmed();
00271 }
00272 else
00273 {
00274 file = _file.mid(i+1).trimmed();
00275 }
00276
00277
00278
00279 KConfig cfg(file, KConfig::SimpleConfig);
00280 KConfigGroup cg(&cfg, "$Version");
00281 QStringList ids = cg.readEntry("update_info", QStringList());
00282 if (ids.contains(id))
00283 return;
00284 ids.append(id);
00285 cg.writeEntry("update_info", ids);
00286 }
00287
00307 bool KonfUpdate::updateFile(const QString &filename)
00308 {
00309 currentFilename = filename;
00310 int i = currentFilename.lastIndexOf('/');
00311 if (i != -1)
00312 currentFilename = currentFilename.mid(i+1);
00313 skip = true;
00314 QFile file(filename);
00315 if (!file.open(QIODevice::ReadOnly))
00316 return false;
00317
00318 log() << "Checking update-file '" << filename << "' for new updates" << endl;
00319
00320 QTextStream ts(&file);
00321 ts.setCodec(QTextCodec::codecForName("ISO-8859-1"));
00322 m_lineCount = 0;
00323 resetOptions();
00324 while(!ts.atEnd())
00325 {
00326 m_line = ts.readLine().trimmed();
00327 m_lineCount++;
00328 if (m_line.isEmpty() || (m_line[0] == '#'))
00329 continue;
00330 if (m_line.startsWith("Id="))
00331 gotId(m_line.mid(3));
00332 else if (skip)
00333 continue;
00334 else if (m_line.startsWith("Options="))
00335 gotOptions(m_line.mid(8));
00336 else if (m_line.startsWith("File="))
00337 gotFile(m_line.mid(5));
00338 else if(skipFile)
00339 continue;
00340 else if (m_line.startsWith("Group="))
00341 gotGroup(m_line.mid(6));
00342 else if (m_line.startsWith("RemoveGroup="))
00343 {
00344 gotRemoveGroup(m_line.mid(12));
00345 resetOptions();
00346 }
00347 else if (m_line.startsWith("Script="))
00348 {
00349 gotScript(m_line.mid(7));
00350 resetOptions();
00351 }
00352 else if (m_line.startsWith("ScriptArguments="))
00353 gotScriptArguments(m_line.mid(16));
00354 else if (m_line.startsWith("Key="))
00355 {
00356 gotKey(m_line.mid(4));
00357 resetOptions();
00358 }
00359 else if (m_line.startsWith("RemoveKey="))
00360 {
00361 gotRemoveKey(m_line.mid(10));
00362 resetOptions();
00363 }
00364 else if (m_line == "AllKeys")
00365 {
00366 gotAllKeys();
00367 resetOptions();
00368 }
00369 else if (m_line == "AllGroups")
00370 {
00371 gotAllGroups();
00372 resetOptions();
00373 }
00374 else
00375 {
00376 log() << currentFilename << ": parse error in line " << m_lineCount << " : '" << m_line << "'" << endl;
00377 }
00378 }
00379
00380 gotId(QString());
00381
00382 KDE_struct_stat buff;
00383 KDE_stat( QFile::encodeName(filename), &buff);
00384 KConfigGroup cg(config, currentFilename);
00385 cg.writeEntry("ctime", int(buff.st_ctime));
00386 cg.writeEntry("mtime", int(buff.st_mtime));
00387 cg.sync();
00388 return true;
00389 }
00390
00391
00392
00393 void KonfUpdate::gotId(const QString &_id)
00394 {
00395 if (!id.isEmpty() && !skip)
00396 {
00397 KConfigGroup cg(config, currentFilename);
00398
00399 QStringList ids = cg.readEntry("done", QStringList());
00400 if (!ids.contains(id))
00401 {
00402 ids.append(id);
00403 cg.writeEntry("done", ids);
00404 cg.sync();
00405 }
00406 }
00407
00408
00409 gotFile(QString());
00410 KConfigGroup cg(config, currentFilename);
00411
00412 QStringList ids = cg.readEntry("done", QStringList());
00413 if (!_id.isEmpty())
00414 {
00415 if (ids.contains(_id))
00416 {
00417
00418 if (!m_bUseConfigInfo)
00419 {
00420 skip = true;
00421 return;
00422 }
00423 }
00424 skip = false;
00425 skipFile = false;
00426 id = _id;
00427 if (m_bUseConfigInfo)
00428 log() << currentFilename << ": Checking update '" << _id << "'" << endl;
00429 else
00430 log() << currentFilename << ": Found new update '" << _id << "'" << endl;
00431 }
00432 }
00433
00434 void KonfUpdate::gotFile(const QString &_file)
00435 {
00436
00437 gotGroup(QString());
00438
00439 if (!oldFile.isEmpty())
00440 {
00441
00442 delete oldConfig1;
00443 oldConfig1 = 0;
00444
00445 KConfigGroup cg(oldConfig2, "$Version");
00446 QStringList ids = cg.readEntry("update_info", QStringList());
00447 QString cfg_id = currentFilename + ':' + id;
00448 if (!ids.contains(cfg_id) && !skip)
00449 {
00450 ids.append(cfg_id);
00451 cg.writeEntry("update_info", ids);
00452 }
00453 cg.sync();
00454 delete oldConfig2;
00455 oldConfig2 = 0;
00456
00457 QString file = KStandardDirs::locateLocal("config", oldFile);
00458 KDE_struct_stat s_buf;
00459 if (KDE_stat(QFile::encodeName(file), &s_buf) == 0)
00460 {
00461 if (s_buf.st_size == 0)
00462 {
00463
00464 unlink(QFile::encodeName(file));
00465 }
00466 }
00467
00468 oldFile.clear();
00469 }
00470 if (!newFile.isEmpty())
00471 {
00472
00473 KConfigGroup cg(newConfig, "$Version");
00474 QStringList ids = cg.readEntry("update_info", QStringList());
00475 QString cfg_id = currentFilename + ':' + id;
00476 if (!ids.contains(cfg_id) && !skip)
00477 {
00478 ids.append(cfg_id);
00479 cg.writeEntry("update_info", ids);
00480 }
00481 newConfig->sync();
00482 delete newConfig;
00483 newConfig = 0;
00484
00485 newFile.clear();
00486 }
00487 newConfig = 0;
00488
00489 int i = _file.indexOf(',');
00490 if (i == -1)
00491 {
00492 oldFile = _file.trimmed();
00493 }
00494 else
00495 {
00496 oldFile = _file.left(i).trimmed();
00497 newFile = _file.mid(i+1).trimmed();
00498 if (oldFile == newFile)
00499 newFile.clear();
00500 }
00501
00502 if (!oldFile.isEmpty())
00503 {
00504 oldConfig2 = new KConfig(oldFile, KConfig::NoGlobals);
00505 QString cfg_id = currentFilename + ':' + id;
00506 KConfigGroup cg(oldConfig2, "$Version");
00507 QStringList ids = cg.readEntry("update_info", QStringList());
00508 if (ids.contains(cfg_id))
00509 {
00510 skip = true;
00511 newFile.clear();
00512 log() << currentFilename << ": Skipping update '" << id << "'" << endl;
00513 }
00514
00515 if (!newFile.isEmpty())
00516 {
00517 newConfig = new KConfig(newFile, KConfig::NoGlobals);
00518 KConfigGroup cg(newConfig, "$Version");
00519 ids = cg.readEntry("update_info", QStringList());
00520 if (ids.contains(cfg_id))
00521 {
00522 skip = true;
00523 log() << currentFilename << ": Skipping update '" << id << "'" << endl;
00524 }
00525 }
00526 else
00527 {
00528 newConfig = oldConfig2;
00529 }
00530
00531 oldConfig1 = new KConfig(oldFile, KConfig::NoGlobals);
00532 }
00533 else
00534 {
00535 newFile.clear();
00536 }
00537 newFileName = newFile;
00538 if (newFileName.isEmpty())
00539 newFileName = oldFile;
00540
00541 skipFile = false;
00542 if( !oldFile.isEmpty())
00543 {
00544 if( oldConfig1 != NULL
00545 && ( oldConfig1->groupList().isEmpty()
00546 || ( oldConfig1->groupList().count() == 1 && oldConfig1->groupList().first() == "$Version" )))
00547 {
00548 log() << currentFilename << ": File '" << oldFile << "' does not exist or empty, skipping" << endl;
00549 skipFile = true;
00550 }
00551 }
00552 }
00553
00554 void KonfUpdate::gotGroup(const QString &_group)
00555 {
00556 int i = _group.indexOf(',');
00557 if (i == -1)
00558 {
00559 oldGroup = _group.trimmed();
00560 newGroup = oldGroup;
00561 }
00562 else
00563 {
00564 oldGroup = _group.left(i).trimmed();
00565 newGroup = _group.mid(i+1).trimmed();
00566 }
00567 }
00568
00569 void KonfUpdate::gotRemoveGroup(const QString &_group)
00570 {
00571 oldGroup = _group.trimmed();
00572
00573 if (!oldConfig1)
00574 {
00575 log() << currentFilename << ": !! RemoveGroup without previous File specification in line " << m_lineCount << " : '" << m_line << "'" << endl;
00576 return;
00577 }
00578
00579 if (!oldConfig1->hasGroup(oldGroup))
00580 return;
00581
00582 oldConfig2->deleteGroup(oldGroup);
00583 log() << currentFilename << ": RemoveGroup removes group " << oldFile << ":" << oldGroup << endl;
00584 }
00585
00586
00587 void KonfUpdate::gotKey(const QString &_key)
00588 {
00589 int i = _key.indexOf(',');
00590 if (i == -1)
00591 {
00592 oldKey = _key.trimmed();
00593 newKey = oldKey;
00594 }
00595 else
00596 {
00597 oldKey = _key.left(i).trimmed();
00598 newKey = _key.mid(i+1).trimmed();
00599 }
00600
00601 if (oldKey.isEmpty() || newKey.isEmpty())
00602 {
00603 log() << currentFilename << ": !! Key specifies invalid key in line " << m_lineCount << " : '" << m_line << "'" << endl;
00604 return;
00605 }
00606 if (!oldConfig1)
00607 {
00608 log() << currentFilename << ": !! Key without previous File specification in line " << m_lineCount << " : '" << m_line << "'" << endl;
00609 return;
00610 }
00611 KConfigGroup cg1( oldConfig1, oldGroup);
00612 if (!cg1.hasKey(oldKey))
00613 return;
00614 QString value = cg1.readEntry(oldKey, QString());
00615 KConfigGroup newFGroup( newConfig, newGroup);
00616 if (!m_bOverwrite && newFGroup.hasKey(newKey))
00617 {
00618 log() << currentFilename << ": Skipping " << newFileName << ":" << newGroup << ":" << newKey << ", already exists."<< endl;
00619 return;
00620 }
00621 log() << currentFilename << ": Updating " << newFileName << ":" << newGroup << ":" << newKey << " to '" << value << "'" << endl;
00622 newFGroup.writeEntry(newKey, value);
00623
00624 if (m_bCopy)
00625 return;
00626
00627
00628 if ((oldConfig2 == newConfig) &&
00629 (oldGroup == newGroup) &&
00630 (oldKey == newKey))
00631 return;
00632 KConfigGroup oldGroup2( oldConfig2, oldGroup);
00633 oldGroup2.deleteEntry(oldKey);
00634 log() << currentFilename << ": Removing " << oldFile << ":" << oldGroup << ":" << oldKey << ", moved." << endl;
00635
00636
00637
00638 }
00639
00640 void KonfUpdate::gotRemoveKey(const QString &_key)
00641 {
00642 oldKey = _key.trimmed();
00643
00644 if (oldKey.isEmpty())
00645 {
00646 log() << currentFilename << ": !! RemoveKey specifies invalid key in line " << m_lineCount << " : '" << m_line << "'" << endl;
00647 return;
00648 }
00649
00650 if (!oldConfig1)
00651 {
00652 log() << currentFilename << ": !! Key without previous File specification in line " << m_lineCount << " : '" << m_line << "'" << endl;
00653 return;
00654 }
00655
00656 KConfigGroup cg1(oldConfig1, oldGroup);
00657 if (!cg1.hasKey(oldKey))
00658 return;
00659 log() << currentFilename << ": RemoveKey removes " << oldFile << ":" << oldGroup << ":" << oldKey << endl;
00660
00661
00662 KConfigGroup cg2( oldConfig2, oldGroup);
00663 cg2.deleteEntry(oldKey);
00664
00665
00666
00667 }
00668
00669 void KonfUpdate::gotAllKeys()
00670 {
00671 if (!oldConfig1)
00672 {
00673 log() << currentFilename << ": !! AllKeys without previous File specification in line " << m_lineCount << " : '" << m_line << "'" << endl;
00674 return;
00675 }
00676
00677 QMap<QString, QString> list = oldConfig1->entryMap(oldGroup);
00678 for(QMap<QString, QString>::Iterator it = list.begin();
00679 it != list.end(); ++it)
00680 {
00681 gotKey(it.key());
00682 }
00683 }
00684
00685 void KonfUpdate::gotAllGroups()
00686 {
00687 if (!oldConfig1)
00688 {
00689 log() << currentFilename << ": !! AllGroups without previous File specification in line " << m_lineCount << " : '" << m_line << "'" << endl;
00690 return;
00691 }
00692
00693 QStringList allGroups = oldConfig1->groupList();
00694 for(QStringList::ConstIterator it = allGroups.begin();
00695 it != allGroups.end(); ++it)
00696 {
00697 oldGroup = *it;
00698 newGroup = oldGroup;
00699 gotAllKeys();
00700 }
00701 }
00702
00703 void KonfUpdate::gotOptions(const QString &_options)
00704 {
00705 QStringList options = _options.split(',');
00706 for(QStringList::ConstIterator it = options.begin();
00707 it != options.end();
00708 ++it)
00709 {
00710 if ( (*it).toLower().trimmed() == "copy")
00711 m_bCopy = true;
00712
00713 if ( (*it).toLower().trimmed() == "overwrite")
00714 m_bOverwrite = true;
00715 }
00716 }
00717
00718 void KonfUpdate::copyGroup(KConfig *cfg1, const QString &group1,
00719 KConfig *cfg2, const QString &group2)
00720 {
00721 KConfigGroup cg1(cfg1, group1);
00722 KConfigGroup cg2(cfg2, group2);
00723 QMap<QString, QString> list = cg1.entryMap();
00724 for(QMap<QString, QString>::Iterator it = list.begin();
00725 it != list.end(); ++it)
00726 {
00727 cg2.writeEntry(it.key(), cg1.readEntry(it.key(), QString()));
00728 }
00729 }
00730
00731 void KonfUpdate::gotScriptArguments(const QString &_arguments)
00732 {
00733 m_arguments = _arguments;
00734 }
00735
00736 void KonfUpdate::gotScript(const QString &_script)
00737 {
00738 QString script, interpreter;
00739 int i = _script.indexOf(',');
00740 if (i == -1)
00741 {
00742 script = _script.trimmed();
00743 }
00744 else
00745 {
00746 script = _script.left(i).trimmed();
00747 interpreter = _script.mid(i+1).trimmed();
00748 }
00749
00750
00751 if (script.isEmpty())
00752 {
00753 log() << currentFilename << ": !! Script fails to specify filename in line " << m_lineCount << " : '" << m_line << "'" << endl;
00754 skip = true;
00755 return;
00756 }
00757
00758
00759
00760 QString path = KStandardDirs::locate("data","kconf_update/"+script);
00761 if (path.isEmpty())
00762 {
00763 if (interpreter.isEmpty())
00764 path = KStandardDirs::locate("lib", "kconf_update_bin/"+script);
00765
00766 if (path.isEmpty())
00767 {
00768 log() << currentFilename << ": !! Script '" << script << "' not found in line " << m_lineCount << " : '" << m_line << "'" << endl;
00769 skip = true;
00770 return;
00771 }
00772 }
00773
00774 if( !m_arguments.isNull())
00775 log() << currentFilename << ": Running script '" << script << "' with arguments '" << m_arguments << "'" << endl;
00776 else
00777 log() << currentFilename << ": Running script '" << script << "'" << endl;
00778
00779 QString cmd;
00780 if (interpreter.isEmpty())
00781 cmd = path;
00782 else
00783 cmd = interpreter + ' ' + path;
00784
00785 if( !m_arguments.isNull())
00786 {
00787 cmd += ' ';
00788 cmd += m_arguments;
00789 }
00790
00791 KTemporaryFile tmp1;
00792 tmp1.open();
00793 KTemporaryFile tmp2;
00794 tmp2.open();
00795 KTemporaryFile tmp3;
00796 tmp3.open();
00797
00798 int result;
00799 if (oldConfig1)
00800 {
00801 if (debug)
00802 {
00803 tmp1.setAutoRemove(false);
00804 log() << "Script input stored in " << tmp1.fileName() << endl;
00805 }
00806 KConfig cfg(tmp1.fileName(), KConfig::SimpleConfig);
00807
00808 if (oldGroup.isEmpty())
00809 {
00810
00811 QStringList grpList = oldConfig1->groupList();
00812 for(QStringList::ConstIterator it = grpList.begin();
00813 it != grpList.end();
00814 ++it)
00815 {
00816 copyGroup(oldConfig1, *it, &cfg, *it);
00817 }
00818 }
00819 else
00820 {
00821 copyGroup(oldConfig1, oldGroup, &cfg, QString());
00822 }
00823 cfg.sync();
00824 result = system(QFile::encodeName(QString("%1 < %2 > %3 2> %4").arg(cmd, tmp1.fileName(), tmp2.fileName(), tmp3.fileName())));
00825 }
00826 else
00827 {
00828
00829 result = system(QFile::encodeName(QString("%1 2> %2").arg(cmd, tmp3.fileName())));
00830 }
00831
00832
00833 {
00834 QFile output(tmp3.fileName());
00835 if (output.open(QIODevice::ReadOnly))
00836 {
00837 QTextStream ts( &output );
00838 ts.setCodec(QTextCodec::codecForName("UTF-8"));
00839 while(!ts.atEnd())
00840 {
00841 QString line = ts.readLine();
00842 log() << "[Script] " << line << endl;
00843 }
00844 }
00845 }
00846
00847 if (result)
00848 {
00849 log() << currentFilename << ": !! An error occurred while running '" << cmd << "'" << endl;
00850 return;
00851 }
00852
00853 if (!oldConfig1)
00854 return;
00855
00856 if (debug)
00857 {
00858 tmp2.setAutoRemove(false);
00859 log() << "Script output stored in " << tmp2.fileName() << endl;
00860 }
00861
00862
00863 {
00864 QString group = oldGroup;
00865 QFile output(tmp2.fileName());
00866 if (output.open(QIODevice::ReadOnly))
00867 {
00868 QTextStream ts( &output );
00869 ts.setCodec(QTextCodec::codecForName("UTF-8"));
00870 while(!ts.atEnd())
00871 {
00872 QString line = ts.readLine();
00873 if (line.startsWith('['))
00874 {
00875 int j = line.indexOf(']')+1;
00876 if (j > 0)
00877 group = line.mid(1, j-2);
00878 }
00879 else if (line.startsWith("# DELETE "))
00880 {
00881 QString key = line.mid(9);
00882 if (key[0] == '[')
00883 {
00884 int j = key.indexOf(']')+1;
00885 if (j > 0)
00886 {
00887 group = key.mid(1,j-2);
00888 key = key.mid(j);
00889 }
00890 }
00891 KConfigGroup cg(oldConfig2, group);
00892 cg.deleteEntry(key);
00893 log() << currentFilename << ": Script removes " << oldFile << ":" << group << ":" << key << endl;
00894
00895
00896
00897 }
00898 else if (line.startsWith("# DELETEGROUP"))
00899 {
00900 QString key = line.mid(13).trimmed();
00901 if (key[0] == '[')
00902 {
00903 int j = key.indexOf(']')+1;
00904 if (j > 0)
00905 {
00906 group = key.mid(1,j-2);
00907 }
00908 }
00909 oldConfig2->deleteGroup(group);
00910 log() << currentFilename << ": Script removes group " << oldFile << ":" << group << endl;
00911 }
00912 }
00913 }
00914 }
00915
00916
00917 m_bCopy = true;
00918 {
00919 KConfig *saveOldConfig1 = oldConfig1;
00920 QString saveOldGroup = oldGroup;
00921 QString saveNewGroup = newGroup;
00922 oldConfig1 = new KConfig(tmp2.fileName(), KConfig::NoGlobals);
00923
00924
00925 QStringList grpList = oldConfig1->groupList();
00926 for(QStringList::ConstIterator it = grpList.begin();
00927 it != grpList.end();
00928 ++it)
00929 {
00930 oldGroup = *it;
00931 if (oldGroup != "<default>")
00932 {
00933 newGroup = oldGroup;
00934 }
00935 gotAllKeys();
00936 }
00937 delete oldConfig1;
00938 oldConfig1 = saveOldConfig1;
00939 oldGroup = saveOldGroup;
00940 newGroup = saveNewGroup;
00941 }
00942 }
00943
00944 void KonfUpdate::resetOptions()
00945 {
00946 m_bCopy = false;
00947 m_bOverwrite = false;
00948 m_arguments.clear();
00949 }
00950
00951
00952 extern "C" KDE_EXPORT int kdemain(int argc, char **argv)
00953 {
00954 KCmdLineOptions options;
00955 options.add("debug", ki18n("Keep output results from scripts"));
00956 options.add("check <update-file>", ki18n("Check whether config file itself requires updating"));
00957 options.add("+[file]", ki18n("File to read update instructions from"));
00958
00959 KAboutData aboutData("kconf_update", 0, ki18n("KConf Update"),
00960 "1.0.2",
00961 ki18n("KDE Tool for updating user configuration files"),
00962 KAboutData::License_GPL,
00963 ki18n("(c) 2001, Waldo Bastian"));
00964
00965 aboutData.addAuthor(ki18n("Waldo Bastian"), KLocalizedString(), "bastian@kde.org");
00966
00967 KCmdLineArgs::init(argc, argv, &aboutData);
00968 KCmdLineArgs::addCmdLineOptions(options);
00969
00970 KComponentData componentData(&aboutData);
00971
00972 KonfUpdate konfUpdate;
00973
00974 return 0;
00975 }