kmail Library API Documentation

kmmsgbase.cpp

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