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