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