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(int _error, const QString& url, const QByteArray &packedArgs, const QByteArray &postData, bool showProgressInfo)
01086 : TransferJob(KURL(), CMD_SPECIAL, packedArgs, postData, showProgressInfo)
01087 {
01088 m_error = _error;
01089 m_errorText = url;
01090 }
01091
01092 };
01093
01094 TransferJob *KIO::http_post( const KURL& url, const QByteArray &postData, bool showProgressInfo )
01095 {
01096 int _error = 0;
01097
01098
01099 static const int bad_ports[] = {
01100 1,
01101 7,
01102 9,
01103 11,
01104 13,
01105 15,
01106 17,
01107 19,
01108 20,
01109 21,
01110 22,
01111 23,
01112 25,
01113 37,
01114 42,
01115 43,
01116 53,
01117 77,
01118 79,
01119 87,
01120 95,
01121 101,
01122 102,
01123 103,
01124 104,
01125 109,
01126 110,
01127 111,
01128 113,
01129 115,
01130 117,
01131 119,
01132 123,
01133 135,
01134 139,
01135 143,
01136 179,
01137 389,
01138 512,
01139 513,
01140 514,
01141 515,
01142 526,
01143 530,
01144 531,
01145 532,
01146 540,
01147 556,
01148 587,
01149 601,
01150 989,
01151 990,
01152 992,
01153 993,
01154 995,
01155 1080,
01156 2049,
01157 4045,
01158 6000,
01159 6667,
01160 0};
01161 for (int cnt=0; bad_ports[cnt]; ++cnt)
01162 if (url.port() == bad_ports[cnt])
01163 {
01164 _error = KIO::ERR_POST_DENIED;
01165 break;
01166 }
01167
01168 if( _error )
01169 {
01170 static bool override_loaded = false;
01171 static QValueList< int >* overriden_ports = NULL;
01172 if( !override_loaded )
01173 {
01174 KConfig cfg( "kio_httprc", true );
01175 overriden_ports = new QValueList< int >;
01176 *overriden_ports = cfg.readIntListEntry( "OverriddenPorts" );
01177 override_loaded = true;
01178 }
01179 for( QValueList< int >::ConstIterator it = overriden_ports->begin();
01180 it != overriden_ports->end();
01181 ++it )
01182 if( overriden_ports->contains( url.port()))
01183 _error = 0;
01184 }
01185
01186
01187 if ((url.protocol() != "http") && (url.protocol() != "https" ))
01188 _error = KIO::ERR_POST_DENIED;
01189
01190 bool redirection = false;
01191 KURL _url(url);
01192 if (_url.path().isEmpty())
01193 {
01194 redirection = true;
01195 _url.setPath("/");
01196 }
01197
01198 if (!_error && !kapp->authorizeURLAction("open", KURL(), _url))
01199 _error = KIO::ERR_ACCESS_DENIED;
01200
01201
01202 if (_error)
01203 {
01204 KIO_ARGS << (int)1 << url;
01205 TransferJob * job = new PostErrorJob(_error, url.prettyURL(), packedArgs, postData, showProgressInfo);
01206 return job;
01207 }
01208
01209
01210 KIO_ARGS << (int)1 << _url;
01211 TransferJob * job = new TransferJob( _url, CMD_SPECIAL,
01212 packedArgs, postData, showProgressInfo );
01213
01214 if (redirection)
01215 QTimer::singleShot(0, job, SLOT(slotPostRedirection()) );
01216
01217 return job;
01218 }
01219
01220
01221
01222
01223 void TransferJob::slotPostRedirection()
01224 {
01225 kdDebug(7007) << "TransferJob::slotPostRedirection(" << m_url.prettyURL() << ")" << endl;
01226
01227 emit redirection(this, m_url);
01228 }
01229
01230
01231 TransferJob *KIO::put( const KURL& url, int permissions,
01232 bool overwrite, bool resume, bool showProgressInfo )
01233 {
01234 KIO_ARGS << url << Q_INT8( overwrite ? 1 : 0 ) << Q_INT8( resume ? 1 : 0 ) << permissions;
01235 TransferJob * job = new TransferJob( url, CMD_PUT, packedArgs, QByteArray(), showProgressInfo );
01236 return job;
01237 }
01238
01240
01241 MimetypeJob::MimetypeJob( const KURL& url, int command,
01242 const QByteArray &packedArgs, bool showProgressInfo )
01243 : TransferJob(url, command, packedArgs, QByteArray(), showProgressInfo)
01244 {
01245 }
01246
01247 void MimetypeJob::start(Slave *slave)
01248 {
01249 TransferJob::start(slave);
01250 }
01251
01252
01253 void MimetypeJob::slotFinished( )
01254 {
01255
01256 if ( m_error == KIO::ERR_IS_DIRECTORY )
01257 {
01258
01259
01260
01261 kdDebug(7007) << "It is in fact a directory!" << endl;
01262 m_mimetype = QString::fromLatin1("inode/directory");
01263 emit TransferJob::mimetype( this, m_mimetype );
01264 m_error = 0;
01265 }
01266 if ( m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error )
01267 {
01268
01269 TransferJob::slotFinished();
01270 } else {
01271
01272 if (queryMetaData("permanent-redirect")=="true")
01273 emit permanentRedirection(this, m_url, m_redirectionURL);
01274 staticData.truncate(0);
01275 m_suspended = false;
01276 m_url = m_redirectionURL;
01277 m_redirectionURL = KURL();
01278 m_packedArgs.truncate(0);
01279 QDataStream stream( m_packedArgs, IO_WriteOnly );
01280 stream << m_url;
01281
01282
01283 slaveDone();
01284 Scheduler::doJob(this);
01285 }
01286 }
01287
01288 MimetypeJob *KIO::mimetype(const KURL& url, bool showProgressInfo )
01289 {
01290 KIO_ARGS << url;
01291 MimetypeJob * job = new MimetypeJob(url, CMD_MIMETYPE, packedArgs, showProgressInfo);
01292 if ( showProgressInfo )
01293 Observer::self()->stating( job, url );
01294 return job;
01295 }
01296
01298
01299
01300 class FileCopyJob::FileCopyJobPrivate
01301 {
01302 public:
01303 KIO::filesize_t m_sourceSize;
01304 SimpleJob *m_delJob;
01305 };
01306
01307
01308
01309
01310
01311
01312
01313
01314 FileCopyJob::FileCopyJob( const KURL& src, const KURL& dest, int permissions,
01315 bool move, bool overwrite, bool resume, bool showProgressInfo)
01316 : Job(showProgressInfo), m_src(src), m_dest(dest),
01317 m_permissions(permissions), m_move(move), m_overwrite(overwrite), m_resume(resume),
01318 m_totalSize(0)
01319 {
01320 if (showProgressInfo && !move)
01321 Observer::self()->slotCopying( this, src, dest );
01322 else if (showProgressInfo && move)
01323 Observer::self()->slotMoving( this, src, dest );
01324
01325
01326 m_moveJob = 0;
01327 m_copyJob = 0;
01328 m_getJob = 0;
01329 m_putJob = 0;
01330 d = new FileCopyJobPrivate;
01331 d->m_delJob = 0;
01332 d->m_sourceSize = (KIO::filesize_t) -1;
01333 QTimer::singleShot(0, this, SLOT(slotStart()));
01334 }
01335
01336 void FileCopyJob::slotStart()
01337 {
01338 if ((m_src.protocol() == m_dest.protocol()) &&
01339 (m_src.host() == m_dest.host()) &&
01340 (m_src.port() == m_dest.port()) &&
01341 (m_src.user() == m_dest.user()) &&
01342 (m_src.pass() == m_dest.pass()) &&
01343 !m_src.hasSubURL() && !m_dest.hasSubURL())
01344 {
01345 if (m_move)
01346 {
01347 m_moveJob = KIO::rename( m_src, m_dest, m_overwrite );
01348 addSubjob( m_moveJob );
01349 connectSubjob( m_moveJob );
01350 }
01351 else
01352 {
01353 startCopyJob();
01354 }
01355 }
01356 else
01357 {
01358 if (!m_move &&
01359 (m_src.isLocalFile() && KProtocolInfo::canCopyFromFile(m_dest))
01360 )
01361 {
01362 startCopyJob(m_dest);
01363 }
01364 else if (!m_move &&
01365 (m_dest.isLocalFile() && KProtocolInfo::canCopyToFile(m_src))
01366 )
01367 {
01368 startCopyJob(m_src);
01369 }
01370 else
01371 {
01372 startDataPump();
01373 }
01374 }
01375 }
01376
01377 FileCopyJob::~FileCopyJob()
01378 {
01379 delete d;
01380 }
01381
01382 void FileCopyJob::setSourceSize( off_t size )
01383 {
01384 d->m_sourceSize = size;
01385 m_totalSize = size;
01386 }
01387
01388 void FileCopyJob::setSourceSize64( KIO::filesize_t size )
01389 {
01390 d->m_sourceSize = size;
01391 m_totalSize = size;
01392 }
01393
01394 void FileCopyJob::startCopyJob()
01395 {
01396 startCopyJob(m_src);
01397 }
01398
01399 void FileCopyJob::startCopyJob(const KURL &slave_url)
01400 {
01401
01402 KIO_ARGS << m_src << m_dest << m_permissions << (Q_INT8) m_overwrite;
01403 m_copyJob = new SimpleJob(slave_url, CMD_COPY, packedArgs, false);
01404 addSubjob( m_copyJob );
01405 connectSubjob( m_copyJob );
01406 }
01407
01408 void FileCopyJob::connectSubjob( SimpleJob * job )
01409 {
01410 connect( job, SIGNAL(totalSize( KIO::Job*, KIO::filesize_t )),
01411 this, SLOT( slotTotalSize(KIO::Job*, KIO::filesize_t)) );
01412
01413 connect( job, SIGNAL(processedSize( KIO::Job*, KIO::filesize_t )),
01414 this, SLOT( slotProcessedSize(KIO::Job*, KIO::filesize_t)) );
01415
01416 connect( job, SIGNAL(percent( KIO::Job*, unsigned long )),
01417 this, SLOT( slotPercent(KIO::Job*, unsigned long)) );
01418
01419 }
01420
01421 void FileCopyJob::slotProcessedSize( KIO::Job *, KIO::filesize_t size )
01422 {
01423 setProcessedSize(size);
01424 emit processedSize( this, size );
01425 if ( size > m_totalSize ) {
01426 slotTotalSize( this, size );
01427 }
01428 emitPercent( size, m_totalSize );
01429 }
01430
01431 void FileCopyJob::slotTotalSize( KIO::Job*, KIO::filesize_t size )
01432 {
01433 m_totalSize = size;
01434 emit totalSize( this, m_totalSize );
01435 }
01436
01437 void FileCopyJob::slotPercent( KIO::Job*, unsigned long pct )
01438 {
01439 if ( pct > m_percent )
01440 {
01441 m_percent = pct;
01442 emit percent( this, m_percent );
01443 }
01444 }
01445
01446 void FileCopyJob::startDataPump()
01447 {
01448
01449
01450 m_canResume = false;
01451 m_resumeAnswerSent = false;
01452 m_getJob = 0L;
01453 m_putJob = put( m_dest, m_permissions, m_overwrite, m_resume, false );
01454
01455
01456
01457
01458 connect( m_putJob, SIGNAL(canResume(KIO::Job *, KIO::filesize_t)),
01459 SLOT( slotCanResume(KIO::Job *, KIO::filesize_t)));
01460 connect( m_putJob, SIGNAL(dataReq(KIO::Job *, QByteArray&)),
01461 SLOT( slotDataReq(KIO::Job *, QByteArray&)));
01462 addSubjob( m_putJob );
01463 }
01464
01465 void FileCopyJob::slotCanResume( KIO::Job* job, KIO::filesize_t offset )
01466 {
01467 if ( job == m_putJob )
01468 {
01469
01470 if (offset)
01471 {
01472 RenameDlg_Result res = R_RESUME;
01473
01474 if (!KProtocolManager::autoResume())
01475 {
01476 QString newPath;
01477 KIO::Job* job = ( !m_progressId && parentJob() ) ? parentJob() : this;
01478
01479 res = Observer::self()->open_RenameDlg(
01480 job, i18n("File Already Exists"),
01481 m_src.prettyURL(0, KURL::StripFileProtocol),
01482 m_dest.prettyURL(0, KURL::StripFileProtocol),
01483 (RenameDlg_Mode) (M_OVERWRITE | M_RESUME | M_NORENAME), newPath,
01484 d->m_sourceSize, offset );
01485 }
01486
01487 if ( res == R_OVERWRITE )
01488 offset = 0;
01489 else if ( res == R_CANCEL )
01490 {
01491 m_putJob->kill(true);
01492 m_error = ERR_USER_CANCELED;
01493 emitResult();
01494 return;
01495 }
01496 }
01497 else
01498 m_resumeAnswerSent = true;
01499
01500 m_getJob = get( m_src, false, false );
01501
01502 m_getJob->addMetaData( "errorPage", "false" );
01503 m_getJob->addMetaData( "AllowCompressedPage", "false" );
01504
01505 if ( d->m_sourceSize != (KIO::filesize_t)-1 )
01506 m_getJob->slotTotalSize( d->m_sourceSize );
01507 if (offset)
01508 {
01509
01510 m_getJob->addMetaData( "resume", KIO::number(offset) );
01511
01512
01513 connect( m_getJob, SIGNAL(canResume(KIO::Job *, KIO::filesize_t)),
01514 SLOT( slotCanResume(KIO::Job *, KIO::filesize_t)));
01515 }
01516 m_putJob->slave()->setOffset( offset );
01517
01518 m_putJob->suspend();
01519 addSubjob( m_getJob );
01520 connectSubjob( m_getJob );
01521 m_getJob->resume();
01522
01523 connect( m_getJob, SIGNAL(data(KIO::Job *, const QByteArray&)),
01524 SLOT( slotData(KIO::Job *, const QByteArray&)));
01525 }
01526 else if ( job == m_getJob )
01527 {
01528
01529 m_canResume = true;
01530
01531
01532 m_getJob->slave()->setOffset( m_putJob->slave()->offset() );
01533 }
01534 else
01535 kdWarning(7007) << "FileCopyJob::slotCanResume from unknown job=" << job
01536 << " m_getJob=" << m_getJob << " m_putJob=" << m_putJob << endl;
01537 }
01538
01539 void FileCopyJob::slotData( KIO::Job * , const QByteArray &data)
01540 {
01541
01542
01543 assert(m_putJob);
01544 m_getJob->suspend();
01545 m_putJob->resume();
01546 m_buffer = data;
01547
01548
01549
01550 if (!m_resumeAnswerSent)
01551 {
01552 m_resumeAnswerSent = true;
01553
01554 m_putJob->slave()->sendResumeAnswer( m_canResume );
01555 }
01556 }
01557
01558 void FileCopyJob::slotDataReq( KIO::Job * , QByteArray &data)
01559 {
01560
01561 if (!m_resumeAnswerSent && !m_getJob)
01562 {
01563
01564 m_error = ERR_INTERNAL;
01565 m_errorText = "'Put' job didn't send canResume or 'Get' job didn't send data!";
01566 m_putJob->kill(true);
01567 emitResult();
01568 return;
01569 }
01570 if (m_getJob)
01571 {
01572 m_getJob->resume();
01573 m_putJob->suspend();
01574 }
01575 data = m_buffer;
01576 m_buffer = QByteArray();
01577 }
01578
01579 void FileCopyJob::slotResult( KIO::Job *job)
01580 {
01581
01582
01583 if ( job->error() )
01584 {
01585 if ((job == m_moveJob) && (job->error() == ERR_UNSUPPORTED_ACTION))
01586 {
01587 m_moveJob = 0;
01588 startCopyJob();
01589 removeSubjob(job);
01590 return;
01591 }
01592 else if ((job == m_copyJob) && (job->error() == ERR_UNSUPPORTED_ACTION))
01593 {
01594 m_copyJob = 0;
01595 startDataPump();
01596 removeSubjob(job);
01597 return;
01598 }
01599 else if (job == m_getJob)
01600 {
01601 m_getJob = 0L;
01602 if (m_putJob)
01603 m_putJob->kill(true);
01604 }
01605 else if (job == m_putJob)
01606 {
01607 m_putJob = 0L;
01608 if (m_getJob)
01609 m_getJob->kill(true);
01610 }
01611 m_error = job->error();
01612 m_errorText = job->errorText();
01613 emitResult();
01614 return;
01615 }
01616
01617 if (job == m_moveJob)
01618 {
01619 m_moveJob = 0;
01620 }
01621
01622 if (job == m_copyJob)
01623 {
01624 m_copyJob = 0;
01625 if (m_move)
01626 {
01627 d->m_delJob = file_delete( m_src, false );
01628 addSubjob(d->m_delJob);
01629 }
01630 }
01631
01632 if (job == m_getJob)
01633 {
01634 m_getJob = 0;
01635 if (m_putJob)
01636 m_putJob->resume();
01637 }
01638
01639 if (job == m_putJob)
01640 {
01641
01642 m_putJob = 0;
01643 if (m_getJob)
01644 {
01645 kdWarning(7007) << "WARNING ! Get still going on..." << endl;
01646 m_getJob->resume();
01647 }
01648 if (m_move)
01649 {
01650 d->m_delJob = file_delete( m_src, false );
01651 addSubjob(d->m_delJob);
01652 }
01653 }
01654
01655 if (job == d->m_delJob)
01656 {
01657 d->m_delJob = 0;
01658 }
01659 removeSubjob(job);
01660 }
01661
01662 FileCopyJob *KIO::file_copy( const KURL& src, const KURL& dest, int permissions,
01663 bool overwrite, bool resume, bool showProgressInfo)
01664 {
01665 return new FileCopyJob( src, dest, permissions, false, overwrite, resume, showProgressInfo );
01666 }
01667
01668 FileCopyJob *KIO::file_move( const KURL& src, const KURL& dest, int permissions,
01669 bool overwrite, bool resume, bool showProgressInfo)
01670 {
01671 return new FileCopyJob( src, dest, permissions, true, overwrite, resume, showProgressInfo );
01672 }
01673
01674 SimpleJob *KIO::file_delete( const KURL& src, bool showProgressInfo)
01675 {
01676 KIO_ARGS << src << Q_INT8(true);
01677 return new SimpleJob(src, CMD_DEL, packedArgs, showProgressInfo );
01678 }
01679
01681
01682
01683 ListJob::ListJob(const KURL& u, bool showProgressInfo, bool _recursive, QString _prefix, bool _includeHidden) :
01684 SimpleJob(u, CMD_LISTDIR, QByteArray(), showProgressInfo),
01685 recursive(_recursive), includeHidden(_includeHidden), prefix(_prefix), m_processedEntries(0)
01686 {
01687
01688
01689 QDataStream stream( m_packedArgs, IO_WriteOnly );
01690 stream << u;
01691 }
01692
01693 void ListJob::slotListEntries( const KIO::UDSEntryList& list )
01694 {
01695
01696 m_processedEntries += list.count();
01697 slotProcessedSize( m_processedEntries );
01698
01699 if (recursive) {
01700 UDSEntryListConstIterator it = list.begin();
01701 UDSEntryListConstIterator end = list.end();
01702
01703 for (; it != end; ++it) {
01704 bool isDir = false;
01705 bool isLink = false;
01706 QString filename;
01707
01708 UDSEntry::ConstIterator it2 = (*it).begin();
01709 UDSEntry::ConstIterator end2 = (*it).end();
01710 for( ; it2 != end2; it2++ ) {
01711 switch( (*it2).m_uds ) {
01712 case UDS_FILE_TYPE:
01713 isDir = S_ISDIR((*it2).m_long);
01714 break;
01715 case UDS_NAME:
01716 filename = (*it2).m_str;
01717 break;
01718 case UDS_LINK_DEST:
01719
01720 isLink = !(*it2).m_str.isEmpty();
01721 break;
01722 default:
01723 break;
01724 }
01725 }
01726 if (isDir && !isLink) {
01727
01728 if (filename != ".." && filename != "." && (includeHidden || filename[0] != '.')) {
01729 KURL newone = url();
01730 newone.addPath(filename);
01731 ListJob *job = new ListJob(newone,
01732 false ,
01733 true ,
01734 prefix + filename + "/",
01735 includeHidden);
01736 Scheduler::scheduleJob(job);
01737 connect(job, SIGNAL(entries( KIO::Job *,
01738 const KIO::UDSEntryList& )),
01739 SLOT( gotEntries( KIO::Job*,
01740 const KIO::UDSEntryList& )));
01741 addSubjob(job);
01742 }
01743 }
01744 }
01745 }
01746
01747
01748
01749
01750 if (prefix.isNull() && includeHidden) {
01751 emit entries(this, list);
01752 } else {
01753
01754 UDSEntryList newlist;
01755
01756 UDSEntryListConstIterator it = list.begin();
01757 UDSEntryListConstIterator end = list.end();
01758 for (; it != end; ++it) {
01759
01760 UDSEntry newone = *it;
01761 UDSEntry::Iterator it2 = newone.begin();
01762 QString filename;
01763 for( ; it2 != newone.end(); it2++ ) {
01764 if ((*it2).m_uds == UDS_NAME) {
01765 filename = (*it2).m_str;
01766 (*it2).m_str = prefix + filename;
01767 }
01768 }
01769
01770
01771 if ( (prefix.isNull() || (filename != ".." && filename != ".") )
01772 && (includeHidden || (filename[0] != '.') ) )
01773 newlist.append(newone);
01774 }
01775
01776 emit entries(this, newlist);
01777 }
01778 }
01779
01780 void ListJob::gotEntries(KIO::Job *, const KIO::UDSEntryList& list )
01781 {
01782
01783 emit entries(this, list);
01784 }
01785
01786 void ListJob::slotResult( KIO::Job * job )
01787 {
01788
01789
01790 removeSubjob( job );
01791 }
01792
01793 void ListJob::slotRedirection( const KURL & url )
01794 {
01795 if (!kapp->authorizeURLAction("redirect", m_url, url))
01796 {
01797 kdWarning(7007) << "ListJob: Redirection from " << m_url.prettyURL() << " to " << url.prettyURL() << " REJECTED!" << endl;
01798 return;
01799 }
01800 m_redirectionURL = url;
01801 if (m_url.hasUser() && !url.hasUser() && (m_url.host().lower() == url.host().lower()))
01802 m_redirectionURL.setUser(m_url.user());
01803 emit redirection( this, url );
01804 }
01805
01806 void ListJob::slotFinished()
01807 {
01808 if ( m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error )
01809 {
01810
01811 SimpleJob::slotFinished();
01812 } else {
01813
01814 if (queryMetaData("permanent-redirect")=="true")
01815 emit permanentRedirection(this, m_url, m_redirectionURL);
01816 m_url = m_redirectionURL;
01817 m_redirectionURL = KURL();
01818 m_packedArgs.truncate(0);
01819 QDataStream stream( m_packedArgs, IO_WriteOnly );
01820 stream << m_url;
01821
01822
01823 slaveDone();
01824 Scheduler::doJob(this);
01825 }
01826 }
01827
01828 void ListJob::slotMetaData( const KIO::MetaData &_metaData) {
01829 SimpleJob::slotMetaData(_metaData);
01830 storeSSLSessionFromJob(m_redirectionURL);
01831 }
01832
01833 ListJob *KIO::listDir( const KURL& url, bool showProgressInfo, bool includeHidden )
01834 {
01835 ListJob * job = new ListJob(url, showProgressInfo,false,QString::null,includeHidden);
01836 return job;
01837 }
01838
01839 ListJob *KIO::listRecursive( const KURL& url, bool showProgressInfo, bool includeHidden )
01840 {
01841 ListJob * job = new ListJob(url, showProgressInfo, true,QString::null,includeHidden);
01842 return job;
01843 }
01844
01845 void ListJob::setUnrestricted(bool unrestricted)
01846 {
01847 if (unrestricted)
01848 extraFlags() |= EF_ListJobUnrestricted;
01849 else
01850 extraFlags() &= ~EF_ListJobUnrestricted;
01851 }
01852
01853 void ListJob::start(Slave *slave)
01854 {
01855 if (!kapp->authorizeURLAction("list", m_url, m_url) && !(extraFlags() & EF_ListJobUnrestricted))
01856 {
01857 m_error = ERR_ACCESS_DENIED;
01858 m_errorText = m_url.url();
01859 QTimer::singleShot(0, this, SLOT(slotFinished()) );
01860 return;
01861 }
01862 connect( slave, SIGNAL( listEntries( const KIO::UDSEntryList& )),
01863 SLOT( slotListEntries( const KIO::UDSEntryList& )));
01864 connect( slave, SIGNAL( totalSize( KIO::filesize_t ) ),
01865 SLOT( slotTotalSize( KIO::filesize_t ) ) );
01866 connect( slave, SIGNAL( redirection(const KURL &) ),
01867 SLOT( slotRedirection(const KURL &) ) );
01868
01869 SimpleJob::start(slave);
01870 }
01871
01872
01873 CopyJob::CopyJob( const KURL::List& src, const KURL& dest, CopyMode mode, bool asMethod, bool showProgressInfo )
01874 : Job(showProgressInfo), m_mode(mode), m_asMethod(asMethod),
01875 destinationState(DEST_NOT_STATED), state(STATE_STATING),
01876 m_totalSize(0), m_processedSize(0), m_fileProcessedSize(0),
01877 m_processedFiles(0), m_processedDirs(0),
01878 m_srcList(src), m_currentStatSrc(m_srcList.begin()),
01879 m_bCurrentOperationIsLink(false), m_bSingleFileCopy(false), m_bOnlyRenames(mode==Move),
01880 m_dest(dest), m_bAutoSkip( false ), m_bOverwriteAll( false ),
01881 m_conflictError(0), m_reportTimer(0)
01882 {
01883 if ( showProgressInfo ) {
01884 connect( this, SIGNAL( totalFiles( KIO::Job*, unsigned long ) ),
01885 Observer::self(), SLOT( slotTotalFiles( KIO::Job*, unsigned long ) ) );
01886
01887 connect( this, SIGNAL( totalDirs( KIO::Job*, unsigned long ) ),
01888 Observer::self(), SLOT( slotTotalDirs( KIO::Job*, unsigned long ) ) );
01889 }
01890 QTimer::singleShot(0, this, SLOT(slotStart()));
01904 }
01905
01906 void CopyJob::slotStart()
01907 {
01913 m_reportTimer = new QTimer(this);
01914
01915 connect(m_reportTimer,SIGNAL(timeout()),this,SLOT(slotReport()));
01916 m_reportTimer->start(REPORT_TIMEOUT,false);
01917
01918
01919 KIO::Job * job = KIO::stat( m_dest, false, 2, false );
01920
01921 addSubjob(job);
01922 }
01923
01924 void CopyJob::slotResultStating( Job *job )
01925 {
01926
01927
01928 if (job->error() && destinationState != DEST_NOT_STATED )
01929 {
01930 KURL srcurl = ((SimpleJob*)job)->url();
01931 if ( !srcurl.isLocalFile() )
01932 {
01933
01934
01935
01936 kdDebug(7007) << "Error while stating source. Activating hack" << endl;
01937 subjobs.remove( job );
01938 assert ( subjobs.isEmpty() );
01939 struct CopyInfo info;
01940 info.permissions = (mode_t) -1;
01941 info.mtime = (time_t) -1;
01942 info.ctime = (time_t) -1;
01943 info.size = (KIO::filesize_t)-1;
01944 info.uSource = srcurl;
01945 info.uDest = m_dest;
01946
01947 if ( destinationState == DEST_IS_DIR && !m_asMethod )
01948 info.uDest.addPath( srcurl.fileName() );
01949
01950 files.append( info );
01951 ++m_currentStatSrc;
01952 statNextSrc();
01953 return;
01954 }
01955
01956 Job::slotResult( job );
01957 return;
01958 }
01959
01960
01961 UDSEntry entry = ((StatJob*)job)->statResult();
01962 bool bDir = false;
01963 bool bLink = false;
01964 UDSEntry::ConstIterator it2 = entry.begin();
01965 for( ; it2 != entry.end(); it2++ ) {
01966 if ( ((*it2).m_uds) == UDS_FILE_TYPE )
01967 bDir = S_ISDIR( (mode_t)(*it2).m_long );
01968 else if ( ((*it2).m_uds) == UDS_LINK_DEST )
01969 bLink = !((*it2).m_str.isEmpty());
01970 }
01971
01972 if ( destinationState == DEST_NOT_STATED )
01973
01974 {
01975 if (job->error())
01976 destinationState = DEST_DOESNT_EXIST;
01977 else {
01978
01979 destinationState = bDir ? DEST_IS_DIR : DEST_IS_FILE;
01980
01981 }
01982 subjobs.remove( job );
01983 assert ( subjobs.isEmpty() );
01984
01985
01986 statNextSrc();
01987 return;
01988 }
01989
01990 m_currentDest = m_dest;
01991
01992 UDSEntryList lst;
01993 lst.append(entry);
01994
01995
01996
01997
01998
01999
02000
02001
02002
02003
02004
02005
02006
02007 m_bCurrentSrcIsDir = false;
02008 slotEntries(job, lst);
02009
02010 KURL srcurl = ((SimpleJob*)job)->url();
02011
02012 subjobs.remove( job );
02013 assert ( subjobs.isEmpty() );
02014
02015 if ( bDir
02016 && !bLink
02017 && m_mode != Link )
02018 {
02019
02020
02021 m_bCurrentSrcIsDir = true;
02022 if ( destinationState == DEST_IS_DIR )
02023 {
02024 if ( !m_asMethod )
02025
02026 m_currentDest.addPath( srcurl.fileName() );
02027 }
02028 else if ( destinationState == DEST_IS_FILE )
02029 {
02030 m_error = ERR_IS_FILE;
02031 m_errorText = m_dest.prettyURL();
02032 emitResult();
02033 return;
02034 }
02035 else
02036 {
02037
02038
02039
02040
02041 destinationState = DEST_IS_DIR;
02042 }
02043
02044 startListing( srcurl );
02045 }
02046 else
02047 {
02048
02049 ++m_currentStatSrc;
02050 statNextSrc();
02051 }
02052 }
02053
02054 void CopyJob::slotReport()
02055 {
02056
02057 Observer * observer = m_progressId ? Observer::self() : 0L;
02058 switch (state) {
02059 case STATE_COPYING_FILES:
02060 emit processedFiles( this, m_processedFiles );
02061 if (observer) observer->slotProcessedFiles(this,m_processedFiles);
02062 if (m_mode==Move)
02063 {
02064 if (observer) observer->slotMoving( this, m_currentSrcURL,m_currentDestURL);
02065 emit moving( this, m_currentSrcURL, m_currentDestURL);
02066 }
02067 else if (m_mode==Link)
02068 {
02069 if (observer) observer->slotCopying( this, m_currentSrcURL, m_currentDestURL );
02070 emit linking( this, m_currentSrcURL.path(), m_currentDestURL );
02071 }
02072 else
02073 {
02074 if (observer) observer->slotCopying( this, m_currentSrcURL, m_currentDestURL );
02075 emit copying( this, m_currentSrcURL, m_currentDestURL );
02076 };
02077 break;
02078
02079 case STATE_CREATING_DIRS:
02080 if (observer) {
02081 observer->slotProcessedDirs( this, m_processedDirs );
02082 observer->slotCreatingDir( this,m_currentDestURL);
02083 }
02084 emit processedDirs( this, m_processedDirs );
02085 emit creatingDir( this, m_currentDestURL );
02086 break;
02087
02088 case STATE_STATING:
02089 case STATE_LISTING:
02090 if (observer) observer->slotCopying( this, m_currentSrcURL, m_currentDestURL );
02091 emit totalSize( this, m_totalSize );
02092 emit totalFiles( this, files.count() );
02093 emit totalDirs( this, dirs.count() );
02094 if (!dirs.isEmpty())
02095 emit aboutToCreate( this, dirs );
02096 if (!files.isEmpty())
02097 emit aboutToCreate( this, files );
02098 break;
02099
02100 default:
02101 break;
02102 }
02103 }
02104
02105 void CopyJob::slotEntries(KIO::Job* job, const UDSEntryList& list)
02106 {
02107 UDSEntryListConstIterator it = list.begin();
02108 UDSEntryListConstIterator end = list.end();
02109 for (; it != end; ++it) {
02110 UDSEntry::ConstIterator it2 = (*it).begin();
02111 struct CopyInfo info;
02112 info.permissions = -1;
02113 info.mtime = (time_t) -1;
02114 info.ctime = (time_t) -1;
02115 info.size = (KIO::filesize_t)-1;
02116 QString relName;
02117 bool isDir = false;
02118 for( ; it2 != (*it).end(); it2++ ) {
02119 switch ((*it2).m_uds) {
02120 case UDS_FILE_TYPE:
02121
02122 isDir = S_ISDIR( (mode_t)((*it2).m_long) );
02123 break;
02124 case UDS_NAME:
02125 relName = (*it2).m_str;
02126 break;
02127 case UDS_LINK_DEST:
02128 info.linkDest = (*it2).m_str;
02129 break;
02130 case UDS_ACCESS:
02131 info.permissions = ((*it2).m_long);
02132 break;
02133 case UDS_SIZE:
02134 info.size = (KIO::filesize_t)((*it2).m_long);
02135 m_totalSize += info.size;
02136 break;
02137 case UDS_MODIFICATION_TIME:
02138 info.mtime = (time_t)((*it2).m_long);
02139 break;
02140 case UDS_CREATION_TIME:
02141 info.ctime = (time_t)((*it2).m_long);
02142 default:
02143 break;
02144 }
02145 }
02146 if (relName != ".." && relName != ".")
02147 {
02148
02149 info.uSource = ((SimpleJob *)job)->url();
02150 if ( m_bCurrentSrcIsDir )
02151 info.uSource.addPath( relName );
02152 info.uDest = m_currentDest;
02153
02154
02155 if ( destinationState == DEST_IS_DIR &&
02156
02157
02158 ( ! ( m_asMethod && state == STATE_STATING ) ) )
02159 {
02160
02161
02162
02163 if ( relName.isEmpty() )
02164 info.uDest.addPath( KIO::encodeFileName( info.uSource.prettyURL() ) );
02165 else
02166 info.uDest.addPath( relName );
02167 }
02168
02169
02170 if ( info.linkDest.isEmpty() && (isDir ) && m_mode != Link )
02171 {
02172 dirs.append( info );
02173 if (m_mode == Move)
02174 dirsToRemove.append( info.uSource );
02175 }
02176 else {
02177 files.append( info );
02178 }
02179 }
02180 }
02181 }
02182
02183 void CopyJob::statNextSrc()
02184 {
02185 if ( m_currentStatSrc != m_srcList.end() )
02186 {
02187 m_currentSrcURL = (*m_currentStatSrc);
02188 if ( m_mode == Link )
02189 {
02190
02191 m_currentDest = m_dest;
02192 struct CopyInfo info;
02193 info.permissions = -1;
02194 info.mtime = (time_t) -1;
02195 info.ctime = (time_t) -1;
02196 info.size = (KIO::filesize_t)-1;
02197 info.uSource = m_currentSrcURL;
02198 info.uDest = m_currentDest;
02199
02200 if ( destinationState == DEST_IS_DIR && !m_asMethod )
02201 {
02202 if (
02203 (m_currentSrcURL.protocol() == info.uDest.protocol()) &&
02204 (m_currentSrcURL.host() == info.uDest.host()) &&
02205 (m_currentSrcURL.port() == info.uDest.port()) &&
02206 (m_currentSrcURL.user() == info.uDest.user()) &&
02207 (m_currentSrcURL.pass() == info.uDest.pass()) )
02208 {
02209
02210 info.uDest.addPath( m_currentSrcURL.fileName() );
02211 }
02212 else
02213 {
02214
02215
02216
02217 info.uDest.addPath( KIO::encodeFileName( m_currentSrcURL.prettyURL() )+".desktop" );
02218 }
02219 }
02220 files.append( info );
02221 ++m_currentStatSrc;
02222 statNextSrc();
02223 }
02224
02225 else if ( m_mode == Move &&
02226 (m_currentSrcURL.protocol() == m_dest.protocol()) &&
02227 (m_currentSrcURL.host() == m_dest.host()) &&
02228 (m_currentSrcURL.port() == m_dest.port()) &&
02229 (m_currentSrcURL.user() == m_dest.user()) &&
02230 (m_currentSrcURL.pass() == m_dest.pass()) )
02231 {
02232 KURL dest = m_dest;
02233
02234 if ( destinationState == DEST_IS_DIR && !m_asMethod )
02235 dest.addPath( m_currentSrcURL.fileName() );
02236 kdDebug(7007) << "This seems to be a suitable case for trying to rename before stat+[list+]copy+del" << endl;
02237 state = STATE_RENAMING;
02238
02239 struct CopyInfo info;
02240 info.permissions = -1;
02241 info.mtime = (time_t) -1;
02242 info.ctime = (time_t) -1;
02243 info.size = (KIO::filesize_t)-1;
02244 info.uSource = m_currentSrcURL;
02245 info.uDest = dest;
02246 QValueList<CopyInfo> files;
02247 files.append(info);
02248 emit aboutToCreate( this, files );
02249
02250 SimpleJob * newJob = KIO::rename( m_currentSrcURL, dest, false );
02251 Scheduler::scheduleJob(newJob);
02252 addSubjob( newJob );
02253 if ( m_currentSrcURL.directory() != dest.directory() )
02254 m_bOnlyRenames = false;
02255 }
02256 else
02257 {
02258
02259 if (m_mode == Move && !KProtocolInfo::supportsDeleting(m_currentSrcURL)) {
02260 KMessageBox::information( 0, buildErrorString(ERR_CANNOT_DELETE, m_currentSrcURL.prettyURL()));
02261 ++m_currentStatSrc;
02262 statNextSrc();
02263 return;
02264 }
02265
02266 Job * job = KIO::stat( m_currentSrcURL, true, 2, false );
02267
02268 state = STATE_STATING;
02269 addSubjob(job);
02270 m_currentDestURL=m_dest;
02271 m_bOnlyRenames = false;
02272 }
02273 } else
02274 {
02275
02276
02277 state = STATE_STATING;
02278 slotReport();
02279
02280 m_bSingleFileCopy = ( files.count() == 1 && dirs.isEmpty() );
02281
02282 state = STATE_CREATING_DIRS;
02283 createNextDir();
02284 }
02285 }
02286
02287
02288 void CopyJob::startListing( const KURL & src )
02289 {
02290 state = STATE_LISTING;
02291 ListJob * newjob = listRecursive( src, false );
02292 newjob->setUnrestricted(true);
02293 connect(newjob, SIGNAL(entries( KIO::Job *,
02294 const KIO::UDSEntryList& )),
02295 SLOT( slotEntries( KIO::Job*,
02296 const KIO::UDSEntryList& )));
02297 addSubjob( newjob );
02298 }
02299
02300 void CopyJob::skip( const KURL & sourceUrl )
02301 {
02302
02303
02304
02305 KURL::List::Iterator sit = m_srcList.find( sourceUrl );
02306 if ( sit != m_srcList.end() )
02307 {
02308
02309 m_srcList.remove( sit );
02310 }
02311 dirsToRemove.remove( sourceUrl );
02312 }
02313
02314 void CopyJob::slotResultCreatingDirs( Job * job )
02315 {
02316
02317 QValueList<CopyInfo>::Iterator it = dirs.begin();
02318
02319 if ( job->error() )
02320 {
02321 m_conflictError = job->error();
02322 if ( (m_conflictError == ERR_DIR_ALREADY_EXIST)
02323 || (m_conflictError == ERR_FILE_ALREADY_EXIST) )
02324 {
02325 KURL oldURL = ((SimpleJob*)job)->url();
02326
02327 if ( m_bAutoSkip ) {
02328
02329 m_skipList.append( oldURL.path( 1 ) );
02330 skip( oldURL );
02331 dirs.remove( it );
02332 } else {
02333
02334 bool bOverwrite = m_bOverwriteAll;
02335 QString destFile = (*it).uDest.path();
02336 QStringList::Iterator sit = m_overwriteList.begin();
02337 for( ; sit != m_overwriteList.end() && !bOverwrite; sit++ )
02338 if ( *sit == destFile.left( (*sit).length() ) )
02339 bOverwrite = true;
02340 if ( bOverwrite ) {
02341 emit copyingDone( this, ( *it ).uSource, ( *it ).uDest, true , false );
02342 dirs.remove( it );
02343 } else {
02344 assert( ((SimpleJob*)job)->url().url() == (*it).uDest.url() );
02345 subjobs.remove( job );
02346 assert ( subjobs.isEmpty() );
02347
02348
02349 KURL existingDest( (*it).uDest );
02350 SimpleJob * newJob = KIO::stat( existingDest, false, 2, false );
02351 Scheduler::scheduleJob(newJob);
02352 kdDebug(7007) << "KIO::stat for resolving conflict on " << existingDest.prettyURL() << endl;
02353 state = STATE_CONFLICT_CREATING_DIRS;
02354 addSubjob(newJob);
02355 return;
02356 }
02357 }
02358 }
02359 else
02360 {
02361
02362 Job::slotResult( job );
02363 return;
02364 }
02365 }
02366 else
02367 {
02368
02369 emit copyingDone( this, (*it).uSource, (*it).uDest, true, false );
02370 dirs.remove( it );
02371 }
02372
02373 m_processedDirs++;
02374
02375 subjobs.remove( job );
02376 assert ( subjobs.isEmpty() );
02377 createNextDir();
02378 }
02379
02380 void CopyJob::slotResultConflictCreatingDirs( KIO::Job * job )
02381 {
02382
02383
02384
02385 QValueList<CopyInfo>::Iterator it = dirs.begin();
02386
02387 time_t destmtime = (time_t)-1;
02388 time_t destctime = (time_t)-1;
02389 KIO::filesize_t destsize = 0;
02390 UDSEntry entry = ((KIO::StatJob*)job)->statResult();
02391 KIO::UDSEntry::ConstIterator it2 = entry.begin();
02392 for( ; it2 != entry.end(); it2++ ) {
02393 switch ((*it2).m_uds) {
02394 case UDS_MODIFICATION_TIME:
02395 destmtime = (time_t)((*it2).m_long);
02396 break;
02397 case UDS_CREATION_TIME:
02398 destctime = (time_t)((*it2).m_long);
02399 break;
02400 case UDS_SIZE:
02401 destsize = (*it2).m_long;
02402 break;
02403 }
02404 }
02405 subjobs.remove( job );
02406 assert ( subjobs.isEmpty() );
02407
02408
02409 RenameDlg_Mode mode = (RenameDlg_Mode)( M_MULTI | M_SKIP );
02410
02411 if ( m_conflictError == ERR_DIR_ALREADY_EXIST )
02412 mode = (RenameDlg_Mode)( mode | (((*it).uSource == (*it).uDest) ? M_OVERWRITE_ITSELF : M_OVERWRITE ));
02413
02414 QString existingDest = (*it).uDest.path();
02415 QString newPath;
02416 if (m_reportTimer)
02417 m_reportTimer->stop();
02418 RenameDlg_Result r = Observer::self()->open_RenameDlg( this, i18n("Folder Already Exists"),
02419 (*it).uSource.prettyURL(0, KURL::StripFileProtocol),
02420 (*it).uDest.prettyURL(0, KURL::StripFileProtocol),
02421 mode, newPath,
02422 (*it).size, destsize,
02423 (*it).ctime, destctime,
02424 (*it).mtime, destmtime );
02425 if (m_reportTimer)
02426 m_reportTimer->start(REPORT_TIMEOUT,false);
02427 switch ( r ) {
02428 case R_CANCEL:
02429 m_error = ERR_USER_CANCELED;
02430 emitResult();
02431 return;
02432 case R_RENAME:
02433 {
02434 QString oldPath = (*it).uDest.path( 1 );
02435 KURL newUrl( (*it).uDest );
02436 newUrl.setPath( newPath );
02437 emit renamed( this, (*it).uDest, newUrl );
02438
02439
02440 (*it).uDest.setPath( newUrl.path( -1 ) );
02441 newPath = newUrl.path( 1 );
02442 QValueList<CopyInfo>::Iterator renamedirit = it;
02443 ++renamedirit;
02444
02445 for( ; renamedirit != dirs.end() ; ++renamedirit )
02446 {
02447 QString path = (*renamedirit).uDest.path();
02448 if ( path.left(oldPath.length()) == oldPath ) {
02449 QString n = path;
02450 n.replace( 0, oldPath.length(), newPath );
02451 kdDebug(7007) << "dirs list: " << (*renamedirit).uSource.path()
02452 << " was going to be " << path
02453 << ", changed into " << n << endl;
02454 (*renamedirit).uDest.setPath( n );
02455 }
02456 }
02457
02458 QValueList<CopyInfo>::Iterator renamefileit = files.begin();
02459 for( ; renamefileit != files.end() ; ++renamefileit )
02460 {
02461 QString path = (*renamefileit).uDest.path();
02462 if ( path.left(oldPath.length()) == oldPath ) {
02463 QString n = path;
02464 n.replace( 0, oldPath.length(), newPath );
02465 kdDebug(7007) << "files list: " << (*renamefileit).uSource.path()
02466 << " was going to be " << path
02467 << ", changed into " << n << endl;
02468 (*renamefileit).uDest.setPath( n );
02469 }
02470 }
02471 if (!dirs.isEmpty())
02472 emit aboutToCreate( this, dirs );
02473 if (!files.isEmpty())
02474 emit aboutToCreate( this, files );
02475 }
02476 break;
02477 case R_AUTO_SKIP:
02478 m_bAutoSkip = true;
02479
02480 case R_SKIP:
02481 m_skipList.append( existingDest );
02482 skip( (*it).uSource );
02483
02484 dirs.remove( it );
02485 m_processedDirs++;
02486 break;
02487 case R_OVERWRITE:
02488 m_overwriteList.append( existingDest );
02489 emit copyingDone( this, ( *it ).uSource, ( *it ).uDest, true , false );
02490
02491 dirs.remove( it );
02492 m_processedDirs++;
02493 break;
02494 case R_OVERWRITE_ALL:
02495 m_bOverwriteAll = true;
02496 emit copyingDone( this, ( *it ).uSource, ( *it ).uDest, true , false );
02497
02498 dirs.remove( it );
02499 m_processedDirs++;
02500 break;
02501 default:
02502 assert( 0 );
02503 }
02504 state = STATE_CREATING_DIRS;
02505
02506 createNextDir();
02507 }
02508
02509 void CopyJob::createNextDir()
02510 {
02511 KURL udir;
02512 if ( !dirs.isEmpty() )
02513 {
02514
02515 QValueList<CopyInfo>::Iterator it = dirs.begin();
02516
02517 while( it != dirs.end() && udir.isEmpty() )
02518 {
02519 QString dir = (*it).uDest.path();
02520 bool bCreateDir = true;
02521
02522 QStringList::Iterator sit = m_skipList.begin();
02523 for( ; sit != m_skipList.end() && bCreateDir; sit++ )
02524
02525 if ( *sit == dir.left( (*sit).length() ) )
02526 bCreateDir = false;
02527
02528 if ( !bCreateDir ) {
02529 dirs.remove( it );
02530 it = dirs.begin();
02531 } else
02532 udir = (*it).uDest;
02533 }
02534 }
02535 if ( !udir.isEmpty() )
02536 {
02537
02538
02539 KIO::SimpleJob *newjob = KIO::mkdir( udir, -1 );
02540 Scheduler::scheduleJob(newjob);
02541
02542 m_currentDestURL = udir;
02543
02544 addSubjob(newjob);
02545 return;
02546 }
02547 else
02548 {
02549 state = STATE_COPYING_FILES;
02550 m_processedFiles++;
02551 copyNextFile();
02552 }
02553 }
02554
02555 void CopyJob::slotResultCopyingFiles( Job * job )
02556 {
02557
02558 QValueList<CopyInfo>::Iterator it = files.begin();
02559 if ( job->error() )
02560 {
02561
02562 if ( m_bAutoSkip )
02563 {
02564 skip( (*it).uSource );
02565 files.remove( it );
02566 }
02567 else
02568 {
02569 m_conflictError = job->error();
02570
02571 if ( ( m_conflictError == ERR_FILE_ALREADY_EXIST )
02572 || ( m_conflictError == ERR_DIR_ALREADY_EXIST ) )
02573 {
02574 subjobs.remove( job );
02575 assert ( subjobs.isEmpty() );
02576
02577 KURL existingFile( (*it).uDest );
02578 SimpleJob * newJob = KIO::stat( existingFile, false, 2, false );
02579 Scheduler::scheduleJob(newJob);
02580 kdDebug(7007) << "KIO::stat for resolving conflict on " << existingFile.prettyURL() << endl;
02581 state = STATE_CONFLICT_COPYING_FILES;
02582 addSubjob(newJob);
02583 return;
02584 }
02585 else
02586 {
02587 if ( m_bCurrentOperationIsLink && job->inherits( "KIO::DeleteJob" ) )
02588 {
02589
02590
02591 files.remove( it );
02592 } else {
02593
02594 slotResultConflictCopyingFiles( job );
02595 return;
02596 }
02597 }
02598 }
02599 } else
02600 {
02601
02602 if ( m_bCurrentOperationIsLink && m_mode == Move
02603 && !job->inherits( "KIO::DeleteJob" )
02604 )
02605 {
02606 subjobs.remove( job );
02607 assert ( subjobs.isEmpty() );
02608
02609
02610 KIO::Job * newjob = KIO::del( (*it).uSource, false , false );
02611 addSubjob( newjob );
02612 return;
02613 }
02614
02615 if ( m_bCurrentOperationIsLink )
02616 {
02617 QString target = ( m_mode == Link ? (*it).uSource.path() : (*it).linkDest );
02618
02619 emit copyingLinkDone( this, (*it).uSource, target, (*it).uDest );
02620 }
02621 else
02622
02623 emit copyingDone( this, (*it).uSource, (*it).uDest, false, false );
02624
02625 files.remove( it );
02626 }
02627 m_processedFiles++;
02628
02629
02630 m_processedSize += m_fileProcessedSize;
02631 m_fileProcessedSize = 0;
02632
02633
02634 subjobs.remove( job );
02635 assert ( subjobs.isEmpty() );
02636 copyNextFile();
02637 }
02638
02639 void CopyJob::slotResultConflictCopyingFiles( KIO::Job * job )
02640 {
02641
02642
02643 QValueList<CopyInfo>::Iterator it = files.begin();
02644
02645 RenameDlg_Result res;
02646 QString newPath;
02647
02648 if (m_reportTimer)
02649 m_reportTimer->stop();
02650
02651 if ( ( m_conflictError == ERR_FILE_ALREADY_EXIST )
02652 || ( m_conflictError == ERR_DIR_ALREADY_EXIST ) )
02653 {
02654
02655 time_t destmtime = (time_t)-1;
02656 time_t destctime = (time_t)-1;
02657 KIO::filesize_t destsize = 0;
02658 UDSEntry entry = ((KIO::StatJob*)job)->statResult();
02659 KIO::UDSEntry::ConstIterator it2 = entry.begin();
02660 for( ; it2 != entry.end(); it2++ ) {
02661 switch ((*it2).m_uds) {
02662 case UDS_MODIFICATION_TIME:
02663 destmtime = (time_t)((*it2).m_long);
02664 break;
02665 case UDS_CREATION_TIME:
02666 destctime = (time_t)((*it2).m_long);
02667 break;
02668 case UDS_SIZE:
02669 destsize = (*it2).m_long;
02670 break;
02671 }
02672 }
02673
02674
02675
02676 RenameDlg_Mode mode = (RenameDlg_Mode)
02677 ( ( m_conflictError == ERR_DIR_ALREADY_EXIST ? 0 :
02678 ( (*it).uSource == (*it).uDest ) ? M_OVERWRITE_ITSELF : M_OVERWRITE ) );
02679 if ( files.count() > 1 )
02680 mode = (RenameDlg_Mode) ( mode | M_MULTI | M_SKIP );
02681 else
02682 mode = (RenameDlg_Mode) ( mode | M_SINGLE );
02683 res = Observer::self()->open_RenameDlg( this, m_conflictError == ERR_FILE_ALREADY_EXIST ?
02684 i18n("File Already Exists") : i18n("Already Exists as Folder"),
02685 (*it).uSource.prettyURL(0, KURL::StripFileProtocol),
02686 (*it).uDest.prettyURL(0, KURL::StripFileProtocol),
02687 mode, newPath,
02688 (*it).size, destsize,
02689 (*it).ctime, destctime,
02690 (*it).mtime, destmtime );
02691
02692 }
02693 else
02694 {
02695 if ( job->error() == ERR_USER_CANCELED )
02696 res = R_CANCEL;
02697 else
02698 {
02699 SkipDlg_Result skipResult = Observer::self()->open_SkipDlg( this, files.count() > 1,
02700 job->errorString() );
02701
02702
02703 res = ( skipResult == S_SKIP ) ? R_SKIP :
02704 ( skipResult == S_AUTO_SKIP ) ? R_AUTO_SKIP :
02705 R_CANCEL;
02706 }
02707 }
02708
02709 if (m_reportTimer)
02710 m_reportTimer->start(REPORT_TIMEOUT,false);
02711
02712 subjobs.remove( job );
02713 assert ( subjobs.isEmpty() );
02714 switch ( res ) {
02715 case R_CANCEL:
02716 m_error = ERR_USER_CANCELED;
02717 emitResult();
02718 return;
02719 case R_RENAME:
02720 {
02721 KURL newUrl( (*it).uDest );
02722 newUrl.setPath( newPath );
02723 emit renamed( this, (*it).uDest, newUrl );
02724 (*it).uDest = newUrl;
02725
02726 QValueList<CopyInfo> files;
02727 files.append(*it);
02728 emit aboutToCreate( this, files );
02729 }
02730 break;
02731 case R_AUTO_SKIP:
02732 m_bAutoSkip = true;
02733
02734 case R_SKIP:
02735
02736 skip( (*it).uSource );
02737 files.remove( it );
02738 m_processedFiles++;
02739 break;
02740 case R_OVERWRITE_ALL:
02741 m_bOverwriteAll = true;
02742 break;
02743 case R_OVERWRITE:
02744
02745 m_overwriteList.append( (*it).uDest.path() );
02746 break;
02747 default:
02748 assert( 0 );
02749 }
02750 state = STATE_COPYING_FILES;
02751
02752 copyNextFile();
02753 }
02754
02755 void CopyJob::copyNextFile()
02756 {
02757 bool bCopyFile = false;
02758
02759
02760 QValueList<CopyInfo>::Iterator it = files.begin();
02761
02762 while (it != files.end() && !bCopyFile)
02763 {
02764 bCopyFile = true;
02765 QString destFile = (*it).uDest.path();
02766
02767 QStringList::Iterator sit = m_skipList.begin();
02768 for( ; sit != m_skipList.end() && bCopyFile; sit++ )
02769
02770 if ( *sit == destFile.left( (*sit).length() ) )
02771 bCopyFile = false;
02772
02773 if (!bCopyFile) {
02774 files.remove( it );
02775 it = files.begin();
02776 }
02777 }
02778
02779 if (bCopyFile)
02780 {
02781
02782 bool bOverwrite = m_bOverwriteAll;
02783 QString destFile = (*it).uDest.path();
02784 kdDebug(7007) << "copying " << destFile << endl;
02785 if ( (*it).uDest == (*it).uSource )
02786 bOverwrite = false;
02787 else
02788 {
02789
02790 QStringList::Iterator sit = m_overwriteList.begin();
02791 for( ; sit != m_overwriteList.end() && !bOverwrite; sit++ )
02792 if ( *sit == destFile.left( (*sit).length() ) )
02793 bOverwrite = true;
02794 }
02795
02796 m_bCurrentOperationIsLink = false;
02797 KIO::Job * newjob = 0L;
02798 if ( m_mode == Link )
02799 {
02800
02801 if (
02802 ((*it).uSource.protocol() == (*it).uDest.protocol()) &&
02803 ((*it).uSource.host() == (*it).uDest.host()) &&
02804 ((*it).uSource.port() == (*it).uDest.port()) &&
02805 ((*it).uSource.user() == (*it).uDest.user()) &&
02806 ((*it).uSource.pass() == (*it).uDest.pass()) )
02807 {
02808
02809 KIO::SimpleJob *newJob = KIO::symlink( (*it).uSource.path(), (*it).uDest, bOverwrite, false );
02810 newjob = newJob;
02811 Scheduler::scheduleJob(newJob);
02812
02813
02814 m_bCurrentOperationIsLink = true;
02815 m_currentSrcURL=(*it).uSource;
02816 m_currentDestURL=(*it).uDest;
02817
02818 } else {
02819
02820 if ( (*it).uDest.isLocalFile() )
02821 {
02822 bool devicesOk=false;
02823
02824
02825 if ((*it).uSource.protocol()==QString::fromLatin1("devices"))
02826 {
02827 QByteArray data;
02828 QByteArray param;
02829 QCString retType;
02830 QDataStream streamout(param,IO_WriteOnly);
02831 streamout<<(*it).uSource;
02832 streamout<<(*it).uDest;
02833 if ( kapp->dcopClient()->call( "kded",
02834 "mountwatcher", "createLink(KURL, KURL)", param,retType,data,false ) )
02835 {
02836 QDataStream streamin(data,IO_ReadOnly);
02837 streamin>>devicesOk;
02838 }
02839 if (devicesOk)
02840 {
02841 files.remove( it );
02842 m_processedFiles++;
02843
02844 copyNextFile();
02845 return;
02846 }
02847 }
02848
02849 if (!devicesOk)
02850 {
02851 QString path = (*it).uDest.path();
02852
02853 QFile f( path );
02854 if ( f.open( IO_ReadWrite ) )
02855 {
02856 f.close();
02857 KSimpleConfig config( path );
02858 config.setDesktopGroup();
02859 config.writePathEntry( QString::fromLatin1("URL"), (*it).uSource.url() );
02860 config.writeEntry( QString::fromLatin1("Name"), (*it).uSource.url() );
02861 config.writeEntry( QString::fromLatin1("Type"), QString::fromLatin1("Link") );
02862 QString protocol = (*it).uSource.protocol();
02863 if ( protocol == QString::fromLatin1("ftp") )
02864 config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("ftp") );
02865 else if ( protocol == QString::fromLatin1("http") )
02866 config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("www") );
02867 else if ( protocol == QString::fromLatin1("info") )
02868 config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("info") );
02869 else if ( protocol == QString::fromLatin1("mailto") )
02870 config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("kmail") );
02871 else
02872 config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("unknown") );
02873 config.sync();
02874 files.remove( it );
02875 m_processedFiles++;
02876
02877 copyNextFile();
02878 return;
02879 }
02880 else
02881 {
02882 kdDebug(7007) << "CopyJob::copyNextFile ERR_CANNOT_OPEN_FOR_WRITING" << endl;
02883 m_error = ERR_CANNOT_OPEN_FOR_WRITING;
02884 m_errorText = (*it).uDest.path();
02885 emitResult();
02886 return;
02887 }
02888 }
02889 } else {
02890
02891 m_error = ERR_CANNOT_SYMLINK;
02892 m_errorText = (*it).uDest.prettyURL();
02893 emitResult();
02894 return;
02895 }
02896 }
02897 }
02898 else if ( !(*it).linkDest.isEmpty() &&
02899 ((*it).uSource.protocol() == (*it).uDest.protocol()) &&
02900 ((*it).uSource.host() == (*it).uDest.host()) &&
02901 ((*it).uSource.port() == (*it).uDest.port()) &&
02902 ((*it).uSource.user() == (*it).uDest.user()) &&
02903 ((*it).uSource.pass() == (*it).uDest.pass()))
02904
02905 {
02906 KIO::SimpleJob *newJob = KIO::symlink( (*it).linkDest, (*it).uDest, bOverwrite, false );
02907 Scheduler::scheduleJob(newJob);
02908 newjob = newJob;
02909
02910
02911 m_currentSrcURL=(*it).linkDest;
02912 m_currentDestURL=(*it).uDest;
02913
02914 m_bCurrentOperationIsLink = true;
02915
02916 } else if (m_mode == Move)
02917 {
02918 KIO::FileCopyJob * moveJob = KIO::file_move( (*it).uSource, (*it).uDest, (*it).permissions, bOverwrite, false, false );
02919 moveJob->setSourceSize64( (*it).size );
02920 newjob = moveJob;
02921
02922
02923 m_currentSrcURL=(*it).uSource;
02924 m_currentDestURL=(*it).uDest;
02925
02926 }
02927 else
02928 {
02929
02930
02931 bool remoteSource = !KProtocolInfo::supportsListing((*it).uSource);
02932 int permissions = ( remoteSource && (*it).uDest.isLocalFile() ) ? -1 : (*it).permissions;
02933 KIO::FileCopyJob * copyJob = KIO::file_copy( (*it).uSource, (*it).uDest, permissions, bOverwrite, false, false );
02934 copyJob->setParentJob( this );
02935 copyJob->setSourceSize64( (*it).size );
02936 newjob = copyJob;
02937
02938 m_currentSrcURL=(*it).uSource;
02939 m_currentDestURL=(*it).uDest;
02940 }
02941 addSubjob(newjob);
02942 connect( newjob, SIGNAL( processedSize( KIO::Job*, KIO::filesize_t ) ),
02943 this, SLOT( slotProcessedSize( KIO::Job*, KIO::filesize_t ) ) );
02944 connect( newjob, SIGNAL( totalSize( KIO::Job*, KIO::filesize_t ) ),
02945 this, SLOT( slotTotalSize( KIO::Job*, KIO::filesize_t ) ) );
02946 }
02947 else
02948 {
02949
02950
02951 deleteNextDir();
02952 }
02953 }
02954
02955 void CopyJob::deleteNextDir()
02956 {
02957 if ( m_mode == Move && !dirsToRemove.isEmpty() )
02958 {
02959 state = STATE_DELETING_DIRS;
02960
02961 KURL::List::Iterator it = dirsToRemove.fromLast();
02962 SimpleJob *job = KIO::rmdir( *it );
02963 Scheduler::scheduleJob(job);
02964 dirsToRemove.remove(it);
02965 addSubjob( job );
02966 }
02967 else
02968 {
02969
02970 if ( !m_bOnlyRenames )
02971 {
02972 KDirNotify_stub allDirNotify("*", "KDirNotify*");
02973 KURL url( m_dest );
02974 if ( destinationState != DEST_IS_DIR || m_asMethod )
02975 url.setPath( url.directory() );
02976
02977 allDirNotify.FilesAdded( url );
02978
02979 if ( m_mode == Move && !m_srcList.isEmpty() )
02980 allDirNotify.FilesRemoved( m_srcList );
02981 }
02982 if (m_reportTimer!=0)
02983 m_reportTimer->stop();
02984 emitResult();
02985 }
02986 }
02987
02988 void CopyJob::slotProcessedSize( KIO::Job*, KIO::filesize_t data_size )
02989 {
02990
02991 m_fileProcessedSize = data_size;
02992 setProcessedSize(m_processedSize + m_fileProcessedSize);
02993
02994 if ( m_processedSize + m_fileProcessedSize > m_totalSize )
02995 {
02996 m_totalSize = m_processedSize + m_fileProcessedSize;
02997
02998 emit totalSize( this, m_totalSize );
02999 }
03000
03001 emit processedSize( this, m_processedSize + m_fileProcessedSize );
03002 emitPercent( m_processedSize + m_fileProcessedSize, m_totalSize );
03003 }
03004
03005 void CopyJob::slotTotalSize( KIO::Job*, KIO::filesize_t size )
03006 {
03007
03008
03009
03010
03011 if ( m_bSingleFileCopy )
03012 {
03013
03014 m_totalSize = size;
03015 emit totalSize( this, size );
03016 }
03017 }
03018
03019 void CopyJob::slotResultDeletingDirs( Job * job )
03020 {
03021 if (job->error())
03022 {
03023
03024
03025
03026 }
03027 subjobs.remove( job );
03028 assert ( subjobs.isEmpty() );
03029 deleteNextDir();
03030 }
03031
03032 void CopyJob::slotResult( Job *job )
03033 {
03034
03035
03036
03037
03038
03039
03040 switch ( state ) {
03041 case STATE_STATING:
03042 slotResultStating( job );
03043 break;
03044 case STATE_RENAMING:
03045 {
03046 int err = job->error();
03047 subjobs.remove( job );
03048 assert ( subjobs.isEmpty() );
03049
03050 KURL dest = m_dest;
03051 if ( destinationState == DEST_IS_DIR && !m_asMethod )
03052 dest.addPath( m_currentSrcURL.fileName() );
03053 if ( err )
03054 {
03055
03056
03057
03058 if ( m_currentSrcURL.isLocalFile() && m_currentSrcURL.url(-1) != dest.url(-1) &&
03059 m_currentSrcURL.url(-1).lower() == dest.url(-1).lower() &&
03060 ( err == ERR_FILE_ALREADY_EXIST || err == ERR_DIR_ALREADY_EXIST ) )
03061 {
03062 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;
03063 QCString _src( QFile::encodeName(m_currentSrcURL.path()) );
03064 QCString _dest( QFile::encodeName(dest.path()) );
03065 KTempFile tmpFile( m_currentSrcURL.directory(false) );
03066 QCString _tmp( QFile::encodeName(tmpFile.name()) );
03067 kdDebug(7007) << "CopyJob::slotResult KTempFile status:" << tmpFile.status() << " using " << _tmp << " as intermediary" << endl;
03068 tmpFile.unlink();
03069 if ( ::rename( _src, _tmp ) == 0 )
03070 {
03071 if ( !QFile::exists( _dest ) && ::rename( _tmp, _dest ) == 0 )
03072 {
03073 kdDebug(7007) << "Success." << endl;
03074 err = 0;
03075 }
03076 else
03077 {
03078
03079 if ( ::rename( _tmp, _src ) != 0 ) {
03080 kdError(7007) << "Couldn't rename " << tmpFile.name() << " back to " << _src << " !" << endl;
03081
03082 Job::slotResult( job );
03083 return;
03084 }
03085 }
03086 }
03087 }
03088 }
03089 if ( err )
03090 {
03091
03092
03093
03094
03095
03096
03097
03098 Q_ASSERT( m_currentSrcURL == *m_currentStatSrc );
03099
03100
03101 if ( err == ERR_DIR_ALREADY_EXIST || err == ERR_FILE_ALREADY_EXIST )
03102 {
03103 if (m_reportTimer)
03104 m_reportTimer->stop();
03105
03106 QString newPath;
03107
03108
03109 RenameDlg_Mode mode = (RenameDlg_Mode)
03110 ( ( m_conflictError == ERR_DIR_ALREADY_EXIST ? 0 :
03111 ( m_currentSrcURL == dest ) ? M_OVERWRITE_ITSELF : M_OVERWRITE ) );
03112
03113
03114
03115
03116 mode = (RenameDlg_Mode) ( mode | M_SINGLE );
03117
03118
03119 RenameDlg_Result r = Observer::self()->open_RenameDlg( this,
03120 err == ERR_FILE_ALREADY_EXIST ? i18n("File Already Exists") : i18n("Already Exists as Folder"),
03121 m_currentSrcURL.prettyURL(0, KURL::StripFileProtocol),
03122 dest.prettyURL(0, KURL::StripFileProtocol),
03123 mode, newPath );
03124 if (m_reportTimer)
03125 m_reportTimer->start(REPORT_TIMEOUT,false);
03126
03127 switch ( r )
03128 {
03129 case R_CANCEL:
03130 {
03131 m_error = ERR_USER_CANCELED;
03132 emitResult();
03133 return;
03134 }
03135 case R_RENAME:
03136 {
03137 m_dest.setPath( newPath );
03138 KIO::Job* job = KIO::stat( m_dest, false, 2, false );
03139 state = STATE_STATING;
03140 destinationState = DEST_NOT_STATED;
03141 addSubjob(job);
03142 return;
03143 }
03144 case R_OVERWRITE:
03145
03146
03147
03148
03149
03150 kdDebug(7007) << "adding to overwrite list: " << dest.path() << endl;
03151 m_overwriteList.append( dest.path() );
03152 break;
03153 default:
03154
03155 break;
03156 }
03157 }
03158
03159 kdDebug(7007) << "Couldn't rename, reverting to normal way, starting with stat" << endl;
03160
03161 KIO::Job* job = KIO::stat( m_currentSrcURL, true, 2, false );
03162 state = STATE_STATING;
03163 addSubjob(job);
03164 m_bOnlyRenames = false;
03165 }
03166 else
03167 {
03168
03169 emit copyingDone( this, *m_currentStatSrc, dest, true, true );
03170 ++m_currentStatSrc;
03171 statNextSrc();
03172 }
03173 }
03174 break;
03175 case STATE_LISTING:
03176
03177
03178 if (job->error())
03179 {
03180 Job::slotResult( job );
03181 return;
03182 }
03183
03184 subjobs.remove( job );
03185 assert ( subjobs.isEmpty() );
03186
03187 ++m_currentStatSrc;
03188 statNextSrc();
03189 break;
03190 case STATE_CREATING_DIRS:
03191 slotResultCreatingDirs( job );
03192 break;
03193 case STATE_CONFLICT_CREATING_DIRS:
03194 slotResultConflictCreatingDirs( job );
03195 break;
03196 case STATE_COPYING_FILES:
03197 slotResultCopyingFiles( job );
03198 break;
03199 case STATE_CONFLICT_COPYING_FILES:
03200 slotResultConflictCopyingFiles( job );
03201 break;
03202 case STATE_DELETING_DIRS:
03203 slotResultDeletingDirs( job );
03204 break;
03205 default:
03206 assert( 0 );
03207 }
03208 }
03209
03210 CopyJob *KIO::copy(const KURL& src, const KURL& dest, bool showProgressInfo )
03211 {
03212
03213 KURL::List srcList;
03214 srcList.append( src );
03215 return new CopyJob( srcList, dest, CopyJob::Copy, false, showProgressInfo );
03216 }
03217
03218 CopyJob *KIO::copyAs(const KURL& src, const KURL& dest, bool showProgressInfo )
03219 {
03220
03221 KURL::List srcList;
03222 srcList.append( src );
03223 return new CopyJob( srcList, dest, CopyJob::Copy, true, showProgressInfo );
03224 }
03225
03226 CopyJob *KIO::copy( const KURL::List& src, const KURL& dest, bool showProgressInfo )
03227 {
03228 return new CopyJob( src, dest, CopyJob::Copy, false, showProgressInfo );
03229 }
03230
03231 CopyJob *KIO::move(const KURL& src, const KURL& dest, bool showProgressInfo )
03232 {
03233 KURL::List srcList;
03234 srcList.append( src );
03235 return new CopyJob( srcList, dest, CopyJob::Move, false, showProgressInfo );
03236 }
03237
03238 CopyJob *KIO::moveAs(const KURL& src, const KURL& dest, bool showProgressInfo )
03239 {
03240 KURL::List srcList;
03241 srcList.append( src );
03242 return new CopyJob( srcList, dest, CopyJob::Move, true, showProgressInfo );
03243 }
03244
03245 CopyJob *KIO::move( const KURL::List& src, const KURL& dest, bool showProgressInfo )
03246 {
03247 return new CopyJob( src, dest, CopyJob::Move, false, showProgressInfo );
03248 }
03249
03250 CopyJob *KIO::link(const KURL& src, const KURL& destDir, bool showProgressInfo )
03251 {
03252 KURL::List srcList;
03253 srcList.append( src );
03254 return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
03255 }
03256
03257 CopyJob *KIO::link(const KURL::List& srcList, const KURL& destDir, bool showProgressInfo )
03258 {
03259 return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
03260 }
03261
03262 CopyJob *KIO::linkAs(const KURL& src, const KURL& destDir, bool showProgressInfo )
03263 {
03264 KURL::List srcList;
03265 srcList.append( src );
03266 return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
03267 }
03268
03270
03271 DeleteJob::DeleteJob( const KURL::List& src, bool shred, bool showProgressInfo )
03272 : Job(showProgressInfo), m_totalSize( 0 ), m_processedSize( 0 ), m_fileProcessedSize( 0 ),
03273 m_processedFiles( 0 ), m_processedDirs( 0 ), m_totalFilesDirs( 0 ),
03274 m_srcList(src), m_currentStat(m_srcList.begin()), m_shred(shred), m_reportTimer(0)
03275 {
03276 if ( showProgressInfo ) {
03277
03278 connect( this, SIGNAL( totalFiles( KIO::Job*, unsigned long ) ),
03279 Observer::self(), SLOT( slotTotalFiles( KIO::Job*, unsigned long ) ) );
03280
03281 connect( this, SIGNAL( totalDirs( KIO::Job*, unsigned long ) ),
03282 Observer::self(), SLOT( slotTotalDirs( KIO::Job*, unsigned long ) ) );
03283
03284
03285
03286
03287
03288
03289
03290
03291
03292
03293
03294 m_reportTimer=new QTimer(this);
03295 connect(m_reportTimer,SIGNAL(timeout()),this,SLOT(slotReport()));
03296
03297 m_reportTimer->start(REPORT_TIMEOUT,false);
03298 }
03299
03300 QTimer::singleShot(0, this, SLOT(slotStart()));
03301 }
03302
03303 void DeleteJob::slotStart()
03304 {
03305 statNextSrc();
03306 }
03307
03308
03309
03310
03311 void DeleteJob::slotReport()
03312 {
03313 if (m_progressId==0)
03314 return;
03315
03316 Observer * observer = Observer::self();
03317
03318 emit deleting( this, m_currentURL );
03319 observer->slotDeleting(this,m_currentURL);
03320
03321 switch( state ) {
03322 case STATE_STATING:
03323 case STATE_LISTING:
03324 emit totalSize( this, m_totalSize );
03325 emit totalFiles( this, files.count() );
03326 emit totalDirs( this, dirs.count() );
03327 break;
03328 case STATE_DELETING_DIRS:
03329 emit processedDirs( this, m_processedDirs );
03330 observer->slotProcessedDirs(this,m_processedDirs);
03331 emitPercent( m_processedFiles + m_processedDirs, m_totalFilesDirs );
03332 break;
03333 case STATE_DELETING_FILES:
03334 observer->slotProcessedFiles(this,m_processedFiles);
03335 emit processedFiles( this, m_processedFiles );
03336 if (!m_shred)
03337 emitPercent( m_processedFiles, m_totalFilesDirs );
03338 break;
03339 }
03340 }
03341
03342
03343 void DeleteJob::slotEntries(KIO::Job* job, const UDSEntryList& list)
03344 {
03345 UDSEntryListConstIterator it = list.begin();
03346 UDSEntryListConstIterator end = list.end();
03347 for (; it != end; ++it)
03348 {
03349 UDSEntry::ConstIterator it2 = (*it).begin();
03350 bool bDir = false;
03351 bool bLink = false;
03352 QString relName;
03353 int atomsFound(0);
03354 for( ; it2 != (*it).end(); it2++ )
03355 {
03356 switch ((*it2).m_uds)
03357 {
03358 case UDS_FILE_TYPE:
03359 bDir = S_ISDIR((*it2).m_long);
03360 atomsFound++;
03361 break;
03362 case UDS_NAME:
03363 relName = ((*it2).m_str);
03364 atomsFound++;
03365 break;
03366 case UDS_LINK_DEST:
03367 bLink = !(*it2).m_str.isEmpty();
03368 atomsFound++;
03369 break;
03370 case UDS_SIZE:
03371 m_totalSize += (KIO::filesize_t)((*it2).m_long);
03372 atomsFound++;
03373 break;
03374 default:
03375 break;
03376 }
03377 if (atomsFound==4) break;
03378 }
03379 assert(!relName.isEmpty());
03380 if (relName != ".." && relName != ".")
03381 {
03382 KURL url = ((SimpleJob *)job)->url();
03383 url.addPath( relName );
03384
03385 if ( bLink )
03386 symlinks.append( url );
03387 else if ( bDir )
03388 dirs.append( url );
03389 else
03390 files.append( url );
03391 }
03392 }
03393 }
03394
03395
03396 void DeleteJob::statNextSrc()
03397 {
03398
03399 if ( m_currentStat != m_srcList.end() )
03400 {
03401 m_currentURL = (*m_currentStat);
03402
03403
03404 if (!KProtocolInfo::supportsDeleting(m_currentURL)) {
03405 KMessageBox::information( 0, buildErrorString(ERR_CANNOT_DELETE, m_currentURL.prettyURL()));
03406 ++m_currentStat;
03407 statNextSrc();
03408 return;
03409 }
03410
03411 state = STATE_STATING;
03412 KIO::SimpleJob * job = KIO::stat( m_currentURL, true, 1, false );
03413 Scheduler::scheduleJob(job);
03414
03415 addSubjob(job);
03416
03417
03418 } else
03419 {
03420 m_totalFilesDirs = files.count()+symlinks.count() + dirs.count();
03421 slotReport();
03422
03423
03424
03425
03426 for ( QStringList::Iterator it = m_parentDirs.begin() ; it != m_parentDirs.end() ; ++it )
03427 KDirWatch::self()->stopDirScan( *it );
03428 state = STATE_DELETING_FILES;
03429 deleteNextFile();
03430 }
03431 }
03432
03433 void DeleteJob::deleteNextFile()
03434 {
03435
03436 if ( !files.isEmpty() || !symlinks.isEmpty() )
03437 {
03438 SimpleJob *job;
03439 do {
03440
03441 KURL::List::Iterator it = files.begin();
03442 bool isLink = false;
03443 if ( it == files.end() )
03444 {
03445 it = symlinks.begin();
03446 isLink = true;
03447 }
03448
03449 if ( m_shred && (*it).isLocalFile() && !isLink )
03450 {
03451
03452 KIO_ARGS << int(3) << (*it).path();
03453 job = KIO::special(KURL("file:/"), packedArgs, false );
03454 Scheduler::scheduleJob(job);
03455 m_currentURL=(*it);
03456 connect( job, SIGNAL( processedSize( KIO::Job*, KIO::filesize_t ) ),
03457 this, SLOT( slotProcessedSize( KIO::Job*, KIO::filesize_t ) ) );
03458 } else
03459 {
03460
03461
03462 if ( (*it).isLocalFile() && unlink( QFile::encodeName((*it).path()) ) == 0 ) {
03463 job = 0;
03464 m_processedFiles++;
03465 if ( m_processedFiles % 300 == 0 ) {
03466 m_currentURL = *it;
03467 slotReport();
03468 }
03469 } else
03470 {
03471 job = KIO::file_delete( *it, false );
03472 Scheduler::scheduleJob(job);
03473 m_currentURL=(*it);
03474 }
03475 }
03476 if ( isLink )
03477 symlinks.remove(it);
03478 else
03479 files.remove(it);
03480 if ( job ) {
03481 addSubjob(job);
03482 return;
03483 }
03484
03485 } while (!job && (!files.isEmpty() || !symlinks.isEmpty()));
03486 }
03487 state = STATE_DELETING_DIRS;
03488 deleteNextDir();
03489 }
03490
03491 void DeleteJob::deleteNextDir()
03492 {
03493 if ( !dirs.isEmpty() )
03494 {
03495 do {
03496
03497 KURL::List::Iterator it = dirs.fromLast();
03498
03499 if ( (*it).isLocalFile() && ::rmdir( QFile::encodeName((*it).path()) ) == 0 ) {
03500
03501 m_processedDirs++;
03502 if ( m_processedDirs % 100 == 0 ) {
03503 m_currentURL = *it;
03504 slotReport();
03505 }
03506 } else
03507 {
03508 SimpleJob *job = KIO::rmdir( *it );
03509 Scheduler::scheduleJob(job);
03510 dirs.remove(it);
03511 addSubjob( job );
03512 return;
03513 }
03514 dirs.remove(it);
03515 } while ( !dirs.isEmpty() );
03516 }
03517
03518
03519 for ( QStringList::Iterator it = m_parentDirs.begin() ; it != m_parentDirs.end() ; ++it )
03520 KDirWatch::self()->restartDirScan( *it );
03521
03522
03523 if ( !m_srcList.isEmpty() )
03524 {
03525 KDirNotify_stub allDirNotify("*", "KDirNotify*");
03526 allDirNotify.FilesRemoved( m_srcList );
03527 }
03528 if (m_reportTimer!=0)
03529 m_reportTimer->stop();
03530 emitResult();
03531 }
03532
03533 void DeleteJob::slotProcessedSize( KIO::Job*, KIO::filesize_t data_size )
03534 {
03535
03536
03537
03538
03539 m_fileProcessedSize = data_size;
03540 setProcessedSize(m_processedSize + m_fileProcessedSize);
03541
03542
03543
03544 emit processedSize( this, m_processedSize + m_fileProcessedSize );
03545
03546
03547 unsigned long ipercent = m_percent;
03548
03549 if ( m_totalSize == 0 )
03550 m_percent = 100;
03551 else
03552 m_percent = (unsigned long)(( (float)(m_processedSize + m_fileProcessedSize) / (float)m_totalSize ) * 100.0);
03553
03554 if ( m_percent > ipercent )
03555 {
03556 emit percent( this, m_percent );
03557
03558 }
03559
03560 }
03561
03562 void DeleteJob::slotResult( Job *job )
03563 {
03564 switch ( state )
03565 {
03566 case STATE_STATING:
03567 {
03568
03569 if (job->error() )
03570 {
03571
03572 Job::slotResult( job );
03573 return;
03574 }
03575
03576
03577 UDSEntry entry = ((StatJob*)job)->statResult();
03578 bool bDir = false;
03579 bool bLink = false;
03580 KIO::filesize_t size = (KIO::filesize_t)-1;
03581 UDSEntry::ConstIterator it2 = entry.begin();
03582 int atomsFound(0);
03583 for( ; it2 != entry.end(); it2++ )
03584 {
03585 if ( ((*it2).m_uds) == UDS_FILE_TYPE )
03586 {
03587 bDir = S_ISDIR( (mode_t)(*it2).m_long );
03588 atomsFound++;
03589 }
03590 else if ( ((*it2).m_uds) == UDS_LINK_DEST )
03591 {
03592 bLink = !((*it2).m_str.isEmpty());
03593 atomsFound++;
03594 }
03595 else if ( ((*it2).m_uds) == UDS_SIZE )
03596 {
03597 size = (*it2).m_long;
03598 atomsFound++;
03599 };
03600 if (atomsFound==3) break;
03601 }
03602
03603 KURL url = ((SimpleJob*)job)->url();
03604
03605 subjobs.remove( job );
03606 assert( subjobs.isEmpty() );
03607
03608 if (bDir && !bLink)
03609 {
03610
03611 dirs.append( url );
03612 if ( url.isLocalFile() && !m_parentDirs.contains( url.path(-1) ) )
03613 m_parentDirs.append( url.path(-1) );
03614
03615
03616
03617 state = STATE_LISTING;
03618 ListJob *newjob = listRecursive( url, false );
03619 newjob->setUnrestricted(true);
03620 Scheduler::scheduleJob(newjob);
03621 connect(newjob, SIGNAL(entries( KIO::Job *,
03622 const KIO::UDSEntryList& )),
03623 SLOT( slotEntries( KIO::Job*,
03624 const KIO::UDSEntryList& )));
03625 addSubjob(newjob);
03626 }
03627 else
03628 {
03629 if ( bLink ) {
03630
03631 symlinks.append( url );
03632 } else {
03633
03634 files.append( url );
03635 }
03636 if ( url.isLocalFile() && !m_parentDirs.contains( url.directory(-1) ) )
03637 m_parentDirs.append( url.directory(-1) );
03638 ++m_currentStat;
03639 statNextSrc();
03640 }
03641 }
03642 break;
03643 case STATE_LISTING:
03644 if ( job->error() )
03645 {
03646
03647 }
03648 subjobs.remove( job );
03649 assert( subjobs.isEmpty() );
03650 ++m_currentStat;
03651 statNextSrc();
03652 break;
03653 case STATE_DELETING_FILES:
03654 if ( job->error() )
03655 {
03656 Job::slotResult( job );
03657 return;
03658 }
03659 subjobs.remove( job );
03660 assert( subjobs.isEmpty() );
03661 m_processedFiles++;
03662
03663 deleteNextFile();
03664 break;
03665 case STATE_DELETING_DIRS:
03666 if ( job->error() )
03667 {
03668 Job::slotResult( job );
03669 return;
03670 }
03671 subjobs.remove( job );
03672 assert( subjobs.isEmpty() );
03673 m_processedDirs++;
03674
03675
03676
03677
03678 deleteNextDir();
03679 break;
03680 default:
03681 assert(0);
03682 }
03683 }
03684
03685 DeleteJob *KIO::del( const KURL& src, bool shred, bool showProgressInfo )
03686 {
03687 KURL::List srcList;
03688 srcList.append( src );
03689 DeleteJob *job = new DeleteJob( srcList, shred, showProgressInfo );
03690 return job;
03691 }
03692
03693 DeleteJob *KIO::del( const KURL::List& src, bool shred, bool showProgressInfo )
03694 {
03695 DeleteJob *job = new DeleteJob( src, shred, showProgressInfo );
03696 return job;
03697 }
03698
03699 MultiGetJob::MultiGetJob(const KURL& url,
03700 bool showProgressInfo)
03701 : TransferJob(url, 0, QByteArray(), QByteArray(), showProgressInfo)
03702 {
03703 m_waitQueue.setAutoDelete(true);
03704 m_activeQueue.setAutoDelete(true);
03705 m_currentEntry = 0;
03706 }
03707
03708 void MultiGetJob::get(long id, const KURL &url, const MetaData &metaData)
03709 {
03710 GetRequest *entry = new GetRequest(id, url, metaData);
03711 entry->metaData["request-id"] = QString("%1").arg(id);
03712 m_waitQueue.append(entry);
03713 }
03714
03715 void MultiGetJob::flushQueue(QPtrList<GetRequest> &queue)
03716 {
03717 GetRequest *entry;
03718
03719
03720 for(entry = m_waitQueue.first(); entry; )
03721 {
03722 if ((m_url.protocol() == entry->url.protocol()) &&
03723 (m_url.host() == entry->url.host()) &&
03724 (m_url.port() == entry->url.port()) &&
03725 (m_url.user() == entry->url.user()))
03726 {
03727 m_waitQueue.take();
03728 queue.append(entry);
03729 entry = m_waitQueue.current();
03730 }
03731 else
03732 {
03733 entry = m_waitQueue.next();
03734 }
03735 }
03736
03737 KIO_ARGS << (Q_INT32) queue.count();
03738 for(entry = queue.first(); entry; entry = queue.next())
03739 {
03740 stream << entry->url << entry->metaData;
03741 }
03742 m_packedArgs = packedArgs;
03743 m_command = CMD_MULTI_GET;
03744 m_outgoingMetaData.clear();
03745 }
03746
03747 void MultiGetJob::start(Slave *slave)
03748 {
03749
03750 GetRequest *entry = m_waitQueue.take(0);
03751 m_activeQueue.append(entry);
03752
03753 m_url = entry->url;
03754
03755 if (!entry->url.protocol().startsWith("http"))
03756 {
03757
03758 KIO_ARGS << entry->url;
03759 m_packedArgs = packedArgs;
03760 m_outgoingMetaData = entry->metaData;
03761 m_command = CMD_GET;
03762 b_multiGetActive = false;
03763 }
03764 else
03765 {
03766 flushQueue(m_activeQueue);
03767 b_multiGetActive = true;
03768 }
03769
03770 TransferJob::start(slave);
03771 }
03772
03773 bool MultiGetJob::findCurrentEntry()
03774 {
03775 if (b_multiGetActive)
03776 {
03777 long id = m_incomingMetaData["request-id"].toLong();
03778 for(GetRequest *entry = m_activeQueue.first(); entry; entry = m_activeQueue.next())
03779 {
03780 if (entry->id == id)
03781 {
03782 m_currentEntry = entry;
03783 return true;
03784 }
03785 }
03786 m_currentEntry = 0;
03787 return false;
03788 }
03789 else
03790 {
03791 m_currentEntry = m_activeQueue.first();
03792 return (m_currentEntry != 0);
03793 }
03794 }
03795
03796 void MultiGetJob::slotRedirection( const KURL &url)
03797 {
03798 if (!findCurrentEntry()) return;
03799 if (!kapp->authorizeURLAction("redirect", m_url, url))
03800 {
03801 kdWarning(7007) << "MultiGetJob: Redirection from " << m_currentEntry->url.prettyURL() << " to " << url.prettyURL() << " REJECTED!" << endl;
03802 return;
03803 }
03804 m_redirectionURL = url;
03805 if (m_currentEntry->url.hasUser() && !url.hasUser() && (m_currentEntry->url.host().lower() == url.host().lower()))
03806 m_redirectionURL.setUser(m_currentEntry->url.user());
03807 get(m_currentEntry->id, m_redirectionURL, m_currentEntry->metaData);
03808 }
03809
03810
03811 void MultiGetJob::slotFinished()
03812 {
03813 if (!findCurrentEntry()) return;
03814 if (m_redirectionURL.isEmpty())
03815 {
03816
03817 emit result(m_currentEntry->id);
03818 }
03819 m_redirectionURL = KURL();
03820 m_error = 0;
03821 m_incomingMetaData.clear();
03822 m_activeQueue.removeRef(m_currentEntry);
03823 if (m_activeQueue.count() == 0)
03824 {
03825 if (m_waitQueue.count() == 0)
03826 {
03827
03828 TransferJob::slotFinished();
03829 }
03830 else
03831 {
03832
03833
03834
03835 GetRequest *entry = m_waitQueue.at(0);
03836 m_url = entry->url;
03837 slaveDone();
03838 Scheduler::doJob(this);
03839 }
03840 }
03841 }
03842
03843 void MultiGetJob::slotData( const QByteArray &_data)
03844 {
03845 if(!m_currentEntry) return;
03846 if(m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error)
03847 emit data(m_currentEntry->id, _data);
03848 }
03849
03850 void MultiGetJob::slotMimetype( const QString &_mimetype )
03851 {
03852 if (b_multiGetActive)
03853 {
03854 QPtrList<GetRequest> newQueue;
03855 flushQueue(newQueue);
03856 if (!newQueue.isEmpty())
03857 {
03858 while(!newQueue.isEmpty())
03859 m_activeQueue.append(newQueue.take(0));
03860 m_slave->send( m_command, m_packedArgs );
03861 }
03862 }
03863 if (!findCurrentEntry()) return;
03864 emit mimetype(m_currentEntry->id, _mimetype);
03865 }
03866
03867 MultiGetJob *KIO::multi_get(long id, const KURL &url, const MetaData &metaData)
03868 {
03869 MultiGetJob * job = new MultiGetJob( url, false );
03870 job->get(id, url, metaData);
03871 return job;
03872 }
03873
03874
03875 #ifdef CACHE_INFO
03876 CacheInfo::CacheInfo(const KURL &url)
03877 {
03878 m_url = url;
03879 }
03880
03881 QString CacheInfo::cachedFileName()
03882 {
03883 const QChar separator = '_';
03884
03885 QString CEF = m_url.path();
03886
03887 int p = CEF.find('/');
03888
03889 while(p != -1)
03890 {
03891 CEF[p] = separator;
03892 p = CEF.find('/', p);
03893 }
03894
03895 QString host = m_url.host().lower();
03896 CEF = host + CEF + '_';
03897
03898 QString dir = KProtocolManager::cacheDir();
03899 if (dir[dir.length()-1] != '/')
03900 dir += "/";
03901
03902 int l = m_url.host().length();
03903 for(int i = 0; i < l; i++)
03904 {
03905 if (host[i].isLetter() && (host[i] != 'w'))
03906 {
03907 dir += host[i];
03908 break;
03909 }
03910 }
03911 if (dir[dir.length()-1] == '/')
03912 dir += "0";
03913
03914 unsigned long hash = 0x00000000;
03915 QCString u = m_url.url().latin1();
03916 for(int i = u.length(); i--;)
03917 {
03918 hash = (hash * 12211 + u[i]) % 2147483563;
03919 }
03920
03921 QString hashString;
03922 hashString.sprintf("%08lx", hash);
03923
03924 CEF = CEF + hashString;
03925
03926 CEF = dir + "/" + CEF;
03927
03928 return CEF;
03929 }
03930
03931 QFile *CacheInfo::cachedFile()
03932 {
03933 const char *mode = (readWrite ? "r+" : "r");
03934
03935 FILE *fs = fopen( CEF.latin1(), mode);
03936 if (!fs)
03937 return 0;
03938
03939 char buffer[401];
03940 bool ok = true;
03941
03942
03943 if (ok && (!fgets(buffer, 400, fs)))
03944 ok = false;
03945 if (ok && (strcmp(buffer, CACHE_REVISION) != 0))
03946 ok = false;
03947
03948 time_t date;
03949 time_t currentDate = time(0);
03950
03951
03952 if (ok && (!fgets(buffer, 400, fs)))
03953 ok = false;
03954 if (ok)
03955 {
03956 int l = strlen(buffer);
03957 if (l>0)
03958 buffer[l-1] = 0;
03959 if (m_.url.url() != buffer)
03960 {
03961 ok = false;
03962 }
03963 }
03964
03965
03966 if (ok && (!fgets(buffer, 400, fs)))
03967 ok = false;
03968 if (ok)
03969 {
03970 date = (time_t) strtoul(buffer, 0, 10);
03971 if (m_maxCacheAge && (difftime(currentDate, date) > m_maxCacheAge))
03972 {
03973 m_bMustRevalidate = true;
03974 m_expireDate = currentDate;
03975 }
03976 }
03977
03978
03979 m_cacheExpireDateOffset = ftell(fs);
03980 if (ok && (!fgets(buffer, 400, fs)))
03981 ok = false;
03982 if (ok)
03983 {
03984 if (m_request.cache == CC_Verify)
03985 {
03986 date = (time_t) strtoul(buffer, 0, 10);
03987
03988 if (!date || difftime(currentDate, date) >= 0)
03989 m_bMustRevalidate = true;
03990 m_expireDate = date;
03991 }
03992 }
03993
03994
03995 if (ok && (!fgets(buffer, 400, fs)))
03996 ok = false;
03997 if (ok)
03998 {
03999 m_etag = QString(buffer).stripWhiteSpace();
04000 }
04001
04002
04003 if (ok && (!fgets(buffer, 400, fs)))
04004 ok = false;
04005 if (ok)
04006 {
04007 m_lastModified = QString(buffer).stripWhiteSpace();
04008 }
04009
04010 fclose(fs);
04011
04012 if (ok)
04013 return fs;
04014
04015 unlink( CEF.latin1());
04016 return 0;
04017
04018 }
04019
04020 void CacheInfo::flush()
04021 {
04022 cachedFile().remove();
04023 }
04024
04025 void CacheInfo::touch()
04026 {
04027
04028 }
04029 void CacheInfo::setExpireDate(int);
04030 void CacheInfo::setExpireTimeout(int);
04031
04032
04033 int CacheInfo::creationDate();
04034 int CacheInfo::expireDate();
04035 int CacheInfo::expireTimeout();
04036 #endif
04037
04038 void Job::virtual_hook( int, void* )
04039 { }
04040
04041 void SimpleJob::virtual_hook( int id, void* data )
04042 { KIO::Job::virtual_hook( id, data ); }
04043
04044 void StatJob::virtual_hook( int id, void* data )
04045 { SimpleJob::virtual_hook( id, data ); }
04046
04047 void TransferJob::virtual_hook( int id, void* data )
04048 { SimpleJob::virtual_hook( id, data ); }
04049
04050 void MultiGetJob::virtual_hook( int id, void* data )
04051 { TransferJob::virtual_hook( id, data ); }
04052
04053 void MimetypeJob::virtual_hook( int id, void* data )
04054 { TransferJob::virtual_hook( id, data ); }
04055
04056 void FileCopyJob::virtual_hook( int id, void* data )
04057 { Job::virtual_hook( id, data ); }
04058
04059 void ListJob::virtual_hook( int id, void* data )
04060 { SimpleJob::virtual_hook( id, data ); }
04061
04062 void CopyJob::virtual_hook( int id, void* data )
04063 { Job::virtual_hook( id, data ); }
04064
04065 void DeleteJob::virtual_hook( int id, void* data )
04066 { Job::virtual_hook( id, data ); }
04067
04068
04069 #include "jobclasses.moc"