4 #include "kmfolderindex.h"
8 #include "globalsettings.h"
9 #include "folderstorage.h"
11 #include <tqfileinfo.h>
14 #include <kstaticdeleter.h>
24 #ifdef HAVE_BYTESWAP_H
33 #define kmail_swap_32(x) bswap_32(x)
35 #define kmail_swap_32(x) \
36 ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
37 (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
44 #define IDS_VERSION 1002
47 #define IDS_HEADER "# KMail-Index-IDs V%d\n*"
56 KMMsgDictEntry(
const KMFolder *aFolder,
int aIndex)
57 : folder( aFolder ), index( aIndex )
74 KMMsgDictREntry(
int size = 0)
77 memset(array.data(), 0, array.size() *
sizeof(KMMsgDictEntry *));
79 swapByteOrder =
false;
90 void set(
int index, KMMsgDictEntry *entry)
93 int size = array.size();
95 int newsize = TQMAX(size + 25, index + 1);
96 array.resize(newsize);
97 for (
int j = size; j < newsize; j++)
100 array.at(index) = entry;
104 KMMsgDictEntry *get(
int index)
106 if (index >= 0 && (
unsigned)index < array.size())
107 return array.at(index);
111 ulong getMsn(
int index)
113 KMMsgDictEntry *entry = get(index);
121 int count = array.size() - 1;
136 TQMemArray<KMMsgDictEntry *> array;
143 static KStaticDeleter<KMMsgDict> msgDict_sd;
148 KMMsgDict::KMMsgDict()
150 int lastSizeOfDict = GlobalSettings::self()->msgDictSizeHint();
151 lastSizeOfDict = ( lastSizeOfDict * 11 ) / 10;
152 GlobalSettings::self()->setMsgDictSizeHint( 0 );
153 dict =
new KMDict( lastSizeOfDict );
160 KMMsgDict::~KMMsgDict()
170 msgDict_sd.setObject( m_self,
new KMMsgDict() );
178 msgDict_sd.setObject( m_self,
new KMMsgDict() );
185 unsigned long KMMsgDict::getNextMsgSerNum() {
186 unsigned long msn = nextMsgSerNum;
191 void KMMsgDict::deleteRentry(KMMsgDictREntry *entry)
196 unsigned long KMMsgDict::insert(
unsigned long msgSerNum,
197 const KMMsgBase *msg,
int index)
199 unsigned long msn = msgSerNum;
201 msn = getNextMsgSerNum();
203 if (msn >= nextMsgSerNum)
204 nextMsgSerNum = msn + 1;
209 kdDebug(5006) <<
"KMMsgDict::insert: Cannot insert the message, "
210 <<
"null pointer to storage. Requested serial: " << msgSerNum
212 kdDebug(5006) <<
" Message info: Subject: " << msg->subject() <<
", To: "
213 << msg->toStrip() <<
", Date: " << msg->dateStr() << endl;
218 index = folder->
find(msg);
221 while (dict->
find((
long)msn)) {
222 msn = getNextMsgSerNum();
228 KMMsgDictEntry *entry =
new KMMsgDictEntry(folder->folder(), index);
229 dict->
insert((
long)msn, entry);
231 KMMsgDictREntry *rentry = folder->
rDict();
233 rentry =
new KMMsgDictREntry();
236 rentry->set(index, entry);
241 unsigned long KMMsgDict::insert(
const KMMsgBase *msg,
int index)
243 unsigned long msn = msg->getMsgSerNum();
244 return insert(msn, msg, index);
249 void KMMsgDict::replace(
unsigned long msgSerNum,
250 const KMMsgBase *msg,
int index)
254 kdDebug(5006) <<
"KMMsgDict::replace: Cannot replace the message serial "
255 <<
"number, null pointer to storage. Requested serial: " << msgSerNum
257 kdDebug(5006) <<
" Message info: Subject: " << msg->subject() <<
", To: "
258 << msg->toStrip() <<
", Date: " << msg->dateStr() << endl;
263 index = folder->
find( msg );
266 KMMsgDictEntry *entry =
new KMMsgDictEntry( folder->folder(), index );
267 dict->
insert( (
long)msgSerNum, entry );
269 KMMsgDictREntry *rentry = folder->
rDict();
271 rentry =
new KMMsgDictREntry();
274 rentry->set(index, entry);
279 void KMMsgDict::remove(
unsigned long msgSerNum)
281 long key = (long)msgSerNum;
282 KMMsgDictEntry *entry = (KMMsgDictEntry *)dict->
find(key);
287 KMMsgDictREntry *rentry = entry->folder->storage()->rDict();
289 rentry->set(entry->index, 0);
295 unsigned long KMMsgDict::remove(
const KMMsgBase *msg)
297 unsigned long msn = msg->getMsgSerNum();
304 void KMMsgDict::update(
const KMMsgBase *msg,
int index,
int newIndex)
306 KMMsgDictREntry *rentry = msg->parent()->storage()->rDict();
308 KMMsgDictEntry *entry = rentry->get(index);
310 entry->index = newIndex;
311 rentry->set(index, 0);
312 rentry->set(newIndex, entry);
320 KMFolder **retFolder,
int *retIndex)
const
322 KMMsgDictEntry *entry = (KMMsgDictEntry *)dict->
find((
long)key);
324 *retFolder = (
KMFolder *)entry->folder;
325 *retIndex = entry->index;
333 KMFolder **retFolder,
int *retIndex)
const
335 getLocation(msg->getMsgSerNum(), retFolder, retIndex);
347 unsigned long msn = 0;
349 KMMsgDictREntry *rentry = folder->storage()->
rDict();
351 msn = rentry->getMsn(index);
361 TQValueList<unsigned long> ret;
362 for (
unsigned int i = 0; i < msgList.count(); i++ ) {
363 unsigned long serNum = msgList.at(i)->getMsgSerNum();
365 ret.append( serNum );
372 TQString KMMsgDict::getFolderIdsLocation(
const FolderStorage &storage )
379 bool KMMsgDict::isFolderIdsOutdated(
const FolderStorage &storage )
381 bool outdated =
false;
384 TQFileInfo idsInfo( getFolderIdsLocation( storage ) );
386 if (!indexInfo.exists() || !idsInfo.exists())
388 if (indexInfo.lastModified() > idsInfo.lastModified())
398 if ( isFolderIdsOutdated( storage ) )
401 TQString filename = getFolderIdsLocation( storage );
402 FILE *fp = fopen(TQFile::encodeName(filename),
"r+");
407 fscanf(fp, IDS_HEADER, &version);
408 if (version != IDS_VERSION) {
414 TQ_UINT32 byte_order;
415 if (!fread(&byte_order,
sizeof(byte_order), 1, fp)) {
419 swapByteOrder = (byte_order == 0x78563412);
422 if (!fread(&count,
sizeof(count), 1, fp)) {
427 count = kmail_swap_32(count);
431 long pos = ftell(fp);
432 fseek(fp, 0, SEEK_END);
433 long fileSize = ftell(fp);
434 fseek(fp, pos, SEEK_SET);
437 if ( (fileSize - pos) < (
long)(count *
sizeof(TQ_UINT32)) ) {
442 KMMsgDictREntry *rentry =
new KMMsgDictREntry(count);
444 for (
unsigned int index = 0; index < count; index++) {
447 bool readOk = fread(&msn,
sizeof(msn), 1, fp);
449 msn = kmail_swap_32(msn);
451 if (!readOk || dict->
find(msn)) {
452 for (
unsigned int i = 0; i < index; i++) {
453 msn = rentry->getMsn(i);
465 kdWarning(5006) <<
"readFolderIds(): Found serial number zero at index " << index
466 <<
" in folder " << filename << endl;
467 msn = getNextMsgSerNum();
468 Q_ASSERT( msn != 0 );
473 KMMsgDictEntry *entry =
new KMMsgDictEntry( storage.folder(), index);
474 dict->
insert((
long)msn, entry);
475 if (msn >= nextMsgSerNum)
476 nextMsgSerNum = msn + 1;
478 rentry->set(index, entry);
482 GlobalSettings::setMsgDictSizeHint( GlobalSettings::msgDictSizeHint() + count );
492 KMMsgDictREntry *KMMsgDict::openFolderIds(
const FolderStorage& storage,
bool truncate)
494 KMMsgDictREntry *rentry = storage.
rDict();
496 rentry =
new KMMsgDictREntry();
501 TQString filename = getFolderIdsLocation( storage );
502 FILE *fp = truncate ? 0 : fopen(TQFile::encodeName(filename),
"r+");
506 fscanf(fp, IDS_HEADER, &version);
507 if (version == IDS_VERSION)
509 TQ_UINT32 byte_order = 0;
510 fread(&byte_order,
sizeof(byte_order), 1, fp);
511 rentry->swapByteOrder = (byte_order == 0x78563412);
522 fp = fopen(TQFile::encodeName(filename),
"w+");
525 kdDebug(5006) <<
"Dict '" << filename
526 <<
"' cannot open with folder " << storage.
label() <<
": "
527 << strerror(errno) <<
" (" << errno <<
")" << endl;
532 fprintf(fp, IDS_HEADER, IDS_VERSION);
533 TQ_UINT32 byteOrder = 0x12345678;
534 fwrite(&byteOrder,
sizeof(byteOrder), 1, fp);
535 rentry->swapByteOrder =
false;
537 rentry->baseOffset = ftell(fp);
546 int KMMsgDict::writeFolderIds(
const FolderStorage &storage )
548 KMMsgDictREntry *rentry = openFolderIds( storage,
true );
551 FILE *fp = rentry->fp;
553 fseek(fp, rentry->baseOffset, SEEK_SET);
555 TQ_UINT32 count = rentry->getRealSize();
556 if (!fwrite(&count,
sizeof(count), 1, fp)) {
557 kdDebug(5006) <<
"Dict cannot write count with folder " << storage.
label() <<
": "
558 << strerror(errno) <<
" (" << errno <<
")" << endl;
562 for (
unsigned int index = 0; index < count; index++) {
563 TQ_UINT32 msn = rentry->getMsn(index);
564 if (!fwrite(&msn,
sizeof(msn), 1, fp))
567 kdWarning(5006) <<
"writeFolderIds(): Serial number of message at index "
568 << index <<
" is zero in folder " << storage.
label() << endl;
574 off_t eof = ftell(fp);
575 TQString filename = getFolderIdsLocation( storage );
576 truncate(TQFile::encodeName(filename), eof);
585 int KMMsgDict::touchFolderIds(
const FolderStorage &storage )
587 KMMsgDictREntry *rentry = openFolderIds( storage,
false);
598 int KMMsgDict::appendToFolderIds(
FolderStorage& storage,
int index)
600 KMMsgDictREntry *rentry = openFolderIds( storage,
false);
603 FILE *fp = rentry->fp;
607 fseek(fp, rentry->baseOffset, SEEK_SET);
609 if (!fread(&count,
sizeof(count), 1, fp)) {
610 kdDebug(5006) <<
"Dict cannot read count for folder " << storage.
label() <<
": "
611 << strerror(errno) <<
" (" << errno <<
")" << endl;
614 if (rentry->swapByteOrder)
615 count = kmail_swap_32(count);
619 if (rentry->swapByteOrder)
620 count = kmail_swap_32(count);
621 fseek(fp, rentry->baseOffset, SEEK_SET);
622 if (!fwrite(&count,
sizeof(count), 1, fp)) {
623 kdDebug(5006) <<
"Dict cannot write count for folder " << storage.
label() <<
": "
624 << strerror(errno) <<
" (" << errno <<
")" << endl;
628 long ofs = (count - 1) *
sizeof(ulong);
630 fseek(fp, ofs, SEEK_CUR);
632 TQ_UINT32 msn = rentry->getMsn(index);
633 if (rentry->swapByteOrder)
634 msn = kmail_swap_32(msn);
635 if (!fwrite(&msn,
sizeof(msn), 1, fp)) {
636 kdDebug(5006) <<
"Dict cannot write count for folder " << storage.
label() <<
": "
637 << strerror(errno) <<
" (" << errno <<
")" << endl;
652 return storage.
rDict() != 0;
660 TQString filename = getFolderIdsLocation( storage );
661 return unlink( TQFile::encodeName( filename) );
The FolderStorage class is the bass class for the storage related aspects of a collection of mail (a ...
virtual TQString indexLocation() const =0
Returns full path to index file.
void setDirty(bool f)
Change the dirty flag.
TQString label() const
Returns the label of the folder for visualization.
void setRDict(KMMsgDictREntry *rentry) const
Sets the reverse-dictionary for this folder.
KMMsgDictREntry * rDict() const
Returns the reverse-dictionary for this folder.
Class representing items in a KMDict.
KMDict implements a lightweight dictionary with serial numbers as keys.
void remove(long key)
Removes an item.
KMDictItem * find(long key)
Find an item by key.
void insert(long key, KMDictItem *item)
Inserts an item without replacing ones with the same key.
A FolderStorage with an index for faster access to often used message properties.
virtual int find(const KMMsgBase *msg) const
Returns the index of the given message or -1 if not found.
KMMsgBase & toMsgBase()
Get KMMsgBase for this object.
KMail message dictionary.
unsigned long getMsgSerNum(KMFolder *folder, int index) const
Find the message serial number for the message located at index index in folder folder.
static TQValueList< unsigned long > serNumList(TQPtrList< KMMsgBase > msgList)
Convert a list of KMMsgBase pointers to a list of serial numbers.
void getLocation(unsigned long key, KMFolder **retFolder, int *retIndex) const
Returns the folder the message represented by the serial number key is in and the index in that folde...
static const KMMsgDict * instance()
Access the globally unique MessageDict.