copyfolderjob.cpp
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 <tdelocale.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 TQPtrList<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, TQT_SIGNAL( completed( KMCommand * ) ), 00099 this, TQT_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, TQT_SIGNAL( completed( KMCommand * ) ), 00108 this, TQT_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, TQT_SIGNAL( folderCopyComplete( bool ) ), 00164 this, TQT_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 TDEConfig * const config = KMKernel::config(); 00175 TDEConfigGroupSaver 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 TQString imapPath; 00195 imapPath = anAccount->createImapPath( selectedStorage->imapPath(), mStorage->folder()->name() ); 00196 KMFolderImap* newStorage = static_cast<KMFolderImap*>( mNewFolder->storage() ); 00197 connect( selectedStorage, TQT_SIGNAL(folderCreationResult(const TQString&, bool)), 00198 this, TQT_SLOT(folderCreationDone(const TQString&, bool)) ); 00199 selectedStorage->createFolder(mStorage->folder()->name(), TQString()); // create it on the server 00200 newStorage->initializeFrom( selectedStorage, imapPath, TQString() ); 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 TQString & 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"