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 config.writeEntry( QString::fromLatin1("Name"), (*it).uSource.url() );
03122 config.writeEntry( QString::fromLatin1("Type"), QString::fromLatin1("Link") );
03123 QString protocol = (*it).uSource.protocol();
03124 if ( protocol == QString::fromLatin1("ftp") )
03125 config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("ftp") );
03126 else if ( protocol == QString::fromLatin1("http") )
03127 config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("www") );
03128 else if ( protocol == QString::fromLatin1("info") )
03129 config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("info") );
03130 else if ( protocol == QString::fromLatin1("mailto") )
03131 config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("kmail") );
03132 else
03133 config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("unknown") );
03134 config.sync();
03135 files.remove( it );
03136 m_processedFiles++;
03137
03138 copyNextFile();
03139 return;
03140 }
03141 else
03142 {
03143 kdDebug(7007) << "CopyJob::copyNextFile ERR_CANNOT_OPEN_FOR_WRITING" << endl;
03144 m_error = ERR_CANNOT_OPEN_FOR_WRITING;
03145 m_errorText = (*it).uDest.path();
03146 emitResult();
03147 return;
03148 }
03149 }
03150 } else {
03151
03152 m_error = ERR_CANNOT_SYMLINK;
03153 m_errorText = (*it).uDest.prettyURL();
03154 emitResult();
03155 return;
03156 }
03157 }
03158 }
03159 else if ( !(*it).linkDest.isEmpty() &&
03160 ((*it).uSource.protocol() == (*it).uDest.protocol()) &&
03161 ((*it).uSource.host() == (*it).uDest.host()) &&
03162 ((*it).uSource.port() == (*it).uDest.port()) &&
03163 ((*it).uSource.user() == (*it).uDest.user()) &&
03164 ((*it).uSource.pass() == (*it).uDest.pass()))
03165
03166 {
03167 KIO::SimpleJob *newJob = KIO::symlink( (*it).linkDest, (*it).uDest, bOverwrite, false );
03168 Scheduler::scheduleJob(newJob);
03169 newjob = newJob;
03170
03171
03172 m_currentSrcURL=(*it).linkDest;
03173 m_currentDestURL=(*it).uDest;
03174 d->m_bURLDirty = true;
03175
03176 m_bCurrentOperationIsLink = true;
03177
03178 } else if (m_mode == Move)
03179 {
03180 KIO::FileCopyJob * moveJob = KIO::file_move( (*it).uSource, (*it).uDest, (*it).permissions, bOverwrite, false, false );
03181 moveJob->setSourceSize64( (*it).size );
03182 newjob = moveJob;
03183
03184
03185 m_currentSrcURL=(*it).uSource;
03186 m_currentDestURL=(*it).uDest;
03187 d->m_bURLDirty = true;
03188
03189 }
03190 else
03191 {
03192
03193
03194 bool remoteSource = !KProtocolInfo::supportsListing((*it).uSource);
03195 int permissions = (*it).permissions;
03196 if ( d->m_defaultPermissions || ( remoteSource && (*it).uDest.isLocalFile() ) )
03197 permissions = -1;
03198 KIO::FileCopyJob * copyJob = KIO::file_copy( (*it).uSource, (*it).uDest, permissions, bOverwrite, false, false );
03199 copyJob->setParentJob( this );
03200 copyJob->setSourceSize64( (*it).size );
03201 newjob = copyJob;
03202
03203 m_currentSrcURL=(*it).uSource;
03204 m_currentDestURL=(*it).uDest;
03205 d->m_bURLDirty = true;
03206 }
03207 addSubjob(newjob);
03208 connect( newjob, SIGNAL( processedSize( KIO::Job*, KIO::filesize_t ) ),
03209 this, SLOT( slotProcessedSize( KIO::Job*, KIO::filesize_t ) ) );
03210 connect( newjob, SIGNAL( totalSize( KIO::Job*, KIO::filesize_t ) ),
03211 this, SLOT( slotTotalSize( KIO::Job*, KIO::filesize_t ) ) );
03212 }
03213 else
03214 {
03215
03216
03217 deleteNextDir();
03218 }
03219 }
03220
03221 void CopyJob::deleteNextDir()
03222 {
03223 if ( m_mode == Move && !dirsToRemove.isEmpty() )
03224 {
03225 state = STATE_DELETING_DIRS;
03226 d->m_bURLDirty = true;
03227
03228 KURL::List::Iterator it = dirsToRemove.fromLast();
03229 SimpleJob *job = KIO::rmdir( *it );
03230 Scheduler::scheduleJob(job);
03231 dirsToRemove.remove(it);
03232 addSubjob( job );
03233 }
03234 else
03235 {
03236
03237 if ( !m_bOnlyRenames )
03238 {
03239 KDirNotify_stub allDirNotify("*", "KDirNotify*");
03240 KURL url( d->m_globalDest );
03241 if ( d->m_globalDestinationState != DEST_IS_DIR || m_asMethod )
03242 url.setPath( url.directory() );
03243
03244 allDirNotify.FilesAdded( url );
03245
03246 if ( m_mode == Move && !m_srcList.isEmpty() )
03247 allDirNotify.FilesRemoved( m_srcList );
03248 }
03249 if (m_reportTimer!=0)
03250 m_reportTimer->stop();
03251 emitResult();
03252 }
03253 }
03254
03255 void CopyJob::slotProcessedSize( KIO::Job*, KIO::filesize_t data_size )
03256 {
03257
03258 m_fileProcessedSize = data_size;
03259 setProcessedSize(m_processedSize + m_fileProcessedSize);
03260
03261 if ( m_processedSize + m_fileProcessedSize > m_totalSize )
03262 {
03263 m_totalSize = m_processedSize + m_fileProcessedSize;
03264
03265 emit totalSize( this, m_totalSize );
03266 }
03267
03268 emit processedSize( this, m_processedSize + m_fileProcessedSize );
03269 emitPercent( m_processedSize + m_fileProcessedSize, m_totalSize );
03270 }
03271
03272 void CopyJob::slotTotalSize( KIO::Job*, KIO::filesize_t size )
03273 {
03274
03275
03276
03277
03278 if ( m_bSingleFileCopy )
03279 {
03280
03281 m_totalSize = size;
03282 emit totalSize( this, size );
03283 }
03284 }
03285
03286 void CopyJob::slotResultDeletingDirs( Job * job )
03287 {
03288 if (job->error())
03289 {
03290
03291
03292
03293 }
03294 subjobs.remove( job );
03295 assert ( subjobs.isEmpty() );
03296 deleteNextDir();
03297 }
03298
03299 void CopyJob::slotResult( Job *job )
03300 {
03301
03302
03303
03304
03305
03306
03307 switch ( state ) {
03308 case STATE_STATING:
03309 slotResultStating( job );
03310 break;
03311 case STATE_RENAMING:
03312 {
03313 int err = job->error();
03314 subjobs.remove( job );
03315 assert ( subjobs.isEmpty() );
03316
03317 KURL dest = m_dest;
03318 if ( destinationState == DEST_IS_DIR && !m_asMethod )
03319 dest.addPath( m_currentSrcURL.fileName() );
03320 if ( err )
03321 {
03322
03323
03324
03325 if ( m_currentSrcURL.isLocalFile() && m_currentSrcURL.url(-1) != dest.url(-1) &&
03326 m_currentSrcURL.url(-1).lower() == dest.url(-1).lower() &&
03327 ( err == ERR_FILE_ALREADY_EXIST || err == ERR_DIR_ALREADY_EXIST ) )
03328 {
03329 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;
03330 QCString _src( QFile::encodeName(m_currentSrcURL.path()) );
03331 QCString _dest( QFile::encodeName(dest.path()) );
03332 KTempFile tmpFile( m_currentSrcURL.directory(false) );
03333 QCString _tmp( QFile::encodeName(tmpFile.name()) );
03334 kdDebug(7007) << "CopyJob::slotResult KTempFile status:" << tmpFile.status() << " using " << _tmp << " as intermediary" << endl;
03335 tmpFile.unlink();
03336 if ( ::rename( _src, _tmp ) == 0 )
03337 {
03338 if ( !QFile::exists( _dest ) && ::rename( _tmp, _dest ) == 0 )
03339 {
03340 kdDebug(7007) << "Success." << endl;
03341 err = 0;
03342 }
03343 else
03344 {
03345
03346 if ( ::rename( _tmp, _src ) != 0 ) {
03347 kdError(7007) << "Couldn't rename " << tmpFile.name() << " back to " << _src << " !" << endl;
03348
03349 Job::slotResult( job );
03350 return;
03351 }
03352 }
03353 }
03354 }
03355 }
03356 if ( err )
03357 {
03358
03359
03360
03361
03362
03363
03364
03365 Q_ASSERT( m_currentSrcURL == *m_currentStatSrc );
03366
03367
03368 if ( err == ERR_DIR_ALREADY_EXIST || err == ERR_FILE_ALREADY_EXIST )
03369 {
03370 if (m_reportTimer)
03371 m_reportTimer->stop();
03372
03373 QString newPath;
03374
03375
03376 RenameDlg_Mode mode = (RenameDlg_Mode)
03377 ( ( m_conflictError == ERR_DIR_ALREADY_EXIST ? 0 :
03378 ( m_currentSrcURL == dest ) ? M_OVERWRITE_ITSELF : M_OVERWRITE ) );
03379
03380
03381
03382
03383 mode = (RenameDlg_Mode) ( mode | M_SINGLE );
03384
03385
03386 RenameDlg_Result r = Observer::self()->open_RenameDlg( this,
03387 err == ERR_FILE_ALREADY_EXIST ? i18n("File Already Exists") : i18n("Already Exists as Folder"),
03388 m_currentSrcURL.prettyURL(0, KURL::StripFileProtocol),
03389 dest.prettyURL(0, KURL::StripFileProtocol),
03390 mode, newPath );
03391 if (m_reportTimer)
03392 m_reportTimer->start(REPORT_TIMEOUT,false);
03393
03394 switch ( r )
03395 {
03396 case R_CANCEL:
03397 {
03398 m_error = ERR_USER_CANCELED;
03399 emitResult();
03400 return;
03401 }
03402 case R_RENAME:
03403 {
03404
03405
03406 m_dest.setPath( newPath );
03407 KIO::Job* job = KIO::stat( m_dest, false, 2, false );
03408 state = STATE_STATING;
03409 destinationState = DEST_NOT_STATED;
03410 addSubjob(job);
03411 return;
03412 }
03413 case R_OVERWRITE:
03414
03415
03416
03417
03418
03419 kdDebug(7007) << "adding to overwrite list: " << dest.path() << endl;
03420 m_overwriteList.append( dest.path() );
03421 break;
03422 default:
03423
03424 break;
03425 }
03426 }
03427
03428 kdDebug(7007) << "Couldn't rename, reverting to normal way, starting with stat" << endl;
03429
03430 KIO::Job* job = KIO::stat( m_currentSrcURL, true, 2, false );
03431 state = STATE_STATING;
03432 addSubjob(job);
03433 m_bOnlyRenames = false;
03434 }
03435 else
03436 {
03437
03438 emit copyingDone( this, *m_currentStatSrc, dest, true, true );
03439 statNextSrc();
03440 }
03441 }
03442 break;
03443 case STATE_LISTING:
03444
03445
03446 if (job->error())
03447 {
03448 Job::slotResult( job );
03449 return;
03450 }
03451
03452 subjobs.remove( job );
03453 assert ( subjobs.isEmpty() );
03454
03455 statNextSrc();
03456 break;
03457 case STATE_CREATING_DIRS:
03458 slotResultCreatingDirs( job );
03459 break;
03460 case STATE_CONFLICT_CREATING_DIRS:
03461 slotResultConflictCreatingDirs( job );
03462 break;
03463 case STATE_COPYING_FILES:
03464 slotResultCopyingFiles( job );
03465 break;
03466 case STATE_CONFLICT_COPYING_FILES:
03467 slotResultConflictCopyingFiles( job );
03468 break;
03469 case STATE_DELETING_DIRS:
03470 slotResultDeletingDirs( job );
03471 break;
03472 default:
03473 assert( 0 );
03474 }
03475 }
03476
03477 void KIO::CopyJob::setDefaultPermissions( bool b )
03478 {
03479 d->m_defaultPermissions = b;
03480 }
03481
03482 CopyJob *KIO::copy(const KURL& src, const KURL& dest, bool showProgressInfo )
03483 {
03484
03485 KURL::List srcList;
03486 srcList.append( src );
03487 return new CopyJob( srcList, dest, CopyJob::Copy, false, showProgressInfo );
03488 }
03489
03490 CopyJob *KIO::copyAs(const KURL& src, const KURL& dest, bool showProgressInfo )
03491 {
03492
03493 KURL::List srcList;
03494 srcList.append( src );
03495 return new CopyJob( srcList, dest, CopyJob::Copy, true, showProgressInfo );
03496 }
03497
03498 CopyJob *KIO::copy( const KURL::List& src, const KURL& dest, bool showProgressInfo )
03499 {
03500 return new CopyJob( src, dest, CopyJob::Copy, false, showProgressInfo );
03501 }
03502
03503 CopyJob *KIO::move(const KURL& src, const KURL& dest, bool showProgressInfo )
03504 {
03505 KURL::List srcList;
03506 srcList.append( src );
03507 return new CopyJob( srcList, dest, CopyJob::Move, false, showProgressInfo );
03508 }
03509
03510 CopyJob *KIO::moveAs(const KURL& src, const KURL& dest, bool showProgressInfo )
03511 {
03512 KURL::List srcList;
03513 srcList.append( src );
03514 return new CopyJob( srcList, dest, CopyJob::Move, true, showProgressInfo );
03515 }
03516
03517 CopyJob *KIO::move( const KURL::List& src, const KURL& dest, bool showProgressInfo )
03518 {
03519 return new CopyJob( src, dest, CopyJob::Move, false, showProgressInfo );
03520 }
03521
03522 CopyJob *KIO::link(const KURL& src, const KURL& destDir, bool showProgressInfo )
03523 {
03524 KURL::List srcList;
03525 srcList.append( src );
03526 return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
03527 }
03528
03529 CopyJob *KIO::link(const KURL::List& srcList, const KURL& destDir, bool showProgressInfo )
03530 {
03531 return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
03532 }
03533
03534 CopyJob *KIO::linkAs(const KURL& src, const KURL& destDir, bool showProgressInfo )
03535 {
03536 KURL::List srcList;
03537 srcList.append( src );
03538 return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
03539 }
03540
03542
03543 DeleteJob::DeleteJob( const KURL::List& src, bool shred, bool showProgressInfo )
03544 : Job(showProgressInfo), m_totalSize( 0 ), m_processedSize( 0 ), m_fileProcessedSize( 0 ),
03545 m_processedFiles( 0 ), m_processedDirs( 0 ), m_totalFilesDirs( 0 ),
03546 m_srcList(src), m_currentStat(m_srcList.begin()), m_shred(shred), m_reportTimer(0)
03547 {
03548 if ( showProgressInfo ) {
03549
03550 connect( this, SIGNAL( totalFiles( KIO::Job*, unsigned long ) ),
03551 Observer::self(), SLOT( slotTotalFiles( KIO::Job*, unsigned long ) ) );
03552
03553 connect( this, SIGNAL( totalDirs( KIO::Job*, unsigned long ) ),
03554 Observer::self(), SLOT( slotTotalDirs( KIO::Job*, unsigned long ) ) );
03555
03556
03557
03558
03559
03560
03561
03562
03563
03564
03565
03566 m_reportTimer=new QTimer(this);
03567 connect(m_reportTimer,SIGNAL(timeout()),this,SLOT(slotReport()));
03568
03569 m_reportTimer->start(REPORT_TIMEOUT,false);
03570 }
03571
03572 QTimer::singleShot(0, this, SLOT(slotStart()));
03573 }
03574
03575 void DeleteJob::slotStart()
03576 {
03577 statNextSrc();
03578 }
03579
03580
03581
03582
03583 void DeleteJob::slotReport()
03584 {
03585 if (m_progressId==0)
03586 return;
03587
03588 Observer * observer = Observer::self();
03589
03590 emit deleting( this, m_currentURL );
03591 observer->slotDeleting(this,m_currentURL);
03592
03593 switch( state ) {
03594 case STATE_STATING:
03595 case STATE_LISTING:
03596 emit totalSize( this, m_totalSize );
03597 emit totalFiles( this, files.count() );
03598 emit totalDirs( this, dirs.count() );
03599 break;
03600 case STATE_DELETING_DIRS:
03601 emit processedDirs( this, m_processedDirs );
03602 observer->slotProcessedDirs(this,m_processedDirs);
03603 emitPercent( m_processedFiles + m_processedDirs, m_totalFilesDirs );
03604 break;
03605 case STATE_DELETING_FILES:
03606 observer->slotProcessedFiles(this,m_processedFiles);
03607 emit processedFiles( this, m_processedFiles );
03608 if (!m_shred)
03609 emitPercent( m_processedFiles, m_totalFilesDirs );
03610 break;
03611 }
03612 }
03613
03614
03615 void DeleteJob::slotEntries(KIO::Job* job, const UDSEntryList& list)
03616 {
03617 UDSEntryListConstIterator it = list.begin();
03618 UDSEntryListConstIterator end = list.end();
03619 for (; it != end; ++it)
03620 {
03621 UDSEntry::ConstIterator it2 = (*it).begin();
03622 bool bDir = false;
03623 bool bLink = false;
03624 QString relName;
03625 int atomsFound(0);
03626 for( ; it2 != (*it).end(); it2++ )
03627 {
03628 switch ((*it2).m_uds)
03629 {
03630 case UDS_FILE_TYPE:
03631 bDir = S_ISDIR((*it2).m_long);
03632 atomsFound++;
03633 break;
03634 case UDS_NAME:
03635 if( relName.isEmpty() )
03636 relName = (*it2).m_str;
03637 break;
03638 case UDS_URL:
03639 relName = KURL((*it2).m_str).fileName();
03640 atomsFound++;
03641 break;
03642 case UDS_LINK_DEST:
03643 bLink = !(*it2).m_str.isEmpty();
03644 atomsFound++;
03645 break;
03646 case UDS_SIZE:
03647 m_totalSize += (KIO::filesize_t)((*it2).m_long);
03648 atomsFound++;
03649 break;
03650 default:
03651 break;
03652 }
03653 if (atomsFound==4) break;
03654 }
03655 assert(!relName.isEmpty());
03656 if (relName != ".." && relName != ".")
03657 {
03658 KURL url = ((SimpleJob *)job)->url();
03659 url.addPath( relName );
03660
03661 if ( bLink )
03662 symlinks.append( url );
03663 else if ( bDir )
03664 dirs.append( url );
03665 else
03666 files.append( url );
03667 }
03668 }
03669 }
03670
03671
03672 void DeleteJob::statNextSrc()
03673 {
03674
03675 if ( m_currentStat != m_srcList.end() )
03676 {
03677 m_currentURL = (*m_currentStat);
03678
03679
03680 if (!KProtocolInfo::supportsDeleting(m_currentURL)) {
03681 QGuardedPtr<DeleteJob> that = this;
03682 ++m_currentStat;
03683 KMessageBox::information( 0, buildErrorString(ERR_CANNOT_DELETE, m_currentURL.prettyURL()));
03684 if (that)
03685 statNextSrc();
03686 return;
03687 }
03688
03689 state = STATE_STATING;
03690 KIO::SimpleJob * job = KIO::stat( m_currentURL, true, 1, false );
03691 Scheduler::scheduleJob(job);
03692
03693 addSubjob(job);
03694
03695
03696 } else
03697 {
03698 m_totalFilesDirs = files.count()+symlinks.count() + dirs.count();
03699 slotReport();
03700
03701
03702
03703
03704 for ( QStringList::Iterator it = m_parentDirs.begin() ; it != m_parentDirs.end() ; ++it )
03705 KDirWatch::self()->stopDirScan( *it );
03706 state = STATE_DELETING_FILES;
03707 deleteNextFile();
03708 }
03709 }
03710
03711 void DeleteJob::deleteNextFile()
03712 {
03713
03714 if ( !files.isEmpty() || !symlinks.isEmpty() )
03715 {
03716 SimpleJob *job;
03717 do {
03718
03719 KURL::List::Iterator it = files.begin();
03720 bool isLink = false;
03721 if ( it == files.end() )
03722 {
03723 it = symlinks.begin();
03724 isLink = true;
03725 }
03726
03727 if ( m_shred && (*it).isLocalFile() && !isLink )
03728 {
03729
03730 KIO_ARGS << int(3) << (*it).path();
03731 job = KIO::special(KURL("file:/"), packedArgs, false );
03732 Scheduler::scheduleJob(job);
03733 m_currentURL=(*it);
03734 connect( job, SIGNAL( processedSize( KIO::Job*, KIO::filesize_t ) ),
03735 this, SLOT( slotProcessedSize( KIO::Job*, KIO::filesize_t ) ) );
03736 } else
03737 {
03738
03739
03740 if ( (*it).isLocalFile() && unlink( QFile::encodeName((*it).path()) ) == 0 ) {
03741 job = 0;
03742 m_processedFiles++;
03743 if ( m_processedFiles % 300 == 0 ) {
03744 m_currentURL = *it;
03745 slotReport();
03746 }
03747 } else
03748 {
03749 job = KIO::file_delete( *it, false );
03750 Scheduler::scheduleJob(job);
03751 m_currentURL=(*it);
03752 }
03753 }
03754 if ( isLink )
03755 symlinks.remove(it);
03756 else
03757 files.remove(it);
03758 if ( job ) {
03759 addSubjob(job);
03760 return;
03761 }
03762
03763 } while (!job && (!files.isEmpty() || !symlinks.isEmpty()));
03764 }
03765 state = STATE_DELETING_DIRS;
03766 deleteNextDir();
03767 }
03768
03769 void DeleteJob::deleteNextDir()
03770 {
03771 if ( !dirs.isEmpty() )
03772 {
03773 do {
03774
03775 KURL::List::Iterator it = dirs.fromLast();
03776
03777 if ( (*it).isLocalFile() && ::rmdir( QFile::encodeName((*it).path()) ) == 0 ) {
03778
03779 m_processedDirs++;
03780 if ( m_processedDirs % 100 == 0 ) {
03781 m_currentURL = *it;
03782 slotReport();
03783 }
03784 } else
03785 {
03786 SimpleJob *job = KIO::rmdir( *it );
03787 Scheduler::scheduleJob(job);
03788 dirs.remove(it);
03789 addSubjob( job );
03790 return;
03791 }
03792 dirs.remove(it);
03793 } while ( !dirs.isEmpty() );
03794 }
03795
03796
03797 for ( QStringList::Iterator it = m_parentDirs.begin() ; it != m_parentDirs.end() ; ++it )
03798 KDirWatch::self()->restartDirScan( *it );
03799
03800
03801 if ( !m_srcList.isEmpty() )
03802 {
03803 KDirNotify_stub allDirNotify("*", "KDirNotify*");
03804 allDirNotify.FilesRemoved( m_srcList );
03805 }
03806 if (m_reportTimer!=0)
03807 m_reportTimer->stop();
03808 emitResult();
03809 }
03810
03811 void DeleteJob::slotProcessedSize( KIO::Job*, KIO::filesize_t data_size )
03812 {
03813
03814
03815
03816
03817 m_fileProcessedSize = data_size;
03818 setProcessedSize(m_processedSize + m_fileProcessedSize);
03819
03820
03821
03822 emit processedSize( this, m_processedSize + m_fileProcessedSize );
03823
03824
03825 unsigned long ipercent = m_percent;
03826
03827 if ( m_totalSize == 0 )
03828 m_percent = 100;
03829 else
03830 m_percent = (unsigned long)(( (float)(m_processedSize + m_fileProcessedSize) / (float)m_totalSize ) * 100.0);
03831
03832 if ( m_percent > ipercent )
03833 {
03834 emit percent( this, m_percent );
03835
03836 }
03837
03838 }
03839
03840 void DeleteJob::slotResult( Job *job )
03841 {
03842 switch ( state )
03843 {
03844 case STATE_STATING:
03845 {
03846
03847 if (job->error() )
03848 {
03849
03850 Job::slotResult( job );
03851 return;
03852 }
03853
03854
03855 UDSEntry entry = ((StatJob*)job)->statResult();
03856 bool bDir = false;
03857 bool bLink = false;
03858 KIO::filesize_t size = (KIO::filesize_t)-1;
03859 UDSEntry::ConstIterator it2 = entry.begin();
03860 int atomsFound(0);
03861 for( ; it2 != entry.end(); it2++ )
03862 {
03863 if ( ((*it2).m_uds) == UDS_FILE_TYPE )
03864 {
03865 bDir = S_ISDIR( (mode_t)(*it2).m_long );
03866 atomsFound++;
03867 }
03868 else if ( ((*it2).m_uds) == UDS_LINK_DEST )
03869 {
03870 bLink = !((*it2).m_str.isEmpty());
03871 atomsFound++;
03872 }
03873 else if ( ((*it2).m_uds) == UDS_SIZE )
03874 {
03875 size = (*it2).m_long;
03876 atomsFound++;
03877 };
03878 if (atomsFound==3) break;
03879 }
03880
03881 KURL url = ((SimpleJob*)job)->url();
03882
03883 subjobs.remove( job );
03884 assert( subjobs.isEmpty() );
03885
03886 if (bDir && !bLink)
03887 {
03888
03889 dirs.append( url );
03890 if ( url.isLocalFile() && !m_parentDirs.contains( url.path(-1) ) )
03891 m_parentDirs.append( url.path(-1) );
03892
03893
03894
03895 state = STATE_LISTING;
03896 ListJob *newjob = listRecursive( url, false );
03897 newjob->setUnrestricted(true);
03898 Scheduler::scheduleJob(newjob);
03899 connect(newjob, SIGNAL(entries( KIO::Job *,
03900 const KIO::UDSEntryList& )),
03901 SLOT( slotEntries( KIO::Job*,
03902 const KIO::UDSEntryList& )));
03903 addSubjob(newjob);
03904 }
03905 else
03906 {
03907 if ( bLink ) {
03908
03909 symlinks.append( url );
03910 } else {
03911
03912 files.append( url );
03913 }
03914 if ( url.isLocalFile() && !m_parentDirs.contains( url.directory(-1) ) )
03915 m_parentDirs.append( url.directory(-1) );
03916 ++m_currentStat;
03917 statNextSrc();
03918 }
03919 }
03920 break;
03921 case STATE_LISTING:
03922 if ( job->error() )
03923 {
03924
03925 }
03926 subjobs.remove( job );
03927 assert( subjobs.isEmpty() );
03928 ++m_currentStat;
03929 statNextSrc();
03930 break;
03931 case STATE_DELETING_FILES:
03932 if ( job->error() )
03933 {
03934 Job::slotResult( job );
03935 return;
03936 }
03937 subjobs.remove( job );
03938 assert( subjobs.isEmpty() );
03939 m_processedFiles++;
03940
03941 deleteNextFile();
03942 break;
03943 case STATE_DELETING_DIRS:
03944 if ( job->error() )
03945 {
03946 Job::slotResult( job );
03947 return;
03948 }
03949 subjobs.remove( job );
03950 assert( subjobs.isEmpty() );
03951 m_processedDirs++;
03952
03953
03954
03955
03956 deleteNextDir();
03957 break;
03958 default:
03959 assert(0);
03960 }
03961 }
03962
03963 DeleteJob *KIO::del( const KURL& src, bool shred, bool showProgressInfo )
03964 {
03965 KURL::List srcList;
03966 srcList.append( src );
03967 DeleteJob *job = new DeleteJob( srcList, shred, showProgressInfo );
03968 return job;
03969 }
03970
03971 DeleteJob *KIO::del( const KURL::List& src, bool shred, bool showProgressInfo )
03972 {
03973 DeleteJob *job = new DeleteJob( src, shred, showProgressInfo );
03974 return job;
03975 }
03976
03977 MultiGetJob::MultiGetJob(const KURL& url,
03978 bool showProgressInfo)
03979 : TransferJob(url, 0, QByteArray(), QByteArray(), showProgressInfo)
03980 {
03981 m_waitQueue.setAutoDelete(true);
03982 m_activeQueue.setAutoDelete(true);
03983 m_currentEntry = 0;
03984 }
03985
03986 void MultiGetJob::get(long id, const KURL &url, const MetaData &metaData)
03987 {
03988 GetRequest *entry = new GetRequest(id, url, metaData);
03989 entry->metaData["request-id"] = QString("%1").arg(id);
03990 m_waitQueue.append(entry);
03991 }
03992
03993 void MultiGetJob::flushQueue(QPtrList<GetRequest> &queue)
03994 {
03995 GetRequest *entry;
03996
03997
03998 for(entry = m_waitQueue.first(); entry; )
03999 {
04000 if ((m_url.protocol() == entry->url.protocol()) &&
04001 (m_url.host() == entry->url.host()) &&
04002 (m_url.port() == entry->url.port()) &&
04003 (m_url.user() == entry->url.user()))
04004 {
04005 m_waitQueue.take();
04006 queue.append(entry);
04007 entry = m_waitQueue.current();
04008 }
04009 else
04010 {
04011 entry = m_waitQueue.next();
04012 }
04013 }
04014
04015 KIO_ARGS << (Q_INT32) queue.count();
04016 for(entry = queue.first(); entry; entry = queue.next())
04017 {
04018 stream << entry->url << entry->metaData;
04019 }
04020 m_packedArgs = packedArgs;
04021 m_command = CMD_MULTI_GET;
04022 m_outgoingMetaData.clear();
04023 }
04024
04025 void MultiGetJob::start(Slave *slave)
04026 {
04027
04028 GetRequest *entry = m_waitQueue.take(0);
04029 m_activeQueue.append(entry);
04030
04031 m_url = entry->url;
04032
04033 if (!entry->url.protocol().startsWith("http"))
04034 {
04035
04036 KIO_ARGS << entry->url;
04037 m_packedArgs = packedArgs;
04038 m_outgoingMetaData = entry->metaData;
04039 m_command = CMD_GET;
04040 b_multiGetActive = false;
04041 }
04042 else
04043 {
04044 flushQueue(m_activeQueue);
04045 b_multiGetActive = true;
04046 }
04047
04048 TransferJob::start(slave);
04049 }
04050
04051 bool MultiGetJob::findCurrentEntry()
04052 {
04053 if (b_multiGetActive)
04054 {
04055 long id = m_incomingMetaData["request-id"].toLong();
04056 for(GetRequest *entry = m_activeQueue.first(); entry; entry = m_activeQueue.next())
04057 {
04058 if (entry->id == id)
04059 {
04060 m_currentEntry = entry;
04061 return true;
04062 }
04063 }
04064 m_currentEntry = 0;
04065 return false;
04066 }
04067 else
04068 {
04069 m_currentEntry = m_activeQueue.first();
04070 return (m_currentEntry != 0);
04071 }
04072 }
04073
04074 void MultiGetJob::slotRedirection( const KURL &url)
04075 {
04076 if (!findCurrentEntry()) return;
04077 if (!kapp->authorizeURLAction("redirect", m_url, url))
04078 {
04079 kdWarning(7007) << "MultiGetJob: Redirection from " << m_currentEntry->url << " to " << url << " REJECTED!" << endl;
04080 return;
04081 }
04082 m_redirectionURL = url;
04083 if (m_currentEntry->url.hasUser() && !url.hasUser() && (m_currentEntry->url.host().lower() == url.host().lower()))
04084 m_redirectionURL.setUser(m_currentEntry->url.user());
04085 get(m_currentEntry->id, m_redirectionURL, m_currentEntry->metaData);
04086 }
04087
04088
04089 void MultiGetJob::slotFinished()
04090 {
04091 if (!findCurrentEntry()) return;
04092 if (m_redirectionURL.isEmpty())
04093 {
04094
04095 emit result(m_currentEntry->id);
04096 }
04097 m_redirectionURL = KURL();
04098 m_error = 0;
04099 m_incomingMetaData.clear();
04100 m_activeQueue.removeRef(m_currentEntry);
04101 if (m_activeQueue.count() == 0)
04102 {
04103 if (m_waitQueue.count() == 0)
04104 {
04105
04106 TransferJob::slotFinished();
04107 }
04108 else
04109 {
04110
04111
04112
04113 GetRequest *entry = m_waitQueue.at(0);
04114 m_url = entry->url;
04115 slaveDone();
04116 Scheduler::doJob(this);
04117 }
04118 }
04119 }
04120
04121 void MultiGetJob::slotData( const QByteArray &_data)
04122 {
04123 if(!m_currentEntry) return;
04124 if(m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error)
04125 emit data(m_currentEntry->id, _data);
04126 }
04127
04128 void MultiGetJob::slotMimetype( const QString &_mimetype )
04129 {
04130 if (b_multiGetActive)
04131 {
04132 QPtrList<GetRequest> newQueue;
04133 flushQueue(newQueue);
04134 if (!newQueue.isEmpty())
04135 {
04136 while(!newQueue.isEmpty())
04137 m_activeQueue.append(newQueue.take(0));
04138 m_slave->send( m_command, m_packedArgs );
04139 }
04140 }
04141 if (!findCurrentEntry()) return;
04142 emit mimetype(m_currentEntry->id, _mimetype);
04143 }
04144
04145 MultiGetJob *KIO::multi_get(long id, const KURL &url, const MetaData &metaData)
04146 {
04147 MultiGetJob * job = new MultiGetJob( url, false );
04148 job->get(id, url, metaData);
04149 return job;
04150 }
04151
04152
04153 #ifdef CACHE_INFO
04154 CacheInfo::CacheInfo(const KURL &url)
04155 {
04156 m_url = url;
04157 }
04158
04159 QString CacheInfo::cachedFileName()
04160 {
04161 const QChar separator = '_';
04162
04163 QString CEF = m_url.path();
04164
04165 int p = CEF.find('/');
04166
04167 while(p != -1)
04168 {
04169 CEF[p] = separator;
04170 p = CEF.find('/', p);
04171 }
04172
04173 QString host = m_url.host().lower();
04174 CEF = host + CEF + '_';
04175
04176 QString dir = KProtocolManager::cacheDir();
04177 if (dir[dir.length()-1] != '/')
04178 dir += "/";
04179
04180 int l = m_url.host().length();
04181 for(int i = 0; i < l; i++)
04182 {
04183 if (host[i].isLetter() && (host[i] != 'w'))
04184 {
04185 dir += host[i];
04186 break;
04187 }
04188 }
04189 if (dir[dir.length()-1] == '/')
04190 dir += "0";
04191
04192 unsigned long hash = 0x00000000;
04193 QCString u = m_url.url().latin1();
04194 for(int i = u.length(); i--;)
04195 {
04196 hash = (hash * 12211 + u[i]) % 2147483563;
04197 }
04198
04199 QString hashString;
04200 hashString.sprintf("%08lx", hash);
04201
04202 CEF = CEF + hashString;
04203
04204 CEF = dir + "/" + CEF;
04205
04206 return CEF;
04207 }
04208
04209 QFile *CacheInfo::cachedFile()
04210 {
04211 const char *mode = (readWrite ? "r+" : "r");
04212
04213 FILE *fs = fopen( CEF.latin1(), mode);
04214 if (!fs)
04215 return 0;
04216
04217 char buffer[401];
04218 bool ok = true;
04219
04220
04221 if (ok && (!fgets(buffer, 400, fs)))
04222 ok = false;
04223 if (ok && (strcmp(buffer, CACHE_REVISION) != 0))
04224 ok = false;
04225
04226 time_t date;
04227 time_t currentDate = time(0);
04228
04229
04230 if (ok && (!fgets(buffer, 400, fs)))
04231 ok = false;
04232 if (ok)
04233 {
04234 int l = strlen(buffer);
04235 if (l>0)
04236 buffer[l-1] = 0;
04237 if (m_.url.url() != buffer)
04238 {
04239 ok = false;
04240 }
04241 }
04242
04243
04244 if (ok && (!fgets(buffer, 400, fs)))
04245 ok = false;
04246 if (ok)
04247 {
04248 date = (time_t) strtoul(buffer, 0, 10);
04249 if (m_maxCacheAge && (difftime(currentDate, date) > m_maxCacheAge))
04250 {
04251 m_bMustRevalidate = true;
04252 m_expireDate = currentDate;
04253 }
04254 }
04255
04256
04257 m_cacheExpireDateOffset = ftell(fs);
04258 if (ok && (!fgets(buffer, 400, fs)))
04259 ok = false;
04260 if (ok)
04261 {
04262 if (m_request.cache == CC_Verify)
04263 {
04264 date = (time_t) strtoul(buffer, 0, 10);
04265
04266 if (!date || difftime(currentDate, date) >= 0)
04267 m_bMustRevalidate = true;
04268 m_expireDate = date;
04269 }
04270 }
04271
04272
04273 if (ok && (!fgets(buffer, 400, fs)))
04274 ok = false;
04275 if (ok)
04276 {
04277 m_etag = QString(buffer).stripWhiteSpace();
04278 }
04279
04280
04281 if (ok && (!fgets(buffer, 400, fs)))
04282 ok = false;
04283 if (ok)
04284 {
04285 m_lastModified = QString(buffer).stripWhiteSpace();
04286 }
04287
04288 fclose(fs);
04289
04290 if (ok)
04291 return fs;
04292
04293 unlink( CEF.latin1());
04294 return 0;
04295
04296 }
04297
04298 void CacheInfo::flush()
04299 {
04300 cachedFile().remove();
04301 }
04302
04303 void CacheInfo::touch()
04304 {
04305
04306 }
04307 void CacheInfo::setExpireDate(int);
04308 void CacheInfo::setExpireTimeout(int);
04309
04310
04311 int CacheInfo::creationDate();
04312 int CacheInfo::expireDate();
04313 int CacheInfo::expireTimeout();
04314 #endif
04315
04316 void Job::virtual_hook( int, void* )
04317 { }
04318
04319 void SimpleJob::virtual_hook( int id, void* data )
04320 { KIO::Job::virtual_hook( id, data ); }
04321
04322 void MkdirJob::virtual_hook( int id, void* data )
04323 { SimpleJob::virtual_hook( id, data ); }
04324
04325 void StatJob::virtual_hook( int id, void* data )
04326 { SimpleJob::virtual_hook( id, data ); }
04327
04328 void TransferJob::virtual_hook( int id, void* data )
04329 { SimpleJob::virtual_hook( id, data ); }
04330
04331 void MultiGetJob::virtual_hook( int id, void* data )
04332 { TransferJob::virtual_hook( id, data ); }
04333
04334 void MimetypeJob::virtual_hook( int id, void* data )
04335 { TransferJob::virtual_hook( id, data ); }
04336
04337 void FileCopyJob::virtual_hook( int id, void* data )
04338 { Job::virtual_hook( id, data ); }
04339
04340 void ListJob::virtual_hook( int id, void* data )
04341 { SimpleJob::virtual_hook( id, data ); }
04342
04343 void CopyJob::virtual_hook( int id, void* data )
04344 { Job::virtual_hook( id, data ); }
04345
04346 void DeleteJob::virtual_hook( int id, void* data )
04347 { Job::virtual_hook( id, data ); }
04348
04349
04350 #include "jobclasses.moc"