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

Plasma

  • plasma
package.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 * Copyright 2007 by Aaron Seigo <aseigo@kde.org> *
3 * Copyright 2007 by Riccardo Iaconelli <riccardo@kde.org> *
4 * *
5 * This library is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU Library General Public *
7 * License as published by the Free Software Foundation; either *
8 * version 2 of the License, or (at your option) any later version. *
9 * *
10 * This library is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
13 * Library General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU Library General Public License *
16 * along with this library; see the file COPYING.LIB. If not, write to *
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
18 * Boston, MA 02110-1301, USA. *
19 *******************************************************************************/
20 
21 #include "package.h"
22 #include "config-plasma.h"
23 
24 #include <QDir>
25 #include <QFile>
26 #include <QRegExp>
27 #include <QtNetwork/QHostInfo>
28 
29 #ifdef QCA2_FOUND
30 #include <QtCrypto>
31 #endif
32 
33 #include <karchive.h>
34 #include <kcomponentdata.h>
35 #include <kdesktopfile.h>
36 #include <kmimetype.h>
37 #include <kplugininfo.h>
38 #include <kstandarddirs.h>
39 #include <ktar.h>
40 #include <ktempdir.h>
41 #include <ktemporaryfile.h>
42 #include <kzip.h>
43 #include <kdebug.h>
44 
45 #include "authorizationmanager.h"
46 #include "dataenginemanager.h"
47 #include "packagemetadata.h"
48 #include "scripting/scriptengine.h"
49 #include "private/authorizationmanager_p.h"
50 #include "private/componentinstaller_p.h"
51 #include "private/package_p.h"
52 #include "private/plasmoidservice_p.h"
53 #include "private/service_p.h"
54 
55 namespace Plasma
56 {
57 
58 bool copyFolder(QString sourcePath, QString targetPath)
59 {
60  QDir source(sourcePath);
61  if(!source.exists())
62  return false;
63 
64  QDir target(targetPath);
65  if(!target.exists()) {
66  QString targetName = target.dirName();
67  target.cdUp();
68  target.mkdir(targetName);
69  target = QDir(targetPath);
70  }
71 
72  foreach (const QString &fileName, source.entryList(QDir::Files)) {
73  QString sourceFilePath = sourcePath + QDir::separator() + fileName;
74  QString targetFilePath = targetPath + QDir::separator() + fileName;
75 
76  if (!QFile::copy(sourceFilePath, targetFilePath)) {
77  return false;
78  }
79  }
80 
81  foreach (const QString &subFolderName, source.entryList(QDir::AllDirs | QDir::NoDotAndDotDot)) {
82  QString sourceSubFolderPath = sourcePath + QDir::separator() + subFolderName;
83  QString targetSubFolderPath = targetPath + QDir::separator() + subFolderName;
84 
85  if (!copyFolder(sourceSubFolderPath, targetSubFolderPath)) {
86  return false;
87  }
88  }
89 
90  return true;
91 }
92 
93 bool removeFolder(QString folderPath)
94 {
95  QDir folder(folderPath);
96  if(!folder.exists())
97  return false;
98 
99  foreach (const QString &fileName, folder.entryList(QDir::Files)) {
100  if (!QFile::remove(folderPath + QDir::separator() + fileName)) {
101  return false;
102  }
103  }
104 
105  foreach (const QString &subFolderName, folder.entryList(QDir::AllDirs | QDir::NoDotAndDotDot)) {
106  if (!removeFolder(folderPath + QDir::separator() + subFolderName)) {
107  return false;
108  }
109  }
110 
111  QString folderName = folder.dirName();
112  folder.cdUp();
113  return folder.rmdir(folderName);
114 }
115 
116 Package::Package()
117  : d(new PackagePrivate(PackageStructure::Ptr(0), QString()))
118 {
119 }
120 
121 Package::Package(const QString &packageRoot, const QString &package,
122  PackageStructure::Ptr structure)
123  : d(new PackagePrivate(structure, packageRoot, package))
124 {
125 }
126 
127 Package::Package(const QString &packagePath, PackageStructure::Ptr structure)
128  : d(new PackagePrivate(structure, packagePath))
129 {
130 }
131 
132 Package::Package(const Package &other)
133  : d(new PackagePrivate(*other.d))
134 {
135 }
136 
137 Package::~Package()
138 {
139  delete d;
140 }
141 
142 Package &Package::operator=(const Package &rhs)
143 {
144  if (&rhs != this) {
145  *d = *rhs.d;
146  }
147 
148  return *this;
149 }
150 
151 bool Package::isValid() const
152 {
153  return d->isValid();
154 }
155 
156 bool PackagePrivate::isValid()
157 {
158  if (!valid || !structure) {
159  return false;
160  }
161 
162  //search for the file in all prefixes and in all possible paths for each prefix
163  //even if it's a big nested loop, usually there is one prefix and one location
164  //so shouldn't cause too much disk access
165  QStringList prefixes = structure->contentsPrefixPaths();
166  if (prefixes.isEmpty()) {
167  prefixes << QString();
168  }
169 
170  foreach (const char *dir, structure->requiredDirectories()) {
171  bool failed = true;
172  foreach (const QString &path, structure->searchPath(dir)) {
173  foreach (const QString &prefix, prefixes) {
174  if (QFile::exists(structure->path() + prefix + path)) {
175  failed = false;
176  break;
177  }
178  }
179  if (!failed) {
180  break;
181  }
182  }
183 
184  if (failed) {
185  kWarning() << "Could not find required directory" << dir;
186  valid = false;
187  return false;
188  }
189  }
190 
191  foreach (const char *file, structure->requiredFiles()) {
192  bool failed = true;
193  foreach (const QString &path, structure->searchPath(file)) {
194  foreach (const QString &prefix, prefixes) {
195  if (QFile::exists(structure->path() + prefix + path)) {
196  failed = false;
197  break;
198  }
199  }
200  if (!failed) {
201  break;
202  }
203  }
204 
205  if (failed) {
206  kWarning() << "Could not find required file" << file;
207  valid = false;
208  return false;
209  }
210  }
211 
212  valid = true;
213  return true;
214 }
215 
216 QString Package::filePath(const char *fileType, const QString &filename) const
217 {
218  if (!d->valid) {
219  //kDebug() << "package is not valid";
220  return QString();
221  }
222 
223  QStringList paths;
224 
225  if (qstrlen(fileType) != 0) {
226  paths = d->structure->searchPath(fileType);
227 
228  if (paths.isEmpty()) {
229  //kDebug() << "no matching path came of it, while looking for" << fileType << filename;
230  return QString();
231  }
232  } else {
233  //when filetype is empty paths is always empty, so try with an empty string
234  paths << QString();
235  }
236 
237  //Nested loop, but in the medium case resolves to just one iteration
238  QStringList prefixes = d->structure->contentsPrefixPaths();
239  if (prefixes.isEmpty()) {
240  prefixes << QString();
241  }
242 
243  //kDebug() << "prefixes:" << prefixes.count() << prefixes;
244  foreach (const QString &contentsPrefix, prefixes) {
245  const QString prefix(d->structure->path() + contentsPrefix);
246 
247  foreach (const QString &path, paths) {
248  QString file = prefix + path;
249 
250  if (!filename.isEmpty()) {
251  file.append("/").append(filename);
252  }
253 
254  //kDebug() << "testing" << file << QFile::exists("/bin/ls") << QFile::exists(file);
255  if (QFile::exists(file)) {
256  if (d->structure->allowExternalPaths()) {
257  //kDebug() << "found" << file;
258  return file;
259  }
260 
261  // ensure that we don't return files outside of our base path
262  // due to symlink or ../ games
263  QDir dir(file);
264  QString canonicalized = dir.canonicalPath() + QDir::separator();
265 
266  //kDebug() << "testing that" << canonicalized << "is in" << d->structure->path();
267  if (canonicalized.startsWith(d->structure->path())) {
268  //kDebug() << "found" << file;
269  return file;
270  }
271  }
272  }
273  }
274 
275  //kDebug() << fileType << filename << "does not exist in" << prefixes << "at root" << d->structure->path();
276  return QString();
277 }
278 
279 QString Package::filePath(const char *fileType) const
280 {
281  return filePath(fileType, QString());
282 }
283 
284 QStringList Package::entryList(const char *fileType) const
285 {
286  if (!d->valid) {
287  return QStringList();
288  }
289 
290  return d->structure->entryList(fileType);
291 }
292 
293 PackageMetadata Package::metadata() const
294 {
295  if (d->structure) {
296  return d->structure->metadata();
297  }
298 
299  return PackageMetadata();
300 }
301 
302 void Package::setPath(const QString &path)
303 {
304  d->setPathFromStructure(path);
305 }
306 
307 const QString Package::path() const
308 {
309  return d->structure ? d->structure->path() : QString();
310 }
311 
312 const PackageStructure::Ptr Package::structure() const
313 {
314  return d->structure;
315 }
316 
317 #ifdef QCA2_FOUND
318 void PackagePrivate::updateHash(const QString &basePath, const QString &subPath, const QDir &dir, QCA::Hash &hash)
319 {
320  // hash is calculated as a function of:
321  // * files ordered alphabetically by name, with each file's:
322  // * path relative to the content root
323  // * file data
324  // * directories ordered alphabetically by name, with each dir's:
325  // * path relative to the content root
326  // * file listing (recursing)
327  // symlinks (in both the file and dir case) are handled by adding
328  // the name of the symlink itself and the abs path of what it points to
329 
330  const QDir::SortFlags sorting = QDir::Name | QDir::IgnoreCase;
331  const QDir::Filters filters = QDir::Hidden | QDir::System | QDir::NoDotAndDotDot;
332  foreach (const QString &file, dir.entryList(QDir::Files | filters, sorting)) {
333  if (!subPath.isEmpty()) {
334  hash.update(subPath.toUtf8());
335  }
336 
337  hash.update(file.toUtf8());
338 
339  QFileInfo info(dir.path() + '/' + file);
340  if (info.isSymLink()) {
341  hash.update(info.symLinkTarget().toUtf8());
342  } else {
343  QFile f(info.filePath());
344  if (f.open(QIODevice::ReadOnly)) {
345  while (!f.atEnd()) {
346  hash.update(f.read(1024));
347  }
348  } else {
349  kWarning() << "could not add" << f.fileName() << "to the hash; file could not be opened for reading. "
350  << "permissions fail?" << info.permissions() << info.isFile();
351  }
352  }
353  }
354 
355  foreach (const QString &subDirPath, dir.entryList(QDir::Dirs | filters, sorting)) {
356  const QString relativePath = subPath + subDirPath + '/';
357  hash.update(relativePath.toUtf8());
358 
359  QDir subDir(dir.path());
360  subDir.cd(subDirPath);
361 
362  if (subDir.path() != subDir.canonicalPath()) {
363  hash.update(subDir.canonicalPath().toUtf8());
364  } else {
365  updateHash(basePath, relativePath, subDir, hash);
366  }
367  }
368 }
369 #endif
370 
371 QString Package::contentsHash() const
372 {
373 #ifdef QCA2_FOUND
374  if (!d->valid) {
375  kWarning() << "can not create hash due to Package being invalid";
376  return QString();
377  }
378 
379  //FIXME: the initializer should go somewhere global to be shared between all plasma uses?
380  QCA::Initializer init;
381  if (!QCA::isSupported("sha1")) {
382  kWarning() << "can not create hash for" << path() << "due to no SHA1 support in QCA2";
383  return QString();
384  }
385 
386  QCA::Hash hash("sha1");
387  QString metadataPath = d->structure->path() + "metadata.desktop";
388  if (QFile::exists(metadataPath)) {
389  QFile f(metadataPath);
390  if (f.open(QIODevice::ReadOnly)) {
391  while (!f.atEnd()) {
392  hash.update(f.read(1024));
393  }
394  } else {
395  kWarning() << "could not add" << f.fileName() << "to the hash; file could not be opened for reading.";
396  }
397  } else {
398  kWarning() << "no metadata at" << metadataPath;
399  }
400 
401  QStringList prefixes = d->structure->contentsPrefixPaths();
402  if (prefixes.isEmpty()) {
403  prefixes << QString();
404  }
405 
406  foreach (QString prefix, prefixes) {
407  const QString basePath = d->structure->path() + prefix;
408  QDir dir(basePath);
409 
410  if (!dir.exists()) {
411  return QString();
412  }
413 
414  d->updateHash(basePath, QString(), dir, hash);
415  }
416  return QCA::arrayToHex(hash.final().toByteArray());
417 #else
418  // no QCA2!
419  kWarning() << "can not create hash for" << path() << "due to no cryptographic support (QCA2)";
420  return QString();
421 #endif
422 }
423 
424 //TODO: provide a version of this that allows one to ask for certain types of packages, etc?
425 // should we be using KService here instead/as well?
426 QStringList Package::listInstalled(const QString &packageRoot) // static
427 {
428  QDir dir(packageRoot);
429 
430  if (!dir.exists()) {
431  return QStringList();
432  }
433 
434  QStringList packages;
435 
436  foreach (const QString &sdir, dir.entryList(QDir::AllDirs | QDir::Readable)) {
437  QString metadata = packageRoot + '/' + sdir + "/metadata.desktop";
438  if (QFile::exists(metadata)) {
439  PackageMetadata m(metadata);
440  packages << m.pluginName();
441  }
442  }
443 
444  return packages;
445 }
446 
447 QStringList Package::listInstalledPaths(const QString &packageRoot) // static
448 {
449  QDir dir(packageRoot);
450 
451  if (!dir.exists()) {
452  return QStringList();
453  }
454 
455  QStringList packages;
456 
457  foreach (const QString &sdir, dir.entryList(QDir::AllDirs | QDir::Readable)) {
458  QString metadata = packageRoot + '/' + sdir + "/metadata.desktop";
459  if (QFile::exists(metadata)) {
460  packages << sdir;
461  }
462  }
463 
464  return packages;
465 }
466 
467 bool Package::installPackage(const QString &package,
468  const QString &packageRoot,
469  const QString &servicePrefix) // static
470 {
471  //TODO: report *what* failed if something does fail
472  QDir root(packageRoot);
473 
474  if (!root.exists()) {
475  KStandardDirs::makeDir(packageRoot);
476  if (!root.exists()) {
477  kWarning() << "Could not create package root directory:" << packageRoot;
478  return false;
479  }
480  }
481 
482  QFileInfo fileInfo(package);
483  if (!fileInfo.exists()) {
484  kWarning() << "No such file:" << package;
485  return false;
486  }
487 
488  QString path;
489  KTempDir tempdir;
490  bool archivedPackage = false;
491 
492  if (fileInfo.isDir()) {
493  // we have a directory, so let's just install what is in there
494  path = package;
495 
496  // make sure we end in a slash!
497  if (path[path.size() - 1] != '/') {
498  path.append('/');
499  }
500  } else {
501  KArchive *archive = 0;
502  KMimeType::Ptr mimetype = KMimeType::findByPath(package);
503 
504  if (mimetype->is("application/zip")) {
505  archive = new KZip(package);
506  } else if (mimetype->is("application/x-compressed-tar") ||
507  mimetype->is("application/x-tar")|| mimetype->is("application/x-bzip-compressed-tar") ||
508  mimetype->is("application/x-xz-compressed-tar") || mimetype->is("application/x-lzma-compressed-tar")) {
509  archive = new KTar(package);
510  } else {
511  kWarning() << "Could not open package file, unsupported archive format:" << package << mimetype->name();
512  return false;
513  }
514 
515  if (!archive->open(QIODevice::ReadOnly)) {
516  kWarning() << "Could not open package file:" << package;
517  delete archive;
518  return false;
519  }
520 
521  archivedPackage = true;
522  path = tempdir.name();
523 
524  const KArchiveDirectory *source = archive->directory();
525  source->copyTo(path);
526 
527  QStringList entries = source->entries();
528  if (entries.count() == 1) {
529  const KArchiveEntry *entry = source->entry(entries[0]);
530  if (entry->isDirectory()) {
531  path.append(entry->name()).append("/");
532  }
533  }
534  delete archive;
535  }
536 
537  QString metadataPath = path + "metadata.desktop";
538  if (!QFile::exists(metadataPath)) {
539  kWarning() << "No metadata file in package" << package << metadataPath;
540  return false;
541  }
542 
543  PackageMetadata meta(metadataPath);
544  QString targetName = meta.pluginName();
545 
546  if (targetName.isEmpty()) {
547  kWarning() << "Package plugin name not specified";
548  return false;
549  }
550 
551  // Ensure that package names are safe so package uninstall can't inject
552  // bad characters into the paths used for removal.
553  QRegExp validatePluginName("^[\\w-\\.]+$"); // Only allow letters, numbers, underscore and period.
554  if (!validatePluginName.exactMatch(targetName)) {
555  kWarning() << "Package plugin name " << targetName << "contains invalid characters";
556  return false;
557  }
558 
559  targetName = packageRoot + '/' + targetName;
560  if (QFile::exists(targetName)) {
561  kWarning() << targetName << "already exists";
562  return false;
563  }
564 
565  if (archivedPackage) {
566  // it's in a temp dir, so just move it over.
567  const bool ok = copyFolder(path, targetName);
568  removeFolder(path);
569  if (!ok) {
570  kWarning() << "Could not move package to destination:" << targetName;
571  return false;
572  }
573  } else {
574  kDebug() << "************************** 12";
575  // it's a directory containing the stuff, so copy the contents rather
576  // than move them
577  const bool ok = copyFolder(path, targetName);
578  kDebug() << "************************** 13";
579  if (!ok) {
580  kWarning() << "Could not copy package to destination:" << targetName;
581  return false;
582  }
583  }
584 
585  if (archivedPackage) {
586  // no need to remove the temp dir (which has been successfully moved if it's an archive)
587  tempdir.setAutoRemove(false);
588  }
589  // check for missing dependencies
590  QString requiredScriptEngine = meta.implementationApi();
591  if (!requiredScriptEngine.isEmpty()) {
592  // figure out the component type to query for
593  ComponentTypes componentTypes = static_cast<ComponentTypes>(0);
594  QStringList serviceTypes = meta.serviceType().split(',');
595  if (serviceTypes.contains("Plasma/Applet")) {
596  componentTypes |= AppletComponent;
597  }
598  if (serviceTypes.contains("Plasma/DataEngine")) {
599  componentTypes |= DataEngineComponent;
600  }
601  if (serviceTypes.contains("Plasma/Runner")) {
602  componentTypes |= RunnerComponent;
603  }
604  if (serviceTypes.contains("Plasma/Wallpaper")) {
605  componentTypes |= WallpaperComponent;
606  }
607  if (componentTypes // ignore non-Plasma/* components (e.g. KWin/Script)
608  && !knownLanguages(componentTypes).contains(requiredScriptEngine)) {
609  // install the missing script engine
610  // force prompting because the user has just explicitly installed a widget
611  ComponentInstaller::self()->installMissingComponent("scriptengine", requiredScriptEngine, 0, true);
612  }
613  }
614  QStringList requiredDataEngines = meta.requiredDataEngines();
615  if (requiredDataEngines.isEmpty()) {
616  // check whether this was explicitly specified as empty
617  QString metaPath = targetName + "/metadata.desktop";
618  KDesktopFile df(metaPath);
619  KConfigGroup cg = df.desktopGroup();
620  if (!cg.hasKey("X-Plasma-RequiredDataEngines")) {
621  // not specified at all, try running the dependency extraction
622  requiredDataEngines = ComponentInstaller::self()->extractDataEngineDependencies(targetName,
623  requiredScriptEngine);
624  }
625  }
626  if (!requiredDataEngines.isEmpty()) {
627  QStringList knownDataEngines = DataEngineManager::self()->listAllEngines(meta.application());
628  foreach (const QString &requiredDataEngine, requiredDataEngines) {
629  if (!knownDataEngines.contains(requiredDataEngine)) {
630  // install the missing data engine
631  // force prompting because the user has just explicitly installed a widget
632  ComponentInstaller::self()->installMissingComponent("dataengine", requiredDataEngine, 0, true);
633  }
634  }
635  }
636 
637  if (!servicePrefix.isEmpty()) {
638  // and now we register it as a service =)
639  kDebug() << "************************** 1";
640  QString metaPath = targetName + "/metadata.desktop";
641  kDebug() << "************************** 2";
642  KDesktopFile df(metaPath);
643  KConfigGroup cg = df.desktopGroup();
644  kDebug() << "************************** 3";
645 
646  // Q: should not installing it as a service disqualify it?
647  // Q: i don't think so since KServiceTypeTrader may not be
648  // used by the installing app in any case, and the
649  // package is properly installed - aseigo
650 
651  //TODO: reduce code duplication with registerPackage below
652 
653  QString serviceName = servicePrefix + meta.pluginName();
654 
655  QString service = KStandardDirs::locateLocal("services", serviceName + ".desktop");
656  kDebug() << "************************** 4";
657  const bool ok = QFile::copy(metaPath, service);
658  kDebug() << "************************** 5";
659  if (ok) {
660  // the icon in the installed file needs to point to the icon in the
661  // installation dir!
662  QString iconPath = targetName + '/' + cg.readEntry("Icon");
663  QFile icon(iconPath);
664  if (icon.exists()) {
665  KDesktopFile df(service);
666  KConfigGroup cg = df.desktopGroup();
667  cg.writeEntry("Icon", iconPath);
668  }
669  } else {
670  kWarning() << "Could not register package as service (this is not necessarily fatal):" << serviceName;
671  }
672  kDebug() << "************************** 7";
673  }
674 
675  return true;
676 }
677 
678 bool Package::uninstallPackage(const QString &pluginName,
679  const QString &packageRoot,
680  const QString &servicePrefix) // static
681 {
682  // We need to remove the package directory and its metadata file.
683  QString targetName = pluginName;
684  targetName = packageRoot + '/' + targetName;
685 
686  if (!QFile::exists(targetName)) {
687  kWarning() << targetName << "does not exist";
688  return false;
689  }
690 
691  QString serviceName = servicePrefix + pluginName;
692 
693  QString service = KStandardDirs::locateLocal("services", serviceName + ".desktop");
694  kDebug() << "Removing service file " << service;
695  bool ok = QFile::remove(service);
696 
697  if (!ok) {
698  kWarning() << "Unable to remove " << service;
699  }
700 
701  ok = removeFolder(targetName);
702  const QString errorString("unknown");
703  if (!ok) {
704  kWarning() << "Could not delete package from:" << targetName << " : " << errorString;
705  return false;
706  }
707 
708  return true;
709 }
710 
711 bool Package::registerPackage(const PackageMetadata &data, const QString &iconPath)
712 {
713  QString serviceName("plasma-applet-" + data.pluginName());
714  QString service = KStandardDirs::locateLocal("services", serviceName + ".desktop");
715 
716  if (data.pluginName().isEmpty()) {
717  return false;
718  }
719 
720  data.write(service);
721 
722  KDesktopFile config(service);
723  KConfigGroup cg = config.desktopGroup();
724  const QString type = data.type().isEmpty() ? "Service" : data.type();
725  cg.writeEntry("Type", type);
726  const QString serviceTypes = data.serviceType().isNull() ? "Plasma/Applet,Plasma/Containment" : data.serviceType();
727  cg.writeEntry("X-KDE-ServiceTypes", serviceTypes);
728  cg.writeEntry("X-KDE-PluginInfo-EnabledByDefault", true);
729 
730  QFile icon(iconPath);
731  if (icon.exists()) {
732  //FIXME: the '/' search will break on non-UNIX. do we care?
733  QString installedIcon("plasma_applet_" + data.pluginName() +
734  iconPath.right(iconPath.length() - iconPath.lastIndexOf("/")));
735  cg.writeEntry("Icon", installedIcon);
736  installedIcon = KStandardDirs::locateLocal("icon", installedIcon);
737  QFile::copy(iconPath, installedIcon);
738  }
739 
740  return true;
741 }
742 
743 bool Package::createPackage(const PackageMetadata &metadata,
744  const QString &source,
745  const QString &destination,
746  const QString &icon) // static
747 {
748  Q_UNUSED(icon)
749  if (!metadata.isValid()) {
750  kWarning() << "Metadata file is not complete";
751  return false;
752  }
753 
754  // write metadata in a temporary file
755  KTemporaryFile metadataFile;
756  if (!metadataFile.open()) {
757  return false;
758  }
759  metadata.write(metadataFile.fileName());
760 
761  // put everything into a zip archive
762  KZip creation(destination);
763  creation.setCompression(KZip::NoCompression);
764  if (!creation.open(QIODevice::WriteOnly)) {
765  return false;
766  }
767 
768  creation.addLocalFile(metadataFile.fileName(), "metadata.desktop");
769  creation.addLocalDirectory(source, "contents");
770  creation.close();
771  return true;
772 }
773 
774 PackagePrivate::PackagePrivate(const PackageStructure::Ptr st, const QString &p)
775  : structure(st),
776  service(0)
777 {
778  setPathFromStructure(p);
779 }
780 
781 PackagePrivate::PackagePrivate(const PackageStructure::Ptr st, const QString &packageRoot, const QString &path)
782  : structure(st),
783  service(0)
784 {
785  setPathFromStructure(packageRoot.isEmpty() ? path : packageRoot % "/" % path);
786 }
787 
788 PackagePrivate::PackagePrivate(const PackagePrivate &other)
789  : structure(other.structure),
790  service(other.service),
791  valid(other.valid)
792 {
793 }
794 
795 PackagePrivate::~PackagePrivate()
796 {
797 }
798 
799 PackagePrivate &PackagePrivate::operator=(const PackagePrivate &rhs)
800 {
801  structure = rhs.structure;
802  service = rhs.service;
803  valid = rhs.valid;
804  return *this;
805 }
806 
807 void PackagePrivate::setPathFromStructure(const QString &path)
808 {
809  if (!structure) {
810  valid = false;
811  return;
812  }
813 
814  QStringList paths;
815  if (path.isEmpty()) {
816  paths << structure->defaultPackageRoot();
817  } else if (QDir::isRelativePath(path)) {
818  QString p = structure->defaultPackageRoot() % "/" % path % "/";
819 
820  if (QDir::isRelativePath(p)) {
821  paths = KGlobal::dirs()->findDirs("data", p);
822  } else {
823  paths << p;
824  }
825  } else {
826  paths << path;
827  }
828 
829  foreach (const QString &p, paths) {
830  structure->setPath(p);
831  // reset valid, otherwise isValid() short-circuits
832  valid = true;
833  if (isValid()) {
834  return;
835  }
836  }
837 
838  valid = false;
839  structure->setPath(QString());
840 }
841 
842 void PackagePrivate::publish(AnnouncementMethods methods)
843 {
844  if (!structure) {
845  return;
846  }
847 
848  if (!service) {
849  service = new PlasmoidService(structure->path());
850  }
851 
852  QString resourceName =
853  i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
854  "%1 on %2", structure->metadata().name(), QHostInfo::localHostName());
855  kDebug() << "publishing package under name " << resourceName;
856  service->d->publish(methods, resourceName, structure->metadata());
857 }
858 
859 void PackagePrivate::unpublish()
860 {
861  if (service) {
862  service->d->unpublish();
863  }
864 }
865 
866 bool PackagePrivate::isPublished() const
867 {
868  if (service) {
869  return service->d->isPublished();
870  } else {
871  return false;
872  }
873 }
874 
875 } // Namespace
packagemetadata.h
Plasma::WallpaperComponent
Plasma::Wallpaper based plugins.
Definition: plasma.h:231
Plasma::PackageMetadata::serviceType
QString serviceType() const
Definition: packagemetadata.cpp:172
authorizationmanager.h
Plasma::PackageMetadata::pluginName
QString pluginName() const
Definition: packagemetadata.cpp:262
Plasma::PackageMetadata::application
QString application() const
Definition: packagemetadata.cpp:212
Plasma::Package::listInstalled
static QStringList listInstalled(const QString &packageRoot)
Returns a list of all installed packages by name.
Definition: package.cpp:426
Plasma::Package::listInstalledPaths
static QStringList listInstalledPaths(const QString &packageRoot)
Returns a list of all paths of installed packages in the given root.
Definition: package.cpp:447
Plasma::PackageMetadata::write
void write(const QString &filename) const
Writes out the metadata to filename, which should be a .desktop file.
Definition: packagemetadata.cpp:88
Plasma::Package::structure
const PackageStructure::Ptr structure() const
Definition: package.cpp:312
Plasma
Namespace for everything in libplasma.
Definition: abstractdialogmanager.cpp:24
Plasma::PackageMetadata::isValid
bool isValid() const
Definition: packagemetadata.cpp:80
Plasma::Package::registerPackage
static bool registerPackage(const PackageMetadata &data, const QString &iconPath)
Registers a package described by the given desktop file.
Definition: package.cpp:711
Plasma::Package::uninstallPackage
static bool uninstallPackage(const QString &package, const QString &packageRoot, const QString &servicePrefix)
Uninstalls a package.
Definition: package.cpp:678
Plasma::Package::installPackage
static bool installPackage(const QString &package, const QString &packageRoot, const QString &servicePrefix)
Installs a package.
Definition: package.cpp:467
Plasma::Package::path
const QString path() const
Definition: package.cpp:307
Plasma::PackageMetadata::requiredDataEngines
QStringList requiredDataEngines() const
Definition: packagemetadata.cpp:252
Plasma::copyFolder
bool copyFolder(QString sourcePath, QString targetPath)
Definition: package.cpp:58
Plasma::PackageMetadata::type
QString type() const
Definition: packagemetadata.cpp:242
Plasma::Package::operator=
Package & operator=(const Package &rhs)
Assignment operator.
Definition: package.cpp:142
Plasma::PackageStructure::Ptr
KSharedPtr< PackageStructure > Ptr
Definition: packagestructure.h:77
Plasma::Package::isValid
bool isValid() const
Definition: package.cpp:151
Plasma::Package
object representing an installed Plasmagik package
Definition: package.h:42
Plasma::DataEngineManager::self
static DataEngineManager * self()
Singleton pattern accessor.
Definition: dataenginemanager.cpp:90
dataenginemanager.h
Plasma::removeFolder
bool removeFolder(QString folderPath)
Definition: package.cpp:93
Plasma::RunnerComponent
Plasma::AbstractRunner based plugsin.
Definition: plasma.h:228
Plasma::DataEngineManager::listAllEngines
static QStringList listAllEngines(const QString &parentApp=QString())
Definition: dataenginemanager.cpp:160
Plasma::Package::entryList
QStringList entryList(const char *fileType) const
Get the list of files of a given type.
Definition: package.cpp:284
Plasma::Package::metadata
PackageMetadata metadata() const
Definition: package.cpp:293
Plasma::Package::~Package
~Package()
Definition: package.cpp:137
Plasma::Package::contentsHash
QString contentsHash() const
Definition: package.cpp:371
Plasma::AppletComponent
Plasma::Applet based plugins.
Definition: plasma.h:226
Plasma::PackageMetadata::implementationApi
QString implementationApi() const
Definition: packagemetadata.cpp:247
Plasma::type
static QScriptValue type(QScriptContext *ctx, QScriptEngine *eng)
Definition: easingcurve.cpp:63
Plasma::DataEngineComponent
Plasma::DataEngine based plugins.
Definition: plasma.h:227
package.h
Plasma::Package::Package
Package()
Default constructor that creates an invalid Package.
Definition: package.cpp:116
Plasma::knownLanguages
QStringList knownLanguages(ComponentTypes types)
Definition: scriptengine.cpp:67
scriptengine.h
Plasma::PackageMetadata
Provides metadata for a Package.
Definition: packagemetadata.h:40
Plasma::Package::setPath
void setPath(const QString &path)
Sets the path to the root of this package.
Definition: package.cpp:302
Plasma::PackageStructure
A description of the expected file structure of a given package type.
Definition: packagestructure.h:72
Plasma::Package::filePath
QString filePath(const char *fileType, const QString &filename) const
Get the path to a given file.
Definition: package.cpp:216
Plasma::Package::createPackage
static bool createPackage(const PackageMetadata &metadata, const QString &source, const QString &destination, const QString &icon=QString())
Creates a package based on the metadata from the files contained in the source directory.
Definition: package.cpp:743
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Fri Nov 14 2014 00:36:53 by doxygen 1.8.8 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Plasma

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

kdelibs-4.14.3 API Reference

Skip menu "kdelibs-4.14.3 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