summaryrefslogtreecommitdiffstats
path: root/tdeio/tdeio/slavebase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tdeio/tdeio/slavebase.cpp')
-rw-r--r--tdeio/tdeio/slavebase.cpp1315
1 files changed, 1315 insertions, 0 deletions
diff --git a/tdeio/tdeio/slavebase.cpp b/tdeio/tdeio/slavebase.cpp
new file mode 100644
index 000000000..e979f530b
--- /dev/null
+++ b/tdeio/tdeio/slavebase.cpp
@@ -0,0 +1,1315 @@
+/*
+ *
+ * This file is part of the KDE libraries
+ * Copyright (c) 2000 Waldo Bastian <bastian@kde.org>
+ * Copyright (c) 2000 David Faure <faure@kde.org>
+ * Copyright (c) 2000 Stephan Kulow <coolo@kde.org>
+ *
+ * $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ **/
+
+#include "slavebase.h"
+
+#include <config.h>
+
+#include <sys/time.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h> // Needed on some systems.
+#endif
+
+#include <assert.h>
+#include <kdebug.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <time.h>
+
+#include <tqfile.h>
+
+#include <dcopclient.h>
+
+#include <kapplication.h>
+#include <ksock.h>
+#include <kcrash.h>
+#include <tdesu/client.h>
+#include <klocale.h>
+#include <ksocks.h>
+
+#include "kremoteencoding.h"
+
+#include "tdeio/slavebase.h"
+#include "tdeio/connection.h"
+#include "tdeio/ioslave_defaults.h"
+#include "tdeio/slaveinterface.h"
+
+#include "uiserver_stub.h"
+
+#ifndef NDEBUG
+#ifdef HAVE_BACKTRACE
+#include <execinfo.h>
+#endif
+#endif
+
+using namespace TDEIO;
+
+template class TQPtrList<TQValueList<UDSAtom> >;
+typedef TQValueList<TQCString> AuthKeysList;
+typedef TQMap<TQString,TQCString> AuthKeysMap;
+#define KIO_DATA TQByteArray data; TQDataStream stream( data, IO_WriteOnly ); stream
+#define KIO_FILESIZE_T(x) (unsigned long)(x & 0xffffffff) << (unsigned long)(x >> 32)
+
+namespace TDEIO {
+
+class SlaveBaseConfig : public TDEConfigBase
+{
+public:
+ SlaveBaseConfig(SlaveBase *_slave)
+ : slave(_slave) { }
+
+ bool internalHasGroup(const TQCString &) const { tqWarning("hasGroup(const TQCString &)");
+return false; }
+
+ TQStringList groupList() const { return TQStringList(); }
+
+ TQMap<TQString,TQString> entryMap(const TQString &group) const
+ { Q_UNUSED(group); return TQMap<TQString,TQString>(); }
+
+ void reparseConfiguration() { }
+
+ KEntryMap internalEntryMap( const TQString &pGroup) const { Q_UNUSED(pGroup); return KEntryMap(); }
+
+ KEntryMap internalEntryMap() const { return KEntryMap(); }
+
+ void putData(const KEntryKey &_key, const KEntry&_data, bool _checkGroup)
+ { Q_UNUSED(_key); Q_UNUSED(_data); Q_UNUSED(_checkGroup); }
+
+ KEntry lookupData(const KEntryKey &_key) const
+ {
+ KEntry entry;
+ TQString value = slave->metaData(_key.c_key);
+ if (!value.isNull())
+ entry.mValue = value.utf8();
+ return entry;
+ }
+protected:
+ SlaveBase *slave;
+};
+
+
+class SlaveBasePrivate {
+public:
+ TQString slaveid;
+ bool resume:1;
+ bool needSendCanResume:1;
+ bool onHold:1;
+ bool wasKilled:1;
+ MetaData configData;
+ SlaveBaseConfig *config;
+ KURL onHoldUrl;
+
+ struct timeval last_tv;
+ TDEIO::filesize_t totalSize;
+ TDEIO::filesize_t sentListEntries;
+ DCOPClient *dcopClient;
+ KRemoteEncoding *remotefile;
+ time_t timeout;
+ TQByteArray timeoutData;
+};
+
+}
+
+static SlaveBase *globalSlave;
+long SlaveBase::s_seqNr;
+
+static volatile bool slaveWriteError = false;
+
+static const char *s_protocol;
+
+#ifdef Q_OS_UNIX
+static void genericsig_handler(int sigNumber)
+{
+ signal(sigNumber,SIG_IGN);
+ //WABA: Don't do anything that requires malloc, we can deadlock on it since
+ //a SIGTERM signal can come in while we are in malloc/free.
+ //kdDebug()<<"tdeioslave : exiting due to signal "<<sigNumber<<endl;
+ //set the flag which will be checked in dispatchLoop() and which *should* be checked
+ //in lengthy operations in the various slaves
+ if (globalSlave!=0)
+ globalSlave->setKillFlag();
+ signal(SIGALRM,SIG_DFL);
+ alarm(5); //generate an alarm signal in 5 seconds, in this time the slave has to exit
+}
+#endif
+
+//////////////
+
+SlaveBase::SlaveBase( const TQCString &protocol,
+ const TQCString &pool_socket,
+ const TQCString &app_socket )
+ : mProtocol(protocol), m_pConnection(0),
+ mPoolSocket( TQFile::decodeName(pool_socket)),
+ mAppSocket( TQFile::decodeName(app_socket))
+{
+ s_protocol = protocol.data();
+#ifdef Q_OS_UNIX
+ if (!getenv("TDE_DEBUG"))
+ {
+ KCrash::setCrashHandler( sigsegv_handler );
+ signal(SIGILL,&sigsegv_handler);
+ signal(SIGTRAP,&sigsegv_handler);
+ signal(SIGABRT,&sigsegv_handler);
+ signal(SIGBUS,&sigsegv_handler);
+ signal(SIGALRM,&sigsegv_handler);
+ signal(SIGFPE,&sigsegv_handler);
+#ifdef SIGPOLL
+ signal(SIGPOLL, &sigsegv_handler);
+#endif
+#ifdef SIGSYS
+ signal(SIGSYS, &sigsegv_handler);
+#endif
+#ifdef SIGVTALRM
+ signal(SIGVTALRM, &sigsegv_handler);
+#endif
+#ifdef SIGXCPU
+ signal(SIGXCPU, &sigsegv_handler);
+#endif
+#ifdef SIGXFSZ
+ signal(SIGXFSZ, &sigsegv_handler);
+#endif
+ }
+
+ struct sigaction act;
+ act.sa_handler = sigpipe_handler;
+ sigemptyset( &act.sa_mask );
+ act.sa_flags = 0;
+ sigaction( SIGPIPE, &act, 0 );
+
+ signal(SIGINT,&genericsig_handler);
+ signal(SIGQUIT,&genericsig_handler);
+ signal(SIGTERM,&genericsig_handler);
+#endif
+
+ globalSlave=this;
+
+ appconn = new Connection();
+ listEntryCurrentSize = 100;
+ struct timeval tp;
+ gettimeofday(&tp, 0);
+ listEntry_sec = tp.tv_sec;
+ listEntry_usec = tp.tv_usec;
+ mConnectedToApp = true;
+
+ d = new SlaveBasePrivate;
+ // by kahl for netmgr (need a way to identify slaves)
+ d->slaveid = protocol;
+ d->slaveid += TQString::number(getpid());
+ d->resume = false;
+ d->needSendCanResume = false;
+ d->config = new SlaveBaseConfig(this);
+ d->onHold = false;
+ d->wasKilled=false;
+ d->last_tv.tv_sec = 0;
+ d->last_tv.tv_usec = 0;
+// d->processed_size = 0;
+ d->totalSize=0;
+ d->sentListEntries=0;
+ d->timeout = 0;
+ connectSlave(mAppSocket);
+
+ d->dcopClient = 0;
+ d->remotefile = 0;
+}
+
+SlaveBase::~SlaveBase()
+{
+ delete d;
+ s_protocol = "";
+}
+
+DCOPClient *SlaveBase::dcopClient()
+{
+ if (!d->dcopClient)
+ {
+ d->dcopClient = TDEApplication::dcopClient();
+ if (!d->dcopClient->isAttached())
+ d->dcopClient->attach();
+ d->dcopClient->setDaemonMode( true );
+ }
+ return d->dcopClient;
+}
+
+void SlaveBase::dispatchLoop()
+{
+#ifdef Q_OS_UNIX //TODO: WIN32
+ fd_set rfds;
+ int retval;
+
+ while (true)
+ {
+ if (d->timeout && (d->timeout < time(0)))
+ {
+ TQByteArray data = d->timeoutData;
+ d->timeout = 0;
+ d->timeoutData = TQByteArray();
+ special(data);
+ }
+ FD_ZERO(&rfds);
+
+ assert(appconn->inited());
+ int maxfd = appconn->fd_from();
+ FD_SET(appconn->fd_from(), &rfds);
+ if( d->dcopClient )
+ {
+ FD_SET( d->dcopClient->socket(), &rfds );
+ if( d->dcopClient->socket() > maxfd )
+ maxfd = d->dcopClient->socket();
+ }
+
+ if (!d->timeout) // we can wait forever
+ {
+ retval = select( maxfd + 1, &rfds, NULL, NULL, NULL);
+ }
+ else
+ {
+ struct timeval tv;
+ tv.tv_sec = kMax(d->timeout-time(0),(time_t) 1);
+ tv.tv_usec = 0;
+ retval = select( maxfd + 1, &rfds, NULL, NULL, &tv);
+ }
+ if ((retval>0) && FD_ISSET(appconn->fd_from(), &rfds))
+ { // dispatch application messages
+ int cmd;
+ TQByteArray data;
+ if ( appconn->read(&cmd, data) != -1 )
+ {
+ dispatch(cmd, data);
+ }
+ else // some error occurred, perhaps no more application
+ {
+ // When the app exits, should the slave be put back in the pool ?
+ if (mConnectedToApp && !mPoolSocket.isEmpty())
+ {
+ disconnectSlave();
+ mConnectedToApp = false;
+ closeConnection();
+ connectSlave(mPoolSocket);
+ }
+ else
+ {
+ return;
+ }
+ }
+ }
+ if( retval > 0 && d->dcopClient && FD_ISSET( d->dcopClient->socket(), &rfds ))
+ {
+ d->dcopClient->processSocketData( d->dcopClient->socket());
+ }
+ if ((retval<0) && (errno != EINTR))
+ {
+ kdDebug(7019) << "dispatchLoop(): select returned " << retval << " "
+ << (errno==EBADF?"EBADF":errno==EINTR?"EINTR":errno==EINVAL?"EINVAL":errno==ENOMEM?"ENOMEM":"unknown")
+ << " (" << errno << ")" << endl;
+ return;
+ }
+ //I think we get here when we were killed in dispatch() and not in select()
+ if (wasKilled())
+ {
+ kdDebug(7019)<<" dispatchLoop() slave was killed, returning"<<endl;
+ return;
+ }
+ }
+#else
+#error The KIO slave system only works under UNIX
+#endif
+}
+
+void SlaveBase::connectSlave(const TQString& path)
+{
+#ifdef Q_OS_UNIX //TODO: TDESocket not yet available on WIN32
+ appconn->init(new TDESocket(TQFile::encodeName(path).data()));
+ if (!appconn->inited())
+ {
+ kdDebug(7019) << "SlaveBase: failed to connect to " << path << endl;
+ exit();
+ }
+
+ setConnection(appconn);
+#endif
+}
+
+void SlaveBase::disconnectSlave()
+{
+ appconn->close();
+}
+
+void SlaveBase::setMetaData(const TQString &key, const TQString &value)
+{
+ mOutgoingMetaData.replace(key, value);
+}
+
+TQString SlaveBase::metaData(const TQString &key) const
+{
+ if (mIncomingMetaData.contains(key))
+ return mIncomingMetaData[key];
+ if (d->configData.contains(key))
+ return d->configData[key];
+ return TQString::null;
+}
+
+bool SlaveBase::hasMetaData(const TQString &key) const
+{
+ if (mIncomingMetaData.contains(key))
+ return true;
+ if (d->configData.contains(key))
+ return true;
+ return false;
+}
+
+// ### remove the next two methods for KDE4 (they miss the const)
+TQString SlaveBase::metaData(const TQString &key) {
+ return const_cast<const SlaveBase*>(this)->metaData( key );
+}
+bool SlaveBase::hasMetaData(const TQString &key) {
+ return const_cast<const SlaveBase*>(this)->hasMetaData( key );
+}
+
+TDEConfigBase *SlaveBase::config()
+{
+ return d->config;
+}
+
+void SlaveBase::sendMetaData()
+{
+ KIO_DATA << mOutgoingMetaData;
+
+ slaveWriteError = false;
+ m_pConnection->send( INF_META_DATA, data );
+ if (slaveWriteError) exit();
+ mOutgoingMetaData.clear(); // Clear
+}
+
+KRemoteEncoding *SlaveBase::remoteEncoding()
+{
+ if (d->remotefile != 0)
+ return d->remotefile;
+
+ return d->remotefile = new KRemoteEncoding(metaData("Charset").latin1());
+}
+
+void SlaveBase::data( const TQByteArray &data )
+{
+ if (!mOutgoingMetaData.isEmpty())
+ sendMetaData();
+ slaveWriteError = false;
+ m_pConnection->send( MSG_DATA, data );
+ if (slaveWriteError) exit();
+}
+
+void SlaveBase::dataReq( )
+{
+/*
+ if (!mOutgoingMetaData.isEmpty())
+ sendMetaData();
+*/
+ if (d->needSendCanResume)
+ canResume(0);
+ m_pConnection->send( MSG_DATA_REQ );
+}
+
+void SlaveBase::error( int _errid, const TQString &_text )
+{
+ mIncomingMetaData.clear(); // Clear meta data
+ mOutgoingMetaData.clear();
+ KIO_DATA << (TQ_INT32) _errid << _text;
+
+ m_pConnection->send( MSG_ERROR, data );
+ //reset
+ listEntryCurrentSize = 100;
+ d->sentListEntries=0;
+ d->totalSize=0;
+}
+
+void SlaveBase::connected()
+{
+ slaveWriteError = false;
+ m_pConnection->send( MSG_CONNECTED );
+ if (slaveWriteError) exit();
+}
+
+void SlaveBase::finished()
+{
+ mIncomingMetaData.clear(); // Clear meta data
+ if (!mOutgoingMetaData.isEmpty())
+ sendMetaData();
+ m_pConnection->send( MSG_FINISHED );
+
+ // reset
+ listEntryCurrentSize = 100;
+ d->sentListEntries=0;
+ d->totalSize=0;
+}
+
+void SlaveBase::needSubURLData()
+{
+ m_pConnection->send( MSG_NEED_SUBURL_DATA );
+}
+
+void SlaveBase::slaveStatus( const TQString &host, bool connected )
+{
+ pid_t pid = getpid();
+ TQ_INT8 b = connected ? 1 : 0;
+ KIO_DATA << pid << mProtocol << host << b;
+ if (d->onHold)
+ stream << d->onHoldUrl;
+ m_pConnection->send( MSG_SLAVE_STATUS, data );
+}
+
+void SlaveBase::canResume()
+{
+ m_pConnection->send( MSG_CANRESUME );
+}
+
+void SlaveBase::totalSize( TDEIO::filesize_t _bytes )
+{
+ KIO_DATA << KIO_FILESIZE_T(_bytes);
+ slaveWriteError = false;
+ m_pConnection->send( INF_TOTAL_SIZE, data );
+ if (slaveWriteError) exit();
+
+ //this one is usually called before the first item is listed in listDir()
+ struct timeval tp;
+ gettimeofday(&tp, 0);
+ listEntry_sec = tp.tv_sec;
+ listEntry_usec = tp.tv_usec;
+ d->totalSize=_bytes;
+ d->sentListEntries=0;
+}
+
+void SlaveBase::processedSize( TDEIO::filesize_t _bytes )
+{
+ bool emitSignal=false;
+ struct timeval tv;
+ int gettimeofday_res=gettimeofday( &tv, 0L );
+
+ if( _bytes == d->totalSize )
+ emitSignal=true;
+ else if ( gettimeofday_res == 0 ) {
+ time_t msecdiff = 2000;
+ if (d->last_tv.tv_sec) {
+ // Compute difference, in ms
+ msecdiff = 1000 * ( tv.tv_sec - d->last_tv.tv_sec );
+ time_t usecdiff = tv.tv_usec - d->last_tv.tv_usec;
+ if ( usecdiff < 0 ) {
+ msecdiff--;
+ msecdiff += 1000;
+ }
+ msecdiff += usecdiff / 1000;
+ }
+ emitSignal=msecdiff >= 100; // emit size 10 times a second
+ }
+
+ if( emitSignal ) {
+ KIO_DATA << KIO_FILESIZE_T(_bytes);
+ slaveWriteError = false;
+ m_pConnection->send( INF_PROCESSED_SIZE, data );
+ if (slaveWriteError) exit();
+ if ( gettimeofday_res == 0 ) {
+ d->last_tv.tv_sec = tv.tv_sec;
+ d->last_tv.tv_usec = tv.tv_usec;
+ }
+ }
+// d->processed_size = _bytes;
+}
+
+void SlaveBase::processedPercent( float /* percent */ )
+{
+ kdDebug(7019) << "SlaveBase::processedPercent: STUB" << endl;
+}
+
+
+void SlaveBase::speed( unsigned long _bytes_per_second )
+{
+ KIO_DATA << (TQ_UINT32) _bytes_per_second;
+ slaveWriteError = false;
+ m_pConnection->send( INF_SPEED, data );
+ if (slaveWriteError) exit();
+}
+
+void SlaveBase::redirection( const KURL& _url )
+{
+ KIO_DATA << _url;
+ m_pConnection->send( INF_REDIRECTION, data );
+}
+
+void SlaveBase::errorPage()
+{
+ m_pConnection->send( INF_ERROR_PAGE );
+}
+
+static bool isSubCommand(int cmd)
+{
+ return ( (cmd == CMD_REPARSECONFIGURATION) ||
+ (cmd == CMD_META_DATA) ||
+ (cmd == CMD_CONFIG) ||
+ (cmd == CMD_SUBURL) ||
+ (cmd == CMD_SLAVE_STATUS) ||
+ (cmd == CMD_SLAVE_CONNECT) ||
+ (cmd == CMD_SLAVE_HOLD) ||
+ (cmd == CMD_MULTI_GET));
+}
+
+void SlaveBase::mimeType( const TQString &_type)
+{
+ // kdDebug(7019) << "(" << getpid() << ") SlaveBase::mimeType '" << _type << "'" << endl;
+ int cmd;
+ do
+ {
+ // Send the meta-data each time we send the mime-type.
+ if (!mOutgoingMetaData.isEmpty())
+ {
+ // kdDebug(7019) << "(" << getpid() << ") mimeType: emitting meta data" << endl;
+ KIO_DATA << mOutgoingMetaData;
+ m_pConnection->send( INF_META_DATA, data );
+ }
+ KIO_DATA << _type;
+ m_pConnection->send( INF_MIME_TYPE, data );
+ while(true)
+ {
+ cmd = 0;
+ if ( m_pConnection->read( &cmd, data ) == -1 ) {
+ kdDebug(7019) << "SlaveBase: mimetype: read error" << endl;
+ exit();
+ }
+ // kdDebug(7019) << "(" << getpid() << ") Slavebase: mimetype got " << cmd << endl;
+ if ( cmd == CMD_HOST) // Ignore.
+ continue;
+ if ( isSubCommand(cmd) )
+ {
+ dispatch( cmd, data );
+ continue; // Disguised goto
+ }
+ break;
+ }
+ }
+ while (cmd != CMD_NONE);
+ mOutgoingMetaData.clear();
+}
+
+void SlaveBase::exit()
+{
+ this->~SlaveBase();
+ ::exit(255);
+}
+
+void SlaveBase::warning( const TQString &_msg)
+{
+ KIO_DATA << _msg;
+ m_pConnection->send( INF_WARNING, data );
+}
+
+void SlaveBase::infoMessage( const TQString &_msg)
+{
+ KIO_DATA << _msg;
+ m_pConnection->send( INF_INFOMESSAGE, data );
+}
+
+bool SlaveBase::requestNetwork(const TQString& host)
+{
+ KIO_DATA << host << d->slaveid;
+ m_pConnection->send( MSG_NET_REQUEST, data );
+
+ if ( waitForAnswer( INF_NETWORK_STATUS, 0, data ) != -1 )
+ {
+ bool status;
+ TQDataStream stream( data, IO_ReadOnly );
+ stream >> status;
+ return status;
+ } else
+ return false;
+}
+
+void SlaveBase::dropNetwork(const TQString& host)
+{
+ KIO_DATA << host << d->slaveid;
+ m_pConnection->send( MSG_NET_DROP, data );
+}
+
+void SlaveBase::statEntry( const UDSEntry& entry )
+{
+ KIO_DATA << entry;
+ slaveWriteError = false;
+ m_pConnection->send( MSG_STAT_ENTRY, data );
+ if (slaveWriteError) exit();
+}
+
+void SlaveBase::listEntry( const UDSEntry& entry, bool _ready )
+{
+ static struct timeval tp;
+ static const int maximum_updatetime = 300;
+ static const int minimum_updatetime = 100;
+
+ if (!_ready) {
+ pendingListEntries.append(entry);
+
+ if (pendingListEntries.count() > listEntryCurrentSize) {
+ gettimeofday(&tp, 0);
+
+ long diff = ((tp.tv_sec - listEntry_sec) * 1000000 +
+ tp.tv_usec - listEntry_usec) / 1000;
+ if (diff==0) diff=1;
+
+ if (diff > maximum_updatetime) {
+ listEntryCurrentSize = listEntryCurrentSize * 3 / 4;
+ _ready = true;
+ }
+//if we can send all list entries of this dir which have not yet been sent
+//within maximum_updatetime, then make listEntryCurrentSize big enough for all of them
+ else if (((pendingListEntries.count()*maximum_updatetime)/diff) > (d->totalSize-d->sentListEntries))
+ listEntryCurrentSize=d->totalSize-d->sentListEntries+1;
+//if we are below minimum_updatetime, estimate how much we will get within
+//maximum_updatetime
+ else if (diff < minimum_updatetime)
+ listEntryCurrentSize = (pendingListEntries.count() * maximum_updatetime) / diff;
+ else
+ _ready=true;
+ }
+ }
+ if (_ready) { // may happen when we started with !ready
+ listEntries( pendingListEntries );
+ pendingListEntries.clear();
+
+ gettimeofday(&tp, 0);
+ listEntry_sec = tp.tv_sec;
+ listEntry_usec = tp.tv_usec;
+ }
+}
+
+void SlaveBase::listEntries( const UDSEntryList& list )
+{
+ KIO_DATA << (TQ_UINT32)list.count();
+ UDSEntryListConstIterator it = list.begin();
+ UDSEntryListConstIterator end = list.end();
+ for (; it != end; ++it)
+ stream << *it;
+ slaveWriteError = false;
+ m_pConnection->send( MSG_LIST_ENTRIES, data);
+ if (slaveWriteError) exit();
+ d->sentListEntries+=(uint)list.count();
+}
+
+void SlaveBase::sendAuthenticationKey( const TQCString& key,
+ const TQCString& group,
+ bool keepPass )
+{
+ KIO_DATA << key << group << keepPass;
+ m_pConnection->send( MSG_AUTH_KEY, data );
+}
+
+void SlaveBase::delCachedAuthentication( const TQString& key )
+{
+ KIO_DATA << key.utf8() ;
+ m_pConnection->send( MSG_DEL_AUTH_KEY, data );
+}
+
+void SlaveBase::sigsegv_handler(int sig)
+{
+#ifdef Q_OS_UNIX
+ signal(sig,SIG_DFL); // Next one kills
+
+ //Kill us if we deadlock
+ signal(SIGALRM,SIG_DFL);
+ alarm(5); //generate an alarm signal in 5 seconds, in this time the slave has to exit
+
+ // Debug and printf should be avoided because they might
+ // call malloc.. and get in a nice recursive malloc loop
+ char buffer[120];
+ snprintf(buffer, sizeof(buffer), "tdeioslave: ####### CRASH ###### protocol = %s pid = %d signal = %d\n", s_protocol, getpid(), sig);
+ write(2, buffer, strlen(buffer));
+#ifndef NDEBUG
+#ifdef HAVE_BACKTRACE
+ void* trace[256];
+ int n = backtrace(trace, 256);
+ if (n)
+ backtrace_symbols_fd(trace, n, 2);
+#endif
+#endif
+ ::exit(1);
+#endif
+}
+
+void SlaveBase::sigpipe_handler (int)
+{
+ // We ignore a SIGPIPE in slaves.
+ // A SIGPIPE can happen in two cases:
+ // 1) Communication error with application.
+ // 2) Communication error with network.
+ slaveWriteError = true;
+
+ // Don't add anything else here, especially no debug output
+}
+
+void SlaveBase::setHost(TQString const &, int, TQString const &, TQString const &)
+{
+}
+
+void SlaveBase::openConnection(void)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_CONNECT)); }
+void SlaveBase::closeConnection(void)
+{ } // No response!
+void SlaveBase::stat(KURL const &)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_STAT)); }
+void SlaveBase::put(KURL const &, int, bool, bool)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_PUT)); }
+void SlaveBase::special(const TQByteArray &)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SPECIAL)); }
+void SlaveBase::listDir(KURL const &)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_LISTDIR)); }
+void SlaveBase::get(KURL const & )
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_GET)); }
+void SlaveBase::mimetype(KURL const &url)
+{ get(url); }
+void SlaveBase::rename(KURL const &, KURL const &, bool)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_RENAME)); }
+void SlaveBase::symlink(TQString const &, KURL const &, bool)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SYMLINK)); }
+void SlaveBase::copy(KURL const &, KURL const &, int, bool)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_COPY)); }
+void SlaveBase::del(KURL const &, bool)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_DEL)); }
+void SlaveBase::mkdir(KURL const &, int)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_MKDIR)); }
+void SlaveBase::chmod(KURL const &, int)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_CHMOD)); }
+void SlaveBase::setSubURL(KURL const &)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_SUBURL)); }
+void SlaveBase::multiGet(const TQByteArray &)
+{ error( ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, CMD_MULTI_GET)); }
+
+
+void SlaveBase::slave_status()
+{ slaveStatus( TQString::null, false ); }
+
+void SlaveBase::reparseConfiguration()
+{
+}
+
+void SlaveBase::localURL(const KURL& remoteURL)
+{
+ bool local = remoteURL.isLocalFile();
+ TQ_INT8 islocal;
+ KURL retURL;
+ if (local) {
+ islocal = true;
+ retURL = remoteURL;
+ }
+ else {
+ islocal = false;
+ retURL = remoteURL;
+ }
+ KIO_DATA << islocal << retURL;
+ m_pConnection->send( INF_LOCALURL, data );
+}
+
+bool SlaveBase::dispatch()
+{
+ assert( m_pConnection );
+
+ int cmd;
+ TQByteArray data;
+ if ( m_pConnection->read( &cmd, data ) == -1 )
+ {
+ kdDebug(7019) << "SlaveBase::dispatch() has read error." << endl;
+ return false;
+ }
+
+ dispatch( cmd, data );
+ return true;
+}
+
+bool SlaveBase::openPassDlg( AuthInfo& info )
+{
+ return openPassDlg(info, TQString::null);
+}
+
+bool SlaveBase::openPassDlg( AuthInfo& info, const TQString &errorMsg )
+{
+ TQCString replyType;
+ TQByteArray params;
+ TQByteArray reply;
+ AuthInfo authResult;
+ long windowId = metaData("window-id").toLong();
+ long progressId = metaData("progress-id").toLong();
+ unsigned long userTimestamp = metaData("user-timestamp").toULong();
+
+ kdDebug(7019) << "SlaveBase::openPassDlg window-id=" << windowId << " progress-id=" << progressId << endl;
+
+ (void) dcopClient(); // Make sure to have a dcop client.
+
+ UIServer_stub uiserver( "tdeio_uiserver", "UIServer" );
+ if (progressId)
+ uiserver.setJobVisible( progressId, false );
+
+ TQDataStream stream(params, IO_WriteOnly);
+
+ if (metaData("no-auth-prompt").lower() == "true")
+ stream << info << TQString("<NoAuthPrompt>") << windowId << s_seqNr << userTimestamp;
+ else
+ stream << info << errorMsg << windowId << s_seqNr << userTimestamp;
+
+ bool callOK = d->dcopClient->call( "kded", "kpasswdserver", "queryAuthInfo(TDEIO::AuthInfo, TQString, long int, long int, unsigned long int)",
+ params, replyType, reply );
+
+ if (progressId)
+ uiserver.setJobVisible( progressId, true );
+
+ if (!callOK)
+ {
+ kdWarning(7019) << "Can't communicate with kded_kpasswdserver!" << endl;
+ return false;
+ }
+
+ if ( replyType == "TDEIO::AuthInfo" )
+ {
+ TQDataStream stream2( reply, IO_ReadOnly );
+ stream2 >> authResult >> s_seqNr;
+ }
+ else
+ {
+ kdError(7019) << "DCOP function queryAuthInfo(...) returns "
+ << replyType << ", expected TDEIO::AuthInfo" << endl;
+ return false;
+ }
+
+ if (!authResult.isModified())
+ return false;
+
+ info = authResult;
+
+ kdDebug(7019) << "SlaveBase::openPassDlg: username=" << info.username << endl;
+ kdDebug(7019) << "SlaveBase::openPassDlg: password=[hidden]" << endl;
+
+ return true;
+}
+
+int SlaveBase::messageBox( MessageBoxType type, const TQString &text, const TQString &caption,
+ const TQString &buttonYes, const TQString &buttonNo )
+{
+ return messageBox( text, type, caption, buttonYes, buttonNo, TQString::null );
+}
+
+int SlaveBase::messageBox( const TQString &text, MessageBoxType type, const TQString &caption,
+ const TQString &buttonYes, const TQString &buttonNo, const TQString &dontAskAgainName )
+{
+ kdDebug(7019) << "messageBox " << type << " " << text << " - " << caption << buttonYes << buttonNo << endl;
+ KIO_DATA << (TQ_INT32)type << text << caption << buttonYes << buttonNo << dontAskAgainName;
+ m_pConnection->send( INF_MESSAGEBOX, data );
+ if ( waitForAnswer( CMD_MESSAGEBOXANSWER, 0, data ) != -1 )
+ {
+ TQDataStream stream( data, IO_ReadOnly );
+ int answer;
+ stream >> answer;
+ kdDebug(7019) << "got messagebox answer" << answer << endl;
+ return answer;
+ } else
+ return 0; // communication failure
+}
+
+bool SlaveBase::canResume( TDEIO::filesize_t offset )
+{
+ kdDebug(7019) << "SlaveBase::canResume offset=" << TDEIO::number(offset) << endl;
+ d->needSendCanResume = false;
+ KIO_DATA << KIO_FILESIZE_T(offset);
+ m_pConnection->send( MSG_RESUME, data );
+ if ( offset )
+ {
+ int cmd;
+ if ( waitForAnswer( CMD_RESUMEANSWER, CMD_NONE, data, &cmd ) != -1 )
+ {
+ kdDebug(7019) << "SlaveBase::canResume returning " << (cmd == CMD_RESUMEANSWER) << endl;
+ return cmd == CMD_RESUMEANSWER;
+ } else
+ return false;
+ }
+ else // No resuming possible -> no answer to wait for
+ return true;
+}
+
+
+
+int SlaveBase::waitForAnswer( int expected1, int expected2, TQByteArray & data, int *pCmd )
+{
+ int cmd, result;
+ for (;;)
+ {
+ result = m_pConnection->read( &cmd, data );
+ if ( result == -1 )
+ {
+ kdDebug(7019) << "SlaveBase::waitForAnswer has read error." << endl;
+ return -1;
+ }
+ if ( cmd == expected1 || cmd == expected2 )
+ {
+ if ( pCmd ) *pCmd = cmd;
+ return result;
+ }
+ if ( isSubCommand(cmd) )
+ {
+ dispatch( cmd, data );
+ }
+ else
+ {
+ kdWarning() << "Got cmd " << cmd << " while waiting for an answer!" << endl;
+ }
+ }
+}
+
+
+int SlaveBase::readData( TQByteArray &buffer)
+{
+ int result = waitForAnswer( MSG_DATA, 0, buffer );
+ //kdDebug(7019) << "readData: length = " << result << " " << endl;
+ return result;
+}
+
+void SlaveBase::setTimeoutSpecialCommand(int timeout, const TQByteArray &data)
+{
+ if (timeout > 0)
+ d->timeout = time(0)+(time_t)timeout;
+ else if (timeout == 0)
+ d->timeout = 1; // Immediate timeout
+ else
+ d->timeout = 0; // Canceled
+
+ d->timeoutData = data;
+}
+
+void SlaveBase::dispatch( int command, const TQByteArray &data )
+{
+ TQDataStream stream( data, IO_ReadOnly );
+
+ KURL url;
+ int i;
+
+ switch( command ) {
+ case CMD_HOST: {
+ // Reset s_seqNr, see kpasswdserver/DESIGN
+ s_seqNr = 0;
+ TQString passwd;
+ TQString host, user;
+ stream >> host >> i >> user >> passwd;
+ setHost( host, i, user, passwd );
+ }
+ break;
+ case CMD_CONNECT:
+ openConnection( );
+ break;
+ case CMD_DISCONNECT:
+ closeConnection( );
+ break;
+ case CMD_SLAVE_STATUS:
+ slave_status();
+ break;
+ case CMD_SLAVE_CONNECT:
+ {
+ d->onHold = false;
+ TQString app_socket;
+ TQDataStream stream( data, IO_ReadOnly);
+ stream >> app_socket;
+ appconn->send( MSG_SLAVE_ACK );
+ disconnectSlave();
+ mConnectedToApp = true;
+ connectSlave(app_socket);
+ } break;
+ case CMD_SLAVE_HOLD:
+ {
+ KURL url;
+ TQDataStream stream( data, IO_ReadOnly);
+ stream >> url;
+ d->onHoldUrl = url;
+ d->onHold = true;
+ disconnectSlave();
+ mConnectedToApp = false;
+ // Do not close connection!
+ connectSlave(mPoolSocket);
+ } break;
+ case CMD_REPARSECONFIGURATION:
+ reparseConfiguration();
+ break;
+ case CMD_CONFIG:
+ stream >> d->configData;
+#ifdef Q_OS_UNIX //TODO: not yet available on WIN32
+ KSocks::setConfig(d->config);
+#endif
+ delete d->remotefile;
+ d->remotefile = 0;
+ break;
+ case CMD_GET:
+ {
+ stream >> url;
+ get( url );
+ } break;
+ case CMD_PUT:
+ {
+ int permissions;
+ TQ_INT8 iOverwrite, iResume;
+ stream >> url >> iOverwrite >> iResume >> permissions;
+ bool overwrite = ( iOverwrite != 0 );
+ bool resume = ( iResume != 0 );
+
+ // Remember that we need to send canResume(), TransferJob is expecting
+ // it. Well, in theory this shouldn't be done if resume is true.
+ // (the resume bool is currently unused)
+ d->needSendCanResume = true /* !resume */;
+
+ put( url, permissions, overwrite, resume);
+ } break;
+ case CMD_STAT:
+ stream >> url;
+ stat( url );
+ break;
+ case CMD_MIMETYPE:
+ stream >> url;
+ mimetype( url );
+ break;
+ case CMD_LISTDIR:
+ stream >> url;
+ listDir( url );
+ break;
+ case CMD_MKDIR:
+ stream >> url >> i;
+ mkdir( url, i );
+ break;
+ case CMD_RENAME:
+ {
+ TQ_INT8 iOverwrite;
+ KURL url2;
+ stream >> url >> url2 >> iOverwrite;
+ bool overwrite = (iOverwrite != 0);
+ rename( url, url2, overwrite );
+ } break;
+ case CMD_SYMLINK:
+ {
+ TQ_INT8 iOverwrite;
+ TQString target;
+ stream >> target >> url >> iOverwrite;
+ bool overwrite = (iOverwrite != 0);
+ symlink( target, url, overwrite );
+ } break;
+ case CMD_COPY:
+ {
+ int permissions;
+ TQ_INT8 iOverwrite;
+ KURL url2;
+ stream >> url >> url2 >> permissions >> iOverwrite;
+ bool overwrite = (iOverwrite != 0);
+ copy( url, url2, permissions, overwrite );
+ } break;
+ case CMD_DEL:
+ {
+ TQ_INT8 isFile;
+ stream >> url >> isFile;
+ del( url, isFile != 0);
+ } break;
+ case CMD_CHMOD:
+ stream >> url >> i;
+ chmod( url, i);
+ break;
+ case CMD_SPECIAL:
+ special( data );
+ break;
+ case CMD_META_DATA:
+ //kdDebug(7019) << "(" << getpid() << ") Incoming meta-data..." << endl;
+ stream >> mIncomingMetaData;
+ break;
+ case CMD_SUBURL:
+ stream >> url;
+ setSubURL(url);
+ break;
+ case CMD_NONE:
+ fprintf(stderr, "Got unexpected CMD_NONE!\n");
+ break;
+ case CMD_MULTI_GET:
+ multiGet( data );
+ break;
+ case CMD_LOCALURL:
+ {
+ stream >> url;
+ localURL( url );
+ } break;
+ default:
+ // Some command we don't understand.
+ // Just ignore it, it may come from some future version of KDE.
+ break;
+ }
+}
+
+TQString SlaveBase::createAuthCacheKey( const KURL& url )
+{
+ if( !url.isValid() )
+ return TQString::null;
+
+ // Generate the basic key sequence.
+ TQString key = url.protocol();
+ key += '-';
+ key += url.host();
+ int port = url.port();
+ if( port )
+ {
+ key += ':';
+ key += TQString::number(port);
+ }
+
+ return key;
+}
+
+bool SlaveBase::pingCacheDaemon() const
+{
+#ifdef Q_OS_UNIX
+ // TODO: Ping kded / kpasswdserver
+ KDEsuClient client;
+ int success = client.ping();
+ if( success == -1 )
+ {
+ success = client.startServer();
+ if( success == -1 )
+ {
+ kdDebug(7019) << "Cannot start a new deamon!!" << endl;
+ return false;
+ }
+ kdDebug(7019) << "Sucessfully started new cache deamon!!" << endl;
+ }
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool SlaveBase::checkCachedAuthentication( AuthInfo& info )
+{
+ TQCString replyType;
+ TQByteArray params;
+ TQByteArray reply;
+ AuthInfo authResult;
+ long windowId = metaData("window-id").toLong();
+ unsigned long userTimestamp = metaData("user-timestamp").toULong();
+
+ kdDebug(7019) << "SlaveBase::checkCachedAuthInfo window = " << windowId << " url = " << info.url.url() << endl;
+
+ (void) dcopClient(); // Make sure to have a dcop client.
+
+ TQDataStream stream(params, IO_WriteOnly);
+ stream << info << windowId << userTimestamp;
+
+ if ( !d->dcopClient->call( "kded", "kpasswdserver", "checkAuthInfo(TDEIO::AuthInfo, long int, unsigned long int)",
+ params, replyType, reply ) )
+ {
+ kdWarning(7019) << "Can't communicate with kded_kpasswdserver!" << endl;
+ return false;
+ }
+
+ if ( replyType == "TDEIO::AuthInfo" )
+ {
+ TQDataStream stream2( reply, IO_ReadOnly );
+ stream2 >> authResult;
+ }
+ else
+ {
+ kdError(7019) << "DCOP function checkAuthInfo(...) returns "
+ << replyType << ", expected TDEIO::AuthInfo" << endl;
+ return false;
+ }
+ if (!authResult.isModified())
+ {
+ return false;
+ }
+
+ info = authResult;
+ return true;
+}
+
+bool SlaveBase::cacheAuthentication( const AuthInfo& info )
+{
+ TQByteArray params;
+ long windowId = metaData("window-id").toLong();
+
+ (void) dcopClient(); // Make sure to have a dcop client.
+
+ TQDataStream stream(params, IO_WriteOnly);
+ stream << info << windowId;
+
+ d->dcopClient->send( "kded", "kpasswdserver", "addAuthInfo(TDEIO::AuthInfo, long int)", params );
+
+ return true;
+}
+
+int SlaveBase::connectTimeout()
+{
+ bool ok;
+ TQString tmp = metaData("ConnectTimeout");
+ int result = tmp.toInt(&ok);
+ if (ok)
+ return result;
+ return DEFAULT_CONNECT_TIMEOUT;
+}
+
+int SlaveBase::proxyConnectTimeout()
+{
+ bool ok;
+ TQString tmp = metaData("ProxyConnectTimeout");
+ int result = tmp.toInt(&ok);
+ if (ok)
+ return result;
+ return DEFAULT_PROXY_CONNECT_TIMEOUT;
+}
+
+
+int SlaveBase::responseTimeout()
+{
+ bool ok;
+ TQString tmp = metaData("ResponseTimeout");
+ int result = tmp.toInt(&ok);
+ if (ok)
+ return result;
+ return DEFAULT_RESPONSE_TIMEOUT;
+}
+
+
+int SlaveBase::readTimeout()
+{
+ bool ok;
+ TQString tmp = metaData("ReadTimeout");
+ int result = tmp.toInt(&ok);
+ if (ok)
+ return result;
+ return DEFAULT_READ_TIMEOUT;
+}
+
+bool SlaveBase::wasKilled() const
+{
+ return d->wasKilled;
+}
+
+void SlaveBase::setKillFlag()
+{
+ d->wasKilled=true;
+}
+
+void SlaveBase::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+