00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "job.h"
00023 #include "job_p.h"
00024
00025 #include <config.h>
00026
00027 #include <sys/types.h>
00028 #include <sys/wait.h>
00029 #include <sys/stat.h>
00030
00031 #include <assert.h>
00032
00033 #include <signal.h>
00034 #include <stdlib.h>
00035 #include <stdio.h>
00036 #include <time.h>
00037 #include <unistd.h>
00038 extern "C" {
00039 #include <pwd.h>
00040 #include <grp.h>
00041 }
00042 #include <QtCore/QTimer>
00043 #include <QtCore/QFile>
00044
00045 #include <kapplication.h>
00046 #include <kauthorized.h>
00047 #include <kglobal.h>
00048 #include <klocale.h>
00049 #include <kconfig.h>
00050 #include <kdebug.h>
00051 #include <kde_file.h>
00052
00053 #include <errno.h>
00054
00055 #include "jobuidelegate.h"
00056 #include "kmimetype.h"
00057 #include "slave.h"
00058 #include "scheduler.h"
00059 #include "kdirwatch.h"
00060 #include "kprotocolinfo.h"
00061 #include "kprotocolmanager.h"
00062 #include "filejob.h"
00063
00064 #include "kssl/ksslcsessioncache.h"
00065
00066 #include <kdirnotify.h>
00067 #include <ktemporaryfile.h>
00068
00069 #ifdef Q_OS_UNIX
00070 #include <utime.h>
00071 #endif
00072
00073 using namespace KIO;
00074
00075 static inline Slave *jobSlave(SimpleJob *job)
00076 {
00077 return SimpleJobPrivate::get(job)->m_slave;
00078 }
00079
00080
00081 #define REPORT_TIMEOUT 200
00082
00083 #define KIO_ARGS QByteArray packedArgs; QDataStream stream( &packedArgs, QIODevice::WriteOnly ); stream
00084
00085 Job::Job() : KCompositeJob(*new JobPrivate, 0)
00086 {
00087 setCapabilities( KJob::Killable | KJob::Suspendable );
00088 }
00089
00090 Job::Job(JobPrivate &dd) : KCompositeJob(dd, 0)
00091 {
00092 setCapabilities( KJob::Killable | KJob::Suspendable );
00093 }
00094
00095 Job::~Job()
00096 {
00097 }
00098
00099 JobUiDelegate *Job::ui() const
00100 {
00101 return static_cast<JobUiDelegate*>( uiDelegate() );
00102 }
00103
00104 bool Job::addSubjob(KJob *jobBase)
00105 {
00106
00107
00108 bool ok = KCompositeJob::addSubjob( jobBase );
00109 KIO::Job *job = dynamic_cast<KIO::Job*>( jobBase );
00110 if (ok && job) {
00111
00112 Q_D(Job);
00113 job->mergeMetaData(d->m_outgoingMetaData);
00114
00115
00116 connect( job, SIGNAL(speed( KJob*, unsigned long )),
00117 SLOT(slotSpeed(KJob*, unsigned long)) );
00118
00119 if (ui() && job->ui()) {
00120 job->ui()->setWindow( ui()->window() );
00121 job->ui()->updateUserTimestamp( ui()->userTimestamp() );
00122 }
00123 }
00124 return ok;
00125 }
00126
00127 bool Job::removeSubjob( KJob *jobBase )
00128 {
00129
00130 return KCompositeJob::removeSubjob( jobBase );
00131 }
00132
00133 void JobPrivate::emitMoving(KIO::Job * job, const KUrl &src, const KUrl &dest)
00134 {
00135 emit job->description(job, i18nc("@title job","Moving"),
00136 qMakePair(i18n("Source"), src.prettyUrl()),
00137 qMakePair(i18n("Destination"), dest.prettyUrl()));
00138 }
00139
00140 void JobPrivate::emitCopying(KIO::Job * job, const KUrl &src, const KUrl &dest)
00141 {
00142 emit job->description(job, i18nc("@title job","Copying"),
00143 qMakePair(i18n("Source"), src.prettyUrl()),
00144 qMakePair(i18n("Destination"), dest.prettyUrl()));
00145 }
00146
00147 void JobPrivate::emitCreatingDir(KIO::Job * job, const KUrl &dir)
00148 {
00149 emit job->description(job, i18nc("@title job","Creating directory"),
00150 qMakePair(i18n("Directory"), dir.prettyUrl()));
00151 }
00152
00153 void JobPrivate::emitDeleting(KIO::Job *job, const KUrl &url)
00154 {
00155 emit job->description(job, i18nc("@title job","Deleting"),
00156 qMakePair(i18n("File"), url.prettyUrl()));
00157 }
00158
00159 void JobPrivate::emitStating(KIO::Job *job, const KUrl &url)
00160 {
00161 emit job->description(job, i18nc("@title job","Stating"),
00162 qMakePair(i18n("File"), url.prettyUrl()));
00163 }
00164
00165 void JobPrivate::emitTransferring(KIO::Job *job, const KUrl &url)
00166 {
00167 emit job->description(job, i18nc("@title job","Transferring"),
00168 qMakePair(i18n("Source"), url.prettyUrl()));
00169 }
00170
00171 void JobPrivate::emitMounting(KIO::Job * job, const QString &dev, const QString &point)
00172 {
00173 emit job->description(job, i18nc("@title job","Mounting"),
00174 qMakePair(i18n("Device"), dev),
00175 qMakePair(i18n("Mountpoint"), point));
00176 }
00177
00178 void JobPrivate::emitUnmounting(KIO::Job * job, const QString &point)
00179 {
00180 emit job->description(job, i18nc("@title job","Unmounting"),
00181 qMakePair(i18n("Mountpoint"), point));
00182 }
00183
00184 bool Job::doKill()
00185 {
00186 kDebug(7007) << "this=" << this << metaObject()->className();
00187
00188 const QList<KJob *> &jobs = subjobs();
00189 QList<KJob *>::const_iterator it = jobs.constBegin();
00190 const QList<KJob *>::const_iterator end = jobs.constEnd();
00191 for ( ; it != end ; ++it )
00192 (*it)->kill( KJob::Quietly );
00193 clearSubjobs();
00194
00195 return true;
00196 }
00197
00198 bool Job::doSuspend()
00199 {
00200 const QList<KJob *> &jobs = subjobs();
00201 QList<KJob *>::const_iterator it = jobs.constBegin();
00202 const QList<KJob *>::const_iterator end = jobs.constEnd();
00203 for ( ; it != end ; ++it )
00204 {
00205 if (!(*it)->suspend())
00206 return false;
00207 }
00208
00209 return true;
00210 }
00211
00212 bool Job::doResume()
00213 {
00214 const QList<KJob *> &jobs = subjobs();
00215 QList<KJob *>::const_iterator it = jobs.constBegin();
00216 const QList<KJob *>::const_iterator end = jobs.constEnd();
00217 for ( ; it != end ; ++it )
00218 {
00219 if (!(*it)->resume())
00220 return false;
00221 }
00222
00223 return true;
00224 }
00225
00226 void JobPrivate::slotSpeed( KJob*, unsigned long speed )
00227 {
00228
00229 q_func()->emitSpeed( speed );
00230 }
00231
00232
00233
00234 void Job::showErrorDialog( QWidget *parent )
00235 {
00236 if ( ui() )
00237 {
00238 ui()->setWindow( parent );
00239 ui()->showErrorMessage();
00240 }
00241 else
00242 {
00243 kError() << errorString();
00244 }
00245 }
00246
00247 bool Job::isInteractive() const
00248 {
00249 return uiDelegate() != 0;
00250 }
00251
00252 void Job::setParentJob(Job* job)
00253 {
00254 Q_D(Job);
00255 Q_ASSERT(d->m_parentJob == 0L);
00256 Q_ASSERT(job);
00257 d->m_parentJob = job;
00258 }
00259
00260 Job* Job::parentJob() const
00261 {
00262 return d_func()->m_parentJob;
00263 }
00264
00265 MetaData Job::metaData() const
00266 {
00267 return d_func()->m_incomingMetaData;
00268 }
00269
00270 QString Job::queryMetaData(const QString &key)
00271 {
00272 return d_func()->m_incomingMetaData.value(key, QString());
00273 }
00274
00275 void Job::setMetaData( const KIO::MetaData &_metaData)
00276 {
00277 Q_D(Job);
00278 d->m_outgoingMetaData = _metaData;
00279 }
00280
00281 void Job::addMetaData( const QString &key, const QString &value)
00282 {
00283 d_func()->m_outgoingMetaData.insert(key, value);
00284 }
00285
00286 void Job::addMetaData( const QMap<QString,QString> &values)
00287 {
00288 Q_D(Job);
00289 QMap<QString,QString>::const_iterator it = values.begin();
00290 for(;it != values.end(); ++it)
00291 d->m_outgoingMetaData.insert(it.key(), it.value());
00292 }
00293
00294 void Job::mergeMetaData( const QMap<QString,QString> &values)
00295 {
00296 Q_D(Job);
00297 QMap<QString,QString>::const_iterator it = values.begin();
00298 for(;it != values.end(); ++it)
00299
00300 if ( !d->m_outgoingMetaData.contains( it.key() ) )
00301 d->m_outgoingMetaData.insert( it.key(), it.value() );
00302 }
00303
00304 MetaData Job::outgoingMetaData() const
00305 {
00306 return d_func()->m_outgoingMetaData;
00307 }
00308
00309 SimpleJob::SimpleJob(SimpleJobPrivate &dd)
00310 : Job(dd)
00311 {
00312 d_func()->simpleJobInit();
00313 }
00314
00315 void SimpleJobPrivate::simpleJobInit()
00316 {
00317 Q_Q(SimpleJob);
00318 if (!m_url.isValid())
00319 {
00320 q->setError( ERR_MALFORMED_URL );
00321 q->setErrorText( m_url.url() );
00322 QTimer::singleShot(0, q, SLOT(slotFinished()) );
00323 return;
00324 }
00325
00326 Scheduler::doJob(q);
00327 }
00328
00329
00330 bool SimpleJob::doKill()
00331 {
00332 Q_D(SimpleJob);
00333 Scheduler::cancelJob( this );
00334 d->m_slave = 0;
00335 return Job::doKill();
00336 }
00337
00338 bool SimpleJob::doSuspend()
00339 {
00340 Q_D(SimpleJob);
00341 if ( d->m_slave )
00342 d->m_slave->suspend();
00343 return Job::doSuspend();
00344 }
00345
00346 bool SimpleJob::doResume()
00347 {
00348 Q_D(SimpleJob);
00349 if ( d->m_slave )
00350 d->m_slave->resume();
00351 return Job::doResume();
00352 }
00353
00354 const KUrl& SimpleJob::url() const
00355 {
00356 return d_func()->m_url;
00357 }
00358
00359 void SimpleJob::putOnHold()
00360 {
00361 Q_D(SimpleJob);
00362 Q_ASSERT( d->m_slave );
00363 if ( d->m_slave )
00364 {
00365 Scheduler::putSlaveOnHold(this, d->m_url);
00366 d->m_slave = 0;
00367 }
00368 kill( Quietly );
00369 }
00370
00371 void SimpleJob::removeOnHold()
00372 {
00373 Scheduler::removeSlaveOnHold();
00374 }
00375
00376 SimpleJob::~SimpleJob()
00377 {
00378 Q_D(SimpleJob);
00379 if (d->m_slave)
00380 {
00381 kDebug(7007) << "Killing running job in destructor!" << kBacktrace();
00382 #if 0
00383 d->m_slave->kill();
00384 Scheduler::jobFinished( this, d->m_slave );
00385 #endif
00386 d->m_slave = 0;
00387 }
00388 Scheduler::cancelJob( this );
00389 }
00390
00391 void SimpleJobPrivate::start(Slave *slave)
00392 {
00393 Q_Q(SimpleJob);
00394 m_slave = slave;
00395
00396 q->connect( slave, SIGNAL( error( int , const QString & ) ),
00397 SLOT( slotError( int , const QString & ) ) );
00398
00399 q->connect( slave, SIGNAL( warning( const QString & ) ),
00400 SLOT( slotWarning( const QString & ) ) );
00401
00402 q->connect( slave, SIGNAL( infoMessage( const QString & ) ),
00403 SLOT( _k_slotSlaveInfoMessage( const QString & ) ) );
00404
00405 q->connect( slave, SIGNAL( connected() ),
00406 SLOT( slotConnected() ) );
00407
00408 q->connect( slave, SIGNAL( finished() ),
00409 SLOT( slotFinished() ) );
00410
00411 if ((m_extraFlags & EF_TransferJobDataSent) == 0)
00412 {
00413 q->connect( slave, SIGNAL( totalSize( KIO::filesize_t ) ),
00414 SLOT( slotTotalSize( KIO::filesize_t ) ) );
00415
00416 q->connect( slave, SIGNAL( processedSize( KIO::filesize_t ) ),
00417 SLOT( slotProcessedSize( KIO::filesize_t ) ) );
00418
00419 q->connect( slave, SIGNAL( speed( unsigned long ) ),
00420 SLOT( slotSpeed( unsigned long ) ) );
00421 }
00422 q->connect( slave, SIGNAL(metaData( const KIO::MetaData& ) ),
00423 SLOT( slotMetaData( const KIO::MetaData& ) ) );
00424
00425 if (ui() && ui()->window())
00426 {
00427 m_outgoingMetaData.insert("window-id", QString::number((long)ui()->window()->winId()));
00428 }
00429
00430 if (ui() && ui()->userTimestamp())
00431 {
00432 m_outgoingMetaData.insert("user-timestamp", QString::number(ui()->userTimestamp()));
00433 }
00434
00435 QString sslSession = KSSLCSessionCache::getSessionForUrl(m_url);
00436 if ( !sslSession.isNull() )
00437 {
00438 m_outgoingMetaData.insert("ssl_session_id", sslSession);
00439 }
00440
00441 if (ui() == 0)
00442 {
00443 m_outgoingMetaData.insert("no-auth-prompt", "true");
00444 }
00445
00446 if (!m_outgoingMetaData.isEmpty())
00447 {
00448 KIO_ARGS << m_outgoingMetaData;
00449 slave->send( CMD_META_DATA, packedArgs );
00450 }
00451
00452 if (!m_subUrl.isEmpty())
00453 {
00454 KIO_ARGS << m_subUrl;
00455 slave->send( CMD_SUBURL, packedArgs );
00456 }
00457
00458 slave->send( m_command, m_packedArgs );
00459 }
00460
00461 void SimpleJobPrivate::slaveDone()
00462 {
00463 Q_Q(SimpleJob);
00464 if (!m_slave) return;
00465 if (m_command == CMD_OPEN) m_slave->send(CMD_CLOSE);
00466 q->disconnect(m_slave);
00467 Scheduler::jobFinished( q, m_slave );
00468 m_slave = 0;
00469 }
00470
00471 void SimpleJob::slotFinished( )
00472 {
00473 Q_D(SimpleJob);
00474
00475 d->slaveDone();
00476
00477 if (!hasSubjobs())
00478 {
00479 if ( !error() && (d->m_command == CMD_MKDIR || d->m_command == CMD_RENAME ) )
00480 {
00481 if ( d->m_command == CMD_MKDIR )
00482 {
00483 KUrl urlDir( url() );
00484 urlDir.setPath( urlDir.directory() );
00485 org::kde::KDirNotify::emitFilesAdded( urlDir.url() );
00486 }
00487 else
00488 {
00489 KUrl src, dst;
00490 QDataStream str( d->m_packedArgs );
00491 str >> src >> dst;
00492 if( src.directory() == dst.directory() )
00493 org::kde::KDirNotify::emitFileRenamed( src.url(), dst.url() );
00494
00495 org::kde::KDirNotify::emitFileMoved( src.url(), dst.url() );
00496 }
00497 }
00498 emitResult();
00499 }
00500 }
00501
00502 void SimpleJob::slotError( int err, const QString & errorText )
00503 {
00504 Q_D(SimpleJob);
00505 setError( err );
00506 setErrorText( errorText );
00507 if ((error() == ERR_UNKNOWN_HOST) && d->m_url.host().isEmpty())
00508 setErrorText( QString() );
00509
00510 slotFinished();
00511 }
00512
00513 void SimpleJob::slotWarning( const QString & errorText )
00514 {
00515 emit warning( this, errorText );
00516 }
00517
00518 void SimpleJobPrivate::_k_slotSlaveInfoMessage( const QString & msg )
00519 {
00520 emit q_func()->infoMessage( q_func(), msg );
00521 }
00522
00523 void SimpleJobPrivate::slotConnected()
00524 {
00525 emit q_func()->connected( q_func() );
00526 }
00527
00528 void SimpleJobPrivate::slotTotalSize( KIO::filesize_t size )
00529 {
00530 Q_Q(SimpleJob);
00531 if (size > q->totalAmount(KJob::Bytes))
00532 {
00533 q->setTotalAmount(KJob::Bytes, size);
00534 }
00535 }
00536
00537 void SimpleJobPrivate::slotProcessedSize( KIO::filesize_t size )
00538 {
00539 Q_Q(SimpleJob);
00540
00541 q->setProcessedAmount(KJob::Bytes, size);
00542 }
00543
00544 void SimpleJobPrivate::slotSpeed( unsigned long speed )
00545 {
00546
00547 q_func()->emitSpeed( speed );
00548 }
00549
00550 void SimpleJob::slotMetaData( const KIO::MetaData &_metaData )
00551 {
00552 Q_D(SimpleJob);
00553 d->m_incomingMetaData += _metaData;
00554 }
00555
00556 void SimpleJob::storeSSLSessionFromJob(const KUrl &redirectionURL)
00557 {
00558 Q_D(SimpleJob);
00559 QString sslSession = queryMetaData("ssl_session_id");
00560
00561 if ( !sslSession.isNull() ) {
00562 const KUrl &queryURL = redirectionURL.isEmpty() ? d->m_url : redirectionURL;
00563 KSSLCSessionCache::putSessionForUrl(queryURL, sslSession);
00564 }
00565 }
00566
00568 class KIO::MkdirJobPrivate: public SimpleJobPrivate
00569 {
00570 public:
00571 MkdirJobPrivate(const KUrl& url, int command, const QByteArray &packedArgs)
00572 : SimpleJobPrivate(url, command, packedArgs)
00573 { }
00574 KUrl m_redirectionURL;
00575 void slotRedirection(const KUrl &url);
00576
00583 virtual void start( Slave *slave );
00584
00585 Q_DECLARE_PUBLIC(MkdirJob)
00586
00587 static inline MkdirJob *newJob(const KUrl& url, int command, const QByteArray &packedArgs)
00588 {
00589 MkdirJob *job = new MkdirJob(*new MkdirJobPrivate(url, command, packedArgs));
00590 job->setUiDelegate(new JobUiDelegate);
00591 return job;
00592 }
00593 };
00594
00595 MkdirJob::MkdirJob(MkdirJobPrivate &dd)
00596 : SimpleJob(dd)
00597 {
00598 }
00599
00600 MkdirJob::~MkdirJob()
00601 {
00602 }
00603
00604 void MkdirJobPrivate::start(Slave *slave)
00605 {
00606 Q_Q(MkdirJob);
00607 q->connect( slave, SIGNAL( redirection(const KUrl &) ),
00608 SLOT( slotRedirection(const KUrl &) ) );
00609
00610 SimpleJobPrivate::start(slave);
00611 }
00612
00613
00614 void MkdirJobPrivate::slotRedirection( const KUrl &url)
00615 {
00616 Q_Q(MkdirJob);
00617 kDebug(7007) << url;
00618 if (!KAuthorized::authorizeUrlAction("redirect", m_url, url))
00619 {
00620 kWarning(7007) << "Redirection from" << m_url << "to" << url << "REJECTED!";
00621 q->setError( ERR_ACCESS_DENIED );
00622 q->setErrorText( url.prettyUrl() );
00623 return;
00624 }
00625 m_redirectionURL = url;
00626 if (m_url.hasUser() && !url.hasUser() && (m_url.host().toLower() == url.host().toLower()))
00627 m_redirectionURL.setUser(m_url.user());
00628
00629 emit q->redirection(q, m_redirectionURL);
00630 }
00631
00632 void MkdirJob::slotFinished()
00633 {
00634 Q_D(MkdirJob);
00635 if ( d->m_redirectionURL.isEmpty() || !d->m_redirectionURL.isValid())
00636 {
00637
00638 SimpleJob::slotFinished();
00639 } else {
00640
00641 if (queryMetaData("permanent-redirect")=="true")
00642 emit permanentRedirection(this, d->m_url, d->m_redirectionURL);
00643 KUrl dummyUrl;
00644 int permissions;
00645 QDataStream istream( d->m_packedArgs );
00646 istream >> dummyUrl >> permissions;
00647
00648 d->m_url = d->m_redirectionURL;
00649 d->m_redirectionURL = KUrl();
00650 d->m_packedArgs.truncate(0);
00651 QDataStream stream( &d->m_packedArgs, QIODevice::WriteOnly );
00652 stream << d->m_url << permissions;
00653
00654
00655 d->slaveDone();
00656 Scheduler::doJob(this);
00657 }
00658 }
00659
00660 SimpleJob *KIO::mkdir( const KUrl& url, int permissions )
00661 {
00662
00663 KIO_ARGS << url << permissions;
00664 return MkdirJobPrivate::newJob(url, CMD_MKDIR, packedArgs);
00665 }
00666
00667 SimpleJob *KIO::rmdir( const KUrl& url )
00668 {
00669
00670 KIO_ARGS << url << qint8(false);
00671 return SimpleJobPrivate::newJob(url, CMD_DEL, packedArgs);
00672 }
00673
00674 SimpleJob *KIO::chmod( const KUrl& url, int permissions )
00675 {
00676
00677 KIO_ARGS << url << permissions;
00678 return SimpleJobPrivate::newJob(url, CMD_CHMOD, packedArgs);
00679 }
00680
00681 SimpleJob *KIO::chown( const KUrl& url, const QString& owner, const QString& group )
00682 {
00683 KIO_ARGS << url << owner << group;
00684 return SimpleJobPrivate::newJob(url, CMD_CHOWN, packedArgs);
00685 }
00686
00687 SimpleJob *KIO::setModificationTime( const KUrl& url, const QDateTime& mtime )
00688 {
00689
00690 KIO_ARGS << url << mtime;
00691 return SimpleJobPrivate::newJobNoUi(url, CMD_SETMODIFICATIONTIME, packedArgs);
00692 }
00693
00694 SimpleJob *KIO::rename( const KUrl& src, const KUrl & dest, JobFlags flags )
00695 {
00696
00697 KIO_ARGS << src << dest << (qint8) (flags & Overwrite);
00698 return SimpleJobPrivate::newJob(src, CMD_RENAME, packedArgs);
00699 }
00700
00701 SimpleJob *KIO::symlink( const QString& target, const KUrl & dest, JobFlags flags )
00702 {
00703
00704 KIO_ARGS << target << dest << (qint8) (flags & Overwrite);
00705 return SimpleJobPrivate::newJob(dest, CMD_SYMLINK, packedArgs, flags);
00706 }
00707
00708 SimpleJob *KIO::special(const KUrl& url, const QByteArray & data, JobFlags flags)
00709 {
00710
00711 return SimpleJobPrivate::newJob(url, CMD_SPECIAL, data, flags);
00712 }
00713
00714 SimpleJob *KIO::mount( bool ro, const QByteArray& fstype, const QString& dev, const QString& point, JobFlags flags )
00715 {
00716 KIO_ARGS << int(1) << qint8( ro ? 1 : 0 )
00717 << QString::fromLatin1(fstype) << dev << point;
00718 SimpleJob *job = special( KUrl("file:/"), packedArgs, flags );
00719 if (!(flags & HideProgressInfo)) {
00720 KIO::JobPrivate::emitMounting(job, dev, point);
00721 }
00722 return job;
00723 }
00724
00725 SimpleJob *KIO::unmount( const QString& point, JobFlags flags )
00726 {
00727 KIO_ARGS << int(2) << point;
00728 SimpleJob *job = special( KUrl("file:/"), packedArgs, flags );
00729 if (!(flags & HideProgressInfo)) {
00730 KIO::JobPrivate::emitUnmounting(job, point);
00731 }
00732 return job;
00733 }
00734
00735
00736
00738
00739 class KIO::StatJobPrivate: public SimpleJobPrivate
00740 {
00741 public:
00742 inline StatJobPrivate(const KUrl& url, int command, const QByteArray &packedArgs)
00743 : SimpleJobPrivate(url, command, packedArgs), m_bSource(true), m_details(2)
00744 {}
00745
00746 UDSEntry m_statResult;
00747 KUrl m_redirectionURL;
00748 bool m_bSource;
00749 short int m_details;
00750 void slotStatEntry( const KIO::UDSEntry & entry );
00751 void slotRedirection( const KUrl &url);
00752
00759 virtual void start( Slave *slave );
00760
00761 Q_DECLARE_PUBLIC(StatJob)
00762
00763 static inline StatJob *newJob(const KUrl& url, int command, const QByteArray &packedArgs,
00764 JobFlags flags )
00765 {
00766 StatJob *job = new StatJob(*new StatJobPrivate(url, command, packedArgs));
00767 job->setUiDelegate(new JobUiDelegate);
00768 if (!(flags & HideProgressInfo)) {
00769 KIO::getJobTracker()->registerJob(job);
00770 emitStating(job, url);
00771 }
00772 return job;
00773 }
00774 };
00775
00776 StatJob::StatJob(StatJobPrivate &dd)
00777 : SimpleJob(dd)
00778 {
00779 }
00780
00781 StatJob::~StatJob()
00782 {
00783 }
00784
00785 void StatJob::setSide( bool source )
00786 {
00787 d_func()->m_bSource = source;
00788 }
00789
00790 void StatJob::setSide( StatSide side )
00791 {
00792 d_func()->m_bSource = side == SourceSide;
00793 }
00794
00795 void StatJob::setDetails( short int details )
00796 {
00797 d_func()->m_details = details;
00798 }
00799
00800 const UDSEntry & StatJob::statResult() const
00801 {
00802 return d_func()->m_statResult;
00803 }
00804
00805 void StatJobPrivate::start(Slave *slave)
00806 {
00807 Q_Q(StatJob);
00808 m_outgoingMetaData.insert( "statSide", m_bSource ? "source" : "dest" );
00809 m_outgoingMetaData.insert( "details", QString::number(m_details) );
00810
00811 q->connect( slave, SIGNAL( statEntry( const KIO::UDSEntry& ) ),
00812 SLOT( slotStatEntry( const KIO::UDSEntry & ) ) );
00813 q->connect( slave, SIGNAL( redirection(const KUrl &) ),
00814 SLOT( slotRedirection(const KUrl &) ) );
00815
00816 SimpleJobPrivate::start(slave);
00817 }
00818
00819 void StatJobPrivate::slotStatEntry( const KIO::UDSEntry & entry )
00820 {
00821
00822 m_statResult = entry;
00823 }
00824
00825
00826 void StatJobPrivate::slotRedirection( const KUrl &url)
00827 {
00828 Q_Q(StatJob);
00829 kDebug(7007) << url;
00830 if (!KAuthorized::authorizeUrlAction("redirect", m_url, url))
00831 {
00832 kWarning(7007) << "Redirection from " << m_url << " to " << url << " REJECTED!";
00833 q->setError( ERR_ACCESS_DENIED );
00834 q->setErrorText( url.prettyUrl() );
00835 return;
00836 }
00837 m_redirectionURL = url;
00838 if (m_url.hasUser() && !url.hasUser() && (m_url.host().toLower() == url.host().toLower()))
00839 m_redirectionURL.setUser(m_url.user());
00840
00841 emit q->redirection(q, m_redirectionURL);
00842 }
00843
00844 void StatJob::slotFinished()
00845 {
00846 Q_D(StatJob);
00847 if ( d->m_redirectionURL.isEmpty() || !d->m_redirectionURL.isValid())
00848 {
00849
00850 SimpleJob::slotFinished();
00851 } else {
00852
00853 if (queryMetaData("permanent-redirect")=="true")
00854 emit permanentRedirection(this, d->m_url, d->m_redirectionURL);
00855 d->m_url = d->m_redirectionURL;
00856 d->m_redirectionURL = KUrl();
00857 d->m_packedArgs.truncate(0);
00858 QDataStream stream( &d->m_packedArgs, QIODevice::WriteOnly );
00859 stream << d->m_url;
00860
00861
00862 d->slaveDone();
00863 Scheduler::doJob(this);
00864 }
00865 }
00866
00867 void StatJob::slotMetaData( const KIO::MetaData &_metaData)
00868 {
00869 Q_D(StatJob);
00870 SimpleJob::slotMetaData(_metaData);
00871 storeSSLSessionFromJob(d->m_redirectionURL);
00872 }
00873
00874 StatJob *KIO::stat(const KUrl& url, JobFlags flags)
00875 {
00876
00877 return stat( url, StatJob::SourceSide, 2, flags );
00878 }
00879
00880 StatJob *KIO::stat(const KUrl& url, bool sideIsSource, short int details, JobFlags flags )
00881 {
00882
00883 KIO_ARGS << url;
00884 StatJob * job = StatJobPrivate::newJob(url, CMD_STAT, packedArgs, flags);
00885 job->setSide( sideIsSource ? StatJob::SourceSide : StatJob::DestinationSide );
00886 job->setDetails( details );
00887 return job;
00888 }
00889
00890 StatJob *KIO::stat(const KUrl& url, KIO::StatJob::StatSide side, short int details, JobFlags flags )
00891 {
00892
00893 KIO_ARGS << url;
00894 StatJob * job = StatJobPrivate::newJob(url, CMD_STAT, packedArgs, flags);
00895 job->setSide( side );
00896 job->setDetails( details );
00897 return job;
00898 }
00899
00900 SimpleJob *KIO::http_update_cache( const KUrl& url, bool no_cache, time_t expireDate)
00901 {
00902 assert( (url.protocol() == "http") || (url.protocol() == "https") );
00903
00904 KIO_ARGS << (int)2 << url << no_cache << qlonglong(expireDate);
00905 SimpleJob * job = SimpleJobPrivate::newJob(url, CMD_SPECIAL, packedArgs);
00906 job->setUiDelegate(new JobUiDelegate());
00907 Scheduler::scheduleJob(job);
00908 return job;
00909 }
00910
00912
00913 TransferJob::TransferJob(TransferJobPrivate &dd)
00914 : SimpleJob(dd)
00915 {
00916 }
00917
00918 TransferJob::~TransferJob()
00919 {
00920 }
00921
00922
00923 void TransferJob::slotData( const QByteArray &_data)
00924 {
00925 Q_D(TransferJob);
00926 if(d->m_redirectionURL.isEmpty() || !d->m_redirectionURL.isValid() || error())
00927 emit data( this, _data);
00928 }
00929
00930
00931 void TransferJob::slotRedirection( const KUrl &url)
00932 {
00933 Q_D(TransferJob);
00934 kDebug(7007) << url;
00935 if (!KAuthorized::authorizeUrlAction("redirect", d->m_url, url))
00936 {
00937 kWarning(7007) << "Redirection from " << d->m_url << " to " << url << " REJECTED!";
00938 return;
00939 }
00940
00941
00942
00943
00944 if (d->m_redirectionList.count(url) > 5)
00945 {
00946 kDebug(7007) << "CYCLIC REDIRECTION!";
00947 setError( ERR_CYCLIC_LINK );
00948 setErrorText( d->m_url.prettyUrl() );
00949 }
00950 else
00951 {
00952 d->m_redirectionURL = url;
00953 if (d->m_url.hasUser() && !url.hasUser() && (d->m_url.host().toLower() == url.host().toLower()))
00954 d->m_redirectionURL.setUser(d->m_url.user());
00955 d->m_redirectionList.append(url);
00956 d->m_outgoingMetaData["ssl_was_in_use"] = d->m_incomingMetaData["ssl_in_use"];
00957
00958 emit redirection(this, d->m_redirectionURL);
00959 }
00960 }
00961
00962 void TransferJob::slotFinished()
00963 {
00964 Q_D(TransferJob);
00965
00966 if (d->m_redirectionURL.isEmpty() || !d->m_redirectionURL.isValid())
00967 SimpleJob::slotFinished();
00968 else {
00969
00970 if (queryMetaData("permanent-redirect")=="true")
00971 emit permanentRedirection(this, d->m_url, d->m_redirectionURL);
00972
00973
00974
00975
00976 d->staticData.truncate(0);
00977 d->m_incomingMetaData.clear();
00978 if (queryMetaData("cache") != "reload")
00979 addMetaData("cache","refresh");
00980 d->m_internalSuspended = false;
00981 d->m_url = d->m_redirectionURL;
00982 d->m_redirectionURL = KUrl();
00983
00984 QString dummyStr;
00985 KUrl dummyUrl;
00986 QDataStream istream( d->m_packedArgs );
00987 switch( d->m_command ) {
00988 case CMD_GET: {
00989 d->m_packedArgs.truncate(0);
00990 QDataStream stream( &d->m_packedArgs, QIODevice::WriteOnly );
00991 stream << d->m_url;
00992 break;
00993 }
00994 case CMD_PUT: {
00995 int permissions;
00996 qint8 iOverwrite, iResume;
00997 istream >> dummyUrl >> iOverwrite >> iResume >> permissions;
00998 d->m_packedArgs.truncate(0);
00999 QDataStream stream( &d->m_packedArgs, QIODevice::WriteOnly );
01000 stream << d->m_url << iOverwrite << iResume << permissions;
01001 break;
01002 }
01003 case CMD_SPECIAL: {
01004 int specialcmd;
01005 istream >> specialcmd;
01006 if (specialcmd == 1)
01007 {
01008 addMetaData("cache","reload");
01009 d->m_packedArgs.truncate(0);
01010 QDataStream stream( &d->m_packedArgs, QIODevice::WriteOnly );
01011 stream << d->m_url;
01012 d->m_command = CMD_GET;
01013 }
01014 break;
01015 }
01016 }
01017
01018
01019 d->slaveDone();
01020 Scheduler::doJob(this);
01021 }
01022 }
01023
01024 void TransferJob::setAsyncDataEnabled(bool enabled)
01025 {
01026 Q_D(TransferJob);
01027 if (enabled)
01028 d->m_extraFlags |= JobPrivate::EF_TransferJobAsync;
01029 else
01030 d->m_extraFlags &= ~JobPrivate::EF_TransferJobAsync;
01031 }
01032
01033 void TransferJob::sendAsyncData(const QByteArray &dataForSlave)
01034 {
01035 Q_D(TransferJob);
01036 if (d->m_extraFlags & JobPrivate::EF_TransferJobNeedData)
01037 {
01038 d->m_slave->send( MSG_DATA, dataForSlave );
01039 if (d->m_extraFlags & JobPrivate::EF_TransferJobDataSent)
01040 {
01041 KIO::filesize_t size = processedAmount(KJob::Bytes)+dataForSlave.size();
01042 setProcessedAmount(KJob::Bytes, size);
01043 }
01044 }
01045
01046 d->m_extraFlags &= ~JobPrivate::EF_TransferJobNeedData;
01047 }
01048
01049 void TransferJob::setReportDataSent(bool enabled)
01050 {
01051 Q_D(TransferJob);
01052 if (enabled)
01053 d->m_extraFlags |= JobPrivate::EF_TransferJobDataSent;
01054 else
01055 d->m_extraFlags &= ~JobPrivate::EF_TransferJobDataSent;
01056 }
01057
01058 bool TransferJob::reportDataSent() const
01059 {
01060 return (d_func()->m_extraFlags & JobPrivate::EF_TransferJobDataSent);
01061 }
01062
01063 QString TransferJob::mimetype() const
01064 {
01065 return d_func()->m_mimetype;
01066 }
01067
01068
01069
01070 void TransferJob::slotDataReq()
01071 {
01072 Q_D(TransferJob);
01073 QByteArray dataForSlave;
01074
01075 d->m_extraFlags |= JobPrivate::EF_TransferJobNeedData;
01076
01077 if (!d->staticData.isEmpty())
01078 {
01079 dataForSlave = d->staticData;
01080 d->staticData.clear();
01081 }
01082 else
01083 {
01084 emit dataReq( this, dataForSlave);
01085
01086 if (d->m_extraFlags & JobPrivate::EF_TransferJobAsync)
01087 return;
01088 }
01089
01090 static const int max_size = 14 * 1024 * 1024;
01091 if (dataForSlave.size() > max_size)
01092 {
01093 kDebug(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 d->staticData = QByteArray(dataForSlave.data() + max_size , dataForSlave.size() - max_size);
01095 dataForSlave.truncate(max_size);
01096 }
01097
01098 sendAsyncData(dataForSlave);
01099
01100 if (d->m_subJob)
01101 {
01102
01103 d->internalSuspend();
01104 d->m_subJob->d_func()->internalResume();
01105 }
01106 }
01107
01108 void TransferJob::slotMimetype( const QString& type )
01109 {
01110 Q_D(TransferJob);
01111 d->m_mimetype = type;
01112 emit mimetype( this, type );
01113 }
01114
01115
01116 void TransferJobPrivate::internalSuspend()
01117 {
01118 m_internalSuspended = true;
01119 if (m_slave)
01120 m_slave->suspend();
01121 }
01122
01123 void TransferJobPrivate::internalResume()
01124 {
01125 m_internalSuspended = false;
01126 if ( m_slave && !suspended )
01127 m_slave->resume();
01128 }
01129
01130 bool TransferJob::doResume()
01131 {
01132 Q_D(TransferJob);
01133 if ( !SimpleJob::doResume() )
01134 return false;
01135 if ( d->m_internalSuspended )
01136 d->internalSuspend();
01137 return true;
01138 }
01139
01140 bool TransferJob::isErrorPage() const
01141 {
01142 return d_func()->m_errorPage;
01143 }
01144
01145 void TransferJobPrivate::start(Slave *slave)
01146 {
01147 Q_Q(TransferJob);
01148 assert(slave);
01149 JobPrivate::emitTransferring(q, m_url);
01150 q->connect( slave, SIGNAL( data( const QByteArray & ) ),
01151 SLOT( slotData( const QByteArray & ) ) );
01152
01153 q->connect( slave, SIGNAL( dataReq() ),
01154 SLOT( slotDataReq() ) );
01155
01156 q->connect( slave, SIGNAL( redirection(const KUrl &) ),
01157 SLOT( slotRedirection(const KUrl &) ) );
01158
01159 q->connect( slave, SIGNAL(mimeType( const QString& ) ),
01160 SLOT( slotMimetype( const QString& ) ) );
01161
01162 q->connect( slave, SIGNAL(errorPage() ),
01163 SLOT( slotErrorPage() ) );
01164
01165 q->connect( slave, SIGNAL( needSubUrlData() ),
01166 SLOT( slotNeedSubUrlData() ) );
01167
01168 q->connect( slave, SIGNAL(canResume( KIO::filesize_t ) ),
01169 SLOT( slotCanResume( KIO::filesize_t ) ) );
01170
01171 if (slave->suspended())
01172 {
01173 m_mimetype = "unknown";
01174
01175 slave->resume();
01176 }
01177
01178 SimpleJobPrivate::start(slave);
01179 if (m_internalSuspended)
01180 slave->suspend();
01181 }
01182
01183 void TransferJobPrivate::slotNeedSubUrlData()
01184 {
01185 Q_Q(TransferJob);
01186
01187 m_subJob = KIO::get( m_subUrl, NoReload, HideProgressInfo);
01188 internalSuspend();
01189 q->connect(m_subJob, SIGNAL( data(KIO::Job*,const QByteArray &)),
01190 SLOT( slotSubUrlData(KIO::Job*,const QByteArray &)));
01191 q->addSubjob(m_subJob);
01192 }
01193
01194 void TransferJobPrivate::slotSubUrlData(KIO::Job*, const QByteArray &data)
01195 {
01196
01197 staticData = data;
01198 m_subJob->d_func()->internalSuspend();
01199 internalResume();
01200 }
01201
01202 void TransferJob::slotMetaData( const KIO::MetaData &_metaData)
01203 {
01204 Q_D(TransferJob);
01205 SimpleJob::slotMetaData(_metaData);
01206 storeSSLSessionFromJob(d->m_redirectionURL);
01207 }
01208
01209 void TransferJobPrivate::slotErrorPage()
01210 {
01211 m_errorPage = true;
01212 }
01213
01214 void TransferJobPrivate::slotCanResume( KIO::filesize_t offset )
01215 {
01216 Q_Q(TransferJob);
01217 emit q->canResume(q, offset);
01218 }
01219
01220 void TransferJob::slotResult( KJob *job)
01221 {
01222 Q_D(TransferJob);
01223
01224 assert(job == d->m_subJob);
01225
01226 SimpleJob::slotResult( job );
01227
01228 if (!error() && job == d->m_subJob)
01229 {
01230 d->m_subJob = 0;
01231 d->internalResume();
01232 }
01233 }
01234
01235 void TransferJob::setModificationTime( const QDateTime& mtime )
01236 {
01237 addMetaData( "modified", mtime.toString( Qt::ISODate ) );
01238 }
01239
01240 TransferJob *KIO::get( const KUrl& url, LoadType reload, JobFlags flags )
01241 {
01242
01243 KIO_ARGS << url;
01244 TransferJob * job = TransferJobPrivate::newJob(url, CMD_GET, packedArgs,
01245 QByteArray(), flags);
01246 if (reload == Reload)
01247 job->addMetaData("cache", "reload");
01248 return job;
01249 }
01250
01251 namespace KIO {
01252 class PostErrorJob : public TransferJob
01253 {
01254 public:
01255
01256 PostErrorJob(int _error, const QString& url, const QByteArray &packedArgs, const QByteArray &postData)
01257 : TransferJob(*new TransferJobPrivate(KUrl(), CMD_SPECIAL, packedArgs, postData))
01258 {
01259 setError( _error );
01260 setErrorText( url );
01261 }
01262
01263 };
01264 }
01265
01266 TransferJob *KIO::http_post( const KUrl& url, const QByteArray &postData, JobFlags flags )
01267 {
01268 int _error = 0;
01269
01270
01271 static const int bad_ports[] = {
01272 1,
01273 7,
01274 9,
01275 11,
01276 13,
01277 15,
01278 17,
01279 19,
01280 20,
01281 21,
01282 22,
01283 23,
01284 25,
01285 37,
01286 42,
01287 43,
01288 53,
01289 77,
01290 79,
01291 87,
01292 95,
01293 101,
01294 102,
01295 103,
01296 104,
01297 109,
01298 110,
01299 111,
01300 113,
01301 115,
01302 117,
01303 119,
01304 123,
01305 135,
01306 139,
01307 143,
01308 179,
01309 389,
01310 512,
01311 513,
01312 514,
01313 515,
01314 526,
01315 530,
01316 531,
01317 532,
01318 540,
01319 556,
01320 587,
01321 601,
01322 989,
01323 990,
01324 992,
01325 993,
01326 995,
01327 1080,
01328 2049,
01329 4045,
01330 6000,
01331 6667,
01332 0};
01333 for (int cnt=0; bad_ports[cnt]; ++cnt)
01334 if (url.port() == bad_ports[cnt])
01335 {
01336 _error = KIO::ERR_POST_DENIED;
01337 break;
01338 }
01339
01340 if ( _error )
01341 {
01342 static bool override_loaded = false;
01343 static QList< int >* overriden_ports = NULL;
01344 if( !override_loaded ) {
01345 KConfig cfg( "kio_httprc" );
01346 overriden_ports = new QList< int >;
01347 *overriden_ports = cfg.group(QString()).readEntry( "OverriddenPorts", QList<int>() );
01348 override_loaded = true;
01349 }
01350 for( QList< int >::ConstIterator it = overriden_ports->begin();
01351 it != overriden_ports->end();
01352 ++it ) {
01353 if( overriden_ports->contains( url.port())) {
01354 _error = 0;
01355 }
01356 }
01357 }
01358
01359
01360 if ((url.protocol() != "http") && (url.protocol() != "https" ))
01361 _error = KIO::ERR_POST_DENIED;
01362
01363 bool redirection = false;
01364 KUrl _url(url);
01365 if (_url.path().isEmpty())
01366 {
01367 redirection = true;
01368 _url.setPath("/");
01369 }
01370
01371 if (!_error && !KAuthorized::authorizeUrlAction("open", KUrl(), _url))
01372 _error = KIO::ERR_ACCESS_DENIED;
01373
01374
01375 if (_error)
01376 {
01377 KIO_ARGS << (int)1 << url;
01378 TransferJob * job = new PostErrorJob(_error, url.prettyUrl(), packedArgs, postData);
01379 job->setUiDelegate(new JobUiDelegate());
01380 if (!(flags & HideProgressInfo)) {
01381 KIO::getJobTracker()->registerJob(job);
01382 }
01383 return job;
01384 }
01385
01386
01387 KIO_ARGS << (int)1 << _url;
01388 TransferJob * job = TransferJobPrivate::newJob(_url, CMD_SPECIAL, packedArgs, postData, flags);
01389
01390 if (redirection)
01391 QTimer::singleShot(0, job, SLOT(slotPostRedirection()) );
01392
01393 return job;
01394 }
01395
01396
01397
01398
01399 void TransferJobPrivate::slotPostRedirection()
01400 {
01401 Q_Q(TransferJob);
01402 kDebug(7007) << "TransferJob::slotPostRedirection(" << m_url << ")";
01403
01404 emit q->redirection(q, m_url);
01405 }
01406
01407
01408 TransferJob *KIO::put( const KUrl& url, int permissions, JobFlags flags )
01409 {
01410 KIO_ARGS << url << qint8( (flags & Overwrite) ? 1 : 0 ) << qint8( (flags & Resume) ? 1 : 0 ) << permissions;
01411 return TransferJobPrivate::newJob(url, CMD_PUT, packedArgs, QByteArray(), flags);
01412 }
01413
01415
01416 class KIO::StoredTransferJobPrivate: public TransferJobPrivate
01417 {
01418 public:
01419 StoredTransferJobPrivate(const KUrl& url, int command,
01420 const QByteArray &packedArgs,
01421 const QByteArray &_staticData)
01422 : TransferJobPrivate(url, command, packedArgs, _staticData),
01423 m_uploadOffset( 0 )
01424 {}
01425 QByteArray m_data;
01426 int m_uploadOffset;
01427
01428 void slotStoredData( KIO::Job *job, const QByteArray &data );
01429 void slotStoredDataReq( KIO::Job *job, QByteArray &data );
01430
01431 Q_DECLARE_PUBLIC(StoredTransferJob)
01432
01433 static inline StoredTransferJob *newJob(const KUrl &url, int command,
01434 const QByteArray &packedArgs, JobFlags flags)
01435 {
01436 StoredTransferJob *job = new StoredTransferJob(
01437 *new StoredTransferJobPrivate(url, command, packedArgs, QByteArray()));
01438 job->setUiDelegate(new JobUiDelegate);
01439 if (!(flags & HideProgressInfo))
01440 KIO::getJobTracker()->registerJob(job);
01441 return job;
01442 }
01443 };
01444
01445 StoredTransferJob::StoredTransferJob(StoredTransferJobPrivate &dd)
01446 : TransferJob(dd)
01447 {
01448 connect( this, SIGNAL( data( KIO::Job *, const QByteArray & ) ),
01449 SLOT( slotStoredData( KIO::Job *, const QByteArray & ) ) );
01450 connect( this, SIGNAL( dataReq( KIO::Job *, QByteArray & ) ),
01451 SLOT( slotStoredDataReq( KIO::Job *, QByteArray & ) ) );
01452 }
01453
01454 StoredTransferJob::~StoredTransferJob()
01455 {
01456 }
01457
01458 void StoredTransferJob::setData( const QByteArray& arr )
01459 {
01460 Q_D(StoredTransferJob);
01461 Q_ASSERT( d->m_data.isNull() );
01462 Q_ASSERT( d->m_uploadOffset == 0 );
01463 d->m_data = arr;
01464 }
01465
01466 QByteArray StoredTransferJob::data() const
01467 {
01468 return d_func()->m_data;
01469 }
01470
01471 void StoredTransferJobPrivate::slotStoredData( KIO::Job *, const QByteArray &data )
01472 {
01473
01474 if ( data.size() == 0 )
01475 return;
01476 unsigned int oldSize = m_data.size();
01477 m_data.resize( oldSize + data.size() );
01478 memcpy( m_data.data() + oldSize, data.data(), data.size() );
01479 }
01480
01481 void StoredTransferJobPrivate::slotStoredDataReq( KIO::Job *, QByteArray &data )
01482 {
01483
01484
01485 const int MAX_CHUNK_SIZE = 64*1024;
01486 int remainingBytes = m_data.size() - m_uploadOffset;
01487 if( remainingBytes > MAX_CHUNK_SIZE ) {
01488
01489 data = QByteArray( m_data.data() + m_uploadOffset, MAX_CHUNK_SIZE );
01490 m_uploadOffset += MAX_CHUNK_SIZE;
01491
01492
01493 } else {
01494
01495 data = QByteArray( m_data.data() + m_uploadOffset, remainingBytes );
01496 m_data = QByteArray();
01497 m_uploadOffset = 0;
01498
01499 }
01500 }
01501
01502 StoredTransferJob *KIO::storedGet( const KUrl& url, LoadType reload, JobFlags flags )
01503 {
01504
01505 KIO_ARGS << url;
01506 StoredTransferJob * job = StoredTransferJobPrivate::newJob(url, CMD_GET, packedArgs, flags);
01507 if (reload == Reload)
01508 job->addMetaData("cache", "reload");
01509 return job;
01510 }
01511
01512 StoredTransferJob *KIO::storedPut( const QByteArray& arr, const KUrl& url, int permissions,
01513 JobFlags flags )
01514 {
01515 KIO_ARGS << url << qint8( (flags & Overwrite) ? 1 : 0 ) << qint8( (flags & Resume) ? 1 : 0 ) << permissions;
01516 StoredTransferJob * job = StoredTransferJobPrivate::newJob(url, CMD_PUT, packedArgs, flags );
01517 job->setData( arr );
01518 return job;
01519 }
01520
01522
01523 class KIO::MimetypeJobPrivate: public KIO::TransferJobPrivate
01524 {
01525 public:
01526 MimetypeJobPrivate(const KUrl& url, int command, const QByteArray &packedArgs)
01527 : TransferJobPrivate(url, command, packedArgs, QByteArray())
01528 {}
01529
01530 Q_DECLARE_PUBLIC(MimetypeJob)
01531
01532 static inline MimetypeJob *newJob(const KUrl& url, int command, const QByteArray &packedArgs,
01533 JobFlags flags)
01534 {
01535 MimetypeJob *job = new MimetypeJob(*new MimetypeJobPrivate(url, command, packedArgs));
01536 job->setUiDelegate(new JobUiDelegate);
01537 if (!(flags & HideProgressInfo)) {
01538 KIO::getJobTracker()->registerJob(job);
01539 emitStating(job, url);
01540 }
01541 return job;
01542 }
01543 };
01544
01545 MimetypeJob::MimetypeJob(MimetypeJobPrivate &dd)
01546 : TransferJob(dd)
01547 {
01548 }
01549
01550 MimetypeJob::~MimetypeJob()
01551 {
01552 }
01553
01554 void MimetypeJob::slotFinished( )
01555 {
01556 Q_D(MimetypeJob);
01557
01558 if ( error() == KIO::ERR_IS_DIRECTORY )
01559 {
01560
01561
01562
01563 kDebug(7007) << "It is in fact a directory!";
01564 d->m_mimetype = QString::fromLatin1("inode/directory");
01565 emit TransferJob::mimetype( this, d->m_mimetype );
01566 setError( 0 );
01567 }
01568 if ( d->m_redirectionURL.isEmpty() || !d->m_redirectionURL.isValid() || error() )
01569 {
01570
01571 TransferJob::slotFinished();
01572 } else {
01573
01574 if (queryMetaData("permanent-redirect")=="true")
01575 emit permanentRedirection(this, d->m_url, d->m_redirectionURL);
01576 d->staticData.truncate(0);
01577 d->m_internalSuspended = false;
01578 d->m_url = d->m_redirectionURL;
01579 d->m_redirectionURL = KUrl();
01580 d->m_packedArgs.truncate(0);
01581 QDataStream stream( &d->m_packedArgs, QIODevice::WriteOnly );
01582 stream << d->m_url;
01583
01584
01585 d->slaveDone();
01586 Scheduler::doJob(this);
01587 }
01588 }
01589
01590 MimetypeJob *KIO::mimetype(const KUrl& url, JobFlags flags)
01591 {
01592 KIO_ARGS << url;
01593 return MimetypeJobPrivate::newJob(url, CMD_MIMETYPE, packedArgs, flags);
01594 }
01595
01597
01598 class KIO::DirectCopyJobPrivate: public KIO::SimpleJobPrivate
01599 {
01600 public:
01601 DirectCopyJobPrivate(const KUrl& url, int command, const QByteArray &packedArgs)
01602 : SimpleJobPrivate(url, command, packedArgs)
01603 {}
01604
01611 virtual void start(Slave *slave);
01612
01613 Q_DECLARE_PUBLIC(DirectCopyJob)
01614 };
01615
01616 DirectCopyJob::DirectCopyJob(const KUrl &url, const QByteArray &packedArgs)
01617 : SimpleJob(*new DirectCopyJobPrivate(url, CMD_COPY, packedArgs))
01618 {
01619 setUiDelegate(new JobUiDelegate);
01620 }
01621
01622 DirectCopyJob::~DirectCopyJob()
01623 {
01624 }
01625
01626 void DirectCopyJobPrivate::start( Slave* slave )
01627 {
01628 Q_Q(DirectCopyJob);
01629 q->connect( slave, SIGNAL(canResume( KIO::filesize_t ) ),
01630 SLOT( slotCanResume( KIO::filesize_t ) ) );
01631 SimpleJobPrivate::start(slave);
01632 }
01633
01634 void DirectCopyJob::slotCanResume( KIO::filesize_t offset )
01635 {
01636 emit canResume(this, offset);
01637 }
01638
01640
01642 class KIO::FileCopyJobPrivate: public KIO::JobPrivate
01643 {
01644 public:
01645 FileCopyJobPrivate(const KUrl& src, const KUrl& dest, int permissions,
01646 bool move, JobFlags flags)
01647 : m_sourceSize(filesize_t(-1)), m_src(src), m_dest(dest), m_moveJob(0), m_copyJob(0), m_delJob(0),
01648 m_chmodJob(0), m_getJob(0), m_putJob(0), m_permissions(permissions),
01649 m_move(move), m_mustChmod(0), m_flags(flags)
01650 {
01651 }
01652 KIO::filesize_t m_sourceSize;
01653 QDateTime m_modificationTime;
01654 KUrl m_src;
01655 KUrl m_dest;
01656 QByteArray m_buffer;
01657 SimpleJob *m_moveJob;
01658 SimpleJob *m_copyJob;
01659 SimpleJob *m_delJob;
01660 SimpleJob *m_chmodJob;
01661 TransferJob *m_getJob;
01662 TransferJob *m_putJob;
01663 int m_permissions;
01664 bool m_move:1;
01665 bool m_canResume:1;
01666 bool m_resumeAnswerSent:1;
01667 bool m_mustChmod:1;
01668 JobFlags m_flags;
01669
01670 void startBestCopyMethod();
01671 void startCopyJob();
01672 void startCopyJob(const KUrl &slave_url);
01673 void startRenameJob(const KUrl &slave_url);
01674 void startDataPump();
01675 void connectSubjob( SimpleJob * job );
01676
01677 void slotStart();
01678 void slotData( KIO::Job *, const QByteArray &data);
01679 void slotDataReq( KIO::Job *, QByteArray &data);
01680 void slotMimetype( KIO::Job*, const QString& type );
01686 void slotProcessedSize( KJob *job, qulonglong size );
01692 void slotTotalSize( KJob *job, qulonglong size );
01698 void slotPercent( KJob *job, unsigned long pct );
01704 void slotCanResume( KIO::Job *job, KIO::filesize_t offset );
01705
01706 Q_DECLARE_PUBLIC(FileCopyJob)
01707
01708 static inline FileCopyJob* newJob(const KUrl& src, const KUrl& dest, int permissions, bool move,
01709 JobFlags flags)
01710 {
01711
01712 FileCopyJob *job = new FileCopyJob(
01713 *new FileCopyJobPrivate(src, dest, permissions, move, flags));
01714 job->setUiDelegate(new JobUiDelegate);
01715 if (!(flags & HideProgressInfo))
01716 KIO::getJobTracker()->registerJob(job);
01717 return job;
01718 }
01719 };
01720
01721
01722
01723
01724
01725
01726
01727
01728 FileCopyJob::FileCopyJob(FileCopyJobPrivate &dd)
01729 : Job(dd)
01730 {
01731
01732 QTimer::singleShot(0, this, SLOT(slotStart()));
01733 }
01734
01735 void FileCopyJobPrivate::slotStart()
01736 {
01737 Q_Q(FileCopyJob);
01738 if (!m_move)
01739 JobPrivate::emitCopying( q, m_src, m_dest );
01740 else
01741 JobPrivate::emitMoving( q, m_src, m_dest );
01742
01743 if ( m_move )
01744 {
01745
01746 if ((m_src.protocol() == m_dest.protocol()) &&
01747 (m_src.host() == m_dest.host()) &&
01748 (m_src.port() == m_dest.port()) &&
01749 (m_src.user() == m_dest.user()) &&
01750 (m_src.pass() == m_dest.pass()) &&
01751 !m_src.hasSubUrl() && !m_dest.hasSubUrl())
01752 {
01753 startRenameJob(m_src);
01754 return;
01755 }
01756 else if (m_src.isLocalFile() && KProtocolManager::canRenameFromFile(m_dest))
01757 {
01758 startRenameJob(m_dest);
01759 return;
01760 }
01761 else if (m_dest.isLocalFile() && KProtocolManager::canRenameToFile(m_src))
01762 {
01763 startRenameJob(m_src);
01764 return;
01765 }
01766
01767 }
01768 startBestCopyMethod();
01769 }
01770
01771 void FileCopyJobPrivate::startBestCopyMethod()
01772 {
01773 if ((m_src.protocol() == m_dest.protocol()) &&
01774 (m_src.host() == m_dest.host()) &&
01775 (m_src.port() == m_dest.port()) &&
01776 (m_src.user() == m_dest.user()) &&
01777 (m_src.pass() == m_dest.pass()) &&
01778 !m_src.hasSubUrl() && !m_dest.hasSubUrl())
01779 {
01780 startCopyJob();
01781 }
01782 else if (m_src.isLocalFile() && KProtocolManager::canCopyFromFile(m_dest))
01783 {
01784 startCopyJob(m_dest);
01785 }
01786 else if (m_dest.isLocalFile() && KProtocolManager::canCopyToFile(m_src))
01787 {
01788 startCopyJob(m_src);
01789 }
01790 else
01791 {
01792 startDataPump();
01793 }
01794 }
01795
01796 FileCopyJob::~FileCopyJob()
01797 {
01798 }
01799
01800 void FileCopyJob::setSourceSize( KIO::filesize_t size )
01801 {
01802 Q_D(FileCopyJob);
01803 d->m_sourceSize = size;
01804 if (size != (KIO::filesize_t) -1)
01805 setTotalAmount(KJob::Bytes, size);
01806 }
01807
01808 void FileCopyJob::setModificationTime( const QDateTime& mtime )
01809 {
01810 Q_D(FileCopyJob);
01811 d->m_modificationTime = mtime;
01812 }
01813
01814 KUrl FileCopyJob::srcUrl() const
01815 {
01816 return d_func()->m_src;
01817 }
01818
01819 KUrl FileCopyJob::destUrl() const
01820 {
01821 return d_func()->m_dest;
01822 }
01823
01824 void FileCopyJobPrivate::startCopyJob()
01825 {
01826 startCopyJob(m_src);
01827 }
01828
01829 void FileCopyJobPrivate::startCopyJob(const KUrl &slave_url)
01830 {
01831 Q_Q(FileCopyJob);
01832
01833 KIO_ARGS << m_src << m_dest << m_permissions << (qint8) (m_flags & Overwrite);
01834 m_copyJob = new DirectCopyJob(slave_url, packedArgs);
01835 q->addSubjob( m_copyJob );
01836 connectSubjob( m_copyJob );
01837 q->connect( m_copyJob, SIGNAL(canResume(KIO::Job *, KIO::filesize_t)),
01838 SLOT(slotCanResume(KIO::Job *, KIO::filesize_t)));
01839 }
01840
01841 void FileCopyJobPrivate::startRenameJob(const KUrl &slave_url)
01842 {
01843 Q_Q(FileCopyJob);
01844 m_mustChmod = true;
01845 KIO_ARGS << m_src << m_dest << (qint8) (m_flags & Overwrite);
01846 m_moveJob = SimpleJobPrivate::newJob(slave_url, CMD_RENAME, packedArgs);
01847 q->addSubjob( m_moveJob );
01848 connectSubjob( m_moveJob );
01849 }
01850
01851 void FileCopyJobPrivate::connectSubjob( SimpleJob * job )
01852 {
01853 Q_Q(FileCopyJob);
01854 q->connect( job, SIGNAL(totalSize( KJob*, qulonglong )),
01855 SLOT( slotTotalSize(KJob*, qulonglong)) );
01856
01857 q->connect( job, SIGNAL(processedSize( KJob*, qulonglong )),
01858 SLOT( slotProcessedSize(KJob*, qulonglong)) );
01859
01860 q->connect( job, SIGNAL(percent( KJob*, unsigned long )),
01861 SLOT( slotPercent(KJob*, unsigned long)) );
01862
01863 }
01864
01865 bool FileCopyJob::doSuspend()
01866 {
01867 Q_D(FileCopyJob);
01868 if (d->m_moveJob)
01869 d->m_moveJob->suspend();
01870
01871 if (d->m_copyJob)
01872 d->m_copyJob->suspend();
01873
01874 if (d->m_getJob)
01875 d->m_getJob->suspend();
01876
01877 if (d->m_putJob)
01878 d->m_putJob->suspend();
01879
01880 Job::doSuspend();
01881 return true;
01882 }
01883
01884 bool FileCopyJob::doResume()
01885 {
01886 Q_D(FileCopyJob);
01887 if (d->m_moveJob)
01888 d->m_moveJob->resume();
01889
01890 if (d->m_copyJob)
01891 d->m_copyJob->resume();
01892
01893 if (d->m_getJob)
01894 d->m_getJob->resume();
01895
01896 if (d->m_putJob)
01897 d->m_putJob->resume();
01898
01899 Job::doResume();
01900 return true;
01901 }
01902
01903 void FileCopyJobPrivate::slotProcessedSize( KJob *, qulonglong size )
01904 {
01905 Q_Q(FileCopyJob);
01906 q->setProcessedAmount(KJob::Bytes, size);
01907 }
01908
01909 void FileCopyJobPrivate::slotTotalSize( KJob*, qulonglong size )
01910 {
01911 Q_Q(FileCopyJob);
01912 if (size > q->totalAmount(KJob::Bytes))
01913 {
01914 q->setTotalAmount(KJob::Bytes, size);
01915 }
01916 }
01917
01918 void FileCopyJobPrivate::slotPercent( KJob*, unsigned long pct )
01919 {
01920 Q_Q(FileCopyJob);
01921 if ( pct > q->percent() ) {
01922 q->setPercent( pct );
01923 }
01924 }
01925
01926 void FileCopyJobPrivate::startDataPump()
01927 {
01928 Q_Q(FileCopyJob);
01929
01930
01931 m_canResume = false;
01932 m_resumeAnswerSent = false;
01933 m_getJob = 0L;
01934 m_putJob = put( m_dest, m_permissions, (m_flags | HideProgressInfo) );
01935
01936 if ( m_modificationTime.isValid() ) {
01937 m_putJob->setModificationTime( m_modificationTime );
01938 }
01939
01940
01941
01942 q->connect( m_putJob, SIGNAL(canResume(KIO::Job *, KIO::filesize_t)),
01943 SLOT( slotCanResume(KIO::Job *, KIO::filesize_t)));
01944 q->connect( m_putJob, SIGNAL(dataReq(KIO::Job *, QByteArray&)),
01945 SLOT( slotDataReq(KIO::Job *, QByteArray&)));
01946 q->addSubjob( m_putJob );
01947 }
01948
01949 void FileCopyJobPrivate::slotCanResume( KIO::Job* job, KIO::filesize_t offset )
01950 {
01951 Q_Q(FileCopyJob);
01952 if ( job == m_putJob || job == m_copyJob )
01953 {
01954
01955 if (offset)
01956 {
01957 RenameDialog_Result res = R_RESUME;
01958
01959 if (!KProtocolManager::autoResume() && !(m_flags & Overwrite))
01960 {
01961 QString newPath;
01962 KIO::Job* job = ( q->parentJob() ) ? q->parentJob() : q;
01963
01964 res = ui()->askFileRename(
01965 job, i18n("File Already Exists"),
01966 m_src.url(),
01967 m_dest.url(),
01968 (RenameDialog_Mode) (M_OVERWRITE | M_RESUME | M_NORENAME), newPath,
01969 m_sourceSize, offset );
01970 }
01971
01972 if ( res == R_OVERWRITE || (m_flags & Overwrite) )
01973 offset = 0;
01974 else if ( res == R_CANCEL )
01975 {
01976 if ( job == m_putJob )
01977 m_putJob->kill( FileCopyJob::Quietly );
01978 else
01979 m_copyJob->kill( FileCopyJob::Quietly );
01980 q->setError( ERR_USER_CANCELED );
01981 q->emitResult();
01982 return;
01983 }
01984 }
01985 else
01986 m_resumeAnswerSent = true;
01987
01988 if ( job == m_putJob )
01989 {
01990 m_getJob = KIO::get( m_src, NoReload, HideProgressInfo );
01991
01992 m_getJob->addMetaData( "errorPage", "false" );
01993 m_getJob->addMetaData( "AllowCompressedPage", "false" );
01994
01995 if ( m_sourceSize != (KIO::filesize_t)-1 )
01996 m_getJob->setTotalAmount(KJob::Bytes, m_sourceSize);
01997 if (offset)
01998 {
01999
02000
02001
02002 m_getJob->addMetaData( "resume", KIO::number(offset) );
02003
02004
02005 q->connect( m_getJob, SIGNAL(canResume(KIO::Job *, KIO::filesize_t)),
02006 SLOT( slotCanResume(KIO::Job *, KIO::filesize_t)));
02007 }
02008 jobSlave(m_putJob)->setOffset( offset );
02009
02010 m_putJob->d_func()->internalSuspend();
02011 q->addSubjob( m_getJob );
02012 connectSubjob( m_getJob );
02013 m_getJob->d_func()->internalResume();
02014
02015 q->connect( m_getJob, SIGNAL(data(KIO::Job*,const QByteArray&)),
02016 SLOT( slotData(KIO::Job*,const QByteArray&)) );
02017 q->connect( m_getJob, SIGNAL(mimetype(KIO::Job*,const QString&) ),
02018 SLOT(slotMimetype(KIO::Job*,const QString&)) );
02019 }
02020 else
02021 {
02022 jobSlave(m_copyJob)->sendResumeAnswer( offset != 0 );
02023 }
02024 }
02025 else if ( job == m_getJob )
02026 {
02027
02028 m_canResume = true;
02029
02030
02031 jobSlave(m_getJob)->setOffset( jobSlave(m_putJob)->offset() );
02032 }
02033 else
02034 kWarning(7007) << "unknown job=" << job
02035 << "m_getJob=" << m_getJob << "m_putJob=" << m_putJob;
02036 }
02037
02038 void FileCopyJobPrivate::slotData( KIO::Job * , const QByteArray &data)
02039 {
02040
02041 assert(m_putJob);
02042 if (!m_putJob) return;
02043 m_getJob->d_func()->internalSuspend();
02044 m_putJob->d_func()->internalResume();
02045 m_buffer += data;
02046
02047
02048
02049 if (!m_resumeAnswerSent)
02050 {
02051 m_resumeAnswerSent = true;
02052
02053 jobSlave(m_putJob)->sendResumeAnswer( m_canResume );
02054 }
02055 }
02056
02057 void FileCopyJobPrivate::slotDataReq( KIO::Job * , QByteArray &data)
02058 {
02059 Q_Q(FileCopyJob);
02060
02061 if (!m_resumeAnswerSent && !m_getJob) {
02062
02063 q->setError( ERR_INTERNAL );
02064 q->setErrorText( "'Put' job did not send canResume or 'Get' job did not send data!" );
02065 m_putJob->kill( FileCopyJob::Quietly );
02066 q->emitResult();
02067 return;
02068 }
02069 if (m_getJob)
02070 {
02071 m_getJob->d_func()->internalResume();
02072 m_putJob->d_func()->internalSuspend();
02073 }
02074 data = m_buffer;
02075 m_buffer = QByteArray();
02076 }
02077
02078 void FileCopyJobPrivate::slotMimetype( KIO::Job*, const QString& type )
02079 {
02080 Q_Q(FileCopyJob);
02081 emit q->mimetype( q, type );
02082 }
02083
02084 void FileCopyJob::slotResult( KJob *job)
02085 {
02086 Q_D(FileCopyJob);
02087
02088 removeSubjob(job);
02089
02090 if ( job->error() )
02091 {
02092 if ((job == d->m_moveJob) && (job->error() == ERR_UNSUPPORTED_ACTION))
02093 {
02094 d->m_moveJob = 0;
02095 d->startBestCopyMethod();
02096 return;
02097 }
02098 else if ((job == d->m_copyJob) && (job->error() == ERR_UNSUPPORTED_ACTION))
02099 {
02100 d->m_copyJob = 0;
02101 d->startDataPump();
02102 return;
02103 }
02104 else if (job == d->m_getJob)
02105 {
02106 d->m_getJob = 0L;
02107 if (d->m_putJob)
02108 {
02109 d->m_putJob->kill( Quietly );
02110 removeSubjob( d->m_putJob );
02111 }
02112 }
02113 else if (job == d->m_putJob)
02114 {
02115 d->m_putJob = 0L;
02116 if (d->m_getJob)
02117 {
02118 d->m_getJob->kill( Quietly );
02119 removeSubjob( d->m_getJob );
02120 }
02121 }
02122 setError( job->error() );
02123 setErrorText( job->errorText() );
02124 emitResult();
02125 return;
02126 }
02127
02128 if (d->m_mustChmod)
02129 {
02130
02131 if (d->m_permissions != -1)
02132 {
02133 d->m_chmodJob = chmod(d->m_dest, d->m_permissions);
02134 }
02135 d->m_mustChmod = false;
02136 }
02137
02138 if (job == d->m_moveJob)
02139 {
02140 d->m_moveJob = 0;
02141 }
02142
02143 if (job == d->m_copyJob)
02144 {
02145 d->m_copyJob = 0;
02146 if (d->m_move)
02147 {
02148 d->m_delJob = file_delete( d->m_src, HideProgressInfo );
02149 addSubjob(d->m_delJob);
02150 }
02151 }
02152
02153 if (job == d->m_getJob)
02154 {
02155
02156 d->m_getJob = 0;
02157 if (d->m_putJob)
02158 d->m_putJob->d_func()->internalResume();
02159 }
02160
02161 if (job == d->m_putJob)
02162 {
02163
02164 d->m_putJob = 0;
02165 if (d->m_getJob)
02166 {
02167
02168
02169 d->m_getJob->d_func()->internalResume();
02170 }
02171 if (d->m_move)
02172 {
02173 d->m_delJob = file_delete( d->m_src, HideProgressInfo );
02174 addSubjob(d->m_delJob);
02175 }
02176 }
02177
02178 if (job == d->m_delJob)
02179 {
02180 d->m_delJob = 0;
02181 }
02182
02183 if (job == d->m_chmodJob)
02184 {
02185 d->m_chmodJob = 0;
02186 }
02187
02188 if ( !hasSubjobs() )
02189 emitResult();
02190 }
02191
02192 FileCopyJob *KIO::file_copy( const KUrl& src, const KUrl& dest, int permissions,
02193 JobFlags flags )
02194 {
02195 return FileCopyJobPrivate::newJob(src, dest, permissions, false, flags);
02196 }
02197
02198 FileCopyJob *KIO::file_move( const KUrl& src, const KUrl& dest, int permissions,
02199 JobFlags flags )
02200 {
02201 return FileCopyJobPrivate::newJob(src, dest, permissions, true, flags);
02202 }
02203
02204 SimpleJob *KIO::file_delete( const KUrl& src, JobFlags flags )
02205 {
02206 KIO_ARGS << src << qint8(true);
02207 return SimpleJobPrivate::newJob(src, CMD_DEL, packedArgs, flags);
02208 }
02209
02211
02212 class KIO::ListJobPrivate: public KIO::SimpleJobPrivate
02213 {
02214 public:
02215 ListJobPrivate(const KUrl& url, bool _recursive, const QString &_prefix, bool _includeHidden)
02216 : SimpleJobPrivate(url, CMD_LISTDIR, QByteArray()),
02217 recursive(_recursive), includeHidden(_includeHidden),
02218 prefix(_prefix), m_processedEntries(0)
02219 {}
02220 bool recursive;
02221 bool includeHidden;
02222 QString prefix;
02223 unsigned long m_processedEntries;
02224 KUrl m_redirectionURL;
02225
02232 virtual void start( Slave *slave );
02233
02234 void slotListEntries( const KIO::UDSEntryList& list );
02235 void slotRedirection( const KUrl &url );
02236 void gotEntries( KIO::Job * subjob, const KIO::UDSEntryList& list );
02237
02238 Q_DECLARE_PUBLIC(ListJob)
02239
02240 static inline ListJob *newJob(const KUrl& u, bool _recursive, const QString &_prefix,
02241 bool _includeHidden, JobFlags flags = HideProgressInfo)
02242 {
02243 ListJob *job = new ListJob(*new ListJobPrivate(u, _recursive, _prefix, _includeHidden));
02244 job->setUiDelegate(new JobUiDelegate);
02245 if (!(flags & HideProgressInfo))
02246 KIO::getJobTracker()->registerJob(job);
02247 return job;
02248 }
02249 };
02250
02251 ListJob::ListJob(ListJobPrivate &dd)
02252 : SimpleJob(dd)
02253 {
02254 Q_D(ListJob);
02255
02256
02257 QDataStream stream( &d->m_packedArgs, QIODevice::WriteOnly );
02258 stream << d->m_url;
02259 }
02260
02261 ListJob::~ListJob()
02262 {
02263 }
02264
02265 void ListJobPrivate::slotListEntries( const KIO::UDSEntryList& list )
02266 {
02267 Q_Q(ListJob);
02268
02269 m_processedEntries += list.count();
02270 slotProcessedSize( m_processedEntries );
02271
02272 if (recursive) {
02273 UDSEntryList::ConstIterator it = list.begin();
02274 const UDSEntryList::ConstIterator end = list.end();
02275
02276 for (; it != end; ++it) {
02277
02278 const UDSEntry& entry = *it;
02279
02280 KUrl itemURL;
02281
02282
02283
02284 if (entry.contains(KIO::UDSEntry::UDS_URL))
02285
02286 itemURL = entry.stringValue(KIO::UDSEntry::UDS_URL);
02287 else {
02288 itemURL = q->url();
02289 const QString fileName = entry.stringValue(KIO::UDSEntry::UDS_NAME);
02290 Q_ASSERT(!fileName.isEmpty());
02291 itemURL.addPath(fileName);
02292 }
02293
02294 if (entry.isDir() && !entry.isLink()) {
02295 const QString filename = itemURL.fileName();
02296
02297 if (filename != ".." && filename != "." && (includeHidden || filename[0] != '.')) {
02298 ListJob *job = ListJobPrivate::newJob(itemURL,
02299 true ,
02300 prefix + filename + '/',
02301 includeHidden);
02302 job->setUiDelegate(new JobUiDelegate());
02303 Scheduler::scheduleJob(job);
02304 q->connect(job, SIGNAL(entries( KIO::Job *, const KIO::UDSEntryList& )),
02305 SLOT( gotEntries( KIO::Job*, const KIO::UDSEntryList& )));
02306 q->addSubjob(job);
02307 }
02308 }
02309 }
02310 }
02311
02312
02313
02314
02315 if (prefix.isNull() && includeHidden) {
02316 emit q->entries(q, list);
02317 } else {
02318
02319 UDSEntryList newlist;
02320
02321 UDSEntryList::const_iterator it = list.begin();
02322 const UDSEntryList::const_iterator end = list.end();
02323 for (; it != end; ++it) {
02324
02325
02326 UDSEntry newone = *it;
02327 const QString filename = newone.stringValue( KIO::UDSEntry::UDS_NAME );
02328
02329
02330 if ( (prefix.isNull() || (filename != ".." && filename != ".") )
02331 && (includeHidden || (filename[0] != '.') ) )
02332 {
02333
02334 newone.insert( KIO::UDSEntry::UDS_NAME, prefix + filename );
02335 newlist.append(newone);
02336 }
02337 }
02338
02339 emit q->entries(q, newlist);
02340 }
02341 }
02342
02343 void ListJobPrivate::gotEntries(KIO::Job *, const KIO::UDSEntryList& list )
02344 {
02345
02346 Q_Q(ListJob);
02347 emit q->entries(q, list);
02348 }
02349
02350 void ListJob::slotResult( KJob * job )
02351 {
02352
02353
02354 removeSubjob( job );
02355 if ( !hasSubjobs() )
02356 emitResult();
02357 }
02358
02359 void ListJobPrivate::slotRedirection( const KUrl & url )
02360 {
02361 Q_Q(ListJob);
02362 if (!KAuthorized::authorizeUrlAction("redirect", m_url, url))
02363 {
02364 kWarning(7007) << "ListJob: Redirection from " << m_url << " to " << url << " REJECTED!";
02365 return;
02366 }
02367 m_redirectionURL = url;
02368 if (m_url.hasUser() && !url.hasUser() && (m_url.host().toLower() == url.host().toLower()))
02369 m_redirectionURL.setUser(m_url.user());
02370 emit q->redirection( q, m_redirectionURL );
02371 }
02372
02373 void ListJob::slotFinished()
02374 {
02375 Q_D(ListJob);
02376
02377 if ( error() == KIO::ERR_IS_FILE && d->m_url.isLocalFile() ) {
02378 KMimeType::Ptr ptr = KMimeType::findByUrl( d->m_url, 0, true, true );
02379 if ( ptr ) {
02380 QString proto = ptr->property("X-KDE-LocalProtocol").toString();
02381 if ( !proto.isEmpty() && KProtocolInfo::isKnownProtocol( proto) ) {
02382 d->m_redirectionURL = d->m_url;
02383 d->m_redirectionURL.setProtocol( proto );
02384 setError( 0 );
02385 emit redirection(this,d->m_redirectionURL);
02386 }
02387 }
02388 }
02389 if ( d->m_redirectionURL.isEmpty() || !d->m_redirectionURL.isValid() || error() ) {
02390
02391 SimpleJob::slotFinished();
02392 } else {
02393
02394
02395 if (queryMetaData("permanent-redirect")=="true")
02396 emit permanentRedirection(this, d->m_url, d->m_redirectionURL);
02397 d->m_url = d->m_redirectionURL;
02398 d->m_redirectionURL = KUrl();
02399 d->m_packedArgs.truncate(0);
02400 QDataStream stream( &d->m_packedArgs, QIODevice::WriteOnly );
02401 stream << d->m_url;
02402
02403
02404 d->slaveDone();
02405 Scheduler::doJob(this);
02406 }
02407 }
02408
02409 void ListJob::slotMetaData( const KIO::MetaData &_metaData)
02410 {
02411 Q_D(ListJob);
02412 SimpleJob::slotMetaData(_metaData);
02413 storeSSLSessionFromJob(d->m_redirectionURL);
02414 }
02415
02416 ListJob *KIO::listDir( const KUrl& url, JobFlags flags, bool includeHidden )
02417 {
02418 return ListJobPrivate::newJob(url, false, QString(), includeHidden, flags);
02419 }
02420
02421 ListJob *KIO::listRecursive( const KUrl& url, JobFlags flags, bool includeHidden )
02422 {
02423 return ListJobPrivate::newJob(url, true, QString(), includeHidden, flags);
02424 }
02425
02426 void ListJob::setUnrestricted(bool unrestricted)
02427 {
02428 Q_D(ListJob);
02429 if (unrestricted)
02430 d->m_extraFlags |= JobPrivate::EF_ListJobUnrestricted;
02431 else
02432 d->m_extraFlags &= ~JobPrivate::EF_ListJobUnrestricted;
02433 }
02434
02435 void ListJobPrivate::start(Slave *slave)
02436 {
02437 Q_Q(ListJob);
02438 if (!KAuthorized::authorizeUrlAction("list", m_url, m_url) &&
02439 !(m_extraFlags & EF_ListJobUnrestricted))
02440 {
02441 q->setError( ERR_ACCESS_DENIED );
02442 q->setErrorText( m_url.url() );
02443 QTimer::singleShot(0, q, SLOT(slotFinished()) );
02444 return;
02445 }
02446 q->connect( slave, SIGNAL( listEntries( const KIO::UDSEntryList& )),
02447 SLOT( slotListEntries( const KIO::UDSEntryList& )));
02448 q->connect( slave, SIGNAL( totalSize( KIO::filesize_t ) ),
02449 SLOT( slotTotalSize( KIO::filesize_t ) ) );
02450 q->connect( slave, SIGNAL( redirection(const KUrl &) ),
02451 SLOT( slotRedirection(const KUrl &) ) );
02452
02453 SimpleJobPrivate::start(slave);
02454 }
02455
02456 const KUrl& ListJob::redirectionUrl() const
02457 {
02458 return d_func()->m_redirectionURL;
02459 }
02460
02462
02463 class KIO::MultiGetJobPrivate: public KIO::TransferJobPrivate
02464 {
02465 public:
02466 MultiGetJobPrivate(const KUrl& url)
02467 : TransferJobPrivate(url, 0, QByteArray(), QByteArray()),
02468 m_currentEntry( 0, KUrl(), MetaData() )
02469 {}
02470 struct GetRequest {
02471 GetRequest(long _id, const KUrl &_url, const MetaData &_metaData)
02472 : id(_id), url(_url), metaData(_metaData) { }
02473 long id;
02474 KUrl url;
02475 MetaData metaData;
02476
02477 inline bool operator==( const GetRequest& req ) const
02478 { return req.id == id; }
02479 };
02480 typedef QLinkedList<GetRequest> RequestQueue;
02481
02482 RequestQueue m_waitQueue;
02483 RequestQueue m_activeQueue;
02484 GetRequest m_currentEntry;
02485 bool b_multiGetActive;
02486
02493 virtual void start(Slave *slave);
02494
02495 bool findCurrentEntry();
02496 void flushQueue(QLinkedList<GetRequest> &queue);
02497
02498 Q_DECLARE_PUBLIC(MultiGetJob)
02499
02500 static inline MultiGetJob *newJob(const KUrl &url)
02501 {
02502 MultiGetJob *job = new MultiGetJob(*new MultiGetJobPrivate(url));
02503 job->setUiDelegate(new JobUiDelegate);
02504 return job;
02505 }
02506 };
02507
02508 MultiGetJob::MultiGetJob(MultiGetJobPrivate &dd)
02509 : TransferJob(dd)
02510 {
02511 }
02512
02513 MultiGetJob::~MultiGetJob()
02514 {
02515 }
02516
02517 void MultiGetJob::get(long id, const KUrl &url, const MetaData &metaData)
02518 {
02519 Q_D(MultiGetJob);
02520 MultiGetJobPrivate::GetRequest entry(id, url, metaData);
02521 entry.metaData["request-id"] = QString::number(id);
02522 d->m_waitQueue.append(entry);
02523 }
02524
02525 void MultiGetJobPrivate::flushQueue(RequestQueue &queue)
02526 {
02527
02528
02529 RequestQueue::iterator wqit = m_waitQueue.begin();
02530 const RequestQueue::iterator wqend = m_waitQueue.end();
02531 while ( wqit != wqend )
02532 {
02533 const GetRequest& entry = *wqit;
02534 if ((m_url.protocol() == entry.url.protocol()) &&
02535 (m_url.host() == entry.url.host()) &&
02536 (m_url.port() == entry.url.port()) &&
02537 (m_url.user() == entry.url.user()))
02538 {
02539 queue.append( entry );
02540 wqit = m_waitQueue.erase( wqit );
02541 }
02542 else
02543 {
02544 ++wqit;
02545 }
02546 }
02547
02548 KIO_ARGS << (qint32) queue.count();
02549 RequestQueue::const_iterator qit = queue.begin();
02550 const RequestQueue::const_iterator qend = queue.end();
02551 for( ; qit != qend; ++qit )
02552 {
02553 stream << (*qit).url << (*qit).metaData;
02554 }
02555 m_packedArgs = packedArgs;
02556 m_command = CMD_MULTI_GET;
02557 m_outgoingMetaData.clear();
02558 }
02559
02560 void MultiGetJobPrivate::start(Slave *slave)
02561 {
02562
02563 GetRequest entry = m_waitQueue.takeFirst();
02564 m_activeQueue.append(entry);
02565
02566 m_url = entry.url;
02567
02568 if (!entry.url.protocol().startsWith("http"))
02569 {
02570
02571 KIO_ARGS << entry.url;
02572 m_packedArgs = packedArgs;
02573 m_outgoingMetaData = entry.metaData;
02574 m_command = CMD_GET;
02575 b_multiGetActive = false;
02576 }
02577 else
02578 {
02579 flushQueue(m_activeQueue);
02580 b_multiGetActive = true;
02581 }
02582
02583 TransferJobPrivate::start(slave);
02584 }
02585
02586 bool MultiGetJobPrivate::findCurrentEntry()
02587 {
02588 if (b_multiGetActive)
02589 {
02590 long id = m_incomingMetaData["request-id"].toLong();
02591 RequestQueue::const_iterator qit = m_activeQueue.begin();
02592 const RequestQueue::const_iterator qend = m_activeQueue.end();
02593 for( ; qit != qend; ++qit )
02594 {
02595 if ((*qit).id == id)
02596 {
02597 m_currentEntry = *qit;
02598 return true;
02599 }
02600 }
02601 m_currentEntry.id = 0;
02602 return false;
02603 }
02604 else
02605 {
02606 if ( m_activeQueue.isEmpty() )
02607 return false;
02608 m_currentEntry = m_activeQueue.first();
02609 return true;
02610 }
02611 }
02612
02613 void MultiGetJob::slotRedirection( const KUrl &url)
02614 {
02615 Q_D(MultiGetJob);
02616 if (!d->findCurrentEntry()) return;
02617 if (!KAuthorized::authorizeUrlAction("redirect", d->m_url, url))
02618 {
02619 kWarning(7007) << "MultiGetJob: Redirection from " << d->m_currentEntry.url << " to " << url << " REJECTED!";
02620 return;
02621 }
02622 d->m_redirectionURL = url;
02623 if (d->m_currentEntry.url.hasUser() && !url.hasUser() && (d->m_currentEntry.url.host().toLower() == url.host().toLower()))
02624 d->m_redirectionURL.setUser(d->m_currentEntry.url.user());
02625 get(d->m_currentEntry.id, d->m_redirectionURL, d->m_currentEntry.metaData);
02626 }
02627
02628
02629 void MultiGetJob::slotFinished()
02630 {
02631 Q_D(MultiGetJob);
02632 if (!d->findCurrentEntry()) return;
02633 if (d->m_redirectionURL.isEmpty())
02634 {
02635
02636 emit result(d->m_currentEntry.id);
02637 }
02638 d->m_redirectionURL = KUrl();
02639 setError( 0 );
02640 d->m_incomingMetaData.clear();
02641 d->m_activeQueue.removeAll(d->m_currentEntry);
02642 if (d->m_activeQueue.count() == 0)
02643 {
02644 if (d->m_waitQueue.count() == 0)
02645 {
02646
02647 TransferJob::slotFinished();
02648 }
02649 else
02650 {
02651
02652
02653
02654 d->m_url = d->m_waitQueue.first().url;
02655 d->slaveDone();
02656 Scheduler::doJob(this);
02657 }
02658 }
02659 }
02660
02661 void MultiGetJob::slotData( const QByteArray &_data)
02662 {
02663 Q_D(MultiGetJob);
02664 if(d->m_redirectionURL.isEmpty() || !d->m_redirectionURL.isValid() || error())
02665 emit data(d->m_currentEntry.id, _data);
02666 }
02667
02668 void MultiGetJob::slotMimetype( const QString &_mimetype )
02669 {
02670 Q_D(MultiGetJob);
02671 if (d->b_multiGetActive)
02672 {
02673 MultiGetJobPrivate::RequestQueue newQueue;
02674 d->flushQueue(newQueue);
02675 if (!newQueue.isEmpty())
02676 {
02677 d->m_activeQueue += newQueue;
02678 d->m_slave->send( d->m_command, d->m_packedArgs );
02679 }
02680 }
02681 if (!d->findCurrentEntry()) return;
02682 emit mimetype(d->m_currentEntry.id, _mimetype);
02683 }
02684
02685 MultiGetJob *KIO::multi_get(long id, const KUrl &url, const MetaData &metaData)
02686 {
02687 MultiGetJob * job = MultiGetJobPrivate::newJob(url);
02688 job->get(id, url, metaData);
02689 return job;
02690 }
02691
02692 class KIO::SpecialJobPrivate: public TransferJobPrivate
02693 {
02694 SpecialJobPrivate(const KUrl& url, int command,
02695 const QByteArray &packedArgs,
02696 const QByteArray &_staticData)
02697 : TransferJobPrivate(url, command, packedArgs, _staticData)
02698 {}
02699 };
02700
02701 SpecialJob::SpecialJob(const KUrl &url, const QByteArray &packedArgs)
02702 : TransferJob(*new TransferJobPrivate(url, CMD_SPECIAL, packedArgs, QByteArray()))
02703 {
02704 }
02705
02706 SpecialJob::~SpecialJob()
02707 {
02708 }
02709
02710 void SpecialJob::setArguments(const QByteArray &data)
02711 {
02712 Q_D(SpecialJob);
02713 d->m_packedArgs = data;
02714 }
02715
02716 QByteArray SpecialJob::arguments() const
02717 {
02718 return d_func()->m_packedArgs;
02719 }
02720
02721
02722 #ifdef CACHE_INFO
02723 CacheInfo::CacheInfo(const KUrl &url)
02724 {
02725 m_url = url;
02726 }
02727
02728 QString CacheInfo::cachedFileName()
02729 {
02730 const QChar separator = '_';
02731
02732 QString CEF = m_url.path();
02733
02734 int p = CEF.find('/');
02735
02736 while(p != -1)
02737 {
02738 CEF[p] = separator;
02739 p = CEF.find('/', p);
02740 }
02741
02742 QString host = m_url.host().toLower();
02743 CEF = host + CEF + '_';
02744
02745 QString dir = KProtocolManager::cacheDir();
02746 if (dir[dir.length()-1] != '/')
02747 dir += '/';
02748
02749 int l = m_url.host().length();
02750 for(int i = 0; i < l; i++)
02751 {
02752 if (host[i].isLetter() && (host[i] != 'w'))
02753 {
02754 dir += host[i];
02755 break;
02756 }
02757 }
02758 if (dir[dir.length()-1] == '/')
02759 dir += '0';
02760
02761 unsigned long hash = 0x00000000;
02762 QString u = m_url.url().toLatin1();
02763 for(int i = u.length(); i--;)
02764 {
02765 hash = (hash * 12211 + u[i]) % 2147483563;
02766 }
02767
02768 QString hashString;
02769 hashString.sprintf("%08lx", hash);
02770
02771 CEF = CEF + hashString;
02772
02773 CEF = dir + '/' + CEF;
02774
02775 return CEF;
02776 }
02777
02778 QFile *CacheInfo::cachedFile()
02779 {
02780 #ifdef Q_WS_WIN
02781 const char *mode = (readWrite ? "rb+" : "rb");
02782 #else
02783 const char *mode = (readWrite ? "r+" : "r");
02784 #endif
02785
02786 FILE *fs = KDE_fopen(QFile::encodeName(CEF), mode);
02787 if (!fs)
02788 return 0;
02789
02790 char buffer[401];
02791 bool ok = true;
02792
02793
02794 if (ok && (!fgets(buffer, 400, fs)))
02795 ok = false;
02796 if (ok && (strcmp(buffer, CACHE_REVISION) != 0))
02797 ok = false;
02798
02799 time_t date;
02800 time_t currentDate = time(0);
02801
02802
02803 if (ok && (!fgets(buffer, 400, fs)))
02804 ok = false;
02805 if (ok)
02806 {
02807 int l = strlen(buffer);
02808 if (l>0)
02809 buffer[l-1] = 0;
02810 if (m_.url.url() != buffer)
02811 {
02812 ok = false;
02813 }
02814 }
02815
02816
02817 if (ok && (!fgets(buffer, 400, fs)))
02818 ok = false;
02819 if (ok)
02820 {
02821 date = (time_t) strtoul(buffer, 0, 10);
02822 if (m_maxCacheAge && (difftime(currentDate, date) > m_maxCacheAge))
02823 {
02824 m_bMustRevalidate = true;
02825 m_expireDate = currentDate;
02826 }
02827 }
02828
02829
02830 m_cacheExpireDateOffset = KDE_ftell(fs);
02831 if (ok && (!fgets(buffer, 400, fs)))
02832 ok = false;
02833 if (ok)
02834 {
02835 if (m_request.cache == CC_Verify)
02836 {
02837 date = (time_t) strtoul(buffer, 0, 10);
02838
02839 if (!date || difftime(currentDate, date) >= 0)
02840 m_bMustRevalidate = true;
02841 m_expireDate = date;
02842 }
02843 }
02844
02845
02846 if (ok && (!fgets(buffer, 400, fs)))
02847 ok = false;
02848 if (ok)
02849 {
02850 m_etag = QString(buffer).trimmed();
02851 }
02852
02853
02854 if (ok && (!fgets(buffer, 400, fs)))
02855 ok = false;
02856 if (ok)
02857 {
02858 m_lastModified = QString(buffer).trimmed();
02859 }
02860
02861 fclose(fs);
02862
02863 if (ok)
02864 return fs;
02865
02866 unlink( QFile::encodeName(CEF) );
02867 return 0;
02868
02869 }
02870
02871 void CacheInfo::flush()
02872 {
02873 cachedFile().remove();
02874 }
02875
02876 void CacheInfo::touch()
02877 {
02878
02879 }
02880 void CacheInfo::setExpireDate(int);
02881 void CacheInfo::setExpireTimeout(int);
02882
02883
02884 int CacheInfo::creationDate();
02885 int CacheInfo::expireDate();
02886 int CacheInfo::expireTimeout();
02887 #endif
02888
02889 #include "jobclasses.moc"
02890 #include "job_p.moc"