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 );
87 if ( aCStr[skip - 1] ==
'\r' ) {
90 if ( aCStr[skip - 1] ==
'\n' ) {
93 if ( aCStr[skip - 2] ==
'\r' ) {
96 if ( aCStr[skip - 1] ==
';' ) {
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 );
145 int pos = aParameter.
indexOf(
'=' );
148 aLabel = aParameter.
left( pos );
149 if ( aValue[0] ==
'"' ) {
150 aValue = aValue.
mid( 1, aValue.
length() - 2 );
158 mimeHeader::getDispositionParm (
const QByteArray& aStr)
160 return getParameter( aStr, dispositionList );
164 mimeHeader::getTypeParm (
const QByteArray& aStr)
166 return getParameter( aStr, typeList );
172 setParameter( aLabel, aValue, dispositionList );
179 setParameter( aLabel, aValue, typeList );
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: " ) +
233 hdrline = ait.
next();
234 useIO.outputMimeLine( hdrline->
getLabel() +
": " +
245 found = aDict.
value( aStr );
257 search = aStr +
'*' + search;
258 found = aDict.
value( search );
262 encoded += KIMAP::encodeRFC2231String( found );
270 retVal = KIMAP::decodeRFC2231String( encoded.
toLocal8Bit() );
276 retVal = KIMAP::decodeRFC2231String( found.
toLocal8Bit() );
293 if ( encoded && !aLabel.
contains(
'*' ) ) {
294 val = KIMAP::encodeRFC2231String( aValue );
300 if ( vlen + llen + 4 > 80 && llen < 80 - 8 - 2 ) {
301 const int limit = 80 - 8 - 2 - (int)llen;
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 );
330 shortLabel = aLabel +
'*' + shortLabel;
331 val = val.
right( vlen - partLen );
332 vlen = vlen - partLen;
335 shortValue =
"''" + shortValue;
342 aDict.
insert( shortLabel.toLower(), shortValue );
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)
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();
389 useIO.outputMimeLine(
"--" + boundary );
391 mimeline->outputPart( useIO );
394 useIO.outputMimeLine(
"--" + boundary +
"--" );
396 if ( !getPostBody().isEmpty() ) {
397 useIO.outputMimeLine( getPostBody() );
403 mimeHeader::parsePart (
mimeIO & useIO,
const QString& boundary)
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 );
440 const QString& boundary,
bool mbox)
449 partBoundary =
QString(
"--" ) + boundary;
450 partEnd =
QString(
"--" ) + boundary +
"--";
453 while ( useIO.inputLine( inputStr ) ) {
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 ) {
507 kDebug( 7116 ) <<
"mimeHeader::parseHeader - finished parsing";
512 mimeHeader::bodyPart (
const QString & _str)
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";
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 );
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() ) {
567 while ( it.hasNext() ) {
569 part->serialize( stream );
574 #ifdef KMAIL_COMPATIBLE
577 mimeHeader::bodyDecoded ()
579 kDebug( 7116 ) <<
"mimeHeader::bodyDecoded";
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 );
620 kDebug( 7116 ) <<
"mimeHeader::setBodyEncoded - out size" << setVal.
size();
623 kDebug( 7116 ) <<
"mimeHeader::setBodyEncoded - out size" << postMultipartBody.
size();
627 mimeHeader::iconName ()
630 KMimeType::mimeType( contentType.toLower() )->icon(
QString(), false );
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;
ulong toULong(bool *ok, int base) const
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
static int parseSeparator(char, const char *)
parses continuated lines
iterator insert(const Key &key, const T &value)
const QByteArray & getValue()
return the value
QByteArray toLower() const
QByteArray & setNum(short n, int base)
const T & at(int i) const
bool startsWith(const QByteArray &ba) const
int indexOf(char ch, int from) const
int count(const T &value) const
void append(const T &value)
QByteArray right(int len) const
const QByteArray & getLabel()
return the label
QByteArray & duplicate(const QByteArray &a)
QString right(int n) const
const T value(const Key &key) const
QByteArray toLocal8Bit() const
bool contains(QChar ch, Qt::CaseSensitivity cs) const
QByteArray left(int len) const
int setStr(const char *)
parse a Line into the class and report characters slurped
QByteArray toLatin1() const
QString mid(int position, int n) const
bool contains(char ch) const
QString left(int n) const
QString fromLatin1(const char *str, int size)