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