Source Code (Use browser search to find items of interest.)

Class Index

kdelibs'CopyJob (./kdelibs/kio/jobclasses.h:463)

    class CopyJob : public Job {
    Q_OBJECT

    public:
        CopyJob( const KURL::List& src, const KURL& dest, bool move, bool showProgressInfo );

    signals:

        void totalSize( KIO::Job *, unsigned long size );
        void totalFiles( KIO::Job *, unsigned long files );
        void totalDirs( KIO::Job *, unsigned long dirs );

        void processedSize( KIO::Job *, unsigned long size );
        void processedFiles( KIO::Job *, unsigned long files );
        void processedDirs( KIO::Job *, unsigned long dirs );

        void speed( KIO::Job *, unsigned long bytes_per_second );

        void copying( KIO::Job *, const KURL& from, const KURL& to );
        void moving( KIO::Job *, const KURL& from, const KURL& to );
        /**
         * The @p job is creating the directory @dir
         */
        void creatingDir( KIO::Job *, const KURL& dir );
        void renaming( KIO::Job *, const KURL& old_name, const KURL& new_name );

        // ?
        void canResume( KIO::Job *, bool can_resume );

    protected:
        void startNextJob();

        // Those aren't slots but submethods for slotResult.
        void slotResultStating( KIO::Job * job );
        void slotResultCreatingDirs( KIO::Job * job );
        void slotResultConflictCreatingDirs( KIO::Job * job );
        void createNextDir();
        void slotResultCopyingFiles( KIO::Job * job );
        void slotResultConflictCopyingFiles( KIO::Job * job );
        void copyNextFile();
        void slotResultDeletingDirs( KIO::Job * job );
        void deleteNextDir();

    protected slots:
        void slotEntries( KIO::Job*, const KIO::UDSEntryList& list );
        virtual void slotResult( KIO::Job *job );

        void slotProcessedSize( KIO::Job*, unsigned long data_size );
        void slotSpeed( KIO::Job*, unsigned long bytes_per_second );

    private:
        bool m_move;
        enum { DEST_NOT_STATED, DEST_IS_DIR, DEST_IS_FILE, DEST_DOESNT_EXIST } destinationState;
        enum { STATE_STATING, STATE_LISTING, STATE_CREATING_DIRS, STATE_CONFLICT_CREATING_DIRS,
               STATE_COPYING_FILES, STATE_CONFLICT_COPYING_FILES, STATE_DELETING_DIRS } state;
        unsigned long m_totalSize;
        unsigned long m_processedSize;
        unsigned long m_fileProcessedSize;
        QValueList<CopyInfo> files;
        QValueList<CopyInfo> dirs;
        KURL::List dirsToRemove;
        KURL::List m_srcList;
        bool m_bCurrentSrcIsDir;
        KURL m_dest;
        KURL m_currentDest;
        //
        QStringList m_skipList;
        QStringList m_overwriteList;
        bool m_bAutoSkip;
        bool m_bOverwriteAll;
        int m_conflictError;
    };


kdelibs'CopyJob::CopyJob() (./kdelibs/kio/job.cpp:964)

