KMime

kmime_headers.cpp
Go to the documentation of this file.
1 /* -*- c++ -*-
2  kmime_headers.cpp
3 
4  KMime, the KDE Internet mail/usenet news message library.
5  SPDX-FileCopyrightText: 2001-2002 the KMime authors.
6  See file AUTHORS for details
7  SPDX-FileCopyrightText: 2006 Volker Krause <[email protected]>
8 
9  SPDX-License-Identifier: LGPL-2.0-or-later
10 */
11 /**
12  @file
13  This file is part of the API for handling @ref MIME data and
14  defines the various header classes:
15  - header's base class defining the common interface
16  - generic base classes for different types of fields
17  - incompatible, Structured-based field classes
18  - compatible, Unstructured-based field classes
19 
20  @brief
21  Defines the various headers classes.
22 
23  @authors the KMime authors (see AUTHORS file),
24  Volker Krause <[email protected]>
25 */
26 
27 #include "kmime_headers.h"
28 #include "kmime_headers_p.h"
29 
30 #include "kmime_util.h"
31 #include "kmime_util_p.h"
32 #include "kmime_codecs.h"
33 #include "kmime_content.h"
34 #include "kmime_headerfactory_p.h"
35 #include "kmime_debug.h"
36 #include "kmime_warning.h"
37 
38 #include <KCodecs>
39 
40 #include <cassert>
41 #include <cctype>
42 
43 // macro to generate a default constructor implementation
44 #define kmime_mk_trivial_ctor( subclass, baseclass ) \
45  subclass::subclass() : baseclass() \
46  { \
47  } \
48  \
49  subclass::~subclass() {}
50 
51 // end kmime_mk_trivial_ctor
52 
53 #define kmime_mk_trivial_ctor_with_dptr( subclass, baseclass ) \
54  subclass::subclass() : baseclass( new subclass##Private ) \
55  { \
56  } \
57  \
58  subclass::~subclass() { \
59  Q_D(subclass); \
60  delete d; /* see comment above the BasePrivate class */ \
61  d_ptr = nullptr; \
62  }
63 
64 // end kmime_mk_trivial_ctor_with_dptr
65 
66 #define kmime_mk_trivial_ctor_with_name( subclass, baseclass, name ) \
67  kmime_mk_trivial_ctor( subclass, baseclass ) \
68  \
69  const char *subclass::type() const \
70  { \
71  return staticType(); \
72  } \
73  const char *subclass::staticType() { return #name; }
74 
75 #define kmime_mk_trivial_ctor_with_name_and_dptr( subclass, baseclass, name ) \
76  kmime_mk_trivial_ctor_with_dptr( subclass, baseclass ) \
77  const char *subclass::type() const { return staticType(); } \
78  const char *subclass::staticType() { return #name; }
79 
80 #define kmime_mk_dptr_ctor( subclass, baseclass ) \
81  subclass::subclass( subclass##Private *d ) : baseclass( d ) {}
82 
83 using namespace KMime;
84 using namespace KMime::Headers;
85 using namespace KMime::Types;
86 using namespace KMime::HeaderParsing;
87 
88 namespace KMime
89 {
90 namespace Headers
91 {
92 //-----<Base>----------------------------------
93 Base::Base() : d_ptr(new BasePrivate)
94 {
95 }
96 
97 Base::Base(BasePrivate *dd) :
98  d_ptr(dd)
99 {
100 }
101 
103 {
104  delete d_ptr;
105  d_ptr = nullptr;
106 }
107 
108 void Base::from7BitString(const char *s, size_t len)
109 {
111 }
112 
114 {
115  if (d_ptr->encCS.isEmpty()) {
116  return Content::defaultCharset();
117  } else {
118  return d_ptr->encCS;
119  }
120 }
121 
123 {
124  d_ptr->encCS = cachedCharset(cs);
125 }
126 
127 const char *Base::type() const
128 {
129  return "";
130 }
131 
132 bool Base::is(const char *t) const
133 {
134  return qstricmp(t, type()) == 0;
135 }
136 
137 bool Base::isMimeHeader() const
138 {
139  return qstrnicmp(type(), "Content-", 8) == 0;
140 }
141 
143 {
144  return QByteArray(type()) + ": ";
145 }
146 
147 //-----</Base>---------------------------------
148 
149 namespace Generics
150 {
151 
152 //-----<Unstructured>-------------------------
153 
154 //@cond PRIVATE
155 kmime_mk_dptr_ctor(Unstructured, Base)
156 //@endcond
157 
158 Unstructured::Unstructured() : Base(new UnstructuredPrivate)
159 {
160 }
161 
162 Unstructured::~Unstructured()
163 {
164  Q_D(Unstructured);
165  delete d;
166  d_ptr = nullptr;
167 }
168 
169 void Unstructured::from7BitString(const QByteArray &s)
170 {
171  Q_D(Unstructured);
172  d->decoded = KCodecs::decodeRFC2047String(s, &d->encCS, Content::defaultCharset());
173 }
174 
175 QByteArray Unstructured::as7BitString(bool withHeaderType) const
176 {
177  const Q_D(Unstructured);
178  QByteArray result;
179  if (withHeaderType) {
180  result = typeIntro();
181  }
182  result += encodeRFC2047String(d->decoded, d->encCS) ;
183 
184  return result;
185 }
186 
187 void Unstructured::fromUnicodeString(const QString &s, const QByteArray &b)
188 {
189  Q_D(Unstructured);
190  d->decoded = s;
191  d->encCS = cachedCharset(b);
192 }
193 
194 QString Unstructured::asUnicodeString() const
195 {
196  return d_func()->decoded;
197 }
198 
199 void Unstructured::clear()
200 {
201  Q_D(Unstructured);
202  d->decoded.truncate(0);
203 }
204 
205 bool Unstructured::isEmpty() const
206 {
207  return d_func()->decoded.isEmpty();
208 }
209 
210 //-----</Unstructured>-------------------------
211 
212 //-----<Structured>-------------------------
213 
214 Structured::Structured() : Base(new StructuredPrivate)
215 {
216 }
217 
218 kmime_mk_dptr_ctor(Structured, Base)
219 
220 Structured::~Structured()
221 {
222  Q_D(Structured);
223  delete d;
224  d_ptr = nullptr;
225 }
226 
227 
228 void Structured::from7BitString(const char *s, size_t len)
229 {
230  Q_D(Structured);
231  if (d->encCS.isEmpty()) {
232  d->encCS = Content::defaultCharset();
233  }
234  parse(s, s + len);
235 }
236 
238 {
239 #if 0
240  Q_D(Structured);
241  //Bug about mailto with space which are replaced by "_" so it failed to parse
242  //=> we reconvert to correct encoding as RFC2047
243  const QString str = KCodecs::decodeRFC2047String(s, &d->encCS, Content::defaultCharset());
244  const QByteArray ba = KCodecs::encodeRFC2047String(str, d->encCS);
245  from7BitString(ba.constData(), ba.length());
246 #else
247  from7BitString(s.constData(), s.length());
248 #endif
249 }
250 
252 {
253  return QString::fromLatin1(as7BitString(false));
254 }
255 
257 {
258  Q_D(Structured);
259  d->encCS = cachedCharset(b);
261 }
262 
263 //-----</Structured>-------------------------
264 
265 //-----<Address>-------------------------
266 
267 Address::Address() : Structured(new AddressPrivate)
268 {
269 }
270 
271 kmime_mk_dptr_ctor(Address, Structured)
272 
273  Address::~Address() = default;
274 
275 // helper method used in AddressList and MailboxList
276 static bool stringToMailbox(const QByteArray &address,
277  const QString &displayName, Types::Mailbox &mbox)
278 {
279  Types::AddrSpec addrSpec;
280  mbox.setName(displayName);
281  const char *cursor = address.constData();
282  if (!parseAngleAddr(cursor, cursor + address.length(), addrSpec)) {
283  if (!parseAddrSpec(cursor, cursor + address.length(), addrSpec)) {
284  qCWarning(KMIME_LOG) << "stringToMailbox: Invalid address";
285  return false;
286  }
287  }
288  mbox.setAddress(addrSpec);
289  return true;
290 }
291 
292 //-----</Address>-------------------------
293 
294 //-----<MailboxList>-------------------------
295 
296 kmime_mk_trivial_ctor_with_dptr(MailboxList, Address)
297 kmime_mk_dptr_ctor(MailboxList, Address)
298 
299 QByteArray MailboxList::as7BitString(bool withHeaderType) const
300 {
301  const Q_D(MailboxList);
302  if (isEmpty()) {
303  return {};
304  }
305 
306  QByteArray rv;
307  if (withHeaderType) {
308  rv = typeIntro();
309  }
310  for (const Types::Mailbox &mbox : std::as_const(d->mailboxList)) {
311  rv += mbox.as7BitString(d->encCS);
312  rv += ", ";
313  }
314  rv.resize(rv.length() - 2);
315  return rv;
316 }
317 
319 {
320  Q_D(MailboxList);
321  d->encCS = cachedCharset(b);
322  from7BitString(encodeRFC2047Sentence(s, b));
323 }
324 
326 {
327  Q_D(const MailboxList);
328  return Mailbox::listToUnicodeString(d->mailboxList);
329 }
330 
332 {
333  Q_D(MailboxList);
334  d->mailboxList.clear();
335 }
336 
338 {
339  return d_func()->mailboxList.isEmpty();
340 }
341 
343 {
344  Q_D(MailboxList);
345  d->mailboxList.append(mbox);
346 }
347 
349  const QString &displayName)
350 {
351  Q_D(MailboxList);
352  Types::Mailbox mbox;
353  if (stringToMailbox(address, displayName, mbox)) {
354  d->mailboxList.append(mbox);
355  }
356 }
357 
360  rv.reserve(d_func()->mailboxList.count());
361  const auto mailboxList = d_func()->mailboxList;
362  for (const Types::Mailbox &mbox : mailboxList) {
363  rv.append(mbox.address());
364  }
365  return rv;
366 }
367 
369 {
370  Q_D(const MailboxList);
371  QStringList rv;
372  rv.reserve(d->mailboxList.count());
373  for (const Types::Mailbox &mbox : std::as_const(d->mailboxList)) {
374  if (mbox.hasName()) {
375  rv.append(mbox.name());
376  } else {
377  rv.append(QString::fromLatin1(mbox.address()));
378  }
379  }
380  return rv;
381 }
382 
384 {
385  Q_D(const MailboxList);
386  if (d->mailboxList.size() == 1) { // fast-path to avoid temporary QStringList in the common case of just one From address
387  const auto& mbox = d->mailboxList.at(0);
388  if (mbox.hasName()) {
389  return mbox.name();
390  } else {
391  return QString::fromLatin1(mbox.address());
392  }
393  }
394  return displayNames().join(QLatin1String(", "));
395 }
396 
398 {
399  return d_func()->mailboxList;
400 }
401 
402 bool MailboxList::parse(const char *&scursor, const char *const send,
403  bool isCRLF)
404 {
405  Q_D(MailboxList);
406  // examples:
407  // from := "From:" mailbox-list CRLF
408  // sender := "Sender:" mailbox CRLF
409 
410  // parse an address-list:
411  QList<Types::Address> maybeAddressList;
412  if (!parseAddressList(scursor, send, maybeAddressList, isCRLF)) {
413  return false;
414  }
415 
416  d->mailboxList.clear();
417  d->mailboxList.reserve(maybeAddressList.count());
418 
419  // extract the mailboxes and complain if there are groups:
420  for (const auto &it : std::as_const(maybeAddressList)) {
421  if (!(it).displayName.isEmpty()) {
422  KMIME_WARN << "mailbox groups in header disallowing them! Name: \""
423  << (it).displayName << "\""
424  << Qt::endl
425  ;
426  }
427  d->mailboxList += (it).mailboxList;
428  }
429  return true;
430 }
431 
432 //-----</MailboxList>-------------------------
433 
434 //-----<SingleMailbox>-------------------------
435 
436 //@cond PRIVATE
437 kmime_mk_trivial_ctor_with_dptr(SingleMailbox, MailboxList)
438 //@endcond
439 
440 bool SingleMailbox::parse(const char *&scursor, const char *const send,
441  bool isCRLF)
442 {
443  Q_D(MailboxList);
444  if (!MailboxList::parse(scursor, send, isCRLF)) {
445  return false;
446  }
447 
448  if (d->mailboxList.count() > 1) {
449  KMIME_WARN << "multiple mailboxes in header allowing only a single one!"
450  << Qt::endl;
451  }
452  return true;
453 }
454 
455 //-----</SingleMailbox>-------------------------
456 
457 //-----<AddressList>-------------------------
458 
459 //@cond PRIVATE
460 kmime_mk_trivial_ctor_with_dptr(AddressList, Address)
461 kmime_mk_dptr_ctor(AddressList, Address)
462 //@endcond
463 
464 QByteArray AddressList::as7BitString(bool withHeaderType) const
465 {
466  const Q_D(AddressList);
467  if (d->addressList.isEmpty()) {
468  return {};
469  }
470 
471  QByteArray rv;
472  if (withHeaderType) {
473  rv = typeIntro();
474  }
475  for (const Types::Address &addr : std::as_const(d->addressList)) {
476  const auto mailBoxList = addr.mailboxList;
477  for (const Types::Mailbox &mbox : mailBoxList) {
478  rv += mbox.as7BitString(d->encCS);
479  rv += ", ";
480  }
481  }
482  rv.resize(rv.length() - 2);
483  return rv;
484 }
485 
487 {
488  Q_D(AddressList);
489  d->encCS = cachedCharset(b);
490  from7BitString(encodeRFC2047Sentence(s, b));
491 }
492 
494 {
495  Q_D(const AddressList);
496  QStringList rv;
497  for (const Types::Address &addr : std::as_const(d->addressList)) {
498  rv.reserve(rv.size() + addr.mailboxList.size());
499  const auto mailboxList = addr.mailboxList;
500  for (const Types::Mailbox &mbox : mailboxList) {
501  rv.append(mbox.prettyAddress());
502  }
503  }
504  return rv.join(QLatin1String(", "));
505 }
506 
508 {
509  Q_D(AddressList);
510  d->addressList.clear();
511 }
512 
514 {
515  return d_func()->addressList.isEmpty();
516 }
517 
519 {
520  Q_D(AddressList);
521  Types::Address addr;
522  addr.mailboxList.append(mbox);
523  d->addressList.append(addr);
524 }
525 
527  const QString &displayName)
528 {
529  Q_D(AddressList);
530  Types::Address addr;
531  Types::Mailbox mbox;
532  if (stringToMailbox(address, displayName, mbox)) {
533  addr.mailboxList.append(mbox);
534  d->addressList.append(addr);
535  }
536 }
537 
540  const auto addressList = d_func()->addressList;
541  for (const Types::Address &addr : addressList) {
542  const auto mailboxList = addr.mailboxList;
543  for (const Types::Mailbox &mbox : mailboxList) {
544  rv.append(mbox.address());
545  }
546  }
547  return rv;
548 }
549 
551 {
552  Q_D(const AddressList);
553  QStringList rv;
554  for (const Types::Address &addr : std::as_const(d->addressList)) {
555  const auto mailboxList = addr.mailboxList;
556  for (const Types::Mailbox &mbox : mailboxList) {
557  if (mbox.hasName()) {
558  rv.append(mbox.name());
559  } else {
560  rv.append(QString::fromLatin1(mbox.address()));
561  }
562  }
563  }
564  return rv;
565 }
566 
568 {
569  // optimize for single entry and avoid creation of the QStringList in that case?
570  return displayNames().join(QLatin1String(", "));
571 }
572 
574 {
576  const auto addressList = d_func()->addressList;
577  for (const Types::Address &addr : addressList) {
578  const auto mailboxList = addr.mailboxList;
579  for (const Types::Mailbox &mbox : mailboxList) {
580  rv.append(mbox);
581  }
582  }
583  return rv;
584 }
585 
586 bool AddressList::parse(const char *&scursor, const char *const send,
587  bool isCRLF)
588 {
589  Q_D(AddressList);
590  QList<Types::Address> maybeAddressList;
591  if (!parseAddressList(scursor, send, maybeAddressList, isCRLF)) {
592  return false;
593  }
594 
595  d->addressList = maybeAddressList;
596  return true;
597 }
598 
599 //-----</AddressList>-------------------------
600 
601 //-----<Token>-------------------------
602 
603 //@cond PRIVATE
604 kmime_mk_trivial_ctor_with_dptr(Token, Structured)
605 kmime_mk_dptr_ctor(Token, Structured)
606 //@endcond
607 
608 QByteArray Token::as7BitString(bool withHeaderType) const
609 {
610  if (isEmpty()) {
611  return {};
612  }
613  if (withHeaderType) {
614  return typeIntro() + d_func()->token;
615  }
616  return d_func()->token;
617 }
618 
620 {
621  Q_D(Token);
622  d->token.clear();
623 }
624 
625 bool Token::isEmpty() const
626 {
627  return d_func()->token.isEmpty();
628 }
629 
631 {
632  return d_func()->token;
633 }
634 
636 {
637  Q_D(Token);
638  d->token = t;
639 }
640 
641 bool Token::parse(const char *&scursor, const char *const send, bool isCRLF)
642 {
643  Q_D(Token);
644  clear();
645  eatCFWS(scursor, send, isCRLF);
646  // must not be empty:
647  if (scursor == send) {
648  return false;
649  }
650 
651  QPair<const char *, int> maybeToken;
652  if (!parseToken(scursor, send, maybeToken, ParseTokenNoFlag)) {
653  return false;
654  }
655  d->token = QByteArray(maybeToken.first, maybeToken.second);
656 
657  // complain if trailing garbage is found:
658  eatCFWS(scursor, send, isCRLF);
659  if (scursor != send) {
660  KMIME_WARN << "trailing garbage after token in header allowing "
661  "only a single token!"
662  << Qt::endl;
663  }
664  return true;
665 }
666 
667 //-----</Token>-------------------------
668 
669 //-----<PhraseList>-------------------------
670 
671 //@cond PRIVATE
672 kmime_mk_trivial_ctor_with_dptr(PhraseList, Structured)
673 //@endcond
674 
675 QByteArray PhraseList::as7BitString(bool withHeaderType) const
676 {
677  const Q_D(PhraseList);
678  if (isEmpty()) {
679  return {};
680  }
681 
682  QByteArray rv;
683  if (withHeaderType) {
684  rv = typeIntro();
685  }
686 
687  for (int i = 0; i < d->phraseList.count(); ++i) {
688  // FIXME: only encode when needed, quote when needed, etc.
689  rv += encodeRFC2047String(d->phraseList[i], d->encCS, false, false);
690  if (i != d->phraseList.count() - 1) {
691  rv += ", ";
692  }
693  }
694 
695  return rv;
696 }
697 
699 {
700  return d_func()->phraseList.join(QLatin1String(", "));
701 }
702 
704 {
705  Q_D(PhraseList);
706  d->phraseList.clear();
707 }
708 
710 {
711  return d_func()->phraseList.isEmpty();
712 }
713 
715 {
716  return d_func()->phraseList;
717 }
718 
719 bool PhraseList::parse(const char *&scursor, const char *const send,
720  bool isCRLF)
721 {
722  Q_D(PhraseList);
723  d->phraseList.clear();
724 
725  while (scursor != send) {
726  eatCFWS(scursor, send, isCRLF);
727  // empty entry ending the list: OK.
728  if (scursor == send) {
729  return true;
730  }
731  // empty entry: ignore.
732  if (*scursor == ',') {
733  scursor++;
734  continue;
735  }
736 
737  QString maybePhrase;
738  if (!parsePhrase(scursor, send, maybePhrase, isCRLF)) {
739  return false;
740  }
741  d->phraseList.append(maybePhrase);
742 
743  eatCFWS(scursor, send, isCRLF);
744  // non-empty entry ending the list: OK.
745  if (scursor == send) {
746  return true;
747  }
748  // comma separating the phrases: eat.
749  if (*scursor == ',') {
750  scursor++;
751  }
752  }
753  return true;
754 }
755 
756 //-----</PhraseList>-------------------------
757 
758 //-----<DotAtom>-------------------------
759 
760 //@cond PRIVATE
761 kmime_mk_trivial_ctor_with_dptr(DotAtom, Structured)
762 //@endcond
763 
764 QByteArray DotAtom::as7BitString(bool withHeaderType) const
765 {
766  if (isEmpty()) {
767  return {};
768  }
769 
770  QByteArray rv;
771  if (withHeaderType) {
772  rv += typeIntro();
773  }
774 
775  rv += d_func()->dotAtom;
776  return rv;
777 }
778 
780 {
781  return QString::fromLatin1(d_func()->dotAtom);
782 }
783 
785 {
786  Q_D(DotAtom);
787  d->dotAtom.clear();
788 }
789 
790 bool DotAtom::isEmpty() const
791 {
792  return d_func()->dotAtom.isEmpty();
793 }
794 
795 bool DotAtom::parse(const char *&scursor, const char *const send,
796  bool isCRLF)
797 {
798  Q_D(DotAtom);
799  QByteArray maybeDotAtom;
800  if (!parseDotAtom(scursor, send, maybeDotAtom, isCRLF)) {
801  return false;
802  }
803 
804  d->dotAtom = maybeDotAtom;
805 
806  eatCFWS(scursor, send, isCRLF);
807  if (scursor != send) {
808  KMIME_WARN << "trailing garbage after dot-atom in header allowing "
809  "only a single dot-atom!"
810  << Qt::endl;
811  }
812  return true;
813 }
814 
815 //-----</DotAtom>-------------------------
816 
817 //-----<Parametrized>-------------------------
818 
819 //@cond PRIVATE
820 kmime_mk_trivial_ctor_with_dptr(Parametrized, Structured)
821 kmime_mk_dptr_ctor(Parametrized, Structured)
822 //@endcond
823 
824 QByteArray Parametrized::as7BitString(bool withHeaderType) const
825 {
826  const Q_D(Parametrized);
827  if (isEmpty()) {
828  return {};
829  }
830 
831  QByteArray rv;
832  if (withHeaderType) {
833  rv += typeIntro();
834  }
835 
836  bool first = true;
837  for (QMap<QString, QString>::ConstIterator it = d->parameterHash.constBegin();
838  it != d->parameterHash.constEnd(); ++it) {
839  if (!first) {
840  rv += "; ";
841  } else {
842  first = false;
843  }
844  if (isUsAscii(it.value())) {
845  rv += it.key().toLatin1() + '=';
846  QByteArray tmp = it.value().toLatin1();
847  addQuotes(tmp, true); // force quoting, eg. for whitespaces in parameter value
848  rv += tmp;
849  } else {
850  if (useOutlookAttachmentEncoding()) {
851  rv += it.key().toLatin1() + '=';
852  qCDebug(KMIME_LOG) << "doing:" << it.value() << QLatin1String(d->encCS);
853  rv += "\"" + encodeRFC2047String(it.value(), d->encCS) + "\"";
854  } else {
855  rv += it.key().toLatin1() + "*=";
856  rv += encodeRFC2231String(it.value(), d->encCS);
857  }
858  }
859  }
860 
861  return rv;
862 }
863 
865 {
866  return d_func()->parameterHash.value(key.toLower());
867 }
868 
869 bool Parametrized::hasParameter(const QString &key) const
870 {
871  return d_func()->parameterHash.contains(key.toLower());
872 }
873 
874 void Parametrized::setParameter(const QString &key, const QString &value)
875 {
876  Q_D(Parametrized);
877  d->parameterHash.insert(key.toLower(), value);
878 }
879 
881 {
882  return d_func()->parameterHash.isEmpty();
883 }
884 
886 {
887  Q_D(Parametrized);
888  d->parameterHash.clear();
889 }
890 
891 bool Parametrized::parse(const char *&scursor, const char *const send,
892  bool isCRLF)
893 {
894  Q_D(Parametrized);
895  d->parameterHash.clear();
896  QByteArray charset;
897  if (!parseParameterListWithCharset(scursor, send, d->parameterHash, charset, isCRLF)) {
898  return false;
899  }
900  d->encCS = charset;
901  return true;
902 }
903 
904 //-----</Parametrized>-------------------------
905 
906 //-----<Ident>-------------------------
907 
908 //@cond PRIVATE
909 kmime_mk_trivial_ctor_with_dptr(Ident, Address)
910 kmime_mk_dptr_ctor(Ident, Address)
911 //@endcond
912 
913 QByteArray Ident::as7BitString(bool withHeaderType) const
914 {
915  const Q_D(Ident);
916  if (d->msgIdList.isEmpty()) {
917  return {};
918  }
919 
920  QByteArray rv;
921  if (withHeaderType) {
922  rv = typeIntro();
923  }
924  for (const Types::AddrSpec &addr : std::as_const(d->msgIdList)) {
925  if (!addr.isEmpty()) {
926  const QString asString = addr.asString();
927  rv += '<';
928  if (!asString.isEmpty()) {
929  rv += asString.toLatin1(); // FIXME: change parsing to use QByteArrays
930  }
931  rv += "> ";
932  }
933  }
934  if (!rv.isEmpty()) {
935  rv.resize(rv.length() - 1);
936  }
937  return rv;
938 }
939 
941 {
942  Q_D(Ident);
943  d->msgIdList.clear();
944  d->cachedIdentifier.clear();
945 }
946 
947 bool Ident::isEmpty() const
948 {
949  return d_func()->msgIdList.isEmpty();
950 }
951 
952 bool Ident::parse(const char *&scursor, const char *const send, bool isCRLF)
953 {
954  Q_D(Ident);
955  // msg-id := "<" id-left "@" id-right ">"
956  // id-left := dot-atom-text / no-fold-quote / local-part
957  // id-right := dot-atom-text / no-fold-literal / domain
958  //
959  // equivalent to:
960  // msg-id := angle-addr
961 
962  d->msgIdList.clear();
963  d->cachedIdentifier.clear();
964 
965  while (scursor != send) {
966  eatCFWS(scursor, send, isCRLF);
967  // empty entry ending the list: OK.
968  if (scursor == send) {
969  return true;
970  }
971  // empty entry: ignore.
972  if (*scursor == ',') {
973  scursor++;
974  continue;
975  }
976 
977  AddrSpec maybeMsgId;
978  if (!parseAngleAddr(scursor, send, maybeMsgId, isCRLF)) {
979  return false;
980  }
981  d->msgIdList.append(maybeMsgId);
982 
983  eatCFWS(scursor, send, isCRLF);
984  // header end ending the list: OK.
985  if (scursor == send) {
986  return true;
987  }
988  // regular item separator: eat it.
989  if (*scursor == ',') {
990  scursor++;
991  }
992  }
993  return true;
994 }
995 
998  const auto msgIdList = d_func()->msgIdList;
999  for (const Types::AddrSpec &addr : msgIdList) {
1000  if (!addr.isEmpty()) {
1001  const QString asString = addr.asString();
1002  if (!asString.isEmpty()) {
1003  rv.append(asString.toLatin1()); // FIXME: change parsing to use QByteArrays
1004  }
1005  }
1006  }
1007  return rv;
1008 }
1009 
1010 void Ident::fromIdent(const Ident* ident)
1011 {
1012  d_func()->encCS = ident->d_func()->encCS;
1013  d_func()->msgIdList = ident->d_func()->msgIdList;
1014  d_func()->cachedIdentifier = ident->d_func()->cachedIdentifier;
1015 }
1016 
1018 {
1019  Q_D(Ident);
1020  QByteArray tmp = id;
1021  if (!tmp.startsWith('<')) {
1022  tmp.prepend('<');
1023  }
1024  if (!tmp.endsWith('>')) {
1025  tmp.append('>');
1026  }
1027  AddrSpec msgId;
1028  const char *cursor = tmp.constData();
1029  if (parseAngleAddr(cursor, cursor + tmp.length(), msgId)) {
1030  d->msgIdList.append(msgId);
1031  } else {
1032  qCWarning(KMIME_LOG) << "Unable to parse address spec!";
1033  }
1034 }
1035 
1036 //-----</Ident>-------------------------
1037 
1038 //-----<SingleIdent>-------------------------
1039 
1040 //@cond PRIVATE
1041 kmime_mk_trivial_ctor_with_dptr(SingleIdent, Ident)
1042 kmime_mk_dptr_ctor(SingleIdent, Ident)
1043 //@endcond
1044 
1045 QByteArray SingleIdent::identifier() const
1046 {
1047  if (d_func()->msgIdList.isEmpty()) {
1048  return {};
1049  }
1050 
1051  if (d_func()->cachedIdentifier.isEmpty()) {
1052  const Types::AddrSpec &addr = d_func()->msgIdList.first();
1053  if (!addr.isEmpty()) {
1054  const QString asString = addr.asString();
1055  if (!asString.isEmpty()) {
1056  d_func()->cachedIdentifier = asString.toLatin1();// FIXME: change parsing to use QByteArrays
1057  }
1058  }
1059  }
1060 
1061  return d_func()->cachedIdentifier;
1062 }
1063 
1065 {
1066  Q_D(SingleIdent);
1067  d->msgIdList.clear();
1068  d->cachedIdentifier.clear();
1069  appendIdentifier(id);
1070 }
1071 
1072 bool SingleIdent::parse(const char *&scursor, const char *const send,
1073  bool isCRLF)
1074 {
1075  Q_D(SingleIdent);
1076  if (!Ident::parse(scursor, send, isCRLF)) {
1077  return false;
1078  }
1079 
1080  if (d->msgIdList.count() > 1) {
1081  KMIME_WARN << "more than one msg-id in header "
1082  << "allowing only a single one!"
1083  << Qt::endl;
1084  }
1085  return true;
1086 }
1087 
1088 //-----</SingleIdent>-------------------------
1089 
1090 } // namespace Generics
1091 
1092 //-----<ReturnPath>-------------------------
1093 
1094 //@cond PRIVATE
1095 kmime_mk_trivial_ctor_with_name_and_dptr(ReturnPath, Generics::Address, Return-Path)
1096 //@endcond
1097 
1098 QByteArray ReturnPath::as7BitString(bool withHeaderType) const
1099 {
1100  if (isEmpty()) {
1101  return {};
1102  }
1103 
1104  QByteArray rv;
1105  if (withHeaderType) {
1106  rv += typeIntro();
1107  }
1108  rv += '<' + d_func()->mailbox.as7BitString(d_func()->encCS) + '>';
1109  return rv;
1110 }
1111 
1113 {
1114  Q_D(ReturnPath);
1115  d->mailbox.setAddress(Types::AddrSpec());
1116  d->mailbox.setName(QString());
1117 }
1118 
1120 {
1121  const Q_D(ReturnPath);
1122  return !d->mailbox.hasAddress() && !d->mailbox.hasName();
1123 }
1124 
1125 bool ReturnPath::parse(const char *&scursor, const char *const send,
1126  bool isCRLF)
1127 {
1128  Q_D(ReturnPath);
1129  eatCFWS(scursor, send, isCRLF);
1130  if (scursor == send) {
1131  return false;
1132  }
1133 
1134  const char *oldscursor = scursor;
1135 
1136  Mailbox maybeMailbox;
1137  if (!parseMailbox(scursor, send, maybeMailbox, isCRLF)) {
1138  // mailbox parsing failed, but check for empty brackets:
1139  scursor = oldscursor;
1140  if (*scursor != '<') {
1141  return false;
1142  }
1143  scursor++;
1144  eatCFWS(scursor, send, isCRLF);
1145  if (scursor == send || *scursor != '>') {
1146  return false;
1147  }
1148  scursor++;
1149 
1150  // prepare a Null mailbox:
1151  AddrSpec emptyAddrSpec;
1152  maybeMailbox.setName(QString());
1153  maybeMailbox.setAddress(emptyAddrSpec);
1154  } else {
1155  // check that there was no display-name:
1156  if (maybeMailbox.hasName()) {
1157  KMIME_WARN << "display-name \"" << maybeMailbox.name()
1158  << "\" in Return-Path!" << Qt::endl;
1159  }
1160  }
1161  d->mailbox = maybeMailbox;
1162 
1163  // see if that was all:
1164  eatCFWS(scursor, send, isCRLF);
1165  // and warn if it wasn't:
1166  if (scursor != send) {
1167  KMIME_WARN << "trailing garbage after angle-addr in Return-Path!"
1168  << Qt::endl;
1169  }
1170  return true;
1171 }
1172 
1173 //-----</ReturnPath>-------------------------
1174 
1175 //-----<Generic>-------------------------------
1176 
1177 // NOTE: Do *not* register Generic with HeaderFactory, since its type() is changeable.
1178 
1179 Generic::Generic() : Generics::Unstructured(new GenericPrivate)
1180 {
1181 }
1182 
1183 Generic::Generic(const char *t, int len) : Generics::Unstructured(new GenericPrivate)
1184 {
1185  setType(t, len);
1186 }
1187 
1188 Generic::~Generic()
1189 {
1190  Q_D(Generic);
1191  delete d;
1192  d_ptr = nullptr;
1193 }
1194 
1196 {
1197  Q_D(Generic);
1198  delete[] d->type;
1199  d->type = nullptr;
1200  Unstructured::clear();
1201 }
1202 
1203 bool Generic::isEmpty() const
1204 {
1205  return d_func()->type == nullptr || Unstructured::isEmpty();
1206 }
1207 
1208 const char *Generic::type() const
1209 {
1210  return d_func()->type;
1211 }
1212 
1213 void Generic::setType(const char *type, int len)
1214 {
1215  Q_D(Generic);
1216  if (d->type) {
1217  delete[] d->type;
1218  }
1219  if (type) {
1220  const int l = (len < 0 ? strlen(type) : len) + 1;
1221  d->type = new char[l];
1222  qstrncpy(d->type, type, l);
1223  } else {
1224  d->type = nullptr;
1225  }
1226 }
1227 
1228 //-----<Generic>-------------------------------
1229 
1230 //-----<MessageID>-----------------------------
1231 
1232 //@cond PRIVATE
1233 kmime_mk_trivial_ctor_with_name(MessageID, Generics::SingleIdent, Message-ID)
1234 //@endcond
1235 
1236 void MessageID::generate(const QByteArray &fqdn)
1237 {
1238  setIdentifier('<' + uniqueString() + '@' + fqdn + '>');
1239 }
1240 
1241 //-----</MessageID>----------------------------
1242 
1243 //-----<Control>-------------------------------
1244 
1245 //@cond PRIVATE
1246 kmime_mk_trivial_ctor_with_name_and_dptr(Control, Generics::Structured, Control)
1247 //@endcond
1248 
1249 QByteArray Control::as7BitString(bool withHeaderType) const
1250 {
1251  const Q_D(Control);
1252  if (isEmpty()) {
1253  return {};
1254  }
1255 
1256  QByteArray rv;
1257  if (withHeaderType) {
1258  rv += typeIntro();
1259  }
1260 
1261  rv += d->name;
1262  if (!d->parameter.isEmpty()) {
1263  rv += ' ' + d->parameter;
1264  }
1265  return rv;
1266 }
1267 
1269 {
1270  Q_D(Control);
1271  d->name.clear();
1272  d->parameter.clear();
1273 }
1274 
1275 bool Control::isEmpty() const
1276 {
1277  return d_func()->name.isEmpty();
1278 }
1279 
1281 {
1282  return d_func()->name;
1283 }
1284 
1286 {
1287  return d_func()->parameter;
1288 }
1289 
1290 bool Control::isCancel() const
1291 {
1292  return d_func()->name.toLower() == "cancel";
1293 }
1294 
1295 void Control::setCancel(const QByteArray &msgid)
1296 {
1297  Q_D(Control);
1298  d->name = "cancel";
1299  d->parameter = msgid;
1300 }
1301 
1302 bool Control::parse(const char *&scursor, const char *const send, bool isCRLF)
1303 {
1304  Q_D(Control);
1305  clear();
1306  eatCFWS(scursor, send, isCRLF);
1307  if (scursor == send) {
1308  return false;
1309  }
1310  const char *start = scursor;
1311  while (scursor != send && !isspace(*scursor)) {
1312  ++scursor;
1313  }
1314  d->name = QByteArray(start, scursor - start);
1315  eatCFWS(scursor, send, isCRLF);
1316  d->parameter = QByteArray(scursor, send - scursor);
1317  return true;
1318 }
1319 
1320 //-----</Control>------------------------------
1321 
1322 //-----<MailCopiesTo>--------------------------
1323 
1324 //@cond PRIVATE
1325 kmime_mk_trivial_ctor_with_name_and_dptr(MailCopiesTo,
1326  Generics::AddressList, Mail-Copies-To)
1327 //@endcond
1328 
1329 QByteArray MailCopiesTo::as7BitString(bool withHeaderType) const
1330 {
1331  QByteArray rv;
1332  if (withHeaderType) {
1333  rv += typeIntro();
1334  }
1335  if (!AddressList::isEmpty()) {
1336  rv += AddressList::as7BitString(false);
1337  } else {
1338  if (d_func()->alwaysCopy) {
1339  rv += "poster";
1340  } else if (d_func()->neverCopy) {
1341  rv += "nobody";
1342  }
1343  }
1344  return rv;
1345 }
1346 
1348 {
1349  if (!AddressList::isEmpty()) {
1350  return AddressList::asUnicodeString();
1351  }
1352  if (d_func()->alwaysCopy) {
1353  return QStringLiteral("poster");
1354  }
1355  if (d_func()->neverCopy) {
1356  return QStringLiteral("nobody");
1357  }
1358  return {};
1359 }
1360 
1362 {
1363  Q_D(MailCopiesTo);
1364  AddressList::clear();
1365  d->alwaysCopy = false;
1366  d->neverCopy = false;
1367 }
1368 
1370 {
1371  return AddressList::isEmpty() && !(d_func()->alwaysCopy || d_func()->neverCopy);
1372 }
1373 
1375 {
1376  return !AddressList::isEmpty() || d_func()->alwaysCopy;
1377 }
1378 
1380 {
1381  Q_D(MailCopiesTo);
1382  clear();
1383  d->alwaysCopy = true;
1384 }
1385 
1387 {
1388  return d_func()->neverCopy;
1389 }
1390 
1392 {
1393  Q_D(MailCopiesTo);
1394  clear();
1395  d->neverCopy = true;
1396 }
1397 
1398 bool MailCopiesTo::parse(const char *&scursor, const char *const send,
1399  bool isCRLF)
1400 {
1401  Q_D(MailCopiesTo);
1402  clear();
1403  if (send - scursor == 5) {
1404  if (qstrnicmp("never", scursor, 5) == 0) {
1405  d->neverCopy = true;
1406  return true;
1407  }
1408  }
1409  if (send - scursor == 6) {
1410  if (qstrnicmp("always", scursor, 6) == 0 || qstrnicmp("poster", scursor, 6) == 0) {
1411  d->alwaysCopy = true;
1412  return true;
1413  }
1414  if (qstrnicmp("nobody", scursor, 6) == 0) {
1415  d->neverCopy = true;
1416  return true;
1417  }
1418  }
1419  return AddressList::parse(scursor, send, isCRLF);
1420 }
1421 
1422 //-----</MailCopiesTo>-------------------------
1423 
1424 //-----<Date>----------------------------------
1425 
1426 //@cond PRIVATE
1427 kmime_mk_trivial_ctor_with_name_and_dptr(Date, Generics::Structured, Date)
1428 //@endcond
1429 
1430 QByteArray Date::as7BitString(bool withHeaderType) const
1431 {
1432  if (isEmpty()) {
1433  return {};
1434  }
1435 
1436  QByteArray rv;
1437  if (withHeaderType) {
1438  rv += typeIntro();
1439  }
1440  //QT5 fix port to QDateTime Qt::RFC2822Date is not enough we need to fix it. We need to use QLocale("C") + add "ddd, ";
1441  //rv += d_func()->dateTime.toString( Qt::RFC2822Date ).toLatin1();
1442  rv += QLocale::c().toString(d_func()->dateTime, QStringLiteral("ddd, ")).toLatin1();
1443  rv += d_func()->dateTime.toString(Qt::RFC2822Date).toLatin1();
1444 
1445  return rv;
1446 }
1447 
1448 void Date::clear() {
1449  Q_D(Date);
1450  d->dateTime = QDateTime();
1451 }
1452 
1453 bool Date::isEmpty() const {
1454  return d_func()->dateTime.isNull() || !d_func()->dateTime.isValid();
1455 }
1456 
1458  return d_func()->dateTime;
1459 }
1460 
1461 void Date::setDateTime(const QDateTime & dt) {
1462  Q_D(Date);
1463  d->dateTime = dt;
1464 }
1465 
1466 int Date::ageInDays() const {
1467  QDate today = QDate::currentDate();
1468  return dateTime().date().daysTo(today);
1469 }
1470 
1471 bool Date::parse(const char *&scursor, const char *const send, bool isCRLF) {
1472  Q_D(Date);
1473  return parseDateTime(scursor, send, d->dateTime, isCRLF);
1474 }
1475 
1476 //-----</Date>---------------------------------
1477 
1478 //-----<Newsgroups>----------------------------
1479 
1480 //@cond PRIVATE
1481 kmime_mk_trivial_ctor_with_name_and_dptr(Newsgroups, Generics::Structured, Newsgroups)
1482 kmime_mk_trivial_ctor_with_name(FollowUpTo, Newsgroups, Followup-To)
1483 //@endcond
1484 
1485 QByteArray Newsgroups::as7BitString(bool withHeaderType) const {
1486  const Q_D(Newsgroups);
1487  if (isEmpty()) {
1488  return {};
1489  }
1490 
1491  QByteArray rv;
1492  if (withHeaderType) {
1493  rv += typeIntro();
1494  }
1495 
1496  for (int i = 0; i < d->groups.count(); ++i) {
1497  rv += d->groups[ i ];
1498  if (i != d->groups.count() - 1) {
1499  rv += ',';
1500  }
1501  }
1502  return rv;
1503 }
1504 
1506  Q_UNUSED(b)
1507  Q_D(Newsgroups);
1508  from7BitString(s.toUtf8());
1509  d->encCS = cachedCharset("UTF-8");
1510 }
1511 
1513  return QString::fromUtf8(as7BitString(false));
1514 }
1515 
1517  Q_D(Newsgroups);
1518  d->groups.clear();
1519 }
1520 
1521 bool Newsgroups::isEmpty() const {
1522  return d_func()->groups.isEmpty();
1523 }
1524 
1525 QList<QByteArray> Newsgroups::groups() const { return d_func()->groups; }
1526 
1528  Q_D(Newsgroups);
1529  d->groups = groups;
1530 }
1531 
1533  return d_func()->groups.count() >= 2;
1534 }
1535 
1536 bool Newsgroups::parse(const char *&scursor, const char *const send, bool isCRLF) {
1537  Q_D(Newsgroups);
1538  clear();
1539  while (true) {
1540  eatCFWS(scursor, send, isCRLF);
1541  if (scursor != send && *scursor == ',') {
1542  ++scursor;
1543  }
1544  eatCFWS(scursor, send, isCRLF);
1545  if (scursor == send) {
1546  return true;
1547  }
1548  const char *start = scursor;
1549  while (scursor != send && !isspace(*scursor) && *scursor != ',') {
1550  ++scursor;
1551  }
1552  QByteArray group(start, scursor - start);
1553  d->groups.append(group);
1554  }
1555  return true;
1556 }
1557 
1558 //-----</Newsgroups>---------------------------
1559 
1560 //-----<Lines>---------------------------------
1561 
1562 //@cond PRIVATE
1563 kmime_mk_trivial_ctor_with_name_and_dptr(Lines, Generics::Structured, Lines)
1564 //@endcond
1565 
1566 QByteArray Lines::as7BitString(bool withHeaderType) const {
1567  if (isEmpty()) {
1568  return {};
1569  }
1570 
1571  QByteArray num;
1572  num.setNum(d_func()->lines);
1573 
1574  if (withHeaderType) {
1575  return typeIntro() + num;
1576  }
1577  return num;
1578 }
1579 
1581  if (isEmpty()) {
1582  return {};
1583  }
1584  return QString::number(d_func()->lines);
1585 }
1586 
1588  Q_D(Lines);
1589  d->lines = -1;
1590 }
1591 
1592 bool Lines::isEmpty() const {
1593  return d_func()->lines == -1;
1594 }
1595 
1597  return d_func()->lines;
1598 }
1599 
1600 void Lines::setNumberOfLines(int lines) {
1601  Q_D(Lines);
1602  d->lines = lines;
1603 }
1604 
1605 bool Lines::parse(const char *&scursor, const char *const send, bool isCRLF) {
1606  Q_D(Lines);
1607  eatCFWS(scursor, send, isCRLF);
1608  if (parseDigits(scursor, send, d->lines) == 0) {
1609  clear();
1610  return false;
1611  }
1612  return true;
1613 }
1614 
1615 //-----</Lines>--------------------------------
1616 
1617 //-----<Content-Type>--------------------------
1618 
1619 //@cond PRIVATE
1620 kmime_mk_trivial_ctor_with_name_and_dptr(ContentType, Generics::Parametrized,
1621  Content-Type)
1622 //@endcond
1623 
1624 bool ContentType::isEmpty() const {
1625  return d_func()->mimeType.isEmpty();
1626 }
1627 
1629  Q_D(ContentType);
1630  d->category = CCsingle;
1631  d->mimeType.clear();
1632  Parametrized::clear();
1633 }
1634 
1635 QByteArray ContentType::as7BitString(bool withHeaderType) const {
1636  if (isEmpty()) {
1637  return {};
1638  }
1639 
1640  QByteArray rv;
1641  if (withHeaderType) {
1642  rv += typeIntro();
1643  }
1644 
1645  rv += mimeType();
1646  if (!Parametrized::isEmpty()) {
1647  rv += "; " + Parametrized::as7BitString(false);
1648  }
1649 
1650  return rv;
1651 }
1652 
1654  Q_D(const ContentType);
1655  return d->mimeType;
1656 }
1657 
1659  Q_D(const ContentType);
1660  const int pos = d->mimeType.indexOf('/');
1661  if (pos < 0) {
1662  return d->mimeType;
1663  } else {
1664  return d->mimeType.left(pos);
1665  }
1666 }
1667 
1669  Q_D(const ContentType);
1670  const int pos = d->mimeType.indexOf('/');
1671  if (pos < 0) {
1672  return {};
1673  } else {
1674  return d->mimeType.mid(pos + 1);
1675  }
1676 }
1677 
1678 void ContentType::setMimeType(const QByteArray & mimeType) {
1679  Q_D(ContentType);
1680  d->mimeType = mimeType;
1681 
1682  if (isMultipart()) {
1683  d->category = CCcontainer;
1684  } else {
1685  d->category = CCsingle;
1686  }
1687 }
1688 
1689 bool ContentType::isMediatype(const char *mediatype) const {
1690  Q_D(const ContentType);
1691  const int len = strlen(mediatype);
1692  return qstrnicmp(d->mimeType.constData(), mediatype, len) == 0 &&
1693  (d->mimeType.at(len) == '/' || d->mimeType.size() == len);
1694 }
1695 
1696 bool ContentType::isSubtype(const char *subtype) const {
1697  Q_D(const ContentType);
1698  const int pos = d->mimeType.indexOf('/');
1699  if (pos < 0) {
1700  return false;
1701  }
1702  const int len = strlen(subtype);
1703  return qstrnicmp(d->mimeType.constData() + pos + 1, subtype, len) == 0 &&
1704  d->mimeType.size() == pos + len + 1;
1705 }
1706 
1707 bool ContentType::isMimeType(const char* mimeType) const
1708 {
1709  Q_D(const ContentType);
1710  return qstricmp(d->mimeType.constData(), mimeType) == 0;
1711 }
1712 
1713 bool ContentType::isText() const {
1714  return (isMediatype("text") || isEmpty());
1715 }
1716 
1718  return (qstricmp(d_func()->mimeType.constData(), "text/plain") == 0 || isEmpty());
1719 }
1720 
1722  return qstricmp(d_func()->mimeType.constData(), "text/html") == 0;
1723 }
1724 
1725 bool ContentType::isImage() const {
1726  return isMediatype("image");
1727 }
1728 
1730  return isMediatype("multipart");
1731 }
1732 
1734  return qstricmp(d_func()->mimeType.constData(), "message/partial") == 0;
1735 }
1736 
1738  QByteArray ret = parameter(QStringLiteral("charset")).toLatin1();
1739  if (ret.isEmpty()) {
1740  //return the default-charset if necessary
1741  ret = Content::defaultCharset();
1742  }
1743  return ret;
1744 }
1745 
1747  setParameter(QStringLiteral("charset"), QString::fromLatin1(s));
1748 }
1749 
1751  return parameter(QStringLiteral("boundary")).toLatin1();
1752 }
1753 
1755  setParameter(QStringLiteral("boundary"), QString::fromLatin1(s));
1756 }
1757 
1759  return parameter(QStringLiteral("name"));
1760 }
1761 
1762 void ContentType::setName(const QString & s, const QByteArray & cs) {
1763  Q_D(ContentType);
1764  d->encCS = cs;
1765  setParameter(QStringLiteral("name"), s);
1766 }
1767 
1769  return parameter(QStringLiteral("id")).toLatin1();
1770 }
1771 
1773  setParameter(QStringLiteral("id"), QString::fromLatin1(s));
1774 }
1775 
1777  QByteArray p = parameter(QStringLiteral("number")).toLatin1();
1778  if (!p.isEmpty()) {
1779  return p.toInt();
1780  } else {
1781  return -1;
1782  }
1783 }
1784 
1786  QByteArray p = parameter(QStringLiteral("total")).toLatin1();
1787  if (!p.isEmpty()) {
1788  return p.toInt();
1789  } else {
1790  return -1;
1791  }
1792 }
1793 
1794 contentCategory ContentType::category() const {
1795  return d_func()->category;
1796 }
1797 
1798 void ContentType::setCategory(contentCategory c) {
1799  Q_D(ContentType);
1800  d->category = c;
1801 }
1802 
1803 void ContentType::setPartialParams(int total, int number) {
1804  setParameter(QStringLiteral("number"), QString::number(number));
1805  setParameter(QStringLiteral("total"), QString::number(total));
1806 }
1807 
1808 bool ContentType::parse(const char *&scursor, const char *const send,
1809  bool isCRLF) {
1810  Q_D(ContentType);
1811  // content-type: type "/" subtype *(";" parameter)
1812  clear();
1813  eatCFWS(scursor, send, isCRLF);
1814  if (scursor == send) {
1815  return false; // empty header
1816  }
1817 
1818  // type
1819  QPair<const char *, int> maybeMimeType;
1820  if (!parseToken(scursor, send, maybeMimeType, ParseTokenNoFlag)) {
1821  return false;
1822  }
1823  // subtype
1824  eatCFWS(scursor, send, isCRLF);
1825  if (scursor == send || *scursor != '/') {
1826  return false;
1827  }
1828  scursor++;
1829  eatCFWS(scursor, send, isCRLF);
1830  if (scursor == send) {
1831  return false;
1832  }
1833  QPair<const char *, int> maybeSubType;
1834  if (!parseToken(scursor, send, maybeSubType, ParseTokenNoFlag)) {
1835  return false;
1836  }
1837 
1838  d->mimeType.reserve(maybeMimeType.second + maybeSubType.second + 1);
1839  d->mimeType = QByteArray(maybeMimeType.first, maybeMimeType.second).toLower()
1840  + '/' + QByteArray(maybeSubType.first, maybeSubType.second).toLower();
1841 
1842  // parameter list
1843  eatCFWS(scursor, send, isCRLF);
1844  if (scursor == send) {
1845  goto success; // no parameters
1846  }
1847  if (*scursor != ';') {
1848  return false;
1849  }
1850  scursor++;
1851 
1852  if (!Parametrized::parse(scursor, send, isCRLF)) {
1853  return false;
1854  }
1855 
1856  // adjust category
1857 success:
1858  if (isMultipart()) {
1859  d->category = CCcontainer;
1860  } else {
1861  d->category = CCsingle;
1862  }
1863  return true;
1864 }
1865 
1866 //-----</Content-Type>-------------------------
1867 
1868 //-----<ContentID>----------------------
1869 
1870 kmime_mk_trivial_ctor_with_name_and_dptr(ContentID, SingleIdent, Content-ID)
1871 kmime_mk_dptr_ctor(ContentID, SingleIdent)
1872 
1873 bool ContentID::parse(const char *&scursor, const char *const send, bool isCRLF) {
1874  Q_D(ContentID);
1875  // Content-id := "<" contentid ">"
1876  // contentid := now whitespaces
1877 
1878  const char *origscursor = scursor;
1879  if (!SingleIdent::parse(scursor, send, isCRLF)) {
1880  scursor = origscursor;
1881  d->msgIdList.clear();
1882  d->cachedIdentifier.clear();
1883 
1884  while (scursor != send) {
1885  eatCFWS(scursor, send, isCRLF);
1886  // empty entry ending the list: OK.
1887  if (scursor == send) {
1888  return true;
1889  }
1890  // empty entry: ignore.
1891  if (*scursor == ',') {
1892  scursor++;
1893  continue;
1894  }
1895 
1896  AddrSpec maybeContentId;
1897  // Almost parseAngleAddr
1898  if (scursor == send || *scursor != '<') {
1899  return false;
1900  }
1901  scursor++; // eat '<'
1902 
1903  eatCFWS(scursor, send, isCRLF);
1904  if (scursor == send) {
1905  return false;
1906  }
1907 
1908  // Save chars until '>''
1909  QByteArray result;
1910  if (!parseDotAtom(scursor, send, result, false)) {
1911  return false;
1912  }
1913 
1914  eatCFWS(scursor, send, isCRLF);
1915  if (scursor == send || *scursor != '>') {
1916  return false;
1917  }
1918  scursor++;
1919  // /Almost parseAngleAddr
1920 
1921  maybeContentId.localPart = QString::fromLatin1(result); // FIXME: just use QByteArray instead of AddrSpec in msgIdList?
1922  d->msgIdList.append(maybeContentId);
1923 
1924  eatCFWS(scursor, send, isCRLF);
1925  // header end ending the list: OK.
1926  if (scursor == send) {
1927  return true;
1928  }
1929  // regular item separator: eat it.
1930  if (*scursor == ',') {
1931  scursor++;
1932  }
1933  }
1934  return true;
1935  } else {
1936  return true;
1937  }
1938 }
1939 
1940 //-----</ContentID>----------------------
1941 
1942 //-----<ContentTransferEncoding>----------------------------
1943 
1944 //@cond PRIVATE
1945 kmime_mk_trivial_ctor_with_name_and_dptr(ContentTransferEncoding,
1946  Generics::Token, Content-Transfer-Encoding)
1947 //@endcond
1948 
1949 typedef struct {
1950  const char *s;
1951  int e;
1952 } encTableType;
1953 
1954 static const encTableType encTable[] = {
1955  { "7Bit", CE7Bit },
1956  { "8Bit", CE8Bit },
1957  { "quoted-printable", CEquPr },
1958  { "base64", CEbase64 },
1959  { "x-uuencode", CEuuenc },
1960  { "binary", CEbinary },
1961  { nullptr, 0}
1962 };
1963 
1966  d->decoded = true;
1967  d->cte = CE7Bit;
1968  Token::clear();
1969 }
1970 
1972  return d_func()->cte;
1973 }
1974 
1977  d->cte = e;
1978 
1979  for (int i = 0; encTable[i].s != nullptr; ++i) {
1980  if (d->cte == encTable[i].e) {
1981  setToken(encTable[i].s);
1982  break;
1983  }
1984  }
1985 }
1986 
1988  return d_func()->decoded;
1989 }
1990 
1993  d->decoded = decoded;
1994 }
1995 
1998  return d->decoded && (d->cte == CEquPr || d->cte == CEbase64);
1999 }
2000 
2001 bool ContentTransferEncoding::parse(const char *&scursor,
2002  const char *const send, bool isCRLF) {
2004  clear();
2005  if (!Token::parse(scursor, send, isCRLF)) {
2006  return false;
2007  }
2008 
2009  // TODO: error handling in case of an unknown encoding?
2010  for (int i = 0; encTable[i].s != nullptr; ++i) {
2011  if (qstricmp(token().constData(), encTable[i].s) == 0) {
2012  d->cte = (contentEncoding)encTable[i].e;
2013  break;
2014  }
2015  }
2016  d->decoded = (d->cte == CE7Bit || d->cte == CE8Bit);
2017  return true;
2018 }
2019 
2020 //-----</ContentTransferEncoding>---------------------------
2021 
2022 //-----<ContentDisposition>--------------------------
2023 
2024 //@cond PRIVATE
2025 kmime_mk_trivial_ctor_with_name_and_dptr(ContentDisposition,
2026  Generics::Parametrized, Content-Disposition)
2027 //@endcond
2028 
2029 QByteArray ContentDisposition::as7BitString(bool withHeaderType) const {
2030  if (isEmpty()) {
2031  return {};
2032  }
2033 
2034  QByteArray rv;
2035  if (withHeaderType) {
2036  rv += typeIntro();
2037  }
2038 
2039  if (d_func()->disposition == CDattachment) {
2040  rv += "attachment";
2041  } else if (d_func()->disposition == CDinline) {
2042  rv += "inline";
2043  } else {
2044  return {};
2045  }
2046 
2047  if (!Parametrized::isEmpty()) {
2048  rv += "; " + Parametrized::as7BitString(false);
2049  }
2050 
2051  return rv;
2052 }
2053 
2055  return d_func()->disposition == CDInvalid;
2056 }
2057 
2060  d->disposition = CDInvalid;
2061  Parametrized::clear();
2062 }
2063 
2065  return d_func()->disposition;
2066 }
2067 
2070  d->disposition = disp;
2071 }
2072 
2074  return parameter(QStringLiteral("filename"));
2075 }
2076 
2078  setParameter(QStringLiteral("filename"), filename);
2079 }
2080 
2081 bool ContentDisposition::parse(const char *&scursor, const char *const send,
2082  bool isCRLF) {
2084  clear();
2085 
2086  // token
2087  QByteArray token;
2088  eatCFWS(scursor, send, isCRLF);
2089  if (scursor == send) {
2090  return false;
2091  }
2092 
2093  QPair<const char *, int> maybeToken;
2094  if (!parseToken(scursor, send, maybeToken, ParseTokenNoFlag)) {
2095  return false;
2096  }
2097 
2098  token = QByteArray(maybeToken.first, maybeToken.second).toLower();
2099  if (token == "inline") {
2100  d->disposition = CDinline;
2101  } else if (token == "attachment") {
2102  d->disposition = CDattachment;
2103  } else {
2104  return false;
2105  }
2106 
2107  // parameter list
2108  eatCFWS(scursor, send, isCRLF);
2109  if (scursor == send) {
2110  return true; // no parameters
2111  }
2112 
2113  if (*scursor != ';') {
2114  return false;
2115  }
2116  scursor++;
2117 
2118  return Parametrized::parse(scursor, send, isCRLF);
2119 }
2120 
2121 //-----</ContentDisposition>-------------------------
2122 
2123 //@cond PRIVATE
2124 kmime_mk_trivial_ctor_with_name(Subject, Generics::Unstructured, Subject)
2125 //@endcond
2126 
2127 Base *createHeader(const QByteArray & type) {
2128  return HeaderFactory::createHeader(type);
2129 }
2130 
2131 //@cond PRIVATE
2132 kmime_mk_trivial_ctor_with_name(ContentDescription,
2133  Generics::Unstructured, Content-Description)
2134 kmime_mk_trivial_ctor_with_name(ContentLocation,
2135  Generics::Unstructured, Content-Location)
2136 kmime_mk_trivial_ctor_with_name(From, Generics::MailboxList, From)
2137 kmime_mk_trivial_ctor_with_name(Sender, Generics::SingleMailbox, Sender)
2138 kmime_mk_trivial_ctor_with_name(To, Generics::AddressList, To)
2139 kmime_mk_trivial_ctor_with_name(Cc, Generics::AddressList, Cc)
2140 kmime_mk_trivial_ctor_with_name(Bcc, Generics::AddressList, Bcc)
2141 kmime_mk_trivial_ctor_with_name(ReplyTo, Generics::AddressList, Reply-To)
2142 kmime_mk_trivial_ctor_with_name(Keywords, Generics::PhraseList, Keywords)
2143 kmime_mk_trivial_ctor_with_name(MIMEVersion, Generics::DotAtom, MIME-Version)
2144 kmime_mk_trivial_ctor_with_name(Supersedes, Generics::SingleIdent, Supersedes)
2145 kmime_mk_trivial_ctor_with_name(InReplyTo, Generics::Ident, In-Reply-To)
2146 kmime_mk_trivial_ctor_with_name(References, Generics::Ident, References)
2147 kmime_mk_trivial_ctor_with_name(Organization, Generics::Unstructured, Organization)
2148 kmime_mk_trivial_ctor_with_name(UserAgent, Generics::Unstructured, User-Agent)
2149 //@endcond
2150 
2151 } // namespace Headers
2152 
2153 } // namespace KMime
Represents a "Newsgroups" header.
void append(const T &value)
Represents a "User-Agent" header.
QMap::const_iterator constBegin() const const
bool isEmpty() const override
Checks if this header contains any data.
bool isImage() const
Returns true if the associated MIME entity is an image.
int partialNumber() const
Returns the position of this part in a multi-part set.
bool isPlainText() const
Returns true if the associated MIME entity is a plain text.
QByteArray parameter() const
Returns the control message parameter.
Represents an (email address, display name) pair according RFC 2822, section 3.4.
Definition: kmime_types.h:37
int numberOfLines() const
Returns the number of lines, undefined if isEmpty() returns true.
A class that encapsulates MIME encoded Content.
Definition: kmime_content.h:97
virtual bool parse(const char *&scursor, const char *const send, bool isCRLF=false)=0
This method parses the raw header and needs to be implemented in every sub-class.
QByteArray toLower() const const
void fromIdent(const Ident *ident)
Initialize this identifier Copy the data from.
QString filename() const
Returns the suggested filename for the associated MIME part.
void clear() override
Deletes.
bool isEmpty() const override
Checks if this header contains any data.
QTextStream & endl(QTextStream &stream)
QString number(int n, int base)
QString fromUtf8(const char *str, int size)
bool parse(const char *&scursor, const char *const send, bool isCRLF=false) override
This method parses the raw header and needs to be implemented in every sub-class.
Base class for headers that deal with (possibly multiple) addresses, allowing groups.
Represents a "Content-Transfer-Encoding" header.
QByteArray mimeType() const
Returns the mimetype.
QString asUnicodeString() const override
Returns the decoded content of the header without the header-type.
bool isEmpty() const override
Checks if this header contains any data.
QByteArray fromRawData(const char *data, int size)
void appendIdentifier(const QByteArray &id)
Appends a new identifier to this header.
void clear() override
Deletes.
@ CEquPr
quoted-printable
Definition: kmime_headers.h:62
bool parse(const char *&scursor, const char *const send, bool isCRLF=false) override
This method parses the raw header and needs to be implemented in every sub-class.
QByteArray & append(char ch)
bool parse(const char *&scursor, const char *const send, bool isCRLF=false) override
This method parses the raw header and needs to be implemented in every sub-class.
QList< QByteArray > addresses() const
Returns a list of all addresses in this header, regardless of groups.
int count(const T &value) const const
QByteArray as7BitString(bool withHeaderType=true) const override
Returns the encoded header.
void from7BitString(const char *s, size_t len) override
Parses the given string.
@ CEbinary
binary
Definition: kmime_headers.h:65
QByteArray rfc2047Charset() const
Returns the charset that is used for RFC2047-encoding.
bool parse(const char *&scursor, const char *const send, bool isCRLF=false) override
This method parses the raw header and needs to be implemented in every sub-class.
QList< QByteArray > groups() const
Returns the list of newsgroups.
Base class for headers containing a dot atom.
bool isEmpty() const override
Checks if this header contains any data.
contentEncoding
Various possible values for the "Content-Transfer-Encoding" header.
Definition: kmime_headers.h:59
QByteArray & setNum(short n, int base)
Represent a "From" header.
@ CDinline
inline
Definition: kmime_headers.h:73
void setRFC2047Charset(const QByteArray &cs)
Sets the charset for RFC2047-encoding.
Types::Mailbox::List mailboxes() const
Returns a list of mailboxes listed in this header.
bool neverCopy() const
Returns true if a mail copy was explicitly denied.
Baseclass of all header-classes.
bool isEmpty() const override
Checks if this header contains any data.
bool is(const char *t) const
Checks if this header is of type t.
QString displayString() const
Returns a single string for user-facing display of this address list.
Base class for all address related headers.
void setCharset(const QByteArray &s)
Sets the charset.
QByteArray toLatin1() const const
Represents a "Sender" header.
void setMimeType(const QByteArray &mimeType)
Sets the mimetype.
void fromUnicodeString(const QString &s, const QByteArray &b) override
Parses the given string and set the charset.
void clear() override
Deletes.
bool parse(const char *&scursor, const char *const send, bool isCRLF=false) override
This method parses the raw header and needs to be implemented in every sub-class.
Represents a "Message-ID" header.
void setId(const QByteArray &s)
Sets the identifier.
bool hasParameter(const QString &key) const
Represents a "References" header.
Base class for headers that deal with (possibly multiple) addresses, but don't allow groups.
const KIMAP2_EXPORT QByteArray encodeRFC2047String(const QByteArray &str)
Represents a "Content-ID" header.
@ CEbase64
base64
Definition: kmime_headers.h:63
QByteArray boundary() const
Returns the boundary (for multipart containers).
QByteArray & prepend(char ch)
Represents a "Keywords" header.
Represents an arbitrary header, that can contain any header-field.
QByteArray mediaType() const
Returns the media type (first part of the mimetype).
void setGroups(const QList< QByteArray > &groups)
Sets the newsgroup list.
QString name() const
Returns the name of the associated MIME entity.
QString parameter(const QString &key) const
Returns the value of the specified parameter.
QByteArray address() const
Returns a string representation of the email address, without the angle brackets.
Definition: kmime_types.cpp:93
bool isMimeType(const char *mimeType) const
Tests if the mime type is mimeType.
QDateTime dateTime() const
Returns the date contained in this header.
Represents a "Control" header.
bool isSubtype(const char *subtype) const
Tests if the mime sub-type equals subtype.
void clear() override
Deletes.
Represents a "Organization" header.
Base class for headers containing a parameter list such as "Content-Type".
void addAddress(const Types::Mailbox &mbox)
Adds an address to this header.
QList< QByteArray > addresses() const
Returns a list of all addresses in this header, regardless of groups.
void reserve(int alloc)
Represents a "Bcc" header.
@ CDattachment
attachment
Definition: kmime_headers.h:74
int size() const const
Represents a "Followup-To" header.
void addAddress(const Types::Mailbox &mbox)
Adds an address to this header.
Base class for headers which deal with a list of msg-id's.
Q_SCRIPTABLE Q_NOREPLY void start()
bool parse(const char *&scursor, const char *const send, bool isCRLF=false) override
This method parses the raw header and needs to be implemented in every sub-class.
void fromUnicodeString(const QString &s, const QByteArray &b) override
Parses the given string and set the charset.
KCODECS_EXPORT QString decodeRFC2047String(const QByteArray &src, QByteArray *usedCS, const QByteArray &defaultCS=QByteArray(), CharsetOption option=NoOption)
Represents a "Cc" header.
QByteArray typeIntro() const
Helper method, returns the header prefix including ":".
void fromUnicodeString(const QString &s, const QByteArray &b) override
Parses the given string and set the charset.
void clear() override
Deletes.
void setToken(const QByteArray &t)
Sets the token to t,.
QString asUnicodeString() const override
Returns the decoded content of the header without the header-type.
bool hasName() const
Returns true if this mailbox has a display name.
Represents a "To" header.
QByteArray controlType() const
Returns the control message type.
QLocale c()
Types::Mailbox::List mailboxes() const
Returns a list of mailboxes listed in this header.
bool isMediatype(const char *mediatype) const
Tests if the media type equals mediatype.
void setAlwaysCopy()
Sets the header to "poster".
contentDisposition disposition() const
Returns the content disposition.
void setName(const QString &name)
Sets the name.
bool isEmpty() const override
Checks if this header contains any data.
bool isEmpty() const const
void clear() override
Deletes.
bool parse(const char *&scursor, const char *const send, bool isCRLF=false) override
This method parses the raw header and needs to be implemented in every sub-class.
const char * type() const override
Returns the type of this header (e.g.
QByteArray toUtf8() const const
Represents a "MIME-Version" header.
void setName(const QString &s, const QByteArray &cs)
Sets the name to s using charset cs.
Represents a "Content-Description" header.
Defines the Content class.
bool isEmpty() const override
Checks if this header contains any data.
void setDateTime(const QDateTime &dt)
Sets the date.
QString toString(qlonglong i) const const
bool alwaysCopy() const
Returns true if a mail copy was explicitly requested.
QStringList displayNames() const
Returns a list of all display names associated with the addresses in this header.
virtual void from7BitString(const char *s, size_t len)
Parses the given string.
Represents a "Content-Type" header.
bool parse(const char *&scursor, const char *const send, bool isCRLF=false) override
This method parses the raw header and needs to be implemented in every sub-class.
bool startsWith(const QByteArray &ba) const const
@ CEuuenc
uuencode
Definition: kmime_headers.h:64
void fromUnicodeString(const QString &s, const QByteArray &b) override
Parses the given string and set the charset.
void setEncoding(contentEncoding e)
Sets the encoding to e.
QString asUnicodeString() const override
Returns the decoded content of the header without the header-type.
Base class for headers which deal with a single atom.
QByteArray token() const
Returns the token.
QByteArray subType() const
Returns the mime sub-type (second part of the mimetype).
@ CDInvalid
Default, invalid value.
Definition: kmime_headers.h:72
void clear() override
Deletes.
void clear() override
Deletes.
QString displayString() const
Returns a single string for user-facing display of this mailbox list.
QDate currentDate()
void setCancel(const QByteArray &msgid)
Changes this header into a cancel control message for the given message-id.
QString name() const
Returns the display name.
void setAddress(const AddrSpec &addr)
Sets the email address.
QString join(const QString &separator) const const
void setNeverCopy()
Sets the header to "never".
bool parse(const char *&scursor, const char *const send, bool isCRLF=false) override
This method parses the raw header and needs to be implemented in every sub-class.
bool isEmpty() const override
Checks if this header contains any data.
Represents a "ReplyTo" header.
QList< QByteArray > identifiers() const
Returns the list of identifiers contained in this header.
Base class for headers containing a list of phrases.
void setParameter(const QString &key, const QString &value)
Sets the parameter key to value.
static QByteArray defaultCharset()
Returns the charset that is used to decode RFC2047 strings in all headers and to decode the body if t...
bool isPartial() const
Returns true if the associated MIME entity contains partial data.
bool isText() const
Returns true if the associated MIME entity is a text.
bool isCancel() const
Returns true if this is a cancel control message.
contentEncoding encoding() const
Returns the encoding specified in this header.
bool isEmpty() const override
Checks if this header contains any data.
void setDisposition(contentDisposition disp)
Sets the content disposition.
virtual ~Base()
Destructor.
Represents a "Subject" header.
bool isEmpty() const override
Checks if this header contains any data.
Abstract base class for unstructured header fields (e.g.
QString toLower() const const
int ageInDays() const
Returns the age of the message.
Base class for structured header fields.
int toInt(bool *ok, int base) const const
QStringList displayNames() const
Returns a list of all display names associated with the addresses in this header.
Represents a "Mail-Copies-To" header.
QByteArray charset() const
Returns the charset for the associated MIME entity.
QByteArray as7BitString(bool withHeaderType=true) const override
Returns the encoded header.
Base class for headers that deal with exactly one mailbox (e.g.
bool isEmpty() const const
void setNumberOfLines(int lines)
Sets the number of lines to lines.
void resize(int size)
bool isDecoded() const
Returns whether the Content containing this header is already decoded.
void clear() override
Deletes.
const char * constData() const const
QString asUnicodeString() const override
Returns the decoded content of the header without the header-type.
QString fromLatin1(const char *str, int size)
contentDisposition
Various possible values for the "Content-Disposition" header.
Definition: kmime_headers.h:71
void setPartialParams(int total, int number)
Sets parameters of a partial MIME entity.
virtual QByteArray as7BitString(bool withHeaderType=true) const =0
Returns the encoded header.
QDate date() const const
bool parse(const char *&scursor, const char *const send, bool isCRLF=false) override
This method parses the raw header and needs to be implemented in every sub-class.
bool parse(const char *&scursor, const char *const send, bool isCRLF=false) override
This method parses the raw header and needs to be implemented in every sub-class.
bool isMimeHeader() const
Checks if this header is a MIME header.
void clear() override
Deletes.
bool isCrossposted() const
Returns true if this message has been cross-posted, i.e.
Represents a "Supersedes" header.
bool isEmpty() const override
Checks if this header contains any data.
void clear()
bool parse(const char *&scursor, const char *const send, bool isCRLF=false) override
This method parses the raw header and needs to be implemented in every sub-class.
bool endsWith(const QByteArray &ba) const const
bool parse(const char *&scursor, const char *const send, bool isCRLF=false) override
This method parses the raw header and needs to be implemented in every sub-class.
QByteArray as7BitString(const QByteArray &encCharset) const
Returns a 7bit transport encoded representation of this mailbox.
QString asUnicodeString() const override
Returns the decoded content of the header without the header-type.
Represents a (email) message.
Definition: kmime_message.h:66
int partialCount() const
Returns the total number of parts in a multi-part set.
Represents a "Date" header.
QString prettyAddress(Quoting quoting=QuoteNever) const
Overloaded method that gives more control over the quoting of the display name.
QString asUnicodeString() const override
Returns the decoded content of the header without the header-type.
Base class for headers which deal with a single msg-id.
bool parse(const char *&scursor, const char *const send, bool isCRLF=false) override
This method parses the raw header and needs to be implemented in every sub-class.
bool parse(const char *&scursor, const char *const send, bool isCRLF=false) override
This method parses the raw header and needs to be implemented in every sub-class.
int length() const const
Represents a "In-Reply-To" header.
bool isEmpty() const override
Checks if this header contains any data.
Base()
Creates an empty header.
bool isMultipart() const
Returns true if the associated MIME entity is a multipart container.
Represents a "Content-Disposition" header.
QString asUnicodeString() const override
Returns the decoded content of the header without the header-type.
void setFilename(const QString &filename)
Sets the suggested filename for the associated MIME part.
void setDecoded(bool isDecoded=true)
Set whether the Content containing this header is already decoded.
QByteArray id() const
Returns the identifier of the associated MIME entity.
Represents a "Content-Location" header.
bool isEmpty() const override
Checks if this header contains any data.
QByteArray encodeRFC2047String(const QString &src, const QByteArray &charset)
bool isHTMLText() const
Returns true if the associated MIME entity is a HTML file.
bool isEmpty() const override
Checks if this header contains any data.
Represents the Return-Path header field.
qint64 daysTo(const QDate &d) const const
QString & append(QChar ch)
bool needToEncode() const
Returns whether the Content containing this header needs to be encoded (i.e., if decoded() is true an...
bool parse(const char *&scursor, const char *const send, bool isCRLF=false) override
This method parses the raw header and needs to be implemented in every sub-class.
const KIMAP2_EXPORT QString encodeRFC2231String(const QString &str)
Represents a "Lines" header.
RFC2822Date
QStringList phrases() const
Returns the list of phrases contained in this header.
bool isEmpty() const override
Checks if this header contains any data.
Q_D(Todo)
void setBoundary(const QByteArray &s)
Sets the multipart container boundary.
bool parse(const char *&scursor, const char *const send, bool isCRLF=false) override
This method parses the raw header and needs to be implemented in every sub-class.
QString asUnicodeString() const override
Returns the decoded content of the header without the header-type.
virtual const char * type() const
Returns the type of this header (e.g.
Defines the various headers classes.
void clear() override
Deletes.
bool isEmpty() const override
Checks if this header contains any data.
void setIdentifier(const QByteArray &id)
Sets the identifier.
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Fri Sep 22 2023 03:52:43 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.