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"