kmail

compactionjob.cpp
1
28#include "compactionjob.h"
29#include "kmfolder.h"
30#include "broadcaststatus.h"
31using 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
46using 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
59MboxCompactionJob::~MboxCompactionJob()
60{
61}
62
63void 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
78TQString 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
91int 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
141void 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
155void 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
202MaildirCompactionJob::~MaildirCompactionJob()
203{
204}
205
206void 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
216int 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
239void 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
252void 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 ...
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.
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.
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.
KMFolder * folder() const
The folder which this task is about, 0 if it was deleted meanwhile.
folderdiaquotatab.h
Definition aboutdata.cpp:40