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 Scheduler::cancelJob( this );
00387 d->m_slave = 0;
00388 }
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 kDebug(7007) << "stat" << url;
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 kDebug(7007) << "stat" << url;
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
02089 if ( job->error() )
02090 {
02091 if ((job == d->m_moveJob) && (job->error() == ERR_UNSUPPORTED_ACTION))
02092 {
02093 d->m_moveJob = 0;
02094 d->startBestCopyMethod();
02095 removeSubjob(job);
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 removeSubjob(job);
02103 return;
02104 }
02105 else if (job == d->m_getJob)
02106 {
02107 d->m_getJob = 0L;
02108 if (d->m_putJob)
02109 {
02110 d->m_putJob->kill( Quietly );
02111 removeSubjob( d->m_putJob );
02112 }
02113 }
02114 else if (job == d->m_putJob)
02115 {
02116 d->m_putJob = 0L;
02117 if (d->m_getJob)
02118 {
02119 d->m_getJob->kill( Quietly );
02120 removeSubjob( d->m_getJob );
02121 }
02122 }
02123 setError( job->error() );
02124 setErrorText( job->errorText() );
02125 emitResult();
02126 return;
02127 }
02128
02129 if (d->m_mustChmod)
02130 {
02131
02132 if (d->m_permissions != -1)
02133 {
02134 d->m_chmodJob = chmod(d->m_dest, d->m_permissions);
02135 }
02136 d->m_mustChmod = false;
02137 }
02138
02139 if (job == d->m_moveJob)
02140 {
02141 d->m_moveJob = 0;
02142 }
02143
02144 if (job == d->m_copyJob)
02145 {
02146 d->m_copyJob = 0;
02147 if (d->m_move)
02148 {
02149 d->m_delJob = file_delete( d->m_src, HideProgressInfo );
02150 addSubjob(d->m_delJob);
02151 }
02152 }
02153
02154 if (job == d->m_getJob)
02155 {
02156
02157 d->m_getJob = 0;
02158 if (d->m_putJob)
02159 d->m_putJob->d_func()->internalResume();
02160 }
02161
02162 if (job == d->m_putJob)
02163 {
02164
02165 d->m_putJob = 0;
02166 if (d->m_getJob)
02167 {
02168
02169
02170 d->m_getJob->d_func()->internalResume();
02171 }
02172 if (d->m_move)
02173 {
02174 d->m_delJob = file_delete( d->m_src, HideProgressInfo );
02175 addSubjob(d->m_delJob);
02176 }
02177 }
02178
02179 if (job == d->m_delJob)
02180 {
02181 d->m_delJob = 0;
02182 }
02183
02184 if (job == d->m_chmodJob)
02185 {
02186 d->m_chmodJob = 0;
02187 }
02188
02189 removeSubjob(job);
02190 if ( !hasSubjobs() )
02191 emitResult();
02192 }
02193
02194 FileCopyJob *KIO::file_copy( const KUrl& src, const KUrl& dest, int permissions,
02195 JobFlags flags )
02196 {
02197 return FileCopyJobPrivate::newJob(src, dest, permissions, false, flags);
02198 }
02199
02200 FileCopyJob *KIO::file_move( const KUrl& src, const KUrl& dest, int permissions,
02201 JobFlags flags )
02202 {
02203 return FileCopyJobPrivate::newJob(src, dest, permissions, true, flags);
02204 }
02205
02206 SimpleJob *KIO::file_delete( const KUrl& src, JobFlags flags )
02207 {
02208 KIO_ARGS << src << qint8(true);
02209 return SimpleJobPrivate::newJob(src, CMD_DEL, packedArgs, flags);
02210 }
02211
02213
02214 class KIO::ListJobPrivate: public KIO::SimpleJobPrivate
02215 {
02216 public:
02217 ListJobPrivate(const KUrl& url, bool _recursive, const QString &_prefix, bool _includeHidden)
02218 : SimpleJobPrivate(url, CMD_LISTDIR, QByteArray()),
02219 recursive(_recursive), includeHidden(_includeHidden),
02220 prefix(_prefix), m_processedEntries(0)
02221 {}
02222 bool recursive;
02223 bool includeHidden;
02224 QString prefix;
02225 unsigned long m_processedEntries;
02226 KUrl m_redirectionURL;
02227
02234 virtual void start( Slave *slave );
02235
02236 void slotListEntries( const KIO::UDSEntryList& list );
02237 void slotRedirection( const KUrl &url );
02238 void gotEntries( KIO::Job * subjob, const KIO::UDSEntryList& list );
02239
02240 Q_DECLARE_PUBLIC(ListJob)
02241
02242 static inline ListJob *newJob(const KUrl& u, bool _recursive, const QString &_prefix,
02243 bool _includeHidden, JobFlags flags = HideProgressInfo)
02244 {
02245 ListJob *job = new ListJob(*new ListJobPrivate(u, _recursive, _prefix, _includeHidden));
02246 job->setUiDelegate(new JobUiDelegate);
02247 if (!(flags & HideProgressInfo))
02248 KIO::getJobTracker()->registerJob(job);
02249 return job;
02250 }
02251 };
02252
02253 ListJob::ListJob(ListJobPrivate &dd)
02254 : SimpleJob(dd)
02255 {
02256 Q_D(ListJob);
02257
02258
02259 QDataStream stream( &d->m_packedArgs, QIODevice::WriteOnly );
02260 stream << d->m_url;
02261 }
02262
02263 ListJob::~ListJob()
02264 {
02265 }
02266
02267 void ListJobPrivate::slotListEntries( const KIO::UDSEntryList& list )
02268 {
02269 Q_Q(ListJob);
02270
02271 m_processedEntries += list.count();
02272 slotProcessedSize( m_processedEntries );
02273
02274 if (recursive) {
02275 UDSEntryList::ConstIterator it = list.begin();
02276 const UDSEntryList::ConstIterator end = list.end();
02277
02278 for (; it != end; ++it) {
02279
02280 const UDSEntry& entry = *it;
02281
02282 KUrl itemURL;
02283
02284
02285
02286 if (entry.contains(KIO::UDSEntry::UDS_URL))
02287
02288 itemURL = entry.stringValue(KIO::UDSEntry::UDS_URL);
02289 else {
02290 itemURL = q->url();
02291 const QString fileName = entry.stringValue(KIO::UDSEntry::UDS_NAME);
02292 Q_ASSERT(!fileName.isEmpty());
02293 itemURL.addPath(fileName);
02294 }
02295
02296 if (entry.isDir() && !entry.isLink()) {
02297 const QString filename = itemURL.fileName();
02298
02299 if (filename != ".." && filename != "." && (includeHidden || filename[0] != '.')) {
02300 ListJob *job = ListJobPrivate::newJob(itemURL,
02301 true ,
02302 prefix + filename + '/',
02303 includeHidden);
02304 job->setUiDelegate(new JobUiDelegate());
02305 Scheduler::scheduleJob(job);
02306 q->connect(job, SIGNAL(entries( KIO::Job *, const KIO::UDSEntryList& )),
02307 SLOT( gotEntries( KIO::Job*, const KIO::UDSEntryList& )));
02308 q->addSubjob(job);
02309 }
02310 }
02311 }
02312 }
02313
02314
02315
02316
02317 if (prefix.isNull() && includeHidden) {
02318 emit q->entries(q, list);
02319 } else {
02320
02321 UDSEntryList newlist;
02322
02323 UDSEntryList::const_iterator it = list.begin();
02324 const UDSEntryList::const_iterator end = list.end();
02325 for (; it != end; ++it) {
02326
02327
02328 UDSEntry newone = *it;
02329 const QString filename = newone.stringValue( KIO::UDSEntry::UDS_NAME );
02330
02331
02332 if ( (prefix.isNull() || (filename != ".." && filename != ".") )
02333 && (includeHidden || (filename[0] != '.') ) )
02334 {
02335
02336 newone.insert( KIO::UDSEntry::UDS_NAME, prefix + filename );
02337 newlist.append(newone);
02338 }
02339 }
02340
02341 emit q->entries(q, newlist);
02342 }
02343 }
02344
02345 void ListJobPrivate::gotEntries(KIO::Job *, const KIO::UDSEntryList& list )
02346 {
02347
02348 Q_Q(ListJob);
02349 emit q->entries(q, list);
02350 }
02351
02352 void ListJob::slotResult( KJob * job )
02353 {
02354
02355
02356 removeSubjob( job );
02357 if ( !hasSubjobs() )
02358 emitResult();
02359 }
02360
02361 void ListJobPrivate::slotRedirection( const KUrl & url )
02362 {
02363 Q_Q(ListJob);
02364 if (!KAuthorized::authorizeUrlAction("redirect", m_url, url))
02365 {
02366 kWarning(7007) << "ListJob: Redirection from " << m_url << " to " << url << " REJECTED!";
02367 return;
02368 }
02369 m_redirectionURL = url;
02370 if (m_url.hasUser() && !url.hasUser() && (m_url.host().toLower() == url.host().toLower()))
02371 m_redirectionURL.setUser(m_url.user());
02372 emit q->redirection( q, m_redirectionURL );
02373 }
02374
02375 void ListJob::slotFinished()
02376 {
02377 Q_D(ListJob);
02378
02379 if ( error() == KIO::ERR_IS_FILE && d->m_url.isLocalFile() ) {
02380 KMimeType::Ptr ptr = KMimeType::findByUrl( d->m_url, 0, true, true );
02381 if ( ptr ) {
02382 QString proto = ptr->property("X-KDE-LocalProtocol").toString();
02383 if ( !proto.isEmpty() && KProtocolInfo::isKnownProtocol( proto) ) {
02384 d->m_redirectionURL = d->m_url;
02385 d->m_redirectionURL.setProtocol( proto );
02386 setError( 0 );
02387 emit redirection(this,d->m_redirectionURL);
02388 }
02389 }
02390 }
02391 if ( d->m_redirectionURL.isEmpty() || !d->m_redirectionURL.isValid() || error() ) {
02392
02393 SimpleJob::slotFinished();
02394 } else {
02395
02396
02397 if (queryMetaData("permanent-redirect")=="true")
02398 emit permanentRedirection(this, d->m_url, d->m_redirectionURL);
02399 d->m_url = d->m_redirectionURL;
02400 d->m_redirectionURL = KUrl();
02401 d->m_packedArgs.truncate(0);
02402 QDataStream stream( &d->m_packedArgs, QIODevice::WriteOnly );
02403 stream << d->m_url;
02404
02405
02406 d->slaveDone();
02407 Scheduler::doJob(this);
02408 }
02409 }
02410
02411 void ListJob::slotMetaData( const KIO::MetaData &_metaData)
02412 {
02413 Q_D(ListJob);
02414 SimpleJob::slotMetaData(_metaData);
02415 storeSSLSessionFromJob(d->m_redirectionURL);
02416 }
02417
02418 ListJob *KIO::listDir( const KUrl& url, JobFlags flags, bool includeHidden )
02419 {
02420 return ListJobPrivate::newJob(url, false, QString(), includeHidden, flags);
02421 }
02422
02423 ListJob *KIO::listRecursive( const KUrl& url, JobFlags flags, bool includeHidden )
02424 {
02425 return ListJobPrivate::newJob(url, true, QString(), includeHidden, flags);
02426 }
02427
02428 void ListJob::setUnrestricted(bool unrestricted)
02429 {
02430 Q_D(ListJob);
02431 if (unrestricted)
02432 d->m_extraFlags |= JobPrivate::EF_ListJobUnrestricted;
02433 else
02434 d->m_extraFlags &= ~JobPrivate::EF_ListJobUnrestricted;
02435 }
02436
02437 void ListJobPrivate::start(Slave *slave)
02438 {
02439 Q_Q(ListJob);
02440 if (!KAuthorized::authorizeUrlAction("list", m_url, m_url) &&
02441 !(m_extraFlags & EF_ListJobUnrestricted))
02442 {
02443 q->setError( ERR_ACCESS_DENIED );
02444 q->setErrorText( m_url.url() );
02445 QTimer::singleShot(0, q, SLOT(slotFinished()) );
02446 return;
02447 }
02448 q->connect( slave, SIGNAL( listEntries( const KIO::UDSEntryList& )),
02449 SLOT( slotListEntries( const KIO::UDSEntryList& )));
02450 q->connect( slave, SIGNAL( totalSize( KIO::filesize_t ) ),
02451 SLOT( slotTotalSize( KIO::filesize_t ) ) );
02452 q->connect( slave, SIGNAL( redirection(const KUrl &) ),
02453 SLOT( slotRedirection(const KUrl &) ) );
02454
02455 SimpleJobPrivate::start(slave);
02456 }
02457
02458 const KUrl& ListJob::redirectionUrl() const
02459 {
02460 return d_func()->m_redirectionURL;
02461 }
02462
02464
02465 class KIO::MultiGetJobPrivate: public KIO::TransferJobPrivate
02466 {
02467 public:
02468 MultiGetJobPrivate(const KUrl& url)
02469 : TransferJobPrivate(url, 0, QByteArray(), QByteArray()),
02470 m_currentEntry( 0, KUrl(), MetaData() )
02471 {}
02472 struct GetRequest {
02473 GetRequest(long _id, const KUrl &_url, const MetaData &_metaData)
02474 : id(_id), url(_url), metaData(_metaData) { }
02475 long id;
02476 KUrl url;
02477 MetaData metaData;
02478
02479 inline bool operator==( const GetRequest& req ) const
02480 { return req.id == id; }
02481 };
02482 typedef QLinkedList<GetRequest> RequestQueue;
02483
02484 RequestQueue m_waitQueue;
02485 RequestQueue m_activeQueue;
02486 GetRequest m_currentEntry;
02487 bool b_multiGetActive;
02488
02495 virtual void start(Slave *slave);
02496
02497 bool findCurrentEntry();
02498 void flushQueue(QLinkedList<GetRequest> &queue);
02499
02500 Q_DECLARE_PUBLIC(MultiGetJob)
02501
02502 static inline MultiGetJob *newJob(const KUrl &url)
02503 {
02504 MultiGetJob *job = new MultiGetJob(*new MultiGetJobPrivate(url));
02505 job->setUiDelegate(new JobUiDelegate);
02506 return job;
02507 }
02508 };
02509
02510 MultiGetJob::MultiGetJob(MultiGetJobPrivate &dd)
02511 : TransferJob(dd)
02512 {
02513 }
02514
02515 MultiGetJob::~MultiGetJob()
02516 {
02517 }
02518
02519 void MultiGetJob::get(long id, const KUrl &url, const MetaData &metaData)
02520 {
02521 Q_D(MultiGetJob);
02522 MultiGetJobPrivate::GetRequest entry(id, url, metaData);
02523 entry.metaData["request-id"] = QString::number(id);
02524 d->m_waitQueue.append(entry);
02525 }
02526
02527 void MultiGetJobPrivate::flushQueue(RequestQueue &queue)
02528 {
02529
02530
02531 RequestQueue::iterator wqit = m_waitQueue.begin();
02532 const RequestQueue::iterator wqend = m_waitQueue.end();
02533 while ( wqit != wqend )
02534 {
02535 const GetRequest& entry = *wqit;
02536 if ((m_url.protocol() == entry.url.protocol()) &&
02537 (m_url.host() == entry.url.host()) &&
02538 (m_url.port() == entry.url.port()) &&
02539 (m_url.user() == entry.url.user()))
02540 {
02541 queue.append( entry );
02542 wqit = m_waitQueue.erase( wqit );
02543 }
02544 else
02545 {
02546 ++wqit;
02547 }
02548 }
02549
02550 KIO_ARGS << (qint32) queue.count();
02551 RequestQueue::const_iterator qit = queue.begin();
02552 const RequestQueue::const_iterator qend = queue.end();
02553 for( ; qit != qend; ++qit )
02554 {
02555 stream << (*qit).url << (*qit).metaData;
02556 }
02557 m_packedArgs = packedArgs;
02558 m_command = CMD_MULTI_GET;
02559 m_outgoingMetaData.clear();
02560 }
02561
02562 void MultiGetJobPrivate::start(Slave *slave)
02563 {
02564
02565 GetRequest entry = m_waitQueue.takeFirst();
02566 m_activeQueue.append(entry);
02567
02568 m_url = entry.url;
02569
02570 if (!entry.url.protocol().startsWith("http"))
02571 {
02572
02573 KIO_ARGS << entry.url;
02574 m_packedArgs = packedArgs;
02575 m_outgoingMetaData = entry.metaData;
02576 m_command = CMD_GET;
02577 b_multiGetActive = false;
02578 }
02579 else
02580 {
02581 flushQueue(m_activeQueue);
02582 b_multiGetActive = true;
02583 }
02584
02585 TransferJobPrivate::start(slave);
02586 }
02587
02588 bool MultiGetJobPrivate::findCurrentEntry()
02589 {
02590 if (b_multiGetActive)
02591 {
02592 long id = m_incomingMetaData["request-id"].toLong();
02593 RequestQueue::const_iterator qit = m_activeQueue.begin();
02594 const RequestQueue::const_iterator qend = m_activeQueue.end();
02595 for( ; qit != qend; ++qit )
02596 {
02597 if ((*qit).id == id)
02598 {
02599 m_currentEntry = *qit;
02600 return true;
02601 }
02602 }
02603 m_currentEntry.id = 0;
02604 return false;
02605 }
02606 else
02607 {
02608 if ( m_activeQueue.isEmpty() )
02609 return false;
02610 m_currentEntry = m_activeQueue.first();
02611 return true;
02612 }
02613 }
02614
02615 void MultiGetJob::slotRedirection( const KUrl &url)
02616 {
02617 Q_D(MultiGetJob);
02618 if (!d->findCurrentEntry()) return;
02619 if (!KAuthorized::authorizeUrlAction("redirect", d->m_url, url))
02620 {
02621 kWarning(7007) << "MultiGetJob: Redirection from " << d->m_currentEntry.url << " to " << url << " REJECTED!";
02622 return;
02623 }
02624 d->m_redirectionURL = url;
02625 if (d->m_currentEntry.url.hasUser() && !url.hasUser() && (d->m_currentEntry.url.host().toLower() == url.host().toLower()))
02626 d->m_redirectionURL.setUser(d->m_currentEntry.url.user());
02627 get(d->m_currentEntry.id, d->m_redirectionURL, d->m_currentEntry.metaData);
02628 }
02629
02630
02631 void MultiGetJob::slotFinished()
02632 {
02633 Q_D(MultiGetJob);
02634 if (!d->findCurrentEntry()) return;
02635 if (d->m_redirectionURL.isEmpty())
02636 {
02637
02638 emit result(d->m_currentEntry.id);
02639 }
02640 d->m_redirectionURL = KUrl();
02641 setError( 0 );
02642 d->m_incomingMetaData.clear();
02643 d->m_activeQueue.removeAll(d->m_currentEntry);
02644 if (d->m_activeQueue.count() == 0)
02645 {
02646 if (d->m_waitQueue.count() == 0)
02647 {
02648
02649 TransferJob::slotFinished();
02650 }
02651 else
02652 {
02653
02654
02655
02656 d->m_url = d->m_waitQueue.first().url;
02657 d->slaveDone();
02658 Scheduler::doJob(this);
02659 }
02660 }
02661 }
02662
02663 void MultiGetJob::slotData( const QByteArray &_data)
02664 {
02665 Q_D(MultiGetJob);
02666 if(d->m_redirectionURL.isEmpty() || !d->m_redirectionURL.isValid() || error())
02667 emit data(d->m_currentEntry.id, _data);
02668 }
02669
02670 void MultiGetJob::slotMimetype( const QString &_mimetype )
02671 {
02672 Q_D(MultiGetJob);
02673 if (d->b_multiGetActive)
02674 {
02675 MultiGetJobPrivate::RequestQueue newQueue;
02676 d->flushQueue(newQueue);
02677 if (!newQueue.isEmpty())
02678 {
02679 d->m_activeQueue += newQueue;
02680 d->m_slave->send( d->m_command, d->m_packedArgs );
02681 }
02682 }
02683 if (!d->findCurrentEntry()) return;
02684 emit mimetype(d->m_currentEntry.id, _mimetype);
02685 }
02686
02687 MultiGetJob *KIO::multi_get(long id, const KUrl &url, const MetaData &metaData)
02688 {
02689 MultiGetJob * job = MultiGetJobPrivate::newJob(url);
02690 job->get(id, url, metaData);
02691 return job;
02692 }
02693
02694 class KIO::SpecialJobPrivate: public TransferJobPrivate
02695 {
02696 SpecialJobPrivate(const KUrl& url, int command,
02697 const QByteArray &packedArgs,
02698 const QByteArray &_staticData)
02699 : TransferJobPrivate(url, command, packedArgs, _staticData)
02700 {}
02701 };
02702
02703 SpecialJob::SpecialJob(const KUrl &url, const QByteArray &packedArgs)
02704 : TransferJob(*new TransferJobPrivate(url, CMD_SPECIAL, packedArgs, QByteArray()))
02705 {
02706 }
02707
02708 SpecialJob::~SpecialJob()
02709 {
02710 }
02711
02712 void SpecialJob::setArguments(const QByteArray &data)
02713 {
02714 Q_D(SpecialJob);
02715 d->m_packedArgs = data;
02716 }
02717
02718 QByteArray SpecialJob::arguments() const
02719 {
02720 return d_func()->m_packedArgs;
02721 }
02722
02723
02724 #ifdef CACHE_INFO
02725 CacheInfo::CacheInfo(const KUrl &url)
02726 {
02727 m_url = url;
02728 }
02729
02730 QString CacheInfo::cachedFileName()
02731 {
02732 const QChar separator = '_';
02733
02734 QString CEF = m_url.path();
02735
02736 int p = CEF.find('/');
02737
02738 while(p != -1)
02739 {
02740 CEF[p] = separator;
02741 p = CEF.find('/', p);
02742 }
02743
02744 QString host = m_url.host().toLower();
02745 CEF = host + CEF + '_';
02746
02747 QString dir = KProtocolManager::cacheDir();
02748 if (dir[dir.length()-1] != '/')
02749 dir += '/';
02750
02751 int l = m_url.host().length();
02752 for(int i = 0; i < l; i++)
02753 {
02754 if (host[i].isLetter() && (host[i] != 'w'))
02755 {
02756 dir += host[i];
02757 break;
02758 }
02759 }
02760 if (dir[dir.length()-1] == '/')
02761 dir += '0';
02762
02763 unsigned long hash = 0x00000000;
02764 QString u = m_url.url().toLatin1();
02765 for(int i = u.length(); i--;)
02766 {
02767 hash = (hash * 12211 + u[i]) % 2147483563;
02768 }
02769
02770 QString hashString;
02771 hashString.sprintf("%08lx", hash);
02772
02773 CEF = CEF + hashString;
02774
02775 CEF = dir + '/' + CEF;
02776
02777 return CEF;
02778 }
02779
02780 QFile *CacheInfo::cachedFile()
02781 {
02782 #ifdef Q_WS_WIN
02783 const char *mode = (readWrite ? "rb+" : "rb");
02784 #else
02785 const char *mode = (readWrite ? "r+" : "r");
02786 #endif
02787
02788 FILE *fs = KDE_fopen(QFile::encodeName(CEF), mode);
02789 if (!fs)
02790 return 0;
02791
02792 char buffer[401];
02793 bool ok = true;
02794
02795
02796 if (ok && (!fgets(buffer, 400, fs)))
02797 ok = false;
02798 if (ok && (strcmp(buffer, CACHE_REVISION) != 0))
02799 ok = false;
02800
02801 time_t date;
02802 time_t currentDate = time(0);
02803
02804
02805 if (ok && (!fgets(buffer, 400, fs)))
02806 ok = false;
02807 if (ok)
02808 {
02809 int l = strlen(buffer);
02810 if (l>0)
02811 buffer[l-1] = 0;
02812 if (m_.url.url() != buffer)
02813 {
02814 ok = false;
02815 }
02816 }
02817
02818
02819 if (ok && (!fgets(buffer, 400, fs)))
02820 ok = false;
02821 if (ok)
02822 {
02823 date = (time_t) strtoul(buffer, 0, 10);
02824 if (m_maxCacheAge && (difftime(currentDate, date) > m_maxCacheAge))
02825 {
02826 m_bMustRevalidate = true;
02827 m_expireDate = currentDate;
02828 }
02829 }
02830
02831
02832 m_cacheExpireDateOffset = KDE_ftell(fs);
02833 if (ok && (!fgets(buffer, 400, fs)))
02834 ok = false;
02835 if (ok)
02836 {
02837 if (m_request.cache == CC_Verify)
02838 {
02839 date = (time_t) strtoul(buffer, 0, 10);
02840
02841 if (!date || difftime(currentDate, date) >= 0)
02842 m_bMustRevalidate = true;
02843 m_expireDate = date;
02844 }
02845 }
02846
02847
02848 if (ok && (!fgets(buffer, 400, fs)))
02849 ok = false;
02850 if (ok)
02851 {
02852 m_etag = QString(buffer).trimmed();
02853 }
02854
02855
02856 if (ok && (!fgets(buffer, 400, fs)))
02857 ok = false;
02858 if (ok)
02859 {
02860 m_lastModified = QString(buffer).trimmed();
02861 }
02862
02863 fclose(fs);
02864
02865 if (ok)
02866 return fs;
02867
02868 unlink( QFile::encodeName(CEF) );
02869 return 0;
02870
02871 }
02872
02873 void CacheInfo::flush()
02874 {
02875 cachedFile().remove();
02876 }
02877
02878 void CacheInfo::touch()
02879 {
02880
02881 }
02882 void CacheInfo::setExpireDate(int);
02883 void CacheInfo::setExpireTimeout(int);
02884
02885
02886 int CacheInfo::creationDate();
02887 int CacheInfo::expireDate();
02888 int CacheInfo::expireTimeout();
02889 #endif
02890
02891 #include "jobclasses.moc"
02892 #include "job_p.moc"