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