45 #include <QtCore/QDir>
46 #include <QtXml/qdom.h>
47 #include <QtCore/Q_PID>
51 #define _WIN32_IE 0x0500
58 :
QObject(parent), m_uploadedentry(NULL), m_uploadprovider(NULL), m_installation(NULL), m_activefeeds(0),
59 m_initialized(false), m_cachepolicy(CacheNever), m_automationpolicy(AutomationOn)
70 kDebug() <<
"Initializing KNS::CoreEngine from '" << configfile <<
"'";
74 kError() <<
"No knsrc file named '" << configfile <<
"' was found." << endl;
82 kError() <<
"No knsrc file named '" << configfile <<
"' was found." << endl;
87 kError() <<
"A knsrc file was found but it doesn't contain a KNewStuff2 section." << endl;
101 if (uncompresssetting ==
"true") {
102 uncompresssetting =
"always";
104 if (uncompresssetting !=
"always" && uncompresssetting !=
"archive" && uncompresssetting !=
"never") {
105 kError() <<
"invalid Uncompress setting chosen, must be one of: always, archive, or never" << endl;
119 if (!checksumpolicy.isEmpty()) {
120 if (checksumpolicy ==
"never")
122 else if (checksumpolicy ==
"ifpossible")
124 else if (checksumpolicy ==
"always")
127 kError() <<
"The checksum policy '" + checksumpolicy +
"' is unknown." << endl;
133 if (!signaturepolicy.isEmpty()) {
134 if (signaturepolicy ==
"never")
136 else if (signaturepolicy ==
"ifpossible")
138 else if (signaturepolicy ==
"always")
141 kError() <<
"The signature policy '" + signaturepolicy +
"' is unknown." << endl;
147 if (!scope.isEmpty()) {
150 else if (scope ==
"system")
153 kError() <<
"The scope '" + scope +
"' is unknown." << endl;
159 kError() <<
"System installation cannot be mixed with InstallPath." << endl;
166 if (!cachePolicy.isEmpty()) {
167 if (cachePolicy ==
"never") {
169 }
else if (cachePolicy ==
"replaceable") {
171 }
else if (cachePolicy ==
"resident") {
173 }
else if (cachePolicy ==
"only") {
176 kError() <<
"Cache policy '" + cachePolicy +
"' is unknown." << endl;
179 kDebug() <<
"cache policy: " << cachePolicy;
181 m_initialized =
true;
188 if (!m_initialized) {
192 return m_componentname;
199 if (!m_initialized) {
200 kError() <<
"Must call KNS::CoreEngine::init() first." << endl;
209 loadProvidersCache();
221 connect(provider_loader,
224 connect(provider_loader,
226 SLOT(slotProvidersFailed()));
228 provider_loader->
load(m_providersurl);
247 for (
int i = 0; i < feeds.count(); i++) {
254 connect(entry_loader,
257 connect(entry_loader,
259 SLOT(slotEntriesFailed()));
260 connect(entry_loader,
262 SLOT(slotProgress(
KJob*,ulong)));
264 entry_loader->
load(provider, feed);
271 if (m_previewfiles.contains(entry)) {
280 if (!source.isValid()) {
281 kError() <<
"The entry doesn't have a preview." << endl;
291 SIGNAL(result(
KJob*)),
292 SLOT(slotPreviewResult(
KJob*)));
294 SIGNAL(progress(
KJob*,ulong)),
295 SLOT(slotProgress(
KJob*,ulong)));
297 m_entry_jobs[job] = entry;
308 if (!source.isValid()) {
309 kError() <<
"The entry doesn't have a payload." << endl;
326 kDebug() <<
"Downloading payload '" << source <<
"' to '" << destination <<
"'";
331 SIGNAL(result(
KJob*)),
332 SLOT(slotPayloadResult(
KJob*)));
334 SIGNAL(percent(
KJob*,ulong)),
335 SLOT(slotProgress(
KJob*,ulong)));
337 m_entry_jobs[job] = entry;
344 if (m_uploadedentry) {
345 kError() <<
"Another upload is in progress!" << endl;
350 kError() <<
"The provider doesn't support uploads." << endl;
357 m_uploadprovider = provider;
358 m_uploadedentry = entry;
367 SIGNAL(result(
KJob*)),
368 SLOT(slotUploadPayloadResult(
KJob*)));
379 mergeProviders(list);
382 void CoreEngine::slotProvidersFailed()
384 kDebug() <<
"slotProvidersFailed";
408 void CoreEngine::slotEntriesFailed()
417 void CoreEngine::slotProgress(
KJob *job,
unsigned long percent)
422 if (copyJob != NULL) {
424 }
else if (transferJob != NULL) {
425 url = transferJob->url().fileName();
432 void CoreEngine::slotPayloadResult(
KJob *job)
435 if (m_entry_jobs.contains(job)) {
436 Entry *entry = m_entry_jobs[job];
437 m_entry_jobs.remove(job);
440 kError() <<
"Cannot load payload file." << endl;
456 void CoreEngine::slotPreviewResult(
KJob *job)
459 kError() <<
"Cannot load preview file." << endl;
462 m_entry_jobs.remove(job);
467 if (m_entry_jobs.contains(job)) {
469 Entry *entry = m_entry_jobs[job];
470 m_entry_jobs.remove(job);
480 void CoreEngine::slotUploadPayloadResult(
KJob *job)
483 kError() <<
"Cannot upload payload file." << endl;
486 m_uploadedentry = NULL;
487 m_uploadprovider = NULL;
495 slotUploadPreviewResult(job);
506 SIGNAL(result(
KJob*)),
507 SLOT(slotUploadPreviewResult(
KJob*)));
510 void CoreEngine::slotUploadPreviewResult(
KJob *job)
513 kError() <<
"Cannot upload preview file." << endl;
516 m_uploadedentry = NULL;
517 m_uploadprovider = NULL;
533 QDomElement exml = eh.entryXML();
536 QDomElement root = doc.createElement(
"ghnsupload");
537 root.appendChild(exml);
539 QFile f(sourcemeta.
path());
540 if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
541 kError() <<
"Cannot write meta information to '" << sourcemeta <<
"'." << endl;
543 m_uploadedentry = NULL;
544 m_uploadprovider = NULL;
549 QTextStream metastream(&f);
555 SIGNAL(result(
KJob*)),
556 SLOT(slotUploadMetaResult(
KJob*)));
559 void CoreEngine::slotUploadMetaResult(
KJob *job)
562 kError() <<
"Cannot upload meta file." << endl;
565 m_uploadedentry = NULL;
566 m_uploadprovider = NULL;
571 m_uploadedentry = NULL;
572 m_uploadprovider = NULL;
579 void CoreEngine::loadRegistry()
585 QString realAppName = m_componentname.split(
':')[0];
589 for (QStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it) {
592 const QStringList files =
dir.entryList(QDir::Files | QDir::Readable);
593 for (QStringList::const_iterator fit = files.begin(); fit != files.end(); ++fit) {
594 QString filepath = (*it) +
'/' + (*fit);
598 QFileInfo info(filepath);
604 QString thisAppName = QString::fromUtf8(QByteArray::fromBase64(info.baseName().toUtf8()));
608 thisAppName = thisAppName.split(
':')[0];
610 if (thisAppName != realAppName) {
614 ret = f.open(QIODevice::ReadOnly);
616 kWarning() <<
"The file could not be opened.";
621 ret = doc.setContent(&f);
623 kWarning() <<
"The file could not be parsed.";
627 QDomElement root = doc.documentElement();
628 if (root.tagName() !=
"ghnsinstall") {
629 kWarning() <<
"The file doesn't seem to be of interest.";
633 QDomElement stuff = root.firstChildElement(
"stuff");
634 if (stuff.isNull()) {
635 kWarning() <<
"Missing GHNS installation metadata.";
640 if (!handler.isValid()) {
641 kWarning() <<
"Invalid GHNS installation metadata.";
645 Entry *e = handler.entryptr();
648 m_entry_registry.insert(
id(e), e);
668 void CoreEngine::loadProvidersCache()
674 if (cachefile.isEmpty()) {
675 kDebug() <<
"Cache not present, skip loading.";
679 kDebug() <<
"Loading provider cache from file '" + cachefile +
"'.";
684 ret = f.open(QIODevice::ReadOnly);
686 kWarning() <<
"The file could not be opened.";
692 ret = doc.setContent(&f);
694 kWarning() <<
"The file could not be parsed.";
699 QDomElement root = doc.documentElement();
700 if (root.tagName() !=
"ghnsproviders") {
701 kWarning() <<
"The file doesn't seem to be of interest.";
706 QDomElement provider = root.firstChildElement(
"provider");
707 if (provider.isNull()) {
708 kWarning() <<
"Missing provider entries in the cache.";
713 while (!provider.isNull()) {
715 if (!handler.isValid()) {
716 kWarning() <<
"Invalid provider metadata.";
720 Provider *p = handler.providerptr();
721 m_provider_cache.append(p);
722 m_provider_index[pid(p)] = p;
733 provider = provider.nextSiblingElement(
"provider");
741 void CoreEngine::loadFeedCache(
Provider *provider)
745 kDebug() <<
"Loading feed cache.";
748 if (cachedirs.size() == 0) {
749 kDebug() <<
"Cache directory not present, skip loading.";
752 QString cachedir = cachedirs.first();
755 if (entrycachedirs.size() == 0) {
756 kDebug() <<
"Cache directory not present, skip loading.";
759 QString entrycachedir = entrycachedirs.first();
761 kDebug() <<
"Load from directory: " + cachedir;
764 for (
int i = 0; i < feeds.count(); i++) {
766 QString feedname = feeds.at(i);
768 QString idbase64 =
QString(pid(provider).toUtf8().toBase64() +
'-' + feedname);
769 QString cachefile = cachedir +
'/' + idbase64 +
".xml";
771 kDebug() <<
" + Load from file: " + cachefile;
775 ret = f.open(QIODevice::ReadOnly);
777 kWarning() <<
"The file could not be opened.";
782 ret = doc.setContent(&f);
784 kWarning() <<
"The file could not be parsed.";
788 QDomElement root = doc.documentElement();
789 if (root.tagName() !=
"ghnsfeeds") {
790 kWarning() <<
"The file doesn't seem to be of interest.";
794 QDomElement entryel = root.firstChildElement(
"entry-id");
795 if (entryel.isNull()) {
796 kWarning() <<
"Missing entries in the cache.";
800 while (!entryel.isNull()) {
801 QString idbase64 = entryel.text();
804 QString filepath = entrycachedir +
'/' + idbase64 +
".meta";
809 Entry *entry = loadEntryCache(filepath);
813 if (m_entry_registry.contains(entryid)) {
814 Entry * registryEntry = m_entry_registry.value(entryid);
824 entryel = entryel.nextSiblingElement(
"entry-id");
833 ret = f.open(QIODevice::ReadOnly);
835 kWarning() <<
"The file " << filepath <<
" could not be opened.";
840 ret = doc.setContent(&f);
842 kWarning() <<
"The file could not be parsed.";
846 QDomElement root = doc.documentElement();
847 if (root.tagName() !=
"ghnscache") {
848 kWarning() <<
"The file doesn't seem to be of interest.";
852 QDomElement stuff = root.firstChildElement(
"stuff");
853 if (stuff.isNull()) {
854 kWarning() <<
"Missing GHNS cache metadata.";
859 if (!handler.isValid()) {
860 kWarning() <<
"Invalid GHNS installation metadata.";
864 Entry *e = handler.entryptr();
866 m_entry_cache.append(e);
867 m_entry_index[id(e)] = e;
869 if (root.hasAttribute(
"previewfile")) {
870 m_previewfiles[e] = root.attribute(
"previewfile");
874 if (root.hasAttribute(
"payloadfile")) {
875 m_payloadfiles[e] = root.attribute(
"payloadfile");
886 void CoreEngine::loadEntriesCache()
892 QStringList cachedirs = d.
findDirs(
"cache",
"knewstuff2-entries.cache/" + m_componentname);
893 if (cachedirs.size() == 0) {
897 QString cachedir = cachedirs.first();
903 for (QStringList::iterator fit = files.begin(); fit != files.end(); ++fit) {
904 QString filepath = cachedir +
'/' + (*fit);
907 Entry *e = loadEntryCache(filepath);
917 void CoreEngine::shutdown()
919 m_entry_index.clear();
920 m_provider_index.clear();
922 qDeleteAll(m_entry_cache);
923 qDeleteAll(m_provider_cache);
925 m_entry_cache.clear();
926 m_provider_cache.clear();
928 delete m_installation;
931 bool CoreEngine::providerCached(
Provider *provider)
933 if (m_cachepolicy ==
CacheNever)
return false;
935 if (m_provider_index.contains(pid(provider)))
944 if (oldfeeds.count() != feeds.count())
946 for (
int i = 0; i < feeds.count(); i++) {
959 for (Provider::List::Iterator it = providers.begin(); it != providers.end(); ++it) {
962 if (providerCached(p)) {
964 Provider *oldprovider = m_provider_index[pid(p)];
965 if (providerChanged(oldprovider, p)) {
966 kDebug() <<
"CACHE: update provider";
987 m_provider_cache.append(p);
988 m_provider_index[pid(p)] = p;
994 bool CoreEngine::entryCached(
Entry *entry)
996 if (m_cachepolicy ==
CacheNever)
return false;
1000 if (m_entry_index.contains(
id(entry)) && m_entry_index[id(entry)]->source() ==
Entry::Cache) {
1013 for (
int i = 0; i < m_entry_cache.count(); i++) {
1014 Entry *oldentry = m_entry_cache.at(i);
1015 if (
id(entry) ==
id(oldentry))
return true;
1026 bool CoreEngine::entryChanged(
Entry *oldentry,
Entry *entry)
1038 for (Entry::List::Iterator it = entries.begin(); it != entries.end(); ++it) {
1045 if (m_entry_registry.contains(thisId)) {
1047 Entry *registryentry = m_entry_registry[thisId];
1050 if (entryChanged(registryentry, e)) {
1058 if (entryCached(e)) {
1060 Entry * cachedentry = m_entry_index[thisId];
1061 if (entryChanged(cachedentry, e)) {
1081 if (entryCached(e)) {
1084 Entry *cachedentry = m_entry_index[thisId];
1085 if (entryChanged(cachedentry, e)) {
1107 m_entry_cache.append(e);
1108 m_entry_index[thisId] = e;
1118 for (
int i = 0; i < feeds.size(); ++i) {
1120 feedname = feeds[i];
1123 cacheFeed(provider, feedname, feed, entries);
1127 if (m_activefeeds == 0) {
1132 void CoreEngine::cacheProvider(
Provider *provider)
1136 kDebug() <<
"Caching provider.";
1139 QString cachefile = cachedir + m_componentname +
"kns2providers.cache.xml";
1141 kDebug() <<
" + Save to file '" + cachefile +
"'.";
1144 QDomElement root = doc.createElement(
"ghnsproviders");
1146 for (Provider::List::Iterator it = m_provider_cache.begin(); it != m_provider_cache.end(); ++it) {
1149 QDomElement pxml = ph.providerXML();
1150 root.appendChild(pxml);
1153 QDomElement pxml = ph.providerXML();
1154 root.appendChild(pxml);
1157 if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
1158 kError() <<
"Cannot write meta information to '" << cachedir <<
"'." << endl;
1162 QTextStream metastream(&f);
1182 QString idbase64 =
QString(pid(provider).toUtf8().toBase64() +
'-' + feedname);
1183 QString cachefile = idbase64 +
".xml";
1185 kDebug() <<
"Caching feed to file '" + cachefile +
"'.";
1188 QDomElement root = doc.createElement(
"ghnsfeeds");
1189 for (
int i = 0; i < entries.count(); i++) {
1190 QString idbase64 = id(entries.at(i)).toUtf8().toBase64();
1191 QDomElement entryel = doc.createElement(
"entry-id");
1192 root.appendChild(entryel);
1193 QDomText entrytext = doc.createTextNode(idbase64);
1194 entryel.appendChild(entrytext);
1197 QFile f(cachedir + cachefile);
1198 if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
1199 kError() <<
"Cannot write meta information to '" << cachedir + cachefile <<
"'." << endl;
1203 QTextStream metastream(&f);
1208 void CoreEngine::cacheEntry(
Entry *entry)
1214 kDebug() <<
"Caching entry in directory '" + cachedir +
"'.";
1219 QString cachefile = idbase64 +
".meta";
1221 kDebug() <<
"Caching to file '" + cachefile +
"'.";
1227 QDomElement exml = eh.entryXML();
1230 QDomElement root = doc.createElement(
"ghnscache");
1231 root.appendChild(exml);
1233 if (m_previewfiles.contains(entry)) {
1234 root.setAttribute(
"previewfile", m_previewfiles[entry]);
1240 QFile f(cachedir + cachefile);
1241 if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
1242 kError() <<
"Cannot write meta information to '" << cachedir + cachefile <<
"'." << endl;
1246 QTextStream metastream(&f);
1251 void CoreEngine::registerEntry(
Entry *entry)
1253 m_entry_registry.insert(
id(entry), entry);
1264 QString registryfile =
QString(
id(entry).toUtf8().toBase64()) +
".meta";
1269 QDomElement exml = eh.entryXML();
1272 QDomElement root = doc.createElement(
"ghnsinstall");
1273 root.appendChild(exml);
1275 if (m_payloadfiles.contains(entry)) {
1276 root.setAttribute(
"payloadfile", m_payloadfiles[entry]);
1279 QFile f(registrydir + registryfile);
1280 if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
1281 kError() <<
"Cannot write meta information to '" << registrydir + registryfile <<
"'." << endl;
1285 QTextStream metastream(&f);
1290 void KNS::CoreEngine::unregisterEntry(
Entry * entry)
1298 QString registryfile =
QString(
id(entry).toUtf8().toBase64()) +
".meta";
1300 QFile::remove(registrydir + registryfile);
1303 m_entry_registry.remove(
id(entry));
1322 for (
int i = 0; i < feeds.count(); i++) {
1323 QString feedtype = feeds.at(i);
1330 return m_componentname;
1335 QList<Entry*> entries = m_payloadfiles.keys(payloadfile);
1336 if (entries.size() != 1) {
1338 kError() <<
"ASSERT: payloadfile is not associated" << endl;
1341 Entry *entry = entries.first();
1356 kError() <<
"Checksum verification not possible" << endl;
1368 kError() <<
"Signature verification not possible" << endl;
1386 QString installpath(payloadfile);
1391 int pathcounter = 0;
1400 if (!m_installation->
targetDir().isEmpty()) {
1409 #if defined(Q_WS_WIN)
1411 WCHAR wPath[MAX_PATH+1];
1412 if ( SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wPath) == S_OK) {
1413 installdir = QString::fromUtf16((
const ushort *) wPath) + QLatin1Char(
'/') + m_installation->
installPath() + QLatin1Char(
'/');
1416 installdir = QDir::home().path() + QLatin1Char(
'/') + m_installation->
installPath() + QLatin1Char(
'/');
1421 installdir = QDir::home().path() +
'/' + m_installation->
installPath() +
'/';
1429 if (pathcounter != 1) {
1430 kError() <<
"Wrong number of installation directories given." << endl;
1434 kDebug() <<
"installdir: " << installdir;
1435 bool isarchive =
true;
1440 installpath = installdir;
1448 if (mimeType->name() ==
"application/zip") {
1449 archive =
new KZip(payloadfile);
1450 }
else if (mimeType->name() ==
"application/tar"
1451 || mimeType->name() ==
"application/x-gzip"
1452 || mimeType->name() ==
"application/x-bzip"
1453 || mimeType->name() ==
"application/x-lzma"
1454 || mimeType->name() ==
"application/x-xz") {
1455 archive =
new KTar(payloadfile);
1458 kError() <<
"Could not determine type of archive file '" << payloadfile <<
"'";
1466 bool success = archive->
open(QIODevice::ReadOnly);
1468 kError() <<
"Cannot open archive file '" << payloadfile <<
"'";
1480 installedFiles << archiveEntries(installdir, dir);
1481 installedFiles << installdir +
'/';
1484 QFile::remove(payloadfile);
1490 kDebug() <<
"isarchive: " << isarchive;
1498 kDebug() <<
"installing non-archive from " << source.
url();
1503 installfile +=
'-' + entry->
version();
1504 if (!ext.isEmpty()) installfile +=
'.' + ext;
1508 installpath = installdir +
'/' + installfile;
1516 QFile file(payloadfile);
1517 bool success =
true;
1519 if (QFile::exists(installpath) && update) {
1520 success = QFile::remove(installpath);
1523 success = file.rename(installpath);
1526 kError() <<
"Cannot move file '" << payloadfile <<
"' to destination '" << installpath <<
"'";
1529 installedFiles << installpath;
1530 installedFiles << installdir +
'/';
1536 if (!m_installation->
command().isEmpty()) {
1540 command.replace(
"%f", fileArg);
1546 int exitcode = process.
execute();
1549 kError() <<
"Command failed" << endl;
1561 SIGNAL(validityResult(
int)),
1562 SLOT(slotInstallationVerification(
int)));
1567 m_payloadfiles[entry] = installpath;
1568 registerEntry(entry);
1584 QFileInfo info(file);
1585 if (info.isFile()) {
1588 command.replace(
"%f", fileArg);
1591 int exitcode = process.
execute();
1594 kError() <<
"Command failed" << endl;
1603 if (file.endsWith(
'/')) {
1605 bool worked = dir.rmdir(file);
1611 if (QFile::exists(file)) {
1612 bool worked = QFile::remove(file);
1614 kWarning() <<
"unable to delete file " << file;
1618 kWarning() <<
"unable to delete file " << file <<
". file does not exist.";
1624 unregisterEntry(entry);
1631 void CoreEngine::slotInstallationVerification(
int result)
1643 m_automationpolicy = policy;
1648 m_cachepolicy = policy;
1655 QString childPath = path +
'/' + entry;
1662 files << archiveEntries(childPath, childDir);
1663 files << childPath +
'/';
1670 #include "coreengine.moc"