Contents of /branches/KDE/3.5/kdebase/konqueror/client/kfmclient.cc
Parent Directory
|
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)
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" |
The KDE Source Repository
Full Width