00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "slavebase.h"
00027
00028 #include <config.h>
00029
00030 #include <sys/time.h>
00031 #ifdef HAVE_SYS_SELECT_H
00032 #include <sys/select.h>
00033 #endif
00034
00035 #include <assert.h>
00036 #include <kdebug.h>
00037 #include <stdlib.h>
00038 #include <errno.h>
00039 #include <unistd.h>
00040 #include <signal.h>
00041 #include <time.h>
00042
00043 #include <qfile.h>
00044
00045 #include <dcopclient.h>
00046
00047 #include <kapplication.h>
00048 #include <ksock.h>
00049 #include <kcrash.h>
00050 #include <kdesu/client.h>
00051 #include <klocale.h>
00052 #include <ksocks.h>
00053
00054 #include "kremoteencoding.h"
00055
00056 #include "kio/slavebase.h"
00057 #include "kio/connection.h"
00058 #include "kio/ioslave_defaults.h"
00059 #include "kio/slaveinterface.h"
00060
00061 #include "uiserver_stub.h"
00062
00063 #ifndef NDEBUG
00064 #ifdef HAVE_BACKTRACE
00065 #include <execinfo.h>
00066 #endif
00067 #endif
00068
00069 using namespace KIO;
00070
00071 template class QPtrList<QValueList<UDSAtom> >;
00072 typedef QValueList<QCString> AuthKeysList;
00073 typedef QMap<QString,QCString> AuthKeysMap;
00074 #define KIO_DATA QByteArray data; QDataStream stream( data, IO_WriteOnly ); stream
00075 #define KIO_FILESIZE_T(x) (unsigned long)(x & 0xffffffff) << (unsigned long)(x >> 32)
00076
00077 namespace KIO {
00078
00079 class SlaveBaseConfig : public KConfigBase
00080 {
00081 public:
00082 SlaveBaseConfig(SlaveBase *_slave)
00083 : slave(_slave) { }
00084
00085 bool internalHasGroup(const QCString &) const { qWarning("hasGroup(const QCString &)");
00086 return false; }
00087
00088 QStringList groupList() const { return QStringList(); }
00089
00090 QMap<QString,QString> entryMap(const QString &group) const
00091 { Q_UNUSED(group); return QMap<QString,QString>(); }
00092
00093 void reparseConfiguration() { }
00094
00095 KEntryMap internalEntryMap( const QString &pGroup) const { Q_UNUSED(pGroup); return KEntryMap(); }
00096
00097 KEntryMap internalEntryMap() const { return KEntryMap(); }
00098
00099 void putData(const KEntryKey &_key, const KEntry&_data, bool _checkGroup)
00100 { Q_UNUSED(_key); Q_UNUSED(_data); Q_UNUSED(_checkGroup); }
00101
00102 KEntry lookupData(const KEntryKey &_key) const
00103 {
00104 KEntry entry;
00105 QString value = slave->metaData(_key.c_key);
00106 if (!value.isNull())
00107 entry.mValue = value.utf8();
00108 return entry;
00109 }
00110 protected:
00111 SlaveBase *slave;
00112 };
00113
00114
00115 class SlaveBasePrivate {
00116 public:
00117 QString slaveid;
00118 bool resume:1;
00119 bool needSendCanResume:1;
00120 bool onHold:1;
00121 bool wasKilled:1;
00122 MetaData configData;
00123 SlaveBaseConfig *config;
00124 KURL onHoldUrl;
00125
00126 struct timeval last_tv;
00127 KIO::filesize_t totalSize;
00128 KIO::filesize_t sentListEntries;
00129 DCOPClient *dcopClient;
00130 KRemoteEncoding *remotefile;
00131 time_t timeout;
00132 QByteArray timeoutData;
00133 };
00134
00135 }
00136
00137 static SlaveBase *globalSlave;
00138 long SlaveBase::s_seqNr;
00139
00140 static volatile bool slaveWriteError = false;
00141
00142 static const char *s_protocol;
00143
00144 #ifdef Q_OS_UNIX
00145 static void genericsig_handler(int sigNumber)
00146 {
00147 signal(sigNumber,SIG_IGN);
00148
00149
00150
00151
00152
00153 if (globalSlave!=0)
00154 globalSlave->setKillFlag();
00155 signal(SIGALRM,SIG_DFL);
00156 alarm(5);
00157 }
00158 #endif
00159
00161
00162 SlaveBase::SlaveBase( const QCString &protocol,
00163 const QCString &pool_socket,
00164 const QCString &app_socket )
00165 : mProtocol(protocol), m_pConnection(0),
00166 mPoolSocket( QFile::decodeName(pool_socket)),
00167 mAppSocket( QFile::decodeName(app_socket))
00168 {
00169 s_protocol = protocol.data();
00170 #ifdef Q_OS_UNIX
00171 if (!getenv("KDE_DEBUG"))
00172 {
00173 KCrash::setCrashHandler( sigsegv_handler );
00174 signal(SIGILL,&sigsegv_handler);
00175 signal(SIGTRAP,&sigsegv_handler);
00176 signal(SIGABRT,&sigsegv_handler);
00177 signal(SIGBUS,&sigsegv_handler);
00178 signal(SIGALRM,&sigsegv_handler);
00179 signal(SIGFPE,&sigsegv_handler);
00180 #ifdef SIGPOLL
00181 signal(SIGPOLL, &sigsegv_handler);
00182 #endif
00183 #ifdef SIGSYS
00184 signal(SIGSYS, &sigsegv_handler);
00185 #endif
00186 #ifdef SIGVTALRM
00187 signal(SIGVTALRM, &sigsegv_handler);
00188 #endif
00189 #ifdef SIGXCPU
00190 signal(SIGXCPU, &sigsegv_handler);
00191 #endif
00192 #ifdef SIGXFSZ
00193 signal(SIGXFSZ, &sigsegv_handler);
00194 #endif
00195 }
00196
00197 struct sigaction act;
00198 act.sa_handler = sigpipe_handler;
00199 sigemptyset( &act.sa_mask );
00200 act.sa_flags = 0;
00201 sigaction( SIGPIPE, &act, 0 );
00202
00203 signal(SIGINT,&genericsig_handler);
00204 signal(SIGQUIT,&genericsig_handler);
00205 signal(SIGTERM,&genericsig_handler);
00206 #endif
00207
00208 globalSlave=this;
00209
00210 appconn = new Connection();
00211 listEntryCurrentSize = 100;
00212 struct timeval tp;
00213 gettimeofday(&tp, 0);
00214 listEntry_sec = tp.tv_sec;
00215 listEntry_usec = tp.tv_usec;
00216 mConnectedToApp = true;
00217
00218 d = new SlaveBasePrivate;
00219
00220 d->slaveid = protocol;
00221 d->slaveid += QString::number(getpid());
00222 d->resume = false;
00223 d->needSendCanResume = false;
00224 d->config = new SlaveBaseConfig(this);
00225 d->onHold = false;
00226 d->wasKilled=false;
00227 d->last_tv.tv_sec = 0;
00228 d->last_tv.tv_usec = 0;
00229
00230 d->totalSize=0;
00231 d->sentListEntries=0;
00232 d->timeout = 0;
00233 connectSlave(mAppSocket);
00234
00235 d->dcopClient = 0;
00236 d->remotefile = 0;
00237 }
00238
00239 SlaveBase::~SlaveBase()
00240 {
00241 delete d;
00242 s_protocol = "";
00243 }
00244
00245 DCOPClient *SlaveBase::dcopClient()
00246 {
00247 if (!d->dcopClient)
00248 {
00249 d->dcopClient = KApplication::dcopClient();
00250 if (!d->dcopClient->isAttached())
00251 d->dcopClient->attach();
00252 d->dcopClient->setDaemonMode( true );
00253 }
00254 return d->dcopClient;
00255 }
00256
00257 void SlaveBase::dispatchLoop()
00258 {
00259 #ifdef Q_OS_UNIX //TODO: WIN32
00260 fd_set rfds;
00261 int retval;
00262
00263 while (true)
00264 {
00265 if (d->timeout && (d->timeout < time(0)))
00266 {
00267 QByteArray data = d->timeoutData;
00268 d->timeout = 0;
00269 d->timeoutData = QByteArray();
00270 special(data);
00271 }
00272 FD_ZERO(&rfds);
00273
00274 assert(appconn->inited());
00275 int maxfd = appconn->fd_from();
00276 FD_SET(appconn->fd_from(), &rfds);
00277 if( d->dcopClient )
00278 {
00279 FD_SET( d->dcopClient->socket(), &rfds );
00280 if( d->dcopClient->socket() > maxfd )
00281 maxfd = d->dcopClient->socket();
00282 }
00283
00284 if (!d->timeout)
00285 {
00286 retval = select( maxfd + 1, &rfds, NULL, NULL, NULL);
00287 }
00288 else
00289 {
00290 struct timeval tv;
00291 tv.tv_sec = kMax(d->timeout-time(0),(time_t) 1);
00292 tv.tv_usec = 0;
00293 retval = select( maxfd + 1, &rfds, NULL, NULL, &tv);
00294 }
00295 if ((retval>0) && FD_ISSET(appconn->fd_from(), &rfds))
00296 {
00297 int cmd;
00298 QByteArray data;
00299 if ( appconn->read(&cmd, data) != -1 )
00300 {
00301 dispatch(cmd, data);
00302 }
00303 else
00304 {
00305
00306 if (mConnectedToApp && !mPoolSocket.isEmpty())
00307 {
00308 disconnectSlave();
00309 mConnectedToApp = false;
00310 closeConnection();
00311 connectSlave(mPoolSocket);
00312 }
00313 else
00314 {
00315 return;
00316 }
00317 }
00318 }
00319 if( retval > 0 && d->dcopClient && FD_ISSET( d->dcopClient->socket(), &rfds ))
00320 {
00321 d->dcopClient->processSocketData( d->dcopClient->socket());
00322 }
00323 if ((retval<0) && (errno != EINTR))
00324 {
00325 kdDebug(7019) << "dispatchLoop(): select returned " << retval << " "
00326 << (errno==EBADF?"EBADF":errno==EINTR?"EINTR":errno==EINVAL?"EINVAL":errno==ENOMEM?"ENOMEM":"unknown")
00327 << " (" << errno << ")" << endl;
00328 return;
00329 }
00330
00331 if (wasKilled())
00332 {
00333 kdDebug(7019)<<" dispatchLoop() slave was killed, returning"<<endl;
00334 return;
00335 }
00336 }
00337 #endif
00338 }
00339
00340 void SlaveBase::connectSlave(const QString& path)
00341 {
00342 #ifdef Q_OS_UNIX //TODO: KSocket not yet available on WIN32
00343 appconn->init(new KSocket(QFile::encodeName(path)));
00344 if (!appconn->inited())
00345 {
00346 kdDebug(7019) << "SlaveBase: failed to connect to " << path << endl;
00347 exit();
00348 }
00349
00350 setConnection(appconn);
00351 #endif
00352 }
00353
00354 void SlaveBase::disconnectSlave()
00355 {
00356 appconn->close();
00357 }
00358
00359 void SlaveBase::setMetaData(const QString &key, const QString &value)
00360 {
00361 mOutgoingMetaData.replace(key, value);
00362 }
00363
00364 QString SlaveBase::metaData(const QString &key) const
00365 {
00366 if (mIncomingMetaData.contains(key))
00367 return mIncomingMetaData[key];
00368 if (d->configData.contains(key))
00369 return d->configData[key];
00370 return QString::null;
00371 }
00372
00373 bool SlaveBase::hasMetaData(const QString &key) const
00374 {
00375 if (mIncomingMetaData.contains(key))
00376 return true;
00377 if (d->configData.contains(key))
00378 return true;
00379 return false;
00380 }
00381
00382
00383 QString SlaveBase::metaData(const QString &key) {
00384 return const_cast<const SlaveBase*>(this)->metaData( key );
00385 }
00386 bool SlaveBase::hasMetaData(const QString &key) {
00387 return const_cast<const SlaveBase*>(this)->hasMetaData( key );
00388 }
00389
00390 KConfigBase *SlaveBase::config()
00391 {
00392 return d->config;
00393 }
00394
00395 void SlaveBase::sendMetaData()
00396 {
00397 KIO_DATA << mOutgoingMetaData;
00398
00399 slaveWriteError = false;
00400 m_pConnection->send( INF_META_DATA, data );
00401 if (slaveWriteError) exit();
00402 mOutgoingMetaData.clear();
00403 }
00404
00405 KRemoteEncoding *SlaveBase::remoteEncoding()
00406 {
00407 if (d->remotefile != 0)
00408 return d->remotefile;
00409
00410 return d->remotefile = new KRemoteEncoding(metaData("Charset").latin1());
00411 }
00412
00413 void SlaveBase::data( const QByteArray &data )
00414 {
00415 if (!mOutgoingMetaData.isEmpty())
00416 sendMetaData();
00417 slaveWriteError = false;
00418 m_pConnection->send( MSG_DATA, data );
00419 if (slaveWriteError) exit();
00420 }
00421
00422 void SlaveBase::dataReq( )
00423 {
00424
00425
00426
00427
00428 if (d->needSendCanResume)
00429 canResume(0);
00430 m_pConnection->send( MSG_DATA_REQ );
00431 }
00432
00433 void SlaveBase::error( int _errid, const QString &_text )
00434 {
00435 mIncomingMetaData.clear();
00436 mOutgoingMetaData.clear();
00437 KIO_DATA << (Q_INT32) _errid << _text;
00438
00439 m_pConnection->send( MSG_ERROR, data );
00440
00441 listEntryCurrentSize = 100;
00442 d->sentListEntries=0;
00443 d->totalSize=0;
00444 }
00445
00446 void SlaveBase::connected()
00447 {
00448 slaveWriteError = false;
00449 m_pConnection->send( MSG_CONNECTED );
00450 if (slaveWriteError) exit();
00451 }
00452
00453 void SlaveBase::finished()
00454 {
00455 mIncomingMetaData.clear();
00456 if (!mOutgoingMetaData.isEmpty())
00457 sendMetaData();
00458 m_pConnection->send( MSG_FINISHED );
00459
00460
00461 listEntryCurrentSize = 100;
00462 d->sentListEntries=0;
00463 d->totalSize=0;
00464 }
00465
00466 void SlaveBase::needSubURLData()
00467 {
00468 m_pConnection->send( MSG_NEED_SUBURL_DATA );
00469 }
00470
00471 void SlaveBase::slaveStatus( const QString &host, bool connected )
00472 {
00473 pid_t pid = getpid();
00474 Q_INT8 b = connected ? 1 : 0;
00475 KIO_DATA << pid << mProtocol << host << b;
00476 if (d->onHold)
00477 stream << d->onHoldUrl;
00478 m_pConnection->send( MSG_SLAVE_STATUS, data );
00479 }
00480
00481 void SlaveBase::canResume()
00482 {
00483 m_pConnection->send( MSG_CANRESUME );
00484 }
00485
00486 void SlaveBase::totalSize( KIO::filesize_t _bytes )
00487 {
00488 KIO_DATA << KIO_FILESIZE_T(_bytes);
00489 slaveWriteError = false;
00490 m_pConnection->send( INF_TOTAL_SIZE, data );
00491 if (slaveWriteError) exit();
00492
00493
00494 struct timeval tp;
00495 gettimeofday(&tp, 0);
00496 listEntry_sec = tp.tv_sec;
00497 listEntry_usec = tp.tv_usec;
00498 d->totalSize=_bytes;
00499 d->sentListEntries=0;
00500 }
00501
00502 void SlaveBase::processedSize( KIO::filesize_t _bytes )
00503 {
00504 bool emitSignal=false;
00505 struct timeval tv;
00506 int gettimeofday_res=gettimeofday( &tv, 0L );
00507
00508 if( _bytes == d->totalSize )
00509 emitSignal=true;
00510 else if ( gettimeofday_res == 0 ) {
00511 time_t msecdiff = 2000;
00512 if (d->last_tv.tv_sec) {
00513
00514 msecdiff = 1000 * ( tv.tv_sec - d->last_tv.tv_sec );
00515 time_t usecdiff = tv.tv_usec - d->last_tv.tv_usec;
00516 if ( usecdiff < 0 ) {
00517 msecdiff--;
00518 msecdiff += 1000;
00519 }
00520 msecdiff += usecdiff / 1000;
00521 }
00522 emitSignal=msecdiff >= 100;
00523 }
00524
00525 if( emitSignal ) {
00526 KIO_DATA << KIO_FILESIZE_T(_bytes);
00527 slaveWriteError = false;
00528 m_pConnection->send( INF_PROCESSED_SIZE, data );
00529 if (slaveWriteError) exit();
00530 if ( gettimeofday_res == 0 ) {
00531 d->last_tv.tv_sec = tv.tv_sec;
00532 d->last_tv.tv_usec = tv.tv_usec;
00533 }
00534 }
00535
00536 }
00537
00538 void SlaveBase::processedPercent( float )
00539 {
00540 kdDebug(7019) << "SlaveBase::processedPercent: STUB" << endl;
00541 }
00542
00543
00544 void SlaveBase::speed( unsigned long _bytes_per_second )
00545 {
00546 KIO_DATA << (Q_UINT32) _bytes_per_second;
00547 slaveWriteError = false;
00548 m_pConnection->send( INF_SPEED, data );
00549 if (slaveWriteError) exit();
00550 }
00551
00552 void SlaveBase::redirection( const KURL& _url )
00553 {
00554 KIO_DATA << _url;
00555 m_pConnection->send( INF_REDIRECTION, data );
00556 }
00557
00558 void SlaveBase::errorPage()
00559 {
00560 m_pConnection->send( INF_ERROR_PAGE );
00561 }
00562
00563 static bool isSubCommand(int cmd)
00564 {
00565 return ( (cmd == CMD_REPARSECONFIGURATION) ||
00566 (cmd == CMD_META_DATA) ||
00567 (cmd == CMD_CONFIG) ||
00568 (cmd == CMD_SUBURL) ||
00569 (cmd == CMD_SLAVE_STATUS) ||
00570 (cmd == CMD_SLAVE_CONNECT) ||
00571 (cmd == CMD_SLAVE_HOLD) ||
00572 (cmd == CMD_MULTI_GET));
00573 }
00574
00575 void SlaveBase::mimeType( const QString &_type)
00576 {
00577
00578 int cmd;
00579 do
00580 {
00581
00582 if (!mOutgoingMetaData.isEmpty())
00583 {
00584
00585 KIO_DATA << mOutgoingMetaData;
00586 m_pConnection->send( INF_META_DATA, data );
00587 }
00588 KIO_DATA << _type;
00589 m_pConnection->send( INF_MIME_TYPE, data );
00590 while(true)
00591 {
00592 cmd = 0;
00593 if ( m_pConnection->read( &cmd, data ) == -1 ) {
00594 kdDebug(7019) << "SlaveBase: mimetype: read error" << endl;
00595 exit();
00596 }
00597
00598 if ( cmd == CMD_HOST)
00599 continue;
00600 if ( isSubCommand(cmd) )
00601 {
00602 dispatch( cmd, data );
00603 continue;
00604 }
00605 break;
00606 }
00607 }
00608 while (cmd != CMD_NONE);
00609 mOutgoingMetaData.clear();
00610 }
00611
00612 void SlaveBase::exit()
00613 {
00614 this->~SlaveBase();
00615 ::exit(255);
00616 }
00617
00618 void SlaveBase::warning( const QString &_msg)
00619 {
00620 KIO_DATA << _msg;
00621 m_pConnection->send( INF_WARNING, data );
00622 }
00623
00624 void SlaveBase::infoMessage( const QString &_msg)
00625 {
00626 KIO_DATA << _msg;
00627 m_pConnection->send( INF_INFOMESSAGE, data );
00628 }
00629
00630 bool SlaveBase::requestNetwork(const QString& host)
00631 {
00632 KIO_DATA << host << d->slaveid;
00633 m_pConnection->send( MSG_NET_REQUEST, data );
00634
00635 if ( waitForAnswer( INF_NETWORK_STATUS, 0, data ) != -1 )
00636 {
00637 bool status;
00638 QDataStream stream( data, IO_ReadOnly );
00639 stream >> status;
00640 return status;
00641 } else
00642 return false;
00643 }
00644
00645 void SlaveBase::dropNetwork(const QString& host)
00646 {
00647 KIO_DATA << host << d->slaveid;
00648 m_pConnection->send( MSG_NET_DROP, data );
00649 }
00650
00651 void SlaveBase::statEntry( const UDSEntry& entry )
00652 {
00653 KIO_DATA << entry;
00654 slaveWriteError = false;
00655 m_pConnection->send( MSG_STAT_ENTRY, data );
00656 if (slaveWriteError) exit();
00657 }
00658
00659 void SlaveBase::listEntry( const UDSEntry& entry, bool _ready )
00660 {
00661 static struct timeval tp;
00662 static const int maximum_updatetime = 300;
00663 static const int minimum_updatetime = 100;
00664
00665 if (!_ready) {
00666 pendingListEntries.append(entry);
00667
00668 if (pendingListEntries.count() > listEntryCurrentSize) {
00669 gettimeofday(&tp, 0);
00670
00671 long diff = ((tp.tv_sec - listEntry_sec) * 1000000 +
00672 tp.tv_usec - listEntry_usec) / 1000;
00673 if (diff==0) diff=1;
00674
00675 if (diff > maximum_updatetime) {
00676 listEntryCurrentSize = listEntryCurrentSize * 3 / 4;
00677 _ready = true;
00678 }
00679
00680
00681 else if (((pendingListEntries.count()*maximum_updatetime)/diff) > (d->totalSize-d->sentListEntries))
00682 listEntryCurrentSize=d->totalSize-d->sentListEntries+1;
00683
00684
00685 else if (diff < minimum_updatetime)
00686 listEntryCurrentSize = (pendingListEntries.count() * maximum_updatetime) / diff;
00687 else
00688 _ready=true;
00689 }
00690 }
00691 if (_ready) {
00692 listEntries( pendingListEntries );
00693 pendingListEntries.clear();
00694
00695 gettimeofday(&tp, 0);
00696 listEntry_sec = tp.tv_sec;
00697 listEntry_usec = tp.tv_usec;
00698 }
00699 }
00700
00701 void SlaveBase::listEntries( const UDSEntryList& list )
00702 {
00703 KIO_DATA << (Q_UINT32)list.count();
00704 UDSEntryListConstIterator it = list.begin();
00705 UDSEntryListConstIterator end = list.end();
00706 for (; it != end; ++it)
00707 stream << *it;
00708 slaveWriteError = false;
00709 m_pConnection->send( MSG_LIST_ENTRIES, data);
00710 if (slaveWriteError) exit();
00711 d->sentListEntries+=(uint)list.count();
00712 }
00713
00714 void SlaveBase::sendAuthenticationKey( const QCString& key,
00715 const QCString& group,
00716 bool keepPass )
00717 {
00718 KIO_DATA << key << group << keepPass;
00719 m_pConnection->send( MSG_AUTH_KEY, data );
00720 }
00721
00722 void SlaveBase::delCachedAuthentication( const QString& key )
00723 {
00724 KIO_DATA << key.utf8() ;
00725 m_pConnection->send( MSG_DEL_AUTH_KEY, data );
00726 }
00727
00728 void SlaveBase::sigsegv_handler(int sig)
00729 {
00730 #ifdef Q_OS_UNIX
00731 signal(sig,SIG_DFL);
00732
00733
00734 signal(SIGALRM,SIG_DFL);
00735 alarm(5);
00736
00737
00738
00739 char buffer[120];
00740 snprintf(buffer, sizeof(buffer), "kioslave: ####### CRASH ###### protocol = %s pid = %d signal = %d\n", s_protocol, getpid(), sig);
00741 write(2, buffer, strlen(buffer));
00742 #ifndef NDEBUG
00743 #ifdef HAVE_BACKTRACE
00744 void* trace[256];
00745 int n = backtrace(trace, 256);
00746 if (n)
00747 backtrace_symbols_fd(trace, n, 2);
00748 #endif
00749 #endif
00750 ::exit(1);
00751 #endif
00752 }
00753
00754 void SlaveBase::sigpipe_handler (int)
00755 {
00756
00757
00758
00759
00760 slaveWriteError = true;
00761
00762
00763 }
00764
00765 void SlaveBase::setHost(QString const &, int, QString const &, QString const &)
00766 {
00767 }
00768
00769 void SlaveBase::openConnection(void)
00770 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_CONNECT)); }
00771 void SlaveBase::closeConnection(void)
00772 { }
00773 void SlaveBase::stat(KURL const &)
00774 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_STAT)); }
00775 void SlaveBase::put(KURL const &, int, bool, bool)
00776 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_PUT)); }
00777 void SlaveBase::special(const QByteArray &)
00778 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SPECIAL)); }
00779 void SlaveBase::listDir(KURL const &)
00780 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_LISTDIR)); }
00781 void SlaveBase::get(KURL const & )
00782 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_GET)); }
00783 void SlaveBase::mimetype(KURL const &url)
00784 { get(url); }
00785 void SlaveBase::rename(KURL const &, KURL const &, bool)
00786 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_RENAME)); }
00787 void SlaveBase::symlink(QString const &, KURL const &, bool)
00788 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SYMLINK)); }
00789 void SlaveBase::copy(KURL const &, KURL const &, int, bool)
00790 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_COPY)); }
00791 void SlaveBase::del(KURL const &, bool)
00792 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_DEL)); }
00793 void SlaveBase::mkdir(KURL const &, int)
00794 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_MKDIR)); }
00795 void SlaveBase::chmod(KURL const &, int)
00796 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_CHMOD)); }
00797 void SlaveBase::setSubURL(KURL const &)
00798 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SUBURL)); }
00799 void SlaveBase::multiGet(const QByteArray &)
00800 { error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_MULTI_GET)); }
00801
00802
00803 void SlaveBase::slave_status()
00804 { slaveStatus( QString::null, false ); }
00805
00806 void SlaveBase::reparseConfiguration()
00807 {
00808 }
00809
00810 bool SlaveBase::dispatch()
00811 {
00812 assert( m_pConnection );
00813
00814 int cmd;
00815 QByteArray data;
00816 if ( m_pConnection->read( &cmd, data ) == -1 )
00817 {
00818 kdDebug(7019) << "SlaveBase::dispatch() has read error." << endl;
00819 return false;
00820 }
00821
00822 dispatch( cmd, data );
00823 return true;
00824 }
00825
00826 bool SlaveBase::openPassDlg( AuthInfo& info )
00827 {
00828 return openPassDlg(info, QString::null);
00829 }
00830
00831 bool SlaveBase::openPassDlg( AuthInfo& info, const QString &errorMsg )
00832 {
00833 QCString replyType;
00834 QByteArray params;
00835 QByteArray reply;
00836 AuthInfo authResult;
00837 long windowId = metaData("window-id").toLong();
00838 long progressId = metaData("progress-id").toLong();
00839 unsigned long userTimestamp = metaData("user-timestamp").toULong();
00840
00841 kdDebug(7019) << "SlaveBase::openPassDlg window-id=" << windowId << " progress-id=" << progressId << endl;
00842
00843 (void) dcopClient();
00844
00845 UIServer_stub uiserver( "kio_uiserver", "UIServer" );
00846 if (progressId)
00847 uiserver.setJobVisible( progressId, false );
00848
00849 QDataStream stream(params, IO_WriteOnly);
00850
00851 if (metaData("no-auth-prompt").lower() == "true")
00852 stream << info << QString("<NoAuthPrompt>") << windowId << s_seqNr << userTimestamp;
00853 else
00854 stream << info << errorMsg << windowId << s_seqNr << userTimestamp;
00855
00856 bool callOK = d->dcopClient->call( "kded", "kpasswdserver", "queryAuthInfo(KIO::AuthInfo, QString, long int, long int, unsigned long int)",
00857 params, replyType, reply );
00858
00859 if (progressId)
00860 uiserver.setJobVisible( progressId, true );
00861
00862 if (!callOK)
00863 {
00864 kdWarning(7019) << "Can't communicate with kded_kpasswdserver!" << endl;
00865 return false;
00866 }
00867
00868 if ( replyType == "KIO::AuthInfo" )
00869 {
00870 QDataStream stream2( reply, IO_ReadOnly );
00871 stream2 >> authResult >> s_seqNr;
00872 }
00873 else
00874 {
00875 kdError(7019) << "DCOP function queryAuthInfo(...) returns "
00876 << replyType << ", expected KIO::AuthInfo" << endl;
00877 return false;
00878 }
00879
00880 if (!authResult.isModified())
00881 return false;
00882
00883 info = authResult;
00884
00885 kdDebug(7019) << "SlaveBase::openPassDlg: username=" << info.username << endl;
00886 kdDebug(7019) << "SlaveBase::openPassDlg: password=[hidden]" << endl;
00887
00888 return true;
00889 }
00890
00891 int SlaveBase::messageBox( MessageBoxType type, const QString &text, const QString &caption,
00892 const QString &buttonYes, const QString &buttonNo )
00893 {
00894 return messageBox( text, type, caption, buttonYes, buttonNo, QString::null );
00895 }
00896
00897 int SlaveBase::messageBox( const QString &text, MessageBoxType type, const QString &caption,
00898 const QString &buttonYes, const QString &buttonNo, const QString &dontAskAgainName )
00899 {
00900 kdDebug(7019) << "messageBox " << type << " " << text << " - " << caption << buttonYes << buttonNo << endl;
00901 KIO_DATA << (Q_INT32)type << text << caption << buttonYes << buttonNo << dontAskAgainName;
00902 m_pConnection->send( INF_MESSAGEBOX, data );
00903 if ( waitForAnswer( CMD_MESSAGEBOXANSWER, 0, data ) != -1 )
00904 {
00905 QDataStream stream( data, IO_ReadOnly );
00906 int answer;
00907 stream >> answer;
00908 kdDebug(7019) << "got messagebox answer" << answer << endl;
00909 return answer;
00910 } else
00911 return 0;
00912 }
00913
00914 bool SlaveBase::canResume( KIO::filesize_t offset )
00915 {
00916 kdDebug(7019) << "SlaveBase::canResume offset=" << KIO::number(offset) << endl;
00917 d->needSendCanResume = false;
00918 KIO_DATA << KIO_FILESIZE_T(offset);
00919 m_pConnection->send( MSG_RESUME, data );
00920 if ( offset )
00921 {
00922 int cmd;
00923 if ( waitForAnswer( CMD_RESUMEANSWER, CMD_NONE, data, &cmd ) != -1 )
00924 {
00925 kdDebug(7019) << "SlaveBase::canResume returning " << (cmd == CMD_RESUMEANSWER) << endl;
00926 return cmd == CMD_RESUMEANSWER;
00927 } else
00928 return false;
00929 }
00930 else
00931 return true;
00932 }
00933
00934
00935
00936 int SlaveBase::waitForAnswer( int expected1, int expected2, QByteArray & data, int *pCmd )
00937 {
00938 int cmd, result;
00939 for (;;)
00940 {
00941 result = m_pConnection->read( &cmd, data );
00942 if ( result == -1 )
00943 {
00944 kdDebug(7019) << "SlaveBase::waitForAnswer has read error." << endl;
00945 return -1;
00946 }
00947 if ( cmd == expected1 || cmd == expected2 )
00948 {
00949 if ( pCmd ) *pCmd = cmd;
00950 return result;
00951 }
00952 if ( isSubCommand(cmd) )
00953 {
00954 dispatch( cmd, data );
00955 }
00956 else
00957 {
00958 kdWarning() << "Got cmd " << cmd << " while waiting for an answer!" << endl;
00959 }
00960 }
00961 }
00962
00963
00964 int SlaveBase::readData( QByteArray &buffer)
00965 {
00966 int result = waitForAnswer( MSG_DATA, 0, buffer );
00967
00968 return result;
00969 }
00970
00971 void SlaveBase::setTimeoutSpecialCommand(int timeout, const QByteArray &data)
00972 {
00973 if (timeout > 0)
00974 d->timeout = time(0)+(time_t)timeout;
00975 else if (timeout == 0)
00976 d->timeout = 1;
00977 else
00978 d->timeout = 0;
00979
00980 d->timeoutData = data;
00981 }
00982
00983 void SlaveBase::dispatch( int command, const QByteArray &data )
00984 {
00985 QDataStream stream( data, IO_ReadOnly );
00986
00987 KURL url;
00988 int i;
00989
00990 switch( command ) {
00991 case CMD_HOST: {
00992
00993 s_seqNr = 0;
00994 QString passwd;
00995 QString host, user;
00996 stream >> host >> i >> user >> passwd;
00997 setHost( host, i, user, passwd );
00998 }
00999 break;
01000 case CMD_CONNECT:
01001 openConnection( );
01002 break;
01003 case CMD_DISCONNECT:
01004 closeConnection( );
01005 break;
01006 case CMD_SLAVE_STATUS:
01007 slave_status();
01008 break;
01009 case CMD_SLAVE_CONNECT:
01010 {
01011 d->onHold = false;
01012 QString app_socket;
01013 QDataStream stream( data, IO_ReadOnly);
01014 stream >> app_socket;
01015 appconn->send( MSG_SLAVE_ACK );
01016 disconnectSlave();
01017 mConnectedToApp = true;
01018 connectSlave(app_socket);
01019 } break;
01020 case CMD_SLAVE_HOLD:
01021 {
01022 KURL url;
01023 QDataStream stream( data, IO_ReadOnly);
01024 stream >> url;
01025 d->onHoldUrl = url;
01026 d->onHold = true;
01027 disconnectSlave();
01028 mConnectedToApp = false;
01029
01030 connectSlave(mPoolSocket);
01031 } break;
01032 case CMD_REPARSECONFIGURATION:
01033 reparseConfiguration();
01034 break;
01035 case CMD_CONFIG:
01036 stream >> d->configData;
01037 #ifdef Q_OS_UNIX //TODO: not yet available on WIN32
01038 KSocks::setConfig(d->config);
01039 #endif
01040 delete d->remotefile;
01041 d->remotefile = 0;
01042 break;
01043 case CMD_GET:
01044 {
01045 stream >> url;
01046 get( url );
01047 } break;
01048 case CMD_PUT:
01049 {
01050 int permissions;
01051 Q_INT8 iOverwrite, iResume;
01052 stream >> url >> iOverwrite >> iResume >> permissions;
01053 bool overwrite = ( iOverwrite != 0 );
01054 bool resume = ( iResume != 0 );
01055
01056
01057
01058
01059 d->needSendCanResume = true ;
01060
01061 put( url, permissions, overwrite, resume);
01062 } break;
01063 case CMD_STAT:
01064 stream >> url;
01065 stat( url );
01066 break;
01067 case CMD_MIMETYPE:
01068 stream >> url;
01069 mimetype( url );
01070 break;
01071 case CMD_LISTDIR:
01072 stream >> url;
01073 listDir( url );
01074 break;
01075 case CMD_MKDIR:
01076 stream >> url >> i;
01077 mkdir( url, i );
01078 break;
01079 case CMD_RENAME:
01080 {
01081 Q_INT8 iOverwrite;
01082 KURL url2;
01083 stream >> url >> url2 >> iOverwrite;
01084 bool overwrite = (iOverwrite != 0);
01085 rename( url, url2, overwrite );
01086 } break;
01087 case CMD_SYMLINK:
01088 {
01089 Q_INT8 iOverwrite;
01090 QString target;
01091 stream >> target >> url >> iOverwrite;
01092 bool overwrite = (iOverwrite != 0);
01093 symlink( target, url, overwrite );
01094 } break;
01095 case CMD_COPY:
01096 {
01097 int permissions;
01098 Q_INT8 iOverwrite;
01099 KURL url2;
01100 stream >> url >> url2 >> permissions >> iOverwrite;
01101 bool overwrite = (iOverwrite != 0);
01102 copy( url, url2, permissions, overwrite );
01103 } break;
01104 case CMD_DEL:
01105 {
01106 Q_INT8 isFile;
01107 stream >> url >> isFile;
01108 del( url, isFile != 0);
01109 } break;
01110 case CMD_CHMOD:
01111 stream >> url >> i;
01112 chmod( url, i);
01113 break;
01114 case CMD_SPECIAL:
01115 special( data );
01116 break;
01117 case CMD_META_DATA:
01118
01119 stream >> mIncomingMetaData;
01120 break;
01121 case CMD_SUBURL:
01122 stream >> url;
01123 setSubURL(url);
01124 break;
01125 case CMD_NONE:
01126 fprintf(stderr, "Got unexpected CMD_NONE!\n");
01127 break;
01128 case CMD_MULTI_GET:
01129 multiGet( data );
01130 break;
01131 default:
01132
01133
01134 break;
01135 }
01136 }
01137
01138 QString SlaveBase::createAuthCacheKey( const KURL& url )
01139 {
01140 if( !url.isValid() )
01141 return QString::null;
01142
01143
01144 QString key = url.protocol();
01145 key += '-';
01146 key += url.host();
01147 int port = url.port();
01148 if( port )
01149 {
01150 key += ':';
01151 key += QString::number(port);
01152 }
01153
01154 return key;
01155 }
01156
01157 bool SlaveBase::pingCacheDaemon() const
01158 {
01159 #ifdef Q_OS_UNIX
01160
01161 KDEsuClient client;
01162 int success = client.ping();
01163 if( success == -1 )
01164 {
01165 success = client.startServer();
01166 if( success == -1 )
01167 {
01168 kdDebug(7019) << "Cannot start a new deamon!!" << endl;
01169 return false;
01170 }
01171 kdDebug(7019) << "Sucessfully started new cache deamon!!" << endl;
01172 }
01173 return true;
01174 #else
01175 return false;
01176 #endif
01177 }
01178
01179 bool SlaveBase::checkCachedAuthentication( AuthInfo& info )
01180 {
01181 QCString replyType;
01182 QByteArray params;
01183 QByteArray reply;
01184 AuthInfo authResult;
01185 long windowId = metaData("window-id").toLong();
01186 unsigned long userTimestamp = metaData("user-timestamp").toULong();
01187
01188 kdDebug(7019) << "SlaveBase::checkCachedAuthInfo window = " << windowId << " url = " << info.url.url() << endl;
01189
01190 (void) dcopClient();
01191
01192 QDataStream stream(params, IO_WriteOnly);
01193 stream << info << windowId << userTimestamp;
01194
01195 if ( !d->dcopClient->call( "kded", "kpasswdserver", "checkAuthInfo(KIO::AuthInfo, long int, unsigned long int)",
01196 params, replyType, reply ) )
01197 {
01198 kdWarning(7019) << "Can't communicate with kded_kpasswdserver!" << endl;
01199 return false;
01200 }
01201
01202 if ( replyType == "KIO::AuthInfo" )
01203 {
01204 QDataStream stream2( reply, IO_ReadOnly );
01205 stream2 >> authResult;
01206 }
01207 else
01208 {
01209 kdError(7019) << "DCOP function checkAuthInfo(...) returns "
01210 << replyType << ", expected KIO::AuthInfo" << endl;
01211 return false;
01212 }
01213 if (!authResult.isModified())
01214 {
01215 return false;
01216 }
01217
01218 info = authResult;
01219 return true;
01220 }
01221
01222 bool SlaveBase::cacheAuthentication( const AuthInfo& info )
01223 {
01224 QByteArray params;
01225 long windowId = metaData("window-id").toLong();
01226
01227 (void) dcopClient();
01228
01229 QDataStream stream(params, IO_WriteOnly);
01230 stream << info << windowId;
01231
01232 d->dcopClient->send( "kded", "kpasswdserver", "addAuthInfo(KIO::AuthInfo, long int)", params );
01233
01234 return true;
01235 }
01236
01237 int SlaveBase::connectTimeout()
01238 {
01239 bool ok;
01240 QString tmp = metaData("ConnectTimeout");
01241 int result = tmp.toInt(&ok);
01242 if (ok)
01243 return result;
01244 return DEFAULT_CONNECT_TIMEOUT;
01245 }
01246
01247 int SlaveBase::proxyConnectTimeout()
01248 {
01249 bool ok;
01250 QString tmp = metaData("ProxyConnectTimeout");
01251 int result = tmp.toInt(&ok);
01252 if (ok)
01253 return result;
01254 return DEFAULT_PROXY_CONNECT_TIMEOUT;
01255 }
01256
01257
01258 int SlaveBase::responseTimeout()
01259 {
01260 bool ok;
01261 QString tmp = metaData("ResponseTimeout");
01262 int result = tmp.toInt(&ok);
01263 if (ok)
01264 return result;
01265 return DEFAULT_RESPONSE_TIMEOUT;
01266 }
01267
01268
01269 int SlaveBase::readTimeout()
01270 {
01271 bool ok;
01272 QString tmp = metaData("ReadTimeout");
01273 int result = tmp.toInt(&ok);
01274 if (ok)
01275 return result;
01276 return DEFAULT_READ_TIMEOUT;
01277 }
01278
01279 bool SlaveBase::wasKilled() const
01280 {
01281 return d->wasKilled;
01282 }
01283
01284 void SlaveBase::setKillFlag()
01285 {
01286 d->wasKilled=true;
01287 }
01288
01289 void SlaveBase::virtual_hook( int, void* )
01290 { }
01291