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 Sat May 1 11:37:33 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003