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