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