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