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