comparison 3rdparty/vmime/doc/book/basics.tex @ 0:a4671277546c tip

created the repository for the thymian project
author ferencd
date Tue, 17 Aug 2021 11:19:54 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:a4671277546c
1 \chapter{Basics}
2
3 % ============================================================================
4 \section{Reference counting}
5
6 \subsection{Introduction} % --------------------------------------------------
7
8 Since version 0.7.2cvs, VMime use smart pointers to simplify memory
9 management. Smart pointers rely on
10 RAII\footnote{Ressource Allocation is Initialisation} so that we do not need
11 to bother with deleting an object (freeing memory) when it is not used
12 anymore.
13
14 There are two possibilities for owning a reference to an object. We can own a
15 strong reference to an object: as long as we keep this reference, the object
16 is not destroyed. Or we can own a weak reference to the object: the object can
17 be destroyed if nobody owns a strong reference to it, in which case the weak
18 reference becomes invalid.
19
20 An object is destroyed as soon as the last strong reference to it is released.
21 At the same tine, all weak references (if any) are automatically set to point
22 to \vnull.
23
24 In VMime, these two types of references are known as {\vcode vmime::shared\_ptr}
25 and {\vcode vmime::weak\_ptr}, respectively.
26
27 \vnote{since November 2013, we switched from an old, intrusive implementation
28 of smart pointers to a more standard one: either Boost {\vcode shared\_ptr<>}
29 implementation or standard C++ one if we are compiling in C++11. Here are the
30 changes:
31
32 {\vcode vmime::ref <>} is replaced with {\vcode vmime::shared\_ptr <>}
33
34 {\vcode vmime::weak\_ref <>} is replaced with {\vcode vmime::weak\_ptr <>}
35
36 {\vcode vmime::create <>} is replaced with {\vcode vmime::make\_shared <>}
37 }
38
39 \subsection{Instanciating reference-counted objects} % -----------------------
40
41 In VMime, all objects that support reference counting inherit from the
42 {\vcode vmime::object} class, which is responsible for
43 incrementing/decrementing the counter and managing the object's life cycle.
44 If you want to create a smart pointer to a new object instance, you should
45 use the function {\vcode vmime::make\_shared} instead of the {\vcode new}
46 operator.
47
48 \begin{lstlisting}[caption={Smarts pointers and creating objects}]
49 class myObject : public vmime::object
50 {
51 public:
52
53 myObject(const vmime::string& name)
54 : m_name(name)
55 {
56 }
57
58 void sayHello()
59 {
60 std::cout << "Hello " << m_name << std::endl;
61 }
62
63 private:
64
65 vmime::string m_name;
66 };
67
68 int main()
69 {
70 vmime::shared_ptr <myObject> obj =
71 vmime::make_shared <myObject>("world");
72
73 obj->sayHello();
74
75 return 0;
76
77 } // Here, 'obj' gets automatically destroyed
78 \end{lstlisting}
79
80 \subsection{Using smart pointers} % ------------------------------------------
81
82 Smart pointers are copiable, assignable and comparable. You can use them like
83 you would use normal ("raw") C++ pointers (eg. you can write
84 \lstinline{!ptr, ptr != NULL, ptr->method(), *ptr}...).
85
86 Type safety is also guaranteed, and you can type cast smart pointers using
87 the {\vcode static\_cast()}, {\vcode dynamic\_cast()} and {\vcode const\_cast()}
88 equivalents on {\vcode vmime::shared\_ptr} and {\vcode vmime::weak\_ptr} objects:
89
90 \begin{lstlisting}[caption={Casting smart pointers}]
91 class myBase : public vmime::object { }
92 class myObject : public myBase { }
93
94 vmime::shared_ptr <myObject> obj = vmime::make_shared <myObject>();
95
96 // Implicit downcast
97 vmime::shared_ptr <myBase> base = obj;
98
99 // Explicit upcast
100 vmime::shared_ptr <myObject> obj2 = vmime::dynamicCast <myObject>(base);
101 \end{lstlisting}
102
103 Weak references are used to resolve reference cycles (an object which refers
104 directly or indirectly to itself). The following example illustrates a
105 typical problem of reference counting:
106
107 \begin{lstlisting}
108 class parent : public vmime::object
109 {
110 public:
111
112 void createChild(vmime::shared_ptr <child> c)
113 {
114 m_child = c;
115 }
116
117 private:
118
119 vmime::shared_ptr <child> m_child;
120 };
121
122 class child : public vmime::object
123 {
124 public:
125
126 child(vmime::shared_ptr <parent> p)
127 : m_parent(p)
128 {
129 }
130
131 private:
132
133 vmime::shared_ptr <parent> m_parent;
134 };
135
136 int main()
137 {
138 vmime::shared_ptr <parent> p = vmime::make_shared <parent>();
139 vmime::shared_ptr <child> c = vmime::make_shared <child>();
140
141 p->setChild(c);
142 }
143 \end{lstlisting}
144
145 In this example, neither {\vcode p} nor {\vcode c} will be deleted when
146 exiting {\vcode main()}. That's because {\vcode p} indirectly points to itself
147 {\em via} {\vcode c}, and {\em vice versa}. The solution is to use a weak
148 reference to the parent:
149
150 \begin{lstlisting}
151 vmime::weak_ptr <parent> m_parent;
152 \end{lstlisting}
153
154 The decision to make the parent or the child a weak reference is purely
155 semantic, and it depends on the context and the relationships between the
156 objects. Note that when the parent is deleted, the {\vcode m\_parent} member
157 of the child points to \vnull.
158
159 More information about reference counting can be found on
160 Wikipedia\footnote{http://en.wikipedia.org/wiki/Reference\_counting}.
161
162 % ============================================================================
163 \section{Error handling}
164
165 In VMime, error handling is exclusively based on exceptions, there is no error
166 codes, or things like that.
167
168 VMime code may throw exceptions in many different situations: an unexpected
169 error occured, an operation is not supported, etc. You should catch them if
170 you want to report failures to the user. This is also useful when debugging
171 your program.
172
173 VMime exceptions support chaining: an exception can be encapsulated into
174 another exception to hide implementation details. The function
175 {\vcode exception::other()} returns the next exception in the chain,
176 or \vnull.
177
178 Following is an example code for catching VMime exceptions and writing error
179 messages to the console:
180
181 \begin{lstlisting}[caption={Catching VMime exceptions}]
182 std::ostream& operator<<(std::ostream& os, const vmime::exception& e)
183 {
184 os << "* vmime::exceptions::" << e.name() << std::endl;
185 os << " what = " << e.what() << std::endl;
186
187 // Recursively print all encapsuled exceptions
188 if (e.other() != NULL)
189 os << *e.other();
190
191 return os;
192 }
193
194 ...
195
196 try
197 {
198 // ...some call to VMime...
199 }
200 catch (vmime::exception& e)
201 {
202 std::cerr << e; // VMime exception
203 }
204 catch (std::exception& e)
205 {
206 std::cerr << e.what(); // standard exception
207 }
208 \end{lstlisting}
209
210 Read the source of {\vexample example6} if yo want to see a more complete
211 example of using VMime exceptions (such as getting more detailed information
212 by using specialized classes of {\vcode vmime::exception}).
213
214
215 % ============================================================================
216 \section{Basic objects}
217
218 \subsection{The {\vcode component} class} % ----------------------------------
219
220 In VMime, all the components of a message inherit from the same class
221 {\vcode component}. This includes the message itself (classes {\vcode message}
222 and {\vcode bodyPart}), the header, the header fields and the value of each
223 header field, the body and all the parts in the message.
224
225 The class component provide a common interface for parsing or generating all
226 these components (methods {\vcode parse()} and {\vcode generate()}). It also
227 provides additional functions to get some information about the parsing
228 process or the structure (methods {\vcode getParsedOffset()},
229 {\vcode getParsedLength()} and {\vcode getChildComponents()}).
230
231 VMime also provides a set of classes corresponding to the basic types found
232 in a message; for example a mailbox, a mailbox list, date/time information,
233 media type, etc. They all inherit from {\vcode component} too.
234
235 \subsection{Date and time} % -------------------------------------------------
236
237 Date and time are used in several places in VMime, particularly in header
238 fields (Date, Received, ...). VMime fully supports RFC-2822's date and time
239 specification. The object {\vcode vmime::datetime} is used to manipulate date
240 and time information, and to parse/generate it from/to RFC-2822 format.
241
242 The following code snippet show various manners of using the
243 {\vcode vmime::datetime} object:
244
245 \begin{lstlisting}[caption={Using {\vcode vmime::datetime} object}]
246 // Creating from string in RFC-2822 format
247 vmime::datetime d1("Sat, 08 Oct 2005 14:07:52 +0200");
248
249 // Creating from components
250 vmime::datetime d2(
251 /* date */ 2005, vmime::datetime::OCTOBER, 8,
252 /* time */ 14, 7, 52,
253 /* zone */ vmime::datetime::GMT2);
254
255 // Getting day of week
256 const int dow = d2.getWeekDay(); // 'dow' should be datetime::SATURDAY
257 \end{lstlisting}
258
259 \subsection{Media type} % ----------------------------------------------------
260
261 In MIME, the nature of the data contained in parts is identified using a
262 media type. A general type (eg. \emph{image}) and a sub-type (eg. \emph{jpeg})
263 are put together to form a media type (eg. \emph{image/jpeg}). This is also
264 called the MIME type.
265
266 There are a lot of media types officially registered, and vendor-specific
267 types are possible (they start with ``x-'', eg.
268 \emph{application/x-zip-compressed}).
269
270 In VMime, the object {\vcode vmime::mediaType} represents a media type. There
271 are also some constants for top-level types and sub-types in the
272 {\vcode vmime::mediaTypes} namespace. For example, you can instanciate a new
273 media type with:
274
275 \begin{lstlisting}
276 vmime::mediaType theType(
277 /* top-level type */ vmime::mediaTypes::IMAGE,
278 /* sub-type */ vmime::mediaTypes::IMAGE_JPEG);
279
280 // theType.getType() is "image"
281 // theType.getSubType() is "jpeg"
282 // theType.generate() returns "image/jpeg"
283 \end{lstlisting}
284
285 For more information about media types, see
286 RFC-2046\footnote{http://www.faqs.org/rfcs/rfc2046.html}.
287
288 \subsection{Mailbox and mailbox groups} % ------------------------------------
289
290 VMime provides several objects for working with mailboxes and addresses.
291
292 The {\vcode vmime::address} class is an abstract type for representing an
293 address: it can be either a mailbox (type {\vcode vmime::mailbox}) or a
294 mailbox group (type {\vcode vmime::mailboxGroup}). A mailbox is composed of
295 an email address (mandatory) and possibly a name. A mailbox group is simply
296 a named list of mailboxes (see Figure \ref{uml_addr_mbox_mboxgroup}).
297
298 \begin{lstlisting}[caption={Using mailboxes and mailbox groups}]
299 vmime::shared_ptr <vmime::mailbox> mbox1 = vmime::make_shared <vmime::mailbox>
300 (/* name */ vmime::text("John Doe"), /* email */ "john.doe@acme.com");
301 vmime::shared_ptr <vmime::mailbox> mbox2 = vmime::make_shared <vmime::mailbox>
302 (/* no name, email only */ "bill@acme.com");
303
304 vmime::shared_ptr <vmime::mailboxGroup> grp = vmime::make_shared <vmime::mailboxGroup>();
305 grp->appendMailbox(mbox1);
306 grp->appendMailbox(mbox2);
307 \end{lstlisting}
308
309 \begin{figure}[ht!]
310 \center\includegraphics[width=0.7\textwidth]
311 {images/address-mailbox-mailboxgroup.png}\endcenter
312 \caption{Diagram for address-related classes}
313 \label{uml_addr_mbox_mboxgroup}
314 \end{figure}
315
316
317 % ============================================================================
318 \section{Message, body parts and header}
319
320 \subsection{Introduction to MIME messages} % ---------------------------------
321
322 A MIME message is a recursive structure in which each part can contains one
323 or more parts (or \emph{entities}). Each part is composed of a header and
324 a body (actual contents). Figure \ref{uml_msg_body_header} shows how this
325 model is implemented in VMime, and all classes that take part in it.
326
327 \begin{figure}
328 \center\includegraphics[width=1.0\textwidth]
329 {images/message-body-header.png}\endcenter
330 \caption{Overall structure of MIME messages}
331 \label{uml_msg_body_header}
332 \end{figure}
333
334
335 \subsection{Header and header fields} % --------------------------------------
336
337 \subsubsection{Standard header fields} % .....................................
338
339 Header fields carry information about a message (or a part) and its contents.
340 Each header field has a name and a value. All types that can be used as a
341 field value inherit from the {\vcode headerFieldValue} class.
342
343 You cannot instanciate header fields directly using their constructor.
344 Instead, you should use the {\vcode headerFieldFactory} object. This ensures
345 the right field type and value type is used for the specified field name.
346 For more information about how to use header fields and the factory, see
347 section \ref{msg-building-simple-message}.
348
349 Some standard fields are officially registered and have their value type
350 specified in a RFC. Table \ref{standard-fields} lists all the fields
351 registered by default in VMime and the value type they contains.
352
353 By default, all unregistered fields have a value of type {\vcode text}.
354
355 \begin{table}[!ht]
356 \begin{center}
357 \noindent\begin{tabularx}{0.85\textwidth}{|X|X|}
358 \hline
359 {\bf Field Name} &
360 {\bf Value Type} \\
361 \hline
362 \hline
363 From & mailbox \\
364 To & addressList \\
365 Cc & addressList \\
366 Bcc & addressList \\
367 Sender & mailbox \\
368 Date & datetime \\
369 Received & relay \\
370 Subject & text \\
371 Reply-To & mailbox \\
372 Delivered-To & mailbox \\
373 Organization & text \\
374 Return-Path & path \\
375 Mime-Version & text \\
376 Content-Type & mediaType \\
377 Content-Transfer-Encoding & encoding \\
378 Content-Description & text \\
379 Content-Disposition & contentDisposition \\
380 Content-Id & messageId \\
381 Content-Location & text \\
382 Message-Id & messageId \\
383 In-Reply-To & messageIdSequence \\
384 References & messageIdSequence \\
385 Original-Message-Id & messageId \\
386 Disposition & disposition \\
387 Disposition-Notification-To & mailboxList \\
388 \hline
389 \end{tabularx}
390 \end{center}
391 \label{standard-fields}
392 \caption{Standard fields and their types}
393 \end{table}
394
395
396 \subsubsection{Parameterized fields} % .......................................
397
398 In addition to a value, some header fields can contain one or more
399 \emph{name=value} couples which are called \emph{parameters}. For example,
400 this is used in the \emph{Content-Type} field to give more information about
401 the content:
402
403 \begin{verbatim}
404 Content-Type: text/plain; charset="utf-8"
405 \end{verbatim}
406
407 Fields that support parameters inherit from the
408 {\vcode parameterizedHeaderField} class which provides methods to deal with
409 these parameters: {\vcode appendParameter()}, {\vcode getParameterAt()}...
410
411 A parameter is identified by a name (eg. \emph{charset}) and associated to
412 a value of type {\vcode vmime::text}. Parameters provide helper functions to
413 convert automatically from basic types to text, and \emph{vice versa}. The
414 following example illustrates it:
415
416 \begin{lstlisting}[caption={Getting and setting parameter value in fields}]
417 vmime::shared_ptr <vmime::parameterizedField> field =
418 header->findField <vmime::parameterizedField>("X-Field-That-Contains-Parameters");
419
420 // Use setValue() to convert from a basic type to 'text'
421 vmime::shared_ptr <vmime::parameter> prm = field->getParameter("my-date-param");
422 prm->setValue(vmime::datetime::now());
423
424 // Use getValueAs() to convert from 'text' to a basic type
425 prm = field->getParameter("my-charset-param");
426 const vmime::charset ch = prm->getValueAs <vmime::charset>();
427 \end{lstlisting}
428
429 Some fields provide easy access to their standard parameters (see
430 Table \ref{standard-prm-fields}). This avoids finding the parameter and
431 \emph{dynamic-casting} its value to the right type. The following code
432 illustrates how to use it:
433
434 \begin{lstlisting}
435 vmime::shared_ptr <vmime::contentTypeField> field =
436 header->getField <vmime::contentTypeField>(vmime::fields::CONTENT_TYPE);
437
438 // 1. First solution: the "hard" way
439 vmime::shared_ptr <vmime::parameter> prm = field->findParameter("charset");
440 const charset ch1 = prm->getValueAs <vmime::charset>();
441
442 // 2. Second solution: the simple way
443 const charset ch2 = field->getCharset();
444 \end{lstlisting}
445
446 \vnote{In both cases, an exception {\vcode no\_such\_parameter} can be
447 thrown if the parameter does not exist, so be sure to catch it.}
448
449 \begin{table}[ht!]
450 \begin{center}
451 \noindent\begin{tabularx}{0.85\textwidth}{|l|l|X|}
452 \hline
453 {\bf Field Name} &
454 {\bf Field Type} &
455 {\bf Parameters} \\
456 \hline
457 \hline
458 Content-Type & contentTypeField & boundary, charset, report-type \\
459 \hline
460 Content-Disposition & contentDispositionField & creation-date,
461 modification-date, read-date, filename, size \\
462 \hline
463 \end{tabularx}
464 \end{center}
465 \label{standard-prm-fields}
466 \caption{Standard parameterized fields}
467 \end{table}
468
469
470
471 % ============================================================================
472 \section{Streams}
473
474 \subsection{Streams and stream adapters} % -----------------------------------
475
476 Streams permit reading or writing data whatever the underlying system is:
477 a file on a hard disk, a socket connected to a remote service...
478
479 There are two types of streams: input streams (from which you can read data)
480 and output streams (in which you can write data). Some adapters are provided
481 for compatibility and convenience, for example:
482
483 \begin{itemize}
484 \item {\vcode inputStreamAdapter} and {\vcode outputStreamAdapter}: allow
485 to use standard C++ iostreams with VMime;
486 \item {\vcode inputStreamStringAdapter} and
487 {\vcode outputStreamStringAdapter}: use a {\vcode vmime::string} object to
488 read/write data.
489 \end{itemize}
490
491 The following example shows two ways of writing the current date to the
492 standard output, using stream adapters:
493
494 \begin{lstlisting}[caption={Using stream adapters}]
495 // Get current date and time
496 const vmime::datetime date = vmime::datetime::now();
497
498 // 1. Using outputStreamAdapter
499 vmime::utility::outputStreamAdapter out(std::cout);
500
501 std::cout << "Current date is: ";
502 date.generate(out);
503 std::cout << std::endl;
504
505 // 2. Using outputStreamStringAdapter
506 vmime::string dateStr;
507 vmime::utility::outputStreamStringAdapter outStr(dateStr);
508
509 date.generate(outStr);
510
511 std::cout << "Current date is: " << dateStr << std::endl;
512 \end{lstlisting}
513
514
515 \subsection{Stream filters} % ------------------------------------------------
516
517 Input and output streams can be filtered to perform inline conversions (for
518 example, there is a filter to convert ``{\textbackslash}r{\textbackslash}n''
519 sequences to ``{\textbackslash}n''). They inherit from
520 {\vcode vmime::utility::filteredInputStream} or
521 {\vcode vmime::utility::filteredOutputStream} and are used like adapters (some
522 filters also accept parameters; read the documentation).
523
524 The most useful filter in VMime (and probably the only one you will need) is
525 the {\vcode charsetFilteredOutputStream}, which performs inline conversion
526 of charsets. See \ref{section_charsets} to know how to use it.
527
528 \vnote{After you have finished to use a filtered output stream, it is
529 important to call {\vcode flush()} on it to flush the internal buffer.
530 If {\vcode flush()} is not called, not all data may be written to the
531 underlying stream.}
532
533
534 % ============================================================================
535 \section{Content handlers}
536
537 \subsection{Introduction} % --------------------------------------------------
538
539 Content handlers are an abstraction for data sources. They are currently used
540 when some data need to be stored for later use (eg. body part contents,
541 attachment data, ...). Data can be stored encoded or unencoded (for more
542 information about encodings, see \ref{section_encodings}).
543
544 \subsection{Extracting data from content handlers} % -------------------------
545
546 You can extract data in a content handler using the {\vcode extract()} method
547 (which automatically decodes data if encoded) or {\vcode extractRaw()} (which
548 extracts data without perfoming any decoding).
549
550 The following example shows how to extract the body text from a message, and
551 writing it to the standard output with charset conversion:
552
553 \begin{lstlisting}[caption={Using content handlers to extract body text from
554 a message}]
555 // Suppose we already have a message
556 vmime::shared_ptr <vmime::message> msg;
557
558 // Obtains a reference to the body contents
559 vmime::shared_ptr <vmime::body> body = msg->getBody();
560 vmime::shared_ptr <vmime::contentHandler> cts = body->getContents();
561
562 vmime::utility::outputStreamAdapter out(std::cout);
563 cts->extract(out);
564 \end{lstlisting}
565
566 \vnote{The body contents is extracted ``as is''. No charset conversion is
567 performed. See \ref{section_charsets} to know more about conversion between
568 charsets.}
569
570
571 \subsection{Creating content handlers} % -------------------------------------
572
573 When you are building a message, you may need to instanciate content handlers
574 if you want to set the contents of a body part. The following code snippet
575 shows how to set the body text of a part from a string:
576
577 \begin{lstlisting}[caption={Setting the contents of a body part}]
578 vmime::shared_ptr <vmime::bodyPart> part; // suppose we have a body part
579
580 // Create a new content handler from a string
581 vmime::shared_ptr <vmime::contentHandler> cth =
582 vmime::make_shared <vmime::stringContentHandler>("Put body contents here");
583
584 // Set the contents
585 part->getBody()->setContents(cth);
586 \end{lstlisting}
587
588 Content handlers are also used when creating attachments. The following
589 example illustrates how to create an attachment from a file:
590
591 \begin{lstlisting}[caption={Creating an attachment from a file}]
592 // Create a stream from a file
593 std::ifstream* fileStream = new std::ifstream();
594
595 fileStream->open("/home/vincent/paris.jpg", std::ios::binary);
596
597 if (!*fileStream)
598 // handle error
599
600 vmime::shared_ptr <utility::stream> dataStream =
601 vmime::make_shared <vmime::utility::inputStreamPointerAdapter>(fileStream);
602
603 // NOTE: 'fileStream' will be automatically deleted
604 // when 'dataStream' is deleted
605
606 // Create a new content handler
607 vmime::shared_ptr <contentHandler> data =
608 vmime::make_shared <vmime::streamContentHandler>(dataStream, 0);
609
610 // Now create the attachment
611 ref <vmime::attachment> att = vmime::make_shared <vmime::defaultAttachment>
612 (
613 /* attachment data */ data,
614 /* content type */ vmime::mediaType("image/jpeg"),
615 /* description */ vmime::text("Holiday photo"),
616 /* filename */ vmime::word("paris.jpg")
617 );
618 \end{lstlisting}
619
620 You will see later that the {\vcode vmime::fileAttachment} class already
621 encapsulates all the mechanics to create an attachment from a file.
622
623
624 % ============================================================================
625 \section{Character sets, charsets and conversions\label{section_charsets}}
626
627 Quoting from RFC-2278: \emph{`` The term 'charset' is used to refer to a
628 method of converting a sequence of octets into a sequence of characters.''}
629
630 With the {\vcode vmime::charset} object, VMime supports conversion between
631 charsets using the {\em iconv} library, which is available on almost all
632 existing platforms. See {\vcode vmime::charset} and
633 {\vcode vmime::charsetConverter} in the class documentation to know more
634 about charset conversion.
635
636 The following example shows how to convert data in one charset to another
637 charset. The data is extracted from the body of a message and converted
638 to UTF-8 charset:
639
640 \begin{lstlisting}[caption={Extracting and converting body contents to a
641 specified charset}]
642 vmime::shared_ptr <vmime::message> msg; // we have a message
643
644 // Obtain the content handler first
645 vmime::shared_ptr <vmime::body> body = msg->getBody();
646 vmime::shared_ptr <const vmime::contentHandler> cth = body->getContents();
647
648 // Then, extract and convert the contents
649 vmime::utility::outputStreamAdapter out(std::cout);
650 vmime::utility::charsetFilteredOutputStream fout
651 (/* source charset */ body->getCharset(),
652 /* dest charset */ vmime::charset("utf-8"),
653 /* dest stream */ out);
654
655 cth->extract(fout);
656
657 fout.flush(); // Very important!
658 \end{lstlisting}
659
660
661 % ============================================================================
662 \section{Non-ASCII text in header fields}
663
664 MIME standard defines methods\footnote{See RFC-2047: Message Header Extensions
665 for Non-ASCII Text} for dealing with data which is not 7-bit only (ie. the
666 ASCII character set), in particular in header fields. For example, the field
667 ``Subject:'' use this data type.
668
669 VMime is fully compatible with RFC-2047 and provides two objects for
670 manipulating 8-bit data: {\vcode vmime::text} and {\vcode vmime::word}. A word
671 represents textual information encoded in a specified charset. A text is
672 composed of one or more words.
673
674 RFC-2047 describes the process of encoding 8-bit data into a 7-bit form;
675 basically, it relies on Base64 and Quoted-Printable encoding. Hopefully, all
676 the encoding/decoding process is done internally by VMime, so creating text
677 objects is fairly simple:
678
679 \begin{lstlisting}[caption={Creating \vcode{vmime::text} objects}]
680 vmime::string inText = "Linux dans un téléphone mobile";
681 vmime::charset inCharset = "utf-8";
682
683 vmime::text outText;
684 outText.createFromString(inText, inCharset);
685
686 // 'outText' now contains 3 words:
687 // . <us-ascii> "Linux dans un "
688 // . <utf-8> "téléphone "
689 // . <us-ascii> "mobile"
690
691 vmime::shared_ptr <vmime::header> header = myMessage->getHeader();
692 header->Subject()->setValue(outText);
693 \end{lstlisting}
694
695 In general, you will not need to decode RFC-2047-encoded data as the process
696 is totally transparent in VMime. If you really have to, you can use the
697 {\vcode vmime::text::decodeAndUnfold()} static method to create a text object
698 from encoded data.
699
700 For example, say you have the following encoded data:
701
702 \begin{verbatim}
703 Linux dans un =?UTF-8?B?dMOpbMOpcGhvbmUgbW9iaWxl?=
704 \end{verbatim}
705
706 You can simply decode it using the following code:
707
708 \begin{lstlisting}[caption={Decoding RFC-2047-encoded data}]
709 vmime::string inData =
710 "Linux dans un =?UTF-8?B?dMOpbMOpcGhvbmUgbW9iaWxl?=";
711
712 vmime::text outText;
713 vmime::text::decodeAndUnfold(inData, &outText);
714 \end{lstlisting}
715
716 {\vcode vmime::text} also provides a function to convert all the words to
717 another charset in a single call. The following example shows how to convert
718 text stored in the Subject field of a message:
719
720 \begin{lstlisting}[caption={Converting data in a {\vcode vmime::text} to a
721 specified charset}]
722 vmime::shared_ptr <vmime::message> msg; // we have a message
723
724 vmime::text subject = msg->getHeader()->Subject()->getValue();
725
726 const vmime::string subjectText =
727 subject.getConvertedText(vmime::charset("utf-8"));
728
729 // 'subjectText' now contains the subject in UTF-8 encoding
730 \end{lstlisting}
731
732
733 % ============================================================================
734 \section{Encodings\label{section_encodings}}
735
736 \subsection{Introduction} % --------------------------------------------------
737
738 The MIME standard defines a certain number of encodings to allow data
739 to be safely transmitted from one peer to another. VMime provides
740 data encoding and decoding using the {\vcode vmime::utility::encoder::encoder} object.
741
742 You should not need to use encoders directly, as all encoding/decoding
743 process is handled internally by the library, but it is good to know
744 they exist and how they work.
745
746 \subsection{Using encoders} % ------------------------------------------------
747
748 You can create an instance of an encoder using the 'vmime::utility::encoder::encoderFactory'
749 object, giving the encoding name ({\it base64}, {\it quoted-printable}, ...).
750 The following example creates an instance of the Base64 encoder to encode
751 some data:
752
753 \begin{lstlisting}[caption={A simple example of using an encoder}]
754 vmime::shared_ptr <vmime::utility::encoder::encoder> enc =
755 vmime::utility::encoder::encoderFactory::getInstance()->create("base64");
756
757 vmime::string inString("Some data to encode");
758 vmime::utility::inputStreamStringAdapter in(inString);
759
760 vmime::string outString;
761 vmime::utility::outputStreamStringAdapter out(outString);
762
763 enc->encode(in, out);
764
765 std::cout << "Encoded data is:" << outString << std::endl;
766 \end{lstlisting}
767
768 \subsection{Enumerating available encoders} % --------------------------------
769
770 The behaviour of the encoders can be configured using properties. However,
771 not all encoders support properties. The following example\footnote{This is
772 an excerpt from {\vexample example6}} enumerates available encoders and the
773 supported properties for each of them:
774
775 \begin{lstlisting}[caption={Enumerating encoders and their properties}]
776 vmime::shared_ptr <vmime::utility::encoder::encoderFactory> ef =
777 vmime::utility::encoder::encoderFactory::getInstance();
778
779 std::cout << "Available encoders:" << std::endl;
780
781 for (int i = 0 ; i < ef->getEncoderCount() ; ++i)
782 {
783 // Output encoder name
784 vmime::shared_ptr <const vmime::utility::encoder::encoderFactory::registeredEncoder>
785 enc = ef->getEncoderAt(i);
786
787 std::cout << " * " << enc->getName() << std::endl;
788
789 // Create an instance of the encoder to get its properties
790 vmime::shared_ptr <vmime::utility::encoder::encoder> e = enc->create();
791
792 std::vector <vmime::string> props = e->getAvailableProperties();
793 std::vector <vmime::string>::const_iterator it;
794
795 for (it = props.begin() ; it != props.end() ; ++it)
796 std::cout << " - " << *it << std::endl;
797 \end{lstlisting}
798
799
800 % ============================================================================
801 \section{Progress listeners}
802
803 Progress listeners are used with objects that can notify you about the state
804 of progress when they are performing an operation.
805
806 The {\vcode vmime::utility::progressListener} interface is rather simple:
807
808 \begin{lstlisting}
809 void start(const int predictedTotal);
810 void progress(const int current, const int currentTotal);
811 void stop(const int total);
812 \end{lstlisting}
813
814 {\vcode start()} and {\vcode stop()} are called at the beginning and the end
815 of the operation, respectively. {\vcode progress()} is called each time the
816 status of progress changes (eg. a chunk of data has been processed). There is
817 no unit specified for the values passed in argument. It depends on the
818 notifier: it can be bytes, percent, number of messages...