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 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; // Can't know the decoded size 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 /* no 8bit */ ); 00112 } 00113 00114 const QTextCodec * KMMessagePart::codec() const { 00115 const QTextCodec * c = KMMsgBase::codecForName( charset() ); 00116 if ( !c ) 00117 // no charset means us-ascii (RFC 2045), so using local encoding should 00118 // be okay 00119 c = kmkernel->networkCodec(); 00120 assert( c ); 00121 return c; 00122 } 00123 00124 QString KMMessagePart::bodyToUnicode(const QTextCodec* codec) const { 00125 if ( !codec ) 00126 // No codec was given, so try the charset in the mail 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 // we can't use the convenience function here, since aStr is not 00156 // a QByteArray...: 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 ); // save to pass null arrays... 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 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 ); // save to pass null strings 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] ); // choose best fitting 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 // Nice: We can use the convenience function :-) 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 // Nice: we can use the convenience function :-) 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(); // cache the decoded 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 // We can't use the codec convenience functions, since we must 00297 // return a QCString, not a QByteArray: 00298 int bufSize = codec->maxDecodedSizeFor( mBody.size() ) + 1; // trailing NUL 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 ); // adds trailing NUL 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 /* trailing NUL */ ); 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" ); // CRLF -> LF conversion 00330 00331 assert( mBodyDecodedSize < 0 || mBodyDecodedSize == len ); 00332 if ( mBodyDecodedSize < 0 ) 00333 mBodyDecodedSize = len; // cache decoded size 00334 00335 return result; 00336 } 00337 00338 00339 //----------------------------------------------------------------------------- 00340 void KMMessagePart::magicSetType(bool aAutoDecode) 00341 { 00342 KMimeMagic::self()->setFollowLinks( true ); // is it necessary ? 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 // search the start of the filename 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 // search the end of the filename 00480 int endOfFilename; 00481 if ( '"' == mContentDisposition[startOfFilename] ) { 00482 startOfFilename++; // the double quote isn't part of the filename 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 ); // space for trailing NUL 00506 } 00507
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 Oct 1 15:19:23 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003