kmail

kmfoldermgr.cpp
1 // kmfoldermgr.cpp
2 
3 #ifdef HAVE_CONFIG_H
4  #include <config.h>
5 #endif
6 
7 #include <sys/types.h>
8 
9 #ifdef HAVE_SYS_STAT_H
10  #include <sys/stat.h>
11 #endif
12 
13 #include <assert.h>
14 #include <fcntl.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <time.h>
18 
19 #include <tqdir.h>
20 
21 #include <tdelocale.h>
22 #include <tdemessagebox.h>
23 #include <tdeconfig.h>
24 #include <kdebug.h>
25 #include <tdeapplication.h>
26 
27 #include "kmmainwin.h"
28 #include "kmfiltermgr.h"
29 #include "kmfoldermgr.h"
30 #include "folderstorage.h"
31 #include "kmfolder.h"
32 #include "kmfoldercachedimap.h"
33 #include "kmacctcachedimap.h"
34 #include "renamejob.h"
35 #include "copyfolderjob.h"
36 
37 using KMail::RenameJob;
39 
40 //-----------------------------------------------------------------------------
41 KMFolderMgr::KMFolderMgr(const TQString& aBasePath, KMFolderDirType dirType):
42  TQObject(), mDir(this, TQString(), dirType)
43 {
44  if ( dirType == KMStandardDir )
45  mDir.setBaseURL( I18N_NOOP("Local Folders") );
46  mQuiet = 0;
47  mChanged = FALSE;
48  setBasePath(aBasePath);
49  mRemoveOrig = 0;
50 }
51 
52 
53 //-----------------------------------------------------------------------------
54 KMFolderMgr::~KMFolderMgr()
55 {
56  mBasePath = TQString();
57 }
58 
59 
60 //-----------------------------------------------------------------------------
61 void KMFolderMgr::expireAll() {
62  TDEConfig *config = KMKernel::config();
63  TDEConfigGroupSaver saver(config, "General");
64  int ret = KMessageBox::Continue;
65 
66  if (config->readBoolEntry("warn-before-expire", true)) {
67  ret = KMessageBox::warningContinueCancel(TDEMainWindow::memberList->first(),
68  i18n("Are you sure you want to expire old messages?"),
69  i18n("Expire Old Messages?"), i18n("Expire"));
70  }
71 
72  if (ret == KMessageBox::Continue) {
73  expireAllFolders( true /*immediate*/ );
74  }
75 
76 }
77 
78 #define DO_FOR_ALL(function, folder_code) \
79  KMFolderNode* node; \
80  TQPtrListIterator<KMFolderNode> it(*dir); \
81  for ( ; (node = it.current()); ) { \
82  ++it; \
83  if (node->isDir()) continue; \
84  KMFolder *folder = static_cast<KMFolder*>(node); \
85  folder_code \
86  KMFolderDir *child = folder->child(); \
87  if (child) \
88  function \
89  }
90 
91 int KMFolderMgr::folderCount(KMFolderDir *dir)
92 {
93  int count = 0;
94  if (dir == 0)
95  dir = &mDir;
96  DO_FOR_ALL(
97  {
98  count += folderCount( child );
99  },
100  {
101  count++;
102  }
103  )
104 
105  return count;
106 }
107 
108 
109 
110 //-----------------------------------------------------------------------------
111 void KMFolderMgr::compactAllFolders(bool immediate, KMFolderDir* dir)
112 {
113  if (dir == 0)
114  dir = &mDir;
115  DO_FOR_ALL(
116  {
117  compactAllFolders( immediate, child );
118  },
119  {
120  if ( folder->needsCompacting() )
121  folder->compact( immediate ? KMFolder::CompactNow : KMFolder::CompactLater );
122  }
123  )
124 }
125 
126 
127 //-----------------------------------------------------------------------------
128 void KMFolderMgr::setBasePath(const TQString& aBasePath)
129 {
130  assert(!aBasePath.isNull());
131 
132  if (aBasePath[0] == '~')
133  {
134  mBasePath = TQDir::homeDirPath();
135  mBasePath.append("/");
136  mBasePath.append(aBasePath.mid(1));
137  }
138  else
139  mBasePath = aBasePath;
140 
141  TQFileInfo info( mBasePath );
142 
143  // FIXME We should ask for an alternative dir, rather than bailing out,
144  // I guess - till
145  if ( info.exists() ) {
146  if ( !info.isDir() ) {
147  KMessageBox::sorry(0, i18n("'%1' does not appear to be a folder.\n"
148  "Please move the file out of the way.")
149  .arg( mBasePath ) );
150  ::exit(-1);
151  }
152  if ( !info.isReadable() || !info.isWritable() ) {
153  KMessageBox::sorry(0, i18n("The permissions of the folder '%1' are "
154  "incorrect;\n"
155  "please make sure that you can view and modify "
156  "the content of this folder.")
157  .arg( mBasePath ) );
158  ::exit(-1);
159  }
160  } else {
161  // ~/Mail (or whatever the user specified) doesn't exist, create it
162  if ( ::mkdir( TQFile::encodeName( mBasePath ) , S_IRWXU ) == -1 ) {
163  KMessageBox::sorry(0, i18n("KMail could not create folder '%1';\n"
164  "please make sure that you can view and "
165  "modify the content of the folder '%2'.")
166  .arg( mBasePath ).arg( TQDir::homeDirPath() ) );
167  ::exit(-1);
168  }
169  }
170  mDir.setPath(mBasePath);
171  mDir.reload();
172  contentsChanged();
173 }
174 
175 
176 //-----------------------------------------------------------------------------
177 KMFolder* KMFolderMgr::createFolder(const TQString& fName, bool sysFldr,
178  KMFolderType aFolderType,
179  KMFolderDir *aFolderDir)
180 {
181  KMFolder* fld;
182  KMFolderDir *fldDir = aFolderDir;
183 
184  if (!aFolderDir)
185  fldDir = &mDir;
186 
187  // check if this is a dimap folder and the folder we want to create has been deleted
188  // since the last sync
189  if ( fldDir->owner() && fldDir->owner()->folderType() == KMFolderTypeCachedImap ) {
190  KMFolderCachedImap *storage = static_cast<KMFolderCachedImap*>( fldDir->owner()->storage() );
191  KMAcctCachedImap *account = storage->account();
192  // guess imap path
193  TQString imapPath = storage->imapPath();
194  if ( !imapPath.endsWith( "/" ) )
195  imapPath += "/";
196  imapPath += fName;
197  if ( account->isDeletedFolder( imapPath ) || account->isDeletedFolder( imapPath + "/" )
198  || account->isPreviouslyDeletedFolder( imapPath )
199  || account->isPreviouslyDeletedFolder( imapPath + "/" ) ) {
200  KMessageBox::error( 0, i18n("A folder with the same name has been deleted since the last mail check."
201  "You need to check mails first before creating another folder with the same name."),
202  i18n("Could Not Create Folder") );
203  return 0;
204  }
205  }
206 
207  fld = fldDir->createFolder(fName, sysFldr, aFolderType);
208  if (fld) {
209  if ( fld->id() == 0 )
210  fld->setId( createId() );
211  contentsChanged();
212  emit folderAdded(fld);
213  if (kmkernel->filterMgr())
214  kmkernel->filterMgr()->folderCreated(fld);
215  }
216 
217  return fld;
218 }
219 
220 
221 //-----------------------------------------------------------------------------
222 KMFolder* KMFolderMgr::find(const TQString& folderName, bool foldersOnly)
223 {
224  KMFolderNode* node;
225 
226  for (node=mDir.first(); node; node=mDir.next())
227  {
228  if (node->isDir() && foldersOnly) continue;
229  if (node->name()==folderName) return (KMFolder*)node;
230  }
231  return 0;
232 }
233 
234 //-----------------------------------------------------------------------------
235 KMFolder* KMFolderMgr::findById(const uint id)
236 {
237  return findIdString( TQString(), id );
238 }
239 
240 //-----------------------------------------------------------------------------
241 KMFolder* KMFolderMgr::findIdString( const TQString& folderId,
242  const uint id,
243  KMFolderDir *dir )
244 {
245  if (!dir)
246  dir = &mDir;
247 
248  DO_FOR_ALL(
249  {
250  KMFolder *folder = findIdString( folderId, id, child );
251  if ( folder )
252  return folder;
253  },
254  {
255  if ( ( !folderId.isEmpty() && folder->idString() == folderId ) ||
256  ( id != 0 && folder->id() == id ) )
257  return folder;
258  }
259  )
260 
261  return 0;
262 }
263 
264 void KMFolderMgr::getFolderURLS( TQStringList& flist, const TQString& prefix,
265  KMFolderDir *adir )
266 {
267  KMFolderDir* dir = adir ? adir : &mDir;
268 
269  DO_FOR_ALL(
270  {
271  getFolderURLS( flist, prefix + "/" + folder->name(), child );
272  },
273  {
274  flist << prefix + "/" + folder->name();
275  }
276  )
277 }
278 
279 KMFolder* KMFolderMgr::getFolderByURL( const TQString& vpath,
280  const TQString& prefix,
281  KMFolderDir *adir )
282 {
283  KMFolderDir* dir = adir ? adir : &mDir;
284  DO_FOR_ALL(
285  {
286  TQString a = prefix + "/" + folder->name();
287  KMFolder * mfolder = getFolderByURL( vpath, a,child );
288  if ( mfolder )
289  return mfolder;
290  },
291  {
292  TQString comp = prefix + "/" + folder->name();
293  if ( comp == vpath )
294  return folder;
295  }
296  )
297  return 0;
298 }
299 
300 //-----------------------------------------------------------------------------
301 KMFolder* KMFolderMgr::findOrCreate(const TQString& aFolderName, bool sysFldr,
302  const uint id)
303 {
304  KMFolder* folder = 0;
305  if ( id == 0 )
306  folder = find(aFolderName);
307  else
308  folder = findById(id);
309 
310  if (!folder)
311  {
312  static bool know_type = false;
313  static KMFolderType type = KMFolderTypeMaildir;
314  if (know_type == false)
315  {
316  know_type = true;
317  TDEConfig *config = KMKernel::config();
318  TDEConfigGroupSaver saver(config, "General");
319  if (config->hasKey("default-mailbox-format"))
320  {
321  if (config->readNumEntry("default-mailbox-format", 1) == 0)
322  type = KMFolderTypeMbox;
323 
324  }
325  }
326 
327  folder = createFolder(aFolderName, sysFldr, type);
328  if (!folder) {
329  KMessageBox::error(0,(i18n("Cannot create file `%1' in %2.\nKMail cannot start without it.").arg(aFolderName).arg(mBasePath)));
330  exit(-1);
331  }
332  if ( id > 0 )
333  folder->setId( id );
334  }
335  return folder;
336 }
337 
338 
339 //-----------------------------------------------------------------------------
340 void KMFolderMgr::remove(KMFolder* aFolder)
341 {
342  if (!aFolder) return;
343  // remember the original folder to trigger contentsChanged later
344  if (!mRemoveOrig) mRemoveOrig = aFolder;
345  if (aFolder->child())
346  {
347  // call remove for every child
348  KMFolderNode* node;
349  TQPtrListIterator<KMFolderNode> it(*aFolder->child());
350  for ( ; (node = it.current()); )
351  {
352  ++it;
353  if (node->isDir()) continue;
354  KMFolder *folder = static_cast<KMFolder*>(node);
355  remove(folder);
356  }
357  }
358  emit folderRemoved(aFolder);
359  removeFolder(aFolder);
360 }
361 
362 void KMFolderMgr::removeFolder(KMFolder* aFolder)
363 {
364  connect(aFolder, TQ_SIGNAL(removed(KMFolder*, bool)),
365  this, TQ_SLOT(removeFolderAux(KMFolder*, bool)));
366  aFolder->remove();
367 }
368 
369 KMFolder* KMFolderMgr::parentFolder( KMFolder* folder )
370 {
371  // find the parent folder by stripping "." and ".directory" from the name
372  KMFolderDir* fdir = folder->parent();
373  TQString parentName = fdir->name();
374  parentName = parentName.mid( 1, parentName.length()-11 );
375  KMFolderNode* parent = fdir->hasNamedFolder( parentName );
376  if ( !parent && fdir->parent() ) // dimap obviously has a different structure
377  parent = fdir->parent()->hasNamedFolder( parentName );
378 
379  KMFolder* parentF = 0;
380  if ( parent )
381  parentF = dynamic_cast<KMFolder*>( parent );
382  return parentF;
383 }
384 
385 void KMFolderMgr::removeFolderAux(KMFolder* aFolder, bool success)
386 {
387  if (!success) {
388  mRemoveOrig = 0;
389  return;
390  }
391 
392  KMFolderDir* fdir = aFolder->parent();
393  KMFolderNode* fN;
394  for (fN = fdir->first(); fN != 0; fN = fdir->next()) {
395  if (fN->isDir() && (fN->name() == "." + aFolder->fileName() + ".directory")) {
396  removeDirAux(static_cast<KMFolderDir*>(fN));
397  break;
398  }
399  }
400  KMFolder* parentF = parentFolder( aFolder );
401 
402  // aFolder will be deleted by the next call!
403  aFolder->parent()->remove(aFolder);
404 
405  // update the children state
406  if ( parentF )
407  {
408  if ( parentF != aFolder )
409  {
410  parentF->storage()->updateChildrenState();
411  }
412  }
413  else
414  kdWarning(5006) << "Can not find parent folder" << endl;
415 
416  if (aFolder == mRemoveOrig) {
417  // call only if we're removing the original parent folder
418  contentsChanged();
419  mRemoveOrig = 0;
420  }
421 }
422 
423 void KMFolderMgr::removeDirAux(KMFolderDir* aFolderDir)
424 {
425  TQDir dir;
426  TQString folderDirLocation = aFolderDir->path();
427  aFolderDir->clear();
428  aFolderDir->parent()->remove(aFolderDir);
429  dir.rmdir(folderDirLocation);
430 }
431 
432 //-----------------------------------------------------------------------------
433 KMFolderRootDir& KMFolderMgr::dir(void)
434 {
435  return mDir;
436 }
437 
438 
439 //-----------------------------------------------------------------------------
440 void KMFolderMgr::contentsChanged(void)
441 {
442  if (mQuiet) mChanged = TRUE;
443  else emit changed();
444 }
445 
446 
447 //-----------------------------------------------------------------------------
448 void KMFolderMgr::reload(void)
449 {
450 }
451 
452 //-----------------------------------------------------------------------------
453 void KMFolderMgr::createFolderList(TQStringList *str,
454  TQValueList<TQGuardedPtr<KMFolder> > *folders)
455 {
456  createFolderList( str, folders, 0, "" );
457 }
458 
459 //-----------------------------------------------------------------------------
460 void KMFolderMgr::createI18nFolderList(TQStringList *str,
461  TQValueList<TQGuardedPtr<KMFolder> > *folders)
462 {
463  createFolderList( str, folders, 0, TQString(), true );
464 }
465 
466 //-----------------------------------------------------------------------------
467 void KMFolderMgr::createFolderList(TQStringList *str,
468  TQValueList<TQGuardedPtr<KMFolder> > *folders,
469  KMFolderDir *adir,
470  const TQString& prefix,
471  bool i18nized)
472 {
473  KMFolderDir* dir = adir ? adir : &mDir;
474 
475  DO_FOR_ALL(
476  {
477  createFolderList(str, folders, child, " " + prefix, i18nized );
478  },
479  {
480  if (i18nized)
481  str->append(prefix + folder->label());
482  else
483  str->append(prefix + folder->name());
484  folders->append( folder );
485  }
486  )
487 }
488 
489 //-----------------------------------------------------------------------------
490 void KMFolderMgr::syncAllFolders( KMFolderDir *adir )
491 {
492  KMFolderDir* dir = adir ? adir : &mDir;
493  DO_FOR_ALL(
494  {
495  syncAllFolders(child);
496  },
497  {
498  if (folder->isOpened())
499  folder->sync();
500  }
501  )
502 }
503 
504 
505 //-----------------------------------------------------------------------------
512 void KMFolderMgr::expireAllFolders(bool immediate, KMFolderDir *adir) {
513  KMFolderDir *dir = adir ? adir : &mDir;
514 
515  DO_FOR_ALL(
516  {
517  expireAllFolders(immediate, child);
518  },
519  {
520  if (folder->isAutoExpire()) {
521  folder->expireOldMessages( immediate );
522  }
523  }
524  )
525 }
526 
527 //-----------------------------------------------------------------------------
528 void KMFolderMgr::quiet(bool beQuiet)
529 {
530  if (beQuiet)
531  mQuiet++;
532  else {
533  mQuiet--;
534  if (mQuiet <= 0)
535  {
536  mQuiet = 0;
537  if (mChanged) emit changed();
538  mChanged = FALSE;
539  }
540  }
541 }
542 
543 //-----------------------------------------------------------------------------
544 void KMFolderMgr::tryReleasingFolder(KMFolder* f, KMFolderDir* adir)
545 {
546  KMFolderDir* dir = adir ? adir : &mDir;
547  DO_FOR_ALL(
548  {
549  tryReleasingFolder(f, child);
550  },
551  {
552  if (folder->isOpened())
553  folder->storage()->tryReleasingFolder(f);
554  }
555  )
556 }
557 
558 //-----------------------------------------------------------------------------
559 uint KMFolderMgr::createId()
560 {
561  int newId;
562  do
563  {
564  newId = kapp->random();
565  } while ( findById( newId ) != 0 );
566 
567  return newId;
568 }
569 
570 //-----------------------------------------------------------------------------
571 void KMFolderMgr::moveFolder( KMFolder* folder, KMFolderDir *newParent )
572 {
573  renameFolder( folder, folder->name(), newParent );
574 }
575 
576 //-----------------------------------------------------------------------------
577 void KMFolderMgr::renameFolder( KMFolder* folder, const TQString& newName,
578  KMFolderDir *newParent )
579 {
580  RenameJob* job = new RenameJob( folder->storage(), newName, newParent );
581  connect( job, TQ_SIGNAL( renameDone( TQString, bool ) ),
582  this, TQ_SLOT( slotRenameDone( TQString, bool ) ) );
583  connect( job, TQ_SIGNAL( renameDone( TQString, bool ) ),
584  this, TQ_SIGNAL( folderMoveOrCopyOperationFinished() ) );
585  job->start();
586 }
587 
588 //-----------------------------------------------------------------------------
589 void KMFolderMgr::copyFolder( KMFolder* folder, KMFolderDir *newParent )
590 {
591  kdDebug(5006) << "Copy folder: " << folder->prettyURL() << endl;
592  CopyFolderJob* job = new CopyFolderJob( folder->storage(), newParent );
593  connect( job, TQ_SIGNAL( folderCopyComplete( bool ) ),
594  this, TQ_SIGNAL( folderMoveOrCopyOperationFinished() ) );
595  job->start();
596 }
597 
598 //-----------------------------------------------------------------------------
599 void KMFolderMgr::slotRenameDone( TQString, bool success )
600 {
601  kdDebug(5006) << k_funcinfo << success << endl;
602 }
603 
604 #include "kmfoldermgr.moc"
virtual void updateChildrenState()
Updates the hasChildren() state.
virtual void tryReleasingFolder(KMFolder *)
Try releasing folder if possible, something is attempting an exclusive access to it.
KMail list that manages the contents of one directory that may contain folders and/or other directori...
Definition: kmfolderdir.h:16
virtual KMFolder * createFolder(const TQString &folderName, bool sysFldr=false, KMFolderType folderType=KMFolderTypeMbox)
Create a mail folder in this directory with given name.
Definition: kmfolderdir.cpp:95
virtual TQString path() const
Return full pathname of this directory.
virtual KMFolderNode * hasNamedFolder(const TQString &name)
Returns folder with given name or zero if it does not exist.
KMFolder * owner() const
Returns the folder whose children we are holding.
Definition: kmfolderdir.h:59
Mail folder.
Definition: kmfolder.h:69
bool isOpened() const
Test if folder is opened.
Definition: kmfolder.cpp:500
void sync()
fsync buffers to disk
Definition: kmfolder.cpp:495
TQString idString() const
Returns a string that can be used to identify this folder.
Definition: kmfolder.cpp:705
virtual TQString prettyURL() const
URL of the node for visualization purposes.
Definition: kmfolder.cpp:593
virtual TQString label() const
Returns the label of the folder for visualization.
Definition: kmfolder.cpp:581
KMFolderDir * child() const
Returns the folder directory associated with this node or 0 if no such directory exists.
Definition: kmfolder.h:157
TQString fileName() const
Returns the filename of the folder (reimplemented in KMFolderImap)
Definition: kmfolder.cpp:238
bool isAutoExpire() const
Does this folder automatically expire old messages?
Definition: kmfolder.h:417
void expireOldMessages(bool immediate)
Expire old messages in this folder.
Definition: kmfolder.cpp:801
KMFolderType folderType() const
Returns the type of this folder.
Definition: kmfolder.cpp:233
void remove()
Removes the folder physically from disk and empties the contents of the folder in memory.
Definition: kmfolder.cpp:515
Copy a hierarchy of folders somewhere else in the folder tree.
Definition: copyfolderjob.h:51
Rename and move (d)imap folders They can be moved everywhere (except search folders) as a new folder ...
Definition: renamejob.h:52