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

KDE's Doxygen guidelines are available online.