• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.9.4 API Reference
  • KDE Home
  • Contact Us
 

kioslave/imap4

  • kioslave
  • imap4
mimeheader.cpp
1 /***************************************************************************
2  mimeheader.cc - description
3  -------------------
4  begin : Fri Oct 20 2000
5  copyright : (C) 2000 by Sven Carstens
6  email : s.carstens@gmx.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "mimeheader.h"
19 #include "mimehdrline.h"
20 #include "mailheader.h"
21 
22 #include <QRegExp>
23 
24 // #include <iostream.h>
25 #include <kglobal.h>
26 #include <kcomponentdata.h>
27 #include <kiconloader.h>
28 #include <kmimetype.h>
29 #include <kcodecs.h>
30 #include <kdebug.h>
31 
32 #include <kimap/rfccodecs.h>
33 using namespace KIMAP;
34 
35 mimeHeader::mimeHeader ()
36  : typeList (), dispositionList (),
37  _contentType("application/octet-stream"),
38  _contentDisposition(), _contentDescription()
39 {
40  // Case insensitive hashes are killing us. Also are they too small?
41  nestedMessage = NULL;
42  contentLength = 0;
43 }
44 
45 mimeHeader::~mimeHeader ()
46 {
47 }
48 
49 /*
50 QPtrList<mimeHeader> mimeHeader::getAllParts()
51 {
52  QPtrList<mimeHeader> retVal;
53 
54  // caller is responsible for clearing
55  retVal.setAutoDelete( false );
56  nestedParts.setAutoDelete( false );
57 
58  // shallow copy
59  retVal = nestedParts;
60 
61  // can't have duplicate pointers
62  nestedParts.clear();
63 
64  // restore initial state
65  nestedParts.setAutoDelete( true );
66 
67  return retVal;
68 } */
69 
70 void
71 mimeHeader::addHdrLine (mimeHdrLine * aHdrLine)
72 {
73  mimeHdrLine *addLine = new mimeHdrLine (aHdrLine);
74  if (addLine)
75  {
76  originalHdrLines.append (addLine);
77  if (qstrnicmp (addLine->getLabel (), "Content-", 8))
78  {
79  additionalHdrLines.append (addLine);
80  }
81  else
82  {
83  int skip;
84  const char *aCStr = addLine->getValue ().data ();
85  QHash < QString, QString > *aList = 0;
86 
87  skip = mimeHdrLine::parseSeparator (';', aCStr);
88  if (skip > 0)
89  {
90  int cut = 0;
91  if (skip >= 2)
92  {
93  if (aCStr[skip - 1] == '\r')
94  cut++;
95  if (aCStr[skip - 1] == '\n')
96  cut++;
97  if (aCStr[skip - 2] == '\r')
98  cut++;
99  if (aCStr[skip - 1] == ';')
100  cut++;
101  }
102  QByteArray mimeValue(aCStr, skip - cut);
103 
104 
105  if (!qstricmp (addLine->getLabel (), "Content-Disposition"))
106  {
107  aList = &dispositionList;
108  setDisposition( mimeValue );
109  }
110  else if (!qstricmp (addLine->getLabel (), "Content-Type"))
111  {
112  aList = &typeList;
113  setType( mimeValue );
114  }
115  else if (!qstricmp (addLine->getLabel (), "Content-Transfer-Encoding"))
116  {
117  setEncoding( mimeValue );
118  }
119  else if (!qstricmp (addLine->getLabel (), "Content-ID"))
120  {
121  setID( mimeValue );
122  }
123  else if (!qstricmp (addLine->getLabel (), "Content-Description"))
124  {
125  setDescription( mimeValue );
126  }
127  else if (!qstricmp (addLine->getLabel (), "Content-MD5"))
128  {
129  setMD5( mimeValue );
130  }
131  else if (!qstricmp (addLine->getLabel (), "Content-Length"))
132  {
133  contentLength = mimeValue.toUInt ();
134  }
135  else
136  {
137  additionalHdrLines.append (addLine);
138  }
139 // cout << addLine->getLabel().data() << ": '" << mimeValue.data() << "'" << endl;
140 
141  aCStr += skip;
142  while ((skip = mimeHdrLine::parseSeparator (';', aCStr)))
143  {
144  if (skip > 0)
145  {
146  if (aList)
147  addParameter (QByteArray (aCStr, skip).simplified(), *aList);
148  mimeValue = QByteArray (addLine->getValue ().data (), skip);
149  aCStr += skip;
150  }
151  else
152  break;
153  }
154  }
155  }
156  }
157 }
158 
159 void
160 mimeHeader::addParameter (const QByteArray& aParameter, QHash < QString, QString > &aList)
161 {
162  QString aValue;
163  QByteArray aLabel;
164  int pos = aParameter.indexOf ('=');
165 // cout << aParameter.left(pos).data();
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);
170 
171  aList.insert (aLabel.toLower(), aValue);
172 // cout << "=" << aValue->data() << endl;
173 }
174 
175 QString
176 mimeHeader::getDispositionParm (const QByteArray& aStr)
177 {
178  return getParameter (aStr, dispositionList);
179 }
180 
181 QString
182 mimeHeader::getTypeParm (const QByteArray& aStr)
183 {
184  return getParameter (aStr, typeList);
185 }
186 
187 void
188 mimeHeader::setDispositionParm (const QByteArray& aLabel, const QString& aValue)
189 {
190  setParameter (aLabel, aValue, dispositionList);
191  return;
192 }
193 
194 void
195 mimeHeader::setTypeParm (const QByteArray& aLabel, const QString& aValue)
196 {
197  setParameter (aLabel, aValue, typeList);
198 }
199 
200 QHashIterator < QString, QString > mimeHeader::getDispositionIterator ()
201 {
202  return QHashIterator < QString, QString > (dispositionList);
203 }
204 
205 QHashIterator < QString, QString > mimeHeader::getTypeIterator ()
206 {
207  return QHashIterator < QString, QString > (typeList);
208 }
209 
210 QListIterator < mimeHdrLine *> mimeHeader::getOriginalIterator ()
211 {
212  return QListIterator < mimeHdrLine *> (originalHdrLines);
213 }
214 
215 QListIterator < mimeHdrLine *> mimeHeader::getAdditionalIterator ()
216 {
217  return QListIterator < mimeHdrLine *> (additionalHdrLines);
218 }
219 
220 void
221 mimeHeader::outputHeader (mimeIO & useIO)
222 {
223  if (!getDisposition ().isEmpty ())
224  {
225  useIO.outputMimeLine (QByteArray ("Content-Disposition: ")
226  + getDisposition ()
227  + outputParameter (dispositionList));
228  }
229 
230  if (!getType ().isEmpty ())
231  {
232  useIO.outputMimeLine (QByteArray ("Content-Type: ")
233  + getType () + outputParameter (typeList));
234  }
235  if (!getDescription ().isEmpty ())
236  useIO.outputMimeLine (QByteArray ("Content-Description: ") +
237  getDescription ());
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: ") +
244  getEncoding ());
245 
246  QListIterator < mimeHdrLine *> ait = getAdditionalIterator ();
247  mimeHdrLine *hdrline;
248  while (ait.hasNext ())
249  {
250  hdrline = ait.next();
251  useIO.outputMimeLine (hdrline->getLabel () + ": " +
252  hdrline->getValue ());
253  }
254  useIO.outputMimeLine (QByteArray (""));
255 }
256 
257 QString
258 mimeHeader::getParameter (const QByteArray& aStr, QHash < QString, QString > &aDict)
259 {
260  QString retVal, found;
261  //see if it is a normal parameter
262  found = aDict.value ( aStr );
263  if ( found.isEmpty() )
264  {
265  //might be a continuated or encoded parameter
266  found = aDict.value ( aStr + '*' );
267  if ( found.isEmpty() )
268  {
269  //continuated parameter
270  QString decoded, encoded;
271  int part = 0;
272 
273  do
274  {
275  QByteArray search;
276  search.setNum (part);
277  search = aStr + '*' + search;
278  found = aDict.value (search);
279  if ( found.isEmpty() )
280  {
281  found = aDict.value (search + '*');
282  if ( !found.isEmpty() )
283  encoded += KIMAP::encodeRFC2231String (found);
284  }
285  else
286  {
287  encoded += found;
288  }
289  part++;
290  }
291  while ( !found.isEmpty() );
292  if (encoded.contains ('\''))
293  {
294  retVal = KIMAP::decodeRFC2231String (encoded.toLocal8Bit ());
295  }
296  else
297  {
298  retVal =
299  KIMAP::decodeRFC2231String (QByteArray ("''") + encoded.toLocal8Bit ());
300  }
301  }
302  else
303  {
304  //simple encoded parameter
305  retVal = KIMAP::decodeRFC2231String (found.toLocal8Bit ());
306  }
307  }
308  else
309  {
310  retVal = found;
311  }
312 
313  return retVal;
314 }
315 
316 void
317 mimeHeader::setParameter (const QByteArray& aLabel, const QString& aValue,
318  QHash < QString, QString > &aDict)
319 {
320  bool encoded = true;
321  uint vlen, llen;
322  QString val = aValue;
323 
324  //see if it needs to get encoded
325  if (encoded && !aLabel.contains('*'))
326  {
327  val = KIMAP::encodeRFC2231String (aValue);
328  }
329  //kDebug(7116) <<"mimeHeader::setParameter() - val = '" << val <<"'";
330  //see if it needs to be truncated
331  vlen = val.length();
332  llen = aLabel.length();
333  if (vlen + llen + 4 > 80 && llen < 80 - 8 - 2 )
334  {
335  const int limit = 80 - 8 - 2 - (int)llen;
336  // the -2 is there to allow extending the length of a part of val
337  // by 1 or 2 in order to prevent an encoded character from being
338  // split in half
339  int i = 0;
340  QString shortValue;
341  QByteArray shortLabel;
342 
343  while (!val.isEmpty ())
344  {
345  int partLen; // the length of the next part of the value
346  if ( limit >= int(vlen) ) {
347  // the rest of the value fits completely into one continued header
348  partLen = vlen;
349  }
350  else {
351  partLen = limit;
352  // make sure that we don't split an encoded char in half
353  if ( val[partLen-1] == '%' ) {
354  partLen += 2;
355  }
356  else if ( partLen > 1 && val[partLen-2] == '%' ) {
357  partLen += 1;
358  }
359  // make sure partLen does not exceed vlen (could happen in case of
360  // an incomplete encoded char)
361  if ( partLen > int(vlen) ) {
362  partLen = vlen;
363  }
364  }
365  shortValue = val.left( partLen );
366  shortLabel.setNum (i);
367  shortLabel = aLabel + '*' + shortLabel;
368  val = val.right( vlen - partLen );
369  vlen = vlen - partLen;
370  if (encoded)
371  {
372  if (i == 0)
373  {
374  shortValue = "''" + shortValue;
375  }
376  shortLabel += '*';
377  }
378  //kDebug(7116) <<"mimeHeader::setParameter() - shortLabel = '" << shortLabel <<"'";
379  //kDebug(7116) <<"mimeHeader::setParameter() - shortValue = '" << shortValue <<"'";
380  //kDebug(7116) <<"mimeHeader::setParameter() - val = '" << val <<"'";
381  aDict.insert (shortLabel.toLower(), shortValue);
382  i++;
383  }
384  }
385  else
386  {
387  aDict.insert (aLabel.toLower(), val);
388  }
389 }
390 
391 QByteArray mimeHeader::outputParameter (QHash < QString, QString > &aDict)
392 {
393  QByteArray retVal;
394  QHashIterator < QString, QString > it (aDict);
395  while (it.hasNext ())
396  {
397  it.next();
398  retVal += (";\n\t" + it.key() + '=').toLatin1 ();
399  if (it.value().indexOf (' ') > 0 || it.value().indexOf (';') > 0)
400  {
401  retVal += '"' + it.value().toUtf8 () + '"';
402  }
403  else
404  {
405  retVal += it.value().toUtf8 ();
406  }
407  }
408  retVal += '\n';
409 
410  return retVal;
411 }
412 
413 void
414 mimeHeader::outputPart (mimeIO & useIO)
415 {
416  QListIterator < mimeHeader *> nestedPartsIterator = getNestedIterator ();
417  QByteArray boundary;
418  if (!getTypeParm ("boundary").isEmpty ())
419  boundary = getTypeParm ("boundary").toLatin1 ();
420 
421  outputHeader (useIO);
422  if (!getPreBody ().isEmpty ())
423  useIO.outputMimeLine (getPreBody ());
424  if (getNestedMessage ())
425  getNestedMessage ()->outputPart (useIO);
426 
427  mimeHeader *mimeline;
428  while (nestedPartsIterator.hasNext())
429  {
430  mimeline = nestedPartsIterator.next();
431  if (!boundary.isEmpty ())
432  useIO.outputMimeLine ("--" + boundary);
433  mimeline->outputPart (useIO);
434  }
435  if (!boundary.isEmpty ())
436  useIO.outputMimeLine ("--" + boundary + "--");
437  if (!getPostBody ().isEmpty ())
438  useIO.outputMimeLine (getPostBody ());
439 }
440 
441 #if 0
442 int
443 mimeHeader::parsePart (mimeIO & useIO, const QString& boundary)
444 {
445  int retVal = 0;
446  bool mbox = false;
447  QByteArray preNested, postNested;
448  mbox = parseHeader (useIO);
449 
450  kDebug(7116) <<"mimeHeader::parsePart - parsing part '" << getType () <<"'";
451  if (!qstrnicmp (getType (), "Multipart", 9))
452  {
453  retVal = parseBody (useIO, preNested, getTypeParm ("boundary")); //this is a message in mime format stuff
454  setPreBody (preNested);
455  int localRetVal;
456  do
457  {
458  mimeHeader *aHeader = new mimeHeader;
459 
460  // set default type for multipart/digest
461  if (!qstrnicmp (getType (), "Multipart/Digest", 16))
462  aHeader->setType ("Message/RFC822");
463 
464  localRetVal = aHeader->parsePart (useIO, getTypeParm ("boundary"));
465  addNestedPart (aHeader);
466  }
467  while (localRetVal); //get nested stuff
468  }
469  if (!qstrnicmp (getType (), "Message/RFC822", 14))
470  {
471  mailHeader *msgHeader = new mailHeader;
472  retVal = msgHeader->parsePart (useIO, boundary);
473  setNestedMessage (msgHeader);
474  }
475  else
476  {
477  retVal = parseBody (useIO, postNested, boundary, mbox); //just a simple part remaining
478  setPostBody (postNested);
479  }
480  return retVal;
481 }
482 
483 int
484 mimeHeader::parseBody (mimeIO & useIO, QByteArray & messageBody,
485  const QString& boundary, bool mbox)
486 {
487  QByteArray inputStr;
488  QByteArray buffer;
489  QString partBoundary;
490  QString partEnd;
491  int retVal = 0; //default is last part
492 
493  if (!boundary.isEmpty ())
494  {
495  partBoundary = QString ("--") + boundary;
496  partEnd = QString ("--") + boundary + "--";
497  }
498 
499  while (useIO.inputLine (inputStr))
500  {
501  //check for the end of all parts
502  if (!partEnd.isEmpty ()
503  && !qstrnicmp (inputStr, partEnd.toLatin1 (), partEnd.length () - 1))
504  {
505  retVal = 0; //end of these parts
506  break;
507  }
508  else if (!partBoundary.isEmpty ()
509  && !qstrnicmp (inputStr, partBoundary.toLatin1 (),
510  partBoundary.length () - 1))
511  {
512  retVal = 1; //continue with next part
513  break;
514  }
515  else if (mbox && inputStr.startsWith ("From ") )
516  {
517  retVal = 0; // end of mbox
518  break;
519  }
520  buffer += inputStr;
521  if (buffer.length () > 16384)
522  {
523  messageBody += buffer;
524  buffer = "";
525  }
526  }
527 
528  messageBody += buffer;
529  return retVal;
530 }
531 #endif
532 
533 bool mimeHeader::parseHeader (mimeIO & useIO)
534 {
535  bool mbox = false;
536  bool first = true;
537  mimeHdrLine my_line;
538  QByteArray inputStr;
539 
540  kDebug(7116) <<"mimeHeader::parseHeader - starting parsing";
541  while (useIO.inputLine (inputStr))
542  {
543  int appended;
544  if (!inputStr.startsWith("From ") || !first) //krazy:exclude=strings
545  {
546  first = false;
547  appended = my_line.appendStr (inputStr);
548  if (!appended)
549  {
550  addHdrLine (&my_line);
551  appended = my_line.setStr (inputStr);
552  }
553  if (appended <= 0)
554  break;
555  }
556  else
557  {
558  mbox = true;
559  first = false;
560  }
561  inputStr = QByteArray();
562  }
563 
564  kDebug(7116) <<"mimeHeader::parseHeader - finished parsing";
565  return mbox;
566 }
567 
568 mimeHeader *
569 mimeHeader::bodyPart (const QString & _str)
570 {
571  // see if it is nested a little deeper
572  int pt = _str.indexOf('.');
573  if (pt != -1)
574  {
575  QString tempStr = _str;
576  mimeHeader *tempPart;
577 
578  tempStr = _str.right (_str.length () - pt - 1);
579  if (nestedMessage)
580  {
581  kDebug(7116) <<"mimeHeader::bodyPart - recursing message";
582  tempPart = nestedMessage->nestedParts.at (_str.left(pt).toULong() - 1);
583  }
584  else
585  {
586  kDebug(7116) <<"mimeHeader::bodyPart - recursing mixed";
587  tempPart = nestedParts.at (_str.left(pt).toULong() - 1);
588  }
589  if (tempPart)
590  tempPart = tempPart->bodyPart (tempStr);
591  return tempPart;
592  }
593 
594  kDebug(7116) <<"mimeHeader::bodyPart - returning part" << _str;
595  // or pick just the plain part
596  if (nestedMessage)
597  {
598  kDebug(7116) <<"mimeHeader::bodyPart - message";
599  return nestedMessage->nestedParts.at (_str.toULong () - 1);
600  }
601  kDebug(7116) <<"mimeHeader::bodyPart - mixed";
602  return nestedParts.at (_str.toULong () - 1);
603 }
604 
605 void mimeHeader::serialize(QDataStream& stream)
606 {
607  int nestedcount = nestedParts.count();
608  if (nestedParts.isEmpty() && nestedMessage)
609  nestedcount = 1;
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;
618  // serialize nested message
619  if (nestedMessage)
620  nestedMessage->serialize(stream);
621 
622  // serialize nested parts
623  if (!nestedParts.isEmpty())
624  {
625  QListIterator < mimeHeader *> it(nestedParts);
626  mimeHeader* part;
627  while ( it.hasNext() ) {
628  part = it.next();
629  part->serialize( stream );
630  }
631  }
632 }
633 
634 #ifdef KMAIL_COMPATIBLE
635 // compatibility subroutines
636 QString
637 mimeHeader::bodyDecoded ()
638 {
639  kDebug(7116) <<"mimeHeader::bodyDecoded";
640  QByteArray temp = bodyDecodedBinary ();
641  return QString::fromLatin1 (temp.data (), temp.count ());
642 }
643 
644 QByteArray
645 mimeHeader::bodyDecodedBinary ()
646 {
647  QByteArray retVal;
648 
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;
654 
655  kDebug(7116) << "mimeHeader::bodyDecodedBinary - size is" << retVal.size ();
656  return retVal;
657 }
658 
659 void
660 mimeHeader::setBodyEncodedBinary (const QByteArray & _arr)
661 {
662  setBodyEncoded (_arr);
663 }
664 
665 void
666 mimeHeader::setBodyEncoded (const QByteArray & _arr)
667 {
668  QByteArray setVal;
669 
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);
675  else
676  setVal.duplicate (_arr);
677  kDebug(7116) <<"mimeHeader::setBodyEncoded - out size" << setVal.size ();
678 
679  postMultipartBody.duplicate (setVal);
680  kDebug(7116) <<"mimeHeader::setBodyEncoded - out size" << postMultipartBody.size ();
681 }
682 
683 QString
684 mimeHeader::iconName ()
685 {
686  QString fileName =
687  KMimeType::mimeType (contentType.toLower ())->icon (QString(), false);
688  QString iconFileName =
689  KGlobal::mainComponent().iconLoader ()->iconPath (fileName, KIconLoader::Desktop);
690 // if (iconFileName.isEmpty())
691 // iconFileName = KGlobal::mainComponent().iconLoader()->iconPath( "unknown", KIconLoader::Desktop );
692  return iconFileName;
693 }
694 
695 void
696 mimeHeader::setNestedMessage (mailHeader * inPart, bool destroy)
697 {
698 // if(nestedMessage && destroy) delete nestedMessage;
699  nestedMessage = inPart;
700 }
701 
702 QString
703 mimeHeader::headerAsString ()
704 {
705  mimeIOQString myIO;
706 
707  outputHeader (myIO);
708  return myIO.getString ();
709 }
710 
711 QString
712 mimeHeader::magicSetType (bool aAutoDecode)
713 {
714  QByteArray body;
715 
716  if (aAutoDecode)
717  body = bodyDecodedBinary ();
718  else
719  body = postMultipartBody;
720 
721  KMimeType::Ptr mime = KMimeType::findByContent (body);
722  QString mimetype = mime->name();
723  contentType = mimetype;
724  return mimetype;
725 }
726 #endif
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Tue Dec 4 2012 14:35:12 by doxygen 1.8.1.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kioslave/imap4

Skip menu "kioslave/imap4"
  • Main Page
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Related Pages

kdepimlibs-4.9.4 API Reference

Skip menu "kdepimlibs-4.9.4 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal