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