1 /* This file is part of the KDE project
2 Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3 Copyright (C) 2000-2005 David Faure <faure@kde.org>
4 Copyright (C) 2001 Waldo Bastian <bastian@kde.org>
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
22 #include <QtCore/QFile>
23 #include <QtCore/Q_PID>
25 #include <kapplication.h>
26 #include <kdeversion.h>
27 #include <kstandarddirs.h>
29 #include <kmessagebox.h>
32 #include <kio/netaccess.h>
35 #include <kcmdlineargs.h>
36 #include <kaboutdata.h>
37 #include <kstartupinfo.h>
45 static const char description
[] =
46 I18N_NOOP("KIO Exec - Opens remote files, watches modifications, asks for upload");
52 KCmdLineArgs
*args
= KCmdLineArgs::parsedArgs();
53 if (args
->count() < 1)
54 KCmdLineArgs::usageError(i18n("'command' expected.\n"));
56 tempfiles
= args
->isSet("tempfiles");
57 if ( args
->isSet( "suggestedfilename" ) )
58 suggestedFileName
= args
->getOption( "suggestedfilename" );
61 command
= args
->arg(0);
62 kDebug() << "command=" << command
;
64 for ( int i
= 1; i
< args
->count(); i
++ )
66 KUrl url
= args
->url(i
);
67 url
= KIO::NetAccess::mostLocalUrl( url
, 0 );
69 //kDebug() << "url=" << url.url() << " filename=" << url.fileName();
70 // A local file, not an URL ?
71 // => It is not encoded and not shell escaped, too.
72 if ( url
.isLocalFile() )
75 file
.path
= url
.path();
77 fileList
.append(file
);
83 KMessageBox::error( 0L, i18n( "The URL %1\nis malformed" , url
.url() ) );
85 KMessageBox::error( 0L, i18n( "Remote URL %1\nnot allowed with --tempfiles switch" , url
.url() ) );
87 // We must fetch the file
89 QString fileName
= KIO::encodeFileName( url
.fileName() );
90 if ( !suggestedFileName
.isEmpty() )
91 fileName
= suggestedFileName
;
92 // Build the destination filename, in ~/.kde/cache-*/krun/
93 // Unlike KDE-1.1, we put the filename at the end so that the extension is kept
94 // (Some programs rely on it)
95 QString tmp
= KGlobal::dirs()->saveLocation( "cache", "krun/" ) +
96 QString("%1.%2.%3").arg(getpid()).arg(jobCounter
++).arg(fileName
);
100 fileList
.append(file
);
105 kDebug() << "Copying " << url
.prettyUrl() << " to " << dest
;
106 KIO::Job
*job
= KIO::file_copy( url
, dest
);
107 jobList
.append( job
);
109 connect( job
, SIGNAL( result( KJob
* ) ), SLOT( slotResult( KJob
* ) ) );
122 if ( counter
== expectedCounter
)
126 void KIOExec::slotResult( KJob
* job
)
128 if (job
&& job
->error())
130 // That error dialog would be queued, i.e. not immediate...
131 //job->showErrorDialog();
132 if ( (job
->error() != KIO::ERR_USER_CANCELED
) )
133 KMessageBox::error( 0L, job
->errorString() );
135 QString path
= static_cast<KIO::FileCopyJob
*>(job
)->destUrl().path();
137 QList
<FileInfo
>::Iterator it
= fileList
.begin();
138 for(;it
!= fileList
.end(); ++it
)
140 if ((*it
).path
== path
)
144 if ( it
!= fileList
.end() )
145 fileList
.erase( it
);
147 kDebug() << path
<< " not found in list";
152 if ( counter
< expectedCounter
)
155 kDebug() << "All files downloaded, will call slotRunApp shortly";
156 // We know we can run the app now - but let's finish the job properly first.
157 QTimer::singleShot( 0, this, SLOT( slotRunApp() ) );
162 void KIOExec::slotRunApp()
164 if ( fileList
.isEmpty() ) {
165 kDebug() << "No files downloaded -> exiting";
167 QApplication::exit(1);
171 KService
service("dummy", command
, QString());
174 // Store modification times
175 QList
<FileInfo
>::Iterator it
= fileList
.begin();
176 for ( ; it
!= fileList
.end() ; ++it
)
178 KDE_struct_stat buff
;
179 (*it
).time
= KDE_stat( QFile::encodeName((*it
).path
), &buff
) ? 0 : buff
.st_mtime
;
181 url
.setPath((*it
).path
);
185 QStringList params
= KRun::processDesktopExec(service
, list
);
187 kDebug() << "EXEC " << KShell::joinArgs( params
);
190 // propagate the startup identification to the started process
192 id
.initId( kapp
->startupId());
193 id
.setupStartupEnv();
196 QString
exe( params
.takeFirst() );
197 const int exit_code
= QProcess::execute( exe
, params
);
200 KStartupInfo::resetStartupEnv();
203 kDebug() << "EXEC done";
205 // Test whether one of the files changed
206 it
= fileList
.begin();
207 for( ;it
!= fileList
.end(); ++it
)
209 KDE_struct_stat buff
;
210 QString src
= (*it
).path
;
211 KUrl dest
= (*it
).url
;
212 if ( (KDE_stat( QFile::encodeName(src
), &buff
) == 0) &&
213 ((*it
).time
!= buff
.st_mtime
) )
217 if ( KMessageBox::questionYesNo( 0L,
218 i18n( "The supposedly temporary file\n%1\nhas been modified.\nDo you still want to delete it?" , dest
.prettyUrl()),
219 i18n( "File Changed" ), KStandardGuiItem::del(), KGuiItem(i18n("Do Not Delete")) ) != KMessageBox::Yes
)
220 continue; // don't delete the temp file
222 else if ( ! dest
.isLocalFile() ) // no upload when it's already a local file
224 if ( KMessageBox::questionYesNo( 0L,
225 i18n( "The file\n%1\nhas been modified.\nDo you want to upload the changes?" , dest
.prettyUrl()),
226 i18n( "File Changed" ), KGuiItem(i18n("Upload")), KGuiItem(i18n("Do Not Upload")) ) == KMessageBox::Yes
)
228 kDebug() << "src='" << src
<< "' dest='" << dest
<< "'";
229 // Do it the synchronous way.
230 if ( !KIO::NetAccess::upload( src
, dest
, 0 ) )
232 KMessageBox::error( 0L, KIO::NetAccess::lastErrorString() );
233 continue; // don't delete the temp file
239 if ((!dest
.isLocalFile() || tempfiles
) && exit_code
== 0) {
240 // Wait for a reasonable time so that even if the application forks on startup (like OOo or amarok)
241 // it will have time to start up and read the file before it gets deleted. #130709.
242 kDebug() << "sleeping...";
244 kDebug() << "about to delete " << src
;
245 unlink( QFile::encodeName(src
) );
250 QApplication::exit(exit_code
);
253 int main( int argc
, char **argv
)
255 KAboutData
aboutData( "kioexec", "kioexec", ki18n("KIOExec"),
256 KDE_VERSION_STRING
, ki18n(description
), KAboutData::License_GPL
,
257 ki18n("(c) 1998-2000,2003 The KFM/Konqueror Developers"));
258 aboutData
.addAuthor(ki18n("David Faure"),KLocalizedString(), "faure@kde.org");
259 aboutData
.addAuthor(ki18n("Stephan Kulow"),KLocalizedString(), "coolo@kde.org");
260 aboutData
.addAuthor(ki18n("Bernhard Rosenkraenzer"),KLocalizedString(), "bero@arklinux.org");
261 aboutData
.addAuthor(ki18n("Waldo Bastian"),KLocalizedString(), "bastian@kde.org");
262 aboutData
.addAuthor(ki18n("Oswald Buddenhagen"),KLocalizedString(), "ossi@kde.org");
264 KCmdLineArgs::init( argc
, argv
, &aboutData
);
266 KCmdLineOptions options
;
267 options
.add("tempfiles", ki18n("Treat URLs as local files and delete them afterwards"));
268 options
.add("suggestedfilename <file name>", ki18n("Suggested file name for the downloaded file"));
269 options
.add("+command", ki18n("Command to execute"));
270 options
.add("+[URLs]", ki18n("URL(s) or local file(s) used for 'command'"));
271 KCmdLineArgs::addCmdLineOptions( options
);
274 app
.setQuitOnLastWindowClosed(false);
278 // Don't go into the event loop if we already want to exit (#172197)