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