
#include <kurl.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <kdebug.h>
#include <ksimpleconfig.h>
#include <kaction.h>

#include <ftpsearch.h>
#include <kping.h>

#include "settings.h"
#include "logwindow.h"
#include "kmainwidget.h"
#include "dlgIndividual.h"
#include "transferlist.h"
#include "transfer.h"

uint Transfer::idcount = 0;  // each new transfer will increase it
FtpSiteManager* Transfer::searchManager = 0L;
KPingPool* Transfer::pinger = 0L;


Transfer::Transfer( TransferList *_view )
  : QListViewItem( _view ) {
  view = _view;
  setupFields();
}


Transfer::Transfer( TransferList *_view, Transfer *after )
  : QListViewItem( _view, (QListViewItem*)after ) {
  view = _view;
  setupFields();
}


Transfer::~Transfer() {
  delete dlgIndividual;
}


void Transfer::setupFields() {
  copyjob = 0L;
  statjob = 0L;
  
  totalSize = 0;
  processedSize = 0;
  percent = 0;

  totalFiles = 1;
  processedFiles = 0;

  canResume = true;
  startTime = QDateTime::currentDateTime();
  speed = 0;
  retryCount = ksettings.reconnectRetries;

  highestSpeed = 0.0;

  if ( ksettings.b_addQueued ){
    mode = MD_QUEUED;
  } else{
    mode = MD_DELAYED;
  }

  if ( ksettings.b_searchFastest ) { // search also gets size
    status = ST_SEARCH;
  } else if ( ksettings.b_getSizes ) {
    status = ST_SIZE_CHECK;
  } else {
    status = ST_STOPPED;
  }

  id = ++idcount;

  if ( ! pinger ) {
    pinger = new KPingPool();
  }

  connect( pinger, SIGNAL( speed( QString, float ) ),
	   this, SLOT( slotPingSpeed( QString, float ) ) );
  connect( this, SIGNAL( statusChanged( Transfer*, int ) ),
	   kmain, SLOT( slotStatusChanged( Transfer*, int ) ) );
  connect( this, SIGNAL( statusChanged( Transfer*, int ) ),
	   this, SLOT( slotUpdateActions( Transfer*, int ) ) );
  connect( this, SIGNAL( log( uint, const QString&, const QString& ) ),
	   kmain->logwin(), SLOT( logTransfer( uint, const QString&, const QString& ) ) );

  // setup actions
  m_paResume = new KAction( i18n("&Resume"), QIconSet(BarIcon("tool_resume")), 0, this,
			    SLOT( slotResume()), this, "resume" );
  m_paPause = new KAction( i18n("&Pause"), QIconSet(BarIcon("tool_pause")), 0, this,
			   SLOT( slotPause()), this, "pause" );
  m_paDelete = new KAction( i18n("&Delete"), QIconSet(BarIcon("tool_delete")), 0, this,
			    SLOT( slotRemove()), this, "delete" );
  m_paRestart = new KAction( i18n("Re&start"), QIconSet(BarIcon("tool_restart")), 0, this,
			     SLOT( slotRestart()), this, "restart" );

  m_paQueue = new KRadioAction( i18n("&Queue"), QIconSet(BarIcon("tool_queue")), 0, this,
				SLOT( slotQueue()), this, "queue" );
  m_paTimer = new KRadioAction( i18n("&Timer"), QIconSet(BarIcon("tool_timer")), 0, this,
				SLOT( slotSchedule()), this, "timer" );
  m_paDelay = new KRadioAction( i18n("De&lay"), QIconSet(BarIcon("tool_delay")), 0, this,
				SLOT( slotDelay()), this, "delay" );

  m_paQueue->setExclusiveGroup( "TransferMode" );
  m_paTimer->setExclusiveGroup( "TransferMode" );
  m_paDelay->setExclusiveGroup( "TransferMode" );

  // setup individual transfer dialog
  dlgIndividual = new DlgIndividual( this );
  if ( ksettings.b_iconifyIndividual ) {
    // TODO : iconify in kwin
//     dlgIndividual->iconify( true );
  }
}