CopyJob::CopyJob( const KURL::List& src, const KURL& dest, bool move, bool showProgressInfo )
  : Job(showProgressInfo), m_move(move),
    destinationState(DEST_NOT_STATED), state(STATE_STATING),
      m_totalSize(0), m_processedSize(0), m_fileProcessedSize(0), m_srcList(src), m_dest(dest),
      m_bAutoSkip( false ), m_bOverwriteAll( false )
{
  if ( showProgressInfo ) {
    connect( this, SIGNAL( totalSize( KIO::Job*, unsigned long ) ),
	     Observer::self(), SLOT( slotTotalSize( KIO::Job*, unsigned long ) ) );
    connect( this, SIGNAL( totalFiles( KIO::Job*, unsigned long ) ),
	     Observer::self(), SLOT( slotTotalFiles( KIO::Job*, unsigned long ) ) );
    connect( this, SIGNAL( totalDirs( KIO::Job*, unsigned long ) ),
	     Observer::self(), SLOT( slotTotalDirs( KIO::Job*, unsigned long ) ) );

    connect( this, SIGNAL( processedSize( KIO::Job*, unsigned long ) ),
	     Observer::self(), SLOT( slotProcessedSize( KIO::Job*, unsigned long ) ) );
    connect( this, SIGNAL( processedFiles( KIO::Job*, unsigned long ) ),
	     Observer::self(), SLOT( slotProcessedFiles( KIO::Job*, unsigned long ) ) );
    connect( this, SIGNAL( processedDirs( KIO::Job*, unsigned long ) ),
	     Observer::self(), SLOT( slotProcessedDirs( KIO::Job*, unsigned long ) ) );

    connect( this, SIGNAL( speed( KIO::Job*, unsigned long ) ),
	     Observer::self(), SLOT( slotSpeed( KIO::Job*, unsigned long ) ) );

    connect( this, SIGNAL( copying( KIO::Job*, const KURL& , const KURL& ) ),
	     Observer::self(), SLOT( slotCopying( KIO::Job*, const KURL&, const KURL& ) ) );
    connect( this, SIGNAL( moving( KIO::Job*, const KURL& , const KURL& ) ),
	     Observer::self(), SLOT( slotMoving( KIO::Job*, const KURL&, const KURL& ) ) );
    connect( this, SIGNAL( creatingDir( KIO::Job*, const KURL& ) ),
	     Observer::self(), SLOT( slotCreatingDir( KIO::Job*, const KURL& ) ) );

    connect( this, SIGNAL( canResume( KIO::Job*, bool ) ),
	     Observer::self(), SLOT( slotCanResume( KIO::Job*, bool ) ) );
  }
    // Stat the dest
    KIO::Job * job = KIO::stat( m_dest );
    kdDebug(7007) << "CopyJob:stating the dest " << m_dest.url() << endl;
    addSubjob(job);
}


kdelibs'CopyJob::slotEntries() (./kdelibs/kio/job.cpp:1004)

void CopyJob::slotEntries(KIO::Job* job, const UDSEntryList& list)
{
    UDSEntryListIterator it(list);
    for (; it.current(); ++it) {
        UDSEntry::ConstIterator it2 = it.current()->begin();
        struct CopyInfo info;
        QString relName;
        for( ; it2 != it.current()->end(); it2++ ) {
            switch ((*it2).m_uds) {
                case UDS_FILE_TYPE:
                    info.type = (mode_t)((*it2).m_long);
                    break;
                case UDS_NAME:
                    relName = (*it2).m_str;
                    break;
                case UDS_LINK_DEST:
                    info.linkDest = (*it2).m_str;
                    break;
                case UDS_ACCESS:
                    info.permissions = (mode_t)((*it2).m_long);
                    break;
                case UDS_SIZE:
                    info.size = (off_t)((*it2).m_long);
                    m_totalSize += info.size;
                    break;
                case UDS_MODIFICATION_TIME:
                    info.mtime = (time_t)((*it2).m_long);
                case UDS_CREATION_TIME:
                    info.ctime = (time_t)((*it2).m_long);
                default:
                    break;
            }
        }
        if (relName != ".." && relName != ".")
        {
            kdDebug(7007) << "CopyJob::slotEntries " << relName << endl;
            info.uSource = ((SimpleJob *)job)->url();
            if ( m_bCurrentSrcIsDir ) // Only if src is a directory. Otherwise uSource is fine as is
                info.uSource.addPath( relName );
            info.uDest = m_currentDest;
            // Append filename or dirname to destination URL, except for links
            // (This is due to the way ::link is written. Alternatively,
            // we could change that...)
            if ( info.linkDest.isEmpty() && destinationState == DEST_IS_DIR )
                info.uDest.addPath( relName );
            if ( info.linkDest.isEmpty() && (S_ISDIR(info.type)) )
            {
                dirs.append( info ); // Directories
                if (m_move)
                    dirsToRemove.append( info.uSource );
            }
            else
                files.append( info ); // Files and any symlinks
        }
    }
}


kdelibs'CopyJob::startNextJob() (./kdelibs/kio/job.cpp:1061)

void CopyJob::startNextJob()
{
    files.clear();
    dirs.clear();
    KURL::List::Iterator it = m_srcList.begin();
    if (it != m_srcList.end())
    {
        // First, stat the src
        Job * job = KIO::stat( *it );
        kdDebug(7007) << "KIO::stat on " << (*it).url() << endl;
        state = STATE_STATING;
        addSubjob(job);
        // keep src url in the list, just in case we need it later
    } else
    {
        emit result(this);
        delete this;
    }
}


kdelibs'CopyJob::slotResultStating() (./kdelibs/kio/job.cpp:1081)

void CopyJob::slotResultStating( Job *job )
{
    kdDebug(7007) << "CopyJob::slotResultStating" << endl;
    // Was there an error while stating the src ?
    if (job->error() && destinationState != DEST_NOT_STATED )
    {
        // Probably : src doesn't exist
        Job::slotResult( job ); // will set the error and emit result(this)
        return;
    }

    // Is it a file or a dir ?
    UDSEntry entry = ((StatJob*)job)->statResult();
    bool bDir = false;
    bool bLink = false;
    UDSEntry::ConstIterator it2 = entry.begin();
    for( ; it2 != entry.end(); it2++ ) {
        if ( ((*it2).m_uds) == UDS_FILE_TYPE )
            bDir = S_ISDIR( (mode_t)(*it2).m_long );
        else if ( ((*it2).m_uds) == UDS_LINK_DEST )
            bLink = !((*it2).m_str.isEmpty());
    }

    if ( destinationState == DEST_NOT_STATED )
        // we were stating the dest
    {
        if (job->error())
            destinationState = DEST_DOESNT_EXIST;
        else
            // Treat symlinks to dirs as dirs here, so no test on bLink
            destinationState = bDir ? DEST_IS_DIR : DEST_IS_FILE;
        subjobs.remove( job );
        assert ( subjobs.isEmpty() ); // We should have only one job at a time ...
        startNextJob();
        return;
    }
    // We were stating the current source URL
    m_currentDest = m_dest;
    // Create a dummy list with it, for slotEntries
    UDSEntryList lst;
    lst.append(new UDSEntry(entry));

    // There 6 cases, and all end up calling slotEntries(job, lst) first :
    // 1 - src is a dir, destination is a directory,
    // slotEntries will append the source-dir-name to the destination
    // 2 - src is a dir, destination is a file, ERROR (done later on)
    // 3 - src is a dir, destination doesn't exist, then it's the destination dirname,
    // so slotEntries will use it as destination.

    // 4 - src is a file, destination is a directory,
    // slotEntries will append the filename to the destination.
    // 5 - src is a file, destination is a file, m_dest is the exact destination name
    // 6 - src is a file, destination doesn't exist, m_dest is the exact destination name
    // Tell slotEntries not to alter the src url
    m_bCurrentSrcIsDir = false;
    slotEntries(job, lst);

    KURL srcurl = ((SimpleJob*)job)->url();

    subjobs.remove( job );
    assert ( subjobs.isEmpty() ); // We should have only one job at a time ...

    if ( bDir && !bLink ) // treat symlinks as files here (no recursion)
    {
        kdDebug(7007) << " Source is a directory " << endl;

        m_bCurrentSrcIsDir = true; // used by slotEntries
        if ( destinationState == DEST_IS_DIR ) // (case 1)
            // Use <desturl>/<directory_copied> as destination, from now on
            m_currentDest.addPath( srcurl.filename() );
        else if ( destinationState == DEST_IS_FILE ) // (case 2)
        {
            m_error = ERR_IS_FILE;
            emit result(this);
            return;
        }
        else // (case 3)
            // otherwise dest is new name for toplevel dir
            // so the destination exists, in fact, from now on.
            // (This even works with other src urls in the list, since the
            //  dir has effectively been created)
            destinationState = DEST_IS_DIR;

        state = STATE_LISTING;
        ListJob *newjob = listRecursive( srcurl, false );
        connect(newjob, SIGNAL(entries( KIO::Job *,
                                        const KIO::UDSEntryList& )),
                SLOT( slotEntries( KIO::Job*,
                                   const KIO::UDSEntryList& )));
        addSubjob( newjob );
    }
    else
    {
        kdDebug(7007) << " Source is a file (or a symlink) " << endl;

	kdDebug() << "totalSize: " << m_totalSize << endl;
	// emit all signals for total numbers
	emit totalSize( this, m_totalSize );
	emit totalFiles( this, 1 );
	emit totalDirs( this, 0 );

        // Skip the "listing" stage and go directly copying the file
        state = STATE_COPYING_FILES;
        copyNextFile();
    }
}


