diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 460c52653ab0dcca6f19a4f492ed2c5e4e963ab0 (patch) | |
tree | 67208f7c145782a7e90b123b982ca78d88cc2c87 /kmail/compactionjob.cpp | |
download | tdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.tar.gz tdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdepim@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kmail/compactionjob.cpp')
-rw-r--r-- | kmail/compactionjob.cpp | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/kmail/compactionjob.cpp b/kmail/compactionjob.cpp new file mode 100644 index 000000000..1b9c143b4 --- /dev/null +++ b/kmail/compactionjob.cpp @@ -0,0 +1,292 @@ +/** + * Copyright (c) 2004 David Faure <faure@kde.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of this program with any edition of + * the Qt library by Trolltech AS, Norway (or with modified versions + * of Qt that use the same license as Qt), and distribute linked + * combinations including the two. You must obey the GNU General + * Public License in all respects for all of the code used other than + * Qt. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from + * your version. + */ +#include "compactionjob.h" +#include "kmfolder.h" +#include "broadcaststatus.h" +using KPIM::BroadcastStatus; +#include "kmfoldermbox.h" +#include "kmfoldermaildir.h" + +#include <kdebug.h> +#include <klocale.h> + +#include <qfile.h> +#include <qfileinfo.h> +#include <qdir.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> + +using namespace KMail; + +// Look at this number of messages in each slotDoWork call +#define COMPACTIONJOB_NRMESSAGES 100 +// And wait this number of milliseconds before calling it again +#define COMPACTIONJOB_TIMERINTERVAL 100 + +MboxCompactionJob::MboxCompactionJob( KMFolder* folder, bool immediate ) + : ScheduledJob( folder, immediate ), mTimer( this, "mTimer" ), mTmpFile( 0 ), + mCurrentIndex( 0 ), mFolderOpen( false ), mSilent( false ) +{ +} + +MboxCompactionJob::~MboxCompactionJob() +{ +} + +void MboxCompactionJob::kill() +{ + Q_ASSERT( mCancellable ); + // We must close the folder if we opened it and got interrupted + if ( mFolderOpen && mSrcFolder && mSrcFolder->storage() ) + mSrcFolder->storage()->close("mboxcompact"); + + if ( mTmpFile ) + fclose( mTmpFile ); + mTmpFile = 0; + if ( !mTempName.isEmpty() ) + QFile::remove( mTempName ); + FolderJob::kill(); +} + +QString MboxCompactionJob::realLocation() const +{ + QString location = mSrcFolder->location(); + QFileInfo inf( location ); + if (inf.isSymLink()) { + KURL u; u.setPath( location ); + // follow (and resolve) symlinks so that the final ::rename() always works + // KURL gives us support for absolute and relative links transparently. + return KURL( u, inf.readLink() ).path(); + } + return location; +} + +int MboxCompactionJob::executeNow( bool silent ) +{ + mSilent = silent; + FolderStorage* storage = mSrcFolder->storage(); + KMFolderMbox* mbox = static_cast<KMFolderMbox *>( storage ); + if (!storage->compactable()) { + kdDebug(5006) << storage->location() << " compaction skipped." << endl; + if ( !mSilent ) { + QString str = i18n( "For safety reasons, compaction has been disabled for %1" ).arg( mbox->label() ); + BroadcastStatus::instance()->setStatusMsg( str ); + } + return 0; + } + kdDebug(5006) << "Compacting " << mSrcFolder->idString() << endl; + + if (KMFolderIndex::IndexOk != mbox->indexStatus()) { + kdDebug(5006) << "Critical error: " << storage->location() << + " has been modified by an external application while KMail was running." << endl; + // exit(1); backed out due to broken nfs + } + + const QFileInfo pathInfo( realLocation() ); + // Use /dir/.mailboxname.compacted so that it's hidden, and doesn't show up after restarting kmail + // (e.g. due to an unfortunate crash while compaction is happening) + mTempName = pathInfo.dirPath() + "/." + pathInfo.fileName() + ".compacted"; + + mode_t old_umask = umask(077); + mTmpFile = fopen(QFile::encodeName(mTempName), "w"); + umask(old_umask); + if (!mTmpFile) { + kdWarning(5006) << "Couldn't start compacting " << mSrcFolder->label() + << " : " << strerror( errno ) + << " while creating " << mTempName << endl; + return errno; + } + mOpeningFolder = true; // Ignore open-notifications while opening the folder + storage->open("mboxcompact"); + mOpeningFolder = false; + mFolderOpen = true; + mOffset = 0; + mCurrentIndex = 0; + + kdDebug(5006) << "MboxCompactionJob: starting to compact folder " << mSrcFolder->location() << " into " << mTempName << endl; + connect( &mTimer, SIGNAL( timeout() ), SLOT( slotDoWork() ) ); + if ( !mImmediate ) + mTimer.start( COMPACTIONJOB_TIMERINTERVAL ); + slotDoWork(); + return mErrorCode; +} + +void MboxCompactionJob::slotDoWork() +{ + // No need to worry about mSrcFolder==0 here. The FolderStorage deletes the jobs on destruction. + KMFolderMbox* mbox = static_cast<KMFolderMbox *>( mSrcFolder->storage() ); + bool bDone = false; + int nbMessages = mImmediate ? -1 /*all*/ : COMPACTIONJOB_NRMESSAGES; + int rc = mbox->compact( mCurrentIndex, nbMessages, + mTmpFile, mOffset /*in-out*/, bDone /*out*/ ); + if ( !mImmediate ) + mCurrentIndex += COMPACTIONJOB_NRMESSAGES; + if ( rc || bDone ) // error, or finished + done( rc ); +} + +void MboxCompactionJob::done( int rc ) +{ + mTimer.stop(); + mCancellable = false; + KMFolderMbox* mbox = static_cast<KMFolderMbox *>( mSrcFolder->storage() ); + if (!rc) + rc = fflush(mTmpFile); + if (!rc) + rc = fsync(fileno(mTmpFile)); + rc |= fclose(mTmpFile); + QString str; + if (!rc) { + bool autoCreate = mbox->autoCreateIndex(); + QString box( realLocation() ); + ::rename(QFile::encodeName(mTempName), QFile::encodeName(box)); + mbox->writeIndex(); + mbox->writeConfig(); + mbox->setAutoCreateIndex( false ); + mbox->close("mboxcompact", true); + mbox->setAutoCreateIndex( autoCreate ); + mbox->setNeedsCompacting( false ); // We are clean now + str = i18n( "Folder \"%1\" successfully compacted" ).arg( mSrcFolder->label() ); + kdDebug(5006) << str << endl; + } else { + mbox->close("mboxcompact"); + str = i18n( "Error occurred while compacting \"%1\". Compaction aborted." ).arg( mSrcFolder->label() ); + kdDebug(5006) << "Error occurred while compacting " << mbox->location() << endl; + kdDebug(5006) << "Compaction aborted." << endl; + QFile::remove( mTempName ); + } + mErrorCode = rc; + + if ( !mSilent ) + BroadcastStatus::instance()->setStatusMsg( str ); + + mFolderOpen = false; + deleteLater(); // later, because of the "return mErrorCode" +} + +//// + +MaildirCompactionJob::MaildirCompactionJob( KMFolder* folder, bool immediate ) + : ScheduledJob( folder, immediate ), mTimer( this, "mTimer" ), + mCurrentIndex( 0 ), mFolderOpen( false ), mSilent( false ) +{ +} + +MaildirCompactionJob::~MaildirCompactionJob() +{ +} + +void MaildirCompactionJob::kill() +{ + Q_ASSERT( mCancellable ); + // We must close the folder if we opened it and got interrupted + if ( mFolderOpen && mSrcFolder && mSrcFolder->storage() ) + mSrcFolder->storage()->close("maildircompact"); + + FolderJob::kill(); +} + +int MaildirCompactionJob::executeNow( bool silent ) +{ + mSilent = silent; + KMFolderMaildir* storage = static_cast<KMFolderMaildir *>( mSrcFolder->storage() ); + kdDebug(5006) << "Compacting " << mSrcFolder->idString() << endl; + + mOpeningFolder = true; // Ignore open-notifications while opening the folder + storage->open("maildircompact"); + mOpeningFolder = false; + mFolderOpen = true; + QString subdirNew(storage->location() + "/new/"); + QDir d(subdirNew); + mEntryList = d.entryList(); + mCurrentIndex = 0; + + kdDebug(5006) << "MaildirCompactionJob: starting to compact in folder " << mSrcFolder->location() << endl; + connect( &mTimer, SIGNAL( timeout() ), SLOT( slotDoWork() ) ); + if ( !mImmediate ) + mTimer.start( COMPACTIONJOB_TIMERINTERVAL ); + slotDoWork(); + return mErrorCode; +} + +void MaildirCompactionJob::slotDoWork() +{ + // No need to worry about mSrcFolder==0 here. The FolderStorage deletes the jobs on destruction. + KMFolderMaildir* storage = static_cast<KMFolderMaildir *>( mSrcFolder->storage() ); + bool bDone = false; + int nbMessages = mImmediate ? -1 /*all*/ : COMPACTIONJOB_NRMESSAGES; + int rc = storage->compact( mCurrentIndex, nbMessages, mEntryList, bDone /*out*/ ); + if ( !mImmediate ) + mCurrentIndex += COMPACTIONJOB_NRMESSAGES; + if ( rc || bDone ) // error, or finished + done( rc ); +} + +void MaildirCompactionJob::done( int rc ) +{ + KMFolderMaildir* storage = static_cast<KMFolderMaildir *>( mSrcFolder->storage() ); + mTimer.stop(); + mCancellable = false; + QString str; + if ( !rc ) { + str = i18n( "Folder \"%1\" successfully compacted" ).arg( mSrcFolder->label() ); + } else { + str = i18n( "Error occurred while compacting \"%1\". Compaction aborted." ).arg( mSrcFolder->label() ); + } + mErrorCode = rc; + storage->setNeedsCompacting( false ); + storage->close("maildircompact"); + if ( storage->isOpened() ) + storage->updateIndex(); + if ( !mSilent ) + BroadcastStatus::instance()->setStatusMsg( str ); + + mFolderOpen = false; + deleteLater(); // later, because of the "return mErrorCode" +} + +//// + +ScheduledJob* ScheduledCompactionTask::run() +{ + if ( !folder() || !folder()->needsCompacting() ) + return 0; + switch( folder()->storage()->folderType() ) { + case KMFolderTypeMbox: + return new MboxCompactionJob( folder(), isImmediate() ); + case KMFolderTypeCachedImap: + case KMFolderTypeMaildir: + return new MaildirCompactionJob( folder(), isImmediate() ); + default: // imap, search, unknown... + return 0; + } +} + +#include "compactionjob.moc" |