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
39
40//-----------------------------------------------------------------------------
41KMFolderMgr::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//-----------------------------------------------------------------------------
54KMFolderMgr::~KMFolderMgr()
55{
56 mBasePath = TQString();
57}
58
59
60//-----------------------------------------------------------------------------
61void 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
91int 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//-----------------------------------------------------------------------------
111void 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//-----------------------------------------------------------------------------
128void 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//-----------------------------------------------------------------------------
177KMFolder* 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//-----------------------------------------------------------------------------
222KMFolder* 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//-----------------------------------------------------------------------------
235KMFolder* KMFolderMgr::findById(const uint id)
236{
237 return findIdString( TQString(), id );
238}
239
240//-----------------------------------------------------------------------------
241KMFolder* 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
264void 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
279KMFolder* 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//-----------------------------------------------------------------------------
301KMFolder* 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//-----------------------------------------------------------------------------
340void 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
362void 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
369KMFolder* 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
385void 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
423void 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//-----------------------------------------------------------------------------
433KMFolderRootDir& KMFolderMgr::dir(void)
434{
435 return mDir;
436}
437
438
439//-----------------------------------------------------------------------------
440void KMFolderMgr::contentsChanged(void)
441{
442 if (mQuiet) mChanged = TRUE;
443 else emit changed();
444}
445
446
447//-----------------------------------------------------------------------------
448void KMFolderMgr::reload(void)
449{
450}
451
452//-----------------------------------------------------------------------------
453void KMFolderMgr::createFolderList(TQStringList *str,
454 TQValueList<TQGuardedPtr<KMFolder> > *folders)
455{
456 createFolderList( str, folders, 0, "" );
457}
458
459//-----------------------------------------------------------------------------
460void KMFolderMgr::createI18nFolderList(TQStringList *str,
461 TQValueList<TQGuardedPtr<KMFolder> > *folders)
462{
463 createFolderList( str, folders, 0, TQString(), true );
464}
465
466//-----------------------------------------------------------------------------
467void 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//-----------------------------------------------------------------------------
490void 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//-----------------------------------------------------------------------------
512void 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//-----------------------------------------------------------------------------
528void 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//-----------------------------------------------------------------------------
544void 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//-----------------------------------------------------------------------------
559uint KMFolderMgr::createId()
560{
561 int newId;
562 do
563 {
564 newId = tdeApp->random();
565 } while ( findById( newId ) != 0 );
566
567 return newId;
568}
569
570//-----------------------------------------------------------------------------
571void KMFolderMgr::moveFolder( KMFolder* folder, KMFolderDir *newParent )
572{
573 renameFolder( folder, folder->name(), newParent );
574}
575
576//-----------------------------------------------------------------------------
577void 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//-----------------------------------------------------------------------------
589void 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//-----------------------------------------------------------------------------
599void 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.
KMFolder * owner() const
Returns the folder whose children we are holding.
Definition: kmfolderdir.h:59
virtual KMFolderNode * hasNamedFolder(const TQString &name)
Returns folder with given name or zero if it does not exist.
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
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
KMFolderDir * child() const
Returns the folder directory associated with this node or 0 if no such directory exists.
Definition: kmfolder.h:157
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