kmmsgbase.cpp
00001 // kmmsgbase.cpp 00002 00003 #include <config.h> 00004 00005 #include "globalsettings.h" 00006 #include "kmmsgbase.h" 00007 00008 #include "kmfolderindex.h" 00009 #include "kmfolder.h" 00010 #include "kmheaders.h" 00011 #include "kmmsgdict.h" 00012 #include "messageproperty.h" 00013 using KMail::MessageProperty; 00014 00015 #include <kdebug.h> 00016 #include <tdeglobal.h> 00017 #include <kcharsets.h> 00018 #include <kasciistringtools.h> 00019 #include <kmdcodec.h> 00020 #include <krfcdate.h> 00021 00022 #include <mimelib/mimepp.h> 00023 #include <kmime_codecs.h> 00024 00025 #include <tqtextcodec.h> 00026 #include <tqdeepcopy.h> 00027 #include <tqregexp.h> 00028 00029 #include <ctype.h> 00030 #include <stdlib.h> 00031 #include <unistd.h> 00032 00033 #ifdef HAVE_BYTESWAP_H 00034 #include <byteswap.h> 00035 #endif 00036 00037 // We define functions as kmail_swap_NN so that we don't get compile errors 00038 // on platforms where bswap_NN happens to be a function instead of a define. 00039 00040 /* Swap bytes in 16 bit value. */ 00041 #ifdef bswap_16 00042 #define kmail_swap_16(x) bswap_16(x) 00043 #else 00044 #define kmail_swap_16(x) \ 00045 ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)) 00046 #endif 00047 00048 /* Swap bytes in 32 bit value. */ 00049 #ifdef bswap_32 00050 #define kmail_swap_32(x) bswap_32(x) 00051 #else 00052 #define kmail_swap_32(x) \ 00053 ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ 00054 (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) 00055 #endif 00056 00057 /* Swap bytes in 64 bit value. */ 00058 #ifdef bswap_64 00059 #define kmail_swap_64(x) bswap_64(x) 00060 #else 00061 #define kmail_swap_64(x) \ 00062 ((((x) & 0xff00000000000000ull) >> 56) \ 00063 | (((x) & 0x00ff000000000000ull) >> 40) \ 00064 | (((x) & 0x0000ff0000000000ull) >> 24) \ 00065 | (((x) & 0x000000ff00000000ull) >> 8) \ 00066 | (((x) & 0x00000000ff000000ull) << 8) \ 00067 | (((x) & 0x0000000000ff0000ull) << 24) \ 00068 | (((x) & 0x000000000000ff00ull) << 40) \ 00069 | (((x) & 0x00000000000000ffull) << 56)) 00070 #endif 00071 00072 //----------------------------------------------------------------------------- 00073 KMMsgBase::KMMsgBase(KMFolder* aParentFolder) 00074 : mParent( aParentFolder ), mIndexOffset( 0 ), 00075 mIndexLength( 0 ), mDirty( false ), mEnableUndo( false ), mStatus( KMMsgStatusUnknown ) 00076 { 00077 } 00078 00079 00080 //----------------------------------------------------------------------------- 00081 KMMsgBase::~KMMsgBase() 00082 { 00083 MessageProperty::forget( this ); 00084 } 00085 00086 KMFolderIndex* KMMsgBase::storage() const 00087 { 00088 // TODO: How did this ever work? What about KMFolderSearch that does 00089 // not inherit KMFolderIndex? 00090 if( mParent ) 00091 return static_cast<KMFolderIndex*>( mParent->storage() ); 00092 return 0; 00093 } 00094 00095 //----------------------------------------------------------------------------- 00096 void KMMsgBase::assign(const KMMsgBase* other) 00097 { 00098 mParent = other->mParent; 00099 mDirty = other->mDirty; 00100 mIndexOffset = other->mIndexOffset; 00101 mIndexLength = other->mIndexLength; 00102 } 00103 00104 //----------------------------------------------------------------------------- 00105 KMMsgBase& KMMsgBase::operator=(const KMMsgBase& other) 00106 { 00107 assign(&other); 00108 return *this; 00109 } 00110 00111 00112 //---------------------------------------------------------------------------- 00113 KMMsgBase::KMMsgBase( const KMMsgBase& other ) 00114 { 00115 assign( &other ); 00116 } 00117 00118 //----------------------------------------------------------------------------- 00119 bool KMMsgBase::isMessage(void) const 00120 { 00121 return false; 00122 } 00123 //----------------------------------------------------------------------------- 00124 void KMMsgBase::toggleStatus(const KMMsgStatus aStatus, int idx) 00125 { 00126 mDirty = true; 00127 KMMsgStatus oldStatus = status(); 00128 if ( status() & aStatus ) { 00129 mStatus &= ~aStatus; 00130 } else { 00131 mStatus |= aStatus; 00132 // Ignored and Watched are toggleable, yet mutually exclusive. 00133 // That is an arbitrary restriction on my part. HAR HAR HAR :) -till 00134 if (aStatus == KMMsgStatusWatched) 00135 mStatus &= ~KMMsgStatusIgnored; 00136 if (aStatus == KMMsgStatusIgnored) 00137 mStatus &= ~KMMsgStatusWatched; 00138 if (aStatus == KMMsgStatusSpam) 00139 mStatus &= ~KMMsgStatusHam; 00140 if (aStatus == KMMsgStatusHam) 00141 mStatus &= ~KMMsgStatusSpam; 00142 } 00143 if (storage()) { 00144 if (idx < 0) 00145 idx = storage()->find( this ); 00146 storage()->msgStatusChanged( oldStatus, status(), idx ); 00147 storage()->headerOfMsgChanged(this, idx); 00148 } 00149 00150 } 00151 00152 //----------------------------------------------------------------------------- 00153 void KMMsgBase::setStatus(const KMMsgStatus aStatus, int idx) 00154 { 00155 mDirty = true; 00156 KMMsgStatus oldStatus = status(); 00157 switch (aStatus) { 00158 case KMMsgStatusRead: 00159 // Unset unread and new, set read 00160 mStatus &= ~KMMsgStatusUnread; 00161 mStatus &= ~KMMsgStatusNew; 00162 mStatus |= KMMsgStatusRead; 00163 break; 00164 00165 case KMMsgStatusUnread: 00166 // unread overrides read 00167 mStatus &= ~KMMsgStatusOld; 00168 mStatus &= ~KMMsgStatusRead; 00169 mStatus &= ~KMMsgStatusNew; 00170 mStatus |= KMMsgStatusUnread; 00171 break; 00172 00173 case KMMsgStatusOld: 00174 // old can't be new or unread 00175 mStatus &= ~KMMsgStatusNew; 00176 mStatus &= ~KMMsgStatusUnread; 00177 mStatus |= KMMsgStatusOld; 00178 break; 00179 00180 case KMMsgStatusNew: 00181 // new overrides old and read 00182 mStatus &= ~KMMsgStatusOld; 00183 mStatus &= ~KMMsgStatusRead; 00184 mStatus &= ~KMMsgStatusUnread; 00185 mStatus |= KMMsgStatusNew; 00186 break; 00187 00188 case KMMsgStatusDeleted: 00189 mStatus |= KMMsgStatusDeleted; 00190 break; 00191 00192 case KMMsgStatusReplied: 00193 mStatus |= KMMsgStatusReplied; 00194 break; 00195 00196 case KMMsgStatusForwarded: 00197 mStatus |= KMMsgStatusForwarded; 00198 break; 00199 00200 case KMMsgStatusQueued: 00201 mStatus |= KMMsgStatusQueued; 00202 break; 00203 00204 case KMMsgStatusTodo: 00205 mStatus |= KMMsgStatusTodo; 00206 break; 00207 00208 case KMMsgStatusSent: 00209 mStatus &= ~KMMsgStatusQueued; 00210 mStatus &= ~KMMsgStatusUnread; 00211 mStatus &= ~KMMsgStatusNew; 00212 mStatus |= KMMsgStatusSent; 00213 break; 00214 00215 case KMMsgStatusFlag: 00216 mStatus |= KMMsgStatusFlag; 00217 break; 00218 00219 // Watched and ignored are mutually exclusive 00220 case KMMsgStatusWatched: 00221 mStatus &= ~KMMsgStatusIgnored; 00222 mStatus |= KMMsgStatusWatched; 00223 break; 00224 00225 case KMMsgStatusIgnored: 00226 mStatus &= ~KMMsgStatusWatched; 00227 mStatus |= KMMsgStatusIgnored; 00228 break; 00229 // as are ham and spam 00230 case KMMsgStatusSpam: 00231 mStatus &= ~KMMsgStatusHam; 00232 mStatus |= KMMsgStatusSpam; 00233 break; 00234 case KMMsgStatusHam: 00235 mStatus &= ~KMMsgStatusSpam; 00236 mStatus |= KMMsgStatusHam; 00237 break; 00238 case KMMsgStatusHasAttach: 00239 mStatus &= ~KMMsgStatusHasNoAttach; 00240 mStatus |= KMMsgStatusHasAttach; 00241 break; 00242 case KMMsgStatusHasNoAttach: 00243 mStatus &= ~KMMsgStatusHasAttach; 00244 mStatus |= KMMsgStatusHasNoAttach; 00245 break; 00246 case KMMsgStatusHasInvitation: 00247 mStatus &= ~KMMsgStatusHasNoInvitation; 00248 mStatus |= KMMsgStatusHasInvitation; 00249 break; 00250 case KMMsgStatusHasNoInvitation: 00251 mStatus &= ~KMMsgStatusHasInvitation; 00252 mStatus |= KMMsgStatusHasNoInvitation; 00253 break; 00254 default: 00255 mStatus = aStatus; 00256 break; 00257 } 00258 00259 if ( oldStatus != mStatus && storage() ) { 00260 if (idx < 0) 00261 idx = storage()->find( this ); 00262 storage()->msgStatusChanged( oldStatus, status(), idx ); 00263 storage()->headerOfMsgChanged( this, idx ); 00264 } 00265 } 00266 00267 00268 00269 //----------------------------------------------------------------------------- 00270 void KMMsgBase::setStatus(const char* aStatusStr, const char* aXStatusStr) 00271 { 00272 // first try to find status from "X-Status" field if given 00273 if (aXStatusStr) { 00274 if (strchr(aXStatusStr, 'N')) setStatus(KMMsgStatusNew); 00275 if (strchr(aXStatusStr, 'U')) setStatus(KMMsgStatusUnread); 00276 if (strchr(aXStatusStr, 'O')) setStatus(KMMsgStatusOld); 00277 if (strchr(aXStatusStr, 'R')) setStatus(KMMsgStatusRead); 00278 if (strchr(aXStatusStr, 'D')) setStatus(KMMsgStatusDeleted); 00279 if (strchr(aXStatusStr, 'A')) setStatus(KMMsgStatusReplied); 00280 if (strchr(aXStatusStr, 'F')) setStatus(KMMsgStatusForwarded); 00281 if (strchr(aXStatusStr, 'Q')) setStatus(KMMsgStatusQueued); 00282 if (strchr(aXStatusStr, 'K')) setStatus(KMMsgStatusTodo); 00283 if (strchr(aXStatusStr, 'S')) setStatus(KMMsgStatusSent); 00284 if (strchr(aXStatusStr, 'G')) setStatus(KMMsgStatusFlag); 00285 if (strchr(aXStatusStr, 'P')) setStatus(KMMsgStatusSpam); 00286 if (strchr(aXStatusStr, 'H')) setStatus(KMMsgStatusHam); 00287 if (strchr(aXStatusStr, 'T')) setStatus(KMMsgStatusHasAttach); 00288 if (strchr(aXStatusStr, 'C')) setStatus(KMMsgStatusHasNoAttach); 00289 } 00290 00291 // Merge the contents of the "Status" field 00292 if (aStatusStr) { 00293 if ((aStatusStr[0]== 'R' && aStatusStr[1]== 'O') || 00294 (aStatusStr[0]== 'O' && aStatusStr[1]== 'R')) { 00295 setStatus( KMMsgStatusOld ); 00296 setStatus( KMMsgStatusRead ); 00297 } 00298 else if (aStatusStr[0] == 'R') 00299 setStatus(KMMsgStatusRead); 00300 else if (aStatusStr[0] == 'D') 00301 setStatus(KMMsgStatusDeleted); 00302 else 00303 setStatus(KMMsgStatusNew); 00304 } 00305 } 00306 00307 00308 void KMMsgBase::setEncryptionState( const KMMsgEncryptionState /*status*/, int idx ) 00309 { 00310 //kdDebug(5006) << "***setEncryptionState1( " << status << " )" << endl; 00311 mDirty = true; 00312 if (storage()) 00313 storage()->headerOfMsgChanged(this, idx); 00314 } 00315 00316 void KMMsgBase::setEncryptionStateChar( TQChar status, int idx ) 00317 { 00318 //kdDebug(5006) << "***setEncryptionState2( " << (status.isNull() ? '?' : status.latin1()) << " )" << endl; 00319 00320 if( status.latin1() == (char)KMMsgEncryptionStateUnknown ) 00321 setEncryptionState( KMMsgEncryptionStateUnknown, idx ); 00322 else if( status.latin1() == (char)KMMsgNotEncrypted ) 00323 setEncryptionState( KMMsgNotEncrypted, idx ); 00324 else if( status.latin1() == (char)KMMsgPartiallyEncrypted ) 00325 setEncryptionState( KMMsgPartiallyEncrypted, idx ); 00326 else if( status.latin1() == (char)KMMsgFullyEncrypted ) 00327 setEncryptionState( KMMsgFullyEncrypted, idx ); 00328 else 00329 setEncryptionState( KMMsgEncryptionStateUnknown, idx ); 00330 } 00331 00332 00333 void KMMsgBase::setSignatureState( const KMMsgSignatureState /*status*/, int idx ) 00334 { 00335 //kdDebug(5006) << "***setSignatureState1( " << status << " )" << endl; 00336 mDirty = true; 00337 if (storage()) 00338 storage()->headerOfMsgChanged(this, idx); 00339 } 00340 00341 void KMMsgBase::setMDNSentState( KMMsgMDNSentState, int idx ) { 00342 mDirty = true; 00343 if ( storage() ) 00344 storage()->headerOfMsgChanged(this, idx); 00345 } 00346 00347 void KMMsgBase::setSignatureStateChar( TQChar status, int idx ) 00348 { 00349 //kdDebug(5006) << "***setSignatureState2( " << (status.isNull() ? '?' : status.latin1()) << " )" << endl; 00350 00351 if( status.latin1() == (char)KMMsgSignatureStateUnknown ) 00352 setSignatureState( KMMsgSignatureStateUnknown, idx ); 00353 else if( status.latin1() == (char)KMMsgNotSigned ) 00354 setSignatureState( KMMsgNotSigned, idx ); 00355 else if( status.latin1() == (char)KMMsgPartiallySigned ) 00356 setSignatureState( KMMsgPartiallySigned,idx ); 00357 else if( status.latin1() == (char)KMMsgFullySigned ) 00358 setSignatureState( KMMsgFullySigned, idx ); 00359 else 00360 setSignatureState( KMMsgSignatureStateUnknown, idx ); 00361 } 00362 00363 //----------------------------------------------------------------------------- 00364 bool KMMsgBase::isUnread(void) const 00365 { 00366 KMMsgStatus st = status(); 00367 return (st & KMMsgStatusUnread && !(st & KMMsgStatusIgnored)); 00368 } 00369 00370 //----------------------------------------------------------------------------- 00371 bool KMMsgBase::isNew(void) const 00372 { 00373 KMMsgStatus st = status(); 00374 return (st & KMMsgStatusNew && !(st & KMMsgStatusIgnored)); 00375 } 00376 00377 //----------------------------------------------------------------------------- 00378 bool KMMsgBase::isOfUnknownStatus(void) const 00379 { 00380 KMMsgStatus st = status(); 00381 return (st == KMMsgStatusUnknown); 00382 } 00383 00384 //----------------------------------------------------------------------------- 00385 bool KMMsgBase::isOld(void) const 00386 { 00387 KMMsgStatus st = status(); 00388 return (st & KMMsgStatusOld); 00389 } 00390 00391 //----------------------------------------------------------------------------- 00392 bool KMMsgBase::isRead(void) const 00393 { 00394 KMMsgStatus st = status(); 00395 return (st & KMMsgStatusRead || st & KMMsgStatusIgnored); 00396 } 00397 00398 //----------------------------------------------------------------------------- 00399 bool KMMsgBase::isDeleted(void) const 00400 { 00401 KMMsgStatus st = status(); 00402 return (st & KMMsgStatusDeleted); 00403 } 00404 00405 //----------------------------------------------------------------------------- 00406 bool KMMsgBase::isReplied(void) const 00407 { 00408 KMMsgStatus st = status(); 00409 return (st & KMMsgStatusReplied); 00410 } 00411 00412 //----------------------------------------------------------------------------- 00413 bool KMMsgBase::isForwarded(void) const 00414 { 00415 KMMsgStatus st = status(); 00416 return (st & KMMsgStatusForwarded); 00417 } 00418 00419 //----------------------------------------------------------------------------- 00420 bool KMMsgBase::isQueued(void) const 00421 { 00422 KMMsgStatus st = status(); 00423 return (st & KMMsgStatusQueued); 00424 } 00425 00426 //----------------------------------------------------------------------------- 00427 bool KMMsgBase::isTodo(void) const 00428 { 00429 KMMsgStatus st = status(); 00430 return (st & KMMsgStatusTodo); 00431 } 00432 00433 //----------------------------------------------------------------------------- 00434 bool KMMsgBase::isSent(void) const 00435 { 00436 KMMsgStatus st = status(); 00437 return (st & KMMsgStatusSent); 00438 } 00439 00440 //----------------------------------------------------------------------------- 00441 bool KMMsgBase::isImportant(void) const 00442 { 00443 KMMsgStatus st = status(); 00444 return (st & KMMsgStatusFlag); 00445 } 00446 00447 //----------------------------------------------------------------------------- 00448 bool KMMsgBase::isWatched(void) const 00449 { 00450 KMMsgStatus st = status(); 00451 return (st & KMMsgStatusWatched); 00452 } 00453 00454 //----------------------------------------------------------------------------- 00455 bool KMMsgBase::isIgnored(void) const 00456 { 00457 KMMsgStatus st = status(); 00458 return (st & KMMsgStatusIgnored); 00459 } 00460 00461 //----------------------------------------------------------------------------- 00462 bool KMMsgBase::isSpam(void) const 00463 { 00464 KMMsgStatus st = status(); 00465 return (st & KMMsgStatusSpam); 00466 } 00467 00468 //----------------------------------------------------------------------------- 00469 bool KMMsgBase::isHam(void) const 00470 { 00471 KMMsgStatus st = status(); 00472 return (st & KMMsgStatusHam); 00473 } 00474 00475 //----------------------------------------------------------------------------- 00476 TQCString KMMsgBase::statusToStr(const KMMsgStatus status) 00477 { 00478 TQCString sstr; 00479 if (status & KMMsgStatusNew) sstr += 'N'; 00480 if (status & KMMsgStatusUnread) sstr += 'U'; 00481 if (status & KMMsgStatusOld) sstr += 'O'; 00482 if (status & KMMsgStatusRead) sstr += 'R'; 00483 if (status & KMMsgStatusDeleted) sstr += 'D'; 00484 if (status & KMMsgStatusReplied) sstr += 'A'; 00485 if (status & KMMsgStatusForwarded) sstr += 'F'; 00486 if (status & KMMsgStatusQueued) sstr += 'Q'; 00487 if (status & KMMsgStatusTodo) sstr += 'K'; 00488 if (status & KMMsgStatusSent) sstr += 'S'; 00489 if (status & KMMsgStatusFlag) sstr += 'G'; 00490 if (status & KMMsgStatusWatched) sstr += 'W'; 00491 if (status & KMMsgStatusIgnored) sstr += 'I'; 00492 if (status & KMMsgStatusSpam) sstr += 'P'; 00493 if (status & KMMsgStatusHam) sstr += 'H'; 00494 if (status & KMMsgStatusHasAttach) sstr += 'T'; 00495 if (status & KMMsgStatusHasNoAttach) sstr += 'C'; 00496 00497 return sstr; 00498 } 00499 00500 //----------------------------------------------------------------------------- 00501 TQString KMMsgBase::statusToSortRank() 00502 { 00503 TQString sstr = "bcbbbbbbbb"; 00504 00505 // put watched ones first, then normal ones, ignored ones last 00506 if (status() & KMMsgStatusWatched) sstr[0] = 'a'; 00507 if (status() & KMMsgStatusIgnored) sstr[0] = 'c'; 00508 00509 // Second level. One of new, old, read, unread 00510 if (status() & KMMsgStatusNew) sstr[1] = 'a'; 00511 if (status() & KMMsgStatusUnread) sstr[1] = 'b'; 00512 //if (status() & KMMsgStatusOld) sstr[1] = 'c'; 00513 //if (status() & KMMsgStatusRead) sstr[1] = 'c'; 00514 00515 // Third level. In somewhat arbitrary order. 00516 if (status() & KMMsgStatusDeleted) sstr[2] = 'a'; 00517 if (status() & KMMsgStatusFlag) sstr[3] = 'a'; 00518 if (status() & KMMsgStatusReplied) sstr[4] = 'a'; 00519 if (status() & KMMsgStatusForwarded) sstr[5] = 'a'; 00520 if (status() & KMMsgStatusQueued) sstr[6] = 'a'; 00521 if (status() & KMMsgStatusSent) sstr[7] = 'a'; 00522 if (status() & KMMsgStatusHam) sstr[8] = 'a'; 00523 if (status() & KMMsgStatusSpam) sstr[8] = 'c'; 00524 if (status() & KMMsgStatusTodo) sstr[9] = 'a'; 00525 00526 return sstr; 00527 } 00528 00529 00530 //----------------------------------------------------------------------------- 00531 void KMMsgBase::setDate(const TQCString& aDateStr) 00532 { 00533 setDate( KRFCDate::parseDate( aDateStr ) ); 00534 } 00535 00536 00537 //----------------------------------------------------------------------------- 00538 TQString KMMsgBase::dateStr(void) const 00539 { 00540 time_t d = date(); 00541 return KMime::DateFormatter::formatDate(KMime::DateFormatter::Fancy, d); 00542 } 00543 00544 00545 //----------------------------------------------------------------------------- 00546 TQString KMMsgBase::skipKeyword(const TQString& aStr, TQChar sepChar, 00547 bool* hasKeyword) 00548 { 00549 unsigned int i = 0, maxChars = 3; 00550 TQString str = aStr; 00551 00552 while (str[0] == ' ') str.remove(0,1); 00553 if (hasKeyword) *hasKeyword=false; 00554 00555 unsigned int strLength(str.length()); 00556 for (i=0; i < strLength && i < maxChars; i++) 00557 { 00558 if (str[i] < 'A' || str[i] == sepChar) break; 00559 } 00560 00561 if (str[i] == sepChar) // skip following spaces too 00562 { 00563 do { 00564 i++; 00565 } while (str[i] == ' '); 00566 if (hasKeyword) *hasKeyword=true; 00567 return str.mid(i); 00568 } 00569 return str; 00570 } 00571 00572 00573 //----------------------------------------------------------------------------- 00574 const TQTextCodec* KMMsgBase::codecForName(const TQCString& _str) 00575 { 00576 if (_str.isEmpty()) return 0; 00577 TQCString codec = _str; 00578 KPIM::kAsciiToLower(codec.data()); 00579 return TDEGlobal::charsets()->codecForName(codec); 00580 } 00581 00582 00583 //----------------------------------------------------------------------------- 00584 TQCString KMMsgBase::toUsAscii(const TQString& _str, bool *ok) 00585 { 00586 bool all_ok =true; 00587 TQString result = _str; 00588 int len = result.length(); 00589 for (int i = 0; i < len; i++) 00590 if (result.at(i).unicode() >= 128) { 00591 result.at(i) = '?'; 00592 all_ok = false; 00593 } 00594 if (ok) 00595 *ok = all_ok; 00596 return result.latin1(); 00597 } 00598 00599 00600 //----------------------------------------------------------------------------- 00601 TQStringList KMMsgBase::supportedEncodings(bool usAscii) 00602 { 00603 TQStringList encodingNames = TDEGlobal::charsets()->availableEncodingNames(); 00604 TQStringList encodings; 00605 TQMap<TQString,bool> mimeNames; 00606 for (TQStringList::Iterator it = encodingNames.begin(); 00607 it != encodingNames.end(); it++) 00608 { 00609 TQTextCodec *codec = TDEGlobal::charsets()->codecForName(*it); 00610 TQString mimeName = (codec) ? TQString(codec->mimeName()).lower() : (*it); 00611 if (mimeNames.find(mimeName) == mimeNames.end()) 00612 { 00613 encodings.append(TDEGlobal::charsets()->languageForEncoding(*it) 00614 + " ( " + mimeName + " )"); 00615 mimeNames.insert(mimeName, true); 00616 } 00617 } 00618 encodings.sort(); 00619 if (usAscii) encodings.prepend(TDEGlobal::charsets() 00620 ->languageForEncoding("us-ascii") + " ( us-ascii )"); 00621 return encodings; 00622 } 00623 00624 namespace { 00625 // don't rely on isblank(), which is a GNU extension in 00626 // <cctype>. But if someone wants to write a configure test for 00627 // isblank(), we can then rename this function to isblank and #ifdef 00628 // it's definition... 00629 inline bool isBlank( char ch ) { return ch == ' ' || ch == '\t' ; } 00630 00631 TQCString unfold( const TQCString & header ) { 00632 if ( header.isEmpty() ) 00633 return TQCString(); 00634 00635 TQCString result( header.size() ); // size() >= length()+1 and size() is O(1) 00636 char * d = result.data(); 00637 00638 for ( const char * s = header.data() ; *s ; ) 00639 if ( *s == '\r' ) { // ignore 00640 ++s; 00641 continue; 00642 } else if ( *s == '\n' ) { // unfold 00643 while ( isBlank( *++s ) ) 00644 ; 00645 *d++ = ' '; 00646 } else 00647 *d++ = *s++; 00648 00649 *d++ = '\0'; 00650 00651 result.truncate( d - result.data() ); 00652 return result; 00653 } 00654 } 00655 00656 00657 //----------------------------------------------------------------------------- 00658 TQString KMMsgBase::decodeRFC2047String(const TQCString& aStr, TQCString prefCharset) 00659 { 00660 if ( aStr.isEmpty() ) 00661 return TQString(); 00662 00663 const TQCString str = unfold( aStr ); 00664 00665 if ( str.isEmpty() ) 00666 return TQString(); 00667 00668 if ( str.find( "=?" ) < 0 ) { 00669 if ( !prefCharset.isEmpty() && 00670 kmkernel->isCodecAsciiCompatible( KMMsgBase::codecForName( prefCharset ) ) ) { 00671 if ( prefCharset == "us-ascii" ) { 00672 // isn`t this foolproof? 00673 return KMMsgBase::codecForName( "utf-8" )->toUnicode( str ); 00674 } else { 00675 return KMMsgBase::codecForName( prefCharset )->toUnicode( str ); 00676 } 00677 } else { 00678 if ( kmkernel->isCodecAsciiCompatible( KMMsgBase::codecForName( 00679 GlobalSettings::self()->fallbackCharacterEncoding().latin1() ) ) ) { 00680 return KMMsgBase::codecForName( GlobalSettings::self()-> 00681 fallbackCharacterEncoding().latin1() )->toUnicode( str ); 00682 } 00683 } 00684 00685 // Not RFC2047 encoded, and codec not ascii-compatible -> interpret as ascii 00686 return TQString::fromAscii( str ); 00687 } 00688 00689 TQString result; 00690 TQCString LWSP_buffer; 00691 bool lastWasEncodedWord = false; 00692 00693 for ( const char * pos = str.data() ; *pos ; ++pos ) { 00694 // collect LWSP after encoded-words, 00695 // because we might need to throw it out 00696 // (when the next word is an encoded-word) 00697 if ( lastWasEncodedWord && isBlank( pos[0] ) ) { 00698 LWSP_buffer += pos[0]; 00699 continue; 00700 } 00701 // verbatimly copy normal text 00702 if (pos[0]!='=' || pos[1]!='?') { 00703 result += LWSP_buffer + pos[0]; 00704 LWSP_buffer = 0; 00705 lastWasEncodedWord = false; 00706 continue; 00707 } 00708 // found possible encoded-word 00709 const char * const beg = pos; 00710 { 00711 // parse charset name 00712 TQCString charset; 00713 int i = 2; 00714 pos += 2; 00715 for ( ; *pos != '?' && ( *pos==' ' || ispunct(*pos) || isalnum(*pos) ); 00716 ++i, ++pos ) { 00717 charset += *pos; 00718 } 00719 if ( *pos!='?' || i<4 ) 00720 goto invalid_encoded_word; 00721 00722 // get encoding and check delimiting question marks 00723 const char encoding[2] = { pos[1], '\0' }; 00724 if (pos[2]!='?' || (encoding[0]!='Q' && encoding[0]!='q' && 00725 encoding[0]!='B' && encoding[0]!='b')) 00726 goto invalid_encoded_word; 00727 pos+=3; i+=3; // skip ?x? 00728 const char * enc_start = pos; 00729 // search for end of encoded part 00730 while ( *pos && !(*pos=='?' && *(pos+1)=='=') ) { 00731 i++; 00732 pos++; 00733 } 00734 if ( !*pos ) 00735 goto invalid_encoded_word; 00736 00737 // valid encoding: decode and throw away separating LWSP 00738 const KMime::Codec * c = KMime::Codec::codecForName( encoding ); 00739 kdFatal( !c, 5006 ) << "No \"" << encoding << "\" codec!?" << endl; 00740 00741 TQByteArray in; in.setRawData( enc_start, pos - enc_start ); 00742 const TQByteArray enc = c->decode( in ); 00743 in.resetRawData( enc_start, pos - enc_start ); 00744 00745 const TQTextCodec * codec = codecForName(charset); 00746 if (!codec) codec = kmkernel->networkCodec(); 00747 result += codec->toUnicode(enc); 00748 lastWasEncodedWord = true; 00749 00750 ++pos; // eat '?' (for loop eats '=') 00751 LWSP_buffer = 0; 00752 } 00753 continue; 00754 invalid_encoded_word: 00755 // invalid encoding, keep separating LWSP. 00756 pos = beg; 00757 if ( !LWSP_buffer.isNull() ) 00758 result += LWSP_buffer; 00759 result += "=?"; 00760 lastWasEncodedWord = false; 00761 ++pos; // eat '?' (for loop eats '=') 00762 LWSP_buffer = 0; 00763 } 00764 return result; 00765 } 00766 00767 00768 //----------------------------------------------------------------------------- 00769 static const TQCString especials = "()<>@,;:\"/[]?.= \033"; 00770 00771 TQCString KMMsgBase::encodeRFC2047Quoted( const TQCString & s, bool base64 ) { 00772 const char * codecName = base64 ? "b" : "q" ; 00773 const KMime::Codec * codec = KMime::Codec::codecForName( codecName ); 00774 kdFatal( !codec, 5006 ) << "No \"" << codecName << "\" found!?" << endl; 00775 TQByteArray in; in.setRawData( s.data(), s.length() ); 00776 const TQByteArray result = codec->encode( in ); 00777 in.resetRawData( s.data(), s.length() ); 00778 return TQCString( result.data(), result.size() + 1 ); 00779 } 00780 00781 TQCString KMMsgBase::encodeRFC2047String(const TQString& _str, 00782 const TQCString& charset) 00783 { 00784 static const TQString dontQuote = "\"()<>,@"; 00785 00786 if (_str.isEmpty()) return TQCString(); 00787 if (charset == "us-ascii") return toUsAscii(_str); 00788 00789 TQCString cset; 00790 if (charset.isEmpty()) 00791 { 00792 cset = kmkernel->networkCodec()->mimeName(); 00793 KPIM::kAsciiToLower(cset.data()); 00794 } 00795 else cset = charset; 00796 00797 const TQTextCodec *codec = codecForName(cset); 00798 if (!codec) codec = kmkernel->networkCodec(); 00799 00800 unsigned int nonAscii = 0; 00801 unsigned int strLength(_str.length()); 00802 for (unsigned int i = 0; i < strLength; i++) 00803 if (_str.at(i).unicode() >= 128) nonAscii++; 00804 bool useBase64 = (nonAscii * 6 > strLength); 00805 00806 unsigned int start, stop, p, pos = 0, encLength; 00807 TQCString result; 00808 bool breakLine = false; 00809 const unsigned int maxLen = 75 - 7 - cset.length(); 00810 00811 while (pos < strLength) 00812 { 00813 start = pos; p = pos; 00814 while (p < strLength) 00815 { 00816 if (!breakLine && (_str.at(p) == ' ' || dontQuote.find(_str.at(p)) != -1)) 00817 start = p + 1; 00818 if (_str.at(p).unicode() >= 128 || _str.at(p).unicode() < 32) 00819 break; 00820 p++; 00821 } 00822 if (breakLine || p < strLength) 00823 { 00824 while (dontQuote.find(_str.at(start)) != -1) start++; 00825 stop = start; 00826 while (stop < strLength && dontQuote.find(_str.at(stop)) == -1) 00827 stop++; 00828 result += _str.mid(pos, start - pos).latin1(); 00829 encLength = encodeRFC2047Quoted(codec->fromUnicode(_str. 00830 mid(start, stop - start)), useBase64).length(); 00831 breakLine = (encLength > maxLen); 00832 if (breakLine) 00833 { 00834 int dif = (stop - start) / 2; 00835 int step = dif; 00836 while (abs(step) > 1) 00837 { 00838 encLength = encodeRFC2047Quoted(codec->fromUnicode(_str. 00839 mid(start, dif)), useBase64).length(); 00840 step = (encLength > maxLen) ? (-abs(step) / 2) : (abs(step) / 2); 00841 dif += step; 00842 } 00843 stop = start + dif; 00844 } 00845 p = stop; 00846 while (p > start && _str.at(p) != ' ') p--; 00847 if (p > start) stop = p; 00848 if (result.right(3) == "?= ") start--; 00849 if (result.right(5) == "?=\n ") { 00850 start--; result.truncate(result.length() - 1); 00851 } 00852 int lastNewLine = result.findRev("\n "); 00853 if (!result.mid(lastNewLine).stripWhiteSpace().isEmpty() 00854 && result.length() - lastNewLine + encLength + 2 > maxLen) 00855 result += "\n "; 00856 result += "=?"; 00857 result += cset; 00858 result += (useBase64) ? "?b?" : "?q?"; 00859 result += encodeRFC2047Quoted(codec->fromUnicode(_str.mid(start, 00860 stop - start)), useBase64); 00861 result += "?="; 00862 if (breakLine) result += "\n "; 00863 pos = stop; 00864 } else { 00865 result += _str.mid(pos).latin1(); 00866 break; 00867 } 00868 } 00869 return result; 00870 } 00871 00872 00873 //----------------------------------------------------------------------------- 00874 TQCString KMMsgBase::encodeRFC2231String( const TQString& _str, 00875 const TQCString& charset ) 00876 { 00877 if ( _str.isEmpty() ) 00878 return TQCString(); 00879 00880 TQCString cset; 00881 if ( charset.isEmpty() ) 00882 { 00883 cset = kmkernel->networkCodec()->mimeName(); 00884 KPIM::kAsciiToLower( cset.data() ); 00885 } 00886 else 00887 cset = charset; 00888 const TQTextCodec *codec = codecForName( cset ); 00889 TQCString latin; 00890 if ( charset == "us-ascii" ) 00891 latin = toUsAscii( _str ); 00892 else if ( codec ) 00893 latin = codec->fromUnicode( _str ); 00894 else 00895 latin = _str.local8Bit(); 00896 00897 char *l; 00898 for ( l = latin.data(); *l; ++l ) { 00899 if ( ( ( *l & 0xE0 ) == 0 ) || ( *l & 0x80 ) ) 00900 // *l is control character or 8-bit char 00901 break; 00902 } 00903 if ( !*l ) 00904 return latin; 00905 00906 TQCString result = cset + "''"; 00907 for ( l = latin.data(); *l; ++l ) { 00908 bool needsQuoting = ( *l & 0x80 ); 00909 if( !needsQuoting ) { 00910 int len = especials.length(); 00911 for ( int i = 0; i < len; i++ ) 00912 if ( *l == especials[i] ) { 00913 needsQuoting = true; 00914 break; 00915 } 00916 } 00917 if ( needsQuoting ) { 00918 result += '%'; 00919 unsigned char hexcode; 00920 hexcode = ( ( *l & 0xF0 ) >> 4 ) + 48; 00921 if ( hexcode >= 58 ) 00922 hexcode += 7; 00923 result += hexcode; 00924 hexcode = ( *l & 0x0F ) + 48; 00925 if ( hexcode >= 58 ) 00926 hexcode += 7; 00927 result += hexcode; 00928 } else { 00929 result += *l; 00930 } 00931 } 00932 return result; 00933 } 00934 00935 //----------------------------------------------------------------------------- 00936 TQCString KMMsgBase::encodeRFC2231StringAutoDetectCharset( const TQString &str, 00937 const TQCString &defaultCharset ) 00938 { 00939 TQCString encoding = KMMsgBase::autoDetectCharset( defaultCharset, 00940 KMMessage::preferredCharsets(), str ); 00941 if ( encoding.isEmpty() ) 00942 encoding = "utf-8"; 00943 return KMMsgBase::encodeRFC2231String( str, encoding ); 00944 } 00945 00946 //----------------------------------------------------------------------------- 00947 TQString KMMsgBase::decodeRFC2231String(const TQCString& _str) 00948 { 00949 int p = _str.find('\''); 00950 if (p < 0) return kmkernel->networkCodec()->toUnicode(_str); 00951 00952 TQCString charset = _str.left(p); 00953 00954 TQCString st = _str.mid(_str.findRev('\'') + 1); 00955 char ch, ch2; 00956 p = 0; 00957 while (p < (int)st.length()) 00958 { 00959 if (st.at(p) == 37) 00960 { 00961 ch = st.at(p+1) - 48; 00962 if (ch > 16) ch -= 7; 00963 ch2 = st.at(p+2) - 48; 00964 if (ch2 > 16) ch2 -= 7; 00965 st.at(p) = ch * 16 + ch2; 00966 st.remove( p+1, 2 ); 00967 } 00968 p++; 00969 } 00970 TQString result; 00971 const TQTextCodec * codec = codecForName( charset ); 00972 if ( !codec ) 00973 codec = kmkernel->networkCodec(); 00974 return codec->toUnicode( st ); 00975 } 00976 00977 TQCString KMMsgBase::extractRFC2231HeaderField( const TQCString &aStr, const TQCString &field ) 00978 { 00979 int n=-1; 00980 TQCString str; 00981 bool found = false; 00982 while ( n<=0 || found ) { 00983 TQString pattern( field ); 00984 pattern += "[*]"; // match a literal * after the fieldname, as defined by RFC 2231 00985 if ( n>=0 ) { // If n<0, check for fieldname*=..., otherwise for fieldname*n= 00986 pattern += TQString::number(n) + "[*]?"; 00987 } 00988 pattern += "="; 00989 00990 TQRegExp fnamePart( pattern, false ); 00991 int startPart = fnamePart.search( aStr ); 00992 int endPart; 00993 found = ( startPart >= 0 ); 00994 if ( found ) { 00995 startPart += fnamePart.matchedLength(); 00996 // Quoted values end at the ending quote 00997 if ( aStr[startPart] == '"' ) { 00998 startPart++; // the double quote isn't part of the filename 00999 endPart = aStr.find('"', startPart) - 1; 01000 } 01001 else { 01002 endPart = aStr.find(';', startPart) - 1; 01003 } 01004 if (endPart < 0) 01005 endPart = 32767; 01006 str += aStr.mid( startPart, endPart-startPart+1).stripWhiteSpace(); 01007 } 01008 n++; 01009 } 01010 return str; 01011 } 01012 01013 TQString KMMsgBase::base64EncodedMD5( const TQString & s, bool utf8 ) { 01014 if (s.stripWhiteSpace().isEmpty()) return ""; 01015 if ( utf8 ) 01016 return base64EncodedMD5( s.stripWhiteSpace().utf8() ); // TQCString overload 01017 else 01018 return base64EncodedMD5( s.stripWhiteSpace().latin1() ); // const char * overload 01019 } 01020 01021 TQString KMMsgBase::base64EncodedMD5( const TQCString & s ) { 01022 if (s.stripWhiteSpace().isEmpty()) return ""; 01023 return base64EncodedMD5( s.stripWhiteSpace().data() ); 01024 } 01025 01026 TQString KMMsgBase::base64EncodedMD5( const char * s, int len ) { 01027 if (!s || !len) return ""; 01028 static const int Base64EncodedMD5Len = 22; 01029 KMD5 md5( s, len ); 01030 return md5.base64Digest().left( Base64EncodedMD5Len ); 01031 } 01032 01033 01034 //----------------------------------------------------------------------------- 01035 TQCString KMMsgBase::autoDetectCharset(const TQCString &_encoding, const TQStringList &encodingList, const TQString &text) 01036 { 01037 TQStringList charsets = encodingList; 01038 if (!_encoding.isEmpty()) 01039 { 01040 TQString currentCharset = TQString::fromLatin1(_encoding); 01041 charsets.remove(currentCharset); 01042 charsets.prepend(currentCharset); 01043 } 01044 01045 TQStringList::ConstIterator it = charsets.begin(); 01046 for (; it != charsets.end(); ++it) 01047 { 01048 TQCString encoding = (*it).latin1(); 01049 if (encoding == "locale") 01050 { 01051 encoding = kmkernel->networkCodec()->mimeName(); 01052 KPIM::kAsciiToLower(encoding.data()); 01053 } 01054 if (text.isEmpty()) 01055 return encoding; 01056 if (encoding == "us-ascii") { 01057 bool ok; 01058 (void) KMMsgBase::toUsAscii(text, &ok); 01059 if (ok) 01060 return encoding; 01061 } 01062 else 01063 { 01064 const TQTextCodec *codec = KMMsgBase::codecForName(encoding); 01065 if (!codec) { 01066 kdDebug(5006) << "Auto-Charset: Something is wrong and I can not get a codec. [" << encoding << "]" << endl; 01067 } else { 01068 if (codec->canEncode(text)) 01069 return encoding; 01070 } 01071 } 01072 } 01073 return 0; 01074 } 01075 01076 01077 //----------------------------------------------------------------------------- 01078 unsigned long KMMsgBase::getMsgSerNum() const 01079 { 01080 unsigned long msn = MessageProperty::serialCache( this ); 01081 if (msn) 01082 return msn; 01083 if (mParent) { 01084 int index = mParent->find((KMMsgBase*)this); 01085 msn = KMMsgDict::instance()->getMsgSerNum(mParent, index); 01086 if (msn) 01087 MessageProperty::setSerialCache( this, msn ); 01088 } 01089 return msn; 01090 } 01091 01092 01093 //----------------------------------------------------------------------------- 01094 KMMsgAttachmentState KMMsgBase::attachmentState() const 01095 { 01096 KMMsgStatus st = status(); 01097 if (st & KMMsgStatusHasAttach) 01098 return KMMsgHasAttachment; 01099 else if (st & KMMsgStatusHasNoAttach) 01100 return KMMsgHasNoAttachment; 01101 else 01102 return KMMsgAttachmentUnknown; 01103 } 01104 01105 01106 KMMsgInvitationState KMMsgBase::invitationState() const 01107 { 01108 KMMsgStatus st = status(); 01109 if (st & KMMsgStatusHasInvitation) 01110 return KMMsgHasInvitation; 01111 else if (st & KMMsgStatusHasNoInvitation) 01112 return KMMsgHasNoInvitation; 01113 else 01114 return KMMsgInvitationUnknown; 01115 } 01116 01117 //----------------------------------------------------------------------------- 01118 static void swapEndian(TQString &str) 01119 { 01120 uint len = str.length(); 01121 str = TQDeepCopy<TQString>(str); 01122 TQChar *unicode = const_cast<TQChar*>( str.unicode() ); 01123 for (uint i = 0; i < len; i++) 01124 unicode[i] = kmail_swap_16(unicode[i].unicode()); 01125 } 01126 01127 //----------------------------------------------------------------------------- 01128 static int g_chunk_length = 0, g_chunk_offset=0; 01129 static uchar *g_chunk = 0; 01130 01131 namespace { 01132 template < typename T > void copy_from_stream( T & x ) { 01133 if( g_chunk_offset + int(sizeof(T)) > g_chunk_length ) { 01134 g_chunk_offset = g_chunk_length; 01135 kdDebug( 5006 ) << "This should never happen.. " 01136 << __FILE__ << ":" << __LINE__ << endl; 01137 x = 0; 01138 } else { 01139 // the memcpy is optimized out by the compiler for the values 01140 // of sizeof(T) that is called with 01141 memcpy( &x, g_chunk + g_chunk_offset, sizeof(T) ); 01142 g_chunk_offset += sizeof(T); 01143 } 01144 } 01145 } 01146 01147 //----------------------------------------------------------------------------- 01148 TQString KMMsgBase::getStringPart(MsgPartType t) const 01149 { 01150 retry: 01151 TQString ret; 01152 01153 g_chunk_offset = 0; 01154 bool using_mmap = false; 01155 bool swapByteOrder = storage()->indexSwapByteOrder(); 01156 if (storage()->indexStreamBasePtr()) { 01157 if (g_chunk) 01158 free(g_chunk); 01159 using_mmap = true; 01160 g_chunk = storage()->indexStreamBasePtr() + mIndexOffset; 01161 g_chunk_length = mIndexLength; 01162 } else { 01163 if(!storage()->mIndexStream) 01164 return ret; 01165 if (g_chunk_length < mIndexLength) 01166 g_chunk = (uchar *)realloc(g_chunk, g_chunk_length = mIndexLength); 01167 off_t first_off=ftell(storage()->mIndexStream); 01168 fseek(storage()->mIndexStream, mIndexOffset, SEEK_SET); 01169 fread( g_chunk, mIndexLength, 1, storage()->mIndexStream); 01170 fseek(storage()->mIndexStream, first_off, SEEK_SET); 01171 } 01172 01173 MsgPartType type; 01174 TQ_UINT16 l; 01175 while(g_chunk_offset < mIndexLength) { 01176 TQ_UINT32 tmp; 01177 copy_from_stream(tmp); 01178 copy_from_stream(l); 01179 if (swapByteOrder) 01180 { 01181 tmp = kmail_swap_32(tmp); 01182 l = kmail_swap_16(l); 01183 } 01184 type = (MsgPartType) tmp; 01185 if(g_chunk_offset + l > mIndexLength) { 01186 kdDebug(5006) << "This should never happen.. " << __FILE__ << ":" << __LINE__ << endl; 01187 if(using_mmap) { 01188 g_chunk_length = 0; 01189 g_chunk = 0; 01190 } 01191 storage()->recreateIndex(); 01192 goto retry; 01193 } 01194 if(type == t) { 01195 // This works because the TQString constructor does a memcpy. 01196 // Otherwise we would need to be concerned about the alignment. 01197 if(l) 01198 ret = TQString((TQChar *)(g_chunk + g_chunk_offset), l/2); 01199 break; 01200 } 01201 g_chunk_offset += l; 01202 } 01203 if(using_mmap) { 01204 g_chunk_length = 0; 01205 g_chunk = 0; 01206 } 01207 // Normally we need to swap the byte order because the TQStrings are written 01208 // in the style of TQt2 (MSB -> network ordered). 01209 // TQStrings in TQt3 expect host ordering. 01210 // On e.g. Intel host ordering is LSB, on e.g. Sparc it is MSB. 01211 01212 #ifndef WORDS_BIGENDIAN 01213 // #warning Byte order is little endian (swap is true) 01214 swapEndian(ret); 01215 #else 01216 // #warning Byte order is big endian (swap is false) 01217 #endif 01218 01219 return ret; 01220 } 01221 01222 //----------------------------------------------------------------------------- 01223 off_t KMMsgBase::getLongPart(MsgPartType t) const 01224 { 01225 retry: 01226 off_t ret = 0; 01227 01228 g_chunk_offset = 0; 01229 bool using_mmap = false; 01230 int sizeOfLong = storage()->indexSizeOfLong(); 01231 bool swapByteOrder = storage()->indexSwapByteOrder(); 01232 if (storage()->indexStreamBasePtr()) { 01233 if (g_chunk) 01234 free(g_chunk); 01235 using_mmap = true; 01236 g_chunk = storage()->indexStreamBasePtr() + mIndexOffset; 01237 g_chunk_length = mIndexLength; 01238 } else { 01239 if (!storage()->mIndexStream) 01240 return ret; 01241 assert(mIndexLength >= 0); 01242 if (g_chunk_length < mIndexLength) 01243 g_chunk = (uchar *)realloc(g_chunk, g_chunk_length = mIndexLength); 01244 off_t first_off=ftell(storage()->mIndexStream); 01245 fseek(storage()->mIndexStream, mIndexOffset, SEEK_SET); 01246 fread( g_chunk, mIndexLength, 1, storage()->mIndexStream); 01247 fseek(storage()->mIndexStream, first_off, SEEK_SET); 01248 } 01249 01250 MsgPartType type; 01251 TQ_UINT16 l; 01252 while (g_chunk_offset < mIndexLength) { 01253 TQ_UINT32 tmp; 01254 copy_from_stream(tmp); 01255 copy_from_stream(l); 01256 if (swapByteOrder) 01257 { 01258 tmp = kmail_swap_32(tmp); 01259 l = kmail_swap_16(l); 01260 } 01261 type = (MsgPartType) tmp; 01262 01263 if (g_chunk_offset + l > mIndexLength) { 01264 kdDebug(5006) << "This should never happen.. " << __FILE__ << ":" << __LINE__ << endl; 01265 if(using_mmap) { 01266 g_chunk_length = 0; 01267 g_chunk = 0; 01268 } 01269 storage()->recreateIndex(); 01270 goto retry; 01271 } 01272 if(type == t) { 01273 assert(sizeOfLong == l); 01274 if (sizeOfLong == sizeof(ret)) 01275 { 01276 copy_from_stream(ret); 01277 if (swapByteOrder) 01278 { 01279 if (sizeof(ret) == 4) 01280 ret = kmail_swap_32(ret); 01281 else 01282 ret = kmail_swap_64(ret); 01283 } 01284 } 01285 else if (sizeOfLong == 4) 01286 { 01287 // Long is stored as 4 bytes in index file, sizeof(long) = 8 01288 TQ_UINT32 ret_32; 01289 copy_from_stream(ret_32); 01290 if (swapByteOrder) 01291 ret_32 = kmail_swap_32(ret_32); 01292 ret = ret_32; 01293 } 01294 else if (sizeOfLong == 8) 01295 { 01296 // Long is stored as 8 bytes in index file, sizeof(long) = 4 01297 TQ_UINT32 ret_1; 01298 TQ_UINT32 ret_2; 01299 copy_from_stream(ret_1); 01300 copy_from_stream(ret_2); 01301 if (!swapByteOrder) 01302 { 01303 // Index file order is the same as the order of this CPU. 01304 #ifndef WORDS_BIGENDIAN 01305 // Index file order is little endian 01306 ret = ret_1; // We drop the 4 most significant bytes 01307 #else 01308 // Index file order is big endian 01309 ret = ret_2; // We drop the 4 most significant bytes 01310 #endif 01311 } 01312 else 01313 { 01314 // Index file order is different from this CPU. 01315 #ifndef WORDS_BIGENDIAN 01316 // Index file order is big endian 01317 ret = ret_2; // We drop the 4 most significant bytes 01318 #else 01319 // Index file order is little endian 01320 ret = ret_1; // We drop the 4 most significant bytes 01321 #endif 01322 // We swap the result to host order. 01323 ret = kmail_swap_32(ret); 01324 } 01325 01326 } 01327 break; 01328 } 01329 g_chunk_offset += l; 01330 } 01331 if(using_mmap) { 01332 g_chunk_length = 0; 01333 g_chunk = 0; 01334 } 01335 return ret; 01336 } 01337 01338 #ifndef WORDS_BIGENDIAN 01339 // We need to use swab to swap bytes to network byte order 01340 #define memcpy_networkorder(to, from, len) swab((char *)(from), (char *)(to), len) 01341 #else 01342 // We're already in network byte order 01343 #define memcpy_networkorder(to, from, len) memcpy(to, from, len) 01344 #endif 01345 01346 #define STORE_DATA_LEN(type, x, len, network_order) do { \ 01347 int len2 = (len > 256) ? 256 : len; \ 01348 if(csize < (length + (len2 + sizeof(short) + sizeof(MsgPartType)))) \ 01349 ret = (uchar *)realloc(ret, csize += len2+sizeof(short)+sizeof(MsgPartType)); \ 01350 TQ_UINT32 t = (TQ_UINT32) type; memcpy(ret+length, &t, sizeof(t)); \ 01351 TQ_UINT16 l = len2; memcpy(ret+length+sizeof(t), &l, sizeof(l)); \ 01352 if (network_order) \ 01353 memcpy_networkorder(ret+length+sizeof(t)+sizeof(l), x, len2); \ 01354 else \ 01355 memcpy(ret+length+sizeof(t)+sizeof(l), x, len2); \ 01356 length += len2+sizeof(t)+sizeof(l); \ 01357 } while(0) 01358 #define STORE_DATA(type, x) STORE_DATA_LEN(type, &x, sizeof(x), false) 01359 01360 //----------------------------------------------------------------------------- 01361 const uchar *KMMsgBase::asIndexString(int &length) const 01362 { 01363 unsigned int csize = 256; 01364 static uchar *ret = 0; //different static buffer here for we may use the other buffer in the functions below 01365 if(!ret) 01366 ret = (uchar *)malloc(csize); 01367 length = 0; 01368 01369 unsigned long tmp; 01370 TQString tmp_str; 01371 01372 //these is at the beginning because it is queried quite often 01373 tmp_str = msgIdMD5().stripWhiteSpace(); 01374 STORE_DATA_LEN(MsgIdMD5Part, tmp_str.unicode(), tmp_str.length() * 2, true); 01375 tmp = mLegacyStatus; 01376 STORE_DATA(MsgLegacyStatusPart, tmp); 01377 01378 //these are completely arbitrary order 01379 tmp_str = fromStrip().stripWhiteSpace(); 01380 STORE_DATA_LEN(MsgFromStripPart, tmp_str.unicode(), tmp_str.length() * 2, true); 01381 tmp_str = subject().stripWhiteSpace(); 01382 STORE_DATA_LEN(MsgSubjectPart, tmp_str.unicode(), tmp_str.length() * 2, true); 01383 tmp_str = toStrip().stripWhiteSpace(); 01384 STORE_DATA_LEN(MsgToStripPart, tmp_str.unicode(), tmp_str.length() * 2, true); 01385 tmp_str = replyToIdMD5().stripWhiteSpace(); 01386 STORE_DATA_LEN(MsgReplyToIdMD5Part, tmp_str.unicode(), tmp_str.length() * 2, true); 01387 tmp_str = xmark().stripWhiteSpace(); 01388 STORE_DATA_LEN(MsgXMarkPart, tmp_str.unicode(), tmp_str.length() * 2, true); 01389 tmp_str = fileName().stripWhiteSpace(); 01390 STORE_DATA_LEN(MsgFilePart, tmp_str.unicode(), tmp_str.length() * 2, true); 01391 tmp = msgSize(); 01392 STORE_DATA(MsgSizePart, tmp); 01393 tmp = folderOffset(); 01394 STORE_DATA(MsgOffsetPart, tmp); 01395 tmp = date(); 01396 STORE_DATA(MsgDatePart, tmp); 01397 tmp = (signatureState() << 16) | encryptionState(); 01398 STORE_DATA(MsgCryptoStatePart, tmp); 01399 tmp = mdnSentState(); 01400 STORE_DATA(MsgMDNSentPart, tmp); 01401 01402 tmp_str = replyToAuxIdMD5().stripWhiteSpace(); 01403 STORE_DATA_LEN(MsgReplyToAuxIdMD5Part, tmp_str.unicode(), tmp_str.length() * 2, true); 01404 01405 tmp_str = strippedSubjectMD5().stripWhiteSpace(); 01406 STORE_DATA_LEN(MsgStrippedSubjectMD5Part, tmp_str.unicode(), tmp_str.length() * 2, true); 01407 01408 tmp = status(); 01409 STORE_DATA(MsgStatusPart, tmp); 01410 01411 tmp = msgSizeServer(); 01412 STORE_DATA(MsgSizeServerPart, tmp); 01413 tmp = UID(); 01414 STORE_DATA(MsgUIDPart, tmp); 01415 01416 tmp_str = from(); 01417 STORE_DATA_LEN( MsgFromPart, tmp_str.unicode(), tmp_str.length() * 2, true ); 01418 01419 tmp_str = to(); 01420 STORE_DATA_LEN( MsgToPart, tmp_str.unicode(), tmp_str.length() * 2, true ); 01421 01422 return ret; 01423 } 01424 #undef STORE_DATA_LEN 01425 #undef STORE_DATA 01426 01427 bool KMMsgBase::syncIndexString() const 01428 { 01429 if(!dirty()) 01430 return true; 01431 int len; 01432 const uchar *buffer = asIndexString(len); 01433 if (len == mIndexLength) { 01434 Q_ASSERT(storage()->mIndexStream); 01435 fseek(storage()->mIndexStream, mIndexOffset, SEEK_SET); 01436 assert( mIndexOffset > 0 ); 01437 fwrite( buffer, len, 1, storage()->mIndexStream); 01438 return true; 01439 } 01440 return false; 01441 } 01442 01443 static TQStringList sReplySubjPrefixes, sForwardSubjPrefixes; 01444 static bool sReplaceSubjPrefix, sReplaceForwSubjPrefix; 01445 01446 //----------------------------------------------------------------------------- 01447 void KMMsgBase::readConfig() 01448 { 01449 TDEConfigGroup composerGroup( KMKernel::config(), "Composer" ); 01450 sReplySubjPrefixes = composerGroup.readListEntry("reply-prefixes", ','); 01451 if (sReplySubjPrefixes.isEmpty()) 01452 sReplySubjPrefixes << "Re\\s*:" << "Re\\[\\d+\\]:" << "Re\\d+:"; 01453 sReplaceSubjPrefix = composerGroup.readBoolEntry("replace-reply-prefix", true); 01454 sForwardSubjPrefixes = composerGroup.readListEntry("forward-prefixes", ','); 01455 if (sForwardSubjPrefixes.isEmpty()) 01456 sForwardSubjPrefixes << "Fwd:" << "FW:"; 01457 sReplaceForwSubjPrefix = composerGroup.readBoolEntry("replace-forward-prefix", true); 01458 } 01459 01460 //----------------------------------------------------------------------------- 01461 // static 01462 TQString KMMsgBase::stripOffPrefixes( const TQString& str ) 01463 { 01464 return replacePrefixes( str, sReplySubjPrefixes + sForwardSubjPrefixes, 01465 true, TQString() ).stripWhiteSpace(); 01466 } 01467 01468 //----------------------------------------------------------------------------- 01469 // static 01470 TQString KMMsgBase::replacePrefixes( const TQString& str, 01471 const TQStringList& prefixRegExps, 01472 bool replace, 01473 const TQString& newPrefix ) 01474 { 01475 bool recognized = false; 01476 // construct a big regexp that 01477 // 1. is anchored to the beginning of str (sans whitespace) 01478 // 2. matches at least one of the part regexps in prefixRegExps 01479 TQString bigRegExp = TQString::fromLatin1("^(?:\\s+|(?:%1))+\\s*") 01480 .arg( prefixRegExps.join(")|(?:") ); 01481 TQRegExp rx( bigRegExp, false /*case insens.*/ ); 01482 if ( !rx.isValid() ) { 01483 kdWarning(5006) << "KMMessage::replacePrefixes(): bigRegExp = \"" 01484 << bigRegExp << "\"\n" 01485 << "prefix regexp is invalid!" << endl; 01486 // try good ole Re/Fwd: 01487 recognized = str.startsWith( newPrefix ); 01488 } else { // valid rx 01489 TQString tmp = str; 01490 if ( rx.search( tmp ) == 0 ) { 01491 recognized = true; 01492 if ( replace ) 01493 return tmp.replace( 0, rx.matchedLength(), newPrefix + ' ' ); 01494 } 01495 } 01496 if ( !recognized ) 01497 return newPrefix + ' ' + str; 01498 else 01499 return str; 01500 } 01501 01502 //----------------------------------------------------------------------------- 01503 TQString KMMsgBase::cleanSubject() const 01504 { 01505 return cleanSubject( sReplySubjPrefixes + sForwardSubjPrefixes, 01506 true, TQString() ).stripWhiteSpace(); 01507 } 01508 01509 //----------------------------------------------------------------------------- 01510 TQString KMMsgBase::cleanSubject( const TQStringList & prefixRegExps, 01511 bool replace, 01512 const TQString & newPrefix ) const 01513 { 01514 return KMMsgBase::replacePrefixes( subject(), prefixRegExps, replace, 01515 newPrefix ); 01516 } 01517 01518 //----------------------------------------------------------------------------- 01519 TQString KMMsgBase::forwardSubject() const { 01520 return cleanSubject( sForwardSubjPrefixes, sReplaceForwSubjPrefix, "Fwd:" ); 01521 } 01522 01523 //----------------------------------------------------------------------------- 01524 TQString KMMsgBase::replySubject() const { 01525 return cleanSubject( sReplySubjPrefixes, sReplaceSubjPrefix, "Re:" ); 01526 }