void Transfer::copy( Transfer* orig ) {
  src = orig->src;
  dest = orig->dest;

  sources = orig->sources;

  id = orig->id;

  // WABA: The following line has been changed to work around a bug in 
  // Qt snapshot from 9 Nov 1999. It can be taken out once we move to
  // a new snapshot.
  // copyjob = orig->copyjob;
  copyjob = orig->copyjob;

  searchJob = orig->searchJob;
  highestSpeed = orig->highestSpeed;
  fastestHost = orig->fastestHost;
  b_saturated = orig->b_saturated;
  hosts = orig->hosts;
  sources = orig->sources;

  startTime = orig->startTime;

  totalSize = orig->totalSize;
  processedSize = orig->processedSize;
  percent = orig->percent;
  totalFiles = orig->totalFiles;
  processedFiles = orig->processedFiles;

  speed = orig->speed;
  remainingTime = orig->remainingTime;

  status = orig->status;
  mode = orig->mode;

  retryCount = orig->retryCount;

  canResume = orig->canResume;

  updateAll();
}


void Transfer::slotUpdateActions( Transfer*, int ) {

  switch ( status ) {
  case ST_RUNNING :
  case ST_TRYING :
    m_paResume->setEnabled( false );
    m_paPause->setEnabled( true );
    m_paRestart->setEnabled( true );
    break;
  case ST_STOPPED :
    m_paResume->setEnabled( true );
    m_paPause->setEnabled( false );
    m_paRestart->setEnabled( false );
    break;
  }

  // disable all signals
  m_paQueue->blockSignals( true );
  m_paTimer->blockSignals( true );
  m_paDelay->blockSignals( true );

  switch ( mode ) {
  case MD_QUEUED :
    m_paQueue->setChecked( true );
    break;
  case MD_SCHEDULED :
    m_paTimer->setChecked( true );
    break;
  case MD_DELAYED :
    m_paDelay->setChecked( true );
    break;
  }

  // enable all signals
  m_paQueue->blockSignals( false );
  m_paTimer->blockSignals( false );
  m_paDelay->blockSignals( false );
}


void Transfer::setSrc( const KURL& _src ) {
  src = _src;
  fastestHost = src.host();
}


void Transfer::setSpeed( unsigned long _speed ) {
  speed = _speed;

  remainingTime = KIO::calculateRemaining( totalSize, processedSize, speed );
}



void Transfer::updateAll() {
  updateStatus( 0 );  // first phase of animation

  slotCopying( 0, src, dest );
  slotCanResume( 0, canResume );
  slotTotalFiles( 0, totalFiles ); 
  slotTotalSize( 0, totalSize ); 
  slotProcessedFiles( 0, processedFiles ); 
  slotProcessedSize( 0, processedSize ); 
  slotSpeed( 0, speed ); 

  slotUpdateActions( 0, 0 );
}


bool Transfer::updateStatus( int counter ) {
  QPixmap *pix = 0L;
  bool isTransfer = false;

  if ( status == ST_RUNNING ){
    pix = view->animConn->at( counter );
    isTransfer = true;
  } else if ( status == ST_TRYING ){
    pix = view->animTry->at( counter );
    isTransfer = true;
  } else if ( status == ST_RETRYING ){
    pix = view->pixRetrying;
    isTransfer = true;
  } else if ( status == ST_STOPPED ||
	      status == ST_SIZE_CHECK ||
	      status == ST_SEARCH ) {
    if ( mode == MD_QUEUED ) {
	pix = view->pixQueued;
    } else if ( mode == MD_SCHEDULED ) {
	pix = view->pixScheduled;
    } else {
      pix = view->pixDelayed;
    }
  } else if ( status == ST_FINISHED ){
    pix = view->pixFinished;
  }

  setPixmap( view->lv_pixmap, *pix );
  return isTransfer;
}


void Transfer::slotSearch() {
  if ( !searchManager ) {
    searchManager = new FtpSiteManager();
  }

  // stop pinging hosts from previous search results
  for ( HostMap::Iterator it = hosts.begin(); it != hosts.end(); ++it ) {
    pinger->remove( it.key() );
  }

  // clear previous search results
  sources.clear();
  b_saturated = false;  // first fill the table ( check speed for all hosts )

  searchJob = new FtpSearch( searchManager->find("Lycos"), src.filename() );
  connect( searchJob, SIGNAL( foundItem( const QString&, const QString&, const QString&,
                                         const QString&, const QString& ) ),
 	   this, SLOT( slotFoundItem( const QString&, const QString&, const QString& ) ) );
  connect( searchJob, SIGNAL( result(KIO::Job*) ),
 	   this, SLOT( slotSearchResult(KIO::Job*) ) );

  // Setup search timer
  searchTimer = new QTimer( this );
  connect( searchTimer, SIGNAL( timeout() ), SLOT( slotSearchTimeout() ) );

  searchTimer->start( ksettings.timeoutSearch, TRUE ); // start a single-shot timer
  emit searchStarted();
}


