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 state = STATE_COPYING_FILES;
02956 m_processedFiles++;
02957 copyNextFile();
02958 }
02959 }
02960
02961 void CopyJob::slotResultCopyingFiles( Job * job )
02962 {
02963
02964 QValueList<CopyInfo>::Iterator it = files.begin();
02965 if ( job->error() )
02966 {
02967
02968 if ( m_bAutoSkip )
02969 {
02970 skip( (*it).uSource );
02971 m_fileProcessedSize = (*it).size;
02972 files.remove( it );
02973 }
02974 else
02975 {
02976 if ( !isInteractive() ) {
02977 Job::slotResult( job );
02978 return;
02979 }
02980
02981 m_conflictError = job->error();
02982
02983 if ( ( m_conflictError == ERR_FILE_ALREADY_EXIST )
02984 || ( m_conflictError == ERR_DIR_ALREADY_EXIST ) )
02985 {
02986 subjobs.remove( job );
02987 assert ( subjobs.isEmpty() );
02988
02989 KURL existingFile( (*it).uDest );
02990 SimpleJob * newJob = KIO::stat( existingFile, false, 2, false );
02991 Scheduler::scheduleJob(newJob);
02992 kdDebug(7007) << "KIO::stat for resolving conflict on " << existingFile << endl;
02993 state = STATE_CONFLICT_COPYING_FILES;
02994 addSubjob(newJob);
02995 return;
02996 }
02997 else
02998 {
02999 if ( m_bCurrentOperationIsLink && job->inherits( "KIO::DeleteJob" ) )
03000 {
03001
03002
03003 m_fileProcessedSize = (*it).size;
03004 files.remove( it );
03005 } else {
03006
03007 slotResultConflictCopyingFiles( job );
03008 return;
03009 }
03010 }
03011 }
03012 } else
03013 {
03014
03015 if ( m_bCurrentOperationIsLink && m_mode == Move
03016 && !job->inherits( "KIO::DeleteJob" )
03017 )
03018 {
03019 subjobs.remove( job );
03020 assert ( subjobs.isEmpty() );
03021
03022
03023 KIO::Job * newjob = KIO::del( (*it).uSource, false , false );
03024 addSubjob( newjob );
03025 return;
03026 }
03027
03028 if ( m_bCurrentOperationIsLink )
03029 {
03030 QString target = ( m_mode == Link ? (*it).uSource.path() : (*it).linkDest );
03031
03032 emit copyingLinkDone( this, (*it).uSource, target, (*it).uDest );
03033 }
03034 else
03035
03036 emit copyingDone( this, (*it).uSource, (*it).uDest, false, false );
03037
03038 files.remove( it );
03039 }
03040 m_processedFiles++;
03041
03042
03043 m_processedSize += m_fileProcessedSize;
03044 m_fileProcessedSize = 0;
03045
03046
03047
03048 removeSubjob( job, true, false );
03049 assert ( subjobs.isEmpty() );
03050 copyNextFile();
03051 }
03052
03053 void CopyJob::slotResultConflictCopyingFiles( KIO::Job * job )
03054 {
03055
03056
03057 QValueList<CopyInfo>::Iterator it = files.begin();
03058
03059 RenameDlg_Result res;
03060 QString newPath;
03061
03062 if (m_reportTimer)
03063 m_reportTimer->stop();
03064
03065 if ( ( m_conflictError == ERR_FILE_ALREADY_EXIST )
03066 || ( m_conflictError == ERR_DIR_ALREADY_EXIST ) )
03067 {
03068
03069 time_t destmtime = (time_t)-1;
03070 time_t destctime = (time_t)-1;
03071 KIO::filesize_t destsize = 0;
03072 QString linkDest;
03073 UDSEntry entry = ((KIO::StatJob*)job)->statResult();
03074 KIO::UDSEntry::ConstIterator it2 = entry.begin();
03075 for( ; it2 != entry.end(); it2++ ) {
03076 switch ((*it2).m_uds) {
03077 case UDS_MODIFICATION_TIME:
03078 destmtime = (time_t)((*it2).m_long);
03079 break;
03080 case UDS_CREATION_TIME:
03081 destctime = (time_t)((*it2).m_long);
03082 break;
03083 case UDS_SIZE:
03084 destsize = (*it2).m_long;
03085 break;
03086 case UDS_LINK_DEST:
03087 linkDest = (*it2).m_str;
03088 break;
03089 }
03090 }
03091
03092
03093
03094 RenameDlg_Mode mode;
03095
03096 if( m_conflictError == ERR_DIR_ALREADY_EXIST )
03097 mode = (RenameDlg_Mode) 0;
03098 else
03099 {
03100 if ( (*it).uSource == (*it).uDest ||
03101 ((*it).uSource.protocol() == (*it).uDest.protocol() &&
03102 (*it).uSource.path(-1) == linkDest) )
03103 mode = M_OVERWRITE_ITSELF;
03104 else
03105 mode = M_OVERWRITE;
03106 }
03107
03108 if ( m_bSingleFileCopy )
03109 mode = (RenameDlg_Mode) ( mode | M_SINGLE );
03110 else
03111 mode = (RenameDlg_Mode) ( mode | M_MULTI | M_SKIP );
03112
03113 res = Observer::self()->open_RenameDlg( this, m_conflictError == ERR_FILE_ALREADY_EXIST ?
03114 i18n("File Already Exists") : i18n("Already Exists as Folder"),
03115 (*it).uSource.url(),
03116 (*it).uDest.url(),
03117 mode, newPath,
03118 (*it).size, destsize,
03119 (*it).ctime, destctime,
03120 (*it).mtime, destmtime );
03121
03122 }
03123 else
03124 {
03125 if ( job->error() == ERR_USER_CANCELED )
03126 res = R_CANCEL;
03127 else if ( !isInteractive() ) {
03128 Job::slotResult( job );
03129 return;
03130 }
03131 else
03132 {
03133 SkipDlg_Result skipResult = Observer::self()->open_SkipDlg( this, files.count() > 1,
03134 job->errorString() );
03135
03136
03137 res = ( skipResult == S_SKIP ) ? R_SKIP :
03138 ( skipResult == S_AUTO_SKIP ) ? R_AUTO_SKIP :
03139 R_CANCEL;
03140 }
03141 }
03142
03143 if (m_reportTimer)
03144 m_reportTimer->start(REPORT_TIMEOUT,false);
03145
03146 subjobs.remove( job );
03147 assert ( subjobs.isEmpty() );
03148 switch ( res ) {
03149 case R_CANCEL:
03150 m_error = ERR_USER_CANCELED;
03151 emitResult();
03152 return;
03153 case R_RENAME:
03154 {
03155 KURL newUrl( (*it).uDest );
03156 newUrl.setPath( newPath );
03157 emit renamed( this, (*it).uDest, newUrl );
03158 (*it).uDest = newUrl;
03159
03160 QValueList<CopyInfo> files;
03161 files.append(*it);
03162 emit aboutToCreate( this, files );
03163 }
03164 break;
03165 case R_AUTO_SKIP:
03166 m_bAutoSkip = true;
03167
03168 case R_SKIP:
03169
03170 skip( (*it).uSource );
03171 m_processedSize += (*it).size;
03172 files.remove( it );
03173 m_processedFiles++;
03174 break;
03175 case R_OVERWRITE_ALL:
03176 m_bOverwriteAll = true;
03177 break;
03178 case R_OVERWRITE:
03179
03180 m_overwriteList.append( (*it).uDest.path() );
03181 break;
03182 default:
03183 assert( 0 );
03184 }
03185 state = STATE_COPYING_FILES;
03186
03187 copyNextFile();
03188 }
03189
03190 void CopyJob::copyNextFile()
03191 {
03192 bool bCopyFile = false;
03193
03194
03195 QValueList<CopyInfo>::Iterator it = files.begin();
03196
03197 while (it != files.end() && !bCopyFile)
03198 {
03199 const QString destFile = (*it).uDest.path();
03200 bCopyFile = !shouldSkip( destFile );
03201 if ( !bCopyFile ) {
03202 files.remove( it );
03203 it = files.begin();
03204 }
03205 }
03206
03207 if (bCopyFile)
03208 {
03209
03210 bool bOverwrite;
03211 const QString destFile = (*it).uDest.path();
03212 kdDebug(7007) << "copying " << destFile << endl;
03213 if ( (*it).uDest == (*it).uSource )
03214 bOverwrite = false;
03215 else
03216 bOverwrite = shouldOverwrite( destFile );
03217
03218 m_bCurrentOperationIsLink = false;
03219 KIO::Job * newjob = 0L;
03220 if ( m_mode == Link )
03221 {
03222
03223 if (
03224 ((*it).uSource.protocol() == (*it).uDest.protocol()) &&
03225 ((*it).uSource.host() == (*it).uDest.host()) &&
03226 ((*it).uSource.port() == (*it).uDest.port()) &&
03227 ((*it).uSource.user() == (*it).uDest.user()) &&
03228 ((*it).uSource.pass() == (*it).uDest.pass()) )
03229 {
03230
03231 KIO::SimpleJob *newJob = KIO::symlink( (*it).uSource.path(), (*it).uDest, bOverwrite, false );
03232 newjob = newJob;
03233 Scheduler::scheduleJob(newJob);
03234
03235
03236 m_bCurrentOperationIsLink = true;
03237 m_currentSrcURL=(*it).uSource;
03238 m_currentDestURL=(*it).uDest;
03239 d->m_bURLDirty = true;
03240
03241 } else {
03242
03243 if ( (*it).uDest.isLocalFile() )
03244 {
03245 bool devicesOk=false;
03246
03247
03248 if ((*it).uSource.protocol()==QString::fromLatin1("devices"))
03249 {
03250 QByteArray data;
03251 QByteArray param;
03252 QCString retType;
03253 QDataStream streamout(param,IO_WriteOnly);
03254 streamout<<(*it).uSource;
03255 streamout<<(*it).uDest;
03256 if ( kapp->dcopClient()->call( "kded",
03257 "mountwatcher", "createLink(KURL, KURL)", param,retType,data,false ) )
03258 {
03259 QDataStream streamin(data,IO_ReadOnly);
03260 streamin>>devicesOk;
03261 }
03262 if (devicesOk)
03263 {
03264 files.remove( it );
03265 m_processedFiles++;
03266
03267 copyNextFile();
03268 return;
03269 }
03270 }
03271
03272 if (!devicesOk)
03273 {
03274 QString path = (*it).uDest.path();
03275
03276 QFile f( path );
03277 if ( f.open( IO_ReadWrite ) )
03278 {
03279 f.close();
03280 KSimpleConfig config( path );
03281 config.setDesktopGroup();
03282 KURL url = (*it).uSource;
03283 url.setPass( "" );
03284 config.writePathEntry( QString::fromLatin1("URL"), url.url() );
03285 config.writeEntry( QString::fromLatin1("Name"), url.url() );
03286 config.writeEntry( QString::fromLatin1("Type"), QString::fromLatin1("Link") );
03287 QString protocol = (*it).uSource.protocol();
03288 if ( protocol == QString::fromLatin1("ftp") )
03289 config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("ftp") );
03290 else if ( protocol == QString::fromLatin1("http") )
03291 config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("www") );
03292 else if ( protocol == QString::fromLatin1("info") )
03293 config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("info") );
03294 else if ( protocol == QString::fromLatin1("mailto") )
03295 config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("kmail") );
03296 else
03297 config.writeEntry( QString::fromLatin1("Icon"), QString::fromLatin1("unknown") );
03298 config.sync();
03299 files.remove( it );
03300 m_processedFiles++;
03301
03302 copyNextFile();
03303 return;
03304 }
03305 else
03306 {
03307 kdDebug(7007) << "CopyJob::copyNextFile ERR_CANNOT_OPEN_FOR_WRITING" << endl;
03308 m_error = ERR_CANNOT_OPEN_FOR_WRITING;
03309 m_errorText = (*it).uDest.path();
03310 emitResult();
03311 return;
03312 }
03313 }
03314 } else {
03315
03316 m_error = ERR_CANNOT_SYMLINK;
03317 m_errorText = (*it).uDest.prettyURL();
03318 emitResult();
03319 return;
03320 }
03321 }
03322 }
03323 else if ( !(*it).linkDest.isEmpty() &&
03324 ((*it).uSource.protocol() == (*it).uDest.protocol()) &&
03325 ((*it).uSource.host() == (*it).uDest.host()) &&
03326 ((*it).uSource.port() == (*it).uDest.port()) &&
03327 ((*it).uSource.user() == (*it).uDest.user()) &&
03328 ((*it).uSource.pass() == (*it).uDest.pass()))
03329
03330 {
03331 KIO::SimpleJob *newJob = KIO::symlink( (*it).linkDest, (*it).uDest, bOverwrite, false );
03332 Scheduler::scheduleJob(newJob);
03333 newjob = newJob;
03334
03335
03336 m_currentSrcURL=(*it).linkDest;
03337 m_currentDestURL=(*it).uDest;
03338 d->m_bURLDirty = true;
03339
03340 m_bCurrentOperationIsLink = true;
03341
03342 } else if (m_mode == Move)
03343 {
03344 KIO::FileCopyJob * moveJob = KIO::file_move( (*it).uSource, (*it).uDest, (*it).permissions, bOverwrite, false, false );
03345 moveJob->setSourceSize64( (*it).size );
03346 newjob = moveJob;
03347
03348
03349 m_currentSrcURL=(*it).uSource;
03350 m_currentDestURL=(*it).uDest;
03351 d->m_bURLDirty = true;
03352
03353 }
03354 else
03355 {
03356
03357
03358 bool remoteSource = !KProtocolInfo::supportsListing((*it).uSource);
03359 int permissions = (*it).permissions;
03360 if ( d->m_defaultPermissions || ( remoteSource && (*it).uDest.isLocalFile() ) )
03361 permissions = -1;
03362 KIO::FileCopyJob * copyJob = KIO::file_copy( (*it).uSource, (*it).uDest, permissions, bOverwrite, false, false );
03363 copyJob->setParentJob( this );
03364 copyJob->setSourceSize64( (*it).size );
03365 newjob = copyJob;
03366
03367 m_currentSrcURL=(*it).uSource;
03368 m_currentDestURL=(*it).uDest;
03369 d->m_bURLDirty = true;
03370 }
03371 addSubjob(newjob);
03372 connect( newjob, SIGNAL( processedSize( KIO::Job*, KIO::filesize_t ) ),
03373 this, SLOT( slotProcessedSize( KIO::Job*, KIO::filesize_t ) ) );
03374 connect( newjob, SIGNAL( totalSize( KIO::Job*, KIO::filesize_t ) ),
03375 this, SLOT( slotTotalSize( KIO::Job*, KIO::filesize_t ) ) );
03376 }
03377 else
03378 {
03379
03380
03381 deleteNextDir();
03382 }
03383 }
03384
03385 void CopyJob::deleteNextDir()
03386 {
03387 if ( m_mode == Move && !dirsToRemove.isEmpty() )
03388 {
03389 state = STATE_DELETING_DIRS;
03390 d->m_bURLDirty = true;
03391
03392 KURL::List::Iterator it = dirsToRemove.fromLast();
03393 SimpleJob *job = KIO::rmdir( *it );
03394 Scheduler::scheduleJob(job);
03395 dirsToRemove.remove(it);
03396 addSubjob( job );
03397 }
03398 else
03399 {
03400
03401 if ( !m_bOnlyRenames )
03402 {
03403 KDirNotify_stub allDirNotify("*", "KDirNotify*");
03404 KURL url( d->m_globalDest );
03405 if ( d->m_globalDestinationState != DEST_IS_DIR || m_asMethod )
03406 url.setPath( url.directory() );
03407
03408 allDirNotify.FilesAdded( url );
03409
03410 if ( m_mode == Move && !m_srcList.isEmpty() ) {
03411
03412 allDirNotify.FilesRemoved( m_srcList );
03413 }
03414 }
03415 if (m_reportTimer!=0)
03416 m_reportTimer->stop();
03417 emitResult();
03418 }
03419 }
03420
03421 void CopyJob::slotProcessedSize( KIO::Job*, KIO::filesize_t data_size )
03422 {
03423
03424 m_fileProcessedSize = data_size;
03425 setProcessedSize(m_processedSize + m_fileProcessedSize);
03426
03427 if ( m_processedSize + m_fileProcessedSize > m_totalSize )
03428 {
03429 m_totalSize = m_processedSize + m_fileProcessedSize;
03430
03431 emit totalSize( this, m_totalSize );
03432 }
03433
03434 emit processedSize( this, m_processedSize + m_fileProcessedSize );
03435 emitPercent( m_processedSize + m_fileProcessedSize, m_totalSize );
03436 }
03437
03438 void CopyJob::slotTotalSize( KIO::Job*, KIO::filesize_t size )
03439 {
03440
03441
03442
03443
03444 if ( m_bSingleFileCopy && size > m_totalSize)
03445 {
03446
03447 m_totalSize = size;
03448 emit totalSize( this, size );
03449 }
03450 }
03451
03452 void CopyJob::slotResultDeletingDirs( Job * job )
03453 {
03454 if (job->error())
03455 {
03456
03457
03458
03459 }
03460 subjobs.remove( job );
03461 assert ( subjobs.isEmpty() );
03462 deleteNextDir();
03463 }
03464
03465 void CopyJob::slotResultRenaming( Job* job )
03466 {
03467 int err = job->error();
03468 const QString errText = job->errorText();
03469 removeSubjob( job, true, false );
03470 assert ( subjobs.isEmpty() );
03471
03472 KURL dest = m_dest;
03473 if ( destinationState == DEST_IS_DIR && !m_asMethod )
03474 dest.addPath( m_currentSrcURL.fileName() );
03475 if ( err )
03476 {
03477
03478
03479
03480 if ( m_currentSrcURL.isLocalFile() && m_currentSrcURL.url(-1) != dest.url(-1) &&
03481 m_currentSrcURL.url(-1).lower() == dest.url(-1).lower() &&
03482 ( err == ERR_FILE_ALREADY_EXIST || err == ERR_DIR_ALREADY_EXIST ) )
03483 {
03484 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;
03485 QCString _src( QFile::encodeName(m_currentSrcURL.path()) );
03486 QCString _dest( QFile::encodeName(dest.path()) );
03487 KTempFile tmpFile( m_currentSrcURL.directory(false) );
03488 QCString _tmp( QFile::encodeName(tmpFile.name()) );
03489 kdDebug(7007) << "CopyJob::slotResult KTempFile status:" << tmpFile.status() << " using " << _tmp << " as intermediary" << endl;
03490 tmpFile.unlink();
03491 if ( ::rename( _src, _tmp ) == 0 )
03492 {
03493 if ( !QFile::exists( _dest ) && ::rename( _tmp, _dest ) == 0 )
03494 {
03495 kdDebug(7007) << "Success." << endl;
03496 err = 0;
03497 }
03498 else
03499 {
03500
03501 if ( ::rename( _tmp, _src ) != 0 ) {
03502 kdError(7007) << "Couldn't rename " << tmpFile.name() << " back to " << _src << " !" << endl;
03503
03504 Job::slotResult( job );
03505 return;
03506 }
03507 }
03508 }
03509 }
03510 }
03511 if ( err )
03512 {
03513
03514
03515
03516
03517
03518
03519
03520 Q_ASSERT( m_currentSrcURL == *m_currentStatSrc );
03521
03522
03523 if ( ( err == ERR_DIR_ALREADY_EXIST || err == ERR_FILE_ALREADY_EXIST )
03524 && isInteractive() )
03525 {
03526 if (m_reportTimer)
03527 m_reportTimer->stop();
03528
03529
03530 if ( m_bAutoSkip ) {
03531
03532 skipSrc();
03533 return;
03534 } else if ( m_bOverwriteAll ) {
03535 ;
03536 } else {
03537 QString newPath;
03538
03539 RenameDlg_Mode mode = (RenameDlg_Mode)
03540 ( ( m_currentSrcURL == dest ) ? M_OVERWRITE_ITSELF : M_OVERWRITE );
03541
03542 if ( m_srcList.count() > 1 )
03543 mode = (RenameDlg_Mode) ( mode | M_MULTI | M_SKIP );
03544 else
03545 mode = (RenameDlg_Mode) ( mode | M_SINGLE );
03546
03547
03548
03549
03550 KIO::filesize_t sizeSrc = (KIO::filesize_t) -1;
03551 KIO::filesize_t sizeDest = (KIO::filesize_t) -1;
03552 time_t ctimeSrc = (time_t) -1;
03553 time_t ctimeDest = (time_t) -1;
03554 time_t mtimeSrc = (time_t) -1;
03555 time_t mtimeDest = (time_t) -1;
03556
03557 KDE_struct_stat stat_buf;
03558 if ( m_currentSrcURL.isLocalFile() &&
03559 KDE_stat(QFile::encodeName(m_currentSrcURL.path()), &stat_buf) == 0 ) {
03560 sizeSrc = stat_buf.st_size;
03561 ctimeSrc = stat_buf.st_ctime;
03562 mtimeSrc = stat_buf.st_mtime;
03563 }
03564 if ( dest.isLocalFile() &&
03565 KDE_stat(QFile::encodeName(dest.path()), &stat_buf) == 0 ) {
03566 sizeDest = stat_buf.st_size;
03567 ctimeDest = stat_buf.st_ctime;
03568 mtimeDest = stat_buf.st_mtime;
03569 }
03570
03571 RenameDlg_Result r = Observer::self()->open_RenameDlg(
03572 this,
03573 err == ERR_FILE_ALREADY_EXIST ? i18n("File Already Exists") : i18n("Already Exists as Folder"),
03574 m_currentSrcURL.url(),
03575 dest.url(),
03576 mode, newPath,
03577 sizeSrc, sizeDest,
03578 ctimeSrc, ctimeDest,
03579 mtimeSrc, mtimeDest );
03580 if (m_reportTimer)
03581 m_reportTimer->start(REPORT_TIMEOUT,false);
03582
03583 switch ( r )
03584 {
03585 case R_CANCEL:
03586 {
03587 m_error = ERR_USER_CANCELED;
03588 emitResult();
03589 return;
03590 }
03591 case R_RENAME:
03592 {
03593
03594
03595 m_dest.setPath( newPath );
03596 KIO::Job* job = KIO::stat( m_dest, false, 2, false );
03597 state = STATE_STATING;
03598 destinationState = DEST_NOT_STATED;
03599 addSubjob(job);
03600 return;
03601 }
03602 case R_AUTO_SKIP:
03603 m_bAutoSkip = true;
03604
03605 case R_SKIP:
03606
03607 skipSrc();
03608 return;
03609 case R_OVERWRITE_ALL:
03610 m_bOverwriteAll = true;
03611 break;
03612 case R_OVERWRITE:
03613
03614
03615
03616
03617
03618 kdDebug(7007) << "adding to overwrite list: " << dest.path() << endl;
03619 m_overwriteList.append( dest.path() );
03620 break;
03621 default:
03622
03623 break;
03624 }
03625 }
03626 } else if ( err != KIO::ERR_UNSUPPORTED_ACTION ) {
03627 kdDebug(7007) << "Couldn't rename " << m_currentSrcURL << " to " << dest << ", aborting" << endl;
03628 m_error = err;
03629 m_errorText = errText;
03630 emitResult();
03631 return;
03632 }
03633 kdDebug(7007) << "Couldn't rename " << m_currentSrcURL << " to " << dest << ", reverting to normal way, starting with stat" << endl;
03634
03635 KIO::Job* job = KIO::stat( m_currentSrcURL, true, 2, false );
03636 state = STATE_STATING;
03637 addSubjob(job);
03638 m_bOnlyRenames = false;
03639 }
03640 else
03641 {
03642
03643 emit copyingDone( this, *m_currentStatSrc, dest, true, true );
03644 statNextSrc();
03645 }
03646 }
03647
03648 void CopyJob::slotResult( Job *job )
03649 {
03650
03651
03652
03653
03654
03655
03656 switch ( state ) {
03657 case STATE_STATING:
03658 slotResultStating( job );
03659 break;
03660 case STATE_RENAMING:
03661 {
03662 slotResultRenaming( job );
03663 break;
03664 }
03665 case STATE_LISTING:
03666
03667
03668 if (job->error())
03669 {
03670 Job::slotResult( job );
03671 return;
03672 }
03673
03674 subjobs.remove( job );
03675 assert ( subjobs.isEmpty() );
03676
03677 statNextSrc();
03678 break;
03679 case STATE_CREATING_DIRS:
03680 slotResultCreatingDirs( job );
03681 break;
03682 case STATE_CONFLICT_CREATING_DIRS:
03683 slotResultConflictCreatingDirs( job );
03684 break;
03685 case STATE_COPYING_FILES:
03686 slotResultCopyingFiles( job );
03687 break;
03688 case STATE_CONFLICT_COPYING_FILES:
03689 slotResultConflictCopyingFiles( job );
03690 break;
03691 case STATE_DELETING_DIRS:
03692 slotResultDeletingDirs( job );
03693 break;
03694 default:
03695 assert( 0 );
03696 }
03697 }
03698
03699 void KIO::CopyJob::setDefaultPermissions( bool b )
03700 {
03701 d->m_defaultPermissions = b;
03702 }
03703
03704
03705 void KIO::CopyJob::setInteractive( bool b )
03706 {
03707 Job::setInteractive( b );
03708 }
03709
03710 CopyJob *KIO::copy(const KURL& src, const KURL& dest, bool showProgressInfo )
03711 {
03712
03713 KURL::List srcList;
03714 srcList.append( src );
03715 return new CopyJob( srcList, dest, CopyJob::Copy, false, showProgressInfo );
03716 }
03717
03718 CopyJob *KIO::copyAs(const KURL& src, const KURL& dest, bool showProgressInfo )
03719 {
03720
03721 KURL::List srcList;
03722 srcList.append( src );
03723 return new CopyJob( srcList, dest, CopyJob::Copy, true, showProgressInfo );
03724 }
03725
03726 CopyJob *KIO::copy( const KURL::List& src, const KURL& dest, bool showProgressInfo )
03727 {
03728 return new CopyJob( src, dest, CopyJob::Copy, false, showProgressInfo );
03729 }
03730
03731 CopyJob *KIO::move(const KURL& src, const KURL& dest, bool showProgressInfo )
03732 {
03733 KURL::List srcList;
03734 srcList.append( src );
03735 return new CopyJob( srcList, dest, CopyJob::Move, false, showProgressInfo );
03736 }
03737
03738 CopyJob *KIO::moveAs(const KURL& src, const KURL& dest, bool showProgressInfo )
03739 {
03740 KURL::List srcList;
03741 srcList.append( src );
03742 return new CopyJob( srcList, dest, CopyJob::Move, true, showProgressInfo );
03743 }
03744
03745 CopyJob *KIO::move( const KURL::List& src, const KURL& dest, bool showProgressInfo )
03746 {
03747 return new CopyJob( src, dest, CopyJob::Move, false, showProgressInfo );
03748 }
03749
03750 CopyJob *KIO::link(const KURL& src, const KURL& destDir, bool showProgressInfo )
03751 {
03752 KURL::List srcList;
03753 srcList.append( src );
03754 return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
03755 }
03756
03757 CopyJob *KIO::link(const KURL::List& srcList, const KURL& destDir, bool showProgressInfo )
03758 {
03759 return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
03760 }
03761
03762 CopyJob *KIO::linkAs(const KURL& src, const KURL& destDir, bool showProgressInfo )
03763 {
03764 KURL::List srcList;
03765 srcList.append( src );
03766 return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
03767 }
03768
03769 CopyJob *KIO::trash(const KURL& src, bool showProgressInfo )
03770 {
03771 KURL::List srcList;
03772 srcList.append( src );
03773 return new CopyJob( srcList, KURL( "trash:/" ), CopyJob::Move, false, showProgressInfo );
03774 }
03775
03776 CopyJob *KIO::trash(const KURL::List& srcList, bool showProgressInfo )
03777 {
03778 return new CopyJob( srcList, KURL( "trash:/" ), CopyJob::Move, false, showProgressInfo );
03779 }
03780
03782
03783 DeleteJob::DeleteJob( const KURL::List& src, bool , bool showProgressInfo )
03784 : Job(showProgressInfo), m_totalSize( 0 ), m_processedSize( 0 ), m_fileProcessedSize( 0 ),
03785 m_processedFiles( 0 ), m_processedDirs( 0 ), m_totalFilesDirs( 0 ),
03786 m_srcList(src), m_currentStat(m_srcList.begin()), m_reportTimer(0)
03787 {
03788 if ( showProgressInfo ) {
03789
03790 connect( this, SIGNAL( totalFiles( KIO::Job*, unsigned long ) ),
03791 Observer::self(), SLOT( slotTotalFiles( KIO::Job*, unsigned long ) ) );
03792
03793 connect( this, SIGNAL( totalDirs( KIO::Job*, unsigned long ) ),
03794 Observer::self(), SLOT( slotTotalDirs( KIO::Job*, unsigned long ) ) );
03795
03796
03797
03798
03799
03800
03801
03802
03803
03804
03805
03806 m_reportTimer=new QTimer(this);
03807 connect(m_reportTimer,SIGNAL(timeout()),this,SLOT(slotReport()));
03808
03809 m_reportTimer->start(REPORT_TIMEOUT,false);
03810 }
03811
03812 QTimer::singleShot(0, this, SLOT(slotStart()));
03813 }
03814
03815 void DeleteJob::slotStart()
03816 {
03817 statNextSrc();
03818 }
03819
03820
03821
03822
03823 void DeleteJob::slotReport()
03824 {
03825 if (m_progressId==0)
03826 return;
03827
03828 Observer * observer = Observer::self();
03829
03830 emit deleting( this, m_currentURL );
03831 observer->slotDeleting(this,m_currentURL);
03832
03833 switch( state ) {
03834 case STATE_STATING:
03835 case STATE_LISTING:
03836 emit totalSize( this, m_totalSize );
03837 emit totalFiles( this, files.count() );
03838 emit totalDirs( this, dirs.count() );
03839 break;
03840 case STATE_DELETING_DIRS:
03841 emit processedDirs( this, m_processedDirs );
03842 observer->slotProcessedDirs(this,m_processedDirs);
03843 emitPercent( m_processedFiles + m_processedDirs, m_totalFilesDirs );
03844 break;
03845 case STATE_DELETING_FILES:
03846 observer->slotProcessedFiles(this,m_processedFiles);
03847 emit processedFiles( this, m_processedFiles );
03848 emitPercent( m_processedFiles, m_totalFilesDirs );
03849 break;
03850 }
03851 }
03852
03853
03854 void DeleteJob::slotEntries(KIO::Job* job, const UDSEntryList& list)
03855 {
03856 UDSEntryListConstIterator it = list.begin();
03857 UDSEntryListConstIterator end = list.end();
03858 for (; it != end; ++it)
03859 {
03860 UDSEntry::ConstIterator it2 = (*it).begin();
03861 bool bDir = false;
03862 bool bLink = false;
03863 QString displayName;
03864 KURL url;
03865 int atomsFound(0);
03866 for( ; it2 != (*it).end(); it2++ )
03867 {
03868 switch ((*it2).m_uds)
03869 {
03870 case UDS_FILE_TYPE:
03871 bDir = S_ISDIR((*it2).m_long);
03872 atomsFound++;
03873 break;
03874 case UDS_NAME:
03875 displayName = (*it2).m_str;
03876 atomsFound++;
03877 break;
03878 case UDS_URL:
03879 url = KURL((*it2).m_str);
03880 atomsFound++;
03881 break;
03882 case UDS_LINK_DEST:
03883 bLink = !(*it2).m_str.isEmpty();
03884 atomsFound++;
03885 break;
03886 case UDS_SIZE:
03887 m_totalSize += (KIO::filesize_t)((*it2).m_long);
03888 atomsFound++;
03889 break;
03890 default:
03891 break;
03892 }
03893 if (atomsFound==5) break;
03894 }
03895 assert(!displayName.isEmpty());
03896 if (displayName != ".." && displayName != ".")
03897 {
03898 if( url.isEmpty() ) {
03899 url = ((SimpleJob *)job)->url();
03900 url.addPath( displayName );
03901 }
03902
03903 if ( bLink )
03904 symlinks.append( url );
03905 else if ( bDir )
03906 dirs.append( url );
03907 else
03908 files.append( url );
03909 }
03910 }
03911 }
03912
03913
03914 void DeleteJob::statNextSrc()
03915 {
03916
03917 if ( m_currentStat != m_srcList.end() )
03918 {
03919 m_currentURL = (*m_currentStat);
03920
03921
03922 if (!KProtocolInfo::supportsDeleting(m_currentURL)) {
03923 QGuardedPtr<DeleteJob> that = this;
03924 ++m_currentStat;
03925 if (isInteractive())
03926 KMessageBox::information( 0, buildErrorString(ERR_CANNOT_DELETE, m_currentURL.prettyURL()));
03927 if (that)
03928 statNextSrc();
03929 return;
03930 }
03931
03932 state = STATE_STATING;
03933 KIO::SimpleJob * job = KIO::stat( m_currentURL, true, 1, false );
03934 Scheduler::scheduleJob(job);
03935
03936 addSubjob(job);
03937
03938
03939 } else
03940 {
03941 m_totalFilesDirs = files.count()+symlinks.count() + dirs.count();
03942 slotReport();
03943
03944
03945
03946
03947 for ( QStringList::Iterator it = m_parentDirs.begin() ; it != m_parentDirs.end() ; ++it )
03948 KDirWatch::self()->stopDirScan( *it );
03949 state = STATE_DELETING_FILES;
03950 deleteNextFile();
03951 }
03952 }
03953
03954 void DeleteJob::deleteNextFile()
03955 {
03956
03957 if ( !files.isEmpty() || !symlinks.isEmpty() )
03958 {
03959 SimpleJob *job;
03960 do {
03961
03962 KURL::List::Iterator it = files.begin();
03963 bool isLink = false;
03964 if ( it == files.end() )
03965 {
03966 it = symlinks.begin();
03967 isLink = true;
03968 }
03969
03970
03971 if ( (*it).isLocalFile() && unlink( QFile::encodeName((*it).path()) ) == 0 ) {
03972 job = 0;
03973 m_processedFiles++;
03974 if ( m_processedFiles % 300 == 0 ) {
03975 m_currentURL = *it;
03976 slotReport();
03977 }
03978 } else
03979 {
03980 job = KIO::file_delete( *it, false );
03981 Scheduler::scheduleJob(job);
03982 m_currentURL=(*it);
03983 }
03984 if ( isLink )
03985 symlinks.remove(it);
03986 else
03987 files.remove(it);
03988 if ( job ) {
03989 addSubjob(job);
03990 return;
03991 }
03992
03993 } while (!job && (!files.isEmpty() || !symlinks.isEmpty()));
03994 }
03995 state = STATE_DELETING_DIRS;
03996 deleteNextDir();
03997 }
03998
03999 void DeleteJob::deleteNextDir()
04000 {
04001 if ( !dirs.isEmpty() )
04002 {
04003 do {
04004
04005 KURL::List::Iterator it = dirs.fromLast();
04006
04007 if ( (*it).isLocalFile() && ::rmdir( QFile::encodeName((*it).path()) ) == 0 ) {
04008
04009 m_processedDirs++;
04010 if ( m_processedDirs % 100 == 0 ) {
04011 m_currentURL = *it;
04012 slotReport();
04013 }
04014 } else {
04015 SimpleJob* job;
04016 if ( KProtocolInfo::canDeleteRecursive( *it ) ) {
04017
04018
04019 job = KIO::file_delete( *it );
04020 } else {
04021 job = KIO::rmdir( *it );
04022 }
04023 Scheduler::scheduleJob(job);
04024 dirs.remove(it);
04025 addSubjob( job );
04026 return;
04027 }
04028 dirs.remove(it);
04029 } while ( !dirs.isEmpty() );
04030 }
04031
04032
04033 for ( QStringList::Iterator it = m_parentDirs.begin() ; it != m_parentDirs.end() ; ++it )
04034 KDirWatch::self()->restartDirScan( *it );
04035
04036
04037 if ( !m_srcList.isEmpty() )
04038 {
04039 KDirNotify_stub allDirNotify("*", "KDirNotify*");
04040
04041 allDirNotify.FilesRemoved( m_srcList );
04042 }
04043 if (m_reportTimer!=0)
04044 m_reportTimer->stop();
04045 emitResult();
04046 }
04047
04048 void DeleteJob::slotProcessedSize( KIO::Job*, KIO::filesize_t data_size )
04049 {
04050
04051
04052
04053
04054 m_fileProcessedSize = data_size;
04055 setProcessedSize(m_processedSize + m_fileProcessedSize);
04056
04057
04058
04059 emit processedSize( this, m_processedSize + m_fileProcessedSize );
04060
04061
04062 unsigned long ipercent = m_percent;
04063
04064 if ( m_totalSize == 0 )
04065 m_percent = 100;
04066 else
04067 m_percent = (unsigned long)(( (float)(m_processedSize + m_fileProcessedSize) / (float)m_totalSize ) * 100.0);
04068
04069 if ( m_percent > ipercent )
04070 {
04071 emit percent( this, m_percent );
04072
04073 }
04074
04075 }
04076
04077 void DeleteJob::slotResult( Job *job )
04078 {
04079 switch ( state )
04080 {
04081 case STATE_STATING:
04082 {
04083
04084 if (job->error() )
04085 {
04086
04087 Job::slotResult( job );
04088 return;
04089 }
04090
04091
04092 UDSEntry entry = ((StatJob*)job)->statResult();
04093 bool bDir = false;
04094 bool bLink = false;
04095 KIO::filesize_t size = (KIO::filesize_t)-1;
04096 UDSEntry::ConstIterator it2 = entry.begin();
04097 int atomsFound(0);
04098 for( ; it2 != entry.end(); it2++ )
04099 {
04100 if ( ((*it2).m_uds) == UDS_FILE_TYPE )
04101 {
04102 bDir = S_ISDIR( (mode_t)(*it2).m_long );
04103 atomsFound++;
04104 }
04105 else if ( ((*it2).m_uds) == UDS_LINK_DEST )
04106 {
04107 bLink = !((*it2).m_str.isEmpty());
04108 atomsFound++;
04109 }
04110 else if ( ((*it2).m_uds) == UDS_SIZE )
04111 {
04112 size = (*it2).m_long;
04113 atomsFound++;
04114 }
04115 if (atomsFound==3) break;
04116 }
04117
04118 KURL url = ((SimpleJob*)job)->url();
04119
04120 subjobs.remove( job );
04121 assert( subjobs.isEmpty() );
04122
04123 if (bDir && !bLink)
04124 {
04125
04126 dirs.append( url );
04127 if ( url.isLocalFile() && !m_parentDirs.contains( url.path(-1) ) )
04128 m_parentDirs.append( url.path(-1) );
04129
04130 if ( !KProtocolInfo::canDeleteRecursive( url ) ) {
04131
04132
04133 state = STATE_LISTING;
04134 ListJob *newjob = listRecursive( url, false );
04135 newjob->setUnrestricted(true);
04136 Scheduler::scheduleJob(newjob);
04137 connect(newjob, SIGNAL(entries( KIO::Job *,
04138 const KIO::UDSEntryList& )),
04139 SLOT( slotEntries( KIO::Job*,
04140 const KIO::UDSEntryList& )));
04141 addSubjob(newjob);
04142 } else {
04143 ++m_currentStat;
04144 statNextSrc();
04145 }
04146 }
04147 else
04148 {
04149 if ( bLink ) {
04150
04151 symlinks.append( url );
04152 } else {
04153
04154 files.append( url );
04155 }
04156 if ( url.isLocalFile() && !m_parentDirs.contains( url.directory(false) ) )
04157 m_parentDirs.append( url.directory(false) );
04158 ++m_currentStat;
04159 statNextSrc();
04160 }
04161 }
04162 break;
04163 case STATE_LISTING:
04164 if ( job->error() )
04165 {
04166
04167 }
04168 subjobs.remove( job );
04169 assert( subjobs.isEmpty() );
04170 ++m_currentStat;
04171 statNextSrc();
04172 break;
04173 case STATE_DELETING_FILES:
04174 if ( job->error() )
04175 {
04176 Job::slotResult( job );
04177 return;
04178 }
04179 subjobs.remove( job );
04180 assert( subjobs.isEmpty() );
04181 m_processedFiles++;
04182
04183 deleteNextFile();
04184 break;
04185 case STATE_DELETING_DIRS:
04186 if ( job->error() )
04187 {
04188 Job::slotResult( job );
04189 return;
04190 }
04191 subjobs.remove( job );
04192 assert( subjobs.isEmpty() );
04193 m_processedDirs++;
04194
04195
04196
04197
04198 deleteNextDir();
04199 break;
04200 default:
04201 assert(0);
04202 }
04203 }
04204
04205 DeleteJob *KIO::del( const KURL& src, bool shred, bool showProgressInfo )
04206 {
04207 KURL::List srcList;
04208 srcList.append( src );
04209 DeleteJob *job = new DeleteJob( srcList, shred, showProgressInfo );
04210 return job;
04211 }
04212
04213 DeleteJob *KIO::del( const KURL::List& src, bool shred, bool showProgressInfo )
04214 {
04215 DeleteJob *job = new DeleteJob( src, shred, showProgressInfo );
04216 return job;
04217 }
04218
04219 MultiGetJob::MultiGetJob(const KURL& url,
04220 bool showProgressInfo)
04221 : TransferJob(url, 0, QByteArray(), QByteArray(), showProgressInfo)
04222 {
04223 m_waitQueue.setAutoDelete(true);
04224 m_activeQueue.setAutoDelete(true);
04225 m_currentEntry = 0;
04226 }
04227
04228 void MultiGetJob::get(long id, const KURL &url, const MetaData &metaData)
04229 {
04230 GetRequest *entry = new GetRequest(id, url, metaData);
04231 entry->metaData["request-id"] = QString("%1").arg(id);
04232 m_waitQueue.append(entry);
04233 }
04234
04235 void MultiGetJob::flushQueue(QPtrList<GetRequest> &queue)
04236 {
04237 GetRequest *entry;
04238
04239
04240 for(entry = m_waitQueue.first(); entry; )
04241 {
04242 if ((m_url.protocol() == entry->url.protocol()) &&
04243 (m_url.host() == entry->url.host()) &&
04244 (m_url.port() == entry->url.port()) &&
04245 (m_url.user() == entry->url.user()))
04246 {
04247 m_waitQueue.take();
04248 queue.append(entry);
04249 entry = m_waitQueue.current();
04250 }
04251 else
04252 {
04253 entry = m_waitQueue.next();
04254 }
04255 }
04256
04257 KIO_ARGS << (Q_INT32) queue.count();
04258 for(entry = queue.first(); entry; entry = queue.next())
04259 {
04260 stream << entry->url << entry->metaData;
04261 }
04262 m_packedArgs = packedArgs;
04263 m_command = CMD_MULTI_GET;
04264 m_outgoingMetaData.clear();
04265 }
04266
04267 void MultiGetJob::start(Slave *slave)
04268 {
04269
04270 GetRequest *entry = m_waitQueue.take(0);
04271 m_activeQueue.append(entry);
04272
04273 m_url = entry->url;
04274
04275 if (!entry->url.protocol().startsWith("http"))
04276 {
04277
04278 KIO_ARGS << entry->url;
04279 m_packedArgs = packedArgs;
04280 m_outgoingMetaData = entry->metaData;
04281 m_command = CMD_GET;
04282 b_multiGetActive = false;
04283 }
04284 else
04285 {
04286 flushQueue(m_activeQueue);
04287 b_multiGetActive = true;
04288 }
04289
04290 TransferJob::start(slave);
04291 }
04292
04293 bool MultiGetJob::findCurrentEntry()
04294 {
04295 if (b_multiGetActive)
04296 {
04297 long id = m_incomingMetaData["request-id"].toLong();
04298 for(GetRequest *entry = m_activeQueue.first(); entry; entry = m_activeQueue.next())
04299 {
04300 if (entry->id == id)
04301 {
04302 m_currentEntry = entry;
04303 return true;
04304 }
04305 }
04306 m_currentEntry = 0;
04307 return false;
04308 }
04309 else
04310 {
04311 m_currentEntry = m_activeQueue.first();
04312 return (m_currentEntry != 0);
04313 }
04314 }
04315
04316 void MultiGetJob::slotRedirection( const KURL &url)
04317 {
04318 if (!findCurrentEntry()) return;
04319 if (!kapp->authorizeURLAction("redirect", m_url, url))
04320 {
04321 kdWarning(7007) << "MultiGetJob: Redirection from " << m_currentEntry->url << " to " << url << " REJECTED!" << endl;
04322 return;
04323 }
04324 m_redirectionURL = url;
04325 if (m_currentEntry->url.hasUser() && !url.hasUser() && (m_currentEntry->url.host().lower() == url.host().lower()))
04326 m_redirectionURL.setUser(m_currentEntry->url.user());
04327 get(m_currentEntry->id, m_redirectionURL, m_currentEntry->metaData);
04328 }
04329
04330
04331 void MultiGetJob::slotFinished()
04332 {
04333 if (!findCurrentEntry()) return;
04334 if (m_redirectionURL.isEmpty())
04335 {
04336
04337 emit result(m_currentEntry->id);
04338 }
04339 m_redirectionURL = KURL();
04340 m_error = 0;
04341 m_incomingMetaData.clear();
04342 m_activeQueue.removeRef(m_currentEntry);
04343 if (m_activeQueue.count() == 0)
04344 {
04345 if (m_waitQueue.count() == 0)
04346 {
04347
04348 TransferJob::slotFinished();
04349 }
04350 else
04351 {
04352
04353
04354
04355 GetRequest *entry = m_waitQueue.at(0);
04356 m_url = entry->url;
04357 slaveDone();
04358 Scheduler::doJob(this);
04359 }
04360 }
04361 }
04362
04363 void MultiGetJob::slotData( const QByteArray &_data)
04364 {
04365 if(!m_currentEntry) return;
04366 if(m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error)
04367 emit data(m_currentEntry->id, _data);
04368 }
04369
04370 void MultiGetJob::slotMimetype( const QString &_mimetype )
04371 {
04372 if (b_multiGetActive)
04373 {
04374 QPtrList<GetRequest> newQueue;
04375 flushQueue(newQueue);
04376 if (!newQueue.isEmpty())
04377 {
04378 while(!newQueue.isEmpty())
04379 m_activeQueue.append(newQueue.take(0));
04380 m_slave->send( m_command, m_packedArgs );
04381 }
04382 }
04383 if (!findCurrentEntry()) return;
04384 emit mimetype(m_currentEntry->id, _mimetype);
04385 }
04386
04387 MultiGetJob *KIO::multi_get(long id, const KURL &url, const MetaData &metaData)
04388 {
04389 MultiGetJob * job = new MultiGetJob( url, false );
04390 job->get(id, url, metaData);
04391 return job;
04392 }
04393
04394
04395 #ifdef CACHE_INFO
04396 CacheInfo::CacheInfo(const KURL &url)
04397 {
04398 m_url = url;
04399 }
04400
04401 QString CacheInfo::cachedFileName()
04402 {
04403 const QChar separator = '_';
04404
04405 QString CEF = m_url.path();
04406
04407 int p = CEF.find('/');
04408
04409 while(p != -1)
04410 {
04411 CEF[p] = separator;
04412 p = CEF.find('/', p);
04413 }
04414
04415 QString host = m_url.host().lower();
04416 CEF = host + CEF + '_';
04417
04418 QString dir = KProtocolManager::cacheDir();
04419 if (dir[dir.length()-1] != '/')
04420 dir += "/";
04421
04422 int l = m_url.host().length();
04423 for(int i = 0; i < l; i++)
04424 {
04425 if (host[i].isLetter() && (host[i] != 'w'))
04426 {
04427 dir += host[i];
04428 break;
04429 }
04430 }
04431 if (dir[dir.length()-1] == '/')
04432 dir += "0";
04433
04434 unsigned long hash = 0x00000000;
04435 QCString u = m_url.url().latin1();
04436 for(int i = u.length(); i--;)
04437 {
04438 hash = (hash * 12211 + u[i]) % 2147483563;
04439 }
04440
04441 QString hashString;
04442 hashString.sprintf("%08lx", hash);
04443
04444 CEF = CEF + hashString;
04445
04446 CEF = dir + "/" + CEF;
04447
04448 return CEF;
04449 }
04450
04451 QFile *CacheInfo::cachedFile()
04452 {
04453 #ifdef Q_WS_WIN
04454 const char *mode = (readWrite ? "rb+" : "rb");
04455 #else
04456 const char *mode = (readWrite ? "r+" : "r");
04457 #endif
04458
04459 FILE *fs = fopen(QFile::encodeName(CEF), mode);
04460 if (!fs)
04461 return 0;
04462
04463 char buffer[401];
04464 bool ok = true;
04465
04466
04467 if (ok && (!fgets(buffer, 400, fs)))
04468 ok = false;
04469 if (ok && (strcmp(buffer, CACHE_REVISION) != 0))
04470 ok = false;
04471
04472 time_t date;
04473 time_t currentDate = time(0);
04474
04475
04476 if (ok && (!fgets(buffer, 400, fs)))
04477 ok = false;
04478 if (ok)
04479 {
04480 int l = strlen(buffer);
04481 if (l>0)
04482 buffer[l-1] = 0;
04483 if (m_.url.url() != buffer)
04484 {
04485 ok = false;
04486 }
04487 }
04488
04489
04490 if (ok && (!fgets(buffer, 400, fs)))
04491 ok = false;
04492 if (ok)
04493 {
04494 date = (time_t) strtoul(buffer, 0, 10);
04495 if (m_maxCacheAge && (difftime(currentDate, date) > m_maxCacheAge))
04496 {
04497 m_bMustRevalidate = true;
04498 m_expireDate = currentDate;
04499 }
04500 }
04501
04502
04503 m_cacheExpireDateOffset = ftell(fs);
04504 if (ok && (!fgets(buffer, 400, fs)))
04505 ok = false;
04506 if (ok)
04507 {
04508 if (m_request.cache == CC_Verify)
04509 {
04510 date = (time_t) strtoul(buffer, 0, 10);
04511
04512 if (!date || difftime(currentDate, date) >= 0)
04513 m_bMustRevalidate = true;
04514 m_expireDate = date;
04515 }
04516 }
04517
04518
04519 if (ok && (!fgets(buffer, 400, fs)))
04520 ok = false;
04521 if (ok)
04522 {
04523 m_etag = QString(buffer).stripWhiteSpace();
04524 }
04525
04526
04527 if (ok && (!fgets(buffer, 400, fs)))
04528 ok = false;
04529 if (ok)
04530 {
04531 m_lastModified = QString(buffer).stripWhiteSpace();
04532 }
04533
04534 fclose(fs);
04535
04536 if (ok)
04537 return fs;
04538
04539 unlink( QFile::encodeName(CEF) );
04540 return 0;
04541
04542 }
04543
04544 void CacheInfo::flush()
04545 {
04546 cachedFile().remove();
04547 }
04548
04549 void CacheInfo::touch()
04550 {
04551
04552 }
04553 void CacheInfo::setExpireDate(int);
04554 void CacheInfo::setExpireTimeout(int);
04555
04556
04557 int CacheInfo::creationDate();
04558 int CacheInfo::expireDate();
04559 int CacheInfo::expireTimeout();
04560 #endif
04561
04562 void Job::virtual_hook( int, void* )
04563 { }
04564
04565 void SimpleJob::virtual_hook( int id, void* data )
04566 { KIO::Job::virtual_hook( id, data ); }
04567
04568 void MkdirJob::virtual_hook( int id, void* data )
04569 { SimpleJob::virtual_hook( id, data ); }
04570
04571 void StatJob::virtual_hook( int id, void* data )
04572 { SimpleJob::virtual_hook( id, data ); }
04573
04574 void TransferJob::virtual_hook( int id, void* data )
04575 { SimpleJob::virtual_hook( id, data ); }
04576
04577 void MultiGetJob::virtual_hook( int id, void* data )
04578 { TransferJob::virtual_hook( id, data ); }
04579
04580 void MimetypeJob::virtual_hook( int id, void* data )
04581 { TransferJob::virtual_hook( id, data ); }
04582
04583 void FileCopyJob::virtual_hook( int id, void* data )
04584 { Job::virtual_hook( id, data ); }
04585
04586 void ListJob::virtual_hook( int id, void* data )
04587 { SimpleJob::virtual_hook( id, data ); }
04588
04589 void CopyJob::virtual_hook( int id, void* data )
04590 { Job::virtual_hook( id, data ); }
04591
04592 void DeleteJob::virtual_hook( int id, void* data )
04593 { Job::virtual_hook( id, data ); }
04594
04595
04596 #include "jobclasses.moc"