19 #include "kmfolderindex.h"
21 #include "kmfoldertype.h"
22 #include "kcursorsaver.h"
24 #include <tqfileinfo.h>
29 #define HAVE_MMAP //need to get this into autoconf FIXME --Sam
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"