void Transfer::getSize() {
  logMessage( i18n("Getting size"));

  statjob = KIO::stat(src);

  connect( statjob, SIGNAL( result( KIO::Job* ) ),
	   SLOT( slotResult( KIO::Job* ) ) );
  
  connect( statjob, SIGNAL( totalSize( KIO::Job*, unsigned long ) ),
 	   SLOT( slotTotalSize( KIO::Job*, unsigned long ) ) );
}


void Transfer::slotResume() {
  logMessage( i18n("Resuming"));

  ASSERT( status == ST_STOPPED );

  copyjob = KIO::copy( src, dest, false );
//   copyjob->copy( src, "ftp://matt@localhost/home/matt/kde/caitoo/WWW" );
//   copyjob->copy( src, "file:/home/matt/kde/tmp" );

  Connect();

  status = ST_TRYING;
  mode = MD_QUEUED;

  emit statusChanged( this, OP_RESUMED );
}


void Transfer::slotPause() {
  logMessage( i18n("Pausing"));

  ASSERT( status == ST_TRYING || status == ST_RUNNING || status == ST_RETRYING );

  if ( status != ST_RETRYING ) {
    copyjob->kill( true ); // kill the job quietly
  }
    
  mode = MD_DELAYED;
  status = ST_STOPPED;
  slotSpeed( 0, 0 );

  emit statusChanged( this, OP_PAUSED );
}


void Transfer::slotPauseOffline() {
  logMessage( i18n("Pausing - Offline"));

  if ( status == ST_TRYING || status == ST_RUNNING || status == ST_SIZE_CHECK ) {
    copyjob->kill( true ); // kill the job quietly
    status = ST_STOPPED;
  } else if ( status == ST_RETRYING ) {
    mode = MD_QUEUED;
    status = ST_STOPPED;
  }
  slotSpeed( 0, 0 );

  emit statusChanged( this, OP_PAUSED );
}


void Transfer::slotRestart() {
  logMessage( i18n("Restarting"));

  if ( status == ST_RUNNING || status == ST_TRYING ) {
    copyjob->kill( true ); // kill the job quietly
  }

  copyjob = KIO::copy( src, dest, false );
  Connect();

  status = ST_TRYING;
  mode = MD_QUEUED;

  emit statusChanged( this, OP_RESTARTED );
}


void Transfer::slotRemove() {
  logMessage( i18n("Deleting"));
  
  if ( status == ST_RUNNING || status == ST_TRYING ) {
    copyjob->kill( true ); // kill the job quietly
  }

  emit statusChanged( this, OP_REMOVED );
}


void Transfer::slotQueue() {
  logMessage( i18n("Queueing"));

  ASSERT ( mode != MD_QUEUED );
  
  mode = MD_QUEUED;
  emit statusChanged( this, OP_QUEUED );
}


void Transfer::slotSchedule() {
  logMessage( i18n("Scheduling"));

  ASSERT ( mode != MD_SCHEDULED );

  // if the time was already set somewhere in the future, keep it
  // otherwise set it to the current time + 60 seconds
  if ( startTime < QDateTime::currentDateTime() ) {
    QDateTime dt = QDateTime::currentDateTime();
    startTime = dt.addSecs( 60 );
  }

  mode = MD_SCHEDULED;
  emit statusChanged( this, OP_SCHEDULED );
}


void Transfer::slotDelay() {
  logMessage( i18n("Delaying"));

  ASSERT ( mode != MD_DELAYED );

  if ( status == ST_RUNNING || status == ST_TRYING ) {
    copyjob->kill( true ); // kill the job quietly
  }

  mode = MD_DELAYED;
  status = ST_STOPPED;
  slotSpeed( 0, 0 );

  emit statusChanged( this, OP_DELAYED );
}


