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