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