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