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

kio/kio

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

kio/kio

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

kio/kio

Skip menu "kio/kio"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kio/kio by doxygen 1.8.13
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |