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 
359 {
361  rv.reserve(d_func()->mailboxList.count());
362  const auto mailboxList = d_func()->mailboxList;
363  for (const Types::Mailbox &mbox : mailboxList) {
364  rv.append(mbox.address());
365  }
366  return rv;
367 }
368 
370 {
371  Q_D(const MailboxList);
372  QStringList rv;
373  rv.reserve(d->mailboxList.count());
374  for (const Types::Mailbox &mbox : std::as_const(d->mailboxList)) {
375  if (mbox.hasName()) {
376  rv.append(mbox.name());
377  } else {
378  rv.append(QString::fromLatin1(mbox.address()));
379  }
380  }
381  return rv;
382 }
383 
385 {
386  Q_D(const MailboxList);
387  if (d->mailboxList.size() == 1) { // fast-path to avoid temporary QStringList in the common case of just one From address
388  const auto& mbox = d->mailboxList.at(0);
389  if (mbox.hasName()) {
390  return mbox.name();
391  } else {
392  return QString::fromLatin1(mbox.address());
393  }
394  }
395  return displayNames().join(QLatin1String(", "));
396 }
397 
399 {
400  return d_func()->mailboxList;
401 }
402 
403 bool MailboxList::parse(const char *&scursor, const char *const send,
404  bool isCRLF)
405 {
406  Q_D(MailboxList);
407  // examples:
408  // from := "From:" mailbox-list CRLF
409  // sender := "Sender:" mailbox CRLF
410 
411  // parse an address-list:
412  QVector<Types::Address> maybeAddressList;
413  if (!parseAddressList(scursor, send, maybeAddressList, isCRLF)) {
414  return false;
415  }
416 
417  d->mailboxList.clear();
418  d->mailboxList.reserve(maybeAddressList.count());
419 
420  // extract the mailboxes and complain if there are groups:
421  for (const auto &it : std::as_const(maybeAddressList)) {
422  if (!(it).displayName.isEmpty()) {
423  KMIME_WARN << "mailbox groups in header disallowing them! Name: \""
424  << (it).displayName << "\""
425  << Qt::endl
426  ;
427  }
428  d->mailboxList += (it).mailboxList;
429  }
430  return true;
431 }
432 
433 //-----</MailboxList>-------------------------
434 
435 //-----<SingleMailbox>-------------------------
436 
437 //@cond PRIVATE
438 kmime_mk_trivial_ctor_with_dptr(SingleMailbox, MailboxList)
439 //@endcond
440 
441 bool SingleMailbox::parse(const char *&scursor, const char *const send,
442  bool isCRLF)
443 {
444  Q_D(MailboxList);
445  if (!MailboxList::parse(scursor, send, isCRLF)) {
446  return false;
447  }
448 
449  if (d->mailboxList.count() > 1) {
450  KMIME_WARN << "multiple mailboxes in header allowing only a single one!"
451  << Qt::endl;
452  }
453  return true;
454 }
455 
456 //-----</SingleMailbox>-------------------------
457 
458 //-----<AddressList>-------------------------
459 
460 //@cond PRIVATE
461 kmime_mk_trivial_ctor_with_dptr(AddressList, Address)
462 kmime_mk_dptr_ctor(AddressList, Address)
463 //@endcond
464 
465 QByteArray AddressList::as7BitString(bool withHeaderType) const
466 {
467  const Q_D(AddressList);
468  if (d->addressList.isEmpty()) {
469  return {};
470  }
471 
472  QByteArray rv;
473  if (withHeaderType) {
474  rv = typeIntro();
475  }
476  for (const Types::Address &addr : std::as_const(d->addressList)) {
477  const auto mailBoxList = addr.mailboxList;
478  for (const Types::Mailbox &mbox : mailBoxList) {
479  rv += mbox.as7BitString(d->encCS);
480  rv += ", ";
481  }
482  }
483  rv.resize(rv.length() - 2);
484  return rv;
485 }
486 
488 {
489  Q_D(AddressList);
490  d->encCS = cachedCharset(b);
491  from7BitString(encodeRFC2047Sentence(s, b));
492 }
493 
495 {
496  Q_D(const AddressList);
497  QStringList rv;
498  for (const Types::Address &addr : std::as_const(d->addressList)) {
499  rv.reserve(rv.size() + addr.mailboxList.size());
500  const auto mailboxList = addr.mailboxList;
501  for (const Types::Mailbox &mbox : mailboxList) {
502  rv.append(mbox.prettyAddress());
503  }
504  }
505  return rv.join(QLatin1String(", "));
506 }
507 
509 {
510  Q_D(AddressList);
511  d->addressList.clear();
512 }
513 
515 {
516  return d_func()->addressList.isEmpty();
517 }
518 
520 {
521  Q_D(AddressList);
522  Types::Address addr;
523  addr.mailboxList.append(mbox);
524  d->addressList.append(addr);
525 }
526 
528  const QString &displayName)
529 {
530  Q_D(AddressList);
531  Types::Address addr;
532  Types::Mailbox mbox;
533  if (stringToMailbox(address, displayName, mbox)) {
534  addr.mailboxList.append(mbox);
535  d->addressList.append(addr);
536  }
537 }
538 
540 {
542  const auto addressList = d_func()->addressList;
543  for (const Types::Address &addr : addressList) {
544  const auto mailboxList = addr.mailboxList;
545  for (const Types::Mailbox &mbox : mailboxList) {
546  rv.append(mbox.address());
547  }
548  }
549  return rv;
550 }
551 
553 {
554  Q_D(const AddressList);
555  QStringList rv;
556  for (const Types::Address &addr : std::as_const(d->addressList)) {
557  const auto mailboxList = addr.mailboxList;
558  for (const Types::Mailbox &mbox : mailboxList) {
559  if (mbox.hasName()) {
560  rv.append(mbox.name());
561  } else {
562  rv.append(QString::fromLatin1(mbox.address()));
563  }
564  }
565  }
566  return rv;
567 }
568 
570 {
571  // optimize for single entry and avoid creation of the QStringList in that case?
572  return displayNames().join(QLatin1String(", "));
573 }
574 
576 {
578  const auto addressList = d_func()->addressList;
579  for (const Types::Address &addr : addressList) {
580  const auto mailboxList = addr.mailboxList;
581  for (const Types::Mailbox &mbox : mailboxList) {
582  rv.append(mbox);
583  }
584  }
585  return rv;
586 }
587 
588 bool AddressList::parse(const char *&scursor, const char *const send,
589  bool isCRLF)
590 {
591  Q_D(AddressList);
592  QVector<Types::Address> maybeAddressList;
593  if (!parseAddressList(scursor, send, maybeAddressList, isCRLF)) {
594  return false;
595  }
596 
597  d->addressList = maybeAddressList;
598  return true;
599 }
600 
601 //-----</AddressList>-------------------------
602 
603 //-----<Token>-------------------------
604 
605 //@cond PRIVATE
606 kmime_mk_trivial_ctor_with_dptr(Token, Structured)
607 kmime_mk_dptr_ctor(Token, Structured)
608 //@endcond
609 
610 QByteArray Token::as7BitString(bool withHeaderType) const
611 {
612  if (isEmpty()) {
613  return {};
614  }
615  if (withHeaderType) {
616  return typeIntro() + d_func()->token;
617  }
618  return d_func()->token;
619 }
620 
622 {
623  Q_D(Token);
624  d->token.clear();
625 }
626 
627 bool Token::isEmpty() const
628 {
629  return d_func()->token.isEmpty();
630 }
631 
633 {
634  return d_func()->token;
635 }
636 
638 {
639  Q_D(Token);
640  d->token = t;
641 }
642 
643 bool Token::parse(const char *&scursor, const char *const send, bool isCRLF)
644 {
645  Q_D(Token);
646  clear();
647  eatCFWS(scursor, send, isCRLF);
648  // must not be empty:
649  if (scursor == send) {
650  return false;
651  }
652 
653  QPair<const char *, int> maybeToken;
654  if (!parseToken(scursor, send, maybeToken, ParseTokenNoFlag)) {
655  return false;
656  }
657  d->token = QByteArray(maybeToken.first, maybeToken.second);
658 
659  // complain if trailing garbage is found:
660  eatCFWS(scursor, send, isCRLF);
661  if (scursor != send) {
662  KMIME_WARN << "trailing garbage after token in header allowing "
663  "only a single token!"
664  << Qt::endl;
665  }
666  return true;
667 }
668 
669 //-----</Token>-------------------------
670 
671 //-----<PhraseList>-------------------------
672 
673 //@cond PRIVATE
674 kmime_mk_trivial_ctor_with_dptr(PhraseList, Structured)
675 //@endcond
676 
677 QByteArray PhraseList::as7BitString(bool withHeaderType) const
678 {
679  const Q_D(PhraseList);
680  if (isEmpty()) {
681  return {};
682  }
683 
684  QByteArray rv;
685  if (withHeaderType) {
686  rv = typeIntro();
687  }
688 
689  for (int i = 0; i < d->phraseList.count(); ++i) {
690  // FIXME: only encode when needed, quote when needed, etc.
691  rv += encodeRFC2047String(d->phraseList[i], d->encCS, false, false);
692  if (i != d->phraseList.count() - 1) {
693  rv += ", ";
694  }
695  }
696 
697  return rv;
698 }
699 
701 {
702  return d_func()->phraseList.join(QLatin1String(", "));
703 }
704 
706 {
707  Q_D(PhraseList);
708  d->phraseList.clear();
709 }
710 
712 {
713  return d_func()->phraseList.isEmpty();
714 }
715 
717 {
718  return d_func()->phraseList;
719 }
720 
721 bool PhraseList::parse(const char *&scursor, const char *const send,
722  bool isCRLF)
723 {
724  Q_D(PhraseList);
725  d->phraseList.clear();
726 
727  while (scursor != send) {
728  eatCFWS(scursor, send, isCRLF);
729  // empty entry ending the list: OK.
730  if (scursor == send) {
731  return true;
732  }
733  // empty entry: ignore.
734  if (*scursor == ',') {
735  scursor++;
736  continue;
737  }
738 
739  QString maybePhrase;
740  if (!parsePhrase(scursor, send, maybePhrase, isCRLF)) {
741  return false;
742  }
743  d->phraseList.append(maybePhrase);
744 
745  eatCFWS(scursor, send, isCRLF);
746  // non-empty entry ending the list: OK.
747  if (scursor == send) {
748  return true;
749  }
750  // comma separating the phrases: eat.
751  if (*scursor == ',') {
752  scursor++;
753  }
754  }
755  return true;
756 }
757 
758 //-----</PhraseList>-------------------------
759 
760 //-----<DotAtom>-------------------------
761 
762 //@cond PRIVATE
763 kmime_mk_trivial_ctor_with_dptr(DotAtom, Structured)
764 //@endcond
765 
766 QByteArray DotAtom::as7BitString(bool withHeaderType) const
767 {
768  if (isEmpty()) {
769  return {};
770  }
771 
772  QByteArray rv;
773  if (withHeaderType) {
774  rv += typeIntro();
775  }
776 
777  rv += d_func()->dotAtom;
778  return rv;
779 }
780 
782 {
783  return QString::fromLatin1(d_func()->dotAtom);
784 }
785 
787 {
788  Q_D(DotAtom);
789  d->dotAtom.clear();
790 }
791 
792 bool DotAtom::isEmpty() const
793 {
794  return d_func()->dotAtom.isEmpty();
795 }
796 
797 bool DotAtom::parse(const char *&scursor, const char *const send,
798  bool isCRLF)
799 {
800  Q_D(DotAtom);
801  QByteArray maybeDotAtom;
802  if (!parseDotAtom(scursor, send, maybeDotAtom, isCRLF)) {
803  return false;
804  }
805 
806  d->dotAtom = maybeDotAtom;
807 
808  eatCFWS(scursor, send, isCRLF);
809  if (scursor != send) {
810  KMIME_WARN << "trailing garbage after dot-atom in header allowing "
811  "only a single dot-atom!"
812  << Qt::endl;
813  }
814  return true;
815 }
816 
817 //-----</DotAtom>-------------------------
818 
819 //-----<Parametrized>-------------------------
820 
821 //@cond PRIVATE
822 kmime_mk_trivial_ctor_with_dptr(Parametrized, Structured)
823 kmime_mk_dptr_ctor(Parametrized, Structured)
824 //@endcond
825 
826 QByteArray Parametrized::as7BitString(bool withHeaderType) const
827 {
828  const Q_D(Parametrized);
829  if (isEmpty()) {
830  return {};
831  }
832 
833  QByteArray rv;
834  if (withHeaderType) {
835  rv += typeIntro();
836  }
837 
838  bool first = true;
839  for (QMap<QString, QString>::ConstIterator it = d->parameterHash.constBegin();
840  it != d->parameterHash.constEnd(); ++it) {
841  if (!first) {
842  rv += "; ";
843  } else {
844  first = false;
845  }
846  if (isUsAscii(it.value())) {
847  rv += it.key().toLatin1() + '=';
848  QByteArray tmp = it.value().toLatin1();
849  addQuotes(tmp, true); // force quoting, eg. for whitespaces in parameter value
850  rv += tmp;
851  } else {
852  if (useOutlookAttachmentEncoding()) {
853  rv += it.key().toLatin1() + '=';
854  qCDebug(KMIME_LOG) << "doing:" << it.value() << QLatin1String(d->encCS);
855  rv += "\"" + encodeRFC2047String(it.value(), d->encCS) + "\"";
856  } else {
857  rv += it.key().toLatin1() + "*=";
858  rv += encodeRFC2231String(it.value(), d->encCS);
859  }
860  }
861  }
862 
863  return rv;
864 }
865 
867 {
868  return d_func()->parameterHash.value(key.toLower());
869 }
870 
871 bool Parametrized::hasParameter(const QString &key) const
872 {
873  return d_func()->parameterHash.contains(key.toLower());
874 }
875 
876 void Parametrized::setParameter(const QString &key, const QString &value)
877 {
878  Q_D(Parametrized);
879  d->parameterHash.insert(key.toLower(), value);
880 }
881 
883 {
884  return d_func()->parameterHash.isEmpty();
885 }
886 
888 {
889  Q_D(Parametrized);
890  d->parameterHash.clear();
891 }
892 
893 bool Parametrized::parse(const char *&scursor, const char *const send,
894  bool isCRLF)
895 {
896  Q_D(Parametrized);
897  d->parameterHash.clear();
898  QByteArray charset;
899  if (!parseParameterListWithCharset(scursor, send, d->parameterHash, charset, isCRLF)) {
900  return false;
901  }
902  d->encCS = charset;
903  return true;
904 }
905 
906 //-----</Parametrized>-------------------------
907 
908 //-----<Ident>-------------------------
909 
910 //@cond PRIVATE
911 kmime_mk_trivial_ctor_with_dptr(Ident, Address)
912 kmime_mk_dptr_ctor(Ident, Address)
913 //@endcond
914 
915 QByteArray Ident::as7BitString(bool withHeaderType) const
916 {
917  const Q_D(Ident);
918  if (d->msgIdList.isEmpty()) {
919  return {};
920  }
921 
922  QByteArray rv;
923  if (withHeaderType) {
924  rv = typeIntro();
925  }
926  for (const Types::AddrSpec &addr : std::as_const(d->msgIdList)) {
927  if (!addr.isEmpty()) {
928  const QString asString = addr.asString();
929  rv += '<';
930  if (!asString.isEmpty()) {
931  rv += asString.toLatin1(); // FIXME: change parsing to use QByteArrays
932  }
933  rv += "> ";
934  }
935  }
936  if (!rv.isEmpty()) {
937  rv.resize(rv.length() - 1);
938  }
939  return rv;
940 }
941 
943 {
944  Q_D(Ident);
945  d->msgIdList.clear();
946  d->cachedIdentifier.clear();
947 }
948 
949 bool Ident::isEmpty() const
950 {
951  return d_func()->msgIdList.isEmpty();
952 }
953 
954 bool Ident::parse(const char *&scursor, const char *const send, bool isCRLF)
955 {
956  Q_D(Ident);
957  // msg-id := "<" id-left "@" id-right ">"
958  // id-left := dot-atom-text / no-fold-quote / local-part
959  // id-right := dot-atom-text / no-fold-literal / domain
960  //
961  // equivalent to:
962  // msg-id := angle-addr
963 
964  d->msgIdList.clear();
965  d->cachedIdentifier.clear();
966 
967  while (scursor != send) {
968  eatCFWS(scursor, send, isCRLF);
969  // empty entry ending the list: OK.
970  if (scursor == send) {
971  return true;
972  }
973  // empty entry: ignore.
974  if (*scursor == ',') {
975  scursor++;
976  continue;
977  }
978 
979  AddrSpec maybeMsgId;
980  if (!parseAngleAddr(scursor, send, maybeMsgId, isCRLF)) {
981  return false;
982  }
983  d->msgIdList.append(maybeMsgId);
984 
985  eatCFWS(scursor, send, isCRLF);
986  // header end ending the list: OK.
987  if (scursor == send) {
988  return true;
989  }
990  // regular item separator: eat it.
991  if (*scursor == ',') {
992  scursor++;
993  }
994  }
995  return true;
996 }
997 
999 {
1001  const auto msgIdList = d_func()->msgIdList;
1002  for (const Types::AddrSpec &addr : msgIdList) {
1003  if (!addr.isEmpty()) {
1004  const QString asString = addr.asString();
1005  if (!asString.isEmpty()) {
1006  rv.append(asString.toLatin1()); // FIXME: change parsing to use QByteArrays
1007  }
1008  }
1009  }
1010  return rv;
1011 }
1012 
1013 void Ident::fromIdent(const Ident* ident)
1014 {
1015  d_func()->encCS = ident->d_func()->encCS;
1016  d_func()->msgIdList = ident->d_func()->msgIdList;
1017  d_func()->cachedIdentifier = ident->d_func()->cachedIdentifier;
1018 }
1019 
1021 {
1022  Q_D(Ident);
1023  QByteArray tmp = id;
1024  if (!tmp.startsWith('<')) {
1025  tmp.prepend('<');
1026  }
1027  if (!tmp.endsWith('>')) {
1028  tmp.append('>');
1029  }
1030  AddrSpec msgId;
1031  const char *cursor = tmp.constData();
1032  if (parseAngleAddr(cursor, cursor + tmp.length(), msgId)) {
1033  d->msgIdList.append(msgId);
1034  } else {
1035  qCWarning(KMIME_LOG) << "Unable to parse address spec!";
1036  }
1037 }
1038 
1039 //-----</Ident>-------------------------
1040 
1041 //-----<SingleIdent>-------------------------
1042 
1043 //@cond PRIVATE
1044 kmime_mk_trivial_ctor_with_dptr(SingleIdent, Ident)
1045 kmime_mk_dptr_ctor(SingleIdent, Ident)
1046 //@endcond
1047 
1048 QByteArray SingleIdent::identifier() const
1049 {
1050  if (d_func()->msgIdList.isEmpty()) {
1051  return {};
1052  }
1053 
1054  if (d_func()->cachedIdentifier.isEmpty()) {
1055  const Types::AddrSpec &addr = d_func()->msgIdList.first();
1056  if (!addr.isEmpty()) {
1057  const QString asString = addr.asString();
1058  if (!asString.isEmpty()) {
1059  d_func()->cachedIdentifier = asString.toLatin1();// FIXME: change parsing to use QByteArrays
1060  }
1061  }
1062  }
1063 
1064  return d_func()->cachedIdentifier;
1065 }
1066 
1068 {
1069  Q_D(SingleIdent);
1070  d->msgIdList.clear();
1071  d->cachedIdentifier.clear();
1072  appendIdentifier(id);
1073 }
1074 
1075 bool SingleIdent::parse(const char *&scursor, const char *const send,
1076  bool isCRLF)
1077 {
1078  Q_D(SingleIdent);
1079  if (!Ident::parse(scursor, send, isCRLF)) {
1080  return false;
1081  }
1082 
1083  if (d->msgIdList.count() > 1) {
1084  KMIME_WARN << "more than one msg-id in header "
1085  << "allowing only a single one!"
1086  << Qt::endl;
1087  }
1088  return true;
1089 }
1090 
1091 //-----</SingleIdent>-------------------------
1092 
1093 } // namespace Generics
1094 
1095 //-----<ReturnPath>-------------------------
1096 
1097 //@cond PRIVATE
1098 kmime_mk_trivial_ctor_with_name_and_dptr(ReturnPath, Generics::Address, Return-Path)
1099 //@endcond
1100 
1101 QByteArray ReturnPath::as7BitString(bool withHeaderType) const
1102 {
1103  if (isEmpty()) {
1104  return {};
1105  }
1106 
1107  QByteArray rv;
1108  if (withHeaderType) {
1109  rv += typeIntro();
1110  }
1111  rv += '<' + d_func()->mailbox.as7BitString(d_func()->encCS) + '>';
1112  return rv;
1113 }
1114 
1116 {
1117  Q_D(ReturnPath);
1118  d->mailbox.setAddress(Types::AddrSpec());
1119  d->mailbox.setName(QString());
1120 }
1121 
1123 {
1124  const Q_D(ReturnPath);
1125  return !d->mailbox.hasAddress() && !d->mailbox.hasName();
1126 }
1127 
1128 bool ReturnPath::parse(const char *&scursor, const char *const send,
1129  bool isCRLF)
1130 {
1131  Q_D(ReturnPath);
1132  eatCFWS(scursor, send, isCRLF);
1133  if (scursor == send) {
1134  return false;
1135  }
1136 
1137  const char *oldscursor = scursor;
1138 
1139  Mailbox maybeMailbox;
1140  if (!parseMailbox(scursor, send, maybeMailbox, isCRLF)) {
1141  // mailbox parsing failed, but check for empty brackets:
1142  scursor = oldscursor;
1143  if (*scursor != '<') {
1144  return false;
1145  }
1146  scursor++;
1147  eatCFWS(scursor, send, isCRLF);
1148  if (scursor == send || *scursor != '>') {
1149  return false;
1150  }
1151  scursor++;
1152 
1153  // prepare a Null mailbox:
1154  AddrSpec emptyAddrSpec;
1155  maybeMailbox.setName(QString());
1156  maybeMailbox.setAddress(emptyAddrSpec);
1157  } else {
1158  // check that there was no display-name:
1159  if (maybeMailbox.hasName()) {
1160  KMIME_WARN << "display-name \"" << maybeMailbox.name()
1161  << "\" in Return-Path!" << Qt::endl;
1162  }
1163  }
1164  d->mailbox = maybeMailbox;
1165 
1166  // see if that was all:
1167  eatCFWS(scursor, send, isCRLF);
1168  // and warn if it wasn't:
1169  if (scursor != send) {
1170  KMIME_WARN << "trailing garbage after angle-addr in Return-Path!"
1171  << Qt::endl;
1172  }
1173  return true;
1174 }
1175 
1176 //-----</ReturnPath>-------------------------
1177 
1178 //-----<Generic>-------------------------------
1179 
1180 // NOTE: Do *not* register Generic with HeaderFactory, since its type() is changeable.
1181 
1182 Generic::Generic() : Generics::Unstructured(new GenericPrivate)
1183 {
1184 }
1185 
1186 Generic::Generic(const char *t, int len) : Generics::Unstructured(new GenericPrivate)
1187 {
1188  setType(t, len);
1189 }
1190 
1191 Generic::~Generic()
1192 {
1193  Q_D(Generic);
1194  delete d;
1195  d_ptr = nullptr;
1196 }
1197 
1199 {
1200  Q_D(Generic);
1201  delete[] d->type;
1202  d->type = nullptr;
1203  Unstructured::clear();
1204 }
1205 
1206 bool Generic::isEmpty() const
1207 {
1208  return d_func()->type == nullptr || Unstructured::isEmpty();
1209 }
1210 
1211 const char *Generic::type() const
1212 {
1213  return d_func()->type;
1214 }
1215 
1216 void Generic::setType(const char *type, int len)
1217 {
1218  Q_D(Generic);
1219  if (d->type) {
1220  delete[] d->type;
1221  }
1222  if (type) {
1223  const int l = (len < 0 ? strlen(type) : len) + 1;
1224  d->type = new char[l];
1225  qstrncpy(d->type, type, l);
1226  } else {
1227  d->type = nullptr;
1228  }
1229 }
1230 
1231 //-----<Generic>-------------------------------
1232 
1233 //-----<MessageID>-----------------------------
1234 
1235 //@cond PRIVATE
1236 kmime_mk_trivial_ctor_with_name(MessageID, Generics::SingleIdent, Message-ID)
1237 //@endcond
1238 
1239 void MessageID::generate(const QByteArray &fqdn)
1240 {
1241  setIdentifier('<' + uniqueString() + '@' + fqdn + '>');
1242 }
1243 
1244 //-----</MessageID>----------------------------
1245 
1246 //-----<Control>-------------------------------
1247 
1248 //@cond PRIVATE
1249 kmime_mk_trivial_ctor_with_name_and_dptr(Control, Generics::Structured, Control)
1250 //@endcond
1251 
1252 QByteArray Control::as7BitString(bool withHeaderType) const
1253 {
1254  const Q_D(Control);
1255  if (isEmpty()) {
1256  return {};
1257  }
1258 
1259  QByteArray rv;
1260  if (withHeaderType) {
1261  rv += typeIntro();
1262  }
1263 
1264  rv += d->name;
1265  if (!d->parameter.isEmpty()) {
1266  rv += ' ' + d->parameter;
1267  }
1268  return rv;
1269 }
1270 
1272 {
1273  Q_D(Control);
1274  d->name.clear();
1275  d->parameter.clear();
1276 }
1277 
1278 bool Control::isEmpty() const
1279 {
1280  return d_func()->name.isEmpty();
1281 }
1282 
1284 {
1285  return d_func()->name;
1286 }
1287 
1289 {
1290  return d_func()->parameter;
1291 }
1292 
1293 bool Control::isCancel() const
1294 {
1295  return d_func()->name.toLower() == "cancel";
1296 }
1297 
1298 void Control::setCancel(const QByteArray &msgid)
1299 {
1300  Q_D(Control);
1301  d->name = "cancel";
1302  d->parameter = msgid;
1303 }
1304 
1305 bool Control::parse(const char *&scursor, const char *const send, bool isCRLF)
1306 {
1307  Q_D(Control);
1308  clear();
1309  eatCFWS(scursor, send, isCRLF);
1310  if (scursor == send) {
1311  return false;
1312  }
1313  const char *start = scursor;
1314  while (scursor != send && !isspace(*scursor)) {
1315  ++scursor;
1316  }
1317  d->name = QByteArray(start, scursor - start);
1318  eatCFWS(scursor, send, isCRLF);
1319  d->parameter = QByteArray(scursor, send - scursor);
1320  return true;
1321 }
1322 
1323 //-----</Control>------------------------------
1324 
1325 //-----<MailCopiesTo>--------------------------
1326 
1327 //@cond PRIVATE
1328 kmime_mk_trivial_ctor_with_name_and_dptr(MailCopiesTo,
1329  Generics::AddressList, Mail-Copies-To)
1330 //@endcond
1331 
1332 QByteArray MailCopiesTo::as7BitString(bool withHeaderType) const
1333 {
1334  QByteArray rv;
1335  if (withHeaderType) {
1336  rv += typeIntro();
1337  }
1338  if (!AddressList::isEmpty()) {
1339  rv += AddressList::as7BitString(false);
1340  } else {
1341  if (d_func()->alwaysCopy) {
1342  rv += "poster";
1343  } else if (d_func()->neverCopy) {
1344  rv += "nobody";
1345  }
1346  }
1347  return rv;
1348 }
1349 
1351 {
1352  if (!AddressList::isEmpty()) {
1353  return AddressList::asUnicodeString();
1354  }
1355  if (d_func()->alwaysCopy) {
1356  return QStringLiteral("poster");
1357  }
1358  if (d_func()->neverCopy) {
1359  return QStringLiteral("nobody");
1360  }
1361  return {};
1362 }
1363 
1365 {
1366  Q_D(MailCopiesTo);
1367  AddressList::clear();
1368  d->alwaysCopy = false;
1369  d->neverCopy = false;
1370 }
1371 
1373 {
1374  return AddressList::isEmpty() && !(d_func()->alwaysCopy || d_func()->neverCopy);
1375 }
1376 
1378 {
1379  return !AddressList::isEmpty() || d_func()->alwaysCopy;
1380 }
1381 
1383 {
1384  Q_D(MailCopiesTo);
1385  clear();
1386  d->alwaysCopy = true;
1387 }
1388 
1390 {
1391  return d_func()->neverCopy;
1392 }
1393 
1395 {
1396  Q_D(MailCopiesTo);
1397  clear();
1398  d->neverCopy = true;
1399 }
1400 
1401 bool MailCopiesTo::parse(const char *&scursor, const char *const send,
1402  bool isCRLF)
1403 {
1404  Q_D(MailCopiesTo);
1405  clear();
1406  if (send - scursor == 5) {
1407  if (qstrnicmp("never", scursor, 5) == 0) {
1408  d->neverCopy = true;
1409  return true;
1410  }
1411  }
1412  if (send - scursor == 6) {
1413  if (qstrnicmp("always", scursor, 6) == 0 || qstrnicmp("poster", scursor, 6) == 0) {
1414  d->alwaysCopy = true;
1415  return true;
1416  }
1417  if (qstrnicmp("nobody", scursor, 6) == 0) {
1418  d->neverCopy = true;
1419  return true;
1420  }
1421  }
1422  return AddressList::parse(scursor, send, isCRLF);
1423 }
1424 
1425 //-----</MailCopiesTo>-------------------------
1426 
1427 //-----<Date>----------------------------------
1428 
1429 //@cond PRIVATE
1430 kmime_mk_trivial_ctor_with_name_and_dptr(Date, Generics::Structured, Date)
1431 //@endcond
1432 
1433 QByteArray Date::as7BitString(bool withHeaderType) const
1434 {
1435  if (isEmpty()) {
1436  return {};
1437  }
1438 
1439  QByteArray rv;
1440  if (withHeaderType) {
1441  rv += typeIntro();
1442  }
1443  //QT5 fix port to QDateTime Qt::RFC2822Date is not enough we need to fix it. We need to use QLocale("C") + add "ddd, ";
1444  //rv += d_func()->dateTime.toString( Qt::RFC2822Date ).toLatin1();
1445  rv += QLocale::c().toString(d_func()->dateTime, QStringLiteral("ddd, ")).toLatin1();
1446  rv += d_func()->dateTime.toString(Qt::RFC2822Date).toLatin1();
1447 
1448  return rv;
1449 }
1450 
1451 void Date::clear() {
1452  Q_D(Date);
1453  d->dateTime = QDateTime();
1454 }
1455 
1456 bool Date::isEmpty() const {
1457  return d_func()->dateTime.isNull() || !d_func()->dateTime.isValid();
1458 }
1459 
1461  return d_func()->dateTime;
1462 }
1463 
1464 void Date::setDateTime(const QDateTime & dt) {
1465  Q_D(Date);
1466  d->dateTime = dt;
1467 }
1468 
1469 int Date::ageInDays() const {
1470  QDate today = QDate::currentDate();
1471  return dateTime().date().daysTo(today);
1472 }
1473 
1474 bool Date::parse(const char *&scursor, const char *const send, bool isCRLF) {
1475  Q_D(Date);
1476  return parseDateTime(scursor, send, d->dateTime, isCRLF);
1477 }
1478 
1479 //-----</Date>---------------------------------
1480 
1481 //-----<Newsgroups>----------------------------
1482 
1483 //@cond PRIVATE
1484 kmime_mk_trivial_ctor_with_name_and_dptr(Newsgroups, Generics::Structured, Newsgroups)
1485 kmime_mk_trivial_ctor_with_name(FollowUpTo, Newsgroups, Followup-To)
1486 //@endcond
1487 
1488 QByteArray Newsgroups::as7BitString(bool withHeaderType) const {
1489  const Q_D(Newsgroups);
1490  if (isEmpty()) {
1491  return {};
1492  }
1493 
1494  QByteArray rv;
1495  if (withHeaderType) {
1496  rv += typeIntro();
1497  }
1498 
1499  for (int i = 0; i < d->groups.count(); ++i) {
1500  rv += d->groups[ i ];
1501  if (i != d->groups.count() - 1) {
1502  rv += ',';
1503  }
1504  }
1505  return rv;
1506 }
1507 
1509  Q_UNUSED(b)
1510  Q_D(Newsgroups);
1511  from7BitString(s.toUtf8());
1512  d->encCS = cachedCharset("UTF-8");
1513 }
1514 
1516  return QString::fromUtf8(as7BitString(false));
1517 }
1518 
1520  Q_D(Newsgroups);
1521  d->groups.clear();
1522 }
1523 
1524 bool Newsgroups::isEmpty() const {
1525  return d_func()->groups.isEmpty();
1526 }
1527 
1529  return d_func()->groups;
1530 }
1531 
1533  Q_D(Newsgroups);
1534  d->groups = groups;
1535 }
1536 
1538  return d_func()->groups.count() >= 2;
1539 }
1540 
1541 bool Newsgroups::parse(const char *&scursor, const char *const send, bool isCRLF) {
1542  Q_D(Newsgroups);
1543  clear();
1544  while (true) {
1545  eatCFWS(scursor, send, isCRLF);
1546  if (scursor != send && *scursor == ',') {
1547  ++scursor;
1548  }
1549  eatCFWS(scursor, send, isCRLF);
1550  if (scursor == send) {
1551  return true;
1552  }
1553  const char *start = scursor;
1554  while (scursor != send && !isspace(*scursor) && *scursor != ',') {
1555  ++scursor;
1556  }
1557  QByteArray group(start, scursor - start);
1558  d->groups.append(group);
1559  }
1560  return true;
1561 }
1562 
1563 //-----</Newsgroups>---------------------------
1564 
1565 //-----<Lines>---------------------------------
1566 
1567 //@cond PRIVATE
1568 kmime_mk_trivial_ctor_with_name_and_dptr(Lines, Generics::Structured, Lines)
1569 //@endcond
1570 
1571 QByteArray Lines::as7BitString(bool withHeaderType) const {
1572  if (isEmpty()) {
1573  return {};
1574  }
1575 
1576  QByteArray num;
1577  num.setNum(d_func()->lines);
1578 
1579  if (withHeaderType) {
1580  return typeIntro() + num;
1581  }
1582  return num;
1583 }
1584 
1586  if (isEmpty()) {
1587  return {};
1588  }
1589  return QString::number(d_func()->lines);
1590 }
1591 
1593  Q_D(Lines);
1594  d->lines = -1;
1595 }
1596 
1597 bool Lines::isEmpty() const {
1598  return d_func()->lines == -1;
1599 }
1600 
1602  return d_func()->lines;
1603 }
1604 
1605 void Lines::setNumberOfLines(int lines) {
1606  Q_D(Lines);
1607  d->lines = lines;
1608 }
1609 
1610 bool Lines::parse(const char *&scursor, const char *const send, bool isCRLF) {
1611  Q_D(Lines);
1612  eatCFWS(scursor, send, isCRLF);
1613  if (parseDigits(scursor, send, d->lines) == 0) {
1614  clear();
1615  return false;
1616  }
1617  return true;
1618 }
1619 
1620 //-----</Lines>--------------------------------
1621 
1622 //-----<Content-Type>--------------------------
1623 
1624 //@cond PRIVATE
1625 kmime_mk_trivial_ctor_with_name_and_dptr(ContentType, Generics::Parametrized,
1626  Content-Type)
1627 //@endcond
1628 
1629 bool ContentType::isEmpty() const {
1630  return d_func()->mimeType.isEmpty();
1631 }
1632 
1634  Q_D(ContentType);
1635  d->category = CCsingle;
1636  d->mimeType.clear();
1637  Parametrized::clear();
1638 }
1639 
1640 QByteArray ContentType::as7BitString(bool withHeaderType) const {
1641  if (isEmpty()) {
1642  return {};
1643  }
1644 
1645  QByteArray rv;
1646  if (withHeaderType) {
1647  rv += typeIntro();
1648  }
1649 
1650  rv += mimeType();
1651  if (!Parametrized::isEmpty()) {
1652  rv += "; " + Parametrized::as7BitString(false);
1653  }
1654 
1655  return rv;
1656 }
1657 
1659  Q_D(const ContentType);
1660  return d->mimeType;
1661 }
1662 
1664  Q_D(const ContentType);
1665  const int pos = d->mimeType.indexOf('/');
1666  if (pos < 0) {
1667  return d->mimeType;
1668  } else {
1669  return d->mimeType.left(pos);
1670  }
1671 }
1672 
1674  Q_D(const ContentType);
1675  const int pos = d->mimeType.indexOf('/');
1676  if (pos < 0) {
1677  return {};
1678  } else {
1679  return d->mimeType.mid(pos + 1);
1680  }
1681 }
1682 
1683 void ContentType::setMimeType(const QByteArray & mimeType) {
1684  Q_D(ContentType);
1685  d->mimeType = mimeType;
1686 
1687  if (isMultipart()) {
1688  d->category = CCcontainer;
1689  } else {
1690  d->category = CCsingle;
1691  }
1692 }
1693 
1694 bool ContentType::isMediatype(const char *mediatype) const {
1695  Q_D(const ContentType);
1696  const int len = strlen(mediatype);
1697  return qstrnicmp(d->mimeType.constData(), mediatype, len) == 0 &&
1698  (d->mimeType.at(len) == '/' || d->mimeType.size() == len);
1699 }
1700 
1701 bool ContentType::isSubtype(const char *subtype) const {
1702  Q_D(const ContentType);
1703  const int pos = d->mimeType.indexOf('/');
1704  if (pos < 0) {
1705  return false;
1706  }
1707  const int len = strlen(subtype);
1708  return qstrnicmp(d->mimeType.constData() + pos + 1, subtype, len) == 0 &&
1709  d->mimeType.size() == pos + len + 1;
1710 }
1711 
1712 bool ContentType::isMimeType(const char* mimeType) const
1713 {
1714  Q_D(const ContentType);
1715  return qstricmp(d->mimeType.constData(), mimeType) == 0;
1716 }
1717 
1718 bool ContentType::isText() const {
1719  return (isMediatype("text") || isEmpty());
1720 }
1721 
1723  return (qstricmp(d_func()->mimeType.constData(), "text/plain") == 0 || isEmpty());
1724 }
1725 
1727  return qstricmp(d_func()->mimeType.constData(), "text/html") == 0;
1728 }
1729 
1730 bool ContentType::isImage() const {
1731  return isMediatype("image");
1732 }
1733 
1735  return isMediatype("multipart");
1736 }
1737 
1739  return qstricmp(d_func()->mimeType.constData(), "message/partial") == 0;
1740 }
1741 
1743  QByteArray ret = parameter(QStringLiteral("charset")).toLatin1();
1744  if (ret.isEmpty()) {
1745  //return the default-charset if necessary
1746  ret = Content::defaultCharset();
1747  }
1748  return ret;
1749 }
1750 
1752  setParameter(QStringLiteral("charset"), QString::fromLatin1(s));
1753 }
1754 
1756  return parameter(QStringLiteral("boundary")).toLatin1();
1757 }
1758 
1760  setParameter(QStringLiteral("boundary"), QString::fromLatin1(s));
1761 }
1762 
1764  return parameter(QStringLiteral("name"));
1765 }
1766 
1767 void ContentType::setName(const QString & s, const QByteArray & cs) {
1768  Q_D(ContentType);
1769  d->encCS = cs;
1770  setParameter(QStringLiteral("name"), s);
1771 }
1772 
1774  return parameter(QStringLiteral("id")).toLatin1();
1775 }
1776 
1778  setParameter(QStringLiteral("id"), QString::fromLatin1(s));
1779 }
1780 
1782  QByteArray p = parameter(QStringLiteral("number")).toLatin1();
1783  if (!p.isEmpty()) {
1784  return p.toInt();
1785  } else {
1786  return -1;
1787  }
1788 }
1789 
1791  QByteArray p = parameter(QStringLiteral("total")).toLatin1();
1792  if (!p.isEmpty()) {
1793  return p.toInt();
1794  } else {
1795  return -1;
1796  }
1797 }
1798 
1799 contentCategory ContentType::category() const {
1800  return d_func()->category;
1801 }
1802 
1803 void ContentType::setCategory(contentCategory c) {
1804  Q_D(ContentType);
1805  d->category = c;
1806 }
1807 
1808 void ContentType::setPartialParams(int total, int number) {
1809  setParameter(QStringLiteral("number"), QString::number(number));
1810  setParameter(QStringLiteral("total"), QString::number(total));
1811 }
1812 
1813 bool ContentType::parse(const char *&scursor, const char *const send,
1814  bool isCRLF) {
1815  Q_D(ContentType);
1816  // content-type: type "/" subtype *(";" parameter)
1817  clear();
1818  eatCFWS(scursor, send, isCRLF);
1819  if (scursor == send) {
1820  return false; // empty header
1821  }
1822 
1823  // type
1824  QPair<const char *, int> maybeMimeType;
1825  if (!parseToken(scursor, send, maybeMimeType, ParseTokenNoFlag)) {
1826  return false;
1827  }
1828  // subtype
1829  eatCFWS(scursor, send, isCRLF);
1830  if (scursor == send || *scursor != '/') {
1831  return false;
1832  }
1833  scursor++;
1834  eatCFWS(scursor, send, isCRLF);
1835  if (scursor == send) {
1836  return false;
1837  }
1838  QPair<const char *, int> maybeSubType;
1839  if (!parseToken(scursor, send, maybeSubType, ParseTokenNoFlag)) {
1840  return false;
1841  }
1842 
1843  d->mimeType.reserve(maybeMimeType.second + maybeSubType.second + 1);
1844  d->mimeType = QByteArray(maybeMimeType.first, maybeMimeType.second).toLower()
1845  + '/' + QByteArray(maybeSubType.first, maybeSubType.second).toLower();
1846 
1847  // parameter list
1848  eatCFWS(scursor, send, isCRLF);
1849  if (scursor == send) {
1850  goto success; // no parameters
1851  }
1852  if (*scursor != ';') {
1853  return false;
1854  }
1855  scursor++;
1856 
1857  if (!Parametrized::parse(scursor, send, isCRLF)) {
1858  return false;
1859  }
1860 
1861  // adjust category
1862 success:
1863  if (isMultipart()) {
1864  d->category = CCcontainer;
1865  } else {
1866  d->category = CCsingle;
1867  }
1868  return true;
1869 }
1870 
1871 //-----</Content-Type>-------------------------
1872 
1873 //-----<ContentID>----------------------
1874 
1875 kmime_mk_trivial_ctor_with_name_and_dptr(ContentID, SingleIdent, Content-ID)
1876 kmime_mk_dptr_ctor(ContentID, SingleIdent)
1877 
1878 bool ContentID::parse(const char *&scursor, const char *const send, bool isCRLF) {
1879  Q_D(ContentID);
1880  // Content-id := "<" contentid ">"
1881  // contentid := now whitespaces
1882 
1883  const char *origscursor = scursor;
1884  if (!SingleIdent::parse(scursor, send, isCRLF)) {
1885  scursor = origscursor;
1886  d->msgIdList.clear();
1887  d->cachedIdentifier.clear();
1888 
1889  while (scursor != send) {
1890  eatCFWS(scursor, send, isCRLF);
1891  // empty entry ending the list: OK.
1892  if (scursor == send) {
1893  return true;
1894  }
1895  // empty entry: ignore.
1896  if (*scursor == ',') {
1897  scursor++;
1898  continue;
1899  }
1900 
1901  AddrSpec maybeContentId;
1902  // Almost parseAngleAddr
1903  if (scursor == send || *scursor != '<') {
1904  return false;
1905  }
1906  scursor++; // eat '<'
1907 
1908  eatCFWS(scursor, send, isCRLF);
1909  if (scursor == send) {
1910  return false;
1911  }
1912 
1913  // Save chars until '>''
1914  QByteArray result;
1915  if (!parseDotAtom(scursor, send, result, false)) {
1916  return false;
1917  }
1918 
1919  eatCFWS(scursor, send, isCRLF);
1920  if (scursor == send || *scursor != '>') {
1921  return false;
1922  }
1923  scursor++;
1924  // /Almost parseAngleAddr
1925 
1926  maybeContentId.localPart = QString::fromLatin1(result); // FIXME: just use QByteArray instead of AddrSpec in msgIdList?
1927  d->msgIdList.append(maybeContentId);
1928 
1929  eatCFWS(scursor, send, isCRLF);
1930  // header end ending the list: OK.
1931  if (scursor == send) {
1932  return true;
1933  }
1934  // regular item separator: eat it.
1935  if (*scursor == ',') {
1936  scursor++;
1937  }
1938  }
1939  return true;
1940  } else {
1941  return true;
1942  }
1943 }
1944 
1945 //-----</ContentID>----------------------
1946 
1947 //-----<ContentTransferEncoding>----------------------------
1948 
1949 //@cond PRIVATE
1950 kmime_mk_trivial_ctor_with_name_and_dptr(ContentTransferEncoding,
1951  Generics::Token, Content-Transfer-Encoding)
1952 //@endcond
1953 
1954 typedef struct {
1955  const char *s;
1956  int e;
1957 } encTableType;
1958 
1959 static const encTableType encTable[] = {
1960  { "7Bit", CE7Bit },
1961  { "8Bit", CE8Bit },
1962  { "quoted-printable", CEquPr },
1963  { "base64", CEbase64 },
1964  { "x-uuencode", CEuuenc },
1965  { "binary", CEbinary },
1966  { nullptr, 0}
1967 };
1968 
1971  d->decoded = true;
1972  d->cte = CE7Bit;
1973  Token::clear();
1974 }
1975 
1977  return d_func()->cte;
1978 }
1979 
1982  d->cte = e;
1983 
1984  for (int i = 0; encTable[i].s != nullptr; ++i) {
1985  if (d->cte == encTable[i].e) {
1986  setToken(encTable[i].s);
1987  break;
1988  }
1989  }
1990 }
1991 
1993  return d_func()->decoded;
1994 }
1995 
1998  d->decoded = decoded;
1999 }
2000 
2003  return d->decoded && (d->cte == CEquPr || d->cte == CEbase64);
2004 }
2005 
2006 bool ContentTransferEncoding::parse(const char *&scursor,
2007  const char *const send, bool isCRLF) {
2009  clear();
2010  if (!Token::parse(scursor, send, isCRLF)) {
2011  return false;
2012  }
2013 
2014  // TODO: error handling in case of an unknown encoding?
2015  for (int i = 0; encTable[i].s != nullptr; ++i) {
2016  if (qstricmp(token().constData(), encTable[i].s) == 0) {
2017  d->cte = (contentEncoding)encTable[i].e;
2018  break;
2019  }
2020  }
2021  d->decoded = (d->cte == CE7Bit || d->cte == CE8Bit);
2022  return true;
2023 }
2024 
2025 //-----</ContentTransferEncoding>---------------------------
2026 
2027 //-----<ContentDisposition>--------------------------
2028 
2029 //@cond PRIVATE
2030 kmime_mk_trivial_ctor_with_name_and_dptr(ContentDisposition,
2031  Generics::Parametrized, Content-Disposition)
2032 //@endcond
2033 
2034 QByteArray ContentDisposition::as7BitString(bool withHeaderType) const {
2035  if (isEmpty()) {
2036  return {};
2037  }
2038 
2039  QByteArray rv;
2040  if (withHeaderType) {
2041  rv += typeIntro();
2042  }
2043 
2044  if (d_func()->disposition == CDattachment) {
2045  rv += "attachment";
2046  } else if (d_func()->disposition == CDinline) {
2047  rv += "inline";
2048  } else {
2049  return {};
2050  }
2051 
2052  if (!Parametrized::isEmpty()) {
2053  rv += "; " + Parametrized::as7BitString(false);
2054  }
2055 
2056  return rv;
2057 }
2058 
2060  return d_func()->disposition == CDInvalid;
2061 }
2062 
2065  d->disposition = CDInvalid;
2066  Parametrized::clear();
2067 }
2068 
2070  return d_func()->disposition;
2071 }
2072 
2075  d->disposition = disp;
2076 }
2077 
2079  return parameter(QStringLiteral("filename"));
2080 }
2081 
2083  setParameter(QStringLiteral("filename"), filename);
2084 }
2085 
2086 bool ContentDisposition::parse(const char *&scursor, const char *const send,
2087  bool isCRLF) {
2089  clear();
2090 
2091  // token
2092  QByteArray token;
2093  eatCFWS(scursor, send, isCRLF);
2094  if (scursor == send) {
2095  return false;
2096  }
2097 
2098  QPair<const char *, int> maybeToken;
2099  if (!parseToken(scursor, send, maybeToken, ParseTokenNoFlag)) {
2100  return false;
2101  }
2102 
2103  token = QByteArray(maybeToken.first, maybeToken.second).toLower();
2104  if (token == "inline") {
2105  d->disposition = CDinline;
2106  } else if (token == "attachment") {
2107  d->disposition = CDattachment;
2108  } else {
2109  return false;
2110  }
2111 
2112  // parameter list
2113  eatCFWS(scursor, send, isCRLF);
2114  if (scursor == send) {
2115  return true; // no parameters
2116  }
2117 
2118  if (*scursor != ';') {
2119  return false;
2120  }
2121  scursor++;
2122 
2123  return Parametrized::parse(scursor, send, isCRLF);
2124 }
2125 
2126 //-----</ContentDisposition>-------------------------
2127 
2128 //@cond PRIVATE
2129 kmime_mk_trivial_ctor_with_name(Subject, Generics::Unstructured, Subject)
2130 //@endcond
2131 
2132 Base *createHeader(const QByteArray & type) {
2133  return HeaderFactory::createHeader(type);
2134 }
2135 
2136 //@cond PRIVATE
2137 kmime_mk_trivial_ctor_with_name(ContentDescription,
2138  Generics::Unstructured, Content-Description)
2139 kmime_mk_trivial_ctor_with_name(ContentLocation,
2140  Generics::Unstructured, Content-Location)
2141 kmime_mk_trivial_ctor_with_name(From, Generics::MailboxList, From)
2142 kmime_mk_trivial_ctor_with_name(Sender, Generics::SingleMailbox, Sender)
2143 kmime_mk_trivial_ctor_with_name(To, Generics::AddressList, To)
2144 kmime_mk_trivial_ctor_with_name(Cc, Generics::AddressList, Cc)
2145 kmime_mk_trivial_ctor_with_name(Bcc, Generics::AddressList, Bcc)
2146 kmime_mk_trivial_ctor_with_name(ReplyTo, Generics::AddressList, Reply-To)
2147 kmime_mk_trivial_ctor_with_name(Keywords, Generics::PhraseList, Keywords)
2148 kmime_mk_trivial_ctor_with_name(MIMEVersion, Generics::DotAtom, MIME-Version)
2149 kmime_mk_trivial_ctor_with_name(Supersedes, Generics::SingleIdent, Supersedes)
2150 kmime_mk_trivial_ctor_with_name(InReplyTo, Generics::Ident, In-Reply-To)
2151 kmime_mk_trivial_ctor_with_name(References, Generics::Ident, References)
2152 kmime_mk_trivial_ctor_with_name(Organization, Generics::Unstructured, Organization)
2153 kmime_mk_trivial_ctor_with_name(UserAgent, Generics::Unstructured, User-Agent)
2154 //@endcond
2155 
2156 } // namespace Headers
2157 
2158 } // 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.
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.
QByteArray encodeRFC2047String(const QString &src, const QByteArray &charset)
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-2023 The KDE developers.
Generated on Tue Feb 7 2023 03:58:49 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.