• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KNewStuff

  • knewstuff
  • knewstuff2
  • core
coreengine.cpp
Go to the documentation of this file.
1/*
2 This file is part of KNewStuff2.
3 Copyright (c) 2007 Josef Spillner <spillner@kde.org>
4 Copyright 2007 Frederik Gladhorn <frederik.gladhorn@kdemail.net>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#include "coreengine.h"
21
22#include "entryhandler.h"
23#include "providerhandler.h"
24#include "entryloader.h"
25#include "providerloader.h"
26#include "installation.h"
27#include "security.h"
28
29#include <kaboutdata.h>
30#include <kconfig.h>
31#include <kconfiggroup.h>
32#include <kcomponentdata.h>
33#include <kdebug.h>
34#include <kstandarddirs.h>
35#include <kcodecs.h>
36#include <kprocess.h>
37#include <kshell.h>
38
39#include <kio/job.h>
40#include <kmimetype.h>
41#include <krandom.h>
42#include <ktar.h>
43#include <kzip.h>
44
45#include <QtCore/QDir>
46#include <QtXml/qdom.h>
47#include <QtCore/Q_PID>
48
49#if defined(Q_OS_WIN)
50#include <windows.h>
51#define _WIN32_IE 0x0500
52#include <shlobj.h>
53#endif
54
55using namespace KNS;
56
57CoreEngine::CoreEngine(QObject* parent)
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)
60{
61}
62
63CoreEngine::~CoreEngine()
64{
65 shutdown();
66}
67
68bool CoreEngine::init(const QString &configfile)
69{
70 kDebug() << "Initializing KNS::CoreEngine from '" << configfile << "'";
71
72 KConfig conf(configfile);
73 if (conf.accessMode() == KConfig::NoAccess) {
74 kError() << "No knsrc file named '" << configfile << "' was found." << endl;
75 return false;
76 }
77 // FIXME: accessMode() doesn't return NoAccess for non-existing files
78 // - bug in kdecore?
79 // - this needs to be looked at again until KConfig backend changes for KDE 4
80 // the check below is a workaround
81 if (KStandardDirs::locate("config", configfile).isEmpty()) {
82 kError() << "No knsrc file named '" << configfile << "' was found." << endl;
83 return false;
84 }
85
86 if (!conf.hasGroup("KNewStuff2")) {
87 kError() << "A knsrc file was found but it doesn't contain a KNewStuff2 section." << endl;
88 return false;
89 }
90
91 KConfigGroup group = conf.group("KNewStuff2");
92 m_providersurl = group.readEntry("ProvidersUrl", QString());
93 //m_componentname = group.readEntry("ComponentName", QString());
94 m_componentname = QFileInfo(KStandardDirs::locate("config", configfile)).baseName() + ':';
95
96 // FIXME: add support for several categories later on
97 // FIXME: read out only when actually installing as a performance improvement?
98 m_installation = new Installation();
99 QString uncompresssetting = group.readEntry("Uncompress", QString("never"));
100 // support old value of true as equivalent of always
101 if (uncompresssetting == "true") {
102 uncompresssetting = "always";
103 }
104 if (uncompresssetting != "always" && uncompresssetting != "archive" && uncompresssetting != "never") {
105 kError() << "invalid Uncompress setting chosen, must be one of: always, archive, or never" << endl;
106 return false;
107 }
108 m_installation->setUncompression(uncompresssetting);
109
110 m_installation->setCommand(group.readEntry("InstallationCommand", QString()));
111 m_installation->setUninstallCommand(group.readEntry("UninstallCommand", QString()));
112 m_installation->setStandardResourceDir(group.readEntry("StandardResource", QString()));
113 m_installation->setTargetDir(group.readEntry("TargetDir", QString()));
114 m_installation->setInstallPath(group.readEntry("InstallPath", QString()));
115 m_installation->setAbsoluteInstallPath(group.readEntry("AbsoluteInstallPath", QString()));
116 m_installation->setCustomName(group.readEntry("CustomName", false));
117
118 QString checksumpolicy = group.readEntry("ChecksumPolicy", QString());
119 if (!checksumpolicy.isEmpty()) {
120 if (checksumpolicy == "never")
121 m_installation->setChecksumPolicy(Installation::CheckNever);
122 else if (checksumpolicy == "ifpossible")
123 m_installation->setChecksumPolicy(Installation::CheckIfPossible);
124 else if (checksumpolicy == "always")
125 m_installation->setChecksumPolicy(Installation::CheckAlways);
126 else {
127 kError() << "The checksum policy '" + checksumpolicy + "' is unknown." << endl;
128 return false;
129 }
130 }
131
132 QString signaturepolicy = group.readEntry("SignaturePolicy", QString());
133 if (!signaturepolicy.isEmpty()) {
134 if (signaturepolicy == "never")
135 m_installation->setSignaturePolicy(Installation::CheckNever);
136 else if (signaturepolicy == "ifpossible")
137 m_installation->setSignaturePolicy(Installation::CheckIfPossible);
138 else if (signaturepolicy == "always")
139 m_installation->setSignaturePolicy(Installation::CheckAlways);
140 else {
141 kError() << "The signature policy '" + signaturepolicy + "' is unknown." << endl;
142 return false;
143 }
144 }
145
146 QString scope = group.readEntry("Scope", QString());
147 if (!scope.isEmpty()) {
148 if (scope == "user")
149 m_installation->setScope(Installation::ScopeUser);
150 else if (scope == "system")
151 m_installation->setScope(Installation::ScopeSystem);
152 else {
153 kError() << "The scope '" + scope + "' is unknown." << endl;
154 return false;
155 }
156
157 if (m_installation->scope() == Installation::ScopeSystem) {
158 if (!m_installation->installPath().isEmpty()) {
159 kError() << "System installation cannot be mixed with InstallPath." << endl;
160 return false;
161 }
162 }
163 }
164
165 QString cachePolicy = group.readEntry("CachePolicy", QString());
166 if (!cachePolicy.isEmpty()) {
167 if (cachePolicy == "never") {
168 m_cachepolicy = CacheNever;
169 } else if (cachePolicy == "replaceable") {
170 m_cachepolicy = CacheReplaceable;
171 } else if (cachePolicy == "resident") {
172 m_cachepolicy = CacheResident;
173 } else if (cachePolicy == "only") {
174 m_cachepolicy = CacheOnly;
175 } else {
176 kError() << "Cache policy '" + cachePolicy + "' is unknown." << endl;
177 }
178 }
179 kDebug() << "cache policy: " << cachePolicy;
180
181 m_initialized = true;
182
183 return true;
184}
185
186QString CoreEngine::componentName() const
187{
188 if (!m_initialized) {
189 return QString();
190 }
191
192 return m_componentname;
193}
194
195void CoreEngine::start()
196{
197 //kDebug() << "starting engine";
198
199 if (!m_initialized) {
200 kError() << "Must call KNS::CoreEngine::init() first." << endl;
201 return;
202 }
203
204 // first load the registry, so we know which entries are installed
205 loadRegistry();
206
207 // then load the providersCache if caching is enabled
208 if (m_cachepolicy != CacheNever) {
209 loadProvidersCache();
210 }
211
212 // FIXME: also return if CacheResident and its conditions fulfilled
213 if (m_cachepolicy == CacheOnly) {
214 //emit signalEntriesFinished();
215 return;
216 }
217
218 ProviderLoader *provider_loader = new ProviderLoader(this);
219
220 // make connections before loading, just in case the iojob is very fast
221 connect(provider_loader,
222 SIGNAL(signalProvidersLoaded(KNS::Provider::List)),
223 SLOT(slotProvidersLoaded(KNS::Provider::List)));
224 connect(provider_loader,
225 SIGNAL(signalProvidersFailed()),
226 SLOT(slotProvidersFailed()));
227
228 provider_loader->load(m_providersurl);
229}
230
231void CoreEngine::loadEntries(Provider *provider)
232{
233 //kDebug() << "loading entries";
234
235 if (m_cachepolicy == CacheOnly) {
236 return;
237 }
238
239 //if (provider != m_provider_index[pid(provider)]) {
240 // // this is the cached provider, and a new provider has been loaded from the internet
241 // // also, this provider's feeds have already been loaded including it's entries
242 // m_provider_cache.removeAll(provider); // just in case it's still in there
243 // return;
244 //}
245
246 QStringList feeds = provider->feeds();
247 for (int i = 0; i < feeds.count(); i++) {
248 Feed *feed = provider->downloadUrlFeed(feeds.at(i));
249 if (feed) {
250 ++m_activefeeds;
251
252 EntryLoader *entry_loader = new EntryLoader(this);
253
254 connect(entry_loader,
255 SIGNAL(signalEntriesLoaded(KNS::Entry::List)),
256 SLOT(slotEntriesLoaded(KNS::Entry::List)));
257 connect(entry_loader,
258 SIGNAL(signalEntriesFailed()),
259 SLOT(slotEntriesFailed()));
260 connect(entry_loader,
261 SIGNAL(signalProgress(KJob*,ulong)),
262 SLOT(slotProgress(KJob*,ulong)));
263
264 entry_loader->load(provider, feed);
265 }
266 }
267}
268
269void CoreEngine::downloadPreview(Entry *entry)
270{
271 if (m_previewfiles.contains(entry)) {
272 // FIXME: ensure somewhere else that preview file even exists
273 //kDebug() << "Reusing preview from '" << m_previewfiles[entry] << "'";
274 emit signalPreviewLoaded(KUrl::fromPath(m_previewfiles[entry]));
275 return;
276 }
277
278 KUrl source = KUrl(entry->preview().representation());
279
280 if (!source.isValid()) {
281 kError() << "The entry doesn't have a preview." << endl;
282 return;
283 }
284
285 KUrl destination = QString(KGlobal::dirs()->saveLocation("tmp") + KRandom::randomString(10));
286 //kDebug() << "Downloading preview '" << source << "' to '" << destination << "'";
287
288 // FIXME: check for validity
289 KIO::FileCopyJob *job = KIO::file_copy(source, destination, -1, KIO::Overwrite | KIO::HideProgressInfo);
290 connect(job,
291 SIGNAL(result(KJob*)),
292 SLOT(slotPreviewResult(KJob*)));
293 connect(job,
294 SIGNAL(progress(KJob*,ulong)),
295 SLOT(slotProgress(KJob*,ulong)));
296
297 m_entry_jobs[job] = entry;
298}
299
300void CoreEngine::downloadPayload(Entry *entry)
301{
302 if(!entry) {
303 emit signalPayloadFailed(entry);
304 return;
305 }
306 KUrl source = KUrl(entry->payload().representation());
307
308 if (!source.isValid()) {
309 kError() << "The entry doesn't have a payload." << endl;
310 emit signalPayloadFailed(entry);
311 return;
312 }
313
314 if (m_installation->isRemote()) {
315 // Remote resource
316 //kDebug() << "Relaying remote payload '" << source << "'";
317 entry->setStatus(Entry::Installed);
318 m_payloadfiles[entry] = entry->payload().representation();
319 install(source.pathOrUrl());
320 emit signalPayloadLoaded(source);
321 // FIXME: we still need registration for eventual deletion
322 return;
323 }
324
325 KUrl destination = QString(KGlobal::dirs()->saveLocation("tmp") + KRandom::randomString(10));
326 kDebug() << "Downloading payload '" << source << "' to '" << destination << "'";
327
328 // FIXME: check for validity
329 KIO::FileCopyJob *job = KIO::file_copy(source, destination, -1, KIO::Overwrite | KIO::HideProgressInfo);
330 connect(job,
331 SIGNAL(result(KJob*)),
332 SLOT(slotPayloadResult(KJob*)));
333 connect(job,
334 SIGNAL(percent(KJob*,ulong)),
335 SLOT(slotProgress(KJob*,ulong)));
336
337 m_entry_jobs[job] = entry;
338}
339
340bool CoreEngine::uploadEntry(Provider *provider, Entry *entry)
341{
342 //kDebug() << "Uploading " << entry->name().representation() << "...";
343
344 if (m_uploadedentry) {
345 kError() << "Another upload is in progress!" << endl;
346 return false;
347 }
348
349 if (!provider->uploadUrl().isValid()) {
350 kError() << "The provider doesn't support uploads." << endl;
351 return false;
352
353 // FIXME: support for <noupload> will go here (file bundle creation etc.)
354 }
355
356 // FIXME: validate files etc.
357 m_uploadprovider = provider;
358 m_uploadedentry = entry;
359
360 KUrl sourcepayload = KUrl(entry->payload().representation());
361 KUrl destfolder = provider->uploadUrl();
362
363 destfolder.setFileName(sourcepayload.fileName());
364
365 KIO::FileCopyJob *fcjob = KIO::file_copy(sourcepayload, destfolder, -1, KIO::Overwrite | KIO::HideProgressInfo);
366 connect(fcjob,
367 SIGNAL(result(KJob*)),
368 SLOT(slotUploadPayloadResult(KJob*)));
369
370 return true;
371}
372
373void CoreEngine::slotProvidersLoaded(KNS::Provider::List list)
374{
375 // note: this is only called from loading the online providers
376 ProviderLoader *loader = dynamic_cast<ProviderLoader*>(sender());
377 delete loader;
378
379 mergeProviders(list);
380}
381
382void CoreEngine::slotProvidersFailed()
383{
384 kDebug() << "slotProvidersFailed";
385 ProviderLoader *loader = dynamic_cast<ProviderLoader*>(sender());
386 delete loader;
387
388 emit signalProvidersFailed();
389}
390
391void CoreEngine::slotEntriesLoaded(KNS::Entry::List list)
392{
393 EntryLoader *loader = dynamic_cast<EntryLoader*>(sender());
394 if (!loader) return;
395 const Provider *provider = loader->provider();
396 Feed *feed = loader->feed();
397 delete loader;
398 m_activefeeds--;
399 //kDebug() << "entriesloaded m_activefeeds: " << m_activefeeds;
400
401 //kDebug() << "Provider source " << provider->name().representation();
402 //kDebug() << "Feed source " << feed->name().representation();
403 //kDebug() << "Feed data: " << feed;
404
405 mergeEntries(list, feed, provider);
406}
407
408void CoreEngine::slotEntriesFailed()
409{
410 EntryLoader *loader = dynamic_cast<EntryLoader*>(sender());
411 delete loader;
412 m_activefeeds--;
413
414 emit signalEntriesFailed();
415}
416
417void CoreEngine::slotProgress(KJob *job, unsigned long percent)
418{
419 QString url;
420 KIO::FileCopyJob * copyJob = qobject_cast<KIO::FileCopyJob*>(job);
421 KIO::TransferJob * transferJob = qobject_cast<KIO::TransferJob*>(job);
422 if (copyJob != NULL) {
423 url = copyJob->srcUrl().fileName();
424 } else if (transferJob != NULL) {
425 url = transferJob->url().fileName();
426 }
427
428 QString message = i18n("loading %1",url);
429 emit signalProgress(message, percent);
430}
431
432void CoreEngine::slotPayloadResult(KJob *job)
433{
434 // for some reason this slot is getting called 3 times on one job error
435 if (m_entry_jobs.contains(job)) {
436 Entry *entry = m_entry_jobs[job];
437 m_entry_jobs.remove(job);
438
439 if (job->error()) {
440 kError() << "Cannot load payload file." << endl;
441 kError() << job->errorString() << endl;
442
443 emit signalPayloadFailed(entry);
444 } else {
445 KIO::FileCopyJob *fcjob = static_cast<KIO::FileCopyJob*>(job);
446 m_payloadfiles[entry] = fcjob->destUrl().path();
447
448 install(fcjob->destUrl().pathOrUrl());
449
450 emit signalPayloadLoaded(fcjob->destUrl());
451 }
452 }
453}
454
455// FIXME: this should be handled more internally to return a (cached) preview image
456void CoreEngine::slotPreviewResult(KJob *job)
457{
458 if (job->error()) {
459 kError() << "Cannot load preview file." << endl;
460 kError() << job->errorString() << endl;
461
462 m_entry_jobs.remove(job);
463 emit signalPreviewFailed();
464 } else {
465 KIO::FileCopyJob *fcjob = static_cast<KIO::FileCopyJob*>(job);
466
467 if (m_entry_jobs.contains(job)) {
468 // now, assign temporary filename to entry and update entry cache
469 Entry *entry = m_entry_jobs[job];
470 m_entry_jobs.remove(job);
471 m_previewfiles[entry] = fcjob->destUrl().path();
472 cacheEntry(entry);
473 }
474 // FIXME: ignore if not? shouldn't happen...
475
476 emit signalPreviewLoaded(fcjob->destUrl());
477 }
478}
479
480void CoreEngine::slotUploadPayloadResult(KJob *job)
481{
482 if (job->error()) {
483 kError() << "Cannot upload payload file." << endl;
484 kError() << job->errorString() << endl;
485
486 m_uploadedentry = NULL;
487 m_uploadprovider = NULL;
488
489 emit signalEntryFailed();
490 return;
491 }
492
493 if (m_uploadedentry->preview().representation().isEmpty()) {
494 // FIXME: we abuse 'job' here for the shortcut if there's no preview
495 slotUploadPreviewResult(job);
496 return;
497 }
498
499 KUrl sourcepreview = KUrl(m_uploadedentry->preview().representation());
500 KUrl destfolder = m_uploadprovider->uploadUrl();
501
502 destfolder.setFileName(sourcepreview.fileName());
503
504 KIO::FileCopyJob *fcjob = KIO::file_copy(sourcepreview, destfolder, -1, KIO::Overwrite | KIO::HideProgressInfo);
505 connect(fcjob,
506 SIGNAL(result(KJob*)),
507 SLOT(slotUploadPreviewResult(KJob*)));
508}
509
510void CoreEngine::slotUploadPreviewResult(KJob *job)
511{
512 if (job->error()) {
513 kError() << "Cannot upload preview file." << endl;
514 kError() << job->errorString() << endl;
515
516 m_uploadedentry = NULL;
517 m_uploadprovider = NULL;
518
519 emit signalEntryFailed();
520 return;
521 }
522
523 // FIXME: the following save code is also in cacheEntry()
524 // when we upload, the entry should probably be cached!
525
526 // FIXME: adhere to meta naming rules as discussed
527 KUrl sourcemeta = QString(KGlobal::dirs()->saveLocation("tmp") + KRandom::randomString(10) + ".meta");
528 KUrl destfolder = m_uploadprovider->uploadUrl();
529
530 destfolder.setFileName(sourcemeta.fileName());
531
532 EntryHandler eh(*m_uploadedentry);
533 QDomElement exml = eh.entryXML();
534
535 QDomDocument doc;
536 QDomElement root = doc.createElement("ghnsupload");
537 root.appendChild(exml);
538
539 QFile f(sourcemeta.path());
540 if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
541 kError() << "Cannot write meta information to '" << sourcemeta << "'." << endl;
542
543 m_uploadedentry = NULL;
544 m_uploadprovider = NULL;
545
546 emit signalEntryFailed();
547 return;
548 }
549 QTextStream metastream(&f);
550 metastream << root;
551 f.close();
552
553 KIO::FileCopyJob *fcjob = KIO::file_copy(sourcemeta, destfolder, -1, KIO::Overwrite | KIO::HideProgressInfo);
554 connect(fcjob,
555 SIGNAL(result(KJob*)),
556 SLOT(slotUploadMetaResult(KJob*)));
557}
558
559void CoreEngine::slotUploadMetaResult(KJob *job)
560{
561 if (job->error()) {
562 kError() << "Cannot upload meta file." << endl;
563 kError() << job->errorString() << endl;
564
565 m_uploadedentry = NULL;
566 m_uploadprovider = NULL;
567
568 emit signalEntryFailed();
569 return;
570 } else {
571 m_uploadedentry = NULL;
572 m_uploadprovider = NULL;
573
574 //KIO::FileCopyJob *fcjob = static_cast<KIO::FileCopyJob*>(job);
575 emit signalEntryUploaded();
576 }
577}
578
579void CoreEngine::loadRegistry()
580{
581 KStandardDirs d;
582
583 //kDebug() << "Loading registry of files for the component: " << m_componentname;
584
585 QString realAppName = m_componentname.split(':')[0];
586
587 // this must be same as in registerEntry()
588 const QStringList dirs = d.findDirs("data", "knewstuff2-entries.registry");
589 for (QStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it) {
590 //kDebug() << " + Load from directory '" + (*it) + "'.";
591 QDir dir((*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);
595 //kDebug() << " + Load from file '" + filepath + "'.";
596
597 bool ret;
598 QFileInfo info(filepath);
599 QFile f(filepath);
600
601 // first see if this file is even for this app
602 // because the registry contains entries for all apps
603 // FIXMEE: should be able to do this with a filter on the entryList above probably
604 QString thisAppName = QString::fromUtf8(QByteArray::fromBase64(info.baseName().toUtf8()));
605
606 // NOTE: the ":" needs to always coincide with the separator character used in
607 // the id(Entry*) method
608 thisAppName = thisAppName.split(':')[0];
609
610 if (thisAppName != realAppName) {
611 continue;
612 }
613
614 ret = f.open(QIODevice::ReadOnly);
615 if (!ret) {
616 kWarning() << "The file could not be opened.";
617 continue;
618 }
619
620 QDomDocument doc;
621 ret = doc.setContent(&f);
622 if (!ret) {
623 kWarning() << "The file could not be parsed.";
624 continue;
625 }
626
627 QDomElement root = doc.documentElement();
628 if (root.tagName() != "ghnsinstall") {
629 kWarning() << "The file doesn't seem to be of interest.";
630 continue;
631 }
632
633 QDomElement stuff = root.firstChildElement("stuff");
634 if (stuff.isNull()) {
635 kWarning() << "Missing GHNS installation metadata.";
636 continue;
637 }
638
639 EntryHandler handler(stuff);
640 if (!handler.isValid()) {
641 kWarning() << "Invalid GHNS installation metadata.";
642 continue;
643 }
644
645 Entry *e = handler.entryptr();
646 e->setStatus(Entry::Installed);
647 e->setSource(Entry::Registry);
648 m_entry_registry.insert(id(e), e);
649 //QString thisid = id(e);
650
651 // we must overwrite cache entries with registered entries
652 // and not just append the latter ones
653 //if (entryCached(e)) {
654 // // it's in the cache, so replace the cache entry with the registered entry
655 // Entry * oldEntry = m_entry_index[thisid];
656 // int index = m_entry_cache.indexOf(oldEntry);
657 // m_entry_cache[index] = e;
658 // //delete oldEntry;
659 //}
660 //else {
661 // m_entry_cache.append(e);
662 //}
663 //m_entry_index[thisid] = e;
664 }
665 }
666}
667
668void CoreEngine::loadProvidersCache()
669{
670 KStandardDirs d;
671
672 // use the componentname so we get the cache specific to this knsrc (kanagram, wallpaper, etc.)
673 QString cachefile = d.findResource("cache", m_componentname + "kns2providers.cache.xml");
674 if (cachefile.isEmpty()) {
675 kDebug() << "Cache not present, skip loading.";
676 return;
677 }
678
679 kDebug() << "Loading provider cache from file '" + cachefile + "'.";
680
681 // make sure we can open and read the file
682 bool ret;
683 QFile f(cachefile);
684 ret = f.open(QIODevice::ReadOnly);
685 if (!ret) {
686 kWarning() << "The file could not be opened.";
687 return;
688 }
689
690 // make sure it's valid xml
691 QDomDocument doc;
692 ret = doc.setContent(&f);
693 if (!ret) {
694 kWarning() << "The file could not be parsed.";
695 return;
696 }
697
698 // make sure there's a root tag
699 QDomElement root = doc.documentElement();
700 if (root.tagName() != "ghnsproviders") {
701 kWarning() << "The file doesn't seem to be of interest.";
702 return;
703 }
704
705 // get the first provider
706 QDomElement provider = root.firstChildElement("provider");
707 if (provider.isNull()) {
708 kWarning() << "Missing provider entries in the cache.";
709 return;
710 }
711
712 // handle each provider
713 while (!provider.isNull()) {
714 ProviderHandler handler(provider);
715 if (!handler.isValid()) {
716 kWarning() << "Invalid provider metadata.";
717 continue;
718 }
719
720 Provider *p = handler.providerptr();
721 m_provider_cache.append(p);
722 m_provider_index[pid(p)] = p;
723
724 emit signalProviderLoaded(p);
725
726 loadFeedCache(p);
727
728 // no longer needed because EnginePrivate::slotProviderLoaded calls loadEntries
729 //if (m_automationpolicy == AutomationOn) {
730 // loadEntries(p);
731 //}
732
733 provider = provider.nextSiblingElement("provider");
734 }
735
736 if (m_cachepolicy == CacheOnly) {
737 emit signalEntriesFinished();
738 }
739}
740
741void CoreEngine::loadFeedCache(Provider *provider)
742{
743 KStandardDirs d;
744
745 kDebug() << "Loading feed cache.";
746
747 QStringList cachedirs = d.findDirs("cache", m_componentname + "kns2feeds.cache");
748 if (cachedirs.size() == 0) {
749 kDebug() << "Cache directory not present, skip loading.";
750 return;
751 }
752 QString cachedir = cachedirs.first();
753
754 QStringList entrycachedirs = d.findDirs("cache", "knewstuff2-entries.cache/");
755 if (entrycachedirs.size() == 0) {
756 kDebug() << "Cache directory not present, skip loading.";
757 return;
758 }
759 QString entrycachedir = entrycachedirs.first();
760
761 kDebug() << "Load from directory: " + cachedir;
762
763 QStringList feeds = provider->feeds();
764 for (int i = 0; i < feeds.count(); i++) {
765 Feed *feed = provider->downloadUrlFeed(feeds.at(i));
766 QString feedname = feeds.at(i);
767
768 QString idbase64 = QString(pid(provider).toUtf8().toBase64() + '-' + feedname);
769 QString cachefile = cachedir + '/' + idbase64 + ".xml";
770
771 kDebug() << " + Load from file: " + cachefile;
772
773 bool ret;
774 QFile f(cachefile);
775 ret = f.open(QIODevice::ReadOnly);
776 if (!ret) {
777 kWarning() << "The file could not be opened.";
778 return;
779 }
780
781 QDomDocument doc;
782 ret = doc.setContent(&f);
783 if (!ret) {
784 kWarning() << "The file could not be parsed.";
785 return;
786 }
787
788 QDomElement root = doc.documentElement();
789 if (root.tagName() != "ghnsfeeds") {
790 kWarning() << "The file doesn't seem to be of interest.";
791 return;
792 }
793
794 QDomElement entryel = root.firstChildElement("entry-id");
795 if (entryel.isNull()) {
796 kWarning() << "Missing entries in the cache.";
797 return;
798 }
799
800 while (!entryel.isNull()) {
801 QString idbase64 = entryel.text();
802 //kDebug() << "loading cache for entry: " << QByteArray::fromBase64(idbase64.toUtf8());
803
804 QString filepath = entrycachedir + '/' + idbase64 + ".meta";
805
806 //kDebug() << "from file '" + filepath + "'.";
807
808 // FIXME: pass feed and make loadEntryCache return void for consistency?
809 Entry *entry = loadEntryCache(filepath);
810 if (entry) {
811 QString entryid = id(entry);
812
813 if (m_entry_registry.contains(entryid)) {
814 Entry * registryEntry = m_entry_registry.value(entryid);
815 entry->setStatus(registryEntry->status());
816 entry->setInstalledFiles(registryEntry->installedFiles());
817 }
818
819 feed->addEntry(entry);
820 //kDebug() << "entry " << entry->name().representation() << " loaded from cache";
821 emit signalEntryLoaded(entry, feed, provider);
822 }
823
824 entryel = entryel.nextSiblingElement("entry-id");
825 }
826 }
827}
828
829KNS::Entry *CoreEngine::loadEntryCache(const QString& filepath)
830{
831 bool ret;
832 QFile f(filepath);
833 ret = f.open(QIODevice::ReadOnly);
834 if (!ret) {
835 kWarning() << "The file " << filepath << " could not be opened.";
836 return NULL;
837 }
838
839 QDomDocument doc;
840 ret = doc.setContent(&f);
841 if (!ret) {
842 kWarning() << "The file could not be parsed.";
843 return NULL;
844 }
845
846 QDomElement root = doc.documentElement();
847 if (root.tagName() != "ghnscache") {
848 kWarning() << "The file doesn't seem to be of interest.";
849 return NULL;
850 }
851
852 QDomElement stuff = root.firstChildElement("stuff");
853 if (stuff.isNull()) {
854 kWarning() << "Missing GHNS cache metadata.";
855 return NULL;
856 }
857
858 EntryHandler handler(stuff);
859 if (!handler.isValid()) {
860 kWarning() << "Invalid GHNS installation metadata.";
861 return NULL;
862 }
863
864 Entry *e = handler.entryptr();
865 e->setStatus(Entry::Downloadable);
866 m_entry_cache.append(e);
867 m_entry_index[id(e)] = e;
868
869 if (root.hasAttribute("previewfile")) {
870 m_previewfiles[e] = root.attribute("previewfile");
871 // FIXME: check here for a [ -f previewfile ]
872 }
873
874 if (root.hasAttribute("payloadfile")) {
875 m_payloadfiles[e] = root.attribute("payloadfile");
876 // FIXME: check here for a [ -f payloadfile ]
877 }
878
879 e->setSource(Entry::Cache);
880
881 return e;
882}
883
884// FIXME: not needed anymore?
885#if 0
886void CoreEngine::loadEntriesCache()
887{
888 KStandardDirs d;
889
890 //kDebug() << "Loading entry cache.";
891
892 QStringList cachedirs = d.findDirs("cache", "knewstuff2-entries.cache/" + m_componentname);
893 if (cachedirs.size() == 0) {
894 //kDebug() << "Cache directory not present, skip loading.";
895 return;
896 }
897 QString cachedir = cachedirs.first();
898
899 //kDebug() << " + Load from directory '" + cachedir + "'.";
900
901 QDir dir(cachedir);
902 QStringList files = dir.entryList(QDir::Files | QDir::Readable);
903 for (QStringList::iterator fit = files.begin(); fit != files.end(); ++fit) {
904 QString filepath = cachedir + '/' + (*fit);
905 //kDebug() << " + Load from file '" + filepath + "'.";
906
907 Entry *e = loadEntryCache(filepath);
908
909 if (e) {
910 // FIXME: load provider/feed information first
911 emit signalEntryLoaded(e, NULL, NULL);
912 }
913 }
914}
915#endif
916
917void CoreEngine::shutdown()
918{
919 m_entry_index.clear();
920 m_provider_index.clear();
921
922 qDeleteAll(m_entry_cache);
923 qDeleteAll(m_provider_cache);
924
925 m_entry_cache.clear();
926 m_provider_cache.clear();
927
928 delete m_installation;
929}
930
931bool CoreEngine::providerCached(Provider *provider)
932{
933 if (m_cachepolicy == CacheNever) return false;
934
935 if (m_provider_index.contains(pid(provider)))
936 return true;
937 return false;
938}
939
940bool CoreEngine::providerChanged(Provider *oldprovider, Provider *provider)
941{
942 QStringList oldfeeds = oldprovider->feeds();
943 QStringList feeds = provider->feeds();
944 if (oldfeeds.count() != feeds.count())
945 return true;
946 for (int i = 0; i < feeds.count(); i++) {
947 Feed *oldfeed = oldprovider->downloadUrlFeed(feeds.at(i));
948 Feed *feed = provider->downloadUrlFeed(feeds.at(i));
949 if (!oldfeed)
950 return true;
951 if (feed->feedUrl() != oldfeed->feedUrl())
952 return true;
953 }
954 return false;
955}
956
957void CoreEngine::mergeProviders(Provider::List providers)
958{
959 for (Provider::List::Iterator it = providers.begin(); it != providers.end(); ++it) {
960 Provider *p = (*it);
961
962 if (providerCached(p)) {
963 kDebug() << "CACHE: hit provider " << p->name().representation();
964 Provider *oldprovider = m_provider_index[pid(p)];
965 if (providerChanged(oldprovider, p)) {
966 kDebug() << "CACHE: update provider";
967 cacheProvider(p);
968 emit signalProviderChanged(p);
969 }
970 // oldprovider can now be deleted, see entry hit case
971 // also take it out of m_provider_cache and m_provider_index
972 //m_provider_cache.removeAll(oldprovider);
973 //delete oldprovider;
974 } else {
975 if (m_cachepolicy != CacheNever) {
976 kDebug() << "CACHE: miss provider " << p->name().representation();
977 cacheProvider(p);
978 }
979 emit signalProviderLoaded(p);
980
981 // no longer needed, because slotProviderLoaded calls loadEntries()
982 //if (m_automationpolicy == AutomationOn) {
983 // loadEntries(p);
984 //}
985 }
986
987 m_provider_cache.append(p);
988 m_provider_index[pid(p)] = p;
989 }
990
991 emit signalProvidersFinished();
992}
993
994bool CoreEngine::entryCached(Entry *entry)
995{
996 if (m_cachepolicy == CacheNever) return false;
997
998 // Direct cache lookup first
999 // FIXME: probably better use URL (changes less frequently) and do iteration
1000 if (m_entry_index.contains(id(entry)) && m_entry_index[id(entry)]->source() == Entry::Cache) {
1001 return true;
1002 }
1003
1004 // If entry wasn't found, either
1005 // - a translation was added which matches our locale better, or
1006 // - our locale preferences changed, or both.
1007 // In that case we've got to find the old name in the new entry,
1008 // since we assume that translations are always added but never removed.
1009
1010 // BIGFIXME: the code below is incomplete, if we are looking for a translation
1011 // id(entry) will not work, as it uses the current locale to get the id
1012
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;
1016 //QString lang = id(oldentry).section(":", 0, 0);
1017 //QString oldname = oldentry->name().translated(lang);
1018 //QString name = entry->name().translated(lang);
1020 //if (name == oldname) return true;
1021 }
1022
1023 return false;
1024}
1025
1026bool CoreEngine::entryChanged(Entry *oldentry, Entry *entry)
1027{
1028 // possibly return true if the status changed? depends on when this is called
1029 if ((!oldentry) || (entry->releaseDate() > oldentry->releaseDate())
1030 || (entry->version() > oldentry->version())
1031 || (entry->release() > oldentry->release()))
1032 return true;
1033 return false;
1034}
1035
1036void CoreEngine::mergeEntries(Entry::List entries, Feed *feed, const Provider *provider)
1037{
1038 for (Entry::List::Iterator it = entries.begin(); it != entries.end(); ++it) {
1039 // TODO: find entry in entrycache, replace if needed
1040 // don't forget marking as 'updateable'
1041 Entry *e = (*it);
1042 QString thisId = id(e);
1043 // set it to Installed if it's in the registry
1044
1045 if (m_entry_registry.contains(thisId)) {
1046 // see if the one online is newer (higher version, release, or release date)
1047 Entry *registryentry = m_entry_registry[thisId];
1048 e->setInstalledFiles(registryentry->installedFiles());
1049
1050 if (entryChanged(registryentry, e)) {
1051 e->setStatus(Entry::Updateable);
1052 emit signalEntryChanged(e);
1053 } else {
1054 // it hasn't changed, so set the status to that of the registry entry
1055 e->setStatus(registryentry->status());
1056 }
1057
1058 if (entryCached(e)) {
1059 // in the registry and the cache, so take the cached one out
1060 Entry * cachedentry = m_entry_index[thisId];
1061 if (entryChanged(cachedentry, e)) {
1062 //kDebug() << "CACHE: update entry";
1063 cachedentry->setStatus(Entry::Updateable);
1064 // entry has changed
1065 if (m_cachepolicy != CacheNever) {
1066 cacheEntry(e);
1067 }
1068 emit signalEntryChanged(e);
1069 }
1070
1071 // take cachedentry out of the feed
1072 feed->removeEntry(cachedentry);
1073 //emit signalEntryRemoved(cachedentry, feed);
1074 } else {
1075 emit signalEntryLoaded(e, feed, provider);
1076 }
1077
1078 } else {
1079 e->setStatus(Entry::Downloadable);
1080
1081 if (entryCached(e)) {
1082 //kDebug() << "CACHE: hit entry " << e->name().representation();
1083 // FIXME: separate version updates from server-side translation updates?
1084 Entry *cachedentry = m_entry_index[thisId];
1085 if (entryChanged(cachedentry, e)) {
1086 //kDebug() << "CACHE: update entry";
1087 e->setStatus(Entry::Updateable);
1088 // entry has changed
1089 if (m_cachepolicy != CacheNever) {
1090 cacheEntry(e);
1091 }
1092 emit signalEntryChanged(e);
1093 // FIXME: cachedentry can now be deleted, but it's still in the list!
1094 // FIXME: better: assigne all values to 'e', keeps refs intact
1095 }
1096 // take cachedentry out of the feed
1097 feed->removeEntry(cachedentry);
1098 //emit signalEntryRemoved(cachedentry, feed);
1099 } else {
1100 if (m_cachepolicy != CacheNever) {
1101 //kDebug() << "CACHE: miss entry " << e->name().representation();
1102 cacheEntry(e);
1103 }
1104 emit signalEntryLoaded(e, feed, provider);
1105 }
1106
1107 m_entry_cache.append(e);
1108 m_entry_index[thisId] = e;
1109 }
1110 }
1111
1112 if (m_cachepolicy != CacheNever) {
1113 // extra code to get the feedname from the provider, we could use feed->name().representation()
1114 // but would need to remove spaces, and latinize it since it can be any encoding
1115 // besides feeds.size() has a max of 4 currently (unsorted, score, downloads, and latest)
1116 QStringList feeds = provider->feeds();
1117 QString feedname;
1118 for (int i = 0; i < feeds.size(); ++i) {
1119 if (provider->downloadUrlFeed(feeds[i]) == feed) {
1120 feedname = feeds[i];
1121 }
1122 }
1123 cacheFeed(provider, feedname, feed, entries);
1124 }
1125
1126 emit signalEntriesFeedFinished(feed);
1127 if (m_activefeeds == 0) {
1128 emit signalEntriesFinished();
1129 }
1130}
1131
1132void CoreEngine::cacheProvider(Provider *provider)
1133{
1134 KStandardDirs d;
1135
1136 kDebug() << "Caching provider.";
1137
1138 QString cachedir = d.saveLocation("cache");
1139 QString cachefile = cachedir + m_componentname + "kns2providers.cache.xml";
1140
1141 kDebug() << " + Save to file '" + cachefile + "'.";
1142
1143 QDomDocument doc;
1144 QDomElement root = doc.createElement("ghnsproviders");
1145
1146 for (Provider::List::Iterator it = m_provider_cache.begin(); it != m_provider_cache.end(); ++it) {
1147 Provider *p = (*it);
1148 ProviderHandler ph(*p);
1149 QDomElement pxml = ph.providerXML();
1150 root.appendChild(pxml);
1151 }
1152 ProviderHandler ph(*provider);
1153 QDomElement pxml = ph.providerXML();
1154 root.appendChild(pxml);
1155
1156 QFile f(cachefile);
1157 if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
1158 kError() << "Cannot write meta information to '" << cachedir << "'." << endl;
1159 // FIXME: ignore?
1160 return;
1161 }
1162 QTextStream metastream(&f);
1163 metastream << root;
1164 f.close();
1165
1166 /*QStringList feeds = p->feeds();
1167 for(int i = 0; i < feeds.count(); i++) {
1168 Feed *feed = p->downloadUrlFeed(feeds.at(i));
1169 cacheFeed(p, feeds.at(i), feed);
1170 }*/
1171}
1172
1173void CoreEngine::cacheFeed(const Provider *provider, const QString & feedname, const Feed *feed, Entry::List entries)
1174{
1175 // feed cache file is a list of entry-id's that are part of this feed
1176 KStandardDirs d;
1177
1178 Q_UNUSED(feed);
1179
1180 QString cachedir = d.saveLocation("cache", m_componentname + "kns2feeds.cache");
1181
1182 QString idbase64 = QString(pid(provider).toUtf8().toBase64() + '-' + feedname);
1183 QString cachefile = idbase64 + ".xml";
1184
1185 kDebug() << "Caching feed to file '" + cachefile + "'.";
1186
1187 QDomDocument doc;
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);
1195 }
1196
1197 QFile f(cachedir + cachefile);
1198 if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
1199 kError() << "Cannot write meta information to '" << cachedir + cachefile << "'." << endl;
1200 // FIXME: ignore?
1201 return;
1202 }
1203 QTextStream metastream(&f);
1204 metastream << root;
1205 f.close();
1206}
1207
1208void CoreEngine::cacheEntry(Entry *entry)
1209{
1210 KStandardDirs d;
1211
1212 QString cachedir = d.saveLocation("cache", "knewstuff2-entries.cache/");
1213
1214 kDebug() << "Caching entry in directory '" + cachedir + "'.";
1215
1216 //FIXME: this must be deterministic, but it could also be an OOB random string
1217 //which gets stored into <ghnscache> just like preview...
1218 QString idbase64 = QString(id(entry).toUtf8().toBase64());
1219 QString cachefile = idbase64 + ".meta";
1220
1221 kDebug() << "Caching to file '" + cachefile + "'.";
1222
1223 // FIXME: adhere to meta naming rules as discussed
1224 // FIXME: maybe related filename to base64-encoded id(), or the reverse?
1225
1226 EntryHandler eh(*entry);
1227 QDomElement exml = eh.entryXML();
1228
1229 QDomDocument doc;
1230 QDomElement root = doc.createElement("ghnscache");
1231 root.appendChild(exml);
1232
1233 if (m_previewfiles.contains(entry)) {
1234 root.setAttribute("previewfile", m_previewfiles[entry]);
1235 }
1236 /*if (m_payloadfiles.contains(entry)) {
1237 root.setAttribute("payloadfile", m_payloadfiles[entry]);
1238 }*/
1239
1240 QFile f(cachedir + cachefile);
1241 if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
1242 kError() << "Cannot write meta information to '" << cachedir + cachefile << "'." << endl;
1243 // FIXME: ignore?
1244 return;
1245 }
1246 QTextStream metastream(&f);
1247 metastream << root;
1248 f.close();
1249}
1250
1251void CoreEngine::registerEntry(Entry *entry)
1252{
1253 m_entry_registry.insert(id(entry), entry);
1254 KStandardDirs d;
1255
1256 //kDebug() << "Registering entry.";
1257
1258 // NOTE: this directory must match loadRegistry
1259 QString registrydir = d.saveLocation("data", "knewstuff2-entries.registry");
1260
1261 //kDebug() << " + Save to directory '" + registrydir + "'.";
1262
1263 // FIXME: see cacheEntry() for naming-related discussion
1264 QString registryfile = QString(id(entry).toUtf8().toBase64()) + ".meta";
1265
1266 //kDebug() << " + Save to file '" + registryfile + "'.";
1267
1268 EntryHandler eh(*entry);
1269 QDomElement exml = eh.entryXML();
1270
1271 QDomDocument doc;
1272 QDomElement root = doc.createElement("ghnsinstall");
1273 root.appendChild(exml);
1274
1275 if (m_payloadfiles.contains(entry)) {
1276 root.setAttribute("payloadfile", m_payloadfiles[entry]);
1277 }
1278
1279 QFile f(registrydir + registryfile);
1280 if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
1281 kError() << "Cannot write meta information to '" << registrydir + registryfile << "'." << endl;
1282 // FIXME: ignore?
1283 return;
1284 }
1285 QTextStream metastream(&f);
1286 metastream << root;
1287 f.close();
1288}
1289
1290void KNS::CoreEngine::unregisterEntry(Entry * entry)
1291{
1292 KStandardDirs d;
1293
1294 // NOTE: this directory must match loadRegistry
1295 QString registrydir = d.saveLocation("data", "knewstuff2-entries.registry");
1296
1297 // FIXME: see cacheEntry() for naming-related discussion
1298 QString registryfile = QString(id(entry).toUtf8().toBase64()) + ".meta";
1299
1300 QFile::remove(registrydir + registryfile);
1301
1302 // remove the entry from m_entry_registry
1303 m_entry_registry.remove(id(entry));
1304}
1305
1306QString CoreEngine::id(Entry *e)
1307{
1308 // This is the primary key of an entry:
1309 // A lookup on the name, which must exist but might be translated
1310 // This requires some care for comparison since translations might be added
1311 return m_componentname + e->name().language() + ':' + e->name().representation();
1312}
1313
1314QString CoreEngine::pid(const Provider *p)
1315{
1316 // This is the primary key of a provider:
1317 // The download URL, which is never translated
1318 // If no download URL exists, a feed or web service URL must exist
1319 // if (p->downloadUrl().isValid())
1320 // return p->downloadUrl().url();
1321 QStringList feeds = p->feeds();
1322 for (int i = 0; i < feeds.count(); i++) {
1323 QString feedtype = feeds.at(i);
1324 Feed *f = p->downloadUrlFeed(feedtype);
1325 if (f->feedUrl().isValid())
1326 return m_componentname + f->feedUrl().url();
1327 }
1328 if (p->webService().isValid())
1329 return m_componentname + p->webService().url();
1330 return m_componentname;
1331}
1332
1333bool CoreEngine::install(const QString &payloadfile)
1334{
1335 QList<Entry*> entries = m_payloadfiles.keys(payloadfile);
1336 if (entries.size() != 1) {
1337 // FIXME: shouldn't ever happen - make this an assertion?
1338 kError() << "ASSERT: payloadfile is not associated" << endl;
1339 return false;
1340 }
1341 Entry *entry = entries.first();
1342
1343 bool update = (entry->status() == Entry::Updateable);
1344 // FIXME: this is only so exposing the KUrl suffices for downloaded entries
1345 entry->setStatus(Entry::Installed);
1346
1347 // FIXME: first of all, do the security stuff here
1348 // this means check sum comparison and signature verification
1349 // signature verification might take a long time - make async?!
1350
1351 if (m_installation->checksumPolicy() != Installation::CheckNever) {
1352 if (entry->checksum().isEmpty()) {
1353 if (m_installation->checksumPolicy() == Installation::CheckIfPossible) {
1354 //kDebug() << "Skip checksum verification";
1355 } else {
1356 kError() << "Checksum verification not possible" << endl;
1357 return false;
1358 }
1359 } else {
1360 //kDebug() << "Verify checksum...";
1361 }
1362 }
1363 if (m_installation->signaturePolicy() != Installation::CheckNever) {
1364 if (entry->signature().isEmpty()) {
1365 if (m_installation->signaturePolicy() == Installation::CheckIfPossible) {
1366 //kDebug() << "Skip signature verification";
1367 } else {
1368 kError() << "Signature verification not possible" << endl;
1369 return false;
1370 }
1371 } else {
1372 //kDebug() << "Verify signature...";
1373 }
1374 }
1375
1376 //kDebug() << "INSTALL resourceDir " << m_installation->standardResourceDir();
1377 //kDebug() << "INSTALL targetDir " << m_installation->targetDir();
1378 //kDebug() << "INSTALL installPath " << m_installation->installPath();
1379 //kDebug() << "INSTALL + scope " << m_installation->scope();
1380 //kDebug() << "INSTALL + customName" << m_installation->customName();
1381 //kDebug() << "INSTALL + uncompression " << m_installation->uncompression();
1382 //kDebug() << "INSTALL + command " << m_installation->command();
1383
1384 // Collect all files that were installed
1385 QStringList installedFiles;
1386 QString installpath(payloadfile);
1387 if (!m_installation->isRemote()) {
1388 // installdir is the target directory
1389 QString installdir;
1390 // installpath also contains the file name if it's a single file, otherwise equal to installdir
1391 int pathcounter = 0;
1392 if (!m_installation->standardResourceDir().isEmpty()) {
1393 if (m_installation->scope() == Installation::ScopeUser) {
1394 installdir = KStandardDirs::locateLocal(m_installation->standardResourceDir().toUtf8(), "/");
1395 } else { // system scope
1396 installdir = KStandardDirs::installPath(m_installation->standardResourceDir().toUtf8());
1397 }
1398 pathcounter++;
1399 }
1400 if (!m_installation->targetDir().isEmpty()) {
1401 if (m_installation->scope() == Installation::ScopeUser) {
1402 installdir = KStandardDirs::locateLocal("data", m_installation->targetDir() + '/');
1403 } else { // system scope
1404 installdir = KStandardDirs::installPath("data") + m_installation->targetDir() + '/';
1405 }
1406 pathcounter++;
1407 }
1408 if (!m_installation->installPath().isEmpty()) {
1409#if defined(Q_WS_WIN)
1410#ifndef _WIN32_WCE
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('/');
1414 } else {
1415#endif
1416 installdir = QDir::home().path() + QLatin1Char('/') + m_installation->installPath() + QLatin1Char('/');
1417#ifndef _WIN32_WCE
1418 }
1419#endif
1420#else
1421 installdir = QDir::home().path() + '/' + m_installation->installPath() + '/';
1422#endif
1423 pathcounter++;
1424 }
1425 if (!m_installation->absoluteInstallPath().isEmpty()) {
1426 installdir = m_installation->absoluteInstallPath() + '/';
1427 pathcounter++;
1428 }
1429 if (pathcounter != 1) {
1430 kError() << "Wrong number of installation directories given." << endl;
1431 return false;
1432 }
1433
1434 kDebug() << "installdir: " << installdir;
1435 bool isarchive = true;
1436
1437 // respect the uncompress flag in the knsrc
1438 if (m_installation->uncompression() == "always" || m_installation->uncompression() == "archive") {
1439 // this is weird but a decompression is not a single name, so take the path instead
1440 installpath = installdir;
1441 KMimeType::Ptr mimeType = KMimeType::findByPath(payloadfile);
1442 //kDebug() << "Postinstallation: uncompress the file";
1443
1444 // FIXME: check for overwriting, malicious archive entries (../foo) etc.
1445 // FIXME: KArchive should provide "safe mode" for this!
1446 KArchive *archive = 0;
1447
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);
1456 } else {
1457 kError() << "Could not determine type of archive file '" << payloadfile << "'";
1458 if (m_installation->uncompression() == "always") {
1459 return false;
1460 }
1461 isarchive = false;
1462 }
1463
1464 if (isarchive) {
1465 bool success = archive->open(QIODevice::ReadOnly);
1466 if (!success) {
1467 kError() << "Cannot open archive file '" << payloadfile << "'";
1468 if (m_installation->uncompression() == "always") {
1469 return false;
1470 }
1471 // otherwise, just copy the file
1472 isarchive = false;
1473 }
1474
1475 if (isarchive) {
1476 const KArchiveDirectory *dir = archive->directory();
1477 dir->copyTo(installdir);
1478
1479 installedFiles << archiveEntries(installdir, dir);
1480 installedFiles << installdir + '/';
1481
1482 archive->close();
1483 QFile::remove(payloadfile);
1484 delete archive;
1485 }
1486 }
1487 }
1488
1489 kDebug() << "isarchive: " << isarchive;
1490
1491 if (m_installation->uncompression() == "never" || (m_installation->uncompression() == "archive" && !isarchive)) {
1492 // no decompress but move to target
1493
1495 // FIXME: make naming convention configurable through *.knsrc? e.g. for kde-look.org image names
1496 KUrl source = KUrl(entry->payload().representation());
1497 kDebug() << "installing non-archive from " << source.url();
1498 QString installfile;
1499 QString ext = source.fileName().section('.', -1);
1500 if (m_installation->customName()) {
1501 installfile = entry->name().representation();
1502 installfile += '-' + entry->version();
1503 if (!ext.isEmpty()) installfile += '.' + ext;
1504 } else {
1505 installfile = source.fileName();
1506 }
1507 installpath = installdir + '/' + installfile;
1508
1509 //kDebug() << "Install to file " << installpath;
1510 // FIXME: copy goes here (including overwrite checking)
1511 // FIXME: what must be done now is to update the cache *again*
1512 // in order to set the new payload filename (on root tag only)
1513 // - this might or might not need to take uncompression into account
1514 // FIXME: for updates, we might need to force an overwrite (that is, deleting before)
1515 QFile file(payloadfile);
1516 bool success = true;
1517
1518 if (QFile::exists(installpath) && update) {
1519 success = QFile::remove(installpath);
1520 }
1521 if (success) {
1522 success = file.rename(installpath);
1523 }
1524 if (!success) {
1525 kError() << "Cannot move file '" << payloadfile << "' to destination '" << installpath << "'";
1526 return false;
1527 }
1528 installedFiles << installpath;
1529 installedFiles << installdir + '/';
1530 }
1531 }
1532
1533 entry->setInstalledFiles(installedFiles);
1534
1535 if (!m_installation->command().isEmpty()) {
1536 KProcess process;
1537 QString command(m_installation->command());
1538 QString fileArg(KShell::quoteArg(installpath));
1539 command.replace("%f", fileArg);
1540
1541 //kDebug() << "Postinstallation: execute command";
1542 //kDebug() << "Command is: " << command;
1543
1544 process.setShellCommand(command);
1545 int exitcode = process.execute();
1546
1547 if (exitcode) {
1548 kError() << "Command failed" << endl;
1549 } else {
1550 //kDebug() << "Command executed successfully";
1551 }
1552 }
1553
1554 // ==== FIXME: security code below must go above, when async handling is complete ====
1555
1556 // FIXME: security object lifecycle - it is a singleton!
1557 Security *sec = Security::ref();
1558
1559 connect(sec,
1560 SIGNAL(validityResult(int)),
1561 SLOT(slotInstallationVerification(int)));
1562
1563 // FIXME: change to accept filename + signature
1564 sec->checkValidity(QString());
1565
1566 m_payloadfiles[entry] = installpath;
1567 registerEntry(entry);
1568 // FIXME: hm, do we need to update the cache really?
1569 // only registration is probably needed here
1570
1571 emit signalEntryChanged(entry);
1572
1573 return true;
1574}
1575
1576bool CoreEngine::uninstall(KNS::Entry *entry)
1577{
1578 entry->setStatus(Entry::Deleted);
1579
1580 if (!m_installation->uninstallCommand().isEmpty()) {
1581 KProcess process;
1582 foreach (const QString& file, entry->installedFiles()) {
1583 QFileInfo info(file);
1584 if (info.isFile()) {
1585 QString fileArg(KShell::quoteArg(file));
1586 QString command(m_installation->uninstallCommand());
1587 command.replace("%f", fileArg);
1588
1589 process.setShellCommand(command);
1590 int exitcode = process.execute();
1591
1592 if (exitcode) {
1593 kError() << "Command failed" << endl;
1594 } else {
1595 //kDebug() << "Command executed successfully";
1596 }
1597 }
1598 }
1599 }
1600
1601 foreach(const QString &file, entry->installedFiles()) {
1602 if (file.endsWith('/')) {
1603 QDir dir;
1604 bool worked = dir.rmdir(file);
1605 if (!worked) {
1606 // Maybe directory contains user created files, ignore it
1607 continue;
1608 }
1609 } else {
1610 if (QFile::exists(file)) {
1611 bool worked = QFile::remove(file);
1612 if (!worked) {
1613 kWarning() << "unable to delete file " << file;
1614 return false;
1615 }
1616 } else {
1617 kWarning() << "unable to delete file " << file << ". file does not exist.";
1618 }
1619 }
1620 }
1621 entry->setUnInstalledFiles(entry->installedFiles());
1622 entry->setInstalledFiles(QStringList());
1623 unregisterEntry(entry);
1624
1625 emit signalEntryChanged(entry);
1626
1627 return true;
1628}
1629
1630void CoreEngine::slotInstallationVerification(int result)
1631{
1632 //kDebug() << "SECURITY result " << result;
1633
1634 if (result & Security::SIGNED_OK)
1635 emit signalInstallationFinished();
1636 else
1637 emit signalInstallationFailed();
1638}
1639
1640void CoreEngine::setAutomationPolicy(AutomationPolicy policy)
1641{
1642 m_automationpolicy = policy;
1643}
1644
1645void CoreEngine::setCachePolicy(CachePolicy policy)
1646{
1647 m_cachepolicy = policy;
1648}
1649
1650QStringList KNS::CoreEngine::archiveEntries(const QString& path, const KArchiveDirectory * dir)
1651{
1652 QStringList files;
1653 foreach(const QString &entry, dir->entries()) {
1654 QString childPath = path + '/' + entry;
1655 if (dir->entry(entry)->isFile()) {
1656 files << childPath;
1657 }
1658
1659 if (dir->entry(entry)->isDirectory()) {
1660 const KArchiveDirectory* childDir = static_cast<const KArchiveDirectory*>(dir->entry(entry));
1661 files << archiveEntries(childPath, childDir);
1662 files << childPath + '/';
1663 }
1664 }
1665 return files;
1666}
1667
1668
1669#include "coreengine.moc"
KArchiveDirectory
KArchive
KArchive::close
virtual bool close()
KArchive::open
virtual bool open(QIODevice::OpenMode mode)
KArchive::directory
const KArchiveDirectory * directory() const
KConfigBase::group
KConfigGroup group(const char *group)
KConfigBase::hasGroup
bool hasGroup(const char *group) const
KConfigBase::NoAccess
NoAccess
KConfigGroup
KConfig
KConfig::accessMode
AccessMode accessMode() const
KIO::FileCopyJob
KIO::FileCopyJob::destUrl
KUrl destUrl() const
KIO::FileCopyJob::srcUrl
KUrl srcUrl() const
KIO::SimpleJob::url
const KUrl & url() const
KIO::TransferJob
KJob
KJob::errorString
virtual QString errorString() const
KJob::error
int error() const
KMimeType::findByPath
static Ptr findByPath(const QString &path, mode_t mode=0, bool fast_mode=false, int *accuracy=0)
KNS::CoreEngine::signalEntriesFinished
void signalEntriesFinished()
KNS::CoreEngine::componentName
QString componentName() const
Definition: coreengine.cpp:186
KNS::CoreEngine::signalProviderLoaded
void signalProviderLoaded(KNS::Provider *provider)
Indicates that the list of providers has been successfully loaded.
KNS::CoreEngine::signalInstallationFinished
void signalInstallationFinished()
KNS::CoreEngine::signalPayloadLoaded
void signalPayloadLoaded(KUrl payload)
KNS::CoreEngine::install
bool install(const QString &payloadfile)
Installs an entry's payload file.
Definition: coreengine.cpp:1333
KNS::CoreEngine::setCachePolicy
void setCachePolicy(CachePolicy policy)
Definition: coreengine.cpp:1645
KNS::CoreEngine::signalInstallationFailed
void signalInstallationFailed()
KNS::CoreEngine::uploadEntry
bool uploadEntry(Provider *provider, Entry *entry)
Uploads a complete entry, including its payload and preview files (if present) and all associated met...
Definition: coreengine.cpp:340
KNS::CoreEngine::signalEntryUploaded
void signalEntryUploaded()
KNS::CoreEngine::signalEntriesFailed
void signalEntriesFailed()
KNS::CoreEngine::mergeEntries
void mergeEntries(Entry::List entries, Feed *feed, const Provider *provider)
Definition: coreengine.cpp:1036
KNS::CoreEngine::~CoreEngine
~CoreEngine()
Destructor.
Definition: coreengine.cpp:63
KNS::CoreEngine::signalEntryLoaded
void signalEntryLoaded(KNS::Entry *entry, const KNS::Feed *feed, const KNS::Provider *provider)
KNS::CoreEngine::downloadPayload
void downloadPayload(Entry *entry)
Downloads a payload file.
Definition: coreengine.cpp:300
KNS::CoreEngine::signalProvidersFinished
void signalProvidersFinished()
KNS::CoreEngine::signalProviderChanged
void signalProviderChanged(KNS::Provider *provider)
KNS::CoreEngine::signalEntryFailed
void signalEntryFailed()
KNS::CoreEngine::signalEntryChanged
void signalEntryChanged(KNS::Entry *entry)
KNS::CoreEngine::signalPayloadFailed
void signalPayloadFailed(KNS::Entry *entry)
KNS::CoreEngine::setAutomationPolicy
void setAutomationPolicy(AutomationPolicy policy)
Definition: coreengine.cpp:1640
KNS::CoreEngine::downloadPreview
void downloadPreview(Entry *entry)
Downloads a preview file.
Definition: coreengine.cpp:269
KNS::CoreEngine::signalProgress
void signalProgress(const QString &message, int percentage)
KNS::CoreEngine::uninstall
bool uninstall(KNS::Entry *entry)
Uninstalls an entry.
Definition: coreengine.cpp:1576
KNS::CoreEngine::start
void start()
Starts the engine.
Definition: coreengine.cpp:195
KNS::CoreEngine::init
bool init(const QString &configfile)
Initializes the engine.
Definition: coreengine.cpp:68
KNS::CoreEngine::signalProvidersFailed
void signalProvidersFailed()
KNS::CoreEngine::signalPreviewFailed
void signalPreviewFailed()
KNS::CoreEngine::CoreEngine
CoreEngine(QObject *parent)
Constructor.
Definition: coreengine.cpp:57
KNS::CoreEngine::CachePolicy
CachePolicy
Policy on how to cache the data received from the network.
Definition: coreengine.h:75
KNS::CoreEngine::CacheResident
@ CacheResident
Operate on cache files but never update them.
Definition: coreengine.h:81
KNS::CoreEngine::CacheOnly
@ CacheOnly
Definition: coreengine.h:83
KNS::CoreEngine::CacheReplaceable
@ CacheReplaceable
Like CacheReplaceable, but only update if necessary.
Definition: coreengine.h:79
KNS::CoreEngine::CacheNever
@ CacheNever
Do not use any cache.
Definition: coreengine.h:77
KNS::CoreEngine::signalEntriesFeedFinished
void signalEntriesFeedFinished(const KNS::Feed *feed)
KNS::CoreEngine::loadEntries
void loadEntries(Provider *provider)
Loads all entries of all the feeds from a provider.
Definition: coreengine.cpp:231
KNS::CoreEngine::signalPreviewLoaded
void signalPreviewLoaded(KUrl preview)
KNS::CoreEngine::AutomationPolicy
AutomationPolicy
Engine automation can be activated to let the engine take care by itself of all the method calls need...
Definition: coreengine.h:98
KNS::EntryHandler
Parser and dumper for KNewStuff data entries.
Definition: entryhandler.h:43
KNS::EntryLoader
KNewStuff entry loader.
Definition: entryloader.h:48
KNS::EntryLoader::feed
Feed * feed() const
Returns the feed which was used for download.
Definition: entryloader.cpp:62
KNS::EntryLoader::provider
const Provider * provider() const
Returns the provider which was used for download.
Definition: entryloader.cpp:67
KNS::EntryLoader::load
void load(const Provider *provider, Feed *feed)
Starts asynchronously loading the list of entries from the given provider for the given feed.
Definition: entryloader.cpp:40
KNS::Entry
KNewStuff data entry container.
Definition: knewstuff2/core/entry.h:47
KNS::Entry::setInstalledFiles
void setInstalledFiles(const QStringList &files)
Set the files that have been installed by the install command.
Definition: knewstuff2/core/entry.cpp:236
KNS::Entry::preview
KTranslatable preview() const
Retrieve the file name of an image containing a preview of the object.
Definition: knewstuff2/core/entry.cpp:171
KNS::Entry::releaseDate
QDate releaseDate() const
Retrieve the date of the object's publication.
Definition: knewstuff2/core/entry.cpp:151
KNS::Entry::setUnInstalledFiles
void setUnInstalledFiles(const QStringList &files)
Set the files that have been uninstalled by the uninstall command.
Definition: knewstuff2/core/entry.cpp:256
KNS::Entry::signature
QString signature() const
Returns the signature for the entry.
Definition: knewstuff2/core/entry.cpp:211
KNS::Entry::name
KTranslatable name() const
Retrieve the name of the data object.
Definition: knewstuff2/core/entry.cpp:81
KNS::Entry::payload
KTranslatable payload() const
Retrieve the file name of the object.
Definition: knewstuff2/core/entry.cpp:161
KNS::Entry::status
Status status()
Retrieves the entry's status.
Definition: knewstuff2/core/entry.cpp:216
KNS::Entry::Cache
@ Cache
Definition: knewstuff2/core/entry.h:320
KNS::Entry::Registry
@ Registry
Definition: knewstuff2/core/entry.h:322
KNS::Entry::checksum
QString checksum() const
Returns the checksum for the entry.
Definition: knewstuff2/core/entry.cpp:201
KNS::Entry::setStatus
void setStatus(Status status)
Sets the entry's status.
Definition: knewstuff2/core/entry.cpp:221
KNS::Entry::setSource
void setSource(Source source)
Definition: knewstuff2/core/entry.cpp:231
KNS::Entry::release
int release() const
Retrieve the release number of the object.
Definition: knewstuff2/core/entry.cpp:141
KNS::Entry::version
QString version() const
Retrieve the version string of the object.
Definition: knewstuff2/core/entry.cpp:131
KNS::Entry::Installed
@ Installed
Definition: knewstuff2/core/entry.h:293
KNS::Entry::Deleted
@ Deleted
Definition: knewstuff2/core/entry.h:295
KNS::Entry::Updateable
@ Updateable
Definition: knewstuff2/core/entry.h:294
KNS::Entry::Downloadable
@ Downloadable
Definition: knewstuff2/core/entry.h:292
KNS::Entry::installedFiles
QStringList installedFiles() const
Retrieve the locally installed files.
Definition: knewstuff2/core/entry.cpp:241
KNS::Feed
KNewStuff feed.
Definition: feed.h:46
KNS::Feed::feedUrl
KUrl feedUrl() const
Retrieve the URL of the feed.
Definition: feed.cpp:67
KNS::Feed::addEntry
void addEntry(Entry *entry)
Adds an association to an entry.
Definition: feed.cpp:72
KNS::Feed::removeEntry
void removeEntry(Entry *entry)
Removes an association to an entry.
Definition: feed.cpp:78
KNS::Installation
KNewStuff entry installation.
Definition: knewstuff2/core/installation.h:45
KNS::Installation::installPath
QString installPath() const
Definition: knewstuff2/core/installation.cpp:134
KNS::Installation::ScopeSystem
@ ScopeSystem
Definition: knewstuff2/core/installation.h:65
KNS::Installation::ScopeUser
@ ScopeUser
Definition: knewstuff2/core/installation.h:64
KNS::Installation::absoluteInstallPath
QString absoluteInstallPath() const
Definition: knewstuff2/core/installation.cpp:139
KNS::Installation::checksumPolicy
Policy checksumPolicy() const
Definition: knewstuff2/core/installation.cpp:153
KNS::Installation::setUninstallCommand
void setUninstallCommand(const QString &command)
Definition: knewstuff2/core/installation.cpp:64
KNS::Installation::standardResourceDir
QString standardResourceDir() const
Definition: knewstuff2/core/installation.cpp:124
KNS::Installation::uncompression
QString uncompression() const
Definition: knewstuff2/core/installation.cpp:109
KNS::Installation::CheckNever
@ CheckNever
Definition: knewstuff2/core/installation.h:58
KNS::Installation::CheckIfPossible
@ CheckIfPossible
Definition: knewstuff2/core/installation.h:59
KNS::Installation::CheckAlways
@ CheckAlways
Definition: knewstuff2/core/installation.h:60
KNS::Installation::isRemote
bool isRemote() const
Definition: knewstuff2/core/installation.cpp:144
KNS::Installation::command
QString command() const
Definition: knewstuff2/core/installation.cpp:114
KNS::Installation::uninstallCommand
QString uninstallCommand() const
Definition: knewstuff2/core/installation.cpp:119
KNS::Installation::setCommand
void setCommand(const QString &command)
Definition: knewstuff2/core/installation.cpp:59
KNS::Installation::setChecksumPolicy
void setChecksumPolicy(Policy policy)
Definition: knewstuff2/core/installation.cpp:89
KNS::Installation::setScope
void setScope(Scope scope)
Definition: knewstuff2/core/installation.cpp:99
KNS::Installation::setTargetDir
void setTargetDir(const QString &dir)
Definition: knewstuff2/core/installation.cpp:74
KNS::Installation::setSignaturePolicy
void setSignaturePolicy(Policy policy)
Definition: knewstuff2/core/installation.cpp:94
KNS::Installation::setAbsoluteInstallPath
void setAbsoluteInstallPath(const QString &dir)
Definition: knewstuff2/core/installation.cpp:84
KNS::Installation::scope
Scope scope() const
Definition: knewstuff2/core/installation.cpp:168
KNS::Installation::setStandardResourceDir
void setStandardResourceDir(const QString &dir)
Definition: knewstuff2/core/installation.cpp:69
KNS::Installation::customName
bool customName() const
Definition: knewstuff2/core/installation.cpp:163
KNS::Installation::targetDir
QString targetDir() const
Definition: knewstuff2/core/installation.cpp:129
KNS::Installation::signaturePolicy
Policy signaturePolicy() const
Definition: knewstuff2/core/installation.cpp:158
KNS::Installation::setInstallPath
void setInstallPath(const QString &dir)
Definition: knewstuff2/core/installation.cpp:79
KNS::Installation::setUncompression
void setUncompression(const QString &uncompression)
Definition: knewstuff2/core/installation.cpp:54
KNS::Installation::setCustomName
void setCustomName(bool customname)
Definition: knewstuff2/core/installation.cpp:104
KNS::KTranslatable::language
QString language() const
Returns the language which most likely resembles the current language.
Definition: ktranslatable.cpp:77
KNS::KTranslatable::representation
QString representation() const
Returns the string which matches most closely the current language.
Definition: ktranslatable.cpp:64
KNS::ProviderHandler
Parser and dumper for KNewStuff providers.
Definition: providerhandler.h:48
KNS::ProviderLoader
KNewStuff provider loader.
Definition: providerloader.h:49
KNS::ProviderLoader::load
void load(const QString &providersurl)
Starts asynchronously loading the list of providers from the specified URL.
Definition: providerloader.cpp:38
KNS::Provider
KNewStuff provider container.
Definition: knewstuff2/core/provider.h:52
KNS::Provider::downloadUrlFeed
Feed * downloadUrlFeed(const QString &feedtype) const
Feed to retrieve for the given feed type.
Definition: knewstuff2/core/provider.cpp:50
KNS::Provider::uploadUrl
KUrl uploadUrl() const
Retrieves the upload URL.
Definition: knewstuff2/core/provider.cpp:84
KNS::Provider::feeds
QStringList feeds() const
Returns a list of all feeds.
Definition: knewstuff2/core/provider.cpp:119
KNS::Provider::name
KTranslatable name() const
Retrieves the common name of the provider.
Definition: knewstuff2/core/provider.cpp:64
KNS::Provider::webService
KUrl webService() const
Retrieves the URL to the DXS Web Service.
Definition: knewstuff2/core/provider.cpp:114
KNS::Security
Handles security related issues, like signing, verifying.
Definition: knewstuff2/core/security.h:48
KNS::Security::checkValidity
void checkValidity(const QString &fileName)
Verifies the integrity and the signature of a tarball file.
Definition: knewstuff2/core/security.cpp:227
KNS::Security::SIGNED_OK
@ SIGNED_OK
The MD5 sum check is OK.
Definition: knewstuff2/core/security.h:86
KNS::Security::ref
static Security * ref()
Definition: knewstuff2/core/security.h:51
KProcess
KProcess::setShellCommand
void setShellCommand(const QString &cmd)
KProcess::execute
int execute(int msecs=-1)
KSharedPtr
KStandardDirs
KStandardDirs::installPath
static QString installPath(const char *type)
KStandardDirs::saveLocation
QString saveLocation(const char *type, const QString &suffix=QString(), bool create=true) const
KStandardDirs::findDirs
QStringList findDirs(const char *type, const QString &reldir) const
KStandardDirs::locate
static QString locate(const char *type, const QString &filename, const KComponentData &cData=KGlobal::mainComponent())
KStandardDirs::findResource
QString findResource(const char *type, const QString &filename) const
KStandardDirs::locateLocal
static QString locateLocal(const char *type, const QString &filename, bool createDir, const KComponentData &cData=KGlobal::mainComponent())
KTar
KUrl
KUrl::pathOrUrl
QString pathOrUrl() const
KUrl::fromPath
static KUrl fromPath(const QString &text)
KUrl::url
QString url(AdjustPathOption trailing=LeaveTrailingSlash) const
KUrl::path
QString path(AdjustPathOption trailing=LeaveTrailingSlash) const
KUrl::setFileName
void setFileName(const QString &_txt)
KUrl::fileName
QString fileName(const DirectoryOptions &options=IgnoreTrailingSlash) const
KZip
QList< Provider * >
QObject
coreengine.h
entryhandler.h
entryloader.h
kDebug
#define kDebug
kWarning
#define kWarning
job.h
kaboutdata.h
kcodecs.h
kcomponentdata.h
kconfig.h
kconfiggroup.h
kdebug.h
i18n
QString i18n(const char *text)
kmimetype.h
installation.h
security.h
kprocess.h
krandom.h
kshell.h
kstandarddirs.h
ktar.h
kzip.h
KGlobal::dirs
KStandardDirs * dirs()
KIO::file_copy
FileCopyJob * file_copy(const KUrl &src, const KUrl &dest, int permissions=-1, JobFlags flags=DefaultFlags)
KIO::HideProgressInfo
HideProgressInfo
KIO::Overwrite
Overwrite
group
group
message
void message(KMessage::MessageType messageType, const QString &text, const QString &caption=QString())
KNS
Definition: knewstuff2/core/author.h:27
KRandom::randomString
QString randomString(int length)
dir
QString dir(const QString &fileClass)
KShell::quoteArg
QString quoteArg(const QString &arg)
providerhandler.h
providerloader.h
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KNewStuff

Skip menu "KNewStuff"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal