kmail

copyfolderjob.cpp

Go to the documentation of this file.
00001 
00029 #include "copyfolderjob.h"
00030 #include "folderstorage.h"
00031 #include "kmacctcachedimap.h"
00032 #include "kmfoldercachedimap.h"
00033 #include "kmfolder.h"
00034 #include "kmfolderdir.h"
00035 #include "kmfoldertype.h"
00036 #include "kmfoldermgr.h"
00037 #include "kmcommands.h"
00038 #include "kmmsgbase.h"
00039 #include "undostack.h"
00040 
00041 #include <kdebug.h>
00042 #include <klocale.h>
00043 #include <config.h>
00044 
00045 using namespace KMail;
00046 
00047 CopyFolderJob::CopyFolderJob( FolderStorage* const storage, KMFolderDir* const newParent )
00048  : FolderJob( 0, tOther, (storage ? storage->folder() : 0) ),
00049    mStorage( storage ), mNewParent( newParent ),
00050    mNewFolder( 0 ), mChildFolderNodeIterator( *mStorage->folder()->createChildFolder() ),
00051    mNextChildFolder( 0 )
00052 {
00053   mStorage->open( "copyfolder" );
00054 }
00055 
00056 CopyFolderJob::~CopyFolderJob()
00057 {
00058   kdDebug(5006) << k_funcinfo << endl;
00059   if ( mNewFolder )
00060     mNewFolder->setMoveInProgress( false );
00061   if ( mStorage )
00062   {
00063     mStorage->folder()->setMoveInProgress( false );
00064     mStorage->close( "copyfolder" );
00065   }
00066 }
00067 
00068 /*
00069  * The basic strategy is to first create the target folder, then copy all the mail
00070  * from the source to the target folder, then recurse for each of the folder's children
00071  */
00072 void CopyFolderJob::execute()
00073 {
00074   if ( createTargetDir() ) {
00075     copyMessagesToTargetDir();
00076   }
00077 }
00078 
00079 void CopyFolderJob::copyMessagesToTargetDir()
00080 {
00081   // Hmmmm. Tasty hack. Can I have fries with that?
00082   mStorage->blockSignals( true );
00083   // move all messages to the new folder
00084   QPtrList<KMMsgBase> msgList;
00085   for ( int i = 0; i < mStorage->count(); i++ )
00086   {
00087     const KMMsgBase* msgBase = mStorage->getMsgBase( i );
00088     assert( msgBase );
00089     msgList.append( msgBase );
00090   }
00091   if ( msgList.count() == 0 ) {
00092     mStorage->blockSignals( false );
00093     // ### be careful, after slotCopyNextChild() the source folder
00094     // (including mStorage) might already be deleted!
00095     slotCopyNextChild(); // no contents, check subfolders
00096   } else {
00097     KMCommand *command = new KMCopyCommand( mNewFolder, msgList );
00098     connect( command, SIGNAL( completed( KMCommand * ) ),
00099         this, SLOT( slotCopyCompleted( KMCommand * ) ) );
00100     command->start();
00101   }
00102 }
00103 
00104 void CopyFolderJob::slotCopyCompleted( KMCommand* command )
00105 {
00106   kdDebug(5006) << k_funcinfo << (command?command->result():0) << endl;
00107   disconnect( command, SIGNAL( completed( KMCommand * ) ),
00108       this, SLOT( slotCopyCompleted( KMCommand * ) ) );
00109 
00110   mStorage->blockSignals( false );
00111 
00112   if ( command && command->result() != KMCommand::OK ) {
00113     rollback();
00114     return;
00115   }
00116   // if we have children, recurse
00117   if ( mStorage->folder()->child() ) {
00118     slotCopyNextChild();
00119   } else {
00120     emit folderCopyComplete( true );
00121     deleteLater();
00122   }
00123 }
00124 
00125 void CopyFolderJob::slotCopyNextChild( bool success )
00126 {
00127   //kdDebug(5006) << k_funcinfo << endl;
00128   if ( mNextChildFolder )
00129     mNextChildFolder->close( "copyfolder" ); // refcount
00130   // previous sibling failed
00131   if ( !success ) {
00132     kdDebug(5006) << "Failed to copy one subfolder, let's not continue:  " << mNewFolder->prettyURL() << endl;
00133     rollback();
00134     emit folderCopyComplete( false );
00135     deleteLater();
00136   }
00137 
00138   KMFolderNode* node = mChildFolderNodeIterator.current();
00139   while ( node && node->isDir() ) {
00140     ++mChildFolderNodeIterator;
00141     node = mChildFolderNodeIterator.current();
00142   }
00143   if ( node ) {
00144     mNextChildFolder = static_cast<KMFolder*>(node);
00145     ++mChildFolderNodeIterator;
00146   } else {
00147     // no more children, we are done
00148     emit folderCopyComplete( true );
00149     deleteLater();
00150     return;
00151   }
00152 
00153   KMFolderDir * const dir = mNewFolder->createChildFolder();
00154   if ( !dir ) {
00155     kdDebug(5006) << "Failed to create subfolders of:  " << mNewFolder->prettyURL() << endl;
00156     emit folderCopyComplete( false );
00157     deleteLater();
00158     return;
00159   }
00160   // let it do its thing and report back when we are ready to do the next sibling
00161   mNextChildFolder->open( "copyfolder" ); // refcount
00162   FolderJob* job = new CopyFolderJob( mNextChildFolder->storage(), dir);
00163   connect( job, SIGNAL( folderCopyComplete( bool ) ),
00164            this, SLOT( slotCopyNextChild( bool ) ) );
00165   job->start();
00166 }
00167 
00168 
00169 // FIXME factor into CreateFolderJob and make async, so it works with online imap
00170 // (create folder code taken from newfolderdialog.cpp)
00171 bool CopyFolderJob::createTargetDir()
00172 {
00173   // get the default mailbox type
00174   KConfig * const config = KMKernel::config();
00175   KConfigGroupSaver saver(config, "General");
00176   int deftype = config->readNumEntry("default-mailbox-format", 1);
00177   if ( deftype < 0 || deftype > 1 ) deftype = 1;
00178 
00179   // the type of the new folder
00180   KMFolderType typenew =
00181     ( deftype == 0 ) ? KMFolderTypeMbox : KMFolderTypeMaildir;
00182   if ( mNewParent->owner() )
00183     typenew = mNewParent->owner()->folderType();
00184 
00185   bool success = false, waitForFolderCreation = false;
00186 
00187   if ( mNewParent->owner() && mNewParent->owner()->folderType() == KMFolderTypeImap ) {
00188     KMFolderImap* selectedStorage = static_cast<KMFolderImap*>( mNewParent->owner()->storage() );
00189     KMAcctImap *anAccount = selectedStorage->account();
00190     // check if a connection is available BEFORE creating the folder
00191     if (anAccount->makeConnection() == ImapAccountBase::Connected) {
00192       mNewFolder = kmkernel->imapFolderMgr()->createFolder( mStorage->folder()->name(), false, typenew, mNewParent );
00193       if ( mNewFolder ) {
00194         QString imapPath;
00195         imapPath = anAccount->createImapPath( selectedStorage->imapPath(), mStorage->folder()->name() );
00196         KMFolderImap* newStorage = static_cast<KMFolderImap*>( mNewFolder->storage() );
00197         connect( selectedStorage, SIGNAL(folderCreationResult(const QString&, bool)),
00198                  this, SLOT(folderCreationDone(const QString&, bool)) );
00199         selectedStorage->createFolder(mStorage->folder()->name(), QString::null); // create it on the server
00200         newStorage->initializeFrom( selectedStorage, imapPath, QString::null );
00201         static_cast<KMFolderImap*>(mNewParent->owner()->storage())->setAccount( selectedStorage->account() );
00202         waitForFolderCreation = true;
00203         success = true;
00204       }
00205     }
00206   } else if ( mNewParent->owner() && mNewParent->owner()->folderType() == KMFolderTypeCachedImap ) {
00207     mNewFolder = kmkernel->dimapFolderMgr()->createFolder( mStorage->folder()->name(), false, typenew, mNewParent );
00208     if ( mNewFolder ) {
00209       KMFolderCachedImap* selectedStorage = static_cast<KMFolderCachedImap*>( mNewParent->owner()->storage() );
00210       KMFolderCachedImap* newStorage = static_cast<KMFolderCachedImap*>( mNewFolder->storage() );
00211       newStorage->initializeFrom( selectedStorage );
00212       success = true;
00213     }
00214   } else {
00215     // local folder
00216     mNewFolder = kmkernel->folderMgr()->createFolder(mStorage->folder()->name(), false, typenew, mNewParent );
00217     if ( mNewFolder )
00218       success = true;
00219   }
00220 
00221   if ( !success ) {
00222       kdWarning(5006) << k_funcinfo << "could not create folder" << endl;
00223       emit folderCopyComplete( false );
00224       deleteLater();
00225       return false;
00226   }
00227 
00228   mNewFolder->setMoveInProgress( true );
00229   mStorage->folder()->setMoveInProgress( true );
00230 
00231   // inherit the folder type
00232   // FIXME we should probably copy over most if not all settings
00233   mNewFolder->storage()->setContentsType( mStorage->contentsType(), true /*quiet*/ );
00234   mNewFolder->storage()->writeConfig();
00235   kdDebug(5006)<< "CopyJob::createTargetDir - " << mStorage->folder()->idString()
00236     << " |=> " << mNewFolder->idString() << endl;
00237   return !waitForFolderCreation;
00238 }
00239 
00240 
00241 void CopyFolderJob::rollback()
00242 {
00243   // copy failed - rollback the last transaction
00244 //   kmkernel->undoStack()->undo();
00245   // .. and delete the new folder
00246   if ( mNewFolder ) {
00247     if ( mNewFolder->folderType() == KMFolderTypeImap )
00248     {
00249       kmkernel->imapFolderMgr()->remove( mNewFolder );
00250     } else if ( mNewFolder->folderType() == KMFolderTypeCachedImap )
00251     {
00252       // tell the account (see KMFolderCachedImap::listDirectory2)
00253       KMFolderCachedImap* folder = static_cast<KMFolderCachedImap*>(mNewFolder->storage());
00254       KMAcctCachedImap* acct = folder->account();
00255       if ( acct )
00256         acct->addDeletedFolder( folder->imapPath() );
00257       kmkernel->dimapFolderMgr()->remove( mNewFolder );
00258     } else if ( mNewFolder->folderType() == KMFolderTypeSearch )
00259     {
00260       // invalid
00261       kdWarning(5006) << k_funcinfo << "cannot remove a search folder" << endl;
00262     } else {
00263       kmkernel->folderMgr()->remove( mNewFolder );
00264     }
00265   }
00266 
00267   emit folderCopyComplete( false );
00268   deleteLater();
00269 }
00270 
00271 void CopyFolderJob::folderCreationDone(const QString & name, bool success)
00272 {
00273   if ( mStorage->folder()->name() != name )
00274     return; // not our business
00275   kdDebug(5006) << k_funcinfo << success << endl;
00276 
00277   if ( !success ) {
00278     rollback();
00279   } else {
00280     copyMessagesToTargetDir();
00281   }
00282 }
00283 #include "copyfolderjob.moc"