KIO
slavebase.cpp
Go to the documentation of this file.
00001 /* 00002 * This file is part of the KDE libraries 00003 * Copyright (c) 2000 Waldo Bastian <bastian@kde.org> 00004 * Copyright (c) 2000 David Faure <faure@kde.org> 00005 * Copyright (c) 2000 Stephan Kulow <coolo@kde.org> 00006 * Copyright (c) 2007 Thiago Macieira <thiago@kde.org> 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Library General Public 00010 * License version 2 as published by the Free Software Foundation. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Library General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Library General Public License 00018 * along with this library; see the file COPYING.LIB. If not, write to 00019 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 * Boston, MA 02110-1301, USA. 00021 * 00022 **/ 00023 00024 #include "slavebase.h" 00025 00026 #include <config.h> 00027 00028 #include <sys/time.h> 00029 00030 #include <kdebug.h> 00031 #include <stdlib.h> 00032 #include <errno.h> 00033 #include <unistd.h> 00034 #include <signal.h> 00035 #include <time.h> 00036 00037 #include <QtCore/QFile> 00038 #include <QtCore/QList> 00039 #include <QtCore/QDateTime> 00040 #include <QtCore/QCoreApplication> 00041 00042 #include <kcrash.h> 00043 #include <kconfig.h> 00044 #include <kconfiggroup.h> 00045 #include <kde_file.h> 00046 #include <klocale.h> 00047 00048 #include "kremoteencoding.h" 00049 00050 #include "connection.h" 00051 #include "ioslave_defaults.h" 00052 #include "slaveinterface.h" 00053 #include "kpasswdserver_p.h" 00054 00055 #ifndef NDEBUG 00056 #ifdef HAVE_BACKTRACE 00057 #include <execinfo.h> 00058 #endif 00059 #endif 00060 00061 extern "C" { 00062 static void sigsegv_handler(int sig); 00063 static void sigpipe_handler(int sig); 00064 } 00065 00066 using namespace KIO; 00067 00068 typedef QList<QByteArray> AuthKeysList; 00069 typedef QMap<QString,QByteArray> AuthKeysMap; 00070 #define KIO_DATA QByteArray data; QDataStream stream( &data, QIODevice::WriteOnly ); stream 00071 #define KIO_FILESIZE_T(x) quint64(x) 00072 00073 namespace KIO { 00074 00075 class SlaveBasePrivate { 00076 public: 00077 SlaveBase* q; 00078 SlaveBasePrivate(SlaveBase* owner): q(owner), m_passwdServer(0) {} 00079 ~SlaveBasePrivate() { delete m_passwdServer; } 00080 00081 UDSEntryList pendingListEntries; 00082 int listEntryCurrentSize; 00083 long listEntry_sec, listEntry_usec; 00084 Connection appConnection; 00085 QString poolSocket; 00086 bool isConnectedToApp; 00087 static qlonglong s_seqNr; 00088 00089 QString slaveid; 00090 bool resume:1; 00091 bool needSendCanResume:1; 00092 bool onHold:1; 00093 bool wasKilled:1; 00094 bool inOpenLoop:1; 00095 bool exit_loop:1; 00096 MetaData configData; 00097 KConfig *config; 00098 KConfigGroup *configGroup; 00099 KUrl onHoldUrl; 00100 00101 struct timeval last_tv; 00102 KIO::filesize_t totalSize; 00103 KIO::filesize_t sentListEntries; 00104 KRemoteEncoding *remotefile; 00105 time_t timeout; 00106 enum { Idle, InsideMethod, FinishedCalled, ErrorCalled } m_state; 00107 QByteArray timeoutData; 00108 00109 KPasswdServer* m_passwdServer; 00110 00111 // Reconstructs configGroup from configData and mIncomingMetaData 00112 void rebuildConfig() 00113 { 00114 configGroup->deleteGroup(KConfigGroup::WriteConfigFlags()); 00115 00116 // mIncomingMetaData cascades over config, so we write config first, 00117 // to let it be overwritten 00118 MetaData::ConstIterator end = configData.constEnd(); 00119 for (MetaData::ConstIterator it = configData.constBegin(); it != end; ++it) 00120 configGroup->writeEntry(it.key(), it->toUtf8(), KConfigGroup::WriteConfigFlags()); 00121 00122 end = q->mIncomingMetaData.constEnd(); 00123 for (MetaData::ConstIterator it = q->mIncomingMetaData.constBegin(); it != end; ++it) 00124 configGroup->writeEntry(it.key(), it->toUtf8(), KConfigGroup::WriteConfigFlags()); 00125 } 00126 00127 void verifyState(const char* cmdName) 00128 { 00129 if ((m_state != FinishedCalled) && (m_state != ErrorCalled)){ 00130 kWarning(7019) << cmdName << "did not call finished() or error()! Please fix the KIO slave."; 00131 } 00132 } 00133 00134 void verifyErrorFinishedNotCalled(const char* cmdName) 00135 { 00136 if (m_state == FinishedCalled || m_state == ErrorCalled) { 00137 kWarning(7019) << cmdName << "called finished() or error(), but it's not supposed to! Please fix the KIO slave."; 00138 } 00139 } 00140 00141 KPasswdServer* passwdServer() 00142 { 00143 if (!m_passwdServer) { 00144 m_passwdServer = new KPasswdServer; 00145 } 00146 00147 return m_passwdServer; 00148 } 00149 }; 00150 00151 } 00152 00153 static SlaveBase *globalSlave; 00154 qlonglong SlaveBasePrivate::s_seqNr; 00155 00156 static volatile bool slaveWriteError = false; 00157 00158 static const char *s_protocol; 00159 00160 #ifdef Q_OS_UNIX 00161 extern "C" { 00162 static void genericsig_handler(int sigNumber) 00163 { 00164 KDE_signal(sigNumber,SIG_IGN); 00165 //WABA: Don't do anything that requires malloc, we can deadlock on it since 00166 //a SIGTERM signal can come in while we are in malloc/free. 00167 //kDebug()<<"kioslave : exiting due to signal "<<sigNumber; 00168 //set the flag which will be checked in dispatchLoop() and which *should* be checked 00169 //in lengthy operations in the various slaves 00170 if (globalSlave!=0) 00171 globalSlave->setKillFlag(); 00172 KDE_signal(SIGALRM,SIG_DFL); 00173 alarm(5); //generate an alarm signal in 5 seconds, in this time the slave has to exit 00174 } 00175 } 00176 #endif 00177 00179 00180 SlaveBase::SlaveBase( const QByteArray &protocol, 00181 const QByteArray &pool_socket, 00182 const QByteArray &app_socket ) 00183 : mProtocol(protocol), 00184 d(new SlaveBasePrivate(this)) 00185 00186 { 00187 d->poolSocket = QFile::decodeName(pool_socket); 00188 s_protocol = protocol.data(); 00189 #ifdef Q_OS_UNIX 00190 if (qgetenv("KDE_DEBUG").isEmpty()) 00191 { 00192 KCrash::setCrashHandler( sigsegv_handler ); 00193 KDE_signal(SIGILL,&sigsegv_handler); 00194 KDE_signal(SIGTRAP,&sigsegv_handler); 00195 KDE_signal(SIGABRT,&sigsegv_handler); 00196 KDE_signal(SIGBUS,&sigsegv_handler); 00197 KDE_signal(SIGALRM,&sigsegv_handler); 00198 KDE_signal(SIGFPE,&sigsegv_handler); 00199 #ifdef SIGPOLL 00200 KDE_signal(SIGPOLL, &sigsegv_handler); 00201 #endif 00202 #ifdef SIGSYS 00203 KDE_signal(SIGSYS, &sigsegv_handler); 00204 #endif 00205 #ifdef SIGVTALRM 00206 KDE_signal(SIGVTALRM, &sigsegv_handler); 00207 #endif 00208 #ifdef SIGXCPU 00209 KDE_signal(SIGXCPU, &sigsegv_handler); 00210 #endif 00211 #ifdef SIGXFSZ 00212 KDE_signal(SIGXFSZ, &sigsegv_handler); 00213 #endif 00214 } 00215 00216 struct sigaction act; 00217 act.sa_handler = sigpipe_handler; 00218 sigemptyset( &act.sa_mask ); 00219 act.sa_flags = 0; 00220 sigaction( SIGPIPE, &act, 0 ); 00221 00222 KDE_signal(SIGINT,&genericsig_handler); 00223 KDE_signal(SIGQUIT,&genericsig_handler); 00224 KDE_signal(SIGTERM,&genericsig_handler); 00225 #endif 00226 00227 globalSlave=this; 00228 00229 d->listEntryCurrentSize = 100; 00230 struct timeval tp; 00231 gettimeofday(&tp, 0); 00232 d->listEntry_sec = tp.tv_sec; 00233 d->listEntry_usec = tp.tv_usec; 00234 d->isConnectedToApp = true; 00235 00236 // by kahl for netmgr (need a way to identify slaves) 00237 d->slaveid = protocol; 00238 d->slaveid += QString::number(getpid()); 00239 d->resume = false; 00240 d->needSendCanResume = false; 00241 d->config = new KConfig(QString(), KConfig::SimpleConfig); 00242 // The KConfigGroup needs the KConfig to exist during its whole lifetime. 00243 d->configGroup = new KConfigGroup(d->config, QString()); 00244 d->onHold = false; 00245 d->wasKilled=false; 00246 d->last_tv.tv_sec = 0; 00247 d->last_tv.tv_usec = 0; 00248 // d->processed_size = 0; 00249 d->totalSize=0; 00250 d->sentListEntries=0; 00251 d->timeout = 0; 00252 connectSlave(QFile::decodeName(app_socket)); 00253 00254 d->remotefile = 0; 00255 d->inOpenLoop = false; 00256 d->exit_loop = false; 00257 } 00258 00259 SlaveBase::~SlaveBase() 00260 { 00261 delete d->configGroup; 00262 delete d->config; 00263 delete d->remotefile; 00264 delete d; 00265 s_protocol = ""; 00266 } 00267 00268 void SlaveBase::dispatchLoop() 00269 { 00270 while (!d->exit_loop) { 00271 if (d->timeout && (d->timeout < time(0))) { 00272 QByteArray data = d->timeoutData; 00273 d->timeout = 0; 00274 d->timeoutData = QByteArray(); 00275 special(data); 00276 } 00277 00278 Q_ASSERT(d->appConnection.inited()); 00279 00280 int ms = -1; 00281 if (d->timeout) 00282 ms = 1000 * qMax<time_t>(d->timeout - time(0), 1); 00283 00284 int ret = -1; 00285 if (d->appConnection.hasTaskAvailable() || d->appConnection.waitForIncomingTask(ms)) { 00286 // dispatch application messages 00287 int cmd; 00288 QByteArray data; 00289 ret = d->appConnection.read(&cmd, data); 00290 00291 if (ret != -1) { 00292 if (d->inOpenLoop) 00293 dispatchOpenCommand(cmd, data); 00294 else 00295 dispatch(cmd, data); 00296 } 00297 } else { 00298 ret = d->appConnection.isConnected() ? 0 : -1; 00299 } 00300 00301 if (ret == -1) { // some error occurred, perhaps no more application 00302 // When the app exits, should the slave be put back in the pool ? 00303 if (!d->exit_loop && d->isConnectedToApp && !d->poolSocket.isEmpty()) { 00304 disconnectSlave(); 00305 d->isConnectedToApp = false; 00306 closeConnection(); 00307 connectSlave(d->poolSocket); 00308 } else { 00309 break; 00310 } 00311 } 00312 00313 //I think we get here when we were killed in dispatch() and not in select() 00314 if (wasKilled()) { 00315 kDebug(7019) << "slave was killed, returning"; 00316 break; 00317 } 00318 00319 // execute deferred deletes 00320 QCoreApplication::sendPostedEvents(NULL, QEvent::DeferredDelete); 00321 } 00322 00323 // execute deferred deletes 00324 QCoreApplication::sendPostedEvents(NULL, QEvent::DeferredDelete); 00325 } 00326 00327 void SlaveBase::connectSlave(const QString &address) 00328 { 00329 d->appConnection.connectToRemote(address); 00330 00331 if (!d->appConnection.inited()) 00332 { 00333 kDebug(7019) << "failed to connect to" << address << endl 00334 << "Reason:" << d->appConnection.errorString(); 00335 exit(); 00336 return; 00337 } 00338 00339 d->inOpenLoop = false; 00340 } 00341 00342 void SlaveBase::disconnectSlave() 00343 { 00344 d->appConnection.close(); 00345 } 00346 00347 void SlaveBase::setMetaData(const QString &key, const QString &value) 00348 { 00349 mOutgoingMetaData.insert(key, value); // replaces existing key if already there 00350 } 00351 00352 QString SlaveBase::metaData(const QString &key) const 00353 { 00354 if (mIncomingMetaData.contains(key)) 00355 return mIncomingMetaData[key]; 00356 if (d->configData.contains(key)) 00357 return d->configData[key]; 00358 return QString(); 00359 } 00360 00361 MetaData SlaveBase::allMetaData() const 00362 { 00363 return mIncomingMetaData; 00364 } 00365 00366 bool SlaveBase::hasMetaData(const QString &key) const 00367 { 00368 if (mIncomingMetaData.contains(key)) 00369 return true; 00370 if (d->configData.contains(key)) 00371 return true; 00372 return false; 00373 } 00374 00375 KConfigGroup *SlaveBase::config() 00376 { 00377 return d->configGroup; 00378 } 00379 00380 void SlaveBase::sendMetaData() 00381 { 00382 sendAndKeepMetaData(); 00383 mOutgoingMetaData.clear(); 00384 } 00385 00386 void SlaveBase::sendAndKeepMetaData() 00387 { 00388 if (!mOutgoingMetaData.isEmpty()) { 00389 KIO_DATA << mOutgoingMetaData; 00390 00391 send(INF_META_DATA, data); 00392 } 00393 } 00394 00395 KRemoteEncoding *SlaveBase::remoteEncoding() 00396 { 00397 if (d->remotefile) 00398 return d->remotefile; 00399 00400 const QByteArray charset (metaData(QLatin1String("Charset")).toLatin1()); 00401 return (d->remotefile = new KRemoteEncoding( charset )); 00402 } 00403 00404 void SlaveBase::data( const QByteArray &data ) 00405 { 00406 sendMetaData(); 00407 send( MSG_DATA, data ); 00408 } 00409 00410 void SlaveBase::dataReq( ) 00411 { 00412 //sendMetaData(); 00413 if (d->needSendCanResume) 00414 canResume(0); 00415 send( MSG_DATA_REQ ); 00416 } 00417 00418 void SlaveBase::opened() 00419 { 00420 sendMetaData(); 00421 send( MSG_OPENED ); 00422 d->inOpenLoop = true; 00423 } 00424 00425 void SlaveBase::error( int _errid, const QString &_text ) 00426 { 00427 if (d->m_state == d->ErrorCalled) { 00428 kWarning(7019) << "error() called twice! Please fix the KIO slave."; 00429 return; 00430 } else if (d->m_state == d->FinishedCalled) { 00431 kWarning(7019) << "error() called after finished()! Please fix the KIO slave."; 00432 return; 00433 } 00434 00435 d->m_state = d->ErrorCalled; 00436 mIncomingMetaData.clear(); // Clear meta data 00437 d->rebuildConfig(); 00438 mOutgoingMetaData.clear(); 00439 KIO_DATA << (qint32) _errid << _text; 00440 00441 send( MSG_ERROR, data ); 00442 //reset 00443 d->listEntryCurrentSize = 100; 00444 d->sentListEntries=0; 00445 d->totalSize=0; 00446 d->inOpenLoop=false; 00447 } 00448 00449 void SlaveBase::connected() 00450 { 00451 send( MSG_CONNECTED ); 00452 } 00453 00454 void SlaveBase::finished() 00455 { 00456 if (d->m_state == d->FinishedCalled) { 00457 kWarning(7019) << "finished() called twice! Please fix the KIO slave."; 00458 return; 00459 } else if (d->m_state == d->ErrorCalled) { 00460 kWarning(7019) << "finished() called after error()! Please fix the KIO slave."; 00461 return; 00462 } 00463 00464 d->m_state = d->FinishedCalled; 00465 mIncomingMetaData.clear(); // Clear meta data 00466 d->rebuildConfig(); 00467 sendMetaData(); 00468 send( MSG_FINISHED ); 00469 00470 // reset 00471 d->listEntryCurrentSize = 100; 00472 d->sentListEntries=0; 00473 d->totalSize=0; 00474 d->inOpenLoop=false; 00475 } 00476 00477 void SlaveBase::needSubUrlData() 00478 { 00479 send( MSG_NEED_SUBURL_DATA ); 00480 } 00481 00482 /* 00483 * Map pid_t to a signed integer type that makes sense for QByteArray; 00484 * only the most common sizes 16 bit and 32 bit are special-cased. 00485 */ 00486 template<int T> struct PIDType { typedef pid_t PID_t; } ; 00487 template<> struct PIDType<2> { typedef qint16 PID_t; } ; 00488 template<> struct PIDType<4> { typedef qint32 PID_t; } ; 00489 00490 void SlaveBase::slaveStatus( const QString &host, bool connected ) 00491 { 00492 pid_t pid = getpid(); 00493 qint8 b = connected ? 1 : 0; 00494 KIO_DATA << (PIDType<sizeof(pid_t)>::PID_t)pid << mProtocol << host << b; 00495 if (d->onHold) 00496 stream << d->onHoldUrl; 00497 send( MSG_SLAVE_STATUS, data ); 00498 } 00499 00500 void SlaveBase::canResume() 00501 { 00502 send( MSG_CANRESUME ); 00503 } 00504 00505 void SlaveBase::totalSize( KIO::filesize_t _bytes ) 00506 { 00507 KIO_DATA << KIO_FILESIZE_T(_bytes); 00508 send( INF_TOTAL_SIZE, data ); 00509 00510 //this one is usually called before the first item is listed in listDir() 00511 struct timeval tp; 00512 gettimeofday(&tp, 0); 00513 d->listEntry_sec = tp.tv_sec; 00514 d->listEntry_usec = tp.tv_usec; 00515 d->totalSize=_bytes; 00516 d->sentListEntries=0; 00517 } 00518 00519 void SlaveBase::processedSize( KIO::filesize_t _bytes ) 00520 { 00521 bool emitSignal=false; 00522 struct timeval tv; 00523 int gettimeofday_res=gettimeofday( &tv, 0L ); 00524 00525 if( _bytes == d->totalSize ) 00526 emitSignal=true; 00527 else if ( gettimeofday_res == 0 ) { 00528 time_t msecdiff = 2000; 00529 if (d->last_tv.tv_sec) { 00530 // Compute difference, in ms 00531 msecdiff = 1000 * ( tv.tv_sec - d->last_tv.tv_sec ); 00532 time_t usecdiff = tv.tv_usec - d->last_tv.tv_usec; 00533 if ( usecdiff < 0 ) { 00534 msecdiff--; 00535 msecdiff += 1000; 00536 } 00537 msecdiff += usecdiff / 1000; 00538 } 00539 emitSignal=msecdiff >= 100; // emit size 10 times a second 00540 } 00541 00542 if( emitSignal ) { 00543 KIO_DATA << KIO_FILESIZE_T(_bytes); 00544 send( INF_PROCESSED_SIZE, data ); 00545 if ( gettimeofday_res == 0 ) { 00546 d->last_tv.tv_sec = tv.tv_sec; 00547 d->last_tv.tv_usec = tv.tv_usec; 00548 } 00549 } 00550 // d->processed_size = _bytes; 00551 } 00552 00553 void SlaveBase::written( KIO::filesize_t _bytes ) 00554 { 00555 KIO_DATA << KIO_FILESIZE_T(_bytes); 00556 send( MSG_WRITTEN, data ); 00557 } 00558 00559 void SlaveBase::position( KIO::filesize_t _pos ) 00560 { 00561 KIO_DATA << KIO_FILESIZE_T(_pos); 00562 send( INF_POSITION, data ); 00563 } 00564 00565 void SlaveBase::processedPercent( float /* percent */ ) 00566 { 00567 kDebug(7019) << "STUB"; 00568 } 00569 00570 00571 void SlaveBase::speed( unsigned long _bytes_per_second ) 00572 { 00573 KIO_DATA << (quint32) _bytes_per_second; 00574 send( INF_SPEED, data ); 00575 } 00576 00577 void SlaveBase::redirection( const KUrl& _url ) 00578 { 00579 KIO_DATA << _url; 00580 send( INF_REDIRECTION, data ); 00581 } 00582 00583 void SlaveBase::errorPage() 00584 { 00585 send( INF_ERROR_PAGE ); 00586 } 00587 00588 static bool isSubCommand(int cmd) 00589 { 00590 return ( (cmd == CMD_REPARSECONFIGURATION) || 00591 (cmd == CMD_META_DATA) || 00592 (cmd == CMD_CONFIG) || 00593 (cmd == CMD_SUBURL) || 00594 (cmd == CMD_SLAVE_STATUS) || 00595 (cmd == CMD_SLAVE_CONNECT) || 00596 (cmd == CMD_SLAVE_HOLD) || 00597 (cmd == CMD_MULTI_GET)); 00598 } 00599 00600 void SlaveBase::mimeType( const QString &_type) 00601 { 00602 kDebug(7019) << _type; 00603 int cmd; 00604 do 00605 { 00606 // Send the meta-data each time we send the mime-type. 00607 if (!mOutgoingMetaData.isEmpty()) 00608 { 00609 // kDebug(7019) << "emitting meta data"; 00610 KIO_DATA << mOutgoingMetaData; 00611 send( INF_META_DATA, data ); 00612 } 00613 KIO_DATA << _type; 00614 send( INF_MIME_TYPE, data ); 00615 while(true) 00616 { 00617 cmd = 0; 00618 int ret = -1; 00619 if (d->appConnection.hasTaskAvailable() || d->appConnection.waitForIncomingTask(-1)) { 00620 ret = d->appConnection.read( &cmd, data ); 00621 } 00622 if (ret == -1) { 00623 kDebug(7019) << "read error"; 00624 exit(); 00625 return; 00626 } 00627 // kDebug(7019) << "got" << cmd; 00628 if ( cmd == CMD_HOST) // Ignore. 00629 continue; 00630 if (!isSubCommand(cmd)) 00631 break; 00632 00633 dispatch( cmd, data ); 00634 } 00635 } 00636 while (cmd != CMD_NONE); 00637 mOutgoingMetaData.clear(); 00638 } 00639 00640 void SlaveBase::exit() 00641 { 00642 d->exit_loop = true; 00643 // Using ::exit() here is too much (crashes in qdbus's qglobalstatic object), 00644 // so let's cleanly exit dispatchLoop() instead. 00645 // Update: we do need to call exit(), otherwise a long download (get()) would 00646 // keep going until it ends, even though the application exited. 00647 ::exit(255); 00648 } 00649 00650 void SlaveBase::warning( const QString &_msg) 00651 { 00652 KIO_DATA << _msg; 00653 send( INF_WARNING, data ); 00654 } 00655 00656 void SlaveBase::infoMessage( const QString &_msg) 00657 { 00658 KIO_DATA << _msg; 00659 send( INF_INFOMESSAGE, data ); 00660 } 00661 00662 bool SlaveBase::requestNetwork(const QString& host) 00663 { 00664 KIO_DATA << host << d->slaveid; 00665 send( MSG_NET_REQUEST, data ); 00666 00667 if ( waitForAnswer( INF_NETWORK_STATUS, 0, data ) != -1 ) 00668 { 00669 bool status; 00670 QDataStream stream( data ); 00671 stream >> status; 00672 return status; 00673 } else 00674 return false; 00675 } 00676 00677 void SlaveBase::dropNetwork(const QString& host) 00678 { 00679 KIO_DATA << host << d->slaveid; 00680 send( MSG_NET_DROP, data ); 00681 } 00682 00683 void SlaveBase::statEntry( const UDSEntry& entry ) 00684 { 00685 KIO_DATA << entry; 00686 send( MSG_STAT_ENTRY, data ); 00687 } 00688 00689 void SlaveBase::listEntry( const UDSEntry& entry, bool _ready ) 00690 { 00691 static struct timeval tp; 00692 static const int maximum_updatetime = 300; 00693 static const int minimum_updatetime = 100; 00694 00695 if (!_ready) { 00696 d->pendingListEntries.append(entry); 00697 00698 if (d->pendingListEntries.count() > d->listEntryCurrentSize) { 00699 gettimeofday(&tp, 0); 00700 00701 long diff = ((tp.tv_sec - d->listEntry_sec) * 1000000 + 00702 tp.tv_usec - d->listEntry_usec) / 1000; 00703 if (diff==0) diff=1; 00704 00705 if (diff > maximum_updatetime) { 00706 d->listEntryCurrentSize = d->listEntryCurrentSize * 3 / 4; 00707 _ready = true; 00708 } 00709 //if we can send all list entries of this dir which have not yet been sent 00710 //within maximum_updatetime, then make d->listEntryCurrentSize big enough for all of them 00711 else if (((d->pendingListEntries.count()*maximum_updatetime)/diff) > static_cast<long>(d->totalSize-d->sentListEntries)) 00712 d->listEntryCurrentSize=d->totalSize-d->sentListEntries+1; 00713 //if we are below minimum_updatetime, estimate how much we will get within 00714 //maximum_updatetime 00715 else if (diff < minimum_updatetime) 00716 d->listEntryCurrentSize = (d->pendingListEntries.count() * maximum_updatetime) / diff; 00717 else 00718 _ready=true; 00719 } 00720 } 00721 if (_ready) { // may happen when we started with !ready 00722 listEntries( d->pendingListEntries ); 00723 d->pendingListEntries.clear(); 00724 00725 gettimeofday(&tp, 0); 00726 d->listEntry_sec = tp.tv_sec; 00727 d->listEntry_usec = tp.tv_usec; 00728 } 00729 } 00730 00731 void SlaveBase::listEntries( const UDSEntryList& list ) 00732 { 00733 KIO_DATA << (quint32)list.count(); 00734 UDSEntryList::ConstIterator it = list.begin(); 00735 const UDSEntryList::ConstIterator end = list.end(); 00736 for (; it != end; ++it) 00737 stream << *it; 00738 send( MSG_LIST_ENTRIES, data); 00739 d->sentListEntries+=(uint)list.count(); 00740 } 00741 00742 static void sigsegv_handler(int sig) 00743 { 00744 #ifdef Q_OS_UNIX 00745 KDE_signal(sig,SIG_DFL); // Next one kills 00746 00747 //Kill us if we deadlock 00748 KDE_signal(SIGALRM,SIG_DFL); 00749 alarm(5); //generate an alarm signal in 5 seconds, in this time the slave has to exit 00750 00751 // Debug and printf should be avoided because they might 00752 // call malloc.. and get in a nice recursive malloc loop 00753 char buffer[120]; 00754 qsnprintf(buffer, sizeof(buffer), "kioslave: ####### CRASH ###### protocol = %s pid = %d signal = %d\n", s_protocol, getpid(), sig); 00755 write(2, buffer, strlen(buffer)); 00756 #ifndef NDEBUG 00757 #ifdef HAVE_BACKTRACE 00758 void* trace[256]; 00759 int n = backtrace(trace, 256); 00760 if (n) 00761 backtrace_symbols_fd(trace, n, 2); 00762 #endif 00763 #endif 00764 ::exit(1); 00765 #endif 00766 } 00767 00768 static void sigpipe_handler (int) 00769 { 00770 // We ignore a SIGPIPE in slaves. 00771 // A SIGPIPE can happen in two cases: 00772 // 1) Communication error with application. 00773 // 2) Communication error with network. 00774 slaveWriteError = true; 00775 00776 // Don't add anything else here, especially no debug output 00777 } 00778 00779 void SlaveBase::setHost(QString const &, quint16, QString const &, QString const &) 00780 { 00781 } 00782 00783 void SlaveBase::openConnection(void) 00784 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_CONNECT)); } 00785 void SlaveBase::closeConnection(void) 00786 { } // No response! 00787 void SlaveBase::stat(KUrl const &) 00788 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_STAT)); } 00789 void SlaveBase::put(KUrl const &, int, JobFlags ) 00790 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_PUT)); } 00791 void SlaveBase::special(const QByteArray &) 00792 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SPECIAL)); } 00793 void SlaveBase::listDir(KUrl const &) 00794 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_LISTDIR)); } 00795 void SlaveBase::get(KUrl const & ) 00796 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_GET)); } 00797 void SlaveBase::open(KUrl const &, QIODevice::OpenMode) 00798 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_OPEN)); } 00799 void SlaveBase::read(KIO::filesize_t) 00800 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_READ)); } 00801 void SlaveBase::write(const QByteArray &) 00802 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_WRITE)); } 00803 void SlaveBase::seek(KIO::filesize_t) 00804 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SEEK)); } 00805 void SlaveBase::close() 00806 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_CLOSE)); } 00807 void SlaveBase::mimetype(KUrl const &url) 00808 { get(url); } 00809 void SlaveBase::rename(KUrl const &, KUrl const &, JobFlags) 00810 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_RENAME)); } 00811 void SlaveBase::symlink(QString const &, KUrl const &, JobFlags) 00812 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SYMLINK)); } 00813 void SlaveBase::copy(KUrl const &, KUrl const &, int, JobFlags) 00814 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_COPY)); } 00815 void SlaveBase::del(KUrl const &, bool) 00816 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_DEL)); } 00817 void SlaveBase::setLinkDest(const KUrl &, const QString&) 00818 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SETLINKDEST)); } 00819 void SlaveBase::mkdir(KUrl const &, int) 00820 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_MKDIR)); } 00821 void SlaveBase::chmod(KUrl const &, int) 00822 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_CHMOD)); } 00823 void SlaveBase::setModificationTime(KUrl const &, const QDateTime&) 00824 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SETMODIFICATIONTIME)); } 00825 void SlaveBase::chown(KUrl const &, const QString &, const QString &) 00826 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_CHOWN)); } 00827 void SlaveBase::setSubUrl(KUrl const &) 00828 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SUBURL)); } 00829 void SlaveBase::multiGet(const QByteArray &) 00830 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_MULTI_GET)); } 00831 00832 00833 void SlaveBase::slave_status() 00834 { slaveStatus( QString(), false ); } 00835 00836 void SlaveBase::reparseConfiguration() 00837 { 00838 delete d->remotefile; 00839 d->remotefile = 0; 00840 } 00841 00842 bool SlaveBase::openPasswordDialog( AuthInfo& info, const QString &errorMsg ) 00843 { 00844 const long windowId = metaData(QLatin1String("window-id")).toLong(); 00845 const unsigned long userTimestamp = metaData(QLatin1String("user-timestamp")).toULong(); 00846 QString errorMessage; 00847 if (metaData(QLatin1String("no-auth-prompt")).compare(QLatin1String("true"), Qt::CaseInsensitive) == 0) { 00848 errorMessage = QLatin1String("<NoAuthPrompt>"); 00849 } else { 00850 errorMessage = errorMsg; 00851 } 00852 00853 AuthInfo dlgInfo (info); 00854 // Make sure the modified flag is not set. 00855 dlgInfo.setModified(false); 00856 // Prevent queryAuthInfo from caching the user supplied password since 00857 // we need the ioslaves to first authenticate against the server with 00858 // it to ensure it is valid. 00859 dlgInfo.setExtraField(QLatin1String("skip-caching-on-query"), true); 00860 00861 KPasswdServer* passwdServer = d->passwdServer(); 00862 00863 if (passwdServer) { 00864 qlonglong seqNr = passwdServer->queryAuthInfo(dlgInfo, errorMessage, windowId, 00865 SlaveBasePrivate::s_seqNr, userTimestamp); 00866 if (seqNr > 0) { 00867 SlaveBasePrivate::s_seqNr = seqNr; 00868 if (dlgInfo.isModified()) { 00869 info = dlgInfo; 00870 return true; 00871 } 00872 } 00873 } 00874 00875 return false; 00876 } 00877 00878 int SlaveBase::messageBox( MessageBoxType type, const QString &text, const QString &caption, 00879 const QString &buttonYes, const QString &buttonNo ) 00880 { 00881 return messageBox( text, type, caption, buttonYes, buttonNo, QString() ); 00882 } 00883 00884 int SlaveBase::messageBox( const QString &text, MessageBoxType type, const QString &caption, 00885 const QString &buttonYes, const QString &buttonNo, 00886 const QString &dontAskAgainName ) 00887 { 00888 kDebug(7019) << "messageBox " << type << " " << text << " - " << caption << buttonYes << buttonNo; 00889 KIO_DATA << (qint32)type << text << caption << buttonYes << buttonNo << dontAskAgainName; 00890 send( INF_MESSAGEBOX, data ); 00891 if ( waitForAnswer( CMD_MESSAGEBOXANSWER, 0, data ) != -1 ) 00892 { 00893 QDataStream stream( data ); 00894 int answer; 00895 stream >> answer; 00896 kDebug(7019) << "got messagebox answer" << answer; 00897 return answer; 00898 } else 00899 return 0; // communication failure 00900 } 00901 00902 bool SlaveBase::canResume( KIO::filesize_t offset ) 00903 { 00904 kDebug(7019) << "offset=" << KIO::number(offset); 00905 d->needSendCanResume = false; 00906 KIO_DATA << KIO_FILESIZE_T(offset); 00907 send( MSG_RESUME, data ); 00908 if ( offset ) 00909 { 00910 int cmd; 00911 if ( waitForAnswer( CMD_RESUMEANSWER, CMD_NONE, data, &cmd ) != -1 ) 00912 { 00913 kDebug(7019) << "returning" << (cmd == CMD_RESUMEANSWER); 00914 return cmd == CMD_RESUMEANSWER; 00915 } else 00916 return false; 00917 } 00918 else // No resuming possible -> no answer to wait for 00919 return true; 00920 } 00921 00922 00923 00924 int SlaveBase::waitForAnswer( int expected1, int expected2, QByteArray & data, int *pCmd ) 00925 { 00926 int cmd, result = -1; 00927 for (;;) 00928 { 00929 if (d->appConnection.hasTaskAvailable() || d->appConnection.waitForIncomingTask(-1)) { 00930 result = d->appConnection.read( &cmd, data ); 00931 } 00932 if (result == -1) { 00933 kDebug(7019) << "read error."; 00934 return -1; 00935 } 00936 00937 if ( cmd == expected1 || cmd == expected2 ) 00938 { 00939 if ( pCmd ) *pCmd = cmd; 00940 return result; 00941 } 00942 if ( isSubCommand(cmd) ) 00943 { 00944 dispatch( cmd, data ); 00945 } 00946 else 00947 { 00948 kFatal(7019) << "Got cmd " << cmd << " while waiting for an answer!"; 00949 } 00950 } 00951 } 00952 00953 00954 int SlaveBase::readData( QByteArray &buffer) 00955 { 00956 int result = waitForAnswer( MSG_DATA, 0, buffer ); 00957 //kDebug(7019) << "readData: length = " << result << " "; 00958 return result; 00959 } 00960 00961 void SlaveBase::setTimeoutSpecialCommand(int timeout, const QByteArray &data) 00962 { 00963 if (timeout > 0) 00964 d->timeout = time(0)+(time_t)timeout; 00965 else if (timeout == 0) 00966 d->timeout = 1; // Immediate timeout 00967 else 00968 d->timeout = 0; // Canceled 00969 00970 d->timeoutData = data; 00971 } 00972 00973 void SlaveBase::dispatch( int command, const QByteArray &data ) 00974 { 00975 QDataStream stream( data ); 00976 00977 KUrl url; 00978 int i; 00979 00980 switch( command ) { 00981 case CMD_HOST: { 00982 // Reset s_seqNr, see kpasswdserver/DESIGN 00983 SlaveBasePrivate::s_seqNr = 0; 00984 QString passwd; 00985 QString host, user; 00986 quint16 port; 00987 stream >> host >> port >> user >> passwd; 00988 d->m_state = d->InsideMethod; 00989 setHost( host, port, user, passwd ); 00990 d->verifyErrorFinishedNotCalled("setHost()"); 00991 d->m_state = d->Idle; 00992 } break; 00993 case CMD_CONNECT: { 00994 openConnection( ); 00995 } break; 00996 case CMD_DISCONNECT: { 00997 closeConnection( ); 00998 } break; 00999 case CMD_SLAVE_STATUS: { 01000 d->m_state = d->InsideMethod; 01001 slave_status(); 01002 // TODO verify that the slave has called slaveStatus()? 01003 d->verifyErrorFinishedNotCalled("slave_status()"); 01004 d->m_state = d->Idle; 01005 } break; 01006 case CMD_SLAVE_CONNECT: { 01007 d->onHold = false; 01008 QString app_socket; 01009 QDataStream stream( data ); 01010 stream >> app_socket; 01011 d->appConnection.send( MSG_SLAVE_ACK ); 01012 disconnectSlave(); 01013 d->isConnectedToApp = true; 01014 connectSlave(app_socket); 01015 virtual_hook(AppConnectionMade, 0); 01016 } break; 01017 case CMD_SLAVE_HOLD: { 01018 KUrl url; 01019 QDataStream stream( data ); 01020 stream >> url; 01021 d->onHoldUrl = url; 01022 d->onHold = true; 01023 disconnectSlave(); 01024 d->isConnectedToApp = false; 01025 // Do not close connection! 01026 connectSlave(d->poolSocket); 01027 } break; 01028 case CMD_REPARSECONFIGURATION: { 01029 d->m_state = d->InsideMethod; 01030 reparseConfiguration(); 01031 d->verifyErrorFinishedNotCalled("reparseConfiguration()"); 01032 d->m_state = d->Idle; 01033 } break; 01034 case CMD_CONFIG: { 01035 stream >> d->configData; 01036 d->rebuildConfig(); 01037 #if 0 //TODO: decide what to do in KDE 4.1 01038 KSocks::setConfig(d->configGroup); 01039 #endif 01040 delete d->remotefile; 01041 d->remotefile = 0; 01042 } break; 01043 case CMD_GET: { 01044 stream >> url; 01045 d->m_state = d->InsideMethod; 01046 get( url ); 01047 d->verifyState("get()"); 01048 d->m_state = d->Idle; 01049 } break; 01050 case CMD_OPEN: { 01051 stream >> url >> i; 01052 QIODevice::OpenMode mode = QFlag(i); 01053 d->m_state = d->InsideMethod; 01054 open(url, mode); //krazy:exclude=syscalls 01055 d->m_state = d->Idle; 01056 } break; 01057 case CMD_PUT: { 01058 int permissions; 01059 qint8 iOverwrite, iResume; 01060 stream >> url >> iOverwrite >> iResume >> permissions; 01061 JobFlags flags; 01062 if ( iOverwrite != 0 ) flags |= Overwrite; 01063 if ( iResume != 0 ) flags |= Resume; 01064 01065 // Remember that we need to send canResume(), TransferJob is expecting 01066 // it. Well, in theory this shouldn't be done if resume is true. 01067 // (the resume bool is currently unused) 01068 d->needSendCanResume = true /* !resume */; 01069 01070 d->m_state = d->InsideMethod; 01071 put( url, permissions, flags); 01072 d->verifyState("put()"); 01073 d->m_state = d->Idle; 01074 } break; 01075 case CMD_STAT: { 01076 stream >> url; 01077 d->m_state = d->InsideMethod; 01078 stat( url ); //krazy:exclude=syscalls 01079 d->verifyState("stat()"); 01080 d->m_state = d->Idle; 01081 } break; 01082 case CMD_MIMETYPE: { 01083 stream >> url; 01084 d->m_state = d->InsideMethod; 01085 mimetype( url ); 01086 d->verifyState("mimetype()"); 01087 d->m_state = d->Idle; 01088 } break; 01089 case CMD_LISTDIR: { 01090 stream >> url; 01091 d->m_state = d->InsideMethod; 01092 listDir( url ); 01093 d->verifyState("listDir()"); 01094 d->m_state = d->Idle; 01095 } break; 01096 case CMD_MKDIR: { 01097 stream >> url >> i; 01098 d->m_state = d->InsideMethod; 01099 mkdir( url, i ); //krazy:exclude=syscalls 01100 d->verifyState("mkdir()"); 01101 d->m_state = d->Idle; 01102 } break; 01103 case CMD_RENAME: { 01104 qint8 iOverwrite; 01105 KUrl url2; 01106 stream >> url >> url2 >> iOverwrite; 01107 JobFlags flags; 01108 if ( iOverwrite != 0 ) flags |= Overwrite; 01109 d->m_state = d->InsideMethod; 01110 rename( url, url2, flags ); //krazy:exclude=syscalls 01111 d->verifyState("rename()"); 01112 d->m_state = d->Idle; 01113 } break; 01114 case CMD_SYMLINK: { 01115 qint8 iOverwrite; 01116 QString target; 01117 stream >> target >> url >> iOverwrite; 01118 JobFlags flags; 01119 if ( iOverwrite != 0 ) flags |= Overwrite; 01120 d->m_state = d->InsideMethod; 01121 symlink( target, url, flags ); 01122 d->verifyState("symlink()"); 01123 d->m_state = d->Idle; 01124 } break; 01125 case CMD_COPY: { 01126 int permissions; 01127 qint8 iOverwrite; 01128 KUrl url2; 01129 stream >> url >> url2 >> permissions >> iOverwrite; 01130 JobFlags flags; 01131 if ( iOverwrite != 0 ) flags |= Overwrite; 01132 d->m_state = d->InsideMethod; 01133 copy( url, url2, permissions, flags ); 01134 d->verifyState("copy()"); 01135 d->m_state = d->Idle; 01136 } break; 01137 case CMD_DEL: { 01138 qint8 isFile; 01139 stream >> url >> isFile; 01140 d->m_state = d->InsideMethod; 01141 del( url, isFile != 0); 01142 d->verifyState("del()"); 01143 d->m_state = d->Idle; 01144 } break; 01145 case CMD_CHMOD: { 01146 stream >> url >> i; 01147 d->m_state = d->InsideMethod; 01148 chmod( url, i); 01149 d->verifyState("chmod()"); 01150 d->m_state = d->Idle; 01151 } break; 01152 case CMD_CHOWN: { 01153 QString owner, group; 01154 stream >> url >> owner >> group; 01155 d->m_state = d->InsideMethod; 01156 chown(url, owner, group); 01157 d->verifyState("chown()"); 01158 d->m_state = d->Idle; 01159 } break; 01160 case CMD_SETMODIFICATIONTIME: { 01161 QDateTime dt; 01162 stream >> url >> dt; 01163 d->m_state = d->InsideMethod; 01164 setModificationTime(url, dt); 01165 d->verifyState("setModificationTime()"); 01166 d->m_state = d->Idle; 01167 } break; 01168 case CMD_SPECIAL: { 01169 d->m_state = d->InsideMethod; 01170 special( data ); 01171 d->verifyState("special()"); 01172 d->m_state = d->Idle; 01173 } break; 01174 case CMD_META_DATA: { 01175 //kDebug(7019) << "(" << getpid() << ") Incoming meta-data..."; 01176 stream >> mIncomingMetaData; 01177 d->rebuildConfig(); 01178 } break; 01179 case CMD_SUBURL: { 01180 stream >> url; 01181 d->m_state = d->InsideMethod; 01182 setSubUrl(url); 01183 d->verifyErrorFinishedNotCalled("setSubUrl()"); 01184 d->m_state = d->Idle; 01185 } break; 01186 case CMD_NONE: { 01187 kWarning(7019) << "Got unexpected CMD_NONE!"; 01188 } break; 01189 case CMD_MULTI_GET: { 01190 d->m_state = d->InsideMethod; 01191 multiGet( data ); 01192 d->verifyState("multiGet()"); 01193 d->m_state = d->Idle; 01194 } break; 01195 default: { 01196 // Some command we don't understand. 01197 // Just ignore it, it may come from some future version of KDE. 01198 } break; 01199 } 01200 } 01201 01202 bool SlaveBase::checkCachedAuthentication( AuthInfo& info ) 01203 { 01204 KPasswdServer* passwdServer = d->passwdServer(); 01205 return (passwdServer && 01206 passwdServer->checkAuthInfo(info, metaData(QLatin1String("window-id")).toLong(), 01207 metaData(QLatin1String("user-timestamp")).toULong())); 01208 } 01209 01210 void SlaveBase::dispatchOpenCommand( int command, const QByteArray &data ) 01211 { 01212 QDataStream stream( data ); 01213 01214 switch( command ) { 01215 case CMD_READ: { 01216 KIO::filesize_t bytes; 01217 stream >> bytes; 01218 read(bytes); 01219 break; 01220 } 01221 case CMD_WRITE: { 01222 write(data); 01223 break; 01224 } 01225 case CMD_SEEK: { 01226 KIO::filesize_t offset; 01227 stream >> offset; 01228 seek(offset); 01229 } 01230 case CMD_NONE: 01231 break; 01232 case CMD_CLOSE: 01233 close(); // must call finish(), which will set d->inOpenLoop=false 01234 break; 01235 default: 01236 // Some command we don't understand. 01237 // Just ignore it, it may come from some future version of KDE. 01238 break; 01239 } 01240 } 01241 01242 bool SlaveBase::cacheAuthentication( const AuthInfo& info ) 01243 { 01244 KPasswdServer* passwdServer = d->passwdServer(); 01245 01246 if (!passwdServer) { 01247 return false; 01248 } 01249 01250 passwdServer->addAuthInfo(info, metaData(QLatin1String("window-id")).toLongLong()); 01251 return true; 01252 } 01253 01254 int SlaveBase::connectTimeout() 01255 { 01256 bool ok; 01257 QString tmp = metaData(QLatin1String("ConnectTimeout")); 01258 int result = tmp.toInt(&ok); 01259 if (ok) 01260 return result; 01261 return DEFAULT_CONNECT_TIMEOUT; 01262 } 01263 01264 int SlaveBase::proxyConnectTimeout() 01265 { 01266 bool ok; 01267 QString tmp = metaData(QLatin1String("ProxyConnectTimeout")); 01268 int result = tmp.toInt(&ok); 01269 if (ok) 01270 return result; 01271 return DEFAULT_PROXY_CONNECT_TIMEOUT; 01272 } 01273 01274 01275 int SlaveBase::responseTimeout() 01276 { 01277 bool ok; 01278 QString tmp = metaData(QLatin1String("ResponseTimeout")); 01279 int result = tmp.toInt(&ok); 01280 if (ok) 01281 return result; 01282 return DEFAULT_RESPONSE_TIMEOUT; 01283 } 01284 01285 01286 int SlaveBase::readTimeout() 01287 { 01288 bool ok; 01289 QString tmp = metaData(QLatin1String("ReadTimeout")); 01290 int result = tmp.toInt(&ok); 01291 if (ok) 01292 return result; 01293 return DEFAULT_READ_TIMEOUT; 01294 } 01295 01296 bool SlaveBase::wasKilled() const 01297 { 01298 return d->wasKilled; 01299 } 01300 01301 void SlaveBase::setKillFlag() 01302 { 01303 d->wasKilled=true; 01304 } 01305 01306 void SlaveBase::send(int cmd, const QByteArray& arr ) 01307 { 01308 slaveWriteError = false; 01309 if (!d->appConnection.send(cmd, arr)) 01310 // Note that slaveWriteError can also be set by sigpipe_handler 01311 slaveWriteError = true; 01312 if (slaveWriteError) exit(); 01313 } 01314 01315 void SlaveBase::virtual_hook( int, void* ) 01316 { /*BASE::virtual_hook( id, data );*/ } 01317 01318 void SlaveBase::lookupHost(const QString& host) 01319 { 01320 KIO_DATA << host; 01321 send(MSG_HOST_INFO_REQ, data); 01322 } 01323 01324 int SlaveBase::waitForHostInfo(QHostInfo& info) 01325 { 01326 QByteArray data; 01327 int result = waitForAnswer(CMD_HOST_INFO, 0, data); 01328 01329 if (result == -1) { 01330 info.setError(QHostInfo::UnknownError); 01331 info.setErrorString(i18n("Unknown Error")); 01332 return result; 01333 } 01334 01335 QDataStream stream(data); 01336 QString hostName; 01337 QList<QHostAddress> addresses; 01338 int error; 01339 QString errorString; 01340 01341 stream >> hostName >> addresses >> error >> errorString; 01342 01343 info.setHostName(hostName); 01344 info.setAddresses(addresses); 01345 info.setError(QHostInfo::HostInfoError(error)); 01346 info.setErrorString(errorString); 01347 01348 return result; 01349 }
KDE 4.7 API Reference