00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #ifdef HAVE_CONFIG_H
00032 #include <config.h>
00033 #endif
00034
00035 #include "actionscheduler.h"
00036
00037 #include "messageproperty.h"
00038 #include "kmfilter.h"
00039 #include "kmfolderindex.h"
00040 #include "kmfoldermgr.h"
00041 #include "kmmsgdict.h"
00042 #include "kmcommands.h"
00043 #include "kmheaders.h"
00044
00045 #include <qtimer.h>
00046 #include <kconfig.h>
00047 #include <kstandarddirs.h>
00048
00049 using namespace KMail;
00050 typedef QPtrList<KMMsgBase> KMMessageList;
00051
00052 KMFolderMgr* ActionScheduler::tempFolderMgr = 0;
00053 int ActionScheduler::refCount = 0;
00054 int ActionScheduler::count = 0;
00055
00056 ActionScheduler::ActionScheduler(KMFilterMgr::FilterSet set,
00057 QPtrList<KMFilter> filters,
00058 KMHeaders *headers,
00059 KMFolder *srcFolder)
00060 :mSet( set ), mHeaders( headers )
00061 {
00062 ++count;
00063 ++refCount;
00064 mExecuting = false;
00065 mExecutingLock = false;
00066 mFetchExecuting = false;
00067 mFiltersAreQueued = false;
00068 mResult = ResultOk;
00069 mIgnore = false;
00070 mAutoDestruct = false;
00071 mAlwaysMatch = false;
00072 KMFilter *filter;
00073 finishTimer = new QTimer( this );
00074 connect( finishTimer, SIGNAL(timeout()), this, SLOT(finish()));
00075 fetchMessageTimer = new QTimer( this );
00076 connect( fetchMessageTimer, SIGNAL(timeout()), this, SLOT(fetchMessage()));
00077 tempCloseFoldersTimer = new QTimer( this );
00078 connect( tempCloseFoldersTimer, SIGNAL(timeout()), this, SLOT(tempCloseFolders()));
00079 processMessageTimer = new QTimer( this );
00080 connect( processMessageTimer, SIGNAL(timeout()), this, SLOT(processMessage()));
00081 filterMessageTimer = new QTimer( this );
00082 connect( filterMessageTimer, SIGNAL(timeout()), this, SLOT(filterMessage()));
00083
00084 for (filter = filters.first(); filter; filter = filters.next())
00085 mFilters.append( *filter );
00086 mDestFolder = 0;
00087 if (srcFolder) {
00088 mDeleteSrcFolder = false;
00089 setSourceFolder( srcFolder );
00090 } else {
00091 QString tmpName;
00092 tmpName.setNum( count );
00093 if (!tempFolderMgr)
00094 tempFolderMgr = new KMFolderMgr(locateLocal("data","kmail/filter"));
00095 KMFolder *tempFolder = tempFolderMgr->findOrCreate( tmpName );
00096 tempFolder->expunge();
00097 mDeleteSrcFolder = true;
00098 setSourceFolder( tempFolder );
00099 }
00100 }
00101
00102 ActionScheduler::~ActionScheduler()
00103 {
00104 tempCloseFolders();
00105 mSrcFolder->close();
00106
00107 if (mDeleteSrcFolder)
00108 tempFolderMgr->remove(mSrcFolder);
00109
00110 --refCount;
00111 if (refCount == 0) {
00112 delete tempFolderMgr;
00113 tempFolderMgr = 0;
00114 }
00115 }
00116
00117 void ActionScheduler::setAutoDestruct( bool autoDestruct )
00118 {
00119 mAutoDestruct = autoDestruct;
00120 }
00121
00122 void ActionScheduler::setAlwaysMatch( bool alwaysMatch )
00123 {
00124 mAlwaysMatch = alwaysMatch;
00125 }
00126
00127 void ActionScheduler::setDefaultDestinationFolder( KMFolder *destFolder )
00128 {
00129 mDestFolder = destFolder;
00130 }
00131
00132 void ActionScheduler::setSourceFolder( KMFolder *srcFolder )
00133 {
00134 srcFolder->open();
00135 if (mSrcFolder) {
00136 disconnect( mSrcFolder, SIGNAL(msgAdded(KMFolder*, Q_UINT32)),
00137 this, SLOT(msgAdded(KMFolder*, Q_UINT32)) );
00138 mSrcFolder->close();
00139 }
00140 mSrcFolder = srcFolder;
00141 int i = 0;
00142 for (i = 0; i < mSrcFolder->count(); ++i)
00143 enqueue( mSrcFolder->getMsgBase( i )->getMsgSerNum() );
00144 if (mSrcFolder)
00145 connect( mSrcFolder, SIGNAL(msgAdded(KMFolder*, Q_UINT32)),
00146 this, SLOT(msgAdded(KMFolder*, Q_UINT32)) );
00147 }
00148
00149 void ActionScheduler::setFilterList( QPtrList<KMFilter> filters )
00150 {
00151 mFiltersAreQueued = true;
00152 mQueuedFilters.clear();
00153 KMFilter *filter;
00154 for (filter = filters.first(); filter; filter = filters.next())
00155 mQueuedFilters.append( *filter );
00156 }
00157
00158 int ActionScheduler::tempOpenFolder( KMFolder* aFolder )
00159 {
00160 assert( aFolder );
00161 tempCloseFoldersTimer->stop();
00162 if ( aFolder == mSrcFolder.operator->() )
00163 return 0;
00164
00165 int rc = aFolder->open();
00166 if (rc)
00167 return rc;
00168
00169 mOpenFolders.append( aFolder );
00170 return 0;
00171 }
00172
00173 void ActionScheduler::tempCloseFolders()
00174 {
00175
00176 QValueListConstIterator<QGuardedPtr<KMFolder> > it;
00177 for (it = mOpenFolders.begin(); it != mOpenFolders.end(); ++it) {
00178 KMFolder *folder = *it;
00179 if (folder)
00180 folder->close();
00181 }
00182 mOpenFolders.clear();
00183 }
00184
00185 void ActionScheduler::execFilters(const QValueList<Q_UINT32> serNums)
00186 {
00187 QValueListConstIterator<Q_UINT32> it;
00188 for (it = serNums.begin(); it != serNums.end(); ++it)
00189 execFilters( *it );
00190 }
00191
00192 void ActionScheduler::execFilters(const QPtrList<KMMsgBase> msgList)
00193 {
00194 KMMsgBase *msgBase;
00195 QPtrList<KMMsgBase> list = msgList;
00196 for (msgBase = list.first(); msgBase; msgBase = list.next())
00197 execFilters( msgBase->getMsgSerNum() );
00198 }
00199
00200 void ActionScheduler::execFilters(KMMsgBase* msgBase)
00201 {
00202 execFilters( msgBase->getMsgSerNum() );
00203 }
00204
00205 void ActionScheduler::execFilters(Q_UINT32 serNum)
00206 {
00207 if (mResult != ResultOk)
00208 return;
00209
00210 if (MessageProperty::filtering( serNum )) {
00211
00212 mResult = ResultError;
00213 if (!mExecuting)
00214 finishTimer->start( 0, true );
00215 } else {
00216
00217 mFetchSerNums.append( serNum );
00218 if (!mFetchExecuting) {
00219
00220 mFetchExecuting = true;
00221 fetchMessageTimer->start( 0, true );
00222 }
00223 }
00224 }
00225
00226 KMMsgBase *ActionScheduler::messageBase(Q_UINT32 serNum)
00227 {
00228 int idx = -1;
00229 KMFolder *folder = 0;
00230 KMMsgBase *msg = 0;
00231 kmkernel->msgDict()->getLocation( serNum, &folder, &idx );
00232
00233
00234 if (folder && (idx != -1)) {
00235
00236 msg = folder->getMsgBase( idx );
00237 tempOpenFolder( folder );
00238 } else {
00239
00240 mResult = ResultError;
00241 finishTimer->start( 0, true );
00242 }
00243 return msg;
00244 }
00245
00246 KMMessage *ActionScheduler::message(Q_UINT32 serNum)
00247 {
00248 int idx = -1;
00249 KMFolder *folder = 0;
00250 KMMessage *msg = 0;
00251 kmkernel->msgDict()->getLocation( serNum, &folder, &idx );
00252
00253
00254 if (folder && (idx != -1)) {
00255
00256 msg = folder->getMsg( idx );
00257 tempOpenFolder( folder );
00258 } else {
00259
00260 mResult = ResultError;
00261 finishTimer->start( 0, true );
00262 }
00263 return msg;
00264 }
00265
00266 void ActionScheduler::finish()
00267 {
00268 if (mResult == ResultCriticalError) {
00269
00270 emit result( mResult );
00271 return;
00272 }
00273
00274 if (!mFetchExecuting && !mExecuting) {
00275
00276
00277
00278
00279 if (!mDeleteSrcFolder && !mDestFolder.isNull() ) {
00280 while ( mSrcFolder->count() > 0 ) {
00281 KMMessage *msg = mSrcFolder->getMsg( 0 );
00282 mDestFolder->moveMsg( msg );
00283 }
00284
00285
00286
00287 tempCloseFoldersTimer->start( 60*1000, true );
00288 }
00289 mSerNums.clear();
00290 mFetchSerNums.clear();
00291
00292 if (mFiltersAreQueued)
00293 mFilters = mQueuedFilters;
00294 mQueuedFilters.clear();
00295 mFiltersAreQueued = false;
00296 ReturnCode aResult = mResult;
00297 mResult = ResultOk;
00298 mExecutingLock = false;
00299 emit result( aResult );
00300 if (mAutoDestruct)
00301 delete this;
00302 }
00303
00304
00305
00306 }
00307
00308 void ActionScheduler::fetchMessage()
00309 {
00310 QValueListIterator<Q_UINT32> mFetchMessageIt = mFetchSerNums.begin();
00311 while (mFetchMessageIt != mFetchSerNums.end()) {
00312 if (!MessageProperty::transferInProgress(*mFetchMessageIt))
00313 break;
00314 ++mFetchMessageIt;
00315 }
00316 if (mFetchMessageIt == mFetchSerNums.end() && !mFetchSerNums.isEmpty())
00317 mResult = ResultError;
00318 if ((mFetchMessageIt == mFetchSerNums.end()) || (mResult != ResultOk)) {
00319 mFetchExecuting = false;
00320 if (!mSrcFolder->count())
00321 mSrcFolder->expunge();
00322 finishTimer->start( 0, true );
00323 return;
00324 }
00325
00326
00327 KMMsgBase *msgBase = messageBase( *mFetchMessageIt );
00328 if (mResult != ResultOk) {
00329 mFetchExecuting = false;
00330 return;
00331 }
00332 mFetchUnget = msgBase->isMessage();
00333 KMMessage *msg = message( *mFetchMessageIt );
00334 if (mResult != ResultOk) {
00335 mFetchExecuting = false;
00336 return;
00337 }
00338
00339 if (msg && msg->isComplete()) {
00340 messageFetched( msg );
00341 } else if (msg) {
00342 FolderJob *job = msg->parent()->createJob( msg );
00343 connect( job, SIGNAL(messageRetrieved( KMMessage* )),
00344 SLOT(messageFetched( KMMessage* )) );
00345 job->start();
00346 } else {
00347 mFetchExecuting = false;
00348 mResult = ResultError;
00349 finishTimer->start( 0, true );
00350 return;
00351 }
00352 }
00353
00354 void ActionScheduler::messageFetched( KMMessage *msg )
00355 {
00356 mFetchSerNums.remove( mFetchSerNums.begin() );
00357
00358 if ((mSet & KMFilterMgr::Explicit) ||
00359 (msg->headerField( "X-KMail-Filtered" ).isEmpty())) {
00360 QString serNumS;
00361 serNumS.setNum( msg->getMsgSerNum() );
00362 KMMessage *newMsg = new KMMessage;
00363 newMsg->fromString(msg->asString());
00364 newMsg->setStatus(msg->status());
00365 newMsg->setComplete(msg->isComplete());
00366 newMsg->setHeaderField( "X-KMail-Filtered", serNumS );
00367 mSrcFolder->addMsg( newMsg );
00368 }
00369 if (mFetchUnget && msg->parent())
00370 msg->parent()->unGetMsg( msg->parent()->find( msg ));
00371 fetchMessageTimer->start( 0, true );
00372 return;
00373 }
00374
00375 void ActionScheduler::msgAdded( KMFolder*, Q_UINT32 serNum )
00376 {
00377 if (!mIgnore)
00378 enqueue( serNum );
00379 }
00380
00381 void ActionScheduler::enqueue(Q_UINT32 serNum)
00382 {
00383 if (mResult != ResultOk)
00384 return;
00385
00386 if (MessageProperty::filtering( serNum )) {
00387
00388 mResult = ResultError;
00389 if (!mExecuting)
00390 finishTimer->start( 0, true );
00391 } else {
00392
00393 mSerNums.append( serNum );
00394
00395 if (!mExecuting) {
00396
00397 mExecuting = true;
00398 mMessageIt = mSerNums.begin();
00399 processMessageTimer->start( 0, true );
00400 }
00401 }
00402 }
00403
00404 void ActionScheduler::processMessage()
00405 {
00406 if (mExecutingLock)
00407 return;
00408 mExecutingLock = true;
00409 mMessageIt = mSerNums.begin();
00410 while (mMessageIt != mSerNums.end()) {
00411 if (!MessageProperty::transferInProgress(*mMessageIt))
00412 break;
00413 ++mMessageIt;
00414 }
00415 if (mMessageIt == mSerNums.end() && !mSerNums.isEmpty())
00416 mResult = ResultError;
00417 if ((mMessageIt == mSerNums.end()) || (mResult != ResultOk)) {
00418 mExecutingLock = false;
00419 mExecuting = false;
00420 finishTimer->start( 0, true );
00421 return;
00422 }
00423
00424
00425 KMMsgBase *msgBase = messageBase( *mMessageIt );
00426 if (mResult != ResultOk) {
00427 mExecuting = false;
00428 return;
00429 }
00430
00431 MessageProperty::setFiltering( *mMessageIt, true );
00432 MessageProperty::setFilterHandler( *mMessageIt, this );
00433 MessageProperty::setFilterFolder( *mMessageIt, mDestFolder );
00434 mFilterIt = mFilters.begin();
00435
00436 mUnget = msgBase->isMessage();
00437 KMMessage *msg = message( *mMessageIt );
00438 if (mResult != ResultOk) {
00439 mExecuting = false;
00440 return;
00441 }
00442
00443 bool mdnEnabled = true;
00444 {
00445 KConfigGroup mdnConfig( kmkernel->config(), "MDN" );
00446 int mode = mdnConfig.readNumEntry( "default-policy", 0 );
00447 if (!mode || mode < 0 || mode > 3)
00448 mdnEnabled = false;
00449 }
00450 mdnEnabled = true;
00451
00452 if ((msg && msg->isComplete()) ||
00453 (msg && !(*mFilterIt).requiresBody(msg) && !mdnEnabled))
00454 {
00455
00456
00457
00458 msg->setTransferInProgress( true );
00459 filterMessageTimer->start( 0, true );
00460 return;
00461 }
00462 if (msg) {
00463 FolderJob *job = msg->parent()->createJob( msg );
00464 connect( job, SIGNAL(messageRetrieved( KMMessage* )),
00465 SLOT(messageRetrieved( KMMessage* )) );
00466 job->start();
00467 } else {
00468 mExecuting = false;
00469 mResult = ResultError;
00470 finishTimer->start( 0, true );
00471 return;
00472 }
00473 }
00474
00475 void ActionScheduler::messageRetrieved(KMMessage* msg)
00476 {
00477
00478 msg->setTransferInProgress( true );
00479 filterMessageTimer->start( 0, true );
00480 }
00481
00482 void ActionScheduler::filterMessage()
00483 {
00484 if (mFilterIt == mFilters.end()) {
00485 moveMessage();
00486 return;
00487 }
00488 if (((mSet & KMFilterMgr::Outbound) && (*mFilterIt).applyOnOutbound()) ||
00489 ((mSet & KMFilterMgr::Inbound) && (*mFilterIt).applyOnInbound()) ||
00490 ((mSet & KMFilterMgr::Explicit) && (*mFilterIt).applyOnExplicit())) {
00491
00492 if (mAlwaysMatch ||
00493 (*mFilterIt).pattern()->matches( *mMessageIt )) {
00494 mFilterAction = (*mFilterIt).actions()->first();
00495 actionMessage();
00496 return;
00497 }
00498 }
00499 ++mFilterIt;
00500 filterMessageTimer->start( 0, true );
00501 }
00502
00503 void ActionScheduler::actionMessage(KMFilterAction::ReturnCode res)
00504 {
00505 if (res == KMFilterAction::CriticalError) {
00506 mResult = ResultCriticalError;
00507 finish();
00508 }
00509 if (mFilterAction) {
00510 KMMessage *msg = message( *mMessageIt );
00511 if (msg) {
00512 KMFilterAction *action = mFilterAction;
00513 mFilterAction = (*mFilterIt).actions()->next();
00514 action->processAsync( msg );
00515 }
00516 } else {
00517
00518 if ((*mFilterIt).stopProcessingHere())
00519 mFilterIt = mFilters.end();
00520 else
00521 ++mFilterIt;
00522 filterMessageTimer->start( 0, true );
00523 }
00524 }
00525
00526 void ActionScheduler::moveMessage()
00527 {
00528 KMMsgBase *msgBase = messageBase( *mMessageIt );
00529 if (!msgBase)
00530 return;
00531
00532 MessageProperty::setTransferInProgress( *mMessageIt, false, true );
00533 KMMessage *msg = message( *mMessageIt );
00534 KMFolder *folder = MessageProperty::filterFolder( *mMessageIt );
00535 QString serNumS = msg->headerField( "X-KMail-Filtered" );
00536 if (!serNumS.isEmpty())
00537 mOriginalSerNum = serNumS.toUInt();
00538 else
00539 mOriginalSerNum = 0;
00540 MessageProperty::setFilterHandler( *mMessageIt, 0 );
00541 MessageProperty::setFiltering( *mMessageIt, false );
00542 mSerNums.remove( *mMessageIt );
00543
00544 KMMessage *orgMsg = 0;
00545 ReturnCode mOldReturnCode = mResult;
00546 if (mOriginalSerNum)
00547 orgMsg = message( mOriginalSerNum );
00548 mResult = mOldReturnCode;
00549 if (!orgMsg || !orgMsg->parent()) {
00550
00551 mSrcFolder->removeMsg( mSrcFolder->find( msg ) );
00552 mExecutingLock = false;
00553 processMessageTimer->start( 0, true );
00554 } else {
00555 if (!folder)
00556 folder = orgMsg->parent();
00557 }
00558
00559 mIgnore = true;
00560 assert( msg->parent() == mSrcFolder.operator->() );
00561 mSrcFolder->take( mSrcFolder->find( msg ) );
00562 mSrcFolder->addMsg( msg );
00563 mIgnore = false;
00564
00565 if (msg && kmkernel->folderIsTrash( folder ))
00566 KMFilterAction::sendMDN( msg, KMime::MDN::Deleted );
00567
00568 KMCommand *cmd = new KMMoveCommand( folder, msg );
00569 connect ( cmd, SIGNAL( completed(bool) ),
00570 this, SLOT( moveMessageFinished(bool) ) );
00571 cmd->start();
00572 }
00573
00574 void ActionScheduler::moveMessageFinished(bool success)
00575 {
00576 if ( !success )
00577 mResult = ResultError;
00578
00579 if (!mSrcFolder->count())
00580 mSrcFolder->expunge();
00581
00582
00583 if ( mHeaders )
00584 mHeaders->clearSelectableAndAboutToBeDeleted( mOriginalSerNum );
00585 KMMessage *msg = 0;
00586 ReturnCode mOldReturnCode = mResult;
00587 if (mOriginalSerNum)
00588 msg = message( mOriginalSerNum );
00589 mResult = mOldReturnCode;
00590 if (msg && msg->parent()) {
00591 KMCommand *cmd = new KMMoveCommand( 0, msg );
00592 cmd->start();
00593 }
00594
00595 if (mResult == ResultOk) {
00596 mExecutingLock = false;
00597 processMessageTimer->start( 0, true );
00598 } else {
00599 finishTimer->start( 0, true );
00600 }
00601
00602 }
00603
00604 #include "actionscheduler.moc"