kmail

kmacctcachedimap.cpp
1
32#ifdef HAVE_CONFIG_H
33#include <config.h>
34#endif
35
36#include "kmacctcachedimap.h"
37using KMail::SieveConfig;
38
39#include "kmfoldertree.h"
40#include "kmfoldermgr.h"
41#include "kmfiltermgr.h"
42#include "kmfoldercachedimap.h"
43#include "kmmainwin.h"
44#include "accountmanager.h"
46#include "progressmanager.h"
47
48#include <tdeio/passdlg.h>
49#include <tdeio/scheduler.h>
50#include <tdeio/slave.h>
51#include <kdebug.h>
52#include <tdestandarddirs.h>
53#include <tdeapplication.h>
54#include <tdeconfig.h>
55
56#include <tqstylesheet.h>
57
58KMAcctCachedImap::KMAcctCachedImap( AccountManager* aOwner,
59 const TQString& aAccountName, uint id )
60 : KMail::ImapAccountBase( aOwner, aAccountName, id ), mFolder( 0 ),
61 mAnnotationCheckPassed(false),
62 mGroupwareType( GroupwareKolab ),
63 mSentCustomLoginCommand(false)
64{
65 // Never EVER set this for the cached IMAP account
66 mAutoExpunge = false;
67}
68
69
70//-----------------------------------------------------------------------------
71KMAcctCachedImap::~KMAcctCachedImap()
72{
73 killAllJobsInternal( true );
74}
75
76
77//-----------------------------------------------------------------------------
78TQString KMAcctCachedImap::type() const
79{
80 return "cachedimap";
81}
82
83void KMAcctCachedImap::init() {
84 ImapAccountBase::init();
85}
86
87//-----------------------------------------------------------------------------
88void KMAcctCachedImap::pseudoAssign( const KMAccount * a ) {
89 killAllJobs( true );
90 if (mFolder)
91 {
92 mFolder->setContentState(KMFolderCachedImap::imapNoInformation);
93 mFolder->setSubfolderState(KMFolderCachedImap::imapNoInformation);
94 }
95 ImapAccountBase::pseudoAssign( a );
96}
97
98//-----------------------------------------------------------------------------
99void KMAcctCachedImap::setImapFolder(KMFolderCachedImap *aFolder)
100{
101 mFolder = aFolder;
102 mFolder->setImapPath( "/" );
103 mFolder->setAccount( this );
104}
105
106
107//-----------------------------------------------------------------------------
108void KMAcctCachedImap::setAutoExpunge( bool /*aAutoExpunge*/ )
109{
110 // Never EVER set this for the cached IMAP account
111 mAutoExpunge = false;
112}
113
114//-----------------------------------------------------------------------------
115void KMAcctCachedImap::killAllJobs( bool disconnectSlave )
116{
117 //kdDebug(5006) << "killAllJobs: disconnectSlave=" << disconnectSlave << " " << mapJobData.count() << " jobs in map." << endl;
118 TQValueList<KMFolderCachedImap*> folderList = killAllJobsInternal( disconnectSlave );
119 for( TQValueList<KMFolderCachedImap*>::Iterator it = folderList.begin(); it != folderList.end(); ++it ) {
120 KMFolderCachedImap *fld = *it;
121 fld->resetSyncState();
122 fld->setContentState(KMFolderCachedImap::imapNoInformation);
123 fld->setSubfolderState(KMFolderCachedImap::imapNoInformation);
124 fld->sendFolderComplete(false);
125 }
126}
127
128//-----------------------------------------------------------------------------
129// Common between killAllJobs and the destructor - which shouldn't call sendFolderComplete
130TQValueList<KMFolderCachedImap*> KMAcctCachedImap::killAllJobsInternal( bool disconnectSlave )
131{
132 // Make list of folders to reset. This must be done last, since folderComplete
133 // can trigger the next queued mail check already.
134 TQValueList<KMFolderCachedImap*> folderList;
135 TQMap<TDEIO::Job*, jobData>::Iterator it = mapJobData.begin();
136 for (; it != mapJobData.end(); ++it) {
137 if ((*it).parent)
138 folderList << static_cast<KMFolderCachedImap*>((*it).parent->storage());
139 // Kill the job - except if it's the one that already died and is calling us
140 if ( !it.key()->error() && mSlave ) {
141 it.key()->kill();
142 mSlave = 0; // killing a job, kills the slave
143 }
144 }
145 mapJobData.clear();
146
147 // Clear the joblist. Make SURE to stop the job emitting "finished"
148 for( TQPtrListIterator<CachedImapJob> it( mJobList ); it.current(); ++it )
149 it.current()->setPassiveDestructor( true );
150 KMAccount::deleteFolderJobs();
151
152 if ( disconnectSlave && mSlave ) {
153 TDEIO::Scheduler::disconnectSlave( mSlave );
154 mSlave = 0;
155 }
156 return folderList;
157}
158
159//-----------------------------------------------------------------------------
160void KMAcctCachedImap::cancelMailCheck()
161{
162 // Make list of folders to reset, like in killAllJobs
163 TQValueList<KMFolderCachedImap*> folderList;
164 TQMap<TDEIO::Job*, jobData>::Iterator it = mapJobData.begin();
165 for (; it != mapJobData.end(); ++it) {
166 if ( (*it).cancellable && (*it).parent )
167 folderList << static_cast<KMFolderCachedImap*>((*it).parent->storage());
168 }
169 // Kill jobs
170 ImapAccountBase::cancelMailCheck();
171 // Reset sync states and emit folderComplete, this is important for
172 // KMAccount::checkingMail() to be reset, in case we restart checking mail later.
173 for( TQValueList<KMFolderCachedImap*>::Iterator it = folderList.begin(); it != folderList.end(); ++it ) {
174 KMFolderCachedImap *fld = *it;
175 fld->resetSyncState();
176 fld->setContentState(KMFolderCachedImap::imapNoInformation);
177 fld->setSubfolderState(KMFolderCachedImap::imapNoInformation);
178 fld->sendFolderComplete(false);
179 }
180}
181
182// Reimplemented from ImapAccountBase because we only check one folder at a time
183void KMAcctCachedImap::slotCheckQueuedFolders()
184{
185 mMailCheckFolders.clear();
186 mMailCheckFolders.append( mFoldersQueuedForChecking.front() );
187 mFoldersQueuedForChecking.pop_front();
188 if ( mFoldersQueuedForChecking.isEmpty() )
189 disconnect( this, TQ_SIGNAL( finishedCheck( bool, CheckStatus ) ),
190 this, TQ_SLOT( slotCheckQueuedFolders() ) );
191
192 kmkernel->acctMgr()->singleCheckMail(this, true);
193 mMailCheckFolders.clear();
194}
195
196void KMAcctCachedImap::processNewMail( bool /*interactive*/ )
197{
198 assert( mFolder ); // George says "better to crash then lose mail"
199
200 if ( mMailCheckFolders.isEmpty() )
201 processNewMail( mFolder, true );
202 else {
203 KMFolder* f = mMailCheckFolders.front();
204 mMailCheckFolders.pop_front();
205
206 // Only check mail if the folder really exists, it might have been removed by the sync in
207 // the meantime.
208 if ( f ) {
209 processNewMail( static_cast<KMFolderCachedImap *>( f->storage() ), !checkingSingleFolder() );
210 }
211 }
212}
213
214void KMAcctCachedImap::processNewMail( KMFolderCachedImap* folder,
215 bool recurse )
216{
217 assert( folder ); // George says "better to crash then lose mail"
218
219 // This should never be set for a cached IMAP account
220 mAutoExpunge = false;
221 mCountLastUnread = 0;
222 mUnreadBeforeCheck.clear();
223 // stop sending noops during sync, that will keep the connection open
224 mNoopTimer.stop();
225
226 // reset namespace todo
227 if ( folder == mFolder && !namespaces().isEmpty() ) {
228 TQStringList nsToList = namespaces()[PersonalNS];
229 TQStringList otherNSToCheck = namespaces()[OtherUsersNS];
230 otherNSToCheck += namespaces()[SharedNS];
231 for ( TQStringList::Iterator it = otherNSToCheck.begin();
232 it != otherNSToCheck.end(); ++it ) {
233 if ( (*it).isEmpty() ) {
234 // empty namespaces are included in the "normal" listing
235 // as the folders are created under the root folder
236 nsToList += *it;
237 }
238 }
239 folder->setNamespacesToList( nsToList );
240 }
241
242 Q_ASSERT( !mMailCheckProgressItem );
243 mMailCheckProgressItem = KPIM::ProgressManager::createProgressItem(
244 "MailCheck" + TQString::number( id() ),
245 TQStyleSheet::escape( folder->label() ), // will be changed immediately in serverSync anyway
246 TQString(),
247 true, // can be cancelled
248 useSSL() || useTLS() );
249 connect( mMailCheckProgressItem, TQ_SIGNAL( progressItemCanceled( KPIM::ProgressItem* ) ),
250 this, TQ_SLOT( slotProgressItemCanceled( KPIM::ProgressItem* ) ) );
251
252 folder->setAccount(this);
253 connect(folder, TQ_SIGNAL(folderComplete(KMFolderCachedImap*, bool)),
254 this, TQ_SLOT(postProcessNewMail(KMFolderCachedImap*, bool)));
255 folder->serverSync( recurse );
256}
257
258void KMAcctCachedImap::postProcessNewMail( KMFolderCachedImap* folder, bool )
259{
260 mNoopTimer.start( 60000 ); // send a noop every minute to avoid "connection broken" errors
261 disconnect(folder, TQ_SIGNAL(folderComplete(KMFolderCachedImap*, bool)),
262 this, TQ_SLOT(postProcessNewMail(KMFolderCachedImap*, bool)));
263 mMailCheckProgressItem->setComplete();
264 mMailCheckProgressItem = 0;
265
266 if ( folder == mFolder ) {
267 // We remove everything from the deleted folders list after a full sync.
268 // Even if it fails (no permission), because on the next sync we want the folder to reappear,
269 // instead of the user being stuck with "can't delete" every time.
270 // And we do it for _all_ deleted folders, even those that were deleted on the server in the first place (slotListResult).
271 // Otherwise this might have side effects much later (e.g. when regaining permissions to a folder we could see before)
272
273#if 0 // this opens a race: delete a folder during a sync (after the sync checked that folder), and it'll be forgotten...
274 mDeletedFolders.clear();
275#endif
276 mPreviouslyDeletedFolders.clear();
277 }
278
279 KMail::ImapAccountBase::postProcessNewMail();
280}
281
282void KMAcctCachedImap::addUnreadMsgCount( const KMFolderCachedImap *folder,
283 int countUnread )
284{
285 if ( folder->imapPath() != "/INBOX/" ) {
286 // new mail in INBOX is processed with KMAccount::processNewMsg() and
287 // therefore doesn't need to be counted here
288 const TQString folderId = folder->folder()->idString();
289 int newInFolder = countUnread;
290 if ( mUnreadBeforeCheck.find( folderId ) != mUnreadBeforeCheck.end() )
291 newInFolder -= mUnreadBeforeCheck[folderId];
292 if ( newInFolder > 0 )
293 addToNewInFolder( folderId, newInFolder );
294 }
295 mCountUnread += countUnread;
296}
297
298void KMAcctCachedImap::addLastUnreadMsgCount( const KMFolderCachedImap *folder,
299 int countLastUnread )
300{
301 mUnreadBeforeCheck[folder->folder()->idString()] = countLastUnread;
302 mCountLastUnread += countLastUnread;
303}
304
305//
306//
307// read/write config
308//
309//
310
311void KMAcctCachedImap::readConfig( /*const*/ TDEConfig/*Base*/ & config ) {
312 ImapAccountBase::readConfig( config );
313 // Apparently this method is only ever called once (from KMKernel::init) so this is ok
314 mPreviouslyDeletedFolders = config.readListEntry( "deleted-folders" );
315 mDeletedFolders.clear(); // but just in case...
316 const TQStringList oldPaths = config.readListEntry( "renamed-folders-paths" );
317 const TQStringList newNames = config.readListEntry( "renamed-folders-names" );
318 TQStringList::const_iterator it = oldPaths.begin();
319 TQStringList::const_iterator nameit = newNames.begin();
320 for( ; it != oldPaths.end() && nameit != newNames.end(); ++it, ++nameit ) {
321 addRenamedFolder( *it, TQString(), *nameit );
322 }
323 mGroupwareType = (GroupwareType)config.readNumEntry( "groupwareType", GroupwareKolab );
324}
325
326void KMAcctCachedImap::writeConfig( TDEConfig/*Base*/ & config ) /*const*/ {
327 ImapAccountBase::writeConfig( config );
328 config.writeEntry( "deleted-folders", mDeletedFolders + mPreviouslyDeletedFolders );
329 config.writeEntry( "renamed-folders-paths", mRenamedFolders.keys() );
330 const TQValueList<RenamedFolder> values = mRenamedFolders.values();
331 TQStringList lstNames;
332 TQValueList<RenamedFolder>::const_iterator it = values.begin();
333 for ( ; it != values.end() ; ++it )
334 lstNames.append( (*it).mNewName );
335 config.writeEntry( "renamed-folders-names", lstNames );
336 config.writeEntry( "groupwareType", mGroupwareType );
337}
338
339void KMAcctCachedImap::invalidateIMAPFolders()
340{
341 invalidateIMAPFolders( mFolder );
342}
343
344void KMAcctCachedImap::invalidateIMAPFolders( KMFolderCachedImap* folder )
345{
346 if( !folder || !folder->folder() )
347 return;
348
349 folder->setAccount(this);
350
351 TQStringList strList;
352 TQValueList<TQGuardedPtr<KMFolder> > folderList;
353 kmkernel->dimapFolderMgr()->createFolderList( &strList, &folderList,
354 folder->folder()->child(), TQString(),
355 false );
356 TQValueList<TQGuardedPtr<KMFolder> >::Iterator it;
357 mCountLastUnread = 0;
358 mUnreadBeforeCheck.clear();
359
360 for( it = folderList.begin(); it != folderList.end(); ++it ) {
361 KMFolder *f = *it;
362 if( f && f->folderType() == KMFolderTypeCachedImap ) {
363 KMFolderCachedImap *cfolder = static_cast<KMFolderCachedImap*>(f->storage());
364 // This invalidates the folder completely
365 cfolder->setUidValidity("INVALID");
366 cfolder->writeUidCache();
367 }
368 }
369 folder->setUidValidity("INVALID");
370 folder->writeUidCache();
371
372 processNewMailInFolder( folder->folder(), Recursive );
373}
374
375//-----------------------------------------------------------------------------
376void KMAcctCachedImap::addDeletedFolder( KMFolder* folder )
377{
378 if ( !folder || folder->folderType() != KMFolderTypeCachedImap )
379 return;
380 KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>(folder->storage());
381 addDeletedFolder( storage->imapPath() );
382 kdDebug(5006) << k_funcinfo << storage->imapPath() << endl;
383
384 // Add all child folders too
385 if( folder->child() ) {
386 KMFolderNode *node = folder->child()->first();
387 while( node ) {
388 if( !node->isDir() ) {
389 addDeletedFolder( static_cast<KMFolder*>( node ) ); // recurse
390 }
391 node = folder->child()->next();
392 }
393 }
394}
395
396void KMAcctCachedImap::addDeletedFolder( const TQString& imapPath )
397{
398 mDeletedFolders << imapPath;
399}
400
401TQStringList KMAcctCachedImap::deletedFolderPaths( const TQString& subFolderPath ) const
402{
403 TQStringList lst;
404 for ( TQStringList::const_iterator it = mDeletedFolders.begin(); it != mDeletedFolders.end(); ++it ) {
405 if ( (*it).startsWith( subFolderPath ) )
406 // We must reverse the order, so that sub sub sub folders are deleted first
407 lst.prepend( *it );
408 }
409 for ( TQStringList::const_iterator it = mPreviouslyDeletedFolders.begin(); it != mPreviouslyDeletedFolders.end(); ++it ) {
410 if ( (*it).startsWith( subFolderPath ) )
411 lst.prepend( *it );
412 }
413 kdDebug(5006) << "KMAcctCachedImap::deletedFolderPaths for " << subFolderPath << " returning: " << lst << endl;
414 Q_ASSERT( !lst.isEmpty() );
415 return lst;
416}
417
418bool KMAcctCachedImap::isDeletedFolder( const TQString& subFolderPath ) const
419{
420 return mDeletedFolders.find( subFolderPath ) != mDeletedFolders.end();
421}
422
423bool KMAcctCachedImap::isPreviouslyDeletedFolder( const TQString& subFolderPath ) const
424{
425 return mPreviouslyDeletedFolders.find( subFolderPath ) != mPreviouslyDeletedFolders.end();
426}
427
428void KMAcctCachedImap::removeDeletedFolder( const TQString& subFolderPath )
429{
430 mDeletedFolders.remove( subFolderPath );
431 mPreviouslyDeletedFolders.remove( subFolderPath );
432}
433
434void KMAcctCachedImap::addRenamedFolder( const TQString& subFolderPath, const TQString& oldLabel, const TQString& newName )
435{
436 mRenamedFolders.insert( subFolderPath, RenamedFolder( oldLabel, newName ) );
437}
438
439void KMAcctCachedImap::removeRenamedFolder( const TQString& subFolderPath )
440{
441 mRenamedFolders.remove( subFolderPath );
442}
443
444void KMAcctCachedImap::slotProgressItemCanceled( ProgressItem* )
445{
446 bool abortConnection = !mSlaveConnected;
447 killAllJobs( abortConnection );
448 if ( abortConnection ) {
449 // If we were trying to connect, tell kmfoldercachedimap so that it moves on
450 emit connectionResult( TDEIO::ERR_USER_CANCELED, TQString() );
451 }
452}
453
454FolderStorage* KMAcctCachedImap::rootFolder() const
455{
456 return mFolder;
457}
458
459
460TQString KMAcctCachedImap::renamedFolder( const TQString& imapPath ) const
461{
462 TQMap<TQString, RenamedFolder>::ConstIterator renit = mRenamedFolders.find( imapPath );
463 if ( renit != mRenamedFolders.end() )
464 return (*renit).mNewName;
465 return TQString();
466}
467
468#include "kmacctcachedimap.moc"
The FolderStorage class is the bass class for the storage related aspects of a collection of mail (a ...
Definition: folderstorage.h:80
virtual int find(const KMMsgBase *msg) const =0
Returns the index of the given message or -1 if not found.
Mail folder.
Definition: kmfolder.h:69
KMFolderType folderType() const
Returns the type of this folder.
Definition: kmfolder.cpp:233
KMFolderDir * child() const
Returns the folder directory associated with this node or 0 if no such directory exists.
Definition: kmfolder.h:157
The account manager is responsible for creating accounts of various types via the factory method crea...
folderdiaquotatab.h
Definition: aboutdata.cpp:40