• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KIO

job.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002     Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
00003                        David Faure <faure@kde.org>
00004                        Waldo Bastian <bastian@kde.org>
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License as published by the Free Software Foundation; either
00009     version 2 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Library General Public License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public License
00017     along with this library; see the file COPYING.LIB.  If not, write to
00018     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019     Boston, MA 02110-1301, USA.
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 //this will update the report dialog with 5 Hz, I think this is fast enough, aleXXX
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     //kDebug(7007) << "addSubjob(" << jobBase << ") this=" << this;
00107 
00108     bool ok = KCompositeJob::addSubjob( jobBase );
00109     KIO::Job *job = dynamic_cast<KIO::Job*>( jobBase );
00110     if (ok && job) {
00111         // Copy metadata into subjob (e.g. window-id, user-timestamp etc.)
00112         Q_D(Job);
00113         job->mergeMetaData(d->m_outgoingMetaData);
00114 
00115         // Forward information from that subjob.
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     //kDebug(7007) << "removeSubjob(" << jobBase << ") this=" << this << "subjobs=" << subjobs().count();
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   // kill all subjobs, without triggering their result slot
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     //kDebug(7007) << speed;
00219     q_func()->emitSpeed( speed );
00220 }
00221 
00222 //Job::errorString is implemented in global.cpp
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         // there's probably a faster way
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     //kDebug() << this;
00323     Q_D(SimpleJob);
00324     Scheduler::cancelJob( this ); // deletes the slave if not 0
00325     d->m_slave = 0; // -> set to 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) // was running
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 ); // deletes the slave
00376 #endif
00377         d->m_slave = 0; // -> set to 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)              // not interactive
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); // Remove all signals between slave and job
00458     Scheduler::jobFinished( q, m_slave );
00459     m_slave = 0;
00460 }
00461 
00462 void SimpleJob::slotFinished( )
00463 {
00464     Q_D(SimpleJob);
00465     // Return slave to the scheduler
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 /*if ( m_command == CMD_RENAME )*/
00479             {
00480                 KUrl src, dst;
00481                 QDataStream str( d->m_packedArgs );
00482                 str >> src >> dst;
00483                 if( src.directory() == dst.directory() ) // For the user, moving isn't renaming. Only renaming is.
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     // error terminates the job
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     //kDebug(7007) << KIO::number(size);
00532     q->setProcessedAmount(KJob::Bytes, size);
00533 }
00534 
00535 void SimpleJobPrivate::slotSpeed( unsigned long speed )
00536 {
00537     //kDebug(7007) << speed;
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 // Slave got a redirection request
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; // We'll remember that when the job finishes
00617      if (m_url.hasUser() && !url.hasUser() && (m_url.host().toLower() == url.host().toLower()))
00618          m_redirectionURL.setUser(m_url.user()); // Preserve user
00619      // Tell the user that we haven't finished yet
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         // Return slave to the scheduler
00629         SimpleJob::slotFinished();
00630     } else {
00631         //kDebug(7007) << "MkdirJob: Redirection to " << m_redirectionURL;
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         // Return slave to the scheduler
00646         d->slaveDone();
00647         Scheduler::doJob(this);
00648     }
00649 }
00650 
00651 SimpleJob *KIO::mkdir( const KUrl& url, int permissions )
00652 {
00653     //kDebug(7007) << "mkdir " << url;
00654     KIO_ARGS << url << permissions;
00655     return MkdirJobPrivate::newJob(url, CMD_MKDIR, packedArgs);
00656 }
00657 
00658 SimpleJob *KIO::rmdir( const KUrl& url )
00659 {
00660     //kDebug(7007) << "rmdir " << url;
00661     KIO_ARGS << url << qint8(false); // isFile is false
00662     return SimpleJobPrivate::newJob(url, CMD_DEL, packedArgs);
00663 }
00664 
00665 SimpleJob *KIO::chmod( const KUrl& url, int permissions )
00666 {
00667     //kDebug(7007) << "chmod " << url;
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     //kDebug(7007) << "setModificationTime " << url << " " << mtime;
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     //kDebug(7007) << "rename " << src << " " << dest;
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     //kDebug(7007) << "symlink target=" << target << " " << dest;
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     //kDebug(7007) << "special " << url;
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     //kDebug(7007);
00813     m_statResult = entry;
00814 }
00815 
00816 // Slave got a redirection request
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; // We'll remember that when the job finishes
00829      if (m_url.hasUser() && !url.hasUser() && (m_url.host().toLower() == url.host().toLower()))
00830         m_redirectionURL.setUser(m_url.user()); // Preserve user
00831      // Tell the user that we haven't finished yet
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         // Return slave to the scheduler
00841         SimpleJob::slotFinished();
00842     } else {
00843         //kDebug(7007) << "StatJob: Redirection to " << m_redirectionURL;
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         // Return slave to the scheduler
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     // Assume sideIsSource. Gets are more common than puts.
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     //kDebug(7007) << "stat" << url;
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     //kDebug(7007) << "stat" << url;
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     // Send http update_cache command (2)
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 // Slave sends data
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 // Slave got a redirection request
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     // Some websites keep redirecting to themselves where each redirection
00932     // acts as the stage in a state-machine. We define "endless redirections"
00933     // as 5 redirections to the same URL.
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; // We'll remember that when the job finishes
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()); // Preserve user
00945        d->m_redirectionList.append(url);
00946        d->m_outgoingMetaData["ssl_was_in_use"] = d->m_incomingMetaData["ssl_in_use"];
00947        // Tell the user that we haven't finished yet
00948        emit redirection(this, d->m_redirectionURL);
00949     }
00950 }
00951 
00952 void TransferJob::slotFinished()
00953 {
00954     Q_D(TransferJob);
00955     //kDebug(7007) << this << "," << m_url;
00956     if (d->m_redirectionURL.isEmpty() || !d->m_redirectionURL.isValid())
00957         SimpleJob::slotFinished();
00958     else {
00959         //kDebug(7007) << "Redirection to" << m_redirectionURL;
00960         if (queryMetaData("permanent-redirect")=="true")
00961             emit permanentRedirection(this, d->m_url, d->m_redirectionURL);
00962         // Honour the redirection
00963         // We take the approach of "redirecting this same job"
00964         // Another solution would be to create a subjob, but the same problem
00965         // happens (unpacking+repacking)
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         // The very tricky part is the packed arguments business
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) // HTTP POST
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         // Return slave to the scheduler
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 // Slave requests data
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        // Bitburger protocol in action
01093        d->internalSuspend(); // Wait for more data from subJob.
01094        d->m_subJob->d_func()->internalResume(); // Ask for more!
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        // WABA: The slave was put on hold. Resume operation.
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     // Job needs data from subURL.
01177     m_subJob = KIO::get( m_subUrl, NoReload, HideProgressInfo);
01178     internalSuspend(); // Put job on hold until we have some data.
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     // The Alternating Bitburg protocol in action again.
01187     staticData = data;
01188     m_subJob->d_func()->internalSuspend(); // Put job on hold until we have delivered the data.
01189     internalResume(); // Activate ourselves again.
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    // This can only be our suburl.
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; // No action required
01221       d->internalResume(); // Make sure we get the remaining data.
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     // Send decoded path and encoded query
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     // filter out some malicious ports
01291     static const int bad_ports[] = {
01292         1,   // tcpmux
01293         7,   // echo
01294         9,   // discard
01295         11,   // systat
01296         13,   // daytime
01297         15,   // netstat
01298         17,   // qotd
01299         19,   // chargen
01300         20,   // ftp-data
01301         21,   // ftp-cntl
01302         22,   // ssh
01303         23,   // telnet
01304         25,   // smtp
01305         37,   // time
01306         42,   // name
01307         43,   // nicname
01308         53,   // domain
01309         77,   // priv-rjs
01310         79,   // finger
01311         87,   // ttylink
01312         95,   // supdup
01313         101,  // hostriame
01314         102,  // iso-tsap
01315         103,  // gppitnp
01316         104,  // acr-nema
01317         109,  // pop2
01318         110,  // pop3
01319         111,  // sunrpc
01320         113,  // auth
01321         115,  // sftp
01322         117,  // uucp-path
01323         119,  // nntp
01324         123,  // NTP
01325         135,  // loc-srv / epmap
01326         139,  // netbios
01327         143,  // imap2
01328         179,  // BGP
01329         389,  // ldap
01330         512,  // print / exec
01331         513,  // login
01332         514,  // shell
01333         515,  // printer
01334         526,  // tempo
01335         530,  // courier
01336         531,  // Chat
01337         532,  // netnews
01338         540,  // uucp
01339         556,  // remotefs
01340         587,  // sendmail
01341         601,  //
01342         989,  // ftps data
01343         990,  // ftps
01344         992,  // telnets
01345         993,  // imap/SSL
01346         995,  // pop3/SSL
01347         1080, // SOCKS
01348         2049, // nfs
01349         4045, // lockd
01350         6000, // x11
01351         6667, // irc
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     // filter out non https? protocols
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     // if request is not valid, return an invalid transfer job
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     // all is ok, return 0
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     // Send http post command (1), decoded path and encoded query
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     // Send http post command (1), decoded path and encoded query
01441     KIO_ARGS << (int)1 << _url;
01442     job = StoredTransferJobPrivate::newJob(_url, CMD_SPECIAL, packedArgs, postData, flags );
01443     return job;
01444 }
01445 
01446 // http post got redirected from http://host to http://host/ by TransferJob
01447 // We must do this redirection ourselves because redirections by the
01448 // slave change post jobs into get jobs.
01449 void TransferJobPrivate::slotPostRedirection()
01450 {
01451     Q_Q(TransferJob);
01452     kDebug(7007) << "TransferJob::slotPostRedirection(" << m_url << ")";
01453     // Tell the user about the new url.
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() ); // check that we're only called once
01483     Q_ASSERT( d->m_uploadOffset == 0 ); // no upload started yet
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   // check for end-of-data marker:
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   // Inspired from kmail's KMKernel::byteArrayToRemoteFile
01505   // send the data in 64 KB chunks
01506   const int MAX_CHUNK_SIZE = 64*1024;
01507   int remainingBytes = m_data.size() - m_uploadOffset;
01508   if( remainingBytes > MAX_CHUNK_SIZE ) {
01509     // send MAX_CHUNK_SIZE bytes to the receiver (deep copy)
01510     data = QByteArray( m_data.data() + m_uploadOffset, MAX_CHUNK_SIZE );
01511     m_uploadOffset += MAX_CHUNK_SIZE;
01512     //kDebug() << "Sending " << MAX_CHUNK_SIZE << " bytes ("
01513     //                << remainingBytes - MAX_CHUNK_SIZE << " bytes remain)\n";
01514   } else {
01515     // send the remaining bytes to the receiver (deep copy)
01516     data = QByteArray( m_data.data() + m_uploadOffset, remainingBytes );
01517     m_data = QByteArray();
01518     m_uploadOffset = 0;
01519     //kDebug() << "Sending " << remainingBytes << " bytes\n";
01520   }
01521 }
01522 
01523 StoredTransferJob *KIO::storedGet( const KUrl& url, LoadType reload, JobFlags flags )
01524 {
01525     // Send decoded path and encoded query
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     //kDebug(7007);
01579     if ( error() == KIO::ERR_IS_DIRECTORY )
01580     {
01581         // It is in fact a directory. This happens when HTTP redirects to FTP.
01582         // Due to the "protocol doesn't support listing" code in KRun, we
01583         // assumed it was a file.
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         // Return slave to the scheduler
01592         TransferJob::slotFinished();
01593     } else {
01594         //kDebug(7007) << "Redirection to " << m_redirectionURL;
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         // Return slave to the scheduler
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         //kDebug(7007) << src << "->" << dest;
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  * The FileCopyJob works according to the famous Bayern
01744  * 'Alternating Bitburger Protocol': we either drink a beer or we
01745  * we order a beer, but never both at the same time.
01746  * Translated to io-slaves: We alternate between receiving a block of data
01747  * and sending it away.
01748  */
01749 FileCopyJob::FileCopyJob(FileCopyJobPrivate &dd)
01750     : Job(dd)
01751 {
01752     //kDebug(7007);
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       // The if() below must be the same as the one in startBestCopyMethod
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       // No fast-move available, use copy + del.
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     //kDebug(7007);
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;  // CMD_RENAME by itself doesn't change permissions
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     //kDebug(7007);
01951 
01952     m_canResume = false;
01953     m_resumeAnswerSent = false;
01954     m_getJob = 0L; // for now
01955     m_putJob = put( m_dest, m_permissions, (m_flags | HideProgressInfo) /* no GUI */);
01956     //kDebug(7007) << "m_putJob=" << m_putJob << "m_dest=" << m_dest;
01957     if ( m_modificationTime.isValid() ) {
01958         m_putJob->setModificationTime( m_modificationTime );
01959     }
01960 
01961     // The first thing the put job will tell us is whether we can
01962     // resume or not (this is always emitted)
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         //kDebug(7007) << "'can resume' from PUT job. offset=" << KIO::number(offset);
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                 // Ask confirmation about resuming previous transfer
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; // No need for an answer
02008 
02009         if ( job == m_putJob )
02010         {
02011             m_getJob = KIO::get( m_src, NoReload, HideProgressInfo /* no GUI */ );
02012             //kDebug(7007) << "m_getJob=" << m_getJob << m_src;
02013             m_getJob->addMetaData( "errorPage", "false" );
02014             m_getJob->addMetaData( "AllowCompressedPage", "false" );
02015             // Set size in subjob. This helps if the slave doesn't emit totalSize.
02016             if ( m_sourceSize != (KIO::filesize_t)-1 )
02017                 m_getJob->setTotalAmount(KJob::Bytes, m_sourceSize);
02018             if (offset)
02019             {
02020                 //kDebug(7007) << "Setting metadata for resume to" << (unsigned long) offset;
02021                 // TODO KDE4: rename to seek or offset and document it
02022                 // This isn't used only for resuming, but potentially also for extracting (#72302).
02023                 m_getJob->addMetaData( "resume", KIO::number(offset) );
02024 
02025                 // Might or might not get emitted
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 ); // Progress info depends on get
02034             m_getJob->d_func()->internalResume(); // Order a beer
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 // copyjob
02042         {
02043             jobSlave(m_copyJob)->sendResumeAnswer( offset != 0 );
02044         }
02045     }
02046     else if ( job == m_getJob )
02047     {
02048         // Cool, the get job said ok, we can resume
02049         m_canResume = true;
02050         //kDebug(7007) << "'can resume' from the GET job -> we can resume";
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    //kDebug(7007) << "data size:" << data.size();
02062    assert(m_putJob);
02063    if (!m_putJob) return; // Don't crash
02064    m_getJob->d_func()->internalSuspend();
02065    m_putJob->d_func()->internalResume(); // Drink the beer
02066    m_buffer += data;
02067 
02068    // On the first set of data incoming, we tell the "put" slave about our
02069    // decision about resuming
02070    if (!m_resumeAnswerSent)
02071    {
02072        m_resumeAnswerSent = true;
02073        //kDebug(7007) << "(first time) -> send resume answer " << m_canResume;
02074        jobSlave(m_putJob)->sendResumeAnswer( m_canResume );
02075    }
02076 }
02077 
02078 void FileCopyJobPrivate::slotDataReq( KIO::Job * , QByteArray &data)
02079 {
02080    Q_Q(FileCopyJob);
02081    //kDebug(7007);
02082    if (!m_resumeAnswerSent && !m_getJob) {
02083        // This can't happen
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(); // Order more beer
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    //kDebug(7007) << "this=" << this << "job=" << job;
02109    removeSubjob(job);
02110    // Did job have an error ?
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        // If d->m_permissions == -1, keep the default permissions
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; // Finished
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/*no GUI*/ ); // Delete source
02170          addSubjob(d->m_delJob);
02171       }
02172    }
02173 
02174    if (job == d->m_getJob)
02175    {
02176        //kDebug(7007) << "m_getJob finished";
02177       d->m_getJob = 0; // No action required
02178       if (d->m_putJob)
02179           d->m_putJob->d_func()->internalResume();
02180    }
02181 
02182    if (job == d->m_putJob)
02183    {
02184        //kDebug(7007) << "m_putJob finished";
02185       d->m_putJob = 0;
02186       if (d->m_getJob)
02187       {
02188           // The get job is still running, probably after emitting data(QByteArray())
02189           // and before we receive its finished().
02190          d->m_getJob->d_func()->internalResume();
02191       }
02192       if (d->m_move)
02193       {
02194          d->m_delJob = file_delete( d->m_src, HideProgressInfo/*no GUI*/ ); // Delete source
02195          addSubjob(d->m_delJob);
02196       }
02197    }
02198 
02199    if (job == d->m_delJob)
02200    {
02201       d->m_delJob = 0; // Finished
02202    }
02203 
02204    if (job == d->m_chmodJob)
02205    {
02206        d->m_chmodJob = 0; // Finished
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); // isFile
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     // We couldn't set the args when calling the parent constructor,
02282     // so do it now.
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     // Emit progress info (takes care of emit processedSize and percent)
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             // const UDSEntry::ConstIterator end2 = entry.end();
02308             // UDSEntry::ConstIterator it2 = entry.find( KIO::UDSEntry::UDS_URL );
02309             // if ( it2 != end2 )
02310             if (entry.contains(KIO::UDSEntry::UDS_URL))
02311                 // itemURL = it2.value().toString();
02312                 itemURL = entry.stringValue(KIO::UDSEntry::UDS_URL);
02313             else { // no URL, use the name
02314                 itemURL = q->url();
02315                 const QString fileName = entry.stringValue(KIO::UDSEntry::UDS_NAME);
02316                 Q_ASSERT(!fileName.isEmpty()); // we'll recurse forever otherwise :)
02317                 itemURL.addPath(fileName);
02318             }
02319 
02320             if (entry.isDir() && !entry.isLink()) {
02321                 const QString filename = itemURL.fileName();
02322                 // skip hidden dirs when listing if requested
02323                 if (filename != ".." && filename != "." && (includeHidden || filename[0] != '.')) {
02324                     ListJob *job = ListJobPrivate::newJobNoUi(itemURL,
02325                                                true /*recursive*/,
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     // Not recursive, or top-level of recursive listing : return now (send . and .. as well)
02338     // exclusion of hidden files also requires the full sweep, but the case for full-listing
02339     // a single dir is probably common enough to justify the shortcut
02340     if (prefix.isNull() && includeHidden) {
02341         emit q->entries(q, list);
02342     } else {
02343         // cull the unwanted hidden dirs and/or parent dir references from the listing, then emit that
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             // Modify the name in the UDSEntry
02351             UDSEntry newone = *it;
02352             const QString filename = newone.stringValue( KIO::UDSEntry::UDS_NAME );
02353             // Avoid returning entries like subdir/. and subdir/.., but include . and .. for
02354             // the toplevel dir, and skip hidden files/dirs if that was requested
02355             if (  (prefix.isNull() || (filename != ".." && filename != ".") )
02356                   && (includeHidden || (filename[0] != '.') )  )
02357             {
02358                 // ## Didn't find a way to use the iterator instead of re-doing a key lookup
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     // Forward entries received by subjob - faking we received them ourselves
02371     Q_Q(ListJob);
02372     emit q->entries(q, list);
02373 }
02374 
02375 void ListJob::slotResult( KJob * job )
02376 {
02377     // If we can't list a subdir, the result is still ok
02378     // This is why we override Job::slotResult() - to skip error checking
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; // We'll remember that when the job finishes
02393     if (m_url.hasUser() && !url.hasUser() && (m_url.host().toLower() == url.host().toLower()))
02394         m_redirectionURL.setUser(m_url.user()); // Preserve user
02395     emit q->redirection( q, m_redirectionURL );
02396 }
02397 
02398 void ListJob::slotFinished()
02399 {
02400     Q_D(ListJob);
02401     // Support for listing archives as directories
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         // Return slave to the scheduler
02416         SimpleJob::slotFinished();
02417     } else {
02418 
02419         //kDebug(7007) << "Redirection to " << d->m_redirectionURL;
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         // Return slave to the scheduler
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    // Use multi-get
02553    // Scan all jobs in m_waitQueue
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    // Send number of URLs, (URL, metadata)*
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    // Add first job from m_waitQueue and add it to m_activeQueue
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       // Use normal get
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); // Anything else to do??
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; // Error
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()); // Preserve user
02650   get(d->m_currentEntry.id, d->m_redirectionURL, d->m_currentEntry.metaData); // Try again
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      // No redirection, tell the world that we are finished.
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         // All done
02672         TransferJob::slotFinished();
02673      }
02674      else
02675      {
02676         // return slave to pool
02677         // fetch new slave for first entry in d->m_waitQueue and call start
02678         // again.
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; // Error, unknown request!
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 // Never defined, never used - what's this code about?
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); // Open for reading and writing
02812    if (!fs)
02813       return 0;
02814 
02815    char buffer[401];
02816    bool ok = true;
02817 
02818   // CacheRevision
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    // URL
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; // Strip newline
02835       if (m_.url.url() != buffer)
02836       {
02837          ok = false; // Hash collision
02838       }
02839    }
02840 
02841    // Creation Date
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    // Expiration Date
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          // After the expire date we need to revalidate.
02864          if (!date || difftime(currentDate, date) >= 0)
02865             m_bMustRevalidate = true;
02866          m_expireDate = date;
02867       }
02868    }
02869 
02870    // ETag
02871    if (ok && (!fgets(buffer, 400, fs)))
02872       ok = false;
02873    if (ok)
02874    {
02875       m_etag = QString(buffer).trimmed();
02876    }
02877 
02878    // Last-Modified
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"

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal