kmail

kmfolderdir.cpp

00001 // kmfolderdir.cpp
00002 
00003 #include <config.h>
00004 #include <qdir.h>
00005 
00006 #include "kmfolderdir.h"
00007 #include "kmfoldersearch.h"
00008 #include "kmfoldercachedimap.h"
00009 #include "kmfolder.h"
00010 
00011 #include <assert.h>
00012 #include <errno.h>
00013 #include <klocale.h>
00014 #include <kmessagebox.h>
00015 #include <kdebug.h>
00016 #include <kstandarddirs.h>
00017 
00018 
00019 //=============================================================================
00020 //=============================================================================
00021 KMFolderRootDir::KMFolderRootDir(KMFolderMgr* manager, const QString& path,
00022                                  KMFolderDirType dirType)
00023   : KMFolderDir( 0, 0, path, dirType ),
00024     mPath( path ),
00025     mManager( manager )
00026 {
00027 }
00028 
00029 //-----------------------------------------------------------------------------
00030 KMFolderRootDir::~KMFolderRootDir()
00031 {
00032   // WABA: We can't let KMFolderDir do this because by the time its
00033   // desctructor gets called, KMFolderRootDir is already destructed
00034   // Most notably the path.
00035   clear();
00036 }
00037 
00038 //-----------------------------------------------------------------------------
00039 void KMFolderRootDir::setPath(const QString& aPath)
00040 {
00041   mPath = aPath;
00042 }
00043 
00044 
00045 //-----------------------------------------------------------------------------
00046 QString KMFolderRootDir::path() const
00047 {
00048   return mPath;
00049 }
00050 
00051 
00052 //-----------------------------------------------------------------------------
00053 QString KMFolderRootDir::prettyURL() const
00054 {
00055   if ( !mBaseURL.isEmpty() )
00056     return i18n( mBaseURL.data() );
00057   else
00058     return QString::null;
00059 }
00060 
00061 
00062 //-----------------------------------------------------------------------------
00063 void KMFolderRootDir::setBaseURL( const QCString &baseURL )
00064 {
00065   mBaseURL = baseURL;
00066 }
00067 
00068 
00069 //-----------------------------------------------------------------------------
00070 KMFolderMgr* KMFolderRootDir::manager() const
00071 {
00072   return mManager;
00073 }
00074 
00075 
00076 //=============================================================================
00077 //=============================================================================
00078 KMFolderDir::KMFolderDir( KMFolder * owner, KMFolderDir* parent,
00079                           const QString& name, KMFolderDirType dirType )
00080   : KMFolderNode( parent, name ), KMFolderNodeList(),
00081     mOwner( owner ), mDirType( dirType )
00082 {
00083   setAutoDelete( true );
00084 }
00085 
00086 
00087 //-----------------------------------------------------------------------------
00088 KMFolderDir::~KMFolderDir()
00089 {
00090   clear();
00091 }
00092 
00093 
00094 //-----------------------------------------------------------------------------
00095 KMFolder* KMFolderDir::createFolder(const QString& aFolderName, bool aSysFldr, KMFolderType aFolderType)
00096 {
00097   KMFolder* fld;
00098 
00099   assert(!aFolderName.isEmpty());
00100   // FIXME urgs, is this still needed
00101   if (mDirType == KMImapDir)
00102     fld = new KMFolder( this, aFolderName, KMFolderTypeImap );
00103   else
00104     fld = new KMFolder( this, aFolderName, aFolderType );
00105 
00106   assert(fld != 0);
00107   fld->setSystemFolder(aSysFldr);
00108 
00109   KMFolderNode* fNode;
00110   int index = 0;
00111   for (fNode=first(); fNode; fNode=next()) {
00112     if (fNode->name().lower() > fld->name().lower()) {
00113       insert( index, fld );
00114       break;
00115     }
00116     ++index;
00117   }
00118 
00119   if (!fNode)
00120     append(fld);
00121 
00122   fld->correctUnreadMsgsCount();
00123   return fld;
00124 }
00125 
00126 
00127 //----------------------------------------------------------------------------
00128 QString KMFolderDir::path() const
00129 {
00130   static QString p;
00131 
00132   if (parent())
00133   {
00134     p = parent()->path();
00135     p.append("/");
00136     p.append(name());
00137   }
00138   else p = "";
00139 
00140   return p;
00141 }
00142 
00143 
00144 //----------------------------------------------------------------------------
00145 QString KMFolderDir::label() const
00146 {
00147   if ( mOwner )
00148     return mOwner->label();
00149   else
00150     return QString::null;
00151 }
00152 
00153 
00154 //-----------------------------------------------------------------------------
00155 QString KMFolderDir::prettyURL() const
00156 {
00157   QString parentUrl;
00158   if ( parent() )
00159     parentUrl = parent()->prettyURL();
00160   if ( !parentUrl.isEmpty() )
00161     return parentUrl + '/' + label();
00162   else
00163     return label();
00164 }
00165 
00166 //-----------------------------------------------------------------------------
00167 void KMFolderDir::addDirToParent( const QString &dirName, KMFolder *parentFolder )
00168 {
00169   KMFolderDir* folderDir = new KMFolderDir( parentFolder, this, dirName, mDirType);
00170   folderDir->reload();
00171   append( folderDir );
00172   parentFolder->setChild( folderDir );
00173 }
00174 
00175 // Get the default folder type of the given dir type. This function should only be used when
00176 // needing to find out what the folder type of a missing folder is.
00177 KMFolderType dirTypeToFolderType( KMFolderDirType dirType )
00178 {
00179   switch( dirType ) {
00180 
00181     // Use maildir for normal folder dirs, as this function is only called when finding a dir
00182     // without a parent folder, which can only happen with maildir-like folders
00183     case KMStandardDir: return KMFolderTypeMaildir;
00184 
00185     case KMImapDir: return KMFolderTypeImap;
00186     case KMDImapDir: return KMFolderTypeCachedImap;
00187     case KMSearchDir: return KMFolderTypeSearch;
00188     default: Q_ASSERT( false ); return KMFolderTypeMaildir;
00189   }
00190 }
00191 
00192 //-----------------------------------------------------------------------------
00193 bool KMFolderDir::reload(void)
00194 {
00195   QDir               dir;
00196   KMFolder*          folder;
00197   QFileInfo*         fileInfo;
00198   QStringList        diList;
00199   QPtrList<KMFolder> folderList;
00200 
00201   clear();
00202 
00203   const QString fldPath = path();
00204   dir.setFilter(QDir::Files | QDir::Dirs | QDir::Hidden);
00205   dir.setNameFilter("*");
00206 
00207   if (!dir.cd(fldPath, TRUE))
00208   {
00209     QString msg = i18n("<qt>Cannot enter folder <b>%1</b>.</qt>").arg(fldPath);
00210     KMessageBox::information(0, msg);
00211     return FALSE;
00212   }
00213 
00214   QFileInfoList* fiList=(QFileInfoList*)dir.entryInfoList();
00215   if (!fiList)
00216   {
00217     QString msg = i18n("<qt>Folder <b>%1</b> is unreadable.</qt>").arg(fldPath);
00218     KMessageBox::information(0, msg);
00219     return FALSE;
00220   }
00221 
00222   for (fileInfo=fiList->first(); fileInfo; fileInfo=fiList->next())
00223   {
00224     const QString fname = fileInfo->fileName();
00225     if( ( fname[0] == '.' ) && !fname.endsWith( ".directory" ) ) {
00226       // ignore all hidden files except our subfolder containers
00227       continue;
00228     }
00229     if( fname == ".directory" ) {
00230       // ignore .directory files (not created by us)
00231       continue;
00232     }
00233     // Collect subdirectories.
00234     if ( fileInfo->isDir() &&
00235          fname.startsWith( "." ) && fname.endsWith( ".directory" ) ) {
00236        diList.append(fname);
00237        continue;
00238     }
00239 
00240     if ( mDirType == KMImapDir
00241       && path().startsWith( KMFolderImap::cacheLocation() ) )
00242     {
00243        // Is the below needed for dimap as well?
00244        if ( KMFolderImap::encodeFileName(
00245                 KMFolderImap::decodeFileName( fname ) ) == fname )
00246        {
00247           folder = new KMFolder(  this, KMFolderImap::decodeFileName( fname ),
00248                                   KMFolderTypeImap );
00249           append(folder);
00250           folderList.append(folder);
00251        }
00252     }
00253     else if ( mDirType == KMDImapDir
00254            && path().startsWith( KMFolderCachedImap::cacheLocation() ) )
00255     {
00256        if (fileInfo->isDir()) // a directory
00257        {
00258           // For this to be a cached IMAP folder, it must be in the KMail dimap
00259           // subdir and must be have a uidcache file or be a maildir folder
00260           QString maildir(fname + "/new");
00261           QString imapcachefile = QString::fromLatin1(".%1.uidcache").arg(fname);
00262           if ( dir.exists( imapcachefile) || dir.exists( maildir ) )
00263           {
00264              folder = new KMFolder( this, fname, KMFolderTypeCachedImap );
00265              append(folder);
00266              folderList.append(folder);
00267           }
00268        }
00269     }
00270     else if ( mDirType == KMSearchDir)
00271     {
00272        folder = new KMFolder( this, fname, KMFolderTypeSearch );
00273        append(folder);
00274        folderList.append(folder);
00275     }
00276     else if ( mDirType == KMStandardDir )
00277     {
00278        // This is neither an imap, dimap nor a search folder. Can be either
00279        // mbox or maildir.
00280        if (fileInfo->isDir())
00281        {
00282           // Maildir folder
00283           if( dir.exists( fname + "/new" ) )
00284           {
00285              folder = new KMFolder( this, fname, KMFolderTypeMaildir );
00286              append(folder);
00287              folderList.append(folder);
00288           }
00289        }
00290        else
00291        {
00292           // all other files are folders (at the moment ;-)
00293           folder = new KMFolder( this, fname, KMFolderTypeMbox );
00294           append(folder);
00295           folderList.append(folder);
00296        }
00297     }
00298   }
00299 
00300   QStringList dirsWithoutFolder = diList;
00301   for (folder=folderList.first(); folder; folder=folderList.next())
00302   {
00303     for(QStringList::Iterator it = diList.begin();
00304         it != diList.end();
00305         ++it)
00306       if (*it == "." + folder->fileName() + ".directory")
00307       {
00308         dirsWithoutFolder.remove( *it );
00309         addDirToParent( *it, folder );
00310         break;
00311       }
00312   }
00313 
00314   // Check if the are any dirs without an associated folder. This can happen if the user messes
00315   // with the on-disk folder structure, see kolab issue 2972. In that case, we don't want to loose
00316   // the subfolders as well, so we recreate the folder so the folder/dir hierachy is OK again.
00317   if ( type() == KMDImapDir ) {
00318     for ( QStringList::Iterator it = dirsWithoutFolder.begin();
00319           it != dirsWithoutFolder.end(); ++it ) {
00320 
00321       // .foo.directory => foo
00322       QString folderName = *it;
00323       int right = folderName.find( ".directory" );
00324       int left = folderName.find( "." );
00325       Q_ASSERT( left != -1 && right != -1 );
00326       folderName = folderName.mid( left + 1, right - 1 );
00327 
00328       kdDebug(5006) << "Found dir without associated folder: " << ( *it ) << ", recreating the folder " << folderName << "." << endl;
00329 
00330       // Recreate the missing folder
00331       KMFolder *folder = new KMFolder( this, folderName, KMFolderTypeCachedImap );
00332       append( folder );
00333       folderList.append( folder );
00334 
00335       addDirToParent( *it, folder );
00336     }
00337   }
00338   return TRUE;
00339 }
00340 
00341 
00342 //-----------------------------------------------------------------------------
00343 KMFolderNode* KMFolderDir::hasNamedFolder(const QString& aName)
00344 {
00345   KMFolderNode* fNode;
00346   for (fNode=first(); fNode; fNode=next()) {
00347     if (fNode->name() == aName)
00348       return fNode;
00349   }
00350   return 0;
00351 }
00352 
00353 
00354 //-----------------------------------------------------------------------------
00355 KMFolderMgr* KMFolderDir::manager() const
00356 {
00357   return parent()->manager();
00358 }
00359 
00360 
00361 #include "kmfolderdir.moc"
00362