kmail Library API Documentation

compactionjob.cpp

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 // Look at this number of messages in each slotDoWork call
00049 #define COMPACTIONJOB_NRMESSAGES 100
00050 // And wait this number of milliseconds before calling it again
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   // We must close the folder if we opened it and got interrupted
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     // follow (and resolve) symlinks so that the final ::rename() always works
00085     // KURL gives us support for absolute and relative links transparently.
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       //      exit(1); backed out due to broken nfs
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; // Ignore open-notifications while opening the folder
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   // No need to worry about mSrcFolder==0 here. The FolderStorage deletes the jobs on destruction.
00141   KMFolderMbox* mbox = static_cast<KMFolderMbox *>( mSrcFolder->storage() );
00142   bool bDone = false;
00143   int nbMessages = mImmediate ? -1 /*all*/ : COMPACTIONJOB_NRMESSAGES;
00144   int rc = mbox->compact( mCurrentIndex, nbMessages,
00145                           mTmpFile, mOffset /*in-out*/, bDone /*out*/ );
00146   if ( !mImmediate )
00147     mCurrentIndex += COMPACTIONJOB_NRMESSAGES;
00148   if ( rc || bDone ) // error, or finished
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 );            // We are clean now
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(); // later, because of the "return mErrorCode"
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   // We must close the folder if we opened it and got interrupted
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; // Ignore open-notifications while opening the folder
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   // No need to worry about mSrcFolder==0 here. The FolderStorage deletes the jobs on destruction.
00238   KMFolderMaildir* storage = static_cast<KMFolderMaildir *>( mSrcFolder->storage() );
00239   bool bDone = false;
00240   int nbMessages = mImmediate ? -1 /*all*/ : COMPACTIONJOB_NRMESSAGES;
00241   int rc = storage->compact( mCurrentIndex, nbMessages, mEntryList, bDone /*out*/ );
00242   if ( !mImmediate )
00243     mCurrentIndex += COMPACTIONJOB_NRMESSAGES;
00244   if ( rc || bDone ) // error, or finished
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(); // later, because of the "return mErrorCode"
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: // imap, search, unknown...
00284     return 0;
00285   }
00286 }
00287 
00288 #include "compactionjob.moc"
KDE Logo
This file is part of the documentation for kmail Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 23 22:43:37 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003