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) );
void setDirty(bool f)
Change the dirty flag.
A FolderStorage with an index for faster access to often used message properties. ...
KMMsgBase & toMsgBase()
Get KMMsgBase for this object.
static const KMMsgDict * instance()
Access the globally unique MessageDict.
Class representing items in a KMDict.
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...
TQString label() const
Returns the label of the folder for visualization.
KMDictItem * find(long key)
Find an item by key.
KMMsgDictREntry * rDict() const
Returns the reverse-dictionary for this folder.
void setRDict(KMMsgDictREntry *rentry) const
Sets the reverse-dictionary for this folder.
void remove(long key)
Removes an item.
void insert(long key, KMDictItem *item)
Inserts an item without replacing ones with the same key.
unsigned long getMsgSerNum(KMFolder *folder, int index) const
Find the message serial number for the message located at index index in folder folder.
virtual TQString indexLocation() const =0
Returns full path to index file.
The FolderStorage class is the bass class for the storage related aspects of a collection of mail (a ...
KMDict implements a lightweight dictionary with serial numbers as keys.
virtual int find(const KMMsgBase *msg) const
Returns the index of the given message or -1 if not found.
KMail message dictionary.