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"