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