kmail

kmacctcachedimap.cpp
1 
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35 
36 #include "kmacctcachedimap.h"
37 using 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 <kstandarddirs.h>
53 #include <tdeapplication.h>
54 #include <tdeconfig.h>
55 
56 #include <tqstylesheet.h>
57 
58 KMAcctCachedImap::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 //-----------------------------------------------------------------------------
71 KMAcctCachedImap::~KMAcctCachedImap()
72 {
73  killAllJobsInternal( true );
74 }
75 
76 
77 //-----------------------------------------------------------------------------
78 TQString KMAcctCachedImap::type() const
79 {
80  return "cachedimap";
81 }
82 
83 void KMAcctCachedImap::init() {
84  ImapAccountBase::init();
85 }
86 
87 //-----------------------------------------------------------------------------
88 void 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 //-----------------------------------------------------------------------------
99 void KMAcctCachedImap::setImapFolder(KMFolderCachedImap *aFolder)
100 {
101  mFolder = aFolder;
102  mFolder->setImapPath( "/" );
103  mFolder->setAccount( this );
104 }
105 
106 
107 //-----------------------------------------------------------------------------
108 void KMAcctCachedImap::setAutoExpunge( bool /*aAutoExpunge*/ )
109 {
110  // Never EVER set this for the cached IMAP account
111  mAutoExpunge = false;
112 }
113 
114 //-----------------------------------------------------------------------------
115 void 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
130 TQValueList<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 //-----------------------------------------------------------------------------
160 void 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
183 void 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 
196 void 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 
214 void 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 
258 void 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 
282 void 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 
298 void 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 
311 void 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 
326 void 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 
339 void KMAcctCachedImap::invalidateIMAPFolders()
340 {
341  invalidateIMAPFolders( mFolder );
342 }
343 
344 void 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 //-----------------------------------------------------------------------------
376 void 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 
396 void KMAcctCachedImap::addDeletedFolder( const TQString& imapPath )
397 {
398  mDeletedFolders << imapPath;
399 }
400 
401 TQStringList 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 
418 bool KMAcctCachedImap::isDeletedFolder( const TQString& subFolderPath ) const
419 {
420  return mDeletedFolders.find( subFolderPath ) != mDeletedFolders.end();
421 }
422 
423 bool KMAcctCachedImap::isPreviouslyDeletedFolder( const TQString& subFolderPath ) const
424 {
425  return mPreviouslyDeletedFolders.find( subFolderPath ) != mPreviouslyDeletedFolders.end();
426 }
427 
428 void KMAcctCachedImap::removeDeletedFolder( const TQString& subFolderPath )
429 {
430  mDeletedFolders.remove( subFolderPath );
431  mPreviouslyDeletedFolders.remove( subFolderPath );
432 }
433 
434 void KMAcctCachedImap::addRenamedFolder( const TQString& subFolderPath, const TQString& oldLabel, const TQString& newName )
435 {
436  mRenamedFolders.insert( subFolderPath, RenamedFolder( oldLabel, newName ) );
437 }
438 
439 void KMAcctCachedImap::removeRenamedFolder( const TQString& subFolderPath )
440 {
441  mRenamedFolders.remove( subFolderPath );
442 }
443 
444 void 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 
454 FolderStorage* KMAcctCachedImap::rootFolder() const
455 {
456  return mFolder;
457 }
458 
459 
460 TQString 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
KMFolderDir * child() const
Returns the folder directory associated with this node or 0 if no such directory exists.
Definition: kmfolder.h:157
KMFolderType folderType() const
Returns the type of this folder.
Definition: kmfolder.cpp:233
The account manager is responsible for creating accounts of various types via the factory method crea...
folderdiaquotatab.h
Definition: aboutdata.cpp:40