kmail

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