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