krop's commit fixes my problem in a better way, reverting
[kdepim.git] / kmail / kmfoldermgr.cpp
blobe7ea47cf67161a82ac17c3bc122642ee4e0f6f2c
1 // kmfoldermgr.cpp
3 #include "kmfoldermgr.h"
5 #include <sys/types.h>
6 #include <sys/stat.h>
8 #include <assert.h>
9 #include <fcntl.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <time.h>
14 #include <QDir>
15 #include <QList>
17 #include <kde_file.h>
18 #include <klocale.h>
19 #include <kmessagebox.h>
20 #include <kconfig.h>
21 #include <kdebug.h>
22 #include <krandom.h>
23 #include <kconfiggroup.h>
25 #include "kmmainwin.h"
26 #include "kmfiltermgr.h"
27 #include "folderstorage.h"
28 #include "kmfolder.h"
29 #include "kmfoldercachedimap.h"
30 #include "kmacctcachedimap.h"
31 #include "renamejob.h"
32 #include "copyfolderjob.h"
34 using KMail::RenameJob;
35 using KMail::CopyFolderJob;
37 //-----------------------------------------------------------------------------
38 KMFolderMgr::KMFolderMgr(const QString& aBasePath, KMFolderDirType dirType):
39 QObject(), mDir(this, QString(), dirType)
41 if ( dirType == KMStandardDir )
42 mDir.setBaseURL( I18N_NOOP("Local Folders") );
43 mQuiet = 0;
44 mChanged = false;
45 setBasePath(aBasePath);
46 mRemoveOrig = 0;
50 //-----------------------------------------------------------------------------
51 KMFolderMgr::~KMFolderMgr()
53 mBasePath.clear();
57 //-----------------------------------------------------------------------------
58 void KMFolderMgr::expireAll() {
59 KSharedConfig::Ptr config = KMKernel::config();
60 KConfigGroup group(config, "General");
61 int ret = KMessageBox::Continue;
63 if ( group.readEntry( "warn-before-expire", true ) ) {
64 ret = KMessageBox::warningContinueCancel(KMainWindow::memberList().first(),
65 i18n("Are you sure you want to expire old messages?"),
66 i18n("Expire Old Messages?"), KGuiItem(i18n("Expire")));
69 if (ret == KMessageBox::Continue) {
70 expireAllFolders( true /*immediate*/ );
75 #define DO_FOR_ALL(function, folder_code) \
76 QList<KMFolderNode*>::const_iterator it; \
77 for ( it = dir->constBegin(); it != dir->constEnd(); ++it ) { \
78 KMFolderNode* node = *it; \
79 if (node->isDir()) continue; \
80 KMFolder *folder = static_cast<KMFolder*>(node); \
81 folder_code \
82 KMFolderDir *child = folder->child(); \
83 if (child) \
84 function \
87 int KMFolderMgr::folderCount(KMFolderDir *dir)
89 int count = 0;
90 if (dir == 0)
91 dir = &mDir;
92 DO_FOR_ALL(
94 count += folderCount( child );
97 count++;
101 return count;
106 //-----------------------------------------------------------------------------
107 void KMFolderMgr::compactAllFolders(bool immediate, KMFolderDir* dir)
109 if (dir == 0)
110 dir = &mDir;
111 DO_FOR_ALL(
113 compactAllFolders( immediate, child );
116 if ( folder->needsCompacting() )
117 folder->compact( immediate ? KMFolder::CompactNow : KMFolder::CompactLater );
123 //-----------------------------------------------------------------------------
124 void KMFolderMgr::setBasePath(const QString& aBasePath)
126 assert(!aBasePath.isEmpty());
128 if (aBasePath.startsWith('~'))
129 mBasePath = QDir::homePath() + '/' + aBasePath.mid(1);
130 else
131 mBasePath = aBasePath;
133 QFileInfo info( mBasePath );
135 // FIXME We should ask for an alternative dir, rather than bailing out,
136 // I guess - till
137 // FIXME We also should return boolean value here instead if exiting - jstaniek
138 if ( info.exists() ) {
139 if ( !info.isDir() ) {
140 KMessageBox::sorry(0, i18n("'%1' does not appear to be a folder.\n"
141 "Please move the file out of the way.",
142 mBasePath ) );
143 ::exit(-1);
145 if ( !info.isReadable() || !info.isWritable() ) {
146 KMessageBox::sorry(0, i18n("The permissions of the folder '%1' are "
147 "incorrect;\n"
148 "please make sure that you can view and modify "
149 "the content of this folder.",
150 mBasePath ) );
151 ::exit(-1);
153 } else {
154 // ~/Mail (or whatever the user specified) doesn't exist, create it
155 if ( KDE_mkdir( QFile::encodeName( mBasePath ), S_IRWXU ) == -1 ) {
156 KMessageBox::sorry( 0, i18n( "KMail could not create folder '%1';\n"
157 "please make sure that you can view and "
158 "modify the content of the folder '%2'.",
159 mBasePath, QDir::homePath() ) );
160 ::exit(-1);
163 mDir.setPath(mBasePath);
164 mDir.reload();
165 contentsChanged();
169 //-----------------------------------------------------------------------------
170 KMFolder* KMFolderMgr::createFolder(const QString& fName, bool sysFldr,
171 KMFolderType aFolderType,
172 KMFolderDir *aFolderDir)
174 KMFolder* fld;
175 KMFolderDir *fldDir = aFolderDir;
177 if (!aFolderDir)
178 fldDir = &mDir;
180 // check if this is a dimap folder and the folder we want to create has been deleted
181 // since the last sync
182 if ( fldDir->owner() && fldDir->owner()->folderType() == KMFolderTypeCachedImap ) {
183 KMFolderCachedImap *storage = static_cast<KMFolderCachedImap*>( fldDir->owner()->storage() );
184 KMAcctCachedImap *account = storage->account();
185 // guess imap path
186 QString imapPath = storage->imapPath();
187 if ( !imapPath.endsWith( '/' ) )
188 imapPath += '/';
189 imapPath += fName;
190 if ( account->isDeletedFolder( imapPath ) || account->isDeletedFolder( imapPath + '/' )
191 || account->isPreviouslyDeletedFolder( imapPath )
192 || account->isPreviouslyDeletedFolder( imapPath + '/' ) ) {
193 KMessageBox::error( 0, i18n("A folder with the same name has been deleted since the last mail check. "
194 "You need to check mails first before creating another folder with the same name."),
195 i18n("Could Not Create Folder") );
196 return 0;
200 fld = fldDir->createFolder(fName, sysFldr, aFolderType);
201 if (fld) {
202 if ( fld->id() == 0 )
203 fld->setId( createId() );
204 contentsChanged();
205 emit folderAdded(fld);
206 if (kmkernel->filterMgr())
207 kmkernel->filterMgr()->folderCreated(fld);
210 return fld;
214 //-----------------------------------------------------------------------------
215 KMFolder* KMFolderMgr::find(const QString& folderName, bool foldersOnly) const
217 QList<KMFolderNode*>::const_iterator it;
218 for ( it = mDir.begin(); it != mDir.end(); ++it )
220 KMFolderNode* node = *it;
221 if (node->isDir() && foldersOnly) continue;
222 if (node->name()==folderName) return (KMFolder*)node;
224 return 0;
227 //-----------------------------------------------------------------------------
228 KMFolder* KMFolderMgr::findById(const uint id) const
230 return findIdString( QString(), id );
233 //-----------------------------------------------------------------------------
234 KMFolder* KMFolderMgr::findIdString( const QString& folderId,
235 const uint id,
236 const KMFolderDir *dir ) const
238 if (!dir)
239 dir = &mDir;
241 DO_FOR_ALL(
243 KMFolder *folder = findIdString( folderId, id, child );
244 if ( folder )
245 return folder;
248 if ( ( !folderId.isEmpty() && folder->idString() == folderId ) ||
249 ( id != 0 && folder->id() == id ) )
250 return folder;
254 return 0;
257 void KMFolderMgr::getFolderURLS( QStringList& flist, const QString& prefix,
258 const KMFolderDir *adir ) const
260 const KMFolderDir* dir = adir ? adir : &mDir;
262 DO_FOR_ALL(
264 getFolderURLS( flist, prefix + '/' + folder->name(), child );
267 flist << prefix + '/' + folder->name();
272 KMFolder* KMFolderMgr::getFolderByURL( const QString& vpath,
273 const QString& prefix,
274 const KMFolderDir *adir ) const
276 const KMFolderDir* dir = adir ? adir : &mDir;
277 DO_FOR_ALL(
279 QString a = prefix + '/' + folder->name();
280 KMFolder * mfolder = getFolderByURL( vpath, a,child );
281 if ( mfolder )
282 return mfolder;
285 QString comp = prefix + '/' + folder->name();
286 if ( comp == vpath )
287 return folder;
290 return 0;
293 //-----------------------------------------------------------------------------
294 KMFolder* KMFolderMgr::findOrCreate(const QString& aFolderName, bool sysFldr,
295 const uint id)
297 KMFolder* folder = 0;
298 if ( id == 0 )
299 folder = find(aFolderName);
300 else
301 folder = findById(id);
303 if (!folder)
305 static bool know_type = false;
306 static KMFolderType type = KMFolderTypeMaildir;
307 if (know_type == false)
309 know_type = true;
310 KSharedConfig::Ptr config = KMKernel::config();
311 KConfigGroup group(config, "General");
312 if (group.hasKey("default-mailbox-format"))
314 if ( group.readEntry("default-mailbox-format", 1 ) == 0 )
315 type = KMFolderTypeMbox;
320 folder = createFolder(aFolderName, sysFldr, type);
321 if (!folder) {
322 KMessageBox::error(0,(i18n("Cannot create file `%1' in %2.\nKMail cannot start without it.", aFolderName, mBasePath)));
323 exit(-1);
325 if ( id > 0 )
326 folder->setId( id );
328 return folder;
332 //-----------------------------------------------------------------------------
333 void KMFolderMgr::remove(KMFolder* aFolder)
335 if ( !aFolder )
336 return;
338 // remember the original folder to trigger contentsChanged later
339 if ( !mRemoveOrig )
340 mRemoveOrig = aFolder;
342 if ( aFolder->child() )
344 // call remove for every child
345 KMFolderNodeList children = *aFolder->child();
346 foreach( KMFolderNode *child, children ) {
347 if ( child->isDir() )
348 continue;
349 KMFolder *folder = static_cast<KMFolder*>( child );
350 remove( folder );
353 emit folderRemoved(aFolder);
354 removeFolder(aFolder);
357 void KMFolderMgr::removeFolder(KMFolder* aFolder)
359 connect(aFolder, SIGNAL(removed(KMFolder*, bool)),
360 this, SLOT(removeFolderAux(KMFolder*, bool)));
361 aFolder->remove();
364 KMFolder* KMFolderMgr::parentFolder( KMFolder* folder )
366 // find the parent folder by stripping "." and ".directory" from the name
367 KMFolderDir* fdir = folder->parent();
368 QString parentName = fdir->name();
369 parentName = parentName.mid( 1, parentName.length()-11 );
370 KMFolderNode* parent = fdir->hasNamedFolder( parentName );
371 if ( !parent && fdir->parent() ) // dimap obviously has a different structure
372 parent = fdir->parent()->hasNamedFolder( parentName );
374 KMFolder* parentF = 0;
375 if ( parent )
376 parentF = dynamic_cast<KMFolder*>( parent );
377 return parentF;
380 void KMFolderMgr::removeFolderAux(KMFolder* aFolder, bool success)
382 if (!success) {
383 mRemoveOrig = 0;
384 return;
387 KMFolderDir* fdir = aFolder->parent();
388 QList<KMFolderNode*>::const_iterator it;
389 for ( it = fdir->constBegin(); it != fdir->constEnd(); ++it ) {
390 KMFolderNode* fN = *it;
391 if (fN->isDir() && (fN->name() == '.' + aFolder->fileName() + ".directory")) {
392 removeDirAux(static_cast<KMFolderDir*>(fN));
393 break;
397 KMFolder* parentF = parentFolder( aFolder );
400 // aFolder will be deleted by the next call!
401 aFolder->parent()->removeAll(aFolder);
403 // update the children state
404 if ( parentF ) {
405 if ( parentF != aFolder ) {
406 parentF->storage()->updateChildrenState();
409 else
410 kWarning() << "Can not find parent folder for " << aFolder->label().toUtf8().data();
412 if (aFolder == mRemoveOrig) {
413 // call only if we're removing the original parent folder
414 contentsChanged();
415 mRemoveOrig = 0;
419 void KMFolderMgr::removeDirAux(KMFolderDir* aFolderDir)
421 QDir dir;
422 QString folderDirLocation = aFolderDir->path();
423 aFolderDir->clear();
424 aFolderDir->parent()->removeAll(aFolderDir);
425 dir.rmdir(folderDirLocation);
428 //-----------------------------------------------------------------------------
429 KMFolderRootDir& KMFolderMgr::dir(void)
431 return mDir;
435 //-----------------------------------------------------------------------------
436 void KMFolderMgr::contentsChanged(void)
438 if (mQuiet) mChanged = true;
439 else emit changed();
443 //-----------------------------------------------------------------------------
444 void KMFolderMgr::reload(void)
448 //-----------------------------------------------------------------------------
449 void KMFolderMgr::createFolderList(QStringList *str,
450 QList<QPointer<KMFolder> > *folders)
452 createFolderList( str, folders, 0, "" );
455 //-----------------------------------------------------------------------------
456 void KMFolderMgr::createI18nFolderList(QStringList *str,
457 QList<QPointer<KMFolder> > *folders)
459 createFolderList( str, folders, 0, QString(), true );
462 //-----------------------------------------------------------------------------
463 void KMFolderMgr::createFolderList(QStringList *str,
464 QList<QPointer<KMFolder> > *folders,
465 KMFolderDir *adir,
466 const QString& prefix,
467 bool i18nized)
469 KMFolderDir* dir = adir ? adir : &mDir;
471 DO_FOR_ALL(
473 createFolderList(str, folders, child, " " + prefix, i18nized );
476 if (i18nized)
477 str->append(prefix + folder->label());
478 else
479 str->append(prefix + folder->name());
480 folders->append( folder );
485 //-----------------------------------------------------------------------------
486 void KMFolderMgr::syncAllFolders( KMFolderDir *adir )
488 KMFolderDir* dir = adir ? adir : &mDir;
489 DO_FOR_ALL(
491 syncAllFolders(child);
494 if (folder->isOpened())
495 folder->sync();
501 //-----------------------------------------------------------------------------
503 * Check each folder in turn to see if it is configured to
504 * AutoExpire. If so, expire old messages.
506 * Should be called with 0 first time around.
508 void KMFolderMgr::expireAllFolders(bool immediate, KMFolderDir *adir) {
509 KMFolderDir *dir = adir ? adir : &mDir;
511 DO_FOR_ALL(
513 expireAllFolders(immediate, child);
516 if (folder->isAutoExpire()) {
517 folder->expireOldMessages( immediate );
523 //-----------------------------------------------------------------------------
524 void KMFolderMgr::quiet(bool beQuiet)
526 if (beQuiet)
527 mQuiet++;
528 else {
529 mQuiet--;
530 if (mQuiet <= 0)
532 mQuiet = 0;
533 if (mChanged) emit changed();
534 mChanged = false;
539 //-----------------------------------------------------------------------------
540 void KMFolderMgr::tryReleasingFolder(KMFolder* f, KMFolderDir* adir)
542 KMFolderDir* dir = adir ? adir : &mDir;
543 DO_FOR_ALL(
545 tryReleasingFolder(f, child);
548 if (folder->isOpened())
549 folder->storage()->tryReleasingFolder(f);
554 //-----------------------------------------------------------------------------
555 uint KMFolderMgr::createId()
557 int newId;
560 newId = KRandom::random();
561 } while ( findById( newId ) != 0 );
563 return newId;
566 //-----------------------------------------------------------------------------
567 void KMFolderMgr::moveFolder( KMFolder* folder, KMFolderDir *newParent )
569 renameFolder( folder, folder->name(), newParent );
572 //-----------------------------------------------------------------------------
573 void KMFolderMgr::renameFolder( KMFolder* folder, const QString& newName,
574 KMFolderDir *newParent )
576 RenameJob* job = new RenameJob( folder->storage(), newName, newParent );
577 connect( job, SIGNAL( renameDone( const QString&, bool ) ),
578 this, SLOT( slotRenameDone( const QString&, bool ) ) );
579 connect( job, SIGNAL( renameDone( const QString&, bool ) ),
580 this, SIGNAL( folderMoveOrCopyOperationFinished() ) );
582 job->start();
585 //-----------------------------------------------------------------------------
586 void KMFolderMgr::copyFolder( KMFolder* folder, KMFolderDir *newParent )
588 kDebug() << "Copy folder:" << folder->prettyUrl();
589 CopyFolderJob* job = new CopyFolderJob( folder->storage(), newParent );
590 connect( job, SIGNAL( folderCopyComplete( bool ) ),
591 this, SIGNAL( folderMoveOrCopyOperationFinished() ) );
592 job->start();
595 //-----------------------------------------------------------------------------
596 void KMFolderMgr::slotRenameDone( const QString&, bool success )
598 kDebug() << success;
601 #include "kmfoldermgr.moc"