• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.9.4 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  if (!d->valid) {
154  return false;
155  }
156 
157  //search for the file in all prefixes and in all possible paths for each prefix
158  //even if it's a big nested loop, usually there is one prefix and one location
159  //so shouldn't cause too much disk access
160  QStringList prefixes = d->structure->contentsPrefixPaths();
161  if (prefixes.isEmpty()) {
162  prefixes << QString();
163  }
164 
165  foreach (const char *dir, d->structure->requiredDirectories()) {
166  bool failed = true;
167  foreach (const QString &path, d->structure->searchPath(dir)) {
168  foreach (const QString &prefix, prefixes) {
169  if (QFile::exists(d->structure->path() + prefix + path)) {
170  failed = false;
171  break;
172  }
173  }
174  if (!failed) {
175  break;
176  }
177  }
178 
179  if (failed) {
180  kWarning() << "Could not find required directory" << dir;
181  d->valid = false;
182  return false;
183  }
184  }
185 
186  foreach (const char *file, d->structure->requiredFiles()) {
187  bool failed = true;
188  foreach (const QString &path, d->structure->searchPath(file)) {
189  foreach (const QString &prefix, prefixes) {
190  if (QFile::exists(d->structure->path() + prefix + path)) {
191  failed = false;
192  break;
193  }
194  }
195  if (!failed) {
196  break;
197  }
198  }
199 
200  if (failed) {
201  kWarning() << "Could not find required file" << file;
202  d->valid = false;
203  return false;
204  }
205  }
206 
207  return true;
208 }
209 
210 QString Package::filePath(const char *fileType, const QString &filename) const
211 {
212  if (!d->valid) {
213  //kDebug() << "package is not valid";
214  return QString();
215  }
216 
217  QStringList paths;
218 
219  if (qstrlen(fileType) != 0) {
220  paths = d->structure->searchPath(fileType);
221 
222  if (paths.isEmpty()) {
223  //kDebug() << "no matching path came of it, while looking for" << fileType << filename;
224  return QString();
225  }
226  } else {
227  //when filetype is empty paths is always empty, so try with an empty string
228  paths << QString();
229  }
230 
231  //Nested loop, but in the medium case resolves to just one iteration
232  QStringList prefixes = d->structure->contentsPrefixPaths();
233  if (prefixes.isEmpty()) {
234  prefixes << QString();
235  }
236 
237  //kDebug() << "prefixes:" << prefixes.count() << prefixes;
238  foreach (const QString &contentsPrefix, prefixes) {
239  const QString prefix(d->structure->path() + contentsPrefix);
240 
241  foreach (const QString &path, paths) {
242  QString file = prefix + path;
243 
244  if (!filename.isEmpty()) {
245  file.append("/").append(filename);
246  }
247 
248  //kDebug() << "testing" << file << QFile::exists("/bin/ls") << QFile::exists(file);
249  if (QFile::exists(file)) {
250  if (d->structure->allowExternalPaths()) {
251  //kDebug() << "found" << file;
252  return file;
253  }
254 
255  // ensure that we don't return files outside of our base path
256  // due to symlink or ../ games
257  QDir dir(file);
258  QString canonicalized = dir.canonicalPath() + QDir::separator();
259 
260  //kDebug() << "testing that" << canonicalized << "is in" << d->structure->path();
261  if (canonicalized.startsWith(d->structure->path())) {
262  //kDebug() << "found" << file;
263  return file;
264  }
265  }
266  }
267  }
268 
269  //kDebug() << fileType << filename << "does not exist in" << prefixes << "at root" << d->structure->path();
270  return QString();
271 }
272 
273 QString Package::filePath(const char *fileType) const
274 {
275  return filePath(fileType, QString());
276 }
277 
278 QStringList Package::entryList(const char *fileType) const
279 {
280  if (!d->valid) {
281  return QStringList();
282  }
283 
284  return d->structure->entryList(fileType);
285 }
286 
287 PackageMetadata Package::metadata() const
288 {
289  if (d->structure) {
290  return d->structure->metadata();
291  }
292 
293  return PackageMetadata();
294 }
295 
296 void Package::setPath(const QString &path)
297 {
298  if (d->structure) {
299  d->structure->setPath(path);
300  d->valid = !d->structure->path().isEmpty();
301  }
302 }
303 
304 const QString Package::path() const
305 {
306  return d->structure ? d->structure->path() : QString();
307 }
308 
309 const PackageStructure::Ptr Package::structure() const
310 {
311  return d->structure;
312 }
313 
314 #ifdef QCA2_FOUND
315 void PackagePrivate::updateHash(const QString &basePath, const QString &subPath, const QDir &dir, QCA::Hash &hash)
316 {
317  // hash is calculated as a function of:
318  // * files ordered alphabetically by name, with each file's:
319  // * path relative to the content root
320  // * file data
321  // * directories ordered alphabetically by name, with each dir's:
322  // * path relative to the content root
323  // * file listing (recursing)
324  // symlinks (in both the file and dir case) are handled by adding
325  // the name of the symlink itself and the abs path of what it points to
326 
327  const QDir::SortFlags sorting = QDir::Name | QDir::IgnoreCase;
328  const QDir::Filters filters = QDir::Hidden | QDir::System | QDir::NoDotAndDotDot;
329  foreach (const QString &file, dir.entryList(QDir::Files | filters, sorting)) {
330  if (!subPath.isEmpty()) {
331  hash.update(subPath.toUtf8());
332  }
333 
334  hash.update(file.toUtf8());
335 
336  QFileInfo info(dir.path() + '/' + file);
337  if (info.isSymLink()) {
338  hash.update(info.symLinkTarget().toUtf8());
339  } else {
340  QFile f(info.filePath());
341  if (f.open(QIODevice::ReadOnly)) {
342  while (!f.atEnd()) {
343  hash.update(f.read(1024));
344  }
345  } else {
346  kWarning() << "could not add" << f.fileName() << "to the hash; file could not be opened for reading. "
347  << "permissions fail?" << info.permissions() << info.isFile();
348  }
349  }
350  }
351 
352  foreach (const QString &subDirPath, dir.entryList(QDir::Dirs | filters, sorting)) {
353  const QString relativePath = subPath + subDirPath + '/';
354  hash.update(relativePath.toUtf8());
355 
356  QDir subDir(dir.path());
357  subDir.cd(subDirPath);
358 
359  if (subDir.path() != subDir.canonicalPath()) {
360  hash.update(subDir.canonicalPath().toUtf8());
361  } else {
362  updateHash(basePath, relativePath, subDir, hash);
363  }
364  }
365 }
366 #endif
367 
368 QString Package::contentsHash() const
369 {
370 #ifdef QCA2_FOUND
371  if (!d->valid) {
372  kWarning() << "can not create hash due to Package being invalid";
373  return QString();
374  }
375 
376  //FIXME: the initializer should go somewhere global to be shared between all plasma uses?
377  QCA::Initializer init;
378  if (!QCA::isSupported("sha1")) {
379  kWarning() << "can not create hash for" << path() << "due to no SHA1 support in QCA2";
380  return QString();
381  }
382 
383  QCA::Hash hash("sha1");
384  QString metadataPath = d->structure->path() + "metadata.desktop";
385  if (QFile::exists(metadataPath)) {
386  QFile f(metadataPath);
387  if (f.open(QIODevice::ReadOnly)) {
388  while (!f.atEnd()) {
389  hash.update(f.read(1024));
390  }
391  } else {
392  kWarning() << "could not add" << f.fileName() << "to the hash; file could not be opened for reading.";
393  }
394  } else {
395  kWarning() << "no metadata at" << metadataPath;
396  }
397 
398  QStringList prefixes = d->structure->contentsPrefixPaths();
399  if (prefixes.isEmpty()) {
400  prefixes << QString();
401  }
402 
403  foreach (QString prefix, prefixes) {
404  const QString basePath = d->structure->path() + prefix;
405  QDir dir(basePath);
406 
407  if (!dir.exists()) {
408  return QString();
409  }
410 
411  d->updateHash(basePath, QString(), dir, hash);
412  }
413  return QCA::arrayToHex(hash.final().toByteArray());
414 #else
415  // no QCA2!
416  kWarning() << "can not create hash for" << path() << "due to no cryptographic support (QCA2)";
417  return QString();
418 #endif
419 }
420 
421 //TODO: provide a version of this that allows one to ask for certain types of packages, etc?
422 // should we be using KService here instead/as well?
423 QStringList Package::listInstalled(const QString &packageRoot) // static
424 {
425  QDir dir(packageRoot);
426 
427  if (!dir.exists()) {
428  return QStringList();
429  }
430 
431  QStringList packages;
432 
433  foreach (const QString &sdir, dir.entryList(QDir::AllDirs | QDir::Readable)) {
434  QString metadata = packageRoot + '/' + sdir + "/metadata.desktop";
435  if (QFile::exists(metadata)) {
436  PackageMetadata m(metadata);
437  packages << m.pluginName();
438  }
439  }
440 
441  return packages;
442 }
443 
444 QStringList Package::listInstalledPaths(const QString &packageRoot) // static
445 {
446  QDir dir(packageRoot);
447 
448  if (!dir.exists()) {
449  return QStringList();
450  }
451 
452  QStringList packages;
453 
454  foreach (const QString &sdir, dir.entryList(QDir::AllDirs | QDir::Readable)) {
455  QString metadata = packageRoot + '/' + sdir + "/metadata.desktop";
456  if (QFile::exists(metadata)) {
457  packages << sdir;
458  }
459  }
460 
461  return packages;
462 }
463 
464 bool Package::installPackage(const QString &package,
465  const QString &packageRoot,
466  const QString &servicePrefix) // static
467 {
468  //TODO: report *what* failed if something does fail
469  QDir root(packageRoot);
470 
471  if (!root.exists()) {
472  KStandardDirs::makeDir(packageRoot);
473  if (!root.exists()) {
474  kWarning() << "Could not create package root directory:" << packageRoot;
475  return false;
476  }
477  }
478 
479  QFileInfo fileInfo(package);
480  if (!fileInfo.exists()) {
481  kWarning() << "No such file:" << package;
482  return false;
483  }
484 
485  QString path;
486  KTempDir tempdir;
487  bool archivedPackage = false;
488 
489  if (fileInfo.isDir()) {
490  // we have a directory, so let's just install what is in there
491  path = package;
492 
493  // make sure we end in a slash!
494  if (path[path.size() - 1] != '/') {
495  path.append('/');
496  }
497  } else {
498  KArchive *archive = 0;
499  KMimeType::Ptr mimetype = KMimeType::findByPath(package);
500 
501  if (mimetype->is("application/zip")) {
502  archive = new KZip(package);
503  } else if (mimetype->is("application/x-compressed-tar") ||
504  mimetype->is("application/x-tar")|| mimetype->is("application/x-bzip-compressed-tar") ||
505  mimetype->is("application/x-xz") || mimetype->is("application/x-lzma")) {
506  archive = new KTar(package);
507  } else {
508  kWarning() << "Could not open package file, unsupported archive format:" << package << mimetype->name();
509  return false;
510  }
511 
512  if (!archive->open(QIODevice::ReadOnly)) {
513  kWarning() << "Could not open package file:" << package;
514  delete archive;
515  return false;
516  }
517 
518  archivedPackage = true;
519  path = tempdir.name();
520 
521  const KArchiveDirectory *source = archive->directory();
522  source->copyTo(path);
523 
524  QStringList entries = source->entries();
525  if (entries.count() == 1) {
526  const KArchiveEntry *entry = source->entry(entries[0]);
527  if (entry->isDirectory()) {
528  path.append(entry->name()).append("/");
529  }
530  }
531  delete archive;
532  }
533 
534  QString metadataPath = path + "metadata.desktop";
535  if (!QFile::exists(metadataPath)) {
536  kWarning() << "No metadata file in package" << package << metadataPath;
537  return false;
538  }
539 
540  PackageMetadata meta(metadataPath);
541  QString targetName = meta.pluginName();
542 
543  if (targetName.isEmpty()) {
544  kWarning() << "Package plugin name not specified";
545  return false;
546  }
547 
548  // Ensure that package names are safe so package uninstall can't inject
549  // bad characters into the paths used for removal.
550  QRegExp validatePluginName("^[\\w-\\.]+$"); // Only allow letters, numbers, underscore and period.
551  if (!validatePluginName.exactMatch(targetName)) {
552  kWarning() << "Package plugin name " << targetName << "contains invalid characters";
553  return false;
554  }
555 
556  targetName = packageRoot + '/' + targetName;
557  if (QFile::exists(targetName)) {
558  kWarning() << targetName << "already exists";
559  return false;
560  }
561 
562  if (archivedPackage) {
563  // it's in a temp dir, so just move it over.
564  const bool ok = copyFolder(path, targetName);
565  removeFolder(path);
566  if (!ok) {
567  kWarning() << "Could not move package to destination:" << targetName;
568  return false;
569  }
570  } else {
571  kDebug() << "************************** 12";
572  // it's a directory containing the stuff, so copy the contents rather
573  // than move them
574  const bool ok = copyFolder(path, targetName);
575  kDebug() << "************************** 13";
576  if (!ok) {
577  kWarning() << "Could not copy package to destination:" << targetName;
578  return false;
579  }
580  }
581 
582  if (archivedPackage) {
583  // no need to remove the temp dir (which has been successfully moved if it's an archive)
584  tempdir.setAutoRemove(false);
585  }
586  // check for missing dependencies
587  QString requiredScriptEngine = meta.implementationApi();
588  if (!requiredScriptEngine.isEmpty()) {
589  // figure out the component type to query for
590  ComponentTypes componentTypes = static_cast<ComponentTypes>(0);
591  QStringList serviceTypes = meta.serviceType().split(',');
592  if (serviceTypes.contains("Plasma/Applet")) {
593  componentTypes |= AppletComponent;
594  }
595  if (serviceTypes.contains("Plasma/DataEngine")) {
596  componentTypes |= DataEngineComponent;
597  }
598  if (serviceTypes.contains("Plasma/Runner")) {
599  componentTypes |= RunnerComponent;
600  }
601  if (serviceTypes.contains("Plasma/Wallpaper")) {
602  componentTypes |= WallpaperComponent;
603  }
604  if (!knownLanguages(componentTypes).contains(requiredScriptEngine)) {
605  // install the missing script engine
606  // force prompting because the user has just explicitly installed a widget
607  ComponentInstaller::self()->installMissingComponent("scriptengine", requiredScriptEngine, 0, true);
608  }
609  }
610  QStringList requiredDataEngines = meta.requiredDataEngines();
611  if (requiredDataEngines.isEmpty()) {
612  // check whether this was explicitly specified as empty
613  QString metaPath = targetName + "/metadata.desktop";
614  KDesktopFile df(metaPath);
615  KConfigGroup cg = df.desktopGroup();
616  if (!cg.hasKey("X-Plasma-RequiredDataEngines")) {
617  // not specified at all, try running the dependency extraction
618  requiredDataEngines = ComponentInstaller::self()->extractDataEngineDependencies(targetName,
619  requiredScriptEngine);
620  }
621  }
622  if (!requiredDataEngines.isEmpty()) {
623  QStringList knownDataEngines = DataEngineManager::self()->listAllEngines(meta.application());
624  foreach (const QString &requiredDataEngine, requiredDataEngines) {
625  if (!knownDataEngines.contains(requiredDataEngine)) {
626  // install the missing data engine
627  // force prompting because the user has just explicitly installed a widget
628  ComponentInstaller::self()->installMissingComponent("dataengine", requiredDataEngine, 0, true);
629  }
630  }
631  }
632 
633  if (!servicePrefix.isEmpty()) {
634  // and now we register it as a service =)
635  kDebug() << "************************** 1";
636  QString metaPath = targetName + "/metadata.desktop";
637  kDebug() << "************************** 2";
638  KDesktopFile df(metaPath);
639  KConfigGroup cg = df.desktopGroup();
640  kDebug() << "************************** 3";
641 
642  // Q: should not installing it as a service disqualify it?
643  // Q: i don't think so since KServiceTypeTrader may not be
644  // used by the installing app in any case, and the
645  // package is properly installed - aseigo
646 
647  //TODO: reduce code duplication with registerPackage below
648 
649  QString serviceName = servicePrefix + meta.pluginName();
650 
651  QString service = KStandardDirs::locateLocal("services", serviceName + ".desktop");
652  kDebug() << "************************** 4";
653  const bool ok = QFile::copy(metaPath, service);
654  kDebug() << "************************** 5";
655  if (ok) {
656  // the icon in the installed file needs to point to the icon in the
657  // installation dir!
658  QString iconPath = targetName + '/' + cg.readEntry("Icon");
659  QFile icon(iconPath);
660  if (icon.exists()) {
661  KDesktopFile df(service);
662  KConfigGroup cg = df.desktopGroup();
663  cg.writeEntry("Icon", iconPath);
664  }
665  } else {
666  kWarning() << "Could not register package as service (this is not necessarily fatal):" << serviceName;
667  }
668  kDebug() << "************************** 7";
669  }
670 
671  return true;
672 }
673 
674 bool Package::uninstallPackage(const QString &pluginName,
675  const QString &packageRoot,
676  const QString &servicePrefix) // static
677 {
678  // We need to remove the package directory and its metadata file.
679  QString targetName = pluginName;
680  targetName = packageRoot + '/' + targetName;
681 
682  if (!QFile::exists(targetName)) {
683  kWarning() << targetName << "does not exist";
684  return false;
685  }
686 
687  QString serviceName = servicePrefix + pluginName;
688 
689  QString service = KStandardDirs::locateLocal("services", serviceName + ".desktop");
690  kDebug() << "Removing service file " << service;
691  bool ok = QFile::remove(service);
692 
693  if (!ok) {
694  kWarning() << "Unable to remove " << service;
695  }
696 
697  ok = removeFolder(targetName);
698  const QString errorString("unknown");
699  if (!ok) {
700  kWarning() << "Could not delete package from:" << targetName << " : " << errorString;
701  return false;
702  }
703 
704  return true;
705 }
706 
707 bool Package::registerPackage(const PackageMetadata &data, const QString &iconPath)
708 {
709  QString serviceName("plasma-applet-" + data.pluginName());
710  QString service = KStandardDirs::locateLocal("services", serviceName + ".desktop");
711 
712  if (data.pluginName().isEmpty()) {
713  return false;
714  }
715 
716  data.write(service);
717 
718  KDesktopFile config(service);
719  KConfigGroup cg = config.desktopGroup();
720  const QString type = data.type().isEmpty() ? "Service" : data.type();
721  cg.writeEntry("Type", type);
722  const QString serviceTypes = data.serviceType().isNull() ? "Plasma/Applet,Plasma/Containment" : data.serviceType();
723  cg.writeEntry("X-KDE-ServiceTypes", serviceTypes);
724  cg.writeEntry("X-KDE-PluginInfo-EnabledByDefault", true);
725 
726  QFile icon(iconPath);
727  if (icon.exists()) {
728  //FIXME: the '/' search will break on non-UNIX. do we care?
729  QString installedIcon("plasma_applet_" + data.pluginName() +
730  iconPath.right(iconPath.length() - iconPath.lastIndexOf("/")));
731  cg.writeEntry("Icon", installedIcon);
732  installedIcon = KStandardDirs::locateLocal("icon", installedIcon);
733  QFile::copy(iconPath, installedIcon);
734  }
735 
736  return true;
737 }
738 
739 bool Package::createPackage(const PackageMetadata &metadata,
740  const QString &source,
741  const QString &destination,
742  const QString &icon) // static
743 {
744  Q_UNUSED(icon)
745  if (!metadata.isValid()) {
746  kWarning() << "Metadata file is not complete";
747  return false;
748  }
749 
750  // write metadata in a temporary file
751  KTemporaryFile metadataFile;
752  if (!metadataFile.open()) {
753  return false;
754  }
755  metadata.write(metadataFile.fileName());
756 
757  // put everything into a zip archive
758  KZip creation(destination);
759  creation.setCompression(KZip::NoCompression);
760  if (!creation.open(QIODevice::WriteOnly)) {
761  return false;
762  }
763 
764  creation.addLocalFile(metadataFile.fileName(), "metadata.desktop");
765  creation.addLocalDirectory(source, "contents");
766  creation.close();
767  return true;
768 }
769 
770 PackagePrivate::PackagePrivate(const PackageStructure::Ptr st, const QString &p)
771  : structure(st),
772  service(0)
773 {
774  if (structure) {
775  if (p.isEmpty()) {
776  structure->setPath(structure->defaultPackageRoot());
777  } else {
778  structure->setPath(p);
779  }
780  }
781 
782  valid = structure && !structure->path().isEmpty();
783 }
784 
785 PackagePrivate::PackagePrivate(const PackageStructure::Ptr st, const QString &packageRoot, const QString &path)
786  : structure(st),
787  service(0)
788 {
789  if (structure) {
790  if (packageRoot.isEmpty()) {
791  structure->setPath(structure->defaultPackageRoot()%"/"%path);
792  } else {
793  structure->setPath(packageRoot%"/"%path);
794  }
795  }
796 
797  valid = structure && !structure->path().isEmpty();
798 }
799 
800 PackagePrivate::PackagePrivate(const PackagePrivate &other)
801  : structure(other.structure),
802  service(other.service),
803  valid(other.valid)
804 {
805 }
806 
807 PackagePrivate::~PackagePrivate()
808 {
809 }
810 
811 PackagePrivate &PackagePrivate::operator=(const PackagePrivate &rhs)
812 {
813  structure = rhs.structure;
814  service = rhs.service;
815  valid = rhs.valid;
816  return *this;
817 }
818 
819 void PackagePrivate::publish(AnnouncementMethods methods)
820 {
821  if (!structure) {
822  return;
823  }
824 
825  if (!service) {
826  service = new PlasmoidService(structure->path());
827  }
828 
829  QString resourceName =
830  i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
831  "%1 on %2", structure->metadata().name(), QHostInfo::localHostName());
832  kDebug() << "publishing package under name " << resourceName;
833  service->d->publish(methods, resourceName, structure->metadata());
834 }
835 
836 void PackagePrivate::unpublish()
837 {
838  if (service) {
839  service->d->unpublish();
840  }
841 }
842 
843 bool PackagePrivate::isPublished() const
844 {
845  if (service) {
846  return service->d->isPublished();
847  } else {
848  return false;
849  }
850 }
851 
852 } // Namespace
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Dec 10 2012 13:45:41 by doxygen 1.8.1.2 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.9.4 API Reference

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