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

Plasma

package.cpp
Go to the documentation of this file.
00001 /******************************************************************************
00002 *   Copyright 2007 by Aaron Seigo <aseigo@kde.org>                            *
00003 *   Copyright 2007 by Riccardo Iaconelli <riccardo@kde.org>                   *
00004 *                                                                             *
00005 *   This library is free software; you can redistribute it and/or             *
00006 *   modify it under the terms of the GNU Library General Public               *
00007 *   License as published by the Free Software Foundation; either              *
00008 *   version 2 of the License, or (at your option) any later version.          *
00009 *                                                                             *
00010 *   This library is distributed in the hope that it will be useful,           *
00011 *   but WITHOUT ANY WARRANTY; without even the implied warranty of            *
00012 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU          *
00013 *   Library General Public License for more details.                          *
00014 *                                                                             *
00015 *   You should have received a copy of the GNU Library General Public License *
00016 *   along with this library; see the file COPYING.LIB.  If not, write to      *
00017 *   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,      *
00018 *   Boston, MA 02110-1301, USA.                                               *
00019 *******************************************************************************/
00020 
00021 #include "package.h"
00022 #include "config-plasma.h"
00023 
00024 #include <QDir>
00025 #include <QFile>
00026 #include <QRegExp>
00027 #include <QtNetwork/QHostInfo>
00028 
00029 #ifdef QCA2_FOUND
00030 #include <QtCrypto>
00031 #endif
00032 
00033 #include <karchive.h>
00034 #include <kcomponentdata.h>
00035 #include <kdesktopfile.h>
00036 #ifndef PLASMA_NO_KIO
00037 #include <kio/copyjob.h>
00038 #include <kio/deletejob.h>
00039 #include <kio/jobclasses.h>
00040 #include <kio/job.h>
00041 #endif
00042 #include <kmimetype.h>
00043 #include <kplugininfo.h>
00044 #include <kstandarddirs.h>
00045 #include <ktar.h>
00046 #include <ktempdir.h>
00047 #include <ktemporaryfile.h>
00048 #include <kzip.h>
00049 #include <kdebug.h>
00050 
00051 #include "authorizationmanager.h"
00052 #include "packagemetadata.h"
00053 #include "private/authorizationmanager_p.h"
00054 #include "private/package_p.h"
00055 #include "private/plasmoidservice_p.h"
00056 #include "private/service_p.h"
00057 
00058 namespace Plasma
00059 {
00060 
00061 #ifdef PLASMA_NO_KIO // Provide some convenience for dealing with folders
00062 
00063 bool copyFolder(QString sourcePath, QString targetPath)
00064 {
00065     QDir source(sourcePath);
00066     if(!source.exists())
00067         return false;
00068 
00069     QDir target(targetPath);
00070     if(!target.exists()) {
00071         QString targetName = target.dirName();
00072         target.cdUp();
00073         target.mkdir(targetName);
00074         target = QDir(targetPath);
00075     }
00076 
00077     foreach (const QString &fileName, source.entryList(QDir::Files)) {
00078         QString sourceFilePath = sourcePath + QDir::separator() + fileName;
00079         QString targetFilePath = targetPath + QDir::separator() + fileName;
00080 
00081         if (!QFile::copy(sourceFilePath, targetFilePath)) {
00082             return false;
00083         }
00084     }
00085 
00086     foreach (const QString &subFolderName, source.entryList(QDir::AllDirs | QDir::NoDotAndDotDot)) {
00087         QString sourceSubFolderPath = sourcePath + QDir::separator() + subFolderName;
00088         QString targetSubFolderPath = targetPath + QDir::separator() + subFolderName;
00089 
00090         if (!copyFolder(sourceSubFolderPath, targetSubFolderPath)) {
00091             return false;
00092         }
00093     }
00094 
00095     return true;
00096 }
00097 
00098 bool removeFolder(QString folderPath)
00099 {
00100     QDir folder(folderPath);
00101     if(!folder.exists())
00102         return false;
00103 
00104     foreach (const QString &fileName, folder.entryList(QDir::Files)) {
00105         if (!QFile::remove(folderPath + QDir::separator() + fileName)) {
00106             return false;
00107         }
00108     }
00109 
00110     foreach (const QString &subFolderName, folder.entryList(QDir::AllDirs | QDir::NoDotAndDotDot)) {
00111         if (!removeFolder(folderPath + QDir::separator() + subFolderName)) {
00112             return false;
00113         }
00114     }
00115 
00116     QString folderName = folder.dirName();
00117     folder.cdUp();
00118     return folder.rmdir(folderName);
00119 }
00120 
00121 #endif // PLASMA_NO_KIO
00122 
00123 
00124 Package::Package()
00125     : d(new PackagePrivate(PackageStructure::Ptr(0), QString()))
00126 {
00127 }
00128 
00129 Package::Package(const QString &packageRoot, const QString &package,
00130                  PackageStructure::Ptr structure)
00131     : d(new PackagePrivate(structure, packageRoot, package))
00132 {
00133 }
00134 
00135 Package::Package(const QString &packagePath, PackageStructure::Ptr structure)
00136     : d(new PackagePrivate(structure, packagePath))
00137 {
00138 }
00139 
00140 Package::Package(const Package &other)
00141     : d(new PackagePrivate(*other.d))
00142 {
00143 }
00144 
00145 Package::~Package()
00146 {
00147     delete d;
00148 }
00149 
00150 Package &Package::operator=(const Package &rhs)
00151 {
00152     if (&rhs != this) {
00153         *d = *rhs.d;
00154     }
00155 
00156     return *this;
00157 }
00158 
00159 bool Package::isValid() const
00160 {
00161     if (!d->valid) {
00162         return false;
00163     }
00164 
00165     //search for the file in all prefixes and in all possible paths for each prefix
00166     //even if it's a big nested loop, usually there is one prefix and one location
00167     //so shouldn't cause too much disk access
00168     QStringList prefixes = d->structure->contentsPrefixPaths();
00169     if (prefixes.isEmpty()) {
00170         prefixes << QString();
00171     }
00172 
00173     foreach (const char *dir, d->structure->requiredDirectories()) {
00174         bool failed = true;
00175         foreach (const QString &path, d->structure->searchPath(dir)) {
00176             foreach (const QString &prefix, prefixes) {
00177                 if (QFile::exists(d->structure->path() + prefix + path)) {
00178                     failed = false;
00179                     break;
00180                 }
00181             }
00182             if (!failed) {
00183                 break;
00184             }
00185         }
00186 
00187         if (failed) {
00188             kWarning() << "Could not find required directory" << dir;
00189             d->valid = false;
00190             return false;
00191         }
00192     }
00193 
00194     foreach (const char *file, d->structure->requiredFiles()) {
00195         bool failed = true;
00196         foreach (const QString &path, d->structure->searchPath(file)) {
00197             foreach (const QString &prefix, prefixes) {
00198                 if (QFile::exists(d->structure->path() + prefix + path)) {
00199                     failed = false;
00200                     break;
00201                 }
00202             }
00203             if (!failed) {
00204                 break;
00205             }
00206         }
00207 
00208         if (failed) {
00209             kWarning() << "Could not find required file" << file;
00210             d->valid = false;
00211             return false;
00212         }
00213     }
00214 
00215     return true;
00216 }
00217 
00218 QString Package::filePath(const char *fileType, const QString &filename) const
00219 {
00220     if (!d->valid) {
00221         //kDebug() << "package is not valid";
00222         return QString();
00223     }
00224 
00225     QStringList paths;
00226 
00227     if (qstrlen(fileType) != 0) {
00228         paths = d->structure->searchPath(fileType);
00229 
00230         if (paths.isEmpty()) {
00231             //kDebug() << "no matching path came of it, while looking for" << fileType << filename;
00232             return QString();
00233         }
00234     } else {
00235         //when filetype is empty paths is always empty, so try with an empty string
00236         paths << QString();
00237     }
00238 
00239     //Nested loop, but in the medium case resolves to just one iteration
00240     QStringList prefixes = d->structure->contentsPrefixPaths();
00241     if (prefixes.isEmpty()) {
00242         prefixes << QString();
00243     }
00244 
00245     //kDebug() << "prefixes:" << prefixes.count() << prefixes;
00246     foreach (const QString &contentsPrefix, prefixes) {
00247         const QString prefix(d->structure->path() + contentsPrefix);
00248 
00249         foreach (const QString &path, paths) {
00250             QString file = prefix + path;
00251 
00252             if (!filename.isEmpty()) {
00253                 file.append("/").append(filename);
00254             }
00255 
00256             //kDebug() << "testing" << file << QFile::exists("/bin/ls") << QFile::exists(file);
00257             if (QFile::exists(file)) {
00258                 if (d->structure->allowExternalPaths()) {
00259                     //kDebug() << "found" << file;
00260                     return file;
00261                 }
00262 
00263                 // ensure that we don't return files outside of our base path
00264                 // due to symlink or ../ games
00265                 QDir dir(file);
00266                 QString canonicalized = dir.canonicalPath() + QDir::separator();
00267 
00268                 //kDebug() << "testing that" << canonicalized << "is in" << d->structure->path();
00269                 if (canonicalized.startsWith(d->structure->path())) {
00270                     //kDebug() << "found" << file;
00271                     return file;
00272                 }
00273             }
00274         }
00275     }
00276 
00277     //kDebug() << fileType << filename << "does not exist in" << prefixes << "at root" << d->structure->path();
00278     return QString();
00279 }
00280 
00281 QString Package::filePath(const char *fileType) const
00282 {
00283     return filePath(fileType, QString());
00284 }
00285 
00286 QStringList Package::entryList(const char *fileType) const
00287 {
00288     if (!d->valid) {
00289         return QStringList();
00290     }
00291 
00292     return d->structure->entryList(fileType);
00293 }
00294 
00295 PackageMetadata Package::metadata() const
00296 {
00297     if (d->structure) {
00298         return d->structure->metadata();
00299     }
00300 
00301     return PackageMetadata();
00302 }
00303 
00304 void Package::setPath(const QString &path)
00305 {
00306     if (d->structure) {
00307         d->structure->setPath(path);
00308         d->valid = !d->structure->path().isEmpty();
00309     }
00310 }
00311 
00312 const QString Package::path() const
00313 {
00314     return d->structure ? d->structure->path() : QString();
00315 }
00316 
00317 const PackageStructure::Ptr Package::structure() const
00318 {
00319     return d->structure;
00320 }
00321 
00322 #ifdef QCA2_FOUND
00323 void PackagePrivate::updateHash(const QString &basePath, const QString &subPath, const QDir &dir, QCA::Hash &hash)
00324 {
00325     // hash is calculated as a function of:
00326     // * files ordered alphabetically by name, with each file's:
00327     //      * path relative to the content root
00328     //      * file data
00329     // * directories ordered alphabetically by name, with each dir's:
00330     //      * path relative to the content root
00331     //      * file listing (recursing)
00332     // symlinks (in both the file and dir case) are handled by adding
00333     // the name of the symlink itself and the abs path of what it points to
00334 
00335     const QDir::SortFlags sorting = QDir::Name | QDir::IgnoreCase;
00336     const QDir::Filters filters = QDir::Hidden | QDir::System | QDir::NoDotAndDotDot;
00337     foreach (const QString &file, dir.entryList(QDir::Files | filters, sorting)) {
00338         if (!subPath.isEmpty()) {
00339             hash.update(subPath.toUtf8());
00340         }
00341 
00342         hash.update(file.toUtf8());
00343 
00344         QFileInfo info(dir.path() + '/' + file);
00345         if (info.isSymLink()) {
00346             hash.update(info.symLinkTarget().toUtf8());
00347         } else {
00348             QFile f(info.filePath());
00349             if (f.open(QIODevice::ReadOnly)) {
00350                 while (!f.atEnd()) {
00351                     hash.update(f.read(1024));
00352                 }
00353             } else {
00354                 kWarning() << "could not add" << f.fileName() << "to the hash; file could not be opened for reading. "
00355                            << "permissions fail?" << info.permissions() << info.isFile();
00356             }
00357         }
00358     }
00359 
00360     foreach (const QString &subDirPath, dir.entryList(QDir::Dirs | filters, sorting)) {
00361         const QString relativePath = subPath + subDirPath + '/';
00362         hash.update(relativePath.toUtf8());
00363 
00364         QDir subDir(dir.path());
00365         subDir.cd(subDirPath);
00366 
00367         if (subDir.path() != subDir.canonicalPath()) {
00368             hash.update(subDir.canonicalPath().toUtf8());
00369         } else {
00370             updateHash(basePath, relativePath, subDir, hash);
00371         }
00372     }
00373 }
00374 #endif
00375 
00376 QString Package::contentsHash() const
00377 {
00378 #ifdef QCA2_FOUND
00379     if (!d->valid) {
00380         kWarning() << "can not create hash due to Package being invalid";
00381         return QString();
00382     }
00383 
00384     //FIXME: the initializer should go somewhere global to be shared between all plasma uses?
00385     QCA::Initializer init;
00386     if (!QCA::isSupported("sha1")) {
00387         kWarning() << "can not create hash for" << path() << "due to no SHA1 support in QCA2";
00388         return QString();
00389     }
00390 
00391     QCA::Hash hash("sha1");
00392     QString metadataPath = d->structure->path() + "metadata.desktop";
00393     if (QFile::exists(metadataPath)) {
00394         QFile f(metadataPath);
00395         if (f.open(QIODevice::ReadOnly)) {
00396             while (!f.atEnd()) {
00397                 hash.update(f.read(1024));
00398             }
00399         } else {
00400             kWarning() << "could not add" << f.fileName() << "to the hash; file could not be opened for reading.";
00401         }
00402     } else {
00403         kWarning() << "no metadata at" << metadataPath;
00404     }
00405 
00406     QStringList prefixes = d->structure->contentsPrefixPaths();
00407     if (prefixes.isEmpty()) {
00408         prefixes << QString();
00409     }
00410 
00411     foreach (QString prefix, prefixes) {
00412         const QString basePath = d->structure->path() + prefix;
00413         QDir dir(basePath);
00414 
00415         if (!dir.exists()) {
00416             return QString();
00417         }
00418 
00419         d->updateHash(basePath, QString(), dir, hash);
00420     }
00421     return QCA::arrayToHex(hash.final().toByteArray());
00422 #else
00423     // no QCA2!
00424     kWarning() << "can not create hash for" << path() << "due to no cryptographic support (QCA2)";
00425     return QString();
00426 #endif
00427 }
00428 
00429 //TODO: provide a version of this that allows one to ask for certain types of packages, etc?
00430 //      should we be using KService here instead/as well?
00431 QStringList Package::listInstalled(const QString &packageRoot) // static
00432 {
00433     QDir dir(packageRoot);
00434 
00435     if (!dir.exists()) {
00436         return QStringList();
00437     }
00438 
00439     QStringList packages;
00440 
00441     foreach (const QString &sdir, dir.entryList(QDir::AllDirs | QDir::Readable)) {
00442         QString metadata = packageRoot + '/' + sdir + "/metadata.desktop";
00443         if (QFile::exists(metadata)) {
00444             PackageMetadata m(metadata);
00445             packages << m.pluginName();
00446         }
00447     }
00448 
00449     return packages;
00450 }
00451 
00452 QStringList Package::listInstalledPaths(const QString &packageRoot) // static
00453 {
00454     QDir dir(packageRoot);
00455 
00456     if (!dir.exists()) {
00457         return QStringList();
00458     }
00459 
00460     QStringList packages;
00461 
00462     foreach (const QString &sdir, dir.entryList(QDir::AllDirs | QDir::Readable)) {
00463         QString metadata = packageRoot + '/' + sdir + "/metadata.desktop";
00464         if (QFile::exists(metadata)) {
00465             packages << sdir;
00466         }
00467     }
00468 
00469     return packages;
00470 }
00471 
00472 bool Package::installPackage(const QString &package,
00473                              const QString &packageRoot,
00474                              const QString &servicePrefix) // static
00475 {
00476     //TODO: report *what* failed if something does fail
00477     QDir root(packageRoot);
00478 
00479     if (!root.exists()) {
00480         KStandardDirs::makeDir(packageRoot);
00481         if (!root.exists()) {
00482             kWarning() << "Could not create package root directory:" << packageRoot;
00483             return false;
00484         }
00485     }
00486 
00487     QFileInfo fileInfo(package);
00488     if (!fileInfo.exists()) {
00489         kWarning() << "No such file:" << package;
00490         return false;
00491     }
00492 
00493     QString path;
00494     KTempDir tempdir;
00495     bool archivedPackage = false;
00496 
00497     if (fileInfo.isDir()) {
00498         // we have a directory, so let's just install what is in there
00499         path = package;
00500 
00501         // make sure we end in a slash!
00502         if (path[path.size() - 1] != '/') {
00503             path.append('/');
00504         }
00505     } else {
00506         KArchive *archive = 0;
00507         KMimeType::Ptr mimetype = KMimeType::findByPath(package);
00508 
00509         if (mimetype->is("application/zip")) {
00510             archive = new KZip(package);
00511         } else if (mimetype->is("application/x-compressed-tar") ||
00512                    mimetype->is("application/x-tar")|| mimetype->is("application/x-bzip-compressed-tar")) {
00513             archive = new KTar(package);
00514         } else {
00515             kWarning() << "Could not open package file, unsupported archive format:" << package << mimetype->name();
00516             return false;
00517         }
00518 
00519         if (!archive->open(QIODevice::ReadOnly)) {
00520             kWarning() << "Could not open package file:" << package;
00521         delete archive;
00522             return false;
00523         }
00524 
00525         archivedPackage = true;
00526         path = tempdir.name();
00527 
00528         const KArchiveDirectory *source = archive->directory();
00529         source->copyTo(path);
00530 
00531         QStringList entries = source->entries();
00532         if (entries.count() == 1) {
00533             const KArchiveEntry *entry = source->entry(entries[0]);
00534             if (entry->isDirectory()) {
00535                 path.append(entry->name()).append("/");
00536             }
00537         }
00538     delete archive;
00539     }
00540 
00541     QString metadataPath = path + "metadata.desktop";
00542     if (!QFile::exists(metadataPath)) {
00543         kWarning() << "No metadata file in package" << package << metadataPath;
00544         return false;
00545     }
00546 
00547     PackageMetadata meta(metadataPath);
00548     QString targetName = meta.pluginName();
00549 
00550     if (targetName.isEmpty()) {
00551         kWarning() << "Package plugin name not specified";
00552         return false;
00553     }
00554 
00555     // Ensure that package names are safe so package uninstall can't inject
00556     // bad characters into the paths used for removal.
00557     QRegExp validatePluginName("^[\\w-\\.]+$"); // Only allow letters, numbers, underscore and period.
00558     if (!validatePluginName.exactMatch(targetName)) {
00559         kWarning() << "Package plugin name " << targetName << "contains invalid characters";
00560         return false;
00561     }
00562 
00563     targetName = packageRoot + '/' + targetName;
00564     if (QFile::exists(targetName)) {
00565         kWarning() << targetName << "already exists";
00566         return false;
00567     }
00568 
00569     if (archivedPackage) {
00570         // it's in a temp dir, so just move it over.
00571 #ifndef PLASMA_NO_KIO
00572         KIO::CopyJob *job = KIO::move(KUrl(path), KUrl(targetName), KIO::HideProgressInfo);
00573         const bool ok = job->exec();
00574         const QString errorString = job->errorString();
00575 #else
00576         const bool ok = copyFolder(path, targetName);
00577         removeFolder(path);
00578         const QString errorString("unknown");
00579 #endif
00580         if (!ok) {
00581             kWarning() << "Could not move package to destination:" << targetName << " : " << errorString;
00582             return false;
00583         }
00584     } else {
00585         // it's a directory containing the stuff, so copy the contents rather
00586         // than move them
00587 #ifndef PLASMA_NO_KIO
00588         KIO::CopyJob *job = KIO::copy(KUrl(path), KUrl(targetName), KIO::HideProgressInfo);
00589         const bool ok = job->exec();
00590         const QString errorString = job->errorString();
00591 #else
00592         const bool ok = copyFolder(path, targetName);
00593         const QString errorString("unknown");
00594 #endif
00595         if (!ok) {
00596             kWarning() << "Could not copy package to destination:" << targetName << " : " << errorString;
00597             return false;
00598         }
00599     }
00600 
00601     if (archivedPackage) {
00602         // no need to remove the temp dir (which has been successfully moved if it's an archive)
00603         tempdir.setAutoRemove(false);
00604     }
00605 
00606     if (!servicePrefix.isEmpty()) {
00607         // and now we register it as a service =)
00608         QString metaPath = targetName + "/metadata.desktop";
00609         KDesktopFile df(metaPath);
00610         KConfigGroup cg = df.desktopGroup();
00611 
00612         // Q: should not installing it as a service disqualify it?
00613         // Q: i don't think so since KServiceTypeTrader may not be
00614         // used by the installing app in any case, and the
00615         // package is properly installed - aseigo
00616 
00617         //TODO: reduce code duplication with registerPackage below
00618 
00619         QString serviceName = servicePrefix + meta.pluginName();
00620 
00621         QString service = KStandardDirs::locateLocal("services", serviceName + ".desktop");
00622 #ifndef PLASMA_NO_KIO
00623         KIO::FileCopyJob *job = KIO::file_copy(metaPath, service, -1, KIO::HideProgressInfo);
00624         const bool ok = job->exec();
00625         const QString errorString = job->errorString();
00626 #else
00627         const bool ok = QFile::copy(metaPath, service);
00628         const QString errorString("unknown");
00629 #endif
00630         if (ok) {
00631             // the icon in the installed file needs to point to the icon in the
00632             // installation dir!
00633             QString iconPath = targetName + '/' + cg.readEntry("Icon");
00634             QFile icon(iconPath);
00635             if (icon.exists()) {
00636                 KDesktopFile df(service);
00637                 KConfigGroup cg = df.desktopGroup();
00638                 cg.writeEntry("Icon", iconPath);
00639             }
00640         } else {
00641             kWarning() << "Could not register package as service (this is not necessarily fatal):" << serviceName << " : " << errorString;
00642         }
00643     }
00644 
00645     return true;
00646 }
00647 
00648 bool Package::uninstallPackage(const QString &pluginName,
00649                                const QString &packageRoot,
00650                                const QString &servicePrefix) // static
00651 {
00652     // We need to remove the package directory and its metadata file.
00653     QString targetName = pluginName;
00654     targetName = packageRoot + '/' + targetName;
00655 
00656     if (!QFile::exists(targetName)) {
00657         kWarning() << targetName << "does not exist";
00658         return false;
00659     }
00660 
00661     QString serviceName = servicePrefix + pluginName;
00662 
00663     QString service = KStandardDirs::locateLocal("services", serviceName + ".desktop");
00664     kDebug() << "Removing service file " << service;
00665     bool ok = QFile::remove(service);
00666 
00667     if (!ok) {
00668         kWarning() << "Unable to remove " << service;
00669     }
00670 
00671 #ifndef PLASMA_NO_KIO
00672     KIO::DeleteJob *job = KIO::del(KUrl(targetName));
00673     ok = job->exec();
00674     const QString errorString = job->errorString();
00675 #else
00676     ok = removeFolder(targetName);
00677     const QString errorString("unknown");
00678 #endif
00679     if (!ok) {
00680         kWarning() << "Could not delete package from:" << targetName << " : " << errorString;
00681         return false;
00682     }
00683 
00684     return true;
00685 }
00686 
00687 bool Package::registerPackage(const PackageMetadata &data, const QString &iconPath)
00688 {
00689     QString serviceName("plasma-applet-" + data.pluginName());
00690     QString service = KStandardDirs::locateLocal("services", serviceName + ".desktop");
00691 
00692     if (data.pluginName().isEmpty()) {
00693         return false;
00694     }
00695 
00696     data.write(service);
00697 
00698     KDesktopFile config(service);
00699     KConfigGroup cg = config.desktopGroup();
00700     const QString type = data.type().isEmpty() ? "Service" : data.type();
00701     cg.writeEntry("Type", type);
00702     const QString serviceTypes = data.serviceType().isNull() ? "Plasma/Applet,Plasma/Containment" : data.serviceType();
00703     cg.writeEntry("X-KDE-ServiceTypes", serviceTypes);
00704     cg.writeEntry("X-KDE-PluginInfo-EnabledByDefault", true);
00705 
00706     QFile icon(iconPath);
00707     if (icon.exists()) {
00708         //FIXME: the '/' search will break on non-UNIX. do we care?
00709         QString installedIcon("plasma_applet_" + data.pluginName() +
00710                               iconPath.right(iconPath.length() - iconPath.lastIndexOf("/")));
00711         cg.writeEntry("Icon", installedIcon);
00712         installedIcon = KStandardDirs::locateLocal("icon", installedIcon);
00713 #ifndef PLASMA_NO_KIO
00714         KIO::FileCopyJob *job = KIO::file_copy(iconPath, installedIcon, -1, KIO::HideProgressInfo);
00715         job->exec();
00716 #else
00717         QFile::copy(iconPath, installedIcon);
00718 #endif
00719     }
00720 
00721     return true;
00722 }
00723 
00724 bool Package::createPackage(const PackageMetadata &metadata,
00725                             const QString &source,
00726                             const QString &destination,
00727                             const QString &icon) // static
00728 {
00729     Q_UNUSED(icon)
00730     if (!metadata.isValid()) {
00731         kWarning() << "Metadata file is not complete";
00732         return false;
00733     }
00734 
00735     // write metadata in a temporary file
00736     KTemporaryFile metadataFile;
00737     if (!metadataFile.open()) {
00738         return false;
00739     }
00740     metadata.write(metadataFile.fileName());
00741 
00742     // put everything into a zip archive
00743     KZip creation(destination);
00744     creation.setCompression(KZip::NoCompression);
00745     if (!creation.open(QIODevice::WriteOnly)) {
00746         return false;
00747     }
00748 
00749     creation.addLocalFile(metadataFile.fileName(), "metadata.desktop");
00750     creation.addLocalDirectory(source, "contents");
00751     creation.close();
00752     return true;
00753 }
00754 
00755 PackagePrivate::PackagePrivate(const PackageStructure::Ptr st, const QString &p)
00756         : structure(st),
00757           service(0)
00758 {
00759     if (structure) {
00760         if (p.isEmpty()) {
00761             structure->setPath(structure->defaultPackageRoot());
00762         } else {
00763             structure->setPath(p);
00764         }
00765     }
00766 
00767     valid = structure && !structure->path().isEmpty();
00768 }
00769 
00770 PackagePrivate::PackagePrivate(const PackageStructure::Ptr st, const QString &packageRoot, const QString &path)
00771         : structure(st),
00772           service(0)
00773 {
00774     if (structure) {
00775         if (packageRoot.isEmpty()) {
00776             structure->setPath(structure->defaultPackageRoot()%"/"%path);
00777         } else {
00778             structure->setPath(packageRoot%"/"%path);
00779         }
00780     }
00781 
00782     valid = structure && !structure->path().isEmpty();
00783 }
00784 
00785 PackagePrivate::PackagePrivate(const PackagePrivate &other)
00786         : structure(other.structure),
00787           service(other.service),
00788           valid(other.valid)
00789 {
00790 }
00791 
00792 PackagePrivate::~PackagePrivate()
00793 {
00794 }
00795 
00796 PackagePrivate &PackagePrivate::operator=(const PackagePrivate &rhs)
00797 {
00798     structure = rhs.structure;
00799     service = rhs.service;
00800     valid = rhs.valid;
00801     return *this;
00802 }
00803 
00804 void PackagePrivate::publish(AnnouncementMethods methods)
00805 {
00806     if (!structure) {
00807         return;
00808     }
00809 
00810     if (!service) {
00811         service = new PlasmoidService(structure->path());
00812     }
00813 
00814     QString resourceName =
00815     i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
00816           "%1 on %2", structure->metadata().name(), QHostInfo::localHostName());
00817     kDebug() << "publishing package under name " << resourceName;
00818     service->d->publish(methods, resourceName, structure->metadata());
00819 }
00820 
00821 void PackagePrivate::unpublish()
00822 {
00823     if (service) {
00824         service->d->unpublish();
00825     }
00826 }
00827 
00828 bool PackagePrivate::isPublished() const
00829 {
00830     if (service) {
00831         return service->d->isPublished();
00832     } else {
00833         return false;
00834     }
00835 }
00836 
00837 } // Namespace

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

Skip menu "kdelibs"
  • 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
Generated for kdelibs by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal