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