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);
65 target.
mkdir(targetName);
66 target =
QDir(targetPath);
78 foreach (
const QString &subFolderName, source.
entryList(QDir::AllDirs | QDir::NoDotAndDotDot)) {
82 if (!
copyFolder(sourceSubFolderPath, targetSubFolderPath)) {
92 QDir folder(folderPath);
102 foreach (
const QString &subFolderName, folder.
entryList(QDir::AllDirs | QDir::NoDotAndDotDot)) {
110 return folder.
rmdir(folderName);
120 : d(new PackagePrivate(structure, packageRoot, package))
125 : d(new PackagePrivate(structure, packagePath))
130 : d(new PackagePrivate(*other.d))
153 bool PackagePrivate::isValid()
155 if (!valid || !structure) {
162 QStringList prefixes = structure->contentsPrefixPaths();
167 foreach (
const char *dir, structure->requiredDirectories()) {
169 foreach (
const QString &path, structure->searchPath(dir)) {
170 foreach (
const QString &prefix, prefixes) {
182 kWarning() <<
"Could not find required directory" << dir;
188 foreach (
const char *file, structure->requiredFiles()) {
190 foreach (
const QString &path, structure->searchPath(file)) {
191 foreach (
const QString &prefix, prefixes) {
203 kWarning() <<
"Could not find required file" << file;
222 if (qstrlen(fileType) != 0) {
223 paths = d->structure->searchPath(fileType);
235 QStringList prefixes = d->structure->contentsPrefixPaths();
241 foreach (
const QString &contentsPrefix, prefixes) {
242 const QString prefix(d->structure->path() + contentsPrefix);
244 foreach (
const QString &path, paths) {
253 if (d->structure->allowExternalPaths()) {
264 if (canonicalized.
startsWith(d->structure->path())) {
287 return d->structure->entryList(fileType);
293 return d->structure->metadata();
301 d->setPathFromStructure(path);
306 return d->structure ? d->structure->path() :
QString();
315 void PackagePrivate::updateHash(
const QString &basePath,
const QString &subPath,
const QDir &dir, QCA::Hash &hash)
328 const QDir::Filters filters = QDir::Hidden | QDir::System | QDir::NoDotAndDotDot;
329 foreach (
const QString &file, dir.
entryList(QDir::Files | filters, sorting)) {
331 hash.update(subPath.
toUtf8());
334 hash.update(file.
toUtf8());
337 if (info.isSymLink()) {
338 hash.update(info.symLinkTarget().toUtf8());
340 QFile f(info.filePath());
341 if (f.open(QIODevice::ReadOnly)) {
343 hash.update(f.read(1024));
346 kWarning() <<
"could not add" << f.
fileName() <<
"to the hash; file could not be opened for reading. "
347 <<
"permissions fail?" << info.permissions() << info.isFile();
352 foreach (
const QString &subDirPath, dir.
entryList(QDir::Dirs | filters, sorting)) {
353 const QString relativePath = subPath + subDirPath +
'/';
354 hash.update(relativePath.
toUtf8());
357 subDir.
cd(subDirPath);
359 if (subDir.path() != subDir.canonicalPath()) {
360 hash.update(subDir.canonicalPath().toUtf8());
362 updateHash(basePath, relativePath, subDir, hash);
372 kWarning() <<
"can not create hash due to Package being invalid";
377 QCA::Initializer init;
378 if (!QCA::isSupported(
"sha1")) {
379 kWarning() <<
"can not create hash for" <<
path() <<
"due to no SHA1 support in QCA2";
383 QCA::Hash hash(
"sha1");
384 QString metadataPath = d->structure->path() +
"metadata.desktop";
386 QFile f(metadataPath);
387 if (f.
open(QIODevice::ReadOnly)) {
389 hash.update(f.
read(1024));
392 kWarning() <<
"could not add" << f.
fileName() <<
"to the hash; file could not be opened for reading.";
395 kWarning() <<
"no metadata at" << metadataPath;
398 QStringList prefixes = d->structure->contentsPrefixPaths();
403 foreach (
QString prefix, prefixes) {
404 const QString basePath = d->structure->path() + prefix;
411 d->updateHash(basePath,
QString(), dir, hash);
413 return QCA::arrayToHex(hash.final().toByteArray());
416 kWarning() <<
"can not create hash for" <<
path() <<
"due to no cryptographic support (QCA2)";
425 QDir dir(packageRoot);
433 foreach (
const QString &sdir, dir.
entryList(QDir::AllDirs | QDir::Readable)) {
446 QDir dir(packageRoot);
454 foreach (
const QString &sdir, dir.
entryList(QDir::AllDirs | QDir::Readable)) {
469 QDir root(packageRoot);
472 KStandardDirs::makeDir(packageRoot);
474 kWarning() <<
"Could not create package root directory:" << packageRoot;
481 kWarning() <<
"No such file:" << package;
487 bool archivedPackage =
false;
489 if (fileInfo.
isDir()) {
494 if (path[path.
size() - 1] !=
'/') {
498 KArchive *archive = 0;
499 KMimeType::Ptr mimetype = KMimeType::findByPath(package);
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-compressed-tar") || mimetype->is(
"application/x-lzma-compressed-tar")) {
506 archive =
new KTar(package);
508 kWarning() <<
"Could not open package file, unsupported archive format:" <<
package << mimetype->name();
512 if (!archive->open(QIODevice::ReadOnly)) {
513 kWarning() <<
"Could not open package file:" << package;
518 archivedPackage =
true;
519 path = tempdir.name();
521 const KArchiveDirectory *source = archive->directory();
522 source->copyTo(path);
525 if (entries.
count() == 1) {
526 const KArchiveEntry *entry = source->entry(entries[0]);
527 if (entry->isDirectory()) {
528 path.
append(entry->name()).append(
"/");
534 QString metadataPath = path +
"metadata.desktop";
536 kWarning() <<
"No metadata file in package" <<
package << metadataPath;
544 kWarning() <<
"Package plugin name not specified";
550 QRegExp validatePluginName(
"^[\\w-\\.]+$");
551 if (!validatePluginName.
exactMatch(targetName)) {
552 kWarning() <<
"Package plugin name " << targetName <<
"contains invalid characters";
556 targetName = packageRoot +
'/' + targetName;
558 kWarning() << targetName <<
"already exists";
562 if (archivedPackage) {
567 kWarning() <<
"Could not move package to destination:" << targetName;
571 kDebug() <<
"************************** 12";
575 kDebug() <<
"************************** 13";
577 kWarning() <<
"Could not copy package to destination:" << targetName;
582 if (archivedPackage) {
584 tempdir.setAutoRemove(
false);
587 if (!servicePrefix.
isEmpty()) {
589 kDebug() <<
"************************** 1";
590 QString metaPath = targetName +
"/metadata.desktop";
591 kDebug() <<
"************************** 2";
592 KDesktopFile df(metaPath);
593 KConfigGroup cg = df.desktopGroup();
594 kDebug() <<
"************************** 3";
605 QString service = KStandardDirs::locateLocal(
"services", serviceName +
".desktop");
606 kDebug() <<
"************************** 4";
608 kDebug() <<
"************************** 5";
612 QString iconPath = targetName +
'/' + cg.readEntry(
"Icon");
613 QFile icon(iconPath);
615 KDesktopFile df(service);
616 KConfigGroup cg = df.desktopGroup();
617 cg.writeEntry(
"Icon", iconPath);
620 kWarning() <<
"Could not register package as service (this is not necessarily fatal):" << serviceName;
622 kDebug() <<
"************************** 7";
633 QString targetName = pluginName;
634 targetName = packageRoot +
'/' + targetName;
637 kWarning() << targetName <<
"does not exist";
641 QString serviceName = servicePrefix + pluginName;
643 QString service = KStandardDirs::locateLocal(
"services", serviceName +
".desktop");
644 kDebug() <<
"Removing service file " << service;
648 kWarning() <<
"Unable to remove " << service;
652 const QString errorString(
"unknown");
654 kWarning() <<
"Could not delete package from:" << targetName <<
" : " << errorString;
664 QString service = KStandardDirs::locateLocal(
"services", serviceName +
".desktop");
672 KDesktopFile config(service);
673 KConfigGroup cg = config.desktopGroup();
675 cg.writeEntry(
"Type", type);
677 cg.writeEntry(
"X-KDE-ServiceTypes", serviceTypes);
678 cg.writeEntry(
"X-KDE-PluginInfo-EnabledByDefault",
true);
680 QFile icon(iconPath);
685 cg.writeEntry(
"Icon", installedIcon);
686 installedIcon = KStandardDirs::locateLocal(
"icon", installedIcon);
700 kWarning() <<
"Metadata file is not complete";
705 KTemporaryFile metadataFile;
706 if (!metadataFile.open()) {
709 metadata.
write(metadataFile.fileName());
712 KZip creation(destination);
713 creation.setCompression(KZip::NoCompression);
714 if (!creation.open(QIODevice::WriteOnly)) {
718 creation.addLocalFile(metadataFile.fileName(),
"metadata.desktop");
719 creation.addLocalDirectory(source,
"contents");
728 setPathFromStructure(p);
735 setPathFromStructure(packageRoot.
isEmpty() ? path : packageRoot %
"/" %
path);
738 PackagePrivate::PackagePrivate(
const PackagePrivate &other)
739 : structure(other.structure),
740 service(other.service),
745 PackagePrivate::~PackagePrivate()
749 PackagePrivate &PackagePrivate::operator=(
const PackagePrivate &rhs)
751 structure = rhs.structure;
752 service = rhs.service;
757 void PackagePrivate::setPathFromStructure(
const QString &path)
766 paths << structure->defaultPackageRoot();
768 QString p = structure->defaultPackageRoot() %
"/" % path %
"/";
771 paths = KGlobal::dirs()->findDirs(
"data", p);
779 foreach (
const QString &p, paths) {
780 structure->setPath(p);
792 void PackagePrivate::publish(AnnouncementMethods methods)
799 service =
new PlasmoidService(structure->path());
803 i18nc(
"%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
805 kDebug() <<
"publishing package under name " << resourceName;
806 service->d->publish(methods, resourceName, structure->metadata());
809 void PackagePrivate::unpublish()
812 service->d->unpublish();
816 bool PackagePrivate::isPublished()
const
819 return service->d->isPublished();
QString & append(QChar ch)
static QStringList listInstalled(const QString &packageRoot)
Returns a list of all installed packages by name.
static QStringList listInstalledPaths(const QString &packageRoot)
Returns a list of all paths of installed packages in the given root.
const PackageStructure::Ptr structure() const
bool copy(const QString &newName)
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
static bool registerPackage(const PackageMetadata &data, const QString &iconPath)
Registers a package described by the given desktop file.
static bool uninstallPackage(const QString &package, const QString &packageRoot, const QString &servicePrefix)
Uninstalls a package.
static bool installPackage(const QString &package, const QString &packageRoot, const QString &servicePrefix)
Installs a package.
int count(const T &value) const
const QString path() const
bool rmdir(const QString &dirName) const
bool copyFolder(QString sourcePath, QString targetPath)
bool cd(const QString &dirName)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
Package & operator=(const Package &rhs)
Assignment operator.
KSharedPtr< PackageStructure > Ptr
qint64 read(char *data, qint64 maxSize)
object representing an installed Plasmagik package
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
QString right(int n) const
bool removeFolder(QString folderPath)
bool isRelativePath(const QString &path)
QStringList entryList(const char *fileType) const
Get the list of files of a given type.
PackageMetadata metadata() const
QString contentsHash() const
static QScriptValue type(QScriptContext *ctx, QScriptEngine *eng)
bool mkdir(const QString &dirName) const
QStringList entryList(QFlags< QDir::Filter > filters, QFlags< QDir::SortFlag > sort) const
Package()
Default constructor that creates an invalid Package.
virtual bool atEnd() const
QString canonicalPath() const
void setPath(const QString &path)
Sets the path to the root of this package.
bool exactMatch(const QString &str) const
A description of the expected file structure of a given package type.
QString filePath(const char *fileType, const QString &filename) const
Get the path to a given file.
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.
QByteArray toUtf8() const