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
KDE 4.6 API Reference