00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "kio/slaveinterface.h"
00020 #include "kio/slavebase.h"
00021 #include "kio/connection.h"
00022 #include <errno.h>
00023 #include <assert.h>
00024 #include <kdebug.h>
00025 #include <stdlib.h>
00026 #include <sys/time.h>
00027 #include <unistd.h>
00028 #include <signal.h>
00029 #include <kio/observer.h>
00030 #include <kapplication.h>
00031 #include <dcopclient.h>
00032 #include <time.h>
00033 #include <qtimer.h>
00034
00035 using namespace KIO;
00036
00037
00038 QDataStream &operator <<(QDataStream &s, const KIO::UDSEntry &e )
00039 {
00040
00041
00042
00043
00044 if (sizeof(long) == 8)
00045 {
00046 s << (Q_UINT32)e.size();
00047 KIO::UDSEntry::ConstIterator it = e.begin();
00048 for( ; it != e.end(); ++it )
00049 s << *it;
00050 return s;
00051 }
00052
00053 Q_UINT32 size = 0;
00054 KIO::UDSEntry::ConstIterator it = e.begin();
00055 for( ; it != e.end(); ++it )
00056 {
00057 size++;
00058 if ((*it).m_uds == KIO::UDS_SIZE)
00059 size++;
00060 }
00061 s << size;
00062 it = e.begin();
00063 for( ; it != e.end(); ++it )
00064 {
00065 if ((*it).m_uds == KIO::UDS_SIZE)
00066 {
00067 KIO::UDSAtom a;
00068 a.m_uds = KIO::UDS_SIZE_LARGE;
00069 a.m_long = (*it).m_long >> 32;
00070 s << a;
00071 }
00072 s << *it;
00073 }
00074 return s;
00075 }
00076
00077 QDataStream &operator >>(QDataStream &s, KIO::UDSEntry &e )
00078 {
00079 e.clear();
00080 Q_UINT32 size;
00081 s >> size;
00082
00083
00084
00085
00086
00087 if (sizeof(long) == 8)
00088 {
00089 for(Q_UINT32 i = 0; i < size; i++)
00090 {
00091 KIO::UDSAtom a;
00092 s >> a;
00093 e.append(a);
00094 }
00095 }
00096 else
00097 {
00098 long long msb = 0;
00099 for(Q_UINT32 i = 0; i < size; i++)
00100 {
00101 KIO::UDSAtom a;
00102 s >> a;
00103 if (a.m_uds == KIO::UDS_SIZE_LARGE)
00104 {
00105 msb = a.m_long;
00106 }
00107 else
00108 {
00109 if (a.m_uds == KIO::UDS_SIZE)
00110 {
00111 if (a.m_long < 0)
00112 a.m_long += (long long) 1 << 32;
00113 a.m_long += msb << 32;
00114 }
00115 e.append(a);
00116 msb = 0;
00117 }
00118 }
00119 }
00120 return s;
00121 }
00122
00123 static const unsigned int max_nums = 8;
00124
00125 class KIO::SlaveInterfacePrivate
00126 {
00127 public:
00128 SlaveInterfacePrivate() {
00129 slave_calcs_speed = false;
00130 start_time.tv_sec = 0;
00131 start_time.tv_usec = 0;
00132 last_time = 0;
00133 nums = 0;
00134 filesize = 0;
00135 offset = 0;
00136 }
00137 bool slave_calcs_speed;
00138 struct timeval start_time;
00139 uint nums;
00140 long times[max_nums];
00141 KIO::filesize_t sizes[max_nums];
00142 size_t last_time;
00143 KIO::filesize_t filesize, offset;
00144
00145 QTimer speed_timer;
00146 };
00147
00149
00150 SlaveInterface::SlaveInterface( Connection * connection )
00151 {
00152 struct sigaction act;
00153 m_pConnection = connection;
00154 m_progressId = 0;
00155 act.sa_handler = sigpipe_handler;
00156 sigemptyset( &act.sa_mask );
00157 act.sa_flags = 0;
00158 sigaction( SIGPIPE, &act, 0 );
00159
00160 d = new SlaveInterfacePrivate;
00161 connect(&d->speed_timer, SIGNAL(timeout()), SLOT(calcSpeed()));
00162 }
00163
00164 SlaveInterface::~SlaveInterface()
00165 {
00166
00167 m_pConnection = 0;
00168
00169 delete d;
00170 }
00171
00172 static KIO::filesize_t readFilesize_t(QDataStream &stream)
00173 {
00174 KIO::filesize_t result;
00175 unsigned long ul;
00176 stream >> ul;
00177 result = ul;
00178 if (stream.atEnd())
00179 return result;
00180 stream >> ul;
00181 result += ((KIO::filesize_t)ul) << 32;
00182 return result;
00183 }
00184
00185
00186 bool SlaveInterface::dispatch()
00187 {
00188 assert( m_pConnection );
00189
00190 int cmd;
00191 QByteArray data;
00192
00193 if (m_pConnection->read( &cmd, data ) == -1)
00194 return false;
00195
00196 return dispatch( cmd, data );
00197 }
00198
00199 void SlaveInterface::calcSpeed()
00200 {
00201 if (d->slave_calcs_speed) {
00202 d->speed_timer.stop();
00203 return;
00204 }
00205
00206 struct timeval tv;
00207 gettimeofday(&tv, 0);
00208
00209 long diff = ((tv.tv_sec - d->start_time.tv_sec) * 1000000 +
00210 tv.tv_usec - d->start_time.tv_usec) / 1000;
00211 if (diff - d->last_time >= 900) {
00212 d->last_time = diff;
00213 if (d->nums == max_nums) {
00214
00215
00216 for (unsigned int i = 1; i < max_nums; ++i) {
00217 d->times[i-1] = d->times[i];
00218 d->sizes[i-1] = d->sizes[i];
00219 }
00220 d->nums--;
00221 }
00222 d->times[d->nums] = diff;
00223 d->sizes[d->nums++] = d->filesize;
00224
00225 KIO::filesize_t lspeed = 1000 * (d->sizes[d->nums-1] - d->sizes[0]) / (d->times[d->nums-1] - d->times[0]);
00226
00227
00228
00229 if (!lspeed) {
00230 d->nums = 1;
00231 d->times[0] = diff;
00232 d->sizes[0] = d->filesize;
00233 }
00234 emit speed(lspeed);
00235 }
00236 }
00237
00238 bool SlaveInterface::dispatch( int _cmd, const QByteArray &rawdata )
00239 {
00240
00241
00242 QDataStream stream( rawdata, IO_ReadOnly );
00243
00244 QString str1;
00245 int i;
00246 Q_INT8 b;
00247 unsigned long ul;
00248
00249 switch( _cmd ) {
00250 case MSG_DATA:
00251 emit data( rawdata );
00252 break;
00253 case MSG_DATA_REQ:
00254 emit dataReq();
00255 break;
00256 case MSG_FINISHED:
00257
00258 d->offset = 0;
00259 d->speed_timer.stop();
00260 emit finished();
00261 break;
00262 case MSG_STAT_ENTRY:
00263 {
00264 UDSEntry entry;
00265 stream >> entry;
00266 emit statEntry(entry);
00267 }
00268 break;
00269 case MSG_LIST_ENTRIES:
00270 {
00271 uint count;
00272 stream >> count;
00273
00274 UDSEntryList list;
00275 UDSEntry entry;
00276 for (uint i = 0; i < count; i++) {
00277 stream >> entry;
00278 list.append(entry);
00279 }
00280 emit listEntries(list);
00281
00282 }
00283 break;
00284 case MSG_RESUME:
00285 {
00286 KIO::filesize_t offset = readFilesize_t(stream);
00287 emit canResume( offset );
00288 }
00289 break;
00290 case MSG_CANRESUME:
00291 d->filesize = d->offset;
00292 emit canResume(0);
00293 break;
00294 case MSG_ERROR:
00295 stream >> i >> str1;
00296 kdDebug(7007) << "error " << i << " " << str1 << endl;
00297 emit error( i, str1 );
00298 break;
00299 case MSG_SLAVE_STATUS:
00300 {
00301 pid_t pid;
00302 QCString protocol;
00303 stream >> pid >> protocol >> str1 >> b;
00304 emit slaveStatus(pid, protocol, str1, (b != 0));
00305 }
00306 break;
00307 case MSG_CONNECTED:
00308 emit connected();
00309 break;
00310
00311 case INF_TOTAL_SIZE:
00312 {
00313 KIO::filesize_t size = readFilesize_t(stream);
00314 gettimeofday(&d->start_time, 0);
00315 d->last_time = 0;
00316 d->filesize = d->offset;
00317 d->sizes[0] = d->filesize;
00318 d->times[0] = 0;
00319 d->nums = 1;
00320 d->speed_timer.start(1000);
00321 d->slave_calcs_speed = false;
00322 emit totalSize( size );
00323 }
00324 break;
00325 case INF_PROCESSED_SIZE:
00326 {
00327 KIO::filesize_t size = readFilesize_t(stream);
00328 emit processedSize( size );
00329 d->filesize = size;
00330 }
00331 break;
00332 case INF_SPEED:
00333 stream >> ul;
00334 d->slave_calcs_speed = true;
00335 d->speed_timer.stop();
00336
00337 emit speed( ul );
00338 break;
00339 case INF_GETTING_FILE:
00340 break;
00341 case INF_ERROR_PAGE:
00342 emit errorPage();
00343 break;
00344 case INF_REDIRECTION:
00345 {
00346 KURL url;
00347 stream >> url;
00348
00349 emit redirection( url );
00350 }
00351 break;
00352 case INF_MIME_TYPE:
00353 stream >> str1;
00354
00355 emit mimeType( str1 );
00356 if (!m_pConnection->suspended())
00357 m_pConnection->sendnow( CMD_NONE, QByteArray() );
00358 break;
00359 case INF_WARNING:
00360 stream >> str1;
00361
00362 emit warning( str1 );
00363 break;
00364 case INF_NEED_PASSWD: {
00365 AuthInfo info;
00366 stream >> info;
00367 openPassDlg( info );
00368 break;
00369 }
00370 case INF_MESSAGEBOX: {
00371 kdDebug(7007) << "needs a msg box" << endl;
00372 QString text, caption, buttonYes, buttonNo;
00373 int type;
00374 stream >> type >> text >> caption >> buttonYes >> buttonNo;
00375 messageBox(type, text, caption, buttonYes, buttonNo);
00376 break;
00377 }
00378 case INF_INFOMESSAGE: {
00379 QString msg;
00380 stream >> msg;
00381 infoMessage(msg);
00382 break;
00383 }
00384 case INF_META_DATA: {
00385 MetaData meta_data;
00386 stream >> meta_data;
00387 metaData(meta_data);
00388 break;
00389 }
00390 case MSG_NET_REQUEST: {
00391 QString host;
00392 QString slaveid;
00393 stream >> host >> slaveid;
00394 requestNetwork(host, slaveid);
00395 break;
00396 }
00397 case MSG_NET_DROP: {
00398 QString host;
00399 QString slaveid;
00400 stream >> host >> slaveid;
00401 dropNetwork(host, slaveid);
00402 break;
00403 }
00404 case MSG_NEED_SUBURL_DATA: {
00405 emit needSubURLData();
00406 break;
00407 }
00408 case MSG_AUTH_KEY: {
00409 bool keep;
00410 QCString key, group;
00411 stream >> key >> group >> keep;
00412 kdDebug(7007) << "Got auth-key: " << key << endl
00413 << " group-key: " << group << endl
00414 << " keep password: " << keep << endl;
00415 emit authorizationKey( key, group, keep );
00416 break;
00417 }
00418 case MSG_DEL_AUTH_KEY: {
00419 QCString key;
00420 stream >> key;
00421 kdDebug(7007) << "Delete auth-key: " << key << endl;
00422 emit delAuthorization( key );
00423 }
00424 default:
00425 kdWarning(7007) << "Slave sends unknown command (" << _cmd << "), dropping slave" << endl;
00426 return false;
00427 }
00428 return true;
00429 }
00430
00431 void SlaveInterface::setOffset( KIO::filesize_t o)
00432 {
00433 d->offset = o;
00434 }
00435
00436 KIO::filesize_t SlaveInterface::offset() const { return d->offset; }
00437
00438 void SlaveInterface::requestNetwork(const QString &host, const QString &slaveid)
00439 {
00440 kdDebug(7007) << "requestNetwork " << host << slaveid << endl;
00441 QByteArray packedArgs;
00442 QDataStream stream( packedArgs, IO_WriteOnly );
00443 stream << true;
00444 m_pConnection->sendnow( INF_NETWORK_STATUS, packedArgs );
00445 }
00446
00447 void SlaveInterface::dropNetwork(const QString &host, const QString &slaveid)
00448 {
00449 kdDebug(7007) << "dropNetwork " << host << slaveid << endl;
00450 }
00451
00452 void SlaveInterface::sendResumeAnswer( bool resume )
00453 {
00454 kdDebug(7007) << "SlaveInterface::sendResumeAnswer ok for resuming :" << resume << endl;
00455 m_pConnection->sendnow( resume ? CMD_RESUMEANSWER : CMD_NONE, QByteArray() );
00456 }
00457
00458 void SlaveInterface::openPassDlg( const QString& prompt, const QString& user, bool readOnly )
00459 {
00460 AuthInfo info;
00461 info.prompt = prompt;
00462 info.username = user;
00463 info.readOnly = readOnly;
00464 openPassDlg( info );
00465 }
00466
00467 void SlaveInterface::openPassDlg( const QString& prompt, const QString& user,
00468 const QString& caption, const QString& comment,
00469 const QString& label, bool readOnly )
00470 {
00471 AuthInfo info;
00472 info.prompt = prompt;
00473 info.username = user;
00474 info.caption = caption;
00475 info.comment = comment;
00476 info.commentLabel = label;
00477 info.readOnly = readOnly;
00478 openPassDlg( info );
00479 }
00480
00481 void SlaveInterface::openPassDlg( AuthInfo& info )
00482 {
00483 kdDebug(7007) << "SlaveInterface::openPassDlg: "
00484 << "User= " << info.username
00485 << ", Message= " << info.prompt << endl;
00486 bool result = Observer::self()->openPassDlg( info );
00487 if ( m_pConnection )
00488 {
00489 QByteArray data;
00490 QDataStream stream( data, IO_WriteOnly );
00491 if ( result )
00492 {
00493 stream << info;
00494 kdDebug(7007) << "SlaveInterface:::openPassDlg got: "
00495 << "User= " << info.username
00496 << ", Password= [hidden]" << endl;
00497 m_pConnection->sendnow( CMD_USERPASS, data );
00498 }
00499 else
00500 m_pConnection->sendnow( CMD_NONE, data );
00501 }
00502 }
00503
00504 void SlaveInterface::messageBox( int type, const QString &text, const QString &_caption,
00505 const QString &buttonYes, const QString &buttonNo )
00506 {
00507 kdDebug(7007) << "messageBox " << type << " " << text << " - " << _caption << endl;
00508 QByteArray packedArgs;
00509 QDataStream stream( packedArgs, IO_WriteOnly );
00510
00511 QString caption( _caption );
00512 if ( type == KIO::SlaveBase::SSLMessageBox )
00513 caption = QString::fromUtf8(kapp->dcopClient()->appId());
00514
00515 emit needProgressId();
00516 kdDebug(7007) << "SlaveInterface::messageBox m_progressId=" << m_progressId << endl;
00517 int result = Observer::messageBox( m_progressId, type, text, caption, buttonYes, buttonNo );
00518 if ( m_pConnection )
00519 {
00520 kdDebug(7007) << this << " SlaveInterface result=" << result << endl;
00521 stream << result;
00522 m_pConnection->sendnow( CMD_MESSAGEBOXANSWER, packedArgs );
00523 }
00524 }
00525
00526 void SlaveInterface::sigpipe_handler(int)
00527 {
00528 int saved_errno = errno;
00529
00530 #ifndef NDEBUG
00531 char msg[1000];
00532 sprintf(msg, "*** SIGPIPE *** (ignored, pid = %ld)\n", (long) getpid());
00533 write(2, msg, strlen(msg));
00534 #endif
00535
00536
00537
00538 errno = saved_errno;
00539 }
00540
00541 void SlaveInterface::virtual_hook( int, void* )
00542 { }
00543
00544 #include "slaveinterface.moc"