37 #include <QtCore/QFile>
38 #include <QtCore/QList>
39 #include <QtCore/QDateTime>
40 #include <QtCore/QCoreApplication>
70 #define KIO_DATA QByteArray data; QDataStream stream( &data, QIODevice::WriteOnly ); stream
71 #define KIO_FILESIZE_T(x) quint64(x)
75 class SlaveBasePrivate {
78 SlaveBasePrivate(
SlaveBase* owner): q(owner), m_passwdServer(0) {}
79 ~SlaveBasePrivate() {
delete m_passwdServer; }
82 QTime m_timeSinceLastBatch;
83 Connection appConnection;
85 bool isConnectedToApp;
86 static qlonglong s_seqNr;
90 bool needSendCanResume:1;
100 struct timeval last_tv;
105 enum { Idle, InsideMethod, FinishedCalled, ErrorCalled } m_state;
106 QByteArray timeoutData;
113 configGroup->deleteGroup(KConfigGroup::WriteConfigFlags());
117 MetaData::ConstIterator
end = configData.constEnd();
118 for (MetaData::ConstIterator it = configData.constBegin(); it != end; ++it)
119 configGroup->writeEntry(it.key(), it->toUtf8(), KConfigGroup::WriteConfigFlags());
121 end = q->mIncomingMetaData.constEnd();
122 for (MetaData::ConstIterator it = q->mIncomingMetaData.constBegin(); it != end; ++it)
123 configGroup->writeEntry(it.key(), it->toUtf8(), KConfigGroup::WriteConfigFlags());
126 void verifyState(
const char* cmdName)
128 if ((m_state != FinishedCalled) && (m_state != ErrorCalled)){
129 kWarning(7019) << cmdName <<
"did not call finished() or error()! Please fix the KIO slave.";
133 void verifyErrorFinishedNotCalled(
const char* cmdName)
135 if (m_state == FinishedCalled || m_state == ErrorCalled) {
136 kWarning(7019) << cmdName <<
"called finished() or error(), but it's not supposed to! Please fix the KIO slave.";
142 if (!m_passwdServer) {
146 return m_passwdServer;
153 qlonglong SlaveBasePrivate::s_seqNr;
163 KDE_signal(sigNumber,SIG_IGN);
171 KDE_signal(SIGALRM,SIG_DFL);
180 const QByteArray &pool_socket,
181 const QByteArray &app_socket )
182 : mProtocol(protocol),
183 d(new SlaveBasePrivate(this))
186 d->poolSocket = QFile::decodeName(pool_socket);
189 if (qgetenv(
"KDE_DEBUG").isEmpty())
215 struct sigaction act;
217 sigemptyset( &act.sa_mask );
219 sigaction( SIGPIPE, &act, 0 );
228 d->isConnectedToApp =
true;
231 d->slaveid = protocol;
234 d->needSendCanResume =
false;
240 d->last_tv.tv_sec = 0;
241 d->last_tv.tv_usec = 0;
244 d->sentListEntries=0;
249 d->inOpenLoop =
false;
250 d->exit_loop =
false;
255 delete d->configGroup;
257 delete d->remotefile;
264 while (!d->exit_loop) {
265 if (d->timeout && (d->timeout < time(0))) {
266 QByteArray
data = d->timeoutData;
268 d->timeoutData = QByteArray();
272 Q_ASSERT(d->appConnection.inited());
276 ms = 1000 * qMax<time_t>(d->timeout - time(0), 1);
279 if (d->appConnection.hasTaskAvailable() || d->appConnection.waitForIncomingTask(ms)) {
283 ret = d->appConnection.read(&cmd, data);
292 ret = d->appConnection.isConnected() ? 0 : -1;
297 if (!d->exit_loop && d->isConnectedToApp && !d->poolSocket.isEmpty()) {
299 d->isConnectedToApp =
false;
309 kDebug(7019) <<
"slave was killed, returning";
314 QCoreApplication::sendPostedEvents(NULL, QEvent::DeferredDelete);
318 QCoreApplication::sendPostedEvents(NULL, QEvent::DeferredDelete);
323 d->appConnection.connectToRemote(address);
325 if (!d->appConnection.inited())
327 kDebug(7019) <<
"failed to connect to" << address << endl
328 <<
"Reason:" << d->appConnection.errorString();
333 d->inOpenLoop =
false;
338 d->appConnection.close();
350 if (d->configData.contains(key))
351 return d->configData[key];
364 if (d->configData.contains(key))
371 return d->configGroup;
392 return d->remotefile;
394 const QByteArray charset (
metaData(QLatin1String(
"Charset")).toLatin1());
407 if (d->needSendCanResume)
416 d->inOpenLoop =
true;
421 if (d->m_state == d->ErrorCalled) {
422 kWarning(7019) <<
"error() called twice! Please fix the KIO slave.";
424 }
else if (d->m_state == d->FinishedCalled) {
425 kWarning(7019) <<
"error() called after finished()! Please fix the KIO slave.";
429 d->m_state = d->ErrorCalled;
437 d->sentListEntries=0;
449 if (d->m_state == d->FinishedCalled) {
450 kWarning(7019) <<
"finished() called twice! Please fix the KIO slave.";
452 }
else if (d->m_state == d->ErrorCalled) {
453 kWarning(7019) <<
"finished() called after error()! Please fix the KIO slave.";
457 d->m_state = d->FinishedCalled;
464 d->sentListEntries=0;
478 template<
int T>
struct PIDType {
typedef pid_t PID_t; } ;
479 template<>
struct PIDType<2> {
typedef qint16 PID_t; } ;
480 template<>
struct PIDType<4> {
typedef qint32 PID_t; } ;
484 pid_t pid = getpid();
485 qint8 b = connected ? 1 : 0;
486 KIO_DATA << (PIDType<sizeof(pid_t)>::PID_t)pid <<
mProtocol << host << b;
488 stream << d->onHoldUrl;
504 d->sentListEntries=0;
511 int gettimeofday_res=gettimeofday( &tv, 0L );
513 if( _bytes == d->totalSize )
515 else if ( gettimeofday_res == 0 ) {
516 time_t msecdiff = 2000;
517 if (d->last_tv.tv_sec) {
519 msecdiff = 1000 * ( tv.tv_sec - d->last_tv.tv_sec );
520 time_t usecdiff = tv.tv_usec - d->last_tv.tv_usec;
521 if ( usecdiff < 0 ) {
525 msecdiff += usecdiff / 1000;
527 emitSignal=msecdiff >= 100;
533 if ( gettimeofday_res == 0 ) {
534 d->last_tv.tv_sec = tv.tv_sec;
535 d->last_tv.tv_usec = tv.tv_usec;
607 if (d->appConnection.hasTaskAvailable() || d->appConnection.waitForIncomingTask(-1)) {
608 ret = d->appConnection.read( &cmd,
data );
611 kDebug(7019) <<
"read error";
658 QDataStream stream(
data );
679 static const int maximum_updatetime = 300;
682 if (d->pendingListEntries.isEmpty()) {
683 d->m_timeSinceLastBatch.restart();
687 d->pendingListEntries.append(entry);
690 if (d->m_timeSinceLastBatch.elapsed() > maximum_updatetime) {
697 d->pendingListEntries.clear();
700 d->m_timeSinceLastBatch.restart();
707 UDSEntryList::ConstIterator it = list.begin();
708 const UDSEntryList::ConstIterator
end = list.end();
709 for (; it != end; ++it)
712 d->sentListEntries+=(uint)list.count();
718 KDE_signal(sig,SIG_DFL);
721 KDE_signal(SIGALRM,SIG_DFL);
727 qsnprintf(buffer,
sizeof(buffer),
"kioslave: ####### CRASH ###### protocol = %s pid = %d signal = %d\n",
s_protocol, getpid(), sig);
728 write(2, buffer, strlen(buffer));
730 #ifdef HAVE_BACKTRACE
732 int n = backtrace(trace, 256);
734 backtrace_symbols_fd(trace, n, 2);
811 delete d->remotefile;
817 const long windowId =
metaData(QLatin1String(
"window-id")).toLong();
818 const unsigned long userTimestamp =
metaData(QLatin1String(
"user-timestamp")).toULong();
820 if (
metaData(QLatin1String(
"no-auth-prompt")).compare(QLatin1String(
"true"), Qt::CaseInsensitive) == 0) {
821 errorMessage = QLatin1String(
"<NoAuthPrompt>");
823 errorMessage = errorMsg;
832 dlgInfo.
setExtraField(QLatin1String(
"skip-caching-on-query"),
true);
837 qlonglong seqNr = passwdServer->
queryAuthInfo(dlgInfo, errorMessage, windowId,
838 SlaveBasePrivate::s_seqNr, userTimestamp);
840 SlaveBasePrivate::s_seqNr = seqNr;
859 const QString &dontAskAgainName )
861 kDebug(7019) <<
"messageBox " << type <<
" " << text <<
" - " << caption << buttonYes << buttonNo;
862 KIO_DATA << (
qint32)type << text << caption << buttonYes << buttonNo << dontAskAgainName;
866 QDataStream stream(
data );
869 kDebug(7019) <<
"got messagebox answer" << answer;
878 d->needSendCanResume =
false;
899 int cmd, result = -1;
902 if (d->appConnection.hasTaskAvailable() || d->appConnection.waitForIncomingTask(-1)) {
903 result = d->appConnection.read( &cmd, data );
906 kDebug(7019) <<
"read error.";
910 if ( cmd == expected1 || cmd == expected2 )
912 if ( pCmd ) *pCmd = cmd;
921 kFatal(7019) <<
"Got cmd " << cmd <<
" while waiting for an answer!";
937 d->timeout = time(0)+(time_t)timeout;
938 else if (timeout == 0)
943 d->timeoutData =
data;
948 QDataStream stream( data );
956 SlaveBasePrivate::s_seqNr = 0;
960 stream >> host >> port >> user >> passwd;
961 d->m_state = d->InsideMethod;
962 setHost( host, port, user, passwd );
963 d->verifyErrorFinishedNotCalled(
"setHost()");
964 d->m_state = d->Idle;
973 d->m_state = d->InsideMethod;
976 d->verifyErrorFinishedNotCalled(
"slave_status()");
977 d->m_state = d->Idle;
982 QDataStream stream( data );
983 stream >> app_socket;
986 d->isConnectedToApp =
true;
992 QDataStream stream( data );
997 d->isConnectedToApp =
false;
1002 d->m_state = d->InsideMethod;
1004 d->verifyErrorFinishedNotCalled(
"reparseConfiguration()");
1005 d->m_state = d->Idle;
1008 stream >> d->configData;
1010 #if 0 //TODO: decide what to do in KDE 4.1
1011 KSocks::setConfig(d->configGroup);
1013 delete d->remotefile;
1018 d->m_state = d->InsideMethod;
1020 d->verifyState(
"get()");
1021 d->m_state = d->Idle;
1025 QIODevice::OpenMode mode = QFlag(i);
1026 d->m_state = d->InsideMethod;
1028 d->m_state = d->Idle;
1032 qint8 iOverwrite, iResume;
1033 stream >> url >> iOverwrite >> iResume >> permissions;
1035 if ( iOverwrite != 0 ) flags |=
Overwrite;
1036 if ( iResume != 0 ) flags |=
Resume;
1041 d->needSendCanResume =
true ;
1043 d->m_state = d->InsideMethod;
1044 put( url, permissions, flags);
1045 d->verifyState(
"put()");
1046 d->m_state = d->Idle;
1050 d->m_state = d->InsideMethod;
1052 d->verifyState(
"stat()");
1053 d->m_state = d->Idle;
1057 d->m_state = d->InsideMethod;
1059 d->verifyState(
"mimetype()");
1060 d->m_state = d->Idle;
1064 d->m_state = d->InsideMethod;
1066 d->verifyState(
"listDir()");
1067 d->m_state = d->Idle;
1071 d->m_state = d->InsideMethod;
1073 d->verifyState(
"mkdir()");
1074 d->m_state = d->Idle;
1079 stream >> url >> url2 >> iOverwrite;
1081 if ( iOverwrite != 0 ) flags |=
Overwrite;
1082 d->m_state = d->InsideMethod;
1083 rename( url, url2, flags );
1084 d->verifyState(
"rename()");
1085 d->m_state = d->Idle;
1090 stream >> target >> url >> iOverwrite;
1092 if ( iOverwrite != 0 ) flags |=
Overwrite;
1093 d->m_state = d->InsideMethod;
1094 symlink( target, url, flags );
1095 d->verifyState(
"symlink()");
1096 d->m_state = d->Idle;
1102 stream >> url >> url2 >> permissions >> iOverwrite;
1104 if ( iOverwrite != 0 ) flags |=
Overwrite;
1105 d->m_state = d->InsideMethod;
1106 copy( url, url2, permissions, flags );
1107 d->verifyState(
"copy()");
1108 d->m_state = d->Idle;
1112 stream >> url >> isFile;
1113 d->m_state = d->InsideMethod;
1114 del( url, isFile != 0);
1115 d->verifyState(
"del()");
1116 d->m_state = d->Idle;
1120 d->m_state = d->InsideMethod;
1122 d->verifyState(
"chmod()");
1123 d->m_state = d->Idle;
1127 stream >> url >> owner >> group;
1128 d->m_state = d->InsideMethod;
1129 chown(url, owner, group);
1130 d->verifyState(
"chown()");
1131 d->m_state = d->Idle;
1135 stream >> url >> dt;
1136 d->m_state = d->InsideMethod;
1138 d->verifyState(
"setModificationTime()");
1139 d->m_state = d->Idle;
1142 d->m_state = d->InsideMethod;
1144 d->verifyState(
"special()");
1145 d->m_state = d->Idle;
1154 d->m_state = d->InsideMethod;
1156 d->verifyErrorFinishedNotCalled(
"setSubUrl()");
1157 d->m_state = d->Idle;
1160 kWarning(7019) <<
"Got unexpected CMD_NONE!";
1163 d->m_state = d->InsideMethod;
1165 d->verifyState(
"multiGet()");
1166 d->m_state = d->Idle;
1178 return (passwdServer &&
1180 metaData(QLatin1String(
"user-timestamp")).toULong()));
1185 QDataStream stream( data );
1219 if (!passwdServer) {
1231 int result = tmp.toInt(&ok);
1241 int result = tmp.toInt(&ok);
1252 int result = tmp.toInt(&ok);
1263 int result = tmp.toInt(&ok);
1271 return d->wasKilled;
1279 void SlaveBase::send(
int cmd,
const QByteArray& arr )
1282 if (!d->appConnection.send(cmd, arr))
1303 info.setError(QHostInfo::UnknownError);
1304 info.setErrorString(
i18n(
"Unknown Error"));
1308 QDataStream stream(data);
1310 QList<QHostAddress> addresses;
1314 stream >> hostName >> addresses >> error >> errorString;
1316 info.setHostName(hostName);
1317 info.setAddresses(addresses);
1318 info.setError(QHostInfo::HostInfoError(error));
1319 info.setErrorString(errorString);