00001
00028
#include "compactionjob.h"
00029
#include "kmfolder.h"
00030
#include "broadcaststatus.h"
00031
using KPIM::BroadcastStatus;
00032
#include "kmfoldermbox.h"
00033
#include "kmfoldermaildir.h"
00034
00035
#include <kdebug.h>
00036
#include <klocale.h>
00037
00038
#include <qfile.h>
00039
#include <qfileinfo.h>
00040
#include <qdir.h>
00041
00042
#include <sys/types.h>
00043
#include <sys/stat.h>
00044
#include <errno.h>
00045
00046
using namespace KMail;
00047
00048
00049
#define COMPACTIONJOB_NRMESSAGES 100
00050
00051
#define COMPACTIONJOB_TIMERINTERVAL 100
00052
00053 MboxCompactionJob::MboxCompactionJob(
KMFolder* folder,
bool immediate )
00054 :
ScheduledJob( folder, immediate ), mTimer( this ), mTmpFile( 0 ),
00055 mCurrentIndex( 0 ), mFolderOpen( false ), mSilent( false )
00056 {
00057 }
00058
00059 MboxCompactionJob::~MboxCompactionJob()
00060 {
00061 }
00062
00063
void MboxCompactionJob::kill()
00064 {
00065 Q_ASSERT( mCancellable );
00066
00067
if ( mFolderOpen && mSrcFolder && mSrcFolder->storage() )
00068 mSrcFolder->storage()->close();
00069
00070
if ( mTmpFile )
00071 fclose( mTmpFile );
00072 mTmpFile = 0;
00073
if ( !mTempName.isEmpty() )
00074 QFile::remove( mTempName );
00075 FolderJob::kill();
00076 }
00077
00078
QString MboxCompactionJob::realLocation()
const
00079
{
00080
QString location = mSrcFolder->location();
00081
QFileInfo inf( location );
00082
if (inf.isSymLink()) {
00083 KURL u; u.setPath( location );
00084
00085
00086
return KURL( u, inf.readLink() ).path();
00087 }
00088
return location;
00089 }
00090
00091
int MboxCompactionJob::executeNow(
bool silent )
00092 {
00093 mSilent = silent;
00094
FolderStorage* storage = mSrcFolder->storage();
00095 KMFolderMbox* mbox = static_cast<KMFolderMbox *>( storage );
00096
if (!storage->
compactable()) {
00097 kdDebug(5006) << storage->
location() <<
" compaction skipped." << endl;
00098
if ( !mSilent ) {
00099
QString str = i18n(
"For safety reasons, compaction has been disabled for %1" ).arg( mbox->label() );
00100 BroadcastStatus::instance()->setStatusMsg( str );
00101 }
00102
return 0;
00103 }
00104 kdDebug(5006) <<
"Compacting " << mSrcFolder->idString() << endl;
00105
00106
if (KMFolderIndex::IndexOk != mbox->indexStatus()) {
00107 kdDebug(5006) <<
"Critical error: " << storage->
location() <<
00108
" has been modified by an external application while KMail was running." << endl;
00109
00110 }
00111
00112 mTempName = realLocation() +
".compacted";
00113
00114 mode_t old_umask = umask(077);
00115 mTmpFile = fopen(QFile::encodeName(mTempName),
"w");
00116 umask(old_umask);
00117
if (!mTmpFile) {
00118 kdWarning(5006) <<
"Couldn't start compacting " << mSrcFolder->label()
00119 <<
" : " << strerror( errno )
00120 <<
" while creating " << mTempName << endl;
00121
return errno;
00122 }
00123 mOpeningFolder =
true;
00124 storage->
open();
00125 mOpeningFolder =
false;
00126 mFolderOpen =
true;
00127 mOffset = 0;
00128 mCurrentIndex = 0;
00129
00130 kdDebug(5006) <<
"MboxCompactionJob: starting to compact in folder " << mSrcFolder->location() << endl;
00131 connect( &mTimer, SIGNAL( timeout() ), SLOT( slotDoWork() ) );
00132
if ( !mImmediate )
00133 mTimer.start( COMPACTIONJOB_TIMERINTERVAL );
00134 slotDoWork();
00135
return mErrorCode;
00136 }
00137
00138
void MboxCompactionJob::slotDoWork()
00139 {
00140
00141 KMFolderMbox* mbox = static_cast<KMFolderMbox *>( mSrcFolder->storage() );
00142
bool bDone =
false;
00143
int nbMessages = mImmediate ? -1 : COMPACTIONJOB_NRMESSAGES;
00144
int rc = mbox->compact( mCurrentIndex, nbMessages,
00145 mTmpFile, mOffset , bDone );
00146
if ( !mImmediate )
00147 mCurrentIndex += COMPACTIONJOB_NRMESSAGES;
00148
if ( rc || bDone )
00149 done( rc );
00150 }
00151
00152
void MboxCompactionJob::done(
int rc )
00153 {
00154 mTimer.stop();
00155 mCancellable =
false;
00156 KMFolderMbox* mbox = static_cast<KMFolderMbox *>( mSrcFolder->storage() );
00157
if (!rc)
00158 rc = fflush(mTmpFile);
00159
if (!rc)
00160 rc = fsync(fileno(mTmpFile));
00161 rc |= fclose(mTmpFile);
00162
QString str;
00163
if (!rc) {
00164
bool autoCreate = mbox->autoCreateIndex();
00165
QString box( realLocation() );
00166 ::rename(QFile::encodeName(mTempName), QFile::encodeName(box));
00167 mbox->writeIndex();
00168 mbox->writeConfig();
00169 mbox->setAutoCreateIndex(
false );
00170 mbox->close(
true);
00171 mbox->setAutoCreateIndex( autoCreate );
00172 mbox->setNeedsCompacting(
false );
00173 str = i18n(
"Folder \"%1\" successfully compacted" ).arg( mSrcFolder->label() );
00174 kdDebug(5006) << str << endl;
00175 }
else {
00176 mbox->close();
00177 str = i18n(
"Error occurred while compacting \"%1\". Compaction aborted." ).arg( mSrcFolder->label() );
00178 kdDebug(5006) <<
"Error occurred while compacting " << mbox->location() << endl;
00179 kdDebug(5006) <<
"Compaction aborted." << endl;
00180 }
00181 mErrorCode = rc;
00182
00183
if ( !mSilent )
00184 BroadcastStatus::instance()->setStatusMsg( str );
00185
00186 mFolderOpen =
false;
00187 deleteLater();
00188 }
00189
00191
00192 MaildirCompactionJob::MaildirCompactionJob(
KMFolder* folder,
bool immediate )
00193 :
ScheduledJob( folder, immediate ), mTimer( this ),
00194 mCurrentIndex( 0 ), mFolderOpen( false ), mSilent( false )
00195 {
00196 }
00197
00198 MaildirCompactionJob::~MaildirCompactionJob()
00199 {
00200 }
00201
00202
void MaildirCompactionJob::kill()
00203 {
00204 Q_ASSERT( mCancellable );
00205
00206
if ( mFolderOpen && mSrcFolder && mSrcFolder->storage() )
00207 mSrcFolder->storage()->close();
00208
00209 FolderJob::kill();
00210 }
00211
00212
int MaildirCompactionJob::executeNow(
bool silent )
00213 {
00214 mSilent = silent;
00215 KMFolderMaildir* storage = static_cast<KMFolderMaildir *>( mSrcFolder->storage() );
00216 kdDebug(5006) <<
"Compacting " << mSrcFolder->idString() << endl;
00217
00218 mOpeningFolder =
true;
00219 storage->open();
00220 mOpeningFolder =
false;
00221 mFolderOpen =
true;
00222
QString subdirNew(storage->location() +
"/new/");
00223
QDir d(subdirNew);
00224 mEntryList = d.entryList();
00225 mCurrentIndex = 0;
00226
00227 kdDebug(5006) <<
"MaildirCompactionJob: starting to compact in folder " << mSrcFolder->location() << endl;
00228 connect( &mTimer, SIGNAL( timeout() ), SLOT( slotDoWork() ) );
00229
if ( !mImmediate )
00230 mTimer.start( COMPACTIONJOB_TIMERINTERVAL );
00231 slotDoWork();
00232
return mErrorCode;
00233 }
00234
00235
void MaildirCompactionJob::slotDoWork()
00236 {
00237
00238 KMFolderMaildir* storage = static_cast<KMFolderMaildir *>( mSrcFolder->storage() );
00239
bool bDone =
false;
00240
int nbMessages = mImmediate ? -1 : COMPACTIONJOB_NRMESSAGES;
00241
int rc = storage->compact( mCurrentIndex, nbMessages, mEntryList, bDone );
00242
if ( !mImmediate )
00243 mCurrentIndex += COMPACTIONJOB_NRMESSAGES;
00244
if ( rc || bDone )
00245 done( rc );
00246 }
00247
00248
void MaildirCompactionJob::done(
int rc )
00249 {
00250 KMFolderMaildir* storage = static_cast<KMFolderMaildir *>( mSrcFolder->storage() );
00251 mTimer.stop();
00252 mCancellable =
false;
00253
QString str;
00254
if ( !rc ) {
00255 str = i18n(
"Folder \"%1\" successfully compacted" ).arg( mSrcFolder->label() );
00256 }
else {
00257 str = i18n(
"Error occurred while compacting \"%1\". Compaction aborted." ).arg( mSrcFolder->label() );
00258 }
00259 mErrorCode = rc;
00260 storage->setNeedsCompacting(
false );
00261 storage->close();
00262
if ( storage->isOpened() )
00263 storage->updateIndex();
00264
if ( !mSilent )
00265 BroadcastStatus::instance()->setStatusMsg( str );
00266
00267 mFolderOpen =
false;
00268 deleteLater();
00269 }
00270
00272
00273 ScheduledJob*
ScheduledCompactionTask::run()
00274 {
00275
if ( !
folder() || !
folder()->
needsCompacting() )
00276
return 0;
00277
switch(
folder()->
storage()->
folderType() ) {
00278
case KMFolderTypeMbox:
00279
return new MboxCompactionJob(
folder(), isImmediate() );
00280
case KMFolderTypeCachedImap:
00281
case KMFolderTypeMaildir:
00282
return new MaildirCompactionJob(
folder(), isImmediate() );
00283
default:
00284
return 0;
00285 }
00286 }
00287
00288
#include "compactionjob.moc"