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