kdelibs'CopyJob::slotResultCreatingDirs() (./kdelibs/kio/job.cpp:1188)

void CopyJob::slotResultCreatingDirs( Job * job )
{
    // The dir we are trying to create:
    QValueList<CopyInfo>::Iterator it = dirs.begin();
    // Was there an error creating a dir ?
    if ( job->error() )
    {
        m_conflictError = job->error();
        if ( (m_conflictError == ERR_DIR_ALREADY_EXIST)
             || (m_conflictError == ERR_FILE_ALREADY_EXIST) )
        {
            QString oldPath = ((SimpleJob*)job)->url().path( 1 );
            // Should we skip automatically ?
            if ( m_bAutoSkip ) {
                // We dont want to copy files in this directory, so we put it on the skip list
                m_skipList.append( oldPath );
                dirs.remove( it ); // Move on to next dir
            } else if ( m_bOverwriteAll ) { // overwrite all => just skip
                dirs.remove( it ); // Move on to next dir
            } else
            {
                assert( ((SimpleJob*)job)->url().url() == (*it).uDest.url() );
                subjobs.remove( job );
                assert ( subjobs.isEmpty() ); // We should have only one job at a time ...

                // We need to stat the existing dir, to get its last-modification time
                KURL existingDest( (*it).uDest );
                Job * newJob = KIO::stat( existingDest );
                kdDebug(7007) << "KIO::stat for resolving conflict on " << existingDest.url() << endl;
                state = STATE_CONFLICT_CREATING_DIRS;
                addSubjob(newJob);
                return; // Don't move to next dir yet !
            }
        }
        else
        {
            // Severe error, abort
            Job::slotResult( job ); // will set the error and emit result(this)
            return;
        }
    }
    else // no error : remove from list, to move on to next dir
        dirs.remove( it );

    subjobs.remove( job );
    assert ( subjobs.isEmpty() ); // We should have only one job at a time ...
    createNextDir();
}


kdelibs'CopyJob::slotResultConflictCreatingDirs() (./kdelibs/kio/job.cpp:1237)

