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     // On 64-bit platforms nothing has changed.
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     // On 32-bit platforms we send UDS_SIZE with UDS_SIZE_LARGE in front
00084     // of it to carry the 32 msb. We can't send a 64 bit UDS_SIZE because
00085     // that would break the compatibility of the wire-protocol with KDE 2.
00086     // On 64-bit platforms nothing has changed.
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     m_pConnection = connection;
00153     m_progressId = 0;
00154 
00155     d = new SlaveInterfacePrivate;
00156     connect(&d->speed_timer, SIGNAL(timeout()), SLOT(calcSpeed()));
00157 }
00158 
00159 SlaveInterface::~SlaveInterface()
00160 {
00161     // Note: no kdDebug() here (scheduler is deleted very late)
00162     m_pConnection = 0; // a bit like the "wasDeleted" of QObject...
00163 
00164     delete d;
00165 }
00166 
00167 static KIO::filesize_t readFilesize_t(QDataStream &stream)
00168 {
00169    KIO::filesize_t result;
00170    unsigned long ul;
00171    stream >> ul;
00172    result = ul;
00173    if (stream.atEnd())
00174       return result;
00175    stream >> ul;
00176    result += ((KIO::filesize_t)ul) << 32;
00177    return result;
00178 }
00179 
00180 
00181 bool SlaveInterface::dispatch()
00182 {
00183     assert( m_pConnection );
00184 
00185     int cmd;
00186     QByteArray data;
00187 
00188     if (m_pConnection->read( &cmd, data ) == -1)
00189       return false;
00190 
00191     return dispatch( cmd, data );
00192 }
00193 
00194 void SlaveInterface::calcSpeed()
00195 {
00196   if (d->slave_calcs_speed) {
00197     d->speed_timer.stop();
00198     return;
00199   }
00200 
00201   struct timeval tv;
00202   gettimeofday(&tv, 0);
00203 
00204   long diff = ((tv.tv_sec - d->start_time.tv_sec) * 1000000 +
00205            tv.tv_usec - d->start_time.tv_usec) / 1000;
00206   if (diff - d->last_time >= 900) {
00207     d->last_time = diff;
00208     if (d->nums == max_nums) {
00209       // let's hope gcc can optimize that well enough
00210       // otherwise I'd try memcpy :)
00211       for (unsigned int i = 1; i < max_nums; ++i) {
00212     d->times[i-1] = d->times[i];
00213     d->sizes[i-1] = d->sizes[i];
00214       }
00215       d->nums--;
00216     }
00217     d->times[d->nums] = diff;
00218     d->sizes[d->nums++] = d->filesize;
00219 
00220     KIO::filesize_t lspeed = 1000 * (d->sizes[d->nums-1] - d->sizes[0]) / (d->times[d->nums-1] - d->times[0]);
00221 
00222     // kdDebug() << "proceeed " << (long)d->filesize << " " << diff << " " << long(d->sizes[d->nums-1] - d->sizes[0]) << " " <<  d->times[d->nums-1] - d->times[0] << " " << long(lspeed) << " " << double(d->filesize) / diff << " " << convertSize(lspeed) << " " << convertSize(long(double(d->filesize) / diff) * 1000) << " " <<  endl ;
00223 
00224     if (!lspeed) {
00225       d->nums = 1;
00226       d->times[0] = diff;
00227       d->sizes[0] = d->filesize;
00228     }
00229     emit speed(lspeed);
00230   }
00231 }
00232 
00233 bool SlaveInterface::dispatch( int _cmd, const QByteArray &rawdata )
00234 {
00235     //kdDebug(7007) << "dispatch " << _cmd << endl;
00236 
00237     QDataStream stream( rawdata, IO_ReadOnly );
00238 
00239     QString str1;
00240     int i;
00241     Q_INT8 b;
00242     unsigned long ul;
00243 
00244     switch( _cmd ) {
00245     case MSG_DATA:
00246     emit data( rawdata );
00247     break;
00248     case MSG_DATA_REQ:
00249         emit dataReq();
00250     break;
00251     case MSG_FINISHED:
00252     //kdDebug(7007) << "Finished [this = " << this << "]" << endl;
00253         d->offset = 0;
00254         d->speed_timer.stop();
00255     emit finished();
00256     break;
00257     case MSG_STAT_ENTRY:
00258     {
00259         UDSEntry entry;
00260         stream >> entry;
00261         emit statEntry(entry);
00262     }
00263     break;
00264     case MSG_LIST_ENTRIES:
00265     {
00266         uint count;
00267         stream >> count;
00268 
00269         UDSEntryList list;
00270         UDSEntry entry;
00271         for (uint i = 0; i < count; i++) {
00272         stream >> entry;
00273         list.append(entry);
00274         }
00275         emit listEntries(list);
00276 
00277     }
00278     break;
00279     case MSG_RESUME: // From the put job
00280     {
00281         KIO::filesize_t offset = readFilesize_t(stream);
00282         emit canResume( offset );
00283     }
00284     break;
00285     case MSG_CANRESUME: // From the get job
00286         d->filesize = d->offset;
00287         emit canResume(0); // the arg doesn't matter
00288         break;
00289     case MSG_ERROR:
00290     stream >> i >> str1;
00291     kdDebug(7007) << "error " << i << " " << str1 << endl;
00292     emit error( i, str1 );
00293     break;
00294     case MSG_SLAVE_STATUS:
00295         {
00296            pid_t pid;
00297            QCString protocol;
00298            stream >> pid >> protocol >> str1 >> b;
00299            emit slaveStatus(pid, protocol, str1, (b != 0));
00300         }
00301         break;
00302     case MSG_CONNECTED:
00303     emit connected();
00304     break;
00305 
00306     case INF_TOTAL_SIZE:
00307     {
00308         KIO::filesize_t size = readFilesize_t(stream);
00309         gettimeofday(&d->start_time, 0);
00310         d->last_time = 0;
00311         d->filesize = d->offset;
00312         d->sizes[0] = d->filesize;
00313         d->times[0] = 0;
00314         d->nums = 1;
00315         d->speed_timer.start(1000);
00316         d->slave_calcs_speed = false;
00317         emit totalSize( size );
00318     }
00319     break;
00320     case INF_PROCESSED_SIZE:
00321     {
00322         KIO::filesize_t size = readFilesize_t(stream);
00323         emit processedSize( size );
00324         d->filesize = size;
00325     }
00326     break;
00327     case INF_SPEED:
00328     stream >> ul;
00329     d->slave_calcs_speed = true;
00330     d->speed_timer.stop();
00331 
00332     emit speed( ul );
00333     break;
00334     case INF_GETTING_FILE:
00335     break;
00336     case INF_ERROR_PAGE:
00337     emit errorPage();
00338     break;
00339     case INF_REDIRECTION:
00340       {
00341     KURL url;
00342     stream >> url;
00343 
00344     emit redirection( url );
00345       }
00346       break;
00347     case INF_MIME_TYPE:
00348     stream >> str1;
00349 
00350     emit mimeType( str1 );
00351         if (!m_pConnection->suspended())
00352             m_pConnection->sendnow( CMD_NONE, QByteArray() );
00353     break;
00354     case INF_WARNING:
00355     stream >> str1;
00356 
00357     emit warning( str1 );
00358     break;
00359     case INF_NEED_PASSWD: {
00360         AuthInfo info;
00361         stream >> info;
00362     openPassDlg( info );
00363     break;
00364     }
00365     case INF_MESSAGEBOX: {
00366     kdDebug(7007) << "needs a msg box" << endl;
00367     QString text, caption, buttonYes, buttonNo;
00368         int type;
00369     stream >> type >> text >> caption >> buttonYes >> buttonNo;
00370     messageBox(type, text, caption, buttonYes, buttonNo);
00371     break;
00372     }
00373     case INF_INFOMESSAGE: {
00374         QString msg;
00375         stream >> msg;
00376         infoMessage(msg);
00377         break;
00378     }
00379     case INF_META_DATA: {
00380         MetaData meta_data;
00381         stream >> meta_data;
00382         metaData(meta_data);
00383         break;
00384     }
00385     case MSG_NET_REQUEST: {
00386         QString host;
00387     QString slaveid;
00388         stream >> host >> slaveid;
00389         requestNetwork(host, slaveid);
00390         break;
00391     }
00392     case MSG_NET_DROP: {
00393         QString host;
00394     QString slaveid;
00395         stream >> host >> slaveid;
00396         dropNetwork(host, slaveid);
00397         break;
00398     }
00399     case MSG_NEED_SUBURL_DATA: {
00400         emit needSubURLData();
00401         break;
00402     }
00403     case MSG_AUTH_KEY: {
00404         bool keep;
00405         QCString key, group;
00406         stream >> key >> group >> keep;
00407         kdDebug(7007) << "Got auth-key:      " << key << endl
00408                       << "    group-key:     " << group << endl
00409                       << "    keep password: " << keep << endl;
00410         emit authorizationKey( key, group, keep );
00411         break;
00412     }
00413     case MSG_DEL_AUTH_KEY: {
00414         QCString key;
00415         stream >> key;
00416         kdDebug(7007) << "Delete auth-key: " << key << endl;
00417         emit delAuthorization( key );
00418     }
00419     default:
00420         kdWarning(7007) << "Slave sends unknown command (" << _cmd << "), dropping slave" << endl;
00421     return false;
00422     }
00423     return true;
00424 }
00425 
00426 void SlaveInterface::setOffset( KIO::filesize_t o)
00427 {
00428     d->offset = o;
00429 }
00430 
00431 KIO::filesize_t SlaveInterface::offset() const { return d->offset; }
00432 
00433 void SlaveInterface::requestNetwork(const QString &host, const QString &slaveid)
00434 {
00435     kdDebug(7007) << "requestNetwork " << host << slaveid << endl;
00436     QByteArray packedArgs;
00437     QDataStream stream( packedArgs, IO_WriteOnly );
00438     stream << true;
00439     m_pConnection->sendnow( INF_NETWORK_STATUS, packedArgs );
00440 }
00441 
00442 void SlaveInterface::dropNetwork(const QString &host, const QString &slaveid)
00443 {
00444     kdDebug(7007) << "dropNetwork " << host << slaveid << endl;
00445 }
00446 
00447 void SlaveInterface::sendResumeAnswer( bool resume )
00448 {
00449     kdDebug(7007) << "SlaveInterface::sendResumeAnswer ok for resuming :" << resume << endl;
00450     m_pConnection->sendnow( resume ? CMD_RESUMEANSWER : CMD_NONE, QByteArray() );
00451 }
00452 
00453 void SlaveInterface::openPassDlg( const QString& prompt, const QString& user, bool readOnly )
00454 {
00455     AuthInfo info;
00456     info.prompt = prompt;
00457     info.username = user;
00458     info.readOnly = readOnly;
00459     openPassDlg( info );
00460 }
00461 
00462 void SlaveInterface::openPassDlg( const QString& prompt, const QString& user,
00463                                   const QString& caption, const QString& comment,
00464                                   const QString& label, bool readOnly )
00465 {
00466     AuthInfo info;
00467     info.prompt = prompt;
00468     info.username = user;
00469     info.caption = caption;
00470     info.comment = comment;
00471     info.commentLabel = label;
00472     info.readOnly = readOnly;
00473     openPassDlg( info );
00474 }
00475 
00476 void SlaveInterface::openPassDlg( AuthInfo& info )
00477 {
00478     kdDebug(7007) << "SlaveInterface::openPassDlg: "
00479                   << "User= " << info.username
00480                   << ", Message= " << info.prompt << endl;
00481     bool result = Observer::self()->openPassDlg( info );
00482     if ( m_pConnection )
00483     {
00484         QByteArray data;
00485         QDataStream stream( data, IO_WriteOnly );
00486         if ( result )
00487         {
00488             stream << info;
00489             kdDebug(7007) << "SlaveInterface:::openPassDlg got: "
00490                           << "User= " << info.username
00491                           << ", Password= [hidden]" << endl;
00492             m_pConnection->sendnow( CMD_USERPASS, data );
00493         }
00494         else
00495             m_pConnection->sendnow( CMD_NONE, data );
00496     }
00497 }
00498 
00499 void SlaveInterface::messageBox( int type, const QString &text, const QString &_caption,
00500                                  const QString &buttonYes, const QString &buttonNo )
00501 {
00502     kdDebug(7007) << "messageBox " << type << " " << text << " - " << _caption << endl;
00503     QByteArray packedArgs;
00504     QDataStream stream( packedArgs, IO_WriteOnly );
00505 
00506     QString caption( _caption );
00507     if ( type == KIO::SlaveBase::SSLMessageBox )
00508         caption = QString::fromUtf8(kapp->dcopClient()->appId()); // hack, see observer.cpp
00509 
00510     emit needProgressId();
00511     kdDebug(7007) << "SlaveInterface::messageBox m_progressId=" << m_progressId << endl;
00512     int result = Observer::/*self()->*/messageBox( m_progressId, type, text, caption, buttonYes, buttonNo );
00513     if ( m_pConnection ) // Don't do anything if deleted meanwhile
00514     {
00515         kdDebug(7007) << this << " SlaveInterface result=" << result << endl;
00516         stream << result;
00517         m_pConnection->sendnow( CMD_MESSAGEBOXANSWER, packedArgs );
00518     }
00519 }
00520 
00521 // No longer used.
00522 // Remove in KDE 4.0
00523 void SlaveInterface::sigpipe_handler(int)
00524 {
00525     int saved_errno = errno;
00526     // Using kdDebug from a signal handler is not a good idea.
00527 #ifndef NDEBUG    
00528     char msg[1000];
00529     sprintf(msg, "*** SIGPIPE *** (ignored, pid = %ld)\n", (long) getpid());
00530     write(2, msg, strlen(msg));
00531 #endif    
00532 
00533     // Do nothing.
00534     // dispatch will return false and that will trigger ERR_SLAVE_DIED in slave.cpp
00535     errno = saved_errno;
00536 }
00537 
00538 void SlaveInterface::virtual_hook( int, void* )
00539 { /*BASE::virtual_hook( id, data );*/ }
00540 
00541 #include "slaveinterface.moc"
KDE Logo
This file is part of the documentation for kio Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Jan 21 09:57:58 2005 by doxygen 1.3.6 written by Dimitri van Heesch, © 1997-2003