36 #include "actionscheduler.h" 38 #include "filterlog.h" 39 #include "messageproperty.h" 41 #include "kmfolderindex.h" 42 #include "kmfoldermgr.h" 43 #include "kmmsgdict.h" 44 #include "kmcommands.h" 45 #include "kmheaders.h" 46 #include "accountmanager.h" 50 #include <tdeconfig.h> 51 #include <kstandarddirs.h> 53 using namespace KMail;
54 typedef TQPtrList<KMMsgBase> KMMessageList;
57 KMFolderMgr* ActionScheduler::tempFolderMgr = 0;
58 int ActionScheduler::refCount = 0;
59 int ActionScheduler::count = 0;
60 TQValueList<ActionScheduler*> *ActionScheduler::schedulerList = 0;
61 bool ActionScheduler::sEnabled =
false;
62 bool ActionScheduler::sEnabledChecked =
false;
64 ActionScheduler::ActionScheduler(KMFilterMgr::FilterSet
set,
65 TQValueList<KMFilter*> filters,
68 :mSet( set ), mHeaders( headers )
73 mExecutingLock =
false;
74 mFetchExecuting =
false;
75 mFiltersAreQueued =
false;
78 mAutoDestruct =
false;
84 finishTimer =
new TQTimer(
this,
"finishTimer" );
85 connect( finishTimer, TQ_SIGNAL(timeout()),
this, TQ_SLOT(finish()));
86 fetchMessageTimer =
new TQTimer(
this,
"fetchMessageTimer" );
87 connect( fetchMessageTimer, TQ_SIGNAL(timeout()),
this, TQ_SLOT(fetchMessage()));
88 tempCloseFoldersTimer =
new TQTimer(
this,
"tempCloseFoldersTimer" );
89 connect( tempCloseFoldersTimer, TQ_SIGNAL(timeout()),
this, TQ_SLOT(tempCloseFolders()));
90 processMessageTimer =
new TQTimer(
this,
"processMessageTimer" );
91 connect( processMessageTimer, TQ_SIGNAL(timeout()),
this, TQ_SLOT(processMessage()));
92 filterMessageTimer =
new TQTimer(
this,
"filterMessageTimer" );
93 connect( filterMessageTimer, TQ_SIGNAL(timeout()),
this, TQ_SLOT(filterMessage()));
94 timeOutTimer =
new TQTimer(
this,
"timeOutTimer" );
95 connect( timeOutTimer, TQ_SIGNAL(timeout()),
this, TQ_SLOT(timeOut()));
96 fetchTimeOutTimer =
new TQTimer(
this,
"fetchTimeOutTimer" );
97 connect( fetchTimeOutTimer, TQ_SIGNAL(timeout()),
this, TQ_SLOT(fetchTimeOut()));
99 TQValueList<KMFilter*>::Iterator it = filters.begin();
100 for (; it != filters.end(); ++it)
101 mFilters.append( **it );
104 mDeleteSrcFolder =
false;
105 setSourceFolder( srcFolder );
108 tmpName.setNum( count );
110 tempFolderMgr =
new KMFolderMgr(locateLocal(
"data",
"kmail/filter"));
111 KMFolder *tempFolder = tempFolderMgr->findOrCreate( tmpName );
113 mDeleteSrcFolder =
true;
114 setSourceFolder( tempFolder );
117 schedulerList =
new TQValueList<ActionScheduler*>;
118 schedulerList->append(
this );
121 ActionScheduler::~ActionScheduler()
123 schedulerList->remove(
this );
125 disconnect( mSrcFolder, TQ_SIGNAL(closed()),
126 this, TQ_SLOT(folderClosedOrExpunged()) );
127 disconnect( mSrcFolder, TQ_SIGNAL(expunged(
KMFolder*)),
128 this, TQ_SLOT(folderClosedOrExpunged()) );
129 mSrcFolder->close(
"actionschedsrc");
131 if (mDeleteSrcFolder)
132 tempFolderMgr->remove(mSrcFolder);
136 delete tempFolderMgr;
141 void ActionScheduler::setAutoDestruct(
bool autoDestruct )
143 mAutoDestruct = autoDestruct;
146 void ActionScheduler::setAlwaysMatch(
bool alwaysMatch )
148 mAlwaysMatch = alwaysMatch;
151 void ActionScheduler::setDefaultDestinationFolder(
KMFolder *destFolder )
153 mDestFolder = destFolder;
156 void ActionScheduler::setSourceFolder(
KMFolder *srcFolder )
158 srcFolder->
open(
"actionschedsrc");
160 disconnect( mSrcFolder, TQ_SIGNAL(msgAdded(
KMFolder*, TQ_UINT32)),
161 this, TQ_SLOT(msgAdded(
KMFolder*, TQ_UINT32)) );
162 disconnect( mSrcFolder, TQ_SIGNAL(closed()),
163 this, TQ_SLOT(folderClosedOrExpunged()) );
164 disconnect( mSrcFolder, TQ_SIGNAL(expunged(
KMFolder*)),
165 this, TQ_SLOT(folderClosedOrExpunged()) );
166 mSrcFolder->close(
"actionschedsrc");
168 mSrcFolder = srcFolder;
170 for (i = 0; i < mSrcFolder->count(); ++i)
171 enqueue( mSrcFolder->getMsgBase( i )->getMsgSerNum() );
173 connect( mSrcFolder, TQ_SIGNAL(msgAdded(
KMFolder*, TQ_UINT32)),
174 this, TQ_SLOT(msgAdded(
KMFolder*, TQ_UINT32)) );
175 connect( mSrcFolder, TQ_SIGNAL(closed()),
176 this, TQ_SLOT(folderClosedOrExpunged()) );
177 connect( mSrcFolder, TQ_SIGNAL(expunged(
KMFolder*)),
178 this, TQ_SLOT(folderClosedOrExpunged()) );
182 void ActionScheduler::setFilterList( TQValueList<KMFilter*> filters )
184 mFiltersAreQueued =
true;
185 mQueuedFilters.clear();
187 TQValueList<KMFilter*>::Iterator it = filters.begin();
188 for (; it != filters.end(); ++it)
189 mQueuedFilters.append( **it );
191 mFilters = mQueuedFilters;
192 mFiltersAreQueued =
false;
193 mQueuedFilters.clear();
197 void ActionScheduler::folderClosedOrExpunged()
202 mSrcFolder->open(
"actionsched" );
206 int ActionScheduler::tempOpenFolder(
KMFolder* aFolder )
209 tempCloseFoldersTimer->stop();
210 if ( aFolder == mSrcFolder.operator->() )
213 int rc = aFolder->
open(
"actionsched");
217 mOpenFolders.append( aFolder );
221 void ActionScheduler::tempCloseFolders()
224 TQValueListConstIterator<TQGuardedPtr<KMFolder> > it;
225 for (it = mOpenFolders.begin(); it != mOpenFolders.end(); ++it) {
228 folder->
close(
"actionsched");
230 mOpenFolders.clear();
233 void ActionScheduler::execFilters(
const TQValueList<TQ_UINT32> serNums)
235 TQValueListConstIterator<TQ_UINT32> it;
236 for (it = serNums.begin(); it != serNums.end(); ++it)
240 void ActionScheduler::execFilters(
const TQPtrList<KMMsgBase> msgList)
243 TQPtrList<KMMsgBase> list = msgList;
244 for (msgBase = list.first(); msgBase; msgBase = list.next())
245 execFilters( msgBase->getMsgSerNum() );
248 void ActionScheduler::execFilters(KMMsgBase* msgBase)
250 execFilters( msgBase->getMsgSerNum() );
253 void ActionScheduler::execFilters(TQ_UINT32 serNum)
255 if (mResult != ResultOk) {
256 if ((mResult != ResultCriticalError) &&
257 !mExecuting && !mExecutingLock && !mFetchExecuting) {
259 if (!mFetchSerNums.isEmpty()) {
260 mFetchSerNums.push_back( mFetchSerNums.first() );
261 mFetchSerNums.pop_front();
266 if (MessageProperty::filtering( serNum )) {
268 mResult = ResultError;
269 if (!mExecuting && !mFetchExecuting)
270 finishTimer->start( 0,
true );
273 mFetchSerNums.append( serNum );
274 if (!mFetchExecuting) {
276 mFetchExecuting =
true;
277 fetchMessageTimer->start( 0,
true );
282 KMMsgBase *ActionScheduler::messageBase(TQ_UINT32 serNum)
290 if (folder && (idx != -1)) {
292 tempOpenFolder( folder );
296 mResult = ResultError;
297 finishTimer->start( 0,
true );
302 KMMessage *ActionScheduler::message(TQ_UINT32 serNum)
310 if (folder && (idx != -1)) {
312 msg = folder->
getMsg( idx );
313 tempOpenFolder( folder );
316 mResult = ResultError;
317 finishTimer->start( 0,
true );
322 void ActionScheduler::finish()
324 if (mResult != ResultOk) {
326 emit result( mResult );
332 if (!mFetchSerNums.isEmpty()) {
336 fetchMessageTimer->start( 0,
true );
339 mFetchExecuting =
false;
342 if (mSerNums.begin() != mSerNums.end()) {
344 processMessageTimer->start( 0,
true );
352 if (!mDeleteSrcFolder && !mDestFolder.isNull() ) {
353 while ( mSrcFolder->count() > 0 ) {
354 KMMessage *msg = mSrcFolder->getMsg( 0 );
355 mDestFolder->moveMsg( msg );
360 tempCloseFoldersTimer->start( 60*1000,
true );
363 mFetchSerNums.clear();
365 if (mFiltersAreQueued)
366 mFilters = mQueuedFilters;
367 mQueuedFilters.clear();
368 mFiltersAreQueued =
false;
369 ReturnCode aResult = mResult;
371 mExecutingLock =
false;
372 emit result( aResult );
381 void ActionScheduler::fetchMessage()
383 TQValueListIterator<TQ_UINT32> mFetchMessageIt = mFetchSerNums.begin();
384 while (mFetchMessageIt != mFetchSerNums.end()) {
385 if (!MessageProperty::transferInProgress(*mFetchMessageIt))
394 if (mFetchMessageIt == mFetchSerNums.end() && !mFetchSerNums.isEmpty()) {
395 mResult = ResultError;
397 if ((mFetchMessageIt == mFetchSerNums.end()) || (mResult != ResultOk)) {
398 mFetchExecuting =
false;
399 if (!mSrcFolder->count())
400 mSrcFolder->expunge();
401 finishTimer->start( 0,
true );
406 KMMsgBase *msgBase = messageBase( *mFetchMessageIt );
408 if ((mResult != ResultOk) || (!msgBase)) {
409 mFetchExecuting =
false;
412 mFetchUnget = msgBase->isMessage();
413 KMMessage *msg = message( *mFetchMessageIt );
414 if (mResult != ResultOk) {
415 mFetchExecuting =
false;
420 messageFetched( msg );
422 fetchTimeOutTime = TQTime::currentTime();
423 fetchTimeOutTimer->start( 60 * 1000,
true );
424 FolderJob *job = msg->parent()->createJob( msg );
425 connect( job, TQ_SIGNAL(messageRetrieved(
KMMessage* )),
430 mFetchExecuting =
false;
431 mResult = ResultError;
432 finishTimer->start( 0,
true );
437 void ActionScheduler::messageFetched(
KMMessage *msg )
439 fetchTimeOutTimer->stop();
442 fetchMessageTimer->start( 0,
true );
446 mFetchSerNums.remove( msg->getMsgSerNum() );
451 if ((mSet & KMFilterMgr::Explicit) ||
452 (msg->
headerField(
"X-KMail-Filtered" ).isEmpty())) {
454 serNumS.setNum( msg->getMsgSerNum() );
456 newMsg->fromString(msg->
asString());
460 mSrcFolder->addMsg( newMsg );
462 fetchMessageTimer->start( 0,
true );
464 if (mFetchUnget && msg->parent())
465 msg->parent()->unGetMsg( msg->parent()->find( msg ));
469 void ActionScheduler::msgAdded(
KMFolder*, TQ_UINT32 serNum )
475 void ActionScheduler::enqueue(TQ_UINT32 serNum)
477 if (mResult != ResultOk)
480 if (MessageProperty::filtering( serNum )) {
482 mResult = ResultError;
483 if (!mExecuting && !mFetchExecuting)
484 finishTimer->start( 0,
true );
487 mSerNums.append( serNum );
493 mMessageIt = mSerNums.begin();
494 processMessageTimer->start( 0,
true );
499 void ActionScheduler::processMessage()
503 mExecutingLock =
true;
504 mMessageIt = mSerNums.begin();
505 while (mMessageIt != mSerNums.end()) {
506 if (!MessageProperty::transferInProgress(*mMessageIt))
511 if (mMessageIt == mSerNums.end() && !mSerNums.isEmpty()) {
513 processMessageTimer->start( 600,
true );
516 if ((mMessageIt == mSerNums.end()) || (mResult != ResultOk)) {
517 mExecutingLock =
false;
519 finishTimer->start( 0,
true );
524 KMMsgBase *msgBase = messageBase( *mMessageIt );
525 if (!msgBase || mResult != ResultOk) {
530 MessageProperty::setFiltering( *mMessageIt,
true );
531 MessageProperty::setFilterHandler( *mMessageIt,
this );
532 MessageProperty::setFilterFolder( *mMessageIt, mDestFolder );
536 mFilterIt = mFilters.begin();
538 mUnget = msgBase->isMessage();
540 if (mResult != ResultOk) {
545 bool mdnEnabled =
true;
547 TDEConfigGroup mdnConfig( kmkernel->config(),
"MDN" );
548 int mode = mdnConfig.readNumEntry(
"default-policy", 0 );
549 if (!mode || mode < 0 || mode > 3)
555 (msg && !(*mFilterIt).requiresBody(msg) && !mdnEnabled))
561 filterMessageTimer->start( 0,
true );
565 FolderJob *job = msg->parent()->createJob( msg );
566 connect( job, TQ_SIGNAL(messageRetrieved(
KMMessage* )),
567 TQ_SLOT(messageRetrieved(
KMMessage* )) );
571 mResult = ResultError;
572 finishTimer->start( 0,
true );
577 void ActionScheduler::messageRetrieved(
KMMessage* msg)
581 filterMessageTimer->start( 0,
true );
584 void ActionScheduler::filterMessage()
586 if (mFilterIt == mFilters.end()) {
590 if (((mSet & KMFilterMgr::Outbound) && (*mFilterIt).applyOnOutbound()) ||
591 ((mSet & KMFilterMgr::Inbound) && (*mFilterIt).applyOnInbound() &&
593 (mAccount && (*mFilterIt).applyOnAccount(mAccountId)))) ||
594 ((mSet & KMFilterMgr::Explicit) && (*mFilterIt).applyOnExplicit())) {
598 TQString logText( i18n(
"<b>Evaluating filter rules:</b> " ) );
599 logText.append( (*mFilterIt).pattern()->asString() );
603 (*mFilterIt).pattern()->matches( *mMessageIt )) {
606 FilterLog::patternResult );
608 mFilterAction = (*mFilterIt).actions()->first();
614 filterMessageTimer->start( 0,
true );
619 if (res == KMFilterAction::CriticalError) {
620 mResult = ResultCriticalError;
627 TQString logText( i18n(
"<b>Applying filter action:</b> %1" )
628 .arg( mFilterAction->displayString() ) );
632 mFilterAction = (*mFilterIt).actions()->next();
637 if ((*mFilterIt).stopProcessingHere())
638 mFilterIt = mFilters.end();
641 filterMessageTimer->start( 0,
true );
645 void ActionScheduler::moveMessage()
647 KMMsgBase *msgBase = messageBase( *mMessageIt );
651 MessageProperty::setTransferInProgress( *mMessageIt,
false,
true );
653 KMFolder *folder = MessageProperty::filterFolder( *mMessageIt );
654 TQString serNumS = msg->
headerField(
"X-KMail-Filtered" );
655 if (!serNumS.isEmpty())
656 mOriginalSerNum = serNumS.toUInt();
659 MessageProperty::setFilterHandler( *mMessageIt, 0 );
660 MessageProperty::setFiltering( *mMessageIt,
false );
661 mSerNums.remove( *mMessageIt );
664 ReturnCode mOldReturnCode = mResult;
666 orgMsg = message( mOriginalSerNum );
667 mResult = mOldReturnCode;
668 if (!orgMsg || !orgMsg->parent()) {
670 mSrcFolder->removeMsg( mSrcFolder->find( msg ) );
671 kdDebug(5006) <<
"The original serial number is missing. " 672 <<
"Cannot complete the filtering." << endl;
673 mExecutingLock =
false;
674 processMessageTimer->start( 0,
true );
678 folder = orgMsg->parent();
682 assert( msg->parent() == mSrcFolder.operator->() );
683 mSrcFolder->take( mSrcFolder->find( msg ) );
684 mSrcFolder->addMsg( msg );
687 if (msg && folder && kmkernel->folderIsTrash( folder ))
690 timeOutTime = TQTime::currentTime();
691 KMCommand *cmd =
new KMMoveCommand( folder, msg );
692 connect( cmd, TQ_SIGNAL( completed( KMCommand * ) ),
693 this, TQ_SLOT( moveMessageFinished( KMCommand * ) ) );
698 timeOutTimer->start( 60 * 1000,
true );
701 void ActionScheduler::moveMessageFinished( KMCommand *command )
703 timeOutTimer->stop();
704 if ( command->result() != KMCommand::OK )
705 mResult = ResultError;
707 if (!mSrcFolder->count())
708 mSrcFolder->expunge();
712 mHeaders->clearSelectableAndAboutToBeDeleted( mOriginalSerNum );
714 ReturnCode mOldReturnCode = mResult;
715 if (mOriginalSerNum) {
716 msg = message( mOriginalSerNum );
717 emit filtered( mOriginalSerNum );
720 mResult = mOldReturnCode;
722 if (msg && msg->parent()) {
723 cmd =
new KMMoveCommand( 0, msg );
727 if (mResult == ResultOk) {
728 mExecutingLock =
false;
730 connect( cmd, TQ_SIGNAL( completed( KMCommand * ) ),
731 this, TQ_SLOT( processMessage() ) );
733 processMessageTimer->start( 0,
true );
738 connect( cmd, TQ_SIGNAL( completed( KMCommand * ) ),
739 this, TQ_SLOT( finish() ) );
741 finishTimer->start( 0,
true );
748 void ActionScheduler::copyMessageFinished( KMCommand *command )
750 if ( command->result() != KMCommand::OK )
751 actionMessage( KMFilterAction::ErrorButGoOn );
756 void ActionScheduler::timeOut()
759 assert( lastCommand );
761 disconnect( lastCommand, TQ_SIGNAL( completed( KMCommand * ) ),
762 this, TQ_SLOT( moveMessageFinished( KMCommand * ) ) );
764 mExecutingLock =
false;
766 finishTimer->start( 0,
true );
768 execFilters( mOriginalSerNum );
771 void ActionScheduler::fetchTimeOut()
776 disconnect( lastJob, TQ_SIGNAL(messageRetrieved(
KMMessage* )),
777 this, TQ_SLOT(messageFetched(
KMMessage* )) );
780 fetchMessageTimer->start( 0,
true );
783 TQString ActionScheduler::debug()
786 TQValueList<ActionScheduler*>::iterator it;
788 for ( it = schedulerList->begin(); it != schedulerList->end(); ++it ) {
789 res.append( TQString(
"ActionScheduler #%1.\n" ).arg( i ) );
790 if ((*it)->mAccount && kmkernel->find( (*it)->mAccountId )) {
791 res.append( TQString(
"Account %1, Name %2.\n" )
792 .arg( (*it)->mAccountId )
793 .arg( kmkernel->acctMgr()->find( (*it)->mAccountId )->name() ) );
795 res.append( TQString(
"mExecuting %1, " ).arg( (*it)->mExecuting ?
"true" :
"false" ) );
796 res.append( TQString(
"mExecutingLock %1, " ).arg( (*it)->mExecutingLock ?
"true" :
"false" ) );
797 res.append( TQString(
"mFetchExecuting %1.\n" ).arg( (*it)->mFetchExecuting ?
"true" :
"false" ) );
798 res.append( TQString(
"mOriginalSerNum %1.\n" ).arg( (*it)->mOriginalSerNum ) );
799 res.append( TQString(
"mMessageIt %1.\n" ).arg( ((*it)->mMessageIt != 0) ? *(*it)->mMessageIt : 0 ) );
800 res.append( TQString(
"mSerNums count %1, " ).arg( (*it)->mSerNums.count() ) );
801 res.append( TQString(
"mFetchSerNums count %1.\n" ).arg( (*it)->mFetchSerNums.count() ) );
802 res.append( TQString(
"mResult " ) );
803 if ((*it)->mResult == ResultOk)
804 res.append( TQString(
"ResultOk.\n" ) );
805 else if ((*it)->mResult == ResultError)
806 res.append( TQString(
"ResultError.\n" ) );
807 else if ((*it)->mResult == ResultCriticalError)
808 res.append( TQString(
"ResultCriticalError.\n" ) );
810 res.append( TQString(
"Unknown.\n" ) );
817 bool ActionScheduler::isEnabled()
822 sEnabledChecked =
true;
823 TDEConfig* config = KMKernel::config();
824 TDEConfigGroupSaver saver(config,
"General");
825 sEnabled = config->readBoolEntry(
"action-scheduler",
false);
829 bool ActionScheduler::ignoreChanges(
bool ignore )
831 bool oldValue = mIgnore;
836 #include "actionscheduler.moc" 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 void sendMDN(KMMessage *msg, KMime::MDN::DispositionType d, const TQValueList< KMime::MDN::DispositionModifier > &m=TQValueList< KMime::MDN::DispositionModifier >())
Automates the sending of MDNs from filter actions.
void setStatus(const KMMsgStatus status, int idx=-1)
Set status and mark dirty.
Abstract base class for KMail's filter actions.
const KMMsgBase * getMsgBase(int idx) const
Provides access to the basic message fields that are also stored in the index.
static const KMMsgDict * instance()
Access the globally unique MessageDict.
void setHeaderField(const TQCString &name, const TQString &value, HeaderFieldType type=Unstructured, bool prepend=false)
Set the header field with the given name to the given value.
void setComplete(bool v)
Set if the message is a complete message.
void add(TQString logEntry, ContentType contentType)
add a log entry
ReturnCode
Possible return codes of process:
bool isLogging()
check the logging state
int expunge()
Delete entire folder.
virtual void processAsync(KMMessage *msg) const
Execute an action on given message asynchronously.
bool isComplete() const
Return true if the complete message is available without referring to the backing store...
TQCString asString() const
Return the entire message contents as a string.
KMMessage * getMsg(int idx)
Read message at given index.
KMMsgStatus status() const
Status of the message.
void close(const char *owner, bool force=false)
Close folder.
The account manager is responsible for creating accounts of various types via the factory method crea...
void setTransferInProgress(bool value, bool force=false)
Set that the message shall not be deleted because it is still required.
int open(const char *owner)
Open folder for access.
void addSeparator()
add a separating line in the log
TQString headerField(const TQCString &name) const
Returns the value of a header field with the given name.
static FilterLog * instance()
access to the singleton instance