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