void Transfer::Connect() {

  connect( copyjob, SIGNAL( canceled( KIO::Job* ) ),
	   SLOT( slotCanceled( KIO::Job* ) ) );

  connect( copyjob, SIGNAL( result( KIO::Job* ) ),
	   SLOT( slotResult( KIO::Job* ) ) );
  
  connect( copyjob, SIGNAL( totalSize( KIO::Job*, unsigned long ) ),
 	   SLOT( slotTotalSize( KIO::Job*, unsigned long ) ) );
  connect( copyjob, SIGNAL( totalFiles( KIO::Job*, unsigned long ) ),
 	   SLOT( slotTotalFiles( KIO::Job*, unsigned long ) ) );

  connect( copyjob, SIGNAL( processedSize( KIO::Job*, unsigned long ) ),
 	   SLOT( slotProcessedSize( KIO::Job*, unsigned long ) ) );
  connect( copyjob, SIGNAL( processedFiles( KIO::Job*, unsigned long ) ),
 	   SLOT( slotProcessedFiles( KIO::Job*, unsigned long ) ) );

  connect( copyjob, SIGNAL( speed( KIO::Job*, unsigned long ) ),
 	   SLOT( slotSpeed( KIO::Job*, unsigned long ) ) );

  connect( copyjob, SIGNAL( copying( KIO::Job*,  const KURL&, const KURL& ) ),
 	   SLOT( slotCopying( KIO::Job*, const KURL&, const KURL& ) ) );

  connect( copyjob, SIGNAL( renaming( KIO::Job*, const KURL&, const KURL& ) ),
 	   SLOT( slotRenaming( KIO::Job*, const KURL&, const KURL& ) ) );

  connect( copyjob, SIGNAL( canResume( KIO::Job*, bool ) ),
 	   SLOT( slotCanResume( KIO::Job*, bool ) ) );

}


void Transfer::slotCanceled( KIO::Job* ) {
  logMessage( i18n("Canceled by user"));
  emit statusChanged( this, OP_CANCELED );
}


void Transfer::slotResult( KIO::Job *job ) {
  if ( job->error() ) {
    // get formated error message
    QString msg = job->errorString();
    int errid = job->error();

    logMessage( i18n( "Error: %1").arg( msg.ascii() ));
    
    // show message only if we are in normal mode
    if ( ! ksettings.b_expertMode ){
      if ( KMessageBox::questionYesNo( kmain, msg, i18n("Message"),
				       i18n("Keep transfer"), 
				       i18n("Delete transfer")) != KMessageBox::Yes) {
	slotCanceled( job );
	return;
      }
    }

    switch ( errid ) {
    case KIO::ERR_CONNECTION_BROKEN:
    case KIO::ERR_UNKNOWN_INTERRUPT:
      // when this option is set, automatically set for restart
      if ( ksettings.b_reconnectOnBroken ) {
	status = ST_RETRYING;
	mode = MD_QUEUED;
	logMessage( i18n("Retrying broken"));
      } else {
	status = ST_STOPPED;
	mode = MD_DELAYED;
	logMessage( i18n("Broken transfer"));
      }
      break;
    case KIO::ERR_CANNOT_OPEN_FOR_READING:
    case KIO::ERR_DOES_NOT_EXIST:
    case KIO::ERR_ACCESS_DENIED:
    case KIO::ERR_CANNOT_ENTER_DIRECTORY:
    case KIO::ERR_COULD_NOT_CREATE_SOCKET:
    case KIO::ERR_COULD_NOT_CONNECT:
    case KIO::ERR_UNKNOWN_HOST:
    case KIO::ERR_UNKNOWN_PROXY_HOST:
    case KIO::ERR_COULD_NOT_READ:
    case KIO::ERR_COULD_NOT_LOGIN:
    case KIO::ERR_SERVICE_NOT_AVAILABLE:
    case KIO::ERR_UNKNOWN:
      // when this option is set, start timeout for restart
      if ( ksettings.b_reconnectOnError ) {
	retryCount--;
	if ( retryCount == 0 ) {  // no more retries
	  status = ST_STOPPED;
	  mode = MD_DELAYED;
	} else {
	  status = ST_RETRYING;
	  mode = MD_SCHEDULED;
	  startTime = QDateTime::currentDateTime().addSecs( ksettings.reconnectTime*60 );
 	  logMessage( i18n( "Attempt number %1").arg( retryCount ));
	}
      } else { // if reconnecting is not enabled - simply set to delayed
	status = ST_STOPPED;
	mode = MD_DELAYED;
      }
      break;

    }

    emit statusChanged( this, OP_ERROR );
  } else {
    // if we were only checking the size, then don't remove from the list
    if ( status == ST_SIZE_CHECK ) {
      status = ST_STOPPED;
      emit statusChanged( this, OP_SIZE_CHECKED );
    } else {
      logMessage( i18n("Download finished"));
  
      if ( ksettings.b_removeOnSuccess ) {
	emit statusChanged( this, OP_FINISHED );
      } else {
	status = ST_FINISHED;
	emit statusChanged( this, OP_FINISHED_KEEP );
      }
    }
  }
}


