KMime

kmime_content.h
Go to the documentation of this file.
1/*
2 kmime_content.h
3
4 KMime, the KDE Internet mail/usenet news message library.
5 SPDX-FileCopyrightText: 2001 the KMime authors.
6 See file AUTHORS for details
7 SPDX-FileCopyrightText: 2006 Volker Krause <vkrause@kde.org>
8 SPDX-FileCopyrightText: 2009 Constantin Berzan <exit3219@gmail.com>
9
10 SPDX-License-Identifier: LGPL-2.0-or-later
11*/
12/**
13 @file
14 This file is part of the API for handling @ref MIME data and
15 defines the Content class.
16
17 @brief
18 Defines the Content class.
19
20 @authors the KMime authors (see AUTHORS file),
21 Volker Krause <vkrause@kde.org>
22
23TODO: possible glossary terms:
24 content
25 encoding, transfer type, disposition, description
26 header
27 body
28 attachment
29 charset
30 article
31 string representation
32 broken-down object representation
33*/
34
35#pragma once
36
37#include "kmime_export.h"
38#include "kmime_contentindex.h"
39#include "kmime_util.h"
40#include "kmime_headers.h"
41
42#include <QByteArray>
43#include <QList>
44#include <QMetaType>
45#include <QSharedPointer>
46
47namespace KMime
48{
49
50class ContentPrivate;
51class Message;
52
53/**
54 @brief
55 A class that encapsulates @ref MIME encoded Content.
56
57 A Content object holds two representations of a content:
58 - the string representation: This is the content encoded as a string ready
59 for transport. Accessible through the encodedContent() method.
60 - the broken-down representation: This is the tree of objects (headers,
61 sub-Contents and (if present) the encapsulated message) that this Content is made of.
62 Accessible through methods like header(), contents() and bodyAsMessage().
63
64 The parse() function updates the broken-down representation of the Content
65 from its string representation. Calling it is necessary to access the
66 headers, sub-Contents or the encapsulated message of this Content.
67
68 The assemble() function updates the string representation of the Content
69 from its broken-down representation. Calling it is necessary for
70 encodedContent() to reflect any changes made to the broken-down representation of the Content.
71
72 There are two basic types of a Content:
73 - A leaf Content: This is a content that is neither a multipart content nor an encapsulated
74 message. Because of this, it will not have any children, it has no sub-contents
75 and is therefore a leaf content.
76 Only leaf contents have a body that is not empty, i.e. functions that operate
77 on the body, such as body(), size() and decodedContent(), will work only on
78 leaf contents.
79 - A non-leaf Content: This is a content that itself doesn't have any body, but that does have
80 sub-contents.
81 This is the case for contents that are of mimetype multipart/ or of mimetype
82 message/rfc822. In case of a multipart content, contents() will return the
83 multipart child contents. In case of an encapsulated message, the message
84 can be accessed with bodyAsMessage(), and contents() will have one entry
85 that is the message as well.
86 On a non-leaf content, body() will have an empty return value and other
87 functions working on the body will not work.
88 A call to parse() is required before the child multipart contents or the
89 encapsulated message is created.
90*/
91/*
92 KDE5:
93 * Do not convert singlepart <-> multipart automatically.
94 * A bunch of methods probably don't need to be virtual (since they're not needed
95 in either Message or NewsArticle).
96*/
97class KMIME_EXPORT Content
98{
99public:
100
101 /**
102 Describes a list of Content objects.
103 */
105
106 /**
107 Creates an empty Content object with a specified parent.
108 @param parent the parent Content object
109 @since 4.3
110 */
111 explicit Content(Content *parent = nullptr);
112
113 /**
114 Destroys this Content object.
115 */
116 virtual ~Content();
117
118 /**
119 Returns true if this Content object is not empty.
120 */
121 [[nodiscard]] bool hasContent() const;
122
123 /**
124 Sets the Content to the given raw data, containing the Content head and
125 body separated by two linefeeds.
126
127 This method operates on the string representation of the Content. Call
128 parse() if you want to access individual headers, sub-Contents or the
129 encapsulated message.
130
131 @note The passed data must not contain any CRLF sequences, only LF.
132 Use CRLFtoLF for conversion before passing in the data.
133
134 @param s is a QByteArray containing the raw Content data.
135 */
136 void setContent(const QByteArray &s);
137
138 /**
139 * Parses the Content.
140 *
141 * This means the broken-down object representation of the Content is
142 * updated from the string representation of the Content.
143 *
144 * Call this if you want to access or change headers, sub-Contents or the
145 * encapsulated message.
146 *
147 * @note Calling parse() twice will not work for multipart contents or for
148 * contents of which the body is an encapsulated message. The reason is that
149 * the first parse() will delete the body, so there is no body to work on for
150 * the second call of parse().
151 *
152 * @note Calling this will reset the message returned by bodyAsMessage(), as
153 * the message is re-parsed as well.
154 * Also, all old sub-contents will be deleted, so any old Content
155 * pointer will become invalid.
156 */
157 void parse();
158
159 /**
160 Returns whether this Content is frozen.
161 A frozen content is immutable, i.e. calling assemble() will never modify
162 its head or body, and encodedContent() will return the same data before
163 and after parsing.
164
165 @since 4.4.
166 @see setFrozen().
167 */
168 [[nodiscard]] bool isFrozen() const;
169
170 /**
171 Freezes this Content if @p frozen is true; otherwise unfreezes it.
172 @param frozen freeze content if @c true, otherwise unfreeze
173 @since 4.4
174 @see isFrozen().
175 */
176 void setFrozen(bool frozen = true);
177
178 /**
179 Generates the MIME content.
180 This means the string representation of this Content is updated from the
181 broken-down object representation.
182 Call this if you have made changes to the content, and want
183 encodedContent() to reflect those changes.
184
185 @note assemble() has no effect if the Content isFrozen(). You may want
186 to freeze, for instance, signed sub-Contents, to make sure they are kept
187 unmodified.
188
189 @note If this content is an encapsulated message, i.e. bodyIsMessage()
190 returns true, then calling assemble() will also assemble the message
191 returned by bodyAsMessage().
192
193 @warning assemble() may change the order of the headers, and other
194 details such as where folding occurs. This may break things like
195 signature verification, so you should *ONLY* call assemble() when you
196 have actually modified the content.
197 */
198 void assemble();
199
200 /**
201 Clears the content, deleting all headers and sub-Contents.
202 */
203 void clear();
204
205 /**
206 Removes all sub-Contents from this content. Deletes them if @p del is true.
207 This is different from calling removeContent() on each sub-Content, because
208 removeContent() will convert this to a single-part Content if only one
209 sub-Content is left. Calling clearContents() does NOT make this Content
210 single-part.
211
212 @param del Whether to delete the sub-Contents.
213 @see removeContent()
214 @since 4.4
215 */
216 void clearContents(bool del = true);
217
218 /**
219 Returns the Content header raw data.
220
221 @see setHead().
222 */
223 [[nodiscard]] QByteArray head() const;
224
225 /**
226 Sets the Content header raw data.
227
228 This method operates on the string representation of the Content. Call
229 parse() if you want to access individual headers.
230
231 @param head is a QByteArray containing the header data.
232
233 @see head().
234 */
235 void setHead(const QByteArray &head);
236
237 /**
238 * Returns all headers.
239 * @since 5.7
240 */
241 [[nodiscard]] QList<Headers::Base *> headers() const;
242
243 /**
244 Returns the first header of type @p type, if it exists. Otherwise returns
245 0. Note that the returned header may be empty.
246 @param type the header type to find
247 @since 4.2
248 */
249 Headers::Base *headerByType(const char *type) const;
250
251 /**
252 Returns the first header of type T, if it exists.
253 If the header does not exist and @p create is true, creates an empty header
254 and returns it. Otherwise returns 0.
255 Note that the returned header may be empty.
256 @param create Whether to create the header if it does not exist.
257 @since 4.4.
258
259 KDE5: BIC: FIXME: Why is the default argument false here? That is
260 inconsistent with the methods in KMime::Message!
261 */
262 template <typename T> T *header(bool create = false);
263
264 /**
265 Returns all @p type headers in the Content.
266 Take care that this result is not cached, so could be slow.
267 @param type the header type to find
268 @since 4.2
269 */
270 [[nodiscard]] QList<Headers::Base *> headersByType(const char *type) const;
271
272 /**
273 Sets the specified header to this Content.
274 Any previous header of the same type is removed.
275 If you need multiple headers of the same type, use appendHeader() or
276 prependHeader().
277
278 @param h The header to set.
279 @see appendHeader()
280 @see removeHeader()
281 @since 4.4
282 */
283 void setHeader(Headers::Base *h);
284
285 /**
286 Appends the specified header to the headers of this Content.
287 @param h The header to append.
288 @since 4.4
289 */
290 void appendHeader(Headers::Base *h);
291
292 /**
293 Searches for the first header of type @p type, and deletes it, removing
294 it from this Content.
295 @param type The type of the header to look for.
296 @return true if a header was found and removed.
297 */
298 bool removeHeader(const char *type);
299
300 /**
301 Searches for the first header of type @p T, and deletes it, removing
302 it from this Content.
303 @tparam T The type of the header to look for.
304 @return true if a header was found and removed.
305 */
306 template <typename T> bool removeHeader();
307
308 /**
309 @return true if this Content has a header of type @p type.
310 @param type The type of the header to look for.
311 */
312 // TODO probably provide hasHeader<T>() too.
313 [[nodiscard]] bool hasHeader(const char *type) const;
314
315 /**
316 Returns the Content-Type header.
317
318 @param create If true, create the header if it doesn't exist yet.
319 */
320 Headers::ContentType *contentType(bool create = true);
321
322 /**
323 Returns the Content-Transfer-Encoding header.
324
325 @param create If true, create the header if it doesn't exist yet.
326 */
328
329 /**
330 Returns the Content-Disposition header.
331
332 @param create If true, create the header if it doesn't exist yet.
333 */
335
336 /**
337 Returns the Content-Description header.
338
339 @param create If true, create the header if it doesn't exist yet.
340 */
342
343 /**
344 Returns the Content-Location header.
345
346 @param create If true, create the header if it doesn't exist yet.
347 @since 4.2
348 */
350
351 /**
352 Returns the Content-ID header.
353 @param create if true, create the header if it does not exist yet.
354 @since 4.4
355 */
356 Headers::ContentID *contentID(bool create = true);
357
358 /**
359 Returns the size of the Content body after encoding.
360 (If the encoding is quoted-printable, this is only an approximate size.)
361 This will return 0 for multipart contents or for encapsulated messages.
362 */
363 [[nodiscard]] int size();
364
365 /**
366 Returns the size of this Content and all sub-Contents.
367 */
368 [[nodiscard]] int storageSize() const;
369
370 /**
371 Returns the Content body raw data.
372
373 Note that this will be empty for multipart contents or for encapsulated
374 messages, after parse() has been called.
375
376 @see setBody().
377 */
378 [[nodiscard]] QByteArray body() const;
379
380 /**
381 Sets the Content body raw data.
382
383 This method operates on the string representation of the Content. Call
384 parse() if you want to access individual sub-Contents or the encapsulated
385 message.
386
387 @param body is a QByteArray containing the body data.
388
389 @see body().
390 */
391 void setBody(const QByteArray &body);
392
393 /**
394 Returns the MIME preamble.
395
396 @return a QByteArray containing the MIME preamble.
397
398 @since 4.9
399 */
400 [[nodiscard]] QByteArray preamble() const;
401
402 /**
403 Sets the MIME preamble.
404
405 @param preamble a QByteArray containing what will be used as the
406 MIME preamble.
407
408 @since 4.9
409 */
410
411 void setPreamble(const QByteArray &preamble);
412
413 /**
414 Returns the MIME preamble.
415
416 @return a QByteArray containing the MIME epilogue.
417
418 @since 4.9
419 */
420 [[nodiscard]] QByteArray epilogue() const;
421
422 /**
423 Sets the MIME preamble.
424
425 @param epilogue a QByteArray containing what will be used as the
426 MIME epilogue.
427
428 @since 4.9
429 */
430 void setEpilogue(const QByteArray &epilogue);
431
432 /**
433 Returns a QByteArray containing the encoded Content, including the
434 Content header and all sub-Contents.
435
436 If you make changes to the broken-down representation of the message, be
437 sure to first call assemble() before calling encodedContent(), otherwise
438 the result will not be up-to-date.
439
440 If this content is an encapsulated message, i.e. bodyIsMessage() returns
441 true, then encodedContent() will use the message returned by bodyAsMessage()
442 as the body of the result, calling encodedContent() on the message.
443
444 @param useCrLf If true, use @ref CRLF instead of @ref LF for linefeeds.
445 */
446 [[nodiscard]] QByteArray encodedContent(bool useCrLf = false);
447
448 /**
449 * Like encodedContent(), with the difference that only the body will be
450 * returned, i.e. the headers are excluded.
451 *
452 * @since 4.6
453 */
454 [[nodiscard]] QByteArray encodedBody();
455
456 /**
457 * Returns the decoded Content body.
458 *
459 * Note that this will be empty for multipart contents or for encapsulated
460 * messages, after parse() has been called.
461 */
462 // TODO: KDE5: BIC: Rename this to decodedBody(), since only the body is
463 // returned. In contrast, setContent() sets the head and the body! Also, try
464 // to make this const.
465 [[nodiscard]] QByteArray decodedContent();
466
467 /**
468 Returns the decoded text. Additional to decodedContent(), this also
469 applies charset decoding. If this is not a text Content, decodedText()
470 returns an empty QString.
471
472 @param trimText If true, then the decoded text will have all trailing
473 whitespace removed.
474 @param removeTrailingNewlines If true, then the decoded text will have
475 all consecutive trailing newlines removed.
476
477 The last trailing new line of the decoded text is always removed.
478
479 */
480 // TODO: KDE5: BIC: Convert to enums. Also, what if trimText = true but
481 // removeTrailingNewlines
482 // is false?
483 [[nodiscard]] QString decodedText(bool trimText = false,
484 bool removeTrailingNewlines = false);
485
486 /**
487 Sets the Content body to the given string using charset of the content type.
488
489 If the charset can not be found, the system charset is taken and the content
490 type header is changed to that charset. The charset of the content type
491 header should be set to a charset that can encode the given string before
492 calling this method.
493
494 This method does not set the content transfer encoding automatically, it
495 needs to be set to a suitable value that can encode the given string before
496 calling this method.
497
498 This method only makes sense for single-part contents, do not try to pass a
499 multipart body or an encapsulated message here, that wouldn't work.
500
501 @param s Unicode-encoded string.
502 */
503 void fromUnicodeString(const QString &s);
504
505 /**
506 Returns the first Content with mimetype text/.
507 */
508 Content *textContent();
509
510 /**
511 * Returns all attachments below this node, recursively.
512 * This does not include crypto parts, nodes of alternative or related
513 * multipart nodes, or the primary body part (see textContent()).
514 * @see KMime::isAttachment(), KMime::hasAttachment()
515 */
516 [[nodiscard]] QList<Content *> attachments();
517
518 /**
519 * For multipart contents, this will return a list of all multipart child
520 * contents. For contents that are of mimetype message/rfc822, this will
521 * return a list with one entry, and that entry is the encapsulated message,
522 * as it would be returned by bodyAsMessage().
523 */
524 [[nodiscard]] QList<Content *> contents() const;
525
526 /**
527 Adds a new sub-Content. If the sub-Content is already part of another
528 Content object, it is removed from there and its parent is updated.
529 If the current Content object is single-part, it is converted to
530 multipart/mixed first.
531
532 @warning If the single-part to multipart conversion happens, all
533 pointers you may have into this object (such as headers) will become
534 invalid!
535
536 @param content The new sub-Content.
537 @param prepend If true, prepend to the Content list; otherwise append.
538 to the Content list.
539
540 @see removeContent().
541 */
542 // KDE5: Do not convert single-part->multipart automatically.
543 [[deprecated("use append/prependContent instead")]] void addContent(Content *content, bool prepend = false);
544
545 /**
546 Appends a new sub-Content. If the sub-Content is already part of another
547 Content object, it is removed from there and its parent is updated.
548
549 @param content The new sub-Content.
550 @see prependContent()
551 @see takeContent()
552 @since 6.0
553 */
554 void appendContent(Content *content);
555 /**
556 Prepends a new sub-Content. If the sub-Content is already part of another
557 Content object, it is removed from there and its parent is updated.
558
559 @param content The new sub-Content.
560 @see appendContent()
561 @see takeContent()
562 @since 6.0
563 */
564 void prependContent(Content *content);
565
566 void replaceContent(Content *oldContent, Content *newContent);
567 /**
568 Removes the given sub-Content. If only one sub-Content is left, the
569 current Content object is converted into a single-part Content.
570
571 @warning If the multipart to single-part conversion happens, the head
572 and body of the single remaining sub-Content are copied over, and the
573 sub-Content is deleted. All pointers to it or into it (such as headers)
574 will become invalid!
575
576 @param content The Content to remove.
577 @param del If true, delete the removed Content object. Otherwise set its
578 parent to 0.
579
580 @see addContent().
581 @see clearContents().
582 */
583 // KDE5: Do not convert multipart->single-part automatically.
584 [[deprecated("use takeContent instead")]] void removeContent(Content *content, bool del = false);
585 /**
586 Removes the given sub-Content and, if that actually was a sub-content
587 returns that.
588
589 @param content The Content to remove. It is not deleted, ownership goes
590 back to the caller.
591
592 @see appendContent()
593 @see prependContent()
594 @see clearContents()
595 @since 6.0
596 */
597 Content *takeContent(Content *content);
598
599 /**
600 Changes the encoding of this Content to @p e. If the Content is binary,
601 this actually re-encodes the data to use the new encoding.
602
603 @param e The new encoding to use.
604 */
605 void changeEncoding(Headers::contentEncoding e);
606
607 /**
608 Returns the charset that is used to decode RFC2047 strings in all headers
609 and to decode the body if the charset is not declared explicitly. It is also
610 used as the charset when encoding RFC2047 strings in headers.
611 */
612 // TODO: Split this up into a charset for encoding and one for decoding, and
613 // make the one for
614 // encoding UTF-8 by default.
615 static QByteArray defaultCharset();
616
617 /**
618 Returns the Content specified by the given index.
619 If the index does not point to a Content, 0 is returned. If the index
620 is invalid (empty), this Content is returned.
621
622 @param index The Content index.
623 */
624 Content *content(const ContentIndex &index) const;
625
626 /**
627 Returns the ContentIndex for the given Content, or an invalid index
628 if the Content is not found within the hierarchy.
629 @param content the Content object to search.
630 */
631 [[nodiscard]] ContentIndex indexForContent(Content *content) const;
632
633 /**
634 Returns true if this is the top-level node in the MIME tree. The top-level
635 node is always a Message or NewsArticle. However, a node can be a Message
636 without being a top-level node when it is an encapsulated message.
637 */
638 [[nodiscard]] bool isTopLevel() const;
639
640 /**
641 * Sets a new parent to the Content and add to its contents list. If it
642 * already had a parent, it is removed from the old parents contents list.
643 * @param parent the new parent
644 * @since 4.3
645 */
646 void setParent(Content *parent);
647
648 /**
649 * Returns the parent content object, or 0 if the content doesn't have a
650 * parent.
651 * @since 4.3
652 */
653 Content *parent() const;
654
655 /**
656 * Returns the toplevel content object, 0 if there is no such object.
657 * @since 4.3
658 */
659 Content *topLevel() const;
660
661 /**
662 * Returns the index of this Content based on the topLevel() object.
663 * @since 4.3
664 */
665 [[nodiscard]] ContentIndex index() const;
666
667 /**
668 * @return true if this content is an encapsulated message, i.e. if it has the
669 * mimetype message/rfc822.
670 *
671 * @since 4.5
672 */
673 // AK_REVIEW: move to MessageViewer/ObjectTreeParser
674 [[nodiscard]] bool bodyIsMessage() const;
675
676 /**
677 * If this content is an encapsulated message, in which case bodyIsMessage()
678 * will return true, the message represented by the body of this content will
679 * be returned. The returned message is already fully parsed. Calling this
680 * method is the aquivalent of calling contents().first() and casting the
681 * result to a KMime::Message*. bodyAsMessage() has the advantage that it will
682 * return a shared pointer that will not be destroyed when the container
683 * message is destroyed or re-parsed.
684 *
685 * The message that is returned here is created when calling parse(), so make
686 * sure to call parse() first. Since each parse() creates a new message
687 * object, a different message object will be returned each time you call
688 * parse().
689 *
690 * If you make changes to the returned message, you need to call assemble() on
691 * this content or on the message if you want that encodedContent() reflects
692 * these changes. This also means that calling assemble() on this content will
693 * assemble the returned message.
694 *
695 * @since 4.5
696 */
697 // AK_REVIEW: move to MessageViewer/ObjectTreeParser
698 [[nodiscard]] QSharedPointer<Message> bodyAsMessage() const;
699
700protected:
701 /**
702 Reimplement this method if you need to assemble additional headers in a
703 derived class. Don't forget to call the implementation of the base class.
704 @return The raw, assembled headers.
705 */
706 virtual QByteArray assembleHeaders();
707
708 //@cond PRIVATE
709 ContentPrivate *d_ptr;
710 //@endcond
711
712private:
713 Q_DECLARE_PRIVATE(Content)
714 Q_DISABLE_COPY(Content)
715};
716
717template <typename T> T *Content::header(bool create)
718{
719 Headers::Base *h = headerByType(T::staticType());
720 if (h) {
721 // Make sure the header is actually of the right type.
722 Q_ASSERT(dynamic_cast<T *>(h));
723 } else if (create) {
724 h = new T;
725 appendHeader(h); // we already know the header doesn't exist yet
726 }
727 return static_cast<T *>(h);
728}
729
730template <typename T> bool Content::removeHeader()
731{
732 return removeHeader(T::staticType());
733}
734
735} // namespace KMime
736
737Q_DECLARE_METATYPE(KMime::Content*)
738
A class to uniquely identify message parts (Content) in a hierarchy.
A class that encapsulates MIME encoded Content.
Headers::ContentDescription * contentDescription(bool create=true)
Returns the Content-Description header.
bool removeHeader()
Searches for the first header of type T, and deletes it, removing it from this Content.
Headers::ContentType * contentType(bool create=true)
Returns the Content-Type header.
Headers::ContentTransferEncoding * contentTransferEncoding(bool create=true)
Returns the Content-Transfer-Encoding header.
Headers::ContentDisposition * contentDisposition(bool create=true)
Returns the Content-Disposition header.
QList< KMime::Content * > List
Describes a list of Content objects.
T * header(bool create=false)
Returns the first header of type T, if it exists.
Headers::ContentID * contentID(bool create=true)
Returns the Content-ID header.
Headers::Base * headerByType(const char *type) const
Returns the first header of type type, if it exists.
Headers::ContentLocation * contentLocation(bool create=true)
Returns the Content-Location header.
void appendHeader(Headers::Base *h)
Appends the specified header to the headers of this Content.
Baseclass of all header-classes.
Represents a "Content-Description" header.
Represents a "Content-Disposition" header.
Represents a "Content-ID" header.
Represents a "Content-Location" header.
Represents a "Content-Transfer-Encoding" header.
Represents a "Content-Type" header.
This file is part of the API for handling MIME data and defines the ContentIndex class.
This file is part of the API for handling MIME data and defines the various header classes:
contentEncoding
Various possible values for the "Content-Transfer-Encoding" header.
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:20:12 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.