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>
21 #include <mimelib/mimepp.h>
22 #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')) {
295 setStatus( KMMsgStatusOld );
296 setStatus( KMMsgStatusRead );
298 else if (aStatusStr[0] ==
'R')
299 setStatus(KMMsgStatusRead);
300 else if (aStatusStr[0] ==
'D')
301 setStatus(KMMsgStatusDeleted);
303 setStatus(KMMsgStatusNew);
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 )
321 setEncryptionState( KMMsgEncryptionStateUnknown, idx );
322 else if( status.latin1() == (
char)KMMsgNotEncrypted )
323 setEncryptionState( KMMsgNotEncrypted, idx );
324 else if( status.latin1() == (
char)KMMsgPartiallyEncrypted )
325 setEncryptionState( KMMsgPartiallyEncrypted, idx );
326 else if( status.latin1() == (
char)KMMsgFullyEncrypted )
327 setEncryptionState( KMMsgFullyEncrypted, idx );
329 setEncryptionState( KMMsgEncryptionStateUnknown, idx );
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 )
352 setSignatureState( KMMsgSignatureStateUnknown, idx );
353 else if( status.latin1() == (
char)KMMsgNotSigned )
354 setSignatureState( KMMsgNotSigned, idx );
355 else if( status.latin1() == (
char)KMMsgPartiallySigned )
356 setSignatureState( KMMsgPartiallySigned,idx );
357 else if( status.latin1() == (
char)KMMsgFullySigned )
358 setSignatureState( KMMsgFullySigned, idx );
360 setSignatureState( KMMsgSignatureStateUnknown, idx );
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 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 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 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,
937 const TQCString &defaultCharset )
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 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);
1393 tmp = folderOffset();
1394 STORE_DATA(MsgOffsetPart, tmp);
1396 STORE_DATA(MsgDatePart, tmp);
1397 tmp = (signatureState() << 16) | encryptionState();
1398 STORE_DATA(MsgCryptoStatePart, tmp);
1399 tmp = mdnSentState();
1400 STORE_DATA(MsgMDNSentPart, tmp);
1402 tmp_str = replyToAuxIdMD5().stripWhiteSpace();
1403 STORE_DATA_LEN(MsgReplyToAuxIdMD5Part, tmp_str.unicode(), tmp_str.length() * 2,
true);
1405 tmp_str = strippedSubjectMD5().stripWhiteSpace();
1406 STORE_DATA_LEN(MsgStrippedSubjectMD5Part, tmp_str.unicode(), tmp_str.length() * 2,
true);
1409 STORE_DATA(MsgStatusPart, tmp);
1411 tmp = msgSizeServer();
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:" );
bool mDirty
if the index is dirty it will be recreated upon close()
A FolderStorage with an index for faster access to often used message properties.
static const TQStringList & preferredCharsets()
Get a list of preferred message charsets.
unsigned long getMsgSerNum(KMFolder *folder, int index) const
Find the message serial number for the message located at index index in folder folder.
static const KMMsgDict * instance()
Access the globally unique MessageDict.