18 #include "mimeheader.h"
19 #include "mimehdrline.h"
20 #include "mailheader.h"
26 #include <kcomponentdata.h>
27 #include <kiconloader.h>
28 #include <kmimetype.h>
32 #include <kimap/rfccodecs.h>
33 using namespace KIMAP;
35 mimeHeader::mimeHeader ()
36 : typeList (), dispositionList (),
37 _contentType(
"application/octet-stream"),
38 _contentDisposition(), _contentDescription()
45 mimeHeader::~mimeHeader ()
76 originalHdrLines.append (addLine);
77 if (qstrnicmp (addLine->
getLabel (),
"Content-", 8))
79 additionalHdrLines.append (addLine);
84 const char *aCStr = addLine->
getValue ().data ();
85 QHash < QString, QString > *aList = 0;
93 if (aCStr[skip - 1] ==
'\r')
95 if (aCStr[skip - 1] ==
'\n')
97 if (aCStr[skip - 2] ==
'\r')
99 if (aCStr[skip - 1] ==
';')
102 QByteArray mimeValue(aCStr, skip - cut);
105 if (!qstricmp (addLine->
getLabel (),
"Content-Disposition"))
107 aList = &dispositionList;
108 setDisposition( mimeValue );
110 else if (!qstricmp (addLine->
getLabel (),
"Content-Type"))
113 setType( mimeValue );
115 else if (!qstricmp (addLine->
getLabel (),
"Content-Transfer-Encoding"))
117 setEncoding( mimeValue );
119 else if (!qstricmp (addLine->
getLabel (),
"Content-ID"))
123 else if (!qstricmp (addLine->
getLabel (),
"Content-Description"))
125 setDescription( mimeValue );
127 else if (!qstricmp (addLine->
getLabel (),
"Content-MD5"))
131 else if (!qstricmp (addLine->
getLabel (),
"Content-Length"))
133 contentLength = mimeValue.toUInt ();
137 additionalHdrLines.append (addLine);
147 addParameter (QByteArray (aCStr, skip).simplified(), *aList);
148 mimeValue = QByteArray (addLine->
getValue ().data (), skip);
160 mimeHeader::addParameter (
const QByteArray& aParameter, QHash < QString, QString > &aList)
164 int pos = aParameter.indexOf (
'=');
166 aValue = QString::fromLatin1 (aParameter.right (aParameter.length () - pos - 1));
167 aLabel = aParameter.left (pos);
168 if (aValue[0] ==
'"')
169 aValue = aValue.mid (1, aValue.length () - 2);
171 aList.insert (aLabel.toLower(), aValue);
176 mimeHeader::getDispositionParm (
const QByteArray& aStr)
178 return getParameter (aStr, dispositionList);
182 mimeHeader::getTypeParm (
const QByteArray& aStr)
184 return getParameter (aStr, typeList);
188 mimeHeader::setDispositionParm (
const QByteArray& aLabel,
const QString& aValue)
190 setParameter (aLabel, aValue, dispositionList);
195 mimeHeader::setTypeParm (
const QByteArray& aLabel,
const QString& aValue)
197 setParameter (aLabel, aValue, typeList);
200 QHashIterator < QString, QString > mimeHeader::getDispositionIterator ()
202 return QHashIterator < QString, QString > (dispositionList);
205 QHashIterator < QString, QString > mimeHeader::getTypeIterator ()
207 return QHashIterator < QString, QString > (typeList);
210 QListIterator < mimeHdrLine *> mimeHeader::getOriginalIterator ()
212 return QListIterator < mimeHdrLine *> (originalHdrLines);
215 QListIterator < mimeHdrLine *> mimeHeader::getAdditionalIterator ()
217 return QListIterator < mimeHdrLine *> (additionalHdrLines);
221 mimeHeader::outputHeader (
mimeIO & useIO)
223 if (!getDisposition ().isEmpty ())
225 useIO.outputMimeLine (QByteArray (
"Content-Disposition: ")
227 + outputParameter (dispositionList));
230 if (!getType ().isEmpty ())
232 useIO.outputMimeLine (QByteArray (
"Content-Type: ")
233 + getType () + outputParameter (typeList));
235 if (!getDescription ().isEmpty ())
236 useIO.outputMimeLine (QByteArray (
"Content-Description: ") +
238 if (!getID ().isEmpty ())
239 useIO.outputMimeLine (QByteArray (
"Content-ID: ") + getID ());
240 if (!getMD5 ().isEmpty ())
241 useIO.outputMimeLine (QByteArray (
"Content-MD5: ") + getMD5 ());
242 if (!getEncoding ().isEmpty ())
243 useIO.outputMimeLine (QByteArray (
"Content-Transfer-Encoding: ") +
246 QListIterator < mimeHdrLine *> ait = getAdditionalIterator ();
248 while (ait.hasNext ())
250 hdrline = ait.next();
251 useIO.outputMimeLine (hdrline->
getLabel () +
": " +
254 useIO.outputMimeLine (QByteArray (
""));
258 mimeHeader::getParameter (
const QByteArray& aStr, QHash < QString, QString > &aDict)
260 QString retVal, found;
262 found = aDict.value ( aStr );
263 if ( found.isEmpty() )
266 found = aDict.value ( aStr +
'*' );
267 if ( found.isEmpty() )
270 QString decoded, encoded;
276 search.setNum (part);
277 search = aStr +
'*' + search;
278 found = aDict.value (search);
279 if ( found.isEmpty() )
281 found = aDict.value (search +
'*');
282 if ( !found.isEmpty() )
283 encoded += KIMAP::encodeRFC2231String (found);
291 while ( !found.isEmpty() );
292 if (encoded.contains (
'\''))
294 retVal = KIMAP::decodeRFC2231String (encoded.toLocal8Bit ());
299 KIMAP::decodeRFC2231String (QByteArray (
"''") + encoded.toLocal8Bit ());
305 retVal = KIMAP::decodeRFC2231String (found.toLocal8Bit ());
317 mimeHeader::setParameter (
const QByteArray& aLabel,
const QString& aValue,
318 QHash < QString, QString > &aDict)
322 QString val = aValue;
325 if (encoded && !aLabel.contains(
'*'))
327 val = KIMAP::encodeRFC2231String (aValue);
332 llen = aLabel.length();
333 if (vlen + llen + 4 > 80 && llen < 80 - 8 - 2 )
335 const int limit = 80 - 8 - 2 - (int)llen;
341 QByteArray shortLabel;
343 while (!val.isEmpty ())
346 if ( limit >=
int(vlen) ) {
353 if ( val[partLen-1] ==
'%' ) {
356 else if ( partLen > 1 && val[partLen-2] ==
'%' ) {
361 if ( partLen >
int(vlen) ) {
365 shortValue = val.left( partLen );
366 shortLabel.setNum (i);
367 shortLabel = aLabel +
'*' + shortLabel;
368 val = val.right( vlen - partLen );
369 vlen = vlen - partLen;
374 shortValue =
"''" + shortValue;
381 aDict.insert (shortLabel.toLower(), shortValue);
387 aDict.insert (aLabel.toLower(), val);
391 QByteArray mimeHeader::outputParameter (QHash < QString, QString > &aDict)
394 QHashIterator < QString, QString > it (aDict);
395 while (it.hasNext ())
398 retVal += (
";\n\t" + it.key() +
'=').toLatin1 ();
399 if (it.value().indexOf (
' ') > 0 || it.value().indexOf (
';') > 0)
401 retVal +=
'"' + it.value().toUtf8 () +
'"';
405 retVal += it.value().toUtf8 ();
414 mimeHeader::outputPart (
mimeIO & useIO)
416 QListIterator < mimeHeader *> nestedPartsIterator = getNestedIterator ();
418 if (!getTypeParm (
"boundary").isEmpty ())
419 boundary = getTypeParm (
"boundary").toLatin1 ();
421 outputHeader (useIO);
422 if (!getPreBody ().isEmpty ())
423 useIO.outputMimeLine (getPreBody ());
424 if (getNestedMessage ())
425 getNestedMessage ()->outputPart (useIO);
428 while (nestedPartsIterator.hasNext())
430 mimeline = nestedPartsIterator.next();
431 if (!boundary.isEmpty ())
432 useIO.outputMimeLine (
"--" + boundary);
433 mimeline->outputPart (useIO);
435 if (!boundary.isEmpty ())
436 useIO.outputMimeLine (
"--" + boundary +
"--");
437 if (!getPostBody ().isEmpty ())
438 useIO.outputMimeLine (getPostBody ());
443 mimeHeader::parsePart (
mimeIO & useIO,
const QString& boundary)
447 QByteArray preNested, postNested;
448 mbox = parseHeader (useIO);
450 kDebug(7116) <<
"mimeHeader::parsePart - parsing part '" << getType () <<
"'";
451 if (!qstrnicmp (getType (),
"Multipart", 9))
453 retVal = parseBody (useIO, preNested, getTypeParm (
"boundary"));
454 setPreBody (preNested);
461 if (!qstrnicmp (getType (),
"Multipart/Digest", 16))
462 aHeader->setType (
"Message/RFC822");
464 localRetVal = aHeader->parsePart (useIO, getTypeParm (
"boundary"));
465 addNestedPart (aHeader);
469 if (!qstrnicmp (getType (),
"Message/RFC822", 14))
472 retVal = msgHeader->parsePart (useIO, boundary);
473 setNestedMessage (msgHeader);
477 retVal = parseBody (useIO, postNested, boundary, mbox);
478 setPostBody (postNested);
484 mimeHeader::parseBody (
mimeIO & useIO, QByteArray & messageBody,
485 const QString& boundary,
bool mbox)
489 QString partBoundary;
493 if (!boundary.isEmpty ())
495 partBoundary = QString (
"--") + boundary;
496 partEnd = QString (
"--") + boundary +
"--";
499 while (useIO.inputLine (inputStr))
502 if (!partEnd.isEmpty ()
503 && !qstrnicmp (inputStr, partEnd.toLatin1 (), partEnd.length () - 1))
508 else if (!partBoundary.isEmpty ()
509 && !qstrnicmp (inputStr, partBoundary.toLatin1 (),
510 partBoundary.length () - 1))
515 else if (mbox && inputStr.startsWith (
"From ") )
521 if (buffer.length () > 16384)
523 messageBody += buffer;
528 messageBody += buffer;
533 bool mimeHeader::parseHeader (
mimeIO & useIO)
540 kDebug(7116) <<
"mimeHeader::parseHeader - starting parsing";
541 while (useIO.inputLine (inputStr))
544 if (!inputStr.startsWith(
"From ") || !first)
547 appended = my_line.appendStr (inputStr);
550 addHdrLine (&my_line);
551 appended = my_line.
setStr (inputStr);
561 inputStr = QByteArray();
564 kDebug(7116) <<
"mimeHeader::parseHeader - finished parsing";
569 mimeHeader::bodyPart (
const QString & _str)
572 int pt = _str.indexOf(
'.');
575 QString tempStr = _str;
578 tempStr = _str.right (_str.length () - pt - 1);
581 kDebug(7116) <<
"mimeHeader::bodyPart - recursing message";
582 tempPart = nestedMessage->nestedParts.at (_str.left(pt).toULong() - 1);
586 kDebug(7116) <<
"mimeHeader::bodyPart - recursing mixed";
587 tempPart = nestedParts.at (_str.left(pt).toULong() - 1);
590 tempPart = tempPart->bodyPart (tempStr);
594 kDebug(7116) <<
"mimeHeader::bodyPart - returning part" << _str;
598 kDebug(7116) <<
"mimeHeader::bodyPart - message";
599 return nestedMessage->nestedParts.at (_str.toULong () - 1);
601 kDebug(7116) <<
"mimeHeader::bodyPart - mixed";
602 return nestedParts.at (_str.toULong () - 1);
605 void mimeHeader::serialize(QDataStream& stream)
607 int nestedcount = nestedParts.count();
608 if (nestedParts.isEmpty() && nestedMessage)
610 stream << nestedcount;
611 stream << _contentType;
612 stream << QString (getTypeParm (
"name"));
613 stream << _contentDescription;
614 stream << _contentDisposition;
615 stream << _contentEncoding;
616 stream << contentLength;
617 stream << partSpecifier;
620 nestedMessage->serialize(stream);
623 if (!nestedParts.isEmpty())
625 QListIterator < mimeHeader *> it(nestedParts);
627 while ( it.hasNext() ) {
629 part->serialize( stream );
634 #ifdef KMAIL_COMPATIBLE
637 mimeHeader::bodyDecoded ()
639 kDebug(7116) <<
"mimeHeader::bodyDecoded";
640 QByteArray temp = bodyDecodedBinary ();
641 return QString::fromLatin1 (temp.data (), temp.count ());
645 mimeHeader::bodyDecodedBinary ()
649 if (contentEncoding.startsWith (QLatin1String(
"quoted-printable"), Qt::CaseInsensitive) )
650 retVal = KCodecs::quotedPrintableDecode(postMultipartBody);
651 else if (contentEncoding.startsWith (QLatin1String(
"base64"), Qt::CaseInsensitive) )
652 KCodecs::base64Decode(postMultipartBody, retVal);
653 else retVal = postMultipartBody;
655 kDebug(7116) <<
"mimeHeader::bodyDecodedBinary - size is" << retVal.size ();
660 mimeHeader::setBodyEncodedBinary (
const QByteArray & _arr)
662 setBodyEncoded (_arr);
666 mimeHeader::setBodyEncoded (
const QByteArray & _arr)
670 kDebug(7116) <<
"mimeHeader::setBodyEncoded - in size" << _arr.size ();
671 if (contentEncoding.startsWith (QLatin1String(
"quoted-printable"), Qt::CaseInsensitive) )
672 setVal = KCodecs::quotedPrintableEncode(_arr);
673 else if (contentEncoding.startsWith (QLatin1String(
"base64"), Qt::CaseInsensitive) )
674 KCodecs::base64Encode(_arr, setVal);
676 setVal.duplicate (_arr);
677 kDebug(7116) <<
"mimeHeader::setBodyEncoded - out size" << setVal.size ();
679 postMultipartBody.duplicate (setVal);
680 kDebug(7116) <<
"mimeHeader::setBodyEncoded - out size" << postMultipartBody.size ();
684 mimeHeader::iconName ()
687 KMimeType::mimeType (contentType.toLower ())->icon (QString(),
false);
688 QString iconFileName =
689 KGlobal::mainComponent().iconLoader ()->iconPath (fileName, KIconLoader::Desktop);
696 mimeHeader::setNestedMessage (
mailHeader * inPart,
bool destroy)
699 nestedMessage = inPart;
703 mimeHeader::headerAsString ()
708 return myIO.getString ();
712 mimeHeader::magicSetType (
bool aAutoDecode)
717 body = bodyDecodedBinary ();
719 body = postMultipartBody;
721 KMimeType::Ptr mime = KMimeType::findByContent (body);
722 QString mimetype = mime->name();
723 contentType = mimetype;