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