void Transfer::slotCopying( KIO::Job*, const KURL& from, const KURL& to) {
  src = from;
  dest = to;

  logMessage( i18n("Copying %1 to %2").arg( src.url().ascii() ).arg( dest.url().ascii() ));

  // source
  setText( view->lv_url, src.url() );

  // destination
  setText( view->lv_filename, dest.filename() );

  dlgIndividual->setCopying( src, dest );
}


void Transfer::slotRenaming( KIO::Job*, const KURL&, const KURL& to ) {
  dest = to;

  logMessage( i18n("Renaming to %1").arg( dest.url().ascii() ));

  // destination
  setText( view->lv_filename, dest.filename() );

  dlgIndividual->setCopying( src, dest );
}


void Transfer::slotCanResume( KIO::Job*, bool resume ) {
  canResume = resume;

  if ( canResume ) {
    logMessage( i18n("Download can be resumed"));
    setText( view->lv_resume, i18n("Yes") );
  } else {
    logMessage( i18n("Download can not be resumed"));
    setText( view->lv_resume, i18n("No") );
  }

  dlgIndividual->setCanResume( canResume );
}


void Transfer::slotSpeed( KIO::Job*, unsigned long bytes_per_second ) {
  setSpeed( bytes_per_second );

  if ( speed == 0 ) {
    setText( view->lv_speed, i18n("Stalled") );
    setText( view->lv_remaining, i18n("Stalled") );
  } else {
    QString tmps = i18n("%1/s").arg(KIO::convertSize(speed));
    setText( view->lv_speed, tmps );
    setText( view->lv_remaining, remainingTime.toString() );
  }

  dlgIndividual->setSpeed( speed, remainingTime );
}


void Transfer::slotTotalSize( KIO::Job*, unsigned long bytes ) {
  totalSize = bytes;

  logMessage( i18n("Total size is %1 bytes").arg( totalSize ));

  if ( status == ST_TRYING ) {
    status = ST_RUNNING;
  }
  setText( view->lv_total, KIO::convertSize( totalSize ) );

  dlgIndividual->setTotalSize( totalSize );
  dlgIndividual->setPercent( 0 );
  dlgIndividual->setProcessedSize( 0 );
}


void Transfer::slotProcessedSize( KIO::Job*, unsigned long bytes ) {
  int old = percent;
  processedSize = bytes;

  if ( totalSize == 0 ) {
    percent = 0;
  } else {
    percent = (int)(( (float)processedSize / (float)totalSize ) * 100.0);
  }
  dlgIndividual->setProcessedSize( processedSize );

  if ( percent != old ) {
    QString tmps;
    if ( percent == 100 ) {
      tmps = i18n("OK");
    } else {
      tmps.setNum(percent);
    }

    setText( view->lv_progress, tmps );

    dlgIndividual->setPercent( percent );
  }
}


void Transfer::slotTotalFiles( KIO::Job*, unsigned long files ) {
  totalFiles = files;

  logMessage( i18n("Total number of files is : %1").arg( totalFiles ));

  QString tmps;
  tmps.sprintf("%d / %d", processedFiles, totalFiles );
  setText( view->lv_count, tmps );

  dlgIndividual->setTotalFiles( totalFiles );
}


void Transfer::slotProcessedFiles( KIO::Job*, unsigned long files ) {
  processedFiles = files;

  logMessage( i18n("Processed number of files is : %1").arg( processedFiles ));

  QString tmps;
  tmps.sprintf("%d / %d", processedFiles, totalFiles );
  setText( view->lv_count, tmps );

  dlgIndividual->setProcessedFiles( processedFiles );
}


void Transfer::slotFoundItem( const QString &, const QString &host, const QString &path ) {
  sources << path;

  if ( ! hosts.contains( host ) ) {
    hosts.insert( host, -1.0 );
  }
  emit found( host );
  if ( sources.count() > ksettings.searchItems ) {
    searchJob->kill();
  }
}


