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 //----------------------------------------------------------------------------- 00111 void KMMessagePart::setBodyEncoded(const QCString& aStr) 00112 { 00113 mBodyDecodedSize = aStr.length(); 00114 00115 switch (cte()) 00116 { 00117 case DwMime::kCteQuotedPrintable: 00118 case DwMime::kCteBase64: 00119 { 00120 Codec * codec = Codec::codecForName( cteStr() ); 00121 assert( codec ); 00122 // we can't use the convenience function here, since aStr is not 00123 // a QByteArray...: 00124 mBody.resize( codec->maxEncodedSizeFor( mBodyDecodedSize ) ); 00125 QCString::ConstIterator iit = aStr.data(); 00126 QCString::ConstIterator iend = aStr.data() + mBodyDecodedSize; 00127 QByteArray::Iterator oit = mBody.begin(); 00128 QByteArray::ConstIterator oend = mBody.end(); 00129 if ( !codec->encode( iit, iend, oit, oend ) ) 00130 kdWarning(5006) << codec->name() 00131 << " codec lies about it's maxEncodedSizeFor( " 00132 << mBodyDecodedSize << " ). Result truncated!" << endl; 00133 mBody.truncate( oit - mBody.begin() ); 00134 break; 00135 } 00136 default: 00137 kdWarning(5006) << "setBodyEncoded: unknown encoding '" << cteStr() 00138 << "'. Assuming binary." << endl; 00139 case DwMime::kCte7bit: 00140 case DwMime::kCte8bit: 00141 case DwMime::kCteBinary: 00142 mBody.duplicate( aStr.data(), mBodyDecodedSize ); 00143 break; 00144 } 00145 } 00146 00147 void KMMessagePart::setBodyAndGuessCte(const QByteArray& aBuf, 00148 QValueList<int> & allowedCte, 00149 bool allow8Bit, 00150 bool willBeSigned ) 00151 { 00152 mBodyDecodedSize = aBuf.size(); 00153 00154 CharFreq cf( aBuf ); // save to pass null arrays... 00155 00156 allowedCte = KMMessage::determineAllowedCtes( cf, allow8Bit, willBeSigned ); 00157 00158 #ifndef NDEBUG 00159 DwString dwCte; 00160 DwCteEnumToStr(allowedCte[0], dwCte); 00161 kdDebug(5006) << "CharFreq returned " << cf.type() << "/" 00162 << cf.printableRatio() << " and I chose " 00163 << dwCte.c_str() << endl; 00164 #endif 00165 00166 setCte( allowedCte[0] ); // choose best fitting 00167 setBodyEncodedBinary( aBuf ); 00168 } 00169 00170 void KMMessagePart::setBodyAndGuessCte(const QCString& aBuf, 00171 QValueList<int> & allowedCte, 00172 bool allow8Bit, 00173 bool willBeSigned ) 00174 { 00175 mBodyDecodedSize = aBuf.length(); 00176 00177 CharFreq cf( aBuf.data(), mBodyDecodedSize ); // save to pass null strings 00178 00179 allowedCte = KMMessage::determineAllowedCtes( cf, allow8Bit, willBeSigned ); 00180 00181 #ifndef NDEBUG 00182 DwString dwCte; 00183 DwCteEnumToStr(allowedCte[0], dwCte); 00184 kdDebug(5006) << "CharFreq returned " << cf.type() << "/" 00185 << cf.printableRatio() << " and I chose " 00186 << dwCte.c_str() << endl; 00187 #endif 00188 00189 setCte( allowedCte[0] ); // choose best fitting 00190 setBodyEncoded( aBuf ); 00191 } 00192 00193 //----------------------------------------------------------------------------- 00194 void KMMessagePart::setBodyEncodedBinary(const QByteArray& aStr) 00195 { 00196 mBodyDecodedSize = aStr.size(); 00197 if (aStr.isEmpty()) 00198 { 00199 mBody.resize(0); 00200 return; 00201 } 00202 00203 switch (cte()) 00204 { 00205 case DwMime::kCteQuotedPrintable: 00206 case DwMime::kCteBase64: 00207 { 00208 Codec * codec = Codec::codecForName( cteStr() ); 00209 assert( codec ); 00210 // Nice: We can use the convenience function :-) 00211 mBody = codec->encode( aStr ); 00212 break; 00213 } 00214 default: 00215 kdWarning(5006) << "setBodyEncodedBinary: unknown encoding '" << cteStr() 00216 << "'. Assuming binary." << endl; 00217 case DwMime::kCte7bit: 00218 case DwMime::kCte8bit: 00219 case DwMime::kCteBinary: 00220 mBody.duplicate( aStr ); 00221 break; 00222 } 00223 } 00224 00225 00226 //----------------------------------------------------------------------------- 00227 QByteArray KMMessagePart::bodyDecodedBinary() const 00228 { 00229 if (mBody.isEmpty()) return QByteArray(); 00230 QByteArray result; 00231 00232 if ( const Codec * codec = Codec::codecForName( cteStr() ) ) 00233 // Nice: we can use the convenience function :-) 00234 result = codec->decode( mBody ); 00235 else 00236 switch (cte()) 00237 { 00238 default: 00239 kdWarning(5006) << "bodyDecodedBinary: unknown encoding '" << cteStr() 00240 << "'. Assuming binary." << endl; 00241 case DwMime::kCte7bit: 00242 case DwMime::kCte8bit: 00243 case DwMime::kCteBinary: 00244 result.duplicate(mBody); 00245 break; 00246 } 00247 00248 assert( mBodyDecodedSize < 0 00249 || (unsigned int)mBodyDecodedSize == result.size() ); 00250 if ( mBodyDecodedSize < 0 ) 00251 mBodyDecodedSize = result.size(); // cache the decoded size. 00252 00253 return result; 00254 } 00255 00256 QCString KMMessagePart::bodyDecoded(void) const 00257 { 00258 if (mBody.isEmpty()) return QCString(""); 00259 QCString result; 00260 int len; 00261 00262 if ( const Codec * codec = Codec::codecForName( cteStr() ) ) { 00263 // We can't use the codec convenience functions, since we must 00264 // return a QCString, not a QByteArray: 00265 int bufSize = codec->maxDecodedSizeFor( mBody.size() ) + 1; // trailing NUL 00266 result.resize( bufSize ); 00267 QByteArray::ConstIterator iit = mBody.begin(); 00268 QCString::Iterator oit = result.begin(); 00269 QCString::ConstIterator oend = result.begin() + bufSize; 00270 if ( !codec->decode( iit, mBody.end(), oit, oend ) ) 00271 kdWarning(5006) << codec->name() 00272 << " lies about it's maxDecodedSizeFor( " 00273 << mBody.size() << " ). Result truncated!" << endl; 00274 len = oit - result.begin(); 00275 result.truncate( len ); // adds trailing NUL 00276 } else 00277 switch (cte()) 00278 { 00279 default: 00280 kdWarning(5006) << "bodyDecoded: unknown encoding '" << cteStr() 00281 << "'. Assuming binary." << endl; 00282 case DwMime::kCte7bit: 00283 case DwMime::kCte8bit: 00284 case DwMime::kCteBinary: 00285 { 00286 len = mBody.size(); 00287 result.resize( len+1 /* trailing NUL */ ); 00288 memcpy(result.data(), mBody.data(), len); 00289 result[len] = 0; 00290 break; 00291 } 00292 } 00293 result = result.replace( "\r\n", "\n" ); // CRLF -> LF conversion 00294 00295 kdWarning( result.length() != (unsigned int)len, 5006 ) 00296 << "KMMessagePart::bodyDecoded(): body is binary but used as text!" << endl; 00297 00298 assert( mBodyDecodedSize < 0 || mBodyDecodedSize == len ); 00299 if ( mBodyDecodedSize < 0 ) 00300 mBodyDecodedSize = len; // cache decoded size 00301 00302 return result; 00303 } 00304 00305 00306 //----------------------------------------------------------------------------- 00307 void KMMessagePart::magicSetType(bool aAutoDecode) 00308 { 00309 KMimeMagic::self()->setFollowLinks( true ); // is it necessary ? 00310 00311 const QByteArray body = ( aAutoDecode ) ? bodyDecodedBinary() : mBody ; 00312 KMimeMagicResult * result = KMimeMagic::self()->findBufferType( body ); 00313 00314 QString mimetype = result->mimeType(); 00315 const int sep = mimetype.find('/'); 00316 mType = mimetype.left(sep).latin1(); 00317 mSubtype = mimetype.mid(sep+1).latin1(); 00318 } 00319 00320 00321 //----------------------------------------------------------------------------- 00322 QString KMMessagePart::iconName(const QString& mimeType) const 00323 { 00324 QString fileName = KMimeType::mimeType(mimeType.isEmpty() ? 00325 (mType + "/" + mSubtype).lower() : mimeType.lower())->icon(QString::null,FALSE); 00326 fileName = KGlobal::instance()->iconLoader()->iconPath( fileName, 00327 KIcon::Desktop ); 00328 return fileName; 00329 } 00330 00331 00332 //----------------------------------------------------------------------------- 00333 int KMMessagePart::type() const { 00334 return DwTypeStrToEnum(DwString(mType)); 00335 } 00336 00337 00338 //----------------------------------------------------------------------------- 00339 void KMMessagePart::setType(int aType) 00340 { 00341 DwString dwType; 00342 DwTypeEnumToStr(aType, dwType); 00343 mType = dwType.c_str(); 00344 } 00345 00346 //----------------------------------------------------------------------------- 00347 int KMMessagePart::subtype() const { 00348 return DwSubtypeStrToEnum(DwString(mSubtype)); 00349 } 00350 00351 00352 //----------------------------------------------------------------------------- 00353 void KMMessagePart::setSubtype(int aSubtype) 00354 { 00355 DwString dwSubtype; 00356 DwSubtypeEnumToStr(aSubtype, dwSubtype); 00357 mSubtype = dwSubtype.c_str(); 00358 } 00359 00360 //----------------------------------------------------------------------------- 00361 QCString KMMessagePart::parameterAttribute(void) const 00362 { 00363 return mParameterAttribute; 00364 } 00365 00366 //----------------------------------------------------------------------------- 00367 QString KMMessagePart::parameterValue(void) const 00368 { 00369 return mParameterValue; 00370 } 00371 00372 //----------------------------------------------------------------------------- 00373 void KMMessagePart::setParameter(const QCString &attribute, 00374 const QString &value) 00375 { 00376 mParameterAttribute = attribute; 00377 mParameterValue = value; 00378 } 00379 00380 //----------------------------------------------------------------------------- 00381 QCString KMMessagePart::contentTransferEncodingStr(void) const 00382 { 00383 return mCte; 00384 } 00385 00386 00387 //----------------------------------------------------------------------------- 00388 int KMMessagePart::contentTransferEncoding(void) const 00389 { 00390 return DwCteStrToEnum(DwString(mCte)); 00391 } 00392 00393 00394 //----------------------------------------------------------------------------- 00395 void KMMessagePart::setContentTransferEncodingStr(const QCString &aStr) 00396 { 00397 mCte = aStr; 00398 } 00399 00400 00401 //----------------------------------------------------------------------------- 00402 void KMMessagePart::setContentTransferEncoding(int aCte) 00403 { 00404 DwString dwCte; 00405 DwCteEnumToStr(aCte, dwCte); 00406 mCte = dwCte.c_str(); 00407 00408 } 00409 00410 00411 //----------------------------------------------------------------------------- 00412 QString KMMessagePart::contentDescription(void) const 00413 { 00414 return KMMsgBase::decodeRFC2047String(mContentDescription); 00415 } 00416 00417 00418 //----------------------------------------------------------------------------- 00419 void KMMessagePart::setContentDescription(const QString &aStr) 00420 { 00421 QCString encoding = KMMsgBase::autoDetectCharset(charset(), 00422 KMMessage::preferredCharsets(), aStr); 00423 if (encoding.isEmpty()) encoding = "utf-8"; 00424 mContentDescription = KMMsgBase::encodeRFC2047String(aStr, encoding); 00425 } 00426 00427 00428 //----------------------------------------------------------------------------- 00429 QString KMMessagePart::fileName(void) const 00430 { 00431 bool bRFC2231encoded = false; 00432 00433 // search the start of the filename 00434 int startOfFilename = mContentDisposition.find("filename*=", 0, FALSE); 00435 if (startOfFilename >= 0) { 00436 bRFC2231encoded = true; 00437 startOfFilename += 10; 00438 } 00439 else { 00440 startOfFilename = mContentDisposition.find("filename=", 0, FALSE); 00441 if (startOfFilename < 0) 00442 return QString::null; 00443 startOfFilename += 9; 00444 } 00445 00446 // search the end of the filename 00447 int endOfFilename; 00448 if ( '"' == mContentDisposition[startOfFilename] ) { 00449 startOfFilename++; // the double quote isn't part of the filename 00450 endOfFilename = mContentDisposition.find('"', startOfFilename) - 1; 00451 } 00452 else { 00453 endOfFilename = mContentDisposition.find(';', startOfFilename) - 1; 00454 } 00455 if (endOfFilename < 0) 00456 endOfFilename = 32767; 00457 00458 const QCString str = mContentDisposition.mid(startOfFilename, 00459 endOfFilename-startOfFilename+1) 00460 .stripWhiteSpace(); 00461 00462 if (bRFC2231encoded) 00463 return KMMsgBase::decodeRFC2231String(str); 00464 else 00465 return KMMsgBase::decodeRFC2047String(str); 00466 } 00467 00468 00469 00470 QCString KMMessagePart::body() const 00471 { 00472 return QCString( mBody.data(), mBody.size() + 1 ); // space for trailing NUL 00473 } 00474
KDE Logo
This file is part of the documentation for kmail Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jul 28 23:58:03 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003