kmail
compactionjob.cppGo to the documentation of this file.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, "mTimer" ), 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("mboxcompact");
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 const QFileInfo pathInfo( realLocation() );
00113
00114
00115 mTempName = pathInfo.dirPath() + "/." + pathInfo.fileName() + ".compacted";
00116
00117 mode_t old_umask = umask(077);
00118 mTmpFile = fopen(QFile::encodeName(mTempName), "w");
00119 umask(old_umask);
00120 if (!mTmpFile) {
00121 kdWarning(5006) << "Couldn't start compacting " << mSrcFolder->label()
00122 << " : " << strerror( errno )
00123 << " while creating " << mTempName << endl;
00124 return errno;
00125 }
00126 mOpeningFolder = true;
00127 storage->open("mboxcompact");
00128 mOpeningFolder = false;
00129 mFolderOpen = true;
00130 mOffset = 0;
00131 mCurrentIndex = 0;
00132
00133 kdDebug(5006) << "MboxCompactionJob: starting to compact folder " << mSrcFolder->location() << " into " << mTempName << endl;
00134 connect( &mTimer, SIGNAL( timeout() ), SLOT( slotDoWork() ) );
00135 if ( !mImmediate )
00136 mTimer.start( COMPACTIONJOB_TIMERINTERVAL );
00137 slotDoWork();
00138 return mErrorCode;
00139 }
00140
00141 void MboxCompactionJob::slotDoWork()
00142 {
00143
00144 KMFolderMbox* mbox = static_cast<KMFolderMbox *>( mSrcFolder->storage() );
00145 bool bDone = false;
00146 int nbMessages = mImmediate ? -1 : COMPACTIONJOB_NRMESSAGES;
00147 int rc = mbox->compact( mCurrentIndex, nbMessages,
00148 mTmpFile, mOffset , bDone );
00149 if ( !mImmediate )
00150 mCurrentIndex += COMPACTIONJOB_NRMESSAGES;
00151 if ( rc || bDone )
00152 done( rc );
00153 }
00154
00155 void MboxCompactionJob::done( int rc )
00156 {
00157 mTimer.stop();
00158 mCancellable = false;
00159 KMFolderMbox* mbox = static_cast<KMFolderMbox *>( mSrcFolder->storage() );
00160 if (!rc)
00161 rc = fflush(mTmpFile);
00162 if (!rc)
00163 rc = fsync(fileno(mTmpFile));
00164 rc |= fclose(mTmpFile);
00165 QString str;
00166 if (!rc) {
00167 bool autoCreate = mbox->autoCreateIndex();
00168 QString box( realLocation() );
00169 ::rename(QFile::encodeName(mTempName), QFile::encodeName(box));
00170 mbox->writeIndex();
00171 mbox->writeConfig();
00172 mbox->setAutoCreateIndex( false );
00173 mbox->close("mboxcompact", true);
00174 mbox->setAutoCreateIndex( autoCreate );
00175 mbox->setNeedsCompacting( false );
00176 str = i18n( "Folder \"%1\" successfully compacted" ).arg( mSrcFolder->label() );
00177 kdDebug(5006) << str << endl;
00178 } else {
00179 mbox->close("mboxcompact");
00180 str = i18n( "Error occurred while compacting \"%1\". Compaction aborted." ).arg( mSrcFolder->label() );
00181 kdDebug(5006) << "Error occurred while compacting " << mbox->location() << endl;
00182 kdDebug(5006) << "Compaction aborted." << endl;
00183 QFile::remove( mTempName );
00184 }
00185 mErrorCode = rc;
00186
00187 if ( !mSilent )
00188 BroadcastStatus::instance()->setStatusMsg( str );
00189
00190 mFolderOpen = false;
00191 deleteLater();
00192 }
00193
00195
00196 MaildirCompactionJob::MaildirCompactionJob( KMFolder* folder, bool immediate )
00197 : ScheduledJob( folder, immediate ), mTimer( this, "mTimer" ),
00198 mCurrentIndex( 0 ), mFolderOpen( false ), mSilent( false )
00199 {
00200 }
00201
00202 MaildirCompactionJob::~MaildirCompactionJob()
00203 {
00204 }
00205
00206 void MaildirCompactionJob::kill()
00207 {
00208 Q_ASSERT( mCancellable );
00209
00210 if ( mFolderOpen && mSrcFolder && mSrcFolder->storage() )
00211 mSrcFolder->storage()->close("maildircompact");
00212
00213 FolderJob::kill();
00214 }
00215
00216 int MaildirCompactionJob::executeNow( bool silent )
00217 {
00218 mSilent = silent;
00219 KMFolderMaildir* storage = static_cast<KMFolderMaildir *>( mSrcFolder->storage() );
00220 kdDebug(5006) << "Compacting " << mSrcFolder->idString() << endl;
00221
00222 mOpeningFolder = true;
00223 storage->open("maildircompact");
00224 mOpeningFolder = false;
00225 mFolderOpen = true;
00226 QString subdirNew(storage->location() + "/new/");
00227 QDir d(subdirNew);
00228 mEntryList = d.entryList();
00229 mCurrentIndex = 0;
00230
00231 kdDebug(5006) << "MaildirCompactionJob: starting to compact in folder " << mSrcFolder->location() << endl;
00232 connect( &mTimer, SIGNAL( timeout() ), SLOT( slotDoWork() ) );
00233 if ( !mImmediate )
00234 mTimer.start( COMPACTIONJOB_TIMERINTERVAL );
00235 slotDoWork();
00236 return mErrorCode;
00237 }
00238
00239 void MaildirCompactionJob::slotDoWork()
00240 {
00241
00242 KMFolderMaildir* storage = static_cast<KMFolderMaildir *>( mSrcFolder->storage() );
00243 bool bDone = false;
00244 int nbMessages = mImmediate ? -1 : COMPACTIONJOB_NRMESSAGES;
00245 int rc = storage->compact( mCurrentIndex, nbMessages, mEntryList, bDone );
00246 if ( !mImmediate )
00247 mCurrentIndex += COMPACTIONJOB_NRMESSAGES;
00248 if ( rc || bDone )
00249 done( rc );
00250 }
00251
00252 void MaildirCompactionJob::done( int rc )
00253 {
00254 KMFolderMaildir* storage = static_cast<KMFolderMaildir *>( mSrcFolder->storage() );
00255 mTimer.stop();
00256 mCancellable = false;
00257 QString str;
00258 if ( !rc ) {
00259 str = i18n( "Folder \"%1\" successfully compacted" ).arg( mSrcFolder->label() );
00260 } else {
00261 str = i18n( "Error occurred while compacting \"%1\". Compaction aborted." ).arg( mSrcFolder->label() );
00262 }
00263 mErrorCode = rc;
00264 storage->setNeedsCompacting( false );
00265 storage->close("maildircompact");
00266 if ( storage->isOpened() )
00267 storage->updateIndex();
00268 if ( !mSilent )
00269 BroadcastStatus::instance()->setStatusMsg( str );
00270
00271 mFolderOpen = false;
00272 deleteLater();
00273 }
00274
00276
00277 ScheduledJob* ScheduledCompactionTask::run()
00278 {
00279 if ( !folder() || !folder()->needsCompacting() )
00280 return 0;
00281 switch( folder()->storage()->folderType() ) {
00282 case KMFolderTypeMbox:
00283 return new MboxCompactionJob( folder(), isImmediate() );
00284 case KMFolderTypeCachedImap:
00285 case KMFolderTypeMaildir:
00286 return new MaildirCompactionJob( folder(), isImmediate() );
00287 default:
00288 return 0;
00289 }
00290 }
00291
00292 #include "compactionjob.moc"
|