kmfoldermgr.cpp
00001 // kmfoldermgr.cpp 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 <tqdir.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 TQString& aBasePath, KMFolderDirType dirType): 00042 TQObject(), mDir(this, TQString(), 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 = TQString(); 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 /*immediate*/ ); 00074 } 00075 00076 } 00077 00078 #define DO_FOR_ALL(function, folder_code) \ 00079 KMFolderNode* node; \ 00080 TQPtrListIterator<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 TQString& aBasePath) 00129 { 00130 assert(!aBasePath.isNull()); 00131 00132 if (aBasePath[0] == '~') 00133 { 00134 mBasePath = TQDir::homeDirPath(); 00135 mBasePath.append("/"); 00136 mBasePath.append(aBasePath.mid(1)); 00137 } 00138 else 00139 mBasePath = aBasePath; 00140 00141 TQFileInfo info( mBasePath ); 00142 00143 // FIXME We should ask for an alternative dir, rather than bailing out, 00144 // I guess - till 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 // ~/Mail (or whatever the user specified) doesn't exist, create it 00162 if ( ::mkdir( TQFile::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( TQDir::homeDirPath() ) ); 00167 ::exit(-1); 00168 } 00169 } 00170 mDir.setPath(mBasePath); 00171 mDir.reload(); 00172 contentsChanged(); 00173 } 00174 00175 00176 //----------------------------------------------------------------------------- 00177 KMFolder* KMFolderMgr::createFolder(const TQString& 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 // check if this is a dimap folder and the folder we want to create has been deleted 00188 // since the last sync 00189 if ( fldDir->owner() && fldDir->owner()->folderType() == KMFolderTypeCachedImap ) { 00190 KMFolderCachedImap *storage = static_cast<KMFolderCachedImap*>( fldDir->owner()->storage() ); 00191 KMAcctCachedImap *account = storage->account(); 00192 // guess imap path 00193 TQString 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 TQString& 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( TQString(), id ); 00238 } 00239 00240 //----------------------------------------------------------------------------- 00241 KMFolder* KMFolderMgr::findIdString( const TQString& 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( TQStringList& flist, const TQString& 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 TQString& vpath, 00280 const TQString& prefix, 00281 KMFolderDir *adir ) 00282 { 00283 KMFolderDir* dir = adir ? adir : &mDir; 00284 DO_FOR_ALL( 00285 { 00286 TQString a = prefix + "/" + folder->name(); 00287 KMFolder * mfolder = getFolderByURL( vpath, a,child ); 00288 if ( mfolder ) 00289 return mfolder; 00290 }, 00291 { 00292 TQString comp = prefix + "/" + folder->name(); 00293 if ( comp == vpath ) 00294 return folder; 00295 } 00296 ) 00297 return 0; 00298 } 00299 00300 //----------------------------------------------------------------------------- 00301 KMFolder* KMFolderMgr::findOrCreate(const TQString& 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 // remember the original folder to trigger contentsChanged later 00344 if (!mRemoveOrig) mRemoveOrig = aFolder; 00345 if (aFolder->child()) 00346 { 00347 // call remove for every child 00348 KMFolderNode* node; 00349 TQPtrListIterator<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, TQT_SIGNAL(removed(KMFolder*, bool)), 00365 this, TQT_SLOT(removeFolderAux(KMFolder*, bool))); 00366 aFolder->remove(); 00367 } 00368 00369 KMFolder* KMFolderMgr::parentFolder( KMFolder* folder ) 00370 { 00371 // find the parent folder by stripping "." and ".directory" from the name 00372 KMFolderDir* fdir = folder->parent(); 00373 TQString parentName = fdir->name(); 00374 parentName = parentName.mid( 1, parentName.length()-11 ); 00375 KMFolderNode* parent = fdir->hasNamedFolder( parentName ); 00376 if ( !parent && fdir->parent() ) // dimap obviously has a different structure 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 // aFolder will be deleted by the next call! 00403 aFolder->parent()->remove(aFolder); 00404 00405 // update the children state 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 // call only if we're removing the original parent folder 00418 contentsChanged(); 00419 mRemoveOrig = 0; 00420 } 00421 } 00422 00423 void KMFolderMgr::removeDirAux(KMFolderDir* aFolderDir) 00424 { 00425 TQDir dir; 00426 TQString 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(TQStringList *str, 00454 TQValueList<TQGuardedPtr<KMFolder> > *folders) 00455 { 00456 createFolderList( str, folders, 0, "" ); 00457 } 00458 00459 //----------------------------------------------------------------------------- 00460 void KMFolderMgr::createI18nFolderList(TQStringList *str, 00461 TQValueList<TQGuardedPtr<KMFolder> > *folders) 00462 { 00463 createFolderList( str, folders, 0, TQString(), true ); 00464 } 00465 00466 //----------------------------------------------------------------------------- 00467 void KMFolderMgr::createFolderList(TQStringList *str, 00468 TQValueList<TQGuardedPtr<KMFolder> > *folders, 00469 KMFolderDir *adir, 00470 const TQString& 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 TQString& newName, 00578 KMFolderDir *newParent ) 00579 { 00580 RenameJob* job = new RenameJob( folder->storage(), newName, newParent ); 00581 connect( job, TQT_SIGNAL( renameDone( TQString, bool ) ), 00582 this, TQT_SLOT( slotRenameDone( TQString, bool ) ) ); 00583 connect( job, TQT_SIGNAL( renameDone( TQString, bool ) ), 00584 this, TQT_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, TQT_SIGNAL( folderCopyComplete( bool ) ), 00594 this, TQT_SIGNAL( folderMoveOrCopyOperationFinished() ) ); 00595 job->start(); 00596 } 00597 00598 //----------------------------------------------------------------------------- 00599 void KMFolderMgr::slotRenameDone( TQString, bool success ) 00600 { 00601 kdDebug(5006) << k_funcinfo << success << endl; 00602 } 00603 00604 #include "kmfoldermgr.moc"