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