24#include "kmime_util.h"
25#include "kmime_util_p.h"
29#include "kmime_header_parsing.h"
30#include "kmime_message.h"
31#include "kmime_warning.h"
33#include <config-kmime.h>
37#include <klocalizedstring.h>
42#include <QtCore/QList>
43#include <QtCore/QString>
44#include <QtCore/QTextCodec>
57QString f_allbackCharEnc;
58bool u_seOutlookEncoding =
false;
60QByteArray cachedCharset(
const QByteArray &name )
62 foreach (
const QByteArray& charset, c_harsetCache ) {
63 if (
qstricmp( name.data(), charset.data() ) == 0 ) {
68 c_harsetCache.append( name.toUpper() );
70 return c_harsetCache.last();
73QByteArray cachedLanguage(
const QByteArray &name )
75 foreach (
const QByteArray&
language, l_anguageCache ) {
81 l_anguageCache.append( name.toUpper() );
83 return l_anguageCache.last();
86bool isUsAscii(
const QString &s )
90 if ( s.at(
i ).toLatin1() <= 0 ) {
100 case Headers::CE7Bit:
return QString::fromLatin1(
"7bit" );
101 case Headers::CE8Bit:
return QString::fromLatin1(
"8bit" );
102 case Headers::CEquPr:
return QString::fromLatin1(
"quoted-printable" );
103 case Headers::CEbase64:
return QString::fromLatin1(
"base64" );
104 case Headers::CEuuenc:
return QString::fromLatin1(
"uuencode" );
105 case Headers::CEbinary:
return QString::fromLatin1(
"binary" );
106 default:
return QString::fromLatin1(
"unknown" );
115 switch (
cf.type() ) {
121 if (
cf.printableRatio() > 5.0/6.0 ) {
144const uchar specialsMap[16] = {
145 0x00, 0x00, 0x00, 0x00,
146 0x20, 0xCA, 0x00, 0x3A,
147 0x80, 0x00, 0x00, 0x1C,
148 0x00, 0x00, 0x00, 0x00
152const uchar tSpecialsMap[16] = {
153 0x00, 0x00, 0x00, 0x00,
154 0x20, 0xC9, 0x00, 0x3F,
155 0x80, 0x00, 0x00, 0x1C,
156 0x00, 0x00, 0x00, 0x00
160const uchar aTextMap[16] = {
161 0x00, 0x00, 0x00, 0x00,
162 0x5F, 0x35, 0xFF, 0xC5,
163 0x7F, 0xFF, 0xFF, 0xE3,
164 0xFF, 0xFF, 0xFF, 0xFE
168const uchar tTextMap[16] = {
169 0x00, 0x00, 0x00, 0x00,
170 0x5F, 0x36, 0xFF, 0xC0,
171 0x7F, 0xFF, 0xFF, 0xE3,
172 0xFF, 0xFF, 0xFF, 0xFE
176const uchar eTextMap[16] = {
177 0x00, 0x00, 0x00, 0x00,
178 0x40, 0x35, 0xFF, 0xC0,
179 0x7F, 0xFF, 0xFF, 0xE0,
180 0x7F, 0xFF, 0xFF, 0xE0
188QString fallbackCharEncoding()
190 return f_allbackCharEnc;
198bool useOutlookAttachmentEncoding()
200 return u_seOutlookEncoding;
204QString decodeRFC2047String(
const QByteArray &
src, QByteArray &
usedCS,
229 result += decoded.toUtf8();
254 if (
tryUtf8.contains( 0xFFFD ) && !f_allbackCharEnc.isEmpty() ) {
255 QTextCodec*
codec = KGlobal::charsets()->codecForName( f_allbackCharEnc );
262QString decodeRFC2047String(
const QByteArray &
src )
265 return decodeRFC2047String(
src,
usedCS,
"utf-8",
false );
268static const char *reservedCharacters =
"\"()<>@,.;:\\[]=";
270QByteArray encodeRFC2047String(
const QString &
src,
const QByteArray &charset,
278 const QTextCodec *
codec = KGlobal::charsets()->codecForName( QString::fromLatin1( charset ),
ok );
283 usedCS = KGlobal::locale()->encoding();
284 codec = KGlobal::charsets()->codecForName( QString::fromLatin1(
usedCS ),
ok );
287 if ( charset.isEmpty() ) {
294 QTextCodec::ConverterState
converterState( QTextCodec::IgnoreHeader );
302 if (
usedCS.contains(
"8859-" ) ) {
354 if ( ( (
c >=
'a' ) && (
c <=
'z' ) ) ||
355 ( (
c >=
'A' ) && (
c <=
'Z' ) ) ||
356 ( (
c >=
'0' ) && (
c <=
'9' ) ) ) {
360 hexcode = ( (
c & 0xF0 ) >> 4 ) + 48;
386QByteArray encodeRFC2047Sentence(
const QString&
src,
const QByteArray& charset )
401 const bool isAscii =
ch->unicode() < 127;
407 result += encodeRFC2047String(
word, charset );
421 result += encodeRFC2047String(
word, charset );
430QByteArray encodeRFC2231String(
const QString&
str,
const QByteArray& charset )
432 if (
str.isEmpty() ) {
436 const QTextCodec *
codec = KGlobal::charsets()->codecForName( QString::fromLatin1( charset ) );
438 if ( charset ==
"us-ascii" ) {
440 }
else if (
codec ) {
448 if ( ( ( *
l & 0xE0 ) == 0 ) || ( *
l & 0x80 ) ) {
457 QByteArray
result = charset +
"''";
461 const QByteArray
especials =
"()<>@,;:\"/[]?.= \033";
463 for (
int i = 0;
i <
len;
i++ ) {
473 hexcode = ( ( *
l & 0xF0 ) >> 4 ) + 48;
492QString decodeRFC2231String(
const QByteArray &
str, QByteArray &
usedCS,
const QByteArray &
defaultCS,
495 int p =
str.indexOf(
'\'' );
497 return KGlobal::charsets()->codecForName( QString::fromLatin1(
defaultCS ) )->toUnicode(
str );
501 QByteArray charset =
str.left(
p );
503 QByteArray
st =
str.mid(
str.lastIndexOf(
'\'' ) + 1 );
507 while (
p < (
int)
st.length() ) {
508 if (
st.at(
p ) == 37 ) {
511 if (
p + 2 <
st.length() ) {
512 ch =
st.at(
p + 1 ) - 48;
516 ch2 =
st.at(
p + 2 ) - 48;
521 st.remove(
p + 1, 2 );
526 kDebug() <<
"Got pre-decoded:" <<
st;
537QString decodeRFC2231String(
const QByteArray &
src )
540 return decodeRFC2231String(
src,
usedCS,
"utf-8",
false );
543QByteArray uniqueString()
545 static char chars[] =
"0123456789abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
556 for (
int i = 0;
i < 10;
i++ ) {
570QByteArray multiPartBoundary()
572 return "nextPart" + uniqueString();
575QByteArray unfoldHeader(
const QByteArray &header )
578 if ( header.isEmpty() ) {
583 while ( (
foldMid = header.indexOf(
'\n',
pos ) ) >= 0 ) {
593 while (
foldEnd <= header.length() - 1 ) {
598 ( ( header[
foldEnd + 1] ==
'0' &&
599 header[
foldEnd + 2] ==
'9' ) ||
600 ( header[
foldEnd + 1] ==
'2' &&
601 header[
foldEnd + 2] ==
'0' ) ) ) {
611 if (
foldEnd < header.length() - 1 ) {
616 const int len = header.length();
626 int len =
src.length() - 1;
653 if (
src.at(
end ) !=
'\n' ) {
659 }
else if (
src[
end + 1] ==
' ' ||
src[
end + 1] ==
'\t' ||
680int indexOfHeader(
const QByteArray &
src,
const QByteArray &name,
int &
end,
int &
dataBegin,
bool *
folded )
686 if (
qstrnicmp(
n.constData(),
src.constData(),
n.length() ) == 0 ) {
715QByteArray extractHeader(
const QByteArray &
src,
const QByteArray &name )
749 while (
begin >= 0 ) {
766void removeHeader( QByteArray &header,
const QByteArray &name )
775QByteArray CRLFtoLF(
const QByteArray &s )
778 ret.replace(
"\r\n",
"\n" );
782QByteArray CRLFtoLF(
const char *s )
785 return CRLFtoLF(
ret );
788QByteArray LFtoCRLF(
const QByteArray &s )
791 ret.replace(
'\n',
"\r\n" );
795QByteArray LFtoCRLF(
const char *s )
798 return LFtoCRLF(
ret );
805 for (
int i = 0;
i <
str.length(); ++
i ) {
819void removeQuots( QByteArray &
str )
824void removeQuots( QString &
str )
829template<
class StringType,
class CharType,
class CharConverterType,
class StringConverterType,
class ToString>
833 for (
int i=0;
i <
str.length();
i++ ) {
862 const int LRO = 0x202D;
863 const int RLO = 0x202E;
864 const int LRE = 0x202A;
865 const int RLE = 0x202B;
866 const int PDF = 0x202C;
872 for (
int i = 0;
i <
input.length();
i++ ) {
881 kWarning() <<
"Possible Unicode spoofing (unexpected PDF) detected in" <<
input;
889 kWarning() <<
"Possible Unicode spoofing detected in" <<
input;
906QString removeBidiControlChars(
const QString &
input )
908 const int LRO = 0x202D;
909 const int RLO = 0x202E;
910 const int LRE = 0x202A;
911 const int RLE = 0x202B;
920static bool isCryptoPart(
Content* content )
933 return ( contentType->
mediaType().toLower() ==
"application" &&
944bool hasAttachment(
Content* content )
970 if ( hasAttachment(
child ) ) {
978bool hasInvitation(
Content *content )
984 if ( isInvitation(content) ) {
991 if ( hasInvitation(
child ) ) {
1006 if ( contentType->
isSubtype(
"signed" ) ||
1007 contentType->
isSubtype(
"pgp-signature" ) ||
1008 contentType->
isSubtype(
"pkcs7-signature" ) ||
1009 contentType->
isSubtype(
"x-pkcs7-signature" ) ||
1010 message->mainBodyPart(
"multipart/signed" ) ||
1011 message->mainBodyPart(
"application/pgp-signature" ) ||
1012 message->mainBodyPart(
"application/pkcs7-signature" ) ||
1013 message->mainBodyPart(
"application/x-pkcs7-signature" ) ) {
1026 if ( contentType->
isSubtype(
"encrypted" ) ||
1027 contentType->
isSubtype(
"pgp-encrypted" ) ||
1028 contentType->
isSubtype(
"pkcs7-mime" ) ||
1029 contentType->
isSubtype(
"x-pkcs7-mime" ) ||
1030 message->mainBodyPart(
"multipart/encrypted" ) ||
1031 message->mainBodyPart(
"application/pgp-encrypted" ) ||
1032 message->mainBodyPart(
"application/pkcs7-mime" ) ||
1033 message->mainBodyPart(
"application/x-pkcs7-mime" ) ) {
1040bool isInvitation(
Content *content )
1048 if ( contentType && contentType->
isMediatype(
"text" ) && contentType->
isSubtype(
"calendar" ) ) {
A class for performing basic data typing using frequency count heuristics.
@ EightBitData
8bit binary
@ SevenBitData
7bit binary
A class that encapsulates MIME encoded Content.
Headers::ContentType * contentType(bool create=true)
Returns the Content-Type header.
Headers::ContentDisposition * contentDisposition(bool create=true)
Returns the Content-Disposition header.
List contents() const
For multipart contents, this will return a list of all multipart child contents.
The KAutoDeleteHash class is a convenience QHash subclass that provides automatic deletion of the val...
Represents a (email) message.
This file is part of the API for handling MIME data and defines the CharFreq class.
This file is part of the API for handling MIME data and defines the Codec class.