• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdeio/tdeio
 

tdeio/tdeio

  • tdeio
  • tdeio
job.cpp
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>
5
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.
10
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.
15
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.
20*/
21
22#include "tdeio/job.h"
23
24#include <config.h>
25
26#include <sys/types.h>
27#include <sys/wait.h>
28#include <sys/stat.h>
29
30#include <assert.h>
31
32#include <signal.h>
33#include <stdlib.h>
34#include <stdio.h>
35#include <time.h>
36#include <unistd.h>
37extern "C" {
38#include <pwd.h>
39#include <grp.h>
40}
41#include <tqtimer.h>
42#include <tqfile.h>
43
44#include <tdeapplication.h>
45#include <tdeglobal.h>
46#include <tdelocale.h>
47#include <ksimpleconfig.h>
48#include <kdebug.h>
49#include <kdialog.h>
50#include <tdemessagebox.h>
51#include <kdatastream.h>
52#include <tdemainwindow.h>
53#include <kde_file.h>
54
55#include <errno.h>
56
57#include "kmimetype.h"
58#include "slave.h"
59#include "scheduler.h"
60#include "kdirwatch.h"
61#include "kmimemagic.h"
62#include "kprotocolinfo.h"
63#include "tdeprotocolmanager.h"
64
65#include "tdeio/observer.h"
66
67#include "kssl/ksslcsessioncache.h"
68
69#include <kdirnotify_stub.h>
70#include <tdetempfile.h>
71#include <dcopclient.h>
72
73#ifdef Q_OS_UNIX
74#include <utime.h>
75#endif
76#if defined TQ_WS_X11
77#include <netwm.h>
78#include <fixx11h.h>
79#endif
80
81using namespace TDEIO;
82template class TQPtrList<TDEIO::Job>;
83
84//this will update the report dialog with 5 Hz, I think this is fast enough, aleXXX
85#define REPORT_TIMEOUT 200
86
87#define TDEIO_ARGS TQByteArray packedArgs; TQDataStream stream( packedArgs, IO_WriteOnly ); stream
88
89class Job::JobPrivate
90{
91public:
92 JobPrivate() : m_autoErrorHandling(false), m_autoWarningHandling(true),
93 m_interactive(true), m_errorParentWidgetGP(0), m_parentJob(0L),
94 m_extraFlags(0), m_processedSize(0), m_userTimestamp(0)
95 {}
96
97 ~JobPrivate()
98 {
99 if (m_errorParentWidgetGP)
100 {
101 delete m_errorParentWidgetGP;
102 }
103 }
104
105 bool m_autoErrorHandling;
106 bool m_autoWarningHandling;
107 bool m_interactive;
108 TQGuardedPtr<TQWidget> *m_errorParentWidgetGP;
109 // Maybe we could use the TQObject parent/child mechanism instead
110 // (requires a new ctor, and moving the ctor code to some init()).
111 Job* m_parentJob;
112 int m_extraFlags;
113 TDEIO::filesize_t m_processedSize;
114 unsigned long m_userTimestamp;
115};
116
117static TQObject *__job_root_obj = nullptr;
118
119static TQObject* __getJobRoot()
120{
121 if (!__job_root_obj)
122 {
123 __job_root_obj = new TQObject(0, "jobroot");
124 }
125 return __job_root_obj;
126}
127
128Job::Job(bool showProgressInfo) : TQObject(__getJobRoot(), "job"), m_error(0), m_percent(0)
129 , m_progressId(0), m_speedTimer(0), d( new JobPrivate )
130{
131 // All jobs delete themselves after emiting 'result'.
132
133 // Notify the UI Server and get a progress id
134 if ( showProgressInfo )
135 {
136 m_progressId = Observer::self()->newJob( this, true );
137 addMetaData("progress-id", TQString::number(m_progressId));
138 //kdDebug(7007) << "Created job " << this << " with progress info -- m_progressId=" << m_progressId << endl;
139 // Connect global progress info signals
140 connect( this, TQ_SIGNAL( percent( TDEIO::Job*, unsigned long ) ),
141 Observer::self(), TQ_SLOT( slotPercent( TDEIO::Job*, unsigned long ) ) );
142 connect( this, TQ_SIGNAL( infoMessage( TDEIO::Job*, const TQString & ) ),
143 Observer::self(), TQ_SLOT( slotInfoMessage( TDEIO::Job*, const TQString & ) ) );
144 connect( this, TQ_SIGNAL( totalSize( TDEIO::Job*, TDEIO::filesize_t ) ),
145 Observer::self(), TQ_SLOT( slotTotalSize( TDEIO::Job*, TDEIO::filesize_t ) ) );
146 connect( this, TQ_SIGNAL( processedSize( TDEIO::Job*, TDEIO::filesize_t ) ),
147 Observer::self(), TQ_SLOT( slotProcessedSize( TDEIO::Job*, TDEIO::filesize_t ) ) );
148 connect( this, TQ_SIGNAL( speed( TDEIO::Job*, unsigned long ) ),
149 Observer::self(), TQ_SLOT( slotSpeed( TDEIO::Job*, unsigned long ) ) );
150 }
151 // Don't exit while this job is running
152 if (tdeApp)
153 tdeApp->ref();
154 if (tdeApp)
155 updateUserTimestamp( tdeApp->userTimestamp());
156}
157
158Job::~Job()
159{
160 delete m_speedTimer;
161 delete d;
162 if (tdeApp)
163 {
164 tdeApp->deref();
165 }
166}
167
168int& Job::extraFlags()
169{
170 return d->m_extraFlags;
171}
172
173void Job::setProcessedSize(TDEIO::filesize_t size)
174{
175 d->m_processedSize = size;
176}
177
178TDEIO::filesize_t Job::getProcessedSize()
179{
180 return d->m_processedSize;
181}
182
183void Job::addSubjob(Job *job, bool inheritMetaData)
184{
185 //kdDebug(7007) << "addSubjob(" << job << ") this = " << this << endl;
186 subjobs.append(job);
187
188 connect( job, TQ_SIGNAL(result(TDEIO::Job*)),
189 TQ_SLOT(slotResult(TDEIO::Job*)) );
190
191 // Forward information from that subjob.
192 connect( job, TQ_SIGNAL(speed( TDEIO::Job*, unsigned long )),
193 TQ_SLOT(slotSpeed(TDEIO::Job*, unsigned long)) );
194
195 connect( job, TQ_SIGNAL(infoMessage( TDEIO::Job*, const TQString & )),
196 TQ_SLOT(slotInfoMessage(TDEIO::Job*, const TQString &)) );
197
198 if (inheritMetaData)
199 job->mergeMetaData(m_outgoingMetaData);
200
201 job->setWindow( m_window );
202 job->updateUserTimestamp( d->m_userTimestamp );
203}
204
205void Job::removeSubjob( Job *job )
206{
207 removeSubjob( job, false, true );
208}
209
210void Job::removeSubjob( Job *job, bool mergeMetaData, bool emitResultIfLast )
211{
212 //kdDebug(7007) << "removeSubjob(" << job << ") this = " << this << " subjobs = " << subjobs.count() << endl;
213 // Merge metadata from subjob
214 if ( mergeMetaData )
215 m_incomingMetaData += job->metaData();
216 subjobs.remove(job);
217 if ( subjobs.isEmpty() && emitResultIfLast )
218 emitResult();
219}
220
221void Job::emitPercent( TDEIO::filesize_t processedSize, TDEIO::filesize_t totalSize )
222{
223 // calculate percents
224 unsigned long ipercent = m_percent;
225
226 if ( totalSize == 0 )
227 m_percent = 100;
228 else
229 m_percent = (unsigned long)(( (float)(processedSize) / (float)(totalSize) ) * 100.0);
230
231 if ( m_percent != ipercent || m_percent == 100 /* for those buggy total sizes that grow */ ) {
232 emit percent( this, m_percent );
233 //kdDebug(7007) << "Job::emitPercent - percent = " << (unsigned int) m_percent << endl;
234 }
235}
236
237void Job::emitSpeed( unsigned long bytes_per_second )
238{
239 //kdDebug(7007) << "Job " << this << " emitSpeed " << bytes_per_second << endl;
240 if ( !m_speedTimer )
241 {
242 m_speedTimer = new TQTimer();
243 connect( m_speedTimer, TQ_SIGNAL( timeout() ), TQ_SLOT( slotSpeedTimeout() ) );
244 }
245 emit speed( this, bytes_per_second );
246 m_speedTimer->start( 5000 ); // 5 seconds interval should be enough
247}
248
249void Job::emitResult()
250{
251 // If we are displaying a progress dialog, remove it first.
252 if ( m_progressId ) // Did we get an ID from the observer ?
253 Observer::self()->jobFinished( m_progressId );
254 if ( m_error && d->m_interactive && d->m_autoErrorHandling )
255 showErrorDialog( d->m_errorParentWidgetGP ? *d->m_errorParentWidgetGP : nullptr);
256 emit result(this);
257 deleteLater();
258}
259
260void Job::kill( bool quietly )
261{
262 kdDebug(7007) << "Job::kill this=" << this << " " << className() << " m_progressId=" << m_progressId << " quietly=" << quietly << endl;
263 // kill all subjobs, without triggering their result slot
264 TQPtrListIterator<Job> it( subjobs );
265 for ( ; it.current() ; ++it )
266 (*it)->kill( true );
267 subjobs.clear();
268
269 if ( ! quietly ) {
270 m_error = ERR_USER_CANCELED;
271 emit canceled( this ); // Not very useful (deprecated)
272 emitResult();
273 } else
274 {
275 if ( m_progressId ) // in both cases we want to hide the progress window
276 Observer::self()->jobFinished( m_progressId );
277 deleteLater();
278 }
279}
280
281void Job::slotResult( Job *job )
282{
283 // Did job have an error ?
284 if ( job->error() && !m_error )
285 {
286 // Store it in the parent only if first error
287 m_error = job->error();
288 m_errorText = job->errorText();
289 }
290 removeSubjob(job);
291}
292
293void Job::slotSpeed( TDEIO::Job*, unsigned long speed )
294{
295 //kdDebug(7007) << "Job::slotSpeed " << speed << endl;
296 emitSpeed( speed );
297}
298
299void Job::slotInfoMessage( TDEIO::Job*, const TQString & msg )
300{
301 emit infoMessage( this, msg );
302}
303
304void Job::slotSpeedTimeout()
305{
306 //kdDebug(7007) << "slotSpeedTimeout()" << endl;
307 // send 0 and stop the timer
308 // timer will be restarted only when we receive another speed event
309 emit speed( this, 0 );
310 m_speedTimer->stop();
311}
312
313//Job::errorString is implemented in global.cpp
314
315void Job::showErrorDialog( TQWidget * parent )
316{
317 //kdDebug(7007) << "Job::showErrorDialog parent=" << parent << endl;
318 tdeApp->enableStyles();
319 // Show a message box, except for "user canceled" or "no content"
320 if ( (m_error != ERR_USER_CANCELED) && (m_error != ERR_NO_CONTENT) ) {
321 //old plain error message
322 //kdDebug(7007) << "Default language: " << TDEGlobal::locale()->defaultLanguage() << endl;
323 if ( 1 )
324 KMessageBox::queuedMessageBox( parent, KMessageBox::Error, errorString() );
325#if 0
326 } else {
327 TQStringList errors = detailedErrorStrings();
328 TQString caption, err, detail;
329 TQStringList::const_iterator it = errors.begin();
330 if ( it != errors.end() )
331 caption = *(it++);
332 if ( it != errors.end() )
333 err = *(it++);
334 if ( it != errors.end() )
335 detail = *it;
336 KMessageBox::queuedDetailedError( parent, err, detail, caption );
337 }
338#endif
339 }
340}
341
342void Job::setAutoErrorHandlingEnabled( bool enable, TQWidget *parentWidget )
343{
344 if (d->m_errorParentWidgetGP && (TQWidget*)(*d->m_errorParentWidgetGP) != parentWidget)
345 {
346 delete d->m_errorParentWidgetGP;
347 d->m_errorParentWidgetGP = nullptr;
348 }
349 d->m_autoErrorHandling = enable;
350 if (enable && parentWidget && !d->m_errorParentWidgetGP)
351 {
352 d->m_errorParentWidgetGP = new TQGuardedPtr<TQWidget>(parentWidget);
353 }
354}
355
356bool Job::isAutoErrorHandlingEnabled() const
357{
358 return d->m_autoErrorHandling;
359}
360
361void Job::setAutoWarningHandlingEnabled( bool enable )
362{
363 d->m_autoWarningHandling = enable;
364}
365
366bool Job::isAutoWarningHandlingEnabled() const
367{
368 return d->m_autoWarningHandling;
369}
370
371void Job::setInteractive(bool enable)
372{
373 d->m_interactive = enable;
374}
375
376bool Job::isInteractive() const
377{
378 return d->m_interactive;
379}
380
381void Job::setWindow(TQWidget *window)
382{
383 m_window = window;
384 TDEIO::Scheduler::registerWindow(window);
385}
386
387TQWidget *Job::window() const
388{
389 return m_window;
390}
391
392void Job::updateUserTimestamp( unsigned long time )
393{
394#if defined TQ_WS_X11
395 if( d->m_userTimestamp == 0 || NET::timestampCompare( time, d->m_userTimestamp ) > 0 )
396 d->m_userTimestamp = time;
397#endif
398}
399
400unsigned long Job::userTimestamp() const
401{
402 return d->m_userTimestamp;
403}
404
405void Job::setParentJob(Job* job)
406{
407 Q_ASSERT(d->m_parentJob == 0L);
408 Q_ASSERT(job);
409 d->m_parentJob = job;
410}
411
412Job* Job::parentJob() const
413{
414 return d->m_parentJob;
415}
416
417MetaData Job::metaData() const
418{
419 return m_incomingMetaData;
420}
421
422TQString Job::queryMetaData(const TQString &key)
423{
424 if (!m_incomingMetaData.contains(key))
425 return TQString::null;
426 return m_incomingMetaData[key];
427}
428
429void Job::setMetaData( const TDEIO::MetaData &_metaData)
430{
431 m_outgoingMetaData = _metaData;
432}
433
434void Job::addMetaData( const TQString &key, const TQString &value)
435{
436 m_outgoingMetaData.insert(key, value);
437}
438
439void Job::addMetaData( const TQMap<TQString,TQString> &values)
440{
441 TQMapConstIterator<TQString,TQString> it = values.begin();
442 for(;it != values.end(); ++it)
443 m_outgoingMetaData.insert(it.key(), it.data());
444}
445
446void Job::mergeMetaData( const TQMap<TQString,TQString> &values)
447{
448 TQMapConstIterator<TQString,TQString> it = values.begin();
449 for(;it != values.end(); ++it)
450 m_outgoingMetaData.insert(it.key(), it.data(), false);
451}
452
453MetaData Job::outgoingMetaData() const
454{
455 return m_outgoingMetaData;
456}
457
458
459SimpleJob::SimpleJob(const KURL& url, int command, const TQByteArray &packedArgs,
460 bool showProgressInfo )
461 : Job(showProgressInfo), m_slave(0), m_packedArgs(packedArgs),
462 m_url(url), m_command(command), m_totalSize(0)
463{
464 if (m_url.hasSubURL())
465 {
466 KURL::List list = KURL::split(m_url);
467 KURL::List::Iterator it = list.fromLast();
468 list.remove(it);
469 m_subUrl = KURL::join(list);
470 //kdDebug(7007) << "New URL = " << m_url.url() << endl;
471 //kdDebug(7007) << "Sub URL = " << m_subUrl.url() << endl;
472 }
473
474 Scheduler::doJob(this);
475
476 if (!m_url.isValid())
477 {
478 kdDebug() << "ERR_MALFORMED_URL" << endl;
479 m_error = ERR_MALFORMED_URL;
480 m_errorText = m_url.url();
481 TQTimer::singleShot(0, this, TQ_SLOT(slotFinished()) );
482 return;
483 }
484}
485
486void SimpleJob::kill( bool quietly )
487{
488 Scheduler::cancelJob( this ); // deletes the slave if not 0
489 m_slave = 0; // -> set to 0
490 Job::kill( quietly );
491}
492
493void SimpleJob::putOnHold()
494{
495 Q_ASSERT( m_slave );
496 if ( m_slave )
497 {
498 Scheduler::putSlaveOnHold(this, m_url);
499 m_slave = 0;
500 }
501 kill(true);
502}
503
504void SimpleJob::removeOnHold()
505{
506 Scheduler::removeSlaveOnHold();
507}
508
509SimpleJob::~SimpleJob()
510{
511 if (m_slave) // was running
512 {
513 kdDebug(7007) << "SimpleJob::~SimpleJob: Killing running job in destructor!" << endl;
514#if 0
515 m_slave->kill();
516 Scheduler::jobFinished( this, m_slave ); // deletes the slave
517#endif
518 Scheduler::cancelJob( this );
519 m_slave = 0; // -> set to 0
520 }
521}
522
523void SimpleJob::start(Slave *slave)
524{
525 m_slave = slave;
526
527 connect( m_slave, TQ_SIGNAL( error( int , const TQString & ) ),
528 TQ_SLOT( slotError( int , const TQString & ) ) );
529
530 connect( m_slave, TQ_SIGNAL( warning( const TQString & ) ),
531 TQ_SLOT( slotWarning( const TQString & ) ) );
532
533 connect( m_slave, TQ_SIGNAL( infoMessage( const TQString & ) ),
534 TQ_SLOT( slotInfoMessage( const TQString & ) ) );
535
536 connect( m_slave, TQ_SIGNAL( connected() ),
537 TQ_SLOT( slotConnected() ) );
538
539 connect( m_slave, TQ_SIGNAL( finished() ),
540 TQ_SLOT( slotFinished() ) );
541
542 if ((extraFlags() & EF_TransferJobDataSent) == 0)
543 {
544 connect( m_slave, TQ_SIGNAL( totalSize( TDEIO::filesize_t ) ),
545 TQ_SLOT( slotTotalSize( TDEIO::filesize_t ) ) );
546
547 connect( m_slave, TQ_SIGNAL( processedSize( TDEIO::filesize_t ) ),
548 TQ_SLOT( slotProcessedSize( TDEIO::filesize_t ) ) );
549
550 connect( m_slave, TQ_SIGNAL( speed( unsigned long ) ),
551 TQ_SLOT( slotSpeed( unsigned long ) ) );
552 }
553
554 connect( slave, TQ_SIGNAL( needProgressId() ),
555 TQ_SLOT( slotNeedProgressId() ) );
556
557 connect( slave, TQ_SIGNAL(metaData( const TDEIO::MetaData& ) ),
558 TQ_SLOT( slotMetaData( const TDEIO::MetaData& ) ) );
559
560 if (m_window)
561 {
562 TQString id;
563 addMetaData("window-id", id.setNum((ulong)m_window->winId()));
564 }
565 if (userTimestamp())
566 {
567 TQString id;
568 addMetaData("user-timestamp", id.setNum(userTimestamp()));
569 }
570
571 TQString sslSession = KSSLCSessionCache::getSessionForURL(m_url);
572 if ( !sslSession.isNull() )
573 {
574 addMetaData("ssl_session_id", sslSession);
575 }
576
577 if (!isInteractive())
578 {
579 addMetaData("no-auth-prompt", "true");
580 }
581
582 if (!m_outgoingMetaData.isEmpty())
583 {
584 TDEIO_ARGS << m_outgoingMetaData;
585 slave->send( CMD_META_DATA, packedArgs );
586 }
587
588 if (!m_subUrl.isEmpty())
589 {
590 TDEIO_ARGS << m_subUrl;
591 m_slave->send( CMD_SUBURL, packedArgs );
592 }
593
594 m_slave->send( m_command, m_packedArgs );
595}
596
597void SimpleJob::slaveDone()
598{
599 if (!m_slave) return;
600 disconnect(m_slave); // Remove all signals between slave and job
601 Scheduler::jobFinished( this, m_slave );
602 m_slave = 0;
603}
604
605void SimpleJob::slotFinished( )
606{
607 // Return slave to the scheduler
608 slaveDone();
609
610 if (subjobs.isEmpty())
611 {
612 if ( !m_error && (m_command == CMD_MKDIR || m_command == CMD_RENAME ) )
613 {
614 KDirNotify_stub allDirNotify( "*", "KDirNotify*" );
615 if ( m_command == CMD_MKDIR )
616 {
617 KURL urlDir( url() );
618 urlDir.setPath( urlDir.directory() );
619 allDirNotify.FilesAdded( urlDir );
620 }
621 else /*if ( m_command == CMD_RENAME )*/
622 {
623 KURL src, dst;
624 TQDataStream str( m_packedArgs, IO_ReadOnly );
625 str >> src >> dst;
626 if ( src.directory() == dst.directory() ) // For the user, moving isn't renaming. Only renaming is.
627 allDirNotify.FileRenamed( src, dst );
628 }
629 }
630 emitResult();
631 }
632}
633
634void SimpleJob::slotError( int error, const TQString & errorText )
635{
636 m_error = error;
637 m_errorText = errorText;
638 if ((m_error == ERR_UNKNOWN_HOST) && m_url.host().isEmpty())
639 m_errorText = TQString::null;
640 // error terminates the job
641 slotFinished();
642}
643
644void SimpleJob::slotWarning( const TQString & errorText )
645{
646 TQGuardedPtr<SimpleJob> guard( this );
647 if (isInteractive() && isAutoWarningHandlingEnabled())
648 {
649 static uint msgBoxDisplayed = 0;
650 if ( msgBoxDisplayed == 0 ) // don't bomb the user with message boxes, only one at a time
651 {
652 msgBoxDisplayed++;
653 KMessageBox::information( 0L, errorText );
654 msgBoxDisplayed--;
655 }
656 // otherwise just discard it.
657 }
658
659 if ( !guard.isNull() )
660 emit warning( this, errorText );
661}
662
663void SimpleJob::slotInfoMessage( const TQString & msg )
664{
665 emit infoMessage( this, msg );
666}
667
668void SimpleJob::slotConnected()
669{
670 emit connected( this );
671}
672
673void SimpleJob::slotNeedProgressId()
674{
675 if ( !m_progressId )
676 m_progressId = Observer::self()->newJob( this, false );
677 m_slave->setProgressId( m_progressId );
678}
679
680void SimpleJob::slotTotalSize( TDEIO::filesize_t size )
681{
682 if (size > m_totalSize)
683 {
684 m_totalSize = size;
685 emit totalSize( this, size );
686 }
687}
688
689void SimpleJob::slotProcessedSize( TDEIO::filesize_t size )
690{
691 //kdDebug(7007) << "SimpleJob::slotProcessedSize " << TDEIO::number(size) << endl;
692 setProcessedSize(size);
693 emit processedSize( this, size );
694 if ( size > m_totalSize ) {
695 slotTotalSize(size); // safety
696 }
697 emitPercent( size, m_totalSize );
698}
699
700void SimpleJob::slotSpeed( unsigned long speed )
701{
702 //kdDebug(7007) << "SimpleJob::slotSpeed( " << speed << " )" << endl;
703 emitSpeed( speed );
704}
705
706void SimpleJob::slotMetaData( const TDEIO::MetaData &_metaData)
707{
708 m_incomingMetaData += _metaData;
709}
710
711void SimpleJob::storeSSLSessionFromJob(const KURL &m_redirectionURL) {
712 TQString sslSession = queryMetaData("ssl_session_id");
713
714 if ( !sslSession.isNull() ) {
715 const KURL &queryURL = m_redirectionURL.isEmpty()?m_url:m_redirectionURL;
716 KSSLCSessionCache::putSessionForURL(queryURL, sslSession);
717 }
718}
719
721MkdirJob::MkdirJob( const KURL& url, int command,
722 const TQByteArray &packedArgs, bool showProgressInfo )
723 : SimpleJob(url, command, packedArgs, showProgressInfo)
724{
725}
726
727void MkdirJob::start(Slave *slave)
728{
729 connect( slave, TQ_SIGNAL( redirection(const KURL &) ),
730 TQ_SLOT( slotRedirection(const KURL &) ) );
731
732 SimpleJob::start(slave);
733}
734
735// Slave got a redirection request
736void MkdirJob::slotRedirection( const KURL &url)
737{
738 kdDebug(7007) << "MkdirJob::slotRedirection(" << url << ")" << endl;
739 if (!tdeApp->authorizeURLAction("redirect", m_url, url))
740 {
741 kdWarning(7007) << "MkdirJob: Redirection from " << m_url << " to " << url << " REJECTED!" << endl;
742 m_error = ERR_ACCESS_DENIED;
743 m_errorText = url.prettyURL();
744 return;
745 }
746 m_redirectionURL = url; // We'll remember that when the job finishes
747 if (m_url.hasUser() && !url.hasUser() && (m_url.host().lower() == url.host().lower()))
748 m_redirectionURL.setUser(m_url.user()); // Preserve user
749 // Tell the user that we haven't finished yet
750 emit redirection(this, m_redirectionURL);
751}
752
753void MkdirJob::slotFinished()
754{
755 if ( m_redirectionURL.isEmpty() || !m_redirectionURL.isValid())
756 {
757 // Return slave to the scheduler
758 SimpleJob::slotFinished();
759 } else {
760 //kdDebug(7007) << "MkdirJob: Redirection to " << m_redirectionURL << endl;
761 if (queryMetaData("permanent-redirect")=="true")
762 emit permanentRedirection(this, m_url, m_redirectionURL);
763 KURL dummyUrl;
764 int permissions;
765 TQDataStream istream( m_packedArgs, IO_ReadOnly );
766 istream >> dummyUrl >> permissions;
767
768 m_url = m_redirectionURL;
769 m_redirectionURL = KURL();
770 m_packedArgs.truncate(0);
771 TQDataStream stream( m_packedArgs, IO_WriteOnly );
772 stream << m_url << permissions;
773
774 // Return slave to the scheduler
775 slaveDone();
776 Scheduler::doJob(this);
777 }
778}
779
780SimpleJob *TDEIO::mkdir( const KURL& url, int permissions )
781{
782 //kdDebug(7007) << "mkdir " << url << endl;
783 TDEIO_ARGS << url << permissions;
784 return new MkdirJob(url, CMD_MKDIR, packedArgs, false);
785}
786
787SimpleJob *TDEIO::rmdir( const KURL& url )
788{
789 //kdDebug(7007) << "rmdir " << url << endl;
790 TDEIO_ARGS << url << TQ_INT8(false); // isFile is false
791 return new SimpleJob(url, CMD_DEL, packedArgs, false);
792}
793
794SimpleJob *TDEIO::chmod( const KURL& url, int permissions )
795{
796 //kdDebug(7007) << "chmod " << url << endl;
797 TDEIO_ARGS << url << permissions;
798 return new SimpleJob(url, CMD_CHMOD, packedArgs, false);
799}
800
801SimpleJob *TDEIO::rename( const KURL& src, const KURL & dest, bool overwrite )
802{
803 //kdDebug(7007) << "rename " << src << " " << dest << endl;
804 TDEIO_ARGS << src << dest << (TQ_INT8) overwrite;
805 return new SimpleJob(src, CMD_RENAME, packedArgs, false);
806}
807
808SimpleJob *TDEIO::symlink( const TQString& target, const KURL & dest, bool overwrite, bool showProgressInfo )
809{
810 //kdDebug(7007) << "symlink target=" << target << " " << dest << endl;
811 TDEIO_ARGS << target << dest << (TQ_INT8) overwrite;
812 return new SimpleJob(dest, CMD_SYMLINK, packedArgs, showProgressInfo);
813}
814
815SimpleJob *TDEIO::special(const KURL& url, const TQByteArray & data, bool showProgressInfo)
816{
817 //kdDebug(7007) << "special " << url << endl;
818 return new SimpleJob(url, CMD_SPECIAL, data, showProgressInfo);
819}
820
821SimpleJob *TDEIO::mount( bool ro, const char *fstype, const TQString& dev, const TQString& point, bool showProgressInfo )
822{
823 TDEIO_ARGS << int(1) << TQ_INT8( ro ? 1 : 0 )
824 << TQString::fromLatin1(fstype) << dev << point;
825 SimpleJob *job = special( KURL("file:/"), packedArgs, showProgressInfo );
826 if ( showProgressInfo )
827 Observer::self()->mounting( job, dev, point );
828 return job;
829}
830
831SimpleJob *TDEIO::unmount( const TQString& point, bool showProgressInfo )
832{
833 TDEIO_ARGS << int(2) << point;
834 SimpleJob *job = special( KURL("file:/"), packedArgs, showProgressInfo );
835 if ( showProgressInfo )
836 Observer::self()->unmounting( job, point );
837 return job;
838}
839
841LocalURLJob::LocalURLJob( const KURL& url, int command,
842 const TQByteArray &packedArgs, bool showProgressInfo )
843 : SimpleJob(url, command, packedArgs, showProgressInfo)
844{
845
846}
847
848void LocalURLJob::start(Slave *slave)
849{
850 connect( slave, TQ_SIGNAL( localURL(const KURL &, bool) ),
851 TQ_SLOT( slotLocalURL(const KURL &, bool) ) );
852
853 SimpleJob::start(slave);
854}
855
856// Slave sent a response!
857void LocalURLJob::slotLocalURL(const KURL &url, bool isLocal)
858{
859 kdDebug(7007) << "LocalURLJob::slotLocalURL(" << url << ")" << endl;
860 emit localURL(this, url, isLocal);
861 deleteLater();
862}
863
864void LocalURLJob::slotFinished()
865{
866 // Return slave to the scheduler
867 SimpleJob::slotFinished();
868}
869
870LocalURLJob *TDEIO::localURL( const KURL& remoteUrl )
871{
872 TDEIO_ARGS << remoteUrl;
873 return new LocalURLJob(remoteUrl, CMD_LOCALURL, packedArgs, false);
874}
875
876
878
879StatJob::StatJob( const KURL& url, int command,
880 const TQByteArray &packedArgs, bool showProgressInfo )
881 : SimpleJob(url, command, packedArgs, showProgressInfo),
882 m_bSource(true), m_details(2)
883{
884}
885
886void StatJob::start(Slave *slave)
887{
888 m_outgoingMetaData.replace( "statSide", m_bSource ? "source" : "dest" );
889 m_outgoingMetaData.replace( "details", TQString::number(m_details) );
890
891 connect( slave, TQ_SIGNAL( statEntry( const TDEIO::UDSEntry& ) ),
892 TQ_SLOT( slotStatEntry( const TDEIO::UDSEntry & ) ) );
893 connect( slave, TQ_SIGNAL( redirection(const KURL &) ),
894 TQ_SLOT( slotRedirection(const KURL &) ) );
895
896 SimpleJob::start(slave);
897}
898
899void StatJob::slotStatEntry( const TDEIO::UDSEntry & entry )
900{
901 //kdDebug(7007) << "StatJob::slotStatEntry" << endl;
902 m_statResult = entry;
903}
904
905// Slave got a redirection request
906void StatJob::slotRedirection( const KURL &url)
907{
908 kdDebug(7007) << "StatJob::slotRedirection(" << url << ")" << endl;
909 if (!tdeApp->authorizeURLAction("redirect", m_url, url))
910 {
911 kdWarning(7007) << "StatJob: Redirection from " << m_url << " to " << url << " REJECTED!" << endl;
912 m_error = ERR_ACCESS_DENIED;
913 m_errorText = url.prettyURL();
914 return;
915 }
916 m_redirectionURL = url; // We'll remember that when the job finishes
917 if (m_url.hasUser() && !url.hasUser() && (m_url.host().lower() == url.host().lower()))
918 m_redirectionURL.setUser(m_url.user()); // Preserve user
919 // Tell the user that we haven't finished yet
920 emit redirection(this, m_redirectionURL);
921}
922
923void StatJob::slotFinished()
924{
925 if ( m_redirectionURL.isEmpty() || !m_redirectionURL.isValid())
926 {
927 // Return slave to the scheduler
928 SimpleJob::slotFinished();
929 } else {
930 //kdDebug(7007) << "StatJob: Redirection to " << m_redirectionURL << endl;
931 if (queryMetaData("permanent-redirect")=="true")
932 emit permanentRedirection(this, m_url, m_redirectionURL);
933 m_url = m_redirectionURL;
934 m_redirectionURL = KURL();
935 m_packedArgs.truncate(0);
936 TQDataStream stream( m_packedArgs, IO_WriteOnly );
937 stream << m_url;
938
939 // Return slave to the scheduler
940 slaveDone();
941 Scheduler::doJob(this);
942 }
943}
944
945void StatJob::slotMetaData( const TDEIO::MetaData &_metaData) {
946 SimpleJob::slotMetaData(_metaData);
947 storeSSLSessionFromJob(m_redirectionURL);
948}
949
950StatJob *TDEIO::stat(const KURL& url, bool showProgressInfo)
951{
952 // Assume sideIsSource. Gets are more common than puts.
953 return stat( url, true, 2, showProgressInfo );
954}
955
956StatJob *TDEIO::stat(const KURL& url, bool sideIsSource, short int details, bool showProgressInfo)
957{
958 kdDebug(7007) << "stat " << url << endl;
959 TDEIO_ARGS << url;
960 StatJob * job = new StatJob(url, CMD_STAT, packedArgs, showProgressInfo );
961 job->setSide( sideIsSource );
962 job->setDetails( details );
963 if ( showProgressInfo )
964 Observer::self()->stating( job, url );
965 return job;
966}
967
968SimpleJob *TDEIO::http_update_cache( const KURL& url, bool no_cache, time_t expireDate)
969{
970 assert( (url.protocol() == "http") || (url.protocol() == "https") );
971 // Send http update_cache command (2)
972 TDEIO_ARGS << (int)2 << url << no_cache << expireDate;
973 SimpleJob * job = new SimpleJob( url, CMD_SPECIAL, packedArgs, false );
974 Scheduler::scheduleJob(job);
975 return job;
976}
977
979
980TransferJob::TransferJob( const KURL& url, int command,
981 const TQByteArray &packedArgs,
982 const TQByteArray &_staticData,
983 bool showProgressInfo)
984 : SimpleJob(url, command, packedArgs, showProgressInfo), staticData( _staticData)
985{
986 m_suspended = false;
987 m_errorPage = false;
988 m_subJob = 0L;
989 if ( showProgressInfo )
990 Observer::self()->slotTransferring( this, url );
991}
992
993// Slave sends data
994void TransferJob::slotData( const TQByteArray &_data)
995{
996 if(m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error)
997 emit data( this, _data);
998}
999
1000// Slave got a redirection request
1001void TransferJob::slotRedirection( const KURL &url)
1002{
1003 kdDebug(7007) << "TransferJob::slotRedirection(" << url << ")" << endl;
1004 if (!tdeApp->authorizeURLAction("redirect", m_url, url))
1005 {
1006 kdWarning(7007) << "TransferJob: Redirection from " << m_url << " to " << url << " REJECTED!" << endl;
1007 return;
1008 }
1009
1010 // Some websites keep redirecting to themselves where each redirection
1011 // acts as the stage in a state-machine. We define "endless redirections"
1012 // as 5 redirections to the same URL.
1013 if (m_redirectionList.contains(url) > 5)
1014 {
1015 kdDebug(7007) << "TransferJob::slotRedirection: CYCLIC REDIRECTION!" << endl;
1016 m_error = ERR_CYCLIC_LINK;
1017 m_errorText = m_url.prettyURL();
1018 }
1019 else
1020 {
1021 m_redirectionURL = url; // We'll remember that when the job finishes
1022 if (m_url.hasUser() && !url.hasUser() && (m_url.host().lower() == url.host().lower()))
1023 m_redirectionURL.setUser(m_url.user()); // Preserve user
1024 m_redirectionList.append(url);
1025 m_outgoingMetaData["ssl_was_in_use"] = m_incomingMetaData["ssl_in_use"];
1026 // Tell the user that we haven't finished yet
1027 emit redirection(this, m_redirectionURL);
1028 }
1029}
1030
1031void TransferJob::slotFinished()
1032{
1033 //kdDebug(7007) << "TransferJob::slotFinished(" << this << ", " << m_url << ")" << endl;
1034 if (m_redirectionURL.isEmpty() || !m_redirectionURL.isValid())
1035 SimpleJob::slotFinished();
1036 else {
1037 //kdDebug(7007) << "TransferJob: Redirection to " << m_redirectionURL << endl;
1038 if (queryMetaData("permanent-redirect")=="true")
1039 emit permanentRedirection(this, m_url, m_redirectionURL);
1040 // Honour the redirection
1041 // We take the approach of "redirecting this same job"
1042 // Another solution would be to create a subjob, but the same problem
1043 // happens (unpacking+repacking)
1044 staticData.truncate(0);
1045 m_incomingMetaData.clear();
1046 if (queryMetaData("cache") != "reload")
1047 addMetaData("cache","refresh");
1048 m_suspended = false;
1049 m_url = m_redirectionURL;
1050 m_redirectionURL = KURL();
1051 // The very tricky part is the packed arguments business
1052 TQString dummyStr;
1053 KURL dummyUrl;
1054 TQDataStream istream( m_packedArgs, IO_ReadOnly );
1055 switch( m_command ) {
1056 case CMD_GET: {
1057 m_packedArgs.truncate(0);
1058 TQDataStream stream( m_packedArgs, IO_WriteOnly );
1059 stream << m_url;
1060 break;
1061 }
1062 case CMD_PUT: {
1063 int permissions;
1064 TQ_INT8 iOverwrite, iResume;
1065 istream >> dummyUrl >> iOverwrite >> iResume >> permissions;
1066 m_packedArgs.truncate(0);
1067 TQDataStream stream( m_packedArgs, IO_WriteOnly );
1068 stream << m_url << iOverwrite << iResume << permissions;
1069 break;
1070 }
1071 case CMD_SPECIAL: {
1072 int specialcmd;
1073 istream >> specialcmd;
1074 if (specialcmd == 1) // HTTP POST
1075 {
1076 addMetaData("cache","reload");
1077 m_packedArgs.truncate(0);
1078 TQDataStream stream( m_packedArgs, IO_WriteOnly );
1079 stream << m_url;
1080 m_command = CMD_GET;
1081 }
1082 break;
1083 }
1084 }
1085
1086 // Return slave to the scheduler
1087 slaveDone();
1088 Scheduler::doJob(this);
1089 }
1090}
1091
1092void TransferJob::setAsyncDataEnabled(bool enabled)
1093{
1094 if (enabled)
1095 extraFlags() |= EF_TransferJobAsync;
1096 else
1097 extraFlags() &= ~EF_TransferJobAsync;
1098}
1099
1100void TransferJob::sendAsyncData(const TQByteArray &dataForSlave)
1101{
1102 if (extraFlags() & EF_TransferJobNeedData)
1103 {
1104 m_slave->send( MSG_DATA, dataForSlave );
1105 if (extraFlags() & EF_TransferJobDataSent)
1106 {
1107 TDEIO::filesize_t size = getProcessedSize()+dataForSlave.size();
1108 setProcessedSize(size);
1109 emit processedSize( this, size );
1110 if ( size > m_totalSize ) {
1111 slotTotalSize(size); // safety
1112 }
1113 emitPercent( size, m_totalSize );
1114 }
1115 }
1116
1117 extraFlags() &= ~EF_TransferJobNeedData;
1118}
1119
1120void TransferJob::setReportDataSent(bool enabled)
1121{
1122 if (enabled)
1123 extraFlags() |= EF_TransferJobDataSent;
1124 else
1125 extraFlags() &= ~EF_TransferJobDataSent;
1126}
1127
1128bool TransferJob::reportDataSent()
1129{
1130 return (extraFlags() & EF_TransferJobDataSent);
1131}
1132
1133
1134// Slave requests data
1135void TransferJob::slotDataReq()
1136{
1137 TQByteArray dataForSlave;
1138
1139 extraFlags() |= EF_TransferJobNeedData;
1140
1141 if (!staticData.isEmpty())
1142 {
1143 dataForSlave = staticData;
1144 staticData = TQByteArray();
1145 }
1146 else
1147 {
1148 emit dataReq( this, dataForSlave);
1149
1150 if (extraFlags() & EF_TransferJobAsync)
1151 return;
1152 }
1153
1154 static const size_t max_size = 14 * 1024 * 1024;
1155 if (dataForSlave.size() > max_size)
1156 {
1157 kdDebug(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";
1158 staticData.duplicate(dataForSlave.data() + max_size , dataForSlave.size() - max_size);
1159 dataForSlave.truncate(max_size);
1160 }
1161
1162 sendAsyncData(dataForSlave);
1163
1164 if (m_subJob)
1165 {
1166 // Bitburger protocol in action
1167 suspend(); // Wait for more data from subJob.
1168 m_subJob->resume(); // Ask for more!
1169 }
1170}
1171
1172void TransferJob::slotMimetype( const TQString& type )
1173{
1174 m_mimetype = type;
1175 emit mimetype( this, m_mimetype);
1176}
1177
1178
1179void TransferJob::suspend()
1180{
1181 m_suspended = true;
1182 if (m_slave)
1183 m_slave->suspend();
1184}
1185
1186void TransferJob::resume()
1187{
1188 m_suspended = false;
1189 if (m_slave)
1190 m_slave->resume();
1191}
1192
1193void TransferJob::start(Slave *slave)
1194{
1195 assert(slave);
1196 connect( slave, TQ_SIGNAL( data( const TQByteArray & ) ),
1197 TQ_SLOT( slotData( const TQByteArray & ) ) );
1198
1199 connect( slave, TQ_SIGNAL( dataReq() ),
1200 TQ_SLOT( slotDataReq() ) );
1201
1202 connect( slave, TQ_SIGNAL( redirection(const KURL &) ),
1203 TQ_SLOT( slotRedirection(const KURL &) ) );
1204
1205 connect( slave, TQ_SIGNAL(mimeType( const TQString& ) ),
1206 TQ_SLOT( slotMimetype( const TQString& ) ) );
1207
1208 connect( slave, TQ_SIGNAL(errorPage() ),
1209 TQ_SLOT( slotErrorPage() ) );
1210
1211 connect( slave, TQ_SIGNAL( needSubURLData() ),
1212 TQ_SLOT( slotNeedSubURLData() ) );
1213
1214 connect( slave, TQ_SIGNAL(canResume( TDEIO::filesize_t ) ),
1215 TQ_SLOT( slotCanResume( TDEIO::filesize_t ) ) );
1216
1217 if (slave->suspended())
1218 {
1219 m_mimetype = "unknown";
1220 // WABA: The slave was put on hold. Resume operation.
1221 slave->resume();
1222 }
1223
1224 SimpleJob::start(slave);
1225 if (m_suspended)
1226 slave->suspend();
1227}
1228
1229void TransferJob::slotNeedSubURLData()
1230{
1231 // Job needs data from subURL.
1232 m_subJob = TDEIO::get( m_subUrl, false, false);
1233 suspend(); // Put job on hold until we have some data.
1234 connect(m_subJob, TQ_SIGNAL( data(TDEIO::Job*,const TQByteArray &)),
1235 TQ_SLOT( slotSubURLData(TDEIO::Job*,const TQByteArray &)));
1236 addSubjob(m_subJob);
1237}
1238
1239void TransferJob::slotSubURLData(TDEIO::Job*, const TQByteArray &data)
1240{
1241 // The Alternating Bitburg protocol in action again.
1242 staticData = data;
1243 m_subJob->suspend(); // Put job on hold until we have delivered the data.
1244 resume(); // Activate ourselves again.
1245}
1246
1247void TransferJob::slotMetaData( const TDEIO::MetaData &_metaData) {
1248 SimpleJob::slotMetaData(_metaData);
1249 storeSSLSessionFromJob(m_redirectionURL);
1250}
1251
1252void TransferJob::slotErrorPage()
1253{
1254 m_errorPage = true;
1255}
1256
1257void TransferJob::slotCanResume( TDEIO::filesize_t offset )
1258{
1259 emit canResume(this, offset);
1260}
1261
1262void TransferJob::slotResult( TDEIO::Job *job)
1263{
1264 // This can only be our suburl.
1265 assert(job == m_subJob);
1266 // Did job have an error ?
1267 if ( job->error() )
1268 {
1269 m_error = job->error();
1270 m_errorText = job->errorText();
1271
1272 emitResult();
1273 return;
1274 }
1275
1276 if (job == m_subJob)
1277 {
1278 m_subJob = 0; // No action required
1279 resume(); // Make sure we get the remaining data.
1280 }
1281 removeSubjob( job, false, false ); // Remove job, but don't kill this job.
1282}
1283
1284TransferJob *TDEIO::get( const KURL& url, bool reload, bool showProgressInfo )
1285{
1286 // Send decoded path and encoded query
1287 TDEIO_ARGS << url;
1288 TransferJob * job = new TransferJob( url, CMD_GET, packedArgs, TQByteArray(), showProgressInfo );
1289 if (reload)
1290 job->addMetaData("cache", "reload");
1291 return job;
1292}
1293
1294class PostErrorJob : public TransferJob
1295{
1296public:
1297
1298 PostErrorJob(int _error, const TQString& url, const TQByteArray &packedArgs, const TQByteArray &postData, bool showProgressInfo)
1299 : TransferJob(KURL(), CMD_SPECIAL, packedArgs, postData, showProgressInfo)
1300 {
1301 m_error = _error;
1302 m_errorText = url;
1303 }
1304
1305};
1306
1307TransferJob *TDEIO::http_post( const KURL& url, const TQByteArray &postData, bool showProgressInfo )
1308{
1309 int _error = 0;
1310
1311 // filter out some malicious ports
1312 static const int bad_ports[] = {
1313 1, // tcpmux
1314 7, // echo
1315 9, // discard
1316 11, // systat
1317 13, // daytime
1318 15, // netstat
1319 17, // qotd
1320 19, // chargen
1321 20, // ftp-data
1322 21, // ftp-cntl
1323 22, // ssh
1324 23, // telnet
1325 25, // smtp
1326 37, // time
1327 42, // name
1328 43, // nicname
1329 53, // domain
1330 77, // priv-rjs
1331 79, // finger
1332 87, // ttylink
1333 95, // supdup
1334 101, // hostriame
1335 102, // iso-tsap
1336 103, // gppitnp
1337 104, // acr-nema
1338 109, // pop2
1339 110, // pop3
1340 111, // sunrpc
1341 113, // auth
1342 115, // sftp
1343 117, // uucp-path
1344 119, // nntp
1345 123, // NTP
1346 135, // loc-srv / epmap
1347 139, // netbios
1348 143, // imap2
1349 179, // BGP
1350 389, // ldap
1351 512, // print / exec
1352 513, // login
1353 514, // shell
1354 515, // printer
1355 526, // tempo
1356 530, // courier
1357 531, // Chat
1358 532, // netnews
1359 540, // uucp
1360 556, // remotefs
1361 587, // sendmail
1362 601, //
1363 989, // ftps data
1364 990, // ftps
1365 992, // telnets
1366 993, // imap/SSL
1367 995, // pop3/SSL
1368 1080, // SOCKS
1369 2049, // nfs
1370 4045, // lockd
1371 6000, // x11
1372 6667, // irc
1373 0};
1374 for (int cnt=0; bad_ports[cnt]; ++cnt)
1375 if (url.port() == bad_ports[cnt])
1376 {
1377 _error = TDEIO::ERR_POST_DENIED;
1378 break;
1379 }
1380
1381 if( _error )
1382 {
1383 static bool override_loaded = false;
1384 static TQValueList< int >* overriden_ports = NULL;
1385 if( !override_loaded )
1386 {
1387 TDEConfig cfg( "tdeio_httprc", true );
1388 overriden_ports = new TQValueList< int >;
1389 *overriden_ports = cfg.readIntListEntry( "OverriddenPorts" );
1390 override_loaded = true;
1391 }
1392 for( TQValueList< int >::ConstIterator it = overriden_ports->begin();
1393 it != overriden_ports->end();
1394 ++it )
1395 if( overriden_ports->contains( url.port()))
1396 _error = 0;
1397 }
1398
1399 // filter out non https? protocols
1400 if ((url.protocol() != "http") && (url.protocol() != "https" ))
1401 _error = TDEIO::ERR_POST_DENIED;
1402
1403 bool redirection = false;
1404 KURL _url(url);
1405 if (_url.path().isEmpty())
1406 {
1407 redirection = true;
1408 _url.setPath("/");
1409 }
1410
1411 if (!_error && !tdeApp->authorizeURLAction("open", KURL(), _url))
1412 _error = TDEIO::ERR_ACCESS_DENIED;
1413
1414 // if request is not valid, return an invalid transfer job
1415 if (_error)
1416 {
1417 TDEIO_ARGS << (int)1 << url;
1418 TransferJob * job = new PostErrorJob(_error, url.prettyURL(), packedArgs, postData, showProgressInfo);
1419 return job;
1420 }
1421
1422 // Send http post command (1), decoded path and encoded query
1423 TDEIO_ARGS << (int)1 << _url;
1424 TransferJob * job = new TransferJob( _url, CMD_SPECIAL,
1425 packedArgs, postData, showProgressInfo );
1426
1427 if (redirection)
1428 TQTimer::singleShot(0, job, TQ_SLOT(slotPostRedirection()) );
1429
1430 return job;
1431}
1432
1433// http post got redirected from http://host to http://host/ by TransferJob
1434// We must do this redirection ourselves because redirections by the
1435// slave change post jobs into get jobs.
1436void TransferJob::slotPostRedirection()
1437{
1438 kdDebug(7007) << "TransferJob::slotPostRedirection(" << m_url << ")" << endl;
1439 // Tell the user about the new url.
1440 emit redirection(this, m_url);
1441}
1442
1443
1444TransferJob *TDEIO::put( const KURL& url, int permissions,
1445 bool overwrite, bool resume, bool showProgressInfo )
1446{
1447 TDEIO_ARGS << url << TQ_INT8( overwrite ? 1 : 0 ) << TQ_INT8( resume ? 1 : 0 ) << permissions;
1448 TransferJob * job = new TransferJob( url, CMD_PUT, packedArgs, TQByteArray(), showProgressInfo );
1449 return job;
1450}
1451
1453
1454StoredTransferJob::StoredTransferJob(const KURL& url, int command,
1455 const TQByteArray &packedArgs,
1456 const TQByteArray &_staticData,
1457 bool showProgressInfo)
1458 : TransferJob( url, command, packedArgs, _staticData, showProgressInfo ),
1459 m_uploadOffset( 0 )
1460{
1461 connect( this, TQ_SIGNAL( data( TDEIO::Job *, const TQByteArray & ) ),
1462 TQ_SLOT( slotStoredData( TDEIO::Job *, const TQByteArray & ) ) );
1463 connect( this, TQ_SIGNAL( dataReq( TDEIO::Job *, TQByteArray & ) ),
1464 TQ_SLOT( slotStoredDataReq( TDEIO::Job *, TQByteArray & ) ) );
1465}
1466
1467void StoredTransferJob::setData( const TQByteArray& arr )
1468{
1469 Q_ASSERT( m_data.isNull() ); // check that we're only called once
1470 Q_ASSERT( m_uploadOffset == 0 ); // no upload started yet
1471 m_data = arr;
1472}
1473
1474void StoredTransferJob::slotStoredData( TDEIO::Job *, const TQByteArray &data )
1475{
1476 // check for end-of-data marker:
1477 if ( data.size() == 0 )
1478 return;
1479 unsigned int oldSize = m_data.size();
1480 m_data.resize( oldSize + data.size(), TQGArray::SpeedOptim );
1481 memcpy( m_data.data() + oldSize, data.data(), data.size() );
1482}
1483
1484void StoredTransferJob::slotStoredDataReq( TDEIO::Job *, TQByteArray &data )
1485{
1486 // Inspired from kmail's KMKernel::byteArrayToRemoteFile
1487 // send the data in 64 KB chunks
1488 const int MAX_CHUNK_SIZE = 64*1024;
1489 int remainingBytes = m_data.size() - m_uploadOffset;
1490 if( remainingBytes > MAX_CHUNK_SIZE ) {
1491 // send MAX_CHUNK_SIZE bytes to the receiver (deep copy)
1492 data.duplicate( m_data.data() + m_uploadOffset, MAX_CHUNK_SIZE );
1493 m_uploadOffset += MAX_CHUNK_SIZE;
1494 //kdDebug() << "Sending " << MAX_CHUNK_SIZE << " bytes ("
1495 // << remainingBytes - MAX_CHUNK_SIZE << " bytes remain)\n";
1496 } else {
1497 // send the remaining bytes to the receiver (deep copy)
1498 data.duplicate( m_data.data() + m_uploadOffset, remainingBytes );
1499 m_data = TQByteArray();
1500 m_uploadOffset = 0;
1501 //kdDebug() << "Sending " << remainingBytes << " bytes\n";
1502 }
1503}
1504
1505StoredTransferJob *TDEIO::storedGet( const KURL& url, bool reload, bool showProgressInfo )
1506{
1507 // Send decoded path and encoded query
1508 TDEIO_ARGS << url;
1509 StoredTransferJob * job = new StoredTransferJob( url, CMD_GET, packedArgs, TQByteArray(), showProgressInfo );
1510 if (reload)
1511 job->addMetaData("cache", "reload");
1512 return job;
1513}
1514
1515StoredTransferJob *TDEIO::storedPut( const TQByteArray& arr, const KURL& url, int permissions,
1516 bool overwrite, bool resume, bool showProgressInfo )
1517{
1518 TDEIO_ARGS << url << TQ_INT8( overwrite ? 1 : 0 ) << TQ_INT8( resume ? 1 : 0 ) << permissions;
1519 StoredTransferJob * job = new StoredTransferJob( url, CMD_PUT, packedArgs, TQByteArray(), showProgressInfo );
1520 job->setData( arr );
1521 return job;
1522}
1523
1525
1526MimetypeJob::MimetypeJob( const KURL& url, int command,
1527 const TQByteArray &packedArgs, bool showProgressInfo )
1528 : TransferJob(url, command, packedArgs, TQByteArray(), showProgressInfo)
1529{
1530}
1531
1532void MimetypeJob::start(Slave *slave)
1533{
1534 TransferJob::start(slave);
1535}
1536
1537
1538void MimetypeJob::slotFinished( )
1539{
1540 //kdDebug(7007) << "MimetypeJob::slotFinished()" << endl;
1541 if ( m_error == TDEIO::ERR_IS_DIRECTORY )
1542 {
1543 // It is in fact a directory. This happens when HTTP redirects to FTP.
1544 // Due to the "protocol doesn't support listing" code in KRun, we
1545 // assumed it was a file.
1546 kdDebug(7007) << "It is in fact a directory!" << endl;
1547 m_mimetype = TQString::fromLatin1("inode/directory");
1548 emit TransferJob::mimetype( this, m_mimetype );
1549 m_error = 0;
1550 }
1551 if ( m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error )
1552 {
1553 // Return slave to the scheduler
1554 TransferJob::slotFinished();
1555 } else {
1556 //kdDebug(7007) << "MimetypeJob: Redirection to " << m_redirectionURL << endl;
1557 if (queryMetaData("permanent-redirect")=="true")
1558 emit permanentRedirection(this, m_url, m_redirectionURL);
1559 staticData.truncate(0);
1560 m_suspended = false;
1561 m_url = m_redirectionURL;
1562 m_redirectionURL = KURL();
1563 m_packedArgs.truncate(0);
1564 TQDataStream stream( m_packedArgs, IO_WriteOnly );
1565 stream << m_url;
1566
1567 // Return slave to the scheduler
1568 slaveDone();
1569 Scheduler::doJob(this);
1570 }
1571}
1572
1573MimetypeJob *TDEIO::mimetype(const KURL& url, bool showProgressInfo )
1574{
1575 TDEIO_ARGS << url;
1576 MimetypeJob * job = new MimetypeJob(url, CMD_MIMETYPE, packedArgs, showProgressInfo);
1577 if ( showProgressInfo )
1578 Observer::self()->stating( job, url );
1579 return job;
1580}
1581
1583
1584DirectCopyJob::DirectCopyJob( const KURL& url, int command,
1585 const TQByteArray &packedArgs, bool showProgressInfo )
1586 : SimpleJob(url, command, packedArgs, showProgressInfo)
1587{
1588}
1589
1590void DirectCopyJob::start( Slave* slave )
1591{
1592 connect( slave, TQ_SIGNAL(canResume( TDEIO::filesize_t ) ),
1593 TQ_SLOT( slotCanResume( TDEIO::filesize_t ) ) );
1594 SimpleJob::start(slave);
1595}
1596
1597void DirectCopyJob::slotCanResume( TDEIO::filesize_t offset )
1598{
1599 emit canResume(this, offset);
1600}
1601
1603
1604
1605class FileCopyJob::FileCopyJobPrivate
1606{
1607public:
1608 TDEIO::filesize_t m_sourceSize;
1609 time_t m_modificationTime;
1610 SimpleJob *m_delJob;
1611};
1612
1613/*
1614 * The FileCopyJob works according to the famous Bayern
1615 * 'Alternating Bitburger Protocol': we either drink a beer or we
1616 * we order a beer, but never both at the same time.
1617 * Tranlated to io-slaves: We alternate between receiving a block of data
1618 * and sending it away.
1619 */
1620FileCopyJob::FileCopyJob( const KURL& src, const KURL& dest, int permissions,
1621 bool move, bool overwrite, bool resume, bool showProgressInfo)
1622 : Job(showProgressInfo), m_src(src), m_dest(dest),
1623 m_permissions(permissions), m_move(move), m_overwrite(overwrite), m_resume(resume),
1624 m_totalSize(0)
1625{
1626 if (showProgressInfo && !move)
1627 Observer::self()->slotCopying( this, src, dest );
1628 else if (showProgressInfo && move)
1629 Observer::self()->slotMoving( this, src, dest );
1630
1631 //kdDebug(7007) << "FileCopyJob::FileCopyJob()" << endl;
1632 m_moveJob = 0;
1633 m_copyJob = 0;
1634 m_getJob = 0;
1635 m_putJob = 0;
1636 d = new FileCopyJobPrivate;
1637 d->m_delJob = 0;
1638 d->m_sourceSize = (TDEIO::filesize_t) -1;
1639 d->m_modificationTime = static_cast<time_t>( -1 );
1640 TQTimer::singleShot(0, this, TQ_SLOT(slotStart()));
1641}
1642
1643void FileCopyJob::slotStart()
1644{
1645 if ( m_move )
1646 {
1647 // The if() below must be the same as the one in startBestCopyMethod
1648 if ((m_src.protocol() == m_dest.protocol()) &&
1649 (m_src.host() == m_dest.host()) &&
1650 (m_src.port() == m_dest.port()) &&
1651 (m_src.user() == m_dest.user()) &&
1652 (m_src.pass() == m_dest.pass()) &&
1653 !m_src.hasSubURL() && !m_dest.hasSubURL())
1654 {
1655 startRenameJob(m_src);
1656 return;
1657 }
1658 else if (m_src.isLocalFile() && KProtocolInfo::canRenameFromFile(m_dest))
1659 {
1660 startRenameJob(m_dest);
1661 return;
1662 }
1663 else if (m_dest.isLocalFile() && KProtocolInfo::canRenameToFile(m_src))
1664 {
1665 startRenameJob(m_src);
1666 return;
1667 }
1668 // No fast-move available, use copy + del.
1669 }
1670 startBestCopyMethod();
1671}
1672
1673void FileCopyJob::startBestCopyMethod()
1674{
1675 if ((m_src.protocol() == m_dest.protocol()) &&
1676 (m_src.host() == m_dest.host()) &&
1677 (m_src.port() == m_dest.port()) &&
1678 (m_src.user() == m_dest.user()) &&
1679 (m_src.pass() == m_dest.pass()) &&
1680 !m_src.hasSubURL() && !m_dest.hasSubURL())
1681 {
1682 startCopyJob();
1683 }
1684 else if (m_src.isLocalFile() && KProtocolInfo::canCopyFromFile(m_dest))
1685 {
1686 startCopyJob(m_dest);
1687 }
1688 else if (m_dest.isLocalFile() && KProtocolInfo::canCopyToFile(m_src))
1689 {
1690 startCopyJob(m_src);
1691 }
1692 else
1693 {
1694 startDataPump();
1695 }
1696}
1697
1698FileCopyJob::~FileCopyJob()
1699{
1700 delete d;
1701}
1702
1703void FileCopyJob::setSourceSize( off_t size )
1704{
1705 d->m_sourceSize = size;
1706 if (size != (off_t) -1)
1707 m_totalSize = size;
1708}
1709
1710void FileCopyJob::setSourceSize64( TDEIO::filesize_t size )
1711{
1712 d->m_sourceSize = size;
1713 if (size != (TDEIO::filesize_t) -1)
1714 m_totalSize = size;
1715}
1716
1717void FileCopyJob::setModificationTime( time_t mtime )
1718{
1719 d->m_modificationTime = mtime;
1720}
1721
1722void FileCopyJob::startCopyJob()
1723{
1724 startCopyJob(m_src);
1725}
1726
1727void FileCopyJob::startCopyJob(const KURL &slave_url)
1728{
1729 //kdDebug(7007) << "FileCopyJob::startCopyJob()" << endl;
1730 TDEIO_ARGS << m_src << m_dest << m_permissions << (TQ_INT8) m_overwrite;
1731 m_copyJob = new DirectCopyJob(slave_url, CMD_COPY, packedArgs, false);
1732 addSubjob( m_copyJob );
1733 connectSubjob( m_copyJob );
1734 connect( m_copyJob, TQ_SIGNAL(canResume(TDEIO::Job *, TDEIO::filesize_t)),
1735 TQ_SLOT( slotCanResume(TDEIO::Job *, TDEIO::filesize_t)));
1736}
1737
1738void FileCopyJob::startRenameJob(const KURL &slave_url)
1739{
1740 TDEIO_ARGS << m_src << m_dest << (TQ_INT8) m_overwrite;
1741 m_moveJob = new SimpleJob(slave_url, CMD_RENAME, packedArgs, false);
1742 addSubjob( m_moveJob );
1743 connectSubjob( m_moveJob );
1744}
1745
1746void FileCopyJob::connectSubjob( SimpleJob * job )
1747{
1748 connect( job, TQ_SIGNAL(totalSize( TDEIO::Job*, TDEIO::filesize_t )),
1749 this, TQ_SLOT( slotTotalSize(TDEIO::Job*, TDEIO::filesize_t)) );
1750
1751 connect( job, TQ_SIGNAL(processedSize( TDEIO::Job*, TDEIO::filesize_t )),
1752 this, TQ_SLOT( slotProcessedSize(TDEIO::Job*, TDEIO::filesize_t)) );
1753
1754 connect( job, TQ_SIGNAL(percent( TDEIO::Job*, unsigned long )),
1755 this, TQ_SLOT( slotPercent(TDEIO::Job*, unsigned long)) );
1756
1757}
1758
1759void FileCopyJob::slotProcessedSize( TDEIO::Job *, TDEIO::filesize_t size )
1760{
1761 setProcessedSize(size);
1762 emit processedSize( this, size );
1763 if ( size > m_totalSize ) {
1764 slotTotalSize( this, size ); // safety
1765 }
1766 emitPercent( size, m_totalSize );
1767}
1768
1769void FileCopyJob::slotTotalSize( TDEIO::Job*, TDEIO::filesize_t size )
1770{
1771 if (size > m_totalSize)
1772 {
1773 m_totalSize = size;
1774 emit totalSize( this, m_totalSize );
1775 }
1776}
1777
1778void FileCopyJob::slotPercent( TDEIO::Job*, unsigned long pct )
1779{
1780 if ( pct > m_percent )
1781 {
1782 m_percent = pct;
1783 emit percent( this, m_percent );
1784 }
1785}
1786
1787void FileCopyJob::startDataPump()
1788{
1789 //kdDebug(7007) << "FileCopyJob::startDataPump()" << endl;
1790
1791 m_canResume = false;
1792 m_resumeAnswerSent = false;
1793 m_getJob = 0L; // for now
1794 m_putJob = put( m_dest, m_permissions, m_overwrite, m_resume, false /* no GUI */);
1795 if ( d->m_modificationTime != static_cast<time_t>( -1 ) ) {
1796 TQDateTime dt; dt.setTime_t( d->m_modificationTime );
1797 m_putJob->addMetaData( "modified", dt.toString( TQt::ISODate ) );
1798 }
1799 //kdDebug(7007) << "FileCopyJob: m_putJob = " << m_putJob << " m_dest=" << m_dest << endl;
1800
1801 // The first thing the put job will tell us is whether we can
1802 // resume or not (this is always emitted)
1803 connect( m_putJob, TQ_SIGNAL(canResume(TDEIO::Job *, TDEIO::filesize_t)),
1804 TQ_SLOT( slotCanResume(TDEIO::Job *, TDEIO::filesize_t)));
1805 connect( m_putJob, TQ_SIGNAL(dataReq(TDEIO::Job *, TQByteArray&)),
1806 TQ_SLOT( slotDataReq(TDEIO::Job *, TQByteArray&)));
1807 addSubjob( m_putJob );
1808}
1809
1810void FileCopyJob::slotCanResume( TDEIO::Job* job, TDEIO::filesize_t offset )
1811{
1812 if ( job == m_putJob || job == m_copyJob )
1813 {
1814 //kdDebug(7007) << "FileCopyJob::slotCanResume from PUT job. offset=" << TDEIO::number(offset) << endl;
1815 if (offset)
1816 {
1817 RenameDlg_Result res = R_RESUME;
1818
1819 if (!KProtocolManager::autoResume() && !m_overwrite)
1820 {
1821 TQString newPath;
1822 TDEIO::Job* job = ( !m_progressId && parentJob() ) ? parentJob() : this;
1823 // Ask confirmation about resuming previous transfer
1824 res = Observer::self()->open_RenameDlg(
1825 job, i18n("File Already Exists"),
1826 m_src.url(),
1827 m_dest.url(),
1828 (RenameDlg_Mode) (M_OVERWRITE | M_RESUME | M_NORENAME), newPath,
1829 d->m_sourceSize, offset );
1830 }
1831
1832 if ( res == R_OVERWRITE || m_overwrite )
1833 offset = 0;
1834 else if ( res == R_CANCEL )
1835 {
1836 if ( job == m_putJob )
1837 m_putJob->kill(true);
1838 else
1839 m_copyJob->kill(true);
1840 m_error = ERR_USER_CANCELED;
1841 emitResult();
1842 return;
1843 }
1844 }
1845 else
1846 m_resumeAnswerSent = true; // No need for an answer
1847
1848 if ( job == m_putJob )
1849 {
1850 m_getJob = get( m_src, false, false /* no GUI */ );
1851 //kdDebug(7007) << "FileCopyJob: m_getJob = " << m_getJob << endl;
1852 m_getJob->addMetaData( "errorPage", "false" );
1853 m_getJob->addMetaData( "AllowCompressedPage", "false" );
1854 // Set size in subjob. This helps if the slave doesn't emit totalSize.
1855 if ( d->m_sourceSize != (TDEIO::filesize_t)-1 )
1856 m_getJob->slotTotalSize( d->m_sourceSize );
1857 if (offset)
1858 {
1859 //kdDebug(7007) << "Setting metadata for resume to " << (unsigned long) offset << endl;
1860 // TODO KDE4: rename to seek or offset and document it
1861 // This isn't used only for resuming, but potentially also for extracting (#72302).
1862 m_getJob->addMetaData( "resume", TDEIO::number(offset) );
1863
1864 // Might or might not get emitted
1865 connect( m_getJob, TQ_SIGNAL(canResume(TDEIO::Job *, TDEIO::filesize_t)),
1866 TQ_SLOT( slotCanResume(TDEIO::Job *, TDEIO::filesize_t)));
1867 }
1868 m_putJob->slave()->setOffset( offset );
1869
1870 m_putJob->suspend();
1871 addSubjob( m_getJob );
1872 connectSubjob( m_getJob ); // Progress info depends on get
1873 m_getJob->resume(); // Order a beer
1874
1875 connect( m_getJob, TQ_SIGNAL(data(TDEIO::Job*,const TQByteArray&)),
1876 TQ_SLOT( slotData(TDEIO::Job*,const TQByteArray&)) );
1877 connect( m_getJob, TQ_SIGNAL(mimetype(TDEIO::Job*,const TQString&) ),
1878 TQ_SLOT(slotMimetype(TDEIO::Job*,const TQString&)) );
1879 }
1880 else // copyjob
1881 {
1882 m_copyJob->slave()->sendResumeAnswer( offset != 0 );
1883 }
1884 }
1885 else if ( job == m_getJob )
1886 {
1887 // Cool, the get job said ok, we can resume
1888 m_canResume = true;
1889 //kdDebug(7007) << "FileCopyJob::slotCanResume from the GET job -> we can resume" << endl;
1890
1891 m_getJob->slave()->setOffset( m_putJob->slave()->offset() );
1892 }
1893 else
1894 kdWarning(7007) << "FileCopyJob::slotCanResume from unknown job=" << job
1895 << " m_getJob=" << m_getJob << " m_putJob=" << m_putJob << endl;
1896}
1897
1898void FileCopyJob::slotData( TDEIO::Job * , const TQByteArray &data)
1899{
1900 //kdDebug(7007) << "FileCopyJob::slotData" << endl;
1901 //kdDebug(7007) << " data size : " << data.size() << endl;
1902 assert(m_putJob);
1903 if (!m_putJob) return; // Don't crash
1904 m_getJob->suspend();
1905 m_putJob->resume(); // Drink the beer
1906 m_buffer = data;
1907
1908 // On the first set of data incoming, we tell the "put" slave about our
1909 // decision about resuming
1910 if (!m_resumeAnswerSent)
1911 {
1912 m_resumeAnswerSent = true;
1913 //kdDebug(7007) << "FileCopyJob::slotData (first time) -> send resume answer " << m_canResume << endl;
1914 m_putJob->slave()->sendResumeAnswer( m_canResume );
1915 }
1916}
1917
1918void FileCopyJob::slotDataReq( TDEIO::Job * , TQByteArray &data)
1919{
1920 //kdDebug(7007) << "FileCopyJob::slotDataReq" << endl;
1921 if (!m_resumeAnswerSent && !m_getJob)
1922 {
1923 // This can't happen (except as a migration bug on 12/10/2000)
1924 m_error = ERR_INTERNAL;
1925 m_errorText = "'Put' job didn't send canResume or 'Get' job didn't send data!";
1926 m_putJob->kill(true);
1927 emitResult();
1928 return;
1929 }
1930 if (m_getJob)
1931 {
1932 m_getJob->resume(); // Order more beer
1933 m_putJob->suspend();
1934 }
1935 data = m_buffer;
1936 m_buffer = TQByteArray();
1937}
1938
1939void FileCopyJob::slotMimetype( TDEIO::Job*, const TQString& type )
1940{
1941 emit mimetype( this, type );
1942}
1943
1944void FileCopyJob::slotResult( TDEIO::Job *job)
1945{
1946 //kdDebug(7007) << "FileCopyJob this=" << this << " ::slotResult(" << job << ")" << endl;
1947 // Did job have an error ?
1948 if ( job->error() )
1949 {
1950 if ((job == m_moveJob) && (job->error() == ERR_UNSUPPORTED_ACTION))
1951 {
1952 m_moveJob = 0;
1953 startBestCopyMethod();
1954 removeSubjob(job);
1955 return;
1956 }
1957 else if ((job == m_copyJob) && (job->error() == ERR_UNSUPPORTED_ACTION))
1958 {
1959 m_copyJob = 0;
1960 startDataPump();
1961 removeSubjob(job);
1962 return;
1963 }
1964 else if (job == m_getJob)
1965 {
1966 m_getJob = 0L;
1967 if (m_putJob)
1968 m_putJob->kill(true);
1969 }
1970 else if (job == m_putJob)
1971 {
1972 m_putJob = 0L;
1973 if (m_getJob)
1974 m_getJob->kill(true);
1975 }
1976 m_error = job->error();
1977 m_errorText = job->errorText();
1978 emitResult();
1979 return;
1980 }
1981
1982 if (job == m_moveJob)
1983 {
1984 m_moveJob = 0; // Finished
1985 }
1986
1987 if (job == m_copyJob)
1988 {
1989 m_copyJob = 0;
1990 if (m_move)
1991 {
1992 d->m_delJob = file_delete( m_src, false/*no GUI*/ ); // Delete source
1993 addSubjob(d->m_delJob);
1994 }
1995 }
1996
1997 if (job == m_getJob)
1998 {
1999 m_getJob = 0; // No action required
2000 if (m_putJob)
2001 m_putJob->resume();
2002 }
2003
2004 if (job == m_putJob)
2005 {
2006 //kdDebug(7007) << "FileCopyJob: m_putJob finished " << endl;
2007 m_putJob = 0;
2008 if (m_getJob)
2009 {
2010 kdWarning(7007) << "WARNING ! Get still going on..." << endl;
2011 m_getJob->resume();
2012 }
2013 if (m_move)
2014 {
2015 d->m_delJob = file_delete( m_src, false/*no GUI*/ ); // Delete source
2016 addSubjob(d->m_delJob);
2017 }
2018 }
2019
2020 if (job == d->m_delJob)
2021 {
2022 d->m_delJob = 0; // Finished
2023 }
2024 removeSubjob(job);
2025}
2026
2027FileCopyJob *TDEIO::file_copy( const KURL& src, const KURL& dest, int permissions,
2028 bool overwrite, bool resume, bool showProgressInfo)
2029{
2030 return new FileCopyJob( src, dest, permissions, false, overwrite, resume, showProgressInfo );
2031}
2032
2033FileCopyJob *TDEIO::file_move( const KURL& src, const KURL& dest, int permissions,
2034 bool overwrite, bool resume, bool showProgressInfo)
2035{
2036 return new FileCopyJob( src, dest, permissions, true, overwrite, resume, showProgressInfo );
2037}
2038
2039SimpleJob *TDEIO::file_delete( const KURL& src, bool showProgressInfo)
2040{
2041 TDEIO_ARGS << src << TQ_INT8(true); // isFile
2042 return new SimpleJob(src, CMD_DEL, packedArgs, showProgressInfo );
2043}
2044
2046
2047// KDE 4: Make it const TQString & _prefix
2048ListJob::ListJob(const KURL& u, bool showProgressInfo, bool _recursive, TQString _prefix, bool _includeHidden) :
2049 SimpleJob(u, CMD_LISTDIR, TQByteArray(), showProgressInfo),
2050 recursive(_recursive), includeHidden(_includeHidden), prefix(_prefix), m_processedEntries(0)
2051{
2052 // We couldn't set the args when calling the parent constructor,
2053 // so do it now.
2054 TQDataStream stream( m_packedArgs, IO_WriteOnly );
2055 stream << u;
2056}
2057
2058void ListJob::slotListEntries( const TDEIO::UDSEntryList& list )
2059{
2060 // Emit progress info (takes care of emit processedSize and percent)
2061 m_processedEntries += list.count();
2062 slotProcessedSize( m_processedEntries );
2063
2064 if (recursive) {
2065 UDSEntryListConstIterator it = list.begin();
2066 UDSEntryListConstIterator end = list.end();
2067
2068 for (; it != end; ++it) {
2069 bool isDir = false;
2070 bool isLink = false;
2071 KURL itemURL;
2072
2073 UDSEntry::ConstIterator it2 = (*it).begin();
2074 UDSEntry::ConstIterator end2 = (*it).end();
2075 for( ; it2 != end2; it2++ ) {
2076 switch( (*it2).m_uds ) {
2077 case UDS_FILE_TYPE:
2078 isDir = S_ISDIR((*it2).m_long);
2079 break;
2080 case UDS_NAME:
2081 if( itemURL.isEmpty() ) {
2082 itemURL = url();
2083 itemURL.addPath( (*it2).m_str );
2084 }
2085 break;
2086 case UDS_URL:
2087 itemURL = (*it2).m_str;
2088 break;
2089 case UDS_LINK_DEST:
2090 // This is a link !!! Don't follow !
2091 isLink = !(*it2).m_str.isEmpty();
2092 break;
2093 default:
2094 break;
2095 }
2096 }
2097 if (isDir && !isLink) {
2098 const TQString filename = itemURL.fileName();
2099 // skip hidden dirs when listing if requested
2100 if (filename != ".." && filename != "." && (includeHidden || filename[0] != '.')) {
2101 ListJob *job = new ListJob(itemURL,
2102 false /*no progress info!*/,
2103 true /*recursive*/,
2104 prefix + filename + "/",
2105 includeHidden);
2106 Scheduler::scheduleJob(job);
2107 connect(job, TQ_SIGNAL(entries( TDEIO::Job *,
2108 const TDEIO::UDSEntryList& )),
2109 TQ_SLOT( gotEntries( TDEIO::Job*,
2110 const TDEIO::UDSEntryList& )));
2111 addSubjob(job);
2112 }
2113 }
2114 }
2115 }
2116
2117 // Not recursive, or top-level of recursive listing : return now (send . and .. as well)
2118 // exclusion of hidden files also requires the full sweep, but the case for full-listing
2119 // a single dir is probably common enough to justify the shortcut
2120 if (prefix.isNull() && includeHidden) {
2121 emit entries(this, list);
2122 } else {
2123 // cull the unwanted hidden dirs and/or parent dir references from the listing, then emit that
2124 UDSEntryList newlist;
2125
2126 UDSEntryListConstIterator it = list.begin();
2127 UDSEntryListConstIterator end = list.end();
2128 for (; it != end; ++it) {
2129
2130 UDSEntry newone = *it;
2131 UDSEntry::Iterator it2 = newone.begin();
2132 TQString filename;
2133 for( ; it2 != newone.end(); it2++ ) {
2134 if ((*it2).m_uds == UDS_NAME) {
2135 filename = (*it2).m_str;
2136 (*it2).m_str = prefix + filename;
2137 }
2138 }
2139 // Avoid returning entries like subdir/. and subdir/.., but include . and .. for
2140 // the toplevel dir, and skip hidden files/dirs if that was requested
2141 if ( (prefix.isNull() || (filename != ".." && filename != ".") )
2142 && (includeHidden || (filename[0] != '.') ) )
2143 newlist.append(newone);
2144 }
2145
2146 emit entries(this, newlist);
2147 }
2148}
2149
2150void ListJob::gotEntries(TDEIO::Job *, const TDEIO::UDSEntryList& list )
2151{
2152 // Forward entries received by subjob - faking we received them ourselves
2153 emit entries(this, list);
2154}
2155
2156void ListJob::slotResult( TDEIO::Job * job )
2157{
2158 // If we can't list a subdir, the result is still ok
2159 // This is why we override Job::slotResult() - to skip error checking
2160 removeSubjob( job );
2161}
2162
2163void ListJob::slotRedirection( const KURL & url )
2164{
2165 if (!tdeApp->authorizeURLAction("redirect", m_url, url))
2166 {
2167 kdWarning(7007) << "ListJob: Redirection from " << m_url << " to " << url << " REJECTED!" << endl;
2168 return;
2169 }
2170 m_redirectionURL = url; // We'll remember that when the job finishes
2171 if (m_url.hasUser() && !url.hasUser() && (m_url.host().lower() == url.host().lower()))
2172 m_redirectionURL.setUser(m_url.user()); // Preserve user
2173 emit redirection( this, m_redirectionURL );
2174}
2175
2176void ListJob::slotFinished()
2177{
2178 // Support for listing archives as directories
2179 if ( m_error == TDEIO::ERR_IS_FILE && m_url.isLocalFile() ) {
2180 KMimeType::Ptr ptr = KMimeType::findByURL( m_url, 0, true, true );
2181 if ( ptr ) {
2182 TQString proto = ptr->property("X-TDE-LocalProtocol").toString();
2183 if ( !proto.isEmpty() && KProtocolInfo::isKnownProtocol(proto) ) {
2184 m_redirectionURL = m_url;
2185 m_redirectionURL.setProtocol( proto );
2186 m_error = 0;
2187 emit redirection(this,m_redirectionURL);
2188 }
2189 }
2190 }
2191 if ( m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error ) {
2192 // Return slave to the scheduler
2193 SimpleJob::slotFinished();
2194 } else {
2195
2196 //kdDebug(7007) << "ListJob: Redirection to " << m_redirectionURL << endl;
2197 if (queryMetaData("permanent-redirect")=="true")
2198 emit permanentRedirection(this, m_url, m_redirectionURL);
2199 m_url = m_redirectionURL;
2200 m_redirectionURL = KURL();
2201 m_packedArgs.truncate(0);
2202 TQDataStream stream( m_packedArgs, IO_WriteOnly );
2203 stream << m_url;
2204
2205 // Return slave to the scheduler
2206 slaveDone();
2207 Scheduler::doJob(this);
2208 }
2209}
2210
2211void ListJob::slotMetaData( const TDEIO::MetaData &_metaData) {
2212 SimpleJob::slotMetaData(_metaData);
2213 storeSSLSessionFromJob(m_redirectionURL);
2214}
2215
2216ListJob *TDEIO::listDir( const KURL& url, bool showProgressInfo, bool includeHidden )
2217{
2218 ListJob * job = new ListJob(url, showProgressInfo,false,TQString::null,includeHidden);
2219 return job;
2220}
2221
2222ListJob *TDEIO::listRecursive( const KURL& url, bool showProgressInfo, bool includeHidden )
2223{
2224 ListJob * job = new ListJob(url, showProgressInfo, true,TQString::null,includeHidden);
2225 return job;
2226}
2227
2228void ListJob::setUnrestricted(bool unrestricted)
2229{
2230 if (unrestricted)
2231 extraFlags() |= EF_ListJobUnrestricted;
2232 else
2233 extraFlags() &= ~EF_ListJobUnrestricted;
2234}
2235
2236void ListJob::start(Slave *slave)
2237{
2238 if (tdeApp && !tdeApp->authorizeURLAction("list", m_url, m_url) && !(extraFlags() & EF_ListJobUnrestricted))
2239 {
2240 m_error = ERR_ACCESS_DENIED;
2241 m_errorText = m_url.url();
2242 TQTimer::singleShot(0, this, TQ_SLOT(slotFinished()) );
2243 return;
2244 }
2245 connect( slave, TQ_SIGNAL( listEntries( const TDEIO::UDSEntryList& )),
2246 TQ_SLOT( slotListEntries( const TDEIO::UDSEntryList& )));
2247 connect( slave, TQ_SIGNAL( totalSize( TDEIO::filesize_t ) ),
2248 TQ_SLOT( slotTotalSize( TDEIO::filesize_t ) ) );
2249 connect( slave, TQ_SIGNAL( redirection(const KURL &) ),
2250 TQ_SLOT( slotRedirection(const KURL &) ) );
2251
2252 SimpleJob::start(slave);
2253}
2254
2255class CopyJob::CopyJobPrivate
2256{
2257public:
2258 CopyJobPrivate() {
2259 m_defaultPermissions = false;
2260 m_bURLDirty = false;
2261 }
2262 // This is the dest URL that was initially given to CopyJob
2263 // It is copied into m_dest, which can be changed for a given src URL
2264 // (when using the RENAME dialog in slotResult),
2265 // and which will be reset for the next src URL.
2266 KURL m_globalDest;
2267 // The state info about that global dest
2268 CopyJob::DestinationState m_globalDestinationState;
2269 // See setDefaultPermissions
2270 bool m_defaultPermissions;
2271 // Whether URLs changed (and need to be emitted by the next slotReport call)
2272 bool m_bURLDirty;
2273 // Used after copying all the files into the dirs, to set mtime (TODO: and permissions?)
2274 // after the copy is done
2275 TQValueList<CopyInfo> m_directoriesCopied;
2276};
2277
2278CopyJob::CopyJob( const KURL::List& src, const KURL& dest, CopyMode mode, bool asMethod, bool showProgressInfo )
2279 : Job(showProgressInfo), m_mode(mode), m_asMethod(asMethod),
2280 destinationState(DEST_NOT_STATED), state(STATE_STATING),
2281 m_totalSize(0), m_processedSize(0), m_fileProcessedSize(0),
2282 m_processedFiles(0), m_processedDirs(0),
2283 m_srcList(src), m_currentStatSrc(m_srcList.begin()),
2284 m_bCurrentOperationIsLink(false), m_bSingleFileCopy(false), m_bOnlyRenames(mode==Move),
2285 m_dest(dest), m_bAutoSkip( false ), m_bOverwriteAll( false ),
2286 m_conflictError(0), m_reportTimer(0)
2287{
2288 d = new CopyJobPrivate;
2289 d->m_globalDest = dest;
2290 d->m_globalDestinationState = destinationState;
2291
2292 if ( showProgressInfo ) {
2293 connect( this, TQ_SIGNAL( totalFiles( TDEIO::Job*, unsigned long ) ),
2294 Observer::self(), TQ_SLOT( slotTotalFiles( TDEIO::Job*, unsigned long ) ) );
2295
2296 connect( this, TQ_SIGNAL( totalDirs( TDEIO::Job*, unsigned long ) ),
2297 Observer::self(), TQ_SLOT( slotTotalDirs( TDEIO::Job*, unsigned long ) ) );
2298 }
2299 TQTimer::singleShot(0, this, TQ_SLOT(slotStart()));
2314}
2315
2316CopyJob::~CopyJob()
2317{
2318 delete d;
2319}
2320
2321void CopyJob::slotStart()
2322{
2328 m_reportTimer = new TQTimer(this);
2329
2330 connect(m_reportTimer,TQ_SIGNAL(timeout()),this,TQ_SLOT(slotReport()));
2331 m_reportTimer->start(REPORT_TIMEOUT,false);
2332
2333 // Stat the dest
2334 TDEIO::Job * job = TDEIO::stat( m_dest, false, 2, false );
2335 //kdDebug(7007) << "CopyJob:stating the dest " << m_dest << endl;
2336 addSubjob(job);
2337}
2338
2339// For unit test purposes
2340TDEIO_EXPORT bool tdeio_resolve_local_urls = true;
2341
2342void CopyJob::slotResultStating( Job *job )
2343{
2344 //kdDebug(7007) << "CopyJob::slotResultStating" << endl;
2345 // Was there an error while stating the src ?
2346 if (job->error() && destinationState != DEST_NOT_STATED )
2347 {
2348 KURL srcurl = ((SimpleJob*)job)->url();
2349 if ( !srcurl.isLocalFile() )
2350 {
2351 // Probably : src doesn't exist. Well, over some protocols (e.g. FTP)
2352 // this info isn't really reliable (thanks to MS FTP servers).
2353 // We'll assume a file, and try to download anyway.
2354 kdDebug(7007) << "Error while stating source. Activating hack" << endl;
2355 subjobs.remove( job );
2356 assert ( subjobs.isEmpty() ); // We should have only one job at a time ...
2357 struct CopyInfo info;
2358 info.permissions = (mode_t) -1;
2359 info.mtime = (time_t) -1;
2360 info.ctime = (time_t) -1;
2361 info.size = (TDEIO::filesize_t)-1;
2362 info.uSource = srcurl;
2363 info.uDest = m_dest;
2364 // Append filename or dirname to destination URL, if allowed
2365 if ( destinationState == DEST_IS_DIR && !m_asMethod )
2366 info.uDest.addPath( srcurl.fileName() );
2367
2368 files.append( info );
2369 statNextSrc();
2370 return;
2371 }
2372 // Local file. If stat fails, the file definitely doesn't exist.
2373 Job::slotResult( job ); // will set the error and emit result(this)
2374 return;
2375 }
2376
2377 // Is it a file or a dir ? Does it have a local path?
2378 UDSEntry entry = ((StatJob*)job)->statResult();
2379 bool bDir = false;
2380 bool bLink = false;
2381 TQString sName;
2382 TQString sLocalPath;
2383 UDSEntry::ConstIterator it2 = entry.begin();
2384 for( ; it2 != entry.end(); it2++ ) {
2385 if ( ((*it2).m_uds) == UDS_FILE_TYPE )
2386 bDir = S_ISDIR( (mode_t)(*it2).m_long );
2387 else if ( ((*it2).m_uds) == UDS_LINK_DEST )
2388 bLink = !((*it2).m_str.isEmpty());
2389 else if ( ((*it2).m_uds) == UDS_NAME )
2390 sName = (*it2).m_str;
2391 else if ( ((*it2).m_uds) == UDS_LOCAL_PATH )
2392 sLocalPath = (*it2).m_str;
2393 }
2394
2395 if ( destinationState == DEST_NOT_STATED )
2396 // we were stating the dest
2397 {
2398 if (job->error())
2399 destinationState = DEST_DOESNT_EXIST;
2400 else {
2401 // Treat symlinks to dirs as dirs here, so no test on bLink
2402 destinationState = bDir ? DEST_IS_DIR : DEST_IS_FILE;
2403 //kdDebug(7007) << "CopyJob::slotResultStating dest is dir:" << bDir << endl;
2404 }
2405 const bool isGlobalDest = m_dest == d->m_globalDest;
2406 if ( isGlobalDest )
2407 d->m_globalDestinationState = destinationState;
2408
2409 if ( !sLocalPath.isEmpty() && tdeio_resolve_local_urls ) {
2410 m_dest = KURL();
2411 m_dest.setPath(sLocalPath);
2412 if ( isGlobalDest )
2413 d->m_globalDest = m_dest;
2414 }
2415
2416 subjobs.remove( job );
2417 assert ( subjobs.isEmpty() );
2418
2419 // After knowing what the dest is, we can start stat'ing the first src.
2420 statCurrentSrc();
2421 return;
2422 }
2423 // We were stating the current source URL
2424 m_currentDest = m_dest; // used by slotEntries
2425 // Create a dummy list with it, for slotEntries
2426 UDSEntryList lst;
2427 lst.append(entry);
2428
2429 // There 6 cases, and all end up calling slotEntries(job, lst) first :
2430 // 1 - src is a dir, destination is a directory,
2431 // slotEntries will append the source-dir-name to the destination
2432 // 2 - src is a dir, destination is a file, ERROR (done later on)
2433 // 3 - src is a dir, destination doesn't exist, then it's the destination dirname,
2434 // so slotEntries will use it as destination.
2435
2436 // 4 - src is a file, destination is a directory,
2437 // slotEntries will append the filename to the destination.
2438 // 5 - src is a file, destination is a file, m_dest is the exact destination name
2439 // 6 - src is a file, destination doesn't exist, m_dest is the exact destination name
2440 // Tell slotEntries not to alter the src url
2441 m_bCurrentSrcIsDir = false;
2442 slotEntries(job, lst);
2443
2444 KURL srcurl;
2445 if (!sLocalPath.isEmpty())
2446 srcurl.setPath(sLocalPath);
2447 else
2448 srcurl = ((SimpleJob*)job)->url();
2449
2450 subjobs.remove( job );
2451 assert ( subjobs.isEmpty() ); // We should have only one job at a time ...
2452
2453 if ( bDir
2454 && !bLink // treat symlinks as files (no recursion)
2455 && m_mode != Link ) // No recursion in Link mode either.
2456 {
2457 //kdDebug(7007) << " Source is a directory " << endl;
2458
2459 m_bCurrentSrcIsDir = true; // used by slotEntries
2460 if ( destinationState == DEST_IS_DIR ) // (case 1)
2461 {
2462 if ( !m_asMethod )
2463 {
2464 // Use <desturl>/<directory_copied> as destination, from now on
2465 TQString directory = srcurl.fileName();
2466 if ( !sName.isEmpty() && KProtocolInfo::fileNameUsedForCopying( srcurl ) == KProtocolInfo::Name )
2467 {
2468 directory = sName;
2469 }
2470 m_currentDest.addPath( directory );
2471 }
2472 }
2473 else if ( destinationState == DEST_IS_FILE ) // (case 2)
2474 {
2475 m_error = ERR_IS_FILE;
2476 m_errorText = m_dest.prettyURL();
2477 emitResult();
2478 return;
2479 }
2480 else // (case 3)
2481 {
2482 // otherwise dest is new name for toplevel dir
2483 // so the destination exists, in fact, from now on.
2484 // (This even works with other src urls in the list, since the
2485 // dir has effectively been created)
2486 destinationState = DEST_IS_DIR;
2487 if ( m_dest == d->m_globalDest )
2488 d->m_globalDestinationState = destinationState;
2489 }
2490
2491 startListing( srcurl );
2492 }
2493 else
2494 {
2495 //kdDebug(7007) << " Source is a file (or a symlink), or we are linking -> no recursive listing " << endl;
2496 statNextSrc();
2497 }
2498}
2499
2500void CopyJob::slotReport()
2501{
2502 // If showProgressInfo was set, m_progressId is > 0.
2503 Observer * observer = m_progressId ? Observer::self() : 0L;
2504 switch (state) {
2505 case STATE_COPYING_FILES:
2506 emit processedFiles( this, m_processedFiles );
2507 if (observer) observer->slotProcessedFiles(this, m_processedFiles);
2508 if (d->m_bURLDirty)
2509 {
2510 // Only emit urls when they changed. This saves time, and fixes #66281
2511 d->m_bURLDirty = false;
2512 if (m_mode==Move)
2513 {
2514 if (observer) observer->slotMoving( this, m_currentSrcURL, m_currentDestURL);
2515 emit moving( this, m_currentSrcURL, m_currentDestURL);
2516 }
2517 else if (m_mode==Link)
2518 {
2519 if (observer) observer->slotCopying( this, m_currentSrcURL, m_currentDestURL ); // we don't have a slotLinking
2520 emit linking( this, m_currentSrcURL.path(), m_currentDestURL );
2521 }
2522 else
2523 {
2524 if (observer) observer->slotCopying( this, m_currentSrcURL, m_currentDestURL );
2525 emit copying( this, m_currentSrcURL, m_currentDestURL );
2526 }
2527 }
2528 break;
2529
2530 case STATE_CREATING_DIRS:
2531 if (observer) observer->slotProcessedDirs( this, m_processedDirs );
2532 emit processedDirs( this, m_processedDirs );
2533 if (d->m_bURLDirty)
2534 {
2535 d->m_bURLDirty = false;
2536 emit creatingDir( this, m_currentDestURL );
2537 if (observer) observer->slotCreatingDir( this, m_currentDestURL);
2538 }
2539 break;
2540
2541 case STATE_STATING:
2542 case STATE_LISTING:
2543 if (d->m_bURLDirty)
2544 {
2545 d->m_bURLDirty = false;
2546 if (observer) observer->slotCopying( this, m_currentSrcURL, m_currentDestURL );
2547 }
2548 emit totalSize( this, m_totalSize );
2549 emit totalFiles( this, files.count() );
2550 emit totalDirs( this, dirs.count() );
2551 break;
2552
2553 default:
2554 break;
2555 }
2556}
2557
2558void CopyJob::slotEntries(TDEIO::Job* job, const UDSEntryList& list)
2559{
2560 UDSEntryListConstIterator it = list.begin();
2561 UDSEntryListConstIterator end = list.end();
2562 for (; it != end; ++it) {
2563 UDSEntry::ConstIterator it2 = (*it).begin();
2564 struct CopyInfo info;
2565 info.permissions = -1;
2566 info.mtime = (time_t) -1;
2567 info.ctime = (time_t) -1;
2568 info.size = (TDEIO::filesize_t)-1;
2569 TQString displayName;
2570 KURL url;
2571 TQString localPath;
2572 bool isDir = false;
2573 for( ; it2 != (*it).end(); it2++ ) {
2574 switch ((*it2).m_uds) {
2575 case UDS_FILE_TYPE:
2576 //info.type = (mode_t)((*it2).m_long);
2577 isDir = S_ISDIR( (mode_t)((*it2).m_long) );
2578 break;
2579 case UDS_NAME: // recursive listing, displayName can be a/b/c/d
2580 displayName = (*it2).m_str;
2581 break;
2582 case UDS_URL: // optional
2583 url = KURL((*it2).m_str);
2584 break;
2585 case UDS_LOCAL_PATH:
2586 localPath = (*it2).m_str;
2587 break;
2588 case UDS_LINK_DEST:
2589 info.linkDest = (*it2).m_str;
2590 break;
2591 case UDS_ACCESS:
2592 info.permissions = ((*it2).m_long);
2593 break;
2594 case UDS_SIZE:
2595 info.size = (TDEIO::filesize_t)((*it2).m_long);
2596 m_totalSize += info.size;
2597 break;
2598 case UDS_MODIFICATION_TIME:
2599 info.mtime = (time_t)((*it2).m_long);
2600 break;
2601 case UDS_CREATION_TIME:
2602 info.ctime = (time_t)((*it2).m_long);
2603 default:
2604 break;
2605 }
2606 }
2607 if (displayName != ".." && displayName != ".")
2608 {
2609 bool hasCustomURL = !url.isEmpty() || !localPath.isEmpty();
2610 if( !hasCustomURL ) {
2611 // Make URL from displayName
2612 url = ((SimpleJob *)job)->url();
2613 if ( m_bCurrentSrcIsDir ) { // Only if src is a directory. Otherwise uSource is fine as is
2614 //kdDebug(7007) << "adding path " << displayName << endl;
2615 url.addPath( displayName );
2616 }
2617 }
2618 //kdDebug(7007) << "displayName=" << displayName << " url=" << url << endl;
2619 if (!localPath.isEmpty() && tdeio_resolve_local_urls) {
2620 url = KURL();
2621 url.setPath(localPath);
2622 }
2623
2624 info.uSource = url;
2625 info.uDest = m_currentDest;
2626 //kdDebug(7007) << " uSource=" << info.uSource << " uDest(1)=" << info.uDest << endl;
2627 // Append filename or dirname to destination URL, if allowed
2628 if ( destinationState == DEST_IS_DIR &&
2629 // "copy/move as <foo>" means 'foo' is the dest for the base srcurl
2630 // (passed here during stating) but not its children (during listing)
2631 ( ! ( m_asMethod && state == STATE_STATING ) ) )
2632 {
2633 TQString destFileName;
2634 if ( hasCustomURL &&
2635 KProtocolInfo::fileNameUsedForCopying( url ) == KProtocolInfo::FromURL ) {
2636 //destFileName = url.fileName(); // Doesn't work for recursive listing
2637 // Count the number of prefixes used by the recursive listjob
2638 int numberOfSlashes = displayName.contains( '/' ); // don't make this a find()!
2639 TQString path = url.path();
2640 int pos = 0;
2641 for ( int n = 0; n < numberOfSlashes + 1; ++n ) {
2642 pos = path.findRev( '/', pos - 1 );
2643 if ( pos == -1 ) { // error
2644 kdWarning(7007) << "tdeioslave bug: not enough slashes in UDS_URL " << path << " - looking for " << numberOfSlashes << " slashes" << endl;
2645 break;
2646 }
2647 }
2648 if ( pos >= 0 ) {
2649 destFileName = path.mid( pos + 1 );
2650 }
2651
2652 } else { // destination filename taken from UDS_NAME
2653 destFileName = displayName;
2654 }
2655
2656 // Here we _really_ have to add some filename to the dest.
2657 // Otherwise, we end up with e.g. dest=..../Desktop/ itself.
2658 // (This can happen when dropping a link to a webpage with no path)
2659 if ( destFileName.isEmpty() )
2660 destFileName = TDEIO::encodeFileName( info.uSource.prettyURL() );
2661
2662 //kdDebug(7007) << " adding destFileName=" << destFileName << endl;
2663 info.uDest.addPath( destFileName );
2664 }
2665 //kdDebug(7007) << " uDest(2)=" << info.uDest << endl;
2666 //kdDebug(7007) << " " << info.uSource << " -> " << info.uDest << endl;
2667 if ( info.linkDest.isEmpty() && isDir && m_mode != Link ) // Dir
2668 {
2669 dirs.append( info ); // Directories
2670 if (m_mode == Move)
2671 dirsToRemove.append( info.uSource );
2672 }
2673 else {
2674 files.append( info ); // Files and any symlinks
2675 }
2676 }
2677 }
2678}
2679
2680void CopyJob::skipSrc()
2681{
2682 m_dest = d->m_globalDest;
2683 destinationState = d->m_globalDestinationState;
2684 ++m_currentStatSrc;
2685 skip( m_currentSrcURL );
2686 statCurrentSrc();
2687}
2688
2689void CopyJob::statNextSrc()
2690{
2691 /* Revert to the global destination, the one that applies to all source urls.
2692 * Imagine you copy the items a b and c into /d, but /d/b exists so the user uses "Rename" to put it in /foo/b instead.
2693 * m_dest is /foo/b for b, but we have to revert to /d for item c and following.
2694 */
2695 m_dest = d->m_globalDest;
2696 destinationState = d->m_globalDestinationState;
2697 ++m_currentStatSrc;
2698 statCurrentSrc();
2699}
2700
2701void CopyJob::statCurrentSrc()
2702{
2703 if ( m_currentStatSrc != m_srcList.end() )
2704 {
2705 m_currentSrcURL = (*m_currentStatSrc);
2706 d->m_bURLDirty = true;
2707 if ( m_mode == Link )
2708 {
2709 // Skip the "stating the source" stage, we don't need it for linking
2710 m_currentDest = m_dest;
2711 struct CopyInfo info;
2712 info.permissions = -1;
2713 info.mtime = (time_t) -1;
2714 info.ctime = (time_t) -1;
2715 info.size = (TDEIO::filesize_t)-1;
2716 info.uSource = m_currentSrcURL;
2717 info.uDest = m_currentDest;
2718 // Append filename or dirname to destination URL, if allowed
2719 if ( destinationState == DEST_IS_DIR && !m_asMethod )
2720 {
2721 if (
2722 (m_currentSrcURL.protocol() == info.uDest.protocol()) &&
2723 (m_currentSrcURL.host() == info.uDest.host()) &&
2724 (m_currentSrcURL.port() == info.uDest.port()) &&
2725 (m_currentSrcURL.user() == info.uDest.user()) &&
2726 (m_currentSrcURL.pass() == info.uDest.pass()) )
2727 {
2728 // This is the case of creating a real symlink
2729 info.uDest.addPath( m_currentSrcURL.fileName() );
2730 }
2731 else
2732 {
2733 // Different protocols, we'll create a .desktop file
2734 // We have to change the extension anyway, so while we're at it,
2735 // name the file like the URL
2736 info.uDest.addPath( TDEIO::encodeFileName( m_currentSrcURL.prettyURL() )+".desktop" );
2737 }
2738 }
2739 files.append( info ); // Files and any symlinks
2740 statNextSrc(); // we could use a loop instead of a recursive call :)
2741 return;
2742 }
2743 else if ( m_mode == Move && (
2744 // Don't go renaming right away if we need a stat() to find out the destination filename
2745 KProtocolInfo::fileNameUsedForCopying( m_currentSrcURL ) == KProtocolInfo::FromURL ||
2746 destinationState != DEST_IS_DIR || m_asMethod )
2747 )
2748 {
2749 // If moving, before going for the full stat+[list+]copy+del thing, try to rename
2750 // The logic is pretty similar to FileCopyJob::slotStart()
2751 if ( (m_currentSrcURL.protocol() == m_dest.protocol()) &&
2752 (m_currentSrcURL.host() == m_dest.host()) &&
2753 (m_currentSrcURL.port() == m_dest.port()) &&
2754 (m_currentSrcURL.user() == m_dest.user()) &&
2755 (m_currentSrcURL.pass() == m_dest.pass()) )
2756 {
2757 startRenameJob( m_currentSrcURL );
2758 return;
2759 }
2760 else if ( m_currentSrcURL.isLocalFile() && KProtocolInfo::canRenameFromFile( m_dest ) )
2761 {
2762 startRenameJob( m_dest );
2763 return;
2764 }
2765 else if ( m_dest.isLocalFile() && KProtocolInfo::canRenameToFile( m_currentSrcURL ) )
2766 {
2767 startRenameJob( m_currentSrcURL );
2768 return;
2769 }
2770 }
2771
2772 // if the file system doesn't support deleting, we do not even stat
2773 if (m_mode == Move && !KProtocolInfo::supportsDeleting(m_currentSrcURL)) {
2774 TQGuardedPtr<CopyJob> that = this;
2775 if (isInteractive())
2776 KMessageBox::information( 0, buildErrorString(ERR_CANNOT_DELETE, m_currentSrcURL.prettyURL()));
2777 if (that)
2778 statNextSrc(); // we could use a loop instead of a recursive call :)
2779 return;
2780 }
2781
2782 // Stat the next src url
2783 Job * job = TDEIO::stat( m_currentSrcURL, true, 2, false );
2784 //kdDebug(7007) << "TDEIO::stat on " << m_currentSrcURL << endl;
2785 state = STATE_STATING;
2786 addSubjob(job);
2787 m_currentDestURL=m_dest;
2788 m_bOnlyRenames = false;
2789 d->m_bURLDirty = true;
2790 }
2791 else
2792 {
2793 // Finished the stat'ing phase
2794 // First make sure that the totals were correctly emitted
2795 state = STATE_STATING;
2796 d->m_bURLDirty = true;
2797 slotReport();
2798 if (!dirs.isEmpty())
2799 emit aboutToCreate( this, dirs );
2800 if (!files.isEmpty())
2801 emit aboutToCreate( this, files );
2802 // Check if we are copying a single file
2803 m_bSingleFileCopy = ( files.count() == 1 && dirs.isEmpty() );
2804 // Then start copying things
2805 state = STATE_CREATING_DIRS;
2806 createNextDir();
2807 }
2808}
2809
2810void CopyJob::startRenameJob( const KURL& slave_url )
2811{
2812 KURL dest = m_dest;
2813 // Append filename or dirname to destination URL, if allowed
2814 if ( destinationState == DEST_IS_DIR && !m_asMethod )
2815 dest.addPath( m_currentSrcURL.fileName() );
2816 kdDebug(7007) << "This seems to be a suitable case for trying to rename before stat+[list+]copy+del" << endl;
2817 state = STATE_RENAMING;
2818
2819 struct CopyInfo info;
2820 info.permissions = -1;
2821 info.mtime = (time_t) -1;
2822 info.ctime = (time_t) -1;
2823 info.size = (TDEIO::filesize_t)-1;
2824 info.uSource = m_currentSrcURL;
2825 info.uDest = dest;
2826 TQValueList<CopyInfo> files;
2827 files.append(info);
2828 emit aboutToCreate( this, files );
2829
2830 TDEIO_ARGS << m_currentSrcURL << dest << (TQ_INT8) false /*no overwrite*/;
2831 SimpleJob * newJob = new SimpleJob(slave_url, CMD_RENAME, packedArgs, false);
2832 Scheduler::scheduleJob(newJob);
2833 addSubjob( newJob );
2834 if ( m_currentSrcURL.directory() != dest.directory() ) // For the user, moving isn't renaming. Only renaming is.
2835 m_bOnlyRenames = false;
2836}
2837
2838void CopyJob::startListing( const KURL & src )
2839{
2840 state = STATE_LISTING;
2841 d->m_bURLDirty = true;
2842 ListJob * newjob = listRecursive( src, false );
2843 newjob->setUnrestricted(true);
2844 connect(newjob, TQ_SIGNAL(entries( TDEIO::Job *,
2845 const TDEIO::UDSEntryList& )),
2846 TQ_SLOT( slotEntries( TDEIO::Job*,
2847 const TDEIO::UDSEntryList& )));
2848 addSubjob( newjob );
2849}
2850
2851void CopyJob::skip( const KURL & sourceUrl )
2852{
2853 // Check if this is one if toplevel sources
2854 // If yes, remove it from m_srcList, for a correct FilesRemoved() signal
2855 //kdDebug(7007) << "CopyJob::skip: looking for " << sourceUrl << endl;
2856 KURL::List::Iterator sit = m_srcList.find( sourceUrl );
2857 if ( sit != m_srcList.end() )
2858 {
2859 //kdDebug(7007) << "CopyJob::skip: removing " << sourceUrl << " from list" << endl;
2860 m_srcList.remove( sit );
2861 }
2862 dirsToRemove.remove( sourceUrl );
2863}
2864
2865bool CopyJob::shouldOverwrite( const TQString& path ) const
2866{
2867 if ( m_bOverwriteAll )
2868 return true;
2869 TQStringList::ConstIterator sit = m_overwriteList.begin();
2870 for( ; sit != m_overwriteList.end(); ++sit )
2871 if ( path.startsWith( *sit ) )
2872 return true;
2873 return false;
2874}
2875
2876bool CopyJob::shouldSkip( const TQString& path ) const
2877{
2878 TQStringList::ConstIterator sit = m_skipList.begin();
2879 for( ; sit != m_skipList.end(); ++sit )
2880 if ( path.startsWith( *sit ) )
2881 return true;
2882 return false;
2883}
2884
2885void CopyJob::slotResultCreatingDirs( Job * job )
2886{
2887 // The dir we are trying to create:
2888 TQValueList<CopyInfo>::Iterator it = dirs.begin();
2889 // Was there an error creating a dir ?
2890 if ( job->error() )
2891 {
2892 m_conflictError = job->error();
2893 if ( (m_conflictError == ERR_DIR_ALREADY_EXIST)
2894 || (m_conflictError == ERR_FILE_ALREADY_EXIST) ) // can't happen?
2895 {
2896 KURL oldURL = ((SimpleJob*)job)->url();
2897 // Should we skip automatically ?
2898 if ( m_bAutoSkip ) {
2899 // We don't want to copy files in this directory, so we put it on the skip list
2900 m_skipList.append( oldURL.path( 1 ) );
2901 skip( oldURL );
2902 dirs.remove( it ); // Move on to next dir
2903 } else {
2904 // Did the user choose to overwrite already?
2905 const TQString destFile = (*it).uDest.path();
2906 if ( shouldOverwrite( destFile ) ) { // overwrite => just skip
2907 emit copyingDone( this, ( *it ).uSource, ( *it ).uDest, true /* directory */, false /* renamed */ );
2908 dirs.remove( it ); // Move on to next dir
2909 } else {
2910 if ( !isInteractive() ) {
2911 Job::slotResult( job ); // will set the error and emit result(this)
2912 return;
2913 }
2914
2915 assert( ((SimpleJob*)job)->url().url() == (*it).uDest.url() );
2916 subjobs.remove( job );
2917 assert ( subjobs.isEmpty() ); // We should have only one job at a time ...
2918
2919 // We need to stat the existing dir, to get its last-modification time
2920 KURL existingDest( (*it).uDest );
2921 SimpleJob * newJob = TDEIO::stat( existingDest, false, 2, false );
2922 Scheduler::scheduleJob(newJob);
2923 kdDebug(7007) << "TDEIO::stat for resolving conflict on " << existingDest << endl;
2924 state = STATE_CONFLICT_CREATING_DIRS;
2925 addSubjob(newJob);
2926 return; // Don't move to next dir yet !
2927 }
2928 }
2929 }
2930 else
2931 {
2932 // Severe error, abort
2933 Job::slotResult( job ); // will set the error and emit result(this)
2934 return;
2935 }
2936 }
2937 else // no error : remove from list, to move on to next dir
2938 {
2939 //this is required for the undo feature
2940 emit copyingDone( this, (*it).uSource, (*it).uDest, true, false );
2941 d->m_directoriesCopied.append( *it );
2942 dirs.remove( it );
2943 }
2944
2945 m_processedDirs++;
2946 //emit processedDirs( this, m_processedDirs );
2947 subjobs.remove( job );
2948 assert( subjobs.isEmpty() ); // We should have only one job at a time ...
2949 createNextDir();
2950}
2951
2952void CopyJob::slotResultConflictCreatingDirs( TDEIO::Job * job )
2953{
2954 // We come here after a conflict has been detected and we've stated the existing dir
2955
2956 // The dir we were trying to create:
2957 TQValueList<CopyInfo>::Iterator it = dirs.begin();
2958 // Its modification time:
2959 time_t destmtime = (time_t)-1;
2960 time_t destctime = (time_t)-1;
2961 TDEIO::filesize_t destsize = 0;
2962 TQString linkDest;
2963
2964 UDSEntry entry = ((TDEIO::StatJob*)job)->statResult();
2965 TDEIO::UDSEntry::ConstIterator it2 = entry.begin();
2966 for( ; it2 != entry.end(); it2++ ) {
2967 switch ((*it2).m_uds) {
2968 case UDS_MODIFICATION_TIME:
2969 destmtime = (time_t)((*it2).m_long);
2970 break;
2971 case UDS_CREATION_TIME:
2972 destctime = (time_t)((*it2).m_long);
2973 break;
2974 case UDS_SIZE:
2975 destsize = (*it2).m_long;
2976 break;
2977 case UDS_LINK_DEST:
2978 linkDest = (*it2).m_str;
2979 break;
2980 }
2981 }
2982 subjobs.remove( job );
2983 assert ( subjobs.isEmpty() ); // We should have only one job at a time ...
2984
2985 // Always multi and skip (since there are files after that)
2986 RenameDlg_Mode mode = (RenameDlg_Mode)( M_MULTI | M_SKIP );
2987 // Overwrite only if the existing thing is a dir (no chance with a file)
2988 if ( m_conflictError == ERR_DIR_ALREADY_EXIST )
2989 {
2990 if( (*it).uSource == (*it).uDest ||
2991 ((*it).uSource.protocol() == (*it).uDest.protocol() &&
2992 (*it).uSource.path(-1) == linkDest) )
2993 mode = (RenameDlg_Mode)( mode | M_OVERWRITE_ITSELF);
2994 else
2995 mode = (RenameDlg_Mode)( mode | M_OVERWRITE );
2996 }
2997
2998 TQString existingDest = (*it).uDest.path();
2999 TQString newPath;
3000 if (m_reportTimer)
3001 m_reportTimer->stop();
3002 RenameDlg_Result r = Observer::self()->open_RenameDlg( this, i18n("Folder Already Exists"),
3003 (*it).uSource.url(),
3004 (*it).uDest.url(),
3005 mode, newPath,
3006 (*it).size, destsize,
3007 (*it).ctime, destctime,
3008 (*it).mtime, destmtime );
3009 if (m_reportTimer)
3010 m_reportTimer->start(REPORT_TIMEOUT,false);
3011 switch ( r ) {
3012 case R_CANCEL:
3013 m_error = ERR_USER_CANCELED;
3014 emitResult();
3015 return;
3016 case R_RENAME:
3017 {
3018 TQString oldPath = (*it).uDest.path( 1 );
3019 KURL newUrl( (*it).uDest );
3020 newUrl.setPath( newPath );
3021 emit renamed( this, (*it).uDest, newUrl ); // for e.g. kpropsdlg
3022
3023 // Change the current one and strip the trailing '/'
3024 (*it).uDest.setPath( newUrl.path( -1 ) );
3025 newPath = newUrl.path( 1 ); // With trailing slash
3026 TQValueList<CopyInfo>::Iterator renamedirit = it;
3027 ++renamedirit;
3028 // Change the name of subdirectories inside the directory
3029 for( ; renamedirit != dirs.end() ; ++renamedirit )
3030 {
3031 TQString path = (*renamedirit).uDest.path();
3032 if ( path.left(oldPath.length()) == oldPath ) {
3033 TQString n = path;
3034 n.replace( 0, oldPath.length(), newPath );
3035 kdDebug(7007) << "dirs list: " << (*renamedirit).uSource.path()
3036 << " was going to be " << path
3037 << ", changed into " << n << endl;
3038 (*renamedirit).uDest.setPath( n );
3039 }
3040 }
3041 // Change filenames inside the directory
3042 TQValueList<CopyInfo>::Iterator renamefileit = files.begin();
3043 for( ; renamefileit != files.end() ; ++renamefileit )
3044 {
3045 TQString path = (*renamefileit).uDest.path();
3046 if ( path.left(oldPath.length()) == oldPath ) {
3047 TQString n = path;
3048 n.replace( 0, oldPath.length(), newPath );
3049 kdDebug(7007) << "files list: " << (*renamefileit).uSource.path()
3050 << " was going to be " << path
3051 << ", changed into " << n << endl;
3052 (*renamefileit).uDest.setPath( n );
3053 }
3054 }
3055 if (!dirs.isEmpty())
3056 emit aboutToCreate( this, dirs );
3057 if (!files.isEmpty())
3058 emit aboutToCreate( this, files );
3059 }
3060 break;
3061 case R_AUTO_SKIP:
3062 m_bAutoSkip = true;
3063 // fall through
3064 case R_SKIP:
3065 m_skipList.append( existingDest );
3066 skip( (*it).uSource );
3067 // Move on to next dir
3068 dirs.remove( it );
3069 m_processedDirs++;
3070 break;
3071 case R_OVERWRITE:
3072 m_overwriteList.append( existingDest );
3073 emit copyingDone( this, ( *it ).uSource, ( *it ).uDest, true /* directory */, false /* renamed */ );
3074 // Move on to next dir
3075 dirs.remove( it );
3076 m_processedDirs++;
3077 break;
3078 case R_OVERWRITE_ALL:
3079 m_bOverwriteAll = true;
3080 emit copyingDone( this, ( *it ).uSource, ( *it ).uDest, true /* directory */, false /* renamed */ );
3081 // Move on to next dir
3082 dirs.remove( it );
3083 m_processedDirs++;
3084 break;
3085 default:
3086 assert( 0 );
3087 }
3088 state = STATE_CREATING_DIRS;
3089 //emit processedDirs( this, m_processedDirs );
3090 createNextDir();
3091}
3092
3093void CopyJob::createNextDir()
3094{
3095 KURL udir;
3096 if ( !dirs.isEmpty() )
3097 {
3098 // Take first dir to create out of list
3099 TQValueList<CopyInfo>::Iterator it = dirs.begin();
3100 // Is this URL on the skip list or the overwrite list ?
3101 while( it != dirs.end() && udir.isEmpty() )
3102 {
3103 const TQString dir = (*it).uDest.path();
3104 if ( shouldSkip( dir ) ) {
3105 dirs.remove( it );
3106 it = dirs.begin();
3107 } else
3108 udir = (*it).uDest;
3109 }
3110 }
3111 if ( !udir.isEmpty() ) // any dir to create, finally ?
3112 {
3113 // Create the directory - with default permissions so that we can put files into it
3114 // TODO : change permissions once all is finished; but for stuff coming from CDROM it sucks...
3115 TDEIO::SimpleJob *newjob = TDEIO::mkdir( udir, -1 );
3116 Scheduler::scheduleJob(newjob);
3117
3118 m_currentDestURL = udir;
3119 d->m_bURLDirty = true;
3120
3121 addSubjob(newjob);
3122 return;
3123 }
3124 else // we have finished creating dirs
3125 {
3126 emit processedDirs( this, m_processedDirs ); // make sure final number appears
3127 if (m_progressId) Observer::self()->slotProcessedDirs( this, m_processedDirs );
3128
3129 state = STATE_COPYING_FILES;
3130 m_processedFiles++; // Ralf wants it to start at 1, not 0
3131 copyNextFile();
3132 }
3133}
3134
3135void CopyJob::slotResultCopyingFiles( Job * job )
3136{
3137 // The file we were trying to copy:
3138 TQValueList<CopyInfo>::Iterator it = files.begin();
3139 if ( job->error() )
3140 {
3141 // Should we skip automatically ?
3142 if ( m_bAutoSkip )
3143 {
3144 skip( (*it).uSource );
3145 m_fileProcessedSize = (*it).size;
3146 files.remove( it ); // Move on to next file
3147 }
3148 else
3149 {
3150 if ( !isInteractive() ) {
3151 Job::slotResult( job ); // will set the error and emit result(this)
3152 return;
3153 }
3154
3155 m_conflictError = job->error(); // save for later
3156 // Existing dest ?
3157 if ( ( m_conflictError == ERR_FILE_ALREADY_EXIST )
3158 || ( m_conflictError == ERR_DIR_ALREADY_EXIST )
3159 || ( m_conflictError == ERR_IDENTICAL_FILES ) )
3160 {
3161 subjobs.remove( job );
3162 assert ( subjobs.isEmpty() );
3163 // We need to stat the existing file, to get its last-modification time
3164 KURL existingFile( (*it).uDest );
3165 SimpleJob * newJob = TDEIO::stat( existingFile, false, 2, false );
3166 Scheduler::scheduleJob(newJob);
3167 kdDebug(7007) << "TDEIO::stat for resolving conflict on " << existingFile << endl;
3168 state = STATE_CONFLICT_COPYING_FILES;
3169 addSubjob(newJob);
3170 return; // Don't move to next file yet !
3171 }
3172 else
3173 {
3174 if ( m_bCurrentOperationIsLink && ::tqt_cast<TDEIO::DeleteJob*>( job ) )
3175 {
3176 // Very special case, see a few lines below
3177 // We are deleting the source of a symlink we successfully moved... ignore error
3178 m_fileProcessedSize = (*it).size;
3179 files.remove( it );
3180 } else {
3181 // Go directly to the conflict resolution, there is nothing to stat
3182 slotResultConflictCopyingFiles( job );
3183 return;
3184 }
3185 }
3186 }
3187 } else // no error
3188 {
3189 // Special case for moving links. That operation needs two jobs, unlike others.
3190 if ( m_bCurrentOperationIsLink && m_mode == Move
3191 && !::tqt_cast<TDEIO::DeleteJob *>( job ) // Deleting source not already done
3192 )
3193 {
3194 subjobs.remove( job );
3195 assert ( subjobs.isEmpty() );
3196 // The only problem with this trick is that the error handling for this del operation
3197 // is not going to be right... see 'Very special case' above.
3198 TDEIO::Job * newjob = TDEIO::del( (*it).uSource, false /*don't shred*/, false /*no GUI*/ );
3199 addSubjob( newjob );
3200 return; // Don't move to next file yet !
3201 }
3202
3203 if ( m_bCurrentOperationIsLink )
3204 {
3205 TQString target = ( m_mode == Link ? (*it).uSource.path() : (*it).linkDest );
3206 //required for the undo feature
3207 emit copyingLinkDone( this, (*it).uSource, target, (*it).uDest );
3208 }
3209 else
3210 //required for the undo feature
3211 emit copyingDone( this, (*it).uSource, (*it).uDest, false, false );
3212 // remove from list, to move on to next file
3213 files.remove( it );
3214 }
3215 m_processedFiles++;
3216
3217 // clear processed size for last file and add it to overall processed size
3218 m_processedSize += m_fileProcessedSize;
3219 m_fileProcessedSize = 0;
3220
3221 //kdDebug(7007) << files.count() << " files remaining" << endl;
3222
3223 removeSubjob( job, true, false ); // merge metadata
3224 assert ( subjobs.isEmpty() ); // We should have only one job at a time ...
3225 copyNextFile();
3226}
3227
3228void CopyJob::slotResultConflictCopyingFiles( TDEIO::Job * job )
3229{
3230 // We come here after a conflict has been detected and we've stated the existing file
3231 // The file we were trying to create:
3232 TQValueList<CopyInfo>::Iterator it = files.begin();
3233
3234 RenameDlg_Result res;
3235 TQString newPath;
3236
3237 if (m_reportTimer)
3238 m_reportTimer->stop();
3239
3240 if ( ( m_conflictError == ERR_FILE_ALREADY_EXIST )
3241 || ( m_conflictError == ERR_DIR_ALREADY_EXIST )
3242 || ( m_conflictError == ERR_IDENTICAL_FILES ) )
3243 {
3244 // Its modification time:
3245 time_t destmtime = (time_t)-1;
3246 time_t destctime = (time_t)-1;
3247 TDEIO::filesize_t destsize = 0;
3248 TQString linkDest;
3249 UDSEntry entry = ((TDEIO::StatJob*)job)->statResult();
3250 TDEIO::UDSEntry::ConstIterator it2 = entry.begin();
3251 for( ; it2 != entry.end(); it2++ ) {
3252 switch ((*it2).m_uds) {
3253 case UDS_MODIFICATION_TIME:
3254 destmtime = (time_t)((*it2).m_long);
3255 break;
3256 case UDS_CREATION_TIME:
3257 destctime = (time_t)((*it2).m_long);
3258 break;
3259 case UDS_SIZE:
3260 destsize = (*it2).m_long;
3261 break;
3262 case UDS_LINK_DEST:
3263 linkDest = (*it2).m_str;
3264 break;
3265 }
3266 }
3267
3268 // Offer overwrite only if the existing thing is a file
3269 // If src==dest, use "overwrite-itself"
3270 RenameDlg_Mode mode;
3271 bool isDir = true;
3272
3273 if( m_conflictError == ERR_DIR_ALREADY_EXIST )
3274 mode = (RenameDlg_Mode) 0;
3275 else
3276 {
3277 if ( (*it).uSource == (*it).uDest ||
3278 ((*it).uSource.protocol() == (*it).uDest.protocol() &&
3279 (*it).uSource.path(-1) == linkDest) )
3280 mode = M_OVERWRITE_ITSELF;
3281 else
3282 mode = M_OVERWRITE;
3283 isDir = false;
3284 }
3285
3286 if ( m_bSingleFileCopy )
3287 mode = (RenameDlg_Mode) ( mode | M_SINGLE );
3288 else
3289 mode = (RenameDlg_Mode) ( mode | M_MULTI | M_SKIP );
3290
3291 res = Observer::self()->open_RenameDlg( this, !isDir ?
3292 i18n("File Already Exists") : i18n("Already Exists as Folder"),
3293 (*it).uSource.url(),
3294 (*it).uDest.url(),
3295 mode, newPath,
3296 (*it).size, destsize,
3297 (*it).ctime, destctime,
3298 (*it).mtime, destmtime );
3299
3300 }
3301 else
3302 {
3303 if ( job->error() == ERR_USER_CANCELED )
3304 res = R_CANCEL;
3305 else if ( !isInteractive() ) {
3306 Job::slotResult( job ); // will set the error and emit result(this)
3307 return;
3308 }
3309 else
3310 {
3311 SkipDlg_Result skipResult = Observer::self()->open_SkipDlg( this, files.count() > 1,
3312 job->errorString() );
3313
3314 // Convert the return code from SkipDlg into a RenameDlg code
3315 res = ( skipResult == S_SKIP ) ? R_SKIP :
3316 ( skipResult == S_AUTO_SKIP ) ? R_AUTO_SKIP :
3317 R_CANCEL;
3318 }
3319 }
3320
3321 if (m_reportTimer)
3322 m_reportTimer->start(REPORT_TIMEOUT,false);
3323
3324 subjobs.remove( job );
3325 assert ( subjobs.isEmpty() );
3326 switch ( res ) {
3327 case R_CANCEL:
3328 m_error = ERR_USER_CANCELED;
3329 emitResult();
3330 return;
3331 case R_RENAME:
3332 {
3333 KURL newUrl( (*it).uDest );
3334 newUrl.setPath( newPath );
3335 emit renamed( this, (*it).uDest, newUrl ); // for e.g. kpropsdlg
3336 (*it).uDest = newUrl;
3337
3338 TQValueList<CopyInfo> files;
3339 files.append(*it);
3340 emit aboutToCreate( this, files );
3341 }
3342 break;
3343 case R_AUTO_SKIP:
3344 m_bAutoSkip = true;
3345 // fall through
3346 case R_SKIP:
3347 // Move on to next file
3348 skip( (*it).uSource );
3349 m_processedSize += (*it).size;
3350 files.remove( it );
3351 m_processedFiles++;
3352 break;
3353 case R_OVERWRITE_ALL:
3354 m_bOverwriteAll = true;
3355 break;
3356 case R_OVERWRITE:
3357 // Add to overwrite list, so that copyNextFile knows to overwrite
3358 m_overwriteList.append( (*it).uDest.path() );
3359 break;
3360 default:
3361 assert( 0 );
3362 }
3363 state = STATE_COPYING_FILES;
3364 //emit processedFiles( this, m_processedFiles );
3365 copyNextFile();
3366}
3367
3368void CopyJob::copyNextFile()
3369{
3370 bool bCopyFile = false;
3371 //kdDebug(7007) << "CopyJob::copyNextFile()" << endl;
3372 // Take the first file in the list
3373 TQValueList<CopyInfo>::Iterator it = files.begin();
3374 // Is this URL on the skip list ?
3375 while (it != files.end() && !bCopyFile)
3376 {
3377 const TQString destFile = (*it).uDest.path();
3378 bCopyFile = !shouldSkip( destFile );
3379 if ( !bCopyFile ) {
3380 files.remove( it );
3381 it = files.begin();
3382 }
3383 }
3384
3385 if (bCopyFile) // any file to create, finally ?
3386 {
3387 // Do we set overwrite ?
3388 bool bOverwrite;
3389 const TQString destFile = (*it).uDest.path();
3390 kdDebug(7007) << "copying " << destFile << endl;
3391 if ( (*it).uDest == (*it).uSource )
3392 bOverwrite = false;
3393 else
3394 bOverwrite = shouldOverwrite( destFile );
3395
3396 m_bCurrentOperationIsLink = false;
3397 TDEIO::Job * newjob = 0L;
3398 if ( m_mode == Link )
3399 {
3400 //kdDebug(7007) << "Linking" << endl;
3401 if (
3402 ((*it).uSource.protocol() == (*it).uDest.protocol()) &&
3403 ((*it).uSource.host() == (*it).uDest.host()) &&
3404 ((*it).uSource.port() == (*it).uDest.port()) &&
3405 ((*it).uSource.user() == (*it).uDest.user()) &&
3406 ((*it).uSource.pass() == (*it).uDest.pass()) )
3407 {
3408 // This is the case of creating a real symlink
3409 TDEIO::SimpleJob *newJob = TDEIO::symlink( (*it).uSource.path(), (*it).uDest, bOverwrite, false /*no GUI*/ );
3410 newjob = newJob;
3411 Scheduler::scheduleJob(newJob);
3412 //kdDebug(7007) << "CopyJob::copyNextFile : Linking target=" << (*it).uSource.path() << " link=" << (*it).uDest << endl;
3413 //emit linking( this, (*it).uSource.path(), (*it).uDest );
3414 m_bCurrentOperationIsLink = true;
3415 m_currentSrcURL=(*it).uSource;
3416 m_currentDestURL=(*it).uDest;
3417 d->m_bURLDirty = true;
3418 //Observer::self()->slotCopying( this, (*it).uSource, (*it).uDest ); // should be slotLinking perhaps
3419 } else {
3420 //kdDebug(7007) << "CopyJob::copyNextFile : Linking URL=" << (*it).uSource << " link=" << (*it).uDest << endl;
3421 if ( (*it).uDest.isLocalFile() )
3422 {
3423 bool devicesOk=false;
3424
3425 // if the source is a devices url, handle it a littlebit special
3426 if ((*it).uSource.protocol()==TQString::fromLatin1("devices"))
3427 {
3428 TQByteArray data;
3429 TQByteArray param;
3430 TQCString retType;
3431 TQDataStream streamout(param,IO_WriteOnly);
3432 streamout<<(*it).uSource;
3433 streamout<<(*it).uDest;
3434 if ( tdeApp && tdeApp->dcopClient()->call( "kded",
3435 "mountwatcher", "createLink(KURL, KURL)", param,retType,data,false ) )
3436 {
3437 TQDataStream streamin(data,IO_ReadOnly);
3438 streamin>>devicesOk;
3439 }
3440 if (devicesOk)
3441 {
3442 files.remove( it );
3443 m_processedFiles++;
3444 //emit processedFiles( this, m_processedFiles );
3445 copyNextFile();
3446 return;
3447 }
3448 }
3449
3450 if (!devicesOk)
3451 {
3452 TQString path = (*it).uDest.path();
3453 //kdDebug(7007) << "CopyJob::copyNextFile path=" << path << endl;
3454 TQFile f( path );
3455 if ( f.open( IO_ReadWrite ) )
3456 {
3457 f.close();
3458 KSimpleConfig config( path );
3459 config.setDesktopGroup();
3460 KURL url = (*it).uSource;
3461 url.setPass( "" );
3462 config.writePathEntry( TQString::fromLatin1("URL"), url.url() );
3463 config.writeEntry( TQString::fromLatin1("Name"), url.url() );
3464 config.writeEntry( TQString::fromLatin1("Type"), TQString::fromLatin1("Link") );
3465 TQString protocol = (*it).uSource.protocol();
3466 if ( protocol == TQString::fromLatin1("ftp") )
3467 config.writeEntry( TQString::fromLatin1("Icon"), TQString::fromLatin1("ftp") );
3468 else if ( protocol == TQString::fromLatin1("http") )
3469 config.writeEntry( TQString::fromLatin1("Icon"), TQString::fromLatin1("www") );
3470 else if ( protocol == TQString::fromLatin1("info") )
3471 config.writeEntry( TQString::fromLatin1("Icon"), TQString::fromLatin1("application-vnd.tde.info") );
3472 else if ( protocol == TQString::fromLatin1("mailto") ) // sven:
3473 config.writeEntry( TQString::fromLatin1("Icon"), TQString::fromLatin1("kmail") ); // added mailto: support
3474 else
3475 config.writeEntry( TQString::fromLatin1("Icon"), TQString::fromLatin1("unknown") );
3476 config.sync();
3477 files.remove( it );
3478 m_processedFiles++;
3479 //emit processedFiles( this, m_processedFiles );
3480 copyNextFile();
3481 return;
3482 }
3483 else
3484 {
3485 kdDebug(7007) << "CopyJob::copyNextFile ERR_CANNOT_OPEN_FOR_WRITING" << endl;
3486 m_error = ERR_CANNOT_OPEN_FOR_WRITING;
3487 m_errorText = (*it).uDest.path();
3488 emitResult();
3489 return;
3490 }
3491 }
3492 } else {
3493 // Todo: not show "link" on remote dirs if the src urls are not from the same protocol+host+...
3494 m_error = ERR_CANNOT_SYMLINK;
3495 m_errorText = (*it).uDest.prettyURL();
3496 emitResult();
3497 return;
3498 }
3499 }
3500 }
3501 else if ( !(*it).linkDest.isEmpty() &&
3502 ((*it).uSource.protocol() == (*it).uDest.protocol()) &&
3503 ((*it).uSource.host() == (*it).uDest.host()) &&
3504 ((*it).uSource.port() == (*it).uDest.port()) &&
3505 ((*it).uSource.user() == (*it).uDest.user()) &&
3506 ((*it).uSource.pass() == (*it).uDest.pass()))
3507 // Copying a symlink - only on the same protocol/host/etc. (#5601, downloading an FTP file through its link),
3508 {
3509 TDEIO::SimpleJob *newJob = TDEIO::symlink( (*it).linkDest, (*it).uDest, bOverwrite, false /*no GUI*/ );
3510 Scheduler::scheduleJob(newJob);
3511 newjob = newJob;
3512 //kdDebug(7007) << "CopyJob::copyNextFile : Linking target=" << (*it).linkDest << " link=" << (*it).uDest << endl;
3513 //emit linking( this, (*it).linkDest, (*it).uDest );
3514 m_currentSrcURL=(*it).linkDest;
3515 m_currentDestURL=(*it).uDest;
3516 d->m_bURLDirty = true;
3517 //Observer::self()->slotCopying( this, (*it).linkDest, (*it).uDest ); // should be slotLinking perhaps
3518 m_bCurrentOperationIsLink = true;
3519 // NOTE: if we are moving stuff, the deletion of the source will be done in slotResultCopyingFiles
3520 } else if (m_mode == Move) // Moving a file
3521 {
3522 TDEIO::FileCopyJob * moveJob = TDEIO::file_move( (*it).uSource, (*it).uDest, (*it).permissions, bOverwrite, false, false/*no GUI*/ );
3523 moveJob->setSourceSize64( (*it).size );
3524 newjob = moveJob;
3525 //kdDebug(7007) << "CopyJob::copyNextFile : Moving " << (*it).uSource << " to " << (*it).uDest << endl;
3526 //emit moving( this, (*it).uSource, (*it).uDest );
3527 m_currentSrcURL=(*it).uSource;
3528 m_currentDestURL=(*it).uDest;
3529 d->m_bURLDirty = true;
3530 //Observer::self()->slotMoving( this, (*it).uSource, (*it).uDest );
3531 }
3532 else // Copying a file
3533 {
3534 // If source isn't local and target is local, we ignore the original permissions
3535 // Otherwise, files downloaded from HTTP end up with -r--r--r--
3536 bool remoteSource = !KProtocolInfo::supportsListing((*it).uSource);
3537 int permissions = (*it).permissions;
3538 if ( d->m_defaultPermissions || ( remoteSource && (*it).uDest.isLocalFile() ) )
3539 permissions = -1;
3540 TDEIO::FileCopyJob * copyJob = TDEIO::file_copy( (*it).uSource, (*it).uDest, permissions, bOverwrite, false, false/*no GUI*/ );
3541 copyJob->setParentJob( this ); // in case of rename dialog
3542 copyJob->setSourceSize64( (*it).size );
3543 copyJob->setModificationTime( (*it).mtime );
3544 newjob = copyJob;
3545 //kdDebug(7007) << "CopyJob::copyNextFile : Copying " << (*it).uSource << " to " << (*it).uDest << endl;
3546 m_currentSrcURL=(*it).uSource;
3547 m_currentDestURL=(*it).uDest;
3548 d->m_bURLDirty = true;
3549 }
3550 addSubjob(newjob);
3551 connect( newjob, TQ_SIGNAL( processedSize( TDEIO::Job*, TDEIO::filesize_t ) ),
3552 this, TQ_SLOT( slotProcessedSize( TDEIO::Job*, TDEIO::filesize_t ) ) );
3553 connect( newjob, TQ_SIGNAL( totalSize( TDEIO::Job*, TDEIO::filesize_t ) ),
3554 this, TQ_SLOT( slotTotalSize( TDEIO::Job*, TDEIO::filesize_t ) ) );
3555 }
3556 else
3557 {
3558 // We're done
3559 //kdDebug(7007) << "copyNextFile finished" << endl;
3560 deleteNextDir();
3561 }
3562}
3563
3564void CopyJob::deleteNextDir()
3565{
3566 if ( m_mode == Move && !dirsToRemove.isEmpty() ) // some dirs to delete ?
3567 {
3568 state = STATE_DELETING_DIRS;
3569 d->m_bURLDirty = true;
3570 // Take first dir to delete out of list - last ones first !
3571 KURL::List::Iterator it = dirsToRemove.fromLast();
3572 SimpleJob *job = TDEIO::rmdir( *it );
3573 Scheduler::scheduleJob(job);
3574 dirsToRemove.remove(it);
3575 addSubjob( job );
3576 }
3577 else
3578 {
3579 // This step is done, move on
3580 setNextDirAttribute();
3581 }
3582}
3583
3584void CopyJob::setNextDirAttribute()
3585{
3586 if ( !d->m_directoriesCopied.isEmpty() )
3587 {
3588 state = STATE_SETTING_DIR_ATTRIBUTES;
3589#ifdef Q_OS_UNIX
3590 // TODO KDE4: this should use a SlaveBase method, but we have none yet in KDE3.
3591 TQValueList<CopyInfo>::Iterator it = d->m_directoriesCopied.begin();
3592 for ( ; it != d->m_directoriesCopied.end() ; ++it ) {
3593 const KURL& url = (*it).uDest;
3594 if ( url.isLocalFile() && (*it).mtime != (time_t)-1 ) {
3595 const TQCString path = TQFile::encodeName( url.path() );
3596 KDE_struct_stat statbuf;
3597 if (KDE_lstat(path, &statbuf) == 0) {
3598 struct utimbuf utbuf;
3599 utbuf.actime = statbuf.st_atime; // access time, unchanged
3600 utbuf.modtime = (*it).mtime; // modification time
3601 utime( path, &utbuf );
3602 }
3603
3604 }
3605 }
3606#endif
3607 d->m_directoriesCopied.clear();
3608 }
3609
3610 // No "else" here, since the above is a simple sync loop
3611
3612 {
3613 // Finished - tell the world
3614 if ( !m_bOnlyRenames )
3615 {
3616 KDirNotify_stub allDirNotify("*", "KDirNotify*");
3617 KURL url( d->m_globalDest );
3618 if ( d->m_globalDestinationState != DEST_IS_DIR || m_asMethod )
3619 url.setPath( url.directory() );
3620 //kdDebug(7007) << "KDirNotify'ing FilesAdded " << url << endl;
3621 allDirNotify.FilesAdded( url );
3622
3623 if ( m_mode == Move && !m_srcList.isEmpty() ) {
3624 //kdDebug(7007) << "KDirNotify'ing FilesRemoved " << m_srcList.toStringList() << endl;
3625 allDirNotify.FilesRemoved( m_srcList );
3626 }
3627 }
3628 if (m_reportTimer)
3629 m_reportTimer->stop();
3630 --m_processedFiles; // undo the "start at 1" hack
3631 slotReport(); // display final numbers, important if progress dialog stays up
3632
3633 emitResult();
3634 }
3635}
3636
3637void CopyJob::slotProcessedSize( TDEIO::Job*, TDEIO::filesize_t data_size )
3638{
3639 //kdDebug(7007) << "CopyJob::slotProcessedSize " << data_size << endl;
3640 m_fileProcessedSize = data_size;
3641 setProcessedSize(m_processedSize + m_fileProcessedSize);
3642
3643 if ( m_processedSize + m_fileProcessedSize > m_totalSize )
3644 {
3645 m_totalSize = m_processedSize + m_fileProcessedSize;
3646 //kdDebug(7007) << "Adjusting m_totalSize to " << m_totalSize << endl;
3647 emit totalSize( this, m_totalSize ); // safety
3648 }
3649 //kdDebug(7007) << "emit processedSize " << (unsigned long) (m_processedSize + m_fileProcessedSize) << endl;
3650 emit processedSize( this, m_processedSize + m_fileProcessedSize );
3651 emitPercent( m_processedSize + m_fileProcessedSize, m_totalSize );
3652}
3653
3654void CopyJob::slotTotalSize( TDEIO::Job*, TDEIO::filesize_t size )
3655{
3656 //kdDebug(7007) << "slotTotalSize: " << size << endl;
3657 // Special case for copying a single file
3658 // This is because some protocols don't implement stat properly
3659 // (e.g. HTTP), and don't give us a size in some cases (redirection)
3660 // so we'd rather rely on the size given for the transfer
3661 if ( m_bSingleFileCopy && size > m_totalSize)
3662 {
3663 //kdDebug(7007) << "slotTotalSize: updating totalsize to " << size << endl;
3664 m_totalSize = size;
3665 emit totalSize( this, size );
3666 }
3667}
3668
3669void CopyJob::slotResultDeletingDirs( Job * job )
3670{
3671 if (job->error())
3672 {
3673 // Couldn't remove directory. Well, perhaps it's not empty
3674 // because the user pressed Skip for a given file in it.
3675 // Let's not display "Could not remove dir ..." for each of those dir !
3676 }
3677 subjobs.remove( job );
3678 assert ( subjobs.isEmpty() );
3679 deleteNextDir();
3680}
3681
3682#if 0 // TODO KDE4
3683void CopyJob::slotResultSettingDirAttributes( Job * job )
3684{
3685 if (job->error())
3686 {
3687 // Couldn't set directory attributes. Ignore the error, it can happen
3688 // with inferior file systems like VFAT.
3689 // Let's not display warnings for each dir like "cp -a" does.
3690 }
3691 subjobs.remove( job );
3692 assert ( subjobs.isEmpty() );
3693 setNextDirAttribute();
3694}
3695#endif
3696
3697void CopyJob::slotResultRenaming( Job* job )
3698{
3699 int err = job->error();
3700 const TQString errText = job->errorText();
3701 removeSubjob( job, true, false ); // merge metadata
3702 assert ( subjobs.isEmpty() );
3703 // Determine dest again
3704 KURL dest = m_dest;
3705 if ( destinationState == DEST_IS_DIR && !m_asMethod )
3706 dest.addPath( m_currentSrcURL.fileName() );
3707 if ( err )
3708 {
3709 // Direct renaming didn't work. Try renaming to a temp name,
3710 // this can help e.g. when renaming 'a' to 'A' on a VFAT partition.
3711 // In that case it's the _same_ dir, we don't want to copy+del (data loss!)
3712 if ( m_currentSrcURL.isLocalFile() && m_currentSrcURL.url(-1) != dest.url(-1) &&
3713 m_currentSrcURL.url(-1).lower() == dest.url(-1).lower() &&
3714 ( err == ERR_FILE_ALREADY_EXIST ||
3715 err == ERR_DIR_ALREADY_EXIST ||
3716 err == ERR_IDENTICAL_FILES ) )
3717 {
3718 kdDebug(7007) << "Couldn't rename directly, dest already exists. Detected special case of lower/uppercase renaming in same dir, try with 2 rename calls" << endl;
3719 TQCString _src( TQFile::encodeName(m_currentSrcURL.path()) );
3720 TQCString _dest( TQFile::encodeName(dest.path()) );
3721 KTempFile tmpFile( m_currentSrcURL.directory(false) );
3722 TQCString _tmp( TQFile::encodeName(tmpFile.name()) );
3723 kdDebug(7007) << "CopyJob::slotResult KTempFile status:" << tmpFile.status() << " using " << _tmp << " as intermediary" << endl;
3724 tmpFile.unlink();
3725 if ( ::rename( _src, _tmp ) == 0 )
3726 {
3727 if ( !TQFile::exists( _dest ) && ::rename( _tmp, _dest ) == 0 )
3728 {
3729 kdDebug(7007) << "Success." << endl;
3730 err = 0;
3731 }
3732 else
3733 {
3734 // Revert back to original name!
3735 if ( ::rename( _tmp, _src ) != 0 ) {
3736 kdError(7007) << "Couldn't rename " << tmpFile.name() << " back to " << _src << " !" << endl;
3737 // Severe error, abort
3738 Job::slotResult( job ); // will set the error and emit result(this)
3739 return;
3740 }
3741 }
3742 }
3743 }
3744 }
3745 if ( err )
3746 {
3747 // This code is similar to CopyJob::slotResultConflictCopyingFiles
3748 // but here it's about the base src url being moved/renamed
3749 // (*m_currentStatSrc) and its dest (m_dest), not about a single file.
3750 // It also means we already stated the dest, here.
3751 // On the other hand we haven't stated the src yet (we skipped doing it
3752 // to save time, since it's not necessary to rename directly!)...
3753
3754 Q_ASSERT( m_currentSrcURL == *m_currentStatSrc );
3755
3756 // Existing dest?
3757 if ( ( err == ERR_DIR_ALREADY_EXIST ||
3758 err == ERR_FILE_ALREADY_EXIST ||
3759 err == ERR_IDENTICAL_FILES )
3760 && isInteractive() )
3761 {
3762 if (m_reportTimer)
3763 m_reportTimer->stop();
3764
3765 // Should we skip automatically ?
3766 if ( m_bAutoSkip ) {
3767 // Move on to next file
3768 skipSrc();
3769 return;
3770 } else if ( m_bOverwriteAll ) {
3771 ; // nothing to do, stat+copy+del will overwrite
3772 } else {
3773 TQString newPath;
3774 // If src==dest, use "overwrite-itself"
3775 RenameDlg_Mode mode = (RenameDlg_Mode)
3776 ( ( m_currentSrcURL == dest ) ? M_OVERWRITE_ITSELF : M_OVERWRITE );
3777
3778 if ( m_srcList.count() > 1 )
3779 mode = (RenameDlg_Mode) ( mode | M_MULTI | M_SKIP );
3780 else
3781 mode = (RenameDlg_Mode) ( mode | M_SINGLE );
3782
3783 // we lack mtime info for both the src (not stated)
3784 // and the dest (stated but this info wasn't stored)
3785 // Let's do it for local files, at least
3786 TDEIO::filesize_t sizeSrc = (TDEIO::filesize_t) -1;
3787 TDEIO::filesize_t sizeDest = (TDEIO::filesize_t) -1;
3788 time_t ctimeSrc = (time_t) -1;
3789 time_t ctimeDest = (time_t) -1;
3790 time_t mtimeSrc = (time_t) -1;
3791 time_t mtimeDest = (time_t) -1;
3792
3793 KDE_struct_stat stat_buf;
3794 if ( m_currentSrcURL.isLocalFile() &&
3795 KDE_stat(TQFile::encodeName(m_currentSrcURL.path()), &stat_buf) == 0 ) {
3796 sizeSrc = stat_buf.st_size;
3797 ctimeSrc = stat_buf.st_ctime;
3798 mtimeSrc = stat_buf.st_mtime;
3799 }
3800 if ( dest.isLocalFile() &&
3801 KDE_stat(TQFile::encodeName(dest.path()), &stat_buf) == 0 ) {
3802 sizeDest = stat_buf.st_size;
3803 ctimeDest = stat_buf.st_ctime;
3804 mtimeDest = stat_buf.st_mtime;
3805 }
3806
3807 RenameDlg_Result r = Observer::self()->open_RenameDlg(
3808 this,
3809 err != ERR_DIR_ALREADY_EXIST ? i18n("File Already Exists") : i18n("Already Exists as Folder"),
3810 m_currentSrcURL.url(),
3811 dest.url(),
3812 mode, newPath,
3813 sizeSrc, sizeDest,
3814 ctimeSrc, ctimeDest,
3815 mtimeSrc, mtimeDest );
3816 if (m_reportTimer)
3817 m_reportTimer->start(REPORT_TIMEOUT,false);
3818
3819 switch ( r )
3820 {
3821 case R_CANCEL:
3822 {
3823 m_error = ERR_USER_CANCELED;
3824 emitResult();
3825 return;
3826 }
3827 case R_RENAME:
3828 {
3829 // Set m_dest to the chosen destination
3830 // This is only for this src url; the next one will revert to d->m_globalDest
3831 m_dest.setPath( newPath );
3832 TDEIO::Job* job = TDEIO::stat( m_dest, false, 2, false );
3833 state = STATE_STATING;
3834 destinationState = DEST_NOT_STATED;
3835 addSubjob(job);
3836 return;
3837 }
3838 case R_AUTO_SKIP:
3839 m_bAutoSkip = true;
3840 // fall through
3841 case R_SKIP:
3842 // Move on to next file
3843 skipSrc();
3844 return;
3845 case R_OVERWRITE_ALL:
3846 m_bOverwriteAll = true;
3847 break;
3848 case R_OVERWRITE:
3849 // Add to overwrite list
3850 // Note that we add dest, not m_dest.
3851 // This ensures that when moving several urls into a dir (m_dest),
3852 // we only overwrite for the current one, not for all.
3853 // When renaming a single file (m_asMethod), it makes no difference.
3854 kdDebug(7007) << "adding to overwrite list: " << dest.path() << endl;
3855 m_overwriteList.append( dest.path() );
3856 break;
3857 default:
3858 //assert( 0 );
3859 break;
3860 }
3861 }
3862 } else if ( err != TDEIO::ERR_UNSUPPORTED_ACTION ) {
3863 kdDebug(7007) << "Couldn't rename " << m_currentSrcURL << " to " << dest << ", aborting" << endl;
3864 m_error = err;
3865 m_errorText = errText;
3866 emitResult();
3867 return;
3868 }
3869 kdDebug(7007) << "Couldn't rename " << m_currentSrcURL << " to " << dest << ", reverting to normal way, starting with stat" << endl;
3870 //kdDebug(7007) << "TDEIO::stat on " << m_currentSrcURL << endl;
3871 TDEIO::Job* job = TDEIO::stat( m_currentSrcURL, true, 2, false );
3872 state = STATE_STATING;
3873 addSubjob(job);
3874 m_bOnlyRenames = false;
3875 }
3876 else
3877 {
3878 //kdDebug(7007) << "Renaming succeeded, move on" << endl;
3879 emit copyingDone( this, *m_currentStatSrc, dest, true, true );
3880 statNextSrc();
3881 }
3882}
3883
3884void CopyJob::slotResult( Job *job )
3885{
3886 //kdDebug(7007) << "CopyJob::slotResult() state=" << (int) state << endl;
3887 // In each case, what we have to do is :
3888 // 1 - check for errors and treat them
3889 // 2 - subjobs.remove(job);
3890 // 3 - decide what to do next
3891
3892 switch ( state ) {
3893 case STATE_STATING: // We were trying to stat a src url or the dest
3894 slotResultStating( job );
3895 break;
3896 case STATE_RENAMING: // We were trying to do a direct renaming, before even stat'ing
3897 {
3898 slotResultRenaming( job );
3899 break;
3900 }
3901 case STATE_LISTING: // recursive listing finished
3902 //kdDebug(7007) << "totalSize: " << (unsigned int) m_totalSize << " files: " << files.count() << " dirs: " << dirs.count() << endl;
3903 // Was there an error ?
3904 if (job->error())
3905 {
3906 Job::slotResult( job ); // will set the error and emit result(this)
3907 return;
3908 }
3909
3910 subjobs.remove( job );
3911 assert ( subjobs.isEmpty() );
3912
3913 statNextSrc();
3914 break;
3915 case STATE_CREATING_DIRS:
3916 slotResultCreatingDirs( job );
3917 break;
3918 case STATE_CONFLICT_CREATING_DIRS:
3919 slotResultConflictCreatingDirs( job );
3920 break;
3921 case STATE_COPYING_FILES:
3922 slotResultCopyingFiles( job );
3923 break;
3924 case STATE_CONFLICT_COPYING_FILES:
3925 slotResultConflictCopyingFiles( job );
3926 break;
3927 case STATE_DELETING_DIRS:
3928 slotResultDeletingDirs( job );
3929 break;
3930 case STATE_SETTING_DIR_ATTRIBUTES: // TODO KDE4
3931 assert( 0 );
3932 //slotResultSettingDirAttributes( job );
3933 break;
3934 default:
3935 assert( 0 );
3936 }
3937}
3938
3939void TDEIO::CopyJob::setDefaultPermissions( bool b )
3940{
3941 d->m_defaultPermissions = b;
3942}
3943
3944// KDE4: remove
3945void TDEIO::CopyJob::setInteractive( bool b )
3946{
3947 Job::setInteractive( b );
3948}
3949
3950CopyJob *TDEIO::copy(const KURL& src, const KURL& dest, bool showProgressInfo )
3951{
3952 //kdDebug(7007) << "TDEIO::copy src=" << src << " dest=" << dest << endl;
3953 KURL::List srcList;
3954 srcList.append( src );
3955 return new CopyJob( srcList, dest, CopyJob::Copy, false, showProgressInfo );
3956}
3957
3958CopyJob *TDEIO::copyAs(const KURL& src, const KURL& dest, bool showProgressInfo )
3959{
3960 //kdDebug(7007) << "TDEIO::copyAs src=" << src << " dest=" << dest << endl;
3961 KURL::List srcList;
3962 srcList.append( src );
3963 return new CopyJob( srcList, dest, CopyJob::Copy, true, showProgressInfo );
3964}
3965
3966CopyJob *TDEIO::copy( const KURL::List& src, const KURL& dest, bool showProgressInfo )
3967{
3968 //kdDebug(7007) << src << " " << dest << endl;
3969 return new CopyJob( src, dest, CopyJob::Copy, false, showProgressInfo );
3970}
3971
3972CopyJob *TDEIO::move(const KURL& src, const KURL& dest, bool showProgressInfo )
3973{
3974 //kdDebug(7007) << src << " " << dest << endl;
3975 KURL::List srcList;
3976 srcList.append( src );
3977 return new CopyJob( srcList, dest, CopyJob::Move, false, showProgressInfo );
3978}
3979
3980CopyJob *TDEIO::moveAs(const KURL& src, const KURL& dest, bool showProgressInfo )
3981{
3982 //kdDebug(7007) << src << " " << dest << endl;
3983 KURL::List srcList;
3984 srcList.append( src );
3985 return new CopyJob( srcList, dest, CopyJob::Move, true, showProgressInfo );
3986}
3987
3988CopyJob *TDEIO::move( const KURL::List& src, const KURL& dest, bool showProgressInfo )
3989{
3990 //kdDebug(7007) << src << " " << dest << endl;
3991 return new CopyJob( src, dest, CopyJob::Move, false, showProgressInfo );
3992}
3993
3994CopyJob *TDEIO::link(const KURL& src, const KURL& destDir, bool showProgressInfo )
3995{
3996 KURL::List srcList;
3997 srcList.append( src );
3998 return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
3999}
4000
4001CopyJob *TDEIO::link(const KURL::List& srcList, const KURL& destDir, bool showProgressInfo )
4002{
4003 return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
4004}
4005
4006CopyJob *TDEIO::linkAs(const KURL& src, const KURL& destDir, bool showProgressInfo )
4007{
4008 KURL::List srcList;
4009 srcList.append( src );
4010 return new CopyJob( srcList, destDir, CopyJob::Link, false, showProgressInfo );
4011}
4012
4013CopyJob *TDEIO::trash(const KURL& src, bool showProgressInfo )
4014{
4015 KURL::List srcList;
4016 srcList.append( src );
4017 return new CopyJob( srcList, KURL( "trash:/" ), CopyJob::Move, false, showProgressInfo );
4018}
4019
4020CopyJob *TDEIO::trash(const KURL::List& srcList, bool showProgressInfo )
4021{
4022 return new CopyJob( srcList, KURL( "trash:/" ), CopyJob::Move, false, showProgressInfo );
4023}
4024
4026
4027DeleteJob::DeleteJob( const KURL::List& src, bool /*shred*/, bool showProgressInfo )
4028: Job(showProgressInfo), m_totalSize( 0 ), m_processedSize( 0 ), m_fileProcessedSize( 0 ),
4029 m_processedFiles( 0 ), m_processedDirs( 0 ), m_totalFilesDirs( 0 ),
4030 m_srcList(src), m_currentStat(m_srcList.begin()), m_reportTimer(0)
4031{
4032 if ( showProgressInfo ) {
4033
4034 connect( this, TQ_SIGNAL( totalFiles( TDEIO::Job*, unsigned long ) ),
4035 Observer::self(), TQ_SLOT( slotTotalFiles( TDEIO::Job*, unsigned long ) ) );
4036
4037 connect( this, TQ_SIGNAL( totalDirs( TDEIO::Job*, unsigned long ) ),
4038 Observer::self(), TQ_SLOT( slotTotalDirs( TDEIO::Job*, unsigned long ) ) );
4039
4040 // See slotReport
4041 /*connect( this, TQ_SIGNAL( processedFiles( TDEIO::Job*, unsigned long ) ),
4042 m_observer, TQ_SLOT( slotProcessedFiles( TDEIO::Job*, unsigned long ) ) );
4043
4044 connect( this, TQ_SIGNAL( processedDirs( TDEIO::Job*, unsigned long ) ),
4045 m_observer, TQ_SLOT( slotProcessedDirs( TDEIO::Job*, unsigned long ) ) );
4046
4047 connect( this, TQ_SIGNAL( deleting( TDEIO::Job*, const KURL& ) ),
4048 m_observer, TQ_SLOT( slotDeleting( TDEIO::Job*, const KURL& ) ) );*/
4049
4050 m_reportTimer=new TQTimer(this);
4051 connect(m_reportTimer,TQ_SIGNAL(timeout()),this,TQ_SLOT(slotReport()));
4052 //this will update the report dialog with 5 Hz, I think this is fast enough, aleXXX
4053 m_reportTimer->start(REPORT_TIMEOUT,false);
4054 }
4055
4056 TQTimer::singleShot(0, this, TQ_SLOT(slotStart()));
4057}
4058
4059void DeleteJob::slotStart()
4060{
4061 statNextSrc();
4062}
4063
4064//this is called often, so calling the functions
4065//from Observer here directly might improve the performance a little bit
4066//aleXXX
4067void DeleteJob::slotReport()
4068{
4069 if (m_progressId==0)
4070 return;
4071
4072 Observer * observer = Observer::self();
4073
4074 emit deleting( this, m_currentURL );
4075 observer->slotDeleting(this,m_currentURL);
4076
4077 switch( state ) {
4078 case STATE_STATING:
4079 case STATE_LISTING:
4080 emit totalSize( this, m_totalSize );
4081 emit totalFiles( this, files.count() );
4082 emit totalDirs( this, dirs.count() );
4083 break;
4084 case STATE_DELETING_DIRS:
4085 emit processedDirs( this, m_processedDirs );
4086 observer->slotProcessedDirs(this,m_processedDirs);
4087 emitPercent( m_processedFiles + m_processedDirs, m_totalFilesDirs );
4088 break;
4089 case STATE_DELETING_FILES:
4090 observer->slotProcessedFiles(this,m_processedFiles);
4091 emit processedFiles( this, m_processedFiles );
4092 emitPercent( m_processedFiles, m_totalFilesDirs );
4093 break;
4094 }
4095}
4096
4097
4098void DeleteJob::slotEntries(TDEIO::Job* job, const UDSEntryList& list)
4099{
4100 UDSEntryListConstIterator it = list.begin();
4101 UDSEntryListConstIterator end = list.end();
4102 for (; it != end; ++it)
4103 {
4104 UDSEntry::ConstIterator it2 = (*it).begin();
4105 bool bDir = false;
4106 bool bLink = false;
4107 TQString displayName;
4108 KURL url;
4109 int atomsFound(0);
4110 for( ; it2 != (*it).end(); it2++ )
4111 {
4112 switch ((*it2).m_uds)
4113 {
4114 case UDS_FILE_TYPE:
4115 bDir = S_ISDIR((*it2).m_long);
4116 atomsFound++;
4117 break;
4118 case UDS_NAME:
4119 displayName = (*it2).m_str;
4120 atomsFound++;
4121 break;
4122 case UDS_URL:
4123 url = KURL((*it2).m_str);
4124 atomsFound++;
4125 break;
4126 case UDS_LINK_DEST:
4127 bLink = !(*it2).m_str.isEmpty();
4128 atomsFound++;
4129 break;
4130 case UDS_SIZE:
4131 m_totalSize += (TDEIO::filesize_t)((*it2).m_long);
4132 atomsFound++;
4133 break;
4134 default:
4135 break;
4136 }
4137 if (atomsFound==5) break;
4138 }
4139 assert(!displayName.isEmpty());
4140 if (displayName != ".." && displayName != ".")
4141 {
4142 if( url.isEmpty() ) {
4143 url = ((SimpleJob *)job)->url(); // assumed to be a dir
4144 url.addPath( displayName );
4145 }
4146 //kdDebug(7007) << "DeleteJob::slotEntries " << displayName << " (" << url << ")" << endl;
4147 if ( bLink )
4148 symlinks.append( url );
4149 else if ( bDir )
4150 dirs.append( url );
4151 else
4152 files.append( url );
4153 }
4154 }
4155}
4156
4157
4158void DeleteJob::statNextSrc()
4159{
4160 //kdDebug(7007) << "statNextSrc" << endl;
4161 if ( m_currentStat != m_srcList.end() )
4162 {
4163 m_currentURL = (*m_currentStat);
4164
4165 // if the file system doesn't support deleting, we do not even stat
4166 if (!KProtocolInfo::supportsDeleting(m_currentURL)) {
4167 TQGuardedPtr<DeleteJob> that = this;
4168 ++m_currentStat;
4169 if (isInteractive())
4170 KMessageBox::information( 0, buildErrorString(ERR_CANNOT_DELETE, m_currentURL.prettyURL()));
4171 if (that)
4172 statNextSrc();
4173 return;
4174 }
4175 // Stat it
4176 state = STATE_STATING;
4177 TDEIO::SimpleJob * job = TDEIO::stat( m_currentURL, true, 1, false );
4178 Scheduler::scheduleJob(job);
4179 //kdDebug(7007) << "TDEIO::stat (DeleteJob) " << m_currentURL << endl;
4180 addSubjob(job);
4181 //if ( m_progressId ) // Did we get an ID from the observer ?
4182 // Observer::self()->slotDeleting( this, *it ); // show asap
4183 } else
4184 {
4185 m_totalFilesDirs = files.count()+symlinks.count() + dirs.count();
4186 slotReport();
4187 // Now we know which dirs hold the files we're going to delete.
4188 // To speed things up and prevent double-notification, we disable KDirWatch
4189 // on those dirs temporarily (using KDirWatch::self, that's the instanced
4190 // used by e.g. kdirlister).
4191 for ( TQStringList::Iterator it = m_parentDirs.begin() ; it != m_parentDirs.end() ; ++it )
4192 KDirWatch::self()->stopDirScan( *it );
4193 state = STATE_DELETING_FILES;
4194 deleteNextFile();
4195 }
4196}
4197
4198void DeleteJob::deleteNextFile()
4199{
4200 //kdDebug(7007) << "deleteNextFile" << endl;
4201 if ( !files.isEmpty() || !symlinks.isEmpty() )
4202 {
4203 SimpleJob *job;
4204 do {
4205 // Take first file to delete out of list
4206 KURL::List::Iterator it = files.begin();
4207 bool isLink = false;
4208 if ( it == files.end() ) // No more files
4209 {
4210 it = symlinks.begin(); // Pick up a symlink to delete
4211 isLink = true;
4212 }
4213 // Normal deletion
4214 // If local file, try do it directly
4215 if ( (*it).isLocalFile() && unlink( TQFile::encodeName((*it).path()) ) == 0 ) {
4216 //kdDebug(7007) << "DeleteJob deleted " << (*it).path() << endl;
4217 job = 0;
4218 m_processedFiles++;
4219 if ( m_processedFiles % 300 == 0 || m_totalFilesDirs < 300) { // update progress info every 300 files
4220 m_currentURL = *it;
4221 slotReport();
4222 }
4223 } else
4224 { // if remote - or if unlink() failed (we'll use the job's error handling in that case)
4225 job = TDEIO::file_delete( *it, false /*no GUI*/);
4226 Scheduler::scheduleJob(job);
4227 m_currentURL=(*it);
4228 }
4229 if ( isLink )
4230 symlinks.remove(it);
4231 else
4232 files.remove(it);
4233 if ( job ) {
4234 addSubjob(job);
4235 return;
4236 }
4237 // loop only if direct deletion worked (job=0) and there is something else to delete
4238 } while (!job && (!files.isEmpty() || !symlinks.isEmpty()));
4239 }
4240 state = STATE_DELETING_DIRS;
4241 deleteNextDir();
4242}
4243
4244void DeleteJob::deleteNextDir()
4245{
4246 if ( !dirs.isEmpty() ) // some dirs to delete ?
4247 {
4248 do {
4249 // Take first dir to delete out of list - last ones first !
4250 KURL::List::Iterator it = dirs.fromLast();
4251 // If local dir, try to rmdir it directly
4252 if ( (*it).isLocalFile() && ::rmdir( TQFile::encodeName((*it).path()) ) == 0 ) {
4253
4254 m_processedDirs++;
4255 if ( m_processedDirs % 100 == 0 ) { // update progress info every 100 dirs
4256 m_currentURL = *it;
4257 slotReport();
4258 }
4259 } else {
4260 SimpleJob* job;
4261 if ( KProtocolInfo::canDeleteRecursive( *it ) ) {
4262 // If the ioslave supports recursive deletion of a directory, then
4263 // we only need to send a single CMD_DEL command, so we use file_delete :)
4264 job = TDEIO::file_delete( *it, false /*no gui*/ );
4265 } else {
4266 job = TDEIO::rmdir( *it );
4267 }
4268 Scheduler::scheduleJob(job);
4269 dirs.remove(it);
4270 addSubjob( job );
4271 return;
4272 }
4273 dirs.remove(it);
4274 } while ( !dirs.isEmpty() );
4275 }
4276
4277 // Re-enable watching on the dirs that held the deleted files
4278 for ( TQStringList::Iterator it = m_parentDirs.begin() ; it != m_parentDirs.end() ; ++it )
4279 KDirWatch::self()->restartDirScan( *it );
4280
4281 // Finished - tell the world
4282 if ( !m_srcList.isEmpty() )
4283 {
4284 KDirNotify_stub allDirNotify("*", "KDirNotify*");
4285 //kdDebug(7007) << "KDirNotify'ing FilesRemoved " << m_srcList.toStringList() << endl;
4286 allDirNotify.FilesRemoved( m_srcList );
4287 }
4288 if (m_reportTimer!=0)
4289 m_reportTimer->stop();
4290 emitResult();
4291}
4292
4293void DeleteJob::slotProcessedSize( TDEIO::Job*, TDEIO::filesize_t data_size )
4294{
4295 // Note: this is the same implementation as CopyJob::slotProcessedSize but
4296 // it's different from FileCopyJob::slotProcessedSize - which is why this
4297 // is not in Job.
4298
4299 m_fileProcessedSize = data_size;
4300 setProcessedSize(m_processedSize + m_fileProcessedSize);
4301
4302 //kdDebug(7007) << "DeleteJob::slotProcessedSize " << (unsigned int) (m_processedSize + m_fileProcessedSize) << endl;
4303
4304 emit processedSize( this, m_processedSize + m_fileProcessedSize );
4305
4306 // calculate percents
4307 unsigned long ipercent = m_percent;
4308
4309 if ( m_totalSize == 0 )
4310 m_percent = 100;
4311 else
4312 m_percent = (unsigned long)(( (float)(m_processedSize + m_fileProcessedSize) / (float)m_totalSize ) * 100.0);
4313
4314 if ( m_percent > ipercent )
4315 {
4316 emit percent( this, m_percent );
4317 //kdDebug(7007) << "DeleteJob::slotProcessedSize - percent = " << (unsigned int) m_percent << endl;
4318 }
4319
4320}
4321
4322void DeleteJob::slotResult( Job *job )
4323{
4324 switch ( state )
4325 {
4326 case STATE_STATING:
4327 {
4328 // Was there an error while stating ?
4329 if (job->error() )
4330 {
4331 // Probably : doesn't exist
4332 Job::slotResult( job ); // will set the error and emit result(this)
4333 return;
4334 }
4335
4336 // Is it a file or a dir ?
4337 UDSEntry entry = ((StatJob*)job)->statResult();
4338 bool bDir = false;
4339 bool bLink = false;
4340// TDEIO::filesize_t size = (TDEIO::filesize_t)-1;
4341 UDSEntry::ConstIterator it2 = entry.begin();
4342 int atomsFound(0);
4343 for( ; it2 != entry.end(); it2++ )
4344 {
4345 if ( ((*it2).m_uds) == UDS_FILE_TYPE )
4346 {
4347 bDir = S_ISDIR( (mode_t)(*it2).m_long );
4348 atomsFound++;
4349 }
4350 else if ( ((*it2).m_uds) == UDS_LINK_DEST )
4351 {
4352 bLink = !((*it2).m_str.isEmpty());
4353 atomsFound++;
4354 }
4355 else if ( ((*it2).m_uds) == UDS_SIZE )
4356 {
4357// size = (*it2).m_long;
4358 atomsFound++;
4359 }
4360 if (atomsFound==3) break;
4361 }
4362
4363 KURL url = ((SimpleJob*)job)->url();
4364
4365 subjobs.remove( job );
4366 assert( subjobs.isEmpty() );
4367
4368 if (bDir && !bLink)
4369 {
4370 // Add toplevel dir in list of dirs
4371 dirs.append( url );
4372 if ( url.isLocalFile() && !m_parentDirs.contains( url.path(-1) ) )
4373 m_parentDirs.append( url.path(-1) );
4374
4375 if ( !KProtocolInfo::canDeleteRecursive( url ) ) {
4376 //kdDebug(7007) << " Target is a directory " << endl;
4377 // List it
4378 state = STATE_LISTING;
4379 ListJob *newjob = listRecursive( url, false );
4380 newjob->setUnrestricted(true); // No KIOSK restrictions
4381 Scheduler::scheduleJob(newjob);
4382 connect(newjob, TQ_SIGNAL(entries( TDEIO::Job *,
4383 const TDEIO::UDSEntryList& )),
4384 TQ_SLOT( slotEntries( TDEIO::Job*,
4385 const TDEIO::UDSEntryList& )));
4386 addSubjob(newjob);
4387 } else {
4388 ++m_currentStat;
4389 statNextSrc();
4390 }
4391 }
4392 else
4393 {
4394 if ( bLink ) {
4395 //kdDebug(7007) << " Target is a symlink" << endl;
4396 symlinks.append( url );
4397 } else {
4398 //kdDebug(7007) << " Target is a file" << endl;
4399 files.append( url );
4400 }
4401 if ( url.isLocalFile() && !m_parentDirs.contains( url.directory(false) ) )
4402 m_parentDirs.append( url.directory(false) );
4403 ++m_currentStat;
4404 statNextSrc();
4405 }
4406 }
4407 break;
4408 case STATE_LISTING:
4409 if ( job->error() )
4410 {
4411 // Try deleting nonetheless, it may be empty (and non-listable)
4412 }
4413 subjobs.remove( job );
4414 assert( subjobs.isEmpty() );
4415 ++m_currentStat;
4416 statNextSrc();
4417 break;
4418 case STATE_DELETING_FILES:
4419 if ( job->error() )
4420 {
4421 Job::slotResult( job ); // will set the error and emit result(this)
4422 return;
4423 }
4424 subjobs.remove( job );
4425 assert( subjobs.isEmpty() );
4426 m_processedFiles++;
4427
4428 deleteNextFile();
4429 break;
4430 case STATE_DELETING_DIRS:
4431 if ( job->error() )
4432 {
4433 Job::slotResult( job ); // will set the error and emit result(this)
4434 return;
4435 }
4436 subjobs.remove( job );
4437 assert( subjobs.isEmpty() );
4438 m_processedDirs++;
4439 //emit processedDirs( this, m_processedDirs );
4440 //if (!m_shred)
4441 //emitPercent( m_processedFiles + m_processedDirs, m_totalFilesDirs );
4442
4443 deleteNextDir();
4444 break;
4445 default:
4446 assert(0);
4447 }
4448}
4449
4450DeleteJob *TDEIO::del( const KURL& src, bool shred, bool showProgressInfo )
4451{
4452 KURL::List srcList;
4453 srcList.append( src );
4454 DeleteJob *job = new DeleteJob( srcList, shred, showProgressInfo );
4455 return job;
4456}
4457
4458DeleteJob *TDEIO::del( const KURL::List& src, bool shred, bool showProgressInfo )
4459{
4460 DeleteJob *job = new DeleteJob( src, shred, showProgressInfo );
4461 return job;
4462}
4463
4464MultiGetJob::MultiGetJob(const KURL& url,
4465 bool showProgressInfo)
4466 : TransferJob(url, 0, TQByteArray(), TQByteArray(), showProgressInfo)
4467{
4468 m_waitQueue.setAutoDelete(true);
4469 m_activeQueue.setAutoDelete(true);
4470 m_currentEntry = 0;
4471}
4472
4473void MultiGetJob::get(long id, const KURL &url, const MetaData &metaData)
4474{
4475 GetRequest *entry = new GetRequest(id, url, metaData);
4476 entry->metaData["request-id"] = TQString("%1").arg(id);
4477 m_waitQueue.append(entry);
4478}
4479
4480void MultiGetJob::flushQueue(TQPtrList<GetRequest> &queue)
4481{
4482 GetRequest *entry;
4483 // Use multi-get
4484 // Scan all jobs in m_waitQueue
4485 for(entry = m_waitQueue.first(); entry; )
4486 {
4487 if ((m_url.protocol() == entry->url.protocol()) &&
4488 (m_url.host() == entry->url.host()) &&
4489 (m_url.port() == entry->url.port()) &&
4490 (m_url.user() == entry->url.user()))
4491 {
4492 m_waitQueue.take();
4493 queue.append(entry);
4494 entry = m_waitQueue.current();
4495 }
4496 else
4497 {
4498 entry = m_waitQueue.next();
4499 }
4500 }
4501 // Send number of URLs, (URL, metadata)*
4502 TDEIO_ARGS << (TQ_INT32) queue.count();
4503 for(entry = queue.first(); entry; entry = queue.next())
4504 {
4505 stream << entry->url << entry->metaData;
4506 }
4507 m_packedArgs = packedArgs;
4508 m_command = CMD_MULTI_GET;
4509 m_outgoingMetaData.clear();
4510}
4511
4512void MultiGetJob::start(Slave *slave)
4513{
4514 // Add first job from m_waitQueue and add it to m_activeQueue
4515 GetRequest *entry = m_waitQueue.take(0);
4516 m_activeQueue.append(entry);
4517
4518 m_url = entry->url;
4519
4520 if (!entry->url.protocol().startsWith("http"))
4521 {
4522 // Use normal get
4523 TDEIO_ARGS << entry->url;
4524 m_packedArgs = packedArgs;
4525 m_outgoingMetaData = entry->metaData;
4526 m_command = CMD_GET;
4527 b_multiGetActive = false;
4528 }
4529 else
4530 {
4531 flushQueue(m_activeQueue);
4532 b_multiGetActive = true;
4533 }
4534
4535 TransferJob::start(slave); // Anything else to do??
4536}
4537
4538bool MultiGetJob::findCurrentEntry()
4539{
4540 if (b_multiGetActive)
4541 {
4542 long id = m_incomingMetaData["request-id"].toLong();
4543 for(GetRequest *entry = m_activeQueue.first(); entry; entry = m_activeQueue.next())
4544 {
4545 if (entry->id == id)
4546 {
4547 m_currentEntry = entry;
4548 return true;
4549 }
4550 }
4551 m_currentEntry = 0;
4552 return false;
4553 }
4554 else
4555 {
4556 m_currentEntry = m_activeQueue.first();
4557 return (m_currentEntry != 0);
4558 }
4559}
4560
4561void MultiGetJob::slotRedirection( const KURL &url)
4562{
4563 if (!findCurrentEntry()) return; // Error
4564 if (tdeApp && !tdeApp->authorizeURLAction("redirect", m_url, url))
4565 {
4566 kdWarning(7007) << "MultiGetJob: Redirection from " << m_currentEntry->url << " to " << url << " REJECTED!" << endl;
4567 return;
4568 }
4569 m_redirectionURL = url;
4570 if (m_currentEntry->url.hasUser() && !url.hasUser() && (m_currentEntry->url.host().lower() == url.host().lower()))
4571 m_redirectionURL.setUser(m_currentEntry->url.user()); // Preserve user
4572 get(m_currentEntry->id, m_redirectionURL, m_currentEntry->metaData); // Try again
4573}
4574
4575
4576void MultiGetJob::slotFinished()
4577{
4578 if (!findCurrentEntry()) return;
4579 if (m_redirectionURL.isEmpty())
4580 {
4581 // No redirection, tell the world that we are finished.
4582 emit result(m_currentEntry->id);
4583 }
4584 m_redirectionURL = KURL();
4585 m_error = 0;
4586 m_incomingMetaData.clear();
4587 m_activeQueue.removeRef(m_currentEntry);
4588 if (m_activeQueue.count() == 0)
4589 {
4590 if (m_waitQueue.count() == 0)
4591 {
4592 // All done
4593 TransferJob::slotFinished();
4594 }
4595 else
4596 {
4597 // return slave to pool
4598 // fetch new slave for first entry in m_waitQueue and call start
4599 // again.
4600 GetRequest *entry = m_waitQueue.at(0);
4601 m_url = entry->url;
4602 slaveDone();
4603 Scheduler::doJob(this);
4604 }
4605 }
4606}
4607
4608void MultiGetJob::slotData( const TQByteArray &_data)
4609{
4610 if(!m_currentEntry) return;// Error, unknown request!
4611 if(m_redirectionURL.isEmpty() || !m_redirectionURL.isValid() || m_error)
4612 emit data(m_currentEntry->id, _data);
4613}
4614
4615void MultiGetJob::slotMimetype( const TQString &_mimetype )
4616{
4617 if (b_multiGetActive)
4618 {
4619 TQPtrList<GetRequest> newQueue;
4620 flushQueue(newQueue);
4621 if (!newQueue.isEmpty())
4622 {
4623 while(!newQueue.isEmpty())
4624 m_activeQueue.append(newQueue.take(0));
4625 m_slave->send( m_command, m_packedArgs );
4626 }
4627 }
4628 if (!findCurrentEntry()) return; // Error, unknown request!
4629 emit mimetype(m_currentEntry->id, _mimetype);
4630}
4631
4632MultiGetJob *TDEIO::multi_get(long id, const KURL &url, const MetaData &metaData)
4633{
4634 MultiGetJob * job = new MultiGetJob( url, false );
4635 job->get(id, url, metaData);
4636 return job;
4637}
4638
4639
4640#ifdef CACHE_INFO
4641CacheInfo::CacheInfo(const KURL &url)
4642{
4643 m_url = url;
4644}
4645
4646TQString CacheInfo::cachedFileName()
4647{
4648 const TQChar separator = '_';
4649
4650 TQString CEF = m_url.path();
4651
4652 int p = CEF.find('/');
4653
4654 while(p != -1)
4655 {
4656 CEF[p] = separator;
4657 p = CEF.find('/', p);
4658 }
4659
4660 TQString host = m_url.host().lower();
4661 CEF = host + CEF + '_';
4662
4663 TQString dir = KProtocolManager::cacheDir();
4664 if (dir[dir.length()-1] != '/')
4665 dir += "/";
4666
4667 int l = m_url.host().length();
4668 for(int i = 0; i < l; i++)
4669 {
4670 if (host[i].isLetter() && (host[i] != 'w'))
4671 {
4672 dir += host[i];
4673 break;
4674 }
4675 }
4676 if (dir[dir.length()-1] == '/')
4677 dir += "0";
4678
4679 unsigned long hash = 0x00000000;
4680 TQCString u = m_url.url().latin1();
4681 for(int i = u.length(); i--;)
4682 {
4683 hash = (hash * 12211 + u[i]) % 2147483563;
4684 }
4685
4686 TQString hashString;
4687 hashString.sprintf("%08lx", hash);
4688
4689 CEF = CEF + hashString;
4690
4691 CEF = dir + "/" + CEF;
4692
4693 return CEF;
4694}
4695
4696TQFile *CacheInfo::cachedFile()
4697{
4698#ifdef TQ_WS_WIN
4699 const char *mode = (readWrite ? "rb+" : "rb");
4700#else
4701 const char *mode = (readWrite ? "r+" : "r");
4702#endif
4703
4704 FILE *fs = fopen(TQFile::encodeName(CEF), mode); // Open for reading and writing
4705 if (!fs)
4706 return 0;
4707
4708 char buffer[401];
4709 bool ok = true;
4710
4711 // CacheRevision
4712 if (ok && (!fgets(buffer, 400, fs)))
4713 ok = false;
4714 if (ok && (strcmp(buffer, CACHE_REVISION) != 0))
4715 ok = false;
4716
4717 time_t date;
4718 time_t currentDate = time(0);
4719
4720 // URL
4721 if (ok && (!fgets(buffer, 400, fs)))
4722 ok = false;
4723 if (ok)
4724 {
4725 int l = strlen(buffer);
4726 if (l>0)
4727 buffer[l-1] = 0; // Strip newline
4728 if (m_.url.url() != buffer)
4729 {
4730 ok = false; // Hash collision
4731 }
4732 }
4733
4734 // Creation Date
4735 if (ok && (!fgets(buffer, 400, fs)))
4736 ok = false;
4737 if (ok)
4738 {
4739 date = (time_t) strtoul(buffer, 0, 10);
4740 if (m_maxCacheAge && (difftime(currentDate, date) > m_maxCacheAge))
4741 {
4742 m_bMustRevalidate = true;
4743 m_expireDate = currentDate;
4744 }
4745 }
4746
4747 // Expiration Date
4748 m_cacheExpireDateOffset = ftell(fs);
4749 if (ok && (!fgets(buffer, 400, fs)))
4750 ok = false;
4751 if (ok)
4752 {
4753 if (m_request.cache == CC_Verify)
4754 {
4755 date = (time_t) strtoul(buffer, 0, 10);
4756 // After the expire date we need to revalidate.
4757 if (!date || difftime(currentDate, date) >= 0)
4758 m_bMustRevalidate = true;
4759 m_expireDate = date;
4760 }
4761 }
4762
4763 // ETag
4764 if (ok && (!fgets(buffer, 400, fs)))
4765 ok = false;
4766 if (ok)
4767 {
4768 m_etag = TQString(buffer).stripWhiteSpace();
4769 }
4770
4771 // Last-Modified
4772 if (ok && (!fgets(buffer, 400, fs)))
4773 ok = false;
4774 if (ok)
4775 {
4776 m_lastModified = TQString(buffer).stripWhiteSpace();
4777 }
4778
4779 fclose(fs);
4780
4781 if (ok)
4782 return fs;
4783
4784 unlink( TQFile::encodeName(CEF) );
4785 return 0;
4786
4787}
4788
4789void CacheInfo::flush()
4790{
4791 cachedFile().remove();
4792}
4793
4794void CacheInfo::touch()
4795{
4796
4797}
4798void CacheInfo::setExpireDate(int);
4799void CacheInfo::setExpireTimeout(int);
4800
4801
4802int CacheInfo::creationDate();
4803int CacheInfo::expireDate();
4804int CacheInfo::expireTimeout();
4805#endif
4806
4807void Job::virtual_hook( int, void* )
4808{ /*BASE::virtual_hook( id, data );*/ }
4809
4810void SimpleJob::virtual_hook( int id, void* data )
4811{ TDEIO::Job::virtual_hook( id, data ); }
4812
4813void MkdirJob::virtual_hook( int id, void* data )
4814{ SimpleJob::virtual_hook( id, data ); }
4815
4816void StatJob::virtual_hook( int id, void* data )
4817{ SimpleJob::virtual_hook( id, data ); }
4818
4819void TransferJob::virtual_hook( int id, void* data )
4820{ SimpleJob::virtual_hook( id, data ); }
4821
4822void MultiGetJob::virtual_hook( int id, void* data )
4823{ TransferJob::virtual_hook( id, data ); }
4824
4825void MimetypeJob::virtual_hook( int id, void* data )
4826{ TransferJob::virtual_hook( id, data ); }
4827
4828void FileCopyJob::virtual_hook( int id, void* data )
4829{ Job::virtual_hook( id, data ); }
4830
4831void ListJob::virtual_hook( int id, void* data )
4832{ SimpleJob::virtual_hook( id, data ); }
4833
4834void CopyJob::virtual_hook( int id, void* data )
4835{ Job::virtual_hook( id, data ); }
4836
4837void DeleteJob::virtual_hook( int id, void* data )
4838{ Job::virtual_hook( id, data ); }
4839
4840void LocalURLJob::virtual_hook( int id, void* data )
4841{ Job::virtual_hook( id, data ); }
4842
4843
4844#include "jobclasses.moc"
KDirWatch::restartDirScan
bool restartDirScan(const TQString &path)
Restarts scanning for specified path.
Definition: kdirwatch.cpp:1737
KDirWatch::self
static KDirWatch * self()
The KDirWatch instance usually globally used in an application.
Definition: kdirwatch.cpp:1634
KDirWatch::stopDirScan
bool stopDirScan(const TQString &path)
Stops scanning the specified path.
Definition: kdirwatch.cpp:1728
KMimeType::findByURL
static Ptr findByURL(const KURL &_url, mode_t _mode=0, bool _is_local_file=false, bool _fast_mode=false)
Finds a KMimeType with the given _url.
Definition: kmimetype.cpp:165
KProtocolInfo::isKnownProtocol
static bool isKnownProtocol(const KURL &url)
Returns whether a protocol is installed that is able to handle url.
Definition: kprotocolinfo.cpp:109
KProtocolInfo::supportsDeleting
static bool supportsDeleting(const KURL &url)
Returns whether the protocol can delete files/objects.
Definition: kprotocolinfo.cpp:166
KProtocolInfo::canCopyFromFile
static bool canCopyFromFile(const KURL &url)
Returns whether the protocol can copy files/objects directly from the filesystem itself.
Definition: kprotocolinfo.cpp:193
KProtocolInfo::canCopyToFile
static bool canCopyToFile(const KURL &url)
Returns whether the protocol can copy files/objects directly to the filesystem itself.
Definition: kprotocolinfo.cpp:203
KProtocolInfo::supportsListing
static bool supportsListing(const KURL &url)
Returns whether the protocol can list files/objects.
Definition: kprotocolinfo.cpp:121
KProtocolManager::cacheDir
static TQString cacheDir()
The directory which contains the cache files.
Definition: tdeprotocolmanager.cpp:189
KProtocolManager::autoResume
static bool autoResume()
Returns true if partial downloads should be automatically resumed.
Definition: tdeprotocolmanager.cpp:523
Observer
Observer for TDEIO::Job progress information.
Definition: observer.h:55
Observer::newJob
int newJob(TDEIO::Job *job, bool showProgress)
Called by the job constructor, to signal its presence to the UI Server.
Definition: observer.cpp:81
Observer::slotTransferring
void slotTransferring(TDEIO::Job *, const KURL &url)
Definition: observer.cpp:188
Observer::self
static Observer * self()
Returns the unique observer object.
Definition: observer.h:66
Observer::jobFinished
void jobFinished(int progressId)
Called by the job destructor, to tell the UI Server that the job ended.
Definition: observer.cpp:93
TDEIO::CopyJob
CopyJob is used to move, copy or symlink files and directories.
Definition: jobclasses.h:1507
TDEIO::CopyJob::renamed
void renamed(TDEIO::Job *job, const KURL &from, const KURL &to)
TDEIO::CopyJob::copyingLinkDone
void copyingLinkDone(TDEIO::Job *job, const KURL &from, const TQString &target, const KURL &to)
TDEIO::CopyJob::CopyMode
CopyMode
Defines the mode of the operation.
Definition: jobclasses.h:1514
TDEIO::CopyJob::aboutToCreate
void aboutToCreate(TDEIO::Job *job, const TQValueList< TDEIO::CopyInfo > &files)
Emitted when it is known which files / directories are going to be created.
TDEIO::CopyJob::processedFiles
void processedFiles(TDEIO::Job *job, unsigned long files)
Sends the number of processed files.
TDEIO::CopyJob::moving
void moving(TDEIO::Job *job, const KURL &from, const KURL &to)
TDEIO::CopyJob::linking
void linking(TDEIO::Job *job, const TQString &target, const KURL &to)
TDEIO::CopyJob::copyingDone
void copyingDone(TDEIO::Job *job, const KURL &from, const KURL &to, bool directory, bool renamed)
TDEIO::CopyJob::CopyJob
CopyJob(const KURL::List &src, const KURL &dest, CopyMode mode, bool asMethod, bool showProgressInfo)
Do not create a CopyJob directly.
Definition: job.cpp:2278
TDEIO::CopyJob::totalDirs
void totalDirs(TDEIO::Job *job, unsigned long dirs)
Emitted when the toal number of direcotries is known.
TDEIO::CopyJob::creatingDir
void creatingDir(TDEIO::Job *job, const KURL &dir)
TDEIO::CopyJob::slotStart
void slotStart()
Definition: job.cpp:2321
TDEIO::CopyJob::slotTotalSize
void slotTotalSize(TDEIO::Job *, TDEIO::filesize_t size)
Definition: job.cpp:3654
TDEIO::CopyJob::setDefaultPermissions
void setDefaultPermissions(bool b)
By default the permissions of the copied files will be those of the source files.
Definition: job.cpp:3939
TDEIO::CopyJob::slotProcessedSize
void slotProcessedSize(TDEIO::Job *, TDEIO::filesize_t data_size)
Forward signal from subjob.
Definition: job.cpp:3637
TDEIO::CopyJob::totalFiles
void totalFiles(TDEIO::Job *job, unsigned long files)
Emitted when the total number of files is known.
TDEIO::CopyJob::setInteractive
void setInteractive(bool b)
When an error happens while copying/moving a file, the user will be presented with a dialog for skipp...
Definition: job.cpp:3945
TDEIO::CopyJob::processedDirs
void processedDirs(TDEIO::Job *job, unsigned long dirs)
Sends the number of processed directories.
TDEIO::CopyJob::copying
void copying(TDEIO::Job *job, const KURL &from, const KURL &to)
TDEIO::DeleteJob
A more complex Job to delete files and directories.
Definition: jobclasses.h:1762
TDEIO::DeleteJob::totalDirs
void totalDirs(TDEIO::Job *job, unsigned long dirs)
Emitted when the toal number of direcotries is known.
TDEIO::DeleteJob::processedDirs
void processedDirs(TDEIO::Job *job, unsigned long dirs)
Sends the number of processed directories.
TDEIO::DeleteJob::DeleteJob
DeleteJob(const KURL::List &src, bool shred, bool showProgressInfo)
Do not create a DeleteJob directly.
Definition: job.cpp:4027
TDEIO::DeleteJob::processedFiles
void processedFiles(TDEIO::Job *job, unsigned long files)
Sends the number of processed files.
TDEIO::DeleteJob::deleting
void deleting(TDEIO::Job *job, const KURL &file)
Sends the URL of the file that is currently being deleted.
TDEIO::DeleteJob::slotProcessedSize
void slotProcessedSize(TDEIO::Job *, TDEIO::filesize_t data_size)
Forward signal from subjob.
Definition: job.cpp:4293
TDEIO::DeleteJob::totalFiles
void totalFiles(TDEIO::Job *job, unsigned long files)
Emitted when the total number of files is known.
TDEIO::FileCopyJob
The FileCopyJob copies data from one place to another.
Definition: jobclasses.h:1249
TDEIO::FileCopyJob::slotCanResume
void slotCanResume(TDEIO::Job *job, TDEIO::filesize_t offset)
Definition: job.cpp:1810
TDEIO::FileCopyJob::slotPercent
void slotPercent(TDEIO::Job *job, unsigned long pct)
Definition: job.cpp:1778
TDEIO::FileCopyJob::slotResult
virtual void slotResult(TDEIO::Job *job)
Definition: job.cpp:1944
TDEIO::FileCopyJob::slotProcessedSize
void slotProcessedSize(TDEIO::Job *job, TDEIO::filesize_t size)
Definition: job.cpp:1759
TDEIO::FileCopyJob::setSourceSize64
void setSourceSize64(TDEIO::filesize_t size)
Definition: job.cpp:1710
TDEIO::FileCopyJob::slotTotalSize
void slotTotalSize(TDEIO::Job *job, TDEIO::filesize_t size)
Definition: job.cpp:1769
TDEIO::FileCopyJob::setSourceSize
void setSourceSize(off_t size) TDE_DEPRECATED
Definition: job.cpp:1703
TDEIO::FileCopyJob::setModificationTime
void setModificationTime(time_t mtime)
Sets the modification time of the file.
Definition: job.cpp:1717
TDEIO::FileCopyJob::mimetype
void mimetype(TDEIO::Job *job, const TQString &type)
Mimetype determined during a file copy.
TDEIO::Job
The base class for all jobs.
Definition: jobclasses.h:67
TDEIO::Job::isAutoWarningHandlingEnabled
bool isAutoWarningHandlingEnabled() const
Returns whether automatic warning handling is enabled or disabled.
Definition: job.cpp:366
TDEIO::Job::removeSubjob
virtual void removeSubjob(Job *job)
Definition: job.cpp:205
TDEIO::Job::updateUserTimestamp
void updateUserTimestamp(unsigned long time)
Updates the last user action timestamp to the given time.
Definition: job.cpp:392
TDEIO::Job::slotResult
virtual void slotResult(TDEIO::Job *job)
Definition: job.cpp:281
TDEIO::Job::mergeMetaData
void mergeMetaData(const TQMap< TQString, TQString > &values)
Definition: job.cpp:446
TDEIO::Job::setProcessedSize
void setProcessedSize(TDEIO::filesize_t size)
Set the processed size, does not emit processedSize.
Definition: job.cpp:173
TDEIO::Job::setParentJob
void setParentJob(Job *parentJob)
Definition: job.cpp:405
TDEIO::Job::setAutoErrorHandlingEnabled
void setAutoErrorHandlingEnabled(bool enable, TQWidget *parentWidget=0)
Definition: job.cpp:342
TDEIO::Job::emitResult
void emitResult()
Utility function to emit the result signal, and suicide this job.
Definition: job.cpp:249
TDEIO::Job::setAutoWarningHandlingEnabled
void setAutoWarningHandlingEnabled(bool enable)
Enable or disable the automatic warning handling.
Definition: job.cpp:361
TDEIO::Job::addSubjob
virtual void addSubjob(Job *job, bool inheritMetaData=true)
Definition: job.cpp:183
TDEIO::Job::getProcessedSize
TDEIO::filesize_t getProcessedSize()
Returns the processed size for this job.
Definition: job.cpp:178
TDEIO::Job::emitSpeed
void emitSpeed(unsigned long speed)
Definition: job.cpp:237
TDEIO::Job::slotSpeed
void slotSpeed(TDEIO::Job *job, unsigned long speed)
Definition: job.cpp:293
TDEIO::Job::detailedErrorStrings
TQStringList detailedErrorStrings(const KURL *reqUrl=0L, int method=-1) const
Converts an error code and a non-i18n error message into i18n strings suitable for presentation in a ...
Definition: global.cpp:478
TDEIO::Job::errorText
const TQString & errorText() const
Returns the error text if there has been an error.
Definition: jobclasses.h:110
TDEIO::Job::parentJob
Job * parentJob() const
Returns the parent job, if there is one.
Definition: job.cpp:412
TDEIO::Job::showErrorDialog
void showErrorDialog(TQWidget *parent=0L)
Display a dialog box to inform the user of the error given by this job.
Definition: job.cpp:315
TDEIO::Job::result
void result(TDEIO::Job *job)
TDEIO::Job::infoMessage
void infoMessage(TDEIO::Job *job, const TQString &msg)
TDEIO::Job::connected
void connected(TDEIO::Job *job)
TDEIO::Job::kill
virtual void kill(bool quietly=true)
Abort this job.
Definition: job.cpp:260
TDEIO::Job::addMetaData
void addMetaData(const TQString &key, const TQString &value)
Definition: job.cpp:434
TDEIO::Job::totalSize
void totalSize(TDEIO::Job *job, TDEIO::filesize_t size)
TDEIO::Job::slotSpeedTimeout
void slotSpeedTimeout()
Remove speed information.
Definition: job.cpp:304
TDEIO::Job::speed
void speed(TDEIO::Job *job, unsigned long speed)
TDEIO::Job::emitPercent
void emitPercent(TDEIO::filesize_t processedSize, TDEIO::filesize_t totalSize)
Definition: job.cpp:221
TDEIO::Job::isInteractive
bool isInteractive() const
Returns whether message display is enabled or disabled.
Definition: job.cpp:376
TDEIO::Job::error
int error() const
Returns the error code, if there has been an error.
Definition: jobclasses.h:94
TDEIO::Job::canceled
void canceled(TDEIO::Job *job)
TDEIO::Job::setWindow
void setWindow(TQWidget *window)
Definition: job.cpp:381
TDEIO::Job::queryMetaData
TQString queryMetaData(const TQString &key)
Definition: job.cpp:422
TDEIO::Job::setInteractive
void setInteractive(bool enable)
Enable or disable the message display from the job.
Definition: job.cpp:371
TDEIO::Job::percent
void percent(TDEIO::Job *job, unsigned long percent)
TDEIO::Job::window
TQWidget * window() const
Definition: job.cpp:387
TDEIO::Job::slotInfoMessage
void slotInfoMessage(TDEIO::Job *job, const TQString &msg)
Definition: job.cpp:299
TDEIO::Job::isAutoErrorHandlingEnabled
bool isAutoErrorHandlingEnabled() const
Definition: job.cpp:356
TDEIO::Job::errorString
TQString errorString() const
Definition: global.cpp:225
TDEIO::Job::metaData
MetaData metaData() const
Definition: job.cpp:417
TDEIO::Job::warning
void warning(TDEIO::Job *job, const TQString &msg)
Emitted to display a warning about this job, as sent by the slave.
TDEIO::Job::setMetaData
void setMetaData(const TDEIO::MetaData &metaData)
Definition: job.cpp:429
TDEIO::Job::processedSize
void processedSize(TDEIO::Job *job, TDEIO::filesize_t size)
TDEIO::ListJob
A ListJob is allows you to get the get the content of a directory.
Definition: jobclasses.h:1391
TDEIO::ListJob::redirection
void redirection(TDEIO::Job *job, const KURL &url)
TDEIO::ListJob::entries
void entries(TDEIO::Job *job, const TDEIO::UDSEntryList &list)
TDEIO::ListJob::setUnrestricted
void setUnrestricted(bool unrestricted)
Do not apply any KIOSK restrictions to this job.
Definition: job.cpp:2228
TDEIO::ListJob::permanentRedirection
void permanentRedirection(TDEIO::Job *job, const KURL &fromUrl, const KURL &toUrl)
TDEIO::ListJob::ListJob
ListJob(const KURL &url, bool showProgressInfo, bool recursive=false, TQString prefix=TQString::null, bool includeHidden=true)
Do not create a ListJob directly.
Definition: job.cpp:2048
TDEIO::LocalURLJob
A TDEIO job that finds a local URL.
Definition: jobclasses.h:1865
TDEIO::LocalURLJob::localURL
void localURL(TDEIO::LocalURLJob *job, const KURL &url, bool isLocal)
TDEIO::LocalURLJob::LocalURLJob
LocalURLJob(const KURL &url, int command, const TQByteArray &packedArgs, bool showProgressInfo)
Do not use this constructor to create a LocalURLJob, use TDEIO::localURL() instead.
Definition: job.cpp:841
TDEIO::MetaData
MetaData is a simple map of key/value strings.
Definition: global.h:516
TDEIO::MimetypeJob
A MimetypeJob is a TransferJob that allows you to get the mime type of an URL.
Definition: jobclasses.h:1207
TDEIO::MimetypeJob::MimetypeJob
MimetypeJob(const KURL &url, int command, const TQByteArray &packedArgs, bool showProgressInfo)
Do not create a MimetypeJob directly.
Definition: job.cpp:1526
TDEIO::MkdirJob
A TDEIO job that creates a directory.
Definition: jobclasses.h:779
TDEIO::MkdirJob::redirection
void redirection(TDEIO::Job *job, const KURL &url)
TDEIO::MkdirJob::permanentRedirection
void permanentRedirection(TDEIO::Job *job, const KURL &fromUrl, const KURL &toUrl)
TDEIO::MkdirJob::MkdirJob
MkdirJob(const KURL &url, int command, const TQByteArray &packedArgs, bool showProgressInfo)
Do not use this constructor to create a MkdirJob, use TDEIO::mkdir() instead.
Definition: job.cpp:721
TDEIO::MultiGetJob
The MultiGetJob is a TransferJob that allows you to get several files from a single server.
Definition: jobclasses.h:1119
TDEIO::MultiGetJob::mimetype
void mimetype(long id, const TQString &type)
TDEIO::MultiGetJob::get
void get(long id, const KURL &url, const MetaData &metaData)
Get an additional file.
Definition: job.cpp:4473
TDEIO::MultiGetJob::data
void data(long id, const TQByteArray &data)
TDEIO::MultiGetJob::MultiGetJob
MultiGetJob(const KURL &url, bool showProgressInfo)
Do not create a MultiGetJob directly, use TDEIO::multi_get() instead.
Definition: job.cpp:4464
TDEIO::MultiGetJob::result
void result(long id)
TDEIO::Scheduler::scheduleJob
static void scheduleJob(SimpleJob *job)
Definition: scheduler.h:137
TDEIO::Scheduler::registerWindow
static void registerWindow(TQWidget *wid)
Definition: scheduler.h:242
TDEIO::Scheduler::putSlaveOnHold
static void putSlaveOnHold(TDEIO::SimpleJob *job, const KURL &url)
Definition: scheduler.h:166
TDEIO::Scheduler::removeSlaveOnHold
static void removeSlaveOnHold()
Removes any slave that might have been put on hold.
Definition: scheduler.h:173
TDEIO::Scheduler::cancelJob
static void cancelJob(SimpleJob *job)
Definition: scheduler.h:144
TDEIO::Scheduler::jobFinished
static void jobFinished(TDEIO::SimpleJob *job, TDEIO::Slave *slave)
Definition: scheduler.h:152
TDEIO::Scheduler::doJob
static void doJob(SimpleJob *job)
Definition: scheduler.h:128
TDEIO::SimpleJob
A simple job (one url and one command).
Definition: jobclasses.h:527
TDEIO::SimpleJob::slotSpeed
void slotSpeed(unsigned long speed)
Definition: job.cpp:700
TDEIO::SimpleJob::removeOnHold
static void removeOnHold()
Discard suspended slave.
Definition: job.cpp:504
TDEIO::SimpleJob::url
const KURL & url() const
Returns the SimpleJob's URL.
Definition: jobclasses.h:548
TDEIO::SimpleJob::putOnHold
virtual void putOnHold()
Abort job.
Definition: job.cpp:493
TDEIO::SimpleJob::slotMetaData
virtual void slotMetaData(const TDEIO::MetaData &_metaData)
Definition: job.cpp:706
TDEIO::SimpleJob::slotProcessedSize
void slotProcessedSize(TDEIO::filesize_t data_size)
Definition: job.cpp:689
TDEIO::SimpleJob::slotConnected
void slotConnected()
Definition: job.cpp:668
TDEIO::SimpleJob::slotFinished
virtual void slotFinished()
Called when the slave marks the job as finished.
Definition: job.cpp:605
TDEIO::SimpleJob::SimpleJob
SimpleJob(const KURL &url, int command, const TQByteArray &packedArgs, bool showProgressInfo)
Creates a new simple job.
Definition: job.cpp:459
TDEIO::SimpleJob::slotInfoMessage
void slotInfoMessage(const TQString &s)
Definition: job.cpp:663
TDEIO::SimpleJob::slotTotalSize
void slotTotalSize(TDEIO::filesize_t data_size)
Definition: job.cpp:680
TDEIO::SimpleJob::kill
virtual void kill(bool quietly=true)
Abort job.
Definition: job.cpp:486
TDEIO::SlaveInterface::sendResumeAnswer
void sendResumeAnswer(bool resume)
Send our answer to the MSG_RESUME (canResume) request (to tell the "put" job whether to resume or not...
Definition: slaveinterface.cpp:447
TDEIO::Slave
Attention developers: If you change the implementation of TDEIO::Slave, do not use connection() or sl...
Definition: slave.h:44
TDEIO::Slave::suspended
bool suspended()
Tells wether the tdeioslave is suspended.
Definition: slave.cpp:274
TDEIO::Slave::suspend
void suspend()
Suspends the operation of the attached tdeioslave.
Definition: slave.cpp:254
TDEIO::Slave::kill
void kill()
Force termination.
Definition: slave.cpp:317
TDEIO::Slave::send
void send(int cmd, const TQByteArray &data=TQByteArray())
Sends the given command to the tdeioslave.
Definition: slave.cpp:285
TDEIO::Slave::resume
void resume()
Resumes the operation of the attached tdeioslave.
Definition: slave.cpp:264
TDEIO::StatJob
A TDEIO job that retrieves information about a file or directory.
Definition: jobclasses.h:687
TDEIO::StatJob::redirection
void redirection(TDEIO::Job *job, const KURL &url)
TDEIO::StatJob::setSide
void setSide(bool source)
A stat() can have two meanings.
Definition: jobclasses.h:708
TDEIO::StatJob::StatJob
StatJob(const KURL &url, int command, const TQByteArray &packedArgs, bool showProgressInfo)
Do not use this constructor to create a StatJob, use TDEIO::stat() instead.
Definition: job.cpp:879
TDEIO::StatJob::permanentRedirection
void permanentRedirection(TDEIO::Job *job, const KURL &fromUrl, const KURL &toUrl)
TDEIO::StatJob::setDetails
void setDetails(short int details)
Definition: jobclasses.h:719
TDEIO::StoredTransferJob
StoredTransferJob is a TransferJob (for downloading or uploading data) that also stores a TQByteArray...
Definition: jobclasses.h:1074
TDEIO::StoredTransferJob::data
TQByteArray data() const
Get hold of the downloaded data.
Definition: jobclasses.h:1103
TDEIO::StoredTransferJob::StoredTransferJob
StoredTransferJob(const KURL &url, int command, const TQByteArray &packedArgs, const TQByteArray &_staticData, bool showProgressInfo)
Do not create a StoredTransferJob.
Definition: job.cpp:1454
TDEIO::StoredTransferJob::setData
void setData(const TQByteArray &arr)
Set data to be uploaded.
Definition: job.cpp:1467
TDEIO::TransferJob
The transfer job pumps data into and/or out of a Slave.
Definition: jobclasses.h:874
TDEIO::TransferJob::data
void data(TDEIO::Job *job, const TQByteArray &data)
Data from the slave has arrived.
TDEIO::TransferJob::mimetype
void mimetype(TDEIO::Job *job, const TQString &type)
TDEIO::TransferJob::resume
void resume()
Flow control.
Definition: job.cpp:1186
TDEIO::TransferJob::slotResult
virtual void slotResult(TDEIO::Job *job)
Definition: job.cpp:1262
TDEIO::TransferJob::redirection
void redirection(TDEIO::Job *job, const KURL &url)
TDEIO::TransferJob::TransferJob
TransferJob(const KURL &url, int command, const TQByteArray &packedArgs, const TQByteArray &_staticData, bool showProgressInfo)
Do not create a TransferJob.
Definition: job.cpp:980
TDEIO::TransferJob::permanentRedirection
void permanentRedirection(TDEIO::Job *job, const KURL &fromUrl, const KURL &toUrl)
TDEIO::TransferJob::reportDataSent
bool reportDataSent()
Returns whether the job reports the amount of data that has been sent (true), or whether the job repo...
Definition: job.cpp:1128
TDEIO::TransferJob::dataReq
void dataReq(TDEIO::Job *job, TQByteArray &data)
TDEIO::TransferJob::suspend
void suspend()
Flow control.
Definition: job.cpp:1179
TDEIO::TransferJob::sendAsyncData
void sendAsyncData(const TQByteArray &data)
Provide data to the job when async data is enabled.
Definition: job.cpp:1100
TDEIO::TransferJob::setReportDataSent
void setReportDataSent(bool enabled)
When enabled, the job reports the amount of data that has been sent, instead of the amount of data th...
Definition: job.cpp:1120
TDEIO::TransferJob::setAsyncDataEnabled
void setAsyncDataEnabled(bool enabled)
Enable the async data mode.
Definition: job.cpp:1092
TDEIO
A namespace for TDEIO globals.
Definition: authinfo.h:29
TDEIO::chmod
TDEIO_EXPORT ChmodJob * chmod(const KFileItemList &lstItems, int permissions, int mask, TQString newOwner, TQString newGroup, bool recursive, bool showProgressInfo=true)
Creates a job that changes permissions/ownership on several files or directories, optionally recursiv...
Definition: chmodjob.cpp:230
TDEIO::file_move
TDEIO_EXPORT FileCopyJob * file_move(const KURL &src, const KURL &dest, int permissions=-1, bool overwrite=false, bool resume=false, bool showProgressInfo=true)
Move a single file.
Definition: job.cpp:2033
TDEIO::link
TDEIO_EXPORT CopyJob * link(const KURL &src, const KURL &destDir, bool showProgressInfo=true)
Create a link.
Definition: job.cpp:3994
TDEIO::multi_get
TDEIO_EXPORT MultiGetJob * multi_get(long id, const KURL &url, const MetaData &metaData)
Creates a new multiple get job.
Definition: job.cpp:4632
TDEIO::symlink
TDEIO_EXPORT SimpleJob * symlink(const TQString &target, const KURL &dest, bool overwrite, bool showProgressInfo=true)
Create or move a symlink.
Definition: job.cpp:808
TDEIO::move
TDEIO_EXPORT CopyJob * move(const KURL &src, const KURL &dest, bool showProgressInfo=true)
Moves a file or directory src to the given destination dest.
Definition: job.cpp:3972
TDEIO::number
TDEIO_EXPORT TQString number(TDEIO::filesize_t size)
Converts a size to a string representation Not unlike TQString::number(...)
Definition: global.cpp:96
TDEIO::file_copy
TDEIO_EXPORT FileCopyJob * file_copy(const KURL &src, const KURL &dest, int permissions=-1, bool overwrite=false, bool resume=false, bool showProgressInfo=true)
Copy a single file.
Definition: job.cpp:2027
TDEIO::del
TDEIO_EXPORT DeleteJob * del(const KURL &src, bool shred=false, bool showProgressInfo=true)
Delete a file or directory.
Definition: job.cpp:4450
TDEIO::special
TDEIO_EXPORT SimpleJob * special(const KURL &url, const TQByteArray &data, bool showProgressInfo=true)
Execute any command that is specific to one slave (protocol).
Definition: job.cpp:815
TDEIO::localURL
TDEIO_EXPORT LocalURLJob * localURL(const KURL &remoteUrl)
Retrieve local URL if available.
Definition: job.cpp:870
TDEIO::mimetype
TDEIO_EXPORT MimetypeJob * mimetype(const KURL &url, bool showProgressInfo=true)
Find mimetype for one file or directory.
Definition: job.cpp:1573
TDEIO::copyAs
TDEIO_EXPORT CopyJob * copyAs(const KURL &src, const KURL &dest, bool showProgressInfo=true)
Copy a file or directory src into the destination dest, which is the destination name in any case,...
Definition: job.cpp:3958
TDEIO::linkAs
TDEIO_EXPORT CopyJob * linkAs(const KURL &src, const KURL &dest, bool showProgressInfo=true)
Create a link.
Definition: job.cpp:4006
TDEIO::file_delete
TDEIO_EXPORT SimpleJob * file_delete(const KURL &src, bool showProgressInfo=true)
Delete a single file.
Definition: job.cpp:2039
TDEIO::http_update_cache
TDEIO_EXPORT SimpleJob * http_update_cache(const KURL &url, bool no_cache, time_t expireDate)
HTTP cache update.
Definition: job.cpp:968
TDEIO::mkdir
TDEIO_EXPORT SimpleJob * mkdir(const KURL &url, int permissions=-1)
Creates a single directory.
Definition: job.cpp:780
TDEIO::UDS_LINK_DEST
@ UDS_LINK_DEST
Name of the file where the link points to Allows to check for a symlink (don't use S_ISLNK !...
Definition: global.h:369
TDEIO::UDS_URL
@ UDS_URL
An alternative URL (If different from the caption)
Definition: global.h:371
TDEIO::UDS_SIZE
@ UDS_SIZE
Size of the file.
Definition: global.h:319
TDEIO::UDS_CREATION_TIME
@ UDS_CREATION_TIME
The time the file was created.
Definition: global.h:362
TDEIO::UDS_MODIFICATION_TIME
@ UDS_MODIFICATION_TIME
The last time the file was modified.
Definition: global.h:358
TDEIO::UDS_FILE_TYPE
@ UDS_FILE_TYPE
File type, part of the mode returned by stat (for a link, this returns the file type of the pointed i...
Definition: global.h:366
TDEIO::UDS_ACCESS
@ UDS_ACCESS
Access permissions (part of the mode returned by stat)
Definition: global.h:356
TDEIO::UDS_NAME
@ UDS_NAME
Filename - as displayed in directory listings etc.
Definition: global.h:335
TDEIO::UDS_LOCAL_PATH
@ UDS_LOCAL_PATH
A local file path if the ioslave display files sitting on the local filesystem (but in another hierar...
Definition: global.h:338
TDEIO::UDSEntry
TQValueList< UDSAtom > UDSEntry
An entry is the list of atoms containing all the information for a file or URL.
Definition: global.h:507
TDEIO::moveAs
TDEIO_EXPORT CopyJob * moveAs(const KURL &src, const KURL &dest, bool showProgressInfo=true)
Moves a file or directory src to the given destination dest.
Definition: job.cpp:3980
TDEIO::buildErrorString
TDEIO_EXPORT TQString buildErrorString(int errorCode, const TQString &errorText)
Returns a translated error message for errorCode using the additional error information provided by e...
Definition: global.cpp:230
TDEIO::put
TDEIO_EXPORT TransferJob * put(const KURL &url, int permissions, bool overwrite, bool resume, bool showProgressInfo=true)
Put (a.k.a.
Definition: job.cpp:1444
TDEIO::trash
TDEIO_EXPORT CopyJob * trash(const KURL &src, bool showProgressInfo=true)
Trash a file or directory.
Definition: job.cpp:4013
TDEIO::rename
TDEIO_EXPORT SimpleJob * rename(const KURL &src, const KURL &dest, bool overwrite)
Rename a file or directory.
Definition: job.cpp:801
TDEIO::storedGet
TDEIO_EXPORT StoredTransferJob * storedGet(const KURL &url, bool reload=false, bool showProgressInfo=true)
Get (a.k.a.
Definition: job.cpp:1505
TDEIO::listDir
TDEIO_EXPORT ListJob * listDir(const KURL &url, bool showProgressInfo=true, bool includeHidden=true)
List the contents of url, which is assumed to be a directory.
Definition: job.cpp:2216
TDEIO::storedPut
TDEIO_EXPORT StoredTransferJob * storedPut(const TQByteArray &arr, const KURL &url, int permissions, bool overwrite, bool resume, bool showProgressInfo=true)
Put (a.k.a.
Definition: job.cpp:1515
TDEIO::encodeFileName
TDEIO_EXPORT TQString encodeFileName(const TQString &str)
Encodes (from the text displayed to the real filename) This translates % into %% and / into ∕ (U+2215...
Definition: global.cpp:165
TDEIO::CC_Verify
@ CC_Verify
Validate cached entry with remote site if expired.
Definition: global.h:391
TDEIO::copy
TDEIO_EXPORT CopyJob * copy(const KURL &src, const KURL &dest, bool showProgressInfo=true)
Copy a file or directory src into the destination dest, which can be a file (including the final file...
Definition: job.cpp:3950
TDEIO::get
TDEIO_EXPORT TransferJob * get(const KURL &url, bool reload=false, bool showProgressInfo=true)
Get (a.k.a.
Definition: job.cpp:1284
TDEIO::RenameDlg_Result
RenameDlg_Result
The result of open_RenameDlg().
Definition: renamedlg.h:40
TDEIO::filesize_t
TQ_ULLONG filesize_t
64-bit file size
Definition: global.h:39
TDEIO::http_post
TDEIO_EXPORT TransferJob * http_post(const KURL &url, const TQByteArray &postData, bool showProgressInfo=true)
HTTP POST (for form data).
Definition: job.cpp:1307
TDEIO::stat
TDEIO_EXPORT StatJob * stat(const KURL &url, bool showProgressInfo=true)
Find all details for one file or directory.
Definition: job.cpp:950
TDEIO::listRecursive
TDEIO_EXPORT ListJob * listRecursive(const KURL &url, bool showProgressInfo=true, bool includeHidden=true)
The same as the previous method, but recurses subdirectories.
Definition: job.cpp:2222
TDEIO::rmdir
TDEIO_EXPORT SimpleJob * rmdir(const KURL &url)
Removes a single directory.
Definition: job.cpp:787
TDEIO::unmount
TDEIO_EXPORT SimpleJob * unmount(const TQString &point, bool showProgressInfo=true)
Unmount filesystem.
Definition: job.cpp:831
TDEIO::mount
TDEIO_EXPORT SimpleJob * mount(bool ro, const char *fstype, const TQString &dev, const TQString &point, bool showProgressInfo=true)
Mount filesystem.
Definition: job.cpp:821

tdeio/tdeio

Skip menu "tdeio/tdeio"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdeio/tdeio

Skip menu "tdeio/tdeio"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeio/tdeio by doxygen 1.9.4
This website is maintained by Timothy Pearson.