kmail Library API Documentation

kmmsgpart.cpp

00001 // kmmsgpart.cpp 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 // set the type 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; // Can't know the decoded size 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 /* no 8bit */ ); 00089 } 00090 00091 const QTextCodec * KMMessagePart::codec() const { 00092 const QTextCodec * c = KMMsgBase::codecForName( charset() ); 00093 if ( !c ) 00094 // no charset means us-ascii (RFC 2045), so using local encoding should 00095 // be okay 00096 c = kmkernel->networkCodec(); 00097 assert( c ); 00098 return c; 00099 } 00100 00101 QString KMMessagePart::bodyToUnicode(const QTextCodec* codec) const { 00102 if ( !codec ) 00103 // No codec was given, so try the charset in the mail 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 // we can't use the convenience function here, since aStr is not 00133 // a QByteArray...: 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 ); // save to pass null arrays... 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] ); // choose best fitting 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 ); // save to pass null strings 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] ); // choose best fitting 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 // Nice: We can use the convenience function :-) 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 // Nice: we can use the convenience function :-) 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(); // cache the decoded 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 // We can't use the codec convenience functions, since we must 00274 // return a QCString, not a QByteArray: 00275 int bufSize = codec->maxDecodedSizeFor( mBody.size() ) + 1; // trailing NUL 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 ); // adds trailing NUL 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 /* trailing NUL */ ); 00298 memcpy(result.data(), mBody.data(), len); 00299 result[len] = 0; 00300 break; 00301 } 00302 } 00303 result = result.replace( "\r\n", "\n" ); // CRLF -> LF conversion 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; // cache decoded size 00311 00312 return result; 00313 } 00314 00315 00316 //----------------------------------------------------------------------------- 00317 void KMMessagePart::magicSetType(bool aAutoDecode) 00318 { 00319 KMimeMagic::self()->setFollowLinks( true ); // is it necessary ? 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 // search the start of the filename 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 // search the end of the filename 00457 int endOfFilename; 00458 if ( '"' == mContentDisposition[startOfFilename] ) { 00459 startOfFilename++; // the double quote isn't part of the filename 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 ); // space for trailing NUL 00483 } 00484
KDE Logo
This file is part of the documentation for kmail Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 27 12:52:47 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003