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.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 27 12:52:02 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003