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