Contents of /branches/KDE/3.5/kdebase/konqueror/client/kfmclient.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 569345 - (show annotations) (download)
Thu Aug 3 15:42:23 2006 UTC (11 years, 5 months ago) by lunakl
File size: 24509 byte(s)
Don't access deleted memory, can even give bogus kfmclient
exit code.


1 /* This file is part of the KDE project
2 Copyright (C) 1999 David Faure <faure@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18 */
19
20 #include <errno.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <signal.h>
24 #include <unistd.h>
25
26 #include <qdir.h>
27
28 #include <kio/job.h>
29 #include <kcmdlineargs.h>
30 #include <kpropertiesdialog.h>
31 #include <klocale.h>
32 #include <ktrader.h>
33 #include <kprocess.h>
34 #include <kstandarddirs.h>
35 #include <kopenwith.h>
36 #include <kurlrequesterdlg.h>
37 #include <kmessagebox.h>
38 #include <kfiledialog.h>
39 #include <kdebug.h>
40 #include <dcopclient.h>
41 #include <kservice.h>
42 #include <qregexp.h>
43
44 #include "kfmclient.h"
45 #include "KonquerorIface_stub.h"
46 #include "KDesktopIface_stub.h"
47 #include "kwin.h"
48
49 #include <X11/Xlib.h>
50
51 static const char appName[] = "kfmclient";
52 static const char programName[] = I18N_NOOP("kfmclient");
53
54 static const char description[] = I18N_NOOP("KDE tool for opening URLs from the command line");
55
56 static const char version[] = "2.0";
57
58 QCString clientApp::startup_id_str;
59 bool clientApp::m_ok = true;
60 bool s_interactive = true;
61
62 static const KCmdLineOptions options[] =
63 {
64 { "noninteractive", I18N_NOOP("Non interactive use: no message boxes"), 0},
65 { "commands", I18N_NOOP("Show available commands"), 0},
66 { "+command", I18N_NOOP("Command (see --commands)"), 0},
67 { "+[URL(s)]", I18N_NOOP("Arguments for command"), 0},
68 KCmdLineLastOption
69 };
70
71 extern "C" KDE_EXPORT int kdemain( int argc, char **argv )
72 {
73 KCmdLineArgs::init(argc, argv, appName, programName, description, version, false);
74
75 KCmdLineArgs::addCmdLineOptions( options );
76 KCmdLineArgs::addTempFileOption();
77
78 KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
79
80 if ( args->isSet("commands") )
81 {
82 KCmdLineArgs::enable_i18n();
83 puts(i18n("\nSyntax:\n").local8Bit());
84 puts(i18n(" kfmclient openURL 'url' ['mimetype']\n"
85 " # Opens a window showing 'url'.\n"
86 " # 'url' may be a relative path\n"
87 " # or file name, such as . or subdir/\n"
88 " # If 'url' is omitted, $HOME is used instead.\n\n").local8Bit());
89 puts(i18n(" # If 'mimetype' is specified, it will be used to determine the\n"
90 " # component that Konqueror should use. For instance, set it to\n"
91 " # text/html for a web page, to make it appear faster\n\n").local8Bit());
92
93 puts(i18n(" kfmclient newTab 'url' ['mimetype']\n"
94 " # Same as above but opens a new tab with 'url' in an existing Konqueror\n"
95 " # window on the current active desktop if possible.\n\n").local8Bit());
96
97 puts(i18n(" kfmclient openProfile 'profile' ['url']\n"
98 " # Opens a window using the given profile.\n"
99 " # 'profile' is a file under ~/.kde/share/apps/konqueror/profiles.\n"
100 " # 'url' is an optional URL to open.\n\n").local8Bit());
101
102 puts(i18n(" kfmclient openProperties 'url'\n"
103 " # Opens a properties menu\n\n").local8Bit());
104 puts(i18n(" kfmclient exec ['url' ['binding']]\n"
105 " # Tries to execute 'url'. 'url' may be a usual\n"
106 " # URL, this URL will be opened. You may omit\n"
107 " # 'binding'. In this case the default binding\n").local8Bit());
108 puts(i18n(" # is tried. Of course URL may be the URL of a\n"
109 " # document, or it may be a *.desktop file.\n").local8Bit());
110 puts(i18n(" # This way you could for example mount a device\n"
111 " # by passing 'Mount default' as binding to \n"
112 " # 'cdrom.desktop'\n\n").local8Bit());
113 puts(i18n(" kfmclient move 'src' 'dest'\n"
114 " # Moves the URL 'src' to 'dest'.\n"
115 " # 'src' may be a list of URLs.\n").local8Bit());
116 //puts(i18n(" # 'dest' may be \"trash:/\" to move the files\n"
117 // " # in the trash bin.\n\n").local8Bit());
118 puts(i18n(" kfmclient download ['src']\n"
119 " # Copies the URL 'src' to a user specified location'.\n"
120 " # 'src' may be a list of URLs, if not present then\n"
121 " # a URL will be requested.\n\n").local8Bit());
122 puts(i18n(" kfmclient copy 'src' 'dest'\n"
123 " # Copies the URL 'src' to 'dest'.\n"
124 " # 'src' may be a list of URLs.\n\n").local8Bit());
125 puts(i18n(" kfmclient sortDesktop\n"
126 " # Rearranges all icons on the desktop.\n\n").local8Bit());
127 puts(i18n(" kfmclient configure\n"
128 " # Re-read Konqueror's configuration.\n\n").local8Bit());
129 puts(i18n(" kfmclient configureDesktop\n"
130 " # Re-read kdesktop's configuration.\n\n").local8Bit());
131
132 puts(i18n("*** Examples:\n"
133 " kfmclient exec file:/root/Desktop/cdrom.desktop \"Mount default\"\n"
134 " // Mounts the CD-ROM\n\n").local8Bit());
135 puts(i18n(" kfmclient exec file:/home/weis/data/test.html\n"
136 " // Opens the file with default binding\n\n").local8Bit());
137 puts(i18n(" kfmclient exec file:/home/weis/data/test.html Netscape\n"
138 " // Opens the file with netscape\n\n").local8Bit());
139 puts(i18n(" kfmclient exec ftp://localhost/\n"
140 " // Opens new window with URL\n\n").local8Bit());
141 puts(i18n(" kfmclient exec file:/root/Desktop/emacs.desktop\n"
142 " // Starts emacs\n\n").local8Bit());
143 puts(i18n(" kfmclient exec file:/root/Desktop/cdrom.desktop\n"
144 " // Opens the CD-ROM's mount directory\n\n").local8Bit());
145 puts(i18n(" kfmclient exec .\n"
146 " // Opens the current directory. Very convenient.\n\n").local8Bit());
147 return 0;
148 }
149
150 return clientApp::doIt() ? 0 /*no error*/ : 1 /*error*/;
151 }
152
153 /*
154 Whether to start a new konqueror or reuse an existing process.
155
156 First of all, this concept is actually broken, as the view used to show
157 the data may change at any time, and therefore Konqy reused to browse
158 "safe" data may eventually browse something completely different.
159 Moreover, it's quite difficult to find out when to reuse, and thus this
160 function is an ugly hack. You've been warned.
161
162 Kfmclient will attempt to find an instance for reusing if either reusing
163 is configured to reuse always,
164 or it's not configured to never reuse, and the URL to-be-opened is "safe".
165 The URL is safe, if the view used to view it is listed in the allowed KPart's.
166 In order to find out the part, mimetype is needed, and KTrader is needed.
167 If mimetype is not known, KMimeType is used (which doesn't work e.g. for remote
168 URLs, but oh well). Since this function may be running without a KApplication
169 instance, I'm actually quite surprised it works, and it may sooner or later break.
170 Nice, isn't it?
171
172 If a profile is being used, and no url has been explicitly given, it needs to be
173 read from the profile. If there's more than one URL listed in the profile, no reusing
174 will be done (oh well), if there's no URL, no reusing will be done either (also
175 because the webbrowsing profile doesn't have any URL listed).
176 */
177 static bool startNewKonqueror( QString url, QString mimetype, const QString& profile )
178 {
179 KConfig cfg( QString::fromLatin1( "konquerorrc" ), true );
180 cfg.setGroup( "Reusing" );
181 QStringList allowed_parts;
182 // is duplicated in ../KonquerorIface.cc
183 allowed_parts << QString::fromLatin1( "konq_iconview.desktop" )
184 << QString::fromLatin1( "konq_multicolumnview.desktop" )
185 << QString::fromLatin1( "konq_sidebartng.desktop" )
186 << QString::fromLatin1( "konq_infolistview.desktop" )
187 << QString::fromLatin1( "konq_treeview.desktop" )
188 << QString::fromLatin1( "konq_detailedlistview.desktop" );
189 if( cfg.hasKey( "SafeParts" )
190 && cfg.readEntry( "SafeParts" ) != QString::fromLatin1( "SAFE" ))
191 allowed_parts = cfg.readListEntry( "SafeParts" );
192 if( allowed_parts.count() == 1 && allowed_parts.first() == QString::fromLatin1( "ALL" ))
193 return false; // all parts allowed
194 if( url.isEmpty())
195 {
196 if( profile.isEmpty())
197 return true;
198 QString profilepath = locate( "data", QString::fromLatin1("konqueror/profiles/") + profile );
199 if( profilepath.isEmpty())
200 return true;
201 KConfig cfg( profilepath, true );
202 cfg.setDollarExpansion( true );
203 cfg.setGroup( "Profile" );
204 QMap< QString, QString > entries = cfg.entryMap( QString::fromLatin1( "Profile" ));
205 QRegExp urlregexp( QString::fromLatin1( "^View[0-9]*_URL$" ));
206 QStringList urls;
207 for( QMap< QString, QString >::ConstIterator it = entries.begin();
208 it != entries.end();
209 ++it )
210 {
211 // don't read value from map, dollar expansion is needed
212 QString value = cfg.readEntry( it.key());
213 if( urlregexp.search( it.key()) >= 0 && !value.isEmpty())
214 urls << value;
215 }
216 if( urls.count() != 1 )
217 return true;
218 url = urls.first();
219 mimetype = QString::fromLatin1( "" );
220 }
221 if( mimetype.isEmpty())
222 mimetype = KMimeType::findByURL( KURL( url ) )->name();
223 KTrader::OfferList offers = KTrader::self()->query( mimetype, QString::fromLatin1( "KParts/ReadOnlyPart" ),
224 QString::null, QString::null );
225 KService::Ptr serv;
226 if( offers.count() > 0 )
227 serv = offers.first();
228 return serv == NULL || !allowed_parts.contains( serv->desktopEntryName() + QString::fromLatin1(".desktop") );
229 }
230
231 static int currentScreen()
232 {
233 if( qt_xdisplay() != NULL )
234 return qt_xscreen();
235 // case when there's no KApplication instance
236 const char* env = getenv( "DISPLAY" );
237 if( env == NULL )
238 return 0;
239 const char* dotpos = strrchr( env, '.' );
240 const char* colonpos = strrchr( env, ':' );
241 if( dotpos != NULL && colonpos != NULL && dotpos > colonpos )
242 return atoi( dotpos + 1 );
243 return 0;
244 }
245
246 // when reusing a preloaded konqy, make sure your always use a DCOP call which opens a profile !
247 static QCString getPreloadedKonqy()
248 {
249 KConfig cfg( QString::fromLatin1( "konquerorrc" ), true );
250 cfg.setGroup( "Reusing" );
251 if( cfg.readNumEntry( "MaxPreloadCount", 1 ) == 0 )
252 return "";
253 DCOPRef ref( "kded", "konqy_preloader" );
254 QCString ret;
255 if( ref.callExt( "getPreloadedKonqy", DCOPRef::NoEventLoop, 3000, currentScreen()).get( ret ))
256 return ret;
257 return QCString();
258 }
259
260
261 static QCString konqyToReuse( const QString& url, const QString& mimetype, const QString& profile )
262 { // prefer(?) preloaded ones
263 QCString ret = getPreloadedKonqy();
264 if( !ret.isEmpty())
265 return ret;
266 if( startNewKonqueror( url, mimetype, profile ))
267 return "";
268 QCString appObj;
269 QByteArray data;
270 QDataStream str( data, IO_WriteOnly );
271 str << currentScreen();
272 if( !KApplication::dcopClient()->findObject( "konqueror*", "KonquerorIface",
273 "processCanBeReused( int )", data, ret, appObj, false, 3000 ) )
274 return "";
275 return ret;
276 }
277
278 static bool krun_has_error = false;
279
280 void clientApp::sendASNChange()
281 {
282 KStartupInfoId id;
283 id.initId( startup_id_str );
284 KStartupInfoData data;
285 data.addPid( 0 ); // say there's another process for this ASN with unknown PID
286 data.setHostname(); // ( no need to bother to get this konqy's PID )
287 Display* dpy = qt_xdisplay();
288 if( dpy == NULL ) // we may be running without QApplication here
289 dpy = XOpenDisplay( NULL );
290 if( dpy != NULL )
291 KStartupInfo::sendChangeX( dpy, id, data );
292 if( dpy != NULL && dpy != qt_xdisplay())
293 XCloseDisplay( dpy );
294 }
295
296 bool clientApp::createNewWindow(const KURL & url, bool newTab, bool tempFile, const QString & mimetype)
297 {
298 kdDebug( 1202 ) << "clientApp::createNewWindow " << url.url() << " mimetype=" << mimetype << endl;
299 // check if user wants to use external browser
300 // ###### this option seems to have no GUI and to be redundant with BrowserApplication now.
301 // ###### KDE4: remove
302 KConfig config( QString::fromLatin1("kfmclientrc"));
303 config.setGroup( QString::fromLatin1("Settings"));
304 QString strBrowser = config.readPathEntry("ExternalBrowser");
305 if (!strBrowser.isEmpty())
306 {
307 if ( tempFile )
308 kdWarning() << "kfmclient used with --tempfile but is passing to an external browser! Tempfile will never be deleted" << endl;
309 KProcess proc;
310 proc << strBrowser << url.url();
311 proc.start( KProcess::DontCare );
312 return true;
313 }
314
315 if (url.protocol().startsWith(QString::fromLatin1("http")))
316 {
317 config.setGroup("General");
318 if (!config.readEntry("BrowserApplication").isEmpty())
319 {
320 clientApp app;
321 KStartupInfo::appStarted();
322
323 KRun * run = new KRun( url, 0, 0, false, false /* no progress window */ ); // TODO pass tempFile [needs support in the KRun ctor]
324 QObject::connect( run, SIGNAL( finished() ), &app, SLOT( delayedQuit() ));
325 QObject::connect( run, SIGNAL( error() ), &app, SLOT( delayedQuit() ));
326 app.exec();
327 return !krun_has_error;
328 }
329 }
330
331 KConfig cfg( QString::fromLatin1( "konquerorrc" ), true );
332 cfg.setGroup( "FMSettings" );
333 if ( newTab || cfg.readBoolEntry( "KonquerorTabforExternalURL", false ) )
334 {
335 QCString foundApp, foundObj;
336 QByteArray data;
337 QDataStream str( data, IO_WriteOnly );
338 if( KApplication::dcopClient()->findObject( "konqueror*", "konqueror-mainwindow*",
339 "windowCanBeUsedForTab()", data, foundApp, foundObj, false, 3000 ) )
340 {
341 DCOPRef ref( foundApp, foundObj );
342 DCOPReply reply = ref.call( "newTabASN", url.url(), startup_id_str, tempFile );
343 if ( reply.isValid() ) {
344 sendASNChange();
345 return true;
346 }
347 }
348 }
349
350 QCString appId = konqyToReuse( url.url(), mimetype, QString::null );
351 if( !appId.isEmpty())
352 {
353 kdDebug( 1202 ) << "clientApp::createNewWindow using existing konqueror" << endl;
354 KonquerorIface_stub konqy( appId, "KonquerorIface" );
355 konqy.createNewWindowASN( url.url(), mimetype, startup_id_str, tempFile );
356 sendASNChange();
357 }
358 else
359 {
360 QString error;
361 /* Well, we can't pass a mimetype through startServiceByDesktopPath !
362 if ( KApplication::startServiceByDesktopPath( QString::fromLatin1("konqueror.desktop"),
363 url.url(), &error ) > 0 )
364 {
365 kdError() << "Couldn't start konqueror from konqueror.desktop: " << error << endl;
366 */
367 // pass kfmclient's startup id to konqueror using kshell
368 KStartupInfoId id;
369 id.initId( startup_id_str );
370 id.setupStartupEnv();
371 KProcess proc;
372 proc << "kshell" << "konqueror";
373 if ( !mimetype.isEmpty() )
374 proc << "-mimetype" << mimetype;
375 if ( tempFile )
376 proc << "-tempfile";
377 proc << url.url();
378 proc.start( KProcess::DontCare );
379 KStartupInfo::resetStartupEnv();
380 kdDebug( 1202 ) << "clientApp::createNewWindow KProcess started" << endl;
381 //}
382 }
383 return true;
384 }
385
386 bool clientApp::openProfile( const QString & profileName, const QString & url, const QString & mimetype )
387 {
388 QCString appId = konqyToReuse( url, mimetype, profileName );
389 if( appId.isEmpty())
390 {
391 QString error;
392 if ( KApplication::startServiceByDesktopPath( QString::fromLatin1("konqueror.desktop"),
393 QString::fromLatin1("--silent"), &error, &appId, NULL, startup_id_str ) > 0 )
394 {
395 kdError() << "Couldn't start konqueror from konqueror.desktop: " << error << endl;
396 return false;
397 }
398 // startServiceByDesktopPath waits for the app to register with DCOP
399 // so when we arrive here, konq is up and running already, and appId contains the identification
400 }
401
402 QString profile = locate( "data", QString::fromLatin1("konqueror/profiles/") + profileName );
403 if ( profile.isEmpty() )
404 {
405 fprintf( stderr, "%s", i18n("Profile %1 not found\n").arg(profileName).local8Bit().data() );
406 ::exit( 0 );
407 }
408 KonquerorIface_stub konqy( appId, "KonquerorIface" );
409 if ( url.isEmpty() )
410 konqy.createBrowserWindowFromProfileASN( profile, profileName, startup_id_str );
411 else if ( mimetype.isEmpty() )
412 konqy.createBrowserWindowFromProfileAndURLASN( profile, profileName, url, startup_id_str );
413 else
414 konqy.createBrowserWindowFromProfileAndURLASN( profile, profileName, url, mimetype, startup_id_str );
415 sleep(2); // Martin Schenk <martin@schenk.com> says this is necessary to let the server read from the socket
416 sendASNChange();
417 return true;
418 }
419
420 void clientApp::delayedQuit()
421 {
422 // Quit in 2 seconds. This leaves time for KRun to pop up
423 // "app not found" in KProcessRunner, if that was the case.
424 QTimer::singleShot( 2000, this, SLOT(deref()) );
425 // don't access the KRun instance later, it will be deleted after calling slots
426 if( static_cast< const KRun* >( sender())->hasError())
427 krun_has_error = true;
428 }
429
430 static void checkArgumentCount(int count, int min, int max)
431 {
432 if (count < min)
433 {
434 fputs( i18n("Syntax Error: Not enough arguments\n").local8Bit(), stderr );
435 ::exit(1);
436 }
437 if (max && (count > max))
438 {
439 fputs( i18n("Syntax Error: Too many arguments\n").local8Bit(), stderr );
440 ::exit(1);
441 }
442 }
443
444 bool clientApp::doIt()
445 {
446 KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
447 int argc = args->count();
448 checkArgumentCount(argc, 1, 0);
449
450 if ( !args->isSet( "ninteractive" ) ) {
451 s_interactive = false;
452 }
453 QCString command = args->arg(0);
454
455 // read ASN env. variable for non-KApp cases
456 startup_id_str = KStartupInfo::currentStartupIdEnv().id();
457
458 if ( command == "openURL" || command == "newTab" )
459 {
460 KInstance inst(appName);
461 if( !KApplication::dcopClient()->attach())
462 {
463 KApplication::startKdeinit();
464 KApplication::dcopClient()->attach();
465 }
466 checkArgumentCount(argc, 1, 3);
467 bool tempFile = KCmdLineArgs::isTempFileSet();
468 if ( argc == 1 )
469 {
470 KURL url;
471 url.setPath(QDir::homeDirPath());
472 return createNewWindow( url, command == "newTab", tempFile );
473 }
474 if ( argc == 2 )
475 {
476 return createNewWindow( args->url(1), command == "newTab", tempFile );
477 }
478 if ( argc == 3 )
479 {
480 return createNewWindow( args->url(1), command == "newTab", tempFile, QString::fromLatin1(args->arg(2)) );
481 }
482 }
483 else if ( command == "openProfile" )
484 {
485 KInstance inst(appName);
486 if( !KApplication::dcopClient()->attach())
487 {
488 KApplication::startKdeinit();
489 KApplication::dcopClient()->attach();
490 }
491 checkArgumentCount(argc, 2, 3);
492 QString url;
493 if ( argc == 3 )
494 url = args->url(2).url();
495 return openProfile( QString::fromLocal8Bit(args->arg(1)), url );
496 }
497
498 // the following commands need KApplication
499 clientApp app;
500
501 if ( command == "openProperties" )
502 {
503 checkArgumentCount(argc, 2, 2);
504 KPropertiesDialog * p = new KPropertiesDialog( args->url(1) );
505 QObject::connect( p, SIGNAL( destroyed() ), &app, SLOT( quit() ));
506 QObject::connect( p, SIGNAL( canceled() ), &app, SLOT( slotDialogCanceled() ));
507 app.exec();
508 return m_ok;
509 }
510 else if ( command == "exec" )
511 {
512 checkArgumentCount(argc, 1, 3);
513 if ( argc == 1 )
514 {
515 KDesktopIface_stub kdesky( "kdesktop", "KDesktopIface" );
516 kdesky.popupExecuteCommand();
517 }
518 else if ( argc == 2 )
519 {
520 KRun * run = new KRun( args->url(1), 0, 0, false, false /* no progress window */ );
521 QObject::connect( run, SIGNAL( finished() ), &app, SLOT( delayedQuit() ));
522 QObject::connect( run, SIGNAL( error() ), &app, SLOT( delayedQuit() ));
523 app.exec();
524 return !krun_has_error;
525 }
526 else if ( argc == 3 )
527 {
528 KURL::List urls;
529 urls.append( args->url(1) );
530 const KTrader::OfferList offers = KTrader::self()->query( QString::fromLocal8Bit( args->arg( 2 ) ), QString::fromLatin1( "Application" ), QString::null, QString::null );
531 if (offers.isEmpty()) return 1;
532 KService::Ptr serv = offers.first();
533 return KRun::run( *serv, urls );
534 }
535 }
536 else if ( command == "move" )
537 {
538 checkArgumentCount(argc, 2, 0);
539 KURL::List srcLst;
540 for ( int i = 1; i <= argc - 2; i++ )
541 srcLst.append( args->url(i) );
542
543 KIO::Job * job = KIO::move( srcLst, args->url(argc - 1) );
544 if ( !s_interactive )
545 job->setInteractive( false );
546 connect( job, SIGNAL( result( KIO::Job * ) ), &app, SLOT( slotResult( KIO::Job * ) ) );
547 app.exec();
548 return m_ok;
549 }
550 else if ( command == "download" )
551 {
552 checkArgumentCount(argc, 0, 0);
553 KURL::List srcLst;
554 if (argc == 1) {
555 while(true) {
556 KURL src = KURLRequesterDlg::getURL();
557 if (!src.isEmpty()) {
558 if (!src.isValid()) {
559 KMessageBox::error(0, i18n("Unable to download from an invalid URL."));
560 continue;
561 }
562 srcLst.append(src);
563 }
564 break;
565 }
566 } else {
567 for ( int i = 1; i <= argc - 1; i++ )
568 srcLst.append( args->url(i) );
569 }
570 if (srcLst.count() == 0)
571 return m_ok;
572 QString dst =
573 KFileDialog::getSaveFileName( (argc<2) ? (QString::null) : (args->url(1).filename()) );
574 if (dst.isEmpty()) // cancelled
575 return m_ok; // AK - really okay?
576 KURL dsturl;
577 dsturl.setPath( dst );
578 KIO::Job * job = KIO::copy( srcLst, dsturl );
579 if ( !s_interactive )
580 job->setInteractive( false );
581 connect( job, SIGNAL( result( KIO::Job * ) ), &app, SLOT( slotResult( KIO::Job * ) ) );
582 app.exec();
583 return m_ok;
584 }
585 else if ( command == "copy" )
586 {
587 checkArgumentCount(argc, 2, 0);
588 KURL::List srcLst;
589 for ( int i = 1; i <= argc - 2; i++ )
590 srcLst.append( args->url(i) );
591
592 KIO::Job * job = KIO::copy( srcLst, args->url(argc - 1) );
593 if ( !s_interactive )
594 job->setInteractive( false );
595 connect( job, SIGNAL( result( KIO::Job * ) ), &app, SLOT( slotResult( KIO::Job * ) ) );
596 app.exec();
597 return m_ok;
598 }
599 else if ( command == "sortDesktop" )
600 {
601 checkArgumentCount(argc, 1, 1);
602
603 KDesktopIface_stub kdesky( "kdesktop", "KDesktopIface" );
604 kdesky.rearrangeIcons( (int)false );
605
606 return true;
607 }
608 else if ( command == "configure" )
609 {
610 checkArgumentCount(argc, 1, 1);
611 QByteArray data;
612 kapp->dcopClient()->send( "*", "KonqMainViewIface", "reparseConfiguration()", data );
613 // Warning. In case something is added/changed here, keep kcontrol/konq/main.cpp in sync.
614 }
615 else if ( command == "configureDesktop" )
616 {
617 checkArgumentCount(argc, 1, 1);
618 KDesktopIface_stub kdesky( "kdesktop", "KDesktopIface" );
619 kdesky.configure();
620 }
621 else
622 {
623 fprintf( stderr, "%s", i18n("Syntax Error: Unknown command '%1'\n").arg(QString::fromLocal8Bit(command)).local8Bit().data() );
624 return false;
625 }
626 return true;
627 }
628
629 void clientApp::slotResult( KIO::Job * job )
630 {
631 if (job->error() && s_interactive)
632 job->showErrorDialog();
633 m_ok = !job->error();
634 quit();
635 }
636
637 void clientApp::slotDialogCanceled()
638 {
639 m_ok = false;
640 quit();
641 }
642
643 #include "kfmclient.moc"