22 #include "config-plasma.h"
27 #include <QtNetwork/QHostInfo>
34 #include <kcomponentdata.h>
35 #include <kdesktopfile.h>
36 #include <kmimetype.h>
37 #include <kplugininfo.h>
38 #include <kstandarddirs.h>
41 #include <ktemporaryfile.h>
47 #include "private/authorizationmanager_p.h"
48 #include "private/package_p.h"
49 #include "private/plasmoidservice_p.h"
50 #include "private/service_p.h"
57 QDir source(sourcePath);
61 QDir target(targetPath);
62 if(!target.exists()) {
63 QString targetName = target.dirName();
65 target.mkdir(targetName);
66 target = QDir(targetPath);
69 foreach (
const QString &fileName, source.entryList(QDir::Files)) {
70 QString sourceFilePath = sourcePath + QDir::separator() + fileName;
71 QString targetFilePath = targetPath + QDir::separator() + fileName;
73 if (!QFile::copy(sourceFilePath, targetFilePath)) {
78 foreach (
const QString &subFolderName, source.entryList(QDir::AllDirs | QDir::NoDotAndDotDot)) {
79 QString sourceSubFolderPath = sourcePath + QDir::separator() + subFolderName;
80 QString targetSubFolderPath = targetPath + QDir::separator() + subFolderName;
82 if (!
copyFolder(sourceSubFolderPath, targetSubFolderPath)) {
92 QDir folder(folderPath);
96 foreach (
const QString &fileName, folder.entryList(QDir::Files)) {
97 if (!QFile::remove(folderPath + QDir::separator() + fileName)) {
102 foreach (
const QString &subFolderName, folder.entryList(QDir::AllDirs | QDir::NoDotAndDotDot)) {
103 if (!
removeFolder(folderPath + QDir::separator() + subFolderName)) {
108 QString folderName = folder.dirName();
110 return folder.rmdir(folderName);
120 : d(new PackagePrivate(structure, packageRoot, package))
125 : d(new PackagePrivate(structure, packagePath))
130 : d(new PackagePrivate(*other.d))
157 QStringList prefixes = d->structure->contentsPrefixPaths();
158 if (prefixes.isEmpty()) {
159 prefixes << QString();
162 foreach (
const char *dir, d->structure->requiredDirectories()) {
164 foreach (
const QString &
path, d->structure->searchPath(dir)) {
165 foreach (
const QString &prefix, prefixes) {
166 if (QFile::exists(d->structure->path() + prefix +
path)) {
177 kWarning() <<
"Could not find required directory" << dir;
183 foreach (
const char *file, d->structure->requiredFiles()) {
185 foreach (
const QString &
path, d->structure->searchPath(file)) {
186 foreach (
const QString &prefix, prefixes) {
187 if (QFile::exists(d->structure->path() + prefix +
path)) {
198 kWarning() <<
"Could not find required file" << file;
216 if (qstrlen(fileType) != 0) {
217 paths = d->structure->searchPath(fileType);
219 if (paths.isEmpty()) {
229 QStringList prefixes = d->structure->contentsPrefixPaths();
230 if (prefixes.isEmpty()) {
231 prefixes << QString();
235 foreach (
const QString &contentsPrefix, prefixes) {
236 const QString prefix(d->structure->path() + contentsPrefix);
238 foreach (
const QString &
path, paths) {
239 QString file = prefix +
path;
241 if (!filename.isEmpty()) {
242 file.append(
"/").append(filename);
246 if (QFile::exists(file)) {
247 if (d->structure->allowExternalPaths()) {
255 QString canonicalized = dir.canonicalPath() + QDir::separator();
258 if (canonicalized.startsWith(d->structure->path())) {
272 return filePath(fileType, QString());
278 return QStringList();
281 return d->structure->entryList(fileType);
287 return d->structure->metadata();
296 d->structure->setPath(path);
297 d->valid = !d->structure->path().isEmpty();
303 return d->structure ? d->structure->path() : QString();
312 void PackagePrivate::updateHash(
const QString &basePath,
const QString &subPath,
const QDir &dir, QCA::Hash &hash)
324 const QDir::SortFlags sorting = QDir::Name | QDir::IgnoreCase;
325 const QDir::Filters filters = QDir::Hidden | QDir::System | QDir::NoDotAndDotDot;
326 foreach (
const QString &file, dir.entryList(QDir::Files | filters, sorting)) {
327 if (!subPath.isEmpty()) {
328 hash.update(subPath.toUtf8());
331 hash.update(file.toUtf8());
333 QFileInfo info(dir.path() +
'/' + file);
334 if (info.isSymLink()) {
335 hash.update(info.symLinkTarget().toUtf8());
337 QFile f(info.filePath());
338 if (f.open(QIODevice::ReadOnly)) {
340 hash.update(f.read(1024));
343 kWarning() <<
"could not add" << f.fileName() <<
"to the hash; file could not be opened for reading. "
344 <<
"permissions fail?" << info.permissions() << info.isFile();
349 foreach (
const QString &subDirPath, dir.entryList(QDir::Dirs | filters, sorting)) {
350 const QString relativePath = subPath + subDirPath +
'/';
351 hash.update(relativePath.toUtf8());
353 QDir subDir(dir.path());
354 subDir.cd(subDirPath);
356 if (subDir.path() != subDir.canonicalPath()) {
357 hash.update(subDir.canonicalPath().toUtf8());
359 updateHash(basePath, relativePath, subDir, hash);
369 kWarning() <<
"can not create hash due to Package being invalid";
374 QCA::Initializer init;
375 if (!QCA::isSupported(
"sha1")) {
376 kWarning() <<
"can not create hash for" <<
path() <<
"due to no SHA1 support in QCA2";
380 QCA::Hash hash(
"sha1");
381 QString metadataPath = d->structure->path() +
"metadata.desktop";
382 if (QFile::exists(metadataPath)) {
383 QFile f(metadataPath);
384 if (f.open(QIODevice::ReadOnly)) {
386 hash.update(f.read(1024));
389 kWarning() <<
"could not add" << f.fileName() <<
"to the hash; file could not be opened for reading.";
392 kWarning() <<
"no metadata at" << metadataPath;
395 QStringList prefixes = d->structure->contentsPrefixPaths();
396 if (prefixes.isEmpty()) {
397 prefixes << QString();
400 foreach (QString prefix, prefixes) {
401 const QString basePath = d->structure->path() + prefix;
408 d->updateHash(basePath, QString(), dir, hash);
410 return QCA::arrayToHex(hash.final().toByteArray());
413 kWarning() <<
"can not create hash for" <<
path() <<
"due to no cryptographic support (QCA2)";
422 QDir dir(packageRoot);
425 return QStringList();
428 QStringList packages;
430 foreach (
const QString &sdir, dir.entryList(QDir::AllDirs | QDir::Readable)) {
431 QString
metadata = packageRoot +
'/' + sdir +
"/metadata.desktop";
432 if (QFile::exists(metadata)) {
443 QDir dir(packageRoot);
446 return QStringList();
449 QStringList packages;
451 foreach (
const QString &sdir, dir.entryList(QDir::AllDirs | QDir::Readable)) {
452 QString
metadata = packageRoot +
'/' + sdir +
"/metadata.desktop";
453 if (QFile::exists(metadata)) {
462 const QString &packageRoot,
463 const QString &servicePrefix)
466 QDir root(packageRoot);
468 if (!root.exists()) {
469 KStandardDirs::makeDir(packageRoot);
470 if (!root.exists()) {
471 kWarning() <<
"Could not create package root directory:" << packageRoot;
476 QFileInfo fileInfo(package);
477 if (!fileInfo.exists()) {
478 kWarning() <<
"No such file:" << package;
484 bool archivedPackage =
false;
486 if (fileInfo.isDir()) {
491 if (path[path.size() - 1] !=
'/') {
495 KArchive *archive = 0;
496 KMimeType::Ptr mimetype = KMimeType::findByPath(package);
498 if (mimetype->is(
"application/zip")) {
499 archive =
new KZip(package);
500 }
else if (mimetype->is(
"application/x-compressed-tar") ||
501 mimetype->is(
"application/x-tar")|| mimetype->is(
"application/x-bzip-compressed-tar") ||
502 mimetype->is(
"application/x-xz") || mimetype->is(
"application/x-lzma")) {
503 archive =
new KTar(package);
505 kWarning() <<
"Could not open package file, unsupported archive format:" <<
package << mimetype->name();
509 if (!archive->open(QIODevice::ReadOnly)) {
510 kWarning() <<
"Could not open package file:" << package;
515 archivedPackage =
true;
516 path = tempdir.name();
518 const KArchiveDirectory *source = archive->directory();
519 source->copyTo(path);
521 QStringList entries = source->entries();
522 if (entries.count() == 1) {
523 const KArchiveEntry *entry = source->entry(entries[0]);
524 if (entry->isDirectory()) {
525 path.append(entry->name()).append(
"/");
531 QString metadataPath = path +
"metadata.desktop";
532 if (!QFile::exists(metadataPath)) {
533 kWarning() <<
"No metadata file in package" <<
package << metadataPath;
540 if (targetName.isEmpty()) {
541 kWarning() <<
"Package plugin name not specified";
547 QRegExp validatePluginName(
"^[\\w-\\.]+$");
548 if (!validatePluginName.exactMatch(targetName)) {
549 kWarning() <<
"Package plugin name " << targetName <<
"contains invalid characters";
553 targetName = packageRoot +
'/' + targetName;
554 if (QFile::exists(targetName)) {
555 kWarning() << targetName <<
"already exists";
559 if (archivedPackage) {
564 kWarning() <<
"Could not move package to destination:" << targetName;
568 kDebug() <<
"************************** 12";
572 kDebug() <<
"************************** 13";
574 kWarning() <<
"Could not copy package to destination:" << targetName;
579 if (archivedPackage) {
581 tempdir.setAutoRemove(
false);
584 if (!servicePrefix.isEmpty()) {
586 kDebug() <<
"************************** 1";
587 QString metaPath = targetName +
"/metadata.desktop";
588 kDebug() <<
"************************** 2";
589 KDesktopFile df(metaPath);
590 KConfigGroup cg = df.desktopGroup();
591 kDebug() <<
"************************** 3";
600 QString serviceName = servicePrefix + meta.
pluginName();
602 QString service = KStandardDirs::locateLocal(
"services", serviceName +
".desktop");
603 kDebug() <<
"************************** 4";
604 const bool ok = QFile::copy(metaPath, service);
605 kDebug() <<
"************************** 5";
609 QString iconPath = targetName +
'/' + cg.readEntry(
"Icon");
610 QFile icon(iconPath);
612 KDesktopFile df(service);
613 KConfigGroup cg = df.desktopGroup();
614 cg.writeEntry(
"Icon", iconPath);
617 kWarning() <<
"Could not register package as service (this is not necessarily fatal):" << serviceName;
619 kDebug() <<
"************************** 7";
626 const QString &packageRoot,
627 const QString &servicePrefix)
630 QString targetName = pluginName;
631 targetName = packageRoot +
'/' + targetName;
633 if (!QFile::exists(targetName)) {
634 kWarning() << targetName <<
"does not exist";
638 QString serviceName = servicePrefix + pluginName;
640 QString service = KStandardDirs::locateLocal(
"services", serviceName +
".desktop");
641 kDebug() <<
"Removing service file " << service;
642 bool ok = QFile::remove(service);
645 kWarning() <<
"Unable to remove " << service;
649 const QString errorString(
"unknown");
651 kWarning() <<
"Could not delete package from:" << targetName <<
" : " << errorString;
660 QString serviceName(
"plasma-applet-" + data.
pluginName());
661 QString service = KStandardDirs::locateLocal(
"services", serviceName +
".desktop");
669 KDesktopFile config(service);
670 KConfigGroup cg = config.desktopGroup();
671 const QString
type = data.
type().isEmpty() ?
"Service" : data.
type();
672 cg.writeEntry(
"Type", type);
673 const QString serviceTypes = data.
serviceType().isNull() ?
"Plasma/Applet,Plasma/Containment" : data.
serviceType();
674 cg.writeEntry(
"X-KDE-ServiceTypes", serviceTypes);
675 cg.writeEntry(
"X-KDE-PluginInfo-EnabledByDefault",
true);
677 QFile icon(iconPath);
680 QString installedIcon(
"plasma_applet_" + data.
pluginName() +
681 iconPath.right(iconPath.length() - iconPath.lastIndexOf(
"/")));
682 cg.writeEntry(
"Icon", installedIcon);
683 installedIcon = KStandardDirs::locateLocal(
"icon", installedIcon);
684 QFile::copy(iconPath, installedIcon);
691 const QString &source,
692 const QString &destination,
697 kWarning() <<
"Metadata file is not complete";
702 KTemporaryFile metadataFile;
703 if (!metadataFile.open()) {
706 metadata.
write(metadataFile.fileName());
709 KZip creation(destination);
710 creation.setCompression(KZip::NoCompression);
711 if (!creation.open(QIODevice::WriteOnly)) {
715 creation.addLocalFile(metadataFile.fileName(),
"metadata.desktop");
716 creation.addLocalDirectory(source,
"contents");
736 PackagePrivate::PackagePrivate(
const PackageStructure::Ptr st,
const QString &packageRoot,
const QString &path)
741 if (packageRoot.isEmpty()) {
744 structure->setPath(packageRoot%
"/"%path);
751 PackagePrivate::PackagePrivate(
const PackagePrivate &other)
752 : structure(other.structure),
753 service(other.service),
758 PackagePrivate::~PackagePrivate()
762 PackagePrivate &PackagePrivate::operator=(
const PackagePrivate &rhs)
764 structure = rhs.structure;
765 service = rhs.service;
770 void PackagePrivate::publish(AnnouncementMethods methods)
777 service =
new PlasmoidService(structure->path());
780 QString resourceName =
781 i18nc(
"%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
782 "%1 on %2", structure->metadata().name(), QHostInfo::localHostName());
783 kDebug() <<
"publishing package under name " << resourceName;
784 service->d->publish(methods, resourceName, structure->metadata());
787 void PackagePrivate::unpublish()
790 service->d->unpublish();
794 bool PackagePrivate::isPublished()
const
797 return service->d->isPublished();