00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 #include <config.h>
00023 
00024 #include <sys/types.h>
00025 #include <sys/wait.h>
00026 #include <sys/stat.h>
00027 
00028 #include <assert.h>
00029 
00030 #include <signal.h>
00031 #include <stdlib.h>
00032 #include <stdio.h>
00033 #include <time.h>
00034 #include <unistd.h>
00035 extern "C" {
00036 #include <pwd.h>
00037 #include <grp.h>
00038 }
00039 #include <qtimer.h>
00040 #include <qfile.h>
00041 
00042 #include <kapplication.h>
00043 #include <kglobal.h>
00044 #include <klocale.h>
00045 #include <ksimpleconfig.h>
00046 #include <kdebug.h>
00047 #include <kdialog.h>
00048 #include <kmessagebox.h>
00049 #include <kdatastream.h>
00050 #include <kmainwindow.h>
00051 
00052 #include <errno.h>
00053 
00054 #include "slave.h"
00055 #include "kio/job.h"
00056 #include "scheduler.h"
00057 #include "kdirwatch.h"
00058 #include "kmimemagic.h"
00059 #include "kprotocolinfo.h"
00060 #include "kprotocolmanager.h"
00061 
00062 #include "kio/observer.h"
00063 
00064 #include "kssl/ksslcsessioncache.h"
00065 
00066 #include <kdirnotify_stub.h>
00067 #include <ktempfile.h>
00068 #include <dcopclient.h>
00069 
00070 using namespace KIO;
00071 template class QPtrList<KIO::Job>;
00072 
00073 
00074 #define REPORT_TIMEOUT 200
00075 
00076 #define KIO_ARGS QByteArray packedArgs; QDataStream stream( packedArgs, IO_WriteOnly ); stream
00077 
00078 class Job::JobPrivate
00079 {
00080 public:
00081     JobPrivate() : m_autoErrorHandling( false ), m_parentJob( 0L ), m_extraFlags(0),
00082                    m_processedSize(0)
00083                    {}
00084 
00085     bool m_autoErrorHandling;
00086     QGuardedPtr<QWidget> m_errorParentWidget;
00087     
00088     
00089     Job* m_parentJob;
00090     int m_extraFlags;
00091     KIO::filesize_t m_processedSize;
00092 };
00093 
00094 Job::Job(bool showProgressInfo) : QObject(0, "job"), m_error(0), m_percent(0)
00095    , m_progressId(0), m_speedTimer(0), d( new JobPrivate )
00096 {
00097     
00098 
00099     
00100     if ( showProgressInfo )
00101     {
00102         m_progressId = Observer::self()->newJob( this, true );
00103         
00104         
00105         connect( this, SIGNAL( percent( KIO::Job*, unsigned long ) ),
00106                  Observer::self(), SLOT( slotPercent( KIO::Job*, unsigned long ) ) );
00107         connect( this, SIGNAL( infoMessage( KIO::Job*, const QString & ) ),
00108                  Observer::self(), SLOT( slotInfoMessage( KIO::Job*, const QString & ) ) );
00109         connect( this, SIGNAL( totalSize( KIO::Job*, KIO::filesize_t ) ),
00110                  Observer::self(), SLOT( slotTotalSize( KIO::Job*, KIO::filesize_t ) ) );
00111         connect( this, SIGNAL( processedSize( KIO::Job*, KIO::filesize_t ) ),
00112                  Observer::self(), SLOT( slotProcessedSize( KIO::Job*, KIO::filesize_t ) ) );
00113         connect( this, SIGNAL( speed( KIO::Job*, unsigned long ) ),
00114                  Observer::self(), SLOT( slotSpeed( KIO::Job*, unsigned long ) ) );
00115     }
00116     
00117     kapp->ref();
00118 }
00119 
00120 Job::~Job()
00121 {
00122     delete m_speedTimer;
00123     delete d;
00124     kapp->deref();
00125 }
00126 
00127 int& Job::extraFlags()
00128 {
00129     return d->m_extraFlags;
00130 }
00131 
00132 void Job::setProcessedSize(KIO::filesize_t size)
00133 {
00134     d->m_processedSize = size;
00135 }
00136 
00137 KIO::filesize_t Job::getProcessedSize()
00138 {
00139     return d->m_processedSize;
00140 }
00141 
00142 void Job::addSubjob(Job *job, bool inheritMetaData)
00143 {
00144     
00145     subjobs.append(job);
00146 
00147     connect( job, SIGNAL(result(KIO::Job*)),
00148              SLOT(slotResult(KIO::Job*)) );
00149 
00150     
00151     connect( job, SIGNAL(speed( KIO::Job*, unsigned long )),
00152              SLOT(slotSpeed(KIO::Job*, unsigned long)) );
00153 
00154     connect( job, SIGNAL(infoMessage( KIO::Job*, const QString & )),
00155              SLOT(slotInfoMessage(KIO::Job*, const QString &)) );
00156 
00157     if (inheritMetaData)
00158        job->mergeMetaData(m_outgoingMetaData);
00159 
00160     job->setWindow( m_window );
00161 }
00162 
00163 void Job::removeSubjob( Job *job )
00164 {
00165     
00166     subjobs.remove(job);
00167     if (subjobs.isEmpty())
00168         emitResult();
00169 }
00170 
00171 void Job::emitPercent( KIO::filesize_t processedSize, KIO::filesize_t totalSize )
00172 {
00173   
00174   unsigned long ipercent = m_percent;
00175 
00176   if ( totalSize == 0 )
00177     m_percent = 100;
00178   else
00179     m_percent = (unsigned long)(( (float)(processedSize) / (float)(totalSize) ) * 100.0);
00180 
00181   if ( m_percent != ipercent || m_percent == 100  ) {
00182     emit percent( this, m_percent );
00183     
00184   }
00185 }
00186 
00187 void Job::emitSpeed( unsigned long bytes_per_second )
00188 {
00189   
00190   if ( !m_speedTimer )
00191   {
00192     m_speedTimer = new QTimer();
00193     connect( m_speedTimer, SIGNAL( timeout() ), SLOT( slotSpeedTimeout() ) );
00194   }
00195   emit speed( this, bytes_per_second );
00196   m_speedTimer->start( 5000 );   
00197 }
00198 
00199 void Job::emitResult()
00200 {
00201   
00202   if ( m_progressId ) 
00203     Observer::self()->jobFinished( m_progressId );
00204   if ( m_error && d->m_autoErrorHandling )
00205     showErrorDialog( d->m_errorParentWidget );
00206   emit result(this);
00207   delete this;
00208 }
00209 
00210 void Job::kill( bool quietly )
00211 {
00212   kdDebug(7007) << "Job::kill this=" << this << " m_progressId=" << m_progressId << " quietly=" << quietly << endl;
00213   
00214   QPtrListIterator<Job> it( subjobs );
00215   for ( ; it.current() ; ++it )
00216      (*it)->kill( true );
00217   subjobs.clear();
00218 
00219   if ( ! quietly ) {
00220     m_error = ERR_USER_CANCELED;
00221     emit canceled( this ); 
00222     emitResult();
00223   } else
00224   {
00225     if ( m_progressId ) 
00226       Observer::self()->jobFinished( m_progressId );
00227     delete this;
00228   }
00229 }
00230 
00231 void Job::slotResult( Job *job )
00232 {
00233     
00234     if ( job->error() && !m_error )
00235     {
00236         
00237         m_error = job->error();
00238         m_errorText = job->errorText();
00239     }
00240     removeSubjob(job);
00241 }
00242 
00243 void Job::slotSpeed( KIO::Job*, unsigned long bytes_per_second )
00244 {
00245   
00246   emitSpeed( bytes_per_second );
00247 }
00248 
00249 void Job::slotInfoMessage( KIO::Job*, const QString & msg )
00250 {
00251   emit infoMessage( this, msg );
00252 }
00253 
00254 void Job::slotSpeedTimeout()
00255 {
00256   
00257   
00258   
00259   emit speed( this, 0 );
00260   m_speedTimer->stop();
00261 }
00262 
00263 
00264 
00265 void Job::showErrorDialog( QWidget * parent )
00266 {
00267   
00268   kapp->enableStyles();
00269   
00270   if ( (m_error != ERR_USER_CANCELED) && (m_error != ERR_NO_CONTENT) ) {
00271     
00272     
00273     if ( 1 )
00274       KMessageBox::queuedMessageBox( parent, KMessageBox::Error, errorString() );
00275 #if 0
00276     } else {
00277       QStringList errors = detailedErrorStrings();
00278       QString caption, err, detail;
00279       QStringList::iterator it = errors.begin();
00280       if ( it != errors.end() )
00281         caption = *(it++);
00282       if ( it != errors.end() )
00283         err = *(it++);
00284       if ( it != errors.end() )
00285         detail = *it;
00286       KMessageBox::queuedDetailedError( parent, err, detail, caption );
00287     }
00288 #endif
00289   }
00290 }
00291 
00292 void Job::setAutoErrorHandlingEnabled( bool enable, QWidget *parentWidget )
00293 {
00294   d->m_autoErrorHandling = enable;
00295   d->m_errorParentWidget = parentWidget;
00296 }
00297 
00298 bool Job::isAutoErrorHandlingEnabled() const
00299 {
00300   return d->m_autoErrorHandling;
00301 }
00302 
00303 void Job::setWindow(QWidget *window)
00304 {
00305   m_window = window;
00306   KIO::Scheduler::registerWindow(window);
00307 }
00308 
00309 QWidget *Job::window() const
00310 {
00311   return m_window;
00312 }
00313 
00314 void Job::setParentJob(Job* job)
00315 {
00316   Q_ASSERT(d->m_parentJob == 0L);
00317   Q_ASSERT(job);
00318   d->m_parentJob = job;
00319 }
00320 
00321 Job* Job::parentJob() const
00322 {
00323   return d->m_parentJob;
00324 }
00325 
00326 MetaData Job::metaData() const
00327 {
00328     return m_incomingMetaData;
00329 }
00330 
00331 QString Job::queryMetaData(const QString &key)
00332 {
00333     if (!m_incomingMetaData.contains(key))
00334        return QString::null;
00335     return m_incomingMetaData[key];
00336 }
00337 
00338 void Job::setMetaData( const KIO::MetaData &_metaData)
00339 {
00340     m_outgoingMetaData = _metaData;
00341 }
00342 
00343 void Job::addMetaData( const QString &key, const QString &value)
00344 {
00345     m_outgoingMetaData.insert(key, value);
00346 }
00347 
00348 void Job::addMetaData( const QMap<QString,QString> &values)
00349 {
00350     QMapConstIterator<QString,QString> it = values.begin();
00351     for(;it != values.end(); ++it)
00352       m_outgoingMetaData.insert(it.key(), it.data());
00353 }
00354 
00355 void Job::mergeMetaData( const QMap<QString,QString> &values)
00356 {
00357     QMapConstIterator<QString,QString> it = values.begin();
00358     for(;it != values.end(); ++it)
00359       m_outgoingMetaData.insert(it.key(), it.data(), false);
00360 }
00361 
00362 MetaData Job::outgoingMetaData() const
00363 {
00364     return m_outgoingMetaData;
00365 }
00366 
00367 
00368 SimpleJob::SimpleJob(const KURL& url, int command, const QByteArray &packedArgs,
00369                      bool showProgressInfo )
00370   : Job(showProgressInfo), m_slave(0), m_packedArgs(packedArgs),
00371     m_url(url), m_command(command), m_totalSize(0)
00372 {
00373     if (!m_url.isValid())
00374     {
00375         m_error = ERR_MALFORMED_URL;
00376         m_errorText = m_url.url();
00377         QTimer::singleShot(0, this, SLOT(slotFinished()) );
00378         return;
00379     }
00380 
00381 
00382     if (m_url.hasSubURL())
00383     {
00384        KURL::List list = KURL::split(m_url);
00385        KURL::List::Iterator it = list.fromLast();
00386        list.remove(it);
00387        m_subUrl = KURL::join(list);
00388        
00389        
00390     }
00391 
00392     Scheduler::doJob(this);
00393 }
00394 
00395 void SimpleJob::kill( bool quietly )
00396 {
00397     Scheduler::cancelJob( this ); 
00398     m_slave = 0; 
00399     Job::kill( quietly );
00400 }
00401 
00402 void SimpleJob::putOnHold()
00403 {
00404     Scheduler::putSlaveOnHold(this, m_url);
00405     m_slave = 0;
00406     kill(true);
00407 }
00408 
00409 void SimpleJob::removeOnHold()
00410 {
00411     Scheduler::removeSlaveOnHold();
00412 }
00413 
00414 SimpleJob::~SimpleJob()
00415 {
00416     if (m_slave) 
00417     {
00418         kdDebug(7007) << "SimpleJob::~SimpleJob: Killing running job in destructor!"  << endl;
00419 #if 0
00420         m_slave->kill();
00421         Scheduler::jobFinished( this, m_slave ); 
00422 #endif
00423         Scheduler::cancelJob( this );
00424         m_slave = 0; 
00425     }
00426 }
00427 
00428 void SimpleJob::start(Slave *slave)
00429 {
00430     m_slave = slave;
00431 
00432     connect( m_slave, SIGNAL( error( int , const QString & ) ),
00433              SLOT( slotError( int , const QString & ) ) );
00434 
00435     connect( m_slave, SIGNAL( warning( const QString & ) ),
00436              SLOT( slotWarning( const QString & ) ) );
00437 
00438     connect( m_slave, SIGNAL( infoMessage( const QString & ) ),
00439              SLOT( slotInfoMessage( const QString & ) ) );
00440 
00441     connect( m_slave, SIGNAL( connected() ),
00442              SLOT( slotConnected() ) );
00443 
00444     connect( m_slave, SIGNAL( finished() ),
00445              SLOT( slotFinished() ) );
00446 
00447     if ((extraFlags() & EF_TransferJobDataSent) == 0)
00448     {
00449         connect( m_slave, SIGNAL( totalSize( KIO::filesize_t ) ),
00450                  SLOT( slotTotalSize( KIO::filesize_t ) ) );
00451 
00452         connect( m_slave, SIGNAL( processedSize( KIO::filesize_t ) ),
00453                  SLOT( slotProcessedSize( KIO::filesize_t ) ) );
00454 
00455         connect( m_slave, SIGNAL( speed( unsigned long ) ),
00456                  SLOT( slotSpeed( unsigned long ) ) );
00457     }
00458 
00459     connect( slave, SIGNAL( needProgressId() ),
00460              SLOT( slotNeedProgressId() ) );
00461 
00462     connect( slave, SIGNAL(metaData( const KIO::MetaData& ) ),
00463              SLOT( slotMetaData( const KIO::MetaData& ) ) );
00464 
00465     if (m_window)
00466     {
00467        QString id;
00468        addMetaData("window-id", id.setNum(m_window->winId()));
00469     }
00470 
00471     QString sslSession = KSSLCSessionCache::getSessionForURL(m_url);
00472     if (sslSession != QString::null)
00473     addMetaData("ssl_session_id", sslSession);
00474 
00475     if (!m_outgoingMetaData.isEmpty())
00476     {
00477        KIO_ARGS << m_outgoingMetaData;
00478        slave->send( CMD_META_DATA, packedArgs );
00479     }
00480 
00481     if (!m_subUrl.isEmpty())
00482     {
00483        KIO_ARGS << m_subUrl;
00484        m_slave->send( CMD_SUBURL, packedArgs );
00485     }
00486 
00487     m_slave->send( m_command, m_packedArgs );
00488 }
00489 
00490 void SimpleJob::slaveDone()
00491 {
00492    if (!m_slave) return;
00493    disconnect(m_slave); 
00494    Scheduler::jobFinished( this, m_slave );
00495    m_slave = 0;
00496 }
00497 
00498 void SimpleJob::slotFinished( )
00499 {
00500     
00501     slaveDone();
00502 
00503     if (subjobs.isEmpty())
00504     {
00505         if ( !m_error )
00506         {
00507             KDirNotify_stub allDirNotify( "*", "KDirNotify*" );
00508             if ( m_command == CMD_MKDIR )
00509             {
00510                 KURL urlDir( url() );
00511                 urlDir.setPath( urlDir.directory() );
00512                 allDirNotify.FilesAdded( urlDir );
00513             }
00514             else if ( m_command == CMD_RENAME )
00515             {
00516                 KURL src, dst;
00517                 QDataStream str( m_packedArgs, IO_ReadOnly );
00518                 str >> src >> dst;
00519                 if ( src.directory() == dst.directory() ) 
00520                     allDirNotify.FileRenamed( src, dst );
00521             }
00522         }
00523         emitResult();
00524     }
00525 }
00526 
00527 void SimpleJob::slotError( int error, const QString & errorText )
00528 {
00529     m_error = error;
00530     m_errorText = errorText;
00531     if ((m_error == ERR_UNKNOWN_HOST) && m_url.host().isEmpty())
00532        m_errorText = QString::null;
00533     
00534     slotFinished();
00535 }
00536 
00537 void SimpleJob::slotWarning( const QString & errorText )
00538 {
00539     static uint msgBoxDisplayed = 0;
00540     if ( msgBoxDisplayed == 0 ) 
00541     {
00542         msgBoxDisplayed++;
00543         KMessageBox::information( 0L, errorText );
00544         msgBoxDisplayed--;
00545     }
00546     
00547 }
00548 
00549 void SimpleJob::slotInfoMessage( const QString & msg )
00550 {
00551     emit infoMessage( this, msg );
00552 }
00553 
00554 void SimpleJob::slotConnected()
00555 {
00556     emit connected( this );
00557 }
00558 
00559 void SimpleJob::slotNeedProgressId()
00560 {
00561     if ( !m_progressId )
00562         m_progressId = Observer::self()->newJob( this, false );
00563     m_slave->setProgressId( m_progressId );
00564 }
00565 
00566 void SimpleJob::slotTotalSize( KIO::filesize_t size )
00567 {
00568     m_totalSize = size;
00569     emit totalSize( this, size );
00570 }
00571 
00572 void SimpleJob::slotProcessedSize( KIO::filesize_t size )
00573 {
00574     
00575     setProcessedSize(size);
00576     emit processedSize( this, size );
00577     if ( size > m_totalSize ) {
00578         slotTotalSize(size); 
00579     }
00580     emitPercent( size, m_totalSize );
00581 }
00582 
00583 void SimpleJob::slotSpeed( unsigned long bytes_per_second )
00584 {
00585     
00586     emitSpeed( bytes_per_second );
00587 }
00588 
00589 void SimpleJob::slotMetaData( const KIO::MetaData &_metaData)
00590 {
00591     m_incomingMetaData += _metaData;
00592 }
00593 
00594 void SimpleJob::storeSSLSessionFromJob(const KURL &m_redirectionURL) {
00595     QString sslSession = queryMetaData("ssl_session_id");
00596 
00597     if (sslSession != QString::null) {
00598     const KURL &queryURL = m_redirectionURL.isEmpty()?m_url:m_redirectionURL;
00599     KSSLCSessionCache::putSessionForURL(queryURL, sslSession);
00600     }
00601 }
00602 
00603 SimpleJob *KIO::mkdir( const KURL& url, int permissions )
00604 {
00605     
00606     KIO_ARGS << url << permissions;
00607     return new SimpleJob(url, CMD_MKDIR, packedArgs, false);
00608 }
00609 
00610 SimpleJob *KIO::rmdir( const KURL& url )
00611 {
00612     
00613     KIO_ARGS << url << Q_INT8(false); 
00614     return new SimpleJob(url, CMD_DEL, packedArgs, false);
00615 }
00616 
00617 SimpleJob *KIO::chmod( const KURL& url, int permissions )
00618 {
00619     
00620     KIO_ARGS << url << permissions;
00621     return new SimpleJob(url, CMD_CHMOD, packedArgs, false);
00622 }
00623 
00624 SimpleJob *KIO::rename( const KURL& src, const KURL & dest, bool overwrite )
00625 {
00626     
00627     KIO_ARGS << src << dest << (Q_INT8) overwrite;
00628     return new SimpleJob(src, CMD_RENAME, packedArgs, false);
00629 }
00630 
00631 SimpleJob *KIO::symlink( const QString& target, const KURL & dest, bool overwrite, bool showProgressInfo )
00632 {
00633     
00634     KIO_ARGS << target << dest << (Q_INT8) overwrite;
00635     return new SimpleJob(dest, CMD_SYMLINK, packedArgs, showProgressInfo);
00636 }
00637 
00638 SimpleJob *KIO::special(const KURL& url, const QByteArray & data, bool showProgressInfo)
00639 {
00640     
00641     return new SimpleJob(url, CMD_SPECIAL, data, showProgressInfo);
00642 }
00643 
00644 SimpleJob *KIO::mount( bool ro, const char *fstype, const QString& dev, const QString& point, bool showProgressInfo )
00645 {
00646     KIO_ARGS << int(1) << Q_INT8( ro ? 1 : 0 )
00647              << QString::fromLatin1(fstype) << dev << point;
00648     SimpleJob *job = special( KURL("file:/"), packedArgs, showProgressInfo );
00649     if ( showProgressInfo )
00650          Observer::self()->mounting( job, dev, point );
00651     return job;
00652 }
00653 
00654 SimpleJob *KIO::unmount( const QString& point, bool showProgressInfo )
00655 {
00656     KIO_ARGS << int(2) << point;
00657     SimpleJob *job = special( KURL("file:/"), packedArgs, showProgressInfo );
00658     if ( showProgressInfo )
00659          Observer::self()->unmounting( job, point );
00660     return job;
00661 }
00662 
00664 
00665 StatJob::StatJob( const KURL& url, int command,
00666                   const QByteArray &packedArgs, bool showProgressInfo )
00667     : SimpleJob(url, command, packedArgs, showProgressInfo),
00668     m_bSource(true), m_details(2)
00669 {
00670 }
00671 
00672 void StatJob::start(Slave *slave)
00673 {
00674     m_outgoingMetaData.replace( "statSide", m_bSource ? "source" : "dest" );
00675     m_outgoingMetaData.replace( "details", QString::number(m_details) );
00676 
00677     SimpleJob::start(slave);
00678 
00679     connect( m_slave, SIGNAL( statEntry( const KIO::UDSEntry& ) ),
00680              SLOT( slotStatEntry( const KIO::UDSEntry & ) ) );
00681     connect( slave, SIGNAL( redirection(const KURL &) ),
00682              SLOT( slotRedirection(const KURL &) ) );
00683 }
00684 
00685 void StatJob::slotStatEntry( const KIO::UDSEntry & entry )
00686 {
00687     
00688     m_statResult = entry;
00689 }
00690 
00691 
00692 void StatJob::slotRedirection( const KURL &url)
00693 {
00694      kdDebug(7007) << "StatJob::slotRedirection(" << url.prettyURL() << ")" << endl;
00695      if (!kapp->authorizeURLAction("redirect", m_url, url))
00696      {
00697        kdWarning(7007) << "StatJob: Redirection from " << m_url.prettyURL() << " to " << url.prettyURL() << " REJECTED!" << endl;
00698        m_error = ERR_ACCESS_DENIED;
00699        m_errorText = url.prettyURL();
00700        return;
00701      }
00702      m_redirectionURL = url; 
00703      if (m_url.hasUser() && !url.hasUser() && (m_url.host().lower() == url.host().lower()))
00704         m_redirectionURL.setUser(m_url.user()); 
00705      
00706      emit redirection(this, m_redirectionURL);
00707 }
00708 
00709 void StatJob::slotFinished()
00710 {
00711     if ( m_redirectionURL.isEmpty() || !m_redirectionURL.isValid())
00712     {
00713         
00714         SimpleJob::slotFinished();
00715     } else {
00716         
00717         if (queryMetaData("permanent-redirect")=="true")
00718             emit permanentRedirection(this, m_url, m_redirectionURL);
00719         m_url = m_redirectionURL;
00720         m_redirectionURL = KURL();
00721         m_packedArgs.truncate(0);
00722         QDataStream stream( m_packedArgs, IO_WriteOnly );
00723         stream << m_url;
00724 
00725         
00726         slaveDone();
00727         Scheduler::doJob(this);
00728     }
00729 }
00730 
00731 void StatJob::slotMetaData( const KIO::MetaData &_metaData) {
00732     SimpleJob::slotMetaData(_metaData);
00733     storeSSLSessionFromJob(m_redirectionURL);
00734 }
00735 
00736 StatJob *KIO::stat(const KURL& url, bool showProgressInfo)
00737 {
00738     
00739     return stat( url, true, 2, showProgressInfo );
00740 }
00741 
00742 StatJob *KIO::stat(const KURL& url, bool sideIsSource, short int details, bool showProgressInfo)
00743 {
00744     kdDebug(7007) << "stat " << url.prettyURL() << endl;
00745     KIO_ARGS << url;
00746     StatJob * job = new StatJob(url, CMD_STAT, packedArgs, showProgressInfo );
00747     job->setSide( sideIsSource );
00748     job->setDetails( details );
00749     if ( showProgressInfo )
00750       Observer::self()->stating( job, url );
00751     return job;
00752 }
00753 
00754 SimpleJob *KIO::http_update_cache( const KURL& url, bool no_cache, time_t expireDate)
00755 {
00756     assert( (url.protocol() == "http") || (url.protocol() == "https") );
00757     
00758     KIO_ARGS << (int)2 << url << no_cache << expireDate;
00759     SimpleJob * job = new SimpleJob( url, CMD_SPECIAL, packedArgs, false );
00760     Scheduler::scheduleJob(job);
00761     return job;
00762 }
00763 
00765 
00766 TransferJob::TransferJob( const KURL& url, int command,
00767                           const QByteArray &packedArgs,
00768                           const QByteArray &_staticData,
00769                           bool showProgressInfo)
00770     : SimpleJob(url, command, packedArgs, showProgressInfo), staticData( _staticData)
00771 {
00772     m_suspended = false;
00773     m_errorPage = false;
00774     m_subJob = 0L;
00775     if ( showProgressInfo )
00776         Observer::self()->slotTransferring( this, url );
00777 }
00778 
00779 
00780 void TransferJob::slotData( const QByteArray &_data)
00781 {
00782     if(m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error)
00783       emit data( this, _data);
00784 }
00785 
00786 
00787 void TransferJob::slotRedirection( const KURL &url)
00788 {
00789      kdDebug(7007) << "TransferJob::slotRedirection(" << url.prettyURL() << ")" << endl;
00790      if (!kapp->authorizeURLAction("redirect", m_url, url))
00791      {
00792        kdWarning(7007) << "TransferJob: Redirection from " << m_url.prettyURL() << " to " << url.prettyURL() << " REJECTED!" << endl;
00793        return;
00794      }
00795 
00796     
00797     
00798     
00799     if (m_redirectionList.contains(url) > 5)
00800     {
00801        kdDebug(7007) << "TransferJob::slotRedirection: CYCLIC REDIRECTION!" << endl;
00802        m_error = ERR_CYCLIC_LINK;
00803        m_errorText = m_url.prettyURL();
00804     }
00805     else
00806     {
00807        m_redirectionURL = url; 
00808        if (m_url.hasUser() && !url.hasUser() && (m_url.host().lower() == url.host().lower()))
00809           m_redirectionURL.setUser(m_url.user()); 
00810        m_redirectionList.append(url);
00811        m_outgoingMetaData["ssl_was_in_use"] = m_incomingMetaData["ssl_in_use"];
00812        
00813        emit redirection(this, m_redirectionURL);
00814     }
00815 }
00816 
00817 void TransferJob::slotFinished()
00818 {
00819    
00820     if (m_redirectionURL.isEmpty() || !m_redirectionURL.isValid())
00821         SimpleJob::slotFinished();
00822     else {
00823         
00824         if (queryMetaData("permanent-redirect")=="true")
00825             emit permanentRedirection(this, m_url, m_redirectionURL);
00826         
00827         
00828         
00829         
00830         staticData.truncate(0);
00831         m_incomingMetaData.clear();
00832         if (queryMetaData("cache") != "reload")
00833             addMetaData("cache","refresh");
00834         m_suspended = false;
00835         m_url = m_redirectionURL;
00836         m_redirectionURL = KURL();
00837         
00838         QString dummyStr;
00839         KURL dummyUrl;
00840         QDataStream istream( m_packedArgs, IO_ReadOnly );
00841         switch( m_command ) {
00842             case CMD_GET: {
00843                 m_packedArgs.truncate(0);
00844                 QDataStream stream( m_packedArgs, IO_WriteOnly );
00845                 stream << m_url;
00846                 break;
00847             }
00848             case CMD_PUT: {
00849                 int permissions;
00850                 Q_INT8 iOverwrite, iResume;
00851                 istream >> dummyUrl >> iOverwrite >> iResume >> permissions;
00852                 m_packedArgs.truncate(0);
00853                 QDataStream stream( m_packedArgs, IO_WriteOnly );
00854                 stream << m_url << iOverwrite << iResume << permissions;
00855                 break;
00856             }
00857             case CMD_SPECIAL: {
00858                 int specialcmd;
00859                 istream >> specialcmd;
00860                 if (specialcmd == 1) 
00861                 {
00862                    addMetaData("cache","reload");
00863                    m_packedArgs.truncate(0);
00864                    QDataStream stream( m_packedArgs, IO_WriteOnly );
00865                    stream << m_url;
00866                    m_command = CMD_GET;
00867                 }
00868                 break;
00869             }
00870         }
00871 
00872         
00873         slaveDone();
00874         Scheduler::doJob(this);
00875     }
00876 }
00877 
00878 void TransferJob::setAsyncDataEnabled(bool enabled)
00879 {
00880     if (enabled)
00881        extraFlags() |= EF_TransferJobAsync;
00882     else
00883        extraFlags() &= ~EF_TransferJobAsync;
00884 }
00885 
00886 void TransferJob::sendAsyncData(const QByteArray &dataForSlave)
00887 {
00888     if (extraFlags() & EF_TransferJobNeedData)
00889     {
00890        m_slave->send( MSG_DATA, dataForSlave );
00891        if (extraFlags() & EF_TransferJobDataSent)
00892        {
00893            KIO::filesize_t size = getProcessedSize()+dataForSlave.size();
00894            setProcessedSize(size);
00895            emit processedSize( this, size );
00896            if ( size > m_totalSize ) {
00897                slotTotalSize(size); 
00898            }
00899            emitPercent( size, m_totalSize );
00900        }
00901     }
00902 
00903     extraFlags() &= ~EF_TransferJobNeedData;
00904 }
00905 
00906 void TransferJob::setReportDataSent(bool enabled)
00907 {
00908     if (enabled)
00909        extraFlags() |= EF_TransferJobDataSent;
00910     else
00911        extraFlags() &= ~EF_TransferJobDataSent;
00912 }
00913 
00914 bool TransferJob::reportDataSent()
00915 {
00916     return (extraFlags() & EF_TransferJobDataSent);
00917 }
00918 
00919 
00920 
00921 void TransferJob::slotDataReq()
00922 {
00923     QByteArray dataForSlave;
00924 
00925     extraFlags() |= EF_TransferJobNeedData;
00926 
00927     if (!staticData.isEmpty())
00928     {
00929        dataForSlave = staticData;
00930        staticData = QByteArray();
00931     }
00932     else
00933     {
00934        emit dataReq( this, dataForSlave);
00935 
00936        if (extraFlags() & EF_TransferJobAsync)
00937           return;
00938     }
00939 
00940     static const size_t max_size = 14 * 1024 * 1024;
00941     if (dataForSlave.size() > max_size)
00942     {
00943        kdDebug(7007) << "send " << dataForSlave.size() / 1024 / 1024 << "MB of data in TransferJob::dataReq. This needs to be splitted, which requires a copy. Fix the application.\n";
00944        staticData.duplicate(dataForSlave.data() + max_size ,  dataForSlave.size() - max_size);
00945        dataForSlave.truncate(max_size);
00946     }
00947 
00948     sendAsyncData(dataForSlave);
00949 
00950     if (m_subJob)
00951     {
00952        
00953        suspend(); 
00954        m_subJob->resume(); 
00955     }
00956 }
00957 
00958 void TransferJob::slotMimetype( const QString& type )
00959 {
00960     m_mimetype = type;
00961     emit mimetype( this, m_mimetype);
00962 }
00963 
00964 
00965 void TransferJob::suspend()
00966 {
00967     m_suspended = true;
00968     if (m_slave)
00969        m_slave->suspend();
00970 }
00971 
00972 void TransferJob::resume()
00973 {
00974     m_suspended = false;
00975     if (m_slave)
00976        m_slave->resume();
00977 }
00978 
00979 void TransferJob::start(Slave *slave)
00980 {
00981     assert(slave);
00982     connect( slave, SIGNAL( data( const QByteArray & ) ),
00983              SLOT( slotData( const QByteArray & ) ) );
00984 
00985     connect( slave, SIGNAL( dataReq() ),
00986              SLOT( slotDataReq() ) );
00987 
00988     connect( slave, SIGNAL( redirection(const KURL &) ),
00989              SLOT( slotRedirection(const KURL &) ) );
00990 
00991     connect( slave, SIGNAL(mimeType( const QString& ) ),
00992              SLOT( slotMimetype( const QString& ) ) );
00993 
00994     connect( slave, SIGNAL(errorPage() ),
00995              SLOT( slotErrorPage() ) );
00996 
00997     connect( slave, SIGNAL( needSubURLData() ),
00998              SLOT( slotNeedSubURLData() ) );
00999 
01000     connect( slave, SIGNAL(canResume( KIO::filesize_t ) ),
01001              SLOT( slotCanResume( KIO::filesize_t ) ) );
01002 
01003     if (slave->suspended())
01004     {
01005        m_mimetype = "unknown";
01006        
01007        slave->resume();
01008     }
01009 
01010     SimpleJob::start(slave);
01011     if (m_suspended)
01012        slave->suspend();
01013 }
01014 
01015 void TransferJob::slotNeedSubURLData()
01016 {
01017     
01018     m_subJob = KIO::get( m_subUrl, false, false);
01019     suspend(); 
01020     connect(m_subJob, SIGNAL( data(KIO::Job*,const QByteArray &)),
01021             SLOT( slotSubURLData(KIO::Job*,const QByteArray &)));
01022     addSubjob(m_subJob);
01023 }
01024 
01025 void TransferJob::slotSubURLData(KIO::Job*, const QByteArray &data)
01026 {
01027     
01028     staticData = data;
01029     m_subJob->suspend(); 
01030     resume(); 
01031 }
01032 
01033 void TransferJob::slotMetaData( const KIO::MetaData &_metaData) {
01034     SimpleJob::slotMetaData(_metaData);
01035     storeSSLSessionFromJob(m_redirectionURL);
01036 }
01037 
01038 void TransferJob::slotErrorPage()
01039 {
01040     m_errorPage = true;
01041 }
01042 
01043 void TransferJob::slotCanResume( KIO::filesize_t offset )
01044 {
01045     emit canResume(this, offset);
01046 }
01047 
01048 void TransferJob::slotResult( KIO::Job *job)
01049 {
01050    
01051    assert(job == m_subJob);
01052    
01053    if ( job->error() )
01054    {
01055       m_error = job->error();
01056       m_errorText = job->errorText();
01057 
01058       emitResult();
01059       return;
01060    }
01061 
01062    if (job == m_subJob)
01063    {
01064       m_subJob = 0; 
01065       resume(); 
01066    }
01067    subjobs.remove(job); 
01068 }
01069 
01070 TransferJob *KIO::get( const KURL& url, bool reload, bool showProgressInfo )
01071 {
01072     
01073     KIO_ARGS << url;
01074     TransferJob * job = new TransferJob( url, CMD_GET, packedArgs, QByteArray(), showProgressInfo );
01075     if (reload)
01076        job->addMetaData("cache", "reload");
01077     return job;
01078 }
01079 
01080 class PostErrorJob : public TransferJob
01081 {
01082 public:
01083 
01084   PostErrorJob(const QString& url, const QByteArray &packedArgs, const QByteArray &postData, bool showProgressInfo)
01085       : TransferJob(KURL(), CMD_SPECIAL, packedArgs, postData, showProgressInfo)
01086   {
01087     m_error = KIO::ERR_POST_DENIED;
01088     m_errorText = url;
01089   }
01090 
01091 };
01092 
01093 TransferJob *KIO::http_post( const KURL& url, const QByteArray &postData, bool showProgressInfo )
01094 {
01095     bool valid = true;
01096 
01097     
01098     if ((url.protocol() != "http") && (url.protocol() != "https" ))
01099         valid = false;
01100 
01101     
01102     static const int bad_ports[] = {
01103         1,   
01104         7,   
01105         9,   
01106         11,   
01107         13,   
01108         15,   
01109         17,   
01110         19,   
01111         20,   
01112         21,   
01113         22,   
01114         23,   
01115         25,   
01116         37,   
01117         42,   
01118         43,   
01119         53,   
01120         77,   
01121         79,   
01122         87,   
01123         95,   
01124         101,  
01125         102,  
01126         103,  
01127         104,  
01128         109,  
01129         110,  
01130         111,  
01131         113,  
01132         115,  
01133         117,  
01134         119,  
01135         123,  
01136         135,  
01137         139,  
01138         143,  
01139         179,  
01140         389,  
01141         512,  
01142         513,  
01143         514,  
01144         515,  
01145         526,  
01146         530,  
01147         531,  
01148         532,  
01149         540,  
01150         556,  
01151         587,  
01152         601,  
01153         989,  
01154         990,  
01155         992,  
01156         993,  
01157         995,  
01158         1080, 
01159         2049, 
01160         4045, 
01161         6000, 
01162         6667, 
01163         0};
01164     for (int cnt=0; bad_ports[cnt]; ++cnt)
01165         if (url.port() == bad_ports[cnt])
01166         {
01167             valid = false;
01168             break;
01169         }
01170 
01171     if( !valid )
01172     {
01173     static bool override_loaded = false;
01174     static QValueList< int >* overriden_ports = NULL;
01175     if( !override_loaded )
01176     {
01177         KConfig cfg( "kio_httprc", true );
01178         overriden_ports = new QValueList< int >;
01179         *overriden_ports = cfg.readIntListEntry( "OverriddenPorts" );
01180         override_loaded = true;
01181     }
01182     for( QValueList< int >::ConstIterator it = overriden_ports->begin();
01183          it != overriden_ports->end();
01184          ++it )
01185         if( overriden_ports->contains( url.port()))
01186         valid = true;
01187     }
01188 
01189 
01190     
01191     if (!valid)
01192     {
01193         KIO_ARGS << (int)1 << url;
01194         TransferJob * job = new PostErrorJob(url.url(), packedArgs, postData, showProgressInfo);
01195         return job;
01196     }
01197 
01198     bool redirection = false;
01199     KURL _url(url);
01200     if (_url.path().isEmpty())
01201     {
01202       redirection = true;
01203       _url.setPath("/");
01204     }
01205 
01206     
01207     KIO_ARGS << (int)1 << _url;
01208     TransferJob * job = new TransferJob( _url, CMD_SPECIAL,
01209                                          packedArgs, postData, showProgressInfo );
01210 
01211     if (redirection)
01212       QTimer::singleShot(0, job, SLOT(slotPostRedirection()) );
01213 
01214     return job;
01215 }
01216 
01217 
01218 
01219 
01220 void TransferJob::slotPostRedirection()
01221 {
01222     kdDebug(7007) << "TransferJob::slotPostRedirection(" << m_url.prettyURL() << ")" << endl;
01223     
01224     emit redirection(this, m_url);
01225 }
01226 
01227 
01228 TransferJob *KIO::put( const KURL& url, int permissions,
01229                   bool overwrite, bool resume, bool showProgressInfo )
01230 {
01231     KIO_ARGS << url << Q_INT8( overwrite ? 1 : 0 ) << Q_INT8( resume ? 1 : 0 ) << permissions;
01232     TransferJob * job = new TransferJob( url, CMD_PUT, packedArgs, QByteArray(), showProgressInfo );
01233     return job;
01234 }
01235 
01237 
01238 MimetypeJob::MimetypeJob( const KURL& url, int command,
01239                   const QByteArray &packedArgs, bool showProgressInfo )
01240     : TransferJob(url, command, packedArgs, QByteArray(), showProgressInfo)
01241 {
01242 }
01243 
01244 void MimetypeJob::start(Slave *slave)
01245 {
01246     TransferJob::start(slave);
01247 }
01248 
01249 
01250 void MimetypeJob::slotFinished( )
01251 {
01252     
01253     if ( m_error == KIO::ERR_IS_DIRECTORY )
01254     {
01255         
01256         
01257         
01258         kdDebug(7007) << "It is in fact a directory!" << endl;
01259         m_mimetype = QString::fromLatin1("inode/directory");
01260         emit TransferJob::mimetype( this, m_mimetype );
01261         m_error = 0;
01262     }
01263     if ( m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error )
01264     {
01265         
01266         TransferJob::slotFinished();
01267     } else {
01268         
01269         if (queryMetaData("permanent-redirect")=="true")
01270             emit permanentRedirection(this, m_url, m_redirectionURL);
01271         staticData.truncate(0);
01272         m_suspended = false;
01273         m_url = m_redirectionURL;
01274         m_redirectionURL = KURL();
01275         m_packedArgs.truncate(0);
01276         QDataStream stream( m_packedArgs, IO_WriteOnly );
01277         stream << m_url;
01278 
01279         
01280         slaveDone();
01281         Scheduler::doJob(this);
01282     }
01283 }
01284 
01285 MimetypeJob *KIO::mimetype(const KURL& url, bool showProgressInfo )
01286 {
01287     KIO_ARGS << url;
01288     MimetypeJob * job = new MimetypeJob(url, CMD_MIMETYPE, packedArgs, showProgressInfo);
01289     if ( showProgressInfo )
01290       Observer::self()->stating( job, url );
01291     return job;
01292 }
01293 
01295 
01296 
01297 class FileCopyJob::FileCopyJobPrivate
01298 {
01299 public:
01300     KIO::filesize_t m_sourceSize;
01301     SimpleJob *m_delJob;
01302 };
01303 
01304 
01305 
01306 
01307 
01308 
01309 
01310 
01311 FileCopyJob::FileCopyJob( const KURL& src, const KURL& dest, int permissions,
01312                           bool move, bool overwrite, bool resume, bool showProgressInfo)
01313     : Job(showProgressInfo), m_src(src), m_dest(dest),
01314       m_permissions(permissions), m_move(move), m_overwrite(overwrite), m_resume(resume),
01315       m_totalSize(0)
01316 {
01317    if (showProgressInfo && !move)
01318       Observer::self()->slotCopying( this, src, dest );
01319    else if (showProgressInfo && move)
01320       Observer::self()->slotMoving( this, src, dest );
01321 
01322     
01323     m_moveJob = 0;
01324     m_copyJob = 0;
01325     m_getJob = 0;
01326     m_putJob = 0;
01327     d = new FileCopyJobPrivate;
01328     d->m_delJob = 0;
01329     d->m_sourceSize = (KIO::filesize_t) -1;
01330     QTimer::singleShot(0, this, SLOT(slotStart()));
01331 }
01332 
01333 void FileCopyJob::slotStart()
01334 {
01335     if ((m_src.protocol() == m_dest.protocol()) &&
01336         (m_src.host() == m_dest.host()) &&
01337         (m_src.port() == m_dest.port()) &&
01338         (m_src.user() == m_dest.user()) &&
01339         (m_src.pass() == m_dest.pass()) &&
01340         !m_src.hasSubURL() && !m_dest.hasSubURL())
01341     {
01342        if (m_move)
01343        {
01344           m_moveJob = KIO::rename( m_src, m_dest, m_overwrite );
01345           addSubjob( m_moveJob );
01346           connectSubjob( m_moveJob );
01347        }
01348        else
01349        {
01350           startCopyJob();
01351        }
01352     }
01353     else
01354     {
01355        if (!m_move &&
01356            (m_src.isLocalFile() && KProtocolInfo::canCopyFromFile(m_dest))
01357           )
01358        {
01359           startCopyJob(m_dest);
01360        }
01361        else if (!m_move &&
01362            (m_dest.isLocalFile() && KProtocolInfo::canCopyToFile(m_src))
01363           )
01364        {
01365           startCopyJob(m_src);
01366        }
01367        else
01368        {
01369           startDataPump();
01370        }
01371     }
01372 }
01373 
01374 FileCopyJob::~FileCopyJob()
01375 {
01376     delete d;
01377 }
01378 
01379 void FileCopyJob::setSourceSize( off_t size )
01380 {
01381     d->m_sourceSize = size;
01382     m_totalSize = size;
01383 }
01384 
01385 void FileCopyJob::setSourceSize64( KIO::filesize_t size )
01386 {
01387     d->m_sourceSize = size;
01388     m_totalSize = size;
01389 }
01390 
01391 void FileCopyJob::startCopyJob()
01392 {
01393     startCopyJob(m_src);
01394 }
01395 
01396 void FileCopyJob::startCopyJob(const KURL &slave_url)
01397 {
01398     
01399     KIO_ARGS << m_src << m_dest << m_permissions << (Q_INT8) m_overwrite;
01400     m_copyJob = new SimpleJob(slave_url, CMD_COPY, packedArgs, false);
01401     addSubjob( m_copyJob );
01402     connectSubjob( m_copyJob );
01403 }
01404 
01405 void FileCopyJob::connectSubjob( SimpleJob * job )
01406 {
01407     connect( job, SIGNAL(totalSize( KIO::Job*, KIO::filesize_t )),
01408              this, SLOT( slotTotalSize(KIO::Job*, KIO::filesize_t)) );
01409 
01410     connect( job, SIGNAL(processedSize( KIO::Job*, KIO::filesize_t )),
01411              this, SLOT( slotProcessedSize(KIO::Job*, KIO::filesize_t)) );
01412 
01413     connect( job, SIGNAL(percent( KIO::Job*, unsigned long )),
01414              this, SLOT( slotPercent(KIO::Job*, unsigned long)) );
01415 
01416 }
01417 
01418 void FileCopyJob::slotProcessedSize( KIO::Job *, KIO::filesize_t size )
01419 {
01420     setProcessedSize(size);
01421     emit processedSize( this, size );
01422     if ( size > m_totalSize ) {
01423         slotTotalSize( this, size ); 
01424     }
01425     emitPercent( size, m_totalSize );
01426 }
01427 
01428 void FileCopyJob::slotTotalSize( KIO::Job*, KIO::filesize_t size )
01429 {
01430     m_totalSize = size;
01431     emit totalSize( this, m_totalSize );
01432 }
01433 
01434 void FileCopyJob::slotPercent( KIO::Job*, unsigned long pct )
01435 {
01436     if ( pct > m_percent )
01437     {
01438         m_percent = pct;
01439         emit percent( this, m_percent );
01440     }
01441 }
01442 
01443 void FileCopyJob::startDataPump()
01444 {
01445     
01446 
01447     m_canResume = false;
01448     m_resumeAnswerSent = false;
01449     m_getJob = 0L; 
01450     m_putJob = put( m_dest, m_permissions, m_overwrite, m_resume, false );
01451     
01452 
01453     
01454     
01455     connect( m_putJob, SIGNAL(canResume(KIO::Job *, KIO::filesize_t)),
01456              SLOT( slotCanResume(KIO::Job *, KIO::filesize_t)));
01457     connect( m_putJob, SIGNAL(dataReq(KIO::Job *, QByteArray&)),
01458              SLOT( slotDataReq(KIO::Job *, QByteArray&)));
01459     addSubjob( m_putJob );
01460 }
01461 
01462 void FileCopyJob::slotCanResume( KIO::Job* job, KIO::filesize_t offset )
01463 {
01464     if ( job == m_putJob )
01465     {
01466         
01467         if (offset)
01468         {
01469             RenameDlg_Result res = R_RESUME;
01470 
01471             if (!KProtocolManager::autoResume())
01472             {
01473                 QString newPath;
01474                 KIO::Job* job = ( !m_progressId && parentJob() ) ? parentJob() : this;
01475                 
01476                 res = Observer::self()->open_RenameDlg(
01477                       job, i18n("File Already Exists"),
01478                       m_src.prettyURL(0, KURL::StripFileProtocol),
01479                       m_dest.prettyURL(0, KURL::StripFileProtocol),
01480                       (RenameDlg_Mode) (M_OVERWRITE | M_RESUME | M_NORENAME), newPath,
01481                       d->m_sourceSize, offset );
01482             }
01483 
01484             if ( res == R_OVERWRITE )
01485               offset = 0;
01486             else if ( res == R_CANCEL )
01487             {
01488                 m_putJob->kill(true);
01489                 m_error = ERR_USER_CANCELED;
01490                 emitResult();
01491                 return;
01492             }
01493         }
01494         else
01495             m_resumeAnswerSent = true; 
01496 
01497         m_getJob = get( m_src, false, false  );
01498         
01499         m_getJob->addMetaData( "errorPage", "false" );
01500         m_getJob->addMetaData( "AllowCompressedPage", "false" );
01501         
01502         if ( d->m_sourceSize != (KIO::filesize_t)-1 )
01503             m_getJob->slotTotalSize( d->m_sourceSize );
01504         if (offset)
01505         {
01506             
01507             m_getJob->addMetaData( "resume", KIO::number(offset) );
01508 
01509             
01510             connect( m_getJob, SIGNAL(canResume(KIO::Job *, KIO::filesize_t)),
01511                      SLOT( slotCanResume(KIO::Job *, KIO::filesize_t)));
01512         }
01513         m_putJob->slave()->setOffset( offset );
01514 
01515         m_putJob->suspend();
01516         addSubjob( m_getJob );
01517         connectSubjob( m_getJob ); 
01518         m_getJob->resume(); 
01519 
01520         connect( m_getJob, SIGNAL(data(KIO::Job *, const QByteArray&)),
01521                  SLOT( slotData(KIO::Job *, const QByteArray&)));
01522     }
01523     else if ( job == m_getJob )
01524     {
01525         
01526         m_canResume = true;
01527         
01528 
01529         m_getJob->slave()->setOffset( m_putJob->slave()->offset() );
01530     }
01531     else
01532         kdWarning(7007) << "FileCopyJob::slotCanResume from unknown job=" << job
01533                         << " m_getJob=" << m_getJob << " m_putJob=" << m_putJob << endl;
01534 }
01535 
01536 void FileCopyJob::slotData( KIO::Job * , const QByteArray &data)
01537 {
01538    
01539    
01540    assert(m_putJob);
01541    m_getJob->suspend();
01542    m_putJob->resume(); 
01543    m_buffer = data;
01544 
01545    
01546    
01547    if (!m_resumeAnswerSent)
01548    {
01549        m_resumeAnswerSent = true;
01550        
01551        m_putJob->slave()->sendResumeAnswer( m_canResume );
01552    }
01553 }
01554 
01555 void FileCopyJob::slotDataReq( KIO::Job * , QByteArray &data)
01556 {
01557    
01558    if (!m_resumeAnswerSent && !m_getJob)
01559    {
01560        
01561        m_error = ERR_INTERNAL;
01562        m_errorText = "'Put' job didn't send canResume or 'Get' job didn't send data!";
01563        m_putJob->kill(true);
01564        emitResult();
01565        return;
01566    }
01567    if (m_getJob)
01568    {
01569       m_getJob->resume(); 
01570       m_putJob->suspend();
01571    }
01572    data = m_buffer;
01573    m_buffer = QByteArray();
01574 }
01575 
01576 void FileCopyJob::slotResult( KIO::Job *job)
01577 {
01578    
01579    
01580    if ( job->error() )
01581    {
01582       if ((job == m_moveJob) && (job->error() == ERR_UNSUPPORTED_ACTION))
01583       {
01584          m_moveJob = 0;
01585          startCopyJob();
01586          removeSubjob(job);
01587          return;
01588       }
01589       else if ((job == m_copyJob) && (job->error() == ERR_UNSUPPORTED_ACTION))
01590       {
01591          m_copyJob = 0;
01592          startDataPump();
01593          removeSubjob(job);
01594          return;
01595       }
01596       else if (job == m_getJob)
01597       {
01598         m_getJob = 0L;
01599         if (m_putJob)
01600           m_putJob->kill(true);
01601       }
01602       else if (job == m_putJob)
01603       {
01604         m_putJob = 0L;
01605         if (m_getJob)
01606           m_getJob->kill(true);
01607       }
01608       m_error = job->error();
01609       m_errorText = job->errorText();
01610       emitResult();
01611       return;
01612    }
01613 
01614    if (job == m_moveJob)
01615    {
01616       m_moveJob = 0; 
01617    }
01618 
01619    if (job == m_copyJob)
01620    {
01621       m_copyJob = 0;
01622       if (m_move)
01623       {
01624          d->m_delJob = file_delete( m_src, false ); 
01625          addSubjob(d->m_delJob);
01626       }
01627    }
01628 
01629    if (job == m_getJob)
01630    {
01631       m_getJob = 0; 
01632       if (m_putJob)
01633          m_putJob->resume();
01634    }
01635 
01636    if (job == m_putJob)
01637    {
01638       
01639       m_putJob = 0;
01640       if (m_getJob)
01641       {
01642          kdWarning(7007) << "WARNING ! Get still going on..." << endl;
01643          m_getJob->resume();
01644       }
01645       if (m_move)
01646       {
01647          d->m_delJob = file_delete( m_src, false ); 
01648          addSubjob(d->m_delJob);
01649       }
01650    }
01651 
01652    if (job == d->m_delJob)
01653    {
01654       d->m_delJob = 0; 
01655    }
01656    removeSubjob(job);
01657 }
01658 
01659 FileCopyJob *KIO::file_copy( const KURL& src, const KURL& dest, int permissions,
01660                              bool overwrite, bool resume, bool showProgressInfo)
01661 {
01662    return new FileCopyJob( src, dest, permissions, false, overwrite, resume, showProgressInfo );
01663 }
01664 
01665 FileCopyJob *KIO::file_move( const KURL& src, const KURL& dest, int permissions,
01666                              bool overwrite, bool resume, bool showProgressInfo)
01667 {
01668    return new FileCopyJob( src, dest, permissions, true, overwrite, resume, showProgressInfo );
01669 }
01670 
01671 SimpleJob *KIO::file_delete( const KURL& src, bool showProgressInfo)
01672 {
01673     KIO_ARGS << src << Q_INT8(true); 
01674     return new SimpleJob(src, CMD_DEL, packedArgs, showProgressInfo );
01675 }
01676 
01678 
01679 
01680 ListJob::ListJob(const KURL& u, bool showProgressInfo, bool _recursive, QString _prefix, bool _includeHidden) :
01681     SimpleJob(u, CMD_LISTDIR, QByteArray(), showProgressInfo),
01682     recursive(_recursive), includeHidden(_includeHidden), prefix(_prefix), m_processedEntries(0)
01683 {
01684     
01685     
01686     QDataStream stream( m_packedArgs, IO_WriteOnly );
01687     stream << u;
01688 }
01689 
01690 void ListJob::slotListEntries( const KIO::UDSEntryList& list )
01691 {
01692     
01693     m_processedEntries += list.count();
01694     slotProcessedSize( m_processedEntries );
01695 
01696     if (recursive) {
01697         UDSEntryListConstIterator it = list.begin();
01698         UDSEntryListConstIterator end = list.end();
01699 
01700         for (; it != end; ++it) {
01701             bool isDir = false;
01702             bool isLink = false;
01703             QString filename;
01704 
01705             UDSEntry::ConstIterator it2 = (*it).begin();
01706             UDSEntry::ConstIterator end2 = (*it).end();
01707             for( ; it2 != end2; it2++ ) {
01708                 switch( (*it2).m_uds ) {
01709                     case UDS_FILE_TYPE:
01710                         isDir = S_ISDIR((*it2).m_long);
01711                         break;
01712                     case UDS_NAME:
01713                         filename = (*it2).m_str;
01714                         break;
01715                     case UDS_LINK_DEST:
01716                         
01717                         isLink = !(*it2).m_str.isEmpty();
01718                         break;
01719                     default:
01720                         break;
01721                 }
01722             }
01723             if (isDir && !isLink) {
01724                 
01725                 if (filename != ".." && filename != "." && (includeHidden || filename[0] != '.')) {
01726                     KURL newone = url();
01727                     newone.addPath(filename);
01728                     ListJob *job = new ListJob(newone,
01729                                                false ,
01730                                                true ,
01731                                                prefix + filename + "/",
01732                                                includeHidden);
01733                     Scheduler::scheduleJob(job);
01734                     connect(job, SIGNAL(entries( KIO::Job *,
01735                                                  const KIO::UDSEntryList& )),
01736                             SLOT( gotEntries( KIO::Job*,
01737                                               const KIO::UDSEntryList& )));
01738                     addSubjob(job);
01739                 }
01740             }
01741         }
01742     }
01743 
01744     
01745     
01746     
01747     if (prefix.isNull() && includeHidden) {
01748         emit entries(this, list);
01749     } else {
01750         
01751         UDSEntryList newlist;
01752 
01753         UDSEntryListConstIterator it = list.begin();
01754         UDSEntryListConstIterator end = list.end();
01755         for (; it != end; ++it) {
01756 
01757             UDSEntry newone = *it;
01758             UDSEntry::Iterator it2 = newone.begin();
01759             QString filename;
01760             for( ; it2 != newone.end(); it2++ ) {
01761                 if ((*it2).m_uds == UDS_NAME) {
01762                     filename = (*it2).m_str;
01763                     (*it2).m_str = prefix + filename;
01764                 }
01765             }
01766             
01767             
01768             if (  (prefix.isNull() || (filename != ".." && filename != ".") )
01769                && (includeHidden || (filename[0] != '.') )  )
01770                 newlist.append(newone);
01771         }
01772 
01773         emit entries(this, newlist);
01774     }
01775 }
01776 
01777 void ListJob::gotEntries(KIO::Job *, const KIO::UDSEntryList& list )
01778 {
01779     
01780     emit entries(this, list);
01781 }
01782 
01783 void ListJob::slotResult( KIO::Job * job )
01784 {
01785     
01786     
01787     removeSubjob( job );
01788 }
01789 
01790 void ListJob::slotRedirection( const KURL & url )
01791 {
01792      if (!kapp->authorizeURLAction("redirect", m_url, url))
01793      {
01794        kdWarning(7007) << "ListJob: Redirection from " << m_url.prettyURL() << " to " << url.prettyURL() << " REJECTED!" << endl;
01795        return;
01796      }
01797     m_redirectionURL = url; 
01798     if (m_url.hasUser() && !url.hasUser() && (m_url.host().lower() == url.host().lower()))
01799         m_redirectionURL.setUser(m_url.user()); 
01800     emit redirection( this, url );
01801 }
01802 
01803 void ListJob::slotFinished()
01804 {
01805     if ( m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error )
01806     {
01807         
01808         SimpleJob::slotFinished();
01809     } else {
01810         
01811         if (queryMetaData("permanent-redirect")=="true")
01812             emit permanentRedirection(this, m_url, m_redirectionURL);
01813         m_url = m_redirectionURL;
01814         m_redirectionURL = KURL();
01815         m_packedArgs.truncate(0);
01816         QDataStream stream( m_packedArgs, IO_WriteOnly );
01817         stream << m_url;
01818 
01819         
01820         slaveDone();
01821         Scheduler::doJob(this);
01822     }
01823 }
01824 
01825 void ListJob::slotMetaData( const KIO::MetaData &_metaData) {
01826     SimpleJob::slotMetaData(_metaData);
01827     storeSSLSessionFromJob(m_redirectionURL);
01828 }
01829 
01830 ListJob *KIO::listDir( const KURL& url, bool showProgressInfo, bool includeHidden )
01831 {
01832     ListJob * job = new ListJob(url, showProgressInfo,false,QString::null,includeHidden);
01833     return job;
01834 }
01835 
01836 ListJob *KIO::listRecursive( const KURL& url, bool showProgressInfo, bool includeHidden )
01837 {
01838     ListJob * job = new ListJob(url, showProgressInfo, true,QString::null,includeHidden);
01839     return job;
01840 }
01841 
01842 void ListJob::setUnrestricted(bool unrestricted)
01843 {
01844     if (unrestricted)
01845        extraFlags() |= EF_ListJobUnrestricted;
01846     else
01847        extraFlags() &= ~EF_ListJobUnrestricted;
01848 }
01849 
01850 void ListJob::start(Slave *slave)
01851 {
01852     if (!kapp->authorizeURLAction("list", m_url, m_url) && !(extraFlags() & EF_ListJobUnrestricted))
01853     {
01854         m_error = ERR_ACCESS_DENIED;
01855         m_errorText = m_url.url();
01856         QTimer::singleShot(0, this, SLOT(slotFinished()) );
01857         return;
01858     }
01859     connect( slave, SIGNAL( listEntries( const KIO::UDSEntryList& )),
01860              SLOT( slotListEntries( const KIO::UDSEntryList& )));
01861     connect( slave, SIGNAL( totalSize( KIO::filesize_t ) ),
01862              SLOT( slotTotalSize( KIO::filesize_t ) ) );
01863     connect( slave, SIGNAL( redirection(const KURL &) ),
01864              SLOT( slotRedirection(const KURL &) ) );
01865 
01866     SimpleJob::start(slave);
01867 }
01868 
01869 
01870 CopyJob::CopyJob( const KURL::List& src, const KURL& dest, CopyMode mode, bool asMethod, bool showProgressInfo )
01871   : Job(showProgressInfo), m_mode(mode), m_asMethod(asMethod),
01872     destinationState(DEST_NOT_STATED), state(STATE_STATING),
01873     m_totalSize(0), m_processedSize(0), m_fileProcessedSize(0),
01874     m_processedFiles(0), m_processedDirs(0),
01875     m_srcList(src), m_currentStatSrc(m_srcList.begin()),
01876     m_bCurrentOperationIsLink(false), m_bSingleFileCopy(false), m_bOnlyRenames(mode==Move),
01877     m_dest(dest), m_bAutoSkip( false ), m_bOverwriteAll( false ),
01878     m_conflictError(0), m_reportTimer(0)
01879 {
01880     if ( showProgressInfo ) {
01881         connect( this, SIGNAL( totalFiles( KIO::Job*, unsigned long ) ),
01882                  Observer::self(), SLOT( slotTotalFiles( KIO::Job*, unsigned long ) ) );
01883 
01884         connect( this, SIGNAL( totalDirs( KIO::Job*, unsigned long ) ),
01885                  Observer::self(), SLOT( slotTotalDirs( KIO::Job*, unsigned long ) ) );
01886     }
01887     QTimer::singleShot(0, this, SLOT(slotStart()));
01888 }
01889 
01890 void CopyJob::slotStart()
01891 {
01897     m_reportTimer = new QTimer(this);
01898 
01899     connect(m_reportTimer,SIGNAL(timeout()),this,SLOT(slotReport()));
01900     m_reportTimer->start(REPORT_TIMEOUT,false);
01901 
01902     
01903     KIO::Job * job = KIO::stat( m_dest, false, 2, false );
01904     
01905     addSubjob(job);
01906 }
01907 
01908 void CopyJob::slotResultStating( Job *job )
01909 {
01910     
01911     
01912     if (job->error() && destinationState != DEST_NOT_STATED )
01913     {
01914         KURL srcurl = ((SimpleJob*)job)->url();
01915         if ( !srcurl.isLocalFile() )
01916         {
01917             
01918             
01919             
01920             kdDebug(7007) << "Error while stating source. Activating hack" << endl;
01921             subjobs.remove( job );
01922             assert ( subjobs.isEmpty() ); 
01923             struct CopyInfo info;
01924             info.permissions = (mode_t) -1;
01925             info.mtime = (time_t) -1;
01926             info.ctime = (time_t) -1;
01927             info.size = (KIO::filesize_t)-1;
01928             info.uSource = srcurl;
01929             info.uDest = m_dest;
01930             
01931             if ( destinationState == DEST_IS_DIR && !m_asMethod )
01932                 info.uDest.addPath( srcurl.fileName() );
01933 
01934             files.append( info );
01935             ++m_currentStatSrc;
01936             statNextSrc();
01937             return;
01938         }
01939         
01940         Job::slotResult( job ); 
01941         return;
01942     }
01943 
01944     
01945     UDSEntry entry = ((StatJob*)job)->statResult();
01946     bool bDir = false;
01947     bool bLink = false;
01948     UDSEntry::ConstIterator it2 = entry.begin();
01949     for( ; it2 != entry.end(); it2++ ) {
01950         if ( ((*it2).m_uds) == UDS_FILE_TYPE )
01951             bDir = S_ISDIR( (mode_t)(*it2).m_long );
01952         else if ( ((*it2).m_uds) == UDS_LINK_DEST )
01953             bLink = !((*it2).m_str.isEmpty());
01954     }
01955 
01956     if ( destinationState == DEST_NOT_STATED )
01957         
01958     {
01959         if (job->error())
01960             destinationState = DEST_DOESNT_EXIST;
01961         else {
01962             
01963             destinationState = bDir ? DEST_IS_DIR : DEST_IS_FILE;
01964             
01965         }
01966         subjobs.remove( job );
01967         assert ( subjobs.isEmpty() );
01968 
01969         
01970         statNextSrc();
01971         return;
01972     }
01973     
01974     m_currentDest = m_dest; 
01975     
01976     UDSEntryList lst;
01977     lst.append(entry);
01978 
01979     
01980     
01981     
01982     
01983     
01984     
01985 
01986     
01987     
01988     
01989     
01990     
01991     m_bCurrentSrcIsDir = false;
01992     slotEntries(job, lst);
01993 
01994     KURL srcurl = ((SimpleJob*)job)->url();
01995 
01996     subjobs.remove( job );
01997     assert ( subjobs.isEmpty() ); 
01998 
01999     if ( bDir
02000          && !bLink 
02001          && m_mode != Link ) 
02002     {
02003         
02004 
02005         m_bCurrentSrcIsDir = true; 
02006         if ( destinationState == DEST_IS_DIR ) 
02007         {
02008             if ( !m_asMethod )
02009                 
02010                 m_currentDest.addPath( srcurl.fileName() );
02011         }
02012         else if ( destinationState == DEST_IS_FILE ) 
02013         {
02014             m_error = ERR_IS_FILE;
02015             m_errorText = m_dest.prettyURL();
02016             emitResult();
02017             return;
02018         }
02019         else 
02020         {
02021             
02022             
02023             
02024             
02025             destinationState = DEST_IS_DIR;
02026         }
02027 
02028         startListing( srcurl );
02029     }
02030     else
02031     {
02032         
02033         ++m_currentStatSrc;
02034         statNextSrc();
02035     }
02036 }
02037 
02038 void CopyJob::slotReport()
02039 {
02040     
02041     Observer * observer = m_progressId ? Observer::self() : 0L;
02042     switch (state) {
02043         case STATE_COPYING_FILES:
02044             emit processedFiles( this, m_processedFiles );
02045             if (observer) observer->slotProcessedFiles(this,m_processedFiles);
02046             if (m_mode==Move)
02047             {
02048                 if (observer) observer->slotMoving( this, m_currentSrcURL,m_currentDestURL);
02049                 emit moving( this, m_currentSrcURL, m_currentDestURL);
02050             }
02051             else if (m_mode==Link)
02052             {
02053                 if (observer) observer->slotCopying( this, m_currentSrcURL, m_currentDestURL ); 
02054                 emit linking( this, m_currentSrcURL.path(), m_currentDestURL );
02055             }
02056             else
02057             {
02058                 if (observer) observer->slotCopying( this, m_currentSrcURL, m_currentDestURL );
02059                 emit copying( this, m_currentSrcURL, m_currentDestURL );
02060             };
02061             break;
02062 
02063         case STATE_CREATING_DIRS:
02064             if (observer) {
02065                 observer->slotProcessedDirs( this, m_processedDirs );
02066                 observer->slotCreatingDir( this,m_currentDestURL);
02067             }
02068             emit processedDirs( this, m_processedDirs );
02069             emit creatingDir( this, m_currentDestURL );
02070             break;
02071 
02072         case STATE_STATING:
02073         case STATE_LISTING:
02074             if (observer) observer->slotCopying( this, m_currentSrcURL, m_currentDestURL );
02075             emit totalSize( this, m_totalSize );
02076             emit totalFiles( this, files.count() );
02077             emit totalDirs( this, dirs.count() );
02078             if (!dirs.isEmpty())
02079                emit aboutToCreate( this, dirs );
02080             if (!files.isEmpty())
02081                emit aboutToCreate( this, files );
02082             break;
02083 
02084         default:
02085             break;
02086     }
02087 }
02088 
02089 void CopyJob::slotEntries(KIO::Job* job, const UDSEntryList& list)
02090 {
02091     UDSEntryListConstIterator it = list.begin();
02092     UDSEntryListConstIterator end = list.end();
02093     for (; it != end; ++it) {
02094         UDSEntry::ConstIterator it2 = (*it).begin();
02095         struct CopyInfo info;
02096         info.permissions = -1;
02097         info.mtime = (time_t) -1;
02098         info.ctime = (time_t) -1;
02099         info.size = (KIO::filesize_t)-1;
02100         QString relName;
02101         bool isDir = false;
02102         for( ; it2 != (*it).end(); it2++ ) {
02103             switch ((*it2).m_uds) {
02104                 case UDS_FILE_TYPE:
02105                     
02106                     isDir = S_ISDIR( (mode_t)((*it2).m_long) );
02107                     break;
02108                 case UDS_NAME:
02109                     relName = (*it2).m_str;
02110                     break;
02111                 case UDS_LINK_DEST:
02112                     info.linkDest = (*it2).m_str;
02113                     break;
02114                 case UDS_ACCESS:
02115                     info.permissions = ((*it2).m_long);
02116                     break;
02117                 case UDS_SIZE:
02118                     info.size = (KIO::filesize_t)((*it2).m_long);
02119                     m_totalSize += info.size;
02120                     break;
02121                 case UDS_MODIFICATION_TIME:
02122                     info.mtime = (time_t)((*it2).m_long);
02123                     break;
02124                 case UDS_CREATION_TIME:
02125                     info.ctime = (time_t)((*it2).m_long);
02126                 default:
02127                     break;
02128             }
02129         }
02130         if (relName != ".." && relName != ".")
02131         {
02132             
02133             info.uSource = ((SimpleJob *)job)->url();
02134             if ( m_bCurrentSrcIsDir ) 
02135                 info.uSource.addPath( relName );
02136             info.uDest = m_currentDest;
02137             
02138             
02139             if ( destinationState == DEST_IS_DIR &&
02140                  
02141                  
02142                  ( ! ( m_asMethod && state == STATE_STATING ) ) )
02143             {
02144                 
02145                 
02146                 
02147                 if ( relName.isEmpty() )
02148                     info.uDest.addPath( KIO::encodeFileName( info.uSource.prettyURL() ) );
02149                 else
02150                     info.uDest.addPath( relName );
02151             }
02152             
02153             
02154             if ( info.linkDest.isEmpty() && (isDir ) && m_mode != Link ) 
02155             {
02156                 dirs.append( info ); 
02157                 if (m_mode == Move)
02158                     dirsToRemove.append( info.uSource );
02159             }
02160             else {
02161                 files.append( info ); 
02162             }
02163         }
02164     }
02165 }
02166 
02167 void CopyJob::statNextSrc()
02168 {
02169     if ( m_currentStatSrc != m_srcList.end() )
02170     {
02171         m_currentSrcURL = (*m_currentStatSrc);
02172         if ( m_mode == Link )
02173         {
02174             
02175             m_currentDest = m_dest;
02176             struct CopyInfo info;
02177             info.permissions = -1;
02178             info.mtime = (time_t) -1;
02179             info.ctime = (time_t) -1;
02180             info.size = (KIO::filesize_t)-1;
02181             info.uSource = m_currentSrcURL;
02182             info.uDest = m_currentDest;
02183             
02184             if ( destinationState == DEST_IS_DIR && !m_asMethod )
02185             {
02186                 if (
02187                     (m_currentSrcURL.protocol() == info.uDest.protocol()) &&
02188                     (m_currentSrcURL.host() == info.uDest.host()) &&
02189                     (m_currentSrcURL.port() == info.uDest.port()) &&
02190                     (m_currentSrcURL.user() == info.uDest.user()) &&
02191                     (m_currentSrcURL.pass() == info.uDest.pass()) )
02192                 {
02193                     
02194                     info.uDest.addPath( m_currentSrcURL.fileName() );
02195                 }
02196                 else
02197                 {
02198                     
02199                     
02200                     
02201                     info.uDest.addPath( KIO::encodeFileName( m_currentSrcURL.prettyURL() )+".desktop" );
02202                 }
02203             }
02204             files.append( info ); 
02205             ++m_currentStatSrc;
02206             statNextSrc(); 
02207         }
02208         
02209         else if ( m_mode == Move &&
02210                   (m_currentSrcURL.protocol() == m_dest.protocol()) &&
02211                   (m_currentSrcURL.host() == m_dest.host()) &&
02212                   (m_currentSrcURL.port() == m_dest.port()) &&
02213                   (m_currentSrcURL.user() == m_dest.user()) &&
02214                   (m_currentSrcURL.pass() == m_dest.pass()) )
02215         {
02216             KURL dest = m_dest;
02217             
02218             if ( destinationState == DEST_IS_DIR && !m_asMethod )
02219                 dest.addPath( m_currentSrcURL.fileName() );
02220             kdDebug(7007) << "This seems to be a suitable case for trying to rename before stat+[list+]copy+del" << endl;
02221             state = STATE_RENAMING;
02222 
02223             struct CopyInfo info;
02224             info.permissions = -1;
02225             info.mtime = (time_t) -1;
02226             info.ctime = (time_t) -1;
02227             info.size = (KIO::filesize_t)-1;
02228             info.uSource = m_currentSrcURL;
02229             info.uDest = dest;
02230             QValueList<CopyInfo> files;
02231             files.append(info);
02232             emit aboutToCreate( this, files );
02233 
02234             SimpleJob * newJob = KIO::rename( m_currentSrcURL, dest, false );
02235             Scheduler::scheduleJob(newJob);
02236             addSubjob( newJob );
02237             if ( m_currentSrcURL.directory() != dest.directory() ) 
02238                 m_bOnlyRenames = false;
02239         }
02240         else
02241         {
02242             
02243             if (m_mode == Move && !KProtocolInfo::supportsDeleting(m_currentSrcURL)) {
02244                 KMessageBox::information( 0, buildErrorString(ERR_CANNOT_DELETE, m_currentSrcURL.prettyURL()));
02245         ++m_currentStatSrc;
02246                 statNextSrc(); 
02247                 return;
02248             }
02249             
02250             Job * job = KIO::stat( m_currentSrcURL, true, 2, false );
02251             
02252             state = STATE_STATING;
02253             addSubjob(job);
02254             m_currentDestURL=m_dest;
02255             m_bOnlyRenames = false;
02256         }
02257     } else
02258     {
02259         
02260         
02261         state = STATE_STATING;
02262         slotReport();
02263         
02264         m_bSingleFileCopy = ( files.count() == 1 && dirs.isEmpty() );
02265         
02266         state = STATE_CREATING_DIRS;
02267         createNextDir();
02268     }
02269 }
02270 
02271 
02272 void CopyJob::startListing( const KURL & src )
02273 {
02274     state = STATE_LISTING;
02275     ListJob * newjob = listRecursive( src, false );
02276     newjob->setUnrestricted(true);
02277     connect(newjob, SIGNAL(entries( KIO::Job *,
02278                                     const KIO::UDSEntryList& )),
02279             SLOT( slotEntries( KIO::Job*,
02280                                const KIO::UDSEntryList& )));
02281     addSubjob( newjob );
02282 }
02283 
02284 void CopyJob::skip( const KURL & sourceUrl )
02285 {
02286     
02287     
02288     
02289     KURL::List::Iterator sit = m_srcList.find( sourceUrl );
02290     if ( sit != m_srcList.end() )
02291     {
02292         
02293         m_srcList.remove( sit );
02294     }
02295     dirsToRemove.remove( sourceUrl );
02296 }
02297 
02298 void CopyJob::slotResultCreatingDirs( Job * job )
02299 {
02300     
02301     QValueList<CopyInfo>::Iterator it = dirs.begin();
02302     
02303     if ( job->error() )
02304     {
02305         m_conflictError = job->error();
02306         if ( (m_conflictError == ERR_DIR_ALREADY_EXIST)
02307              || (m_conflictError == ERR_FILE_ALREADY_EXIST) )
02308         {
02309             KURL oldURL = ((SimpleJob*)job)->url();
02310             
02311             if ( m_bAutoSkip ) {
02312                 
02313                 m_skipList.append( oldURL.path( 1 ) );
02314                 skip( oldURL );
02315                 dirs.remove( it ); 
02316             } else if ( m_bOverwriteAll ) { 
02317                 emit copyingDone( this, ( *it ).uSource, ( *it ).uDest, true , false  );
02318                 dirs.remove( it ); 
02319             } else
02320             {
02321                 assert( ((SimpleJob*)job)->url().url() == (*it).uDest.url() );
02322                 subjobs.remove( job );
02323                 assert ( subjobs.isEmpty() ); 
02324 
02325                 
02326                 KURL existingDest( (*it).uDest );
02327                 SimpleJob * newJob = KIO::stat( existingDest, false, 2, false );
02328                 Scheduler::scheduleJob(newJob);
02329                 kdDebug(7007) << "KIO::stat for resolving conflict on " << existingDest.prettyURL() << endl;
02330                 state = STATE_CONFLICT_CREATING_DIRS;
02331                 addSubjob(newJob);
02332                 return; 
02333             }
02334         }
02335         else
02336         {
02337             
02338             Job::slotResult( job ); 
02339             return;
02340         }
02341     }
02342     else 
02343     {
02344        
02345         emit copyingDone( this, (*it).uSource, (*it).uDest, true, false );
02346         dirs.remove( it );
02347     }
02348 
02349     m_processedDirs++;
02350     
02351     subjobs.remove( job );
02352     assert ( subjobs.isEmpty() ); 
02353     createNextDir();
02354 }
02355 
02356 void CopyJob::slotResultConflictCreatingDirs( KIO::Job * job )
02357 {
02358     
02359 
02360     
02361     QValueList<CopyInfo>::Iterator it = dirs.begin();
02362     
02363     time_t destmtime = (time_t)-1;
02364     time_t destctime = (time_t)-1;
02365     KIO::filesize_t destsize = 0;
02366     UDSEntry entry = ((KIO::StatJob*)job)->statResult();
02367     KIO::UDSEntry::ConstIterator it2 = entry.begin();
02368     for( ; it2 != entry.end(); it2++ ) {
02369         switch ((*it2).m_uds) {
02370             case UDS_MODIFICATION_TIME:
02371                 destmtime = (time_t)((*it2).m_long);
02372                 break;
02373             case UDS_CREATION_TIME:
02374                 destctime = (time_t)((*it2).m_long);
02375                 break;
02376             case UDS_SIZE:
02377                 destsize = (*it2).m_long;
02378                 break;
02379         }
02380     }
02381     subjobs.remove( job );
02382     assert ( subjobs.isEmpty() ); 
02383 
02384     
02385     RenameDlg_Mode mode = (RenameDlg_Mode)( M_MULTI | M_SKIP );
02386     
02387     if ( m_conflictError == ERR_DIR_ALREADY_EXIST )
02388         mode = (RenameDlg_Mode)( mode | (((*it).uSource == (*it).uDest) ? M_OVERWRITE_ITSELF : M_OVERWRITE ));
02389 
02390     QString existingDest = (*it).uDest.path();
02391     QString newPath;
02392     if (m_reportTimer)
02393         m_reportTimer->stop();
02394     RenameDlg_Result r = Observer::self()->open_RenameDlg( this, i18n("Folder Already Exists"),
02395                                          (*it).uSource.prettyURL(0, KURL::StripFileProtocol),
02396                                          (*it).uDest.prettyURL(0, KURL::StripFileProtocol),
02397                                          mode, newPath,
02398                                          (*it).size, destsize,
02399                                          (*it).ctime, destctime,
02400                                          (*it).mtime, destmtime );
02401     if (m_reportTimer)
02402         m_reportTimer->start(REPORT_TIMEOUT,false);
02403     switch ( r ) {
02404         case R_CANCEL:
02405             m_error = ERR_USER_CANCELED;
02406             emitResult();
02407             return;
02408         case R_RENAME:
02409         {
02410             QString oldPath = (*it).uDest.path( 1 );
02411             KURL newUrl( (*it).uDest );
02412             newUrl.setPath( newPath );
02413             emit renamed( this, (*it).uDest, newUrl ); 
02414 
02415             
02416             (*it).uDest = newUrl.path( -1 );
02417             newPath = newUrl.path( 1 ); 
02418             QValueList<CopyInfo>::Iterator renamedirit = it;
02419             ++renamedirit;
02420             
02421             for( ; renamedirit != dirs.end() ; ++renamedirit )
02422             {
02423                 QString path = (*renamedirit).uDest.path();
02424                 if ( path.left(oldPath.length()) == oldPath ) {
02425                     QString n = path;
02426                     n.replace( 0, oldPath.length(), newPath );
02427                     kdDebug(7007) << "dirs list: " << (*renamedirit).uSource.path()
02428                                   << " was going to be " << path
02429                                   << ", changed into " << n << endl;
02430                     (*renamedirit).uDest.setPath( n );
02431                 }
02432             }
02433             
02434             QValueList<CopyInfo>::Iterator renamefileit = files.begin();
02435             for( ; renamefileit != files.end() ; ++renamefileit )
02436             {
02437                 QString path = (*renamefileit).uDest.path();
02438                 if ( path.left(oldPath.length()) == oldPath ) {
02439                     QString n = path;
02440                     n.replace( 0, oldPath.length(), newPath );
02441                     kdDebug(7007) << "files list: " << (*renamefileit).uSource.path()
02442                                   << " was going to be " << path
02443                                   << ", changed into " << n << endl;
02444                     (*renamefileit).uDest.setPath( n );
02445                 }
02446             }
02447             if (!dirs.isEmpty())
02448                 emit aboutToCreate( this, dirs );
02449             if (!files.isEmpty())
02450                 emit aboutToCreate( this, files );
02451         }
02452         break;
02453         case R_AUTO_SKIP:
02454             m_bAutoSkip = true;
02455             
02456         case R_SKIP:
02457             m_skipList.append( existingDest );
02458             skip( (*it).uSource );
02459             
02460             dirs.remove( it );
02461             break;
02462         case R_OVERWRITE:
02463             m_overwriteList.append( existingDest );
02464             emit copyingDone( this, ( *it ).uSource, ( *it ).uDest, true , false  );
02465             
02466             dirs.remove( it );
02467             break;
02468         case R_OVERWRITE_ALL:
02469             m_bOverwriteAll = true;
02470             emit copyingDone( this, ( *it ).uSource, ( *it ).uDest, true , false  );
02471             
02472             dirs.remove( it );
02473             break;
02474         default:
02475             assert( 0 );
02476     }
02477     state = STATE_CREATING_DIRS;
02478     m_processedDirs++;
02479     
02480     createNextDir();
02481 }
02482 
02483 void CopyJob::createNextDir()
02484 {
02485     KURL udir;
02486     if ( !dirs.isEmpty() )
02487     {
02488         
02489         QValueList<CopyInfo>::Iterator it = dirs.begin();
02490         
02491         while( it != dirs.end() && udir.isEmpty() )
02492         {
02493             QString dir = (*it).uDest.path();
02494             bool bCreateDir = true; 
02495 
02496             QStringList::Iterator sit = m_skipList.begin();
02497             for( ; sit != m_skipList.end() && bCreateDir; sit++ )
02498                 
02499                 if ( *sit == dir.left( (*sit).length() ) )
02500                     bCreateDir = false; 
02501 
02502             if ( !bCreateDir ) {
02503                 dirs.remove( it );
02504                 it = dirs.begin();
02505             } else
02506                 udir = (*it).uDest;
02507         }
02508     }
02509     if ( !udir.isEmpty() ) 
02510     {
02511         
02512         
02513         KIO::SimpleJob *newjob = KIO::mkdir( udir, -1 );
02514         Scheduler::scheduleJob(newjob);
02515 
02516         m_currentDestURL = udir;
02517 
02518         addSubjob(newjob);
02519         return;
02520     }
02521     else 
02522     {
02523         state = STATE_COPYING_FILES;
02524         m_processedFiles++; 
02525         copyNextFile();
02526     }
02527 }
02528 
02529 void CopyJob::slotResultCopyingFiles( Job * job )
02530 {
02531     
02532     QValueList<CopyInfo>::Iterator it = files.begin();
02533     if ( job->error() )
02534     {
02535         
02536         if ( m_bAutoSkip )
02537         {
02538             skip( (*it).uSource );
02539             files.remove( it ); 
02540         }
02541         else
02542         {
02543             m_conflictError = job->error(); 
02544             
02545             if ( ( m_conflictError == ERR_FILE_ALREADY_EXIST )
02546                  || ( m_conflictError == ERR_DIR_ALREADY_EXIST ) )
02547             {
02548                 subjobs.remove( job );
02549                 assert ( subjobs.isEmpty() );
02550                 
02551                 KURL existingFile( (*it).uDest );
02552                 SimpleJob * newJob = KIO::stat( existingFile, false, 2, false );
02553                 Scheduler::scheduleJob(newJob);
02554                 kdDebug(7007) << "KIO::stat for resolving conflict on " << existingFile.prettyURL() << endl;
02555                 state = STATE_CONFLICT_COPYING_FILES;
02556                 addSubjob(newJob);
02557                 return; 
02558             }
02559             else
02560             {
02561                 if ( m_bCurrentOperationIsLink && job->inherits( "KIO::DeleteJob" ) )
02562                 {
02563                     
02564                     
02565                     files.remove( it );
02566                 } else {
02567                     
02568                     slotResultConflictCopyingFiles( job );
02569                     return;
02570                 }
02571             }
02572         }
02573     } else 
02574     {
02575         
02576         if ( m_bCurrentOperationIsLink && m_mode == Move
02577              && !job->inherits( "KIO::DeleteJob" ) 
02578              )
02579         {
02580             subjobs.remove( job );
02581             assert ( subjobs.isEmpty() );
02582             
02583             
02584             KIO::Job * newjob = KIO::del( (*it).uSource, false , false  );
02585             addSubjob( newjob );
02586             return; 
02587         }
02588 
02589         if ( m_bCurrentOperationIsLink )
02590         {
02591             QString target = ( m_mode == Link ? (*it).uSource.path() : (*it).linkDest );
02592             
02593             emit copyingLinkDone( this, (*it).uSource, target, (*it).uDest );
02594         }
02595         else
02596             
02597             emit copyingDone( this, (*it).uSource, (*it).uDest, false, false );
02598         
02599         files.remove( it );
02600     }
02601     m_processedFiles++;
02602 
02603     
02604     m_processedSize += m_fileProcessedSize;
02605     m_fileProcessedSize = 0;
02606 
02607     
02608     subjobs.remove( job );
02609     assert ( subjobs.isEmpty() ); 
02610     copyNextFile();
02611 }
02612 
02613 void CopyJob::slotResultConflictCopyingFiles( KIO::Job * job )
02614 {
02615     
02616     
02617     QValueList<CopyInfo>::Iterator it = files.begin();
02618 
02619     RenameDlg_Result res;
02620     QString newPath;
02621 
02622     if (m_reportTimer)
02623         m_reportTimer->stop();
02624 
02625     if ( ( m_conflictError == ERR_FILE_ALREADY_EXIST )
02626       || ( m_conflictError == ERR_DIR_ALREADY_EXIST ) )
02627     {
02628         
02629         time_t destmtime = (time_t)-1;
02630         time_t destctime = (time_t)-1;
02631         KIO::filesize_t destsize = 0;
02632         UDSEntry entry = ((KIO::StatJob*)job)->statResult();
02633         KIO::UDSEntry::ConstIterator it2 = entry.begin();
02634         for( ; it2 != entry.end(); it2++ ) {
02635             switch ((*it2).m_uds) {
02636                 case UDS_MODIFICATION_TIME:
02637                     destmtime = (time_t)((*it2).m_long);
02638                     break;
02639                 case UDS_CREATION_TIME:
02640                     destctime = (time_t)((*it2).m_long);
02641                     break;
02642                 case UDS_SIZE:
02643                     destsize = (*it2).m_long;
02644                     break;
02645             }
02646         }
02647 
02648         
02649         
02650         RenameDlg_Mode mode = (RenameDlg_Mode)
02651             ( ( m_conflictError == ERR_DIR_ALREADY_EXIST ? 0 :
02652              ( (*it).uSource == (*it).uDest ) ? M_OVERWRITE_ITSELF : M_OVERWRITE ) );
02653         if ( files.count() > 1 ) 
02654             mode = (RenameDlg_Mode) ( mode | M_MULTI | M_SKIP );
02655         else
02656             mode = (RenameDlg_Mode) ( mode | M_SINGLE );
02657         res = Observer::self()->open_RenameDlg( this, m_conflictError == ERR_FILE_ALREADY_EXIST ?
02658                                 i18n("File Already Exists") : i18n("Already Exists as Folder"),
02659                                 (*it).uSource.prettyURL(0, KURL::StripFileProtocol),
02660                                 (*it).uDest.prettyURL(0, KURL::StripFileProtocol),
02661                                 mode, newPath,
02662                               (*it).size, destsize,
02663                               (*it).ctime, destctime,
02664                               (*it).mtime, destmtime );
02665 
02666     }
02667     else
02668     {
02669         if ( job->error() == ERR_USER_CANCELED )
02670             res = R_CANCEL;
02671         else
02672         {
02673             SkipDlg_Result skipResult = Observer::self()->open_SkipDlg( this, files.count() > 1,
02674                                                                         job->errorString() );
02675 
02676             
02677             res = ( skipResult == S_SKIP ) ? R_SKIP :
02678                          ( skipResult == S_AUTO_SKIP ) ? R_AUTO_SKIP :
02679                                         R_CANCEL;
02680         }
02681     }
02682 
02683     if (m_reportTimer)
02684         m_reportTimer->start(REPORT_TIMEOUT,false);
02685 
02686     subjobs.remove( job );
02687     assert ( subjobs.isEmpty() );
02688     switch ( res ) {
02689         case R_CANCEL:
02690             m_error = ERR_USER_CANCELED;
02691             emitResult();
02692             return;
02693         case R_RENAME:
02694         {
02695             KURL newUrl( (*it).uDest );
02696             newUrl.setPath( newPath );
02697             emit renamed( this, (*it).uDest, newUrl ); 
02698             (*it).uDest = newUrl;
02699 
02700             QValueList<CopyInfo> files;
02701             files.append(*it);
02702             emit aboutToCreate( this, files );
02703         }
02704         break;
02705         case R_AUTO_SKIP:
02706             m_bAutoSkip = true;
02707             
02708         case R_SKIP:
02709             
02710             skip( (*it).uSource );
02711             files.remove( it );
02712             break;
02713        case R_OVERWRITE_ALL:
02714             m_bOverwriteAll = true;
02715             break;
02716         case R_OVERWRITE:
02717             
02718             m_overwriteList.append( (*it).uDest.path() );
02719             break;
02720         default:
02721             assert( 0 );
02722     }
02723     state = STATE_COPYING_FILES;
02724     m_processedFiles++;
02725     
02726     copyNextFile();
02727 }
02728 
02729 void CopyJob::copyNextFile()
02730 {
02731     bool bCopyFile = false;
02732     
02733     
02734     QValueList<CopyInfo>::Iterator it = files.begin();
02735     
02736     while (it != files.end() && !bCopyFile)
02737     {
02738         bCopyFile = true;
02739         QString destFile = (*it).uDest.path();
02740 
02741         QStringList::Iterator sit = m_skipList.begin();
02742         for( ; sit != m_skipList.end() && bCopyFile; sit++ )
02743             
02744             if ( *sit == destFile.left( (*sit).length() ) )
02745                 bCopyFile = false; 
02746 
02747         if (!bCopyFile) {
02748             files.remove( it );
02749             it = files.begin();
02750         }
02751     }
02752 
02753     if (bCopyFile) 
02754     {
02755         
02756         bool bOverwrite = m_bOverwriteAll; 
02757         QString destFile = (*it).uDest.path();
02758         if ( (*it).uDest == (*it).uSource )
02759             bOverwrite = false;
02760         else
02761         {
02762             
02763             QStringList::Iterator sit = m_overwriteList.begin();
02764             for( ; sit != m_overwriteList.end() && !bOverwrite; sit++ )
02765                 if ( *sit == destFile.left( (*sit).length() ) )
02766                     bOverwrite = true;
02767         }
02768 
02769         m_bCurrentOperationIsLink = false;
02770         KIO::Job * newjob = 0L;
02771         if ( m_mode == Link )
02772         {
02773             
02774             if (
02775                 ((*it).uSource.protocol() == (*it).uDest.protocol()) &&
02776                 ((*it).uSource.host() == (*it).uDest.host()) &&
02777                 ((*it).uSource.port() == (*it).uDest.port()) &&
02778                 ((*it).uSource.user() == (*it).uDest.user()) &&
02779                 ((*it).uSource.pass() == (*it).uDest.pass()) )
02780             {
02781                 
02782                 KIO::SimpleJob *newJob = KIO::symlink( (*it).uSource.path(), (*it).uDest, bOverwrite, false  );
02783                 newjob = newJob;
02784                 Scheduler::scheduleJob(newJob);
02785                 
02786                 
02787                 m_bCurrentOperationIsLink = true;
02788                 m_currentSrcURL=(*it).uSource;
02789                 m_currentDestURL=(*it).uDest;
02790                 
02791             } else {
02792                 
02793                 if ( (*it).uDest.isLocalFile() )
02794                 {
02795                     bool devicesOk=false;
02796 
02797                     
02798                     if ((*it).uSource.protocol()==QString::fromLatin1("devices"))
02799                     {
02800                        QByteArray data;
02801                        QByteArray param;
02802                        QCString retType;
02803                        QDataStream streamout(param,IO_WriteOnly);
02804                        streamout<<(*it).uSource;
02805                        streamout<<(*it).uDest;
02806                        if ( kapp->dcopClient()->call( "kded",
02807                             "mountwatcher", "createLink(KURL, KURL)", param,retType,data,false ) )
02808                        {
02809                           QDataStream streamin(data,IO_ReadOnly);
02810                           streamin>>devicesOk;
02811                        }
02812                        if (devicesOk)
02813                        {
02814                            files.remove( it );
02815                            m_processedFiles++;
02816                            
02817                            copyNextFile();
02818                            return;
02819                        }
02820                     }
02821 
02822                     if (!devicesOk)
02823                     {
02824                        QString path = (*it).uDest.path();
02825                        
02826                        QFile f( path );
02827                        if ( f.open( IO_ReadWrite ) )
02828                        {
02829                            f.close();
02830                            KSimpleConfig config( path );
02831                            config.setDesktopGroup();
02832                            config.writePathEntry( QString::fromLatin1("URL"), (*it).uSource.url() );
02833                            config.writeEntry( QString::fromLatin1("Name"), (*it).uSource.url() );
02834                            config.writeEntry( QString::fromLatin1("Type"), QString::fromLatin1("Link") );
02835                            QString protocol = (*it).uSource.protocol();
02836                            if ( protocol == QString::fromLatin1("ftp") )
02837                                config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("ftp") );
02838                            else if ( protocol == QString::fromLatin1("http") )
02839                                config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("www") );
02840                            else if ( protocol == QString::fromLatin1("info") )
02841                                config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("info") );
02842                            else if ( protocol == QString::fromLatin1("mailto") )   
02843                                config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("kmail") ); 
02844                            else
02845                                config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("unknown") );
02846                            config.sync();
02847                            files.remove( it );
02848                            m_processedFiles++;
02849                            
02850                            copyNextFile();
02851                            return;
02852                        }
02853                        else
02854                        {
02855                            kdDebug(7007) << "CopyJob::copyNextFile ERR_CANNOT_OPEN_FOR_WRITING" << endl;
02856                            m_error = ERR_CANNOT_OPEN_FOR_WRITING;
02857                            m_errorText = (*it).uDest.path();
02858                            emitResult();
02859                            return;
02860                        }
02861                     }
02862                 } else {
02863                     
02864                     m_error = ERR_CANNOT_SYMLINK;
02865                     m_errorText = (*it).uDest.prettyURL();
02866                     emitResult();
02867                     return;
02868                 }
02869             }
02870         }
02871         else if ( !(*it).linkDest.isEmpty() &&
02872                   ((*it).uSource.protocol() == (*it).uDest.protocol()) &&
02873                   ((*it).uSource.host() == (*it).uDest.host()) &&
02874                   ((*it).uSource.port() == (*it).uDest.port()) &&
02875                   ((*it).uSource.user() == (*it).uDest.user()) &&
02876                   ((*it).uSource.pass() == (*it).uDest.pass()))
02877             
02878         {
02879             KIO::SimpleJob *newJob = KIO::symlink( (*it).linkDest, (*it).uDest, bOverwrite, false  );
02880             Scheduler::scheduleJob(newJob);
02881             newjob = newJob;
02882             
02883             
02884             m_currentSrcURL=(*it).linkDest;
02885             m_currentDestURL=(*it).uDest;
02886             
02887             m_bCurrentOperationIsLink = true;
02888             
02889         } else if (m_mode == Move) 
02890         {
02891             KIO::FileCopyJob * moveJob = KIO::file_move( (*it).uSource, (*it).uDest, (*it).permissions, bOverwrite, false, false );
02892             moveJob->setSourceSize64( (*it).size );
02893             newjob = moveJob;
02894             
02895             
02896             m_currentSrcURL=(*it).uSource;
02897             m_currentDestURL=(*it).uDest;
02898             
02899         }
02900         else 
02901         {
02902             
02903             
02904             
02905             
02906             bool remoteSource = !(*it).uSource.isLocalFile() && ((*it).uSource.protocol() != "tar"); 
02907             int permissions = ( remoteSource && (*it).uDest.isLocalFile() ) ? -1 : (*it).permissions;
02908             KIO::FileCopyJob * copyJob = KIO::file_copy( (*it).uSource, (*it).uDest, permissions, bOverwrite, false, false );
02909             copyJob->setParentJob( this ); 
02910             copyJob->setSourceSize64( (*it).size );
02911             newjob = copyJob;
02912             
02913             m_currentSrcURL=(*it).uSource;
02914             m_currentDestURL=(*it).uDest;
02915         }
02916         addSubjob(newjob);
02917         connect( newjob, SIGNAL( processedSize( KIO::Job*, KIO::filesize_t ) ),
02918                  this, SLOT( slotProcessedSize( KIO::Job*, KIO::filesize_t ) ) );
02919         connect( newjob, SIGNAL( totalSize( KIO::Job*, KIO::filesize_t ) ),
02920                  this, SLOT( slotTotalSize( KIO::Job*, KIO::filesize_t ) ) );
02921     }
02922     else
02923     {
02924         
02925         
02926         deleteNextDir();
02927     }
02928 }
02929 
02930 void CopyJob::deleteNextDir()
02931 {
02932     if ( m_mode == Move && !dirsToRemove.isEmpty() ) 
02933     {
02934         state = STATE_DELETING_DIRS;
02935         
02936         KURL::List::Iterator it = dirsToRemove.fromLast();
02937         SimpleJob *job = KIO::rmdir( *it );
02938         Scheduler::scheduleJob(job);
02939         dirsToRemove.remove(it);
02940         addSubjob( job );
02941     }
02942     else
02943     {
02944         
02945         if ( !m_bOnlyRenames )
02946         {
02947             KDirNotify_stub allDirNotify("*", "KDirNotify*");
02948             KURL url( m_dest );
02949             if ( destinationState != DEST_IS_DIR || m_asMethod )
02950                 url.setPath( url.directory() );
02951             
02952             allDirNotify.FilesAdded( url );
02953 
02954             if ( m_mode == Move && !m_srcList.isEmpty() )
02955                 allDirNotify.FilesRemoved( m_srcList );
02956         }
02957         if (m_reportTimer!=0)
02958             m_reportTimer->stop();
02959         emitResult();
02960     }
02961 }
02962 
02963 void CopyJob::slotProcessedSize( KIO::Job*, KIO::filesize_t data_size )
02964 {
02965   
02966   m_fileProcessedSize = data_size;
02967   setProcessedSize(m_processedSize + m_fileProcessedSize);
02968 
02969   if ( m_processedSize + m_fileProcessedSize > m_totalSize )
02970   {
02971     m_totalSize = m_processedSize + m_fileProcessedSize;
02972     
02973     emit totalSize( this, m_totalSize ); 
02974   }
02975   
02976   emit processedSize( this, m_processedSize + m_fileProcessedSize );
02977   emitPercent( m_processedSize + m_fileProcessedSize, m_totalSize );
02978 }
02979 
02980 void CopyJob::slotTotalSize( KIO::Job*, KIO::filesize_t size )
02981 {
02982   
02983   
02984   
02985   
02986   if ( m_bSingleFileCopy )
02987   {
02988     
02989     m_totalSize = size;
02990     emit totalSize( this, size );
02991   }
02992 }
02993 
02994 void CopyJob::slotResultDeletingDirs( Job * job )
02995 {
02996     if (job->error())
02997     {
02998         
02999         
03000         
03001     }
03002     subjobs.remove( job );
03003     assert ( subjobs.isEmpty() );
03004     deleteNextDir();
03005 }
03006 
03007 void CopyJob::slotResult( Job *job )
03008 {
03009     
03010     
03011     
03012     
03013     
03014 
03015     switch ( state ) {
03016         case STATE_STATING: 
03017             slotResultStating( job );
03018             break;
03019         case STATE_RENAMING: 
03020         {
03021             int err = job->error();
03022             subjobs.remove( job );
03023             assert ( subjobs.isEmpty() );
03024             
03025             KURL dest = m_dest;
03026             if ( destinationState == DEST_IS_DIR && !m_asMethod )
03027                 dest.addPath( m_currentSrcURL.fileName() );
03028             if ( err )
03029             {
03030                 
03031                 
03032                 
03033                 if ( m_currentSrcURL.isLocalFile() && m_currentSrcURL.url(-1) != dest.url(-1) &&
03034                      m_currentSrcURL.url(-1).lower() == dest.url(-1).lower() &&
03035                      ( err == ERR_FILE_ALREADY_EXIST || err == ERR_DIR_ALREADY_EXIST ) )
03036                 {
03037                     kdDebug(7007) << "Couldn't rename directly, dest already exists. Detected special case of lower/uppercase renaming in same dir, try with 2 rename calls" << endl;
03038                     QCString _src( QFile::encodeName(m_currentSrcURL.path()) );
03039                     QCString _dest( QFile::encodeName(dest.path()) );
03040                     KTempFile tmpFile( m_currentSrcURL.directory(false) );
03041                     QCString _tmp( QFile::encodeName(tmpFile.name()) );
03042                     kdDebug(7007) << "CopyJob::slotResult KTempFile status:" << tmpFile.status() << " using " << _tmp << " as intermediary" << endl;
03043                     tmpFile.unlink();
03044                     if ( ::rename( _src, _tmp ) == 0 )
03045                     {
03046                         if ( !QFile::exists( _dest ) && ::rename( _tmp, _dest ) == 0 )
03047                         {
03048                             kdDebug(7007) << "Success." << endl;
03049                             err = 0;
03050                         }
03051                         else
03052                         {
03053                             
03054                             if ( ::rename( _tmp, _src ) != 0 ) {
03055                                 kdError(7007) << "Couldn't rename " << tmpFile.name() << " back to " << _src << " !" << endl;
03056                                 
03057                                 Job::slotResult( job ); 
03058                                 return;
03059                             }
03060                         }
03061                     }
03062                 }
03063             }
03064             if ( err )
03065             {
03066                 m_currentSrcURL=*m_currentStatSrc;
03067                 m_currentDestURL=m_dest;
03068 
03069                 if ( err == ERR_DIR_ALREADY_EXIST || err == ERR_FILE_ALREADY_EXIST )
03070                 {
03071                     if (m_reportTimer)
03072                         m_reportTimer->stop();
03073 
03074                     QString newPath;
03075                     RenameDlg_Mode mode = M_SINGLE;
03076                     RenameDlg_Result r = Observer::self()->open_RenameDlg( this,
03077                                          err == ERR_FILE_ALREADY_EXIST ? i18n("File Already Exists") : i18n("Already Exists as Folder"),
03078                                          m_currentSrcURL.prettyURL(0, KURL::StripFileProtocol),
03079                                          m_currentDestURL.prettyURL(0, KURL::StripFileProtocol),
03080                                          mode, newPath );
03081                     if (m_reportTimer)
03082                         m_reportTimer->start(REPORT_TIMEOUT,false);
03083 
03084                     switch ( r )
03085                     {
03086                         case R_CANCEL:
03087                         {
03088                             m_error = ERR_USER_CANCELED;
03089                             emitResult();
03090                             return;
03091                         }
03092                         case R_RENAME:
03093                         {
03094                             m_dest.setPath( newPath );
03095                             KIO::Job* job = KIO::stat( m_dest, false, 2, false );
03096                             state = STATE_STATING;
03097                             destinationState = DEST_NOT_STATED;
03098                             addSubjob(job);
03099                             break;
03100                         }
03101                         default:
03102                             
03103                             break;
03104                     }
03105                 }
03106                 else
03107                 {
03108                     kdDebug(7007) << "Couldn't rename, reverting to normal way, starting with stat" << endl;
03109                     
03110                     KIO::Job* job = KIO::stat( m_currentSrcURL, true, 2, false );
03111                     state = STATE_STATING;
03112                     addSubjob(job);
03113                     m_bOnlyRenames = false;
03114                 }
03115             }
03116             else
03117             {
03118                 
03119                 emit copyingDone( this, *m_currentStatSrc, dest, true, true );
03120                 ++m_currentStatSrc;
03121                 statNextSrc();
03122             }
03123         }
03124         break;
03125         case STATE_LISTING: 
03126             
03127             
03128             if (job->error())
03129             {
03130                 Job::slotResult( job ); 
03131                 return;
03132             }
03133 
03134             subjobs.remove( job );
03135             assert ( subjobs.isEmpty() );
03136 
03137             ++m_currentStatSrc;
03138             statNextSrc();
03139             break;
03140         case STATE_CREATING_DIRS:
03141             slotResultCreatingDirs( job );
03142             break;
03143         case STATE_CONFLICT_CREATING_DIRS:
03144             slotResultConflictCreatingDirs( job );
03145             break;
03146         case STATE_COPYING_FILES:
03147             slotResultCopyingFiles( job );
03148             break;
03149         case STATE_CONFLICT_COPYING_FILES:
03150             slotResultConflictCopyingFiles( job );
03151             break;
03152         case STATE_DELETING_DIRS:
03153             slotResultDeletingDirs( job );
03154             break;
03155         default:
03156             assert( 0 );
03157     }
03158 }
03159 
03160 CopyJob *KIO::copy(const KURL& src, const KURL& dest, bool showProgressInfo )
03161 {
03162     
03163     KURL::List srcList;
03164     srcList.append( src );
03165     return new CopyJob( srcList, dest, CopyJob::Copy, false, showProgressInfo );
03166 }
03167 
03168 CopyJob *KIO::copyAs(const KURL& src, const KURL& dest, bool showProgressInfo )
03169 {
03170     
03171     KURL::List srcList;
03172     srcList.append( src );
03173     return new CopyJob( srcList, dest, CopyJob::Copy, true, showProgressInfo );
03174 }
03175 
03176 CopyJob *KIO::copy( const KURL::List& src, const KURL& dest, bool showProgressInfo )
03177 {
03178     return new CopyJob( src, dest, CopyJob::Copy, false, showProgressInfo );
03179 }
03180 
03181 CopyJob *KIO::move(const KURL& src, const KURL& dest, bool showProgressInfo )
03182 {
03183     KURL::List srcList;
03184     srcList.append( src );
03185     return new CopyJob( srcList, dest, CopyJob::Move, false, showProgressInfo );
03186 }
03187 
03188 CopyJob *KIO::moveAs(const KURL& src, const KURL& dest, bool showProgressInfo )
03189 {
03190     KURL::List srcList;
03191     srcList.append( src );
03192     return new CopyJob( srcList, dest, CopyJob::Move, true, showProgressInfo );
03193 }
03194 
03195 CopyJob *KIO::move( const KURL::List& src, const KURL& dest, bool showProgressInfo )
03196 {
03197     return new CopyJob( src, dest, CopyJob::Move, false, showProgressInfo );
03198 }
03199 
03200 CopyJob *KIO::link(const KURL& src, const KURL& destDir, bool showProgressInfo )
03201 {
03202     KURL::List srcList;
03203     srcList.append( src );
03204     return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
03205 }
03206 
03207 CopyJob *KIO::link(const KURL::List& srcList, const KURL& destDir, bool showProgressInfo )
03208 {
03209     return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
03210 }
03211 
03212 CopyJob *KIO::linkAs(const KURL& src, const KURL& destDir, bool showProgressInfo )
03213 {
03214     KURL::List srcList;
03215     srcList.append( src );
03216     return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
03217 }
03218 
03220 
03221 DeleteJob::DeleteJob( const KURL::List& src, bool shred, bool showProgressInfo )
03222 : Job(showProgressInfo), m_totalSize( 0 ), m_processedSize( 0 ), m_fileProcessedSize( 0 ),
03223   m_processedFiles( 0 ), m_processedDirs( 0 ), m_totalFilesDirs( 0 ),
03224   m_srcList(src), m_currentStat(m_srcList.begin()), m_shred(shred), m_reportTimer(0)
03225 {
03226   if ( showProgressInfo ) {
03227 
03228      connect( this, SIGNAL( totalFiles( KIO::Job*, unsigned long ) ),
03229               Observer::self(), SLOT( slotTotalFiles( KIO::Job*, unsigned long ) ) );
03230 
03231      connect( this, SIGNAL( totalDirs( KIO::Job*, unsigned long ) ),
03232               Observer::self(), SLOT( slotTotalDirs( KIO::Job*, unsigned long ) ) );
03233 
03234      
03235      
03236 
03237 
03238 
03239 
03240 
03241 
03242 
03243 
03244      m_reportTimer=new QTimer(this);
03245      connect(m_reportTimer,SIGNAL(timeout()),this,SLOT(slotReport()));
03246      
03247      m_reportTimer->start(REPORT_TIMEOUT,false);
03248   }
03249 
03250   QTimer::singleShot(0, this, SLOT(slotStart()));
03251 }
03252 
03253 void DeleteJob::slotStart()
03254 {
03255   statNextSrc();
03256 }
03257 
03258 
03259 
03260 
03261 void DeleteJob::slotReport()
03262 {
03263    if (m_progressId==0)
03264       return;
03265 
03266    Observer * observer = Observer::self();
03267 
03268    emit deleting( this, m_currentURL );
03269    observer->slotDeleting(this,m_currentURL);
03270 
03271    switch( state ) {
03272         case STATE_STATING:
03273         case STATE_LISTING:
03274             emit totalSize( this, m_totalSize );
03275             emit totalFiles( this, files.count() );
03276             emit totalDirs( this, dirs.count() );
03277             break;
03278         case STATE_DELETING_DIRS:
03279             emit processedDirs( this, m_processedDirs );
03280             observer->slotProcessedDirs(this,m_processedDirs);
03281             emitPercent( m_processedFiles + m_processedDirs, m_totalFilesDirs );
03282             break;
03283         case STATE_DELETING_FILES:
03284             observer->slotProcessedFiles(this,m_processedFiles);
03285             emit processedFiles( this, m_processedFiles );
03286             if (!m_shred)
03287                emitPercent( m_processedFiles, m_totalFilesDirs );
03288             break;
03289    }
03290 }
03291 
03292 
03293 void DeleteJob::slotEntries(KIO::Job* job, const UDSEntryList& list)
03294 {
03295    UDSEntryListConstIterator it = list.begin();
03296    UDSEntryListConstIterator end = list.end();
03297    for (; it != end; ++it)
03298    {
03299       UDSEntry::ConstIterator it2 = (*it).begin();
03300       bool bDir = false;
03301       bool bLink = false;
03302       QString relName;
03303       int atomsFound(0);
03304       for( ; it2 != (*it).end(); it2++ )
03305       {
03306          switch ((*it2).m_uds)
03307          {
03308          case UDS_FILE_TYPE:
03309             bDir = S_ISDIR((*it2).m_long);
03310             atomsFound++;
03311             break;
03312          case UDS_NAME:
03313             relName = ((*it2).m_str);
03314             atomsFound++;
03315             break;
03316          case UDS_LINK_DEST:
03317             bLink = !(*it2).m_str.isEmpty();
03318             atomsFound++;
03319             break;
03320          case UDS_SIZE:
03321             m_totalSize += (KIO::filesize_t)((*it2).m_long);
03322             atomsFound++;
03323             break;
03324          default:
03325             break;
03326          }
03327          if (atomsFound==4) break;
03328       }
03329       assert(!relName.isEmpty());
03330       if (relName != ".." && relName != ".")
03331       {
03332          KURL url = ((SimpleJob *)job)->url(); 
03333          url.addPath( relName );
03334          
03335          if ( bLink )
03336             symlinks.append( url );
03337          else if ( bDir )
03338             dirs.append( url );
03339          else
03340             files.append( url );
03341       }
03342    }
03343 }
03344 
03345 
03346 void DeleteJob::statNextSrc()
03347 {
03348     
03349     if ( m_currentStat != m_srcList.end() )
03350     {
03351         m_currentURL = (*m_currentStat);
03352 
03353         
03354         if (!KProtocolInfo::supportsDeleting(m_currentURL)) {
03355             KMessageBox::information( 0, buildErrorString(ERR_CANNOT_DELETE, m_currentURL.prettyURL()));
03356             ++m_currentStat;
03357             statNextSrc(); 
03358             return;
03359         }
03360         
03361         state = STATE_STATING;
03362         KIO::SimpleJob * job = KIO::stat( m_currentURL, true, 1, false );
03363         Scheduler::scheduleJob(job);
03364         
03365         addSubjob(job);
03366         
03367         
03368     } else
03369     {
03370         m_totalFilesDirs = files.count()+symlinks.count() + dirs.count();
03371         slotReport();
03372         
03373         
03374         
03375         
03376         for ( QStringList::Iterator it = m_parentDirs.begin() ; it != m_parentDirs.end() ; ++it )
03377             KDirWatch::self()->stopDirScan( *it );
03378         state = STATE_DELETING_FILES;
03379     deleteNextFile();
03380     }
03381 }
03382 
03383 void DeleteJob::deleteNextFile()
03384 {
03385     
03386     if ( !files.isEmpty() || !symlinks.isEmpty() )
03387     {
03388         SimpleJob *job;
03389         do {
03390             
03391             KURL::List::Iterator it = files.begin();
03392             bool isLink = false;
03393             if ( it == files.end() ) 
03394             {
03395                 it = symlinks.begin(); 
03396                 isLink = true;
03397             }
03398             
03399             if ( m_shred && (*it).isLocalFile() && !isLink )
03400             {
03401                 
03402                 KIO_ARGS << int(3) << (*it).path();
03403                 job = KIO::special(KURL("file:/"), packedArgs, false );
03404                 Scheduler::scheduleJob(job);
03405                 m_currentURL=(*it);
03406                 connect( job, SIGNAL( processedSize( KIO::Job*, KIO::filesize_t ) ),
03407                          this, SLOT( slotProcessedSize( KIO::Job*, KIO::filesize_t ) ) );
03408             } else
03409             {
03410                 
03411                 
03412                 if ( (*it).isLocalFile() && unlink( QFile::encodeName((*it).path()) ) == 0 ) {
03413                     job = 0;
03414                     m_processedFiles++;
03415                     if ( m_processedFiles % 300 == 0 ) { 
03416                         m_currentURL = *it;
03417                         slotReport();
03418                     }
03419                 } else
03420                 { 
03421                     job = KIO::file_delete( *it, false );
03422                     Scheduler::scheduleJob(job);
03423                     m_currentURL=(*it);
03424                 }
03425             }
03426             if ( isLink )
03427                 symlinks.remove(it);
03428             else
03429                 files.remove(it);
03430             if ( job ) {
03431                 addSubjob(job);
03432                 return;
03433             }
03434             
03435         } while (!job && (!files.isEmpty() || !symlinks.isEmpty()));
03436     }
03437     state = STATE_DELETING_DIRS;
03438     deleteNextDir();
03439 }
03440 
03441 void DeleteJob::deleteNextDir()
03442 {
03443     if ( !dirs.isEmpty() ) 
03444     {
03445         do {
03446             
03447             KURL::List::Iterator it = dirs.fromLast();
03448             
03449             if ( (*it).isLocalFile() && ::rmdir( QFile::encodeName((*it).path()) ) == 0 ) {
03450 
03451                 m_processedDirs++;
03452                 if ( m_processedDirs % 100 == 0 ) { 
03453                     m_currentURL = *it;
03454                     slotReport();
03455                 }
03456             } else
03457             {
03458                 SimpleJob *job = KIO::rmdir( *it );
03459                 Scheduler::scheduleJob(job);
03460                 dirs.remove(it);
03461                 addSubjob( job );
03462                 return;
03463             }
03464             dirs.remove(it);
03465         } while ( !dirs.isEmpty() );
03466     }
03467 
03468     
03469     for ( QStringList::Iterator it = m_parentDirs.begin() ; it != m_parentDirs.end() ; ++it )
03470         KDirWatch::self()->restartDirScan( *it );
03471 
03472     
03473     if ( !m_srcList.isEmpty() )
03474     {
03475         KDirNotify_stub allDirNotify("*", "KDirNotify*");
03476         allDirNotify.FilesRemoved( m_srcList );
03477     }
03478     if (m_reportTimer!=0)
03479        m_reportTimer->stop();
03480     emitResult();
03481 }
03482 
03483 void DeleteJob::slotProcessedSize( KIO::Job*, KIO::filesize_t data_size )
03484 {
03485    
03486    
03487    
03488 
03489    m_fileProcessedSize = data_size;
03490    setProcessedSize(m_processedSize + m_fileProcessedSize);
03491 
03492    
03493 
03494    emit processedSize( this, m_processedSize + m_fileProcessedSize );
03495 
03496    
03497    unsigned long ipercent = m_percent;
03498 
03499    if ( m_totalSize == 0 )
03500       m_percent = 100;
03501    else
03502       m_percent = (unsigned long)(( (float)(m_processedSize + m_fileProcessedSize) / (float)m_totalSize ) * 100.0);
03503 
03504    if ( m_percent > ipercent )
03505    {
03506       emit percent( this, m_percent );
03507       
03508    }
03509 
03510 }
03511 
03512 void DeleteJob::slotResult( Job *job )
03513 {
03514    switch ( state )
03515    {
03516    case STATE_STATING:
03517       {
03518          
03519          if (job->error() )
03520          {
03521             
03522             Job::slotResult( job ); 
03523             return;
03524          }
03525 
03526          
03527          UDSEntry entry = ((StatJob*)job)->statResult();
03528          bool bDir = false;
03529          bool bLink = false;
03530          KIO::filesize_t size = (KIO::filesize_t)-1;
03531          UDSEntry::ConstIterator it2 = entry.begin();
03532          int atomsFound(0);
03533          for( ; it2 != entry.end(); it2++ )
03534          {
03535             if ( ((*it2).m_uds) == UDS_FILE_TYPE )
03536             {
03537                bDir = S_ISDIR( (mode_t)(*it2).m_long );
03538                atomsFound++;
03539             }
03540             else if ( ((*it2).m_uds) == UDS_LINK_DEST )
03541             {
03542                bLink = !((*it2).m_str.isEmpty());
03543                atomsFound++;
03544             }
03545             else if ( ((*it2).m_uds) == UDS_SIZE )
03546             {
03547                size = (*it2).m_long;
03548                atomsFound++;
03549             };
03550             if (atomsFound==3) break;
03551          }
03552 
03553          KURL url = ((SimpleJob*)job)->url();
03554 
03555          subjobs.remove( job );
03556          assert( subjobs.isEmpty() );
03557 
03558          if (bDir && !bLink)
03559          {
03560             
03561             dirs.append( url );
03562             if ( url.isLocalFile() && !m_parentDirs.contains( url.path(-1) ) )
03563                 m_parentDirs.append( url.path(-1) );
03564 
03565             
03566             
03567             state = STATE_LISTING;
03568             ListJob *newjob = listRecursive( url, false );
03569             newjob->setUnrestricted(true); 
03570             Scheduler::scheduleJob(newjob);
03571             connect(newjob, SIGNAL(entries( KIO::Job *,
03572                                             const KIO::UDSEntryList& )),
03573                     SLOT( slotEntries( KIO::Job*,
03574                                        const KIO::UDSEntryList& )));
03575             addSubjob(newjob);
03576          }
03577          else
03578          {
03579             if ( bLink ) {
03580                 
03581                 symlinks.append( url );
03582             } else {
03583                 
03584                 files.append( url );
03585             }
03586             if ( url.isLocalFile() && !m_parentDirs.contains( url.directory(-1) ) )
03587                 m_parentDirs.append( url.directory(-1) );
03588             ++m_currentStat;
03589             statNextSrc();
03590          }
03591       }
03592       break;
03593    case STATE_LISTING:
03594       if ( job->error() )
03595       {
03596          
03597       }
03598       subjobs.remove( job );
03599       assert( subjobs.isEmpty() );
03600       ++m_currentStat;
03601       statNextSrc();
03602       break;
03603    case STATE_DELETING_FILES:
03604       if ( job->error() )
03605       {
03606          Job::slotResult( job ); 
03607          return;
03608       }
03609       subjobs.remove( job );
03610       assert( subjobs.isEmpty() );
03611       m_processedFiles++;
03612 
03613       deleteNextFile();
03614       break;
03615    case STATE_DELETING_DIRS:
03616       if ( job->error() )
03617       {
03618          Job::slotResult( job ); 
03619          return;
03620       }
03621       subjobs.remove( job );
03622       assert( subjobs.isEmpty() );
03623       m_processedDirs++;
03624       
03625       
03626          
03627 
03628       deleteNextDir();
03629       break;
03630    default:
03631       assert(0);
03632    }
03633 }
03634 
03635 DeleteJob *KIO::del( const KURL& src, bool shred, bool showProgressInfo )
03636 {
03637   KURL::List srcList;
03638   srcList.append( src );
03639   DeleteJob *job = new DeleteJob( srcList, shred, showProgressInfo );
03640   return job;
03641 }
03642 
03643 DeleteJob *KIO::del( const KURL::List& src, bool shred, bool showProgressInfo )
03644 {
03645   DeleteJob *job = new DeleteJob( src, shred, showProgressInfo );
03646   return job;
03647 }
03648 
03649 MultiGetJob::MultiGetJob(const KURL& url,
03650                          bool showProgressInfo)
03651  : TransferJob(url, 0, QByteArray(), QByteArray(), showProgressInfo)
03652 {
03653    m_waitQueue.setAutoDelete(true);
03654    m_activeQueue.setAutoDelete(true);
03655    m_currentEntry = 0;
03656 }
03657 
03658 void MultiGetJob::get(long id, const KURL &url, const MetaData &metaData)
03659 {
03660    GetRequest *entry = new GetRequest(id, url, metaData);
03661    entry->metaData["request-id"] = QString("%1").arg(id);
03662    m_waitQueue.append(entry);
03663 }
03664 
03665 void MultiGetJob::flushQueue(QPtrList<GetRequest> &queue)
03666 {
03667    GetRequest *entry;
03668    
03669    
03670    for(entry = m_waitQueue.first(); entry; )
03671    {
03672       if ((m_url.protocol() == entry->url.protocol()) &&
03673           (m_url.host() == entry->url.host()) &&
03674           (m_url.port() == entry->url.port()) &&
03675           (m_url.user() == entry->url.user()))
03676       {
03677          m_waitQueue.take();
03678          queue.append(entry);
03679          entry = m_waitQueue.current();
03680       }
03681       else
03682       {
03683          entry = m_waitQueue.next();
03684       }
03685    }
03686    
03687    KIO_ARGS << (Q_INT32) queue.count();
03688    for(entry = queue.first(); entry; entry = queue.next())
03689    {
03690       stream << entry->url << entry->metaData;
03691    }
03692    m_packedArgs = packedArgs;
03693    m_command = CMD_MULTI_GET;
03694    m_outgoingMetaData.clear();
03695 }
03696 
03697 void MultiGetJob::start(Slave *slave)
03698 {
03699    
03700    GetRequest *entry = m_waitQueue.take(0);
03701    m_activeQueue.append(entry);
03702 
03703    m_url = entry->url;
03704 
03705    if (!entry->url.protocol().startsWith("http"))
03706    {
03707       
03708       KIO_ARGS << entry->url;
03709       m_packedArgs = packedArgs;
03710       m_outgoingMetaData = entry->metaData;
03711       m_command = CMD_GET;
03712       b_multiGetActive = false;
03713    }
03714    else
03715    {
03716       flushQueue(m_activeQueue);
03717       b_multiGetActive = true;
03718    }
03719 
03720    TransferJob::start(slave); 
03721 }
03722 
03723 bool MultiGetJob::findCurrentEntry()
03724 {
03725    if (b_multiGetActive)
03726    {
03727       long id = m_incomingMetaData["request-id"].toLong();
03728       for(GetRequest *entry = m_activeQueue.first(); entry; entry = m_activeQueue.next())
03729       {
03730          if (entry->id == id)
03731          {
03732             m_currentEntry = entry;
03733             return true;
03734          }
03735       }
03736       m_currentEntry = 0;
03737       return false;
03738    }
03739    else
03740    {
03741       m_currentEntry = m_activeQueue.first();
03742       return (m_currentEntry != 0);
03743    }
03744 }
03745 
03746 void MultiGetJob::slotRedirection( const KURL &url)
03747 {
03748   if (!findCurrentEntry()) return; 
03749   if (!kapp->authorizeURLAction("redirect", m_url, url))
03750   {
03751      kdWarning(7007) << "MultiGetJob: Redirection from " << m_currentEntry->url.prettyURL() << " to " << url.prettyURL() << " REJECTED!" << endl;
03752      return;
03753   }
03754   m_redirectionURL = url;
03755   if (m_currentEntry->url.hasUser() && !url.hasUser() && (m_currentEntry->url.host().lower() == url.host().lower()))
03756       m_redirectionURL.setUser(m_currentEntry->url.user()); 
03757   get(m_currentEntry->id, m_redirectionURL, m_currentEntry->metaData); 
03758 }
03759 
03760 
03761 void MultiGetJob::slotFinished()
03762 {
03763   if (!findCurrentEntry()) return;
03764   if (m_redirectionURL.isEmpty())
03765   {
03766      
03767      emit result(m_currentEntry->id);
03768   }
03769   m_redirectionURL = KURL();
03770   m_error = 0;
03771   m_incomingMetaData.clear();
03772   m_activeQueue.removeRef(m_currentEntry);
03773   if (m_activeQueue.count() == 0)
03774   {
03775      if (m_waitQueue.count() == 0)
03776      {
03777         
03778         TransferJob::slotFinished();
03779      }
03780      else
03781      {
03782         
03783         
03784         
03785         GetRequest *entry = m_waitQueue.at(0);
03786         m_url = entry->url;
03787         slaveDone();
03788         Scheduler::doJob(this);
03789      }
03790   }
03791 }
03792 
03793 void MultiGetJob::slotData( const QByteArray &_data)
03794 {
03795   if(!m_currentEntry) return;
03796   if(m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error)
03797      emit data(m_currentEntry->id, _data);
03798 }
03799 
03800 void MultiGetJob::slotMimetype( const QString &_mimetype )
03801 {
03802   if (b_multiGetActive)
03803   {
03804      QPtrList<GetRequest> newQueue;
03805      flushQueue(newQueue);
03806      if (!newQueue.isEmpty())
03807      {
03808         while(!newQueue.isEmpty())
03809            m_activeQueue.append(newQueue.take(0));
03810         m_slave->send( m_command, m_packedArgs );
03811      }
03812   }
03813   if (!findCurrentEntry()) return; 
03814   emit mimetype(m_currentEntry->id, _mimetype);
03815 }
03816 
03817 MultiGetJob *KIO::multi_get(long id, const KURL &url, const MetaData &metaData)
03818 {
03819     MultiGetJob * job = new MultiGetJob( url, false );
03820     job->get(id, url, metaData);
03821     return job;
03822 }
03823 
03824 
03825 #ifdef CACHE_INFO
03826 CacheInfo::CacheInfo(const KURL &url)
03827 {
03828     m_url = url;
03829 }
03830 
03831 QString CacheInfo::cachedFileName()
03832 {
03833    const QChar separator = '_';
03834 
03835    QString CEF = m_url.path();
03836 
03837    int p = CEF.find('/');
03838 
03839    while(p != -1)
03840    {
03841       CEF[p] = separator;
03842       p = CEF.find('/', p);
03843    }
03844 
03845    QString host = m_url.host().lower();
03846    CEF = host + CEF + '_';
03847 
03848    QString dir = KProtocolManager::cacheDir();
03849    if (dir[dir.length()-1] != '/')
03850       dir += "/";
03851 
03852    int l = m_url.host().length();
03853    for(int i = 0; i < l; i++)
03854    {
03855       if (host[i].isLetter() && (host[i] != 'w'))
03856       {
03857          dir += host[i];
03858          break;
03859       }
03860    }
03861    if (dir[dir.length()-1] == '/')
03862       dir += "0";
03863 
03864    unsigned long hash = 0x00000000;
03865    QCString u = m_url.url().latin1();
03866    for(int i = u.length(); i--;)
03867    {
03868       hash = (hash * 12211 + u[i]) % 2147483563;
03869    }
03870 
03871    QString hashString;
03872    hashString.sprintf("%08lx", hash);
03873 
03874    CEF = CEF + hashString;
03875 
03876    CEF = dir + "/" + CEF;
03877 
03878    return CEF;
03879 }
03880 
03881 QFile *CacheInfo::cachedFile()
03882 {
03883    const char *mode = (readWrite ? "r+" : "r");
03884 
03885    FILE *fs = fopen( CEF.latin1(), mode); 
03886    if (!fs)
03887       return 0;
03888 
03889    char buffer[401];
03890    bool ok = true;
03891 
03892   
03893   if (ok && (!fgets(buffer, 400, fs)))
03894       ok = false;
03895    if (ok && (strcmp(buffer, CACHE_REVISION) != 0))
03896       ok = false;
03897 
03898    time_t date;
03899    time_t currentDate = time(0);
03900 
03901    
03902    if (ok && (!fgets(buffer, 400, fs)))
03903       ok = false;
03904    if (ok)
03905    {
03906       int l = strlen(buffer);
03907       if (l>0)
03908          buffer[l-1] = 0; 
03909       if (m_.url.url() != buffer)
03910       {
03911          ok = false; 
03912       }
03913    }
03914 
03915    
03916    if (ok && (!fgets(buffer, 400, fs)))
03917       ok = false;
03918    if (ok)
03919    {
03920       date = (time_t) strtoul(buffer, 0, 10);
03921       if (m_maxCacheAge && (difftime(currentDate, date) > m_maxCacheAge))
03922       {
03923          m_bMustRevalidate = true;
03924          m_expireDate = currentDate;
03925       }
03926    }
03927 
03928    
03929    m_cacheExpireDateOffset = ftell(fs);
03930    if (ok && (!fgets(buffer, 400, fs)))
03931       ok = false;
03932    if (ok)
03933    {
03934       if (m_request.cache == CC_Verify)
03935       {
03936          date = (time_t) strtoul(buffer, 0, 10);
03937          
03938          if (!date || difftime(currentDate, date) >= 0)
03939             m_bMustRevalidate = true;
03940          m_expireDate = date;
03941       }
03942    }
03943 
03944    
03945    if (ok && (!fgets(buffer, 400, fs)))
03946       ok = false;
03947    if (ok)
03948    {
03949       m_etag = QString(buffer).stripWhiteSpace();
03950    }
03951 
03952    
03953    if (ok && (!fgets(buffer, 400, fs)))
03954       ok = false;
03955    if (ok)
03956    {
03957       m_lastModified = QString(buffer).stripWhiteSpace();
03958    }
03959 
03960    fclose(fs);
03961 
03962    if (ok)
03963       return fs;
03964 
03965    unlink( CEF.latin1());
03966    return 0;
03967 
03968 }
03969 
03970 void CacheInfo::flush()
03971 {
03972     cachedFile().remove();
03973 }
03974 
03975 void CacheInfo::touch()
03976 {
03977 
03978 }
03979 void CacheInfo::setExpireDate(int);
03980 void CacheInfo::setExpireTimeout(int);
03981 
03982 
03983 int CacheInfo::creationDate();
03984 int CacheInfo::expireDate();
03985 int CacheInfo::expireTimeout();
03986 #endif
03987 
03988 void Job::virtual_hook( int, void* )
03989 {  }
03990 
03991 void SimpleJob::virtual_hook( int id, void* data )
03992 { KIO::Job::virtual_hook( id, data ); }
03993 
03994 void StatJob::virtual_hook( int id, void* data )
03995 { SimpleJob::virtual_hook( id, data ); }
03996 
03997 void TransferJob::virtual_hook( int id, void* data )
03998 { SimpleJob::virtual_hook( id, data ); }
03999 
04000 void MultiGetJob::virtual_hook( int id, void* data )
04001 { TransferJob::virtual_hook( id, data ); }
04002 
04003 void MimetypeJob::virtual_hook( int id, void* data )
04004 { TransferJob::virtual_hook( id, data ); }
04005 
04006 void FileCopyJob::virtual_hook( int id, void* data )
04007 { Job::virtual_hook( id, data ); }
04008 
04009 void ListJob::virtual_hook( int id, void* data )
04010 { SimpleJob::virtual_hook( id, data ); }
04011 
04012 void CopyJob::virtual_hook( int id, void* data )
04013 { Job::virtual_hook( id, data ); }
04014 
04015 void DeleteJob::virtual_hook( int id, void* data )
04016 { Job::virtual_hook( id, data ); }
04017 
04018 
04019 #include "jobclasses.moc"