5 #include "globalsettings.h" 8 #include "kmfolderindex.h" 10 #include "kmheaders.h" 11 #include "kmmsgdict.h" 12 #include "messageproperty.h" 13 using KMail::MessageProperty;
16 #include <tdeglobal.h> 17 #include <kcharsets.h> 18 #include <kasciistringtools.h> 22 #include <mimelib/mimepp.h> 23 #include <kmime_codecs.h> 25 #include <tqtextcodec.h> 26 #include <tqdeepcopy.h> 33 #ifdef HAVE_BYTESWAP_H 42 #define kmail_swap_16(x) bswap_16(x) 44 #define kmail_swap_16(x) \ 45 ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)) 50 #define kmail_swap_32(x) bswap_32(x) 52 #define kmail_swap_32(x) \ 53 ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ 54 (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) 59 #define kmail_swap_64(x) bswap_64(x) 61 #define kmail_swap_64(x) \ 62 ((((x) & 0xff00000000000000ull) >> 56) \ 63 | (((x) & 0x00ff000000000000ull) >> 40) \ 64 | (((x) & 0x0000ff0000000000ull) >> 24) \ 65 | (((x) & 0x000000ff00000000ull) >> 8) \ 66 | (((x) & 0x00000000ff000000ull) << 8) \ 67 | (((x) & 0x0000000000ff0000ull) << 24) \ 68 | (((x) & 0x000000000000ff00ull) << 40) \ 69 | (((x) & 0x00000000000000ffull) << 56)) 73 KMMsgBase::KMMsgBase(
KMFolder* aParentFolder)
74 : mParent( aParentFolder ), mIndexOffset( 0 ),
75 mIndexLength( 0 ), mDirty( false ), mEnableUndo( false ), mStatus( KMMsgStatusUnknown )
81 KMMsgBase::~KMMsgBase()
83 MessageProperty::forget(
this );
96 void KMMsgBase::assign(
const KMMsgBase* other)
98 mParent = other->mParent;
100 mIndexOffset = other->mIndexOffset;
101 mIndexLength = other->mIndexLength;
105 KMMsgBase& KMMsgBase::operator=(
const KMMsgBase& other)
113 KMMsgBase::KMMsgBase(
const KMMsgBase& other )
119 bool KMMsgBase::isMessage(
void)
const 124 void KMMsgBase::toggleStatus(
const KMMsgStatus aStatus,
int idx)
127 KMMsgStatus oldStatus =
status();
128 if (
status() & aStatus ) {
134 if (aStatus == KMMsgStatusWatched)
135 mStatus &= ~KMMsgStatusIgnored;
136 if (aStatus == KMMsgStatusIgnored)
137 mStatus &= ~KMMsgStatusWatched;
138 if (aStatus == KMMsgStatusSpam)
139 mStatus &= ~KMMsgStatusHam;
140 if (aStatus == KMMsgStatusHam)
141 mStatus &= ~KMMsgStatusSpam;
145 idx = storage()->find(
this );
146 storage()->msgStatusChanged( oldStatus,
status(), idx );
147 storage()->headerOfMsgChanged(
this, idx);
153 void KMMsgBase::setStatus(
const KMMsgStatus aStatus,
int idx)
156 KMMsgStatus oldStatus =
status();
158 case KMMsgStatusRead:
160 mStatus &= ~KMMsgStatusUnread;
161 mStatus &= ~KMMsgStatusNew;
162 mStatus |= KMMsgStatusRead;
165 case KMMsgStatusUnread:
167 mStatus &= ~KMMsgStatusOld;
168 mStatus &= ~KMMsgStatusRead;
169 mStatus &= ~KMMsgStatusNew;
170 mStatus |= KMMsgStatusUnread;
175 mStatus &= ~KMMsgStatusNew;
176 mStatus &= ~KMMsgStatusUnread;
177 mStatus |= KMMsgStatusOld;
182 mStatus &= ~KMMsgStatusOld;
183 mStatus &= ~KMMsgStatusRead;
184 mStatus &= ~KMMsgStatusUnread;
185 mStatus |= KMMsgStatusNew;
188 case KMMsgStatusDeleted:
189 mStatus |= KMMsgStatusDeleted;
192 case KMMsgStatusReplied:
193 mStatus |= KMMsgStatusReplied;
196 case KMMsgStatusForwarded:
197 mStatus |= KMMsgStatusForwarded;
200 case KMMsgStatusQueued:
201 mStatus |= KMMsgStatusQueued;
204 case KMMsgStatusTodo:
205 mStatus |= KMMsgStatusTodo;
208 case KMMsgStatusSent:
209 mStatus &= ~KMMsgStatusQueued;
210 mStatus &= ~KMMsgStatusUnread;
211 mStatus &= ~KMMsgStatusNew;
212 mStatus |= KMMsgStatusSent;
215 case KMMsgStatusFlag:
216 mStatus |= KMMsgStatusFlag;
220 case KMMsgStatusWatched:
221 mStatus &= ~KMMsgStatusIgnored;
222 mStatus |= KMMsgStatusWatched;
225 case KMMsgStatusIgnored:
226 mStatus &= ~KMMsgStatusWatched;
227 mStatus |= KMMsgStatusIgnored;
230 case KMMsgStatusSpam:
231 mStatus &= ~KMMsgStatusHam;
232 mStatus |= KMMsgStatusSpam;
235 mStatus &= ~KMMsgStatusSpam;
236 mStatus |= KMMsgStatusHam;
238 case KMMsgStatusHasAttach:
239 mStatus &= ~KMMsgStatusHasNoAttach;
240 mStatus |= KMMsgStatusHasAttach;
242 case KMMsgStatusHasNoAttach:
243 mStatus &= ~KMMsgStatusHasAttach;
244 mStatus |= KMMsgStatusHasNoAttach;
246 case KMMsgStatusHasInvitation:
247 mStatus &= ~KMMsgStatusHasNoInvitation;
248 mStatus |= KMMsgStatusHasInvitation;
250 case KMMsgStatusHasNoInvitation:
251 mStatus &= ~KMMsgStatusHasInvitation;
252 mStatus |= KMMsgStatusHasNoInvitation;
259 if ( oldStatus != mStatus && storage() ) {
261 idx = storage()->find(
this );
262 storage()->msgStatusChanged( oldStatus,
status(), idx );
263 storage()->headerOfMsgChanged(
this, idx );
270 void KMMsgBase::setStatus(
const char* aStatusStr,
const char* aXStatusStr)
274 if (strchr(aXStatusStr,
'N'))
setStatus(KMMsgStatusNew);
275 if (strchr(aXStatusStr,
'U'))
setStatus(KMMsgStatusUnread);
276 if (strchr(aXStatusStr,
'O'))
setStatus(KMMsgStatusOld);
277 if (strchr(aXStatusStr,
'R'))
setStatus(KMMsgStatusRead);
278 if (strchr(aXStatusStr,
'D'))
setStatus(KMMsgStatusDeleted);
279 if (strchr(aXStatusStr,
'A'))
setStatus(KMMsgStatusReplied);
280 if (strchr(aXStatusStr,
'F'))
setStatus(KMMsgStatusForwarded);
281 if (strchr(aXStatusStr,
'Q'))
setStatus(KMMsgStatusQueued);
282 if (strchr(aXStatusStr,
'K'))
setStatus(KMMsgStatusTodo);
283 if (strchr(aXStatusStr,
'S'))
setStatus(KMMsgStatusSent);
284 if (strchr(aXStatusStr,
'G'))
setStatus(KMMsgStatusFlag);
285 if (strchr(aXStatusStr,
'P'))
setStatus(KMMsgStatusSpam);
286 if (strchr(aXStatusStr,
'H'))
setStatus(KMMsgStatusHam);
287 if (strchr(aXStatusStr,
'T'))
setStatus(KMMsgStatusHasAttach);
288 if (strchr(aXStatusStr,
'C'))
setStatus(KMMsgStatusHasNoAttach);
293 if ((aStatusStr[0]==
'R' && aStatusStr[1]==
'O') ||
294 (aStatusStr[0]==
'O' && aStatusStr[1]==
'R')) {
298 else if (aStatusStr[0] ==
'R')
300 else if (aStatusStr[0] ==
'D')
308 void KMMsgBase::setEncryptionState(
const KMMsgEncryptionState ,
int idx )
313 storage()->headerOfMsgChanged(
this, idx);
316 void KMMsgBase::setEncryptionStateChar( TQChar
status,
int idx )
320 if( status.latin1() == (char)KMMsgEncryptionStateUnknown )
322 else if( status.latin1() == (char)KMMsgNotEncrypted )
324 else if( status.latin1() == (char)KMMsgPartiallyEncrypted )
326 else if( status.latin1() == (char)KMMsgFullyEncrypted )
333 void KMMsgBase::setSignatureState(
const KMMsgSignatureState ,
int idx )
338 storage()->headerOfMsgChanged(
this, idx);
341 void KMMsgBase::setMDNSentState( KMMsgMDNSentState,
int idx ) {
344 storage()->headerOfMsgChanged(
this, idx);
347 void KMMsgBase::setSignatureStateChar( TQChar status,
int idx )
351 if( status.latin1() == (char)KMMsgSignatureStateUnknown )
353 else if( status.latin1() == (char)KMMsgNotSigned )
355 else if( status.latin1() == (char)KMMsgPartiallySigned )
357 else if( status.latin1() == (char)KMMsgFullySigned )
364 bool KMMsgBase::isUnread(
void)
const 366 KMMsgStatus st =
status();
367 return (st & KMMsgStatusUnread && !(st & KMMsgStatusIgnored));
371 bool KMMsgBase::isNew(
void)
const 373 KMMsgStatus st =
status();
374 return (st & KMMsgStatusNew && !(st & KMMsgStatusIgnored));
378 bool KMMsgBase::isOfUnknownStatus(
void)
const 380 KMMsgStatus st =
status();
381 return (st == KMMsgStatusUnknown);
385 bool KMMsgBase::isOld(
void)
const 387 KMMsgStatus st =
status();
388 return (st & KMMsgStatusOld);
392 bool KMMsgBase::isRead(
void)
const 394 KMMsgStatus st =
status();
395 return (st & KMMsgStatusRead || st & KMMsgStatusIgnored);
399 bool KMMsgBase::isDeleted(
void)
const 401 KMMsgStatus st =
status();
402 return (st & KMMsgStatusDeleted);
406 bool KMMsgBase::isReplied(
void)
const 408 KMMsgStatus st =
status();
409 return (st & KMMsgStatusReplied);
413 bool KMMsgBase::isForwarded(
void)
const 415 KMMsgStatus st =
status();
416 return (st & KMMsgStatusForwarded);
420 bool KMMsgBase::isQueued(
void)
const 422 KMMsgStatus st =
status();
423 return (st & KMMsgStatusQueued);
427 bool KMMsgBase::isTodo(
void)
const 429 KMMsgStatus st =
status();
430 return (st & KMMsgStatusTodo);
434 bool KMMsgBase::isSent(
void)
const 436 KMMsgStatus st =
status();
437 return (st & KMMsgStatusSent);
441 bool KMMsgBase::isImportant(
void)
const 443 KMMsgStatus st =
status();
444 return (st & KMMsgStatusFlag);
448 bool KMMsgBase::isWatched(
void)
const 450 KMMsgStatus st =
status();
451 return (st & KMMsgStatusWatched);
455 bool KMMsgBase::isIgnored(
void)
const 457 KMMsgStatus st =
status();
458 return (st & KMMsgStatusIgnored);
462 bool KMMsgBase::isSpam(
void)
const 464 KMMsgStatus st =
status();
465 return (st & KMMsgStatusSpam);
469 bool KMMsgBase::isHam(
void)
const 471 KMMsgStatus st =
status();
472 return (st & KMMsgStatusHam);
476 TQCString KMMsgBase::statusToStr(
const KMMsgStatus status)
479 if (status & KMMsgStatusNew) sstr +=
'N';
480 if (status & KMMsgStatusUnread) sstr +=
'U';
481 if (status & KMMsgStatusOld) sstr +=
'O';
482 if (status & KMMsgStatusRead) sstr +=
'R';
483 if (status & KMMsgStatusDeleted) sstr +=
'D';
484 if (status & KMMsgStatusReplied) sstr +=
'A';
485 if (status & KMMsgStatusForwarded) sstr +=
'F';
486 if (status & KMMsgStatusQueued) sstr +=
'Q';
487 if (status & KMMsgStatusTodo) sstr +=
'K';
488 if (status & KMMsgStatusSent) sstr +=
'S';
489 if (status & KMMsgStatusFlag) sstr +=
'G';
490 if (status & KMMsgStatusWatched) sstr +=
'W';
491 if (status & KMMsgStatusIgnored) sstr +=
'I';
492 if (status & KMMsgStatusSpam) sstr +=
'P';
493 if (status & KMMsgStatusHam) sstr +=
'H';
494 if (status & KMMsgStatusHasAttach) sstr +=
'T';
495 if (status & KMMsgStatusHasNoAttach) sstr +=
'C';
501 TQString KMMsgBase::statusToSortRank()
503 TQString sstr =
"bcbbbbbbbb";
506 if (
status() & KMMsgStatusWatched) sstr[0] =
'a';
507 if (
status() & KMMsgStatusIgnored) sstr[0] =
'c';
510 if (
status() & KMMsgStatusNew) sstr[1] =
'a';
511 if (
status() & KMMsgStatusUnread) sstr[1] =
'b';
516 if (
status() & KMMsgStatusDeleted) sstr[2] =
'a';
517 if (
status() & KMMsgStatusFlag) sstr[3] =
'a';
518 if (
status() & KMMsgStatusReplied) sstr[4] =
'a';
519 if (
status() & KMMsgStatusForwarded) sstr[5] =
'a';
520 if (
status() & KMMsgStatusQueued) sstr[6] =
'a';
521 if (
status() & KMMsgStatusSent) sstr[7] =
'a';
522 if (
status() & KMMsgStatusHam) sstr[8] =
'a';
523 if (
status() & KMMsgStatusSpam) sstr[8] =
'c';
524 if (
status() & KMMsgStatusTodo) sstr[9] =
'a';
531 void KMMsgBase::setDate(
const TQCString& aDateStr)
533 setDate( KRFCDate::parseDate( aDateStr ) );
538 TQString KMMsgBase::dateStr(
void)
const 541 return KMime::DateFormatter::formatDate(KMime::DateFormatter::Fancy, d);
546 TQString KMMsgBase::skipKeyword(
const TQString& aStr, TQChar sepChar,
549 unsigned int i = 0, maxChars = 3;
552 while (str[0] ==
' ') str.remove(0,1);
553 if (hasKeyword) *hasKeyword=
false;
555 unsigned int strLength(str.length());
556 for (i=0; i < strLength && i < maxChars; i++)
558 if (str[i] <
'A' || str[i] == sepChar)
break;
561 if (str[i] == sepChar)
565 }
while (str[i] ==
' ');
566 if (hasKeyword) *hasKeyword=
true;
574 const TQTextCodec* KMMsgBase::codecForName(
const TQCString& _str)
576 if (_str.isEmpty())
return 0;
577 TQCString
codec = _str;
578 KPIM::kAsciiToLower(codec.data());
579 return TDEGlobal::charsets()->codecForName(codec);
584 TQCString KMMsgBase::toUsAscii(
const TQString& _str,
bool *ok)
587 TQString result = _str;
588 int len = result.length();
589 for (
int i = 0; i < len; i++)
590 if (result.at(i).unicode() >= 128) {
596 return result.latin1();
601 TQStringList KMMsgBase::supportedEncodings(
bool usAscii)
603 TQStringList encodingNames = TDEGlobal::charsets()->availableEncodingNames();
604 TQStringList encodings;
605 TQMap<TQString,bool> mimeNames;
606 for (TQStringList::Iterator it = encodingNames.begin();
607 it != encodingNames.end(); it++)
609 TQTextCodec *codec = TDEGlobal::charsets()->codecForName(*it);
610 TQString mimeName = (
codec) ? TQString(codec->mimeName()).lower() : (*it);
611 if (mimeNames.find(mimeName) == mimeNames.end())
613 encodings.append(TDEGlobal::charsets()->languageForEncoding(*it)
614 +
" ( " + mimeName +
" )");
615 mimeNames.insert(mimeName,
true);
619 if (usAscii) encodings.prepend(TDEGlobal::charsets()
620 ->languageForEncoding(
"us-ascii") +
" ( us-ascii )");
629 inline bool isBlank(
char ch ) {
return ch ==
' ' || ch ==
'\t' ; }
631 TQCString unfold(
const TQCString & header ) {
632 if ( header.isEmpty() )
635 TQCString result( header.size() );
636 char * d = result.data();
638 for (
const char * s = header.data() ; *s ; )
642 }
else if ( *s ==
'\n' ) {
643 while ( isBlank( *++s ) )
651 result.truncate( d - result.data() );
658 TQString KMMsgBase::decodeRFC2047String(
const TQCString& aStr, TQCString prefCharset)
660 if ( aStr.isEmpty() )
663 const TQCString str = unfold( aStr );
668 if ( str.find(
"=?" ) < 0 ) {
669 if ( !prefCharset.isEmpty() &&
670 kmkernel->isCodecAsciiCompatible( KMMsgBase::codecForName( prefCharset ) ) ) {
671 if ( prefCharset ==
"us-ascii" ) {
673 return KMMsgBase::codecForName(
"utf-8" )->toUnicode( str );
675 return KMMsgBase::codecForName( prefCharset )->toUnicode( str );
678 if ( kmkernel->isCodecAsciiCompatible( KMMsgBase::codecForName(
679 GlobalSettings::self()->fallbackCharacterEncoding().latin1() ) ) ) {
680 return KMMsgBase::codecForName( GlobalSettings::self()->
681 fallbackCharacterEncoding().latin1() )->toUnicode( str );
686 return TQString::fromAscii( str );
690 TQCString LWSP_buffer;
691 bool lastWasEncodedWord =
false;
693 for (
const char * pos = str.data() ; *pos ; ++pos ) {
697 if ( lastWasEncodedWord && isBlank( pos[0] ) ) {
698 LWSP_buffer += pos[0];
702 if (pos[0]!=
'=' || pos[1]!=
'?') {
703 result += LWSP_buffer + pos[0];
705 lastWasEncodedWord =
false;
709 const char *
const beg = pos;
715 for ( ; *pos !=
'?' && ( *pos==
' ' || ispunct(*pos) || isalnum(*pos) );
719 if ( *pos!=
'?' || i<4 )
720 goto invalid_encoded_word;
723 const char encoding[2] = { pos[1],
'\0' };
724 if (pos[2]!=
'?' || (encoding[0]!=
'Q' && encoding[0]!=
'q' &&
725 encoding[0]!=
'B' && encoding[0]!=
'b'))
726 goto invalid_encoded_word;
728 const char * enc_start = pos;
730 while ( *pos && !(*pos==
'?' && *(pos+1)==
'=') ) {
735 goto invalid_encoded_word;
738 const KMime::Codec * c = KMime::Codec::codecForName( encoding );
739 kdFatal( !c, 5006 ) <<
"No \"" << encoding <<
"\" codec!?" << endl;
741 TQByteArray in; in.setRawData( enc_start, pos - enc_start );
742 const TQByteArray enc = c->decode( in );
743 in.resetRawData( enc_start, pos - enc_start );
745 const TQTextCodec * codec = codecForName(charset);
746 if (!codec) codec = kmkernel->networkCodec();
747 result += codec->toUnicode(enc);
748 lastWasEncodedWord =
true;
754 invalid_encoded_word:
757 if ( !LWSP_buffer.isNull() )
758 result += LWSP_buffer;
760 lastWasEncodedWord =
false;
769 static const TQCString especials =
"()<>@,;:\"/[]?.= \033";
771 TQCString KMMsgBase::encodeRFC2047Quoted(
const TQCString & s,
bool base64 ) {
772 const char * codecName = base64 ?
"b" :
"q" ;
773 const KMime::Codec * codec = KMime::Codec::codecForName( codecName );
774 kdFatal( !codec, 5006 ) <<
"No \"" << codecName <<
"\" found!?" << endl;
775 TQByteArray in; in.setRawData( s.data(), s.length() );
776 const TQByteArray result = codec->encode( in );
777 in.resetRawData( s.data(), s.length() );
778 return TQCString( result.data(), result.size() + 1 );
781 TQCString KMMsgBase::encodeRFC2047String(
const TQString& _str,
782 const TQCString& charset)
784 static const TQString dontQuote =
"\"()<>,@";
786 if (_str.isEmpty())
return TQCString();
787 if (charset ==
"us-ascii")
return toUsAscii(_str);
790 if (charset.isEmpty())
792 cset = kmkernel->networkCodec()->mimeName();
793 KPIM::kAsciiToLower(cset.data());
797 const TQTextCodec *codec = codecForName(cset);
798 if (!codec) codec = kmkernel->networkCodec();
800 unsigned int nonAscii = 0;
801 unsigned int strLength(_str.length());
802 for (
unsigned int i = 0; i < strLength; i++)
803 if (_str.at(i).unicode() >= 128) nonAscii++;
804 bool useBase64 = (nonAscii * 6 > strLength);
806 unsigned int start, stop, p, pos = 0, encLength;
808 bool breakLine =
false;
809 const unsigned int maxLen = 75 - 7 - cset.length();
811 while (pos < strLength)
813 start = pos; p = pos;
814 while (p < strLength)
816 if (!breakLine && (_str.at(p) ==
' ' || dontQuote.find(_str.at(p)) != -1))
818 if (_str.at(p).unicode() >= 128 || _str.at(p).unicode() < 32)
822 if (breakLine || p < strLength)
824 while (dontQuote.find(_str.at(start)) != -1) start++;
826 while (stop < strLength && dontQuote.find(_str.at(stop)) == -1)
828 result += _str.mid(pos, start - pos).latin1();
829 encLength = encodeRFC2047Quoted(codec->fromUnicode(_str.
830 mid(start, stop - start)), useBase64).length();
831 breakLine = (encLength > maxLen);
834 int dif = (stop - start) / 2;
836 while (abs(step) > 1)
838 encLength = encodeRFC2047Quoted(codec->fromUnicode(_str.
839 mid(start, dif)), useBase64).length();
840 step = (encLength > maxLen) ? (-abs(step) / 2) : (abs(step) / 2);
846 while (p > start && _str.at(p) !=
' ') p--;
847 if (p > start) stop = p;
848 if (result.right(3) ==
"?= ") start--;
849 if (result.right(5) ==
"?=\n ") {
850 start--; result.truncate(result.length() - 1);
852 int lastNewLine = result.findRev(
"\n ");
853 if (!result.mid(lastNewLine).stripWhiteSpace().isEmpty()
854 && result.length() - lastNewLine + encLength + 2 > maxLen)
858 result += (useBase64) ?
"?b?" :
"?q?";
859 result += encodeRFC2047Quoted(codec->fromUnicode(_str.mid(start,
860 stop - start)), useBase64);
862 if (breakLine) result +=
"\n ";
865 result += _str.mid(pos).latin1();
874 TQCString KMMsgBase::encodeRFC2231String(
const TQString& _str,
875 const TQCString& charset )
877 if ( _str.isEmpty() )
881 if ( charset.isEmpty() )
883 cset = kmkernel->networkCodec()->mimeName();
884 KPIM::kAsciiToLower( cset.data() );
888 const TQTextCodec *codec = codecForName( cset );
890 if ( charset ==
"us-ascii" )
891 latin = toUsAscii( _str );
893 latin = codec->fromUnicode( _str );
895 latin = _str.local8Bit();
898 for ( l = latin.data(); *l; ++l ) {
899 if ( ( ( *l & 0xE0 ) == 0 ) || ( *l & 0x80 ) )
906 TQCString result = cset +
"''";
907 for ( l = latin.data(); *l; ++l ) {
908 bool needsQuoting = ( *l & 0x80 );
909 if( !needsQuoting ) {
910 int len = especials.length();
911 for (
int i = 0; i < len; i++ )
912 if ( *l == especials[i] ) {
917 if ( needsQuoting ) {
919 unsigned char hexcode;
920 hexcode = ( ( *l & 0xF0 ) >> 4 ) + 48;
924 hexcode = ( *l & 0x0F ) + 48;
936 TQCString KMMsgBase::encodeRFC2231StringAutoDetectCharset(
const TQString &str,
939 TQCString encoding = KMMsgBase::autoDetectCharset( defaultCharset,
941 if ( encoding.isEmpty() )
943 return KMMsgBase::encodeRFC2231String( str, encoding );
947 TQString KMMsgBase::decodeRFC2231String(
const TQCString& _str)
949 int p = _str.find(
'\'');
950 if (p < 0)
return kmkernel->networkCodec()->toUnicode(_str);
952 TQCString charset = _str.left(p);
954 TQCString st = _str.mid(_str.findRev(
'\'') + 1);
957 while (p < (
int)st.length())
961 ch = st.at(p+1) - 48;
962 if (ch > 16) ch -= 7;
963 ch2 = st.at(p+2) - 48;
964 if (ch2 > 16) ch2 -= 7;
965 st.at(p) = ch * 16 + ch2;
971 const TQTextCodec * codec = codecForName( charset );
973 codec = kmkernel->networkCodec();
974 return codec->toUnicode( st );
977 TQCString KMMsgBase::extractRFC2231HeaderField(
const TQCString &aStr,
const TQCString &field )
982 while ( n<=0 || found ) {
983 TQString pattern( field );
986 pattern += TQString::number(n) +
"[*]?";
990 TQRegExp fnamePart( pattern,
false );
991 int startPart = fnamePart.search( aStr );
993 found = ( startPart >= 0 );
995 startPart += fnamePart.matchedLength();
997 if ( aStr[startPart] ==
'"' ) {
999 endPart = aStr.find(
'"', startPart) - 1;
1002 endPart = aStr.find(
';', startPart) - 1;
1006 str += aStr.mid( startPart, endPart-startPart+1).stripWhiteSpace();
1013 TQString KMMsgBase::base64EncodedMD5(
const TQString & s,
bool utf8 ) {
1014 if (s.stripWhiteSpace().isEmpty())
return "";
1016 return base64EncodedMD5( s.stripWhiteSpace().utf8() );
1018 return base64EncodedMD5( s.stripWhiteSpace().latin1() );
1021 TQString KMMsgBase::base64EncodedMD5(
const TQCString & s ) {
1022 if (s.stripWhiteSpace().isEmpty())
return "";
1023 return base64EncodedMD5( s.stripWhiteSpace().data() );
1026 TQString KMMsgBase::base64EncodedMD5(
const char * s,
int len ) {
1027 if (!s || !len)
return "";
1028 static const int Base64EncodedMD5Len = 22;
1030 return md5.base64Digest().left( Base64EncodedMD5Len );
1035 TQCString KMMsgBase::autoDetectCharset(
const TQCString &_encoding,
const TQStringList &encodingList,
const TQString &text)
1037 TQStringList charsets = encodingList;
1038 if (!_encoding.isEmpty())
1040 TQString currentCharset = TQString::fromLatin1(_encoding);
1041 charsets.remove(currentCharset);
1042 charsets.prepend(currentCharset);
1045 TQStringList::ConstIterator it = charsets.begin();
1046 for (; it != charsets.end(); ++it)
1048 TQCString encoding = (*it).latin1();
1049 if (encoding ==
"locale")
1051 encoding = kmkernel->networkCodec()->mimeName();
1052 KPIM::kAsciiToLower(encoding.data());
1056 if (encoding ==
"us-ascii") {
1058 (void) KMMsgBase::toUsAscii(text, &ok);
1064 const TQTextCodec *codec = KMMsgBase::codecForName(encoding);
1066 kdDebug(5006) <<
"Auto-Charset: Something is wrong and I can not get a codec. [" << encoding <<
"]" << endl;
1068 if (codec->canEncode(text))
1078 unsigned long KMMsgBase::getMsgSerNum()
const 1080 unsigned long msn = MessageProperty::serialCache(
this );
1084 int index = mParent->find((KMMsgBase*)
this);
1087 MessageProperty::setSerialCache(
this, msn );
1094 KMMsgAttachmentState KMMsgBase::attachmentState()
const 1096 KMMsgStatus st =
status();
1097 if (st & KMMsgStatusHasAttach)
1098 return KMMsgHasAttachment;
1099 else if (st & KMMsgStatusHasNoAttach)
1100 return KMMsgHasNoAttachment;
1102 return KMMsgAttachmentUnknown;
1106 KMMsgInvitationState KMMsgBase::invitationState()
const 1108 KMMsgStatus st =
status();
1109 if (st & KMMsgStatusHasInvitation)
1110 return KMMsgHasInvitation;
1111 else if (st & KMMsgStatusHasNoInvitation)
1112 return KMMsgHasNoInvitation;
1114 return KMMsgInvitationUnknown;
1118 static void swapEndian(TQString &str)
1120 uint len = str.length();
1121 str = TQDeepCopy<TQString>(str);
1122 TQChar *unicode =
const_cast<TQChar*
>( str.unicode() );
1123 for (uint i = 0; i < len; i++)
1124 unicode[i] = kmail_swap_16(unicode[i].unicode());
1128 static int g_chunk_length = 0, g_chunk_offset=0;
1129 static uchar *g_chunk = 0;
1132 template <
typename T >
void copy_from_stream( T & x ) {
1133 if( g_chunk_offset +
int(
sizeof(T)) > g_chunk_length ) {
1134 g_chunk_offset = g_chunk_length;
1135 kdDebug( 5006 ) <<
"This should never happen.. " 1136 << __FILE__ <<
":" << __LINE__ << endl;
1141 memcpy( &x, g_chunk + g_chunk_offset,
sizeof(T) );
1142 g_chunk_offset +=
sizeof(T);
1148 TQString KMMsgBase::getStringPart(MsgPartType t)
const 1154 bool using_mmap =
false;
1155 bool swapByteOrder = storage()->indexSwapByteOrder();
1156 if (storage()->indexStreamBasePtr()) {
1160 g_chunk = storage()->indexStreamBasePtr() + mIndexOffset;
1161 g_chunk_length = mIndexLength;
1163 if(!storage()->mIndexStream)
1165 if (g_chunk_length < mIndexLength)
1166 g_chunk = (uchar *)realloc(g_chunk, g_chunk_length = mIndexLength);
1167 off_t first_off=ftell(storage()->mIndexStream);
1168 fseek(storage()->mIndexStream, mIndexOffset, SEEK_SET);
1169 fread( g_chunk, mIndexLength, 1, storage()->mIndexStream);
1170 fseek(storage()->mIndexStream, first_off, SEEK_SET);
1175 while(g_chunk_offset < mIndexLength) {
1177 copy_from_stream(tmp);
1178 copy_from_stream(l);
1181 tmp = kmail_swap_32(tmp);
1182 l = kmail_swap_16(l);
1184 type = (MsgPartType) tmp;
1185 if(g_chunk_offset + l > mIndexLength) {
1186 kdDebug(5006) <<
"This should never happen.. " << __FILE__ <<
":" << __LINE__ << endl;
1191 storage()->recreateIndex();
1198 ret = TQString((TQChar *)(g_chunk + g_chunk_offset), l/2);
1201 g_chunk_offset += l;
1212 #ifndef WORDS_BIGENDIAN 1223 off_t KMMsgBase::getLongPart(MsgPartType t)
const 1229 bool using_mmap =
false;
1230 int sizeOfLong = storage()->indexSizeOfLong();
1231 bool swapByteOrder = storage()->indexSwapByteOrder();
1232 if (storage()->indexStreamBasePtr()) {
1236 g_chunk = storage()->indexStreamBasePtr() + mIndexOffset;
1237 g_chunk_length = mIndexLength;
1239 if (!storage()->mIndexStream)
1241 assert(mIndexLength >= 0);
1242 if (g_chunk_length < mIndexLength)
1243 g_chunk = (uchar *)realloc(g_chunk, g_chunk_length = mIndexLength);
1244 off_t first_off=ftell(storage()->mIndexStream);
1245 fseek(storage()->mIndexStream, mIndexOffset, SEEK_SET);
1246 fread( g_chunk, mIndexLength, 1, storage()->mIndexStream);
1247 fseek(storage()->mIndexStream, first_off, SEEK_SET);
1252 while (g_chunk_offset < mIndexLength) {
1254 copy_from_stream(tmp);
1255 copy_from_stream(l);
1258 tmp = kmail_swap_32(tmp);
1259 l = kmail_swap_16(l);
1261 type = (MsgPartType) tmp;
1263 if (g_chunk_offset + l > mIndexLength) {
1264 kdDebug(5006) <<
"This should never happen.. " << __FILE__ <<
":" << __LINE__ << endl;
1269 storage()->recreateIndex();
1273 assert(sizeOfLong == l);
1274 if (sizeOfLong ==
sizeof(ret))
1276 copy_from_stream(ret);
1279 if (
sizeof(ret) == 4)
1280 ret = kmail_swap_32(ret);
1282 ret = kmail_swap_64(ret);
1285 else if (sizeOfLong == 4)
1289 copy_from_stream(ret_32);
1291 ret_32 = kmail_swap_32(ret_32);
1294 else if (sizeOfLong == 8)
1299 copy_from_stream(ret_1);
1300 copy_from_stream(ret_2);
1304 #ifndef WORDS_BIGENDIAN 1315 #ifndef WORDS_BIGENDIAN 1323 ret = kmail_swap_32(ret);
1329 g_chunk_offset += l;
1338 #ifndef WORDS_BIGENDIAN 1340 #define memcpy_networkorder(to, from, len) swab((char *)(from), (char *)(to), len) 1343 #define memcpy_networkorder(to, from, len) memcpy(to, from, len) 1346 #define STORE_DATA_LEN(type, x, len, network_order) do { \ 1347 int len2 = (len > 256) ? 256 : len; \ 1348 if(csize < (length + (len2 + sizeof(short) + sizeof(MsgPartType)))) \ 1349 ret = (uchar *)realloc(ret, csize += len2+sizeof(short)+sizeof(MsgPartType)); \ 1350 TQ_UINT32 t = (TQ_UINT32) type; memcpy(ret+length, &t, sizeof(t)); \ 1351 TQ_UINT16 l = len2; memcpy(ret+length+sizeof(t), &l, sizeof(l)); \ 1352 if (network_order) \ 1353 memcpy_networkorder(ret+length+sizeof(t)+sizeof(l), x, len2); \ 1355 memcpy(ret+length+sizeof(t)+sizeof(l), x, len2); \ 1356 length += len2+sizeof(t)+sizeof(l); \ 1358 #define STORE_DATA(type, x) STORE_DATA_LEN(type, &x, sizeof(x), false) 1361 const uchar *KMMsgBase::asIndexString(
int &length)
const 1363 unsigned int csize = 256;
1364 static uchar *ret = 0;
1366 ret = (uchar *)malloc(csize);
1373 tmp_str = msgIdMD5().stripWhiteSpace();
1374 STORE_DATA_LEN(MsgIdMD5Part, tmp_str.unicode(), tmp_str.length() * 2,
true);
1375 tmp = mLegacyStatus;
1376 STORE_DATA(MsgLegacyStatusPart, tmp);
1379 tmp_str = fromStrip().stripWhiteSpace();
1380 STORE_DATA_LEN(MsgFromStripPart, tmp_str.unicode(), tmp_str.length() * 2,
true);
1381 tmp_str =
subject().stripWhiteSpace();
1382 STORE_DATA_LEN(MsgSubjectPart, tmp_str.unicode(), tmp_str.length() * 2,
true);
1383 tmp_str = toStrip().stripWhiteSpace();
1384 STORE_DATA_LEN(MsgToStripPart, tmp_str.unicode(), tmp_str.length() * 2,
true);
1385 tmp_str = replyToIdMD5().stripWhiteSpace();
1386 STORE_DATA_LEN(MsgReplyToIdMD5Part, tmp_str.unicode(), tmp_str.length() * 2,
true);
1387 tmp_str =
xmark().stripWhiteSpace();
1388 STORE_DATA_LEN(MsgXMarkPart, tmp_str.unicode(), tmp_str.length() * 2,
true);
1389 tmp_str =
fileName().stripWhiteSpace();
1390 STORE_DATA_LEN(MsgFilePart, tmp_str.unicode(), tmp_str.length() * 2,
true);
1392 STORE_DATA(MsgSizePart, tmp);
1394 STORE_DATA(MsgOffsetPart, tmp);
1396 STORE_DATA(MsgDatePart, tmp);
1398 STORE_DATA(MsgCryptoStatePart, tmp);
1399 tmp = mdnSentState();
1400 STORE_DATA(MsgMDNSentPart, tmp);
1403 STORE_DATA_LEN(MsgReplyToAuxIdMD5Part, tmp_str.unicode(), tmp_str.length() * 2,
true);
1406 STORE_DATA_LEN(MsgStrippedSubjectMD5Part, tmp_str.unicode(), tmp_str.length() * 2,
true);
1409 STORE_DATA(MsgStatusPart, tmp);
1412 STORE_DATA(MsgSizeServerPart, tmp);
1414 STORE_DATA(MsgUIDPart, tmp);
1417 STORE_DATA_LEN( MsgFromPart, tmp_str.unicode(), tmp_str.length() * 2, true );
1420 STORE_DATA_LEN( MsgToPart, tmp_str.unicode(), tmp_str.length() * 2, true );
1424 #undef STORE_DATA_LEN 1427 bool KMMsgBase::syncIndexString()
const 1432 const uchar *buffer = asIndexString(len);
1433 if (len == mIndexLength) {
1434 Q_ASSERT(storage()->mIndexStream);
1435 fseek(storage()->mIndexStream, mIndexOffset, SEEK_SET);
1436 assert( mIndexOffset > 0 );
1437 fwrite( buffer, len, 1, storage()->mIndexStream);
1443 static TQStringList sReplySubjPrefixes, sForwardSubjPrefixes;
1444 static bool sReplaceSubjPrefix, sReplaceForwSubjPrefix;
1447 void KMMsgBase::readConfig()
1449 TDEConfigGroup composerGroup( KMKernel::config(),
"Composer" );
1450 sReplySubjPrefixes = composerGroup.readListEntry(
"reply-prefixes",
',');
1451 if (sReplySubjPrefixes.isEmpty())
1452 sReplySubjPrefixes <<
"Re\\s*:" <<
"Re\\[\\d+\\]:" <<
"Re\\d+:";
1453 sReplaceSubjPrefix = composerGroup.readBoolEntry(
"replace-reply-prefix",
true);
1454 sForwardSubjPrefixes = composerGroup.readListEntry(
"forward-prefixes",
',');
1455 if (sForwardSubjPrefixes.isEmpty())
1456 sForwardSubjPrefixes <<
"Fwd:" <<
"FW:";
1457 sReplaceForwSubjPrefix = composerGroup.readBoolEntry(
"replace-forward-prefix",
true);
1462 TQString KMMsgBase::stripOffPrefixes(
const TQString& str )
1464 return replacePrefixes( str, sReplySubjPrefixes + sForwardSubjPrefixes,
1465 true, TQString() ).stripWhiteSpace();
1470 TQString KMMsgBase::replacePrefixes(
const TQString& str,
1471 const TQStringList& prefixRegExps,
1473 const TQString& newPrefix )
1475 bool recognized =
false;
1479 TQString bigRegExp = TQString::fromLatin1(
"^(?:\\s+|(?:%1))+\\s*")
1480 .arg( prefixRegExps.join(
")|(?:") );
1481 TQRegExp rx( bigRegExp,
false );
1482 if ( !rx.isValid() ) {
1483 kdWarning(5006) <<
"KMMessage::replacePrefixes(): bigRegExp = \"" 1484 << bigRegExp <<
"\"\n" 1485 <<
"prefix regexp is invalid!" << endl;
1487 recognized = str.startsWith( newPrefix );
1490 if ( rx.search( tmp ) == 0 ) {
1493 return tmp.replace( 0, rx.matchedLength(), newPrefix +
' ' );
1497 return newPrefix +
' ' + str;
1503 TQString KMMsgBase::cleanSubject()
const 1505 return cleanSubject( sReplySubjPrefixes + sForwardSubjPrefixes,
1506 true, TQString() ).stripWhiteSpace();
1510 TQString KMMsgBase::cleanSubject(
const TQStringList & prefixRegExps,
1512 const TQString & newPrefix )
const 1514 return KMMsgBase::replacePrefixes(
subject(), prefixRegExps, replace,
1519 TQString KMMsgBase::forwardSubject()
const {
1520 return cleanSubject( sForwardSubjPrefixes, sReplaceForwSubjPrefix,
"Fwd:" );
1524 TQString KMMsgBase::replySubject()
const {
1525 return cleanSubject( sReplySubjPrefixes, sReplaceSubjPrefix,
"Re:" );
static TQCString defaultCharset()
Get the default message charset.
void setSignatureState(const KMMsgSignatureState, int idx=-1)
Set signature status of the message.
TQString replyToAuxIdMD5() const
Get the second to last id from the References header field.
TQString subject() const
Get or set the 'Subject' header field.
TQString from() const
Get or set the 'From' header field.
void setStatus(const KMMsgStatus status, int idx=-1)
Set status and mark dirty.
const TQTextCodec * codec() const
Get a TQTextCodec suitable for this message part.
A FolderStorage with an index for faster access to often used message properties. ...
bool mDirty
if the index is dirty it will be recreated upon close()
static const KMMsgDict * instance()
Access the globally unique MessageDict.
TQString fileName() const
Get/set filename in mail folder.
KMMsgStatus status() const
Status of the message.
TQString xmark() const
Get or set the 'X-Mark' header field.
off_t folderOffset() const
Get/set offset in mail folder.
size_t msgSize() const
Get/set size of message in the folder including the whole header in bytes.
TQString to() const
Get or set the 'To' header field.
unsigned long getMsgSerNum(KMFolder *folder, int index) const
Find the message serial number for the message located at index index in folder folder.
KMMsgEncryptionState encryptionState() const
Encryption status of the message.
static const TQStringList & preferredCharsets()
Get a list of preferred message charsets.
KMMsgSignatureState signatureState() const
Signature status of the message.
TQCString charset() const
Get the message charset.
TQString strippedSubjectMD5() const
Get a hash of the subject with all prefixes such as Re: removed.
ulong UID() const
Get/set UID.
void setEncryptionState(const KMMsgEncryptionState, int idx=-1)
Set encryption status of the message.
size_t msgSizeServer() const
Get/set size on server.