kio Library API Documentation

slaveinterface.cpp

00001 /* This file is part of the KDE libraries 00002 Copyright (C) 2000 David Faure <faure@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License version 2 as published by the Free Software Foundation. 00007 00008 This library is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00011 Library General Public License for more details. 00012 00013 You should have received a copy of the GNU Library General Public License 00014 along with this library; see the file COPYING.LIB. If not, write to 00015 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00016 Boston, MA 02111-1307, USA. 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 // On 32-bit platforms we send UDS_SIZE with UDS_SIZE_LARGE in front 00041 // of it to carry the 32 msb. We can't send a 64 bit UDS_SIZE because 00042 // that would break the compatibility of the wire-protocol with KDE 2. 00043 // We do the same on 64-bit platforms in case we run in a mixed 32/64bit 00044 // environment. 00045 00046 Q_UINT32 size = 0; 00047 KIO::UDSEntry::ConstIterator it = e.begin(); 00048 for( ; it != e.end(); ++it ) 00049 { 00050 size++; 00051 if ((*it).m_uds == KIO::UDS_SIZE) 00052 size++; 00053 } 00054 s << size; 00055 it = e.begin(); 00056 for( ; it != e.end(); ++it ) 00057 { 00058 if ((*it).m_uds == KIO::UDS_SIZE) 00059 { 00060 KIO::UDSAtom a; 00061 a.m_uds = KIO::UDS_SIZE_LARGE; 00062 a.m_long = (*it).m_long >> 32; 00063 s << a; 00064 } 00065 s << *it; 00066 } 00067 return s; 00068 } 00069 00070 QDataStream &operator >>(QDataStream &s, KIO::UDSEntry &e ) 00071 { 00072 e.clear(); 00073 Q_UINT32 size; 00074 s >> size; 00075 00076 // On 32-bit platforms we send UDS_SIZE with UDS_SIZE_LARGE in front 00077 // of it to carry the 32 msb. We can't send a 64 bit UDS_SIZE because 00078 // that would break the compatibility of the wire-protocol with KDE 2. 00079 // We do the same on 64-bit platforms in case we run in a mixed 32/64bit 00080 // environment. 00081 Q_LLONG msb = 0; 00082 for(Q_UINT32 i = 0; i < size; i++) 00083 { 00084 KIO::UDSAtom a; 00085 s >> a; 00086 if (a.m_uds == KIO::UDS_SIZE_LARGE) 00087 { 00088 msb = a.m_long; 00089 } 00090 else 00091 { 00092 if (a.m_uds == KIO::UDS_SIZE) 00093 { 00094 if (a.m_long < 0) 00095 a.m_long += (Q_LLONG) 1 << 32; 00096 a.m_long += msb << 32; 00097 } 00098 e.append(a); 00099 msb = 0; 00100 } 00101 } 00102 return s; 00103 } 00104 00105 static const unsigned int max_nums = 8; 00106 00107 class KIO::SlaveInterfacePrivate 00108 { 00109 public: 00110 SlaveInterfacePrivate() { 00111 slave_calcs_speed = false; 00112 start_time.tv_sec = 0; 00113 start_time.tv_usec = 0; 00114 last_time = 0; 00115 nums = 0; 00116 filesize = 0; 00117 offset = 0; 00118 } 00119 bool slave_calcs_speed; 00120 struct timeval start_time; 00121 uint nums; 00122 long times[max_nums]; 00123 KIO::filesize_t sizes[max_nums]; 00124 size_t last_time; 00125 KIO::filesize_t filesize, offset; 00126 00127 QTimer speed_timer; 00128 }; 00129 00131 00132 SlaveInterface::SlaveInterface( Connection * connection ) 00133 { 00134 m_pConnection = connection; 00135 m_progressId = 0; 00136 00137 d = new SlaveInterfacePrivate; 00138 connect(&d->speed_timer, SIGNAL(timeout()), SLOT(calcSpeed())); 00139 } 00140 00141 SlaveInterface::~SlaveInterface() 00142 { 00143 // Note: no kdDebug() here (scheduler is deleted very late) 00144 m_pConnection = 0; // a bit like the "wasDeleted" of QObject... 00145 00146 delete d; 00147 } 00148 00149 static KIO::filesize_t readFilesize_t(QDataStream &stream) 00150 { 00151 KIO::filesize_t result; 00152 unsigned long ul; 00153 stream >> ul; 00154 result = ul; 00155 if (stream.atEnd()) 00156 return result; 00157 stream >> ul; 00158 result += ((KIO::filesize_t)ul) << 32; 00159 return result; 00160 } 00161 00162 00163 bool SlaveInterface::dispatch() 00164 { 00165 assert( m_pConnection ); 00166 00167 int cmd; 00168 QByteArray data; 00169 00170 if (m_pConnection->read( &cmd, data ) == -1) 00171 return false; 00172 00173 return dispatch( cmd, data ); 00174 } 00175 00176 void SlaveInterface::calcSpeed() 00177 { 00178 if (d->slave_calcs_speed) { 00179 d->speed_timer.stop(); 00180 return; 00181 } 00182 00183 struct timeval tv; 00184 gettimeofday(&tv, 0); 00185 00186 long diff = ((tv.tv_sec - d->start_time.tv_sec) * 1000000 + 00187 tv.tv_usec - d->start_time.tv_usec) / 1000; 00188 if (diff - d->last_time >= 900) { 00189 d->last_time = diff; 00190 if (d->nums == max_nums) { 00191 // let's hope gcc can optimize that well enough 00192 // otherwise I'd try memcpy :) 00193 for (unsigned int i = 1; i < max_nums; ++i) { 00194 d->times[i-1] = d->times[i]; 00195 d->sizes[i-1] = d->sizes[i]; 00196 } 00197 d->nums--; 00198 } 00199 d->times[d->nums] = diff; 00200 d->sizes[d->nums++] = d->filesize - d->offset; 00201 00202 KIO::filesize_t lspeed = 1000 * (d->sizes[d->nums-1] - d->sizes[0]) / (d->times[d->nums-1] - d->times[0]); 00203 00204 // kdDebug() << "proceeed " << (long)d->filesize << " " << diff << " " 00205 // << long(d->sizes[d->nums-1] - d->sizes[0]) << " " 00206 // << d->times[d->nums-1] - d->times[0] << " " 00207 // << long(lspeed) << " " << double(d->filesize) / diff 00208 // << " " << convertSize(lspeed) << " " 00209 // << convertSize(long(double(d->filesize) / diff) * 1000) << " " 00210 // << endl ; 00211 00212 if (!lspeed) { 00213 d->nums = 1; 00214 d->times[0] = diff; 00215 d->sizes[0] = d->filesize - d->offset; 00216 } 00217 emit speed(lspeed); 00218 } 00219 } 00220 00221 bool SlaveInterface::dispatch( int _cmd, const QByteArray &rawdata ) 00222 { 00223 //kdDebug(7007) << "dispatch " << _cmd << endl; 00224 00225 QDataStream stream( rawdata, IO_ReadOnly ); 00226 00227 QString str1; 00228 Q_INT32 i; 00229 Q_INT8 b; 00230 Q_UINT32 ul; 00231 00232 switch( _cmd ) { 00233 case MSG_DATA: 00234 emit data( rawdata ); 00235 break; 00236 case MSG_DATA_REQ: 00237 emit dataReq(); 00238 break; 00239 case MSG_FINISHED: 00240 //kdDebug(7007) << "Finished [this = " << this << "]" << endl; 00241 d->offset = 0; 00242 d->speed_timer.stop(); 00243 emit finished(); 00244 break; 00245 case MSG_STAT_ENTRY: 00246 { 00247 UDSEntry entry; 00248 stream >> entry; 00249 emit statEntry(entry); 00250 } 00251 break; 00252 case MSG_LIST_ENTRIES: 00253 { 00254 Q_UINT32 count; 00255 stream >> count; 00256 00257 UDSEntryList list; 00258 UDSEntry entry; 00259 for (uint i = 0; i < count; i++) { 00260 stream >> entry; 00261 list.append(entry); 00262 } 00263 emit listEntries(list); 00264 00265 } 00266 break; 00267 case MSG_RESUME: // From the put job 00268 { 00269 d->offset = readFilesize_t(stream); 00270 emit canResume( d->offset ); 00271 } 00272 break; 00273 case MSG_CANRESUME: // From the get job 00274 d->filesize = d->offset; 00275 emit canResume(0); // the arg doesn't matter 00276 break; 00277 case MSG_ERROR: 00278 stream >> i >> str1; 00279 kdDebug(7007) << "error " << i << " " << str1 << endl; 00280 emit error( i, str1 ); 00281 break; 00282 case MSG_SLAVE_STATUS: 00283 { 00284 pid_t pid; 00285 QCString protocol; 00286 stream >> pid >> protocol >> str1 >> b; 00287 emit slaveStatus(pid, protocol, str1, (b != 0)); 00288 } 00289 break; 00290 case MSG_CONNECTED: 00291 emit connected(); 00292 break; 00293 00294 case INF_TOTAL_SIZE: 00295 { 00296 KIO::filesize_t size = readFilesize_t(stream); 00297 gettimeofday(&d->start_time, 0); 00298 d->last_time = 0; 00299 d->filesize = d->offset; 00300 d->sizes[0] = d->filesize - d->offset; 00301 d->times[0] = 0; 00302 d->nums = 1; 00303 d->speed_timer.start(1000); 00304 d->slave_calcs_speed = false; 00305 emit totalSize( size ); 00306 } 00307 break; 00308 case INF_PROCESSED_SIZE: 00309 { 00310 KIO::filesize_t size = readFilesize_t(stream); 00311 emit processedSize( size ); 00312 d->filesize = size; 00313 } 00314 break; 00315 case INF_SPEED: 00316 stream >> ul; 00317 d->slave_calcs_speed = true; 00318 d->speed_timer.stop(); 00319 00320 emit speed( ul ); 00321 break; 00322 case INF_GETTING_FILE: 00323 break; 00324 case INF_ERROR_PAGE: 00325 emit errorPage(); 00326 break; 00327 case INF_REDIRECTION: 00328 { 00329 KURL url; 00330 stream >> url; 00331 00332 emit redirection( url ); 00333 } 00334 break; 00335 case INF_MIME_TYPE: 00336 stream >> str1; 00337 00338 emit mimeType( str1 ); 00339 if (!m_pConnection->suspended()) 00340 m_pConnection->sendnow( CMD_NONE, QByteArray() ); 00341 break; 00342 case INF_WARNING: 00343 stream >> str1; 00344 00345 emit warning( str1 ); 00346 break; 00347 case INF_NEED_PASSWD: { 00348 AuthInfo info; 00349 stream >> info; 00350 openPassDlg( info ); 00351 break; 00352 } 00353 case INF_MESSAGEBOX: { 00354 kdDebug(7007) << "needs a msg box" << endl; 00355 QString text, caption, buttonYes, buttonNo, dontAskAgainName; 00356 int type; 00357 stream >> type >> text >> caption >> buttonYes >> buttonNo; 00358 if (stream.atEnd()) 00359 messageBox(type, text, caption, buttonYes, buttonNo); 00360 else { 00361 stream >> dontAskAgainName; 00362 messageBox(type, text, caption, buttonYes, buttonNo, dontAskAgainName); 00363 } 00364 break; 00365 } 00366 case INF_INFOMESSAGE: { 00367 QString msg; 00368 stream >> msg; 00369 infoMessage(msg); 00370 break; 00371 } 00372 case INF_META_DATA: { 00373 MetaData meta_data; 00374 stream >> meta_data; 00375 metaData(meta_data); 00376 break; 00377 } 00378 case MSG_NET_REQUEST: { 00379 QString host; 00380 QString slaveid; 00381 stream >> host >> slaveid; 00382 requestNetwork(host, slaveid); 00383 break; 00384 } 00385 case MSG_NET_DROP: { 00386 QString host; 00387 QString slaveid; 00388 stream >> host >> slaveid; 00389 dropNetwork(host, slaveid); 00390 break; 00391 } 00392 case MSG_NEED_SUBURL_DATA: { 00393 emit needSubURLData(); 00394 break; 00395 } 00396 case MSG_AUTH_KEY: { 00397 bool keep; 00398 QCString key, group; 00399 stream >> key >> group >> keep; 00400 kdDebug(7007) << "Got auth-key: " << key << endl 00401 << " group-key: " << group << endl 00402 << " keep password: " << keep << endl; 00403 emit authorizationKey( key, group, keep ); 00404 break; 00405 } 00406 case MSG_DEL_AUTH_KEY: { 00407 QCString key; 00408 stream >> key; 00409 kdDebug(7007) << "Delete auth-key: " << key << endl; 00410 emit delAuthorization( key ); 00411 } 00412 default: 00413 kdWarning(7007) << "Slave sends unknown command (" << _cmd << "), dropping slave" << endl; 00414 return false; 00415 } 00416 return true; 00417 } 00418 00419 void SlaveInterface::setOffset( KIO::filesize_t o) 00420 { 00421 d->offset = o; 00422 } 00423 00424 KIO::filesize_t SlaveInterface::offset() const { return d->offset; } 00425 00426 void SlaveInterface::requestNetwork(const QString &host, const QString &slaveid) 00427 { 00428 kdDebug(7007) << "requestNetwork " << host << slaveid << endl; 00429 QByteArray packedArgs; 00430 QDataStream stream( packedArgs, IO_WriteOnly ); 00431 stream << true; 00432 m_pConnection->sendnow( INF_NETWORK_STATUS, packedArgs ); 00433 } 00434 00435 void SlaveInterface::dropNetwork(const QString &host, const QString &slaveid) 00436 { 00437 kdDebug(7007) << "dropNetwork " << host << slaveid << endl; 00438 } 00439 00440 void SlaveInterface::sendResumeAnswer( bool resume ) 00441 { 00442 kdDebug(7007) << "SlaveInterface::sendResumeAnswer ok for resuming :" << resume << endl; 00443 m_pConnection->sendnow( resume ? CMD_RESUMEANSWER : CMD_NONE, QByteArray() ); 00444 } 00445 00446 void SlaveInterface::openPassDlg( const QString& prompt, const QString& user, bool readOnly ) 00447 { 00448 AuthInfo info; 00449 info.prompt = prompt; 00450 info.username = user; 00451 info.readOnly = readOnly; 00452 openPassDlg( info ); 00453 } 00454 00455 void SlaveInterface::openPassDlg( const QString& prompt, const QString& user, 00456 const QString& caption, const QString& comment, 00457 const QString& label, bool readOnly ) 00458 { 00459 AuthInfo info; 00460 info.prompt = prompt; 00461 info.username = user; 00462 info.caption = caption; 00463 info.comment = comment; 00464 info.commentLabel = label; 00465 info.readOnly = readOnly; 00466 openPassDlg( info ); 00467 } 00468 00469 void SlaveInterface::openPassDlg( AuthInfo& info ) 00470 { 00471 kdDebug(7007) << "SlaveInterface::openPassDlg: " 00472 << "User= " << info.username 00473 << ", Message= " << info.prompt << endl; 00474 bool result = Observer::self()->openPassDlg( info ); 00475 if ( m_pConnection ) 00476 { 00477 QByteArray data; 00478 QDataStream stream( data, IO_WriteOnly ); 00479 if ( result ) 00480 { 00481 stream << info; 00482 kdDebug(7007) << "SlaveInterface:::openPassDlg got: " 00483 << "User= " << info.username 00484 << ", Password= [hidden]" << endl; 00485 m_pConnection->sendnow( CMD_USERPASS, data ); 00486 } 00487 else 00488 m_pConnection->sendnow( CMD_NONE, data ); 00489 } 00490 } 00491 00492 void SlaveInterface::messageBox( int type, const QString &text, const QString &_caption, 00493 const QString &buttonYes, const QString &buttonNo ) 00494 { 00495 messageBox( type, text, _caption, buttonYes, buttonNo, QString::null ); 00496 } 00497 00498 void SlaveInterface::messageBox( int type, const QString &text, const QString &_caption, 00499 const QString &buttonYes, const QString &buttonNo, const QString &dontAskAgainName ) 00500 { 00501 kdDebug(7007) << "messageBox " << type << " " << text << " - " << _caption << " " << dontAskAgainName << endl; 00502 QByteArray packedArgs; 00503 QDataStream stream( packedArgs, IO_WriteOnly ); 00504 00505 QString caption( _caption ); 00506 if ( type == KIO::SlaveBase::SSLMessageBox ) 00507 caption = QString::fromUtf8(kapp->dcopClient()->appId()); // hack, see observer.cpp 00508 00509 emit needProgressId(); 00510 kdDebug(7007) << "SlaveInterface::messageBox m_progressId=" << m_progressId << endl; 00511 QGuardedPtr<SlaveInterface> me = this; 00512 m_pConnection->suspend(); 00513 int result = Observer::/*self()->*/messageBox( m_progressId, type, text, caption, buttonYes, buttonNo, dontAskAgainName ); 00514 if ( me && m_pConnection ) // Don't do anything if deleted meanwhile 00515 { 00516 m_pConnection->resume(); 00517 kdDebug(7007) << this << " SlaveInterface result=" << result << endl; 00518 stream << result; 00519 m_pConnection->sendnow( CMD_MESSAGEBOXANSWER, packedArgs ); 00520 } 00521 } 00522 00523 // No longer used. 00524 // Remove in KDE 4.0 00525 void SlaveInterface::sigpipe_handler(int) 00526 { 00527 int saved_errno = errno; 00528 // Using kdDebug from a signal handler is not a good idea. 00529 #ifndef NDEBUG 00530 char msg[1000]; 00531 sprintf(msg, "*** SIGPIPE *** (ignored, pid = %ld)\n", (long) getpid()); 00532 write(2, msg, strlen(msg)); 00533 #endif 00534 00535 // Do nothing. 00536 // dispatch will return false and that will trigger ERR_SLAVE_DIED in slave.cpp 00537 errno = saved_errno; 00538 } 00539 00540 void SlaveInterface::virtual_hook( int, void* ) 00541 { /*BASE::virtual_hook( id, data );*/ } 00542 00543 #include "slaveinterface.moc"
KDE Logo
This file is part of the documentation for kio Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Apr 12 23:09:33 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003