void CopyJob::slotResultConflictCreatingDirs( KIO::Job * job )
{
    // We come here after a conflict has been detected and we've stated the existing dir

    // The dir we were trying to create:
    QValueList<CopyInfo>::Iterator it = dirs.begin();
    // Its modification time:
    time_t destmtime = (time_t)-1;
    time_t destctime = (time_t)-1;
    unsigned long destsize = 0;
    UDSEntry entry = ((KIO::StatJob*)job)->statResult();
    KIO::UDSEntry::ConstIterator it2 = entry.begin();
    for( ; it2 != entry.end(); it2++ ) {
        switch ((*it2).m_uds) {
            case UDS_MODIFICATION_TIME:
                destmtime = (time_t)((*it2).m_long);
                break;
            case UDS_CREATION_TIME:
                destctime = (time_t)((*it2).m_long);
                break;
            case UDS_SIZE:
                destsize = (*it2).m_long;
                break;
        }
    }
    subjobs.remove( job );
    assert ( subjobs.isEmpty() ); // We should have only one job at a time ...

    // Always multi and skip (since there are files after that)
    RenameDlg_Mode mode = (RenameDlg_Mode)( M_MULTI | M_SKIP );
    // Overwrite only if the existing thing is a dir (no chance with a file)
    if ( m_conflictError == ERR_DIR_ALREADY_EXIST )
        mode = (RenameDlg_Mode)( mode | M_OVERWRITE );

    QString existingDest = (*it).uDest.path();
    QString newPath;
    RenameDlg_Result r = open_RenameDlg( i18n("Directory already exists"),
                                         (*it).uSource.url(), existingDest, mode, newPath,
                                         (*it).size, destsize,
                                         (*it).ctime, destctime,
                                         (*it).mtime, destmtime );
    switch ( r ) {
        case R_CANCEL:
            m_error = ERR_USER_CANCELED;
            emit result(this);
            delete this;
            return;
        case R_RENAME:
        {
            QString oldPath = (*it).uDest.path( 1 );
            KURL newUrl( (*it).uDest );
            newUrl.setPath( newPath );
            // Change the current one and strip the trailing '/'
            (*it).uDest = newUrl.path( -1 );
            newPath = newUrl.path( 1 ); // With trailing slash
            QValueList<CopyInfo>::Iterator renamedirit = it;
            renamedirit++;
            // Change the name of subdirectories inside the directory
            for( ; renamedirit != dirs.end() ; ++renamedirit )
            {
                QString path = (*renamedirit).uDest.path();
                if ( strncmp( path, oldPath, oldPath.length() ) == 0 )
                    (*renamedirit).uDest.setPath( path.replace( 0, oldPath.length(), newPath ) );
            }
            // Change filenames inside the directory
            QValueList<CopyInfo>::Iterator renamefileit = files.begin();
            for( ; renamefileit != files.end() ; ++renamefileit )
            {
                QString path = (*renamefileit).uDest.path();
                if ( strncmp( path, oldPath, oldPath.length() ) == 0 )
                    (*renamefileit).uDest.setPath( path.replace( 0, oldPath.length(), newPath ) );
            }
        }
        break;
        case R_AUTO_SKIP:
            m_bAutoSkip = true;
            // fall through
        case R_SKIP:
            m_skipList.append( existingDest );
            // Move on to next dir
            dirs.remove( it );
            break;
        case R_OVERWRITE:
            m_overwriteList.append( existingDest );
            // Move on to next dir
            dirs.remove( it );
            break;
        case R_OVERWRITE_ALL:
            m_bOverwriteAll = true;
            // Move on to next dir
            dirs.remove( it );
            break;
        default:
            assert( 0 );
    }
    state = STATE_CREATING_DIRS;
    createNextDir();
}


kdelibs'CopyJob::createNextDir() (./kdelibs/kio/job.cpp:1336)

void CopyJob::createNextDir()
{
    // Take first dir to create out of list
    QValueList<CopyInfo>::Iterator it = dirs.begin();
    bool bCreateDir = false; // get in the loop
    QString dir = (*it).uDest.path();
    // Is this URL on the skip list or the overwrite list ?
    while( it != dirs.end() && !bCreateDir )
    {
        bCreateDir = true; // we'll create it if it's not in any list

        QStringList::Iterator sit = m_skipList.begin();
        for( ; sit != m_skipList.end() && bCreateDir; sit++ )
            // Is dir a subdirectory of *sit ?
            if ( qstrncmp( *sit, dir, (*sit).length() ) == 0 )
                bCreateDir = false; // skip this dir

        /* Don't look on the overwrite list. If a/ exists, we must still create a/b/
           (David)
        sit = m_overwriteList.begin();
        for( ; sit != m_overwriteList.end() && bCreateDir; sit++ )
            if ( strncmp( *sit, dir, (*sit).length() ) == 0 )
                bCreateDir = false; // overwrite -> it exists
        */

        if ( !bCreateDir ) {
            dirs.remove( it );
            it = dirs.begin();
        }
    }
    if ( bCreateDir ) // any dir to create, finally ?
    {
        // Create the directory - with default permissions so that we can put files into it
        // TODO : change permissions once all is finished
        KIO::Job * newjob = KIO::mkdir( (*it).uDest, -1 );
	emit creatingDir( this, (*it).uDest);
        addSubjob(newjob);
        return;
    }
    else // we have finished creating dirs
    {
        state = STATE_COPYING_FILES;
        copyNextFile();
    }
}


kdelibs'CopyJob::slotResultCopyingFiles() (./kdelibs/kio/job.cpp:1382)

