kmail

copyfolderjob.cpp
1 
29 #include "copyfolderjob.h"
30 #include "folderstorage.h"
31 #include "kmacctcachedimap.h"
32 #include "kmfoldercachedimap.h"
33 #include "kmfolder.h"
34 #include "kmfolderdir.h"
35 #include "kmfoldertype.h"
36 #include "kmfoldermgr.h"
37 #include "kmcommands.h"
38 #include "kmmsgbase.h"
39 #include "undostack.h"
40 
41 #include <kdebug.h>
42 #include <klocale.h>
43 #include <config.h>
44 
45 using namespace KMail;
46 
47 CopyFolderJob::CopyFolderJob( FolderStorage* const storage, KMFolderDir* const newParent )
48  : FolderJob( 0, tOther, (storage ? storage->folder() : 0) ),
49  mStorage( storage ), mNewParent( newParent ),
50  mNewFolder( 0 ), mChildFolderNodeIterator( *mStorage->folder()->createChildFolder() ),
51  mNextChildFolder( 0 )
52 {
53  mStorage->open( "copyfolder" );
54 }
55 
56 CopyFolderJob::~CopyFolderJob()
57 {
58  kdDebug(5006) << k_funcinfo << endl;
59  if ( mNewFolder )
60  mNewFolder->setMoveInProgress( false );
61  if ( mStorage )
62  {
63  mStorage->folder()->setMoveInProgress( false );
64  mStorage->close( "copyfolder" );
65  }
66 }
67 
68 /*
69  * The basic strategy is to first create the target folder, then copy all the mail
70  * from the source to the target folder, then recurse for each of the folder's children
71  */
72 void CopyFolderJob::execute()
73 {
74  if ( createTargetDir() ) {
76  }
77 }
78 
80 {
81  // Hmmmm. Tasty hack. Can I have fries with that?
82  mStorage->blockSignals( true );
83  // move all messages to the new folder
84  TQPtrList<KMMsgBase> msgList;
85  for ( int i = 0; i < mStorage->count(); i++ )
86  {
87  const KMMsgBase* msgBase = mStorage->getMsgBase( i );
88  assert( msgBase );
89  msgList.append( msgBase );
90  }
91  if ( msgList.count() == 0 ) {
92  mStorage->blockSignals( false );
93  // ### be careful, after slotCopyNextChild() the source folder
94  // (including mStorage) might already be deleted!
95  slotCopyNextChild(); // no contents, check subfolders
96  } else {
97  KMCommand *command = new KMCopyCommand( mNewFolder, msgList );
98  connect( command, TQT_SIGNAL( completed( KMCommand * ) ),
99  this, TQT_SLOT( slotCopyCompleted( KMCommand * ) ) );
100  command->start();
101  }
102 }
103 
104 void CopyFolderJob::slotCopyCompleted( KMCommand* command )
105 {
106  kdDebug(5006) << k_funcinfo << (command?command->result():0) << endl;
107  disconnect( command, TQT_SIGNAL( completed( KMCommand * ) ),
108  this, TQT_SLOT( slotCopyCompleted( KMCommand * ) ) );
109 
110  mStorage->blockSignals( false );
111 
112  if ( command && command->result() != KMCommand::OK ) {
113  rollback();
114  return;
115  }
116  // if we have children, recurse
117  if ( mStorage->folder()->child() ) {
119  } else {
120  emit folderCopyComplete( true );
121  deleteLater();
122  }
123 }
124 
126 {
127  //kdDebug(5006) << k_funcinfo << endl;
128  if ( mNextChildFolder )
129  mNextChildFolder->close( "copyfolder" ); // refcount
130  // previous sibling failed
131  if ( !success ) {
132  kdDebug(5006) << "Failed to copy one subfolder, let's not continue: " << mNewFolder->prettyURL() << endl;
133  rollback();
134  emit folderCopyComplete( false );
135  deleteLater();
136  }
137 
138  KMFolderNode* node = mChildFolderNodeIterator.current();
139  while ( node && node->isDir() ) {
140  ++mChildFolderNodeIterator;
141  node = mChildFolderNodeIterator.current();
142  }
143  if ( node ) {
144  mNextChildFolder = static_cast<KMFolder*>(node);
145  ++mChildFolderNodeIterator;
146  } else {
147  // no more children, we are done
148  emit folderCopyComplete( true );
149  deleteLater();
150  return;
151  }
152 
153  KMFolderDir * const dir = mNewFolder->createChildFolder();
154  if ( !dir ) {
155  kdDebug(5006) << "Failed to create subfolders of: " << mNewFolder->prettyURL() << endl;
156  emit folderCopyComplete( false );
157  deleteLater();
158  return;
159  }
160  // let it do its thing and report back when we are ready to do the next sibling
161  mNextChildFolder->open( "copyfolder" ); // refcount
162  FolderJob* job = new CopyFolderJob( mNextChildFolder->storage(), dir);
163  connect( job, TQT_SIGNAL( folderCopyComplete( bool ) ),
164  this, TQT_SLOT( slotCopyNextChild( bool ) ) );
165  job->start();
166 }
167 
168 
169 // FIXME factor into CreateFolderJob and make async, so it works with online imap
170 // (create folder code taken from newfolderdialog.cpp)
172 {
173  // get the default mailbox type
174  KConfig * const config = KMKernel::config();
175  KConfigGroupSaver saver(config, "General");
176  int deftype = config->readNumEntry("default-mailbox-format", 1);
177  if ( deftype < 0 || deftype > 1 ) deftype = 1;
178 
179  // the type of the new folder
180  KMFolderType typenew =
181  ( deftype == 0 ) ? KMFolderTypeMbox : KMFolderTypeMaildir;
182  if ( mNewParent->owner() )
183  typenew = mNewParent->owner()->folderType();
184 
185  bool success = false, waitForFolderCreation = false;
186 
187  if ( mNewParent->owner() && mNewParent->owner()->folderType() == KMFolderTypeImap ) {
188  KMFolderImap* selectedStorage = static_cast<KMFolderImap*>( mNewParent->owner()->storage() );
189  KMAcctImap *anAccount = selectedStorage->account();
190  // check if a connection is available BEFORE creating the folder
191  if (anAccount->makeConnection() == ImapAccountBase::Connected) {
192  mNewFolder = kmkernel->imapFolderMgr()->createFolder( mStorage->folder()->name(), false, typenew, mNewParent );
193  if ( mNewFolder ) {
194  TQString imapPath;
195  imapPath = anAccount->createImapPath( selectedStorage->imapPath(), mStorage->folder()->name() );
196  KMFolderImap* newStorage = static_cast<KMFolderImap*>( mNewFolder->storage() );
197  connect( selectedStorage, TQT_SIGNAL(folderCreationResult(const TQString&, bool)),
198  this, TQT_SLOT(folderCreationDone(const TQString&, bool)) );
199  selectedStorage->createFolder(mStorage->folder()->name(), TQString()); // create it on the server
200  newStorage->initializeFrom( selectedStorage, imapPath, TQString() );
201  static_cast<KMFolderImap*>(mNewParent->owner()->storage())->setAccount( selectedStorage->account() );
202  waitForFolderCreation = true;
203  success = true;
204  }
205  }
206  } else if ( mNewParent->owner() && mNewParent->owner()->folderType() == KMFolderTypeCachedImap ) {
207  mNewFolder = kmkernel->dimapFolderMgr()->createFolder( mStorage->folder()->name(), false, typenew, mNewParent );
208  if ( mNewFolder ) {
209  KMFolderCachedImap* selectedStorage = static_cast<KMFolderCachedImap*>( mNewParent->owner()->storage() );
210  KMFolderCachedImap* newStorage = static_cast<KMFolderCachedImap*>( mNewFolder->storage() );
211  newStorage->initializeFrom( selectedStorage );
212  success = true;
213  }
214  } else {
215  // local folder
216  mNewFolder = kmkernel->folderMgr()->createFolder(mStorage->folder()->name(), false, typenew, mNewParent );
217  if ( mNewFolder )
218  success = true;
219  }
220 
221  if ( !success ) {
222  kdWarning(5006) << k_funcinfo << "could not create folder" << endl;
223  emit folderCopyComplete( false );
224  deleteLater();
225  return false;
226  }
227 
228  mNewFolder->setMoveInProgress( true );
229  mStorage->folder()->setMoveInProgress( true );
230 
231  // inherit the folder type
232  // FIXME we should probably copy over most if not all settings
233  mNewFolder->storage()->setContentsType( mStorage->contentsType(), true /*quiet*/ );
234  mNewFolder->storage()->writeConfig();
235  kdDebug(5006)<< "CopyJob::createTargetDir - " << mStorage->folder()->idString()
236  << " |=> " << mNewFolder->idString() << endl;
237  return !waitForFolderCreation;
238 }
239 
240 
242 {
243  // copy failed - rollback the last transaction
244 // kmkernel->undoStack()->undo();
245  // .. and delete the new folder
246  if ( mNewFolder ) {
247  if ( mNewFolder->folderType() == KMFolderTypeImap )
248  {
249  kmkernel->imapFolderMgr()->remove( mNewFolder );
250  } else if ( mNewFolder->folderType() == KMFolderTypeCachedImap )
251  {
252  // tell the account (see KMFolderCachedImap::listDirectory2)
253  KMFolderCachedImap* folder = static_cast<KMFolderCachedImap*>(mNewFolder->storage());
254  KMAcctCachedImap* acct = folder->account();
255  if ( acct )
256  acct->addDeletedFolder( folder->imapPath() );
257  kmkernel->dimapFolderMgr()->remove( mNewFolder );
258  } else if ( mNewFolder->folderType() == KMFolderTypeSearch )
259  {
260  // invalid
261  kdWarning(5006) << k_funcinfo << "cannot remove a search folder" << endl;
262  } else {
263  kmkernel->folderMgr()->remove( mNewFolder );
264  }
265  }
266 
267  emit folderCopyComplete( false );
268  deleteLater();
269 }
270 
271 void CopyFolderJob::folderCreationDone(const TQString & name, bool success)
272 {
273  if ( mStorage->folder()->name() != name )
274  return; // not our business
275  kdDebug(5006) << k_funcinfo << success << endl;
276 
277  if ( !success ) {
278  rollback();
279  } else {
281  }
282 }
283 #include "copyfolderjob.moc"