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

KIO

kdesktopfileactions.cpp
Go to the documentation of this file.
00001 /*  This file is part of the KDE libraries
00002  *  Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
00003  *                     David Faure   <faure@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 version 2 as published by the Free Software Foundation;
00008  *
00009  *  This library is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  *  Library General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU Library General Public License
00015  *  along with this library; see the file COPYING.LIB.  If not, write to
00016  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  *  Boston, MA 02110-1301, USA.
00018  **/
00019 
00020 #include "kdesktopfileactions.h"
00021 
00022 #include "config-kio.h"
00023 
00024 #include "krun.h"
00025 #include "kautomount.h"
00026 #include <kmessageboxwrapper.h>
00027 #include <kdirnotify.h>
00028 #include <kmountpoint.h>
00029 
00030 #include <kstandarddirs.h>
00031 #include <kdesktopfile.h>
00032 #include <kconfiggroup.h>
00033 #include <klocale.h>
00034 #include <kservice.h>
00035 
00036 #ifndef KIO_NO_SOLID
00037 //Solid
00038 #include <solid/devicenotifier.h>
00039 #include <solid/device.h>
00040 #include <solid/deviceinterface.h>
00041 #include <solid/predicate.h>
00042 #include <solid/storageaccess.h>
00043 #include <solid/opticaldrive.h>
00044 #include <solid/opticaldisc.h>
00045 #include <solid/block.h>
00046 #endif
00047 
00048 enum BuiltinServiceType { ST_MOUNT = 0x0E1B05B0, ST_UNMOUNT = 0x0E1B05B1 }; // random numbers
00049 
00050 static bool runFSDevice( const KUrl& _url, const KDesktopFile &cfg );
00051 static bool runApplication( const KUrl& _url, const QString & _serviceFile );
00052 static bool runLink( const KUrl& _url, const KDesktopFile &cfg );
00053 
00054 bool KDesktopFileActions::run( const KUrl& u, bool _is_local )
00055 {
00056     // It might be a security problem to run external untrusted desktop
00057     // entry files
00058     if ( !_is_local )
00059         return false;
00060 
00061     KDesktopFile cfg( u.path() );
00062     if ( !cfg.desktopGroup().hasKey("Type") )
00063     {
00064         QString tmp = i18n("The desktop entry file %1 "
00065                            "has no Type=... entry.", u.path() );
00066         KMessageBoxWrapper::error( 0, tmp);
00067         return false;
00068     }
00069 
00070     //kDebug(7000) << "TYPE = " << type.data();
00071 
00072     if ( cfg.hasDeviceType() )
00073         return runFSDevice( u, cfg );
00074     else if ( cfg.hasApplicationType()
00075               || (cfg.readType() == "Service" && !cfg.desktopGroup().readEntry("Exec").isEmpty())) // for kio_settings
00076         return runApplication( u, u.toLocalFile() );
00077     else if ( cfg.hasLinkType() )
00078         return runLink( u, cfg );
00079 
00080     QString tmp = i18n("The desktop entry of type\n%1\nis unknown.",  cfg.readType() );
00081     KMessageBoxWrapper::error( 0, tmp);
00082 
00083     return false;
00084 }
00085 
00086 static bool runFSDevice( const KUrl& _url, const KDesktopFile &cfg )
00087 {
00088     bool retval = false;
00089 
00090     QString dev = cfg.readDevice();
00091 
00092     if ( dev.isEmpty() )
00093     {
00094         QString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.",  _url.path() );
00095         KMessageBoxWrapper::error( 0, tmp);
00096         return retval;
00097     }
00098 
00099     KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByDevice( dev );
00100     // Is the device already mounted ?
00101     if (mp) {
00102         KUrl mpURL(mp->mountPoint());
00103         // Open a new window
00104         retval = KRun::runUrl( mpURL, QLatin1String("inode/directory"), 0 /*TODO - window*/ );
00105     } else {
00106         KConfigGroup cg = cfg.desktopGroup();
00107         bool ro = cg.readEntry("ReadOnly", false);
00108         QString fstype = cg.readEntry( "FSType" );
00109         if ( fstype == "Default" ) // KDE-1 thing
00110             fstype.clear();
00111         QString point = cg.readEntry( "MountPoint" );
00112 #ifndef Q_WS_WIN
00113         (void) new KAutoMount( ro, fstype.toLatin1(), dev, point, _url.path() );
00114 #endif
00115         retval = false;
00116     }
00117 
00118     return retval;
00119 }
00120 
00121 static bool runApplication( const KUrl& , const QString & _serviceFile )
00122 {
00123     KService s( _serviceFile );
00124     if ( !s.isValid() )
00125         // The error message was already displayed, so we can just quit here
00126         // ### KDE4: is this still the case?
00127         return false;
00128 
00129     KUrl::List lst;
00130     return KRun::run( s, lst, 0 /*TODO - window*/ );
00131 }
00132 
00133 static bool runLink( const KUrl& _url, const KDesktopFile &cfg )
00134 {
00135     QString u = cfg.readUrl();
00136     if ( u.isEmpty() )
00137     {
00138         QString tmp = i18n("The desktop entry file\n%1\nis of type Link but has no URL=... entry.",  _url.prettyUrl() );
00139         KMessageBoxWrapper::error( 0, tmp );
00140         return false;
00141     }
00142 
00143     KUrl url ( u );
00144     KRun* run = new KRun(url,(QWidget*)0);
00145 
00146     // X-KDE-LastOpenedWith holds the service desktop entry name that
00147     // was should be preferred for opening this URL if possible.
00148     // This is used by the Recent Documents menu for instance.
00149     QString lastOpenedWidth = cfg.desktopGroup().readEntry( "X-KDE-LastOpenedWith" );
00150     if ( !lastOpenedWidth.isEmpty() )
00151         run->setPreferredService( lastOpenedWidth );
00152 
00153     return false;
00154 }
00155 
00156 QList<KServiceAction> KDesktopFileActions::builtinServices( const KUrl& _url )
00157 {
00158     QList<KServiceAction> result;
00159 
00160     if ( !_url.isLocalFile() )
00161         return result;
00162 
00163     bool offerMount = false;
00164     bool offerUnmount = false;
00165 
00166     KDesktopFile cfg( _url.toLocalFile() );
00167     if ( cfg.hasDeviceType() ) {  // url to desktop file
00168         const QString dev = cfg.readDevice();
00169         if ( dev.isEmpty() ) {
00170             QString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.",  _url.toLocalFile() );
00171             KMessageBoxWrapper::error(0, tmp);
00172             return result;
00173         }
00174 
00175         KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByDevice( dev );
00176         if (mp) {
00177             offerUnmount = true;
00178         }
00179         else {
00180             offerMount = true;
00181         }
00182     }
00183 #ifndef KIO_NO_SOLID
00184     else { // url to device
00185         Solid::Predicate predicate(Solid::DeviceInterface::Block, "device", _url.toLocalFile());
00186         const QList<Solid::Device> devList = Solid::Device::listFromQuery(predicate, QString());
00187         if (devList.empty()) {
00188             kDebug(7000) << "Device" << _url.toLocalFile() << "not found";
00189             return result;
00190         }
00191         Solid::Device device = devList[0];
00192         Solid::StorageAccess *access = device.as<Solid::StorageAccess>();
00193         Solid::StorageDrive *drive = device.parent().as<Solid::StorageDrive>();
00194         bool mounted = access && access->isAccessible();
00195 
00196         if ((mounted || device.is<Solid::OpticalDisc>()) && drive && drive->isRemovable()) {
00197             offerUnmount = true;
00198         }
00199 
00200         if (!mounted && ((drive && drive->isHotpluggable()) || device.is<Solid::OpticalDisc>())) {
00201             offerMount = true;
00202         }
00203     }
00204 #endif
00205 
00206     if (offerMount) {
00207         KServiceAction mount("mount", i18n("Mount"), QString(), QString(), false);
00208         mount.setData(QVariant(ST_MOUNT));
00209         result.append(mount);
00210     }
00211 
00212     if (offerUnmount) {
00213         QString text;
00214 #ifdef HAVE_VOLMGT
00215          /*
00216           *  Solaris' volume management can only umount+eject
00217           */
00218         text = i18n("Eject");
00219 #else
00220         text = i18n("Unmount");
00221 #endif
00222         KServiceAction unmount("unmount", text, QString(), QString(), false);
00223         unmount.setData(QVariant(ST_UNMOUNT));
00224         result.append(unmount);
00225     }
00226 
00227     return result;
00228 }
00229 
00230 QList<KServiceAction> KDesktopFileActions::userDefinedServices( const QString& path, bool bLocalFiles )
00231 {
00232     KDesktopFile cfg( path );
00233     return userDefinedServices( path, cfg, bLocalFiles );
00234 }
00235 
00236 QList<KServiceAction> KDesktopFileActions::userDefinedServices( const QString& path, const KDesktopFile& cfg, bool bLocalFiles, const KUrl::List & file_list )
00237 {
00238     Q_UNUSED(path); // this was just for debugging; we use service.entryPath() now.
00239     KService service(&cfg);
00240     return userDefinedServices(service, bLocalFiles, file_list);
00241 }
00242 
00243 QList<KServiceAction> KDesktopFileActions::userDefinedServices( const KService& service, bool bLocalFiles, const KUrl::List & file_list )
00244 {
00245     QList<KServiceAction> result;
00246 
00247     if (!service.isValid()) // e.g. TryExec failed
00248         return result;
00249 
00250     QStringList keys;
00251     const QString actionMenu = service.property("X-KDE-GetActionMenu", QVariant::String).toString();
00252     if (!actionMenu.isEmpty()) {
00253         const QStringList dbuscall = actionMenu.split(QChar(' '));
00254         if (dbuscall.count() >= 4) {
00255             const QString& app       = dbuscall.at( 0 );
00256             const QString& object    = dbuscall.at( 1 );
00257             const QString& interface = dbuscall.at( 2 );
00258             const QString& function  = dbuscall.at( 3 );
00259 
00260             QDBusInterface remote( app, object, interface );
00261             // Do NOT use QDBus::BlockWithGui here. It runs a nested event loop,
00262             // in which timers can fire, leading to crashes like #149736.
00263             QDBusReply<QStringList> reply = remote.call(function, file_list.toStringList());
00264             keys = reply;               // ensures that the reply was a QStringList
00265             if (keys.isEmpty())
00266                 return result;
00267         } else {
00268             kWarning(7000) << "The desktop file" << service.entryPath()
00269                            << "has an invalid X-KDE-GetActionMenu entry."
00270                            << "Syntax is: app object interface function";
00271         }
00272     }
00273 
00274     // Now, either keys is empty (all actions) or it's set to the actions we want
00275 
00276     foreach(const KServiceAction& action, service.actions()) {
00277         if (keys.isEmpty() || keys.contains(action.name())) {
00278             const QString exec = action.exec();
00279             if (bLocalFiles || exec.contains("%U") || exec.contains("%u")) {
00280                 result.append( action );
00281             }
00282         }
00283     }
00284 
00285     return result;
00286 }
00287 
00288 void KDesktopFileActions::executeService( const KUrl::List& urls, const KServiceAction& action )
00289 {
00290     //kDebug(7000) << "EXECUTING Service " << action.name();
00291 
00292     int actionData = action.data().toInt();
00293     if ( actionData == ST_MOUNT || actionData == ST_UNMOUNT ) {
00294         Q_ASSERT( urls.count() == 1 );
00295         const QString path = urls.first().toLocalFile();
00296         //kDebug(7000) << "MOUNT&UNMOUNT";
00297 
00298         KDesktopFile cfg( path );
00299         if (cfg.hasDeviceType()) { // path to desktop file
00300             const QString dev = cfg.readDevice();
00301             if ( dev.isEmpty() ) {
00302                 QString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.",  path );
00303                 KMessageBoxWrapper::error( 0, tmp );
00304                 return;
00305             }
00306             KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByDevice( dev );
00307 
00308             if ( actionData == ST_MOUNT ) {
00309                 // Already mounted? Strange, but who knows ...
00310                 if ( mp ) {
00311                     kDebug(7000) << "ALREADY Mounted";
00312                     return;
00313                 }
00314 
00315                 const KConfigGroup group = cfg.desktopGroup();
00316                 bool ro = group.readEntry("ReadOnly", false);
00317                 QString fstype = group.readEntry( "FSType" );
00318                 if ( fstype == "Default" ) // KDE-1 thing
00319                     fstype.clear();
00320                 QString point = group.readEntry( "MountPoint" );
00321 #ifndef Q_WS_WIN
00322                 (void)new KAutoMount( ro, fstype.toLatin1(), dev, point, path, false );
00323 #endif
00324             } else if ( actionData == ST_UNMOUNT ) {
00325                 // Not mounted? Strange, but who knows ...
00326                 if ( !mp )
00327                     return;
00328 
00329 #ifndef Q_WS_WIN
00330                 (void)new KAutoUnmount( mp->mountPoint(), path );
00331 #endif
00332             }
00333         }
00334 #ifndef KIO_NO_SOLID
00335         else { // path to device
00336             Solid::Predicate predicate(Solid::DeviceInterface::Block, "device", path);
00337             const QList<Solid::Device> devList = Solid::Device::listFromQuery(predicate, QString());
00338             if (!devList.empty()) {
00339                 Solid::Device device = devList[0];
00340                 if ( actionData == ST_MOUNT ) {
00341                     if (device.is<Solid::StorageVolume>()) {
00342                         Solid::StorageAccess *access = device.as<Solid::StorageAccess>();
00343                         if (access) {
00344                             access->setup();
00345                         }
00346                     }
00347                 } else if ( actionData == ST_UNMOUNT ) {
00348                     if (device.is<Solid::OpticalDisc>()) {
00349                         Solid::OpticalDrive *drive = device.parent().as<Solid::OpticalDrive>();
00350                         if (drive != 0) {
00351                             drive->eject();
00352                         }
00353                     } else if (device.is<Solid::StorageVolume>()) {
00354                         Solid::StorageAccess *access = device.as<Solid::StorageAccess>();
00355                         if (access && access->isAccessible()) {
00356                             access->teardown();
00357                         }
00358                     }
00359                 }
00360             }
00361             else {
00362                 kDebug(7000) << "Device" << path << "not found";
00363             }
00364         }
00365 #endif
00366     } else {
00367         kDebug() << action.name() << "first url's path=" << urls.first().path() << "exec=" << action.exec();
00368         KRun::run( action.exec(), urls, 0, action.text(), action.icon());
00369         // The action may update the desktop file. Example: eject unmounts (#5129).
00370         org::kde::KDirNotify::emitFilesChanged( urls.toStringList() );
00371     }
00372 }
00373 

KIO

Skip menu "KIO"
  • 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