00001
00002
00003
#include <config.h>
00004
#include <kmimemagic.h>
00005
#include <kmimetype.h>
00006
#include <kdebug.h>
00007
#include <kmdcodec.h>
00008
00009
#include "kmmsgpart.h"
00010
#include "kmmessage.h"
00011
#include "kmkernel.h"
00012
00013
#include <kmime_charfreq.h>
00014
#include <kmime_codecs.h>
00015
#include <mimelib/enum.h>
00016
#include <mimelib/utility.h>
00017
#include <mimelib/string.h>
00018
00019
#include <kiconloader.h>
00020
#include <qtextcodec.h>
00021
00022
#include <assert.h>
00023
00024
using namespace KMime;
00025
00026
00027 KMMessagePart::KMMessagePart()
00028 : mType(
"text"), mSubtype(
"plain"), mCte(
"7bit"), mBodyDecodedSize(0),
00029 mParent(0), mLoadHeaders(false), mLoadPart(false)
00030 {
00031 }
00032
00033
00034 KMMessagePart::KMMessagePart(
QDataStream & stream )
00035 : mParent(0), mLoadHeaders(false), mLoadPart(false)
00036 {
00037
unsigned long size;
00038 stream >> mOriginalContentTypeStr >> mName >> mContentDescription
00039 >> mContentDisposition >> mCte >> size >> mPartSpecifier;
00040
00041 mContentDisposition = mContentDisposition.lower();
00042 mOriginalContentTypeStr = mOriginalContentTypeStr.upper();
00043
00044
00045
int sep = mOriginalContentTypeStr.find(
'/');
00046 mType = mOriginalContentTypeStr.left(sep);
00047 mSubtype = mOriginalContentTypeStr.mid(sep+1);
00048
00049 mBodyDecodedSize = size;
00050 }
00051
00052
00053
00054 KMMessagePart::~KMMessagePart()
00055 {
00056 }
00057
00058
00059
00060
int KMMessagePart::decodedSize(
void)
const
00061
{
00062
if (mBodyDecodedSize < 0)
00063 mBodyDecodedSize = bodyDecodedBinary().size();
00064
return mBodyDecodedSize;
00065 }
00066
00067
00068
00069
void KMMessagePart::setBody(
const QCString &aStr)
00070 {
00071 mBody.duplicate( aStr.data(), aStr.length() );
00072
00073
int enc = cte();
00074
if (enc == DwMime::kCte7bit || enc == DwMime::kCte8bit || enc == DwMime::kCteBinary)
00075 mBodyDecodedSize = mBody.size();
00076
else
00077 mBodyDecodedSize = -1;
00078 }
00079
00080
void KMMessagePart::setBodyFromUnicode(
const QString & str ) {
00081
QCString encoding = KMMsgBase::autoDetectCharset( charset(), KMMessage::preferredCharsets(), str );
00082
if ( encoding.isEmpty() )
00083 encoding =
"utf-8";
00084
const QTextCodec * codec = KMMsgBase::codecForName( encoding );
00085 assert( codec );
00086
QValueList<int> dummy;
00087 setCharset( encoding );
00088 setBodyAndGuessCte( codec->fromUnicode( str ), dummy,
false );
00089 }
00090
00091
const QTextCodec * KMMessagePart::codec()
const {
00092
const QTextCodec * c = KMMsgBase::codecForName( charset() );
00093
if ( !c )
00094
00095
00096 c = kmkernel->networkCodec();
00097 assert( c );
00098
return c;
00099 }
00100
00101
QString KMMessagePart::bodyToUnicode(
const QTextCodec* codec)
const {
00102
if ( !codec )
00103
00104 codec = this->codec();
00105 assert( codec );
00106
00107
return codec->toUnicode( bodyDecoded() );
00108 }
00109
00110
void KMMessagePart::setCharset(
const QCString & c ) {
00111 kdWarning( type() != DwMime::kTypeText )
00112 <<
"KMMessagePart::setCharset(): trying to set a charset for a non-textual mimetype." << endl
00113 <<
"Fix this caller:" << endl
00114 <<
"====================================================================" << endl
00115 << kdBacktrace( 5 ) << endl
00116 <<
"====================================================================" << endl;
00117 mCharset = c;
00118 }
00119
00120
00121
void KMMessagePart::setBodyEncoded(
const QCString& aStr)
00122 {
00123 mBodyDecodedSize = aStr.length();
00124
00125
switch (cte())
00126 {
00127
case DwMime::kCteQuotedPrintable:
00128
case DwMime::kCteBase64:
00129 {
00130 Codec * codec = Codec::codecForName( cteStr() );
00131 assert( codec );
00132
00133
00134 mBody.resize( codec->maxEncodedSizeFor( mBodyDecodedSize ) );
00135 QCString::ConstIterator iit = aStr.data();
00136 QCString::ConstIterator iend = aStr.data() + mBodyDecodedSize;
00137 QByteArray::Iterator oit = mBody.begin();
00138 QByteArray::ConstIterator oend = mBody.end();
00139
if ( !codec->encode( iit, iend, oit, oend ) )
00140 kdWarning(5006) << codec->name()
00141 <<
" codec lies about it's maxEncodedSizeFor( "
00142 << mBodyDecodedSize <<
" ). Result truncated!" << endl;
00143 mBody.truncate( oit - mBody.begin() );
00144
break;
00145 }
00146
default:
00147 kdWarning(5006) <<
"setBodyEncoded: unknown encoding '" << cteStr()
00148 <<
"'. Assuming binary." << endl;
00149
case DwMime::kCte7bit:
00150
case DwMime::kCte8bit:
00151
case DwMime::kCteBinary:
00152 mBody.duplicate( aStr.data(), mBodyDecodedSize );
00153
break;
00154 }
00155 }
00156
00157
void KMMessagePart::setBodyAndGuessCte(
const QByteArray& aBuf,
00158
QValueList<int> & allowedCte,
00159
bool allow8Bit,
00160
bool willBeSigned )
00161 {
00162 mBodyDecodedSize = aBuf.size();
00163
00164 CharFreq cf( aBuf );
00165
00166 allowedCte = KMMessage::determineAllowedCtes( cf, allow8Bit, willBeSigned );
00167
00168
#ifndef NDEBUG
00169
DwString dwCte;
00170 DwCteEnumToStr(allowedCte[0], dwCte);
00171 kdDebug(5006) <<
"CharFreq returned " << cf.type() <<
"/"
00172 << cf.printableRatio() <<
" and I chose "
00173 << dwCte.c_str() << endl;
00174
#endif
00175
00176 setCte( allowedCte[0] );
00177 setBodyEncodedBinary( aBuf );
00178 }
00179
00180
void KMMessagePart::setBodyAndGuessCte(
const QCString& aBuf,
00181
QValueList<int> & allowedCte,
00182
bool allow8Bit,
00183
bool willBeSigned )
00184 {
00185 mBodyDecodedSize = aBuf.length();
00186
00187 CharFreq cf( aBuf.data(), mBodyDecodedSize );
00188
00189 allowedCte = KMMessage::determineAllowedCtes( cf, allow8Bit, willBeSigned );
00190
00191
#ifndef NDEBUG
00192
DwString dwCte;
00193 DwCteEnumToStr(allowedCte[0], dwCte);
00194 kdDebug(5006) <<
"CharFreq returned " << cf.type() <<
"/"
00195 << cf.printableRatio() <<
" and I chose "
00196 << dwCte.c_str() << endl;
00197
#endif
00198
00199 setCte( allowedCte[0] );
00200 setBodyEncoded( aBuf );
00201 }
00202
00203
00204
void KMMessagePart::setBodyEncodedBinary(
const QByteArray& aStr)
00205 {
00206 mBodyDecodedSize = aStr.size();
00207
if (aStr.isEmpty())
00208 {
00209 mBody.resize(0);
00210
return;
00211 }
00212
00213
switch (cte())
00214 {
00215
case DwMime::kCteQuotedPrintable:
00216
case DwMime::kCteBase64:
00217 {
00218 Codec * codec = Codec::codecForName( cteStr() );
00219 assert( codec );
00220
00221 mBody = codec->encode( aStr );
00222
break;
00223 }
00224
default:
00225 kdWarning(5006) <<
"setBodyEncodedBinary: unknown encoding '" << cteStr()
00226 <<
"'. Assuming binary." << endl;
00227
case DwMime::kCte7bit:
00228
case DwMime::kCte8bit:
00229
case DwMime::kCteBinary:
00230 mBody.duplicate( aStr );
00231
break;
00232 }
00233 }
00234
00235
00236
00237
QByteArray KMMessagePart::bodyDecodedBinary()
const
00238
{
00239
if (mBody.isEmpty())
return QByteArray();
00240
QByteArray result;
00241
00242
if (
const Codec * codec = Codec::codecForName( cteStr() ) )
00243
00244 result = codec->decode( mBody );
00245
else
00246
switch (cte())
00247 {
00248
default:
00249 kdWarning(5006) <<
"bodyDecodedBinary: unknown encoding '" << cteStr()
00250 <<
"'. Assuming binary." << endl;
00251
case DwMime::kCte7bit:
00252
case DwMime::kCte8bit:
00253
case DwMime::kCteBinary:
00254 result.duplicate(mBody);
00255
break;
00256 }
00257
00258 assert( mBodyDecodedSize < 0
00259 || (
unsigned int)mBodyDecodedSize == result.size() );
00260
if ( mBodyDecodedSize < 0 )
00261 mBodyDecodedSize = result.size();
00262
00263
return result;
00264 }
00265
00266
QCString KMMessagePart::bodyDecoded(
void)
const
00267
{
00268
if (mBody.isEmpty())
return QCString(
"");
00269
QCString result;
00270
int len;
00271
00272
if (
const Codec * codec = Codec::codecForName( cteStr() ) ) {
00273
00274
00275
int bufSize = codec->maxDecodedSizeFor( mBody.size() ) + 1;
00276 result.resize( bufSize );
00277 QByteArray::ConstIterator iit = mBody.begin();
00278 QCString::Iterator oit = result.begin();
00279 QCString::ConstIterator oend = result.begin() + bufSize;
00280
if ( !codec->decode( iit, mBody.end(), oit, oend ) )
00281 kdWarning(5006) << codec->name()
00282 <<
" lies about it's maxDecodedSizeFor( "
00283 << mBody.size() <<
" ). Result truncated!" << endl;
00284 len = oit - result.begin();
00285 result.truncate( len );
00286 }
else
00287
switch (cte())
00288 {
00289
default:
00290 kdWarning(5006) <<
"bodyDecoded: unknown encoding '" << cteStr()
00291 <<
"'. Assuming binary." << endl;
00292
case DwMime::kCte7bit:
00293
case DwMime::kCte8bit:
00294
case DwMime::kCteBinary:
00295 {
00296 len = mBody.size();
00297 result.resize( len+1 );
00298 memcpy(result.data(), mBody.data(), len);
00299 result[len] = 0;
00300
break;
00301 }
00302 }
00303 result = result.replace(
"\r\n",
"\n" );
00304
00305 kdWarning( result.length() != (
unsigned int)len, 5006 )
00306 <<
"KMMessagePart::bodyDecoded(): body is binary but used as text!" << endl;
00307
00308 assert( mBodyDecodedSize < 0 || mBodyDecodedSize == len );
00309
if ( mBodyDecodedSize < 0 )
00310 mBodyDecodedSize = len;
00311
00312
return result;
00313 }
00314
00315
00316
00317
void KMMessagePart::magicSetType(
bool aAutoDecode)
00318 {
00319 KMimeMagic::self()->setFollowLinks(
true );
00320
00321
const QByteArray body = ( aAutoDecode ) ? bodyDecodedBinary() : mBody ;
00322 KMimeMagicResult * result = KMimeMagic::self()->findBufferType( body );
00323
00324
QString mimetype = result->mimeType();
00325
const int sep = mimetype.find(
'/');
00326 mType = mimetype.left(sep).latin1();
00327 mSubtype = mimetype.mid(sep+1).latin1();
00328 }
00329
00330
00331
00332
QString KMMessagePart::iconName(
const QString& mimeType)
const
00333
{
00334
QString fileName = KMimeType::mimeType(mimeType.isEmpty() ?
00335 (mType +
"/" + mSubtype).lower() : mimeType.lower())->icon(
QString::null,FALSE);
00336 fileName = KGlobal::instance()->iconLoader()->iconPath( fileName,
00337 KIcon::Desktop );
00338
return fileName;
00339 }
00340
00341
00342
00343
int KMMessagePart::type()
const {
00344
return DwTypeStrToEnum(DwString(mType));
00345 }
00346
00347
00348
00349
void KMMessagePart::setType(
int aType)
00350 {
00351 DwString dwType;
00352 DwTypeEnumToStr(aType, dwType);
00353 mType = dwType.c_str();
00354 }
00355
00356
00357
int KMMessagePart::subtype()
const {
00358
return DwSubtypeStrToEnum(DwString(mSubtype));
00359 }
00360
00361
00362
00363
void KMMessagePart::setSubtype(
int aSubtype)
00364 {
00365 DwString dwSubtype;
00366 DwSubtypeEnumToStr(aSubtype, dwSubtype);
00367 mSubtype = dwSubtype.c_str();
00368 }
00369
00370
00371
QCString KMMessagePart::parameterAttribute(
void)
const
00372
{
00373
return mParameterAttribute;
00374 }
00375
00376
00377
QString KMMessagePart::parameterValue(
void)
const
00378
{
00379
return mParameterValue;
00380 }
00381
00382
00383
void KMMessagePart::setParameter(
const QCString &attribute,
00384
const QString &value)
00385 {
00386 mParameterAttribute = attribute;
00387 mParameterValue = value;
00388 }
00389
00390
00391
QCString KMMessagePart::contentTransferEncodingStr(
void)
const
00392
{
00393
return mCte;
00394 }
00395
00396
00397
00398
int KMMessagePart::contentTransferEncoding(
void)
const
00399
{
00400
return DwCteStrToEnum(DwString(mCte));
00401 }
00402
00403
00404
00405
void KMMessagePart::setContentTransferEncodingStr(
const QCString &aStr)
00406 {
00407 mCte = aStr;
00408 }
00409
00410
00411
00412
void KMMessagePart::setContentTransferEncoding(
int aCte)
00413 {
00414 DwString dwCte;
00415 DwCteEnumToStr(aCte, dwCte);
00416 mCte = dwCte.c_str();
00417
00418 }
00419
00420
00421
00422
QString KMMessagePart::contentDescription(
void)
const
00423
{
00424
return KMMsgBase::decodeRFC2047String(mContentDescription);
00425 }
00426
00427
00428
00429
void KMMessagePart::setContentDescription(
const QString &aStr)
00430 {
00431
QCString encoding = KMMsgBase::autoDetectCharset(charset(),
00432 KMMessage::preferredCharsets(), aStr);
00433
if (encoding.isEmpty()) encoding =
"utf-8";
00434 mContentDescription = KMMsgBase::encodeRFC2047String(aStr, encoding);
00435 }
00436
00437
00438
00439
QString KMMessagePart::fileName(
void)
const
00440
{
00441
bool bRFC2231encoded =
false;
00442
00443
00444
int startOfFilename = mContentDisposition.find(
"filename*=", 0, FALSE);
00445
if (startOfFilename >= 0) {
00446 bRFC2231encoded =
true;
00447 startOfFilename += 10;
00448 }
00449
else {
00450 startOfFilename = mContentDisposition.find(
"filename=", 0, FALSE);
00451
if (startOfFilename < 0)
00452
return QString::null;
00453 startOfFilename += 9;
00454 }
00455
00456
00457
int endOfFilename;
00458
if (
'"' == mContentDisposition[startOfFilename] ) {
00459 startOfFilename++;
00460 endOfFilename = mContentDisposition.find(
'"', startOfFilename) - 1;
00461 }
00462
else {
00463 endOfFilename = mContentDisposition.find(
';', startOfFilename) - 1;
00464 }
00465
if (endOfFilename < 0)
00466 endOfFilename = 32767;
00467
00468
const QCString str = mContentDisposition.mid(startOfFilename,
00469 endOfFilename-startOfFilename+1)
00470 .stripWhiteSpace();
00471
00472
if (bRFC2231encoded)
00473
return KMMsgBase::decodeRFC2231String(str);
00474
else
00475
return KMMsgBase::decodeRFC2047String(str);
00476 }
00477
00478
00479
00480
QCString KMMessagePart::body()
const
00481
{
00482
return QCString( mBody.data(), mBody.size() + 1 );
00483 }
00484