diff --git a/khtml/khtml_run.cpp b/khtml/khtml_run.cpp
index 61f0397e32..971c490c03 100644
--- a/khtml/khtml_run.cpp
+++ b/khtml/khtml_run.cpp
@@ -1,104 +1,93 @@
/* This file is part of the KDE project
*
* Copyright (C) 1998, 1999 Torben Weis
* 1999 Lars Knoll
* 1999 Antti Koivisto
* 2000 Simon Hausmann
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "khtml_run.h"
#include "khtmlpart_p.h"
#include
#include
#include
#include "khtml_ext.h"
#include
KHTMLRun::KHTMLRun( KHTMLPart *part, khtml::ChildFrame *child, const KUrl &url,
const KParts::OpenUrlArguments& args,
const KParts::BrowserArguments &browserArgs,
bool hideErrorDialog )
: KParts::BrowserRun( url, args, browserArgs, part, part->widget() ? part->widget()->topLevelWidget() : 0,
false, false, hideErrorDialog ),
m_child( child )
{
// Don't use an external browser for parts of a webpage we are rendering. (iframes at least are one example)
setEnableExternalBrowser(false);
// get the wheel to start spinning
part->started(0L);
}
//KHTMLPart *KHTMLRun::htmlPart() const
//{ return static_cast(part()); }
void KHTMLRun::foundMimeType( const QString &_type )
{
+ //kDebug(6050) << this << _type;
Q_ASSERT(!hasFinished());
QString mimeType = _type; // this ref comes from the job, we lose it when using KIO again
- // Disable autoDelete for processObjectRequest(), because it may open a
- // dialog which would start an event loop, causing the autoDelete timer
- // slot to be called before leaving processObjectRequest()
- bool autoDeleteWasEnabled = autoDelete();
- setAutoDelete( false );
bool requestProcessed = static_cast(part())->processObjectRequest( m_child, KRun::url(), mimeType );
- if (autoDeleteWasEnabled ) {
- // Reenable autoDelete and restart timer to make sure our instance
- // eventually get deleted
- setAutoDelete( true );
- timer().start( 0 );
- }
-
if ( requestProcessed )
setFinished( true );
else {
if ( hasFinished() ) // abort was called (this happens with the activex fallback for instance)
return;
// Couldn't embed -> call BrowserRun::handleNonEmbeddable()
KParts::BrowserRun::NonEmbeddableResult res = handleNonEmbeddable( mimeType );
if ( res == KParts::BrowserRun::Delayed )
return;
setFinished( res == KParts::BrowserRun::Handled );
if ( hasFinished() ) { // saved or canceled -> flag completed
m_child->m_bCompleted = true;
static_cast(part())->checkCompleted();
}
}
- if ( hasFinished() )
- {
+ if ( hasFinished() ) {
+ kDebug() << "finished";
timer().setSingleShot( true );
timer().start( 0 );
return;
}
- //kDebug(6050) << "KHTMLRun::foundMimeType " << _type << " couldn't open";
+ //kDebug(6050) << _type << " couldn't open";
KRun::foundMimeType( mimeType );
// "open" is finished -> flag completed
m_child->m_bCompleted = true;
static_cast(part())->checkCompleted();
}
void KHTMLRun::save( const KUrl & url, const QString & suggestedFilename )
{
KHTMLPopupGUIClient::saveURL( part()->widget(), i18n( "Save As" ), url, arguments().metaData(), QString(), 0, suggestedFilename );
}
#include "khtml_run.moc"
diff --git a/kio/kio/krun.cpp b/kio/kio/krun.cpp
index b75663cc10..de2bb66125 100644
--- a/kio/kio/krun.cpp
+++ b/kio/kio/krun.cpp
@@ -1,1490 +1,1512 @@
/* This file is part of the KDE libraries
Copyright (C) 2000 Torben Weis
Copyright (C) 2006 David Faure
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "krun.h"
#include "krun_p.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kmimetypetrader.h"
#include "kmimetype.h"
#include "kio/jobclasses.h" // for KIO::JobFlags
#include "kio/job.h"
#include "kio/jobuidelegate.h"
#include "kio/global.h"
#include "kio/scheduler.h"
#include "kio/netaccess.h"
#include "kfile/kopenwithdialog.h"
#include "kfile/krecentdocument.h"
#include "kdesktopfileactions.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef Q_WS_X11
#include
#endif
class KRun::KRunPrivate
{
public:
KRunPrivate(KRun *parent)
: q(parent),
- m_showingError(false)
+ m_showingDialog(false)
{
}
void init (const KUrl& url, QWidget* window, mode_t mode,
bool isLocalFile, bool showProgressInfo, const QByteArray& asn);
+ // This helper method makes debugging easier: a single breakpoint for all
+ // the code paths that start the timer - at least from KRun itself.
+ // TODO: add public method startTimer() and deprecate timer() accessor,
+ // starting is the only valid use of the timer in subclasses (BrowserRun, KHTMLRun and KonqRun)
+ void startTimer() {
+ m_timer.start(0);
+ }
+
KRun *q;
- bool m_showingError;
+ bool m_showingDialog;
bool m_runExecutables;
QString m_preferredService;
QString m_externalBrowser;
QString m_localPath;
QString m_suggestedFileName;
QPointer m_window;
QByteArray m_asn;
KUrl m_strURL;
bool m_bFault;
bool m_bAutoDelete;
bool m_bProgressInfo;
bool m_bFinished;
KIO::Job * m_job;
QTimer m_timer;
/**
* Used to indicate that the next action is to scan the file.
* This action is invoked from slotTimeout.
*/
bool m_bScanFile;
bool m_bIsDirectory;
/**
* Used to indicate that the next action is to initialize.
* This action is invoked from slotTimeout
*/
bool m_bInit;
bool m_bIsLocalFile;
mode_t m_mode;
};
bool KRun::isExecutableFile( const KUrl& url, const QString &mimetype )
{
if ( !url.isLocalFile() )
return false;
QFileInfo file( url.path() );
if ( file.isExecutable() ) // Got a prospective file to run
{
KMimeType::Ptr mimeType = KMimeType::mimeType( mimetype );
if ( mimeType->is("application/x-executable") || mimeType->is("application/x-executable-script") )
return true;
}
return false;
}
// This is called by foundMimeType, since it knows the mimetype of the URL
bool KRun::runUrl( const KUrl& u, const QString& _mimetype, QWidget* window, bool tempFile, bool runExecutables, const QString& suggestedFileName, const QByteArray& asn )
{
bool noRun = false;
bool noAuth = false;
if ( _mimetype == "inode/directory-locked" )
{
KMessageBoxWrapper::error( window,
i18n("Unable to enter %1.\nYou do not have access rights to this location.", Qt::escape(u.prettyUrl())) );
return false;
}
else if ( _mimetype == "application/x-desktop" )
{
if ( u.isLocalFile() && runExecutables )
return KDesktopFileActions::run( u, true );
}
else if ( isExecutableFile(u, _mimetype) )
{
if ( u.isLocalFile() && runExecutables)
{
if (KAuthorized::authorize("shell_access"))
{
return (KRun::runCommand(KShell::quoteArg(u.path()), QString(), QString(), window, asn)); // just execute the url as a command
// ## TODO implement deleting the file if tempFile==true
}
else
{
noAuth = true;
}
}
else if (_mimetype == "application/x-executable")
noRun = true;
}
else if ( isExecutable(_mimetype) )
{
if (!runExecutables)
noRun = true;
if (!KAuthorized::authorize("shell_access"))
noAuth = true;
}
if ( noRun )
{
KMessageBox::sorry( window,
i18n("The file %1 is an executable program. "
"For safety it will not be started.", Qt::escape(u.prettyUrl())));
return false;
}
if ( noAuth )
{
KMessageBoxWrapper::error( window,
i18n("You do not have permission to run %1.", Qt::escape(u.prettyUrl())) );
return false;
}
KUrl::List lst;
lst.append( u );
KService::Ptr offer = KMimeTypeTrader::self()->preferredService( _mimetype );
if ( !offer )
{
// Open-with dialog
// TODO : pass the mimetype as a parameter, to show it (comment field) in the dialog !
// Hmm, in fact KOpenWithDialog::setServiceType already guesses the mimetype from the first URL of the list...
return displayOpenWithDialog( lst, window, tempFile, suggestedFileName, asn );
}
return KRun::run( *offer, lst, window, tempFile, suggestedFileName, asn );
}
bool KRun::displayOpenWithDialog( const KUrl::List& lst, QWidget* window, bool tempFiles, const QString& suggestedFileName,
const QByteArray& asn )
{
if (!KAuthorized::authorizeKAction("openwith"))
{
KMessageBox::sorry(window, i18n("You are not authorized to select an application to open this file."));
return false;
}
KOpenWithDialog l( lst, i18n("Open with:"), QString(), window );
if ( l.exec() )
{
KService::Ptr service = l.service();
if ( service )
return KRun::run( *service, lst, window, tempFiles, suggestedFileName, asn );
kDebug(7010) << "No service set, running " << l.text();
return KRun::run( l.text(), lst, window, false, suggestedFileName, asn ); // TODO handle tempFiles
}
return false;
}
void KRun::shellQuote( QString &_str )
{
// Credits to Walter, says Bernd G. :)
if (_str.isEmpty()) // Don't create an explicit empty parameter
return;
QChar q('\'');
_str.replace(q, "'\\''").prepend(q).append(q);
}
class KRunMX1 : public KMacroExpanderBase {
public:
KRunMX1( const KService &_service ) :
KMacroExpanderBase( '%' ), hasUrls( false ), hasSpec( false ), service( _service ) {}
bool hasUrls:1, hasSpec:1;
protected:
virtual int expandEscapedMacro( const QString &str, int pos, QStringList &ret );
private:
const KService &service;
};
int
KRunMX1::expandEscapedMacro( const QString &str, int pos, QStringList &ret )
{
uint option = str[pos + 1].unicode();
switch( option ) {
case 'c':
ret << service.name().replace( '%', "%%" );
break;
case 'k':
ret << service.entryPath().replace( '%', "%%" );
break;
case 'i':
ret << "-icon" << service.icon().replace( '%', "%%" );
break;
case 'm':
// ret << "-miniicon" << service.icon().replace( '%', "%%" );
kWarning() << "-miniicon isn't supported anymore (service "
<< service.name() << ')' << endl;
break;
case 'u':
case 'U':
hasUrls = true;
/* fallthrough */
case 'f':
case 'F':
case 'n':
case 'N':
case 'd':
case 'D':
case 'v':
hasSpec = true;
/* fallthrough */
default:
return -2; // subst with same and skip
}
return 2;
}
class KRunMX2 : public KMacroExpanderBase {
public:
KRunMX2( const KUrl::List &_urls ) :
KMacroExpanderBase( '%' ), ignFile( false ), urls( _urls ) {}
bool ignFile:1;
protected:
virtual int expandEscapedMacro( const QString &str, int pos, QStringList &ret );
private:
void subst( int option, const KUrl &url, QStringList &ret );
const KUrl::List &urls;
};
void
KRunMX2::subst( int option, const KUrl &url, QStringList &ret )
{
switch( option ) {
case 'u':
ret << ((url.isLocalFile() && url.fragment().isNull() && url.encodedQuery().isNull()) ?
url.toLocalFile() : url.url());
break;
case 'd':
ret << url.directory();
break;
case 'f':
ret << url.path();
break;
case 'n':
ret << url.fileName();
break;
case 'v':
if (url.isLocalFile() && QFile::exists( url.path() ) )
ret << KDesktopFile( url.path() ).desktopGroup().readEntry( "Dev" );
break;
}
return;
}
int
KRunMX2::expandEscapedMacro( const QString &str, int pos, QStringList &ret )
{
uint option = str[pos + 1].unicode();
switch( option ) {
case 'f':
case 'u':
case 'n':
case 'd':
case 'v':
if( urls.isEmpty() ) {
if (!ignFile)
kDebug() << "KRun::processDesktopExec: No URLs supplied to single-URL service " << str;
} else if( urls.count() > 1 )
kWarning() << "KRun::processDesktopExec: " << urls.count() << " URLs supplied to single-URL service " << str;
else
subst( option, urls.first(), ret );
break;
case 'F':
case 'U':
case 'N':
case 'D':
option += 'a' - 'A';
for( KUrl::List::ConstIterator it = urls.begin(); it != urls.end(); ++it )
subst( option, *it, ret );
break;
case '%':
ret = QStringList(QLatin1String("%"));
break;
default:
return -2; // subst with same and skip
}
return 2;
}
QStringList KRun::processDesktopExec(const KService &_service, const KUrl::List& _urls, bool tempFiles, const QString& suggestedFileName)
{
QString exec = _service.exec();
if ( exec.isEmpty() ) {
kWarning() << "KRun: no Exec field in `" << _service.entryPath() << "' !";
return QStringList();
}
QStringList result;
bool appHasTempFileOption;
KRunMX1 mx1( _service );
KRunMX2 mx2( _urls );
if( !mx1.expandMacrosShellQuote( exec ) ) { // Error in shell syntax
kWarning() << "KRun: syntax error in command" << _service.exec() << ", service" << _service.name();
return QStringList();
}
// FIXME: the current way of invoking kioexec disables term and su use
// Check if we need "tempexec" (kioexec in fact)
appHasTempFileOption = tempFiles && _service.property("X-KDE-HasTempFileOption").toBool();
if( tempFiles && !appHasTempFileOption && _urls.size() ) {
const QString kioexec = KStandardDirs::findExe("kioexec");
Q_ASSERT(!kioexec.isEmpty());
result << kioexec << "--tempfiles" << exec;
if ( !suggestedFileName.isEmpty() ) {
result << "--suggestedfilename";
result << suggestedFileName;
}
result += _urls.toStringList();
return result;
}
// Check if we need kioexec
if( !mx1.hasUrls ) {
for( KUrl::List::ConstIterator it = _urls.begin(); it != _urls.end(); ++it )
if ( !(*it).isLocalFile() && !KProtocolInfo::isHelperProtocol(*it) ) {
// We need to run the app through kioexec
const QString kioexec = KStandardDirs::findExe("kioexec");
Q_ASSERT(!kioexec.isEmpty());
result << kioexec;
if ( tempFiles )
result << "--tempfiles";
if ( !suggestedFileName.isEmpty() ) {
result << "--suggestedfilename";
result << suggestedFileName;
}
result << exec;
result += _urls.toStringList();
return result;
}
}
if ( appHasTempFileOption )
exec += " --tempfile";
// Did the user forget to append something like '%f'?
// If so, then assume that '%f' is the right choice => the application
// accepts only local files.
if( !mx1.hasSpec ) {
exec += " %f";
mx2.ignFile = true;
}
mx2.expandMacrosShellQuote( exec ); // syntax was already checked, so don't check return value
/*
1 = need_shell, 2 = terminal, 4 = su
0 << split(cmd)
1 << "sh" << "-c" << cmd
2 << split(term) << "-e" << split(cmd)
3 << split(term) << "-e" << "sh" << "-c" << cmd
4 << "kdesu" << "-u" << user << "-c" << cmd
5 << "kdesu" << "-u" << user << "-c" << ("sh -c " + quote(cmd))
6 << split(term) << "-e" << "su" << user << "-c" << cmd
7 << split(term) << "-e" << "su" << user << "-c" << ("sh -c " + quote(cmd))
"sh -c" is needed in the "su" case, too, as su uses the user's login shell, not sh.
this could be optimized with the -s switch of some su versions (e.g., debian linux).
*/
if (_service.terminal()) {
KConfigGroup cg(KGlobal::config(), "General");
QString terminal = cg.readPathEntry("TerminalApplication", "konsole");
if (terminal == "konsole")
terminal += " -caption=%c %i %m";
terminal += ' ';
terminal += _service.terminalOptions();
if( !mx1.expandMacrosShellQuote( terminal ) ) {
kWarning() << "KRun: syntax error in command `" << terminal << "', service `" << _service.name() << "'";
return QStringList();
}
mx2.expandMacrosShellQuote( terminal );
result = KShell::splitArgs( terminal ); // assuming that the term spec never needs a shell!
result << "-e";
}
KShell::Errors err;
QStringList execlist = KShell::splitArgs(exec, KShell::AbortOnMeta | KShell::TildeExpand, &err);
if (err == KShell::NoError && !execlist.isEmpty()) { // mx1 checked for syntax errors already
// Resolve the executable to ensure that helpers in lib/kde4/libexec/ are found.
// Too bad for commands that need a shell - they must reside in $PATH.
const QString exePath = KStandardDirs::findExe(execlist[0]);
if (!exePath.isEmpty())
execlist[0] = exePath;
}
if (_service.substituteUid()) {
if (_service.terminal())
result << "su";
else
result << KStandardDirs::findExe("kdesu") << "-u";
result << _service.username() << "-c";
if (err == KShell::FoundMeta)
exec = "/bin/sh -c " + KShell::quoteArg(exec);
else
exec = KShell::joinArgs(execlist);
result << exec;
} else {
if (err == KShell::FoundMeta)
result << "/bin/sh" << "-c" << exec;
else
result += execlist;
}
return result;
}
//static
QString KRun::binaryName( const QString & execLine, bool removePath )
{
// Remove parameters and/or trailing spaces.
QStringList args = KShell::splitArgs( execLine );
for (QStringList::ConstIterator it = args.begin(); it != args.end(); ++it)
if (!(*it).contains('='))
// Remove path if wanted
return removePath ? (*it).mid((*it).lastIndexOf('/') + 1) : *it;
return QString();
}
static bool runCommandInternal( KProcess* proc, const KService* service, const QString& binName,
const QString &execName, const QString & iconName, QWidget* window, const QByteArray& asn )
{
if( window != NULL )
window = window->topLevelWidget();
if (service && !service->entryPath().isEmpty()
&& !KDesktopFile::isAuthorizedDesktopFile( service->entryPath() ))
{
kWarning() << "No authorization to execute " << service->entryPath();
KMessageBox::sorry( window, i18n("You are not authorized to execute this file."));
return false;
}
QString bin = KRun::binaryName( binName, true );
#ifdef Q_WS_X11 // Startup notification doesn't work with QT/E, service isn't needed without Startup notification
bool silent;
QByteArray wmclass;
KStartupInfoId id;
bool startup_notify = ( asn != "0" && KRun::checkStartupNotify( binName, service, &silent, &wmclass ));
if( startup_notify )
{
id.initId( asn );
id.setupStartupEnv();
KStartupInfoData data;
data.setHostname();
data.setBin( bin );
if( !execName.isEmpty())
data.setName( execName );
else if( service && !service->name().isEmpty())
data.setName( service->name());
data.setDescription( i18n( "Launching %1" , data.name()));
if( !iconName.isEmpty())
data.setIcon( iconName );
else if( service && !service->icon().isEmpty())
data.setIcon( service->icon());
if( !wmclass.isEmpty())
data.setWMClass( wmclass );
if( silent )
data.setSilent( KStartupInfoData::Yes );
data.setDesktop( KWindowSystem::currentDesktop());
if( window )
data.setLaunchedBy( window->winId());
KStartupInfo::sendStartup( id, data );
}
int pid = KProcessRunner::run( proc, binName, id );
if( startup_notify && pid )
{
KStartupInfoData data;
data.addPid( pid );
KStartupInfo::sendChange( id, data );
KStartupInfo::resetStartupEnv();
}
return pid != 0;
#else
Q_UNUSED( execName );
Q_UNUSED( iconName );
return KProcessRunner::run( proc, bin ) != 0;
#endif
}
// This code is also used in klauncher.
bool KRun::checkStartupNotify( const QString& /*binName*/, const KService* service, bool* silent_arg, QByteArray* wmclass_arg )
{
bool silent = false;
QByteArray wmclass;
if( service && service->property( "StartupNotify" ).isValid())
{
silent = !service->property( "StartupNotify" ).toBool();
wmclass = service->property( "StartupWMClass" ).toString().toLatin1();
}
else if( service && service->property( "X-KDE-StartupNotify" ).isValid())
{
silent = !service->property( "X-KDE-StartupNotify" ).toBool();
wmclass = service->property( "X-KDE-WMClass" ).toString().toLatin1();
}
else // non-compliant app
{
if( service )
{
if( service->isApplication() )
wmclass = "0"; // doesn't have .desktop entries needed, start as non-compliant
else
return false; // no startup notification at all
}
else
{
#if 0
// Create startup notification even for apps for which there shouldn't be any,
// just without any visual feedback. This will ensure they'll be positioned on the proper
// virtual desktop, and will get user timestamp from the ASN ID.
wmclass = "0";
silent = true;
#else // That unfortunately doesn't work, when the launched non-compliant application
// launches another one that is compliant and there is any delay inbetween (bnc:#343359)
return false;
#endif
}
}
if( silent_arg != NULL )
*silent_arg = silent;
if( wmclass_arg != NULL )
*wmclass_arg = wmclass;
return true;
}
static bool runTempService( const KService& _service, const KUrl::List& _urls, QWidget* window,
bool tempFiles, const QString& suggestedFileName, const QByteArray& asn )
{
if (!_urls.isEmpty()) {
kDebug(7010) << "runTempService: first url " << _urls.first().url();
}
QStringList args;
if ((_urls.count() > 1) && !_service.allowMultipleFiles())
{
// We need to launch the application N times. That sucks.
// We ignore the result for application 2 to N.
// For the first file we launch the application in the
// usual way. The reported result is based on this
// application.
KUrl::List::ConstIterator it = _urls.begin();
while(++it != _urls.end())
{
KUrl::List singleUrl;
singleUrl.append(*it);
runTempService( _service, singleUrl, window, tempFiles, suggestedFileName, "" );
}
KUrl::List singleUrl;
singleUrl.append(_urls.first());
args = KRun::processDesktopExec( _service, singleUrl, tempFiles, suggestedFileName );
}
else
{
args = KRun::processDesktopExec(_service, _urls, tempFiles, suggestedFileName );
}
if (args.isEmpty()) {
KMessageBox::sorry(window, i18n("Error processing Exec field in %1", _service.entryPath()) );
return false;
}
kDebug(7010) << "runTempService: KProcess args=" << args;
KProcess * proc = new KProcess;
*proc << args;
if (!_service.path().isEmpty())
proc->setWorkingDirectory(_service.path());
return runCommandInternal( proc, &_service, KRun::binaryName( _service.exec(), false ),
_service.name(), _service.icon(), window, asn );
}
// WARNING: don't call this from processDesktopExec, since klauncher uses that too...
static KUrl::List resolveURLs( const KUrl::List& _urls, const KService& _service )
{
// Check which protocols the application supports.
// This can be a list of actual protocol names, or just KIO for KDE apps.
QStringList supportedProtocols = _service.property("X-KDE-Protocols").toStringList();
KRunMX1 mx1( _service );
QString exec = _service.exec();
if ( mx1.expandMacrosShellQuote( exec ) && !mx1.hasUrls ) {
Q_ASSERT( supportedProtocols.isEmpty() ); // huh? If you support protocols you need %u or %U...
} else {
if ( supportedProtocols.isEmpty() )
{
// compat mode: assume KIO if not set and it's a KDE app
QStringList categories = _service.property("Categories").toStringList();
if ( categories.contains("KDE") )
supportedProtocols.append( "KIO" );
else { // if no KDE app, be a bit over-generic
supportedProtocols.append( "http");
supportedProtocols.append( "ftp");
}
}
}
kDebug(7010) << "supportedProtocols:" << supportedProtocols;
KUrl::List urls( _urls );
if ( !supportedProtocols.contains( "KIO" ) ) {
for( KUrl::List::Iterator it = urls.begin(); it != urls.end(); ++it ) {
const KUrl url = *it;
bool supported = url.isLocalFile() || supportedProtocols.contains( url.protocol().toLower() );
kDebug(7010) << "Looking at url=" << url << " supported=" << supported;
if ( !supported && KProtocolInfo::protocolClass(url.protocol()) == ":local" )
{
// Maybe we can resolve to a local URL?
KUrl localURL = KIO::NetAccess::mostLocalUrl( url, 0 );
if ( localURL != url ) {
*it = localURL;
kDebug(7010) << "Changed to " << localURL;
}
}
}
}
return urls;
}
bool KRun::run( const KService& _service, const KUrl::List& _urls, QWidget* window,
bool tempFiles, const QString& suggestedFileName, const QByteArray& asn )
{
if (!_service.entryPath().isEmpty() &&
!KDesktopFile::isAuthorizedDesktopFile( _service.entryPath()))
{
kWarning() << "No authorization to execute " << _service.entryPath();
KMessageBox::sorry( window, i18n("You are not authorized to execute this service.") );
return false;
}
if ( !tempFiles )
{
// Remember we opened those urls, for the "recent documents" menu in kicker
KUrl::List::ConstIterator it = _urls.begin();
for(; it != _urls.end(); ++it) {
//kDebug(7010) << "KRecentDocument::adding " << (*it).url();
KRecentDocument::add( *it, _service.desktopEntryName() );
}
}
if ( tempFiles || _service.entryPath().isEmpty() || !suggestedFileName.isEmpty() )
{
return runTempService( _service, _urls, window, tempFiles, suggestedFileName, asn );
}
kDebug(7010) << "KRun::run " << _service.entryPath();
if (!_urls.isEmpty()) {
kDebug(7010) << "First url " << _urls.first().url();
}
// Resolve urls if needed, depending on what the app supports
const KUrl::List urls = resolveURLs( _urls, _service );
QString error;
int pid = 0;
QByteArray myasn = asn;
// startServiceByDesktopPath() doesn't take QWidget*, add it to the startup info now
if( window != NULL )
{
if( myasn.isEmpty())
myasn = KStartupInfo::createNewStartupId();
if( myasn != "0" )
{
KStartupInfoId id;
id.initId( myasn );
KStartupInfoData data;
data.setLaunchedBy( window->winId());
KStartupInfo::sendChange( id, data );
}
}
int i = KToolInvocation::startServiceByDesktopPath(
_service.entryPath(), urls.toStringList(), &error, 0L, &pid, myasn
);
if (i != 0)
{
kDebug(7010) << error;
KMessageBox::sorry( window, error );
return false;
}
kDebug(7010) << "startServiceByDesktopPath worked fine";
return true;
}
bool KRun::run( const QString& _exec, const KUrl::List& _urls, QWidget* window, const QString& _name,
const QString& _icon, const QByteArray& asn )
{
KService::Ptr service(new KService(_name, _exec, _icon));
return run( *service, _urls, window, false, QString(), asn );
}
bool KRun::runCommand( const QString &cmd, QWidget* window )
{
QString bin = binaryName( cmd, true );
return KRun::runCommand( cmd, bin, bin, window, "" );
}
bool KRun::runCommand( const QString& cmd, const QString &execName, const QString & iconName, QWidget* window, const QByteArray& asn )
{
kDebug(7010) << "runCommand " << cmd << "," << execName;
KProcess * proc = new KProcess;
proc->setShellCommand( cmd );
QString bin = binaryName( execName, true );
KService::Ptr service = KService::serviceByDesktopName( bin );
return runCommandInternal( proc, service.data(), bin, execName, iconName, window, asn );
}
KRun::KRun( const KUrl& url, QWidget* window, mode_t mode, bool isLocalFile,
bool showProgressInfo, const QByteArray& asn )
: d(new KRunPrivate(this))
{
d->m_timer.setObjectName( "KRun::timer" );
d->m_timer.setSingleShot( true );
d->init (url, window, mode, isLocalFile, showProgressInfo, asn );
}
void KRun::KRunPrivate::init ( const KUrl& url, QWidget* window, mode_t mode, bool isLocalFile,
bool showProgressInfo, const QByteArray& asn )
{
m_bFault = false;
m_bAutoDelete = true;
m_bProgressInfo = showProgressInfo;
m_bFinished = false;
m_job = 0L;
m_strURL = url;
m_bScanFile = false;
m_bIsDirectory = false;
m_bIsLocalFile = isLocalFile;
m_mode = mode;
m_runExecutables = true;
m_window = window;
m_asn = asn;
q->setEnableExternalBrowser(true);
// Start the timer. This means we will return to the event
// loop and do initialization afterwards.
// Reason: We must complete the constructor before we do anything else.
m_bInit = true;
q->connect( &m_timer, SIGNAL( timeout() ), q, SLOT( slotTimeout() ) );
- m_timer.start( 0 );
+ startTimer();
kDebug(7010) << " new KRun " << q << " " << url.prettyUrl() << " timer=" << &m_timer;
KGlobal::ref();
}
void KRun::init()
{
kDebug(7010) << "INIT called";
if ( !d->m_strURL.isValid() )
{
- d->m_showingError = true;
+ // TODO KDE5: call virtual method on error (see BrowserRun::init)
+ d->m_showingDialog = true;
KMessageBoxWrapper::error( d->m_window, i18n( "Malformed URL\n%1", d->m_strURL.url() ) );
- d->m_showingError = false;
+ d->m_showingDialog = false;
d->m_bFault = true;
d->m_bFinished = true;
- d->m_timer.start( 0 );
+ d->startTimer();
return;
}
if ( !KAuthorized::authorizeUrlAction( "open", KUrl(), d->m_strURL) )
{
QString msg = KIO::buildErrorString(KIO::ERR_ACCESS_DENIED, d->m_strURL.prettyUrl());
- d->m_showingError = true;
+ d->m_showingDialog = true;
KMessageBoxWrapper::error( d->m_window, msg );
- d->m_showingError = false;
+ d->m_showingDialog = false;
d->m_bFault = true;
d->m_bFinished = true;
- d->m_timer.start( 0 );
+ d->startTimer();
return;
}
if ( !d->m_bIsLocalFile && d->m_strURL.isLocalFile() )
d->m_bIsLocalFile = true;
QString exec;
if (d->m_strURL.protocol().startsWith("http"))
{
exec = d->m_externalBrowser;
}
if ( d->m_bIsLocalFile )
{
if ( d->m_mode == 0 )
{
KDE_struct_stat buff;
if ( KDE_stat( QFile::encodeName(d->m_strURL.path()), &buff ) == -1 )
{
- d->m_showingError = true;
+ d->m_showingDialog = true;
KMessageBoxWrapper::error( d->m_window, i18n( "Unable to run the command specified. The file or folder %1 does not exist." , Qt::escape(d->m_strURL.prettyUrl()) ) );
- d->m_showingError = false;
+ d->m_showingDialog = false;
d->m_bFault = true;
d->m_bFinished = true;
- d->m_timer.start( 0 );
+ d->startTimer();
return;
}
d->m_mode = buff.st_mode;
}
KMimeType::Ptr mime = KMimeType::findByUrl( d->m_strURL, d->m_mode, d->m_bIsLocalFile );
assert( mime );
kDebug(7010) << "MIME TYPE is " << mime->name();
- foundMimeType( mime->name() );
+ mimeTypeDetermined( mime->name() );
return;
}
else if ( !exec.isEmpty() || KProtocolInfo::isHelperProtocol( d->m_strURL ) ) {
kDebug(7010) << "Helper protocol";
bool ok = false;
KUrl::List urls;
urls.append( d->m_strURL );
if (exec.isEmpty())
{
exec = KProtocolInfo::exec( d->m_strURL.protocol() );
if (exec.isEmpty())
{
- foundMimeType(KProtocolManager::defaultMimetype(d->m_strURL));
+ mimeTypeDetermined(KProtocolManager::defaultMimetype(d->m_strURL));
return;
}
run( exec, urls, d->m_window, false, QString(), d->m_asn );
ok = true;
}
else if (exec.startsWith('!'))
{
exec = exec.mid(1); // Literal command
exec += " %u";
run( exec, urls, d->m_window, false, QString(), d->m_asn );
ok = true;
}
else
{
KService::Ptr service = KService::serviceByStorageId( exec );
if (service)
{
run( *service, urls, d->m_window, false, QString(), d->m_asn );
ok = true;
}
}
if (ok)
{
d->m_bFinished = true;
// will emit the error and autodelete this
- d->m_timer.start( 0 );
+ d->startTimer();
return;
}
}
// Did we already get the information that it is a directory ?
if ( S_ISDIR( d->m_mode ) )
{
- foundMimeType( "inode/directory" );
+ mimeTypeDetermined( "inode/directory" );
return;
}
// Let's see whether it is a directory
if ( !KProtocolManager::supportsListing( d->m_strURL ) )
{
//kDebug(7010) << "Protocol has no support for listing";
// No support for listing => it can't be a directory (example: http)
scanFile();
return;
}
kDebug(7010) << "Testing directory (stating)";
// It may be a directory or a file, let's stat
KIO::JobFlags flags = d->m_bProgressInfo ? KIO::DefaultFlags : KIO::HideProgressInfo;
KIO::StatJob *job = KIO::stat( d->m_strURL, KIO::StatJob::SourceSide, 0 /* no details */, flags );
job->ui()->setWindow (d->m_window);
connect( job, SIGNAL( result( KJob * ) ),
this, SLOT( slotStatResult( KJob * ) ) );
d->m_job = job;
kDebug(7010) << " Job " << job << " is about stating " << d->m_strURL.url();
}
KRun::~KRun()
{
kDebug(7010) << "KRun::~KRun() " << this;
d->m_timer.stop();
killJob();
KGlobal::deref();
kDebug(7010) << "KRun::~KRun() done " << this;
delete d;
}
void KRun::scanFile()
{
- kDebug(7010) << "###### KRun::scanFile " << d->m_strURL.url();
+ kDebug(7010) << d->m_strURL;
// First, let's check for well-known extensions
// Not when there is a query in the URL, in any case.
if ( d->m_strURL.query().isEmpty() )
{
KMimeType::Ptr mime = KMimeType::findByUrl( d->m_strURL );
assert( mime );
if ( mime->name() != "application/octet-stream" || d->m_bIsLocalFile )
{
kDebug(7010) << "Scanfile: MIME TYPE is " << mime->name();
- foundMimeType( mime->name() );
+ mimeTypeDetermined( mime->name() );
return;
}
}
// No mimetype found, and the URL is not local (or fast mode not allowed).
// We need to apply the 'KIO' method, i.e. either asking the server or
// getting some data out of the file, to know what mimetype it is.
if ( !KProtocolManager::supportsReading( d->m_strURL ) )
{
kError(7010) << "#### NO SUPPORT FOR READING!" << endl;
d->m_bFault = true;
d->m_bFinished = true;
- d->m_timer.start( 0 );
+ d->startTimer();
return;
}
kDebug(7010) << this << " Scanning file " << d->m_strURL.url();
KIO::JobFlags flags = d->m_bProgressInfo ? KIO::DefaultFlags : KIO::HideProgressInfo;
KIO::TransferJob *job = KIO::get( d->m_strURL, KIO::NoReload /*reload*/, flags );
job->ui()->setWindow (d->m_window);
connect(job, SIGNAL( result(KJob *)),
this, SLOT( slotScanFinished(KJob *)));
connect(job, SIGNAL( mimetype(KIO::Job *, const QString &)),
this, SLOT( slotScanMimeType(KIO::Job *, const QString &)));
d->m_job = job;
kDebug(7010) << " Job " << job << " is about getting from " << d->m_strURL.url();
}
void KRun::slotTimeout()
{
kDebug(7010) << this << " slotTimeout called";
if ( d->m_bInit )
{
d->m_bInit = false;
init();
return;
}
if ( d->m_bFault ) {
emit error();
}
if ( d->m_bFinished ) {
emit finished();
}
else
{
if ( d->m_bScanFile )
{
d->m_bScanFile = false;
scanFile();
return;
}
else if ( d->m_bIsDirectory )
{
d->m_bIsDirectory = false;
- foundMimeType( "inode/directory" );
+ mimeTypeDetermined( "inode/directory" );
return;
}
}
if ( d->m_bAutoDelete )
{
delete this;
return;
}
}
void KRun::slotStatResult( KJob * job )
{
d->m_job = 0L;
if (job->error())
{
- d->m_showingError = true;
+ d->m_showingDialog = true;
kError(7010) << this << " ERROR " << job->error() << " " << job->errorString() << endl;
job->uiDelegate()->showErrorMessage();
//kDebug(7010) << this << " KRun returning from showErrorDialog, starting timer to delete us";
- d->m_showingError = false;
+ d->m_showingDialog = false;
d->m_bFault = true;
d->m_bFinished = true;
// will emit the error and autodelete this
- d->m_timer.start( 0 );
+ d->startTimer();
} else {
kDebug(7010) << "Finished";
if(!qobject_cast(job))
kFatal() << "job is a " << typeid(*job).name() << " should be a StatJob";
const KIO::UDSEntry entry = ((KIO::StatJob*)job)->statResult();
const mode_t mode = entry.numberValue( KIO::UDSEntry::UDS_FILE_TYPE );
if ( S_ISDIR( mode ) )
d->m_bIsDirectory = true; // it's a dir
else
d->m_bScanFile = true; // it's a file
d->m_localPath = entry.stringValue( KIO::UDSEntry::UDS_LOCAL_PATH );
// mimetype already known? (e.g. print:/manager)
const QString knownMimeType = entry.stringValue( KIO::UDSEntry::UDS_MIME_TYPE ) ;
if ( !knownMimeType.isEmpty() )
{
- foundMimeType( knownMimeType );
+ mimeTypeDetermined( knownMimeType );
d->m_bFinished = true;
}
// We should have found something
assert ( d->m_bScanFile || d->m_bIsDirectory );
// Start the timer. Once we get the timer event this
// protocol server is back in the pool and we can reuse it.
// This gives better performance than starting a new slave
- d->m_timer.start( 0 );
+ d->startTimer();
}
}
void KRun::slotScanMimeType( KIO::Job *, const QString &mimetype )
{
if ( mimetype.isEmpty() )
kWarning(7010) << "KRun::slotScanFinished : MimetypeJob didn't find a mimetype! Probably a kioslave bug.";
- foundMimeType( mimetype );
+ mimeTypeDetermined( mimetype );
d->m_job = 0;
}
void KRun::slotScanFinished( KJob *job )
{
d->m_job = 0;
if (job->error())
{
- d->m_showingError = true;
+ d->m_showingDialog = true;
kError(7010) << this << " ERROR (stat) : " << job->error() << " " << job->errorString() << endl;
job->uiDelegate()->showErrorMessage();
//kDebug(7010) << this << " KRun returning from showErrorDialog, starting timer to delete us";
- d->m_showingError = false;
+ d->m_showingDialog = false;
d->m_bFault = true;
d->m_bFinished = true;
// will emit the error and autodelete this
- d->m_timer.start( 0 );
+ d->startTimer();
}
}
+void KRun::mimeTypeDetermined(const QString& mimeType)
+{
+ // foundMimeType reimplementations might show a dialog box;
+ // make sure some timer doesn't kill us meanwhile (#137678, #156447)
+ Q_ASSERT(!d->m_showingDialog);
+ d->m_showingDialog = true;
+
+ foundMimeType(mimeType);
+
+ d->m_showingDialog = false;
+}
+
void KRun::foundMimeType( const QString& type )
{
kDebug(7010) << "Resulting mime type is " << type;
/*
// Automatically unzip stuff
// Disabled since the new KIO doesn't have filters yet.
if ( type == "application/x-gzip" ||
type == "application/x-bzip" ||
type == "application/x-bzip" )
{
KUrl::List lst = KUrl::split( m_strURL );
if ( lst.isEmpty() )
{
QString tmp = i18n( "Malformed URL" );
tmp += "\n";
tmp += m_strURL.url();
KMessageBoxWrapper::error( 0L, tmp );
return;
}
if ( type == "application/x-gzip" )
lst.prepend( KUrl( "gzip:/decompress" ) );
else if ( type == "application/x-bzip" )
lst.prepend( KUrl( "bzip:/decompress" ) );
else if ( type == "application/x-bzip" )
lst.prepend( KUrl( "bzip2:/decompress" ) );
else if ( type == "application/x-tar" )
lst.prepend( KUrl( "tar:/" ) );
// Move the HTML style reference to the leftmost URL
KUrl::List::Iterator it = lst.begin();
++it;
(*lst.begin()).setRef( (*it).ref() );
(*it).setRef( QString() );
// Create the new URL
m_strURL = KUrl::join( lst );
kDebug(7010) << "Now trying with " << debugString(m_strURL.url());
killJob();
// We don't know if this is a file or a directory. Let's test this first.
// (For instance a tar.gz is a directory contained inside a file)
// It may be a directory or a file, let's stat
KIO::StatJob *job = KIO::stat( m_strURL, m_bProgressInfo );
connect( job, SIGNAL( result( KJob * ) ),
this, SLOT( slotStatResult( KJob * ) ) );
m_job = job;
return;
}
*/
KIO::TransferJob *job = qobject_cast( d->m_job );
if ( job )
{
job->putOnHold();
KIO::Scheduler::publishSlaveOnHold();
d->m_job = 0;
}
Q_ASSERT( !d->m_bFinished );
KMimeType::Ptr mime = KMimeType::mimeType( type );
if ( !mime )
kWarning(7010) << "Unknown mimetype " << type;
// Suport for preferred service setting, see setPreferredService
if ( !d->m_preferredService.isEmpty() ) {
kDebug(7010) << "Attempting to open with preferred service: " << d->m_preferredService;
KService::Ptr serv = KService::serviceByDesktopName( d->m_preferredService );
if ( serv && serv->hasMimeType( mime.data() ) )
{
KUrl::List lst;
lst.append( d->m_strURL );
d->m_bFinished = KRun::run( *serv, lst, d->m_window, false, QString(), d->m_asn );
/// Note: the line above means that if that service failed, we'll
/// go to runUrl to maybe find another service, even though a dialog
/// box was displayed. That's good if runUrl tries another service,
/// but it's not good if it tries the same one :}
}
}
// Resolve .desktop files from media:/, remote:/, applications:/ etc.
if ( mime && mime->is( "application/x-desktop" ) && !d->m_localPath.isEmpty() )
{
d->m_strURL = KUrl();
d->m_strURL.setPath( d->m_localPath );
}
if (!d->m_bFinished && KRun::runUrl( d->m_strURL, type, d->m_window, false /*tempfile*/, d->m_runExecutables, d->m_suggestedFileName, d->m_asn )){
d->m_bFinished = true;
}
else{
d->m_bFinished = true;
d->m_bFault = true;
}
- d->m_timer.start( 0 );
+ d->startTimer();
}
void KRun::killJob()
{
if ( d->m_job )
{
kDebug(7010) << "KRun::killJob run=" << this << " m_job=" << d->m_job;
d->m_job->kill();
d->m_job = 0L;
}
}
void KRun::abort()
{
- kDebug(7010) << "KRun::abort " << this << " m_showingError=" << d->m_showingError;
+ kDebug(7010) << "KRun::abort " << this << " m_showingDialog=" << d->m_showingDialog;
killJob();
// If we're showing an error message box, the rest will be done
// after closing the msgbox -> don't autodelete nor emit signals now.
- if ( d->m_showingError )
+ if ( d->m_showingDialog )
return;
d->m_bFault = true;
d->m_bFinished = true;
d->m_bInit = false;
d->m_bScanFile = false;
// will emit the error and autodelete this
- d->m_timer.start( 0 );
+ d->startTimer();
}
bool KRun::hasError() const
{
return d->m_bFault;
}
bool KRun::hasFinished() const
{
return d->m_bFinished;
}
bool KRun::autoDelete() const
{
return d->m_bAutoDelete;
}
void KRun::setAutoDelete(bool b)
{
d->m_bAutoDelete = b;
}
void KRun::setEnableExternalBrowser(bool b)
{
if (b)
d->m_externalBrowser = KConfigGroup(KGlobal::config(), "General").readEntry("BrowserApplication");
else
d->m_externalBrowser.clear();
}
void KRun::setPreferredService( const QString& desktopEntryName )
{
d->m_preferredService = desktopEntryName;
}
void KRun::setRunExecutables(bool b)
{
d->m_runExecutables = b;
}
void KRun::setSuggestedFileName( const QString& fileName )
{
d->m_suggestedFileName = fileName;
}
QString KRun::suggestedFileName() const
{
return d->m_suggestedFileName;
}
bool KRun::isExecutable( const QString& serviceType )
{
return ( serviceType == "application/x-desktop" ||
serviceType == "application/x-executable" ||
serviceType == "application/x-ms-dos-executable" ||
serviceType == "application/x-shellscript" );
}
void KRun::setUrl( const KUrl &url )
{
d->m_strURL = url;
}
KUrl KRun::url() const
{
return d->m_strURL;
}
void KRun::setError( bool error )
{
d->m_bFault = error;
}
void KRun::setProgressInfo( bool progressInfo )
{
d->m_bProgressInfo = progressInfo;
}
bool KRun::progressInfo() const
{
return d->m_bProgressInfo;
}
void KRun::setFinished( bool finished )
{
d->m_bFinished = finished;
+ // TODO d->startTimer(); (and later on remove it from callers...)
}
void KRun::setJob( KIO::Job *job )
{
d->m_job = job;
}
KIO::Job* KRun::job()
{
return d->m_job;
}
QTimer& KRun::timer()
{
return d->m_timer;
}
void KRun::setDoScanFile( bool scanFile )
{
d->m_bScanFile = scanFile;
}
bool KRun::doScanFile() const
{
return d->m_bScanFile;
}
void KRun::setIsDirecory( bool isDirectory )
{
d->m_bIsDirectory = isDirectory;
}
bool KRun::isDirectory() const
{
return d->m_bIsDirectory;
}
void KRun::setInitializeNextAction( bool initialize )
{
d->m_bInit = initialize;
}
bool KRun::initializeNextAction() const
{
return d->m_bInit;
}
void KRun::setIsLocalFile( bool isLocalFile )
{
d->m_bIsLocalFile = isLocalFile;
}
bool KRun::isLocalFile() const
{
return d->m_bIsLocalFile;
}
void KRun::setMode( mode_t mode )
{
d->m_mode = mode;
}
mode_t KRun::mode() const
{
return d->m_mode;
}
/****************/
#ifndef Q_WS_X11
int KProcessRunner::run(KProcess * p, const QString & binName)
{
return (new KProcessRunner(p, binName))->pid();
}
#else
int KProcessRunner::run(KProcess * p, const QString & binName, const KStartupInfoId& id)
{
return (new KProcessRunner(p, binName, id))->pid();
}
#endif
#ifndef Q_WS_X11
KProcessRunner::KProcessRunner(KProcess * p, const QString & _binName)
#else
KProcessRunner::KProcessRunner(KProcess * p, const QString & _binName, const KStartupInfoId& _id) :
id(_id)
#endif
{
process = p;
binName = _binName;
connect(process, SIGNAL(finished(int, QProcess::ExitStatus)),
this, SLOT(slotProcessExited(int, QProcess::ExitStatus)));
process->start();
if (!process->waitForStarted()) {
slotProcessExited(127, QProcess::CrashExit);
}
}
KProcessRunner::~KProcessRunner()
{
delete process;
}
int KProcessRunner::pid() const
{
return process ? process->pid() : 0;
}
void
KProcessRunner::slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus)
{
kDebug(7010) << "slotProcessExited " << binName;
kDebug(7010) << "normalExit " << (exitStatus == QProcess::NormalExit);
kDebug(7010) << "exitCode " << exitCode;
bool showErr = exitStatus == QProcess::NormalExit
&& (exitCode == 127 || exitCode == 1);
if (!binName.isEmpty() && (showErr || pid() == 0 )) {
// Often we get 1 (zsh, csh) or 127 (ksh, bash) because the binary doesn't exist.
// We can't just rely on that, but it's a good hint.
// Before assuming its really so, we'll try to find the binName
// relatively to current directory, and then in the PATH.
if (!QFile(binName).exists() && KStandardDirs::findExe(binName).isEmpty()) {
KGlobal::ref();
KMessageBox::sorry(0L, i18n("Could not find the program '%1'", binName));
KGlobal::deref();
}
}
#ifdef Q_WS_X11
if (!id.none()) {
KStartupInfoData data;
data.addPid(pid()); // announce this pid for the startup notification has finished
data.setHostname();
KStartupInfo::sendFinish(id, data);
}
#endif
deleteLater();
}
#include "krun.moc"
#include "krun_p.moc"
diff --git a/kio/kio/krun.h b/kio/kio/krun.h
index 418b531fd6..7340f0c3c3 100644
--- a/kio/kio/krun.h
+++ b/kio/kio/krun.h
@@ -1,501 +1,512 @@
// -*- mode: c++; c-basic-offset: 2 -*-
/* This file is part of the KDE project
Copyright (C) 1998, 1999 Torben Weis
Copyright (C) 2006 David Faure
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KRUN_H
#define KRUN_H
#include
#include
#include
#include
#include
#include
class KService;
class KStartupInfo;
class KJob;
namespace KIO {
class Job;
}
/**
* To open files with their associated applications in KDE, use KRun.
*
* It can execute any desktop entry, as well as any file, using
* the default application or another application "bound" to the file type
* (or URL protocol).
*
* In that example, the mimetype of the file is not known by the application,
* so a KRun instance must be created. It will determine the mimetype by itself.
* If the mimetype is known, or if you even know the service (application) to
* use for this file, use one of the static methods.
*
* By default KRun uses auto deletion. It causes the KRun instance to delete
* itself when the it finished its task. If you allocate the KRun
* object on the stack you must disable auto deletion, otherwise it will crash.
*
* @short Opens files with their associated applications in KDE
*/
class KIO_EXPORT KRun : public QObject
{
Q_OBJECT
public:
/**
* @param url the URL of the file or directory to 'run'
*
* @param window
* The top-level widget of the app that invoked this object.
* It is used to make sure private information like passwords
* are properly handled per application.
*
* @param mode The @p st_mode field of struct stat. If
* you don't know this set it to 0.
*
* @param isLocalFile
* If this parameter is set to @p false then @p url is
* examined to find out whether it is a local URL or
* not. This flag is just used to improve speed, since the
* function KUrl::isLocalFile is a bit slow.
*
* @param showProgressInfo
* Whether to show progress information when determining the
* type of the file (i.e. when using KIO::stat and KIO::mimetype)
* Before you set this to false to avoid a dialog box, think about
* a very slow FTP server...
* It is always better to provide progress info in such cases.
* @param asn
* Application startup notification id, if available (otherwise "").
*/
KRun( const KUrl& url, QWidget* window, mode_t mode = 0,
bool isLocalFile = false, bool showProgressInfo = true, const QByteArray& asn = "" );
/**
* Destructor. Don't call it yourself, since a KRun object auto-deletes
* itself.
*/
virtual ~KRun();
/**
* Abort this KRun. This kills any jobs launched by it,
* and leads to deletion if auto-deletion is on.
* This is much safer than deleting the KRun (in case it's
* currently showing an error dialog box, for instance)
*/
void abort();
/**
* Returns true if the KRun instance has an error.
* @return true when an error occurred
* @see error()
*/
bool hasError() const;
/**
* Returns true if the KRun instance has finished.
* @return true if the KRun instance has finished
* @see finished()
*/
bool hasFinished() const;
/**
* Checks whether auto delete is activated.
* Auto-deletion causes the KRun instance to delete itself
* when it finished its task.
* By default auto deletion is on.
* @return true if auto deletion is on, false otherwise
*/
bool autoDelete() const;
/**
* Enables or disabled auto deletion.
* Auto deletion causes the KRun instance to delete itself
* when it finished its task. If you allocate the KRun
* object on the stack you must disable auto deletion.
* By default auto deletion is on.
* @param b true to enable auto deletion, false to disable
*/
void setAutoDelete(bool b);
/**
* Set the preferred service for opening this URL, after
* its mimetype will have been found by KRun. IMPORTANT: the service is
* only used if its configuration says it can handle this mimetype.
* This is used for instance for the X-KDE-LastOpenedWith key, for
* the recent documents list.
* @param desktopEntryName the desktopEntryName of the service, e.g. "kate".
*/
void setPreferredService( const QString& desktopEntryName );
/**
* Sets whether executables, .desktop files or shell scripts should
* be run by KRun. This is enabled by default.
* @param b whether to run executable files or not.
* @see isExecutable()
*/
void setRunExecutables(bool b);
/**
* Sets whether the external webbrowser setting should be honoured.
* This is enabled by default.
* This should only be disabled in webbrowser applications.
* @param b whether to enable the external browser or not.
*/
void setEnableExternalBrowser(bool b);
/**
* Sets the file name to use in the case of downloading the file to a tempfile
* in order to give to a non-url-aware application. Some apps rely on the extension
* to determine the mimetype of the file. Usually the file name comes from the URL,
* but in the case of the HTTP Content-Disposition header, we need to override the
* file name.
*/
void setSuggestedFileName( const QString& fileName );
/**
* Suggested file name given by the server (e.g. HTTP content-disposition)
*/
QString suggestedFileName() const;
/**
* Open a list of URLs with a certain service (application).
*
* @param service the service to run
* @param urls the list of URLs, can be empty (app launched
* without argument)
* @param window The top-level widget of the app that invoked this object.
* @param tempFiles if true and urls are local files, they will be deleted
* when the application exits.
* @param suggestedFileName see setSuggestedFileName
* @param asn Application startup notification id, if any (otherwise "").
* @return @c true on success, @c false on error
*/
static bool run( const KService& service, const KUrl::List& urls, QWidget* window,
bool tempFiles = false, const QString& suggestedFileName = QString(), const QByteArray& asn = "" );
/**
* Open a list of URLs with.
*
* @param exec the name of the executable, for example
* "/usr/bin/netscape".
* @param urls the list of URLs to open, can be empty (app launched without argument)
* @param window The top-level widget of the app that invoked this object.
* @param name the logical name of the application, for example
* "Netscape 4.06".
* @param icon the icon which should be used by the application.
* @param asn Application startup notification id, if any (otherwise "").
* @return @c true on success, @c false on error
*/
static bool run( const QString& exec, const KUrl::List& urls, QWidget* window,
const QString& name = QString(),
const QString& icon = QString(),
const QByteArray& asn = "" );
/**
* Open the given URL.
*
* This function is used after the mime type
* is found out. It will search for all services which can handle
* the mime type and call run() afterwards.
* @param url the URL to open
* @param mimetype the mime type of the resource
* @param window The top-level widget of the app that invoked this object.
* @param tempFile if true and url is a local file, it will be deleted
* when the launched application exits.
* @param runExecutables if false then local .desktop files,
* executables and shell scripts will not be run.
* See also isExecutable().
* @param suggestedFileName see setSuggestedFileName
* @param asn Application startup notification id, if any (otherwise "").
* @return @c true on success, @c false on error
*/
static bool runUrl( const KUrl& url, const QString& mimetype, QWidget* window,
bool tempFile = false , bool runExecutables = true, const QString& suggestedFileName = QString(), const QByteArray& asn = "" );
/**
* Run the given shell command and notifies kicker of the starting
* of the application. If the program to be called doesn't exist,
* an error box will be displayed.
*
* Use only when you know the full command line. Otherwise use the other
* static methods, or KRun's constructor.
*
* @p cmd must be a shell command. You must not append "&"
* to it, since the function will do that for you.
* @param window The top-level widget of the app that invoked this object.
*
* @return @c true on success, @c false on error
*/
static bool runCommand( const QString &cmd, QWidget* window );
/**
* Same as the other runCommand(), but it also takes the name of the
* binary, to display an error message in case it couldn't find it.
*
* @param cmd must be a shell command. You must not append "&"
* to it, since the function will do that for you.
* @param execName the name of the executable
* @param icon icon for app starting notification
* @param window The top-level widget of the app that invoked this object.
* @param asn Application startup notification id, if any (otherwise "").
* @return @c true on success, @c false on error
*/
static bool runCommand( const QString& cmd, const QString & execName, const QString & icon, QWidget* window, const QByteArray& asn = "" );
/**
* Display the Open-With dialog for those URLs, and run the chosen application.
* @param lst the list of applications to run
* @param window The top-level widget of the app that invoked this object.
* @param tempFiles if true and lst are local files, they will be deleted
* when the application exits.
* @param suggestedFileName see setSuggestedFileName
* @param asn Application startup notification id, if any (otherwise "").
* @return false if the dialog was canceled
*/
static bool displayOpenWithDialog( const KUrl::List& lst, QWidget* window,
bool tempFiles = false, const QString& suggestedFileName = QString(), const QByteArray& asn = "" );
/**
* Quotes a string for the shell.
* An empty string will @em not be quoted.
*
* @deprecated Use KShell::quoteArg() instead. @em Note that this function
* behaves differently for empty arguments and returns the result
* differently.
*
* @param str the string to quote. The quoted string will be written here
*/
static KDE_DEPRECATED void shellQuote( QString &str );
/**
* Processes a Exec= line as found in .desktop files.
* @param _service the service to extract information from.
* @param _urls The urls the service should open.
* @param tempFiles if true and urls are local files, they will be deleted
* when the application exits.
* @param suggestedFileName see setSuggestedFileName
*
* @return a list of arguments suitable for KProcess::setProgram().
*/
static QStringList processDesktopExec(const KService &_service, const KUrl::List &_urls, bool tempFiles = false, const QString& suggestedFileName = QString() );
/**
* Given a full command line (e.g. the Exec= line from a .desktop file),
* extract the name of the binary being run.
* @param execLine the full command line
* @param removePath if true, remove a (relative or absolute) path. E.g. /usr/bin/ls becomes ls.
* @return the name of the binary to run
*/
static QString binaryName( const QString & execLine, bool removePath );
/**
* Returns whether @p serviceType refers to an executable program instead
* of a data file.
*/
static bool isExecutable( const QString& serviceType );
/**
* Returns whether the @p url of @p mimetype is executable.
* To be executable the file must pass the following rules:
* -# Must reside on the local filesystem.
* -# Must be marked as executable for the user by the filesystem.
* -# The mime type must inherit application/x-executable or application/x-executable-script.
* To allow a script to run when the above rules are satisfied add the entry
* @code
* X-KDE-IsAlso=application/x-executable-script
* @endcode
* to the mimetype's desktop file.
*/
static bool isExecutableFile( const KUrl& url, const QString &mimetype );
/**
* @internal
*/
static bool checkStartupNotify( const QString& binName, const KService* service, bool* silent_arg, QByteArray* wmclass_arg );
Q_SIGNALS:
/**
* Emitted when the operation finished.
* @see hasFinished()
*/
void finished();
/**
* Emitted when the operation had an error.
* @see hasError()
*/
void error();
protected Q_SLOTS:
/**
* All following protected slots are used by subclasses of KRun!
*/
/**
* This slot is called whenever the internal time has
* a timeout.
*/
void slotTimeout();
/**
* This slot is called when the scan job is finished.
*/
void slotScanFinished( KJob * );
/**
* This slot is called when the scan job has found out
* the mime type.
*/
void slotScanMimeType( KIO::Job *, const QString &type );
+ /**
+ * Call this from subclasses when you have determined the mimetype.
+ * It will call foundMimeType, but also sets up protection against deletion during message boxes.
+ * @since 4.0.2
+ */
+ void mimeTypeDetermined(const QString& mimeType);
+
/**
* This slot is called when the 'stat' job has finished.
*/
virtual void slotStatResult( KJob * );
protected:
/**
* All following protected methods are used by subclasses of KRun!
*/
/**
* Initializes the krun object.
*/
virtual void init();
/**
* Start scanning a file.
*/
virtual void scanFile();
/**
- * Called if the mimetype has been detected. The function checks
- * whether the document and appends the gzip protocol to the
- * URL. Otherwise runUrl is called to finish the job.
+ * Called if the mimetype has been detected. The function runs
+ * the application associated with this mimetype.
+ * Reimplement this method to implement a different behavior,
+ * like opening the component for displaying the URL embedded.
*/
virtual void foundMimeType( const QString& type );
/**
* Kills the file scanning job.
*/
virtual void killJob();
/**
* Sets the url.
*/
void setUrl( const KUrl &url );
/**
* Returns the url.
*/
KUrl url() const;
/**
* Sets whether an error has occured.
*/
void setError( bool error );
/**
* Sets whether progress information shall be shown.
*/
void setProgressInfo( bool progressInfo );
/**
* Returns whether progress information are shown.
*/
bool progressInfo() const;
/**
- * Marks the job as finished.
+ * Marks this 'KRun' instance as finished.
*/
void setFinished( bool finished );
/**
* Sets the job.
*/
void setJob( KIO::Job *job );
/**
* Returns the job.
*/
KIO::Job* job();
/**
* Returns the timer object.
*/
QTimer& timer();
/**
- * Sets whether the file shall be scanned.
+ * Indicate that the next action is to scan the file.
+ * @deprecated not useful in public API
*/
- void setDoScanFile( bool scanFile );
+ KDE_DEPRECATED void setDoScanFile( bool scanFile );
/**
* Returns whether the file shall be scanned.
+ * @deprecated not useful in public API
*/
- bool doScanFile() const;
+ KDE_DEPRECATED bool doScanFile() const;
/**
* Sets whether it is a directory.
+ * @deprecated typo in the name, and not useful as a public method
*/
- void setIsDirecory( bool isDirectory );
+ KDE_DEPRECATED void setIsDirecory( bool isDirectory );
/**
* Returns whether it is a directory.
*/
bool isDirectory() const;
/**
- * Returns whether the next action shall be initialized.
+ * @deprecated not useful in public API
*/
- void setInitializeNextAction( bool initialize );
+ KDE_DEPRECATED void setInitializeNextAction( bool initialize );
/**
- * Returns whether the next action shall be initialized.
+ * @deprecated not useful in public API
*/
- bool initializeNextAction() const;
+ KDE_DEPRECATED bool initializeNextAction() const;
/**
* Sets whether it is a local file.
*/
void setIsLocalFile( bool isLocalFile );
/**
* Returns whether it is a local file.
*/
bool isLocalFile() const;
/**
* Sets the file mode.
*/
void setMode( mode_t mode );
/**
* Returns the file mode.
*/
mode_t mode() const;
private:
class KRunPrivate;
KRunPrivate* const d;
};
#endif
diff --git a/kparts/browserrun.cpp b/kparts/browserrun.cpp
index 3b3f682e61..a3f545ffd5 100644
--- a/kparts/browserrun.cpp
+++ b/kparts/browserrun.cpp
@@ -1,541 +1,541 @@
/* This file is part of the KDE project
*
* Copyright (C) 2002 David Faure
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License version 2, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "browserrun.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace KParts;
class BrowserRun::BrowserRunPrivate
{
public:
bool m_bHideErrorDialog;
bool m_bRemoveReferrer;
bool m_bTrustedSource;
KParts::OpenUrlArguments m_args;
KParts::BrowserArguments m_browserArgs;
KParts::ReadOnlyPart *m_part; // QGuardedPtr?
QPointer m_window;
QString m_mimeType;
QString m_contentDisposition;
};
BrowserRun::BrowserRun( const KUrl& url, const KParts::OpenUrlArguments& args,
const KParts::BrowserArguments& browserArgs,
KParts::ReadOnlyPart *part, QWidget* window,
bool removeReferrer, bool trustedSource, bool hideErrorDialog )
: KRun( url, window, 0 /*mode*/, false /*is_local_file known*/, false /* no GUI */ ),
d(new BrowserRunPrivate)
{
d->m_bHideErrorDialog = hideErrorDialog;
d->m_bRemoveReferrer = removeReferrer;
d->m_bTrustedSource = trustedSource;
d->m_args = args;
d->m_browserArgs = browserArgs;
d->m_part = part;
d->m_window = window;
}
BrowserRun::~BrowserRun()
{
delete d;
}
KParts::ReadOnlyPart* BrowserRun::part() const
{
return d->m_part;
}
KUrl BrowserRun::url() const
{
return KRun::url();
}
void BrowserRun::init()
{
if ( d->m_bHideErrorDialog )
{
// ### KRun doesn't call a virtual method when it finds out that the URL
// is either malformed, or points to a non-existing local file...
// So we need to reimplement some of the checks, to handle d->m_bHideErrorDialog
if ( !KRun::url().isValid() ) {
redirectToError( KIO::ERR_MALFORMED_URL, KRun::url().url() );
return;
}
if ( !isLocalFile() && !hasError() && KRun::url().isLocalFile() )
setIsLocalFile( true );
if ( isLocalFile() ) {
struct stat buff;
if ( stat( QFile::encodeName(KRun::url().toLocalFile()), &buff ) == -1 )
{
kDebug(1000) << "BrowserRun::init:" << KRun::url().toLocalFile() << "doesn't exist.";
redirectToError( KIO::ERR_DOES_NOT_EXIST, KRun::url().toLocalFile() );
return;
}
setMode( buff.st_mode ); // while we're at it, save it for KRun::init() to use it
}
}
KRun::init();
}
void BrowserRun::scanFile()
{
kDebug(1000) << "BrowserRun::scanfile" << KRun::url();
// Let's check for well-known extensions
// Not when there is a query in the URL, in any case.
// Optimization for http/https, findByURL doesn't trust extensions over http.
if ( KRun::url().query().isEmpty() && !KRun::url().protocol().startsWith("http") )
{
KMimeType::Ptr mime = KMimeType::findByUrl( KRun::url() );
assert( mime );
if ( mime->name() != "application/octet-stream" || isLocalFile() )
{
kDebug(1000) << "Scanfile: MIME TYPE is" << mime->name();
- foundMimeType( mime->name() );
+ mimeTypeDetermined( mime->name() );
return;
}
}
QMap& metaData = d->m_args.metaData();
if ( d->m_part ) {
const QString proto = d->m_part->url().protocol().toLower();
if (proto == "https" || proto == "webdavs") {
metaData.insert("main_frame_request", "TRUE" );
metaData.insert("ssl_was_in_use", "TRUE" );
metaData.insert("ssl_activate_warnings", "TRUE" );
} else if (proto == "http" || proto == "webdav") {
metaData.insert("ssl_activate_warnings", "TRUE" );
metaData.insert("ssl_was_in_use", "FALSE" );
}
// Set the PropagateHttpHeader meta-data if it has not already been set...
if (!metaData.contains("PropagateHttpHeader"))
metaData.insert("PropagateHttpHeader", "TRUE");
}
KIO::TransferJob *job;
if ( d->m_browserArgs.doPost() && KRun::url().protocol().startsWith("http")) {
job = KIO::http_post( KRun::url(), d->m_browserArgs.postData, KIO::HideProgressInfo );
job->addMetaData( "content-type", d->m_browserArgs.contentType() );
} else {
job = KIO::get(KRun::url(),
- d->m_args.reload() ? KIO::Reload : KIO::NoReload,
+ d->m_args.reload() ? KIO::Reload : KIO::NoReload,
KIO::HideProgressInfo);
}
if ( d->m_bRemoveReferrer )
metaData.remove("referrer");
job->addMetaData( metaData );
job->ui()->setWindow( d->m_window );
connect( job, SIGNAL( result( KJob *)),
this, SLOT( slotBrowserScanFinished(KJob *)));
connect( job, SIGNAL( mimetype( KIO::Job *, const QString &)),
this, SLOT( slotBrowserMimetype(KIO::Job *, const QString &)));
setJob( job );
}
void BrowserRun::slotBrowserScanFinished(KJob *job)
{
kDebug(1000) << "BrowserRun::slotBrowserScanFinished";
if ( job->error() == KIO::ERR_IS_DIRECTORY )
{
// It is in fact a directory. This happens when HTTP redirects to FTP.
// Due to the "protocol doesn't support listing" code in BrowserRun, we
// assumed it was a file.
kDebug(1000) << "It is in fact a directory!";
// Update our URL in case of a redirection
KRun::setUrl( static_cast(job)->url() );
setJob( 0 );
- foundMimeType( "inode/directory" );
+ mimeTypeDetermined( "inode/directory" );
}
else
{
if ( job->error() )
handleError( job );
else
KRun::slotScanFinished(job);
}
}
void BrowserRun::slotBrowserMimetype( KIO::Job *_job, const QString &type )
{
Q_ASSERT( _job == KRun::job() );
KIO::TransferJob *job = static_cast(KRun::job());
// Update our URL in case of a redirection
//kDebug(1000) << "old URL=" << KRun::url();
//kDebug(1000) << "new URL=" << job->url();
setUrl( job->url() );
kDebug(1000) << "slotBrowserMimetype: found" << type << "for" << KRun::url();
// Suggested filename given by the server (e.g. HTTP content-disposition)
// When set, we should really be saving instead of embedding
const QString suggestedFileName = job->queryMetaData("content-disposition-filename");
setSuggestedFileName(suggestedFileName); // store it (in KRun)
//kDebug(1000) << "suggestedFileName=" << suggestedFileName;
d->m_contentDisposition = job->queryMetaData("content-disposition-type");
// Make a copy to avoid a dead reference
QString _type = type;
job->putOnHold();
setJob( 0 );
- foundMimeType( _type );
+ mimeTypeDetermined( _type );
}
BrowserRun::NonEmbeddableResult BrowserRun::handleNonEmbeddable( const QString& _mimeType )
{
QString mimeType( _mimeType );
Q_ASSERT( !hasFinished() ); // only come here if the mimetype couldn't be embedded
// Support for saving remote files.
if ( mimeType != "inode/directory" && // dirs can't be saved
!KRun::url().isLocalFile() )
{
if ( isTextExecutable(mimeType) )
mimeType = QLatin1String("text/plain"); // view, don't execute
kDebug(1000) << "BrowserRun: ask for saving";
KService::Ptr offer = KMimeTypeTrader::self()->preferredService(mimeType, "Application");
// ... -> ask whether to save
KParts::BrowserRun::AskSaveResult res = askSave( KRun::url(), offer, mimeType, suggestedFileName() );
if ( res == KParts::BrowserRun::Save ) {
save( KRun::url(), suggestedFileName() );
kDebug(1000) << "BrowserRun::handleNonEmbeddable: Save: returning Handled";
setFinished( true );
return Handled;
}
else if ( res == KParts::BrowserRun::Cancel ) {
// saving done or canceled
kDebug(1000) << "BrowserRun::handleNonEmbeddable: Cancel: returning Handled";
setFinished( true );
return Handled;
}
else // "Open" chosen (done by KRun::foundMimeType, called when returning NotHandled)
{
// If we were in a POST, we can't just pass a URL to an external application.
// We must save the data to a tempfile first.
if ( d->m_browserArgs.doPost() )
{
kDebug(1000) << "BrowserRun: request comes from a POST, can't pass a URL to another app, need to save";
d->m_mimeType = mimeType;
QString extension;
QString fileName = suggestedFileName().isEmpty() ? KRun::url().fileName() : suggestedFileName();
int extensionPos = fileName.lastIndexOf( '.' );
if ( extensionPos != -1 )
extension = fileName.mid( extensionPos ); // keep the '.'
KTemporaryFile tempFile;
tempFile.setSuffix(extension);
tempFile.setAutoRemove(false);
tempFile.open();
KUrl destURL;
destURL.setPath( tempFile.fileName() );
KIO::Job *job = KIO::file_copy( KRun::url(), destURL, 0600, KIO::Overwrite );
job->ui()->setWindow(d->m_window);
connect( job, SIGNAL(result(KJob *)),
this, SLOT(slotCopyToTempFileResult(KJob *)) );
return Delayed; // We'll continue after the job has finished
}
}
}
// Check if running is allowed
if ( !d->m_bTrustedSource && // ... and untrusted source...
!allowExecution( mimeType, KRun::url() ) ) // ...and the user said no (for executables etc.)
{
setFinished( true );
return Handled;
}
KIO::SimpleJob::removeOnHold(); // Kill any slave that was put on hold.
return NotHandled;
}
//static
bool BrowserRun::allowExecution( const QString &mimeType, const KUrl &url )
{
if ( !KRun::isExecutable( mimeType ) )
return true;
if ( !url.isLocalFile() ) // Don't permit to execute remote files
return false;
return ( KMessageBox::warningContinueCancel( 0,
i18n( "Do you really want to execute '%1'?", url.prettyUrl() ),
i18n("Execute File?"), KGuiItem(i18n("Execute")) ) == KMessageBox::Continue );
}
static QString makeQuestion( const KUrl& url, const QString& mimeType, const QString& suggestedFileName )
{
QString surl = KStringHandler::csqueeze( url.prettyUrl() );
KMimeType::Ptr mime = KMimeType::mimeType( mimeType );
QString comment = mimeType;
// Test if the mimeType is not recognize as octet-stream.
// If so then keep mime-type as comment
if (mime && mime->name() != KMimeType::defaultMimeType()) {
// The mime-type is known so display the comment instead of mime-type
comment = mime->comment();
}
// The strange order in the i18n() calls below is due to the possibility
// of surl containing a '%'
if ( suggestedFileName.isEmpty() )
return i18n("Open '%2'?\nType: %1", comment, surl);
else
return i18n("Open '%3'?\nName: %2\nType: %1", comment, suggestedFileName, surl);
}
//static
// TODO should take a QWidget* parent argument
BrowserRun::AskSaveResult BrowserRun::askSave( const KUrl & url, KService::Ptr offer, const QString& mimeType, const QString & suggestedFileName )
{
// SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC
// NOTE: Keep this function in sync with kdebase/kcontrol/filetypes/filetypedetails.cpp
// FileTypeDetails::updateAskSave()
QString question = makeQuestion( url, mimeType, suggestedFileName );
// Text used for the open button
QString openText = (offer && !offer->name().isEmpty())
? i18n("&Open with '%1'", offer->name())
: i18n("&Open With...");
int choice = KMessageBox::questionYesNoCancel(
0, question, url.host(),
KStandardGuiItem::saveAs(), KGuiItem(openText), KStandardGuiItem::cancel(),
QLatin1String("askSave")+ mimeType ); // dontAskAgainName, KEEP IN SYNC!!!
return choice == KMessageBox::Yes ? Save : ( choice == KMessageBox::No ? Open : Cancel );
// SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC
}
//static
// TODO should take a QWidget* parent argument
BrowserRun::AskSaveResult BrowserRun::askEmbedOrSave( const KUrl & url, const QString& mimeType, const QString & suggestedFileName, int flags )
{
// SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC
// NOTE: Keep this function in sync with kdebase/kcontrol/filetypes/filetypedetails.cpp
// FileTypeDetails::updateAskSave()
KMimeType::Ptr mime = KMimeType::mimeType( mimeType );
// Don't ask for:
// - html (even new tabs would ask, due to about:blank!)
// - dirs obviously (though not common over HTTP :),
// - images (reasoning: no need to save, most of the time, because fast to see)
// e.g. postscript is different, because takes longer to read, so
// it's more likely that the user might want to save it.
// - multipart/* ("server push", see kmultipart)
// - other strange 'internal' mimetypes like print/manager...
// KEEP IN SYNC!!!
if (flags != (int)AttachmentDisposition && (
mime->is( "text/html" ) ||
mime->is( "application/xml" ) ||
mime->is( "inode/directory" ) ||
mimeType.startsWith( "image" ) ||
mime->is( "multipart/x-mixed-replace" ) ||
mime->is( "multipart/replace" ) ||
mimeType.startsWith( "print" ) ) )
return Open;
QString question = makeQuestion( url, mimeType, suggestedFileName );
// don't use KStandardGuiItem::open() here which has trailing ellipsis!
int choice = KMessageBox::questionYesNoCancel(
0, question, url.host(),
KStandardGuiItem::saveAs(), KGuiItem( i18n( "&Open" ), "document-open"), KStandardGuiItem::cancel(),
QLatin1String("askEmbedOrSave")+ mimeType ); // dontAskAgainName, KEEP IN SYNC!!!
return choice == KMessageBox::Yes ? Save : ( choice == KMessageBox::No ? Open : Cancel );
// SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC
}
// Default implementation, overridden in KHTMLRun
void BrowserRun::save( const KUrl & url, const QString & suggestedFileName )
{
simpleSave( url, suggestedFileName, d->m_window );
}
void BrowserRun::simpleSave( const KUrl & url, const QString & suggestedFileName,
QWidget* window )
{
// DownloadManager <-> konqueror integration
// find if the integration is enabled
// the empty key means no integration
// only use the downloadmanager for non-local urls
if ( !url.isLocalFile() )
{
KConfigGroup cfg = KSharedConfig::openConfig("konquerorrc", KConfig::NoGlobals)->group("HTML Settings");
QString downloadManger = cfg.readPathEntry("DownloadManager", QString());
if (!downloadManger.isEmpty())
{
// then find the download manager location
kDebug(1000) << "Using: "<setOperationMode( KFileDialog::Saving );
dlg->setCaption(i18n("Save As"));
dlg->setSelection( suggestedFileName.isEmpty() ? url.fileName() : suggestedFileName );
if ( dlg->exec() )
{
KUrl destURL( dlg->selectedUrl() );
if ( destURL.isValid() )
{
KIO::Job *job = KIO::copy( url, destURL );
job->ui()->setWindow (window);
job->ui()->setAutoErrorHandlingEnabled( true );
}
}
delete dlg;
}
void BrowserRun::slotStatResult( KJob *job )
{
if ( job->error() ) {
kDebug(1000) << "BrowserRun::slotStatResult:" << job->errorString();
handleError( job );
} else
KRun::slotStatResult( job );
}
void BrowserRun::handleError( KJob * job )
{
if ( !job ) { // Shouldn't happen, see docu.
kWarning(1000) << "BrowserRun::handleError called with job=0! hideErrorDialog=" << d->m_bHideErrorDialog;
return;
}
if (d->m_bHideErrorDialog && job->error() != KIO::ERR_NO_CONTENT)
{
redirectToError( job->error(), job->errorText() );
return;
}
// Reuse code in KRun, to benefit from d->m_showingError etc.
KRun::slotStatResult( job );
}
void BrowserRun::redirectToError( int error, const QString& errorText )
{
/**
* To display this error in KHTMLPart instead of inside a dialog box,
* we tell konq that the mimetype is text/html, and we redirect to
* an error:/ URL that sends the info to khtml.
*
* The format of the error:/ URL is error:/?query#url,
* where two variables are passed in the query:
* error = int kio error code, errText = QString error text from kio
* The sub-url is the URL that we were trying to open.
*/
KUrl newURL(QString("error:/?error=%1&errText=%2")
.arg( error )
.arg( QString::fromUtf8( QUrl::toPercentEncoding( errorText ) ) ) );
KUrl runURL = KRun::url();
runURL.setPass( QString() ); // don't put the password in the error URL
KUrl::List lst;
lst << newURL << runURL;
KRun::setUrl( KUrl::join( lst ) );
//kDebug(1202) << "BrowserRun::handleError KRun::url()=" << ;
setJob( 0 );
- foundMimeType( "text/html" );
+ mimeTypeDetermined( "text/html" );
}
void BrowserRun::slotCopyToTempFileResult(KJob *job)
{
if ( job->error() ) {
job->uiDelegate()->showErrorMessage();
} else {
// Same as KRun::foundMimeType but with a different URL
(void) (KRun::runUrl( static_cast(job)->destUrl(), d->m_mimeType, d->m_window ));
}
setError( true ); // see above
setFinished( true );
timer().start( 0 );
}
bool BrowserRun::isTextExecutable( const QString &mimeType )
{
return ( mimeType == "application/x-desktop" ||
mimeType == "application/x-shellscript" );
}
bool BrowserRun::hideErrorDialog() const
{
return d->m_bHideErrorDialog;
}
QString BrowserRun::contentDisposition() const {
return d->m_contentDisposition;
}
KParts::OpenUrlArguments& KParts::BrowserRun::arguments()
{
return d->m_args;
}
KParts::BrowserArguments& KParts::BrowserRun::browserArguments()
{
return d->m_browserArgs;
}
#include "browserrun.moc"