19#include "kmfolderindex.h" 
   21#include "kmfoldertype.h" 
   22#include "kcursorsaver.h" 
   24#include <tqfileinfo.h> 
   36#define INDEX_VERSION 1507 
   54#include <tdeapplication.h> 
   56#include <tdemessagebox.h> 
   65#define kmail_swap_32(x) bswap_32(x) 
   67#define kmail_swap_32(x) \ 
   68     ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >>  8) |           \ 
   69      (((x) & 0x0000ff00) <<  8) | (((x) & 0x000000ff) << 24)) 
   82    mIndexStreamPtrLength = 0;
 
   83    mIndexSwapByteOrder = 
false;
 
   84    mIndexSizeOfLong = 
sizeof(long);
 
   90KMFolderIndex::~KMFolderIndex()
 
   97  TQString sLocation(folder()->path());
 
   99  if ( !sLocation.isEmpty() ) {
 
  104  sLocation += 
".index";
 
  117      if ( !
mMsgList.at(i)->syncIndexString() ) {
 
  135  const uchar *buffer = 0;
 
  138  tempName = indexName + 
".temp";
 
  139  unlink(TQFile::encodeName(tempName));
 
  143  utime(TQFile::encodeName(
location()), 0);
 
  145  old_umask = umask(077);
 
  146  FILE *tmpIndexStream = fopen(TQFile::encodeName(tempName), 
"w");
 
  151  fprintf(tmpIndexStream, 
"# KMail-Index V%d\n", INDEX_VERSION);
 
  154  TQ_UINT32 byteOrder = 0x12345678;
 
  155  TQ_UINT32 sizeOfLong = 
sizeof(long);
 
  157  TQ_UINT32 header_length = 
sizeof(byteOrder)+
sizeof(sizeOfLong);
 
  158  char pad_char = 
'\0';
 
  159  fwrite(&pad_char, 
sizeof(pad_char), 1, tmpIndexStream);
 
  160  fwrite(&header_length, 
sizeof(header_length), 1, tmpIndexStream);
 
  163  fwrite(&byteOrder, 
sizeof(byteOrder), 1, tmpIndexStream);
 
  164  fwrite(&sizeOfLong, 
sizeof(sizeOfLong), 1, tmpIndexStream);
 
  166  off_t nho = ftell(tmpIndexStream);
 
  168  if ( !createEmptyIndex ) {
 
  172      if (!(msgBase = 
mMsgList.at(i))) 
continue;
 
  173      buffer = msgBase->asIndexString(len);
 
  174      fwrite(&len,
sizeof(len), 1, tmpIndexStream);
 
  176      off_t tmp = ftell(tmpIndexStream);
 
  177      msgBase->setIndexOffset(tmp);
 
  178      msgBase->setIndexLength(len);
 
  179      if(fwrite(buffer, len, 1, tmpIndexStream) != 1)
 
  180    kdDebug(5006) << 
"Whoa! " << __FILE__ << 
":" << __LINE__ << endl;
 
  184  int fError = ferror( tmpIndexStream );
 
  186    fclose( tmpIndexStream );
 
  189  if(    ( fflush( tmpIndexStream ) != 0 )
 
  190      || ( fsync( fileno( tmpIndexStream ) ) != 0 ) ) {
 
  192    fclose( tmpIndexStream );
 
  195  if( fclose( tmpIndexStream ) != 0 )
 
  198  ::rename(TQFile::encodeName(tempName), TQFile::encodeName(indexName));
 
  203  if ( createEmptyIndex )
 
  206  mIndexStream = fopen(TQFile::encodeName(indexName), 
"r+"); 
 
  210  updateIndexStreamPtr();
 
  221    kdDebug(5006) << k_funcinfo << 
"Reading index for " << 
label() << endl;
 
  245    if(version >= 1505) {
 
  252      if (mIndexSwapByteOrder)
 
  253        len = kmail_swap_32(len);
 
  257        kdDebug(5006) << k_funcinfo << 
" Unable to seek to the end of the message!" << endl;
 
  260      mi = 
new KMMsgInfo(folder(), offs, len);
 
  264      TQCString line(MAX_LINE);
 
  267      if (*line.data() == 
'\0') {
 
  273      mi = 
new KMMsgInfo(folder());
 
  274      mi->compat_fromOldIndexString(line, mConvertToUtf8);
 
  277      kdDebug(5006) << k_funcinfo << 
" Unable to create message info object!" << endl;
 
  289    else if (mi->isNew())
 
  291      mi->setStatus(KMMsgStatusUnread);
 
  295    if ((mi->isNew()) || (mi->isUnread()) ||
 
  296        (folder() == kmkernel->outboxFolder()))
 
  305    mConvertToUtf8 = 
false;
 
  310  if ( version < 1507 ) {
 
  311    updateInvitationAndAddressFieldsFromContents();
 
  318    kdDebug(5006) << k_funcinfo << 
"Done reading the index for " << 
label() << 
", we have " << mTotalMsgs << 
" messages." << endl;
 
  337  mIndexSwapByteOrder = 
false;
 
  338  mIndexSizeOfLong = 
sizeof(long);
 
  340  int ret = fscanf(
mIndexStream, 
"# KMail-Index V%d\n", &indexVersion);
 
  341  if ( ret == EOF || ret == 0 )
 
  349    kdWarning(5006) << 
"Index file " << 
indexLocation() << 
" is corrupted!!. Re-creating it." << endl;
 
  350    recreateIndex( 
false  );
 
  354  if (indexVersion < 1505 ) {
 
  355      if(indexVersion == 1503) {
 
  356      kdDebug(5006) << 
"Converting old index file " << 
indexLocation() << 
" to utf-8" << endl;
 
  357      mConvertToUtf8 = 
true;
 
  360  } 
else if (indexVersion == 1505) {
 
  361  } 
else if (indexVersion < INDEX_VERSION && indexVersion != 1506) {
 
  362      kdDebug(5006) << 
"Index file " << 
indexLocation() << 
" is out of date. Re-creating it." << endl;
 
  365  } 
else if(indexVersion > INDEX_VERSION) {
 
  366      tdeApp->setOverrideCursor(KCursor::arrowCursor());
 
  367      int r = KMessageBox::questionYesNo(0,
 
  369                        "The mail index for '%1' is from an unknown version of KMail (%2).\n" 
  370                        "This index can be regenerated from your mail folder, but some " 
  371                        "information, including status flags, may be lost. Do you wish " 
  372                        "to downgrade your index file?") .arg(name()) .arg(indexVersion), TQString(), i18n(
"Downgrade"), i18n(
"Do Not Downgrade") );
 
  373      tdeApp->restoreOverrideCursor();
 
  374      if (r == KMessageBox::Yes)
 
  380      TQ_UINT32 byteOrder = 0;
 
  381      TQ_UINT32 sizeOfLong = 
sizeof(long); 
 
  383      TQ_UINT32 header_length = 0;
 
  385      fread(&header_length, 
sizeof(header_length), 1, 
mIndexStream);
 
  386      if (header_length > 0xFFFF)
 
  387         header_length = kmail_swap_32(header_length);
 
  389      off_t endOfHeader = ftell(
mIndexStream) + header_length;
 
  391      bool needs_update = 
true;
 
  393      if (header_length >= 
sizeof(byteOrder))
 
  396         mIndexSwapByteOrder = (byteOrder == 0x78563412);
 
  397         header_length -= 
sizeof(byteOrder);
 
  399         if (header_length >= 
sizeof(sizeOfLong))
 
  401            fread(&sizeOfLong, 
sizeof(sizeOfLong), 1, 
mIndexStream);
 
  402            if (mIndexSwapByteOrder)
 
  403               sizeOfLong = kmail_swap_32(sizeOfLong);
 
  404            mIndexSizeOfLong = sizeOfLong;
 
  405            header_length -= 
sizeof(sizeOfLong);
 
  406            needs_update = 
false;
 
  409      if (needs_update || mIndexSwapByteOrder || (mIndexSizeOfLong != 
sizeof(
long)))
 
  414      if (mIndexSwapByteOrder)
 
  415         kdDebug(5006) << 
"Index File has byte order swapped!" << endl;
 
  416      if (mIndexSizeOfLong != 
sizeof(
long))
 
  417         kdDebug(5006) << 
"Index File sizeOfLong is " << mIndexSizeOfLong << 
" while sizeof(long) is " << 
sizeof(long) << 
" !" << endl;
 
  425bool KMFolderIndex::updateIndexStreamPtr(
bool just_close)
 
  427bool KMFolderIndex::updateIndexStreamPtr(
bool)
 
  432    utime(TQFile::encodeName(location()), 0);
 
  433    utime(TQFile::encodeName(indexLocation()), 0);
 
  434    utime(TQFile::encodeName( KMMsgDict::getFolderIdsLocation( *
this ) ), 0);
 
  436  mIndexSwapByteOrder = 
false;
 
  440        munmap((
char *)mIndexStreamPtr, mIndexStreamPtrLength);
 
  442    mIndexStreamPtrLength = 0;
 
  446    assert(mIndexStream);
 
  447    struct stat stat_buf;
 
  448    if(fstat(fileno(mIndexStream), &stat_buf) == -1) {
 
  450        munmap((
char *)mIndexStreamPtr, mIndexStreamPtrLength);
 
  452    mIndexStreamPtrLength = 0;
 
  456    munmap((
char *)mIndexStreamPtr, mIndexStreamPtrLength);
 
  457    mIndexStreamPtrLength = stat_buf.st_size;
 
  458    mIndexStreamPtr = (uchar *)mmap(0, mIndexStreamPtrLength, PROT_READ, MAP_SHARED,
 
  459                    fileno(mIndexStream), 0);
 
  460    if(mIndexStreamPtr == MAP_FAILED) {
 
  462    mIndexStreamPtrLength = 0;
 
  478    if (!contInfo.exists()) 
return KMFolderIndex::IndexOk;
 
  479    if (!indInfo.exists()) 
return KMFolderIndex::IndexMissing;
 
  481    return ( contInfo.lastModified() > indInfo.lastModified() )
 
  482        ? KMFolderIndex::IndexTooOld
 
  483        : KMFolderIndex::IndexOk;
 
  486void KMFolderIndex::clearIndex(
bool autoDelete, 
bool syncDict)
 
  492void KMFolderIndex::truncateIndex()
 
  505  for (
unsigned int idx = 0; idx < 
mMsgList.
high(); idx++)
 
  507      KMMsgDict::mutableInstance()->insert(0, 
mMsgList.at( idx ), idx);
 
  512KMMsgInfo* KMFolderIndex::setIndexEntry( 
int idx, 
KMMessage *msg )
 
  514  KMMsgInfo *msgInfo = msg->
msgInfo();
 
  516    msgInfo = 
new KMMsgInfo( folder() );
 
  525void KMFolderIndex::recreateIndex( 
bool readIndexAfterwards )
 
  527  tdeApp->setOverrideCursor(KCursor::arrowCursor());
 
  528  KMessageBox::information(0,
 
  529       i18n(
"The mail index for '%1' is corrupted and will be regenerated now, " 
  530            "but some information, like status flags, might get lost.").arg(name()));
 
  531  tdeApp->restoreOverrideCursor();
 
  533  if ( readIndexAfterwards ) {
 
  542void KMFolderIndex::silentlyRecreateIndex()
 
  545  open( 
"silentlyRecreateIndex" );
 
  550  close( 
"silentlyRecreateIndex" );
 
  553void KMFolderIndex::updateInvitationAndAddressFieldsFromContents()
 
  555  kdDebug(5006) << 
"Updating index for " << 
label() << 
", this might take a while." << endl;
 
  556  for ( uint i = 0; i < 
mMsgList.size(); i++ ) {
 
  557    KMMsgInfo * 
const msgInfo = 
dynamic_cast<KMMsgInfo*
>( 
mMsgList[i] );
 
  560      if ( msgString.size() > 0 ) {
 
  563        msg.updateInvitationState();
 
  564        if ( msg.
status() & KMMsgStatusHasInvitation ) {
 
  565          msgInfo->setStatus( msgInfo->status() | KMMsgStatusHasInvitation );
 
  567        if ( msg.
status() & KMMsgStatusHasNoInvitation ) {
 
  568          msgInfo->setStatus( msgInfo->status() | KMMsgStatusHasNoInvitation );
 
  570        msgInfo->setFrom( msg.
from() );
 
  571        msgInfo->setTo( msg.
to() );
 
  577#include "kmfolderindex.moc" 
The FolderStorage class is the bass class for the storage related aspects of a collection of mail (a ...
 
virtual DwString getDwString(int idx)=0
Read a message and returns a DwString.
 
int writeFolderIdsFile() const
Writes the message serial number file.
 
virtual int open(const char *owner)=0
Open folder for access.
 
virtual int count(bool cache=false) const
Number of messages in this folder.
 
virtual int rename(const TQString &newName, KMFolderDir *aParent=0)
Physically rename the folder.
 
bool isOpened() const
Test if folder is opened, i.e.
 
virtual TQString fileName() const
Returns the filename of the folder (reimplemented in KMFolderImap)
 
bool needsCompact
sven: true if on destruct folder needs to be compacted.
 
int touchFolderIdsFile()
Touches the message serial number file.
 
static TQString dotEscape(const TQString &)
Escape a leading dot.
 
void setDirty(bool f)
Change the dirty flag.
 
KMail::FolderContentsType contentsType() const
 
void close(const char *owner, bool force=false)
Close folder.
 
bool mDirty
if the index is dirty it will be recreated upon close()
 
virtual void writeConfig()
Write the config file.
 
bool dirty() const
Returns true if the table of contents is dirty.
 
TQString label() const
Returns the label of the folder for visualization.
 
bool mCompactable
false if index file is out of sync with mbox file
 
TQString location() const
Returns full path to folder file.
 
int mUnreadMsgs
number of unread messages, -1 if not yet set
 
bool mAutoCreateIndex
is the automatic creation of a index file allowed ?
 
sets a cursor and makes sure it's restored on destruction Create a KCursorSaver object when you want ...
 
bool readIndexHeader(int *gv=0)
Read index header.
 
KMFolderIndex(KMFolder *folder, const char *name=0)
Usually a parent is given.
 
FILE * mIndexStream
table of contents file
 
virtual int writeIndex(bool createEmptyIndex=false)
Write index to index-file.
 
virtual TQString indexLocation() const
Returns full path to index file.
 
off_t mHeaderOffset
offset of header of index file
 
virtual int count(bool cache=false) const
Number of messages in this folder.
 
IndexStatus
This enum indicates the status of the index file.
 
virtual IndexStatus indexStatus()=0
Tests whether the contents of this folder is newer than the index.
 
virtual int updateIndex()
Incrementally update the index if possible else call writeIndex.
 
bool readIndex()
Read index file and fill the message-info list mMsgList.
 
virtual int createIndexFromContents()=0
Create index file from messages file and fill the message-info list mMsgList.
 
virtual void fillMessageDict()
Inserts messages into the message dictionary by iterating over the message list.
 
KMMsgList mMsgList
list of index entries or messages
 
TQString from() const
Get or set the 'From' header field.
 
KMMsgInfo * msgInfo()
Get the KMMsgInfo object that was set with setMsgInfo().
 
TQString to() const
Get or set the 'To' header field.
 
void fromDwString(const DwString &str, bool setStatus=false)
Parse the string and create this message from it.
 
KMMsgStatus status() const
Status of the message.
 
void setMsgInfo(KMMsgInfo *msgInfo)
Set the KMMsgInfo object corresponding to this message.
 
void clear(bool autoDelete=true, bool syncDict=false)
Clear messages.
 
unsigned int append(KMMsgBase *msg, bool syncDict=true)
Append given message after the last used message.
 
unsigned int high() const
Returns first unused index (index of last message plus one).
 
void set(unsigned int idx, KMMsgBase *msg)
Set message at given index.
 
unsigned int count() const
Number of messages in the array.