klauncher.cpp

00001 /*
00002   This file is part of the KDE libraries
00003   Copyright (c) 1999 Waldo Bastian <bastian@kde.org>
00004 
00005   This library is free software; you can redistribute it and/or
00006   modify it under the terms of the GNU Library General Public
00007   License version 2 as published by the Free Software Foundation.
00008 
00009   This library is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012   Library General Public License for more details.
00013 
00014   You should have received a copy of the GNU Library General Public License
00015   along with this library; see the file COPYING.LIB.  If not, write to
00016   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017   Boston, MA 02110-1301, USA.
00018 */
00019 #ifdef HAVE_CONFIG_H
00020 #include <config.h>
00021 #endif
00022 
00023 #include <stdio.h>
00024 #include <unistd.h>
00025 #include <stdlib.h>
00026 #include <errno.h>
00027 #include <signal.h>
00028 #include <sys/time.h>
00029 
00030 #include <qfile.h>
00031 
00032 #include <kconfig.h>
00033 #include <kdebug.h>
00034 #include <klibloader.h>
00035 #include <klocale.h>
00036 #include <kprotocolmanager.h>
00037 #include <kprotocolinfo.h>
00038 #include <krun.h>
00039 #include <kstandarddirs.h>
00040 #include <ktempfile.h>
00041 #include <kurl.h>
00042 
00043 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00044 #include <kstartupinfo.h> // schroder
00045 #endif
00046 
00047 
00048 #include "kio/global.h"
00049 #include "kio/connection.h"
00050 #include "kio/slaveinterface.h"
00051 
00052 #include "klauncher.h"
00053 #include "klauncher_cmds.h"
00054 
00055 //#if defined Q_WS_X11 && ! defined K_WS_QTONLY
00056 #ifdef Q_WS_X11
00057 //#undef K_WS_QTONLY
00058 #include <X11/Xlib.h> // schroder
00059 #endif
00060 
00061 // Dispose slaves after being idle for SLAVE_MAX_IDLE seconds
00062 #define SLAVE_MAX_IDLE  30
00063 
00064 using namespace KIO;
00065 
00066 template class QPtrList<KLaunchRequest>;
00067 template class QPtrList<IdleSlave>;
00068 
00069 IdleSlave::IdleSlave(KSocket *socket)
00070 {
00071    mConn.init(socket);
00072    mConn.connect(this, SLOT(gotInput()));
00073    mConn.send( CMD_SLAVE_STATUS );
00074    mPid = 0;
00075    mBirthDate = time(0);
00076    mOnHold = false;
00077 }
00078 
00079 void
00080 IdleSlave::gotInput()
00081 {
00082    int cmd;
00083    QByteArray data;
00084    if (mConn.read( &cmd, data) == -1)
00085    {
00086       // Communication problem with slave.
00087       kdError(7016) << "SlavePool: No communication with slave." << endl;
00088       delete this;
00089    }
00090    else if (cmd == MSG_SLAVE_ACK)
00091    {
00092       delete this;
00093    }
00094    else if (cmd != MSG_SLAVE_STATUS)
00095    {
00096       kdError(7016) << "SlavePool: Unexpected data from slave." << endl;
00097       delete this;
00098    }
00099    else
00100    {
00101       QDataStream stream( data, IO_ReadOnly );
00102       pid_t pid;
00103       QCString protocol;
00104       QString host;
00105       Q_INT8 b;
00106       stream >> pid >> protocol >> host >> b;
00107 // Overload with (bool) onHold, (KURL) url.
00108       if (!stream.atEnd())
00109       {
00110          KURL url;
00111          stream >> url;
00112          mOnHold = true;
00113          mUrl = url;
00114       }
00115 
00116       mPid = pid;
00117       mConnected = (b != 0);
00118       mProtocol = protocol;
00119       mHost = host;
00120       emit statusUpdate(this);
00121    }
00122 }
00123 
00124 void
00125 IdleSlave::connect(const QString &app_socket)
00126 {
00127    QByteArray data;
00128    QDataStream stream( data, IO_WriteOnly);
00129    stream << app_socket;
00130    mConn.send( CMD_SLAVE_CONNECT, data );
00131    // Timeout!
00132 }
00133 
00134 void
00135 IdleSlave::reparseConfiguration()
00136 {
00137    mConn.send( CMD_REPARSECONFIGURATION );
00138 }
00139 
00140 bool
00141 IdleSlave::match(const QString &protocol, const QString &host, bool connected)
00142 {
00143    if (mOnHold) return false;
00144    if (protocol != mProtocol) return false;
00145    if (host.isEmpty()) return true;
00146    if (host != mHost) return false;
00147    if (!connected) return true;
00148    if (!mConnected) return false;
00149    return true;
00150 }
00151 
00152 bool
00153 IdleSlave::onHold(const KURL &url)
00154 {
00155    if (!mOnHold) return false;
00156    return (url == mUrl);
00157 }
00158 
00159 int
00160 IdleSlave::age(time_t now)
00161 {
00162    return (int) difftime(now, mBirthDate);
00163 }
00164 
00165 KLauncher::KLauncher(int _kdeinitSocket, bool new_startup)
00166   : KApplication( false, false ), // No Styles, No GUI
00167     DCOPObject("klauncher"),
00168     kdeinitSocket(_kdeinitSocket), mAutoStart( new_startup ),
00169     dontBlockReading(false), newStartup( new_startup )
00170 {
00171 #ifdef Q_WS_X11
00172    mCached_dpy = NULL;
00173 #endif
00174    connect(&mAutoTimer, SIGNAL(timeout()), this, SLOT(slotAutoStart()));
00175    requestList.setAutoDelete(true);
00176    mSlaveWaitRequest.setAutoDelete(true);
00177    dcopClient()->setNotifications( true );
00178    connect(dcopClient(), SIGNAL( applicationRegistered( const QCString &)),
00179            this, SLOT( slotAppRegistered( const QCString &)));
00180    dcopClient()->connectDCOPSignal( "DCOPServer", "", "terminateKDE()",
00181                                     objId(), "terminateKDE()", false );
00182 
00183    QString prefix = locateLocal("socket", "klauncher");
00184    KTempFile domainname(prefix, QString::fromLatin1(".slave-socket"));
00185    if (domainname.status() != 0)
00186    {
00187       // Sever error!
00188       qDebug("KLauncher: Fatal error, can't create tempfile!");
00189       ::exit(1);
00190    }
00191    mPoolSocketName = domainname.name();
00192 #ifdef __CYGWIN__
00193    domainname.close();
00194    domainname.unlink();
00195 #endif
00196    mPoolSocket = new KServerSocket(QFile::encodeName(mPoolSocketName));
00197    connect(mPoolSocket, SIGNAL(accepted( KSocket *)),
00198            SLOT(acceptSlave(KSocket *)));
00199 
00200    connect(&mTimer, SIGNAL(timeout()), SLOT(idleTimeout()));
00201 
00202    kdeinitNotifier = new QSocketNotifier(kdeinitSocket, QSocketNotifier::Read);
00203    connect(kdeinitNotifier, SIGNAL( activated( int )),
00204            this, SLOT( slotKDEInitData( int )));
00205    kdeinitNotifier->setEnabled( true );
00206    lastRequest = 0;
00207    bProcessingQueue = false;
00208 
00209    mSlaveDebug = getenv("KDE_SLAVE_DEBUG_WAIT");
00210    if (!mSlaveDebug.isEmpty())
00211    {
00212       qWarning("Klauncher running in slave-debug mode for slaves of protocol '%s'", mSlaveDebug.data());
00213    }
00214    mSlaveValgrind = getenv("KDE_SLAVE_VALGRIND");
00215    if (!mSlaveValgrind.isEmpty())
00216    {
00217       mSlaveValgrindSkin = getenv("KDE_SLAVE_VALGRIND_SKIN");
00218       qWarning("Klauncher running slaves through valgrind for slaves of protocol '%s'", mSlaveValgrind.data());
00219    }
00220    klauncher_header request_header;
00221    request_header.cmd = LAUNCHER_OK;
00222    request_header.arg_length = 0;
00223    write(kdeinitSocket, &request_header, sizeof(request_header));
00224 
00225    {
00226     QString browser(::getenv("BROWSER"));
00227     if( browser.isEmpty() || browser == "/usr/bin/xbrowser" )
00228     {
00229         KConfig config("kdeglobals", true);
00230         config.setGroup("General");
00231         browser = config.readEntry("BrowserApplication");
00232         if (!browser.isEmpty())
00233         {
00234         if (browser.startsWith("!"))
00235                 browser = browser.mid(1);
00236         }
00237         else
00238             browser = "/usr/bin/kfmclient openProfile webbrowsing";
00239         setLaunchEnv("BROWSER", browser.latin1());
00240 
00241         QString help_browser(::getenv("HELP_BROWSER"));
00242         if( help_browser.isEmpty() )
00243         {
00244         setLaunchEnv("HELP_BROWSER", browser.latin1());
00245         }
00246     }
00247     QString mailer(::getenv("MAILER"));
00248     if( mailer.isEmpty() )
00249     {
00250         KConfig config("emaildefaults");
00251         config.setGroup("Defaults");
00252         QString group = config.readEntry("Profile","Default");
00253         config.setGroup( QString("PROFILE_%1").arg(group) );
00254         mailer = config.readPathEntry("EmailClient");
00255 
00256         if( mailer.isEmpty() )
00257         {
00258         mailer = "kmail";
00259         }
00260         setLaunchEnv("MAILER", mailer.latin1());
00261     }
00262    }
00263 }
00264 
00265 KLauncher::~KLauncher()
00266 {
00267    close();
00268 }
00269 
00270 void KLauncher::close()
00271 {
00272    if (!mPoolSocketName.isEmpty())
00273    {
00274       QCString filename = QFile::encodeName(mPoolSocketName);
00275       unlink(filename.data());
00276    }
00277 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00278 //#ifdef Q_WS_X11
00279    if( mCached_dpy != NULL )
00280        XCloseDisplay( mCached_dpy );
00281 #endif
00282 }
00283 
00284 void
00285 KLauncher::destruct(int exit_code)
00286 {
00287    if (kapp) ((KLauncher*)kapp)->close();
00288    // We don't delete kapp here, that's intentional.
00289    ::exit(exit_code);
00290 }
00291 
00292 bool
00293 KLauncher::process(const QCString &fun, const QByteArray &data,
00294                    QCString &replyType, QByteArray &replyData)
00295 {
00296    if ((fun == "exec_blind(QCString,QValueList<QCString>)")
00297        || (fun == "exec_blind(QCString,QValueList<QCString>,QValueList<QCString>,QCString)"))
00298    {
00299       QDataStream stream(data, IO_ReadOnly);
00300       replyType = "void";
00301       QCString name;
00302       QValueList<QCString> arg_list;
00303       QCString startup_id = "0";
00304       QValueList<QCString> envs;
00305       stream >> name >> arg_list;
00306       if( fun == "exec_blind(QCString,QValueList<QCString>,QValueList<QCString>,QCString)" )
00307           stream >> envs >> startup_id;
00308       kdDebug(7016) << "KLauncher: Got exec_blind('" << name << "', ...)" << endl;
00309       exec_blind( name, arg_list, envs, startup_id);
00310       return true;
00311    }
00312    if ((fun == "start_service_by_name(QString,QStringList)") ||
00313        (fun == "start_service_by_desktop_path(QString,QStringList)")||
00314        (fun == "start_service_by_desktop_name(QString,QStringList)")||
00315        (fun == "kdeinit_exec(QString,QStringList)") ||
00316        (fun == "kdeinit_exec_wait(QString,QStringList)") ||
00317        (fun == "start_service_by_name(QString,QStringList,QValueList<QCString>,QCString)") ||
00318        (fun == "start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString)")||
00319        (fun == "start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString)") ||
00320        (fun == "start_service_by_name(QString,QStringList,QValueList<QCString>,QCString,bool)") ||
00321        (fun == "start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString,bool)")||
00322        (fun == "start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString,bool)") ||
00323        (fun == "kdeinit_exec(QString,QStringList,QValueList<QCString>)") ||
00324        (fun == "kdeinit_exec_wait(QString,QStringList,QValueList<QCString>)") ||
00325        (fun == "kdeinit_exec(QString,QStringList,QValueList<QCString>,QCString)") ||
00326        (fun == "kdeinit_exec_wait(QString,QStringList,QValueList<QCString>,QCString)"))
00327    {
00328       QDataStream stream(data, IO_ReadOnly);
00329       bool bNoWait = false;
00330       QString serviceName;
00331       QStringList urls;
00332       QValueList<QCString> envs;
00333       QCString startup_id = "";
00334       DCOPresult.result = -1;
00335       DCOPresult.dcopName = 0;
00336       DCOPresult.error = QString::null;
00337       DCOPresult.pid = 0;
00338       stream >> serviceName >> urls;
00339       if ((fun == "start_service_by_name(QString,QStringList,QValueList<QCString>,QCString,bool)") ||
00340           (fun == "start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString,bool)")||
00341           (fun == "start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString,bool)"))
00342          stream >> envs >> startup_id >> bNoWait;
00343       else if ((fun == "start_service_by_name(QString,QStringList,QValueList<QCString>,QCString)") ||
00344           (fun == "start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString)")||
00345           (fun == "start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString)"))
00346          stream >> envs >> startup_id;
00347       else if ((fun == "kdeinit_exec(QString,QStringList,QValueList<QCString>)") ||
00348           (fun == "kdeinit_exec_wait(QString,QStringList,QValueList<QCString>)"))
00349          stream >> envs;
00350       else if ((fun == "kdeinit_exec(QString,QStringList,QValueList<QCString>,QCString)") ||
00351           (fun == "kdeinit_exec_wait(QString,QStringList,QValueList<QCString>,QCString)"))
00352          stream >> envs >> startup_id;
00353       bool finished;
00354       if (strncmp(fun, "start_service_by_name(", 22) == 0)
00355       {
00356          kdDebug(7016) << "KLauncher: Got start_service_by_name('" << serviceName << "', ...)" << endl;
00357          finished = start_service_by_name(serviceName, urls, envs, startup_id, bNoWait);
00358       }
00359       else if (strncmp(fun, "start_service_by_desktop_path(", 30) == 0)
00360       {
00361          kdDebug(7016) << "KLauncher: Got start_service_by_desktop_path('" << serviceName << "', ...)" << endl;
00362          finished = start_service_by_desktop_path(serviceName, urls, envs, startup_id, bNoWait);
00363       }
00364       else if (strncmp(fun, "start_service_by_desktop_name(", 30) == 0)
00365       {
00366          kdDebug(7016) << "KLauncher: Got start_service_by_desktop_name('" << serviceName << "', ...)" << endl;
00367          finished = start_service_by_desktop_name(serviceName, urls, envs, startup_id, bNoWait );
00368       }
00369       else if ((fun == "kdeinit_exec(QString,QStringList)")
00370               || (fun == "kdeinit_exec(QString,QStringList,QValueList<QCString>)")
00371               || (fun == "kdeinit_exec(QString,QStringList,QValueList<QCString>,QCString)"))
00372       {
00373          kdDebug(7016) << "KLauncher: Got kdeinit_exec('" << serviceName << "', ...)" << endl;
00374          finished = kdeinit_exec(serviceName, urls, envs, startup_id, false);
00375       }
00376       else
00377       {
00378          kdDebug(7016) << "KLauncher: Got kdeinit_exec_wait('" << serviceName << "', ...)" << endl;
00379          finished = kdeinit_exec(serviceName, urls, envs, startup_id, true);
00380       }
00381       if (!finished)
00382       {
00383          replyType = "serviceResult";
00384          QDataStream stream2(replyData, IO_WriteOnly);
00385          stream2 << DCOPresult.result << DCOPresult.dcopName << DCOPresult.error << DCOPresult.pid;
00386       }
00387       return true;
00388    }
00389    else if (fun == "requestSlave(QString,QString,QString)")
00390    {
00391       QDataStream stream(data, IO_ReadOnly);
00392       QString protocol;
00393       QString host;
00394       QString app_socket;
00395       stream >> protocol >> host >> app_socket;
00396       replyType = "QString";
00397       QString error;
00398       pid_t pid = requestSlave(protocol, host, app_socket, error);
00399       QDataStream stream2(replyData, IO_WriteOnly);
00400       stream2 << pid << error;
00401       return true;
00402    }
00403    else if (fun == "requestHoldSlave(KURL,QString)")
00404    {
00405       QDataStream stream(data, IO_ReadOnly);
00406       KURL url;
00407       QString app_socket;
00408       stream >> url >> app_socket;
00409       replyType = "pid_t";
00410       pid_t pid = requestHoldSlave(url, app_socket);
00411       QDataStream stream2(replyData, IO_WriteOnly);
00412       stream2 << pid;
00413       return true;
00414    }
00415    else if (fun == "waitForSlave(pid_t)")
00416    {
00417       QDataStream stream(data, IO_ReadOnly);
00418       pid_t pid;
00419       stream >> pid;
00420       waitForSlave(pid);
00421       replyType = "void";
00422       return true;
00423 
00424    }
00425    else if (fun == "setLaunchEnv(QCString,QCString)")
00426    {
00427       QDataStream stream(data, IO_ReadOnly);
00428       QCString name;
00429       QCString value;
00430       stream >> name >> value;
00431       setLaunchEnv(name, value);
00432       replyType = "void";
00433       return true;
00434    }
00435    else if (fun == "reparseConfiguration()")
00436    {
00437       KGlobal::config()->reparseConfiguration();
00438       kdDebug(7016) << "KLauncher::process : reparseConfiguration" << endl;
00439       KProtocolManager::reparseConfiguration();
00440       IdleSlave *slave;
00441       for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
00442           slave->reparseConfiguration();
00443       replyType = "void";
00444       return true;
00445    }
00446    else if (fun == "terminateKDE()")
00447    {
00448       ::signal( SIGHUP, SIG_IGN);
00449       ::signal( SIGTERM, SIG_IGN);
00450       kdDebug() << "KLauncher::process ---> terminateKDE" << endl;
00451       klauncher_header request_header;
00452       request_header.cmd = LAUNCHER_TERMINATE_KDE;
00453       request_header.arg_length = 0;
00454       write(kdeinitSocket, &request_header, sizeof(request_header));
00455       destruct(0);
00456    }
00457    else if (fun == "autoStart()")
00458    {
00459       kdDebug() << "KLauncher::process ---> autoStart" << endl;
00460       autoStart(1);
00461       replyType = "void";
00462       return true;
00463    }
00464    else if (fun == "autoStart(int)")
00465    {
00466       kdDebug() << "KLauncher::process ---> autoStart(int)" << endl;
00467       QDataStream stream(data, IO_ReadOnly);
00468       int phase;
00469       stream >> phase;
00470       autoStart(phase);
00471       replyType = "void";
00472       return true;
00473    }
00474 
00475    if (DCOPObject::process(fun, data, replyType, replyData))
00476    {
00477       return true;
00478    }
00479    kdWarning(7016) << "Got unknown DCOP function: " << fun << endl;
00480    return false;
00481 }
00482 
00483 QCStringList
00484 KLauncher::interfaces()
00485 {
00486     QCStringList ifaces = DCOPObject::interfaces();
00487     ifaces += "KLauncher";
00488     return ifaces;
00489 }
00490 
00491 QCStringList
00492 KLauncher::functions()
00493 {
00494     QCStringList funcs = DCOPObject::functions();
00495     funcs << "void exec_blind(QCString,QValueList<QCString>)";
00496     funcs << "void exec_blind(QCString,QValueList<QCString>,QValueList<QCString>,QCString)";
00497     funcs << "serviceResult start_service_by_name(QString,QStringList)";
00498     funcs << "serviceResult start_service_by_desktop_path(QString,QStringList)";
00499     funcs << "serviceResult start_service_by_desktop_name(QString,QStringList)";
00500     funcs << "serviceResult kdeinit_exec(QString,QStringList)";
00501     funcs << "serviceResult kdeinit_exec_wait(QString,QStringList)";
00502     funcs << "serviceResult start_service_by_name(QString,QStringList,QValueList<QCString>,QCString)";
00503     funcs << "serviceResult start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString)";
00504     funcs << "serviceResult start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString)";
00505     funcs << "serviceResult start_service_by_name(QString,QStringList,QValueList<QCString>,QCString,bool)";
00506     funcs << "serviceResult start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString,bool)";
00507     funcs << "serviceResult start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString,bool)";
00508     funcs << "serviceResult kdeinit_exec(QString,QStringList,QValueList<QCString>)";
00509     funcs << "serviceResult kdeinit_exec_wait(QString,QStringList,QValueList<QCString>)";
00510     funcs << "QString requestSlave(QString,QString,QString)";
00511     funcs << "pid_t requestHoldSlave(KURL,QString)";
00512     funcs << "void waitForSlave(pid_t)";
00513     funcs << "void setLaunchEnv(QCString,QCString)";
00514     funcs << "void reparseConfiguration()";
00515 //    funcs << "void terminateKDE()";
00516     funcs << "void autoStart()";
00517     funcs << "void autoStart(int)";
00518     return funcs;
00519 }
00520 
00521 void KLauncher::setLaunchEnv(const QCString &name, const QCString &_value)
00522 {
00523    QCString value(_value);
00524    if (value.isNull())
00525       value = "";
00526    klauncher_header request_header;
00527    QByteArray requestData(name.length()+value.length()+2);
00528    memcpy(requestData.data(), name.data(), name.length()+1);
00529    memcpy(requestData.data()+name.length()+1, value.data(), value.length()+1);
00530    request_header.cmd = LAUNCHER_SETENV;
00531    request_header.arg_length = requestData.size();
00532    write(kdeinitSocket, &request_header, sizeof(request_header));
00533    write(kdeinitSocket, requestData.data(), request_header.arg_length);
00534 }
00535 
00536 /*
00537  * Read 'len' bytes from 'sock' into buffer.
00538  * returns -1 on failure, 0 on no data.
00539  */
00540 static int
00541 read_socket(int sock, char *buffer, int len)
00542 {
00543   ssize_t result;
00544   int bytes_left = len;
00545   while ( bytes_left > 0)
00546   {
00547      result = read(sock, buffer, bytes_left);
00548      if (result > 0)
00549      {
00550         buffer += result;
00551         bytes_left -= result;
00552      }
00553      else if (result == 0)
00554         return -1;
00555      else if ((result == -1) && (errno != EINTR))
00556         return -1;
00557   }
00558   return 0;
00559 }
00560 
00561 
00562 void
00563 KLauncher::slotKDEInitData(int)
00564 {
00565    klauncher_header request_header;
00566    QByteArray requestData;
00567    if( dontBlockReading )
00568    {
00569    // in case we get a request to start an application and data arrive
00570    // to kdeinitSocket at the same time, requestStart() will already
00571    // call slotKDEInitData(), so we must check there's still something
00572    // to read, otherwise this would block
00573       fd_set in;
00574       timeval tm = { 0, 0 };
00575       FD_ZERO ( &in );
00576       FD_SET( kdeinitSocket, &in );
00577       select( kdeinitSocket + 1, &in, 0, 0, &tm );
00578       if( !FD_ISSET( kdeinitSocket, &in ))
00579          return;
00580    }
00581    dontBlockReading = false;
00582    int result = read_socket(kdeinitSocket, (char *) &request_header,
00583                             sizeof( request_header));
00584    if (result == -1)
00585    {
00586       kdDebug() << "Exiting on read_socket errno: " << errno << endl;
00587       ::signal( SIGHUP, SIG_IGN);
00588       ::signal( SIGTERM, SIG_IGN);
00589       destruct(255); // Exit!
00590    }
00591    requestData.resize(request_header.arg_length);
00592    result = read_socket(kdeinitSocket, (char *) requestData.data(),
00593                         request_header.arg_length);
00594 
00595    if (request_header.cmd == LAUNCHER_DIED)
00596    {
00597      long *request_data;
00598      request_data = (long *) requestData.data();
00599      processDied(request_data[0], request_data[1]);
00600      return;
00601    }
00602    if (lastRequest && (request_header.cmd == LAUNCHER_OK))
00603    {
00604      long *request_data;
00605      request_data = (long *) requestData.data();
00606      lastRequest->pid = (pid_t) (*request_data);
00607      kdDebug(7016) << lastRequest->name << " (pid " << lastRequest->pid <<
00608         ") up and running." << endl;
00609      switch(lastRequest->dcop_service_type)
00610      {
00611        case KService::DCOP_None:
00612        {
00613          lastRequest->status = KLaunchRequest::Running;
00614          break;
00615        }
00616 
00617        case KService::DCOP_Unique:
00618        {
00619          lastRequest->status = KLaunchRequest::Launching;
00620          break;
00621        }
00622 
00623        case KService::DCOP_Wait:
00624        {
00625          lastRequest->status = KLaunchRequest::Launching;
00626          break;
00627        }
00628 
00629        case KService::DCOP_Multi:
00630        {
00631          lastRequest->status = KLaunchRequest::Launching;
00632          break;
00633        }
00634      }
00635      lastRequest = 0;
00636      return;
00637    }
00638    if (lastRequest && (request_header.cmd == LAUNCHER_ERROR))
00639    {
00640      lastRequest->status = KLaunchRequest::Error;
00641      if (!requestData.isEmpty())
00642         lastRequest->errorMsg = QString::fromUtf8((char *) requestData.data());
00643      lastRequest = 0;
00644      return;
00645    }
00646 
00647    kdWarning(7016) << "Unexpected command from KDEInit (" << (unsigned int) request_header.cmd
00648                  << ")" << endl;
00649 }
00650 
00651 void
00652 KLauncher::processDied(pid_t pid, long /* exitStatus */)
00653 {
00654    KLaunchRequest *request = requestList.first();
00655    for(; request; request = requestList.next())
00656    {
00657       if (request->pid == pid)
00658       {
00659          if (request->dcop_service_type == KService::DCOP_Wait)
00660             request->status = KLaunchRequest::Done;
00661          else if ((request->dcop_service_type == KService::DCOP_Unique) &&
00662         (dcopClient()->isApplicationRegistered(request->dcop_name)))
00663             request->status = KLaunchRequest::Running;
00664          else
00665             request->status = KLaunchRequest::Error;
00666          requestDone(request);
00667          return;
00668       }
00669    }
00670 }
00671 
00672 void
00673 KLauncher::slotAppRegistered(const QCString &appId)
00674 {
00675    const char *cAppId = appId.data();
00676    if (!cAppId) return;
00677 
00678    KLaunchRequest *request = requestList.first();
00679    KLaunchRequest *nextRequest;
00680    for(; request; request = nextRequest)
00681    {
00682       nextRequest = requestList.next();
00683       if (request->status != KLaunchRequest::Launching)
00684          continue;
00685 
00686       // For unique services check the requested service name first
00687       if ((request->dcop_service_type == KService::DCOP_Unique) &&
00688           ((appId == request->dcop_name) ||
00689            dcopClient()->isApplicationRegistered(request->dcop_name)))
00690       {
00691          request->status = KLaunchRequest::Running;
00692          requestDone(request);
00693          continue;
00694       }
00695 
00696       const char *rAppId = request->dcop_name.data();
00697       if (!rAppId) continue;
00698 
00699       int l = strlen(rAppId);
00700       if ((strncmp(rAppId, cAppId, l) == 0) &&
00701           ((cAppId[l] == '\0') || (cAppId[l] == '-')))
00702       {
00703          request->dcop_name = appId;
00704          request->status = KLaunchRequest::Running;
00705          requestDone(request);
00706          continue;
00707       }
00708    }
00709 }
00710 
00711 void
00712 KLauncher::autoStart(int phase)
00713 {
00714    if( mAutoStart.phase() >= phase )
00715        return;
00716    mAutoStart.setPhase(phase);
00717    if( newStartup )
00718    {
00719       if (phase == 0)
00720          mAutoStart.loadAutoStartList();
00721    }
00722    else
00723    {
00724       if (phase == 1)
00725          mAutoStart.loadAutoStartList();
00726    }
00727    mAutoTimer.start(0, true);
00728 }
00729 
00730 void
00731 KLauncher::slotAutoStart()
00732 {
00733    KService::Ptr s;
00734    do
00735    {
00736       QString service = mAutoStart.startService();
00737       if (service.isEmpty())
00738       {
00739          // Done
00740      if( !mAutoStart.phaseDone())
00741      {
00742         mAutoStart.setPhaseDone();
00743         // Emit signal
00744             if( newStartup )
00745             {
00746            QCString autoStartSignal;
00747                autoStartSignal.sprintf( "autoStart%dDone()", mAutoStart.phase());
00748                emitDCOPSignal(autoStartSignal, QByteArray());
00749             }
00750             else
00751             {
00752            QCString autoStartSignal( "autoStartDone()" );
00753            int phase = mAutoStart.phase();
00754            if ( phase > 1 )
00755                autoStartSignal.sprintf( "autoStart%dDone()", phase );
00756                emitDCOPSignal(autoStartSignal, QByteArray());
00757             }
00758      }
00759          return;
00760       }
00761       s = new KService(service);
00762    }
00763    while (!start_service(s, QStringList(), QValueList<QCString>(), "0", false, true));
00764    // Loop till we find a service that we can start.
00765 }
00766 
00767 void
00768 KLauncher::requestDone(KLaunchRequest *request)
00769 {
00770    if ((request->status == KLaunchRequest::Running) ||
00771        (request->status == KLaunchRequest::Done))
00772    {
00773       DCOPresult.result = 0;
00774       DCOPresult.dcopName = request->dcop_name;
00775       DCOPresult.error = QString::null;
00776       DCOPresult.pid = request->pid;
00777    }
00778    else
00779    {
00780       DCOPresult.result = 1;
00781       DCOPresult.dcopName = "";
00782       DCOPresult.error = i18n("KDEInit could not launch '%1'.").arg(request->name);
00783       if (!request->errorMsg.isEmpty())
00784          DCOPresult.error += ":\n" + request->errorMsg;
00785       DCOPresult.pid = 0;
00786 
00787 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00788 //#ifdef Q_WS_X11
00789       if (!request->startup_dpy.isEmpty())
00790       {
00791          Display* dpy = NULL;
00792          if( (mCached_dpy != NULL) &&
00793               (request->startup_dpy == XDisplayString( mCached_dpy )))
00794             dpy = mCached_dpy;
00795          if( dpy == NULL )
00796             dpy = XOpenDisplay( request->startup_dpy );
00797          if( dpy )
00798          {
00799             KStartupInfoId id;
00800             id.initId( request->startup_id );
00801             KStartupInfo::sendFinishX( dpy, id );
00802             if( mCached_dpy != dpy && mCached_dpy != NULL )
00803                XCloseDisplay( mCached_dpy );
00804             mCached_dpy = dpy;
00805          }
00806       }
00807 #endif
00808    }
00809 
00810    if (request->autoStart)
00811    {
00812       mAutoTimer.start(0, true);
00813    }
00814 
00815    if (request->transaction)
00816    {
00817       QByteArray replyData;
00818       QCString replyType;
00819       replyType = "serviceResult";
00820       QDataStream stream2(replyData, IO_WriteOnly);
00821       stream2 << DCOPresult.result << DCOPresult.dcopName << DCOPresult.error << DCOPresult.pid;
00822       dcopClient()->endTransaction( request->transaction,
00823                                     replyType, replyData);
00824    }
00825    requestList.removeRef( request );
00826 }
00827 
00828 void
00829 KLauncher::requestStart(KLaunchRequest *request)
00830 {
00831    requestList.append( request );
00832    // Send request to kdeinit.
00833    klauncher_header request_header;
00834    QByteArray requestData;
00835    int length = 0;
00836    length += sizeof(long); // Nr of. Args
00837    length += request->name.length() + 1; // Cmd
00838    for(QValueList<QCString>::Iterator it = request->arg_list.begin();
00839        it != request->arg_list.end();
00840        it++)
00841    {
00842       length += (*it).length() + 1; // Args...
00843    }
00844    length += sizeof(long); // Nr of. envs
00845    for(QValueList<QCString>::ConstIterator it = request->envs.begin();
00846        it != request->envs.end();
00847        it++)
00848    {
00849       length += (*it).length() + 1; // Envs...
00850    }
00851    length += sizeof( long ); // avoid_loops
00852 #ifdef Q_WS_X11
00853    bool startup_notify = !request->startup_id.isNull() && request->startup_id != "0";
00854    if( startup_notify )
00855        length += request->startup_id.length() + 1;
00856 #endif
00857    if (!request->cwd.isEmpty())
00858        length += request->cwd.length() + 1;
00859 
00860    requestData.resize( length );
00861 
00862    char *p = requestData.data();
00863    long l = request->arg_list.count()+1;
00864    memcpy(p, &l, sizeof(long));
00865    p += sizeof(long);
00866    strcpy(p, request->name.data());
00867    p += strlen(p) + 1;
00868    for(QValueList<QCString>::Iterator it = request->arg_list.begin();
00869        it != request->arg_list.end();
00870        it++)
00871    {
00872       strcpy(p, (*it).data());
00873       p += strlen(p) + 1;
00874    }
00875    l = request->envs.count();
00876    memcpy(p, &l, sizeof(long));
00877    p += sizeof(long);
00878    for(QValueList<QCString>::ConstIterator it = request->envs.begin();
00879        it != request->envs.end();
00880        it++)
00881    {
00882       strcpy(p, (*it).data());
00883       p += strlen(p) + 1;
00884    }
00885    l = 0; // avoid_loops, always false here
00886    memcpy(p, &l, sizeof(long));
00887    p += sizeof(long);
00888 #ifdef Q_WS_X11
00889    if( startup_notify )
00890    {
00891       strcpy(p, request->startup_id.data());
00892       p += strlen( p ) + 1;
00893    }
00894 #endif
00895    if (!request->cwd.isEmpty())
00896    {
00897       strcpy(p, request->cwd.data());
00898       p += strlen( p ) + 1;
00899    }
00900 #ifdef Q_WS_X11
00901    request_header.cmd = startup_notify ? LAUNCHER_EXT_EXEC : LAUNCHER_EXEC_NEW;
00902 #else
00903    request_header.cmd = LAUNCHER_EXEC_NEW;
00904 #endif
00905    request_header.arg_length = length;
00906    write(kdeinitSocket, &request_header, sizeof(request_header));
00907    write(kdeinitSocket, requestData.data(), request_header.arg_length);
00908 
00909    // Wait for pid to return.
00910    lastRequest = request;
00911    dontBlockReading = false;
00912    do {
00913       slotKDEInitData( kdeinitSocket );
00914    }
00915    while (lastRequest != 0);
00916    dontBlockReading = true;
00917 }
00918 
00919 void
00920 KLauncher::exec_blind( const QCString &name, const QValueList<QCString> &arg_list,
00921     const QValueList<QCString> &envs, const QCString& startup_id )
00922 {
00923    KLaunchRequest *request = new KLaunchRequest;
00924    request->autoStart = false;
00925    request->name = name;
00926    request->arg_list =  arg_list;
00927    request->dcop_name = 0;
00928    request->dcop_service_type = KService::DCOP_None;
00929    request->pid = 0;
00930    request->status = KLaunchRequest::Launching;
00931    request->transaction = 0; // No confirmation is send
00932    request->envs = envs;
00933    // Find service, if any - strip path if needed
00934    KService::Ptr service = KService::serviceByDesktopName( name.mid( name.findRev( '/' ) + 1 ));
00935    if (service != NULL)
00936        send_service_startup_info( request,  service,
00937            startup_id, QValueList< QCString >());
00938    else // no .desktop file, no startup info
00939        cancel_service_startup_info( request, startup_id, envs );
00940 
00941    requestStart(request);
00942    // We don't care about this request any longer....
00943    requestDone(request);
00944 }
00945 
00946 
00947 bool
00948 KLauncher::start_service_by_name(const QString &serviceName, const QStringList &urls,
00949     const QValueList<QCString> &envs, const QCString& startup_id, bool blind)
00950 {
00951    KService::Ptr service = 0;
00952    // Find service
00953    service = KService::serviceByName(serviceName);
00954    if (!service)
00955    {
00956       DCOPresult.result = ENOENT;
00957       DCOPresult.error = i18n("Could not find service '%1'.").arg(serviceName);
00958       cancel_service_startup_info( NULL, startup_id, envs ); // cancel it if any
00959       return false;
00960    }
00961    return start_service(service, urls, envs, startup_id, blind);
00962 }
00963 
00964 bool
00965 KLauncher::start_service_by_desktop_path(const QString &serviceName, const QStringList &urls,
00966     const QValueList<QCString> &envs, const QCString& startup_id, bool blind)
00967 {
00968    KService::Ptr service = 0;
00969    // Find service
00970    if (serviceName[0] == '/')
00971    {
00972       // Full path
00973       service = new KService(serviceName);
00974    }
00975    else
00976    {
00977       service = KService::serviceByDesktopPath(serviceName);
00978    }
00979    if (!service)
00980    {
00981       DCOPresult.result = ENOENT;
00982       DCOPresult.error = i18n("Could not find service '%1'.").arg(serviceName);
00983       cancel_service_startup_info( NULL, startup_id, envs ); // cancel it if any
00984       return false;
00985    }
00986    return start_service(service, urls, envs, startup_id, blind);
00987 }
00988 
00989 bool
00990 KLauncher::start_service_by_desktop_name(const QString &serviceName, const QStringList &urls,
00991     const QValueList<QCString> &envs, const QCString& startup_id, bool blind)
00992 {
00993    KService::Ptr service = 0;
00994    // Find service
00995    service = KService::serviceByDesktopName(serviceName);
00996    if (!service)
00997    {
00998       DCOPresult.result = ENOENT;
00999       DCOPresult.error = i18n("Could not find service '%1'.").arg(serviceName);
01000       cancel_service_startup_info( NULL, startup_id, envs ); // cancel it if any
01001       return false;
01002    }
01003    return start_service(service, urls, envs, startup_id, blind);
01004 }
01005 
01006 bool
01007 KLauncher::start_service(KService::Ptr service, const QStringList &_urls,
01008     const QValueList<QCString> &envs, const QCString& startup_id, bool blind, bool autoStart)
01009 {
01010    QStringList urls = _urls;
01011    if (!service->isValid())
01012    {
01013       DCOPresult.result = ENOEXEC;
01014       DCOPresult.error = i18n("Service '%1' is malformatted.").arg(service->desktopEntryPath());
01015       cancel_service_startup_info( NULL, startup_id, envs ); // cancel it if any
01016       return false;
01017    }
01018    KLaunchRequest *request = new KLaunchRequest;
01019    request->autoStart = autoStart;
01020 
01021    if ((urls.count() > 1) && !service->allowMultipleFiles())
01022    {
01023       // We need to launch the application N times. That sucks.
01024       // We ignore the result for application 2 to N.
01025       // For the first file we launch the application in the
01026       // usual way. The reported result is based on this
01027       // application.
01028       QStringList::ConstIterator it = urls.begin();
01029       for(++it;
01030           it != urls.end();
01031           ++it)
01032       {
01033          QStringList singleUrl;
01034          singleUrl.append(*it);
01035          QCString startup_id2 = startup_id;
01036          if( !startup_id2.isEmpty() && startup_id2 != "0" )
01037              startup_id2 = "0"; // can't use the same startup_id several times
01038          start_service( service, singleUrl, envs, startup_id2, true);
01039       }
01040       QString firstURL = *(urls.begin());
01041       urls.clear();
01042       urls.append(firstURL);
01043    }
01044    createArgs(request, service, urls);
01045 
01046    // We must have one argument at least!
01047    if (!request->arg_list.count())
01048    {
01049       DCOPresult.result = ENOEXEC;
01050       DCOPresult.error = i18n("Service '%1' is malformatted.").arg(service->desktopEntryPath());
01051       delete request;
01052       cancel_service_startup_info( NULL, startup_id, envs );
01053       return false;
01054    }
01055 
01056    request->name = request->arg_list.first();
01057    request->arg_list.remove(request->arg_list.begin());
01058 
01059    request->dcop_service_type =  service->DCOPServiceType();
01060 
01061    if ((request->dcop_service_type == KService::DCOP_Unique) ||
01062        (request->dcop_service_type == KService::DCOP_Multi))
01063    {
01064       QVariant v = service->property("X-DCOP-ServiceName");
01065       if (v.isValid())
01066          request->dcop_name = v.toString().utf8();
01067       if (request->dcop_name.isEmpty())
01068       {
01069          request->dcop_name = QFile::encodeName(KRun::binaryName(service->exec(), true));
01070       }
01071    }
01072 
01073    request->pid = 0;
01074    request->transaction = 0;
01075    request->envs = envs;
01076    send_service_startup_info( request, service, startup_id, envs );
01077 
01078    // Request will be handled later.
01079    if (!blind && !autoStart)
01080    {
01081       request->transaction = dcopClient()->beginTransaction();
01082    }
01083    queueRequest(request);
01084    return true;
01085 }
01086 
01087 void
01088 KLauncher::send_service_startup_info( KLaunchRequest *request, KService::Ptr service, const QCString& startup_id,
01089     const QValueList<QCString> &envs )
01090 {
01091 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
01092 //#ifdef Q_WS_X11 // KStartup* isn't implemented for Qt/Embedded yet
01093     request->startup_id = "0";
01094     if( startup_id == "0" )
01095         return;
01096     bool silent;
01097     QCString wmclass;
01098     if( !KRun::checkStartupNotify( QString::null, service, &silent, &wmclass ))
01099         return;
01100     KStartupInfoId id;
01101     id.initId( startup_id );
01102     const char* dpy_str = NULL;
01103     for( QValueList<QCString>::ConstIterator it = envs.begin();
01104          it != envs.end();
01105          ++it )
01106         if( strncmp( *it, "DISPLAY=", 8 ) == 0 )
01107             dpy_str = static_cast< const char* >( *it ) + 8;
01108     Display* dpy = NULL;
01109     if( dpy_str != NULL && mCached_dpy != NULL
01110         && qstrcmp( dpy_str, XDisplayString( mCached_dpy )) == 0 )
01111         dpy = mCached_dpy;
01112     if( dpy == NULL )
01113         dpy = XOpenDisplay( dpy_str );
01114     request->startup_id = id.id();
01115     if( dpy == NULL )
01116     {
01117         cancel_service_startup_info( request, startup_id, envs );
01118         return;
01119     }
01120 
01121     request->startup_dpy = dpy_str;
01122 
01123     KStartupInfoData data;
01124     data.setName( service->name());
01125     data.setIcon( service->icon());
01126     data.setDescription( i18n( "Launching %1" ).arg( service->name()));
01127     if( !wmclass.isEmpty())
01128         data.setWMClass( wmclass );
01129     if( silent )
01130         data.setSilent( KStartupInfoData::Yes );
01131     // the rest will be sent by kdeinit
01132     KStartupInfo::sendStartupX( dpy, id, data );
01133     if( mCached_dpy != dpy && mCached_dpy != NULL )
01134         XCloseDisplay( mCached_dpy );
01135     mCached_dpy = dpy;
01136     return;
01137 #else
01138     return;
01139 #endif
01140 }
01141 
01142 void
01143 KLauncher::cancel_service_startup_info( KLaunchRequest* request, const QCString& startup_id,
01144     const QValueList<QCString> &envs )
01145 {
01146 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
01147 //#ifdef Q_WS_X11 // KStartup* isn't implemented for Qt/Embedded yet
01148     if( request != NULL )
01149         request->startup_id = "0";
01150     if( !startup_id.isEmpty() && startup_id != "0" )
01151     {
01152         const char* dpy_str = NULL;
01153         for( QValueList<QCString>::ConstIterator it = envs.begin();
01154              it != envs.end();
01155              ++it )
01156             if( strncmp( *it, "DISPLAY=", 8 ) == 0 )
01157                 dpy_str = static_cast< const char* >( *it ) + 8;
01158         Display* dpy = NULL;
01159         if( dpy_str != NULL && mCached_dpy != NULL
01160             && qstrcmp( dpy_str, XDisplayString( mCached_dpy )) == 0 )
01161             dpy = mCached_dpy;
01162         if( dpy == NULL )
01163             dpy = XOpenDisplay( dpy_str );
01164         if( dpy == NULL )
01165             return;
01166         KStartupInfoId id;
01167         id.initId( startup_id );
01168         KStartupInfo::sendFinishX( dpy, id );
01169         if( mCached_dpy != dpy && mCached_dpy != NULL )
01170            XCloseDisplay( mCached_dpy );
01171         mCached_dpy = dpy;
01172     }
01173 #endif
01174 }
01175 
01176 bool
01177 KLauncher::kdeinit_exec(const QString &app, const QStringList &args,
01178    const QValueList<QCString> &envs, QCString startup_id, bool wait)
01179 {
01180    KLaunchRequest *request = new KLaunchRequest;
01181    request->autoStart = false;
01182 
01183    for(QStringList::ConstIterator it = args.begin();
01184        it != args.end();
01185        it++)
01186    {
01187        QString arg = *it;
01188        request->arg_list.append(arg.local8Bit());
01189    }
01190 
01191    request->name = app.local8Bit();
01192 
01193    if (wait)
01194       request->dcop_service_type = KService::DCOP_Wait;
01195    else
01196       request->dcop_service_type = KService::DCOP_None;
01197    request->dcop_name = 0;
01198    request->pid = 0;
01199 #ifdef Q_WS_X11
01200    request->startup_id = startup_id;
01201 #endif
01202    request->envs = envs;
01203    if( app != "kbuildsycoca" ) // avoid stupid loop
01204    {
01205        // Find service, if any - strip path if needed
01206        KService::Ptr service = KService::serviceByDesktopName( app.mid( app.findRev( '/' ) + 1 ));
01207        if (service != NULL)
01208            send_service_startup_info( request,  service,
01209                startup_id, QValueList< QCString >());
01210        else // no .desktop file, no startup info
01211            cancel_service_startup_info( request, startup_id, envs );
01212    }
01213    request->transaction = dcopClient()->beginTransaction();
01214    queueRequest(request);
01215    return true;
01216 }
01217 
01218 void
01219 KLauncher::queueRequest(KLaunchRequest *request)
01220 {
01221    requestQueue.append( request );
01222    if (!bProcessingQueue)
01223    {
01224       bProcessingQueue = true;
01225       QTimer::singleShot(0, this, SLOT( slotDequeue() ));
01226    }
01227 }
01228 
01229 void
01230 KLauncher::slotDequeue()
01231 {
01232    do {
01233       KLaunchRequest *request = requestQueue.take(0);
01234       // process request
01235       request->status = KLaunchRequest::Launching;
01236       requestStart(request);
01237       if (request->status != KLaunchRequest::Launching)
01238       {
01239          // Request handled.
01240          requestDone( request );
01241          continue;
01242       }
01243    } while(requestQueue.count());
01244    bProcessingQueue = false;
01245 }
01246 
01247 void
01248 KLauncher::createArgs( KLaunchRequest *request, const KService::Ptr service ,
01249                        const QStringList &urls)
01250 {
01251   QStringList params = KRun::processDesktopExec(*service, urls, false);
01252 
01253   for(QStringList::ConstIterator it = params.begin();
01254       it != params.end(); ++it)
01255   {
01256      request->arg_list.append((*it).local8Bit());
01257   }
01258   request->cwd = QFile::encodeName(service->path());
01259 }
01260 
01262 
01263 pid_t
01264 KLauncher::requestHoldSlave(const KURL &url, const QString &app_socket)
01265 {
01266     IdleSlave *slave;
01267     for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
01268     {
01269        if (slave->onHold(url))
01270           break;
01271     }
01272     if (slave)
01273     {
01274        mSlaveList.removeRef(slave);
01275        slave->connect(app_socket);
01276        return slave->pid();
01277     }
01278     return 0;
01279 }
01280 
01281 
01282 pid_t
01283 KLauncher::requestSlave(const QString &protocol,
01284                         const QString &host,
01285                         const QString &app_socket,
01286                         QString &error)
01287 {
01288     IdleSlave *slave;
01289     for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
01290     {
01291        if (slave->match(protocol, host, true))
01292           break;
01293     }
01294     if (!slave)
01295     {
01296        for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
01297        {
01298           if (slave->match(protocol, host, false))
01299              break;
01300        }
01301     }
01302     if (!slave)
01303     {
01304        for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
01305        {
01306           if (slave->match(protocol, QString::null, false))
01307              break;
01308        }
01309     }
01310     if (slave)
01311     {
01312        mSlaveList.removeRef(slave);
01313        slave->connect(app_socket);
01314        return slave->pid();
01315     }
01316 
01317     QString _name = KProtocolInfo::exec(protocol);
01318     if (_name.isEmpty())
01319     {
01320     error = i18n("Unknown protocol '%1'.\n").arg(protocol);
01321         return 0;
01322     }
01323 
01324     QCString name = _name.latin1(); // ex: "kio_ftp"
01325     QCString arg1 = protocol.latin1();
01326     QCString arg2 = QFile::encodeName(mPoolSocketName);
01327     QCString arg3 = QFile::encodeName(app_socket);
01328     QValueList<QCString> arg_list;
01329     arg_list.append(arg1);
01330     arg_list.append(arg2);
01331     arg_list.append(arg3);
01332 
01333 //    kdDebug(7016) << "KLauncher: launching new slave " << _name << " with protocol=" << protocol << endl;
01334     if (mSlaveDebug == arg1)
01335     {
01336        klauncher_header request_header;
01337        request_header.cmd = LAUNCHER_DEBUG_WAIT;
01338        request_header.arg_length = 0;
01339        write(kdeinitSocket, &request_header, sizeof(request_header));
01340     }
01341     if (mSlaveValgrind == arg1)
01342     {
01343        arg_list.prepend(QFile::encodeName(KLibLoader::findLibrary(name)));
01344        arg_list.prepend(QFile::encodeName(locate("exe", "kioslave")));
01345        name = "valgrind";
01346        if (!mSlaveValgrindSkin.isEmpty()) {
01347            arg_list.prepend(QCString("--tool=") + mSlaveValgrindSkin);
01348        } else
01349        arg_list.prepend("--tool=memcheck");
01350     }
01351 
01352     KLaunchRequest *request = new KLaunchRequest;
01353     request->autoStart = false;
01354     request->name = name;
01355     request->arg_list =  arg_list;
01356     request->dcop_name = 0;
01357     request->dcop_service_type = KService::DCOP_None;
01358     request->pid = 0;
01359 #ifdef Q_WS_X11
01360     request->startup_id = "0";
01361 #endif
01362     request->status = KLaunchRequest::Launching;
01363     request->transaction = 0; // No confirmation is send
01364     requestStart(request);
01365     pid_t pid = request->pid;
01366 
01367 //    kdDebug(7016) << "Slave launched, pid = " << pid << endl;
01368 
01369     // We don't care about this request any longer....
01370     requestDone(request);
01371     if (!pid)
01372     {
01373        error = i18n("Error loading '%1'.\n").arg(name);
01374     }
01375     return pid;
01376 }
01377 
01378 void
01379 KLauncher::waitForSlave(pid_t pid)
01380 {
01381     IdleSlave *slave;
01382     for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
01383     {
01384         if (slave->pid() == pid)
01385            return; // Already here.
01386     }
01387     SlaveWaitRequest *waitRequest = new SlaveWaitRequest;
01388     waitRequest->transaction = dcopClient()->beginTransaction();
01389     waitRequest->pid = pid;
01390     mSlaveWaitRequest.append(waitRequest);
01391 }
01392 
01393 void
01394 KLauncher::acceptSlave(KSocket *slaveSocket)
01395 {
01396     IdleSlave *slave = new IdleSlave(slaveSocket);
01397     // Send it a SLAVE_STATUS command.
01398     mSlaveList.append(slave);
01399     connect(slave, SIGNAL(destroyed()), this, SLOT(slotSlaveGone()));
01400     connect(slave, SIGNAL(statusUpdate(IdleSlave *)),
01401         this, SLOT(slotSlaveStatus(IdleSlave *)));
01402     if (!mTimer.isActive())
01403     {
01404        mTimer.start(1000*10);
01405     }
01406 }
01407 
01408 void
01409 KLauncher::slotSlaveStatus(IdleSlave *slave)
01410 {
01411     SlaveWaitRequest *waitRequest = mSlaveWaitRequest.first();
01412     while(waitRequest)
01413     {
01414        if (waitRequest->pid == slave->pid())
01415        {
01416           QByteArray replyData;
01417           QCString replyType;
01418           replyType = "void";
01419           dcopClient()->endTransaction( waitRequest->transaction, replyType, replyData);
01420           mSlaveWaitRequest.removeRef(waitRequest);
01421           waitRequest = mSlaveWaitRequest.current();
01422        }
01423        else
01424        {
01425           waitRequest = mSlaveWaitRequest.next();
01426        }
01427     }
01428 }
01429 
01430 void
01431 KLauncher::slotSlaveGone()
01432 {
01433     IdleSlave *slave = (IdleSlave *) sender();
01434     mSlaveList.removeRef(slave);
01435     if ((mSlaveList.count() == 0) && (mTimer.isActive()))
01436     {
01437        mTimer.stop();
01438     }
01439 }
01440 
01441 void
01442 KLauncher::idleTimeout()
01443 {
01444     bool keepOneFileSlave=true;
01445     time_t now = time(0);
01446     IdleSlave *slave;
01447     for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
01448     {
01449         if ((slave->protocol()=="file") && (keepOneFileSlave))
01450            keepOneFileSlave=false;
01451         else if (slave->age(now) > SLAVE_MAX_IDLE)
01452         {
01453            // killing idle slave
01454            delete slave;
01455         }
01456     }
01457 }
01458 
01459 #include "klauncher.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys