00001
00002
00003 #ifdef HAVE_CONFIG_H
00004 #include <config.h>
00005 #endif
00006
00007 #include <sys/types.h>
00008
00009 #ifdef HAVE_SYS_STAT_H
00010 #include <sys/stat.h>
00011 #endif
00012
00013 #include <assert.h>
00014 #include <fcntl.h>
00015 #include <stdlib.h>
00016 #include <unistd.h>
00017 #include <time.h>
00018
00019 #include <qdir.h>
00020
00021 #include <klocale.h>
00022 #include <kmessagebox.h>
00023 #include <kconfig.h>
00024 #include <kdebug.h>
00025 #include <kapplication.h>
00026
00027 #include "kmmainwin.h"
00028 #include "kmfiltermgr.h"
00029 #include "kmfoldermgr.h"
00030 #include "undostack.h"
00031 #include "kmmsgdict.h"
00032 #include "folderstorage.h"
00033 #include "renamejob.h"
00034 #include "copyfolderjob.h"
00035
00036 using KMail::RenameJob;
00037 using KMail::CopyFolderJob;
00038
00039
00040 KMFolderMgr::KMFolderMgr(const QString& aBasePath, KMFolderDirType dirType):
00041 QObject(), mDir(this, QString::null, dirType)
00042 {
00043 if ( dirType == KMStandardDir )
00044 mDir.setBaseURL( I18N_NOOP("Local") );
00045 mQuiet = 0;
00046 mChanged = FALSE;
00047 setBasePath(aBasePath);
00048 mRemoveOrig = 0;
00049 }
00050
00051
00052
00053 KMFolderMgr::~KMFolderMgr()
00054 {
00055 if (kmkernel->undoStack())
00056 kmkernel->undoStack()->clear();
00057 mBasePath = QString::null;
00058 }
00059
00060
00061
00062 void KMFolderMgr::expireAll() {
00063 KConfig *config = KMKernel::config();
00064 KConfigGroupSaver saver(config, "General");
00065 int ret = KMessageBox::Continue;
00066
00067 if (config->readBoolEntry("warn-before-expire", true)) {
00068 ret = KMessageBox::warningContinueCancel(KMainWindow::memberList->first(),
00069 i18n("Are you sure you want to expire old messages?"),
00070 i18n("Expire Old Messages?"), i18n("Expire"));
00071 }
00072
00073 if (ret == KMessageBox::Continue) {
00074 expireAllFolders( true );
00075 }
00076
00077 }
00078
00079 #define DO_FOR_ALL(function, folder_code) \
00080 KMFolderNode* node; \
00081 QPtrListIterator<KMFolderNode> it(*dir); \
00082 for ( ; (node = it.current()); ) { \
00083 ++it; \
00084 if (node->isDir()) continue; \
00085 KMFolder *folder = static_cast<KMFolder*>(node); \
00086 folder_code \
00087 KMFolderDir *child = folder->child(); \
00088 if (child) \
00089 function \
00090 }
00091
00092 int KMFolderMgr::folderCount(KMFolderDir *dir)
00093 {
00094 int count = 0;
00095 if (dir == 0)
00096 dir = &mDir;
00097 DO_FOR_ALL(
00098 {
00099 count += folderCount( child );
00100 },
00101 {
00102 count++;
00103 }
00104 )
00105
00106 return count;
00107 }
00108
00109
00110
00111
00112 void KMFolderMgr::compactAllFolders(bool immediate, KMFolderDir* dir)
00113 {
00114 if (dir == 0)
00115 dir = &mDir;
00116 DO_FOR_ALL(
00117 {
00118 compactAllFolders( immediate, child );
00119 },
00120 {
00121 if ( folder->needsCompacting() )
00122 folder->compact( immediate ? KMFolder::CompactNow : KMFolder::CompactLater );
00123 }
00124 )
00125 }
00126
00127
00128
00129 void KMFolderMgr::setBasePath(const QString& aBasePath)
00130 {
00131 assert(!aBasePath.isNull());
00132
00133 if (aBasePath[0] == '~')
00134 {
00135 mBasePath = QDir::homeDirPath();
00136 mBasePath.append("/");
00137 mBasePath.append(aBasePath.mid(1));
00138 }
00139 else
00140 mBasePath = aBasePath;
00141
00142 QFileInfo info( mBasePath );
00143
00144
00145
00146 if ( info.exists() ) {
00147 if ( !info.isDir() ) {
00148 KMessageBox::sorry(0, i18n("'%1' does not appear to be a folder.\n"
00149 "Please move the file out of the way.")
00150 .arg( mBasePath ) );
00151 ::exit(-1);
00152 }
00153 if ( !info.isReadable() || !info.isWritable() ) {
00154 KMessageBox::sorry(0, i18n("The permissions of the folder '%1' are "
00155 "incorrect;\n"
00156 "please make sure that you can view and modify "
00157 "the content of this folder.")
00158 .arg( mBasePath ) );
00159 ::exit(-1);
00160 }
00161 } else {
00162
00163 if ( ::mkdir( QFile::encodeName( mBasePath ) , S_IRWXU ) == -1 ) {
00164 KMessageBox::sorry(0, i18n("KMail could not create folder '%1';\n"
00165 "please make sure that you can view and "
00166 "modify the content of the folder '%2'.")
00167 .arg( mBasePath ).arg( QDir::homeDirPath() ) );
00168 ::exit(-1);
00169 }
00170 }
00171 mDir.setPath(mBasePath);
00172 mDir.reload();
00173 contentsChanged();
00174 }
00175
00176
00177
00178 KMFolder* KMFolderMgr::createFolder(const QString& fName, bool sysFldr,
00179 KMFolderType aFolderType,
00180 KMFolderDir *aFolderDir)
00181 {
00182 KMFolder* fld;
00183 KMFolderDir *fldDir = aFolderDir;
00184
00185 if (!aFolderDir)
00186 fldDir = &mDir;
00187 fld = fldDir->createFolder(fName, sysFldr, aFolderType);
00188 if (fld) {
00189 contentsChanged();
00190 emit folderAdded(fld);
00191 if (kmkernel->filterMgr())
00192 kmkernel->filterMgr()->folderCreated(fld);
00193 }
00194
00195 return fld;
00196 }
00197
00198
00199
00200 KMFolder* KMFolderMgr::find(const QString& folderName, bool foldersOnly)
00201 {
00202 KMFolderNode* node;
00203
00204 for (node=mDir.first(); node; node=mDir.next())
00205 {
00206 if (node->isDir() && foldersOnly) continue;
00207 if (node->name()==folderName) return (KMFolder*)node;
00208 }
00209 return 0;
00210 }
00211
00212
00213 KMFolder* KMFolderMgr::findById(const uint id)
00214 {
00215 return findIdString( QString::null, id );
00216 }
00217
00218
00219 KMFolder* KMFolderMgr::findIdString( const QString& folderId,
00220 const uint id,
00221 KMFolderDir *dir )
00222 {
00223 if (!dir)
00224 dir = &mDir;
00225
00226 DO_FOR_ALL(
00227 {
00228 KMFolder *folder = findIdString( folderId, id, child );
00229 if ( folder )
00230 return folder;
00231 },
00232 {
00233 if ( ( !folderId.isEmpty() && folder->idString() == folderId ) ||
00234 ( id != 0 && folder->id() == id ) )
00235 return folder;
00236 }
00237 )
00238
00239 return 0;
00240 }
00241
00242 void KMFolderMgr::getFolderURLS( QStringList& flist, const QString& prefix,
00243 KMFolderDir *adir )
00244 {
00245 KMFolderDir* dir = adir ? adir : &mDir;
00246
00247 DO_FOR_ALL(
00248 {
00249 getFolderURLS( flist, prefix + "/" + folder->name(), child );
00250 },
00251 {
00252 flist << prefix + "/" + folder->name();
00253 }
00254 )
00255 }
00256
00257 KMFolder* KMFolderMgr::getFolderByURL( const QString& vpath,
00258 const QString& prefix,
00259 KMFolderDir *adir )
00260 {
00261 KMFolderDir* dir = adir ? adir : &mDir;
00262 DO_FOR_ALL(
00263 {
00264 QString a = prefix + "/" + folder->name();
00265 KMFolder * mfolder = getFolderByURL( vpath, a,child );
00266 if ( mfolder )
00267 return mfolder;
00268 },
00269 {
00270 QString comp = prefix + "/" + folder->name();
00271 if ( comp == vpath )
00272 return folder;
00273 }
00274 )
00275 return 0;
00276 }
00277
00278
00279 KMFolder* KMFolderMgr::findOrCreate(const QString& aFolderName, bool sysFldr,
00280 const uint id)
00281 {
00282 KMFolder* folder = 0;
00283 if ( id == 0 )
00284 folder = find(aFolderName);
00285 else
00286 folder = findById(id);
00287
00288 if (!folder)
00289 {
00290 static bool know_type = false;
00291 static KMFolderType type = KMFolderTypeMaildir;
00292 if (know_type == false)
00293 {
00294 know_type = true;
00295 KConfig *config = KMKernel::config();
00296 KConfigGroupSaver saver(config, "General");
00297 if (config->hasKey("default-mailbox-format"))
00298 {
00299 if (config->readNumEntry("default-mailbox-format", 1) == 0)
00300 type = KMFolderTypeMbox;
00301
00302 }
00303 }
00304
00305 folder = createFolder(aFolderName, sysFldr, type);
00306 if (!folder) {
00307 KMessageBox::error(0,(i18n("Cannot create file `%1' in %2.\nKMail cannot start without it.").arg(aFolderName).arg(mBasePath)));
00308 exit(-1);
00309 }
00310 if ( id > 0 )
00311 folder->setId( id );
00312 }
00313 return folder;
00314 }
00315
00316
00317
00318 void KMFolderMgr::remove(KMFolder* aFolder)
00319 {
00320 if (!aFolder) return;
00321
00322 if (!mRemoveOrig) mRemoveOrig = aFolder;
00323 if (aFolder->child())
00324 {
00325
00326 KMFolderNode* node;
00327 QPtrListIterator<KMFolderNode> it(*aFolder->child());
00328 for ( ; (node = it.current()); )
00329 {
00330 ++it;
00331 if (node->isDir()) continue;
00332 KMFolder *folder = static_cast<KMFolder*>(node);
00333 remove(folder);
00334 }
00335 }
00336 emit folderRemoved(aFolder);
00337 removeFolder(aFolder);
00338 }
00339
00340 void KMFolderMgr::removeFolder(KMFolder* aFolder)
00341 {
00342 connect(aFolder, SIGNAL(removed(KMFolder*, bool)),
00343 this, SLOT(removeFolderAux(KMFolder*, bool)));
00344 aFolder->remove();
00345 }
00346
00347 void KMFolderMgr::removeFolderAux(KMFolder* aFolder, bool success)
00348 {
00349 if (!success) {
00350 mRemoveOrig = 0;
00351 return;
00352 }
00353
00354 KMFolderDir* fdir = aFolder->parent();
00355 KMFolderNode* fN;
00356 for (fN = fdir->first(); fN != 0; fN = fdir->next()) {
00357 if (fN->isDir() && (fN->name() == "." + aFolder->fileName() + ".directory")) {
00358 removeDirAux(static_cast<KMFolderDir*>(fN));
00359 break;
00360 }
00361 }
00362 aFolder->parent()->remove(aFolder);
00363
00364 QString parentName = fdir->name();
00365 parentName = parentName.mid( 1, parentName.length()-11 );
00366 KMFolderNode* parent = fdir->hasNamedFolder( parentName );
00367 if ( !parent && fdir->parent() )
00368 parent = fdir->parent()->hasNamedFolder( parentName );
00369
00370 if ( parent )
00371 static_cast<KMFolder*>(parent)->storage()->updateChildrenState();
00372 else
00373 kdWarning(5006) << "Can not find parent folder" << endl;
00374
00375 if (aFolder == mRemoveOrig) {
00376
00377 contentsChanged();
00378 mRemoveOrig = 0;
00379 }
00380 }
00381
00382 void KMFolderMgr::removeDirAux(KMFolderDir* aFolderDir)
00383 {
00384 QDir dir;
00385 QString folderDirLocation = aFolderDir->path();
00386 aFolderDir->clear();
00387 aFolderDir->parent()->remove(aFolderDir);
00388 dir.rmdir(folderDirLocation);
00389 }
00390
00391
00392 KMFolderRootDir& KMFolderMgr::dir(void)
00393 {
00394 return mDir;
00395 }
00396
00397
00398
00399 void KMFolderMgr::contentsChanged(void)
00400 {
00401 if (mQuiet) mChanged = TRUE;
00402 else emit changed();
00403 }
00404
00405
00406
00407 void KMFolderMgr::reload(void)
00408 {
00409 }
00410
00411
00412 void KMFolderMgr::createFolderList(QStringList *str,
00413 QValueList<QGuardedPtr<KMFolder> > *folders)
00414 {
00415 createFolderList( str, folders, 0, "" );
00416 }
00417
00418
00419 void KMFolderMgr::createI18nFolderList(QStringList *str,
00420 QValueList<QGuardedPtr<KMFolder> > *folders)
00421 {
00422 createFolderList( str, folders, 0, QString::null, true );
00423 }
00424
00425
00426 void KMFolderMgr::createFolderList(QStringList *str,
00427 QValueList<QGuardedPtr<KMFolder> > *folders,
00428 KMFolderDir *adir,
00429 const QString& prefix,
00430 bool i18nized)
00431 {
00432 KMFolderDir* dir = adir ? adir : &mDir;
00433
00434 DO_FOR_ALL(
00435 {
00436 createFolderList(str, folders, child, " " + prefix, i18nized );
00437 },
00438 {
00439 if (i18nized)
00440 str->append(prefix + folder->label());
00441 else
00442 str->append(prefix + folder->name());
00443 folders->append( folder );
00444 }
00445 )
00446 }
00447
00448
00449 void KMFolderMgr::syncAllFolders( KMFolderDir *adir )
00450 {
00451 KMFolderDir* dir = adir ? adir : &mDir;
00452 DO_FOR_ALL(
00453 {
00454 syncAllFolders(child);
00455 },
00456 {
00457 if (folder->isOpened())
00458 folder->sync();
00459 }
00460 )
00461 }
00462
00463
00464
00471 void KMFolderMgr::expireAllFolders(bool immediate, KMFolderDir *adir) {
00472 KMFolderDir *dir = adir ? adir : &mDir;
00473
00474 DO_FOR_ALL(
00475 {
00476 expireAllFolders(immediate, child);
00477 },
00478 {
00479 if (folder->isAutoExpire()) {
00480 folder->expireOldMessages( immediate );
00481 }
00482 }
00483 )
00484 }
00485
00486
00487 void KMFolderMgr::invalidateFolder(KMMsgDict *dict, KMFolder *folder)
00488 {
00489 unlink(QFile::encodeName(folder->indexLocation()) + ".sorted");
00490 unlink(QFile::encodeName(folder->indexLocation()) + ".ids");
00491 if (dict) {
00492 folder->fillMsgDict(dict);
00493 dict->writeFolderIds(folder);
00494 }
00495 emit folderInvalidated(folder);
00496 }
00497
00498
00499 void KMFolderMgr::readMsgDict(KMMsgDict *dict, KMFolderDir *dir, int pass)
00500 {
00501 bool atTop = false;
00502 if (!dir) {
00503 dir = &mDir;
00504 atTop = true;
00505 }
00506
00507 DO_FOR_ALL(
00508 {
00509 readMsgDict(dict, child, pass);
00510 },
00511 {
00512 if (pass == 1) {
00513 dict->readFolderIds(folder);
00514 } else if (pass == 2) {
00515 if (!dict->hasFolderIds(folder)) {
00516 invalidateFolder(dict, folder);
00517 }
00518 }
00519 }
00520 )
00521
00522 if (pass == 1 && atTop)
00523 readMsgDict(dict, dir, pass + 1);
00524 }
00525
00526
00527 void KMFolderMgr::writeMsgDict(KMMsgDict *dict, KMFolderDir *dir)
00528 {
00529 if (!dir)
00530 dir = &mDir;
00531
00532 DO_FOR_ALL(
00533 {
00534 writeMsgDict(dict, child);
00535 },
00536 {
00537 folder->writeMsgDict(dict);
00538 }
00539 )
00540 }
00541
00542
00543 void KMFolderMgr::quiet(bool beQuiet)
00544 {
00545 if (beQuiet)
00546 mQuiet++;
00547 else {
00548 mQuiet--;
00549 if (mQuiet <= 0)
00550 {
00551 mQuiet = 0;
00552 if (mChanged) emit changed();
00553 mChanged = FALSE;
00554 }
00555 }
00556 }
00557
00558
00559 void KMFolderMgr::tryReleasingFolder(KMFolder* f, KMFolderDir* adir)
00560 {
00561 KMFolderDir* dir = adir ? adir : &mDir;
00562 DO_FOR_ALL(
00563 {
00564 tryReleasingFolder(f, child);
00565 },
00566 {
00567 if (folder->isOpened())
00568 folder->storage()->tryReleasingFolder(f);
00569 }
00570 )
00571 }
00572
00573
00574 uint KMFolderMgr::createId()
00575 {
00576 int newId;
00577 do
00578 {
00579 newId = kapp->random();
00580 } while ( findById( newId ) != 0 );
00581
00582 return newId;
00583 }
00584
00585
00586 void KMFolderMgr::moveFolder( KMFolder* folder, KMFolderDir *newParent )
00587 {
00588 renameFolder( folder, folder->name(), newParent );
00589 }
00590
00591
00592 void KMFolderMgr::renameFolder( KMFolder* folder, const QString& newName,
00593 KMFolderDir *newParent )
00594 {
00595 RenameJob* job = new RenameJob( folder->storage(), newName, newParent );
00596 connect( job, SIGNAL( renameDone( QString, bool ) ),
00597 this, SLOT( slotRenameDone( QString, bool ) ) );
00598 job->start();
00599 }
00600
00601
00602 void KMFolderMgr::copyFolder( KMFolder* folder, KMFolderDir *newParent )
00603 {
00604 kdDebug(5006) << "Copy folder: " << folder->prettyURL() << endl;
00605 CopyFolderJob* job = new CopyFolderJob( folder->storage(), newParent );
00606 job->start();
00607 }
00608
00609
00610 void KMFolderMgr::slotRenameDone( QString, bool success )
00611 {
00612 kdDebug(5006) << k_funcinfo << success << endl;
00613 }
00614
00615 #include "kmfoldermgr.moc"