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 ()
75 originalHdrLines.append( addLine );
76 if ( qstrnicmp( addLine->
getLabel(),
"Content-", 8 ) ) {
77 additionalHdrLines.append( addLine );
80 const char *aCStr = addLine->
getValue().data();
81 QHash < QString, QString > *aList = 0;
87 if ( aCStr[skip - 1] ==
'\r' ) {
90 if ( aCStr[skip - 1] ==
'\n' ) {
93 if ( aCStr[skip - 2] ==
'\r' ) {
96 if ( aCStr[skip - 1] ==
';' ) {
100 QByteArray mimeValue( aCStr, skip - cut );
102 if ( !qstricmp( addLine->
getLabel(),
"Content-Disposition" ) ) {
103 aList = &dispositionList;
104 setDisposition( mimeValue );
105 }
else if ( !qstricmp( addLine->
getLabel(),
"Content-Type" ) ) {
107 setType( mimeValue );
108 }
else if ( !qstricmp( addLine->
getLabel(),
"Content-Transfer-Encoding" ) ) {
109 setEncoding( mimeValue );
110 }
else if ( !qstricmp( addLine->
getLabel(),
"Content-ID" ) ) {
112 }
else if ( !qstricmp( addLine->
getLabel(),
"Content-Description" ) ) {
113 setDescription( mimeValue );
114 }
else if ( !qstricmp( addLine->
getLabel(),
"Content-MD5" ) ) {
116 }
else if ( !qstricmp( addLine->
getLabel(),
"Content-Length" ) ) {
117 contentLength = mimeValue.toUInt();
119 additionalHdrLines.append( addLine );
127 addParameter( QByteArray( aCStr, skip ).simplified(), *aList );
129 mimeValue = QByteArray( addLine->
getValue().data(), skip );
141 mimeHeader::addParameter (
const QByteArray& aParameter, QHash < QString, QString > &aList)
145 int pos = aParameter.indexOf(
'=' );
147 aValue = QString::fromLatin1( aParameter.right( aParameter.length() - pos - 1 ) );
148 aLabel = aParameter.left( pos );
149 if ( aValue[0] ==
'"' ) {
150 aValue = aValue.mid( 1, aValue.length() - 2 );
153 aList.insert( aLabel.toLower(), aValue );
158 mimeHeader::getDispositionParm (
const QByteArray& aStr)
160 return getParameter( aStr, dispositionList );
164 mimeHeader::getTypeParm (
const QByteArray& aStr)
166 return getParameter( aStr, typeList );
170 mimeHeader::setDispositionParm (
const QByteArray& aLabel,
const QString& aValue)
172 setParameter( aLabel, aValue, dispositionList );
177 mimeHeader::setTypeParm (
const QByteArray& aLabel,
const QString& aValue)
179 setParameter( aLabel, aValue, typeList );
182 QHashIterator < QString, QString > mimeHeader::getDispositionIterator ()
184 return QHashIterator < QString, QString > ( dispositionList );
187 QHashIterator < QString, QString > mimeHeader::getTypeIterator ()
189 return QHashIterator < QString, QString > ( typeList );
192 QListIterator < mimeHdrLine *> mimeHeader::getOriginalIterator ()
194 return QListIterator < mimeHdrLine *> ( originalHdrLines );
197 QListIterator < mimeHdrLine *> mimeHeader::getAdditionalIterator ()
199 return QListIterator < mimeHdrLine *> ( additionalHdrLines );
203 mimeHeader::outputHeader (
mimeIO & useIO)
205 if ( !getDisposition().isEmpty() ) {
206 useIO.outputMimeLine( QByteArray(
"Content-Disposition: " )
208 + outputParameter( dispositionList ) );
211 if ( !getType().isEmpty() ) {
212 useIO.outputMimeLine( QByteArray(
"Content-Type: " )
213 + getType() + outputParameter( typeList ) );
215 if ( !getDescription().isEmpty() ) {
216 useIO.outputMimeLine( QByteArray(
"Content-Description: " ) +
219 if ( !getID().isEmpty() ) {
220 useIO.outputMimeLine( QByteArray(
"Content-ID: " ) + getID() );
222 if ( !getMD5().isEmpty() ) {
223 useIO.outputMimeLine( QByteArray(
"Content-MD5: " ) + getMD5() );
225 if ( !getEncoding().isEmpty() ) {
226 useIO.outputMimeLine( QByteArray(
"Content-Transfer-Encoding: " ) +
230 QListIterator < mimeHdrLine *> ait = getAdditionalIterator();
232 while ( ait.hasNext() ) {
233 hdrline = ait.next();
234 useIO.outputMimeLine( hdrline->
getLabel() +
": " +
237 useIO.outputMimeLine( QByteArray(
"" ) );
241 mimeHeader::getParameter (
const QByteArray& aStr, QHash < QString, QString > &aDict)
243 QString retVal, found;
245 found = aDict.value( aStr );
246 if ( found.isEmpty() ) {
248 found = aDict.value( aStr +
'*' );
249 if ( found.isEmpty() ) {
251 QString decoded, encoded;
256 search.setNum( part );
257 search = aStr +
'*' + search;
258 found = aDict.value( search );
259 if ( found.isEmpty() ) {
260 found = aDict.value( search +
'*' );
261 if ( !found.isEmpty() ) {
262 encoded += KIMAP::encodeRFC2231String( found );
268 }
while ( !found.isEmpty() );
269 if ( encoded.contains(
'\'' ) ) {
270 retVal = KIMAP::decodeRFC2231String( encoded.toLocal8Bit() );
272 retVal = KIMAP::decodeRFC2231String( QByteArray(
"''" ) + encoded.toLocal8Bit() );
276 retVal = KIMAP::decodeRFC2231String( found.toLocal8Bit() );
285 mimeHeader::setParameter (
const QByteArray& aLabel,
const QString& aValue,
286 QHash < QString, QString > &aDict)
290 QString val = aValue;
293 if ( encoded && !aLabel.contains(
'*' ) ) {
294 val = KIMAP::encodeRFC2231String( aValue );
299 llen = aLabel.length();
300 if ( vlen + llen + 4 > 80 && llen < 80 - 8 - 2 ) {
301 const int limit = 80 - 8 - 2 - (int)llen;
307 QByteArray shortLabel;
309 while ( !val.isEmpty() ) {
311 if ( limit >=
int(vlen) ) {
317 if ( val[partLen-1] ==
'%' ) {
319 }
else if ( partLen > 1 && val[partLen-2] ==
'%' ) {
324 if ( partLen >
int(vlen) ) {
328 shortValue = val.left( partLen );
329 shortLabel.setNum( i );
330 shortLabel = aLabel +
'*' + shortLabel;
331 val = val.right( vlen - partLen );
332 vlen = vlen - partLen;
335 shortValue =
"''" + shortValue;
342 aDict.insert( shortLabel.toLower(), shortValue );
346 aDict.insert( aLabel.toLower(), val );
350 QByteArray mimeHeader::outputParameter (QHash < QString, QString > &aDict)
353 QHashIterator < QString, QString > it( aDict );
354 while ( it.hasNext() ) {
356 retVal += (
";\n\t" + it.key() +
'=' ).toLatin1();
357 if ( it.value().indexOf(
' ' ) > 0 || it.value().indexOf(
';' ) > 0 ) {
358 retVal +=
'"' + it.value().toUtf8() +
'"';
360 retVal += it.value().toUtf8();
369 mimeHeader::outputPart (
mimeIO & useIO)
371 QListIterator < mimeHeader *> nestedPartsIterator = getNestedIterator();
373 if ( !getTypeParm(
"boundary" ).isEmpty() ) {
374 boundary = getTypeParm(
"boundary" ).toLatin1();
377 outputHeader( useIO );
378 if ( !getPreBody().isEmpty() ) {
379 useIO.outputMimeLine( getPreBody() );
381 if ( getNestedMessage() ) {
382 getNestedMessage()->outputPart( useIO );
386 while ( nestedPartsIterator.hasNext() ) {
387 mimeline = nestedPartsIterator.next();
388 if ( !boundary.isEmpty() ) {
389 useIO.outputMimeLine(
"--" + boundary );
391 mimeline->outputPart( useIO );
393 if ( !boundary.isEmpty() ) {
394 useIO.outputMimeLine(
"--" + boundary +
"--" );
396 if ( !getPostBody().isEmpty() ) {
397 useIO.outputMimeLine( getPostBody() );
403 mimeHeader::parsePart (
mimeIO & useIO,
const QString& boundary)
407 QByteArray preNested, postNested;
408 mbox = parseHeader( useIO );
410 kDebug( 7116 ) <<
"mimeHeader::parsePart - parsing part '" << getType() <<
"'";
411 if ( !qstrnicmp( getType(),
"Multipart", 9 ) ) {
412 retVal = parseBody( useIO, preNested, getTypeParm(
"boundary" ) );
413 setPreBody( preNested );
419 if ( !qstrnicmp( getType(),
"Multipart/Digest", 16 ) ) {
420 aHeader->setType(
"Message/RFC822" );
423 localRetVal = aHeader->parsePart( useIO, getTypeParm(
"boundary" ) );
424 addNestedPart( aHeader );
425 }
while ( localRetVal );
427 if ( !qstrnicmp( getType(),
"Message/RFC822", 14 ) ) {
429 retVal = msgHeader->parsePart( useIO, boundary );
430 setNestedMessage( msgHeader );
432 retVal = parseBody( useIO, postNested, boundary, mbox );
433 setPostBody( postNested );
439 mimeHeader::parseBody (
mimeIO & useIO, QByteArray & messageBody,
440 const QString& boundary,
bool mbox)
444 QString partBoundary;
448 if ( !boundary.isEmpty() ) {
449 partBoundary = QString(
"--" ) + boundary;
450 partEnd = QString(
"--" ) + boundary +
"--";
453 while ( useIO.inputLine( inputStr ) ) {
455 if ( !partEnd.isEmpty() &&
456 !qstrnicmp( inputStr, partEnd.toLatin1(), partEnd.length() - 1 ) ) {
459 }
else if ( !partBoundary.isEmpty() &&
460 !qstrnicmp( inputStr, partBoundary.toLatin1(),
461 partBoundary.length() - 1 ) ) {
464 }
else if ( mbox && inputStr.startsWith(
"From " ) ) {
469 if ( buffer.length() > 16384 ) {
470 messageBody += buffer;
475 messageBody += buffer;
480 bool mimeHeader::parseHeader (
mimeIO & useIO)
487 kDebug( 7116 ) <<
"mimeHeader::parseHeader - starting parsing";
488 while ( useIO.inputLine( inputStr ) ) {
490 if ( !inputStr.startsWith(
"From " ) || !first ) {
492 appended = my_line.appendStr( inputStr );
494 addHdrLine( &my_line );
495 appended = my_line.
setStr( inputStr );
497 if ( appended <= 0 ) {
504 inputStr = QByteArray();
507 kDebug( 7116 ) <<
"mimeHeader::parseHeader - finished parsing";
512 mimeHeader::bodyPart (
const QString & _str)
515 int pt = _str.indexOf(
'.' );
517 QString tempStr = _str;
520 tempStr = _str.right( _str.length() - pt - 1 );
521 if ( nestedMessage ) {
522 kDebug( 7116 ) <<
"mimeHeader::bodyPart - recursing message";
523 tempPart = nestedMessage->nestedParts.at( _str.left( pt ).toULong() - 1 );
525 kDebug( 7116 ) <<
"mimeHeader::bodyPart - recursing mixed";
526 tempPart = nestedParts.at( _str.left( pt ).toULong() - 1 );
529 tempPart = tempPart->bodyPart( tempStr );
534 kDebug( 7116 ) <<
"mimeHeader::bodyPart - returning part" << _str;
536 if ( nestedMessage ) {
537 kDebug( 7116 ) <<
"mimeHeader::bodyPart - message";
538 return nestedMessage->nestedParts.at( _str.toULong() - 1 );
540 kDebug( 7116 ) <<
"mimeHeader::bodyPart - mixed";
541 return nestedParts.at( _str.toULong() - 1 );
544 void mimeHeader::serialize(QDataStream& stream)
546 int nestedcount = nestedParts.count();
547 if ( nestedParts.isEmpty() && nestedMessage ) {
550 stream << nestedcount;
551 stream << _contentType;
552 stream << QString( getTypeParm(
"name" ) );
553 stream << _contentDescription;
554 stream << _contentDisposition;
555 stream << _contentEncoding;
556 stream << contentLength;
557 stream << partSpecifier;
559 if ( nestedMessage ) {
560 nestedMessage->serialize( stream );
564 if ( !nestedParts.isEmpty() ) {
565 QListIterator < mimeHeader *> it( nestedParts );
567 while ( it.hasNext() ) {
569 part->serialize( stream );
574 #ifdef KMAIL_COMPATIBLE
577 mimeHeader::bodyDecoded ()
579 kDebug( 7116 ) <<
"mimeHeader::bodyDecoded";
580 QByteArray temp = bodyDecodedBinary();
581 return QString::fromLatin1( temp.data(), temp.count() );
585 mimeHeader::bodyDecodedBinary ()
589 if ( contentEncoding.startsWith( QLatin1String(
"quoted-printable" ), Qt::CaseInsensitive ) ) {
590 retVal = KCodecs::quotedPrintableDecode( postMultipartBody );
591 }
else if ( contentEncoding.startsWith( QLatin1String(
"base64" ), Qt::CaseInsensitive ) ) {
592 KCodecs::base64Decode( postMultipartBody, retVal );
594 retVal = postMultipartBody;
597 kDebug( 7116 ) <<
"mimeHeader::bodyDecodedBinary - size is" << retVal.size();
602 mimeHeader::setBodyEncodedBinary (
const QByteArray & _arr)
604 setBodyEncoded( _arr );
608 mimeHeader::setBodyEncoded (
const QByteArray & _arr)
612 kDebug( 7116 ) <<
"mimeHeader::setBodyEncoded - in size" << _arr.size();
613 if ( contentEncoding.startsWith( QLatin1String(
"quoted-printable" ), Qt::CaseInsensitive ) ) {
614 setVal = KCodecs::quotedPrintableEncode( _arr );
615 }
else if ( contentEncoding.startsWith( QLatin1String(
"base64" ), Qt::CaseInsensitive ) ) {
616 KCodecs::base64Encode( _arr, setVal );
618 setVal.duplicate( _arr );
620 kDebug( 7116 ) <<
"mimeHeader::setBodyEncoded - out size" << setVal.size();
622 postMultipartBody.duplicate( setVal );
623 kDebug( 7116 ) <<
"mimeHeader::setBodyEncoded - out size" << postMultipartBody.size();
627 mimeHeader::iconName ()
630 KMimeType::mimeType( contentType.toLower() )->icon( QString(), false );
631 QString iconFileName =
632 KGlobal::mainComponent().iconLoader()->iconPath( fileName, KIconLoader::Desktop );
639 mimeHeader::setNestedMessage (
mailHeader * inPart,
bool destroy)
642 nestedMessage = inPart;
646 mimeHeader::headerAsString ()
650 outputHeader( myIO );
651 return myIO.getString();
655 mimeHeader::magicSetType (
bool aAutoDecode)
660 body = bodyDecodedBinary();
662 body = postMultipartBody;
665 KMimeType::Ptr mime = KMimeType::findByContent( body );
666 QString mimetype = mime->name();
667 contentType = mimetype;