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