kioslaves

mimeheader.cc

Go to the documentation of this file.
00001 /***************************************************************************
00002                           mimeheader.cc  -  description
00003                              -------------------
00004     begin                : Fri Oct 20 2000
00005     copyright            : (C) 2000 by Sven Carstens
00006     email                : s.carstens@gmx.de
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include "mimeheader.h"
00019 #include "mimehdrline.h"
00020 #include "mailheader.h"
00021 #include "rfcdecoder.h"
00022 
00023 #include <qregexp.h>
00024 
00025 // #include <iostream.h>
00026 #include <kglobal.h>
00027 #include <kinstance.h>
00028 #include <kiconloader.h>
00029 #include <kmimetype.h>
00030 #include <kmimemagic.h>
00031 #include <kmdcodec.h>
00032 #include <kdebug.h>
00033 
00034 mimeHeader::mimeHeader ():
00035 typeList (17, false), dispositionList (17, false)
00036 {
00037   // Case insensitive hashes are killing us.  Also are they too small?
00038   originalHdrLines.setAutoDelete (true);
00039   additionalHdrLines.setAutoDelete (false); // is also in original lines
00040   nestedParts.setAutoDelete (true);
00041   typeList.setAutoDelete (true);
00042   dispositionList.setAutoDelete (true);
00043   nestedMessage = NULL;
00044   contentLength = 0;
00045   contentType = "application/octet-stream";
00046 }
00047 
00048 mimeHeader::~mimeHeader ()
00049 {
00050 }
00051 
00052 /*
00053 QPtrList<mimeHeader> mimeHeader::getAllParts()
00054 {
00055     QPtrList<mimeHeader> retVal;
00056 
00057     // caller is responsible for clearing
00058     retVal.setAutoDelete( false );
00059     nestedParts.setAutoDelete( false );
00060 
00061     // shallow copy
00062     retVal = nestedParts;
00063 
00064     // can't have duplicate pointers
00065     nestedParts.clear();
00066 
00067     // restore initial state
00068     nestedParts.setAutoDelete( true );
00069 
00070     return retVal;
00071 } */
00072 
00073 void
00074 mimeHeader::addHdrLine (mimeHdrLine * aHdrLine)
00075 {
00076   mimeHdrLine *addLine = new mimeHdrLine (aHdrLine);
00077   if (addLine)
00078   {
00079     originalHdrLines.append (addLine);
00080     if (qstrnicmp (addLine->getLabel (), "Content-", 8))
00081     {
00082       additionalHdrLines.append (addLine);
00083     }
00084     else
00085     {
00086       int skip;
00087       char *aCStr = addLine->getValue ().data ();
00088       QDict < QString > *aList = 0;
00089 
00090       skip = mimeHdrLine::parseSeparator (';', aCStr);
00091       if (skip > 0)
00092       {
00093         int cut = 0;
00094         if (skip >= 2)
00095         {
00096           if (aCStr[skip - 1] == '\r')
00097             cut++;
00098           if (aCStr[skip - 1] == '\n')
00099             cut++;
00100           if (aCStr[skip - 2] == '\r')
00101             cut++;
00102           if (aCStr[skip - 1] == ';')
00103             cut++;
00104         }
00105         QCString mimeValue = QCString (aCStr, skip - cut + 1);  // cutting of one because of 0x00
00106 
00107 
00108         if (!qstricmp (addLine->getLabel (), "Content-Disposition"))
00109         {
00110           aList = &dispositionList;
00111           _contentDisposition = mimeValue;
00112         }
00113         else if (!qstricmp (addLine->getLabel (), "Content-Type"))
00114         {
00115           aList = &typeList;
00116           contentType = mimeValue;
00117         }
00118         else
00119           if (!qstricmp (addLine->getLabel (), "Content-Transfer-Encoding"))
00120         {
00121           contentEncoding = mimeValue;
00122         }
00123         else if (!qstricmp (addLine->getLabel (), "Content-ID"))
00124         {
00125           contentID = mimeValue;
00126         }
00127         else if (!qstricmp (addLine->getLabel (), "Content-Description"))
00128         {
00129           _contentDescription = mimeValue;
00130         }
00131         else if (!qstricmp (addLine->getLabel (), "Content-MD5"))
00132         {
00133           contentMD5 = mimeValue;
00134         }
00135         else if (!qstricmp (addLine->getLabel (), "Content-Length"))
00136         {
00137           contentLength = mimeValue.toULong ();
00138         }
00139         else
00140         {
00141           additionalHdrLines.append (addLine);
00142         }
00143 //        cout << addLine->getLabel().data() << ": '" << mimeValue.data() << "'" << endl;
00144 
00145         aCStr += skip;
00146         while ((skip = mimeHdrLine::parseSeparator (';', aCStr)))
00147         {
00148           if (skip > 0)
00149           {
00150             addParameter (QCString (aCStr, skip).simplifyWhiteSpace(), aList);
00151 //            cout << "-- '" << aParm.data() << "'" << endl;
00152             mimeValue = QCString (addLine->getValue ().data (), skip);
00153             aCStr += skip;
00154           }
00155           else
00156             break;
00157         }
00158       }
00159     }
00160   }
00161 }
00162 
00163 void
00164 mimeHeader::addParameter (const QCString& aParameter, QDict < QString > *aList)
00165 {
00166   if ( !aList )
00167     return;
00168 
00169   QString *aValue;
00170   QCString aLabel;
00171   int pos = aParameter.find ('=');
00172 //  cout << aParameter.left(pos).data();
00173   aValue = new QString ();
00174   aValue->setLatin1 (aParameter.right (aParameter.length () - pos - 1));
00175   aLabel = aParameter.left (pos);
00176   if ((*aValue)[0] == '"')
00177     *aValue = aValue->mid (1, aValue->length () - 2);
00178 
00179   aList->insert (aLabel, aValue);
00180 //  cout << "=" << aValue->data() << endl;
00181 }
00182 
00183 QString
00184 mimeHeader::getDispositionParm (const QCString& aStr)
00185 {
00186   return getParameter (aStr, &dispositionList);
00187 }
00188 
00189 QString
00190 mimeHeader::getTypeParm (const QCString& aStr)
00191 {
00192   return getParameter (aStr, &typeList);
00193 }
00194 
00195 void
00196 mimeHeader::setDispositionParm (const QCString& aLabel, const QString& aValue)
00197 {
00198   setParameter (aLabel, aValue, &dispositionList);
00199   return;
00200 }
00201 
00202 void
00203 mimeHeader::setTypeParm (const QCString& aLabel, const QString& aValue)
00204 {
00205   setParameter (aLabel, aValue, &typeList);
00206 }
00207 
00208 QDictIterator < QString > mimeHeader::getDispositionIterator ()
00209 {
00210   return QDictIterator < QString > (dispositionList);
00211 }
00212 
00213 QDictIterator < QString > mimeHeader::getTypeIterator ()
00214 {
00215   return QDictIterator < QString > (typeList);
00216 }
00217 
00218 QPtrListIterator < mimeHdrLine > mimeHeader::getOriginalIterator ()
00219 {
00220   return QPtrListIterator < mimeHdrLine > (originalHdrLines);
00221 }
00222 
00223 QPtrListIterator < mimeHdrLine > mimeHeader::getAdditionalIterator ()
00224 {
00225   return QPtrListIterator < mimeHdrLine > (additionalHdrLines);
00226 }
00227 
00228 void
00229 mimeHeader::outputHeader (mimeIO & useIO)
00230 {
00231   if (!getDisposition ().isEmpty ())
00232   {
00233     useIO.outputMimeLine (QCString ("Content-Disposition: ")
00234                           + getDisposition ()
00235                           + outputParameter (&dispositionList));
00236   }
00237 
00238   if (!getType ().isEmpty ())
00239   {
00240     useIO.outputMimeLine (QCString ("Content-Type: ")
00241                           + getType () + outputParameter (&typeList));
00242   }
00243   if (!getDescription ().isEmpty ())
00244     useIO.outputMimeLine (QCString ("Content-Description: ") +
00245                           getDescription ());
00246   if (!getID ().isEmpty ())
00247     useIO.outputMimeLine (QCString ("Content-ID: ") + getID ());
00248   if (!getMD5 ().isEmpty ())
00249     useIO.outputMimeLine (QCString ("Content-MD5: ") + getMD5 ());
00250   if (!getEncoding ().isEmpty ())
00251     useIO.outputMimeLine (QCString ("Content-Transfer-Encoding: ") +
00252                           getEncoding ());
00253 
00254   QPtrListIterator < mimeHdrLine > ait = getAdditionalIterator ();
00255   while (ait.current ())
00256   {
00257     useIO.outputMimeLine (ait.current ()->getLabel () + ": " +
00258                           ait.current ()->getValue ());
00259     ++ait;
00260   }
00261   useIO.outputMimeLine (QCString (""));
00262 }
00263 
00264 QString
00265 mimeHeader::getParameter (const QCString& aStr, QDict < QString > *aDict)
00266 {
00267   QString retVal, *found;
00268   if (aDict)
00269   {
00270     //see if it is a normal parameter
00271     found = aDict->find (aStr);
00272     if (!found)
00273     {
00274       //might be a continuated or encoded parameter
00275       found = aDict->find (aStr + "*");
00276       if (!found)
00277       {
00278         //continuated parameter
00279         QString decoded, encoded;
00280         int part = 0;
00281 
00282         do
00283         {
00284           QCString search;
00285           search.setNum (part);
00286           search = aStr + "*" + search;
00287           found = aDict->find (search);
00288           if (!found)
00289           {
00290             found = aDict->find (search + "*");
00291             if (found)
00292               encoded += rfcDecoder::encodeRFC2231String (*found);
00293           }
00294           else
00295           {
00296             encoded += *found;
00297           }
00298           part++;
00299         }
00300         while (found);
00301         if (encoded.find ('\'') >= 0)
00302         {
00303           retVal = rfcDecoder::decodeRFC2231String (encoded.local8Bit ());
00304         }
00305         else
00306         {
00307           retVal =
00308             rfcDecoder::decodeRFC2231String (QCString ("''") +
00309                                              encoded.local8Bit ());
00310         }
00311       }
00312       else
00313       {
00314         //simple encoded parameter
00315         retVal = rfcDecoder::decodeRFC2231String (found->local8Bit ());
00316       }
00317     }
00318     else
00319     {
00320       retVal = *found;
00321     }
00322   }
00323   return retVal;
00324 }
00325 
00326 void
00327 mimeHeader::setParameter (const QCString& aLabel, const QString& aValue,
00328                           QDict < QString > *aDict)
00329 {
00330   bool encoded = true;
00331   uint vlen, llen;
00332   QString val = aValue;
00333 
00334   if (aDict)
00335   {
00336 
00337     //see if it needs to get encoded
00338     if (encoded && aLabel.find ('*') == -1)
00339     {
00340       val = rfcDecoder::encodeRFC2231String (aValue);
00341     }
00342     //kdDebug(7116) << "mimeHeader::setParameter() - val = '" << val << "'" << endl;
00343     //see if it needs to be truncated
00344     vlen = val.length();
00345     llen = aLabel.length();
00346     if (vlen + llen + 4 > 80 && llen < 80 - 8 - 2 )
00347     {
00348       const int limit = 80 - 8 - 2 - (int)llen;
00349       // the -2 is there to allow extending the length of a part of val
00350       // by 1 or 2 in order to prevent an encoded character from being
00351       // split in half
00352       int i = 0;
00353       QString shortValue;
00354       QCString shortLabel;
00355 
00356       while (!val.isEmpty ())
00357       {
00358         int partLen; // the length of the next part of the value
00359         if ( limit >= int(vlen) ) {
00360           // the rest of the value fits completely into one continued header
00361           partLen = vlen;
00362         }
00363         else {
00364           partLen = limit;
00365           // make sure that we don't split an encoded char in half
00366           if ( val[partLen-1] == '%' ) {
00367             partLen += 2;
00368           }
00369           else if ( partLen > 1 && val[partLen-2] == '%' ) {
00370             partLen += 1;
00371           }
00372           // make sure partLen does not exceed vlen (could happen in case of
00373           // an incomplete encoded char)
00374           if ( partLen > int(vlen) ) {
00375             partLen = vlen;
00376           }
00377         }
00378         shortValue = val.left( partLen );
00379         shortLabel.setNum (i);
00380         shortLabel = aLabel + "*" + shortLabel;
00381         val = val.right( vlen - partLen );
00382         vlen = vlen - partLen;
00383         if (encoded)
00384         {
00385           if (i == 0)
00386           {
00387             shortValue = "''" + shortValue;
00388           }
00389           shortLabel += "*";
00390         }
00391         //kdDebug(7116) << "mimeHeader::setParameter() - shortLabel = '" << shortLabel << "'" << endl;
00392         //kdDebug(7116) << "mimeHeader::setParameter() - shortValue = '" << shortValue << "'" << endl;
00393         //kdDebug(7116) << "mimeHeader::setParameter() - val        = '" << val << "'" << endl;
00394         aDict->insert (shortLabel, new QString (shortValue));
00395         i++;
00396       }
00397     }
00398     else
00399     {
00400       aDict->insert (aLabel, new QString (val));
00401     }
00402   }
00403 }
00404 
00405 QCString
00406 mimeHeader::outputParameter (QDict < QString > *aDict)
00407 {
00408   QCString retVal;
00409   if (aDict)
00410   {
00411     QDictIterator < QString > it (*aDict);
00412     while (it.current ())
00413     {
00414       retVal += (";\n\t" + it.currentKey () + "=").latin1 ();
00415       if (it.current ()->find (' ') > 0 || it.current ()->find (';') > 0)
00416       {
00417         retVal += '"' + it.current ()->utf8 () + '"';
00418       }
00419       else
00420       {
00421         retVal += it.current ()->utf8 ();
00422       }
00423       // << it.current()->utf8() << "'";
00424       ++it;
00425     }
00426     retVal += "\n";
00427   }
00428   return retVal;
00429 }
00430 
00431 void
00432 mimeHeader::outputPart (mimeIO & useIO)
00433 {
00434   QPtrListIterator < mimeHeader > nestedParts = getNestedIterator ();
00435   QCString boundary;
00436   if (!getTypeParm ("boundary").isEmpty ())
00437     boundary = getTypeParm ("boundary").latin1 ();
00438 
00439   outputHeader (useIO);
00440   if (!getPreBody ().isEmpty ())
00441     useIO.outputMimeLine (getPreBody ());
00442   if (getNestedMessage ())
00443     getNestedMessage ()->outputPart (useIO);
00444   while (nestedParts.current ())
00445   {
00446     if (!boundary.isEmpty ())
00447       useIO.outputMimeLine ("--" + boundary);
00448     nestedParts.current ()->outputPart (useIO);
00449     ++nestedParts;
00450   }
00451   if (!boundary.isEmpty ())
00452     useIO.outputMimeLine ("--" + boundary + "--");
00453   if (!getPostBody ().isEmpty ())
00454     useIO.outputMimeLine (getPostBody ());
00455 }
00456 
00457 int
00458 mimeHeader::parsePart (mimeIO & useIO, const QString& boundary)
00459 {
00460   int retVal = 0;
00461   bool mbox = false;
00462   QCString preNested, postNested;
00463   mbox = parseHeader (useIO);
00464 
00465   kdDebug(7116) << "mimeHeader::parsePart - parsing part '" << getType () << "'" << endl;
00466   if (!qstrnicmp (getType (), "Multipart", 9))
00467   {
00468     retVal = parseBody (useIO, preNested, getTypeParm ("boundary"));  //this is a message in mime format stuff
00469     setPreBody (preNested);
00470     int localRetVal;
00471     do
00472     {
00473       mimeHeader *aHeader = new mimeHeader;
00474 
00475       // set default type for multipart/digest
00476       if (!qstrnicmp (getType (), "Multipart/Digest", 16))
00477         aHeader->setType ("Message/RFC822");
00478 
00479       localRetVal = aHeader->parsePart (useIO, getTypeParm ("boundary"));
00480       addNestedPart (aHeader);
00481     }
00482     while (localRetVal);        //get nested stuff
00483   }
00484   if (!qstrnicmp (getType (), "Message/RFC822", 14))
00485   {
00486     mailHeader *msgHeader = new mailHeader;
00487     retVal = msgHeader->parsePart (useIO, boundary);
00488     setNestedMessage (msgHeader);
00489   }
00490   else
00491   {
00492     retVal = parseBody (useIO, postNested, boundary, mbox); //just a simple part remaining
00493     setPostBody (postNested);
00494   }
00495   return retVal;
00496 }
00497 
00498 int
00499 mimeHeader::parseBody (mimeIO & useIO, QCString & messageBody,
00500                        const QString& boundary, bool mbox)
00501 {
00502   QCString inputStr;
00503   QCString buffer;
00504   QString partBoundary;
00505   QString partEnd;
00506   int retVal = 0;               //default is last part
00507 
00508   if (!boundary.isEmpty ())
00509   {
00510     partBoundary = QString ("--") + boundary;
00511     partEnd = QString ("--") + boundary + "--";
00512   }
00513 
00514   while (useIO.inputLine (inputStr))
00515   {
00516     //check for the end of all parts
00517     if (!partEnd.isEmpty ()
00518         && !qstrnicmp (inputStr, partEnd.latin1 (), partEnd.length () - 1))
00519     {
00520       retVal = 0;               //end of these parts
00521       break;
00522     }
00523     else if (!partBoundary.isEmpty ()
00524              && !qstrnicmp (inputStr, partBoundary.latin1 (),
00525                             partBoundary.length () - 1))
00526     {
00527       retVal = 1;               //continue with next part
00528       break;
00529     }
00530     else if (mbox && inputStr.find ("From ") == 0)
00531     {
00532       retVal = 0;               // end of mbox
00533       break;
00534     }
00535     buffer += inputStr;
00536     if (buffer.length () > 16384)
00537     {
00538       messageBody += buffer;
00539       buffer = "";
00540     }
00541   }
00542 
00543   messageBody += buffer;
00544   return retVal;
00545 }
00546 
00547 bool
00548 mimeHeader::parseHeader (mimeIO & useIO)
00549 {
00550   bool mbox = false;
00551   bool first = true;
00552   mimeHdrLine my_line;
00553   QCString inputStr;
00554 
00555   kdDebug(7116) << "mimeHeader::parseHeader - starting parsing" << endl;
00556   while (useIO.inputLine (inputStr))
00557   {
00558     int appended;
00559     if (inputStr.find ("From ") != 0 || !first)
00560     {
00561       first = false;
00562       appended = my_line.appendStr (inputStr);
00563       if (!appended)
00564       {
00565         addHdrLine (&my_line);
00566         appended = my_line.setStr (inputStr);
00567       }
00568       if (appended <= 0)
00569         break;
00570     }
00571     else
00572     {
00573       mbox = true;
00574       first = false;
00575     }
00576     inputStr = (const char *) NULL;
00577   }
00578 
00579   kdDebug(7116) << "mimeHeader::parseHeader - finished parsing" << endl;
00580   return mbox;
00581 }
00582 
00583 mimeHeader *
00584 mimeHeader::bodyPart (const QString & _str)
00585 {
00586   // see if it is nested a little deeper
00587   int pt = _str.find('.');
00588   if (pt != -1)
00589   {
00590     QString tempStr = _str;
00591     mimeHeader *tempPart;
00592 
00593     tempStr = _str.right (_str.length () - pt - 1);
00594     if (nestedMessage)
00595     {
00596       kdDebug(7116) << "mimeHeader::bodyPart - recursing message" << endl;
00597       tempPart = nestedMessage->nestedParts.at (_str.left(pt).toULong() - 1);
00598     }
00599     else
00600     {
00601       kdDebug(7116) << "mimeHeader::bodyPart - recursing mixed" << endl;
00602       tempPart = nestedParts.at (_str.left(pt).toULong() - 1);
00603     }
00604     if (tempPart)
00605       tempPart = tempPart->bodyPart (tempStr);
00606     return tempPart;
00607   }
00608 
00609   kdDebug(7116) << "mimeHeader::bodyPart - returning part " << _str << endl;
00610   // or pick just the plain part
00611   if (nestedMessage)
00612   {
00613     kdDebug(7116) << "mimeHeader::bodyPart - message" << endl;
00614     return nestedMessage->nestedParts.at (_str.toULong () - 1);
00615   }
00616   kdDebug(7116) << "mimeHeader::bodyPart - mixed" << endl;
00617   return nestedParts.at (_str.toULong () - 1);
00618 }
00619 
00620 void mimeHeader::serialize(QDataStream& stream)
00621 {
00622   int nestedcount = nestedParts.count();
00623   if (nestedParts.isEmpty() && nestedMessage)
00624     nestedcount = 1;
00625   stream << nestedcount << contentType << QString (getTypeParm ("name")) << _contentDescription
00626     << _contentDisposition << contentEncoding << contentLength << partSpecifier;
00627   // serialize nested message
00628   if (nestedMessage)
00629     nestedMessage->serialize(stream);
00630 
00631   // serialize nested parts
00632   if (!nestedParts.isEmpty())
00633   {
00634     QPtrListIterator < mimeHeader > it(nestedParts);
00635     mimeHeader* part;
00636     while ( (part = it.current()) != 0 )
00637     {
00638       ++it;
00639       part->serialize(stream);
00640     }
00641   }
00642 }
00643 
00644 #ifdef KMAIL_COMPATIBLE
00645 // compatibility subroutines
00646 QString
00647 mimeHeader::bodyDecoded ()
00648 {
00649   kdDebug(7116) << "mimeHeader::bodyDecoded" << endl;
00650   QByteArray temp;
00651 
00652   temp = bodyDecodedBinary ();
00653   return QString::fromLatin1 (temp.data (), temp.count ());
00654 }
00655 
00656 QByteArray
00657 mimeHeader::bodyDecodedBinary ()
00658 {
00659   QByteArray retVal;
00660 
00661   if (contentEncoding.find ("quoted-printable", 0, false) == 0)
00662     retVal = KCodecs::quotedPrintableDecode(postMultipartBody);
00663   else if (contentEncoding.find ("base64", 0, false) == 0)
00664     KCodecs::base64Decode(postMultipartBody, retVal);
00665   else retVal = postMultipartBody;
00666 
00667   kdDebug(7116) << "mimeHeader::bodyDecodedBinary - size is " << retVal.size () << endl;
00668   return retVal;
00669 }
00670 
00671 void
00672 mimeHeader::setBodyEncodedBinary (const QByteArray & _arr)
00673 {
00674   setBodyEncoded (_arr);
00675 }
00676 
00677 void
00678 mimeHeader::setBodyEncoded (const QByteArray & _arr)
00679 {
00680   QByteArray setVal;
00681 
00682   kdDebug(7116) << "mimeHeader::setBodyEncoded - in size " << _arr.size () << endl;
00683   if (contentEncoding.find ("quoted-printable", 0, false) == 0)
00684     setVal = KCodecs::quotedPrintableEncode(_arr);
00685   else if (contentEncoding.find ("base64", 0, false) == 0)
00686     KCodecs::base64Encode(_arr, setVal);
00687   else
00688     setVal.duplicate (_arr);
00689   kdDebug(7116) << "mimeHeader::setBodyEncoded - out size " << setVal.size () << endl;
00690 
00691   postMultipartBody.duplicate (setVal);
00692   kdDebug(7116) << "mimeHeader::setBodyEncoded - out size " << postMultipartBody.size () << endl;
00693 }
00694 
00695 QString
00696 mimeHeader::iconName ()
00697 {
00698   QString fileName;
00699 
00700   // FIXME: bug?  Why throw away this data?
00701   fileName =
00702     KMimeType::mimeType (contentType.lower ())->icon (QString::null, false);
00703   fileName =
00704     KGlobal::instance ()->iconLoader ()->iconPath (fileName, KIcon::Desktop);
00705 //  if (fileName.isEmpty())
00706 //    fileName = KGlobal::instance()->iconLoader()->iconPath( "unknown", KIcon::Desktop );
00707   return fileName;
00708 }
00709 
00710 void
00711 mimeHeader::setNestedMessage (mailHeader * inPart, bool destroy)
00712 {
00713 //  if(nestedMessage && destroy) delete nestedMessage;
00714   nestedMessage = inPart;
00715 }
00716 
00717 QString
00718 mimeHeader::headerAsString ()
00719 {
00720   mimeIOQString myIO;
00721 
00722   outputHeader (myIO);
00723   return myIO.getString ();
00724 }
00725 
00726 QString
00727 mimeHeader::magicSetType (bool aAutoDecode)
00728 {
00729   QString mimetype;
00730   QByteArray body;
00731   KMimeMagicResult *result;
00732 
00733   KMimeMagic::self ()->setFollowLinks (TRUE); // is it necessary ?
00734 
00735   if (aAutoDecode)
00736     body = bodyDecodedBinary ();
00737   else
00738     body = postMultipartBody;
00739 
00740   result = KMimeMagic::self ()->findBufferType (body);
00741   mimetype = result->mimeType ();
00742   contentType = mimetype;
00743   return mimetype;
00744 }
00745 #endif