main.cpp
00001 /* This file is part of the KDE project 00002 Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> 00003 Copyright (C) 2000 David Faure <faure@kde.org> 00004 Copyright (C) 2001 Waldo Bastian <bastian@kde.org> 00005 00006 This program is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU General Public 00008 License as published by the Free Software Foundation; either 00009 version 2 of the License, or (at your option) any later version. 00010 00011 This program is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with this program; see the file COPYING. If not, write to 00018 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00019 Boston, MA 02110-1301, USA. 00020 */ 00021 00022 #include <config.h> 00023 #include <unistd.h> 00024 #include <stdlib.h> 00025 #include <sys/stat.h> 00026 00027 #include <tqfile.h> 00028 00029 #include <kapplication.h> 00030 #include <kstandarddirs.h> 00031 #include <kdebug.h> 00032 #include <kmessagebox.h> 00033 #include <kio/job.h> 00034 #include <krun.h> 00035 #include <kio/netaccess.h> 00036 #include <kprocess.h> 00037 #include <kservice.h> 00038 #include <klocale.h> 00039 #include <kcmdlineargs.h> 00040 #include <kaboutdata.h> 00041 #include <kstartupinfo.h> 00042 #include <kshell.h> 00043 #include <kde_file.h> 00044 00045 00046 #include "main.h" 00047 00048 00049 static const char description[] = 00050 I18N_NOOP("KIO Exec - Opens remote files, watches modifications, asks for upload"); 00051 00052 static KCmdLineOptions options[] = 00053 { 00054 { "tempfiles", I18N_NOOP("Treat URLs as local files and delete them afterwards"), 0 }, 00055 { "suggestedfilename <file name>", I18N_NOOP("Suggested file name for the downloaded file"), 0 }, 00056 { "+command", I18N_NOOP("Command to execute"), 0 }, 00057 { "+[URLs]", I18N_NOOP("URL(s) or local file(s) used for 'command'"), 0 }, 00058 KCmdLineLastOption 00059 }; 00060 00061 00062 int jobCounter = 0; 00063 00064 TQPtrList<KIO::Job>* jobList = 0L; 00065 00066 KIOExec::KIOExec() 00067 { 00068 jobList = new TQPtrList<KIO::Job>; 00069 jobList->setAutoDelete( false ); // jobs autodelete themselves 00070 00071 KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); 00072 if (args->count() < 1) 00073 KCmdLineArgs::usage(i18n("'command' expected.\n")); 00074 00075 tempfiles = args->isSet("tempfiles"); 00076 if ( args->isSet( "suggestedfilename" ) ) 00077 suggestedFileName = TQString::fromLocal8Bit( args->getOption( "suggestedfilename" ) ); 00078 expectedCounter = 0; 00079 command = args->arg(0); 00080 kdDebug() << "command=" << command << endl; 00081 00082 for ( int i = 1; i < args->count(); i++ ) 00083 { 00084 KURL url = args->url(i); 00085 // we need to map system:/ etc to make sure we get this right 00086 url = KIO::NetAccess::mostLocalURL( url, 0 ); 00087 00088 //kdDebug() << "url=" << url.url() << " filename=" << url.fileName() << endl; 00089 // A local file, not an URL ? 00090 // => It is not encoded and not shell escaped, too. 00091 if ( url.isLocalFile() ) 00092 { 00093 fileInfo file; 00094 file.path = url.path(); 00095 file.url = url; 00096 fileList.append(file); 00097 } 00098 // It is an URL 00099 else 00100 { 00101 if ( !url.isValid() ) 00102 KMessageBox::error( 0L, i18n( "The URL %1\nis malformed" ).arg( url.url() ) ); 00103 else if ( tempfiles ) 00104 KMessageBox::error( 0L, i18n( "Remote URL %1\nnot allowed with --tempfiles switch" ).arg( url.url() ) ); 00105 else 00106 // We must fetch the file 00107 { 00108 TQString fileName = KIO::encodeFileName( url.fileName() ); 00109 if ( !suggestedFileName.isEmpty() ) 00110 fileName = suggestedFileName; 00111 // Build the destination filename, in ~/.trinity/cache-*/krun/ 00112 // Unlike KDE-1.1, we put the filename at the end so that the extension is kept 00113 // (Some programs rely on it) 00114 TQString tmp = KGlobal::dirs()->saveLocation( "cache", "krun/" ) + 00115 TQString("%1.%2.%3").arg(getpid()).arg(jobCounter++).arg(fileName); 00116 fileInfo file; 00117 file.path = tmp; 00118 file.url = url; 00119 fileList.append(file); 00120 00121 expectedCounter++; 00122 KURL dest; 00123 dest.setPath( tmp ); 00124 kdDebug() << "Copying " << url.prettyURL() << " to " << dest << endl; 00125 KIO::Job *job = KIO::file_copy( url, dest ); 00126 jobList->append( job ); 00127 00128 connect( job, TQT_SIGNAL( result( KIO::Job * ) ), TQT_SLOT( slotResult( KIO::Job * ) ) ); 00129 } 00130 } 00131 } 00132 args->clear(); 00133 00134 if ( tempfiles ) { 00135 // #113991 00136 TQTimer::singleShot( 0, this, TQT_SLOT( slotRunApp() ) ); 00137 //slotRunApp(); // does not return 00138 return; 00139 } 00140 00141 counter = 0; 00142 if ( counter == expectedCounter ) 00143 slotResult( 0L ); 00144 } 00145 00146 void KIOExec::slotResult( KIO::Job * job ) 00147 { 00148 if (job && job->error()) 00149 { 00150 // That error dialog would be queued, i.e. not immediate... 00151 //job->showErrorDialog(); 00152 if ( (job->error() != KIO::ERR_USER_CANCELED) ) 00153 KMessageBox::error( 0L, job->errorString() ); 00154 00155 TQString path = static_cast<KIO::FileCopyJob*>(job)->destURL().path(); 00156 00157 TQValueList<fileInfo>::Iterator it = fileList.begin(); 00158 for(;it != fileList.end(); ++it) 00159 { 00160 if ((*it).path == path) 00161 break; 00162 } 00163 00164 if ( it != fileList.end() ) 00165 fileList.remove( it ); 00166 else 00167 kdDebug() << static_cast<KIO::FileCopyJob*>(job)->destURL().path() << " not found in list" << endl; 00168 } 00169 00170 counter++; 00171 00172 if ( counter < expectedCounter ) 00173 return; 00174 00175 kdDebug() << "All files downloaded, will call slotRunApp shortly" << endl; 00176 // We know we can run the app now - but let's finish the job properly first. 00177 TQTimer::singleShot( 0, this, TQT_SLOT( slotRunApp() ) ); 00178 00179 jobList->clear(); 00180 } 00181 00182 void KIOExec::slotRunApp() 00183 { 00184 if ( fileList.isEmpty() ) { 00185 kdDebug() << k_funcinfo << "No files downloaded -> exiting" << endl; 00186 exit(1); 00187 } 00188 00189 KService service("dummy", command, TQString::null); 00190 00191 KURL::List list; 00192 // Store modification times 00193 TQValueList<fileInfo>::Iterator it = fileList.begin(); 00194 for ( ; it != fileList.end() ; ++it ) 00195 { 00196 KDE_struct_stat buff; 00197 (*it).time = KDE_stat( TQFile::encodeName((*it).path), &buff ) ? 0 : buff.st_mtime; 00198 KURL url; 00199 url.setPath((*it).path); 00200 list << url; 00201 } 00202 00203 TQStringList params = KRun::processDesktopExec(service, list, false /*no shell*/); 00204 00205 kdDebug() << "EXEC " << KShell::joinArgs( params ) << endl; 00206 00207 #ifdef Q_WS_X11 00208 // propagate the startup indentification to the started process 00209 KStartupInfoId id; 00210 id.initId( kapp->startupId()); 00211 id.setupStartupEnv(); 00212 #endif 00213 00214 KProcess proc; 00215 proc << params; 00216 proc.start( KProcess::Block ); 00217 00218 #ifdef Q_WS_X11 00219 KStartupInfo::resetStartupEnv(); 00220 #endif 00221 00222 kdDebug() << "EXEC done" << endl; 00223 00224 // Test whether one of the files changed 00225 it = fileList.begin(); 00226 for( ;it != fileList.end(); ++it ) 00227 { 00228 KDE_struct_stat buff; 00229 TQString src = (*it).path; 00230 KURL dest = (*it).url; 00231 if ( (KDE_stat( TQFile::encodeName(src), &buff ) == 0) && 00232 ((*it).time != buff.st_mtime) ) 00233 { 00234 if ( tempfiles ) 00235 { 00236 if ( KMessageBox::questionYesNo( 0L, 00237 i18n( "The supposedly temporary file\n%1\nhas been modified.\nDo you still want to delete it?" ).arg(dest.prettyURL()), 00238 i18n( "File Changed" ), KStdGuiItem::del(), i18n("Do Not Delete") ) != KMessageBox::Yes ) 00239 continue; // don't delete the temp file 00240 } 00241 else if ( ! dest.isLocalFile() ) // no upload when it's already a local file 00242 { 00243 if ( KMessageBox::questionYesNo( 0L, 00244 i18n( "The file\n%1\nhas been modified.\nDo you want to upload the changes?" ).arg(dest.prettyURL()), 00245 i18n( "File Changed" ), i18n("Upload"), i18n("Do Not Upload") ) == KMessageBox::Yes ) 00246 { 00247 kdDebug() << TQString(TQString("src='%1' dest='%2'").arg(src).arg(dest.url())).ascii() << endl; 00248 // Do it the synchronous way. 00249 if ( !KIO::NetAccess::upload( src, dest, 0 ) ) 00250 { 00251 KMessageBox::error( 0L, KIO::NetAccess::lastErrorString() ); 00252 continue; // don't delete the temp file 00253 } 00254 } 00255 } 00256 } 00257 00258 if ( !dest.isLocalFile() || tempfiles ) { 00259 // Wait for a reasonable time so that even if the application forks on startup (like OOo or amarok) 00260 // it will have time to start up and read the file before it gets deleted. #130709. 00261 kdDebug() << "sleeping..." << endl; 00262 sleep(180); // 3 mn 00263 kdDebug() << "about to delete " << src << endl; 00264 unlink( TQFile::encodeName(src) ); 00265 } 00266 } 00267 00268 //kapp->quit(); not efficient enough 00269 exit(0); 00270 } 00271 00272 int main( int argc, char **argv ) 00273 { 00274 KAboutData aboutData( "kioexec", I18N_NOOP("KIOExec"), 00275 VERSION, description, KAboutData::License_GPL, 00276 "(c) 1998-2000,2003 The KFM/Konqueror Developers"); 00277 aboutData.addAuthor("David Faure",0, "faure@kde.org"); 00278 aboutData.addAuthor("Stephan Kulow",0, "coolo@kde.org"); 00279 aboutData.addAuthor("Bernhard Rosenkraenzer",0, "bero@arklinux.org"); 00280 aboutData.addAuthor("Waldo Bastian",0, "bastian@kde.org"); 00281 aboutData.addAuthor("Oswald Buddenhagen",0, "ossi@kde.org"); 00282 00283 KCmdLineArgs::init( argc, argv, &aboutData ); 00284 KCmdLineArgs::addCmdLineOptions( options ); 00285 00286 KApplication app; 00287 00288 KIOExec exec; 00289 00290 kdDebug() << "Constructor returned..." << endl; 00291 return app.exec(); 00292 } 00293 00294 #include "main.moc"