1 /* This file is part of the KDE libraries
2 Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
3 David Faure <faure@kde.org>
4 Waldo Bastian <bastian@kde.org>
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
27 #include <sys/types.h>
42 #include <QtCore/QTimer>
43 #include <QtCore/QFile>
45 #include <kapplication.h>
46 #include <kauthorized.h>
55 #include "jobuidelegate.h"
56 #include "kmimetype.h"
58 #include "scheduler.h"
59 #include "kdirwatch.h"
60 #include "kprotocolinfo.h"
61 #include "kprotocolmanager.h"
64 #include "kssl/ksslcsessioncache.h"
66 #include <kdirnotify.h>
67 #include <ktemporaryfile.h>
71 static inline Slave
*jobSlave(SimpleJob
*job
)
73 return SimpleJobPrivate::get(job
)->m_slave
;
76 //this will update the report dialog with 5 Hz, I think this is fast enough, aleXXX
77 #define REPORT_TIMEOUT 200
79 #define KIO_ARGS QByteArray packedArgs; QDataStream stream( &packedArgs, QIODevice::WriteOnly ); stream
81 Job::Job() : KCompositeJob(*new JobPrivate
, 0)
83 setCapabilities( KJob::Killable
| KJob::Suspendable
);
86 Job::Job(JobPrivate
&dd
) : KCompositeJob(dd
, 0)
88 setCapabilities( KJob::Killable
| KJob::Suspendable
);
95 JobUiDelegate
*Job::ui() const
97 return static_cast<JobUiDelegate
*>( uiDelegate() );
100 bool Job::addSubjob(KJob
*jobBase
)
102 //kDebug(7007) << "addSubjob(" << jobBase << ") this=" << this;
104 bool ok
= KCompositeJob::addSubjob( jobBase
);
105 KIO::Job
*job
= dynamic_cast<KIO::Job
*>( jobBase
);
107 // Copy metadata into subjob (e.g. window-id, user-timestamp etc.)
109 job
->mergeMetaData(d
->m_outgoingMetaData
);
111 // Forward information from that subjob.
112 connect(job
, SIGNAL(speed(KJob
*,ulong
)),
113 SLOT(slotSpeed(KJob
*,ulong
)));
115 if (ui() && job
->ui()) {
116 job
->ui()->setWindow( ui()->window() );
117 job
->ui()->updateUserTimestamp( ui()->userTimestamp() );
123 bool Job::removeSubjob( KJob
*jobBase
)
125 //kDebug(7007) << "removeSubjob(" << jobBase << ") this=" << this << "subjobs=" << subjobs().count();
126 return KCompositeJob::removeSubjob( jobBase
);
129 void JobPrivate::emitMoving(KIO::Job
* job
, const KUrl
&src
, const KUrl
&dest
)
131 emit job
->description(job
, i18nc("@title job","Moving"),
132 qMakePair(i18nc("The source of a file operation", "Source"), src
.prettyUrl()),
133 qMakePair(i18nc("The destination of a file operation", "Destination"), dest
.prettyUrl()));
136 void JobPrivate::emitCopying(KIO::Job
* job
, const KUrl
&src
, const KUrl
&dest
)
138 emit job
->description(job
, i18nc("@title job","Copying"),
139 qMakePair(i18nc("The source of a file operation", "Source"), src
.prettyUrl()),
140 qMakePair(i18nc("The destination of a file operation", "Destination"), dest
.prettyUrl()));
143 void JobPrivate::emitCreatingDir(KIO::Job
* job
, const KUrl
&dir
)
145 emit job
->description(job
, i18nc("@title job","Creating directory"),
146 qMakePair(i18n("Directory"), dir
.prettyUrl()));
149 void JobPrivate::emitDeleting(KIO::Job
*job
, const KUrl
&url
)
151 emit job
->description(job
, i18nc("@title job","Deleting"),
152 qMakePair(i18n("File"), url
.prettyUrl()));
155 void JobPrivate::emitStating(KIO::Job
*job
, const KUrl
&url
)
157 emit job
->description(job
, i18nc("@title job","Examining"),
158 qMakePair(i18n("File"), url
.prettyUrl()));
161 void JobPrivate::emitTransferring(KIO::Job
*job
, const KUrl
&url
)
163 emit job
->description(job
, i18nc("@title job","Transferring"),
164 qMakePair(i18nc("The source of a file operation", "Source"), url
.prettyUrl()));
167 void JobPrivate::emitMounting(KIO::Job
* job
, const QString
&dev
, const QString
&point
)
169 emit job
->description(job
, i18nc("@title job","Mounting"),
170 qMakePair(i18n("Device"), dev
),
171 qMakePair(i18n("Mountpoint"), point
));
174 void JobPrivate::emitUnmounting(KIO::Job
* job
, const QString
&point
)
176 emit job
->description(job
, i18nc("@title job","Unmounting"),
177 qMakePair(i18n("Mountpoint"), point
));
182 // kill all subjobs, without triggering their result slot
183 Q_FOREACH( KJob
* it
, subjobs()) {
184 it
->kill( KJob::Quietly
);
191 bool Job::doSuspend()
193 Q_FOREACH(KJob
* it
, subjobs()) {
203 Q_FOREACH ( KJob
* it
, subjobs() )
212 void JobPrivate::slotSpeed( KJob
*, unsigned long speed
)
214 //kDebug(7007) << speed;
215 q_func()->emitSpeed( speed
);
218 //Job::errorString is implemented in global.cpp
220 void Job::showErrorDialog( QWidget
*parent
)
224 ui()->setWindow( parent
);
225 ui()->showErrorMessage();
229 kError() << errorString();
233 bool Job::isInteractive() const
235 return uiDelegate() != 0;
238 void Job::setParentJob(Job
* job
)
241 Q_ASSERT(d
->m_parentJob
== 0L);
243 d
->m_parentJob
= job
;
246 Job
* Job::parentJob() const
248 return d_func()->m_parentJob
;
251 MetaData
Job::metaData() const
253 return d_func()->m_incomingMetaData
;
256 QString
Job::queryMetaData(const QString
&key
)
258 return d_func()->m_incomingMetaData
.value(key
, QString());
261 void Job::setMetaData( const KIO::MetaData
&_metaData
)
264 d
->m_outgoingMetaData
= _metaData
;
267 void Job::addMetaData( const QString
&key
, const QString
&value
)
269 d_func()->m_outgoingMetaData
.insert(key
, value
);
272 void Job::addMetaData( const QMap
<QString
,QString
> &values
)
275 QMap
<QString
,QString
>::const_iterator it
= values
.begin();
276 for(;it
!= values
.end(); ++it
)
277 d
->m_outgoingMetaData
.insert(it
.key(), it
.value());
280 void Job::mergeMetaData( const QMap
<QString
,QString
> &values
)
283 QMap
<QString
,QString
>::const_iterator it
= values
.begin();
284 for(;it
!= values
.end(); ++it
)
285 // there's probably a faster way
286 if ( !d
->m_outgoingMetaData
.contains( it
.key() ) )
287 d
->m_outgoingMetaData
.insert( it
.key(), it
.value() );
290 MetaData
Job::outgoingMetaData() const
292 return d_func()->m_outgoingMetaData
;
295 SimpleJob::SimpleJob(SimpleJobPrivate
&dd
)
298 d_func()->simpleJobInit();
301 void SimpleJobPrivate::simpleJobInit()
304 if (!m_url
.isValid())
306 q
->setError( ERR_MALFORMED_URL
);
307 q
->setErrorText( m_url
.url() );
308 QTimer::singleShot(0, q
, SLOT(slotFinished()) );
316 bool SimpleJob::doKill()
320 Scheduler::cancelJob( this ); // deletes the slave if not 0
321 d
->m_slave
= 0; // -> set to 0
322 return Job::doKill();
325 bool SimpleJob::doSuspend()
329 d
->m_slave
->suspend();
330 return Job::doSuspend();
333 bool SimpleJob::doResume()
337 d
->m_slave
->resume();
338 return Job::doResume();
341 const KUrl
& SimpleJob::url() const
343 return d_func()->m_url
;
346 void SimpleJob::putOnHold()
349 Q_ASSERT( d
->m_slave
);
352 Scheduler::putSlaveOnHold(this, d
->m_url
);
358 void SimpleJob::removeOnHold()
360 Scheduler::removeSlaveOnHold();
363 SimpleJob::~SimpleJob()
366 if (d
->m_slave
) // was running
368 kDebug(7007) << "Killing running job in destructor!" << kBacktrace();
371 Scheduler::jobFinished( this, d
->m_slave
); // deletes the slave
373 d
->m_slave
= 0; // -> set to 0
375 Scheduler::cancelJob( this );
378 void SimpleJobPrivate::start(Slave
*slave
)
383 q
->connect( slave
, SIGNAL(error(int,QString
)),
384 SLOT(slotError(int,QString
)) );
386 q
->connect( slave
, SIGNAL(warning(QString
)),
387 SLOT(slotWarning(QString
)) );
389 q
->connect( slave
, SIGNAL(infoMessage(QString
)),
390 SLOT(_k_slotSlaveInfoMessage(QString
)) );
392 q
->connect( slave
, SIGNAL(connected()),
393 SLOT(slotConnected()));
395 q
->connect( slave
, SIGNAL(finished()),
396 SLOT(slotFinished()) );
398 if ((m_extraFlags
& EF_TransferJobDataSent
) == 0) // this is a "get" job
400 q
->connect( slave
, SIGNAL(totalSize(KIO::filesize_t
)),
401 SLOT(slotTotalSize(KIO::filesize_t
)) );
403 q
->connect( slave
, SIGNAL(processedSize(KIO::filesize_t
)),
404 SLOT(slotProcessedSize(KIO::filesize_t
)) );
406 q
->connect( slave
, SIGNAL(speed(ulong
)),
407 SLOT(slotSpeed(ulong
)) );
409 q
->connect( slave
, SIGNAL(metaData(KIO::MetaData
)),
410 SLOT(slotMetaData(KIO::MetaData
)) );
412 if (ui() && ui()->window())
414 m_outgoingMetaData
.insert("window-id", QString::number((long)ui()->window()->winId()));
417 if (ui() && ui()->userTimestamp())
419 m_outgoingMetaData
.insert("user-timestamp", QString::number(ui()->userTimestamp()));
422 QString sslSession
= KSSLCSessionCache::getSessionForUrl(m_url
);
423 if ( !sslSession
.isNull() )
425 m_outgoingMetaData
.insert("ssl_session_id", sslSession
);
428 if (ui() == 0) // not interactive
430 m_outgoingMetaData
.insert("no-auth-prompt", "true");
433 if (!m_outgoingMetaData
.isEmpty())
435 KIO_ARGS
<< m_outgoingMetaData
;
436 slave
->send( CMD_META_DATA
, packedArgs
);
439 if (!m_subUrl
.isEmpty())
441 KIO_ARGS
<< m_subUrl
;
442 slave
->send( CMD_SUBURL
, packedArgs
);
445 slave
->send( m_command
, m_packedArgs
);
448 void SimpleJobPrivate::slaveDone()
451 if (!m_slave
) return;
452 if (m_command
== CMD_OPEN
) m_slave
->send(CMD_CLOSE
);
453 q
->disconnect(m_slave
); // Remove all signals between slave and job
454 Scheduler::jobFinished( q
, m_slave
);
458 void SimpleJob::slotFinished( )
461 // Return slave to the scheduler
466 if ( !error() && (d
->m_command
== CMD_MKDIR
|| d
->m_command
== CMD_RENAME
) )
468 if ( d
->m_command
== CMD_MKDIR
)
470 KUrl
urlDir( url() );
471 urlDir
.setPath( urlDir
.directory() );
472 org::kde::KDirNotify::emitFilesAdded( urlDir
.url() );
474 else /*if ( m_command == CMD_RENAME )*/
477 QDataStream
str( d
->m_packedArgs
);
479 if( src
.directory() == dst
.directory() ) // For the user, moving isn't renaming. Only renaming is.
480 org::kde::KDirNotify::emitFileRenamed( src
.url(), dst
.url() );
482 org::kde::KDirNotify::emitFileMoved( src
.url(), dst
.url() );
489 void SimpleJob::slotError( int err
, const QString
& errorText
)
493 setErrorText( errorText
);
494 if ((error() == ERR_UNKNOWN_HOST
) && d
->m_url
.host().isEmpty())
495 setErrorText( QString() );
496 // error terminates the job
500 void SimpleJob::slotWarning( const QString
& errorText
)
502 emit
warning( this, errorText
);
505 void SimpleJobPrivate::_k_slotSlaveInfoMessage( const QString
& msg
)
507 emit
q_func()->infoMessage( q_func(), msg
);
510 void SimpleJobPrivate::slotConnected()
512 emit
q_func()->connected( q_func() );
515 void SimpleJobPrivate::slotTotalSize( KIO::filesize_t size
)
518 if (size
> q
->totalAmount(KJob::Bytes
))
520 q
->setTotalAmount(KJob::Bytes
, size
);
524 void SimpleJobPrivate::slotProcessedSize( KIO::filesize_t size
)
527 //kDebug(7007) << KIO::number(size);
528 q
->setProcessedAmount(KJob::Bytes
, size
);
531 void SimpleJobPrivate::slotSpeed( unsigned long speed
)
533 //kDebug(7007) << speed;
534 q_func()->emitSpeed( speed
);
537 void SimpleJob::slotMetaData( const KIO::MetaData
&_metaData
)
540 d
->m_incomingMetaData
+= _metaData
;
543 void SimpleJob::storeSSLSessionFromJob(const KUrl
&redirectionURL
)
546 QString sslSession
= queryMetaData("ssl_session_id");
548 if ( !sslSession
.isNull() ) {
549 const KUrl
&queryURL
= redirectionURL
.isEmpty() ? d
->m_url
: redirectionURL
;
550 KSSLCSessionCache::putSessionForUrl(queryURL
, sslSession
);
555 class KIO::MkdirJobPrivate
: public SimpleJobPrivate
558 MkdirJobPrivate(const KUrl
& url
, int command
, const QByteArray
&packedArgs
)
559 : SimpleJobPrivate(url
, command
, packedArgs
)
561 KUrl m_redirectionURL
;
562 void slotRedirection(const KUrl
&url
);
566 * Called by the scheduler when a @p slave gets to
568 * @param slave the slave that starts working on this job
570 virtual void start( Slave
*slave
);
572 Q_DECLARE_PUBLIC(MkdirJob
)
574 static inline MkdirJob
*newJob(const KUrl
& url
, int command
, const QByteArray
&packedArgs
)
576 MkdirJob
*job
= new MkdirJob(*new MkdirJobPrivate(url
, command
, packedArgs
));
577 job
->setUiDelegate(new JobUiDelegate
);
582 MkdirJob::MkdirJob(MkdirJobPrivate
&dd
)
587 MkdirJob::~MkdirJob()
591 void MkdirJobPrivate::start(Slave
*slave
)
594 q
->connect( slave
, SIGNAL( redirection(const KUrl
&) ),
595 SLOT( slotRedirection(const KUrl
&) ) );
597 SimpleJobPrivate::start(slave
);
600 // Slave got a redirection request
601 void MkdirJobPrivate::slotRedirection( const KUrl
&url
)
605 if (!KAuthorized::authorizeUrlAction("redirect", m_url
, url
))
607 kWarning(7007) << "Redirection from" << m_url
<< "to" << url
<< "REJECTED!";
608 q
->setError( ERR_ACCESS_DENIED
);
609 q
->setErrorText( url
.prettyUrl() );
612 m_redirectionURL
= url
; // We'll remember that when the job finishes
613 if (m_url
.hasUser() && !url
.hasUser() && (m_url
.host().toLower() == url
.host().toLower()))
614 m_redirectionURL
.setUser(m_url
.user()); // Preserve user
615 // Tell the user that we haven't finished yet
616 emit q
->redirection(q
, m_redirectionURL
);
619 void MkdirJob::slotFinished()
622 if ( d
->m_redirectionURL
.isEmpty() || !d
->m_redirectionURL
.isValid())
624 // Return slave to the scheduler
625 SimpleJob::slotFinished();
627 //kDebug(7007) << "MkdirJob: Redirection to " << m_redirectionURL;
628 if (queryMetaData("permanent-redirect")=="true")
629 emit
permanentRedirection(this, d
->m_url
, d
->m_redirectionURL
);
632 QDataStream
istream( d
->m_packedArgs
);
633 istream
>> dummyUrl
>> permissions
;
635 d
->m_url
= d
->m_redirectionURL
;
636 d
->m_redirectionURL
= KUrl();
637 d
->m_packedArgs
.truncate(0);
638 QDataStream
stream( &d
->m_packedArgs
, QIODevice::WriteOnly
);
639 stream
<< d
->m_url
<< permissions
;
641 // Return slave to the scheduler
643 Scheduler::doJob(this);
647 SimpleJob
*KIO::mkdir( const KUrl
& url
, int permissions
)
649 //kDebug(7007) << "mkdir " << url;
650 KIO_ARGS
<< url
<< permissions
;
651 return MkdirJobPrivate::newJob(url
, CMD_MKDIR
, packedArgs
);
654 SimpleJob
*KIO::rmdir( const KUrl
& url
)
656 //kDebug(7007) << "rmdir " << url;
657 KIO_ARGS
<< url
<< qint8(false); // isFile is false
658 return SimpleJobPrivate::newJob(url
, CMD_DEL
, packedArgs
);
661 SimpleJob
*KIO::chmod( const KUrl
& url
, int permissions
)
663 //kDebug(7007) << "chmod " << url;
664 KIO_ARGS
<< url
<< permissions
;
665 return SimpleJobPrivate::newJob(url
, CMD_CHMOD
, packedArgs
);
668 SimpleJob
*KIO::chown( const KUrl
& url
, const QString
& owner
, const QString
& group
)
670 KIO_ARGS
<< url
<< owner
<< group
;
671 return SimpleJobPrivate::newJob(url
, CMD_CHOWN
, packedArgs
);
674 SimpleJob
*KIO::setModificationTime( const KUrl
& url
, const QDateTime
& mtime
)
676 //kDebug(7007) << "setModificationTime " << url << " " << mtime;
677 KIO_ARGS
<< url
<< mtime
;
678 return SimpleJobPrivate::newJobNoUi(url
, CMD_SETMODIFICATIONTIME
, packedArgs
);
681 SimpleJob
*KIO::rename( const KUrl
& src
, const KUrl
& dest
, JobFlags flags
)
683 //kDebug(7007) << "rename " << src << " " << dest;
684 KIO_ARGS
<< src
<< dest
<< (qint8
) (flags
& Overwrite
);
685 return SimpleJobPrivate::newJob(src
, CMD_RENAME
, packedArgs
);
688 SimpleJob
*KIO::symlink( const QString
& target
, const KUrl
& dest
, JobFlags flags
)
690 //kDebug(7007) << "symlink target=" << target << " " << dest;
691 KIO_ARGS
<< target
<< dest
<< (qint8
) (flags
& Overwrite
);
692 return SimpleJobPrivate::newJob(dest
, CMD_SYMLINK
, packedArgs
, flags
);
695 SimpleJob
*KIO::special(const KUrl
& url
, const QByteArray
& data
, JobFlags flags
)
697 //kDebug(7007) << "special " << url;
698 return SimpleJobPrivate::newJob(url
, CMD_SPECIAL
, data
, flags
);
701 SimpleJob
*KIO::mount( bool ro
, const QByteArray
& fstype
, const QString
& dev
, const QString
& point
, JobFlags flags
)
703 KIO_ARGS
<< int(1) << qint8( ro
? 1 : 0 )
704 << QString::fromLatin1(fstype
) << dev
<< point
;
705 SimpleJob
*job
= special( KUrl("file:/"), packedArgs
, flags
);
706 if (!(flags
& HideProgressInfo
)) {
707 KIO::JobPrivate::emitMounting(job
, dev
, point
);
712 SimpleJob
*KIO::unmount( const QString
& point
, JobFlags flags
)
714 KIO_ARGS
<< int(2) << point
;
715 SimpleJob
*job
= special( KUrl("file:/"), packedArgs
, flags
);
716 if (!(flags
& HideProgressInfo
)) {
717 KIO::JobPrivate::emitUnmounting(job
, point
);
726 class KIO::StatJobPrivate
: public SimpleJobPrivate
729 inline StatJobPrivate(const KUrl
& url
, int command
, const QByteArray
&packedArgs
)
730 : SimpleJobPrivate(url
, command
, packedArgs
), m_bSource(true), m_details(2)
733 UDSEntry m_statResult
;
734 KUrl m_redirectionURL
;
737 void slotStatEntry( const KIO::UDSEntry
& entry
);
738 void slotRedirection( const KUrl
&url
);
742 * Called by the scheduler when a @p slave gets to
744 * @param slave the slave that starts working on this job
746 virtual void start( Slave
*slave
);
748 Q_DECLARE_PUBLIC(StatJob
)
750 static inline StatJob
*newJob(const KUrl
& url
, int command
, const QByteArray
&packedArgs
,
753 StatJob
*job
= new StatJob(*new StatJobPrivate(url
, command
, packedArgs
));
754 job
->setUiDelegate(new JobUiDelegate
);
755 if (!(flags
& HideProgressInfo
)) {
756 KIO::getJobTracker()->registerJob(job
);
757 emitStating(job
, url
);
763 StatJob::StatJob(StatJobPrivate
&dd
)
772 void StatJob::setSide( bool source
)
774 d_func()->m_bSource
= source
;
777 void StatJob::setSide( StatSide side
)
779 d_func()->m_bSource
= side
== SourceSide
;
782 void StatJob::setDetails( short int details
)
784 d_func()->m_details
= details
;
787 const UDSEntry
& StatJob::statResult() const
789 return d_func()->m_statResult
;
792 void StatJobPrivate::start(Slave
*slave
)
795 m_outgoingMetaData
.insert( "statSide", m_bSource
? "source" : "dest" );
796 m_outgoingMetaData
.insert( "details", QString::number(m_details
) );
798 q
->connect( slave
, SIGNAL( statEntry( const KIO::UDSEntry
& ) ),
799 SLOT( slotStatEntry( const KIO::UDSEntry
& ) ) );
800 q
->connect( slave
, SIGNAL( redirection(const KUrl
&) ),
801 SLOT( slotRedirection(const KUrl
&) ) );
803 SimpleJobPrivate::start(slave
);
806 void StatJobPrivate::slotStatEntry( const KIO::UDSEntry
& entry
)
809 m_statResult
= entry
;
812 // Slave got a redirection request
813 void StatJobPrivate::slotRedirection( const KUrl
&url
)
817 if (!KAuthorized::authorizeUrlAction("redirect", m_url
, url
))
819 kWarning(7007) << "Redirection from " << m_url
<< " to " << url
<< " REJECTED!";
820 q
->setError( ERR_ACCESS_DENIED
);
821 q
->setErrorText( url
.prettyUrl() );
824 m_redirectionURL
= url
; // We'll remember that when the job finishes
825 if (m_url
.hasUser() && !url
.hasUser() && (m_url
.host().toLower() == url
.host().toLower()))
826 m_redirectionURL
.setUser(m_url
.user()); // Preserve user
827 // Tell the user that we haven't finished yet
828 emit q
->redirection(q
, m_redirectionURL
);
831 void StatJob::slotFinished()
834 if ( d
->m_redirectionURL
.isEmpty() || !d
->m_redirectionURL
.isValid())
836 // Return slave to the scheduler
837 SimpleJob::slotFinished();
839 //kDebug(7007) << "StatJob: Redirection to " << m_redirectionURL;
840 if (queryMetaData("permanent-redirect")=="true")
841 emit
permanentRedirection(this, d
->m_url
, d
->m_redirectionURL
);
842 d
->m_url
= d
->m_redirectionURL
;
843 d
->m_redirectionURL
= KUrl();
844 d
->m_packedArgs
.truncate(0);
845 QDataStream
stream( &d
->m_packedArgs
, QIODevice::WriteOnly
);
848 // Return slave to the scheduler
850 Scheduler::doJob(this);
854 void StatJob::slotMetaData( const KIO::MetaData
&_metaData
)
857 SimpleJob::slotMetaData(_metaData
);
858 storeSSLSessionFromJob(d
->m_redirectionURL
);
861 StatJob
*KIO::stat(const KUrl
& url
, JobFlags flags
)
863 // Assume sideIsSource. Gets are more common than puts.
864 return stat( url
, StatJob::SourceSide
, 2, flags
);
867 StatJob
*KIO::stat(const KUrl
& url
, bool sideIsSource
, short int details
, JobFlags flags
)
869 //kDebug(7007) << "stat" << url;
871 StatJob
* job
= StatJobPrivate::newJob(url
, CMD_STAT
, packedArgs
, flags
);
872 job
->setSide( sideIsSource
? StatJob::SourceSide
: StatJob::DestinationSide
);
873 job
->setDetails( details
);
877 StatJob
*KIO::stat(const KUrl
& url
, KIO::StatJob::StatSide side
, short int details
, JobFlags flags
)
879 //kDebug(7007) << "stat" << url;
881 StatJob
* job
= StatJobPrivate::newJob(url
, CMD_STAT
, packedArgs
, flags
);
882 job
->setSide( side
);
883 job
->setDetails( details
);
887 SimpleJob
*KIO::http_update_cache( const KUrl
& url
, bool no_cache
, time_t expireDate
)
889 assert( (url
.protocol() == "http") || (url
.protocol() == "https") );
890 // Send http update_cache command (2)
891 KIO_ARGS
<< (int)2 << url
<< no_cache
<< qlonglong(expireDate
);
892 SimpleJob
* job
= SimpleJobPrivate::newJob(url
, CMD_SPECIAL
, packedArgs
);
893 Scheduler::scheduleJob(job
);
899 TransferJob::TransferJob(TransferJobPrivate
&dd
)
903 if (d
->m_command
== CMD_PUT
) {
904 d
->m_extraFlags
|= JobPrivate::EF_TransferJobDataSent
;
908 TransferJob::~TransferJob()
913 void TransferJob::slotData( const QByteArray
&_data
)
916 if(d
->m_redirectionURL
.isEmpty() || !d
->m_redirectionURL
.isValid() || error())
917 emit
data( this, _data
);
920 void KIO::TransferJob::setTotalSize(KIO::filesize_t bytes
)
922 setTotalAmount(KJob::Bytes
, bytes
);
925 // Slave got a redirection request
926 void TransferJob::slotRedirection( const KUrl
&url
)
930 if (!KAuthorized::authorizeUrlAction("redirect", d
->m_url
, url
))
932 kWarning(7007) << "Redirection from " << d
->m_url
<< " to " << url
<< " REJECTED!";
936 // Some websites keep redirecting to themselves where each redirection
937 // acts as the stage in a state-machine. We define "endless redirections"
938 // as 5 redirections to the same URL.
939 if (d
->m_redirectionList
.count(url
) > 5)
941 kDebug(7007) << "CYCLIC REDIRECTION!";
942 setError( ERR_CYCLIC_LINK
);
943 setErrorText( d
->m_url
.prettyUrl() );
947 d
->m_redirectionURL
= url
; // We'll remember that when the job finishes
948 if (d
->m_url
.hasUser() && !url
.hasUser() && (d
->m_url
.host().toLower() == url
.host().toLower()))
949 d
->m_redirectionURL
.setUser(d
->m_url
.user()); // Preserve user
950 d
->m_redirectionList
.append(url
);
951 d
->m_outgoingMetaData
["ssl_was_in_use"] = d
->m_incomingMetaData
["ssl_in_use"];
952 // Tell the user that we haven't finished yet
953 emit
redirection(this, d
->m_redirectionURL
);
957 void TransferJob::slotFinished()
960 //kDebug(7007) << this << "," << m_url;
961 if (d
->m_redirectionURL
.isEmpty() || !d
->m_redirectionURL
.isValid())
962 SimpleJob::slotFinished();
964 //kDebug(7007) << "Redirection to" << m_redirectionURL;
965 if (queryMetaData("permanent-redirect")=="true")
966 emit
permanentRedirection(this, d
->m_url
, d
->m_redirectionURL
);
967 // Honour the redirection
968 // We take the approach of "redirecting this same job"
969 // Another solution would be to create a subjob, but the same problem
970 // happens (unpacking+repacking)
971 d
->staticData
.truncate(0);
972 d
->m_incomingMetaData
.clear();
973 if (queryMetaData("cache") != "reload")
974 addMetaData("cache","refresh");
975 d
->m_internalSuspended
= false;
976 d
->m_url
= d
->m_redirectionURL
;
977 d
->m_redirectionURL
= KUrl();
978 // The very tricky part is the packed arguments business
981 QDataStream
istream( d
->m_packedArgs
);
982 switch( d
->m_command
) {
984 d
->m_packedArgs
.truncate(0);
985 QDataStream
stream( &d
->m_packedArgs
, QIODevice::WriteOnly
);
991 qint8 iOverwrite
, iResume
;
992 istream
>> dummyUrl
>> iOverwrite
>> iResume
>> permissions
;
993 d
->m_packedArgs
.truncate(0);
994 QDataStream
stream( &d
->m_packedArgs
, QIODevice::WriteOnly
);
995 stream
<< d
->m_url
<< iOverwrite
<< iResume
<< permissions
;
1000 istream
>> specialcmd
;
1001 if (specialcmd
== 1) // HTTP POST
1003 addMetaData("cache","reload");
1004 d
->m_packedArgs
.truncate(0);
1005 QDataStream
stream( &d
->m_packedArgs
, QIODevice::WriteOnly
);
1007 d
->m_command
= CMD_GET
;
1013 // Return slave to the scheduler
1015 Scheduler::doJob(this);
1019 void TransferJob::setAsyncDataEnabled(bool enabled
)
1023 d
->m_extraFlags
|= JobPrivate::EF_TransferJobAsync
;
1025 d
->m_extraFlags
&= ~JobPrivate::EF_TransferJobAsync
;
1028 void TransferJob::sendAsyncData(const QByteArray
&dataForSlave
)
1031 if (d
->m_extraFlags
& JobPrivate::EF_TransferJobNeedData
)
1033 d
->m_slave
->send( MSG_DATA
, dataForSlave
);
1034 if (d
->m_extraFlags
& JobPrivate::EF_TransferJobDataSent
) // put job -> emit progress
1036 KIO::filesize_t size
= processedAmount(KJob::Bytes
)+dataForSlave
.size();
1037 setProcessedAmount(KJob::Bytes
, size
);
1041 d
->m_extraFlags
&= ~JobPrivate::EF_TransferJobNeedData
;
1044 void TransferJob::setReportDataSent(bool enabled
)
1048 d
->m_extraFlags
|= JobPrivate::EF_TransferJobDataSent
;
1050 d
->m_extraFlags
&= ~JobPrivate::EF_TransferJobDataSent
;
1053 bool TransferJob::reportDataSent() const
1055 return (d_func()->m_extraFlags
& JobPrivate::EF_TransferJobDataSent
);
1058 QString
TransferJob::mimetype() const
1060 return d_func()->m_mimetype
;
1064 // Slave requests data
1065 void TransferJob::slotDataReq()
1068 QByteArray dataForSlave
;
1070 d
->m_extraFlags
|= JobPrivate::EF_TransferJobNeedData
;
1072 if (!d
->staticData
.isEmpty())
1074 dataForSlave
= d
->staticData
;
1075 d
->staticData
.clear();
1079 emit
dataReq( this, dataForSlave
);
1081 if (d
->m_extraFlags
& JobPrivate::EF_TransferJobAsync
)
1085 static const int max_size
= 14 * 1024 * 1024;
1086 if (dataForSlave
.size() > max_size
)
1088 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";
1089 d
->staticData
= QByteArray(dataForSlave
.data() + max_size
, dataForSlave
.size() - max_size
);
1090 dataForSlave
.truncate(max_size
);
1093 sendAsyncData(dataForSlave
);
1097 // Bitburger protocol in action
1098 d
->internalSuspend(); // Wait for more data from subJob.
1099 d
->m_subJob
->d_func()->internalResume(); // Ask for more!
1103 void TransferJob::slotMimetype( const QString
& type
)
1106 d
->m_mimetype
= type
;
1107 emit
mimetype( this, type
);
1111 void TransferJobPrivate::internalSuspend()
1113 m_internalSuspended
= true;
1118 void TransferJobPrivate::internalResume()
1120 m_internalSuspended
= false;
1121 if ( m_slave
&& !suspended
)
1125 bool TransferJob::doResume()
1128 if ( !SimpleJob::doResume() )
1130 if ( d
->m_internalSuspended
)
1131 d
->internalSuspend();
1135 bool TransferJob::isErrorPage() const
1137 return d_func()->m_errorPage
;
1140 void TransferJobPrivate::start(Slave
*slave
)
1144 JobPrivate::emitTransferring(q
, m_url
);
1145 q
->connect( slave
, SIGNAL( data( const QByteArray
& ) ),
1146 SLOT( slotData( const QByteArray
& ) ) );
1148 q
->connect( slave
, SIGNAL( dataReq() ),
1149 SLOT( slotDataReq() ) );
1151 q
->connect( slave
, SIGNAL( redirection(const KUrl
&) ),
1152 SLOT( slotRedirection(const KUrl
&) ) );
1154 q
->connect( slave
, SIGNAL(mimeType( const QString
& ) ),
1155 SLOT( slotMimetype( const QString
& ) ) );
1157 q
->connect( slave
, SIGNAL(errorPage() ),
1158 SLOT( slotErrorPage() ) );
1160 q
->connect( slave
, SIGNAL( needSubUrlData() ),
1161 SLOT( slotNeedSubUrlData() ) );
1163 q
->connect( slave
, SIGNAL(canResume( KIO::filesize_t
) ),
1164 SLOT( slotCanResume( KIO::filesize_t
) ) );
1166 if (slave
->suspended())
1168 m_mimetype
= "unknown";
1169 // WABA: The slave was put on hold. Resume operation.
1173 SimpleJobPrivate::start(slave
);
1174 if (m_internalSuspended
)
1178 void TransferJobPrivate::slotNeedSubUrlData()
1181 // Job needs data from subURL.
1182 m_subJob
= KIO::get( m_subUrl
, NoReload
, HideProgressInfo
);
1183 internalSuspend(); // Put job on hold until we have some data.
1184 q
->connect(m_subJob
, SIGNAL( data(KIO::Job
*,const QByteArray
&)),
1185 SLOT( slotSubUrlData(KIO::Job
*,const QByteArray
&)));
1186 q
->addSubjob(m_subJob
);
1189 void TransferJobPrivate::slotSubUrlData(KIO::Job
*, const QByteArray
&data
)
1191 // The Alternating Bitburg protocol in action again.
1193 m_subJob
->d_func()->internalSuspend(); // Put job on hold until we have delivered the data.
1194 internalResume(); // Activate ourselves again.
1197 void TransferJob::slotMetaData( const KIO::MetaData
&_metaData
)
1200 SimpleJob::slotMetaData(_metaData
);
1201 storeSSLSessionFromJob(d
->m_redirectionURL
);
1204 void TransferJobPrivate::slotErrorPage()
1209 void TransferJobPrivate::slotCanResume( KIO::filesize_t offset
)
1212 emit q
->canResume(q
, offset
);
1215 void TransferJob::slotResult( KJob
*job
)
1218 // This can only be our suburl.
1219 assert(job
== d
->m_subJob
);
1221 SimpleJob::slotResult( job
);
1223 if (!error() && job
== d
->m_subJob
)
1225 d
->m_subJob
= 0; // No action required
1226 d
->internalResume(); // Make sure we get the remaining data.
1230 void TransferJob::setModificationTime( const QDateTime
& mtime
)
1232 addMetaData( "modified", mtime
.toString( Qt::ISODate
) );
1235 TransferJob
*KIO::get( const KUrl
& url
, LoadType reload
, JobFlags flags
)
1237 // Send decoded path and encoded query
1239 TransferJob
* job
= TransferJobPrivate::newJob(url
, CMD_GET
, packedArgs
,
1240 QByteArray(), flags
);
1241 if (reload
== Reload
)
1242 job
->addMetaData("cache", "reload");
1246 class KIO::StoredTransferJobPrivate
: public TransferJobPrivate
1249 StoredTransferJobPrivate(const KUrl
& url
, int command
,
1250 const QByteArray
&packedArgs
,
1251 const QByteArray
&_staticData
)
1252 : TransferJobPrivate(url
, command
, packedArgs
, _staticData
),
1258 void slotStoredData( KIO::Job
*job
, const QByteArray
&data
);
1259 void slotStoredDataReq( KIO::Job
*job
, QByteArray
&data
);
1261 Q_DECLARE_PUBLIC(StoredTransferJob
)
1263 static inline StoredTransferJob
*newJob(const KUrl
&url
, int command
,
1264 const QByteArray
&packedArgs
,
1265 const QByteArray
&staticData
, JobFlags flags
)
1267 StoredTransferJob
*job
= new StoredTransferJob(
1268 *new StoredTransferJobPrivate(url
, command
, packedArgs
, staticData
));
1269 job
->setUiDelegate(new JobUiDelegate
);
1270 if (!(flags
& HideProgressInfo
))
1271 KIO::getJobTracker()->registerJob(job
);
1277 class PostErrorJob
: public StoredTransferJob
1281 PostErrorJob(int _error
, const QString
& url
, const QByteArray
&packedArgs
, const QByteArray
&postData
)
1282 : StoredTransferJob(*new StoredTransferJobPrivate(KUrl(), CMD_SPECIAL
, packedArgs
, postData
))
1285 setErrorText( url
);
1291 static KIO::PostErrorJob
* precheckHttpPost( const KUrl
& url
, const QByteArray
& postData
, JobFlags flags
)
1295 // filter out some malicious ports
1296 static const int bad_ports
[] = {
1330 135, // loc-srv / epmap
1335 512, // print / exec
1358 for (int cnt
=0; bad_ports
[cnt
]; ++cnt
)
1359 if (url
.port() == bad_ports
[cnt
])
1361 _error
= KIO::ERR_POST_DENIED
;
1367 static bool override_loaded
= false;
1368 static QList
< int >* overriden_ports
= NULL
;
1369 if( !override_loaded
) {
1370 KConfig
cfg( "kio_httprc" );
1371 overriden_ports
= new QList
< int >;
1372 *overriden_ports
= cfg
.group(QString()).readEntry( "OverriddenPorts", QList
<int>() );
1373 override_loaded
= true;
1375 for( QList
< int >::ConstIterator it
= overriden_ports
->constBegin();
1376 it
!= overriden_ports
->constEnd();
1378 if( overriden_ports
->contains( url
.port())) {
1384 // filter out non https? protocols
1385 if ((url
.protocol() != "http") && (url
.protocol() != "https" ))
1386 _error
= KIO::ERR_POST_DENIED
;
1388 if (!_error
&& !KAuthorized::authorizeUrlAction("open", KUrl(), url
))
1389 _error
= KIO::ERR_ACCESS_DENIED
;
1391 // if request is not valid, return an invalid transfer job
1394 KIO_ARGS
<< (int)1 << url
;
1395 PostErrorJob
* job
= new PostErrorJob(_error
, url
.prettyUrl(), packedArgs
, postData
);
1396 job
->setUiDelegate(new JobUiDelegate());
1397 if (!(flags
& HideProgressInfo
)) {
1398 KIO::getJobTracker()->registerJob(job
);
1403 // all is ok, return 0
1407 TransferJob
*KIO::http_post( const KUrl
& url
, const QByteArray
&postData
, JobFlags flags
)
1409 bool redirection
= false;
1411 if (_url
.path().isEmpty())
1417 TransferJob
* job
= precheckHttpPost(_url
, postData
, flags
);
1421 // Send http post command (1), decoded path and encoded query
1422 KIO_ARGS
<< (int)1 << _url
;
1423 job
= TransferJobPrivate::newJob(_url
, CMD_SPECIAL
, packedArgs
, postData
, flags
);
1426 QTimer::singleShot(0, job
, SLOT(slotPostRedirection()) );
1431 StoredTransferJob
*KIO::storedHttpPost( const QByteArray
& postData
, const KUrl
& url
, JobFlags flags
)
1433 bool redirection
= false;
1435 if (_url
.path().isEmpty())
1441 StoredTransferJob
* job
= precheckHttpPost(_url
, postData
, flags
);
1445 // Send http post command (1), decoded path and encoded query
1446 KIO_ARGS
<< (int)1 << _url
;
1447 job
= StoredTransferJobPrivate::newJob(_url
, CMD_SPECIAL
, packedArgs
, postData
, flags
);
1451 // http post got redirected from http://host to http://host/ by TransferJob
1452 // We must do this redirection ourselves because redirections by the
1453 // slave change post jobs into get jobs.
1454 void TransferJobPrivate::slotPostRedirection()
1457 kDebug(7007) << "TransferJob::slotPostRedirection(" << m_url
<< ")";
1458 // Tell the user about the new url.
1459 emit q
->redirection(q
, m_url
);
1463 TransferJob
*KIO::put( const KUrl
& url
, int permissions
, JobFlags flags
)
1465 KIO_ARGS
<< url
<< qint8( (flags
& Overwrite
) ? 1 : 0 ) << qint8( (flags
& Resume
) ? 1 : 0 ) << permissions
;
1466 return TransferJobPrivate::newJob(url
, CMD_PUT
, packedArgs
, QByteArray(), flags
);
1471 StoredTransferJob::StoredTransferJob(StoredTransferJobPrivate
&dd
)
1474 connect( this, SIGNAL( data( KIO::Job
*, const QByteArray
& ) ),
1475 SLOT( slotStoredData( KIO::Job
*, const QByteArray
& ) ) );
1476 connect( this, SIGNAL( dataReq( KIO::Job
*, QByteArray
& ) ),
1477 SLOT( slotStoredDataReq( KIO::Job
*, QByteArray
& ) ) );
1480 StoredTransferJob::~StoredTransferJob()
1484 void StoredTransferJob::setData( const QByteArray
& arr
)
1486 Q_D(StoredTransferJob
);
1487 Q_ASSERT( d
->m_data
.isNull() ); // check that we're only called once
1488 Q_ASSERT( d
->m_uploadOffset
== 0 ); // no upload started yet
1490 setTotalSize( d
->m_data
.size() );
1493 QByteArray
StoredTransferJob::data() const
1495 return d_func()->m_data
;
1498 void StoredTransferJobPrivate::slotStoredData( KIO::Job
*, const QByteArray
&data
)
1500 // check for end-of-data marker:
1501 if ( data
.size() == 0 )
1503 unsigned int oldSize
= m_data
.size();
1504 m_data
.resize( oldSize
+ data
.size() );
1505 memcpy( m_data
.data() + oldSize
, data
.data(), data
.size() );
1508 void StoredTransferJobPrivate::slotStoredDataReq( KIO::Job
*, QByteArray
&data
)
1510 // Inspired from kmail's KMKernel::byteArrayToRemoteFile
1511 // send the data in 64 KB chunks
1512 const int MAX_CHUNK_SIZE
= 64*1024;
1513 int remainingBytes
= m_data
.size() - m_uploadOffset
;
1514 if( remainingBytes
> MAX_CHUNK_SIZE
) {
1515 // send MAX_CHUNK_SIZE bytes to the receiver (deep copy)
1516 data
= QByteArray( m_data
.data() + m_uploadOffset
, MAX_CHUNK_SIZE
);
1517 m_uploadOffset
+= MAX_CHUNK_SIZE
;
1518 //kDebug() << "Sending " << MAX_CHUNK_SIZE << " bytes ("
1519 // << remainingBytes - MAX_CHUNK_SIZE << " bytes remain)\n";
1521 // send the remaining bytes to the receiver (deep copy)
1522 data
= QByteArray( m_data
.data() + m_uploadOffset
, remainingBytes
);
1523 m_data
= QByteArray();
1525 //kDebug() << "Sending " << remainingBytes << " bytes\n";
1529 StoredTransferJob
*KIO::storedGet( const KUrl
& url
, LoadType reload
, JobFlags flags
)
1531 // Send decoded path and encoded query
1533 StoredTransferJob
* job
= StoredTransferJobPrivate::newJob(url
, CMD_GET
, packedArgs
, QByteArray(), flags
);
1534 if (reload
== Reload
)
1535 job
->addMetaData("cache", "reload");
1539 StoredTransferJob
*KIO::storedPut( const QByteArray
& arr
, const KUrl
& url
, int permissions
,
1542 KIO_ARGS
<< url
<< qint8( (flags
& Overwrite
) ? 1 : 0 ) << qint8( (flags
& Resume
) ? 1 : 0 ) << permissions
;
1543 StoredTransferJob
* job
= StoredTransferJobPrivate::newJob(url
, CMD_PUT
, packedArgs
, QByteArray(), flags
);
1544 job
->setData( arr
);
1550 class KIO::MimetypeJobPrivate
: public KIO::TransferJobPrivate
1553 MimetypeJobPrivate(const KUrl
& url
, int command
, const QByteArray
&packedArgs
)
1554 : TransferJobPrivate(url
, command
, packedArgs
, QByteArray())
1557 Q_DECLARE_PUBLIC(MimetypeJob
)
1559 static inline MimetypeJob
*newJob(const KUrl
& url
, int command
, const QByteArray
&packedArgs
,
1562 MimetypeJob
*job
= new MimetypeJob(*new MimetypeJobPrivate(url
, command
, packedArgs
));
1563 job
->setUiDelegate(new JobUiDelegate
);
1564 if (!(flags
& HideProgressInfo
)) {
1565 KIO::getJobTracker()->registerJob(job
);
1566 emitStating(job
, url
);
1572 MimetypeJob::MimetypeJob(MimetypeJobPrivate
&dd
)
1577 MimetypeJob::~MimetypeJob()
1581 void MimetypeJob::slotFinished( )
1585 if ( error() == KIO::ERR_IS_DIRECTORY
)
1587 // It is in fact a directory. This happens when HTTP redirects to FTP.
1588 // Due to the "protocol doesn't support listing" code in KRun, we
1589 // assumed it was a file.
1590 kDebug(7007) << "It is in fact a directory!";
1591 d
->m_mimetype
= QString::fromLatin1("inode/directory");
1592 emit
TransferJob::mimetype( this, d
->m_mimetype
);
1595 if ( d
->m_redirectionURL
.isEmpty() || !d
->m_redirectionURL
.isValid() || error() )
1597 // Return slave to the scheduler
1598 TransferJob::slotFinished();
1600 //kDebug(7007) << "Redirection to " << m_redirectionURL;
1601 if (queryMetaData("permanent-redirect")=="true")
1602 emit
permanentRedirection(this, d
->m_url
, d
->m_redirectionURL
);
1603 d
->staticData
.truncate(0);
1604 d
->m_internalSuspended
= false;
1605 d
->m_url
= d
->m_redirectionURL
;
1606 d
->m_redirectionURL
= KUrl();
1607 d
->m_packedArgs
.truncate(0);
1608 QDataStream
stream( &d
->m_packedArgs
, QIODevice::WriteOnly
);
1611 // Return slave to the scheduler
1613 Scheduler::doJob(this);
1617 MimetypeJob
*KIO::mimetype(const KUrl
& url
, JobFlags flags
)
1620 return MimetypeJobPrivate::newJob(url
, CMD_MIMETYPE
, packedArgs
, flags
);
1623 //////////////////////////
1625 class KIO::DirectCopyJobPrivate
: public KIO::SimpleJobPrivate
1628 DirectCopyJobPrivate(const KUrl
& url
, int command
, const QByteArray
&packedArgs
)
1629 : SimpleJobPrivate(url
, command
, packedArgs
)
1634 * Called by the scheduler when a @p slave gets to
1636 * @param slave the slave that starts working on this job
1638 virtual void start(Slave
*slave
);
1640 Q_DECLARE_PUBLIC(DirectCopyJob
)
1643 DirectCopyJob::DirectCopyJob(const KUrl
&url
, const QByteArray
&packedArgs
)
1644 : SimpleJob(*new DirectCopyJobPrivate(url
, CMD_COPY
, packedArgs
))
1646 setUiDelegate(new JobUiDelegate
);
1649 DirectCopyJob::~DirectCopyJob()
1653 void DirectCopyJobPrivate::start( Slave
* slave
)
1656 q
->connect( slave
, SIGNAL(canResume( KIO::filesize_t
) ),
1657 SLOT( slotCanResume( KIO::filesize_t
) ) );
1658 SimpleJobPrivate::start(slave
);
1661 void DirectCopyJob::slotCanResume( KIO::filesize_t offset
)
1663 emit
canResume(this, offset
);
1666 //////////////////////////
1669 class KIO::FileCopyJobPrivate
: public KIO::JobPrivate
1672 FileCopyJobPrivate(const KUrl
& src
, const KUrl
& dest
, int permissions
,
1673 bool move
, JobFlags flags
)
1674 : m_sourceSize(filesize_t(-1)), m_src(src
), m_dest(dest
), m_moveJob(0), m_copyJob(0), m_delJob(0),
1675 m_chmodJob(0), m_getJob(0), m_putJob(0), m_permissions(permissions
),
1676 m_move(move
), m_mustChmod(0), m_flags(flags
)
1679 KIO::filesize_t m_sourceSize
;
1680 QDateTime m_modificationTime
;
1683 QByteArray m_buffer
;
1684 SimpleJob
*m_moveJob
;
1685 SimpleJob
*m_copyJob
;
1686 SimpleJob
*m_delJob
;
1687 SimpleJob
*m_chmodJob
;
1688 TransferJob
*m_getJob
;
1689 TransferJob
*m_putJob
;
1693 bool m_resumeAnswerSent
:1;
1697 void startBestCopyMethod();
1698 void startCopyJob();
1699 void startCopyJob(const KUrl
&slave_url
);
1700 void startRenameJob(const KUrl
&slave_url
);
1701 void startDataPump();
1702 void connectSubjob( SimpleJob
* job
);
1705 void slotData( KIO::Job
*, const QByteArray
&data
);
1706 void slotDataReq( KIO::Job
*, QByteArray
&data
);
1707 void slotMimetype( KIO::Job
*, const QString
& type
);
1709 * Forward signal from subjob
1710 * @param job the job that emitted this signal
1711 * @param size the processed size in bytes
1713 void slotProcessedSize( KJob
*job
, qulonglong size
);
1715 * Forward signal from subjob
1716 * @param job the job that emitted this signal
1717 * @param size the total size
1719 void slotTotalSize( KJob
*job
, qulonglong size
);
1721 * Forward signal from subjob
1722 * @param job the job that emitted this signal
1723 * @param pct the percentage
1725 void slotPercent( KJob
*job
, unsigned long pct
);
1727 * Forward signal from subjob
1728 * @param job the job that emitted this signal
1729 * @param offset the offset to resume from
1731 void slotCanResume( KIO::Job
*job
, KIO::filesize_t offset
);
1733 Q_DECLARE_PUBLIC(FileCopyJob
)
1735 static inline FileCopyJob
* newJob(const KUrl
& src
, const KUrl
& dest
, int permissions
, bool move
,
1738 //kDebug(7007) << src << "->" << dest;
1739 FileCopyJob
*job
= new FileCopyJob(
1740 *new FileCopyJobPrivate(src
, dest
, permissions
, move
, flags
));
1741 job
->setUiDelegate(new JobUiDelegate
);
1742 if (!(flags
& HideProgressInfo
))
1743 KIO::getJobTracker()->registerJob(job
);
1749 * The FileCopyJob works according to the famous Bayern
1750 * 'Alternating Bitburger Protocol': we either drink a beer or we
1751 * we order a beer, but never both at the same time.
1752 * Translated to io-slaves: We alternate between receiving a block of data
1753 * and sending it away.
1755 FileCopyJob::FileCopyJob(FileCopyJobPrivate
&dd
)
1759 QTimer::singleShot(0, this, SLOT(slotStart()));
1762 void FileCopyJobPrivate::slotStart()
1766 JobPrivate::emitCopying( q
, m_src
, m_dest
);
1768 JobPrivate::emitMoving( q
, m_src
, m_dest
);
1772 // The if() below must be the same as the one in startBestCopyMethod
1773 if ((m_src
.protocol() == m_dest
.protocol()) &&
1774 (m_src
.host() == m_dest
.host()) &&
1775 (m_src
.port() == m_dest
.port()) &&
1776 (m_src
.user() == m_dest
.user()) &&
1777 (m_src
.pass() == m_dest
.pass()) &&
1778 !m_src
.hasSubUrl() && !m_dest
.hasSubUrl())
1780 startRenameJob(m_src
);
1783 else if (m_src
.isLocalFile() && KProtocolManager::canRenameFromFile(m_dest
))
1785 startRenameJob(m_dest
);
1788 else if (m_dest
.isLocalFile() && KProtocolManager::canRenameToFile(m_src
))
1790 startRenameJob(m_src
);
1793 // No fast-move available, use copy + del.
1795 startBestCopyMethod();
1798 void FileCopyJobPrivate::startBestCopyMethod()
1800 if ((m_src
.protocol() == m_dest
.protocol()) &&
1801 (m_src
.host() == m_dest
.host()) &&
1802 (m_src
.port() == m_dest
.port()) &&
1803 (m_src
.user() == m_dest
.user()) &&
1804 (m_src
.pass() == m_dest
.pass()) &&
1805 !m_src
.hasSubUrl() && !m_dest
.hasSubUrl())
1809 else if (m_src
.isLocalFile() && KProtocolManager::canCopyFromFile(m_dest
))
1811 startCopyJob(m_dest
);
1813 else if (m_dest
.isLocalFile() && KProtocolManager::canCopyToFile(m_src
))
1815 startCopyJob(m_src
);
1823 FileCopyJob::~FileCopyJob()
1827 void FileCopyJob::setSourceSize( KIO::filesize_t size
)
1830 d
->m_sourceSize
= size
;
1831 if (size
!= (KIO::filesize_t
) -1)
1832 setTotalAmount(KJob::Bytes
, size
);
1835 void FileCopyJob::setModificationTime( const QDateTime
& mtime
)
1838 d
->m_modificationTime
= mtime
;
1841 KUrl
FileCopyJob::srcUrl() const
1843 return d_func()->m_src
;
1846 KUrl
FileCopyJob::destUrl() const
1848 return d_func()->m_dest
;
1851 void FileCopyJobPrivate::startCopyJob()
1853 startCopyJob(m_src
);
1856 void FileCopyJobPrivate::startCopyJob(const KUrl
&slave_url
)
1860 KIO_ARGS
<< m_src
<< m_dest
<< m_permissions
<< (qint8
) (m_flags
& Overwrite
);
1861 m_copyJob
= new DirectCopyJob(slave_url
, packedArgs
);
1862 q
->addSubjob( m_copyJob
);
1863 connectSubjob( m_copyJob
);
1864 q
->connect( m_copyJob
, SIGNAL(canResume(KIO::Job
*, KIO::filesize_t
)),
1865 SLOT(slotCanResume(KIO::Job
*, KIO::filesize_t
)));
1868 void FileCopyJobPrivate::startRenameJob(const KUrl
&slave_url
)
1871 m_mustChmod
= true; // CMD_RENAME by itself doesn't change permissions
1872 KIO_ARGS
<< m_src
<< m_dest
<< (qint8
) (m_flags
& Overwrite
);
1873 m_moveJob
= SimpleJobPrivate::newJobNoUi(slave_url
, CMD_RENAME
, packedArgs
);
1874 q
->addSubjob( m_moveJob
);
1875 connectSubjob( m_moveJob
);
1878 void FileCopyJobPrivate::connectSubjob( SimpleJob
* job
)
1881 q
->connect( job
, SIGNAL(totalSize( KJob
*, qulonglong
)),
1882 SLOT( slotTotalSize(KJob
*, qulonglong
)) );
1884 q
->connect( job
, SIGNAL(processedSize( KJob
*, qulonglong
)),
1885 SLOT( slotProcessedSize(KJob
*, qulonglong
)) );
1887 q
->connect( job
, SIGNAL(percent( KJob
*, unsigned long )),
1888 SLOT( slotPercent(KJob
*, unsigned long)) );
1892 bool FileCopyJob::doSuspend()
1896 d
->m_moveJob
->suspend();
1899 d
->m_copyJob
->suspend();
1902 d
->m_getJob
->suspend();
1905 d
->m_putJob
->suspend();
1911 bool FileCopyJob::doResume()
1915 d
->m_moveJob
->resume();
1918 d
->m_copyJob
->resume();
1921 d
->m_getJob
->resume();
1924 d
->m_putJob
->resume();
1930 void FileCopyJobPrivate::slotProcessedSize( KJob
*, qulonglong size
)
1933 q
->setProcessedAmount(KJob::Bytes
, size
);
1936 void FileCopyJobPrivate::slotTotalSize( KJob
*, qulonglong size
)
1939 if (size
> q
->totalAmount(KJob::Bytes
))
1941 q
->setTotalAmount(KJob::Bytes
, size
);
1945 void FileCopyJobPrivate::slotPercent( KJob
*, unsigned long pct
)
1948 if ( pct
> q
->percent() ) {
1949 q
->setPercent( pct
);
1953 void FileCopyJobPrivate::startDataPump()
1958 m_canResume
= false;
1959 m_resumeAnswerSent
= false;
1960 m_getJob
= 0L; // for now
1961 m_putJob
= put( m_dest
, m_permissions
, (m_flags
| HideProgressInfo
) /* no GUI */);
1962 //kDebug(7007) << "m_putJob=" << m_putJob << "m_dest=" << m_dest;
1963 if ( m_modificationTime
.isValid() ) {
1964 m_putJob
->setModificationTime( m_modificationTime
);
1967 // The first thing the put job will tell us is whether we can
1968 // resume or not (this is always emitted)
1969 q
->connect( m_putJob
, SIGNAL(canResume(KIO::Job
*, KIO::filesize_t
)),
1970 SLOT( slotCanResume(KIO::Job
*, KIO::filesize_t
)));
1971 q
->connect( m_putJob
, SIGNAL(dataReq(KIO::Job
*, QByteArray
&)),
1972 SLOT( slotDataReq(KIO::Job
*, QByteArray
&)));
1973 q
->addSubjob( m_putJob
);
1976 void FileCopyJobPrivate::slotCanResume( KIO::Job
* job
, KIO::filesize_t offset
)
1979 if ( job
== m_putJob
|| job
== m_copyJob
)
1981 //kDebug(7007) << "'can resume' from PUT job. offset=" << KIO::number(offset);
1984 RenameDialog_Result res
= R_RESUME
;
1986 if (!KProtocolManager::autoResume() && !(m_flags
& Overwrite
))
1989 KIO::Job
* job
= ( q
->parentJob() ) ? q
->parentJob() : q
;
1990 // Ask confirmation about resuming previous transfer
1991 res
= ui()->askFileRename(
1992 job
, i18n("File Already Exists"),
1995 (RenameDialog_Mode
) (M_OVERWRITE
| M_RESUME
| M_NORENAME
), newPath
,
1996 m_sourceSize
, offset
);
1999 if ( res
== R_OVERWRITE
|| (m_flags
& Overwrite
) )
2001 else if ( res
== R_CANCEL
)
2003 if ( job
== m_putJob
)
2004 m_putJob
->kill( FileCopyJob::Quietly
);
2006 m_copyJob
->kill( FileCopyJob::Quietly
);
2007 q
->setError( ERR_USER_CANCELED
);
2013 m_resumeAnswerSent
= true; // No need for an answer
2015 if ( job
== m_putJob
)
2017 m_getJob
= KIO::get( m_src
, NoReload
, HideProgressInfo
/* no GUI */ );
2018 //kDebug(7007) << "m_getJob=" << m_getJob << m_src;
2019 m_getJob
->addMetaData( "errorPage", "false" );
2020 m_getJob
->addMetaData( "AllowCompressedPage", "false" );
2021 // Set size in subjob. This helps if the slave doesn't emit totalSize.
2022 if ( m_sourceSize
!= (KIO::filesize_t
)-1 )
2023 m_getJob
->setTotalAmount(KJob::Bytes
, m_sourceSize
);
2026 //kDebug(7007) << "Setting metadata for resume to" << (unsigned long) offset;
2027 // TODO KDE4: rename to seek or offset and document it
2028 // This isn't used only for resuming, but potentially also for extracting (#72302).
2029 m_getJob
->addMetaData( "resume", KIO::number(offset
) );
2031 // Might or might not get emitted
2032 q
->connect( m_getJob
, SIGNAL(canResume(KIO::Job
*, KIO::filesize_t
)),
2033 SLOT( slotCanResume(KIO::Job
*, KIO::filesize_t
)));
2035 jobSlave(m_putJob
)->setOffset( offset
);
2037 m_putJob
->d_func()->internalSuspend();
2038 q
->addSubjob( m_getJob
);
2039 connectSubjob( m_getJob
); // Progress info depends on get
2040 m_getJob
->d_func()->internalResume(); // Order a beer
2042 q
->connect( m_getJob
, SIGNAL(data(KIO::Job
*,const QByteArray
&)),
2043 SLOT( slotData(KIO::Job
*,const QByteArray
&)) );
2044 q
->connect( m_getJob
, SIGNAL(mimetype(KIO::Job
*,const QString
&) ),
2045 SLOT(slotMimetype(KIO::Job
*,const QString
&)) );
2049 jobSlave(m_copyJob
)->sendResumeAnswer( offset
!= 0 );
2052 else if ( job
== m_getJob
)
2054 // Cool, the get job said ok, we can resume
2056 //kDebug(7007) << "'can resume' from the GET job -> we can resume";
2058 jobSlave(m_getJob
)->setOffset( jobSlave(m_putJob
)->offset() );
2061 kWarning(7007) << "unknown job=" << job
2062 << "m_getJob=" << m_getJob
<< "m_putJob=" << m_putJob
;
2065 void FileCopyJobPrivate::slotData( KIO::Job
* , const QByteArray
&data
)
2067 //kDebug(7007) << "data size:" << data.size();
2069 if (!m_putJob
) return; // Don't crash
2070 m_getJob
->d_func()->internalSuspend();
2071 m_putJob
->d_func()->internalResume(); // Drink the beer
2074 // On the first set of data incoming, we tell the "put" slave about our
2075 // decision about resuming
2076 if (!m_resumeAnswerSent
)
2078 m_resumeAnswerSent
= true;
2079 //kDebug(7007) << "(first time) -> send resume answer " << m_canResume;
2080 jobSlave(m_putJob
)->sendResumeAnswer( m_canResume
);
2084 void FileCopyJobPrivate::slotDataReq( KIO::Job
* , QByteArray
&data
)
2088 if (!m_resumeAnswerSent
&& !m_getJob
) {
2089 // This can't happen
2090 q
->setError( ERR_INTERNAL
);
2091 q
->setErrorText( "'Put' job did not send canResume or 'Get' job did not send data!" );
2092 m_putJob
->kill( FileCopyJob::Quietly
);
2098 m_getJob
->d_func()->internalResume(); // Order more beer
2099 m_putJob
->d_func()->internalSuspend();
2102 m_buffer
= QByteArray();
2105 void FileCopyJobPrivate::slotMimetype( KIO::Job
*, const QString
& type
)
2108 emit q
->mimetype( q
, type
);
2111 void FileCopyJob::slotResult( KJob
*job
)
2114 //kDebug(7007) << "this=" << this << "job=" << job;
2116 // Did job have an error ?
2119 if ((job
== d
->m_moveJob
) && (job
->error() == ERR_UNSUPPORTED_ACTION
))
2122 d
->startBestCopyMethod();
2125 else if ((job
== d
->m_copyJob
) && (job
->error() == ERR_UNSUPPORTED_ACTION
))
2131 else if (job
== d
->m_getJob
)
2136 d
->m_putJob
->kill( Quietly
);
2137 removeSubjob( d
->m_putJob
);
2140 else if (job
== d
->m_putJob
)
2145 d
->m_getJob
->kill( Quietly
);
2146 removeSubjob( d
->m_getJob
);
2149 setError( job
->error() );
2150 setErrorText( job
->errorText() );
2157 // If d->m_permissions == -1, keep the default permissions
2158 if (d
->m_permissions
!= -1)
2160 d
->m_chmodJob
= chmod(d
->m_dest
, d
->m_permissions
);
2162 d
->m_mustChmod
= false;
2165 if (job
== d
->m_moveJob
)
2167 d
->m_moveJob
= 0; // Finished
2170 if (job
== d
->m_copyJob
)
2175 d
->m_delJob
= file_delete( d
->m_src
, HideProgressInfo
/*no GUI*/ ); // Delete source
2176 addSubjob(d
->m_delJob
);
2180 if (job
== d
->m_getJob
)
2182 //kDebug(7007) << "m_getJob finished";
2183 d
->m_getJob
= 0; // No action required
2185 d
->m_putJob
->d_func()->internalResume();
2188 if (job
== d
->m_putJob
)
2190 //kDebug(7007) << "m_putJob finished";
2194 // The get job is still running, probably after emitting data(QByteArray())
2195 // and before we receive its finished().
2196 d
->m_getJob
->d_func()->internalResume();
2200 d
->m_delJob
= file_delete( d
->m_src
, HideProgressInfo
/*no GUI*/ ); // Delete source
2201 addSubjob(d
->m_delJob
);
2205 if (job
== d
->m_delJob
)
2207 d
->m_delJob
= 0; // Finished
2210 if (job
== d
->m_chmodJob
)
2212 d
->m_chmodJob
= 0; // Finished
2215 if ( !hasSubjobs() )
2219 FileCopyJob
*KIO::file_copy( const KUrl
& src
, const KUrl
& dest
, int permissions
,
2222 return FileCopyJobPrivate::newJob(src
, dest
, permissions
, false, flags
);
2225 FileCopyJob
*KIO::file_move( const KUrl
& src
, const KUrl
& dest
, int permissions
,
2228 return FileCopyJobPrivate::newJob(src
, dest
, permissions
, true, flags
);
2231 SimpleJob
*KIO::file_delete( const KUrl
& src
, JobFlags flags
)
2233 KIO_ARGS
<< src
<< qint8(true); // isFile
2234 return SimpleJobPrivate::newJob(src
, CMD_DEL
, packedArgs
, flags
);
2239 class KIO::ListJobPrivate
: public KIO::SimpleJobPrivate
2242 ListJobPrivate(const KUrl
& url
, bool _recursive
, const QString
&_prefix
, bool _includeHidden
)
2243 : SimpleJobPrivate(url
, CMD_LISTDIR
, QByteArray()),
2244 recursive(_recursive
), includeHidden(_includeHidden
),
2245 prefix(_prefix
), m_processedEntries(0)
2250 unsigned long m_processedEntries
;
2251 KUrl m_redirectionURL
;
2255 * Called by the scheduler when a @p slave gets to
2257 * @param slave the slave that starts working on this job
2259 virtual void start( Slave
*slave
);
2261 void slotListEntries( const KIO::UDSEntryList
& list
);
2262 void slotRedirection( const KUrl
&url
);
2263 void gotEntries( KIO::Job
* subjob
, const KIO::UDSEntryList
& list
);
2265 Q_DECLARE_PUBLIC(ListJob
)
2267 static inline ListJob
*newJob(const KUrl
& u
, bool _recursive
, const QString
&_prefix
,
2268 bool _includeHidden
, JobFlags flags
= HideProgressInfo
)
2270 ListJob
*job
= new ListJob(*new ListJobPrivate(u
, _recursive
, _prefix
, _includeHidden
));
2271 job
->setUiDelegate(new JobUiDelegate
);
2272 if (!(flags
& HideProgressInfo
))
2273 KIO::getJobTracker()->registerJob(job
);
2276 static inline ListJob
*newJobNoUi(const KUrl
& u
, bool _recursive
, const QString
&_prefix
,
2277 bool _includeHidden
)
2279 return new ListJob(*new ListJobPrivate(u
, _recursive
, _prefix
, _includeHidden
));
2283 ListJob::ListJob(ListJobPrivate
&dd
)
2287 // We couldn't set the args when calling the parent constructor,
2289 QDataStream
stream( &d
->m_packedArgs
, QIODevice::WriteOnly
);
2297 void ListJobPrivate::slotListEntries( const KIO::UDSEntryList
& list
)
2300 // Emit progress info (takes care of emit processedSize and percent)
2301 m_processedEntries
+= list
.count();
2302 slotProcessedSize( m_processedEntries
);
2305 UDSEntryList::ConstIterator it
= list
.begin();
2306 const UDSEntryList::ConstIterator end
= list
.end();
2308 for (; it
!= end
; ++it
) {
2310 const UDSEntry
& entry
= *it
;
2313 // const UDSEntry::ConstIterator end2 = entry.end();
2314 // UDSEntry::ConstIterator it2 = entry.find( KIO::UDSEntry::UDS_URL );
2315 // if ( it2 != end2 )
2316 if (entry
.contains(KIO::UDSEntry::UDS_URL
))
2317 // itemURL = it2.value().toString();
2318 itemURL
= entry
.stringValue(KIO::UDSEntry::UDS_URL
);
2319 else { // no URL, use the name
2321 const QString fileName
= entry
.stringValue(KIO::UDSEntry::UDS_NAME
);
2322 Q_ASSERT(!fileName
.isEmpty()); // we'll recurse forever otherwise :)
2323 itemURL
.addPath(fileName
);
2326 if (entry
.isDir() && !entry
.isLink()) {
2327 const QString filename
= itemURL
.fileName();
2328 // skip hidden dirs when listing if requested
2329 if (filename
!= ".." && filename
!= "." && (includeHidden
|| filename
[0] != '.')) {
2330 ListJob
*job
= ListJobPrivate::newJobNoUi(itemURL
,
2332 prefix
+ filename
+ '/',
2334 Scheduler::scheduleJob(job
);
2335 q
->connect(job
, SIGNAL(entries( KIO::Job
*, const KIO::UDSEntryList
& )),
2336 SLOT( gotEntries( KIO::Job
*, const KIO::UDSEntryList
& )));
2343 // Not recursive, or top-level of recursive listing : return now (send . and .. as well)
2344 // exclusion of hidden files also requires the full sweep, but the case for full-listing
2345 // a single dir is probably common enough to justify the shortcut
2346 if (prefix
.isNull() && includeHidden
) {
2347 emit q
->entries(q
, list
);
2349 // cull the unwanted hidden dirs and/or parent dir references from the listing, then emit that
2350 UDSEntryList newlist
;
2352 UDSEntryList::const_iterator it
= list
.begin();
2353 const UDSEntryList::const_iterator end
= list
.end();
2354 for (; it
!= end
; ++it
) {
2356 // Modify the name in the UDSEntry
2357 UDSEntry newone
= *it
;
2358 const QString filename
= newone
.stringValue( KIO::UDSEntry::UDS_NAME
);
2359 // Avoid returning entries like subdir/. and subdir/.., but include . and .. for
2360 // the toplevel dir, and skip hidden files/dirs if that was requested
2361 if ( (prefix
.isNull() || (filename
!= ".." && filename
!= ".") )
2362 && (includeHidden
|| (filename
[0] != '.') ) )
2364 // ## Didn't find a way to use the iterator instead of re-doing a key lookup
2365 newone
.insert( KIO::UDSEntry::UDS_NAME
, prefix
+ filename
);
2366 newlist
.append(newone
);
2370 emit q
->entries(q
, newlist
);
2374 void ListJobPrivate::gotEntries(KIO::Job
*, const KIO::UDSEntryList
& list
)
2376 // Forward entries received by subjob - faking we received them ourselves
2378 emit q
->entries(q
, list
);
2381 void ListJob::slotResult( KJob
* job
)
2383 // If we can't list a subdir, the result is still ok
2384 // This is why we override Job::slotResult() - to skip error checking
2385 removeSubjob( job
);
2386 if ( !hasSubjobs() )
2390 void ListJobPrivate::slotRedirection( const KUrl
& url
)
2393 if (!KAuthorized::authorizeUrlAction("redirect", m_url
, url
))
2395 kWarning(7007) << "ListJob: Redirection from " << m_url
<< " to " << url
<< " REJECTED!";
2398 m_redirectionURL
= url
; // We'll remember that when the job finishes
2399 if (m_url
.hasUser() && !url
.hasUser() && (m_url
.host().toLower() == url
.host().toLower()))
2400 m_redirectionURL
.setUser(m_url
.user()); // Preserve user
2401 emit q
->redirection( q
, m_redirectionURL
);
2404 void ListJob::slotFinished()
2407 // Support for listing archives as directories
2408 if ( error() == KIO::ERR_IS_FILE
&& d
->m_url
.isLocalFile() ) {
2409 KMimeType::Ptr ptr
= KMimeType::findByUrl( d
->m_url
, 0, true, true );
2411 QString proto
= ptr
->property("X-KDE-LocalProtocol").toString();
2412 if ( !proto
.isEmpty() && KProtocolInfo::isKnownProtocol( proto
) ) {
2413 d
->m_redirectionURL
= d
->m_url
;
2414 d
->m_redirectionURL
.setProtocol( proto
);
2416 emit
redirection(this,d
->m_redirectionURL
);
2420 if ( d
->m_redirectionURL
.isEmpty() || !d
->m_redirectionURL
.isValid() || error() ) {
2421 // Return slave to the scheduler
2422 SimpleJob::slotFinished();
2425 //kDebug(7007) << "Redirection to " << d->m_redirectionURL;
2426 if (queryMetaData("permanent-redirect")=="true")
2427 emit
permanentRedirection(this, d
->m_url
, d
->m_redirectionURL
);
2428 d
->m_url
= d
->m_redirectionURL
;
2429 d
->m_redirectionURL
= KUrl();
2430 d
->m_packedArgs
.truncate(0);
2431 QDataStream
stream( &d
->m_packedArgs
, QIODevice::WriteOnly
);
2434 // Return slave to the scheduler
2436 Scheduler::doJob(this);
2440 void ListJob::slotMetaData( const KIO::MetaData
&_metaData
)
2443 SimpleJob::slotMetaData(_metaData
);
2444 storeSSLSessionFromJob(d
->m_redirectionURL
);
2447 ListJob
*KIO::listDir( const KUrl
& url
, JobFlags flags
, bool includeHidden
)
2449 return ListJobPrivate::newJob(url
, false, QString(), includeHidden
, flags
);
2452 ListJob
*KIO::listRecursive( const KUrl
& url
, JobFlags flags
, bool includeHidden
)
2454 return ListJobPrivate::newJob(url
, true, QString(), includeHidden
, flags
);
2457 void ListJob::setUnrestricted(bool unrestricted
)
2461 d
->m_extraFlags
|= JobPrivate::EF_ListJobUnrestricted
;
2463 d
->m_extraFlags
&= ~JobPrivate::EF_ListJobUnrestricted
;
2466 void ListJobPrivate::start(Slave
*slave
)
2469 if (!KAuthorized::authorizeUrlAction("list", m_url
, m_url
) &&
2470 !(m_extraFlags
& EF_ListJobUnrestricted
))
2472 q
->setError( ERR_ACCESS_DENIED
);
2473 q
->setErrorText( m_url
.url() );
2474 QTimer::singleShot(0, q
, SLOT(slotFinished()) );
2477 q
->connect( slave
, SIGNAL( listEntries( const KIO::UDSEntryList
& )),
2478 SLOT( slotListEntries( const KIO::UDSEntryList
& )));
2479 q
->connect( slave
, SIGNAL( totalSize( KIO::filesize_t
) ),
2480 SLOT( slotTotalSize( KIO::filesize_t
) ) );
2481 q
->connect( slave
, SIGNAL( redirection(const KUrl
&) ),
2482 SLOT( slotRedirection(const KUrl
&) ) );
2484 SimpleJobPrivate::start(slave
);
2487 const KUrl
& ListJob::redirectionUrl() const
2489 return d_func()->m_redirectionURL
;
2494 class KIO::MultiGetJobPrivate
: public KIO::TransferJobPrivate
2497 MultiGetJobPrivate(const KUrl
& url
)
2498 : TransferJobPrivate(url
, 0, QByteArray(), QByteArray()),
2499 m_currentEntry( 0, KUrl(), MetaData() )
2502 GetRequest(long _id
, const KUrl
&_url
, const MetaData
&_metaData
)
2503 : id(_id
), url(_url
), metaData(_metaData
) { }
2508 inline bool operator==( const GetRequest
& req
) const
2509 { return req
.id
== id
; }
2511 typedef QLinkedList
<GetRequest
> RequestQueue
;
2513 RequestQueue m_waitQueue
;
2514 RequestQueue m_activeQueue
;
2515 GetRequest m_currentEntry
;
2516 bool b_multiGetActive
;
2520 * Called by the scheduler when a @p slave gets to
2522 * @param slave the slave that starts working on this job
2524 virtual void start(Slave
*slave
);
2526 bool findCurrentEntry();
2527 void flushQueue(QLinkedList
<GetRequest
> &queue
);
2529 Q_DECLARE_PUBLIC(MultiGetJob
)
2531 static inline MultiGetJob
*newJob(const KUrl
&url
)
2533 MultiGetJob
*job
= new MultiGetJob(*new MultiGetJobPrivate(url
));
2534 job
->setUiDelegate(new JobUiDelegate
);
2539 MultiGetJob::MultiGetJob(MultiGetJobPrivate
&dd
)
2544 MultiGetJob::~MultiGetJob()
2548 void MultiGetJob::get(long id
, const KUrl
&url
, const MetaData
&metaData
)
2551 MultiGetJobPrivate::GetRequest
entry(id
, url
, metaData
);
2552 entry
.metaData
["request-id"] = QString::number(id
);
2553 d
->m_waitQueue
.append(entry
);
2556 void MultiGetJobPrivate::flushQueue(RequestQueue
&queue
)
2559 // Scan all jobs in m_waitQueue
2560 RequestQueue::iterator wqit
= m_waitQueue
.begin();
2561 const RequestQueue::iterator wqend
= m_waitQueue
.end();
2562 while ( wqit
!= wqend
)
2564 const GetRequest
& entry
= *wqit
;
2565 if ((m_url
.protocol() == entry
.url
.protocol()) &&
2566 (m_url
.host() == entry
.url
.host()) &&
2567 (m_url
.port() == entry
.url
.port()) &&
2568 (m_url
.user() == entry
.url
.user()))
2570 queue
.append( entry
);
2571 wqit
= m_waitQueue
.erase( wqit
);
2578 // Send number of URLs, (URL, metadata)*
2579 KIO_ARGS
<< (qint32
) queue
.count();
2580 RequestQueue::const_iterator qit
= queue
.begin();
2581 const RequestQueue::const_iterator qend
= queue
.end();
2582 for( ; qit
!= qend
; ++qit
)
2584 stream
<< (*qit
).url
<< (*qit
).metaData
;
2586 m_packedArgs
= packedArgs
;
2587 m_command
= CMD_MULTI_GET
;
2588 m_outgoingMetaData
.clear();
2591 void MultiGetJobPrivate::start(Slave
*slave
)
2593 // Add first job from m_waitQueue and add it to m_activeQueue
2594 GetRequest entry
= m_waitQueue
.takeFirst();
2595 m_activeQueue
.append(entry
);
2599 if (!entry
.url
.protocol().startsWith("http"))
2602 KIO_ARGS
<< entry
.url
;
2603 m_packedArgs
= packedArgs
;
2604 m_outgoingMetaData
= entry
.metaData
;
2605 m_command
= CMD_GET
;
2606 b_multiGetActive
= false;
2610 flushQueue(m_activeQueue
);
2611 b_multiGetActive
= true;
2614 TransferJobPrivate::start(slave
); // Anything else to do??
2617 bool MultiGetJobPrivate::findCurrentEntry()
2619 if (b_multiGetActive
)
2621 long id
= m_incomingMetaData
["request-id"].toLong();
2622 RequestQueue::const_iterator qit
= m_activeQueue
.begin();
2623 const RequestQueue::const_iterator qend
= m_activeQueue
.end();
2624 for( ; qit
!= qend
; ++qit
)
2626 if ((*qit
).id
== id
)
2628 m_currentEntry
= *qit
;
2632 m_currentEntry
.id
= 0;
2637 if ( m_activeQueue
.isEmpty() )
2639 m_currentEntry
= m_activeQueue
.first();
2644 void MultiGetJob::slotRedirection( const KUrl
&url
)
2647 if (!d
->findCurrentEntry()) return; // Error
2648 if (!KAuthorized::authorizeUrlAction("redirect", d
->m_url
, url
))
2650 kWarning(7007) << "MultiGetJob: Redirection from " << d
->m_currentEntry
.url
<< " to " << url
<< " REJECTED!";
2653 d
->m_redirectionURL
= url
;
2654 if (d
->m_currentEntry
.url
.hasUser() && !url
.hasUser() && (d
->m_currentEntry
.url
.host().toLower() == url
.host().toLower()))
2655 d
->m_redirectionURL
.setUser(d
->m_currentEntry
.url
.user()); // Preserve user
2656 get(d
->m_currentEntry
.id
, d
->m_redirectionURL
, d
->m_currentEntry
.metaData
); // Try again
2660 void MultiGetJob::slotFinished()
2663 if (!d
->findCurrentEntry()) return;
2664 if (d
->m_redirectionURL
.isEmpty())
2666 // No redirection, tell the world that we are finished.
2667 emit
result(d
->m_currentEntry
.id
);
2669 d
->m_redirectionURL
= KUrl();
2671 d
->m_incomingMetaData
.clear();
2672 d
->m_activeQueue
.removeAll(d
->m_currentEntry
);
2673 if (d
->m_activeQueue
.count() == 0)
2675 if (d
->m_waitQueue
.count() == 0)
2678 TransferJob::slotFinished();
2682 // return slave to pool
2683 // fetch new slave for first entry in d->m_waitQueue and call start
2685 d
->m_url
= d
->m_waitQueue
.first().url
;
2687 Scheduler::doJob(this);
2692 void MultiGetJob::slotData( const QByteArray
&_data
)
2695 if(d
->m_redirectionURL
.isEmpty() || !d
->m_redirectionURL
.isValid() || error())
2696 emit
data(d
->m_currentEntry
.id
, _data
);
2699 void MultiGetJob::slotMimetype( const QString
&_mimetype
)
2702 if (d
->b_multiGetActive
)
2704 MultiGetJobPrivate::RequestQueue newQueue
;
2705 d
->flushQueue(newQueue
);
2706 if (!newQueue
.isEmpty())
2708 d
->m_activeQueue
+= newQueue
;
2709 d
->m_slave
->send( d
->m_command
, d
->m_packedArgs
);
2712 if (!d
->findCurrentEntry()) return; // Error, unknown request!
2713 emit
mimetype(d
->m_currentEntry
.id
, _mimetype
);
2716 MultiGetJob
*KIO::multi_get(long id
, const KUrl
&url
, const MetaData
&metaData
)
2718 MultiGetJob
* job
= MultiGetJobPrivate::newJob(url
);
2719 job
->get(id
, url
, metaData
);
2723 class KIO::SpecialJobPrivate
: public TransferJobPrivate
2725 SpecialJobPrivate(const KUrl
& url
, int command
,
2726 const QByteArray
&packedArgs
,
2727 const QByteArray
&_staticData
)
2728 : TransferJobPrivate(url
, command
, packedArgs
, _staticData
)
2732 SpecialJob::SpecialJob(const KUrl
&url
, const QByteArray
&packedArgs
)
2733 : TransferJob(*new TransferJobPrivate(url
, CMD_SPECIAL
, packedArgs
, QByteArray()))
2737 SpecialJob::~SpecialJob()
2741 void SpecialJob::setArguments(const QByteArray
&data
)
2744 d
->m_packedArgs
= data
;
2747 QByteArray
SpecialJob::arguments() const
2749 return d_func()->m_packedArgs
;
2752 // Never defined, never used - what's this code about?
2754 CacheInfo::CacheInfo(const KUrl
&url
)
2759 QString
CacheInfo::cachedFileName()
2761 const QChar separator
= '_';
2763 QString CEF
= m_url
.path();
2765 int p
= CEF
.find('/');
2770 p
= CEF
.find('/', p
);
2773 QString host
= m_url
.host().toLower();
2774 CEF
= host
+ CEF
+ '_';
2776 QString dir
= KProtocolManager::cacheDir();
2777 if (dir
[dir
.length()-1] != '/')
2780 int l
= m_url
.host().length();
2781 for(int i
= 0; i
< l
; i
++)
2783 if (host
[i
].isLetter() && (host
[i
] != 'w'))
2789 if (dir
[dir
.length()-1] == '/')
2792 unsigned long hash
= 0x00000000;
2793 QString u
= m_url
.url().toLatin1();
2794 for(int i
= u
.length(); i
--;)
2796 hash
= (hash
* 12211 + u
[i
]) % 2147483563;
2800 hashString
.sprintf("%08lx", hash
);
2802 CEF
= CEF
+ hashString
;
2804 CEF
= dir
+ '/' + CEF
;
2809 QFile
*CacheInfo::cachedFile()
2812 const char *mode
= (readWrite
? "rb+" : "rb");
2814 const char *mode
= (readWrite
? "r+" : "r");
2817 FILE *fs
= KDE_fopen(QFile::encodeName(CEF
), mode
); // Open for reading and writing
2825 if (ok
&& (!fgets(buffer
, 400, fs
)))
2827 if (ok
&& (strcmp(buffer
, CACHE_REVISION
) != 0))
2831 time_t currentDate
= time(0);
2834 if (ok
&& (!fgets(buffer
, 400, fs
)))
2838 int l
= strlen(buffer
);
2840 buffer
[l
-1] = 0; // Strip newline
2841 if (m_
.url
.url() != buffer
)
2843 ok
= false; // Hash collision
2848 if (ok
&& (!fgets(buffer
, 400, fs
)))
2852 date
= (time_t) strtoul(buffer
, 0, 10);
2853 if (m_maxCacheAge
&& (difftime(currentDate
, date
) > m_maxCacheAge
))
2855 m_bMustRevalidate
= true;
2856 m_expireDate
= currentDate
;
2861 m_cacheExpireDateOffset
= KDE_ftell(fs
);
2862 if (ok
&& (!fgets(buffer
, 400, fs
)))
2866 if (m_request
.cache
== CC_Verify
)
2868 date
= (time_t) strtoul(buffer
, 0, 10);
2869 // After the expire date we need to revalidate.
2870 if (!date
|| difftime(currentDate
, date
) >= 0)
2871 m_bMustRevalidate
= true;
2872 m_expireDate
= date
;
2877 if (ok
&& (!fgets(buffer
, 400, fs
)))
2881 m_etag
= QString(buffer
).trimmed();
2885 if (ok
&& (!fgets(buffer
, 400, fs
)))
2889 m_lastModified
= QString(buffer
).trimmed();
2897 unlink( QFile::encodeName(CEF
) );
2902 void CacheInfo::flush()
2904 cachedFile().remove();
2907 void CacheInfo::touch()
2911 void CacheInfo::setExpireDate(int);
2912 void CacheInfo::setExpireTimeout(int);
2915 int CacheInfo::creationDate();
2916 int CacheInfo::expireDate();
2917 int CacheInfo::expireTimeout();
2920 #include "jobclasses.moc"
2921 #include "job_p.moc"