mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-23 10:22:50 +00:00
694 lines
19 KiB
C++
694 lines
19 KiB
C++
/*
|
|
Copyright (c) 1996-1998 Stefan Taferner <taferner@kde.org>
|
|
Copyright (c) 2009 Bertjan Broeksema <broeksema@kde.org>
|
|
|
|
This library is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU Library General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or (at your
|
|
option) any later version.
|
|
|
|
This library 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 Library General Public
|
|
License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to the
|
|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
02110-1301, USA.
|
|
|
|
NOTE: Most of the code inside here is an slightly adjusted version of
|
|
kdepim/kmail/kmfoldermbox.cpp. This is why I added a line for Stefan Taferner.
|
|
|
|
Bertjan Broeksema, april 2009
|
|
*/
|
|
|
|
#include "mbox.h"
|
|
#include "mbox_p.h"
|
|
#include "mboxentry_p.h"
|
|
|
|
#include <KDebug>
|
|
#include <KStandardDirs>
|
|
#include <KUrl>
|
|
|
|
#include <QtCore/QBuffer>
|
|
#include <QtCore/QProcess>
|
|
|
|
using namespace KMBox;
|
|
|
|
/// public methods.
|
|
|
|
MBox::MBox()
|
|
: d( new MBoxPrivate( this ) )
|
|
{
|
|
// Set some sane defaults
|
|
d->mFileLocked = false;
|
|
d->mLockType = None;
|
|
|
|
d->mUnlockTimer.setInterval( 0 );
|
|
d->mUnlockTimer.setSingleShot( true );
|
|
}
|
|
|
|
MBox::~MBox()
|
|
{
|
|
if ( d->mFileLocked ) {
|
|
unlock();
|
|
}
|
|
|
|
d->close();
|
|
|
|
delete d;
|
|
}
|
|
|
|
// Appended entries works as follows: When an mbox file is loaded from disk,
|
|
// d->mInitialMboxFileSize is set to the file size at that moment. New entries
|
|
// are stored in memory (d->mAppendedEntries). The initial file size and the size
|
|
// of the buffer determine the offset for the next message to append.
|
|
MBoxEntry MBox::appendMessage( const KMime::Message::Ptr &entry )
|
|
{
|
|
// It doesn't make sense to add entries when we don't have an reference file.
|
|
Q_ASSERT( !d->mMboxFile.fileName().isEmpty() );
|
|
|
|
const QByteArray rawEntry = MBoxPrivate::escapeFrom( entry->encodedContent() );
|
|
|
|
if ( rawEntry.size() <= 0 ) {
|
|
kDebug() << "Message added to folder `" << d->mMboxFile.fileName()
|
|
<< "' contains no data. Ignoring it.";
|
|
return MBoxEntry();
|
|
}
|
|
|
|
int nextOffset = d->mAppendedEntries.size(); // Offset of the appended message
|
|
|
|
// Make sure the byte array is large enough to check for an end character.
|
|
// Then check if the required newlines are there.
|
|
if ( nextOffset < 1 && d->mMboxFile.size() > 0 ) { // Empty, add one empty line
|
|
d->mAppendedEntries.append( "\n" );
|
|
++nextOffset;
|
|
} else if ( nextOffset == 1 && d->mAppendedEntries.at( 0 ) != '\n' ) {
|
|
// This should actually not happen, but catch it anyway.
|
|
if ( d->mMboxFile.size() < 0 ) {
|
|
d->mAppendedEntries.append( "\n" );
|
|
++nextOffset;
|
|
}
|
|
} else if ( nextOffset >= 2 ) {
|
|
if ( d->mAppendedEntries.at( nextOffset - 1 ) != '\n' ) {
|
|
if ( d->mAppendedEntries.at( nextOffset ) != '\n' ) {
|
|
d->mAppendedEntries.append( "\n\n" );
|
|
nextOffset += 2;
|
|
} else {
|
|
d->mAppendedEntries.append( "\n" );
|
|
++nextOffset;
|
|
}
|
|
}
|
|
}
|
|
|
|
const QByteArray separator = MBoxPrivate::mboxMessageSeparator( rawEntry );
|
|
d->mAppendedEntries.append( separator );
|
|
d->mAppendedEntries.append( rawEntry );
|
|
if ( rawEntry[rawEntry.size() - 1] != '\n' ) {
|
|
d->mAppendedEntries.append( "\n\n" );
|
|
} else {
|
|
d->mAppendedEntries.append( "\n" );
|
|
}
|
|
|
|
MBoxEntry resultEntry;
|
|
resultEntry.d->mOffset = d->mInitialMboxFileSize + nextOffset;
|
|
resultEntry.d->mMessageSize = rawEntry.size();
|
|
resultEntry.d->mSeparatorSize = separator.size();
|
|
d->mEntries << resultEntry;
|
|
|
|
return resultEntry;
|
|
}
|
|
|
|
MBoxEntry::List MBox::entries( const MBoxEntry::List &deletedEntries ) const
|
|
{
|
|
if ( deletedEntries.isEmpty() ) {
|
|
// fast path
|
|
return d->mEntries;
|
|
}
|
|
|
|
MBoxEntry::List result;
|
|
|
|
foreach ( const MBoxEntry &entry, d->mEntries ) {
|
|
if ( !deletedEntries.contains( entry ) ) {
|
|
result << entry;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
QString MBox::fileName() const
|
|
{
|
|
return d->mMboxFile.fileName();
|
|
}
|
|
|
|
bool MBox::load( const QString &fileName )
|
|
{
|
|
if ( d->mFileLocked ) {
|
|
return false;
|
|
}
|
|
|
|
d->initLoad( fileName );
|
|
|
|
if ( !lock() ) {
|
|
kDebug() << "Failed to lock";
|
|
return false;
|
|
}
|
|
|
|
d->mInitialMboxFileSize = d->mMboxFile.size(); // AFTER the file has been locked
|
|
|
|
QByteArray line;
|
|
QByteArray prevSeparator;
|
|
quint64 offs = 0; // The offset of the next message to read.
|
|
|
|
while ( !d->mMboxFile.atEnd() ) {
|
|
quint64 pos = d->mMboxFile.pos();
|
|
|
|
line = d->mMboxFile.readLine();
|
|
|
|
// if atEnd, use mail only if there was a separator line at all,
|
|
// otherwise it's not a valid mbox
|
|
if ( d->isMBoxSeparator( line ) ||
|
|
( d->mMboxFile.atEnd() && ( prevSeparator.size() != 0 ) ) ) {
|
|
|
|
// if we are the at the file end, update pos to not forget the last line
|
|
if ( d->mMboxFile.atEnd() ) {
|
|
pos = d->mMboxFile.pos();
|
|
}
|
|
|
|
// Found the separator or at end of file, the message starts at offs
|
|
quint64 msgSize = pos - offs;
|
|
|
|
if ( pos > 0 ) {
|
|
// This is not the separator of the first mail in the file. If pos == 0
|
|
// than we matched the separator of the first mail in the file.
|
|
MBoxEntry entry;
|
|
entry.d->mOffset = offs;
|
|
entry.d->mSeparatorSize = prevSeparator.size();
|
|
entry.d->mMessageSize = msgSize - 1;
|
|
|
|
// Don't add the separator size and the newline up to the message size.
|
|
entry.d->mMessageSize -= prevSeparator.size() + 1;
|
|
|
|
d->mEntries << entry;
|
|
}
|
|
|
|
if ( d->isMBoxSeparator( line ) ) {
|
|
prevSeparator = line;
|
|
}
|
|
|
|
offs += msgSize; // Mark the beginning of the next message.
|
|
}
|
|
}
|
|
|
|
// FIXME: What if unlock fails?
|
|
// if no separator was found, the file is still valid if it is empty
|
|
return unlock() && ( ( prevSeparator.size() != 0 ) || ( d->mMboxFile.size() == 0 ) );
|
|
}
|
|
|
|
bool MBox::lock()
|
|
{
|
|
if ( d->mMboxFile.fileName().isEmpty() ) {
|
|
return false; // We cannot lock if there is no file loaded.
|
|
}
|
|
|
|
// We can't load another file when the mbox currently is locked so if d->mFileLocked
|
|
// is true atm just return true.
|
|
if ( locked() ) {
|
|
return true;
|
|
}
|
|
|
|
if ( d->mLockType == None ) {
|
|
d->mFileLocked = true;
|
|
if ( d->open() ) {
|
|
d->startTimerIfNeeded();
|
|
return true;
|
|
}
|
|
|
|
d->mFileLocked = false;
|
|
return false;
|
|
}
|
|
|
|
QStringList args;
|
|
int rc = 0;
|
|
|
|
switch ( d->mLockType ) {
|
|
case ProcmailLockfile:
|
|
args << QLatin1String( "-l20" ) << QLatin1String( "-r5" );
|
|
if ( !d->mLockFileName.isEmpty() ) {
|
|
args << QString::fromLocal8Bit( QFile::encodeName( d->mLockFileName ) );
|
|
} else {
|
|
args << QString::fromLocal8Bit( QFile::encodeName( d->mMboxFile.fileName() +
|
|
QLatin1String( ".lock" ) ) );
|
|
}
|
|
|
|
rc = QProcess::execute( QLatin1String( "lockfile" ), args );
|
|
if ( rc != 0 ) {
|
|
kDebug() << "lockfile -l20 -r5 " << d->mMboxFile.fileName()
|
|
<< ": Failed (" << rc << ") switching to read only mode";
|
|
d->mReadOnly = true; // In case the MBox object was created read/write we
|
|
// set it to read only when locking failed.
|
|
} else {
|
|
d->mFileLocked = true;
|
|
}
|
|
break;
|
|
|
|
case MuttDotlock:
|
|
args << QString::fromLocal8Bit( QFile::encodeName( d->mMboxFile.fileName() ) );
|
|
rc = QProcess::execute( QLatin1String( "mutt_dotlock" ), args );
|
|
|
|
if ( rc != 0 ) {
|
|
kDebug() << "mutt_dotlock " << d->mMboxFile.fileName()
|
|
<< ": Failed (" << rc << ") switching to read only mode";
|
|
d->mReadOnly = true; // In case the MBox object was created read/write we
|
|
// set it to read only when locking failed.
|
|
} else {
|
|
d->mFileLocked = true;
|
|
}
|
|
break;
|
|
|
|
case MuttDotlockPrivileged:
|
|
args << QLatin1String( "-p" )
|
|
<< QString::fromLocal8Bit( QFile::encodeName( d->mMboxFile.fileName() ) );
|
|
rc = QProcess::execute( QLatin1String( "mutt_dotlock" ), args );
|
|
|
|
if ( rc != 0 ) {
|
|
kDebug() << "mutt_dotlock -p " << d->mMboxFile.fileName() << ":"
|
|
<< ": Failed (" << rc << ") switching to read only mode";
|
|
d->mReadOnly = true;
|
|
} else {
|
|
d->mFileLocked = true;
|
|
}
|
|
break;
|
|
|
|
case None:
|
|
d->mFileLocked = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if ( d->mFileLocked ) {
|
|
if ( !d->open() ) {
|
|
const bool unlocked = unlock();
|
|
Q_ASSERT( unlocked ); // If this fails we're in trouble.
|
|
Q_UNUSED( unlocked );
|
|
}
|
|
}
|
|
|
|
d->startTimerIfNeeded();
|
|
return d->mFileLocked;
|
|
}
|
|
|
|
bool MBox::locked() const
|
|
{
|
|
return d->mFileLocked;
|
|
}
|
|
|
|
static bool lessThanByOffset( const MBoxEntry &left, const MBoxEntry &right )
|
|
{
|
|
return left.messageOffset() < right.messageOffset();
|
|
}
|
|
|
|
bool MBox::purge( const MBoxEntry::List &deletedEntries, QList<MBoxEntry::Pair> *movedEntries )
|
|
{
|
|
if ( d->mMboxFile.fileName().isEmpty() ) {
|
|
return false; // No file loaded yet.
|
|
}
|
|
|
|
if ( deletedEntries.isEmpty() ) {
|
|
return true; // Nothing to do.
|
|
}
|
|
|
|
if ( !lock() ) {
|
|
return false;
|
|
}
|
|
|
|
foreach ( const MBoxEntry &entry, deletedEntries ) {
|
|
d->mMboxFile.seek( entry.messageOffset() );
|
|
const QByteArray line = d->mMboxFile.readLine();
|
|
|
|
if ( !d->isMBoxSeparator( line ) ) {
|
|
qDebug() << "Found invalid separator at:" << entry.messageOffset();
|
|
unlock();
|
|
return false; // The file is messed up or the index is incorrect.
|
|
}
|
|
}
|
|
|
|
// All entries are deleted, so just resize the file to a size of 0.
|
|
if ( deletedEntries.size() == d->mEntries.size() ) {
|
|
d->mEntries.clear();
|
|
d->mMboxFile.resize( 0 );
|
|
kDebug() << "Purge comleted successfully, unlocking the file.";
|
|
return unlock();
|
|
}
|
|
|
|
qSort( d->mEntries.begin(), d->mEntries.end(), lessThanByOffset );
|
|
quint64 writeOffset = 0;
|
|
bool writeOffSetInitialized = false;
|
|
MBoxEntry::List resultingEntryList;
|
|
QList<MBoxEntry::Pair> tmpMovedEntries;
|
|
|
|
quint64 origFileSize = d->mMboxFile.size();
|
|
|
|
QListIterator<MBoxEntry> i( d->mEntries );
|
|
while ( i.hasNext() ) {
|
|
MBoxEntry entry = i.next();
|
|
|
|
if ( deletedEntries.contains( entry ) && !writeOffSetInitialized ) {
|
|
writeOffset = entry.messageOffset();
|
|
writeOffSetInitialized = true;
|
|
} else if ( writeOffSetInitialized &&
|
|
writeOffset < entry.messageOffset() &&
|
|
!deletedEntries.contains( entry ) ) {
|
|
// The current message doesn't have to be deleted, but must be moved.
|
|
// First determine the size of the entry that must be moved.
|
|
quint64 entrySize = 0;
|
|
if ( i.hasNext() ) {
|
|
entrySize = i.next().messageOffset() - entry.messageOffset();
|
|
i.previous(); // Go back to make sure that we also handle the next entry.
|
|
} else {
|
|
entrySize = origFileSize - entry.messageOffset();
|
|
}
|
|
|
|
Q_ASSERT( entrySize > 0 ); // MBox entries really cannot have a size <= 0;
|
|
|
|
// we map the whole area of the file starting at the writeOffset up to the
|
|
// message that have to be moved into memory. This includes eventually the
|
|
// messages that are the deleted between the first deleted message
|
|
// encountered and the message that has to be moved.
|
|
quint64 mapSize = entry.messageOffset() + entrySize - writeOffset;
|
|
|
|
// Now map writeOffSet + mapSize into mem.
|
|
uchar *memArea = d->mMboxFile.map( writeOffset, mapSize );
|
|
|
|
// Now read the entry that must be moved to writeOffset.
|
|
quint64 startOffset = entry.messageOffset() - writeOffset;
|
|
memmove( memArea, memArea + startOffset, entrySize );
|
|
|
|
d->mMboxFile.unmap( memArea );
|
|
|
|
MBoxEntry resultEntry;
|
|
resultEntry.d->mOffset = writeOffset;
|
|
resultEntry.d->mSeparatorSize = entry.separatorSize();
|
|
resultEntry.d->mMessageSize = entry.messageSize();
|
|
|
|
resultingEntryList << resultEntry;
|
|
tmpMovedEntries << MBoxEntry::Pair( MBoxEntry( entry.messageOffset() ),
|
|
MBoxEntry( resultEntry.messageOffset() ) );
|
|
writeOffset += entrySize;
|
|
} else if ( !deletedEntries.contains( entry ) ) {
|
|
// Unmoved and not deleted entry, can only ocure before the first deleted
|
|
// entry.
|
|
Q_ASSERT( !writeOffSetInitialized );
|
|
resultingEntryList << entry;
|
|
}
|
|
}
|
|
|
|
// Chop off remaining entry bits.
|
|
d->mMboxFile.resize( writeOffset );
|
|
d->mEntries = resultingEntryList;
|
|
|
|
kDebug() << "Purge comleted successfully, unlocking the file.";
|
|
if ( movedEntries ) {
|
|
*movedEntries = tmpMovedEntries;
|
|
}
|
|
return unlock(); // FIXME: What if this fails? It will return false but the
|
|
// file has changed.
|
|
}
|
|
|
|
QByteArray MBox::readRawMessage( const MBoxEntry &entry )
|
|
{
|
|
const bool wasLocked = locked();
|
|
if ( !wasLocked ) {
|
|
if ( !lock() ) {
|
|
return QByteArray();
|
|
}
|
|
}
|
|
|
|
// TODO: Add error handling in case locking failed.
|
|
|
|
quint64 offset = entry.messageOffset();
|
|
|
|
Q_ASSERT( d->mFileLocked );
|
|
Q_ASSERT( d->mMboxFile.isOpen() );
|
|
Q_ASSERT( ( d->mInitialMboxFileSize + d->mAppendedEntries.size() ) > offset );
|
|
|
|
QByteArray message;
|
|
|
|
if ( offset < d->mInitialMboxFileSize ) {
|
|
d->mMboxFile.seek( offset );
|
|
|
|
QByteArray line = d->mMboxFile.readLine();
|
|
|
|
if ( !d->isMBoxSeparator( line ) ) {
|
|
kDebug() << "[MBox::readEntry] Invalid entry at:" << offset;
|
|
if ( !wasLocked ) {
|
|
unlock();
|
|
}
|
|
return QByteArray(); // The file is messed up or the index is incorrect.
|
|
}
|
|
|
|
line = d->mMboxFile.readLine();
|
|
while ( !d->isMBoxSeparator( line ) ) {
|
|
message += line;
|
|
if ( d->mMboxFile.atEnd() ) {
|
|
break;
|
|
}
|
|
line = d->mMboxFile.readLine();
|
|
}
|
|
} else {
|
|
offset -= d->mInitialMboxFileSize;
|
|
if ( offset > static_cast<quint64>( d->mAppendedEntries.size() ) ) {
|
|
if ( !wasLocked ) {
|
|
unlock();
|
|
}
|
|
return QByteArray();
|
|
}
|
|
|
|
QBuffer buffer( &( d->mAppendedEntries ) );
|
|
buffer.open( QIODevice::ReadOnly );
|
|
buffer.seek( offset );
|
|
|
|
QByteArray line = buffer.readLine();
|
|
|
|
if ( !d->isMBoxSeparator( line ) ) {
|
|
kDebug() << "[MBox::readEntry] Invalid appended entry at:" << offset;
|
|
if ( !wasLocked ) {
|
|
unlock();
|
|
}
|
|
return QByteArray(); // The file is messed up or the index is incorrect.
|
|
}
|
|
|
|
line = buffer.readLine();
|
|
while ( !d->isMBoxSeparator( line ) && !buffer.atEnd() ) {
|
|
message += line;
|
|
line = buffer.readLine();
|
|
}
|
|
}
|
|
|
|
// Remove te last '\n' added by writeEntry.
|
|
if ( message.endsWith( '\n' ) ) {
|
|
message.chop( 1 );
|
|
}
|
|
|
|
MBoxPrivate::unescapeFrom( message.data(), message.size() );
|
|
|
|
if ( !wasLocked ) {
|
|
if ( !d->startTimerIfNeeded() ) {
|
|
const bool unlocked = unlock();
|
|
Q_ASSERT( unlocked );
|
|
Q_UNUSED( unlocked );
|
|
}
|
|
}
|
|
|
|
return message;
|
|
}
|
|
|
|
KMime::Message *MBox::readMessage( const MBoxEntry &entry )
|
|
{
|
|
const QByteArray message = readRawMessage( entry );
|
|
if ( message.isEmpty() ) {
|
|
return 0;
|
|
}
|
|
|
|
KMime::Message *mail = new KMime::Message();
|
|
mail->setContent( KMime::CRLFtoLF( message ) );
|
|
mail->parse();
|
|
|
|
return mail;
|
|
}
|
|
|
|
QByteArray MBox::readMessageHeaders( const MBoxEntry &entry )
|
|
{
|
|
const bool wasLocked = d->mFileLocked;
|
|
if ( !wasLocked ) {
|
|
if (!lock()) {
|
|
kDebug() << "Failed to lock";
|
|
return QByteArray();
|
|
}
|
|
}
|
|
|
|
const quint64 offset = entry.messageOffset();
|
|
|
|
Q_ASSERT( d->mFileLocked );
|
|
Q_ASSERT( d->mMboxFile.isOpen() );
|
|
Q_ASSERT( ( d->mInitialMboxFileSize + d->mAppendedEntries.size() ) > offset );
|
|
|
|
QByteArray headers;
|
|
if ( offset < d->mInitialMboxFileSize ) {
|
|
d->mMboxFile.seek( offset );
|
|
QByteArray line = d->mMboxFile.readLine();
|
|
|
|
while ( line[0] != '\n' && !d->mMboxFile.atEnd() ) {
|
|
headers += line;
|
|
line = d->mMboxFile.readLine();
|
|
}
|
|
} else {
|
|
QBuffer buffer( &( d->mAppendedEntries ) );
|
|
buffer.open( QIODevice::ReadOnly );
|
|
buffer.seek( offset - d->mInitialMboxFileSize );
|
|
QByteArray line = buffer.readLine();
|
|
|
|
while ( line[0] != '\n' && !buffer.atEnd() ) {
|
|
headers += line;
|
|
line = buffer.readLine();
|
|
}
|
|
}
|
|
|
|
if ( !wasLocked ) {
|
|
unlock();
|
|
}
|
|
|
|
return headers;
|
|
}
|
|
|
|
bool MBox::save( const QString &fileName )
|
|
{
|
|
if ( !fileName.isEmpty() && KUrl( fileName ).toLocalFile() != d->mMboxFile.fileName() ) {
|
|
if ( !d->mMboxFile.copy( fileName ) ) {
|
|
return false;
|
|
}
|
|
|
|
if ( d->mAppendedEntries.size() == 0 ) {
|
|
return true; // Nothing to do
|
|
}
|
|
|
|
QFile otherFile( fileName );
|
|
Q_ASSERT( otherFile.exists() );
|
|
if ( !otherFile.open( QIODevice::ReadWrite ) ) {
|
|
return false;
|
|
}
|
|
|
|
otherFile.seek( d->mMboxFile.size() );
|
|
otherFile.write( d->mAppendedEntries );
|
|
|
|
// Don't clear mAppendedEntries and don't update mInitialFileSize. These
|
|
// are still valid for the original file.
|
|
return true;
|
|
}
|
|
|
|
if ( d->mAppendedEntries.size() == 0 ) {
|
|
return true; // Nothing to do.
|
|
}
|
|
|
|
if ( !lock() ) {
|
|
return false;
|
|
}
|
|
|
|
Q_ASSERT( d->mMboxFile.isOpen() );
|
|
|
|
d->mMboxFile.seek( d->mMboxFile.size() );
|
|
d->mMboxFile.write( d->mAppendedEntries );
|
|
d->mAppendedEntries.clear();
|
|
d->mInitialMboxFileSize = d->mMboxFile.size();
|
|
|
|
return unlock();
|
|
}
|
|
|
|
bool MBox::setLockType( LockType ltype )
|
|
{
|
|
if ( d->mFileLocked ) {
|
|
kDebug() << "File is currently locked.";
|
|
return false; // Don't change the method if the file is currently locked.
|
|
}
|
|
|
|
switch ( ltype ) {
|
|
case ProcmailLockfile:
|
|
if ( KStandardDirs::findExe( QLatin1String( "lockfile" ) ).isEmpty() ) {
|
|
kDebug() << "Could not find the lockfile executable";
|
|
return false;
|
|
}
|
|
break;
|
|
case MuttDotlock: // fall through
|
|
case MuttDotlockPrivileged:
|
|
if ( KStandardDirs::findExe( QLatin1String( "mutt_dotlock" ) ).isEmpty() ) {
|
|
kDebug() << "Could not find the mutt_dotlock executable";
|
|
return false;
|
|
}
|
|
break;
|
|
default:
|
|
break; // We assume fcntl available and lock_none doesn't need a check.
|
|
}
|
|
|
|
d->mLockType = ltype;
|
|
return true;
|
|
}
|
|
|
|
void MBox::setLockFile( const QString &lockFile )
|
|
{
|
|
d->mLockFileName = lockFile;
|
|
}
|
|
|
|
void MBox::setUnlockTimeout( int msec )
|
|
{
|
|
d->mUnlockTimer.setInterval( msec );
|
|
}
|
|
|
|
bool MBox::unlock()
|
|
{
|
|
if ( d->mLockType == None && !d->mFileLocked ) {
|
|
d->mFileLocked = false;
|
|
d->mMboxFile.close();
|
|
return true;
|
|
}
|
|
|
|
int rc = 0;
|
|
QStringList args;
|
|
|
|
switch ( d->mLockType ) {
|
|
case ProcmailLockfile:
|
|
// QFile::remove returns true on succes so negate the result.
|
|
if ( !d->mLockFileName.isEmpty() ) {
|
|
rc = !QFile( d->mLockFileName ).remove();
|
|
} else {
|
|
rc = !QFile( d->mMboxFile.fileName() + QLatin1String( ".lock" ) ).remove();
|
|
}
|
|
break;
|
|
|
|
case MuttDotlock:
|
|
args << QLatin1String( "-u" )
|
|
<< QString::fromLocal8Bit( QFile::encodeName( d->mMboxFile.fileName() ) );
|
|
rc = QProcess::execute( QLatin1String( "mutt_dotlock" ), args );
|
|
break;
|
|
|
|
case MuttDotlockPrivileged:
|
|
args << QLatin1String( "-u" ) << QLatin1String( "-p" )
|
|
<< QString::fromLocal8Bit( QFile::encodeName( d->mMboxFile.fileName() ) );
|
|
rc = QProcess::execute( QLatin1String( "mutt_dotlock" ), args );
|
|
break;
|
|
|
|
case None: // Fall through.
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if ( rc == 0 ) { // Unlocking succeeded
|
|
d->mFileLocked = false;
|
|
}
|
|
|
|
d->mMboxFile.close();
|
|
|
|
return !d->mFileLocked;
|
|
}
|