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 KURL url = (*it).uSource;
03125 url.setPass( "" );
03126 config.writePathEntry( QString::fromLatin1("URL"), url.url() );
03127 config.writeEntry( QString::fromLatin1("Name"), url.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 ( m_currentSrcURL == dest ) ? M_OVERWRITE_ITSELF : M_OVERWRITE );
03380
03381 if ( m_srcList.count() > 1 )
03382 mode = (RenameDlg_Mode) ( mode | M_MULTI | M_SKIP );
03383 else
03384 mode = (RenameDlg_Mode) ( mode | M_SINGLE );
03385
03386
03387
03388
03389 KIO::filesize_t sizeSrc = (KIO::filesize_t) -1;
03390 KIO::filesize_t sizeDest = (KIO::filesize_t) -1;
03391 time_t ctimeSrc = (time_t) -1;
03392 time_t ctimeDest = (time_t) -1;
03393 time_t mtimeSrc = (time_t) -1;
03394 time_t mtimeDest = (time_t) -1;
03395
03396 KDE_struct_stat stat_buf;
03397 if ( m_currentSrcURL.isLocalFile() &&
03398 KDE_stat(QFile::encodeName(m_currentSrcURL.path()), &stat_buf) == 0 ) {
03399 sizeSrc = stat_buf.st_size;
03400 ctimeSrc = stat_buf.st_ctime;
03401 mtimeSrc = stat_buf.st_mtime;
03402 }
03403 if ( dest.isLocalFile() &&
03404 KDE_stat(QFile::encodeName(dest.path()), &stat_buf) == 0 ) {
03405 sizeDest = stat_buf.st_size;
03406 ctimeDest = stat_buf.st_ctime;
03407 mtimeDest = stat_buf.st_mtime;
03408 }
03409
03410 RenameDlg_Result r = Observer::self()->open_RenameDlg(
03411 this,
03412 err == ERR_FILE_ALREADY_EXIST ? i18n("File Already Exists") : i18n("Already Exists as Folder"),
03413 m_currentSrcURL.prettyURL(0, KURL::StripFileProtocol),
03414 dest.prettyURL(0, KURL::StripFileProtocol),
03415 mode, newPath,
03416 sizeSrc, sizeDest,
03417 ctimeSrc, ctimeDest,
03418 mtimeSrc, mtimeDest );
03419 if (m_reportTimer)
03420 m_reportTimer->start(REPORT_TIMEOUT,false);
03421
03422 switch ( r )
03423 {
03424 case R_CANCEL:
03425 {
03426 m_error = ERR_USER_CANCELED;
03427 emitResult();
03428 return;
03429 }
03430 case R_RENAME:
03431 {
03432
03433
03434 m_dest.setPath( newPath );
03435 KIO::Job* job = KIO::stat( m_dest, false, 2, false );
03436 state = STATE_STATING;
03437 destinationState = DEST_NOT_STATED;
03438 addSubjob(job);
03439 return;
03440 }
03441 case R_AUTO_SKIP:
03442 m_bAutoSkip = true;
03443
03444 case R_SKIP:
03445
03446 skipSrc();
03447 return;
03448 case R_OVERWRITE_ALL:
03449 m_bOverwriteAll = true;
03450 break;
03451 case R_OVERWRITE:
03452
03453
03454
03455
03456
03457 kdDebug(7007) << "adding to overwrite list: " << dest.path() << endl;
03458 m_overwriteList.append( dest.path() );
03459 break;
03460 default:
03461
03462 break;
03463 }
03464 }
03465 }
03466
03467 kdDebug(7007) << "Couldn't rename, reverting to normal way, starting with stat" << endl;
03468
03469 KIO::Job* job = KIO::stat( m_currentSrcURL, true, 2, false );
03470 state = STATE_STATING;
03471 addSubjob(job);
03472 m_bOnlyRenames = false;
03473 }
03474 else
03475 {
03476
03477 emit copyingDone( this, *m_currentStatSrc, dest, true, true );
03478 statNextSrc();
03479 }
03480 }
03481
03482 void CopyJob::slotResult( Job *job )
03483 {
03484
03485
03486
03487
03488
03489
03490 switch ( state ) {
03491 case STATE_STATING:
03492 slotResultStating( job );
03493 break;
03494 case STATE_RENAMING:
03495 {
03496 slotResultRenaming( job );
03497 break;
03498 }
03499 case STATE_LISTING:
03500
03501
03502 if (job->error())
03503 {
03504 Job::slotResult( job );
03505 return;
03506 }
03507
03508 subjobs.remove( job );
03509 assert ( subjobs.isEmpty() );
03510
03511 statNextSrc();
03512 break;
03513 case STATE_CREATING_DIRS:
03514 slotResultCreatingDirs( job );
03515 break;
03516 case STATE_CONFLICT_CREATING_DIRS:
03517 slotResultConflictCreatingDirs( job );
03518 break;
03519 case STATE_COPYING_FILES:
03520 slotResultCopyingFiles( job );
03521 break;
03522 case STATE_CONFLICT_COPYING_FILES:
03523 slotResultConflictCopyingFiles( job );
03524 break;
03525 case STATE_DELETING_DIRS:
03526 slotResultDeletingDirs( job );
03527 break;
03528 default:
03529 assert( 0 );
03530 }
03531 }
03532
03533 void KIO::CopyJob::setDefaultPermissions( bool b )
03534 {
03535 d->m_defaultPermissions = b;
03536 }
03537
03538 CopyJob *KIO::copy(const KURL& src, const KURL& dest, bool showProgressInfo )
03539 {
03540
03541 KURL::List srcList;
03542 srcList.append( src );
03543 return new CopyJob( srcList, dest, CopyJob::Copy, false, showProgressInfo );
03544 }
03545
03546 CopyJob *KIO::copyAs(const KURL& src, const KURL& dest, bool showProgressInfo )
03547 {
03548
03549 KURL::List srcList;
03550 srcList.append( src );
03551 return new CopyJob( srcList, dest, CopyJob::Copy, true, showProgressInfo );
03552 }
03553
03554 CopyJob *KIO::copy( const KURL::List& src, const KURL& dest, bool showProgressInfo )
03555 {
03556 return new CopyJob( src, dest, CopyJob::Copy, false, showProgressInfo );
03557 }
03558
03559 CopyJob *KIO::move(const KURL& src, const KURL& dest, bool showProgressInfo )
03560 {
03561 KURL::List srcList;
03562 srcList.append( src );
03563 return new CopyJob( srcList, dest, CopyJob::Move, false, showProgressInfo );
03564 }
03565
03566 CopyJob *KIO::moveAs(const KURL& src, const KURL& dest, bool showProgressInfo )
03567 {
03568 KURL::List srcList;
03569 srcList.append( src );
03570 return new CopyJob( srcList, dest, CopyJob::Move, true, showProgressInfo );
03571 }
03572
03573 CopyJob *KIO::move( const KURL::List& src, const KURL& dest, bool showProgressInfo )
03574 {
03575 return new CopyJob( src, dest, CopyJob::Move, false, showProgressInfo );
03576 }
03577
03578 CopyJob *KIO::link(const KURL& src, const KURL& destDir, bool showProgressInfo )
03579 {
03580 KURL::List srcList;
03581 srcList.append( src );
03582 return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
03583 }
03584
03585 CopyJob *KIO::link(const KURL::List& srcList, const KURL& destDir, bool showProgressInfo )
03586 {
03587 return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
03588 }
03589
03590 CopyJob *KIO::linkAs(const KURL& src, const KURL& destDir, bool showProgressInfo )
03591 {
03592 KURL::List srcList;
03593 srcList.append( src );
03594 return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
03595 }
03596
03598
03599 DeleteJob::DeleteJob( const KURL::List& src, bool shred, bool showProgressInfo )
03600 : Job(showProgressInfo), m_totalSize( 0 ), m_processedSize( 0 ), m_fileProcessedSize( 0 ),
03601 m_processedFiles( 0 ), m_processedDirs( 0 ), m_totalFilesDirs( 0 ),
03602 m_srcList(src), m_currentStat(m_srcList.begin()), m_shred(shred), m_reportTimer(0)
03603 {
03604 if ( showProgressInfo ) {
03605
03606 connect( this, SIGNAL( totalFiles( KIO::Job*, unsigned long ) ),
03607 Observer::self(), SLOT( slotTotalFiles( KIO::Job*, unsigned long ) ) );
03608
03609 connect( this, SIGNAL( totalDirs( KIO::Job*, unsigned long ) ),
03610 Observer::self(), SLOT( slotTotalDirs( KIO::Job*, unsigned long ) ) );
03611
03612
03613
03614
03615
03616
03617
03618
03619
03620
03621
03622 m_reportTimer=new QTimer(this);
03623 connect(m_reportTimer,SIGNAL(timeout()),this,SLOT(slotReport()));
03624
03625 m_reportTimer->start(REPORT_TIMEOUT,false);
03626 }
03627
03628 QTimer::singleShot(0, this, SLOT(slotStart()));
03629 }
03630
03631 void DeleteJob::slotStart()
03632 {
03633 statNextSrc();
03634 }
03635
03636
03637
03638
03639 void DeleteJob::slotReport()
03640 {
03641 if (m_progressId==0)
03642 return;
03643
03644 Observer * observer = Observer::self();
03645
03646 emit deleting( this, m_currentURL );
03647 observer->slotDeleting(this,m_currentURL);
03648
03649 switch( state ) {
03650 case STATE_STATING:
03651 case STATE_LISTING:
03652 emit totalSize( this, m_totalSize );
03653 emit totalFiles( this, files.count() );
03654 emit totalDirs( this, dirs.count() );
03655 break;
03656 case STATE_DELETING_DIRS:
03657 emit processedDirs( this, m_processedDirs );
03658 observer->slotProcessedDirs(this,m_processedDirs);
03659 emitPercent( m_processedFiles + m_processedDirs, m_totalFilesDirs );
03660 break;
03661 case STATE_DELETING_FILES:
03662 observer->slotProcessedFiles(this,m_processedFiles);
03663 emit processedFiles( this, m_processedFiles );
03664 if (!m_shred)
03665 emitPercent( m_processedFiles, m_totalFilesDirs );
03666 break;
03667 }
03668 }
03669
03670
03671 void DeleteJob::slotEntries(KIO::Job* job, const UDSEntryList& list)
03672 {
03673 UDSEntryListConstIterator it = list.begin();
03674 UDSEntryListConstIterator end = list.end();
03675 for (; it != end; ++it)
03676 {
03677 UDSEntry::ConstIterator it2 = (*it).begin();
03678 bool bDir = false;
03679 bool bLink = false;
03680 QString relName;
03681 int atomsFound(0);
03682 for( ; it2 != (*it).end(); it2++ )
03683 {
03684 switch ((*it2).m_uds)
03685 {
03686 case UDS_FILE_TYPE:
03687 bDir = S_ISDIR((*it2).m_long);
03688 atomsFound++;
03689 break;
03690 case UDS_NAME:
03691 if( relName.isEmpty() )
03692 relName = (*it2).m_str;
03693 break;
03694 case UDS_URL:
03695 relName = KURL((*it2).m_str).fileName();
03696 atomsFound++;
03697 break;
03698 case UDS_LINK_DEST:
03699 bLink = !(*it2).m_str.isEmpty();
03700 atomsFound++;
03701 break;
03702 case UDS_SIZE:
03703 m_totalSize += (KIO::filesize_t)((*it2).m_long);
03704 atomsFound++;
03705 break;
03706 default:
03707 break;
03708 }
03709 if (atomsFound==4) break;
03710 }
03711 assert(!relName.isEmpty());
03712 if (relName != ".." && relName != ".")
03713 {
03714 KURL url = ((SimpleJob *)job)->url();
03715 url.addPath( relName );
03716
03717 if ( bLink )
03718 symlinks.append( url );
03719 else if ( bDir )
03720 dirs.append( url );
03721 else
03722 files.append( url );
03723 }
03724 }
03725 }
03726
03727
03728 void DeleteJob::statNextSrc()
03729 {
03730
03731 if ( m_currentStat != m_srcList.end() )
03732 {
03733 m_currentURL = (*m_currentStat);
03734
03735
03736 if (!KProtocolInfo::supportsDeleting(m_currentURL)) {
03737 QGuardedPtr<DeleteJob> that = this;
03738 ++m_currentStat;
03739 KMessageBox::information( 0, buildErrorString(ERR_CANNOT_DELETE, m_currentURL.prettyURL()));
03740 if (that)
03741 statNextSrc();
03742 return;
03743 }
03744
03745 state = STATE_STATING;
03746 KIO::SimpleJob * job = KIO::stat( m_currentURL, true, 1, false );
03747 Scheduler::scheduleJob(job);
03748
03749 addSubjob(job);
03750
03751
03752 } else
03753 {
03754 m_totalFilesDirs = files.count()+symlinks.count() + dirs.count();
03755 slotReport();
03756
03757
03758
03759
03760 for ( QStringList::Iterator it = m_parentDirs.begin() ; it != m_parentDirs.end() ; ++it )
03761 KDirWatch::self()->stopDirScan( *it );
03762 state = STATE_DELETING_FILES;
03763 deleteNextFile();
03764 }
03765 }
03766
03767 void DeleteJob::deleteNextFile()
03768 {
03769
03770 if ( !files.isEmpty() || !symlinks.isEmpty() )
03771 {
03772 SimpleJob *job;
03773 do {
03774
03775 KURL::List::Iterator it = files.begin();
03776 bool isLink = false;
03777 if ( it == files.end() )
03778 {
03779 it = symlinks.begin();
03780 isLink = true;
03781 }
03782
03783 if ( m_shred && (*it).isLocalFile() && !isLink )
03784 {
03785
03786 KIO_ARGS << int(3) << (*it).path();
03787 job = KIO::special(KURL("file:/"), packedArgs, false );
03788 Scheduler::scheduleJob(job);
03789 m_currentURL=(*it);
03790 connect( job, SIGNAL( processedSize( KIO::Job*, KIO::filesize_t ) ),
03791 this, SLOT( slotProcessedSize( KIO::Job*, KIO::filesize_t ) ) );
03792 } else
03793 {
03794
03795
03796 if ( (*it).isLocalFile() && unlink( QFile::encodeName((*it).path()) ) == 0 ) {
03797 job = 0;
03798 m_processedFiles++;
03799 if ( m_processedFiles % 300 == 0 ) {
03800 m_currentURL = *it;
03801 slotReport();
03802 }
03803 } else
03804 {
03805 job = KIO::file_delete( *it, false );
03806 Scheduler::scheduleJob(job);
03807 m_currentURL=(*it);
03808 }
03809 }
03810 if ( isLink )
03811 symlinks.remove(it);
03812 else
03813 files.remove(it);
03814 if ( job ) {
03815 addSubjob(job);
03816 return;
03817 }
03818
03819 } while (!job && (!files.isEmpty() || !symlinks.isEmpty()));
03820 }
03821 state = STATE_DELETING_DIRS;
03822 deleteNextDir();
03823 }
03824
03825 void DeleteJob::deleteNextDir()
03826 {
03827 if ( !dirs.isEmpty() )
03828 {
03829 do {
03830
03831 KURL::List::Iterator it = dirs.fromLast();
03832
03833 if ( (*it).isLocalFile() && ::rmdir( QFile::encodeName((*it).path()) ) == 0 ) {
03834
03835 m_processedDirs++;
03836 if ( m_processedDirs % 100 == 0 ) {
03837 m_currentURL = *it;
03838 slotReport();
03839 }
03840 } else
03841 {
03842 SimpleJob *job = KIO::rmdir( *it );
03843 Scheduler::scheduleJob(job);
03844 dirs.remove(it);
03845 addSubjob( job );
03846 return;
03847 }
03848 dirs.remove(it);
03849 } while ( !dirs.isEmpty() );
03850 }
03851
03852
03853 for ( QStringList::Iterator it = m_parentDirs.begin() ; it != m_parentDirs.end() ; ++it )
03854 KDirWatch::self()->restartDirScan( *it );
03855
03856
03857 if ( !m_srcList.isEmpty() )
03858 {
03859 KDirNotify_stub allDirNotify("*", "KDirNotify*");
03860 allDirNotify.FilesRemoved( m_srcList );
03861 }
03862 if (m_reportTimer!=0)
03863 m_reportTimer->stop();
03864 emitResult();
03865 }
03866
03867 void DeleteJob::slotProcessedSize( KIO::Job*, KIO::filesize_t data_size )
03868 {
03869
03870
03871
03872
03873 m_fileProcessedSize = data_size;
03874 setProcessedSize(m_processedSize + m_fileProcessedSize);
03875
03876
03877
03878 emit processedSize( this, m_processedSize + m_fileProcessedSize );
03879
03880
03881 unsigned long ipercent = m_percent;
03882
03883 if ( m_totalSize == 0 )
03884 m_percent = 100;
03885 else
03886 m_percent = (unsigned long)(( (float)(m_processedSize + m_fileProcessedSize) / (float)m_totalSize ) * 100.0);
03887
03888 if ( m_percent > ipercent )
03889 {
03890 emit percent( this, m_percent );
03891
03892 }
03893
03894 }
03895
03896 void DeleteJob::slotResult( Job *job )
03897 {
03898 switch ( state )
03899 {
03900 case STATE_STATING:
03901 {
03902
03903 if (job->error() )
03904 {
03905
03906 Job::slotResult( job );
03907 return;
03908 }
03909
03910
03911 UDSEntry entry = ((StatJob*)job)->statResult();
03912 bool bDir = false;
03913 bool bLink = false;
03914 KIO::filesize_t size = (KIO::filesize_t)-1;
03915 UDSEntry::ConstIterator it2 = entry.begin();
03916 int atomsFound(0);
03917 for( ; it2 != entry.end(); it2++ )
03918 {
03919 if ( ((*it2).m_uds) == UDS_FILE_TYPE )
03920 {
03921 bDir = S_ISDIR( (mode_t)(*it2).m_long );
03922 atomsFound++;
03923 }
03924 else if ( ((*it2).m_uds) == UDS_LINK_DEST )
03925 {
03926 bLink = !((*it2).m_str.isEmpty());
03927 atomsFound++;
03928 }
03929 else if ( ((*it2).m_uds) == UDS_SIZE )
03930 {
03931 size = (*it2).m_long;
03932 atomsFound++;
03933 };
03934 if (atomsFound==3) break;
03935 }
03936
03937 KURL url = ((SimpleJob*)job)->url();
03938
03939 subjobs.remove( job );
03940 assert( subjobs.isEmpty() );
03941
03942 if (bDir && !bLink)
03943 {
03944
03945 dirs.append( url );
03946 if ( url.isLocalFile() && !m_parentDirs.contains( url.path(-1) ) )
03947 m_parentDirs.append( url.path(-1) );
03948
03949
03950
03951 state = STATE_LISTING;
03952 ListJob *newjob = listRecursive( url, false );
03953 newjob->setUnrestricted(true);
03954 Scheduler::scheduleJob(newjob);
03955 connect(newjob, SIGNAL(entries( KIO::Job *,
03956 const KIO::UDSEntryList& )),
03957 SLOT( slotEntries( KIO::Job*,
03958 const KIO::UDSEntryList& )));
03959 addSubjob(newjob);
03960 }
03961 else
03962 {
03963 if ( bLink ) {
03964
03965 symlinks.append( url );
03966 } else {
03967
03968 files.append( url );
03969 }
03970 if ( url.isLocalFile() && !m_parentDirs.contains( url.directory(-1) ) )
03971 m_parentDirs.append( url.directory(-1) );
03972 ++m_currentStat;
03973 statNextSrc();
03974 }
03975 }
03976 break;
03977 case STATE_LISTING:
03978 if ( job->error() )
03979 {
03980
03981 }
03982 subjobs.remove( job );
03983 assert( subjobs.isEmpty() );
03984 ++m_currentStat;
03985 statNextSrc();
03986 break;
03987 case STATE_DELETING_FILES:
03988 if ( job->error() )
03989 {
03990 Job::slotResult( job );
03991 return;
03992 }
03993 subjobs.remove( job );
03994 assert( subjobs.isEmpty() );
03995 m_processedFiles++;
03996
03997 deleteNextFile();
03998 break;
03999 case STATE_DELETING_DIRS:
04000 if ( job->error() )
04001 {
04002 Job::slotResult( job );
04003 return;
04004 }
04005 subjobs.remove( job );
04006 assert( subjobs.isEmpty() );
04007 m_processedDirs++;
04008
04009
04010
04011
04012 deleteNextDir();
04013 break;
04014 default:
04015 assert(0);
04016 }
04017 }
04018
04019 DeleteJob *KIO::del( const KURL& src, bool shred, bool showProgressInfo )
04020 {
04021 KURL::List srcList;
04022 srcList.append( src );
04023 DeleteJob *job = new DeleteJob( srcList, shred, showProgressInfo );
04024 return job;
04025 }
04026
04027 DeleteJob *KIO::del( const KURL::List& src, bool shred, bool showProgressInfo )
04028 {
04029 DeleteJob *job = new DeleteJob( src, shred, showProgressInfo );
04030 return job;
04031 }
04032
04033 MultiGetJob::MultiGetJob(const KURL& url,
04034 bool showProgressInfo)
04035 : TransferJob(url, 0, QByteArray(), QByteArray(), showProgressInfo)
04036 {
04037 m_waitQueue.setAutoDelete(true);
04038 m_activeQueue.setAutoDelete(true);
04039 m_currentEntry = 0;
04040 }
04041
04042 void MultiGetJob::get(long id, const KURL &url, const MetaData &metaData)
04043 {
04044 GetRequest *entry = new GetRequest(id, url, metaData);
04045 entry->metaData["request-id"] = QString("%1").arg(id);
04046 m_waitQueue.append(entry);
04047 }
04048
04049 void MultiGetJob::flushQueue(QPtrList<GetRequest> &queue)
04050 {
04051 GetRequest *entry;
04052
04053
04054 for(entry = m_waitQueue.first(); entry; )
04055 {
04056 if ((m_url.protocol() == entry->url.protocol()) &&
04057 (m_url.host() == entry->url.host()) &&
04058 (m_url.port() == entry->url.port()) &&
04059 (m_url.user() == entry->url.user()))
04060 {
04061 m_waitQueue.take();
04062 queue.append(entry);
04063 entry = m_waitQueue.current();
04064 }
04065 else
04066 {
04067 entry = m_waitQueue.next();
04068 }
04069 }
04070
04071 KIO_ARGS << (Q_INT32) queue.count();
04072 for(entry = queue.first(); entry; entry = queue.next())
04073 {
04074 stream << entry->url << entry->metaData;
04075 }
04076 m_packedArgs = packedArgs;
04077 m_command = CMD_MULTI_GET;
04078 m_outgoingMetaData.clear();
04079 }
04080
04081 void MultiGetJob::start(Slave *slave)
04082 {
04083
04084 GetRequest *entry = m_waitQueue.take(0);
04085 m_activeQueue.append(entry);
04086
04087 m_url = entry->url;
04088
04089 if (!entry->url.protocol().startsWith("http"))
04090 {
04091
04092 KIO_ARGS << entry->url;
04093 m_packedArgs = packedArgs;
04094 m_outgoingMetaData = entry->metaData;
04095 m_command = CMD_GET;
04096 b_multiGetActive = false;
04097 }
04098 else
04099 {
04100 flushQueue(m_activeQueue);
04101 b_multiGetActive = true;
04102 }
04103
04104 TransferJob::start(slave);
04105 }
04106
04107 bool MultiGetJob::findCurrentEntry()
04108 {
04109 if (b_multiGetActive)
04110 {
04111 long id = m_incomingMetaData["request-id"].toLong();
04112 for(GetRequest *entry = m_activeQueue.first(); entry; entry = m_activeQueue.next())
04113 {
04114 if (entry->id == id)
04115 {
04116 m_currentEntry = entry;
04117 return true;
04118 }
04119 }
04120 m_currentEntry = 0;
04121 return false;
04122 }
04123 else
04124 {
04125 m_currentEntry = m_activeQueue.first();
04126 return (m_currentEntry != 0);
04127 }
04128 }
04129
04130 void MultiGetJob::slotRedirection( const KURL &url)
04131 {
04132 if (!findCurrentEntry()) return;
04133 if (!kapp->authorizeURLAction("redirect", m_url, url))
04134 {
04135 kdWarning(7007) << "MultiGetJob: Redirection from " << m_currentEntry->url << " to " << url << " REJECTED!" << endl;
04136 return;
04137 }
04138 m_redirectionURL = url;
04139 if (m_currentEntry->url.hasUser() && !url.hasUser() && (m_currentEntry->url.host().lower() == url.host().lower()))
04140 m_redirectionURL.setUser(m_currentEntry->url.user());
04141 get(m_currentEntry->id, m_redirectionURL, m_currentEntry->metaData);
04142 }
04143
04144
04145 void MultiGetJob::slotFinished()
04146 {
04147 if (!findCurrentEntry()) return;
04148 if (m_redirectionURL.isEmpty())
04149 {
04150
04151 emit result(m_currentEntry->id);
04152 }
04153 m_redirectionURL = KURL();
04154 m_error = 0;
04155 m_incomingMetaData.clear();
04156 m_activeQueue.removeRef(m_currentEntry);
04157 if (m_activeQueue.count() == 0)
04158 {
04159 if (m_waitQueue.count() == 0)
04160 {
04161
04162 TransferJob::slotFinished();
04163 }
04164 else
04165 {
04166
04167
04168
04169 GetRequest *entry = m_waitQueue.at(0);
04170 m_url = entry->url;
04171 slaveDone();
04172 Scheduler::doJob(this);
04173 }
04174 }
04175 }
04176
04177 void MultiGetJob::slotData( const QByteArray &_data)
04178 {
04179 if(!m_currentEntry) return;
04180 if(m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error)
04181 emit data(m_currentEntry->id, _data);
04182 }
04183
04184 void MultiGetJob::slotMimetype( const QString &_mimetype )
04185 {
04186 if (b_multiGetActive)
04187 {
04188 QPtrList<GetRequest> newQueue;
04189 flushQueue(newQueue);
04190 if (!newQueue.isEmpty())
04191 {
04192 while(!newQueue.isEmpty())
04193 m_activeQueue.append(newQueue.take(0));
04194 m_slave->send( m_command, m_packedArgs );
04195 }
04196 }
04197 if (!findCurrentEntry()) return;
04198 emit mimetype(m_currentEntry->id, _mimetype);
04199 }
04200
04201 MultiGetJob *KIO::multi_get(long id, const KURL &url, const MetaData &metaData)
04202 {
04203 MultiGetJob * job = new MultiGetJob( url, false );
04204 job->get(id, url, metaData);
04205 return job;
04206 }
04207
04208
04209 #ifdef CACHE_INFO
04210 CacheInfo::CacheInfo(const KURL &url)
04211 {
04212 m_url = url;
04213 }
04214
04215 QString CacheInfo::cachedFileName()
04216 {
04217 const QChar separator = '_';
04218
04219 QString CEF = m_url.path();
04220
04221 int p = CEF.find('/');
04222
04223 while(p != -1)
04224 {
04225 CEF[p] = separator;
04226 p = CEF.find('/', p);
04227 }
04228
04229 QString host = m_url.host().lower();
04230 CEF = host + CEF + '_';
04231
04232 QString dir = KProtocolManager::cacheDir();
04233 if (dir[dir.length()-1] != '/')
04234 dir += "/";
04235
04236 int l = m_url.host().length();
04237 for(int i = 0; i < l; i++)
04238 {
04239 if (host[i].isLetter() && (host[i] != 'w'))
04240 {
04241 dir += host[i];
04242 break;
04243 }
04244 }
04245 if (dir[dir.length()-1] == '/')
04246 dir += "0";
04247
04248 unsigned long hash = 0x00000000;
04249 QCString u = m_url.url().latin1();
04250 for(int i = u.length(); i--;)
04251 {
04252 hash = (hash * 12211 + u[i]) % 2147483563;
04253 }
04254
04255 QString hashString;
04256 hashString.sprintf("%08lx", hash);
04257
04258 CEF = CEF + hashString;
04259
04260 CEF = dir + "/" + CEF;
04261
04262 return CEF;
04263 }
04264
04265 QFile *CacheInfo::cachedFile()
04266 {
04267 const char *mode = (readWrite ? "r+" : "r");
04268
04269 FILE *fs = fopen( CEF.latin1(), mode);
04270 if (!fs)
04271 return 0;
04272
04273 char buffer[401];
04274 bool ok = true;
04275
04276
04277 if (ok && (!fgets(buffer, 400, fs)))
04278 ok = false;
04279 if (ok && (strcmp(buffer, CACHE_REVISION) != 0))
04280 ok = false;
04281
04282 time_t date;
04283 time_t currentDate = time(0);
04284
04285
04286 if (ok && (!fgets(buffer, 400, fs)))
04287 ok = false;
04288 if (ok)
04289 {
04290 int l = strlen(buffer);
04291 if (l>0)
04292 buffer[l-1] = 0;
04293 if (m_.url.url() != buffer)
04294 {
04295 ok = false;
04296 }
04297 }
04298
04299
04300 if (ok && (!fgets(buffer, 400, fs)))
04301 ok = false;
04302 if (ok)
04303 {
04304 date = (time_t) strtoul(buffer, 0, 10);
04305 if (m_maxCacheAge && (difftime(currentDate, date) > m_maxCacheAge))
04306 {
04307 m_bMustRevalidate = true;
04308 m_expireDate = currentDate;
04309 }
04310 }
04311
04312
04313 m_cacheExpireDateOffset = ftell(fs);
04314 if (ok && (!fgets(buffer, 400, fs)))
04315 ok = false;
04316 if (ok)
04317 {
04318 if (m_request.cache == CC_Verify)
04319 {
04320 date = (time_t) strtoul(buffer, 0, 10);
04321
04322 if (!date || difftime(currentDate, date) >= 0)
04323 m_bMustRevalidate = true;
04324 m_expireDate = date;
04325 }
04326 }
04327
04328
04329 if (ok && (!fgets(buffer, 400, fs)))
04330 ok = false;
04331 if (ok)
04332 {
04333 m_etag = QString(buffer).stripWhiteSpace();
04334 }
04335
04336
04337 if (ok && (!fgets(buffer, 400, fs)))
04338 ok = false;
04339 if (ok)
04340 {
04341 m_lastModified = QString(buffer).stripWhiteSpace();
04342 }
04343
04344 fclose(fs);
04345
04346 if (ok)
04347 return fs;
04348
04349 unlink( CEF.latin1());
04350 return 0;
04351
04352 }
04353
04354 void CacheInfo::flush()
04355 {
04356 cachedFile().remove();
04357 }
04358
04359 void CacheInfo::touch()
04360 {
04361
04362 }
04363 void CacheInfo::setExpireDate(int);
04364 void CacheInfo::setExpireTimeout(int);
04365
04366
04367 int CacheInfo::creationDate();
04368 int CacheInfo::expireDate();
04369 int CacheInfo::expireTimeout();
04370 #endif
04371
04372 void Job::virtual_hook( int, void* )
04373 { }
04374
04375 void SimpleJob::virtual_hook( int id, void* data )
04376 { KIO::Job::virtual_hook( id, data ); }
04377
04378 void MkdirJob::virtual_hook( int id, void* data )
04379 { SimpleJob::virtual_hook( id, data ); }
04380
04381 void StatJob::virtual_hook( int id, void* data )
04382 { SimpleJob::virtual_hook( id, data ); }
04383
04384 void TransferJob::virtual_hook( int id, void* data )
04385 { SimpleJob::virtual_hook( id, data ); }
04386
04387 void MultiGetJob::virtual_hook( int id, void* data )
04388 { TransferJob::virtual_hook( id, data ); }
04389
04390 void MimetypeJob::virtual_hook( int id, void* data )
04391 { TransferJob::virtual_hook( id, data ); }
04392
04393 void FileCopyJob::virtual_hook( int id, void* data )
04394 { Job::virtual_hook( id, data ); }
04395
04396 void ListJob::virtual_hook( int id, void* data )
04397 { SimpleJob::virtual_hook( id, data ); }
04398
04399 void CopyJob::virtual_hook( int id, void* data )
04400 { Job::virtual_hook( id, data ); }
04401
04402 void DeleteJob::virtual_hook( int id, void* data )
04403 { Job::virtual_hook( id, data ); }
04404
04405
04406 #include "jobclasses.moc"