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

KIO

job.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002     Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
00003                        David Faure <faure@kde.org>
00004                        Waldo Bastian <bastian@kde.org>
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License as published by the Free Software Foundation; either
00009     version 2 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Library General Public License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public License
00017     along with this library; see the file COPYING.LIB.  If not, write to
00018     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019     Boston, MA 02110-1301, USA.
00020 */
00021 
00022 #include "job.h"
00023 #include "job_p.h"
00024 
00025 #include <config.h>
00026 
00027 #include <sys/types.h>
00028 #include <sys/wait.h>
00029 #include <sys/stat.h>
00030 
00031 #include <assert.h>
00032 
00033 #include <signal.h>
00034 #include <stdlib.h>
00035 #include <stdio.h>
00036 #include <time.h>
00037 #include <unistd.h>
00038 extern "C" {
00039 #include <pwd.h>
00040 #include <grp.h>
00041 }
00042 #include <QtCore/QTimer>
00043 #include <QtCore/QFile>
00044 
00045 #include <kapplication.h>
00046 #include <kauthorized.h>
00047 #include <kglobal.h>
00048 #include <klocale.h>
00049 #include <kconfig.h>
00050 #include <kdebug.h>
00051 #include <kde_file.h>
00052 
00053 #include <errno.h>
00054 
00055 #include "jobuidelegate.h"
00056 #include "kmimetype.h"
00057 #include "slave.h"
00058 #include "scheduler.h"
00059 #include "kdirwatch.h"
00060 #include "kprotocolinfo.h"
00061 #include "kprotocolmanager.h"
00062 #include "filejob.h"
00063 
00064 #include "kssl/ksslcsessioncache.h"
00065 
00066 #include <kdirnotify.h>
00067 #include <ktemporaryfile.h>
00068 
00069 #ifdef Q_OS_UNIX
00070 #include <utime.h>
00071 #endif
00072 
00073 using namespace KIO;
00074 
00075 static inline Slave *jobSlave(SimpleJob *job)
00076 {
00077     return SimpleJobPrivate::get(job)->m_slave;
00078 }
00079 
00080 //this will update the report dialog with 5 Hz, I think this is fast enough, aleXXX
00081 #define REPORT_TIMEOUT 200
00082 
00083 #define KIO_ARGS QByteArray packedArgs; QDataStream stream( &packedArgs, QIODevice::WriteOnly ); stream
00084 
00085 Job::Job() : KCompositeJob(*new JobPrivate, 0)
00086 {
00087     setCapabilities( KJob::Killable | KJob::Suspendable );
00088 }
00089 
00090 Job::Job(JobPrivate &dd) : KCompositeJob(dd, 0)
00091 {
00092     setCapabilities( KJob::Killable | KJob::Suspendable );
00093 }
00094 
00095 Job::~Job()
00096 {
00097 }
00098 
00099 JobUiDelegate *Job::ui() const
00100 {
00101     return static_cast<JobUiDelegate*>( uiDelegate() );
00102 }
00103 
00104 bool Job::addSubjob(KJob *jobBase)
00105 {
00106     //kDebug(7007) << "addSubjob(" << jobBase << ") this=" << this;
00107 
00108     bool ok = KCompositeJob::addSubjob( jobBase );
00109     KIO::Job *job = dynamic_cast<KIO::Job*>( jobBase );
00110     if (ok && job) {
00111         // Forward information from that subjob.
00112         connect( job, SIGNAL(speed( KJob*, unsigned long )),
00113                  SLOT(slotSpeed(KJob*, unsigned long)) );
00114 
00115         if (ui() && job->ui()) {
00116             job->ui()->setWindow( ui()->window() );
00117             job->ui()->updateUserTimestamp( ui()->userTimestamp() );
00118         }
00119     }
00120     return ok;
00121 }
00122 
00123 bool Job::removeSubjob( KJob *jobBase )
00124 {
00125     //kDebug(7007) << "removeSubjob(" << jobBase << ") this=" << this << "subjobs=" << subjobs().count();
00126     return KCompositeJob::removeSubjob( jobBase );
00127 }
00128 
00129 void JobPrivate::emitMoving(KIO::Job * job, const KUrl &src, const KUrl &dest)
00130 {
00131     emit job->description(job, i18nc("@title job","Moving"),
00132                           qMakePair(i18n("Source"), src.prettyUrl()),
00133                           qMakePair(i18n("Destination"), dest.prettyUrl()));
00134 }
00135 
00136 void JobPrivate::emitCopying(KIO::Job * job, const KUrl &src, const KUrl &dest)
00137 {
00138     emit job->description(job, i18nc("@title job","Copying"),
00139                           qMakePair(i18n("Source"), src.prettyUrl()),
00140                           qMakePair(i18n("Destination"), dest.prettyUrl()));
00141 }
00142 
00143 void JobPrivate::emitCreatingDir(KIO::Job * job, const KUrl &dir)
00144 {
00145     emit job->description(job, i18nc("@title job","Creating directory"),
00146                           qMakePair(i18n("Directory"), dir.prettyUrl()));
00147 }
00148 
00149 void JobPrivate::emitDeleting(KIO::Job *job, const KUrl &url)
00150 {
00151     emit job->description(job, i18nc("@title job","Deleting"),
00152                           qMakePair(i18n("File"), url.prettyUrl()));
00153 }
00154 
00155 void JobPrivate::emitStating(KIO::Job *job, const KUrl &url)
00156 {
00157     emit job->description(job, i18nc("@title job","Stating"),
00158                           qMakePair(i18n("File"), url.prettyUrl()));
00159 }
00160 
00161 void JobPrivate::emitTransferring(KIO::Job *job, const KUrl &url)
00162 {
00163     emit job->description(job, i18nc("@title job","Transferring"),
00164                           qMakePair(i18n("Source"), url.prettyUrl()));
00165 }
00166 
00167 void JobPrivate::emitMounting(KIO::Job * job, const QString &dev, const QString &point)
00168 {
00169     emit job->description(job, i18nc("@title job","Mounting"),
00170                           qMakePair(i18n("Device"), dev),
00171                           qMakePair(i18n("Mountpoint"), point));
00172 }
00173 
00174 void JobPrivate::emitUnmounting(KIO::Job * job, const QString &point)
00175 {
00176     emit job->description(job, i18nc("@title job","Unmounting"),
00177                           qMakePair(i18n("Mountpoint"), point));
00178 }
00179 
00180 bool Job::doKill()
00181 {
00182   kDebug(7007) << "Job::kill this=" << this << " " << metaObject()->className();
00183   // kill all subjobs, without triggering their result slot
00184   const QList<KJob *> &jobs = subjobs();
00185   QList<KJob *>::const_iterator it = jobs.constBegin();
00186   const QList<KJob *>::const_iterator end = jobs.constEnd();
00187   for ( ; it != end ; ++it )
00188     (*it)->kill( KJob::Quietly );
00189   clearSubjobs();
00190 
00191   return true;
00192 }
00193 
00194 bool Job::doSuspend()
00195 {
00196     const QList<KJob *> &jobs = subjobs();
00197     QList<KJob *>::const_iterator it = jobs.constBegin();
00198     const QList<KJob *>::const_iterator end = jobs.constEnd();
00199     for ( ; it != end ; ++it )
00200     {
00201         if (!(*it)->suspend())
00202             return false;
00203     }
00204 
00205     return true;
00206 }
00207 
00208 bool Job::doResume()
00209 {
00210     const QList<KJob *> &jobs = subjobs();
00211     QList<KJob *>::const_iterator it = jobs.constBegin();
00212     const QList<KJob *>::const_iterator end = jobs.constEnd();
00213     for ( ; it != end ; ++it )
00214     {
00215         if (!(*it)->resume())
00216             return false;
00217     }
00218 
00219     return true;
00220 }
00221 
00222 void JobPrivate::slotSpeed( KJob*, unsigned long speed )
00223 {
00224     //kDebug(7007) << "Job::slotSpeed " << speed;
00225     q_func()->emitSpeed( speed );
00226 }
00227 
00228 //Job::errorString is implemented in global.cpp
00229 
00230 void Job::showErrorDialog( QWidget *parent )
00231 {
00232     if ( ui() )
00233     {
00234         ui()->setWindow( parent );
00235         ui()->showErrorMessage();
00236     }
00237     else
00238     {
00239         kError() << errorString() << endl;
00240     }
00241 }
00242 
00243 bool Job::isInteractive() const
00244 {
00245   return uiDelegate() != 0;
00246 }
00247 
00248 void Job::setParentJob(Job* job)
00249 {
00250   Q_D(Job);
00251   Q_ASSERT(d->m_parentJob == 0L);
00252   Q_ASSERT(job);
00253   d->m_parentJob = job;
00254 }
00255 
00256 Job* Job::parentJob() const
00257 {
00258   return d_func()->m_parentJob;
00259 }
00260 
00261 MetaData Job::metaData() const
00262 {
00263     return d_func()->m_incomingMetaData;
00264 }
00265 
00266 QString Job::queryMetaData(const QString &key)
00267 {
00268     return d_func()->m_incomingMetaData.value(key, QString());
00269 }
00270 
00271 void Job::setMetaData( const KIO::MetaData &_metaData)
00272 {
00273     Q_D(Job);
00274     d->m_outgoingMetaData = _metaData;
00275 }
00276 
00277 void Job::addMetaData( const QString &key, const QString &value)
00278 {
00279     d_func()->m_outgoingMetaData.insert(key, value);
00280 }
00281 
00282 void Job::addMetaData( const QMap<QString,QString> &values)
00283 {
00284     Q_D(Job);
00285     QMap<QString,QString>::const_iterator it = values.begin();
00286     for(;it != values.end(); ++it)
00287         d->m_outgoingMetaData.insert(it.key(), it.value());
00288 }
00289 
00290 void Job::mergeMetaData( const QMap<QString,QString> &values)
00291 {
00292     Q_D(Job);
00293     QMap<QString,QString>::const_iterator it = values.begin();
00294     for(;it != values.end(); ++it)
00295         // there's probably a faster way
00296         if ( !d->m_outgoingMetaData.contains( it.key() ) )
00297             d->m_outgoingMetaData.insert( it.key(), it.value() );
00298 }
00299 
00300 MetaData Job::outgoingMetaData() const
00301 {
00302     return d_func()->m_outgoingMetaData;
00303 }
00304 
00305 SimpleJob::SimpleJob(SimpleJobPrivate &dd)
00306   : Job(dd)
00307 {
00308     d_func()->simpleJobInit();
00309 }
00310 
00311 void SimpleJobPrivate::simpleJobInit()
00312 {
00313     Q_Q(SimpleJob);
00314     if (!m_url.isValid())
00315     {
00316         q->setError( ERR_MALFORMED_URL );
00317         q->setErrorText( m_url.url() );
00318         QTimer::singleShot(0, q, SLOT(slotFinished()) );
00319         return;
00320     }
00321 
00322     Scheduler::doJob(q);
00323 }
00324 
00325 
00326 bool SimpleJob::doKill()
00327 {
00328     Q_D(SimpleJob);
00329     Scheduler::cancelJob( this ); // deletes the slave if not 0
00330     d->m_slave = 0; // -> set to 0
00331     return Job::doKill();
00332 }
00333 
00334 bool SimpleJob::doSuspend()
00335 {
00336     Q_D(SimpleJob);
00337     if ( d->m_slave )
00338         d->m_slave->suspend();
00339     return Job::doSuspend();
00340 }
00341 
00342 bool SimpleJob::doResume()
00343 {
00344     Q_D(SimpleJob);
00345     if ( d->m_slave )
00346         d->m_slave->resume();
00347     return Job::doResume();
00348 }
00349 
00350 const KUrl& SimpleJob::url() const
00351 {
00352     return d_func()->m_url;
00353 }
00354 
00355 void SimpleJob::putOnHold()
00356 {
00357     Q_D(SimpleJob);
00358     Q_ASSERT( d->m_slave );
00359     if ( d->m_slave )
00360     {
00361         Scheduler::putSlaveOnHold(this, d->m_url);
00362         d->m_slave = 0;
00363     }
00364     kill( Quietly );
00365 }
00366 
00367 void SimpleJob::removeOnHold()
00368 {
00369     Scheduler::removeSlaveOnHold();
00370 }
00371 
00372 SimpleJob::~SimpleJob()
00373 {
00374     Q_D(SimpleJob);
00375     if (d->m_slave) // was running
00376     {
00377         kDebug(7007) << "SimpleJob::~SimpleJob: Killing running job in destructor!"  << kBacktrace();
00378 #if 0
00379         d->m_slave->kill();
00380         Scheduler::jobFinished( this, d->m_slave ); // deletes the slave
00381 #endif
00382         Scheduler::cancelJob( this );
00383         d->m_slave = 0; // -> set to 0
00384     }
00385 }
00386 
00387 void SimpleJobPrivate::start(Slave *slave)
00388 {
00389     Q_Q(SimpleJob);
00390     m_slave = slave;
00391 
00392     q->connect( slave, SIGNAL( error( int , const QString & ) ),
00393                 SLOT( slotError( int , const QString & ) ) );
00394 
00395     q->connect( slave, SIGNAL( warning( const QString & ) ),
00396                 SLOT( slotWarning( const QString & ) ) );
00397 
00398     q->connect( slave, SIGNAL( infoMessage( const QString & ) ),
00399                 SLOT( _k_slotSlaveInfoMessage( const QString & ) ) );
00400 
00401     q->connect( slave, SIGNAL( connected() ),
00402                 SLOT( slotConnected() ) );
00403 
00404     q->connect( slave, SIGNAL( finished() ),
00405                 SLOT( slotFinished() ) );
00406 
00407     if ((m_extraFlags & EF_TransferJobDataSent) == 0)
00408     {
00409         q->connect( slave, SIGNAL( totalSize( KIO::filesize_t ) ),
00410                     SLOT( slotTotalSize( KIO::filesize_t ) ) );
00411 
00412         q->connect( slave, SIGNAL( processedSize( KIO::filesize_t ) ),
00413                     SLOT( slotProcessedSize( KIO::filesize_t ) ) );
00414 
00415         q->connect( slave, SIGNAL( speed( unsigned long ) ),
00416                     SLOT( slotSpeed( unsigned long ) ) );
00417     }
00418     q->connect( slave, SIGNAL(metaData( const KIO::MetaData& ) ),
00419                 SLOT( slotMetaData( const KIO::MetaData& ) ) );
00420 
00421     if (ui() && ui()->window())
00422     {
00423         m_outgoingMetaData.insert("window-id", QString::number((long)ui()->window()->winId()));
00424     }
00425 
00426     if (ui() && ui()->userTimestamp())
00427     {
00428         m_outgoingMetaData.insert("user-timestamp", QString::number(ui()->userTimestamp()));
00429     }
00430 
00431     QString sslSession = KSSLCSessionCache::getSessionForUrl(m_url);
00432     if ( !sslSession.isNull() )
00433     {
00434         m_outgoingMetaData.insert("ssl_session_id", sslSession);
00435     }
00436 
00437     if (ui() == 0)              // not interactive
00438     {
00439         m_outgoingMetaData.insert("no-auth-prompt", "true");
00440     }
00441 
00442     if (!m_outgoingMetaData.isEmpty())
00443     {
00444         KIO_ARGS << m_outgoingMetaData;
00445         slave->send( CMD_META_DATA, packedArgs );
00446     }
00447 
00448     if (!m_subUrl.isEmpty())
00449     {
00450        KIO_ARGS << m_subUrl;
00451        slave->send( CMD_SUBURL, packedArgs );
00452     }
00453 
00454     slave->send( m_command, m_packedArgs );
00455 }
00456 
00457 void SimpleJobPrivate::slaveDone()
00458 {
00459     Q_Q(SimpleJob);
00460     if (!m_slave) return;
00461     q->disconnect(m_slave); // Remove all signals between slave and job
00462     Scheduler::jobFinished( q, m_slave );
00463     m_slave = 0;
00464 }
00465 
00466 void SimpleJob::slotFinished( )
00467 {
00468     Q_D(SimpleJob);
00469     // Return slave to the scheduler
00470     d->slaveDone();
00471 
00472     if (!hasSubjobs())
00473     {
00474         if ( !error() && (d->m_command == CMD_MKDIR || d->m_command == CMD_RENAME ) )
00475         {
00476             if ( d->m_command == CMD_MKDIR )
00477             {
00478                 KUrl urlDir( url() );
00479                 urlDir.setPath( urlDir.directory() );
00480                 org::kde::KDirNotify::emitFilesAdded( urlDir.url() );
00481             }
00482             else /*if ( m_command == CMD_RENAME )*/
00483             {
00484                 KUrl src, dst;
00485                 QDataStream str( d->m_packedArgs );
00486                 str >> src >> dst;
00487                 if( src.directory() == dst.directory() ) // For the user, moving isn't renaming. Only renaming is.
00488                     org::kde::KDirNotify::emitFileRenamed( src.url(), dst.url() );
00489             }
00490         }
00491         emitResult();
00492     }
00493 }
00494 
00495 void SimpleJob::slotError( int err, const QString & errorText )
00496 {
00497     Q_D(SimpleJob);
00498     setError( err );
00499     setErrorText( errorText );
00500     if ((error() == ERR_UNKNOWN_HOST) && d->m_url.host().isEmpty())
00501        setErrorText( QString() );
00502     // error terminates the job
00503     slotFinished();
00504 }
00505 
00506 void SimpleJob::slotWarning( const QString & errorText )
00507 {
00508     emit warning( this, errorText );
00509 }
00510 
00511 void SimpleJobPrivate::_k_slotSlaveInfoMessage( const QString & msg )
00512 {
00513     emit q_func()->infoMessage( q_func(), msg );
00514 }
00515 
00516 void SimpleJobPrivate::slotConnected()
00517 {
00518     emit q_func()->connected( q_func() );
00519 }
00520 
00521 void SimpleJobPrivate::slotTotalSize( KIO::filesize_t size )
00522 {
00523     Q_Q(SimpleJob);
00524     if (size > q->totalAmount(KJob::Bytes))
00525     {
00526         q->setTotalAmount(KJob::Bytes, size);
00527     }
00528 }
00529 
00530 void SimpleJobPrivate::slotProcessedSize( KIO::filesize_t size )
00531 {
00532     Q_Q(SimpleJob);
00533     //kDebug(7007) << "SimpleJob::slotProcessedSize " << KIO::number(size);
00534     q->setProcessedAmount(KJob::Bytes, size);
00535 }
00536 
00537 void SimpleJobPrivate::slotSpeed( unsigned long speed )
00538 {
00539     //kDebug(7007) << "SimpleJob::slotSpeed( " << speed << " )";
00540     q_func()->emitSpeed( speed );
00541 }
00542 
00543 void SimpleJob::slotMetaData( const KIO::MetaData &_metaData )
00544 {
00545     Q_D(SimpleJob);
00546     d->m_incomingMetaData += _metaData;
00547 }
00548 
00549 void SimpleJob::storeSSLSessionFromJob(const KUrl &redirectionURL)
00550 {
00551     Q_D(SimpleJob);
00552     QString sslSession = queryMetaData("ssl_session_id");
00553 
00554     if ( !sslSession.isNull() ) {
00555         const KUrl &queryURL = redirectionURL.isEmpty() ? d->m_url : redirectionURL;
00556         KSSLCSessionCache::putSessionForUrl(queryURL, sslSession);
00557     }
00558 }
00559 
00561 class KIO::MkdirJobPrivate: public SimpleJobPrivate
00562 {
00563 public:
00564     MkdirJobPrivate(const KUrl& url, int command, const QByteArray &packedArgs)
00565         : SimpleJobPrivate(url, command, packedArgs)
00566         { }
00567     KUrl m_redirectionURL;
00568     void slotRedirection(const KUrl &url);
00569 
00576     virtual void start( Slave *slave );
00577 
00578     Q_DECLARE_PUBLIC(MkdirJob)
00579 
00580     static inline MkdirJob *newJob(const KUrl& url, int command, const QByteArray &packedArgs)
00581     {
00582         MkdirJob *job = new MkdirJob(*new MkdirJobPrivate(url, command, packedArgs));
00583         job->setUiDelegate(new JobUiDelegate);
00584         return job;
00585     }
00586 };
00587 
00588 MkdirJob::MkdirJob(MkdirJobPrivate &dd)
00589     : SimpleJob(dd)
00590 {
00591 }
00592 
00593 MkdirJob::~MkdirJob()
00594 {
00595 }
00596 
00597 void MkdirJobPrivate::start(Slave *slave)
00598 {
00599     Q_Q(MkdirJob);
00600     q->connect( slave, SIGNAL( redirection(const KUrl &) ),
00601                 SLOT( slotRedirection(const KUrl &) ) );
00602 
00603     SimpleJobPrivate::start(slave);
00604 }
00605 
00606 // Slave got a redirection request
00607 void MkdirJobPrivate::slotRedirection( const KUrl &url)
00608 {
00609      Q_Q(MkdirJob);
00610      kDebug(7007) << "MkdirJob::slotRedirection(" << url << ")";
00611      if (!KAuthorized::authorizeUrlAction("redirect", m_url, url))
00612      {
00613          kWarning(7007) << "MkdirJob: Redirection from " << m_url << " to " << url << " REJECTED!";
00614          q->setError( ERR_ACCESS_DENIED );
00615          q->setErrorText( url.prettyUrl() );
00616          return;
00617      }
00618      m_redirectionURL = url; // We'll remember that when the job finishes
00619      if (m_url.hasUser() && !url.hasUser() && (m_url.host().toLower() == url.host().toLower()))
00620          m_redirectionURL.setUser(m_url.user()); // Preserve user
00621      // Tell the user that we haven't finished yet
00622      emit q->redirection(q, m_redirectionURL);
00623 }
00624 
00625 void MkdirJob::slotFinished()
00626 {
00627     Q_D(MkdirJob);
00628     if ( d->m_redirectionURL.isEmpty() || !d->m_redirectionURL.isValid())
00629     {
00630         // Return slave to the scheduler
00631         SimpleJob::slotFinished();
00632     } else {
00633         //kDebug(7007) << "MkdirJob: Redirection to " << m_redirectionURL;
00634         if (queryMetaData("permanent-redirect")=="true")
00635             emit permanentRedirection(this, d->m_url, d->m_redirectionURL);
00636         KUrl dummyUrl;
00637         int permissions;
00638         QDataStream istream( d->m_packedArgs );
00639         istream >> dummyUrl >> permissions;
00640 
00641         d->m_url = d->m_redirectionURL;
00642         d->m_redirectionURL = KUrl();
00643         d->m_packedArgs.truncate(0);
00644         QDataStream stream( &d->m_packedArgs, QIODevice::WriteOnly );
00645         stream << d->m_url << permissions;
00646 
00647         // Return slave to the scheduler
00648         d->slaveDone();
00649         Scheduler::doJob(this);
00650     }
00651 }
00652 
00653 SimpleJob *KIO::mkdir( const KUrl& url, int permissions )
00654 {
00655     //kDebug(7007) << "mkdir " << url;
00656     KIO_ARGS << url << permissions;
00657     return MkdirJobPrivate::newJob(url, CMD_MKDIR, packedArgs);
00658 }
00659 
00660 SimpleJob *KIO::rmdir( const KUrl& url )
00661 {
00662     //kDebug(7007) << "rmdir " << url;
00663     KIO_ARGS << url << qint8(false); // isFile is false
00664     return SimpleJobPrivate::newJob(url, CMD_DEL, packedArgs);
00665 }
00666 
00667 SimpleJob *KIO::chmod( const KUrl& url, int permissions )
00668 {
00669     //kDebug(7007) << "chmod " << url;
00670     KIO_ARGS << url << permissions;
00671     return SimpleJobPrivate::newJob(url, CMD_CHMOD, packedArgs);
00672 }
00673 
00674 SimpleJob *KIO::chown( const KUrl& url, const QString& owner, const QString& group )
00675 {
00676     KIO_ARGS << url << owner << group;
00677     return SimpleJobPrivate::newJob(url, CMD_CHOWN, packedArgs);
00678 }
00679 
00680 SimpleJob *KIO::setModificationTime( const KUrl& url, const QDateTime& mtime )
00681 {
00682     //kDebug(7007) << "setModificationTime " << url << " " << mtime;
00683     KIO_ARGS << url << mtime;
00684     return SimpleJobPrivate::newJobNoUi(url, CMD_SETMODIFICATIONTIME, packedArgs);
00685 }
00686 
00687 SimpleJob *KIO::rename( const KUrl& src, const KUrl & dest, JobFlags flags )
00688 {
00689     //kDebug(7007) << "rename " << src << " " << dest;
00690     KIO_ARGS << src << dest << (qint8) (flags & Overwrite);
00691     return SimpleJobPrivate::newJob(src, CMD_RENAME, packedArgs);
00692 }
00693 
00694 SimpleJob *KIO::symlink( const QString& target, const KUrl & dest, JobFlags flags )
00695 {
00696     //kDebug(7007) << "symlink target=" << target << " " << dest;
00697     KIO_ARGS << target << dest << (qint8) (flags & Overwrite);
00698     return SimpleJobPrivate::newJob(dest, CMD_SYMLINK, packedArgs, flags);
00699 }
00700 
00701 SimpleJob *KIO::special(const KUrl& url, const QByteArray & data, JobFlags flags)
00702 {
00703     //kDebug(7007) << "special " << url;
00704     return SimpleJobPrivate::newJob(url, CMD_SPECIAL, data, flags);
00705 }
00706 
00707 SimpleJob *KIO::mount( bool ro, const QByteArray& fstype, const QString& dev, const QString& point, JobFlags flags )
00708 {
00709     KIO_ARGS << int(1) << qint8( ro ? 1 : 0 )
00710              << QString::fromLatin1(fstype) << dev << point;
00711     SimpleJob *job = special( KUrl("file:/"), packedArgs, flags );
00712     if (!(flags & HideProgressInfo)) {
00713         KIO::JobPrivate::emitMounting(job, dev, point);
00714     }
00715     return job;
00716 }
00717 
00718 SimpleJob *KIO::unmount( const QString& point, JobFlags flags )
00719 {
00720     KIO_ARGS << int(2) << point;
00721     SimpleJob *job = special( KUrl("file:/"), packedArgs, flags );
00722     if (!(flags & HideProgressInfo)) {
00723         KIO::JobPrivate::emitUnmounting(job, point);
00724     }
00725     return job;
00726 }
00727 
00728 
00729 
00731 
00732 class KIO::StatJobPrivate: public SimpleJobPrivate
00733 {
00734 public:
00735     inline StatJobPrivate(const KUrl& url, int command, const QByteArray &packedArgs)
00736         : SimpleJobPrivate(url, command, packedArgs), m_bSource(true), m_details(2)
00737         {}
00738 
00739     UDSEntry m_statResult;
00740     KUrl m_redirectionURL;
00741     bool m_bSource;
00742     short int m_details;
00743     void slotStatEntry( const KIO::UDSEntry & entry );
00744     void slotRedirection( const KUrl &url);
00745 
00752     virtual void start( Slave *slave );
00753 
00754     Q_DECLARE_PUBLIC(StatJob)
00755 
00756     static inline StatJob *newJob(const KUrl& url, int command, const QByteArray &packedArgs,
00757         JobFlags flags )
00758     {
00759         StatJob *job = new StatJob(*new StatJobPrivate(url, command, packedArgs));
00760         job->setUiDelegate(new JobUiDelegate);
00761         if (!(flags & HideProgressInfo)) {
00762             KIO::getJobTracker()->registerJob(job);
00763             emitStating(job, url);
00764         }
00765         return job;
00766     }
00767 };
00768 
00769 StatJob::StatJob(StatJobPrivate &dd)
00770     : SimpleJob(dd)
00771 {
00772 }
00773 
00774 StatJob::~StatJob()
00775 {
00776 }
00777 
00778 void StatJob::setSide( bool source )
00779 {
00780     d_func()->m_bSource = source;
00781 }
00782 
00783 void StatJob::setSide( StatSide side )
00784 {
00785     d_func()->m_bSource = side == SourceSide;
00786 }
00787 
00788 void StatJob::setDetails( short int details )
00789 {
00790     d_func()->m_details = details;
00791 }
00792 
00793 const UDSEntry & StatJob::statResult() const
00794 {
00795     return d_func()->m_statResult;
00796 }
00797 
00798 void StatJobPrivate::start(Slave *slave)
00799 {
00800     Q_Q(StatJob);
00801     m_outgoingMetaData.insert( "statSide", m_bSource ? "source" : "dest" );
00802     m_outgoingMetaData.insert( "details", QString::number(m_details) );
00803 
00804     q->connect( slave, SIGNAL( statEntry( const KIO::UDSEntry& ) ),
00805              SLOT( slotStatEntry( const KIO::UDSEntry & ) ) );
00806     q->connect( slave, SIGNAL( redirection(const KUrl &) ),
00807              SLOT( slotRedirection(const KUrl &) ) );
00808 
00809     SimpleJobPrivate::start(slave);
00810 }
00811 
00812 void StatJobPrivate::slotStatEntry( const KIO::UDSEntry & entry )
00813 {
00814     //kDebug(7007) << "StatJob::slotStatEntry";
00815     m_statResult = entry;
00816 }
00817 
00818 // Slave got a redirection request
00819 void StatJobPrivate::slotRedirection( const KUrl &url)
00820 {
00821      Q_Q(StatJob);
00822      kDebug(7007) << "StatJob::slotRedirection(" << url << ")";
00823      if (!KAuthorized::authorizeUrlAction("redirect", m_url, url))
00824      {
00825        kWarning(7007) << "StatJob: Redirection from " << m_url << " to " << url << " REJECTED!";
00826        q->setError( ERR_ACCESS_DENIED );
00827        q->setErrorText( url.prettyUrl() );
00828        return;
00829      }
00830      m_redirectionURL = url; // We'll remember that when the job finishes
00831      if (m_url.hasUser() && !url.hasUser() && (m_url.host().toLower() == url.host().toLower()))
00832         m_redirectionURL.setUser(m_url.user()); // Preserve user
00833      // Tell the user that we haven't finished yet
00834      emit q->redirection(q, m_redirectionURL);
00835 }
00836 
00837 void StatJob::slotFinished()
00838 {
00839     Q_D(StatJob);
00840     if ( d->m_redirectionURL.isEmpty() || !d->m_redirectionURL.isValid())
00841     {
00842         // Return slave to the scheduler
00843         SimpleJob::slotFinished();
00844     } else {
00845         //kDebug(7007) << "StatJob: Redirection to " << m_redirectionURL;
00846         if (queryMetaData("permanent-redirect")=="true")
00847             emit permanentRedirection(this, d->m_url, d->m_redirectionURL);
00848         d->m_url = d->m_redirectionURL;
00849         d->m_redirectionURL = KUrl();
00850         d->m_packedArgs.truncate(0);
00851         QDataStream stream( &d->m_packedArgs, QIODevice::WriteOnly );
00852         stream << d->m_url;
00853 
00854         // Return slave to the scheduler
00855         d->slaveDone();
00856         Scheduler::doJob(this);
00857     }
00858 }
00859 
00860 void StatJob::slotMetaData( const KIO::MetaData &_metaData)
00861 {
00862     Q_D(StatJob);
00863     SimpleJob::slotMetaData(_metaData);
00864     storeSSLSessionFromJob(d->m_redirectionURL);
00865 }
00866 
00867 StatJob *KIO::stat(const KUrl& url, JobFlags flags)
00868 {
00869     // Assume sideIsSource. Gets are more common than puts.
00870     return stat( url, StatJob::SourceSide, 2, flags );
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->