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