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