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

KIO

  • sources
  • kde-4.14
  • kdelibs
  • kio
  • kio
kdesktopfileactions.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2  * Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
3  * David Faure <faure@kde.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License version 2 as published by the Free Software Foundation;
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB. If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  **/
19 
20 #include "kdesktopfileactions.h"
21 
22 #include "config-kio.h"
23 
24 #include "krun.h"
25 #include "kautomount.h"
26 #include <kmessageboxwrapper.h>
27 #include <kdirnotify.h>
28 #include <kmountpoint.h>
29 
30 #include <kstandarddirs.h>
31 #include <kdesktopfile.h>
32 #include <kconfiggroup.h>
33 #include <klocale.h>
34 #include <kservice.h>
35 
36 #ifndef KIO_NO_SOLID
37 //Solid
38 #include <solid/devicenotifier.h>
39 #include <solid/device.h>
40 #include <solid/deviceinterface.h>
41 #include <solid/predicate.h>
42 #include <solid/storageaccess.h>
43 #include <solid/opticaldrive.h>
44 #include <solid/opticaldisc.h>
45 #include <solid/block.h>
46 #endif
47 
48 enum BuiltinServiceType { ST_MOUNT = 0x0E1B05B0, ST_UNMOUNT = 0x0E1B05B1 }; // random numbers
49 
50 static bool runFSDevice( const KUrl& _url, const KDesktopFile &cfg );
51 static bool runApplication( const KUrl& _url, const QString & _serviceFile );
52 static bool runLink( const KUrl& _url, const KDesktopFile &cfg );
53 
54 bool KDesktopFileActions::run( const KUrl& u, bool _is_local )
55 {
56  // It might be a security problem to run external untrusted desktop
57  // entry files
58  if ( !_is_local )
59  return false;
60 
61  KDesktopFile cfg(u.toLocalFile());
62  if ( !cfg.desktopGroup().hasKey("Type") )
63  {
64  QString tmp = i18n("The desktop entry file %1 "
65  "has no Type=... entry.", u.toLocalFile() );
66  KMessageBoxWrapper::error( 0, tmp);
67  return false;
68  }
69 
70  //kDebug(7000) << "TYPE = " << type.data();
71 
72  if ( cfg.hasDeviceType() )
73  return runFSDevice( u, cfg );
74  else if ( cfg.hasApplicationType()
75  || (cfg.readType() == "Service" && !cfg.desktopGroup().readEntry("Exec").isEmpty())) // for kio_settings
76  return runApplication( u, u.toLocalFile() );
77  else if ( cfg.hasLinkType() )
78  return runLink( u, cfg );
79 
80  QString tmp = i18n("The desktop entry of type\n%1\nis unknown.", cfg.readType() );
81  KMessageBoxWrapper::error( 0, tmp);
82 
83  return false;
84 }
85 
86 static bool runFSDevice( const KUrl& _url, const KDesktopFile &cfg )
87 {
88  bool retval = false;
89 
90  QString dev = cfg.readDevice();
91 
92  if ( dev.isEmpty() )
93  {
94  QString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.", _url.toLocalFile() );
95  KMessageBoxWrapper::error( 0, tmp);
96  return retval;
97  }
98 
99  KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByDevice( dev );
100  // Is the device already mounted ?
101  if (mp) {
102  KUrl mpURL(mp->mountPoint());
103  // Open a new window
104  retval = KRun::runUrl( mpURL, QLatin1String("inode/directory"), 0 /*TODO - window*/ );
105  } else {
106  KConfigGroup cg = cfg.desktopGroup();
107  bool ro = cg.readEntry("ReadOnly", false);
108  QString fstype = cg.readEntry( "FSType" );
109  if ( fstype == "Default" ) // KDE-1 thing
110  fstype.clear();
111  QString point = cg.readEntry( "MountPoint" );
112 #ifndef Q_WS_WIN
113  (void) new KAutoMount( ro, fstype.toLatin1(), dev, point, _url.toLocalFile() );
114 #endif
115  retval = false;
116  }
117 
118  return retval;
119 }
120 
121 static bool runApplication( const KUrl& , const QString & _serviceFile )
122 {
123  KService s( _serviceFile );
124  if ( !s.isValid() )
125  // The error message was already displayed, so we can just quit here
126  // ### KDE4: is this still the case?
127  return false;
128 
129  KUrl::List lst;
130  return KRun::run( s, lst, 0 /*TODO - window*/ );
131 }
132 
133 static bool runLink( const KUrl& _url, const KDesktopFile &cfg )
134 {
135  QString u = cfg.readUrl();
136  if ( u.isEmpty() )
137  {
138  QString tmp = i18n("The desktop entry file\n%1\nis of type Link but has no URL=... entry.", _url.prettyUrl() );
139  KMessageBoxWrapper::error( 0, tmp );
140  return false;
141  }
142 
143  KUrl url ( u );
144  KRun* run = new KRun(url,(QWidget*)0);
145 
146  // X-KDE-LastOpenedWith holds the service desktop entry name that
147  // was should be preferred for opening this URL if possible.
148  // This is used by the Recent Documents menu for instance.
149  QString lastOpenedWidth = cfg.desktopGroup().readEntry( "X-KDE-LastOpenedWith" );
150  if ( !lastOpenedWidth.isEmpty() )
151  run->setPreferredService( lastOpenedWidth );
152 
153  return false;
154 }
155 
156 QList<KServiceAction> KDesktopFileActions::builtinServices( const KUrl& _url )
157 {
158  QList<KServiceAction> result;
159 
160  if ( !_url.isLocalFile() )
161  return result;
162 
163  bool offerMount = false;
164  bool offerUnmount = false;
165 
166  KDesktopFile cfg( _url.toLocalFile() );
167  if ( cfg.hasDeviceType() ) { // url to desktop file
168  const QString dev = cfg.readDevice();
169  if ( dev.isEmpty() ) {
170  QString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.", _url.toLocalFile() );
171  KMessageBoxWrapper::error(0, tmp);
172  return result;
173  }
174 
175  KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByDevice( dev );
176  if (mp) {
177  offerUnmount = true;
178  }
179  else {
180  offerMount = true;
181  }
182  }
183 #ifndef KIO_NO_SOLID
184  else { // url to device
185  Solid::Predicate predicate(Solid::DeviceInterface::Block, "device", _url.toLocalFile());
186  const QList<Solid::Device> devList = Solid::Device::listFromQuery(predicate, QString());
187  if (devList.empty()) {
188  kDebug(7000) << "Device" << _url.toLocalFile() << "not found";
189  return result;
190  }
191  Solid::Device device = devList[0];
192  Solid::StorageAccess *access = device.as<Solid::StorageAccess>();
193  Solid::StorageDrive *drive = device.parent().as<Solid::StorageDrive>();
194  bool mounted = access && access->isAccessible();
195 
196  if ((mounted || device.is<Solid::OpticalDisc>()) && drive && drive->isRemovable()) {
197  offerUnmount = true;
198  }
199 
200  if (!mounted && ((drive && drive->isHotpluggable()) || device.is<Solid::OpticalDisc>())) {
201  offerMount = true;
202  }
203  }
204 #endif
205 
206  if (offerMount) {
207  KServiceAction mount("mount", i18n("Mount"), QString(), QString(), false);
208  mount.setData(QVariant(ST_MOUNT));
209  result.append(mount);
210  }
211 
212  if (offerUnmount) {
213  QString text;
214 #ifdef HAVE_VOLMGT
215  /*
216  * Solaris' volume management can only umount+eject
217  */
218  text = i18n("Eject");
219 #else
220  text = i18n("Unmount");
221 #endif
222  KServiceAction unmount("unmount", text, QString(), QString(), false);
223  unmount.setData(QVariant(ST_UNMOUNT));
224  result.append(unmount);
225  }
226 
227  return result;
228 }
229 
230 QList<KServiceAction> KDesktopFileActions::userDefinedServices( const QString& path, bool bLocalFiles )
231 {
232  KDesktopFile cfg( path );
233  return userDefinedServices( path, cfg, bLocalFiles );
234 }
235 
236 QList<KServiceAction> KDesktopFileActions::userDefinedServices( const QString& path, const KDesktopFile& cfg, bool bLocalFiles, const KUrl::List & file_list )
237 {
238  Q_UNUSED(path); // this was just for debugging; we use service.entryPath() now.
239  KService service(&cfg);
240  return userDefinedServices(service, bLocalFiles, file_list);
241 }
242 
243 QList<KServiceAction> KDesktopFileActions::userDefinedServices( const KService& service, bool bLocalFiles, const KUrl::List & file_list )
244 {
245  QList<KServiceAction> result;
246 
247  if (!service.isValid()) // e.g. TryExec failed
248  return result;
249 
250  QStringList keys;
251  const QString actionMenu = service.property("X-KDE-GetActionMenu", QVariant::String).toString();
252  if (!actionMenu.isEmpty()) {
253  const QStringList dbuscall = actionMenu.split(QChar(' '));
254  if (dbuscall.count() >= 4) {
255  const QString& app = dbuscall.at( 0 );
256  const QString& object = dbuscall.at( 1 );
257  const QString& interface = dbuscall.at( 2 );
258  const QString& function = dbuscall.at( 3 );
259 
260  QDBusInterface remote( app, object, interface );
261  // Do NOT use QDBus::BlockWithGui here. It runs a nested event loop,
262  // in which timers can fire, leading to crashes like #149736.
263  QDBusReply<QStringList> reply = remote.call(function, file_list.toStringList());
264  keys = reply; // ensures that the reply was a QStringList
265  if (keys.isEmpty())
266  return result;
267  } else {
268  kWarning(7000) << "The desktop file" << service.entryPath()
269  << "has an invalid X-KDE-GetActionMenu entry."
270  << "Syntax is: app object interface function";
271  }
272  }
273 
274  // Now, either keys is empty (all actions) or it's set to the actions we want
275 
276  foreach(const KServiceAction& action, service.actions()) {
277  if (keys.isEmpty() || keys.contains(action.name())) {
278  const QString exec = action.exec();
279  if (bLocalFiles || exec.contains("%U") || exec.contains("%u")) {
280  result.append( action );
281  }
282  }
283  }
284 
285  return result;
286 }
287 
288 void KDesktopFileActions::executeService( const KUrl::List& urls, const KServiceAction& action )
289 {
290  //kDebug(7000) << "EXECUTING Service " << action.name();
291 
292  int actionData = action.data().toInt();
293  if ( actionData == ST_MOUNT || actionData == ST_UNMOUNT ) {
294  Q_ASSERT( urls.count() == 1 );
295  const QString path = urls.first().toLocalFile();
296  //kDebug(7000) << "MOUNT&UNMOUNT";
297 
298  KDesktopFile cfg( path );
299  if (cfg.hasDeviceType()) { // path to desktop file
300  const QString dev = cfg.readDevice();
301  if ( dev.isEmpty() ) {
302  QString tmp = i18n("The desktop entry file\n%1\nis of type FSDevice but has no Dev=... entry.", path );
303  KMessageBoxWrapper::error( 0, tmp );
304  return;
305  }
306  KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByDevice( dev );
307 
308  if ( actionData == ST_MOUNT ) {
309  // Already mounted? Strange, but who knows ...
310  if ( mp ) {
311  kDebug(7000) << "ALREADY Mounted";
312  return;
313  }
314 
315  const KConfigGroup group = cfg.desktopGroup();
316  bool ro = group.readEntry("ReadOnly", false);
317  QString fstype = group.readEntry( "FSType" );
318  if ( fstype == "Default" ) // KDE-1 thing
319  fstype.clear();
320  QString point = group.readEntry( "MountPoint" );
321 #ifndef Q_WS_WIN
322  (void)new KAutoMount( ro, fstype.toLatin1(), dev, point, path, false );
323 #endif
324  } else if ( actionData == ST_UNMOUNT ) {
325  // Not mounted? Strange, but who knows ...
326  if ( !mp )
327  return;
328 
329 #ifndef Q_WS_WIN
330  (void)new KAutoUnmount( mp->mountPoint(), path );
331 #endif
332  }
333  }
334 #ifndef KIO_NO_SOLID
335  else { // path to device
336  Solid::Predicate predicate(Solid::DeviceInterface::Block, "device", path);
337  const QList<Solid::Device> devList = Solid::Device::listFromQuery(predicate, QString());
338  if (!devList.empty()) {
339  Solid::Device device = devList[0];
340  if ( actionData == ST_MOUNT ) {
341  if (device.is<Solid::StorageVolume>()) {
342  Solid::StorageAccess *access = device.as<Solid::StorageAccess>();
343  if (access) {
344  access->setup();
345  }
346  }
347  } else if ( actionData == ST_UNMOUNT ) {
348  if (device.is<Solid::OpticalDisc>()) {
349  Solid::OpticalDrive *drive = device.parent().as<Solid::OpticalDrive>();
350  if (drive != 0) {
351  drive->eject();
352  }
353  } else if (device.is<Solid::StorageVolume>()) {
354  Solid::StorageAccess *access = device.as<Solid::StorageAccess>();
355  if (access && access->isAccessible()) {
356  access->teardown();
357  }
358  }
359  }
360  }
361  else {
362  kDebug(7000) << "Device" << path << "not found";
363  }
364  }
365 #endif
366  } else {
367  kDebug() << action.name() << "first url's path=" << urls.first().toLocalFile() << "exec=" << action.exec();
368  KRun::run( action.exec(), urls, 0, action.text(), action.icon());
369  // The action may update the desktop file. Example: eject unmounts (#5129).
370  org::kde::KDirNotify::emitFilesChanged( urls.toStringList() );
371  }
372 }
373 
KServiceAction::icon
QString icon() const
i18n
QString i18n(const char *text)
KRun::run
static bool run(const KService &service, const KUrl::List &urls, QWidget *window, bool tempFiles=false, const QString &suggestedFileName=QString(), const QByteArray &asn=QByteArray())
Open a list of URLs with a certain service (application).
Definition: krun.cpp:984
KIO::unmount
SimpleJob * unmount(const QString &point, JobFlags flags=DefaultFlags)
Unmount filesystem.
Definition: job.cpp:762
KSharedPtr
Definition: kprotocolmanager.h:31
QWidget
group
ST_MOUNT
Definition: kdesktopfileactions.cpp:48
kmountpoint.h
KMountPoint::currentMountPoints
static List currentMountPoints(DetailsNeededFlags infoNeeded=BasicInfoNeeded)
QDBusReply
KDesktopFileActions::userDefinedServices
QList< KServiceAction > userDefinedServices(const QString &path, bool bLocalFiles)
Returns a list of services defined by the user as possible actions on the given .desktop file...
Definition: kdesktopfileactions.cpp:230
KAutoMount
This class implements synchronous mounting of devices, as well as showing a file-manager window after...
Definition: kautomount.h:45
QChar
QString::split
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
kdirnotify.h
KService
QList::at
const T & at(int i) const
KService::property
QVariant property(const QString &_name, QVariant::Type t) const
KMountPoint::List::findByDevice
Ptr findByDevice(const QString &device) const
QStringList::contains
bool contains(const QString &str, Qt::CaseSensitivity cs) const
runApplication
static bool runApplication(const KUrl &_url, const QString &_serviceFile)
Definition: kdesktopfileactions.cpp:121
KUrl::toLocalFile
QString toLocalFile(AdjustPathOption trailing=LeaveTrailingSlash) const
kdesktopfile.h
kDebug
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
klocale.h
KServiceAction
KDesktopFileActions::run
bool run(const KUrl &_url, bool _is_local)
Invokes the default action for the desktop entry.
Definition: kdesktopfileactions.cpp:54
QDBusAbstractInterface::call
QDBusMessage call(const QString &method, const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, const QVariant &arg7, const QVariant &arg8)
KUrl
KDesktopFileActions::builtinServices
QList< KServiceAction > builtinServices(const KUrl &url)
Returns a list of services for the given .desktop file that are handled by kio itself.
Definition: kdesktopfileactions.cpp:156
KRun
To open files with their associated applications in KDE, use KRun.
Definition: krun.h:59
QString::clear
void clear()
KIO::mount
SimpleJob * mount(bool ro, const QByteArray &fstype, const QString &dev, const QString &point, JobFlags flags=DefaultFlags)
Mount filesystem.
Definition: job.cpp:751
kdesktopfileactions.h
QList::count
int count(const T &value) const
QList::append
void append(const T &value)
KAutoUnmount
This class implements synchronous unmounting of devices, It is a wrapper around the asychronous KIO::...
Definition: kautomount.h:85
KDesktopFile::readDevice
QString readDevice() const
QList::empty
bool empty() const
QVariant::toInt
int toInt(bool *ok) const
KDesktopFile::hasDeviceType
bool hasDeviceType() const
BuiltinServiceType
BuiltinServiceType
Definition: kdesktopfileactions.cpp:48
runFSDevice
static bool runFSDevice(const KUrl &_url, const KDesktopFile &cfg)
Definition: kdesktopfileactions.cpp:86
QList::isEmpty
bool isEmpty() const
QString::isEmpty
bool isEmpty() const
kmessageboxwrapper.h
QList::first
T & first()
QString
QList< KServiceAction >
KDesktopFile::readUrl
QString readUrl() const
KServiceAction::data
QVariant data() const
QStringList
kservice.h
QDBusInterface
QString::contains
bool contains(QChar ch, Qt::CaseSensitivity cs) const
KServiceAction::text
QString text() const
KDesktopFile
runLink
static bool runLink(const KUrl &_url, const KDesktopFile &cfg)
Definition: kdesktopfileactions.cpp:133
KConfigGroup
KUrl::List
krun.h
KRun::setPreferredService
void setPreferredService(const QString &desktopEntryName)
Set the preferred service for opening this URL, after its mimetype will have been found by KRun...
Definition: krun.cpp:1587
KRun::runUrl
static bool runUrl(const KUrl &url, const QString &mimetype, QWidget *window, bool tempFile=false, bool runExecutables=true, const QString &suggestedFileName=QString(), const QByteArray &asn=QByteArray())
Open the given URL.
Definition: krun.cpp:122
QString::toLatin1
QByteArray toLatin1() const
KServiceAction::setData
void setData(const QVariant &userData)
QLatin1String
KServiceAction::exec
QString exec() const
access
int access(const QString &path, int mode)
kstandarddirs.h
KUrl::List::toStringList
QStringList toStringList() const
OrgKdeKDirNotifyInterface::emitFilesChanged
static void emitFilesChanged(const QStringList &fileList)
Definition: kdirnotify.cpp:52
kWarning
static QDebug kWarning(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
KServiceAction::name
QString name() const
KService::actions
QList< KServiceAction > actions() const
ST_UNMOUNT
Definition: kdesktopfileactions.cpp:48
KDesktopFileActions::executeService
void executeService(const KUrl::List &urls, const KServiceAction &service)
Execute service on the list of urls.
Definition: kdesktopfileactions.cpp:288
KUrl::isLocalFile
bool isLocalFile() const
QVariant::toString
QString toString() const
kautomount.h
KConfigGroup::readEntry
T readEntry(const QString &key, const T &aDefault) const
KDesktopFile::desktopGroup
KConfigGroup desktopGroup() const
KMessageBoxWrapper::error
static void error(QWidget *parent, const QString &text, const QString &caption=QString())
Definition: kmessageboxwrapper.h:33
KUrl::prettyUrl
QString prettyUrl(AdjustPathOption trailing=LeaveTrailingSlash) const
kconfiggroup.h
QVariant
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:24:53 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

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

Skip menu "kdelibs API Reference"
  • 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

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal