00001
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
00036
00037
00038
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
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
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
00087
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
00136
00137
if (aStatus == KMMsgStatusWatched)
00138 mStatus &= ~KMMsgStatusIgnored;
00139
if (aStatus == KMMsgStatusIgnored) {
00140 mStatus &= ~KMMsgStatusWatched;
00141
00142
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
00169 mStatus &= ~KMMsgStatusUnread;
00170 mStatus &= ~KMMsgStatusNew;
00171 mStatus |= KMMsgStatusRead;
00172
break;
00173
00174
case KMMsgStatusUnread:
00175
00176 mStatus &= ~KMMsgStatusOld;
00177 mStatus &= ~KMMsgStatusRead;
00178 mStatus &= ~KMMsgStatusNew;
00179 mStatus |= KMMsgStatusUnread;
00180
break;
00181
00182
case KMMsgStatusOld:
00183
00184 mStatus &= ~KMMsgStatusNew;
00185 mStatus &= ~KMMsgStatusUnread;
00186 mStatus |= KMMsgStatusOld;
00187
break;
00188
00189
case KMMsgStatusNew:
00190
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
00225
case KMMsgStatusWatched:
00226 mStatus &= ~KMMsgStatusIgnored;
00227 mStatus |= KMMsgStatusWatched;
00228
break;
00229
00230
case KMMsgStatusIgnored:
00231 mStatus &= ~KMMsgStatusWatched;
00232 mStatus |= KMMsgStatusIgnored;
00233
break;
00234
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
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
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 ,
int idx )
00305 {
00306
00307 mDirty = TRUE;
00308
if (storage())
00309 storage()->headerOfMsgChanged(
this, idx);
00310 }
00311
00312
void KMMsgBase::setEncryptionStateChar(
QChar status,
int idx )
00313 {
00314
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 ,
int idx )
00330 {
00331
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
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
00494
if (status() & KMMsgStatusWatched) sstr[0] =
'a';
00495
if (status() & KMMsgStatusIgnored) sstr[0] =
'c';
00496
00497
00498
if (status() & KMMsgStatusNew) sstr[1] =
'a';
00499
if (status() & KMMsgStatusUnread) sstr[1] =
'b';
00500
00501
00502
00503
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)
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
00610
00611
00612
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() );
00620
char * d = result.data();
00621
00622
for (
const char * s = header.data() ; *s ; )
00623
if ( *s ==
'\r' ) {
00624 ++s;
00625
continue;
00626 }
else if ( *s ==
'\n' ) {
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
00661
00662
00663
if ( lastWasEncodedWord && isBlank( pos[0] ) ) {
00664 LWSP_buffer += pos[0];
00665
continue;
00666 }
00667
00668
if (pos[0]!=
'=' || pos[1]!=
'?') {
00669 result += LWSP_buffer + pos[0];
00670 LWSP_buffer = 0;
00671 lastWasEncodedWord = FALSE;
00672
continue;
00673 }
00674
00675
const char *
const beg = pos;
00676 {
00677
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
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;
00693
const char * enc_start = pos;
00694
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
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;
00716 LWSP_buffer = 0;
00717 }
00718
continue;
00719 invalid_encoded_word:
00720
00721 pos = beg;
00722 result += LWSP_buffer;
00723 result +=
"=?";
00724 lastWasEncodedWord =
false;
00725 ++pos;
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
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() );
00926
else
00927
return base64EncodedMD5( s.stripWhiteSpace().latin1() );
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
01077
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
01127
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
01139
01140
01141
01142
01143
#ifndef WORDS_BIGENDIAN
01144
01145 swapEndian(ret);
01146
#else
01147
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
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
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
01229
#ifndef WORDS_BIGENDIAN
01230
01231 ret = ret_1;
01232
#else
01233
01234 ret = ret_2;
01235
#endif
01236
}
01237
else
01238 {
01239
01240
#ifndef WORDS_BIGENDIAN
01241
01242 ret = ret_2;
01243
#else
01244
01245 ret = ret_1;
01246
#endif
01247
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
01265
#define memcpy_networkorder(to, from, len) swab((char *)(from), (char *)(to), len)
01266
#else
01267
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;
01290
if(!ret)
01291 ret = (uchar *)malloc(csize);
01292 length = 0;
01293
01294
unsigned long tmp;
01295
QString tmp_str;
01296
01297
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
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
01381
QString KMMsgBase::stripOffPrefixes(
const QString& str )
01382 {
01383
return replacePrefixes( str, sReplySubjPrefixes + sForwardSubjPrefixes,
01384
true, QString::null ).stripWhiteSpace();
01385 }
01386
01387
01388
01389
QString KMMsgBase::replacePrefixes(
const QString& str,
01390
const QStringList& prefixRegExps,
01391
bool replace,
01392
const QString& newPrefix )
01393 {
01394
bool recognized =
false;
01395
01396
01397
01398
QString bigRegExp = QString::fromLatin1(
"^(?:\\s+|(?:%1))+\\s*")
01399 .arg( prefixRegExps.join(
")|(?:") );
01400
QRegExp rx( bigRegExp,
false );
01401
if ( !rx.isValid() ) {
01402 kdWarning(5006) <<
"KMMessage::replacePrefixes(): bigRegExp = \""
01403 << bigRegExp <<
"\"\n"
01404 <<
"prefix regexp is invalid!" << endl;
01405
01406 recognized = str.startsWith( newPrefix );
01407 }
else {
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 }