kmail

compactionjob.cpp
1 
28 #include "compactionjob.h"
29 #include "kmfolder.h"
30 #include "broadcaststatus.h"
31 using KPIM::BroadcastStatus;
32 #include "kmfoldermbox.h"
33 #include "kmfoldermaildir.h"
34 
35 #include <kdebug.h>
36 #include <tdelocale.h>
37 
38 #include <tqfile.h>
39 #include <tqfileinfo.h>
40 #include <tqdir.h>
41 
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <errno.h>
45 
46 using namespace KMail;
47 
48 // Look at this number of messages in each slotDoWork call
49 #define COMPACTIONJOB_NRMESSAGES 100
50 // And wait this number of milliseconds before calling it again
51 #define COMPACTIONJOB_TIMERINTERVAL 100
52 
54  : ScheduledJob( folder, immediate ), mTimer( this, "mTimer" ), mTmpFile( 0 ),
55  mCurrentIndex( 0 ), mFolderOpen( false ), mSilent( false )
56 {
57 }
58 
59 MboxCompactionJob::~MboxCompactionJob()
60 {
61 }
62 
63 void MboxCompactionJob::kill()
64 {
65  Q_ASSERT( mCancellable );
66  // We must close the folder if we opened it and got interrupted
67  if ( mFolderOpen && mSrcFolder && mSrcFolder->storage() )
68  mSrcFolder->storage()->close("mboxcompact");
69 
70  if ( mTmpFile )
71  fclose( mTmpFile );
72  mTmpFile = 0;
73  if ( !mTempName.isEmpty() )
74  TQFile::remove( mTempName );
75  FolderJob::kill();
76 }
77 
78 TQString MboxCompactionJob::realLocation() const
79 {
80  TQString location = mSrcFolder->location();
81  TQFileInfo inf( location );
82  if (inf.isSymLink()) {
83  KURL u; u.setPath( location );
84  // follow (and resolve) symlinks so that the final ::rename() always works
85  // KURL gives us support for absolute and relative links transparently.
86  return KURL( u, inf.readLink() ).path();
87  }
88  return location;
89 }
90 
91 int MboxCompactionJob::executeNow( bool silent )
92 {
93  mSilent = silent;
94  FolderStorage* storage = mSrcFolder->storage();
95  KMFolderMbox* mbox = static_cast<KMFolderMbox *>( storage );
96  if (!storage->compactable()) {
97  kdDebug(5006) << storage->location() << " compaction skipped." << endl;
98  if ( !mSilent ) {
99  TQString str = i18n( "For safety reasons, compaction has been disabled for %1" ).arg( mbox->label() );
100  BroadcastStatus::instance()->setStatusMsg( str );
101  }
102  return 0;
103  }
104  kdDebug(5006) << "Compacting " << mSrcFolder->idString() << endl;
105 
106  if (KMFolderIndex::IndexOk != mbox->indexStatus()) {
107  kdDebug(5006) << "Critical error: " << storage->location() <<
108  " has been modified by an external application while KMail was running." << endl;
109  // exit(1); backed out due to broken nfs
110  }
111 
112  const TQFileInfo pathInfo( realLocation() );
113  // Use /dir/.mailboxname.compacted so that it's hidden, and doesn't show up after restarting kmail
114  // (e.g. due to an unfortunate crash while compaction is happening)
115  mTempName = pathInfo.dirPath() + "/." + pathInfo.fileName() + ".compacted";
116 
117  mode_t old_umask = umask(077);
118  mTmpFile = fopen(TQFile::encodeName(mTempName), "w");
119  umask(old_umask);
120  if (!mTmpFile) {
121  kdWarning(5006) << "Couldn't start compacting " << mSrcFolder->label()
122  << " : " << strerror( errno )
123  << " while creating " << mTempName << endl;
124  return errno;
125  }
126  mOpeningFolder = true; // Ignore open-notifications while opening the folder
127  storage->open("mboxcompact");
128  mOpeningFolder = false;
129  mFolderOpen = true;
130  mOffset = 0;
131  mCurrentIndex = 0;
132 
133  kdDebug(5006) << "MboxCompactionJob: starting to compact folder " << mSrcFolder->location() << " into " << mTempName << endl;
134  connect( &mTimer, TQ_SIGNAL( timeout() ), TQ_SLOT( slotDoWork() ) );
135  if ( !mImmediate )
136  mTimer.start( COMPACTIONJOB_TIMERINTERVAL );
137  slotDoWork();
138  return mErrorCode;
139 }
140 
141 void MboxCompactionJob::slotDoWork()
142 {
143  // No need to worry about mSrcFolder==0 here. The FolderStorage deletes the jobs on destruction.
144  KMFolderMbox* mbox = static_cast<KMFolderMbox *>( mSrcFolder->storage() );
145  bool bDone = false;
146  int nbMessages = mImmediate ? -1 /*all*/ : COMPACTIONJOB_NRMESSAGES;
147  int rc = mbox->compact( mCurrentIndex, nbMessages,
148  mTmpFile, mOffset /*in-out*/, bDone /*out*/ );
149  if ( !mImmediate )
150  mCurrentIndex += COMPACTIONJOB_NRMESSAGES;
151  if ( rc || bDone ) // error, or finished
152  done( rc );
153 }
154 
155 void MboxCompactionJob::done( int rc )
156 {
157  mTimer.stop();
158  mCancellable = false;
159  KMFolderMbox* mbox = static_cast<KMFolderMbox *>( mSrcFolder->storage() );
160  if (!rc)
161  rc = fflush(mTmpFile);
162  if (!rc)
163  rc = fsync(fileno(mTmpFile));
164  rc |= fclose(mTmpFile);
165  TQString str;
166  if (!rc) {
167  bool autoCreate = mbox->autoCreateIndex();
168  TQString box( realLocation() );
169  ::rename(TQFile::encodeName(mTempName), TQFile::encodeName(box));
170  mbox->writeIndex();
171  mbox->writeConfig();
172  mbox->setAutoCreateIndex( false );
173  mbox->close("mboxcompact", true);
174  mbox->setAutoCreateIndex( autoCreate );
175  mbox->setNeedsCompacting( false ); // We are clean now
176  str = i18n( "Folder \"%1\" successfully compacted" ).arg( mSrcFolder->label() );
177  kdDebug(5006) << str << endl;
178  } else {
179  mbox->close("mboxcompact");
180  str = i18n( "Error occurred while compacting \"%1\". Compaction aborted." ).arg( mSrcFolder->label() );
181  kdDebug(5006) << "Error occurred while compacting " << mbox->location() << endl;
182  kdDebug(5006) << "Compaction aborted." << endl;
183  TQFile::remove( mTempName );
184  }
185  mErrorCode = rc;
186 
187  if ( !mSilent )
188  BroadcastStatus::instance()->setStatusMsg( str );
189 
190  mFolderOpen = false;
191  deleteLater(); // later, because of the "return mErrorCode"
192 }
193 
195 
197  : ScheduledJob( folder, immediate ), mTimer( this, "mTimer" ),
198  mCurrentIndex( 0 ), mFolderOpen( false ), mSilent( false )
199 {
200 }
201 
202 MaildirCompactionJob::~MaildirCompactionJob()
203 {
204 }
205 
206 void MaildirCompactionJob::kill()
207 {
208  Q_ASSERT( mCancellable );
209  // We must close the folder if we opened it and got interrupted
210  if ( mFolderOpen && mSrcFolder && mSrcFolder->storage() )
211  mSrcFolder->storage()->close("maildircompact");
212 
213  FolderJob::kill();
214 }
215 
216 int MaildirCompactionJob::executeNow( bool silent )
217 {
218  mSilent = silent;
219  KMFolderMaildir* storage = static_cast<KMFolderMaildir *>( mSrcFolder->storage() );
220  kdDebug(5006) << "Compacting " << mSrcFolder->idString() << endl;
221 
222  mOpeningFolder = true; // Ignore open-notifications while opening the folder
223  storage->open("maildircompact");
224  mOpeningFolder = false;
225  mFolderOpen = true;
226  TQString subdirNew(storage->location() + "/new/");
227  TQDir d(subdirNew);
228  mEntryList = d.entryList();
229  mCurrentIndex = 0;
230 
231  kdDebug(5006) << "MaildirCompactionJob: starting to compact in folder " << mSrcFolder->location() << endl;
232  connect( &mTimer, TQ_SIGNAL( timeout() ), TQ_SLOT( slotDoWork() ) );
233  if ( !mImmediate )
234  mTimer.start( COMPACTIONJOB_TIMERINTERVAL );
235  slotDoWork();
236  return mErrorCode;
237 }
238 
239 void MaildirCompactionJob::slotDoWork()
240 {
241  // No need to worry about mSrcFolder==0 here. The FolderStorage deletes the jobs on destruction.
242  KMFolderMaildir* storage = static_cast<KMFolderMaildir *>( mSrcFolder->storage() );
243  bool bDone = false;
244  int nbMessages = mImmediate ? -1 /*all*/ : COMPACTIONJOB_NRMESSAGES;
245  int rc = storage->compact( mCurrentIndex, nbMessages, mEntryList, bDone /*out*/ );
246  if ( !mImmediate )
247  mCurrentIndex += COMPACTIONJOB_NRMESSAGES;
248  if ( rc || bDone ) // error, or finished
249  done( rc );
250 }
251 
252 void MaildirCompactionJob::done( int rc )
253 {
254  KMFolderMaildir* storage = static_cast<KMFolderMaildir *>( mSrcFolder->storage() );
255  mTimer.stop();
256  mCancellable = false;
257  TQString str;
258  if ( !rc ) {
259  str = i18n( "Folder \"%1\" successfully compacted" ).arg( mSrcFolder->label() );
260  } else {
261  str = i18n( "Error occurred while compacting \"%1\". Compaction aborted." ).arg( mSrcFolder->label() );
262  }
263  mErrorCode = rc;
264  storage->setNeedsCompacting( false );
265  storage->close("maildircompact");
266  if ( storage->isOpened() )
267  storage->updateIndex();
268  if ( !mSilent )
269  BroadcastStatus::instance()->setStatusMsg( str );
270 
271  mFolderOpen = false;
272  deleteLater(); // later, because of the "return mErrorCode"
273 }
274 
276 
278 {
279  if ( !folder() || !folder()->needsCompacting() )
280  return 0;
281  switch( folder()->storage()->folderType() ) {
282  case KMFolderTypeMbox:
283  return new MboxCompactionJob( folder(), isImmediate() );
284  case KMFolderTypeCachedImap:
285  case KMFolderTypeMaildir:
286  return new MaildirCompactionJob( folder(), isImmediate() );
287  default: // imap, search, unknown...
288  return 0;
289  }
290 }
291 
292 #include "compactionjob.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.
bool compactable() const
false if index file is out of sync with mbox file
TQString location() const
Returns full path to folder file.
Mail folder.
Definition: kmfolder.h:69
A job that runs in the background and compacts maildir folders.
Definition: compactionjob.h:74
MaildirCompactionJob(KMFolder *folder, bool immediate)
folder should be a folder with a KMFolderMaildir storage.
A job that runs in the background and compacts mbox folders.
Definition: compactionjob.h:40
MboxCompactionJob(KMFolder *folder, bool immediate)
folder should be a folder with a KMFolderMbox storage.
virtual ScheduledJob * run()
Run this task, i.e.
Base class for scheduled jobs.
Definition: jobscheduler.h:144
KMFolder * folder() const
The folder which this task is about, 0 if it was deleted meanwhile.
Definition: jobscheduler.h:79
folderdiaquotatab.h
Definition: aboutdata.cpp:40