kmail

expirejob.cpp
1 
29 #include "expirejob.h"
30 #include "kmfolder.h"
31 #include "globalsettings.h"
32 #include "folderstorage.h"
33 #include "broadcaststatus.h"
34 using KPIM::BroadcastStatus;
35 #include "kmcommands.h"
36 
37 #include <kdebug.h>
38 #include <tdelocale.h>
39 
40 using namespace KMail;
41 
42 // Look at this number of messages in each slotDoWork call
43 #define EXPIREJOB_NRMESSAGES 100
44 // And wait this number of milliseconds before calling it again
45 #define EXPIREJOB_TIMERINTERVAL 100
46 
47 /*
48  Testcases for folder expiry:
49  Automatic expiry:
50  - normal case (ensure folder has old mails and expiry settings, wait for auto-expiry)
51  - having the folder selected when the expiry job would run (gets delayed)
52  - selecting a folder while an expiry job is running for it (should interrupt)
53  - exiting kmail while an expiry job is running (should abort & delete things cleanly)
54  Manual expiry:
55  - RMB / expire (for one folder) [KMMainWidget::slotExpireFolder()]
56  - RMB on Local Folders / Expire All Folders [KMFolderMgr::expireAll()]
57  - Expire All Folders [KMMainWidget::slotExpireAll()]
58 */
59 
60 
61 ExpireJob::ExpireJob( KMFolder* folder, bool immediate )
62  : ScheduledJob( folder, immediate ), mTimer( this ), mCurrentIndex( 0 ),
63  mFolderOpen( false ), mMoveToFolder( 0 )
64 {
65 }
66 
67 ExpireJob::~ExpireJob()
68 {
69 }
70 
71 void ExpireJob::kill()
72 {
73  Q_ASSERT( mCancellable );
74  // We must close the folder if we opened it and got interrupted
75  if ( mFolderOpen && mSrcFolder && mSrcFolder->storage() )
76  mSrcFolder->storage()->close( "expirejob" );
77  FolderJob::kill();
78 }
79 
80 void ExpireJob::execute()
81 {
82  mMaxUnreadTime = -1;
83  mMaxReadTime = -1;
84  mCurrentIndex = 0;
85 
86  int unreadDays, readDays;
87  mSrcFolder->daysToExpire( unreadDays, readDays );
88  if (unreadDays >= 0) {
89  kdDebug(5006) << "ExpireJob: deleting unread older than "<< unreadDays << " days" << endl;
90  mMaxUnreadTime = time(0) - unreadDays * 3600 * 24;
91  }
92  if (readDays >= 0) {
93  kdDebug(5006) << "ExpireJob: deleting read older than "<< readDays << " days" << endl;
94  mMaxReadTime = time(0) - readDays * 3600 * 24;
95  }
96 
97  if ((mMaxUnreadTime == 0) && (mMaxReadTime == 0)) {
98  kdDebug(5006) << "ExpireJob: nothing to do" << endl;
99  delete this;
100  return;
101  }
102 
103  FolderStorage* storage = mSrcFolder->storage();
104  mOpeningFolder = true; // Ignore open-notifications while opening the folder
105  storage->open( "expirejob" );
106  mOpeningFolder = false;
107  mFolderOpen = true;
108  mCurrentIndex = storage->count()-1;
109  kdDebug(5006) << "ExpireJob: starting to expire in folder " << mSrcFolder->location() << endl;
110  connect( &mTimer, TQ_SIGNAL( timeout() ), TQ_SLOT( slotDoWork() ) );
111  mTimer.start( EXPIREJOB_TIMERINTERVAL );
112  slotDoWork();
113  // do nothing here, we might be deleted!
114 }
115 
116 void ExpireJob::slotDoWork()
117 {
118  // No need to worry about mSrcFolder==0 here. The FolderStorage deletes the jobs on destruction.
119  FolderStorage* storage = mSrcFolder->storage();
120  int stopIndex = mImmediate ? 0 : TQMAX( 0, mCurrentIndex - EXPIREJOB_NRMESSAGES );
121 #ifdef DEBUG_SCHEDULER
122  kdDebug(5006) << "ExpireJob: checking messages " << mCurrentIndex << " to " << stopIndex << endl;
123 #endif
124  for( ; mCurrentIndex >= stopIndex; mCurrentIndex-- ) {
125  const KMMsgBase *mb = storage->getMsgBase( mCurrentIndex );
126 #ifdef DEBUG_SCHEDULER
127  kdDebug(5006) << "ExpireJob: checking message " << mCurrentIndex << " existence" << endl;
128 #endif
129  if (mb == 0)
130  continue;
131 #ifdef DEBUG_SCHEDULER
132  kdDebug(5006) << "ExpireJob: checking message " << mCurrentIndex << " importance" << endl;
133 #endif
134  if ( ( mb->isImportant() || mb->isTodo() || mb->isWatched() )
135  && GlobalSettings::self()->excludeImportantMailFromExpiry() )
136  continue;
137 
138 #ifdef DEBUG_SCHEDULER
139  kdDebug(5006) << "ExpireJob: checking message " << mCurrentIndex << " time" << endl;
140 #endif
141  time_t maxTime = mb->isUnread() ? mMaxUnreadTime : mMaxReadTime;
142 
143 #ifdef DEBUG_SCHEDULER
144  kdDebug(5006) << "ExpireJob: checking message " << mCurrentIndex << " time (" << mb->date() << " vs " << maxTime << ")" << endl;
145 #endif
146  if (mb->date() < maxTime) {
147  kdDebug(5006) << "ExpireJob: expiring message " << mCurrentIndex << " from folder " << mSrcFolder->location() << endl;
148  mRemovedMsgs.append( storage->getMsgBase( mCurrentIndex ) );
149  }
150  }
151  if ( stopIndex == 0 )
152  done();
153 }
154 
155 void ExpireJob::done()
156 {
157  mTimer.stop();
158 
159  TQString str;
160  bool moving = false;
161 
162  if ( !mRemovedMsgs.isEmpty() ) {
163  int count = mRemovedMsgs.count();
164  // The command shouldn't kill us because it opens the folder
165  mCancellable = false;
166  if ( mSrcFolder->expireAction() == KMFolder::ExpireDelete ) {
167  // Expire by deletion, i.e. move to null target folder
168  kdDebug(5006) << "ExpireJob: finished expiring in folder "
169  << mSrcFolder->location()
170  << " " << count << " messages to remove." << endl;
171  KMMoveCommand* cmd = new KMMoveCommand( 0, mRemovedMsgs );
172  connect( cmd, TQ_SIGNAL( completed( KMCommand * ) ),
173  this, TQ_SLOT( slotMessagesMoved( KMCommand * ) ) );
174  cmd->start();
175  moving = true;
176  str = i18n( "Removing 1 old message from folder %1...",
177  "Removing %n old messages from folder %1...", count )
178  .arg( mSrcFolder->label() );
179  } else {
180  // Expire by moving
181  mMoveToFolder =
182  kmkernel->findFolderById( mSrcFolder->expireToFolderId() );
183  if ( !mMoveToFolder ) {
184  str = i18n( "Cannot expire messages from folder %1: destination "
185  "folder %2 not found" )
186  .arg( mSrcFolder->label(), mSrcFolder->expireToFolderId() );
187  kdWarning(5006) << str << endl;
188  } else {
189  kdDebug(5006) << "ExpireJob: finished expiring in folder "
190  << mSrcFolder->location() << " "
191  << mRemovedMsgs.count() << " messages to move to "
192  << mMoveToFolder->label() << endl;
193  KMMoveCommand* cmd = new KMMoveCommand( mMoveToFolder, mRemovedMsgs );
194  connect( cmd, TQ_SIGNAL( completed( KMCommand * ) ),
195  this, TQ_SLOT( slotMessagesMoved( KMCommand * ) ) );
196  cmd->start();
197  moving = true;
198  str = i18n( "Moving 1 old message from folder %1 to folder %2...",
199  "Moving %n old messages from folder %1 to folder %2...",
200  count )
201  .arg( mSrcFolder->label(), mMoveToFolder->label() );
202  }
203  }
204  }
205  if ( !str.isEmpty() )
206  BroadcastStatus::instance()->setStatusMsg( str );
207 
208  TDEConfigGroup group( KMKernel::config(), "Folder-" + mSrcFolder->idString() );
209  group.writeEntry( "Current", -1 ); // i.e. make it invalid, the serial number will be used
210 
211  if ( !moving ) {
212  mSrcFolder->storage()->close( "expirejob" );
213  mFolderOpen = false;
214  delete this;
215  }
216 }
217 
218 void ExpireJob::slotMessagesMoved( KMCommand *command )
219 {
220  mSrcFolder->storage()->close( "expirejob" );
221  mFolderOpen = false;
222  TQString msg;
223  switch ( command->result() ) {
224  case KMCommand::OK:
225  if ( mSrcFolder->expireAction() == KMFolder::ExpireDelete ) {
226  msg = i18n( "Removed 1 old message from folder %1.",
227  "Removed %n old messages from folder %1.",
228  mRemovedMsgs.count() )
229  .arg( mSrcFolder->label() );
230  }
231  else {
232  msg = i18n( "Moved 1 old message from folder %1 to folder %2.",
233  "Moved %n old messages from folder %1 to folder %2.",
234  mRemovedMsgs.count() )
235  .arg( mSrcFolder->label(), mMoveToFolder->label() );
236  }
237  break;
238  case KMCommand::Failed:
239  if ( mSrcFolder->expireAction() == KMFolder::ExpireDelete ) {
240  msg = i18n( "Removing old messages from folder %1 failed." )
241  .arg( mSrcFolder->label() );
242  }
243  else {
244  msg = i18n( "Moving old messages from folder %1 to folder %2 failed." )
245  .arg( mSrcFolder->label(), mMoveToFolder->label() );
246  }
247  break;
248  case KMCommand::Canceled:
249  if ( mSrcFolder->expireAction() == KMFolder::ExpireDelete ) {
250  msg = i18n( "Removing old messages from folder %1 was canceled." )
251  .arg( mSrcFolder->label() );
252  }
253  else {
254  msg = i18n( "Moving old messages from folder %1 to folder %2 was "
255  "canceled." )
256  .arg( mSrcFolder->label(), mMoveToFolder->label() );
257  }
258  default: ;
259  }
260  BroadcastStatus::instance()->setStatusMsg( msg );
261 
262  deleteLater();
263 }
264 
265 #include "expirejob.moc"
The FolderStorage class is the bass class for the storage related aspects of a collection of mail (a ...
Definition: folderstorage.h:80
virtual int open(const char *owner)=0
Open folder for access.
virtual int count(bool cache=false) const
Number of messages in this folder.
virtual const KMMsgBase * getMsgBase(int idx) const =0
Provides access to the basic message fields that are also stored in the index.
Mail folder.
Definition: kmfolder.h:69
Base class for scheduled jobs.
Definition: jobscheduler.h:144
folderdiaquotatab.h
Definition: aboutdata.cpp:40