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