19 #include "kmfolderindex.h"
21 #include "kmfoldertype.h"
22 #include "kcursorsaver.h"
24 #include <tqfileinfo.h>
36 #define INDEX_VERSION 1507
51 #ifdef HAVE_BYTESWAP_H
54 #include <tdeapplication.h>
56 #include <tdemessagebox.h>
57 #include <tdelocale.h>
58 #include "kmmsgdict.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))
73 #include <sys/types.h>
82 mIndexStreamPtrLength = 0;
83 mIndexSwapByteOrder =
false;
84 mIndexSizeOfLong =
sizeof(long);
90 KMFolderIndex::~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 kapp->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 kapp->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;
425 bool KMFolderIndex::updateIndexStreamPtr(
bool just_close)
427 bool 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;
486 void KMFolderIndex::clearIndex(
bool autoDelete,
bool syncDict)
492 void KMFolderIndex::truncateIndex()
505 for (
unsigned int idx = 0; idx <
mMsgList.
high(); idx++)
507 KMMsgDict::mutableInstance()->insert(0,
mMsgList.at( idx ), idx);
512 KMMsgInfo* KMFolderIndex::setIndexEntry(
int idx,
KMMessage *msg )
514 KMMsgInfo *msgInfo = msg->
msgInfo();
516 msgInfo =
new KMMsgInfo( folder() );
525 void KMFolderIndex::recreateIndex(
bool readIndexAfterwards )
527 kapp->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 kapp->restoreOverrideCursor();
533 if ( readIndexAfterwards ) {
542 void KMFolderIndex::silentlyRecreateIndex()
545 open(
"silentlyRecreateIndex" );
550 close(
"silentlyRecreateIndex" );
553 void 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.
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.
KMMsgInfo * msgInfo()
Get the KMMsgInfo object that was set with setMsgInfo().
KMMsgStatus status() const
Status of the message.
void setMsgInfo(KMMsgInfo *msgInfo)
Set the KMMsgInfo object corresponding to this message.
unsigned int append(KMMsgBase *msg, bool syncDict=true)
Append given message after the last used message.
void clear(bool autoDelete=TRUE, bool syncDict=false)
Clear messages.
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.