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