void Transfer::slotSearchResult( KIO::Job *job ) {
  if ( job->error() ) {
    logMessage( i18n( "Search Error: %1").arg( job->errorText().ascii() ) );

    if ( ! ksettings.b_expertMode ) {
      KMessageBox::error( kmain, i18n("Search Error"), job->errorString() );
    }
  } else {
    logMessage( i18n( "Search finished") );
  }

  if ( sources.count() > 0 ) { // if we found anything
    HostMap::Iterator it;
    
    // add pinger hosts
    for ( it = hosts.begin(); it != hosts.end(); ++it ) {
      pinger->add( it.key() );
    }
  }
}


void Transfer::slotSearchTimeout() {
  logMessage( i18n( "Search timeout - stop searching") );
  searchJob->kill();
}


void Transfer::slotPingSpeed( QString host, float ping_speed ) {
  if ( ! b_saturated ) {  // when we are only filling the table
    if ( highestSpeed < ping_speed ) {
      highestSpeed = ping_speed;
      fastestHost = host;
    }

    hosts[host] = ping_speed;

    bool flag = true;
    for ( HostMap::Iterator it = hosts.begin(); it != hosts.end(); ++it ) {
      if ( it.data() == -1.0 ) {
	flag = false;
	break;
      }
    }

    if ( flag ) { // each host pinged at least once
      b_saturated = true;
      logMessage( i18n( "All hosts were checked for speed") );
      for ( QStringList::Iterator it = sources.begin(); it != sources.end(); ++it ) {
	KURL url( *it );
	if ( url.host() == fastestHost ) {
	  src = *it;
	  slotResume(); // start copying from the fastest host
	}
      }
    }
  } else if ( highestSpeed < ping_speed ) {

    if ( src.host() == host ) {
      highestSpeed = ping_speed; // only set a new speed maximum
    } else if ( ksettings.b_switchHosts ) {
      highestSpeed = ping_speed;
      fastestHost = host;
      
      // find a new source
      for ( QStringList::Iterator it = sources.begin(); it != sources.end(); ++it ) {
	KURL url2( *it );
	if ( url2.host() == fastestHost ) {
	  src = *it;
	  break;
	}
      }
      
      logMessage( i18n( "Switching host to: %1").arg( fastestHost ) );
      slotRestart(); // start copying from the new fastest host
    }
  }

  emit pingSpeed( host, ping_speed );
}


void Transfer::showIndividual() {
  dlgIndividual->show();
}


void Transfer::logMessage( const QString &message ) {
  kDebugInfo( 5001, message );

  emit log( id, src.filename(), message );
}


bool Transfer::read( KSimpleConfig *config, int id ) {
  QString str;

  str.sprintf( "Item%d", id );
  config->setGroup( str );
    
  src = config->readEntry( "Source", "" );
  dest = config->readEntry( "Dest", "" );

  if ( src.isEmpty() || dest.isEmpty() ) {
    return false;
  }

  if ( src.isMalformed() && ! ksettings.b_expertMode ) {
    KMessageBox::error( kmain, i18n("Malformed URL :\n") + src.url(), i18n( "Error" ) );
    return false;
  }

  mode = config->readNumEntry( "Mode", MD_QUEUED );
  status = config->readNumEntry( "Status", ST_RUNNING );
  startTime = config->readDateTimeEntry( "ScheduledTime" );
  canResume = config->readBoolEntry( "CanResume", true );
  totalSize = config->readNumEntry( "TotalSize", 0 );
  totalFiles = config->readNumEntry( "TotalFiles", 1 );
  processedSize = config->readNumEntry( "ProcessedSize", 0 );
  processedFiles = config->readNumEntry( "ProcessedFiles", 0 );

  if ( status == ST_RETRYING ) {
    mode = MD_QUEUED;
    status = ST_RUNNING;
  } else if ( status != ST_FINISHED && totalSize != 0 ) {
    status = ST_STOPPED;
  }

  updateAll();
  return true;
}


void Transfer::write( KSimpleConfig *config, int id ) {
  QString str;
  str.sprintf( "Item%d", id );

  config->setGroup( str );
  config->writeEntry( "Source", src.url() );
  config->writeEntry( "Dest", dest.url() );
  config->writeEntry( "Mode", mode );
  config->writeEntry( "Status", status );
  config->writeEntry( "CanResume", canResume );
  config->writeEntry( "TotalSize", totalSize );
  config->writeEntry( "ProcessedSize", processedSize );
  config->writeEntry( "TotalFiles", totalFiles );
  config->writeEntry( "ProcessedFiles", processedFiles );
  config->writeEntry( "ScheduledTime", startTime );
}
