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