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 int listEntryCurrentSize;
83 long listEntry_sec, listEntry_usec;
84 Connection appConnection;
86 bool isConnectedToApp;
87 static qlonglong s_seqNr;
91 bool needSendCanResume:1;
101 struct timeval last_tv;
106 enum { Idle, InsideMethod, FinishedCalled, ErrorCalled } m_state;
107 QByteArray timeoutData;
114 configGroup->deleteGroup(KConfigGroup::WriteConfigFlags());
118 MetaData::ConstIterator
end = configData.constEnd();
119 for (MetaData::ConstIterator it = configData.constBegin(); it != end; ++it)
120 configGroup->writeEntry(it.key(), it->toUtf8(), KConfigGroup::WriteConfigFlags());
122 end = q->mIncomingMetaData.constEnd();
123 for (MetaData::ConstIterator it = q->mIncomingMetaData.constBegin(); it != end; ++it)
124 configGroup->writeEntry(it.key(), it->toUtf8(), KConfigGroup::WriteConfigFlags());
127 void verifyState(
const char* cmdName)
129 if ((m_state != FinishedCalled) && (m_state != ErrorCalled)){
130 kWarning(7019) << cmdName <<
"did not call finished() or error()! Please fix the KIO slave.";
134 void verifyErrorFinishedNotCalled(
const char* cmdName)
136 if (m_state == FinishedCalled || m_state == ErrorCalled) {
137 kWarning(7019) << cmdName <<
"called finished() or error(), but it's not supposed to! Please fix the KIO slave.";
143 if (!m_passwdServer) {
147 return m_passwdServer;
154 qlonglong SlaveBasePrivate::s_seqNr;
164 KDE_signal(sigNumber,SIG_IGN);
172 KDE_signal(SIGALRM,SIG_DFL);
181 const QByteArray &pool_socket,
182 const QByteArray &app_socket )
183 : mProtocol(protocol),
184 d(new SlaveBasePrivate(this))
187 d->poolSocket = QFile::decodeName(pool_socket);
190 if (qgetenv(
"KDE_DEBUG").isEmpty())
216 struct sigaction act;
218 sigemptyset( &act.sa_mask );
220 sigaction( SIGPIPE, &act, 0 );
229 d->listEntryCurrentSize = 100;
231 gettimeofday(&tp, 0);
232 d->listEntry_sec = tp.tv_sec;
233 d->listEntry_usec = tp.tv_usec;
234 d->isConnectedToApp =
true;
237 d->slaveid = protocol;
240 d->needSendCanResume =
false;
246 d->last_tv.tv_sec = 0;
247 d->last_tv.tv_usec = 0;
250 d->sentListEntries=0;
255 d->inOpenLoop =
false;
256 d->exit_loop =
false;
261 delete d->configGroup;
263 delete d->remotefile;
270 while (!d->exit_loop) {
271 if (d->timeout && (d->timeout < time(0))) {
272 QByteArray
data = d->timeoutData;
274 d->timeoutData = QByteArray();
278 Q_ASSERT(d->appConnection.inited());
282 ms = 1000 * qMax<time_t>(d->timeout - time(0), 1);
285 if (d->appConnection.hasTaskAvailable() || d->appConnection.waitForIncomingTask(ms)) {
289 ret = d->appConnection.read(&cmd, data);
298 ret = d->appConnection.isConnected() ? 0 : -1;
303 if (!d->exit_loop && d->isConnectedToApp && !d->poolSocket.isEmpty()) {
305 d->isConnectedToApp =
false;
315 kDebug(7019) <<
"slave was killed, returning";
320 QCoreApplication::sendPostedEvents(NULL, QEvent::DeferredDelete);
324 QCoreApplication::sendPostedEvents(NULL, QEvent::DeferredDelete);
329 d->appConnection.connectToRemote(address);
331 if (!d->appConnection.inited())
333 kDebug(7019) <<
"failed to connect to" << address << endl
334 <<
"Reason:" << d->appConnection.errorString();
339 d->inOpenLoop =
false;
344 d->appConnection.close();
356 if (d->configData.contains(key))
357 return d->configData[key];
370 if (d->configData.contains(key))
377 return d->configGroup;
398 return d->remotefile;
400 const QByteArray charset (
metaData(QLatin1String(
"Charset")).toLatin1());
413 if (d->needSendCanResume)
422 d->inOpenLoop =
true;
427 if (d->m_state == d->ErrorCalled) {
428 kWarning(7019) <<
"error() called twice! Please fix the KIO slave.";
430 }
else if (d->m_state == d->FinishedCalled) {
431 kWarning(7019) <<
"error() called after finished()! Please fix the KIO slave.";
435 d->m_state = d->ErrorCalled;
443 d->listEntryCurrentSize = 100;
444 d->sentListEntries=0;
456 if (d->m_state == d->FinishedCalled) {
457 kWarning(7019) <<
"finished() called twice! Please fix the KIO slave.";
459 }
else if (d->m_state == d->ErrorCalled) {
460 kWarning(7019) <<
"finished() called after error()! Please fix the KIO slave.";
464 d->m_state = d->FinishedCalled;
471 d->listEntryCurrentSize = 100;
472 d->sentListEntries=0;
486 template<
int T>
struct PIDType {
typedef pid_t PID_t; } ;
487 template<>
struct PIDType<2> {
typedef qint16 PID_t; } ;
488 template<>
struct PIDType<4> {
typedef qint32 PID_t; } ;
492 pid_t pid = getpid();
493 qint8 b = connected ? 1 : 0;
494 KIO_DATA << (PIDType<sizeof(pid_t)>::PID_t)pid <<
mProtocol << host << b;
496 stream << d->onHoldUrl;
512 gettimeofday(&tp, 0);
513 d->listEntry_sec = tp.tv_sec;
514 d->listEntry_usec = tp.tv_usec;
516 d->sentListEntries=0;
523 int gettimeofday_res=gettimeofday( &tv, 0L );
525 if( _bytes == d->totalSize )
527 else if ( gettimeofday_res == 0 ) {
528 time_t msecdiff = 2000;
529 if (d->last_tv.tv_sec) {
531 msecdiff = 1000 * ( tv.tv_sec - d->last_tv.tv_sec );
532 time_t usecdiff = tv.tv_usec - d->last_tv.tv_usec;
533 if ( usecdiff < 0 ) {
537 msecdiff += usecdiff / 1000;
539 emitSignal=msecdiff >= 100;
545 if ( gettimeofday_res == 0 ) {
546 d->last_tv.tv_sec = tv.tv_sec;
547 d->last_tv.tv_usec = tv.tv_usec;
619 if (d->appConnection.hasTaskAvailable() || d->appConnection.waitForIncomingTask(-1)) {
620 ret = d->appConnection.read( &cmd,
data );
623 kDebug(7019) <<
"read error";
670 QDataStream stream(
data );
691 static struct timeval tp;
692 static const int maximum_updatetime = 300;
693 static const int minimum_updatetime = 100;
696 d->pendingListEntries.append(entry);
698 if (d->pendingListEntries.count() > d->listEntryCurrentSize) {
699 gettimeofday(&tp, 0);
701 long diff = ((tp.tv_sec - d->listEntry_sec) * 1000000 +
702 tp.tv_usec - d->listEntry_usec) / 1000;
705 if (diff > maximum_updatetime) {
706 d->listEntryCurrentSize = d->listEntryCurrentSize * 3 / 4;
711 else if (((d->pendingListEntries.count()*maximum_updatetime)/diff) >
static_cast<long>(d->totalSize-d->sentListEntries))
712 d->listEntryCurrentSize=d->totalSize-d->sentListEntries+1;
715 else if (diff < minimum_updatetime)
716 d->listEntryCurrentSize = (d->pendingListEntries.count() * maximum_updatetime) / diff;
723 d->pendingListEntries.clear();
725 gettimeofday(&tp, 0);
726 d->listEntry_sec = tp.tv_sec;
727 d->listEntry_usec = tp.tv_usec;
734 UDSEntryList::ConstIterator it = list.begin();
735 const UDSEntryList::ConstIterator
end = list.end();
736 for (; it != end; ++it)
739 d->sentListEntries+=(uint)list.count();
745 KDE_signal(sig,SIG_DFL);
748 KDE_signal(SIGALRM,SIG_DFL);
754 qsnprintf(buffer,
sizeof(buffer),
"kioslave: ####### CRASH ###### protocol = %s pid = %d signal = %d\n",
s_protocol, getpid(), sig);
755 write(2, buffer, strlen(buffer));
757 #ifdef HAVE_BACKTRACE
759 int n = backtrace(trace, 256);
761 backtrace_symbols_fd(trace, n, 2);
838 delete d->remotefile;
844 const long windowId =
metaData(QLatin1String(
"window-id")).toLong();
845 const unsigned long userTimestamp =
metaData(QLatin1String(
"user-timestamp")).toULong();
847 if (
metaData(QLatin1String(
"no-auth-prompt")).compare(QLatin1String(
"true"), Qt::CaseInsensitive) == 0) {
848 errorMessage = QLatin1String(
"<NoAuthPrompt>");
850 errorMessage = errorMsg;
859 dlgInfo.
setExtraField(QLatin1String(
"skip-caching-on-query"),
true);
864 qlonglong seqNr = passwdServer->
queryAuthInfo(dlgInfo, errorMessage, windowId,
865 SlaveBasePrivate::s_seqNr, userTimestamp);
867 SlaveBasePrivate::s_seqNr = seqNr;
886 const QString &dontAskAgainName )
888 kDebug(7019) <<
"messageBox " << type <<
" " << text <<
" - " << caption << buttonYes << buttonNo;
889 KIO_DATA << (
qint32)type << text << caption << buttonYes << buttonNo << dontAskAgainName;
893 QDataStream stream(
data );
896 kDebug(7019) <<
"got messagebox answer" << answer;
905 d->needSendCanResume =
false;
926 int cmd, result = -1;
929 if (d->appConnection.hasTaskAvailable() || d->appConnection.waitForIncomingTask(-1)) {
930 result = d->appConnection.read( &cmd, data );
933 kDebug(7019) <<
"read error.";
937 if ( cmd == expected1 || cmd == expected2 )
939 if ( pCmd ) *pCmd = cmd;
948 kFatal(7019) <<
"Got cmd " << cmd <<
" while waiting for an answer!";
964 d->timeout = time(0)+(time_t)timeout;
965 else if (timeout == 0)
970 d->timeoutData =
data;
975 QDataStream stream( data );
983 SlaveBasePrivate::s_seqNr = 0;
987 stream >> host >> port >> user >> passwd;
988 d->m_state = d->InsideMethod;
989 setHost( host, port, user, passwd );
990 d->verifyErrorFinishedNotCalled(
"setHost()");
991 d->m_state = d->Idle;
1000 d->m_state = d->InsideMethod;
1003 d->verifyErrorFinishedNotCalled(
"slave_status()");
1004 d->m_state = d->Idle;
1009 QDataStream stream( data );
1010 stream >> app_socket;
1013 d->isConnectedToApp =
true;
1019 QDataStream stream( data );
1024 d->isConnectedToApp =
false;
1029 d->m_state = d->InsideMethod;
1031 d->verifyErrorFinishedNotCalled(
"reparseConfiguration()");
1032 d->m_state = d->Idle;
1035 stream >> d->configData;
1037 #if 0 //TODO: decide what to do in KDE 4.1
1038 KSocks::setConfig(d->configGroup);
1040 delete d->remotefile;
1045 d->m_state = d->InsideMethod;
1047 d->verifyState(
"get()");
1048 d->m_state = d->Idle;
1052 QIODevice::OpenMode mode = QFlag(i);
1053 d->m_state = d->InsideMethod;
1055 d->m_state = d->Idle;
1059 qint8 iOverwrite, iResume;
1060 stream >> url >> iOverwrite >> iResume >> permissions;
1062 if ( iOverwrite != 0 ) flags |=
Overwrite;
1063 if ( iResume != 0 ) flags |=
Resume;
1068 d->needSendCanResume =
true ;
1070 d->m_state = d->InsideMethod;
1071 put( url, permissions, flags);
1072 d->verifyState(
"put()");
1073 d->m_state = d->Idle;
1077 d->m_state = d->InsideMethod;
1079 d->verifyState(
"stat()");
1080 d->m_state = d->Idle;
1084 d->m_state = d->InsideMethod;
1086 d->verifyState(
"mimetype()");
1087 d->m_state = d->Idle;
1091 d->m_state = d->InsideMethod;
1093 d->verifyState(
"listDir()");
1094 d->m_state = d->Idle;
1098 d->m_state = d->InsideMethod;
1100 d->verifyState(
"mkdir()");
1101 d->m_state = d->Idle;
1106 stream >> url >> url2 >> iOverwrite;
1108 if ( iOverwrite != 0 ) flags |=
Overwrite;
1109 d->m_state = d->InsideMethod;
1110 rename( url, url2, flags );
1111 d->verifyState(
"rename()");
1112 d->m_state = d->Idle;
1117 stream >> target >> url >> iOverwrite;
1119 if ( iOverwrite != 0 ) flags |=
Overwrite;
1120 d->m_state = d->InsideMethod;
1121 symlink( target, url, flags );
1122 d->verifyState(
"symlink()");
1123 d->m_state = d->Idle;
1129 stream >> url >> url2 >> permissions >> iOverwrite;
1131 if ( iOverwrite != 0 ) flags |=
Overwrite;
1132 d->m_state = d->InsideMethod;
1133 copy( url, url2, permissions, flags );
1134 d->verifyState(
"copy()");
1135 d->m_state = d->Idle;
1139 stream >> url >> isFile;
1140 d->m_state = d->InsideMethod;
1141 del( url, isFile != 0);
1142 d->verifyState(
"del()");
1143 d->m_state = d->Idle;
1147 d->m_state = d->InsideMethod;
1149 d->verifyState(
"chmod()");
1150 d->m_state = d->Idle;
1154 stream >> url >> owner >> group;
1155 d->m_state = d->InsideMethod;
1156 chown(url, owner, group);
1157 d->verifyState(
"chown()");
1158 d->m_state = d->Idle;
1162 stream >> url >> dt;
1163 d->m_state = d->InsideMethod;
1165 d->verifyState(
"setModificationTime()");
1166 d->m_state = d->Idle;
1169 d->m_state = d->InsideMethod;
1171 d->verifyState(
"special()");
1172 d->m_state = d->Idle;
1181 d->m_state = d->InsideMethod;
1183 d->verifyErrorFinishedNotCalled(
"setSubUrl()");
1184 d->m_state = d->Idle;
1187 kWarning(7019) <<
"Got unexpected CMD_NONE!";
1190 d->m_state = d->InsideMethod;
1192 d->verifyState(
"multiGet()");
1193 d->m_state = d->Idle;
1205 return (passwdServer &&
1207 metaData(QLatin1String(
"user-timestamp")).toULong()));
1212 QDataStream stream( data );
1246 if (!passwdServer) {
1258 int result = tmp.toInt(&ok);
1268 int result = tmp.toInt(&ok);
1279 int result = tmp.toInt(&ok);
1290 int result = tmp.toInt(&ok);
1298 return d->wasKilled;
1306 void SlaveBase::send(
int cmd,
const QByteArray& arr )
1309 if (!d->appConnection.send(cmd, arr))
1330 info.setError(QHostInfo::UnknownError);
1331 info.setErrorString(
i18n(
"Unknown Error"));
1335 QDataStream stream(data);
1337 QList<QHostAddress> addresses;
1341 stream >> hostName >> addresses >> error >> errorString;
1343 info.setHostName(hostName);
1344 info.setAddresses(addresses);
1345 info.setError(QHostInfo::HostInfoError(error));
1346 info.setErrorString(errorString);