kmail Library API Documentation

kmmsgdict.cpp

00001 /* kmail message dictionary */ 00002 /* Author: Ronen Tzur <rtzur@shani.net> */ 00003 00004 #include "kmfolderindex.h" 00005 #include "kmmsgdict.h" 00006 #include "kmdict.h" 00007 00008 #include <qfileinfo.h> 00009 00010 #include <kdebug.h> 00011 00012 #include <stdio.h> 00013 #include <unistd.h> 00014 00015 #include <errno.h> 00016 00017 #include <config.h> 00018 00019 #ifdef HAVE_BYTESWAP_H 00020 #include <byteswap.h> 00021 #endif 00022 00023 // We define functions as kmail_swap_NN so that we don't get compile errors 00024 // on platforms where bswap_NN happens to be a function instead of a define. 00025 00026 /* Swap bytes in 32 bit value. */ 00027 #ifdef bswap_32 00028 #define kmail_swap_32(x) bswap_32(x) 00029 #else 00030 #define kmail_swap_32(x) \ 00031 ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ 00032 (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) 00033 #endif 00034 00035 00036 //----------------------------------------------------------------------------- 00037 00038 // Current version of the .index.ids files 00039 #define IDS_VERSION 1002 00040 00041 // The asterisk at the end is important 00042 #define IDS_HEADER "# KMail-Index-IDs V%d\n*" 00043 00044 //----------------------------------------------------------------------------- 00045 00046 class KMMsgDictEntry : public KMDictItem 00047 { 00048 public: 00049 KMMsgDictEntry(const KMFolder *aFolder, int aIndex) 00050 { folder = aFolder; index = aIndex; } 00051 00052 const KMFolder *folder; 00053 int index; 00054 }; 00055 00056 //----------------------------------------------------------------------------- 00057 00058 class KMMsgDictREntry 00059 { 00060 public: 00061 KMMsgDictREntry(int size = 0) 00062 { 00063 array.resize(size); 00064 for (int i = 0; i < size; i++) 00065 array.at(i) = 0; 00066 fp = 0; 00067 swapByteOrder = false; 00068 baseOffset = 0; 00069 } 00070 00071 ~KMMsgDictREntry() 00072 { 00073 array.resize(0); 00074 if (fp) 00075 fclose(fp); 00076 } 00077 00078 void set(int index, KMMsgDictEntry *entry) 00079 { 00080 if (index >= 0) { 00081 int size = array.size(); 00082 if (index >= size) { 00083 int newsize = QMAX(size + 25, index + 1); 00084 array.resize(newsize); 00085 for (int j = size; j < newsize; j++) 00086 array.at(j) = 0; 00087 } 00088 array.at(index) = entry; 00089 } 00090 } 00091 00092 KMMsgDictEntry *get(int index) 00093 { 00094 if (index >= 0 && (unsigned)index < array.size()) 00095 return array.at(index); 00096 return 0; 00097 } 00098 00099 ulong getMsn(int index) 00100 { 00101 KMMsgDictEntry *entry = get(index); 00102 if (entry) 00103 return entry->key; 00104 return 0; 00105 } 00106 00107 int getRealSize() 00108 { 00109 int count = array.size() - 1; 00110 while (count >= 0) { 00111 if (array.at(count)) 00112 break; 00113 count--; 00114 } 00115 return count + 1; 00116 } 00117 00118 void sync() 00119 { 00120 fflush(fp); 00121 } 00122 00123 public: 00124 QMemArray<KMMsgDictEntry *> array; 00125 FILE *fp; 00126 bool swapByteOrder; 00127 off_t baseOffset; 00128 }; 00129 00130 //----------------------------------------------------------------------------- 00131 00132 KMMsgDict::KMMsgDict() 00133 { 00134 dict = new KMDict(9973); 00135 nextMsgSerNum = 1; 00136 } 00137 00138 //----------------------------------------------------------------------------- 00139 00140 KMMsgDict::~KMMsgDict() 00141 { 00142 delete dict; 00143 } 00144 00145 //----------------------------------------------------------------------------- 00146 00147 unsigned long KMMsgDict::getNextMsgSerNum() { 00148 unsigned long msn = nextMsgSerNum; 00149 nextMsgSerNum++; 00150 return msn; 00151 } 00152 00153 void KMMsgDict::deleteRentry(KMMsgDictREntry *entry) 00154 { 00155 delete entry; 00156 } 00157 00158 //----------------------------------------------------------------------------- 00159 unsigned long KMMsgDict::insert(unsigned long msn, const KMMessage * msg, int idx ) { 00160 return insert( msn, &msg->toMsgBase(), idx ); 00161 } 00162 00163 00164 unsigned long KMMsgDict::insert(unsigned long msgSerNum, 00165 const KMMsgBase *msg, int index) 00166 { 00167 unsigned long msn = msgSerNum; 00168 if (!msn) { 00169 msn = getNextMsgSerNum(); 00170 } else { 00171 if (msn >= nextMsgSerNum) 00172 nextMsgSerNum = msn + 1; 00173 } 00174 00175 KMFolderIndex *folder = msg->parent(); 00176 if (folder && index == -1) 00177 index = folder->find(msg); 00178 00179 // Should not happen, indicates id file corruption 00180 while (dict->find((long)msn)) { 00181 msn = getNextMsgSerNum(); 00182 folder->setDirty( true ); // rewrite id file 00183 } 00184 00185 // Should not happen, indicates id file corruption 00186 while (dict->find((long)msn)) { 00187 msn = getNextMsgSerNum(); 00188 folder->setDirty( true ); // rewrite id file 00189 } 00190 00191 KMMsgDictEntry *entry = new KMMsgDictEntry(folder, index); 00192 dict->replace((long)msn, entry); 00193 00194 KMMsgDictREntry *rentry = folder->rDict(); 00195 if (!rentry) { 00196 rentry = new KMMsgDictREntry(); 00197 folder->setRDict(rentry); 00198 } 00199 rentry->set(index, entry); 00200 00201 return msn; 00202 } 00203 00204 unsigned long KMMsgDict::insert(const KMMsgBase *msg, int index) 00205 { 00206 unsigned long msn = msg->getMsgSerNum(); 00207 return insert(msn, msg, index); 00208 } 00209 00210 //----------------------------------------------------------------------------- 00211 00212 void KMMsgDict::remove(unsigned long msgSerNum) 00213 { 00214 long key = (long)msgSerNum; 00215 KMMsgDictEntry *entry = (KMMsgDictEntry *)dict->find(key); 00216 if (!entry) 00217 return; 00218 00219 if (entry->folder) { 00220 KMMsgDictREntry *rentry = entry->folder->rDict(); 00221 if (rentry) 00222 rentry->set(entry->index, 0); 00223 } 00224 00225 dict->remove((long)key); 00226 } 00227 00228 unsigned long KMMsgDict::remove(const KMMsgBase *msg) 00229 { 00230 unsigned long msn = msg->getMsgSerNum(); 00231 remove(msn); 00232 return msn; 00233 } 00234 00235 //----------------------------------------------------------------------------- 00236 00237 void KMMsgDict::update(const KMMsgBase *msg, int index, int newIndex) 00238 { 00239 KMMsgDictREntry *rentry = msg->parent()->rDict(); 00240 if (rentry) { 00241 KMMsgDictEntry *entry = rentry->get(index); 00242 if (entry) { 00243 entry->index = newIndex; 00244 rentry->set(index, 0); 00245 rentry->set(newIndex, entry); 00246 } 00247 } 00248 } 00249 00250 //----------------------------------------------------------------------------- 00251 00252 void KMMsgDict::getLocation(unsigned long key, 00253 KMFolder **retFolder, int *retIndex) 00254 { 00255 KMMsgDictEntry *entry = (KMMsgDictEntry *)dict->find((long)key); 00256 if (entry) { 00257 *retFolder = (KMFolder *)entry->folder; 00258 *retIndex = entry->index; 00259 } else { 00260 *retFolder = 0; 00261 *retIndex = -1; 00262 } 00263 } 00264 00265 void KMMsgDict::getLocation(const KMMsgBase *msg, 00266 KMFolder **retFolder, int *retIndex) 00267 { 00268 getLocation(msg->getMsgSerNum(), retFolder, retIndex); 00269 } 00270 00271 void KMMsgDict::getLocation( const KMMessage * msg, KMFolder * *retFolder, int * retIndex ) { 00272 getLocation( msg->toMsgBase().getMsgSerNum(), retFolder, retIndex ); 00273 } 00274 00275 //----------------------------------------------------------------------------- 00276 00277 unsigned long KMMsgDict::getMsgSerNum(KMFolder *folder, int index) 00278 { 00279 unsigned long msn = 0; 00280 KMMsgDictREntry *rentry = folder->rDict(); 00281 if (rentry) 00282 msn = rentry->getMsn(index); 00283 return msn; 00284 } 00285 00286 //----------------------------------------------------------------------------- 00287 00288 QString KMMsgDict::getFolderIdsLocation(const KMFolder *folder) 00289 { 00290 return folder->indexLocation() + ".ids"; 00291 } 00292 00293 //----------------------------------------------------------------------------- 00294 00295 bool KMMsgDict::isFolderIdsOutdated(const KMFolder *folder) 00296 { 00297 bool outdated = false; 00298 00299 QFileInfo indexInfo(folder->indexLocation()); 00300 QFileInfo idsInfo(getFolderIdsLocation(folder)); 00301 00302 if (!indexInfo.exists() || !idsInfo.exists()) 00303 outdated = true; 00304 if (indexInfo.lastModified() > idsInfo.lastModified()) 00305 outdated = true; 00306 00307 return outdated; 00308 } 00309 00310 //----------------------------------------------------------------------------- 00311 00312 int KMMsgDict::readFolderIds(KMFolder *folder) 00313 { 00314 if (isFolderIdsOutdated(folder)) 00315 return -1; 00316 00317 QString filename = getFolderIdsLocation(folder); 00318 FILE *fp = fopen(QFile::encodeName(filename), "r+"); 00319 if (!fp) 00320 return -1; 00321 00322 int version = 0; 00323 fscanf(fp, IDS_HEADER, &version); 00324 if (version != IDS_VERSION) { 00325 fclose(fp); 00326 return -1; 00327 } 00328 00329 bool swapByteOrder; 00330 Q_UINT32 byte_order; 00331 if (!fread(&byte_order, sizeof(byte_order), 1, fp)) { 00332 fclose(fp); 00333 return -1; 00334 } 00335 swapByteOrder = (byte_order == 0x78563412); 00336 00337 Q_UINT32 count; 00338 if (!fread(&count, sizeof(count), 1, fp)) { 00339 fclose(fp); 00340 return -1; 00341 } 00342 if (swapByteOrder) 00343 count = kmail_swap_32(count); 00344 00345 KMMsgDictREntry *rentry = new KMMsgDictREntry(count); 00346 00347 for (unsigned int index = 0; index < count; index++) { 00348 Q_UINT32 msn; 00349 00350 bool readOk = fread(&msn, sizeof(msn), 1, fp); 00351 if (swapByteOrder) 00352 msn = kmail_swap_32(msn); 00353 00354 if (!readOk || dict->find(msn)) { 00355 for (unsigned int i = 0; i < index; i++) { 00356 msn = rentry->getMsn(i); 00357 dict->remove((long)msn); 00358 } 00359 delete rentry; 00360 fclose(fp); 00361 return -1; 00362 } 00363 00364 //if (!msn) 00365 //kdDebug(5006) << "Dict found zero serial number in folder " << folder->label() << endl; 00366 00367 KMMsgDictEntry *entry = new KMMsgDictEntry(folder, index); 00368 dict->replace((long)msn, entry); 00369 if (msn >= nextMsgSerNum) 00370 nextMsgSerNum = msn + 1; 00371 00372 rentry->set(index, entry); 00373 } 00374 00375 fclose(fp); 00376 folder->setRDict(rentry); 00377 00378 return 0; 00379 } 00380 00381 //----------------------------------------------------------------------------- 00382 00383 KMMsgDictREntry *KMMsgDict::openFolderIds(KMFolder *folder, bool truncate) 00384 { 00385 KMMsgDictREntry *rentry = folder->rDict(); 00386 if (!rentry) { 00387 rentry = new KMMsgDictREntry(); 00388 folder->setRDict(rentry); 00389 } 00390 00391 if (!rentry->fp) { 00392 QString filename = getFolderIdsLocation(folder); 00393 FILE *fp = truncate ? 0 : fopen(QFile::encodeName(filename), "r+"); 00394 if (fp) 00395 { 00396 int version = 0; 00397 fscanf(fp, IDS_HEADER, &version); 00398 if (version == IDS_VERSION) 00399 { 00400 Q_UINT32 byte_order = 0; 00401 fread(&byte_order, sizeof(byte_order), 1, fp); 00402 rentry->swapByteOrder = (byte_order == 0x78563412); 00403 } 00404 else 00405 { 00406 fclose(fp); 00407 fp = 0; 00408 } 00409 } 00410 00411 if (!fp) 00412 { 00413 fp = fopen(QFile::encodeName(filename), "w+"); 00414 if (!fp) 00415 { 00416 kdDebug(5006) << "Dict '" << filename 00417 << "' cannot open with folder " << folder->label() << ": " 00418 << strerror(errno) << " (" << errno << ")" << endl; 00419 delete rentry; 00420 rentry = 0; 00421 return 0; 00422 } 00423 fprintf(fp, IDS_HEADER, IDS_VERSION); 00424 Q_UINT32 byteOrder = 0x12345678; 00425 fwrite(&byteOrder, sizeof(byteOrder), 1, fp); 00426 rentry->swapByteOrder = false; 00427 } 00428 rentry->baseOffset = ftell(fp); 00429 rentry->fp = fp; 00430 } 00431 00432 return rentry; 00433 } 00434 00435 //----------------------------------------------------------------------------- 00436 00437 int KMMsgDict::writeFolderIds(KMFolder *folder) 00438 { 00439 KMMsgDictREntry *rentry = openFolderIds(folder, true); 00440 if (!rentry) 00441 return 0; 00442 FILE *fp = rentry->fp; 00443 00444 fseek(fp, rentry->baseOffset, SEEK_SET); 00445 // kdDebug(5006) << "Dict writing for folder " << folder->label() << endl; 00446 Q_UINT32 count = rentry->getRealSize(); 00447 if (!fwrite(&count, sizeof(count), 1, fp)) { 00448 kdDebug(5006) << "Dict cannot write count with folder " << folder->label() << ": " 00449 << strerror(errno) << " (" << errno << ")" << endl; 00450 return -1; 00451 } 00452 00453 for (unsigned int index = 0; index < count; index++) { 00454 Q_UINT32 msn = rentry->getMsn(index); 00455 if (!fwrite(&msn, sizeof(msn), 1, fp)) 00456 return -1; 00457 } 00458 00459 rentry->sync(); 00460 00461 off_t eof = ftell(fp); 00462 QString filename = getFolderIdsLocation(folder); 00463 truncate(QFile::encodeName(filename), eof); 00464 fclose(rentry->fp); 00465 rentry->fp = 0; 00466 00467 return 0; 00468 } 00469 00470 //----------------------------------------------------------------------------- 00471 00472 int KMMsgDict::touchFolderIds(KMFolder *folder) 00473 { 00474 KMMsgDictREntry *rentry = openFolderIds(folder, false); 00475 if (rentry) { 00476 rentry->sync(); 00477 fclose(rentry->fp); 00478 rentry->fp = 0; 00479 } 00480 return 0; 00481 } 00482 00483 //----------------------------------------------------------------------------- 00484 00485 int KMMsgDict::appendtoFolderIds(KMFolder *folder, int index) 00486 { 00487 KMMsgDictREntry *rentry = openFolderIds(folder, false); 00488 if (!rentry) 00489 return 0; 00490 FILE *fp = rentry->fp; 00491 00492 // kdDebug(5006) << "Dict appending for folder " << folder->label() << endl; 00493 00494 fseek(fp, rentry->baseOffset, SEEK_SET); 00495 Q_UINT32 count; 00496 if (!fread(&count, sizeof(count), 1, fp)) { 00497 kdDebug(5006) << "Dict cannot read count for folder " << folder->label() << ": " 00498 << strerror(errno) << " (" << errno << ")" << endl; 00499 return 0; 00500 } 00501 if (rentry->swapByteOrder) 00502 count = kmail_swap_32(count); 00503 00504 count++; 00505 00506 if (rentry->swapByteOrder) 00507 count = kmail_swap_32(count); 00508 fseek(fp, rentry->baseOffset, SEEK_SET); 00509 if (!fwrite(&count, sizeof(count), 1, fp)) { 00510 kdDebug(5006) << "Dict cannot write count for folder " << folder->label() << ": " 00511 << strerror(errno) << " (" << errno << ")" << endl; 00512 return 0; 00513 } 00514 00515 long ofs = (count - 1) * sizeof(ulong); 00516 if (ofs > 0) 00517 fseek(fp, ofs, SEEK_CUR); 00518 00519 Q_UINT32 msn = rentry->getMsn(index); 00520 if (rentry->swapByteOrder) 00521 msn = kmail_swap_32(msn); 00522 if (!fwrite(&msn, sizeof(msn), 1, fp)) { 00523 kdDebug(5006) << "Dict cannot write count for folder " << folder->label() << ": " 00524 << strerror(errno) << " (" << errno << ")" << endl; 00525 return 0; 00526 } 00527 00528 rentry->sync(); 00529 fclose(rentry->fp); 00530 rentry->fp = 0; 00531 00532 return 0; 00533 } 00534 00535 //----------------------------------------------------------------------------- 00536 00537 bool KMMsgDict::hasFolderIds(const KMFolder *folder) 00538 { 00539 return folder->rDict() != 0; 00540 } 00541 00542 //----------------------------------------------------------------------------- 00543 00544 bool KMMsgDict::removeFolderIds(KMFolder *folder) 00545 { 00546 folder->setRDict(0); 00547 QString filename = getFolderIdsLocation(folder); 00548 return unlink(QFile::encodeName(filename)); 00549 }
KDE Logo
This file is part of the documentation for kmail Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jul 28 23:58:03 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003