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

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
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  •     Sodep
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.9-20090814
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