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 {
00408 if ( parentF != aFolder )
00409 {
00410 parentF->storage()->updateChildrenState();
00411 }
00412 }
00413 else
00414 kdWarning(5006) << "Can not find parent folder" << endl;
00415
00416 if (aFolder == mRemoveOrig) {
00417
00418 contentsChanged();
00419 mRemoveOrig = 0;
00420 }
00421 }
00422
00423 void KMFolderMgr::removeDirAux(KMFolderDir* aFolderDir)
00424 {
00425 QDir dir;
00426 QString folderDirLocation = aFolderDir->path();
00427 aFolderDir->clear();
00428 aFolderDir->parent()->remove(aFolderDir);
00429 dir.rmdir(folderDirLocation);
00430 }
00431
00432
00433 KMFolderRootDir& KMFolderMgr::dir(void)
00434 {
00435 return mDir;
00436 }
00437
00438
00439
00440 void KMFolderMgr::contentsChanged(void)
00441 {
00442 if (mQuiet) mChanged = TRUE;
00443 else emit changed();
00444 }
00445
00446
00447
00448 void KMFolderMgr::reload(void)
00449 {
00450 }
00451
00452
00453 void KMFolderMgr::createFolderList(QStringList *str,
00454 QValueList<QGuardedPtr<KMFolder> > *folders)
00455 {
00456 createFolderList( str, folders, 0, "" );
00457 }
00458
00459
00460 void KMFolderMgr::createI18nFolderList(QStringList *str,
00461 QValueList<QGuardedPtr<KMFolder> > *folders)
00462 {
00463 createFolderList( str, folders, 0, QString::null, true );
00464 }
00465
00466
00467 void KMFolderMgr::createFolderList(QStringList *str,
00468 QValueList<QGuardedPtr<KMFolder> > *folders,
00469 KMFolderDir *adir,
00470 const QString& prefix,
00471 bool i18nized)
00472 {
00473 KMFolderDir* dir = adir ? adir : &mDir;
00474
00475 DO_FOR_ALL(
00476 {
00477 createFolderList(str, folders, child, " " + prefix, i18nized );
00478 },
00479 {
00480 if (i18nized)
00481 str->append(prefix + folder->label());
00482 else
00483 str->append(prefix + folder->name());
00484 folders->append( folder );
00485 }
00486 )
00487 }
00488
00489
00490 void KMFolderMgr::syncAllFolders( KMFolderDir *adir )
00491 {
00492 KMFolderDir* dir = adir ? adir : &mDir;
00493 DO_FOR_ALL(
00494 {
00495 syncAllFolders(child);
00496 },
00497 {
00498 if (folder->isOpened())
00499 folder->sync();
00500 }
00501 )
00502 }
00503
00504
00505
00512 void KMFolderMgr::expireAllFolders(bool immediate, KMFolderDir *adir) {
00513 KMFolderDir *dir = adir ? adir : &mDir;
00514
00515 DO_FOR_ALL(
00516 {
00517 expireAllFolders(immediate, child);
00518 },
00519 {
00520 if (folder->isAutoExpire()) {
00521 folder->expireOldMessages( immediate );
00522 }
00523 }
00524 )
00525 }
00526
00527
00528 void KMFolderMgr::quiet(bool beQuiet)
00529 {
00530 if (beQuiet)
00531 mQuiet++;
00532 else {
00533 mQuiet--;
00534 if (mQuiet <= 0)
00535 {
00536 mQuiet = 0;
00537 if (mChanged) emit changed();
00538 mChanged = FALSE;
00539 }
00540 }
00541 }
00542
00543
00544 void KMFolderMgr::tryReleasingFolder(KMFolder* f, KMFolderDir* adir)
00545 {
00546 KMFolderDir* dir = adir ? adir : &mDir;
00547 DO_FOR_ALL(
00548 {
00549 tryReleasingFolder(f, child);
00550 },
00551 {
00552 if (folder->isOpened())
00553 folder->storage()->tryReleasingFolder(f);
00554 }
00555 )
00556 }
00557
00558
00559 uint KMFolderMgr::createId()
00560 {
00561 int newId;
00562 do
00563 {
00564 newId = kapp->random();
00565 } while ( findById( newId ) != 0 );
00566
00567 return newId;
00568 }
00569
00570
00571 void KMFolderMgr::moveFolder( KMFolder* folder, KMFolderDir *newParent )
00572 {
00573 renameFolder( folder, folder->name(), newParent );
00574 }
00575
00576
00577 void KMFolderMgr::renameFolder( KMFolder* folder, const QString& newName,
00578 KMFolderDir *newParent )
00579 {
00580 RenameJob* job = new RenameJob( folder->storage(), newName, newParent );
00581 connect( job, SIGNAL( renameDone( QString, bool ) ),
00582 this, SLOT( slotRenameDone( QString, bool ) ) );
00583 connect( job, SIGNAL( renameDone( QString, bool ) ),
00584 this, SIGNAL( folderMoveOrCopyOperationFinished() ) );
00585 job->start();
00586 }
00587
00588
00589 void KMFolderMgr::copyFolder( KMFolder* folder, KMFolderDir *newParent )
00590 {
00591 kdDebug(5006) << "Copy folder: " << folder->prettyURL() << endl;
00592 CopyFolderJob* job = new CopyFolderJob( folder->storage(), newParent );
00593 connect( job, SIGNAL( folderCopyComplete( bool ) ),
00594 this, SIGNAL( folderMoveOrCopyOperationFinished() ) );
00595 job->start();
00596 }
00597
00598
00599 void KMFolderMgr::slotRenameDone( QString, bool success )
00600 {
00601 kdDebug(5006) << k_funcinfo << success << endl;
00602 }
00603
00604 #include "kmfoldermgr.moc"