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 m_totalSize = size;
01569 }
01570
01571 void FileCopyJob::setSourceSize64( KIO::filesize_t size )
01572 {
01573 d->m_sourceSize = size;
01574 m_totalSize = size;
01575 }
01576
01577 void FileCopyJob::startCopyJob()
01578 {
01579 startCopyJob(m_src);
01580 }
01581
01582 void FileCopyJob::startCopyJob(const KURL &slave_url)
01583 {
01584
01585 KIO_ARGS << m_src << m_dest << m_permissions << (Q_INT8) m_overwrite;
01586 m_copyJob = new DirectCopyJob(slave_url, CMD_COPY, packedArgs, false);
01587 addSubjob( m_copyJob );
01588 connectSubjob( m_copyJob );
01589 connect( m_copyJob, SIGNAL(canResume(KIO::Job *, KIO::filesize_t)),
01590 SLOT( slotCanResume(KIO::Job *, KIO::filesize_t)));
01591 }
01592
01593 void FileCopyJob::startRenameJob(const KURL &slave_url)
01594 {
01595 KIO_ARGS << m_src << m_dest << (Q_INT8) m_overwrite;
01596 m_moveJob = new SimpleJob(slave_url, CMD_RENAME, packedArgs, false);
01597 addSubjob( m_moveJob );
01598 connectSubjob( m_moveJob );
01599 }
01600
01601 void FileCopyJob::connectSubjob( SimpleJob * job )
01602 {
01603 connect( job, SIGNAL(totalSize( KIO::Job*, KIO::filesize_t )),
01604 this, SLOT( slotTotalSize(KIO::Job*, KIO::filesize_t)) );
01605
01606 connect( job, SIGNAL(processedSize( KIO::Job*, KIO::filesize_t )),
01607 this, SLOT( slotProcessedSize(KIO::Job*, KIO::filesize_t)) );
01608
01609 connect( job, SIGNAL(percent( KIO::Job*, unsigned long )),
01610 this, SLOT( slotPercent(KIO::Job*, unsigned long)) );
01611
01612 }
01613
01614 void FileCopyJob::slotProcessedSize( KIO::Job *, KIO::filesize_t size )
01615 {
01616 setProcessedSize(size);
01617 emit processedSize( this, size );
01618 if ( size > m_totalSize ) {
01619 slotTotalSize( this, size );
01620 }
01621 emitPercent( size, m_totalSize );
01622 }
01623
01624 void FileCopyJob::slotTotalSize( KIO::Job*, KIO::filesize_t size )
01625 {
01626 if (size > m_totalSize)
01627 {
01628 m_totalSize = size;
01629 emit totalSize( this, m_totalSize );
01630 }
01631 }
01632
01633 void FileCopyJob::slotPercent( KIO::Job*, unsigned long pct )
01634 {
01635 if ( pct > m_percent )
01636 {
01637 m_percent = pct;
01638 emit percent( this, m_percent );
01639 }
01640 }
01641
01642 void FileCopyJob::startDataPump()
01643 {
01644
01645
01646 m_canResume = false;
01647 m_resumeAnswerSent = false;
01648 m_getJob = 0L;
01649 m_putJob = put( m_dest, m_permissions, m_overwrite, m_resume, false );
01650
01651
01652
01653
01654 connect( m_putJob, SIGNAL(canResume(KIO::Job *, KIO::filesize_t)),
01655 SLOT( slotCanResume(KIO::Job *, KIO::filesize_t)));
01656 connect( m_putJob, SIGNAL(dataReq(KIO::Job *, QByteArray&)),
01657 SLOT( slotDataReq(KIO::Job *, QByteArray&)));
01658 addSubjob( m_putJob );
01659 }
01660
01661 void FileCopyJob::slotCanResume( KIO::Job* job, KIO::filesize_t offset )
01662 {
01663 if ( job == m_putJob || job == m_copyJob )
01664 {
01665
01666 if (offset)
01667 {
01668 RenameDlg_Result res = R_RESUME;
01669
01670 if (!KProtocolManager::autoResume() && !m_overwrite)
01671 {
01672 QString newPath;
01673 KIO::Job* job = ( !m_progressId && parentJob() ) ? parentJob() : this;
01674
01675 res = Observer::self()->open_RenameDlg(
01676 job, i18n("File Already Exists"),
01677 m_src.url(),
01678 m_dest.url(),
01679 (RenameDlg_Mode) (M_OVERWRITE | M_RESUME | M_NORENAME), newPath,
01680 d->m_sourceSize, offset );
01681 }
01682
01683 if ( res == R_OVERWRITE || m_overwrite )
01684 offset = 0;
01685 else if ( res == R_CANCEL )
01686 {
01687 if ( job == m_putJob )
01688 m_putJob->kill(true);
01689 else
01690 m_copyJob->kill(true);
01691 m_error = ERR_USER_CANCELED;
01692 emitResult();
01693 return;
01694 }
01695 }
01696 else
01697 m_resumeAnswerSent = true;
01698
01699 if ( job == m_putJob )
01700 {
01701 m_getJob = get( m_src, false, false );
01702
01703 m_getJob->addMetaData( "errorPage", "false" );
01704 m_getJob->addMetaData( "AllowCompressedPage", "false" );
01705
01706 if ( d->m_sourceSize != (KIO::filesize_t)-1 )
01707 m_getJob->slotTotalSize( d->m_sourceSize );
01708 if (offset)
01709 {
01710
01711 m_getJob->addMetaData( "resume", KIO::number(offset) );
01712
01713
01714 connect( m_getJob, SIGNAL(canResume(KIO::Job *, KIO::filesize_t)),
01715 SLOT( slotCanResume(KIO::Job *, KIO::filesize_t)));
01716 }
01717 m_putJob->slave()->setOffset( offset );
01718
01719 m_putJob->suspend();
01720 addSubjob( m_getJob );
01721 connectSubjob( m_getJob );
01722 m_getJob->resume();
01723
01724 connect( m_getJob, SIGNAL(data(KIO::Job *, const QByteArray&)),
01725 SLOT( slotData(KIO::Job *, const QByteArray&)));
01726 }
01727 else
01728 {
01729 m_copyJob->slave()->sendResumeAnswer( offset != 0 );
01730 }
01731 }
01732 else if ( job == m_getJob )
01733 {
01734
01735 m_canResume = true;
01736
01737
01738 m_getJob->slave()->setOffset( m_putJob->slave()->offset() );
01739 }
01740 else
01741 kdWarning(7007) << "FileCopyJob::slotCanResume from unknown job=" << job
01742 << " m_getJob=" << m_getJob << " m_putJob=" << m_putJob << endl;
01743 }
01744
01745 void FileCopyJob::slotData( KIO::Job * , const QByteArray &data)
01746 {
01747
01748
01749 assert(m_putJob);
01750 if (!m_putJob) return;
01751 m_getJob->suspend();
01752 m_putJob->resume();
01753 m_buffer = data;
01754
01755
01756
01757 if (!m_resumeAnswerSent)
01758 {
01759 m_resumeAnswerSent = true;
01760
01761 m_putJob->slave()->sendResumeAnswer( m_canResume );
01762 }
01763 }
01764
01765 void FileCopyJob::slotDataReq( KIO::Job * , QByteArray &data)
01766 {
01767
01768 if (!m_resumeAnswerSent && !m_getJob)
01769 {
01770
01771 m_error = ERR_INTERNAL;
01772 m_errorText = "'Put' job didn't send canResume or 'Get' job didn't send data!";
01773 m_putJob->kill(true);
01774 emitResult();
01775 return;
01776 }
01777 if (m_getJob)
01778 {
01779 m_getJob->resume();
01780 m_putJob->suspend();
01781 }
01782 data = m_buffer;
01783 m_buffer = QByteArray();
01784 }
01785
01786 void FileCopyJob::slotResult( KIO::Job *job)
01787 {
01788
01789
01790 if ( job->error() )
01791 {
01792 if ((job == m_moveJob) && (job->error() == ERR_UNSUPPORTED_ACTION))
01793 {
01794 m_moveJob = 0;
01795 startBestCopyMethod();
01796 removeSubjob(job);
01797 return;
01798 }
01799 else if ((job == m_copyJob) && (job->error() == ERR_UNSUPPORTED_ACTION))
01800 {
01801 m_copyJob = 0;
01802 startDataPump();
01803 removeSubjob(job);
01804 return;
01805 }
01806 else if (job == m_getJob)
01807 {
01808 m_getJob = 0L;
01809 if (m_putJob)
01810 m_putJob->kill(true);
01811 }
01812 else if (job == m_putJob)
01813 {
01814 m_putJob = 0L;
01815 if (m_getJob)
01816 m_getJob->kill(true);
01817 }
01818 m_error = job->error();
01819 m_errorText = job->errorText();
01820 emitResult();
01821 return;
01822 }
01823
01824 if (job == m_moveJob)
01825 {
01826 m_moveJob = 0;
01827 }
01828
01829 if (job == m_copyJob)
01830 {
01831 m_copyJob = 0;
01832 if (m_move)
01833 {
01834 d->m_delJob = file_delete( m_src, false );
01835 addSubjob(d->m_delJob);
01836 }
01837 }
01838
01839 if (job == m_getJob)
01840 {
01841 m_getJob = 0;
01842 if (m_putJob)
01843 m_putJob->resume();
01844 }
01845
01846 if (job == m_putJob)
01847 {
01848
01849 m_putJob = 0;
01850 if (m_getJob)
01851 {
01852 kdWarning(7007) << "WARNING ! Get still going on..." << endl;
01853 m_getJob->resume();
01854 }
01855 if (m_move)
01856 {
01857 d->m_delJob = file_delete( m_src, false );
01858 addSubjob(d->m_delJob);
01859 }
01860 }
01861
01862 if (job == d->m_delJob)
01863 {
01864 d->m_delJob = 0;
01865 }
01866 removeSubjob(job);
01867 }
01868
01869 FileCopyJob *KIO::file_copy( const KURL& src, const KURL& dest, int permissions,
01870 bool overwrite, bool resume, bool showProgressInfo)
01871 {
01872 return new FileCopyJob( src, dest, permissions, false, overwrite, resume, showProgressInfo );
01873 }
01874
01875 FileCopyJob *KIO::file_move( const KURL& src, const KURL& dest, int permissions,
01876 bool overwrite, bool resume, bool showProgressInfo)
01877 {
01878 return new FileCopyJob( src, dest, permissions, true, overwrite, resume, showProgressInfo );
01879 }
01880
01881 SimpleJob *KIO::file_delete( const KURL& src, bool showProgressInfo)
01882 {
01883 KIO_ARGS << src << Q_INT8(true);
01884 return new SimpleJob(src, CMD_DEL, packedArgs, showProgressInfo );
01885 }
01886
01888
01889
01890 ListJob::ListJob(const KURL& u, bool showProgressInfo, bool _recursive, QString _prefix, bool _includeHidden) :
01891 SimpleJob(u, CMD_LISTDIR, QByteArray(), showProgressInfo),
01892 recursive(_recursive), includeHidden(_includeHidden), prefix(_prefix), m_processedEntries(0)
01893 {
01894
01895
01896 QDataStream stream( m_packedArgs, IO_WriteOnly );
01897 stream << u;
01898 }
01899
01900 void ListJob::slotListEntries( const KIO::UDSEntryList& list )
01901 {
01902
01903 m_processedEntries += list.count();
01904 slotProcessedSize( m_processedEntries );
01905
01906 if (recursive) {
01907 UDSEntryListConstIterator it = list.begin();
01908 UDSEntryListConstIterator end = list.end();
01909
01910 for (; it != end; ++it) {
01911 bool isDir = false;
01912 bool isLink = false;
01913 KURL itemURL;
01914
01915 UDSEntry::ConstIterator it2 = (*it).begin();
01916 UDSEntry::ConstIterator end2 = (*it).end();
01917 for( ; it2 != end2; it2++ ) {
01918 switch( (*it2).m_uds ) {
01919 case UDS_FILE_TYPE:
01920 isDir = S_ISDIR((*it2).m_long);
01921 break;
01922 case UDS_NAME:
01923 if( itemURL.isEmpty() ) {
01924 itemURL = url();
01925 itemURL.addPath( (*it2).m_str );
01926 }
01927 break;
01928 case UDS_URL:
01929 itemURL = (*it2).m_str;
01930 break;
01931 case UDS_LINK_DEST:
01932
01933 isLink = !(*it2).m_str.isEmpty();
01934 break;
01935 default:
01936 break;
01937 }
01938 }
01939 if (isDir && !isLink) {
01940 const QString filename = itemURL.fileName();
01941
01942 if (filename != ".." && filename != "." && (includeHidden || filename[0] != '.')) {
01943 ListJob *job = new ListJob(itemURL,
01944 false ,
01945 true ,
01946 prefix + filename + "/",
01947 includeHidden);
01948 Scheduler::scheduleJob(job);
01949 connect(job, SIGNAL(entries( KIO::Job *,
01950 const KIO::UDSEntryList& )),
01951 SLOT( gotEntries( KIO::Job*,
01952 const KIO::UDSEntryList& )));
01953 addSubjob(job);
01954 }
01955 }
01956 }
01957 }
01958
01959
01960
01961
01962 if (prefix.isNull() && includeHidden) {
01963 emit entries(this, list);
01964 } else {
01965
01966 UDSEntryList newlist;
01967
01968 UDSEntryListConstIterator it = list.begin();
01969 UDSEntryListConstIterator end = list.end();
01970 for (; it != end; ++it) {
01971
01972 UDSEntry newone = *it;
01973 UDSEntry::Iterator it2 = newone.begin();
01974 QString filename;
01975 for( ; it2 != newone.end(); it2++ ) {
01976 if ((*it2).m_uds == UDS_NAME) {
01977 filename = (*it2).m_str;
01978 (*it2).m_str = prefix + filename;
01979 }
01980 }
01981
01982
01983 if ( (prefix.isNull() || (filename != ".." && filename != ".") )
01984 && (includeHidden || (filename[0] != '.') ) )
01985 newlist.append(newone);
01986 }
01987
01988 emit entries(this, newlist);
01989 }
01990 }
01991
01992 void ListJob::gotEntries(KIO::Job *, const KIO::UDSEntryList& list )
01993 {
01994
01995 emit entries(this, list);
01996 }
01997
01998 void ListJob::slotResult( KIO::Job * job )
01999 {
02000
02001
02002 removeSubjob( job );
02003 }
02004
02005 void ListJob::slotRedirection( const KURL & url )
02006 {
02007 if (!kapp->authorizeURLAction("redirect", m_url, url))
02008 {
02009 kdWarning(7007) << "ListJob: Redirection from " << m_url << " to " << url << " REJECTED!" << endl;
02010 return;
02011 }
02012 m_redirectionURL = url;
02013 if (m_url.hasUser() && !url.hasUser() && (m_url.host().lower() == url.host().lower()))
02014 m_redirectionURL.setUser(m_url.user());
02015 emit redirection( this, m_redirectionURL );
02016 }
02017
02018 void ListJob::slotFinished()
02019 {
02020
02021 if ( m_error == KIO::ERR_IS_FILE && m_url.isLocalFile() ) {
02022 KMimeType::Ptr ptr = KMimeType::findByURL( m_url, 0, true, true );
02023 if ( ptr ) {
02024 QString proto = ptr->property("X-KDE-LocalProtocol").toString();
02025 if ( !proto.isEmpty() ) {
02026 m_redirectionURL = m_url;
02027 m_redirectionURL.setProtocol( proto );
02028 m_error = 0;
02029 emit redirection(this,m_redirectionURL);
02030 }
02031 }
02032 }
02033 if ( m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error ) {
02034
02035 SimpleJob::slotFinished();
02036 } else {
02037
02038
02039 if (queryMetaData("permanent-redirect")=="true")
02040 emit permanentRedirection(this, m_url, m_redirectionURL);
02041 m_url = m_redirectionURL;
02042 m_redirectionURL = KURL();
02043 m_packedArgs.truncate(0);
02044 QDataStream stream( m_packedArgs, IO_WriteOnly );
02045 stream << m_url;
02046
02047
02048 slaveDone();
02049 Scheduler::doJob(this);
02050 }
02051 }
02052
02053 void ListJob::slotMetaData( const KIO::MetaData &_metaData) {
02054 SimpleJob::slotMetaData(_metaData);
02055 storeSSLSessionFromJob(m_redirectionURL);
02056 }
02057
02058 ListJob *KIO::listDir( const KURL& url, bool showProgressInfo, bool includeHidden )
02059 {
02060 ListJob * job = new ListJob(url, showProgressInfo,false,QString::null,includeHidden);
02061 return job;
02062 }
02063
02064 ListJob *KIO::listRecursive( const KURL& url, bool showProgressInfo, bool includeHidden )
02065 {
02066 ListJob * job = new ListJob(url, showProgressInfo, true,QString::null,includeHidden);
02067 return job;
02068 }
02069
02070 void ListJob::setUnrestricted(bool unrestricted)
02071 {
02072 if (unrestricted)
02073 extraFlags() |= EF_ListJobUnrestricted;
02074 else
02075 extraFlags() &= ~EF_ListJobUnrestricted;
02076 }
02077
02078 void ListJob::start(Slave *slave)
02079 {
02080 if (!kapp->authorizeURLAction("list", m_url, m_url) && !(extraFlags() & EF_ListJobUnrestricted))
02081 {
02082 m_error = ERR_ACCESS_DENIED;
02083 m_errorText = m_url.url();
02084 QTimer::singleShot(0, this, SLOT(slotFinished()) );
02085 return;
02086 }
02087 connect( slave, SIGNAL( listEntries( const KIO::UDSEntryList& )),
02088 SLOT( slotListEntries( const KIO::UDSEntryList& )));
02089 connect( slave, SIGNAL( totalSize( KIO::filesize_t ) ),
02090 SLOT( slotTotalSize( KIO::filesize_t ) ) );
02091 connect( slave, SIGNAL( redirection(const KURL &) ),
02092 SLOT( slotRedirection(const KURL &) ) );
02093
02094 SimpleJob::start(slave);
02095 }
02096
02097 class CopyJob::CopyJobPrivate
02098 {
02099 public:
02100 CopyJobPrivate() {
02101 m_defaultPermissions = false;
02102 m_interactive = true;
02103 m_bURLDirty = false;
02104 }
02105
02106
02107
02108
02109 KURL m_globalDest;
02110
02111 CopyJob::DestinationState m_globalDestinationState;
02112
02113 bool m_defaultPermissions;
02114
02115 bool m_interactive;
02116
02117 bool m_bURLDirty;
02118 };
02119
02120 CopyJob::CopyJob( const KURL::List& src, const KURL& dest, CopyMode mode, bool asMethod, bool showProgressInfo )
02121 : Job(showProgressInfo), m_mode(mode), m_asMethod(asMethod),
02122 destinationState(DEST_NOT_STATED), state(STATE_STATING),
02123 m_totalSize(0), m_processedSize(0), m_fileProcessedSize(0),
02124 m_processedFiles(0), m_processedDirs(0),
02125 m_srcList(src), m_currentStatSrc(m_srcList.begin()),
02126 m_bCurrentOperationIsLink(false), m_bSingleFileCopy(false), m_bOnlyRenames(mode==Move),
02127 m_dest(dest), m_bAutoSkip( false ), m_bOverwriteAll( false ),
02128 m_conflictError(0), m_reportTimer(0)
02129 {
02130 d = new CopyJobPrivate;
02131 d->m_globalDest = dest;
02132 d->m_globalDestinationState = destinationState;
02133
02134 if ( showProgressInfo ) {
02135 connect( this, SIGNAL( totalFiles( KIO::Job*, unsigned long ) ),
02136 Observer::self(), SLOT( slotTotalFiles( KIO::Job*, unsigned long ) ) );
02137
02138 connect( this, SIGNAL( totalDirs( KIO::Job*, unsigned long ) ),
02139 Observer::self(), SLOT( slotTotalDirs( KIO::Job*, unsigned long ) ) );
02140 }
02141 QTimer::singleShot(0, this, SLOT(slotStart()));
02155 }
02156
02157 CopyJob::~CopyJob()
02158 {
02159 delete d;
02160 }
02161
02162 void CopyJob::slotStart()
02163 {
02169 m_reportTimer = new QTimer(this);
02170
02171 connect(m_reportTimer,SIGNAL(timeout()),this,SLOT(slotReport()));
02172 m_reportTimer->start(REPORT_TIMEOUT,false);
02173
02174
02175 KIO::Job * job = KIO::stat( m_dest, false, 2, false );
02176
02177 addSubjob(job);
02178 }
02179
02180 void CopyJob::slotResultStating( Job *job )
02181 {
02182
02183
02184 if (job->error() && destinationState != DEST_NOT_STATED )
02185 {
02186 KURL srcurl = ((SimpleJob*)job)->url();
02187 if ( !srcurl.isLocalFile() )
02188 {
02189
02190
02191
02192 kdDebug(7007) << "Error while stating source. Activating hack" << endl;
02193 subjobs.remove( job );
02194 assert ( subjobs.isEmpty() );
02195 struct CopyInfo info;
02196 info.permissions = (mode_t) -1;
02197 info.mtime = (time_t) -1;
02198 info.ctime = (time_t) -1;
02199 info.size = (KIO::filesize_t)-1;
02200 info.uSource = srcurl;
02201 info.uDest = m_dest;
02202
02203 if ( destinationState == DEST_IS_DIR && !m_asMethod )
02204 info.uDest.addPath( srcurl.fileName() );
02205
02206 files.append( info );
02207 statNextSrc();
02208 return;
02209 }
02210
02211 Job::slotResult( job );
02212 return;
02213 }
02214
02215
02216 UDSEntry entry = ((StatJob*)job)->statResult();
02217 bool bDir = false;
02218 bool bLink = false;
02219 QString sName;
02220 UDSEntry::ConstIterator it2 = entry.begin();
02221 for( ; it2 != entry.end(); it2++ ) {
02222 if ( ((*it2).m_uds) == UDS_FILE_TYPE )
02223 bDir = S_ISDIR( (mode_t)(*it2).m_long );
02224 else if ( ((*it2).m_uds) == UDS_LINK_DEST )
02225 bLink = !((*it2).m_str.isEmpty());
02226 else if ( ((*it2).m_uds) == UDS_NAME )
02227 sName = (*it2).m_str;
02228 }
02229
02230 if ( destinationState == DEST_NOT_STATED )
02231
02232 {
02233 if (job->error())
02234 destinationState = DEST_DOESNT_EXIST;
02235 else {
02236
02237 destinationState = bDir ? DEST_IS_DIR : DEST_IS_FILE;
02238
02239 }
02240 if ( m_dest == d->m_globalDest )
02241 d->m_globalDestinationState = destinationState;
02242 subjobs.remove( job );
02243 assert ( subjobs.isEmpty() );
02244
02245
02246 statCurrentSrc();
02247 return;
02248 }
02249
02250 m_currentDest = m_dest;
02251
02252 UDSEntryList lst;
02253 lst.append(entry);
02254
02255
02256
02257
02258
02259
02260
02261
02262
02263
02264
02265
02266
02267 m_bCurrentSrcIsDir = false;
02268 slotEntries(job, lst);
02269
02270 KURL srcurl = ((SimpleJob*)job)->url();
02271
02272 subjobs.remove( job );
02273 assert ( subjobs.isEmpty() );
02274
02275 if ( bDir
02276 && !bLink
02277 && m_mode != Link )
02278 {
02279
02280
02281 m_bCurrentSrcIsDir = true;
02282 if ( destinationState == DEST_IS_DIR )
02283 {
02284 if ( !m_asMethod )
02285 {
02286
02287 QString directory = srcurl.fileName();
02288 if ( !sName.isEmpty() && KProtocolInfo::fileNameUsedForCopying( srcurl ) == KProtocolInfo::Name )
02289 {
02290 directory = sName;
02291 }
02292 m_currentDest.addPath( directory );
02293 }
02294 }
02295 else if ( destinationState == DEST_IS_FILE )
02296 {
02297 m_error = ERR_IS_FILE;
02298 m_errorText = m_dest.prettyURL();
02299 emitResult();
02300 return;
02301 }
02302 else
02303 {
02304
02305
02306
02307
02308 destinationState = DEST_IS_DIR;
02309 if ( m_dest == d->m_globalDest )
02310 d->m_globalDestinationState = destinationState;
02311 }
02312
02313 startListing( srcurl );
02314 }
02315 else
02316 {
02317
02318 statNextSrc();
02319 }
02320 }
02321
02322 void CopyJob::slotReport()
02323 {
02324
02325 Observer * observer = m_progressId ? Observer::self() : 0L;
02326 switch (state) {
02327 case STATE_COPYING_FILES:
02328 emit processedFiles( this, m_processedFiles );
02329 if (observer) observer->slotProcessedFiles(this, m_processedFiles);
02330 if (d->m_bURLDirty)
02331 {
02332
02333 d->m_bURLDirty = false;
02334 if (m_mode==Move)
02335 {
02336 if (observer) observer->slotMoving( this, m_currentSrcURL, m_currentDestURL);
02337 emit moving( this, m_currentSrcURL, m_currentDestURL);
02338 }
02339 else if (m_mode==Link)
02340 {
02341 if (observer) observer->slotCopying( this, m_currentSrcURL, m_currentDestURL );
02342 emit linking( this, m_currentSrcURL.path(), m_currentDestURL );
02343 }
02344 else
02345 {
02346 if (observer) observer->slotCopying( this, m_currentSrcURL, m_currentDestURL );
02347 emit copying( this, m_currentSrcURL, m_currentDestURL );
02348 }
02349 }
02350 break;
02351
02352 case STATE_CREATING_DIRS:
02353 if (observer) observer->slotProcessedDirs( this, m_processedDirs );
02354 emit processedDirs( this, m_processedDirs );
02355 if (d->m_bURLDirty)
02356 {
02357 d->m_bURLDirty = false;
02358 emit creatingDir( this, m_currentDestURL );
02359 if (observer) observer->slotCreatingDir( this, m_currentDestURL);
02360 }
02361 break;
02362
02363 case STATE_STATING:
02364 case STATE_LISTING:
02365 if (d->m_bURLDirty)
02366 {
02367 d->m_bURLDirty = false;
02368 if (observer) observer->slotCopying( this, m_currentSrcURL, m_currentDestURL );
02369 }
02370 emit totalSize( this, m_totalSize );
02371 emit totalFiles( this, files.count() );
02372 emit totalDirs( this, dirs.count() );
02373 break;
02374
02375 default:
02376 break;
02377 }
02378 }
02379
02380 void CopyJob::slotEntries(KIO::Job* job, const UDSEntryList& list)
02381 {
02382 UDSEntryListConstIterator it = list.begin();
02383 UDSEntryListConstIterator end = list.end();
02384 for (; it != end; ++it) {
02385 UDSEntry::ConstIterator it2 = (*it).begin();
02386 struct CopyInfo info;
02387 info.permissions = -1;
02388 info.mtime = (time_t) -1;
02389 info.ctime = (time_t) -1;
02390 info.size = (KIO::filesize_t)-1;
02391 QString displayName;
02392 KURL url;
02393 QString localPath;
02394 bool isDir = false;
02395 for( ; it2 != (*it).end(); it2++ ) {
02396 switch ((*it2).m_uds) {
02397 case UDS_FILE_TYPE:
02398
02399 isDir = S_ISDIR( (mode_t)((*it2).m_long) );
02400 break;
02401 case UDS_NAME:
02402 displayName = (*it2).m_str;
02403 break;
02404 case UDS_URL:
02405 url = KURL((*it2).m_str);
02406 break;
02407 case UDS_LOCAL_PATH:
02408 localPath = (*it2).m_str;
02409 break;
02410 case UDS_LINK_DEST:
02411 info.linkDest = (*it2).m_str;
02412 break;
02413 case UDS_ACCESS:
02414 info.permissions = ((*it2).m_long);
02415 break;
02416 case UDS_SIZE:
02417 info.size = (KIO::filesize_t)((*it2).m_long);
02418 m_totalSize += info.size;
02419 break;
02420 case UDS_MODIFICATION_TIME:
02421 info.mtime = (time_t)((*it2).m_long);
02422 break;
02423 case UDS_CREATION_TIME:
02424 info.ctime = (time_t)((*it2).m_long);
02425 default:
02426 break;
02427 }
02428 }
02429 if (displayName != ".." && displayName != ".")
02430 {
02431 bool hasCustomURL = !url.isEmpty() || !localPath.isEmpty();
02432 if( !hasCustomURL ) {
02433
02434 url = ((SimpleJob *)job)->url();
02435 if ( m_bCurrentSrcIsDir ) {
02436
02437 url.addPath( displayName );
02438 }
02439 }
02440
02441 if (!localPath.isEmpty()) {
02442 url = KURL();
02443 url.setPath(localPath);
02444 }
02445
02446 info.uSource = url;
02447 info.uDest = m_currentDest;
02448
02449
02450 if ( destinationState == DEST_IS_DIR &&
02451
02452
02453 ( ! ( m_asMethod && state == STATE_STATING ) ) )
02454 {
02455 QString destFileName;
02456 if ( hasCustomURL &&
02457 KProtocolInfo::fileNameUsedForCopying( url ) == KProtocolInfo::FromURL ) {
02458
02459
02460 int numberOfSlashes = displayName.contains( '/' );
02461 QString path = url.path();
02462 int pos = 0;
02463 for ( int n = 0; n < numberOfSlashes + 1; ++n ) {
02464 pos = path.findRev( '/', pos - 1 );
02465 if ( pos == -1 ) {
02466 kdWarning(7007) << "kioslave bug: not enough slashes in UDS_URL " << path << " - looking for " << numberOfSlashes << " slashes" << endl;
02467 break;
02468 }
02469 }
02470 if ( pos >= 0 ) {
02471 destFileName = path.mid( pos + 1 );
02472 }
02473
02474 } else {
02475 destFileName = displayName;
02476 }
02477
02478
02479
02480
02481 if ( destFileName.isEmpty() )
02482 destFileName = KIO::encodeFileName( info.uSource.prettyURL() );
02483
02484
02485 info.uDest.addPath( destFileName );
02486 }
02487
02488
02489 if ( info.linkDest.isEmpty() && isDir && m_mode != Link )
02490 {
02491 dirs.append( info );
02492 if (m_mode == Move)
02493 dirsToRemove.append( info.uSource );
02494 }
02495 else {
02496 files.append( info );
02497 }
02498 }
02499 }
02500 }
02501
02502 void CopyJob::skipSrc()
02503 {
02504 m_dest = d->m_globalDest;
02505 destinationState = d->m_globalDestinationState;
02506 ++m_currentStatSrc;
02507 skip( m_currentSrcURL );
02508 statCurrentSrc();
02509 }
02510
02511 void CopyJob::statNextSrc()
02512 {
02513 m_dest = d->m_globalDest;
02514 destinationState = d->m_globalDestinationState;
02515 ++m_currentStatSrc;
02516 statCurrentSrc();
02517 }
02518
02519 void CopyJob::statCurrentSrc()
02520 {
02521 if ( m_currentStatSrc != m_srcList.end() )
02522 {
02523 m_currentSrcURL = (*m_currentStatSrc);
02524 d->m_bURLDirty = true;
02525 if ( m_mode == Link )
02526 {
02527
02528 m_currentDest = m_dest;
02529 struct CopyInfo info;
02530 info.permissions = -1;
02531 info.mtime = (time_t) -1;
02532 info.ctime = (time_t) -1;
02533 info.size = (KIO::filesize_t)-1;
02534 info.uSource = m_currentSrcURL;
02535 info.uDest = m_currentDest;
02536
02537 if ( destinationState == DEST_IS_DIR && !m_asMethod )
02538 {
02539 if (
02540 (m_currentSrcURL.protocol() == info.uDest.protocol()) &&
02541 (m_currentSrcURL.host() == info.uDest.host()) &&
02542 (m_currentSrcURL.port() == info.uDest.port()) &&
02543 (m_currentSrcURL.user() == info.uDest.user()) &&
02544 (m_currentSrcURL.pass() == info.uDest.pass()) )
02545 {
02546
02547 info.uDest.addPath( m_currentSrcURL.fileName() );
02548 }
02549 else
02550 {
02551
02552
02553
02554 info.uDest.addPath( KIO::encodeFileName( m_currentSrcURL.prettyURL() )+".desktop" );
02555 }
02556 }
02557 files.append( info );
02558 statNextSrc();
02559 return;
02560 }
02561 else if ( m_mode == Move && (
02562
02563 KProtocolInfo::fileNameUsedForCopying( m_currentSrcURL ) == KProtocolInfo::FromURL ||
02564 destinationState != DEST_IS_DIR || m_asMethod )
02565 )
02566 {
02567
02568
02569 if ( (m_currentSrcURL.protocol() == m_dest.protocol()) &&
02570 (m_currentSrcURL.host() == m_dest.host()) &&
02571 (m_currentSrcURL.port() == m_dest.port()) &&
02572 (m_currentSrcURL.user() == m_dest.user()) &&
02573 (m_currentSrcURL.pass() == m_dest.pass()) )
02574 {
02575 startRenameJob( m_currentSrcURL );
02576 return;
02577 }
02578 else if ( m_currentSrcURL.isLocalFile() && KProtocolInfo::canRenameFromFile( m_dest ) )
02579 {
02580 startRenameJob( m_dest );
02581 return;
02582 }
02583 else if ( m_dest.isLocalFile() && KProtocolInfo::canRenameToFile( m_currentSrcURL ) )
02584 {
02585 startRenameJob( m_currentSrcURL );
02586 return;
02587 }
02588 }
02589
02590
02591 if (m_mode == Move && !KProtocolInfo::supportsDeleting(m_currentSrcURL)) {
02592 QGuardedPtr<CopyJob> that = this;
02593 KMessageBox::information( 0, buildErrorString(ERR_CANNOT_DELETE, m_currentSrcURL.prettyURL()));
02594 if (that)
02595 statNextSrc();
02596 return;
02597 }
02598
02599
02600 Job * job = KIO::stat( m_currentSrcURL, true, 2, false );
02601
02602 state = STATE_STATING;
02603 addSubjob(job);
02604 m_currentDestURL=m_dest;
02605 m_bOnlyRenames = false;
02606 d->m_bURLDirty = true;
02607 }
02608 else
02609 {
02610
02611
02612 state = STATE_STATING;
02613 d->m_bURLDirty = true;
02614 slotReport();
02615 if (!dirs.isEmpty())
02616 emit aboutToCreate( this, dirs );
02617 if (!files.isEmpty())
02618 emit aboutToCreate( this, files );
02619
02620 m_bSingleFileCopy = ( files.count() == 1 && dirs.isEmpty() );
02621
02622 state = STATE_CREATING_DIRS;
02623 createNextDir();
02624 }
02625 }
02626
02627 void CopyJob::startRenameJob( const KURL& slave_url )
02628 {
02629 KURL dest = m_dest;
02630
02631 if ( destinationState == DEST_IS_DIR && !m_asMethod )
02632 dest.addPath( m_currentSrcURL.fileName() );
02633 kdDebug(7007) << "This seems to be a suitable case for trying to rename before stat+[list+]copy+del" << endl;
02634 state = STATE_RENAMING;
02635
02636 struct CopyInfo info;
02637 info.permissions = -1;
02638 info.mtime = (time_t) -1;
02639 info.ctime = (time_t) -1;
02640 info.size = (KIO::filesize_t)-1;
02641 info.uSource = m_currentSrcURL;
02642 info.uDest = dest;
02643 QValueList<CopyInfo> files;
02644 files.append(info);
02645 emit aboutToCreate( this, files );
02646
02647 KIO_ARGS << m_currentSrcURL << dest << (Q_INT8) false ;
02648 SimpleJob * newJob = new SimpleJob(slave_url, CMD_RENAME, packedArgs, false);
02649 Scheduler::scheduleJob(newJob);
02650 addSubjob( newJob );
02651 if ( m_currentSrcURL.directory() != dest.directory() )
02652 m_bOnlyRenames = false;
02653 }
02654
02655 void CopyJob::startListing( const KURL & src )
02656 {
02657 state = STATE_LISTING;
02658 d->m_bURLDirty = true;
02659 ListJob * newjob = listRecursive( src, false );
02660 newjob->setUnrestricted(true);
02661 connect(newjob, SIGNAL(entries( KIO::Job *,
02662 const KIO::UDSEntryList& )),
02663 SLOT( slotEntries( KIO::Job*,
02664 const KIO::UDSEntryList& )));
02665 addSubjob( newjob );
02666 }
02667
02668 void CopyJob::skip( const KURL & sourceUrl )
02669 {
02670
02671
02672
02673 KURL::List::Iterator sit = m_srcList.find( sourceUrl );
02674 if ( sit != m_srcList.end() )
02675 {
02676
02677 m_srcList.remove( sit );
02678 }
02679 dirsToRemove.remove( sourceUrl );
02680 }
02681
02682 bool CopyJob::shouldOverwrite( const QString& path ) const
02683 {
02684 if ( m_bOverwriteAll )
02685 return true;
02686 QStringList::ConstIterator sit = m_overwriteList.begin();
02687 for( ; sit != m_overwriteList.end(); ++sit )
02688 if ( path.startsWith( *sit ) )
02689 return true;
02690 return false;
02691 }
02692
02693 bool CopyJob::shouldSkip( const QString& path ) const
02694 {
02695 QStringList::ConstIterator sit = m_skipList.begin();
02696 for( ; sit != m_skipList.end(); ++sit )
02697 if ( path.startsWith( *sit ) )
02698 return true;
02699 return false;
02700 }
02701
02702 void CopyJob::slotResultCreatingDirs( Job * job )
02703 {
02704
02705 QValueList<CopyInfo>::Iterator it = dirs.begin();
02706
02707 if ( job->error() )
02708 {
02709 m_conflictError = job->error();
02710 if ( (m_conflictError == ERR_DIR_ALREADY_EXIST)
02711 || (m_conflictError == ERR_FILE_ALREADY_EXIST) )
02712 {
02713 KURL oldURL = ((SimpleJob*)job)->url();
02714
02715 if ( m_bAutoSkip ) {
02716
02717 m_skipList.append( oldURL.path( 1 ) );
02718 skip( oldURL );
02719 dirs.remove( it );
02720 } else {
02721
02722 const QString destFile = (*it).uDest.path();
02723 if ( shouldOverwrite( destFile ) ) {
02724 emit copyingDone( this, ( *it ).uSource, ( *it ).uDest, true , false );
02725 dirs.remove( it );
02726 } else {
02727 if ( !d->m_interactive ) {
02728 Job::slotResult( job );
02729 return;
02730 }
02731
02732 assert( ((SimpleJob*)job)->url().url() == (*it).uDest.url() );
02733 subjobs.remove( job );
02734 assert ( subjobs.isEmpty() );
02735
02736
02737 KURL existingDest( (*it).uDest );
02738 SimpleJob * newJob = KIO::stat( existingDest, false, 2, false );
02739 Scheduler::scheduleJob(newJob);
02740 kdDebug(7007) << "KIO::stat for resolving conflict on " << existingDest << endl;
02741 state = STATE_CONFLICT_CREATING_DIRS;
02742 addSubjob(newJob);
02743 return;
02744 }
02745 }
02746 }
02747 else
02748 {
02749
02750 Job::slotResult( job );
02751 return;
02752 }
02753 }
02754 else
02755 {
02756
02757 emit copyingDone( this, (*it).uSource, (*it).uDest, true, false );
02758 dirs.remove( it );
02759 }
02760
02761 m_processedDirs++;
02762
02763 subjobs.remove( job );
02764 assert ( subjobs.isEmpty() );
02765 createNextDir();
02766 }
02767
02768 void CopyJob::slotResultConflictCreatingDirs( KIO::Job * job )
02769 {
02770
02771
02772
02773 QValueList<CopyInfo>::Iterator it = dirs.begin();
02774
02775 time_t destmtime = (time_t)-1;
02776 time_t destctime = (time_t)-1;
02777 KIO::filesize_t destsize = 0;
02778 QString linkDest;
02779
02780 UDSEntry entry = ((KIO::StatJob*)job)->statResult();
02781 KIO::UDSEntry::ConstIterator it2 = entry.begin();
02782 for( ; it2 != entry.end(); it2++ ) {
02783 switch ((*it2).m_uds) {
02784 case UDS_MODIFICATION_TIME:
02785 destmtime = (time_t)((*it2).m_long);
02786 break;
02787 case UDS_CREATION_TIME:
02788 destctime = (time_t)((*it2).m_long);
02789 break;
02790 case UDS_SIZE:
02791 destsize = (*it2).m_long;
02792 break;
02793 case UDS_LINK_DEST:
02794 linkDest = (*it2).m_str;
02795 break;
02796 }
02797 }
02798 subjobs.remove( job );
02799 assert ( subjobs.isEmpty() );
02800
02801
02802 RenameDlg_Mode mode = (RenameDlg_Mode)( M_MULTI | M_SKIP );
02803
02804 if ( m_conflictError == ERR_DIR_ALREADY_EXIST )
02805 {
02806 if( (*it).uSource == (*it).uDest ||
02807 ((*it).uSource.protocol() == (*it).uDest.protocol() &&
02808 (*it).uSource.path(-1) == linkDest) )
02809 mode = (RenameDlg_Mode)( mode | M_OVERWRITE_ITSELF);
02810 else
02811 mode = (RenameDlg_Mode)( mode | M_OVERWRITE );
02812 }
02813
02814 QString existingDest = (*it).uDest.path();
02815 QString newPath;
02816 if (m_reportTimer)
02817 m_reportTimer->stop();
02818 RenameDlg_Result r = Observer::self()->open_RenameDlg( this, i18n("Folder Already Exists"),
02819 (*it).uSource.url(),
02820 (*it).uDest.url(),
02821 mode, newPath,
02822 (*it).size, destsize,
02823 (*it).ctime, destctime,
02824 (*it).mtime, destmtime );
02825 if (m_reportTimer)
02826 m_reportTimer->start(REPORT_TIMEOUT,false);
02827 switch ( r ) {
02828 case R_CANCEL:
02829 m_error = ERR_USER_CANCELED;
02830 emitResult();
02831 return;
02832 case R_RENAME:
02833 {
02834 QString oldPath = (*it).uDest.path( 1 );
02835 KURL newUrl( (*it).uDest );
02836 newUrl.setPath( newPath );
02837 emit renamed( this, (*it).uDest, newUrl );
02838
02839
02840 (*it).uDest.setPath( newUrl.path( -1 ) );
02841 newPath = newUrl.path( 1 );
02842 QValueList<CopyInfo>::Iterator renamedirit = it;
02843 ++renamedirit;
02844
02845 for( ; renamedirit != dirs.end() ; ++renamedirit )
02846 {
02847 QString path = (*renamedirit).uDest.path();
02848 if ( path.left(oldPath.length()) == oldPath ) {
02849 QString n = path;
02850 n.replace( 0, oldPath.length(), newPath );
02851 kdDebug(7007) << "dirs list: " << (*renamedirit).uSource.path()
02852 << " was going to be " << path
02853 << ", changed into " << n << endl;
02854 (*renamedirit).uDest.setPath( n );
02855 }
02856 }
02857
02858 QValueList<CopyInfo>::Iterator renamefileit = files.begin();
02859 for( ; renamefileit != files.end() ; ++renamefileit )
02860 {
02861 QString path = (*renamefileit).uDest.path();
02862 if ( path.left(oldPath.length()) == oldPath ) {
02863 QString n = path;
02864 n.replace( 0, oldPath.length(), newPath );
02865 kdDebug(7007) << "files list: " << (*renamefileit).uSource.path()
02866 << " was going to be " << path
02867 << ", changed into " << n << endl;
02868 (*renamefileit).uDest.setPath( n );
02869 }
02870 }
02871 if (!dirs.isEmpty())
02872 emit aboutToCreate( this, dirs );
02873 if (!files.isEmpty())
02874 emit aboutToCreate( this, files );
02875 }
02876 break;
02877 case R_AUTO_SKIP:
02878 m_bAutoSkip = true;
02879
02880 case R_SKIP:
02881 m_skipList.append( existingDest );
02882 skip( (*it).uSource );
02883
02884 dirs.remove( it );
02885 m_processedDirs++;
02886 break;
02887 case R_OVERWRITE:
02888 m_overwriteList.append( existingDest );
02889 emit copyingDone( this, ( *it ).uSource, ( *it ).uDest, true , false );
02890
02891 dirs.remove( it );
02892 m_processedDirs++;
02893 break;
02894 case R_OVERWRITE_ALL:
02895 m_bOverwriteAll = true;
02896 emit copyingDone( this, ( *it ).uSource, ( *it ).uDest, true , false );
02897
02898 dirs.remove( it );
02899 m_processedDirs++;
02900 break;
02901 default:
02902 assert( 0 );
02903 }
02904 state = STATE_CREATING_DIRS;
02905
02906 createNextDir();
02907 }
02908
02909 void CopyJob::createNextDir()
02910 {
02911 KURL udir;
02912 if ( !dirs.isEmpty() )
02913 {
02914
02915 QValueList<CopyInfo>::Iterator it = dirs.begin();
02916
02917 while( it != dirs.end() && udir.isEmpty() )
02918 {
02919 const QString dir = (*it).uDest.path();
02920 if ( shouldSkip( dir ) ) {
02921 dirs.remove( it );
02922 it = dirs.begin();
02923 } else
02924 udir = (*it).uDest;
02925 }
02926 }
02927 if ( !udir.isEmpty() )
02928 {
02929
02930
02931 KIO::SimpleJob *newjob = KIO::mkdir( udir, -1 );
02932 Scheduler::scheduleJob(newjob);
02933
02934 m_currentDestURL = udir;
02935 d->m_bURLDirty = true;
02936
02937 addSubjob(newjob);
02938 return;
02939 }
02940 else
02941 {
02942 state = STATE_COPYING_FILES;
02943 m_processedFiles++;
02944 copyNextFile();
02945 }
02946 }
02947
02948 void CopyJob::slotResultCopyingFiles( Job * job )
02949 {
02950
02951 QValueList<CopyInfo>::Iterator it = files.begin();
02952 if ( job->error() )
02953 {
02954
02955 if ( m_bAutoSkip )
02956 {
02957 skip( (*it).uSource );
02958 m_fileProcessedSize = (*it).size;
02959 files.remove( it );
02960 }
02961 else
02962 {
02963 if ( !d->m_interactive ) {
02964 Job::slotResult( job );
02965 return;
02966 }
02967
02968 m_conflictError = job->error();
02969
02970 if ( ( m_conflictError == ERR_FILE_ALREADY_EXIST )
02971 || ( m_conflictError == ERR_DIR_ALREADY_EXIST ) )
02972 {
02973 subjobs.remove( job );
02974 assert ( subjobs.isEmpty() );
02975
02976 KURL existingFile( (*it).uDest );
02977 SimpleJob * newJob = KIO::stat( existingFile, false, 2, false );
02978 Scheduler::scheduleJob(newJob);
02979 kdDebug(7007) << "KIO::stat for resolving conflict on " << existingFile << endl;
02980 state = STATE_CONFLICT_COPYING_FILES;
02981 addSubjob(newJob);
02982 return;
02983 }
02984 else
02985 {
02986 if ( m_bCurrentOperationIsLink && job->inherits( "KIO::DeleteJob" ) )
02987 {
02988
02989
02990 m_fileProcessedSize = (*it).size;
02991 files.remove( it );
02992 } else {
02993
02994 slotResultConflictCopyingFiles( job );
02995 return;
02996 }
02997 }
02998 }
02999 } else
03000 {
03001
03002 if ( m_bCurrentOperationIsLink && m_mode == Move
03003 && !job->inherits( "KIO::DeleteJob" )
03004 )
03005 {
03006 subjobs.remove( job );
03007 assert ( subjobs.isEmpty() );
03008
03009
03010 KIO::Job * newjob = KIO::del( (*it).uSource, false , false );
03011 addSubjob( newjob );
03012 return;
03013 }
03014
03015 if ( m_bCurrentOperationIsLink )
03016 {
03017 QString target = ( m_mode == Link ? (*it).uSource.path() : (*it).linkDest );
03018
03019 emit copyingLinkDone( this, (*it).uSource, target, (*it).uDest );
03020 }
03021 else
03022
03023 emit copyingDone( this, (*it).uSource, (*it).uDest, false, false );
03024
03025 files.remove( it );
03026 }
03027 m_processedFiles++;
03028
03029
03030 m_processedSize += m_fileProcessedSize;
03031 m_fileProcessedSize = 0;
03032
03033
03034
03035 removeSubjob( job, true, false );
03036 assert ( subjobs.isEmpty() );
03037 copyNextFile();
03038 }
03039
03040 void CopyJob::slotResultConflictCopyingFiles( KIO::Job * job )
03041 {
03042
03043
03044 QValueList<CopyInfo>::Iterator it = files.begin();
03045
03046 RenameDlg_Result res;
03047 QString newPath;
03048
03049 if (m_reportTimer)
03050 m_reportTimer->stop();
03051
03052 if ( ( m_conflictError == ERR_FILE_ALREADY_EXIST )
03053 || ( m_conflictError == ERR_DIR_ALREADY_EXIST ) )
03054 {
03055
03056 time_t destmtime = (time_t)-1;
03057 time_t destctime = (time_t)-1;
03058 KIO::filesize_t destsize = 0;
03059 QString linkDest;
03060 UDSEntry entry = ((KIO::StatJob*)job)->statResult();
03061 KIO::UDSEntry::ConstIterator it2 = entry.begin();
03062 for( ; it2 != entry.end(); it2++ ) {
03063 switch ((*it2).m_uds) {
03064 case UDS_MODIFICATION_TIME:
03065 destmtime = (time_t)((*it2).m_long);
03066 break;
03067 case UDS_CREATION_TIME:
03068 destctime = (time_t)((*it2).m_long);
03069 break;
03070 case UDS_SIZE:
03071 destsize = (*it2).m_long;
03072 break;
03073 case UDS_LINK_DEST:
03074 linkDest = (*it2).m_str;
03075 break;
03076 }
03077 }
03078
03079
03080
03081 RenameDlg_Mode mode;
03082
03083 if( m_conflictError == ERR_DIR_ALREADY_EXIST )
03084 mode = (RenameDlg_Mode) 0;
03085 else
03086 {
03087 if ( (*it).uSource == (*it).uDest ||
03088 ((*it).uSource.protocol() == (*it).uDest.protocol() &&
03089 (*it).uSource.path(-1) == linkDest) )
03090 mode = M_OVERWRITE_ITSELF;
03091 else
03092 mode = M_OVERWRITE;
03093 }
03094
03095 if ( m_bSingleFileCopy )
03096 mode = (RenameDlg_Mode) ( mode | M_SINGLE );
03097 else
03098 mode = (RenameDlg_Mode) ( mode | M_MULTI | M_SKIP );
03099
03100 res = Observer::self()->open_RenameDlg( this, m_conflictError == ERR_FILE_ALREADY_EXIST ?
03101 i18n("File Already Exists") : i18n("Already Exists as Folder"),
03102 (*it).uSource.url(),
03103 (*it).uDest.url(),
03104 mode, newPath,
03105 (*it).size, destsize,
03106 (*it).ctime, destctime,
03107 (*it).mtime, destmtime );
03108
03109 }
03110 else
03111 {
03112 if ( job->error() == ERR_USER_CANCELED )
03113 res = R_CANCEL;
03114 else if ( !d->m_interactive ) {
03115 Job::slotResult( job );
03116 return;
03117 }
03118 else
03119 {
03120 SkipDlg_Result skipResult = Observer::self()->open_SkipDlg( this, files.count() > 1,
03121 job->errorString() );
03122
03123
03124 res = ( skipResult == S_SKIP ) ? R_SKIP :
03125 ( skipResult == S_AUTO_SKIP ) ? R_AUTO_SKIP :
03126 R_CANCEL;
03127 }
03128 }
03129
03130 if (m_reportTimer)
03131 m_reportTimer->start(REPORT_TIMEOUT,false);
03132
03133 subjobs.remove( job );
03134 assert ( subjobs.isEmpty() );
03135 switch ( res ) {
03136 case R_CANCEL:
03137 m_error = ERR_USER_CANCELED;
03138 emitResult();
03139 return;
03140 case R_RENAME:
03141 {
03142 KURL newUrl( (*it).uDest );
03143 newUrl.setPath( newPath );
03144 emit renamed( this, (*it).uDest, newUrl );
03145 (*it).uDest = newUrl;
03146
03147 QValueList<CopyInfo> files;
03148 files.append(*it);
03149 emit aboutToCreate( this, files );
03150 }
03151 break;
03152 case R_AUTO_SKIP:
03153 m_bAutoSkip = true;
03154
03155 case R_SKIP:
03156
03157 skip( (*it).uSource );
03158 m_processedSize += (*it).size;
03159 files.remove( it );
03160 m_processedFiles++;
03161 break;
03162 case R_OVERWRITE_ALL:
03163 m_bOverwriteAll = true;
03164 break;
03165 case R_OVERWRITE:
03166
03167 m_overwriteList.append( (*it).uDest.path() );
03168 break;
03169 default:
03170 assert( 0 );
03171 }
03172 state = STATE_COPYING_FILES;
03173
03174 copyNextFile();
03175 }
03176
03177 void CopyJob::copyNextFile()
03178 {
03179 bool bCopyFile = false;
03180
03181
03182 QValueList<CopyInfo>::Iterator it = files.begin();
03183
03184 while (it != files.end() && !bCopyFile)
03185 {
03186 const QString destFile = (*it).uDest.path();
03187 bCopyFile = !shouldSkip( destFile );
03188 if ( !bCopyFile ) {
03189 files.remove( it );
03190 it = files.begin();
03191 }
03192 }
03193
03194 if (bCopyFile)
03195 {
03196
03197 bool bOverwrite;
03198 const QString destFile = (*it).uDest.path();
03199 kdDebug(7007) << "copying " << destFile << endl;
03200 if ( (*it).uDest == (*it).uSource )
03201 bOverwrite = false;
03202 else
03203 bOverwrite = shouldOverwrite( destFile );
03204
03205 m_bCurrentOperationIsLink = false;
03206 KIO::Job * newjob = 0L;
03207 if ( m_mode == Link )
03208 {
03209
03210 if (
03211 ((*it).uSource.protocol() == (*it).uDest.protocol()) &&
03212 ((*it).uSource.host() == (*it).uDest.host()) &&
03213 ((*it).uSource.port() == (*it).uDest.port()) &&
03214 ((*it).uSource.user() == (*it).uDest.user()) &&
03215 ((*it).uSource.pass() == (*it).uDest.pass()) )
03216 {
03217
03218 KIO::SimpleJob *newJob = KIO::symlink( (*it).uSource.path(), (*it).uDest, bOverwrite, false );
03219 newjob = newJob;
03220 Scheduler::scheduleJob(newJob);
03221
03222
03223 m_bCurrentOperationIsLink = true;
03224 m_currentSrcURL=(*it).uSource;
03225 m_currentDestURL=(*it).uDest;
03226 d->m_bURLDirty = true;
03227
03228 } else {
03229
03230 if ( (*it).uDest.isLocalFile() )
03231 {
03232 bool devicesOk=false;
03233
03234
03235 if ((*it).uSource.protocol()==QString::fromLatin1("devices"))
03236 {
03237 QByteArray data;
03238 QByteArray param;
03239 QCString retType;
03240 QDataStream streamout(param,IO_WriteOnly);
03241 streamout<<(*it).uSource;
03242 streamout<<(*it).uDest;
03243 if ( kapp->dcopClient()->call( "kded",
03244 "mountwatcher", "createLink(KURL, KURL)", param,retType,data,false ) )
03245 {
03246 QDataStream streamin(data,IO_ReadOnly);
03247 streamin>>devicesOk;
03248 }
03249 if (devicesOk)
03250 {
03251 files.remove( it );
03252 m_processedFiles++;
03253
03254 copyNextFile();
03255 return;
03256 }
03257 }
03258
03259 if (!devicesOk)
03260 {
03261 QString path = (*it).uDest.path();
03262
03263 QFile f( path );
03264 if ( f.open( IO_ReadWrite ) )
03265 {
03266 f.close();
03267 KSimpleConfig config( path );
03268 config.setDesktopGroup();
03269 KURL url = (*it).uSource;
03270 url.setPass( "" );
03271 config.writePathEntry( QString::fromLatin1("URL"), url.url() );
03272 config.writeEntry( QString::fromLatin1("Name"), url.url() );
03273 config.writeEntry( QString::fromLatin1("Type"), QString::fromLatin1("Link") );
03274 QString protocol = (*it).uSource.protocol();
03275 if ( protocol == QString::fromLatin1("ftp") )
03276 config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("ftp") );
03277 else if ( protocol == QString::fromLatin1("http") )
03278 config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("www") );
03279 else if ( protocol == QString::fromLatin1("info") )
03280 config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("info") );
03281 else if ( protocol == QString::fromLatin1("mailto") )
03282 config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("kmail") );
03283 else
03284 config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("unknown") );
03285 config.sync();
03286 files.remove( it );
03287 m_processedFiles++;
03288
03289 copyNextFile();
03290 return;
03291 }
03292 else
03293 {
03294 kdDebug(7007) << "CopyJob::copyNextFile ERR_CANNOT_OPEN_FOR_WRITING" << endl;
03295 m_error = ERR_CANNOT_OPEN_FOR_WRITING;
03296 m_errorText = (*it).uDest.path();
03297 emitResult();
03298 return;
03299 }
03300 }
03301 } else {
03302
03303 m_error = ERR_CANNOT_SYMLINK;
03304 m_errorText = (*it).uDest.prettyURL();
03305 emitResult();
03306 return;
03307 }
03308 }
03309 }
03310 else if ( !(*it).linkDest.isEmpty() &&
03311 ((*it).uSource.protocol() == (*it).uDest.protocol()) &&
03312 ((*it).uSource.host() == (*it).uDest.host()) &&
03313 ((*it).uSource.port() == (*it).uDest.port()) &&
03314 ((*it).uSource.user() == (*it).uDest.user()) &&
03315 ((*it).uSource.pass() == (*it).uDest.pass()))
03316
03317 {
03318 KIO::SimpleJob *newJob = KIO::symlink( (*it).linkDest, (*it).uDest, bOverwrite, false );
03319 Scheduler::scheduleJob(newJob);
03320 newjob = newJob;
03321
03322
03323 m_currentSrcURL=(*it).linkDest;
03324 m_currentDestURL=(*it).uDest;
03325 d->m_bURLDirty = true;
03326
03327 m_bCurrentOperationIsLink = true;
03328
03329 } else if (m_mode == Move)
03330 {
03331 KIO::FileCopyJob * moveJob = KIO::file_move( (*it).uSource, (*it).uDest, (*it).permissions, bOverwrite, false, false );
03332 moveJob->setSourceSize64( (*it).size );
03333 newjob = moveJob;
03334
03335
03336 m_currentSrcURL=(*it).uSource;
03337 m_currentDestURL=(*it).uDest;
03338 d->m_bURLDirty = true;
03339
03340 }
03341 else
03342 {
03343
03344
03345 bool remoteSource = !KProtocolInfo::supportsListing((*it).uSource);
03346 int permissions = (*it).permissions;
03347 if ( d->m_defaultPermissions || ( remoteSource && (*it).uDest.isLocalFile() ) )
03348 permissions = -1;
03349 KIO::FileCopyJob * copyJob = KIO::file_copy( (*it).uSource, (*it).uDest, permissions, bOverwrite, false, false );
03350 copyJob->setParentJob( this );
03351 copyJob->setSourceSize64( (*it).size );
03352 newjob = copyJob;
03353
03354 m_currentSrcURL=(*it).uSource;
03355 m_currentDestURL=(*it).uDest;
03356 d->m_bURLDirty = true;
03357 }
03358 addSubjob(newjob);
03359 connect( newjob, SIGNAL( processedSize( KIO::Job*, KIO::filesize_t ) ),
03360 this, SLOT( slotProcessedSize( KIO::Job*, KIO::filesize_t ) ) );
03361 connect( newjob, SIGNAL( totalSize( KIO::Job*, KIO::filesize_t ) ),
03362 this, SLOT( slotTotalSize( KIO::Job*, KIO::filesize_t ) ) );
03363 }
03364 else
03365 {
03366
03367
03368 deleteNextDir();
03369 }
03370 }
03371
03372 void CopyJob::deleteNextDir()
03373 {
03374 if ( m_mode == Move && !dirsToRemove.isEmpty() )
03375 {
03376 state = STATE_DELETING_DIRS;
03377 d->m_bURLDirty = true;
03378
03379 KURL::List::Iterator it = dirsToRemove.fromLast();
03380 SimpleJob *job = KIO::rmdir( *it );
03381 Scheduler::scheduleJob(job);
03382 dirsToRemove.remove(it);
03383 addSubjob( job );
03384 }
03385 else
03386 {
03387
03388 if ( !m_bOnlyRenames )
03389 {
03390 KDirNotify_stub allDirNotify("*", "KDirNotify*");
03391 KURL url( d->m_globalDest );
03392 if ( d->m_globalDestinationState != DEST_IS_DIR || m_asMethod )
03393 url.setPath( url.directory() );
03394
03395 allDirNotify.FilesAdded( url );
03396
03397 if ( m_mode == Move && !m_srcList.isEmpty() ) {
03398
03399 allDirNotify.FilesRemoved( m_srcList );
03400 }
03401 }
03402 if (m_reportTimer!=0)
03403 m_reportTimer->stop();
03404 emitResult();
03405 }
03406 }
03407
03408 void CopyJob::slotProcessedSize( KIO::Job*, KIO::filesize_t data_size )
03409 {
03410
03411 m_fileProcessedSize = data_size;
03412 setProcessedSize(m_processedSize + m_fileProcessedSize);
03413
03414 if ( m_processedSize + m_fileProcessedSize > m_totalSize )
03415 {
03416 m_totalSize = m_processedSize + m_fileProcessedSize;
03417
03418 emit totalSize( this, m_totalSize );
03419 }
03420
03421 emit processedSize( this, m_processedSize + m_fileProcessedSize );
03422 emitPercent( m_processedSize + m_fileProcessedSize, m_totalSize );
03423 }
03424
03425 void CopyJob::slotTotalSize( KIO::Job*, KIO::filesize_t size )
03426 {
03427
03428
03429
03430
03431 if ( m_bSingleFileCopy && size > m_totalSize)
03432 {
03433
03434 m_totalSize = size;
03435 emit totalSize( this, size );
03436 }
03437 }
03438
03439 void CopyJob::slotResultDeletingDirs( Job * job )
03440 {
03441 if (job->error())
03442 {
03443
03444
03445
03446 }
03447 subjobs.remove( job );
03448 assert ( subjobs.isEmpty() );
03449 deleteNextDir();
03450 }
03451
03452 void CopyJob::slotResultRenaming( Job* job )
03453 {
03454 int err = job->error();
03455 const QString errText = job->errorText();
03456 removeSubjob( job, true, false );
03457 assert ( subjobs.isEmpty() );
03458
03459 KURL dest = m_dest;
03460 if ( destinationState == DEST_IS_DIR && !m_asMethod )
03461 dest.addPath( m_currentSrcURL.fileName() );
03462 if ( err )
03463 {
03464
03465
03466
03467 if ( m_currentSrcURL.isLocalFile() && m_currentSrcURL.url(-1) != dest.url(-1) &&
03468 m_currentSrcURL.url(-1).lower() == dest.url(-1).lower() &&
03469 ( err == ERR_FILE_ALREADY_EXIST || err == ERR_DIR_ALREADY_EXIST ) )
03470 {
03471 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;
03472 QCString _src( QFile::encodeName(m_currentSrcURL.path()) );
03473 QCString _dest( QFile::encodeName(dest.path()) );
03474 KTempFile tmpFile( m_currentSrcURL.directory(false) );
03475 QCString _tmp( QFile::encodeName(tmpFile.name()) );
03476 kdDebug(7007) << "CopyJob::slotResult KTempFile status:" << tmpFile.status() << " using " << _tmp << " as intermediary" << endl;
03477 tmpFile.unlink();
03478 if ( ::rename( _src, _tmp ) == 0 )
03479 {
03480 if ( !QFile::exists( _dest ) && ::rename( _tmp, _dest ) == 0 )
03481 {
03482 kdDebug(7007) << "Success." << endl;
03483 err = 0;
03484 }
03485 else
03486 {
03487
03488 if ( ::rename( _tmp, _src ) != 0 ) {
03489 kdError(7007) << "Couldn't rename " << tmpFile.name() << " back to " << _src << " !" << endl;
03490
03491 Job::slotResult( job );
03492 return;
03493 }
03494 }
03495 }
03496 }
03497 }
03498 if ( err )
03499 {
03500
03501
03502
03503
03504
03505
03506
03507 Q_ASSERT( m_currentSrcURL == *m_currentStatSrc );
03508
03509
03510 if ( ( err == ERR_DIR_ALREADY_EXIST || err == ERR_FILE_ALREADY_EXIST )
03511 && d->m_interactive )
03512 {
03513 if (m_reportTimer)
03514 m_reportTimer->stop();
03515
03516
03517 if ( m_bAutoSkip ) {
03518
03519 skipSrc();
03520 return;
03521 } else if ( m_bOverwriteAll ) {
03522 ;
03523 } else {
03524 QString newPath;
03525
03526 RenameDlg_Mode mode = (RenameDlg_Mode)
03527 ( ( m_currentSrcURL == dest ) ? M_OVERWRITE_ITSELF : M_OVERWRITE );
03528
03529 if ( m_srcList.count() > 1 )
03530 mode = (RenameDlg_Mode) ( mode | M_MULTI | M_SKIP );
03531 else
03532 mode = (RenameDlg_Mode) ( mode | M_SINGLE );
03533
03534
03535
03536
03537 KIO::filesize_t sizeSrc = (KIO::filesize_t) -1;
03538 KIO::filesize_t sizeDest = (KIO::filesize_t) -1;
03539 time_t ctimeSrc = (time_t) -1;
03540 time_t ctimeDest = (time_t) -1;
03541 time_t mtimeSrc = (time_t) -1;
03542 time_t mtimeDest = (time_t) -1;
03543
03544 KDE_struct_stat stat_buf;
03545 if ( m_currentSrcURL.isLocalFile() &&
03546 KDE_stat(QFile::encodeName(m_currentSrcURL.path()), &stat_buf) == 0 ) {
03547 sizeSrc = stat_buf.st_size;
03548 ctimeSrc = stat_buf.st_ctime;
03549 mtimeSrc = stat_buf.st_mtime;
03550 }
03551 if ( dest.isLocalFile() &&
03552 KDE_stat(QFile::encodeName(dest.path()), &stat_buf) == 0 ) {
03553 sizeDest = stat_buf.st_size;
03554 ctimeDest = stat_buf.st_ctime;
03555 mtimeDest = stat_buf.st_mtime;
03556 }
03557
03558 RenameDlg_Result r = Observer::self()->open_RenameDlg(
03559 this,
03560 err == ERR_FILE_ALREADY_EXIST ? i18n("File Already Exists") : i18n("Already Exists as Folder"),
03561 m_currentSrcURL.url(),
03562 dest.url(),
03563 mode, newPath,
03564 sizeSrc, sizeDest,
03565 ctimeSrc, ctimeDest,
03566 mtimeSrc, mtimeDest );
03567 if (m_reportTimer)
03568 m_reportTimer->start(REPORT_TIMEOUT,false);
03569
03570 switch ( r )
03571 {
03572 case R_CANCEL:
03573 {
03574 m_error = ERR_USER_CANCELED;
03575 emitResult();
03576 return;
03577 }
03578 case R_RENAME:
03579 {
03580
03581
03582 m_dest.setPath( newPath );
03583 KIO::Job* job = KIO::stat( m_dest, false, 2, false );
03584 state = STATE_STATING;
03585 destinationState = DEST_NOT_STATED;
03586 addSubjob(job);
03587 return;
03588 }
03589 case R_AUTO_SKIP:
03590 m_bAutoSkip = true;
03591
03592 case R_SKIP:
03593
03594 skipSrc();
03595 return;
03596 case R_OVERWRITE_ALL:
03597 m_bOverwriteAll = true;
03598 break;
03599 case R_OVERWRITE:
03600
03601
03602
03603
03604
03605 kdDebug(7007) << "adding to overwrite list: " << dest.path() << endl;
03606 m_overwriteList.append( dest.path() );
03607 break;
03608 default:
03609
03610 break;
03611 }
03612 }
03613 } else if ( err != KIO::ERR_UNSUPPORTED_ACTION ) {
03614 kdDebug(7007) << "Couldn't rename " << m_currentSrcURL << " to " << dest << ", aborting" << endl;
03615 m_error = err;
03616 m_errorText = errText;
03617 emitResult();
03618 return;
03619 }
03620 kdDebug(7007) << "Couldn't rename " << m_currentSrcURL << " to " << dest << ", reverting to normal way, starting with stat" << endl;
03621
03622 KIO::Job* job = KIO::stat( m_currentSrcURL, true, 2, false );
03623 state = STATE_STATING;
03624 addSubjob(job);
03625 m_bOnlyRenames = false;
03626 }
03627 else
03628 {
03629
03630 emit copyingDone( this, *m_currentStatSrc, dest, true, true );
03631 statNextSrc();
03632 }
03633 }
03634
03635 void CopyJob::slotResult( Job *job )
03636 {
03637
03638
03639
03640
03641
03642
03643 switch ( state ) {
03644 case STATE_STATING:
03645 slotResultStating( job );
03646 break;
03647 case STATE_RENAMING:
03648 {
03649 slotResultRenaming( job );
03650 break;
03651 }
03652 case STATE_LISTING:
03653
03654
03655 if (job->error())
03656 {
03657 Job::slotResult( job );
03658 return;
03659 }
03660
03661 subjobs.remove( job );
03662 assert ( subjobs.isEmpty() );
03663
03664 statNextSrc();
03665 break;
03666 case STATE_CREATING_DIRS:
03667 slotResultCreatingDirs( job );
03668 break;
03669 case STATE_CONFLICT_CREATING_DIRS:
03670 slotResultConflictCreatingDirs( job );
03671 break;
03672 case STATE_COPYING_FILES:
03673 slotResultCopyingFiles( job );
03674 break;
03675 case STATE_CONFLICT_COPYING_FILES:
03676 slotResultConflictCopyingFiles( job );
03677 break;
03678 case STATE_DELETING_DIRS:
03679 slotResultDeletingDirs( job );
03680 break;
03681 default:
03682 assert( 0 );
03683 }
03684 }
03685
03686 void KIO::CopyJob::setDefaultPermissions( bool b )
03687 {
03688 d->m_defaultPermissions = b;
03689 }
03690
03691 void KIO::CopyJob::setInteractive( bool b )
03692 {
03693 d->m_interactive = b;
03694 }
03695
03696 CopyJob *KIO::copy(const KURL& src, const KURL& dest, bool showProgressInfo )
03697 {
03698
03699 KURL::List srcList;
03700 srcList.append( src );
03701 return new CopyJob( srcList, dest, CopyJob::Copy, false, showProgressInfo );
03702 }
03703
03704 CopyJob *KIO::copyAs(const KURL& src, const KURL& dest, bool showProgressInfo )
03705 {
03706
03707 KURL::List srcList;
03708 srcList.append( src );
03709 return new CopyJob( srcList, dest, CopyJob::Copy, true, showProgressInfo );
03710 }
03711
03712 CopyJob *KIO::copy( const KURL::List& src, const KURL& dest, bool showProgressInfo )
03713 {
03714 return new CopyJob( src, dest, CopyJob::Copy, false, showProgressInfo );
03715 }
03716
03717 CopyJob *KIO::move(const KURL& src, const KURL& dest, bool showProgressInfo )
03718 {
03719 KURL::List srcList;
03720 srcList.append( src );
03721 return new CopyJob( srcList, dest, CopyJob::Move, false, showProgressInfo );
03722 }
03723
03724 CopyJob *KIO::moveAs(const KURL& src, const KURL& dest, bool showProgressInfo )
03725 {
03726 KURL::List srcList;
03727 srcList.append( src );
03728 return new CopyJob( srcList, dest, CopyJob::Move, true, showProgressInfo );
03729 }
03730
03731 CopyJob *KIO::move( const KURL::List& src, const KURL& dest, bool showProgressInfo )
03732 {
03733 return new CopyJob( src, dest, CopyJob::Move, false, showProgressInfo );
03734 }
03735
03736 CopyJob *KIO::link(const KURL& src, const KURL& destDir, bool showProgressInfo )
03737 {
03738 KURL::List srcList;
03739 srcList.append( src );
03740 return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
03741 }
03742
03743 CopyJob *KIO::link(const KURL::List& srcList, const KURL& destDir, bool showProgressInfo )
03744 {
03745 return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
03746 }
03747
03748 CopyJob *KIO::linkAs(const KURL& src, const KURL& destDir, bool showProgressInfo )
03749 {
03750 KURL::List srcList;
03751 srcList.append( src );
03752 return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
03753 }
03754
03755 CopyJob *KIO::trash(const KURL& src, bool showProgressInfo )
03756 {
03757 KURL::List srcList;
03758 srcList.append( src );
03759 return new CopyJob( srcList, KURL( "trash:/" ), CopyJob::Move, false, showProgressInfo );
03760 }
03761
03762 CopyJob *KIO::trash(const KURL::List& srcList, bool showProgressInfo )
03763 {
03764 return new CopyJob( srcList, KURL( "trash:/" ), CopyJob::Move, false, showProgressInfo );
03765 }
03766
03768
03769 DeleteJob::DeleteJob( const KURL::List& src, bool , bool showProgressInfo )
03770 : Job(showProgressInfo), m_totalSize( 0 ), m_processedSize( 0 ), m_fileProcessedSize( 0 ),
03771 m_processedFiles( 0 ), m_processedDirs( 0 ), m_totalFilesDirs( 0 ),
03772 m_srcList(src), m_currentStat(m_srcList.begin()), m_reportTimer(0)
03773 {
03774 if ( showProgressInfo ) {
03775
03776 connect( this, SIGNAL( totalFiles( KIO::Job*, unsigned long ) ),
03777 Observer::self(), SLOT( slotTotalFiles( KIO::Job*, unsigned long ) ) );
03778
03779 connect( this, SIGNAL( totalDirs( KIO::Job*, unsigned long ) ),
03780 Observer::self(), SLOT( slotTotalDirs( KIO::Job*, unsigned long ) ) );
03781
03782
03783
03784
03785
03786
03787
03788
03789
03790
03791
03792 m_reportTimer=new QTimer(this);
03793 connect(m_reportTimer,SIGNAL(timeout()),this,SLOT(slotReport()));
03794
03795 m_reportTimer->start(REPORT_TIMEOUT,false);
03796 }
03797
03798 QTimer::singleShot(0, this, SLOT(slotStart()));
03799 }
03800
03801 void DeleteJob::slotStart()
03802 {
03803 statNextSrc();
03804 }
03805
03806
03807
03808
03809 void DeleteJob::slotReport()
03810 {
03811 if (m_progressId==0)
03812 return;
03813
03814 Observer * observer = Observer::self();
03815
03816 emit deleting( this, m_currentURL );
03817 observer->slotDeleting(this,m_currentURL);
03818
03819 switch( state ) {
03820 case STATE_STATING:
03821 case STATE_LISTING:
03822 emit totalSize( this, m_totalSize );
03823 emit totalFiles( this, files.count() );
03824 emit totalDirs( this, dirs.count() );
03825 break;
03826 case STATE_DELETING_DIRS:
03827 emit processedDirs( this, m_processedDirs );
03828 observer->slotProcessedDirs(this,m_processedDirs);
03829 emitPercent( m_processedFiles + m_processedDirs, m_totalFilesDirs );
03830 break;
03831 case STATE_DELETING_FILES:
03832 observer->slotProcessedFiles(this,m_processedFiles);
03833 emit processedFiles( this, m_processedFiles );
03834 emitPercent( m_processedFiles, m_totalFilesDirs );
03835 break;
03836 }
03837 }
03838
03839
03840 void DeleteJob::slotEntries(KIO::Job* job, const UDSEntryList& list)
03841 {
03842 UDSEntryListConstIterator it = list.begin();
03843 UDSEntryListConstIterator end = list.end();
03844 for (; it != end; ++it)
03845 {
03846 UDSEntry::ConstIterator it2 = (*it).begin();
03847 bool bDir = false;
03848 bool bLink = false;
03849 QString displayName;
03850 KURL url;
03851 int atomsFound(0);
03852 for( ; it2 != (*it).end(); it2++ )
03853 {
03854 switch ((*it2).m_uds)
03855 {
03856 case UDS_FILE_TYPE:
03857 bDir = S_ISDIR((*it2).m_long);
03858 atomsFound++;
03859 break;
03860 case UDS_NAME:
03861 displayName = (*it2).m_str;
03862 atomsFound++;
03863 break;
03864 case UDS_URL:
03865 url = KURL((*it2).m_str);
03866 atomsFound++;
03867 break;
03868 case UDS_LINK_DEST:
03869 bLink = !(*it2).m_str.isEmpty();
03870 atomsFound++;
03871 break;
03872 case UDS_SIZE:
03873 m_totalSize += (KIO::filesize_t)((*it2).m_long);
03874 atomsFound++;
03875 break;
03876 default:
03877 break;
03878 }
03879 if (atomsFound==5) break;
03880 }
03881 assert(!displayName.isEmpty());
03882 if (displayName != ".." && displayName != ".")
03883 {
03884 if( url.isEmpty() ) {
03885 url = ((SimpleJob *)job)->url();
03886 url.addPath( displayName );
03887 }
03888
03889 if ( bLink )
03890 symlinks.append( url );
03891 else if ( bDir )
03892 dirs.append( url );
03893 else
03894 files.append( url );
03895 }
03896 }
03897 }
03898
03899
03900 void DeleteJob::statNextSrc()
03901 {
03902
03903 if ( m_currentStat != m_srcList.end() )
03904 {
03905 m_currentURL = (*m_currentStat);
03906
03907
03908 if (!KProtocolInfo::supportsDeleting(m_currentURL)) {
03909 QGuardedPtr<DeleteJob> that = this;
03910 ++m_currentStat;
03911 KMessageBox::information( 0, buildErrorString(ERR_CANNOT_DELETE, m_currentURL.prettyURL()));
03912 if (that)
03913 statNextSrc();
03914 return;
03915 }
03916
03917 state = STATE_STATING;
03918 KIO::SimpleJob * job = KIO::stat( m_currentURL, true, 1, false );
03919 Scheduler::scheduleJob(job);
03920
03921 addSubjob(job);
03922
03923
03924 } else
03925 {
03926 m_totalFilesDirs = files.count()+symlinks.count() + dirs.count();
03927 slotReport();
03928
03929
03930
03931
03932 for ( QStringList::Iterator it = m_parentDirs.begin() ; it != m_parentDirs.end() ; ++it )
03933 KDirWatch::self()->stopDirScan( *it );
03934 state = STATE_DELETING_FILES;
03935 deleteNextFile();
03936 }
03937 }
03938
03939 void DeleteJob::deleteNextFile()
03940 {
03941
03942 if ( !files.isEmpty() || !symlinks.isEmpty() )
03943 {
03944 SimpleJob *job;
03945 do {
03946
03947 KURL::List::Iterator it = files.begin();
03948 bool isLink = false;
03949 if ( it == files.end() )
03950 {
03951 it = symlinks.begin();
03952 isLink = true;
03953 }
03954
03955
03956 if ( (*it).isLocalFile() && unlink( QFile::encodeName((*it).path()) ) == 0 ) {
03957 job = 0;
03958 m_processedFiles++;
03959 if ( m_processedFiles % 300 == 0 ) {
03960 m_currentURL = *it;
03961 slotReport();
03962 }
03963 } else
03964 {
03965 job = KIO::file_delete( *it, false );
03966 Scheduler::scheduleJob(job);
03967 m_currentURL=(*it);
03968 }
03969 if ( isLink )
03970 symlinks.remove(it);
03971 else
03972 files.remove(it);
03973 if ( job ) {
03974 addSubjob(job);
03975 return;
03976 }
03977
03978 } while (!job && (!files.isEmpty() || !symlinks.isEmpty()));
03979 }
03980 state = STATE_DELETING_DIRS;
03981 deleteNextDir();
03982 }
03983
03984 void DeleteJob::deleteNextDir()
03985 {
03986 if ( !dirs.isEmpty() )
03987 {
03988 do {
03989
03990 KURL::List::Iterator it = dirs.fromLast();
03991
03992 if ( (*it).isLocalFile() && ::rmdir( QFile::encodeName((*it).path()) ) == 0 ) {
03993
03994 m_processedDirs++;
03995 if ( m_processedDirs % 100 == 0 ) {
03996 m_currentURL = *it;
03997 slotReport();
03998 }
03999 } else {
04000 SimpleJob* job;
04001 if ( KProtocolInfo::canDeleteRecursive( *it ) ) {
04002
04003
04004 job = KIO::file_delete( *it );
04005 } else {
04006 job = KIO::rmdir( *it );
04007 }
04008 Scheduler::scheduleJob(job);
04009 dirs.remove(it);
04010 addSubjob( job );
04011 return;
04012 }
04013 dirs.remove(it);
04014 } while ( !dirs.isEmpty() );
04015 }
04016
04017
04018 for ( QStringList::Iterator it = m_parentDirs.begin() ; it != m_parentDirs.end() ; ++it )
04019 KDirWatch::self()->restartDirScan( *it );
04020
04021
04022 if ( !m_srcList.isEmpty() )
04023 {
04024 KDirNotify_stub allDirNotify("*", "KDirNotify*");
04025
04026 allDirNotify.FilesRemoved( m_srcList );
04027 }
04028 if (m_reportTimer!=0)
04029 m_reportTimer->stop();
04030 emitResult();
04031 }
04032
04033 void DeleteJob::slotProcessedSize( KIO::Job*, KIO::filesize_t data_size )
04034 {
04035
04036
04037
04038
04039 m_fileProcessedSize = data_size;
04040 setProcessedSize(m_processedSize + m_fileProcessedSize);
04041
04042
04043
04044 emit processedSize( this, m_processedSize + m_fileProcessedSize );
04045
04046
04047 unsigned long ipercent = m_percent;
04048
04049 if ( m_totalSize == 0 )
04050 m_percent = 100;
04051 else
04052 m_percent = (unsigned long)(( (float)(m_processedSize + m_fileProcessedSize) / (float)m_totalSize ) * 100.0);
04053
04054 if ( m_percent > ipercent )
04055 {
04056 emit percent( this, m_percent );
04057
04058 }
04059
04060 }
04061
04062 void DeleteJob::slotResult( Job *job )
04063 {
04064 switch ( state )
04065 {
04066 case STATE_STATING:
04067 {
04068
04069 if (job->error() )
04070 {
04071
04072 Job::slotResult( job );
04073 return;
04074 }
04075
04076
04077 UDSEntry entry = ((StatJob*)job)->statResult();
04078 bool bDir = false;
04079 bool bLink = false;
04080 KIO::filesize_t size = (KIO::filesize_t)-1;
04081 UDSEntry::ConstIterator it2 = entry.begin();
04082 int atomsFound(0);
04083 for( ; it2 != entry.end(); it2++ )
04084 {
04085 if ( ((*it2).m_uds) == UDS_FILE_TYPE )
04086 {
04087 bDir = S_ISDIR( (mode_t)(*it2).m_long );
04088 atomsFound++;
04089 }
04090 else if ( ((*it2).m_uds) == UDS_LINK_DEST )
04091 {
04092 bLink = !((*it2).m_str.isEmpty());
04093 atomsFound++;
04094 }
04095 else if ( ((*it2).m_uds) == UDS_SIZE )
04096 {
04097 size = (*it2).m_long;
04098 atomsFound++;
04099 }
04100 if (atomsFound==3) break;
04101 }
04102
04103 KURL url = ((SimpleJob*)job)->url();
04104
04105 subjobs.remove( job );
04106 assert( subjobs.isEmpty() );
04107
04108 if (bDir && !bLink)
04109 {
04110
04111 dirs.append( url );
04112 if ( url.isLocalFile() && !m_parentDirs.contains( url.path(-1) ) )
04113 m_parentDirs.append( url.path(-1) );
04114
04115 if ( !KProtocolInfo::canDeleteRecursive( url ) ) {
04116
04117
04118 state = STATE_LISTING;
04119 ListJob *newjob = listRecursive( url, false );
04120 newjob->setUnrestricted(true);
04121 Scheduler::scheduleJob(newjob);
04122 connect(newjob, SIGNAL(entries( KIO::Job *,
04123 const KIO::UDSEntryList& )),
04124 SLOT( slotEntries( KIO::Job*,
04125 const KIO::UDSEntryList& )));
04126 addSubjob(newjob);
04127 } else {
04128 ++m_currentStat;
04129 statNextSrc();
04130 }
04131 }
04132 else
04133 {
04134 if ( bLink ) {
04135
04136 symlinks.append( url );
04137 } else {
04138
04139 files.append( url );
04140 }
04141 if ( url.isLocalFile() && !m_parentDirs.contains( url.directory(false) ) )
04142 m_parentDirs.append( url.directory(false) );
04143 ++m_currentStat;
04144 statNextSrc();
04145 }
04146 }
04147 break;
04148 case STATE_LISTING:
04149 if ( job->error() )
04150 {
04151
04152 }
04153 subjobs.remove( job );
04154 assert( subjobs.isEmpty() );
04155 ++m_currentStat;
04156 statNextSrc();
04157 break;
04158 case STATE_DELETING_FILES:
04159 if ( job->error() )
04160 {
04161 Job::slotResult( job );
04162 return;
04163 }
04164 subjobs.remove( job );
04165 assert( subjobs.isEmpty() );
04166 m_processedFiles++;
04167
04168 deleteNextFile();
04169 break;
04170 case STATE_DELETING_DIRS:
04171 if ( job->error() )
04172 {
04173 Job::slotResult( job );
04174 return;
04175 }
04176 subjobs.remove( job );
04177 assert( subjobs.isEmpty() );
04178 m_processedDirs++;
04179
04180
04181
04182
04183 deleteNextDir();
04184 break;
04185 default:
04186 assert(0);
04187 }
04188 }
04189
04190 DeleteJob *KIO::del( const KURL& src, bool shred, bool showProgressInfo )
04191 {
04192 KURL::List srcList;
04193 srcList.append( src );
04194 DeleteJob *job = new DeleteJob( srcList, shred, showProgressInfo );
04195 return job;
04196 }
04197
04198 DeleteJob *KIO::del( const KURL::List& src, bool shred, bool showProgressInfo )
04199 {
04200 DeleteJob *job = new DeleteJob( src, shred, showProgressInfo );
04201 return job;
04202 }
04203
04204 MultiGetJob::MultiGetJob(const KURL& url,
04205 bool showProgressInfo)
04206 : TransferJob(url, 0, QByteArray(), QByteArray(), showProgressInfo)
04207 {
04208 m_waitQueue.setAutoDelete(true);
04209 m_activeQueue.setAutoDelete(true);
04210 m_currentEntry = 0;
04211 }
04212
04213 void MultiGetJob::get(long id, const KURL &url, const MetaData &metaData)
04214 {
04215 GetRequest *entry = new GetRequest(id, url, metaData);
04216 entry->metaData["request-id"] = QString("%1").arg(id);
04217 m_waitQueue.append(entry);
04218 }
04219
04220 void MultiGetJob::flushQueue(QPtrList<GetRequest> &queue)
04221 {
04222 GetRequest *entry;
04223
04224
04225 for(entry = m_waitQueue.first(); entry; )
04226 {
04227 if ((m_url.protocol() == entry->url.protocol()) &&
04228 (m_url.host() == entry->url.host()) &&
04229 (m_url.port() == entry->url.port()) &&
04230 (m_url.user() == entry->url.user()))
04231 {
04232 m_waitQueue.take();
04233 queue.append(entry);
04234 entry = m_waitQueue.current();
04235 }
04236 else
04237 {
04238 entry = m_waitQueue.next();
04239 }
04240 }
04241
04242 KIO_ARGS << (Q_INT32) queue.count();
04243 for(entry = queue.first(); entry; entry = queue.next())
04244 {
04245 stream << entry->url << entry->metaData;
04246 }
04247 m_packedArgs = packedArgs;
04248 m_command = CMD_MULTI_GET;
04249 m_outgoingMetaData.clear();
04250 }
04251
04252 void MultiGetJob::start(Slave *slave)
04253 {
04254
04255 GetRequest *entry = m_waitQueue.take(0);
04256 m_activeQueue.append(entry);
04257
04258 m_url = entry->url;
04259
04260 if (!entry->url.protocol().startsWith("http"))
04261 {
04262
04263 KIO_ARGS << entry->url;
04264 m_packedArgs = packedArgs;
04265 m_outgoingMetaData = entry->metaData;
04266 m_command = CMD_GET;
04267 b_multiGetActive = false;
04268 }
04269 else
04270 {
04271 flushQueue(m_activeQueue);
04272 b_multiGetActive = true;
04273 }
04274
04275 TransferJob::start(slave);
04276 }
04277
04278 bool MultiGetJob::findCurrentEntry()
04279 {
04280 if (b_multiGetActive)
04281 {
04282 long id = m_incomingMetaData["request-id"].toLong();
04283 for(GetRequest *entry = m_activeQueue.first(); entry; entry = m_activeQueue.next())
04284 {
04285 if (entry->id == id)
04286 {
04287 m_currentEntry = entry;
04288 return true;
04289 }
04290 }
04291 m_currentEntry = 0;
04292 return false;
04293 }
04294 else
04295 {
04296 m_currentEntry = m_activeQueue.first();
04297 return (m_currentEntry != 0);
04298 }
04299 }
04300
04301 void MultiGetJob::slotRedirection( const KURL &url)
04302 {
04303 if (!findCurrentEntry()) return;
04304 if (!kapp->authorizeURLAction("redirect", m_url, url))
04305 {
04306 kdWarning(7007) << "MultiGetJob: Redirection from " << m_currentEntry->url << " to " << url << " REJECTED!" << endl;
04307 return;
04308 }
04309 m_redirectionURL = url;
04310 if (m_currentEntry->url.hasUser() && !url.hasUser() && (m_currentEntry->url.host().lower() == url.host().lower()))
04311 m_redirectionURL.setUser(m_currentEntry->url.user());
04312 get(m_currentEntry->id, m_redirectionURL, m_currentEntry->metaData);
04313 }
04314
04315
04316 void MultiGetJob::slotFinished()
04317 {
04318 if (!findCurrentEntry()) return;
04319 if (m_redirectionURL.isEmpty())
04320 {
04321
04322 emit result(m_currentEntry->id);
04323 }
04324 m_redirectionURL = KURL();
04325 m_error = 0;
04326 m_incomingMetaData.clear();
04327 m_activeQueue.removeRef(m_currentEntry);
04328 if (m_activeQueue.count() == 0)
04329 {
04330 if (m_waitQueue.count() == 0)
04331 {
04332
04333 TransferJob::slotFinished();
04334 }
04335 else
04336 {
04337
04338
04339
04340 GetRequest *entry = m_waitQueue.at(0);
04341 m_url = entry->url;
04342 slaveDone();
04343 Scheduler::doJob(this);
04344 }
04345 }
04346 }
04347
04348 void MultiGetJob::slotData( const QByteArray &_data)
04349 {
04350 if(!m_currentEntry) return;
04351 if(m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error)
04352 emit data(m_currentEntry->id, _data);
04353 }
04354
04355 void MultiGetJob::slotMimetype( const QString &_mimetype )
04356 {
04357 if (b_multiGetActive)
04358 {
04359 QPtrList<GetRequest> newQueue;
04360 flushQueue(newQueue);
04361 if (!newQueue.isEmpty())
04362 {
04363 while(!newQueue.isEmpty())
04364 m_activeQueue.append(newQueue.take(0));
04365 m_slave->send( m_command, m_packedArgs );
04366 }
04367 }
04368 if (!findCurrentEntry()) return;
04369 emit mimetype(m_currentEntry->id, _mimetype);
04370 }
04371
04372 MultiGetJob *KIO::multi_get(long id, const KURL &url, const MetaData &metaData)
04373 {
04374 MultiGetJob * job = new MultiGetJob( url, false );
04375 job->get(id, url, metaData);
04376 return job;
04377 }
04378
04379
04380 #ifdef CACHE_INFO
04381 CacheInfo::CacheInfo(const KURL &url)
04382 {
04383 m_url = url;
04384 }
04385
04386 QString CacheInfo::cachedFileName()
04387 {
04388 const QChar separator = '_';
04389
04390 QString CEF = m_url.path();
04391
04392 int p = CEF.find('/');
04393
04394 while(p != -1)
04395 {
04396 CEF[p] = separator;
04397 p = CEF.find('/', p);
04398 }
04399
04400 QString host = m_url.host().lower();
04401 CEF = host + CEF + '_';
04402
04403 QString dir = KProtocolManager::cacheDir();
04404 if (dir[dir.length()-1] != '/')
04405 dir += "/";
04406
04407 int l = m_url.host().length();
04408 for(int i = 0; i < l; i++)
04409 {
04410 if (host[i].isLetter() && (host[i] != 'w'))
04411 {
04412 dir += host[i];
04413 break;
04414 }
04415 }
04416 if (dir[dir.length()-1] == '/')
04417 dir += "0";
04418
04419 unsigned long hash = 0x00000000;
04420 QCString u = m_url.url().latin1();
04421 for(int i = u.length(); i--;)
04422 {
04423 hash = (hash * 12211 + u[i]) % 2147483563;
04424 }
04425
04426 QString hashString;
04427 hashString.sprintf("%08lx", hash);
04428
04429 CEF = CEF + hashString;
04430
04431 CEF = dir + "/" + CEF;
04432
04433 return CEF;
04434 }
04435
04436 QFile *CacheInfo::cachedFile()
04437 {
04438 #ifdef Q_WS_WIN
04439 const char *mode = (readWrite ? "rb+" : "rb");
04440 #else
04441 const char *mode = (readWrite ? "r+" : "r");
04442 #endif
04443
04444 FILE *fs = fopen(QFile::encodeName(CEF), mode);
04445 if (!fs)
04446 return 0;
04447
04448 char buffer[401];
04449 bool ok = true;
04450
04451
04452 if (ok && (!fgets(buffer, 400, fs)))
04453 ok = false;
04454 if (ok && (strcmp(buffer, CACHE_REVISION) != 0))
04455 ok = false;
04456
04457 time_t date;
04458 time_t currentDate = time(0);
04459
04460
04461 if (ok && (!fgets(buffer, 400, fs)))
04462 ok = false;
04463 if (ok)
04464 {
04465 int l = strlen(buffer);
04466 if (l>0)
04467 buffer[l-1] = 0;
04468 if (m_.url.url() != buffer)
04469 {
04470 ok = false;
04471 }
04472 }
04473
04474
04475 if (ok && (!fgets(buffer, 400, fs)))
04476 ok = false;
04477 if (ok)
04478 {
04479 date = (time_t) strtoul(buffer, 0, 10);
04480 if (m_maxCacheAge && (difftime(currentDate, date) > m_maxCacheAge))
04481 {
04482 m_bMustRevalidate = true;
04483 m_expireDate = currentDate;
04484 }
04485 }
04486
04487
04488 m_cacheExpireDateOffset = ftell(fs);
04489 if (ok && (!fgets(buffer, 400, fs)))
04490 ok = false;
04491 if (ok)
04492 {
04493 if (m_request.cache == CC_Verify)
04494 {
04495 date = (time_t) strtoul(buffer, 0, 10);
04496
04497 if (!date || difftime(currentDate, date) >= 0)
04498 m_bMustRevalidate = true;
04499 m_expireDate = date;
04500 }
04501 }
04502
04503
04504 if (ok && (!fgets(buffer, 400, fs)))
04505 ok = false;
04506 if (ok)
04507 {
04508 m_etag = QString(buffer).stripWhiteSpace();
04509 }
04510
04511
04512 if (ok && (!fgets(buffer, 400, fs)))
04513 ok = false;
04514 if (ok)
04515 {
04516 m_lastModified = QString(buffer).stripWhiteSpace();
04517 }
04518
04519 fclose(fs);
04520
04521 if (ok)
04522 return fs;
04523
04524 unlink( QFile::encodeName(CEF) );
04525 return 0;
04526
04527 }
04528
04529 void CacheInfo::flush()
04530 {
04531 cachedFile().remove();
04532 }
04533
04534 void CacheInfo::touch()
04535 {
04536
04537 }
04538 void CacheInfo::setExpireDate(int);
04539 void CacheInfo::setExpireTimeout(int);
04540
04541
04542 int CacheInfo::creationDate();
04543 int CacheInfo::expireDate();
04544 int CacheInfo::expireTimeout();
04545 #endif
04546
04547 void Job::virtual_hook( int, void* )
04548 { }
04549
04550 void SimpleJob::virtual_hook( int id, void* data )
04551 { KIO::Job::virtual_hook( id, data ); }
04552
04553 void MkdirJob::virtual_hook( int id, void* data )
04554 { SimpleJob::virtual_hook( id, data ); }
04555
04556 void StatJob::virtual_hook( int id, void* data )
04557 { SimpleJob::virtual_hook( id, data ); }
04558
04559 void TransferJob::virtual_hook( int id, void* data )
04560 { SimpleJob::virtual_hook( id, data ); }
04561
04562 void MultiGetJob::virtual_hook( int id, void* data )
04563 { TransferJob::virtual_hook( id, data ); }
04564
04565 void MimetypeJob::virtual_hook( int id, void* data )
04566 { TransferJob::virtual_hook( id, data ); }
04567
04568 void FileCopyJob::virtual_hook( int id, void* data )
04569 { Job::virtual_hook( id, data ); }
04570
04571 void ListJob::virtual_hook( int id, void* data )
04572 { SimpleJob::virtual_hook( id, data ); }
04573
04574 void CopyJob::virtual_hook( int id, void* data )
04575 { Job::virtual_hook( id, data ); }
04576
04577 void DeleteJob::virtual_hook( int id, void* data )
04578 { Job::virtual_hook( id, data ); }
04579
04580
04581 #include "jobclasses.moc"