00001
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 <kglobal.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 <qtextcodec.h>
00026 #include <qdeepcopy.h>
00027 #include <qregexp.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
00038
00039
00040
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
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
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
00089
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
00133
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
00160 mStatus &= ~KMMsgStatusUnread;
00161 mStatus &= ~KMMsgStatusNew;
00162 mStatus |= KMMsgStatusRead;
00163 break;
00164
00165 case KMMsgStatusUnread:
00166
00167 mStatus &= ~KMMsgStatusOld;
00168 mStatus &= ~KMMsgStatusRead;
00169 mStatus &= ~KMMsgStatusNew;
00170 mStatus |= KMMsgStatusUnread;
00171 break;
00172
00173 case KMMsgStatusOld:
00174
00175 mStatus &= ~KMMsgStatusNew;
00176 mStatus &= ~KMMsgStatusUnread;
00177 mStatus |= KMMsgStatusOld;
00178 break;
00179
00180 case KMMsgStatusNew:
00181
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
00220 case KMMsgStatusWatched:
00221 mStatus &= ~KMMsgStatusIgnored;
00222 mStatus |= KMMsgStatusWatched;
00223 break;
00224
00225 case KMMsgStatusIgnored:
00226 mStatus &= ~KMMsgStatusWatched;
00227 mStatus |= KMMsgStatusIgnored;
00228 break;
00229
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 default:
00247 mStatus = aStatus;
00248 break;
00249 }
00250
00251 if ( oldStatus != mStatus && storage() ) {
00252 if (idx < 0)
00253 idx = storage()->find( this );
00254 storage()->msgStatusChanged( oldStatus, status(), idx );
00255 storage()->headerOfMsgChanged( this, idx );
00256 }
00257 }
00258
00259
00260
00261
00262 void KMMsgBase::setStatus(const char* aStatusStr, const char* aXStatusStr)
00263 {
00264
00265 if (aXStatusStr) {
00266 if (strchr(aXStatusStr, 'N')) setStatus(KMMsgStatusNew);
00267 if (strchr(aXStatusStr, 'U')) setStatus(KMMsgStatusUnread);
00268 if (strchr(aXStatusStr, 'O')) setStatus(KMMsgStatusOld);
00269 if (strchr(aXStatusStr, 'R')) setStatus(KMMsgStatusRead);
00270 if (strchr(aXStatusStr, 'D')) setStatus(KMMsgStatusDeleted);
00271 if (strchr(aXStatusStr, 'A')) setStatus(KMMsgStatusReplied);
00272 if (strchr(aXStatusStr, 'F')) setStatus(KMMsgStatusForwarded);
00273 if (strchr(aXStatusStr, 'Q')) setStatus(KMMsgStatusQueued);
00274 if (strchr(aXStatusStr, 'K')) setStatus(KMMsgStatusTodo);
00275 if (strchr(aXStatusStr, 'S')) setStatus(KMMsgStatusSent);
00276 if (strchr(aXStatusStr, 'G')) setStatus(KMMsgStatusFlag);
00277 if (strchr(aXStatusStr, 'P')) setStatus(KMMsgStatusSpam);
00278 if (strchr(aXStatusStr, 'H')) setStatus(KMMsgStatusHam);
00279 if (strchr(aXStatusStr, 'T')) setStatus(KMMsgStatusHasAttach);
00280 if (strchr(aXStatusStr, 'C')) setStatus(KMMsgStatusHasNoAttach);
00281 }
00282
00283
00284 if (aStatusStr) {
00285 if ((aStatusStr[0]== 'R' && aStatusStr[1]== 'O') ||
00286 (aStatusStr[0]== 'O' && aStatusStr[1]== 'R')) {
00287 setStatus( KMMsgStatusOld );
00288 setStatus( KMMsgStatusRead );
00289 }
00290 else if (aStatusStr[0] == 'R')
00291 setStatus(KMMsgStatusRead);
00292 else if (aStatusStr[0] == 'D')
00293 setStatus(KMMsgStatusDeleted);
00294 else
00295 setStatus(KMMsgStatusNew);
00296 }
00297 }
00298
00299
00300 void KMMsgBase::setEncryptionState( const KMMsgEncryptionState , int idx )
00301 {
00302
00303 mDirty = true;
00304 if (storage())
00305 storage()->headerOfMsgChanged(this, idx);
00306 }
00307
00308 void KMMsgBase::setEncryptionStateChar( QChar status, int idx )
00309 {
00310
00311
00312 if( status.latin1() == (char)KMMsgEncryptionStateUnknown )
00313 setEncryptionState( KMMsgEncryptionStateUnknown, idx );
00314 else if( status.latin1() == (char)KMMsgNotEncrypted )
00315 setEncryptionState( KMMsgNotEncrypted, idx );
00316 else if( status.latin1() == (char)KMMsgPartiallyEncrypted )
00317 setEncryptionState( KMMsgPartiallyEncrypted, idx );
00318 else if( status.latin1() == (char)KMMsgFullyEncrypted )
00319 setEncryptionState( KMMsgFullyEncrypted, idx );
00320 else
00321 setEncryptionState( KMMsgEncryptionStateUnknown, idx );
00322 }
00323
00324
00325 void KMMsgBase::setSignatureState( const KMMsgSignatureState , int idx )
00326 {
00327
00328 mDirty = true;
00329 if (storage())
00330 storage()->headerOfMsgChanged(this, idx);
00331 }
00332
00333 void KMMsgBase::setMDNSentState( KMMsgMDNSentState, int idx ) {
00334 mDirty = true;
00335 if ( storage() )
00336 storage()->headerOfMsgChanged(this, idx);
00337 }
00338
00339 void KMMsgBase::setSignatureStateChar( QChar status, int idx )
00340 {
00341
00342
00343 if( status.latin1() == (char)KMMsgSignatureStateUnknown )
00344 setSignatureState( KMMsgSignatureStateUnknown, idx );
00345 else if( status.latin1() == (char)KMMsgNotSigned )
00346 setSignatureState( KMMsgNotSigned, idx );
00347 else if( status.latin1() == (char)KMMsgPartiallySigned )
00348 setSignatureState( KMMsgPartiallySigned,idx );
00349 else if( status.latin1() == (char)KMMsgFullySigned )
00350 setSignatureState( KMMsgFullySigned, idx );
00351 else
00352 setSignatureState( KMMsgSignatureStateUnknown, idx );
00353 }
00354
00355
00356 bool KMMsgBase::isUnread(void) const
00357 {
00358 KMMsgStatus st = status();
00359 return (st & KMMsgStatusUnread && !(st & KMMsgStatusIgnored));
00360 }
00361
00362
00363 bool KMMsgBase::isNew(void) const
00364 {
00365 KMMsgStatus st = status();
00366 return (st & KMMsgStatusNew && !(st & KMMsgStatusIgnored));
00367 }
00368
00369
00370 bool KMMsgBase::isOfUnknownStatus(void) const
00371 {
00372 KMMsgStatus st = status();
00373 return (st == KMMsgStatusUnknown);
00374 }
00375
00376
00377 bool KMMsgBase::isOld(void) const
00378 {
00379 KMMsgStatus st = status();
00380 return (st & KMMsgStatusOld);
00381 }
00382
00383
00384 bool KMMsgBase::isRead(void) const
00385 {
00386 KMMsgStatus st = status();
00387 return (st & KMMsgStatusRead || st & KMMsgStatusIgnored);
00388 }
00389
00390
00391 bool KMMsgBase::isDeleted(void) const
00392 {
00393 KMMsgStatus st = status();
00394 return (st & KMMsgStatusDeleted);
00395 }
00396
00397
00398 bool KMMsgBase::isReplied(void) const
00399 {
00400 KMMsgStatus st = status();
00401 return (st & KMMsgStatusReplied);
00402 }
00403
00404
00405 bool KMMsgBase::isForwarded(void) const
00406 {
00407 KMMsgStatus st = status();
00408 return (st & KMMsgStatusForwarded);
00409 }
00410
00411
00412 bool KMMsgBase::isQueued(void) const
00413 {
00414 KMMsgStatus st = status();
00415 return (st & KMMsgStatusQueued);
00416 }
00417
00418
00419 bool KMMsgBase::isTodo(void) const
00420 {
00421 KMMsgStatus st = status();
00422 return (st & KMMsgStatusTodo);
00423 }
00424
00425
00426 bool KMMsgBase::isSent(void) const
00427 {
00428 KMMsgStatus st = status();
00429 return (st & KMMsgStatusSent);
00430 }
00431
00432
00433 bool KMMsgBase::isImportant(void) const
00434 {
00435 KMMsgStatus st = status();
00436 return (st & KMMsgStatusFlag);
00437 }
00438
00439
00440 bool KMMsgBase::isWatched(void) const
00441 {
00442 KMMsgStatus st = status();
00443 return (st & KMMsgStatusWatched);
00444 }
00445
00446
00447 bool KMMsgBase::isIgnored(void) const
00448 {
00449 KMMsgStatus st = status();
00450 return (st & KMMsgStatusIgnored);
00451 }
00452
00453
00454 bool KMMsgBase::isSpam(void) const
00455 {
00456 KMMsgStatus st = status();
00457 return (st & KMMsgStatusSpam);
00458 }
00459
00460
00461 bool KMMsgBase::isHam(void) const
00462 {
00463 KMMsgStatus st = status();
00464 return (st & KMMsgStatusHam);
00465 }
00466
00467
00468 QCString KMMsgBase::statusToStr(const KMMsgStatus status)
00469 {
00470 QCString sstr;
00471 if (status & KMMsgStatusNew) sstr += 'N';
00472 if (status & KMMsgStatusUnread) sstr += 'U';
00473 if (status & KMMsgStatusOld) sstr += 'O';
00474 if (status & KMMsgStatusRead) sstr += 'R';
00475 if (status & KMMsgStatusDeleted) sstr += 'D';
00476 if (status & KMMsgStatusReplied) sstr += 'A';
00477 if (status & KMMsgStatusForwarded) sstr += 'F';
00478 if (status & KMMsgStatusQueued) sstr += 'Q';
00479 if (status & KMMsgStatusTodo) sstr += 'K';
00480 if (status & KMMsgStatusSent) sstr += 'S';
00481 if (status & KMMsgStatusFlag) sstr += 'G';
00482 if (status & KMMsgStatusWatched) sstr += 'W';
00483 if (status & KMMsgStatusIgnored) sstr += 'I';
00484 if (status & KMMsgStatusSpam) sstr += 'P';
00485 if (status & KMMsgStatusHam) sstr += 'H';
00486 if (status & KMMsgStatusHasAttach) sstr += 'T';
00487 if (status & KMMsgStatusHasNoAttach) sstr += 'C';
00488
00489 return sstr;
00490 }
00491
00492
00493 QString KMMsgBase::statusToSortRank()
00494 {
00495 QString sstr = "bcbbbbbbbb";
00496
00497
00498 if (status() & KMMsgStatusWatched) sstr[0] = 'a';
00499 if (status() & KMMsgStatusIgnored) sstr[0] = 'c';
00500
00501
00502 if (status() & KMMsgStatusNew) sstr[1] = 'a';
00503 if (status() & KMMsgStatusUnread) sstr[1] = 'b';
00504
00505
00506
00507
00508 if (status() & KMMsgStatusDeleted) sstr[2] = 'a';
00509 if (status() & KMMsgStatusFlag) sstr[3] = 'a';
00510 if (status() & KMMsgStatusReplied) sstr[4] = 'a';
00511 if (status() & KMMsgStatusForwarded) sstr[5] = 'a';
00512 if (status() & KMMsgStatusQueued) sstr[6] = 'a';
00513 if (status() & KMMsgStatusSent) sstr[7] = 'a';
00514 if (status() & KMMsgStatusHam) sstr[8] = 'a';
00515 if (status() & KMMsgStatusSpam) sstr[8] = 'c';
00516 if (status() & KMMsgStatusTodo) sstr[9] = 'a';
00517
00518 return sstr;
00519 }
00520
00521
00522
00523 void KMMsgBase::setDate(const QCString& aDateStr)
00524 {
00525 setDate( KRFCDate::parseDate( aDateStr ) );
00526 }
00527
00528
00529
00530 QString KMMsgBase::dateStr(void) const
00531 {
00532 time_t d = date();
00533 return KMime::DateFormatter::formatDate(KMime::DateFormatter::Fancy, d);
00534 }
00535
00536
00537
00538 QString KMMsgBase::skipKeyword(const QString& aStr, QChar sepChar,
00539 bool* hasKeyword)
00540 {
00541 unsigned int i = 0, maxChars = 3;
00542 QString str = aStr;
00543
00544 while (str[0] == ' ') str.remove(0,1);
00545 if (hasKeyword) *hasKeyword=false;
00546
00547 unsigned int strLength(str.length());
00548 for (i=0; i < strLength && i < maxChars; i++)
00549 {
00550 if (str[i] < 'A' || str[i] == sepChar) break;
00551 }
00552
00553 if (str[i] == sepChar)
00554 {
00555 do {
00556 i++;
00557 } while (str[i] == ' ');
00558 if (hasKeyword) *hasKeyword=true;
00559 return str.mid(i);
00560 }
00561 return str;
00562 }
00563
00564
00565
00566 const QTextCodec* KMMsgBase::codecForName(const QCString& _str)
00567 {
00568 if (_str.isEmpty()) return 0;
00569 QCString codec = _str;
00570 KPIM::kAsciiToLower(codec.data());
00571 return KGlobal::charsets()->codecForName(codec);
00572 }
00573
00574
00575
00576 QCString KMMsgBase::toUsAscii(const QString& _str, bool *ok)
00577 {
00578 bool all_ok =true;
00579 QString result = _str;
00580 int len = result.length();
00581 for (int i = 0; i < len; i++)
00582 if (result.at(i).unicode() >= 128) {
00583 result.at(i) = '?';
00584 all_ok = false;
00585 }
00586 if (ok)
00587 *ok = all_ok;
00588 return result.latin1();
00589 }
00590
00591
00592
00593 QStringList KMMsgBase::supportedEncodings(bool usAscii)
00594 {
00595 QStringList encodingNames = KGlobal::charsets()->availableEncodingNames();
00596 QStringList encodings;
00597 QMap<QString,bool> mimeNames;
00598 for (QStringList::Iterator it = encodingNames.begin();
00599 it != encodingNames.end(); it++)
00600 {
00601 QTextCodec *codec = KGlobal::charsets()->codecForName(*it);
00602 QString mimeName = (codec) ? QString(codec->mimeName()).lower() : (*it);
00603 if (mimeNames.find(mimeName) == mimeNames.end())
00604 {
00605 encodings.append(KGlobal::charsets()->languageForEncoding(*it)
00606 + " ( " + mimeName + " )");
00607 mimeNames.insert(mimeName, true);
00608 }
00609 }
00610 encodings.sort();
00611 if (usAscii) encodings.prepend(KGlobal::charsets()
00612 ->languageForEncoding("us-ascii") + " ( us-ascii )");
00613 return encodings;
00614 }
00615
00616 namespace {
00617
00618
00619
00620
00621 inline bool isBlank( char ch ) { return ch == ' ' || ch == '\t' ; }
00622
00623 QCString unfold( const QCString & header ) {
00624 if ( header.isEmpty() )
00625 return QCString();
00626
00627 QCString result( header.size() );
00628 char * d = result.data();
00629
00630 for ( const char * s = header.data() ; *s ; )
00631 if ( *s == '\r' ) {
00632 ++s;
00633 continue;
00634 } else if ( *s == '\n' ) {
00635 while ( isBlank( *++s ) )
00636 ;
00637 *d++ = ' ';
00638 } else
00639 *d++ = *s++;
00640
00641 *d++ = '\0';
00642
00643 result.truncate( d - result.data() );
00644 return result;
00645 }
00646 }
00647
00648
00649
00650 QString KMMsgBase::decodeRFC2047String(const QCString& aStr, QCString prefCharset)
00651 {
00652 if ( aStr.isEmpty() )
00653 return QString::null;
00654
00655 const QCString str = unfold( aStr );
00656
00657 if ( str.isEmpty() )
00658 return QString::null;
00659
00660 if ( str.find( "=?" ) < 0 ) {
00661 if ( !prefCharset.isEmpty() ) {
00662 if ( prefCharset == "us-ascii" ) {
00663
00664 return KMMsgBase::codecForName( "utf-8" )->toUnicode( str );
00665 } else {
00666 return KMMsgBase::codecForName( prefCharset )->toUnicode( str );
00667 }
00668 } else {
00669 return KMMsgBase::codecForName( GlobalSettings::self()->
00670 fallbackCharacterEncoding().latin1() )->toUnicode( str );
00671 }
00672 }
00673
00674 QString result;
00675 QCString LWSP_buffer;
00676 bool lastWasEncodedWord = false;
00677
00678 for ( const char * pos = str.data() ; *pos ; ++pos ) {
00679
00680
00681
00682 if ( lastWasEncodedWord && isBlank( pos[0] ) ) {
00683 LWSP_buffer += pos[0];
00684 continue;
00685 }
00686
00687 if (pos[0]!='=' || pos[1]!='?') {
00688 result += LWSP_buffer + pos[0];
00689 LWSP_buffer = 0;
00690 lastWasEncodedWord = false;
00691 continue;
00692 }
00693
00694 const char * const beg = pos;
00695 {
00696
00697 QCString charset;
00698 int i = 2;
00699 pos += 2;
00700 for ( ; *pos != '?' && ( *pos==' ' || ispunct(*pos) || isalnum(*pos) );
00701 ++i, ++pos ) {
00702 charset += *pos;
00703 }
00704 if ( *pos!='?' || i<4 )
00705 goto invalid_encoded_word;
00706
00707
00708 const char encoding[2] = { pos[1], '\0' };
00709 if (pos[2]!='?' || (encoding[0]!='Q' && encoding[0]!='q' &&
00710 encoding[0]!='B' && encoding[0]!='b'))
00711 goto invalid_encoded_word;
00712 pos+=3; i+=3;
00713 const char * enc_start = pos;
00714
00715 while ( *pos && !(*pos=='?' && *(pos+1)=='=') ) {
00716 i++;
00717 pos++;
00718 }
00719 if ( !*pos )
00720 goto invalid_encoded_word;
00721
00722
00723 const KMime::Codec * c = KMime::Codec::codecForName( encoding );
00724 kdFatal( !c, 5006 ) << "No \"" << encoding << "\" codec!?" << endl;
00725
00726 QByteArray in; in.setRawData( enc_start, pos - enc_start );
00727 const QByteArray enc = c->decode( in );
00728 in.resetRawData( enc_start, pos - enc_start );
00729
00730 const QTextCodec * codec = codecForName(charset);
00731 if (!codec) codec = kmkernel->networkCodec();
00732 result += codec->toUnicode(enc);
00733 lastWasEncodedWord = true;
00734
00735 ++pos;
00736 LWSP_buffer = 0;
00737 }
00738 continue;
00739 invalid_encoded_word:
00740
00741 pos = beg;
00742 if ( !LWSP_buffer.isNull() )
00743 result += LWSP_buffer;
00744 result += "=?";
00745 lastWasEncodedWord = false;
00746 ++pos;
00747 LWSP_buffer = 0;
00748 }
00749 return result;
00750 }
00751
00752
00753
00754 static const QCString especials = "()<>@,;:\"/[]?.= \033";
00755
00756 QCString KMMsgBase::encodeRFC2047Quoted( const QCString & s, bool base64 ) {
00757 const char * codecName = base64 ? "b" : "q" ;
00758 const KMime::Codec * codec = KMime::Codec::codecForName( codecName );
00759 kdFatal( !codec, 5006 ) << "No \"" << codecName << "\" found!?" << endl;
00760 QByteArray in; in.setRawData( s.data(), s.length() );
00761 const QByteArray result = codec->encode( in );
00762 in.resetRawData( s.data(), s.length() );
00763 return QCString( result.data(), result.size() + 1 );
00764 }
00765
00766 QCString KMMsgBase::encodeRFC2047String(const QString& _str,
00767 const QCString& charset)
00768 {
00769 static const QString dontQuote = "\"()<>,@";
00770
00771 if (_str.isEmpty()) return QCString();
00772 if (charset == "us-ascii") return toUsAscii(_str);
00773
00774 QCString cset;
00775 if (charset.isEmpty())
00776 {
00777 cset = kmkernel->networkCodec()->mimeName();
00778 KPIM::kAsciiToLower(cset.data());
00779 }
00780 else cset = charset;
00781
00782 const QTextCodec *codec = codecForName(cset);
00783 if (!codec) codec = kmkernel->networkCodec();
00784
00785 unsigned int nonAscii = 0;
00786 unsigned int strLength(_str.length());
00787 for (unsigned int i = 0; i < strLength; i++)
00788 if (_str.at(i).unicode() >= 128) nonAscii++;
00789 bool useBase64 = (nonAscii * 6 > strLength);
00790
00791 unsigned int start, stop, p, pos = 0, encLength;
00792 QCString result;
00793 bool breakLine = false;
00794 const unsigned int maxLen = 75 - 7 - cset.length();
00795
00796 while (pos < strLength)
00797 {
00798 start = pos; p = pos;
00799 while (p < strLength)
00800 {
00801 if (!breakLine && (_str.at(p) == ' ' || dontQuote.find(_str.at(p)) != -1))
00802 start = p + 1;
00803 if (_str.at(p).unicode() >= 128 || _str.at(p).unicode() < 32)
00804 break;
00805 p++;
00806 }
00807 if (breakLine || p < strLength)
00808 {
00809 while (dontQuote.find(_str.at(start)) != -1) start++;
00810 stop = start;
00811 while (stop < strLength && dontQuote.find(_str.at(stop)) == -1)
00812 stop++;
00813 result += _str.mid(pos, start - pos).latin1();
00814 encLength = encodeRFC2047Quoted(codec->fromUnicode(_str.
00815 mid(start, stop - start)), useBase64).length();
00816 breakLine = (encLength > maxLen);
00817 if (breakLine)
00818 {
00819 int dif = (stop - start) / 2;
00820 int step = dif;
00821 while (abs(step) > 1)
00822 {
00823 encLength = encodeRFC2047Quoted(codec->fromUnicode(_str.
00824 mid(start, dif)), useBase64).length();
00825 step = (encLength > maxLen) ? (-abs(step) / 2) : (abs(step) / 2);
00826 dif += step;
00827 }
00828 stop = start + dif;
00829 }
00830 p = stop;
00831 while (p > start && _str.at(p) != ' ') p--;
00832 if (p > start) stop = p;
00833 if (result.right(3) == "?= ") start--;
00834 if (result.right(5) == "?=\n ") {
00835 start--; result.truncate(result.length() - 1);
00836 }
00837 int lastNewLine = result.findRev("\n ");
00838 if (!result.mid(lastNewLine).stripWhiteSpace().isEmpty()
00839 && result.length() - lastNewLine + encLength + 2 > maxLen)
00840 result += "\n ";
00841 result += "=?";
00842 result += cset;
00843 result += (useBase64) ? "?b?" : "?q?";
00844 result += encodeRFC2047Quoted(codec->fromUnicode(_str.mid(start,
00845 stop - start)), useBase64);
00846 result += "?=";
00847 if (breakLine) result += "\n ";
00848 pos = stop;
00849 } else {
00850 result += _str.mid(pos).latin1();
00851 break;
00852 }
00853 }
00854 return result;
00855 }
00856
00857
00858
00859 QCString KMMsgBase::encodeRFC2231String( const QString& _str,
00860 const QCString& charset )
00861 {
00862 if ( _str.isEmpty() )
00863 return QCString();
00864
00865 QCString cset;
00866 if ( charset.isEmpty() )
00867 {
00868 cset = kmkernel->networkCodec()->mimeName();
00869 KPIM::kAsciiToLower( cset.data() );
00870 }
00871 else
00872 cset = charset;
00873 const QTextCodec *codec = codecForName( cset );
00874 QCString latin;
00875 if ( charset == "us-ascii" )
00876 latin = toUsAscii( _str );
00877 else if ( codec )
00878 latin = codec->fromUnicode( _str );
00879 else
00880 latin = _str.local8Bit();
00881
00882 char *l;
00883 for ( l = latin.data(); *l; ++l ) {
00884 if ( ( ( *l & 0xE0 ) == 0 ) || ( *l & 0x80 ) )
00885
00886 break;
00887 }
00888 if ( !*l )
00889 return latin;
00890
00891 QCString result = cset + "''";
00892 for ( l = latin.data(); *l; ++l ) {
00893 bool needsQuoting = ( *l & 0x80 );
00894 if( !needsQuoting ) {
00895 int len = especials.length();
00896 for ( int i = 0; i < len; i++ )
00897 if ( *l == especials[i] ) {
00898 needsQuoting = true;
00899 break;
00900 }
00901 }
00902 if ( needsQuoting ) {
00903 result += '%';
00904 unsigned char hexcode;
00905 hexcode = ( ( *l & 0xF0 ) >> 4 ) + 48;
00906 if ( hexcode >= 58 )
00907 hexcode += 7;
00908 result += hexcode;
00909 hexcode = ( *l & 0x0F ) + 48;
00910 if ( hexcode >= 58 )
00911 hexcode += 7;
00912 result += hexcode;
00913 } else {
00914 result += *l;
00915 }
00916 }
00917 return result;
00918 }
00919
00920
00921 QCString KMMsgBase::encodeRFC2231StringAutoDetectCharset( const QString &str,
00922 const QCString &defaultCharset )
00923 {
00924 QCString encoding = KMMsgBase::autoDetectCharset( defaultCharset,
00925 KMMessage::preferredCharsets(), str );
00926 if ( encoding.isEmpty() )
00927 encoding = "utf-8";
00928 return KMMsgBase::encodeRFC2231String( str, encoding );
00929 }
00930
00931
00932 QString KMMsgBase::decodeRFC2231String(const QCString& _str)
00933 {
00934 int p = _str.find('\'');
00935 if (p < 0) return kmkernel->networkCodec()->toUnicode(_str);
00936
00937 QCString charset = _str.left(p);
00938
00939 QCString st = _str.mid(_str.findRev('\'') + 1);
00940 char ch, ch2;
00941 p = 0;
00942 while (p < (int)st.length())
00943 {
00944 if (st.at(p) == 37)
00945 {
00946 ch = st.at(p+1) - 48;
00947 if (ch > 16) ch -= 7;
00948 ch2 = st.at(p+2) - 48;
00949 if (ch2 > 16) ch2 -= 7;
00950 st.at(p) = ch * 16 + ch2;
00951 st.remove( p+1, 2 );
00952 }
00953 p++;
00954 }
00955 QString result;
00956 const QTextCodec * codec = codecForName( charset );
00957 if ( !codec )
00958 codec = kmkernel->networkCodec();
00959 return codec->toUnicode( st );
00960 }
00961
00962 QCString KMMsgBase::extractRFC2231HeaderField( const QCString &aStr, const QCString &field )
00963 {
00964 int n=-1;
00965 QCString str;
00966 bool found = false;
00967 while ( n<=0 || found ) {
00968 QString pattern( field );
00969 pattern += "[*]";
00970 if ( n>=0 ) {
00971 pattern += QString::number(n) + "[*]?";
00972 }
00973 pattern += "=";
00974
00975 QRegExp fnamePart( pattern, false );
00976 int startPart = fnamePart.search( aStr );
00977 int endPart;
00978 found = ( startPart >= 0 );
00979 if ( found ) {
00980 startPart += fnamePart.matchedLength();
00981
00982 if ( aStr[startPart] == '"' ) {
00983 startPart++;
00984 endPart = aStr.find('"', startPart) - 1;
00985 }
00986 else {
00987 endPart = aStr.find(';', startPart) - 1;
00988 }
00989 if (endPart < 0)
00990 endPart = 32767;
00991 str += aStr.mid( startPart, endPart-startPart+1).stripWhiteSpace();
00992 }
00993 n++;
00994 }
00995 return str;
00996 }
00997
00998 QString KMMsgBase::base64EncodedMD5( const QString & s, bool utf8 ) {
00999 if (s.stripWhiteSpace().isEmpty()) return "";
01000 if ( utf8 )
01001 return base64EncodedMD5( s.stripWhiteSpace().utf8() );
01002 else
01003 return base64EncodedMD5( s.stripWhiteSpace().latin1() );
01004 }
01005
01006 QString KMMsgBase::base64EncodedMD5( const QCString & s ) {
01007 if (s.stripWhiteSpace().isEmpty()) return "";
01008 return base64EncodedMD5( s.stripWhiteSpace().data() );
01009 }
01010
01011 QString KMMsgBase::base64EncodedMD5( const char * s, int len ) {
01012 if (!s || !len) return "";
01013 static const int Base64EncodedMD5Len = 22;
01014 KMD5 md5( s, len );
01015 return md5.base64Digest().left( Base64EncodedMD5Len );
01016 }
01017
01018
01019
01020 QCString KMMsgBase::autoDetectCharset(const QCString &_encoding, const QStringList &encodingList, const QString &text)
01021 {
01022 QStringList charsets = encodingList;
01023 if (!_encoding.isEmpty())
01024 {
01025 QString currentCharset = QString::fromLatin1(_encoding);
01026 charsets.remove(currentCharset);
01027 charsets.prepend(currentCharset);
01028 }
01029
01030 QStringList::ConstIterator it = charsets.begin();
01031 for (; it != charsets.end(); ++it)
01032 {
01033 QCString encoding = (*it).latin1();
01034 if (encoding == "locale")
01035 {
01036 encoding = kmkernel->networkCodec()->mimeName();
01037 KPIM::kAsciiToLower(encoding.data());
01038 }
01039 if (text.isEmpty())
01040 return encoding;
01041 if (encoding == "us-ascii") {
01042 bool ok;
01043 (void) KMMsgBase::toUsAscii(text, &ok);
01044 if (ok)
01045 return encoding;
01046 }
01047 else
01048 {
01049 const QTextCodec *codec = KMMsgBase::codecForName(encoding);
01050 if (!codec) {
01051 kdDebug(5006) << "Auto-Charset: Something is wrong and I can not get a codec. [" << encoding << "]" << endl;
01052 } else {
01053 if (codec->canEncode(text))
01054 return encoding;
01055 }
01056 }
01057 }
01058 return 0;
01059 }
01060
01061
01062
01063 unsigned long KMMsgBase::getMsgSerNum() const
01064 {
01065 unsigned long msn = MessageProperty::serialCache( this );
01066 if (msn)
01067 return msn;
01068 if (mParent) {
01069 int index = mParent->find((KMMsgBase*)this);
01070 msn = KMMsgDict::instance()->getMsgSerNum(mParent, index);
01071 if (msn)
01072 MessageProperty::setSerialCache( this, msn );
01073 }
01074 return msn;
01075 }
01076
01077
01078
01079 KMMsgAttachmentState KMMsgBase::attachmentState() const
01080 {
01081 KMMsgStatus st = status();
01082 if (st & KMMsgStatusHasAttach)
01083 return KMMsgHasAttachment;
01084 else if (st & KMMsgStatusHasNoAttach)
01085 return KMMsgHasNoAttachment;
01086 else
01087 return KMMsgAttachmentUnknown;
01088 }
01089
01090
01091 static void swapEndian(QString &str)
01092 {
01093 uint len = str.length();
01094 str = QDeepCopy<QString>(str);
01095 QChar *unicode = const_cast<QChar*>( str.unicode() );
01096 for (uint i = 0; i < len; i++)
01097 unicode[i] = kmail_swap_16(unicode[i].unicode());
01098 }
01099
01100
01101 static int g_chunk_length = 0, g_chunk_offset=0;
01102 static uchar *g_chunk = 0;
01103
01104 namespace {
01105 template < typename T > void copy_from_stream( T & x ) {
01106 if( g_chunk_offset + int(sizeof(T)) > g_chunk_length ) {
01107 g_chunk_offset = g_chunk_length;
01108 kdDebug( 5006 ) << "This should never happen.. "
01109 << __FILE__ << ":" << __LINE__ << endl;
01110 x = 0;
01111 } else {
01112
01113
01114 memcpy( &x, g_chunk + g_chunk_offset, sizeof(T) );
01115 g_chunk_offset += sizeof(T);
01116 }
01117 }
01118 }
01119
01120
01121 QString KMMsgBase::getStringPart(MsgPartType t) const
01122 {
01123 retry:
01124 QString ret;
01125
01126 g_chunk_offset = 0;
01127 bool using_mmap = false;
01128 bool swapByteOrder = storage()->indexSwapByteOrder();
01129 if (storage()->indexStreamBasePtr()) {
01130 if (g_chunk)
01131 free(g_chunk);
01132 using_mmap = true;
01133 g_chunk = storage()->indexStreamBasePtr() + mIndexOffset;
01134 g_chunk_length = mIndexLength;
01135 } else {
01136 if(!storage()->mIndexStream)
01137 return ret;
01138 if (g_chunk_length < mIndexLength)
01139 g_chunk = (uchar *)realloc(g_chunk, g_chunk_length = mIndexLength);
01140 off_t first_off=ftell(storage()->mIndexStream);
01141 fseek(storage()->mIndexStream, mIndexOffset, SEEK_SET);
01142 fread( g_chunk, mIndexLength, 1, storage()->mIndexStream);
01143 fseek(storage()->mIndexStream, first_off, SEEK_SET);
01144 }
01145
01146 MsgPartType type;
01147 Q_UINT16 l;
01148 while(g_chunk_offset < mIndexLength) {
01149 Q_UINT32 tmp;
01150 copy_from_stream(tmp);
01151 copy_from_stream(l);
01152 if (swapByteOrder)
01153 {
01154 tmp = kmail_swap_32(tmp);
01155 l = kmail_swap_16(l);
01156 }
01157 type = (MsgPartType) tmp;
01158 if(g_chunk_offset + l > mIndexLength) {
01159 kdDebug(5006) << "This should never happen.. " << __FILE__ << ":" << __LINE__ << endl;
01160 if(using_mmap) {
01161 g_chunk_length = 0;
01162 g_chunk = 0;
01163 }
01164 storage()->recreateIndex();
01165 goto retry;
01166 }
01167 if(type == t) {
01168
01169
01170 if(l)
01171 ret = QString((QChar *)(g_chunk + g_chunk_offset), l/2);
01172 break;
01173 }
01174 g_chunk_offset += l;
01175 }
01176 if(using_mmap) {
01177 g_chunk_length = 0;
01178 g_chunk = 0;
01179 }
01180
01181
01182
01183
01184
01185 #ifndef WORDS_BIGENDIAN
01186
01187 swapEndian(ret);
01188 #else
01189
01190 #endif
01191
01192 return ret;
01193 }
01194
01195
01196 off_t KMMsgBase::getLongPart(MsgPartType t) const
01197 {
01198 retry:
01199 off_t ret = 0;
01200
01201 g_chunk_offset = 0;
01202 bool using_mmap = false;
01203 int sizeOfLong = storage()->indexSizeOfLong();
01204 bool swapByteOrder = storage()->indexSwapByteOrder();
01205 if (storage()->indexStreamBasePtr()) {
01206 if (g_chunk)
01207 free(g_chunk);
01208 using_mmap = true;
01209 g_chunk = storage()->indexStreamBasePtr() + mIndexOffset;
01210 g_chunk_length = mIndexLength;
01211 } else {
01212 if (!storage()->mIndexStream)
01213 return ret;
01214 assert(mIndexLength >= 0);
01215 if (g_chunk_length < mIndexLength)
01216 g_chunk = (uchar *)realloc(g_chunk, g_chunk_length = mIndexLength);
01217 off_t first_off=ftell(storage()->mIndexStream);
01218 fseek(storage()->mIndexStream, mIndexOffset, SEEK_SET);
01219 fread( g_chunk, mIndexLength, 1, storage()->mIndexStream);
01220 fseek(storage()->mIndexStream, first_off, SEEK_SET);
01221 }
01222
01223 MsgPartType type;
01224 Q_UINT16 l;
01225 while (g_chunk_offset < mIndexLength) {
01226 Q_UINT32 tmp;
01227 copy_from_stream(tmp);
01228 copy_from_stream(l);
01229 if (swapByteOrder)
01230 {
01231 tmp = kmail_swap_32(tmp);
01232 l = kmail_swap_16(l);
01233 }
01234 type = (MsgPartType) tmp;
01235
01236 if (g_chunk_offset + l > mIndexLength) {
01237 kdDebug(5006) << "This should never happen.. " << __FILE__ << ":" << __LINE__ << endl;
01238 if(using_mmap) {
01239 g_chunk_length = 0;
01240 g_chunk = 0;
01241 }
01242 storage()->recreateIndex();
01243 goto retry;
01244 }
01245 if(type == t) {
01246 assert(sizeOfLong == l);
01247 if (sizeOfLong == sizeof(ret))
01248 {
01249 copy_from_stream(ret);
01250 if (swapByteOrder)
01251 {
01252 if (sizeof(ret) == 4)
01253 ret = kmail_swap_32(ret);
01254 else
01255 ret = kmail_swap_64(ret);
01256 }
01257 }
01258 else if (sizeOfLong == 4)
01259 {
01260
01261 Q_UINT32 ret_32;
01262 copy_from_stream(ret_32);
01263 if (swapByteOrder)
01264 ret_32 = kmail_swap_32(ret_32);
01265 ret = ret_32;
01266 }
01267 else if (sizeOfLong == 8)
01268 {
01269
01270 Q_UINT32 ret_1;
01271 Q_UINT32 ret_2;
01272 copy_from_stream(ret_1);
01273 copy_from_stream(ret_2);
01274 if (!swapByteOrder)
01275 {
01276
01277 #ifndef WORDS_BIGENDIAN
01278
01279 ret = ret_1;
01280 #else
01281
01282 ret = ret_2;
01283 #endif
01284 }
01285 else
01286 {
01287
01288 #ifndef WORDS_BIGENDIAN
01289
01290 ret = ret_2;
01291 #else
01292
01293 ret = ret_1;
01294 #endif
01295
01296 ret = kmail_swap_32(ret);
01297 }
01298
01299 }
01300 break;
01301 }
01302 g_chunk_offset += l;
01303 }
01304 if(using_mmap) {
01305 g_chunk_length = 0;
01306 g_chunk = 0;
01307 }
01308 return ret;
01309 }
01310
01311 #ifndef WORDS_BIGENDIAN
01312
01313 #define memcpy_networkorder(to, from, len) swab((char *)(from), (char *)(to), len)
01314 #else
01315
01316 #define memcpy_networkorder(to, from, len) memcpy(to, from, len)
01317 #endif
01318
01319 #define STORE_DATA_LEN(type, x, len, network_order) do { \
01320 int len2 = (len > 256) ? 256 : len; \
01321 if(csize < (length + (len2 + sizeof(short) + sizeof(MsgPartType)))) \
01322 ret = (uchar *)realloc(ret, csize += len2+sizeof(short)+sizeof(MsgPartType)); \
01323 Q_UINT32 t = (Q_UINT32) type; memcpy(ret+length, &t, sizeof(t)); \
01324 Q_UINT16 l = len2; memcpy(ret+length+sizeof(t), &l, sizeof(l)); \
01325 if (network_order) \
01326 memcpy_networkorder(ret+length+sizeof(t)+sizeof(l), x, len2); \
01327 else \
01328 memcpy(ret+length+sizeof(t)+sizeof(l), x, len2); \
01329 length += len2+sizeof(t)+sizeof(l); \
01330 } while(0)
01331 #define STORE_DATA(type, x) STORE_DATA_LEN(type, &x, sizeof(x), false)
01332
01333
01334 const uchar *KMMsgBase::asIndexString(int &length) const
01335 {
01336 unsigned int csize = 256;
01337 static uchar *ret = 0;
01338 if(!ret)
01339 ret = (uchar *)malloc(csize);
01340 length = 0;
01341
01342 unsigned long tmp;
01343 QString tmp_str;
01344
01345
01346 tmp_str = msgIdMD5().stripWhiteSpace();
01347 STORE_DATA_LEN(MsgIdMD5Part, tmp_str.unicode(), tmp_str.length() * 2, true);
01348 tmp = mLegacyStatus;
01349 STORE_DATA(MsgLegacyStatusPart, tmp);
01350
01351
01352 tmp_str = fromStrip().stripWhiteSpace();
01353 STORE_DATA_LEN(MsgFromPart, tmp_str.unicode(), tmp_str.length() * 2, true);
01354 tmp_str = subject().stripWhiteSpace();
01355 STORE_DATA_LEN(MsgSubjectPart, tmp_str.unicode(), tmp_str.length() * 2, true);
01356 tmp_str = toStrip().stripWhiteSpace();
01357 STORE_DATA_LEN(MsgToPart, tmp_str.unicode(), tmp_str.length() * 2, true);
01358 tmp_str = replyToIdMD5().stripWhiteSpace();
01359 STORE_DATA_LEN(MsgReplyToIdMD5Part, tmp_str.unicode(), tmp_str.length() * 2, true);
01360 tmp_str = xmark().stripWhiteSpace();
01361 STORE_DATA_LEN(MsgXMarkPart, tmp_str.unicode(), tmp_str.length() * 2, true);
01362 tmp_str = fileName().stripWhiteSpace();
01363 STORE_DATA_LEN(MsgFilePart, tmp_str.unicode(), tmp_str.length() * 2, true);
01364 tmp = msgSize();
01365 STORE_DATA(MsgSizePart, tmp);
01366 tmp = folderOffset();
01367 STORE_DATA(MsgOffsetPart, tmp);
01368 tmp = date();
01369 STORE_DATA(MsgDatePart, tmp);
01370 tmp = (signatureState() << 16) | encryptionState();
01371 STORE_DATA(MsgCryptoStatePart, tmp);
01372 tmp = mdnSentState();
01373 STORE_DATA(MsgMDNSentPart, tmp);
01374
01375 tmp_str = replyToAuxIdMD5().stripWhiteSpace();
01376 STORE_DATA_LEN(MsgReplyToAuxIdMD5Part, tmp_str.unicode(), tmp_str.length() * 2, true);
01377
01378 tmp_str = strippedSubjectMD5().stripWhiteSpace();
01379 STORE_DATA_LEN(MsgStrippedSubjectMD5Part, tmp_str.unicode(), tmp_str.length() * 2, true);
01380
01381 tmp = status();
01382 STORE_DATA(MsgStatusPart, tmp);
01383
01384 tmp = msgSizeServer();
01385 STORE_DATA(MsgSizeServerPart, tmp);
01386 tmp = UID();
01387 STORE_DATA(MsgUIDPart, tmp);
01388
01389 return ret;
01390 }
01391 #undef STORE_DATA_LEN
01392 #undef STORE_DATA
01393
01394 bool KMMsgBase::syncIndexString() const
01395 {
01396 if(!dirty())
01397 return true;
01398 int len;
01399 const uchar *buffer = asIndexString(len);
01400 if (len == mIndexLength) {
01401 Q_ASSERT(storage()->mIndexStream);
01402 fseek(storage()->mIndexStream, mIndexOffset, SEEK_SET);
01403 assert( mIndexOffset > 0 );
01404 fwrite( buffer, len, 1, storage()->mIndexStream);
01405 return true;
01406 }
01407 return false;
01408 }
01409
01410 static QStringList sReplySubjPrefixes, sForwardSubjPrefixes;
01411 static bool sReplaceSubjPrefix, sReplaceForwSubjPrefix;
01412
01413
01414 void KMMsgBase::readConfig()
01415 {
01416 KConfigGroup composerGroup( KMKernel::config(), "Composer" );
01417 sReplySubjPrefixes = composerGroup.readListEntry("reply-prefixes", ',');
01418 if (sReplySubjPrefixes.isEmpty())
01419 sReplySubjPrefixes << "Re\\s*:" << "Re\\[\\d+\\]:" << "Re\\d+:";
01420 sReplaceSubjPrefix = composerGroup.readBoolEntry("replace-reply-prefix", true);
01421 sForwardSubjPrefixes = composerGroup.readListEntry("forward-prefixes", ',');
01422 if (sForwardSubjPrefixes.isEmpty())
01423 sForwardSubjPrefixes << "Fwd:" << "FW:";
01424 sReplaceForwSubjPrefix = composerGroup.readBoolEntry("replace-forward-prefix", true);
01425 }
01426
01427
01428
01429 QString KMMsgBase::stripOffPrefixes( const QString& str )
01430 {
01431 return replacePrefixes( str, sReplySubjPrefixes + sForwardSubjPrefixes,
01432 true, QString::null ).stripWhiteSpace();
01433 }
01434
01435
01436
01437 QString KMMsgBase::replacePrefixes( const QString& str,
01438 const QStringList& prefixRegExps,
01439 bool replace,
01440 const QString& newPrefix )
01441 {
01442 bool recognized = false;
01443
01444
01445
01446 QString bigRegExp = QString::fromLatin1("^(?:\\s+|(?:%1))+\\s*")
01447 .arg( prefixRegExps.join(")|(?:") );
01448 QRegExp rx( bigRegExp, false );
01449 if ( !rx.isValid() ) {
01450 kdWarning(5006) << "KMMessage::replacePrefixes(): bigRegExp = \""
01451 << bigRegExp << "\"\n"
01452 << "prefix regexp is invalid!" << endl;
01453
01454 recognized = str.startsWith( newPrefix );
01455 } else {
01456 QString tmp = str;
01457 if ( rx.search( tmp ) == 0 ) {
01458 recognized = true;
01459 if ( replace )
01460 return tmp.replace( 0, rx.matchedLength(), newPrefix + ' ' );
01461 }
01462 }
01463 if ( !recognized )
01464 return newPrefix + ' ' + str;
01465 else
01466 return str;
01467 }
01468
01469
01470 QString KMMsgBase::cleanSubject() const
01471 {
01472 return cleanSubject( sReplySubjPrefixes + sForwardSubjPrefixes,
01473 true, QString::null ).stripWhiteSpace();
01474 }
01475
01476
01477 QString KMMsgBase::cleanSubject( const QStringList & prefixRegExps,
01478 bool replace,
01479 const QString & newPrefix ) const
01480 {
01481 return KMMsgBase::replacePrefixes( subject(), prefixRegExps, replace,
01482 newPrefix );
01483 }
01484
01485
01486 QString KMMsgBase::forwardSubject() const {
01487 return cleanSubject( sForwardSubjPrefixes, sReplaceForwSubjPrefix, "Fwd:" );
01488 }
01489
01490
01491 QString KMMsgBase::replySubject() const {
01492 return cleanSubject( sReplySubjPrefixes, sReplaceSubjPrefix, "Re:" );
01493 }