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 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
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
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 , int idx )
00309 {
00310
00311 mDirty = true;
00312 if (storage())
00313 storage()->headerOfMsgChanged(this, idx);
00314 }
00315
00316 void KMMsgBase::setEncryptionStateChar( QChar status, int idx )
00317 {
00318
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 , int idx )
00334 {
00335
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( QChar status, int idx )
00348 {
00349
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 QCString KMMsgBase::statusToStr(const KMMsgStatus status)
00477 {
00478 QCString 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 QString KMMsgBase::statusToSortRank()
00502 {
00503 QString sstr = "bcbbbbbbbb";
00504
00505
00506 if (status() & KMMsgStatusWatched) sstr[0] = 'a';
00507 if (status() & KMMsgStatusIgnored) sstr[0] = 'c';
00508
00509
00510 if (status() & KMMsgStatusNew) sstr[1] = 'a';
00511 if (status() & KMMsgStatusUnread) sstr[1] = 'b';
00512
00513
00514
00515
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 QCString& aDateStr)
00532 {
00533 setDate( KRFCDate::parseDate( aDateStr ) );
00534 }
00535
00536
00537
00538 QString KMMsgBase::dateStr(void) const
00539 {
00540 time_t d = date();
00541 return KMime::DateFormatter::formatDate(KMime::DateFormatter::Fancy, d);
00542 }
00543
00544
00545
00546 QString KMMsgBase::skipKeyword(const QString& aStr, QChar sepChar,
00547 bool* hasKeyword)
00548 {
00549 unsigned int i = 0, maxChars = 3;
00550 QString 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)
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 QTextCodec* KMMsgBase::codecForName(const QCString& _str)
00575 {
00576 if (_str.isEmpty()) return 0;
00577 QCString codec = _str;
00578 KPIM::kAsciiToLower(codec.data());
00579 return KGlobal::charsets()->codecForName(codec);
00580 }
00581
00582
00583
00584 QCString KMMsgBase::toUsAscii(const QString& _str, bool *ok)
00585 {
00586 bool all_ok =true;
00587 QString 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 QStringList KMMsgBase::supportedEncodings(bool usAscii)
00602 {
00603 QStringList encodingNames = KGlobal::charsets()->availableEncodingNames();
00604 QStringList encodings;
00605 QMap<QString,bool> mimeNames;
00606 for (QStringList::Iterator it = encodingNames.begin();
00607 it != encodingNames.end(); it++)
00608 {
00609 QTextCodec *codec = KGlobal::charsets()->codecForName(*it);
00610 QString mimeName = (codec) ? QString(codec->mimeName()).lower() : (*it);
00611 if (mimeNames.find(mimeName) == mimeNames.end())
00612 {
00613 encodings.append(KGlobal::charsets()->languageForEncoding(*it)
00614 + " ( " + mimeName + " )");
00615 mimeNames.insert(mimeName, true);
00616 }
00617 }
00618 encodings.sort();
00619 if (usAscii) encodings.prepend(KGlobal::charsets()
00620 ->languageForEncoding("us-ascii") + " ( us-ascii )");
00621 return encodings;
00622 }
00623
00624 namespace {
00625
00626
00627
00628
00629 inline bool isBlank( char ch ) { return ch == ' ' || ch == '\t' ; }
00630
00631 QCString unfold( const QCString & header ) {
00632 if ( header.isEmpty() )
00633 return QCString();
00634
00635 QCString result( header.size() );
00636 char * d = result.data();
00637
00638 for ( const char * s = header.data() ; *s ; )
00639 if ( *s == '\r' ) {
00640 ++s;
00641 continue;
00642 } else if ( *s == '\n' ) {
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 QString KMMsgBase::decodeRFC2047String(const QCString& aStr, QCString prefCharset)
00659 {
00660 if ( aStr.isEmpty() )
00661 return QString::null;
00662
00663 const QCString str = unfold( aStr );
00664
00665 if ( str.isEmpty() )
00666 return QString::null;
00667
00668 if ( str.find( "=?" ) < 0 ) {
00669 if ( !prefCharset.isEmpty() &&
00670 kmkernel->isCodecAsciiCompatible( KMMsgBase::codecForName( prefCharset ) ) ) {
00671 if ( prefCharset == "us-ascii" ) {
00672
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
00686 return QString::fromAscii( str );
00687 }
00688
00689 QString result;
00690 QCString LWSP_buffer;
00691 bool lastWasEncodedWord = false;
00692
00693 for ( const char * pos = str.data() ; *pos ; ++pos ) {
00694
00695
00696
00697 if ( lastWasEncodedWord && isBlank( pos[0] ) ) {
00698 LWSP_buffer += pos[0];
00699 continue;
00700 }
00701
00702 if (pos[0]!='=' || pos[1]!='?') {
00703 result += LWSP_buffer + pos[0];
00704 LWSP_buffer = 0;
00705 lastWasEncodedWord = false;
00706 continue;
00707 }
00708
00709 const char * const beg = pos;
00710 {
00711
00712 QCString 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
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;
00728 const char * enc_start = pos;
00729
00730 while ( *pos && !(*pos=='?' && *(pos+1)=='=') ) {
00731 i++;
00732 pos++;
00733 }
00734 if ( !*pos )
00735 goto invalid_encoded_word;
00736
00737
00738 const KMime::Codec * c = KMime::Codec::codecForName( encoding );
00739 kdFatal( !c, 5006 ) << "No \"" << encoding << "\" codec!?" << endl;
00740
00741 QByteArray in; in.setRawData( enc_start, pos - enc_start );
00742 const QByteArray enc = c->decode( in );
00743 in.resetRawData( enc_start, pos - enc_start );
00744
00745 const QTextCodec * codec = codecForName(charset);
00746 if (!codec) codec = kmkernel->networkCodec();
00747 result += codec->toUnicode(enc);
00748 lastWasEncodedWord = true;
00749
00750 ++pos;
00751 LWSP_buffer = 0;
00752 }
00753 continue;
00754 invalid_encoded_word:
00755
00756 pos = beg;
00757 if ( !LWSP_buffer.isNull() )
00758 result += LWSP_buffer;
00759 result += "=?";
00760 lastWasEncodedWord = false;
00761 ++pos;
00762 LWSP_buffer = 0;
00763 }
00764 return result;
00765 }
00766
00767
00768
00769 static const QCString especials = "()<>@,;:\"/[]?.= \033";
00770
00771 QCString KMMsgBase::encodeRFC2047Quoted( const QCString & 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 QByteArray in; in.setRawData( s.data(), s.length() );
00776 const QByteArray result = codec->encode( in );
00777 in.resetRawData( s.data(), s.length() );
00778 return QCString( result.data(), result.size() + 1 );
00779 }
00780
00781 QCString KMMsgBase::encodeRFC2047String(const QString& _str,
00782 const QCString& charset)
00783 {
00784 static const QString dontQuote = "\"()<>,@";
00785
00786 if (_str.isEmpty()) return QCString();
00787 if (charset == "us-ascii") return toUsAscii(_str);
00788
00789 QCString cset;
00790 if (charset.isEmpty())
00791 {
00792 cset = kmkernel->networkCodec()->mimeName();
00793 KPIM::kAsciiToLower(cset.data());
00794 }
00795 else cset = charset;
00796
00797 const QTextCodec *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 QCString 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 QCString KMMsgBase::encodeRFC2231String( const QString& _str,
00875 const QCString& charset )
00876 {
00877 if ( _str.isEmpty() )
00878 return QCString();
00879
00880 QCString cset;
00881 if ( charset.isEmpty() )
00882 {
00883 cset = kmkernel->networkCodec()->mimeName();
00884 KPIM::kAsciiToLower( cset.data() );
00885 }
00886 else
00887 cset = charset;
00888 const QTextCodec *codec = codecForName( cset );
00889 QCString 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
00901 break;
00902 }
00903 if ( !*l )
00904 return latin;
00905
00906 QCString 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 QCString KMMsgBase::encodeRFC2231StringAutoDetectCharset( const QString &str,
00937 const QCString &defaultCharset )
00938 {
00939 QCString 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 QString KMMsgBase::decodeRFC2231String(const QCString& _str)
00948 {
00949 int p = _str.find('\'');
00950 if (p < 0) return kmkernel->networkCodec()->toUnicode(_str);
00951
00952 QCString charset = _str.left(p);
00953
00954 QCString 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 QString result;
00971 const QTextCodec * codec = codecForName( charset );
00972 if ( !codec )
00973 codec = kmkernel->networkCodec();
00974 return codec->toUnicode( st );
00975 }
00976
00977 QCString KMMsgBase::extractRFC2231HeaderField( const QCString &aStr, const QCString &field )
00978 {
00979 int n=-1;
00980 QCString str;
00981 bool found = false;
00982 while ( n<=0 || found ) {
00983 QString pattern( field );
00984 pattern += "[*]";
00985 if ( n>=0 ) {
00986 pattern += QString::number(n) + "[*]?";
00987 }
00988 pattern += "=";
00989
00990 QRegExp fnamePart( pattern, false );
00991 int startPart = fnamePart.search( aStr );
00992 int endPart;
00993 found = ( startPart >= 0 );
00994 if ( found ) {
00995 startPart += fnamePart.matchedLength();
00996
00997 if ( aStr[startPart] == '"' ) {
00998 startPart++;
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 QString KMMsgBase::base64EncodedMD5( const QString & s, bool utf8 ) {
01014 if (s.stripWhiteSpace().isEmpty()) return "";
01015 if ( utf8 )
01016 return base64EncodedMD5( s.stripWhiteSpace().utf8() );
01017 else
01018 return base64EncodedMD5( s.stripWhiteSpace().latin1() );
01019 }
01020
01021 QString KMMsgBase::base64EncodedMD5( const QCString & s ) {
01022 if (s.stripWhiteSpace().isEmpty()) return "";
01023 return base64EncodedMD5( s.stripWhiteSpace().data() );
01024 }
01025
01026 QString 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 QCString KMMsgBase::autoDetectCharset(const QCString &_encoding, const QStringList &encodingList, const QString &text)
01036 {
01037 QStringList charsets = encodingList;
01038 if (!_encoding.isEmpty())
01039 {
01040 QString currentCharset = QString::fromLatin1(_encoding);
01041 charsets.remove(currentCharset);
01042 charsets.prepend(currentCharset);
01043 }
01044
01045 QStringList::ConstIterator it = charsets.begin();
01046 for (; it != charsets.end(); ++it)
01047 {
01048 QCString 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 QTextCodec *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(QString &str)
01119 {
01120 uint len = str.length();
01121 str = QDeepCopy<QString>(str);
01122 QChar *unicode = const_cast<QChar*>( 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
01140
01141 memcpy( &x, g_chunk + g_chunk_offset, sizeof(T) );
01142 g_chunk_offset += sizeof(T);
01143 }
01144 }
01145 }
01146
01147
01148 QString KMMsgBase::getStringPart(MsgPartType t) const
01149 {
01150 retry:
01151 QString 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 Q_UINT16 l;
01175 while(g_chunk_offset < mIndexLength) {
01176 Q_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
01196
01197 if(l)
01198 ret = QString((QChar *)(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
01208
01209
01210
01211
01212 #ifndef WORDS_BIGENDIAN
01213
01214 swapEndian(ret);
01215 #else
01216
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 bool using_mmap = false;
01229 bool swapByteOrder = storage()->indexSwapByteOrder();
01230 int sizeOfLong = storage()->indexSizeOfLong();
01231 if (storage()->indexStreamBasePtr()) {
01232 if (g_chunk)
01233 free(g_chunk);
01234 using_mmap = true;
01235 g_chunk = storage()->indexStreamBasePtr() + mIndexOffset;
01236 g_chunk_length = mIndexLength;
01237 } else {
01238 if (!storage()->mIndexStream)
01239 return ret;
01240 assert(mIndexLength >= 0);
01241 if (g_chunk_length < mIndexLength)
01242 g_chunk = (uchar *)realloc(g_chunk, g_chunk_length = mIndexLength);
01243 off_t first_off = ftell(storage()->mIndexStream);
01244 fseek(storage()->mIndexStream, mIndexOffset, SEEK_SET);
01245 fread( g_chunk, mIndexLength, 1, storage()->mIndexStream);
01246 fseek(storage()->mIndexStream, first_off, SEEK_SET);
01247 }
01248
01249 Q_UINT16 len;
01250 for ( g_chunk_offset = 0; g_chunk_offset < mIndexLength; g_chunk_offset += len ) {
01251 Q_UINT32 tmp;
01252 copy_from_stream(tmp);
01253 copy_from_stream(len);
01254 if (swapByteOrder)
01255 {
01256 tmp = kmail_swap_32(tmp);
01257 len = kmail_swap_16(len);
01258 }
01259 MsgPartType type = (MsgPartType) tmp;
01260
01261 if (g_chunk_offset + len > mIndexLength) {
01262 kdDebug() << "This should never happen..";
01263 if(using_mmap) {
01264 g_chunk_length = 0;
01265 g_chunk = 0;
01266 }
01267 if (!storage()->recreateIndex())
01268 return 0;
01269 goto retry;
01270 }
01271 if(type == t) {
01272 assert(sizeOfLong == len);
01273 if (sizeOfLong == sizeof(ret))
01274 {
01275 copy_from_stream(ret);
01276 if (swapByteOrder)
01277 {
01278 if (sizeof(ret) == 4)
01279 ret = kmail_swap_32(ret);
01280 else
01281 ret = kmail_swap_64(ret);
01282 }
01283 }
01284 else if (sizeOfLong == 4)
01285 {
01286
01287 Q_UINT32 ret_32;
01288 copy_from_stream(ret_32);
01289 if (swapByteOrder)
01290 ret_32 = kmail_swap_32(ret_32);
01291 ret = ret_32;
01292 }
01293 else if (sizeOfLong == 8)
01294 {
01295
01296 Q_UINT32 ret_1;
01297 Q_UINT32 ret_2;
01298 copy_from_stream(ret_1);
01299 copy_from_stream(ret_2);
01300 if (!swapByteOrder)
01301 {
01302
01303 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
01304
01305 ret = ret_1;
01306 #else
01307
01308 ret = ret_2;
01309 #endif
01310 }
01311 else
01312 {
01313
01314 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
01315
01316 ret = ret_2;
01317 #else
01318
01319 ret = ret_1;
01320 #endif
01321
01322
01323
01324 ret = kmail_swap_32(ret);
01325 }
01326
01327 }
01328 break;
01329 }
01330 }
01331 if(using_mmap) {
01332 g_chunk_length = 0;
01333 g_chunk = 0;
01334 }
01335
01336 return ret;
01337 }
01338
01339 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
01340
01341 #define memcpy_networkorder(to, from, len) swab((char *)(from), (char *)(to), len)
01342 #else
01343
01344 #define memcpy_networkorder(to, from, len) memcpy(to, from, len)
01345 #endif
01346
01347 #define STORE_DATA_LEN(type, x, len, network_order) \
01348 do { \
01349 int len2 = (len > 256) ? 256 : len; \
01350 if(csize < (length + (len2 + sizeof(short) + sizeof(MsgPartType)))) \
01351 ret = (uchar *)realloc(ret, csize += len2+sizeof(short)+sizeof(MsgPartType)); \
01352 Q_UINT32 t = (Q_UINT32) type; memcpy(ret+length, &t, sizeof(t)); \
01353 Q_UINT16 l = len2; memcpy(ret+length+sizeof(t), &l, sizeof(l)); \
01354 if (network_order) \
01355 memcpy_networkorder(ret+length+sizeof(t)+sizeof(l), x, len2); \
01356 else \
01357 memcpy(ret+length+sizeof(t)+sizeof(l), x, len2); \
01358 length += len2+sizeof(t)+sizeof(l); \
01359 } while(0)
01360
01361 #define STORE_DATA(type, x) STORE_DATA_LEN(type, &x, sizeof(x), false)
01362
01363
01364 const uchar *KMMsgBase::asIndexString(int &length) const
01365 {
01366 unsigned int csize = 256;
01367 static uchar *ret = 0;
01368 if(!ret)
01369 ret = (uchar *)malloc(csize);
01370 length = 0;
01371
01372 unsigned long tmp;
01373 QString tmp_str;
01374
01375
01376 tmp_str = msgIdMD5().stripWhiteSpace();
01377 STORE_DATA_LEN(MsgIdMD5Part, tmp_str.unicode(), tmp_str.length() * 2, true);
01378 tmp = mLegacyStatus;
01379 STORE_DATA(MsgLegacyStatusPart, tmp);
01380
01381
01382 tmp_str = fromStrip().stripWhiteSpace();
01383 STORE_DATA_LEN(MsgFromStripPart, tmp_str.unicode(), tmp_str.length() * 2, true);
01384 tmp_str = subject().stripWhiteSpace();
01385 STORE_DATA_LEN(MsgSubjectPart, tmp_str.unicode(), tmp_str.length() * 2, true);
01386 tmp_str = toStrip().stripWhiteSpace();
01387 STORE_DATA_LEN(MsgToStripPart, tmp_str.unicode(), tmp_str.length() * 2, true);
01388 tmp_str = replyToIdMD5().stripWhiteSpace();
01389 STORE_DATA_LEN(MsgReplyToIdMD5Part, tmp_str.unicode(), tmp_str.length() * 2, true);
01390 tmp_str = xmark().stripWhiteSpace();
01391 STORE_DATA_LEN(MsgXMarkPart, tmp_str.unicode(), tmp_str.length() * 2, true);
01392 tmp_str = fileName().stripWhiteSpace();
01393 STORE_DATA_LEN(MsgFilePart, tmp_str.unicode(), tmp_str.length() * 2, true);
01394 tmp = msgSize();
01395 STORE_DATA(MsgSizePart, tmp);
01396 tmp = folderOffset();
01397 STORE_DATA(MsgOffsetPart, tmp);
01398 tmp = date();
01399 STORE_DATA(MsgDatePart, tmp);
01400 tmp = (signatureState() << 16) | encryptionState();
01401 STORE_DATA(MsgCryptoStatePart, tmp);
01402 tmp = mdnSentState();
01403 STORE_DATA(MsgMDNSentPart, tmp);
01404
01405 tmp_str = replyToAuxIdMD5().stripWhiteSpace();
01406 STORE_DATA_LEN(MsgReplyToAuxIdMD5Part, tmp_str.unicode(), tmp_str.length() * 2, true);
01407
01408 tmp_str = strippedSubjectMD5().stripWhiteSpace();
01409 STORE_DATA_LEN(MsgStrippedSubjectMD5Part, tmp_str.unicode(), tmp_str.length() * 2, true);
01410
01411 tmp = status();
01412 STORE_DATA(MsgStatusPart, tmp);
01413
01414 tmp = msgSizeServer();
01415 STORE_DATA(MsgSizeServerPart, tmp);
01416 tmp = UID();
01417 STORE_DATA(MsgUIDPart, tmp);
01418
01419 tmp_str = from();
01420 STORE_DATA_LEN( MsgFromPart, tmp_str.unicode(), tmp_str.length() * 2, true );
01421
01422 tmp_str = to();
01423 STORE_DATA_LEN( MsgToPart, tmp_str.unicode(), tmp_str.length() * 2, true );
01424
01425 return ret;
01426 }
01427 #undef STORE_DATA_LEN
01428 #undef STORE_DATA
01429
01430 bool KMMsgBase::syncIndexString() const
01431 {
01432 if(!dirty())
01433 return true;
01434 int len;
01435 const uchar *buffer = asIndexString(len);
01436 if (len == mIndexLength) {
01437 Q_ASSERT(storage()->mIndexStream);
01438 fseek(storage()->mIndexStream, mIndexOffset, SEEK_SET);
01439 assert( mIndexOffset > 0 );
01440 fwrite( buffer, len, 1, storage()->mIndexStream);
01441 return true;
01442 }
01443 return false;
01444 }
01445
01446 static QStringList sReplySubjPrefixes, sForwardSubjPrefixes;
01447 static bool sReplaceSubjPrefix, sReplaceForwSubjPrefix;
01448
01449
01450 void KMMsgBase::readConfig()
01451 {
01452 KConfigGroup composerGroup( KMKernel::config(), "Composer" );
01453 sReplySubjPrefixes = composerGroup.readListEntry("reply-prefixes", ',');
01454 if (sReplySubjPrefixes.isEmpty())
01455 sReplySubjPrefixes << "Re\\s*:" << "Re\\[\\d+\\]:" << "Re\\d+:";
01456 sReplaceSubjPrefix = composerGroup.readBoolEntry("replace-reply-prefix", true);
01457 sForwardSubjPrefixes = composerGroup.readListEntry("forward-prefixes", ',');
01458 if (sForwardSubjPrefixes.isEmpty())
01459 sForwardSubjPrefixes << "Fwd:" << "FW:";
01460 sReplaceForwSubjPrefix = composerGroup.readBoolEntry("replace-forward-prefix", true);
01461 }
01462
01463
01464
01465 QString KMMsgBase::stripOffPrefixes( const QString& str )
01466 {
01467 return replacePrefixes( str, sReplySubjPrefixes + sForwardSubjPrefixes,
01468 true, QString::null ).stripWhiteSpace();
01469 }
01470
01471
01472
01473 QString KMMsgBase::replacePrefixes( const QString& str,
01474 const QStringList& prefixRegExps,
01475 bool replace,
01476 const QString& newPrefix )
01477 {
01478 bool recognized = false;
01479
01480
01481
01482 QString bigRegExp = QString::fromLatin1("^(?:\\s+|(?:%1))+\\s*")
01483 .arg( prefixRegExps.join(")|(?:") );
01484 QRegExp rx( bigRegExp, false );
01485 if ( !rx.isValid() ) {
01486 kdWarning(5006) << "KMMessage::replacePrefixes(): bigRegExp = \""
01487 << bigRegExp << "\"\n"
01488 << "prefix regexp is invalid!" << endl;
01489
01490 recognized = str.startsWith( newPrefix );
01491 } else {
01492 QString tmp = str;
01493 if ( rx.search( tmp ) == 0 ) {
01494 recognized = true;
01495 if ( replace )
01496 return tmp.replace( 0, rx.matchedLength(), newPrefix + ' ' );
01497 }
01498 }
01499 if ( !recognized )
01500 return newPrefix + ' ' + str;
01501 else
01502 return str;
01503 }
01504
01505
01506 QString KMMsgBase::cleanSubject() const
01507 {
01508 return cleanSubject( sReplySubjPrefixes + sForwardSubjPrefixes,
01509 true, QString::null ).stripWhiteSpace();
01510 }
01511
01512
01513 QString KMMsgBase::cleanSubject( const QStringList & prefixRegExps,
01514 bool replace,
01515 const QString & newPrefix ) const
01516 {
01517 return KMMsgBase::replacePrefixes( subject(), prefixRegExps, replace,
01518 newPrefix );
01519 }
01520
01521
01522 QString KMMsgBase::forwardSubject() const {
01523 return cleanSubject( sForwardSubjPrefixes, sReplaceForwSubjPrefix, "Fwd:" );
01524 }
01525
01526
01527 QString KMMsgBase::replySubject() const {
01528 return cleanSubject( sReplySubjPrefixes, sReplaceSubjPrefix, "Re:" );
01529 }