kmail

kmacctimap.cpp
1
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25
26#include "kmacctimap.h"
27using KMail::SieveConfig;
28
29#include "kmmessage.h"
30#include "broadcaststatus.h"
31using KPIM::BroadcastStatus;
32#include "kmfoldertree.h"
33#include "kmfoldermgr.h"
34#include "kmfolderimap.h"
35#include "kmmainwin.h"
36#include "kmmsgdict.h"
37#include "kmfilter.h"
38#include "kmfiltermgr.h"
39#include "folderstorage.h"
40#include "imapjob.h"
41#include "actionscheduler.h"
42using KMail::ActionScheduler;
43using KMail::ImapJob;
44using KMail::ImapAccountBase;
45#include "progressmanager.h"
46using KPIM::ProgressItem;
47using KPIM::ProgressManager;
48#include <tdeio/scheduler.h>
49#include <tdeio/slave.h>
50#include <tdemessagebox.h>
51#include <kdebug.h>
52
53#include <tqstylesheet.h>
54
55#include <errno.h>
56
57//-----------------------------------------------------------------------------
58KMAcctImap::KMAcctImap(AccountManager* aOwner, const TQString& aAccountName, uint id):
59 KMail::ImapAccountBase(aOwner, aAccountName, id),
60 mCountRemainChecks( 0 ),
61 mErrorTimer( 0, "mErrorTimer" )
62{
63 mFolder = 0;
64 mScheduler = 0;
65 mNoopTimer.start( 60000 ); // // send a noop every minute
66 mOpenFolders.setAutoDelete(true);
67 connect(kmkernel->imapFolderMgr(), TQ_SIGNAL(changed()),
68 this, TQ_SLOT(slotUpdateFolderList()));
69 connect(&mErrorTimer, TQ_SIGNAL(timeout()), TQ_SLOT(slotResetConnectionError()));
70
71 TQString serNumUri = locateLocal( "data", "kmail/unfiltered." +
72 TQString("%1").arg(KAccount::id()) );
73 TDEConfig config( serNumUri );
74 TQStringList serNums = config.readListEntry( "unfiltered" );
75 mFilterSerNumsToSave.setAutoDelete( false );
76
77 for ( TQStringList::ConstIterator it = serNums.begin();
78 it != serNums.end(); ++it ) {
79 mFilterSerNums.append( (*it).toUInt() );
80 mFilterSerNumsToSave.insert( *it, (const int *)1 );
81 }
82}
83
84
85//-----------------------------------------------------------------------------
86KMAcctImap::~KMAcctImap()
87{
88 killAllJobs( true );
89
90 TQString serNumUri = locateLocal( "data", "kmail/unfiltered." +
91 TQString("%1").arg(KAccount::id()) );
92 TDEConfig config( serNumUri );
93 TQStringList serNums;
94 TQDictIterator<int> it( mFilterSerNumsToSave );
95 for( ; it.current(); ++it )
96 serNums.append( it.currentKey() );
97 config.writeEntry( "unfiltered", serNums );
98}
99
100
101//-----------------------------------------------------------------------------
102TQString KMAcctImap::type() const
103{
104 return "imap";
105}
106
107//-----------------------------------------------------------------------------
108void KMAcctImap::pseudoAssign( const KMAccount * a ) {
109 killAllJobs( true );
110 if (mFolder)
111 {
112 mFolder->setContentState(KMFolderImap::imapNoInformation);
113 mFolder->setSubfolderState(KMFolderImap::imapNoInformation);
114 }
115 ImapAccountBase::pseudoAssign( a );
116}
117
118//-----------------------------------------------------------------------------
119void KMAcctImap::setImapFolder(KMFolderImap *aFolder)
120{
121 mFolder = aFolder;
122 mFolder->setImapPath( "/" );
123}
124
125
126//-----------------------------------------------------------------------------
127
128bool KMAcctImap::handleError( int errorCode, const TQString &errorMsg, TDEIO::Job* job, const TQString& context, bool abortSync )
129{
130 /* TODO check where to handle this one better. */
131 if ( errorCode == TDEIO::ERR_DOES_NOT_EXIST ) {
132 // folder is gone, so reload the folderlist
133 if ( mFolder )
134 mFolder->listDirectory();
135 return true;
136 }
137 return ImapAccountBase::handleError( errorCode, errorMsg, job, context, abortSync );
138}
139
140
141//-----------------------------------------------------------------------------
142void KMAcctImap::killAllJobs( bool disconnectSlave )
143{
144 TQMap<TDEIO::Job*, jobData>::Iterator it = mapJobData.begin();
145 for ( ; it != mapJobData.end(); ++it)
146 {
147 TQPtrList<KMMessage> msgList = (*it).msgList;
148 TQPtrList<KMMessage>::Iterator it2 = msgList.begin();
149 for ( ; it2 != msgList.end(); ++it2 ) {
150 KMMessage *msg = *it2;
151 if ( msg->transferInProgress() ) {
152 kdDebug(5006) << "KMAcctImap::killAllJobs - resetting mail" << endl;
153 msg->setTransferInProgress( false );
154 }
155 }
156 if ((*it).parent)
157 {
158 // clear folder state
159 KMFolderImap *fld = static_cast<KMFolderImap*>((*it).parent->storage());
160 fld->setCheckingValidity(false);
161 fld->quiet(false);
162 fld->setContentState(KMFolderImap::imapNoInformation);
163 fld->setSubfolderState(KMFolderImap::imapNoInformation);
164 fld->sendFolderComplete(false);
165 fld->removeJobs();
166 }
167 if ( (*it).progressItem )
168 {
169 (*it).progressItem->setComplete();
170 }
171 }
172 if (mSlave && mapJobData.begin() != mapJobData.end())
173 {
174 mSlave->kill();
175 mSlave = 0;
176 }
177 // remove the jobs
178 mapJobData.clear();
179 // KMAccount::deleteFolderJobs(); doesn't work here always, it deletes jobs from
180 // its own mJobList instead of our mJobList...
181 KMAccount::deleteFolderJobs();
182 TQPtrListIterator<ImapJob> it2( mJobList );
183 while ( it2.current() ) {
184 ImapJob *job = it2.current();
185 ++it2;
186 job->kill();
187 }
188 mJobList.clear();
189 // make sure that no new-mail-check is blocked
190 if (mCountRemainChecks > 0)
191 {
192 checkDone( false, CheckOK ); // returned 0 new messages
193 mCountRemainChecks = 0;
194 }
195 if ( disconnectSlave && slave() ) {
196 TDEIO::Scheduler::disconnectSlave( slave() );
197 mSlave = 0;
198 }
199}
200
201//-----------------------------------------------------------------------------
202void KMAcctImap::ignoreJobsForMessage( KMMessage* msg )
203{
204 if (!msg) return;
205 TQPtrListIterator<ImapJob> it( mJobList );
206 while ( it.current() )
207 {
208 ImapJob *job = it.current();
209 ++it;
210 if ( job->msgList().first() == msg )
211 {
212 job->kill();
213 }
214 }
215}
216
217//-----------------------------------------------------------------------------
218void KMAcctImap::ignoreJobsForFolder( KMFolder* folder )
219{
220 TQPtrListIterator<ImapJob> it( mJobList );
221 while ( it.current() )
222 {
223 ImapJob *job = it.current();
224 ++it;
225 if ( !job->msgList().isEmpty() && job->msgList().first()->parent() == folder )
226 {
227 job->kill();
228 }
229 }
230}
231
232//-----------------------------------------------------------------------------
233void KMAcctImap::removeSlaveJobsForFolder( KMFolder* folder )
234{
235 // Make sure the folder is not referenced in any tdeio slave jobs
236 TQMap<TDEIO::Job*, jobData>::Iterator it = mapJobData.begin();
237 while ( it != mapJobData.end() ) {
238 TQMap<TDEIO::Job*, jobData>::Iterator i = it;
239 it++;
240 if ( (*i).parent ) {
241 if ( (*i).parent == folder ) {
242 mapJobData.remove(i);
243 }
244 }
245 }
246}
247
248//-----------------------------------------------------------------------------
249void KMAcctImap::cancelMailCheck()
250{
251 // Make list of folders to reset, like in killAllJobs
252 TQValueList<KMFolderImap*> folderList;
253 TQMap<TDEIO::Job*, jobData>::Iterator it = mapJobData.begin();
254 for (; it != mapJobData.end(); ++it) {
255 if ( (*it).cancellable && (*it).parent ) {
256 folderList << static_cast<KMFolderImap*>((*it).parent->storage());
257 }
258 }
259 // Kill jobs
260 // FIXME
261 // ImapAccountBase::cancelMailCheck();
262 killAllJobs( true );
263 // emit folderComplete, this is important for
264 // KMAccount::checkingMail() to be reset, in case we restart checking mail later.
265 for( TQValueList<KMFolderImap*>::Iterator it = folderList.begin(); it != folderList.end(); ++it ) {
266 KMFolderImap *fld = *it;
267 fld->sendFolderComplete(false);
268 }
269}
270
271//-----------------------------------------------------------------------------
272void KMAcctImap::processNewMail(bool interactive)
273{
274 kdDebug() << "processNewMail " << mCheckingSingleFolder << ",status="<<makeConnection()<<endl;
275 if (!mFolder || !mFolder->folder() || !mFolder->folder()->child() ||
276 makeConnection() == ImapAccountBase::Error)
277 {
278 mCountRemainChecks = 0;
279 mCheckingSingleFolder = false;
280 checkDone( false, CheckError );
281 return;
282 }
283 // if necessary then initialize the list of folders which should be checked
284 if( mMailCheckFolders.isEmpty() )
285 {
286 slotUpdateFolderList();
287 // if no folders should be checked then the check is finished
288 if( mMailCheckFolders.isEmpty() )
289 {
290 checkDone( false, CheckOK );
291 mCheckingSingleFolder = false;
292 return;
293 }
294 }
295 // Ok, we're really checking, get a progress item;
296 Q_ASSERT( !mMailCheckProgressItem );
297 mMailCheckProgressItem =
298 ProgressManager::createProgressItem(
299 "MailCheckAccount" + name(),
300 i18n("Checking account: %1" ).arg( TQStyleSheet::escape( name() ) ),
301 TQString(), // status
302 true, // can be canceled
303 useSSL() || useTLS() );
304
305 mMailCheckProgressItem->setTotalItems( mMailCheckFolders.count() );
306 connect ( mMailCheckProgressItem,
307 TQ_SIGNAL( progressItemCanceled( KPIM::ProgressItem*) ),
308 this,
309 TQ_SLOT( slotMailCheckCanceled() ) );
310
311 TQValueList<TQGuardedPtr<KMFolder> >::Iterator it;
312 // first get the current count of unread-messages
313 mCountRemainChecks = 0;
314 mCountUnread = 0;
315 mUnreadBeforeCheck.clear();
316 for (it = mMailCheckFolders.begin(); it != mMailCheckFolders.end(); ++it)
317 {
318 KMFolder *folder = *it;
319 if (folder && !folder->noContent())
320 {
321 mUnreadBeforeCheck[folder->idString()] = folder->countUnread();
322 }
323 }
324 bool gotError = false;
325 // then check for new mails
326 for (it = mMailCheckFolders.begin(); it != mMailCheckFolders.end(); ++it)
327 {
328 KMFolder *folder = *it;
329 if (folder && !folder->noContent())
330 {
331 KMFolderImap *imapFolder = static_cast<KMFolderImap*>(folder->storage());
332 if ( imapFolder->getContentState() != KMFolderImap::imapListingInProgress
333 && imapFolder->getContentState() != KMFolderImap::imapDownloadInProgress )
334 {
335 // connect the result-signals for new-mail-notification
336 mCountRemainChecks++;
337
338 if (imapFolder->isSelected()) {
339 connect(imapFolder, TQ_SIGNAL(folderComplete(KMFolderImap*, bool)),
340 this, TQ_SLOT(postProcessNewMail(KMFolderImap*, bool)));
341 imapFolder->getFolder();
342 } else if ( kmkernel->filterMgr()->atLeastOneIncomingFilterAppliesTo( id() ) &&
343 imapFolder->folder()->isSystemFolder() &&
344 imapFolder->imapPath() == "/INBOX/" ) {
345 imapFolder->open("acctimap"); // will be closed in the folderSelected slot
346 // first get new headers before we select the folder
347 imapFolder->setSelected( true );
348 connect( imapFolder, TQ_SIGNAL( folderComplete( KMFolderImap*, bool ) ),
349 this, TQ_SLOT( slotFolderSelected( KMFolderImap*, bool) ) );
350 imapFolder->getFolder();
351 }
352 else {
353 connect(imapFolder, TQ_SIGNAL(numUnreadMsgsChanged(KMFolder*)),
354 this, TQ_SLOT(postProcessNewMail(KMFolder*)));
355 bool ok = imapFolder->processNewMail(interactive);
356 if (!ok)
357 {
358 // there was an error so cancel
359 mCountRemainChecks--;
360 gotError = true;
361 if ( mMailCheckProgressItem ) {
362 mMailCheckProgressItem->incCompletedItems();
363 mMailCheckProgressItem->updateProgress();
364 }
365 }
366 }
367 }
368 }
369 } // end for
370 if ( gotError )
371 slotUpdateFolderList();
372 // for the case the account is down and all folders report errors
373 if ( mCountRemainChecks == 0 )
374 {
375 mCountLastUnread = 0; // => mCountUnread - mCountLastUnread == new count
376 ImapAccountBase::postProcessNewMail();
377 mUnreadBeforeCheck.clear();
378 mCheckingSingleFolder = false;
379 }
380}
381
382//-----------------------------------------------------------------------------
383void KMAcctImap::postProcessNewMail(KMFolderImap* folder, bool)
384{
385 disconnect(folder, TQ_SIGNAL(folderComplete(KMFolderImap*, bool)),
386 this, TQ_SLOT(postProcessNewMail(KMFolderImap*, bool)));
387 postProcessNewMail(static_cast<KMFolder*>(folder->folder()));
388}
389
390void KMAcctImap::postProcessNewMail( KMFolder * folder )
391{
392 disconnect( folder->storage(), TQ_SIGNAL(numUnreadMsgsChanged(KMFolder*)),
393 this, TQ_SLOT(postProcessNewMail(KMFolder*)) );
394
395 if ( mMailCheckProgressItem ) {
396 mMailCheckProgressItem->incCompletedItems();
397 mMailCheckProgressItem->updateProgress();
398 mMailCheckProgressItem->setStatus( folder->prettyURL() + i18n(" completed") );
399 }
400 mCountRemainChecks--;
401
402 // count the unread messages
403 const TQString folderId = folder->idString();
404 int newInFolder = folder->countUnread();
405 if ( mUnreadBeforeCheck.find( folderId ) != mUnreadBeforeCheck.end() )
406 newInFolder -= mUnreadBeforeCheck[folderId];
407 if ( newInFolder > 0 ) {
408 addToNewInFolder( folderId, newInFolder );
409 mCountUnread += newInFolder;
410 }
411
412 // Filter messages
413 TQValueListIterator<TQ_UINT32> filterIt = mFilterSerNums.begin();
414 TQValueList<TQ_UINT32> inTransit;
415
416 if (ActionScheduler::isEnabled() ||
417 kmkernel->filterMgr()->atLeastOneOnlineImapFolderTarget()) {
418 KMFilterMgr::FilterSet set = KMFilterMgr::Inbound;
419 TQValueList<KMFilter*> filters = kmkernel->filterMgr()->filters();
420 if (!mScheduler) {
421 mScheduler = new KMail::ActionScheduler( set, filters );
422 mScheduler->setAccountId( id() );
423 connect( mScheduler, TQ_SIGNAL(filtered(TQ_UINT32)), this, TQ_SLOT(slotFiltered(TQ_UINT32)) );
424 } else {
425 mScheduler->setFilterList( filters );
426 }
427 }
428
429 while (filterIt != mFilterSerNums.end()) {
430 int idx = -1;
431 KMFolder *folder = 0;
432 KMMessage *msg = 0;
433 KMMsgDict::instance()->getLocation( *filterIt, &folder, &idx );
434 // It's possible that the message has been deleted or moved into a
435 // different folder, or that the serNum is stale
436 if ( !folder ) {
437 mFilterSerNumsToSave.remove( TQString( "%1" ).arg( *filterIt ) );
438 ++filterIt;
439 continue;
440 }
441
442 KMFolderImap *imapFolder = dynamic_cast<KMFolderImap*>(folder->storage());
443 if (!imapFolder ||
444 !imapFolder->folder()->isSystemFolder() ||
445 !(imapFolder->imapPath() == "/INBOX/") ) { // sanity checking
446 mFilterSerNumsToSave.remove( TQString( "%1" ).arg( *filterIt ) );
447 ++filterIt;
448 continue;
449 }
450
451 if (idx != -1) {
452
453 msg = folder->getMsg( idx );
454 if (!msg) { // sanity checking
455 mFilterSerNumsToSave.remove( TQString( "%1" ).arg( *filterIt ) );
456 ++filterIt;
457 continue;
458 }
459
460 if (ActionScheduler::isEnabled() ||
461 kmkernel->filterMgr()->atLeastOneOnlineImapFolderTarget()) {
462 mScheduler->execFilters( msg );
463 } else {
464 if (msg->transferInProgress()) {
465 inTransit.append( *filterIt );
466 ++filterIt;
467 continue;
468 }
469 msg->setTransferInProgress(true);
470 if ( !msg->isComplete() ) {
471 FolderJob *job = folder->createJob(msg);
472 connect(job, TQ_SIGNAL(messageRetrieved(KMMessage*)),
473 TQ_SLOT(slotFilterMsg(KMMessage*)));
474 job->start();
475 } else {
476 mFilterSerNumsToSave.remove( TQString( "%1" ).arg( *filterIt ) );
477 if (slotFilterMsg(msg) == 2) break;
478 }
479 }
480 }
481 ++filterIt;
482 }
483 mFilterSerNums = inTransit;
484
485 if (mCountRemainChecks == 0)
486 {
487 // all checks are done
488 mCountLastUnread = 0; // => mCountUnread - mCountLastUnread == new count
489 // when we check only one folder (=selected) and we have new mails
490 // then do not display a summary as the normal status message is better
491 bool showStatus = ( mCheckingSingleFolder && mCountUnread > 0 ) ? false : true;
492 ImapAccountBase::postProcessNewMail( showStatus );
493 mUnreadBeforeCheck.clear();
494 mCheckingSingleFolder = false;
495 }
496}
497
498//-----------------------------------------------------------------------------
499void KMAcctImap::slotFiltered(TQ_UINT32 serNum)
500{
501 mFilterSerNumsToSave.remove( TQString( "%1" ).arg( serNum ) );
502}
503
504//-----------------------------------------------------------------------------
505void KMAcctImap::slotUpdateFolderList()
506{
507 if ( !mFolder || !mFolder->folder() || !mFolder->folder()->child() )
508 {
509 kdWarning(5006) << "KMAcctImap::slotUpdateFolderList return" << endl;
510 return;
511 }
512 TQStringList strList;
513 mMailCheckFolders.clear();
514 kmkernel->imapFolderMgr()->createFolderList(&strList, &mMailCheckFolders,
515 mFolder->folder()->child(), TQString(), false);
516 // the new list
517 TQValueList<TQGuardedPtr<KMFolder> > includedFolders;
518 // check for excluded folders
519 TQValueList<TQGuardedPtr<KMFolder> >::Iterator it;
520 for (it = mMailCheckFolders.begin(); it != mMailCheckFolders.end(); ++it)
521 {
522 KMFolderImap* folder = static_cast<KMFolderImap*>(((KMFolder*)(*it))->storage());
523 if (folder->includeInMailCheck())
524 includedFolders.append(*it);
525 }
526 mMailCheckFolders = includedFolders;
527}
528
529//-----------------------------------------------------------------------------
530void KMAcctImap::listDirectory()
531{
532 mFolder->listDirectory();
533}
534
535//-----------------------------------------------------------------------------
536void KMAcctImap::readConfig(TDEConfig& config)
537{
538 ImapAccountBase::readConfig( config );
539}
540
541//-----------------------------------------------------------------------------
542void KMAcctImap::slotMailCheckCanceled()
543{
544 if( mMailCheckProgressItem )
545 mMailCheckProgressItem->setComplete();
546 cancelMailCheck();
547}
548
549//-----------------------------------------------------------------------------
550FolderStorage* KMAcctImap::rootFolder() const
551{
552 return mFolder;
553}
554
555ImapAccountBase::ConnectionState KMAcctImap::makeConnection()
556{
557 if ( mSlaveConnectionError )
558 {
559 mErrorTimer.start(100, true); // Clear error flag
560 return Error;
561 }
562 return ImapAccountBase::makeConnection();
563}
564
565void KMAcctImap::slotResetConnectionError()
566{
567 mSlaveConnectionError = false;
568 kdDebug(5006) << k_funcinfo << endl;
569}
570
571void KMAcctImap::slotFolderSelected( KMFolderImap* folder, bool )
572{
573 folder->setSelected( false );
574 disconnect( folder, TQ_SIGNAL( folderComplete( KMFolderImap*, bool ) ),
575 this, TQ_SLOT( slotFolderSelected( KMFolderImap*, bool) ) );
576 postProcessNewMail( static_cast<KMFolder*>(folder->folder()) );
577 folder->close( "acctimap" );
578}
579
580void KMAcctImap::execFilters(TQ_UINT32 serNum)
581{
582 if ( !kmkernel->filterMgr()->atLeastOneFilterAppliesTo( id() ) ) return;
583 TQValueListIterator<TQ_UINT32> findIt = mFilterSerNums.find( serNum );
584 if ( findIt != mFilterSerNums.end() )
585 return;
586 mFilterSerNums.append( serNum );
587 mFilterSerNumsToSave.insert( TQString( "%1" ).arg( serNum ), (const int *)1 );
588}
589
590int KMAcctImap::slotFilterMsg( KMMessage *msg )
591{
592 if ( !msg ) {
593 // messageRetrieved(0) is always possible
594 return -1;
595 }
596 msg->setTransferInProgress(false);
597 TQ_UINT32 serNum = msg->getMsgSerNum();
598 if ( serNum )
599 mFilterSerNumsToSave.remove( TQString( "%1" ).arg( serNum ) );
600
601 int filterResult = kmkernel->filterMgr()->process(msg,
602 KMFilterMgr::Inbound,
603 true,
604 id() );
605 if (filterResult == 2) {
606 // something went horribly wrong (out of space?)
607 kmkernel->emergencyExit( i18n("Unable to process messages: " ) + TQString::fromLocal8Bit(strerror(errno)));
608 return 2;
609 }
610 if (msg->parent()) { // unGet this msg
611 int idx = -1;
612 KMFolder * p = 0;
613 KMMsgDict::instance()->getLocation( msg, &p, &idx );
614 assert( p == msg->parent() ); assert( idx >= 0 );
615 p->unGetMsg( idx );
616 }
617
618 return filterResult;
619}
620
621#include "kmacctimap.moc"
The FolderStorage class is the bass class for the storage related aspects of a collection of mail (a ...
Mail folder.
Definition kmfolder.h:69
int countUnread()
Number of new or unread messages in this folder.
Definition kmfolder.cpp:450
TQString idString() const
Returns a string that can be used to identify this folder.
Definition kmfolder.cpp:705
virtual TQString prettyURL() const
URL of the node for visualization purposes.
Definition kmfolder.cpp:593
KMMsgInfo * unGetMsg(int idx)
Replace KMMessage with KMMsgInfo and delete KMMessage
Definition kmfolder.cpp:326
FolderJob * createJob(KMMessage *msg, FolderJob::JobType jt=FolderJob::tGetMessage, KMFolder *folder=0, TQString partSpecifier=TQString(), const AttachmentStrategy *as=0) const
These methods create respective FolderJob (You should derive FolderJob for each derived KMFolder).
Definition kmfolder.cpp:346
KMMessage * getMsg(int idx)
Read message at given index.
Definition kmfolder.cpp:321
bool noContent() const
Returns, if the folder can't contain mails, but only subfolder.
Definition kmfolder.cpp:301
This is a Mime Message.
Definition kmmessage.h:68
void setTransferInProgress(bool value, bool force=false)
Set that the message shall not be deleted because it is still required.
bool transferInProgress() const
Return, if the message should not be deleted.
bool isComplete() const
Return true if the complete message is available without referring to the backing store.
Definition kmmessage.h:867
void getLocation(unsigned long key, KMFolder **retFolder, int *retIndex) const
Returns the folder the message represented by the serial number key is in and the index in that folde...
static const KMMsgDict * instance()
Access the globally unique MessageDict.
The account manager is responsible for creating accounts of various types via the factory method crea...
folderdiaquotatab.h
Definition aboutdata.cpp:40