krop's commit fixes my problem in a better way, reverting
[kdepim.git] / kmail / kmfolderdir.cpp
blob5c0535842163e266d84595afe1b5477567d2820e
1 // kmfolderdir.cpp
4 #include "kmfolderdir.h"
5 #include "kmfoldersearch.h"
6 #include "kmfoldercachedimap.h"
7 #include "kmfolder.h"
8 #include "kmfoldermgr.h"
10 #include <assert.h>
11 #include <errno.h>
12 #include <klocale.h>
13 #include <kmessagebox.h>
14 #include <kdebug.h>
15 #include <kstandarddirs.h>
17 #include <QDir>
18 #include <QList>
19 #include <QByteArray>
21 //=============================================================================
22 //=============================================================================
23 KMFolderRootDir::KMFolderRootDir(KMFolderMgr* manager, const QString& path,
24 KMFolderDirType dirType)
25 : KMFolderDir( 0, 0, path, dirType ),
26 mPath( path ),
27 mManager( manager )
31 //-----------------------------------------------------------------------------
32 KMFolderRootDir::~KMFolderRootDir()
34 // WABA: We can't let KMFolderDir do this because by the time its
35 // desctructor gets called, KMFolderRootDir is already destructed
36 // Most notably the path.
37 qDeleteAll( begin(), end() ); // we own the pointers to our folders
38 clear();
41 //-----------------------------------------------------------------------------
42 void KMFolderRootDir::setPath(const QString& aPath)
44 mPath = aPath;
48 //-----------------------------------------------------------------------------
49 QString KMFolderRootDir::path() const
51 return mPath;
55 //-----------------------------------------------------------------------------
56 QString KMFolderRootDir::prettyUrl() const
58 if ( !mBaseURL.isEmpty() )
59 return i18n( mBaseURL.data() );
60 else
61 return QString();
65 //-----------------------------------------------------------------------------
66 void KMFolderRootDir::setBaseURL( const QByteArray &baseURL )
68 mBaseURL = baseURL;
72 //-----------------------------------------------------------------------------
73 KMFolderMgr* KMFolderRootDir::manager() const
75 return mManager;
79 //=============================================================================
80 //=============================================================================
81 KMFolderDir::KMFolderDir( KMFolder * owner, KMFolderDir* parent,
82 const QString& name, KMFolderDirType dirType )
83 : KMFolderNode( parent, name ), KMFolderNodeList(),
84 mOwner( owner ), mDirType( dirType )
88 //-----------------------------------------------------------------------------
89 KMFolderDir::~KMFolderDir()
91 qDeleteAll( begin(), end() ); // we own the pointers to our folders
92 clear();
96 //-----------------------------------------------------------------------------
97 KMFolder* KMFolderDir::createFolder(const QString& aFolderName, bool aSysFldr, KMFolderType aFolderType)
99 KMFolder* fld;
101 assert(!aFolderName.isEmpty());
102 // FIXME urgs, is this still needed
103 if (mDirType == KMImapDir)
104 fld = new KMFolder( this, aFolderName, KMFolderTypeImap );
105 else
106 fld = new KMFolder( this, aFolderName, aFolderType );
108 assert(fld != 0);
109 fld->setSystemFolder(aSysFldr);
111 bool inserted = false;
112 QListIterator<KMFolderNode*> it( *this);
113 int index = 0;
114 while ( it.hasNext() ) {
115 KMFolderNode* fNode = it.next();
116 if (fNode->name().toLower() > fld->name().toLower()) {
117 insert( index, fld );
118 inserted = true;
119 break;
121 ++index;
124 if ( !inserted )
125 append(fld);
127 fld->correctUnreadMsgsCount();
128 return fld;
132 //----------------------------------------------------------------------------
133 QString KMFolderDir::path() const
135 static QString p;
137 if (parent())
139 p = parent()->path();
140 p.append("/");
141 p.append(name());
143 else p = "";
145 return p;
149 //----------------------------------------------------------------------------
150 QString KMFolderDir::label() const
152 if ( mOwner )
153 return mOwner->label();
154 else
155 return QString();
159 //-----------------------------------------------------------------------------
160 QString KMFolderDir::prettyUrl() const
162 QString parentUrl;
163 if ( parent() )
164 parentUrl = parent()->prettyUrl();
165 if ( !parentUrl.isEmpty() )
166 return parentUrl + '/' + label();
167 else
168 return label();
171 //-----------------------------------------------------------------------------
172 void KMFolderDir::addDirToParent( const QString &dirName, KMFolder *parentFolder )
174 KMFolderDir* folderDir = new KMFolderDir( parentFolder, this, dirName, mDirType);
175 folderDir->reload();
176 append( folderDir );
177 parentFolder->setChild( folderDir );
180 // Get the default folder type of the given dir type. This function should only be used when
181 // needing to find out what the folder type of a missing folder is.
182 KMFolderType dirTypeToFolderType( KMFolderDirType dirType )
184 switch( dirType ) {
186 // Use maildir for normal folder dirs, as this function is only called when finding a dir
187 // without a parent folder, which can only happen with maildir-like folders
188 case KMStandardDir: return KMFolderTypeMaildir;
190 case KMImapDir: return KMFolderTypeImap;
191 case KMDImapDir: return KMFolderTypeCachedImap;
192 case KMSearchDir: return KMFolderTypeSearch;
193 default: Q_ASSERT( false ); return KMFolderTypeMaildir;
197 //-----------------------------------------------------------------------------
198 bool KMFolderDir::reload(void)
200 qDeleteAll( begin(), end() ); // we own the pointers to our folders
201 clear();
203 const QString fldPath = path();
204 QDir dir;
205 dir.setFilter(QDir::Files | QDir::Dirs | QDir::Hidden | QDir::NoDotAndDotDot);
206 dir.setNameFilters(QStringList("*"));
208 if ( !dir.cd(fldPath) )
210 QString msg = i18n("<qt>Cannot enter folder <b>%1</b>.</qt>", fldPath);
211 KMessageBox::information(0, msg);
212 return false;
215 if ( !dir.isReadable() )
217 QString msg = i18n("<qt>Folder <b>%1</b> is unreadable.</qt>", fldPath);
218 KMessageBox::information(0, msg);
219 return false;
222 QSet<QString> dirs;
223 QList<KMFolder*> folderList;
224 const QFileInfoList fiList( dir.entryInfoList() );
225 Q_FOREACH( const QFileInfo& fileInfo, fiList )
227 const QString fname = fileInfo.fileName();
228 const bool fileIsHidden = fname.startsWith('.');
229 if ( fileIsHidden && !fname.endsWith( QLatin1String(".directory") ) ) {
230 // ignore all hidden files except our subfolder containers
231 continue;
233 if ( fname == ".directory"
234 #ifdef KMAIL_SQLITE_INDEX
235 || fname.endsWith( QLatin1String(".index.db") )
236 #endif
238 // ignore .directory and *.index.db files (not created by us)
239 continue;
241 // Collect subdirectories.
242 if ( fileInfo.isDir() &&
243 fileIsHidden && fname.endsWith( QLatin1String(".directory") ) )
245 dirs.insert(fname);
246 continue;
249 // define folder parameters
250 QString folderName;
251 KMFolderType folderType = KMFolderTypeMaildir;
252 bool withIndex = true;
253 bool exportedSernums = true;
255 if ( mDirType == KMImapDir
256 && path().startsWith( KMFolderImap::cacheLocation() ) )
258 // Is the below needed for dimap as well?
259 if ( KMFolderImap::encodeFileName(
260 KMFolderImap::decodeFileName( fname ) ) == fname )
262 folderName = KMFolderImap::decodeFileName( fname );
263 folderType = KMFolderTypeImap;
266 else if ( mDirType == KMDImapDir
267 && path().startsWith( KMFolderCachedImap::cacheLocation() ) )
269 if (fileInfo.isDir()) // a directory
271 // For this to be a cached IMAP folder, it must be in the KMail dimap
272 // subdir and must be have a uidcache file or be a maildir folder
273 QString maildir(fname + "/new");
274 QString imapcachefile = QString::fromLatin1(".%1.uidcache").arg(fname);
275 if ( dir.exists( imapcachefile) || dir.exists( maildir ) )
277 folderName = fname;
278 folderType = KMFolderTypeCachedImap;
282 else if ( mDirType == KMSearchDir)
284 folderName = fname;
285 folderType = KMFolderTypeSearch;
287 else if ( mDirType == KMStandardDir )
289 // This is neither an imap, dimap nor a search folder. Can be either
290 // mbox or maildir.
291 if (fileInfo.isDir())
293 // Maildir folder
294 if( dir.exists( fname + "/new" ) )
296 folderName = fname;
297 folderType = KMFolderTypeMaildir;
300 else
302 // all other files are folders (at the moment ;-)
303 folderName = fname;
304 folderType = KMFolderTypeMbox;
308 //TODO if ( &manager()->dir() == this && folderName == QLatin1String( "outbox" ) )
309 //TODO withIndex = false;
311 // create folder
312 if ( !folderName.isEmpty() ) {
313 KMFolder* newFolder = new KMFolder( this, folderName, folderType, withIndex, exportedSernums );
314 append( newFolder );
315 folderList.append( newFolder );
319 QSet<QString> dirsWithoutFolder = dirs;
320 foreach ( KMFolder* folder, folderList )
322 const QString dirName = '.' + folder->fileName() + ".directory";
323 if ( dirs.contains( dirName ) )
325 dirsWithoutFolder.remove( dirName );
326 addDirToParent( dirName, folder );
330 // Check if the are any dirs without an associated folder. This can happen if the user messes
331 // with the on-disk folder structure, see kolab issue 2972. In that case, we don't want to loose
332 // the subfolders as well, so we recreate the folder so the folder/dir hierachy is OK again.
333 if ( type() == KMDImapDir ) {
334 foreach ( const QString &dirName, dirsWithoutFolder ) {
336 // .foo.directory => foo
337 QString folderName = dirName;
338 int right = folderName.indexOf( ".directory" );
339 int left = folderName.indexOf( "." );
340 Q_ASSERT( left != -1 && right != -1 );
341 folderName = folderName.mid( left + 1, right - 1 );
343 kWarning() << "Found dir without associated folder:" << dirName << ", recreating the folder"
344 << folderName;
346 // Recreate the missing folder
347 KMFolder *folder = new KMFolder( this, folderName, KMFolderTypeCachedImap );
348 append( folder );
349 folderList.append( folder );
351 addDirToParent( dirName, folder );
354 return true;
357 //-----------------------------------------------------------------------------
358 KMFolderNode* KMFolderDir::hasNamedFolder(const QString& aName)
360 QListIterator<KMFolderNode*> it(*this);
361 while ( it.hasNext() ) {
362 KMFolderNode* node = it.next();
363 if ( node && node->name() == aName ) {
364 return node;
367 return 0;
371 //-----------------------------------------------------------------------------
372 KMFolderMgr* KMFolderDir::manager() const
374 return parent()->manager();
378 #include "kmfolderdir.moc"