• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.8.3 API Reference
  • KDE Home
  • Contact Us
 

KMBox Library

mbox.cpp
00001 /*
00002   Copyright (c) 1996-1998 Stefan Taferner <taferner@kde.org>
00003   Copyright (c) 2009 Bertjan Broeksema <broeksema@kde.org>
00004 
00005   This library is free software; you can redistribute it and/or modify it
00006   under the terms of the GNU Library General Public License as published by
00007   the Free Software Foundation; either version 2 of the License, or (at your
00008   option) any later version.
00009 
00010   This library is distributed in the hope that it will be useful, but WITHOUT
00011   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00012   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00013   License for more details.
00014 
00015   You should have received a copy of the GNU Library General Public License
00016   along with this library; see the file COPYING.LIB.  If not, write to the
00017   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00018   02110-1301, USA.
00019 
00020   NOTE: Most of the code inside here is an slightly adjusted version of
00021   kdepim/kmail/kmfoldermbox.cpp. This is why I added a line for Stefan Taferner.
00022 
00023   Bertjan Broeksema, april 2009
00024 */
00025 
00026 #include "mbox.h"
00027 #include "mbox_p.h"
00028 #include "mboxentry_p.h"
00029 
00030 #include <KDebug>
00031 #include <KStandardDirs>
00032 #include <KUrl>
00033 
00034 #include <QtCore/QBuffer>
00035 #include <QtCore/QProcess>
00036 
00037 using namespace KMBox;
00038 
00040 
00041 MBox::MBox()
00042   : d( new MBoxPrivate( this ) )
00043 {
00044   // Set some sane defaults
00045   d->mFileLocked = false;
00046   d->mLockType = None;
00047 
00048   d->mUnlockTimer.setInterval( 0 );
00049   d->mUnlockTimer.setSingleShot( true );
00050 }
00051 
00052 MBox::~MBox()
00053 {
00054   if ( d->mFileLocked ) {
00055     unlock();
00056   }
00057 
00058   d->close();
00059 
00060   delete d;
00061 }
00062 
00063 // Appended entries works as follows: When an mbox file is loaded from disk,
00064 // d->mInitialMboxFileSize is set to the file size at that moment. New entries
00065 // are stored in memory (d->mAppendedEntries). The initial file size and the size
00066 // of the buffer determine the offset for the next message to append.
00067 MBoxEntry MBox::appendMessage( const KMime::Message::Ptr &entry )
00068 {
00069   // It doesn't make sense to add entries when we don't have an reference file.
00070   Q_ASSERT( !d->mMboxFile.fileName().isEmpty() );
00071 
00072   const QByteArray rawEntry = MBoxPrivate::escapeFrom( entry->encodedContent() );
00073 
00074   if ( rawEntry.size() <= 0 ) {
00075     kDebug() << "Message added to folder `" << d->mMboxFile.fileName()
00076              << "' contains no data. Ignoring it.";
00077     return MBoxEntry();
00078   }
00079 
00080   int nextOffset = d->mAppendedEntries.size(); // Offset of the appended message
00081 
00082   // Make sure the byte array is large enough to check for an end character.
00083   // Then check if the required newlines are there.
00084   if ( nextOffset < 1 && d->mMboxFile.size() > 0 ) { // Empty, add one empty line
00085     d->mAppendedEntries.append( "\n" );
00086     ++nextOffset;
00087   } else if ( nextOffset == 1 && d->mAppendedEntries.at( 0 ) != '\n' ) {
00088     // This should actually not happen, but catch it anyway.
00089     if ( d->mMboxFile.size() < 0 ) {
00090       d->mAppendedEntries.append( "\n" );
00091       ++nextOffset;
00092     }
00093   } else if ( nextOffset >= 2 ) {
00094     if ( d->mAppendedEntries.at( nextOffset - 1 ) != '\n' ) {
00095       if ( d->mAppendedEntries.at( nextOffset ) != '\n' ) {
00096         d->mAppendedEntries.append( "\n\n" );
00097         nextOffset += 2;
00098       } else {
00099         d->mAppendedEntries.append( "\n" );
00100         ++nextOffset;
00101       }
00102     }
00103   }
00104 
00105   const QByteArray separator = MBoxPrivate::mboxMessageSeparator( rawEntry );
00106   d->mAppendedEntries.append( separator );
00107   d->mAppendedEntries.append( rawEntry );
00108   if ( rawEntry[rawEntry.size() - 1] != '\n' ) {
00109     d->mAppendedEntries.append( "\n\n" );
00110   } else {
00111     d->mAppendedEntries.append( "\n" );
00112   }
00113 
00114   MBoxEntry resultEntry;
00115   resultEntry.d->mOffset = d->mInitialMboxFileSize + nextOffset;
00116   resultEntry.d->mMessageSize = rawEntry.size();
00117   resultEntry.d->mSeparatorSize = separator.size();
00118   d->mEntries << resultEntry;
00119 
00120   return resultEntry;
00121 }
00122 
00123 MBoxEntry::List MBox::entries( const MBoxEntry::List &deletedEntries ) const
00124 {
00125   MBoxEntry::List result;
00126 
00127   foreach ( const MBoxEntry &entry, d->mEntries ) {
00128     if ( !deletedEntries.contains( entry ) ) {
00129       result << entry;
00130     }
00131   }
00132 
00133   return result;
00134 }
00135 
00136 QString MBox::fileName() const
00137 {
00138   return d->mMboxFile.fileName();
00139 }
00140 
00141 bool MBox::load( const QString &fileName )
00142 {
00143   if ( d->mFileLocked ) {
00144     return false;
00145   }
00146 
00147   d->initLoad( fileName );
00148 
00149   if ( !lock() ) {
00150     kDebug() << "Failed to lock";
00151     return false;
00152   }
00153 
00154   QByteArray line;
00155   QByteArray prevSeparator;
00156   quint64 offs = 0; // The offset of the next message to read.
00157 
00158   while ( !d->mMboxFile.atEnd() ) {
00159     quint64 pos = d->mMboxFile.pos();
00160 
00161     line = d->mMboxFile.readLine();
00162 
00163     // if atEnd, use mail only if there was a separator line at all,
00164     // otherwise it's not a valid mbox
00165     if ( d->isMBoxSeparator( line ) ||
00166          ( d->mMboxFile.atEnd() && ( prevSeparator.size() != 0 ) ) ) {
00167 
00168       // if we are the at the file end, update pos to not forget the last line
00169       if ( d->mMboxFile.atEnd() ) {
00170         pos = d->mMboxFile.pos();
00171       }
00172 
00173       // Found the separator or at end of file, the message starts at offs
00174       quint64 msgSize = pos - offs;
00175 
00176       if( pos > 0 ) {
00177         // This is not the separator of the first mail in the file. If pos == 0
00178         // than we matched the separator of the first mail in the file.
00179         MBoxEntry entry;
00180         entry.d->mOffset = offs;
00181         entry.d->mSeparatorSize = prevSeparator.size();
00182         entry.d->mMessageSize = msgSize - 1;
00183 
00184         // Don't add the separator size and the newline up to the message size.
00185         entry.d->mMessageSize -= prevSeparator.size() + 1;
00186 
00187         d->mEntries << entry;
00188       }
00189 
00190       if ( d->isMBoxSeparator( line ) ) {
00191         prevSeparator = line;
00192       }
00193 
00194       offs += msgSize; // Mark the beginning of the next message.
00195     }
00196   }
00197 
00198   // FIXME: What if unlock fails?
00199   // if no separator was found, the file is still valid if it is empty
00200   return unlock() && ( ( prevSeparator.size() != 0 ) || ( d->mMboxFile.size() == 0 ) );
00201 }
00202 
00203 bool MBox::lock()
00204 {
00205   if ( d->mMboxFile.fileName().isEmpty() ) {
00206     return false; // We cannot lock if there is no file loaded.
00207   }
00208 
00209   // We can't load another file when the mbox currently is locked so if d->mFileLocked
00210   // is true atm just return true.
00211   if ( locked() ) {
00212     return true;
00213   }
00214 
00215   if ( d->mLockType == None ) {
00216     d->mFileLocked = true;
00217     if ( d->open() ) {
00218       d->startTimerIfNeeded();
00219       return true;
00220     }
00221 
00222     d->mFileLocked = false;
00223     return false;
00224   }
00225 
00226   QStringList args;
00227   int rc = 0;
00228 
00229   switch( d->mLockType ) {
00230   case ProcmailLockfile:
00231     args << QLatin1String( "-l20" ) << QLatin1String( "-r5" );
00232     if ( !d->mLockFileName.isEmpty() ) {
00233       args << QString::fromLocal8Bit( QFile::encodeName( d->mLockFileName ) );
00234     } else {
00235       args << QString::fromLocal8Bit( QFile::encodeName( d->mMboxFile.fileName() +
00236                                                          QLatin1String( ".lock" ) ) );
00237     }
00238 
00239     rc = QProcess::execute( QLatin1String( "lockfile" ), args );
00240     if ( rc != 0 ) {
00241       kDebug() << "lockfile -l20 -r5 " << d->mMboxFile.fileName()
00242                << ": Failed ("<< rc << ") switching to read only mode";
00243       d->mReadOnly = true; // In case the MBox object was created read/write we
00244       // set it to read only when locking failed.
00245     } else {
00246       d->mFileLocked = true;
00247     }
00248     break;
00249 
00250   case MuttDotlock:
00251     args << QString::fromLocal8Bit( QFile::encodeName( d->mMboxFile.fileName() ) );
00252     rc = QProcess::execute( QLatin1String( "mutt_dotlock" ), args );
00253 
00254     if ( rc != 0 ) {
00255       kDebug() << "mutt_dotlock " << d->mMboxFile.fileName()
00256                << ": Failed (" << rc << ") switching to read only mode";
00257       d->mReadOnly = true; // In case the MBox object was created read/write we
00258       // set it to read only when locking failed.
00259     } else {
00260       d->mFileLocked = true;
00261     }
00262     break;
00263 
00264   case MuttDotlockPrivileged:
00265     args << QLatin1String( "-p" )
00266          << QString::fromLocal8Bit( QFile::encodeName( d->mMboxFile.fileName() ) );
00267     rc = QProcess::execute( QLatin1String( "mutt_dotlock" ), args );
00268 
00269     if ( rc != 0 ) {
00270       kDebug() << "mutt_dotlock -p " << d->mMboxFile.fileName() << ":"
00271                << ": Failed (" << rc << ") switching to read only mode";
00272       d->mReadOnly = true;
00273     } else {
00274       d->mFileLocked = true;
00275     }
00276     break;
00277 
00278   case None:
00279     d->mFileLocked = true;
00280     break;
00281   default:
00282     break;
00283   }
00284 
00285   if ( d->mFileLocked ) {
00286     if ( !d->open() ) {
00287       const bool unlocked = unlock();
00288       Q_ASSERT( unlocked ); // If this fails we're in trouble.
00289       Q_UNUSED( unlocked );
00290     }
00291   }
00292 
00293   d->startTimerIfNeeded();
00294   return d->mFileLocked;
00295 }
00296 
00297 bool MBox::locked() const
00298 {
00299   return d->mFileLocked;
00300 }
00301 
00302 static bool lessThanByOffset( const MBoxEntry &left, const MBoxEntry &right )
00303 {
00304   return left.messageOffset() < right.messageOffset();
00305 }
00306 
00307 bool MBox::purge( const MBoxEntry::List &deletedEntries, QList<MBoxEntry::Pair> *movedEntries )
00308 {
00309   if ( d->mMboxFile.fileName().isEmpty() ) {
00310     return false; // No file loaded yet.
00311   }
00312 
00313   if ( deletedEntries.isEmpty() ) {
00314     return true; // Nothing to do.
00315   }
00316 
00317   if ( !lock() ) {
00318     return false;
00319   }
00320 
00321   foreach ( const MBoxEntry &entry, deletedEntries ) {
00322     d->mMboxFile.seek( entry.messageOffset() );
00323     const QByteArray line = d->mMboxFile.readLine();
00324 
00325     if ( !d->isMBoxSeparator( line ) ) {
00326       qDebug() << "Found invalid separator at:" << entry.messageOffset();
00327       unlock();
00328       return false; // The file is messed up or the index is incorrect.
00329     }
00330   }
00331 
00332   // All entries are deleted, so just resize the file to a size of 0.
00333   if ( deletedEntries.size() == d->mEntries.size() ) {
00334     d->mEntries.clear();
00335     d->mMboxFile.resize( 0 );
00336     kDebug() << "Purge comleted successfully, unlocking the file.";
00337     return unlock();
00338   }
00339 
00340   qSort( d->mEntries.begin(), d->mEntries.end(), lessThanByOffset );
00341   quint64 writeOffset = 0;
00342   bool writeOffSetInitialized = false;
00343   MBoxEntry::List resultingEntryList;
00344   QList<MBoxEntry::Pair> tmpMovedEntries;
00345 
00346   quint64 origFileSize = d->mMboxFile.size();
00347 
00348   QListIterator<MBoxEntry> i( d->mEntries );
00349   while ( i.hasNext() ) {
00350     MBoxEntry entry = i.next();
00351 
00352     if ( deletedEntries.contains( entry ) && !writeOffSetInitialized ) {
00353       writeOffset = entry.messageOffset();
00354       writeOffSetInitialized = true;
00355     } else if ( writeOffSetInitialized &&
00356                 writeOffset < entry.messageOffset() &&
00357                 !deletedEntries.contains( entry ) ) {
00358       // The current message doesn't have to be deleted, but must be moved.
00359       // First determine the size of the entry that must be moved.
00360       quint64 entrySize = 0;
00361       if ( i.hasNext() ) {
00362         entrySize = i.next().messageOffset() - entry.messageOffset();
00363         i.previous(); // Go back to make sure that we also handle the next entry.
00364       } else {
00365         entrySize = origFileSize - entry.messageOffset();
00366       }
00367 
00368       Q_ASSERT( entrySize > 0 ); // MBox entries really cannot have a size <= 0;
00369 
00370       // we map the whole area of the file starting at the writeOffset up to the
00371       // message that have to be moved into memory. This includes eventually the
00372       // messages that are the deleted between the first deleted message
00373       // encountered and the message that has to be moved.
00374       quint64 mapSize = entry.messageOffset() + entrySize - writeOffset;
00375 
00376       // Now map writeOffSet + mapSize into mem.
00377       uchar *memArea = d->mMboxFile.map( writeOffset, mapSize );
00378 
00379       // Now read the entry that must be moved to writeOffset.
00380       quint64 startOffset = entry.messageOffset() - writeOffset;
00381       memmove( memArea, memArea + startOffset, entrySize );
00382 
00383       d->mMboxFile.unmap( memArea );
00384 
00385       MBoxEntry resultEntry;
00386       resultEntry.d->mOffset = writeOffset;
00387       resultEntry.d->mSeparatorSize = entry.separatorSize();
00388       resultEntry.d->mMessageSize = entry.messageSize();
00389 
00390       resultingEntryList << resultEntry;
00391       tmpMovedEntries << MBoxEntry::Pair( MBoxEntry( entry.messageOffset() ),
00392                                           MBoxEntry( resultEntry.messageOffset() ) );
00393       writeOffset += entrySize;
00394     } else if ( !deletedEntries.contains( entry ) ) {
00395       // Unmoved and not deleted entry, can only ocure before the first deleted
00396       // entry.
00397       Q_ASSERT( !writeOffSetInitialized );
00398       resultingEntryList << entry;
00399     }
00400   }
00401 
00402   // Chop off remaining entry bits.
00403   d->mMboxFile.resize( writeOffset );
00404   d->mEntries = resultingEntryList;
00405 
00406   kDebug() << "Purge comleted successfully, unlocking the file.";
00407   if ( movedEntries ) {
00408     *movedEntries = tmpMovedEntries;
00409   }
00410   return unlock(); // FIXME: What if this fails? It will return false but the
00411                    // file has changed.
00412 }
00413 
00414 QByteArray MBox::readRawMessage( const MBoxEntry &entry )
00415 {
00416   const bool wasLocked = locked();
00417   if ( !wasLocked ) {
00418     if ( !lock() ) {
00419       return QByteArray();
00420     }
00421   }
00422 
00423   // TODO: Add error handling in case locking failed.
00424 
00425   quint64 offset = entry.messageOffset();
00426 
00427   Q_ASSERT( d->mFileLocked );
00428   Q_ASSERT( d->mMboxFile.isOpen() );
00429   Q_ASSERT( ( d->mInitialMboxFileSize + d->mAppendedEntries.size() ) > offset );
00430 
00431   QByteArray message;
00432 
00433   if ( offset < d->mInitialMboxFileSize ) {
00434     d->mMboxFile.seek( offset );
00435 
00436     QByteArray line = d->mMboxFile.readLine();
00437 
00438     if ( !d->isMBoxSeparator( line ) ) {
00439       kDebug() << "[MBox::readEntry] Invalid entry at:" << offset;
00440       if ( !wasLocked ) {
00441         unlock();
00442       }
00443       return QByteArray(); // The file is messed up or the index is incorrect.
00444     }
00445 
00446     line = d->mMboxFile.readLine();
00447     while ( !d->isMBoxSeparator( line ) ) {
00448       message += line;
00449       if ( d->mMboxFile.atEnd() ) {
00450         break;
00451       }
00452       line = d->mMboxFile.readLine();
00453     }
00454   } else {
00455     offset -= d->mInitialMboxFileSize;
00456     if ( offset > static_cast<quint64>( d->mAppendedEntries.size() ) ) {
00457       if ( !wasLocked ) {
00458         unlock();
00459       }
00460       return QByteArray();
00461     }
00462 
00463     QBuffer buffer( &(d->mAppendedEntries) );
00464     buffer.open( QIODevice::ReadOnly );
00465     buffer.seek( offset );
00466 
00467     QByteArray line = buffer.readLine();
00468 
00469     if ( !d->isMBoxSeparator( line ) ) {
00470       kDebug() << "[MBox::readEntry] Invalid appended entry at:" << offset;
00471       if ( !wasLocked ) {
00472         unlock();
00473       }
00474       return QByteArray(); // The file is messed up or the index is incorrect.
00475     }
00476 
00477     line = buffer.readLine();
00478     while ( !d->isMBoxSeparator( line ) && !buffer.atEnd() ) {
00479       message += line;
00480       line = buffer.readLine();
00481     }
00482   }
00483 
00484   // Remove te last '\n' added by writeEntry.
00485   if ( message.endsWith( '\n' ) ) {
00486     message.chop( 1 );
00487   }
00488 
00489   MBoxPrivate::unescapeFrom( message.data(), message.size() );
00490 
00491   if ( !wasLocked ) {
00492     if ( !d->startTimerIfNeeded() ) {
00493       const bool unlocked = unlock();
00494       Q_ASSERT( unlocked );
00495       Q_UNUSED( unlocked );
00496     }
00497   }
00498 
00499   return message;
00500 }
00501 
00502 KMime::Message *MBox::readMessage( const MBoxEntry &entry )
00503 {
00504   const QByteArray message = readRawMessage( entry );
00505   if ( message.isEmpty() ) {
00506     return 0;
00507   }
00508 
00509   KMime::Message *mail = new KMime::Message();
00510   mail->setContent( KMime::CRLFtoLF( message ) );
00511   mail->parse();
00512 
00513   return mail;
00514 }
00515 
00516 QByteArray MBox::readMessageHeaders( const MBoxEntry &entry )
00517 {
00518   const bool wasLocked = d->mFileLocked;
00519   if ( !wasLocked ) {
00520     lock();
00521   }
00522 
00523   const quint64 offset = entry.messageOffset();
00524 
00525   Q_ASSERT( d->mFileLocked );
00526   Q_ASSERT( d->mMboxFile.isOpen() );
00527   Q_ASSERT( ( d->mInitialMboxFileSize + d->mAppendedEntries.size() ) > offset );
00528 
00529   QByteArray headers;
00530   if ( offset < d->mInitialMboxFileSize ) {
00531     d->mMboxFile.seek( offset );
00532     QByteArray line = d->mMboxFile.readLine();
00533 
00534     while ( line[0] != '\n' && !d->mMboxFile.atEnd() ) {
00535       headers += line;
00536       line = d->mMboxFile.readLine();
00537     }
00538   } else {
00539     QBuffer buffer( &(d->mAppendedEntries) );
00540     buffer.open( QIODevice::ReadOnly );
00541     buffer.seek( offset - d->mInitialMboxFileSize );
00542     QByteArray line = buffer.readLine();
00543 
00544     while ( line[0] != '\n' && !buffer.atEnd() ) {
00545       headers += line;
00546       line = buffer.readLine();
00547     }
00548   }
00549 
00550   if ( !wasLocked ) {
00551     unlock();
00552   }
00553 
00554   return headers;
00555 }
00556 
00557 bool MBox::save( const QString &fileName )
00558 {
00559   if ( !fileName.isEmpty() && KUrl( fileName ).toLocalFile() != d->mMboxFile.fileName() ) {
00560     if ( !d->mMboxFile.copy( fileName ) ) {
00561       return false;
00562     }
00563 
00564     if ( d->mAppendedEntries.size() == 0 ) {
00565       return true; // Nothing to do
00566     }
00567 
00568     QFile otherFile( fileName );
00569     Q_ASSERT( otherFile.exists() );
00570     if ( !otherFile.open( QIODevice::ReadWrite ) ) {
00571       return false;
00572     }
00573 
00574     otherFile.seek( d->mMboxFile.size() );
00575     otherFile.write( d->mAppendedEntries );
00576 
00577     // Don't clear mAppendedEntries and don't update mInitialFileSize. These
00578     // are still valid for the original file.
00579     return true;
00580   }
00581 
00582   if ( d->mAppendedEntries.size() == 0 ) {
00583     return true; // Nothing to do.
00584   }
00585 
00586   if ( !lock() ) {
00587     return false;
00588   }
00589 
00590   Q_ASSERT( d->mMboxFile.isOpen() );
00591 
00592   d->mMboxFile.seek( d->mMboxFile.size() );
00593   d->mMboxFile.write( d->mAppendedEntries );
00594   d->mAppendedEntries.clear();
00595   d->mInitialMboxFileSize = d->mMboxFile.size();
00596 
00597   return unlock();
00598 }
00599 
00600 bool MBox::setLockType( LockType ltype )
00601 {
00602   if ( d->mFileLocked ) {
00603     kDebug() << "File is currently locked.";
00604     return false; // Don't change the method if the file is currently locked.
00605   }
00606 
00607   switch ( ltype ) {
00608     case ProcmailLockfile:
00609       if ( KStandardDirs::findExe( QLatin1String( "lockfile" ) ).isEmpty() ) {
00610         kDebug() << "Could not find the lockfile executable";
00611         return false;
00612       }
00613       break;
00614     case MuttDotlock: // fall through
00615     case MuttDotlockPrivileged:
00616       if ( KStandardDirs::findExe( QLatin1String( "mutt_dotlock" ) ).isEmpty() ) {
00617         kDebug() << "Could not find the mutt_dotlock executable";
00618         return false;
00619       }
00620       break;
00621     default:
00622       break; // We assume fcntl available and lock_none doesn't need a check.
00623   }
00624 
00625   d->mLockType = ltype;
00626   return true;
00627 }
00628 
00629 void MBox::setLockFile( const QString &lockFile )
00630 {
00631   d->mLockFileName = lockFile;
00632 }
00633 
00634 void MBox::setUnlockTimeout( int msec )
00635 {
00636   d->mUnlockTimer.setInterval( msec );
00637 }
00638 
00639 bool MBox::unlock()
00640 {
00641   if ( d->mLockType == None && !d->mFileLocked ) {
00642     d->mFileLocked = false;
00643     d->mMboxFile.close();
00644     return true;
00645   }
00646 
00647   int rc = 0;
00648   QStringList args;
00649 
00650   switch( d->mLockType ) {
00651     case ProcmailLockfile:
00652       // QFile::remove returns true on succes so negate the result.
00653       if ( !d->mLockFileName.isEmpty() ) {
00654         rc = !QFile( d->mLockFileName ).remove();
00655       } else {
00656         rc = !QFile( d->mMboxFile.fileName() + QLatin1String( ".lock" ) ).remove();
00657       }
00658       break;
00659 
00660     case MuttDotlock:
00661       args << QLatin1String( "-u" )
00662            << QString::fromLocal8Bit( QFile::encodeName( d->mMboxFile.fileName() ) );
00663       rc = QProcess::execute( QLatin1String( "mutt_dotlock" ), args );
00664       break;
00665 
00666     case MuttDotlockPrivileged:
00667       args << QLatin1String( "-u" ) << QLatin1String( "-p" )
00668            << QString::fromLocal8Bit( QFile::encodeName( d->mMboxFile.fileName() ) );
00669       rc = QProcess::execute( QLatin1String( "mutt_dotlock" ), args );
00670       break;
00671 
00672     case None: // Fall through.
00673     default:
00674       break;
00675   }
00676 
00677   if ( rc == 0 ) { // Unlocking succeeded
00678     d->mFileLocked = false;
00679   }
00680 
00681   d->mMboxFile.close();
00682 
00683   return !d->mFileLocked;
00684 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Thu May 10 2012 22:17:24 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KMBox Library

Skip menu "KMBox Library"
  • Main Page
  • Alphabetical List
  • Class List
  • Class Members
  • File List
  • Related Pages

kdepimlibs-4.8.3 API Reference

Skip menu "kdepimlibs-4.8.3 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal