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

KNewStuff

  • sources
  • kde-4.12
  • kdelibs
  • 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 
55 using namespace KNS;
56 
57 CoreEngine::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 
63 CoreEngine::~CoreEngine()
64 {
65  shutdown();
66 }
67 
68 bool 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 
186 QString CoreEngine::componentName() const
187 {
188  if (!m_initialized) {
189  return QString();
190  }
191 
192  return m_componentname;
193 }
194 
195 void 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 
231 void 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 
269 void 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 
300 void 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 
340 bool 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 
373 void 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 
382 void CoreEngine::slotProvidersFailed()
383 {
384  kDebug() << "slotProvidersFailed";
385  ProviderLoader *loader = dynamic_cast<ProviderLoader*>(sender());
386  delete loader;
387 
388  emit signalProvidersFailed();
389 }
390 
391 void 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 
408 void CoreEngine::slotEntriesFailed()
409 {
410  EntryLoader *loader = dynamic_cast<EntryLoader*>(sender());
411  delete loader;
412  m_activefeeds--;
413 
414  emit signalEntriesFailed();
415 }
416 
417 void 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 
432 void 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
456 void 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 
480 void 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 
510 void 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 
559 void 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 
579 void 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 
668 void 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 
741 void 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 
829 KNS::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
886 void 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 
917 void 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 
931 bool 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 
940 bool 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 
957 void 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 
994 bool 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 
1026 bool 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 
1036 void 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 
1132 void 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 
1173 void 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 
1208 void 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 
1251 void 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 
1290 void 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 
1306 QString 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 
1314 QString 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 
1333 bool 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 
1576 bool 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 
1630 void 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 
1640 void CoreEngine::setAutomationPolicy(AutomationPolicy policy)
1641 {
1642  m_automationpolicy = policy;
1643 }
1644 
1645 void CoreEngine::setCachePolicy(CachePolicy policy)
1646 {
1647  m_cachepolicy = policy;
1648 }
1649 
1650 QStringList 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"
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::Entry::setUnInstalledFiles
void setUnInstalledFiles(const QStringList &files)
Set the files that have been uninstalled by the uninstall command.
Definition: knewstuff2/core/entry.cpp:256
KProcess::setShellCommand
void setShellCommand(const QString &cmd)
KNS::CoreEngine::signalProvidersFailed
void signalProvidersFailed()
message
void message(KMessage::MessageType messageType, const QString &text, const QString &caption=QString())
KNS::Entry::Registry
Definition: knewstuff2/core/entry.h:322
KStandardDirs::saveLocation
QString saveLocation(const char *type, const QString &suffix=QString(), bool create=true) const
i18n
QString i18n(const char *text)
KIO::Overwrite
KNS::CoreEngine::init
bool init(const QString &configfile)
Initializes the engine.
Definition: coreengine.cpp:68
krandom.h
KNS::CoreEngine::signalInstallationFailed
void signalInstallationFailed()
KProcess
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::Provider::name
KTranslatable name() const
Retrieves the common name of the provider.
Definition: knewstuff2/core/provider.cpp:64
KNS::Entry::checksum
QString checksum() const
Returns the checksum for the entry.
Definition: knewstuff2/core/entry.cpp:201
KNS::Installation::setUninstallCommand
void setUninstallCommand(const QString &command)
Definition: knewstuff2/core/installation.cpp:64
kdebug.h
KNS::ProviderHandler
Parser and dumper for KNewStuff providers.
Definition: providerhandler.h:47
kmimetype.h
KArchiveEntry::isDirectory
virtual bool isDirectory() const
KNS::Installation::standardResourceDir
QString standardResourceDir() const
Definition: knewstuff2/core/installation.cpp:124
group
KNS::Installation::scope
Scope scope() const
Definition: knewstuff2/core/installation.cpp:168
KNS::Entry
KNewStuff data entry container.
Definition: knewstuff2/core/entry.h:46
KNS::Installation::uncompression
QString uncompression() const
Definition: knewstuff2/core/installation.cpp:109
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())
KIO::HideProgressInfo
KNS::Entry::releaseDate
QDate releaseDate() const
Retrieve the date of the object's publication.
Definition: knewstuff2/core/entry.cpp:151
kconfig.h
KArchive
KNS::CoreEngine::loadEntries
void loadEntries(Provider *provider)
Loads all entries of all the feeds from a provider.
Definition: coreengine.cpp:231
KNS::EntryLoader::provider
const Provider * provider() const
Returns the provider which was used for download.
Definition: entryloader.cpp:67
kshell.h
KNS::Installation::ScopeSystem
Definition: knewstuff2/core/installation.h:65
KNS::CoreEngine::signalProviderLoaded
void signalProviderLoaded(KNS::Provider *provider)
Indicates that the list of providers has been successfully loaded.
KNS::Installation::CheckAlways
Definition: knewstuff2/core/installation.h:60
KNS::Entry::status
Status status()
Retrieves the entry's status.
Definition: knewstuff2/core/entry.cpp:216
KGlobal::dirs
KStandardDirs * dirs()
KNS::Entry::version
QString version() const
Retrieve the version string of the object.
Definition: knewstuff2/core/entry.cpp:131
KNS::Installation::checksumPolicy
Policy checksumPolicy() const
Definition: knewstuff2/core/installation.cpp:153
kError
static QDebug kError(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
KConfig::hasGroup
bool hasGroup(const QString &group) const
KNS::CoreEngine::downloadPreview
void downloadPreview(Entry *entry)
Downloads a preview file.
Definition: coreengine.cpp:269
KUrl::fromPath
static KUrl fromPath(const QString &text)
KConfig::group
KConfigGroup group(const QByteArray &group)
KNS::CoreEngine::CachePolicy
CachePolicy
Policy on how to cache the data received from the network.
Definition: coreengine.h:75
KNS::Installation::CheckIfPossible
Definition: knewstuff2/core/installation.h:59
KNS::CoreEngine::~CoreEngine
~CoreEngine()
Destructor.
Definition: coreengine.cpp:63
KNS::Entry::release
int release() const
Retrieve the release number of the object.
Definition: knewstuff2/core/entry.cpp:141
providerloader.h
KNS::Provider::uploadUrl
KUrl uploadUrl() const
Retrieves the upload URL.
Definition: knewstuff2/core/provider.cpp:84
KNS::CoreEngine::signalPayloadLoaded
void signalPayloadLoaded(KUrl payload)
KIO::FileCopyJob::destUrl
KUrl destUrl() const
QString
KNS::CoreEngine::CacheReplaceable
Like CacheReplaceable, but only update if necessary.
Definition: coreengine.h:79
KNS::CoreEngine::CoreEngine
CoreEngine(QObject *parent)
Constructor.
Definition: coreengine.cpp:57
KNS::Entry::setSource
void setSource(Source source)
Definition: knewstuff2/core/entry.cpp:231
KNS::Installation::uninstallCommand
QString uninstallCommand() const
Definition: knewstuff2/core/installation.cpp:119
QObject
kDebug
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
KNS::Entry::name
KTranslatable name() const
Retrieve the name of the data object.
Definition: knewstuff2/core/entry.cpp:81
KNS::Entry::Deleted
Definition: knewstuff2/core/entry.h:295
KNS::CoreEngine::CacheNever
Do not use any cache.
Definition: coreengine.h:77
KUrl
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::CoreEngine::signalProgress
void signalProgress(const QString &message, int percentage)
entryloader.h
KNS::CoreEngine::componentName
QString componentName() const
Definition: coreengine.cpp:186
installation.h
kzip.h
KNS::KTranslatable::language
QString language() const
Returns the language which most likely resembles the current language.
Definition: ktranslatable.cpp:77
KNS::Installation::customName
bool customName() const
Definition: knewstuff2/core/installation.cpp:163
kprocess.h
KNS::Entry::payload
KTranslatable payload() const
Retrieve the file name of the object.
Definition: knewstuff2/core/entry.cpp:161
KNS::Entry::signature
QString signature() const
Returns the signature for the entry.
Definition: knewstuff2/core/entry.cpp:211
KIO::FileCopyJob::srcUrl
KUrl srcUrl() const
KNS::Installation::CheckNever
Definition: knewstuff2/core/installation.h:58
KIO::file_copy
FileCopyJob * file_copy(const KUrl &src, const KUrl &dest, int permissions=-1, JobFlags flags=DefaultFlags)
KNS::Provider::downloadUrlFeed
Feed * downloadUrlFeed(const QString &feedtype) const
Feed to retrieve for the given feed type.
Definition: knewstuff2/core/provider.cpp:50
KNS::Security
Handles security related issues, like signing, verifying.
Definition: knewstuff2/core/security.h:47
KNS::Security::checkValidity
void checkValidity(const QString &fileName)
Verifies the integrity and the signature of a tarball file.
Definition: knewstuff2/core/security.cpp:216
KNS::Installation::setSignaturePolicy
void setSignaturePolicy(Policy policy)
Definition: knewstuff2/core/installation.cpp:94
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::signalInstallationFinished
void signalInstallationFinished()
KNS::CoreEngine::CacheOnly
Definition: coreengine.h:83
KNS::Provider::feeds
QStringList feeds() const
Returns a list of all feeds.
Definition: knewstuff2/core/provider.cpp:119
KNS::Security::SIGNED_OK
The MD5 sum check is OK.
Definition: knewstuff2/core/security.h:86
KNS::CoreEngine::signalEntryFailed
void signalEntryFailed()
KConfig::accessMode
AccessMode accessMode() const
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
KStandardDirs
KNS::Feed::feedUrl
KUrl feedUrl() const
Retrieve the URL of the feed.
Definition: feed.cpp:67
KTar
QStringList
KNS::EntryLoader::feed
Feed * feed() const
Returns the feed which was used for download.
Definition: entryloader.cpp:62
entryhandler.h
KUrl::pathOrUrl
QString pathOrUrl() const
KNS::Installation::setAbsoluteInstallPath
void setAbsoluteInstallPath(const QString &dir)
Definition: knewstuff2/core/installation.cpp:84
KNS::Installation::setChecksumPolicy
void setChecksumPolicy(Policy policy)
Definition: knewstuff2/core/installation.cpp:89
KNS::Installation::setTargetDir
void setTargetDir(const QString &dir)
Definition: knewstuff2/core/installation.cpp:74
KNS::Entry::Cache
Definition: knewstuff2/core/entry.h:320
KNS::CoreEngine::signalPreviewFailed
void signalPreviewFailed()
KNS::CoreEngine::signalProvidersFinished
void signalProvidersFinished()
KNS::Installation
KNewStuff entry installation.
Definition: knewstuff2/core/installation.h:44
KZip
KUrl::path
QString path(AdjustPathOption trailing=LeaveTrailingSlash) const
KNS::CoreEngine::signalEntryChanged
void signalEntryChanged(KNS::Entry *entry)
KNS::Feed::addEntry
void addEntry(Entry *entry)
Adds an association to an entry.
Definition: feed.cpp:72
KNS::CoreEngine::uninstall
bool uninstall(KNS::Entry *entry)
Uninstalls an entry.
Definition: coreengine.cpp:1576
KNS::KTranslatable::representation
QString representation() const
Returns the string which matches most closely the current language.
Definition: ktranslatable.cpp:64
KNS::Entry::installedFiles
QStringList installedFiles() const
Retrieve the locally installed files.
Definition: knewstuff2/core/entry.cpp:241
KNS::ProviderLoader::load
void load(const QString &providersurl)
Starts asynchronously loading the list of providers from the specified URL.
Definition: providerloader.cpp:38
KShell::quoteArg
QString quoteArg(const QString &arg)
KNS::CoreEngine::signalEntriesFeedFinished
void signalEntriesFeedFinished(const KNS::Feed *feed)
KNS::CoreEngine::signalPayloadFailed
void signalPayloadFailed(KNS::Entry *entry)
KStandardDirs::installPath
static QString installPath(const char *type)
KNS::Entry::Installed
Definition: knewstuff2/core/entry.h:293
KArchiveDirectory::copyTo
void copyTo(const QString &dest, bool recursive=true) const
KNS::Installation::setUncompression
void setUncompression(const QString &uncompression)
Definition: knewstuff2/core/installation.cpp:54
KArchiveDirectory::entry
const KArchiveEntry * entry(const QString &name) const
KNS::Installation::setCommand
void setCommand(const QString &command)
Definition: knewstuff2/core/installation.cpp:59
KNS::Installation::targetDir
QString targetDir() const
Definition: knewstuff2/core/installation.cpp:129
ktar.h
job.h
KConfigGroup
KNS::CoreEngine::install
bool install(const QString &payloadfile)
Installs an entry's payload file.
Definition: coreengine.cpp:1333
KConfig
KNS::CoreEngine::signalEntriesFinished
void signalEntriesFinished()
KNS::CoreEngine::signalEntryLoaded
void signalEntryLoaded(KNS::Entry *entry, const KNS::Feed *feed, const KNS::Provider *provider)
KUrl::setFileName
void setFileName(const QString &_txt)
KArchiveDirectory
KConfig::NoAccess
KNS::CoreEngine::signalEntriesFailed
void signalEntriesFailed()
dir
QString dir(const QString &fileClass)
KNS::Installation::setScope
void setScope(Scope scope)
Definition: knewstuff2/core/installation.cpp:99
KUrl::fileName
QString fileName(const DirectoryOptions &options=IgnoreTrailingSlash) const
KNS::Security::ref
static Security * ref()
Definition: knewstuff2/core/security.h:51
KStandardDirs::locateLocal
static QString locateLocal(const char *type, const QString &filename, const KComponentData &cData=KGlobal::mainComponent())
providerhandler.h
KNS::Feed::removeEntry
void removeEntry(Entry *entry)
Removes an association to an entry.
Definition: feed.cpp:78
KIO::FileCopyJob
kstandarddirs.h
KNS::Installation::setInstallPath
void setInstallPath(const QString &dir)
Definition: knewstuff2/core/installation.cpp:79
KNS::Entry::Downloadable
Definition: knewstuff2/core/entry.h:292
KStandardDirs::findResource
QString findResource(const char *type, const QString &filename) const
KProcess::execute
int execute(int msecs=-1)
KNS::CoreEngine::signalProviderChanged
void signalProviderChanged(KNS::Provider *provider)
KNS::Installation::absoluteInstallPath
QString absoluteInstallPath() const
Definition: knewstuff2/core/installation.cpp:139
kWarning
static QDebug kWarning(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
KNS::ProviderLoader
KNewStuff provider loader.
Definition: providerloader.h:48
KNS::CoreEngine::signalPreviewLoaded
void signalPreviewLoaded(KUrl preview)
KUrl::url
QString url(AdjustPathOption trailing=LeaveTrailingSlash) const
kcodecs.h
kaboutdata.h
KNS::Provider::webService
KUrl webService() const
Retrieves the URL to the DXS Web Service.
Definition: knewstuff2/core/provider.cpp:114
KIO::TransferJob
KNS::CoreEngine::setCachePolicy
void setCachePolicy(CachePolicy policy)
Definition: coreengine.cpp:1645
KNS::Installation::setStandardResourceDir
void setStandardResourceDir(const QString &dir)
Definition: knewstuff2/core/installation.cpp:69
KNS::CoreEngine::start
void start()
Starts the engine.
Definition: coreengine.cpp:195
kcomponentdata.h
KNS::Feed
KNewStuff feed.
Definition: feed.h:45
KNS::Installation::installPath
QString installPath() const
Definition: knewstuff2/core/installation.cpp:134
security.h
KNS::Entry::setStatus
void setStatus(Status status)
Sets the entry's status.
Definition: knewstuff2/core/entry.cpp:221
KNS::CoreEngine::setAutomationPolicy
void setAutomationPolicy(AutomationPolicy policy)
Definition: coreengine.cpp:1640
KNS::EntryHandler
Parser and dumper for KNewStuff data entries.
Definition: entryhandler.h:42
coreengine.h
KNS::CoreEngine::signalEntryUploaded
void signalEntryUploaded()
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
KRandom::randomString
QString randomString(int length)
KConfigGroup::readEntry
T readEntry(const QString &key, const T &aDefault) const
KNS::Installation::setCustomName
void setCustomName(bool customname)
Definition: knewstuff2/core/installation.cpp:104
KJob
KNS::Provider
KNewStuff provider container.
Definition: knewstuff2/core/provider.h:51
KNS::CoreEngine::CacheResident
Operate on cache files but never update them.
Definition: coreengine.h:81
KArchiveDirectory::entries
QStringList entries() const
kconfiggroup.h
KNS::CoreEngine::downloadPayload
void downloadPayload(Entry *entry)
Downloads a payload file.
Definition: coreengine.cpp:300
KNS::Entry::Updateable
Definition: knewstuff2/core/entry.h:294
KNS::Installation::signaturePolicy
Policy signaturePolicy() const
Definition: knewstuff2/core/installation.cpp:158
KNS::Installation::ScopeUser
Definition: knewstuff2/core/installation.h:64
QList< Provider * >
KNS::CoreEngine::mergeEntries
void mergeEntries(Entry::List entries, Feed *feed, const Provider *provider)
Definition: coreengine.cpp:1036
KNS::EntryLoader
KNewStuff entry loader.
Definition: entryloader.h:47
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:50:48 by doxygen 1.8.7 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 API Reference

Skip menu "kdelibs 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
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



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