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

KIO

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