kmail

kmfoldermgr.cpp

Go to the documentation of this file.
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 <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 /*immediate*/ );
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   // 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( 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   // 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     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   // 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     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   // find the parent folder by stripping "." and ".directory" from the name
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() ) // 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   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"