• Skip to content
  • Skip to link menu
KDE 4.6 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     if (!QCA::isSupported("sha1")) {
00385         kWarning() << "can not create hash for" << path() << "due to no SHA1 support in QCA2";
00386         return QString();
00387     }
00388 
00389     QCA::Hash hash("sha1");
00390     QString metadataPath = d->structure->path() + "metadata.desktop";
00391     if (QFile::exists(metadataPath)) {
00392         QFile f(metadataPath);
00393         if (f.open(QIODevice::ReadOnly)) {
00394             while (!f.atEnd()) {
00395                 hash.update(f.read(1024));
00396             }
00397         } else {
00398             kWarning() << "could not add" << f.fileName() << "to the hash; file could not be opened for reading.";
00399         }
00400     } else {
00401         kWarning() << "no metadata at" << metadataPath;
00402     }
00403 
00404     QStringList prefixes = d->structure->contentsPrefixPaths();
00405     if (prefixes.isEmpty()) {
00406         prefixes << QString();
00407     }
00408 
00409     foreach (QString prefix, prefixes) {
00410         const QString basePath = d->structure->path() + prefix;
00411         QDir dir(basePath);
00412 
00413         if (!dir.exists()) {
00414             return QString();
00415         }
00416 
00417         d->updateHash(basePath, QString(), dir, hash);
00418     }
00419     return QCA::arrayToHex(hash.final().toByteArray());
00420 #else
00421     // no QCA2!
00422     kWarning() << "can not create hash for" << path() << "due to no cryptographic support (QCA2)";
00423     return QString();
00424 #endif
00425 }
00426 
00427 //TODO: provide a version of this that allows one to ask for certain types of packages, etc?
00428 //      should we be using KService here instead/as well?
00429 QStringList Package::listInstalled(const QString &packageRoot) // static
00430 {
00431     QDir dir(packageRoot);
00432 
00433     if (!dir.exists()) {
00434         return QStringList();
00435     }
00436 
00437     QStringList packages;
00438 
00439     foreach (const QString &sdir, dir.entryList(QDir::AllDirs | QDir::Readable)) {
00440         QString metadata = packageRoot + '/' + sdir + "/metadata.desktop";
00441         if (QFile::exists(metadata)) {
00442             PackageMetadata m(metadata);
00443             packages << m.pluginName();
00444         }
00445     }
00446 
00447     return packages;
00448 }
00449 
00450 QStringList Package::listInstalledPaths(const QString &packageRoot) // static
00451 {
00452     QDir dir(packageRoot);
00453 
00454     if (!dir.exists()) {
00455         return QStringList();
00456     }
00457 
00458     QStringList packages;
00459 
00460     foreach (const QString &sdir, dir.entryList(QDir::AllDirs | QDir::Readable)) {
00461         QString metadata = packageRoot + '/' + sdir + "/metadata.desktop";
00462         if (QFile::exists(metadata)) {
00463             packages << sdir;
00464         }
00465     }
00466 
00467     return packages;
00468 }
00469 
00470 bool Package::installPackage(const QString &package,
00471                              const QString &packageRoot,
00472                              const QString &servicePrefix) // static
00473 {
00474     //TODO: report *what* failed if something does fail
00475     QDir root(packageRoot);
00476 
00477     if (!root.exists()) {
00478         KStandardDirs::makeDir(packageRoot);
00479         if (!root.exists()) {
00480             kWarning() << "Could not create package root directory:" << packageRoot;
00481             return false;
00482         }
00483     }
00484 
00485     QFileInfo fileInfo(package);
00486     if (!fileInfo.exists()) {
00487         kWarning() << "No such file:" << package;
00488         return false;
00489     }
00490 
00491     QString path;
00492     KTempDir tempdir;
00493     bool archivedPackage = false;
00494 
00495     if (fileInfo.isDir()) {
00496         // we have a directory, so let's just install what is in there
00497         path = package;
00498 
00499         // make sure we end in a slash!
00500         if (path[path.size() - 1] != '/') {
00501             path.append('/');
00502         }
00503     } else {
00504         KArchive *archive = 0;
00505         KMimeType::Ptr mimetype = KMimeType::findByPath(package);
00506 
00507         if (mimetype->is("application/zip")) {
00508             archive = new KZip(package);
00509         } else if (mimetype->is("application/x-compressed-tar") ||
00510                    mimetype->is("application/x-tar")|| mimetype->is("application/x-bzip-compressed-tar")) {
00511             archive = new KTar(package);
00512         } else {
00513             kWarning() << "Could not open package file, unsupported archive format:" << package << mimetype->name();
00514             return false;
00515         }
00516 
00517         if (!archive->open(QIODevice::ReadOnly)) {
00518             kWarning() << "Could not open package file:" << package;
00519         delete archive;
00520             return false;
00521         }
00522 
00523         archivedPackage = true;
00524         path = tempdir.name();
00525 
00526         const KArchiveDirectory *source = archive->directory();
00527         source->copyTo(path);
00528 
00529         QStringList entries = source->entries();
00530         if (entries.count() == 1) {
00531             const KArchiveEntry *entry = source->entry(entries[0]);
00532             if (entry->isDirectory()) {
00533                 path.append(entry->name()).append("/");
00534             }
00535         }
00536     delete archive;
00537     }
00538 
00539     QString metadataPath = path + "metadata.desktop";
00540     if (!QFile::exists(metadataPath)) {
00541         kWarning() << "No metadata file in package" << package << metadataPath;
00542         return false;
00543     }
00544 
00545     PackageMetadata meta(metadataPath);
00546     QString targetName = meta.pluginName();
00547 
00548     if (targetName.isEmpty()) {
00549         kWarning() << "Package plugin name not specified";
00550         return false;
00551     }
00552 
00553     // Ensure that package names are safe so package uninstall can't inject
00554     // bad characters into the paths used for removal.
00555     QRegExp validatePluginName("^[\\w-\\.]+$"); // Only allow letters, numbers, underscore and period.
00556     if (!validatePluginName.exactMatch(targetName)) {
00557         kWarning() << "Package plugin name " << targetName << "contains invalid characters";
00558         return false;
00559     }
00560 
00561     targetName = packageRoot + '/' + targetName;
00562     if (QFile::exists(targetName)) {
00563         kWarning() << targetName << "already exists";
00564         return false;
00565     }
00566 
00567     if (archivedPackage) {
00568         // it's in a temp dir, so just move it over.
00569 #ifndef PLASMA_NO_KIO
00570         KIO::CopyJob *job = KIO::move(KUrl(path), KUrl(targetName), KIO::HideProgressInfo);
00571         const bool ok = job->exec();
00572         const QString errorString = job->errorString();
00573 #else
00574         const bool ok = copyFolder(path, targetName);
00575         removeFolder(path);
00576         const QString errorString("unknown");
00577 #endif
00578         if (!ok) {
00579             kWarning() << "Could not move package to destination:" << targetName << " : " << errorString;
00580             return false;
00581         }
00582     } else {
00583         // it's a directory containing the stuff, so copy the contents rather
00584         // than move them
00585 #ifndef PLASMA_NO_KIO
00586         KIO::CopyJob *job = KIO::copy(KUrl(path), KUrl(targetName), KIO::HideProgressInfo);
00587         const bool ok = job->exec();
00588         const QString errorString = job->errorString();
00589 #else
00590         const bool ok = copyFolder(path, targetName);
00591         const QString errorString("unknown");
00592 #endif
00593         if (!ok) {
00594             kWarning() << "Could not copy package to destination:" << targetName << " : " << errorString;
00595             return false;
00596         }
00597     }
00598 
00599     if (archivedPackage) {
00600         // no need to remove the temp dir (which has been successfully moved if it's an archive)
00601         tempdir.setAutoRemove(false);
00602     }
00603 
00604     if (!servicePrefix.isEmpty()) {
00605         // and now we register it as a service =)
00606         QString metaPath = targetName + "/metadata.desktop";
00607         KDesktopFile df(metaPath);
00608         KConfigGroup cg = df.desktopGroup();
00609 
00610         // Q: should not installing it as a service disqualify it?
00611         // Q: i don't think so since KServiceTypeTrader may not be
00612         // used by the installing app in any case, and the
00613         // package is properly installed - aseigo
00614 
00615         //TODO: reduce code duplication with registerPackage below
00616 
00617         QString serviceName = servicePrefix + meta.pluginName();
00618 
00619         QString service = KStandardDirs::locateLocal("services", serviceName + ".desktop");
00620 #ifndef PLASMA_NO_KIO
00621         KIO::FileCopyJob *job = KIO::file_copy(metaPath, service, -1, KIO::HideProgressInfo);
00622         const bool ok = job->exec();
00623         const QString errorString = job->errorString();
00624 #else
00625         const bool ok = QFile::copy(metaPath, service);
00626         const QString errorString("unknown");
00627 #endif
00628         if (ok) {
00629             // the icon in the installed file needs to point to the icon in the
00630             // installation dir!
00631             QString iconPath = targetName + '/' + cg.readEntry("Icon");
00632             QFile icon(iconPath);
00633             if (icon.exists()) {
00634                 KDesktopFile df(service);
00635                 KConfigGroup cg = df.desktopGroup();
00636                 cg.writeEntry("Icon", iconPath);
00637             }
00638         } else {
00639             kWarning() << "Could not register package as service (this is not necessarily fatal):" << serviceName << " : " << errorString;
00640         }
00641     }
00642 
00643     return true;
00644 }
00645 
00646 bool Package::uninstallPackage(const QString &pluginName,
00647                                const QString &packageRoot,
00648                                const QString &servicePrefix) // static
00649 {
00650     // We need to remove the package directory and its metadata file.
00651     QString targetName = pluginName;
00652     targetName = packageRoot + '/' + targetName;
00653 
00654     if (!QFile::exists(targetName)) {
00655         kWarning() << targetName << "does not exist";
00656         return false;
00657     }
00658 
00659     QString serviceName = servicePrefix + pluginName;
00660 
00661     QString service = KStandardDirs::locateLocal("services", serviceName + ".desktop");
00662     kDebug() << "Removing service file " << service;
00663     bool ok = QFile::remove(service);
00664 
00665     if (!ok) {
00666         kWarning() << "Unable to remove " << service;
00667     }
00668 
00669 #ifndef PLASMA_NO_KIO
00670     KIO::DeleteJob *job = KIO::del(KUrl(targetName));
00671     ok = job->exec();
00672     const QString errorString = job->errorString();
00673 #else
00674     ok = removeFolder(targetName);
00675     const QString errorString("unknown");
00676 #endif
00677     if (!ok) {
00678         kWarning() << "Could not delete package from:" << targetName << " : " << errorString;
00679         return false;
00680     }
00681 
00682     return true;
00683 }
00684 
00685 bool Package::registerPackage(const PackageMetadata &data, const QString &iconPath)
00686 {
00687     QString serviceName("plasma-applet-" + data.pluginName());
00688     QString service = KStandardDirs::locateLocal("services", serviceName + ".desktop");
00689 
00690     if (data.pluginName().isEmpty()) {
00691         return false;
00692     }
00693 
00694     data.write(service);
00695 
00696     KDesktopFile config(service);
00697     KConfigGroup cg = config.desktopGroup();
00698     const QString type = data.type().isEmpty() ? "Service" : data.type();
00699     cg.writeEntry("Type", type);
00700     const QString serviceTypes = data.serviceType().isNull() ? "Plasma/Applet,Plasma/Containment" : data.serviceType();
00701     cg.writeEntry("X-KDE-ServiceTypes", serviceTypes);
00702     cg.writeEntry("X-KDE-PluginInfo-EnabledByDefault", true);
00703 
00704     QFile icon(iconPath);
00705     if (icon.exists()) {
00706         //FIXME: the '/' search will break on non-UNIX. do we care?
00707         QString installedIcon("plasma_applet_" + data.pluginName() +
00708                               iconPath.right(iconPath.length() - iconPath.lastIndexOf("/")));
00709         cg.writeEntry("Icon", installedIcon);
00710         installedIcon = KStandardDirs::locateLocal("icon", installedIcon);
00711 #ifndef PLASMA_NO_KIO
00712         KIO::FileCopyJob *job = KIO::file_copy(iconPath, installedIcon, -1, KIO::HideProgressInfo);
00713         job->exec();
00714 #else
00715         QFile::copy(iconPath, installedIcon);
00716 #endif
00717     }
00718 
00719     return true;
00720 }
00721 
00722 bool Package::createPackage(const PackageMetadata &metadata,
00723                             const QString &source,
00724                             const QString &destination,
00725                             const QString &icon) // static
00726 {
00727     Q_UNUSED(icon)
00728     if (!metadata.isValid()) {
00729         kWarning() << "Metadata file is not complete";
00730         return false;
00731     }
00732 
00733     // write metadata in a temporary file
00734     KTemporaryFile metadataFile;
00735     if (!metadataFile.open()) {
00736         return false;
00737     }
00738     metadata.write(metadataFile.fileName());
00739 
00740     // put everything into a zip archive
00741     KZip creation(destination);
00742     creation.setCompression(KZip::NoCompression);
00743     if (!creation.open(QIODevice::WriteOnly)) {
00744         return false;
00745     }
00746 
00747     creation.addLocalFile(metadataFile.fileName(), "metadata.desktop");
00748     creation.addLocalDirectory(source, "contents");
00749     creation.close();
00750     return true;
00751 }
00752 
00753 PackagePrivate::PackagePrivate(const PackageStructure::Ptr st, const QString &p)
00754         : structure(st),
00755           service(0)
00756 {
00757     if (structure) {
00758         structure->setPath(p);
00759     }
00760 
00761     valid = structure && !structure->path().isEmpty();
00762 }
00763 
00764 PackagePrivate::PackagePrivate(const PackagePrivate &other)
00765         : structure(other.structure),
00766           service(other.service),
00767           valid(other.valid)
00768 {
00769 }
00770 
00771 PackagePrivate::~PackagePrivate()
00772 {
00773 }
00774 
00775 PackagePrivate &PackagePrivate::operator=(const PackagePrivate &rhs)
00776 {
00777     structure = rhs.structure;
00778     service = rhs.service;
00779     valid = rhs.valid;
00780     return *this;
00781 }
00782 
00783 void PackagePrivate::publish(AnnouncementMethods methods)
00784 {
00785     if (!structure) {
00786         return;
00787     }
00788 
00789     if (!service) {
00790         service = new PlasmoidService(structure->path());
00791     }
00792 
00793     QString resourceName =
00794     i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
00795           "%1 on %2", structure->metadata().name(), QHostInfo::localHostName());
00796     kDebug() << "publishing package under name " << resourceName;
00797     service->d->publish(methods, resourceName, structure->metadata());
00798 }
00799 
00800 void PackagePrivate::unpublish()
00801 {
00802     if (service) {
00803         service->d->unpublish();
00804     }
00805 }
00806 
00807 bool PackagePrivate::isPublished() const
00808 {
00809     if (service) {
00810         return service->d->isPublished();
00811     } else {
00812         return false;
00813     }
00814 }
00815 
00816 } // Namespace

Plasma

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • 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.3
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