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