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