kmail

expirejob.cpp

00001 
00029 #include "expirejob.h"
00030 #include "kmfolder.h"
00031 #include "globalsettings.h"
00032 #include "folderstorage.h"
00033 #include "broadcaststatus.h"
00034 using KPIM::BroadcastStatus;
00035 #include "kmcommands.h"
00036 
00037 #include <kdebug.h>
00038 #include <tdelocale.h>
00039 
00040 using namespace KMail;
00041 
00042 // Look at this number of messages in each slotDoWork call
00043 #define EXPIREJOB_NRMESSAGES 100
00044 // And wait this number of milliseconds before calling it again
00045 #define EXPIREJOB_TIMERINTERVAL 100
00046 
00047 /*
00048  Testcases for folder expiry:
00049   Automatic expiry:
00050   - normal case (ensure folder has old mails and expiry settings, wait for auto-expiry)
00051   - having the folder selected when the expiry job would run (gets delayed)
00052   - selecting a folder while an expiry job is running for it (should interrupt)
00053   - exiting kmail while an expiry job is running (should abort & delete things cleanly)
00054   Manual expiry:
00055   - RMB / expire (for one folder)                   [KMMainWidget::slotExpireFolder()]
00056   - RMB on Local Folders / Expire All Folders       [KMFolderMgr::expireAll()]
00057   - Expire All Folders                              [KMMainWidget::slotExpireAll()]
00058 */
00059 
00060 
00061 ExpireJob::ExpireJob( KMFolder* folder, bool immediate )
00062  : ScheduledJob( folder, immediate ), mTimer( this ), mCurrentIndex( 0 ),
00063    mFolderOpen( false ), mMoveToFolder( 0 )
00064 {
00065 }
00066 
00067 ExpireJob::~ExpireJob()
00068 {
00069 }
00070 
00071 void ExpireJob::kill()
00072 {
00073   Q_ASSERT( mCancellable );
00074   // We must close the folder if we opened it and got interrupted
00075   if ( mFolderOpen && mSrcFolder && mSrcFolder->storage() )
00076     mSrcFolder->storage()->close( "expirejob" );
00077   FolderJob::kill();
00078 }
00079 
00080 void ExpireJob::execute()
00081 {
00082   mMaxUnreadTime = -1;
00083   mMaxReadTime = -1;
00084   mCurrentIndex = 0;
00085 
00086   int unreadDays, readDays;
00087   mSrcFolder->daysToExpire( unreadDays, readDays );
00088   if (unreadDays >= 0) {
00089     kdDebug(5006) << "ExpireJob: deleting unread older than "<< unreadDays << " days" << endl;
00090     mMaxUnreadTime = time(0) - unreadDays * 3600 * 24;
00091   }
00092   if (readDays >= 0) {
00093     kdDebug(5006) << "ExpireJob: deleting read older than "<< readDays << " days" << endl;
00094     mMaxReadTime = time(0) - readDays * 3600 * 24;
00095   }
00096 
00097   if ((mMaxUnreadTime == 0) && (mMaxReadTime == 0)) {
00098     kdDebug(5006) << "ExpireJob: nothing to do" << endl;
00099     delete this;
00100     return;
00101   }
00102 
00103   FolderStorage* storage = mSrcFolder->storage();
00104   mOpeningFolder = true; // Ignore open-notifications while opening the folder
00105   storage->open( "expirejob" );
00106   mOpeningFolder = false;
00107   mFolderOpen = true;
00108   mCurrentIndex = storage->count()-1;
00109   kdDebug(5006) << "ExpireJob: starting to expire in folder " << mSrcFolder->location() << endl;
00110   connect( &mTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( slotDoWork() ) );
00111   mTimer.start( EXPIREJOB_TIMERINTERVAL );
00112   slotDoWork();
00113   // do nothing here, we might be deleted!
00114 }
00115 
00116 void ExpireJob::slotDoWork()
00117 {
00118   // No need to worry about mSrcFolder==0 here. The FolderStorage deletes the jobs on destruction.
00119   FolderStorage* storage = mSrcFolder->storage();
00120   int stopIndex = mImmediate ? 0 : TQMAX( 0, mCurrentIndex - EXPIREJOB_NRMESSAGES );
00121 #ifdef DEBUG_SCHEDULER
00122   kdDebug(5006) << "ExpireJob: checking messages " << mCurrentIndex << " to " << stopIndex << endl;
00123 #endif
00124   for( ; mCurrentIndex >= stopIndex; mCurrentIndex-- ) {
00125     const KMMsgBase *mb = storage->getMsgBase( mCurrentIndex );
00126 #ifdef DEBUG_SCHEDULER
00127     kdDebug(5006) << "ExpireJob: checking message " << mCurrentIndex << " existence" << endl;
00128 #endif
00129     if (mb == 0)
00130       continue;
00131 #ifdef DEBUG_SCHEDULER
00132     kdDebug(5006) << "ExpireJob: checking message " << mCurrentIndex << " importance" << endl;
00133 #endif
00134     if ( ( mb->isImportant() || mb->isTodo() || mb->isWatched() )
00135       && GlobalSettings::self()->excludeImportantMailFromExpiry() )
00136        continue;
00137 
00138 #ifdef DEBUG_SCHEDULER
00139     kdDebug(5006) << "ExpireJob: checking message " << mCurrentIndex << " time" << endl;
00140 #endif
00141     time_t maxTime = mb->isUnread() ? mMaxUnreadTime : mMaxReadTime;
00142 
00143 #ifdef DEBUG_SCHEDULER
00144     kdDebug(5006) << "ExpireJob: checking message " << mCurrentIndex << " time (" << mb->date() << " vs " << maxTime << ")" << endl;
00145 #endif
00146     if (mb->date() < maxTime) {
00147       kdDebug(5006) << "ExpireJob: expiring message " << mCurrentIndex << " from folder " << mSrcFolder->location() << endl;
00148       mRemovedMsgs.append( storage->getMsgBase( mCurrentIndex ) );
00149     }
00150   }
00151   if ( stopIndex == 0 )
00152     done();
00153 }
00154 
00155 void ExpireJob::done()
00156 {
00157   mTimer.stop();
00158 
00159   TQString str;
00160   bool moving = false;
00161 
00162   if ( !mRemovedMsgs.isEmpty() ) {
00163     int count = mRemovedMsgs.count();
00164     // The command shouldn't kill us because it opens the folder
00165     mCancellable = false;
00166     if ( mSrcFolder->expireAction() == KMFolder::ExpireDelete ) {
00167       // Expire by deletion, i.e. move to null target folder
00168       kdDebug(5006) << "ExpireJob: finished expiring in folder "
00169                     << mSrcFolder->location()
00170                     << " " << count << " messages to remove." << endl;
00171       KMMoveCommand* cmd = new KMMoveCommand( 0, mRemovedMsgs );
00172       connect( cmd, TQT_SIGNAL( completed( KMCommand * ) ),
00173                this, TQT_SLOT( slotMessagesMoved( KMCommand * ) ) );
00174       cmd->start();
00175       moving = true;
00176       str = i18n( "Removing 1 old message from folder %1...",
00177                   "Removing %n old messages from folder %1...", count )
00178             .arg( mSrcFolder->label() );
00179     } else {
00180       // Expire by moving
00181       mMoveToFolder =
00182         kmkernel->findFolderById( mSrcFolder->expireToFolderId() );
00183       if ( !mMoveToFolder ) {
00184         str = i18n( "Cannot expire messages from folder %1: destination "
00185                     "folder %2 not found" )
00186               .arg( mSrcFolder->label(), mSrcFolder->expireToFolderId() );
00187         kdWarning(5006) << str << endl;
00188       } else {
00189         kdDebug(5006) << "ExpireJob: finished expiring in folder "
00190                       << mSrcFolder->location() << " "
00191                       << mRemovedMsgs.count() << " messages to move to "
00192                       << mMoveToFolder->label() << endl;
00193         KMMoveCommand* cmd = new KMMoveCommand( mMoveToFolder, mRemovedMsgs );
00194         connect( cmd, TQT_SIGNAL( completed( KMCommand * ) ),
00195                  this, TQT_SLOT( slotMessagesMoved( KMCommand * ) ) );
00196         cmd->start();
00197         moving = true;
00198         str = i18n( "Moving 1 old message from folder %1 to folder %2...",
00199                     "Moving %n old messages from folder %1 to folder %2...",
00200                     count )
00201               .arg( mSrcFolder->label(), mMoveToFolder->label() );
00202       }
00203     }
00204   }
00205   if ( !str.isEmpty() )
00206     BroadcastStatus::instance()->setStatusMsg( str );
00207 
00208   TDEConfigGroup group( KMKernel::config(), "Folder-" + mSrcFolder->idString() );
00209   group.writeEntry( "Current", -1 ); // i.e. make it invalid, the serial number will be used
00210 
00211   if ( !moving ) {
00212     mSrcFolder->storage()->close( "expirejob" );
00213     mFolderOpen = false;
00214     delete this;
00215   }
00216 }
00217 
00218 void ExpireJob::slotMessagesMoved( KMCommand *command )
00219 {
00220   mSrcFolder->storage()->close( "expirejob" );
00221   mFolderOpen = false;
00222   TQString msg;
00223   switch ( command->result() ) {
00224   case KMCommand::OK:
00225     if ( mSrcFolder->expireAction() == KMFolder::ExpireDelete ) {
00226       msg = i18n( "Removed 1 old message from folder %1.",
00227                   "Removed %n old messages from folder %1.",
00228                   mRemovedMsgs.count() )
00229             .arg( mSrcFolder->label() );
00230     }
00231     else {
00232       msg = i18n( "Moved 1 old message from folder %1 to folder %2.",
00233                   "Moved %n old messages from folder %1 to folder %2.",
00234                   mRemovedMsgs.count() )
00235             .arg( mSrcFolder->label(), mMoveToFolder->label() );
00236     }
00237     break;
00238   case KMCommand::Failed:
00239     if ( mSrcFolder->expireAction() == KMFolder::ExpireDelete ) {
00240       msg = i18n( "Removing old messages from folder %1 failed." )
00241             .arg( mSrcFolder->label() );
00242     }
00243     else {
00244       msg = i18n( "Moving old messages from folder %1 to folder %2 failed." )
00245             .arg( mSrcFolder->label(), mMoveToFolder->label() );
00246     }
00247     break;
00248   case KMCommand::Canceled:
00249     if ( mSrcFolder->expireAction() == KMFolder::ExpireDelete ) {
00250       msg = i18n( "Removing old messages from folder %1 was canceled." )
00251             .arg( mSrcFolder->label() );
00252     }
00253     else {
00254       msg = i18n( "Moving old messages from folder %1 to folder %2 was "
00255                   "canceled." )
00256             .arg( mSrcFolder->label(), mMoveToFolder->label() );
00257     }
00258   default: ;
00259   }
00260   BroadcastStatus::instance()->setStatusMsg( msg );
00261 
00262   deleteLater();
00263 }
00264 
00265 #include "expirejob.moc"