void CopyJob::slotResultCopyingFiles( Job * job )
{
    // The file we were trying to copy:
    QValueList<CopyInfo>::Iterator it = files.begin();
    if ( job->error() )
    {
        m_conflictError = job->error(); // save for later
        // Existing dest ?
        if ( ( m_conflictError == ERR_FILE_ALREADY_EXIST )
          || ( m_conflictError == ERR_DIR_ALREADY_EXIST ) )
        {
            // Should we skip automatically ?
            if ( m_bAutoSkip )
                files.remove( it ); // Move on to next file
            else
            {
                subjobs.remove( job );
                assert ( subjobs.isEmpty() );
                // We need to stat the existing file, to get its last-modification time
                KURL existingFile( (*it).uDest );
                Job * newJob = KIO::stat( existingFile );
                kdDebug(7007) << "KIO::stat for resolving conflict on " << existingFile.url() << endl;
                state = STATE_CONFLICT_COPYING_FILES;
                addSubjob(newJob);
                return; // Don't move to next file yet !
            }
        }
        else
        {
            // Go directly to the conflict resolution, there is nothing to stat
            slotResultConflictCopyingFiles( job );
            return;
        }
    } else // no error : remove from list, to move on to next file
        files.remove( it );

    kdDebug() << "" << files.count() << " files remaining" << endl;
    subjobs.remove( job );
    assert ( subjobs.isEmpty() ); // We should have only one job at a time ...
    copyNextFile();
}


kdelibs'CopyJob::slotResultConflictCopyingFiles() (./kdelibs/kio/job.cpp:1424)

void CopyJob::slotResultConflictCopyingFiles( KIO::Job * job )
{
    // We come here after a conflict has been detected and we've stated the existing file
    // The file we were trying to create:
    QValueList<CopyInfo>::Iterator it = files.begin();

    RenameDlg_Result res;
    QString newPath;

    if ( ( m_conflictError == ERR_FILE_ALREADY_EXIST )
      || ( m_conflictError == ERR_DIR_ALREADY_EXIST ) )
    {
        // Its modification time:
        time_t destmtime = (time_t)-1;
        time_t destctime = (time_t)-1;
        unsigned long destsize = 0;
        UDSEntry entry = ((KIO::StatJob*)job)->statResult();
        KIO::UDSEntry::ConstIterator it2 = entry.begin();
        for( ; it2 != entry.end(); it2++ ) {
            switch ((*it2).m_uds) {
                case UDS_MODIFICATION_TIME:
                    destmtime = (time_t)((*it2).m_long);
                    break;
                case UDS_CREATION_TIME:
                    destctime = (time_t)((*it2).m_long);
                    break;
                case UDS_SIZE:
                    destsize = (*it2).m_long;
                    break;
            }
        }

        // Offer overwrite only if the existing thing is a file
        RenameDlg_Mode mode = (RenameDlg_Mode)
            ( m_conflictError == ERR_FILE_ALREADY_EXIST ? M_OVERWRITE : 0 );
        if ( files.count() > 0 ) // Not last one
            mode = (RenameDlg_Mode) ( mode | M_MULTI | M_SKIP );
        else
            mode = (RenameDlg_Mode) ( mode | M_SINGLE );
        res = open_RenameDlg( m_conflictError == ERR_FILE_ALREADY_EXIST ?
                                i18n("File already exists") : i18n("Already exists as a directory"),
                              (*it).uSource.url(), (*it).uDest.path(), mode, newPath,
                              (*it).size, destsize,
                              (*it).ctime, destctime,
                              (*it).mtime, destmtime );
    }
    else
    {
        SkipDlg_Result skipResult = open_SkipDlg( files.count() > 0,
                                                  job->errorString() );

        // Convert the return code from SkipDlg into a RenameDlg code
        res = ( skipResult == S_SKIP ) ? R_SKIP :
            ( skipResult == S_AUTO_SKIP ) ? R_AUTO_SKIP :
            R_CANCEL;
    }

    subjobs.remove( job );
    assert ( subjobs.isEmpty() );
    switch ( res ) {
        case R_CANCEL:
            m_error = ERR_USER_CANCELED;
            emit result(this);
            delete this;
            return;
        case R_RENAME:
        {
            KURL newUrl( (*it).uDest );
            newUrl.setPath( newPath );
            (*it).uDest = newUrl;
            // emit renamed ??
        }
        break;
        case R_AUTO_SKIP:
            m_bAutoSkip = true;
            // fall through
        case R_SKIP:
            // Move on to next file
            files.remove( it );
            break;
       case R_OVERWRITE_ALL:
            m_bOverwriteAll = true;
            break;
        case R_OVERWRITE:
            // Add to overwrite list, so that copyNextFile knows to overwrite
            m_overwriteList.append( (*it).uDest.path() );
            break;
        default:
            assert( 0 );
    }
    state = STATE_COPYING_FILES;
    copyNextFile();
}


