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";
115 for (
unsigned int i = 0; !dirty && i <
mMsgList.
high(); i++ ) {
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;
425 bool KMFolderIndex::updateIndexStreamPtr(
bool just_close)
427 bool KMFolderIndex::updateIndexStreamPtr(
bool)
432 utime(TQFile::encodeName(
location()), 0);
434 utime(TQFile::encodeName( KMMsgDict::getFolderIdsLocation( *
this ) ), 0);
436 mIndexSwapByteOrder =
false;
440 munmap((
char *)mIndexStreamPtr, mIndexStreamPtrLength);
442 mIndexStreamPtrLength = 0;
447 struct stat stat_buf;
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,
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 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 ) {
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" void setDirty(bool f)
Change the dirty flag.
bool dirty() const
Returns TRUE if the table of contents is dirty.
int writeFolderIdsFile() const
Writes the message serial number file.
virtual TQString indexLocation() const
Returns full path to index file.
off_t mHeaderOffset
offset of header of index file
KMail::FolderContentsType contentsType() const
bool needsCompact
sven: true if on destruct folder needs to be compacted.
IndexStatus
This enum indicates the status of the index file.
bool mDirty
if the index is dirty it will be recreated upon close()
void clear(bool autoDelete=TRUE, bool syncDict=false)
Clear messages.
virtual int updateIndex()
Incrementally update the index if possible else call writeIndex.
bool readIndexHeader(int *gv=0)
Read index header.
virtual TQString fileName() const
Returns the filename of the folder (reimplemented in KMFolderImap)
FILE * mIndexStream
table of contents file
bool isOpened() const
Test if folder is opened, i.e.
TQString from() const
Get or set the 'From' header field.
bool mAutoCreateIndex
is the automatic creation of a index file allowed ?
TQString location() const
Returns full path to folder file.
virtual DwString getDwString(int idx)=0
Read a message and returns a DwString.
KMMsgInfo * msgInfo()
Get the KMMsgInfo object that was set with setMsgInfo().
bool readIndex()
Read index file and fill the message-info list mMsgList.
static TQString dotEscape(const TQString &)
Escape a leading dot.
void setMsgInfo(KMMsgInfo *msgInfo)
Set the KMMsgInfo object corresponding to this message.
virtual int writeIndex(bool createEmptyIndex=false)
Write index to index-file.
void close(const char *owner, bool force=false)
Close folder.
virtual void writeConfig()
Write the config file.
int touchFolderIdsFile()
Touches the message serial number file.
KMMsgList mMsgList
list of index entries or messages
void fromDwString(const DwString &str, bool setStatus=false)
Parse the string and create this message from it.
int mUnreadMsgs
number of unread messages, -1 if not yet set
KMFolderIndex(KMFolder *folder, const char *name=0)
Usually a parent is given.
The FolderStorage class is the bass class for the storage related aspects of a collection of mail (a ...
sets a cursor and makes sure it's restored on destruction Create a KCursorSaver object when you want ...
KMMsgStatus status() const
Status of the message.
virtual void fillMessageDict()
Inserts messages into the message dictionary by iterating over the message list.
unsigned int high() const
Returns first unused index (index of last message plus one).
virtual int createIndexFromContents()=0
Create index file from messages file and fill the message-info list mMsgList.
unsigned int append(KMMsgBase *msg, bool syncDict=true)
Append given message after the last used message.
bool mCompactable
false if index file is out of sync with mbox file
virtual int rename(const TQString &newName, KMFolderDir *aParent=0)
Physically rename the folder.
void set(unsigned int idx, KMMsgBase *msg)
Set message at given index.
TQString label() const
Returns the label of the folder for visualization.
TQString to() const
Get or set the 'To' header field.
virtual IndexStatus indexStatus()=0
Tests whether the contents of this folder is newer than the index.
virtual int count(bool cache=false) const
Number of messages in this folder.
virtual int open(const char *owner)=0
Open folder for access.
virtual int count(bool cache=false) const
Number of messages in this folder.
unsigned int count() const
Number of messages in the array.