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

KDECore

  • sources
  • kde-4.14
  • kdelibs
  • kdecore
  • kernel
ktoolinvocation_x11.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2  Copyright (c) 1997,1998 Matthias Kalle Dalheimer <kalle@kde.org>
3  Copyright (c) 1999 Espen Sand <espen@kde.org>
4  Copyright (c) 2000-2004 Frerich Raabe <raabe@kde.org>
5  Copyright (c) 2003,2004 Oswald Buddenhagen <ossi@kde.org>
6  Copyright (c) 2006 Thiago Macieira <thiago@kde.org>
7  Copyright (C) 2008 Aaron Seigo <aseigo@kde.org>
8 
9  This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Library General Public
11  License as published by the Free Software Foundation; either
12  version 2 of the License, or (at your option) any later version.
13 
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  Library General Public License for more details.
18 
19  You should have received a copy of the GNU Library General Public License
20  along with this library; see the file COPYING.LIB. If not, write to
21  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  Boston, MA 02110-1301, USA.
23 */
24 
25 #include <config.h>
26 
27 #include "ktoolinvocation.h"
28 
29 #include <kconfiggroup.h>
30 #include <kmimetypetrader.h>
31 
32 #include "kcmdlineargs.h"
33 #include "kconfig.h"
34 #include "kcodecs.h"
35 #include "kdebug.h"
36 #include "kglobal.h"
37 #include "kshell.h"
38 #include "kmacroexpander.h"
39 #include "klocale.h"
40 #include "kstandarddirs.h"
41 #include "kmessage.h"
42 #include "kservice.h"
43 
44 #include <QtCore/QCoreApplication>
45 #include <QtCore/QProcess>
46 #include <QtCore/QHash>
47 #include <QtCore/QDebug>
48 #include <QtCore/QBool>
49 #include <QtCore/QFile>
50 #include <QtDBus/QtDBus>
51 
52 static QStringList splitEmailAddressList( const QString & aStr )
53 {
54  // This is a copy of KPIM::splitEmailAddrList().
55  // Features:
56  // - always ignores quoted characters
57  // - ignores everything (including parentheses and commas)
58  // inside quoted strings
59  // - supports nested comments
60  // - ignores everything (including double quotes and commas)
61  // inside comments
62 
63  QStringList list;
64 
65  if (aStr.isEmpty())
66  return list;
67 
68  QString addr;
69  uint addrstart = 0;
70  int commentlevel = 0;
71  bool insidequote = false;
72 
73  for (int index=0; index<aStr.length(); index++) {
74  // the following conversion to latin1 is o.k. because
75  // we can safely ignore all non-latin1 characters
76  switch (aStr[index].toLatin1()) {
77  case '"' : // start or end of quoted string
78  if (commentlevel == 0)
79  insidequote = !insidequote;
80  break;
81  case '(' : // start of comment
82  if (!insidequote)
83  commentlevel++;
84  break;
85  case ')' : // end of comment
86  if (!insidequote) {
87  if (commentlevel > 0)
88  commentlevel--;
89  else {
90  //kDebug() << "Error in address splitting: Unmatched ')'"
91  // << endl;
92  return list;
93  }
94  }
95  break;
96  case '\\' : // quoted character
97  index++; // ignore the quoted character
98  break;
99  case ',' :
100  if (!insidequote && (commentlevel == 0)) {
101  addr = aStr.mid(addrstart, index-addrstart);
102  if (!addr.isEmpty())
103  list += addr.simplified();
104  addrstart = index+1;
105  }
106  break;
107  }
108  }
109  // append the last address to the list
110  if (!insidequote && (commentlevel == 0)) {
111  addr = aStr.mid(addrstart, aStr.length()-addrstart);
112  if (!addr.isEmpty())
113  list += addr.simplified();
114  }
115  //else
116  // kDebug() << "Error in address splitting: "
117  // << "Unexpected end of address list"
118  // << endl;
119 
120  return list;
121 }
122 
123 #ifdef Q_WS_MAEMO_5
124 // taken from QDesktopServices, which we cannot use here due to it being in QtGui
125 inline static bool maemo5Launch(const QUrl &url)
126 {
127  typedef bool (*Ptr_hildon_uri_open)(const char *, void *, void **);
128  static Ptr_hildon_uri_open hildon_uri_open = 0;
129 
130  if (!hildon_uri_open) {
131  QLibrary lib(QLatin1String("libhildonmime"), 0, 0);
132  hildon_uri_open = (Ptr_hildon_uri_open)lib.resolve("hildon_uri_open");
133  }
134  if (hildon_uri_open)
135  return hildon_uri_open(url.toEncoded().constData(), 0, 0);
136  return false;
137 }
138 #endif
139 
140 void KToolInvocation::invokeMailer(const QString &_to, const QString &_cc, const QString &_bcc,
141  const QString &subject, const QString &body,
142  const QString & /*messageFile TODO*/, const QStringList &attachURLs,
143  const QByteArray& startup_id )
144 {
145  if (!isMainThreadActive())
146  return;
147 
148  KConfig config(QString::fromLatin1("emaildefaults"));
149  KConfigGroup defaultsGrp(&config, "Defaults");
150 
151  QString group = defaultsGrp.readEntry("Profile","Default");
152 
153  KConfigGroup profileGrp(&config, QString::fromLatin1("PROFILE_%1").arg(group) );
154  QString command = profileGrp.readPathEntry("EmailClient", QString());
155 
156  QString to, cc, bcc;
157  if (command.isEmpty() || command == QLatin1String("kmail")
158  || command.endsWith(QLatin1String("/kmail")))
159  {
160  command = QLatin1String("kmail --composer -s %s -c %c -b %b --body %B --attach %A -- %t");
161  if ( !_to.isEmpty() )
162  {
163  KUrl url;
164  url.setProtocol(QLatin1String("mailto"));
165  url.setPath(_to);
166  to = QString::fromLatin1(url.toEncoded());
167  }
168  if ( !_cc.isEmpty() )
169  {
170  KUrl url;
171  url.setProtocol(QLatin1String("mailto"));
172  url.setPath(_cc);
173  cc = QString::fromLatin1(url.toEncoded());
174  }
175  if ( !_bcc.isEmpty() )
176  {
177  KUrl url;
178  url.setProtocol(QLatin1String("mailto"));
179  url.setPath(_bcc);
180  bcc = QString::fromLatin1(url.toEncoded());
181  }
182  } else {
183  to = _to;
184  cc = _cc;
185  bcc = _bcc;
186  if( !command.contains( QLatin1Char('%') ))
187  command += QLatin1String(" %u");
188  }
189 
190  if (profileGrp.readEntry("TerminalClient", false))
191  {
192  KConfigGroup confGroup( KGlobal::config(), "General" );
193  QString preferredTerminal = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole"));
194  command = preferredTerminal + QString::fromLatin1(" -e ") + command;
195  }
196 
197  QStringList cmdTokens = KShell::splitArgs(command);
198  QString cmd = cmdTokens.takeFirst();
199 
200  KUrl url;
201  //QStringList qry;
202  if (!to.isEmpty())
203  {
204  QStringList tos = splitEmailAddressList( to );
205  url.setPath( tos.first() );
206  tos.erase( tos.begin() );
207  for (QStringList::ConstIterator it = tos.constBegin(); it != tos.constEnd(); ++it)
208  url.addQueryItem(QString::fromLatin1("to"), *it);
209  //qry.append( "to=" + QLatin1String(KUrl::toPercentEncoding( *it ) ));
210  }
211  const QStringList ccs = splitEmailAddressList( cc );
212  for (QStringList::ConstIterator it = ccs.constBegin(); it != ccs.constEnd(); ++it)
213  url.addQueryItem(QString::fromLatin1("cc"), *it);
214  //qry.append( "cc=" + QLatin1String(KUrl::toPercentEncoding( *it ) ));
215  const QStringList bccs = splitEmailAddressList( bcc );
216  for (QStringList::ConstIterator it = bccs.constBegin(); it != bccs.constEnd(); ++it)
217  url.addQueryItem(QString::fromLatin1("bcc"), *it);
218  //qry.append( "bcc=" + QLatin1String(KUrl::toPercentEncoding( *it ) ));
219  for (QStringList::ConstIterator it = attachURLs.constBegin(); it != attachURLs.constEnd(); ++it)
220  url.addQueryItem(QString::fromLatin1("attach"), *it);
221  //qry.append( "attach=" + QLatin1String(KUrl::toPercentEncoding( *it ) ));
222  if (!subject.isEmpty())
223  url.addQueryItem(QString::fromLatin1("subject"), subject);
224  //qry.append( "subject=" + QLatin1String(KUrl::toPercentEncoding( subject ) ));
225  if (!body.isEmpty())
226  url.addQueryItem(QString::fromLatin1("body"), body);
227  //qry.append( "body=" + QLatin1String(KUrl::toPercentEncoding( body ) ));
228  //url.setQuery( qry.join( "&" ) );
229 
230  if ( ! (to.isEmpty() && (!url.hasQuery())) )
231  url.setProtocol(QString::fromLatin1("mailto"));
232 
233  QHash<QChar, QString> keyMap;
234  keyMap.insert(QLatin1Char('t'), to);
235  keyMap.insert(QLatin1Char('s'), subject);
236  keyMap.insert(QLatin1Char('c'), cc);
237  keyMap.insert(QLatin1Char('b'), bcc);
238  keyMap.insert(QLatin1Char('B'), body);
239  keyMap.insert(QLatin1Char('u'), url.url());
240 
241  QString attachlist = attachURLs.join(QString::fromLatin1(","));
242  attachlist.prepend(QLatin1Char('\''));
243  attachlist.append(QLatin1Char('\''));
244  keyMap.insert(QLatin1Char('A'), attachlist);
245 
246  for (QStringList::Iterator it = cmdTokens.begin(); it != cmdTokens.end(); )
247  {
248  if (*it == QLatin1String("%A"))
249  {
250  if (it == cmdTokens.begin()) // better safe than sorry ...
251  continue;
252  QStringList::ConstIterator urlit = attachURLs.begin();
253  QStringList::ConstIterator urlend = attachURLs.end();
254  if ( urlit != urlend )
255  {
256  QStringList::Iterator previt = it;
257  --previt;
258  *it = *urlit;
259  ++it;
260  while ( ++urlit != urlend )
261  {
262  cmdTokens.insert( it, *previt );
263  cmdTokens.insert( it, *urlit );
264  }
265  } else {
266  --it;
267  it = cmdTokens.erase( cmdTokens.erase( it ) );
268  }
269  } else {
270  *it = KMacroExpander::expandMacros(*it, keyMap);
271  ++it;
272  }
273  }
274 
275  QString error;
276  // TODO this should check if cmd has a .desktop file, and use data from it, together
277  // with sending more ASN data
278  if (kdeinitExec(cmd, cmdTokens, &error, NULL, startup_id ))
279  {
280  KMessage::message(KMessage::Error,
281  i18n("Could not launch the mail client:\n\n%1", error),
282  i18n("Could not launch Mail Client"));
283  }
284 }
285 
286 void KToolInvocation::invokeBrowser( const QString &url, const QByteArray& startup_id )
287 {
288  if (!isMainThreadActive())
289  return;
290 
291 #ifdef Q_WS_MAEMO_5
292  if (maemo5Launch(url))
293  return;
294 #endif
295  QStringList args;
296  args << url;
297  QString error;
298 
299  // This method should launch a webbrowser, preferably without doing a mimetype
300  // check first, like KRun (i.e. kde-open) would do.
301 
302  // In a KDE session, honour BrowserApplication if set, otherwise use preferred app for text/html if any,
303  // otherwise xdg-open, otherwise kde-open (which does a mimetype check first though).
304 
305  // Outside KDE, call xdg-open if present, otherwise fallback to the above logic.
306 
307  QString exe; // the binary we are going to launch.
308 
309  const QString xdg_open = KStandardDirs::findExe(QString::fromLatin1("xdg-open"));
310  if (qgetenv("KDE_FULL_SESSION").isEmpty()) {
311  exe = xdg_open;
312  }
313 
314  if (exe.isEmpty()) {
315  // We're in a KDE session (or there's no xdg-open installed)
316  KConfigGroup config(KGlobal::config(), "General");
317  const QString browserApp = config.readPathEntry("BrowserApplication", QString());
318  if (!browserApp.isEmpty()) {
319  exe = browserApp;
320  if (exe.startsWith(QLatin1Char('!'))) {
321  exe = exe.mid(1); // Literal command
322  QStringList cmdTokens = KShell::splitArgs(exe);
323  exe = cmdTokens.takeFirst();
324  args = cmdTokens + args;
325  } else {
326  // desktop file ID
327  KService::Ptr service = KService::serviceByStorageId(exe);
328  if (service) {
329  kDebug() << "Starting service" << service->entryPath();
330  if (startServiceByDesktopPath(service->entryPath(), args,
331  &error, 0, 0, startup_id)) {
332  KMessage::message(KMessage::Error,
333  // TODO: i18n("Could not launch %1:\n\n%2", exe, error),
334  i18n("Could not launch the browser:\n\n%1", error),
335  i18n("Could not launch Browser"));
336  }
337  return;
338  }
339  }
340  } else {
341  const KService::Ptr htmlApp = KMimeTypeTrader::self()->preferredService(QLatin1String("text/html"));
342  if (htmlApp) {
343  // WORKAROUND: For bugs 264562 and 265474:
344  // In order to correctly handle non-HTML urls we change the service
345  // desktop file name to "kfmclient.desktop" whenever the above query
346  // returns "kfmclient_html.desktop".Otherwise, the hard coded mime-type
347  // "text/html" mime-type parameter in the kfmclient_html will cause all
348  // URLs to be treated as if they are HTML page.
349  QString entryPath = htmlApp->entryPath();
350  if (entryPath.endsWith(QLatin1String("kfmclient_html.desktop"))) {
351  entryPath.remove(entryPath.length()-13, 5);
352  }
353  QString error;
354  int pid = 0;
355  int err = startServiceByDesktopPath(entryPath, url, &error, 0, &pid, startup_id);
356  if (err != 0) {
357  KMessage::message(KMessage::Error,
358  // TODO: i18n("Could not launch %1:\n\n%2", htmlApp->exec(), error),
359  i18n("Could not launch the browser:\n\n%1", error),
360  i18n("Could not launch Browser"));
361  } else { // success
362  return;
363  }
364  } else {
365  exe = xdg_open;
366  }
367  }
368  }
369 
370  if (exe.isEmpty()) {
371  exe = QString::fromLatin1("kde-open"); // it's from kdebase-runtime, it has to be there.
372  }
373 
374  kDebug(180) << "Using" << exe << "to open" << url;
375  if (kdeinitExec(exe, args, &error, NULL, startup_id ))
376  {
377  KMessage::message(KMessage::Error,
378  // TODO: i18n("Could not launch %1:\n\n%2", exe, error),
379  i18n("Could not launch the browser:\n\n%1", error),
380  i18n("Could not launch Browser"));
381  }
382 }
383 
384 void KToolInvocation::invokeTerminal(const QString &command,
385  const QString &workdir,
386  const QByteArray &startup_id)
387 {
388  if (!isMainThreadActive()) {
389  return;
390  }
391 
392  KConfigGroup confGroup( KGlobal::config(), "General" );
393  QString exec = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole"));
394 
395  if (!command.isEmpty()) {
396  if (exec == QLatin1String("konsole")) {
397  exec += QString::fromLatin1(" --noclose");
398  } else if (exec == QLatin1String("xterm")) {
399  exec += QString::fromLatin1(" -hold");
400  }
401 
402  exec += QString::fromLatin1(" -e ") + command;
403  }
404 
405  QStringList cmdTokens = KShell::splitArgs(exec);
406  QString cmd = cmdTokens.takeFirst();
407 
408  if (exec == QLatin1String("konsole") && !workdir.isEmpty()) {
409  cmdTokens << QString::fromLatin1("--workdir");
410  cmdTokens << workdir;
411  // For other terminals like xterm, we'll simply change the working
412  // directory before launching them, see below.
413  }
414 
415  QString error;
416  if (self()->startServiceInternal("kdeinit_exec_with_workdir",
417  cmd, cmdTokens, &error, 0, NULL, startup_id, false, workdir)) {
418  KMessage::message(KMessage::Error,
419  i18n("Could not launch the terminal client:\n\n%1", error),
420  i18n("Could not launch Terminal Client"));
421  }
422 }
KMessage::message
void message(KMessage::MessageType messageType, const QString &text, const QString &caption=QString())
Display a long message of a certain type.
Definition: kmessage.cpp:92
i18n
QString i18n(const char *text)
Returns a localized version of a string.
Definition: klocalizedstring.h:630
KSharedPtr< KService >
QString::append
QString & append(QChar ch)
QHash::insert
iterator insert(const Key &key, const T &value)
kdebug.h
QByteArray
KMacroExpander::group
Definition: kmacroexpander_unix.cpp:34
QString::prepend
QString & prepend(QChar ch)
kconfig.h
kshell.h
QString::simplified
QString simplified() const
QList::erase
iterator erase(iterator pos)
KToolInvocation::invokeMailer
static void invokeMailer(const QString &address, const QString &subject, const QByteArray &startup_id=QByteArray())
Convenience method; invokes the standard email application.
Definition: ktoolinvocation.cpp:319
KUrl::addQueryItem
void addQueryItem(const QString &_item, const QString &_value)
Add an additional query item.
Definition: kurl.cpp:1868
pid
static pid_t pid
Definition: k3resolvermanager.cpp:249
QStringList::join
QString join(const QString &separator) const
QString::remove
QString & remove(int position, int n)
ktoolinvocation.h
klocale.h
KUrl
Represents and parses a URL.
Definition: kurl.h:111
KGlobal::config
KSharedConfigPtr config()
Returns the general config object.
Definition: kglobal.cpp:139
KUrl::setPath
void setPath(const QString &path)
Definition: kurl.cpp:1772
KShell::splitArgs
QStringList splitArgs(const QString &cmd, Options flags=NoOptions, Errors *err=0)
Splits cmd according to system shell word splitting and quoting rules.
Definition: kshell_unix.cpp:70
kglobal.h
splitEmailAddressList
static QStringList splitEmailAddressList(const QString &aStr)
Definition: ktoolinvocation_x11.cpp:52
KToolInvocation::startServiceByDesktopPath
static int startServiceByDesktopPath(const QString &_name, const QString &URL, QString *error=0, QString *serviceName=0, int *pid=0, const QByteArray &startup_id=QByteArray(), bool noWait=false)
Starts a service based on the desktop path of the service.
Definition: ktoolinvocation.cpp:174
KUrl::setProtocol
void setProtocol(const QString &proto)
Sets the protocol for the URL (i.e., file, http, etc.)
Definition: kurl.cpp:677
KSycocaEntry::entryPath
QString entryPath() const
Definition: ksycocaentry.cpp:104
kmacroexpander.h
QHash
Definition: ksycocafactory.h:28
kcmdlineargs.h
QString::isEmpty
bool isEmpty() const
QByteArray::constData
const char * constData() const
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
kmimetypetrader.h
KMimeTypeTrader::self
static KMimeTypeTrader * self()
This is a static pointer to the KMimeTypeTrader singleton.
Definition: kmimetypetrader.cpp:38
QString::endsWith
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
QList::Iterator
typedef Iterator
KMessage::Error
Error message.
Definition: kmessage.h:57
QList::first
T & first()
QString
QStringList
kservice.h
KMacroExpander::expandMacros
QString expandMacros(const QString &ostr, const QHash< QChar, QString > &map, QChar c)
Perform safe macro expansion (substitution) on a string.
Definition: kmacroexpander.cpp:340
maemo5Launch
static bool maemo5Launch(const QUrl &url)
Definition: ktoolinvocation_x11.cpp:125
QList::end
iterator end()
QString::contains
bool contains(QChar ch, Qt::CaseSensitivity cs) const
QUrl
QLatin1Char
KConfigGroup
A class for one specific group in a KConfig object.
Definition: kconfiggroup.h:53
KConfig
The central class of the KDE configuration data system.
Definition: kconfig.h:70
QString::mid
QString mid(int position, int n) const
QLibrary::resolve
void * resolve(const char *symbol)
QList::takeFirst
T takeFirst()
QLatin1String
QList::insert
void insert(int i, const T &value)
kstandarddirs.h
KStandardDirs::findExe
static QString findExe(const QString &appname, const QString &pathstr=QString(), SearchOptions options=NoSearchOptions)
Finds the executable in the system path.
Definition: kstandarddirs.cpp:1328
QList::ConstIterator
typedef ConstIterator
QLibrary
bool
QString::length
int length() const
QString::fromLatin1
QString fromLatin1(const char *str, int size)
kDebug
#define kDebug
Definition: kdebug.h:316
KUrl::url
QString url(AdjustPathOption trailing=LeaveTrailingSlash) const
Returns the URL as string, with all escape sequences intact, encoded in a given charset.
Definition: kurl.cpp:1035
kcodecs.h
QList::constEnd
const_iterator constEnd() const
QList::constBegin
const_iterator constBegin() const
KToolInvocation::invokeBrowser
static void invokeBrowser(const QString &url, const QByteArray &startup_id=QByteArray())
Invokes the user's preferred browser.
Definition: ktoolinvocation_win.cpp:37
kmessage.h
QUrl::hasQuery
bool hasQuery() const
KToolInvocation::invokeTerminal
static void invokeTerminal(const QString &command, const QString &workdir=QString(), const QByteArray &startup_id="")
Invokes the standard terminal application.
Definition: ktoolinvocation_win.cpp:82
QList::begin
iterator begin()
KToolInvocation::kdeinitExec
static int kdeinitExec(const QString &name, const QStringList &args=QStringList(), QString *error=0, int *pid=0, const QByteArray &startup_id=QByteArray())
Starts a program via kdeinit.
Definition: ktoolinvocation.cpp:228
KMimeTypeTrader::preferredService
KService::Ptr preferredService(const QString &mimeType, const QString &genericServiceType=QString::fromLatin1("Application"))
Returns the preferred service for mimeType and genericServiceType.
Definition: kmimetypetrader.cpp:157
QUrl::toEncoded
QByteArray toEncoded(QFlags< QUrl::FormattingOption > options) const
kconfiggroup.h
KService::serviceByStorageId
static Ptr serviceByStorageId(const QString &_storageId)
Find a service by its storage-id or desktop-file path.
Definition: kservice.cpp:638
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:22:11 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDECore

Skip menu "KDECore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • 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