kdelibs'CopyJob::copyNextFile() (./kdelibs/kio/job.cpp:1518)

void CopyJob::copyNextFile()
{
    kdDebug(7007) << "CopyJob::copyNextFile()" << endl;

    // clear processed size for last file and add it to overall processed size
    m_processedSize += m_fileProcessedSize;
    m_fileProcessedSize = 0;

    // Take the first file in the list
    QValueList<CopyInfo>::Iterator it = files.begin();
    bool bCopyFile = false; // get into the loop
    QString destFile = (*it).uDest.path();
    // Is this URL on the skip list ?
    while (it != files.end() && !bCopyFile)
    {
        bCopyFile = true;

        QStringList::Iterator sit = m_skipList.begin();
        for( ; sit != m_skipList.end() && bCopyFile; sit++ )
            // Is destFile in *sit (or a subdirectory of *sit) ?
            if ( qstrncmp( *sit, destFile, (*sit).length() ) == 0 )
                bCopyFile = false; // skip this file

        if (!bCopyFile) {
            files.remove( it );
            it = files.begin();
        }
    }

    if (bCopyFile) // any file to create, finally ?
    {
        // Do we set overwrite ?
        bool bOverwrite = m_bOverwriteAll; // yes if overwrite all
        // or if on the overwrite list
        QStringList::Iterator sit = m_overwriteList.begin();
        for( ; sit != m_overwriteList.end() && !bOverwrite; sit++ )
            if ( strncmp( *sit, destFile, (*sit).length() ) == 0 )
                bOverwrite = true;

        KIO::Job * newjob;
        if ( !(*it).linkDest.isEmpty() ) // Copying a symlink
        {
            KURL::List srcList;
            // The "source" is in fact what the existing link points to
            srcList.append( KURL( (*it).linkDest ) );
            if ( KIO::link( srcList, (*it).uDest ) )
            {
                if (m_move)
                {
                    newjob = KIO::del( (*it).uSource, false /*shred*/, false /*no GUI*/ );
                }
                else
                {
                    // Done with this one
                    files.remove( it );
                    copyNextFile();
                    return;
                }
            } else
            {
                // Error - move to next file
                files.remove( it );
                copyNextFile();
                return;
            }
        } else if (m_move) // Moving a file
        {
            newjob = KIO::file_move( (*it).uSource, (*it).uDest, (*it).permissions, bOverwrite, false, false/*no GUI*/ );
            kdDebug() << "CopyJob::copyNextFile : Moving " << (*it).uSource.url() << " to " << (*it).uDest.url() << endl;
	    emit moving( this, (*it).uSource, (*it).uDest );
        }
        else // Copying a file
        {
            newjob = KIO::file_copy( (*it).uSource, (*it).uDest, (*it).permissions, bOverwrite, false, false/*no GUI*/ );
            kdDebug() << "CopyJob::copyNextFile : Copying " << (*it).uSource.url() << " to " << (*it).uDest.url() << endl;
	    emit copying( this, (*it).uSource, (*it).uDest );
        }
        addSubjob(newjob);
	connect( newjob, SIGNAL( processedSize( KIO::Job*, unsigned long ) ),
		 this, SLOT( slotProcessedSize( KIO::Job*, unsigned long ) ) );
	connect( newjob, SIGNAL( speed( KIO::Job*, unsigned long ) ),
		 this, SLOT( slotSpeed( KIO::Job*, unsigned long ) ) );
    }
    else
    {
        if ( m_move ) // moving ? We need to delete dirs
        {
            kdDebug(7007) << "copyNextFile finished, deleting dirs" << endl;
            state = STATE_DELETING_DIRS;
            deleteNextDir();
        } else {
            // When we're done : move on to next src url
            kdDebug(7007) << "copyNextFile finished, moving to next url" << endl;
            m_srcList.remove(m_srcList.begin());
            startNextJob();
        }
    }
}


