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
53MboxCompactionJob::MboxCompactionJob( KMFolder* folder, bool immediate )
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 ...
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
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