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