kdelibs'CopyJob::deleteNextDir() (./kdelibs/kio/job.cpp:1617)

void CopyJob::deleteNextDir()
{
    if ( !dirsToRemove.isEmpty() ) // some dirs to delete ?
    {
        // Take first dir to delete out of list - last ones first !
        KURL::List::Iterator it = dirsToRemove.fromLast();
        SimpleJob *job = KIO::rmdir( *it );
        dirsToRemove.remove(it);
        addSubjob( job );
    }
    else // We have finished deleting
    {
        m_srcList.remove(m_srcList.begin()); // done with this url
        startNextJob();
    }
}


kdelibs'CopyJob::slotProcessedSize() (./kdelibs/kio/job.cpp:1634)

void CopyJob::slotProcessedSize( KIO::Job*, unsigned long data_size )
{
  m_fileProcessedSize = data_size;

  kdDebug(7007) << "CopyJob::slotProcessedSize " << m_processedSize + m_fileProcessedSize << endl;
  emit processedSize( this, m_processedSize + m_fileProcessedSize );

  // calculate percents
  unsigned long ipercent = m_percent;

  if ( m_totalSize == 0 )
    m_percent = 100;
  else
    m_percent = (unsigned long)(( (float)(m_processedSize + m_fileProcessedSize) / (float)m_totalSize ) * 100.0);

  if ( m_percent > ipercent ) {
    emit percent( this, m_percent );
    kdDebug(7007) << "CopyJob::slotProcessedSize - percent =  " << m_percent << endl;
  }
}


kdelibs'CopyJob::slotSpeed() (./kdelibs/kio/job.cpp:1655)

void CopyJob::slotSpeed( KIO::Job*, unsigned long bytes_per_second )
{
  kdDebug(7007) << "CopyJob::slotSpeed " << bytes_per_second << endl;
  emit speed( this, bytes_per_second );
}


kdelibs'CopyJob::slotResultDeletingDirs() (./kdelibs/kio/job.cpp:1661)

void CopyJob::slotResultDeletingDirs( Job * job )
{
    if (job->error())
    {
        // Couldn't remove directory. Well, perhaps it's not empty
        // because the user pressed Skip for a given file in it.
        // Let's not display "Could not remove dir ..." for each of those dir !
    }
    subjobs.remove( job );
    assert ( subjobs.isEmpty() );
    deleteNextDir();
}


kdelibs'CopyJob::slotResult() (./kdelibs/kio/job.cpp:1674)

void CopyJob::slotResult( Job *job )
{
    kdDebug() << "CopyJob::slotResult() state=" << state << endl;
    // In each case, what we have to do is :
    // 1 - check for errors and treat them
    // 2 - subjobs.remove(job);
    // 3 - decide what to do next

    switch ( state ) {
        case STATE_STATING: // We were trying to stat a src url or the dest
            slotResultStating( job );
            break;
        case STATE_LISTING: // recursive listing finished
	    kdDebug() << "totalSize: " << m_totalSize << " files: " << files.count() << " dirs: " << dirs.count() << endl;
            // Was there an error ?
            if (job->error())
            {
                Job::slotResult( job ); // will set the error and emit result(this)
                return;
            }

            subjobs.remove( job );
            assert ( subjobs.isEmpty() ); // We should have only one job at a time ...

	    // emit all signals for total numbers
	    emit totalSize( this, m_totalSize );
	    emit totalFiles( this, files.count() );
	    emit totalDirs( this, dirs.count() );

            state = STATE_CREATING_DIRS;
            createNextDir();
            break;
        case STATE_CREATING_DIRS:
            slotResultCreatingDirs( job );
            break;
        case STATE_CONFLICT_CREATING_DIRS:
            slotResultConflictCreatingDirs( job );
            break;
        case STATE_COPYING_FILES:
            slotResultCopyingFiles( job );
            break;
        case STATE_CONFLICT_COPYING_FILES:
            slotResultConflictCopyingFiles( job );
            break;
        case STATE_DELETING_DIRS:
            slotResultDeletingDirs( job );
            break;
        default:
            assert( 0 );
    }
}