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